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