Ejemplo n.º 1
0
    def get_solution(self, m):                    
        solution = Candidate()
        
      #  f = open('sol.txt', 'w')
        
        for var_a in m.getVars():
            vname = var_a.getAttr(GRB.Attr.VarName)
            if self.objective_type == ObjectiveType.MAX_FLEX_UNCERTAINTY:
                if vname.find("cl") == -1 and vname.find("cu") == -1:
                    continue
                
                #f.write('%s    %s\n' % (var_a.getAttr(GRB.Attr.VarName), var_a.getAttr(GRB.Attr.X)))
                
                # if vname.find("l") != -1:
                #   print(var_a.getAttr(GRB.Attr.VarName), var_a.getAttr(GRB.Attr.X))
                e = self.relax_e[vname]
    
                new_relaxation = TemporalRelaxation(e)
                if vname.find("cl") != -1:
                    new_relaxation.relaxed_lb = var_a.getAttr("X")
                    if new_relaxation.relaxed_lb != e.get_lower_bound():
                        solution.add_temporal_relaxation(new_relaxation)                            
                else :
                    new_relaxation.relaxed_ub = var_a.getAttr("X")
                    if new_relaxation.relaxed_ub != e.get_upper_bound():
                        solution.add_temporal_relaxation(new_relaxation)   
            elif self.objective_type == ObjectiveType.MIN_COST:
                if vname.find("vlr") == -1 and vname.find("vur") == -1:
                    continue;
                e = self.relax_e[vname]
                #print(vname,e.fro, e.to)
                new_relaxation = TemporalRelaxation(e)
                if vname.find("vlr") != -1:
                    new_relaxation.relaxed_lb = self.l[(e.fro,e.to)].getValue()
                else:
                    new_relaxation.relaxed_ub = self.u[(e.fro, e.to)].getValue()
                if var_a.getAttr("X") > 0:
                    solution.add_temporal_relaxation(new_relaxation)
#        for e in self.network.temporal_constraints.values():
#            if e.activated:
#                print(e.fro, e.to, self.l[(e.fro, e.to)].getValue(), self.u[(e.fro, e.to)].getValue())
                                     
                    
        solution.utility = round(m.getObjective().getValue(), 6)
        if solution.utility > 1000 and self.objective_type == ObjectiveType.MAX_FLEX_UNCERTAINTY:
            solution.utility = 1000
        
#         for node_a in range(1, self.num_nodes+1):
#             for node_b in range(1, self.num_nodes+1):
#                 if node_a != node_b:
#                     f.write("%s->%s [%s, %s]\n"%(node_a,node_b,self.l[(node_a,node_b)].getValue(), self.u[(node_a,node_b)].getValue() ))
#        # if solution.utility > 100:
        #    solution.utility = 100
      #  f.close()
        
        #print a dot file
     #   f = open('sol.dot', 'w')
      #  f.write('digraph G {\n nodesep = .45; \n size = 30;\n label="CCTP";\n')
#          
#         for e in self.network.temporal_constraints.values():
#             if e.activated:
#                 f.write('"%s"->"%s"'%(e.fro, e.to))
#                 tlb = self.l[(e.fro, e.to)].getValue()
#                 tub = self.u[(e.fro, e.to)].getValue() 
#                 f.write('[ label = "[%s,%s]'%(tlb, tub))
#                 if not e.controllable:
#                     f.write(' type=dashed')
#                 f.write('"];\n')           
#                  #%d"];'%(e.fro, e.to,e.get_lower_bound(),e.get_upper_bound(),e.controllable))
             
      #  f.write("}")
      #  f.close()
        return solution     
Ejemplo n.º 2
0
    def generate_maxflex_relaxations(candidate,negative_cycle):

        if len(negative_cycle.constraints) == 0:
            return None,0

        all_cycles = candidate.continuously_resolved_cycles.copy()
        all_cycles.add(negative_cycle)

        # Solve using PuLP, TODO, incorporate interface to other solvers,
        # especially for nonlinear objective functions
        prob = LpProblem("MaxFlexConflictResolution", LpMaximize)

        # Solve using PyOpt/Snopt,
        # especially for nonlinear constraints/objective functions

        # construct variables and constraints
        lp_variables = {}
        lp_objective = []

        max_flex_variable = LpVariable("Max Flex",0, None)
        lp_objective.append(max_flex_variable)

        # status indicating the feasibility of the relaxation problem
        # 1 is feasible
        # 0 is infeasible
        # Note that this variable is shared by PuLP for its result
        status = 1;

        # We only consider the relaxation of the upper bound of
        # uncontrollable duration.
        # which means that we basically ignore the definition of
        # 'relaxable bounds' in the network, and only consider the upper bounds
        # of uncertain durations.

        for cycle in all_cycles:

            lp_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:
                        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 not constraint.controllable:
                            variable = LpVariable(constraint.id + "-UB",constraint.lower_bound, constraint.upper_bound)
                            lp_variables[(constraint,bound)] = variable
                            # add the variable to the objective function

                            max_flex_constraint = []
                            max_flex_constraint.append((variable-constraint.lower_bound))
                            max_flex_constraint.append(-1.0*max_flex_variable)
                            prob += sum(max_flex_constraint) >= 0
                        else:
                            variable = constraint.upper_bound

                    assert variable is not None

                lp_constraint.append(variable*coefficient)

            # add the constraint to the problem
            # print(str(lp_constraint))
            if sum(lp_constraint) >= 0:
                # print(str(sum(lp_constraint)) + " >= 0")
                prob += sum(lp_constraint) >= 0
            else:
                status = 0;
                # this is not resolvable
                # no need to proceed

        if status > 0:
            # Set the objective function
            prob += sum(lp_objective)
            # for c in prob.constraints:
            #     print("CON: ", prob.constraints[c])
            # print("OBJ: ", prob.objective)

            # Solve the problem
            try:
                import gurobipy
                status = prob.solve(solvers.GUROBI(mip=False,msg=False))
            except ImportError:
                pass # Gurobi doesn't exist, use default Pulp solver.
                status = prob.solve()

            # exit(0);


        # if no solution was found, do nothing

        if status > 0:
            # A solution has been bound
            # extract the result and store them into a set of relaxation
            # the outcome is a set of relaxations
            relaxations = []
            max_flex_value = value(max_flex_variable)

            for constraint, bound in lp_variables.keys():
                variable = lp_variables[(constraint, bound)]
                relaxed_bound = value(variable)

                if bound == 0:
                    # check if this constraint bound is relaxed
                    if relaxed_bound != constraint.lower_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_lb = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)

                elif bound == 1:
                    # same for upper bound
                    if relaxed_bound != constraint.upper_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_ub = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)

            if len(relaxations) > 0:
                return relaxations,max_flex_value

        return None,0
