/*Implementation of PStep_ColumnGenerator.h

It contains the member functions of PStep_ColumnGenerator1

*/

#include "PStep_ColumnGenerator.h"

//PStep_ColumnGenerator1:
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//Constructor functions:
//------------------------------------------------------------------------------------

//Basic constructor
//Initializes the arrays of the duals to the appropriate sizes
PStep_ColumnGenerator1::PStep_ColumnGenerator1(PStep_AlgorithmMembers& InitAlgorithmMembers, PStep_Adder& InitAdder, PStep_PricingProblemSolver& InitSolver)
	:PStep_ColumnGenerator(InitAlgorithmMembers, InitAdder, InitSolver), UseLimitedArcs(false), DoNotCheckReachability(false)
{

	//Obtain number of locations
	short int NumberOfLocations = AlgorithmMembers.Instance.NumberOfCustomers + 1;

	//Initialize reduced cost template
	ReducedCostTemplate = new double*[NumberOfLocations];
	//Go over all starting locations
	for (short int i = 0; i < NumberOfLocations; ++i){
		//Initialize reduced costs template
		ReducedCostTemplate[i] = new double[NumberOfLocations];
		//Go over all end locations
		for (short int j = 0; j < NumberOfLocations; ++j){
			ReducedCostTemplate[i][j] = 0;
		}
	}

}

//Generate columns
//------------------------------------------------------------------------------------

//Solve pricing problem seperately for every(non - redundant) start and end node combination.
//The pricing problems are solved in layered style, meaning dominance is only applied for labels
//corresponding to partial paths containg the same amount of locations and finishing at the same node.
void PStep_ColumnGenerator1::GenerateColumns(){

	GenerateColumns1();

}


