diff --git a/bcp_cvrptw.cpp b/bcp_cvrptw.cpp index c829ad9e0a86bf899b84ae73d3772db8ff272f0d..9246fe40dbe58945677e0fba30884d3061008414 100644 --- a/bcp_cvrptw.cpp +++ b/bcp_cvrptw.cpp @@ -36,7 +36,7 @@ c_ControllerCVRPTW::c_ControllerCVRPTW(std::string instanceFile, string schedule Solver ("Solver", 3, false ), MaxNumberSRCutsPerIteration ("MaxNumberSRCutsPerIteration", 10, false), UseSubsetRowCuts ("UseSubsetRowCuts", false, false), - MaxSRCutsPerCustomerPerIteration("MaxSRCutsPerCustomerPerIteration", INFTY, false), + MaxSRCutsPerCustomerPerIteration("MaxSRCutsPerCustomerPerIteration", (int) INFTY, false), UseCapacityCuts("UseCapacityCuts", false, false), MaxNumberCapCutsPerIteration ("MaxNumberCapCutsPerIteration", 10, false), NetworkOfTasks ("NetworkOfTasks", true, false), diff --git a/bcp_cvrptw.h b/bcp_cvrptw.h index bf4daa1d6cc78f84e7d8440062262433dd1a21ec..663bb65730e2dbeffd73a482c321ecd6c67511f0 100644 --- a/bcp_cvrptw.h +++ b/bcp_cvrptw.h @@ -26,6 +26,8 @@ extern bool schedulePartNetwork; class c_PricingSolverHierarchyCVRPTW; +//@Francesco: This file contains everything problem specific for the column generation algorithm (but not the labeling for the pricing problem). At first we probably do not need to touch it. + class c_ControllerCVRPTW : public c_Controller, public c_CVRPTW_Instance_With_RDC { c_Matrix<c_REF_CVRPTW*> m_REFs; int i_numSubsetRowCuts; @@ -119,8 +121,8 @@ public: c_IntListParameter HeuristicPricersNetworkSizes; c_IntParameter Solver; c_BoolParameter UseSubsetRowCuts; - c_DoubleParameter CutTolerance; // Epsilonwert zur �berschreitung der SRI - c_IntParameter MaxNumberSRCutsPerIteration; // zum Festlegen wieviele der Maxviolating Subsets �bernommen werden + c_DoubleParameter CutTolerance; + c_IntParameter MaxNumberSRCutsPerIteration; c_IntParameter MaxSRCutsPerCustomerPerIteration; c_IntParameter MaxCutNodeLevel; c_BoolParameter NetworkOfTasks; diff --git a/cvrptw_instance.h b/cvrptw_instance.h index 024b83d7701fd0cd2b31eb9790b6e731a2b88d91..58535a3b6a92d2a5bf3bb36154e3f58e1710af2d 100644 --- a/cvrptw_instance.h +++ b/cvrptw_instance.h @@ -25,6 +25,7 @@ bool v_contains(std::vector<T> const &v, T const &x) { return v.end() != std::find(v.begin(), v.end(), x); } +//@Francesco: This file contains everythin relevant for the instance data, especially the class c_CVRPTW_Instance musst be adapted if necessary (and accordingly in the .cpp) class c_CVRPTW_Instance { string instanceName; @@ -43,8 +44,8 @@ class c_CVRPTW_Instance { vector<double> v_demand; //demand per day. If customer is not visited every day, the demand of all following days without visit has to be fulfilled too vector<int> v_frequency; // just in case frequency is needed vector<int> v_serviceTime; - vector<int> v_startTime; // untere Zeitfenstergrenze - vector<int> v_endTime; // obere Zeitfenstergrenze + vector<int> v_startTime; // lower TW border + vector<int> v_endTime; // upper TW border vector<double> v_xCoord; vector<double> v_yCoord; int i_capacity; @@ -52,15 +53,8 @@ class c_CVRPTW_Instance { ////For every vertex (customers for every day) int i_origDepotVertex; int i_destDepotVertex; - //c_IntMatrix m_costsVertex; - //c_IntMatrix m_timesVertex; - //vector<int> v_demandVertex; //demand per day. If customer is not visited every day, the demand of all following days without visit has to be fulfilled too? - //vector<int> v_serviceTimeVertex; - //vector<int> v_startTimeVertex; // untere Zeitfenstergrenze - //vector<int> v_endTimeVertex; // obere Zeitfenstergrenze - - /*vector<int> v_frequence; - vector<int> v_maxDaysUntilNextVisit;*/ + + int i_planningHorizon; vector<vector<vector<bool>>> v_schedulesPerCustomer; //for every customer vector of all allowed schedule (a schedule is represented by bool vector saying if visit at the day ) //length of numNodes vector<c_SchedulePart*> v_scheduleParts; @@ -119,12 +113,6 @@ public: int ArcExists( int n1, int n2 ) const; //refers to nodes bool ArcExistsOnDay( int v1, int v2, int day) const; //refers to vertices - //int Frequence(int i) const; - //int MaxDaysUntilNextVisit(int i) const; - - - //vector<int> v_capacityPerVehPerDay; //for instances of Cordeau - const int PlanningHorizon() const { return i_planningHorizon;} const vector<vector<bool>>& GetAllowedSchedules( int cust ) const { return v_schedulesPerCustomer[cust];} //Schedule parts @@ -144,12 +132,6 @@ public: //void createVertices(); int OrigDepotVertex(int day = -1) const; int DestDepotVertex(int day = -1) const; - /*int CostVertex( int i, int j ) const { return m_costsVertex(i,j);} - int TimeVertex( int i, int j ) const { return m_timesVertex(i,j);} - const int DemandVertex( int i ) const { return v_demandVertex[i];} - const int ServiceTimeVertex( int i ) const { return v_serviceTimeVertex[i];} - const int StartTimeVertex(int i) const { return v_startTimeVertex[i];} - const int EndTimeVertex(int i) const { return v_endTimeVertex[i];}*/ const int GetNode( int vertex ) const; const int GetDay( int vertex ) const; @@ -182,14 +164,18 @@ public: void storeVertexInfos(); //sets i_numVertices, v_nodesOfVertices, v_daysOfVertices vector<bool> createSchedule(int maxDaysUntilNextVisit, int startDay); - //vector<int> shiftSchedule(const vector<int>& schedule, int days); void FixCustToFirstDay(int customer); }; + + + + +//@Francesco: c_CVRPTW_Instance_With_RDC should remain as it is at first /* -This is an extended version of the instance which can store reduced costs and the ng-path neighborhoods +This is an extended version of the instance which can store reduced costs, dual prices, and the ng-path neighborhoods and other stuff related to the solution method */ class c_CVRPTW_Instance_With_RDC : public c_CVRPTW_Instance { c_DoubleMatrix m_rdc; @@ -198,9 +184,7 @@ class c_CVRPTW_Instance_With_RDC : public c_CVRPTW_Instance { vector<vector<int> > v_subsetsOfCuts; std::vector<std::vector<int> > v_ng; std::vector<std::vector<int> > v_ng_index; - //For Ryan-Foster-Branching. Ggf.: TODO: Remove - /*vector<vector<int>> v_enforcedPartnersPerNode; - vector<vector<int>> v_forbiddenPartnersPerNode;*/ + public: c_CVRPTW_Instance_With_RDC(string instanceFile, string scheduleFile ); @@ -214,12 +198,6 @@ public: void SetSRIs(const vector<vector<int> >& sris){ v_subsetsOfCuts = sris;} const vector<vector<int> >& getSRIs() const {return v_subsetsOfCuts;} - //For Ryan-Foster-Branching. Ggf.: TODO: Remove - /*void ResetTogetherness(); - void SetTogetherness( int cust1, int cust2, bool together ); - const vector<int>& GetEnforcedPartners(int cust) const {return v_enforcedPartnersPerNode[cust];} - const vector<int>& GetForbiddenPartners(int cust) const {return v_forbiddenPartnersPerNode[cust];}*/ - void SetRDC( int i, int j, int day, double rdc ); double RDC( int i, int j, int day) const; void SetNGNeighborhood( int i, const vector<int>& ng_i ); diff --git a/cvrptw_ref.cpp b/cvrptw_ref.cpp index 7e0710ef4dda199a5558b8201a266a91e03cc197..0569098bd10f10fb55f45f64e441e3401a7f1090 100644 --- a/cvrptw_ref.cpp +++ b/cvrptw_ref.cpp @@ -19,10 +19,7 @@ c_ResVectorCVRPTW::c_ResVectorCVRPTW( const c_ResVectorCVRPTW& orig ) i_help = orig.i_help; l_visit = orig.l_visit; bs_SubsetRowCutactive = orig.bs_SubsetRowCutactive; - /*if( ryanFosterActive ){ - bs_enforcedCusts = orig.bs_enforcedCusts; - bs_forbiddenCusts = orig.bs_forbiddenCusts; - }*/ + } void c_ResVectorCVRPTW::OutputInStream(std::ostream& s) const @@ -47,11 +44,6 @@ bool c_REF_CVRPTW::PropagateFw( const c_ResVectorCVRPTW_Fw& old_res, c_ResVector return false; - /*if( ryanFosterActive ){ - if( old_res.bs_forbiddenCusts[i_headNode] ) - return false; - }*/ - if( taskNetwork ){ new_res.i_load = old_res.i_load + o_instance.DemandPerDay( i_headNode ); if ( new_res.i_load > o_instance.Capacity() + CGBase::CG_EPS ) @@ -79,8 +71,7 @@ bool c_REF_CVRPTW::PropagateFw( const c_ResVectorCVRPTW_Fw& old_res, c_ResVector // compute new resource values new_res.d_cost = old_res.d_cost+ o_instance.RDC( i_tail, i_head, i_day ); - //iteriere �ber alle Cuts: Wenn i_head im subset ist, dann ver�ndere bitset an dieser Stelle - //wenn Wechsel von true auf false, addiere sigma (dual-variable des betrachteten cuts) mit getSRIDual(cutId), denn Instanz kennt die Werte + //if SR-value changed to zero subtract dual price new_res.bs_SubsetRowCutactive = old_res.bs_SubsetRowCutactive ^ bs_IncrementCutCounter_Fw ; for (auto cutId = o_instance.getActiveCutIds().begin(); cutId != o_instance.getActiveCutIds().end();cutId++) { @@ -93,27 +84,6 @@ bool c_REF_CVRPTW::PropagateFw( const c_ResVectorCVRPTW_Fw& old_res, c_ResVector if ( i_headNode == o_instance.DestDepot() && new_res.d_cost > -0.00001 ) return false; - //if( ryanFosterActive ){ - // //Update enforced and forbidden custs - - // new_res.bs_enforcedCusts = old_res.bs_enforcedCusts; - // if( !old_res.bs_enforcedCusts[i_headNode] ){ //TODO: Attention: works only if each customer is included in maximal one enforced pair. Otherwise complete route has to be traversed - // for each( int partner in o_instance.GetEnforcedPartners(i_headNode) ){ - // new_res.bs_enforcedCusts[partner] = true; - // } - // } else{ //If head was enforced, job is done now - // new_res.bs_enforcedCusts[i_headNode] = false; - // } - // new_res.bs_forbiddenCusts = old_res.bs_forbiddenCusts; - // for each( int partner in o_instance.GetForbiddenPartners(i_headNode) ){ - // new_res.bs_forbiddenCusts[partner] = true; - // } - - // if( i_headNode == o_instance.DestDepot() && new_res.bs_enforcedCusts.any() ) - // //don't finish a tour without all enforced customers - // return false; - //} - // elementarity, ng-path etc. new_res.l_visit = 0; int ng_size = o_instance.NGNeighborhoodSize(i_tailNode); @@ -132,20 +102,15 @@ bool c_REF_CVRPTW::PropagateFw( const c_ResVectorCVRPTW_Fw& old_res, c_ResVector bool c_REF_CVRPTW::PropagateBw(const c_ResVectorCVRPTW_Bw& old_res, c_ResVectorCVRPTW_Bw& new_res ) const { - /*if( !IsInNetwork() ) - return false;*/ + //Branching and Network related if ( !IsActive() ) return false; int idx = o_instance.NGIndex(i_headNode, i_tailNode); if ( idx>= 0 && (old_res.l_visit & (1<<idx)) && (i_tailNode != i_headNode) ) return false; - /*if( ryanFosterActive ){ - if( old_res.bs_forbiddenCusts[i_tailNode] ) - return false; - }*/ - + // compute new resource values if( taskNetwork ){ new_res.i_load = old_res.i_load + o_instance.DemandPerDay( i_tailNode ); if ( new_res.i_load > o_instance.Capacity() + CGBase::CG_EPS ) @@ -167,11 +132,9 @@ bool c_REF_CVRPTW::PropagateBw(const c_ResVectorCVRPTW_Bw& old_res, c_ResVectorC return false; new_res.i_help = min( old_res.i_dur - o_instance.StartTime(i_headNode), old_res.i_help ); } - - // compute new resource values new_res.d_cost = old_res.d_cost + o_instance.RDC( i_tail, i_head, i_day ); - //******************************************************************************** - // entspricht exakt dem Verfahren von Forward, nur ist nun tail zu betrachten, daher bs_IncrementCutCounter_Bw + + //Subset-row new_res.bs_SubsetRowCutactive = old_res.bs_SubsetRowCutactive ^ bs_IncrementCutCounter_Bw ; for (auto cutId = o_instance.getActiveCutIds().begin(); cutId != o_instance.getActiveCutIds().end(); cutId++) { @@ -180,32 +143,10 @@ bool c_REF_CVRPTW::PropagateBw(const c_ResVectorCVRPTW_Bw& old_res, c_ResVectorC } } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // no rdc>0 at enddepot! if ( i_tailNode == o_instance.OrigDepot() && new_res.d_cost > -0.00001 ) return false; - - //if( ryanFosterActive ){ - // //Update enforced and forbidden custs - // new_res.bs_enforcedCusts = old_res.bs_enforcedCusts; - // if( !old_res.bs_enforcedCusts[i_tailNode] ){ //TODO: Attention: works only if each customer is included in maximal one enforced pair. Otherwise complete route has to be traversed - // for each( int partner in o_instance.GetEnforcedPartners(i_tailNode) ){ - // new_res.bs_enforcedCusts[partner] = true; - // } - // } else{ //If head was enforced, job is done now - // new_res.bs_enforcedCusts[i_tailNode] = false; - // } - // new_res.bs_forbiddenCusts = old_res.bs_forbiddenCusts; - // for each( int partner in o_instance.GetForbiddenPartners(i_tailNode) ){ - // new_res.bs_forbiddenCusts[partner] = true; - // } - - // if( i_tailNode == o_instance.OrigDepot() && new_res.bs_enforcedCusts.any() ) - // //don't finish a tour without all enforced customers - // return false; - //} - // elementarity, ng-path etc. new_res.l_visit = 0; int ng_size = o_instance.NGNeighborhoodSize(i_headNode); @@ -242,14 +183,6 @@ bool c_LabelCVRPTW_Fw::operator<=(const c_LabelCVRPTW_Fw& second) if( costForComparison > second.Cost() ) return false; - //if( ryanFosterActive ){ - // //for both sets it is better to have less customers set to true, more freedom - // if (exactDom && (~second.bs_enforcedCusts & bs_enforcedCusts).any()) - // return false; - // if (exactDom && (~second.bs_forbiddenCusts & bs_forbiddenCusts).any()) - // return false; - //} - for (auto cutId = p_REF->o_instance.getActiveCutIds().begin(); cutId != p_REF->o_instance.getActiveCutIds().end(); cutId++) { if (bs_SubsetRowCutactive[*cutId] && !second.bs_SubsetRowCutactive[*cutId]) costForComparison -= p_REF->o_instance.getSRIDual(*cutId); @@ -271,14 +204,6 @@ bool c_LabelCVRPTW_Bw::operator<=(const c_LabelCVRPTW_Bw& second) if( costForComparison > second.Cost() ) return false; - //if( ryanFosterActive ){ - // //for both sets it is better to have less customers set to true, more freedom - // if (exactDom && (~second.bs_enforcedCusts & bs_enforcedCusts).any()) - // return false; - // if (exactDom && (~second.bs_forbiddenCusts & bs_forbiddenCusts).any()) - // return false; - //} - for (auto cutId = p_REF->o_instance.getActiveCutIds().begin(); cutId != p_REF->o_instance.getActiveCutIds().end(); cutId++) { if (bs_SubsetRowCutactive[*cutId] && !second.bs_SubsetRowCutactive[*cutId]) costForComparison -= p_REF->o_instance.getSRIDual(*cutId); @@ -374,7 +299,7 @@ bool c_LabelCVRPTW_Bw::containsRoute(const vector<int>& route, int& nextExpected -//For Separation +//For Separation -> k-path,capacity cuts (not relevant atm) ///////////////////////////////////////////////////////////////////////////// // c_ResVectorPVRPTW_Separation diff --git a/cvrptw_ref.h b/cvrptw_ref.h index 19a0f92c02434563ea75fe5bd45acb2a11716766..dd4a08af16489883375150cefe1e22154d3ec77b 100644 --- a/cvrptw_ref.h +++ b/cvrptw_ref.h @@ -23,6 +23,8 @@ extern bool minTourDuration; extern bool exactDom; extern bool ryanFosterActive; + +//@Francesco: This file contains everything problem-specific for the labeling algorihm, especially the ressource vector for the labeling must be adapted (including its methods in the .cpp) and the methods PropagateFw and PropagateBw of the REF class c_ResVectorCVRPTW { public: // not nice but effective @@ -70,6 +72,8 @@ public: }; + + class c_REF_CVRPTW : public c_REF<c_ResVectorCVRPTW_Fw,c_ResVectorCVRPTW_Bw> { protected: @@ -147,7 +151,7 @@ public: -//For Separation +//For Separation -> k-path,capacity cuts (not relevant atm) class c_ResVectorPVRPTW_Separation { public: // not nice but effective diff --git a/espprc/dominance_mgnt_with_buckets.h b/espprc/dominance_mgnt_with_buckets.h new file mode 100644 index 0000000000000000000000000000000000000000..95dd81d87eb7fee2ad0484e5475d95391158a3ed --- /dev/null +++ b/espprc/dominance_mgnt_with_buckets.h @@ -0,0 +1,782 @@ +#ifndef ESPPTW_DOMINANCE_MGNT_WITH_BUCKET_H +#define ESPPTW_DOMINANCE_MGNT_WITH_BUCKET_H + +#include <iostream> +#include <functional> +#include <tuple> +#include <cassert> +#include <algorithm> + +#include "statistics_mgnt.h" + +///////////////////////////////////////////////////////////////////////////// +// c_Dominance_Manager_WithBuckets +///////////////////////////////////////////////////////////////////////////// + +namespace espprc +{ + +template <class Label> +struct s_Bucket { + Label* p_first_label; /* singly-linked list with those "old" labels on which the dominance algorithm has already been run */ + Label* p_first_added_label; /* singly-linked list with "new" labels, dominance algorithm has NOT been run */ + bool b_old_labels_tested_interbucket; +}; + + +template <class Label, class tTuple, class StatManager = c_EmptyStatisticsManager> +class c_Dominance_Manager_WithBuckets { +protected: + bool b_fw; + int i_node; + int i_bm_bucket_index; + int i_added_labels; + tTuple t_streckfaktor; + int i_startTime; + tTuple t_numBuckets; + std::vector<int> v_activeBuckets; + int i_lastActiveBucket; + //const my_tuple t_max_size; + std::function<tTuple(const Label&, const tTuple&, int)> f_bucket_assign; + std::function<int(int, int, int, int)> f_bm_bucket_index_assign; + std::vector<s_Bucket<Label> > v_buckets; + Label* apply_dominance(Label*& p_first_label, Label*& p_first_added_label, bool old_labels_tested_interbucket); // return value is first label to delete + Label* apply_dominance_interbucket(Label*& p_labels_to_dominate, Label* p_dominator_labels); + void Sort(Label*& start, std::function<bool(Label*, Label*)>* sorter); + std::function<bool(Label*, Label*)>* f_breakingCriterion; + std::function<bool(Label*, Label*)>* f_sorter; + void Reverse(Label*& start); + StatManager o_initial_stat; + StatManager* p_stat; +public: + c_Dominance_Manager_WithBuckets(); + void SetInfo(bool fw, int node) { b_fw = fw; i_node = node; } + + void insert(Label*); + Label* apply_dominance(int bm_bucket_index = -1); // return value is first label to delete + Label* apply_final_dominance(int bm_bucket_index = -1); + Label* begin(); // iterate over all undominated labels + Label* next(Label* current); + void clear(); + int size() const { return i_added_labels; } + void OutputInStream(std::ostream& s) const; // Output all Label of this dominance manager + void Sort(std::function<bool(Label*, Label*)>* sorter); + void SetAssignmentFunction(std::function<tTuple(const Label&, const tTuple&, int)> bucket_assign) { f_bucket_assign = bucket_assign; } + void SetBMBucketIndexAssignmentFunction(std::function<int(int, int, int, int)> bm_bucket_index_assign) { f_bm_bucket_index_assign = bm_bucket_index_assign; } + void SetStreckfaktor(tTuple fact, tTuple numBuckets); + void SetStartTime(int time){ i_startTime = time; } + const vector<int>& ActiveBucketsSorted(); + Label* begin(int bucket); // iterate over all undominated labels + Label* next(int bucket, Label* current); + void SortAllBuckets(std::function<bool(Label*, Label*)>* sorter); + void SortBucket(std::function<bool(Label*, Label*)>* sorter, int bucket); + void Splice(Label*& p_first_label, Label*& p_first_added_label); + void SetSortingFunction(std::function<bool(Label*, Label*)>* sorter) { f_sorter = sorter; } + void SetBreakingCriterionFunction(std::function<bool(Label*, Label*)>* breakingCriterion) { f_breakingCriterion = breakingCriterion; } + void ReverseAllBuckets(); + void ReverseBucket(int bucket); + void ResetOldLabelsTestedInterbucket(int currentExtensionManagerBucket); + void OutputOldBucketsTested(); + void SetStatisticsManager(StatManager& stat) { p_stat = &stat; } + StatManager& StatisticsManager() { return *p_stat; } + void PrepareForWarmstart(int currentExtensionManagerBucket); +#ifdef SPPRC_CHECK_PATH + void CheckDominance(Label* label1, Label* label2); +#endif +}; + + +template <class Label, class tTuple, class StatManager> +c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::c_Dominance_Manager_WithBuckets() +: i_bm_bucket_index(-1), + i_added_labels(0), + i_lastActiveBucket(0), + o_initial_stat(), + p_stat(&o_initial_stat) +{} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::SetStreckfaktor(tTuple fact, tTuple numBuckets) +{ + t_streckfaktor = fact; + t_numBuckets = numBuckets; + i_lastActiveBucket = 0; + v_activeBuckets.clear(); + v_activeBuckets.resize(get<0>(t_numBuckets)); + v_buckets.resize(get<0>(t_numBuckets)); + for (int i = 0; i < (int)v_buckets.size(); ++i) + { + v_buckets[i].p_first_label = nullptr; + v_buckets[i].p_first_added_label = nullptr; + v_buckets[i].b_old_labels_tested_interbucket = false; + } +} + + +template <class Label, class tTuple, class StatManager> +Label* c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::apply_dominance(Label*& p_first_label, Label*& p_first_added_label, bool old_labels_tested_interbucket) +{ + // if there are no additional labels then there are no labels in dominance + if (!p_first_added_label) + return NULL; + Label* ret_labels_to_del = NULL; + //Sort new labels (old ones are already sorted) + Sort(p_first_added_label, f_sorter); + // dominance between two new labels (quick solution: test in both directions) + Label* pred_new1 = NULL; + for (Label* curr_new1 = p_first_added_label; + curr_new1; + pred_new1 = curr_new1, curr_new1 = (curr_new1 ? curr_new1->next() : NULL)) + { + Label* pred_new2 = curr_new1; + for (Label* curr_new2 = curr_new1->next(); curr_new2; /**/) + { + p_stat->OnDominanceTest(b_fw, i_node); + if (*curr_new1 <= *curr_new2) + { // new1 dominates new2 +#ifdef SPPRC_CHECK_PATH + CheckDominance(curr_new1, curr_new2); +#endif + pred_new2->set_next(curr_new2->next()); + curr_new2->set_next(ret_labels_to_del); + ret_labels_to_del = curr_new2; + + curr_new2 = pred_new2->next(); + i_added_labels--; + } + else + { + p_stat->OnDominanceTest(b_fw, i_node); + if (*curr_new2 <= *curr_new1) + { // new2 dominates new1 +#ifdef SPPRC_CHECK_PATH + CheckDominance(curr_new2, curr_new1); +#endif + if (pred_new1) + pred_new1->set_next(curr_new1->next()); + else + p_first_added_label = curr_new1->next(); + curr_new1->set_next(ret_labels_to_del); + ret_labels_to_del = curr_new1; + + curr_new1 = (pred_new1 ? pred_new1->next() : p_first_added_label); + curr_new2 = curr_new1->next(); + pred_new2 = curr_new1; + i_added_labels--; + } + else // no domination + { + pred_new2 = curr_new2; + curr_new2 = curr_new2->next(); + } + } + } + } + // old dominates new labels + Label* pred_old = NULL; + for (Label* curr_old = p_first_label; curr_old; + pred_old = curr_old, curr_old = (curr_old ? curr_old->next() : NULL)) + { + Label* pred_new = NULL; + for (Label* curr_new = p_first_added_label; curr_new; /**/) + { + if ((*f_breakingCriterion)(curr_old, curr_new)) + break; + p_stat->OnDominanceTest(b_fw, i_node); + if (*curr_old <= *curr_new) + { // old dominates new +#ifdef SPPRC_CHECK_PATH + CheckDominance(curr_old, curr_new); +#endif + if (pred_new) + pred_new->set_next(curr_new->next()); + else + p_first_added_label = curr_new->next(); + curr_new->set_next(ret_labels_to_del); + ret_labels_to_del = curr_new; + curr_new = (pred_new ? pred_new->next() : p_first_added_label); + i_added_labels--; + } + else // no dominance + { + pred_new = curr_new; + curr_new = curr_new->next(); + } + } + } + // new dominates old labels + Label* pred_new = NULL; + for (Label* curr_new = p_first_added_label; curr_new; + pred_new = curr_new, curr_new = (curr_new ? curr_new->next() : NULL)) + { + Label* pred_old = NULL; + for (Label* curr_old = p_first_label; curr_old; /**/) + { + if ((*f_breakingCriterion)(curr_new, curr_old)) + break; + p_stat->OnDominanceTest(b_fw, i_node); + if (*curr_new <= *curr_old) + { // new dominates old +#ifdef SPPRC_CHECK_PATH + CheckDominance(curr_new, curr_old); +#endif + if (pred_old) + pred_old->set_next(curr_old->next()); + else + p_first_label = curr_old->next(); + curr_old->set_next(ret_labels_to_del); + ret_labels_to_del = curr_old; + curr_old = (pred_old ? pred_old->next() : p_first_label); + i_added_labels--; + } + else // no dominance + { + pred_old = curr_old; + curr_old = curr_old->next(); + } + } + } + //splice (both lists are sorted) + //New labels stay new when the bm_bucket index is smaller than the index of this bucket, because they should be tested against other buckets; set them old after these tests + if (!old_labels_tested_interbucket) + { + if (p_first_label && p_first_added_label) + Splice(p_first_label, p_first_added_label); + else if (p_first_added_label) + p_first_label = p_first_added_label; + p_first_added_label = NULL; + } + return ret_labels_to_del; +} + + +template <class Label, class tTuple, class StatManager> +Label* c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::apply_dominance_interbucket(Label*& p_labels_to_dominate, Label* p_dominator_labels) +{ + // if there are no additional labels then there are no labels in dominance + if (!p_labels_to_dominate || !p_dominator_labels) + return NULL; + Label* ret_labels_to_del = NULL; + // dominance between old and new labels + Label* pred_old = NULL; + for (Label* curr_old = p_dominator_labels; curr_old; + pred_old = curr_old, curr_old = (curr_old ? curr_old->next() : NULL)) + { + Label* pred_new = NULL; + for (Label* curr_new = p_labels_to_dominate; curr_new; /**/) + { + if ((*f_breakingCriterion)(curr_old, curr_new)) + break; + p_stat->OnDominanceTest(b_fw, i_node); + if (*curr_old < *curr_new) + { // old dominates new +#ifdef SPPRC_CHECK_PATH + CheckDominance(curr_old, curr_new); +#endif + if (pred_new) + pred_new->set_next(curr_new->next()); + else + p_labels_to_dominate = curr_new->next(); + curr_new->set_next(ret_labels_to_del); + ret_labels_to_del = curr_new; + curr_new = (pred_new ? pred_new->next() : p_labels_to_dominate); + i_added_labels--; + } + else // no dominance + { + pred_new = curr_new; + curr_new = curr_new->next(); + } + } + } + // those labels to delete + return ret_labels_to_del; +} + + +template <class Label, class tTuple, class StatManager> +Label* c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::apply_dominance(int bm_bucket_index) +{ + i_bm_bucket_index = bm_bucket_index; + Label* first_to_delete = nullptr; + for (int k = 0; k < i_lastActiveBucket; ++k) + { + int i = v_activeBuckets[k]; + s_Bucket<Label>& bucket = v_buckets[i]; + Label* new_to_delete = apply_dominance(bucket.p_first_label, bucket.p_first_added_label, bucket.b_old_labels_tested_interbucket); + if (new_to_delete) + { + // determine last element in singly-linked list + Label* last = new_to_delete; + while (last->next()) + last = last->next(); + last->set_next(first_to_delete); + first_to_delete = new_to_delete; + } + } + // if current i_bm_bucket_index is not in node TW + int streckindex = f_bm_bucket_index_assign(i_bm_bucket_index, i_startTime, get<0>(t_streckfaktor), get<0>(t_numBuckets)); + if (streckindex < 0 || streckindex >= get<0>(t_numBuckets)) + return first_to_delete; + // dominance between different buckets + //for (int k = 0; k < i_lastActiveBucket;) + //{ + // int position = v_activeBuckets[k]; + // if (position != streckindex) + // { + // ++k; + // continue; + // } + s_Bucket<Label>& bucket_to_dominate = v_buckets[streckindex]; + for (int k2 = 0; k2 < i_lastActiveBucket; ++k2) + { + int positionDominator = v_activeBuckets[k2]; + if (streckindex <= positionDominator) + continue; + s_Bucket<Label>& dominator_bucket = v_buckets[positionDominator]; + //compare new labels against old from dominator bucket + Label* new_to_delete = apply_dominance_interbucket(bucket_to_dominate.b_old_labels_tested_interbucket ? bucket_to_dominate.p_first_added_label : bucket_to_dominate.p_first_label, dominator_bucket.p_first_label); + if (new_to_delete) + { + Label* last = new_to_delete; + while (last->next()) + last = last->next(); + last->set_next(first_to_delete); + first_to_delete = new_to_delete; + } + if (!bucket_to_dominate.p_first_added_label && !bucket_to_dominate.p_first_label) + { + for (int i = 0; i < i_lastActiveBucket; ++i) + { + if (streckindex == v_activeBuckets[i]) + { + --i_lastActiveBucket; + swap(v_activeBuckets[i], v_activeBuckets[i_lastActiveBucket]); + return first_to_delete; + } + } + } + } + if (bucket_to_dominate.p_first_label && bucket_to_dominate.p_first_added_label) + Splice(bucket_to_dominate.p_first_label, bucket_to_dominate.p_first_added_label); + else if (bucket_to_dominate.p_first_added_label) + bucket_to_dominate.p_first_label = bucket_to_dominate.p_first_added_label; + bucket_to_dominate.p_first_added_label = NULL; + bucket_to_dominate.b_old_labels_tested_interbucket = true; + return first_to_delete; +} + + +template <class Label, class tTuple, class StatManager> +Label* c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::apply_final_dominance(int bm_bucket_index) +{ + i_bm_bucket_index = bm_bucket_index; + Label* first_to_delete = nullptr; + for (int k = 0; k < i_lastActiveBucket; ++k) + { + int i = v_activeBuckets[k]; + s_Bucket<Label>& bucket = v_buckets[i]; + //bucket.b_old_labels_tested_interbucket = false; + Label* new_to_delete = apply_dominance(bucket.p_first_label, bucket.p_first_added_label, bucket.b_old_labels_tested_interbucket); + if (new_to_delete) + { + // determine last element in singly-linked list + Label* last = new_to_delete; + while (last->next()) + last = last->next(); + last->set_next(first_to_delete); + first_to_delete = new_to_delete; + } + } + int streckindex = f_bm_bucket_index_assign(i_bm_bucket_index, i_startTime, get<0>(t_streckfaktor), get<0>(t_numBuckets)); + if (streckindex < 0 || streckindex >= get<0>(t_numBuckets)) + return first_to_delete; + // dominance between different buckets + for (int k = 0; k < i_lastActiveBucket;) + { + int position = v_activeBuckets[k]; + s_Bucket<Label>& bucket_to_dominate = v_buckets[position]; + + for (int k2 = 0; k2 < i_lastActiveBucket; ++k2) + { + if (k == k2) + continue; + int positionDominator = v_activeBuckets[k2]; + s_Bucket<Label>& dominator_bucket = v_buckets[positionDominator]; + if (position > positionDominator) + { + //compare new labels against old from dominator bucket + //this is always done, for buckets in same column and others + Label* new_to_delete = apply_dominance_interbucket(bucket_to_dominate.b_old_labels_tested_interbucket ? bucket_to_dominate.p_first_added_label : bucket_to_dominate.p_first_label, dominator_bucket.p_first_label); + if (new_to_delete) + { + Label* last = new_to_delete; + while (last->next()) + last = last->next(); + last->set_next(first_to_delete); + first_to_delete = new_to_delete; + } + if (!bucket_to_dominate.p_first_added_label && !bucket_to_dominate.p_first_label) + { + --i_lastActiveBucket; + swap(v_activeBuckets[k], v_activeBuckets[i_lastActiveBucket]); + --k; + break; + } + } + } + ++k; + } + for (int k = 0; k < i_lastActiveBucket; ++k) + { + int position = v_activeBuckets[k]; + s_Bucket<Label>& bucket_to_dominate = v_buckets[position]; + if (bucket_to_dominate.p_first_label && bucket_to_dominate.p_first_added_label) + Splice(bucket_to_dominate.p_first_label, bucket_to_dominate.p_first_added_label); + else if (bucket_to_dominate.p_first_added_label) + bucket_to_dominate.p_first_label = bucket_to_dominate.p_first_added_label; + bucket_to_dominate.p_first_added_label = NULL; + //bucket_to_dominate.b_old_labels_tested_interbucket = true; + } + return first_to_delete; +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::OutputInStream(std::ostream& s) const +{ + for (int i = 0; i < (int)v_buckets.size(); ++i) + { + Label* label = v_buckets[i].p_first_label; + while (label) + { + label->OutputInStream(s); + s << endl; + label = label->next(); + } + } + s << "________________" << endl; +} + + +template <class Label, class tTuple, class StatManager> +Label* c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::next(Label* current) +{ + if (current->next()) + return current->next(); + tTuple key(f_bucket_assign(*current, t_streckfaktor, get<0>(t_numBuckets))); + assert(get<0>(key) >= 0); + int position = get<0>(key); + for (int i = position+1; i < (int)v_buckets.size(); ++i) + if (v_buckets[i].p_first_label) + return v_buckets[i].p_first_label; + return nullptr; +} + + +template <class Label, class tTuple, class StatManager> +Label* c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::begin() +{ + for (int i = 0; i < (int)v_buckets.size(); ++i) + if (v_buckets[i].p_first_label) + return v_buckets[i].p_first_label; + return nullptr; +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::insert(Label* new_label) +{ + p_stat->OnLabelInserted(b_fw, i_node); + // insert into singly-linked list right at the beginning + i_added_labels++; + tTuple key(f_bucket_assign(*new_label, t_streckfaktor, get<0>(t_numBuckets))); + assert(get<0>(key) >= 0); + int position = get<0>(key); + if (v_buckets[position].p_first_added_label || v_buckets[position].p_first_label) + { + new_label->set_next(v_buckets[position].p_first_added_label); + v_buckets[position].p_first_added_label = new_label; + } + else + { + new_label->set_next(nullptr); + v_buckets[position].p_first_label = nullptr; + v_buckets[position].p_first_added_label = new_label; + int streckindex = f_bm_bucket_index_assign(i_bm_bucket_index, i_startTime, get<0>(t_streckfaktor), get<0>(t_numBuckets)); + if (i_bm_bucket_index >= 0 && get<0>(key) == streckindex) + v_buckets[position].b_old_labels_tested_interbucket = true; + else + v_buckets[position].b_old_labels_tested_interbucket = false; + v_activeBuckets[i_lastActiveBucket++] = position; + } +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::clear() +{ + i_added_labels = 0; + //for (int i = 0; i < (int)v_buckets.size(); ++i) + for (int k = 0; k < i_lastActiveBucket; ++k) + { + int i = v_activeBuckets[k]; + s_Bucket<Label>& bucket = v_buckets[i]; + Label* p_first_label = bucket.p_first_label; + while (p_first_label) + { + Label* help = p_first_label; + p_first_label = p_first_label->next(); + delete help; + } + Label* p_first_added_label = bucket.p_first_added_label; + while (p_first_added_label) + { + Label* help = p_first_added_label; + p_first_added_label = p_first_added_label->next(); + delete help; + } + bucket.p_first_label = nullptr; + bucket.p_first_added_label = nullptr; + bucket.b_old_labels_tested_interbucket = false; + } + i_bm_bucket_index = -1; + i_lastActiveBucket = 0; +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label,tTuple, StatManager>::Sort(std::function<bool(Label*, Label*)>* sorter) +{ + cout << "c_Bucket_Dominance_Manager does not allow global sorting of all labels." << endl; + throw; +} + + +template <class Label, class tTuple, class StatManager> +const vector<int>& c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::ActiveBucketsSorted() +{ + sort(v_activeBuckets.begin(), v_activeBuckets.begin() + i_lastActiveBucket); + return v_activeBuckets; +} + + +template <class Label, class tTuple, class StatManager> +Label* c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::begin(int bucket) +{ + return v_buckets[bucket].p_first_label; +} + + +template <class Label, class tTuple, class StatManager> +Label* c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::next(int bucket, Label* current) +{ + return current->next(); +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::SortAllBuckets(std::function<bool(Label*, Label*)>* sorter) +{ + for (int k = 0; k < i_lastActiveBucket; ++k) + SortBucket(sorter, v_activeBuckets[k]); +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::SortBucket(std::function<bool(Label*, Label*)>* sorter, int bucket) +{ + Sort(v_buckets[bucket].p_first_label, sorter); +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::Sort(Label*& from, std::function<bool(Label*, Label*)>* sorter) +{ + // trivial cases + if (from == NULL || from->next() == NULL) + return; + if (from->next()->next() == NULL) // only two labels + { + if (!(*sorter)(from, from->next())) + { + Label* new_start = from->next(); + from->next()->set_next(from); + from->set_next(NULL); + from = new_start; + } + return; + } + // Split in the middle + int length = 0; + Label* it = from; + Label* mid = from; + while (it) + { + it = it->next(); + length++; + if (length % 2 == 0 && it) + mid = mid->next(); + } + // Sort each part + Label* right = mid->next(); + mid->set_next(NULL); + Sort(from, sorter); + Sort(right, sorter); + // Merge both parts together + Label* result = NULL; + Label* last = NULL; + while (from && right) + { + if (result == NULL) + { + if ((*sorter)(from, right)) + result = from; + else + result = right; + } + if ((*sorter)(from, right)) + { + if (last) + last->set_next(from); + last = from; + from = from->next(); + } + else + { + if (last) + last->set_next(right); + last = right; + right = right->next(); + } + } + // add remaining parts + if (from) + last->set_next(from); + if (right) + last->set_next(right); + // return resulting start label + from = result; +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::Splice(Label*& p_first_label, Label*& p_first_added_label) +{ + Label* result = NULL; + Label* last = NULL; + while (p_first_added_label && p_first_label) + { + if (result == NULL) + { + if ((*f_sorter)(p_first_added_label, p_first_label)) + result = p_first_added_label; + else + result = p_first_label; + } + if ((*f_sorter)(p_first_added_label, p_first_label)) + { + if (last) + last->set_next(p_first_added_label); + last = p_first_added_label; + p_first_added_label = p_first_added_label->next(); + } + else + { + if (last) + last->set_next(p_first_label); + last = p_first_label; + p_first_label = p_first_label->next(); + } + } + // add remaining parts + if (p_first_added_label) + last->set_next(p_first_added_label); + if (p_first_label) + last->set_next(p_first_label); + p_first_label = result; +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::ReverseAllBuckets() +{ + for (int k = 0; k < i_lastActiveBucket; ++k) + ReverseBucket(v_activeBuckets[k]); +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::ReverseBucket(int bucket) +{ + Reverse(v_buckets[bucket].p_first_label); +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::Reverse(Label*& start) +{ + Label* prev = NULL; + Label* current = start; + Label* next = NULL; + while (current != NULL) + { + next = current->next(); + current->set_next(prev); + prev = current; + current = next; + } + start = prev; +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::ResetOldLabelsTestedInterbucket(int currentExtensionManagerBucket) +{ + int streckindex = f_bm_bucket_index_assign(currentExtensionManagerBucket, i_startTime, get<0>(t_streckfaktor), get<0>(t_numBuckets)); + //if (streckindex < 0 || streckindex >= get<0>(t_numBuckets)) + // return; + for (int k = 0; k < i_lastActiveBucket; ++k) + { + int i = v_activeBuckets[k]; + if (i > streckindex) + v_buckets[i].b_old_labels_tested_interbucket = false; + else + v_buckets[i].b_old_labels_tested_interbucket = true; + } +} + + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::OutputOldBucketsTested() +{ + for (int k = 0; k < i_lastActiveBucket; ++k) + { + int i = v_activeBuckets[k]; + cout << "Bucket " << i << " b_old_labels_tested_interbucket is set to " << (v_buckets[i].b_old_labels_tested_interbucket ? "true" : "false") << endl; + } +} + +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::PrepareForWarmstart(int currentExtensionManagerBucket) +{ + ResetOldLabelsTestedInterbucket(currentExtensionManagerBucket); +} + + +#ifdef SPPRC_CHECK_PATH +template <class Label, class tTuple, class StatManager> +void c_Dominance_Manager_WithBuckets<Label, tTuple, StatManager>::CheckDominance(Label * label1, Label * label2) +{ + if (label2->b_check_required) + { + cout << "### Label Id=" << label1->Id() << " eliminates Label Id=" << label2->Id() << "\n"; + } +} +#endif + + +} // of namespace + +#endif // of ESPPTW_DOMINANCE_MGNT_WITH_BUCKET_H \ No newline at end of file diff --git a/espprc/extension_mgnt.h b/espprc/extension_mgnt.h new file mode 100644 index 0000000000000000000000000000000000000000..b112b4be2714a1110c7f0a74e07909b956b87fd2 --- /dev/null +++ b/espprc/extension_mgnt.h @@ -0,0 +1,239 @@ +#ifndef ESPPTW_EXTENSION_MGNT_H +#define ESPPTW_EXTENSION_MGNT_H + +/* +This is what used to be a "bucket manager". + +It is however responsible to control which label +is selected next to be *extended*. Therefore, the +new terminology is "extension manager" +*/ + +#include <iostream> +#include <vector> +#include <map> + + +namespace espprc +{ + +///////////////////////////////////////////////////////////////////////////// +// c_Extension_Manager +// for ESPPRC with only positive (>0) critical resource consumptions +///////////////////////////////////////////////////////////////////////////// +// +// * should be the fastest extension manager +// * works only for instances with no REF with value 0 on the critical resource +// * LIFO: labels that are inserted last are extended first +// * dominance is invoked as soon as the last label of a bucket is finished + + +template <class Label, bool increasingRes> +class c_Extension_Manager { +protected: + int i_curr_bucket_idx; + int i_last_id; + std::vector<std::vector<Label*> > o_buckets; + bool b_invoke_dom_alg; + std::vector<int> v_position; // position for label id + // statistics + int i_added_labels; + int i_erased_labels; +public: + c_Extension_Manager(); + typedef Label tLabel; + + void insert(Label*); + void erase(Label*); + bool is_erased(int id) const; + Label* get_next(); // return and set next label to propagate + bool invoke_dominance_algorithm(); + void clear(); + + void OutputInStream(std::ostream& s) const; // IO: number of labels in current bucket + // statistics + int AddedLabels() const { return i_added_labels; } + int ErasedLabels() const { return i_erased_labels; } + int OpenLabels() const { return (i_added_labels - i_erased_labels); } + int GetBucketIndex() const { return i_curr_bucket_idx; } + void ResetBucketIndex() { increasingRes ? i_curr_bucket_idx = 0 : i_curr_bucket_idx = (int)o_buckets.size() - 1; } + void IncreaseBucketIndex(); +}; + + +template <class Label, bool increasingRes> +bool c_Extension_Manager<Label, increasingRes>::is_erased(int id) const +{ + return (v_position[id] == -1); +} + + +template <class Label, bool increasingRes> +void c_Extension_Manager<Label, increasingRes>::clear() +{ + int buckets_size = (int)o_buckets.size(); + for (int i = 0; i < buckets_size; i++) + o_buckets[i].clear(); + i_curr_bucket_idx = 0; + b_invoke_dom_alg = true; + i_added_labels = 0; + i_erased_labels = 0; + i_last_id = -1; +} + + +template <class Label, bool increasingRes> +void c_Extension_Manager<Label, increasingRes>::OutputInStream(std::ostream& s) const +{ + s << "Labels in Bucket " << i_curr_bucket_idx << ":" << o_buckets[i_curr_bucket_idx].size() << endl; +} + + +template <class Label, bool increasingRes> +c_Extension_Manager<Label, increasingRes>::c_Extension_Manager() +: i_curr_bucket_idx(0), + i_last_id(-1), + b_invoke_dom_alg(true), + i_added_labels(0), + i_erased_labels(0) +{} + + +template <class Label, bool increasingRes> +bool c_Extension_Manager<Label, increasingRes>::invoke_dominance_algorithm() +{ + if (b_invoke_dom_alg) + { + b_invoke_dom_alg = false; + return true; + } + return false; +} + + +template <class Label, bool increasingRes> +Label* c_Extension_Manager<Label, increasingRes>::get_next() +{ + Label* ret = nullptr; + while (!ret) + { + if (increasingRes) + { + while (i_curr_bucket_idx < (int)o_buckets.size() && o_buckets[i_curr_bucket_idx].empty()) + { + i_curr_bucket_idx++; + b_invoke_dom_alg = true; + } + } + else + { + while (i_curr_bucket_idx >= 0 && o_buckets[i_curr_bucket_idx].empty()) + { + i_curr_bucket_idx--; + b_invoke_dom_alg = true; + } + } + // nothing left? + if (i_curr_bucket_idx < 0 || i_curr_bucket_idx >= (int)o_buckets.size()) + { + i_last_id = -1; + return nullptr; + } + // otherwise erase and return first element + vector<Label*>& the_bucket = o_buckets[i_curr_bucket_idx]; + while (!the_bucket.empty() && !the_bucket.back()) + the_bucket.pop_back(); + if (the_bucket.empty()) + continue; + ret = the_bucket.back(); + the_bucket.pop_back(); + i_last_id = ret->Id(); + //// Find out if the next non-null label is still in the same bucket + //// If not, invoke the dominance algorithm + //while (!the_bucket.empty() && !the_bucket.back()) + // the_bucket.pop_back(); + //if (the_bucket.empty()) + // b_invoke_dom_alg = true; + } + i_erased_labels++; + return ret; +} + + +template <class Label, bool increasingRes> +void c_Extension_Manager<Label, increasingRes>::erase(Label* label) +{ + int id = label->Id(); + int idx = v_position[id]; + v_position[id] = -1; + int res_val = (*label)(); + + if ((int)o_buckets[res_val].size() > idx) + { + o_buckets[res_val][idx] = nullptr; + i_erased_labels++; + } +} + + +// insert element to bucket container +template <class Label, bool increasingRes> +void c_Extension_Manager<Label, increasingRes>::insert(Label* label) +{ + i_added_labels++; + int res_val = (*label)(); + if (increasingRes) + { + //for an increasing resource, extend the bucket-container + if (res_val >= (int)o_buckets.size()) + o_buckets.resize(2 * res_val + 1); + } + else + { + //set the current bucket index to the end, when insert is done for the first time + if (res_val >= (int)o_buckets.size()) + o_buckets.resize(res_val + 1); + //decreasing resource can never be less than the current bucket index, but when a new pricing iteration is started + if (res_val > i_curr_bucket_idx) + i_curr_bucket_idx = res_val; + } + int idx = (int)o_buckets[res_val].size(); + o_buckets[res_val].push_back(label); + if ((int)v_position.size() <= label->Id()) + { + v_position.resize(2 * label->Id() + 1, -1); + } + v_position[label->Id()] = idx; +} + + +template <class Label, bool increasingRes> +void c_Extension_Manager<Label, increasingRes>::IncreaseBucketIndex() +{ + do + { + if (increasingRes) + { + while (i_curr_bucket_idx < (int)o_buckets.size() && o_buckets[i_curr_bucket_idx].empty()) + i_curr_bucket_idx++; + } + else + { + while (i_curr_bucket_idx >= 0 && o_buckets[i_curr_bucket_idx].empty()) + i_curr_bucket_idx--; + } + // nothing left? + if (i_curr_bucket_idx < 0 || i_curr_bucket_idx >= (int)o_buckets.size()) + return; + // otherwise check if there are non-eliminated labels in this bucket + vector<Label*>& the_bucket = o_buckets[i_curr_bucket_idx]; + while (!the_bucket.empty() && !the_bucket.back()) + the_bucket.pop_back(); + } while (o_buckets[i_curr_bucket_idx].empty()); +} + + + +}; // of namespace + +#endif // ESPPTW_EXTENSION_MGNT_H \ No newline at end of file diff --git a/espprc/extension_mgnt_zero_consumption.h b/espprc/extension_mgnt_zero_consumption.h new file mode 100644 index 0000000000000000000000000000000000000000..c5eec8c910dddc048ddf5d74e2ab6f9ac10ec0d8 --- /dev/null +++ b/espprc/extension_mgnt_zero_consumption.h @@ -0,0 +1,229 @@ +#ifndef ESPPTW_EXTENSION_MGNT_ZERO_EXT_H +#define ESPPTW_EXTENSION_MGNT_ZERO_EXT_H + +/* +This is what used to be a "bucket manager". + +It is however responsible to control which label +is selected next to be *extended*. Therefore, the +new terminology is "extension manager" +*/ + +#include <iostream> +#include <vector> +#include <map> + + +namespace espprc +{ + +///////////////////////////////////////////////////////////////////////////// +// c_Extension_Manager_ZeroConsumption +// for ESPPRC with critical resource consuming 0 units +///////////////////////////////////////////////////////////////////////////// +// +// * should be the second fastest bucket manager, much faster than the c_Bucket_Manager_UsingUnorderedMap +// * works for instances with REFs with value 0 on the critical resource +// +// * Differs from c_Bucket_Manager_UsingVector by: +// * 1. FIFO: labels that are inserted first are extended first (a little bit less efficient) +// * 2. Dominance is invoked after every label extension (more costly) + + +/* This is the only implementation of a extension manager that can handle REFs with increase 0 in the critical +resource defining the bucket index. It is guaranteed that for identical critical resource values a label +with smaller ID is extended before any other label with larger ID (same critical resource). */ + + +template <class Label, bool increasingRes> +class c_Extension_Manager_ZeroConsumption { +protected: + int i_curr_bucket_idx; + std::vector<std::vector<Label*> > o_buckets; + std::vector<int> v_position; // position for label id + // statistics + int i_added_labels; + int i_erased_labels; + int i_pos_in_curr_bucket; +public: + c_Extension_Manager_ZeroConsumption(); + typedef Label tLabel; + + void insert( Label* ); + void erase( Label* ); + bool is_erased(int id) const; + Label* get_next(); // return and set next label to propagate + bool invoke_dominance_algorithm(); + void clear(); + + void OutputInStream( std::ostream& s ) const; // IO: number of labels in current bucket + // statistics + int AddedLabels() const { return i_added_labels; } + int ErasedLabels() const { return i_erased_labels; } + int OpenLabels() const { return (i_added_labels - i_erased_labels); } + int GetBucketIndex() const { return i_curr_bucket_idx; } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// implementation +//////////////////////////////////////////////////////////////////////////////////////////////////////// + + +template <class Label, bool increasingRes> +c_Extension_Manager_ZeroConsumption<Label, increasingRes>::c_Extension_Manager_ZeroConsumption() +: i_curr_bucket_idx (0), + i_added_labels(0), + i_erased_labels(0), + i_pos_in_curr_bucket(0) +{} + + +template <class Label, bool increasingRes> +bool c_Extension_Manager_ZeroConsumption<Label, increasingRes>::invoke_dominance_algorithm() +{ + //Dominance has to be checked after every label extension in case of REFs with value 0 on critical resource: + //Several labels inside the same bucket could be created when the bucket is already started, which dominate each other. + //But they are already extended when dominance is invoked only at the end of a bucket + // -> dominance of an extended label leads to access on deleted memory! + return true; +} + + +template <class Label, bool increasingRes> +bool c_Extension_Manager_ZeroConsumption<Label, increasingRes>::is_erased(int id) const +{ + return (v_position[id] == -1); +} + + +template <class Label, bool increasingRes> +void c_Extension_Manager_ZeroConsumption<Label, increasingRes>::clear() +{ + int buckets_size = (int)o_buckets.size(); + for (int i = 0; i < buckets_size;i++) + o_buckets[i].clear(); + i_curr_bucket_idx = 0; + i_added_labels = 0; + i_erased_labels = 0; + i_pos_in_curr_bucket = 0; +} + + +template <class Label, bool increasingRes> +void c_Extension_Manager_ZeroConsumption<Label, increasingRes>::OutputInStream(std::ostream& s) const +{ + s << "Labels in Bucket " << i_curr_bucket_idx << ":" << o_buckets[i_curr_bucket_idx].size() << endl; +} + + +//more clear and efficient version of Jean-Bertrand: +template <class Label, bool increasingRes> +Label* c_Extension_Manager_ZeroConsumption<Label, increasingRes>::get_next() +{ + if (increasingRes) + { + int obucketsize = (int)o_buckets.size(); + //if the end of the current bucket is passed, go to the next bucket + if (i_pos_in_curr_bucket >= (int)o_buckets[i_curr_bucket_idx].size()) + { + o_buckets[i_curr_bucket_idx].clear(); + i_pos_in_curr_bucket = 0; + do + { + if (++i_curr_bucket_idx >= obucketsize) return nullptr; + } while (o_buckets[i_curr_bucket_idx].empty()); + } + //if there is no label at the current position in the bucket, increase it (and go to next bucket if the end of the bucket is passed) + while (!(o_buckets[i_curr_bucket_idx][i_pos_in_curr_bucket])) + if (++i_pos_in_curr_bucket >= (int)o_buckets[i_curr_bucket_idx].size()) + { + o_buckets[i_curr_bucket_idx].clear(); + i_pos_in_curr_bucket = 0; + do + { + if (++i_curr_bucket_idx >= obucketsize) return nullptr; + } while (o_buckets[i_curr_bucket_idx].empty()); + } + } + else + { + if (i_pos_in_curr_bucket >= (int)o_buckets[i_curr_bucket_idx].size()) + { + o_buckets[i_curr_bucket_idx].clear(); + i_pos_in_curr_bucket = 0; + do + { + if (--i_curr_bucket_idx < 0) + return nullptr; + } while (o_buckets[i_curr_bucket_idx].empty()); + } + while (!(o_buckets[i_curr_bucket_idx][i_pos_in_curr_bucket])) + if (++i_pos_in_curr_bucket >= (int)o_buckets[i_curr_bucket_idx].size()) + { + o_buckets[i_curr_bucket_idx].clear(); + i_pos_in_curr_bucket = 0; + do + { + if (--i_curr_bucket_idx < 0) + return nullptr; + } while (o_buckets[i_curr_bucket_idx].empty()); + } + } + Label* ret = o_buckets[i_curr_bucket_idx][i_pos_in_curr_bucket]; + ++i_pos_in_curr_bucket; + ++i_erased_labels; + return ret; +} + + +template <class Label, bool increasingRes> +void c_Extension_Manager_ZeroConsumption<Label, increasingRes>::erase( Label* label ) +{ + if ((int)v_position.size() <= label->Id()) + return; + i_erased_labels++; + int idx=v_position[label->Id()]; + v_position[label->Id()] = -1; + int res_val = (*label)(); + if (idx>-1) + o_buckets[res_val][idx] = nullptr; +} + + +// insert element to bucket container +template <class Label, bool increasingRes> +void c_Extension_Manager_ZeroConsumption<Label, increasingRes>::insert( Label* label ) +{ + i_added_labels++; + int res_val = (*label)(); + if( increasingRes ) + { + //for an increasing resource, extend the bucket-container + if ( res_val >= (int)o_buckets.size() ) + o_buckets.resize( 2*res_val+1 ); + } + else + { + //set the current bucket index to the end, when insert is done for the first time + if ( res_val >= (int)o_buckets.size() ) + o_buckets.resize( res_val+1 ); + //decreasing resource can never be less than the current bucket index, but when a new pricing iteration is started + if( res_val > i_curr_bucket_idx ) + i_curr_bucket_idx = res_val; + } + int idx=(int) o_buckets[res_val].size(); + o_buckets[res_val].push_back(label); + if ((int)v_position.size()<=label->Id()) + { + v_position.resize(2*label->Id()+1,-1); + } + v_position[label->Id()]=idx; +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +}; // of namespace + +#endif // ESPPTW_EXTENSION_MGNT_ZERO_EXT_H \ No newline at end of file diff --git a/espprc/statistics_mgnt.cpp b/espprc/statistics_mgnt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a1f8e0958efd8df88d50eb1ae704a43a4aaaf9c --- /dev/null +++ b/espprc/statistics_mgnt.cpp @@ -0,0 +1,119 @@ +#include "statistics_mgnt.h" + +namespace espprc +{ + using namespace std; + + // for everything related to statistics + + void c_StatisticsManager::OnLabelInserted(bool fw, int node) + { + if (fw) + v_cnt_fw_labels_inserted[node]++; + else + v_cnt_bw_labels_inserted[node]++; + } + + void c_StatisticsManager::OnDominanceTest(bool fw, int node) + { + if (fw) + v_cnt_fw_dominance_tests[node]++; + else + v_cnt_bw_dominance_tests[node]++; + } + + + void c_StatisticsManager::OutputInStream(const c_Stopwatch& timer, std::string text, std::ostream& s) const + { + if (timer.NumStops() == 1) + { + s << text << " " << timer.FormattedTime() << " " << timer.TotalNanoseconds() << " ns" << endl; + } + if (timer.NumStops() > 1) + { + s << text << " (#=" << timer.NumStops() << ")" << endl; + s << "\tavg: " << timer.FormattedAvgTime() << " " << timer.AvgNanoseconds() << " ns" << endl; + s << "\tmin: " << timer.FormattedMinTime() << " " << timer.MinNanoseconds() << " ns" << endl; + s << "\tmax: " << timer.FormattedMaxTime() << " " << timer.MaxNanoseconds() << " ns" << endl; + } + } + + void c_StatisticsManager::resize(int num_nodes) + { + v_cnt_fw_labels_inserted.resize(num_nodes, 0); + v_cnt_bw_labels_inserted.resize(num_nodes, 0); + v_cnt_fw_dominance_tests.resize(num_nodes, 0); + v_cnt_bw_dominance_tests.resize(num_nodes, 0); + } + + + void c_StatisticsManager::OutputInStream(std::ostream& s) const + { + s << "Statistics:" << endl; + OutputInStream(o_timer_fw_labeling, "fw labeling", s); + OutputInStream(o_timer_fw_labeling_propagate, "fw propagate", s); + OutputInStream(o_timer_fw_labeling_dominance, "fw dominance", s); + // + OutputInStream(o_timer_bw_labeling, "bw labeling", s); + OutputInStream(o_timer_bw_labeling_propagate, "bw propagate", s); + OutputInStream(o_timer_bw_labeling_dominance, "bw dominance", s); + // + OutputInStream(o_timer_bidir_labeling, "bidir labeling", s); + OutputInStream(o_timer_bidir_labeling_fw_part, "bidir fw labeling", s); + OutputInStream(o_timer_bidir_labeling_fw_part_propagate, "bidir fw propagate", s); + OutputInStream(o_timer_bidir_labeling_fw_part_dominance, "bidir fw dominance", s); + OutputInStream(o_timer_bidir_labeling_bw_part, "bidir bw labeling", s); + OutputInStream(o_timer_bidir_labeling_bw_part_propagate, "bidir bw propagate", s); + OutputInStream(o_timer_bidir_labeling_bw_part_dominance, "bidir bw dominance", s); + OutputInStream(o_timer_bidir_labeling_merge, "bidir merge", s); + // + s << "Labels inserted fw: "; + for (int i = 0; i < (int)v_cnt_fw_labels_inserted.size(); i++) + if (v_cnt_fw_labels_inserted[i]) + s << "[" << i << "]:" << v_cnt_fw_labels_inserted[i] << " "; + s << endl; + s << "Labels inserted bw: "; + for (int i = 0; i < (int)v_cnt_bw_labels_inserted.size(); i++) + if (v_cnt_bw_labels_inserted[i]) + s << "[" << i << "]:" << v_cnt_bw_labels_inserted[i] << " "; + s << endl; + // + s << "Dominance tests fw: "; + for (int i = 0; i < (int)v_cnt_fw_dominance_tests.size(); i++) + if (v_cnt_fw_dominance_tests[i]) + s << "[" << i << "]:" << v_cnt_fw_dominance_tests[i] << " "; + s << endl; + s << "Dominance tests bw: "; + for (int i = 0; i < (int)v_cnt_bw_dominance_tests.size(); i++) + if (v_cnt_bw_dominance_tests[i] ) + s << "[" << i << "]:" << v_cnt_bw_dominance_tests[i] << " "; + s << endl; + } + + void c_StatisticsManager::ResetStatistics() + { + // timers + o_timer_fw_labeling.Reset(); + o_timer_bw_labeling.Reset(); + o_timer_bidir_labeling.Reset(); + o_timer_bidir_labeling_fw_part.Reset(); + o_timer_bidir_labeling_bw_part.Reset(); + o_timer_bidir_labeling_merge.Reset(); + o_timer_fw_labeling_propagate.Reset(); + o_timer_fw_labeling_dominance.Reset(); + o_timer_bw_labeling_propagate.Reset(); + o_timer_bw_labeling_dominance.Reset(); + o_timer_bidir_labeling_fw_part_propagate.Reset(); + o_timer_bidir_labeling_fw_part_dominance.Reset(); + o_timer_bidir_labeling_bw_part_propagate.Reset(); + o_timer_bidir_labeling_bw_part_dominance.Reset(); + o_timer_bidir_labeling_merge.Reset(); + // counters + v_cnt_fw_labels_inserted.assign(v_cnt_fw_labels_inserted.size(), 0); + v_cnt_bw_labels_inserted.assign(v_cnt_bw_labels_inserted.size(), 0); + v_cnt_fw_dominance_tests.assign(v_cnt_fw_dominance_tests.size(), 0); + v_cnt_bw_dominance_tests.assign(v_cnt_fw_dominance_tests.size(), 0); + } + +} // of namespace espprc + diff --git a/espprc/statistics_mgnt.h b/espprc/statistics_mgnt.h new file mode 100644 index 0000000000000000000000000000000000000000..65983213867ce33ad352b045af4ea0a98f7b203e --- /dev/null +++ b/espprc/statistics_mgnt.h @@ -0,0 +1,143 @@ +#ifndef STATISTICS_MGNT_H +#define STATISTICS_MGNT_H + +#include <vector> + +#include "../SharedFiles/stopwatch.h" + +namespace espprc +{ + using namespace std; + + // for everything related to statistics + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // c_EmptyStatisticsManager + //////////////////////////////////////////////////////////////////////////////////////////////////////// + + class c_EmptyStatisticsManager { + public: + c_EmptyStatisticsManager() {} + void resize(int num_nodes) {} + // the following member functions must be provided, possible to leave them blank + // this way the compiler can ompletely disregard the member function so that + // (true!!!) zero overhead results. + // fw + void OnStartFwLabeling() {} + void OnEndFwLabeling() {} + void OnStartFwPropagate() {} + void OnEndFwPropagate() {} + void OnStartFwDominance() {} + void OnEndFwDominance() {} + // bw + void OnStartBwLabeling() {} + void OnEndBwLabeling() {} + void OnStartBwPropagate() {} + void OnEndBwPropagate() {} + void OnStartBwDominance() {} + void OnEndBwDominance() {} + // bidir + void OnStartBidirLabeling() {} + void OnEndBidirLabeling() {} + void OnStartBidirFwLabeling() {} // fw + void OnEndBidirFwLabeling() {} + void OnStartBidirFwPropagate() {} + void OnEndBidirFwPropagate() {} + void OnStartBidirFwDominance() {} + void OnEndBidirFwDominance() {} + void OnStartBidirBwLabeling() {} //bw + void OnEndBidirBwLabeling() {} + void OnStartBidirBwPropagate() {} + void OnEndBidirBwPropagate() {} + void OnStartBidirBwDominance() {} + void OnEndBidirBwDominance() {} + void OnStartBidirMerge() {} // merge + void OnEndBidirMerge() {} + // dominance manager + void OnLabelInserted(bool fw, int node) {} + void OnDominanceTest(bool fw, int node) {} + + void ResetStatistics() {} + void OutputInStream(std::ostream& s) const { s << "No statistics" << endl; } + }; + + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // c_StatisticsManager + //////////////////////////////////////////////////////////////////////////////////////////////////////// + + + class c_StatisticsManager { + public: + c_Stopwatch o_timer_fw_labeling; + c_Stopwatch o_timer_fw_labeling_propagate; + c_Stopwatch o_timer_fw_labeling_dominance; + // + c_Stopwatch o_timer_bw_labeling; + c_Stopwatch o_timer_bw_labeling_propagate; + c_Stopwatch o_timer_bw_labeling_dominance; + // + c_Stopwatch o_timer_bidir_labeling; + c_Stopwatch o_timer_bidir_labeling_fw_part; + c_Stopwatch o_timer_bidir_labeling_bw_part; + c_Stopwatch o_timer_bidir_labeling_merge; + c_Stopwatch o_timer_bidir_labeling_fw_part_propagate; + c_Stopwatch o_timer_bidir_labeling_fw_part_dominance; + c_Stopwatch o_timer_bidir_labeling_bw_part_propagate; + c_Stopwatch o_timer_bidir_labeling_bw_part_dominance; + // + std::vector<int> v_cnt_fw_labels_inserted; + std::vector<int> v_cnt_bw_labels_inserted; + std::vector<int> v_cnt_fw_dominance_tests; + std::vector<int> v_cnt_bw_dominance_tests; + // + void OutputInStream(const c_Stopwatch& timer, std::string text, std::ostream& s) const; + public: + c_StatisticsManager() : v_cnt_fw_labels_inserted(0), v_cnt_bw_labels_inserted(0), v_cnt_fw_dominance_tests(0), v_cnt_bw_dominance_tests(0) {} + void resize(int num_nodes); + // fw + void OnStartFwLabeling() { o_timer_fw_labeling.Restart(); } + void OnEndFwLabeling() { o_timer_fw_labeling.Stop(); } + void OnStartFwPropagate() { o_timer_fw_labeling_propagate.Restart(); } + void OnEndFwPropagate() { o_timer_fw_labeling_propagate.Stop(); } + void OnStartFwDominance() { o_timer_fw_labeling_dominance.Restart(); } + void OnEndFwDominance() { o_timer_fw_labeling_dominance.Stop(); } + // bw + void OnStartBwLabeling() { o_timer_bw_labeling.Restart(); } + void OnEndBwLabeling() { o_timer_bw_labeling.Stop(); } + void OnStartBwPropagate() { o_timer_bw_labeling_propagate.Restart(); } + void OnEndBwPropagate() { o_timer_bw_labeling_propagate.Stop(); } + void OnStartBwDominance() { o_timer_bw_labeling_dominance.Restart(); } + void OnEndBwDominance() { o_timer_bw_labeling_dominance.Stop(); } + // bidir + void OnStartBidirLabeling() { o_timer_bidir_labeling.Restart(); } + void OnEndBidirLabeling() { o_timer_bidir_labeling.Stop(); } + // + void OnStartBidirFwLabeling() { o_timer_bidir_labeling_fw_part.Restart(); } // fw + void OnEndBidirFwLabeling() { o_timer_bidir_labeling_fw_part.Stop(); } + void OnStartBidirFwPropagate() { o_timer_bidir_labeling_fw_part_propagate.Restart(); } + void OnEndBidirFwPropagate() { o_timer_bidir_labeling_fw_part_propagate.Stop(); } + void OnStartBidirFwDominance() { o_timer_bidir_labeling_fw_part_dominance.Restart(); } + void OnEndBidirFwDominance() { o_timer_bidir_labeling_fw_part_dominance.Stop(); } + // + void OnStartBidirBwLabeling() { o_timer_bidir_labeling_bw_part.Restart(); } //bw + void OnEndBidirBwLabeling() { o_timer_bidir_labeling_bw_part.Stop(); } + void OnStartBidirBwPropagate() { o_timer_bidir_labeling_bw_part_propagate.Restart(); } + void OnEndBidirBwPropagate() { o_timer_bidir_labeling_bw_part_propagate.Stop(); } + void OnStartBidirBwDominance() { o_timer_bidir_labeling_bw_part_dominance.Restart(); } + void OnEndBidirBwDominance() { o_timer_bidir_labeling_bw_part_dominance.Stop(); } + // + void OnStartBidirMerge() { o_timer_bidir_labeling_merge.Restart(); } // merge + void OnEndBidirMerge() { o_timer_bidir_labeling_merge.Stop(); } + // dominance manager + void OnLabelInserted(bool fw, int node); + void OnDominanceTest(bool fw, int node); + // + void ResetStatistics(); + void OutputInStream(std::ostream& s) const; + }; + + +} // of namespace espprc + +#endif // of STATISTICS_MGNT_H