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