Ejemplo n.º 1
0
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('ctype', Complementarity)
        kwargs.setdefault('dense', False)
        _init = tuple(_arg for _arg in (kwargs.pop('initialize', None),
                                        kwargs.pop('rule', None),
                                        kwargs.pop('expr', None))
                      if _arg is not None)
        if len(_init) > 1:
            raise ValueError(
                "Duplicate initialization: Complementarity() only accepts "
                "one of 'initialize=', 'rule=', and 'expr='")
        elif _init:
            _init = _init[0]
        else:
            _init = None

        self._init_rule = Initializer(_init,
                                      treat_sequences_as_mappings=False,
                                      allow_generators=True)

        if self._init_rule is not None:
            kwargs['rule'] = Complementarity._complementarity_rule
        Block.__init__(self, *args, **kwargs)

        # HACK to make the "counted call" syntax work.  We wait until
        # after the base class is set up so that is_indexed() is
        # reliable.
        if self._init_rule is not None \
           and self._init_rule.__class__ is IndexedCallInitializer:
            self._init_rule = CountedCallInitializer(self, self._init_rule)
Ejemplo n.º 2
0
def create_submodel_hp_block(instance):
    """
    Creates highpoint relaxation with the given specified model; does
    not include any submodel or block that is deactivated
    """
    block = Block(concrete=True)

    # get the objective for the master problem
    for c in instance.component_objects(Objective, descend_into=False):
        block.add_component(c.name, Reference(c))

    # get the variables of the model (if there are more submodels, then
    # extraneous variables may be added to the block)
    for c in instance.component_objects(Var,
                                        sort=True,
                                        descend_into=True,
                                        active=True):
        block.add_component(c.name, Reference(c))

    # get the constraints from the main model
    for c in instance.component_objects(Constraint,
                                        sort=True,
                                        descend_into=True,
                                        active=True):
        block.add_component(c.name, Reference(c))

    # deactivate the highpoint relaxation
    block.deactivate()

    return block
Ejemplo n.º 3
0
    def _generate_model(self):
        self.model = ConcreteModel()
        model = self.model
        model._name = self.description

        model.s = Set(initialize=[1,2])
        model.x = Var()
        model.y = Var()
        model.z = Var(bounds=(0,None))

        model.obj = Objective(model.s,
                              rule=inactive_index_LP_obj_rule)
        model.OBJ = Objective(expr=model.x+model.y)
        model.obj[1].deactivate()
        model.OBJ.deactivate()
        model.c1 = ConstraintList()
        model.c1.add(model.x<=1)   # index=1
        model.c1.add(model.x>=-1)  # index=2
        model.c1.add(model.y<=1)   # index=3
        model.c1.add(model.y>=-1)  # index=4
        model.c1[1].deactivate()
        model.c1[4].deactivate()
        model.c2 = Constraint(model.s,
                              rule=inactive_index_LP_c2_rule)

        model.b = Block()
        model.b.c = Constraint(expr=model.z >= 2)
        model.B = Block(model.s)
        model.B[1].c = Constraint(expr=model.z >= 3)
        model.B[2].c = Constraint(expr=model.z >= 1)

        model.b.deactivate()
        model.B.deactivate()
        model.B[2].activate()
Ejemplo n.º 4
0
 def test_nested_blocks(self):
     """Test with nested blocks."""
     m = ConcreteModel()
     m.b = Block()
     m.inactive_b = Block()
     m.inactive_b.deactivate()
     m.b.x = Var()
     m.b.x2 = Var(domain=Binary)
     m.b.x3 = Var(domain=Integers)
     m.inactive_b.x = Var()
     m.b.c = Constraint(expr=m.b.x == m.b.x2)
     m.inactive_b.c = Constraint(expr=m.b.x == 1)
     m.inactive_b.c2 = Constraint(expr=m.inactive_b.x == 15)
     model_size = build_model_size_report(m)
     self.assertEqual(model_size.activated.variables, 2)
     self.assertEqual(model_size.overall.variables, 4)
     self.assertEqual(model_size.activated.binary_variables, 1)
     self.assertEqual(model_size.overall.binary_variables, 1)
     self.assertEqual(model_size.activated.integer_variables, 0)
     self.assertEqual(model_size.overall.integer_variables, 1)
     self.assertEqual(model_size.activated.constraints, 1)
     self.assertEqual(model_size.overall.constraints, 3)
     self.assertEqual(model_size.activated.disjuncts, 0)
     self.assertEqual(model_size.overall.disjuncts, 0)
     self.assertEqual(model_size.activated.disjunctions, 0)
     self.assertEqual(model_size.overall.disjunctions, 0)
Ejemplo n.º 5
0
def makeNetworkDisjunction(minimize=True):
    """ creates a GDP model with pyomo.network components """
    m = ConcreteModel()

    m.feed = feed = Block()
    m.wkbx = wkbx = Block()
    m.dest = dest = Block()

    m.orange = orange = Disjunct()
    m.blue = blue = Disjunct()

    m.orange_or_blue = Disjunction(expr=[orange,blue])

    blue.blue_box = blue_box = Block()

    feed.x = Var(bounds=(0,1))
    wkbx.x = Var(bounds=(0,1))
    dest.x = Var(bounds=(0,1))

    wkbx.inlet = ntwk.Port(initialize={"x":wkbx.x})
    wkbx.outlet = ntwk.Port(initialize={"x":wkbx.x})

    feed.outlet = ntwk.Port(initialize={"x":feed.x})
    dest.inlet = ntwk.Port(initialize={"x":dest.x})

    blue_box.x = Var(bounds=(0,1))
    blue_box.x_wkbx = Var(bounds=(0,1))
    blue_box.x_dest = Var(bounds=(0,1))


    blue_box.inlet_feed = ntwk.Port(initialize={"x":blue_box.x})
    blue_box.outlet_wkbx = ntwk.Port(initialize={"x":blue_box.x})

    blue_box.inlet_wkbx = ntwk.Port(initialize={"x":blue_box.x_wkbx})
    blue_box.outlet_dest = ntwk.Port(initialize={"x":blue_box.x_dest})

    blue_box.multiplier_constr = Constraint(expr=blue_box.x_dest == \
                                            2*blue_box.x_wkbx)

    # orange arcs
    orange.a1 = ntwk.Arc(source=feed.outlet, destination=wkbx.inlet)
    orange.a2 = ntwk.Arc(source=wkbx.outlet, destination=dest.inlet)

    # blue arcs
    blue.a1 = ntwk.Arc(source=feed.outlet, destination=blue_box.inlet_feed)
    blue.a2 = ntwk.Arc(source=blue_box.outlet_wkbx, destination=wkbx.inlet)
    blue.a3 = ntwk.Arc(source=wkbx.outlet, destination=blue_box.inlet_wkbx)
    blue.a4 = ntwk.Arc(source=blue_box.outlet_dest, destination=dest.inlet)

    # maximize/minimize "production"
    if minimize:
        m.obj = Objective(expr=m.dest.x)
    else:
        m.obj = Objective(expr=m.dest.x, sense=maximize)

    # create a completely fixed model
    feed.x.fix(0.42)

    return m
Ejemplo n.º 6
0
 def test_getname_error(self):
     m = ConcreteModel()
     m.b = Block()
     m.b.v = Var()
     m.c = Block()
     self.assertRaises(RuntimeError,
                       m.b.v.getname,
                       fully_qualified=True,
                       relative_to=m.c)
Ejemplo n.º 7
0
    def __init__(self, *args, **kwargs):
        if kwargs.pop('_deep_copying', None):
            # Hack for Python 2.4 compatibility
            # Deep copy will copy all items as necessary, so no need to
            # complete parsing
            return

        kwargs.setdefault('ctype', Disjunct)
        Block.__init__(self, *args, **kwargs)
Ejemplo n.º 8
0
    def __init__(self, *args, **kwargs):
        if kwargs.pop('_deep_copying', None):
            # Hack for Python 2.4 compatibility
            # Deep copy will copy all items as necessary, so no need to
            # complete parsing
            return

        kwargs.setdefault('ctype', Disjunct)
        Block.__init__(self, *args, **kwargs)
