Skip to content

Commit 4f1d8b4

Browse files
committed
throttle lemmas in nla_solver untested
1 parent e26ad99 commit 4f1d8b4

File tree

9 files changed

+155
-104
lines changed

9 files changed

+155
-104
lines changed

src/math/lp/dioph_eq.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2542,7 +2542,7 @@ namespace lp {
25422542
public:
25432543

25442544
void explain(explanation& ex) {
2545-
SASSERT(ex.empty());
2545+
ex.clear();
25462546
if (has_conflict_index()) {
25472547
TRACE(dio, print_entry(m_normalize_conflict_index, tout << "conflict:", true) << std::endl;);
25482548
for (auto ci : lra.flatten(explain_fixed_in_meta_term(m_l_matrix.m_rows[m_normalize_conflict_index], m_normalize_conflict_gcd)))

src/math/lp/explanation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class explanation {
7070
}
7171
}
7272

73-
bool empty() const { return m_vector.empty() || m_set.empty(); }
73+
bool empty() const { return m_vector.empty() && m_set.empty(); }
7474
size_t size() const { return std::max(m_vector.size(), m_set.size()); }
7575

7676
class cimpq {

src/math/lp/nla_core.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,7 @@ rational core::val(const factorization& f) const {
10401040
return r;
10411041
}
10421042

1043-
lemma_builder::lemma_builder(core& c, char const* name):name(name), c(c) {
1043+
lemma_builder::lemma_builder(core& c, const char* name):name(name), c(c) {
10441044
c.m_lemmas.push_back(lemma());
10451045
}
10461046

src/math/lp/nla_monotone_lemmas.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,30 @@
77
--*/
88
#include "math/lp/nla_basics_lemmas.h"
99
#include "math/lp/nla_core.h"
10+
#include "util/trail.h"
1011
namespace nla {
1112

1213
monotone::monotone(core * c) : common(c) {}
1314

15+
bool monotone::throttle_monotone(const monic& m, bool is_lt, const std::string& debug_location) {
16+
// Check if throttling is enabled
17+
if (!c().params().arith_nl_thrl())
18+
return false;
19+
20+
// Create the key for this specific monotonicity_lemma invocation
21+
monotone_key key(m.var(), is_lt);
22+
23+
// Check if this combination has already been processed
24+
if (m_processed_monotone.contains(key)) {
25+
TRACE(nla_solver, tout << "throttled monotonicity_lemma at " << debug_location << "\n";);
26+
return true;
27+
}
28+
29+
// Mark this combination as processed and add to trail for backtracking
30+
m_processed_monotone.insert(key);
31+
c().trail().push(insert_map(m_processed_monotone, key));
32+
return false;
33+
}
1434

1535
void monotone::monotonicity_lemma() {
1636
unsigned shift = random();
@@ -29,7 +49,13 @@ void monotone::monotonicity_lemma(monic const& m) {
2949
return;
3050
const rational prod_val = abs(c().product_value(m));
3151
const rational m_val = abs(var_val(m));
32-
if (m_val < prod_val)
52+
bool is_lt = m_val < prod_val;
53+
54+
// Check if this specific combination should be throttled
55+
if (throttle_monotone(m, is_lt, __FUNCTION__))
56+
return;
57+
58+
if (is_lt)
3359
monotonicity_lemma_lt(m);
3460
else if (m_val > prod_val)
3561
monotonicity_lemma_gt(m);

src/math/lp/nla_monotone_lemmas.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,43 @@
66
Nikolaj Bjorner (nbjorner)
77
--*/
88
#pragma once
9+
#include "util/hashtable.h"
10+
#include "util/hash.h"
11+
912
namespace nla {
1013
class core;
1114
class monotone : common {
1215
public:
1316
monotone(core *core);
1417
void monotonicity_lemma();
18+
19+
// Structure to represent the key parameters for throttling monotonicity_lemma
20+
struct monotone_key {
21+
short mvar;
22+
bool is_lt;
23+
24+
// Default constructor for hashtable
25+
monotone_key() : mvar(0), is_lt(false) {}
26+
27+
monotone_key(lpvar mvar, bool is_lt)
28+
: mvar(static_cast<short>(mvar)), is_lt(is_lt) {}
29+
30+
bool operator==(const monotone_key& other) const {
31+
return mvar == other.mvar && is_lt == other.is_lt;
32+
}
33+
};
34+
35+
struct monotone_key_hash {
36+
unsigned operator()(const monotone_key& k) const {
37+
return combine_hash(static_cast<unsigned>(k.mvar),
38+
static_cast<unsigned>(k.is_lt));
39+
}
40+
};
41+
1542
private:
43+
hashtable<monotone_key, monotone_key_hash, default_eq<monotone_key>> m_processed_monotone;
44+
bool throttle_monotone(const monic& m, bool is_lt, const std::string& debug_location);
45+
1646
void monotonicity_lemma(monic const& m);
1747
void monotonicity_lemma_gt(const monic& m);
1848
void monotonicity_lemma_lt(const monic& m);

src/math/lp/nla_order_lemmas.cpp

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -84,52 +84,59 @@ void order::order_lemma_on_binomial(const monic& ac) {
8484
void order::order_lemma_on_binomial_sign(const monic& xy, lpvar x, lpvar y, int sign) {
8585
if (!c().var_is_int(x) && val(x).is_big())
8686
return;
87-
// throttle!!!
87+
8888

8989
SASSERT(!_().mon_has_zero(xy.vars()));
9090
int sy = rat_sign(val(y));
91+
// throttle here
92+
if (throttle_binomial_sign(xy, x, y, sign, sy, __FUNCTION__))
93+
return;
94+
9195
lemma_builder lemma(c(), __FUNCTION__);
9296
lemma |= ineq(y, sy == 1 ? llc::LE : llc::GE, 0); // negate sy
9397
lemma |= ineq(x, sy*sign == 1 ? llc::GT : llc::LT , val(x));
9498
lemma |= ineq(term(xy.var(), - val(x), y), sign == 1 ? llc::LE : llc::GE, 0);
9599
}
96100

97-
bool order::throttle_monic(const monic& ac, std::string const & debug_location ) { // todo - remove debug location!
101+
bool order::throttle_mon_ol(const monic& ac, lpvar a, const rational& c_sign, lpvar c_var,
102+
const monic& bd, const factor& b, const rational& d_sign,
103+
lpvar d, llc ab_cmp, const std::string& debug_location) {
98104
// Check if throttling is enabled
99105
if (!c().params().arith_nl_thrl())
100106
return false;
101107

102-
// Check if this monic has already been processed using its variable ID
103-
if (m_processed_monics.contains(ac.var())) {
104-
TRACE(nla_solver, tout << "throttled at " << debug_location << "\n";);
108+
// Create the key for this specific generate_mon_ol invocation
109+
mon_ol_key key(ac.var(), a, c_sign, c_var, bd.var(), b.var(), d_sign, d, ab_cmp);
110+
111+
// Check if this combination has already been processed
112+
if (m_processed_mon_ol.contains(key)) {
113+
TRACE(nla_solver, tout << "throttled generate_mon_ol at " << debug_location << "\n";);
105114
return true;
106115
}
107116

108-
// Mark this monic as processed and add to trail for backtracking
109-
m_processed_monics.insert(ac.var());
110-
c().trail().push(insert_map(m_processed_monics, ac.var()));
117+
// Mark this combination as processed and add to trail for backtracking
118+
m_processed_mon_ol.insert(key);
119+
c().trail().push(insert_map(m_processed_mon_ol, key));
111120
return false;
112121
}
113122

114-
bool order::throttle_mon_ol(const monic& ac, lpvar a, const rational& c_sign, lpvar c_var,
115-
const monic& bd, const factor& b, const rational& d_sign,
116-
lpvar d, llc ab_cmp, const std::string& debug_location) {
123+
bool order::throttle_binomial_sign(const monic& xy, lpvar x, lpvar y, int sign, int sy, const std::string& debug_location) {
117124
// Check if throttling is enabled
118125
if (!c().params().arith_nl_thrl())
119126
return false;
120127

121-
// Create the key for this specific generate_mon_ol invocation
122-
mon_ol_key key(ac.var(), a, c_sign, c_var, bd.var(), b.var(), d_sign, d, ab_cmp);
128+
// Create the key for this specific order_lemma_on_binomial_sign invocation
129+
binomial_sign_key key(xy.var(), x, y, sign, sy);
123130

124131
// Check if this combination has already been processed
125-
if (m_processed_mon_ol.contains(key)) {
126-
TRACE(nla_solver, tout << "throttled generate_mon_ol at " << debug_location << "\n";);
132+
if (m_processed_binomial_sign.contains(key)) {
133+
TRACE(nla_solver, tout << "throttled order_lemma_on_binomial_sign at " << debug_location << "\n";);
127134
return true;
128135
}
129136

130137
// Mark this combination as processed and add to trail for backtracking
131-
m_processed_mon_ol.insert(key);
132-
c().trail().push(insert_map(m_processed_mon_ol, key));
138+
m_processed_binomial_sign.insert(key);
139+
c().trail().push(insert_map(m_processed_binomial_sign, key));
133140
return false;
134141
}
135142

src/math/lp/nla_order_lemmas.h

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,29 @@ class order: common {
2121
void order_lemma();
2222

2323
// Structure to represent the key parameters for throttling generate_mon_ol
24+
// Optimized for memory efficiency with packed fields
2425
struct mon_ol_key {
25-
lpvar ac_var;
26-
lpvar a;
27-
rational c_sign;
28-
lpvar c;
29-
lpvar bd_var;
30-
lpvar b_var;
31-
rational d_sign;
32-
lpvar d;
33-
llc ab_cmp;
26+
short ac_var;
27+
short a;
28+
signed char c_sign; // -1, 0, 1 fits in signed char
29+
short c;
30+
short bd_var;
31+
short b_var;
32+
signed char d_sign; // -1, 0, 1 fits in signed char
33+
short d;
34+
unsigned char ab_cmp; // llc enum fits in unsigned char
3435

3536
// Default constructor for hashtable
36-
mon_ol_key() : ac_var(0), a(0), c_sign(0), c(0), bd_var(0), b_var(0), d_sign(0), d(0), ab_cmp(llc::EQ) {}
37+
mon_ol_key() : ac_var(0), a(0), c_sign(0), c(0), bd_var(0), b_var(0), d_sign(0), d(0), ab_cmp(static_cast<unsigned char>(llc::EQ)) {}
3738

38-
mon_ol_key(lpvar ac_var, lpvar a, const rational& c_sign, lpvar c,
39-
lpvar bd_var, lpvar b_var, const rational& d_sign, lpvar d, llc ab_cmp)
40-
: ac_var(ac_var), a(a), c_sign(c_sign), c(c), bd_var(bd_var),
41-
b_var(b_var), d_sign(d_sign), d(d), ab_cmp(ab_cmp) {}
39+
mon_ol_key(lpvar ac_var, lpvar a, const rational& c_sign_rat, lpvar c,
40+
lpvar bd_var, lpvar b_var, const rational& d_sign_rat, lpvar d, llc ab_cmp)
41+
: ac_var(static_cast<short>(ac_var)), a(static_cast<short>(a)),
42+
c_sign(c_sign_rat.is_pos() ? 1 : (c_sign_rat.is_neg() ? -1 : 0)),
43+
c(static_cast<short>(c)), bd_var(static_cast<short>(bd_var)),
44+
b_var(static_cast<short>(b_var)),
45+
d_sign(d_sign_rat.is_pos() ? 1 : (d_sign_rat.is_neg() ? -1 : 0)),
46+
d(static_cast<short>(d)), ab_cmp(static_cast<unsigned char>(ab_cmp)) {}
4247

4348
bool operator==(const mon_ol_key& other) const {
4449
return ac_var == other.ac_var && a == other.a && c_sign == other.c_sign &&
@@ -49,13 +54,16 @@ class order: common {
4954

5055
struct mon_ol_key_hash {
5156
unsigned operator()(const mon_ol_key& k) const {
52-
return combine_hash(combine_hash(combine_hash(combine_hash(
53-
combine_hash(combine_hash(combine_hash(combine_hash(
54-
static_cast<unsigned>(k.ac_var), static_cast<unsigned>(k.a)),
55-
k.c_sign.hash()), static_cast<unsigned>(k.c)),
56-
static_cast<unsigned>(k.bd_var)), static_cast<unsigned>(k.b_var)),
57-
k.d_sign.hash()), static_cast<unsigned>(k.d)),
58-
static_cast<unsigned>(k.ab_cmp));
57+
// Optimized hash with better distribution using bit shifts
58+
unsigned h1 = (static_cast<unsigned>(k.ac_var) << 16) | static_cast<unsigned>(k.a);
59+
unsigned h2 = (static_cast<unsigned>(k.c_sign + 1) << 24) |
60+
(static_cast<unsigned>(k.c) << 8) | static_cast<unsigned>(k.bd_var);
61+
unsigned h3 = (static_cast<unsigned>(k.b_var) << 16) |
62+
((static_cast<unsigned>(k.d_sign + 1) << 8)) |
63+
static_cast<unsigned>(k.d);
64+
unsigned h4 = static_cast<unsigned>(k.ab_cmp);
65+
66+
return combine_hash(combine_hash(h1, h2), combine_hash(h3, h4));
5967
}
6068
};
6169

@@ -64,8 +72,44 @@ class order: common {
6472
const monic& bd, const factor& b, const rational& d_sign,
6573
lpvar d, llc ab_cmp, const std::string& debug_location);
6674

67-
int_hashtable<int_hash, default_eq<int>> m_processed_monics;
68-
bool throttle_monic(const monic&, const std::string & debug_location);
75+
// Structure to represent the key parameters for throttling order_lemma_on_binomial_sign
76+
// Optimized for memory efficiency with packed fields
77+
struct binomial_sign_key {
78+
short xy_var;
79+
short x;
80+
short y;
81+
signed char sign;
82+
signed char sy;
83+
84+
// Default constructor for hashtable
85+
binomial_sign_key() : xy_var(0), x(0), y(0), sign(0), sy(0) {}
86+
87+
binomial_sign_key(lpvar xy_var, lpvar x, lpvar y, int sign, int sy)
88+
: xy_var(static_cast<short>(xy_var)), x(static_cast<short>(x)),
89+
y(static_cast<short>(y)), sign(static_cast<signed char>(sign)),
90+
sy(static_cast<signed char>(sy)) {}
91+
92+
bool operator==(const binomial_sign_key& other) const {
93+
return xy_var == other.xy_var && x == other.x && y == other.y &&
94+
sign == other.sign && sy == other.sy;
95+
}
96+
};
97+
98+
struct binomial_sign_key_hash {
99+
unsigned operator()(const binomial_sign_key& k) const {
100+
// Optimized hash with better distribution
101+
unsigned h1 = (static_cast<unsigned>(k.xy_var) << 16) | static_cast<unsigned>(k.x);
102+
unsigned h2 = (static_cast<unsigned>(k.y) << 16) |
103+
((static_cast<unsigned>(k.sign + 127) << 8)) | // shift sign to positive range
104+
static_cast<unsigned>(k.sy + 127); // shift sy to positive range
105+
106+
return combine_hash(h1, h2);
107+
}
108+
};
109+
110+
hashtable<binomial_sign_key, binomial_sign_key_hash, default_eq<binomial_sign_key>> m_processed_binomial_sign;
111+
bool throttle_binomial_sign(const monic& xy, lpvar x, lpvar y, int sign, int sy, const std::string& debug_location);
112+
69113
private:
70114

71115
bool order_lemma_on_ac_and_bc_and_factors(const monic& ac,

src/math/lp/nla_solver.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ namespace nla {
107107
void solver::check_bounded_divisions() {
108108
m_core->check_bounded_divisions();
109109
}
110-
//return only the non-empty lemmas
111-
solver::non_empty_lemmas_range solver::lemmas() const {
112-
return non_empty_lemmas_range(m_core->lemmas());
110+
111+
const vector<lemma>& solver::lemmas() const {
112+
return m_core->lemmas();
113113
}
114114

115115
vector<nla::ineq> const& solver::literals() const {

src/math/lp/nla_solver.h

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -54,63 +54,7 @@ namespace nla {
5454
vector<lp::equality> const& equalities() const;
5555
bool should_check_feasible() const { return m_core->should_check_feasible(); }
5656

57-
// Iterator class for filtering out empty lemmas
58-
class non_empty_lemma_iterator {
59-
vector<nla::lemma>::const_iterator current_;
60-
vector<nla::lemma>::const_iterator end_;
61-
62-
void advance_to_non_empty() {
63-
while (current_ != end_ && current_->is_empty()) {
64-
std::cout << "skip\n";
65-
++current_;
66-
}
67-
}
68-
69-
public:
70-
non_empty_lemma_iterator(vector<nla::lemma>::const_iterator start,
71-
vector<nla::lemma>::const_iterator end)
72-
: current_(start), end_(end) {
73-
advance_to_non_empty();
74-
}
75-
76-
const nla::lemma& operator*() const { return *current_; }
77-
const nla::lemma* operator->() const { return &*current_; }
78-
79-
non_empty_lemma_iterator& operator++() {
80-
++current_;
81-
advance_to_non_empty();
82-
return *this;
83-
}
84-
85-
bool operator!=(const non_empty_lemma_iterator& other) const {
86-
return current_ != other.current_;
87-
}
88-
89-
bool operator==(const non_empty_lemma_iterator& other) const {
90-
return current_ == other.current_;
91-
}
92-
};
93-
94-
// Helper class to provide range-based iteration over non-empty lemmas
95-
class non_empty_lemmas_range {
96-
const vector<nla::lemma>& lemmas_;
97-
public:
98-
non_empty_lemmas_range(const vector<nla::lemma>& lemmas) : lemmas_(lemmas) {}
99-
100-
non_empty_lemma_iterator begin() const {
101-
return non_empty_lemma_iterator(lemmas_.begin(), lemmas_.end());
102-
}
103-
104-
non_empty_lemma_iterator end() const {
105-
return non_empty_lemma_iterator(lemmas_.end(), lemmas_.end());
106-
}
107-
108-
bool empty() const {
109-
return begin() == end();
110-
}
111-
};
112-
113-
non_empty_lemmas_range lemmas() const;
57+
const vector<nla::lemma>& lemmas() const;
11458

11559
};
11660
}

0 commit comments

Comments
 (0)