@@ -437,6 +437,126 @@ void Counter::td_decompose() {
437437 verb_print (1 , " [td] decompose time: " << cpu_time () - my_time);
438438}
439439
440+ void Counter::compute_minfill_score () {
441+ auto nodes = opt_indep_support_end-1 ;
442+ if (!conf.do_td_use_opt_indep ) nodes = indep_support_end-1 ;
443+
444+ // Compute minfill scores for all variables
445+ // Score is based on the degree and potential fill-in when eliminating the variable
446+ // Takes into account current assignments: satisfied clauses are skipped,
447+ // and only unassigned variables contribute to the graph
448+
449+ // Build adjacency lists for each variable
450+ vector<set<uint32_t >> adj (nodes + 1 );
451+
452+ // Add edges from binary clauses
453+ all_lits (i) {
454+ Lit l (i/2 , i%2 == 0 );
455+ for (const auto & l2: watches[l].binaries ) {
456+ if (l2.red ()) continue ;
457+ if (l.var () > nodes || l2.lit ().var () > nodes) continue ;
458+
459+ // Skip if clause is already satisfied
460+ if (val (l) == T_TRI || val (l2.lit ()) == T_TRI) continue ;
461+
462+ // Only add edge if both variables are unassigned
463+ if (val (l.var ()) == X_TRI && val (l2.lit ().var ()) == X_TRI && l.var () != l2.lit ().var ()) {
464+ adj[l.var ()].insert (l2.lit ().var ());
465+ adj[l2.lit ().var ()].insert (l.var ());
466+ }
467+ }
468+ }
469+
470+ // Add edges from long clauses
471+ for (const auto & off: long_irred_cls) {
472+ Clause& cl = *alloc->ptr (off);
473+
474+ // Check if clause is satisfied and collect unassigned variables
475+ bool satisfied = false ;
476+ vector<uint32_t > unassigned_vars;
477+
478+ for (uint32_t i = 0 ; i < cl.sz ; i++) {
479+ if (val (cl[i]) == T_TRI) {
480+ satisfied = true ;
481+ break ;
482+ }
483+ if (cl[i].var () <= nodes && val (cl[i].var ()) == X_TRI) {
484+ unassigned_vars.push_back (cl[i].var ());
485+ }
486+ }
487+
488+ // Skip if clause is satisfied
489+ if (satisfied) continue ;
490+
491+ // Add edges between all pairs of unassigned variables
492+ for (size_t i = 0 ; i < unassigned_vars.size (); i++) {
493+ for (size_t j = i+1 ; j < unassigned_vars.size (); j++) {
494+ uint32_t v1 = unassigned_vars[i];
495+ uint32_t v2 = unassigned_vars[j];
496+ adj[v1].insert (v2);
497+ adj[v2].insert (v1);
498+ }
499+ }
500+ }
501+
502+ // Compute minfill score for each variable
503+ vector<uint32_t > fill_scores (nodes + 1 , 0 );
504+ uint32_t max_fill = 0 ;
505+ uint32_t num_unassigned = 0 ;
506+
507+ for (uint32_t v = 1 ; v <= nodes; v++) {
508+ // Skip assigned variables
509+ if (val (v) != X_TRI) continue ;
510+
511+ num_unassigned++;
512+
513+ // Count how many edges would need to be added between neighbors of v
514+ uint32_t fill_count = 0 ;
515+ vector<uint32_t > neighbors (adj[v].begin (), adj[v].end ());
516+
517+ for (size_t i = 0 ; i < neighbors.size (); i++) {
518+ for (size_t j = i+1 ; j < neighbors.size (); j++) {
519+ uint32_t n1 = neighbors[i];
520+ uint32_t n2 = neighbors[j];
521+ // If edge doesn't exist between neighbors, it would need to be added
522+ if (adj[n1].find (n2) == adj[n1].end ()) {
523+ fill_count++;
524+ }
525+ }
526+ }
527+
528+ fill_scores[v] = fill_count;
529+ if (fill_count > max_fill) max_fill = fill_count;
530+ }
531+
532+ // Normalize scores: lower fill-in gets higher score
533+ // We invert so that variables with low fill-in get high scores
534+ for (uint32_t v = 1 ; v <= nodes; v++) {
535+ // Skip assigned variables
536+ if (val (v) != X_TRI) {
537+ minfill_score[v] = 0.0 ;
538+ continue ;
539+ }
540+
541+ if (max_fill > 0 ) {
542+ minfill_score[v] = (double )(max_fill - fill_scores[v]) / (double )max_fill;
543+ } else {
544+ minfill_score[v] = 1.0 ;
545+ }
546+ }
547+
548+ // Compute weight similar to TD, using unassigned variables
549+ double ratio = num_unassigned > 0 ? (double )max_fill / (double )num_unassigned : 0.0 ;
550+ minfill_weight = exp (ratio * conf.minfill_exp_mult ) / conf.minfill_divider ;
551+ if (minfill_weight < conf.minfill_minweight ) minfill_weight = conf.minfill_minweight ;
552+ if (minfill_weight > conf.minfill_maxweight ) minfill_weight = conf.minfill_maxweight ;
553+
554+ verb_print (1 , " [minfill] max fill: " << max_fill
555+ << " unassigned: " << num_unassigned
556+ << " ratio: " << std::fixed << std::setprecision (3 ) << ratio
557+ << " weight: " << minfill_weight);
558+ }
559+
440560// Self-check count without restart with CMS only
441561FF Counter::check_count_norestart_cms (const Cube& c) {
442562 verb_print (1 , " Checking cube count with CMS (no verb, no restart)" );
@@ -1007,6 +1127,10 @@ vector<Cube> Counter::one_restart_count() {
10071127 tdscore.resize (nVars ()+1 , 0 );
10081128 td_decompose ();
10091129 }
1130+ if (conf.do_minfill ) {
1131+ minfill_score.clear ();
1132+ minfill_score.resize (nVars ()+1 , 0 );
1133+ }
10101134 count_loop ();
10111135 if (conf.verb >= 3 ) stats.print_short (this , comp_manager->get_cache ());
10121136 return mini_cubes;
@@ -1190,8 +1314,10 @@ void Counter::decide_lit() {
11901314 // The decision literal is now ready. Deal with it.
11911315 uint32_t v = 0 ;
11921316 switch (conf.decide ) {
1193- case 0 : v = find_best_branch (false , !conf.do_use_sat_solver ); break ;
1194- case 1 : v = find_best_branch (true , !conf.do_use_sat_solver ); break ;
1317+ case 0 : v = find_best_branch (false , true , !conf.do_use_sat_solver ); break ; // TD only
1318+ case 1 : v = find_best_branch (true , true , !conf.do_use_sat_solver ); break ; // ignore TD and minfill
1319+ case 2 : v = find_best_branch (true , false , !conf.do_use_sat_solver ); break ; // minfill only
1320+ case 3 : v = find_best_branch (false , false , !conf.do_use_sat_solver ); break ; // TD+minfill
11951321 default : assert (false );
11961322 }
11971323
@@ -1215,25 +1341,28 @@ void Counter::decide_lit() {
12151341}
12161342
12171343// The higher, the better. It is never below 0.
1218- double Counter::score_of (const uint32_t v, bool ignore_td) const {
1344+ double Counter::score_of (const uint32_t v, bool ignore_td, bool ignore_minfill ) const {
12191345 bool print = false ;
12201346 /* if (stats.decisions % 40000 == 0) print = 1; */
12211347 /* print = true; */
12221348 /* print = false; */
12231349 double act_score = 0 ;
12241350 double td_score = 0 ;
1351+ double minfill_sc = 0 ;
12251352 double freq_score = 0 ;
12261353
12271354 if (!tdscore.empty () && !ignore_td) td_score = td_weight*tdscore[v];
1355+ if (!minfill_score.empty () && !ignore_minfill) minfill_sc = minfill_weight*minfill_score[v];
12281356 act_score = var_act (v)/conf.act_score_divisor ;
12291357 freq_score = (double )comp_manager->freq_score_of (v)/conf.freq_score_divisor ;
1230- double score = act_score+td_score+freq_score;
1358+ double score = act_score+td_score+minfill_sc+ freq_score;
12311359 if (print) cout << " v: " << setw (4 ) << v
12321360 << setw (3 ) << " conflK: " << stats.conflicts /1000
12331361 << setw (5 ) << " decK: " << stats.decisions /1000
12341362 << setw (6 ) << " act_score: " << act_score/score
12351363 << setw (6 ) << " freq_score: " << freq_score/score
12361364 << setw (6 ) << " td_score: " << td_score/score
1365+ << setw (6 ) << " minfill_score: " << minfill_sc/score
12371366 << setw (6 ) << " total: " << score
12381367 << setw (6 ) << endl;
12391368
@@ -1269,7 +1398,7 @@ double Counter::td_lookahead_score(const uint32_t v, const uint32_t base_comp_tw
12691398 return -1 *std::max<int32_t >({w[0 ],w[1 ]})*w[0 ]*w[1 ];
12701399}
12711400
1272- uint32_t Counter::find_best_branch (const bool ignore_td, const bool also_nonindep) {
1401+ uint32_t Counter::find_best_branch (const bool ignore_td, const bool ignore_minfill, const bool also_nonindep) {
12731402 last_dec_candidates = 0 ;
12741403 bool only_optional_indep = true ;
12751404 uint32_t best_var = 0 ;
@@ -1278,6 +1407,9 @@ uint32_t Counter::find_best_branch(const bool ignore_td, const bool also_noninde
12781407 is_indep = false ;
12791408 bool couldnt_find_indep = false ; // only used when also_nonindep is true
12801409
1410+ if (!ignore_minfill && conf.do_minfill && (dec_level () < 4 || decisions.empty ()))
1411+ compute_minfill_score ();
1412+
12811413 VERBOSE_DEBUG_DO (cout << " decision level: " << dec_level () << " var options: " );
12821414 if (weighted ()) {
12831415 if (vars_act_dec.size () < (dec_level ()+1 ) * (nVars ()+1 )) {
@@ -1315,7 +1447,7 @@ uint32_t Counter::find_best_branch(const bool ignore_td, const bool also_noninde
13151447 if (dec_level () < conf.td_lookahead &&
13161448 tw > conf.td_lookahead_tw_cutoff )
13171449 score = td_lookahead_score (v, tw);
1318- else score = score_of (v, ignore_td) ;
1450+ else score = score_of (v, ignore_td, ignore_minfill ) ;
13191451 if (best_var == 0 || score > best_var_score) {
13201452 best_var = v;
13211453 best_var_score = score;
0 commit comments