Ejemplo n.º 9
0
    def _create_transformation_block(self, context):
        new_xfrm_block_name = unique_component_name(context, 'logic_to_linear')
        new_xfrm_block = Block(doc="Transformation objects for logic_to_linear")
        setattr(context, new_xfrm_block_name, new_xfrm_block)

        new_xfrm_block.transformed_constraints = ConstraintList()
        new_xfrm_block.augmented_vars = BooleanVarList()
        new_xfrm_block.augmented_vars_asbinary = VarList( domain=Binary)

        return new_xfrm_block
Ejemplo n.º 10
0
    def _f(m: Block):
        m.lmbda = Var(vertices, domain=NonNegativeReals)  # 非负
        m.y = Var(simplices, domain=Binary)  # 二进制

        m.a0 = Constraint(dimensions, rule=lambda m, d: sum(m.lmbda[v] * pointsT[d][v] for v in vertices) == input[d])
        if bound == 'eq':
            m.a1 = Constraint(expr=output == sum(m.lmbda[v] * values[v] for v in vertices))
        elif bound == 'lb':
            m.a1 = Constraint(expr=output <= sum(m.lmbda[v] * values[v] for v in vertices))
        elif bound == 'ub':
            m.a1 = Constraint(expr=output >= sum(m.lmbda[v] * values[v] for v in vertices))
        else:
            raise RuntimeError("bound值错误!bound=" + bound)

        m.b = Constraint(expr=sum(m.lmbda[v] for v in vertices) == 1)

        # generate a map from vertex index to simplex index,
        # which avoids an n^2 lookup when generating the
        # constraint
        vertex_to_simplex = [[] for _ in vertices]
        for s, simplex in enumerate(tri.simplices):
            for v in simplex:
                vertex_to_simplex[v].append(s)
        m.c0 = Constraint(vertices, rule=lambda m, v: m.lmbda[v] <= sum(m.y[s] for s in vertex_to_simplex[v]))
        m.c1 = Constraint(expr=sum(m.y[s] for s in simplices) == 1)
        return m
Ejemplo n.º 11
0
    def _add_transformation_block(self, instance):
        # make a transformation block on instance to put transformed disjuncts
        # on
        transBlockName = unique_component_name(instance,
                                               '_pyomo_gdp_bigm_relaxation')
        transBlock = Block()
        instance.add_component(transBlockName, transBlock)
        transBlock.relaxedDisjuncts = Block(NonNegativeIntegers)
        transBlock.lbub = Set(initialize=['lb', 'ub'])

        return transBlock
Ejemplo n.º 12
0
 def disj_rule(d, flag):
     m = d.model()
     if flag:
         d.b = Block()
         d.b.c = Constraint(expr=m.x == 0)
         d.add_component('b.c', Constraint(expr=m.y >= 9))
         d.b.anotherblock = Block()
         d.b.anotherblock.c = Constraint(expr=m.y >= 11)
         d.bb = Block([1])
         d.bb[1].c = Constraint(expr=m.x == 0)
     else:
         d.c = Constraint(expr=m.x >= 80)
Ejemplo n.º 13
0
def makeHierarchicalNested_DeclOrderMatchesInstantationOrder():
    """Here, we put the disjunctive components on Blocks, but we do it in the 
    same order that we declared the blocks, that is, on each block, decl order
    matches instantiation order."""
    m = ConcreteModel()
    m.I = RangeSet(1, 4)
    m.x = Var(m.I, bounds=(-2, 6))
    m.disjunct_block = Block()
    m.disjunction_block = Block()
    instantiate_hierarchical_nested_model(m)

    return m
Ejemplo n.º 14
0
def makeHierarchicalNested_DeclOrderOppositeInstantationOrder():
    """Here, we declare the Blocks in the opposite order. This means that 
    decl order will be *opposite* instantiation order, which means that we 
    can break our targets preprocessing without even using targets if we 
    are not correctly identifying what is nested in what!"""
    m = ConcreteModel()
    m.I = RangeSet(1, 4)
    m.x = Var(m.I, bounds=(-2, 6))
    m.disjunction_block = Block()
    m.disjunct_block = Block()
    instantiate_hierarchical_nested_model(m)

    return m
Ejemplo n.º 15
0
def create_linear_dual_from_matrix_repn(c, b, P, d):
    blk = Block()
    n, m = P.shape
    # Add dual variables
    blk.var = Var(range(n), within=NonNegativeReals)
    # Dual objective
    blk.obj = Constraint(expr=quicksum(d[j] * b.var[j] for j in range(n)) <= b)
    # Dual constraints
    blk.cons = ConstraintList()
    for i in range(m):
        blk.cons.add(quicksum(P[i, j] * b.var[j] for j in range(n)) == c[i])

    return blk
Ejemplo n.º 16
0
def dlog(m: Block,
         tri: qhull.Delaunay,
         values: List[float],
         input: List[SimpleVar] = None,
         output: SimpleVar = None,
         bound: str = 'eq',
         **kw):
    values = np.array(values).tolist()
    ndim = len(input)
    nsimplices = len(tri.simplices)
    npoints = len(tri.points)
    pointsT = list(zip(*tri.points))
    # create index objects
    dimensions = list(range(ndim))
    simplices = list(range(nsimplices))  # 跟单纯形 数量一致
    vertices = list(range(npoints))
    bound = bound.lower()
    L = int(math.ceil(math.log2(nsimplices)))
    L_Range = list(range(L))
    vp = [0, 1, 2]
    #
    m.lmbda = Var(simplices, vp, domain=NonNegativeReals)  # 非负
    m.a0 = Constraint(
        dimensions,
        rule=lambda m, d: sum(m.lmbda[s, v] * pointsT[d][tri.simplices[s][v]]
                              for s in simplices for v in vp) == input[d])
    if bound == 'eq':
        m.a1 = Constraint(expr=output == sum(
            m.lmbda[s, v] * values[tri.simplices[s][v]] for s in simplices
            for v in vp))
    elif bound == 'lb':
        m.a1 = Constraint(
            expr=output <= sum(m.lmbda[s, v] * values[tri.simplices[s][v]]
                               for s in simplices for v in vp))
    elif bound == 'ub':
        m.a1 = Constraint(
            expr=output >= sum(m.lmbda[s, v] * values[tri.simplices[s][v]]
                               for s in simplices for v in vp))
    else:
        raise RuntimeError("bound值错误!bound=" + bound)

    m.b1 = Constraint(expr=sum(m.lmbda[s, v] for s in simplices
                               for v in vp) == 1)

    m.y = Var(L_Range, domain=Binary)  # 二进制

    m.c0 = Constraint(L_Range,
                      rule=lambda m, l: sum(m.lmbda[s, v] for s in simplices
                                            if bin(s)[2:].zfill(L)[l] == '1'
                                            for v in vp) <= m.y[l])
    m.c1 = Constraint(L_Range,
                      rule=lambda m, l: sum(m.lmbda[s, v] for s in simplices
                                            if bin(s)[2:].zfill(L)[l] == '0'
                                            for v in vp) <= 1 - m.y[l])
    return m
Ejemplo n.º 17
0
def _write_bundle_NL(worker,
                     bundle,
                     output_directory,
                     linking_suffix_name,
                     objective_suffix_name,
                     symbolic_solver_labels):

    assert os.path.exists(output_directory)

    bundle_instance = worker._bundle_binding_instance_map[bundle.name]
    assert not hasattr(bundle_instance, ".tmpblock")
    tmpblock = Block(concrete=True)
    bundle_instance.add_component(".tmpblock", tmpblock)

    #
    # linking variable suffix
    #
    tmpblock.add_component(linking_suffix_name,
                           Suffix(direction=Suffix.EXPORT))
    linking_suffix = getattr(tmpblock, linking_suffix_name)

    # Loop over all nodes for the bundle except the leaf nodes,
    # which have no blended variables
    scenario_tree = worker.scenario_tree
    for stage in bundle.scenario_tree.stages[:-1]:
        for _node in stage.nodes:
            # get the node of off the real scenario tree
            # as this has the linked variable information
            node = scenario_tree.get_node(_node.name)
            master_variable = bundle_instance.find_component(
                "MASTER_BLEND_VAR_"+str(node.name))
            for variable_id in node._standard_variable_ids:
                linking_suffix[master_variable[variable_id]] = variable_id

    #
    # objective weight suffix
    #
    tmpblock.add_component(objective_suffix_name,
                           Suffix(direction=Suffix.EXPORT))

    getattr(tmpblock, objective_suffix_name)[bundle_instance] = \
        bundle._probability

    output_filename = os.path.join(output_directory, str(bundle.name)+".nl")
    bundle_instance.write(
        output_filename,
        io_options={'symbolic_solver_labels': symbolic_solver_labels})

    bundle_instance.del_component(tmpblock)
