Scippy

SoPlex

Sequential object-oriented simPlex

classset.h
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the class library */
4/* SoPlex --- the Sequential object-oriented simPlex. */
5/* */
6/* Copyright (c) 1996-2024 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SoPlex; see the file LICENSE. If not email to soplex@zib.de. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file classset.h
26 * @brief Set of class objects.
27 */
28#ifndef _CLASSSET_H_
29#define _CLASSSET_H_
30
31
32#include <string.h>
33#include <assert.h>
34
35#include "soplex/array.h"
36#include "soplex/dataarray.h"
37#include "soplex/classarray.h"
38#include "soplex/datakey.h"
39#include "soplex/spxalloc.h"
40#include "soplex/exceptions.h"
41#include "soplex/svectorbase.h"
42
43namespace soplex
44{
45/**@class ClassSet
46 @brief Set of class objects.
47 @ingroup Elementary
48
49 Class ClassSet manages of sets of class objects of a
50 template type T. For constructing a ClassSet the maximum number
51 of entries must be given. The current maximum number may be inquired
52 with method max().
53
54 Adding more then max() elements to a ClassSet will core dump. However,
55 method reMax() allows to reset max() without loss of elements currently
56 in the ClassSet. The current number of elements in a ClassSet is returned
57 by method num().
58
59 Adding elements to a ClassSet is done via methods add() or create(),
60 while remove() removes elements from a ClassSet. When adding an element
61 to a ClassSet the new element is assigned a DataKey. DataKeys serve to
62 access CLASS elements in a set via a version of the subscript
63 operator[](DataKey).
64
65 For convenience all elements in a ClassSet are implicitely numbered
66 from 0 through num()-1 and can be accessed with these numbers
67 using a 2nd subscript operator[](int). The reason for providing
68 DataKeys to access elements of a ClassSet is that the Key of an
69 element remains unchanged as long as the element is a member of the
70 ClassSet, while the numbers will change in an undefined way, if
71 other elements are added to or removed from the ClassSet.
72
73 The elements in a ClassSet and their DataKeys are stored in two arrays:
74 - theitem keeps the objects along with their number stored in item.
75 - thekey keeps the DataKey::idx's of the elements in a ClassSet.
76
77 Both arrays have size themax.
78
79 In #thekey only elements 0 thru thenum-1 contain DataKey::idx%'s of
80 valid elements, i.e., elements currently in the ClassSet.
81 The current number of elements in the ClassSet is counted in thenum.
82
83 In #theitem only elements 0 thru thesize-1 are used, but only some of
84 them actually contain real class elements of the ClassSet. They are
85 recognized by having info >= 0, which gives the number of that
86 element. Otherwise info < 0 indicates an unused element. Unused
87 elements are linked in a single linked list: starting with element
88 <tt>-firstfree-1</tt>, the next free element is given by
89 <tt>-info-1.</tt> The last free element in the list is marked by
90 <tt>info == -themax-1.</tt> Finally all elements in theitem with
91 <tt>index >= thesize</tt> are unused as well.
92*/
93template<class T>
95{
96protected:
97
98 //-----------------------------------
99 /**@name Types */
100 ///@{
101 ///
102 struct Item
103 {
104 T data; ///< T element
105 int info; ///< element number. info \f$\in\f$ [0,thesize-1]
106 ///< iff element is used
107 }* theitem; ///< array of elements in the ClassSet
108 ///@}
109
110 //-----------------------------------
111 /**@name Data */
112 ///@{
113 DataKey* thekey; ///< DataKey::idx's of elements
114 int themax; ///< length of arrays theitem and thekey
115 int thesize; ///< highest used element in theitem
116 int thenum; ///< number of elements in ClassSet
117 int firstfree; ///< first unused element in theitem
118 ///@}
119
120public:
121
122 //-----------------------------------
123 /**@name Extension
124 * Whenever a new element is added to a ClassSet, the latter assigns it a
125 * DataKey. For this all methods that extend a ClassSet by one ore more
126 * elements are provided with two signatures, one of them having a
127 * parameter for returning the assigned DataKey(s).
128 */
129 ///@{
130 /// adds an element.
131 void add(DataKey& newkey, const T& item)
132 {
133 T* newelem = create(newkey);
134
135 assert(newelem != nullptr);
136
137 *newelem = item;
138 }
139 /// adds element \p item.
140 void add(const T& item)
141 {
142 T* newelem = create();
143
144 assert(newelem != nullptr);
145
146 *newelem = item;
147 }
148
149 /// add several items.
150 void add(DataKey newkey[], const T* item, int n)
151 {
152 assert(n >= 0);
153 assert(num() + n <= max());
154
155 for(int i = 0; i < n; ++i)
156 add(newkey[i], item[i]);
157 }
158
159 /// adds \p n elements from \p items.
160 void add(const T* items, int n)
161 {
162 assert(n >= 0);
163 assert(num() + n <= max());
164
165 for(int i = 0; i < n; ++i)
166 add(items[i]);
167 }
168
169 /// adds several new items.
170 void add(DataKey newkey[], const ClassSet < T >& set)
171 {
172 assert(num() + set.num() <= max());
173
174 for(int i = 0; i < set.num(); ++i)
175 add(newkey[i], set[i]);
176 }
177
178 /// adds all elements of \p set.
179 void add(const ClassSet < T >& set)
180 {
181 assert(num() + set.num() <= max());
182
183 for(int i = 0; i < set.num(); ++i)
184 add(set[i]);
185 }
186
187 /// creates new class element in ClassSet.
188 /**@return Pointer to the newly created element.
189 */
190 T* create(DataKey& newkey)
191 {
192 assert(num() < max());
193
194 if(firstfree != -themax - 1)
195 {
196 newkey.idx = -firstfree - 1;
197 firstfree = theitem[newkey.idx].info;
198 }
199 else
200 newkey.idx = thesize++;
201
202 thekey[thenum] = newkey;
203 theitem[newkey.idx].info = thenum;
204 ++thenum;
205
206 return &(theitem[newkey.idx].data);
207 }
208 /// creates new (uninitialized) class element in ClassSet.
209 /**@return Pointer to the newly created element.
210 */
212 {
213 DataKey tmp;
214 return create(tmp);
215 }
216 ///@}
217
218 //-----------------------------------
219 /**@name Shrinkage
220 * When elements are removed from a ClassSet, the remaining ones are
221 * renumbered from 0 through the new size()-1. How this renumbering is
222 * performed will not be revealed, since it might be target of future
223 * changes. However, some methods provide a parameter
224 * <tt>int* perm</tt>, which
225 * returns the new order after the removal: If <tt>perm[i] < 0</tt>,
226 * the element numbered i prior to the removal operation has been removed
227 * from the set. Otherwise, <tt>perm[i] = j >= 0</tt> means that the
228 * element with number i prior to the removal operation has been
229 * renumbered to j. Removing a single element from a ClassSet yields a
230 * simple renumbering of the elements: The last element in the set
231 * (i.e., element num()-1) is moved to the index of the removed element.
232 */
233 ///@{
234 /// removes the \p removenum 'th element.
235 void remove(int removenum)
236 {
237 if(has(removenum))
238 {
239 int idx = thekey[removenum].idx;
240
241 theitem[idx].info = firstfree;
242 firstfree = -idx - 1;
243
244 while(-firstfree == thesize)
245 {
247 --thesize;
248 }
249
250 --thenum;
251
252 if(removenum != thenum)
253 {
254 thekey[removenum] = thekey[thenum];
255 theitem[thekey[removenum].idx].info = removenum;
256 }
257 }
258 }
259
260 /// removes element with key \p removekey.
261 void remove(const DataKey& removekey)
262 {
263 remove(number(removekey));
264 }
265
266 /// remove multiple elements.
267 /** This method removes all elements for the ClassSet with an
268 * index i such that \p perm[i] < 0. Upon completion, \p perm contains
269 * the new numbering of elements.
270 */
271 void remove(int perm[])
272 {
273 int k, j, first = -1;
274
275 // setup permutation and remove items
276 for(k = j = 0; k < num(); ++k)
277 {
278 if(perm[k] >= 0) // j has not been removed ...
279 perm[k] = j++;
280 else
281 {
282 int idx = thekey[k].idx;
283 theitem[idx].info = firstfree;
284 firstfree = -idx - 1;
285
286 if(first < 0)
287 first = k;
288 }
289 }
290
291 if(first >= 0) // move remaining items
292 {
293 for(k = first, j = num(); k < j; ++k)
294 {
295 if(perm[k] >= 0)
296 {
297 thekey[perm[k]] = thekey[k];
298 theitem[thekey[k].idx].info = perm[k];
299 thekey[k].idx = -1;
300 }
301 else
302 --thenum;
303 }
304 }
305 }
306
307 /// remove \p n elements given by \p keys and \p perm.
308 void remove(const DataKey* keys, int n, int* perm)
309 {
310 assert(perm != nullptr);
311
312 for(int i = num() - 1; i >= 0; --i)
313 perm[i] = i;
314
315 while(--n >= 0)
316 perm[number(keys[n])] = -1;
317
318 remove(perm);
319 }
320 /// remove \p n elements given by \p keys.
321 void remove(const DataKey* keys, int n)
322 {
323 DataArray<int> perm(num());
324 remove(keys, n, perm.get_ptr());
325 }
326 /// remove \p n elements given by \p nums and \p perm.
327 void remove(const int* nums, int n, int* perm)
328 {
329 assert(perm != nullptr);
330
331 for(int i = num() - 1; i >= 0; --i)
332 perm[i] = i;
333
334 while(--n >= 0)
335 perm[nums[n]] = -1;
336
337 remove(perm);
338 }
339 /// remove \p n elements with numbers \p nums.
340 void remove(const int* nums, int n)
341 {
342 DataArray<int> perm(num());
343 remove(nums, n, perm.get_ptr());
344 }
345
346 /// remove all elements.
347 void clear()
348 {
349 thesize = 0;
350 thenum = 0;
351 firstfree = -themax - 1;
352 }
353 ///@}
354
355 //-----------------------------------
356 /**@name Access
357 * When accessing elements from a ClassSet with one of the index
358 * operators, it must be ensured that the index is valid for the
359 * ClassSet. If this is not known afore, it is the programmers
360 * responsability to ensure this using the inquiry methods below.
361 */
362 ///@{
363 ///
364 T& operator[](int n)
365 {
366 assert(n >= 0 && n < thenum);
367 return theitem[thekey[n].idx].data;
368 }
369 /// returns element number \p n.
370 const T& operator[](int n) const
371 {
372 assert(n >= 0 && n < thenum);
373 return theitem[thekey[n].idx].data;
374 }
375
376 ///
377 T& operator[](const DataKey& k)
378 {
379 assert(k.idx < thesize);
380 return theitem[k.idx].data;
381 }
382 /// returns element with DataKey \p k.
383 const T& operator[](const DataKey& k) const
384 {
385 assert(k.idx < thesize);
386 return theitem[k.idx].data;
387 }
388 ///@}
389
390 //-----------------------------------
391 /**@name Inquiry */
392 ///@{
393 /// returns maximum number of elements that would fit into ClassSet.
394 int max() const
395 {
396 return themax;
397 }
398
399 /// returns number of elements currently in ClassSet.
400 int num() const
401 {
402 return thenum;
403 }
404
405 /// returns the maximum DataKey::idx currently in ClassSet.
406 int size() const
407 {
408 return thesize;
409 }
410
411 /// returns DataKey of \p n 'th element in ClassSet.
412 DataKey key(int n) const
413 {
414 assert(n >= 0 && n < num());
415 return thekey[n];
416 }
417
418 /// returns DataKey of element \p item in ClassSet.
419 DataKey key(const T* item) const
420 {
421 assert(number(item) >= 0);
422 return thekey[number(item)];
423 }
424
425 /// returns the number of the element with DataKey \p k in ClassSet or -1,
426 /// if it doesn't exist.
427 int number(const DataKey& k) const
428 {
429 if(k.idx < 0 || k.idx >= size())
430 throw SPxException("Invalid index");
431
432 return theitem[k.idx].info;
433 }
434
435 /**@todo Please check whether this is correctly implemented! */
436 /// returns the number of element \p item in ClassSet,
437 /// throws exception if it doesn't exist.
438 int number(const T* item) const
439 {
440 ptrdiff_t idx = reinterpret_cast<const struct Item*>(item) - theitem;
441
442 if(idx < 0 || idx >= size())
443 throw SPxException("Invalid index");
444
445 return theitem[idx].info;
446 }
447
448 /// Is \p k a valid DataKey of an element in ClassSet?
449 bool has(const DataKey& k) const
450 {
451 return theitem[k.idx].info >= 0;
452 }
453
454 /// Is \p n a valid number of an element in ClassSet?
455 bool has(int n) const
456 {
457 return (n >= 0 && n < num());
458 }
459
460 /// Does \p item belong to ClassSet?
461 bool has(const T* item) const
462 {
463 int n;
464
465 try
466 {
467 n = number(item);
468 }
469 catch(...)
470 {
471 return false;
472 }
473
474 return n >= 0;
475 }
476 ///@}
477
478 //-----------------------------------
479 /**@name Miscellaneous */
480 ///@{
481 /// resets max() to \p newmax.
482 /** This method will not succeed if \p newmax < size(), in which case
483 * \p newmax == size() will be taken. As generally this method involves
484 * copying the #ClassSet%s elements in memory, reMax() returns the
485 * number of bytes the addresses of elements in the ClassSet have been
486 * moved. Note, that this is identical for all elements in the
487 * ClassSet.
488 */
489 ptrdiff_t reMax(int newmax = 0)
490 {
491 int i;
492 Item* newMem = nullptr;
493 newmax = (newmax < size()) ? size() : newmax;
494
495 int* lastfree = &firstfree;
496
497 while(*lastfree != -themax - 1)
498 lastfree = &(theitem[ -1 - *lastfree].info);
499
500 *lastfree = -newmax - 1;
501
502 spx_alloc(newMem, newmax);
503
504 /* call copy constructor for first elements */
505 for(i = 0; i < max(); i++)
506 {
507 newMem[i].data = std::move(theitem[i].data);
508 newMem[i].info = theitem[i].info;
509 }
510
511 /* call default constructor for remaining elements */
512 for(; i < newmax; i++)
513 new(&(newMem[i])) Item();
514
515 /* compute pointer difference */
516 ptrdiff_t pshift = reinterpret_cast<char*>(newMem) - reinterpret_cast<char*>(theitem);
517
519
520 theitem = newMem;
521 themax = newmax;
522
524
525 return pshift;
526 }
527
528 /// consistency check.
529 bool isConsistent() const
530 {
531#ifdef ENABLE_CONSISTENCY_CHECKS
532
533 if(theitem == 0 || thekey == 0)
534 return SPX_MSG_INCONSISTENT("ClassSet");
535
536 if(thesize > themax || thenum > themax || thenum > thesize)
537 return SPX_MSG_INCONSISTENT("ClassSet");
538
539 if(thesize == thenum && firstfree != -themax - 1)
540 return SPX_MSG_INCONSISTENT("ClassSet");
541
542 if(thesize != thenum && firstfree == -themax - 1)
543 return SPX_MSG_INCONSISTENT("ClassSet");
544
545 for(int i = 0; i < thenum; ++i)
546 if(theitem[thekey[i].idx].info != i)
547 return SPX_MSG_INCONSISTENT("ClassSet");
548
549#endif
550
551 return true;
552 }
553 ///@}
554
555 //-----------------------------------
556 /**@name Constructors / Destructors */
557 ///@{
558 /// default constructor.
559 explicit
560 ClassSet(int pmax = 8)
561 : theitem(nullptr)
562 , thekey(nullptr)
563 , themax(pmax < 1 ? 8 : pmax)
564 , thesize(0)
565 , thenum(0)
566
567 {
568 firstfree = -themax - 1;
569
571
572 /* call default constructor for each element */
573 for(int i = 0; i < themax; i++)
574 new(&(theitem[i])) Item();
575
576 try
577 {
579 }
580 catch(const SPxMemoryException& x)
581 {
583 throw x;
584 }
585
586 assert(isConsistent());
587 }
588
589 /// copy constructor.
590 ClassSet(const ClassSet& old)
591 : theitem(0)
592 , thekey(nullptr)
593 , themax(old.themax)
594 , thesize(old.thesize)
595 , thenum(old.thenum)
596 {
597 firstfree = (old.firstfree == -old.themax - 1)
598 ? -themax - 1
599 : old.firstfree;
600
602
603 /* call copy constructor for first elements */
604 int i;
605
606 for(i = 0; i < old.thenum; i++)
607 new(&(theitem[i])) Item(old.theitem[i]);
608
609 /* call default constructor for remaining elements */
610 for(; i < old.themax; i++)
611 new(&(theitem[i])) Item();
612
613 try
614 {
616 }
617 catch(const SPxMemoryException& x)
618 {
620 throw x;
621 }
622
623 memcpy(thekey, old.thekey, themax * sizeof(*thekey));
624
625 assert(isConsistent());
626 }
627
628 /// assignment operator.
629 /** The assignment operator involves #reMax()%ing the lvalue ClassSet
630 * to the size needed for copying all elements of the rvalue. After the
631 * assignment all DataKeys from the lvalue are valid for the rvalue as
632 * well. They refer to a copy of the corresponding class elements.
633 */
635 {
636 if(this != &rhs)
637 {
638 int i;
639
640 if(rhs.size() > max())
641 reMax(rhs.size());
642
643 clear();
644
645 for(i = 0; i < rhs.size(); ++i)
646 theitem[i] = std::move(rhs.theitem[i]);
647
648 for(i = 0; i < rhs.num(); ++i)
649 thekey[i] = rhs.thekey[i];
650
651 if(rhs.firstfree == -rhs.themax - 1)
652 firstfree = -themax - 1;
653 else
654 {
655 firstfree = rhs.firstfree;
656 i = rhs.firstfree;
657
658 while(rhs.theitem[ -i - 1].info != -rhs.themax - 1)
659 i = rhs.theitem[ -i - 1].info;
660
661 theitem[ -i - 1].info = -themax - 1;
662 }
663
664 thenum = rhs.thenum;
665 thesize = rhs.thesize;
666
667 assert(isConsistent());
668 }
669
670 return *this;
671 }
672
673 /// destructor.
675 {
676 if(theitem)
678
679 if(thekey)
681 }
682 ///@}
683};
684
685} // namespace soplex
686#endif // _CLASSSET_H_
Save arrays of arbitrary types.
Save arrays of data objects.
Set of class objects.
Definition: classset.h:95
void remove(const int *nums, int n)
remove n elements with numbers nums.
Definition: classset.h:340
ClassSet(const ClassSet &old)
copy constructor.
Definition: classset.h:590
T * create(DataKey &newkey)
creates new class element in ClassSet.
Definition: classset.h:190
void remove(int removenum)
removes the removenum 'th element.
Definition: classset.h:235
bool has(int n) const
Is n a valid number of an element in ClassSet?
Definition: classset.h:455
ClassSet(int pmax=8)
default constructor.
Definition: classset.h:560
void remove(const DataKey &removekey)
removes element with key removekey.
Definition: classset.h:261
void remove(const DataKey *keys, int n)
remove n elements given by keys.
Definition: classset.h:321
bool isConsistent() const
consistency check.
Definition: classset.h:529
T & operator[](int n)
Definition: classset.h:364
struct soplex::ClassSet::Item * theitem
array of elements in the ClassSet
int themax
length of arrays theitem and thekey
Definition: classset.h:114
void add(const ClassSet< T > &set)
adds all elements of set.
Definition: classset.h:179
void add(DataKey newkey[], const ClassSet< T > &set)
adds several new items.
Definition: classset.h:170
void add(DataKey &newkey, const T &item)
adds an element.
Definition: classset.h:131
int number(const T *item) const
returns the number of element item in ClassSet, throws exception if it doesn't exist.
Definition: classset.h:438
void remove(int perm[])
remove multiple elements.
Definition: classset.h:271
T & operator[](const DataKey &k)
Definition: classset.h:377
int firstfree
first unused element in theitem
Definition: classset.h:117
const T & operator[](const DataKey &k) const
returns element with DataKey k.
Definition: classset.h:383
int number(const DataKey &k) const
returns the number of the element with DataKey k in ClassSet or -1, if it doesn't exist.
Definition: classset.h:427
void add(DataKey newkey[], const T *item, int n)
add several items.
Definition: classset.h:150
int max() const
returns maximum number of elements that would fit into ClassSet.
Definition: classset.h:394
DataKey key(const T *item) const
returns DataKey of element item in ClassSet.
Definition: classset.h:419
ptrdiff_t reMax(int newmax=0)
resets max() to newmax.
Definition: classset.h:489
T * create()
creates new (uninitialized) class element in ClassSet.
Definition: classset.h:211
void add(const T &item)
adds element item.
Definition: classset.h:140
int num() const
returns number of elements currently in ClassSet.
Definition: classset.h:400
int thesize
highest used element in theitem
Definition: classset.h:115
bool has(const T *item) const
Does item belong to ClassSet?
Definition: classset.h:461
bool has(const DataKey &k) const
Is k a valid DataKey of an element in ClassSet?
Definition: classset.h:449
DataKey * thekey
DataKey::idx's of elements.
Definition: classset.h:113
void add(const T *items, int n)
adds n elements from items.
Definition: classset.h:160
void clear()
remove all elements.
Definition: classset.h:347
const T & operator[](int n) const
returns element number n.
Definition: classset.h:370
DataKey key(int n) const
returns DataKey of n 'th element in ClassSet.
Definition: classset.h:412
void remove(const DataKey *keys, int n, int *perm)
remove n elements given by keys and perm.
Definition: classset.h:308
int thenum
number of elements in ClassSet
Definition: classset.h:116
ClassSet< T > & operator=(const ClassSet< T > &rhs)
assignment operator.
Definition: classset.h:634
~ClassSet()
destructor.
Definition: classset.h:674
int size() const
returns the maximum DataKey::idx currently in ClassSet.
Definition: classset.h:406
void remove(const int *nums, int n, int *perm)
remove n elements given by nums and perm.
Definition: classset.h:327
T * get_ptr()
get a C pointer to the data.
Definition: dataarray.h:123
Entry identifier class for items of a DataSet.
Definition: datakey.h:56
int idx
(locally) unique key index
Definition: datakey.h:65
Exception base class.
Definition: exceptions.h:42
Exception class for out of memory exceptions.
Definition: exceptions.h:80
Save arrays of data objects.
Entry identifier class for items of a DataSet.
Exception classes for SoPlex.
Everything should be within this namespace.
void spx_realloc(T &p, int n)
Change amount of allocated memory.
Definition: spxalloc.h:90
void spx_free(T &p)
Release memory.
Definition: spxalloc.h:121
void spx_alloc(T &p, int n=1)
Allocate memory.
Definition: spxalloc.h:58
Memory allocation routines.
#define SPX_MSG_INCONSISTENT(name)
Definition: spxdefines.h:175
int info
element number. info [0,thesize-1] iff element is used
Definition: classset.h:105
T data
T element.
Definition: classset.h:104
Sparse vectors.