/*Implementation of PStep_Algorithm.h

It contains the cut functions of PStep_Algorithm

*/

#include "PStep_Algorithm.h"

//Cut functions:
//------------------------------------------------------------------------------------

//Create an IloExpr representing a cut.
//The indices of EdgeFlowCut represent nodes.
//The expression sums all edges between these nodes.
//The IloNumVarArray theta is such that theta[(j-1)j/2+i] provides the edge flow on (i,j) for i<j.
//The expression is stored in Cut.
void PStep_Algorithm::CreateCutExpression_ByNodes(PStep_EdgeFlowCut &CurrentEdgeFlowCut, IloNumVarArray &theta, IloExpr &Cut){

	//Go over all locations in the cut
	for (auto CurrentLocationIndex = CurrentEdgeFlowCut.Indices.begin(); CurrentLocationIndex != CurrentEdgeFlowCut.Indices.end(); ++CurrentLocationIndex){
		//Initialize support vaiables:
		//Obtain the current locations
		short int CurrentLocation = *CurrentLocationIndex;
		//Obtain the first next index
		std::list<short int>::iterator FirstNextIndex = CurrentLocationIndex;
		++FirstNextIndex;
		//Go over all other locations in the cut
		for (auto OtherLocationIndex = FirstNextIndex; OtherLocationIndex != CurrentEdgeFlowCut.Indices.end(); ++OtherLocationIndex){
			//Obtain the other location
			short int OtherLocation = *OtherLocationIndex;
			//Add the edge between the current and other location to the cut
			if (CurrentLocation < OtherLocation){
				Cut += theta[(OtherLocation - 1)*OtherLocation / 2 + CurrentLocation];
			}
			else{
				Cut += theta[(CurrentLocation - 1)*CurrentLocation / 2 + OtherLocation];
			}
		}
	}

}

//Create an IloExpr representing a cut.
//The indices of EdgeFlowCut represent edges.
//The expression sums all these edges.
//The expression is stored in Cut.
void PStep_Algorithm::CreateCutExpression_ByEdges(PStep_EdgeFlowCut &CurrentEdgeFlowCut, IloNumVarArray &theta, IloExpr &Cut){

	//Go over all edges
	for (auto CurrentEdge = CurrentEdgeFlowCut.Indices.begin(); CurrentEdge != CurrentEdgeFlowCut.Indices.end(); ++CurrentEdge){
		Cut += theta[*CurrentEdge];
	}

}

//Create an IloExpr representing a cut.
//The indices of TwoEdgeHypotourCut are the indices of edges in the cut.
//The expression sums all these edges multiplied with their corresponding coefficients.
//The expression is stored in Cut.
void PStep_Algorithm::CreateCutExpression_ByEdgesAndCoefficients(PStep_EdgeAndCoefficientCut &CurrentEdgeAndCoefficientCut, IloNumVarArray &theta, IloExpr &Cut){

	//Go over all edges
	for (auto CurrentEdgeAndCoefficient = CurrentEdgeAndCoefficientCut.EdgeAndCoefficients.begin(); CurrentEdgeAndCoefficient != CurrentEdgeAndCoefficientCut.EdgeAndCoefficients.end(); ++CurrentEdgeAndCoefficient){
		Cut += (CurrentEdgeAndCoefficient->Coefficient)*(theta[CurrentEdgeAndCoefficient->EdgeIndex]);
	}

}

//Create branching cuts on the number of vehicles and add them to the TreeNode 
void PStep_Algorithm::CreateFixedNumberOfVehiclesCut(PStep_TreeNode& TreeNode){

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

	//Check whether the number of vehicles is fixed in the current instance.
	if (AlgorithmMembers.Instance.NumberOfVehiclesIsFixed){
		//The number of vehicles is fixed
		//Add cut by edges.

		//Initialize cut
		PStep_EdgeFlowCut FixedNumberOfVehiclesConstraint;
		//Set bound
		FixedNumberOfVehiclesConstraint.Bound = 2*(AlgorithmMembers.Instance.FixedNumberOfVehicles);
		
		//Create list of edges that are part of this cut:
		//Initialize counter
		short int Counter = 0;
		//Go over all customers
		for (short int j = 1; j < NumberOfLocations; ++j){
			FixedNumberOfVehiclesConstraint.Indices.push_front(Counter);
			Counter += j;
		}
		//Add the cut to the tree node
		TreeNode.EdgeFlowCuts_ByEdges_EQ.push_front(FixedNumberOfVehiclesConstraint);

	}
	//Check whether a lower bound on the number of vehicles is required
	else if (AlgorithmMembers.AlgorithmSettings.UseNumberOfVehiclesLowerBound){
		//A lower bound on the number of vehicles is required
		//Add cut by edges.

		//Initialize cut
		PStep_EdgeFlowCut NumberOfVehiclesConstraint;

		//Compute lower bound:
		//Obtain demand
		double* Demand = AlgorithmMembers.Instance.Demand;
		//Initialize total demand
		double TotalDemand = 0;
		//Go over all customers
		for (short int i = 0; i < NumberOfCustomers; ++i){
			TotalDemand += Demand[i];
		}
		//Compute lower bound
		NumberOfVehiclesConstraint.Bound = 2 * std::ceil(TotalDemand/AlgorithmMembers.Instance.VehicleCapacity);

		//Create list of edges that are part of this cut:
		//Initialize counter
		short int Counter = 0;
		//Go over all customers
		for (short int j = 1; j < NumberOfLocations; ++j){
			NumberOfVehiclesConstraint.Indices.push_front(Counter);
			Counter += j;
		}
		//Add the cut to the tree node
		TreeNode.EdgeFlowCuts_ByEdges_LB.push_front(NumberOfVehiclesConstraint);
	}

}