Ejemplo n.º 1
0
class LinearProgram:
    def __init__(self, hbw_task=None):

        if hbw_task is None:
            return

        self.model = Model(hbw_task.instance_name + '.lp')

        # LP variables
        self.variables = []  # was all_variables
        self.make_model_vars(hbw_task)
        self.model.update()

        # LP Constraints
        self.constraints = []
        self.make_model_constraints(hbw_task)
        self.model.update()

        self.goal_constraints = set()
        #self.model.write( 'tmp.lp' )

    def copy(self):
        from copy import deepcopy

        new_lp = LinearProgram()
        new_lp.model = self.model.copy()
        new_lp.constraints = []
        new_lp.goal_constraints = set()
        for index, ext_constraint in enumerate(self.constraints):
            new_lp.constraints.append((deepcopy(ext_constraint[0]),
                                       new_lp.model.getConstrs()[index]))
        return new_lp

    def make_model_vars(self, hbw_task):
        # each cylinder contains a piston of negl. weight and cross
        # section area equal to the cylinder's. In general, there will
        # be a fluid column below it

        self.fluid_column_heights = [
        ]  # the k-th element of this list corresponds with d_k
        for x in xrange(hbw_task.objects.num_cylinders()):
            varname = 'd_{0}'.format(x)
            fch_i = self.model.addVar(vtype=GRB.CONTINUOUS,
                                      name=varname,
                                      lb=0.0,
                                      ub=hbw_task.objects.cylinders[x].height)
            self.fluid_column_heights.append(fch_i)

        self.variables += self.fluid_column_heights

        # modeling the partial wts of blocks on the piston as a list of
        # LP variables -- pw_i = partial wt of blocks in the range [0,i-1] that are in the cylinder
        # base case -- pw_0 = 0
        self.partial_wts = {}  # this contains vars w_i,k

        for i in xrange(hbw_task.objects.num_blocks()):
            for j in xrange(hbw_task.objects.num_cylinders()):
                varname = 'w_{0},{1}'.format(i, j)
                pw_ij = self.model.addVar(vtype=GRB.CONTINUOUS,
                                          name=varname,
                                          lb=0.0,
                                          ub=hbw_task.objects.blocks[i].weight)
                self.partial_wts[(i, j)] = pw_ij
                self.variables.append(pw_ij)
        # wt of columns (fluid + blocks) in each cylinder

        self.column_wts = []
        for x in xrange(hbw_task.objects.num_cylinders()):
            varname = 'f_{0}'.format(x)
            cw_x = self.model.addVar(vtype=GRB.CONTINUOUS, name=varname)
            self.column_wts.append(cw_x)
        self.variables += self.column_wts

    def get_all_variables(self):
        return self.variables

    def get_all_constraints(self):
        return self.constraints

    def make_model_constraints(self, hbw_task):
        self.constraints = self.make_partial_wt_constraints(hbw_task)
        self.constraints += self.make_column_wt_constraints(hbw_task)
        self.constraints += self.make_pressure_balancing_constraints(hbw_task)
        self.constraints += self.make_fluid_balancing_constraint(hbw_task)

    def make_partial_wt_constraints(self, hbw_task):
        wt_constraints = []
        for cylId in xrange(hbw_task.objects.num_cylinders()):
            wt_constraints += self.make_wt_constraints_for_cylinder(
                cylId, hbw_task)
        return wt_constraints

    def make_wt_constraints_for_cylinder(self, cylId,
                                         hbw_task):  #hbw_obj, vars):
        from hbw3.planning import in_cylinder
        wt_constraints = []
        cylinder = hbw_task.objects.cylinders[cylId]

        for i in xrange(0, hbw_task.objects.num_blocks()):
            var = hbw_task.block_container[i]
            var_valuation = [
                (var.index,
                 hbw_task.block_container_values[in_cylinder(cylId)])
            ]

            constraint = (var_valuation,
                          self.model.addConstr(
                              self.partial_wts[(i, cylId)] -
                              hbw_task.objects.blocks[i].weight == 0))
            wt_constraints.append(constraint)

            for name, v in hbw_task.block_container_values.iteritems():
                if name == in_cylinder(cylId): continue
                var_valuation = [(var.index, v)]

                constraint = (var_valuation,
                              self.model.addConstr(
                                  self.partial_wts[(i, cylId)] == 0))
                wt_constraints.append(constraint)

        return wt_constraints

    # this function adds equality constraints to calculate the total downward force
    # at the bottom of the cylinder (column_wt = total weight of all blocks + wt of fluid column)
    def make_column_wt_constraints_for_cylinder(self, cylId, hbw_task):
        density = hbw_task.objects.get_fluid_density()
        cross_section_area_of_cyl = hbw_task.objects.cylinders[cylId].area

        constr = (
            [],  # unconditional
            self.model.addConstr(
                self.column_wts[cylId] - density * cross_section_area_of_cyl *
                self.fluid_column_heights[cylId] -
                quicksum(self.partial_wts[(i, cylId)]
                         for i in xrange(hbw_task.objects.num_blocks())) == 0))
        return constr

    def make_column_wt_constraints(self, hbw_task):
        return [
            self.make_column_wt_constraints_for_cylinder(cylId, hbw_task)
            for cylId in xrange(hbw_task.objects.num_cylinders())
        ]

    def make_pressure_balancing_constraints(self, hbw_task):
        pb_constraints = []
        # we have 'numCylinders -1' constraints - one for each consecutive pair
        for cylId in xrange(hbw_task.objects.num_cylinders() - 1):
            # constr for cylId & cylId + 1
            reciprocal_area_1 = 1.0 / hbw_task.objects.cylinders[cylId].area
            reciprocal_area_2 = 1.0 / hbw_task.objects.cylinders[cylId +
                                                                 1].area

            lpconstr = (
                [],  # unconditional
                self.model.addConstr(
                    reciprocal_area_1 * self.column_wts[cylId] -
                    reciprocal_area_2 * self.column_wts[cylId + 1] == 0))
            pb_constraints.append(lpconstr)

        return pb_constraints

    def make_fluid_balancing_constraint(self, hbw_task):
        constr = (
            [],  # unconditional
            self.model.addConstr(
                quicksum(hbw_task.objects.cylinders[cylId].area *
                         self.fluid_column_heights[cylId]
                         for cylId in xrange(hbw_task.objects.num_cylinders()))
                == hbw_task.objects.fluid.total_fluid_in_cylinders))
        return [constr]

    def print_constraints(self):
        for phi, gamma in self.constraints:
            if len(phi) == 0:
                print(' True -> %s' % gamma)
            else:
                head = ' & '.join(['%s = %s' % (x, v) for x, v in phi])
                print(' %s -> %s' % (head, gamma))
