def read_sol(model, sol_filename, symbol_map_filename, suffixes=[".*"]): """ Reads the solution from the SOL file and generates a results object with an appropriate symbol map for loading it into the given Pyomo model. By default all suffixes found in the NL file will be extracted. This can be overridden using the suffixes keyword, which should be a list of suffix names or regular expressions (or None). """ if suffixes is None: suffixes = [] # parse the SOL file with ReaderFactory(ResultsFormat.sol) as reader: results = reader(sol_filename, suffixes=suffixes) # regenerate the symbol_map for this model with open(symbol_map_filename, "rb") as f: symbol_cuid_pairs = pickle.load(f) symbol_map = SymbolMap() symbol_map.addSymbols((cuid.find_component(model), symbol) for symbol, cuid in symbol_cuid_pairs) # tag the results object with the symbol_map results._smap = symbol_map return results
def __init__(self, model=None, logger=None): self.variable_label_map = SymbolMap(NumericLabeler('x')) self.prefix_expr_list = self._get_default_functions() self.variable_list = [] self.bounds_list = [] self.expression_list = [] self.disjunctions_list = [] self.walker = SMT_visitor(self.variable_label_map) self.solver = z3.Solver() self.logger = logger if model is not None: self._process_model(model)
class SMTSatSolver(object): """ Satisfiability solver that checks constraint feasibility through use of z3 Sat Solver. Object stores expressions and variables in form consistent with SMT-LIB standard. For documentation on SMT-LIB standard see http://smtlib.cs.uiowa.edu/ """ def __str__(self): """ Defined string representation of object """ string = "" string = string + "Variables:\n" for v in self.variable_list: string = string + v string = string + "Bounds:\n" for e in self.bounds_list: string = string + e string = string + "Expressions:\n" for e in self.expression_list: string = string + e string = string + "Disjunctions:\n" for djn in self.disjunctions_list: string = string + "Disjunction: " + djn[0] + "\n" for disj in djn[1]: string = string + " " + disj[0] + " : " + "\n" for c in disj[1]: string = string + " " + c + "\n" return string def __init__(self, model=None, logger=None): self.variable_label_map = SymbolMap(NumericLabeler('x')) self.prefix_expr_list = self._get_default_functions() self.variable_list = [] self.bounds_list = [] self.expression_list = [] self.disjunctions_list = [] self.walker = SMT_visitor(self.variable_label_map) self.solver = z3.Solver() self.logger = logger if model is not None: self._process_model(model) # Set up functions to be added to beginning of string def _get_default_functions(self): default = list() default.append("(define-fun exp ((x Real)) Real (^ %0.15f x))" % (math.exp(1),)) return default # processes pyomo model into SMT model def _process_model(self, model): for v in model.component_data_objects(ctype=Var, descend_into=True): smtstring = self.add_var(v) for c in model.component_data_objects(ctype=Constraint, active=True): self.add_expr(c.expr) for djn in model.component_data_objects(ctype=Disjunction): if djn.active: self._process_active_disjunction(djn) else: self._process_inactive_disjunction(djn) # define bound constraints def _add_bound(self, var): nm = self.variable_label_map.getSymbol(var) lb = var.lb ub = var.ub if lb is not None: self.bounds_list.append("(assert (>= " + nm + " " + str(lb) + "))\n") if ub is not None: self.bounds_list.append("(assert (<= " + nm + " " + str(ub) + "))\n") # define variables def add_var(self, var): label = self.variable_label_map.getSymbol(var) domain = var.domain if isinstance(domain, RealSet): self.variable_list.append("(declare-fun " + label + "() Real)\n") self._add_bound(var) elif isinstance(domain, IntegerSet): self.variable_list.append("(declare-fun " + label + "() Int)\n") self._add_bound(var) elif isinstance(domain, BooleanSet): self.variable_list.append("(declare-fun " + label + "() Int)\n") self._add_bound(var) else: raise NotImplementedError("SMT cannot handle" + str(domain) + "variables") return label # Defines SMT expression from pyomo expression def add_expr(self, expression): try: smtexpr = self.walker.walk_expression(expression) self.expression_list.append("(assert " + smtexpr + ")\n") except NotImplementedError as e: if self.logger is not None: self.logger.warning("Skipping Expression: " + str(e)) # Computes the SMT Model for the disjunction from the internal class storage def _compute_disjunction_string(self, smt_djn): djn_string = smt_djn[0] for disj in smt_djn[1]: cons_string = "true" for c in disj[1]: cons_string = "(and " + cons_string + " " + c + ")" djn_string = djn_string + "(assert (=> ( = 1 " + disj[0] + ") " + cons_string + "))\n" return djn_string # converts disjunction to internal class storage def _process_active_disjunction(self, djn): or_expr = "0" disjuncts = [] for disj in djn.disjuncts: constraints = [] iv = disj.indicator_var label = self.add_var(iv) or_expr = "(+ " + or_expr + " " + label + ")" for c in disj.component_data_objects(ctype=Constraint, active=True): try: constraints.append(self.walker.walk_expression(c.expr)) except NotImplementedError as e: if self.logger is not None: self.logger.warning("Skipping Disjunct Expression: " + str(e)) disjuncts.append((label, constraints)) if djn.xor: or_expr = "(assert (= 1 " + or_expr + "))\n" else: or_expr = "(assert (>= 1 " + or_expr + "))\n" self.disjunctions_list.append((or_expr, disjuncts)) # processes inactive disjunction indicator vars without constraints def _process_inactive_disjunction(self, djn): or_expr = "0" for disj in djn.disjuncts: iv = disj.indicator_var label = self.add_var(iv) or_expr = "(+ " + or_expr + " " + label + ")" if djn.xor: or_expr = "(assert (= 1 " + or_expr + "))\n" else: or_expr = "(assert (>= 1 " + or_expr + "))\n" self.expression_list.append(or_expr) def get_SMT_string(self): prefix_string = ''.join(self.prefix_expr_list) variable_string = ''.join(self.variable_list) bounds_string = ''.join(self.bounds_list) expression_string = ''.join(self.expression_list) disjunctions_string = ''.join([self._compute_disjunction_string(d) for d in self.disjunctions_list]) smtstring = prefix_string + variable_string + bounds_string + expression_string + disjunctions_string return smtstring def get_var_dict(self): labels = [x for x in self.variable_label_map.bySymbol] labels.sort() vars = [self.variable_label_map.getObject(l) for l in labels] return zip(labels, vars) # Checks Satisfiability of model def check(self): self.solver.append(z3.parse_smt2_string(self.get_SMT_string())) return self.solver.check()
class SMTSatSolver(object): """ Satisfiability solver that checks constraint feasibility through use of z3 Sat Solver. Object stores expressions and variables in form consistent with SMT-LIB standard. For documentation on SMT-LIB standard see http://smtlib.cs.uiowa.edu/ """ def __str__(self): """ Defined string representation of object """ string = "" string = string + "Variables:\n" for v in self.variable_list: string = string + v string = string + "Bounds:\n" for e in self.bounds_list: string = string + e string = string + "Expressions:\n" for e in self.expression_list: string = string + e string = string + "Disjunctions:\n" for djn in self.disjunctions_list: string = string + "Disjunction: " + djn[0] + "\n" for disj in djn[1]: string = string + " " + disj[0] + " : " + "\n" for c in disj[1]: string = string + " " + c + "\n" return string def __init__(self, model=None, logger=None): self.variable_label_map = SymbolMap(NumericLabeler('x')) self.prefix_expr_list = self._get_default_functions() self.variable_list = [] self.bounds_list = [] self.expression_list = [] self.disjunctions_list = [] self.walker = SMT_visitor(self.variable_label_map) self.solver = z3.Solver() self.logger = logger if model is not None: self._process_model(model) # Set up functions to be added to beginning of string def _get_default_functions(self): default = list() default.append("(define-fun exp ((x Real)) Real (^ %0.15f x))" % (math.exp(1), )) return default # processes pyomo model into SMT model def _process_model(self, model): for v in model.component_data_objects(ctype=Var, descend_into=True): smtstring = self.add_var(v) for c in model.component_data_objects(ctype=Constraint, active=True): self.add_expr(c.expr) for djn in model.component_data_objects(ctype=Disjunction): if djn.active: self._process_active_disjunction(djn) else: self._process_inactive_disjunction(djn) # define bound constraints def _add_bound(self, var): nm = self.variable_label_map.getSymbol(var) lb = var.lb ub = var.ub if lb is not None: self.bounds_list.append("(assert (>= " + nm + " " + str(lb) + "))\n") if ub is not None: self.bounds_list.append("(assert (<= " + nm + " " + str(ub) + "))\n") # define variables def add_var(self, var): label = self.variable_label_map.getSymbol(var) domain = var.domain if var.is_continuous(): self.variable_list.append("(declare-fun " + label + "() Real)\n") self._add_bound(var) elif var.is_binary(): self.variable_list.append("(declare-fun " + label + "() Int)\n") self._add_bound(var) elif var.is_integer(): self.variable_list.append("(declare-fun " + label + "() Int)\n") self._add_bound(var) else: raise NotImplementedError("SMT cannot handle " + str(domain) + " variables") return label # Defines SMT expression from pyomo expression def add_expr(self, expression): try: smtexpr = self.walker.walk_expression(expression) self.expression_list.append("(assert " + smtexpr + ")\n") except NotImplementedError as e: if self.logger is not None: self.logger.warning("Skipping Expression: " + str(e)) # Computes the SMT Model for the disjunction from the internal class storage def _compute_disjunction_string(self, smt_djn): djn_string = smt_djn[0] for disj in smt_djn[1]: cons_string = "true" for c in disj[1]: cons_string = "(and " + cons_string + " " + c + ")" djn_string = djn_string + "(assert (=> ( = 1 " + disj[ 0] + ") " + cons_string + "))\n" return djn_string # converts disjunction to internal class storage def _process_active_disjunction(self, djn): or_expr = "0" disjuncts = [] for disj in djn.disjuncts: constraints = [] iv = disj.indicator_var label = self.add_var(iv) or_expr = "(+ " + or_expr + " " + label + ")" for c in disj.component_data_objects(ctype=Constraint, active=True): try: constraints.append(self.walker.walk_expression(c.expr)) except NotImplementedError as e: if self.logger is not None: self.logger.warning("Skipping Disjunct Expression: " + str(e)) disjuncts.append((label, constraints)) if djn.xor: or_expr = "(assert (= 1 " + or_expr + "))\n" else: or_expr = "(assert (>= 1 " + or_expr + "))\n" self.disjunctions_list.append((or_expr, disjuncts)) # processes inactive disjunction indicator vars without constraints def _process_inactive_disjunction(self, djn): or_expr = "0" for disj in djn.disjuncts: iv = disj.indicator_var label = self.add_var(iv) or_expr = "(+ " + or_expr + " " + label + ")" if djn.xor: or_expr = "(assert (= 1 " + or_expr + "))\n" else: or_expr = "(assert (>= 1 " + or_expr + "))\n" self.expression_list.append(or_expr) def get_SMT_string(self): prefix_string = ''.join(self.prefix_expr_list) variable_string = ''.join(self.variable_list) bounds_string = ''.join(self.bounds_list) expression_string = ''.join(self.expression_list) disjunctions_string = ''.join([ self._compute_disjunction_string(d) for d in self.disjunctions_list ]) smtstring = prefix_string + variable_string + bounds_string + expression_string + disjunctions_string return smtstring def get_var_dict(self): labels = [x for x in self.variable_label_map.bySymbol] labels.sort() vars = [self.variable_label_map.getObject(l) for l in labels] return zip(labels, vars) # Checks Satisfiability of model def check(self): self.solver.append(z3.parse_smt2_string(self.get_SMT_string())) return self.solver.check()