def calculate_accuracy(domain, target_formula, learned_formula): # from sys import path # path.insert(0, "/Users/samuelkolb/Documents/PhD/wmi-pa/experiments/client") # from run import compute_wmi print("Calculate accuracy:") # print(pretty_print(target_formula)) # print(pretty_print(learned_formula)) # r0, r1 = [smt.Symbol(n, smt.REAL) for n in ["r0", "r1"]] # b0, b1, b2, b3 = [smt.Symbol(n, smt.BOOL) for n in ["b0", "b1", "b2", "b3"]] # t1 = (~(1.0 <= 0.427230115861 * r0 + 1.02084935803 * r1) | ~(1.0 <= 1.59402729715 * r0 + 0.309004054118 * r1) | ~b1) # t2 = (b2 | (1.0 <= 1.59402729715 * r0 + 0.309004054118 * r1) | ~b0) # domain = problem.Domain(["x", "y"], {"x": smt.REAL, "y": smt.REAL}, {"x": (0, 1), "y": (0, 1)}) # x, y = smt.Symbol("x", smt.REAL), smt.Symbol("y", smt.REAL) # t2 = (1.0 <= 1.5 * x + 0.5 * y) # t2 = (2 <= 3 * x + y) # f = (t1 & t2) flat = { "domain": problem.export_domain(domain, False), "query": parse.smt_to_nested(smt.Iff(target_formula, learned_formula)) } print(domain) print(pretty_print(target_formula)) print(pretty_print(learned_formula)) # accuracy = list(compute_wmi(domain, [smt.Iff(target_formula, learned_formula)]))[0] output = str(subprocess.check_output(["/Users/samuelkolb/Documents/PhD/wmi-pa/env/bin/python", "/Users/samuelkolb/Documents/PhD/wmi-pa/experiments/client/run.py", "-s", json.dumps(flat)])) accuracy = float(output.split(": ")[1]) print(accuracy) return accuracy
def test_xadd_iff_real(): domain = Domain.make([], ["x", "y"], real_bounds=(-1, 1)) x, y = domain.get_symbols() c = 0.00000001 f1 = (x * c > 0) & (x * c <= y * c) & (y * c < c) f2 = normalize_formula(f1) xadd_vol1 = XaddEngine(domain, (f1 | f2) & (~f1 | ~f2), smt.Real(1.0)).compute_volume() xadd_vol2 = XaddEngine(domain, smt.Iff(f1, ~f2), smt.Real(1.0)).compute_volume() xadd_vol3 = XaddEngine(domain, ~smt.Iff(f1, f2), smt.Real(1.0)).compute_volume() assert xadd_vol1 == pytest.approx(0, EXACT_REL_ERROR) assert xadd_vol2 == pytest.approx(0, EXACT_REL_ERROR) assert xadd_vol3 == pytest.approx(0, EXACT_REL_ERROR)
def test_rejection_iff_real(): domain = Domain.make([], ["x", "y"], real_bounds=(-1, 1)) x, y = domain.get_symbols() c = 0.00000001 f1 = (x * c > 0) & (x * c <= y * c) & (y * c < c) f2 = normalize_formula(f1) rej_vol1 = RejectionEngine(domain, (f1 | f2) & (~f1 | ~f2), smt.Real(1.0), 100000).compute_volume() rej_vol2 = RejectionEngine(domain, smt.Iff(f1, ~f2), smt.Real(1.0), 100000).compute_volume() rej_vol3 = RejectionEngine(domain, ~smt.Iff(f1, f2), smt.Real(1.0), 100000).compute_volume() assert rej_vol1 == pytest.approx(0, REL_ERROR**3) assert rej_vol2 == pytest.approx(0, REL_ERROR**3) assert rej_vol3 == pytest.approx(0, REL_ERROR**3)
def generate_click_graph(n): def t(c): return smt.Ite(c, one, zero) sim_n, cl_n, b_n, sim_x_n, b_x_n = "sim", "cl", "b", "sim_x", "b_x" domain = Domain.make( # Boolean ["{}_{}".format(sim_n, i) for i in range(n)] + ["{}_{}_{}".format(cl_n, i, j) for i in range(n) for j in (0, 1)] + ["{}_{}_{}".format(b_n, i, j) for i in range(n) for j in (0, 1)], # Real ["{}".format(sim_x_n)] + ["{}_{}_{}".format(b_x_n, i, j) for i in range(n) for j in (0, 1)], real_bounds=(0, 1)) sim = [domain.get_symbol("{}_{}".format(sim_n, i)) for i in range(n)] cl = [[domain.get_symbol("{}_{}_{}".format(cl_n, i, j)) for j in (0, 1)] for i in range(n)] b = [[domain.get_symbol("{}_{}_{}".format(b_n, i, j)) for j in (0, 1)] for i in range(n)] sim_x = domain.get_symbol("{}".format(sim_x_n)) b_x = [[domain.get_symbol("{}_{}_{}".format(b_x_n, i, j)) for j in (0, 1)] for i in range(n)] support = smt.And([ smt.Iff(cl[i][0], b[i][0]) & smt.Iff(cl[i][1], (sim[i] & b[i][0]) | (~sim[i] & b[i][1])) for i in range(n) ]) one = smt.Real(1) zero = smt.Real(0) w_sim_x = t(sim_x >= 0) * t(sim_x <= 1) w_sim = [smt.Ite(s_i, sim_x, 1 - sim_x) for s_i in sim] w_b_x = [ t(b_x[i][j] >= 0) * t(b_x[i][j] <= 1) for i in range(n) for j in (0, 1) ] w_b = [ smt.Ite(b[i][j], b_x[i][j], 1 - b_x[i][j]) for i in range(n) for j in (0, 1) ] weight = smt.Times(*([w_sim_x] + w_sim + w_b_x + w_b)) return Density(domain, support, weight)
def test_rejection_iff_bool(): domain = Domain.make(["a", "b"]) a, b = domain.get_symbols() print(domain) vol_t = RejectionEngine(domain, smt.TRUE(), smt.Real(1.0), 100000).compute_volume() vol1 = RejectionEngine(domain, (a | b) & (~a | ~b), smt.Real(1.0), 100000).compute_volume() vol2 = RejectionEngine(domain, smt.Iff(a, ~b), smt.Real(1.0), 100000).compute_volume() vol3 = RejectionEngine(domain, ~smt.Iff(a, b), smt.Real(1.0), 100000).compute_volume() print(vol1, vol2, vol3, vol_t) # print(PredicateAbstractionEngine(domain, a | b, smt.Real(1.0)).compute_volume()) print(XaddEngine(domain, a | b, smt.Real(1.0)).compute_volume()) quit()
def test_pa_iff_real(): pytest.skip("Bug fix requires changing PA solver") domain = Domain.make([], ["x", "y"], real_bounds=(-1, 1)) x, y = domain.get_symbols() c = 0.00000001 f1 = (x * c >= 0) & (x * c <= y * c) & (y * c < c) f2 = normalize_formula(f1) print(smt_to_nested(f2)) pa_vol1 = PredicateAbstractionEngine( domain, domain.get_bounds() & (f1 | f2) & (~f1 | ~f2), smt.Real(1.0)).compute_volume() smt.write_smtlib(domain.get_bounds() & (f1 | f2) & (~f1 | ~f2), "test_pa_iff_real.support") smt.write_smtlib(smt.Real(1.0), "test_pa_iff_real.weight") pa_vol2 = PredicateAbstractionEngine(domain, smt.Iff(f1, ~f2), smt.Real(1.0)).compute_volume() pa_vol3 = PredicateAbstractionEngine(domain, ~smt.Iff(f1, f2), smt.Real(1.0)).compute_volume() assert pa_vol1 == pytest.approx(0, REL_ERROR**3) assert pa_vol2 == pytest.approx(0, REL_ERROR**3) assert pa_vol3 == pytest.approx(0, REL_ERROR**3)
def test_convert_support(): x, y = smt.Symbol("x", smt.REAL), smt.Symbol("y", smt.REAL) a = smt.Symbol("a", smt.BOOL) formula = (x < 0) | (~a & (x < -1)) | smt.Ite(a, x < 4, x < 8) # Convert formula into abstracted one (replacing inequalities) env, repl_formula, literal_info = extract_and_replace_literals(formula) result = compile_to_sdd(formula=repl_formula, literals=literal_info, vtree=None) recovered = recover_formula(sdd_node=result, literals=literal_info, env=env) # print(pretty_print(recovered)) with smt.Solver() as solver: solver.add_assertion(~smt.Iff(formula, recovered)) # print(pretty_print(formula)) # print(pretty_print(recovered)) assert not solver.solve( ), f"Expected UNSAT but found model {solver.get_model()}"
def accuracy_approx(experiment): key = "accuracy_approx:{}".format(experiment.imported_from_file) if Properties.db.exists(key): return Properties.db.get(key) else: pysmt.environment.push_env() pysmt.environment.get_env().enable_infix_notation = True if os.path.basename(experiment.imported_from_file).startswith("synthetic"): db = Properties.get_db_synthetic(experiment) name = Properties.to_synthetic_name(experiment.imported_from_file) entry = db.get(name) domain = import_domain(json.loads(entry["domain"])) true_formula = nested_to_smt(entry["formula"]) else: density = Density.import_from(experiment.parameters.original_values["domain"]) domain = Domain(density.domain.variables, density.domain.var_types, Properties.get_bound(experiment)) true_formula = density.support learned_formula = nested_to_smt(experiment.results.formula) engine = RejectionEngine(domain, smt.TRUE(), smt.Real(1.0), 100000) accuracy = engine.compute_probability(smt.Iff(true_formula, learned_formula)) pysmt.environment.pop_env() print(accuracy) Properties.db.set(key, accuracy) return accuracy
def find_cnf(data, domain, active_indices, solver, n_c, n_h): # Constants n_b_original = len(domain.bool_vars) n_b = n_b_original * 2 n_r = len(domain.real_vars) n_d = len(data) real_features = [[row[v] for v in domain.real_vars] for row, _ in data] bool_features = [[row[v] for v in domain.bool_vars] for row, _ in data] labels = [row[1] for row in data] # Variables a_hr = [[ smt.Symbol("a_hr[{}][{}]".format(h, r), REAL) for r in range(n_r) ] for h in range(n_h)] b_h = [smt.Symbol("b_h[{}]".format(h), REAL) for h in range(n_h)] s_ch = [[smt.Symbol("s_ch[{}][{}]".format(c, h)) for h in range(n_h)] for c in range(n_c)] s_cb = [[smt.Symbol("s_cb[{}][{}]".format(c, b)) for b in range(n_b)] for c in range(n_c)] # Aux variables s_ih = [[smt.Symbol("s_ih[{}][{}]".format(i, h)) for h in range(n_h)] for i in range(n_d)] s_ic = [[smt.Symbol("s_ic[{}][{}]".format(i, c)) for c in range(n_c)] for i in range(n_d)] # Constraints for i in active_indices: x_r, x_b, label = real_features[i], bool_features[i], labels[i] for h in range(n_h): sum_coefficients = smt.Plus( [a_hr[h][r] * smt.Real(x_r[r]) for r in range(n_r)]) if label: solver.add_assertion( smt.Iff(s_ih[i][h], sum_coefficients + DELTA <= b_h[h])) else: solver.add_assertion( smt.Iff(s_ih[i][h], sum_coefficients - DELTA <= b_h[h])) for c in range(n_c): solver.add_assertion( smt.Iff( s_ic[i][c], smt.Or([smt.FALSE()] + [(s_ch[c][h] & s_ih[i][h]) for h in range(n_h)] + [s_cb[c][b] for b in range(n_b_original) if x_b[b]] + [ s_cb[c][b] for b in range(n_b_original, n_b) if not x_b[b - n_b_original] ]))) if label: solver.add_assertion(smt.And([s_ic[i][c] for c in range(n_c)])) else: solver.add_assertion(smt.Or([~s_ic[i][c] for c in range(n_c)])) if not solver.solve(): return None model = solver.get_model() x_vars = [domain.get_symbol(domain.real_vars[r]) for r in range(n_r)] half_spaces = [ smt.Plus([model.get_value(a_hr[h][r]) * x_vars[r] for r in range(n_r)]) <= model.get_value(b_h[h]) for h in range(n_h) ] b_vars = [ domain.get_symbol(domain.bool_vars[b]) for b in range(n_b_original) ] bool_literals = [b_vars[b] for b in range(n_b_original)] bool_literals += [~b_vars[b] for b in range(n_b - n_b_original)] conjunctions = [ [half_spaces[h] for h in range(n_h) if model.get_py_value(s_ch[c][h])] + [ bool_literals[b] for b in range(n_b) if model.get_py_value(s_cb[c][b]) ] for c in range(n_c) ] return smt.And([smt.Or(conjunction) for conjunction in conjunctions])
def learn_partial(self, solver, domain, data, new_active_indices): # Constants n_b_original = len(domain.bool_vars) n_b = n_b_original * 2 n_r = len(domain.real_vars) n_h_original = self.half_space_count if n_r > 0 else 0 n_h = n_h_original * 2 if self.allow_negations else n_h_original n_c = self.conjunction_count n_d = len(data) real_features = [[row[v] for v in domain.real_vars] for row, _ in data] bool_features = [[row[v] for v in domain.bool_vars] for row, _ in data] labels = [row[1] for row in data] # Variables a_hr = [[ smt.Symbol("a_hr[{}][{}]".format(h, r), REAL) for r in range(n_r) ] for h in range(n_h_original)] b_h = [ smt.Symbol("b_h[{}]".format(h), REAL) for h in range(n_h_original) ] s_ch = [[smt.Symbol("s_ch[{}][{}]".format(c, h)) for h in range(n_h)] for c in range(n_c)] s_cb = [[smt.Symbol("s_cb[{}][{}]".format(c, b)) for b in range(n_b)] for c in range(n_c)] # Aux variables s_ih = [[smt.Symbol("s_ih[{}][{}]".format(i, h)) for h in range(n_h)] for i in range(n_d)] s_ic = [[smt.Symbol("s_ic[{}][{}]".format(i, c)) for c in range(n_c)] for i in range(n_d)] # Constraints for i in new_active_indices: x_r, x_b, label = real_features[i], bool_features[i], labels[i] for h in range(n_h_original): sum_coefficients = smt.Plus( [a_hr[h][r] * smt.Real(x_r[r]) for r in range(n_r)]) solver.add_assertion( smt.Iff(s_ih[i][h], sum_coefficients <= b_h[h])) for h in range(n_h_original, n_h): solver.add_assertion( smt.Iff(s_ih[i][h], ~s_ih[i][h - n_h_original])) for c in range(n_c): solver.add_assertion( smt.Iff( s_ic[i][c], smt.And([smt.TRUE()] + [(~s_ch[c][h] | s_ih[i][h]) for h in range(n_h)] + [ ~s_cb[c][b] for b in range(n_b_original) if not x_b[b] ] + [ ~s_cb[c][b] for b in range(n_b_original, n_b) if x_b[b - n_b_original] ]))) if label: solver.add_assertion(smt.Or([s_ic[i][c] for c in range(n_c)])) else: solver.add_assertion(smt.And([~s_ic[i][c] for c in range(n_c)])) solver.solve() model = solver.get_model() x_vars = [domain.get_symbol(domain.real_vars[r]) for r in range(n_r)] half_spaces = [ smt.Plus( [model.get_value(a_hr[h][r]) * x_vars[r] for r in range(n_r)]) <= model.get_value(b_h[h]) for h in range(n_h_original) ] + [ smt.Plus( [model.get_value(a_hr[h][r]) * x_vars[r] for r in range(n_r)]) > model.get_value(b_h[h]) for h in range(n_h - n_h_original) ] b_vars = [ domain.get_symbol(domain.bool_vars[b]) for b in range(n_b_original) ] bool_literals = [b_vars[b] for b in range(n_b_original)] bool_literals += [~b_vars[b] for b in range(n_b - n_b_original)] conjunctions = [[ half_spaces[h] for h in range(n_h) if model.get_py_value(s_ch[c][h]) ] + [ bool_literals[b] for b in range(n_b) if model.get_py_value(s_cb[c][b]) ] for c in range(n_c)] return smt.Or([smt.And(conjunction) for conjunction in conjunctions])
def __ne__(self, other: 'SMTBit') -> 'SMTBit': return type(self)(smt.Not(smt.Iff(self.value, other.value)))
def order_equal(pair1, pair2): x_t, x_f, y_t, y_f = pair1 + pair2 return smt.Iff(x_t, y_t) & smt.Iff(x_f, y_f)
def learn_partial(self, solver, domain: Domain, data: np.ndarray, labels: np.ndarray, new_active_indices: Set): # Constants n_b_original = len(domain.bool_vars) n_b = n_b_original * 2 n_r = len(domain.real_vars) n_h_original = self.half_space_count if n_r > 0 else 0 n_h = n_h_original * 2 if self.allow_negations else n_h_original n_c = self.conjunction_count n_d = data.shape[0] real_indices = np.array( [domain.var_types[v] == smt.REAL for v in domain.variables]) real_features = data[:, real_indices] bool_features = data[:, np.logical_not(real_indices)] # Variables a_hr = [[ smt.Symbol("a_hr[{}][{}]".format(h, r), REAL) for r in range(n_r) ] for h in range(n_h_original)] b_h = [ smt.Symbol("b_h[{}]".format(h), REAL) for h in range(n_h_original) ] s_ch = [[smt.Symbol("s_ch[{}][{}]".format(c, h)) for h in range(n_h)] for c in range(n_c)] s_cb = [[smt.Symbol("s_cb[{}][{}]".format(c, b)) for b in range(n_b)] for c in range(n_c)] # Aux variables s_ih = [[smt.Symbol("s_ih[{}][{}]".format(i, h)) for h in range(n_h)] for i in range(n_d)] s_ic = [[smt.Symbol("s_ic[{}][{}]".format(i, c)) for c in range(n_c)] for i in range(n_d)] def pair(real: bool, c: int, index: int) -> Tuple[FNode, FNode]: if real: return s_ch[c][index], s_ch[c][index + n_h_original] else: return s_cb[c][index], s_cb[c][index + n_b_original] def order_equal(pair1, pair2): x_t, x_f, y_t, y_f = pair1 + pair2 return smt.Iff(x_t, y_t) & smt.Iff(x_f, y_f) def order_geq(pair1, pair2): x_t, x_f, y_t, y_f = pair1 + pair2 return x_t | y_f | ((~x_f) & (~y_t)) def pairs(c: int) -> List[Tuple[FNode, FNode]]: return [pair(True, c, i) for i in range(n_h_original) ] + [pair(False, c, i) for i in range(n_b_original)] def order_geq_lex(c1: int, c2: int): pairs_c1, pairs_c2 = pairs(c1), pairs(c2) assert len(pairs_c1) == len(pairs_c2) constraints = smt.TRUE() for j in range(len(pairs_c1)): condition = smt.TRUE() for i in range(j): condition &= order_equal(pairs_c1[i], pairs_c2[i]) constraints &= smt.Implies(condition, order_geq(pairs_c1[j], pairs_c2[j])) return constraints # Constraints for i in new_active_indices: x_r, x_b, label = [float(val) for val in real_features[i] ], bool_features[i], labels[i] for h in range(n_h_original): sum_coefficients = smt.Plus( [a_hr[h][r] * smt.Real(x_r[r]) for r in range(n_r)]) solver.add_assertion( smt.Iff(s_ih[i][h], sum_coefficients <= b_h[h])) for h in range(n_h_original, n_h): solver.add_assertion( smt.Iff(s_ih[i][h], ~s_ih[i][h - n_h_original])) for c in range(n_c): solver.add_assertion( smt.Iff( s_ic[i][c], smt. Or([smt.FALSE()] + [(s_ch[c][h] & s_ih[i][h]) for h in range(n_h)] + [s_cb[c][b] for b in range(n_b_original) if x_b[b]] + [ s_cb[c][b] for b in range(n_b_original, n_b) if not x_b[b - n_b_original] ]))) # --- [start] symmetry breaking --- # Mutually exclusive if "m" in self.symmetries: for c in range(n_c): for h in range(n_h_original): solver.add_assertion(~(s_ch[c][h] & s_ch[c][h + n_h_original])) for b in range(n_b_original): solver.add_assertion(~(s_cb[c][b] & s_cb[c][b + n_b_original])) # Normalized if "n" in self.symmetries: for h in range(n_h_original): solver.add_assertion( smt.Equals(b_h[h], smt.Real(1.0)) | smt.Equals(b_h[h], smt.Real(0.0))) # Vertical symmetries if "v" in self.symmetries: for c in range(n_c - 1): solver.add_assertion(order_geq_lex(c, c + 1)) # Horizontal symmetries if "h" in self.symmetries: for h in range(n_h_original - 1): solver.add_assertion(a_hr[h][0] >= a_hr[h + 1][0]) # --- [end] symmetry breaking --- if label: solver.add_assertion(smt.And([s_ic[i][c] for c in range(n_c)])) else: solver.add_assertion(smt.Or([~s_ic[i][c] for c in range(n_c)])) solver.solve() model = solver.get_model() x_vars = [domain.get_symbol(domain.real_vars[r]) for r in range(n_r)] half_spaces = [ smt.Plus( [model.get_value(a_hr[h][r]) * x_vars[r] for r in range(n_r)]) <= model.get_value(b_h[h]) for h in range(n_h_original) ] + [ smt.Plus( [model.get_value(a_hr[h][r]) * x_vars[r] for r in range(n_r)]) > model.get_value(b_h[h]) for h in range(n_h - n_h_original) ] b_vars = [ domain.get_symbol(domain.bool_vars[b]) for b in range(n_b_original) ] bool_literals = [b_vars[b] for b in range(n_b_original)] bool_literals += [~b_vars[b] for b in range(n_b - n_b_original)] conjunctions = [[ half_spaces[h] for h in range(n_h) if model.get_py_value(s_ch[c][h]) ] + [ bool_literals[b] for b in range(n_b) if model.get_py_value(s_cb[c][b]) ] for c in range(n_c)] return smt.And([smt.Or(conjunction) for conjunction in conjunctions])
def initialize(self, mdp, colors, hole_options, reward_name, okay_states, target_states, threshold, relation): logger.warning("This approach has been tested sparsely.") prob0E, prob1A = stormpy.compute_prob01min_states( mdp, okay_states, target_states) sink_states = ~okay_states assert len(mdp.initial_states) == 1 self.state_vars = [ smt.Symbol("p_{}".format(i), smt.REAL) for i in range(mdp.nr_states) ] self.state_prob1_vars = [ smt.Symbol("asure_{}".format(i)) for i in range(mdp.nr_states) ] self.state_probpos_vars = [ smt.Symbol("x_{}".format(i)) for i in range(mdp.nr_states) ] self.state_order_vars = [ smt.Symbol("r_{}".format(i), smt.REAL) for i in range(mdp.nr_states) ] self.option_vars = dict() for h, opts in hole_options.items(): self.option_vars[h] = { index: smt.Symbol("h_{}_{}".format(h, opt)) for index, opt in enumerate(opts) } self.transition_system = [] logger.debug("Obtain rewards if necessary") rewards = mdp.reward_models[reward_name] if reward_name else None if rewards: assert not rewards.has_transition_rewards state_rewards = rewards.has_state_rewards action_rewards = rewards.has_state_action_rewards logger.debug( "Model has state rewards: {}, has state/action rewards {}". format(state_rewards, action_rewards)) self.transition_system.append( self.state_prob1_vars[mdp.initial_states[0]]) threshold_inequality, action_constraint_inequality = self._to_smt_relation( relation) # TODO or GE self.transition_system.append( threshold_inequality(self.state_vars[mdp.initial_states[0]], smt.Real(float(threshold)))) state_order_domain_constraint = smt.And([ smt.And(smt.GE(var, smt.Real(0)), smt.LE(var, smt.Real(1))) for var in self.state_order_vars ]) self.transition_system.append(state_order_domain_constraint) #TODO how to ensure that prob is zero if there is no path. select_parameter_value_constraints = [] for h, opts in self.option_vars.items(): select_parameter_value_constraints.append( smt.Or(ov for ov in opts.values())) for i, opt1 in enumerate(opts.values()): for opt2 in list(opts.values())[i + 1:]: select_parameter_value_constraints.append( smt.Not(smt.And(opt1, opt2))) #logger.debug("Consistency: {}".format(smt.And(select_parameter_value_constraints))) self.transition_system.append( smt.And(select_parameter_value_constraints)) for state in mdp.states: if sink_states.get(state.id): assert rewards is None self.transition_system.append( smt.Equals(self.state_vars[state.id], smt.REAL(0))) #logger.debug("Constraint: {}".format(self.transition_system[-1])) self.transition_system.append( smt.Not(self.state_prob1_vars[state.id])) #logger.debug("Constraint: {}".format(self.transition_system[-1])) self.transition_system.append( smt.Equals(self.state_order_vars[state.id], smt.Real(0))) #logger.debug("Constraint: {}".format(self.transition_system[-1])) elif target_states.get(state.id): self.transition_system.append( smt.Equals(self.state_order_vars[state.id], smt.Real(1))) #logger.debug("Constraint: {}".format(self.transition_system[-1])) self.transition_system.append(self.state_prob1_vars[state.id]) #logger.debug("Constraint: {}".format(self.transition_system[-1])) if rewards is None: self.transition_system.append( smt.Equals(self.state_vars[state.id], smt.Real(1))) #logger.debug("Constraint: {}".format(self.transition_system[-1])) else: self.transition_system.append( self.state_probpos_vars[state.id]) #logger.debug("Constraint: {}".format(self.transition_system[-1])) self.transition_system.append( smt.Equals(self.state_vars[state.id], smt.Real(0))) #logger.debug("Constraint: {}".format(self.transition_system[-1])) else: state_in_prob1A = False state_in_prob0E = False if prob0E.get(state.id): state_in_prob0E = True else: self.transition_system.append( smt.Equals(self.state_order_vars[state.id], smt.Real(1))) #logger.debug("Constraint: {}".format(self.transition_system[-1])) self.transition_system.append( self.state_probpos_vars[state.id]) #logger.debug("Constraint: {}".format(self.transition_system[-1])) if rewards and not state_in_prob0E: if prob1A.get(state.id): self.transition_system.append( self.state_prob1_vars[state.id]) logger.debug("Constraint: {}".format( self.transition_system[-1])) state_in_prob1A = True for action in state.actions: action_index = mdp.nondeterministic_choice_indices[ state.id] + action.id #logger.debug("Action index: {}".format(action_index)) precondition = smt.And([ self.option_vars[hole][list(option)[0]] for hole, option in colors.get(action_index, dict()).items() ]) reward_value = None if rewards: reward_const = (rewards.get_state_reward( state.id) if state_rewards else 0.0) + ( rewards.get_state_action_reward(action_index) if action_rewards else 0.0) reward_value = smt.Real(reward_const) act_constraint = action_constraint_inequality( self.state_vars[state.id], smt.Plus([ smt.Times(smt.Real(t.value()), self. state_vars[t.column]) for t in action.transitions ] + [reward_value] if reward_value else [])) full_act_constraint = act_constraint if state_in_prob0E: if not rewards: full_act_constraint = smt.And( smt.Implies(self.state_probpos_vars[state.id], act_constraint), smt.Implies( smt.Not(self.state_probpos_vars), smt.Equals(self.state_vars[state.id], smt.Real(0)))) self.transition_system.append( smt.Implies( precondition, smt.Iff( self.state_probpos_vars[state.id], smt.Or([ smt.And( self.state_probpos_vars[t.column], smt.LT( self.state_order_vars[ state.id], self.state_order_vars[ t.column])) for t in action.transitions ])))) #logger.debug("Constraint: {}".format(self.transition_system[-1])) if rewards and not state_in_prob1A: # prob_one(state) <-> probpos AND for all succ prob_one(succ) self.transition_system.append( smt.Implies( precondition, smt.Iff( self.state_prob1_vars[state.id], smt.And([ self.state_prob1_vars[t.column] for t in action.transitions ] + [self.state_probpos_vars[state.id]])))) #logger.debug("Constraint: {}".format(self.transition_system[-1])) self.transition_system.append( smt.Implies(precondition, full_act_constraint)) #logger.debug("Constraint: {}".format(self.transition_system[-1])) if rewards: self.transition_system.append( smt.And([smt.GE(sv, smt.Real(0)) for sv in self.state_vars])) else: self.transition_system.append( smt.And([ smt.And(smt.GE(sv, smt.Real(0)), smt.LE(sv, smt.Real(1))) for sv in self.state_vars ])) #print(self.transition_system) formula = smt.And(self.transition_system) logger.info("Start SMT solver") model = smt.get_model(formula) if model: logger.info("SAT: Found {}".format(model)) else: logger.info("UNSAT.")