1 /* $Id: CoinModelUseful.cpp 2083 2019-01-06 19:38:09Z unxusr $ */
2 // Copyright (C) 2005, 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 #include "CoinPragma.hpp"
7
8 #include <cstdlib>
9 #include <cmath>
10 #include <cassert>
11 #include <cfloat>
12 #include <string>
13 #include <cstdio>
14 #include <iostream>
15
16 #include "CoinHelperFunctions.hpp"
17
18 #include "CoinModelUseful.hpp"
19
20 //#############################################################################
21 // Constructors / Destructor / Assignment
22 //#############################################################################
23
24 //-------------------------------------------------------------------
25 // Default Constructor
26 //-------------------------------------------------------------------
CoinModelLink()27 CoinModelLink::CoinModelLink()
28 : row_(-1)
29 , column_(-1)
30 , value_(0.0)
31 , position_(-1)
32 , onRow_(true)
33 {
34 }
35
36 //-------------------------------------------------------------------
37 // Copy constructor
38 //-------------------------------------------------------------------
CoinModelLink(const CoinModelLink & rhs)39 CoinModelLink::CoinModelLink(const CoinModelLink &rhs)
40 : row_(rhs.row_)
41 , column_(rhs.column_)
42 , value_(rhs.value_)
43 , position_(rhs.position_)
44 , onRow_(rhs.onRow_)
45 {
46 }
47
48 //-------------------------------------------------------------------
49 // Destructor
50 //-------------------------------------------------------------------
~CoinModelLink()51 CoinModelLink::~CoinModelLink()
52 {
53 }
54
55 //----------------------------------------------------------------
56 // Assignment operator
57 //-------------------------------------------------------------------
58 CoinModelLink &
operator =(const CoinModelLink & rhs)59 CoinModelLink::operator=(const CoinModelLink &rhs)
60 {
61 if (this != &rhs) {
62 row_ = rhs.row_;
63 column_ = rhs.column_;
64 value_ = rhs.value_;
65 position_ = rhs.position_;
66 onRow_ = rhs.onRow_;
67 }
68 return *this;
69 }
70
71 namespace {
72 const int mmult[] = {
73 262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
74 241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829,
75 221281, 218849, 216319, 213721, 211093, 208673, 206263, 203773,
76 201233, 198637, 196159, 193603, 191161, 188701, 186149, 183761,
77 181303, 178873, 176389, 173897, 171469, 169049, 166471, 163871,
78 161387, 158941, 156437, 153949, 151531, 149159, 146749, 144299,
79 141709, 139369, 136889, 134591, 132169, 129641, 127343, 124853,
80 122477, 120163, 117757, 115361, 112979, 110567, 108179, 105727,
81 103387, 101021, 98639, 96179, 93911, 91583, 89317, 86939, 84521,
82 82183, 79939, 77587, 75307, 72959, 70793, 68447, 66103
83 };
84 const int lengthMult = static_cast< int >(sizeof(mmult) / sizeof(int));
85 }
86
87 //#############################################################################
88 // Constructors / Destructor / Assignment
89 //#############################################################################
90
91 //-------------------------------------------------------------------
92 // Default Constructor
93 //-------------------------------------------------------------------
CoinModelHash()94 CoinModelHash::CoinModelHash()
95 : names_(NULL)
96 , hash_(NULL)
97 , numberItems_(0)
98 , maximumItems_(0)
99 , lastSlot_(-1)
100 {
101 }
102
103 //-------------------------------------------------------------------
104 // Copy constructor
105 //-------------------------------------------------------------------
CoinModelHash(const CoinModelHash & rhs)106 CoinModelHash::CoinModelHash(const CoinModelHash &rhs)
107 : names_(NULL)
108 , hash_(NULL)
109 , numberItems_(rhs.numberItems_)
110 , maximumItems_(rhs.maximumItems_)
111 , lastSlot_(rhs.lastSlot_)
112 {
113 if (maximumItems_) {
114 names_ = new char *[maximumItems_];
115 for (int i = 0; i < maximumItems_; i++) {
116 names_[i] = CoinStrdup(rhs.names_[i]);
117 }
118 hash_ = CoinCopyOfArray(rhs.hash_, 4 * maximumItems_);
119 }
120 }
121
122 //-------------------------------------------------------------------
123 // Destructor
124 //-------------------------------------------------------------------
~CoinModelHash()125 CoinModelHash::~CoinModelHash()
126 {
127 for (int i = 0; i < maximumItems_; i++)
128 free(names_[i]);
129 delete[] names_;
130 delete[] hash_;
131 }
132
133 //----------------------------------------------------------------
134 // Assignment operator
135 //-------------------------------------------------------------------
136 CoinModelHash &
operator =(const CoinModelHash & rhs)137 CoinModelHash::operator=(const CoinModelHash &rhs)
138 {
139 if (this != &rhs) {
140 for (int i = 0; i < maximumItems_; i++)
141 free(names_[i]);
142 delete[] names_;
143 delete[] hash_;
144 numberItems_ = rhs.numberItems_;
145 maximumItems_ = rhs.maximumItems_;
146 lastSlot_ = rhs.lastSlot_;
147 if (maximumItems_) {
148 names_ = new char *[maximumItems_];
149 for (int i = 0; i < maximumItems_; i++) {
150 names_[i] = CoinStrdup(rhs.names_[i]);
151 }
152 hash_ = CoinCopyOfArray(rhs.hash_, 4 * maximumItems_);
153 } else {
154 names_ = NULL;
155 hash_ = NULL;
156 }
157 }
158 return *this;
159 }
160 // Set number of items
setNumberItems(int number)161 void CoinModelHash::setNumberItems(int number)
162 {
163 assert(number >= 0 && number <= numberItems_);
164 numberItems_ = number;
165 }
166 // Resize hash (also re-hashs)
resize(int maxItems,bool forceReHash)167 void CoinModelHash::resize(int maxItems, bool forceReHash)
168 {
169 assert(numberItems_ <= maximumItems_);
170 if (maxItems <= maximumItems_ && !forceReHash)
171 return;
172 int n = maximumItems_;
173 maximumItems_ = maxItems;
174 char **names = new char *[maximumItems_];
175 int i;
176 for (i = 0; i < n; i++)
177 names[i] = names_[i];
178 for (; i < maximumItems_; i++)
179 names[i] = NULL;
180 delete[] names_;
181 names_ = names;
182 delete[] hash_;
183 int maxHash = 4 * maximumItems_;
184 hash_ = new CoinModelHashLink[maxHash];
185 int ipos;
186
187 for (i = 0; i < maxHash; i++) {
188 hash_[i].index = -1;
189 hash_[i].next = -1;
190 }
191
192 /*
193 * Initialize the hash table. Only the index of the first name that
194 * hashes to a value is entered in the table; subsequent names that
195 * collide with it are not entered.
196 */
197 for (i = 0; i < numberItems_; ++i) {
198 if (names_[i]) {
199 ipos = hashValue(names_[i]);
200 if (hash_[ipos].index == -1) {
201 hash_[ipos].index = i;
202 }
203 }
204 }
205
206 /*
207 * Now take care of the names that collided in the preceding loop,
208 * by finding some other entry in the table for them.
209 * Since there are as many entries in the table as there are names,
210 * there must be room for them.
211 */
212 lastSlot_ = -1;
213 for (i = 0; i < numberItems_; ++i) {
214 if (!names_[i])
215 continue;
216 char *thisName = names[i];
217 ipos = hashValue(thisName);
218
219 while (true) {
220 int j1 = hash_[ipos].index;
221
222 if (j1 == i)
223 break;
224 else {
225 char *thisName2 = names[j1];
226
227 if (strcmp(thisName, thisName2) == 0) {
228 printf("** duplicate name %s\n", names[i]);
229 abort();
230 break;
231 } else {
232 int k = hash_[ipos].next;
233
234 if (k == -1) {
235 while (true) {
236 ++lastSlot_;
237 if (lastSlot_ > numberItems_) {
238 printf("** too many names\n");
239 abort();
240 break;
241 }
242 if (hash_[lastSlot_].index == -1) {
243 break;
244 }
245 }
246 hash_[ipos].next = lastSlot_;
247 hash_[lastSlot_].index = i;
248 break;
249 } else {
250 ipos = k;
251 /* nothing worked - try it again */
252 }
253 }
254 }
255 }
256 }
257 }
258 // validate
validateHash() const259 void CoinModelHash::validateHash() const
260 {
261 for (int i = 0; i < numberItems_; ++i) {
262 if (names_[i]) {
263 assert(hash(names_[i]) >= 0);
264 }
265 }
266 }
267 // Returns index or -1
hash(const char * name) const268 int CoinModelHash::hash(const char *name) const
269 {
270 int found = -1;
271
272 int ipos;
273
274 /* default if we don't find anything */
275 if (!numberItems_)
276 return -1;
277
278 ipos = hashValue(name);
279 while (true) {
280 int j1 = hash_[ipos].index;
281
282 if (j1 >= 0) {
283 char *thisName2 = names_[j1];
284
285 if (strcmp(name, thisName2) != 0) {
286 int k = hash_[ipos].next;
287
288 if (k != -1)
289 ipos = k;
290 else
291 break;
292 } else {
293 found = j1;
294 break;
295 }
296 } else {
297 int k = hash_[ipos].next;
298
299 if (k != -1)
300 ipos = k;
301 else
302 break;
303 }
304 }
305 return found;
306 }
307 // Adds to hash
addHash(int index,const char * name)308 void CoinModelHash::addHash(int index, const char *name)
309 {
310 // resize if necessary
311 if (numberItems_ >= maximumItems_)
312 resize(1000 + 3 * numberItems_ / 2);
313 assert(!names_[index]);
314 names_[index] = CoinStrdup(name);
315 int ipos = hashValue(name);
316 numberItems_ = CoinMax(numberItems_, index + 1);
317 if (hash_[ipos].index < 0) {
318 hash_[ipos].index = index;
319 } else {
320 while (true) {
321 int j1 = hash_[ipos].index;
322
323 if (j1 == index)
324 break; // duplicate?
325 else {
326 if (j1 >= 0) {
327 char *thisName2 = names_[j1];
328 if (strcmp(name, thisName2) == 0) {
329 printf("** duplicate name %s\n", names_[index]);
330 abort();
331 break;
332 } else {
333 int k = hash_[ipos].next;
334
335 if (k == -1) {
336 while (true) {
337 ++lastSlot_;
338 if (lastSlot_ > numberItems_) {
339 printf("** too many names\n");
340 abort();
341 break;
342 }
343 if (hash_[lastSlot_].index < 0 && hash_[lastSlot_].next < 0) {
344 break;
345 }
346 }
347 hash_[ipos].next = lastSlot_;
348 hash_[lastSlot_].index = index;
349 hash_[lastSlot_].next = -1;
350 break;
351 } else {
352 ipos = k;
353 }
354 }
355 } else {
356 //slot available
357 hash_[ipos].index = index;
358 }
359 }
360 }
361 }
362 }
363 // Deletes from hash
deleteHash(int index)364 void CoinModelHash::deleteHash(int index)
365 {
366 if (index < numberItems_ && names_[index]) {
367
368 int ipos = hashValue(names_[index]);
369
370 while (ipos >= 0) {
371 int j1 = hash_[ipos].index;
372 if (j1 != index) {
373 ipos = hash_[ipos].next;
374 } else {
375 hash_[ipos].index = -1; // available
376 break;
377 }
378 }
379 assert(ipos >= 0);
380 free(names_[index]);
381 names_[index] = NULL;
382 }
383 }
384 // Returns name at position (or NULL)
385 const char *
name(int which) const386 CoinModelHash::name(int which) const
387 {
388 if (which < numberItems_)
389 return names_[which];
390 else
391 return NULL;
392 }
393 // Returns non const name at position (or NULL)
394 char *
getName(int which) const395 CoinModelHash::getName(int which) const
396 {
397 if (which < numberItems_)
398 return names_[which];
399 else
400 return NULL;
401 }
402 // Sets name at position (does not create)
setName(int which,char * name)403 void CoinModelHash::setName(int which, char *name)
404 {
405 if (which < numberItems_)
406 names_[which] = name;
407 }
408 // Returns a hash value
hashValue(const char * name) const409 int CoinModelHash::hashValue(const char *name) const
410 {
411
412 int n = 0;
413 int j;
414 int length = static_cast< int >(strlen(name));
415 // may get better spread with unsigned
416 const unsigned char *name2 = reinterpret_cast< const unsigned char * >(name);
417 while (length) {
418 int length2 = CoinMin(length, lengthMult);
419 for (j = 0; j < length2; ++j) {
420 n += mmult[j] * name2[j];
421 }
422 name += length2;
423 length -= length2;
424 }
425 int maxHash = 4 * maximumItems_;
426 return (abs(n) % maxHash); /* integer abs */
427 }
428 //#############################################################################
429 // Constructors / Destructor / Assignment
430 //#############################################################################
431 //-------------------------------------------------------------------
432 // Default Constructor
433 //-------------------------------------------------------------------
CoinModelHash2()434 CoinModelHash2::CoinModelHash2()
435 : hash_(NULL)
436 , numberItems_(0)
437 , maximumItems_(0)
438 , lastSlot_(-1)
439 {
440 }
441
442 //-------------------------------------------------------------------
443 // Copy constructor
444 //-------------------------------------------------------------------
CoinModelHash2(const CoinModelHash2 & rhs)445 CoinModelHash2::CoinModelHash2(const CoinModelHash2 &rhs)
446 : hash_(NULL)
447 , numberItems_(rhs.numberItems_)
448 , maximumItems_(rhs.maximumItems_)
449 , lastSlot_(rhs.lastSlot_)
450 {
451 if (maximumItems_) {
452 hash_ = CoinCopyOfArray(rhs.hash_, 4 * maximumItems_);
453 }
454 }
455
456 //-------------------------------------------------------------------
457 // Destructor
458 //-------------------------------------------------------------------
~CoinModelHash2()459 CoinModelHash2::~CoinModelHash2()
460 {
461 delete[] hash_;
462 }
463
464 //----------------------------------------------------------------
465 // Assignment operator
466 //-------------------------------------------------------------------
467 CoinModelHash2 &
operator =(const CoinModelHash2 & rhs)468 CoinModelHash2::operator=(const CoinModelHash2 &rhs)
469 {
470 if (this != &rhs) {
471 delete[] hash_;
472 numberItems_ = rhs.numberItems_;
473 maximumItems_ = rhs.maximumItems_;
474 lastSlot_ = rhs.lastSlot_;
475 if (maximumItems_) {
476 hash_ = CoinCopyOfArray(rhs.hash_, 4 * maximumItems_);
477 } else {
478 hash_ = NULL;
479 }
480 }
481 return *this;
482 }
483 // Set number of items
setNumberItems(CoinBigIndex number)484 void CoinModelHash2::setNumberItems(CoinBigIndex number)
485 {
486 assert(number >= 0 && (number <= numberItems_ || !numberItems_));
487 numberItems_ = number;
488 }
489 // Resize hash (also re-hashs)
resize(CoinBigIndex maxItems,const CoinModelTriple * triples,bool forceReHash)490 void CoinModelHash2::resize(CoinBigIndex maxItems, const CoinModelTriple *triples, bool forceReHash)
491 {
492 assert(numberItems_ <= maximumItems_ || !maximumItems_);
493 if (maxItems <= maximumItems_ && !forceReHash)
494 return;
495 if (maxItems > maximumItems_) {
496 maximumItems_ = maxItems;
497 delete[] hash_;
498 hash_ = new CoinModelHashLink2[4 * maximumItems_];
499 }
500 CoinBigIndex maxHash = 4 * maximumItems_;
501 CoinBigIndex ipos;
502 CoinBigIndex i;
503 for (i = 0; i < maxHash; i++) {
504 hash_[i].index = -1;
505 hash_[i].next = -1;
506 }
507
508 /*
509 * Initialize the hash table. Only the index of the first name that
510 * hashes to a value is entered in the table; subsequent names that
511 * collide with it are not entered.
512 */
513 for (i = 0; i < numberItems_; ++i) {
514 int row = static_cast< int >(rowInTriple(triples[i]));
515 int column = triples[i].column;
516 if (column >= 0) {
517 ipos = hashValue(row, column);
518 if (hash_[ipos].index == -1) {
519 hash_[ipos].index = i;
520 }
521 }
522 }
523
524 /*
525 * Now take care of the entries that collided in the preceding loop,
526 * by finding some other entry in the table for them.
527 * Since there are as many entries in the table as there are entries,
528 * there must be room for them.
529 */
530 lastSlot_ = -1;
531 for (i = 0; i < numberItems_; ++i) {
532 int row = static_cast< int >(rowInTriple(triples[i]));
533 int column = triples[i].column;
534 if (column >= 0) {
535 ipos = hashValue(row, column);
536
537 while (true) {
538 CoinBigIndex j1 = hash_[ipos].index;
539
540 if (j1 == i)
541 break;
542 else {
543 int row2 = static_cast< int >(rowInTriple(triples[j1]));
544 int column2 = triples[j1].column;
545 if (row == row2 && column == column2) {
546 printf("** duplicate entry %d %d\n", row, column);
547 abort();
548 break;
549 } else {
550 CoinBigIndex k = hash_[ipos].next;
551
552 if (k == -1) {
553 while (true) {
554 ++lastSlot_;
555 if (lastSlot_ > numberItems_) {
556 printf("** too many entries\n");
557 abort();
558 break;
559 }
560 if (hash_[lastSlot_].index == -1) {
561 break;
562 }
563 }
564 hash_[ipos].next = lastSlot_;
565 hash_[lastSlot_].index = i;
566 break;
567 } else {
568 ipos = k;
569 }
570 }
571 }
572 }
573 }
574 }
575 }
576 // Returns index or -1
577 CoinBigIndex
hash(int row,int column,const CoinModelTriple * triples) const578 CoinModelHash2::hash(int row, int column, const CoinModelTriple *triples) const
579 {
580 CoinBigIndex found = -1;
581
582 CoinBigIndex ipos;
583
584 /* default if we don't find anything */
585 if (!numberItems_)
586 return -1;
587
588 ipos = hashValue(row, column);
589 while (true) {
590 CoinBigIndex j1 = hash_[ipos].index;
591
592 if (j1 >= 0) {
593 int row2 = static_cast< int >(rowInTriple(triples[j1]));
594 int column2 = triples[j1].column;
595 if (row != row2 || column != column2) {
596 CoinBigIndex k = hash_[ipos].next;
597
598 if (k != -1)
599 ipos = k;
600 else
601 break;
602 } else {
603 found = j1;
604 break;
605 }
606 } else {
607 CoinBigIndex k = hash_[ipos].next;
608
609 if (k != -1)
610 ipos = k;
611 else
612 break;
613 }
614 }
615 return found;
616 }
617 // Adds to hash
addHash(CoinBigIndex index,int row,int column,const CoinModelTriple * triples)618 void CoinModelHash2::addHash(CoinBigIndex index, int row, int column, const CoinModelTriple *triples)
619 {
620 // resize if necessary
621 if (numberItems_ >= maximumItems_ || index + 1 >= maximumItems_)
622 resize(CoinMax(1000 + 3 * numberItems_ / 2, index + 1), triples);
623 CoinBigIndex ipos = hashValue(row, column);
624 numberItems_ = CoinMax(numberItems_, index + 1);
625 assert(numberItems_ <= maximumItems_);
626 if (hash_[ipos].index < 0) {
627 hash_[ipos].index = index;
628 } else {
629 while (true) {
630 CoinBigIndex j1 = hash_[ipos].index;
631
632 if (j1 == index) {
633 break; // duplicate??
634 } else {
635 if (j1 >= 0) {
636 int row2 = static_cast< int >(rowInTriple(triples[j1]));
637 int column2 = triples[j1].column;
638 if (row == row2 && column == column2) {
639 printf("** duplicate entry %d %d\n", row, column);
640 abort();
641 break;
642 } else {
643 CoinBigIndex k = hash_[ipos].next;
644
645 if (k == -1) {
646 while (true) {
647 ++lastSlot_;
648 if (lastSlot_ > numberItems_) {
649 printf("** too many entrys\n");
650 abort();
651 break;
652 }
653 if (hash_[lastSlot_].index < 0) {
654 break;
655 }
656 }
657 hash_[ipos].next = lastSlot_;
658 hash_[lastSlot_].index = index;
659 hash_[lastSlot_].next = -1;
660 break;
661 } else {
662 ipos = k;
663 }
664 }
665 } else {
666 // slot available
667 hash_[ipos].index = index;
668 }
669 }
670 }
671 }
672 }
673 // Deletes from hash
deleteHash(CoinBigIndex index,int row,int column)674 void CoinModelHash2::deleteHash(CoinBigIndex index, int row, int column)
675 {
676 if (index < numberItems_) {
677
678 CoinBigIndex ipos = hashValue(row, column);
679
680 while (ipos >= 0) {
681 CoinBigIndex j1 = hash_[ipos].index;
682 if (j1 != index) {
683 ipos = hash_[ipos].next;
684 } else {
685 hash_[ipos].index = -1; // available
686 break;
687 }
688 }
689 }
690 }
691 namespace {
692 const int mmult2[] = {
693 262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
694 241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829
695 };
696 }
697 // Returns a hash value
698 CoinBigIndex
hashValue(int row,int column) const699 CoinModelHash2::hashValue(int row, int column) const
700 {
701
702 // Optimizer should take out one side of if
703 if (sizeof(int) == 4 * sizeof(char)) {
704 unsigned char tempChar[4];
705
706 unsigned int n = 0;
707 int *temp = reinterpret_cast< int * >(tempChar);
708 *temp = row;
709 n += mmult2[0] * tempChar[0];
710 n += mmult2[1] * tempChar[1];
711 n += mmult2[2] * tempChar[2];
712 n += mmult[3] * tempChar[3];
713 *temp = column;
714 n += mmult2[0 + 8] * tempChar[0];
715 n += mmult2[1 + 8] * tempChar[1];
716 n += mmult2[2 + 8] * tempChar[2];
717 n += mmult2[3 + 8] * tempChar[3];
718 return n % (maximumItems_ << 1);
719 } else {
720 // ints are 8
721 unsigned char tempChar[8];
722
723 int n = 0;
724 unsigned int j;
725 int *temp = reinterpret_cast< int * >(tempChar);
726 *temp = row;
727 for (j = 0; j < sizeof(int); ++j) {
728 int itemp = tempChar[j];
729 n += mmult2[j] * itemp;
730 }
731 *temp = column;
732 for (j = 0; j < sizeof(int); ++j) {
733 int itemp = tempChar[j];
734 n += mmult2[j + 8] * itemp;
735 }
736 CoinBigIndex maxHash = 4 * maximumItems_;
737 CoinBigIndex absN = abs(n);
738 CoinBigIndex returnValue = absN % maxHash;
739 return returnValue;
740 }
741 }
742 //#############################################################################
743 // Constructors / Destructor / Assignment
744 //#############################################################################
745
746 //-------------------------------------------------------------------
747 // Default Constructor
748 //-------------------------------------------------------------------
CoinModelLinkedList()749 CoinModelLinkedList::CoinModelLinkedList()
750 : previous_(NULL)
751 , next_(NULL)
752 , first_(NULL)
753 , last_(NULL)
754 , numberMajor_(0)
755 , maximumMajor_(0)
756 , numberElements_(0)
757 , maximumElements_(0)
758 , type_(-1)
759 {
760 }
761
762 //-------------------------------------------------------------------
763 // Copy constructor
764 //-------------------------------------------------------------------
CoinModelLinkedList(const CoinModelLinkedList & rhs)765 CoinModelLinkedList::CoinModelLinkedList(const CoinModelLinkedList &rhs)
766 : numberMajor_(rhs.numberMajor_)
767 , maximumMajor_(rhs.maximumMajor_)
768 , numberElements_(rhs.numberElements_)
769 , maximumElements_(rhs.maximumElements_)
770 , type_(rhs.type_)
771 {
772 if (maximumMajor_) {
773 previous_ = CoinCopyOfArray(rhs.previous_, maximumElements_);
774 next_ = CoinCopyOfArray(rhs.next_, maximumElements_);
775 first_ = CoinCopyOfArray(rhs.first_, maximumMajor_ + 1);
776 last_ = CoinCopyOfArray(rhs.last_, maximumMajor_ + 1);
777 } else {
778 previous_ = NULL;
779 next_ = NULL;
780 first_ = NULL;
781 last_ = NULL;
782 }
783 }
784
785 //-------------------------------------------------------------------
786 // Destructor
787 //-------------------------------------------------------------------
~CoinModelLinkedList()788 CoinModelLinkedList::~CoinModelLinkedList()
789 {
790 delete[] previous_;
791 delete[] next_;
792 delete[] first_;
793 delete[] last_;
794 }
795
796 //----------------------------------------------------------------
797 // Assignment operator
798 //-------------------------------------------------------------------
799 CoinModelLinkedList &
operator =(const CoinModelLinkedList & rhs)800 CoinModelLinkedList::operator=(const CoinModelLinkedList &rhs)
801 {
802 if (this != &rhs) {
803 delete[] previous_;
804 delete[] next_;
805 delete[] first_;
806 delete[] last_;
807 numberMajor_ = rhs.numberMajor_;
808 maximumMajor_ = rhs.maximumMajor_;
809 numberElements_ = rhs.numberElements_;
810 maximumElements_ = rhs.maximumElements_;
811 type_ = rhs.type_;
812 if (maximumMajor_) {
813 previous_ = CoinCopyOfArray(rhs.previous_, maximumElements_);
814 next_ = CoinCopyOfArray(rhs.next_, maximumElements_);
815 first_ = CoinCopyOfArray(rhs.first_, maximumMajor_ + 1);
816 last_ = CoinCopyOfArray(rhs.last_, maximumMajor_ + 1);
817 } else {
818 previous_ = NULL;
819 next_ = NULL;
820 first_ = NULL;
821 last_ = NULL;
822 }
823 }
824 return *this;
825 }
826 // Resize list - for row list maxMajor is maximum rows
resize(int maxMajor,CoinBigIndex maxElements)827 void CoinModelLinkedList::resize(int maxMajor, CoinBigIndex maxElements)
828 {
829 maxMajor = CoinMax(maxMajor, maximumMajor_);
830 maxElements = CoinMax(maxElements, maximumElements_);
831 if (maxMajor > maximumMajor_) {
832 CoinBigIndex *first = new CoinBigIndex[maxMajor + 1];
833 CoinBigIndex free;
834 if (maximumMajor_) {
835 CoinMemcpyN(first_, maximumMajor_, first);
836 #ifdef ZEROFAULT
837 memset(first + maximumMajor_, 0, (maxMajor - maximumMajor_) * sizeof(CoinBigIndex));
838 #endif
839 free = first_[maximumMajor_];
840 first[maximumMajor_] = -1;
841 } else {
842 free = -1;
843 }
844 first[maxMajor] = free;
845 delete[] first_;
846 first_ = first;
847 CoinBigIndex *last = new CoinBigIndex[maxMajor + 1];
848 if (maximumMajor_) {
849 CoinMemcpyN(last_, maximumMajor_, last);
850 #ifdef ZEROFAULT
851 memset(last + maximumMajor_, 0, (maxMajor - maximumMajor_) * sizeof(CoinBigIndex));
852 #endif
853 free = last_[maximumMajor_];
854 last[maximumMajor_] = -1;
855 } else {
856 free = -1;
857 }
858 last[maxMajor] = free;
859 delete[] last_;
860 last_ = last;
861 maximumMajor_ = maxMajor;
862 }
863 if (maxElements > maximumElements_) {
864 CoinBigIndex *previous = new CoinBigIndex[maxElements];
865 CoinMemcpyN(previous_, numberElements_, previous);
866 #ifdef ZEROFAULT
867 memset(previous + numberElements_, 0,
868 (maxElements - numberElements_) * sizeof(CoinBigIndex));
869 #endif
870 delete[] previous_;
871 previous_ = previous;
872 CoinBigIndex *next = new CoinBigIndex[maxElements];
873 CoinMemcpyN(next_, numberElements_, next);
874 #ifdef ZEROFAULT
875 memset(next + numberElements_, 0, (maxElements - numberElements_) * sizeof(CoinBigIndex));
876 #endif
877 delete[] next_;
878 next_ = next;
879 maximumElements_ = maxElements;
880 }
881 }
882 // Create list - for row list maxMajor is maximum rows
create(int maxMajor,CoinBigIndex maxElements,int numberMajor,int,int type,CoinBigIndex numberElements,const CoinModelTriple * triples)883 void CoinModelLinkedList::create(int maxMajor, CoinBigIndex maxElements,
884 int numberMajor, int /*numberMinor*/, int type,
885 CoinBigIndex numberElements, const CoinModelTriple *triples)
886 {
887 maxMajor = CoinMax(maxMajor, maximumMajor_);
888 maxMajor = CoinMax(maxMajor, numberMajor);
889 maxElements = CoinMax(maxElements, maximumElements_);
890 maxElements = CoinMax(maxElements, numberElements);
891 type_ = type;
892 assert(!previous_);
893 previous_ = new CoinBigIndex[maxElements];
894 next_ = new CoinBigIndex[maxElements];
895 maximumElements_ = maxElements;
896 assert(maxElements >= numberElements);
897 assert(maxMajor > 0 && !maximumMajor_);
898 first_ = new CoinBigIndex[maxMajor + 1];
899 last_ = new CoinBigIndex[maxMajor + 1];
900 #ifdef ZEROFAULT
901 memset(previous_, 0, maxElements * sizeof(CoinBigIndex));
902 memset(next_, 0, maxElements * sizeof(CoinBigIndex));
903 memset(first_, 0, (maxMajor + 1) * sizeof(CoinBigIndex));
904 memset(last_, 0, (maxMajor + 1) * sizeof(CoinBigIndex));
905 #endif
906 assert(numberElements >= 0);
907 numberElements_ = numberElements;
908 maximumMajor_ = maxMajor;
909 // do lists
910 int i;
911 for (i = 0; i < numberMajor; i++) {
912 first_[i] = -1;
913 last_[i] = -1;
914 }
915 first_[maximumMajor_] = -1;
916 last_[maximumMajor_] = -1;
917 int freeChain = -1;
918 for (i = 0; i < numberElements; i++) {
919 if (triples[i].column >= 0) {
920 int iMajor;
921 if (!type_) {
922 // for rows
923 iMajor = static_cast< int >(rowInTriple(triples[i]));
924 } else {
925 iMajor = triples[i].column;
926 }
927 assert(iMajor < numberMajor);
928 if (first_[iMajor] >= 0) {
929 // not first
930 CoinBigIndex j = last_[iMajor];
931 next_[j] = i;
932 previous_[i] = j;
933 } else {
934 // first
935 first_[iMajor] = i;
936 previous_[i] = -1;
937 }
938 last_[iMajor] = i;
939 } else {
940 // on deleted list
941 if (freeChain >= 0) {
942 next_[freeChain] = i;
943 previous_[i] = freeChain;
944 } else {
945 first_[maximumMajor_] = i;
946 previous_[i] = -1;
947 }
948 freeChain = i;
949 }
950 }
951 // Now clean up
952 if (freeChain >= 0) {
953 next_[freeChain] = -1;
954 last_[maximumMajor_] = freeChain;
955 }
956 for (i = 0; i < numberMajor; i++) {
957 CoinBigIndex k = last_[i];
958 if (k >= 0) {
959 next_[k] = -1;
960 last_[i] = k;
961 }
962 }
963 numberMajor_ = numberMajor;
964 }
965 /* Adds to list - easy case i.e. add row to row list
966 Returns where chain starts
967 */
968 CoinBigIndex
addEasy(int majorIndex,CoinBigIndex numberOfElements,const int * indices,const double * elements,CoinModelTriple * triples,CoinModelHash2 & hash)969 CoinModelLinkedList::addEasy(int majorIndex, CoinBigIndex numberOfElements, const int *indices,
970 const double *elements, CoinModelTriple *triples,
971 CoinModelHash2 &hash)
972 {
973 assert(majorIndex < maximumMajor_);
974 if (numberOfElements + numberElements_ > maximumElements_) {
975 resize(maximumMajor_, (3 * (numberElements_ + numberOfElements)) / 2 + 1000);
976 }
977 CoinBigIndex first = -1;
978 if (majorIndex >= numberMajor_) {
979 for (int i = numberMajor_; i <= majorIndex; i++) {
980 first_[i] = -1;
981 last_[i] = -1;
982 }
983 }
984 if (numberOfElements) {
985 bool doHash = hash.maximumItems() != 0;
986 CoinBigIndex lastFree = last_[maximumMajor_];
987 CoinBigIndex last = last_[majorIndex];
988 for (int i = 0; i < numberOfElements; i++) {
989 CoinBigIndex put;
990 if (lastFree >= 0) {
991 put = lastFree;
992 lastFree = previous_[lastFree];
993 } else {
994 put = numberElements_;
995 assert(put < maximumElements_);
996 numberElements_++;
997 }
998 if (type_ == 0) {
999 // row
1000 setRowAndStringInTriple(triples[put], majorIndex, false);
1001 triples[put].column = indices[i];
1002 } else {
1003 // column
1004 setRowAndStringInTriple(triples[put], indices[i], false);
1005 triples[put].column = majorIndex;
1006 }
1007 triples[put].value = elements[i];
1008 if (doHash)
1009 hash.addHash(put, static_cast< int >(rowInTriple(triples[put])), triples[put].column, triples);
1010 if (last >= 0) {
1011 next_[last] = put;
1012 } else {
1013 first_[majorIndex] = put;
1014 }
1015 previous_[put] = last;
1016 last = put;
1017 }
1018 next_[last] = -1;
1019 if (last_[majorIndex] < 0) {
1020 // first in row
1021 first = first_[majorIndex];
1022 } else {
1023 first = next_[last_[majorIndex]];
1024 }
1025 last_[majorIndex] = last;
1026 if (lastFree >= 0) {
1027 next_[lastFree] = -1;
1028 last_[maximumMajor_] = lastFree;
1029 } else {
1030 first_[maximumMajor_] = -1;
1031 last_[maximumMajor_] = -1;
1032 }
1033 }
1034 numberMajor_ = CoinMax(numberMajor_, majorIndex + 1);
1035 return first;
1036 }
1037 /* Adds to list - hard case i.e. add row to column list
1038 */
addHard(int minorIndex,CoinBigIndex numberOfElements,const int * indices,const double * elements,CoinModelTriple * triples,CoinModelHash2 & hash)1039 void CoinModelLinkedList::addHard(int minorIndex, CoinBigIndex numberOfElements, const int *indices,
1040 const double *elements, CoinModelTriple *triples,
1041 CoinModelHash2 &hash)
1042 {
1043 CoinBigIndex lastFree = last_[maximumMajor_];
1044 bool doHash = hash.maximumItems() != 0;
1045 for (int i = 0; i < numberOfElements; i++) {
1046 CoinBigIndex put;
1047 if (lastFree >= 0) {
1048 put = lastFree;
1049 lastFree = previous_[lastFree];
1050 } else {
1051 put = numberElements_;
1052 assert(put < maximumElements_);
1053 numberElements_++;
1054 }
1055 int other = indices[i];
1056 if (type_ == 0) {
1057 // row
1058 setRowAndStringInTriple(triples[put], other, false);
1059 triples[put].column = minorIndex;
1060 } else {
1061 // column
1062 setRowAndStringInTriple(triples[put], minorIndex, false);
1063 triples[put].column = other;
1064 }
1065 triples[put].value = elements[i];
1066 if (doHash)
1067 hash.addHash(put, static_cast< int >(rowInTriple(triples[put])), triples[put].column, triples);
1068 if (other >= numberMajor_) {
1069 // Need to fill in null values
1070 fill(numberMajor_, other + 1);
1071 numberMajor_ = other + 1;
1072 }
1073 CoinBigIndex last = last_[other];
1074 if (last >= 0) {
1075 next_[last] = put;
1076 } else {
1077 first_[other] = put;
1078 }
1079 previous_[put] = last;
1080 next_[put] = -1;
1081 last_[other] = put;
1082 }
1083 if (lastFree >= 0) {
1084 next_[lastFree] = -1;
1085 last_[maximumMajor_] = lastFree;
1086 } else {
1087 first_[maximumMajor_] = -1;
1088 last_[maximumMajor_] = -1;
1089 }
1090 }
1091 /* Adds to list - hard case i.e. add row to column list
1092 This is when elements have been added to other copy
1093 */
addHard(CoinBigIndex first,const CoinModelTriple * triples,CoinBigIndex firstFree,CoinBigIndex lastFree,const CoinBigIndex * next)1094 void CoinModelLinkedList::addHard(CoinBigIndex first, const CoinModelTriple *triples,
1095 CoinBigIndex firstFree, CoinBigIndex lastFree, const CoinBigIndex *next)
1096 {
1097 first_[maximumMajor_] = firstFree;
1098 last_[maximumMajor_] = lastFree;
1099 CoinBigIndex put = first;
1100 int minorIndex = -1;
1101 while (put >= 0) {
1102 assert(put < maximumElements_);
1103 numberElements_ = CoinMax(numberElements_, put + 1);
1104 int other;
1105 if (type_ == 0) {
1106 // row
1107 other = rowInTriple(triples[put]);
1108 if (minorIndex >= 0)
1109 assert(triples[put].column == minorIndex);
1110 else
1111 minorIndex = triples[put].column;
1112 } else {
1113 // column
1114 other = triples[put].column;
1115 if (minorIndex >= 0)
1116 assert(static_cast< int >(rowInTriple(triples[put])) == minorIndex);
1117 else
1118 minorIndex = rowInTriple(triples[put]);
1119 }
1120 assert(other < maximumMajor_);
1121 if (other >= numberMajor_) {
1122 // Need to fill in null values
1123 fill(numberMajor_, other + 1);
1124 numberMajor_ = other + 1;
1125 }
1126 CoinBigIndex last = last_[other];
1127 if (last >= 0) {
1128 next_[last] = put;
1129 } else {
1130 first_[other] = put;
1131 }
1132 previous_[put] = last;
1133 next_[put] = -1;
1134 last_[other] = put;
1135 put = next[put];
1136 }
1137 }
1138 /* Deletes from list - same case i.e. delete row from row list
1139 */
deleteSame(int which,CoinModelTriple * triples,CoinModelHash2 & hash,bool zapTriples)1140 void CoinModelLinkedList::deleteSame(int which, CoinModelTriple *triples,
1141 CoinModelHash2 &hash, bool zapTriples)
1142 {
1143 assert(which >= 0);
1144 if (which < numberMajor_) {
1145 CoinBigIndex lastFree = last_[maximumMajor_];
1146 CoinBigIndex put = first_[which];
1147 first_[which] = -1;
1148 while (put >= 0) {
1149 if (hash.numberItems()) {
1150 // take out of hash
1151 hash.deleteHash(put, static_cast< int >(rowInTriple(triples[put])), triples[put].column);
1152 }
1153 if (zapTriples) {
1154 triples[put].column = -1;
1155 triples[put].value = 0.0;
1156 }
1157 if (lastFree >= 0) {
1158 next_[lastFree] = put;
1159 } else {
1160 first_[maximumMajor_] = put;
1161 }
1162 previous_[put] = lastFree;
1163 lastFree = put;
1164 put = next_[put];
1165 }
1166 if (lastFree >= 0) {
1167 next_[lastFree] = -1;
1168 last_[maximumMajor_] = lastFree;
1169 } else {
1170 assert(last_[maximumMajor_] == -1);
1171 }
1172 last_[which] = -1;
1173 }
1174 }
1175 /* Deletes from list - other case i.e. delete row from column list
1176 This is when elements have been deleted from other copy
1177 */
updateDeleted(int,CoinModelTriple * triples,CoinModelLinkedList & otherList)1178 void CoinModelLinkedList::updateDeleted(int /*which*/, CoinModelTriple *triples,
1179 CoinModelLinkedList &otherList)
1180 {
1181 CoinBigIndex firstFree = otherList.firstFree();
1182 CoinBigIndex lastFree = otherList.lastFree();
1183 const CoinBigIndex *previousOther = otherList.previous();
1184 assert(maximumMajor_);
1185 if (lastFree >= 0) {
1186 // First free should be same
1187 if (first_[maximumMajor_] >= 0)
1188 assert(firstFree == first_[maximumMajor_]);
1189 CoinBigIndex last = last_[maximumMajor_];
1190 first_[maximumMajor_] = firstFree;
1191 // Maybe nothing to do
1192 if (last_[maximumMajor_] == lastFree)
1193 return;
1194 last_[maximumMajor_] = lastFree;
1195 int iMajor;
1196 if (!type_) {
1197 // for rows
1198 iMajor = static_cast< int >(rowInTriple(triples[lastFree]));
1199 } else {
1200 iMajor = triples[lastFree].column;
1201 }
1202 if (first_[iMajor] >= 0) {
1203 // take out
1204 CoinBigIndex previousThis = previous_[lastFree];
1205 CoinBigIndex nextThis = next_[lastFree];
1206 if (previousThis >= 0 && previousThis != last) {
1207 next_[previousThis] = nextThis;
1208 #ifndef NDEBUG
1209 int iTest;
1210 if (!type_) {
1211 // for rows
1212 iTest = static_cast< int >(rowInTriple(triples[previousThis]));
1213 } else {
1214 iTest = triples[previousThis].column;
1215 }
1216 assert(triples[previousThis].column >= 0);
1217 assert(iTest == iMajor);
1218 #endif
1219 } else {
1220 first_[iMajor] = nextThis;
1221 }
1222 if (nextThis >= 0) {
1223 previous_[nextThis] = previousThis;
1224 #ifndef NDEBUG
1225 int iTest;
1226 if (!type_) {
1227 // for rows
1228 iTest = static_cast< int >(rowInTriple(triples[nextThis]));
1229 } else {
1230 iTest = triples[nextThis].column;
1231 }
1232 assert(triples[nextThis].column >= 0);
1233 assert(iTest == iMajor);
1234 #endif
1235 } else {
1236 last_[iMajor] = previousThis;
1237 }
1238 }
1239 triples[lastFree].column = -1;
1240 triples[lastFree].value = 0.0;
1241 // Do first (by which I mean last)
1242 next_[lastFree] = -1;
1243 CoinBigIndex previous = previousOther[lastFree];
1244 while (previous != last) {
1245 if (previous >= 0) {
1246 if (!type_) {
1247 // for rows
1248 iMajor = static_cast< int >(rowInTriple(triples[previous]));
1249 } else {
1250 iMajor = triples[previous].column;
1251 }
1252 if (first_[iMajor] >= 0) {
1253 // take out
1254 CoinBigIndex previousThis = previous_[previous];
1255 CoinBigIndex nextThis = next_[previous];
1256 if (previousThis >= 0 && previousThis != last) {
1257 next_[previousThis] = nextThis;
1258 #ifndef NDEBUG
1259 int iTest;
1260 if (!type_) {
1261 // for rows
1262 iTest = static_cast< int >(rowInTriple(triples[previousThis]));
1263 } else {
1264 iTest = triples[previousThis].column;
1265 }
1266 assert(triples[previousThis].column >= 0);
1267 assert(iTest == iMajor);
1268 #endif
1269 } else {
1270 first_[iMajor] = nextThis;
1271 }
1272 if (nextThis >= 0) {
1273 previous_[nextThis] = previousThis;
1274 #ifndef NDEBUG
1275 int iTest;
1276 if (!type_) {
1277 // for rows
1278 iTest = static_cast< int >(rowInTriple(triples[nextThis]));
1279 } else {
1280 iTest = triples[nextThis].column;
1281 }
1282 assert(triples[nextThis].column >= 0);
1283 assert(iTest == iMajor);
1284 #endif
1285 } else {
1286 last_[iMajor] = previousThis;
1287 }
1288 }
1289 triples[previous].column = -1;
1290 triples[previous].value = 0.0;
1291 next_[previous] = lastFree;
1292 } else {
1293 assert(lastFree == firstFree);
1294 }
1295 previous_[lastFree] = previous;
1296 lastFree = previous;
1297 previous = previousOther[lastFree];
1298 }
1299 if (last >= 0) {
1300 next_[previous] = lastFree;
1301 } else {
1302 assert(firstFree == lastFree);
1303 }
1304 previous_[lastFree] = previous;
1305 }
1306 }
1307 /* Deletes one element from Row list
1308 */
deleteRowOne(CoinBigIndex position,CoinModelTriple * triples,CoinModelHash2 & hash)1309 void CoinModelLinkedList::deleteRowOne(CoinBigIndex position, CoinModelTriple *triples,
1310 CoinModelHash2 &hash)
1311 {
1312 int row = rowInTriple(triples[position]);
1313 assert(row < numberMajor_);
1314 if (hash.numberItems()) {
1315 // take out of hash
1316 hash.deleteHash(position, static_cast< int >(rowInTriple(triples[position])), triples[position].column);
1317 }
1318 CoinBigIndex previous = previous_[position];
1319 CoinBigIndex next = next_[position];
1320 // put on free list
1321 CoinBigIndex lastFree = last_[maximumMajor_];
1322 if (lastFree >= 0) {
1323 next_[lastFree] = position;
1324 } else {
1325 first_[maximumMajor_] = position;
1326 assert(last_[maximumMajor_] == -1);
1327 }
1328 last_[maximumMajor_] = position;
1329 previous_[position] = lastFree;
1330 next_[position] = -1;
1331 // Now take out of row
1332 if (previous >= 0) {
1333 next_[previous] = next;
1334 } else {
1335 first_[row] = next;
1336 }
1337 if (next >= 0) {
1338 previous_[next] = previous;
1339 } else {
1340 last_[row] = previous;
1341 }
1342 }
1343 /* Update column list for one element when
1344 one element deleted from row copy
1345 */
updateDeletedOne(CoinBigIndex position,const CoinModelTriple * triples)1346 void CoinModelLinkedList::updateDeletedOne(CoinBigIndex position, const CoinModelTriple *triples)
1347 {
1348 assert(maximumMajor_);
1349 int column = triples[position].column;
1350 assert(column >= 0 && column < numberMajor_);
1351 CoinBigIndex previous = previous_[position];
1352 CoinBigIndex next = next_[position];
1353 // put on free list
1354 CoinBigIndex lastFree = last_[maximumMajor_];
1355 if (lastFree >= 0) {
1356 next_[lastFree] = position;
1357 } else {
1358 first_[maximumMajor_] = position;
1359 assert(last_[maximumMajor_] == -1);
1360 }
1361 last_[maximumMajor_] = position;
1362 previous_[position] = lastFree;
1363 next_[position] = -1;
1364 // Now take out of column
1365 if (previous >= 0) {
1366 next_[previous] = next;
1367 } else {
1368 first_[column] = next;
1369 }
1370 if (next >= 0) {
1371 previous_[next] = previous;
1372 } else {
1373 last_[column] = previous;
1374 }
1375 }
1376 // Fills first,last with -1
fill(int first,int last)1377 void CoinModelLinkedList::fill(int first, int last)
1378 {
1379 for (int i = first; i < last; i++) {
1380 first_[i] = -1;
1381 last_[i] = -1;
1382 }
1383 }
1384 /* Puts in free list from other list */
synchronize(CoinModelLinkedList & other)1385 void CoinModelLinkedList::synchronize(CoinModelLinkedList &other)
1386 {
1387 CoinBigIndex first = other.first_[other.maximumMajor_];
1388 first_[maximumMajor_] = first;
1389 CoinBigIndex last = other.last_[other.maximumMajor_];
1390 last_[maximumMajor_] = last;
1391 CoinBigIndex put = first;
1392 while (put >= 0) {
1393 previous_[put] = other.previous_[put];
1394 next_[put] = other.next_[put];
1395 put = next_[put];
1396 }
1397 }
1398 // Checks that links are consistent
validateLinks(const CoinModelTriple * triples) const1399 void CoinModelLinkedList::validateLinks(const CoinModelTriple *triples) const
1400 {
1401 char *mark = new char[maximumElements_];
1402 memset(mark, 0, maximumElements_);
1403 CoinBigIndex lastElement = -1;
1404 int i;
1405 for (i = 0; i < numberMajor_; i++) {
1406 CoinBigIndex position = first_[i];
1407 #ifndef NDEBUG
1408 CoinBigIndex lastPosition = -1;
1409 #endif
1410 while (position >= 0) {
1411 assert(position == first_[i] || next_[previous_[position]] == position);
1412 assert(type_ || i == static_cast< int >(rowInTriple(triples[position]))); // i == iMajor for rows
1413 assert(!type_ || i == triples[position].column); // i == iMajor
1414 assert(triples[position].column >= 0);
1415 mark[position] = 1;
1416 lastElement = CoinMax(lastElement, position);
1417 #ifndef NDEBUG
1418 lastPosition = position;
1419 #endif
1420 position = next_[position];
1421 }
1422 assert(lastPosition == last_[i]);
1423 }
1424 for (i = 0; i <= lastElement; i++) {
1425 if (!mark[i])
1426 assert(triples[i].column == -1);
1427 }
1428 delete[] mark;
1429 }
1430
1431 /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
1432 */
1433