def z3_expression_to_nusmv(expression, tables=None, other_tables=None): z3_to_nusmv = { z3p.Z3_OP_AND: ' & ', z3p.Z3_OP_ADD: ' + ', z3p.Z3_OP_MOD: ' mod ', z3p.Z3_OP_EQ: ' = ', z3p.Z3_OP_LT: ' < ', z3p.Z3_OP_GT: ' > ' } kind = expression.decl().kind() if (z3p.is_const(expression) and expression.decl().name().startswith('table_')): assert tables is not None table_name = expression.decl().name() assert table_name in tables or table_name in other_tables table_expression = tables[ table_name] if table_name in tables else other_tables[table_name] case_expression = 'case ' for condition, result in table_expression: c = z3_expression_to_nusmv(condition, tables) r = z3_expression_to_nusmv(result, tables) case_expression += '{} : {}; '.format(c, r) case_expression += 'esac' return case_expression elif kind in z3_to_nusmv: children = [ z3_expression_to_nusmv(c, tables) for c in expression.children() ] return '({})'.format(z3_to_nusmv[kind].join(children)) elif expression == z3p.BoolVal(True): return 'TRUE' elif expression == z3p.BoolVal(False): return 'FALSE' elif kind == z3p.Z3_OP_NOT: e = z3_expression_to_nusmv(expression.arg(0)) return '!({})'.format(e) elif z3p.is_const(expression): return str(expression) elif kind == z3p.Z3_OP_ITE: guard = z3_expression_to_nusmv(expression.arg(0)) then_branch = z3_expression_to_nusmv(expression.arg(1)) else_branch = z3_expression_to_nusmv(expression.arg(2)) return '(case {} : {}; TRUE : {}; esac)'.format( guard, then_branch, else_branch) else: raise NotImplementedError( 'Cannot translate expression {} to nusmv.'.format(expression))
def translate_expression(self, e): if e == z3p.BoolVal(True): return 'TheLTS->MakeTrue()' elif e == z3p.BoolVal(False): return 'TheLTS->MakeFalse()' elif z3p.is_int_value(e): return 'TheLTS->MakeVal("{i}", TheLTS->MakeRangeType({i}, {i}))'.format(i=e) elif z3p.is_const(e) and e in self.channels: return self.translate_channel_reference(e) elif z3p.is_const(e): return '{}Exp'.format(to_camel_case(e.decl().name())) elif e.num_args() == 1: return self.translate_unary_expression(e) elif e.num_args() == 2 and e.decl().kind() == z3p.Z3_OP_SELECT: return self.translate_channel_reference(e) elif e.num_args() == 2: return self.translate_binary_expression(e) elif e.num_args() == 3: return self.translate_ternary_expreession(e) else: raise NotImplementedError("can't translate expression {} with {}".format(e, e.num_args()))
def z3_expression_to_nusmv(expression, tables=None, other_tables=None): z3_to_nusmv = {z3p.Z3_OP_AND: ' & ', z3p.Z3_OP_ADD: ' + ', z3p.Z3_OP_MOD: ' mod ', z3p.Z3_OP_EQ: ' = ', z3p.Z3_OP_LT: ' < ', z3p.Z3_OP_GT: ' > '} kind = expression.decl().kind() if (z3p.is_const(expression) and expression.decl().name().startswith('table_')): assert tables is not None table_name = expression.decl().name() assert table_name in tables or table_name in other_tables table_expression = tables[table_name] if table_name in tables else other_tables[table_name] case_expression = 'case ' for condition, result in table_expression: c = z3_expression_to_nusmv(condition, tables) r = z3_expression_to_nusmv(result, tables) case_expression += '{} : {}; '.format(c, r) case_expression += 'esac' return case_expression elif kind in z3_to_nusmv: children = [z3_expression_to_nusmv(c, tables) for c in expression.children()] return '({})'.format(z3_to_nusmv[kind].join(children)) elif expression == z3p.BoolVal(True): return 'TRUE' elif expression == z3p.BoolVal(False): return 'FALSE' elif kind == z3p.Z3_OP_NOT: e = z3_expression_to_nusmv(expression.arg(0)) return '!({})'.format(e) elif z3p.is_const(expression): return str(expression) elif kind == z3p.Z3_OP_ITE: guard = z3_expression_to_nusmv(expression.arg(0)) then_branch = z3_expression_to_nusmv(expression.arg(1)) else_branch = z3_expression_to_nusmv(expression.arg(2)) return '(case {} : {}; TRUE : {}; esac)'.format(guard, then_branch, else_branch) else: raise NotImplementedError('Cannot translate expression {} to nusmv.'.format(expression))
def inputs_in_constraints_for_function(self, function_name, table): retval = [] for constraint in self.constraints: expressions = [constraint] while len(expressions) > 0: expression = expressions.pop() if not z3p.is_const(expression): if expression.decl().name() == function_name: retval.append(expression) else: for i in range(expression.num_args()): expressions.append(expression.arg(i)) return retval
def selects_in_expression(expression): expressions = [expression] selects = [] while len(expressions) > 0: expression = expressions.pop(0) if z3p.is_const(expression): continue elif z3p.is_app(expression): if expression.decl().kind() == z3p.Z3_OP_SELECT: selects.append(expression) else: for i in range(expression.num_args()): expressions.append(expression.arg(i)) return selects
def evaluate_expression(expression, symbolic_memory, concrete_memory, tables=None): if isinstance(expression, int): return expression if isinstance(expression, tuple): return expression if z3p.is_const(expression): if z3p.is_bool_or_int_value(expression): return expression if expression in symbolic_memory: return symbolic_memory[expression] elif expression.decl().name().startswith('table_'): assert expression.decl().name() in tables table_expression = tables[expression.decl().name()] first_value = table_expression[0][1] if first_value.sort() == z3p.IntSort(): last_else = z3p.IntVal(0) else: last_else = z3p.BoolVal(False) if_expression = None for conditional, value in table_expression: guard = evaluate_expression(conditional, symbolic_memory, concrete_memory) last_else = z3p.If(guard, value, last_else) return z3p.simplify(last_else) else: return concrete_memory[expression] elif expression.decl().kind() == z3p.Z3_OP_SELECT: if expression in symbolic_memory: return symbolic_memory[expression] else: return concrete_memory[expression] else: new_args = [ evaluate_expression(expression.arg(i), symbolic_memory, concrete_memory, tables) for i in range(expression.num_args()) ] if expression.decl().kind() == z3p.Z3_OP_AND: return z3p.And(*new_args) else: return expression.decl()(*new_args)
def evaluate_expression(expression, symbolic_memory, concrete_memory, tables=None): if isinstance(expression, int): return expression if isinstance(expression, tuple): return expression if z3p.is_const(expression): if z3p.is_bool_or_int_value(expression): return expression if expression in symbolic_memory: return symbolic_memory[expression] elif expression.decl().name().startswith('table_'): assert expression.decl().name() in tables table_expression = tables[expression.decl().name()] first_value = table_expression[0][1] if first_value.sort() == z3p.IntSort(): last_else = z3p.IntVal(0) else: last_else = z3p.BoolVal(False) if_expression = None for conditional, value in table_expression: guard = evaluate_expression(conditional, symbolic_memory, concrete_memory) last_else = z3p.If(guard, value, last_else) return z3p.simplify(last_else) else: return concrete_memory[expression] elif expression.decl().kind() == z3p.Z3_OP_SELECT: if expression in symbolic_memory: return symbolic_memory[expression] else: return concrete_memory[expression] else: new_args = [evaluate_expression(expression.arg(i), symbolic_memory, concrete_memory, tables) for i in range(expression.num_args())] if expression.decl().kind() == z3p.Z3_OP_AND: return z3p.And(*new_args) else: return expression.decl()(*new_args)
def __init__(self, name, locations, initial_location, transitions, variables=None, initial_values=None, input_channels=None, output_channels=None, tables=None, variable_ranges=None, output_channel_ranges=None, compassion=None, justice=None): """ Every node represents a control location and has a unique name. Transitions are of the form (soruce, channel[, channel expression], guard, update, target) where source and target must be automaton control locations, channel an input or output channel, channel expression is there if the channel is an output one, guard is a z3 boolean expression, update is a pair (variable, expression). """ super(SymbolicAutomaton, self).__init__() self.name = name self.variables = variables if variables is not None else [] self.transitions = transitions self.initial_values = initial_values if initial_values is not None else [] self.initials = {} for v, value in zip(self.variables, self.initial_values): self.initials[v] = value assert len(self.variables) == len(self.initial_values), "# of initial values should match # of variables: variables {}, initials: {}".format(self.variables, self.initial_values) self.variable_initial_value = dict(zip([str(v) for v in self.variables], self.initial_values)) # TODO change this to work with uninitialized variables # change variables input to include initial values self.input_channels = input_channels if input_channels is not None else [] self.output_channels = output_channels if output_channels is not None else [] # add channel with unit type unit can be an mtype with just one symbol for l in locations: self.add_node(l) for transition in transitions: channel_expression = [] # if it is an input transition, there is no expression for the message to send if len(transition) == 6: name, source, channel, guard, update, target = transition assert channel not in self.output_channels, "Output channel {} used in input transition {}".format(channel, transition) kind = 'input' # output transitions elif len(transition) == 7: name, source, channel, channel_expression, guard, update, target = transition assert channel not in self.input_channels, "Input channel {} used in output transition {}".format(channel, transition) kind = 'output' # internal transitios elif len(transition) == 5: name, source, guard, update, target = transition channel = None assert source in locations and target in locations, transition assert (channel in self.input_channels or channel in self.output_channels or channel is None), transition if channel is None: kind = 'internal' if name is None: name = 't_{}'.format(self.number_of_edges()) self.add_edge(source, target, channel=channel, channel_expression=channel_expression, guard=guard, update=update, name=name, kind=kind, automaton=self) assert initial_location in self.nodes() self.initial_location = initial_location self.tables = {} if tables is None else tables self.channel_edges = {} self.update_channel_edges() self.changes = [] self.transition_variables = {} self.update_transition_variables() self.variable_ranges = {} if variable_ranges is None else variable_ranges self.output_channel_ranges = {} if output_channel_ranges is None else output_channel_ranges for v in self.variables: if v.sort() == z3p.IntSort(): assert v in self.variable_ranges, "No range declared for {}".format(v) for variable, variable_range in self.variable_ranges.items(): assert variable in self.variables, "Variable {} was not declared".format(variable) assert variable.sort() == z3p.IntSort() assert isinstance(variable_range, tuple) and len(variable_range) == 2 assert isinstance(variable_range[0], int) assert isinstance(variable_range[1], int) assert variable_range[0] <= variable_range[1] for output_channel_or_field, output_channel_range in self.output_channel_ranges.items(): if not z3p.is_const(output_channel_or_field) and output_channel_or_field.decl().kind() == z3p.Z3_OP_SELECT: assert output_channel_or_field.arg(0) in self.output_channels else: assert output_channel_or_field in self.output_channels # assert output_channel.sort() == z3p.IntSort() assert isinstance(output_channel_range, tuple) and len(output_channel_range) == 2 assert isinstance(output_channel_range[0], int) assert isinstance(output_channel_range[1], int) assert output_channel_range[0] < output_channel_range[1] if compassion is not None: self.compassion = compassion else: self.compassion = [] if justice is not None: self.justice = justice else: self.justice = []