Salome HOME
updated copyright message
[modules/yacs.git] / src / engine / AbstractPoint.cxx
1 // Copyright (C) 2015-2023  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "AbstractPoint.hxx"
21 #include "LinkedBlocPoint.hxx"
22 #include "ForkBlocPoint.hxx"
23 #include "NotSimpleCasePoint.hxx"
24 #include "SetOfPoints.hxx"
25 #include "BagPoint.hxx"
26 #include "ElementaryPoint.hxx"
27 #include "Node.hxx"
28 #include "Bloc.hxx"
29
30 #include <algorithm>
31
32 using namespace YACS::ENGINE;
33
34 AbstractPoint::~AbstractPoint()
35 {
36 }
37
38 AbstractPoint *AbstractPoint::getGodFather()
39 {
40   if(_father==0)
41     return this;
42   else
43     return _father->getGodFather();
44 }
45
46 bool AbstractPoint::isBegin()
47 {
48   Node *beg(getFirstNode());
49   InGate *ing(beg->getInGate());
50   return ing->getBackLinks().empty();
51 }
52
53 bool AbstractPoint::isLast()
54 {
55   Node *endd(getLastNode());
56   OutGate *oug(endd->getOutGate());
57   return oug->edSetInGate().empty();
58 }
59
60 bool AbstractPoint::isSimplyLinkedBeforeAfter(BlocPoint *sop)
61 {
62   Node *beg(getFirstNode()),*endd(getLastNode());
63   return isSimplyLinkedBefore(sop,beg) && isSimplyLinkedAfter(sop,endd);
64 }
65
66 bool AbstractPoint::isSimplyLinkedAfterNullBefore(BlocPoint *sop)
67 {
68   Node *beg(getFirstNode()),*endd(getLastNode());
69   return IsNoLinksBefore(beg) && isSimplyLinkedAfter(sop,endd);
70 }
71
72 bool AbstractPoint::isSimplyLinkedBeforeNullAfter(BlocPoint *sop)
73 {
74   Node *beg(getFirstNode()),*endd(getLastNode());
75   return IsNoLinksAfter(endd) && isSimplyLinkedBefore(sop,beg);
76 }
77
78 bool AbstractPoint::isNullBeforeNullAfter(BlocPoint *sop)
79 {
80   Node *beg(getFirstNode()),*endd(getLastNode());
81   return IsNoLinksBefore(beg) && IsNoLinksAfter(endd);
82 }
83
84 /*!
85  * precondition : isSimplyLinkedBeforeAfter must return true on \a this.
86  */
87 LinkedBlocPoint *AbstractPoint::tryAsLink(BlocPoint *sop)
88 {
89   Node *bb(getFirstNode()),*ee(getLastNode());
90   std::list<AbstractPoint *> l; l.push_back(this);
91   AbstractPoint *cur2(0);
92   //
93   cur2=sop->getNodeB4(bb);
94   while(cur2)
95     {
96       if(dynamic_cast<NotSimpleCasePoint *>(cur2))
97         continue;
98       Node *cur3(cur2->getFirstNode());
99       if(cur2->isSimplyLinkedBeforeAfter(sop))
100         {
101           l.push_front(cur2);
102           cur2=sop->getNodeB4(cur3);
103           continue;
104         }
105       else if(IsGatherB4Ext(cur3) && isSimplyLinkedAfter(sop,cur2->getLastNode()))
106         {
107           l.push_front(cur2);
108           break;
109         }
110       else
111         break;
112     }
113   //
114   cur2=sop->getNodeAfter(ee);
115   while(cur2)
116     {
117       if(dynamic_cast<NotSimpleCasePoint *>(cur2))
118         continue;
119       Node *cur3(cur2->getLastNode());
120       if(cur2->isSimplyLinkedBeforeAfter(sop))
121         {
122           l.push_back(cur2);
123           cur2=sop->getNodeAfter(cur3);
124           continue;
125         }
126       else if(IsScatterAfterExt(cur3) && isSimplyLinkedBefore(sop,cur2->getFirstNode()))
127         {
128           l.push_back(cur2);
129           break;
130         }
131       else
132         break;
133     }
134   if(l.size()>1)
135     {
136       return new LinkedBlocPoint(l,getFather());
137     }
138   else
139     return nullptr;
140 }
141
142 /*!
143  * precondition : isSimplyLinkedBeforeAfter must return true on \a this.
144  */
145 ForkBlocPoint *AbstractPoint::tryAsFork(BlocPoint *sop)
146 {
147   Node *bb(GetNodeB4(getFirstNode())),*ee(GetNodeAfter(getLastNode()));
148   AbstractPoint *bb2(sop->findPointWithNode(bb)),*ee2(sop->findPointWithNode(ee));
149   //
150   const std::list<AbstractPoint *>& lp(sop->getListOfPoints());
151   std::list<AbstractPoint *> l; l.push_back(this);
152   for(std::list<AbstractPoint *>::const_iterator it=lp.begin();it!=lp.end();it++)
153     {
154       if(*it==this)
155         continue;
156       if(dynamic_cast<NotSimpleCasePoint *>(*it))
157         continue;
158       Node *curFirst((*it)->getFirstNode()),*curEnd((*it)->getLastNode());
159       if(!IsSimplyLinkedBeforeExt(curFirst) || !IsSimplyLinkedAfterExt(curEnd))
160         continue;
161       Node *curbb(GetNodeB4(curFirst)),*curee(GetNodeAfter(curEnd));
162       AbstractPoint *bb3(sop->findPointWithNode(curbb)),*ee3(sop->findPointWithNode(curee));
163       if(bb2==bb3 && ee2==ee3)
164         l.push_back(*it);
165     }
166   if(l.size()>1)
167     {
168       return new ForkBlocPoint(l,getFather());
169     }
170   else
171     return nullptr;
172 }
173
174 ForkBlocPoint *AbstractPoint::tryAsForkBis(BlocPoint *sop)
175 {
176   Node *bb(GetNodeB4(getFirstNode())),*ee(GetNodeAfter(getLastNode()));
177   AbstractPoint *ee2(sop->findPointWithNode(ee));
178   //
179   const std::list<AbstractPoint *>& lp(sop->getListOfPoints());
180   std::list<AbstractPoint *> l; l.push_back(this);
181   for(std::list<AbstractPoint *>::const_iterator it=lp.begin();it!=lp.end();it++)
182     {
183       if(*it==this)
184         continue;
185       if(dynamic_cast<NotSimpleCasePoint *>(*it))
186         continue;
187       Node *curFirst((*it)->getFirstNode()),*curEnd((*it)->getLastNode());
188       if(!IsNoLinksBefore(curFirst) || !IsSimplyLinkedAfterExt(curEnd))
189         continue;
190       Node *curee(GetNodeAfter(curEnd));
191       AbstractPoint *ee3(sop->findPointWithNode(curee));
192       if(ee2==ee3)
193         l.push_back(*it);
194     }
195   if(l.size()>1)
196     {
197       return new ForkBlocPoint(l,getFather());
198     }
199   else
200     return nullptr;
201 }
202
203 ForkBlocPoint *AbstractPoint::tryAsForkTer(BlocPoint *sop)
204 {
205   Node *bb(GetNodeB4(getFirstNode())),*ee(GetNodeAfter(getLastNode()));
206   AbstractPoint *bb2(sop->findPointWithNode(bb));
207   //
208   const std::list<AbstractPoint *>& lp(sop->getListOfPoints());
209   std::list<AbstractPoint *> l; l.push_back(this);
210   for(std::list<AbstractPoint *>::const_iterator it=lp.begin();it!=lp.end();it++)
211     {
212       if(*it==this)
213         continue;
214       if(dynamic_cast<NotSimpleCasePoint *>(*it))
215         continue;
216       Node *curFirst((*it)->getFirstNode()),*curEnd((*it)->getLastNode());
217       if(!IsSimplyLinkedBeforeExt(curFirst) || !IsNoLinksAfter(curEnd))
218         continue;
219       Node *curbb(GetNodeB4(curFirst));
220       AbstractPoint *bb3(sop->findPointWithNode(curbb));
221       if(bb2==bb3)
222         l.push_back(*it);
223     }
224   if(l.size()>1)
225     {
226       return new ForkBlocPoint(l,getFather());
227     }
228   else
229     return nullptr;
230 }
231
232 ForkBlocPoint *AbstractPoint::tryAsForkQuatro(BlocPoint *sop)
233 {
234   Node *bb(GetNodeB4(getFirstNode())),*ee(GetNodeAfter(getLastNode()));
235   AbstractPoint *bb2(sop->findPointWithNode(bb));
236   //
237   const std::list<AbstractPoint *>& lp(sop->getListOfPoints());
238   std::list<AbstractPoint *> l; l.push_back(this);
239   for(std::list<AbstractPoint *>::const_iterator it=lp.begin();it!=lp.end();it++)
240     {
241       if(*it==this)
242         continue;
243       if(dynamic_cast<NotSimpleCasePoint *>(*it))
244         continue;
245       Node *curFirst((*it)->getFirstNode()),*curEnd((*it)->getLastNode());
246       if(!IsNoLinksBefore(curFirst) || !IsNoLinksAfter(curEnd))
247         continue;
248       Node *curbb(GetNodeB4(curFirst));
249       AbstractPoint *bb3(sop->findPointWithNode(curbb));
250       if(bb2==bb3)
251         l.push_back(*it);
252     }
253   if(l.size()>1)
254     {
255       return new ForkBlocPoint(l,getFather());
256     }
257   else
258     return nullptr;
259 }
260
261 #include <iostream>
262
263 class Visitor1 : public YACS::ENGINE::PointVisitor
264 {
265 public:
266   Visitor1(std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m):_m(m) { }
267   void beginForkBlocPoint(ForkBlocPoint *pt) { }
268   void endForkBlocPoint(ForkBlocPoint *pt) { }
269   void beginLinkedBlocPoint(LinkedBlocPoint *pt) { }
270   void endLinkedBlocPoint(LinkedBlocPoint *pt) { }
271   void beginElementaryPoint(ElementaryPoint *pt)
272   {
273     std::string nodeName(pt->getNodeName());
274     auto it(_m->find(nodeName));
275     if(it==_m->end())
276       {
277         (*_m)[nodeName] = std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> >(pt,pt->getNode(),std::make_shared<Bloc>(nodeName));
278       }
279   }
280   void endElementaryPoint(ElementaryPoint *pt) { }
281   void beginNotSimpleCasePoint(NotSimpleCasePoint *pt) { }
282   void endNotSimpleCasePoint(NotSimpleCasePoint *pt) { }
283 private:
284   std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *_m;
285 };
286
287 /*!
288  * Feed m with all ElementaryPoints inside \a ptToBeRewired.
289  */
290 void AbstractPoint::FeedData(AbstractPoint *ptToBeRewired, std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m)
291 {
292   Visitor1 vis(m);
293   ptToBeRewired->accept(&vis);
294 }
295
296 /*!
297  * Feed m with all ElementaryPoints inside \a ptsToBeRewired.
298  */
299 void AbstractPoint::FeedData(const std::list<AbstractPoint *>& ptsToBeRewired, std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m)
300 {
301   for(auto it : ptsToBeRewired)
302     FeedData(it,m);
303 }
304
305 bool containsPtsToKill(const std::vector<AbstractPoint *>& ptsToKill, Node *node)
306 {
307   for(auto it : ptsToKill)
308     if(it->contains(node))
309       return true;
310   return false;
311 }
312
313 /*!
314  * This method go throw all ElementaryPoints of \a m. 
315  * For each ElementaryPoint change the Node instance underneath. And then create links between those new Node by excluding all links going whose destination :
316  * - is inside \a ptToKill
317  * - is not refered by \a m
318  * 
319  * CF links of old nodes are NOT touched for unrewire phase.
320  * Typically all ElementaryPoints inside \a ptToKill are NOT into \a m.
321  */
322 void AbstractPoint::Rewire(const std::vector<AbstractPoint *>& ptsToKill, std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m)
323 {
324   for(auto it : *m)
325     {
326       ElementaryPoint *pt(std::get<0>(it.second));
327       Node *node(std::get<1>(it.second));
328       auto newNode(std::get<2>(it.second).get());
329       pt->setNode(newNode);
330     }
331   for(auto it : *m)
332     {
333       ElementaryPoint *pt(std::get<0>(it.second));
334       Node *node(std::get<1>(it.second));
335       auto newNode(std::get<2>(it.second).get());
336       if(containsPtsToKill(ptsToKill,newNode))
337         continue;
338       for(auto it2 : node->getOutGate()->edSetInGate())
339         {
340           Node *nodeFwd(it2->getNode());
341           std::string nodeFwdName(nodeFwd->getName());
342           auto it3(m->find(nodeFwdName));
343           if(it3!=m->end())
344             {
345               Node *nodeFwdNew = std::get<2>(it3->second).get();
346               if(!containsPtsToKill(ptsToKill,newNode))
347                 {
348                   newNode->getOutGate()->edAddInGate(nodeFwdNew->getInGate());
349                 }
350               //else
351               // node after nodeFwd is not in m fall into \a ptToKill
352               // -> ignore link.
353             }
354           //else
355           // node after nodeFwd is not in m. Typically because nodeFwd has not been put in m
356           // concretely : do not link incoming links to Node * inside ptToKill
357         }
358     }
359 }
360
361 /*!
362  * Unrewire consists into replacing newly created nodes into old one in ElementaryPoints contained in m.
363  * As CF links of old ENGINE::Node * has not be touched the CF graph is the same.
364  */
365 void AbstractPoint::UnRewire(std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > >& m)
366 {
367   for(auto it : m)
368     {
369       ElementaryPoint *pt(std::get<0>(it.second));
370       Node *node(std::get<1>(it.second));
371       pt->setNode(node);
372     }
373 }
374
375 void AbstractPoint::Display(std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m)
376 {
377   for(auto it : *m)
378     {
379       ElementaryPoint *pt(std::get<0>(it.second));
380       auto newNode(pt->getNode());
381       for(auto it2 : newNode->getOutGate()->edSetInGate())
382         {
383           std::cerr << pt->getNodeName() << " -> " << it2->getNode()->getName() << " " << newNode->typeName() << std::endl;
384         }
385     }
386 }
387
388 /*!
389  * This methods tries to deal with \a sop that can t be considered as a composite of Link, Fork.
390  * 
391  * Do do so, this methods tries to exclude \a this from \a sop and then analyze if the graph can be decomposited into Links and Forks. If yes \a somethingDone is set to true and \a nodes is updated in consequence.
392  * 
393  * If the algorithm fails \a nodes are let untouched and \a somethingDone is let false.
394  *
395  */
396 void AbstractPoint::TryAsNotSimpleCase(AbstractPoint *father, const std::vector<AbstractPoint *>& ptsToKill, std::list<AbstractPoint *>& nodes, bool& somethingDone)
397 {
398   std::list<AbstractPoint *> lp2;
399   for(auto it : nodes)
400     {
401       if(std::find(ptsToKill.cbegin(),ptsToKill.cend(),it)==ptsToKill.cend())
402         lp2.push_back(it->deepCopy(nullptr));
403     }
404   BagPoint *tmp(new BagPoint(lp2,nullptr));
405   for(auto it : lp2)
406     it->setFather(tmp);
407   SetOfPoints sopTest(tmp);
408   std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > m;
409   FeedData(tmp,&m);
410   Rewire(ptsToKill,&m);
411   try
412     {
413       sopTest.basicSimplify();
414     }
415   catch(YACS::Exception& ex)
416     {// By removing elements in ptsToKill from this impossible to have a classical case -> un rewire to rollback nodes state
417       UnRewire(m);
418       return ;
419     }
420   AbstractPoint *pt(sopTest.getUniqueAndReleaseIt());
421   pt->setFather(father);
422   UnRewire(m);
423   for(auto it : nodes)
424     if(std::find(ptsToKill.cbegin(),ptsToKill.cend(),it)==ptsToKill.cend())
425       delete it;
426   nodes.clear();
427   nodes.push_back(pt);
428   for(auto it : ptsToKill)
429     {
430       std::list<AbstractPoint *> l; l.push_back(it);
431       nodes.push_back( new NotSimpleCasePoint(l,father) );
432     }
433   somethingDone = true;
434 }
435
436 bool AbstractPoint::IsGatherB4Ext(Node *node)
437 {
438   InGate *ing(node->getInGate());
439   return ing->getBackLinks().size()!=1;
440 }
441
442 bool AbstractPoint::isSimplyLinkedAfter(BlocPoint *sop, Node *node)
443 {
444   OutGate *oug(node->getOutGate());
445   std::list<InGate *> ings(oug->edSetInGate());
446   if(ings.size()==1)
447     return true;
448   if(ings.size()==0)
449     return false;
450   AbstractPoint *dummy=0;
451   return IsCommonDirectSonOf(sop,ings,dummy);
452 }
453
454 bool AbstractPoint::IsSimplyLinkedAfterExt(Node *node)
455 {
456   OutGate *oug(node->getOutGate());
457   return oug->edSetInGate().size()<=1;
458 }
459
460 bool AbstractPoint::IsScatterAfterExt(Node *node)
461 {
462   OutGate *oug(node->getOutGate());
463   return oug->edSetInGate().size()!=1;
464 }
465
466 bool AbstractPoint::isSimplyLinkedBefore(BlocPoint *sop, Node *node)
467 {
468   InGate *ing(node->getInGate());
469   std::list<OutGate *> outgs(ing->getBackLinks());
470   if(outgs.size()==1)
471     return true;
472   if(outgs.size()==0)
473     return false;
474   AbstractPoint *dummy=0;
475   return IsCommonDirectSonOf(sop,outgs,dummy);
476 }
477
478 bool AbstractPoint::IsSimplyLinkedBeforeExt(Node *node)
479 {
480   InGate *ing(node->getInGate());
481   return ing->getBackLinks().size()<=1;
482 }
483
484 bool AbstractPoint::IsNoLinksBefore(Node *node)
485 {
486   InGate *ing(node->getInGate());
487   return ing->getBackLinks().size()==0;
488 }
489
490 bool AbstractPoint::IsNoLinksAfter(Node *node)
491 {
492   OutGate *oug(node->getOutGate());
493   return oug->edSetInGate().size()==0;
494 }
495
496 Node *AbstractPoint::GetNodeB4(Node *node)
497 {
498   InGate *ing(node->getInGate());
499   std::list<OutGate *> bl(ing->getBackLinks());
500   if(bl.size()>1)
501     throw Exception("AbstractPoint::GetNodeB4 : precond not OK !");
502   if(bl.size()==0)
503     return 0;
504   return bl.front()->getNode();
505 }
506
507 Node *AbstractPoint::GetNodeAfter(Node *node)
508 {
509   OutGate *oug(node->getOutGate());
510   std::list<InGate *> fl(oug->edSetInGate());
511   if(fl.size()>1)
512     throw Exception("AbstractPoint::GetNodeAfter : precond not OK !");
513   if(fl.size()==0)
514     return 0;
515   return (*fl.begin())->getNode();
516 }
517
518 AbstractPoint *AbstractPoint::GetDirectSonOf(AbstractPoint *refFather, AbstractPoint *sonOrLittleSon)
519 {
520   if(!sonOrLittleSon)
521     throw YACS::Exception("AbstractPoint::GetDirectSonOf : sonOrLittleSon is null !");
522   AbstractPoint *curFath(sonOrLittleSon->getFather()),*cur(sonOrLittleSon);
523   while(curFath && curFath!=refFather)
524     {
525       cur=curFath;
526       curFath=cur->getFather();
527     }
528   if(!curFath)
529     throw YACS::Exception("AbstractPoint::GetDirectSonOf : not in the same family !");
530   return cur;
531 }
532
533 bool AbstractPoint::IsCommonDirectSonOf(AbstractPoint *refFather, const std::list<OutGate *>& outgs, AbstractPoint *&ret)
534 {
535   if(outgs.size()<1)
536     throw YACS::Exception("AbstractPoint::GetCommonDirectSonOf1 : not enough !");
537   std::list<OutGate *>::const_iterator it(outgs.begin());
538   OutGate *ref(*(it++));
539   AbstractPoint *ref2(GetDirectSonOf(refFather,refFather->findPointWithNode(ref->getNode())));
540   for(;it!=outgs.end();it++)
541     {
542       if(!ref2->contains((*it)->getNode()))
543         return false;
544     }
545   ret=ref2;
546   return true;
547 }
548
549 bool AbstractPoint::IsCommonDirectSonOf(AbstractPoint *refFather, const std::list<InGate *>& ings, AbstractPoint *&ret)
550 {
551   if(ings.size()<1)
552     throw YACS::Exception("AbstractPoint::GetCommonDirectSonOf2 : not enough !");
553   std::list<InGate *>::const_iterator it(ings.begin());
554   InGate *ref(*(it++));
555   AbstractPoint *ref2(GetDirectSonOf(refFather,refFather->findPointWithNode(ref->getNode())));
556   for(;it!=ings.end();it++)
557     {
558       if(!ref2->contains((*it)->getNode()))
559         return false;
560     }
561   ret=ref2;
562   return true;
563 }