Ejemplo n.º 3
0
    def generate_cc_relaxations(candidate,negative_cycle,feasibility_type,cc,pInfinity=1e6,nInfinity=-1e6):

        global prob_means
        global prob_stds
        global prob_vars
        global cc_var

        all_cycles = candidate.continuously_resolved_cycles.copy()
        all_cycles.add(negative_cycle)
        # print("CC Solving against " + str(len(all_cycles)) + " cycles")

        numVar = 0
        numConstraint = 0

        # Solve using Snopt,
        # especiallFy for nonlinear constraints/objective functions

        # construct variables and constraints
        variables = {}
        variable_bounds = {}
        initial_values = {}
        constraints = []
        objective = {}

        list_iA = []
        list_jA = []
        list_A = []
        neA_count = 0

        list_iG = []
        list_jG = []
        neG_count = 0

        prob_durations = set()
        prob_means = []
        prob_stds = []
        prob_vars = []
        cc_var = -1

        # status indicating the feasibility of the relaxation problem
        # 1 is feasible
        # 0 is infeasible
        # Note that this variable is shared by PuLP for its result
        status = 1;

        # print("Cycles: " + str(len(all_cycles)))
        for cycle in all_cycles:
            lp_ncycle_constraint = {}
            rhs = 0

            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 variables:
                    variable = 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 or (not constraint.controllable and constraint.probabilistic):
                        # if constraint.relaxable_lb:
                            # print("LB cost " + str(constraint.relax_cost_lb) + "/" + constraint.name)

                            variable = numVar
                            variables[(constraint, bound)] = variable
                            initial_values[variable] = constraint.get_lower_bound()
                            numVar += 1

                            if constraint.controllable or feasibility_type == FeasibilityType.CONSISTENCY:
                                # add the variable to the objective function

                                variable_bounds[variable] = [nInfinity,constraint.lower_bound]
                                objective[variable] = [-1*constraint.relax_cost_lb,constraint.lower_bound*constraint.relax_cost_lb]

                            else:
                                variable_bounds[variable] = [constraint.lower_bound,constraint.upper_bound-0.001]

                                # We collect all probabilistic durations
                                # for encoding the chance constraint
                                if constraint.probabilistic:
                                    prob_durations.add(constraint)
                                else:
                                    objective[variable] = [constraint.relax_cost_lb,
                                                           -1 * constraint.lower_bound * constraint.relax_cost_lb]

                                    # Add an additional constraint to make sure that
                                    # the lower bound is smaller than the upper bound
                                    # Only for non-probabilistic constraint
                                    if (constraint, 1) in variables :
                                        ub_variable = variables[(constraint, 1)]

                                        constraint = {}
                                        constraint[ub_variable] = 1
                                        constraint[variable] = -1
                                        constraint['lb'] = 0.001
                                        constraint['ub'] = pInfinity

                                        constraints.append(constraint)

                                        list_iA.append(len(constraints))
                                        list_jA.append(ub_variable + 1)
                                        list_A.append(1)
                                        neA_count += 1

                                        list_iA.append(len(constraints))
                                        list_jA.append(variable + 1)
                                        list_A.append(-1)
                                        neA_count += 1

                            lp_ncycle_constraint[variable] = coefficient

                        else:
                            variable = constraint.lower_bound
                            rhs -= constraint.lower_bound*coefficient

                    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 or (not constraint.controllable and constraint.probabilistic):
                        # if constraint.relaxable_ub:
                            # print("UB cost " + str(constraint.relax_cost_ub) + "/" + constraint.name)

                            variable = numVar
                            variables[(constraint, bound)] = variable
                            initial_values[variable] = constraint.get_upper_bound()
                            numVar += 1

                            if constraint.controllable or feasibility_type == FeasibilityType.CONSISTENCY:
                                variable_bounds[variable] = [constraint.upper_bound, pInfinity]
                                objective[variable] = [constraint.relax_cost_ub,-1*constraint.upper_bound*constraint.relax_cost_ub]

                            else:
                                variable_bounds[variable] = [constraint.lower_bound+0.001, constraint.upper_bound]

                                # We collection all probabilistic durations
                                # for encoding the chance constraint
                                if constraint.probabilistic:
                                    prob_durations.add(constraint)
                                else:
                                    objective[variable] = [-1 * constraint.relax_cost_ub,
                                                           constraint.upper_bound * constraint.relax_cost_ub]

                                    # Add an additional constraint to make sure that
                                    # the lower bound is smaller than the upper bound
                                    # Only for non-probabilistic constraint
                                    if (constraint, 0) in variables:
                                        lb_variable = variables[(constraint, 0)]

                                        constraint = {}
                                        constraint[variable] = 1
                                        constraint[lb_variable] = -1
                                        constraint['lb'] = 0.001
                                        constraint['ub'] = pInfinity

                                        constraints.append(constraint)

                                        list_iA.append(len(constraints))
                                        list_jA.append(variable + 1)
                                        list_A.append(1)
                                        neA_count += 1

                                        list_iA.append(len(constraints))
                                        list_jA.append(lb_variable + 1)
                                        list_A.append(-1)
                                        neA_count += 1

                            lp_ncycle_constraint[variable] = coefficient
                        else:
                            variable = constraint.upper_bound
                            rhs -= constraint.upper_bound * coefficient
                    assert variable is not None

                else:
                    lp_ncycle_constraint[variable] = coefficient

                # print("Adding variable " + str(coefficient) + "*"+str(variable))

            # add the ncycle constraint to the problem
            # print(str(lp_ncycle_constraint))
            constraints.append(lp_ncycle_constraint)
            # print("C" + str(len(constraints)) + ": ", end="")
            empty_constraint = True
            for key in lp_ncycle_constraint:
                if lp_ncycle_constraint[key] != 0:
                    list_iA.append(len(constraints))
                    list_jA.append(key + 1)
                    list_A.append(lp_ncycle_constraint[key])
                    neA_count += 1
                    empty_constraint = False

                # constraint,bound = variables[key]
                # print(str(lp_ncycle_constraint[key]) + "*" + "(" +str(key)+ ") ", end="")

            lp_ncycle_constraint['lb'] = rhs+0.0001
            lp_ncycle_constraint['ub'] = pInfinity

            if empty_constraint and rhs > 0:
                # This constraint cannot be met
                return None,0

            # print(">= " + str(rhs))


        # Create the chance constraint
        if len(prob_durations) > 0:
            cc_constraint = {}
            constraints.append(cc_constraint)

            # Check if the chance constraint is relaxable
            if cc.relaxable_bound:
                cc_constraint['lb'] = -1
                cc_constraint['ub'] = 0

                # we need to encode an additional variable
                # to represent cc
                cc_var = numVar
                variables[("CC", 1)] = cc_var
                numVar += 1
                variable_bounds[cc_var] = [cc.risk_bound, pInfinity]

                list_iA.append(len(constraints))
                list_jA.append(cc_var + 1)
                list_A.append(-1)
                neA_count += 1

                # And add cc to the objective function
                objective[cc_var] = [cc.relax_cost, -1 * cc.risk_bound * cc.relax_cost]

            else:
                cc_constraint['lb'] = 0
                cc_constraint['ub'] = cc.risk_bound

            # print("C" + str(len(constraints)) + " (CC): ", end="")
            # print(str(cc_constraint['lb']) + "<= ", end="")

            for constraint in prob_durations:

                if (constraint, 0) in variables:
                    lb_var = variables[(constraint, 0)]
                else:
                    lb_var = numVar
                    variables[(constraint, 0)] = lb_var
                    numVar += 1

                if (constraint, 1) in variables:
                    ub_var = variables[(constraint, 1)]
                else:
                    ub_var = numVar
                    variables[(constraint, 1)] = ub_var
                    numVar += 1

                # override their domain since we are free to
                # allocate any values for them
                variable_bounds[lb_var] = [0, constraint.mean]
                variable_bounds[ub_var] = [constraint.mean, pInfinity]

                # initial_values[lb_var] = constraint.mean - 4*constraint.std
                # initial_values[ub_var] = constraint.mean + 4*constraint.std

                initial_values[lb_var] = constraint.get_lower_bound()
                initial_values[ub_var] = constraint.get_upper_bound()

                list_iG.append(len(constraints))
                list_jG.append(lb_var + 1)
                neG_count += 1
                list_iG.append(len(constraints))
                list_jG.append(ub_var + 1)
                neG_count += 1
                prob_vars.append(lb_var)
                prob_vars.append(ub_var)

                # print("Risk((" + str(lb_var) + ")--"+str(constraint.mean)+"--"+str(constraint.std)+"--("+str(ub_var)+")) ", end="")

                prob_means.append(constraint.mean)
                prob_stds.append(constraint.std)

            # print("<= " + str(cc_constraint['ub']))

        # Add the objective as the last constraint
        constraints.append(objective)

        for key in objective:
            list_iA.append(len(constraints))
            list_jA.append(key + 1)
            list_A.append(objective[key][0])

            if objective[key][0] != 0:
                neA_count += 1

        objective['lb'] = nInfinity
        objective['ub'] = pInfinity


        # Start Constructing the problem!!
        # Solve using SNOPT
        snopt.check_memory_compatibility()

        # minrw, miniw, mincw defines how much character, integer and real
        # storeage is neede to solve the problem.
        # ! assigned by SNOPT
        minrw = np.zeros((1), dtype=np.int32)
        miniw = np.zeros((1), dtype=np.int32)
        mincw = np.zeros((1), dtype=np.int32)

        # Workspace for character, integer and real arrays.
        # The plus 1 is for the objective function
        rw = np.zeros((2000*(len(variables)+len(constraints)),), dtype=np.float64)
        iw = np.zeros((1000*(len(variables)+len(constraints)),), dtype=np.int32)
        cw = np.zeros((8 * 500,), dtype=np.character)

        # rw = np.zeros((10000,), dtype=np.float64)
        # iw = np.zeros((10000,), dtype=np.int32)
        # cw = np.zeros((8 * 500,), dtype=np.character)

        # The Start variable for SnoptA
        Cold = np.array([0], dtype=np.int32)
        Basis = np.array([1], dtype=np.int32)
        Warm = np.array([2], dtype=np.int32)

        # Variable definitions

        # Initial values
        x = np.zeros((len(variables),), dtype=np.float64)

        # Lower and upper bounds
        xlow = np.zeros((len(variables),), dtype=np.float64)
        xupp = np.zeros((len(variables),), dtype=np.float64)

        for key in variable_bounds:
            if key in initial_values:
                x[key] = initial_values[key]
            bounds = variable_bounds[key]
            xlow[key] = bounds[0]
            xupp[key] = bounds[1]

        # Initial values for x
        xstate = np.zeros((len(variables),), dtype=np.int32)

        # Vector of dual variables for the bound constraints
        # ! assigned by SNOPT
        xmul = np.zeros((len(variables),), dtype=np.float64)


        # Initialize values for constraints
        F = np.zeros((len(constraints),), dtype=np.float64)

        # Lower and upper bounds for constraints
        Flow = np.zeros((len(constraints),), dtype=np.float64)
        Fupp = np.zeros((len(constraints),), dtype=np.float64)

        for idx in range(0,len(constraints)):
            constraint = constraints[idx]
            Flow[idx] = constraint['lb']
            Fupp[idx] = constraint['ub']


        # Initial states
        Fstate = np.zeros((len(constraints),), dtype=np.int32)
        # Estimate of the vector of Lagrange multipliers.
        # Since we know nothing about it at the moment. Set it to zero.
        Fmul = np.zeros((len(constraints),), dtype=np.float64)

        # Constant added to the objective row for
        # printing purposes
        ObjAdd = np.zeros((1,), dtype=np.float64)
        ObjAdd[0] = 0

        # The last row F is the objective function
        ObjRow = np.zeros((1,), dtype=np.int32)
        ObjRow[0] = len(constraints) # NOTE: We must add one to mesh with fortran */

        # Reports the result of the call to snOptA
        INFO = np.zeros((1,), dtype=np.int32)

        # Set number of variables
        n = np.zeros((1,), dtype=np.int32)
        n[0] = len(variables)

        # Set the number of functions (constraints and objectives)
        # in F
        neF = np.zeros((1,), dtype=np.int32)
        neF[0] = len(constraints)

        # dimension of arrays iAfun, jAvar and A
        # They contain the nonzero elements of the linear part A

        lenA = np.zeros((1,), dtype=np.int32)
        lenA[0] = len(list_iA)
        neA = np.zeros((1,), dtype=np.int32)
        neA[0] = neA_count

        # iAfun = np.zeros((lenA[0],), dtype=np.int32)
        # jAvar = np.zeros((lenA[0],), dtype=np.int32)
        # A = np.zeros((lenA[0],), dtype=np.float64)

        if lenA[0] > 0:
            iAfun = np.array(list_iA, dtype=np.int32)
            jAvar = np.array(list_jA, dtype=np.int32)
            A = np.array(list_A, dtype=np.float64)
        else:
            lenA[0] = 1
            iAfun = np.zeros((lenA[0],), dtype=np.int32)
            jAvar = np.zeros((lenA[0],), dtype=np.int32)
            A = np.zeros((lenA[0],), dtype=np.float64)

        # dimension of arrays iGfun and jGvar
        # They contain the nonzero elements of the nonlinear part of the derivativeG
        lenG = np.zeros((1,), dtype=np.int32)
        lenG[0] = len(list_iG)
        neG = np.zeros((1,), dtype=np.int32)
        neG[0] = neG_count

        if lenG[0] > 0:
            iGfun = np.array(list_iG, dtype=np.int32)
            jGvar = np.array(list_jG, dtype=np.int32)
        else:
            lenG[0] = 1
            iGfun = np.zeros((lenG[0],), dtype=np.int32)
            jGvar = np.zeros((lenG[0],), dtype=np.int32)

        # Generate the usrf function for SNOPT


        # names for variables and constraints
        # By default no names provided (both set to 1)
        nxname = np.zeros((1,), dtype=np.int32)
        nFname = np.zeros((1,), dtype=np.int32)
        nxname[0] = 1
        nFname[0] = 1

        # Names for variables and problem functions
        # not used when nxname and nFname are set to 1
        xnames = np.zeros((1 * 8,), dtype=np.character)
        Fnames = np.zeros((1 * 8,), dtype=np.character)
        Prob = np.zeros((200 * 8,), dtype=np.character)


        # final number of superbasic variables
        # ! assigned by SNOPT
        nS = np.zeros((1,), dtype=np.int32)

        # Number and sum of the infeasibilities of constraints
        nInf = np.zeros((1,), dtype=np.int32)
        sInf = np.zeros((1,), dtype=np.float64)




        # Define Print and Summary files
        # Must be called before any other SNOPT routing

        # Unit number for summary file
        iSumm = np.zeros((1,), dtype=np.int32)
        iSumm[0] = 0

        # Unit number for the print file
        iPrint = np.zeros((1,), dtype=np.int32)
        iPrint[0] = 0

        # Unit number for the specs file
        iSpecs = np.zeros((1,), dtype=np.int32)
        iSpecs[0] = 4

        # name for output print and spec files
        printname = np.zeros((200 * 8,), dtype=np.character)
        specname = np.zeros((200 * 8,), dtype=np.character)

        # open output files using snfilewrappers.[ch] */
        specn = "sntoya.spc"
        printn = "sntoya.out"
        specname[:len(specn)] = list(specn)
        printname[:len(printn)] = list(printn)

        # Open the print file, fortran style */
        snopt.snopenappend(iPrint, printname, INFO)


        # ================================================================== */
        # First,  sninit_ MUST be called to initialize optional parameters   */
        # to their default values.                                           */
        # ================================================================== */

        snopt.sninit(iPrint, iSumm, cw, iw, rw)


        # Set configurations
        strOpt = np.zeros((200 * 8,), dtype=np.character)
        DerOpt = np.zeros((1,), dtype=np.int32)

        # set derivative options
        strOpt_s = "Derivative option"
        DerOpt[0] = 1
        strOpt[:len(strOpt_s)] = list(strOpt_s)
        snopt.snseti(strOpt, DerOpt, iPrint, iSumm, INFO, cw, iw, rw)

        # set iteration limit
        Major = np.array([250], dtype=np.int32)
        strOpt_s = "Major Iteration limit"
        strOpt[:len(strOpt_s)] = list(strOpt_s)

        snopt.snseti(strOpt, Major, iPrint, iSumm, INFO, cw, iw, rw)

        # SnoptA will compute the Jacobian by finite-differences.   */
        # The user has the option of calling  snJac  to define the  */
        # coordinate arrays (iAfun,jAvar,A) and (iGfun, jGvar).     */


        #     ------------------------------------------------------------------ */
        #     Go for it, using a Cold start.                                     */
        #     ------------------------------------------------------------------ */

        # print("Computing relaxation")

        snopt.snopta(Cold, neF, n, nxname, nFname,
                     ObjAdd, ObjRow, Prob, usrf,
                     iAfun, jAvar, lenA, neA, A,
                     iGfun, jGvar, lenG, neG,
                     xlow, xupp, xnames, Flow, Fupp, Fnames,
                     x, xstate, xmul, F, Fstate, Fmul,
                     INFO, mincw, miniw, minrw,
                     nS, nInf, sInf, cw, iw, rw, cw, iw, rw)

        snopt.snclose(iPrint)
        snopt.snclose(iSpecs)

        # print("Done computing relaxation")

        # print("Solution " + str(x))

        if INFO[0] == 1:

            # An optimal solution has been found
            # extract the result and store them into a set of relaxation
            # the outcome is a set of relaxations
            relaxations = []
            allocations = []
            cc_relaxations = []

            # print("Found relaxation: INFO=" + str(INFO[0]))

            for constraint, bound in variables.keys():
                variable = variables[(constraint, bound)]
                relaxed_bound = x[variable]
                # print(str(variable) + "==" + str(x[variable]))

                if constraint == "CC":
                    # print("Relaxing CC from " + str(cc.risk_bound) + " to " + str(relaxed_bound))

                    if abs(relaxed_bound-cc.risk_bound) > 0.001:

                        cc_relaxation = ChanceConstraintRelaxation(cc)
                        cc_relaxation.relaxed_bound = relaxed_bound
                        cc_relaxations.append(cc_relaxation)
                    continue

                if not constraint.controllable and constraint.probabilistic:

                    # This is allocation
                    # Both lb and ub variables must have been included in the calculation

                    if bound == 0:
                        lb_variable = variables[(constraint, 0)]
                        ub_variable = variables[(constraint, 1)]
                        allocated_lb = x[lb_variable]
                        allocated_ub = x[ub_variable]

                        allocation = TemporalAllocation(constraint)
                        allocation.allocated_lb = allocated_lb
                        allocation.allocated_ub = allocated_ub
                        # allocation.pretty_print()
                        allocations.append(allocation)

                else:
                    # This is relaxation
                    if bound == 0:
                        # check if this constraint bound is relaxed
                        if abs(relaxed_bound - constraint.lower_bound) > 0.001:
                            # yes! create a new relaxation for it
                            relaxation = TemporalRelaxation(constraint)
                            relaxation.relaxed_lb = relaxed_bound
                            # relaxation.pretty_print()
                            relaxations.append(relaxation)

                    elif bound == 1:
                        # same for upper bound
                        if abs(relaxed_bound - constraint.upper_bound) > 0.001:
                            # yes! create a new relaxation for it
                            relaxation = TemporalRelaxation(constraint)
                            relaxation.relaxed_ub = relaxed_bound
                            # relaxation.pretty_print()
                            relaxations.append(relaxation)

            # print("")

            if len(relaxations) > 0 or len(allocations) > 0:
                return relaxations, allocations, cc_relaxations, 0

        return None, None, None, 0
