/*Implementation of PStep_ColumnGenerator

It contains the member functions of PStep_ColumnGenerator and all derived classes

Also, commented-out code can be found to set 'four-dimensional p-step capacity'.
Search for:"BEGIN FOUR DIMENSIONAL P-STEP CAPACITY"

*/

#include "PStep_ColumnGenerator.h"

//PStep_ColumnGenerator:
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

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

//Basic constructor
//Initializes the arrays of the duals to the appropriate sizes
PStep_ColumnGenerator::PStep_ColumnGenerator(PStep_AlgorithmMembers& InitAlgorithmMembers, PStep_Adder& InitAdder, PStep_PricingProblemSolver& InitSolver)
	:AlgorithmMembers(InitAlgorithmMembers), Adder(InitAdder), Solver(InitSolver)
{
	//Obtain number of customers, locations and edges
	short int NumberOfCustomers = AlgorithmMembers.Instance.NumberOfCustomers;
	short int NumberOfLocations = NumberOfCustomers + 1;
	short int NumberOfEdges = (NumberOfLocations - 1)*NumberOfLocations / 2;	

	//Initialize duals:
	Lambda = new double[NumberOfCustomers];
	Mu = new double[NumberOfCustomers];
	Nu = new double[NumberOfCustomers];
	Pi = new double[NumberOfEdges];

	//Initialize dynamic state space relaxation members:
	ApplyDSSR = false;
	Adder.ApplyDSSR = &ApplyDSSR;

}

//Print functions
//------------------------------------------------------------------------------------

//Print Lambda
void PStep_ColumnGenerator::PrintLambda(){
	
	//Print
	for (short int i = 0; i < AlgorithmMembers.Instance.NumberOfCustomers; ++i){
		std::cout << i + 1 << ": " << Lambda[i] << std::endl;
	}

}

//Print Mu
void PStep_ColumnGenerator::PrintMu(){

	//Print
	for (short int i = 0; i < AlgorithmMembers.Instance.NumberOfCustomers; ++i){
		std::cout << i + 1 << ": " << Mu[i] << std::endl;
	}

}

//Print Nu
void PStep_ColumnGenerator::PrintNu(){

	//Print
	for (short int i = 0; i < AlgorithmMembers.Instance.NumberOfCustomers; ++i){
		std::cout << i + 1 << ": " << Nu[i] << std::endl;
	}

}

//Print Pi
void PStep_ColumnGenerator::PrintPi(){

	//Compute the number of edges
	short int NumberOfEdges = (AlgorithmMembers.Instance.NumberOfCustomers - 1)*(AlgorithmMembers.Instance.NumberOfCustomers + 1) / 2;

	//Print
	for (short int i = 0; i < NumberOfEdges; ++i){
		std::cout << i + 1 << ": " << Pi[i] << std::endl;
	}

}

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

//Default destructor
PStep_ColumnGenerator::~PStep_ColumnGenerator(){
	
	//Delete
	delete[]Lambda;
	delete[]Mu;
	delete[]Nu;
	delete[]Pi;

}

