Scippy

SoPlex

Sequential object-oriented simPlex

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