diff --git a/graph/graph.cpp b/graph/graph.cpp index 04d6cd812ec3c8f0cb3610417e97b0d2a2395568..71e518e771d142594316d475e4add3128b035b6f 100644 --- a/graph/graph.cpp +++ b/graph/graph.cpp @@ -180,6 +180,12 @@ #define COST_TABLE "BENCH_COST" +//============================================================================= +// How many bytes does the bitstring in one element of the adjacency list have? +//============================================================================= + +#define BITSTRING_BYTES 4 + //============================================================================= // Include Files: //============================================================================= @@ -358,6 +364,361 @@ long str_int(str_t digits) { } +//============================================================================= +// Class for Linked List Element in Node Set (contains bit array): +//============================================================================= + +class NodeSetElem { + public: + + // Constructor: + NodeSetElem(int start_value) + { + next_ = (NodeSetElem *) 0; + start_ = start_value; + unsigned char *p = bits_; + for(int i = BITSTRING_BYTES; i > 0; i--) + *p++ = '\0'; + } + + // Get start node number (to be added to all numbers in bit array): + inline int start() const { + return start_; + } + + // Get link to next list elem: + inline NodeSetElem *next() const { + return next_; + } + + // Set link to next list elem: + inline void set_next(NodeSetElem *next_elem) { + next_ = next_elem; + } + + // Get bit in bit array: + inline bool bit(int index) const { + + // Check validity, part I: + if(index < 0) { + std::cerr << "get_bit: Invalid bit index (negative)!"; + exit(3); + } + + // Determine position in bit array: + int bit_no = index % 8; + index = index / 8; + + // Check parameter, part II: + if(index >= BITSTRING_BYTES) { + std::cerr << "get_bit: Invalid bit index (too large)!"; + exit(4); + } + + // Get bit: + return (bits_[index] & ((0x1) << bit_no)) != 0; + } + + // Set bit in bit array: + inline void set_bit(int index) { + + // Check validity, part I: + if(index < 0) { + std::cerr << "set_bit: Invalid bit index (negative)!"; + exit(5); + } + + // Determine position in bit array: + int bit_no = index % 8; + index = index / 8; + + // Check parameter, part II: + if(index >= BITSTRING_BYTES) { + std::cerr << "set_bit: Invalid bit index (too large)!"; + exit(6); + } + + // Set bit: + bits_[index] |= (0x1) << bit_no; + } + + // Find next set bit in bit array with position >= index: + inline int next_bit(int index) { + + // Check validity, part I: + if(index < 0) { + std::cerr << "next_bit: Invalid bit index (negative)!"; + exit(7); + } + + // Determine position in bit array: + int bit_no = index % 8; + index = index / 8; + + // Check parameter, part II: + if(index >= BITSTRING_BYTES) { + std::cerr << "next_bit: Invalid bit index (too large)!"; + exit(8); + } + + // Find next set bit (-1 if there is no further bit): + unsigned char byte = bits_[index]; + if(byte != 0) { + switch(bit_no) { + case 0: + if(byte & 0x1) + return (index*8); + /* FALLTHROUGH */ + case 1: + if(byte & 0x2) + return (index*8 + 1); + /* FALLTHROUGH */ + case 2: + if(byte & 0x4) + return (index*8 + 2); + /* FALLTHROUGH */ + case 3: + if(byte & 0x8) + return (index*8 + 3); + /* FALLTHROUGH */ + case 4: + if(byte & 0x10) + return (index*8 + 4); + /* FALLTHROUGH */ + case 5: + if(byte & 0x20) + return (index*8 + 5); + /* FALLTHROUGH */ + case 6: + if(byte & 0x40) + return (index*8 + 6); + /* FALLTHROUGH */ + case 7: + if(byte & 0x80) + return (index*8 + 7); + } + } + while(++index < BITSTRING_BYTES) { + byte = bits_[index]; + if(byte != 0) { + if(byte & 0x1) + return (index*8); + if(byte & 0x2) + return (index*8 + 1); + if(byte & 0x4) + return (index*8 + 2); + if(byte & 0x8) + return (index*8 + 3); + if(byte & 0x10) + return (index*8 + 4); + if(byte & 0x20) + return (index*8 + 5); + if(byte & 0x40) + return (index*8 + 6); + if(byte & 0x80) + return (index*8 + 7); + } + } + + // No set bit found: + return -1; + } + + // Attributes: + private: + NodeSetElem *next_; + int start_; + unsigned char bits_[BITSTRING_BYTES]; +}; + +//----------------------------------------------------------------------------- +// Pointer Type for Node Number List Element: +//----------------------------------------------------------------------------- + +typedef NodeSetElem *node_set_elem_t; + +#define NODE_SET_ELEM_NULL (static_cast<node_set_elem_t>(0)) + + +//============================================================================= +// Class for Scan/Cursor over Node Set (set of non-negative integers): +//============================================================================= + +class NodeSetScan { + public: + + // Constructor: + NodeSetScan(node_set_elem_t list) + { + list_ = list; + curr_elem_ = list; + if(curr_elem_ != NODE_SET_ELEM_NULL) + start_ = curr_elem_->start(); + else + start_ = 0; + next_index_ = 0; + } + + // Get next node number in set (-1 if there is no further element): + int next() { + // Check whether we are at the end of the list: + if(curr_elem_ == NODE_SET_ELEM_NULL) + return -1; + + // Try to find next value in current list element: + if(next_index_ < BITSTRING_BYTES * 8) { + int bit = curr_elem_->next_bit(next_index_); + if(bit >= 0) { + next_index_ = bit + 1; + return start_ + bit; + } + } + + // Move to next list element: + curr_elem_ = curr_elem_->next(); + if(curr_elem_ == NODE_SET_ELEM_NULL) + return -1; + + // We know that list elements are non-empty: + start_ = curr_elem_->start(); + int bit = curr_elem_->next_bit(next_index_); + next_index_ = bit + 1; + return start_ + bit; + } + + // Reset scan to start: + void reset() { + curr_elem_ = list_; + if(curr_elem_ != NODE_SET_ELEM_NULL) + start_ = curr_elem_->start(); + else + start_ = 0; + next_index_ = 0; + } + + // Attributes: + private: + node_set_elem_t list_; + node_set_elem_t curr_elem_; + int start_; + int next_index_; +}; + +//----------------------------------------------------------------------------- +// Pointer Type for Node Number List Element: +//----------------------------------------------------------------------------- + +typedef NodeSetScan *node_set_scan_t; + +#define NODE_SET_SCAN_NULL (static_cast<node_set_scan_t>(0)) + + + +//============================================================================= +// Class for Node Set (represented as linked list of bit arrays): +//============================================================================= + +// Note that this actually manages a set of node numbers, +// i.e. non-negative integers. + +class NodeSet { + + public: + + // Constructor: + NodeSet() { + list_ = NODE_SET_ELEM_NULL; + } + + // Destructor: + ~NodeSet() { + node_set_elem_t next = NODE_SET_ELEM_NULL; + for(node_set_elem_t elem = list_; elem; elem = next) { + next = elem->next(); + delete elem; + } + } + + // Insert a node number: + void insert(int n) { + int start = n / (BITSTRING_BYTES * 8); + int index = n % (BITSTRING_BYTES * 8); + + // Handle empty list: + if(list_ == NODE_SET_ELEM_NULL) { + list_ = new NodeSetElem(start); + list_->set_bit(index); + return; + } + + // Handle insertion into first element: + if(list_->start() == start) { + list_->set_bit(index); + return; + } + + // Handle insertion before first element: + if(list_->start() > start) { + node_set_elem_t elem = new NodeSetElem(start); + elem->set_bit(index); + elem->set_next(list_); + list_ = elem; + } + + // Now we can have a pointer to the previous element: + node_set_elem_t prev = list_; + node_set_elem_t next = prev->next(); + while(next != NODE_SET_ELEM_NULL) { + int next_start = next->start(); + // Insert into next element: + if(next_start == start) { + next->set_bit(index); + return; + } + // Insert before next element: + if(next_start > start) { + node_set_elem_t elem = new NodeSetElem(start); + elem->set_bit(index); + elem->set_next(next); + prev->set_next(elem); + } + // Now we know that next_start < start, move on: + prev = next; + next = next->next(); + } + + // Insert node at the very end of the list: + node_set_elem_t elem = new NodeSetElem(start); + elem->set_bit(index); + prev->set_next(elem); + } + + // Check whether a nonnegative integer exists in the set: + bool contains(int n) { + int start = n / (BITSTRING_BYTES * 8); + int index = n % (BITSTRING_BYTES * 8); + for(node_set_elem_t elem = list_; elem; elem = elem->next()) { + int elem_start = elem->start(); + if(elem_start == start) + return elem->bit(index); + if(elem_start > start) + return false; + } + } + + // Attributes: + private: + node_set_elem_t list_; +}; + +//----------------------------------------------------------------------------- +// Pointer Type for Node Set (really a set of non-negative integers): +//----------------------------------------------------------------------------- + +typedef NodeSet *node_set_t; + +#define NODE_SET_NULL (static_cast<node_set_t>(0)) + //============================================================================= // Class for Graph Nodes (one line of the adjacency matrix): //=============================================================================