gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
HomologyPostProcessing.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 //
6 // Contributed by Matti Pellikka <matti.pellikka@microsoft.com>.
7 
8 #include <stdlib.h>
9 #include <string>
10 #include <iostream>
11 #include <sstream>
12 #include "GmshGlobal.h"
13 #include "GmshConfig.h"
14 #include "GModel.h"
15 #include "Chain.h"
16 #include "fullMatrix.h"
17 #include "HomologyPostProcessing.h"
18 
19 #if defined(HAVE_KBIPACK)
20 
21 StringXNumber HomologyPostProcessingOptions_Number[] = {
22  {GMSH_FULLRC, "ApplyBoundaryOperatorToResults", nullptr, 0}};
23 
24 StringXString HomologyPostProcessingOptions_String[] = {
25  {GMSH_FULLRC, "TransformationMatrix", nullptr, "1, 0; 0, 1"},
26  {GMSH_FULLRC, "PhysicalGroupsOfOperatedChains", nullptr, "1, 2"},
27  {GMSH_FULLRC, "PhysicalGroupsOfOperatedChains2", nullptr, ""},
28  {GMSH_FULLRC, "PhysicalGroupsToTraceResults", nullptr, ""},
29  {GMSH_FULLRC, "PhysicalGroupsToProjectResults", nullptr, ""},
30  {GMSH_FULLRC, "NameForResultChains", nullptr, "c"},
31 };
32 
33 extern "C" {
34 GMSH_Plugin *GMSH_RegisterHomologyPostProcessingPlugin()
35 {
36  return new GMSH_HomologyPostProcessingPlugin();
37 }
38 }
39 
40 std::string GMSH_HomologyPostProcessingPlugin::getHelp() const
41 {
42  return "Plugin(HomologyPostProcessing) operates on representative "
43  "basis chains of homology and cohomology spaces. Functionality:\n\n"
44 
45  "1. (co)homology basis transformation:\n "
46  "'TransformationMatrix': Integer matrix of the transformation.\n "
47  "'PhysicalGroupsOfOperatedChains': (Co)chains of a (co)homology space "
48  "basis to be transformed.\n "
49  "Results a new (co)chain basis that is an integer combination of the "
50  "given basis.\n\n"
51 
52  "2. Make basis representations of a homology space and a cohomology "
53  "space compatible:\n"
54  "'PhysicalGroupsOfOperatedChains': Chains of a homology space basis.\n"
55  "'PhysicalGroupsOfOperatedChains2': Cochains of a cohomology space "
56  "basis.\n"
57  "Results a new basis for the homology space such that the incidence "
58  "matrix of the new basis and the basis of the cohomology space is the "
59  "identity matrix.\n\n"
60 
61  "Options:\n"
62  "'PhysicalGroupsToTraceResults': Trace the resulting (co)chains to "
63  "the given physical groups.\n"
64  "'PhysicalGroupsToProjectResults': Project the resulting (co)chains "
65  "to the complement of the given physical groups.\n"
66  "'NameForResultChains': Post-processing view name prefix for the "
67  "results.\n"
68  "'ApplyBoundaryOperatorToResults': Apply boundary operator to the "
69  "resulting chains.\n";
70 }
71 
72 int GMSH_HomologyPostProcessingPlugin::getNbOptions() const
73 {
74  return sizeof(HomologyPostProcessingOptions_Number) / sizeof(StringXNumber);
75 }
76 
77 StringXNumber *GMSH_HomologyPostProcessingPlugin::getOption(int iopt)
78 {
79  return &HomologyPostProcessingOptions_Number[iopt];
80 }
81 
82 int GMSH_HomologyPostProcessingPlugin::getNbOptionsStr() const
83 {
84  return sizeof(HomologyPostProcessingOptions_String) / sizeof(StringXString);
85 }
86 
87 StringXString *GMSH_HomologyPostProcessingPlugin::getOptionStr(int iopt)
88 {
89  return &HomologyPostProcessingOptions_String[iopt];
90 }
91 
92 bool GMSH_HomologyPostProcessingPlugin::parseStringOpt(
93  int stringOpt, std::vector<int> &intList)
94 {
95  std::string list = HomologyPostProcessingOptions_String[stringOpt].def;
96  intList.clear();
97 
98  int n;
99  char a;
100  std::istringstream ss(list);
101  while(ss >> n) {
102  intList.push_back(n);
103  if(ss >> a) {
104  if(a != ',') {
105  Msg::Error("Unexpected character \'%c\' while parsing \'%s\'", a,
106  HomologyPostProcessingOptions_String[stringOpt].str);
107  return false;
108  }
109  }
110  }
111  return true;
112 }
113 
114 int GMSH_HomologyPostProcessingPlugin::detIntegerMatrix(
115  std::vector<int> &matrix)
116 {
117  int n = sqrt((double)matrix.size());
118  fullMatrix<double> m(n, n);
119  for(int i = 0; i < n; i++)
120  for(int j = 0; j < n; j++) m(i, j) = matrix.at(i * n + j);
121 
122  return m.determinant();
123 }
124 
125 bool GMSH_HomologyPostProcessingPlugin::invertIntegerMatrix(
126  std::vector<int> &matrix)
127 {
128  int n = sqrt((double)matrix.size());
129  fullMatrix<double> m(n, n);
130  for(int i = 0; i < n; i++)
131  for(int j = 0; j < n; j++) m(i, j) = matrix.at(i * n + j);
132 
133  if(!m.invertInPlace()) {
134  Msg::Error("Matrix is not unimodular");
135  return false;
136  }
137 
138  for(int i = 0; i < n; i++)
139  for(int j = 0; j < n; j++) matrix.at(i * n + j) = m(i, j);
140  return true;
141 }
142 
143 PView *GMSH_HomologyPostProcessingPlugin::execute(PView *v)
144 {
145  std::string matrixString = HomologyPostProcessingOptions_String[0].def;
146  std::string opString1 = HomologyPostProcessingOptions_String[1].def;
147  std::string opString2 = HomologyPostProcessingOptions_String[2].def;
148  std::string cname = HomologyPostProcessingOptions_String[5].def;
149  std::string traceString = HomologyPostProcessingOptions_String[3].def;
150  std::string projectString = HomologyPostProcessingOptions_String[4].def;
151  int bd = (int)HomologyPostProcessingOptions_Number[0].def;
152 
153  GModel *m = GModel::current();
154 
155  int n;
156  char a;
157  int cols = 0;
158  int col = 0;
159  std::vector<int> matrix;
160  if(matrixString != "I") {
161  std::istringstream ss(matrixString);
162  while(ss >> n) {
163  matrix.push_back(n);
164  col++;
165  if(ss >> a) {
166  if(a != ',' && a != ';') {
167  Msg::Error("Unexpected character \'%c\' while parsing \'%s\'", a,
168  HomologyPostProcessingOptions_String[0].str);
169  return nullptr;
170  }
171  if(a == ';') {
172  if(cols != 0 && cols != col) {
173  Msg::Error("Number of columns must match (%d != %d)", cols, col);
174  return nullptr;
175  }
176  cols = col;
177  col = 0;
178  }
179  }
180  }
181  if(cols != 0 && cols != col && col != 0) {
182  Msg::Error("Number of columns must match (%d != %d)", cols, col);
183  return nullptr;
184  }
185  if(cols == 0) cols = col;
186  }
187 
188  int rows = 0;
189  if(!matrix.empty()) {
190  rows = matrix.size() / cols;
191  if((int)matrix.size() % cols != 0) {
192  Msg::Error(
193  "Number of matrix rows and columns aren't compatible (residual: %d)",
194  (int)matrix.size() % cols);
195  return nullptr;
196  }
197  }
198 
199  std::vector<int> basisPhysicals;
200  if(!parseStringOpt(1, basisPhysicals)) return nullptr;
201  std::vector<int> basisPhysicals2;
202  if(!parseStringOpt(2, basisPhysicals2)) return nullptr;
203 
204  if(matrixString != "I" && (int)basisPhysicals.size() != cols &&
205  basisPhysicals2.empty()) {
206  Msg::Error(
207  "Number of matrix columns and operated chains must match (%d != %d)",
208  cols, basisPhysicals.size());
209  return nullptr;
210  }
211  else if(matrixString == "I") {
212  cols = basisPhysicals.size();
213  rows = cols;
214  matrix = std::vector<int>(cols * cols, 0);
215  for(int i = 0; i < cols; i++) matrix.at(i * cols + i) = 1;
216  }
217 
218  if(!basisPhysicals2.empty() &&
219  basisPhysicals.size() != basisPhysicals2.size()) {
220  Msg::Error("Number of operated chains must match (%d != %d)",
221  basisPhysicals.size(), basisPhysicals2.size());
222  return nullptr;
223  }
224 
225  std::vector<int> tracePhysicals;
226  if(!parseStringOpt(3, tracePhysicals)) return nullptr;
227  std::vector<int> projectPhysicals;
228  if(!parseStringOpt(4, projectPhysicals)) return nullptr;
229 
230  std::vector<Chain<int> > curBasis;
231  for(std::size_t i = 0; i < basisPhysicals.size(); i++) {
232  curBasis.push_back(Chain<int>(m, basisPhysicals.at(i)));
233  }
234  if(curBasis.empty()) {
235  Msg::Error("No operated chains given");
236  return nullptr;
237  }
238  int dim = curBasis.at(0).getDim();
239 
240  std::vector<Chain<int> > curBasis2;
241  for(std::size_t i = 0; i < basisPhysicals2.size(); i++) {
242  curBasis2.push_back(Chain<int>(m, basisPhysicals2.at(i)));
243  }
244 
245  if(!curBasis2.empty()) {
246  rows = curBasis2.size();
247  cols = curBasis.size();
248  matrix = std::vector<int>(rows * cols, 0);
249  for(int i = 0; i < rows; i++)
250  for(int j = 0; j < cols; j++)
251  matrix.at(i * cols + j) = incidence(curBasis2.at(i), curBasis.at(j));
252  }
253 
254  if(!curBasis2.empty())
255  Msg::Debug("Incidence matrix: ");
256  else
257  Msg::Debug("Transformation matrix: ");
258  for(int i = 0; i < rows; i++)
259  for(int j = 0; j < cols; j++)
260  Msg::Debug("(%d, %d) = %d", i, j, matrix.at(i * cols + j));
261 
262  std::vector<Chain<int> > newBasis(rows, Chain<int>());
263  if(!curBasis2.empty()) {
264  Msg::Info("Computing new basis %d-chains such that the incidence matrix of "
265  "%d-chain bases %s and %s is the indentity matrix",
266  dim, dim, opString1.c_str(), opString2.c_str());
267  int det = detIntegerMatrix(matrix);
268  if(det != 1 && det != -1)
269  Msg::Warning("Incidence matrix is not unimodular (det = %d)", det);
270  if(!invertIntegerMatrix(matrix)) return nullptr;
271  for(int i = 0; i < rows; i++)
272  for(int j = 0; j < cols; j++)
273  newBasis.at(i) += matrix.at(i * cols + j) * curBasis2.at(j);
274  }
275  else {
276  Msg::Info("Applying transformation matrix [%s] to %d-chains %s",
277  matrixString.c_str(), dim, opString1.c_str());
278  if(rows == cols) {
279  int det = detIntegerMatrix(matrix);
280  if(det != 1 && det != -1)
281  Msg::Warning("Transformation matrix is not unimodular (det = %d)", det);
282  }
283  for(int i = 0; i < rows; i++)
284  for(int j = 0; j < cols; j++)
285  newBasis.at(i) += matrix.at(i * cols + j) * curBasis.at(j);
286  }
287 
288  if(bd) {
289  Msg::Info("Applying boundary operator to the result %d-chains", dim);
290  for(std::size_t i = 0; i < newBasis.size(); i++)
291  newBasis.at(i) = newBasis.at(i).getBoundary();
292  }
293 
294  if(!tracePhysicals.empty()) {
295  Msg::Info("Taking trace of result %d-chains to domain %s", dim,
296  traceString.c_str());
297  for(std::size_t i = 0; i < newBasis.size(); i++)
298  newBasis.at(i) = newBasis.at(i).getTrace(m, tracePhysicals);
299  }
300  if(!projectPhysicals.empty()) {
301  Msg::Info("Taking projection of result %d-chains to the complement of the "
302  "domain %s",
303  dim, projectString.c_str());
304  for(std::size_t i = 0; i < newBasis.size(); i++)
305  newBasis.at(i) = newBasis.at(i).getProject(m, projectPhysicals);
306  }
307  if(!tracePhysicals.empty() || !projectPhysicals.empty())
308  ElemChain::clearVertexCache();
309 
310  for(std::size_t i = 0; i < newBasis.size(); i++) {
311  std::string dims = convertInt(newBasis.at(i).getDim());
312  std::string nums = convertInt(i + 1);
313  newBasis.at(i).setName("C" + dims + " " + cname + nums);
314  newBasis.at(i).addToModel(m);
315  }
316 
317  return nullptr;
318 }
319 
320 #endif
StringXString
Definition: Options.h:910
PView
Definition: PView.h:27
GMSH_Plugin
Definition: Plugin.h:26
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
StringXNumber
Definition: Options.h:918
fullMatrix< double >
GMSH_FULLRC
#define GMSH_FULLRC
Definition: Options.h:20
GModel
Definition: GModel.h:44
Chain.h
StringXString::def
std::string def
Definition: Options.h:914
GmshGlobal.h
HomologyPostProcessing.h
GModel.h
fullMatrix.h
GModel::current
static GModel * current(int index=-1)
Definition: GModel.cpp:136