1 | /* $Id: CoinPackedVector.cpp 1373 2011-01-03 23:57:44Z lou $ */ |
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 | |
13 | #include "CoinHelperFunctions.hpp" |
14 | #include "CoinPackedVector.hpp" |
15 | |
16 | //############################################################################# |
17 | |
18 | void |
19 | CoinPackedVector::clear() |
20 | { |
21 | nElements_ = 0; |
22 | clearBase(); |
23 | } |
24 | |
25 | //############################################################################# |
26 | |
27 | CoinPackedVector & |
28 | CoinPackedVector::operator=(const CoinPackedVector & rhs) |
29 | { |
30 | if (this != &rhs) { |
31 | clear(); |
32 | gutsOfSetVector(rhs.getNumElements(), rhs.getIndices(), rhs.getElements(), |
33 | CoinPackedVectorBase::testForDuplicateIndex(), |
34 | "operator=" ); |
35 | } |
36 | return *this; |
37 | } |
38 | |
39 | //############################################################################# |
40 | |
41 | CoinPackedVector & |
42 | CoinPackedVector::operator=(const CoinPackedVectorBase & rhs) |
43 | { |
44 | if (this != &rhs) { |
45 | clear(); |
46 | gutsOfSetVector(rhs.getNumElements(), rhs.getIndices(), rhs.getElements(), |
47 | CoinPackedVectorBase::testForDuplicateIndex(), |
48 | "operator= from base" ); |
49 | } |
50 | return *this; |
51 | } |
52 | |
53 | //############################################################################# |
54 | #if 0 |
55 | void |
56 | CoinPackedVector::assignVector(int size, int*& inds, double*& elems, |
57 | bool testForDuplicateIndex) |
58 | { |
59 | clear(); |
60 | // Allocate storage |
61 | if ( size != 0 ) { |
62 | reserve(size); |
63 | nElements_ = size; |
64 | indices_ = inds; inds = NULL; |
65 | elements_ = elems; elems = NULL; |
66 | CoinIotaN(origIndices_, size, 0); |
67 | } |
68 | try { |
69 | CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex); |
70 | } |
71 | catch (CoinError e) { |
72 | throw CoinError("duplicate index" , "assignVector" , "CoinPackedVector" ); |
73 | } |
74 | } |
75 | #else |
76 | void |
77 | CoinPackedVector::assignVector(int size, int*& inds, double*& elems, |
78 | bool testForDuplicateIndex) |
79 | { |
80 | clear(); |
81 | // Allocate storage |
82 | if ( size != 0 ) { |
83 | //reserve(size); //This is a BUG!!! |
84 | nElements_ = size; |
85 | if (indices_ != NULL) delete[] indices_; |
86 | indices_ = inds; inds = NULL; |
87 | if (elements_ != NULL) delete[] elements_; |
88 | elements_ = elems; elems = NULL; |
89 | if (origIndices_ != NULL) delete[] origIndices_; |
90 | origIndices_ = new int[size]; |
91 | CoinIotaN(origIndices_, size, 0); |
92 | capacity_ = size; |
93 | } |
94 | if (testForDuplicateIndex) { |
95 | try { |
96 | CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex); |
97 | } |
98 | catch (CoinError e) { |
99 | throw CoinError("duplicate index" , "assignVector" , |
100 | "CoinPackedVector" ); |
101 | } |
102 | } else { |
103 | setTestsOff(); |
104 | } |
105 | } |
106 | #endif |
107 | |
108 | //############################################################################# |
109 | |
110 | void |
111 | CoinPackedVector::setVector(int size, const int * inds, const double * elems, |
112 | bool testForDuplicateIndex) |
113 | { |
114 | clear(); |
115 | gutsOfSetVector(size, inds, elems, testForDuplicateIndex, "setVector" ); |
116 | } |
117 | |
118 | //############################################################################# |
119 | |
120 | void |
121 | CoinPackedVector::setConstant(int size, const int * inds, double value, |
122 | bool testForDuplicateIndex) |
123 | { |
124 | clear(); |
125 | gutsOfSetConstant(size, inds, value, testForDuplicateIndex, "setConstant" ); |
126 | } |
127 | |
128 | //############################################################################# |
129 | |
130 | void |
131 | CoinPackedVector::setFull(int size, const double * elems, |
132 | bool testForDuplicateIndex) |
133 | { |
134 | // Clear out any values presently stored |
135 | clear(); |
136 | |
137 | // Allocate storage |
138 | if ( size!=0 ) { |
139 | reserve(size); |
140 | nElements_ = size; |
141 | |
142 | CoinIotaN(origIndices_, size, 0); |
143 | CoinIotaN(indices_, size, 0); |
144 | CoinDisjointCopyN(elems, size, elements_); |
145 | } |
146 | // Full array can not have duplicates |
147 | CoinPackedVectorBase::setTestForDuplicateIndexWhenTrue(testForDuplicateIndex); |
148 | } |
149 | |
150 | //############################################################################# |
151 | /* Indices are not specified and are taken to be 0,1,...,size-1, |
152 | but only where non zero*/ |
153 | |
154 | void |
155 | CoinPackedVector::setFullNonZero(int size, const double * elems, |
156 | bool testForDuplicateIndex) |
157 | { |
158 | // Clear out any values presently stored |
159 | clear(); |
160 | |
161 | // For now waste space |
162 | // Allocate storage |
163 | if ( size!=0 ) { |
164 | reserve(size); |
165 | nElements_ = 0; |
166 | int i; |
167 | for (i=0;i<size;i++) { |
168 | if (elems[i]) { |
169 | origIndices_[nElements_]= i; |
170 | indices_[nElements_]= i; |
171 | elements_[nElements_++] = elems[i]; |
172 | } |
173 | } |
174 | } |
175 | // Full array can not have duplicates |
176 | CoinPackedVectorBase::setTestForDuplicateIndexWhenTrue(testForDuplicateIndex); |
177 | } |
178 | |
179 | |
180 | //############################################################################# |
181 | |
182 | void |
183 | CoinPackedVector::setElement(int index, double element) |
184 | { |
185 | #ifndef COIN_FAST_CODE |
186 | if ( index >= nElements_ ) |
187 | throw CoinError("index >= size()" , "setElement" , "CoinPackedVector" ); |
188 | if ( index < 0 ) |
189 | throw CoinError("index < 0" , "setElement" , "CoinPackedVector" ); |
190 | #endif |
191 | elements_[index] = element; |
192 | } |
193 | |
194 | //############################################################################# |
195 | |
196 | void |
197 | CoinPackedVector::insert( int index, double element ) |
198 | { |
199 | const int s = nElements_; |
200 | if (testForDuplicateIndex()) { |
201 | std::set<int>& is = *indexSet("insert" , "CoinPackedVector" ); |
202 | if (! is.insert(index).second) |
203 | throw CoinError("Index already exists" , "insert" , "CoinPackedVector" ); |
204 | } |
205 | |
206 | if( capacity_ <= s ) { |
207 | reserve( CoinMax(5, 2*capacity_) ); |
208 | assert( capacity_ > s ); |
209 | } |
210 | indices_[s] = index; |
211 | elements_[s] = element; |
212 | origIndices_[s] = s; |
213 | ++nElements_; |
214 | } |
215 | |
216 | //############################################################################# |
217 | |
218 | void |
219 | CoinPackedVector::append(const CoinPackedVectorBase & caboose) |
220 | { |
221 | const int cs = caboose.getNumElements(); |
222 | if (cs == 0) { |
223 | return; |
224 | } |
225 | if (testForDuplicateIndex()) { |
226 | // Just to initialize the index heap |
227 | indexSet("append (1st call)" , "CoinPackedVector" ); |
228 | } |
229 | const int s = nElements_; |
230 | // Make sure there is enough room for the caboose |
231 | if ( capacity_ < s + cs) |
232 | reserve(CoinMax(s + cs, 2 * capacity_)); |
233 | |
234 | const int * cind = caboose.getIndices(); |
235 | const double * celem = caboose.getElements(); |
236 | CoinDisjointCopyN(cind, cs, indices_ + s); |
237 | CoinDisjointCopyN(celem, cs, elements_ + s); |
238 | CoinIotaN(origIndices_ + s, cs, s); |
239 | nElements_ += cs; |
240 | if (testForDuplicateIndex()) { |
241 | std::set<int>& is = *indexSet("append (2nd call)" , "CoinPackedVector" ); |
242 | for (int i = 0; i < cs; ++i) { |
243 | if (!is.insert(cind[i]).second) |
244 | throw CoinError("duplicate index" , "append" , "CoinPackedVector" ); |
245 | } |
246 | } |
247 | } |
248 | |
249 | //############################################################################# |
250 | |
251 | void |
252 | CoinPackedVector::swap(int i, int j) |
253 | { |
254 | if ( i >= nElements_ ) |
255 | throw CoinError("index i >= size()" ,"swap" ,"CoinPackedVector" ); |
256 | if ( i < 0 ) |
257 | throw CoinError("index i < 0" ,"swap" ,"CoinPackedVector" ); |
258 | if ( i >= nElements_ ) |
259 | throw CoinError("index j >= size()" ,"swap" ,"CoinPackedVector" ); |
260 | if ( i < 0 ) |
261 | throw CoinError("index j < 0" ,"swap" ,"CoinPackedVector" ); |
262 | |
263 | // Swap positions i and j of the |
264 | // indices and elements arrays |
265 | std::swap(indices_[i], indices_[j]); |
266 | std::swap(elements_[i], elements_[j]); |
267 | } |
268 | |
269 | //############################################################################# |
270 | |
271 | void |
272 | CoinPackedVector::truncate( int n ) |
273 | { |
274 | if ( n > nElements_ ) |
275 | throw CoinError("n > size()" ,"truncate" ,"CoinPackedVector" ); |
276 | if ( n < 0 ) |
277 | throw CoinError("n < 0" ,"truncate" ,"CoinPackedVector" ); |
278 | nElements_ = n; |
279 | clearBase(); |
280 | } |
281 | |
282 | //############################################################################# |
283 | |
284 | void |
285 | CoinPackedVector::operator+=(double value) |
286 | { |
287 | std::transform(elements_, elements_ + nElements_, elements_, |
288 | std::bind2nd(std::plus<double>(), value) ); |
289 | } |
290 | |
291 | //----------------------------------------------------------------------------- |
292 | |
293 | void |
294 | CoinPackedVector::operator-=(double value) |
295 | { |
296 | std::transform(elements_, elements_ + nElements_, elements_, |
297 | std::bind2nd(std::minus<double>(), value) ); |
298 | } |
299 | |
300 | //----------------------------------------------------------------------------- |
301 | |
302 | void |
303 | CoinPackedVector::operator*=(double value) |
304 | { |
305 | std::transform(elements_, elements_ + nElements_, elements_, |
306 | std::bind2nd(std::multiplies<double>(), value) ); |
307 | } |
308 | |
309 | //----------------------------------------------------------------------------- |
310 | |
311 | void |
312 | CoinPackedVector::operator/=(double value) |
313 | { |
314 | std::transform(elements_, elements_ + nElements_, elements_, |
315 | std::bind2nd(std::divides<double>(), value) ); |
316 | } |
317 | |
318 | //############################################################################# |
319 | |
320 | void |
321 | CoinPackedVector::sortOriginalOrder() { |
322 | CoinSort_3(origIndices_, origIndices_ + nElements_, indices_, elements_); |
323 | } |
324 | |
325 | //############################################################################# |
326 | |
327 | void |
328 | CoinPackedVector::reserve(int n) |
329 | { |
330 | // don't make allocated space smaller |
331 | if ( n <= capacity_ ) |
332 | return; |
333 | capacity_ = n; |
334 | |
335 | // save pointers to existing data |
336 | int * tempIndices = indices_; |
337 | int * tempOrigIndices = origIndices_; |
338 | double * tempElements = elements_; |
339 | |
340 | // allocate new space |
341 | indices_ = new int [capacity_]; |
342 | origIndices_ = new int [capacity_]; |
343 | elements_ = new double [capacity_]; |
344 | |
345 | // copy data to new space |
346 | if (nElements_ > 0) { |
347 | CoinDisjointCopyN(tempIndices, nElements_, indices_); |
348 | CoinDisjointCopyN(tempOrigIndices, nElements_, origIndices_); |
349 | CoinDisjointCopyN(tempElements, nElements_, elements_); |
350 | } |
351 | |
352 | // free old data |
353 | delete [] tempElements; |
354 | delete [] tempOrigIndices; |
355 | delete [] tempIndices; |
356 | } |
357 | |
358 | //############################################################################# |
359 | |
360 | CoinPackedVector::CoinPackedVector (bool testForDuplicateIndex) : |
361 | CoinPackedVectorBase(), |
362 | indices_(NULL), |
363 | elements_(NULL), |
364 | nElements_(0), |
365 | origIndices_(NULL), |
366 | capacity_(0) |
367 | { |
368 | // This won't fail, the packed vector is empty. There can't be duplicate |
369 | // indices. |
370 | CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex); |
371 | } |
372 | |
373 | //----------------------------------------------------------------------------- |
374 | |
375 | CoinPackedVector::CoinPackedVector(int size, |
376 | const int * inds, const double * elems, |
377 | bool testForDuplicateIndex) : |
378 | CoinPackedVectorBase(), |
379 | indices_(NULL), |
380 | elements_(NULL), |
381 | nElements_(0), |
382 | origIndices_(NULL), |
383 | capacity_(0) |
384 | { |
385 | gutsOfSetVector(size, inds, elems, testForDuplicateIndex, |
386 | "constructor for array value" ); |
387 | } |
388 | |
389 | //----------------------------------------------------------------------------- |
390 | |
391 | CoinPackedVector::CoinPackedVector(int size, |
392 | const int * inds, double value, |
393 | bool testForDuplicateIndex) : |
394 | CoinPackedVectorBase(), |
395 | indices_(NULL), |
396 | elements_(NULL), |
397 | nElements_(0), |
398 | origIndices_(NULL), |
399 | capacity_(0) |
400 | { |
401 | gutsOfSetConstant(size, inds, value, testForDuplicateIndex, |
402 | "constructor for constant value" ); |
403 | } |
404 | |
405 | //----------------------------------------------------------------------------- |
406 | |
407 | CoinPackedVector::CoinPackedVector(int capacity, int size, |
408 | int *&inds, double *&elems, |
409 | bool /*testForDuplicateIndex*/) : |
410 | CoinPackedVectorBase(), |
411 | indices_(inds), |
412 | elements_(elems), |
413 | nElements_(size), |
414 | origIndices_(NULL), |
415 | capacity_(capacity) |
416 | { |
417 | assert( size <= capacity ); |
418 | inds = NULL; |
419 | elems = NULL; |
420 | origIndices_ = new int[capacity_]; |
421 | CoinIotaN(origIndices_, size, 0); |
422 | } |
423 | |
424 | //----------------------------------------------------------------------------- |
425 | |
426 | CoinPackedVector::CoinPackedVector(int size, const double * element, |
427 | bool testForDuplicateIndex) : |
428 | CoinPackedVectorBase(), |
429 | indices_(NULL), |
430 | elements_(NULL), |
431 | nElements_(0), |
432 | origIndices_(NULL), |
433 | capacity_(0) |
434 | { |
435 | setFull(size, element, testForDuplicateIndex); |
436 | } |
437 | |
438 | //----------------------------------------------------------------------------- |
439 | |
440 | CoinPackedVector::CoinPackedVector(const CoinPackedVectorBase & rhs) : |
441 | CoinPackedVectorBase(), |
442 | indices_(NULL), |
443 | elements_(NULL), |
444 | nElements_(0), |
445 | origIndices_(NULL), |
446 | capacity_(0) |
447 | { |
448 | gutsOfSetVector(rhs.getNumElements(), rhs.getIndices(), rhs.getElements(), |
449 | rhs.testForDuplicateIndex(), "copy constructor from base" ); |
450 | } |
451 | |
452 | //----------------------------------------------------------------------------- |
453 | |
454 | CoinPackedVector::CoinPackedVector(const CoinPackedVector & rhs) : |
455 | CoinPackedVectorBase(), |
456 | indices_(NULL), |
457 | elements_(NULL), |
458 | nElements_(0), |
459 | origIndices_(NULL), |
460 | capacity_(0) |
461 | { |
462 | gutsOfSetVector(rhs.getNumElements(), rhs.getIndices(), rhs.getElements(), |
463 | rhs.testForDuplicateIndex(), "copy constructor" ); |
464 | } |
465 | |
466 | //----------------------------------------------------------------------------- |
467 | |
468 | CoinPackedVector::~CoinPackedVector () |
469 | { |
470 | delete [] indices_; |
471 | delete [] origIndices_; |
472 | delete [] elements_; |
473 | } |
474 | |
475 | //############################################################################# |
476 | |
477 | void |
478 | CoinPackedVector::gutsOfSetVector(int size, |
479 | const int * inds, const double * elems, |
480 | bool testForDuplicateIndex, |
481 | const char * method) |
482 | { |
483 | if ( size != 0 ) { |
484 | reserve(size); |
485 | nElements_ = size; |
486 | CoinDisjointCopyN(inds, size, indices_); |
487 | CoinDisjointCopyN(elems, size, elements_); |
488 | CoinIotaN(origIndices_, size, 0); |
489 | } |
490 | if (testForDuplicateIndex) { |
491 | try { |
492 | CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex); |
493 | } |
494 | catch (CoinError e) { |
495 | throw CoinError("duplicate index" , method, "CoinPackedVector" ); |
496 | } |
497 | } else { |
498 | setTestsOff(); |
499 | } |
500 | } |
501 | |
502 | //----------------------------------------------------------------------------- |
503 | |
504 | void |
505 | CoinPackedVector::gutsOfSetConstant(int size, |
506 | const int * inds, double value, |
507 | bool testForDuplicateIndex, |
508 | const char * method) |
509 | { |
510 | if ( size != 0 ) { |
511 | reserve(size); |
512 | nElements_ = size; |
513 | CoinDisjointCopyN(inds, size, indices_); |
514 | CoinFillN(elements_, size, value); |
515 | CoinIotaN(origIndices_, size, 0); |
516 | } |
517 | try { |
518 | CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex); |
519 | } |
520 | catch (CoinError e) { |
521 | throw CoinError("duplicate index" , method, "CoinPackedVector" ); |
522 | } |
523 | } |
524 | |
525 | //############################################################################# |
526 | |