Ejemplo n.º 2
0
class LinearProgram:
    def __init__(self, psr_task=None):
        if psr_task is None:
            return
        self.model = Model(psr_task.instance_name + '.lp')

        # LP variables
        self.variables = []  # was all_variables
        self.make_model_vars(psr_task)
        self.model.update()

        # LP Constraints
        self.constraints = []
        self.make_model_constraints(psr_task)
        self.model.update()

        self.goal_constraints = set()

    def copy(self):
        from copy import deepcopy

        new_lp = LinearProgram()
        new_lp.variables = deepcopy(self.variables)
        new_lp.goal_constraints = deepcopy(self.goal_constraints)
        new_lp.model = self.model.copy()
        new_lp.constraints = []
        for index, ext_constraint in enumerate(self.constraints):
            new_lp.constraints.append((deepcopy(ext_constraint[0]),
                                       new_lp.model.getConstrs()[index]))
        return new_lp

    def __make_power_vars(self, task):
        for cb in task.network.TECircuitbreakerLines:
            # it is always zero
            # NOTE: if it always zero, this should simplify some constraints - and this variable should
            # not be in the model
            cb.power = self.model.addVar(name='p_{0}'.format(cb.name),
                                         lb=0.0,
                                         ub=0.0,
                                         vtype=GRB.CONTINUOUS)

        for r_line in task.network.TERDeviceLines:
            r_line.power = self.model.addVar(name='p_{0}'.format(r_line.name),
                                             lb=-r_line.capacity,
                                             ub=r_line.capacity,
                                             vtype=GRB.CONTINUOUS)

        for m_line in task.network.TEMDeviceLines:
            m_line.power = self.model.addVar(name='p_{0}'.format(m_line.name),
                                             lb=-m_line.capacity,
                                             ub=m_line.capacity,
                                             vtype=GRB.CONTINUOUS)

        for bus in task.network.TEBuses:
            lb_fed = 1.0 if ((bus.generation_max > 0)
                             and not bus.fault) else 0.0
            bus.fed = self.model.addVar(name='b_{0}_fed'.format(bus.name),
                                        lb=lb_fed,
                                        ub=1.0,
                                        vtype=GRB.CONTINUOUS)
            bus.generation = self.model.addVar(name='b_{0}_gen'.format(
                bus.name),
                                               lb=0.0,
                                               ub=bus.generation_max,
                                               vtype=GRB.CONTINUOUS)
            # theta is an angle, so it should be bounded by a full circle
            # assuming unit is degrees, that is, between -180 and +180
            bus.theta = self.model.addVar(name='b_{0}_theta'.format(bus.name),
                                          lb=-180.0,
                                          ub=180.0,
                                          vtype=GRB.CONTINUOUS)