//Solve pricing problem seperately for every(non - redundant) start and end node combination.
//The pricing problems are solved in layered style, meaning dominance is only applied for labels
//corresponding to partial paths containg the same amount of locations and finishing at the same node.
void PStep_ColumnGenerator1::GenerateColumns1(){
	
	//Initialization:
	//*****************************************************************************************

	//Obtain p
	short int p = AlgorithmMembers.AlgorithmSettings.p;
	//Obtain Tolerance
	double Tolerance = AlgorithmMembers.Tolerance;
	//Obtain indicator indicating whether ng-path relaxation is used
	bool UseNGPathRelaxation = AlgorithmMembers.AlgorithmSettings.UseNGPathRelaxation;
	//Obtain neighbourhoods
	std::vector<std::vector<short int >>& Neighbourhoods = AlgorithmMembers.Neighbourhoods;
	//Obtain NotInNeighbourhood
	bool** (&NotInNeighbourhood) = AlgorithmMembers.NotInNeighbourhood;
	//Obtain pricing problems
	PStep_PricingProblem** (&PricingProblems) = AlgorithmMembers.PricingProblems;
	//Obtain lists of relevant pricing problems
	std::list<PStep_PricingProblem*> &RelevantDepotCustomerPricingProblems = AlgorithmMembers.RelevantDepotCustomerPricingProblems;
	std::list<PStep_PricingProblem*> &RelevantCustomerDepotPricingProblems = AlgorithmMembers.RelevantCustomerDepotPricingProblems;
	std::list<PStep_PricingProblem*> &RelevantCustomerCustomerPricingProblems = AlgorithmMembers.RelevantCustomerCustomerPricingProblems;

	//SetReducedCostTemplate
	SetReducedCostTemplate();

	//Initialize list of layered labeling algorithms
	std::forward_list<PStep_LayeredLabelingAlgorithm> LabelingAlgorithms;

	//Initialize list of solved pricing problems
	//This list gets updated after a succesful run of PStep_LayeredLabelingAlgorithm
	std::forward_list<PStep_PricingProblem*> SolvedPricingProblems;

	//Initialize reachability setters:
	//********************************
	//Initialize Container for PStep_ReachabilitySetter
	std::forward_list<PStep_ReachabilitySetter> ReachabilitySetters;
	//Initialize Container for PStep_NGReachabilitySetter
	std::forward_list<PStep_NGReachabilitySetter> NGReachabilitySetters;
	//Initialize pointer to a current reachability setter
	PStep_ReachabilitySetter* CurrentReachabilitySetter;

	//Initialize extenders:
	//*********************
	//Initialize Container for PStep_StandardExtenders
	std::forward_list<PStep_StandardExtender> StandardExtenders;
	//Initialize Container for PStep_ZeroLoadDepotFinalExtender
	std::forward_list<PStep_ZeroLoadDepotFinalExtender> ZeroLoadDepotFinalExtenders;
	//Initialize Container for PStep_ZeroLoadFinalExtender
	std::forward_list<PStep_ZeroLoadFinalExtender> ZeroLoadFinalExtenders;
	//Initialize Container for PStep_MaxLoadDepotFinalExtender
	std::forward_list<PStep_MaxLoadDepotFinalExtender> MaxLoadDepotFinalExtenders;
	//Initialize Container for PStep_MaxLoadFinalExtender
	std::forward_list<PStep_MaxLoadFinalExtender> MaxLoadFinalExtenders;

	//Initialize dominators:
	//**********************
	//Initialize Dominator
	PStep_ReachabilityDominator Dominator(Tolerance);
	//Initialize load dominator
	PStep_LoadDominator LoadDominator(Tolerance);
	//Initialize ng-path dominator
	PStep_NGReachabilityDominator NGDominator(Tolerance, Neighbourhoods);
	//Initialize pointer to the current dominator
	PStep_Dominator* CurrentDominator;
	//Check which dominator should be used
	if (DoNotCheckReachability){
		CurrentDominator = &LoadDominator;
	}
	else if (UseNGPathRelaxation){
		CurrentDominator = &NGDominator;
	}
	else{
		CurrentDominator = &Dominator;
	}
	//Initialize Container for PStep_NGReachabilityDominator, to be used
	//if dynamic state space relaxation is applied.
	std::forward_list<PStep_NGReachabilityDominator> DSSRNGReachabilityDominators;

	//Initialize algorithm for the pricing problem from depot to depot:
	//*****************************************************************
	//Check whether p is not 1, in which case this pricing problem is nonsense.
	if (p > 1){

		//Obtain pricing problem
		PStep_PricingProblem &CurrentPricingProblem = PricingProblems[0][0];
		//Obtain demand
		double* Demand = CurrentPricingProblem.Demand;
		//Obtain capacity plus tolerance
		double CapacityPlusTolerance = CurrentPricingProblem.Capacity + Tolerance;

		//Set reduced costs
		SetReducedCosts(CurrentPricingProblem, 0, 0);

		//Check whether dynamic state-space relaxation is applied
		if (ApplyDSSR){
			//Create Reachability setter
			NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, CurrentPricingProblem.CurrentDSSRNotInNeighbourhood);
			//Set current reachability setter
			CurrentReachabilitySetter = &(NGReachabilitySetters.front());
			//Check whether reachability should be checked
			if (!DoNotCheckReachability){
				//Create dominator
				DSSRNGReachabilityDominators.emplace_front(Tolerance, CurrentPricingProblem.CurrentDSSRNeighbourhoods);
				//Set current dominator
				CurrentDominator = &(DSSRNGReachabilityDominators.front());
			}
		}
		else if (UseNGPathRelaxation){
			//Create Reachability setter
			NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, NotInNeighbourhood);
			//Set current reachability setter
			CurrentReachabilitySetter = &(NGReachabilitySetters.front());
		}
		else{
			//Create Reachability setter
			ReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance);
			//Set current reachability setter
			CurrentReachabilitySetter = &(ReachabilitySetters.front());
		}

		//Create standard extender
		StandardExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, *CurrentReachabilitySetter);
		//Create Final extender
		ZeroLoadDepotFinalExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, Tolerance);
		
		//Create Layered Labeling Algorithm
		LabelingAlgorithms.emplace_front(CurrentPricingProblem, StandardExtenders.front(), ZeroLoadDepotFinalExtenders.front(), *CurrentDominator, UseLimitedArcs, SolvedPricingProblems);

	}

	//Initialize algorithm for the pricing problems from depot to customers:
	//**********************************************************************
	//Go over all relevant pricing problems from depot to customer
	for (auto RelevantPricingProblem = RelevantDepotCustomerPricingProblems.begin(); RelevantPricingProblem != RelevantDepotCustomerPricingProblems.end(); ++RelevantPricingProblem){
		
		//Obtain current pricing problem
		PStep_PricingProblem &CurrentPricingProblem = (**RelevantPricingProblem);
		//Obtain current sink
		short int jMinusOne = CurrentPricingProblem.Sink-1;
		//Obtain demand
		double* Demand = CurrentPricingProblem.Demand;
		//Obtain capacity plus tolerance
		double CapacityPlusTolerance = CurrentPricingProblem.Capacity + Tolerance;

		//Set reduced costs
		double ReducedCostConstant = Lambda[jMinusOne] + Mu[jMinusOne];
		SetReducedCosts(CurrentPricingProblem, Nu[jMinusOne], ReducedCostConstant);

		//Check which reachability setter should be used
		if (ApplyDSSR){
			//Create Reachability setter
			NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, CurrentPricingProblem.CurrentDSSRNotInNeighbourhood);
			//Set current reachability setter
			CurrentReachabilitySetter = &(NGReachabilitySetters.front());
			//Check whether reachability should be checked
			if (!DoNotCheckReachability){
				//Create dominator
				DSSRNGReachabilityDominators.emplace_front(Tolerance, CurrentPricingProblem.CurrentDSSRNeighbourhoods);
				//Set current dominator
				CurrentDominator = &(DSSRNGReachabilityDominators.front());
			}
		}
		else if (UseNGPathRelaxation){
			//Create NGReachabilitySetter
			NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, NotInNeighbourhood);
			//Set current reachability setter
			CurrentReachabilitySetter = &(NGReachabilitySetters.front());
		}
		else{
			//Create ReachabilitySetter
			ReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance);
			//Set current reachability setter
			CurrentReachabilitySetter = &(ReachabilitySetters.front());
		}
		//Create standard extender
		StandardExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, *CurrentReachabilitySetter);
		//Create Final extender
		ZeroLoadFinalExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, Tolerance);
		
		//Create Layered Labeling Algorithm
		LabelingAlgorithms.emplace_front(CurrentPricingProblem, StandardExtenders.front(), ZeroLoadFinalExtenders.front(), *CurrentDominator, UseLimitedArcs, SolvedPricingProblems);

	}

	//Initialize algorithm for the pricing problems from customer to depot:
	//*********************************************************************
	//Go over all relevant pricing problems from customer to depot
	for (auto RelevantPricingProblem = RelevantCustomerDepotPricingProblems.begin(); RelevantPricingProblem != RelevantCustomerDepotPricingProblems.end(); ++RelevantPricingProblem){

		//Obtain current pricing problem
		PStep_PricingProblem &CurrentPricingProblem = (**RelevantPricingProblem);
		//Obtain current source
		short int iMinusOne = CurrentPricingProblem.Source-1;
		//Obtain demand
		double* Demand = CurrentPricingProblem.Demand;
		//Obtain capacity
		double Capacity = CurrentPricingProblem.Capacity;
		//Obtain capacity plus tolerance
		double CapacityPlusTolerance = Capacity + Tolerance;

		//Set reduced costs
		double ReducedCostConstant = -Lambda[iMinusOne] - Mu[iMinusOne] - Nu[iMinusOne] * Capacity;
		SetReducedCosts(CurrentPricingProblem, Nu[iMinusOne], ReducedCostConstant);

		//Check whether dynamic state-space relaxation is applied
		if (ApplyDSSR){
			//Create Reachability setter
			NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, CurrentPricingProblem.CurrentDSSRNotInNeighbourhood);
			//Set current reachability setter
			CurrentReachabilitySetter = &(NGReachabilitySetters.front());
			//Check whether reachability should be checked
			if (!DoNotCheckReachability){
				//Create dominator
				DSSRNGReachabilityDominators.emplace_front(Tolerance, CurrentPricingProblem.CurrentDSSRNeighbourhoods);
				//Set current dominator
				CurrentDominator = &(DSSRNGReachabilityDominators.front());
			}
		}
		else if (UseNGPathRelaxation){
			//Create NGReachabilitySetter
			NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, NotInNeighbourhood);
			//Set current reachability setter
			CurrentReachabilitySetter = &(NGReachabilitySetters.front());
		}
		else{
			//Create ReachabilitySetter
			ReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance);
			//Set current reachability setter
			CurrentReachabilitySetter = &(ReachabilitySetters.front());
		}
		//Create standard extender
		StandardExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, *CurrentReachabilitySetter);
		//Create Final extender
		MaxLoadDepotFinalExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, Tolerance, Capacity);
		
		//Create Layered Labeling Algorithm
		LabelingAlgorithms.emplace_front(CurrentPricingProblem, StandardExtenders.front(), MaxLoadDepotFinalExtenders.front(), *CurrentDominator, UseLimitedArcs, SolvedPricingProblems);

	}

	//Initialize algorithm for the pricing problems from customer to customers:
	//*************************************************************************
	//Go over all relevant pricing problems from customer to customer
	for (auto RelevantPricingProblem = RelevantCustomerCustomerPricingProblems.begin(); RelevantPricingProblem != RelevantCustomerCustomerPricingProblems.end(); ++RelevantPricingProblem){

		//Obtain current source and sink
		short int i = (*RelevantPricingProblem)->Source;
		short int iMinusOne = i - 1;
		short int j = (*RelevantPricingProblem)->Sink;
		short int jMinusOne = j - 1;

		//Initialize indicators, indicating which customer, i or j, has larger Nu
		short int LargeNuCustomer = iMinusOne;
		short int SmallNuCustomer = jMinusOne;
		//Set indictors to the right value
		if (Nu[LargeNuCustomer] < Nu[SmallNuCustomer]){
			LargeNuCustomer = jMinusOne;
			SmallNuCustomer = iMinusOne;
		}

		//Check whether the p-step from LargeNuCustomer to SmallNuCustomer has a cost
		//lower or equal to the cost of the same p-step reversed.
		//Keep in mind that with strict inequality, the starting load of 'Large to Small' is set to the maximum,
		//while the reverse has starting load 0. In case equality, this is irrelevant.
		if (2 * (Mu[SmallNuCustomer] - Mu[LargeNuCustomer]) - Nu[LargeNuCustomer] * ((*RelevantPricingProblem)->Capacity + (*RelevantPricingProblem)->Demand[LargeNuCustomer]) + Nu[SmallNuCustomer] * ((*RelevantPricingProblem)->Capacity + (*RelevantPricingProblem)->Demand[SmallNuCustomer]) < -Tolerance){
			//A p-step from LargeNuCustomer to SmallNuCustomer has lower cost than its reverse.

			//Obtain current pricing problem
			PStep_PricingProblem* TempPricingProblem; 
			if (LargeNuCustomer == iMinusOne){
				TempPricingProblem = *RelevantPricingProblem;
			}
			else{
				TempPricingProblem = &PricingProblems[j][i];
			}
			PStep_PricingProblem &CurrentPricingProblem = *TempPricingProblem;

			//Set up the algorithm to generate p-steps with maximum load:

			//Obtain demand
			double* Demand = CurrentPricingProblem.Demand;
			//Obtain capacity
			double Capacity = CurrentPricingProblem.Capacity;
			//Obtain capacity plus tolerance
			double CapacityPlusTolerance = Capacity + Tolerance;

			//Set reduced costs
			double ReducedCostConstant = Lambda[SmallNuCustomer] - Lambda[LargeNuCustomer] + Mu[SmallNuCustomer] - Mu[LargeNuCustomer] + (Nu[SmallNuCustomer] - Nu[LargeNuCustomer]) * Capacity;
			SetReducedCosts(CurrentPricingProblem, Nu[LargeNuCustomer], ReducedCostConstant);

			//Check which reachability setter should be used
			if (ApplyDSSR){
				//Create Reachability setter
				NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, CurrentPricingProblem.CurrentDSSRNotInNeighbourhood);
				//Set current reachability setter
				CurrentReachabilitySetter = &(NGReachabilitySetters.front());
				//Check whether reachability should be checked
				if (!DoNotCheckReachability){
					//Create dominator
					DSSRNGReachabilityDominators.emplace_front(Tolerance, CurrentPricingProblem.CurrentDSSRNeighbourhoods);
					//Set current dominator
					CurrentDominator = &(DSSRNGReachabilityDominators.front());
				}
			}
			else if (UseNGPathRelaxation){
				//Create NGReachabilitySetter
				NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, NotInNeighbourhood);
				//Set current reachability setter
				CurrentReachabilitySetter = &(NGReachabilitySetters.front());
			}
			else{
				//Create ReachabilitySetter
				ReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance);
				//Set current reachability setter
				CurrentReachabilitySetter = &(ReachabilitySetters.front());
			}
			//Create standard extender
			StandardExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, *CurrentReachabilitySetter);
			//Create Final extender
			MaxLoadFinalExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, Tolerance, Capacity);
			
			//Create Layered Labeling Algorithm
			LabelingAlgorithms.emplace_front(CurrentPricingProblem, StandardExtenders.front(), MaxLoadFinalExtenders.front(), *CurrentDominator, UseLimitedArcs, SolvedPricingProblems);

		}
		else{
			//A p-step from SmallNuCustomer to LargeNuCustomer has lower or equal cost compared to the reverse.

			//Obtain current pricing problem
			PStep_PricingProblem* TempPricingProblem;
			if (SmallNuCustomer == iMinusOne){
				TempPricingProblem = *RelevantPricingProblem;
			}
			else{
				TempPricingProblem = &PricingProblems[j][i];
			}
			PStep_PricingProblem &CurrentPricingProblem = *TempPricingProblem;

			//Set up the algorithm to generate p-steps with zero load:

			//Obtain demand
			double* Demand = CurrentPricingProblem.Demand;
			//Obtain capacity
			double Capacity = CurrentPricingProblem.Capacity;
			//Obtain capacity plus tolerance
			double CapacityPlusTolerance = Capacity + Tolerance;

			//Set reduced costs
			double ReducedCostConstant = Lambda[LargeNuCustomer] - Lambda[SmallNuCustomer] + Mu[LargeNuCustomer] - Mu[SmallNuCustomer] + (Nu[LargeNuCustomer] - Nu[SmallNuCustomer])*Demand[SmallNuCustomer];
			SetReducedCosts(CurrentPricingProblem, Nu[LargeNuCustomer], ReducedCostConstant);

			//Check which reachability setter should be used
			if (ApplyDSSR){
				//Create Reachability setter
				NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, CurrentPricingProblem.CurrentDSSRNotInNeighbourhood);
				//Set current reachability setter
				CurrentReachabilitySetter = &(NGReachabilitySetters.front());
				//Check whether reachability should be checked
				if (!DoNotCheckReachability){
					//Create dominator
					DSSRNGReachabilityDominators.emplace_front(Tolerance, CurrentPricingProblem.CurrentDSSRNeighbourhoods);
					//Set current dominator
					CurrentDominator = &(DSSRNGReachabilityDominators.front());
				}
			}
			else if (UseNGPathRelaxation){
				//Create NGReachabilitySetter
				NGReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance, NotInNeighbourhood);
				//Set current reachability setter
				CurrentReachabilitySetter = &(NGReachabilitySetters.front());
			}
			else{
				//Create ReachabilitySetter
				ReachabilitySetters.emplace_front(Demand, CapacityPlusTolerance);
				//Set current reachability setter
				CurrentReachabilitySetter = &(ReachabilitySetters.front());
			}
			//Create standard extender
			StandardExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, *CurrentReachabilitySetter);
			//Create Final extender
			ZeroLoadFinalExtenders.emplace_front(Demand, CurrentPricingProblem.ReducedArcCosts, Tolerance);
			
			//Create Layered Labeling Algorithm
			LabelingAlgorithms.emplace_front(CurrentPricingProblem, StandardExtenders.front(), ZeroLoadFinalExtenders.front(), *CurrentDominator, UseLimitedArcs, SolvedPricingProblems);

		}

	}

	//Solve pricing problems:
	//*****************************************************************************************

	//Make a list of pointers to the shortest path algorithms which refer to the Layered Labeling Algorithms
	std::forward_list<PStep_ShortestPathAlgorithm*> TempList;
	for (auto CurrentLA = LabelingAlgorithms.begin(); CurrentLA != LabelingAlgorithms.end(); ++CurrentLA){
		TempList.push_front(&(*CurrentLA));
	}

	//Solve
	Solver.Solve(TempList);

	//Add p-steps:
	//*****************************************************************************************

	//Add
	Adder.AddMultiplePPCandidateLabels(SolvedPricingProblems);
	
}

