def solve(self) -> List[str] or None: logging.info('solving the query..') self._query_storage += '(echo "done")' lines_response = [] # TODO: XXX: ugly (know about check-sat + protected): avoiding deadlock due to pipe overfull extracting = False for l in self._query_storage._output: self._process.stdin.write(bytes(l + '\n', 'utf-8')) self._process.stdin.flush() # just in case if l.strip().startswith('(check-sat'): z3_response = str(self._process.stdout.readline(), 'utf-8').strip() if z3_response == 'unsat': self._query_storage = StrAwareList() return None if z3_response == 'sat': logging.debug('z3 returned sat, extracting the model') extracting = True continue else: assert 0, 'z3 returned unexpected smth: ' + lines_response[ 0] if extracting: z3_response = str(self._process.stdout.readline(), 'utf-8').strip() lines_response.append(z3_response) self._query_storage = StrAwareList() return lines_response
def _mark_states_with_moore_signals(lts: LTS, state_variable, moore_signals): dot_lines = StrAwareList() for state in lts.states: state_label = Label({state_variable: state}) value_by_signal = dict() for signal in moore_signals: signal_model = lts.model_by_signal[signal] value = signal_model[state_label] value_by_signal[signal] = value signals_str = _convert_label_to_dot(value_by_signal) color = '' if state in lts.init_states: color = ', fillcolor="green", style=filled' if signals_str != '': dot_lines += '"{state}" [label="{out}\\n{state}"{color}]'.format( color=color, state=state, out=signals_str) else: dot_lines += '"{state}" [label="{state}"{color}]'.format( color=color, state=state) return dot_lines
def _colorize_nodes(lts): dot_lines = StrAwareList() for state in lts.states: dot_lines += '"{state}" [{color}]'.format_map({'state': state, 'color': ['', 'fillcolor="green",style=filled'][ state in lts.init_states]}) return dot_lines
def to_boolean_nusmv(lts: LTS, specification: SpecProperty) -> str: nof_state_bits = int(max(1, math.ceil(math.log(len(lts.states), 2)))) bits_by_state = dict((state, bin_fixed_list(i, nof_state_bits)) for (i, state) in enumerate(sorted(lts.states))) state_bits = lmap(_ith_state_bit, range(nof_state_bits)) _assert_no_intersection(state_bits, list(lts.input_signals) + lts.output_signals) dot_lines = StrAwareList() dot_lines += 'MODULE main' dot_lines += 'IVAR' dot_lines += [ ' {signal} : boolean;'.format(signal=s.name) for s in lts.input_signals ] dot_lines += 'VAR' dot_lines += [' {si} : boolean;'.format(si=si) for si in state_bits] dot_lines += 'DEFINE' dot_lines += [ ' {out_name} := {formula} ;'.format(out_name=out_name, formula=_get_formula( out_name, out_model, bits_by_state)) for (out_name, out_model) in lts.model_by_name.items() ] dot_lines += 'ASSIGN' for i, sb in enumerate(state_bits): sb_init = str(bits_by_state[list(lts.init_states)[0]][i]).upper() dot_lines += ' init({sb}) := {init_sb};'.format(sb=sb, init_sb=sb_init) dot_lines += ' next({sb}) := '.format(sb=sb) dot_lines += ' case' for (label, next_state) in lts.tau_model.items(): sb_next = str(bits_by_state[next_state][i]).upper() dot_lines += ' {formula} : {next_state};'.format( formula=_clause_to_formula(label, bits_by_state), next_state=sb_next) dot_lines += ' TRUE : FALSE;' # default: unreachable states, don't care dot_lines += ' esac;' expr = BinOp('->', and_expressions(specification.assumptions), and_expressions(specification.guarantees)) expr = WeakToUntilConverterVisitor().dispatch( expr) # SMV does not have Weak until dot_lines += 'LTLSPEC ' + AstToSmvProperty().dispatch(expr) return '\n'.join(dot_lines)
def __init__(self, z3_path): super().__init__(StrAwareList()) z3_cmd = z3_path + ' -smt2 -in ' args = shlex.split(z3_cmd) self._process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logging.info('created z3 process: ' + str(self._process.pid))
def _label_states_with_outvalues(lts:LTS, filter='all'): dot_lines = StrAwareList() for state in lts.states: signal_vals_pairs = [(var, vals) for (var, vals) in lts.model_by_name.items() if var in filter or filter == 'all'] outvals = dict([(var, vals[Label({'state': state})]) # TODO: hack for (var, vals) in signal_vals_pairs]) outvals_str = _convert_to_dot(outvals) if outvals_str != '': dot_lines += '"{state}"[label="{out}\\n({state})"]'.format(state=state, out=outvals_str) return dot_lines
def _get_init_condition_on_tokens(self): conditions = StrAwareList() states = self.states_by_process[0] s0, s1 = states[0], states[1] tok_func_desc = self.outvar_desc_by_process[0][self._has_tok_signal] conditions += self.underlying_solver.call_func( tok_func_desc, {self.state_arg_name: s1}) conditions += self.underlying_solver.op_not( self.underlying_solver.call_func(tok_func_desc, {self.state_arg_name: s0})) return conditions
def __init__(self, logic: Logic, z3_path, logger): super().__init__(StrAwareList(), logic) z3_cmd = z3_path + ' -smt2 -in ' args = shlex.split(z3_cmd) self._logger = logger self._process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self._logger.info('created z3 process: ' + str(self._process.pid))
def solve(self): self._logger.info('solving the query..') self._query_storage += '(echo "done")' self._process.stdin.write(bytes(str(self._query_storage), 'utf-8')) self._process.stdin.flush() # just in case lines = self._read_block() self._assert_no_errors(lines) self._query_storage = StrAwareList() if lines[0] == 'sat': return lines[1:] return None
def _restrict_trans(self, impl, permissible_states): #: :type: FuncDescription trans_func_desc = impl.taus_descs[0] assertions = StrAwareList() for curr_state in permissible_states: free_input_vars = self._get_free_vars(Label(), impl) value_by_arg = self._get_proc_tau_args(curr_state, Label(), 0, impl) next_state = self._underlying_solver.call_func(trans_func_desc, value_by_arg) assertions += self._underlying_solver.assert_( self._underlying_solver.forall_bool(free_input_vars, self._get_permissible_states_clause(next_state, permissible_states))) return assertions
def get_architecture_requirements(self): """ 'One process only possesses the token initially' Generic encoder considers different initial configurations of the ring, making sure that all possible initial token distributions are verified. """ conditions = StrAwareList() states = self.states_by_process[0] s0, s1 = states[0], states[1] tok_func_desc = self.outvar_desc_by_process[0][ self._has_tok_signals[0]] conditions += self.underlying_solver.call_func( tok_func_desc, {self.state_arg_name: s1}) conditions += self.underlying_solver.op_not( self.underlying_solver.call_func(tok_func_desc, {self.state_arg_name: s0})) return conditions
def _lts_to_dot(lts: LTS, state_variable, moore_signals): logger = logging.getLogger(__file__) dot_lines = StrAwareList() dot_lines += 'digraph module {\n rankdir=LR;\n' dot_lines += _mark_states_with_moore_signals(lts, state_variable, moore_signals) edge_labels = _build_edge_labels(lts, state_variable, moore_signals) logger.debug('non-simplified model: \n' + str(edge_labels)) simplified_edge_labels = simplify_edge_labels(edge_labels) # simplified_edge_labels = edge_labels for (src, dst), io_labels in simplified_edge_labels.items(): if not io_labels: # possible due to the simplification dot_lines += '"{src}" -> "{dst}" [label="1"]'.format(src=src, dst=dst) for io_label in io_labels: i_vals = dict() o_vals = dict() for signal, value in io_label.items(): if signal in lts.input_signals: i_vals[signal] = value else: o_vals[signal] = value i_vals_str = _convert_label_to_dot(i_vals) or '1' o_vals_str = _convert_label_to_dot(o_vals) dot_lines += '"{src}" -> "{dst}" [label="{in_}{out}"]'.format( src=src, dst=dst, in_=i_vals_str, out=('/' + '\\n' + o_vals_str) if o_vals_str != '' else '') dot_lines += '}' return '\n'.join(dot_lines)
def to_dot(lts:LTS, outvars_treated_as_moore=()): logger = logging.getLogger(__file__) dot_lines = StrAwareList() dot_lines += 'digraph module {\n' dot_lines += _colorize_nodes(lts) + '\n' dot_lines += _label_states_with_outvalues(lts, outvars_treated_as_moore) srcdst_to_io_labels = _build_srcdst_to_io_labels(lts, outvars_treated_as_moore) logger.debug('non-simplified model: \n' + str(srcdst_to_io_labels)) simplified_srcdst_to_io_labels = _simplify_srcdst_to_io_labels(srcdst_to_io_labels) logger.debug('the model after edge simplifications: \n' + str(srcdst_to_io_labels)) for (src, dst), io_labels in simplified_srcdst_to_io_labels.items(): for io_label in io_labels: i_vals = dict() o_vals = dict() for signal, value in io_label.items(): if signal in lts.input_signals: i_vals[signal] = value else: o_vals[signal] = value i_vals_str = _convert_to_dot(i_vals) or '*' o_vals_str = _convert_to_dot(o_vals) o_vals_str = '/' + '\\n' + o_vals_str if o_vals_str != '' else '' dot_lines += '"{state}" -> "{x_state}" [label="{in}{mark_out}"]'.format_map( {'state': src, 'x_state': dst, 'in': i_vals_str, 'mark_out': o_vals_str}) dot_lines += '}' return '\n'.join(dot_lines)
def _get_tok_rings_safety_props( self) -> StrAwareList: # TODO: should be able to specify states! """ Return (in SMT form, constraints on non-wrapped tau function): G(tok & !sends -> Xtok(tau(!prev))) G(sends -> tok) G(sends -> X!tok(!prev)) G(Xtok(prev)) G(!tok -> !Xtok(!prev)) """ smt_lines = StrAwareList() tau_desc = self.taus_descs[0] tau_signals = self.orig_inputs[0] tok_func_desc = self.outvar_desc_by_process[0][self._has_tok_signal] sends_func_desc = self.outvar_desc_by_process[0][self._sends_signal] prev_is_false_label = Label({self._sends_prev_signal: False}) prev_is_true_label = Label({self._sends_prev_signal: True}) states = self.states_by_process[0] for state in states: state_arg = {self.state_arg_name: state} has_tok_expr = call_func(tok_func_desc, state_arg) sends_tok_expr = call_func(sends_func_desc, state_arg) _, free_vars = build_signals_values(tau_signals, prev_is_false_label) nprev_arg, _ = build_signals_values(tau_signals, prev_is_false_label) nprev_state_arg = add_dicts(nprev_arg, state_arg) prev_arg, _ = build_signals_values(tau_signals, prev_is_true_label) prev_state_arg = add_dicts(prev_arg, state_arg) tau_nprev_expr = call_func(tau_desc, nprev_state_arg) tok_of_tau_nprev_expr = call_func( tok_func_desc, {self.state_arg_name: tau_nprev_expr}) tau_prev_expr = call_func(tau_desc, prev_state_arg) tok_of_tau_prev_expr = call_func( tok_func_desc, {self.state_arg_name: tau_prev_expr}) # tok_dont_disappear = forall_bool( free_vars, op_implies(op_and([has_tok_expr, op_not(sends_tok_expr)]), tok_of_tau_nprev_expr)) sends_with_token_only = forall_bool( free_vars, op_implies(sends_tok_expr, has_tok_expr)) sends_means_release = forall_bool( free_vars, op_implies(sends_tok_expr, op_not(tok_of_tau_nprev_expr))) sends_prev_means_acquire = forall_bool(free_vars, tok_of_tau_prev_expr) no_sends_prev_no_tok_means_no_next_tok = forall_bool( free_vars, op_implies(op_not(has_tok_expr), op_not(tok_of_tau_nprev_expr))) smt_lines += [ tok_dont_disappear, sends_with_token_only, sends_means_release, sends_prev_means_acquire, no_sends_prev_no_tok_means_no_next_tok ] return smt_lines
def lts_to_verilog(lts:LTS) -> str: s = StrAwareList() s += 'module model(i_clk, \n{inputs}, \n{outputs});'.format(inputs=', '.join(map(lambda sig: sig.name, lts.input_signals)), outputs=', '.join(map(lambda sig: sig.name, lts.output_signals))) s.newline() s += 'input i_clk;' s += '\n'.join(['input {sig};'.format(sig=sig.name) for sig in lts.input_signals]) s.newline() s += '\n'.join(['output {sig};'.format(sig=sig.name) for sig in lts.output_signals]) s.newline() nof_state_bits = max(1, math.ceil(math.log2(len(lts.states)))) s += 'reg [{max_bit}:0] {state};'.format(max_bit=nof_state_bits-1, state=lts.state_name) s.newline() s += '\n'.join(['wire {out};'.format(out=sig.name) for sig in lts.output_signals]) s.newline() for out_sig, value_tuples in lts.output_models.items(): labels_true = lmap(lambda x: x[0], filter(lambda label_value: label_value[1], value_tuples.items())) assign = 'assign {sig} = {true_expr};'.format(sig=out_sig.name, true_expr=' || '.join(map(_label_to_verilog, labels_true)) if labels_true else '0') s += assign s.newline() s += 'initial begin' s += '{state} = 0;'.format(state=lts.state_name) s += 'end' s.newline() s += 'always@(posedge i_clk)' s += 'begin' tau_items = tuple(lts.tau_model.items()) s += 'if ({expr}) {state} = {next_val};'.format(expr=_label_to_verilog(tau_items[0][0]), state=lts.state_name, next_val=tau_items[0][1]) for lbl, val in tau_items[1:]: s += 'else if ({expr}) {state} = {next_val};'.format(expr=_label_to_verilog(lbl), state=lts.state_name, next_val=val) s += 'end' s += 'endmodule' return s.to_str()
def lts_to_verilog(lts:LTS, module_name:str) -> str: s = StrAwareList() s += 'module {module}({inputs}, {outputs});'.format( inputs=', '.join(map(lambda sig: sig.name, lts.input_signals)), outputs=', '.join(map(lambda sig: sig.name, lts.output_signals)), module=module_name) s.newline() s += '\n'.join(['input {sig};'.format(sig=sig.name) for sig in lts.input_signals]) s.newline() s += '\n'.join(['output {sig};'.format(sig=sig.name) for sig in lts.output_signals]) s.newline() # TODO: don't use latches for state-less models nof_state_bits = math.ceil(math.log2(len(lts.states))) s += 'reg [{max_bit}:0] {state};'.format(max_bit=int(max(0., nof_state_bits-1)), # max_bit is at least 0 state=lts.state_name) s.newline() s += '\n'.join(['wire {out};'.format(out=sig.name) for sig in lts.output_signals]) s.newline() for out_sig, value_tuples in lts.output_models.items(): labels_true = lmap(lambda x: x[0], filter(lambda label_value: label_value[1], value_tuples.items())) assign = 'assign {sig} = {true_expr};'.format(sig=out_sig.name, true_expr=' || '.join(map(_label_to_verilog, labels_true)) if labels_true else '0') s += assign s.newline() s += 'initial begin' s += '{state} = 0;'.format(state=lts.state_name) s += 'end' s.newline() s += 'always@($global_clock)' s += 'begin' # you can also use '=' instead of '<=' here, but we will be strict tau_items = tuple(lts.tau_model.items()) s += 'if ({expr}) {state} <= {next_val};'.format(expr=_label_to_verilog(tau_items[0][0]), state=lts.state_name, next_val=tau_items[0][1]) for lbl, val in tau_items[1:]: s += 'else if ({expr}) {state} <= {next_val};'.format(expr=_label_to_verilog(lbl), state=lts.state_name, next_val=val) s += 'end' s += 'endmodule' return s.to_str()
def atm_to_verilog(atm: Automaton, sys_inputs: Iterable[Signal], sys_outputs: Iterable[Signal], module_name: str, bad_out_name: str) -> str: assert len(lfilter(lambda n: is_final_sink(n), atm.nodes)) == 1,\ 'for now I support only one bad state which must be a sink' sys_inputs = set(sys_inputs) sys_outputs = set(sys_outputs) verilog_by_sig = {s: 'controllable_' + s.name for s in sys_outputs} verilog_by_sig.update({s: s.name for s in sys_inputs}) verilog_by_node = {q: '__q' + q.name for q in atm.nodes} sink_q = lfilter(lambda n: is_final_sink(n), atm.nodes)[0] module_inputs = list( chain(map(lambda i: i.name, sys_inputs), map(lambda o: 'controllable_' + o.name, sys_outputs))) s = StrAwareList() s += 'module {module_name}({inputs}, {output});'.format( module_name=module_name, inputs=', '.join(module_inputs), output=bad_out_name) s.newline() s += '\n'.join('input %s;' % i for i in module_inputs) s.newline() s += 'output %s;' % bad_out_name s.newline() s += '\n'.join('reg %s;' % vq for vq in verilog_by_node.values()) s.newline() s += 'wire %s;' % bad_out_name s += 'assign {bad} = {sink_q};'.format(bad=bad_out_name, sink_q=verilog_by_node[sink_q]) s.newline() s += 'initial begin' s += '\n'.join('%s = 1;' % verilog_by_node[iq] for iq in atm.init_nodes) s += '\n'.join('%s = 0;' % verilog_by_node[q] for q in atm.nodes - atm.init_nodes) s += 'end' s.newline() s += 'always@($global_clock)' s += 'begin' def lbl_to_v(lbl: Label) -> str: return ' && '.join( ('!%s', '%s')[lbl[s]] % verilog_by_sig[s] for s in lbl) or '1' for q in atm.nodes: incoming_edges = incoming_transitions(q, atm) if not incoming_edges: update_expr = '0' else: update_expr = ' || '.join('{src} && {lbl}'.format( src=verilog_by_node[edge[0]], lbl=lbl_to_v(edge[1])) for edge in incoming_edges) s += ' {q} <= {update_expr};'.format(q=verilog_by_node[q], update_expr=update_expr) s += 'end' s += 'endmodule' return s.to_str()
def convert(aht:AHT or None, shared_aht:SharedAHT, dstFormPropMgr:DstFormulaPropMgr)\ -> str: def _gen_unique_name(__=[]) -> str: # mutable default arg is on purpose name = '__n' + str(len(__)) __.append('') return name transitions = shared_aht.transitions if not aht \ else get_reachable_from(aht.init_node, shared_aht.transitions, dstFormPropMgr)[1] all_nodes = set() # Set[Node] trans_dot = StrAwareList() InvisNode = namedtuple('InvisNode', ['name', 'is_existential']) invis_nodes = set() # type: Set['InvNode'] for t in transitions: # type: Transition all_nodes.add(t.src) inv_node = InvisNode(name=_gen_unique_name(), is_existential=t.src.is_existential) invis_nodes.add(inv_node) trans_dot += '"{src}" -> "{invisible}" [label="{label}"];'.format( src=t.src.name, invisible=inv_node.name, label=_label_to_short_string(t.state_label)) cubes = to_dnf_set(t.dst_expr) # type: List[List[Expr]] colors = 'black blue purple green yellow orange red brown pink gray'.split() for cube in cubes: # type: List[Expr] # each cube gets its own color color = colors.pop(0) if len(colors) else 'gray' for lit in cube: # type: BinOp assert lit.name == '=', "should be prop of the form sig=1; and not negated" dstFormProp = dstFormPropMgr.get_dst_form_prop(get_sig_number(lit)[0].name) trans_dot += '"{invisible}" -> "{dst}" [color={color}, label="{ext_label}"];'.format( invisible=inv_node.name, dst=dstFormProp.dst_state.name, color=color, ext_label=_ext_label_to_short_string(dstFormProp.ext_label)) all_nodes.add(dstFormProp.dst_state) # end of 'for t in aht.transitions' invis_nodes_dot = ['{n} [label="DNF", shape=box, fontsize=6, style=rounded, margin=0, width=0.3, height=0.2];' .format(n=n.name) for n in invis_nodes] nodes_dot = '\n'.join(['"{n}" [color="{color}", shape="{shape}" {initial}];' .format(n=n.name, color=('red', 'green')[n.is_existential], shape=('ellipse', 'doubleoctagon')[n.is_final], initial='' if n != (aht.init_node if aht else None) else ', style=filled, fillcolor=gray') for n in all_nodes]) dot_lines = StrAwareList() + 'digraph "automaton" {' + \ 'rankdir=LR;' + \ (('label="%s"' % aht.name) if aht else '') + \ nodes_dot + \ trans_dot +\ invis_nodes_dot +\ '}' return '\n'.join(dot_lines)