-
Notifications
You must be signed in to change notification settings - Fork 17
Three-tier nogood management system #213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Currently, the function |
.high_lbd | ||
.iter() | ||
.chain(self.learned_nogood_ids.mid_lbd.iter()) | ||
.chain(self.learned_nogood_ids.low_lbd.iter()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comments above states that low-lbd nogoods do not get their activities updated. Should it be rescaled here then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch, I removed the iterator over low_lbd nogoods.
/// Learned nogoods are partitioned into three categories: high-, mid-, and low-lbd nogoods. | ||
/// Each tier has a predefined limit on the number of nogoods it may store. | ||
/// If a tier has more nogoods than the limit prescribes, roughly half of the nogoods from the | ||
/// tier are removed. High- and mid-tier nogoods remove the least active nogoods, whereas |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the sorting of low-tier nogoods based on the paper(s) or is this a design choice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is based on the paper listed right before this comment block. I tried to make this clear with the comments, can you have a look and let me know what was the issue?
context.is_predicate_falsified(watcher1) | ||
&& context | ||
.assignments | ||
.get_decision_level_for_predicate(&watcher1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As stated in the comments, get_decision_level_for_predicate
only works for satisfied predicates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, fixed!
p.s. "As stated in the comments" -> which comments? For me, there were no comments for get_decision_level_for_predicate
for the propagation context. I did add a comment now.
else { | ||
self.learned_nogood_ids.low_lbd.push(*id); | ||
false | ||
fn are_watched_predicates_falsified_at_root_level( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name could be a bit more clear to indicate that it checks whether one of the watchers is falsified at the root
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Now called has_a_watched_predicate_falsified_at_root_level
.
// We maintain a flag that signals if the process below will require another pass. | ||
// This can happen when the cached predicate is falsified at the root level. | ||
// Note that each nogood is watched twice. | ||
// Since we do not know if this is the first or second watcher with this nogood, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be clarified a bit; what is meant by 'this', and the first
or second
watcher is a bit unclear. Maybe something like:
When we encounter a watcher where its cached predicate is falsified at the root, we mark it as deleted. However, we could have encountered the other watcher (with a different cached predicate) attached to this nogood prior to encountering this watcher with a falsified cached predicate ; to ensure that we delete this other watcher as well, we require another pass
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, I updated the comment.
== 0 | ||
{ | ||
// Mark that a nogood has been deleted due to the cached predicate. | ||
another_pass_needed = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we can retrieve what Predicate
is being watched by the other watcher, perhaps we can do a more targeted deletion if this turns out to be a hotspot?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify? Here the nogood is deleted because of the cached predicate, and not a watched predicate.
Note that the first time we delete based on a watched predicate, the nogood gets marked as deleted, so it never tests its watched predicates again.
fn promote_mid_lbd_nogoods(&mut self) { | ||
self.learned_nogood_ids.mid_lbd.retain(|id| { | ||
// Still a mid-tier nogood? | ||
if self.nogood_info[*id].lbd > self.parameters.lbd_low { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a >
in this function but a >=
in the promote_high_lbd_nogoods
case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a comment in the if block. In short, the nogood is a mid-lbd nogood, so it is enough to test if it became a low-lbd nogood, otherwise it stays in the mid-lbd range.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it looks good, but I would suggest making a refactoring. Can we separate a NogoodDatabase
from the NogoodPropagator
and have the database be a field on the propagator? At the moment, everything is in the propagator and it is extremely confusing to discern what is concerned with propagation and what is concerned with database management.
/// Nogoods can move from higher tiers to lower tiers if the lbd drops sufficiently low, but | ||
/// not the other way around. This is the main difference regarding this aspect from the paper | ||
/// "Improving Implementation of SAT Competitions 2017–2019 Winners". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't low lbd go to high tiers? For completeness of this description we might want to include that. Right now, it seems a bit mysterious.
I drafted a new nogood management strategy. The previous version was a "temporary" solution that stayed for too long; this version is supposed to be better.
There are a few changes:
Can you please have a detailed look at the code, to see if something looks strange, e.g., does the code follow the comments?
In particular, there is an issue that surprises me, and where the tests fail. Have a look at the function
are_watched_predicates_falsified_at_root_level
. For some reason, when running the tests, getting a decision level for a predicate that is assigned fails - how is that possible?