Ejemplo n.º 18
0
    def _generate_model(self):
        self.model = ConcreteModel()
        model = self.model
        model._name = self.description

        model.b = Block()
        model.B = Block([1,2,3])
        model.a = Param(initialize=1.0, mutable=True)
        model.b.x = Var(within=NonNegativeReals)
        model.B[1].x = Var(within=NonNegativeReals)

        model.obj = Objective(expr=model.b.x + 3.0*model.B[1].x)
        model.obj.deactivate()
        model.B[2].c = Constraint(expr=-model.B[1].x <= -model.a)
        model.B[2].obj = Objective(expr=model.b.x + 3.0*model.B[1].x + 2)
        model.B[3].c = Constraint(expr=2.0 <= model.b.x/model.a - model.B[1].x <= 10)
Ejemplo n.º 19
0
def generate_norm_inf_objective_function(model, setpoint_model, discrete_only=False):
    """This function generates objective (PF-OA main problem) for minimum Norm Infinity distance to setpoint_model.

    Norm-Infinity distance of (x,y) = \max_i |x_i - y_i|.

    Args:
        model (Pyomo model): the model that needs new objective function.
        setpoint_model (Pyomo model): the model that provides the base point for us to calculate the distance.
        discrete_only (bool, optional): whether only optimize on distance between the discrete variables. Defaults to False.

    Returns:
        Objective: the norm infinity objective function
    """
    # skip objective_value variable and slack_var variables
    var_filter = (lambda v: v.is_integer()) if discrete_only \
        else (lambda v: v.name != 'MindtPy_utils.objective_value' and
              'MindtPy_utils.feas_opt.slack_var' not in v.name)
    model_vars = list(filter(var_filter, model.MindtPy_utils.variable_list))
    setpoint_vars = list(
        filter(var_filter, setpoint_model.MindtPy_utils.variable_list))
    assert len(model_vars) == len(
        setpoint_vars), 'Trying to generate Norm Infinity objective function for models with different number of variables'
    model.MindtPy_utils.del_component('L_infinity_obj')
    obj_blk = model.MindtPy_utils.L_infinity_obj = Block()
    obj_blk.L_infinity_obj_var = Var(domain=Reals, bounds=(0, None))
    obj_blk.abs_reform = ConstraintList()
    for v_model, v_setpoint in zip(model_vars,
                                   setpoint_vars):
        obj_blk.abs_reform.add(
            expr=v_model - v_setpoint.value >= -obj_blk.L_infinity_obj_var)
        obj_blk.abs_reform.add(
            expr=v_model - v_setpoint.value <= obj_blk.L_infinity_obj_var)

    return Objective(expr=obj_blk.L_infinity_obj_var)
Ejemplo n.º 20
0
    def test_rules_with_None_in_set(self):
        def noarg_rule(b):
            b.args = ()
        def onearg_rule(b, i):
            b.args = (i,)
        def twoarg_rule(b, i, j):
            b.args = (i,j)
        m = ConcreteModel()
        m.b1 = Block(rule=noarg_rule)
        self.assertEqual(m.b1.args, ())

        m.b2 = Block([None], rule=onearg_rule)
        self.assertEqual(m.b2[None].args, (None,))

        m.b3 = Block([(None,1)], rule=twoarg_rule)
        self.assertEqual(m.b3[None,1].args, ((None,1)))
Ejemplo n.º 21
0
Archivo: util.py Proyecto: dilr/pyomo
def reformulate_integer_variables(model, config):
    integer_vars = list(v for v in model.component_data_objects(
        ctype=Var, descend_into=(Block, Disjunct))
                        if v.is_integer() and not v.fixed)
    if len(integer_vars) == 0:
        return  # if no free integer variables, no reformulation needed.

    if config.reformulate_integer_vars_using is None:
        config.logger.warning(
            "Model contains unfixed integer variables. "
            "GDPopt will reformulate using base 2 binary variables "
            "by default. To specify a different method, see the "
            "reformulate_integer_vars_using configuration option.")
        config.reformulate_integer_vars_using = 'base2_binary'

    config.logger.info(
        "Reformulating integer variables using the %s strategy." %
        config.reformulate_integer_vars_using)

    # Set up reformulation block
    reform_block = model.GDPopt_utils.integer_reform = Block(
        doc="Holds variables and constraints for reformulating "
        "integer variables to binary variables.")
    reform_block.new_binary_var = Var(
        Any,
        domain=Binary,
        dense=False,
        doc="Binary variable with index (int_var.name, indx)")
    reform_block.integer_to_binary_constraint = Constraint(
        Any,
        doc="Equality constraints mapping the binary variable values "
        "to the integer variable value.")

    # check that variables are bounded and non-negative
    for int_var in integer_vars:
        if not (int_var.has_lb() and int_var.has_ub()):
            raise ValueError(
                "Integer variable %s is missing an "
                "upper or lower bound. LB: %s; UB: %s. "
                "GDPopt does not support unbounded integer variables." %
                (int_var.name, int_var.lb, int_var.ub))
        if int_var.lb < 0:
            raise ValueError("Integer variable %s can be negative. "
                             "GDPopt currently only supports positive integer "
                             "variables." % (int_var.name))
        # do the reformulation
        highest_power = floor(log(value(int_var.ub), 2))
        var_name = int_var.name
        reform_block.integer_to_binary_constraint.add(
            var_name,
            expr=int_var == sum(reform_block.new_binary_var[var_name, pwr] *
                                (2**pwr)
                                for pwr in range(0,
                                                 int(highest_power) + 1)))
        int_var.domain = NonNegativeReals

    config.logger.info("Reformulated %s integer variables using "
                       "%s binary variables and %s constraints." %
                       (len(integer_vars), len(reform_block.new_binary_var),
                        len(reform_block.integer_to_binary_constraint)))
Ejemplo n.º 22
0
def add_affine_cuts(nlp_result, solve_data, config):
    with time_code(solve_data.timing, "affine cut generation"):
        m = solve_data.linear_GDP
        if config.calc_disjunctive_bounds:
            with time_code(solve_data.timing, "disjunctive variable bounding"):
                TransformationFactory(
                    'contrib.compute_disj_var_bounds').apply_to(
                        m,
                        solver=config.mip_solver
                        if config.obbt_disjunctive_bounds else None)
        config.logger.info("Adding affine cuts.")
        GDPopt = m.GDPopt_utils
        counter = 0
        for var, val in zip(GDPopt.variable_list, nlp_result.var_values):
            if val is not None and not var.fixed:
                var.value = val

        for constr in constraints_in_True_disjuncts(m, config):
            # Note: this includes constraints that are deactivated in the current model (linear_GDP)

            disjunctive_var_bounds = disjunctive_bounds(constr.parent_block())

            if constr.body.polynomial_degree() in (1, 0):
                continue

            vars_in_constr = list(identify_variables(constr.body))
            if any(var.value is None for var in vars_in_constr):
                continue  # a variable has no values

            # mcpp stuff
            mc_eqn = mc(constr.body, disjunctive_var_bounds)
            # mc_eqn = mc(constr.body)
            ccSlope = mc_eqn.subcc()
            cvSlope = mc_eqn.subcv()
            ccStart = mc_eqn.concave()
            cvStart = mc_eqn.convex()
            ub_int = min(
                constr.upper,
                mc_eqn.upper()) if constr.has_ub() else mc_eqn.upper()
            lb_int = max(
                constr.lower,
                mc_eqn.lower()) if constr.has_lb() else mc_eqn.lower()

            parent_block = constr.parent_block()
            # Create a block on which to put outer approximation cuts.
            aff_utils = parent_block.component('GDPopt_aff')
            if aff_utils is None:
                aff_utils = parent_block.GDPopt_aff = Block(
                    doc="Block holding affine constraints")
                aff_utils.GDPopt_aff_cons = ConstraintList()
            aff_cuts = aff_utils.GDPopt_aff_cons
            concave_cut = sum(ccSlope[var] * (var - var.value)
                              for var in vars_in_constr) + ccStart >= lb_int
            convex_cut = sum(cvSlope[var] * (var - var.value)
                             for var in vars_in_constr) + cvStart <= ub_int
            aff_cuts.add(expr=concave_cut)
            aff_cuts.add(expr=convex_cut)
            counter += 2

        config.logger.info("Added %s affine cuts" % counter)
