1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the class library */
4 /* SoPlex --- the Sequential object-oriented simPlex. */
5 /* */
6 /* Copyright (C) 1996-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SoPlex is distributed under the terms of the ZIB Academic Licence. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SoPlex; see the file COPYING. If not email to soplex@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16
17 /**@file ssvectorbase.h
18 * @brief Semi sparse vector.
19 */
20 #ifndef _SSVECTORBASE_H_
21 #define _SSVECTORBASE_H_
22
23 #include <assert.h>
24
25 #include "soplex/spxdefines.h"
26 #include "soplex/vectorbase.h"
27 #include "soplex/idxset.h"
28 #include "soplex/spxalloc.h"
29 #include "soplex/timer.h"
30 #include "soplex/stablesum.h"
31
32 namespace soplex
33 {
34 template < class R > class SVectorBase;
35 template < class R > class SVSetBase;
36
37 /**@brief Semi sparse vector.
38 * @ingroup Algebra
39 *
40 * This class implements semi-sparse vectors. Such are #VectorBase%s where the indices of its nonzero elements can be
41 * stored in an extra IdxSet. Only elements with absolute value > #epsilon are considered to be nonzero. Since really
42 * storing the nonzeros is not always convenient, an SSVectorBase provides two different stati: setup and not setup.
43 * An SSVectorBase being setup means that the nonzero indices are available, otherwise an SSVectorBase is just an
44 * ordinary VectorBase with an empty IdxSet. Note that due to arithmetic operation, zeros can slip in, i.e., it is
45 * only guaranteed that at least every non-zero is in the IdxSet.
46 */
47 template < class R >
48 class SSVectorBase : public VectorBase<R>, protected IdxSet
49 {
50 private:
51
52 friend class VectorBase<R>;
53 template < class S > friend class DSVectorBase;
54
55 // ------------------------------------------------------------------------------------------------------------------
56 /**@name Data */
57 ///@{
58
59 /// Is the SSVectorBase set up?
60 bool setupStatus;
61
62 /// A value x with |x| < epsilon is considered zero.
63 R epsilon;
64
65 /// Allocates enough space to accommodate \p newmax values.
66 void setMax(int newmax)
67 {
68 assert(idx != 0);
69 assert(newmax != 0);
70 assert(newmax >= IdxSet::size());
71
72 len = newmax;
73 spx_realloc(idx, len);
74 }
75
76 ///@}
77
78 public:
79
80 // ------------------------------------------------------------------------------------------------------------------
81 /**@name Status of an SSVectorBase
82 *
83 * An SSVectorBase can be set up or not. In case it is set up, its IdxSet correctly contains all indices of nonzero
84 * elements of the SSVectorBase. Otherwise, it does not contain any useful data. Whether or not an SSVectorBase is
85 * setup can be determined with the method \ref soplex::SSVectorBase::isSetup() "isSetup()".
86 *
87 * There are three methods for directly affecting the setup status of an SSVectorBase:
88 *
89 * - unSetup(): This method sets the status to ``not setup''.
90 *
91 * - setup(): This method initializes the IdxSet to the SSVectorBase's nonzero indices and sets the status to
92 * ``setup''.
93 *
94 * - forceSetup(): This method sets the status to ``setup'' without verifying that the IdxSet correctly contains all
95 * nonzero indices. It may be used when the nonzero indices have been computed externally.
96 */
97 ///@{
98
99 /// Only used in slufactor.hpp.
100 R* get_ptr()
101 {
102 return VectorBase<R>::get_ptr();
103 }
104 /// Returns the non-zero epsilon used.
105 R getEpsilon() const
106 {
107 return epsilon;
108 }
109
110 /// Changes the non-zero epsilon, invalidating the setup. */
111 void setEpsilon(R eps)
112 {
113 if(eps != epsilon)
114 {
115 epsilon = eps;
116 setupStatus = false;
117 }
118 }
119
120 /// Returns setup status.
121 bool isSetup() const
122 {
123 return setupStatus;
124 }
125
126 /// Makes SSVectorBase not setup.
127 void unSetup()
128 {
129 setupStatus = false;
130 }
131
132 /// Initializes nonzero indices for elements with absolute values above #epsilon and sets all other elements to 0.
133 void setup()
134 {
135 if(!isSetup())
136 {
137 IdxSet::clear();
138
139 int d = dim();
140 num = 0;
141
142 for(int i = 0; i < d; ++i)
143 {
144 if(VectorBase<R>::val[i] != R(0))
145 {
146 if(spxAbs(VectorBase<R>::val[i]) <= epsilon)
147 VectorBase<R>::val[i] = R(0);
148 else
149 {
150 idx[num] = i;
151 num++;
152 }
153 }
154 }
155
156 setupStatus = true;
157
158 assert(isConsistent());
159 }
160 }
161
162 /// Forces setup status.
163 void forceSetup()
164 {
165 setupStatus = true;
166 }
167
168 ///@}
169
170 // ------------------------------------------------------------------------------------------------------------------
171 /**@name Methods for setup SSVectorBases */
172 ///@{
173
174 /// Returns index of the \p n 'th nonzero element.
175 int index(int n) const
176 {
177 assert(isSetup());
178
179 return IdxSet::index(n);
180 }
181
182 /// Returns value of the \p n 'th nonzero element.
183 R value(int n) const
184 {
185 assert(isSetup());
186 assert(n >= 0 && n < size());
187
188 return VectorBase<R>::val[idx[n]];
189 }
190
191 /// Finds the position of index \p i in the #IdxSet, or -1 if \p i doesn't exist.
192 int pos(int i) const
193 {
194 assert(isSetup());
195
196 return IdxSet::pos(i);
197 }
198
199 /// Returns the number of nonzeros.
200 int size() const
201 {
202 assert(isSetup());
203
204 return IdxSet::size();
205 }
206
207 /// Adds nonzero (\p i, \p x) to SSVectorBase.
208 /** No nonzero with index \p i must exist in the SSVectorBase. */
209 void add(int i, R x)
210 {
211 assert(VectorBase<R>::val[i] == R(0));
212 assert(pos(i) < 0);
213
(1) Event deref_parm_in_call: |
Function "addIdx" dereferences "this->idx". [details] |
214 addIdx(i);
215 VectorBase<R>::val[i] = x;
216 }
217
218 /// Sets \p i 'th element to \p x.
219 void setValue(int i, R x)
220 {
221 assert(i >= 0);
222 assert(i < VectorBase<R>::dim());
223
224 if(isSetup())
225 {
226 int n = pos(i);
227
228 if(n < 0)
229 {
230 if(spxAbs(x) > epsilon)
231 IdxSet::add(1, &i);
232 }
233 else if(x == R(0))
234 clearNum(n);
235 }
236
237 VectorBase<R>::val[i] = x;
238
239 assert(isConsistent());
240 }
241
242 /// Scale \p i 'th element by a
243 void scaleValue(int i, int scaleExp)
244 {
245 assert(i >= 0);
246 assert(i < VectorBase<R>::dim());
247
248 VectorBase<R>::val[i] = spxLdexp(VectorBase<R>::val[i], scaleExp);
249
250 assert(isConsistent());
251 }
252
253 /// Clears element \p i.
254 void clearIdx(int i)
255 {
256 if(isSetup())
257 {
258 int n = pos(i);
259
260 if(n >= 0)
261 remove(n);
262 }
263
264 VectorBase<R>::val[i] = 0;
265
266 assert(isConsistent());
267 }
268
269 /// Sets \p n 'th nonzero element to 0 (index \p n must exist).
270 void clearNum(int n)
271 {
272 assert(isSetup());
273 assert(index(n) >= 0);
274
275 VectorBase<R>::val[index(n)] = 0;
276 remove(n);
277
278 assert(isConsistent());
279 }
280
281 ///@}
282
283 // ------------------------------------------------------------------------------------------------------------------
284 /**@name Methods independent of the Status */
285 ///@{
286
287 /// Returns \p i 'th value.
288 R operator[](int i) const
289 {
290 return VectorBase<R>::val[i];
291 }
292
293 /// Returns array indices.
294 const int* indexMem() const
295 {
296 return idx;
297 }
298
299 /// Returns array values.
300 const R* values() const
301 {
302 return VectorBase<R>::val.data();
303 }
304
305 /// Returns indices.
306 const IdxSet& indices() const
307 {
308 return *this;
309 }
310
311 /// Returns array indices.
312 int* altIndexMem()
313 {
314 unSetup();
315 return idx;
316 }
317
318 /// Returns array values.
319 R* altValues()
320 {
321 unSetup();
322 return VectorBase<R>::val.data();
323 }
324
325 /// Returns indices.
326 IdxSet& altIndices()
327 {
328 unSetup();
329 return *this;
330 }
331
332 ///@}
333
334 // ------------------------------------------------------------------------------------------------------------------
335 /**@name Arithmetic operations */
336 ///@{
337
338 /// Addition.
339 template < class S >
340 SSVectorBase<R>& operator+=(const VectorBase<S>& vec)
341 {
342 VectorBase<S>::operator+=(vec);
343
344 if(isSetup())
345 {
346 setupStatus = false;
347 setup();
348 }
349
350 return *this;
351 }
352
353 /// Addition.
354 template < class S >
355 SSVectorBase<R>& operator+=(const SVectorBase<S>& vec);
356
357 /// Addition.
358 template < class S >
359 SSVectorBase<R>& operator+=(const SSVectorBase<S>& vec)
360 {
361 assert(vec.isSetup());
362
363 for(int i = vec.size() - 1; i >= 0; --i)
364 VectorBase<R>::val[vec.index(i)] += vec.value(i);
365
366 if(isSetup())
367 {
368 setupStatus = false;
369 setup();
370 }
371
372 return *this;
373 }
374
375 /// Subtraction.
376 template < class S >
377 SSVectorBase<R>& operator-=(const VectorBase<S>& vec)
378 {
379 VectorBase<R>::operator-=(vec);
380
381 if(isSetup())
382 {
383 setupStatus = false;
384 setup();
385 }
386
387 return *this;
388 }
389
390 /// Subtraction.
391 template < class S >
392 SSVectorBase<R>& operator-=(const SVectorBase<S>& vec);
393
394 /// Subtraction.
395 template < class S >
396 SSVectorBase<R>& operator-=(const SSVectorBase<S>& vec)
397 {
398 if(vec.isSetup())
399 {
400 for(int i = vec.size() - 1; i >= 0; --i)
401 VectorBase<R>::val[vec.index(i)] -= vec.value(i);
402 }
403 else
404 VectorBase<R>::operator-=(VectorBase<S>(vec));
405
406 if(isSetup())
407 {
408 setupStatus = false;
409 setup();
410 }
411
412 return *this;
413 }
414
415 /// Scaling.
416 template < class S >
417 SSVectorBase<R>& operator*=(S x)
418 {
419 assert(isSetup());
420 assert(x != S(0));
421
422 for(int i = size() - 1; i >= 0; --i)
423 VectorBase<R>::val[index(i)] *= x;
424
425 assert(isConsistent());
426
427 return *this;
428 }
429
430 // Inner product.
431 template < class S >
432 R operator*(const SSVectorBase<S>& w)
433 {
434 setup();
435
436 StableSum<R> x;
437 int i = size() - 1;
438 int j = w.size() - 1;
439
440 // both *this and w non-zero vectors?
441 if(i >= 0 && j >= 0)
442 {
443 int vi = index(i);
444 int wj = w.index(j);
445
446 while(i != 0 && j != 0)
447 {
448 if(vi == wj)
449 {
450 x += VectorBase<R>::val[vi] * R(w.val[wj]);
451 vi = index(--i);
452 wj = w.index(--j);
453 }
454 else if(vi > wj)
455 vi = index(--i);
456 else
457 wj = w.index(--j);
458 }
459
460 /* check remaining indices */
461
462 while(i != 0 && vi != wj)
463 vi = index(--i);
464
465 while(j != 0 && vi != wj)
466 wj = w.index(--j);
467
468 if(vi == wj)
469 x += VectorBase<R>::val[vi] * R(w.val[wj]);
470 }
471
472 return x;
473 }
474
475 /// Addition of a scaled vector.
476 ///@todo SSVectorBase::multAdd() should be rewritten without pointer arithmetic.
477 template < class S, class T >
478 SSVectorBase<R>& multAdd(S xx, const SVectorBase<T>& vec);
479
480 /// Addition of a scaled vector.
481 template < class S, class T >
482 SSVectorBase<R>& multAdd(S x, const VectorBase<T>& vec)
483 {
484 VectorBase<R>::multAdd(x, vec);
485
486 if(isSetup())
487 {
488 setupStatus = false;
489 setup();
490 }
491
492 return *this;
493 }
494
495 /// Assigns pair wise vector product to SSVectorBase.
496 template < class S, class T >
497 SSVectorBase<R>& assignPWproduct4setup(const SSVectorBase<S>& x, const SSVectorBase<T>& y);
498
499 /// Assigns \f$x^T \cdot A\f$ to SSVectorBase.
500 template < class S, class T >
501 SSVectorBase<R>& assign2product(const SSVectorBase<S>& x, const SVSetBase<T>& A);
502
503 /// Assigns SSVectorBase to \f$A \cdot x\f$ for a setup \p x.
504 template < class S, class T >
505 SSVectorBase<R>& assign2product4setup(const SVSetBase<S>& A, const SSVectorBase<T>& x,
506 Timer* timeSparse, Timer* timeFull, int& nCallsSparse, int& nCallsFull);
507
508 public:
509
510 /// Assigns SSVectorBase to \f$A \cdot x\f$ thereby setting up \p x.
511 template < class S, class T >
512 SSVectorBase<R>& assign2productAndSetup(const SVSetBase<S>& A, SSVectorBase<T>& x);
513
514 /// Maximum absolute value, i.e., infinity norm.
515 R maxAbs() const
516 {
517 if(isSetup())
518 {
519 R maxabs = 0;
520
521 for(int i = 0; i < num; ++i)
522 {
523 R x = spxAbs(VectorBase<R>::val[idx[i]]);
524
525 if(x > maxabs)
526 maxabs = x;
527 }
528
529 return maxabs;
530 }
531 else
532 return VectorBase<R>::maxAbs();
533 }
534
535 /// Squared euclidian norm.
536 R length2() const
537 {
538 R x = 0;
539
540 if(isSetup())
541 {
542 for(int i = 0; i < num; ++i)
543 x += VectorBase<R>::val[idx[i]] * VectorBase<R>::val[idx[i]];
544 }
545 else
546 x = VectorBase<R>::length2();
547
548 return x;
549 }
550
551 /// Floating point approximation of euclidian norm (without any approximation guarantee).
552 R length() const
553 {
554 return spxSqrt(R(length2()));
555 }
556
557 ///@}
558
559 // ------------------------------------------------------------------------------------------------------------------
560 /**@name Miscellaneous */
561 ///@{
562
563 /// Dimension of VectorBase.
564 int dim() const
565 {
566 return VectorBase<R>::dim();
567 }
568
569 /// Resets dimension to \p newdim.
570 void reDim(int newdim)
571 {
572 for(int i = IdxSet::size() - 1; i >= 0; --i)
573 {
574 if(index(i) >= newdim)
575 remove(i);
576 }
577
578 VectorBase<R>::reDim(newdim);
579 setMax(VectorBase<R>::memSize() + 1);
580
581 assert(isConsistent());
582 }
583
584 /// Sets number of nonzeros (thereby unSetup SSVectorBase).
585 void setSize(int n)
586 {
587 assert(n >= 0);
588 assert(n <= IdxSet::max());
589
590 unSetup();
591 num = n;
592 }
593
594 /// Resets memory consumption to \p newsize.
595 void reMem(int newsize)
596 {
597 VectorBase<R>::reSize(newsize);
598 assert(isConsistent());
599
600 setMax(VectorBase<R>::memSize() + 1);
601 }
602
603 /// Clears vector.
604 void clear()
605 {
606 if(isSetup())
607 {
608 for(int i = 0; i < num; ++i)
609 VectorBase<R>::val[idx[i]] = 0;
610 }
611 else
612 VectorBase<R>::clear();
613
614 IdxSet::clear();
615 setupStatus = true;
616
617 assert(isConsistent());
618 }
619
620 /// consistency check.
621 bool isConsistent() const
622 {
623 #ifdef ENABLE_CONSISTENCY_CHECKS
624
625 if(VectorBase<R>::dim() > IdxSet::max())
626 return MSGinconsistent("SSVectorBase");
627
628 if(VectorBase<R>::dim() < IdxSet::dim())
629 return MSGinconsistent("SSVectorBase");
630
631 if(isSetup())
632 {
633 for(int i = 0; i < VectorBase<R>::dim(); ++i)
634 {
635 int j = pos(i);
636
637 if(j < 0 && spxAbs(VectorBase<R>::val[i]) > 0)
638 {
639 MSG_ERROR(std::cerr << "ESSVEC01 i = " << i
640 << "\tidx = " << j
641 << "\tval = " << std::setprecision(16) << VectorBase<R>::val[i]
642 << std::endl;)
643
644 return MSGinconsistent("SSVectorBase");
645 }
646 }
647 }
648
649 return VectorBase<R>::isConsistent() && IdxSet::isConsistent();
650 #else
651 return true;
652 #endif
653 }
654
655 ///@}
656
657 // ------------------------------------------------------------------------------------------------------------------
658 /**@name Constructors / Destructors */
659 ///@{
660
661 /// Default constructor.
662 explicit SSVectorBase<R>(int p_dim, R p_eps = Param::epsilon())
663 : VectorBase<R>(p_dim)
(1) Event write_constant_to_parm_in_call: |
Called function writes 0 to a dereference of parameter "this". [details] |
664 , IdxSet()
665 , setupStatus(true)
666 , epsilon(p_eps)
667 {
(2) Event cond_true: |
Condition "p_dim < 1", taking true branch. |
668 len = (p_dim < 1) ? 1 : p_dim;
669 spx_alloc(idx, len);
670 VectorBase<R>::clear();
671
672 assert(isConsistent());
673 }
674
675 /// Copy constructor.
676 template < class S >
677 SSVectorBase<R>(const SSVectorBase<S>& vec)
678 : VectorBase<R>(vec)
679 , IdxSet()
680 , setupStatus(vec.setupStatus)
681 , epsilon(vec.epsilon)
682 {
683 len = (vec.dim() < 1) ? 1 : vec.dim();
684 spx_alloc(idx, len);
685 IdxSet::operator=(vec);
686
687 assert(isConsistent());
688 }
689
690 /// Copy constructor.
691 /** The redundancy with the copy constructor below is necessary since otherwise the compiler doesn't realize that it
692 * could use the more general one with S = R and generates a shallow copy constructor.
693 */
694 SSVectorBase<R>(const SSVectorBase<R>& vec)
695 : VectorBase<R>(vec)
696 , IdxSet()
697 , setupStatus(vec.setupStatus)
698 , epsilon(vec.epsilon)
699 {
700 len = (vec.dim() < 1) ? 1 : vec.dim();
701 spx_alloc(idx, len);
702 IdxSet::operator=(vec);
703
704 assert(isConsistent());
705 }
706
707 /// Constructs nonsetup copy of \p vec.
708 template < class S >
709 explicit SSVectorBase<R>(const VectorBase<S>& vec, R eps = Param::epsilon())
710 : VectorBase<R>(vec)
711 , IdxSet()
712 , setupStatus(false)
713 , epsilon(eps)
714 {
715 len = (vec.dim() < 1) ? 1 : vec.dim();
716 spx_alloc(idx, len);
717
718 assert(isConsistent());
719 }
720
721 /// Sets up \p rhs vector, and assigns it.
722 template < class S >
723 void setup_and_assign(SSVectorBase<S>& rhs)
724 {
725 clear();
726 epsilon = rhs.epsilon;
727 setMax(rhs.max());
728 VectorBase<R>::reDim(rhs.dim());
729
730 if(rhs.isSetup())
731 {
732 IdxSet::operator=(rhs);
733
734 for(int i = size() - 1; i >= 0; --i)
735 {
736 int j = index(i);
737 VectorBase<R>::val[j] = rhs.val[j];
738 }
739 }
740 else
741 {
742 int d = rhs.dim();
743 num = 0;
744
745 for(int i = 0; i < d; ++i)
746 {
747 if(rhs.val[i] != 0)
748 {
749 if(spxAbs(rhs.val[i]) > epsilon)
750 {
751 rhs.idx[num] = i;
752 idx[num] = i;
753 VectorBase<R>::val[i] = rhs.val[i];
754 num++;
755 }
756 else
757 rhs.val[i] = 0;
758 }
759 }
760
761 rhs.num = num;
762 rhs.setupStatus = true;
763 }
764
765 setupStatus = true;
766
767 assert(rhs.isConsistent());
768 assert(isConsistent());
769 }
770
771 /// Assigns only the elements of \p rhs.
772 template < class S >
773 SSVectorBase<R>& assign(const SVectorBase<S>& rhs);
774
775 /// Assignment operator.
776 template < class S >
777 SSVectorBase<R>& operator=(const SSVectorBase<S>& rhs)
778 {
779 assert(rhs.isConsistent());
780
781 if(this != &rhs)
782 {
783 clear();
784 epsilon = rhs.epsilon;
785 setMax(rhs.max());
786 VectorBase<R>::reDim(rhs.dim());
787
788 if(rhs.isSetup())
789 {
790 IdxSet::operator=(rhs);
791
792 for(int i = size() - 1; i >= 0; --i)
793 {
794 int j = index(i);
795 VectorBase<R>::val[j] = rhs.val[j];
796 }
797 }
798 else
799 {
800 int d = rhs.dim();
801 num = 0;
802
803 for(int i = 0; i < d; ++i)
804 {
805 if(spxAbs(rhs.val[i]) > epsilon)
806 {
807 VectorBase<R>::val[i] = rhs.val[i];
808 idx[num] = i;
809 num++;
810 }
811 }
812 }
813
814 setupStatus = true;
815 }
816
817 assert(isConsistent());
818
819 return *this;
820 }
821
822 /// Assignment operator.
823 SSVectorBase<R>& operator=(const SSVectorBase<R>& rhs)
824 {
825 assert(rhs.isConsistent());
826
827 if(this != &rhs)
828 {
829 clear();
830 epsilon = rhs.epsilon;
831 setMax(rhs.max());
832 VectorBase<R>::reDim(rhs.dim());
833
834 if(rhs.isSetup())
835 {
836 IdxSet::operator=(rhs);
837
838 for(int i = size() - 1; i >= 0; --i)
839 {
840 int j = index(i);
841 VectorBase<R>::val[j] = rhs.val[j];
842 }
843 }
844 else
845 {
846 num = 0;
847
848 for(int i = 0; i < rhs.dim(); ++i)
849 {
850 if(spxAbs(rhs.val[i]) > epsilon)
851 {
852 VectorBase<R>::val[i] = rhs.val[i];
853 idx[num] = i;
854 num++;
855 }
856 }
857 }
858
859 setupStatus = true;
860 }
861
862 assert(isConsistent());
863
864 return *this;
865 }
866
867 /// Assignment operator.
868 template < class S >
869 SSVectorBase<R>& operator=(const SVectorBase<S>& rhs);
870
871 /// Assignment operator.
872 template < class S >
873 SSVectorBase<R>& operator=(const VectorBase<S>& rhs)
874 {
875 unSetup();
876 VectorBase<R>::operator=(rhs);
877
878 assert(isConsistent());
879
880 return *this;
881 }
882
883 /// destructor
884 ~SSVectorBase<R>()
885 {
886 if(idx)
887 spx_free(idx);
888 }
889
890 ///@}
891
892 private:
893
894 // ------------------------------------------------------------------------------------------------------------------
895 /**@name Private helpers */
896 ///@{
897
898 /// Assignment helper.
899 template < class S, class T >
900 SSVectorBase<R>& assign2product1(const SVSetBase<S>& A, const SSVectorBase<T>& x);
901
902 /// Assignment helper.
903 template < class S, class T >
904 SSVectorBase<R>& assign2productShort(const SVSetBase<S>& A, const SSVectorBase<T>& x);
905
906 /// Assignment helper.
907 template < class S, class T >
908 SSVectorBase<R>& assign2productFull(const SVSetBase<S>& A, const SSVectorBase<T>& x);
909
910 ///@}
911 };
912
913 } // namespace soplex
914 #endif // _SSVECTORBASE_H_
915