Ejemplo n.º 4
0
    def generate_mincost_relaxations(candidate, negative_cycle,
                                     feasibility_type):

        all_cycles = candidate.continuously_resolved_cycles.copy()
        all_cycles.add(negative_cycle)

        # print("Solving against " + str(len(all_cycles)) + " cycles")

        # Solve using PuLP, TODO, incorporate interface to other solvers,
        # especially for nonlinear objective functions
        prob = LpProblem("MinCostConflictResolution", LpMinimize)

        # Solve using PyOpt/Snopt,
        # especially for nonlinear constraints/objective functions

        # construct variables and constraints
        lp_variables = {}
        lp_objective = []

        # status indicating the feasibility of the relaxation problem
        # 1 is feasible
        # 0 is infeasible
        # Note that this variable is shared by PuLP for its result
        status = 1
        # 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:
                                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:
                                variable = LpVariable(constraint.id + "-UB",
                                                      constraint.upper_bound,
                                                      None)
                                # print("New UB VAR: " + str(variable) + " [" + str(constraint.upper_bound) + "," + str(None) + "]")
                                # add the variable to the objective function
                                lp_variables[(constraint, bound)] = variable
                                lp_objective.append(
                                    (variable - constraint.upper_bound) *
                                    constraint.relax_cost_ub)
                            else:
                                variable = LpVariable(
                                    constraint.id + "-UB",
                                    constraint.lower_bound + 0.001,
                                    constraint.upper_bound)
                                # print("New UB-UC VAR: " + str(variable) + " [" + str(constraint.upper_bound) + "," + str(None) + "]")
                                lp_variables[(constraint, bound)] = variable
                                lp_objective.append(
                                    (constraint.upper_bound - variable) *
                                    constraint.relax_cost_ub)

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

                    assert variable is not None
                # print("Adding variable " + str(coefficient) + "*"+str(variable))
                lp_ncycle_constraint.append(variable * coefficient)

            # add the constraint to the problem
            # print(str(lp_ncycle_constraint))
            if sum(lp_ncycle_constraint) >= 0:
                # print(str(sum(lp_ncycle_constraint)) + " >= 0")
                # Over relax a bit to account for precision issues
                prob += sum(lp_ncycle_constraint) >= 0.0
            else:
                status = 0
                # this is not resolvable
                # no need to proceed

        if status > 0:
            # Set the objective function
            prob += sum(lp_objective)
            # for c in prob.constraints:
            #     print("CON: ", prob.constraints[c])
            # print("OBJ: ", prob.objective)

            # Solve the problem
            try:
                import gurobipy
                status = prob.solve(pulp.GUROBI(mip=False, msg=False))
            except ImportError:
                # pass # Gurobi doesn't exist, use default Pulp solver.
                status = prob.solve()

            # exit(0);

        # print("Computing relaxation")
        # if no solution was found, do nothing

        if status > 0:

            # A solution has been found
            # extract the result and store them into a set of relaxation
            # the outcome is a set of relaxations
            relaxations = []

            # print("Found relaxation")
            for constraint, bound in lp_variables.keys():
                variable = lp_variables[(constraint, bound)]
                relaxed_bound = value(variable)

                if bound == 0:
                    # check if this constraint bound is relaxed
                    if relaxed_bound != constraint.lower_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_lb = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)
                        assert relaxation.relaxed_lb <= constraint.upper_bound

                elif bound == 1:
                    # same for upper bound
                    if relaxed_bound != constraint.upper_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_ub = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)
                        assert relaxation.relaxed_ub >= constraint.lower_bound

            # print("")

            if len(relaxations) > 0:
                return relaxations, 0

        return None, 0
