When the SAT solver returns SAT, the resulting model provides a counterexample that distinguishes two nodes previously thought to be equivalent. This counterexample can be used to refine the entire set of candidates through resimulation:
|
// TODO: Refine equivalence classes based on counterexamples from SAT |
|
// solver |
This is quite effective to reduce the number of SAT calls.
So certainly the API change would be:
struct CexPattern {
DenseMap<Value, bool> inputAssignment;
};
FailureOr<CexPattern> extractCounterexample();
DenseMap<Value, bool> simulateSinglePattern(const CexPattern &pattern);
void refineCandidateClass(SmallVector<std::pair<Value, bool>> &members,
const DenseMap<Value, bool> &bitValues,
SmallVector<SmallVector<std::pair<Value, bool>>> &newClasses);
and changing the verification loop from the current:
for (member in class.drop_front())
verifyEquivalence(representative, member);
into a worklist:
SmallVector<SmallVector<Value>> pending = {members};
while (!pending.empty()) {
auto cls = pending.pop_back_val();
if (cls.size() <= 1) continue;
Value repr = chooseRepresentative(cls);
SmallVector<Value> proved{repr};
SmallVector<Value> disproved;
for (Value member : drop_front(cls)) {
switch (verifyEquivalence(repr, member)) {
case Proved:
proved.push_back(member);
break;
case Disproved: {
auto cex = extractCounterexample();
auto eval = simulateSinglePattern(*cex);
SmallVector<SmallVector<Value>> split;
refineCandidateClass(cls, eval, split);
pending.append(split.begin(), split.end());
goto next_class;
}
case Unknown:
// Give up a member.
}
}
recordProvenClass(proved);
next_class:;
}
This is a rough sketch so there might be a better way to implement this.
When the SAT solver returns SAT, the resulting model provides a counterexample that distinguishes two nodes previously thought to be equivalent. This counterexample can be used to refine the entire set of candidates through resimulation:
circt/lib/Dialect/Synth/Transforms/FunctionalReduction.cpp
Lines 571 to 572 in 5e21c95
This is quite effective to reduce the number of SAT calls.
So certainly the API change would be:
and changing the verification loop from the current:
into a worklist:
SmallVector<SmallVector<Value>> pending = {members}; while (!pending.empty()) { auto cls = pending.pop_back_val(); if (cls.size() <= 1) continue; Value repr = chooseRepresentative(cls); SmallVector<Value> proved{repr}; SmallVector<Value> disproved; for (Value member : drop_front(cls)) { switch (verifyEquivalence(repr, member)) { case Proved: proved.push_back(member); break; case Disproved: { auto cex = extractCounterexample(); auto eval = simulateSinglePattern(*cex); SmallVector<SmallVector<Value>> split; refineCandidateClass(cls, eval, split); pending.append(split.begin(), split.end()); goto next_class; } case Unknown: // Give up a member. } } recordProvenClass(proved); next_class:; }This is a rough sketch so there might be a better way to implement this.