#self.model.setObjective(quicksum([bus.generation for bus in task.network.TEBuses]), GRB.MAXIMIZE)

    def make_model_vars(self, task):
        self.__make_power_vars(task)

    def __make_kirchoff_constraints(self, task):

        for bus in task.network.TEBuses:
            c = self.model.addConstr(
                bus.generation +
                quicksum([l.power for l in bus.connections_in]), GRB.EQUAL,
                bus.load_max * bus.fed +
                quicksum([l.power for l in bus.connections_out]))
            #c = self.model.addConstr( 	bus.generation + quicksum( [ l.power for l in bus.connections_in ] )
            #				- bus.load_max * bus.fed + quicksum( [ -l.power for l in bus.connections_out ] )
            #				== 0.0 )
            self.constraints.append(([], c))

    # Corresponds with TEcreate_default_goal
    def make_bus_feeding_constraints(self, task):
        bus_feeding_constraints = []
        for bus in task.network.TEBuses:
            if bus.fault:
                c = self.model.addConstr(bus.fed, GRB.EQUAL, 0.0)
                self.constraints.append(([], c))
                bus_feeding_constraints.append(len(self.constraints) - 1)
            else:
                if bus.generation_max > 0.0:  # is a generator
                    c = self.model.addConstr(bus.fed, GRB.EQUAL, 1.0)
                    self.constraints.append(([], c))
                    bus_feeding_constraints.append(len(self.constraints) - 1)
        self.model.update()
        print('Constraints in goal: {0}'.format(len(bus_feeding_constraints)))
        self.goal_constraints = set(bus_feeding_constraints)
        return self.goal_constraints

    # Corresponds with TEpowerlines_create_goal
    def make_bus_feeding_constraints_2(self, task):
        bus_feeding_constraints = []
        for bus in task.network.TEBuses:
            if bus.fault:
                c = self.model.addConstr(bus.fed, GRB.EQUAL, 0.0)
                self.constraints.append(([], c))
                #bus_feeding_constraints.append( len(self.constraints)-1 )
                continue
            if not bus.feed: continue
            c = self.model.addConstr(bus.fed, GRB.EQUAL, 1.0)
            self.constraints.append(([], c))
            bus_feeding_constraints.append(len(self.constraints) - 1)
        self.model.update()
        print('Constraints in goal: {0}'.format(len(bus_feeding_constraints)))
        #print( 'Constraints in self {0}, constraints in Gurobi obj {1}'.format( len(self.constraints), len(self.model.getConstrs()) ) )
        self.goal_constraints = set(bus_feeding_constraints)
        return self.goal_constraints

    def __make_line_constraints(self, task):

        for line in task.network.TERDeviceLines + task.network.TEMDeviceLines:
            c_dc_flow_model_closed = self.model.addConstr(
                line.power, GRB.EQUAL, -line.susceptance *
                (line.connections[0].theta - line.connections[1].theta))
            self.constraints.append(
                ([(line.closed.index, True)], c_dc_flow_model_closed))
            c_dc_flow_model_open = self.model.addConstr(
                line.power, GRB.EQUAL, 0.0)
            self.constraints.append(
                ([(line.closed.index, False)], c_dc_flow_model_open))
            c_bus_feeding_state = self.model.addConstr(line.connections[0].fed,
                                                       GRB.EQUAL,
                                                       line.connections[1].fed)
            #c_bus_feeding_state = self.model.addConstr( line.connections[0].fed - line.connections[1].fed == 0.0 )
            self.constraints.append(
                ([(line.closed.index, True)], c_bus_feeding_state))

    def __make_circuit_breaker_constraints(self, task):

        for breaker in task.network.TECircuitbreakerLines:
            c_if_closed_always_fed = self.model.addConstr(
                breaker.connections[0].fed, GRB.EQUAL, 1.0)
            self.constraints.append(
                ([(breaker.closed.index, True)], c_if_closed_always_fed))
            c_if_open_not_fed = self.model.addConstr(
                breaker.connections[0].fed, GRB.EQUAL, 0.0)
            self.constraints.append(
                ([(breaker.closed.index, False)], c_if_open_not_fed))
            # March 2015: This follows from Sylvie's IJCAI-13 paper on PSR
            # see constraints on circuit breakers
            if_open_kill_gen_in_connected_bus = self.model.addConstr(
                breaker.connections[0].generation, GRB.EQUAL, 0.0)
            self.constraints.append(([(breaker.closed.index, False)],
                                     if_open_kill_gen_in_connected_bus))

    def make_model_constraints(self, task):
        self.__make_kirchoff_constraints(task)
        self.__make_line_constraints(task)
        self.__make_circuit_breaker_constraints(task)
        #self.make_bus_feeding_constraints( task )

    def print_constraints(self):
        for phi, gamma in self.constraints:
            if len(phi) == 0:
                print(' True -> %s' % gamma)
            else:
                head = ' & '.join(['%s = %s' % (x, v) for x, v in phi])
                print(' %s -> %s' % (head, gamma))