Ejemplo n.º 5
0
    def generate_cc_relaxations(candidate,
                                negative_cycle,
                                feasibility_type,
                                cc,
                                pInfinity=1e6,
                                nInfinity=-1e6):

        global prob_means
        global prob_stds
        global prob_vars
        global cc_var

        all_cycles = candidate.continuously_resolved_cycles.copy()
        all_cycles.add(negative_cycle)
        # print("CC Solving against " + str(len(all_cycles)) + " cycles")

        numVar = 0
        numConstraint = 0

        # Solve using Snopt,
        # especiallFy for nonlinear constraints/objective functions

        # construct variables and constraints
        variables = {}
        variable_bounds = {}
        initial_values = {}
        constraints = []
        objective = {}

        list_iA = []
        list_jA = []
        list_A = []
        neA_count = 0

        list_iG = []
        list_jG = []
        neG_count = 0

        prob_durations = set()
        prob_means = []
        prob_stds = []
        prob_vars = []
        cc_var = -1

        # status indicating the feasibility of the relaxation problem
        # 1 is feasible
        # 0 is infeasible
        # Note that this variable is shared by PuLP for its result
        status = 1

        # print("Cycles: " + str(len(all_cycles)))
        for cycle in all_cycles:
            lp_ncycle_constraint = {}
            rhs = 0

            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 variables:
                    variable = 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 or (
                                not constraint.controllable
                                and constraint.probabilistic):
                            # if constraint.relaxable_lb:
                            # print("LB cost " + str(constraint.relax_cost_lb) + "/" + constraint.name)

                            variable = numVar
                            variables[(constraint, bound)] = variable
                            initial_values[
                                variable] = constraint.get_lower_bound()
                            numVar += 1

                            if constraint.controllable or feasibility_type == FeasibilityType.CONSISTENCY:
                                # add the variable to the objective function

                                variable_bounds[variable] = [
                                    nInfinity, constraint.lower_bound
                                ]
                                objective[variable] = [
                                    -1 * constraint.relax_cost_lb,
                                    constraint.lower_bound *
                                    constraint.relax_cost_lb
                                ]

                            else:
                                variable_bounds[variable] = [
                                    constraint.lower_bound,
                                    constraint.upper_bound - 0.001
                                ]

                                # We collect all probabilistic durations
                                # for encoding the chance constraint
                                if constraint.probabilistic:
                                    prob_durations.add(constraint)
                                else:
                                    objective[variable] = [
                                        constraint.relax_cost_lb,
                                        -1 * constraint.lower_bound *
                                        constraint.relax_cost_lb
                                    ]

                                    # Add an additional constraint to make sure that
                                    # the lower bound is smaller than the upper bound
                                    # Only for non-probabilistic constraint
                                    if (constraint, 1) in variables:
                                        ub_variable = variables[(constraint,
                                                                 1)]

                                        constraint = {}
                                        constraint[ub_variable] = 1
                                        constraint[variable] = -1
                                        constraint['lb'] = 0.001
                                        constraint['ub'] = pInfinity

                                        constraints.append(constraint)

                                        list_iA.append(len(constraints))
                                        list_jA.append(ub_variable + 1)
                                        list_A.append(1)
                                        neA_count += 1

                                        list_iA.append(len(constraints))
                                        list_jA.append(variable + 1)
                                        list_A.append(-1)
                                        neA_count += 1

                            lp_ncycle_constraint[variable] = coefficient

                        else:
                            variable = constraint.lower_bound
                            rhs -= constraint.lower_bound * coefficient

                    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 or (
                                not constraint.controllable
                                and constraint.probabilistic):
                            # if constraint.relaxable_ub:
                            # print("UB cost " + str(constraint.relax_cost_ub) + "/" + constraint.name)

                            variable = numVar
                            variables[(constraint, bound)] = variable
                            initial_values[
                                variable] = constraint.get_upper_bound()
                            numVar += 1

                            if constraint.controllable or feasibility_type == FeasibilityType.CONSISTENCY:
                                variable_bounds[variable] = [
                                    constraint.upper_bound, pInfinity
                                ]
                                objective[variable] = [
                                    constraint.relax_cost_ub,
                                    -1 * constraint.upper_bound *
                                    constraint.relax_cost_ub
                                ]

                            else:
                                variable_bounds[variable] = [
                                    constraint.lower_bound + 0.001,
                                    constraint.upper_bound
                                ]

                                # We collection all probabilistic durations
                                # for encoding the chance constraint
                                if constraint.probabilistic:
                                    prob_durations.add(constraint)
                                else:
                                    objective[variable] = [
                                        -1 * constraint.relax_cost_ub,
                                        constraint.upper_bound *
                                        constraint.relax_cost_ub
                                    ]

                                    # Add an additional constraint to make sure that
                                    # the lower bound is smaller than the upper bound
                                    # Only for non-probabilistic constraint
                                    if (constraint, 0) in variables:
                                        lb_variable = variables[(constraint,
                                                                 0)]

                                        constraint = {}
                                        constraint[variable] = 1
                                        constraint[lb_variable] = -1
                                        constraint['lb'] = 0.001
                                        constraint['ub'] = pInfinity

                                        constraints.append(constraint)

                                        list_iA.append(len(constraints))
                                        list_jA.append(variable + 1)
                                        list_A.append(1)
                                        neA_count += 1

                                        list_iA.append(len(constraints))
                                        list_jA.append(lb_variable + 1)
                                        list_A.append(-1)
                                        neA_count += 1

                            lp_ncycle_constraint[variable] = coefficient
                        else:
                            variable = constraint.upper_bound
                            rhs -= constraint.upper_bound * coefficient
                    assert variable is not None

                else:
                    lp_ncycle_constraint[variable] = coefficient

                # print("Adding variable " + str(coefficient) + "*"+str(variable))

            # add the ncycle constraint to the problem
            # print(str(lp_ncycle_constraint))
            constraints.append(lp_ncycle_constraint)
            # print("C" + str(len(constraints)) + ": ", end="")
            empty_constraint = True
            for key in lp_ncycle_constraint:
                if lp_ncycle_constraint[key] != 0:
                    list_iA.append(len(constraints))
                    list_jA.append(key + 1)
                    list_A.append(lp_ncycle_constraint[key])
                    neA_count += 1
                    empty_constraint = False

                # constraint,bound = variables[key]
                # print(str(lp_ncycle_constraint[key]) + "*" + "(" +str(key)+ ") ", end="")

            lp_ncycle_constraint['lb'] = rhs + 0.0001
            lp_ncycle_constraint['ub'] = pInfinity

            if empty_constraint and rhs > 0:
                # This constraint cannot be met
                return None, 0

            # print(">= " + str(rhs))

        # Create the chance constraint
        if len(prob_durations) > 0:
            cc_constraint = {}
            constraints.append(cc_constraint)

            # Check if the chance constraint is relaxable
            if cc.relaxable_bound:
                cc_constraint['lb'] = -1
                cc_constraint['ub'] = 0

                # we need to encode an additional variable
                # to represent cc
                cc_var = numVar
                variables[("CC", 1)] = cc_var
                numVar += 1
                variable_bounds[cc_var] = [cc.risk_bound, pInfinity]

                list_iA.append(len(constraints))
                list_jA.append(cc_var + 1)
                list_A.append(-1)
                neA_count += 1

                # And add cc to the objective function
                objective[cc_var] = [
                    cc.relax_cost, -1 * cc.risk_bound * cc.relax_cost
                ]

            else:
                cc_constraint['lb'] = 0
                cc_constraint['ub'] = cc.risk_bound

            # print("C" + str(len(constraints)) + " (CC): ", end="")
            # print(str(cc_constraint['lb']) + "<= ", end="")

            for constraint in prob_durations:

                if (constraint, 0) in variables:
                    lb_var = variables[(constraint, 0)]
                else:
                    lb_var = numVar
                    variables[(constraint, 0)] = lb_var
                    numVar += 1

                if (constraint, 1) in variables:
                    ub_var = variables[(constraint, 1)]
                else:
                    ub_var = numVar
                    variables[(constraint, 1)] = ub_var
                    numVar += 1

                # override their domain since we are free to
                # allocate any values for them
                variable_bounds[lb_var] = [0, constraint.mean]
                variable_bounds[ub_var] = [constraint.mean, pInfinity]

                # initial_values[lb_var] = constraint.mean - 4*constraint.std
                # initial_values[ub_var] = constraint.mean + 4*constraint.std

                initial_values[lb_var] = constraint.get_lower_bound()
                initial_values[ub_var] = constraint.get_upper_bound()

                list_iG.append(len(constraints))
                list_jG.append(lb_var + 1)
                neG_count += 1
                list_iG.append(len(constraints))
                list_jG.append(ub_var + 1)
                neG_count += 1
                prob_vars.append(lb_var)
                prob_vars.append(ub_var)

                # print("Risk((" + str(lb_var) + ")--"+str(constraint.mean)+"--"+str(constraint.std)+"--("+str(ub_var)+")) ", end="")

                prob_means.append(constraint.mean)
                prob_stds.append(constraint.std)

            # print("<= " + str(cc_constraint['ub']))

        # Add the objective as the last constraint
        constraints.append(objective)

        for key in objective:
            list_iA.append(len(constraints))
            list_jA.append(key + 1)
            list_A.append(objective[key][0])

            if objective[key][0] != 0:
                neA_count += 1

        objective['lb'] = nInfinity
        objective['ub'] = pInfinity

        # Start Constructing the problem!!
        # Solve using SNOPT
        snopt.check_memory_compatibility()

        # minrw, miniw, mincw defines how much character, integer and real
        # storeage is neede to solve the problem.
        # ! assigned by SNOPT
        minrw = np.zeros((1), dtype=np.int32)
        miniw = np.zeros((1), dtype=np.int32)
        mincw = np.zeros((1), dtype=np.int32)

        # Workspace for character, integer and real arrays.
        # The plus 1 is for the objective function
        rw = np.zeros((2000 * (len(variables) + len(constraints)), ),
                      dtype=np.float64)
        iw = np.zeros((1000 * (len(variables) + len(constraints)), ),
                      dtype=np.int32)
        cw = np.zeros((8 * 500, ), dtype=np.character)

        # rw = np.zeros((10000,), dtype=np.float64)
        # iw = np.zeros((10000,), dtype=np.int32)
        # cw = np.zeros((8 * 500,), dtype=np.character)

        # The Start variable for SnoptA
        Cold = np.array([0], dtype=np.int32)
        Basis = np.array([1], dtype=np.int32)
        Warm = np.array([2], dtype=np.int32)

        # Variable definitions

        # Initial values
        x = np.zeros((len(variables), ), dtype=np.float64)

        # Lower and upper bounds
        xlow = np.zeros((len(variables), ), dtype=np.float64)
        xupp = np.zeros((len(variables), ), dtype=np.float64)

        for key in variable_bounds:
            if key in initial_values:
                x[key] = initial_values[key]
            bounds = variable_bounds[key]
            xlow[key] = bounds[0]
            xupp[key] = bounds[1]

        # Initial values for x
        xstate = np.zeros((len(variables), ), dtype=np.int32)

        # Vector of dual variables for the bound constraints
        # ! assigned by SNOPT
        xmul = np.zeros((len(variables), ), dtype=np.float64)

        # Initialize values for constraints
        F = np.zeros((len(constraints), ), dtype=np.float64)

        # Lower and upper bounds for constraints
        Flow = np.zeros((len(constraints), ), dtype=np.float64)
        Fupp = np.zeros((len(constraints), ), dtype=np.float64)

        for idx in range(0, len(constraints)):
            constraint = constraints[idx]
            Flow[idx] = constraint['lb']
            Fupp[idx] = constraint['ub']

        # Initial states
        Fstate = np.zeros((len(constraints), ), dtype=np.int32)
        # Estimate of the vector of Lagrange multipliers.
        # Since we know nothing about it at the moment. Set it to zero.
        Fmul = np.zeros((len(constraints), ), dtype=np.float64)

        # Constant added to the objective row for
        # printing purposes
        ObjAdd = np.zeros((1, ), dtype=np.float64)
        ObjAdd[0] = 0

        # The last row F is the objective function
        ObjRow = np.zeros((1, ), dtype=np.int32)
        ObjRow[0] = len(
            constraints)  # NOTE: We must add one to mesh with fortran */

        # Reports the result of the call to snOptA
        INFO = np.zeros((1, ), dtype=np.int32)

        # Set number of variables
        n = np.zeros((1, ), dtype=np.int32)
        n[0] = len(variables)

        # Set the number of functions (constraints and objectives)
        # in F
        neF = np.zeros((1, ), dtype=np.int32)
        neF[0] = len(constraints)

        # dimension of arrays iAfun, jAvar and A
        # They contain the nonzero elements of the linear part A

        lenA = np.zeros((1, ), dtype=np.int32)
        lenA[0] = len(list_iA)
        neA = np.zeros((1, ), dtype=np.int32)
        neA[0] = neA_count

        # iAfun = np.zeros((lenA[0],), dtype=np.int32)
        # jAvar = np.zeros((lenA[0],), dtype=np.int32)
        # A = np.zeros((lenA[0],), dtype=np.float64)

        if lenA[0] > 0:
            iAfun = np.array(list_iA, dtype=np.int32)
            jAvar = np.array(list_jA, dtype=np.int32)
            A = np.array(list_A, dtype=np.float64)
        else:
            lenA[0] = 1
            iAfun = np.zeros((lenA[0], ), dtype=np.int32)
            jAvar = np.zeros((lenA[0], ), dtype=np.int32)
            A = np.zeros((lenA[0], ), dtype=np.float64)

        # dimension of arrays iGfun and jGvar
        # They contain the nonzero elements of the nonlinear part of the derivativeG
        lenG = np.zeros((1, ), dtype=np.int32)
        lenG[0] = len(list_iG)
        neG = np.zeros((1, ), dtype=np.int32)
        neG[0] = neG_count

        if lenG[0] > 0:
            iGfun = np.array(list_iG, dtype=np.int32)
            jGvar = np.array(list_jG, dtype=np.int32)
        else:
            lenG[0] = 1
            iGfun = np.zeros((lenG[0], ), dtype=np.int32)
            jGvar = np.zeros((lenG[0], ), dtype=np.int32)

        # Generate the usrf function for SNOPT

        # names for variables and constraints
        # By default no names provided (both set to 1)
        nxname = np.zeros((1, ), dtype=np.int32)
        nFname = np.zeros((1, ), dtype=np.int32)
        nxname[0] = 1
        nFname[0] = 1

        # Names for variables and problem functions
        # not used when nxname and nFname are set to 1
        xnames = np.zeros((1 * 8, ), dtype=np.character)
        Fnames = np.zeros((1 * 8, ), dtype=np.character)
        Prob = np.zeros((200 * 8, ), dtype=np.character)

        # final number of superbasic variables
        # ! assigned by SNOPT
        nS = np.zeros((1, ), dtype=np.int32)

        # Number and sum of the infeasibilities of constraints
        nInf = np.zeros((1, ), dtype=np.int32)
        sInf = np.zeros((1, ), dtype=np.float64)

        # Define Print and Summary files
        # Must be called before any other SNOPT routing

        # Unit number for summary file
        iSumm = np.zeros((1, ), dtype=np.int32)
        iSumm[0] = 0

        # Unit number for the print file
        iPrint = np.zeros((1, ), dtype=np.int32)
        iPrint[0] = 0

        # Unit number for the specs file
        iSpecs = np.zeros((1, ), dtype=np.int32)
        iSpecs[0] = 4

        # name for output print and spec files
        printname = np.zeros((200 * 8, ), dtype=np.character)
        specname = np.zeros((200 * 8, ), dtype=np.character)

        # open output files using snfilewrappers.[ch] */
        specn = "sntoya.spc"
        printn = "sntoya.out"
        specname[:len(specn)] = list(specn)
        printname[:len(printn)] = list(printn)

        # Open the print file, fortran style */
        snopt.snopenappend(iPrint, printname, INFO)

        # ================================================================== */
        # First,  sninit_ MUST be called to initialize optional parameters   */
        # to their default values.                                           */
        # ================================================================== */

        snopt.sninit(iPrint, iSumm, cw, iw, rw)

        # Set configurations
        strOpt = np.zeros((200 * 8, ), dtype=np.character)
        DerOpt = np.zeros((1, ), dtype=np.int32)

        # set derivative options
        strOpt_s = "Derivative option"
        DerOpt[0] = 1
        strOpt[:len(strOpt_s)] = list(strOpt_s)
        snopt.snseti(strOpt, DerOpt, iPrint, iSumm, INFO, cw, iw, rw)

        # set iteration limit
        Major = np.array([250], dtype=np.int32)
        strOpt_s = "Major Iteration limit"
        strOpt[:len(strOpt_s)] = list(strOpt_s)

        snopt.snseti(strOpt, Major, iPrint, iSumm, INFO, cw, iw, rw)

        # SnoptA will compute the Jacobian by finite-differences.   */
        # The user has the option of calling  snJac  to define the  */
        # coordinate arrays (iAfun,jAvar,A) and (iGfun, jGvar).     */

        #     ------------------------------------------------------------------ */
        #     Go for it, using a Cold start.                                     */
        #     ------------------------------------------------------------------ */

        # print("Computing relaxation")

        snopt.snopta(Cold, neF, n, nxname, nFname, ObjAdd, ObjRow, Prob, usrf,
                     iAfun, jAvar, lenA, neA, A, iGfun, jGvar, lenG, neG, xlow,
                     xupp, xnames, Flow, Fupp, Fnames, x, xstate, xmul, F,
                     Fstate, Fmul, INFO, mincw, miniw, minrw, nS, nInf, sInf,
                     cw, iw, rw, cw, iw, rw)

        snopt.snclose(iPrint)
        snopt.snclose(iSpecs)

        # print("Done computing relaxation")

        # print("Solution " + str(x))

        if INFO[0] == 1:

            # An optimal solution has been found
            # extract the result and store them into a set of relaxation
            # the outcome is a set of relaxations
            relaxations = []
            allocations = []
            cc_relaxations = []

            # print("Found relaxation: INFO=" + str(INFO[0]))

            for constraint, bound in variables.keys():
                variable = variables[(constraint, bound)]
                relaxed_bound = x[variable]
                # print(str(variable) + "==" + str(x[variable]))

                if constraint == "CC":
                    # print("Relaxing CC from " + str(cc.risk_bound) + " to " + str(relaxed_bound))

                    if abs(relaxed_bound - cc.risk_bound) > 0.001:

                        cc_relaxation = ChanceConstraintRelaxation(cc)
                        cc_relaxation.relaxed_bound = relaxed_bound
                        cc_relaxations.append(cc_relaxation)
                    continue

                if not constraint.controllable and constraint.probabilistic:

                    # This is allocation
                    # Both lb and ub variables must have been included in the calculation

                    if bound == 0:
                        lb_variable = variables[(constraint, 0)]
                        ub_variable = variables[(constraint, 1)]
                        allocated_lb = x[lb_variable]
                        allocated_ub = x[ub_variable]

                        allocation = TemporalAllocation(constraint)
                        allocation.allocated_lb = allocated_lb
                        allocation.allocated_ub = allocated_ub
                        # allocation.pretty_print()
                        allocations.append(allocation)

                else:
                    # This is relaxation
                    if bound == 0:
                        # check if this constraint bound is relaxed
                        if abs(relaxed_bound - constraint.lower_bound) > 0.001:
                            # yes! create a new relaxation for it
                            relaxation = TemporalRelaxation(constraint)
                            relaxation.relaxed_lb = relaxed_bound
                            # relaxation.pretty_print()
                            relaxations.append(relaxation)

                    elif bound == 1:
                        # same for upper bound
                        if abs(relaxed_bound - constraint.upper_bound) > 0.001:
                            # yes! create a new relaxation for it
                            relaxation = TemporalRelaxation(constraint)
                            relaxation.relaxed_ub = relaxed_bound
                            # relaxation.pretty_print()
                            relaxations.append(relaxation)

            # print("")

            if len(relaxations) > 0 or len(allocations) > 0:
                return relaxations, allocations, cc_relaxations, 0

        return None, None, None, 0
