├── bin └── .empty ├── README.md ├── Makefile ├── LICENSE.txt └── src ├── steiner.cpp ├── targetver.h ├── rfw_random.cpp ├── execution_log.h ├── rfw_stack.h ├── simplequeue.h ├── voronoi.h ├── dual.h ├── buckets.h ├── rfw_timer.h ├── constructive.h ├── rfw_timer.cpp ├── uset.h ├── spgconfig.h ├── elite.h ├── drawer.h ├── stedgelinear.h ├── perturbation.h ├── uf.h ├── rfw_random.h ├── binheap.h ├── pairheap.h ├── LSVertexInsertion.h ├── solution.h ├── LSBasics.h └── LSVertexElimination.h /bin/.empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ms-steiner-puw 2 | An evolutionary multi-start algorithm for the Steiner Tree Problem in graphs with a fast local search. 3 | 4 | This project is the implementation of the algorithm introduced in the paper _A Robust and Scalable Algorithm for the Steiner Problem in Graphs_ by Thomas Pajor, Eduardo Uchoa, Renato F. Werneck. 5 | 6 | The paper is available here: http://arxiv.org/abs/1412.2787 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -std=c++11 -O3 -fopenmp -DNDEBUG 3 | LDFLAGS = 4 | BIN = ./bin 5 | SRC = ./src 6 | 7 | .PHONY: steiner 8 | 9 | all: steiner 10 | 11 | rfw_timer: 12 | $(CXX) $(CXXFLAGS) -o $(BIN)/rfw_timer.o -c $(SRC)/rfw_timer.cpp 13 | 14 | rfw_random: 15 | $(CXX) $(CXXFLAGS) -o $(BIN)/rfw_random.o -c $(SRC)/rfw_random.cpp 16 | 17 | steiner: rfw_timer rfw_random 18 | $(CXX) $(CXXFLAGS) -o $(BIN)/steiner.o -c $(SRC)/steiner.cpp 19 | $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(BIN)/steiner $(BIN)/steiner.o $(BIN)/rfw_random.o $(BIN)/rfw_timer.o 20 | rm $(BIN)/rfw_random.o $(BIN)/rfw_timer.o $(BIN)/steiner.o 21 | 22 | clean: 23 | rm -f $(BIN)/* 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Algorithm for Steiner Problem in Graphs 2 | 3 | Copyright (c) Microsoft Corporation, Thomas Pajor, Eduardo Uchoa, Renato F. Werneck 4 | 5 | All rights reserved. 6 | 7 | MIT License 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 13 | -------------------------------------------------------------------------------- /src/steiner.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | // steiner.cpp : Defines the entry point for the console application. 17 | 18 | #include 19 | #include 20 | #include "spgsolver.h" 21 | 22 | int main (int argc, char **argv) { 23 | SPGSolver::Solve(argc, argv); 24 | return 0; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/targetver.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | #pragma once 17 | 18 | // Including SDKDDKVer.h defines the highest available Windows platform. 19 | 20 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 21 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 22 | 23 | #include 24 | -------------------------------------------------------------------------------- /src/rfw_random.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | #include "rfw_random.h" 16 | 17 | const unsigned long int RFWRandom::maxvalue = (unsigned long int)0xffffffff;// (unsigned long int)(-1); 18 | 19 | const unsigned long int RFWRandom::MATRIX_A = 0x9908b0dfUL; /* constant vector a */ 20 | const unsigned long int RFWRandom::UPPER_MASK = 0x80000000UL; /* most significant w-r bits */ 21 | const unsigned long int RFWRandom::LOWER_MASK = 0x7fffffffUL; /* least significant r bits */ 22 | 23 | unsigned long RFWRandom::mt[N]; /* the array for the state vector */ 24 | int RFWRandom::mti=N+1; /* mti==N+1 means mt[N] is not initialized */ 25 | 26 | -------------------------------------------------------------------------------- /src/execution_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | 22 | #include "graph.h" 23 | #include "rfw_timer.h" 24 | #include "solution.h" 25 | #include "graph.h" 26 | 27 | class ExecutionLog { 28 | 29 | public: 30 | 31 | ExecutionLog(Graph *g, RFWTimer *t, double tl) : timerPtr(t), bestSolution(g), timeLimit(tl) {} 32 | 33 | typedef pair EntryType; 34 | 35 | inline void AddSolution(SteinerSolution &sol) { 36 | // Obey the time limit. 37 | if (timeLimit > 0 && timerPtr->getTime() > timeLimit) 38 | return; 39 | 40 | #pragma omp critical (exec_log) 41 | { 42 | if (solCost.empty()) { 43 | solCost.push_back(EntryType(sol.GetCost(), timerPtr->getTime())); 44 | bestSolution.CopyFrom(&sol); 45 | } 46 | else { 47 | if (solCost.back().first > sol.GetCost() + EDGE_COST_PRECISION) { 48 | solCost.push_back(EntryType(sol.GetCost(), timerPtr->getTime())); 49 | bestSolution.CopyFrom(&sol); 50 | } 51 | } 52 | } 53 | } 54 | 55 | // These are the cost and running times for each incumbent solution. 56 | vector solCost; 57 | 58 | // Pointer to a "global" timer. 59 | RFWTimer *timerPtr = nullptr; 60 | 61 | // Everything is awesome. 62 | SteinerSolution bestSolution; 63 | const double timeLimit; 64 | 65 | }; -------------------------------------------------------------------------------- /src/rfw_stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | /*------------------------------------------------------- 17 | | RFWStack: stack of elements of type T. Upper bound 18 | | n on maximum size must be known in advance. 19 | | Initialization done in O(n) time, all other 20 | | operations in constant time. 21 | | 22 | | author: Microsoft Corporation 23 | *------------------------------------------------------*/ 24 | 25 | #ifndef RFW_STACK_H 26 | #define RFW_STACK_H 27 | #include 28 | 29 | template class RFWStack { 30 | private: 31 | T *stack; 32 | int top, size; 33 | 34 | public: 35 | inline bool isFull() {return (top==size);} 36 | 37 | inline void push (T i) { 38 | if (debug) assert (top0 && p<=top); 58 | return (stack[p]); 59 | } 60 | 61 | RFWStack (int s) { 62 | if (debug) assert (s>0); 63 | top = 0; 64 | size = s; 65 | stack = new T [size+1]; 66 | }; 67 | 68 | inline void reset() {top = 0;} 69 | 70 | ~RFWStack () {delete [] stack;}; 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/simplequeue.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | #pragma once 17 | 18 | /// Trivial queue used for BFS-like applications. May store elements from 19 | /// 0 to maxid, and supports no more than maxid insertions (it does not 20 | /// wrap-up). 21 | 22 | #include 23 | #include 24 | 25 | class SimpleQueue { 26 | private: 27 | int maxid; 28 | int nextins; //position of next insertion 29 | int nextrem; //position of next removal 30 | int *queue; 31 | 32 | void fatal (const string &msg) { 33 | fprintf (stderr, "ERROR::SimpleQueue: %s.\n", msg.c_str()); 34 | exit(-1); 35 | } 36 | 37 | public: 38 | /// Create queue with of a given max size. 39 | SimpleQueue(int _maxid) { 40 | maxid = _maxid; 41 | queue = new int [maxid+1]; 42 | Reset(); 43 | } 44 | 45 | ~SimpleQueue() {delete [] queue;} 46 | 47 | inline void Reset() { 48 | nextins = 0; 49 | nextrem = 0; 50 | } 51 | 52 | inline int Count() const { 53 | return (nextins - nextrem); 54 | } 55 | 56 | inline void Insert (int x) { 57 | if (nextins > maxid) fatal ("insertion limit exceeded"); 58 | queue[nextins++] = x; 59 | } 60 | 61 | inline bool IsEmpty() const { 62 | return (nextrem >= nextins); 63 | } 64 | 65 | inline int Remove() { 66 | if (IsEmpty()) fatal ("cannot remove from empty queue"); 67 | return queue[nextrem++]; 68 | } 69 | 70 | inline void Output() { 71 | fprintf (stderr, "Queue: ["); 72 | for (int i=nextrem; i 18 | #include 19 | #include "uset.h" 20 | #include "graph.h" 21 | #include "simplequeue.h" 22 | 23 | class DualAscentData { 24 | int hidden_vertex; //vertex we'll pretend is not in the graph (useful for strong branching) 25 | 26 | public: 27 | Graph *g; 28 | UniverseSet *rlist; 29 | SimpleQueue *queue; 30 | UniverseSet *component; 31 | EdgeCost *rcost; 32 | EdgeCost *dist_from_root; 33 | EdgeCost *dist_to_terminal; 34 | int *unsatlist; // 35 | int *unsattails; //tails of unsatlist (we could just ask the graph, but keeping an explicit list improves locality) 36 | int unsatcount; // 37 | 38 | 39 | bool *delarc; //delarc[a] is true iff there if (directed) *ARC* can be deleted 40 | int deledgecount; 41 | int n; 42 | int m; 43 | EdgeCost dualcost; //total dual cost of the current solution 44 | int root; 45 | 46 | inline bool IsHidden(int v) {return (v ==hidden_vertex);} 47 | inline void Hide(int v) {hidden_vertex = v;} 48 | inline void UnhideVertices() {hidden_vertex = 0;} 49 | 50 | DualAscentData (Graph *_g) { 51 | //fprintf (stderr, "Initializing ascent data.\n"); 52 | g = _g; 53 | n = g->VertexCount(); 54 | m = g->EdgeCount(); 55 | rlist = new UniverseSet(n); 56 | queue = new SimpleQueue(n); 57 | component = new UniverseSet(n); 58 | rcost = new EdgeCost [2*m+1]; 59 | delarc = new bool [2*m+1]; 60 | unsatlist = new int [2*m]; 61 | unsattails = new int [2*m]; 62 | unsatcount = 0; 63 | deledgecount = 0; 64 | UnhideVertices(); 65 | 66 | dist_from_root = new EdgeCost [n+1]; 67 | dist_to_terminal = new EdgeCost [n+1]; 68 | 69 | 70 | ResetReducedCosts(); 71 | for (int e=0; e<=2*m; e++) {delarc[e] = false;} 72 | dualcost = 0; 73 | } 74 | 75 | /* 76 | bool IsArcDeleted (SPGArc *a) const { 77 | return deledge[a->label]; 78 | }*/ 79 | 80 | ~DualAscentData() { 81 | delete [] dist_to_terminal; 82 | delete [] dist_from_root; 83 | delete [] unsatlist; 84 | delete [] unsattails; 85 | delete [] delarc; 86 | delete [] rcost; 87 | delete component; 88 | delete queue; 89 | delete rlist; 90 | } 91 | 92 | 93 | // for 94 | void ResetReducedCosts() { 95 | for (int v=1; v<=n; v++) { 96 | SPGArc *a, *end; 97 | //for (int pa=g.GetStart(v); paGetBounds(v,a,end); aGetOutgoingLabel(v,a); 103 | rcost[alabel] = a->cost; 104 | } 105 | } 106 | } 107 | }; 108 | -------------------------------------------------------------------------------- /src/buckets.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | /// 21 | /// StaticBuckets: maps elements (0...maxid) to buckets (0...nbuckets) 22 | /// Once in a bucket, an element cannot be moved or deleted. 23 | /// And it's impossible to know which bucket an element belongs to. 24 | /// 25 | class StaticBuckets { 26 | private: 27 | int maxid; //universe is 0...maxid 28 | int maxbucket; //buckets 0...maxbucket 29 | 30 | int *next; //next[v]: successor of v in its list (-2:none, -1:end of list) 31 | int *first; //first[b]: first element in b's bucket (-1: none) 32 | 33 | void fatal (const string &msg) { 34 | fprintf (stderr, "StaticBuckets::Error: %s.\n", msg.c_str()); 35 | exit(-1); 36 | } 37 | 38 | public: 39 | void Reset() { 40 | int i; 41 | for (i = 0; i <= maxid; i++) next[i] = -2; //element is no list 42 | for (i = 0; i <= maxbucket; i++) first[i] = -1; //all buckets empty 43 | } 44 | 45 | void CheckEmpty() { 46 | fprintf (stderr, "Checking if StaticBuckets is empty... "); 47 | int i; 48 | for (i=0; i<=maxid; i++) if (next[i] != -2) fatal ("StaticBuckets.next has wrong value"); 49 | for (i=0; i<=maxbucket; i++) if (first[i] != -1) fatal ("StaticBuckets.first has wrong value"); 50 | fprintf (stderr, "done.\n"); 51 | } 52 | 53 | inline bool IsEmpty(int b) { return (first[b] == -1); } 54 | 55 | StaticBuckets (int _maxid, int _maxbucket) { 56 | maxid = _maxid; 57 | maxbucket = _maxbucket; 58 | 59 | next = new int[maxid + 1]; 60 | first = new int[maxbucket + 1]; 61 | 62 | Reset(); 63 | } 64 | 65 | ~StaticBuckets() { 66 | delete [] next; 67 | delete [] first; 68 | } 69 | 70 | void Reset(int b) { 71 | int i = first[b]; 72 | if (i > -1) { 73 | do { 74 | int j = next[i]; 75 | next[i] = -2; 76 | i = j; 77 | } while (i > 0); 78 | } 79 | first[b] = -1; 80 | } 81 | 82 | /// 83 | /// Insert an element into a bucket. Element must not be in any bucket already. 84 | /// 85 | /// the element 86 | /// the bucket 87 | void Insert(int e, int b) { 88 | if (next[e] >= -1) fatal ("Elements cannot be reassigned."); 89 | next[e] = first[b]; 90 | first[b] = e; 91 | } 92 | 93 | /// 94 | /// Enumerate all elements in bucket b. 95 | /// 96 | /// the bucket 97 | /// 98 | 99 | /* 100 | void GetBounds (int b, int &p, int &pend) { 101 | 102 | }*/ 103 | 104 | inline int GetFirst(int b) {return first[b];} 105 | inline int GetNext(int e) {return next[e];} 106 | 107 | /* 108 | public IEnumerable ElementEnumerator(int b) { 109 | for (int e = first[b]; e >= 0; e = next[e]) { yield return e; } 110 | }*/ 111 | }; 112 | -------------------------------------------------------------------------------- /src/rfw_timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | /********************************************************** 17 | * 18 | * RFWTimer 19 | * - measures running time in second 20 | * - supports four different facilities (clock, rusage, htime, hrtimer) 21 | * - define RFW_USAGE, RFW_CLOCK, RFW_HTIME, RFW_HRTIMER 22 | * - if none is the defined, a very crude heuristic is used 23 | * to determine which one is to be used; don't rely on 24 | * it too much 25 | **********************************************************/ 26 | 27 | #pragma once 28 | 29 | //----------------------------------------------------- 30 | // heuristic to determine which timing facility to use 31 | //----------------------------------------------------- 32 | #ifndef RFW_RUSAGE 33 | #ifndef RFW_CLOCK 34 | #ifndef RFW_HTIME 35 | #ifndef RFW_HRTIMER 36 | #ifndef RFW_STL 37 | 38 | #ifdef _MSC_VER 39 | #define RFW_HRTIMER 40 | #else 41 | #define RFW_CLOCK 42 | #endif 43 | 44 | #endif 45 | #endif 46 | #endif 47 | #endif 48 | #endif 49 | 50 | #ifdef RFW_HRTIMER 51 | #include 52 | #undef min 53 | #undef max 54 | #endif 55 | 56 | 57 | #ifdef RFW_RUSAGE 58 | #include 59 | #include 60 | #endif 61 | 62 | #ifdef RFW_HTIME 63 | #include 64 | #endif 65 | 66 | #ifdef RFW_CLOCK 67 | #include 68 | #include 69 | #endif 70 | 71 | #ifdef RFW_STL 72 | #include 73 | #endif 74 | 75 | //------------------ 76 | // the class itself 77 | //------------------ 78 | class RFWTimer { 79 | private: 80 | bool running; //is it running now? (false -> paused) 81 | double base_time; //time of previous runs since last reset 82 | double max_time; //reference time 83 | 84 | #ifdef RFW_CLOCK 85 | double getUserTime(); 86 | double start_time; 87 | #endif 88 | 89 | #ifdef RFW_HRTIMER 90 | typedef struct { 91 | LARGE_INTEGER start; 92 | LARGE_INTEGER stop; 93 | } stopWatch; 94 | stopWatch timer; 95 | double frequency; 96 | //LARGE_INTEGER frequency; 97 | #endif 98 | 99 | #ifdef RFW_HTIME 100 | long start_time, end_time; 101 | #endif 102 | 103 | #ifdef RFW_RUSAGE 104 | struct rusage ru; 105 | struct timeval start_time, end_time, sample_time; 106 | #endif 107 | 108 | #ifdef RFW_CHRONO 109 | // Wall clock 110 | std::chrono::high_resolution_clock::time_point start_time; 111 | #endif 112 | 113 | void setBaseTime (double bt); 114 | 115 | //facility-dependent functions 116 | double getElapsedTime(); //time since last resume/start 117 | void startTiming(); //store time for future comparison 118 | void init(); 119 | 120 | public: 121 | //basic functions 122 | RFWTimer (bool start=false); 123 | double getTime(); //return current time 124 | double pause(); //pause and return current time 125 | double resume(); //continue if paused, start if reset; return time before resuming 126 | double start(); //reset and resume; return time before reset 127 | double reset(); //reset timer and pause (at zero); return time before reset 128 | 129 | //auxiliary functions 130 | void setMaxTime (double mt); 131 | double getMaxTime(); 132 | double getTimeToExpire(); 133 | bool isTimeExpired (); 134 | }; 135 | -------------------------------------------------------------------------------- /src/constructive.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "binheap.h" 12 | #include "graph.h" 13 | #include "solution.h" 14 | #include "rfw_timer.h" 15 | #include "LSBasics.h" 16 | 17 | /* 18 | #include "uf.h" 19 | #include "uset.h" 20 | #include "voronoi.h" 21 | #include "rfw_random.h" 22 | #include "rfw_stack.h" 23 | #include "drawer.h" 24 | #include "dual.h" 25 | #include "stedgelinear.h" 26 | #include "pairheap.h" 27 | #include "buckets.h" 28 | #include 29 | #include 30 | #include "elite.h" 31 | #include "spgconfig.h" 32 | #include 33 | #include "execution_log.h" 34 | #include "LSVertexInsertion.h" 35 | #include "LSVertexElimination.h" 36 | #include "LSBasics.h" 37 | #include "LSKeyPath.h" 38 | #include "BranchBound.h" 39 | */ 40 | 41 | class ConstructiveAlgorithms { 42 | private: 43 | static void fatal (const string &msg) { 44 | Basics::fatal(msg); 45 | } 46 | 47 | 48 | public: 49 | static void SPH (Graph &g, SteinerSolution &solution, EdgeCost *pertcost, int root) { 50 | const bool verbose = false; 51 | unsigned int v; 52 | int n = g.VertexCount(); 53 | int m = g.EdgeCount(); 54 | 55 | static bool PATH_ERROR = false; 56 | 57 | if (verbose) fprintf (stderr, "Running SPH from %d... ", root); 58 | 59 | BinaryHeap heap(n); //vertices to scan 60 | vector parc(n+1,-1); //parent arc 61 | vector dist(n+1,-1); //current distance 62 | 63 | solution.Reset(); 64 | heap.Insert(root, 0); 65 | dist[root] = 0; //root already in the tree, but no parent edge 66 | parc[root] = 0; //already in the tree 67 | 68 | int nterm = g.TerminalCount(); 69 | int tcount = 0; 70 | if (g.IsTerminal(root)) tcount ++; 71 | 72 | //int scancount = 0; 73 | //int inscount = 1; 74 | //int pathsum = 0; 75 | 76 | //while (!heap.IsEmpty()) { 77 | while (tcount < nterm) { 78 | if (verbose) {fprintf (stderr, "Here."); fflush(stderr);} 79 | if (heap.IsEmpty()) { 80 | for (int x=1; x<=n; x++) { 81 | if (dist[x] < 0) fprintf (stderr, "Vertex %d has distance %d.\n", x, dist[x]); 82 | } 83 | fatal ("heap is empty"); 84 | } 85 | EdgeCost curcost; 86 | heap.RemoveFirst(v, curcost); //lowest element in the heap 87 | if (verbose) { 88 | fprintf (stderr, "Processing %d with distance %d.\n", v, curcost); 89 | fflush (stderr); 90 | } 91 | if (curcost<0) { 92 | fprintf (stderr, "Vertex %d has negative cost (%d)", v, curcost); 93 | fatal ("invalid heap entry"); 94 | } 95 | 96 | //found a terminal: add incoming path to the solution, 97 | //reinsert its vertices into the heap with zero distance 98 | if (g.IsTerminal(v) && (parc[v]>0)) { 99 | int curpath = 0; 100 | if (verbose) fprintf (stderr, "Adding terminal %d.\n", v); 101 | //fflush(stderr); 102 | tcount ++; 103 | int w = v; 104 | EdgeCost addedcost = 0; 105 | do { 106 | int e = parc[w]; 107 | //if (e <= 0) break; 108 | curpath ++; 109 | if (v!=w) heap.Insert(w, 0); // RECENT CHANGE: NO NEED TO INSERT IF V==W 110 | //else fprintf (stderr, "."); 111 | //inscount ++; 112 | dist[w] = 0; //its distance label is zero 113 | parc[w] = 0; //w now belongs to the tree 114 | if (!solution.Insert(e)) fatal ("failed to add edge"); 115 | EdgeCost acost = (pertcost!=NULL) ? pertcost[e] : g.GetCost(e); 116 | addedcost += acost; 117 | w = g.GetOther(e,w); 118 | } while (parc[w]>0); 119 | if (addedcost != curcost) { 120 | if (!PATH_ERROR) { 121 | fprintf (stderr, "WARNING (SPH): addedcost:%.20lg curcost:%.20lg\n", addedcost, curcost); 122 | PATH_ERROR = true; 123 | } 124 | //fprintf (stderr, "Inconsistent path in SPH."); 125 | } 126 | //pathsum += curpath; 127 | curcost = 0; 128 | } 129 | 130 | if (verbose) fprintf (stderr, "Processing a non-terminal.\n"); 131 | 132 | // scan outgoing arcs, add anything that improves to the solution 133 | //scancount ++; 134 | SPGArc *arc, *end; 135 | for (g.GetBounds(v,arc,end); archead; 137 | if (parc[w]==0) continue; //already in the solution 138 | //if ((w==root) || (solution.GetDegree(w)>0)) continue; //already in solution 139 | EdgeCost acost = (pertcost) ? pertcost[arc->label] : arc->cost; //g.GetCost(arc->label); 140 | EdgeCost newcost = acost + curcost; 141 | 142 | if (newcost < 0) { 143 | fprintf (stderr, "Arc %d + cost %lg led to newcost %lg.", acost, (double)curcost, (double)newcost); 144 | fatal ("Cost overflow."); 145 | } 146 | 147 | if ((newcostlabel; 152 | if (verbose) {fprintf (stderr, "Inserted %d with cost %d.\n", w, newcost); fflush (stderr);} 153 | } 154 | } 155 | if (verbose) {fprintf (stderr, "x"); fflush(stderr);} 156 | } 157 | //fprintf (stderr, "%.3f ", (double)scancount / (double)n); 158 | //fprintf (stderr, "%.3f ", (double)pathsum / (double)tcount); 159 | //fprintf (stderr, "%.3f,%.3f seconds ", (double)inscount / (double)n, timer.getTime()*1000); 160 | if (verbose) fprintf (stderr, "Found solution %d ", solution.GetCost()); 161 | } 162 | 163 | 164 | }; 165 | 166 | 167 | -------------------------------------------------------------------------------- /src/rfw_timer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | /************************************* 17 | * 18 | * RFWTimer (used for time measured) 19 | * 20 | *************************************/ 21 | 22 | #include "rfw_timer.h" 23 | 24 | #define INFINITE_TIME 10e100 25 | 26 | /******************** 27 | * Generic functions 28 | ********************/ 29 | 30 | RFWTimer::RFWTimer (bool s) { 31 | init(); 32 | base_time = 0.0; 33 | max_time = 0.0; 34 | if (s) start(); 35 | else running = false; 36 | } 37 | 38 | double RFWTimer::getTime() { 39 | if (running) return (getElapsedTime() + base_time); 40 | else return base_time; 41 | } 42 | 43 | double RFWTimer::start() { 44 | double current = getTime(); 45 | base_time = 0.0; 46 | startTiming(); 47 | running = true; 48 | return current; 49 | } 50 | 51 | void RFWTimer::setMaxTime (double mt) {max_time = mt;} 52 | double RFWTimer::getMaxTime () {return max_time;} 53 | 54 | bool RFWTimer::isTimeExpired () { 55 | if (getMaxTime() == 0) return false; 56 | bool time_expired = (getTime() >= getMaxTime()); 57 | return time_expired; 58 | } 59 | 60 | double RFWTimer::getTimeToExpire () { //may be negative! 61 | if (getMaxTime() == 0) return INFINITE_TIME; 62 | else return (getTime() - getMaxTime()); 63 | } 64 | 65 | void RFWTimer::setBaseTime (double bt) {base_time = bt;} 66 | 67 | double RFWTimer::reset() { 68 | double current = getTime(); 69 | running = false; 70 | base_time = 0.0; 71 | return current; 72 | } 73 | 74 | double RFWTimer::pause() { 75 | base_time = getTime(); 76 | running = false; 77 | return base_time; 78 | } 79 | 80 | double RFWTimer::resume() { 81 | if (running) return getTime(); 82 | else { 83 | running = true; 84 | startTiming(); 85 | return base_time; 86 | } 87 | } 88 | 89 | //------------ 90 | // RFW_RUSAGE 91 | //------------ 92 | 93 | #ifdef RFW_RUSAGE 94 | 95 | void RFWTimer::init(){}; 96 | 97 | void RFWTimer::startTiming() { 98 | getrusage(RUSAGE_SELF, &ru); 99 | start_time = ru.ru_utime; 100 | } 101 | 102 | double RFWTimer::getElapsedTime() { 103 | double t; 104 | getrusage(RUSAGE_SELF, &ru); 105 | end_time = ru.ru_utime; 106 | if (end_time.tv_usec < start_time.tv_usec){ 107 | end_time.tv_usec += 1000000; 108 | end_time.tv_sec -= 1; 109 | } 110 | t = 100.0*(double)(end_time.tv_sec - start_time.tv_sec) + (double)(end_time.tv_usec - start_time.tv_usec) / (double)10000.0; 111 | return ((double)t/(double)100); 112 | } 113 | 114 | #endif 115 | 116 | 117 | //----------- 118 | // RFW_CLOCK 119 | //----------- 120 | 121 | #ifdef RFW_CLOCK 122 | 123 | void RFWTimer::init(){}; 124 | 125 | void RFWTimer::startTiming() {start_time = getUserTime();} 126 | 127 | double RFWTimer::getElapsedTime() { 128 | return (getUserTime() - start_time); 129 | } 130 | 131 | double RFWTimer::getUserTime() { 132 | double msecs = (double) clock() / CLOCKS_PER_SEC; 133 | if (msecs > 0) return msecs; 134 | else return 0.0; //sometimes msecs is -0.000 (go figure...) 135 | } 136 | 137 | #endif 138 | 139 | 140 | /************* 141 | *RFW_HTIME 142 | *************/ 143 | 144 | #ifdef RFW_HTIME 145 | 146 | void RFWTimer::init() {}; 147 | 148 | void RFWTimer::startTiming() {start_time = (long)gethrvtime();} 149 | 150 | double RFWTimer::getElapsedTime() { 151 | return (double)(gethrvtime()-start_time)/(double)10e8; 152 | } 153 | 154 | #endif 155 | 156 | 157 | #ifdef RFW_HRTIMER 158 | 159 | void RFWTimer::init() { 160 | LARGE_INTEGER f; 161 | QueryPerformanceFrequency(&f) ; 162 | frequency = (double)f.QuadPart; 163 | } 164 | 165 | void RFWTimer::startTiming() { 166 | QueryPerformanceCounter(&timer.start); 167 | } 168 | 169 | double RFWTimer::getElapsedTime() { 170 | QueryPerformanceCounter(&timer.stop); 171 | /* 172 | LARGE_INTEGER time; 173 | time.QuadPart = timer.stop.QuadPart - timer.start.QuadPart;*/ 174 | //LARGE_INTEGER frequency; 175 | //QueryPerformanceFrequency(&frequency) ; 176 | //return ((double)time.QuadPart / (double)frequency.QuadPart); 177 | return ((double)(timer.stop.QuadPart - timer.start.QuadPart) / frequency); 178 | } 179 | 180 | #endif 181 | 182 | 183 | /************* 184 | *RFW_CHRONO 185 | *************/ 186 | 187 | #ifdef RFW_CHRONO 188 | 189 | void RFWTimer::init() {}; 190 | 191 | void RFWTimer::startTiming() { start_time = std::chrono::high_resolution_clock::now(); } 192 | 193 | double RFWTimer::getElapsedTime() { 194 | std::chrono::duration elapsed = std::chrono::high_resolution_clock::now() - start_time; 195 | return elapsed.count(); 196 | } 197 | 198 | #endif -------------------------------------------------------------------------------- /src/uset.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | //#ifndef UNIVERSESET_H 17 | //#define UNIVERSESET_H 18 | //#include "rfw_random.h" 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | 26 | class UniverseSet { 27 | private: 28 | int *perm; 29 | int *pos; //pos[v]: position of element v 30 | int maxid; //maximum allowed identifier 31 | int nextpos; //position of next insertion 32 | int nil; 33 | 34 | 35 | /// 36 | /// Swap element in position pi into position nextpos. 37 | /// 38 | /// current element position 39 | void MakeNext(int pi) { 40 | int i = perm[pi]; //element originally in position i 41 | int j = perm[nextpos]; //element originally in nextpos 42 | 43 | //i goes to nextpos 44 | perm[nextpos] = i; 45 | pos[i] = nextpos; 46 | 47 | //j goes to pi 48 | perm[pi] = j; 49 | pos[j] = pi; 50 | } 51 | 52 | void fatal (const string &msg) { 53 | fprintf (stderr, "%s\n", msg.c_str()); 54 | exit(-1); 55 | } 56 | 57 | void die (const string &msg) { 58 | fprintf(stderr, "(UniverseSet): %s.\n", msg.c_str()); 59 | fatal(msg); 60 | } 61 | 62 | 63 | public: 64 | /// 65 | /// Create a set representing elements 0...n. 66 | /// 67 | /// 68 | UniverseSet (int _maxid) { 69 | maxid = _maxid; 70 | nil = maxid + 1; 71 | perm = new int [_maxid+1]; 72 | pos = new int [_maxid+1]; 73 | HardReset(); 74 | } 75 | 76 | 77 | /* 78 | void Permute(OptRandom random) { 79 | for (int i=nextpos-1; i>0; i--) { 80 | int j = random.GetInteger(0, i); 81 | 82 | int t = perm[i]; 83 | perm[i] = perm[j]; 84 | perm[j] = t; 85 | 86 | pos[perm[i]] = i; 87 | pos[perm[j]] = j; 88 | } 89 | }*/ 90 | 91 | inline int PickAny() { 92 | if (IsEmpty()) die ("Cannot pick element from an empty set."); 93 | return (perm[0]); 94 | } 95 | 96 | /// 97 | /// Empty the set. 98 | /// 99 | void HardReset() 100 | { 101 | //Console.WriteLine("Resetting...\n"); 102 | for (int i=0; i<=maxid; i++) { 103 | pos[i] = i; 104 | perm[i] = i; 105 | } 106 | nextpos = 0; 107 | } 108 | 109 | void Reset() { 110 | while (!IsEmpty()) {Remove(perm[0]);} 111 | } 112 | 113 | 114 | inline bool Contains(int i) const {return (pos[i]= nextpos) return false; 128 | nextpos--; 129 | MakeNext(pi); 130 | return true; 131 | } 132 | 133 | 134 | /* 135 | int PickRandom(RFWLocalRandom &r) { 136 | if (IsEmpty()) die("Cannot pick element from an empty set."); 137 | return (perm[r.getInteger(0,nextpos-1)]); 138 | } 139 | 140 | int PickRandom() { 141 | if (IsEmpty()) die("Cannot pick element from an empty set."); 142 | return (perm[RFWRandom::getInteger(0,nextpos-1)]); 143 | }*/ 144 | 145 | inline int Count() {return (nextpos);} 146 | 147 | inline int MaxId() {return maxid;} 148 | 149 | inline void Copy(UniverseSet *s) { 150 | if (s->MaxId() != MaxId()) die("Cannot copy from incompatible set"); 151 | 152 | Reset(); //make this set empty 153 | Unite(s); //take the union with the other set 154 | 155 | /* 156 | int i, end; 157 | for (s->GetBounds(i, end); iPickPos(i); 159 | 160 | //foreach (int v in s.ElementEnumerator()) { 161 | Insert(v); 162 | }*/ 163 | } 164 | 165 | inline void Unite (UniverseSet *s) { 166 | if (s->MaxId() > MaxId()) die ("Cannot unite potentially larger set.\n"); 167 | int i, end; 168 | for (s->GetBounds(i,end); iPickPos(i)); 170 | } 171 | 172 | } 173 | 174 | inline void GetBounds(int &start, int &end) { 175 | start = 0; 176 | end = nextpos; 177 | } 178 | 179 | inline int PickPos(int p) { 180 | if (p<0 || p>nextpos) die ("picking from invalid position"); 181 | return perm[p]; 182 | } 183 | 184 | 185 | 186 | void Output() { 187 | int i, end; 188 | for (i=0; i<=maxid; i++) { 189 | if (Contains(i)) fprintf (stderr, "#"); 190 | else fprintf (stderr, "_"); 191 | } 192 | for (GetBounds(i,end); i 20 | 21 | class SolutionPool { 22 | private: 23 | vector sol; 24 | int count; //number of solutions currently in the pool 25 | int capacity; //capacity of the pool 26 | SteinerConfig *config; 27 | 28 | 29 | public: 30 | SolutionPool(int cap) { 31 | capacity = cap; 32 | sol.resize(cap+1); 33 | //sol = new Solution[capacity + 1]; 34 | for (int i = 0; i <= cap; i++) sol[i] = NULL; 35 | count = 0; 36 | } 37 | 38 | inline int GetCapacity() { 39 | return capacity; 40 | } 41 | 42 | inline int GetCount() { 43 | return count; 44 | } 45 | 46 | 47 | 48 | /// 49 | /// Tries adding a solution to the pool. Returns its new position if successful, 50 | /// and zero if the solution is not added. 51 | /// 52 | /// 53 | /// 54 | int Add(SteinerSolution *s) { 55 | bool verbose = false; 56 | const bool VERBOSE_DIFF = false; 57 | 58 | double bestdiff = 0; 59 | 60 | RFWLocalRandom random; 61 | //OptRandom random = new OptRandom(); 62 | 63 | if (verbose) fprintf(stderr, "Adding solution.\n"); 64 | bool present = false; //is the solution already in the pool 65 | int wcount = 0; //number of solutions worse than s 66 | int bestpos = 0; 67 | bool DETERMINISTIC = false; 68 | bool SQUARE_SCORE = true; 69 | double accscore = 0; 70 | 71 | for (int i = 1; i <= count; i++) { 72 | //any solution that is equal or worse than s is a candidate for removal 73 | if (!sol[i]->IsBetter(s)) { 74 | double diff = s->GetDifference(sol[i]); //1 - inter/union (of edges) 75 | if (diff == 0) { 76 | present = true; 77 | break; 78 | } 79 | if (VERBOSE_DIFF) fprintf (stderr, " %.3f:%.0f", diff, sol[i]->GetCost()); 80 | 81 | wcount ++; 82 | 83 | if (DETERMINISTIC) { 84 | //Console.Error.Write("[{0}] ", diff); 85 | if (bestpos == 0 || diff < bestdiff) { 86 | bestpos = i; 87 | bestdiff = diff; 88 | } else { 89 | if (diff == bestdiff) { 90 | fprintf (stderr, "%.2f ", diff); 91 | } 92 | } 93 | } else { 94 | double curscore = 1.0 / (double)diff; //(sol[i].GetValue() - s.GetValue()); 95 | if (SQUARE_SCORE) {curscore *= curscore;} 96 | accscore += curscore; 97 | if (bestpos == 0 || (random.GetDouble() * accscore < curscore)) { 98 | if (VERBOSE_DIFF) fprintf (stderr, "<<<"); 99 | bestpos = i; 100 | bestdiff = diff; 101 | } 102 | } 103 | } 104 | } 105 | 106 | if (VERBOSE_DIFF) fprintf (stderr, "\n"); 107 | 108 | //solution is already there 109 | if (present) return 0; 110 | 111 | if (verbose) fprintf (stderr, "count%d:cap%d ", count, capacity); 112 | 113 | //pool is full and nobody is worse 114 | if (count == capacity) { //full pool? 115 | if (wcount == 0) return 0; //nobody worse 116 | } else { //there's still space 117 | count++; //add one more element in the last position 118 | bestpos = count; 119 | } 120 | 121 | if (verbose) { 122 | fprintf (stderr, "+"); 123 | fprintf (stderr, "Adding to position %d.\n", bestpos); 124 | } 125 | 126 | if (sol[bestpos] == NULL) { 127 | sol[bestpos] = new SteinerSolution(s); //(Solution)s.Clone(); 128 | } else { 129 | if (verbose) fprintf (stderr, "Replacing %d by %d difference is %.4f, out of %d candidates.", sol[bestpos]->GetCost(), s->GetCost(), bestdiff, wcount); 130 | sol[bestpos]->CopyFrom(s); 131 | } 132 | return bestpos; 133 | } 134 | 135 | void Pick(int i, SteinerSolution *s) { 136 | //if (i <= 0 || i > count) throw new Exception("Invalid solution found"); 137 | s->CopyFrom(sol[i]); 138 | } 139 | 140 | SteinerSolution *GetReference(int i) { 141 | return sol[i]; 142 | } 143 | 144 | int FindBestPosition () { 145 | fprintf (stderr, "Here I am (%d,%d)!\n", count, GetCount()); 146 | fflush(stderr); 147 | 148 | if (count == 0) return -1; 149 | int best = 1; 150 | for (int i=2; i<=count; i++) { 151 | fprintf (stderr, "%d ", i); 152 | fflush(stderr); 153 | if (sol[i] == NULL) exit(-1); 154 | if (sol[i]->GetCost() < sol[best]->GetCost()) best = i; 155 | } 156 | 157 | fprintf (stderr, "Returning %d.\n", best); 158 | fflush(stderr); 159 | 160 | return best; 161 | } 162 | 163 | EdgeCost FindBestCost() { 164 | if (count == 0) return numeric_limits::max(); 165 | else return sol[FindBestPosition()]->GetCost(); 166 | } 167 | 168 | void Output(FILE *file, int columns) { 169 | for (int i=1; i<=count; i++) { 170 | int column = (i-1) % columns; 171 | if (column == 0) { 172 | if (i > 1) fprintf (file, "\n"); 173 | fprintf (file, "%5d :", i); 174 | } 175 | fprintf (stderr, " %6lg", sol[i] ? (double)sol[i]->GetCost() : -1.0); 176 | } 177 | fprintf (stderr, "\n"); 178 | } 179 | 180 | 181 | void Reset() { count = 0; } 182 | 183 | void HardReset() { 184 | for (int i=0; i<=capacity; i++) { 185 | if (sol[i]) { 186 | delete sol[i]; 187 | sol[i] = NULL; 188 | } 189 | } 190 | count = 0; 191 | } 192 | 193 | int Capacity() { return capacity; } 194 | int Count() { return count; } 195 | 196 | ~SolutionPool() { 197 | for (int i=0; i<=capacity; i++) { 198 | if (sol[i]) delete sol[i]; 199 | } 200 | } 201 | }; -------------------------------------------------------------------------------- /src/drawer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include "graph.h" 20 | #include 21 | 22 | class GraphDrawer { 23 | private: 24 | static void fatal (const string &msg) { 25 | fprintf (stderr, "GraphDrawer::ERROR: %s.\n", msg.c_str()); 26 | exit(-1); 27 | } 28 | 29 | typedef enum {GDE_STANDARD, GDE_SOLUTION, GDE_DELETED} EdgeType; 30 | typedef enum {GDV_STANDARD, GDV_DELETED} VertexType; 31 | 32 | 33 | static void OutputHeader(FILE *file) { 34 | 35 | 36 | fprintf (file, "add style vertex #vertex\n"); 37 | fprintf (file, "set style vertex #size 1\n"); 38 | fprintf (file, "set style vertex #shape 0\n"); 39 | fprintf (file, "set style vertex #color_r 0.5\n"); 40 | fprintf (file, "set style vertex #color_g 0.5\n"); 41 | fprintf (file, "set style vertex #color_b 0.5\n"); 42 | fprintf (file, "set style vertex #label_height 1\n"); 43 | fprintf (file, "set style vertex #label_font Helvetica\n"); 44 | fprintf (file, "add style delvertex vertex\n"); 45 | fprintf (file, "set style delvertex #color_r 0.9\n"); 46 | fprintf (file, "set style delvertex #color_g 0.9\n"); 47 | fprintf (file, "set style delvertex #color_b 0.9\n"); 48 | fprintf (file, "proxy vertex #label #name string\n"); 49 | fprintf (file, "add style terminal vertex\n"); 50 | fprintf (file, "set style terminal #size 2\n"); 51 | fprintf (file, "set style terminal #shape 1\n"); 52 | fprintf (file, "add style edge #edge\n"); 53 | fprintf (file, "set style edge #width 0.25\n"); 54 | fprintf (file, "set style edge #color_r 0.75\n"); 55 | fprintf (file, "set style edge #color_g 0.75\n"); 56 | fprintf (file, "set style edge #color_b 0.75\n"); 57 | } 58 | 59 | template static double FindScalingFactor(GRAPH &g,vector &etype) { 60 | fprintf (stderr, "Finding scaling factor.\n"); 61 | 62 | vector lengths; 63 | 64 | int m = g.EdgeCount(); 65 | for (int e=1; e<=m; e++) { 66 | if (etype[e]==GDE_DELETED) continue; 67 | int v,w; 68 | g.GetEndpoints(e,v,w); 69 | 70 | double vx,vy,wx,wy; 71 | g.coord.GetCoordinates(v,vx,vy); 72 | g.coord.GetCoordinates(w,wx,wy); 73 | 74 | //fprintf (stderr, "%.2f %.2f\n", vx, vy); 75 | 76 | double deltax = (wx-vx); 77 | double deltay = (wy-vy); 78 | 79 | double sqdist = deltax*deltax + deltay*deltay; 80 | lengths.push_back(sqdist); 81 | } 82 | 83 | /* 84 | for (int i=0; i static void OutputVertices(FILE *file, GRAPH &g, vector &etype, vector &vtype) { 104 | int n = g.VertexCount(); 105 | double scale = FindScalingFactor(g,etype); 106 | for (int i=0; i<2; i++) { 107 | if (i==0) { 108 | fprintf (file, "use style vertex\n"); 109 | } else { 110 | fprintf (file, "use style terminal\n"); 111 | } 112 | for (int v=1; v<=n; v++) { 113 | if (g.IsTerminal(v) == (i!=0)) { 114 | double x, y; 115 | g.coord.GetCoordinates(v,x,y); 116 | x *= scale; 117 | y *= scale; 118 | if (i==0) { 119 | if (vtype[v] == GDV_DELETED) fprintf (file, "use style delvertex\n"); 120 | else if (vtype[v] == GDV_STANDARD) fprintf (file, "use style vertex\n"); 121 | } 122 | fprintf (file, "add vertex %d %.0f %.0f\n", v, x, y); 123 | } 124 | } 125 | } 126 | } 127 | 128 | template static void OutputEdges(FILE *file, GRAPH &g, vector &edgeinfo) { 129 | int m = g.EdgeCount(); 130 | fprintf (file, "use style edge\n"); 131 | for (int e=1; e<=m; e++) { 132 | if (edgeinfo[e]!=GDE_STANDARD) continue; 133 | int v,w; 134 | g.GetEndpoints(e,v,w); 135 | fprintf (file, "add edge %d %d %d \n", e, v, w); 136 | } 137 | } 138 | 139 | template void MarkAllEdges (GRAPH &g, vector &etype, EdgeType t) { 140 | int m = g.EdgeCount(); 141 | 142 | 143 | } 144 | 145 | public: 146 | 147 | template static void DrawSolution (FILE *file, GRAPH &g, vector &edgeinfo, vector &vinfo) { 148 | OutputHeader(file); 149 | OutputVertices(file,g,edgeinfo,vinfo); 150 | OutputEdges(file,g,edgeinfo); 151 | } 152 | 153 | template static void DrawGraph (char *filename, GRAPH &g) { 154 | FILE *file = fopen (filename, "w"); 155 | if (!file) fatal ("could not open filename for drawing"); 156 | int m = g.EdgeCount(); 157 | int n = g.VertexCount(); 158 | vector etype(m+1,GDE_STANDARD); 159 | vector vtype(n+1,GDV_STANDARD); 160 | DrawSolution (file, g, etype, vtype); 161 | fclose(file); 162 | } 163 | 164 | template static void DrawSubgraph (const string &filename, GRAPH &g, vector &emarked, vector &vkept) { 165 | FILE *file = fopen (filename.c_str(), "w"); 166 | if (!file) fatal ("could not open filename for drawing"); 167 | int m = g.EdgeCount(); 168 | int n = g.VertexCount(); 169 | vector etype(m+1,GDE_STANDARD); 170 | vector vtype(n+1,GDV_STANDARD); 171 | for (int e=1; e<=m; e++) { 172 | if (!emarked[e]) etype[e] = GDE_DELETED; 173 | } 174 | for (int v=1; v<=n; v++) { 175 | if (!vkept[v]) vtype[v] = GDV_DELETED; 176 | } 177 | 178 | DrawSolution (file, g, etype, vtype); 179 | fclose(file); 180 | } 181 | 182 | }; 183 | -------------------------------------------------------------------------------- /src/stedgelinear.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | 21 | /// 22 | /// Linear-time implementation of link-cut trees with costs on edges. 23 | /// 24 | template class STEdgeLinear { 25 | private: 26 | struct Node { 27 | CostType cost; 28 | int parent; 29 | 30 | void SetParentCost(int p, CostType c) { 31 | cost = c; 32 | parent = p; 33 | } 34 | }; 35 | 36 | int n; //maximum item id 37 | int m; //edge count 38 | Node* node; 39 | 40 | void fatal (const string &msg) { 41 | fprintf (stderr, "STEdgeLinear::Error: %s\n", msg.c_str()); 42 | exit(-1); 43 | } 44 | 45 | public: 46 | 47 | STEdgeLinear(int _n) { 48 | n = _n; 49 | node = new Node[n + 1]; 50 | for (int v = 1; v <= n; v++) { 51 | node[v].parent = 0; 52 | } 53 | } 54 | 55 | ~STEdgeLinear() { 56 | delete [] node; 57 | } 58 | 59 | /// 60 | /// Return the root of the tree containing v. 61 | /// 62 | /// Input vertex. 63 | /// 64 | inline int GetRoot(int v) { 65 | const bool verbose = false; 66 | if (verbose) { 67 | int p, count = 0; 68 | while ((p=node[v].parent) != 0) {v = p; ++count;} 69 | if (count>0) fprintf (stderr, "%d ", count); 70 | return v; 71 | 72 | } else { 73 | int p; 74 | while ((p=node[v].parent) != 0) {v = p;} 75 | return v; 76 | } 77 | } 78 | 79 | /// 80 | /// Return the cost of the arc between v and its parent. Throws 81 | /// an exception if v is the root. 82 | /// 83 | /// Input vertex. 84 | /// 85 | inline CostType GetCost(int v) { 86 | if (v == 0) fatal ("Invalid node id."); 87 | if (node[v].parent == 0) fatal("root has no parent edge"); 88 | return node[v].cost; 89 | } 90 | 91 | 92 | /// 93 | /// Return the parent of vertex v (zero if it's a root). 94 | /// 95 | /// Input vertex. 96 | /// 97 | inline int GetParent(int v) const { 98 | return node[v].parent; 99 | } 100 | 101 | 102 | /// 103 | /// Return the id of the bottom vertex of the minimum-cost edge on the path from v to 104 | /// the root. Returns 0 if v is the root. 105 | /// 106 | /// Input vertex. 107 | /// 108 | inline int GetMinCost(int v) { 109 | int w = 0; 110 | CostType mincost = node[v].cost; //could be undefined, don't care 111 | 112 | int p = node[v].parent; 113 | while (p != 0) { 114 | if (node[v].cost <= mincost) { 115 | w = v; 116 | mincost = node[v].cost; 117 | } 118 | v = p; 119 | p = node[v].parent; 120 | } 121 | return w; 122 | } 123 | 124 | /// 125 | /// Increase by 'cost' the cost of all arcs on the path from v to the root. 126 | /// 127 | /// Starting vertex. 128 | /// Amount to increment. 129 | inline void AddCost(int v, CostType cost) { 130 | int p = GetParent(v); 131 | while (p != 0) { 132 | node[v].cost += cost; 133 | v = p; 134 | p = node[v].parent; 135 | } 136 | } 137 | 138 | /// 139 | /// Insert edge (v,w) with cost c. Does nothing if v is not a root, 140 | /// or if v and w are the same component. 141 | /// 142 | /// First endpoint. 143 | /// Second endpoint. 144 | /// Edge cost. 145 | inline void Link(int v, int w, CostType c) { 146 | if (node[v].parent != 0) return; 147 | if (GetRoot(w) == v) return; 148 | m++; //one more edge! 149 | node[v].parent = w; 150 | node[v].cost = c; 151 | } 152 | 153 | /// 154 | /// Cut the edge between v and its parent and returns its cost. 155 | /// Throws an exception if v is a root. 156 | /// 157 | /// Input vertex. 158 | /// Cost of parent edge. 159 | inline CostType cut(int v) { 160 | if (node[v].parent == 0) fatal ("root cannot be cut"); 161 | m--; 162 | node[v].parent = 0; 163 | return node[v].cost; //no need to actually change the cost 164 | } 165 | 166 | /// 167 | /// Reverse the direction of every edge on the path from v to w 168 | /// 169 | /// Starting vertex. 170 | inline void Evert(int v) { 171 | int s = v; //source 172 | 173 | const bool verbose = false; 174 | 175 | CostType curcost = node[v].cost; 176 | int curparent = node[v].parent; 177 | 178 | int ecount = 0; 179 | 180 | while (curparent!=0) { 181 | Node &curnode = node[curparent]; 182 | 183 | /* 184 | CostType nextcost = node[curparent].cost; 185 | int nextparent = node[curparent].parent; 186 | node[curparent].SetParentCost(v,curcost); 187 | */ 188 | CostType nextcost = curnode.cost; 189 | int nextparent = curnode.parent; 190 | curnode.SetParentCost(v,curcost); 191 | 192 | if (verbose) ecount ++; 193 | 194 | v = curparent; 195 | curcost = nextcost; 196 | curparent = nextparent; 197 | } 198 | if (verbose) fprintf (stderr, "%d ", ecount); 199 | node[s].parent = 0; 200 | } 201 | 202 | /// 203 | /// Get number of vertices in the forest. 204 | /// 205 | /// Number of vertices in the forest. 206 | int GetVertexCount() { return n; } 207 | 208 | 209 | /// 210 | /// Find number of edges in the forest. 211 | /// 212 | /// Number of edges in the tree. 213 | int GetEdgeCount() { return m; } 214 | }; -------------------------------------------------------------------------------- /src/perturbation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "spgconfig.h" 3 | 4 | 5 | class Perturbator { 6 | int PERTURBATION_MODE; 7 | double base; 8 | double range; 9 | double threshold; 10 | SteinerConfig *config; 11 | 12 | static void fatal (const string &msg) { 13 | fprintf (stderr, "ERROR: %s.\n", msg.c_str()); 14 | fflush(stderr); 15 | exit(-1); 16 | } 17 | 18 | public: 19 | void SetParameters (int n, SteinerConfig *_config) { 20 | config = _config; 21 | PERTURBATION_MODE = config->PERTURBATION_MODE; 22 | base = config->PERT_FLOOR; 23 | range = config->PERT_RANGE; 24 | threshold = 0; 25 | if (PERTURBATION_MODE == 2) { 26 | threshold = sqrt((double)n) / (double)n; 27 | } else if (PERTURBATION_MODE == 4) { 28 | threshold = sqrt((double)n) / (double)(2*n); 29 | } else { 30 | threshold = (log(n)/log(2)) / (double)n; 31 | } 32 | } 33 | 34 | double GetPerturbation(double r) { 35 | //fprintf(stderr, "r is %.10f, threshold=%.10f\n", r, threshold); 36 | //cerr << r << endl; 37 | switch (PERTURBATION_MODE) { 38 | case 0: return base + r * range; break; //expected value is 1.5 39 | case 1: return base + r + 1/(10.0*r); break; //NOT TRUE EXPECTATION 40 | case 2: return (r >= threshold) ? 1 + range * r : range/r; break; 41 | case 3: return base + range * r*r; break; 42 | case 4: return (r >= threshold) ? 1 + range * r : range/r; break; 43 | case 5: return base + range * (1.0 - r*r); break; 44 | case 6: return base + 1.5 * r * r; break; //expected value is 1.5 45 | case 7: return (r >= threshold) ? 1 + range * r : max(r/threshold, 0.0000001); break; 46 | default: fatal ("invalid perturbation mode"); 47 | } 48 | return 0; 49 | } 50 | 51 | void ResetRange (double r) { 52 | if (config->PERT_EXTRA > 0) { 53 | range = config->PERT_RANGE + config->PERT_EXTRA * r; 54 | } 55 | /* 56 | if (VARIABLE_RANGE) { 57 | if (3*r < 1) range = .25; 58 | else if (3*r > 2) range = 1; 59 | else range = 4; 60 | }*/ 61 | } 62 | }; 63 | 64 | 65 | 66 | class PerturbationTools { 67 | public: 68 | static void fatal (const string &msg) { 69 | fprintf (stderr, "ERROR: %s.\n", msg.c_str()); 70 | fflush(stderr); 71 | exit(-1); 72 | } 73 | 74 | static void VertexPerturbation (Graph &g, vector &pertcost, RFWLocalRandom &random, SteinerConfig *config) { 75 | int n = g.VertexCount(); 76 | int m = g.EdgeCount(); 77 | 78 | Perturbator p; 79 | p.SetParameters(n, config); 80 | p.ResetRange(random.GetDouble()); 81 | 82 | static bool first = true; 83 | if (first) { 84 | fprintf (stderr, "USING PERTURBATION MODE %d\n", config->PERTURBATION_MODE); 85 | first = false; 86 | } 87 | vector vpert(n+1); 88 | 89 | for (int v=0; v<=n; v++) { 90 | //fprintf(stderr, "<<<<"); 91 | vpert[v] = p.GetPerturbation(random.GetDouble()); 92 | } 93 | 94 | // each edge is perturbed by the average of its endpoints 95 | for (int e = 1; e <= m; e++) { 96 | int v, w; 97 | g.GetEndpoints(e, v, w); 98 | double p = (vpert[v] + vpert[w]) / 2.0; 99 | EdgeCost cost =g.GetCost(e) * (EdgeCost)p; 100 | pertcost[e] = cost; 101 | } 102 | } 103 | 104 | 105 | 106 | static void OldVertexPerturbation (Graph &g, vector &pertcost, RFWLocalRandom &random) { 107 | const bool debug = false; 108 | //fprintf (stderr, "vp"); 109 | 110 | int n = g.VertexCount(); 111 | int m = g.EdgeCount(); 112 | int divisor = 1; 113 | 114 | EdgeCost mine = g.GetMinCost(); 115 | while (mine > 1000) { 116 | divisor *= 10; 117 | mine /= 10; 118 | } 119 | 120 | bool UNIFORM = false; 121 | 122 | int t = g.TerminalCount(); 123 | 124 | vector vpert(n+1); 125 | for (int v=0; v<=n; v++) { 126 | if (UNIFORM) { 127 | // it was 100,200 128 | vpert[v] = random.GetInteger(100,200); //it's 100,120 for local stuff 129 | //vpert[v] = random.GetInteger(100, 200); 100 + 20 * g.GetDegree(v)); 130 | } else { 131 | double r = random.GetDouble(); 132 | //r = (1 - r*r); 133 | //vpert[v] = 100 + 100 * (r + 1/r); 134 | vpert[v] = 100*r + 10/r; 135 | //vpert[v] = 100 + 20*r + 1/r; 136 | 137 | //fprintf (stderr, "%.1f ", vpert[v]); 138 | } 139 | } 140 | 141 | for (int e = 1; e <= m; e++) { 142 | int v, w; 143 | g.GetEndpoints(e, v, w); 144 | bool average = true; 145 | 146 | EdgeCost p; 147 | if (average) { 148 | p = (vpert[v] + vpert[w]) / 2; 149 | } else { 150 | /* 151 | ArcCost minp = (vpert[v] < vpert[w]) ? vpert[v] : vpert[w]; 152 | ArcCost maxp = (vpert[v] > vpert[w]) ? vpert[v] : vpert[w]; 153 | p = (3*minp + maxp) / 4; 154 | */ 155 | } 156 | 157 | //ArcCost p = (vpert[v] < vpert[w]) ? vpert[v] : vpert[w]; 158 | 159 | //Console.Error.Write("<{0}>", p); 160 | 161 | EdgeCost cost = (g.GetCost(e) / divisor) * p; 162 | pertcost[e] = cost; 163 | } 164 | } 165 | 166 | static void AdaptivePerturbation (Graph &g, vector &pertcost, SolutionPool &elite, RFWLocalRandom &random) { 167 | 168 | int m = g.EdgeCount(); 169 | int solcount = elite.Count(); 170 | 171 | //fprintf (stderr, "There should be %d elite solutions.\n", solcount); 172 | //fflush (stderr); 173 | 174 | for (int e=1; e<=m; e++) pertcost[e] = 0; 175 | 176 | // count the number of times each edge is used 177 | for (int i=1; i<=solcount; i++) { 178 | SteinerSolution *s = elite.GetReference(i); 179 | if (!s) fatal ("Something really bad happened.\n"); 180 | for (int e=1; e<=m; e++) { 181 | //fprintf (stderr, "%d ", e); 182 | //fflush (stderr); 183 | if (s->Contains(e)) pertcost[e] ++; 184 | } 185 | } 186 | 187 | //fprintf (stderr, "Done computing multiplicities.\n"); 188 | 189 | double factor = (90.0 / (double)solcount); 190 | 191 | int maxc = 0; 192 | for (int e=1; e<=m; e++) { 193 | int c = (int)pertcost[e]; 194 | if (c > maxc) maxc = c; 195 | pertcost[e] = g.GetCost(e) * random.GetInteger(100, 110 + (int)ceil((double)c * factor)); 196 | } 197 | 198 | fprintf (stderr, "%d ", maxc, solcount); 199 | } 200 | 201 | static void InitPerturbation(Graph &g, vector &pertcost, RFWLocalRandom &random, SteinerConfig *config) { 202 | //double p = config->PERT_VERTEX; 203 | bool USE_VERTEX_PERTURBATION = (random.GetDouble() < config->PERT_VERTEX); 204 | //fprintf (stderr, "USING VERTEX PERTURBATION? %d\n", USE_VERTEX_PERTURBATION); 205 | 206 | //bool USE_VERTEX_PERTURBATION = config->PERT_VERTEX; //random.GetInteger(1,2)==1; // 207 | if (USE_VERTEX_PERTURBATION) { 208 | VertexPerturbation(g, pertcost, random, config); 209 | return; 210 | } 211 | fprintf (stderr, "e"); 212 | Perturbator p; 213 | p.SetParameters(g.VertexCount(), config); 214 | p.ResetRange(random.GetDouble()); 215 | 216 | int m = g.EdgeCount(); 217 | for (int e=1; e<=m; e++) { 218 | //pertcost[e] = (base + range * random.GetDouble()) * g.GetCost(e); 219 | pertcost[e] = p.GetPerturbation(random.GetDouble()) * g.GetCost(e); 220 | } 221 | } 222 | 223 | static void ApplyPerturbation (Graph &g, vector &pertcost, RFWLocalRandom &random, double minfactor, double maxfactor) { 224 | double range = (maxfactor - minfactor); 225 | 226 | int m = g.EdgeCount(); 227 | for (int e=1; e<=m; e++) { 228 | double factor = minfactor + range * random.GetDoubleOpen(); 229 | pertcost[e] = (EdgeCost)factor * g.GetCost(e); 230 | } 231 | } 232 | 233 | }; 234 | 235 | -------------------------------------------------------------------------------- /src/uf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | 21 | class UnionFind { 22 | private: 23 | //#define USE_UF_STRUCT 24 | #ifdef USE_UF_STRUCT 25 | struct UFUnit { 26 | int p; 27 | int size; 28 | inline void SetPS(int _p, int _s) {p = _p; size = _s;} 29 | }; 30 | inline int GetSize(int i) const {return uf[i].size;} 31 | inline int GetParent(int i) const {return uf[i].p;} 32 | inline void SetSize(int i, int s) {uf[i].size = s;} 33 | inline void SetParent(int i, int _p) {uf[i].p = _p;} 34 | inline void IncSize(int i, int s) {uf[i].size += s;} 35 | inline void ResetParentSize(int i) {uf[i].SetPS(i,1);} 36 | inline void AllocateStructures() {uf = new UFUnit[n+1];} 37 | inline void FreeStructures() {delete [] uf;} 38 | UFUnit *uf; 39 | #else 40 | int *ufmemory; 41 | int *parent; 42 | int *size; 43 | inline int GetSize(int i) const {return size[i];} 44 | inline int GetParent(int i) const {return parent[i];} 45 | inline void SetSize(int i, int s) {size[i] = s;} 46 | inline void SetParent(int i, int p) {parent[i] = p;} 47 | inline void IncSize(int i, int s) {size[i] += s;} 48 | inline void ResetParentSize(int i) {parent[i]=i; size[i]=1;;} 49 | inline void AllocateStructures() { 50 | //ufmemory = new int [n + n + 2]; 51 | //parent = ufmemory; 52 | //size = &ufmemory[n+1]; 53 | parent = new int [n+1]; 54 | size = new int [n+1]; 55 | } 56 | inline void FreeStructures() { 57 | //delete [] ufmemory; 58 | delete [] size; 59 | delete [] parent; 60 | } 61 | 62 | #endif 63 | 64 | 65 | 66 | int n; //data structure supports numbers from 0 to maxid 67 | 68 | 69 | public: 70 | // total capacity of the data structure 71 | inline int Elements() const {return n;} 72 | 73 | // number of elements in a set 74 | inline int ComponentSize(int i) {return GetSize(Find(i));} 75 | //{return uf[Find(i)].size;} 76 | 77 | // number of independent groups 78 | //inline int GroupCount(int i) const {return groups;} 79 | 80 | void Output() { 81 | for (int i=1; i<=n; i++) { 82 | int r = Find(i); 83 | fprintf(stderr, "%d:%d (s%d)", i, r, GetSize(r)); 84 | } 85 | fprintf (stderr, "\n"); 86 | } 87 | 88 | /// 89 | /// Constructor. 90 | /// 91 | /// Number of elements (=maximum id) 92 | UnionFind(int maxid) { 93 | n = maxid; 94 | AllocateStructures(); 95 | Reset(); 96 | } 97 | 98 | ~UnionFind() {FreeStructures();} 99 | 100 | /// Partition elements into singletons (in linear time). 101 | void Reset() { 102 | for (int i=0; i<=n; i++) ResetParentSize(i); 103 | 104 | //{uf[i].SetPS(i,1);} 105 | } 106 | 107 | /// 108 | /// Function that resets a single element; BE CAREFUL WHEN USING IT! 109 | /// 110 | /// the group to be reset 111 | inline void Reset(int i) { 112 | // maybe ResetParentSize is enough 113 | 114 | if (GetParent(i)!=i) { 115 | SetParent(i,i); 116 | //groups --; 117 | } 118 | SetSize(i,1); 119 | 120 | /* 121 | if (uf[i].p != i) { 122 | uf[i].p = i; 123 | groups--; 124 | } 125 | uf[i].rank = 0; 126 | uf[i].size = 1;*/ 127 | } 128 | 129 | 130 | // Find representative of the set containing x. 131 | // x: an element of the set 132 | // output: set representative 133 | inline int Find (int x) { 134 | //fprintf (stderr, "Finding %d (this=%p,parent=%p,size=%p).\n", x, this, parent, size); 135 | //fflush (stderr); 136 | //optimizing the common case: parent is already the root 137 | int p = GetParent(x); //parent 138 | int r = GetParent(p); //grandparent 139 | if (r==p) return r; //common case! 140 | 141 | //keep looking for the root 142 | while ((p=GetParent(r))!=r) {r = p;} 143 | 144 | //compress path 145 | while ((p=GetParent(x))!=r) { 146 | SetParent(x,r); 147 | x = p; 148 | } 149 | 150 | return r; 151 | } 152 | 153 | // get the size of set containing x 154 | inline int Size(int x) { 155 | return GetSize(Find(x)); 156 | } 157 | 158 | // Join sets containing x and y (if needed), returns true iff successful 159 | inline bool Union (int x, int y) { 160 | // pick roots of both sets 161 | x = Find(x); y = Find(y); 162 | if (x == y) return false; //same set: nothing to do 163 | 164 | // heaviest element becomes new root of the other 165 | int sx = GetSize(x); 166 | int sy = GetSize(y); 167 | 168 | //x root 169 | if (sx > sy) { // x becomes root 170 | IncSize(x,sy); 171 | SetParent(y,x); 172 | } else { // y becomes root 173 | IncSize(y,sx); 174 | SetParent(x,y); 175 | } 176 | return true; 177 | 178 | 179 | /* 180 | // heaviest element becomes new root of the other 181 | int sx = uf[x].size; 182 | int sy = uf[y].size; 183 | 184 | //x root 185 | if (sx > sy) { // x becomes root 186 | uf[x].size += sy; 187 | uf[y].p = x; 188 | } else { // y becomes root 189 | uf[y].size += sx; 190 | uf[x].p = y; 191 | } 192 | return true; 193 | */ 194 | } 195 | }; 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | /* 208 | 209 | class UnionFindRank { 210 | private: 211 | struct UFUnit { 212 | int p; 213 | int rank; 214 | int size; 215 | 216 | inline void SetPRS(int _p, int _r, int _s) { 217 | p = _p; 218 | rank = _r; 219 | size = _s; 220 | } 221 | }; 222 | 223 | UFUnit *uf; 224 | int n; //number of vertices 225 | int groups; //number of groups 226 | 227 | public: 228 | // total capacity of the data structure 229 | inline int Elements() const {return n;} 230 | 231 | // number of elements in a set 232 | inline int ComponentSize(int i) {return uf[Find(i)].size;} 233 | 234 | // number of independent groups 235 | inline int GroupCount(int i) const {return groups;} 236 | 237 | void Output() { 238 | for (int i=1; i<=n; i++) { 239 | int r = Find(i); 240 | fprintf(stderr, "%d:%d (r%d,s%d)", i, r, uf[r].rank, uf[r].size); 241 | } 242 | fprintf (stderr, "\n"); 243 | } 244 | 245 | /// 246 | /// Constructor. 247 | /// 248 | /// Number of elements (=maximum id) 249 | UnionFindRank(int _n) { 250 | n = _n; 251 | uf = new UFUnit[n+1]; 252 | Reset(); 253 | } 254 | 255 | ~UnionFindRank() {delete [] uf;} 256 | 257 | /// Partition elements into singletons (in linear time). 258 | void Reset() { 259 | for (int i=1; i<=n; i++) { 260 | uf[i].p = i; 261 | uf[i].rank = 0; 262 | uf[i].size = 1; 263 | } 264 | groups = n; 265 | } 266 | 267 | /// 268 | /// Function that resets a single element; BE CAREFUL WHEN USING IT! 269 | /// 270 | /// the group to be reset 271 | //public void Reset(int i) { 272 | // if (uf[i].p != i) { 273 | // uf[i].p = i; 274 | // groups--; 275 | // } 276 | // uf[i].rank = 0; 277 | // uf[i].size = 1; 278 | //} 279 | 280 | 281 | // Find representative of the set containing x. 282 | // x: an element of the set 283 | // output: set representative 284 | int Find (int x) { 285 | int p, r = x; 286 | while ((p=uf[r].p) != r) {r = p;} 287 | 288 | //compress path 289 | while ((p=uf[x].p) != r) { 290 | uf[x].p = r; 291 | x = p; 292 | } 293 | return r; 294 | } 295 | 296 | // get the size of set containing x 297 | inline int Size(int x) { 298 | return uf[Find(x)].size; 299 | } 300 | 301 | // Join sets containing x and y (if needed), returns true iff successful 302 | inline bool Union (int x, int y) { 303 | // pick roots of both sets 304 | x = Find(x); 305 | y = Find(y); 306 | if (x == y) return false; //same set: nothing to do 307 | 308 | // pick highest rank 309 | groups --; 310 | int rx = uf[x].rank; 311 | int ry = uf[y].rank; 312 | 313 | //x root 314 | if (rx > ry) { // x root 315 | uf[x].size += uf[y].size; 316 | uf[y].p = x; //x is the new root 317 | } else { // y root 318 | if (rx == ry) {uf[y].rank++;} //increase rank if needed 319 | uf[y].size += uf[x].size; 320 | uf[x].p = y; 321 | } 322 | return true; 323 | } 324 | 325 | ~UnionFindRank() {delete [] uf;} 326 | }; 327 | */ 328 | -------------------------------------------------------------------------------- /src/rfw_random.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | #pragma once 17 | /* C++ Wrapper written by Microsoft Corporation on original C code by 18 | Nishimura and Matsumoto. Original header follows. */ 19 | 20 | /* 21 | A C-program for MT19937, with initialization improved 2002/1/26. 22 | Coded by Takuji Nishimura and Makoto Matsumoto. 23 | 24 | Before using, initialize the state by using init_genrand(seed) 25 | or init_by_array(init_key, key_length). 26 | 27 | Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, 28 | All rights reserved. 29 | 30 | Redistribution and use in source and binary forms, with or without 31 | modification, are permitted provided that the following conditions 32 | are met: 33 | 34 | 1. Redistributions of source code must retain the above copyright 35 | notice, this list of conditions and the following disclaimer. 36 | 37 | 2. Redistributions in binary form must reproduce the above copyright 38 | notice, this list of conditions and the following disclaimer in the 39 | documentation and/or other materials provided with the distribution. 40 | 41 | 3. The names of its contributors may not be used to endorse or promote 42 | products derived from this software without specific prior written 43 | permission. 44 | 45 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 46 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 47 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 48 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 49 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 50 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 52 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 53 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 54 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 55 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | 58 | Any feedback is very welcome. 59 | http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html 60 | email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) 61 | */ 62 | 63 | #ifndef RFW_RANDOM_H 64 | #define RFW_RANDOM_H 65 | 66 | #include 67 | #include 68 | 69 | class RFWRandom { 70 | public: 71 | static const unsigned long int maxvalue; 72 | 73 | /* Period parameters */ 74 | enum {N=624, M=397}; 75 | static const unsigned long int MATRIX_A; /* constant vector a */ 76 | static const unsigned long int UPPER_MASK; /* most significant w-r bits */ 77 | static const unsigned long int LOWER_MASK; /* least significant r bits */ 78 | private: 79 | 80 | static unsigned long mt[N]; /* the array for the state vector */ 81 | static int mti; /* mti==N+1 means mt[N] is not initialized */ 82 | 83 | 84 | /* initializes mt[N] with a seed */ 85 | static void init_genrand(unsigned long s) 86 | { 87 | mt[0]= s & 0xffffffffUL; 88 | for (mti=1; mti> 30)) + mti); 91 | /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ 92 | /* In the previous versions, MSBs of the seed affect */ 93 | /* only MSBs of the array mt[]. */ 94 | /* 2002/01/09 modified by Makoto Matsumoto */ 95 | mt[mti] &= 0xffffffffUL; 96 | /* for >32 bit machines */ 97 | } 98 | } 99 | 100 | 101 | /* generates a random number on [0,0xffffffff]-interval */ 102 | static unsigned long genrand_int32(void) 103 | { 104 | unsigned long y; 105 | static unsigned long mag01[2]={0x0UL, MATRIX_A}; 106 | /* mag01[x] = x * MATRIX_A for x=0,1 */ 107 | 108 | if (mti >= N) { /* generate N words at one time */ 109 | int kk; 110 | 111 | if (mti == N+1) /* if init_genrand() has not been called, */ 112 | init_genrand(5489UL); /* a default initial seed is used */ 113 | 114 | for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; 117 | } 118 | for (;kk> 1) ^ mag01[y & 0x1UL]; 121 | } 122 | y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); 123 | mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; 124 | 125 | mti = 0; 126 | } 127 | 128 | y = mt[mti++]; 129 | 130 | /* Tempering */ 131 | y ^= (y >> 11); 132 | y ^= (y << 7) & 0x9d2c5680UL; 133 | y ^= (y << 15) & 0xefc60000UL; 134 | y ^= (y >> 18); 135 | 136 | return y; 137 | } 138 | 139 | public: 140 | //constructors 141 | RFWRandom () {randomize(1);} 142 | 143 | //randomize procedures 144 | static void randomize (unsigned long s) { 145 | if (s==0) s = 1; 146 | init_genrand(s); 147 | } 148 | 149 | static unsigned long getRand() {return genrand_int32();} 150 | 151 | //pick an integer uniformly at random between inf and sup (both inclusive) 152 | static int getInteger (int inf, int sup) { 153 | if (sup<=inf) return inf; 154 | unsigned long range, minallowed, u; 155 | 156 | range = (unsigned long)(sup-inf+1); //number of values allowed 157 | minallowed = (maxvalue % range) + 1; //restrict search space to avoid small numbers 158 | if (minallowed==range) minallowed = 0; 159 | do {u = getRand();} //repeat until a good number is found 160 | while (u < minallowed); 161 | 162 | return (inf + (int)(u % range)); //return a number in the range 163 | } 164 | 165 | 166 | 167 | static float getFloat () {return (float)getDouble();} //get a float number in [0;1] 168 | static double getDouble() {return getDoubleClosed();} //double in the range [0;1] 169 | static double getDoubleClosed() {return ((double)getRand()/(double)maxvalue);} //double in the range [0;1] 170 | static double getDoubleOpen() {return ((double)getRand()/((double)(maxvalue)+1.0));} //double in the range [0;1) 171 | static bool getBool () {return (getRand() & 1);} 172 | 173 | }; 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | class RFWLocalRandom { 182 | private: 183 | //static const unsigned long int maxvalue; 184 | 185 | /* Period parameters */ 186 | //enum {N=624, M=397}; 187 | //static const unsigned long int MATRIX_A; /* constant vector a */ 188 | //static const unsigned long int UPPER_MASK; /* most significant w-r bits */ 189 | //static const unsigned long int LOWER_MASK; /* least significant r bits */ 190 | 191 | unsigned long mt[RFWRandom::N]; /* the array for the state vector */ 192 | int mti; /* mti==N+1 means mt[N] is not initialized */ 193 | 194 | 195 | /* initializes mt[N] with a seed */ 196 | void init_genrand(unsigned long s) 197 | { 198 | mt[0]= s & 0xffffffffUL; 199 | for (mti=1; mti> 30)) + mti); 202 | /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ 203 | /* In the previous versions, MSBs of the seed affect */ 204 | /* only MSBs of the array mt[]. */ 205 | /* 2002/01/09 modified by Makoto Matsumoto */ 206 | mt[mti] &= 0xffffffffUL; 207 | /* for >32 bit machines */ 208 | } 209 | } 210 | 211 | 212 | /* generates a random number on [0,0xffffffff]-interval */ 213 | unsigned long genrand_int32(void) 214 | { 215 | unsigned long y; 216 | unsigned long mag01[2]={0x0UL, RFWRandom::MATRIX_A}; 217 | /* mag01[x] = x * MATRIX_A for x=0,1 */ 218 | 219 | if (mti >= RFWRandom::N) { /* generate N words at one time */ 220 | int kk; 221 | 222 | if (mti == RFWRandom::N+1) /* if init_genrand() has not been called, */ 223 | init_genrand(5489UL); /* a default initial seed is used */ 224 | 225 | for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; 228 | } 229 | for (;kk> 1) ^ mag01[y & 0x1UL]; 232 | } 233 | y = (mt[RFWRandom::N-1]&RFWRandom::UPPER_MASK)|(mt[0]&RFWRandom::LOWER_MASK); 234 | mt[RFWRandom::N-1] = mt[RFWRandom::M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; 235 | 236 | mti = 0; 237 | } 238 | 239 | y = mt[mti++]; 240 | 241 | /* Tempering */ 242 | y ^= (y >> 11); 243 | y ^= (y << 7) & 0x9d2c5680UL; 244 | y ^= (y << 15) & 0xefc60000UL; 245 | y ^= (y >> 18); 246 | 247 | return y; 248 | } 249 | 250 | public: 251 | //constructors 252 | RFWLocalRandom () {Randomize(1);} 253 | RFWLocalRandom (unsigned long s) {Randomize(s);} 254 | 255 | 256 | void CriticalRandomize() { 257 | //#pragma omp critical 258 | { 259 | //fprintf (stderr, "cr"); 260 | Randomize((unsigned int)RFWRandom::getInteger(0,2000000000)); 261 | } 262 | } 263 | 264 | void Randomize() { 265 | Randomize((unsigned int)RFWRandom::getInteger(0,2000000000)); 266 | } 267 | 268 | //randomize procedures 269 | void Randomize (unsigned long s) { 270 | if (s==0) s = 1; 271 | init_genrand(s); 272 | } 273 | 274 | unsigned long GetRand() {return genrand_int32();} 275 | 276 | //pick an integer uniformly at random between inf and sup (both inclusive) 277 | int GetInteger (int inf, int sup) { 278 | if (sup<=inf) return inf; 279 | unsigned long range, minallowed, u; 280 | 281 | range = (unsigned long)(sup-inf+1); //number of values allowed 282 | minallowed = (RFWRandom::maxvalue % range) + 1; //restrict search space to avoid small numbers 283 | if (minallowed==range) minallowed = 0; 284 | do {u = GetRand();} //repeat until a good number is found 285 | while (u < minallowed); 286 | 287 | return (inf + (int)(u % range)); //return a number in the range 288 | } 289 | 290 | 291 | 292 | float GetFloat () {return (float)GetDouble();} //get a float number in [0;1] 293 | double GetDouble() { return GetDoubleClosed(); } //double in the range [0;1] 294 | //double GetDouble() { double r = GetDoubleClosed(); fprintf(stderr, "<<< %.10f : %.10f : %d >>>", r, (double)RFWRandom::maxvalue, sizeof(RFWRandom::maxvalue)); return r; } //double in the range [0;1] 295 | double GetDoubleClosed() { return ((double)GetRand() / (double)RFWRandom::maxvalue); } //double in the range [0;1] 296 | double GetDoubleOpen() {return ((double)GetRand()/((double)(RFWRandom::maxvalue)+1.0));} //double in the range [0;1) 297 | bool GetBool () {return (GetRand() & 1);} 298 | 299 | }; 300 | 301 | 302 | 303 | 304 | #endif 305 | -------------------------------------------------------------------------------- /src/binheap.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include 21 | using namespace std; 22 | 23 | /// 24 | /// Binary heap holding integral keys between 1 and maxid, with 25 | /// values of type T. Lower values have higher priority. 26 | /// 27 | template class BinaryHeap { 28 | 29 | private: 30 | /// 31 | /// Basic heap element structure supporting generic types 32 | /// 45 | /// Swaps elements in positions a and b. 46 | /// 47 | /// 48 | /// 49 | inline void Swap(int a, int b) { 50 | HeapUnit tmp = h[a]; 51 | h[a] = h[b]; 52 | h[b] = tmp; 53 | heappos[h[a].label] = a; 54 | heappos[h[b].label] = b; 55 | } 56 | 57 | /// 58 | /// Standard 'up' operation performed on the element in the n-th position 59 | /// 60 | /// Position. 61 | inline void Up(int n) { 62 | //while ((n > 1) && (GetValue(n / 2).CompareTo(GetValue(n)) > 0)) { 63 | while ((n>1) && IsBetter(GetValue(n), GetValue(n/2))) { 64 | Swap(n, n/2); 65 | n = n/2; 66 | } 67 | } 68 | 69 | inline T GetValue(int pos) const { return h[pos].value; } 70 | inline int GetLabel(int pos) const { return (h[pos].label); } 71 | 72 | /// 73 | /// Move the element currently in position n down to an appropriate position. 74 | /// 75 | /// Position. 76 | void Down(int n) { 77 | HeapUnit tmp; 78 | T minchild; 79 | int two_n; 80 | 81 | if ((two_n = 2*n) < nextpos) { 82 | tmp = h[n]; //Save the original value 83 | do { 84 | bool first = true; 85 | minchild = GetValue(two_n); //guess first child is the best 86 | //if (((two_n + 1) < nextpos) && (minchild.CompareTo(GetValue(two_n + 1)) > 0)) { 87 | if ((two_n+1 < nextpos) && IsBetter(GetValue(two_n+1), minchild)) { //unless the second is better 88 | minchild = GetValue(two_n + 1); 89 | first = false; 90 | } 91 | //if (tmp.value.CompareTo(minchild) > 0) { //tmp is higher than the child 92 | if (IsBetter(minchild, tmp.value)) { //is the child better than the current value? 93 | //if (minchild.CompareTo(GetValue(two_n)) == 0) { 94 | if (first) { //minchild was the first 95 | h[n] = h[two_n]; 96 | heappos[h[n].label] = n; 97 | n = two_n; 98 | } else { //minchild is the second 99 | h[n] = h[two_n + 1]; 100 | heappos[h[n].label] = n; 101 | n = two_n + 1; 102 | } 103 | two_n = 2 * n; 104 | } 105 | else { 106 | break; 107 | } 108 | } while (two_n < nextpos); 109 | h[n] = tmp; 110 | heappos[h[n].label] = n; 111 | } 112 | } 113 | 114 | 115 | /// 116 | /// Find out if 'a' is strictly better than 'b' 117 | /// 118 | /// first value 119 | /// second value 120 | /// true iff a is strictly better (smaller) than b 121 | inline bool IsBetter(T a, T b) const { 122 | //return (a.CompareTo(b) < 0); 123 | return (a 127 | /// Creates a new heap that can hold elements from 1 to n. 128 | /// 129 | /// Maximum id (minimum is 1). 130 | BinaryHeap(int n) { 131 | nextpos = 1; 132 | lastpos = n; 133 | 134 | h = new HeapUnit[n+1]; 135 | heappos = new int[n+1]; 136 | 137 | for (int v = 0; v <= n; v++) heappos[v] = 0; 138 | } 139 | 140 | /* 141 | * Destructor 142 | */ 143 | virtual ~BinaryHeap() { 144 | delete[] h; 145 | delete[] heappos; 146 | }; 147 | 148 | 149 | /// 150 | /// Remove the element with the highest priority from the heap. Its label and value are returned. 151 | /// 152 | /// 153 | /// 154 | void RemoveFirst(unsigned &label, T &value) { 155 | label = h[1].label; 156 | value = GetValue(1); 157 | 158 | h[1] = h[nextpos-1]; 159 | heappos[h[1].label] = 1; 160 | 161 | heappos[label] = 0; 162 | 163 | nextpos --; 164 | Down(1); 165 | } 166 | 167 | T PeekTopValue() {return GetValue(1);} 168 | 169 | /* 170 | void PeekFirst(unsigned &label, T &value) { 171 | label = h[1].label; 172 | value = GetValue(1); 173 | }*/ 174 | 175 | T MinValue(){ 176 | return GetValue(1); 177 | } 178 | 179 | /// 180 | /// Heapify operation 181 | /// 182 | void Heapify() { 183 | int i; 184 | for (i = (nextpos - 1) / 2; i >= 1; i--) { 185 | Down(i); 186 | } 187 | } 188 | 189 | 190 | /// 191 | /// Removes the element with the specified label from the heap 192 | /// 193 | /// 194 | void RemoveElement(unsigned label) { 195 | //get original position, check if element is actually in the heap 196 | int pos = heappos[label]; 197 | if (pos!=0) { 198 | 199 | //heappos[label] = lastpos+1; // Element will no longer belong to the heap 200 | heappos[label] = 0; 201 | nextpos--; // One fewer element 202 | 203 | // If the heap is not empty and this is not the last element, update the heap 204 | if ((nextpos != 1) && (nextpos != pos)) { 205 | h[pos] = h[nextpos]; // Last element replaces the removed one 206 | heappos[h[pos].label] = pos; // Let the element know its new position 207 | 208 | //unless parent is strictly better, go up 209 | //if ((pos > 1) && (h[pos].value.CompareTo(h[pos / 2].value) <= 0)) { 210 | if ((pos>1) && !IsBetter(h[pos/2].value, h[pos].value)) { 211 | Up(pos); 212 | } else { 213 | Down(pos); 214 | } 215 | } 216 | } 217 | } 218 | 219 | 220 | /// 221 | /// Insert and/or decrease the value of an element in the heap. Returns 222 | /// true iff successful (false if the new value is worse). 223 | /// 224 | /// Label of the new element. 225 | /// Value of the new element. 226 | /// True iff the element is inserted or updated. 227 | bool Insert(unsigned label, T value) { 228 | int prevpos = heappos[label]; 229 | if (prevpos != 0) { // Already in the heap 230 | //if (h[prevpos].value.CompareTo(value) < 0) { //do not allow demotions 231 | if (IsBetter(h[prevpos].value, value)) { //do not allow demotions 232 | return false; 233 | } else { //positive updates 234 | h[prevpos].value = value; 235 | Up(prevpos); 236 | return true; 237 | } 238 | } 239 | 240 | //not in the heap: insert it 241 | h[nextpos].label = label; 242 | h[nextpos].value = value; 243 | heappos[label] = nextpos; 244 | Up(nextpos); 245 | nextpos++; 246 | return true; 247 | } 248 | 249 | /// 250 | /// Change the key of element 'label' to value. If the element is 251 | /// not already in the heap, insert it; otherwise, just update it. 252 | /// The key will be changed regardless of whether the new key has 253 | /// higher or lower priority. 254 | /// 255 | /// 256 | /// 257 | void FixKey (unsigned label, T value) { 258 | int current_pos = heappos[label]; 259 | if (current_pos == 0) { //element is not there: insert it 260 | h[nextpos].label = label; 261 | h[nextpos].value = value; 262 | heappos[label] = nextpos; 263 | Up(nextpos); 264 | nextpos++; 265 | } else { 266 | T old_value = h[current_pos].value; 267 | //int sign = value.CompareTo(current_value); 268 | //if (sign < 0) { //strictly better 269 | 270 | h[current_pos].value = value; 271 | 272 | //if the old value was better, move element down; otherwise, bubble up as needed 273 | if (IsBetter(old_value, value)) Down(current_pos); 274 | else Up(current_pos); 275 | } 276 | } 277 | 278 | 279 | /// 280 | /// Add (label,value) as the last element of the current heap; 281 | /// MAY VIOLATE HEAP ORDER. The heap will be inconsistent 282 | /// until 'heapify' is called. This operation takes constant time. 283 | /// 284 | /// 285 | /// 286 | /// 287 | bool PushBack(unsigned label, T value) { 288 | if (Contains(label)) return false; 289 | h[nextpos].label = label; 290 | h[nextpos].value = value; 291 | heappos[label] = nextpos; 292 | nextpos++; 293 | return true; 294 | } 295 | 296 | inline T GetElementValue(int v) { return (GetValue(heappos[v])); } 297 | inline bool Contains(int v) { return (heappos[v] != 0); } 298 | inline bool IsEmpty() { return (nextpos == 1); } 299 | inline int GetSize() { return (nextpos-1); } 300 | inline int GetMaxSize() { return (lastpos); } 301 | 302 | /// 303 | /// Remove all elements from the heap. 304 | /// (Time proportional to the number of elements.) 305 | /// 306 | void Reset() { 307 | bool full = false; 308 | if (full) { 309 | //Console.Error.WriteLine("Resetting heap (expensive)."); 310 | cerr << "Resetting heap (expensive).\n"; 311 | nextpos = 1; 312 | for (int i = 0; i < lastpos; i++) {heappos[i] = 0;} 313 | } else { 314 | for (int p = 1; p < nextpos; p++) heappos[h[p].label] = 0; 315 | nextpos = 1; 316 | } 317 | } 318 | 319 | 320 | 321 | 322 | /// 323 | /// Sanity checks the heap invariants and internal mappings. 324 | /// DEBUG FUNCTION ONLY. 325 | /// 326 | /// true iff the data structure passes all tests 327 | bool Check() { 328 | fprintf (stderr, "Checking heap (%d elements)... ", nextpos); 329 | for (int i = nextpos - 1; i > 1; i--) { 330 | //if (h[i].value.CompareTo(h[i / 2].value) < 0) { 331 | if (IsBetter(h[i].value, h[i/2].value)) { 332 | //Console.WriteLine("{0} ({1}) is child of {2} ({3}). There are {{4} elements.", 333 | cerr << h[i].value << " (" << i << ") is child of " << h[i/2].value << " (" << i/2 << "). There are " << nextpos-1 << "elements.\n"; 334 | //h[i].value, i, h[i / 2].value, i / 2, nextpos - 1); 335 | return false; 336 | } 337 | } 338 | 339 | for (int i = 1; i < nextpos; i++) { 340 | if (heappos[h[i].label] != i) { 341 | //Console.WriteLine("Element {0} thinks it is in position {1}, but it isn't.", h[i].label, i); 342 | cerr << "Element " << h[i].label << " things it's in position " << i << ", but it isn't.\n"; 343 | return false; 344 | } 345 | } 346 | 347 | for (int i = 1; i <= lastpos; i++) { 348 | int pos = heappos[i]; 349 | if ((pos > 0) && (pos <= lastpos)) { 350 | if (pos >= nextpos) { 351 | //Console.WriteLine("Element {0}'s reported position ({1}) is out of bounds (there are only {2} elements).\n", i, pos, nextpos - 1); 352 | cerr << "Element " << i << "'s reported position (" << pos << ") is out of bounds (there are only " << nextpos-1 << " elements).\n"; 353 | return false; 354 | } 355 | if (h[pos].label != i) { 356 | //Console.WriteLine("Element {0} is not in the position he thinks he is ({1}); {2} is there.\n", i, pos, h[pos].label); 357 | cerr << "Element " << i << " is not in the position it things it is (" << pos << "); " << h[pos].label << " is there.\n"; 358 | //i, pos, h[pos].label 359 | return false; 360 | } 361 | } 362 | } 363 | 364 | fprintf (stderr, "passed.\n"); 365 | 366 | return true; 367 | } 368 | }; 369 | 370 | //#endif -------------------------------------------------------------------------------- /src/pairheap.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | #pragma once 16 | #include 17 | 18 | template class PairingNode { 19 | public: 20 | int child; 21 | int sibling; 22 | int parent; //0:isolated >0:actual parent <0:has root '-parent' 23 | T nodevalue; 24 | 25 | void SetSiblingParentValue(int s, int p, T v) { 26 | sibling = s; 27 | parent = p; 28 | nodevalue = v; 29 | } 30 | 31 | //node[x].Sibling = nil; //no siblings 32 | //node[x].Value = value; //assign value to x 33 | //node[x].Parent = nil; 34 | 35 | /* 36 | public int Sibling { 37 | get { return sibling; } 38 | set { sibling = value; } 39 | }*/ 40 | 41 | bool IsBetter (PairingNode x) { 42 | //return (nodevalue.CompareTo(x.Value) < 0); 43 | return (nodevalue < x.nodevalue); 44 | } 45 | 46 | //return (node[x].Value.CompareTo(node[y].Value) < 0); 47 | 48 | /* 49 | inline int Child { 50 | get { return child; } 51 | set { child = value; } 52 | } 53 | 54 | inline T Value { 55 | get { return nodevalue; } 56 | set { nodevalue = value; } 57 | } 58 | 59 | inline int Parent { 60 | get { return parent; } 61 | set { parent = value; } 62 | }*/ 63 | 64 | void Reset(int nil, int p) { 65 | child = sibling = nil; 66 | parent = p; 67 | } 68 | }; 69 | 70 | 71 | template class PairingHeap { 72 | public: 73 | 74 | private: 75 | void fatal (const string &msg) { 76 | fprintf (stderr, "ERROR::PairingHeap: %s.\n", msg.c_str()); 77 | fflush(stderr); 78 | exit(-1); 79 | } 80 | 81 | bool verbose; 82 | int emax; //maximum id used in the heap (from 1 to n) 83 | int hmax; //maximum heap name (1 to hmax) 84 | vector > node; //* node; 85 | //int *name2root; //name2root[h]: root of heap named h. May be nil. 86 | vector name2root; 87 | int nil; //null pointer (should perhaps replace this by zero) 88 | 89 | public: 90 | //get parent node 91 | inline int GetParent(int i) const {return node[i].parent;} 92 | inline int GetSibling(int i) const {return node[i].sibling;} 93 | inline T GetValue(int i) const {return node[i].nodevalue; } 94 | inline int GetChild(int i) const {return node[i].child;} 95 | 96 | void Reset() { 97 | for (int h = 1; h <= hmax; h++) name2root[h] = nil; 98 | for (int e = 1; e <= emax; e++) node[e].Reset(nil,nil); 99 | name2root[0] = -1; 100 | node[0].Reset(nil,nil); 101 | } 102 | 103 | /// 104 | /// Create collection of _hmax heaps with _emax elements in total. 105 | /// 106 | /// Number of elements. 107 | /// 108 | public: 109 | PairingHeap(int _emax, int _hmax) { 110 | verbose = false; 111 | emax = _emax; //number of elements to represent (maximum id) 112 | hmax = _hmax; 113 | nil = -1; 114 | //return; 115 | //node = new PairingNode[emax + 1]; //each element has a node 116 | //name2root = new int[hmax + 1]; //pointer from each heap name to its root node 117 | node.resize(emax+1); 118 | name2root.resize(hmax+1); 119 | //stack = new int [hmax]; 120 | Reset(); 121 | if (verbose) fprintf (stderr, "Created meldable structure with %d elements and %d heaps.\n", emax, hmax); 122 | } 123 | 124 | ~PairingHeap() { 125 | //fprintf (stderr, "Deleting pairing heap... "); 126 | //fflush(stderr); 127 | //delete [] name2root; 128 | //fprintf (stderr, "*"); fflush(stderr); 129 | //delete [] node; 130 | //fprintf (stderr, "done deleting pairing heap.\n"); 131 | //fflush(stderr); 132 | } 133 | 134 | /// 135 | /// Create an empty heap. 136 | /// 137 | /// Heap name. 138 | /* 139 | public void MakeHeap(int h) { 140 | if (name2root[h] != nil) { 141 | Console.Error.WriteLine("WARNING: CREATING PREVIOUSLY EXISTING HEAP."); 142 | } 143 | name2root[h] = nil; 144 | }*/ 145 | 146 | 147 | /// 148 | /// Return the top element of a heap, without changing it. 149 | /// 150 | /// Heap name. 151 | inline int FindMin(int h, T &value) { 152 | int r = name2root[h]; 153 | if (r == nil) fatal ("Cannot take minimum from empty heap"); 154 | value = GetValue(r); 155 | return r; 156 | } 157 | 158 | inline bool Isolated(int x) const { 159 | return (GetParent(x) == nil); 160 | 161 | } 162 | 163 | private: 164 | inline bool IsBetter(int x, int y) { 165 | return node[x].IsBetter(node[y]); //SHOULD MAKE THIS SIMPLER! 166 | //return (node[x].Value.CompareTo(node[y].Value) < 0); 167 | //return (GetValue(x).CompareTo(GetValue(y)) < 0); 168 | } 169 | 170 | 171 | /// 172 | /// Link heaps rooted at r1 and r2. Return the root of the resulting heap. 173 | /// 174 | /// One heap, and the name of the resulting heap. 175 | /// Second heap 176 | int Link(int r1, int r2) { 177 | //simple cases: at least one is empty 178 | if (r1 == nil) return r2; 179 | if (r2 == nil) return r1; 180 | 181 | int p, c; //parent, child 182 | if (IsBetter(r2, r1)) { 183 | //if (node[r2].IsBetter(node[r1])) { 184 | p = r2; c = r1; 185 | } else { 186 | p = r1; c = r2; 187 | } 188 | 189 | if (p<1 || p>emax) fatal ("parent out of range"); 190 | if (c<1 || c>emax) { 191 | fprintf (stderr, "p=%d c=%d\n", p, c); 192 | fatal ("child out of range"); 193 | } 194 | 195 | int oldchild = node[p].child; 196 | 197 | node[c].sibling = oldchild; 198 | if (oldchild != nil) node[oldchild].parent = c; 199 | node[p].child = c; 200 | node[c].parent = p; 201 | return p; 202 | } 203 | 204 | /// 205 | /// Assign name h to the heap rooted at r. 206 | /// 207 | void SetName(int h, int r) { 208 | if (r != nil) node[r].parent = -h; //make root point to heap 209 | name2root[h] = r; //keep pointer to root 210 | } 211 | 212 | void FreeName(int h) { 213 | int r = name2root[h]; 214 | if (r != nil) { 215 | name2root[h] = nil; 216 | node[r].parent = nil; 217 | } //else throw new Exception ("FreeName cannot be called on empty heap."); 218 | } 219 | 220 | public: 221 | void Insert(int h, int x, T value) { 222 | //if (!Isolated(x)) {}; //throw new Exception("Only isolated elements can be inserted"); 223 | if (h<1 || h>hmax) fatal ("heap out of range"); 224 | if (x<1 || x>emax) fatal ("element out of range"); 225 | 226 | if (node[x].parent != nil) { 227 | fprintf (stderr, "Node %d has parent %d.\n", x, node[x].parent); 228 | fatal ("Only isolated elements can be inserted"); 229 | } 230 | 231 | node[x].sibling = nil; //no siblings 232 | node[x].nodevalue = value; //assign value to x 233 | node[x].parent = nil; //THIS IS PROBABLY NOT NECESSARY 234 | //node[x].SetSiblingParentValue(nil, nil, value); 235 | int r = name2root[h]; 236 | 237 | r = Link(r, x); 238 | SetName(h, r); 239 | //if (r != nil) node[r].Parent = -h; //make root point to heap 240 | //name2root[h] = r; //keep pointer to root 241 | } 242 | 243 | 244 | public: 245 | /// 246 | /// Merge two heaps, h1 and h2, creating a new heap h1 247 | /// 248 | void Merge(int h1, int h2) { 249 | if (h1 == h2) return; 250 | //Console.Error.WriteLine("Merging {0}:{1}.", h1, h2); 251 | int r1 = name2root[h1]; 252 | int r2 = name2root[h2]; 253 | //Console.Error.WriteLine("Done with names."); 254 | FreeName(h1); 255 | FreeName(h2); 256 | 257 | int r = Link(r1, r2); 258 | //if (r != nil) { 259 | SetName(h1, r); //do this even if r is null... 260 | //else throw new Exception ("The result of a merge cannot be null."); 261 | } 262 | 263 | private: 264 | /// 265 | /// Create a single heap from the sibling list starting at v. 266 | /// 267 | /// 268 | /// 269 | int PairUp (int current) { 270 | int firstdone = nil; 271 | int next = 0; 272 | 273 | //Console.Error.WriteLine("Pairing up, starting at {0}.", current); 274 | 275 | //state: (<<>>current next nextnext>>>) 276 | //(the firstdone list is reversed) 277 | 278 | //FIRST PASS: pair elements from left to right while 279 | //reversing the newly created list. 280 | while (true) { 281 | next = node[current].sibling; 282 | int nextnext = (next!=nil) ? node[next].sibling : nil; 283 | int temp = Link(current, next); 284 | node[temp].sibling = firstdone; 285 | firstdone = temp; 286 | 287 | if (nextnext == nil) break; 288 | current = nextnext; //advance 289 | } 290 | 291 | //Second pass: just link everybody 292 | current = firstdone; 293 | next = node[current].sibling; 294 | while (next!=nil) { 295 | int nextnext = node[next].sibling; 296 | current = Link(current, next); //join the first two trees 297 | node[current].sibling = nextnext; //is this really necessary? 298 | next = nextnext; //advance pointers 299 | } 300 | 301 | return current; 302 | } 303 | 304 | public: 305 | void DecreaseKey(int h, int x, T value) { 306 | if (Isolated(x)) fatal("Cannot decrease key of isolated node."); 307 | fprintf (stderr, "Warning: not checking for improvement."); 308 | //if (node[x].Value < value) throw new Exception("DecreaseKey cannot increase key."); 309 | node[x].Value = value; 310 | 311 | int p = node[x].parent; 312 | if (p == nil) return; 313 | 314 | //remove subtree rooted at x 315 | int s = node[x].sibling; 316 | 317 | //there is a parent in the binary tree 318 | if (node[p].sibling == x) { //actually a sibling 319 | node[p].sibling = s; 320 | } else { //really a child 321 | node[p].child = s; 322 | } 323 | 324 | if (s != nil) { 325 | node[s].parent = p; 326 | } 327 | 328 | node[x].sibling = nil; 329 | node[x].parent = nil; 330 | 331 | //combine the subtree with the current root 332 | int r = name2root[h]; 333 | r = Link(r, x); 334 | SetName(h, r); 335 | } 336 | 337 | public: 338 | void Output(int h) { 339 | fprintf (stderr, "Outputting heap %d.\n", h); 340 | int r = name2root[h]; 341 | fprintf (stderr, "Root is %d.\n", r); 342 | 343 | for (int e = 1; e <= emax; e++) { 344 | fprintf (stderr, "%d: p%d s%d c%d", e, node[e].parent, node[e].sibling, node[e].child); 345 | } 346 | } 347 | 348 | /* 349 | public delegate T Transform(T x); 350 | 351 | 352 | /// 353 | /// Traverse the entire heap h, applying a transformation to each element. 354 | /// 355 | /// The heap. 356 | /// Function from T to T. 357 | public void Traverse(int h, Transform transf) { 358 | int v = name2root[h]; 359 | int from = 0; //0: parent; 1:child; 2:sibling 360 | int travcount = 0; 361 | 362 | bool verbose = false; 363 | Console.Error.WriteLine("Traversing heap {0}, root {1}... ({2} {3})", h, v, node[v].Parent, nil); 364 | 365 | while (v >= 0) { 366 | int p = node[v].Parent; 367 | int c = node[v].Child; 368 | int s = node[v].Sibling; 369 | 370 | if (from == 0) { 371 | if (verbose) { 372 | Console.Error.WriteLine("v={0} p={1} c={2} s={3} ", v, p, c, s); 373 | Console.Error.Write("BEFORE{0}:{1} -> ", v, node[v].Value); 374 | } 375 | node[v].Value = transf(node[v].Value); 376 | if (verbose) Console.Error.Write(" -> AFTER{0}:{1}\n", v, node[v].Value); 377 | 378 | 379 | travcount++; 380 | } 381 | 382 | //go to child if possible 383 | if ((from == 0) && (c != nil)) { 384 | v = c; //from remains zero 385 | } else { //after child, go to sibling 386 | if ((from != 2) && (s != nil)) { 387 | v = s; 388 | from = 0; 389 | } else { //after child and sibling, go back up 390 | //going to parent (from doesn't matter if v is the root) 391 | from = 0; 392 | if (p > 0) from = (node[p].Child == v) ? 1 : 2; 393 | v = p; 394 | } 395 | } 396 | } 397 | Console.Error.WriteLine(" ({0} elements traversed).", travcount); 398 | 399 | }*/ 400 | 401 | public: 402 | int DeleteMin(int h, T &value) { 403 | int r = name2root[h]; 404 | if (r == nil) fatal("Cannot delete from an empty heap."); 405 | 406 | value = node[r].nodevalue; 407 | int c = node[r].child; 408 | node[r].parent = node[r].child = nil; //make node r isolated 409 | 410 | if (c != nil) c = PairUp(c); 411 | SetName(h,c); 412 | 413 | return r; 414 | } 415 | 416 | 417 | inline bool IsEmpty(int h) const { 418 | /* 419 | fprintf (stderr, "Checking if %d is empty.\n", h); 420 | fflush (stderr); 421 | fprintf (stderr, "Checking if %d is empty (%d).\n", h, name2root[h]); 422 | fflush (stderr);*/ 423 | 424 | return (name2root[h] == nil); 425 | } 426 | }; 427 | 428 | /* 429 | public class TraversablePairingHeap : PairingHeap where T : IComparable { 430 | 431 | public TraversablePairingHeap (int _emax, int _hmax) : base (_emax, _hmax) { 432 | 433 | } 434 | 435 | 436 | }*/ 437 | -------------------------------------------------------------------------------- /src/LSVertexInsertion.h: -------------------------------------------------------------------------------- 1 | #include "graph.h" 2 | #include "solution.h" 3 | #include "rfw_random.h" 4 | #include "rfw_stack.h" 5 | #include "LSBasics.h" 6 | 7 | #pragma once 8 | 9 | class LSVertexInsertion { 10 | struct LocalArc { 11 | public: 12 | int v; 13 | int w; 14 | EdgeCost cost; 15 | 16 | LocalArc(int _v, int _w, EdgeCost _cost) { 17 | v = _v; 18 | w = _w; 19 | cost = _cost; 20 | } 21 | 22 | void Set(int _v, int _w, EdgeCost _cost) { 23 | v = _v; 24 | w = _w; 25 | cost = _cost; 26 | } 27 | 28 | LocalArc() {v=w=0; cost=0;} 29 | }; 30 | 31 | private: 32 | static void fatal (const string &msg) { 33 | Basics::fatal(msg); 34 | } 35 | 36 | /// 37 | /// Rebuild a solution based on the dynamic tree. 38 | /// 39 | static void RebuildSolution (STEdgeLinear &dyntree, SteinerSolution &solution) { 40 | bool verbose = false; 41 | if (verbose) fprintf (stderr, "Rebuilding solution from dynamic tree."); 42 | Graph *g = solution.g; 43 | int n = g->VertexCount(); 44 | solution.Reset(); 45 | 46 | for (int v=1; v<=n; v++) { 47 | int w = dyntree.GetParent(v); 48 | if (w == 0) continue; 49 | EdgeCost cost = -dyntree.cut(v); 50 | 51 | // find a matching edge 52 | SPGArc *a, *end; 53 | for (g->GetBounds(v,a,end); ahead == w) { 55 | int e = a->label; 56 | if (a->cost == cost) { //just in case there are parallel edges 57 | solution.Insert(e); 58 | break; 59 | } 60 | } 61 | } 62 | } 63 | 64 | if (verbose) fprintf (stderr, "Solution costs %d.", solution.GetCost()); 65 | } 66 | 67 | static void MarkSolutionVertices (SteinerSolution &solution, UniverseSet &svertices) { 68 | int n = solution.g->VertexCount(); 69 | for (int v=1; v<=n; v++) { 70 | if (solution.GetDegree(v)>0) svertices.Insert(v); 71 | } 72 | } 73 | 74 | 75 | public: 76 | /// 77 | /// Steiner-vertex insertion local search. 78 | /// 79 | /// Initial solution (may change). 80 | /// Maximum number of vertices checked. 81 | /// 82 | static int VertexInsertion(Graph &g, SteinerSolution &solution, int maxv, RFWLocalRandom &random) { 83 | int n = g.VertexCount(); 84 | int v = 0; 85 | 86 | bool changed = false; 87 | bool CHANGE_ON_TIE = false; 88 | const bool debug_mode = false; 89 | const bool randomize = true; //randomize order in which vertices are tested 90 | const bool high_verbose = false; 91 | const bool verbose = false; 92 | if (verbose) { 93 | fprintf (stderr, "Running vertex-insertion local search."); 94 | fprintf (stderr, "Solution costs %.0f.", solution.GetCost()); 95 | } 96 | 97 | RFWStack removed (n); //edges temporarily removed from the tree 98 | RFWStack inserted (n); //edges temporarily inserted into the tree 99 | 100 | //list of all vertices in the solution 101 | UniverseSet svertices(n); 102 | MarkSolutionVertices(solution, svertices); 103 | if (verbose) fprintf (stderr, "Solution has %d vertices.\n", svertices.Count()); 104 | 105 | //compute number of solution neighbors for each nonsolution vertex 106 | int *solneighbors = new int[n + 1]; //this is zero for terminals! 107 | for (v=1; v<=n; v++) {solneighbors[v] = 0;} 108 | int p, pend; 109 | for (svertices.GetBounds(p,pend); phead; 114 | if (!svertices.Contains(w)) solneighbors[w]++; 115 | } 116 | } 117 | 118 | 119 | if (verbose) fprintf (stderr, "Inserting initial edges into the tree.\n"); 120 | EdgeCost cost0 = solution.GetCost(); 121 | if (high_verbose) fprintf(stderr, "Initial solution value is %.10f.", cost0); 122 | STEdgeLinear dyntree (n); // dynamic tree data structure 123 | 124 | int m = g.EdgeCount(); 125 | for (int e=1; e<=m; e++) { // looping over all edges (could be more efficient) 126 | if (!solution.Contains(e)) continue; 127 | int a, b; 128 | g.GetEndpoints(e, a, b); 129 | EdgeCost cost = g.GetCost(e); 130 | if (debug_mode && (!svertices.Contains(a) || !svertices.Contains(b))) fatal ("inconsistent solution representation"); 131 | dyntree.Evert(a); // make a the root of its component 132 | dyntree.Link(a, b, -cost); // add arc from a to b (b becomes a's parent) 133 | } 134 | 135 | int impmoves = 0; //number of improving moves 136 | EdgeCost curcost = cost0; //current solution value 137 | int failures = 0; //number of consecutive failures to improve 138 | 139 | // create a random permutation of all vertices 140 | // (there should be a separate function for this) 141 | int *perm = new int[n + 1]; 142 | for (v = 1; v <= n; v++) {perm[v] = v;} 143 | if (randomize) { 144 | for (v = 1; v < n; v++) { 145 | int w = random.GetInteger(v, n); 146 | int t = perm[v]; 147 | perm[v] = perm[w]; 148 | perm[w] = t; 149 | } 150 | } 151 | 152 | // prepare for the main loop 153 | int pos = 0; 154 | v = 1; 155 | int count = 0; 156 | 157 | const bool TIME_EVERTS = false; // measure time taken on "evert" operations? 158 | RFWTimer evertime; 159 | if (TIME_EVERTS) { 160 | evertime.start(); 161 | evertime.pause(); 162 | } 163 | 164 | // perform operations until we have n failures in a row 165 | while (failures < n) { 166 | if (count >= maxv) break; //enough tries---just stop 167 | count ++; 168 | if (++pos > n) pos = 1; 169 | v = perm[pos]; 170 | 171 | //consider only nonterminals with at least two neighbors in the solution 172 | if (solneighbors[v] <= 1) {failures++; continue;} 173 | 174 | if (debug_mode && svertices.Contains(v)) fprintf (stderr, "Should not have been here (%d, solneighbors %d).", v, solneighbors[v]); 175 | if (verbose) fprintf (stderr, "Processing %d: ", v); 176 | 177 | EdgeCost increase = 0; //increase in cost 178 | int inscount = 0; //number of insertions 179 | int tries = 0; 180 | bool first = true; 181 | 182 | //invariant: the new vertex (v) will be the root during these operations 183 | SPGArc *a, *end; 184 | for (g.GetBounds(v,a,end); ahead; 186 | if (!svertices.Contains(w)) continue; //only care about neighbors in the solution 187 | tries++; 188 | EdgeCost cost = a->cost; 189 | 190 | if (first) { //first edge: just insert it 191 | if (TIME_EVERTS) evertime.resume(); 192 | dyntree.Evert(w); //make w the root of its tree 193 | if (TIME_EVERTS) evertime.pause(); 194 | if (debug_mode && (dyntree.GetRoot(v) == dyntree.GetRoot(w))) fatal ("v cannot be on the same tree as w"); 195 | dyntree.Link(w, v, -cost); //v is the new root 196 | if (verbose) fprintf (stderr, "+%.2f I(%d,%d) (r:%d)", (double)cost, v, w, dyntree.GetRoot(v)); 197 | increase += cost; 198 | inscount++; 199 | inserted.push(a->label); // remember edge (for later removal) 200 | first = false; 201 | } else { 202 | //other edges: insert only if they improve something 203 | if (debug_mode && (dyntree.GetRoot(w) != v)) { 204 | fprintf (stderr, "In solution: %d.", svertices.Contains(w)); 205 | fprintf (stderr, "v:%d e:%d", svertices.Count(), -1); //solution.Count()); 206 | fprintf (stderr, " %d:%d:%d:%d", v, dyntree.GetRoot(v), w, dyntree.GetRoot(w)); 207 | fatal ("tree does not have the right root"); 208 | } 209 | int z = dyntree.GetMinCost(w); //get mincost edge (z,pz) on the w-v path 210 | if (debug_mode) { 211 | if (z == 0) fatal ("path should not be empty"); 212 | if (dyntree.GetRoot(z) == z) fprintf (stderr, "%d is its own root, from v=%d and w=%d and root(w)=%d!", z, v, w, dyntree.GetRoot(w)); 213 | } 214 | EdgeCost zcost = -dyntree.GetCost(z); 215 | 216 | //we might want to remove edge (z,pz) with cost zcost 217 | if (zcost > cost) { 218 | if (verbose) fprintf (stderr, " %.2f->%.2f", (double)zcost, (double)cost); 219 | int pz = dyntree.GetParent(z); 220 | 221 | //if we are removing an original edge, remember it 222 | //(it may need to be reinserted later) 223 | if (pz != v) {removed.push(LocalArc(z,pz,zcost));} 224 | if (verbose) fprintf(stderr, " R(%d,%d)", z, pz); 225 | 226 | //remove arc (z,pz) 227 | EdgeCost t = -dyntree.cut(z); //remove the edge 228 | if (debug_mode && (t != zcost)) fatal ("Internal costs are not consistent"); 229 | 230 | if (TIME_EVERTS) evertime.resume(); 231 | dyntree.Evert(w); //make w the root of its component 232 | if (TIME_EVERTS) evertime.pause(); 233 | dyntree.Link(w, v, -cost); //add arc from w to v; v remains root 234 | 235 | if (debug_mode && (dyntree.GetRoot(v) != v)) fatal("tree does not have the right root"); 236 | 237 | increase += (cost - zcost); 238 | inscount++; 239 | inserted.push(a->label); //remove the new edge 240 | if (verbose) fprintf (stderr, " I(%d,%d):%d ", w, v, a->label); 241 | } 242 | } 243 | } 244 | 245 | //fprintf (stderr, "%d ", tries); 246 | 247 | if (verbose) fprintf (stderr, " = %.2f after %d insertions (tries=%d degree=%d).", increase, inscount, tries, solneighbors[v]); 248 | 249 | // if the new solution is worse, we must restore the original one 250 | bool restore; 251 | if (increase <= -EDGE_COST_PRECISION) { //solution improved! 252 | impmoves++; 253 | failures = 1; //not zero because we don't need v itself 254 | restore = false; 255 | } else { //same or worse 256 | restore = (increase > EDGE_COST_PRECISION || !CHANGE_ON_TIE); 257 | failures++; 258 | } 259 | 260 | //if the solution did not improve, restore original tree 261 | if (restore) { 262 | //remove the newly inserted edges; they are all neighbors of v 263 | //(note that some may have been removed already) 264 | while (!inserted.isEmpty()) { 265 | int alabel = inserted.pop(); 266 | int w = g.GetOther(alabel, v); 267 | 268 | if (verbose) { 269 | fprintf (stderr, "ToRem%d ", alabel); 270 | int tx, ty; 271 | g.GetEndpoints(alabel, tx, ty); 272 | fprintf (stderr, " [%d,%d]", tx, ty); 273 | } 274 | 275 | dyntree.Evert(w); //WARNING: ISN'T IT ENOUGH TO KEEP V AS THE ROOT ALL THE WAY? IT SHOULD BE THE IMMEDIATE PARENT OF EVERYBODY. 276 | 277 | //if the edge is still there, remove it 278 | if (dyntree.GetParent(v) == w) { 279 | dyntree.cut(v); 280 | if (verbose) fprintf (stderr, "deleting (%d,%d) ", v, w); 281 | } else { 282 | if (verbose) fprintf(stderr, " @@@ (v:%d pv:%d w:%d) ", v, dyntree.GetParent(v), w); 283 | } 284 | } 285 | 286 | //reinsert temporarily removed edges 287 | while (!removed.isEmpty()) { 288 | LocalArc larc = removed.pop(); //why can't we remember just integers? 289 | if (TIME_EVERTS) evertime.resume(); 290 | dyntree.Evert(larc.v); //make one of the endpoints the root 291 | if (TIME_EVERTS) evertime.pause(); 292 | dyntree.Link(larc.v, larc.w, -larc.cost); //link one to the other 293 | if (verbose) fprintf (stderr, "R"); 294 | } 295 | 296 | if (verbose) { 297 | int dyncount = dyntree.GetEdgeCount(); 298 | int solcount = -1; //solution.Count(); 299 | fprintf (stderr, "Dynamic tree now has {0} edges. Solution has {1} edges.", dyntree.GetEdgeCount(), -1); //solution.Count()); 300 | } 301 | } else { 302 | //we're going to the neighbor! 303 | curcost += increase; 304 | removed.reset(); //no need to remember just-removed edges 305 | inserted.reset(); //no need to remember just-inserted edges 306 | svertices.Insert(v); //solution has one new vertex 307 | solneighbors[v] = 0; //v now belongs to the solution 308 | changed = true; 309 | 310 | // we will NOT change the list of edges in the solution until we 311 | // we reach a local optimal; we only update auxiliary data structures as we go 312 | SPGArc *a, *end; 313 | for (g.GetBounds(v,a,end); ahead; 315 | if (!svertices.Contains(w)) {solneighbors[w]++;} //fix degree 316 | } 317 | } 318 | 319 | if (high_verbose && increase < -EDGE_COST_PRECISION) { 320 | fprintf (stderr, "Vertex %d improves the solution by %.10f.\n", v, (double)-increase); 321 | } 322 | } 323 | 324 | EdgeCost improvement = cost0 - curcost; 325 | 326 | if (high_verbose && impmoves > 0 && improvement > EDGE_COST_PRECISION) { 327 | fprintf (stderr, "End of local search; found %d improving moves (tried %d).", impmoves, count); 328 | fprintf (stderr, "Solution went from %.1f to %.1f: %.10f.\n", cost0, curcost, improvement); 329 | } 330 | 331 | 332 | if (TIME_EVERTS) fprintf (stderr, "%.2f ", 1000*evertime.getTime()); 333 | 334 | if (improvement > EDGE_COST_PRECISION) { 335 | if (!changed) fatal ("inconsistent assessment"); 336 | RebuildSolution(dyntree, solution); 337 | } else { 338 | if (changed) fprintf (stderr, "Not using changed version (improvement: %.10f / %.10f).\n", improvement, EDGE_COST_PRECISION); 339 | } 340 | 341 | if (verbose) fprintf (stderr, "Found %.2f, mst is %.2f.", (double)curcost, (double)solution.GetCost()); 342 | 343 | if (solneighbors) delete [] solneighbors; 344 | if (perm) delete [] perm; 345 | return impmoves; 346 | } 347 | 348 | }; 349 | -------------------------------------------------------------------------------- /src/solution.h: -------------------------------------------------------------------------------- 1 | /* 2 | Algorithm for Steiner Problem in Graphs 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include "graph.h" 21 | 22 | class SteinerSolution { 23 | public: 24 | Graph *g; 25 | private: 26 | vector edge; //incident vector of edges in the solution 27 | vector degree; //current degrees of all solution vertices 28 | int nleaves; //number of nonterminal leaves 29 | EdgeCost cost; //total solution cost 30 | 31 | inline void ProcessInsertion(int v) { 32 | int d = ++degree[v]; 33 | if (d<=2 && !g->IsTerminal(v)) { 34 | if (d==1) nleaves ++; 35 | else nleaves --; 36 | } 37 | } 38 | 39 | // process v when removing one of its endpoints 40 | inline void ProcessRemoval (int v) { 41 | int d = --degree[v]; 42 | if (d<2 && !g->IsTerminal(v)) { 43 | if (d==0) nleaves --; 44 | else nleaves ++; 45 | } 46 | } 47 | 48 | 49 | public: 50 | inline int LeafCount() const {return nleaves;} 51 | inline bool Contains(int e) const { return edge[e]; } 52 | inline size_t EdgeCapacity() const { return edge.size(); } 53 | 54 | void Reset() { 55 | fill_n(edge.begin(), g->EdgeCount()+1, false); 56 | fill_n(degree.begin(), g->VertexCount()+1, 0); 57 | cost = g->GetFixedCost(); 58 | nleaves = 0; 59 | } 60 | 61 | inline bool Insert (int e) { 62 | if (Contains(e)) return false; 63 | edge[e] = true; 64 | cost += g->GetCost(e); 65 | ProcessInsertion(g->GetFirstEndpoint(e)); 66 | ProcessInsertion(g->GetSecondEndpoint(e)); 67 | return true; 68 | } 69 | 70 | int EdgeCount() { 71 | int ecount = 0; 72 | int m = g->EdgeCount(); 73 | for (int e=1; e<=m; e++) { 74 | if (Contains(e)) ecount ++; 75 | } 76 | return ecount; 77 | } 78 | 79 | void Output(FILE *file) { 80 | fprintf (stderr, "Outputting solution..."); // to {0}... ", filename); 81 | //System.IO.StreamWriter file = new System.IO.StreamWriter(@filename); 82 | 83 | 84 | int m = g->EdgeCount(); 85 | fprintf (file, "m %d\n", EdgeCount()); 86 | fprintf (file, "c %.0f\n", GetCost()); 87 | for (int e = 1; e<=m; e++) { 88 | if (!Contains(e)) continue; 89 | int v, w; 90 | g->GetEndpoints(e, v, w); 91 | fprintf (file, "e %d %d %.0f\n", v, w, g->GetCost(e)); 92 | } 93 | fprintf (stderr, "done.\n"); 94 | } 95 | 96 | void Output (char *prefix) { 97 | char filename[2048]; 98 | sprintf (filename, "%s.%09.0lf.sol", prefix, (double)GetCost()); 99 | FILE *file = fopen (filename, "w"); 100 | if (!file) { 101 | fprintf (stderr, "Could not open <%s> for output. Will not output solution.\n", filename); 102 | return; 103 | } 104 | Output(file); 105 | fclose(file); 106 | fprintf (stderr, "Solution written to <%s>.\n", filename); 107 | fflush(stderr); 108 | } 109 | 110 | 111 | 112 | 113 | /// Remove edge e from the current solution. Returns true iff 114 | /// the edge was actually in the solution before. 115 | inline bool Remove(int e) { 116 | if (edge[e]==false) return false; 117 | edge[e] = false; 118 | cost -= g->GetCost(e); 119 | ProcessRemoval(g->GetFirstEndpoint(e)); 120 | ProcessRemoval(g->GetSecondEndpoint(e)); 121 | return true; 122 | } 123 | 124 | 125 | inline int GetDegree (int v) const {return degree[v];} 126 | inline EdgeCost GetCost () const {return cost;} 127 | 128 | bool IsBetter (SteinerSolution *s) { 129 | return (GetCost() < s->GetCost() - EDGE_COST_PRECISION); 130 | } 131 | 132 | void UpdateCost() { 133 | const bool verbose = false; 134 | if (verbose) fprintf (stderr, "Cost updated from %d to ", cost); 135 | int m = g->EdgeCount(); 136 | cost = g->GetFixedCost(); 137 | for (int e=1; e<=m; e++) { 138 | if (Contains(e)) cost += g->GetCost(e); 139 | } 140 | if (verbose) fprintf (stderr, "%d.\n", cost); 141 | } 142 | 143 | 144 | 145 | SteinerSolution (Graph *_g) { 146 | g = _g; 147 | edge.resize(g->EdgeCount()+1); 148 | degree.resize(g->VertexCount()+1); 149 | Reset(); 150 | } 151 | 152 | SteinerSolution (SteinerSolution *s) { 153 | g = s->g; 154 | edge.resize(g->EdgeCount()+1); 155 | degree.resize(g->VertexCount()+1); 156 | Reset(); 157 | CopyFrom(s); 158 | } 159 | 160 | void CopyFrom(SteinerSolution *s) { 161 | if (g != s->g) { 162 | g = s->g; 163 | } else { 164 | Reset(); 165 | } 166 | int m = g->EdgeCount(); 167 | for (int e=1; e<=m; e++) { 168 | if (s->Contains(e)) Insert(e); 169 | } 170 | 171 | //fprintf (stderr, "Created solution with %d arcs.\n", this->EdgeCount()); 172 | 173 | //foreach (int e in ((SteinerSolution)s).ElementEnumerator()) { 174 | // Insert(e); 175 | //} 176 | //Console.Error.WriteLine("copy not implemented"); 177 | } 178 | 179 | 180 | /// 181 | /// Compute degree of difference between this solution and ds, given 182 | /// by (union - intersection) / intersection. In particular, the result 183 | /// is zero iff the solutions are identical, and 1 if they have no edge 184 | /// in common. 185 | double GetDifference(SteinerSolution *s) { 186 | //SteinerSolution s = (SteinerSolution)ds; 187 | //int common = 0; 188 | //int scount = 0; 189 | 190 | int ucount = 0; //edges.Count(); //number of edges in the union 191 | int icount = 0; //number of edges in the intersection 192 | 193 | int m = g->EdgeCount(); 194 | for (int e=1; e<=m; e++) { 195 | int count = (Contains(e) ? 1 : 0) + (s->Contains(e) ? 1 : 0); 196 | if (count == 0) continue; 197 | //fprintf (stderr, "%d%d ", Contains(e), s->Contains(e)); 198 | ucount ++; //1 or 2 199 | if (count == 2) { 200 | icount ++; 201 | } 202 | } 203 | 204 | //fprintf (stderr, "[%d/%d] ", icount, ucount); 205 | 206 | return (1.0 - (double)icount/(double)ucount); 207 | } 208 | 209 | }; 210 | 211 | #if 0 212 | using ArcCost = System.Double; 213 | 214 | namespace SteinerOpt { 215 | [Serializable] 216 | public class SteinerSolution : IOptSolution { 217 | private UniverseSet edges; //list of edges in the solution 218 | private ArcCost cost; 219 | private int [] degree; 220 | private int nleaves; //number of degree-one nonterminals 221 | 222 | [NonSerialized] 223 | WeightedGraph g; 224 | 225 | /// 226 | /// Compute degree of difference between this solution and ds, given 227 | /// by (union - intersection) / intersection. In particular, the result 228 | /// is zero iff the solutions are identical, and 1 if they have no edge 229 | /// in common. 230 | /// 231 | /// 232 | /// 233 | public double GetDifference(IOptSolution ds) { 234 | SteinerSolution s = (SteinerSolution)ds; 235 | //int common = 0; 236 | //int scount = 0; 237 | 238 | int ucount = edges.Count(); //number of edges in the union 239 | int icount = 0; //number of edges in the intersection 240 | 241 | foreach (int e in s.ElementEnumerator()) { 242 | if (edges.Contains(e)) {icount ++;} 243 | else ucount ++; 244 | } 245 | 246 | return (1.0 - (double)icount/(double)ucount); 247 | 248 | 249 | /* 250 | 251 | foreach (int e in s.ElementEnumerator()) { 252 | scount++; 253 | if (s.Contains(e)) common++; 254 | } 255 | 256 | int total = edges.Count() + scount; 257 | return (double)(total - common) / (double)total; 258 | */ 259 | } 260 | 261 | public void OutputSolution(string filename) { 262 | Console.Error.Write("Outputting solution to {0}... ", filename); 263 | System.IO.StreamWriter file = new System.IO.StreamWriter(@filename); 264 | /*file.WriteLine("c "); 265 | file.WriteLine("n {0}", n); 266 | file.WriteLine("b {0}", bestsol.GetCost()); 267 | file.WriteLine("s {0}", nsols); 268 | for (v=1; v<=n; v++) { 269 | int degree = bestsol.GetDegree(v); 270 | int inbest = 0; 271 | if (degree > 0) inbest = 1; 272 | //if (bestsol.Contains(v)) {inbest = 1;} 273 | file.WriteLine("v {0} {1} {2} {3}", v, inbest, degree, (double)vcount[v]/(double)nsols); 274 | } 275 | file.Close(); 276 | */ 277 | 278 | file.WriteLine("m {0}", edges.Count()); 279 | file.WriteLine("c {0}", GetCost()); 280 | foreach (int e in edges.ElementEnumerator()) { 281 | int v, w; 282 | g.GetEndpoints(e, out v, out w); 283 | file.WriteLine("e {0} {1} {2}", e, v, w); 284 | } 285 | file.Close(); 286 | Console.Error.WriteLine("done.\n"); 287 | } 288 | 289 | public object GetValue() { 290 | return GetCost(); 291 | } 292 | 293 | public int GetDegree(int v) { 294 | return degree[v]; 295 | } 296 | 297 | public int LeafCount() {return nleaves;} 298 | 299 | public bool IsBetter(IOptSolution s) { 300 | return (GetCost() < ((SteinerSolution)s).GetCost()); 301 | } 302 | 303 | public void CopyFrom(IOptSolution _s) { 304 | SteinerSolution s = (SteinerSolution)_s; 305 | 306 | if (g != s.GetGraph()) { 307 | SetGraph(s.GetGraph()); 308 | } else { 309 | Reset(); 310 | } 311 | foreach (int e in ((SteinerSolution)s).ElementEnumerator()) { 312 | Insert(e); 313 | } 314 | //Console.Error.WriteLine("copy not implemented"); 315 | } 316 | 317 | public object Clone() { 318 | SteinerSolution s = new SteinerSolution(g); 319 | s.CopyFrom(this); 320 | //Console.Error.WriteLine("Function not implemented"); 321 | //return new SteinerSolution(null); 322 | return s; 323 | } 324 | 325 | public SteinerSolution(WeightedGraph _g) { 326 | SetGraph(_g); 327 | cost = 0; 328 | /* 329 | g = _g; 330 | int m = g.EdgeCount(); 331 | edges = new UniverseSet(m); 332 | cost = 0;*/ 333 | } 334 | 335 | public SteinerSolution() { 336 | g = null; 337 | cost = 0; 338 | } 339 | 340 | public void SetGraph(WeightedGraph _g) { 341 | //g = (WeightedGraph) _g; 342 | g = _g; 343 | int m = g.EdgeCount(); 344 | edges = new UniverseSet(m); 345 | int n = g.VertexCount(); 346 | 347 | //Console.Error.WriteLine("graph initialized"); 348 | degree = new int [n+1]; 349 | for (int i=0; i<=n; i++) degree[i] = 0; 350 | nleaves = 0; 351 | } 352 | 353 | public int Count() { 354 | return edges.Count(); 355 | } 356 | 357 | public WeightedGraph GetGraph() { 358 | return g; 359 | } 360 | 361 | public IEnumerable ElementEnumerator() { 362 | return edges.ElementEnumerator(); 363 | } 364 | 365 | public bool Contains(int e) { 366 | return edges.Contains(e); 367 | } 368 | 369 | public bool Insert(int e) { 370 | if (edges.Insert(e)) { 371 | int a, b; 372 | g.GetEndpoints(e, out a, out b); 373 | int d = (++degree[a]); 374 | if (d<=2 && !g.IsTerminal(a)) { 375 | if (d==1) nleaves ++; 376 | else nleaves --; 377 | } 378 | d = (++degree[b]); 379 | if (d <= 2 && !g.IsTerminal(b)) { 380 | if (d == 1) nleaves++; 381 | else nleaves--; 382 | } 383 | 384 | 385 | //if (((degree[a] ++)==0) && (!g.IsTerminal(a))) nleaves ++; 386 | //if (((degree[b] ++)==0) && (!g.IsTerminal(b))) nleaves ++; 387 | //degree[b] ++; 388 | //if (a == 1) Console.Error.WriteLine("{0}:{1} ", a, degree[a]); 389 | //if (b == 1) Console.Error.WriteLine("{0}:{1} ", b, degree[b]); 390 | cost += g.GetCost(e); 391 | return true; 392 | } else return false; 393 | } 394 | 395 | public void Reset() { 396 | foreach (int e in edges.ElementEnumerator()) { 397 | int a, b; 398 | g.GetEndpoints(e, out a, out b); 399 | //if (((--degree[a]) == 0) && (!g.IsTerminal(a))) nleaves --; 400 | //if (((--degree[b]) == 0) && (!g.IsTerminal(b))) nleaves ++; 401 | degree[a] --; 402 | degree[b] --; 403 | } 404 | nleaves = 0; 405 | edges.Reset(); 406 | cost = 0; 407 | } 408 | 409 | /// 410 | /// Remove edge e from the current solution. Returns true iff 411 | /// the edge was actually in the solution before. 412 | /// 413 | /// edge to be removed 414 | /// true iff the edge did belong to the solution 415 | public bool Remove(int e) { 416 | if (edges.Remove(e)) { 417 | cost -= g.GetCost(e); 418 | int a, b; 419 | g.GetEndpoints(e, out a, out b); 420 | 421 | int d = --degree[a]; 422 | if (d<2 && !g.IsTerminal(a)) { 423 | if (d==0) nleaves --; 424 | else nleaves ++; 425 | } 426 | 427 | d = --degree[b]; 428 | if (d<2 && !g.IsTerminal(b)) { 429 | if (d==0) nleaves --; 430 | else nleaves ++; 431 | } 432 | 433 | 434 | //if ((--degree[a] == 0) && (!g.IsTerminal(a))) nleaves --; 435 | //if ((--degree[b] == 0) && (!g.IsTerminal(b))) nleaves ++; 436 | return true; 437 | } else return false; 438 | } 439 | 440 | public void Copy(SteinerSolution s) { 441 | cost = 0; 442 | edges.Reset(); 443 | foreach (int e in s.ElementEnumerator()) { 444 | edges.Insert(e); 445 | cost += g.GetCost(e); 446 | } 447 | } 448 | 449 | /// 450 | /// Recompute solution cost to account for (possibly new) 451 | /// edge weights on the graph. Useful after a perturbation 452 | /// is added to the graph. 453 | /// 454 | public void UpdateCost() { 455 | //Console.Error.Write("Initial cost is {0}... ", cost); 456 | cost = 0; 457 | foreach (int e in this.ElementEnumerator()) { 458 | cost += g.GetCost(e); 459 | } 460 | ///Console.Error.WriteLine("Updated solution cost is {0}.", cost); 461 | } 462 | 463 | public ArcCost GetCost() { 464 | return cost; 465 | } 466 | } 467 | } 468 | 469 | #endif -------------------------------------------------------------------------------- /src/LSBasics.h: -------------------------------------------------------------------------------- 1 | #include "graph.h" 2 | 3 | #pragma once 4 | 5 | 6 | struct DFSData { 7 | int *id2dfs; //maps vertex ids to post-order numbers 8 | int *dfs2id; //maps post-order numbers to vertex ids 9 | int *id2parc; //maps vertex ids to parent arcs in the dfs tree 10 | 11 | DFSData(int n) { 12 | id2dfs = new int [n+1]; 13 | dfs2id = new int [n+1]; 14 | id2parc = new int [n+1]; 15 | } 16 | 17 | ~DFSData() { 18 | delete [] id2parc; 19 | delete [] dfs2id; 20 | delete [] id2dfs; 21 | //fprintf (stderr, "Deleted DFS data.\n"); 22 | //fflush(stderr); 23 | } 24 | }; 25 | 26 | 27 | class GlobalInfo { 28 | EdgeCost bestfound; 29 | int solved; 30 | 31 | public: 32 | int bbpruned; //true iff bb pruned at a node that was not yet solved 33 | EdgeCost fixed; //hack because bb cannot handle fixed costs 34 | // 35 | EdgeCost UpdateBestFound(EdgeCost bf) { 36 | double answer = bestfound; 37 | if (bf != answer) { 38 | #pragma omp critical 39 | { 40 | if (bf < bestfound) { 41 | bestfound = bf; 42 | fprintf (stderr, "[[[ %.2f ]]] ", bestfound); 43 | } 44 | answer = bestfound; 45 | } 46 | } 47 | return answer; 48 | } 49 | 50 | inline bool IsSolved() { 51 | return (solved!=0); 52 | } 53 | 54 | void MakeSolved() { 55 | solved = 1; 56 | } 57 | 58 | GlobalInfo() { 59 | bestfound = INFINITE_COST; 60 | fixed = 0; 61 | solved = 0; 62 | bbpruned = 0; 63 | } 64 | }; 65 | 66 | 67 | class CutRecorder { 68 | public: 69 | vector cutlist; 70 | 71 | void Reset() { 72 | cutlist.clear(); 73 | } 74 | 75 | void Reset(int size) { 76 | cutlist.reserve(size); 77 | cutlist.clear(); 78 | } 79 | 80 | inline void AddArc(int alabel) { 81 | cutlist.push_back(alabel); 82 | } 83 | 84 | inline void CloseCut() { 85 | cutlist.push_back(-1); 86 | } 87 | 88 | }; 89 | 90 | class GraphMapper { 91 | private: 92 | void Init() { 93 | oldn = oldm = 0; 94 | v2new = e2new = NULL; 95 | } 96 | 97 | public: 98 | int *v2new; 99 | int *e2new; 100 | int oldn, oldm; 101 | 102 | GraphMapper() { 103 | Init(); 104 | } 105 | 106 | void Reset(int _oldn, int _oldm) { 107 | oldn = _oldn; 108 | oldm = _oldm; 109 | v2new = new int [oldn+1]; 110 | e2new = new int [oldm+1]; 111 | for (int e=1; e<=oldm; e++) e2new[e] = -1; 112 | for (int v=1; v<=oldn; v++) v2new[v] = -1; 113 | } 114 | 115 | ~GraphMapper() { 116 | if (v2new) delete [] v2new; 117 | if (e2new) delete [] e2new; 118 | } 119 | 120 | void Destroy() { 121 | if (v2new) delete [] v2new; 122 | if (e2new) delete [] e2new; 123 | Init(); 124 | } 125 | 126 | }; 127 | 128 | class Basics { 129 | public: 130 | 131 | static void ReportResults (FILE *file, const string &prefix, double seconds, EdgeCost solvalue, EdgeCost bestknown) { 132 | fprintf (file, "%ssolution %.20f\n", prefix.c_str(), (double)solvalue); 133 | fprintf(file, "%stimeus %.3f\n", prefix.c_str(), 1000000.0 * seconds); 134 | fprintf(file, "%stimems %.6f\n", prefix.c_str(), 1000.0 * seconds); 135 | fprintf(file, "%stimes %.9f\n", prefix.c_str(), seconds); 136 | double ratio = (double)solvalue / (double)bestknown; 137 | double error = ratio - 1; 138 | fprintf(file, "%sratio %.20f\n", prefix.c_str(), ratio); 139 | fprintf(file, "%serror %.20f\n", prefix.c_str(), error); 140 | fprintf(file, "%spcterror %.20f\n", prefix.c_str(), 100.0 * error); 141 | 142 | } 143 | 144 | 145 | static void fatal (const string &msg) { 146 | fprintf (stderr, "ERROR: %s.\n", msg.c_str()); 147 | fflush(stderr); 148 | exit(-1); 149 | } 150 | 151 | // this is old; the terminal is not random 152 | static int WrongPickRandomTerminal(Graph &g) { 153 | //fprintf (stderr, "r"); 154 | int n = g.VertexCount(); 155 | for (int v=1; v<=n; v++) if (g.IsTerminal(v)) return v; 156 | fatal ("could not find terminal"); 157 | return 0; 158 | } 159 | 160 | static int PickRandomTerminal(Graph &g) { 161 | //fprintf (stderr, "r"); 162 | int n = g.VertexCount(); 163 | int count = 0; 164 | int target = RFWRandom::getInteger(1,g.TerminalCount()); 165 | for (int v=1; v<=n; v++) { 166 | if (g.IsTerminal(v)) { 167 | if (++count == target) return v; 168 | } 169 | } 170 | fatal ("could not find terminal"); 171 | return 0; 172 | } 173 | 174 | static int PickRandomTerminal(Graph &g, RFWLocalRandom &random) { 175 | static bool first = true; 176 | if (first) { 177 | fprintf (stderr, "PICKRANDOMTERMINAL IS NOT PROPERLY SET.\n"); 178 | first = false; 179 | } 180 | int n = g.VertexCount(); 181 | int count = 0; 182 | int target = random.GetInteger(1,g.TerminalCount()); 183 | for (int v=1; v<=n; v++) { 184 | if (g.IsTerminal(v)) { 185 | if (++count == target) return v; 186 | } 187 | } 188 | fatal ("could not find terminal"); 189 | return 0; 190 | } 191 | 192 | 193 | 194 | /// 195 | /// Perform DFS on the solution, numbering vertices in reverse post-order. 196 | /// Returns the number of vertices visited. 197 | /// 198 | /// Root of DFS. 199 | /// Current solution. 200 | /// Output: map from dfs number to id (-1 if not visited) 201 | /// Output: map from id to dfs number (-1 if not visited) 202 | /// Output: map from it to parent arc (0 if not visited) 203 | static int DFS (Graph &g, int r, SteinerSolution &solution, DFSData &dfsdata, RFWStack &stack) { 204 | // this is a funny implementation of dfs: when we first scan a vertex, we simply add to the stack 205 | // every nonscanned neighbor---even those that are already in the stack. This requires a stack of size m. 206 | // WARNING! IF WE ARE ONLY SCANNING EDGES OF THE SOLUTION, THE SIZE IS N 207 | int *id2dfs = dfsdata.id2dfs; 208 | int *dfs2id = dfsdata.dfs2id; 209 | int *id2parc = dfsdata.id2parc; 210 | 211 | int n = g.VertexCount(); 212 | int m = g.EdgeCount(); 213 | 214 | stack.reset(); 215 | 216 | //id2dfs: -1:unreached 0:scanned >0:processed 217 | for (int v=0; v<=n; v++) { 218 | id2dfs[v] = -1; //everybody unreached, initially 219 | dfs2id[v] = -1; 220 | id2parc[v] = 0; 221 | } 222 | 223 | stack.push(r); 224 | int nextdfs = 1; 225 | 226 | while (!stack.isEmpty()) { 227 | int v = stack.pop(); 228 | int vdfs = id2dfs[v]; 229 | if (vdfs > 0) {continue;} //vertex already processed: nothing else to do 230 | 231 | //vertex already scanned, but with no label; we assign it a label now 232 | if (vdfs == 0) { 233 | id2dfs[v] = nextdfs; 234 | dfs2id[nextdfs] = v; 235 | nextdfs++; 236 | continue; 237 | } 238 | 239 | //vertex not yet scanned: scan it, put it back on the stack (a label will be assigned later) 240 | stack.push(v); 241 | id2dfs[v] = 0; 242 | 243 | //foreach (WeightedGraph.Arc arc in g.ArcEnumerator(v)) { 244 | SPGArc *a, *end; 245 | //for (int pa=g.GetStart(v); palabel; //g.GetArcLabel(pa); 248 | if (!solution.Contains(alabel)) continue; 249 | int w = a->head; //g.GetArcHead(pa);//arc.head; 250 | if (id2dfs[w] >= 0) continue; //w already scanned: no need to go there again 251 | id2parc[w] = alabel; 252 | stack.push(w); 253 | } 254 | } 255 | return nextdfs - 1; 256 | } 257 | 258 | // add all vertices in the current solution to solnodes 259 | // (vertices with incident edges) 260 | static void MarkSolutionNodes(Graph &g, SteinerSolution &solution, UniverseSet &solnodes) { 261 | int n = g.VertexCount(); 262 | for (int v=1; v<=n; v++) { 263 | if (solution.GetDegree(v)>0) solnodes.Insert(v); 264 | } 265 | } 266 | 267 | //mark the components containing the elements of the stack 268 | static void MarkComponent(Graph &g, RFWStack &stack, int *id2parc, UniverseSet &marked) { 269 | //Console.Error.Write("+"); 270 | //Invariant: a vertex becomes marked when it is inserted into the stack 271 | //A marked vertex is or was on the stack. 272 | 273 | bool verbose = false; 274 | if (verbose) fprintf (stderr, "Marking component from %d vertices; marked has %d.", stack.getNElements(), marked.Count()); 275 | 276 | //make invariants true for original vertices 277 | for (int i = stack.getNElements(); i >= 1; i--) { 278 | int v = stack.peek(i); 279 | if (marked.Contains(v)) fprintf (stderr, "BAD"); 280 | marked.Insert(v); 281 | } 282 | 283 | int mcount = marked.Count(); 284 | 285 | //add all relevant tree children to the stack 286 | while (!stack.isEmpty()) { 287 | int v = stack.pop(); 288 | SPGArc *a, *end; 289 | for (g.GetBounds(v,a,end); ahead; //g.GetArcHead(pa); 292 | if (id2parc[w]==a->label) { //g.GetArcLabel(pa)) { 293 | if (marked.Insert(w)) { 294 | //mcount ++; 295 | stack.push(w); 296 | } 297 | } 298 | } 299 | /* 300 | foreach (WeightedGraph.Arc arc in g.ArcEnumerator(v)) { 301 | int w = arc.head; 302 | if (id2parc[w]==arc.label) { 303 | if (marked.Insert(w)) stack.Push(w); 304 | } 305 | }*/ 306 | } 307 | 308 | mcount = marked.Count() - mcount; 309 | if (verbose) fprintf(stderr, "%d elements marked", mcount); 310 | 311 | /* if (verbose) {Console.Error.WriteLine(" {0} elements marked.", marked.Count()); 312 | foreach (int e in marked.ElementEnumerator()) {Console.Error.Write("+{0} ", e);}}*/ 313 | } 314 | 315 | 316 | static void CheckSolution(Graph &g, SteinerSolution &solution) { 317 | if (!InnerCheck(g, solution, false)) { 318 | fatal ("Invalid solution"); 319 | } 320 | } 321 | 322 | static bool InnerCheck(Graph &g, SteinerSolution &solution, bool verbose) { 323 | int n = g.VertexCount(); 324 | UniverseSet svertices(n); 325 | UnionFind uf(n); 326 | Basics::MarkSolutionNodes(g, solution, svertices); 327 | int ncomp = svertices.Count(); 328 | 329 | UniverseSet terminals(n); 330 | for (int t=1; t<=g.VertexCount(); t++) { 331 | if (g.IsTerminal(t)) terminals.Insert(t); 332 | } 333 | 334 | //Console.Error.WriteLine("Term 335 | 336 | //foreach (int e in solution.ElementEnumerator()) 337 | 338 | int m = g.EdgeCount(); 339 | int ecount = 0; 340 | for (int e=1; e<=m; e++) { 341 | if (!solution.Contains(e)) continue; 342 | ecount ++; 343 | int v, w; 344 | g.GetEndpoints(e, v, w); 345 | if (!svertices.Contains(v) || !svertices.Contains(w)) { 346 | fprintf (stderr, "Edge %d=(%d,%d), membership %d %d.\n", 347 | e, v, w, svertices.Contains(v), svertices.Contains(w)); 348 | fatal ("Inconsistent vertex membership in solution"); 349 | } 350 | 351 | terminals.Remove(v); 352 | terminals.Remove(w); 353 | 354 | if (uf.Find(v) == uf.Find(w)) { 355 | fprintf (stderr, "Vertices %d, %d already in the same component.", v, w); 356 | fatal ("Solution has a cycle."); 357 | } else { 358 | uf.Union(v, w); 359 | ncomp --; 360 | } 361 | } 362 | 363 | if (terminals.Count() > 0) { 364 | fprintf (stderr, "Terminals not in solution: %d.", terminals.Count()); 365 | fatal ("Missing terminals in solution."); 366 | } 367 | 368 | 369 | fprintf (stderr, "[CHECKING:n=%d:m=%d:%d components]", svertices.Count(), ecount, ncomp); 370 | if (verbose) { 371 | for (int v=1; v<=n; v++) { 372 | if (svertices.Contains(v)) { 373 | fprintf (stderr, "%d:%d ", v, uf.Find(v)); 374 | } 375 | } 376 | fprintf (stderr, "\n"); 377 | } 378 | 379 | 380 | if (ecount != svertices.Count() - 1) return false; 381 | else return true; 382 | } 383 | 384 | 385 | 386 | 387 | 388 | /// 389 | /// Compute the Voronoi diagram of the current graph, given a set of bases 390 | /// and maybe the perturbed cost of the edges. 391 | /// 392 | /// Output: description of the Voronoi diagram 393 | /// List of bases. 394 | /// Preallocated heap to be used in the computation (will be reset) 395 | /// Edge costs (use original costs if null). 396 | static void ComputeVoronoi(Graph &g, VoronoiData &voronoi, UniverseSet &baselist, BinaryHeap &heap, EdgeCost *pertcost) { 397 | const bool GLOBAL_USE_VORONOI_TIE_BREAKER = false; // NOT CLEAR WHERE THIS THING IS SUPPOSED TO BE DEFINED 398 | 399 | const bool verbose = false; 400 | voronoi.Reset(); 401 | int nbases = 0; 402 | heap.Reset(); 403 | 404 | // initialize with all bases 405 | int p, pend; 406 | for (baselist.GetBounds(p,pend); phead; //g.GetArcHead(pa); 433 | EdgeCost newdist = dist; 434 | 435 | if (pertcost == NULL) newdist += a->cost; //g.GetArcCost(pa); 436 | else newdist += pertcost[a->label]; 437 | 438 | bool improve = false; 439 | 440 | if (voronoi.GetBase(w) == 0) improve = true; 441 | else if (newdist <= voronoi.GetDistance(w)) improve = true; //using leq here to prefer shorter edges... 442 | else if (USE_TIEBREAKERS && newdist == voronoi.GetDistance(w)) { 443 | if (randomize) { 444 | fatal ("randomization not implemented!\n"); //(stderr, "NOT IMPLEMENTED!\n 445 | //improve = (random.GetInteger(0, 1) == 0); //(arc.cost < g.GetCost(voronoi.GetParentArc(w))); 446 | } else if (PREFER_TERMINALS) { 447 | improve = g.IsTerminal(voronoi.GetBase(v)); 448 | } 449 | //improve = (arc.cost < g.GetCost(voronoi.GetParentArc(w))); 450 | } 451 | 452 | if (improve) { //make w a tentative child of v 453 | heap.Insert(w, newdist); 454 | voronoi.Update(w, voronoi.GetBase(v), a->label, newdist); 455 | } 456 | } 457 | } 458 | } 459 | 460 | /// Iteratively removes all degree-one vertices in the solution. 461 | /// Takes O(1) if there are no such vertices. If there are, takes 462 | /// O(n) + degree of all vertices removed. 463 | /// Original solution (will be modified). 464 | static void Prune(Graph &g, SteinerSolution &solution) { 465 | if (solution.LeafCount()==0) return; //WARNING: THIS SHOULD BE THERE! 466 | 467 | int n = g.VertexCount(); 468 | for (int v=1; v<=n; v++) { 469 | int t = v; 470 | while (solution.GetDegree(t)==1 && !g.IsTerminal(t)) { 471 | //find the unique incident solution edge 472 | SPGArc *a, *end; 473 | for (g.GetBounds(t,a,end); alabel; 475 | if (!solution.Contains(alabel)) continue; 476 | solution.Remove(alabel); 477 | t = g.GetOther(alabel,t); //process the other endpoint next 478 | break; 479 | } 480 | } 481 | } 482 | } 483 | 484 | }; 485 | -------------------------------------------------------------------------------- /src/LSVertexElimination.h: -------------------------------------------------------------------------------- 1 | #include "graph.h" 2 | #include "solution.h" 3 | #include "rfw_random.h" 4 | #include "LSBasics.h" 5 | 6 | class LSVertexElimination { 7 | private: 8 | static void fatal (const string &msg) { 9 | fprintf (stderr, "ERROR: %s.\n", msg.c_str()); 10 | fflush(stderr); 11 | exit(-1); 12 | } 13 | 14 | /// 15 | /// Compute nearest common ancestors of all edges with both ends in the solution. 16 | /// Puts edge (v,w) in bucket NCA(v,w). 17 | /// 18 | /// 19 | /// 20 | /// 21 | /// 22 | static void ComputeNCA(Graph &g, StaticBuckets &hzt, UniverseSet &svertices, DFSData &dfsdata, int root) { 23 | bool verbose = false; 24 | int *id2dfs = dfsdata.id2dfs; 25 | int *id2parc = dfsdata.id2parc; 26 | int *dfs2id = dfsdata.dfs2id; 27 | 28 | int v, n = g.VertexCount(); 29 | int *ancestor = new int [n+1]; //auxiliary variable used for nca computations... 30 | UnionFind ncauf (n); //auxilary data structure for nca computation 31 | 32 | for (v=1; v<=n; v++) ancestor[v] = v; //and everybody is its own ancestor 33 | hzt.Reset(); //reset list of visited nodes 34 | 35 | int nhzt = 0; //number of horizontal edges 36 | 37 | //traverse nodes in bottom-up order, ending up in the root 38 | int count = 0; 39 | for (int vdfs=1; vdfs<=n; vdfs++) { 40 | v = dfs2id[vdfs]; 41 | if (verbose) fprintf (stderr, "%d:%d\n", vdfs, v); 42 | if (v<=0) break; 43 | 44 | //for (int pa = g.GetStart(v); pa < g.GetEnd(v); pa++) { 45 | SPGArc *a, *end; 46 | for (g.GetBounds(v,a,end); ahead; //g.GetArcHead(pa); 48 | 49 | //look at (v,w) if w in solution and already processed 50 | if (svertices.Contains(w) && (id2dfs[w] < vdfs)) { 51 | int nca = ancestor[ncauf.Find(w)]; 52 | if (nca<1 || nca>n) fatal ("nca out of range"); 53 | if (v==nca || w==nca) continue; 54 | nhzt++; 55 | hzt.Insert(a->label, nca); //g.GetArcLabel(pa), nca); 56 | if (verbose) fprintf (stderr, "Inserting (%d,%d) into bucket %d.\n", v,w, nca); 57 | } 58 | } 59 | 60 | //unite v with its parent 61 | if (v!=root) { 62 | int parent = g.GetOther(id2parc[v],v); 63 | ncauf.Union(parent,v); 64 | ancestor[ncauf.Find(v)] = parent; //parent is the ancestor 65 | } 66 | } 67 | 68 | delete [] ancestor; 69 | //edges per horizontal edge 70 | if (verbose) fprintf (stderr, "%d edges are horizontal, total count is %d.", nhzt, count); 71 | } 72 | 73 | public: 74 | 75 | /*------------------------------------------ 76 | * Local search based on vertex elimination 77 | *-----------------------------------------*/ 78 | static int VertexElimination(Graph &g, SteinerSolution &solution, RFWLocalRandom &random) { 79 | bool verbose = false; 80 | if (verbose) { 81 | fprintf (stderr, "\n\nRunning local search based on vertex eliminations.\n"); 82 | fflush(stderr); 83 | } 84 | //bool JUST_COUNT = false; 85 | int improvements = 0; 86 | int n = g.VertexCount(); 87 | int m = g.EdgeCount(); 88 | int v; 89 | 90 | DFSData dfsdata(n); 91 | int *id2dfs = dfsdata.id2dfs; 92 | int *dfs2id = dfsdata.dfs2id; 93 | int *id2parc = dfsdata.id2parc; 94 | 95 | //bool [] forbidden = new bool [n+1]; 96 | UniverseSet forbidden(n);// = new UniverseSet(n); 97 | bool *pinned = new bool [n+1]; 98 | for (v=1; v<=n; v++) {pinned[v] = false;} 99 | 100 | 101 | //StaticStack stack = new StaticStack(m); 102 | RFWStack stack(m); 103 | 104 | //UniverseSet svertices = new UniverseSet(n); //vertices in the original solution 105 | UniverseSet svertices(n); //vertices in the original solution 106 | 107 | StaticBuckets hzt (m, n); //horizontal edges 108 | 109 | UnionFind uf (n); //union find data structure 110 | UnionFind kuf (n); // union find for Kruskal computation 111 | BinaryHeap kheap(m); //binary heap for Kruskal computation 112 | 113 | //UnionFind uf = new UnionFind(n); //union find data structure 114 | //UnionFind kuf = new UnionFind(n); //union find for kruskal computation 115 | //BinaryHeap kheap = new BinaryHeap(m); //binary heap for kruskal computation 116 | 117 | UniverseSet cedges (m); 118 | 119 | int root = Basics::PickRandomTerminal(g,random); 120 | //fprintf (stderr, "r%d ", root); 121 | 122 | //root = 5; 123 | if (verbose) fprintf (stderr, "Root is %d.\n", root); 124 | 125 | //profit from each possible move 126 | EdgeCost *profit = new EdgeCost[n + 1]; 127 | for (v=1; v<=n; v++) profit[v] = 0; 128 | 129 | //CheckSolution(solution); 130 | int visited = Basics::DFS(g, root, solution, dfsdata, stack); 131 | if (verbose) fprintf (stderr, "DFS visited %d vertices from root %d.", visited, root); 132 | 133 | if (visited < g.TerminalCount()) { 134 | fprintf (stderr, "Visited %d vertices, but there are %d terminals.", visited, g.TerminalCount()); 135 | fatal ("Something wrong."); 136 | } 137 | 138 | //find list of all original solution vertices 139 | Basics::MarkSolutionNodes(g, solution, svertices); 140 | 141 | 142 | //find set of horizontal edges 143 | if (verbose) { 144 | fprintf (stderr, "Solution has %d vertices.\n", svertices.Count()); 145 | fflush(stderr); 146 | } 147 | 148 | ComputeNCA(g, hzt, svertices, dfsdata, root); //id2dfs, id2parc); 149 | 150 | 151 | if (verbose) { 152 | fprintf (stderr, "Done computing NCAs.\n"); 153 | fflush(stderr); 154 | } 155 | 156 | //data about subtrees 157 | PairingHeap heap(2 * m, n); 158 | UniverseSet subtrees (n); 159 | 160 | bool high_verbose = false; //verbose; 161 | 162 | int solsize = svertices.Count(); 163 | if (verbose) { 164 | fprintf (stderr, "Initiating main loop.\n"); 165 | fflush(stderr); 166 | } 167 | 168 | for (int i = 1; i < solsize; i++) { 169 | v = dfs2id[i]; 170 | 171 | if (verbose) { 172 | fprintf (stderr, "\n\nProcessing vertex %d (dfs=%d, pinned=%d): ", v, id2dfs[v], pinned[v]); 173 | fflush(stderr); 174 | } 175 | 176 | //------------------------------------ 177 | // find original subtrees of vertex v 178 | //------------------------------------ 179 | EdgeCost remcost = 0; //total cost of edges removed 180 | remcost += g.GetCost(id2parc[v]); //arc to the parent 181 | subtrees.Reset(); 182 | 183 | if (high_verbose) { 184 | fprintf (stderr, "Scanning."); fflush(stderr); 185 | } 186 | 187 | //for (int pa=g.GetStart(v); palabel; //g.GetArcLabel(pa); 191 | int w = a->head; //g.GetArcHead(pa); 192 | 193 | if (high_verbose) { 194 | fprintf (stderr, "Looking at (%d,%d)... ", v, w); 195 | fflush(stderr); 196 | } 197 | 198 | //look at all *original* children (some children may have been removed) 199 | if (id2parc[w] == alabel) { 200 | remcost += a->cost; //g.GetArcCost(pa); //arc.cost; 201 | subtrees.Insert(uf.Find(w)); 202 | if (verbose) { 203 | int f = uf.Find(w); 204 | if (verbose) {fprintf (stderr, "Vertex %d corresponds to set %d with size %d ", w, f, uf.Size(f)); fflush(stderr);} 205 | } 206 | } 207 | if (high_verbose) { 208 | fprintf (stderr, "End of %d.\n", w); 209 | fflush (stderr); 210 | } 211 | } 212 | 213 | if (high_verbose) { 214 | fprintf (stderr, "%d children, cost cost is %.2f, terminal %d.\n", subtrees.Count(), remcost, g.IsTerminal(v)); 215 | fflush(stderr); 216 | } 217 | 218 | //if (!g.IsTerminal(v)) { 219 | // if (pinned[v]) Console.Error.Write("PINNED({0})", v); 220 | // else Console.Error.Write("."); 221 | //} 222 | 223 | if (g.IsTerminal(v) || pinned[v]) { 224 | //if (pinned[v]) Console.Error.Write("."); 225 | if (verbose) { 226 | if (pinned[v]) fprintf (stderr, "PINNED(%d)", v); 227 | fprintf (stderr, "T! "); 228 | fflush (stderr); 229 | } 230 | } else { 231 | //we may want to remove this vertex (not pinned or a terminal) 232 | if (verbose) { 233 | fprintf (stderr, "R! "); 234 | fflush(stderr); 235 | } 236 | 237 | //penalize edges incident to forbidden nodes? 238 | //bool USE_FORBIDDEN_PENALTIES = false; 239 | //double badpenalty = 0; 240 | 241 | //list of edges for Kruskal's algorithm 242 | kheap.Reset(); 243 | 244 | //process each subtree: clean up heap to find cheapest edge that is actually 245 | //vertical, then insert it into kheap (the list of candidate edges). 246 | //foreach (int s in subtrees.ElementEnumerator()) { 247 | int p, pend; 248 | 249 | 250 | for (subtrees.GetBounds(p,pend); p m) a -= m; 304 | //kheap.Insert(a, value); 305 | //kheap.PushBack(a,value + badpenalty); 306 | kheap.PushBack(a,value); 307 | if (verbose) { 308 | fprintf (stderr, "Done pushing back %d.", a); 309 | fflush(stderr); 310 | } 311 | } 312 | if (verbose) {fprintf (stderr, "%d-done ", s); fflush(stderr);} 313 | } 314 | 315 | //insert horizontal edges into heap 316 | //foreach (int ha in hzt.ElementEnumerator(v)) { 317 | 318 | // WARNING: CHECK THAT THIS IS DOING THE RIGHT THING 319 | for (int ha=hzt.GetFirst(v); ha>=0; ha=hzt.GetNext(ha)) { 320 | 321 | /*if (USE_FORBIDDEN_PENALTIES) {int x, y; g.GetDirectedEndpoints(ha, out x, out y); 322 | if (forbidden.Contains(x) || forbidden.Contains(y)) badpenalty = 1/(double)(n+1); 323 | }*/ 324 | //kheap.PushBack(ha, g.GetCost(ha) + badpenalty); 325 | if (verbose) { 326 | int x,y; 327 | g.GetEndpoints(ha, x, y); 328 | fprintf (stderr, "Adding edge %d=(%d,%d) to kheap.\n", ha, x, y); 329 | } 330 | kheap.PushBack(ha, g.GetCost(ha)); 331 | } 332 | kheap.Heapify(); 333 | 334 | if (verbose) { 335 | fprintf (stderr, "There are %d edges in total in kheap.", kheap.GetSize()); 336 | fflush(stderr); 337 | } 338 | 339 | 340 | 341 | //run kruskal on modified graph 342 | EdgeCost altcost = 0; 343 | int picked = 0; 344 | cedges.Reset(); 345 | int goal = subtrees.Count(); 346 | while (!kheap.IsEmpty()) { 347 | EdgeCost cost; 348 | unsigned int a; //WARNING: MADE THIS UNSIGNED 349 | kheap.RemoveFirst(a, cost); 350 | int x, y; 351 | g.GetEndpoints(a, x, y); 352 | 353 | if (verbose) fprintf (stderr, "h(%d,%d) ", x, y); 354 | 355 | if (forbidden.Contains(x) || forbidden.Contains(y)) { 356 | continue; 357 | //break; 358 | //continue; //WARNING: BY DOING THIS, WE ARE NO LONGER GUARANTEED TO FIND AN MST 359 | } 360 | 361 | int gx = uf.Find(x); 362 | if (!subtrees.Contains(gx)) gx = v; 363 | int gy = uf.Find(y); 364 | if (!subtrees.Contains(gy)) gy = v; 365 | 366 | //x and y are now the representatives of their original components 367 | if (kuf.Find(gx) != kuf.Find(gy)) { 368 | cedges.Insert(a); 369 | kuf.Union(gx, gy); 370 | altcost += cost; 371 | picked++; 372 | if (picked == goal) break; //done building the tree 373 | } 374 | } 375 | if (high_verbose) { 376 | fprintf (stderr, "Alternative has %d edges and cost %.2f (subtrees:%d).\n", picked, altcost, subtrees.Count()); 377 | fflush(stderr); 378 | } 379 | 380 | if (verbose && picked!=goal) {fprintf(stderr, "VEDISCONNECTED");} 381 | 382 | if (picked == goal) { 383 | //Console.Error.WriteLine("GOT HERE! NOW TRYING!"); 384 | if (high_verbose) fprintf (stderr, "Cost: %.2f -> %.2f.", (double)remcost, (double)altcost); 385 | double impcost = remcost - altcost; //improvement 386 | if (impcost > EDGE_COST_PRECISION) { 387 | //found an improving move! change the solution 388 | improvements++; 389 | 390 | bool local_verbose = verbose; 391 | if (local_verbose) fprintf(stderr, "I%.2f->%.2f %.2f->", (double)remcost, (double)altcost, (double)solution.GetCost()); 392 | 393 | //remove all neighboring edges 394 | SPGArc *a, *end; 395 | 396 | if (local_verbose) solution.Output(stderr); 397 | 398 | int removals = 0; 399 | //for (int pa = g.GetStart(v); pa < g.GetEnd(v); pa++) { 400 | for (g.GetBounds(v,a,end); alabel)) { //will do nothing if the solution is not there 402 | removals ++; 403 | if (local_verbose) { 404 | fprintf (stderr, "Removing %d=(%d,%d) with cost %d.\n", a->label, v, a->head, a->cost); 405 | if (solution.Contains(a->label)) fatal ("Something bad!\n"); 406 | } 407 | } 408 | } 409 | 410 | if (local_verbose) fprintf (stderr, "Removed vertex %d with %d incident edges (remcost=%d altcost=%d).\n", v, removals, remcost, altcost); 411 | 412 | //add new edges 413 | //foreach (int newedge in cedges.ElementEnumerator()) { 414 | int insertions = 0; 415 | int p, pend; 416 | for (cedges.GetBounds(p,pend); phead; //g.GetArcHead(pa); //varc.head; 481 | if (!svertices.Contains(w)) continue; //edge must link to other original solution vertex 482 | if (subtrees.Contains(uf.Find(w))) continue; //edge must not go to subtree 483 | int alabel = a->label; //g.GetArcLabel(pa); //varc.label; 484 | if (id2parc[v] == alabel) continue; //edge must not go to original parent 485 | 486 | //get unique label for the directed version of the arc 487 | int dlabel = (v < w) ? alabel : alabel + m; 488 | //if (verbose) {fprintf (stderr, "i(%d,%d) with label %d (alabel:%d).", v, w, dlabel, alabel); fflush(stderr);} 489 | heap.Insert(v, dlabel, a->cost); //g.GetArcCost(pa)); //varc.cost); 490 | if (verbose) fprintf (stderr, "Inserted (%d,%d) into heap %d.\n", v, w, v); 491 | insertions++; 492 | } 493 | } 494 | 495 | if (verbose) fprintf(stderr, "Made %d insertions to heap %d.\n", insertions, v); 496 | 497 | //unite heap for v and its subtrees 498 | int rep = v; //new representative of the heap 499 | //foreach (int subrep in subtrees.ElementEnumerator()) { 500 | int p, pend; 501 | for (subtrees.GetBounds(p,pend); p