2022-08-30 15:42:35 +08:00

459 lines
12 KiB
C

#include "compact.h"
#include "inline.h"
#include "print.h"
#include "resize.h"
static void
reimport_literal (kissat * solver, unsigned eidx, unsigned mlit)
{
import *import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
assert (!import->eliminated);
LOG ("reimporting external variable %u as internal literal %u (was %u)",
eidx, mlit, import->lit);
import->lit = mlit;
}
unsigned
kissat_compact_literals (kissat * solver, unsigned *mfixed_ptr)
{
INC (compacted);
#if !defined(QUIET) || !defined(NDEBUG)
const unsigned active = solver->active;
#ifndef QUIET
const unsigned inactive = solver->vars - active;
kissat_phase (solver, "compact", GET (compacted),
"compacting garbage collection "
"(%u inactive variables %.2f%%)",
inactive, kissat_percent (inactive, solver->vars));
#endif
#endif
#ifdef LOGGING
assert (!solver->compacting);
solver->compacting = true;
#endif
unsigned mfixed = INVALID_LIT;
unsigned vars = 0;
for (all_variables (iidx))
{
const flags *flags = FLAGS (iidx);
if (flags->eliminated)
continue;
const unsigned ilit = LIT (iidx);
unsigned mlit;
if (flags->fixed)
{
const value value = kissat_fixed (solver, ilit);
assert (value);
if (mfixed == INVALID_LIT)
{
mlit = mfixed = LIT (vars);
LOG2 ("first fixed %u mapped to %u assigned to %d",
ilit, mfixed, value);
if (value < 0)
mfixed = NOT (mfixed);
LOG2 ("all other fixed mapped to %u", mfixed);
vars++;
}
else if (value < 0)
{
mlit = NOT (mfixed);
LOG2 ("negatively fixed %u mapped to %u", ilit, mlit);
}
else
{
mlit = mfixed;
LOG2 ("positively fixed %u mapped to %u", ilit, mlit);
}
}
else if (flags->active)
{
assert (flags->active);
mlit = LIT (vars);
LOG2 ("remapping %u to %u", ilit, mlit);
vars++;
}
else
{
const int elit = PEEK_STACK (solver->exportk, iidx);
if (elit)
{
const unsigned eidx = ABS (elit);
import *import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
assert (!import->eliminated);
import->imported = false;
LOG2 ("external variable %d not imported anymore", eidx);
POKE_STACK (solver->exportk, iidx, 0);
}
else
LOG2 ("skipping inactive %u", ilit);
continue;
}
assert (mlit <= ilit);
assert (mlit != NOT (ilit));
if (mlit == ilit)
continue;
const int elit = PEEK_STACK (solver->exportk, iidx);
const unsigned eidx = ABS (elit);
if (elit < 0)
mlit = NOT (mlit);
reimport_literal (solver, eidx, mlit);
}
*mfixed_ptr = mfixed;
LOG ("compacting to %u variables %.2f%% from %u",
vars, kissat_percent (vars, solver->vars), solver->vars);
assert (vars == active || vars == active + 1);
return vars;
}
static void
compact_literal (kissat * solver, unsigned dst_lit, unsigned src_lit)
{
assert (dst_lit < src_lit);
assert (dst_lit != NOT (src_lit));
const unsigned dst_idx = IDX (dst_lit);
const unsigned src_idx = IDX (src_lit);
assert (dst_idx != src_idx);
LOG ("mapping old internal literal %u to %u", src_lit, dst_lit);
solver->assigned[dst_idx] = solver->assigned[src_idx];
solver->flags[dst_idx] = solver->flags[src_idx];
solver->phases[dst_idx] = solver->phases[src_idx];
const unsigned not_src_lit = NOT (src_lit);
const unsigned not_dst_lit = NOT (dst_lit);
solver->values[dst_lit] = solver->values[src_lit];
solver->values[not_dst_lit] = solver->values[not_src_lit];
if(solver->heuristic==1 || solver->mab)
solver->conflicted_chb[dst_idx] = solver->conflicted_chb[src_idx];
if(solver->mab) solver->mab_chosen[dst_idx] = solver->mab_chosen[src_idx];
}
static unsigned
map_idx (kissat * solver, unsigned iidx)
{
int elit = PEEK_STACK (solver->exportk, iidx);
if (!elit)
return INVALID_IDX;
assert (elit);
const unsigned eidx = ABS (elit);
assert (eidx);
import *import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
if (import->eliminated)
return INVALID_IDX;
const unsigned mlit = import->lit;
const unsigned midx = IDX (mlit);
assert (midx <= iidx);
return midx;
}
static void
compact_queue (kissat * solver)
{
LOG ("compacting queue");
links *links = solver->links, *l;
unsigned *p = &solver->queue.first, prev = DISCONNECT;
solver->queue.stamp = 0;
for (unsigned idx; !DISCONNECTED (idx = *p); p = &l->next)
{
const unsigned midx = map_idx (solver, idx);
assert (midx != INVALID_IDX);
l = links + idx;
l->prev = prev;
l->stamp = ++solver->queue.stamp;
if (idx == solver->queue.search.idx)
{
solver->queue.search.idx = midx;
solver->queue.search.stamp = l->stamp;
}
*p = prev = midx;
}
solver->queue.last = prev;
*p = DISCONNECT;
for (all_variables (idx))
{
const unsigned midx = map_idx (solver, idx);
if (midx == INVALID_IDX)
continue;
links[midx] = links[idx];
}
}
static void
compact_scores (kissat * solver, unsigned vars, heap *old_scores)
{
LOG ("compacting scores");
heap new_scores;
memset (&new_scores, 0, sizeof new_scores);
kissat_resize_heap (solver, &new_scores, vars);
if (old_scores->tainted)
{
LOG ("copying scores of tainted old scores heap");
for (all_variables (idx))
{
const unsigned midx = map_idx (solver, idx);
if (midx == INVALID_IDX)
continue;
const double score = kissat_get_heap_score (old_scores, idx);
kissat_update_heap (solver, &new_scores, midx, score);
}
}
else
LOG ("no need to copy scores of old untainted scores heap");
LOG ("now pushing mapped literals onto new heap");
for (all_stack (unsigned, idx, old_scores->stack))
{
const unsigned midx = map_idx (solver, idx);
if (midx == INVALID_IDX)
continue;
kissat_push_heap (solver, &new_scores, midx);
}
kissat_release_heap (solver, old_scores);
if(solver->heuristic==0)
solver->scores = new_scores;
else
solver->scores_chb = new_scores;
}
static void
compact_trail (kissat * solver)
{
LOG ("compacting trail");
const size_t size = SIZE_STACK (solver->trail);
for (size_t i = 0; i < size; i++)
{
const unsigned ilit = PEEK_STACK (solver->trail, i);
const unsigned mlit = kissat_map_literal (solver, ilit, true);
assert (mlit != INVALID_LIT);
POKE_STACK (solver->trail, i, mlit);
const unsigned idx = IDX (ilit);
assigned *a = solver->assigned + idx;
if (!a->binary)
continue;
const unsigned other = a->reason;
assert (VALID_INTERNAL_LITERAL (other));
const unsigned mother = kissat_map_literal (solver, other, true);
assert (mother != INVALID_LIT);
a->reason = mother;
}
}
static void
compact_frames (kissat * solver)
{
LOG ("compacting frames");
const size_t size = SIZE_STACK (solver->frames);
for (size_t level = 1; level < size; level++)
{
frame *frame = &FRAME (level);
const unsigned ilit = frame->decision;
const unsigned mlit = kissat_map_literal (solver, ilit, true);
assert (mlit != INVALID_LIT);
frame->decision = mlit;
}
}
static void
compact_export (kissat * solver, unsigned vars)
{
LOG ("compacting export");
const size_t size = SIZE_STACK (solver->exportk);
assert (size <= UINT_MAX);
assert (size == solver->vars);
for (unsigned iidx = 0; iidx < size; iidx++)
{
const unsigned elit = PEEK_STACK (solver->exportk, iidx);
if (!elit)
continue;
const unsigned midx = map_idx (solver, iidx);
if (midx == INVALID_IDX)
continue;
POKE_STACK (solver->exportk, midx, elit);
}
RESIZE_STACK (solver->exportk, vars);
SHRINK_STACK (solver->exportk);
#ifndef NDEBUG
assert (SIZE_STACK (solver->exportk) == vars);
for (unsigned iidx = 0; iidx < vars; iidx++)
{
const int elit = PEEK_STACK (solver->exportk, iidx);
assert (VALID_EXTERNAL_LITERAL (elit));
const unsigned eidx = ABS (elit);
const import *import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
if (import->eliminated)
continue;
unsigned mlit = import->lit;
if (elit < 0)
mlit = NOT (mlit);
const unsigned ilit = LIT (iidx);
assert (mlit == ilit);
}
#endif
}
static void
compact_units (kissat * solver, unsigned mfixed)
{
LOG ("compacting units (first fixed %u)", mfixed);
assert (kissat_fixed (solver, mfixed) > 0);
for (all_stack (int, elit, solver->units))
{
const unsigned eidx = ABS (elit);
const unsigned mlit = elit < 0 ? NOT (mfixed) : mfixed;
const import *import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
assert (!import->eliminated);
const unsigned ilit = import->lit;
if (mlit != ilit)
reimport_literal (solver, eidx, mlit);
}
}
static void
compact_transitive (kissat * solver, unsigned vars)
{
unsigned mlit = 0;
if (vars)
{
unsigned ilit = solver->transitive;
unsigned iidx = IDX (ilit);
if (ACTIVE (iidx))
mlit = kissat_map_literal (solver, ilit, true);
else
{
while (iidx < VARS && !ACTIVE (iidx))
iidx++;
if (iidx == VARS)
mlit = INVALID_LIT;
else
{
ilit = LIT (iidx);
mlit = kissat_map_literal (solver, ilit, true);
}
}
if (mlit == INVALID_LIT)
mlit = 0;
}
LOG ("new transitive reduction starting literal %u", mlit);
solver->transitive = mlit;
}
static void
compact_best_and_target_values (kissat * solver, unsigned vars)
{
const phase *phases = solver->phases;
const flags *flags = solver->flags;
unsigned best_assigned = 0;
unsigned target_assigned = 0;
for (unsigned idx = 0; idx < vars; idx++)
{
if (!flags[idx].active)
continue;
const phase *p = phases + idx;
if (p->target)
target_assigned++;
if (p->best)
best_assigned++;
}
if (solver->target_assigned != target_assigned)
{
LOG ("compacting target assigned from %u to %u",
solver->target_assigned, target_assigned);
solver->target_assigned = target_assigned;
}
if (solver->best_assigned != best_assigned)
{
LOG ("compacting best assigned from %u to %u",
solver->best_assigned, best_assigned);
solver->best_assigned = best_assigned;
}
kissat_reset_consistently_assigned (solver);
}
void
kissat_finalize_compacting (kissat * solver, unsigned vars, unsigned mfixed)
{
LOG ("finalizing compacting");
assert (vars <= solver->vars);
#ifdef LOGGING
assert (solver->compacting);
#endif
if (vars == solver->vars)
{
#ifdef LOGGING
solver->compacting = false;
LOG ("number of variables does not change");
#endif
return;
}
unsigned reduced = solver->vars - vars;
LOG ("compacted number of variables from %u to %u", solver->vars, vars);
compact_transitive (solver, vars);
bool first = true;
for (all_variables (iidx))
{
flags *flags = FLAGS (iidx);
if (flags->fixed && first)
first = false;
else if (!flags->active)
POKE_STACK (solver->exportk, iidx, 0);
}
compact_trail (solver);
for (all_variables (iidx))
{
const unsigned ilit = LIT (iidx);
const unsigned mlit = kissat_map_literal (solver, ilit, true);
if (mlit != INVALID_LIT && ilit != mlit)
compact_literal (solver, mlit, ilit);
}
if (mfixed != INVALID_LIT)
compact_units (solver, mfixed);
memset (solver->assigned + vars, 0, reduced * sizeof (assigned));
memset (solver->flags + vars, 0, reduced * sizeof (flags));
memset (solver->values + 2 * vars, 0, 2 * reduced * sizeof (value));
memset (solver->watches + 2 * vars, 0, 2 * reduced * sizeof (watches));
if(solver->heuristic==1 || solver->mab)
memset (solver->conflicted_chb + vars, 0, reduced * sizeof (unsigned));
if(solver->mab) memset (solver->mab_chosen + vars, 0, reduced * sizeof (unsigned));
compact_queue (solver);
// MAB
if(solver->mab){
unsigned old_heuristic = solver->heuristic;
solver->heuristic = 0;
compact_scores (solver, vars,&solver->scores);
solver->heuristic = 1;
compact_scores (solver, vars,&solver->scores_chb);
solver->heuristic = old_heuristic;
}else compact_scores (solver, vars,solver->heuristic==0?&solver->scores:&solver->scores_chb);
compact_frames (solver);
compact_export (solver, vars);
compact_best_and_target_values (solver, vars);
solver->vars = vars;
#ifdef LOGGING
solver->compacting = false;
#endif
kissat_decrease_size (solver);
}