Ejemplo n.º 6
0
    def generate_mincost_relaxations(candidate,negative_cycle,feasibility_type):

        all_cycles = candidate.continuously_resolved_cycles.copy()
        all_cycles.add(negative_cycle)

        # print("Solving against " + str(len(all_cycles)) + " cycles")

        # Solve using PuLP, TODO, incorporate interface to other solvers,
        # especially for nonlinear objective functions
        prob = LpProblem("MinCostConflictResolution", LpMinimize)

        # Solve using PyOpt/Snopt,
        # especially for nonlinear constraints/objective functions

        # construct variables and constraints
        lp_variables = {}
        lp_objective = []

        # status indicating the feasibility of the relaxation problem
        # 1 is feasible
        # 0 is infeasible
        # Note that this variable is shared by PuLP for its result
        status = 1;
        # 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:
                                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:
                                variable = LpVariable(constraint.id + "-UB",constraint.upper_bound, None)
                                # print("New UB VAR: " + str(variable) + " [" + str(constraint.upper_bound) + "," + str(None) + "]")
                                # add the variable to the objective function
                                lp_variables[(constraint,bound)] = variable
                                lp_objective.append((variable - constraint.upper_bound) * constraint.relax_cost_ub)
                            else:
                                variable = LpVariable(constraint.id + "-UB",constraint.lower_bound+0.001, constraint.upper_bound)
                                # print("New UB-UC VAR: " + str(variable) + " [" + str(constraint.upper_bound) + "," + str(None) + "]")
                                lp_variables[(constraint,bound)] = variable
                                lp_objective.append((constraint.upper_bound - variable) * constraint.relax_cost_ub)

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


                    assert variable is not None
                # print("Adding variable " + str(coefficient) + "*"+str(variable))
                lp_ncycle_constraint.append(variable*coefficient)

            # add the constraint to the problem
            # print(str(lp_ncycle_constraint))
            if sum(lp_ncycle_constraint) >= 0:
                # print(str(sum(lp_ncycle_constraint)) + " >= 0")
                # Over relax a bit to account for precision issues
                prob += sum(lp_ncycle_constraint) >= 0.0
            else:
                status = 0;
                # this is not resolvable
                # no need to proceed

        if status > 0:
            # Set the objective function
            prob += sum(lp_objective)
            # for c in prob.constraints:
            #     print("CON: ", prob.constraints[c])
            # print("OBJ: ", prob.objective)

            # Solve the problem
            try:
                import gurobipy
                status = prob.solve(solvers.GUROBI(mip=False,msg=False))
            except ImportError:
                # pass # Gurobi doesn't exist, use default Pulp solver.
                status = prob.solve()

            # exit(0);

        # print("Computing relaxation")
        # if no solution was found, do nothing

        if status > 0:

            # A solution has been found
            # extract the result and store them into a set of relaxation
            # the outcome is a set of relaxations
            relaxations = []

            # print("Found relaxation")
            for constraint, bound in lp_variables.keys():
                variable = lp_variables[(constraint, bound)]
                relaxed_bound = value(variable)

                if bound == 0:
                    # check if this constraint bound is relaxed
                    if relaxed_bound != constraint.lower_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_lb = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)
                        assert relaxation.relaxed_lb <= constraint.upper_bound


                elif bound == 1:
                    # same for upper bound
                    if relaxed_bound != constraint.upper_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_ub = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)
                        assert relaxation.relaxed_ub >= constraint.lower_bound

            # print("")

            if len(relaxations) > 0:
                return relaxations,0

        return None,0
