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=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
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 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