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
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.index = Set( ordered=True, initialize=sorted(tree_node._standard_variable_ids)) node_block.z = Param(node_block.index, initialize=0.0, mutable=True) node_block.y = Param(node_block.index, initialize=0.0, mutable=True) node_block.rho = Param(node_block.index, initialize=0.0, mutable=True) for id_ in node_block.index: 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
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) # create a component map to keep track of id() for the # original object and the referenced object block._map = ComponentMap() # get the objective for the master problem for c in instance.component_objects(Objective, descend_into=False): ref = Reference(c) block.add_component(c.name, ref) block._map[c] = ref[None] # 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): if c.is_indexed(): ref = Reference(c[...]) block.add_component(c.name, ref) block._map[c] = ref else: ref = Reference(c) block.add_component(c.name, ref) block._map[c] = ref[None] # get the constraints from the main model for c in instance.component_objects(Constraint, sort=True, descend_into=True, active=True): if c.is_indexed(): ref = Reference(c[...]) block.add_component(c.name, ref) block._map[c] = ref else: ref = Reference(c) block.add_component(c.name, ref) block._map[c] = ref[None] # deactivate the highpoint relaxation # block.deactivate() return block
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)
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)
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
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.ctype == Disjunction) constraints = list(obj for obj in disjunctions_or_constraints if obj.ctype == 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=range(len(disjunctions))) ans.INDEX = Set(dimen=len(disjunctions), initialize=_squish_singletons( itertools.product(*tuple( range(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 = _clone_all_but_indicator_vars( disjunctions[i].disjuncts[idx[i] if isinstance(idx, tuple ) else idx]) for k, v in list(tmp.component_map().items()): if v.parent_block() is not tmp: # Skip indicator_var and binary_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: if constr.is_indexed(): for indx in constr: ans.disjuncts[idx].improper_constraints.add( (constr[indx].lower, constr[indx].body, constr[indx].upper)) constr[indx].deactivate() # need this so that we can take an improper basic step with a # ConstraintData else: ans.disjuncts[idx].improper_constraints.add( (constr.lower, constr.body, constr.upper)) constr.deactivate() # # Link the new disjunct indicator_var's to the original # indicator_var's. Since only one of the new # NAME_BUFFER = {} ans.indicator_links = ConstraintList() for i in ans.DISJUNCTIONS: for j in range(len(disjunctions[i].disjuncts)): orig_var = disjunctions[i].disjuncts[j].indicator_var orig_binary_var = orig_var.get_associated_binary() ans.indicator_links.add(orig_binary_var == sum( ans.disjuncts[idx].binary_indicator_var for idx in ans.INDEX if (idx[i] if isinstance(idx, tuple) else idx) == j)) # and throw on a Reference to original on the block for v in (orig_var, orig_binary_var): name_base = v.getname(fully_qualified=True, name_buffer=NAME_BUFFER) ans.add_component(unique_component_name(ans, name_base), Reference(v)) # 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
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_ampl_repn", "_gen_con_ampl_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
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_ampl_repn", "_gen_con_ampl_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
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
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