def _preprocess_(cls, variables, formula): variables = tuple(variables) if set(variables) != free_variables(formula): raise IvyError("Free variables {} must match formula: {}".format(variables, formula)) if not all(type(v) is Var and first_order_sort(v.sort) for v in variables): raise IvyError("Concept variables must be first-order: {}".format(variables)) return variables, formula
def suppose_empty(self, concept): self.push() f = self.domain.concepts[concept].formula self.suppose_constraints.append( ForAll(free_variables(f), Not(f)) ) self.recompute()
def is_epr_rec(term, uvars): if is_forall(term): return is_epr_rec(term.body, frozenset.union(uvars, term.variables)) if is_exists(term): if frozenset.intersection(lu.free_variables(term), uvars): return False return is_epr_rec(term.body, frozenset()) return all(is_epr_rec(a, uvars) for a in term.args)
def is_epr_rec(term,uvars): if is_forall(term): return is_epr_rec(term.body,frozenset.union(uvars,term.variables)) if is_exists(term): if frozenset.intersection(lu.free_variables(term),uvars): return False return is_epr_rec(term.body,frozenset()) return all(is_epr_rec(a,uvars) for a in term.args)
def rename_vars_no_clash(fmlas1,fmlas2): """ Rename the free variables in formula list fmlas1 so they occur nowhere in fmlas2, avoiding capture """ uvs = lu.used_variables(*fmlas2) uvs = lu.union(uvs,lu.bound_variables(*fmlas1)) rn = iu.UniqueRenamer('',(v.name for v in uvs)) vs = lu.free_variables(*fmlas1) vmap = dict((v,Variable(rn(v.name),v.sort)) for v in vs) return [lu.substitute(f,vmap) for f in fmlas1]
def rename_vars_no_clash(fmlas1, fmlas2): """ Rename the free variables in formula list fmlas1 so they occur nowhere in fmlas2, avoiding capture """ uvs = lu.used_variables(*fmlas2) uvs = lu.union(uvs, lu.bound_variables(*fmlas1)) rn = iu.UniqueRenamer('', (v.name for v in uvs)) vs = lu.free_variables(*fmlas1) vmap = dict((v, Variable(rn(v.name), v.sort)) for v in vs) return [lu.substitute(f, vmap) for f in fmlas1]
def _preprocess_(cls, name, variables, formula): if not isinstance(name,str): raise IvyError("Concept name {} is not a string".format(name)) variables = tuple(variables) if set(variables) != free_variables(formula): raise IvyError("Free variables {} must match formula: {}".format(variables, formula)) if not all(type(v) is Var and first_order_sort(v.sort) for v in variables): raise IvyError("Concept variables must be first-order: {}".format(variables)) return name,variables, formula
def _preprocess_(cls, variables, formula): variables = tuple(variables) if set(variables) != free_variables(formula): raise IvyError("Free variables {} must match formula: {}".format(variables, formula)) if not all(type(v) is Var and type(v.sort) is FunctionSort and v.sort.range == Boolean for v in variables): raise IvyError("ConceptCombiner variables must be relational: {}".format(variables)) return variables, formula
def emit_clear_progress(impl, obj=None): for df in im.module.progress: vs = list(lu.free_variables(df.args[0])) open_loop(impl, vs) code = [] indent(code) if obj != None: code.append('obj.') df.args[0].emit(impl, code) code.append(' = 0;\n') impl.extend(code) close_loop(impl, vs)
def emit_clear_progress(impl,obj=None): for df in im.module.progress: vs = list(lu.free_variables(df.args[0])) open_loop(impl,vs) code = [] indent(code) if obj != None: code.append('obj.') df.args[0].emit(impl,code) code.append(' = 0;\n') impl.extend(code) close_loop(impl,vs)
def get_sort_arcs(assumes, asserts): for sym in il.all_symbols(): name = sym.name sort = sym.sort rng = sort.rng if il.is_uninterpreted_sort(rng): for ds in sort.dom: if il.is_uninterpreted_sort(ds): yield (ds, rng, sym) for fmla, ast in assumes + asserts: for a in get_qa_arcs(fmla, ast, True, list(lu.free_variables(fmla))): yield a for fmla, ast in asserts: for a in get_qa_arcs(fmla, ast, False, []): yield a
def get_selected_conjecture(self): """ Return a positive universal conjecture based on the selected facts. The result is a Clauses object """ from logic_util import used_constants, free_variables, substitute from ivy_logic_utils import negate, Clauses, simplify_clauses facts = self.get_active_facts() assert len(free_variables( * facts)) == 0, "conjecture would contain existential quantifiers..." sig_symbols = frozenset(il.sig.symbols.values()) facts_consts = used_constants(*facts) subs = {} rn = iu.VariableGenerator() for c in sorted(facts_consts, key=lambda c: c.name): if c.is_numeral() and il.is_uninterpreted_sort(c.sort): # prefix = str(c.sort)[:2].upper() + c.name subs[c] = lg.Var(rn(c.sort.name), c.sort) literals = [negate(substitute(f, subs)) for f in facts] result = Clauses([lg.Or(*literals)]) result = simplify_clauses(result) # now rename again to get a pretty clause, since some # variables have been eliminated by simplify_clauses # assert len(result.fmlas) == 1 # clause = result.fmlas[0] # subs = {} # count = defaultdict(int) # for c in free_variables(clause): # prefix = str(c.sort)[0].upper() # count[prefix] += 1 # subs[c] = lg.Var(prefix + str(count[prefix]), c.sort) # result = Clauses([substitute(clause, subs)]) # change to negation of conjunction rather than disjunction assert len(result.fmlas) == 1 if type(result.fmlas[0]) is lg.Or: result = Clauses( [lg.Not(lg.And(*(negate(lit) for lit in result.fmlas[0])))]) return result
def emit_assign(self, header): global indent_level vs = list(lu.free_variables(self.args[0])) if len(vs) == 0: emit_assign_simple(self, header) return global temp_ctr tmp = '__tmp' + str(temp_ctr) temp_ctr += 1 indent(header) header.append('int ' + tmp) for v in vs: header.append('[' + str(sort_card(v.sort)) + ']') header.append(';\n') for idx in vs: indent(header) header.append('for (int ' + str(idx) + ' = 0; ' + str(idx) + ' < ' + str(sort_card(idx.sort)) + '; ' + str(idx) + '++) {\n') indent_level += 1 code = [] indent(code) code.append(tmp + ''.join('[' + varname(v.name) + ']' for v in vs) + ' = ') self.args[1].emit(header, code) code.append(';\n') header.extend(code) for idx in vs: indent_level -= 1 indent(header) header.append('}\n') for idx in vs: indent(header) header.append('for (int ' + str(idx) + ' = 0; ' + str(idx) + ' < ' + str(sort_card(idx.sort)) + '; ' + str(idx) + '++) {\n') indent_level += 1 code = [] indent(code) self.args[0].emit(header, code) code.append(' = ' + tmp + ''.join('[' + varname(v.name) + ']' for v in vs) + ';\n') header.extend(code) for idx in vs: indent_level -= 1 indent(header) header.append('}\n')
def concretize_terms(terms, sorts=None): """ Concretize the sorts in a list of terms. Free variables must have the same sort in all terms. The list 'sorts' gives a sort upper bound for each term (use TopS to leave the sort unspecified). """ # give sort names to all the free variables and constants: names = free_variables(*terms, by_name=True).union(x.name for x in used_constants(*terms)) env = dict((name, SortVar()) for name in names) pairs = [infer_sorts(term, env) for term in terms] if sorts is not None: for (s, tt), sort in zip(pairs, sorts): unify(s, sort) return [tt() for s, tt in pairs]
def concretize_terms(terms,sorts=None): """ Concretize the sorts in a list of terms. Free variables must have the same sort in all terms. The list 'sorts' gives a sort upper bound for each term (use TopS to leave the sort unspecified). """ # give sort names to all the free variables and constants: names = free_variables(*terms, by_name=True).union( x.name for x in used_constants(*terms) ) env = dict((name, SortVar()) for name in names) pairs = [infer_sorts(term,env) for term in terms] if sorts is not None: for (s,tt),sort in zip(pairs,sorts): unify(s,sort) return [tt() for s,tt in pairs]
def get_selected_conjecture(self): """ Return a positive universal conjecture based on the selected facts. The result is a Clauses object """ from logic_util import used_constants, free_variables, substitute from ivy_logic_utils import negate, Clauses, simplify_clauses facts = self.get_active_facts() assert len(free_variables(*facts)) == 0, "conjecture would contain existential quantifiers..." sig_symbols = frozenset(il.sig.symbols.values()) facts_consts = used_constants(*facts) subs = {} rn = iu.UniqueRenamer() for c in sorted(facts_consts, key=lambda c: c.name): if c.is_numeral() and il.is_uninterpreted_sort(c.sort): prefix = str(c.sort)[:2].upper() + str(c) subs[c] = lg.Var(rn(prefix), c.sort) literals = [negate(substitute(f, subs)) for f in facts] result = Clauses([lg.Or(*literals)]) result = simplify_clauses(result) # now rename again to get a pretty clause, since some # variables have been eliminated by simplify_clauses # assert len(result.fmlas) == 1 # clause = result.fmlas[0] # subs = {} # count = defaultdict(int) # for c in free_variables(clause): # prefix = str(c.sort)[0].upper() # count[prefix] += 1 # subs[c] = lg.Var(prefix + str(count[prefix]), c.sort) # result = Clauses([substitute(clause, subs)]) # change to negation of conjunction rather than disjunction assert len(result.fmlas) == 1 if type(result.fmlas[0]) is lg.Or: result = Clauses([lg.Not(lg.And(*(negate(lit) for lit in result.fmlas[0])))]) return result
def emit_assign(self,header): global indent_level vs = list(lu.free_variables(self.args[0])) if len(vs) == 0: emit_assign_simple(self,header) return global temp_ctr tmp = '__tmp' + str(temp_ctr) temp_ctr += 1 indent(header) header.append('int ' + tmp) for v in vs: header.append('[' + str(sort_card(v.sort)) + ']') header.append(';\n') for idx in vs: indent(header) header.append('for (int ' + str(idx) + ' = 0; ' + str(idx) + ' < ' + str(sort_card(idx.sort)) + '; ' + str(idx) + '++) {\n') indent_level += 1 code = [] indent(code) code.append(tmp + ''.join('['+varname(v.name)+']' for v in vs) + ' = ') self.args[1].emit(header,code) code.append(';\n') header.extend(code) for idx in vs: indent_level -= 1 indent(header) header.append('}\n') for idx in vs: indent(header) header.append('for (int ' + str(idx) + ' = 0; ' + str(idx) + ' < ' + str(sort_card(idx.sort)) + '; ' + str(idx) + '++) {\n') indent_level += 1 code = [] indent(code) self.args[0].emit(header,code) code.append(' = ' + tmp + ''.join('['+varname(v.name)+']' for v in vs) + ';\n') header.extend(code) for idx in vs: indent_level -= 1 indent(header) header.append('}\n')
def get_sort_arcs(assumes,asserts,strat_map): # for sym in il.all_symbols(): # name = sym.name # sort = sym.sort # rng = sort.rng # if il.is_uninterpreted_sort(rng): # for ds in sort.dom: # if il.is_uninterpreted_sort(ds): # yield (ds,rng,sym) # show_strat_map(strat_map) for func,node in list(strat_map.iteritems()): if isinstance(func,tuple) and not il.is_interpreted_symbol(func[0]): yield (find(node),find(strat_map[func[0]]),func[0]) for fmla,ast in assumes + asserts: for a in get_qa_arcs(fmla,ast,True,list(lu.free_variables(fmla)),strat_map): yield a for fmla,ast in asserts: for a in get_qa_arcs(fmla,ast,False,[],strat_map): yield a
def is_alternation_free(term): return is_prenex_universal( term) or is_prenex_existential(term) and not lu.free_variables(term)
def close_formula(fmla): variables = list(lu.free_variables(fmla)) if variables == []: return fmla else: return ForAll(variables, fmla)
def _suppose_empty(self,concept): f = self.domain.concepts[concept].formula self.suppose_constraints.append( ForAll(free_variables(f), Not(f)) )
def is_in_logic(term,logic): assert logic in logics if logic == "epr": if lu.free_variables(term): return is_prenex_universal(term) return is_ea(term)
def _suppose_empty(self, concept): f = self.domain.concepts[concept].formula self.suppose_constraints.append(ForAll(free_variables(f), Not(f)))
def is_alternation_free(term): return is_prenex_universal(term) or is_prenex_existential(term) and not lu.free_variables(term)
def emit_tick(header,impl,classname): global indent_level indent_level += 1 indent(header) header.append('void __tick(int timeout);\n') indent_level -= 1 indent(impl) impl.append('void ' + classname + '::__tick(int __timeout){\n') indent_level += 1 rely_map = defaultdict(list) for df in im.module.rely: key = df.args[0] if isinstance(df,il.Implies) else df rely_map[key.rep].append(df) for df in im.module.progress: vs = list(lu.free_variables(df.args[0])) open_loop(impl,vs) code = [] indent(code) df.args[0].emit(impl,code) code.append(' = ') df.args[1].emit(impl,code) code.append(' ? 0 : ') df.args[0].emit(impl,code) code.append(' + 1;\n') impl.extend(code) close_loop(impl,vs) for df in im.module.progress: if any(not isinstance(r,il.Implies) for r in rely_map[df.defines()]): continue vs = list(lu.free_variables(df.args[0])) open_loop(impl,vs) maxt = new_temp(impl) indent(impl) impl.append(maxt + ' = 0;\n') for r in rely_map[df.defines()]: if not isinstance(r,il.Implies): continue rvs = list(lu.free_variables(r.args[0])) assert len(rvs) == len(vs) subs = dict(zip(rvs,vs)) ## TRICKY: If there are any free variables on rhs of ## rely not occuring on left, we must prevent their capture ## by substitution xvs = set(lu.free_variables(r.args[1])) xvs = xvs - set(rvs) for xv in xvs: subs[xv.name] = xv.rename(xv.name + '__') xvs = [subs[xv.name] for xv in xvs] e = ilu.substitute_ast(r.args[1],subs) open_loop(impl,xvs) indent(impl) impl.append('{} = std::max({},'.format(maxt,maxt)) e.emit(impl,impl) impl.append(');\n') close_loop(impl,xvs) indent(impl) impl.append('if (' + maxt + ' > __timeout)\n ') indent(impl) df.args[0].emit(impl,impl) impl.append(' = 0;\n') indent(impl) impl.append('ivy_check_progress(') df.args[0].emit(impl,impl) impl.append(',{});\n'.format(maxt)) close_loop(impl,vs) indent_level -= 1 indent(impl) impl.append('}\n')
def emit_tick(header, impl, classname): global indent_level indent_level += 1 indent(header) header.append('void __tick(int timeout);\n') indent_level -= 1 indent(impl) impl.append('void ' + classname + '::__tick(int __timeout){\n') indent_level += 1 rely_map = defaultdict(list) for df in im.module.rely: key = df.args[0] if isinstance(df, il.Implies) else df rely_map[key.rep].append(df) for df in im.module.progress: vs = list(lu.free_variables(df.args[0])) open_loop(impl, vs) code = [] indent(code) df.args[0].emit(impl, code) code.append(' = ') df.args[1].emit(impl, code) code.append(' ? 0 : ') df.args[0].emit(impl, code) code.append(' + 1;\n') impl.extend(code) close_loop(impl, vs) for df in im.module.progress: if any(not isinstance(r, il.Implies) for r in rely_map[df.defines()]): continue vs = list(lu.free_variables(df.args[0])) open_loop(impl, vs) maxt = new_temp(impl) indent(impl) impl.append(maxt + ' = 0;\n') for r in rely_map[df.defines()]: if not isinstance(r, il.Implies): continue rvs = list(lu.free_variables(r.args[0])) assert len(rvs) == len(vs) subs = dict(zip(rvs, vs)) ## TRICKY: If there are any free variables on rhs of ## rely not occuring on left, we must prevent their capture ## by substitution xvs = set(lu.free_variables(r.args[1])) xvs = xvs - set(rvs) for xv in xvs: subs[xv.name] = xv.rename(xv.name + '__') xvs = [subs[xv.name] for xv in xvs] e = ilu.substitute_ast(r.args[1], subs) open_loop(impl, xvs) indent(impl) impl.append('{} = std::max({},'.format(maxt, maxt)) e.emit(impl, impl) impl.append(');\n') close_loop(impl, xvs) indent(impl) impl.append('if (' + maxt + ' > __timeout)\n ') indent(impl) df.args[0].emit(impl, impl) impl.append(' = 0;\n') indent(impl) impl.append('ivy_check_progress(') df.args[0].emit(impl, impl) impl.append(',{});\n'.format(maxt)) close_loop(impl, vs) indent_level -= 1 indent(impl) impl.append('}\n')
def infer_sorts(t, env=None): """ Infer the sort of term t in environment env. env maps symbol names to sort variables. The result is a pair: (s, tt) where s is a sort or sort variable with the sort of t in env, and tt is a closure that, when called, will concretize t according to inferred sort information at its call time. If env is not None, it must contain all the free variables and constants used in t. """ if env is None: names = free_variables(t, by_name=True).union( x.name for x in used_constants(t) ) env = dict((name, SortVar()) for name in names) if type(t) in (Var, Const): if is_polymorphic(t): # each instance can have different sort s = insert_sortvars(t.sort,{}) else: s = env[t.name] unify(s, t.sort) return s, lambda: type(t)(t.name, convert_from_sortvars(s)) elif type(t) is Apply: func_s, func_t = infer_sorts(t.func, env) xys = [infer_sorts(tt, env) for tt in t.terms] terms_s = [x for x, y in xys] terms_t = [y for x, y in xys] sorts = terms_s + [SortVar()] unify(func_s, FunctionSort(*sorts)) return sorts[-1], lambda: Apply(func_t(), *( x() for x in terms_t )) elif type(t) is Eq: s1, t1 = infer_sorts(t.t1, env) s2, t2 = infer_sorts(t.t2, env) unify(s1, s2) return Boolean, lambda: Eq(t1(), t2()) elif type(t) is Ite: s_cond, t_cond = infer_sorts(t.cond, env) s_then, t_then = infer_sorts(t.t_then, env) s_else, t_else = infer_sorts(t.t_else, env) unify(s_cond, Boolean) unify(s_then, s_else) return s_then, lambda: Ite(t_cond(), t_then(), t_else()) elif type(t) in (Not, And, Or, Implies, Iff): xys = [infer_sorts(tt, env) for tt in t] terms_s = [x for x, y in xys] terms_t = [y for x, y in xys] for s in terms_s: unify(s, Boolean) return Boolean, lambda: type(t)(*[ x() for x in terms_t ]) elif type(t) in (ForAll, Exists): # create a copy of the environment and shadow that quantified # variables env = env.copy() env.update((v.name, SortVar()) for v in t.variables) vars_t = [infer_sorts(v, env)[1] for v in t.variables] body_s, body_t = infer_sorts(t.body, env) unify(body_s, Boolean) return Boolean, lambda: type(t)( [x() for x in vars_t], body_t(), ) elif hasattr(t,'clone'): xys = [infer_sorts(tt, env) for tt in t.args] terms_t = [y for x, y in xys] return TopSort(), lambda: t.clone([ x() for x in terms_t ]) else: assert False, type(t)
def infer_sorts(t, env=None): """ Infer the sort of term t in environment env. env maps symbol names to sort variables. The result is a pair: (s, tt) where s is a sort or sort variable with the sort of t in env, and tt is a closure that, when called, will concretize t according to inferred sort information at its call time. If env is not None, it must contain all the free variables and constants used in t. """ if env is None: names = free_variables(t, by_name=True).union(x.name for x in used_constants(t)) env = dict((name, SortVar()) for name in names) if type(t) in (Var, Const): if is_polymorphic(t): # each instance can have different sort s = insert_sortvars(t.sort, {}) else: s = env[t.name] unify(s, t.sort) return s, lambda: type(t)(t.name, convert_from_sortvars(s)) elif type(t) is Apply: func_s, func_t = infer_sorts(t.func, env) xys = [infer_sorts(tt, env) for tt in t.terms] terms_s = [x for x, y in xys] terms_t = [y for x, y in xys] sorts = terms_s + [SortVar()] unify(func_s, FunctionSort(*sorts)) return sorts[-1], lambda: Apply(func_t(), *(x() for x in terms_t)) elif type(t) is Eq: s1, t1 = infer_sorts(t.t1, env) s2, t2 = infer_sorts(t.t2, env) unify(s1, s2) return Boolean, lambda: Eq(t1(), t2()) elif type(t) is Ite: s_cond, t_cond = infer_sorts(t.cond, env) s_then, t_then = infer_sorts(t.t_then, env) s_else, t_else = infer_sorts(t.t_else, env) unify(s_cond, Boolean) unify(s_then, s_else) return s_then, lambda: Ite(t_cond(), t_then(), t_else()) elif type(t) in (Not, And, Or, Implies, Iff): xys = [infer_sorts(tt, env) for tt in t] terms_s = [x for x, y in xys] terms_t = [y for x, y in xys] for s in terms_s: unify(s, Boolean) return Boolean, lambda: type(t)(*[x() for x in terms_t]) elif type(t) in (ForAll, Exists): # create a copy of the environment and shadow that quantified # variables env = env.copy() env.update((v.name, SortVar()) for v in t.variables) vars_t = [infer_sorts(v, env)[1] for v in t.variables] body_s, body_t = infer_sorts(t.body, env) unify(body_s, Boolean) return Boolean, lambda: type(t)( [x() for x in vars_t], body_t(), ) elif hasattr(t, 'clone'): xys = [infer_sorts(tt, env) for tt in t.args] terms_t = [y for x, y in xys] return TopSort(), lambda: t.clone([x() for x in terms_t]) else: assert False, type(t)
def is_epr(term): return is_epr_rec(term,lu.free_variables(term))
def close_formula(fmla): variables = list(lu.free_variables(fmla)) if variables == []: return fmla else: return ForAll(variables,fmla)
def is_epr(term): return is_epr_rec(term, lu.free_variables(term))
def is_in_logic(term, logic): assert logic in logics if logic == "epr": if lu.free_variables(term): return is_prenex_universal(term) return is_ea(term)