def all_loopbacks(self, vars, k, heqvar=None): lvars = list(vars) vars_k = [TS.get_timed(v, k) for v in lvars] loopback = FALSE() eqvar = None heqvars = None if heqvar is not None: eqvar = Symbol(EQVAR, BOOL) heqvars = [] peqvars = FALSE() for i in range(k): vars_i = [TS.get_timed(v, i) for v in lvars] eq_k_i = And( [EqualsOrIff(vars_k[j], vars_i[j]) for j in range(len(lvars))]) if heqvar is not None: eqvar_i = TS.get_timed(eqvar, i) peqvars = Or(peqvars, eqvar_i) eq_k_i = And(eqvar_i, Iff(eqvar_i, eq_k_i)) heqvars.append(Iff(TS.get_timed(heqvar, i), peqvars)) loopback = Or(loopback, eq_k_i) if heqvar is not None: loopback = And(loopback, And(heqvars)) return loopback
def all_simple_loopbacks(self, vars, k): lvars = list(vars) vars_k = [TS.get_timed(v, k) for v in lvars] loopback = [] eqvar = None heqvars = None peqvars = FALSE() for i in range(k): vars_i = [TS.get_timed(v, i) for v in lvars] eq_k_i = And([EqualsOrIff(vars_k[j], vars_i[j]) for j in range(len(lvars))]) loopback.append(eq_k_i) loopback.append(FALSE()) return loopback
def _remap_model_zz(self, vars, model, k): retmodel = dict([el for el in dict(model).items() if not TS.is_ptimed(el[0])]) for var in vars: for t in range(int(k/2)+1, k+1, 1): retmodel[TS.get_timed(var, t)] = model[TS.get_ptimed(var, k-t)] return retmodel
def revise_abstract_clock(model, abstract_clock_list): newmodel = {} abs_clock = dict(abstract_clock_list) length = 0 for var, value in model.items(): refvar = TS.get_ref_var(var) time = TS.get_time(var) if time > 0: if refvar not in abs_clock: newmodel[TS.get_timed(refvar, (time*2)-1)] = value newmodel[TS.get_timed(refvar, (time*2))] = value else: newmodel[TS.get_timed(refvar, (time*2)-1)] = abs_clock[refvar][1] if value == abs_clock[refvar][1]: newmodel[TS.get_timed(refvar, (time*2))] = abs_clock[refvar][0] else: newmodel[TS.get_timed(refvar, (time*2))] = abs_clock[refvar][1] if ((time*2)+1) > length: length = ((time*2)) else: if refvar not in abs_clock: newmodel[TS.get_timed(refvar, 0)] = value else: newmodel[TS.get_timed(refvar, 0)] = abs_clock[refvar][0] return (newmodel, length)
def _remap_model_zz(self, vars, model, k): retmodel = dict(model) for var in vars: for t in range(int(k / 2) + 1, k + 1, 1): retmodel[TS.get_timed(var, t)] = model[TS.get_ptimed(var, k - t)] return retmodel
def _remap_model_bwd(self, vars, model, k): retmodel = dict() for var in vars: for t in range(k + 1): retmodel[TS.get_timed(var, t)] = model[TS.get_ptimed(var, k - t)] return retmodel
def loop_free(self, vars_, k_end, k_start=0): Logger.log("Simple path from %s to %s"%(k_start, k_end), 2) if k_end == k_start: return TRUE() def not_eq_states(vars1, vars2): assert len(vars1) == len(vars2) eqvars = [] for i in range(len(vars1)): eqvars.append(EqualsOrIff(vars1[i], vars2[i])) return Not(And(eqvars)) lvars = list(vars_) end_vars = [TS.get_timed(v, k_end) for v in lvars] formula = [] for t in range(k_start, k_end, 1): formula.append(not_eq_states(end_vars, [TS.get_timed(v, t) for v in lvars])) return And(formula)
def print_trace(self, hts, modeldic, length, map_function=None, find_loop=False): trace = [] prevass = [] hex_values = False trace.append("---> INIT <---") if self.all_vars: varlist = list(hts.vars) else: varlist = list( hts.input_vars.union(hts.output_vars).union(hts.state_vars)) if self.extra_vars is not None: varlist = list(set(varlist).union(set(self.extra_vars))) strvarlist = [(map_function(var.symbol_name()), var) for var in varlist if not self.is_hidden(var.symbol_name())] strvarlist.sort() for var in strvarlist: var_0 = TS.get_timed(var[1], 0) if var_0 not in modeldic: continue varass = (var[0], modeldic[var_0]) if hex_values: varass = (varass[0], dec_to_hex(varass[1].constant_value(), int(var[1].symbol_type().width / 4))) if self.diff_only: prevass.append(varass) trace.append(" I: %s = %s" % (varass[0], varass[1])) if self.diff_only: prevass = dict(prevass) for t in range(length): trace.append("\n---> STATE %s <---" % (t + 1)) for var in strvarlist: var_t = TS.get_timed(var[1], t + 1) if var_t not in modeldic: continue varass = (var[0], modeldic[var_t]) if hex_values: varass = (varass[0], dec_to_hex(varass[1].constant_value(), int(var[1].symbol_type().width / 4))) if (not self.diff_only) or (prevass[varass[0]] != varass[1]): trace.append(" S%s: %s = %s" % (t + 1, varass[0], varass[1])) if self.diff_only: prevass[varass[0]] = varass[1] if find_loop: last_state = [(var[0], modeldic[TS.get_timed(var[1], length)]) for var in strvarlist] last_state.sort() loop_id = -1 for i in range(length): state_i = [(var[0], modeldic[TS.get_timed(var[1], i)]) for var in strvarlist] state_i.sort() if state_i == last_state: loop_id = i break if loop_id >= 0: trace.append("\n---> STATE %s loop to STATE %s <---" % (length, loop_id)) trace = NL.join(trace) return trace
def print_trace(self, hts, model, length, map_function=None, find_loop=False, abstract_clock_list=None): abstract_clock = (abstract_clock_list is not None) and (len(abstract_clock_list) > 0) if abstract_clock: (model, length) = revise_abstract_clock(model, abstract_clock_list) trace = [] prevass = [] # Initial state printing trace.append("%sINIT%s"%(PRE_TRACE, POS_TRACE)) if self.all_vars: varlist = list(hts.vars) else: varlist = list(hts.input_vars.union(hts.output_vars)) if self.prop_vars is not None: varlist = list(set(varlist).union(set(self.prop_vars))) strvarlist = [(map_function(var[0]), var[1]) for var in sort_system_variables(varlist, True) if not self.is_hidden(var[0])] for var in strvarlist: var_0 = TS.get_timed(var[1], 0) if var_0 not in model: prevass.append((var[0], None)) continue varass = (var[0], model[var_0]) if (self.values_base == TraceValuesBase.HEX) and (var[1].symbol_type().is_bv_type()): varass = (varass[0], "%d'h%s"%(var[1].symbol_type().width, dec_to_hex(varass[1].constant_value(), int(var[1].symbol_type().width/4)))) if (self.values_base == TraceValuesBase.BIN) and (var[1].symbol_type().is_bv_type()): varass = (varass[0], "%d'b%s"%(var[1].symbol_type().width, dec_to_bin(varass[1].constant_value(), int(var[1].symbol_type().width)))) if self.diff_only: prevass.append(varass) trace.append(" I: %s = %s"%(varass[0], varass[1])) if self.diff_only: prevass = dict(prevass) # Success state printing for t in range(length): trace.append("\n%s%s %d%s"%(PRE_TRACE, STATE, t+1, POS_TRACE)) for var in strvarlist: var_t = TS.get_timed(var[1], t+1) if var_t not in model: continue varass = (var[0], model[var_t]) if (self.values_base == TraceValuesBase.HEX) and (var[1].symbol_type().is_bv_type()): varass = (varass[0], "%d'h%s"%(var[1].symbol_type().width, dec_to_hex(varass[1].constant_value(), int(var[1].symbol_type().width/4)))) if (self.values_base == TraceValuesBase.BIN) and (var[1].symbol_type().is_bv_type()): varass = (varass[0], "%d'b%s"%(var[1].symbol_type().width, dec_to_bin(varass[1].constant_value(), int(var[1].symbol_type().width)))) if (not self.diff_only) or (prevass[varass[0]] != varass[1]): trace.append(" S%s: %s = %s"%(t+1, varass[0], varass[1])) if self.diff_only: prevass[varass[0]] = varass[1] if find_loop: last_state = [(var[0], model[TS.get_timed(var[1], length)]) for var in strvarlist] last_state.sort() loop_id = -1 for i in range(length): state_i = [(var[0], model[TS.get_timed(var[1], i)]) for var in strvarlist] state_i.sort() if state_i == last_state: loop_id = i break if loop_id >= 0: end = ("STATE %s"%loop_id) if loop_id > 0 else "INIT" trace.append("\n---> %s (Loop) <---"%(end)) strtrace = NL.join(trace) trace = Trace(strtrace, length) trace.human_readable = True return trace
def sim_no_unroll(self, hts, cover, k, all_vars=True, inc=False): init = hts.single_init() invar = hts.single_invar() trans = hts.single_trans() init_0 = self.at_time(init, 0) invar_0 = self.at_time(invar, 0) trans_01 = self.unroll(trans, invar, 1) cover_1 = self.at_time(cover, 1) full_model = {} if all_vars: relevant_vars = hts.vars else: relevant_vars = hts.state_vars | hts.output_vars relevant_vars_0 = [TS.get_timed(v, 0) for v in relevant_vars] relevant_vars_1 = [TS.get_timed(v, 1) for v in relevant_vars] relevant_vars_01 = [(TS.get_timed(v, 0), TS.get_timed(v, 1), v) for v in relevant_vars] self._reset_assertions(self.solver) # Picking Initial State Logger.log("\nSolving for k=0", 1) self._add_assertion(self.solver, And(init_0, invar_0)) if self._solve(self.solver): init_model = self._get_model(self.solver, relevant_vars_0) init_0 = And([EqualsOrIff(v, init_model[v]) for v in relevant_vars_0]) for v in relevant_vars_0: full_model[v] = init_model[v] Logger.msg(".", 0, not(Logger.level(1))) else: return (0, None) self._reset_assertions(self.solver) if inc: self._add_assertion(self.solver, trans_01) self._add_assertion(self.solver, invar_0) init_model = None for t in range(1, k + 1): Logger.log("\nSolving for k=%s"%(t), 1) if not inc: self._reset_assertions(self.solver, True) formula = And(init_0, invar_0) self._add_assertion(self.solver, trans_01) else: formula = init_0 self._push(self.solver) self._add_assertion(self.solver, formula) res_step = self._solve(self.solver) if res_step: Logger.msg(".", 0, not(Logger.level(1))) Logger.log("Able to step forward at k=%s"%(t), 2) if all_vars: init_model = self._get_model(self.solver) else: init_model = self._get_model(self.solver, relevant_vars_1) model = init_model else: Logger.log("System deadlocked at k=%s"%(t), 2) return (-1, full_model) # Use previous model as initial state for next sat call init_0 = [] init_1 = [] for v in relevant_vars_01: if v[1] not in init_model: continue val = init_model[v[1]] full_model[TS.get_timed(v[2], t)] = val init_0.append(EqualsOrIff(v[0], val)) init_1.append(EqualsOrIff(v[1], val)) init_0 = And(init_0) if cover != TRUE(): init_1 = And(init_1) self._add_assertion(self.solver, init_1) self._add_assertion(self.solver, cover_1) res_cont = self._solve(self.solver) if res_cont: Logger.log('Reached cover in no unroll simulation at k=%s'%(t), 2) model = init_model return (t, full_model) else: Logger.log('Cover not reached at k=%s'%t, 2) if inc: self._pop(self.solver) return (t, full_model)
def solve_safety_inc_bwd(self, hts, prop, k, assert_property=False, generalize=None): solver = self.solver.copy("inc_bwd") self._reset_assertions(solver) has_next = TS.has_next(prop) if has_next: prop = TS.to_prev(prop) init = hts.single_init() trans = hts.single_trans() invar = hts.single_invar() formula = self.at_ptime(And(Not(prop), invar), -1) Logger.log("Add not property at time %d"%0, 2) self._add_assertion(solver, formula) skip_push = False constraints = TRUE() models = 0 t = 0 k_min = 1 if has_next else 0 while (t < k+1): if not skip_push: self._push(solver) skip_push = False if not skip_push: pinit = self.at_ptime(init, t-1) Logger.log("Add init at time %d"%t, 2) self._add_assertion(solver, pinit) if constraints != TRUE(): for j in range(t+1): self._add_assertion(solver, self.at_ptime(constraints, j-1), "Addditional Constraints") if self.preferred is not None: try: for (var, val) in self.preferred: solver.solver.set_preferred_var(TS.get_timed(var, t), val) except: Logger.warning("Current solver does not support preferred variables") self.preferred = None if (t >= k_min) and self._solve(solver): Logger.log("Counterexample found with k=%s"%(t), 1) model = self._get_model(solver) models += 1 if models > 20: Logger.msg("R", 0, not(Logger.level(1))) self._reset_solver(solver) models = 0 if generalize is not None: constr, res = generalize(model, t) if res: return (t, model) constraints = And(constraints, Not(constr)) skip_push = True continue else: return (t, model) else: Logger.log("No counterexample found with k=%s"%(t), 1) Logger.msg(".", 0, not(Logger.level(1))) self._pop(solver) skip_push = False trans_t = self.unroll(trans, invar, t, t+1) self._add_assertion(solver, trans_t) if assert_property and t > 0: prop_t = self.unroll(TRUE(), prop, t-1, t) self._add_assertion(solver, prop_t) Logger.log("Add property at time %d"%t, 2) t += 1 return (t-1, None)
def solve_safety_inc_fwd(self, hts, prop, k, k_min, \ all_vars=False, generalize=None, prove=None): add_unsat_cons = False prove = self.config.prove if prove is None else prove solver_name = "inc_fwd%s"%("_prove" if prove else "") solver = self.solver.copy(solver_name) self._reset_assertions(solver) if prove: solver_ind = self.solver.copy("%s_ind"%solver_name) self._reset_assertions(solver_ind) if all_vars: relevant_vars = hts.vars else: relevant_vars = hts.state_vars | hts.output_vars init = hts.single_init() trans = hts.single_trans() invar = hts.single_invar() acc_init = TRUE() acc_prop = TRUE() acc_loop_free = TRUE() trans_t = TRUE() if self.config.simplify: Logger.log("Simplifying the Transition System", 1) if Logger.level(2): timer = Logger.start_timer("Simplify") init = simplify(init) trans = simplify(trans) invar = simplify(invar) if Logger.level(2): Logger.get_timer(timer) n_prop_t = FALSE() init_0 = self.at_time(And(init, invar), 0) Logger.log("Add init and invar", 2) self._add_assertion(solver, init_0) if prove: # add invariants at time 0, but not init self._add_assertion(solver_ind, self.at_time(invar, 0), "invar") next_prop = TS.has_next(prop) if next_prop: if k < 1: Logger.error("Invariant checking with next variables requires at least k=1") k_min = 1 skip_push = False constraints = TRUE() t = k_min for i in range(t): trans_t = self.unroll(trans, invar, i+1, i) self._add_assertion(solver, trans_t) Logger.msg("Unroll and call check-sat without property", 2) # Note: Seems to help a lot to call check-sat here # without this some solvers will run out of memory on large problems # it likely lets them do some internal clean up, and learn some things # about the model self._solve(solver) Logger.msg("_", 0, not(Logger.level(1))) while (t < k+1): if not skip_push: self._push(solver) skip_push = False t_prop = t-1 if next_prop else t if k_min > 0: if (not next_prop) or (next_prop and t>0): if n_prop_t == FALSE(): n_prop_t = self.at_time(Not(prop), t_prop) else: n_prop_t = Or(n_prop_t, self.at_time(Not(prop), t_prop)) else: n_prop_t = self.at_time(Not(prop), t) Logger.log("Add not property at time %d"%t, 2) if not skip_push: self._add_assertion(solver, n_prop_t, "Property") if constraints != TRUE(): self._add_assertion(solver, self.at_time(constraints, t), "Addditional Constraints") if t >= k_min: Logger.log("\nSolving for k=%s"%(t), 1) if self.preferred is not None: try: for (var, val) in self.preferred: for j in range(t+1): solver.solver.set_preferred_var(TS.get_timed(var, j), val) except: Logger.warning("Current solver does not support preferred variables") self.preferred = None if self._solve(solver): Logger.log("Counterexample found with k=%s"%(t), 1) model = self._get_model(solver) if generalize is not None: constr, res = generalize(model, t) if res: return (t, model) constraints = And(constraints, Not(constr)) skip_push = True continue else: return (t, model) else: Logger.log("No counterexample found with k=%s"%(t), 1) Logger.msg(".", 0, not(Logger.level(1))) if add_unsat_cons and prove: self._add_assertion(solver, Implies(self.at_time(And(init, invar), 1), self.at_time(Not(prop), t_prop+1))) self._add_assertion(solver, Not(n_prop_t)) else: Logger.log("\nSkipping solving for k=%s (k_min=%s)"%(t,k_min), 1) Logger.msg("_", 0, not(Logger.level(1))) self._pop(solver) skip_push = False if prove: if t > k_min: loop_free = self.loop_free(relevant_vars, t, t-1) # Checking I & T & loopFree acc_init = And(acc_init, self.at_time(Not(init), t)) acc_loop_free = And(acc_loop_free, loop_free) self._push(solver) self._add_assertion(solver, acc_init) self._add_assertion(solver, acc_loop_free) if self._solve(solver): Logger.log("Induction (I & lF) failed with k=%s"%(t), 1) else: Logger.log("Induction (I & lF) holds with k=%s"%(t), 1) return (t, True) self._pop(solver) # Checking T & loopFree & !P self._add_assertion(solver_ind, trans_t, comment="trans") self._add_assertion(solver_ind, loop_free, comment="loop_free") self._push(solver_ind) self._add_assertion(solver_ind, self.at_time(Not(prop), t_prop)) if self._solve(solver_ind): Logger.log("Induction (lF & !P) failed with k=%s"%(t), 1) else: Logger.log("Induction (lF & !P) holds with k=%s"%(t), 1) return (t, True) self._pop(solver_ind) self._add_assertion(solver_ind, self.at_time(prop, t_prop), "prop") else: if not next_prop: self._add_assertion(solver_ind, self.at_time(prop, t_prop), "prop") else: # add skipped transition self._add_assertion(solver_ind, trans_t, comment="trans") trans_t = self.unroll(trans, invar, t+1, t) self._add_assertion(solver, trans_t) t += 1 return (t-1, None)
def encode_l(self, formula, t_i, t_k, t_l): if formula.is_constant(): return formula if formula.is_symbol(): assert (t_i >= 0) return TS.get_timed(formula, t_i) if formula.is_equals(): return self.mgr.Equals( self.encode_l(formula.args()[0], t_i, t_k, t_l), self.encode_l(formula.args()[1], t_i, t_k, t_l)) if formula.is_and(): return self.mgr.And( self.encode_l(formula.args()[0], t_i, t_k, t_l), self.encode_l(formula.args()[1], t_i, t_k, t_l)) if formula.is_or(): return self.mgr.Or(self.encode_l(formula.args()[0], t_i, t_k, t_l), self.encode_l(formula.args()[1], t_i, t_k, t_l)) if formula.is_lt(): return self.mgr.LT(self.encode_l(formula.args()[0], t_i, t_k, t_l), self.encode_l(formula.args()[1], t_i, t_k, t_l)) if formula.is_bv_ult(): return self.mgr.BVULT( self.encode_l(formula.args()[0], t_i, t_k, t_l), self.encode_l(formula.args()[1], t_i, t_k, t_l)) if formula.is_bv_ule(): return self.mgr.BVULE( self.encode_l(formula.args()[0], t_i, t_k, t_l), self.encode_l(formula.args()[1], t_i, t_k, t_l)) if formula.is_implies(): return self.mgr.Implies( self.encode_l(formula.args()[0], t_i, t_k, t_l), self.encode_l(formula.args()[1], t_i, t_k, t_l)) if formula.is_not(): return self.mgr.Not(self.encode_l(formula.args()[0], t_i, t_k, t_l)) if formula.node_type() == LTL_X: if t_i < t_k: return self.encode_l(formula.args()[0], t_i + 1, t_k, t_l) return self.encode_l(formula.args()[0], t_l, t_k, t_l) if formula.node_type() == LTL_G: return And([ self.encode_l(formula.args()[0], j, t_k, t_l) for j in range(min(t_i, t_l), t_k + 1, 1) ]) if formula.node_type() == LTL_F: return Or([ self.encode_l(formula.args()[0], j, t_k, t_l) for j in range(min(t_i, t_l), t_k + 1, 1) ]) if formula.node_type() == LTL_U: formula_h = formula.args()[0] formula_g = formula.args()[1] u1 = Or([And(self.encode_l(formula_g, j, t_k, t_l), \ And([self.encode_l(formula_h, n, t_k, t_l) for n in range(t_i, j, 1)])) for j in range(t_i, t_k+1, 1)]) u2 = Or([And(self.encode_l(formula_g, j, t_k, t_l), \ And([self.encode_l(formula_h, n, t_k, t_l) for n in range(t_i, t_k+1, 1)]), \ And([self.encode_l(formula_h, n, t_k, t_l) for n in range(t_l, j, 1)])) for j in range(t_l, t_i, 1)]) return Or(u1, u2) if formula.node_type() == LTL_R: formula_h = formula.args()[0] formula_g = formula.args()[1] r1 = And([ self.encode_l(formula_g, j, t_k, t_l) for j in range(min(t_i, t_l), t_k + 1, 1) ]) r2 = Or([And(self.encode_l(formula_h, j, t_k, t_l), \ And([self.encode_l(formula_g, n, t_k, t_l) for n in range(t_i, j+1, 1)])) for j in range(t_i, t_k+1, 1)]) r3 = Or([And(self.encode_l(formula_h, j, t_k, t_l), \ And([self.encode_l(formula_g, n, t_k, t_l) for n in range(t_i, t_k+1, 1)]), \ And([self.encode_l(formula_g, n, t_k, t_l) for n in range(t_l, j+1, 1)])) for j in range(t_l, t_i, 1)]) return Or(r1, r2, r3) if formula.node_type() == LTL_O: return Or([ self.encode_l(formula.args()[0], j, t_k, t_l) for j in range(t_i, t_k + 1, 1) ]) if formula.node_type() == LTL_H: return And([ self.encode_l(formula.args()[0], j, t_k, t_l) for j in range(t_i, t_k + 1, 1) ]) Logger.error("Invalid LTL operator")
def encode(self, formula, t_i, t_k): if formula.is_constant(): return formula if formula.is_symbol(): assert (t_i >= 0) return TS.get_timed(formula, t_i) if formula.is_equals(): return self.mgr.Equals(self.encode(formula.args()[0], t_i, t_k), self.encode(formula.args()[1], t_i, t_k)) if formula.is_and(): return self.mgr.And(self.encode(formula.args()[0], t_i, t_k), self.encode(formula.args()[1], t_i, t_k)) if formula.is_implies(): return self.mgr.Or( self.mgr.Not(self.encode(formula.args()[0], t_i, t_k)), self.encode(formula.args()[1], t_i, t_k)) if formula.is_not(): return self.mgr.Not(self.encode(formula.args()[0], t_i, t_k)) if formula.is_lt(): return self.mgr.LT(self.encode(formula.args()[0], t_i, t_k), self.encode(formula.args()[1], t_i, t_k)) if formula.is_bv_ult(): return self.mgr.BVULT(self.encode(formula.args()[0], t_i, t_k), self.encode(formula.args()[1], t_i, t_k)) if formula.is_bv_ule(): return self.mgr.BVULE(self.encode(formula.args()[0], t_i, t_k), self.encode(formula.args()[1], t_i, t_k)) if formula.is_or(): return self.mgr.Or(self.encode(formula.args()[0], t_i, t_k), self.encode(formula.args()[1], t_i, t_k)) if formula.node_type() == LTL_X: if t_i < t_k: return self.encode(formula.args()[0], t_i + 1, t_k) return FALSE() if formula.node_type() == LTL_G: return FALSE() if formula.node_type() == LTL_F: return Or([ self.encode(formula.args()[0], j, t_k) for j in range(t_i, t_k + 1, 1) ]) if formula.node_type() == LTL_U: formula_h = formula.args()[0] formula_g = formula.args()[1] return Or([And(self.encode(formula_g, j, t_k), \ And([self.encode(formula_h, n, t_k) for n in range(t_i, j, 1)])) for j in range(t_i, t_k+1, 1)]) if formula.node_type() == LTL_R: formula_h = formula.args()[0] formula_g = formula.args()[1] return Or([And(self.encode(formula_h, j, t_k), \ And([self.encode(formula_g, n, t_k) for n in range(t_i, j+1, 1)])) for j in range(t_i, t_k+1, 1)]) if formula.node_type() == LTL_O: return Or([ self.encode(formula.args()[0], j, t_k) for j in range(t_i, t_k + 1, 1) ]) if formula.node_type() == LTL_H: return And([ self.encode(formula.args()[0], j, t_k) for j in range(t_i, t_k + 1, 1) ]) Logger.error("Invalid LTL operator")