/*Implementation of PStep_Dominator

It contains the member functions of PStep_Dominator and all derived classes

*/

#include "PStep_Dominator.h"

//PStep_Dominator:
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load and costs are checked.
bool PStep_Dominator::Dominate(const Label& CurrentLabel, const Label& NextLabel){

	//Check dominance
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance && CurrentLabel.Cost <= NextLabel.Cost + Tolerance){
		return true;
	}
	return false;

}

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load and costs are checked.
bool PStep_Dominator::Dominate(const ForwardLabel& CurrentLabel, const ForwardLabel& NextLabel){

	//Check dominance
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance && CurrentLabel.Cost <= NextLabel.Cost + Tolerance){
		return true;
	}
	return false;

}

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load and costs are checked.
bool PStep_Dominator::Dominate(const BackwardLabel& CurrentLabel, const BackwardLabel& NextLabel){

	//Check dominance
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance && CurrentLabel.Cost <= NextLabel.Cost + Tolerance){
		return true;
	}
	return false;

}


//PStep_ReachabilityDominator:
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load and reachability are checked.
bool PStep_ReachabilityDominator::Dominate(const Label& CurrentLabel, const Label& NextLabel){
	
	//Check Dominance:
	//Check load and costs
	if (CurrentLabel.Load > NextLabel.Load + Tolerance){
		return false;
	}
	else
	{//Check reachability
		//Obtain end point
		bool* CurrentReachableEnd = &CurrentLabel.Reachable[CurrentLabel.NumberOfCustomers];
		//Initialize pointer to Reachable of NextLabel
		bool* NextReachable = NextLabel.Reachable;
		//Go over all customers
		for (bool* CurrentReachable = CurrentLabel.Reachable; CurrentReachable != CurrentReachableEnd; ++CurrentReachable){
			//Check dominance
			if (*NextReachable && !(*CurrentReachable)){
				return false;
			}
			//Update pointer to Reachable of NextLabel
			++NextReachable;
		}
		/*//Old version:
		for (short int i = 0; i < CurrentLabel.NumberOfCustomers; ++i){
			if (NextLabel.Reachable[i] && !(CurrentLabel.Reachable[i])){
				return false;
			}
		}*/

	}
	return true;

	/*//Bitset version
	//Check dominance
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance && CurrentLabel.Cost <= NextLabel.Cost + Tolerance && ((CurrentLabel.Reachable | NextLabel.Reachable) == CurrentLabel.Reachable)){
		return true;
	}
	return false;*/

}

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load and reachability are checked.
bool PStep_ReachabilityDominator::Dominate(const ForwardLabel& CurrentLabel, const ForwardLabel& NextLabel){

	//Check Dominance:
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance && ((CurrentLabel.Reachable | NextLabel.Reachable) == CurrentLabel.Reachable)){
		return true;
	}
	return false;

}

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load and reachability are checked.
bool PStep_ReachabilityDominator::Dominate(const BackwardLabel& CurrentLabel, const BackwardLabel& NextLabel){

	//Check Dominance:
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance && ((CurrentLabel.Reachable | NextLabel.Reachable) == CurrentLabel.Reachable)){
		return true;
	}
	return false;

}

//PStep_LoadDominator:
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load is checked.
bool PStep_LoadDominator::Dominate(const Label& CurrentLabel, const Label& NextLabel){

	//Check dominance
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance){
		return true;
	}
	return false;

}
bool PStep_LoadDominator::Dominate(const ForwardLabel& CurrentLabel, const ForwardLabel& NextLabel){

	//Check dominance
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance){
		return true;
	}
	return false;

}
bool PStep_LoadDominator::Dominate(const BackwardLabel& CurrentLabel, const BackwardLabel& NextLabel){

	//Check dominance
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance){
		return true;
	}
	return false;

}

//PStep_ReachabilityOnlyDominator:
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively reachability is checked.
bool PStep_ReachabilityOnlyDominator::Dominate(const Label& CurrentLabel, const Label& NextLabel){

	//Check Dominance:
	
	//Check reachability
	//Obtain end point
	bool* CurrentReachableEnd = &CurrentLabel.Reachable[CurrentLabel.NumberOfCustomers];
	//Initialize pointer to Reachable of NextLabel
	bool* NextReachable = NextLabel.Reachable;
	//Go over all customers
	for (bool* CurrentReachable = CurrentLabel.Reachable; CurrentReachable != CurrentReachableEnd; ++CurrentReachable){
		//Check dominance
		if (*NextReachable && !(*CurrentReachable)){
			return false;
		}
		//Update pointer to Reachable of NextLabel
		++NextReachable;
	}
	return true;

}

//PStep_NGReachabilityDominator:
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load, costs and reachability are checked.
//Reachability is checked only for customers in the neighbourhood of CurrentLabel.LastLocation.
//NOTE: This function CANNOT be applied if the CurrentLabel.LastLocation is the depot.
bool PStep_NGReachabilityDominator::Dominate(const Label& CurrentLabel, const Label& NextLabel){

	//Check Dominance:
	//Check load and costs
	if (CurrentLabel.Load > NextLabel.Load + Tolerance){
		return false;
	}
	else
	{ //Check reachability

		//Obtain the neighbourhood of the CurrentLabel.LastLocation
		std::vector<short int >& CurrentNeighbourhood = Neighbourhoods[CurrentLabel.LastLocation-1];

		//Go over all customers in the neighbourhood
		for (auto i = CurrentNeighbourhood.begin(); i != CurrentNeighbourhood.end(); ++i){
			if (NextLabel.Reachable[*i] && !(CurrentLabel.Reachable[*i])){
				return false;
			}
		}

	}
	return true;

}

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load, costs and reachability are checked.
//Reachability is checked only for customers in the neighbourhood of CurrentLabel.LastLocation.
//NOTE: This function CANNOT be applied if the CurrentLabel.LastLocation is the depot.
bool PStep_NGReachabilityDominator::Dominate(const ForwardLabel& CurrentLabel, const ForwardLabel& NextLabel){

	//Check Dominance:
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance && ((CurrentLabel.Reachable | NextLabel.Reachable) == CurrentLabel.Reachable)){
		return true;
	}
	return false;

}

//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively load, costs and reachability are checked.
//Reachability is checked only for customers in the neighbourhood of CurrentLabel.LastLocation.
//NOTE: This function CANNOT be applied if the CurrentLabel.FirstLocation is the depot.
bool PStep_NGReachabilityDominator::Dominate(const BackwardLabel& CurrentLabel, const BackwardLabel& NextLabel){

	//Check Dominance:
	if (CurrentLabel.Load <= NextLabel.Load + Tolerance && ((CurrentLabel.Reachable | NextLabel.Reachable) == CurrentLabel.Reachable)){
		return true;
	}
	return false;

}

//PStep_NGReachabilityOnlyDominator:
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//This function checks whether CurrentLabel dominates NextLabel, if so the output is true, otherwise false.
//Exclusively reachability is checked.
//Reachability is checked only for customers in the neighbourhood of CurrentLabel.LastLocation.
//NOTE: This function CANNOT be applied if the CurrentLabel.LastLocation is the depot.
bool PStep_NGReachabilityOnlyDominator::Dominate(const Label& CurrentLabel, const Label& NextLabel){

	//Check Dominance:
	
	//Check reachability
	//Obtain the neighbourhood of the CurrentLabel.LastLocation
	std::vector<short int >& CurrentNeighbourhood = Neighbourhoods[CurrentLabel.LastLocation - 1];
	//Go over all customers in the neighbourhood
	for (auto i = CurrentNeighbourhood.begin(); i != CurrentNeighbourhood.end(); ++i){
		if (NextLabel.Reachable[*i] && !(CurrentLabel.Reachable[*i])){
			return false;
		}
	}
	return true;

}