Ejemplo n.º 3
0
def populate_dual_subproblem(data, upper_cost=None, flow_cost=None):
    """
    Function that populates the Benders Dual Subproblem, as suggested by the
    paper "Minimal Infeasible Subsystems and Bender's cuts" by Fischetti,
    Salvagnin and Zanette.
    :param data:        Problem data structure
    :param upper_cost:  Link setup decisions fixed in the master
    :param flow_cost:   This is the cost of the continuous variables of the
                        master problem, as explained in the paper
    :return:            Numpy array of Gurobi model objects
    """

    # Gurobi model objects
    subproblems = np.empty(shape=(data.periods, data.commodities),
                           dtype=object)

    # Construct model for period/commodity 0.
    # Then, copy this and change the coefficients
    dual_subproblem = Model('dual_subproblem_(0,0)')

    # Ranges we are going to need
    arcs, periods, commodities = xrange(data.arcs.size), xrange(
        data.periods), xrange(data.commodities)

    # Origins and destinations of commodities
    origins, destinations = data.origins, data.destinations

    # We use arrays to store variable indexes and variable objects. Why use
    # both? Gurobi wont let us get the values of individual variables
    # within a callback.. We just get the values of a large array of
    # variables, in the order they were initially defined. To separate them
    # in variable categories, we will have to use index arrays
    flow_index = np.zeros(shape=data.nodes, dtype=int)
    flow_duals = np.empty_like(flow_index, dtype=object)
    ubounds_index = np.zeros(shape=len(arcs), dtype=int)
    ubounds_duals = np.empty_like(ubounds_index, dtype=object)

    # Makes sure we don't add variables more than once
    flow_duals_names = set()

    if upper_cost is None:
        upper_cost = np.zeros(shape=(len(periods), len(arcs)), dtype=float)
    if flow_cost is None:
        flow_cost = np.zeros(shape=(len(periods), len(commodities)),
                             dtype=float)

    # Populate all variables in one loop, keep track of their indexes
    # Data for period = 0, com = 0
    count = 0
    for arc in arcs:
        ubounds_duals[arc] = dual_subproblem.addVar(
            obj=-upper_cost[0, arc], lb=0., name='ubound_dual_a{}'.format(arc))
        ubounds_index[arc] = count
        count += 1
        start_node, end_node = get_2d_index(data.arcs[arc], data.nodes)
        start_node, end_node = start_node - 1, end_node - 1
        for node in (start_node, end_node):
            var_name = 'flow_dual_n{}'.format(node)
            if var_name not in flow_duals_names:
                flow_duals_names.add(var_name)
                obj, ub = 0., GRB.INFINITY
                if data.origins[0] == node:
                    obj = 1.
                if data.destinations[0] == node:
                    obj = -1.
                    ub = 0.
                flow_duals[node] = \
                    dual_subproblem.addVar(
                        obj=obj, lb=0., name=var_name)
                flow_index[node] = count
                count += 1
    opt_var = dual_subproblem.addVar(obj=-flow_cost[0, 0],
                                     lb=0.,
                                     name='optimality_var')
    dual_subproblem.params.threads = 2
    dual_subproblem.params.LogFile = ""
    dual_subproblem.update()

    # Add constraints
    demand = data.demand[0, 0]
    for arc in arcs:
        start_node, end_node = get_2d_index(data.arcs[arc], data.nodes)
        start_node, end_node = start_node - 1, end_node - 1
        lhs = flow_duals[start_node] - flow_duals[end_node] \
              - ubounds_duals[arc] - \
              opt_var * data.variable_cost[arc] * demand
        dual_subproblem.addConstr(lhs <= 0., name='flow_a{}'.format(arc))

    # Original Fischetti model
    lhs = quicksum(ubounds_duals) + opt_var
    dual_subproblem.addConstr(lhs == 1, name='normalization_constraint')

    # Store variable indices
    dual_subproblem._ubounds_index = ubounds_index
    dual_subproblem._flow_index = flow_index
    dual_subproblem._all_variables = np.array(dual_subproblem.getVars())
    dual_subproblem._flow_duals = np.take(dual_subproblem._all_variables,
                                          flow_index)
    dual_subproblem._ubound_duals = np.take(dual_subproblem._all_variables,
                                            ubounds_index)

    dual_subproblem.setParam('OutputFlag', 0)
    dual_subproblem.modelSense = GRB.MAXIMIZE
    dual_subproblem.update()

    subproblems[0, 0] = dual_subproblem

    for period, com in product(periods, commodities):
        if (period, com) != (0, 0):
            model = dual_subproblem.copy()
            optimality_var = model.getVarByName('optimality_var')
            optimality_var.Obj = -flow_cost[period, com]
            demand = data.demand[period, com]
            for node in xrange(data.nodes):
                variable = model.getVarByName('flow_dual_n{}'.format(node))
                if origins[com] == node:
                    obj = 1.
                elif destinations[com] == node:
                    obj = -1.
                else:
                    obj = 0.
                variable.obj = obj
            for arc in arcs:
                variable = model.getVarByName('ubound_dual_a{}'.format(arc))
                variable.Obj = -np.sum(upper_cost[:period + 1, arc])
                constraint = model.getConstrByName('flow_a{}'.format(arc))
                model.chgCoeff(constraint, optimality_var,
                               -demand * data.variable_cost[arc])
            model._all_variables = np.array(model.getVars())
            model.update()
            subproblems[period, com] = model
    return subproblems