Ejemplo n.º 23
0
def makeTwoTermDisj_IndexedConstraints():
    """Single two-term disjunction with IndexedConstraints on both disjuncts.  
    Does not bound the variables, so cannot be transformed by hull at all and 
    requires specifying m values in bigm.
    """
    m = ConcreteModel()
    m.s = Set(initialize=[1, 2])
    m.a = Var(m.s)
    m.b = Block()

    def disj1_rule(disjunct):
        m = disjunct.model()

        def c_rule(d, s):
            return m.a[s] == 0

        disjunct.c = Constraint(m.s, rule=c_rule)

    m.b.simpledisj1 = Disjunct(rule=disj1_rule)

    def disj2_rule(disjunct):
        m = disjunct.model()

        def c_rule(d, s):
            return m.a[s] <= 3

        disjunct.c = Constraint(m.s, rule=c_rule)

    m.b.simpledisj2 = Disjunct(rule=disj2_rule)
    m.b.disjunction = Disjunction(expr=[m.b.simpledisj1, m.b.simpledisj2])
    return m
Ejemplo n.º 24
0
def _process_container(blk, config):
    if not hasattr(blk, '_induced_linearity_info'):
        blk._induced_linearity_info = Block()
    else:
        assert blk._induced_linearity_info.ctype == Block
    eff_discr_vars = detect_effectively_discrete_vars(
        blk, config.equality_tolerance)
    # TODO will need to go through this for each disjunct, since it does
    # not (should not) descend into Disjuncts.

    # Determine the valid values for the effectively discrete variables
    possible_var_values = determine_valid_values(blk, eff_discr_vars, config)

    # Collect find bilinear expressions that can be reformulated using
    # knowledge of effectively discrete variables
    bilinear_map = _bilinear_expressions(blk)

    # Relevant constraints are those with bilinear terms that involve
    # effectively_discrete_vars
    processed_pairs = ComponentSet()
    for v1, var_values in possible_var_values.items():
        v1_pairs = bilinear_map.get(v1, ())
        for v2, bilinear_constrs in v1_pairs.items():
            if (v1, v2) in processed_pairs:
                continue
            _process_bilinear_constraints(blk, v1, v2, var_values,
                                          bilinear_constrs)
            processed_pairs.add((v2, v1))
Ejemplo n.º 25
0
def makeTwoTermDisj_IndexedConstraints():
    m = ConcreteModel()
    m.s = Set(initialize=[1, 2])
    m.a = Var(m.s)
    m.b = Block()

    def disj1_rule(disjunct):
        m = disjunct.model()

        def c_rule(d, s):
            return m.a[s] == 0

        disjunct.c = Constraint(m.s, rule=c_rule)

    m.b.simpledisj1 = Disjunct(rule=disj1_rule)

    def disj2_rule(disjunct):
        m = disjunct.model()

        def c_rule(d, s):
            return m.a[s] <= 3

        disjunct.c = Constraint(m.s, rule=c_rule)

    m.b.simpledisj2 = Disjunct(rule=disj2_rule)
    m.b.disjunction = Disjunction(expr=[m.b.simpledisj1, m.b.simpledisj2])
    return m
Ejemplo n.º 26
0
    def _apply_to(self, instance, **kwds):
        # TODO: This data should be stored differently.  We cannot nest this transformation with itself
        if getattr(instance, 'bilinear_data_', None) is None:
            instance.bilinear_data_ = Block()
            instance.bilinear_data_.cache = {}
            instance.bilinear_data_.vlist = VarList()
            instance.bilinear_data_.vlist_boolean = []
            instance.bilinear_data_.IDX = Set()
            instance.bilinear_data_.disjuncts_ = Disjunct(
                instance.bilinear_data_.IDX * [0, 1])
            instance.bilinear_data_.disjunction_data = {}
            instance.bilinear_data_.o_expr = {}
            instance.bilinear_data_.c_body = {}
        #
        # Iterate over all blocks
        #
        for block in instance.block_data_objects(
                active=True, sort=SortComponents.deterministic):
            self._transformBlock(block, instance)
        #
        # WEH: I wish I had a DisjunctList and DisjunctionList object...
        #
        def rule(block, i):
            return instance.bilinear_data_.disjunction_data[i]

        instance.bilinear_data_.disjunction_ = Disjunction(
            instance.bilinear_data_.IDX, rule=rule)
Ejemplo n.º 27
0
def cc(m: Block,
       tri: qhull.Delaunay,
       values: List[float],
       input: List[SimpleVar] = None,
       output: SimpleVar = None,
       bound: str = 'eq',
       **kw):
    values = np.array(values).tolist()
    ndim = len(input)
    nsimplices = len(tri.simplices)
    npoints = len(tri.points)
    pointsT = list(zip(*tri.points))
    # create index objects
    dimensions = list(range(ndim))
    simplices = list(range(nsimplices))  # 跟单纯形 数量一致
    vertices = list(range(npoints))
    bound = bound.lower()

    m.lmbda = Var(vertices, domain=NonNegativeReals)  # 非负
    m.y = Var(simplices, domain=Binary)  # 二进制
    # m.y = Var(simplices, domain=NonNegativeReals, bounds=(0, 1))  # 二进制

    m.a0 = Constraint(dimensions,
                      rule=lambda m, d: sum(m.lmbda[v] * pointsT[d][v]
                                            for v in vertices) == input[d])
    if bound == 'eq':
        m.a1 = Constraint(expr=output == sum(m.lmbda[v] * values[v]
                                             for v in vertices))
    elif bound == 'lb':
        m.a1 = Constraint(expr=output <= sum(m.lmbda[v] * values[v]
                                             for v in vertices))
    elif bound == 'ub':
        m.a1 = Constraint(expr=output >= sum(m.lmbda[v] * values[v]
                                             for v in vertices))
    else:
        raise RuntimeError("bound值错误!bound=" + bound)

    m.b = Constraint(expr=sum(m.lmbda[v] for v in vertices) == 1)

    # generate a map from vertex index to simplex index,
    # which avoids an n^2 lookup when generating the
    # constraint
    vertex_to_simplex = [[] for _ in vertices]
    for s, simplex in enumerate(tri.simplices):
        for v in simplex:
            vertex_to_simplex[v].append(s)
    m.c0 = Constraint(
        vertices,
        rule=lambda m, v: m.lmbda[v] <= sum(m.y[s]
                                            for s in vertex_to_simplex[v]))
    m.c1 = Constraint(expr=sum(m.y[s] for s in simplices) == 1)
    return m
