1 | /* $Id: CoinIndexedVector.cpp 1448 2011-06-19 15:34:41Z stefan $ */ |
2 | // Copyright (C) 2000, International Business Machines |
3 | // Corporation and others. All Rights Reserved. |
4 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
5 | |
6 | #if defined(_MSC_VER) |
7 | // Turn off compiler warning about long names |
8 | # pragma warning(disable:4786) |
9 | #endif |
10 | |
11 | #include <cassert> |
12 | #include <cstdio> |
13 | |
14 | #include "CoinTypes.hpp" |
15 | #include "CoinFloatEqual.hpp" |
16 | #include "CoinHelperFunctions.hpp" |
17 | #include "CoinIndexedVector.hpp" |
18 | #include "CoinTypes.hpp" |
19 | //############################################################################# |
20 | |
21 | void |
22 | CoinIndexedVector::clear() |
23 | { |
24 | if (!packedMode_) { |
25 | if (3*nElements_<capacity_) { |
26 | int i=0; |
27 | if ((nElements_&1)!=0) { |
28 | elements_[indices_[0]]=0.0; |
29 | i=1; |
30 | } |
31 | for (;i<nElements_;i+=2) { |
32 | int i0 = indices_[i]; |
33 | int i1 = indices_[i+1]; |
34 | elements_[i0]=0.0; |
35 | elements_[i1]=0.0; |
36 | } |
37 | } else { |
38 | CoinZeroN(elements_,capacity_); |
39 | } |
40 | } else { |
41 | CoinZeroN(elements_,nElements_); |
42 | } |
43 | nElements_ = 0; |
44 | packedMode_=false; |
45 | //checkClear(); |
46 | } |
47 | |
48 | //############################################################################# |
49 | |
50 | void |
51 | CoinIndexedVector::empty() |
52 | { |
53 | delete [] indices_; |
54 | indices_=NULL; |
55 | if (elements_) |
56 | delete [] (elements_-offset_); |
57 | elements_=NULL; |
58 | nElements_ = 0; |
59 | capacity_=0; |
60 | packedMode_=false; |
61 | } |
62 | |
63 | //############################################################################# |
64 | |
65 | CoinIndexedVector & |
66 | CoinIndexedVector::operator=(const CoinIndexedVector & rhs) |
67 | { |
68 | if (this != &rhs) { |
69 | clear(); |
70 | packedMode_=rhs.packedMode_; |
71 | if (!packedMode_) |
72 | gutsOfSetVector(rhs.capacity_,rhs.nElements_, |
73 | rhs.indices_, rhs.elements_); |
74 | else |
75 | gutsOfSetPackedVector(rhs.capacity_,rhs.nElements_, |
76 | rhs.indices_, rhs.elements_); |
77 | } |
78 | return *this; |
79 | } |
80 | /* Copy the contents of one vector into another. If multiplier is 1 |
81 | It is the equivalent of = but if vectors are same size does |
82 | not re-allocate memory just clears and copies */ |
83 | void |
84 | CoinIndexedVector::copy(const CoinIndexedVector & rhs, double multiplier) |
85 | { |
86 | if (capacity_==rhs.capacity_) { |
87 | // can do fast |
88 | clear(); |
89 | packedMode_=rhs.packedMode_; |
90 | nElements_=0; |
91 | if (!packedMode_) { |
92 | for (int i=0;i<rhs.nElements_;i++) { |
93 | int index = rhs.indices_[i]; |
94 | double value = rhs.elements_[index]*multiplier; |
95 | if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) |
96 | value = COIN_INDEXED_REALLY_TINY_ELEMENT; |
97 | elements_[index]=value; |
98 | indices_[nElements_++]=index; |
99 | } |
100 | } else { |
101 | for (int i=0;i<rhs.nElements_;i++) { |
102 | int index = rhs.indices_[i]; |
103 | double value = rhs.elements_[i]*multiplier; |
104 | if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) |
105 | value = COIN_INDEXED_REALLY_TINY_ELEMENT; |
106 | elements_[nElements_]=value; |
107 | indices_[nElements_++]=index; |
108 | } |
109 | } |
110 | } else { |
111 | // do as two operations |
112 | *this = rhs; |
113 | (*this) *= multiplier; |
114 | } |
115 | } |
116 | |
117 | //############################################################################# |
118 | #ifndef CLP_NO_VECTOR |
119 | CoinIndexedVector & |
120 | CoinIndexedVector::operator=(const CoinPackedVectorBase & rhs) |
121 | { |
122 | clear(); |
123 | packedMode_=false; |
124 | gutsOfSetVector(rhs.getNumElements(), |
125 | rhs.getIndices(), rhs.getElements()); |
126 | return *this; |
127 | } |
128 | #endif |
129 | //############################################################################# |
130 | |
131 | void |
132 | CoinIndexedVector::borrowVector(int size, int numberIndices, int* inds, double* elems) |
133 | { |
134 | empty(); |
135 | capacity_=size; |
136 | nElements_ = numberIndices; |
137 | indices_ = inds; |
138 | elements_ = elems; |
139 | |
140 | // whole point about borrowvector is that it is lightweight so no testing is done |
141 | } |
142 | |
143 | //############################################################################# |
144 | |
145 | void |
146 | CoinIndexedVector::returnVector() |
147 | { |
148 | indices_=NULL; |
149 | elements_=NULL; |
150 | nElements_ = 0; |
151 | capacity_=0; |
152 | packedMode_=false; |
153 | } |
154 | |
155 | //############################################################################# |
156 | |
157 | void |
158 | CoinIndexedVector::setVector(int size, const int * inds, const double * elems) |
159 | { |
160 | clear(); |
161 | gutsOfSetVector(size, inds, elems); |
162 | } |
163 | //############################################################################# |
164 | |
165 | |
166 | void |
167 | CoinIndexedVector::setVector(int size, int numberIndices, const int * inds, const double * elems) |
168 | { |
169 | clear(); |
170 | gutsOfSetVector(size, numberIndices, inds, elems); |
171 | } |
172 | //############################################################################# |
173 | |
174 | void |
175 | CoinIndexedVector::setConstant(int size, const int * inds, double value) |
176 | { |
177 | clear(); |
178 | gutsOfSetConstant(size, inds, value); |
179 | } |
180 | |
181 | //############################################################################# |
182 | |
183 | void |
184 | CoinIndexedVector::setFull(int size, const double * elems) |
185 | { |
186 | // Clear out any values presently stored |
187 | clear(); |
188 | |
189 | #ifndef COIN_FAST_CODE |
190 | if (size<0) |
191 | throw CoinError("negative number of indices" , "setFull" , "CoinIndexedVector" ); |
192 | #endif |
193 | reserve(size); |
194 | nElements_ = 0; |
195 | // elements_ array is all zero |
196 | int i; |
197 | for (i=0;i<size;i++) { |
198 | int indexValue=i; |
199 | if (fabs(elems[i])>=COIN_INDEXED_TINY_ELEMENT) { |
200 | elements_[indexValue]=elems[i]; |
201 | indices_[nElements_++]=indexValue; |
202 | } |
203 | } |
204 | } |
205 | //############################################################################# |
206 | |
207 | /** Access the i'th element of the full storage vector. */ |
208 | double & |
209 | CoinIndexedVector::operator[](int index) const |
210 | { |
211 | assert (!packedMode_); |
212 | #ifndef COIN_FAST_CODE |
213 | if ( index >= capacity_ ) |
214 | throw CoinError("index >= capacity()" , "[]" , "CoinIndexedVector" ); |
215 | if ( index < 0 ) |
216 | throw CoinError("index < 0" , "[]" , "CoinIndexedVector" ); |
217 | #endif |
218 | double * where = elements_ + index; |
219 | return *where; |
220 | |
221 | } |
222 | //############################################################################# |
223 | |
224 | void |
225 | CoinIndexedVector::setElement(int index, double element) |
226 | { |
227 | #ifndef COIN_FAST_CODE |
228 | if ( index >= nElements_ ) |
229 | throw CoinError("index >= size()" , "setElement" , "CoinIndexedVector" ); |
230 | if ( index < 0 ) |
231 | throw CoinError("index < 0" , "setElement" , "CoinIndexedVector" ); |
232 | #endif |
233 | elements_[indices_[index]] = element; |
234 | } |
235 | |
236 | //############################################################################# |
237 | |
238 | void |
239 | CoinIndexedVector::insert( int index, double element ) |
240 | { |
241 | #ifndef COIN_FAST_CODE |
242 | if ( index < 0 ) |
243 | throw CoinError("index < 0" , "setElement" , "CoinIndexedVector" ); |
244 | #endif |
245 | if (index >= capacity_) |
246 | reserve(index+1); |
247 | #ifndef COIN_FAST_CODE |
248 | if (elements_[index]) |
249 | throw CoinError("Index already exists" , "insert" , "CoinIndexedVector" ); |
250 | #endif |
251 | indices_[nElements_++] = index; |
252 | elements_[index] = element; |
253 | } |
254 | |
255 | //############################################################################# |
256 | |
257 | void |
258 | CoinIndexedVector::add( int index, double element ) |
259 | { |
260 | #ifndef COIN_FAST_CODE |
261 | if ( index < 0 ) |
262 | throw CoinError("index < 0" , "setElement" , "CoinIndexedVector" ); |
263 | #endif |
264 | if (index >= capacity_) |
265 | reserve(index+1); |
266 | if (elements_[index]) { |
267 | element += elements_[index]; |
268 | if (fabs(element)>= COIN_INDEXED_TINY_ELEMENT) { |
269 | elements_[index] = element; |
270 | } else { |
271 | elements_[index] = COIN_INDEXED_REALLY_TINY_ELEMENT; |
272 | } |
273 | } else if (fabs(element)>= COIN_INDEXED_TINY_ELEMENT) { |
274 | indices_[nElements_++] = index; |
275 | assert (nElements_<=capacity_); |
276 | elements_[index] = element; |
277 | } |
278 | } |
279 | |
280 | //############################################################################# |
281 | |
282 | int |
283 | CoinIndexedVector::clean( double tolerance ) |
284 | { |
285 | int number = nElements_; |
286 | int i; |
287 | nElements_=0; |
288 | assert(!packedMode_); |
289 | for (i=0;i<number;i++) { |
290 | int indexValue = indices_[i]; |
291 | if (fabs(elements_[indexValue])>=tolerance) { |
292 | indices_[nElements_++]=indexValue; |
293 | } else { |
294 | elements_[indexValue]=0.0; |
295 | } |
296 | } |
297 | return nElements_; |
298 | } |
299 | |
300 | //############################################################################# |
301 | // For debug check vector is clear i.e. no elements |
302 | void CoinIndexedVector::checkClear() |
303 | { |
304 | #ifndef NDEBUG |
305 | assert(!nElements_); |
306 | assert(!packedMode_); |
307 | int i; |
308 | for (i=0;i<capacity_;i++) { |
309 | assert(!elements_[i]); |
310 | } |
311 | // check mark array zeroed |
312 | char * mark = reinterpret_cast<char *> (indices_+capacity_); |
313 | for (i=0;i<capacity_;i++) { |
314 | assert(!mark[i]); |
315 | } |
316 | #else |
317 | if(nElements_) { |
318 | printf("%d nElements_ - checkClear\n" ,nElements_); |
319 | abort(); |
320 | } |
321 | if(packedMode_) { |
322 | printf("packed mode when empty - checkClear\n" ); |
323 | abort(); |
324 | } |
325 | int i; |
326 | int n=0; |
327 | int k=-1; |
328 | for (i=0;i<capacity_;i++) { |
329 | if(elements_[i]) { |
330 | n++; |
331 | if (k<0) |
332 | k=i; |
333 | } |
334 | } |
335 | if(n) { |
336 | printf("%d elements, first %d - checkClear\n" ,n,k); |
337 | abort(); |
338 | } |
339 | #endif |
340 | } |
341 | // For debug check vector is clean i.e. elements match indices |
342 | void CoinIndexedVector::checkClean() |
343 | { |
344 | int i; |
345 | if (packedMode_) { |
346 | for (i=0;i<nElements_;i++) |
347 | assert(elements_[i]); |
348 | for (;i<capacity_;i++) |
349 | assert(!elements_[i]); |
350 | } else { |
351 | double * copy = new double[capacity_]; |
352 | CoinMemcpyN(elements_,capacity_,copy); |
353 | for (i=0;i<nElements_;i++) { |
354 | int indexValue = indices_[i]; |
355 | copy[indexValue]=0.0; |
356 | } |
357 | for (i=0;i<capacity_;i++) |
358 | assert(!copy[i]); |
359 | delete [] copy; |
360 | } |
361 | #ifndef NDEBUG |
362 | // check mark array zeroed |
363 | char * mark = reinterpret_cast<char *> (indices_+capacity_); |
364 | for (i=0;i<capacity_;i++) { |
365 | assert(!mark[i]); |
366 | } |
367 | #endif |
368 | } |
369 | |
370 | //############################################################################# |
371 | #ifndef CLP_NO_VECTOR |
372 | void |
373 | CoinIndexedVector::append(const CoinPackedVectorBase & caboose) |
374 | { |
375 | const int cs = caboose.getNumElements(); |
376 | |
377 | const int * cind = caboose.getIndices(); |
378 | const double * celem = caboose.getElements(); |
379 | int maxIndex=-1; |
380 | int i; |
381 | for (i=0;i<cs;i++) { |
382 | int indexValue = cind[i]; |
383 | if (indexValue<0) |
384 | throw CoinError("negative index" , "append" , "CoinIndexedVector" ); |
385 | if (maxIndex<indexValue) |
386 | maxIndex = indexValue; |
387 | } |
388 | reserve(maxIndex+1); |
389 | bool needClean=false; |
390 | int numberDuplicates=0; |
391 | for (i=0;i<cs;i++) { |
392 | int indexValue=cind[i]; |
393 | if (elements_[indexValue]) { |
394 | numberDuplicates++; |
395 | elements_[indexValue] += celem[i] ; |
396 | if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) |
397 | needClean=true; // need to go through again |
398 | } else { |
399 | if (fabs(celem[i])>=COIN_INDEXED_TINY_ELEMENT) { |
400 | elements_[indexValue]=celem[i]; |
401 | indices_[nElements_++]=indexValue; |
402 | } |
403 | } |
404 | } |
405 | if (needClean) { |
406 | // go through again |
407 | int size=nElements_; |
408 | nElements_=0; |
409 | for (i=0;i<size;i++) { |
410 | int indexValue=indices_[i]; |
411 | double value=elements_[indexValue]; |
412 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
413 | indices_[nElements_++]=indexValue; |
414 | } else { |
415 | elements_[indexValue]=0.0; |
416 | } |
417 | } |
418 | } |
419 | if (numberDuplicates) |
420 | throw CoinError("duplicate index" , "append" , "CoinIndexedVector" ); |
421 | } |
422 | #endif |
423 | //############################################################################# |
424 | |
425 | void |
426 | CoinIndexedVector::swap(int i, int j) |
427 | { |
428 | if ( i >= nElements_ ) |
429 | throw CoinError("index i >= size()" ,"swap" ,"CoinIndexedVector" ); |
430 | if ( i < 0 ) |
431 | throw CoinError("index i < 0" ,"swap" ,"CoinIndexedVector" ); |
432 | if ( j >= nElements_ ) |
433 | throw CoinError("index j >= size()" ,"swap" ,"CoinIndexedVector" ); |
434 | if ( j < 0 ) |
435 | throw CoinError("index j < 0" ,"swap" ,"CoinIndexedVector" ); |
436 | |
437 | // Swap positions i and j of the |
438 | // indices array |
439 | |
440 | int isave = indices_[i]; |
441 | indices_[i] = indices_[j]; |
442 | indices_[j] = isave; |
443 | } |
444 | |
445 | //############################################################################# |
446 | |
447 | void |
448 | CoinIndexedVector::truncate( int n ) |
449 | { |
450 | reserve(n); |
451 | } |
452 | |
453 | //############################################################################# |
454 | |
455 | void |
456 | CoinIndexedVector::operator+=(double value) |
457 | { |
458 | assert (!packedMode_); |
459 | int i,indexValue; |
460 | for (i=0;i<nElements_;i++) { |
461 | indexValue = indices_[i]; |
462 | double newValue = elements_[indexValue] + value; |
463 | if (fabs(newValue)>=COIN_INDEXED_TINY_ELEMENT) |
464 | elements_[indexValue] = newValue; |
465 | else |
466 | elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT; |
467 | } |
468 | } |
469 | |
470 | //----------------------------------------------------------------------------- |
471 | |
472 | void |
473 | CoinIndexedVector::operator-=(double value) |
474 | { |
475 | assert (!packedMode_); |
476 | int i,indexValue; |
477 | for (i=0;i<nElements_;i++) { |
478 | indexValue = indices_[i]; |
479 | double newValue = elements_[indexValue] - value; |
480 | if (fabs(newValue)>=COIN_INDEXED_TINY_ELEMENT) |
481 | elements_[indexValue] = newValue; |
482 | else |
483 | elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT; |
484 | } |
485 | } |
486 | |
487 | //----------------------------------------------------------------------------- |
488 | |
489 | void |
490 | CoinIndexedVector::operator*=(double value) |
491 | { |
492 | assert (!packedMode_); |
493 | int i,indexValue; |
494 | for (i=0;i<nElements_;i++) { |
495 | indexValue = indices_[i]; |
496 | double newValue = elements_[indexValue] * value; |
497 | if (fabs(newValue)>=COIN_INDEXED_TINY_ELEMENT) |
498 | elements_[indexValue] = newValue; |
499 | else |
500 | elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT; |
501 | } |
502 | } |
503 | |
504 | //----------------------------------------------------------------------------- |
505 | |
506 | void |
507 | CoinIndexedVector::operator/=(double value) |
508 | { |
509 | assert (!packedMode_); |
510 | int i,indexValue; |
511 | for (i=0;i<nElements_;i++) { |
512 | indexValue = indices_[i]; |
513 | double newValue = elements_[indexValue] / value; |
514 | if (fabs(newValue)>=COIN_INDEXED_TINY_ELEMENT) |
515 | elements_[indexValue] = newValue; |
516 | else |
517 | elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT; |
518 | } |
519 | } |
520 | //############################################################################# |
521 | |
522 | void |
523 | CoinIndexedVector::reserve(int n) |
524 | { |
525 | int i; |
526 | // don't make allocated space smaller but do take off values |
527 | if ( n < capacity_ ) { |
528 | #ifndef COIN_FAST_CODE |
529 | if (n<0) |
530 | throw CoinError("negative capacity" , "reserve" , "CoinIndexedVector" ); |
531 | #endif |
532 | int nNew=0; |
533 | for (i=0;i<nElements_;i++) { |
534 | int indexValue=indices_[i]; |
535 | if (indexValue<n) { |
536 | indices_[nNew++]=indexValue; |
537 | } else { |
538 | elements_[indexValue]=0.0; |
539 | } |
540 | } |
541 | nElements_=nNew; |
542 | } else if (n>capacity_) { |
543 | |
544 | // save pointers to existing data |
545 | int * tempIndices = indices_; |
546 | double * tempElements = elements_; |
547 | double * delTemp = elements_-offset_; |
548 | |
549 | // allocate new space |
550 | int nPlus; |
551 | if (sizeof(int)==4*sizeof(char)) |
552 | nPlus=(n+3)>>2; |
553 | else |
554 | nPlus=(n+7)>>4; |
555 | indices_ = new int [n+nPlus]; |
556 | CoinZeroN(indices_+n,nPlus); |
557 | // align on 64 byte boundary |
558 | double * temp = new double [n+7]; |
559 | offset_ = 0; |
560 | CoinInt64 xx = reinterpret_cast<CoinInt64>(temp); |
561 | int iBottom = static_cast<int>(xx & 63); |
562 | if (iBottom) |
563 | offset_ = (64-iBottom)>>3; |
564 | elements_ = temp + offset_; |
565 | |
566 | // copy data to new space |
567 | // and zero out part of array |
568 | if (nElements_ > 0) { |
569 | CoinMemcpyN(tempIndices, nElements_, indices_); |
570 | CoinMemcpyN(tempElements, capacity_, elements_); |
571 | CoinZeroN(elements_+capacity_,n-capacity_); |
572 | } else { |
573 | CoinZeroN(elements_,n); |
574 | } |
575 | capacity_ = n; |
576 | |
577 | // free old data |
578 | if (tempElements) |
579 | delete [] delTemp; |
580 | delete [] tempIndices; |
581 | } |
582 | } |
583 | |
584 | //############################################################################# |
585 | |
586 | CoinIndexedVector::CoinIndexedVector () : |
587 | indices_(NULL), |
588 | elements_(NULL), |
589 | nElements_(0), |
590 | capacity_(0), |
591 | offset_(0), |
592 | packedMode_(false) |
593 | { |
594 | } |
595 | |
596 | |
597 | CoinIndexedVector::CoinIndexedVector (int size) : |
598 | indices_(NULL), |
599 | elements_(NULL), |
600 | nElements_(0), |
601 | capacity_(0), |
602 | offset_(0), |
603 | packedMode_(false) |
604 | { |
605 | // Get space |
606 | reserve(size); |
607 | } |
608 | |
609 | //----------------------------------------------------------------------------- |
610 | |
611 | CoinIndexedVector::CoinIndexedVector(int size, |
612 | const int * inds, const double * elems) : |
613 | indices_(NULL), |
614 | elements_(NULL), |
615 | nElements_(0), |
616 | capacity_(0), |
617 | offset_(0), |
618 | packedMode_(false) |
619 | { |
620 | gutsOfSetVector(size, inds, elems); |
621 | } |
622 | |
623 | //----------------------------------------------------------------------------- |
624 | |
625 | CoinIndexedVector::CoinIndexedVector(int size, |
626 | const int * inds, double value) : |
627 | indices_(NULL), |
628 | elements_(NULL), |
629 | nElements_(0), |
630 | capacity_(0), |
631 | offset_(0), |
632 | packedMode_(false) |
633 | { |
634 | gutsOfSetConstant(size, inds, value); |
635 | } |
636 | |
637 | //----------------------------------------------------------------------------- |
638 | |
639 | CoinIndexedVector::CoinIndexedVector(int size, const double * element) : |
640 | indices_(NULL), |
641 | elements_(NULL), |
642 | nElements_(0), |
643 | capacity_(0), |
644 | offset_(0), |
645 | packedMode_(false) |
646 | { |
647 | setFull(size, element); |
648 | } |
649 | |
650 | //----------------------------------------------------------------------------- |
651 | #ifndef CLP_NO_VECTOR |
652 | CoinIndexedVector::CoinIndexedVector(const CoinPackedVectorBase & rhs) : |
653 | indices_(NULL), |
654 | elements_(NULL), |
655 | nElements_(0), |
656 | capacity_(0), |
657 | offset_(0), |
658 | packedMode_(false) |
659 | { |
660 | gutsOfSetVector(rhs.getNumElements(), |
661 | rhs.getIndices(), rhs.getElements()); |
662 | } |
663 | #endif |
664 | //----------------------------------------------------------------------------- |
665 | |
666 | CoinIndexedVector::CoinIndexedVector(const CoinIndexedVector & rhs) : |
667 | indices_(NULL), |
668 | elements_(NULL), |
669 | nElements_(0), |
670 | capacity_(0), |
671 | offset_(0), |
672 | packedMode_(false) |
673 | { |
674 | if (!rhs.packedMode_) |
675 | gutsOfSetVector(rhs.capacity_,rhs.nElements_, rhs.indices_, rhs.elements_); |
676 | else |
677 | gutsOfSetPackedVector(rhs.capacity_,rhs.nElements_, rhs.indices_, rhs.elements_); |
678 | } |
679 | |
680 | //----------------------------------------------------------------------------- |
681 | |
682 | CoinIndexedVector::CoinIndexedVector(const CoinIndexedVector * rhs) : |
683 | indices_(NULL), |
684 | elements_(NULL), |
685 | nElements_(0), |
686 | capacity_(0), |
687 | offset_(0), |
688 | packedMode_(false) |
689 | { |
690 | if (!rhs->packedMode_) |
691 | gutsOfSetVector(rhs->capacity_,rhs->nElements_, rhs->indices_, rhs->elements_); |
692 | else |
693 | gutsOfSetPackedVector(rhs->capacity_,rhs->nElements_, rhs->indices_, rhs->elements_); |
694 | } |
695 | |
696 | //----------------------------------------------------------------------------- |
697 | |
698 | CoinIndexedVector::~CoinIndexedVector () |
699 | { |
700 | delete [] indices_; |
701 | if (elements_) |
702 | delete [] (elements_-offset_); |
703 | } |
704 | //############################################################################# |
705 | //############################################################################# |
706 | |
707 | /// Return the sum of two indexed vectors |
708 | CoinIndexedVector |
709 | CoinIndexedVector::operator+( |
710 | const CoinIndexedVector& op2) |
711 | { |
712 | assert (!packedMode_); |
713 | int i; |
714 | int nElements=nElements_; |
715 | int capacity = CoinMax(capacity_,op2.capacity_); |
716 | CoinIndexedVector newOne(*this); |
717 | newOne.reserve(capacity); |
718 | bool needClean=false; |
719 | // new one now can hold everything so just modify old and add new |
720 | for (i=0;i<op2.nElements_;i++) { |
721 | int indexValue=op2.indices_[i]; |
722 | double value=op2.elements_[indexValue]; |
723 | double oldValue=elements_[indexValue]; |
724 | if (!oldValue) { |
725 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
726 | newOne.elements_[indexValue]=value; |
727 | newOne.indices_[nElements++]=indexValue; |
728 | } |
729 | } else { |
730 | value += oldValue; |
731 | newOne.elements_[indexValue]=value; |
732 | if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) { |
733 | needClean=true; |
734 | } |
735 | } |
736 | } |
737 | newOne.nElements_=nElements; |
738 | if (needClean) { |
739 | // go through again |
740 | newOne.nElements_=0; |
741 | for (i=0;i<nElements;i++) { |
742 | int indexValue=newOne.indices_[i]; |
743 | double value=newOne.elements_[indexValue]; |
744 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
745 | newOne.indices_[newOne.nElements_++]=indexValue; |
746 | } else { |
747 | newOne.elements_[indexValue]=0.0; |
748 | } |
749 | } |
750 | } |
751 | return newOne; |
752 | } |
753 | |
754 | /// Return the difference of two indexed vectors |
755 | CoinIndexedVector |
756 | CoinIndexedVector::operator-( |
757 | const CoinIndexedVector& op2) |
758 | { |
759 | assert (!packedMode_); |
760 | int i; |
761 | int nElements=nElements_; |
762 | int capacity = CoinMax(capacity_,op2.capacity_); |
763 | CoinIndexedVector newOne(*this); |
764 | newOne.reserve(capacity); |
765 | bool needClean=false; |
766 | // new one now can hold everything so just modify old and add new |
767 | for (i=0;i<op2.nElements_;i++) { |
768 | int indexValue=op2.indices_[i]; |
769 | double value=op2.elements_[indexValue]; |
770 | double oldValue=elements_[indexValue]; |
771 | if (!oldValue) { |
772 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
773 | newOne.elements_[indexValue]=-value; |
774 | newOne.indices_[nElements++]=indexValue; |
775 | } |
776 | } else { |
777 | value = oldValue-value; |
778 | newOne.elements_[indexValue]=value; |
779 | if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) { |
780 | needClean=true; |
781 | } |
782 | } |
783 | } |
784 | newOne.nElements_=nElements; |
785 | if (needClean) { |
786 | // go through again |
787 | newOne.nElements_=0; |
788 | for (i=0;i<nElements;i++) { |
789 | int indexValue=newOne.indices_[i]; |
790 | double value=newOne.elements_[indexValue]; |
791 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
792 | newOne.indices_[newOne.nElements_++]=indexValue; |
793 | } else { |
794 | newOne.elements_[indexValue]=0.0; |
795 | } |
796 | } |
797 | } |
798 | return newOne; |
799 | } |
800 | |
801 | /// Return the element-wise product of two indexed vectors |
802 | CoinIndexedVector |
803 | CoinIndexedVector::operator*( |
804 | const CoinIndexedVector& op2) |
805 | { |
806 | assert (!packedMode_); |
807 | int i; |
808 | int nElements=nElements_; |
809 | int capacity = CoinMax(capacity_,op2.capacity_); |
810 | CoinIndexedVector newOne(*this); |
811 | newOne.reserve(capacity); |
812 | bool needClean=false; |
813 | // new one now can hold everything so just modify old and add new |
814 | for (i=0;i<op2.nElements_;i++) { |
815 | int indexValue=op2.indices_[i]; |
816 | double value=op2.elements_[indexValue]; |
817 | double oldValue=elements_[indexValue]; |
818 | if (oldValue) { |
819 | value *= oldValue; |
820 | newOne.elements_[indexValue]=value; |
821 | if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) { |
822 | needClean=true; |
823 | } |
824 | } |
825 | } |
826 | |
827 | newOne.nElements_=nElements; |
828 | |
829 | if (needClean) { |
830 | // go through again |
831 | newOne.nElements_=0; |
832 | for (i=0;i<nElements;i++) { |
833 | int indexValue=newOne.indices_[i]; |
834 | double value=newOne.elements_[indexValue]; |
835 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
836 | newOne.indices_[newOne.nElements_++]=indexValue; |
837 | } else { |
838 | newOne.elements_[indexValue]=0.0; |
839 | } |
840 | } |
841 | } |
842 | return newOne; |
843 | } |
844 | |
845 | /// Return the element-wise ratio of two indexed vectors |
846 | CoinIndexedVector |
847 | CoinIndexedVector::operator/ (const CoinIndexedVector& op2) |
848 | { |
849 | assert (!packedMode_); |
850 | // I am treating 0.0/0.0 as 0.0 |
851 | int i; |
852 | int nElements=nElements_; |
853 | int capacity = CoinMax(capacity_,op2.capacity_); |
854 | CoinIndexedVector newOne(*this); |
855 | newOne.reserve(capacity); |
856 | bool needClean=false; |
857 | // new one now can hold everything so just modify old and add new |
858 | for (i=0;i<op2.nElements_;i++) { |
859 | int indexValue=op2.indices_[i]; |
860 | double value=op2.elements_[indexValue]; |
861 | double oldValue=elements_[indexValue]; |
862 | if (oldValue) { |
863 | if (!value) |
864 | throw CoinError("zero divisor" , "/" , "CoinIndexedVector" ); |
865 | value = oldValue/value; |
866 | newOne.elements_[indexValue]=value; |
867 | if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) { |
868 | needClean=true; |
869 | } |
870 | } |
871 | } |
872 | |
873 | newOne.nElements_=nElements; |
874 | |
875 | if (needClean) { |
876 | // go through again |
877 | newOne.nElements_=0; |
878 | for (i=0;i<nElements;i++) { |
879 | int indexValue=newOne.indices_[i]; |
880 | double value=newOne.elements_[indexValue]; |
881 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
882 | newOne.indices_[newOne.nElements_++]=indexValue; |
883 | } else { |
884 | newOne.elements_[indexValue]=0.0; |
885 | } |
886 | } |
887 | } |
888 | return newOne; |
889 | } |
890 | // The sum of two indexed vectors |
891 | void |
892 | CoinIndexedVector::operator+=(const CoinIndexedVector& op2) |
893 | { |
894 | // do slowly at first |
895 | *this = *this + op2; |
896 | } |
897 | |
898 | // The difference of two indexed vectors |
899 | void |
900 | CoinIndexedVector::operator-=( const CoinIndexedVector& op2) |
901 | { |
902 | // do slowly at first |
903 | *this = *this - op2; |
904 | } |
905 | |
906 | // The element-wise product of two indexed vectors |
907 | void |
908 | CoinIndexedVector::operator*=(const CoinIndexedVector& op2) |
909 | { |
910 | // do slowly at first |
911 | *this = *this * op2; |
912 | } |
913 | |
914 | // The element-wise ratio of two indexed vectors (0.0/0.0 => 0.0) (0 vanishes) |
915 | void |
916 | CoinIndexedVector::operator/=(const CoinIndexedVector& op2) |
917 | { |
918 | // do slowly at first |
919 | *this = *this / op2; |
920 | } |
921 | //############################################################################# |
922 | void |
923 | CoinIndexedVector::sortDecrIndex() |
924 | { |
925 | // Should replace with std sort |
926 | double * elements = new double [nElements_]; |
927 | CoinZeroN (elements,nElements_); |
928 | CoinSort_2(indices_, indices_ + nElements_, elements, |
929 | CoinFirstGreater_2<int, double>()); |
930 | delete [] elements; |
931 | } |
932 | |
933 | void |
934 | CoinIndexedVector::sortIncrElement() |
935 | { |
936 | double * elements = new double [nElements_]; |
937 | int i; |
938 | for (i=0;i<nElements_;i++) |
939 | elements[i] = elements_[indices_[i]]; |
940 | CoinSort_2(elements, elements + nElements_, indices_, |
941 | CoinFirstLess_2<double, int>()); |
942 | delete [] elements; |
943 | } |
944 | |
945 | void |
946 | CoinIndexedVector::sortDecrElement() |
947 | { |
948 | double * elements = new double [nElements_]; |
949 | int i; |
950 | for (i=0;i<nElements_;i++) |
951 | elements[i] = elements_[indices_[i]]; |
952 | CoinSort_2(elements, elements + nElements_, indices_, |
953 | CoinFirstGreater_2<double, int>()); |
954 | delete [] elements; |
955 | } |
956 | //############################################################################# |
957 | |
958 | void |
959 | CoinIndexedVector::gutsOfSetVector(int size, |
960 | const int * inds, const double * elems) |
961 | { |
962 | #ifndef COIN_FAST_CODE |
963 | if (size<0) |
964 | throw CoinError("negative number of indices" , "setVector" , "CoinIndexedVector" ); |
965 | #endif |
966 | assert(!packedMode_); |
967 | // find largest |
968 | int i; |
969 | int maxIndex=-1; |
970 | for (i=0;i<size;i++) { |
971 | int indexValue = inds[i]; |
972 | #ifndef COIN_FAST_CODE |
973 | if (indexValue<0) |
974 | throw CoinError("negative index" , "setVector" , "CoinIndexedVector" ); |
975 | #endif |
976 | if (maxIndex<indexValue) |
977 | maxIndex = indexValue; |
978 | } |
979 | reserve(maxIndex+1); |
980 | nElements_ = 0; |
981 | // elements_ array is all zero |
982 | bool needClean=false; |
983 | int numberDuplicates=0; |
984 | for (i=0;i<size;i++) { |
985 | int indexValue=inds[i]; |
986 | if (elements_[indexValue] == 0) |
987 | { |
988 | if (fabs(elems[i])>=COIN_INDEXED_TINY_ELEMENT) { |
989 | indices_[nElements_++]=indexValue; |
990 | elements_[indexValue]=elems[i]; |
991 | } |
992 | } |
993 | else |
994 | { |
995 | numberDuplicates++; |
996 | elements_[indexValue] += elems[i] ; |
997 | if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) |
998 | needClean=true; // need to go through again |
999 | } |
1000 | } |
1001 | if (needClean) { |
1002 | // go through again |
1003 | size=nElements_; |
1004 | nElements_=0; |
1005 | for (i=0;i<size;i++) { |
1006 | int indexValue=indices_[i]; |
1007 | double value=elements_[indexValue]; |
1008 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
1009 | indices_[nElements_++]=indexValue; |
1010 | } else { |
1011 | elements_[indexValue]=0.0; |
1012 | } |
1013 | } |
1014 | } |
1015 | if (numberDuplicates) |
1016 | throw CoinError("duplicate index" , "setVector" , "CoinIndexedVector" ); |
1017 | } |
1018 | |
1019 | //############################################################################# |
1020 | |
1021 | void |
1022 | CoinIndexedVector::gutsOfSetVector(int size, int numberIndices, |
1023 | const int * inds, const double * elems) |
1024 | { |
1025 | assert(!packedMode_); |
1026 | |
1027 | int i; |
1028 | reserve(size); |
1029 | #ifndef COIN_FAST_CODE |
1030 | if (numberIndices<0) |
1031 | throw CoinError("negative number of indices" , "setVector" , "CoinIndexedVector" ); |
1032 | #endif |
1033 | nElements_ = 0; |
1034 | // elements_ array is all zero |
1035 | bool needClean=false; |
1036 | int numberDuplicates=0; |
1037 | for (i=0;i<numberIndices;i++) { |
1038 | int indexValue=inds[i]; |
1039 | #ifndef COIN_FAST_CODE |
1040 | if (indexValue<0) |
1041 | throw CoinError("negative index" , "setVector" , "CoinIndexedVector" ); |
1042 | else if (indexValue>=size) |
1043 | throw CoinError("too large an index" , "setVector" , "CoinIndexedVector" ); |
1044 | #endif |
1045 | if (elements_[indexValue]) { |
1046 | numberDuplicates++; |
1047 | elements_[indexValue] += elems[indexValue] ; |
1048 | if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) |
1049 | needClean=true; // need to go through again |
1050 | } else { |
1051 | if (fabs(elems[indexValue])>=COIN_INDEXED_TINY_ELEMENT) { |
1052 | elements_[indexValue]=elems[indexValue]; |
1053 | indices_[nElements_++]=indexValue; |
1054 | } |
1055 | } |
1056 | } |
1057 | if (needClean) { |
1058 | // go through again |
1059 | size=nElements_; |
1060 | nElements_=0; |
1061 | for (i=0;i<size;i++) { |
1062 | int indexValue=indices_[i]; |
1063 | double value=elements_[indexValue]; |
1064 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
1065 | indices_[nElements_++]=indexValue; |
1066 | } else { |
1067 | elements_[indexValue]=0.0; |
1068 | } |
1069 | } |
1070 | } |
1071 | if (numberDuplicates) |
1072 | throw CoinError("duplicate index" , "setVector" , "CoinIndexedVector" ); |
1073 | } |
1074 | |
1075 | //----------------------------------------------------------------------------- |
1076 | |
1077 | void |
1078 | CoinIndexedVector::gutsOfSetPackedVector(int size, int numberIndices, |
1079 | const int * inds, const double * elems) |
1080 | { |
1081 | packedMode_=true; |
1082 | |
1083 | int i; |
1084 | reserve(size); |
1085 | #ifndef COIN_FAST_CODE |
1086 | if (numberIndices<0) |
1087 | throw CoinError("negative number of indices" , "setVector" , "CoinIndexedVector" ); |
1088 | #endif |
1089 | nElements_ = 0; |
1090 | // elements_ array is all zero |
1091 | // Does not check for duplicates |
1092 | for (i=0;i<numberIndices;i++) { |
1093 | int indexValue=inds[i]; |
1094 | #ifndef COIN_FAST_CODE |
1095 | if (indexValue<0) |
1096 | throw CoinError("negative index" , "setVector" , "CoinIndexedVector" ); |
1097 | else if (indexValue>=size) |
1098 | throw CoinError("too large an index" , "setVector" , "CoinIndexedVector" ); |
1099 | #endif |
1100 | if (fabs(elems[i])>=COIN_INDEXED_TINY_ELEMENT) { |
1101 | elements_[nElements_]=elems[i]; |
1102 | indices_[nElements_++]=indexValue; |
1103 | } |
1104 | } |
1105 | } |
1106 | |
1107 | //----------------------------------------------------------------------------- |
1108 | |
1109 | void |
1110 | CoinIndexedVector::gutsOfSetConstant(int size, |
1111 | const int * inds, double value) |
1112 | { |
1113 | |
1114 | assert(!packedMode_); |
1115 | #ifndef COIN_FAST_CODE |
1116 | if (size<0) |
1117 | throw CoinError("negative number of indices" , "setConstant" , "CoinIndexedVector" ); |
1118 | #endif |
1119 | // find largest |
1120 | int i; |
1121 | int maxIndex=-1; |
1122 | for (i=0;i<size;i++) { |
1123 | int indexValue = inds[i]; |
1124 | #ifndef COIN_FAST_CODE |
1125 | if (indexValue<0) |
1126 | throw CoinError("negative index" , "setConstant" , "CoinIndexedVector" ); |
1127 | #endif |
1128 | if (maxIndex<indexValue) |
1129 | maxIndex = indexValue; |
1130 | } |
1131 | |
1132 | reserve(maxIndex+1); |
1133 | nElements_ = 0; |
1134 | int numberDuplicates=0; |
1135 | // elements_ array is all zero |
1136 | bool needClean=false; |
1137 | for (i=0;i<size;i++) { |
1138 | int indexValue=inds[i]; |
1139 | if (elements_[indexValue] == 0) |
1140 | { |
1141 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
1142 | elements_[indexValue] += value; |
1143 | indices_[nElements_++]=indexValue; |
1144 | } |
1145 | } |
1146 | else |
1147 | { |
1148 | numberDuplicates++; |
1149 | elements_[indexValue] += value ; |
1150 | if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) |
1151 | needClean=true; // need to go through again |
1152 | } |
1153 | } |
1154 | if (needClean) { |
1155 | // go through again |
1156 | size=nElements_; |
1157 | nElements_=0; |
1158 | for (i=0;i<size;i++) { |
1159 | int indexValue=indices_[i]; |
1160 | double value=elements_[indexValue]; |
1161 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
1162 | indices_[nElements_++]=indexValue; |
1163 | } else { |
1164 | elements_[indexValue]=0.0; |
1165 | } |
1166 | } |
1167 | } |
1168 | if (numberDuplicates) |
1169 | throw CoinError("duplicate index" , "setConstant" , "CoinIndexedVector" ); |
1170 | } |
1171 | |
1172 | //############################################################################# |
1173 | // Append a CoinIndexedVector to the end |
1174 | void |
1175 | CoinIndexedVector::append(const CoinIndexedVector & caboose) |
1176 | { |
1177 | const int cs = caboose.getNumElements(); |
1178 | |
1179 | const int * cind = caboose.getIndices(); |
1180 | const double * celem = caboose.denseVector(); |
1181 | int maxIndex=-1; |
1182 | int i; |
1183 | for (i=0;i<cs;i++) { |
1184 | int indexValue = cind[i]; |
1185 | #ifndef COIN_FAST_CODE |
1186 | if (indexValue<0) |
1187 | throw CoinError("negative index" , "append" , "CoinIndexedVector" ); |
1188 | #endif |
1189 | if (maxIndex<indexValue) |
1190 | maxIndex = indexValue; |
1191 | } |
1192 | reserve(maxIndex+1); |
1193 | bool needClean=false; |
1194 | int numberDuplicates=0; |
1195 | for (i=0;i<cs;i++) { |
1196 | int indexValue=cind[i]; |
1197 | if (elements_[indexValue]) { |
1198 | numberDuplicates++; |
1199 | elements_[indexValue] += celem[indexValue] ; |
1200 | if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) |
1201 | needClean=true; // need to go through again |
1202 | } else { |
1203 | if (fabs(celem[indexValue])>=COIN_INDEXED_TINY_ELEMENT) { |
1204 | elements_[indexValue]=celem[indexValue]; |
1205 | indices_[nElements_++]=indexValue; |
1206 | } |
1207 | } |
1208 | } |
1209 | if (needClean) { |
1210 | // go through again |
1211 | int size=nElements_; |
1212 | nElements_=0; |
1213 | for (i=0;i<size;i++) { |
1214 | int indexValue=indices_[i]; |
1215 | double value=elements_[indexValue]; |
1216 | if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) { |
1217 | indices_[nElements_++]=indexValue; |
1218 | } else { |
1219 | elements_[indexValue]=0.0; |
1220 | } |
1221 | } |
1222 | } |
1223 | if (numberDuplicates) |
1224 | throw CoinError("duplicate index" , "append" , "CoinIndexedVector" ); |
1225 | } |
1226 | #ifndef CLP_NO_VECTOR |
1227 | /* Equal. Returns true if vectors have same length and corresponding |
1228 | element of each vector is equal. */ |
1229 | bool |
1230 | CoinIndexedVector::operator==(const CoinPackedVectorBase & rhs) const |
1231 | { |
1232 | const int cs = rhs.getNumElements(); |
1233 | |
1234 | const int * cind = rhs.getIndices(); |
1235 | const double * celem = rhs.getElements(); |
1236 | if (nElements_!=cs) |
1237 | return false; |
1238 | int i; |
1239 | bool okay=true; |
1240 | for (i=0;i<cs;i++) { |
1241 | int iRow = cind[i]; |
1242 | if (celem[i]!=elements_[iRow]) { |
1243 | okay=false; |
1244 | break; |
1245 | } |
1246 | } |
1247 | return okay; |
1248 | } |
1249 | // Not equal |
1250 | bool |
1251 | CoinIndexedVector::operator!=(const CoinPackedVectorBase & rhs) const |
1252 | { |
1253 | const int cs = rhs.getNumElements(); |
1254 | |
1255 | const int * cind = rhs.getIndices(); |
1256 | const double * celem = rhs.getElements(); |
1257 | if (nElements_!=cs) |
1258 | return true; |
1259 | int i; |
1260 | bool okay=false; |
1261 | for (i=0;i<cs;i++) { |
1262 | int iRow = cind[i]; |
1263 | if (celem[i]!=elements_[iRow]) { |
1264 | okay=true; |
1265 | break; |
1266 | } |
1267 | } |
1268 | return okay; |
1269 | } |
1270 | #endif |
1271 | /* Equal. Returns true if vectors have same length and corresponding |
1272 | element of each vector is equal. */ |
1273 | bool |
1274 | CoinIndexedVector::operator==(const CoinIndexedVector & rhs) const |
1275 | { |
1276 | const int cs = rhs.nElements_; |
1277 | |
1278 | const int * cind = rhs.indices_; |
1279 | const double * celem = rhs.elements_; |
1280 | if (nElements_!=cs) |
1281 | return false; |
1282 | int i; |
1283 | bool okay=true; |
1284 | CoinRelFltEq eq(1.0e-8); |
1285 | for (i=0;i<cs;i++) { |
1286 | int iRow = cind[i]; |
1287 | if (!eq(celem[iRow],elements_[iRow])) { |
1288 | okay=false; |
1289 | break; |
1290 | } |
1291 | } |
1292 | return okay; |
1293 | } |
1294 | /// Not equal |
1295 | bool |
1296 | CoinIndexedVector::operator!=(const CoinIndexedVector & rhs) const |
1297 | { |
1298 | const int cs = rhs.nElements_; |
1299 | |
1300 | const int * cind = rhs.indices_; |
1301 | const double * celem = rhs.elements_; |
1302 | if (nElements_!=cs) |
1303 | return true; |
1304 | int i; |
1305 | bool okay=false; |
1306 | for (i=0;i<cs;i++) { |
1307 | int iRow = cind[i]; |
1308 | if (celem[iRow]!=elements_[iRow]) { |
1309 | okay=true; |
1310 | break; |
1311 | } |
1312 | } |
1313 | return okay; |
1314 | } |
1315 | // Get value of maximum index |
1316 | int |
1317 | CoinIndexedVector::getMaxIndex() const |
1318 | { |
1319 | int maxIndex = -COIN_INT_MAX; |
1320 | int i; |
1321 | for (i=0;i<nElements_;i++) |
1322 | maxIndex = CoinMax(maxIndex,indices_[i]); |
1323 | return maxIndex; |
1324 | } |
1325 | // Get value of minimum index |
1326 | int |
1327 | CoinIndexedVector::getMinIndex() const |
1328 | { |
1329 | int minIndex = COIN_INT_MAX; |
1330 | int i; |
1331 | for (i=0;i<nElements_;i++) |
1332 | minIndex = CoinMin(minIndex,indices_[i]); |
1333 | return minIndex; |
1334 | } |
1335 | // Scan dense region and set up indices |
1336 | int |
1337 | CoinIndexedVector::scan() |
1338 | { |
1339 | nElements_=0; |
1340 | return scan(0,capacity_); |
1341 | } |
1342 | // Scan dense region from start to < end and set up indices |
1343 | int |
1344 | CoinIndexedVector::scan(int start, int end) |
1345 | { |
1346 | assert(!packedMode_); |
1347 | end = CoinMin(end,capacity_); |
1348 | start = CoinMax(start,0); |
1349 | int i; |
1350 | int number = 0; |
1351 | int * indices = indices_+nElements_; |
1352 | for (i=start;i<end;i++) |
1353 | if (elements_[i]) |
1354 | indices[number++] = i; |
1355 | nElements_ += number; |
1356 | return number; |
1357 | } |
1358 | // Scan dense region and set up indices with tolerance |
1359 | int |
1360 | CoinIndexedVector::scan(double tolerance) |
1361 | { |
1362 | nElements_=0; |
1363 | return scan(0,capacity_,tolerance); |
1364 | } |
1365 | // Scan dense region from start to < end and set up indices with tolerance |
1366 | int |
1367 | CoinIndexedVector::scan(int start, int end, double tolerance) |
1368 | { |
1369 | assert(!packedMode_); |
1370 | end = CoinMin(end,capacity_); |
1371 | start = CoinMax(start,0); |
1372 | int i; |
1373 | int number = 0; |
1374 | int * indices = indices_+nElements_; |
1375 | for (i=start;i<end;i++) { |
1376 | double value = elements_[i]; |
1377 | if (value) { |
1378 | if (fabs(value)>=tolerance) |
1379 | indices[number++] = i; |
1380 | else |
1381 | elements_[i]=0.0; |
1382 | } |
1383 | } |
1384 | nElements_ += number; |
1385 | return number; |
1386 | } |
1387 | // These pack down |
1388 | int |
1389 | CoinIndexedVector::cleanAndPack( double tolerance ) |
1390 | { |
1391 | int number = nElements_; |
1392 | int i; |
1393 | nElements_=0; |
1394 | assert(!packedMode_); |
1395 | for (i=0;i<number;i++) { |
1396 | int indexValue = indices_[i]; |
1397 | double value = elements_[indexValue]; |
1398 | elements_[indexValue]=0.0; |
1399 | if (fabs(value)>=tolerance) { |
1400 | elements_[nElements_]=value; |
1401 | indices_[nElements_++]=indexValue; |
1402 | } |
1403 | } |
1404 | packedMode_=true; |
1405 | return nElements_; |
1406 | } |
1407 | // These pack down |
1408 | int |
1409 | CoinIndexedVector::cleanAndPackSafe( double tolerance ) |
1410 | { |
1411 | int number = nElements_; |
1412 | if (number) { |
1413 | int i; |
1414 | nElements_=0; |
1415 | assert(!packedMode_); |
1416 | double * temp=NULL; |
1417 | bool gotMemory; |
1418 | if (number*3<capacity_-3-9999999) { |
1419 | // can find room without new |
1420 | gotMemory=false; |
1421 | // But may need to align on 8 byte boundary |
1422 | char * tempC = reinterpret_cast<char *> (indices_+number); |
1423 | CoinInt64 xx = reinterpret_cast<CoinInt64>(tempC); |
1424 | CoinInt64 iBottom = xx & 7; |
1425 | if (iBottom) |
1426 | tempC += 8-iBottom; |
1427 | temp = reinterpret_cast<double *> (tempC); |
1428 | xx = reinterpret_cast<CoinInt64>(temp); |
1429 | iBottom = xx & 7; |
1430 | assert(!iBottom); |
1431 | } else { |
1432 | // might be better to do complete scan |
1433 | gotMemory=true; |
1434 | temp = new double[number]; |
1435 | } |
1436 | for (i=0;i<number;i++) { |
1437 | int indexValue = indices_[i]; |
1438 | double value = elements_[indexValue]; |
1439 | elements_[indexValue]=0.0; |
1440 | if (fabs(value)>=tolerance) { |
1441 | temp[nElements_]=value; |
1442 | indices_[nElements_++]=indexValue; |
1443 | } |
1444 | } |
1445 | CoinMemcpyN(temp,nElements_,elements_); |
1446 | if (gotMemory) |
1447 | delete [] temp; |
1448 | packedMode_=true; |
1449 | } |
1450 | return nElements_; |
1451 | } |
1452 | // Scan dense region and set up indices |
1453 | int |
1454 | CoinIndexedVector::scanAndPack() |
1455 | { |
1456 | nElements_=0; |
1457 | return scanAndPack(0,capacity_); |
1458 | } |
1459 | // Scan dense region from start to < end and set up indices |
1460 | int |
1461 | CoinIndexedVector::scanAndPack(int start, int end) |
1462 | { |
1463 | assert(!packedMode_); |
1464 | end = CoinMin(end,capacity_); |
1465 | start = CoinMax(start,0); |
1466 | int i; |
1467 | int number = 0; |
1468 | int * indices = indices_+nElements_; |
1469 | for (i=start;i<end;i++) { |
1470 | double value = elements_[i]; |
1471 | elements_[i]=0.0; |
1472 | if (value) { |
1473 | elements_[number]=value; |
1474 | indices[number++] = i; |
1475 | } |
1476 | } |
1477 | nElements_ += number; |
1478 | packedMode_=true; |
1479 | return number; |
1480 | } |
1481 | // Scan dense region and set up indices with tolerance |
1482 | int |
1483 | CoinIndexedVector::scanAndPack(double tolerance) |
1484 | { |
1485 | nElements_=0; |
1486 | return scanAndPack(0,capacity_,tolerance); |
1487 | } |
1488 | // Scan dense region from start to < end and set up indices with tolerance |
1489 | int |
1490 | CoinIndexedVector::scanAndPack(int start, int end, double tolerance) |
1491 | { |
1492 | assert(!packedMode_); |
1493 | end = CoinMin(end,capacity_); |
1494 | start = CoinMax(start,0); |
1495 | int i; |
1496 | int number = 0; |
1497 | int * indices = indices_+nElements_; |
1498 | for (i=start;i<end;i++) { |
1499 | double value = elements_[i]; |
1500 | elements_[i]=0.0; |
1501 | if (fabs(value)>=tolerance) { |
1502 | elements_[number]=value; |
1503 | indices[number++] = i; |
1504 | } |
1505 | } |
1506 | nElements_ += number; |
1507 | packedMode_=true; |
1508 | return number; |
1509 | } |
1510 | // This is mainly for testing - goes from packed to indexed |
1511 | void |
1512 | CoinIndexedVector::expand() |
1513 | { |
1514 | if (nElements_&&packedMode_) { |
1515 | double * temp = new double[capacity_]; |
1516 | int i; |
1517 | for (i=0;i<nElements_;i++) |
1518 | temp[indices_[i]]=elements_[i]; |
1519 | CoinZeroN(elements_,nElements_); |
1520 | for (i=0;i<nElements_;i++) { |
1521 | int iRow = indices_[i]; |
1522 | elements_[iRow]=temp[iRow]; |
1523 | } |
1524 | delete [] temp; |
1525 | } |
1526 | packedMode_=false; |
1527 | } |
1528 | // Create packed array |
1529 | void |
1530 | CoinIndexedVector::createPacked(int number, const int * indices, |
1531 | const double * elements) |
1532 | { |
1533 | nElements_=number; |
1534 | packedMode_=true; |
1535 | CoinMemcpyN(indices,number,indices_); |
1536 | CoinMemcpyN(elements,number,elements_); |
1537 | } |
1538 | // Print out |
1539 | void |
1540 | CoinIndexedVector::print() const |
1541 | { |
1542 | printf("Vector has %d elements (%spacked mode)\n" ,nElements_,packedMode_ ? "" : "un" ); |
1543 | for (int i=0;i<nElements_;i++) { |
1544 | if (i&&(i%5==0)) |
1545 | printf("\n" ); |
1546 | int index = indices_[i]; |
1547 | double value = packedMode_ ? elements_[i] : elements_[index]; |
1548 | printf(" (%d,%g)" ,index,value); |
1549 | } |
1550 | printf("\n" ); |
1551 | } |
1552 | |
1553 | // Zero out array |
1554 | void |
1555 | CoinArrayWithLength::clear() |
1556 | { |
1557 | assert ((size_>0&&array_)||!array_); |
1558 | memset (array_,0,size_); |
1559 | } |
1560 | static char * mallocArray(long size) |
1561 | { |
1562 | if (size>0) { |
1563 | char * array = new char [size]; |
1564 | return array; |
1565 | } else { |
1566 | return NULL; |
1567 | } |
1568 | } |
1569 | static void freeArray(void * array) |
1570 | { |
1571 | char * charArray = reinterpret_cast<char *> (array); |
1572 | delete [] charArray; |
1573 | } |
1574 | // Conditionally gets new array |
1575 | char * |
1576 | CoinArrayWithLength::conditionalNew(long sizeWanted) |
1577 | { |
1578 | if (size_==-1) { |
1579 | freeArray(array_); |
1580 | array_ = mallocArray(sizeWanted); |
1581 | } else { |
1582 | setCapacity(); |
1583 | if (sizeWanted>size_) { |
1584 | freeArray(array_); |
1585 | size_ = static_cast<int> (sizeWanted*101/100)+64; |
1586 | // round to multiple of 16 |
1587 | size_ -= size_%16; |
1588 | array_ = mallocArray(size_); |
1589 | } |
1590 | } |
1591 | return array_; |
1592 | } |
1593 | // Conditionally deletes |
1594 | void |
1595 | CoinArrayWithLength::conditionalDelete() |
1596 | { |
1597 | if (size_==-1) { |
1598 | freeArray(array_); |
1599 | array_=NULL; |
1600 | } else if (size_>=0) { |
1601 | size_ = -size_-2; |
1602 | } |
1603 | } |
1604 | /* Copy constructor. */ |
1605 | CoinArrayWithLength::CoinArrayWithLength(const CoinArrayWithLength & rhs) |
1606 | { |
1607 | assert (rhs.getCapacity()>=0); |
1608 | size_=rhs.size_; |
1609 | array_ = mallocArray(getCapacity()); |
1610 | if (size_>0) |
1611 | CoinMemcpyN(rhs.array_,size_,array_); |
1612 | } |
1613 | |
1614 | /* Copy constructor.2 */ |
1615 | CoinArrayWithLength::CoinArrayWithLength(const CoinArrayWithLength * rhs) |
1616 | { |
1617 | assert (rhs->getCapacity()>=0); |
1618 | size_=rhs->size_; |
1619 | array_ = mallocArray(getCapacity()); |
1620 | if (size_>0) |
1621 | CoinMemcpyN(rhs->array_,size_,array_); |
1622 | } |
1623 | /* Assignment operator. */ |
1624 | CoinArrayWithLength & |
1625 | CoinArrayWithLength::operator=(const CoinArrayWithLength & rhs) |
1626 | { |
1627 | if (this != &rhs) { |
1628 | assert (rhs.size_!=-1||!rhs.array_); |
1629 | if (rhs.size_==-1) { |
1630 | freeArray(array_); |
1631 | array_=NULL; |
1632 | size_=-1; |
1633 | } else { |
1634 | int capacity = getCapacity(); |
1635 | int rhsCapacity = rhs.getCapacity(); |
1636 | if (capacity<rhsCapacity) { |
1637 | freeArray(array_); |
1638 | array_ = mallocArray(rhsCapacity); |
1639 | } |
1640 | size_=rhs.size_; |
1641 | if (size_>0) |
1642 | CoinMemcpyN(rhs.array_,size_,array_); |
1643 | } |
1644 | } |
1645 | return *this; |
1646 | } |
1647 | /* Assignment with length (if -1 use internal length) */ |
1648 | void |
1649 | CoinArrayWithLength::copy(const CoinArrayWithLength & rhs, int numberBytes) |
1650 | { |
1651 | if (numberBytes==-1||numberBytes<=rhs.getCapacity()) { |
1652 | CoinArrayWithLength::operator=(rhs); |
1653 | } else { |
1654 | assert (numberBytes>=0); |
1655 | if (size_==-1) { |
1656 | freeArray(array_); |
1657 | array_=NULL; |
1658 | } else { |
1659 | size_=-1; |
1660 | } |
1661 | if (rhs.size_>=0) |
1662 | size_ = numberBytes; |
1663 | array_ = mallocArray(numberBytes); |
1664 | if (rhs.array_) |
1665 | CoinMemcpyN(rhs.array_,numberBytes,array_); |
1666 | } |
1667 | } |
1668 | /* Assignment with length - does not copy */ |
1669 | void |
1670 | CoinArrayWithLength::allocate(const CoinArrayWithLength & rhs, int numberBytes) |
1671 | { |
1672 | if (numberBytes==-1||numberBytes<=rhs.getCapacity()) { |
1673 | assert (rhs.size_!=-1||!rhs.array_); |
1674 | if (rhs.size_==-1) { |
1675 | freeArray(array_); |
1676 | array_=NULL; |
1677 | size_=-1; |
1678 | } else { |
1679 | int capacity = getCapacity(); |
1680 | int rhsCapacity = rhs.getCapacity(); |
1681 | if (capacity<rhsCapacity) { |
1682 | freeArray(array_); |
1683 | array_ = mallocArray(rhsCapacity); |
1684 | } |
1685 | size_=rhs.size_; |
1686 | } |
1687 | } else { |
1688 | assert (numberBytes>=0); |
1689 | if (size_==-1) { |
1690 | freeArray(array_); |
1691 | array_=NULL; |
1692 | } else { |
1693 | size_=-1; |
1694 | } |
1695 | if (rhs.size_>=0) |
1696 | size_ = numberBytes; |
1697 | array_ = mallocArray(numberBytes); |
1698 | } |
1699 | } |
1700 | // Does what is needed to set persistence |
1701 | void |
1702 | CoinArrayWithLength::setPersistence(int flag,int currentLength) |
1703 | { |
1704 | if (flag) { |
1705 | if (size_==-1) { |
1706 | if (currentLength&&array_) { |
1707 | size_=currentLength; |
1708 | } else { |
1709 | size_=0; |
1710 | freeArray(array_); |
1711 | array_=NULL; |
1712 | } |
1713 | } |
1714 | } else { |
1715 | size_=-1; |
1716 | } |
1717 | } |
1718 | // Swaps memory between two members |
1719 | void |
1720 | CoinArrayWithLength::swap(CoinArrayWithLength & other) |
1721 | { |
1722 | #ifdef COIN_DEVELOP |
1723 | if (!(size_==other.size_||size_==-1||other.size_==-1)) |
1724 | printf("Two arrays have sizes - %d and %d\n" ,size_,other.size_); |
1725 | #endif |
1726 | char * swapArray = other.array_; |
1727 | other.array_=array_; |
1728 | array_=swapArray; |
1729 | int swapSize = other.size_; |
1730 | other.size_=size_; |
1731 | size_=swapSize; |
1732 | } |
1733 | // Extend a persistent array keeping data (size in bytes) |
1734 | void |
1735 | CoinArrayWithLength::extend(int newSize) |
1736 | { |
1737 | //assert (newSize>=getCapacity()&&getCapacity()>=0); |
1738 | assert (size_>=0); // not much point otherwise |
1739 | if (newSize>size_) { |
1740 | char * temp = mallocArray(newSize); |
1741 | CoinMemcpyN(array_,size_,temp); |
1742 | freeArray(array_); |
1743 | array_=temp; |
1744 | size_=newSize; |
1745 | } |
1746 | } |
1747 | |