//BEGIN FOUR DIMENSIONAL P-STEP CAPACITY
/*

//p-step specific capacity
//PStepCapacity[i][j][k][l] gives the capacity on a p-step from location i to location j visiting
//location k in layer l (unless l=0).
//It is the capacity when extending a label from k as l'th location to the l+1'th location.
//The first location i=j=0 is the depot, while k=0 is the first customer.
//The first layer is l=0, where l corresponds to the l'th location on the p-step. Here l ranges from
//0 up to (but not including) p.
//Note that PStepCapacity[i][j][k][0] is the capacity without visiting k at all, it is of use when
//extending the initial label from i.
double**** PStepCapacity;
//***********************

//Set PStepCapacity:
	//------------------
	//Initialize PStepCapacity
	PStepCapacity = new double***[NumberOfLocations];

	//PStepCapacity - From Depot:
	//***************************

	//First consider PStepCapacity for p-steps from the depot.
	//For these p-steps, set the capacity to VehicleCapacity minus
	//the demand of the end location, the p-2 other smallest demands, excluding customer k,
	//except when the last location is the depot, in which case the capacity is simply VehicleCapacity.
	PStepCapacity[0] = new double**[NumberOfLocations];
	//First consider the depot as end location, set all capacities equal to the vehicle capacity.
	PStepCapacity[0][0] = new double*[NumberOfCustomers];
	for (short int k = 0; k < NumberOfCustomers; ++k){
		PStepCapacity[0][0][k] = new double[p];
		for (short int l = 0; l < p; ++l){
			PStepCapacity[0][0][k][l] = VehicleCapacity;
		}
	}
	//Next consider all customer locations as end location of the p-step starting at the depot.
	for (short int j = 1; j < NumberOfLocations; ++j){
		//Initialize PStepCapacity for p-step i-j
		PStepCapacity[0][j] = new double*[NumberOfCustomers];
		//Compute the vehicle capacity minus the miminal demand of a p-step from the j to the depot (excluding the demand of j):
		//Initialize excluded customers
		std::vector<short int> FirstLayerExcludedCustomers;
		FirstLayerExcludedCustomers.push_back(j - 1);
		//Compute the capacity
		double FirstLayerCapacity = ComputeCapacity(VehicleCapacity, SmallestDemand, SmallestDemandLocations, p - 1, FirstLayerExcludedCustomers, NumberOfCustomers);
		//Go over all customers
		for (short int k = 0; k < NumberOfCustomers; ++k){
			//Initialize all layers
			PStepCapacity[0][j][k] = new double[p];
			//Set first layer
			PStepCapacity[0][j][k][0] = FirstLayerCapacity;
			//Set last layer
			PStepCapacity[0][j][k][p - 1] = FirstLayerCapacity;
			//Compute the capacity of all other layers
			//Initialize excluded customers
			std::vector<short int> ExcludedCustomers = FirstLayerExcludedCustomers;
			ExcludedCustomers.push_back(k);
			//Compute the capacity for this layer
			double TempCapacity = ComputeCapacity(VehicleCapacity, SmallestDemand, SmallestDemandLocations, p-1, ExcludedCustomers, NumberOfCustomers);
			//Go over all other layers and set the capacity
			for (short int l = 1; l < p-1; ++l){
				PStepCapacity[0][j][k][l] = TempCapacity;
			}
		}
	}//End consider all customer locations as end location of the p-step starting at the depot.

	//PStepCapacity - From customers:
	//*******************************

	//Go over all customers
	for (short int i = 1; i < NumberOfLocations; ++i){
		//Initialize PStepCapacity for p-steps starting from i
		PStepCapacity[i] = new double**[NumberOfLocations];

		//First consider paths ending at the depot.
		//For these p-steps the capacity is the vehicle capacity minus the minimal
		//load when visiting p-l-2 customers.
		
		//Initialize PStepCapacity for p-step i-0
		PStepCapacity[i][0] = new double*[NumberOfCustomers];
		//Compute the vehicle capacity minus the miminal demand of a p-step (minus one location) from i to the depot excluding the demand of i:
		//Initialize excluded customers
		std::vector<short int> FirstLayerExcludedCustomers;
		FirstLayerExcludedCustomers.push_back(i - 1);
		//Compute the capacity
		double FirstLayerCapacity = ComputeCapacity(VehicleCapacity, SmallestDemand, SmallestDemandLocations, p - 2, FirstLayerExcludedCustomers, NumberOfCustomers);
		//Go over all customers
		for (short int k = 0; k < NumberOfCustomers; ++k){
			//Initialize PStepCapacity 
			PStepCapacity[i][0][k] = new double[p];
			//Set first layer
			PStepCapacity[i][0][k][0] = FirstLayerCapacity;
			//Set last layer
			PStepCapacity[i][0][k][p - 1] = VehicleCapacity;
			//Compute the capacity of all other layers:
			//Check whether there are sufficient layers to process
			if (p >= 3){
				//Set the capacity of the semi-last layer, because the last location is the depot.
				PStepCapacity[i][0][k][p - 2] = VehicleCapacity;
				//Continue with the remaining layers
				//Initialize excluded customers
				std::vector<short int> ExcludedCustomers = FirstLayerExcludedCustomers;
				ExcludedCustomers.push_back(k);
				//Compute the capacities.
				ComputeLayerCapacity(PStepCapacity[i][0][k], 1, p - 3, 0, SmallestDemand, SmallestDemandLocations, ExcludedCustomers, NumberOfCustomers);
			}
		}

		//Finally consider paths from a customers to another customer
		//For these p-steps the capacity is the vehicle capacity minus the minimal
		//load when visiting 2*p-2-l locations.

		//Go over all customers
		for (short int j = 1; j < NumberOfLocations; ++j){

			//Initialize PStepCapacity
			PStepCapacity[i][j] = new double*[NumberOfCustomers];
			//Compute the vehicle capacity minus the miminal demand of 2p-2 locations excluding the demand of i but including j:
			//Reinitialize excluded customers
			FirstLayerExcludedCustomers.clear();
			FirstLayerExcludedCustomers.push_back(i - 1);
			FirstLayerExcludedCustomers.push_back(j - 1);
			//Compute the capacity
			double FirstLayerCapacity;
			//Check whether there are enough locations to include to consider (2p-2) to include the demand of j
			if (p == 1){
				FirstLayerCapacity = VehicleCapacity;
			}
			else{
				FirstLayerCapacity = ComputeCapacity(VehicleCapacity, SmallestDemand, SmallestDemandLocations, 2 * p - 3, FirstLayerExcludedCustomers, NumberOfCustomers) - Demand[j - 1];
			}
			//Go over all customers
			for (short int k = 0; k < NumberOfCustomers; ++k){
				//Initialize PStepCapacity
				PStepCapacity[i][j][k] = new double[p];
				//Set first layer
				PStepCapacity[i][j][k][0] = FirstLayerCapacity;
				//Initialize excluded customers
				std::vector<short int> ExcludedCustomers = FirstLayerExcludedCustomers;
				ExcludedCustomers.push_back(k);
				//Initialize CustomerIndex
				short int CustomerIndex=0;
				//Set last layer
				PStepCapacity[i][j][k][p - 1] = ComputeCapacity(VehicleCapacity, SmallestDemand, SmallestDemandLocations, p - 1, ExcludedCustomers, NumberOfCustomers, CustomerIndex);
				//Compute the capacity of all other layers:
				//Check whether there are sufficient layers to process
				if (p >= 3){
					//Set the capacity of the semi-last layer, because the last location is the depot.
					PStepCapacity[i][j][k][p - 2] = PStepCapacity[i][j][k][p - 1]-Demand[j-1];
					//Continue with the remaining layers
					//Compute the capacities.
					ComputeLayerCapacity(PStepCapacity[i][j][k], 1, p - 3, CustomerIndex , SmallestDemand, SmallestDemandLocations, ExcludedCustomers, NumberOfCustomers);
				}
			}

		}//end go over all customers j

	}//end go over all customers i

Delete:
//*****************************
//Delete PStepCapacity
if (!(NumberOfLocations == 0 || PStepCapacity == 0)){
	for (short int i = 0; i < NumberOfLocations; ++i){
		for (short int j = 0; j < NumberOfLocations; ++j){
			for (short int k = 0; k < NumberOfLocations - 1; ++k){
				delete[]PStepCapacity[i][j][k];
			}
			delete[]PStepCapacity[i][j];
		}
		delete[]PStepCapacity[i];
	}
	delete[]PStepCapacity;
}
else{
	PStepCapacity = 0;
}

//Print functions:
//Print PStepCapacity for the p-step from location i to j, when visiting customer k
void PStep_ColumnGenerator1::PrintPStepCapacity(short int i, short int j, short int k){

	//print
	std::cout << "p-step " << i << "-" << j << " via " << k+1 << ": " << PStepCapacity[i][j][k][0];
	for (short int l = 1; l < AlgorithmMembers.AlgorithmSettings.p; ++l){
		std::cout << " - " << PStepCapacity[i][j][k][l];
	}
	std::cout <<std::endl;

}

//Print PStepCapacity for the p-step from location i to j
void PStep_ColumnGenerator1::PrintPStepCapacity(short int i, short int j){

	//Print for every intermediate customer k
	for (short int k = 0; k < AlgorithmMembers.Instance.NumberOfCustomers; ++k){
		PrintPStepCapacity(i, j, k);
	}

}

*/
//END FOUR DIMENSIONAL P-STEP CAPACITY