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 
19 #include "BlockVector.hpp"
20 
21 #include <boost/numeric/ublas/vector_proxy.hpp>  // for project
22 #include <boost/numeric/ublas/vector_sparse.hpp>
23 #include <vector>
24 
25 #include "SiconosVector.hpp"
26 
27 #include "SiconosAlgebra.hpp"
28 #include "SiconosAlgebraTools.hpp" // for isComparableTo
29 #include "Tools.hpp"
30 //#define DEBUG_STDOUT
31 //#define DEBUG_MESSAGES
32 #include "siconos_debug.h"
33 #include "SiconosException.hpp"
34 
35 
36 using Siconos::Algebra::isComparableTo;
37 
38 // =================================================
39 //                CONSTRUCTORS
40 // =================================================
BlockVector()41 BlockVector::BlockVector()
42 {
43   _tabIndex.reset(new Index());
44 }
45 
BlockVector(const BlockVector & v)46 BlockVector::BlockVector(const BlockVector &v)
47 {
48   Index::size_type nbBlocks = v.numberOfBlocks();
49   _tabIndex.reset(new Index());
50   _tabIndex->reserve(nbBlocks);
51   _vect.reserve(nbBlocks);
52   VectorOfVectors::const_iterator it;
53   for(it = v.begin(); it != v.end(); ++it)
54   {
55     _vect.push_back(std::shared_ptr<SiconosVector>(new SiconosVector(**it))) ;
56     _sizeV += (*it)->size();
57     _tabIndex->push_back(_sizeV);
58   }
59 }
60 
BlockVector(SP::SiconosVector v1,SP::SiconosVector v2)61 BlockVector::BlockVector(SP::SiconosVector v1, SP::SiconosVector v2)
62 {
63   // Insert the two vectors in the container
64   // NO COPY !!
65   if(! v1  && ! v2)
66     THROW_EXCEPTION("both vectors are nullptr.");
67 
68   _tabIndex.reset(new Index());
69 
70   _tabIndex->reserve(2);
71   _vect.reserve(2);
72 
73   if(v1)
74   {
75     _vect.push_back(v1);
76     _sizeV = v1->size();
77     _tabIndex->push_back(_sizeV);
78 
79   }
80   else
81     // If first parameter is a nullptr pointer, then set this(1) to a SiconosVector of the same size as v2, and equal to 0.
82   {
83     // This case is usefull to set xDot in LagrangianDS.
84     _sizeV = v2->size();
85 
86     _vect.push_back(std::shared_ptr<SiconosVector>(new SiconosVector(_sizeV)));
87     _tabIndex->push_back(_sizeV);
88 
89   }
90   if(v2)
91   {
92     _vect.push_back(v2);
93     _sizeV += v2->size();
94     _tabIndex->push_back(_sizeV);
95 
96   }
97   else // If second parameter is a nullptr pointer, then set this(2) to a SiconosVector of the same size as v1, and equal to 0.
98   {
99     // This case is usefull to set xDot in LagrangianDS.
100 
101     _vect.push_back(std::shared_ptr<SiconosVector>(new SiconosVector(v1->size())));
102     _sizeV += v1->size();
103     _tabIndex->push_back(_sizeV);
104   }
105 }
106 
BlockVector(unsigned int numberOfBlocks,unsigned int dim)107 BlockVector::BlockVector(unsigned int numberOfBlocks, unsigned int dim)
108 {
109   _tabIndex.reset(new Index());
110   _tabIndex->reserve(numberOfBlocks);
111   _vect.reserve(numberOfBlocks);
112   for(unsigned int i = 0; i < numberOfBlocks; ++i)
113   {
114     _vect.push_back(std::shared_ptr<SiconosVector>(new SiconosVector(dim)));
115     _tabIndex->push_back(dim * (i + 1));
116   }
117   _sizeV = dim * numberOfBlocks;
118 }
119 
BlockVector(unsigned int numberOfBlocks)120 BlockVector::BlockVector(unsigned int numberOfBlocks)
121 {
122   _tabIndex.reset(new Index());
123   _tabIndex->resize(numberOfBlocks);
124   _vect.resize(numberOfBlocks);
125 }
126 
127 // ===========================
128 //      private method
129 // ===========================
130 
_update()131 void BlockVector::_update()
132 {
133   _sizeV=0;
134   _tabIndex.reset(new Index());
135 
136   VectorOfVectors::iterator it;
137   for(it = _vect.begin(); it != _vect.end(); ++it)
138   {
139     if(*it)
140     {
141       _sizeV += (*it)->size();
142     }
143     _tabIndex->push_back(_sizeV);
144   }
145 }
146 
147 // ===========================
148 //       fill vector
149 // ===========================
150 
isDense() const151 bool BlockVector::isDense() const
152 {
153   return std::find_if(_vect.begin(), _vect.end(), TestDense()) != _vect.end();
154 }
155 
zero()156 void BlockVector::zero()
157 {
158   VectorOfVectors::iterator it;
159   for(it = _vect.begin(); it != _vect.end(); ++it)
160     (*it)->zero();
161 }
162 
fill(double value)163 void BlockVector::fill(double value)
164 {
165   VectorOfVectors::iterator it;
166   for(it = _vect.begin(); it != _vect.end(); ++it)
167     if((*it))(*it)->fill(value);
168 }
169 
170 //=====================
171 // screen display
172 //=====================
173 
display() const174 void BlockVector::display() const
175 {
176   VectorOfVectors::const_iterator it;
177   std::cout << "=======> Block Vector Display (" << _tabIndex->size() << " block(s)): " << std::endl;
178   for(it = _vect.begin(); it != _vect.end(); ++it)
179   {
180     DEBUG_EXPR(std::cout <<"(*it)" << (*it) << std::endl;);
181     if(*it)
182       (*it)->display();
183     else
184       std::cout << "(*it)-> nullptr" <<std::endl;
185   }
186 }
187 
188 //=====================
189 // convert to a string
190 //=====================
191 
toString() const192 std::string BlockVector::toString() const
193 {
194   return ::toString(*this);
195 }
196 
197 //=====================
198 // convert to an ostream
199 //=====================
200 
operator <<(std::ostream & os,const BlockVector & bv)201 std::ostream& operator<<(std::ostream& os, const BlockVector& bv)
202 {
203   VectorOfVectors::const_iterator it;
204   os << "[" << bv._vect.size() << "](";
205   for(it = bv._vect.begin(); it != bv._vect.end(); ++it)
206   {
207     if(it != bv._vect.begin()) os << ",";
208     if(*it) os << **it;
209     else os << "(nil)";
210   }
211   os << ")";
212   return os;
213 }
214 
215 //=============================
216 // Elements access (get or set)
217 //=============================
218 
getValue(unsigned int pos) const219 double BlockVector::getValue(unsigned int pos) const
220 {
221   unsigned int blockNum = 0;
222 
223   while(pos >= (*_tabIndex)[blockNum] && blockNum < _tabIndex->size())
224     blockNum ++;
225 
226   unsigned int relativePos = pos;
227 
228   if(blockNum != 0)
229     relativePos -= (*_tabIndex)[blockNum - 1];
230 
231   return (*_vect[blockNum])(relativePos);
232 }
233 
setValue(unsigned int pos,double value)234 void BlockVector::setValue(unsigned int pos, double value)
235 {
236   unsigned int blockNum = 0;
237 
238   while(pos >= (*_tabIndex)[blockNum] && blockNum < _tabIndex->size())
239     blockNum ++;
240 
241   unsigned int relativePos = pos;
242 
243   if(blockNum != 0)
244     relativePos -= (*_tabIndex)[blockNum - 1];
245 
246   (*_vect[blockNum])(relativePos) = value;
247 }
248 
operator ()(unsigned int pos)249 double& BlockVector::operator()(unsigned int pos)
250 {
251   unsigned int blockNum = 0;
252 
253   while(pos >= (*_tabIndex)[blockNum] && blockNum < _tabIndex->size())
254     blockNum ++;
255 
256   unsigned int relativePos = pos;
257 
258   if(blockNum != 0)
259     relativePos -= (*_tabIndex)[blockNum - 1];
260 
261   return (*_vect[blockNum])(relativePos);
262 }
263 
operator ()(unsigned int pos) const264 double BlockVector::operator()(unsigned int pos) const
265 {
266   return getValue(pos);
267 }
268 
269 //============================================
270 // Access (get or set) to blocks of elements
271 //============================================
272 
273 
setVector(unsigned int pos,const SiconosVector & v)274 void BlockVector::setVector(unsigned int pos, const SiconosVector& v)
275 {
276   assert(pos < _vect.size() && "insertion out of vector size");
277   if(! _vect[pos])
278     THROW_EXCEPTION("this[pos] == nullptr pointer.");
279   *_vect[pos] = v ;
280 }
281 
setVectorPtr(unsigned int pos,SP::SiconosVector v)282 void BlockVector::setVectorPtr(unsigned int pos, SP::SiconosVector v)
283 {
284   assert(pos < _vect.size() && "insertion out of vector size");
285   _vect[pos] = v;
286   _update();
287 }
288 
setAllVect(VectorOfVectors & v)289 void BlockVector::setAllVect(VectorOfVectors& v)
290 {
291   _vect = v;
292   _update();
293 }
294 
295 // SP::SiconosVector BlockVector::operator [](unsigned int pos)
296 // {
297 //   return  _vect[pos];
298 // }
299 
300 // SPC::SiconosVector BlockVector::operator [](unsigned int pos) const
301 // {
302 //   return  _vect[pos];
303 // }
304 
getNumVectorAtPos(unsigned int pos) const305 unsigned int BlockVector::getNumVectorAtPos(unsigned int pos) const
306 {
307   unsigned int blockNum = 0;
308 
309   while(pos >= (*_tabIndex)[blockNum] && blockNum < _tabIndex->size() - 1)
310     blockNum ++;
311   return blockNum;
312 }
313 
314 
operator =(const BlockVector & vIn)315 BlockVector& BlockVector::operator = (const BlockVector& vIn)
316 {
317   if(&vIn == this) return *this;
318   else
319   {
320     if(isComparableTo(*this, vIn))  // if vIn and this are "block-consistent"
321     {
322       VectorOfVectors::iterator it1;
323       VectorOfVectors::const_iterator it2 = vIn.begin();
324 
325       for(it1 = _vect.begin(); it1 != _vect.end(); ++it1)
326       {
327         (**it1) = (**it2);
328         it2++;
329       }
330     }
331     else
332     {
333       for(unsigned int i = 0; i < _sizeV; ++i)
334         (*this)(i) = vIn(i);
335     }
336     return *this;
337   }
338 }
339 
operator =(const double * data)340 BlockVector& BlockVector::operator = (const double* data)
341 {
342   VectorOfVectors::iterator it1;
343   unsigned indxPos = 0;
344 
345   for(it1 = _vect.begin(); it1 != _vect.end(); ++it1)
346   {
347     SiconosVector& v = **it1;
348     v = &data[indxPos];
349     indxPos += v.size();
350   }
351   return *this;
352 }
353 
354 
operator -=(const BlockVector & vIn)355 BlockVector& BlockVector::operator -= (const BlockVector& vIn)
356 {
357   if(isComparableTo(*this, vIn))  // if vIn and this are "block-consistent"
358   {
359     unsigned int i = 0;
360     VectorOfVectors::iterator it1;
361 
362     for(it1 = _vect.begin(); it1 != _vect.end(); ++it1)
363       **it1 -= *(vIn.vector(i++));
364   }
365   else // use of a temporary SimpleVector... bad way, to be improved. But this case happens rarely ...
366   {
367     for(unsigned int i = 0; i < _sizeV; ++i)
368       (*this)(i) -= vIn(i);
369   }
370   return *this;
371 }
372 
operator -=(const SiconosVector & vIn)373 BlockVector& BlockVector::operator -= (const SiconosVector& vIn)
374 {
375   unsigned int dim = vIn.size(); // size of the block to be added.
376   if(dim > _sizeV) THROW_EXCEPTION("invalid ranges");
377 
378   VectorOfVectors::const_iterator it;
379   Siconos::UBLAS_TYPE numVIn = vIn.num();
380   unsigned int currentSize;
381   Siconos::UBLAS_TYPE currentNum;
382   unsigned int index = 0;
383   for(it = _vect.begin(); it != _vect.end(); ++it)
384   {
385     currentSize = (*it)->size();
386     currentNum = (*it)->num();
387     if(numVIn != currentNum)
388       THROW_EXCEPTION("inconsistent types.");
389     if(numVIn == Siconos::DENSE)
390       noalias(*(*it)->dense()) -=  ublas::subrange(*vIn.dense(), index, index + currentSize) ;
391     else
392       noalias(*(*it)->sparse()) -=  ublas::subrange(*vIn.sparse(), index, index + currentSize) ;
393     index += currentSize;
394   }
395   return *this;
396 }
397 
operator +=(const BlockVector & vIn)398 BlockVector& BlockVector::operator += (const BlockVector& vIn)
399 {
400   if(isComparableTo(*this, vIn))  // if vIn and this are "block-consistent"
401   {
402     unsigned int i = 0;
403     VectorOfVectors::iterator it1;
404 
405     for(it1 = _vect.begin(); it1 != _vect.end(); ++it1)
406       **it1 += *(vIn.vector(i++));
407   }
408   else // use of a temporary SimpleVector... bad way, to be improved. But this case happens rarely ...
409   {
410     for(unsigned int i = 0; i < _sizeV; ++i)
411       (*this)(i) += vIn(i);
412   }
413   return *this;
414 }
415 
operator +=(const SiconosVector & vIn)416 BlockVector& BlockVector::operator += (const SiconosVector& vIn)
417 {
418   // Add a part of vIn (starting from index) to the current vector.
419   // vIn must be a SimpleVector.
420 
421   // At the end of the present function, index is equal to index + the dim. of the added sub-vector.
422 
423   unsigned int dim = vIn.size(); // size of the block to be added.
424   if(dim > _sizeV) THROW_EXCEPTION("invalid ranges");
425 
426   VectorOfVectors::const_iterator it;
427   Siconos::UBLAS_TYPE numVIn = vIn.num(), currentNum;
428   unsigned int currentSize;
429   unsigned int index = 0;
430 
431   for(it = _vect.begin(); it != _vect.end(); ++it)
432   {
433     currentSize = (*it)->size();
434     currentNum = (*it)->num();
435     if(numVIn != currentNum) THROW_EXCEPTION("inconsistent types.");
436     if(numVIn == Siconos::DENSE)
437       noalias(*(*it)->dense()) += ublas::subrange(*vIn.dense(), index, index + currentSize) ;
438     else
439       noalias(*(*it)->sparse()) += ublas::subrange(*vIn.sparse(), index, index + currentSize) ;
440     index += currentSize;
441   }
442   return *this;
443 }
444 
445 // void BlockVector::insert(const  SiconosVector& v)
446 // {
447 //   _sizeV += v.size();
448 
449 //   _vect.push_back(std::shared_ptr<SiconosVector>(new SiconosVector(v))); // Copy
450 
451 //   _tabIndex->push_back(_sizeV);
452 // }
453 
insertPtr(SP::SiconosVector v)454 void BlockVector::insertPtr(SP::SiconosVector v)
455 {
456   if(!v)
457     THROW_EXCEPTION("v is a nullptr vector.");
458 
459   _sizeV += v->size();
460   _vect.push_back(v);
461   _tabIndex->push_back(_sizeV);
462 }
463 
setBlock(const SiconosVector & vIn,unsigned int sizeB,unsigned int startIn,unsigned int startOut)464 void BlockVector::setBlock(const SiconosVector& vIn, unsigned int sizeB, unsigned int startIn, unsigned int startOut)
465 {
466   // Check dim ...
467   unsigned int endOut = startOut + sizeB;
468 
469   assert(startIn < vIn.size());
470   assert(startOut < size());
471   assert((startIn + sizeB) <= vIn.size());
472   assert(endOut <= size());
473 
474   // We look for the block of vOut that include index startOut
475   unsigned int blockOutStart = 0;
476   while(startOut >= (*_tabIndex)[blockOutStart] && blockOutStart < _tabIndex->size())
477     blockOutStart++;
478   // Relative position in the block blockOutStart.
479   unsigned int posOut = startOut;
480   if(blockOutStart != 0)
481     posOut -= (*_tabIndex)[blockOutStart - 1];
482 
483   // We look for the block of vOut that include index endOut
484   unsigned int blockOutEnd = blockOutStart;
485   while(endOut > (*_tabIndex)[blockOutEnd] && blockOutEnd < _tabIndex->size())
486     blockOutEnd ++;
487 
488   // => the block to be set runs from block number blockOutStart to block number blockOutEnd.
489 
490   if(blockOutEnd == blockOutStart)  //
491   {
492     vIn.toBlock(*_vect[blockOutStart], sizeB, startIn, posOut);
493   }
494   else // More that one block of vOut are concerned
495   {
496 
497     // The current considered block ...
498     SP::SiconosVector currentBlock = _vect[blockOutStart];
499 
500     // Size of the subBlock of vOut to be set.
501     size_t subSizeB = currentBlock->size() - posOut;
502     unsigned int posIn = startIn;
503 
504     // Set first sub-block (currentBlock) values, between index posOut and posOut+subSizeB,
505     // with vIn values from posIn to posIn+subSizeB.
506     vIn.toBlock(*currentBlock, subSizeB, posIn, posOut);
507 
508     // Other blocks, except number blockOutEnd.
509     unsigned int currentBlockNum = blockOutStart + 1;
510     while(currentBlockNum != blockOutEnd)
511     {
512       posIn += subSizeB;
513       currentBlock = _vect[currentBlockNum];
514       subSizeB = currentBlock->size();
515       vIn.toBlock(*currentBlock, subSizeB, posIn, 0);
516       currentBlockNum++;
517     }
518     // set last subBlock ...
519     currentBlock = _vect[blockOutEnd];
520 
521     posIn += subSizeB;
522 
523     // Size of the considered sub-block
524     subSizeB = endOut - (*_tabIndex)[blockOutEnd - 1];
525 
526     vIn.toBlock(*currentBlock, subSizeB, posIn, 0);
527   }
528 
529 }
530 
norm2() const531 double BlockVector::norm2() const
532 {
533   double d = 0;
534   VectorOfVectors::const_iterator it;
535   for(it = _vect.begin(); it != _vect.end(); ++it)
536   {
537     assert(*it);
538     d += pow((*it)->norm2(), 2);
539   }
540   return sqrt(d);
541 }
542 
normInf() const543 double BlockVector::normInf() const
544 {
545   double d = 0;
546   VectorOfVectors::const_iterator it;
547   for(it = _vect.begin(); it != _vect.end(); ++it)
548   {
549     assert(*it);
550     d = fmax((*it)->normInf(), d);
551   }
552   return d;
553 }
554 
555 
556 
prepareVectorForPlugin() const557 SP::SiconosVector BlockVector::prepareVectorForPlugin() const
558 {
559   {
560     if(_tabIndex->size()> 1)
561     {
562       SP::SiconosVector copy(new SiconosVector(*this));
563       return copy;
564     }
565     else
566     {
567       // No copy, just a ref.
568       return _vect[0];
569     }
570   }
571 }
572 
573 
574 
575 
operator =(const SiconosVector & vIn)576 BlockVector& BlockVector::operator =(const SiconosVector& vIn)
577 {
578   setBlock(vIn, _sizeV, 0, 0);
579   return *this;
580 }
581 
operator *=(double s)582 BlockVector& BlockVector::operator *= (double s)
583 {
584   VectorOfVectors::iterator it;
585   for(it = begin(); it != end(); ++it)
586     (**it) *= s;
587   return *this;
588 }
589 
operator /=(double s)590 BlockVector& BlockVector::operator /= (double s)
591 {
592   VectorOfVectors::iterator it;
593   for(it = begin(); it != end(); ++it)
594     (**it) /= s;
595   return *this;
596 }
597