SoPlex Documentation
Loading...
Searching...
No Matches
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 != 0);
136
137 *newelem = item;
138 }
139 /// adds element \p item.
140 void add(const T& item)
141 {
142 T* newelem = create();
143
144
145 assert(newelem != 0);
146
147 *newelem = item;
148 }
149
150 /// add several items.
151 void add(DataKey newkey[], const T* item, int n)
152 {
153 assert(n >= 0);
154 assert(num() + n <= max());
155
156 for(int i = 0; i < n; ++i)
157 add(newkey[i], item[i]);
158 }
159
160 /// adds \p n elements from \p items.
161 void add(const T* items, int n)
162 {
163 assert(n >= 0);
164 assert(num() + n <= max());
165
166 for(int i = 0; i < n; ++i)
167 add(items[i]);
168 }
169
170 /// adds several new items.
171 void add(DataKey newkey[], const ClassSet < T >& set)
172 {
173 assert(num() + set.num() <= max());
174
175 for(int i = 0; i < set.num(); ++i)
176 add(newkey[i], set[i]);
177 }
178
179 /// adds all elements of \p set.
180 void add(const ClassSet < T >& set)
181 {
182 assert(num() + set.num() <= max());
183
184 for(int i = 0; i < set.num(); ++i)
185 add(set[i]);
186 }
187
188 /// creates new class element in ClassSet.
189 /**@return Pointer to the newly created element.
190 */
191 T* create(DataKey& newkey)
192 {
193 assert(num() < max());
194
195 if(firstfree != -themax - 1)
196 {
197 newkey.idx = -firstfree - 1;
198 firstfree = theitem[newkey.idx].info;
199 }
200 else
201 newkey.idx = thesize++;
202
203 thekey[thenum] = newkey;
204 theitem[newkey.idx].info = thenum;
205 ++thenum;
206
207 return &(theitem[newkey.idx].data);
208 }
209 /// creates new (uninitialized) class element in ClassSet.
210 /**@return Pointer to the newly created element.
211 */
213 {
214 DataKey tmp;
215 return create(tmp);
216 }
217 ///@}
218
219 //-----------------------------------
220 /**@name Shrinkage
221 * When elements are removed from a ClassSet, the remaining ones are
222 * renumbered from 0 through the new size()-1. How this renumbering is
223 * performed will not be revealed, since it might be target of future
224 * changes. However, some methods provide a parameter
225 * <tt>int* perm</tt>, which
226 * returns the new order after the removal: If <tt>perm[i] < 0</tt>,
227 * the element numbered i prior to the removal operation has been removed
228 * from the set. Otherwise, <tt>perm[i] = j >= 0</tt> means that the
229 * element with number i prior to the removal operation has been
230 * renumbered to j. Removing a single element from a ClassSet yields a
231 * simple renumbering of the elements: The last element in the set
232 * (i.e., element num()-1) is moved to the index of the removed element.
233 */
234 ///@{
235 /// removes the \p removenum 'th element.
236 void remove(int removenum)
237 {
238 if(has(removenum))
239 {
240 int idx = thekey[removenum].idx;
241
242 theitem[idx].info = firstfree;
243 firstfree = -idx - 1;
244
245 while(-firstfree == thesize)
246 {
248 --thesize;
249 }
250
251 --thenum;
252
253 if(removenum != thenum)
254 {
255 thekey[removenum] = thekey[thenum];
256 theitem[thekey[removenum].idx].info = removenum;
257 }
258 }
259 }
260
261 /// removes element with key \p removekey.
262 void remove(const DataKey& removekey)
263 {
264 remove(number(removekey));
265 }
266
267 /// remove multiple elements.
268 /** This method removes all elements for the ClassSet with an
269 * index i such that \p perm[i] < 0. Upon completion, \p perm contains
270 * the new numbering of elements.
271 */
272 void remove(int perm[])
273 {
274 int k, j, first = -1;
275
276 // setup permutation and remove items
277 for(k = j = 0; k < num(); ++k)
278 {
279 if(perm[k] >= 0) // j has not been removed ...
280 perm[k] = j++;
281 else
282 {
283 int idx = thekey[k].idx;
284 theitem[idx].info = firstfree;
285 firstfree = -idx - 1;
286
287 if(first < 0)
288 first = k;
289 }
290 }
291
292 if(first >= 0) // move remaining items
293 {
294 for(k = first, j = num(); k < j; ++k)
295 {
296 if(perm[k] >= 0)
297 {
298 thekey[perm[k]] = thekey[k];
299 theitem[thekey[k].idx].info = perm[k];
300 thekey[k].idx = -1;
301 }
302 else
303 --thenum;
304 }
305 }
306 }
307
308 /// remove \p n elements given by \p keys and \p perm.
309 void remove(const DataKey* keys, int n, int* perm)
310 {
311 assert(perm != 0);
312
313 for(int i = num() - 1; i >= 0; --i)
314 perm[i] = i;
315
316 while(--n >= 0)
317 perm[number(keys[n])] = -1;
318
319 remove(perm);
320 }
321 /// remove \p n elements given by \p keys.
322 void remove(const DataKey* keys, int n)
323 {
324 DataArray<int> perm(num());
325 remove(keys, n, perm.get_ptr());
326 }
327 /// remove \p n elements given by \p nums and \p perm.
328 void remove(const int* nums, int n, int* perm)
329 {
330 assert(perm != 0);
331
332 for(int i = num() - 1; i >= 0; --i)
333 perm[i] = i;
334
335 while(--n >= 0)
336 perm[nums[n]] = -1;
337
338 remove(perm);
339 }
340 /// remove \p n elements with numbers \p nums.
341 void remove(const int* nums, int n)
342 {
343 DataArray<int> perm(num());
344 remove(nums, n, perm.get_ptr());
345 }
346
347 /// remove all elements.
348 void clear()
349 {
350 thesize = 0;
351 thenum = 0;
352 firstfree = -themax - 1;
353 }
354 ///@}
355
356 //-----------------------------------
357 /**@name Access
358 * When accessing elements from a ClassSet with one of the index
359 * operators, it must be ensured that the index is valid for the
360 * ClassSet. If this is not known afore, it is the programmers
361 * responsability to ensure this using the inquiry methods below.
362 */
363 ///@{
364 ///
365 T& operator[](int n)
366 {
367 assert(n >= 0 && n < thenum);
368 return theitem[thekey[n].idx].data;
369 }
370 /// returns element number \p n.
371 const T& operator[](int n) const
372 {
373 assert(n >= 0 && n < thenum);
374 return theitem[thekey[n].idx].data;
375 }
376
377 ///
378 T& operator[](const DataKey& k)
379 {
380 assert(k.idx < thesize);
381 return theitem[k.idx].data;
382 }
383 /// returns element with DataKey \p k.
384 const T& operator[](const DataKey& k) const
385 {
386 assert(k.idx < thesize);
387 return theitem[k.idx].data;
388 }
389 ///@}
390
391 //-----------------------------------
392 /**@name Inquiry */
393 ///@{
394 /// returns maximum number of elements that would fit into ClassSet.
395 int max() const
396 {
397 return themax;
398 }
399
400 /// returns number of elements currently in ClassSet.
401 int num() const
402 {
403 return thenum;
404 }
405
406 /// returns the maximum DataKey::idx currently in ClassSet.
407 int size() const
408 {
409 return thesize;
410 }
411
412 /// returns DataKey of \p n 'th element in ClassSet.
413 DataKey key(int n) const
414 {
415 assert(n >= 0 && n < num());
416 return thekey[n];
417 }
418
419 /// returns DataKey of element \p item in ClassSet.
420 DataKey key(const T* item) const
421 {
422 assert(number(item) >= 0);
423 return thekey[number(item)];
424 }
425
426 /// returns the number of the element with DataKey \p k in ClassSet or -1,
427 /// if it doesn't exist.
428 int number(const DataKey& k) const
429 {
430 if(k.idx < 0 || k.idx >= size())
431 throw SPxException("Invalid index");
432
433 return theitem[k.idx].info;
434 }
435
436 /**@todo Please check whether this is correctly implemented! */
437 /// returns the number of element \p item in ClassSet,
438 /// throws exception if it doesn't exist.
439 int number(const T* item) const
440 {
441 ptrdiff_t idx = reinterpret_cast<const struct Item*>(item) - theitem;
442
443 if(idx < 0 || idx >= size())
444 throw SPxException("Invalid index");
445
446 return theitem[idx].info;
447 }
448
449 /// Is \p k a valid DataKey of an element in ClassSet?
450 bool has(const DataKey& k) const
451 {
452 return theitem[k.idx].info >= 0;
453 }
454
455 /// Is \p n a valid number of an element in ClassSet?
456 bool has(int n) const
457 {
458 return (n >= 0 && n < num());
459 }
460
461 /// Does \p item belong to ClassSet?
462 bool has(const T* item) const
463 {
464 int n;
465
466 try
467 {
468 n = number(item);
469 }
470 catch(...)
471 {
472 return false;
473 }
474
475 return n >= 0;
476 }
477 ///@}
478
479 //-----------------------------------
480 /**@name Miscellaneous */
481 ///@{
482 /// resets max() to \p newmax.
483 /** This method will not succeed if \p newmax < size(), in which case
484 * \p newmax == size() will be taken. As generally this method involves
485 * copying the #ClassSet%s elements in memory, reMax() returns the
486 * number of bytes the addresses of elements in the ClassSet have been
487 * moved. Note, that this is identical for all elements in the
488 * ClassSet.
489 */
490 ptrdiff_t reMax(int newmax = 0)
491 {
492 int i;
493 Item* newMem = 0;
494 newmax = (newmax < size()) ? size() : newmax;
495
496 int* lastfree = &firstfree;
497
498 while(*lastfree != -themax - 1)
499 lastfree = &(theitem[ -1 - *lastfree].info);
500
501 *lastfree = -newmax - 1;
502
503 spx_alloc(newMem, newmax);
504
505 /* call copy constructor for first elements */
506 for(i = 0; i < max(); i++)
507 {
508 newMem[i].data = std::move(theitem[i].data);
509 newMem[i].info = theitem[i].info;
510 }
511
512 /* call default constructor for remaining elements */
513 for(; i < newmax; i++)
514 new(&(newMem[i])) Item();
515
516 /* compute pointer difference */
517 ptrdiff_t pshift = reinterpret_cast<char*>(newMem) - reinterpret_cast<char*>(theitem);
518
520
521 theitem = newMem;
522 themax = newmax;
523
525
526 return pshift;
527 }
528
529 /// consistency check.
530 bool isConsistent() const
531 {
532#ifdef ENABLE_CONSISTENCY_CHECKS
533
534 if(theitem == 0 || thekey == 0)
535 return SPX_MSG_INCONSISTENT("ClassSet");
536
537 if(thesize > themax || thenum > themax || thenum > thesize)
538 return SPX_MSG_INCONSISTENT("ClassSet");
539
540 if(thesize == thenum && firstfree != -themax - 1)
541 return SPX_MSG_INCONSISTENT("ClassSet");
542
543 if(thesize != thenum && firstfree == -themax - 1)
544 return SPX_MSG_INCONSISTENT("ClassSet");
545
546 for(int i = 0; i < thenum; ++i)
547 if(theitem[thekey[i].idx].info != i)
548 return SPX_MSG_INCONSISTENT("ClassSet");
549
550#endif
551
552 return true;
553 }
554 ///@}
555
556 //-----------------------------------
557 /**@name Constructors / Destructors */
558 ///@{
559 /// default constructor.
560 explicit
561 ClassSet(int pmax = 8)
562 : theitem(0)
563 , thekey(0)
564 , themax(pmax < 1 ? 8 : pmax)
565 , thesize(0)
566 , thenum(0)
567
568 {
569 firstfree = -themax - 1;
570
572
573 /* call default constructor for each element */
574 for(int i = 0; i < themax; i++)
575 new(&(theitem[i])) Item();
576
577 try
578 {
580 }
581 catch(const SPxMemoryException& x)
582 {
584 throw x;
585 }
586
587 assert(isConsistent());
588 }
589
590 /// copy constructor.
591 ClassSet(const ClassSet& old)
592 : theitem(0)
593 , thekey(0)
594 , themax(old.themax)
595 , thesize(old.thesize)
596 , thenum(old.thenum)
597 {
598 firstfree = (old.firstfree == -old.themax - 1)
599 ? -themax - 1
600 : old.firstfree;
601
603
604 /* call copy constructor for first elements */
605 int i;
606
607 for(i = 0; i < old.thenum; i++)
608 new(&(theitem[i])) Item(old.theitem[i]);
609
610 /* call default constructor for remaining elements */
611 for(; i < old.themax; i++)
612 new(&(theitem[i])) Item();
613
614 try
615 {
617 }
618 catch(const SPxMemoryException& x)
619 {
621 throw x;
622 }
623
624 memcpy(thekey, old.thekey, themax * sizeof(*thekey));
625
626 assert(isConsistent());
627 }
628
629 /// assignment operator.
630 /** The assignment operator involves #reMax()%ing the lvalue ClassSet
631 * to the size needed for copying all elements of the rvalue. After the
632 * assignment all DataKeys from the lvalue are valid for the rvalue as
633 * well. They refer to a copy of the corresponding class elements.
634 */
636 {
637 if(this != &rhs)
638 {
639 int i;
640
641 if(rhs.size() > max())
642 reMax(rhs.size());
643
644 clear();
645
646 for(i = 0; i < rhs.size(); ++i)
647 theitem[i] = std::move(rhs.theitem[i]);
648
649 for(i = 0; i < rhs.num(); ++i)
650 thekey[i] = rhs.thekey[i];
651
652 if(rhs.firstfree == -rhs.themax - 1)
653 firstfree = -themax - 1;
654 else
655 {
656 firstfree = rhs.firstfree;
657 i = rhs.firstfree;
658
659 while(rhs.theitem[ -i - 1].info != -rhs.themax - 1)
660 i = rhs.theitem[ -i - 1].info;
661
662 theitem[ -i - 1].info = -themax - 1;
663 }
664
665 thenum = rhs.thenum;
666 thesize = rhs.thesize;
667
668 assert(isConsistent());
669 }
670
671 return *this;
672 }
673
674 /// destructor.
676 {
677 if(theitem)
679
680 if(thekey)
682 }
683 ///@}
684};
685
686} // namespace soplex
687#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:341
ClassSet(const ClassSet &old)
copy constructor.
Definition classset.h:591
T * create(DataKey &newkey)
creates new class element in ClassSet.
Definition classset.h:191
void remove(int removenum)
removes the removenum 'th element.
Definition classset.h:236
bool has(int n) const
Is n a valid number of an element in ClassSet?
Definition classset.h:456
ClassSet(int pmax=8)
default constructor.
Definition classset.h:561
void remove(const DataKey &removekey)
removes element with key removekey.
Definition classset.h:262
void remove(const DataKey *keys, int n)
remove n elements given by keys.
Definition classset.h:322
bool isConsistent() const
consistency check.
Definition classset.h:530
T & operator[](int n)
Definition classset.h:365
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:180
void add(DataKey newkey[], const ClassSet< T > &set)
adds several new items.
Definition classset.h:171
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:439
void remove(int perm[])
remove multiple elements.
Definition classset.h:272
T & operator[](const DataKey &k)
Definition classset.h:378
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:384
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:428
void add(DataKey newkey[], const T *item, int n)
add several items.
Definition classset.h:151
int max() const
returns maximum number of elements that would fit into ClassSet.
Definition classset.h:395
DataKey key(const T *item) const
returns DataKey of element item in ClassSet.
Definition classset.h:420
ptrdiff_t reMax(int newmax=0)
resets max() to newmax.
Definition classset.h:490
T * create()
creates new (uninitialized) class element in ClassSet.
Definition classset.h:212
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:401
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:462
bool has(const DataKey &k) const
Is k a valid DataKey of an element in ClassSet?
Definition classset.h:450
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:161
void clear()
remove all elements.
Definition classset.h:348
const T & operator[](int n) const
returns element number n.
Definition classset.h:371
DataKey key(int n) const
returns DataKey of n 'th element in ClassSet.
Definition classset.h:413
void remove(const DataKey *keys, int n, int *perm)
remove n elements given by keys and perm.
Definition classset.h:309
int thenum
number of elements in ClassSet
Definition classset.h:116
ClassSet< T > & operator=(const ClassSet< T > &rhs)
assignment operator.
Definition classset.h:635
~ClassSet()
destructor.
Definition classset.h:675
int size() const
returns the maximum DataKey::idx currently in ClassSet.
Definition classset.h:407
void remove(const int *nums, int n, int *perm)
remove n elements given by nums and perm.
Definition classset.h:328
Safe arrays of data objects.
Definition dataarray.h:75
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
Sparse vectors.