# 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
        # print("Cycles: " + str(len(all_cycles)))
        for cycle in all_cycles:
            # cycle.pretty_print()

            lp_ncycle_constraint = []

            for constraint, bound in cycle.constraints.keys():
                # The constraint is a pair (temporal_constraint,0/1)
                # where 0 or 1 represent if it is the lower or upper bound

                # first we define the variables
                # which only come from relaxable bounds of constraints
                # in other words, if no constraint in a negative cycle is
                # relaxable, the LP is infeasible
                # and we can stop here

                # TODO: add handler for uncontrollable duration
                variable = None
                if (constraint, bound) in lp_variables:
                    variable = lp_variables[(constraint, bound)]

                coefficient = cycle.constraints[(constraint, bound)]

                if variable is None:
                    if bound == 0:
                        # lower bound, the domain is less than the original LB
                        # if the constraint is not relaxable, fix its domain
                        if constraint.relaxable_lb:
                            # print("LB cost " + str(constraint.relax_cost_lb) + "/" + 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

        # print("Cycles: " + str(len(all_cycles)))
        for cycle in all_cycles:
            # cycle.pretty_print()

            lp_ncycle_constraint = []

            for constraint, bound in cycle.constraints.keys():
                # The constraint is a pair (temporal_constraint,0/1)
                # where 0 or 1 represent if it is the lower or upper bound

                # first we define the variables
                # which only come from relaxable bounds of constraints
                # in other words, if no constraint in a negative cycle is
                # relaxable, the LP is infeasible
                # and we can stop here

                # TODO: add handler for uncontrollable duration
                variable = None
                if (constraint, bound) in lp_variables:
                    variable = lp_variables[(constraint, bound)]

                coefficient = cycle.constraints[(constraint, bound)]

                if variable is None:
                    if bound == 0:
                        # lower bound, the domain is less than the original LB
                        # if the constraint is not relaxable, fix its domain
                        if constraint.relaxable_lb:
                            # print("LB cost " + str(constraint.relax_cost_lb) + "/" + constraint.name)


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