# Path: search/temporal_relaxation.py
# class TemporalRelaxation(object):
# 
#     def __init__(self, constraint):
#         self.constraint = constraint
#         self.relaxed_lb = None
#         self.relaxed_ub = None
# 
#     def implement(self):
#         if self.relaxed_lb is not None:
#             self.constraint.relaxed_lb = self.relaxed_lb
# 
#         if self.relaxed_ub is not None:
#             self.constraint.relaxed_ub = self.relaxed_ub
# 
#     def pretty_print(self):
#         if self.relaxed_lb is not None:
#             cost = -1 * abs(self.relaxed_lb - self.constraint.lower_bound) * self.constraint.relax_cost_lb
#             print(str(self.constraint.name) + "(LB): "+ str(self.constraint.lower_bound) +" -> "+str(self.relaxed_lb) + " (" +str(cost)+ ")")
# 
#         if self.relaxed_ub is not None:
#             cost = -1 * abs(self.relaxed_ub - self.constraint.upper_bound) * self.constraint.relax_cost_ub
#             print(str(self.constraint.name) + "(UB): "+ str(self.constraint.upper_bound) +" -> "+str(self.relaxed_ub) + " (" +str(cost)+ ")")
# 
# Path: temporal_network/tpnu.py
# class FeasibilityType(object):
#     CONSISTENCY = 1
#     STRONG_CONTROLLABILITY = 2
#     DYNAMIC_CONTROLLABILITY = 3


from pulp import solvers, LpProblem, LpMinimize, LpVariable, value
from search.temporal_relaxation import TemporalRelaxation
from temporal_network.tpnu import FeasibilityType
                import gurobipy
                                variable = LpVariable(constraint.id + "-LB",None,constraint.lower_bound)
                                # print("New LB VAR: " + str(variable) + " [" + str(None) + "," + str(constraint.lower_bound) + "]")
                                # add the variable to the objective function
                                lp_variables[(constraint,bound)] = variable
                                lp_objective.append((constraint.lower_bound - variable) * constraint.relax_cost_lb)
                            else:
                                variable = LpVariable(constraint.id + "-LB",constraint.lower_bound, constraint.upper_bound-0.001)
                                # print("New LB-UC VAR: " + str(variable) + " [" + str(None) + "," + str(constraint.lower_bound) + "]")
                                # add the variable to the objective function
                                lp_variables[(constraint,bound)] = variable
                                lp_objective.append((variable - constraint.lower_bound) * constraint.relax_cost_lb)

                                # Add an additional constraint to make sure that
                                # the lower bound is smaller than the upper bound
                                if (constraint,1) in lp_variables:
                                    ub_variable = lp_variables[(constraint,1)]
                                    uncertain_duration_constraint = []
                                    uncertain_duration_constraint.append((ub_variable - variable))
                                    prob += sum(uncertain_duration_constraint) >= 0.001
                                    # print("Adding domain constraint for " + constraint.name)

                        else:
                            variable = constraint.lower_bound

                    elif bound == 1:
                        # upper bound, the domain is larger than the original UB
                        # if the constraint is not relaxable, fix its domain
                        if constraint.relaxable_ub:
                            # print("UB cost " + str(constraint.relax_cost_ub) + "/" + constraint.name)


# Path: search/temporal_relaxation.py
# class TemporalRelaxation(object):
# 
#     def __init__(self, constraint):
#         self.constraint = constraint
#         self.relaxed_lb = None
#         self.relaxed_ub = None
# 
#     def implement(self):
#         if self.relaxed_lb is not None:
#             self.constraint.relaxed_lb = self.relaxed_lb
# 
#         if self.relaxed_ub is not None:
#             self.constraint.relaxed_ub = self.relaxed_ub
# 
#     def pretty_print(self):
#         if self.relaxed_lb is not None:
#             cost = -1 * abs(self.relaxed_lb - self.constraint.lower_bound) * self.constraint.relax_cost_lb
#             print(str(self.constraint.name) + "(LB): "+ str(self.constraint.lower_bound) +" -> "+str(self.relaxed_lb) + " (" +str(cost)+ ")")
# 
#         if self.relaxed_ub is not None:
#             cost = -1 * abs(self.relaxed_ub - self.constraint.upper_bound) * self.constraint.relax_cost_ub
#             print(str(self.constraint.name) + "(UB): "+ str(self.constraint.upper_bound) +" -> "+str(self.relaxed_ub) + " (" +str(cost)+ ")")
# 
# Path: temporal_network/tpnu.py
# class FeasibilityType(object):
#     CONSISTENCY = 1
#     STRONG_CONTROLLABILITY = 2
#     DYNAMIC_CONTROLLABILITY = 3


# Path: search/mincost_relaxation.py
from pulp import solvers, LpProblem, LpMinimize, LpVariable, value
from search.temporal_relaxation import TemporalRelaxation
from temporal_network.tpnu import FeasibilityType
                import gurobipy

                                variable = LpVariable(constraint.id + "-LB",None,constraint.lower_bound)
                                # print("New LB VAR: " + str(variable) + " [" + str(None) + "," + str(constraint.lower_bound) + "]")
                                # add the variable to the objective function
                                lp_variables[(constraint,bound)] = variable
                                lp_objective.append((constraint.lower_bound - variable) * constraint.relax_cost_lb)
                            else:
                                variable = LpVariable(constraint.id + "-LB",constraint.lower_bound, constraint.upper_bound-0.001)
                                # print("New LB-UC VAR: " + str(variable) + " [" + str(None) + "," + str(constraint.lower_bound) + "]")
                                # add the variable to the objective function
                                lp_variables[(constraint,bound)] = variable
                                lp_objective.append((variable - constraint.lower_bound) * constraint.relax_cost_lb)

                                # Add an additional constraint to make sure that
                                # the lower bound is smaller than the upper bound
                                if (constraint,1) in lp_variables:
                                    ub_variable = lp_variables[(constraint,1)]
                                    uncertain_duration_constraint = []
                                    uncertain_duration_constraint.append((ub_variable - variable))
                                    prob += sum(uncertain_duration_constraint) >= 0.001
                                    # print("Adding domain constraint for " + constraint.name)

                        else:
                            variable = constraint.lower_bound

                    elif bound == 1:
                        # upper bound, the domain is larger than the original UB
                        # if the constraint is not relaxable, fix its domain
                        if constraint.relaxable_ub:
                            # print("UB cost " + str(constraint.relax_cost_ub) + "/" + constraint.name)


                            if constraint.controllable or feasibility_type == FeasibilityType.CONSISTENCY: