Skip to content

Commit 745e12e

Browse files
committed
Clean blocking implementation
1 parent 9a5b277 commit 745e12e

File tree

4 files changed

+233
-5
lines changed

4 files changed

+233
-5
lines changed

src/comp_analyzer.cpp

Lines changed: 225 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,214 @@ inline std::ostream& operator<<(std::ostream& os, const ClData& d)
4040
return os;
4141
}
4242

43+
void CompAnalyzer::calc_blocked(
44+
const LiteralIndexedVector<LitWatchList> & watches,
45+
const ClauseAllocator* alloc, const vector<ClauseOfs>& long_irred_cls)
46+
{
47+
const uint32_t n = max_var+1;
48+
clid_to_blocking_lits.resize(long_irred_cls.size()+1);
49+
if (!conf.do_blocked_clauses) return;
50+
51+
if (counter->get_opt_indep_support_end() >= max_var+1) {
52+
verb_print(1, "No need to calculate blocked clauses, as all vars are opt independent");
53+
return;
54+
}
55+
if (long_irred_cls.empty()) {
56+
verb_print(1, "No need to calculate blocked clauses, since there are only binary irred clauses");
57+
return;
58+
}
59+
if (n < 10) {
60+
verb_print(1, "No need to calculate blocked clauses, the number of variables is too low");
61+
return;
62+
}
63+
const double start_time = cpu_time();
64+
65+
// build occ lists
66+
vector<vector<Lit>> id_to_cl;
67+
vector<vector<uint32_t>> occs;
68+
occs.resize(n*2);
69+
uint32_t clid_bin_start;
70+
71+
if (true) {
72+
uint32_t clid = 1;
73+
id_to_cl.resize(1);
74+
vector<Lit> tmp;
75+
for (const auto& off: long_irred_cls) {
76+
const Clause& cl = *alloc->ptr(off);
77+
assert(cl.size() > 2);
78+
tmp.clear();
79+
tmp.insert(tmp.end(), cl.begin(), cl.end());
80+
for(const auto& l: cl) occs[l.raw()].push_back(clid);
81+
id_to_cl.push_back(tmp);
82+
assert(id_to_cl.size()-1 == clid);
83+
clid++;
84+
}
85+
clid_bin_start = clid;
86+
87+
for (uint32_t v = 1; v < n; v++) {
88+
for(uint32_t i = 0; i < 2; i++) {
89+
Lit l(v, i);
90+
for (const auto& bincl: watches[l].binaries) {
91+
if (bincl.irred()) {
92+
tmp.clear();
93+
tmp.push_back(l);
94+
tmp.push_back(bincl.lit());
95+
occs[tmp[0].raw()].push_back(clid);
96+
occs[tmp[1].raw()].push_back(clid);
97+
id_to_cl.push_back(tmp);
98+
assert(id_to_cl.size()-1 == clid);
99+
clid++;
100+
}
101+
}
102+
}
103+
}
104+
}
105+
106+
// System below does NOT work if any literal is already set
107+
// This is guaranteed to be NOT BAD if arjun is run before
108+
bool bad = false;
109+
for (uint32_t v = 1; v < n; v++) {
110+
for(uint32_t i = 0; i < 2; i++) {
111+
Lit l(v, i);
112+
if (!is_unknown(l)) bad = true;
113+
}
114+
}
115+
if (bad) {
116+
verb_print(1, "Some vars are not unknown, cannot calculate blocked clauses");
117+
return;
118+
}
119+
120+
uint32_t blocked_tot = 0;
121+
vector<char> seen(n*2, 0);
122+
vector<char> seen_set(n*2, 0);
123+
vector<Lit> seen_set_clear;
124+
vector<Lit> todo_lits;
125+
for (uint32_t v = 1; v < n; v++) for(uint32_t i = 0; i < 2; i++) todo_lits.push_back(Lit(v, i));
126+
std::shuffle(todo_lits.begin(), todo_lits.end(), mtrand);
127+
128+
int64_t todo_total = 400*1000LL*1000LL;
129+
uint32_t lit_abandoned = 0;
130+
for (const auto& l_set: todo_lits) {
131+
int64_t todo_per_lit = 1000*1000LL;
132+
if (todo_total <= 0) break;
133+
bool unsat = false;
134+
/* cout << "lit set: " << l_set << endl; */
135+
vector<Lit> prop_q;
136+
prop_q.push_back(l_set);
137+
// slow propagation..
138+
SLOW_DEBUG_DO(for(const auto& l: seen_set) assert(l == 0));
139+
while(!prop_q.empty()) {
140+
Lit p = prop_q.back();
141+
seen_set[p.raw()] = 1;
142+
seen_set_clear.push_back(p);
143+
prop_q.pop_back();
144+
for(const auto& cl_id: occs[l_set.neg().raw()]) {
145+
const auto& cl = id_to_cl[cl_id];
146+
bool sat = false;
147+
uint32_t unk = 0;
148+
Lit lit_unk = Lit();
149+
for(const auto& l: cl) {
150+
todo_per_lit--;
151+
todo_total--;
152+
if (seen_set[l.raw()]) {
153+
sat = 1;
154+
break;
155+
}
156+
if (seen[l.neg().raw()]) continue;
157+
unk++;
158+
lit_unk = l;
159+
if (unk > 1) break;
160+
}
161+
if (!sat && unk == 0) {
162+
// wow, unsat
163+
unsat = true;
164+
return;
165+
}
166+
if (sat) continue;
167+
if (unk == 1) prop_q.push_back(lit_unk);
168+
}
169+
}
170+
if (unsat) goto next;
171+
172+
for(uint32_t clid = 1; clid < clid_bin_start; clid++) {
173+
if (todo_per_lit <= 0) {lit_abandoned++; goto next;}
174+
const auto& cl = id_to_cl[clid];
175+
assert(cl.size() > 2);
176+
177+
// already satisfied
178+
bool sat_already = false;
179+
for(const auto& l: cl) if (seen_set[l.raw()]) {
180+
sat_already = true;
181+
break;
182+
}
183+
if (sat_already) continue;
184+
185+
// cannot actually be blocked
186+
bool could_be_blocked = false;
187+
for(const auto& l: cl) if (l.var() >= counter->get_opt_indep_support_end()) {
188+
could_be_blocked = true;
189+
break;
190+
}
191+
if (!could_be_blocked) continue;
192+
/* cout << "cl to block: " << cl << endl; */
193+
194+
bool blocked = false;
195+
SLOW_DEBUG_DO(for(const auto& l: seen) assert(l == 0));
196+
for(const auto& l: cl) seen[l.raw()] = 1;
197+
for(const auto& l: cl) if (l.var() >= counter->get_opt_indep_support_end()) {
198+
// could be blocked on this var, i.e. l.var()
199+
// must be blocked relative to all other clauses it could be resolved with
200+
blocked = true;
201+
for(const auto& clid2: occs[l.neg().raw()]) {
202+
bool blocked_rel_this = false;
203+
const auto& cl2 = id_to_cl[clid2];
204+
for(const auto& l2: cl2) {
205+
todo_per_lit--;
206+
todo_total--;
207+
if (l2.neg() == l) continue; // resolve on this, skip
208+
/* if (seen[l2.neg().raw()]) { */
209+
if (seen_set[l2.raw()]|| seen[l2.neg().raw()]) {
210+
/* cout << "blocked with cl2 " << cl2 << " on: " << l2
211+
* << " -- actually, set instead? " << (int)(l2 == l_set) << endl; */
212+
blocked_rel_this = true;
213+
break;
214+
}
215+
}
216+
if (!blocked_rel_this) {
217+
blocked = false;
218+
break;
219+
}
220+
}
221+
if (!blocked) continue; // try next var
222+
if (blocked) {
223+
/* cout << "BINGO! cl: " << cl << " blocked on: " << l << " given: " << l_set << endl; */
224+
clid_to_blocking_lits[clid].push_back(l_set);
225+
blocked_tot++;
226+
break;
227+
}
228+
}
229+
for(const auto& l: cl) seen[l.raw()] = 0;
230+
}
231+
232+
next:
233+
for(const auto& l: seen_set_clear) seen_set[l.raw()] = 0;
234+
seen_set_clear.clear();
235+
}
236+
237+
uint32_t cls_blocked = 0;
238+
for(auto& lits: clid_to_blocking_lits) {
239+
if (!lits.empty()) cls_blocked++;
240+
std::shuffle(lits.begin(), lits.end(), mtrand);
241+
}
242+
243+
verb_print(1, "Blocked tot: " << blocked_tot
244+
<< " lits abandoned: " << lit_abandoned << " global t-out: " << (todo_total <= 0)
245+
<< " t-remain: " << (double)todo_total/(1000.0*1000.0) << "M"
246+
<< " avg blocked/lit: " << (double)blocked_tot/(double)(n*2-2) << " T: " << cpu_time()-start_time);
247+
verb_print(1, "cls with blocked lits: " << cls_blocked << " / " << long_irred_cls.size()
248+
<< " = " << (double)cls_blocked/(double)long_irred_cls.size()*100 << "%");
249+
}
250+
43251
// Builds occ lists and sets things up, Done exactly ONCE for a whole counting runkk
44252
// this sets up unif_occ
45253
void CompAnalyzer::initialize(
@@ -60,7 +268,8 @@ void CompAnalyzer::initialize(
60268
return a.size() < b.size();
61269
};
62270
auto long_irred_cls = _long_irred_cls;
63-
std::sort(long_irred_cls.begin(), long_irred_cls.end(), mysorter);
271+
std::stable_sort(long_irred_cls.begin(), long_irred_cls.end(), mysorter);
272+
calc_blocked(watches, alloc, long_irred_cls);
64273

65274
max_clid = 1;
66275
max_tri_clid = 1;
@@ -74,17 +283,18 @@ void CompAnalyzer::initialize(
74283
const Clause& cl = *alloc->ptr(off);
75284
assert(cl.size() > 2);
76285
const uint32_t long_cl_off = long_clauses_data.size();
286+
77287
if (cl.size() > 3) {
78288
Lit blk_lit = cl[cl.size()/2];
79289
for(const auto&l: cl) long_clauses_data.push_back(l);
80290
long_clauses_data.push_back(SENTINEL_LIT);
81-
82291
for(const auto& l: cl) {
83292
const uint32_t var = l.var();
84293
assert(var < n);
85294
ClData d;
86295
d.id = max_clid;
87296
d.blk_lit = blk_lit;
297+
d.example_blocking = NOT_A_LIT;
88298
d.off = long_cl_off;
89299
unif_occ_long[var].push_back(d);
90300
}
@@ -98,6 +308,7 @@ void CompAnalyzer::initialize(
98308
ClData d;
99309
d.id = max_clid;
100310
d.blk_lit = lits[0];
311+
d.example_blocking = NOT_A_LIT;
101312
d.off = lits[1].raw();
102313
unif_occ_long[l.var()].push_back(d);
103314
}
@@ -183,11 +394,17 @@ void CompAnalyzer::initialize(
183394
}
184395
}
185396

186-
// check longs
397+
// check longs & adjust blocking lits to random ones
187398
for(uint32_t v = 0; v < unif_occ_long.size(); v++) {
188399
assert(unif_occ_long[v].size() == holder.size_long(v));
189400
for(uint32_t i = 0; i < unif_occ_long[v].size(); i++) {
190401
assert(unif_occ_long[v][i] == holder.begin_long(v)[i]);
402+
auto& d = holder.begin_long(v)[i];
403+
auto& blk_lits = clid_to_blocking_lits[d.id];
404+
if (!blk_lits.empty()) {
405+
std::uniform_int_distribution<uint32_t> dist(0, blk_lits.size()-1);
406+
d.example_blocking = blk_lits[dist(mtrand)];
407+
}
191408
}
192409
}
193410
}
@@ -342,7 +559,8 @@ void CompAnalyzer::record_comp(const uint32_t var, const uint32_t sup_comp_long_
342559
if (archetype.clause_unvisited_in_sup_comp(d.id)) {
343560
const Lit l1 = d.get_lit1();
344561
const Lit l2 = d.get_lit2();
345-
if (is_true(l1) || is_true(l2)) {
562+
if (is_true(l1) || is_true(l2) ||
563+
(d.example_blocking != NOT_A_LIT && is_true(d.example_blocking))) {
346564
archetype.clear_cl(d.id);
347565
sat = true;
348566
/* goto end_sat; */
@@ -355,7 +573,8 @@ void CompAnalyzer::record_comp(const uint32_t var, const uint32_t sup_comp_long_
355573
} else continue;
356574
} else {
357575
if (archetype.clause_unvisited_in_sup_comp(d.id)) {
358-
if (is_true(d.blk_lit)) {
576+
if (is_true(d.blk_lit) ||
577+
(d.example_blocking != NOT_A_LIT && is_true(d.example_blocking))) {
359578
archetype.clear_cl(d.id);
360579
sat = true;
361580
goto end_sat;
@@ -393,6 +612,7 @@ end_sat:;
393612
CompAnalyzer::CompAnalyzer(
394613
const LiteralIndexedVector<TriValue> & lit_values,
395614
Counter* _counter) :
615+
mtrand(_counter->get_conf().seed),
396616
values(lit_values),
397617
conf(_counter->get_conf()),
398618
indep_support_end(_counter->get_indep_support_end()),

src/comp_analyzer.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct ClData {
5252
uint32_t id;
5353
uint32_t off;
5454
Lit blk_lit;
55+
Lit example_blocking = NOT_A_LIT;
5556
bool operator==(const ClData& other) const {
5657
return id == other.id && off == other.off && blk_lit == other.blk_lit;
5758
}
@@ -178,6 +179,11 @@ class CompAnalyzer {
178179
CompArchetype& get_archetype() { return archetype; }
179180

180181
private:
182+
void calc_blocked(const LiteralIndexedVector<LitWatchList> & literals,
183+
const ClauseAllocator* alloc, const vector<ClauseOfs>& long_irred_cls);
184+
vector<vector<Lit>> clid_to_blocking_lits;
185+
std::mt19937_64 mtrand;
186+
181187
// the id of the last clause
182188
// note that clause ID is the clause number,
183189
// different from the offset of the clause in the literal pool

src/counter_config.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct CounterConfiguration {
4040
int max_num_rst = -1;
4141
uint32_t lbd_cutoff_always_keep_cube = 3;
4242
uint32_t max_num_cubes_per_restart = 6;
43+
int do_blocked_clauses = 1;
4344

4445
int cache_time_update = 2;
4546

src/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ void add_ganak_options()
133133
myopt("--appmct", conf.appmc_timeout, atof, "after K seconds");
134134
myopt("--epsilon", conf.appmc_epsilon, atof, "AppMC epsilon");
135135
myopt("--chronobt", conf.do_chronobt, atof, "ChronoBT. SAT must be DISABLED or this will fail");
136+
myopt("--blocked", conf.do_blocked_clauses, atof, "Blocked clauses, semi-dynamic, with example lit");
136137
//
137138
// Arjun options
138139
myopt("--arjun", do_arjun, atoi, "Use arjun");

0 commit comments

Comments
 (0)