Ejemplo n.º 4
0
class LinearProgram:
    def __init__(self, hbw_task=None):

        if hbw_task is None:
            return

        self.model = Model(hbw_task.instance_name + '.lp')

        # LP variables
        self.variables = []  # was all_variables
        self.make_model_vars(hbw_task)
        self.model.update()

        # LP Constraints
        self.constraints = []
        self.make_model_constraints(hbw_task)
        self.model.update()

        self.goal_constraints = set()

    def copy(self):
        from copy import deepcopy
        new_lp = LinearProgram()
        new_lp.model = self.model.copy()
        new_lp.constraints = []
        new_lp.goal_constraints = set()
        for index, ext_constraint in enumerate(self.constraints):
            new_lp.constraints.append((deepcopy(ext_constraint[0]),
                                       new_lp.model.getConstrs()[index]))
        return new_lp

    def make_model_vars(self, hbw_task):
        # each cylinder contains a piston of negl. weight and cross
        # section area equal to the cylinder's. In general, there will
        # be a fluid column below it

        self.fluid_column_heights = []
        for x in xrange(hbw_task.objects.num_cylinders()):
            varname = 'fluid_col_ht_cyl_%d' % x
            fch_i = self.model.addVar(vtype=GRB.CONTINUOUS,
                                      name=varname,
                                      lb=0.0,
                                      ub=hbw_task.objects.cylinders[x].height)
            self.fluid_column_heights.append(fch_i)

        self.variables += self.fluid_column_heights

        # modeling the partial wts of blocks on the piston as a list of
        # LP variables -- pw_i = partial wt of blocks in the range [0,i-1] that are in the cylinder
        # base case -- pw_0 = 0
        self.partial_wts = {}

        for i in xrange(hbw_task.objects.num_blocks() + 1):
            for j in xrange(hbw_task.objects.num_cylinders()):
                varname = 'pw_%d_cyl_%d' % (i, j)
                pw_ij = self.model.addVar(vtype=GRB.CONTINUOUS, name=varname)
                self.partial_wts[(i, j)] = pw_ij
                self.variables.append(pw_ij)
        # wt of columns (fluid + blocks) in each cylinder

        self.column_wts = []
        for x in xrange(hbw_task.objects.num_cylinders()):
            varname = 'col_wt_cyl_%d' % x
            cw_x = self.model.addVar(vtype=GRB.CONTINUOUS, name=varname)
            self.column_wts.append(cw_x)
        self.variables += self.column_wts

    def get_all_variables(self):
        return self.variables

    def get_all_constraints(self):
        return self.constraints

    def make_model_constraints(self, hbw_task):
        self.constraints = self.make_partial_wt_constraints(hbw_task)
        self.constraints += self.make_column_wt_constraints(hbw_task)
        self.constraints += self.make_pressure_balancing_constraints(hbw_task)
        self.constraints += self.make_fluid_balancing_constraint(hbw_task)

    def make_partial_wt_constraints(self, hbw_task):
        wt_constraints = []
        for cylId in xrange(hbw_task.objects.num_cylinders()):
            wt_constraints += self.make_wt_constraints_for_cylinder(
                cylId, hbw_task)
        return wt_constraints

    def make_wt_constraints_for_cylinder(self, cylId,
                                         hbw_task):  #hbw_obj, vars):
        wt_constraints = []
        cylinder = hbw_task.objects.cylinders[cylId]

        # base case constraint
        base_constraint = ([],
                           self.model.addConstr(
                               self.partial_wts[(0, cylId)] == 0))
        wt_constraints.append(base_constraint)

        for blockId in xrange(hbw_task.objects.num_blocks()):
            # for the inductive case, two switched constraints
            var = hbw_task.block_in_cylinder[(blockId, cylId)]
            var_valuation = [(var.index, False)]
            # for the below, note that blocks are indexed from 0 to n-1
            # but the corr. LP vars are indexed from 1 to n
            # since 0 is the base-case var
            # for var = False
            false_constraint = (var_valuation,
                                self.model.addConstr(
                                    self.partial_wts[(blockId + 1, cylId)] -
                                    self.partial_wts[(blockId, cylId)] == 0))
            wt_constraints.append(false_constraint)

            # same for var being True
            block = hbw_task.objects.blocks[blockId]
            var_valuation = [(var.index, True)]
            true_constraint = (
                var_valuation,
                self.model.addConstr(
                    self.partial_wts[(blockId + 1, cylId)] -
                    self.partial_wts[(blockId, cylId)] == block.weight))
            wt_constraints.append(true_constraint)

        return wt_constraints

    # this function adds equality constraints to calculate the total downward force
    # at the bottom of the cylinder (column_wt = total weight of all blocks + wt of fluid column)
    def make_column_wt_constraints_for_cylinder(self, cylId, hbw_task):
        density = hbw_task.objects.get_fluid_density()
        cross_section_area_of_cyl = hbw_task.objects.cylinders[cylId].area

        lpvar_wt_of_blocks = self.partial_wts[(
            hbw_task.objects.num_blocks(),
            cylId)]  #element corresponding to total wt of blocks

        constr = (
            [],  # unconditional
            self.model.addConstr(
                self.column_wts[cylId] - density * cross_section_area_of_cyl *
                self.fluid_column_heights[cylId] - lpvar_wt_of_blocks == 0))

        return constr

    def make_column_wt_constraints(self, hbw_task):
        return [
            self.make_column_wt_constraints_for_cylinder(cylId, hbw_task)
            for cylId in xrange(hbw_task.objects.num_cylinders())
        ]

    def make_pressure_balancing_constraints(self, hbw_task):
        pb_constraints = []
        # we have 'numCylinders -1' constraints - one for each consecutive pair
        for cylId in xrange(hbw_task.objects.num_cylinders() - 1):
            # constr for cylId & cylId + 1
            reciprocal_area_1 = 1.0 / hbw_task.objects.cylinders[cylId].area
            reciprocal_area_2 = 1.0 / hbw_task.objects.cylinders[cylId +
                                                                 1].area

            lpconstr = (
                [],  # unconditional
                self.model.addConstr(
                    reciprocal_area_1 * self.column_wts[cylId] -
                    reciprocal_area_2 * self.column_wts[cylId + 1] == 0))

            pb_constraints.append(lpconstr)

        return pb_constraints

    def make_fluid_balancing_constraint(self, hbw_task):
        constr = (
            [],  # unconditional
            self.model.addConstr(
                quicksum(hbw_task.objects.cylinders[cylId].area *
                         self.fluid_column_heights[cylId]
                         for cylId in xrange(hbw_task.objects.num_cylinders()))
                == hbw_task.objects.fluid.total_fluid_in_cylinders))

        return [constr]

    def print_constraints(self):
        for phi, gamma in self.constraints:
            if len(phi) == 0:
                print(' True -> %s' % gamma)
            else:
                head = ' & '.join(['%s = %s' % (x, v) for x, v in phi])
                print(' %s -> %s' % (head, gamma))