Ejemplo n.º 28
0
    def test_gdp_tree(self):
        m = ConcreteModel()
        m.x = Var()
        m.block = Block()
        m.block.d1 = Disjunct()
        m.block.d1.dd1 = Disjunct()
        m.disj1 = Disjunct()
        m.block.disjunction = Disjunction(expr=[m.block.d1, m.disj1])
        m.block.d1.b = Block()
        m.block.d1.b.dd2 = Disjunct()
        m.block.d1.b.dd3 = Disjunct()
        m.block.d1.disjunction = Disjunction(
            expr=[m.block.d1.dd1, m.block.d1.b.dd2, m.block.d1.b.dd3])
        m.block.d1.b.dd2.disjunction = Disjunction(
            expr=[[m.x >= 1], [m.x <= -1]])
        targets = (m, )
        knownBlocks = {}
        tree = get_gdp_tree(targets, m, knownBlocks)

        # check tree structure first
        vertices = tree.vertices
        self.assertEqual(len(vertices), 10)
        in_degrees = {
            m.block.d1: 1,
            m.block.disjunction: 0,
            m.disj1: 1,
            m.block.d1.disjunction: 1,
            m.block.d1.dd1: 1,
            m.block.d1.b.dd2: 1,
            m.block.d1.b.dd3: 1,
            m.block.d1.b.dd2.disjunction: 1,
            m.block.d1.b.dd2.disjunction.disjuncts[0]: 1,
            m.block.d1.b.dd2.disjunction.disjuncts[1]: 1
        }
        for key, val in in_degrees.items():
            self.assertEqual(tree.in_degree(key), val)

        # This should be deterministic, so we can just check the order
        topo_sort = [
            m.block.disjunction, m.disj1, m.block.d1, m.block.d1.disjunction,
            m.block.d1.b.dd3, m.block.d1.b.dd2, m.block.d1.b.dd2.disjunction,
            m.block.d1.b.dd2.disjunction.disjuncts[1],
            m.block.d1.b.dd2.disjunction.disjuncts[0], m.block.d1.dd1
        ]
        sort = tree.topological_sort()
        for i, node in enumerate(sort):
            self.assertIs(node, topo_sort[i])
    def make_tiny_model_where_bounds_matter(self):
        m = ConcreteModel()
        m.b = Block()
        m.x = Var(bounds=(0, 15))
        m.y = Var(bounds=(3, 5))
        m.b.c = Constraint(expr=m.x + m.y <= 8)

        return m
Ejemplo n.º 30
0
 def _transfer_var_references(self, fromBlock, toBlock):
     disjunctList = toBlock.relaxedDisjuncts
     for idx, disjunctBlock in iteritems(fromBlock.relaxedDisjuncts):
         # move all the of the local var references
         newblock = disjunctList[len(disjunctList)]
         newblock.localVarReferences = Block()
         newblock.localVarReferences.transfer_attributes_from(
             disjunctBlock.localVarReferences)
Ejemplo n.º 31
0
 def test_active_parent_block(self):
     m = ConcreteModel()
     m.d1 = Block()
     m.d1.sub1 = Disjunct()
     m.d1.sub2 = Disjunct()
     m.d1.disj = Disjunction(expr=[m.d1.sub1, m.d1.sub2])
     with self.assertRaises(GDP_Error):
         TransformationFactory('gdp.reclassify').apply_to(m)
Ejemplo n.º 32
0
 def _add_relaxation_block(self, instance, name):
     # creates transformation block with a unique name based on name, adds it
     # to instance, and returns it.
     transBlockName = unique_component_name(
         instance, '_pyomo_gdp_cuttingplane_relaxation')
     transBlock = Block()
     instance.add_component(transBlockName, transBlock)
     return transBlockName, transBlock
Ejemplo n.º 33
0
def _write_scenario_NL(worker,
                       scenario,
                       output_directory,
                       linking_suffix_name,
                       objective_suffix_name,
                       symbolic_solver_labels):

    assert os.path.exists(output_directory)
    instance = scenario._instance
    assert not hasattr(instance, ".tmpblock")
    tmpblock = Block(concrete=True)
    instance.add_component(".tmpblock", tmpblock)

    #
    # linking variable suffix
    #
    bySymbol = instance._ScenarioTreeSymbolMap.bySymbol
    tmpblock.add_component(linking_suffix_name,
                           Suffix(direction=Suffix.EXPORT))
    linking_suffix = getattr(tmpblock, linking_suffix_name)

    # Loop over all nodes for the scenario except the leaf node,
    # which has no blended variables
    for node in scenario._node_list[:-1]:
        for variable_id in node._standard_variable_ids:
            linking_suffix[bySymbol[variable_id]] = variable_id

    #
    # objective weight suffix
    #
    tmpblock.add_component(objective_suffix_name,
                           Suffix(direction=Suffix.EXPORT))
    getattr(tmpblock, objective_suffix_name)[instance] = \
        scenario._probability

    output_filename = os.path.join(output_directory,
                                   str(scenario.name)+".nl")
    instance.write(
        output_filename,
        io_options={'symbolic_solver_labels': symbolic_solver_labels})

    instance.del_component(tmpblock)
Ejemplo n.º 34
0
def prune_possible_values(block_scope, possible_values, config):
    # Prune the set of possible values by solving a series of feasibility
    # problems
    top_level_scope = block_scope.model()
    tmp_name = unique_component_name(
        top_level_scope, '_induced_linearity_prune_data')
    tmp_orig_blk = Block()
    setattr(top_level_scope, tmp_name, tmp_orig_blk)
    tmp_orig_blk._possible_values = possible_values
    tmp_orig_blk._possible_value_vars = list(v for v in possible_values)
    tmp_orig_blk._tmp_block_scope = (block_scope,)
    model = top_level_scope.clone()
    tmp_clone_blk = getattr(model, tmp_name)
    for obj in model.component_data_objects(Objective, active=True):
        obj.deactivate()
    for constr in model.component_data_objects(
            Constraint, active=True, descend_into=(Block, Disjunct)):
        if constr.body.polynomial_degree() not in (1, 0):
            constr.deactivate()
    if block_scope.type() == Disjunct:
        disj = tmp_clone_blk._tmp_block_scope[0]
        disj.indicator_var.fix(1)
        TransformationFactory('gdp.bigm').apply_to(model)
    tmp_clone_blk.test_feasible = Constraint()
    tmp_clone_blk._obj = Objective(expr=1)
    for eff_discr_var, vals in tmp_clone_blk._possible_values.items():
        val_feasible = {}
        for val in vals:
            tmp_clone_blk.test_feasible.set_value(eff_discr_var == val)
            with SuppressConstantObjectiveWarning():
                res = SolverFactory(config.pruning_solver).solve(model)
            if res.solver.termination_condition is tc.infeasible:
                val_feasible[val] = False
        tmp_clone_blk._possible_values[eff_discr_var] = set(
            v for v in tmp_clone_blk._possible_values[eff_discr_var]
            if val_feasible.get(v, True))
    for i, var in enumerate(tmp_orig_blk._possible_value_vars):
        possible_values[var] = tmp_clone_blk._possible_values[
            tmp_clone_blk._possible_value_vars[i]]

    return possible_values
Ejemplo n.º 35
0
 def _get_block_model(self):
     model = ConcreteModel()
     model.s = Set(initialize=[1,2])
     b = Block(concrete=True)
     b.s = Set(initialize=[1,2])
     b.x = Var()
     b.X = Var(model.s)
     model.b1 = b.clone()
     model.b2 = b.clone()
     model.b3 = b.clone()
     model.b4 = b.clone()
     model.B1 = Block(model.s, rule=lambda _,i: b.clone())
     model.B2 = Block(model.s, rule=lambda _,i: b.clone())
     model.B3 = Block(model.s, rule=lambda _,i: b.clone())
     model.B4 = Block(model.s, rule=lambda _,i: b.clone())
     model.FirstStageCost = Expression(expr=0.0)
     model.SecondStageCost = Expression(expr=0.0)
     model.obj = Objective(expr=0.0)
     return model
