1 /* Siconos is a program dedicated to modeling, simulation and control
2  * of non smooth dynamical systems.
3  *
4  * Copyright 2021 INRIA.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17 */
18 #include "Topology.hpp"
19 #include "SiconosException.hpp"
20 #include "NonSmoothLaw.hpp"
21 #include "NonSmoothDynamicalSystem.hpp"
22 #include "Interaction.hpp"
23 #include "EqualityConditionNSL.hpp"
24 #include "OneStepIntegrator.hpp"
25 
26 #if (__cplusplus >= 201103L) && !defined(USE_BOOST_FOR_CXX11)
27 #include <functional>
28 #else
29 #include <boost/bind.hpp>
30 #endif
31 
32 
33 #include <algorithm>
34 #include <limits>
35 
36 //#define DEBUG_STDOUT
37 //#define DEBUG_MESSAGES 1
38 #include "siconos_debug.h"
39 
40 #define MAX_RELATIVE_DEGREE 999
41 
42 // --- CONSTRUCTORS/DESTRUCTOR ---
43 
44 // default
Topology()45 Topology::Topology()
46 {
47   _IG.resize(1);
48   _DSG.resize(1);
49 
50   _IG[0].reset(new InteractionsGraph());
51   _DSG[0].reset(new DynamicalSystemsGraph());
52 
53   _IG[0]->update_vertices_indices();
54   _IG[0]->update_edges_indices();
55 }
56 
57 // destructor
~Topology()58 Topology::~Topology()
59 {
60   clear();
61 }
62 
63 std::pair<DynamicalSystemsGraph::EDescriptor, InteractionsGraph::VDescriptor>
__addInteractionInIndexSet0(SP::Interaction inter,SP::DynamicalSystem ds1,SP::DynamicalSystem ds2)64 Topology::__addInteractionInIndexSet0(SP::Interaction inter, SP::DynamicalSystem ds1, SP::DynamicalSystem ds2)
65 {
66   // !! Private function !!
67   //
68   // This function must
69   // - insert interaction and ds into IG/DSG
70   // - update graph properties related to modeling (DSlink ...)
71   //
72   // Expected result : all interaction methods can be safely called after a call
73   // to this function (whatever the simulation is, if it exists or not).
74 
75   // Update total number of constraints
76   _numberOfConstraints += inter->nonSmoothLaw()->size();
77 
78   SP::DynamicalSystem ds2_ = ds2;
79   // _DSG is the hyper forest : (vertices : dynamical systems, edges :
80   // Interactions)
81   //
82   // _IG is the hyper graph : (vertices : Interactions, edges :
83   // dynamical systems)
84   assert(_DSG[0]->edges_number() == _IG[0]->size());
85 
86   // _IG = L(_DSG),  L is the line graph transformation
87   // vector of the Interaction
88   DynamicalSystemsGraph::VDescriptor dsgv1, dsgv2;
89   dsgv1 = _DSG[0]->add_vertex(ds1);
90 
91   if(ds2)
92   {
93     dsgv2 = _DSG[0]->add_vertex(ds2);
94   }
95   else
96   {
97     dsgv2 = dsgv1;
98     ds2_ = ds1;
99   }
100 
101   // this may be a multi edges graph
102   assert(!_DSG[0]->is_edge(dsgv1, dsgv2, inter));
103   assert(!_IG[0]->is_vertex(inter));
104   InteractionsGraph::VDescriptor ig_new_ve;
105   DynamicalSystemsGraph::EDescriptor new_ed;
106   std::tie(new_ed, ig_new_ve) = _DSG[0]->add_edge(dsgv1, dsgv2, inter, *_IG[0]);
107 
108   inter->initializeLinkToDsVariables(*ds1, *ds2_);
109 
110   // add self branches in vertex properties
111   // note : boost graph SEGFAULT on self branch removal
112   // see https://svn.boost.org/trac/boost/ticket/4622
113   _IG[0]->properties(ig_new_ve).source = ds1;
114   _IG[0]->properties(ig_new_ve).source_pos = 0;
115 
116   if(!ds2) // self loop in ds graph, source=target in interaction graph
117   {
118     _IG[0]->properties(ig_new_ve).target = ds1;
119     _IG[0]->properties(ig_new_ve).target_pos = 0;
120   }
121   else
122   {
123     _IG[0]->properties(ig_new_ve).target = ds2;
124     _IG[0]->properties(ig_new_ve).target_pos = ds1->dimension();
125   }
126 
127   assert(_IG[0]->bundle(ig_new_ve) == inter);
128   assert(_IG[0]->is_vertex(inter));
129   assert(_DSG[0]->is_edge(dsgv1, dsgv2, inter));
130   assert(_DSG[0]->edges_number() == _IG[0]->size());
131 
132 
133 
134 
135   return std::pair<DynamicalSystemsGraph::EDescriptor, InteractionsGraph::VDescriptor>(new_ed, ig_new_ve);
136 }
137 
138 /* an edge is removed from _DSG graph if the corresponding vertex is
139    removed from the adjoint graph (_IG)
140 */
141 struct VertexIsRemoved
142 {
VertexIsRemovedVertexIsRemoved143   VertexIsRemoved(SP::Interaction I,
144                   SP::DynamicalSystemsGraph sg, SP::InteractionsGraph asg) :
145     _I(I), __DSG(sg), __IG(asg) {};
operator ()VertexIsRemoved146   bool operator()(DynamicalSystemsGraph::EDescriptor ed)
147   {
148 
149     if(__IG->is_vertex(__DSG->bundle(ed)))
150     {
151       InteractionsGraph::VDescriptor ivd = __IG->descriptor(__DSG->bundle(ed));
152 
153       if(__IG->bundle(ivd) == _I)
154       {
155         __IG->remove_vertex(__DSG->bundle(ed));
156 
157         assert(__IG->size() == __DSG->edges_number() - 1);
158 
159         return true;
160       }
161       else
162       {
163         return false;
164       }
165     }
166     else
167     {
168       return true;
169     }
170   }
171   SP::Interaction _I;
172   SP::DynamicalSystemsGraph __DSG;
173   SP::InteractionsGraph __IG;
174 };
175 
176 /* an edge is removed from _DSG graph if the corresponding vertex is
177    removed from the adjoint graph (_IG)
178 */
179 struct VertexIsRemovedDS
180 {
VertexIsRemovedDSVertexIsRemovedDS181   VertexIsRemovedDS(SP::DynamicalSystem ds,
182                     SP::DynamicalSystemsGraph sg, SP::InteractionsGraph asg) :
183     _ds(ds), __DSG(sg), __IG(asg) {};
operator ()VertexIsRemovedDS184   bool operator()(DynamicalSystemsGraph::EDescriptor ed)
185   {
186     if(__IG->is_vertex(__DSG->bundle(ed)))
187     {
188       InteractionsGraph::VDescriptor ivd = __IG->descriptor(__DSG->bundle(ed));
189 
190       if(__IG->properties(ivd).source == _ds
191           || __IG->properties(ivd).target == _ds)
192       {
193         __IG->remove_vertex(__DSG->bundle(ed));
194 
195         assert(__IG->size() == __DSG->edges_number() - 1);
196 
197         return true;
198       }
199       else
200       {
201         return false;
202       }
203     }
204     else
205     {
206       return true;
207     }
208   }
209   SP::DynamicalSystem _ds;
210   SP::DynamicalSystemsGraph __DSG;
211   SP::InteractionsGraph __IG;
212 };
213 
214 /* remove an interaction : remove edges (Interaction) from _DSG if
215    corresponding vertices are removed from _IG */
__removeInteractionFromIndexSet(SP::Interaction inter)216 void Topology::__removeInteractionFromIndexSet(SP::Interaction inter)
217 {
218 
219   SP::DynamicalSystem ds1 = _IG[0]->properties(_IG[0]->descriptor(inter)).source;
220   SP::DynamicalSystem ds2 = _IG[0]->properties(_IG[0]->descriptor(inter)).target;
221   _DSG[0]->remove_out_edge_if(_DSG[0]->descriptor(ds1), VertexIsRemoved(inter, _DSG[0], _IG[0]));
222   if(ds1 != ds2)
223     _DSG[0]->remove_out_edge_if(_DSG[0]->descriptor(ds2), VertexIsRemoved(inter, _DSG[0], _IG[0]));
224 }
225 
226 
insertDynamicalSystem(SP::DynamicalSystem ds)227 void Topology::insertDynamicalSystem(SP::DynamicalSystem ds)
228 {
229   _DSG[0]->add_vertex(ds);
230   setHasChanged(true);
231 }
232 
233 /* remove a dynamical system : remove edges (DynamicalSystem) from _IG if
234    corresponding vertices are removed from _DSG */
__removeDynamicalSystemFromIndexSet(SP::DynamicalSystem ds)235 void Topology::__removeDynamicalSystemFromIndexSet(SP::DynamicalSystem ds)
236 {
237   _DSG[0]->remove_edge_if(_DSG[0]->descriptor(ds),
238                           VertexIsRemovedDS(ds, _DSG[0], _IG[0]));
239 
240   // note: remove_vertex also calls clear_vertex and removes all in/out edges
241   _DSG[0]->remove_vertex(ds);
242 }
243 
244 
setName(SP::DynamicalSystem ds,const std::string & name)245 void Topology::setName(SP::DynamicalSystem ds, const std::string& name)
246 {
247   DynamicalSystemsGraph::VDescriptor dsgv = _DSG[0]->descriptor(ds);
248   _DSG[0]->name.insert(dsgv, name);
249 }
250 
name(SP::DynamicalSystem ds)251 std::string Topology::name(SP::DynamicalSystem ds)
252 {
253   DynamicalSystemsGraph::VDescriptor dsgv = _DSG[0]->descriptor(ds);
254   if(dsgv)
255     return _DSG[0]->name.at(dsgv);
256   else
257     return "";
258 }
259 
setName(SP::Interaction inter,const std::string & name)260 void Topology::setName(SP::Interaction inter, const std::string& name)
261 {
262   InteractionsGraph::VDescriptor igv = _IG[0]->descriptor(inter);
263   _IG[0]->name.insert(igv, name);
264 }
265 
name(SP::Interaction inter)266 std::string Topology::name(SP::Interaction inter)
267 {
268   InteractionsGraph::VDescriptor igv = _IG[0]->descriptor(inter);
269   if(igv)
270     return _IG[0]->name.at(igv);
271   else
272     return "";
273 }
274 
setOSI(SP::DynamicalSystem ds,SP::OneStepIntegrator OSI)275 void Topology::setOSI(SP::DynamicalSystem ds, SP::OneStepIntegrator OSI)
276 {
277   _DSG[0]->properties(_DSG[0]->descriptor(ds)).osi = OSI;
278 }
279 
setControlProperty(SP::Interaction inter,const bool isControlInteraction)280 void Topology::setControlProperty(SP::Interaction inter,
281                                   const bool isControlInteraction)
282 {
283   InteractionsGraph::VDescriptor ivd = _IG[0]->descriptor(inter);
284   DynamicalSystemsGraph::VDescriptor dvd = _DSG[0]->descriptor(_IG[0]->properties(ivd).target);
285   SP::Interaction interG;
286   DynamicalSystemsGraph::OEIterator oei, oeiend;
287   for(std::tie(oei, oeiend) = _DSG[0]->out_edges(dvd); oei != oeiend; ++oei)
288   {
289     interG = _DSG[0]->bundle(*oei);
290     if(inter == interG)
291     {
292       _DSG[0]->properties(*oei).forControl = isControlInteraction;
293       break;
294     }
295   }
296   _IG[0]->properties(ivd).forControl = isControlInteraction;
297 }
298 
indexSet(unsigned int num) const299 SP::InteractionsGraph Topology::indexSet(unsigned int num) const
300 {
301   if(num >= _IG.size())
302   {
303     THROW_EXCEPTION("Topology::indexSet: indexSet does not exist");
304   }
305   assert(num < _IG.size()) ;
306   return _IG[num];
307 };
308 
removeInteraction(SP::Interaction inter)309 void Topology::removeInteraction(SP::Interaction inter)
310 {
311   DEBUG_PRINTF("removeInteraction : %p\n", &*inter);
312 
313   assert(_DSG[0]->edges_number() == _IG[0]->size());
314   __removeInteractionFromIndexSet(inter);
315   assert(_DSG[0]->edges_number() == _IG[0]->size());
316   setHasChanged(true);
317 }
318 
removeDynamicalSystem(SP::DynamicalSystem ds)319 void Topology::removeDynamicalSystem(SP::DynamicalSystem ds)
320 {
321   DEBUG_PRINTF("removeDynamicalSystem : %p\n", &*ds);
322 
323   assert(_DSG[0]->edges_number() == _IG[0]->size() && "1");
324   __removeDynamicalSystemFromIndexSet(ds);
325   assert(_DSG[0]->edges_number() == _IG[0]->size() && "2");
326   setHasChanged(true);
327 }
328 
329 
330 std::pair<DynamicalSystemsGraph::EDescriptor, InteractionsGraph::VDescriptor>
link(SP::Interaction inter,SP::DynamicalSystem ds,SP::DynamicalSystem ds2)331 Topology::link(SP::Interaction inter, SP::DynamicalSystem ds, SP::DynamicalSystem ds2)
332 {
333   DEBUG_PRINTF("Topology::link : inter %p, ds1 %p, ds2 %p\n", &*inter, &*ds,
334                &*ds2);
335 
336   // If the interaction is already in the graph remove it
337   if(indexSet0()->is_vertex(inter))
338   {
339     __removeInteractionFromIndexSet(inter);
340   }
341 
342   // Compute interaction dimension (sum of involved dynamical systems sizes)
343   unsigned int sumOfDSSizes = 0;
344   sumOfDSSizes += ds->dimension();
345   if(ds2)
346   {
347     sumOfDSSizes += ds2->dimension();
348     inter->setHas2Bodies(true);
349   }
350   inter->setDSSizes(sumOfDSSizes);
351 
352   return __addInteractionInIndexSet0(inter, ds, ds2);
353 }
354 
hasInteraction(SP::Interaction inter) const355 bool Topology::hasInteraction(SP::Interaction inter) const
356 {
357   return indexSet0()->is_vertex(inter);
358 }
359 
hasDynamicalSystem(SP::DynamicalSystem ds) const360 bool Topology::hasDynamicalSystem(SP::DynamicalSystem ds) const
361 {
362   return _DSG[0]->is_vertex(ds);
363 }
364 
setProperties()365 void Topology::setProperties()
366 {
367   _IG[0]->update_vertices_indices();
368   _IG[0]->update_edges_indices();
369 
370   for(unsigned int i = 1; i < _IG.size(); ++i)
371   {
372     // .. global properties may be defined here with
373     // InteractionsSubGraphProperties(), see SiconosProperties.hpp
374     // VertexSubProperties or EdgeSubProperties and the macros
375     // INSTALL_GRAPH_PROPERTIES
376 
377     _IG[i]->properties().symmetric = _symmetric;
378 
379     _IG[i]->update_vertices_indices();
380     _IG[i]->update_edges_indices();
381   }
382 
383   _DSG[0]->properties().symmetric = _symmetric;
384 
385   _DSG[0]->update_vertices_indices();
386   _DSG[0]->update_edges_indices();
387 
388 }
389 
clear()390 void Topology::clear()
391 {
392   _IG.clear();
393   _DSG.clear();
394 }
395 
getDynamicalSystem(unsigned int requiredNumber) const396 SP::DynamicalSystem Topology::getDynamicalSystem(unsigned int requiredNumber) const
397 {
398   DynamicalSystemsGraph::VIterator vi, vdend;
399   SP::DynamicalSystem ds;
400   unsigned int currentNumber;
401   for(std::tie(vi, vdend) = _DSG[0]->vertices(); vi != vdend; ++vi)
402   {
403     ds = _DSG[0]->bundle(*vi);
404     currentNumber = ds->number();
405     if(currentNumber == requiredNumber)
406       return ds;
407   }
408 
409   THROW_EXCEPTION("Topology::getDynamicalSystem(n) ds not found.");
410 
411   return ds;
412 }
413 
414 
displayDynamicalSystems() const415 void Topology::displayDynamicalSystems() const
416 {
417   DynamicalSystemsGraph::VIterator vi, vdend;
418   SP::DynamicalSystem ds;
419   unsigned int currentNumber;
420   for(std::tie(vi, vdend) = _DSG[0]->vertices(); vi != vdend; ++vi)
421   {
422     ds = _DSG[0]->bundle(*vi);
423     currentNumber = ds->number();
424     std::cout << "Dynamical system number : " << currentNumber << std::endl;
425     ds->display();
426   }
427 }
428 
getDynamicalSystem(std::string name) const429 SP::DynamicalSystem Topology::getDynamicalSystem(std::string name) const
430 {
431   DynamicalSystemsGraph::VIterator vi, vdend;
432   for(std::tie(vi, vdend) = _DSG[0]->vertices(); vi != vdend; ++vi)
433   {
434     if(name == _DSG[0]->name.at(*vi))
435       return _DSG[0]->bundle(*vi);
436   }
437 
438   THROW_EXCEPTION("Topology::getDynamicalSystem() ds not found.");
439 
440   return SP::DynamicalSystem();
441 }
442 
443 
numberOfInvolvedDS(unsigned int inumber)444 unsigned int Topology::numberOfInvolvedDS(unsigned int inumber)
445 {
446   if(inumber >= _IG.size())
447   {
448     THROW_EXCEPTION("Topology::numberOfInvolvedDS :: index number must be smaller than the number of indexSets");
449   }
450 
451   /* on an adjoint graph a dynamical system may be on several edges */
452   std::map<SP::DynamicalSystem, bool> flag;
453 
454   unsigned int return_value = 0;
455 
456   SP::InteractionsGraph indexSet = _IG[inumber];
457 
458   InteractionsGraph::VIterator vi, viend;
459   for(std::tie(vi, viend) = indexSet->vertices();
460       vi != viend; ++vi)
461   {
462     if(indexSet->properties(*vi).source)
463     {
464       if(flag.find(indexSet->properties(*vi).source) == flag.end())
465       {
466         flag[indexSet->properties(*vi).source] = true;
467         return_value++;
468       }
469     }
470     if(indexSet->properties(*vi).target)
471     {
472       if(flag.find(indexSet->properties(*vi).target) == flag.end())
473       {
474         flag[indexSet->properties(*vi).target] = true;
475         return_value++;
476       }
477     }
478   }
479 
480   InteractionsGraph::EIterator ei, eiend;
481 
482   for(std::tie(ei, eiend) = indexSet->edges();
483       ei != eiend; ++ei)
484   {
485     if(flag.find(indexSet->bundle(*ei)) == flag.end())
486     {
487       flag[indexSet->bundle(*ei)] = true;
488       return_value++;
489     }
490   }
491 
492   return return_value;
493 }
494 
getInteraction(unsigned int requiredNumber) const495 SP::Interaction Topology::getInteraction(unsigned int requiredNumber) const
496 {
497   InteractionsGraph::VIterator vi, vdend;
498   SP::Interaction inter;
499   unsigned int currentNumber;
500   for(std::tie(vi, vdend) = _IG[0]->vertices(); vi != vdend; ++vi)
501   {
502     inter = _IG[0]->bundle(*vi);
503     currentNumber = inter->number();
504     if(currentNumber == requiredNumber)
505       return inter;
506   }
507 
508   return inter;
509 }
510 
getInteraction(std::string name) const511 SP::Interaction Topology::getInteraction(std::string name) const
512 {
513   DynamicalSystemsGraph::VIterator vi, vdend;
514   for(std::tie(vi, vdend) = _IG[0]->vertices(); vi != vdend; ++vi)
515   {
516     if(name == _IG[0]->name.at(*vi))
517       return _IG[0]->bundle(*vi);
518   }
519 
520   return SP::Interaction();
521 }
522 
interactionsForDS(SP::DynamicalSystem ds) const523 std::vector<SP::Interaction> Topology::interactionsForDS(
524   SP::DynamicalSystem ds) const
525 {
526   InteractionsGraph::VIterator ui, uiend;
527   SP::Interaction inter;
528   std::vector<SP::Interaction> result;
529   if(!ds) return result;
530   for(std::tie(ui, uiend) = _IG[0]->vertices(); ui != uiend; ++ui)
531   {
532     inter = _IG[0]->bundle(*ui);
533     SP::DynamicalSystem ds1 = _IG[0]->properties(_IG[0]->descriptor(inter)).source;
534     SP::DynamicalSystem ds2 = _IG[0]->properties(_IG[0]->descriptor(inter)).target;
535     if(ds == ds1 || ds == ds2)
536       result.push_back(inter);
537   }
538   return result;
539 }
540 
interactionsForPairOfDS(SP::DynamicalSystem dsA,SP::DynamicalSystem dsB) const541 std::vector<SP::Interaction> Topology::interactionsForPairOfDS(
542   SP::DynamicalSystem dsA,
543   SP::DynamicalSystem dsB) const
544 {
545   InteractionsGraph::VIterator ui, uiend;
546   SP::Interaction inter;
547   std::vector<SP::Interaction> result;
548   if(!dsA && !dsB) return result;
549   for(std::tie(ui, uiend) = _IG[0]->vertices(); ui != uiend; ++ui)
550   {
551     inter = _IG[0]->bundle(*ui);
552     SP::DynamicalSystem ds1 = _IG[0]->properties(_IG[0]->descriptor(inter)).source;
553     SP::DynamicalSystem ds2 = _IG[0]->properties(_IG[0]->descriptor(inter)).target;
554     int found = 0;
555     if(dsA == ds1)
556       found = 1;
557     else if(dsA == ds2)
558       found = 2;
559     if(found==2 && dsB != ds1)
560       found = 0;
561     else if(found==1 && dsB == ds2)
562       found = 0;
563     if(found)
564       result.push_back(inter);
565   }
566   return result;
567 }
568 
569 std::vector<SP::DynamicalSystem>
dynamicalSystemsForInteraction(SP::Interaction inter) const570 Topology::dynamicalSystemsForInteraction(
571   SP::Interaction inter) const
572 {
573   SP::DynamicalSystem ds1 = _IG[0]->properties(_IG[0]->descriptor(inter)).source;
574   SP::DynamicalSystem ds2 = _IG[0]->properties(_IG[0]->descriptor(inter)).target;
575   std::vector<SP::DynamicalSystem> result;
576   if(ds1) result.push_back(ds1);
577   if(ds2 && ds1 != ds2) result.push_back(ds2);
578   return result;
579 }
580