Ejemplo n.º 5
0
class LinearProgram :
        
        def __init__( self, task = None ) :

                if task is None:
                        return

                self.task = task
        
                self.model = Model( task.instance_name + '.lp' )

                # LP variables
                self.variables = [] # was all_variables
                self.make_model_vars( task )
                self.model.update()

                # LP Constraints
                self.constraints = []
                self.make_model_constraints( task )
                self.model.update()

                self.goal_constraints = set( range(self.first_goal_constraint, len(self.constraints)) )
                #self.model.write( 'tmp.lp' )

        def copy( self ) :
                from copy import deepcopy

                new_lp = LinearProgram( )
                new_lp.model = self.model.copy()
                new_lp.constraints = []
                for index, ext_constraint in enumerate(self.constraints) :
                        new_lp.constraints.append( ( deepcopy(ext_constraint[0]), new_lp.model.getConstrs()[index] ) )
                new_lp.first_goal_constraint = self.first_goal_constraint
                new_lp.goal_constraints = set( range (new_lp.first_goal_constraint, len(new_lp.constraints)) )
                return new_lp

        def make_model_vars( self, task ) :
                # vars are x_{v,l,t} for vehicle v, (non-depot) location l
                # and goods type t in {ambient, chilled}; if the vehicle
                # is non-refridgerated, only t = ambient should be created.
                
                self.varindex = {}
                for (vname, _, cap, chilled) in task.vehicles:
                        for loc in task.locations[1:]:
                                varname = 'x_{0}_{1}_ambient'.format(vname, loc)
                                x = self.model.addVar(vtype = GRB.CONTINUOUS, 
                                                      name = varname,
                                                      lb = 0.0,
                                                      ub = cap)
                                self.variables.append(x)
                                self.varindex[(vname, loc, 'ambient')] = x
                                if chilled:
                                        varname = 'x_{0}_{1}_chilled'.format(vname, loc)
                                        x = self.model.addVar(vtype = GRB.CONTINUOUS, 
                                                              name = varname,
                                                              lb = 0.0,
                                                              ub = cap)
                                        self.variables.append(x)
                                        self.varindex[(vname, loc, 'chilled')] = x


        def get_all_variables (self):
                return self.variables

        def get_all_constraints (self):
                return self.constraints

        def make_model_constraints (self, task):
                self.constraints = []

                # vehicle capacity constraints: sum of allocations
                # to all locations and goods types must be within
                # vehicle capacity.
                for (vname, _, cap, chilled) in task.vehicles:
                        avars = [ self.varindex[(vname, loc, 'ambient')] for loc in task.locations[1:] ]
                        if chilled:
                                avars += [ self.varindex[(vname, loc, 'chilled')] for loc in task.locations[1:] ]
                        c = self.model.addConstr( quicksum( avars ), GRB.LESS_EQUAL, float(cap) )
                        constraint = ( [], c )
                        self.constraints.append( constraint )

                # switched constraints:
                # visited[v,l] = False -> x_v_l_{a,c} = 0,
                # for all v and l
                for (vname, _, _, chilled) in task.vehicles:
                        for loc in task.locations[1:]:
                                var = task.visited[(vname, loc)]
                                trigger = [ ( var.index, False ) ]
                                constraint = ( trigger, self.model.addConstr( self.varindex[(vname, loc, 'ambient')], GRB.EQUAL, 0.0) )
                                self.constraints.append(constraint)
                                if chilled:
                                        constraint = ( trigger, self.model.addConstr( self.varindex[(vname, loc, 'chilled')], GRB.EQUAL, 0.0) )
                                        self.constraints.append(constraint)

                # goal constraints
                self.first_goal_constraint = len(self.constraints)
                for loc in task.locations[1:]:
                        (qc, qa) = task.demand[loc]
                        avars = []
                        cvars = []
                        for (vname, _, _, chilled) in task.vehicles:
                                avars.append(self.varindex[ (vname, loc, 'ambient') ])
                                if chilled:
                                        cvars.append(self.varindex[ (vname, loc, 'chilled') ])
                        c = self.model.addConstr( quicksum( avars ), GRB.EQUAL, float(qa) )
                        #print(loc, c, qa)
                        self.constraints.append( ( [], c ) )
                        c = self.model.addConstr( quicksum( cvars ), GRB.EQUAL, float(qc) )
                        #print(loc, c, qc)
                        self.constraints.append( ( [], c ) )


        def print_constraints (self):
                for index,(phi, gamma) in enumerate(self.constraints):
                        if len(phi) == 0 : 
                                print( index, ' True -> %s'%gamma )
                        else :
                                head = ' & '.join( [ '%s = %s'%(self.task.state_vars[x].name,v) for x,v in phi ] )
                                print ( index, ' %s -> %s'%( head, gamma ) )