Ejemplo n.º 36
0
def _process_bilinear_constraints(block, v1, v2, var_values, bilinear_constrs):
    # TODO check that the appropriate variable bounds exist.
    if not (v2.has_lb() and v2.has_ub()):
        logger.warning(textwrap.dedent("""\
            Attempting to transform bilinear term {v1} * {v2} using effectively
            discrete variable {v1}, but {v2} is missing a lower or upper bound:
            ({v2lb}, {v2ub}).
            """.format(v1=v1, v2=v2, v2lb=v2.lb, v2ub=v2.ub)).strip())
        return False
    blk = Block()
    unique_name = unique_component_name(
        block, ("%s_%s_bilinear" % (v1.local_name, v2.local_name))
        .replace('[', '').replace(']', ''))
    block._induced_linearity_info.add_component(unique_name, blk)
    # TODO think about not using floats as indices in a set
    blk.valid_values = Set(initialize=var_values)
    blk.x_active = Var(blk.valid_values, domain=Binary, initialize=1)
    blk.v_increment = Var(
        blk.valid_values, domain=v2.domain,
        bounds=(v2.lb, v2.ub), initialize=v2.value)
    blk.v_defn = Constraint(expr=v2 == summation(blk.v_increment))

    @blk.Constraint(blk.valid_values)
    def v_lb(blk, val):
        return v2.lb * blk.x_active[val] <= blk.v_increment[val]

    @blk.Constraint(blk.valid_values)
    def v_ub(blk, val):
        return blk.v_increment[val] <= v2.ub * blk.x_active[val]
    blk.select_one_value = Constraint(expr=summation(blk.x_active) == 1)
    # Categorize as case 1 or case 2
    for bilinear_constr in bilinear_constrs:
        # repn = generate_standard_repn(bilinear_constr.body)

        # Case 1: no other variables besides bilinear term in constraint. v1
        # (effectively discrete variable) is positive.
        # if (len(repn.quadratic_vars) == 1 and len(repn.linear_vars) == 0
        #         and repn.nonlinear_expr is None):
        #     _reformulate_case_1(v1, v2, discrete_constr, bilinear_constr)

        # NOTE: Case 1 is left unimplemented for now, because it involves some
        # messier logic with respect to how the transformation needs to happen.

        # Case 2: this is everything else, but do we want to have a special
        # case if there are nonlinear expressions involved with the constraint?
        pass
        _reformulate_case_2(blk, v1, v2, bilinear_constr)
    pass
Ejemplo n.º 37
0
def BuildPiecewiseND(xvars, zvar, tri, zvals):
    """
    Builds constraints defining a D-dimensional
    piecewise representation of the given triangulation.

    Args:
        xvars: A (D, 1) array of Pyomo variable objects
               representing the inputs of the piecewise
               function.
        zvar: A Pyomo variable object set equal to the
              output of the piecewise function.
        tri: A triangulation over the discretized
             variable domain. Required attributes:
           - points: An (npoints, D) shaped array listing the
                     D-dimensional coordinates of the
                     discretization points.
           - simplices: An (nsimplices, D+1) shaped array of
                        integers specifying the D+1 indices
                        of the points vector that define
                        each simplex of the triangulation.
        zvals: An (npoints, 1) shaped array listing the
               value of the piecewise function at each of
               coordinates in the triangulation points
               array.

    Returns:
        A Pyomo Block object containing variables and
        constraints that define the piecewise function.
    """

    b = Block(concrete=True)
    ndim = len(xvars)
    nsimplices = len(tri.simplices)
    npoints = len(tri.points)
    pointsT = list(zip(*tri.points))

    # create index objects
    b.dimensions =  RangeSet(0, ndim-1)
    b.simplices = RangeSet(0, nsimplices-1)
    b.vertices = RangeSet(0, npoints-1)

    # create variables
    b.lmda = Var(b.vertices, within=NonNegativeReals)
    b.y = Var(b.simplices, within=Binary)

    # create constraints
    def input_c_rule(b, d):
        pointsTd = pointsT[d]
        return xvars[d] == sum(pointsTd[v]*b.lmda[v]
                               for v in b.vertices)
    b.input_c = Constraint(b.dimensions, rule=input_c_rule)

    b.output_c = Constraint(expr=\
        zvar == sum(zvals[v]*b.lmda[v] for v in b.vertices))

    b.convex_c = Constraint(expr=\
        sum(b.lmda[v] for v in b.vertices) == 1)

    # generate a map from vertex index to simplex index,
    # which avoids an n^2 lookup when generating the
    # constraint
    vertex_to_simplex = [[] for v in b.vertices]
    for s, simplex in enumerate(tri.simplices):
        for v in simplex:
            vertex_to_simplex[v].append(s)
    def vertex_regions_rule(b, v):
        return b.lmda[v] <= \
            sum(b.y[s] for s in vertex_to_simplex[v])
    b.vertex_regions_c = \
        Constraint(b.vertices, rule=vertex_regions_rule)

    b.single_region_c = Constraint(expr=\
        sum(b.y[s] for s in b.simplices) == 1)

    return b
Ejemplo n.º 38
0
def _write_scenario_nl(worker,
                       scenario,
                       output_directory,
                       io_options):

    assert os.path.exists(output_directory)
    instance = scenario._instance
    assert not hasattr(instance, ".schuripopt")
    tmpblock = Block(concrete=True)
    instance.add_component(".schuripopt", tmpblock)

    #
    # linking variable suffix
    #
    bySymbol = instance._ScenarioTreeSymbolMap.bySymbol
    tmpblock.add_component(_variable_id_suffix_name,
                           Suffix(direction=Suffix.EXPORT,
                                  datatype=Suffix.INT))
    linking_suffix = getattr(tmpblock, _variable_id_suffix_name)

    # Loop over all nodes for the scenario except the leaf node,
    # which has no blended variables
    for node in scenario._node_list[:-1]:
        node_name = node.name
        for variable_id in node._standard_variable_ids:
            # Assumes ASL uses 4-byte, signed integers to store suffixes,
            # and we need positive suffix values
            linking_suffix[bySymbol[variable_id]] = \
                scenario_tree_id_to_pint32(node_name, variable_id)
    # make sure the conversion from scenario tree id to int
    # did not have any collisions
    _ids = list(linking_suffix.values())
    assert len(_ids) == len(set(_ids))

    #
    # objective weight suffix
    #
    tmpblock.add_component(_objective_weight_suffix_name,
                           Suffix(direction=Suffix.EXPORT))
    getattr(tmpblock, _objective_weight_suffix_name)[instance] = \
        scenario.probability

    # take care to disable any advanced preprocessing flags since we
    # are not going through the scenario tree manager solver interface
    # TODO: resolve this preprocessing mess
    block_attrs = []
    for block in instance.block_data_objects(active=True):
        attrs = []
        for attr_name in ("_gen_obj_repn",
                          "_gen_con_repn"):
            if hasattr(block, attr_name):
                attrs.append((attr_name, getattr(block, attr_name)))
                setattr(block, attr_name, True)
        if len(attrs):
            block_attrs.append((block, attrs))

    output_filename = os.path.join(output_directory,
                                   str(scenario.name)+".nl")

    # write the model and obtain the symbol_map
    _, smap_id = instance.write(
        output_filename,
        format=ProblemFormat.nl,
        io_options=io_options)
    symbol_map = instance.solutions.symbol_map[smap_id]

    # reset preprocessing flags
    # TODO: resolve this preprocessing mess
    for block, attrs in block_attrs:
        for attr_name, attr_val in attrs:
            setattr(block, attr_name, attr_val)

    instance.del_component(tmpblock)

    return output_filename, symbol_map
