/*Implementation of PStep_Experiments Experiment1

*/

#include "PStep_Experiments.h"

//Experiment type 1 - Column generation
void Experiment1(){

	//ALGORITHM SETTINGS:
	//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

	//p values
	std::vector<int> P = { 1, 2, 3, 4, 5, 6, 128 };

	//Initialize template algorithm settings
	PStep_AlgorithmSettings TemplateAlgorithmSettings(0, 3600, false, false);
	TemplateAlgorithmSettings.UseAdjustedCapacity = true;
	TemplateAlgorithmSettings.UseNGPathRelaxation = false;
	TemplateAlgorithmSettings.NeighbourhoodSize = 8;
	TemplateAlgorithmSettings.InitialPSteps = 3;
	TemplateAlgorithmSettings.PricingProblemSelection = 1;
	TemplateAlgorithmSettings.ColumnGenerator = 21;
	TemplateAlgorithmSettings.ColumnManager = 3;
	TemplateAlgorithmSettings.SeparationStrategy = 0;

	//INPUT FILES:
	//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

	//Test Instances folder:
	//----------------------
	//The folder where all generated instances are saved
	std::stringstream TestInstancesFolder;
	TestInstancesFolder << "C:\\Users\\Priscilla\\Remy\\Visual Studio 2013\\Projects\\P-Step_CVRP\\Project Output\\Test Instances\\";

	//Selection of E instances to run:
	//--------------------------------
	//The E instances are encoded by pairs of values, they are given below by N and K in order of appearance.
	//std::vector<int> N = { 13, 22, 23, 30, 31, 33, 51, 76, 76, 76, 76, 101, 101 };
	//std::vector<int> K = { 4, 4, 3, 3, 7, 4, 5, 7, 8, 10, 14, 8, 14 };
	//Selection of E instances:
	std::vector<int> EN = { 13, 22, 23, 30, 31, 33, 51 };
	std::vector<int> EK = { 4, 4, 3, 3, 7, 4, 5 };

	//Selection of A instances to run:
	//--------------------------------
	//The A instances are encoded by pairs of values, they are given below by N and K in order of appearance.
	//std::vector<int> N = { 32, 33, 33, 34, 36, 37, 37, 38, 39, 39, 44, 45, 45, 46, 48, 53, 54, 55, 60, 61, 62, 63, 63, 64, 65, 69, 80 };
	//std::vector<int> K = { 5, 5, 6, 5, 5, 5, 6, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 9, 9, 9, 8, 9, 10, 9, 9, 9, 10 };
	//Selection of A instances:
	std::vector<int> AN = { 32, 33, 33, 34, 36, 37, 37, 38, 39, 39, 44, 45, 45, 46, 48 };
	std::vector<int> AK = { 5, 5, 6, 5, 5, 5, 6, 5, 5, 6, 6, 6, 7, 7, 7 };


	//OUTPUT FILES:
	//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

	//Test Output folder:
	//-------------------
	//The folder where the output is saved
	std::stringstream TestOutputFolder;
	TestOutputFolder << "C:\\Users\\Priscilla\\Remy\\Visual Studio 2013\\Projects\\P-Step_CVRP\\Project Output\\Test Output\\";

	//Initialize output files:
	//------------------------
	//Initialize computation time summary file
	std::stringstream TimeSummaryFileName;
	TimeSummaryFileName << TestOutputFolder.str().c_str() << "TimeSummary.txt";
	std::ofstream InitialTimeSummaryFile(TimeSummaryFileName.str().c_str());
	//Check whether the file could be opened
	if (!InitialTimeSummaryFile){
		std::cout << "Cannot open file " << TimeSummaryFileName.str().c_str() << "." << std::endl;
		return;
	}
	else{
		//Write headers of the summary file
		InitialTimeSummaryFile << "Computation time in seconds" << std::endl;
		InitialTimeSummaryFile << "Instance \\ p";
		for (auto p = P.begin(); p != P.end(); ++p){
			InitialTimeSummaryFile << " & " << *p;
		}
		InitialTimeSummaryFile << " \\\\" << std::endl;
	}
	//Initialize LP value summary file
	std::stringstream LPValueSummaryFileName;
	LPValueSummaryFileName << TestOutputFolder.str().c_str() << "LPValueSummary.txt";
	std::ofstream LPValueSummaryFile(LPValueSummaryFileName.str().c_str());
	//Check whether the file could be opened
	if (!LPValueSummaryFile){
		std::cout << "Cannot open file " << LPValueSummaryFileName.str().c_str() << "." << std::endl;
		return;
	}
	else{
		//Write headers of the summary file
		LPValueSummaryFile << "LP value" << std::endl;
		LPValueSummaryFile << "Instance \\ p";
		for (auto p = P.begin(); p != P.end(); ++p){
			LPValueSummaryFile << " & " << *p;
		}
		LPValueSummaryFile << " \\\\" << std::endl;
	}
	//close summary files
	InitialTimeSummaryFile.close();
	LPValueSummaryFile.close();

	//Number of digits behind the comma in the summary output files
	int Digits = 2;


	//EXPERIMENT
	//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

	//Solve E instances:
	//************************************************************************
	//Check if any E instances are selected
	if (!EK.empty()){

		//Print progress:
		std::cout << "Computation time in seconds of the E instances:" << std::endl;
		std::cout << "-----------------------------------------------" << std::endl;

		//Go over all E instances
		auto k = EK.begin();
		for (auto n = EN.begin(); n != EN.end(); ++n){

			//Read instance
			std::stringstream InstanceFileName;
			InstanceFileName << TestInstancesFolder.str().c_str() << "HomeMadeFormat_E-n" << *n << "-k" << *k << ".txt";
			CVRPInstance CurrentInstance(InstanceFileName.str().c_str());

			//Update summary files:
			//Open summary files
			std::ofstream TimeSummaryFile1(TimeSummaryFileName.str().c_str(), std::ios::app);
			std::ofstream LPValueSummaryFile1(LPValueSummaryFileName.str().c_str(), std::ios::app);
			//Update files
			TimeSummaryFile1 << "E-n" << *n << "-k" << *k;
			LPValueSummaryFile1 << "E-n" << *n << "-k" << *k;
			//Close files
			TimeSummaryFile1.close();
			LPValueSummaryFile1.close();

			//Print progress:
			std::cout << "E-n" << *n << "-k" << *k;

			//Go over all selected values of p
			for (auto p = P.begin(); p != P.end(); ++p){

				//Initialize settings
				PStep_AlgorithmSettings CurrentAlgorithmSettings = TemplateAlgorithmSettings;
				CurrentAlgorithmSettings.p = *p;

				//Initialize algorithm
				PStep_Algorithm Algorithm;

				//Perform Branch-Price-and-Cut
				Algorithm.SolveRootNode(CurrentInstance, CurrentAlgorithmSettings);

				//Write output to file:
				std::stringstream OutputFileName;
				OutputFileName << TestOutputFolder.str().c_str() << "CGStatistics_E-n" << *n << "-k" << *k << "_p" << *p << ".txt";
				Algorithm.AlgorithmMembers.CurrentCGStatistics.Write(OutputFileName.str().c_str());

				//Append results to summary files
				//Open summary files
				std::ofstream TimeSummaryFile2(TimeSummaryFileName.str().c_str(), std::ios::app);
				std::ofstream LPValueSummaryFile2(LPValueSummaryFileName.str().c_str(), std::ios::app);
				//Set precision of summary files
				TimeSummaryFile2 << std::fixed;
				TimeSummaryFile2.precision(Digits);
				LPValueSummaryFile2 << std::fixed;
				LPValueSummaryFile2.precision(Digits);
				//Check algorithm flag and update summary files
				if (Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 0){
					TimeSummaryFile2 << " & " << Algorithm.AlgorithmMembers.CurrentCGStatistics.TotalComputationTime;
					LPValueSummaryFile2 << " & " << Algorithm.AlgorithmMembers.CurrentCGStatistics.FinalValue;
				}
				else if (Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 1){
					TimeSummaryFile2 << " & -";
					LPValueSummaryFile2 << " & -";
				}
				else if (Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 2){
					TimeSummaryFile2 << " & " << Algorithm.AlgorithmMembers.CurrentCGStatistics.TotalComputationTime;
					LPValueSummaryFile2 << " & -";
				}
				//Close summary files
				TimeSummaryFile2.close();
				LPValueSummaryFile2.close();

				//Print progress
				if (Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 0 || Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 2){
					std::cout << " & " << Algorithm.AlgorithmMembers.CurrentCGStatistics.TotalComputationTime;
				}
				else{
					std::cout << " & -";
				}

			}//end go over all selected values of p

			//Update summary files:
			//Open summary files
			std::ofstream TimeSummaryFile3(TimeSummaryFileName.str().c_str(), std::ios::app);
			std::ofstream LPValueSummaryFile3(LPValueSummaryFileName.str().c_str(), std::ios::app);
			//Update files
			TimeSummaryFile3 << " \\\\" << std::endl;
			LPValueSummaryFile3 << " \\\\" << std::endl;
			//Close files
			TimeSummaryFile3.close();
			LPValueSummaryFile3.close();

			//Print progress:
			std::cout << " \\\\" << std::endl;

			//Update k
			++k;

		} //end go over all E-instances

		//Print progress:
		std::cout << std::endl;

	}//end check whether E instances are selected

	//Solve A instances:
	//************************************************************************
	//Check if any A instances are selected
	if (!AK.empty()){

		//Print progress:
		std::cout << "Computation time in seconds of the A instances:" << std::endl;
		std::cout << "-----------------------------------------------" << std::endl;

		//Go over all A instances
		auto k = AK.begin();
		for (auto n = AN.begin(); n != AN.end(); ++n){

			//Read instance
			std::stringstream InstanceFileName;
			InstanceFileName << TestInstancesFolder.str().c_str() << "HomeMadeFormat_A-n" << *n << "-k" << *k << ".txt";
			CVRPInstance CurrentInstance(InstanceFileName.str().c_str());

			//Update summary files:
			//Open summary files
			std::ofstream TimeSummaryFile1(TimeSummaryFileName.str().c_str(), std::ios::app);
			std::ofstream LPValueSummaryFile1(LPValueSummaryFileName.str().c_str(), std::ios::app);
			//Update files
			TimeSummaryFile1 << "A-n" << *n << "-k" << *k;
			LPValueSummaryFile1 << "A-n" << *n << "-k" << *k;
			//Close files
			TimeSummaryFile1.close();
			LPValueSummaryFile1.close();

			//Print progress:
			std::cout << "A-n" << *n << "-k" << *k;

			//Go over all selected values of p
			for (auto p = P.begin(); p != P.end(); ++p){

				//Initialize settings
				PStep_AlgorithmSettings CurrentAlgorithmSettings = TemplateAlgorithmSettings;
				CurrentAlgorithmSettings.p = *p;

				//Initialize algorithm
				PStep_Algorithm Algorithm;

				//Perform Branch-Price-and-Cut
				Algorithm.SolveRootNode(CurrentInstance, CurrentAlgorithmSettings);

				//Write output to file:
				std::stringstream OutputFileName;
				OutputFileName << TestOutputFolder.str().c_str() << "CGStatistics_A-n" << *n << "-k" << *k << "_p" << *p << ".txt";
				Algorithm.AlgorithmMembers.CurrentCGStatistics.Write(OutputFileName.str().c_str());

				//Append results to summary files
				//Open summary files
				std::ofstream TimeSummaryFile2(TimeSummaryFileName.str().c_str(), std::ios::app);
				std::ofstream LPValueSummaryFile2(LPValueSummaryFileName.str().c_str(), std::ios::app);
				//Set precision of summary files
				TimeSummaryFile2 << std::fixed;
				TimeSummaryFile2.precision(Digits);
				LPValueSummaryFile2 << std::fixed;
				LPValueSummaryFile2.precision(Digits);
				//Check algorithm flag and update summary files
				if (Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 0){
					TimeSummaryFile2 << " & " << Algorithm.AlgorithmMembers.CurrentCGStatistics.TotalComputationTime;
					LPValueSummaryFile2 << " & " << Algorithm.AlgorithmMembers.CurrentCGStatistics.FinalValue;
				}
				else if (Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 1){
					TimeSummaryFile2 << " & -";
					LPValueSummaryFile2 << " & -";
				}
				else if (Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 2){
					TimeSummaryFile2 << " & " << Algorithm.AlgorithmMembers.CurrentCGStatistics.TotalComputationTime;
					LPValueSummaryFile2 << " & -";
				}
				//Close summary files
				TimeSummaryFile2.close();
				LPValueSummaryFile2.close();

				//Print progress
				if (Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 0 || Algorithm.AlgorithmMembers.CurrentCGStatistics.Flag == 2){
					std::cout << " & " << Algorithm.AlgorithmMembers.CurrentCGStatistics.TotalComputationTime;
				}
				else{
					std::cout << " & -";
				}

			}//end go over all selected values of p

			//Update summary files:
			//Open summary files
			std::ofstream TimeSummaryFile3(TimeSummaryFileName.str().c_str(), std::ios::app);
			std::ofstream LPValueSummaryFile3(LPValueSummaryFileName.str().c_str(), std::ios::app);
			//Update files
			TimeSummaryFile3 << " \\\\" << std::endl;
			LPValueSummaryFile3 << " \\\\" << std::endl;
			//Close files
			TimeSummaryFile3.close();
			LPValueSummaryFile3.close();

			//Print progress:
			std::cout << " \\\\" << std::endl;

			//Update k
			++k;

		} //end go over all A-instances

		//Print progress:
		std::cout << std::endl;

	}//end check whether A instances are selected

}