Ejemplo n.º 7
0
    def generate_maxflex_relaxations(candidate, negative_cycle):

        if len(negative_cycle.constraints) == 0:
            return None, 0

        all_cycles = candidate.continuously_resolved_cycles.copy()
        all_cycles.add(negative_cycle)

        # Solve using PuLP, TODO, incorporate interface to other solvers,
        # especially for nonlinear objective functions
        prob = LpProblem("MaxFlexConflictResolution", LpMaximize)

        # Solve using PyOpt/Snopt,
        # especially for nonlinear constraints/objective functions

        # construct variables and constraints
        lp_variables = {}
        lp_objective = []

        max_flex_variable = LpVariable("Max Flex", 0, None)
        lp_objective.append(max_flex_variable)

        # status indicating the feasibility of the relaxation problem
        # 1 is feasible
        # 0 is infeasible
        # Note that this variable is shared by PuLP for its result
        status = 1

        # We only consider the relaxation of the upper bound of
        # uncontrollable duration.
        # which means that we basically ignore the definition of
        # 'relaxable bounds' in the network, and only consider the upper bounds
        # of uncertain durations.

        for cycle in all_cycles:

            lp_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:
                        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 not constraint.controllable:
                            variable = LpVariable(constraint.id + "-UB",
                                                  constraint.lower_bound,
                                                  constraint.upper_bound)
                            lp_variables[(constraint, bound)] = variable
                            # add the variable to the objective function

                            max_flex_constraint = []
                            max_flex_constraint.append(
                                (variable - constraint.lower_bound))
                            max_flex_constraint.append(-1.0 *
                                                       max_flex_variable)
                            prob += sum(max_flex_constraint) >= 0
                        else:
                            variable = constraint.upper_bound

                    assert variable is not None

                lp_constraint.append(variable * coefficient)

            # add the constraint to the problem
            # print(str(lp_constraint))
            if sum(lp_constraint) >= 0:
                # print(str(sum(lp_constraint)) + " >= 0")
                prob += sum(lp_constraint) >= 0
            else:
                status = 0
                # this is not resolvable
                # no need to proceed

        if status > 0:
            # Set the objective function
            prob += sum(lp_objective)
            # for c in prob.constraints:
            #     print("CON: ", prob.constraints[c])
            # print("OBJ: ", prob.objective)

            # Solve the problem
            try:
                import gurobipy
                status = prob.solve(pulp.GUROBI(mip=False, msg=False))
            except ImportError:
                pass  # Gurobi doesn't exist, use default Pulp solver.
                status = prob.solve()

            # exit(0);

        # if no solution was found, do nothing

        if status > 0:
            # A solution has been bound
            # extract the result and store them into a set of relaxation
            # the outcome is a set of relaxations
            relaxations = []
            max_flex_value = value(max_flex_variable)

            for constraint, bound in lp_variables.keys():
                variable = lp_variables[(constraint, bound)]
                relaxed_bound = value(variable)

                if bound == 0:
                    # check if this constraint bound is relaxed
                    if relaxed_bound != constraint.lower_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_lb = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)

                elif bound == 1:
                    # same for upper bound
                    if relaxed_bound != constraint.upper_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_ub = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)

            if len(relaxations) > 0:
                return relaxations, max_flex_value

        return None, 0