Ejemplo n.º 39
0
def _write_bundle_nl(worker,
                     bundle,
                     output_directory,
                     io_options):

    assert os.path.exists(output_directory)

    bundle_instance = worker._bundle_binding_instance_map[bundle.name]
    assert not hasattr(bundle_instance, ".schuripopt")
    tmpblock = Block(concrete=True)
    bundle_instance.add_component(".schuripopt", tmpblock)

    #
    # linking variable suffix
    #
    tmpblock.add_component(_variable_id_suffix_name,
                           Suffix(direction=Suffix.EXPORT,
                                  datatype=Suffix.INT))
    linking_suffix = getattr(tmpblock, _variable_id_suffix_name)

    # Loop over all nodes for the bundle except the leaf nodes,
    # which have no blended variables
    scenario_tree = worker.scenario_tree
    for stage in bundle.scenario_tree.stages[:-1]:
        for _node in stage.nodes:
            # get the node of off the real scenario tree
            # as this has the linked variable information
            node = scenario_tree.get_node(_node.name)
            node_name = node.name
            master_variable = bundle_instance.find_component(
                "MASTER_BLEND_VAR_"+str(node.name))
            for variable_id in node._standard_variable_ids:
                # Assumes ASL uses 4-byte, signed integers to store suffixes,
                # and we need positive suffix values
                linking_suffix[master_variable[variable_id]] = \
                    scenario_tree_id_to_pint32(node_name, variable_id)
    # make sure the conversion from scenario tree id to int
    # did not have any collisions
    _ids = list(linking_suffix.values())
    assert len(_ids) == len(set(_ids))

    #
    # objective weight suffix
    #
    tmpblock.add_component(_objective_weight_suffix_name,
                           Suffix(direction=Suffix.EXPORT))
    getattr(tmpblock, _objective_weight_suffix_name)[bundle_instance] = \
        bundle.probability

    # take care to disable any advanced preprocessing flags since we
    # are not going through the scenario tree manager solver interface
    # TODO: resolve this preprocessing mess
    block_attrs = []
    for block in bundle_instance.block_data_objects(active=True):
        attrs = []
        for attr_name in ("_gen_obj_repn",
                          "_gen_con_repn"):
            if hasattr(block, attr_name):
                attrs.append((attr_name, getattr(block, attr_name)))
                setattr(block, attr_name, True)
        if len(attrs):
            block_attrs.append((block, attrs))

    output_filename = os.path.join(output_directory,
                                   str(bundle.name)+".nl")
    # write the model and obtain the symbol_map
    _, smap_id = bundle_instance.write(
        output_filename,
        format=ProblemFormat.nl,
        io_options=io_options)
    symbol_map = bundle_instance.solutions.symbol_map[smap_id]

    # reset preprocessing flags
    # TODO: resolve this preprocessing mess
    for block, attrs in block_attrs:
        for attr_name, attr_val in attrs:
            setattr(block, attr_name, attr_val)

    bundle_instance.del_component(tmpblock)

    return output_filename, symbol_map
Ejemplo n.º 40
0
    def _apply_to(self, model, **kwds):
        """Apply the transformation to the given model."""
        config = self.CONFIG(kwds.pop('options', {}))
        config.set_value(kwds)

        integer_vars = list(
            v for v in model.component_data_objects(
                ctype=Var, descend_into=(Block, Disjunct))
            if v.is_integer() and not v.fixed)
        if len(integer_vars) == 0:
            logger.info("Model has no free integer variables. No reformulation needed.")
            return

        vars_on_constr = ComponentSet()
        for c in model.component_data_objects(
                ctype=Constraint, descend_into=(Block, Disjunct), active=True):
            vars_on_constr.update(v for v in identify_variables(c.body, include_fixed=False)
                                  if v.is_integer())

        if config.ignore_unused:
            num_vars_not_on_constr = len(integer_vars) - len(vars_on_constr)
            if num_vars_not_on_constr > 0:
                logger.info(
                    "%s integer variables on the model are not attached to any constraints. "
                    "Ignoring unused variables."
                )
            integer_vars = list(vars_on_constr)

        logger.info(
            "Reformulating integer variables using the %s strategy."
            % config.strategy)

        # Set up reformulation block
        blk_name = unique_component_name(model, "_int_to_binary_reform")
        reform_block = Block(
            doc="Holds variables and constraints for reformulating "
                "integer variables to binary variables."
        )
        setattr(model, blk_name, reform_block)

        reform_block.int_var_set = RangeSet(0, len(integer_vars) - 1)

        reform_block.new_binary_var = Var(
            Any, domain=Binary, dense=False,
            doc="Binary variable with index (int_var_idx, idx)")
        reform_block.integer_to_binary_constraint = Constraint(
            reform_block.int_var_set,
            doc="Equality constraints mapping the binary variable values "
                "to the integer variable value.")

        # check that variables are bounded and non-negative
        for idx, int_var in enumerate(integer_vars):
            if not (int_var.has_lb() and int_var.has_ub()):
                raise ValueError(
                    "Integer variable %s is missing an "
                    "upper or lower bound. LB: %s; UB: %s. "
                    "Integer to binary reformulation does not support unbounded integer variables."
                    % (int_var.name, int_var.lb, int_var.ub))
            if int_var.lb < 0:
                raise ValueError(
                    "Integer variable %s can be negative. "
                    "Integer to binary reformulation currently only supports non-negative integer "
                    "variables." % (int_var.name,)
                )
            # do the reformulation
            highest_power = int(floor(log(value(int_var.ub), 2)))
            # TODO potentially fragile due to floating point

            reform_block.integer_to_binary_constraint.add(
                idx, expr=int_var == sum(
                    reform_block.new_binary_var[idx, pwr] * (2 ** pwr)
                    for pwr in range(0, highest_power + 1)))

            # Relax the original integer variable
            int_var.domain = NonNegativeReals

        logger.info(
            "Reformulated %s integer variables using "
            "%s binary variables and %s constraints."
            % (len(integer_vars), len(reform_block.new_binary_var),
               len(reform_block.integer_to_binary_constraint)))
Ejemplo n.º 41
0
Archivo: admm.py Proyecto: Pyomo/pyomo
def EXTERNAL_initialize_for_admm(manager,
                                 scenario):
    if manager.get_option("verbose"):
        print("Initializing scenario %s for admm algorithm"
              % (scenario.name))
    admm_block = Block(concrete=True)
    assert not hasattr(scenario._instance, ".admm")
    scenario._instance.add_component(".admm", admm_block)

    # Augment the objective with lagrangian and penalty terms
    # and weight the original objective by the scenario probability.
    # The langrangian and penalty terms will be computed after
    # the parameters are created.
    user_cost_expression = scenario._instance_cost_expression
    admm_block.cost_expression = Expression(initialize=\
        scenario.probability * user_cost_expression)
    admm_block.lagrangian_expression = Expression(initialize=0.0)
    admm_block.penalty_expression = Expression(initialize=0.0)
    # these are used in the objective, they can be toggled
    # between the expression above or something else (e.g., 0.0)
    admm_block.cost_term = Expression(
        initialize=admm_block.cost_expression)
    admm_block.lagrangian_term = Expression(
        initialize=admm_block.lagrangian_expression)
    admm_block.penalty_term = Expression(
        initialize=admm_block.penalty_expression)
    objective_direction = 1
    if manager.objective_sense == maximize:
        objective_direction = -1
    scenario._instance_objective.expr = \
        admm_block.cost_term + \
        admm_block.lagrangian_term * objective_direction + \
        admm_block.penalty_term * objective_direction

    # add objective parameters to admm block
    for tree_node in scenario.node_list[:-1]:
        assert not tree_node.is_leaf_node()
        node_block = Block(concrete=True)
        admm_block.add_component(tree_node.name,
                                 node_block)
        node_block.node_index_set = Set(
            ordered=True,
            initialize=sorted(tree_node._standard_variable_ids))
        node_block.z = Param(node_block.node_index_set,
                             initialize=0.0,
                             mutable=True)
        node_block.y = Param(node_block.node_index_set,
                             initialize=0.0,
                             mutable=True)
        node_block.rho = Param(node_block.node_index_set,
                               initialize=0.0,
                               mutable=True)

        for id_ in node_block.node_index_set:
            varname, index = tree_node._variable_ids[id_]
            var = scenario._instance.find_component(varname)[index]
            admm_block.lagrangian_expression.expr += \
                node_block.y[id_] * (var - node_block.z[id_])
            admm_block.penalty_expression.expr += \
                (node_block.rho[id_] / 2.0) * (var - node_block.z[id_])**2

    # The objective has changed so flag this if necessary.
    if manager.preprocessor is not None:
        manager.preprocessor.objective_updated[scenario.name] = True
