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
18void
19CoinPackedVector::clear()
20{
21 nElements_ = 0;
22 clearBase();
23}
24
25//#############################################################################
26
27CoinPackedVector &
28CoinPackedVector::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
41CoinPackedVector &
42CoinPackedVector::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
55void
56CoinPackedVector::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
76void
77CoinPackedVector::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
110void
111CoinPackedVector::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
120void
121CoinPackedVector::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
130void
131CoinPackedVector::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
154void
155CoinPackedVector::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
182void
183CoinPackedVector::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
196void
197CoinPackedVector::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
218void
219CoinPackedVector::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
251void
252CoinPackedVector::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
271void
272CoinPackedVector::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
284void
285CoinPackedVector::operator+=(double value)
286{
287 std::transform(elements_, elements_ + nElements_, elements_,
288 std::bind2nd(std::plus<double>(), value) );
289}
290
291//-----------------------------------------------------------------------------
292
293void
294CoinPackedVector::operator-=(double value)
295{
296 std::transform(elements_, elements_ + nElements_, elements_,
297 std::bind2nd(std::minus<double>(), value) );
298}
299
300//-----------------------------------------------------------------------------
301
302void
303CoinPackedVector::operator*=(double value)
304{
305 std::transform(elements_, elements_ + nElements_, elements_,
306 std::bind2nd(std::multiplies<double>(), value) );
307}
308
309//-----------------------------------------------------------------------------
310
311void
312CoinPackedVector::operator/=(double value)
313{
314 std::transform(elements_, elements_ + nElements_, elements_,
315 std::bind2nd(std::divides<double>(), value) );
316}
317
318//#############################################################################
319
320void
321CoinPackedVector::sortOriginalOrder() {
322 CoinSort_3(origIndices_, origIndices_ + nElements_, indices_, elements_);
323}
324
325//#############################################################################
326
327void
328CoinPackedVector::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
360CoinPackedVector::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
375CoinPackedVector::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
391CoinPackedVector::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
407CoinPackedVector::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
426CoinPackedVector::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
440CoinPackedVector::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
454CoinPackedVector::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
468CoinPackedVector::~CoinPackedVector ()
469{
470 delete [] indices_;
471 delete [] origIndices_;
472 delete [] elements_;
473}
474
475//#############################################################################
476
477void
478CoinPackedVector::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
504void
505CoinPackedVector::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