Ejemplo n.º 6
0
class LinearProgram:
    def __init__(self, counters_task):

        self.model = Model(counters_task.instance_name + '.lp')

        # LP Vars
        self.variables = []
        self.make_model_vars(counters_task)
        self.model.update()

        # LP Constraints
        self.constraints = []
        self.make_model_constraints(counters_task)
        self.model.update()

        self.goal_constraints = set()

    def copy(self):
        from copy import deepcopy

        new_lp = LinearProgram()
        new_lp.variables = deepcopy(self.variables)
        new_lp.goal_constraints = deepcopy(self.goal_constraints)
        new_lp.model = self.model.copy()
        new_lp.constraints = []
        for index, ext_constraint in enumerate(self.constraints):
            new_lp.constraints.append((deepcopy(ext_constraint[0]),
                                       new_lp.model.getConstrs()[index]))
        return new_lp

    def make_model_vars(self, task):
        for x_c in task.counter_values:
            x_c_2 = self.model.addVar(name=x_c.name,
                                      lb=min(x_c.domain),
                                      ub=max(x_c.domain),
                                      vtype=GRB.INTEGER)
            self.variables.append(x_c_2)

    def make_model_constraints(self, task):

        for i in range(0, len(self.variables)):
            x = task.counter_values[i]
            x2 = self.variables[i]

            # Equivalence constraints
            for v in x.domain:
                c = self.model.addConstr(x2 == v)
                self.constraints.append(([(x.index, v)], c))

            # Bounds constraints
            gt_zero = self.model.addConstr(x2 >= 0)
            lt_max = self.model.addConstr(x2, GRB.LESS_EQUAL, task.max_value)

            self.constraints.append(([], gt_zero))
            self.constraints.append(([], lt_max))

    def make_goal_constraints(self, goal_condition):
        goal_constraints = []
        for cond, lhs, rhs in goal_condition:
            x_lhs = None
            x_rhs = None
            for x in self.model.getVars():
                if lhs in x.getAttr('VarName'):
                    x_lhs = x
                if rhs in x.getAttr('VarName'):
                    x_rhs = x
            assert x_lhs is not None
            assert x_rhs is not None
            c = None
            if cond == '<':
                c = ([], self.model.addConstr(x_lhs <= x_rhs))
                self.constraints.append(c)
                goal_constraints.append(len(self.constraints) - 1)

                c = ([], self.model.addConstr(x_lhs <= x_rhs - 1))
                self.constraints.append(c)
                goal_constraints.append(len(self.constraints) - 1)
            elif cond == '>':
                c = ([], self.model.addConstr(x_lhs >= x_rhs))
                self.constraints.append(c)
                goal_constraints.append(len(self.constraints) - 1)

                c = ([], self.model.addConstr(x_lhs - 1 >= x_rhs))
                self.constraints.append(c)
                goal_constraints.append(len(self.constraints) - 1)

            elif cond == '=':
                c = ([], self.model.addConstr(x_lhs == x_rhs))
                self.constraints.append(c)
                goal_constraints.append(len(self.constraints) - 1)

            else:
                assert False

        self.model.update()
        self.goal_constraints = set(goal_constraints)
        return self.goal_constraints
Ejemplo n.º 7
0
class LinearProgram:
    def __init__(self, counters_task=None):

        if counters_task is None:
            return

        self.model = Model(counters_task.instance_name + '.lp')

        self.var_map = {}

        # LP Vars
        self.variables = []
        self.make_model_vars(counters_task)
        self.model.update()

        # LP Constraints
        self.constraints = []
        self.make_model_constraints(counters_task)
        self.model.update()

        self.goal_constraints = set()

    def copy(self):
        from copy import deepcopy

        new_lp = LinearProgram()
        new_lp.goal_constraints = deepcopy(self.goal_constraints)
        new_lp.model = self.model.copy()
        new_lp.constraints = []
        for index, ext_constraint in enumerate(self.constraints):
            new_lp.constraints.append((deepcopy(ext_constraint[0]),
                                       new_lp.model.getConstrs()[index]))
        return new_lp

    def make_model_vars(self, task):
        for x_c in task.counter_values:
            x_c_2 = self.model.addVar(name=x_c, lb=0, ub=task.max_value -
                                      1)  ## , vtype = GRB.INTEGER
            self.variables.append(x_c_2)
            self.var_map[x_c] = x_c_2

    def make_model_constraints(self, task):

        for counter in task.counter_values:
            for k in xrange(0, task.max_value):
                x = self.var_map[counter]
                c = self.model.addConstr(k <= x)
                self.constraints.append(
                    ([(task.counter_values[counter][k].index, True)], c))
                c = self.model.addConstr(x <= k - 1)
                self.constraints.append(
                    ([(task.counter_values[counter][k].index, False)], c))

    def make_goal_constraints(self, goal_condition):
        goal_constraints = []
        # print(goal_condition)
        # print(self.model.variables)
        # print(self.var_map)
        for cond, lhs, rhs in goal_condition:
            # x_lhs = None
            # x_rhs = None
            # for x in self.model.getVars() :
            # 	if lhs in x.getAttr('VarName') :
            # 		x_lhs = x
            # 	if rhs in x.getAttr('VarName') :
            # 		x_rhs = x
            # assert x_lhs is not None
            # assert x_rhs is not None
            x_lhs = self.var_map[lhs]
            x_rhs = self.var_map[rhs]
            c = None
            if cond == '<':
                c = ([], self.model.addConstr(x_lhs <= x_rhs - 1))
                self.constraints.append(c)
                goal_constraints.append(len(self.constraints) - 1)

            elif cond == '>':
                c = ([], self.model.addConstr(x_lhs - 1 >= x_rhs))
                self.constraints.append(c)
                goal_constraints.append(len(self.constraints) - 1)

            elif cond == '=':
                c = ([], self.model.addConstr(x_lhs == x_rhs))
                self.constraints.append(c)
                goal_constraints.append(len(self.constraints) - 1)

            else:
                assert False

        self.model.update()
        self.goal_constraints = set(goal_constraints)
        return self.goal_constraints