//Neighborhood functions:
//------------------------------------------------------------------------------------

//Reset DSSN attributes, for all pricing problems.
void PStep_ColumnGenerator1::ResetDSSRNeighbourhoods(){

	//Obtain lists of relevant pricing problems
	std::list<PStep_PricingProblem*> &RelevantDepotCustomerPricingProblems = AlgorithmMembers.RelevantDepotCustomerPricingProblems;
	std::list<PStep_PricingProblem*> &RelevantCustomerDepotPricingProblems = AlgorithmMembers.RelevantCustomerDepotPricingProblems;
	std::list<PStep_PricingProblem*> &RelevantCustomerCustomerPricingProblems = AlgorithmMembers.RelevantCustomerCustomerPricingProblems;

	//Check whether the depot-depot pricing problem is relevant
	if (AlgorithmMembers.AlgorithmSettings.p > 1){
		AlgorithmMembers.PricingProblems[0][0].ResetDSSRNeighbourhoods();
	}

	//Go over all relevant Depot-Customer pricing problems
	for (auto CurrentPricingProblem = RelevantDepotCustomerPricingProblems.begin(); CurrentPricingProblem != RelevantDepotCustomerPricingProblems.end(); ++CurrentPricingProblem){
		(*CurrentPricingProblem)->ResetDSSRNeighbourhoods();
	}
	//Go over all relevant Customer-Depot pricing problems
	for (auto CurrentPricingProblem = RelevantCustomerDepotPricingProblems.begin(); CurrentPricingProblem != RelevantCustomerDepotPricingProblems.end(); ++CurrentPricingProblem){
		(*CurrentPricingProblem)->ResetDSSRNeighbourhoods();
	}
	//Go over all relevant Customer-Customer pricing problems
	for (auto CurrentPricingProblem = RelevantCustomerCustomerPricingProblems.begin(); CurrentPricingProblem != RelevantCustomerCustomerPricingProblems.end(); ++CurrentPricingProblem){
		(*CurrentPricingProblem)->ResetDSSRNeighbourhoods();
		//Also reset the 'reverse' pricing problem
		AlgorithmMembers.PricingProblems[(*CurrentPricingProblem)->Sink][(*CurrentPricingProblem)->Source].ResetDSSRNeighbourhoods();
	}

}