Ejemplo n.º 42
0
    def transformForTrustRegion(self,model,eflist):
        # transform and model into suitable form for TRF method
        #
        # Arguments:
        # model : pyomo model containing ExternalFunctions
        # eflist : a list of the external functions that will be
        #   handled with TRF method rather than calls to compiled code

        efSet = set([id(x) for x in eflist])

        TRF = Block()

        # Get all varibles
        seenVar = Set()
        allVariables = []
        for var in model.component_data_objects(Var):
            if id(var) not in seenVar:
                seenVar.add(id(var))
                allVariables.append(var)


        # This assumes that an external funtion call is present, required!
        model.add_component(unique_component_name(model,'tR'), TRF)
        TRF.y = VarList()
        TRF.x = VarList()
        TRF.conset = ConstraintList()
        TRF.external_fcns = []
        TRF.exfn_xvars = []

        # TODO: Copy constraints onto block so that transformation can be reversed.

        for con in model.component_data_objects(Constraint,active=True):
            con.set_value((con.lower, self.substituteEF(con.body,TRF,efSet), con.upper))
        for obj in model.component_data_objects(Objective,active=True):
            obj.set_value(self.substituteEF(obj.expr,TRF,efSet))
            ## Assume only one ative objective function here
            self.objective=obj

        if self.objective.sense == maximize:
            self.objective.expr = -1* self.objective.expr
            self.objective.sense = minimize



        # xvars and zvars are lists of x and z varibles as in the paper
        TRF.xvars = []
        TRF.zvars = []
        seenVar = Set()
        for varss in TRF.exfn_xvars:
            for var in varss:
                if id(var) not in seenVar:
                    seenVar.add(id(var))
                    TRF.xvars.append(var)

        for var in allVariables:
            if id(var) not in seenVar:
                seenVar.add(id(var))
                TRF.zvars.append(var)

        # TODO: build dict for exfn_xvars
        # assume it is not bottleneck of the code
        self.exfn_xvars_ind = []
        for varss in TRF.exfn_xvars:
            listtmp = []
            for var in varss:
                for i in range(len(TRF.xvars)):
                    if(id(var)==id(TRF.xvars[i])):
                        listtmp.append(i)
                        break

            self.exfn_xvars_ind.append(listtmp)

        return TRF
Ejemplo n.º 43
0
Archivo: bigm.py Proyecto: Pyomo/pyomo
    def _apply_to(self, instance, **kwds):
        config = self.CONFIG(kwds.pop('options', {}))

        # We will let args override suffixes and estimate as a last
        # resort. More specific args/suffixes override ones anywhere in
        # the tree. Suffixes lower down in the tree override ones higher
        # up.
        if 'default_bigM' in kwds:
            logger.warn("DEPRECATED: the 'default_bigM=' argument has been "
                        "replaced by 'bigM='")
            config.bigM = kwds.pop('default_bigM')

        config.set_value(kwds)
        bigM = config.bigM

        # make a transformation block to put transformed disjuncts on
        transBlockName = unique_component_name(
            instance,
            '_pyomo_gdp_bigm_relaxation')
        transBlock = Block()
        instance.add_component(transBlockName, transBlock)
        transBlock.relaxedDisjuncts = Block(Any)
        transBlock.lbub = Set(initialize=['lb', 'ub'])
        # this is a dictionary for keeping track of IndexedDisjuncts
        # and IndexedDisjunctions so that, at the end of the
        # transformation, we can check that the ones with no active
        # DisjstuffDatas are deactivated.
        transBlock.disjContainers = ComponentSet()

        targets = config.targets
        if targets is None:
            targets = (instance, )
            _HACK_transform_whole_instance = True
        else:
            _HACK_transform_whole_instance = False
        for _t in targets:
            t = _t.find_component(instance)
            if t is None:
                raise GDP_Error(
                    "Target %s is not a component on the instance!" % _t)

            if t.type() is Disjunction:
                if t.parent_component() is t:
                    self._transformDisjunction(t, transBlock, bigM)
                else:
                    self._transformDisjunctionData(
                        t, transBlock, bigM, t.index())
            elif t.type() in (Block, Disjunct):
                if t.parent_component() is t:
                    self._transformBlock(t, transBlock, bigM)
                else:
                    self._transformBlockData(t, transBlock, bigM)
            else:
                raise GDP_Error(
                    "Target %s was not a Block, Disjunct, or Disjunction. "
                    "It was of type %s and can't be transformed."
                    % (t.name, type(t)))
        # Go through our dictionary of indexed things and deactivate
        # the containers that don't have any active guys inside of
        # them. So the invalid component logic will tell us if we
        # missed something getting transformed.
        for obj in transBlock.disjContainers:
            if not obj.active:
                continue
            for i in obj:
                if obj[i].active:
                    break
            else:
                # HACK due to active flag implementation.
                #
                # Ideally we would not have to do any of this (an
                # ActiveIndexedComponent would get its active status by
                # querring the active status of all the contained Data
                # objects).  As a fallback, we would like to call:
                #
                #    obj._deactivate_without_fixing_indicator()
                #
                # However, the sreaightforward implementation of that
                # method would have unintended side effects (fixing the
                # contained _DisjunctData's indicator_vars!) due to our
                # class hierarchy.  Instead, we will directly call the
                # relevant base class (safe-ish since we are verifying
                # that all the contained _DisjunctionData are
                # deactivated directly above).
                ActiveComponent.deactivate(obj)

        # HACK for backwards compatibility with the older GDP transformations
        #
        # Until the writers are updated to find variables on things
        # other than active blocks, we need to reclassify the Disjuncts
        # as Blocks after transformation so that the writer will pick up
        # all the variables that it needs (in this case, indicator_vars).
        if _HACK_transform_whole_instance:
            HACK_GDP_Disjunct_Reclassifier().apply_to(instance)
Ejemplo n.º 44
0
def apply_basic_step(disjunctions_or_constraints):
    #
    # Basic steps only apply to XOR'd disjunctions
    #
    disjunctions = list(obj for obj in disjunctions_or_constraints
                        if obj.type() == Disjunction)
    constraints = list(obj for obj in disjunctions_or_constraints
                       if obj.type() == Constraint)
    for d in disjunctions:
        if not d.xor:
            raise ValueError(
                "Basic steps can only be applied to XOR'd disjunctions\n\t"
                "(raised by disjunction %s)" % (d.name,))
        if not d.active:
            logger.warning("Warning: applying basic step to a previously "
                           "deactivated disjunction (%s)" % (d.name,))

    ans = Block(concrete=True)
    ans.DISJUNCTIONS = Set(initialize=xrange(len(disjunctions)))
    ans.INDEX = Set(
        dimen=len(disjunctions),
        initialize=_squish_singletons(itertools.product(
            *tuple( xrange(len(d.disjuncts)) for d in disjunctions ))))

    #
    # Form the individual disjuncts for the new basic step
    #
    ans.disjuncts = Disjunct(ans.INDEX)
    for idx in ans.INDEX:
        #
        # Each source disjunct will be copied (cloned) into its own
        # subblock
        #
        ans.disjuncts[idx].src = Block(ans.DISJUNCTIONS)
        for i in ans.DISJUNCTIONS:
            tmp = _pseudo_clone(disjunctions[i].disjuncts[
                idx[i] if isinstance(idx, tuple) else idx])
            for k,v in list(iteritems( tmp.component_map() )):
                if k == 'indicator_var':
                    continue
                tmp.del_component(k)
                ans.disjuncts[idx].src[i].add_component(k,v)
        # Copy in the constraints corresponding to the improper disjunctions
        ans.disjuncts[idx].improper_constraints = ConstraintList()
        for constr in constraints:
            for indx in constr:
                ans.disjuncts[idx].improper_constraints.add(
                    (constr[indx].lower, constr[indx].body, constr[indx].upper)
                )
                constr[indx].deactivate()

    #
    # Link the new disjunct indicator_var's to the original
    # indicator_var's.  Since only one of the new
    #
    ans.indicator_links = ConstraintList()
    for i in ans.DISJUNCTIONS:
        for j in xrange(len(disjunctions[i].disjuncts)):
            ans.indicator_links.add(
                disjunctions[i].disjuncts[j].indicator_var ==
                sum( ans.disjuncts[idx].indicator_var for idx in ans.INDEX
                     if (idx[i] if isinstance(idx, tuple) else idx) == j ))

    # Form the new disjunction
    ans.disjunction = Disjunction(expr=[ans.disjuncts[i] for i in ans.INDEX])

    #
    # Deactivate the old disjunctions / disjuncts
    #
    for i in ans.DISJUNCTIONS:
        disjunctions[i].deactivate()
        for d in disjunctions[i].disjuncts:
            d._deactivate_without_fixing_indicator()

    return ans