NeoPZ
TPZCutHillMcKee.cpp
Go to the documentation of this file.
1 
2 #include "TPZCutHillMcKee.h"
3 #include "fstream"
4 
5 void TPZCutHillMcKee::SGraph::Set2Vec(const std::set<int64_t> &myset,
6  TPZVec<int64_t> &myVec) const{
7  const int64_t n = myset.size();
8  myVec.Resize(n);
9  std::set<int64_t>::const_iterator w, e = myset.end();
10  int64_t i;
11  for(w = myset.begin(), i = 0; w != e; w++, i++){
12  myVec[i] = *w;
13  }
14 }//void
15 
17 // std::cout << "TPZCutHillMcKee::SGraph::SmallestDegree size = " << this->NNodes() << std::endl;
18 // std::cout.flush();
19  int64_t mindegree = 1000000;
20  int64_t found = -1;
21  const int64_t n = this->NNodes();
22  for(int64_t i = 0; i < n; i++){
23  if(ExploredNodes[i] == 1) continue;
24  int64_t degree = this->Degree(i);
25  if(degree < mindegree){
26  mindegree = degree;
27  found = i;
28  }
29  }//for
30  return found;
31 }
32 
33 
35  const TPZVec< int64_t > &exceptedNodes,
36  TPZStack<int64_t> &adjNodes){
37  adjNodes.Resize(this->NNodes());//pre allocating memory
38  int64_t count = 0;
39  TPZVec<int64_t> History(this->NNodes(),0); //avoiding duplicates in adjNodes. it could be a std::set. set is better when few elements
40  for(int64_t i = 0; i < parents.NElements(); i++){
41  int64_t nlocal;
42  int64_t * localAdjNodes = AdjacentNodesPtr(parents[i], nlocal);
43  for(int64_t j = 0; j < nlocal; j++){
44  const int64_t node = localAdjNodes[j];
45  if(exceptedNodes[node] == 0 && History[node] == 0){
46  adjNodes[count] = node;
47  count++;
48  History[node] = 1;
49  }
50  }//j
51  }//i
52  adjNodes.Resize(count);
53  adjNodes.Shrink(); //saving memory
54 }//void
55 
57  const int64_t n = this->Degree(parent);
58  adjNodes.Resize(n);
59  for(int64_t i = 0; i < n; i++){
60  const int64_t adj = fnodegraph[fnodegraphindex[parent]+i];
61  adjNodes[i] = adj;
62  }//for
63 }//void
64 
66  const TPZVec<int64_t> &exceptedNodes,
67  TPZVec<int64_t> &adjNodes){
68  std::multimap<int64_t,int64_t> order;
69 
70  const int64_t ndegree = this->Degree(parent);
71  int64_t count = 0;
72  for(int64_t i = 0; i < ndegree; i++){
73  const int64_t adj = fnodegraph[fnodegraphindex[parent]+i];
74  if(exceptedNodes[adj] == 1) continue;
75  const int64_t adjDegree = this->Degree(adj);
76  order.insert(std::make_pair(adjDegree,adj));
77  count++;
78  }//for
79 
80  adjNodes.Resize(count);
81 #ifdef PZDEBUG
82  if(count != (int64_t)(order.size()) ){
83  DebugStop();
84  }
85 #endif
86  std::multimap<int64_t,int64_t>::const_iterator mapIt;
87  int64_t i;
88  for(i = 0, mapIt = order.begin(); mapIt != order.end(); i++, mapIt++){
89  adjNodes[i] = mapIt->second;
90  }
91 }//void
92 
94  TPZStack< TPZStack<int64_t> > &LevelStructure){
95  LevelStructure.Resize(0);
96 
98 
99  TPZStack<int64_t> thisLevel;
100  thisLevel.Resize(1);
101  thisLevel[0] = rootNode;
102 
103  TPZVec<int64_t> ProcessedNodes(this->NNodes(),0);
104 
105  for(int64_t iLevel = 0; iLevel < this->NNodes(); iLevel++){
106 
107  const int64_t nThisLevel = thisLevel.NElements();
108  if(nThisLevel == 0) break;
109  for(int64_t i = 0; i < nThisLevel; i++){
110  const int64_t node = thisLevel[i];
111  ProcessedNodes[node] = 1;
112  }
113  LevelStructure.Push( thisLevel);
114 
115  this->GetAdjacentNodes(LevelStructure[LevelStructure.NElements() - 1], ProcessedNodes, thisLevel);
116 
117  }//for que de fato eh while
118 
119  LevelStructure.Shrink();//saving memory
120 
121 }//void
122 
124  std::multimap<int64_t,int64_t> mymap;
125  for(int64_t i = 0; i < nodes.NElements(); i++){
126  const int64_t node = nodes[i];
127  const int64_t degree = this->Degree(node);
128  mymap.insert(std::make_pair(degree,node));
129  }//for
130  std::multimap<int64_t,int64_t>::const_iterator mapIt;
131  int64_t i;
132  for(i = 0, mapIt = mymap.begin(); mapIt != mymap.end(); i++, mapIt++){
133  nodes[i] = mapIt->second;
134  }
135 }//void
136 
138 
139  const int64_t nelsOrig = LastLevel.NElements();
140 
141  //accorging to suggestion of INTERNATIONAL JOURNAL FOR NUMERICAL METHODS IN ENGINEERING, VOL. 28,2651-2679 (1989)
142  //A FORTRAN PROGRAM FOR PROFILE AND WAVEFRONT REDUCTION by S. W. SLOAN
143  //removing nodes with same degree
144  std::map< int64_t, int64_t > mymap;
145  for(int64_t i = 0; i < LastLevel.NElements(); i++){
146  const int64_t node = LastLevel[i];
147  const int64_t degree = this->Degree( node );
148  mymap[ degree ] = node;
149  }
150  LastLevel.Resize(mymap.size());
151  std::map< int64_t, int64_t >::const_iterator w, e = mymap.end();
152  int64_t i;
153  for(i = 0, w = mymap.begin(); w != e; w++, i++){
154  LastLevel[i] = w->second;
155  }
156 
157  //Previously, Sloan had suggested, in the article of 1986, LastLevel.Resize( (LastLevel.NElements()+2)/2 );
158  const int64_t newsize = (nelsOrig+2)/2;
159  if(newsize < LastLevel.NElements()){
160  LastLevel.Resize( newsize );
161  }
162 
163 }
164 
165 void TPZCutHillMcKee::SGraph::PseudoPeripheralNodes(int64_t &startNode, int64_t &endNode){
166 
167  endNode = -1;
168 
169  TPZManVector<int64_t> emptyVec(this->NNodes(), 0);
170  //step 1: first guess
171  startNode = SmallestDegree(emptyVec);
172 
173  //step 2: rooted level structure
174  TPZStack< TPZStack<int64_t> > LevelStructure;
175  this->RootedLevelStructure(startNode, LevelStructure);
176 
177 #ifdef PZDEBUG_CM
178  std::ofstream myfile("c:\\Temp\\PseudoPeripheralNodes.txt");
179 #endif
180 
181  int64_t count = 0;
182  const int64_t maxCount = 10;
183  TPZStack< TPZStack<int64_t> > localLevelStructure;
184  TPZStack<int64_t> LastLevel;
185  LastLevel.Resize( this->NNodes() );//pre allocating memory
186  LastLevel.Resize(0);
187  while(count < maxCount || endNode == -1){ //maxCount pra não ficar aqui eternamente
188 
189  count++;
190  const int64_t cpStart = startNode;
191  const int64_t cpEnd = endNode;
192 #ifdef PZDEBUG_CM
193  myfile << "\nstart = " << startNode << " end = " << endNode << "\n\n";
194 #endif
195  const int64_t nlevels = LevelStructure.NElements();
196  if(!nlevels) break;
197  LastLevel = LevelStructure[ nlevels-1 ];
198  //step 3 - sort the last level
199  this->SortNodes(LastLevel);
200  //step 4 - shrink the last level
201  ShrinkLastLevel(LastLevel);
202 
203  //step 5
204  int64_t we = 1000000000L;
205  int64_t hs = nlevels;
206  const int64_t nelLastLevel = LastLevel.NElements();
207  for(int64_t iQ = 0; iQ < nelLastLevel; iQ++){
208 
209  const int64_t nodeAtQ = LastLevel[iQ];
210 #ifdef PZDEBUG_CM
211  myfile << count << "\t" << iQ << "\t";myfile.flush();
212 #endif
213  this->RootedLevelStructure(nodeAtQ, localLevelStructure);
214 #ifdef PZDEBUG_CM
215  myfile << "rooted\t";myfile.flush();
216 #endif
217 
218  const int64_t h = localLevelStructure.NElements();
219  int64_t w = 0;
220  for(int64_t j = 0; j < h; j++){
221  const int64_t localW = localLevelStructure[j].NElements();
222  if(localW > w) w = localW;
223  }
224  if(h > hs && w < we){
225  startNode = nodeAtQ;
226  LevelStructure = localLevelStructure;
227 #ifdef PZDEBUG_CM
228  myfile << "break\n";myfile.flush();
229 #endif
230  break;
231  }
232  else if(w < we){
233  endNode = nodeAtQ;
234  we = w;
235  }
236 #ifdef PZDEBUG_CM
237  myfile << "end\n";myfile.flush();
238 #endif
239 
240  }//for iStep
241 #ifdef PZDEBUG_CM
242  myfile << "\n"; myfile.flush();
243 #endif
244 
245  if(cpStart == startNode && cpEnd == endNode){
246  break;
247  }
248  }//while
249 
250  if(startNode == -1 || endNode == -1) DebugStop();
251 
252 }//void
253 
255 
257  fReverse = true;
258 #ifdef PZDEBUG
259  fVerbose = true;
260 #else
261  fVerbose = false;
262 #endif
263 }
264 
265 TPZCutHillMcKee::TPZCutHillMcKee(int64_t NElements, int64_t NNodes, bool Reverse):TPZRenumbering(NElements,NNodes){
266  fReverse = Reverse;
267 #ifdef PZDEBUG
268  fVerbose = true;
269 #else
270  fVerbose = false;
271 #endif
272 }
273 
275 
276 }
277 
278 
280 
281  TPZVec<int64_t> permGather, permScatter;
282  TPZVec<int64_t> permGatherReverse, permScatterReverse;
283 
284  this->Resequence(permGather, permScatter, permGatherReverse, permScatterReverse);
285 
286  if(fReverse){
287  perm = permGatherReverse;
288  iperm = permScatterReverse;
289  }
290  else{
291  perm = permGather;
292  iperm = permScatter;
293  }
294 
295 }//void
296 
298  TPZVec<int64_t> &permGatherReverse, TPZVec<int64_t> &permScatterReverse){
299 
300  if(this->fVerbose) {
301  std::cout << "TPZCutHillMcKee ConvertGraph...";
302  std::cout.flush();
303  }
304  SGraph graph;
306  graph.fnodegraph.Shrink();
307  graph.fnodegraphindex.Shrink();
308 
309 
310 #ifdef PZDEBUG_CM
311  if(0){
312  int64_t grafoindex[7] = {0,3,6,9,14,19,22};
313  int64_t grafo[22] = {3,4,5, 2,3,4, 1,3,4, 0,1,2,4,5, 0,1,2,3,5, 0,3,4};
314  graph.fnodegraphindex.Resize(7);
315  for(int64_t i = 0; i < 7; i++) graph.fnodegraphindex[i] = grafoindex[i];
316  graph.fnodegraph.Resize(22);
317  for(int64_t i = 0; i < 22; i++) graph.fnodegraph[i] = grafo[i];
318 
319  {
320  TPZStack< TPZStack<int64_t> > LevelStructure;
321  graph.RootedLevelStructure(1, LevelStructure);
322  std::ofstream myfile("c:\\Temp\\LevelStructure.txt");
323  for(int64_t iLevel = 0; iLevel < LevelStructure.NElements(); iLevel++){
324  myfile << "Level " << iLevel << ": ";
325  for(int64_t j = 0; j < LevelStructure[iLevel].NElements(); j++){
326  myfile << LevelStructure[iLevel][j] << " ";
327  }
328  myfile << "\n";
329  }
330  }
331 
332  {
333  int64_t startNode = -1, endNode = -1;
334  graph.PseudoPeripheralNodes(startNode, endNode);
335  TPZStack< TPZStack<int64_t> > LevelStructure;
336  graph.RootedLevelStructure(startNode, LevelStructure);
337  std::ofstream myfile("c:\\Temp\\LevelStructureAfterPeripheral.txt");
338  for(int64_t iLevel = 0; iLevel < LevelStructure.NElements(); iLevel++){
339  myfile << "Level " << iLevel << ": ";
340  for(int64_t j = 0; j < LevelStructure[iLevel].NElements(); j++){
341  myfile << LevelStructure[iLevel][j] << " ";
342  }
343  myfile << "\n";
344  }
345  }
346 
347  }//if
348 #endif
349 
350  //CutHillMcKee
351  std::queue<int64_t> Q;
353  TPZManVector<int64_t> adjNodes;
354  //reservando memoria em R
355  const int64_t nnodes = graph.NNodes();
356  R.Resize(nnodes);
357  R.Resize(0);
358  TPZVec<int64_t> ExploredNodes(nnodes,0);
359  if(this->fVerbose) {
360  std::cout << "TPZCutHillMcKee process...\n";std::cout.flush();
361  }
362 
363  bool firstTime = true;
364  while(R.NElements() != graph.NNodes()){
365  if(this->fVerbose){
366  std::cout << "Calling TPZCutHillMcKee::SGraph::SmallestDegree\n";
367  std::cout.flush();
368  }
369  int64_t Parent = -1;
370  if(firstTime){
371  int64_t startNode = -1, endNode = -1;
372  graph.PseudoPeripheralNodes(startNode, endNode);
373  Parent = startNode;
374  firstTime = false;
375  }
376  else Parent = graph.SmallestDegree(ExploredNodes);
377 
378  if(Parent == -1){
379  if(R.NElements() == graph.NNodes()) return;
380  else DebugStop();
381  }
382 
383  this->ProcessParentNode(Parent, graph, ExploredNodes, R, Q, adjNodes);
384  while(Q.size()){
385  const int64_t Child = Q.front();
386  Q.pop();
387  this->ProcessParentNode(Child, graph, ExploredNodes, R, Q, adjNodes);
388  }
389 
390  }//loop completo
391 
392  const int64_t n = R.NElements();
393  if(n != nnodes) DebugStop();
394 
395 #ifdef PZDEBUG
396 {//verificando se ha duplicados
397  std::set<int64_t> check;
398  for(int64_t i = 0; i < n; i++) check.insert(R[i]);
399  if( ((int64_t)(check.size())) != n) DebugStop();
400 }
401 #endif
402 
403  if(this->fVerbose){
404  std::cout << "TPZCutHillMcKee Filling perm and iperm vectors...";std::cout.flush();
405  }
406 
407 
408  permScatterReverse.Resize(n);
409  for(int64_t i = 0; i < n; i++) permScatterReverse[n-1-i] = R[i];
410  permGatherReverse.Resize(n);
411  for(int64_t i = 0; i < n; i++) permGatherReverse[ permScatterReverse[i] ] = i;
412 
413 
414  permScatter = R;
415  permGather.Resize(n);
416  for(int64_t i = 0; i < n; i++) permGather[ permScatter[i] ] = i;
417 
418 
419 }
420 
422  SGraph &graph,
423  TPZVec<int64_t> &ExploredNodes,
425  std::queue<int64_t> &Q,
426  TPZVec<int64_t> &adjNodes){
427 
428  R.Push( Parent );
429  ExploredNodes[Parent] = 1;
430  graph.AdjacentNodesOrdered(Parent, ExploredNodes, adjNodes);
431  const int64_t nadj = adjNodes.NElements();
432  for(int64_t i = 0; i < nadj; i++){
433  if(ExploredNodes[adjNodes[i]] == 0){//then a new element
434  Q.push(adjNodes[i]);
435  ExploredNodes[adjNodes[i]] = 1;
436  }
437  }//for
438 
439 
440 }//void
441 
void Set2Vec(const std::set< int64_t > &myset, TPZVec< int64_t > &myVec) const
TPZManVector< int64_t > fnodegraph
Implements a vector class which allows to use external storage provided by the user. Utility.
Definition: pzquad.h:16
void ShrinkLastLevel(TPZVec< int64_t > &LastLevel)
void GetAdjacentNodes(const TPZVec< int64_t > &parents, const TPZVec< int64_t > &exceptedNodes, TPZStack< int64_t > &adjNodes)
void ConvertGraph(TPZVec< int64_t > &elgraph, TPZVec< int64_t > &elgraphindex, TPZManVector< int64_t > &nodegraph, TPZManVector< int64_t > &nodegraphindex)
Will convert an element graph defined by elgraph and elgraphindex into a node graph defined by nodegr...
virtual void Resequence(TPZVec< int64_t > &permGather, TPZVec< int64_t > &permScatter, TPZVec< int64_t > &permGatherReverse, TPZVec< int64_t > &permScatterReverse)
virtual ~TPZCutHillMcKee()
void degree(int root, int adj_num, int adj_row[], int adj[], int mask[], int deg[], int *iccsze, int ls[], int node_num)
Definition: rcm.cpp:875
void AdjacentNodes(int64_t parent, TPZVec< int64_t > &adjNodes)
clarg::argBool h("-h", "help message", false)
int64_t Degree(int64_t node)
virtual void Resize(const int64_t newsize, const T &object)
Resizes the vector object.
Definition: pzmanvector.h:426
void RootedLevelStructure(int64_t rootNode, TPZStack< TPZStack< int64_t > > &LevelStructure)
TPZVec< int64_t > fElementGraphIndex
Indicates for each element the index of the first entry with fElementGraph for that element The size ...
virtual void Resize(const int64_t newsize, const T &object)
Resizes the vector object reallocating the necessary storage, copying the existing objects to the new...
Definition: pzvec.h:373
void Push(const T object)
Pushes a copy of the object on the stack.
Definition: pzstack.h:80
This abstract class which defines the behavior which derived classes need to implement for implement...
#define DebugStop()
Returns a message to user put a breakpoint in.
Definition: pzerror.h:20
int64_t SmallestDegree(TPZVec< int64_t > &ExploredNodes)
void AdjacentNodesOrdered(int64_t parent, const TPZVec< int64_t > &exceptedNodes, TPZVec< int64_t > &adjNodes)
void Shrink()
It reallocates storage to fit the necessary storage exactly.
Definition: pzmanvector.h:388
TPZVec< int64_t > fElementGraph
Node number of each element.
TPZManVector< int64_t > fnodegraphindex
int64_t * AdjacentNodesPtr(int64_t parent, int64_t &n)
int64_t NElements() const
Returns the number of elements of the vector.
Definition: pzvec.h:190
void SortNodes(TPZVec< int64_t > &nodes)
void PseudoPeripheralNodes(int64_t &startNode, int64_t &endNode)
void ProcessParentNode(int64_t Parent, SGraph &graph, TPZVec< int64_t > &ExploredNodes, TPZStack< int64_t > &R, std::queue< int64_t > &Q, TPZVec< int64_t > &adjNodes)
void