refactor: binary encoding of at most one clauses#37
refactor: binary encoding of at most one clauses#37baszalmstra wants to merge 13 commits intoprefix-dev:mainfrom
Conversation
|
This is really good work. I'm excited to see such a positive impact! |
|
Use the snapshots from #44 I can confirm that at least for the conda ecosystem this is a huge win. I used the This is what the graph looks like with this branch: |
|
I also can confirm that this implementation helps with the resolution — that's neat! I am looking at what needs to be fixed on the unsat reports so that it can be integrated. |
Sync with `main` + potential suggestions / rest of implementation (if any)
1d1a903 to
e42b8b1
Compare
|
I computed timing comparisons similar using the tools from #64: As we already know this PR is a clear win. |
|
Those also are greatly encouraging results, I will block some time to review it this week. |
jjerphan
left a comment
There was a problem hiding this comment.
A first naive pass.
I still need to have a look at the core of collapse_variable_nodes and to compare memory footprint and runtime from main's.
| pub(crate) enum ConflictNode { | ||
| /// Node corresponding to a solvable | ||
| Solvable(InternalSolvableId), | ||
| /// Node corresponding to a solvable |
There was a problem hiding this comment.
| /// Node corresponding to a solvable | |
| /// Node corresponding to a variable |
| /// A variable in the SAT problem. A variable either references a solvable, or | ||
| /// an intermediate variable. |
There was a problem hiding this comment.
| /// A variable in the SAT problem. A variable either references a solvable, or | |
| /// an intermediate variable. | |
| /// A variable in the SAT problem. A variable either references a solvable, or | |
| /// an intermediate variable which are generally introduced by the encoding of clauses. |
| pub fn reset(&mut self, variable: VarId) { | ||
| let (map, idx) = match variable.expand() { | ||
| ExpandedVar::Solvable(s) => (&mut self.solvables, s.to_usize()), | ||
| ExpandedVar::Variable(v) => (&mut self.variables, v as usize), |
There was a problem hiding this comment.
Must ExpandedVar::Variable also implement to_usize?
| /// In SAT terms: (¬A ∨ ¬B) | ||
| ForbidMultipleInstances(InternalSolvableId, InternalSolvableId, NameId), | ||
| ForbidMultipleInstances(InternalSolvableId, Literal, NameId), | ||
|
|
There was a problem hiding this comment.
Julien nitpicking: is this required?
| #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)] | ||
| pub(crate) struct InternalSolvableId(u32); | ||
|
|
||
| const INTERNAL_SOLVABLE_NULL: u32 = u32::MAX; |
There was a problem hiding this comment.
How about keeping this value and using it in implementations?
| /// Returns the null variable id. This is used to represent the absence | ||
| /// of a variable. | ||
| pub fn null() -> VarId { | ||
| VarId(u32::MAX) |
There was a problem hiding this comment.
| VarId(u32::MAX) | |
| VarId(INTERNAL_SOLVABLE_NULL) |
|
|
||
| /// Returns true if this variable id is null. | ||
| pub fn is_null(self) -> bool { | ||
| self.0 == u32::MAX |
There was a problem hiding this comment.
| self.0 == u32::MAX | |
| self.0 == INTERNAL_SOLVABLE_NULL |
| // use the "Binary Encoding" from | ||
| // https://www.it.uu.se/research/group/astra/ModRef10/papers/Alan%20M.%20Frisch%20and%20Paul%20A.%20Giannoros.%20SAT%20Encodings%20of%20the%20At-Most-k%20Constraint%20-%20ModRef%202010.pdf |
There was a problem hiding this comment.
| // use the "Binary Encoding" from | |
| // https://www.it.uu.se/research/group/astra/ModRef10/papers/Alan%20M.%20Frisch%20and%20Paul%20A.%20Giannoros.%20SAT%20Encodings%20of%20the%20At-Most-k%20Constraint%20-%20ModRef%202010.pdf | |
| // Use the "Binary Encoding" of the At-Most-One (AMO) clause | |
| // from Frisch, A.M., & Giannaros, P.A. (2010). | |
| // SAT Encodings of the At-Most-k Constraint Some Old, | |
| // Some New, Some Fast, Some Slow. | |
| // See: https://www.it.uu.se/research/group/astra/ModRef10/papers/Alan%20M.%20Frisch%20and%20Paul%20A.%20Giannoros.%20SAT%20Encodings%20of%20the%20At-Most-k%20Constraint%20-%20ModRef%202010.pdf |
| if candidates.len() == 2 { | ||
| let clause_id = clauses.alloc(ClauseState::forbid_multiple( | ||
| candidates[0].into(), | ||
| Literal { | ||
| var_id: candidates[1].into(), | ||
| negate: true, | ||
| }, | ||
| name_id, | ||
| )); | ||
|
|
||
| debug_assert!(clauses[clause_id].has_watches()); | ||
| output.clauses_to_watch.push(clause_id); | ||
| } else if candidates.len() == 3 { | ||
| for (a, b) in [(0, 1), (0, 2), (1, 2)] { | ||
| let clause_id = clauses.alloc(ClauseState::forbid_multiple( | ||
| candidates[a].into(), | ||
| Literal { | ||
| var_id: candidates[b].into(), | ||
| negate: true, | ||
| }, | ||
| name_id, | ||
| )); |
There was a problem hiding this comment.
Are those special cases of a particular encoding?
|
superseded by #91 |




This PR uses binary encoding to reduce the number of clauses added by a significant factor. My benchmarks show a performance improvement of at least 50%!
I did break unsat reports, that is something I have to look into.