def update_blackboard(self, B): """ Saturates a Blackboard B with additive inferences. """ timer.start(timer.PADD) messages.announce_module('polyhedron additive module') # learn_additive_sign_info(blackboard) comparisons = get_additive_information(B) h_matrix = lrs_util.create_h_format_matrix(comparisons, B.num_terms) messages.announce('Halfplane matrix:', messages.DEBUG) messages.announce(h_matrix, messages.DEBUG) v_matrix, v_lin_set = lrs_util.get_vertices(h_matrix) messages.announce('Vertex matrix:', messages.DEBUG) #messages.announce(str(v_matrix), messages.DEBUG) for l in v_matrix: messages.announce(str(l), messages.DEBUG) messages.announce('Linear set:', messages.DEBUG) messages.announce(str(v_lin_set), messages.DEBUG) new_comparisons = get_2d_comparisons(v_matrix, v_lin_set) for c in new_comparisons: B.assert_comparison(c) timer.stop(timer.PADD)
def update_blackboard(self, B): """ Instantiates all stored axioms with respect to B and asserts new clauses. """ timer.start(timer.FUN) messages.announce_module('axiom module') n = B.num_terms + len(B.equalities.keys()) + len(B.zero_equalities) #if n == self.num_eqs: # messages.announce("No new information for the axiom module to use.", messages.DEBUG) # timer.stop(timer.FUN) # return self.num_eqs = n for a in self.axioms: messages.announce("Instantiating axiom: {}".format(a), messages.DEBUG) if a.unifiable: clauses = instantiate(a, self.used_envs, B) for c in clauses: B.assert_clause(*c) else: clauses = instantiate_triggerless(a, self.used_envs, B) for c in clauses: B.assert_clause(*c) timer.stop(timer.FUN)
def update_blackboard(self, B): """ Adds axioms for sin, cos, tan, floor """ timer.start(timer.BUILTIN) ts = [B.term_defs[i] for i in range(B.num_terms)] funcs = [t.func.name for t in ts if isinstance(t, terms.FuncTerm)] if (not self.added['sin'] and 'sin' in funcs): self.am.add_axioms(sin_axioms) self.added['sin'] = True if (not self.added['cos'] and 'cos' in funcs): self.am.add_axioms(cos_axioms) self.added['cos'] = True if (not self.added['tan'] and 'tan' in funcs): self.am.add_axioms(tan_axioms) self.added['tan'] = True if (not self.added['floor'] and 'floor' in funcs): self.am.add_axioms(floor_axioms) self.added['floor'] = True if (not self.added['abs'] and 'abs' in funcs): self.am.add_axioms(abs_axioms) self.added['abs'] = True timer.stop(timer.BUILTIN)
def update_blackboard(self, B): """ Learns equalities and inequalities from additive information in B, and asserts them to B. """ timer.start(timer.FMADD) messages.announce_module('Fourier-Motzkin additive module') eqs, comps = get_additive_information(B) for i in range(B.num_terms): # at this point, eqs and comps have all comparisons with indices >= i i_eqs, i_comps = eqs, comps # determine all comparisons with IVar(i) and IVar(j) with j >= i for j in range(i + 1, B.num_terms): # at this point, i_eqs and i_comps have all comparisons with i and indices >= j ij_eqs, ij_comps = i_eqs, i_comps # determine all comparisons between IVar(i) and IVar(j) for k in range(j + 1, B.num_terms): ij_eqs, ij_comps = elim(ij_eqs, ij_comps, k) assert_comparisons_to_blackboard(ij_eqs, ij_comps, B) # done with IVar(j) i_eqs, i_comps = elim(i_eqs, i_comps, j) # add this point, i_eqs and i_comps contain only comparisons with IVar(i) alone assert_comparisons_to_blackboard(i_eqs, i_comps, B) # done with IVar(i) eqs, comps = elim(eqs, comps, i) timer.stop(timer.FMADD)
def update_blackboard(self, B): """ Adds axioms corresponding to each nth root function present. """ messages.announce_module('nth root value module') timer.start(timer.ROOT) #nth_roots = [] def is_nth_root_term(i): """ Returns True if t_i is of the form abs(t_j). """ return (isinstance(B.term_defs[i], terms.FuncTerm) and isinstance(B.term_defs[i].func, terms.NthRoot)) def root_degree(i): """ If t_i is of the form NthRoot(n, t_j), returns n. """ return B.term_defs[i].func.n nth_roots = set([root_degree(i) for i in range(B.num_terms) if is_nth_root_term(i)]) x = terms.Var('x') for n in nth_roots: if n % 2 == 0: self.am.add_axiom(formulas.Forall([x], formulas.Implies(x >= 0, terms.root(n, x) ** n == x))) self.am.add_axiom(formulas.Forall([x], formulas.Implies(x >= 0, terms.root(n, x) >= 0))) else: self.am.add_axiom(formulas.Forall([x], terms.root(n, x) ** n == x)) timer.stop(timer.ROOT)
def update_blackboard(self, B): """ Learns sign information and equalities and inequalities from multiplicative information in B, and asserts them to B. """ timer.start(timer.FMMUL) messages.announce_module('Fourier-Motzkin multiplicative module') mul_util.derive_info_from_definitions(B) mul_util.preprocess_cancellations(B) eqs, comps = get_multiplicative_information(B) # t0 = 1; ignore for i in range(1, B.num_terms): # at this point, eqs and comps have all comparisons with indices >= i i_eqs, i_comps = eqs, comps # determine all comparisons with IVar(i) and IVar(j) with j >= i for j in range(i + 1, B.num_terms): # at this point, i_eqs and i_comps have all comparisons with i and indices >= j ij_eqs, ij_comps = i_eqs, i_comps # determine all comparisons between IVar(i) and IVar(j) for k in range(j + 1, B.num_terms): ij_eqs, ij_comps = elim(ij_eqs, ij_comps, k) #print 'comps:', ij_comps assert_comparisons_to_blackboard(ij_eqs, ij_comps, B) # done with IVar(j) i_eqs, i_comps = elim(i_eqs, i_comps, j) # add this point, i_eqs and i_comps contain only comparisons with IVar(i) alone assert_comparisons_to_blackboard(i_eqs, i_comps, B) # done with IVar(i) eqs, comps = elim(eqs, comps, i) timer.stop(timer.FMMUL)
def update_blackboard(self, B): """ Saturates a Blackboard B with multiplicative inferences. """ timer.start(timer.PMUL) messages.announce_module('polyhedron multiplicative module') mul_util.derive_info_from_definitions(B) mul_util.preprocess_cancellations(B) m_comparisons = mul_util.get_multiplicative_information(B) # Each ti in m_comparisons really represents |t_i|. p = add_of_mul_comps(m_comparisons, B.num_terms) a_comparisons, prime_of_index, num_terms = p a_comparisons = [terms.comp_eval[c[1]](c[0], 0) for c in a_comparisons] h_matrix = lrs_util.create_h_format_matrix(a_comparisons, num_terms) messages.announce('Halfplane matrix:', messages.DEBUG) messages.announce(h_matrix, messages.DEBUG) v_matrix, v_lin_set = lrs_util.get_vertices(h_matrix) messages.announce('Vertex matrix:', messages.DEBUG) for l in v_matrix: messages.announce(str(l), messages.DEBUG) messages.announce('Linear set:', messages.DEBUG) messages.announce(str(v_lin_set), messages.DEBUG) new_comparisons = get_mul_comparisons(v_matrix, v_lin_set, B.num_terms, prime_of_index) for m1, m2, coeff, comp in new_comparisons: c = mul_util.process_mul_comp(m1, m2, coeff, comp, B) if c is not None: B.assert_comparison(c) timer.stop(timer.PMUL)
def update_blackboard(self, B): """ Asserts identities about minm terms """ messages.announce_module('minimum module') timer.start(timer.MINM) for i in range(B.num_terms): if isinstance( B.term_defs[i], terms.FuncTerm) and B.term_defs[i].func_name == 'minm': # t_i is of the form minm(...) args = B.term_defs[i].args # assert that t_i is le all of its arguments for a in args: B.assert_comparison(terms.IVar(i) <= a) # see if we can infer the sign # TODO: optimize if all(B.implies_comparison(a > 0) for a in args): B.assert_comparison(terms.IVar(i) > 0) elif all(B.implies_comparison(a >= 0) for a in args): B.assert_comparison(terms.IVar(i) >= 0) if any(B.implies_comparison(a < 0) for a in args): B.assert_comparison(terms.IVar(i) < 0) elif any(B.implies_comparison(a <= 0) for a in args): B.assert_comparison(terms.IVar(i) <= 0) # see if any multiple of another problem term is known to be less than all the # arguments. for j in range(B.num_terms): if j != i: comp_range = geometry.ComparisonRange( geometry.neg_infty, geometry.infty, True, True, True) for a in args: new_comp_range = B.le_coeff_range( j, a.term.index, a.coeff) comp_range = comp_range & new_comp_range if comp_range.is_empty(): break if not comp_range.is_empty(): if comp_range.lower.type == geometry.VAL: c = comp_range.lower.val if comp_range.lower_strict: B.assert_comparison( c * terms.IVar(j) < terms.IVar(i)) else: B.assert_comparison( c * terms.IVar(j) <= terms.IVar(i)) if comp_range.upper.type == geometry.VAL: c = comp_range.upper.val if comp_range.upper_strict: B.assert_comparison( c * terms.IVar(j) < terms.IVar(i)) else: B.assert_comparison( c * terms.IVar(j) <= terms.IVar(i)) timer.stop(timer.MINM)
def update_blackboard(self, B): """ Asserts identities about exp and log terms found in B. """ timer.start(timer.EXP) messages.announce_module('exponential module') if any(isinstance(t, terms.FuncTerm) and t.func == terms.exp for t in B.term_defs.values()): B.assert_comparison(terms.exp(0) == 1) if any(isinstance(t, terms.FuncTerm) and t.func == terms.log for t in B.term_defs.values()): B.assert_comparison(terms.log(1) == 0) exp_factor_constant(B) exp_factor_sum(B) log_factor_exponent(B) log_factor_product(B) timer.stop(timer.EXP)
def update_blackboard(self, B): """ Asserts identities about minm terms """ messages.announce_module('minimum module') timer.start(timer.MINM) for i in range(B.num_terms): if isinstance(B.term_defs[i], terms.FuncTerm) and B.term_defs[i].func_name == 'minm': # t_i is of the form minm(...) args = B.term_defs[i].args # assert that t_i is le all of its arguments for a in args: B.assert_comparison(terms.IVar(i) <= a) # see if we can infer the sign # TODO: optimize if all(B.implies_comparison(a > 0) for a in args): B.assert_comparison(terms.IVar(i) > 0) elif all(B.implies_comparison(a >= 0) for a in args): B.assert_comparison(terms.IVar(i) >= 0) if any(B.implies_comparison(a < 0) for a in args): B.assert_comparison(terms.IVar(i) < 0) elif any(B.implies_comparison(a <= 0) for a in args): B.assert_comparison(terms.IVar(i) <= 0) # see if any multiple of another problem term is known to be less than all the # arguments. for j in range(B.num_terms): if j != i: comp_range = geometry.ComparisonRange(geometry.neg_infty, geometry.infty, True, True, True) for a in args: new_comp_range = B.le_coeff_range(j, a.term.index, a.coeff) comp_range = comp_range & new_comp_range if comp_range.is_empty(): break if not comp_range.is_empty(): if comp_range.lower.type == geometry.VAL: c = comp_range.lower.val if comp_range.lower_strict: B.assert_comparison(c * terms.IVar(j) < terms.IVar(i)) else: B.assert_comparison(c * terms.IVar(j) <= terms.IVar(i)) if comp_range.upper.type == geometry.VAL: c = comp_range.upper.val if comp_range.upper_strict: B.assert_comparison(c * terms.IVar(j) < terms.IVar(i)) else: B.assert_comparison(c * terms.IVar(j) <= terms.IVar(i)) timer.stop(timer.MINM)
def update_blackboard(self, B): """ Asserts identities about exp and log terms found in B. """ timer.start(timer.EXP) messages.announce_module('exponential module') if any(isinstance(t, terms.FuncTerm) and t.func == terms.exp for t in B.term_defs.values()): B.assert_comparison(terms.exp(0) == 1) if any(isinstance(t, terms.FuncTerm) and t.func == terms.log for t in B.term_defs.values()): B.assert_comparison(terms.log(1) == 0) exp_factor_constant(B) exp_factor_sum(B) #exp_factor_both(B) log_factor_exponent(B) log_factor_product(B) timer.stop(timer.EXP)
def update_blackboard(self, B): """ Adds axioms corresponding to each nth root function present. """ messages.announce_module('nth root value module') timer.start(timer.ROOT) #nth_roots = [] def is_nth_root_term(i): """ Returns True if t_i is of the form abs(t_j). """ return (isinstance(B.term_defs[i], terms.FuncTerm) and isinstance(B.term_defs[i].func, terms.NthRoot)) def root_degree(i): """ If t_i is of the form NthRoot(n, t_j), returns n. """ return B.term_defs[i].func.n nth_roots = set([ root_degree(i) for i in range(B.num_terms) if is_nth_root_term(i) ]) x = terms.Var('x') for n in nth_roots: if n % 2 == 0: self.am.add_axiom( formulas.Forall([x], formulas.Implies(x >= 0, terms.root(n, x)**n == x))) self.am.add_axiom( formulas.Forall([x], formulas.Implies(x >= 0, terms.root(n, x) >= 0))) else: self.am.add_axiom( formulas.Forall([x], terms.root(n, x)**n == x)) timer.stop(timer.ROOT)
def update_blackboard(self, B): """ Checks the blackboard B for function terms with equal arguments, and asserts that the function terms are equal. """ def eq_func_terms(f1, f2): """ Returns true if f1 and f2 have the same name and arity, and all args are equal. """ if f1.func_name != f2.func_name or len(f1.args) != len(f2.args): return False for i in range(len(f1.args)): arg1, arg2 = f1.args[i], f2.args[i] if arg1.coeff == 0: eq = B.implies(arg2.term.index, terms.EQ, 0, 0) or arg2.coeff == 0 else: eq = B.implies(arg1.term.index, terms.EQ, fractions.Fraction(arg2.coeff, arg1.coeff), arg2.term.index) if not eq: return False return True timer.start(timer.CCM) messages.announce_module('congruence closure module') func_classes = {} for i in (d for d in range(B.num_terms) if isinstance(B.term_defs[d], terms.FuncTerm)): name = B.term_defs[i].func_name func_classes[name] = func_classes.get(name, []) + [i] for name in func_classes: tinds = func_classes[name] for (i, j) in itertools.combinations(tinds, 2): # ti and tj are function terms with the same symbols. check if they're equal. f1, f2 = B.term_defs[i], B.term_defs[j] if eq_func_terms(f1, f2): B.assert_comparison(terms.IVar(i) == terms.IVar(j)) timer.stop(timer.CCM)
def update_blackboard(self, B): """ Adds axioms for sin, cos, tan, floor """ timer.start(timer.BUILTIN) ts = [B.term_defs[i] for i in range(B.num_terms)] funcs = [t.func.name for t in ts if isinstance(t, terms.FuncTerm)] if (not self.added['sin'] and 'sin' in funcs): self.am.add_axioms(sin_axioms) self.added['sin'] = True if (not self.added['cos'] and 'cos' in funcs): self.am.add_axioms(cos_axioms) self.added['cos'] = True if (not self.added['tan'] and 'tan' in funcs): self.am.add_axioms(tan_axioms) self.added['tan'] = True if (not self.added['floor'] and 'floor' in funcs): self.am.add_axioms(floor_axioms) self.added['floor'] = True if (not self.added['abs'] and 'abs' in funcs): self.am.add_axioms(abs_axioms) self.added['abs'] = True if (not self.added['exp'] and 'exp' in funcs): self.am.add_axioms(exp_axioms) self.added['exp'] = True if (not self.added['log'] and 'log' in funcs): self.am.add_axioms(log_axioms) self.added['log'] = True timer.stop(timer.BUILTIN)
def update_blackboard(self, B): """ Adds variations on the triangle inequality. Looks for expressions abs(c1 * t1 + ... + ck * tk) for which each ti either occurs in an abs term, or has a known sign. In that case, adds inequalities corresponding to abs(c1 * t1 + ... + ck * tk) <= abs(c1 * t1) + ... + abs(ck * tk) abs(c1 * t1 + ... + ck * tk) >= abs(cj * tj) - (abs(c1 * t1) + ... + abs(ck * tk)) """ messages.announce_module('absolute value module') timer.start(timer.ABS) def is_abs_term(i): """ Returns True if t_i is of the form abs(t_j). """ return (isinstance(B.term_defs[i], terms.FuncTerm) and B.term_defs[i].func_name == 'abs') def abs_arg_index(i): """ If t_i is of the form abs(t_j), returns j. """ return B.term_defs[i].args[0].term.index def is_sum_term(i): """ Return True if t_i is a sum. """ return isinstance(B.term_defs[i], terms.AddTerm) def sum_args(i): """ Assuming t_i is a sum, returns the arguments. """ return B.term_defs[i].args # indices i of terms t_i of the form abs(t_j) abs_indices = [i for i in range(B.num_terms) if is_abs_term(i)] # indices j of terms occurring in the context abs(t_j) abs_wrapped_indices = [abs_arg_index(i) for i in abs_indices] # indices of terms of the form abs(c1 * t1 + ... + ck * tk) abs_sum_indices = [i for i in abs_indices if is_sum_term(abs_arg_index(i))] def abs_present(i): """ Returns True if t_i occurs in the context abs(t_i) or has known sign, which is to say, something equivalent to abs(t_i) is already a problem term. """ return i in abs_wrapped_indices or B.weak_sign(i) == 1 or B.weak_sign(i) == -1 def abs_of(i): """ Assuming abs_present(i), returns an expression equal to abs(t_i). """ if B.weak_sign(i) == 1: return terms.IVar(i) elif B.weak_sign(i) == -1: return terms.IVar(i) * -1 else: return terms.IVar(next(j for j in abs_indices if abs_arg_index(j) == i)) for i in abs_sum_indices: args = sum_args(abs_arg_index(i)) if all(abs_present(a.term.index) for a in args): abs_of_args = [a.coeff * abs_of(a.term.index) for a in args] sum_of_abs_of_args = reduce(lambda x, y: x + y, abs_of_args, 0) B.assert_comparison(terms.IVar(i) <= sum_of_abs_of_args) for a in abs_of_args: B.assert_comparison(terms.IVar(i) >= a * 2 - sum_of_abs_of_args) timer.stop(timer.ABS)
def update_blackboard(self, B): """ Adds variations on the triangle inequality. Looks for expressions abs(c1 * t1 + ... + ck * tk) for which each ti either occurs in an abs term, or has a known sign. In that case, adds inequalities corresponding to abs(c1 * t1 + ... + ck * tk) <= abs(c1 * t1) + ... + abs(ck * tk) abs(c1 * t1 + ... + ck * tk) >= abs(cj * tj) - (abs(c1 * t1) + ... + abs(ck * tk)) """ messages.announce_module('absolute value module') timer.start(timer.ABS) def is_abs_term(i): """ Returns True if t_i is of the form abs(t_j). """ return (isinstance(B.term_defs[i], terms.FuncTerm) and B.term_defs[i].func_name == 'abs') def abs_arg_index(i): """ If t_i is of the form abs(t_j), returns j. """ return B.term_defs[i].args[0].term.index def is_sum_term(i): """ Return True if t_i is a sum. """ return isinstance(B.term_defs[i], terms.AddTerm) def sum_args(i): """ Assuming t_i is a sum, returns the arguments. """ return B.term_defs[i].args # indices i of terms t_i of the form abs(t_j) abs_indices = [i for i in range(B.num_terms) if is_abs_term(i)] # indices j of terms occurring in the context abs(t_j) abs_wrapped_indices = [abs_arg_index(i) for i in abs_indices] # indices of terms of the form abs(c1 * t1 + ... + ck * tk) abs_sum_indices = [ i for i in abs_indices if is_sum_term(abs_arg_index(i)) ] def abs_present(i): """ Returns True if t_i occurs in the context abs(t_i) or has known sign, which is to say, something equivalent to abs(t_i) is already a problem term. """ return i in abs_wrapped_indices or B.weak_sign( i) == 1 or B.weak_sign(i) == -1 def abs_of(i): """ Assuming abs_present(i), returns an expression equal to abs(t_i). """ if B.weak_sign(i) == 1: return terms.IVar(i) elif B.weak_sign(i) == -1: return terms.IVar(i) * -1 else: return terms.IVar( next(j for j in abs_indices if abs_arg_index(j) == i)) for i in abs_sum_indices: args = sum_args(abs_arg_index(i)) if all(abs_present(a.term.index) for a in args): abs_of_args = [a.coeff * abs_of(a.term.index) for a in args] sum_of_abs_of_args = reduce(lambda x, y: x + y, abs_of_args, 0) B.assert_comparison(terms.IVar(i) <= sum_of_abs_of_args) for a in abs_of_args: B.assert_comparison( terms.IVar(i) >= a * 2 - sum_of_abs_of_args) timer.stop(timer.ABS)