Skip to content

Commit 1741855

Browse files
committed
collect the explanation correctly
1 parent bc0fdfe commit 1741855

File tree

2 files changed

+88
-40
lines changed

2 files changed

+88
-40
lines changed

src/math/lp/dioph_eq.cpp

+71-38
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@
2323
-- lia: point to int_solver.
2424
-- m_entries: it keeps all "entry" objects.
2525
-- m_e_matrix: i-th row of this matrix keeps the term corresponding to
26-
m_entries[i]. The actual term is the sum of the matrix row and the constant
27-
m_c of the entry. The column j of the matrix corresponds to j column of
28-
lar_solver if j < lra.column_count(). Otherwise, j is a fresh column. It has
29-
to change in the interactive version. Implementation remarks:
26+
m_entries[i]. The actual term corresponding to m_entry[i] is the sum of the
27+
matrix i-th row and the constant m_entry[].m_c.
28+
The mapping between the columns of lar_solver and m_e_matrix is controlled by m_var_register.
29+
local_to_lar_solver(lar_solver_to_local(j)) == j. If local_to_lar_solver(j) == -1
30+
then j is a fresh variable, that is such that got introduced when normalizing a term like 3x-6y + 5z +11 = 0,
31+
when no variable has a coefficient +-1.
32+
3033
-- get_term_from_entry(unsigned i) return a term corresponding i-th entry.
3134
If t = get_term_from_entry(i) then we have equality t = 0. Initially
3235
get_term_from_entry(i) is set to initt(j) = lra.get_term(j) - j, for some
@@ -246,6 +249,7 @@ namespace lp {
246249
bool m_left;
247250
bool m_fully_explored = false;
248251
void flip() {
252+
SASSERT(m_fully_explored == false);
249253
m_left = !m_left;
250254
m_fully_explored = true;
251255
}
@@ -415,6 +419,8 @@ namespace lp {
415419

416420
// A conflict is reported when the gcd of the monomial coefficients does not divide the free coefficent.
417421
// If there is no conflict the entry is divided, normalized, by gcd.
422+
// The function returns true if and only if there is no conflict. In the case of a conflict a branch
423+
// can be returned as well.
418424
bool normalize_e_by_gcd(unsigned ei) {
419425
entry& e = m_entries[ei];
420426
TRACE("dioph_eq", print_entry(ei, tout) << std::endl;);
@@ -437,7 +443,7 @@ namespace lp {
437443
return true;
438444
}
439445
// c_g is not integral
440-
if (lra.settings().stats().m_dio_conflicts %
446+
if (lra.stats().m_dio_calls %
441447
lra.settings().dio_cut_from_proof_period() ==
442448
0 &&
443449
!has_fresh_var(ei))
@@ -563,7 +569,7 @@ namespace lp {
563569
subs_front_in_indexed_vector(q);
564570
}
565571

566-
lia_move tighten_with_S() {
572+
lia_move tighten_terms_with_S() {
567573
for (unsigned j = 0; j < lra.column_count(); j++) {
568574
if (!lra.column_has_term(j) || lra.column_is_free(j) ||
569575
is_fixed(j) || !lia.column_is_int(j))
@@ -792,26 +798,35 @@ namespace lp {
792798
return dep;
793799
}
794800

795-
lia_move iterate() {
801+
lia_move process_f() {
796802
while (m_f.size()) {
797803
if (!normalize_by_gcd()) {
798-
lra.settings().stats().m_dio_conflicts++;
799804
if (m_report_branch) {
805+
lra.stats().m_dio_cut_from_proofs++;
800806
m_report_branch = false;
801807
return lia_move::branch;
808+
} else {
809+
lra.stats().m_dio_normalize_conflicts++;
802810
}
803811
return lia_move::conflict;
804812
}
805813
rewrite_eqs();
806814
if (m_conflict_index != UINT_MAX) {
807-
lra.settings().stats().m_dio_conflicts++;
815+
lra.stats().m_dio_rewrite_conflicts++;
808816
return lia_move::conflict;
809817
}
810818
}
819+
return lia_move::undef;
820+
}
821+
822+
lia_move process_f_and_tighten_terms() {
823+
lia_move ret = process_f();
824+
if (ret != lia_move::undef)
825+
return ret;
811826
TRACE("dioph_eq", print_S(tout););
812-
lia_move ret = tighten_with_S();
827+
ret = tighten_terms_with_S();
813828
if (ret == lia_move::conflict) {
814-
lra.settings().stats().m_dio_conflicts++;
829+
lra.stats().m_dio_tighten_conflicts++;
815830
return lia_move::conflict;
816831
}
817832
return lia_move::undef;
@@ -835,16 +850,13 @@ namespace lp {
835850
}
836851

837852
// returns true if the left and the right branches were explored
838-
bool undo_last_branch() {
839-
if (m_branch_stack.back().m_fully_explored) {
840-
TRACE("dio_br", tout << "pop fully explored, m_branch_stack.size():" << m_branch_stack.size() << std::endl;);
853+
void undo_explored_branches() {
854+
TRACE("dio_br", tout << "m_branch_stack.size():" << m_branch_stack.size() << std::endl;);
855+
while (m_branch_stack.size() && m_branch_stack.back().m_fully_explored) {
841856
m_branch_stack.pop_back();
842-
return true;
857+
lra_pop();
843858
}
844-
// exploring the other side of the branch
845-
TRACE("dio_br", tout << "flipped branch" << std::endl;);
846-
m_branch_stack.back().flip();
847-
return false;
859+
TRACE("dio_br", tout << "after pop:m_branch_stack.size():" << m_branch_stack.size() << std::endl;);
848860
}
849861

850862
lia_move check_fixing(unsigned j) const {
@@ -903,6 +915,7 @@ namespace lp {
903915
if (br.m_j == UINT_MAX)
904916
return false;
905917
m_branch_stack.push_back(br);
918+
lra.stats().m_dio_branching_depth = std::max(lra.stats().m_dio_branching_depth, (unsigned)m_branch_stack.size());
906919
return true;
907920
}
908921

@@ -912,10 +925,10 @@ namespace lp {
912925
} else {
913926
lra.add_var_bound(b->m_j, lconstraint_kind::GE, b->m_rs + mpq(1));
914927
}
915-
if (lra.column_is_fixed(b->m_j)) {
916-
if (fix_var(lar_solver_to_local(b->m_j)) == lia_move::conflict)
917-
return lia_move::conflict;
918-
}
928+
// if (lra.column_is_fixed(b->m_j)) {
929+
// if (fix_var(lar_solver_to_local(b->m_j)) == lia_move::conflict)
930+
// return lia_move::conflict;
931+
// }
919932
return lia_move::undef;
920933
}
921934

@@ -927,20 +940,32 @@ namespace lp {
927940
}
928941
void lra_pop() {
929942
m_lra_level--;
943+
SASSERT(m_lra_level != UINT_MAX);
930944
lra.pop();
931945
lra.find_feasible_solution();
932946
SASSERT(lra.get_status() == lp_status::CANCELLED || lra.is_feasible());
933947
}
934948

935-
lia_move process_undef() {
949+
void transfer_explanations_from_closed_branches() {
950+
m_infeas_explanation.clear();
951+
for (auto ci : m_explanation_of_branches) {
952+
if (this->lra.constraints().valid_index(ci))
953+
m_infeas_explanation.push_back(ci);
954+
}
955+
956+
}
957+
958+
lia_move branching_on_undef() {
936959
m_explanation_of_branches.clear();
937960
branch* b;
938961
bool need_create_branch = true;
939962
m_number_of_iterations = 0;
940963
while (++m_number_of_iterations < m_max_number_of_iterations) {
964+
lra.stats().m_dio_branch_iterations++;
941965
if (need_create_branch) {
942966
if (!push_branch()) {
943967
undo_branching();
968+
lra.stats().m_dio_branching_sats++;
944969
return lia_move::sat;
945970
}
946971
need_create_branch = false;
@@ -950,13 +975,16 @@ namespace lp {
950975

951976
if (add_var_bound_for_branch(b) == lia_move::conflict) {
952977
collect_evidence();
953-
if (m_branch_stack.size() == 0)
978+
undo_explored_branches();
979+
if (m_branch_stack.size() == 0) {
980+
lra.stats().m_dio_branching_infeasibles++;
981+
transfer_explanations_from_closed_branches();
954982
return lia_move::conflict;
983+
}
955984
TRACE("dio_br", tout << lp_status_to_string(lra.get_status()) << std::endl;
956985
tout << "explanation:\n"; lra.print_expl(tout, m_infeas_explanation););
957-
if (undo_last_branch())
958-
need_create_branch = true;
959-
lra_pop();
986+
need_create_branch = false;
987+
m_branch_stack.back().flip();
960988
continue;
961989
}
962990
auto st = lra.find_feasible_solution();
@@ -966,6 +994,7 @@ namespace lp {
966994
TRACE("dio_br", tout << "n_of_ii:" << n_of_ii << "\n";);
967995
if (n_of_ii == 0) {
968996
undo_branching();
997+
lra.stats().m_dio_branching_sats++;
969998
return lia_move::sat;
970999
}
9711000
// got to create a new branch
@@ -974,13 +1003,19 @@ namespace lp {
9741003
} else {
9751004
if (st == lp_status::CANCELLED) return lia_move::undef;
9761005
collect_evidence();
977-
if (m_branch_stack.size() == 0)
978-
return lia_move::conflict;
1006+
undo_explored_branches();
1007+
if (m_branch_stack.size() == 0) {
1008+
lra.stats().m_dio_branching_infeasibles++;
1009+
transfer_explanations_from_closed_branches();
1010+
enable_trace("dioph_eq");
1011+
return lia_move::conflict;
1012+
}
9791013
TRACE("dio_br", tout << lp_status_to_string(lra.get_status()) << std::endl;
9801014
tout << "explanation:\n"; lra.print_expl(tout, m_infeas_explanation););
981-
if (undo_last_branch())
982-
need_create_branch = true;
1015+
1016+
need_create_branch = false;
9831017
lra_pop();
1018+
m_branch_stack.back().flip();
9841019
}
9851020
}
9861021
undo_branching();
@@ -1049,20 +1084,20 @@ namespace lp {
10491084
br.m_left = (lra.settings().random_next() % 2 == 0);
10501085
br.m_rs = floor(lra.get_column_value(bj).x);
10511086

1052-
TRACE("dio_br", tout << " br.m_j:" << br.m_j << ","
1087+
TRACE("dio_br", tout << "score:" << score << "; br.m_j:" << br.m_j << ","
10531088
<< (br.m_left ? "left" : "right") << ", br.m_rs:" << br.m_rs << std::endl;);
10541089
return br;
10551090
}
10561091

10571092
public:
10581093
lia_move check() {
1059-
lra.settings().stats().m_dio_calls++;
1094+
lra.stats().m_dio_calls++;
10601095
init();
1061-
lia_move ret = iterate();
1096+
lia_move ret = process_f_and_tighten_terms();
10621097
if (ret == lia_move::branch || ret == lia_move::conflict)
10631098
return ret;
10641099
SASSERT(ret == lia_move::undef);
1065-
ret = process_undef();
1100+
ret = branching_on_undef();
10661101
if (ret == lia_move::sat || ret == lia_move::conflict)
10671102
return ret;
10681103
SASSERT(ret == lia_move::undef);
@@ -1382,8 +1417,6 @@ namespace lp {
13821417
public:
13831418
void explain(explanation& ex) {
13841419
if (m_conflict_index == UINT_MAX) {
1385-
SASSERT(!(lra.get_status() == lp_status::FEASIBLE ||
1386-
lra.get_status() == lp_status::OPTIMAL));
13871420
for (auto ci : m_infeas_explanation) {
13881421
ex.push_back(ci.ci());
13891422
}

src/math/lp/lp_settings.h

+17-2
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,15 @@ struct statistics {
128128
unsigned m_grobner_conflicts = 0;
129129
unsigned m_offset_eqs = 0;
130130
unsigned m_fixed_eqs = 0;
131-
unsigned m_dio_conflicts = 0;
132131
unsigned m_dio_calls = 0;
132+
unsigned m_dio_normalize_conflicts = 0;
133+
unsigned m_dio_tighten_conflicts = 0;
134+
unsigned m_dio_branch_iterations= 0;
135+
unsigned m_dio_branching_depth = 0;
136+
unsigned m_dio_cut_from_proofs = 0;
137+
unsigned m_dio_branching_infeasibles = 0;
138+
unsigned m_dio_rewrite_conflicts = 0;
139+
unsigned m_dio_branching_sats = 0;
133140
::statistics m_st = {};
134141

135142
void reset() {
@@ -163,7 +170,15 @@ struct statistics {
163170
st.update("arith-nra-calls", m_nra_calls);
164171
st.update("arith-bounds-improvements", m_nla_bounds_improvements);
165172
st.update("arith-dio-calls", m_dio_calls);
166-
st.update("arith-dio-conflicts", m_dio_conflicts);
173+
st.update("arith-dio-normalize-conflicts", m_dio_normalize_conflicts);
174+
st.update("arith-dio-tighten-conflicts", m_dio_tighten_conflicts);
175+
st.update("arith-dio-branch-iterations", m_dio_branch_iterations);
176+
st.update("arith-dio-branch-depths", m_dio_branching_depth);
177+
st.update("arith-dio-cut-from-proofs", m_dio_cut_from_proofs);
178+
st.update("arith-dio-branching-infeasibles", m_dio_branching_infeasibles);
179+
st.update("arith-dio-rewrite-conflicts", m_dio_rewrite_conflicts);
180+
st.update("arith-dio-branching-sats", m_dio_branching_sats);
181+
st.update("arith-dio-branching-depth", m_dio_branching_depth);
167182
st.copy(m_st);
168183
}
169184
};

0 commit comments

Comments
 (0)