/*++ Copyright (c) 2006 Microsoft Corporation Module Name: theory_dense_diff_logic_def.h Abstract: Author: Leonardo de Moura (leonardo) 2008-05-16. Revision History: --*/ #ifndef _THEORY_DENSE_DIFF_LOGIC_DEF_H_ #define _THEORY_DENSE_DIFF_LOGIC_DEF_H_ #include"smt_context.h" #include"theory_dense_diff_logic.h" #include"ast_pp.h" #include"smt_model_generator.h" namespace smt { template theory_dense_diff_logic::theory_dense_diff_logic(ast_manager & m, theory_arith_params & p): theory(m.get_family_id("arith")), m_params(p), m_autil(m), m_arith_eq_adapter(*this, p, m_autil), m_non_diff_logic_exprs(false), m_var_value_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)) { m_edges.push_back(edge()); } template inline app * theory_dense_diff_logic::mk_zero_for(expr * n) { return m_autil.mk_numeral(rational(0), get_manager().get_sort(n)); } template theory_var theory_dense_diff_logic::mk_var(enode * n) { theory_var v = theory::mk_var(n); bool is_int = m_autil.is_int(n->get_owner()); m_is_int.push_back(is_int); m_f_targets.push_back(f_target()); typename matrix::iterator it = m_matrix.begin(); typename matrix::iterator end = m_matrix.end(); for (; it != end; ++it) { it->push_back(cell()); } m_matrix.push_back(row()); row & r = m_matrix.back(); SASSERT(r.empty()); r.resize(v+1); cell & c = m_matrix[v][v]; c.m_edge_id = self_edge_id; c.m_distance.reset(); SASSERT(check_vector_sizes()); get_context().attach_th_var(n, this, v); return v; } template theory_var theory_dense_diff_logic::internalize_term_core(app * n) { context & ctx = get_context(); if (ctx.e_internalized(n)) { enode * e = ctx.get_enode(n); if (is_attached_to_var(e)) return e->get_th_var(get_id()); } rational _k; if (m_autil.is_add(n) && to_app(n)->get_num_args() == 2 && m_autil.is_numeral(to_app(n)->get_arg(0), _k)) { numeral k(_k); if (m_params.m_arith_reflect) internalize_term_core(to_app(to_app(n)->get_arg(0))); theory_var s = internalize_term_core(to_app(to_app(n)->get_arg(1))); enode * e = ctx.mk_enode(n, !m_params.m_arith_reflect, false, true); theory_var v = mk_var(e); add_edge(s, v, k, null_literal); k.neg(); add_edge(v, s, k, null_literal); return v; } else if (m_autil.is_numeral(n, _k)) { enode * e = ctx.mk_enode(n, false, false, true); // internalizer is marking enodes as interpreted whenever the associated ast is a value and a constant. // e->mark_as_interpreted(); theory_var v = mk_var(e); if (_k.is_zero()) return v; theory_var z = internalize_term_core(mk_zero_for(n)); numeral k(_k); add_edge(z, v, k, null_literal); k.neg(); add_edge(v, z, k, null_literal); return v; } else if (!m_autil.is_arith_expr(n)) { if (!ctx.e_internalized(n)) ctx.internalize(n, false); enode * e = ctx.get_enode(n); if (!is_attached_to_var(e)) return mk_var(e); else return e->get_th_var(get_id()); } else { return null_theory_var; } } template void theory_dense_diff_logic::found_non_diff_logic_expr(expr * n) { if (!m_non_diff_logic_exprs) { TRACE("non_diff_logic", tout << "found non diff logic expression:\n" << mk_pp(n, get_manager()) << "\n";); get_context().push_trail(value_trail(m_non_diff_logic_exprs)); m_non_diff_logic_exprs = true; } } template bool theory_dense_diff_logic::internalize_atom(app * n, bool gate_ctx) { if (memory::above_high_watermark()) { found_non_diff_logic_expr(n); // little hack... TODO: change to no_memory and return l_undef if SAT return false; } TRACE("ddl", tout << "internalizing atom:\n" << mk_pp(n, get_manager()) << "\n";); context & ctx = get_context(); SASSERT(!ctx.b_internalized(n)); SASSERT(m_autil.is_le(n) || m_autil.is_ge(n)); theory_var source, target; SASSERT(m_autil.is_le(n) || m_autil.is_ge(n)); app * lhs = to_app(n->get_arg(0)); app * rhs = to_app(n->get_arg(1)); SASSERT(m_autil.is_numeral(rhs)); rational _k; m_autil.is_numeral(rhs, _k); numeral offset(_k); app * s, * t; if (m_autil.is_add(lhs) && to_app(lhs)->get_num_args() == 2 && is_times_minus_one(to_app(lhs)->get_arg(1), s)) { t = to_app(to_app(lhs)->get_arg(0)); } else if (m_autil.is_mul(lhs) && to_app(lhs)->get_num_args() == 2 && m_autil.is_minus_one(to_app(lhs)->get_arg(0))) { s = to_app(to_app(lhs)->get_arg(1)); t = mk_zero_for(s); } else if (!m_autil.is_arith_expr(lhs)) { t = to_app(lhs); s = mk_zero_for(t); } else { TRACE("ddl", tout << "failed to internalize:\n" << mk_pp(n, get_manager()) << "\n";); found_non_diff_logic_expr(n); return false; } source = internalize_term_core(s); target = internalize_term_core(t); if (source == null_theory_var || target == null_theory_var) { TRACE("ddl", tout << "failed to internalize:\n" << mk_pp(n, get_manager()) << "\n";); found_non_diff_logic_expr(n); return false; } SASSERT(source != null_theory_var && target != null_theory_var); if (m_autil.is_ge(n)) { std::swap(source, target); offset.neg(); } bool_var bv = ctx.mk_bool_var(n); ctx.set_var_theory(bv, get_id()); atom * a = alloc(atom, bv, source, target, offset); m_atoms.push_back(a); m_bv2atoms.setx(bv, a, 0); m_matrix[source][target].m_occs.push_back(a); m_matrix[target][source].m_occs.push_back(a); TRACE("ddl", tout << "succeeded internalizing:\n" << mk_pp(n, get_manager()) << "\n";); return true; } template void theory_dense_diff_logic::mk_clause(literal l1, literal l2) { get_context().mk_th_axiom(get_id(), l1, l2); } template void theory_dense_diff_logic::mk_clause(literal l1, literal l2, literal l3) { get_context().mk_th_axiom(get_id(), l1, l2, l3); } template bool theory_dense_diff_logic::internalize_term(app * term) { if (memory::above_high_watermark()) { found_non_diff_logic_expr(term); // little hack... TODO: change to no_memory and return l_undef if SAT return false; } TRACE("ddl", tout << "internalizing term: " << mk_pp(term, get_manager()) << "\n";); theory_var v = internalize_term_core(term); TRACE("ddl", tout << mk_pp(term, get_manager()) << "\ninternalization result: " << (v != null_theory_var) << "\n";); if (v == null_theory_var) found_non_diff_logic_expr(term); return v != null_theory_var; } template void theory_dense_diff_logic::internalize_eq_eh(app * atom, bool_var v) { if (memory::above_high_watermark()) return; context & ctx = get_context(); app * lhs = to_app(atom->get_arg(0)); app * rhs = to_app(atom->get_arg(1)); app * s; if (m_autil.is_add(lhs) && to_app(lhs)->get_num_args() == 2 && is_times_minus_one(to_app(lhs)->get_arg(1), s) && m_autil.is_numeral(rhs)) { // force axioms for (= (+ x (* -1 y)) k) // this is necessary because (+ x (* -1 y)) is not a diff logic term. m_arith_eq_adapter.mk_axioms(ctx.get_enode(lhs), ctx.get_enode(rhs)); return; } if (m_params.m_arith_eager_eq_axioms) { enode * n1 = ctx.get_enode(lhs); enode * n2 = ctx.get_enode(rhs); if (n1->get_th_var(get_id()) != null_theory_var && n2->get_th_var(get_id()) != null_theory_var) m_arith_eq_adapter.mk_axioms(n1, n2); } } template void theory_dense_diff_logic::apply_sort_cnstr(enode * n, sort * s) { // do nothing... } template void theory_dense_diff_logic::assign_eh(bool_var v, bool is_true) { if (get_context().has_th_justification(v, get_id())) { TRACE("ddl", tout << "ignoring atom propagated by the theory.\n";); return; } atom * a = m_bv2atoms.get(v, 0); if (!a) { SASSERT(get_manager().is_eq(get_context().bool_var2expr(v))); return; } m_stats.m_num_assertions++; literal l = literal(v, !is_true); theory_var s = a->get_source(); theory_var t = a->get_target(); numeral k = a->get_offset(); TRACE("assign_profile", tout << "#" << get_enode(s)->get_owner_id() << " #" << get_enode(t)->get_owner_id() << " " << k << "\n";); if (l.sign()) { k.neg(); k -= get_epsilon(s); add_edge(t, s, k, l); } else { add_edge(s, t, k, l); } TRACE("ddl_detail", display(tout);); } template void theory_dense_diff_logic::new_eq_eh(theory_var v1, theory_var v2) { m_arith_eq_adapter.new_eq_eh(v1, v2); } template bool theory_dense_diff_logic::use_diseqs() const { return true; } template void theory_dense_diff_logic::new_diseq_eh(theory_var v1, theory_var v2) { m_arith_eq_adapter.new_diseq_eh(v1, v2); } template void theory_dense_diff_logic::conflict_resolution_eh(app * atom, bool_var v) { // do nothing } template void theory_dense_diff_logic::push_scope_eh() { theory::push_scope_eh(); m_scopes.push_back(scope()); scope & s = m_scopes.back(); s.m_atoms_lim = m_atoms.size(); s.m_edges_lim = m_edges.size(); s.m_cell_trail_lim = m_cell_trail.size(); } template void theory_dense_diff_logic::pop_scope_eh(unsigned num_scopes) { unsigned lvl = m_scopes.size(); SASSERT(num_scopes <= lvl); unsigned new_lvl = lvl - num_scopes; scope & s = m_scopes[new_lvl]; restore_cells(s.m_cell_trail_lim); m_edges.shrink(s.m_edges_lim); del_atoms(s.m_atoms_lim); del_vars(get_old_num_vars(num_scopes)); m_scopes.shrink(new_lvl); theory::pop_scope_eh(num_scopes); } template void theory_dense_diff_logic::restore_cells(unsigned old_size) { unsigned sz = m_cell_trail.size(); unsigned i = sz; while (i > old_size) { i--; cell_trail & t = m_cell_trail[i]; cell & c = m_matrix[t.m_source][t.m_target]; c.m_edge_id = t.m_old_edge_id; c.m_distance = t.m_old_distance; } m_cell_trail.shrink(old_size); } template void theory_dense_diff_logic::del_atoms(unsigned old_size) { typename atoms::iterator begin = m_atoms.begin() + old_size; typename atoms::iterator it = m_atoms.end(); while (it != begin) { --it; atom * a = *it; TRACE("del_atoms", tout << "deleting: p" << a->get_bool_var() << "\n";); m_bv2atoms[a->get_bool_var()] = 0; theory_var s = a->get_source(); theory_var t = a->get_target(); TRACE("del_atoms", tout << "m_matrix.size() " << m_matrix.size() << ", m_matrix[s].size() " << m_matrix[s].size() << ", m_matrix[t].size(): " << m_matrix[t].size() << ", t: " << t << ", s: " << s << "\n";); SASSERT(m_matrix[s][t].m_occs.back() == a); SASSERT(m_matrix[t][s].m_occs.back() == a); m_matrix[s][t].m_occs.pop_back(); m_matrix[t][s].m_occs.pop_back(); dealloc(a); } m_atoms.shrink(old_size); } template void theory_dense_diff_logic::del_vars(unsigned old_num_vars) { int num_vars = get_num_vars(); SASSERT(num_vars >= static_cast(old_num_vars)); if (num_vars != static_cast(old_num_vars)) { m_is_int.shrink(old_num_vars); m_f_targets.shrink(old_num_vars); m_matrix.shrink(old_num_vars); typename matrix::iterator it = m_matrix.begin(); typename matrix::iterator end = m_matrix.end(); for (; it != end; ++it) { it->shrink(old_num_vars); } } } template void theory_dense_diff_logic::restart_eh() { m_arith_eq_adapter.restart_eh(); } template void theory_dense_diff_logic::init_search_eh() { m_arith_eq_adapter.init_search_eh(); } template final_check_status theory_dense_diff_logic::final_check_eh() { init_model(); if (assume_eqs(m_var_value_table)) return FC_CONTINUE; // logical context contains arithmetic expressions that are not // in the difference logic fragment. if (m_non_diff_logic_exprs) return FC_GIVEUP; return FC_DONE; } template bool theory_dense_diff_logic::can_propagate() { // do nothing return false; } template void theory_dense_diff_logic::propagate() { // do nothing } template void theory_dense_diff_logic::flush_eh() { // do nothing } template void theory_dense_diff_logic::reset_eh() { del_atoms(0); m_atoms .reset(); m_bv2atoms .reset(); m_edges .reset(); m_matrix .reset(); m_is_int .reset(); m_f_targets .reset(); m_cell_trail .reset(); m_scopes .reset(); m_non_diff_logic_exprs = false; m_edges.push_back(edge()); theory::reset_eh(); } template bool theory_dense_diff_logic::validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const { return is_true ? m_assignment[v1] == m_assignment[v2] : m_assignment[v1] != m_assignment[v2]; } /** \brief Store in results the antecedents that justify that the distance between source and target. */ template void theory_dense_diff_logic::get_antecedents(theory_var source, theory_var target, literal_vector & result) { TRACE("ddl", tout << "get_antecedents, source: #" << get_enode(source)->get_owner_id() << ", target: #" << get_enode(target)->get_owner_id() << "\n";); CTRACE("ddl", !is_connected(source, target), display(tout);); SASSERT(is_connected(source, target)); svector & todo = m_tmp_pairs; todo.reset(); if (source != target) todo.push_back(var_pair(source, target)); while (!todo.empty()) { var_pair & curr = todo.back(); theory_var s = curr.first; theory_var t = curr.second; todo.pop_back(); SASSERT(is_connected(s, t)); cell & c = m_matrix[s][t]; SASSERT(c.m_edge_id != self_edge_id); edge & e = m_edges[c.m_edge_id]; if (e.m_justification != null_literal) result.push_back(e.m_justification); if (s != e.m_source) todo.push_back(var_pair(s, e.m_source)); if (e.m_target != t) todo.push_back(var_pair(e.m_target, t)); } } template void theory_dense_diff_logic::update_cells() { edge_id new_edge_id = m_edges.size() - 1; edge & last = m_edges.back(); theory_var s = last.m_source; theory_var t = last.m_target; numeral const & k = last.m_offset; // Compute set F of nodes such that: // x in F iff // k + d(t, x) < d(s, x) numeral new_dist; row & t_row = m_matrix[t]; typename row::iterator it = t_row.begin(); typename row::iterator end = t_row.end(); typename f_targets::iterator fbegin = m_f_targets.begin(); typename f_targets::iterator target = fbegin; for (theory_var x = 0; it != end; ++it, ++x) { if (it->m_edge_id != null_edge_id && x != s) { new_dist = k; new_dist += it->m_distance; cell & s_x = m_matrix[s][x]; TRACE("ddl", tout << "s: #" << get_enode(s)->get_owner_id() << " x: #" << get_enode(x)->get_owner_id() << " new_dist: " << new_dist << "\n"; tout << "already has edge: " << s_x.m_edge_id << " old dist: " << s_x.m_distance << "\n";); if (s_x.m_edge_id == null_edge_id || new_dist < s_x.m_distance) { target->m_target = x; target->m_new_distance = new_dist; ++target; } } } typename f_targets::iterator fend = target; // For each node y such that y --> s, and for each node x in F, // check whether d(y, s) + new_dist(x) < d(y, x). typename matrix::iterator it2 = m_matrix.begin(); typename matrix::iterator end2 = m_matrix.end(); for (theory_var y = 0; it2 != end2; ++it2, ++y) { if (y != t) { row & r = *it2; cell & c = r[s]; if (c.m_edge_id != null_edge_id) { numeral const & d_y_s = c.m_distance; target = fbegin; for (; target != fend; ++target) { theory_var x = target->m_target; if (x != y) { new_dist = d_y_s; new_dist += target->m_new_distance; cell & y_x = m_matrix[y][x]; if (y_x.m_edge_id == null_edge_id || new_dist < y_x.m_distance) { m_cell_trail.push_back(cell_trail(y, x, y_x.m_edge_id, y_x.m_distance)); y_x.m_edge_id = new_edge_id; y_x.m_distance = new_dist; if (!y_x.m_occs.empty()) { propagate_using_cell(y, x); } } } } } } } CASSERT("ddl", check_matrix()); } template void theory_dense_diff_logic::assign_literal(literal l, theory_var source, theory_var target) { context & ctx = get_context(); literal_vector & antecedents = m_tmp_literals; antecedents.reset(); get_antecedents(source, target, antecedents); ctx.assign(l, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), antecedents.size(), antecedents.c_ptr(), l))); } template void theory_dense_diff_logic::propagate_using_cell(theory_var source, theory_var target) { cell & c = m_matrix[source][target]; SASSERT(c.m_edge_id != null_edge_id); numeral neg_dist = c.m_distance; neg_dist.neg(); context & ctx = get_context(); typename atoms::const_iterator it = c.m_occs.begin(); typename atoms::const_iterator end = c.m_occs.end(); for (; it != end; ++it) { atom * a = *it; if (ctx.get_assignment(a->get_bool_var()) == l_undef) { if (a->get_source() == source) { SASSERT(a->get_target() == target); if (c.m_distance <= a->get_offset()) { m_stats.m_num_propagations++; TRACE("ddl", tout << "asserting atom to true: "; display_atom(tout, a); tout << "distance(#" << get_enode(source)->get_owner_id() << ", #" << get_enode(target)->get_owner_id() << "): " << c.m_distance << "\n";); assign_literal(literal(a->get_bool_var(), false), source, target); } } else { SASSERT(a->get_source() == target); SASSERT(a->get_target() == source); if (neg_dist > a->get_offset()) { m_stats.m_num_propagations++; TRACE("ddl", tout << "asserting atom to true: "; display_atom(tout, a); tout << "distance(#" << get_enode(source)->get_owner_id() << ", #" << get_enode(target)->get_owner_id() << "): " << c.m_distance << "\n";); assign_literal(literal(a->get_bool_var(), true), source, target); } } } } } template inline void theory_dense_diff_logic::add_edge(theory_var source, theory_var target, numeral const & offset, literal l) { TRACE("ddl", tout << "trying adding edge: #" << get_enode(source)->get_owner_id() << " -- " << offset << " --> #" << get_enode(target)->get_owner_id() << "\n";); cell & c_inv = m_matrix[target][source]; if (c_inv.m_edge_id != null_edge_id && - c_inv.m_distance > offset) { // conflict detected. TRACE("ddl", tout << "conflict detected: #" << get_enode(source)->get_owner_id() << " #" << get_enode(target)->get_owner_id() << " offset: " << offset << ", c_inv.m_edge_id: " << c_inv.m_edge_id << ", c_inv.m_distance: " << c_inv.m_distance << "\n";); literal_vector & antecedents = m_tmp_literals; antecedents.reset(); get_antecedents(target, source, antecedents); if (l != null_literal) antecedents.push_back(l); context & ctx = get_context(); region & r = ctx.get_region(); ctx.set_conflict(ctx.mk_justification(theory_conflict_justification(get_id(), r, antecedents.size(), antecedents.c_ptr()))); return; } cell & c = m_matrix[source][target]; if (c.m_edge_id == null_edge_id || offset < c.m_distance) { TRACE("ddl", tout << "adding edge: #" << get_enode(source)->get_owner_id() << " -- " << offset << " --> #" << get_enode(target)->get_owner_id() << "\n";); m_edges.push_back(edge(source, target, offset, l)); update_cells(); } } #ifdef Z3DEBUG template bool theory_dense_diff_logic::check_vector_sizes() const { SASSERT(m_matrix.size() == m_f_targets.size()); SASSERT(m_is_int.size() == m_matrix.size()); typename matrix::const_iterator it = m_matrix.begin(); typename matrix::const_iterator end = m_matrix.end(); for (; it != end; ++it) { SASSERT(it->size() == m_matrix.size()); } return true; } template bool theory_dense_diff_logic::check_matrix() const { int sz = m_matrix.size(); for (theory_var i = 0; i < sz; i++) { for (theory_var j = 0; j < sz; j++) { cell const & c = m_matrix[i][j]; if (c.m_edge_id == self_edge_id) { SASSERT(i == j); SASSERT(c.m_distance.is_zero()); } else if (c.m_edge_id != null_edge_id) { edge const & e = m_edges[c.m_edge_id]; theory_var s = e.m_source; theory_var t = e.m_target; numeral k = get_distance(i, s); k += e.m_offset; k += get_distance(t, j); if (c.m_distance != k) { CTRACE("ddl", c.m_distance != k, tout << "i: " << i << " j: " << j << " k: " << k << " c.m_distance: " << c.m_distance << "\n"; display(tout);); SASSERT(c.m_distance == k); } } } } return true; } #endif template void theory_dense_diff_logic::display(std::ostream & out) const { out << "Theory dense difference logic:\n"; display_var2enode(out); typename matrix::const_iterator it1 = m_matrix.begin(); typename matrix::const_iterator end1 = m_matrix.end(); for (int v1 = 0; it1 != end1; ++it1, ++v1) { typename row::const_iterator it2 = it1->begin(); typename row::const_iterator end2 = it1->end(); for (int v2 = 0; it2 != end2; ++it2, ++v2) { if (it2->m_edge_id != null_edge_id && it2->m_edge_id != self_edge_id) { out << "#"; out.width(5); out << std::left << get_enode(v1)->get_owner_id() << " -- "; out.width(10); out << std::left << it2->m_distance << " : id"; out.width(5); out << std::left << it2->m_edge_id << " --> #"; out << get_enode(v2)->get_owner_id() << "\n"; } } } out << "atoms:\n"; typename atoms::const_iterator it2 = m_atoms.begin(); typename atoms::const_iterator end2 = m_atoms.end(); for (;it2 != end2; ++it2) { atom * a = *it2; display_atom(out, a); } } template void theory_dense_diff_logic::display_atom(std::ostream & out, atom * a) const { out << "#"; out.width(5); out << std::left << get_enode(a->get_target())->get_owner_id() << " - #"; out.width(5); out << std::left << get_enode(a->get_source())->get_owner_id() << " <= "; out.width(10); out << std::left << a->get_offset() << " assignment: " << get_context().get_assignment(a->get_bool_var()) << "\n"; } template void theory_dense_diff_logic::collect_statistics(::statistics & st) const { st.update("dd assertions", m_stats.m_num_assertions); st.update("dd propagations", m_stats.m_num_propagations); m_arith_eq_adapter.collect_statistics(st); } /** \brief Build a model for doing model-based theory combination. */ template void theory_dense_diff_logic::init_model() { int num_vars = get_num_vars(); m_assignment.reset(); m_assignment.resize(num_vars); for (int i = 0; i < num_vars; i++) { row & r = m_matrix[i]; numeral & d = m_assignment[i]; for (int j = 0; j < num_vars; j++) { if (i != j) { cell & c = r[j]; if (c.m_edge_id != null_edge_id && c.m_distance < d) { d = c.m_distance; } } } } for (int i = 0; i < num_vars; i++) m_assignment[i].neg(); TRACE("ddl_model", tout << "ddl model\n"; for (theory_var v = 0; v < num_vars; v++) { tout << "#" << mk_pp(get_enode(v)->get_owner(), get_manager()) << " = " << m_assignment[v] << "\n"; }); } /** The arithmetic module uses infinitesimals. So, an inf_numeral (n,k) represents n + k*epsilon where epsilon is a very small number. In order to generate a model, we need to compute a value for epsilon in a way all inequalities remain satisfied. assume we have the inequality x - y <= (n_c, k_c) where the interpretation for x and y is: (n_x, k_x) and (n_y, k_y). So, (n_x, k_x) <= (n_y + n_c, k_y + k_c) The only intersting case is n_x < n_y + n_c and k_x > k_y + k_c. Using the definition of infinitesimal numbers we have: n_x + k_x * epsilon <= n_y + n_c + (k_y + k_c) * epsilon Therefore: epsilon <= (n_y + n_c - n_x) / (k_x - k_y - k_c) */ template void theory_dense_diff_logic::compute_epsilon() { m_epsilon = rational(1); typename edges::const_iterator it = m_edges.begin(); typename edges::const_iterator end = m_edges.end(); // first edge is null SASSERT(it->m_target == null_theory_var); SASSERT(it->m_source == null_theory_var); ++it; for (; it != end; ++it) { edge const & e = *it; rational n_x = m_assignment[e.m_target].get_rational().to_rational(); rational k_x = m_assignment[e.m_target].get_infinitesimal().to_rational(); rational n_y = m_assignment[e.m_source].get_rational().to_rational(); rational k_y = m_assignment[e.m_source].get_infinitesimal().to_rational(); rational n_c = e.m_offset.get_rational().to_rational(); rational k_c = e.m_offset.get_infinitesimal().to_rational(); TRACE("epsilon", tout << "(n_x,k_x): " << n_x << ", " << k_x << ", (n_y,k_y): " << n_y << ", " << k_y << ", (n_c,k_c): " << n_c << ", " << k_c << "\n";); if (n_x < n_y + n_c && k_x > k_y + k_c) { rational new_epsilon = (n_y + n_c - n_x) / (k_x - k_y - k_c); if (new_epsilon < m_epsilon) { TRACE("epsilon", tout << "new epsilon: " << new_epsilon << "\n";); m_epsilon = new_epsilon; } } } } template void theory_dense_diff_logic::fix_zero() { int num_vars = get_num_vars(); for (int v = 0; v < num_vars; ++v) { enode * n = get_enode(v); if (m_autil.is_zero(n->get_owner()) && !m_assignment[v].is_zero()) { numeral val = m_assignment[v]; sort * s = get_manager().get_sort(n->get_owner()); // adjust the value of all variables that have the same sort. for (int v2 = 0; v2 < num_vars; ++v2) { enode * n2 = get_enode(v2); if (get_manager().get_sort(n2->get_owner()) == s) { m_assignment[v2] -= val; } } SASSERT(m_assignment[v].is_zero()); } } TRACE("ddl_model", tout << "ddl model\n"; for (theory_var v = 0; v < num_vars; v++) { tout << "#" << mk_pp(get_enode(v)->get_owner(), get_manager()) << " = " << m_assignment[v] << "\n"; }); } template void theory_dense_diff_logic::init_model(model_generator & m) { m_factory = alloc(arith_factory, get_manager()); m.register_factory(m_factory); fix_zero(); compute_epsilon(); } template model_value_proc * theory_dense_diff_logic::mk_value(enode * n, model_generator & mg) { theory_var v = n->get_th_var(get_id()); SASSERT(v != null_theory_var); numeral const & val = m_assignment[v]; rational num = val.get_rational().to_rational() + m_epsilon * val.get_infinitesimal().to_rational(); return alloc(expr_wrapper_proc, m_factory->mk_value(num, is_int(v))); } }; #endif /* _THEORY_DENSE_DIFF_LOGIC_DEF_H_ */