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