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-2019 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/dataarray.h"
27 #include "soplex/datakey.h"
28 #include "soplex/spxalloc.h"
29 #include "soplex/exceptions.h"
30 
31 namespace soplex
32 {
33 /**@class DataSet
34  @brief Set of data objects.
35  @ingroup Elementary
36 
37  Class DataSet manages of sets of data objects of a
38  template type DATA. For constructing a DataSet the maximum number
39  of entries must be given. The current maximum number may be inquired
40  with method max().
41 
42  Adding more then max() elements to a DataSet will core dump. However,
43  method reMax() allows to reset max() without loss of elements currently
44  in the DataSet. The current number of elements in a DataSet is returned
45  by method num().
46 
47  Adding elements to a DataSet is done via methods add() or create(),
48  while remove() removes elements from a DataSet. When adding an element
49  to a DataSet the new element is assigned a DataKey. DataKeys serve to
50  access DATA elements in a set via a version of the subscript
51  operator[](DataKey).
52 
53  For convenience all elements in a DataSet are implicitely numbered
54  from 0 through num()-1 and can be accessed with these numbers
55  using a 2nd subscript operator[](int). The reason for providing
56  DataKeys to access elements of a DataSet is that the Key of an
57  element remains unchanged as long as the element is a member of the
58  DataSet, while the numbers will change in an undefined way, if
59  other elements are added to or removed from the DataSet.
60 
61  The elements in a DataSet and their DataKeys are stored in two arrays:
62  - theitem keeps the elements data along with their number stored in item.
63  - thekey keeps the DataKey::idx's of the elements in a DataSet.
64 
65  Both arrays have size themax.
66 
67  In #thekey only elements 0 thru thenum-1 contain DataKey::idx%'s of
68  valid elements, i.e., elements currently in the DataSet.
69  The current number of elements in the DataSet is counted in thenum.
70 
71  In #theitem only elements 0 thru thesize-1 are used, but only some of
72  them actually contain real data elements of the DataSet. They are
73  recognized by having info >= 0, which gives the number of that
74  element. Otherwise info < 0 indicates an unused element. Unused
75  elements are linked in a single linked list: starting with element
76  <tt>-firstfree-1</tt>, the next free element is given by
77  <tt>-info-1.</tt> The last free element in the list is marked by
78  <tt>info == -themax-1.</tt> Finally all elements in theitem with
79  <tt>index >= thesize</tt> are unused as well.
80 
81  @warning malloc/realloc and memcpy are used to handle the members
82  of the set. If you use DataSet with something that is not
83  a \ref DataObjects "Data Object" you will be in severe trouble.
84 */
85 template<class DATA>
86 class DataSet
87 {
88 protected:
89 
90  //-----------------------------------
91  /**@name Types */
92  //@{
93  ///
94  struct Item
95  {
96  DATA data; ///< data element
97  int info; ///< element number. info \f$\in\f$ [0,thesize-1]
98  ///< iff element is used
99  }* theitem; ///< array of elements in the DataSet
100  //@}
101 
102  //-----------------------------------
103  /**@name Data */
104  //@{
105  DataKey* thekey; ///< DataKey::idx's of elements
106  int themax; ///< length of arrays theitem and thekey
107  int thesize; ///< highest used element in theitem
108  int thenum; ///< number of elements in DataSet
109  int firstfree; ///< first unused element in theitem
110  //@}
111 
112 public:
113 
114  //-----------------------------------
115  /**@name Extension
116  * Whenever a new element is added to a DataSet, the latter assigns it a
117  * DataKey. For this all methods that extend a DataSet by one ore more
118  * elements are provided with two signatures, one of them having a
119  * parameter for returning the assigned DataKey(s).
120  */
121  //@{
122  /// adds an element.
123  void add(DataKey& newkey, const DATA& item)
124  {
125  DATA* data = create(newkey);
126 
127  assert(data != 0);
128 
129  *data = item;
130  }
131  /// adds element \p item.
132  /**@return 0 on success and non-zero, if an error occured.
133  */
134  void add(const DATA& item)
135  {
136  DATA* data = create();
137 
138  assert(data != 0);
139 
140  *data = item;
141  }
142 
143  /// add several items.
144  void add(DataKey newkey[], const DATA* 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 DATA* 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 DataSet < DATA >& 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 DataSet < DATA >& 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 data element in DataSet.
182  /**@return Pointer to the newly created element.
183  */
184  DATA* 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) data element in DataSet.
203  /**@return Pointer to the newly created element.
204  */
205  DATA* create()
206  {
207  DataKey tmp;
208  return create(tmp);
209  }
210  //@}
211 
212  //-----------------------------------
213  /**@name Shrinkage
214  * When elements are removed from a DataSet, 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 DataSet 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 DataSet 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 DataSet with one of the index
352  * operators, it must be ensured that the index is valid for the
353  * DataSet. If this is not known afore, it is the programmers
354  * responsability to ensure this using the inquiry methods below.
355  */
356  //@{
357  ///
358  DATA& 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 DATA& operator[](int n) const
365  {
366  assert(n >= 0 && n < thenum);
367  return theitem[thekey[n].idx].data;
368  }
369 
370  ///
371  DATA& 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 DATA& 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 DataSet.
388  int max() const
389  {
390  return themax;
391  }
392 
393  /// returns number of elements currently in DataSet.
394  int num() const
395  {
396  return thenum;
397  }
398 
399  /// returns the maximum DataKey::idx currently in DataSet.
400  int size() const
401  {
402  return thesize;
403  }
404 
405  /// returns DataKey of \p n 'th element in DataSet.
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 DataSet.
413  DataKey key(const DATA* 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 DataSet 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 DataSet,
431  /// throws exception if it doesn't exist.
432  int number(const DATA* 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 DataSet?
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 DataSet?
449  bool has(int n) const
450  {
451  return (n >= 0 && n < num());
452  }
453 
454  /// Does \p item belong to DataSet?
455  bool has(const DATA* 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 #DataSet%s elements in memory, reMax() returns the
479  * number of bytes the addresses of elements in the DataSet have been
480  * moved. Note, that this is identical for all elements in the
481  * DataSet.
482  */
483  ptrdiff_t reMax(int newmax = 0)
484  {
485  struct Item* old_theitem = theitem;
486  newmax = (newmax < size()) ? size() : newmax;
487 
488  int* lastfree = &firstfree;
489 
490  while(*lastfree != -themax - 1)
491  lastfree = &(theitem[ -1 - *lastfree].info);
492 
493  *lastfree = -newmax - 1;
494 
495  themax = newmax;
496  spx_realloc(theitem, themax);
497  spx_realloc(thekey, themax);
498 
499  return reinterpret_cast<char*>(theitem)
500  - reinterpret_cast<char*>(old_theitem);
501  }
502 
503  /// consistency check.
504  bool isConsistent() const
505  {
506 #ifdef ENABLE_CONSISTENCY_CHECKS
507 
508  if(theitem == 0 || thekey == 0)
509  return MSGinconsistent("DataSet");
510 
511  if(thesize > themax || thenum > themax || thenum > thesize)
512  return MSGinconsistent("DataSet");
513 
514  if(thesize == thenum && firstfree != -themax - 1)
515  return MSGinconsistent("DataSet");
516 
517  if(thesize != thenum && firstfree == -themax - 1)
518  return MSGinconsistent("DataSet");
519 
520  for(int i = 0; i < thenum; ++i)
521  if(theitem[thekey[i].idx].info != i)
522  return MSGinconsistent("DataSet");
523 
524 #endif
525 
526  return true;
527  }
528  //@}
529 
530  //-----------------------------------
531  /**@name Constructors / Destructors */
532  //@{
533  /// default constructor.
534  explicit
535  DataSet(int pmax = 8)
536  : theitem(0)
537  , thekey(0)
538  , themax(pmax < 1 ? 8 : pmax)
539  , thesize(0)
540  , thenum(0)
541 
542  {
543  firstfree = -themax - 1;
544 
545  spx_alloc(theitem, themax);
546 
547  try
548  {
549  spx_alloc(thekey, themax);
550  }
551  catch(const SPxMemoryException& x)
552  {
553  spx_free(theitem);
554  throw x;
555  }
556 
557  assert(isConsistent());
558  }
559 
560  /// copy constructor.
561  DataSet(const DataSet& old)
562  : theitem(0)
563  , thekey(0)
564  , themax(old.themax)
565  , thesize(old.thesize)
566  , thenum(old.thenum)
567  {
568  firstfree = (old.firstfree == -old.themax - 1)
569  ? -themax - 1
570  : old.firstfree;
571 
572  spx_alloc(theitem, themax);
573 
574  try
575  {
576  spx_alloc(thekey, themax);
577  }
578  catch(const SPxMemoryException& x)
579  {
580  spx_free(theitem);
581  throw x;
582  }
583 
584  memcpy(theitem, old.theitem, themax * sizeof(*theitem));
585  memcpy(thekey, old.thekey, themax * sizeof(*thekey));
586 
587  assert(isConsistent());
588  }
589 
590  /// assignment operator.
591  /** The assignment operator involves #reMax()%ing the lvalue DataSet
592  * to the size needed for copying all elements of the rvalue. After the
593  * assignment all DataKeys from the lvalue are valid for the rvalue as
594  * well. They refer to a copy of the corresponding data elements.
595  */
597  {
598  if(this != &rhs)
599  {
600  int i;
601 
602  if(rhs.size() > max())
603  reMax(rhs.size());
604 
605  clear();
606 
607  for(i = 0; i < rhs.size(); ++i)
608  memcpy(&theitem[i], &rhs.theitem[i], sizeof(*theitem));
609 
610  for(i = 0; i < rhs.num(); ++i)
611  thekey[i] = rhs.thekey[i];
612 
613  if(rhs.firstfree == -rhs.themax - 1)
614  firstfree = -themax - 1;
615  else
616  {
617  firstfree = rhs.firstfree;
618  i = rhs.firstfree;
619 
620  while(rhs.theitem[ -i - 1].info != -rhs.themax - 1)
621  i = rhs.theitem[ -i - 1].info;
622 
623  theitem[ -i - 1].info = -themax - 1;
624  }
625 
626  thenum = rhs.thenum;
627  thesize = rhs.thesize;
628 
629  assert(isConsistent());
630  }
631 
632  return *this;
633  }
634 
635  /// destructor.
637  {
638  if(theitem)
639  spx_free(theitem);
640 
641  if(thekey)
642  spx_free(thekey);
643  }
644  //@}
645 };
646 
647 } // namespace soplex
648 #endif // _DATASET_H_
DataKey * thekey
DataKey::idx&#39;s of elements.
Definition: dataset.h:105
int thenum
number of elements in DataSet
Definition: dataset.h:108
struct soplex::DataSet::Item * theitem
array of elements in the DataSet
DATA & operator[](const DataKey &k)
Definition: dataset.h:371
DataKey key(int n) const
returns DataKey of n &#39;th element in DataSet.
Definition: dataset.h:406
Entry identifier class for items of a DataSet.
void add(const DATA *items, int n)
adds n elements from items.
Definition: dataset.h:154
Memory allocation routines.
void add(const DataSet< DATA > &set)
adds all elements of set.
Definition: dataset.h:173
T * get_ptr()
get a C pointer to the data.
Definition: dataarray.h:110
Exception classes for SoPlex.
ptrdiff_t reMax(int newmax=0)
resets max() to newmax.
Definition: dataset.h:483
int info
element number. info [0,thesize-1] iff element is used
Definition: dataset.h:97
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:432
bool has(const DATA *item) const
Does item belong to DataSet?
Definition: dataset.h:455
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:358
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:48
Set of data objects.Class DataSet manages of sets of data objects of a template type DATA...
Definition: dataset.h:86
DataSet(const DataSet &old)
copy constructor.
Definition: dataset.h:561
void add(DataKey &newkey, const DATA &item)
adds an element.
Definition: dataset.h:123
DATA * create()
creates new (uninitialized) data element in DataSet.
Definition: dataset.h:205
bool has(int n) const
Is n a valid number of an element in DataSet?
Definition: dataset.h:449
DataSet< DATA > & operator=(const DataSet< DATA > &rhs)
assignment operator.
Definition: dataset.h:596
int thesize
highest used element in theitem
Definition: dataset.h:107
void clear()
remove all elements.
Definition: dataset.h:341
bool isConsistent() const
consistency check.
Definition: dataset.h:504
DataKey key(const DATA *item) const
returns DataKey of element item in DataSet.
Definition: dataset.h:413
int firstfree
first unused element in theitem
Definition: dataset.h:109
void spx_realloc(T &p, int n)
Change amount of allocated memory.
Definition: spxalloc.h:79
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:636
bool has(const DataKey &k) const
Is k a valid DataKey of an element in DataSet?
Definition: dataset.h:443
DataSet(int pmax=8)
default constructor.
Definition: dataset.h:535
void add(DataKey newkey[], const DataSet< DATA > &set)
adds several new items.
Definition: dataset.h:164
int size() const
returns the maximum DataKey::idx currently in DataSet.
Definition: dataset.h:400
const DATA & operator[](const DataKey &k) const
returns element with DataKey k.
Definition: dataset.h:377
int max() const
returns maximum number of elements that would fit into DataSet.
Definition: dataset.h:388
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:421
DATA * create(DataKey &newkey)
creates new data element in DataSet.
Definition: dataset.h:184
#define MSGinconsistent(name)
Definition: spxdefines.h:126
DATA data
data element
Definition: dataset.h:96
Save arrays of data objects.
void add(const DATA &item)
adds element item.
Definition: dataset.h:134
int num() const
returns number of elements currently in DataSet.
Definition: dataset.h:394
int idx
(locally) unique key index
Definition: datakey.h:56
void spx_free(T &p)
Release memory.
Definition: spxalloc.h:110
const DATA & operator[](int n) const
returns element number n.
Definition: dataset.h:364
void add(DataKey newkey[], const DATA *item, int n)
add several items.
Definition: dataset.h:144
int themax
length of arrays theitem and thekey
Definition: dataset.h:106