Ejemplo n.º 8
0
def populate_dual_subproblem(data):
    """
    Function that populates the Benders Dual Subproblem, as suggested by the
    paper "Minimal Infeasible Subsystems and Bender's cuts" by Fischetti,
    Salvagnin and Zanette.
    :param data:        Problem data structure
    :param upper_cost:  Link setup decisions fixed in the master
    :param flow_cost:   This is the cost of the continuous variables of the
                        master problem, as explained in the paper
    :return:            Numpy array of Gurobi model objects
    """

    # Gurobi model objects
    subproblems = np.empty(shape=(data.periods, data.commodities),
                           dtype=object)

    # Construct model for period/commodity 0.
    # Then, copy this and change the coefficients
    subproblem = Model('subproblem_(0,0)')

    # Ranges we are going to need
    arcs, periods, commodities, nodes = xrange(data.arcs.size), xrange(
        data.periods), xrange(data.commodities), xrange(data.nodes)

    # Other data
    demand, var_cost = data.demand, data.variable_cost

    # Origins and destinations of commodities
    origins, destinations = data.origins, data.destinations

    # We use arrays to store variable indexes and variable objects. Why use
    # both? Gurobi wont let us get the values of individual variables
    # within a callback.. We just get the values of a large array of
    # variables, in the order they were initially defined. To separate them
    # in variable categories, we will have to use index arrays
    flow_vars = np.empty_like(arcs, dtype=object)

    # Populate all variables in one loop, keep track of their indexes
    # Data for period = 0, com = 0
    for arc in arcs:
        flow_vars[arc] = subproblem.addVar(obj=demand[0, 0] * var_cost[arc],
                                           lb=0.,
                                           ub=1.,
                                           name='flow_a{}'.format(arc))

    subproblem.update()
    # Add constraints
    for node in nodes:
        out_arcs = get_2d_index(data.arcs, data.nodes)[0] == node + 1
        in_arcs = get_2d_index(data.arcs, data.nodes)[1] == node + 1
        lhs = quicksum(flow_vars[out_arcs]) - quicksum(flow_vars[in_arcs])
        subproblem.addConstr(lhs == 0., name='flow_bal{}'.format(node))
    subproblem.update()

    # Store variables
    subproblem._all_variables = flow_vars.tolist()

    # Set parameters
    subproblem.setParam('OutputFlag', 0)
    subproblem.modelSense = GRB.MINIMIZE
    subproblem.params.threads = 2
    subproblem.params.LogFile = ""
    subproblem.update()

    subproblems[0, 0] = subproblem

    for period, com in product(periods, commodities):
        if (period, com) != (0, 0):
            model = subproblem.copy()
            model.ModelName = 'subproblem_({},{})'.format(period, com)
            flow_cost = data.demand[period, com] * var_cost
            model.setObjective(LinExpr(flow_cost.tolist(), model.getVars()))
            model.setAttr('rhs', model.getConstrs(), [0.0] * data.nodes)

            model._all_variables = model.getVars()
            model.update()
            subproblems[period, com] = model

    return subproblems
Ejemplo n.º 9
0
m.setAttr('ModelSense', GRB.MAXIMIZE)

m.update()

m.addConstr(x1 + x2 <= 6, "c0")
m.addConstr(9*x1 + 5*x2 <= 45, "c1")
m.setParam( 'OutputFlag', False )
m.optimize()

logStatus(m)

root = bn.BBNode(None, '', '', 0)

node1 = bn.BBNode(root,'x1','ub',3)
m1 = m.copy()
m1.addConstr(m1.getVars()[0] <= 3, "node1")
m1.optimize()
logStatus(m1)

node2 = bn.BBNode(root,'x1','lb',4)
m2 = m.copy()
m2.addConstr(m2.getVars()[0] >= 4, "node2")
m2.optimize()
logStatus(m2)

node21 = bn.BBNode(node2,'x2','ub', 1)
m21 = m2.copy()
m21.addConstr(m21.getVars()[1] <= 1,"node21")
m21.optimize()
logStatus(m21)