def substitute_hole_in_expression(self, expression, pairs): """ Expression is a z3 expression, and pairs is a list of pairs of the form (function declaration representing hole, substitute) For now substitute can only be a value. TODO: change this so substitute can be a conditional expression as well. The latter will require to introduce a 'table variable'. """ assert z3p.is_expr(expression) holes = [pair[0] for pair in pairs] if z3p.is_bool_or_int_value(expression): return expression if z3p.is_app(expression): declaration = expression.decl() for hole, substitute in pairs: if declaration == hole: input_variables = [expression.arg(i) for i in range(expression.num_args())] conditional = constraint_model.lookup_table_to_conditional_expression(substitute, input_variables) # introduce table variable and add table declaration in tables table_id = len(self.tables.keys()) table_var_name = 'table_{}'.format(table_id) self.tables[table_var_name] = conditional return z3p.Const(table_var_name, hole.range()) if expression.num_args() == 2: expression1 = self.substitute_hole_in_expression(expression.arg(0), pairs) expression2 = self.substitute_hole_in_expression(expression.arg(1), pairs) operator = expression.decl() return operator(expression1, expression2) return expression
def lookup_table_for_function(self, function_name): """Returns a model for the function as a dictionary. The dictionary has tuples of argument values as keys. In particular, if the function has a single argument, the key will still be a single element tuple. """ assert (function_name in self.function_names and function_name in self.z3_functions_by_name) z3_function = self.z3_functions_by_name[function_name] model = self.solver.model() table = {} for i in self.function_name_to_domain_values[function_name]: table[i] = model.evaluate(z3_function(i)) # If a value is unconstrained the z3 model might just return # a variable back, therefore for the boolean case if not z3p.is_bool_or_int_value(table[i]) and table[i].sort() == z3p.BoolSort(): # a constant value is returned here. table[i] = z3p.BoolVal(False) return table
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 lookup_table_for_function(self, function_name): """Returns a model for the function as a dictionary. The dictionary has tuples of argument values as keys. In particular, if the function has a single argument, the key will still be a single element tuple. """ assert (function_name in self.function_names and function_name in self.z3_functions_by_name) z3_function = self.z3_functions_by_name[function_name] model = self.solver.model() table = {} for i in self.function_name_to_domain_values[function_name]: table[i] = model.evaluate(z3_function(i)) # If a value is unconstrained the z3 model might just return # a variable back, therefore for the boolean case if not z3p.is_bool_or_int_value( table[i]) and table[i].sort() == z3p.BoolSort(): # a constant value is returned here. table[i] = z3p.BoolVal(False) return table
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)