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