//Set RerunRequired of all relevant pricing problems to NewRerunRequired.
void PStep_ColumnGenerator1::SetRerunRequiredPerPricingProblem(bool NewRerunRequired){

	//Obtain lists of relevant pricing problems
	std::list<PStep_PricingProblem*> &RelevantDepotCustomerPricingProblems = AlgorithmMembers.RelevantDepotCustomerPricingProblems;
	std::list<PStep_PricingProblem*> &RelevantCustomerDepotPricingProblems = AlgorithmMembers.RelevantCustomerDepotPricingProblems;
	std::list<PStep_PricingProblem*> &RelevantCustomerCustomerPricingProblems = AlgorithmMembers.RelevantCustomerCustomerPricingProblems;

	//Check whether the depot-depot pricing problem is relevant
	if (AlgorithmMembers.AlgorithmSettings.p > 1){
		AlgorithmMembers.PricingProblems[0][0].RerunRequired = NewRerunRequired;
	}

	//Go over all relevant Depot-Customer pricing problems
	for (auto CurrentPricingProblem = RelevantDepotCustomerPricingProblems.begin(); CurrentPricingProblem != RelevantDepotCustomerPricingProblems.end(); ++CurrentPricingProblem){
		(*CurrentPricingProblem)->RerunRequired = NewRerunRequired;
	}
	//Go over all relevant Customer-Depot pricing problems
	for (auto CurrentPricingProblem = RelevantCustomerDepotPricingProblems.begin(); CurrentPricingProblem != RelevantCustomerDepotPricingProblems.end(); ++CurrentPricingProblem){
		(*CurrentPricingProblem)->RerunRequired = NewRerunRequired;
	}
	//Go over all relevant Customer-Customer pricing problems
	for (auto CurrentPricingProblem = RelevantCustomerCustomerPricingProblems.begin(); CurrentPricingProblem != RelevantCustomerCustomerPricingProblems.end(); ++CurrentPricingProblem){
		(*CurrentPricingProblem)->RerunRequired = NewRerunRequired;
		//Also reset the 'reverse' pricing problem
		AlgorithmMembers.PricingProblems[(*CurrentPricingProblem)->Sink][(*CurrentPricingProblem)->Source].RerunRequired = NewRerunRequired;
	}

}

//Reduced cost functions
//------------------------------------------------------------------------------------

//Set the reduced costs template.
//The costs will be set to TravelCosts-Pi-2*lambda.
//It is assumed that ReducedCostTemplate is iniitialized when calling this function.
void PStep_ColumnGenerator1::SetReducedCostTemplate(){

	//Obtain number of locations
	short int NumberOfLocations = AlgorithmMembers.Instance.NumberOfCustomers + 1;
	//Obtain travel costs
	double **TravelCosts = AlgorithmMembers.Instance.TravelCosts;
	//Obtain all arcs
	std::vector<std::vector<PStep_Arc>>& AllArcs = AlgorithmMembers.Arcs;

	//Go over all starting locations
	for (short int i = 0; i < NumberOfLocations; ++i){
		//Go over all end locations
		for (short int j = 0; j < NumberOfLocations; ++j){
			ReducedCostTemplate[i][j] = TravelCosts[i][j] - Pi[AllArcs[i][j].Index];
			if (j>0){
				ReducedCostTemplate[i][j] -= 2 * Lambda[j - 1];
			}
		}
	}

}

//Set the reduced costs of a pricing problem, in particular ReducedArcCosts and ReducedCostConstant.
//It is assumed that PricingProblem.ReducedArcCosts is already initialized when calling
//this function.
//Furthermore, it is assumed that ReducedCostTemplate is initialized to TravelCost-Pi.
//Note for use:
//- In the case of zero starting load: Dual = -Nu[StartLocation]
//- In the case of maximum starting load: Dual = +Nu[EndLocation]
void PStep_ColumnGenerator1::SetReducedCosts(PStep_PricingProblem &PricingProblem, double Dual, double ReducedCostConstant){

	//Obtain number of locations
	short int NumberOfLocations = PricingProblem.NumberOfLocations;
	//Obtain Demand
	double* (&Demand) = PricingProblem.Demand;
	//Obtain ReducedArcCosts
	double** (&ReducedArcCosts) = PricingProblem.ReducedArcCosts;
	
	//Set reduced arc costs:
	//Go over all starting locations
	for (short int i = 0; i < NumberOfLocations; ++i){
		//Consider the depot
		ReducedArcCosts[i][0] = ReducedCostTemplate[i][0];
		//Go over all non-depot end locations
		for (short int j = 1; j < NumberOfLocations; ++j){
			ReducedArcCosts[i][j] = ReducedCostTemplate[i][j] + Dual*Demand[j - 1];
		}
	}

	//Set reduced cost constant:
	PricingProblem.ReducedCostConstant = ReducedCostConstant;

}

//Destructor functions
//------------------------------------------------------------------------------------

//Default destructor
PStep_ColumnGenerator1::~PStep_ColumnGenerator1(){

	//Obtain the number of locations
	short int NumberOfLocations = AlgorithmMembers.Instance.NumberOfCustomers + 1;

	//Delete ReducedArcCosts
	if (!(NumberOfLocations == 0 || ReducedCostTemplate == 0)){
		for (short int i = 0; i < NumberOfLocations; ++i){
			delete[]ReducedCostTemplate[i];
		}
		delete[]ReducedCostTemplate;
	}
	else{
		ReducedCostTemplate = 0;
	}

}