feat: Semantic Minimisation during Conflict Analysis#406
feat: Semantic Minimisation during Conflict Analysis#406ImkoMarijnissen wants to merge 59 commits into
Conversation
… in semantic minimiser
This reverts commit b99b962.
…tive minimiser when when replaced
| while lower_bound != i32::MIN | ||
| && let Some((lb_updated, _)) = self.domains[domain].holes.get(&(lower_bound - 1)) | ||
| && *lb_updated | ||
| && context.get_checkpoint_for_predicate(predicate!(domain != lower_bound - 1)) | ||
| == Some(0) | ||
| { | ||
| lower_bound -= 1; | ||
| context.explain_root_assignment(predicate!(domain != lower_bound)); | ||
| } |
There was a problem hiding this comment.
If I understand this correctly, it introduces
There was a problem hiding this comment.
It only introduces the hole(s) when we have an element
There was a problem hiding this comment.
Hmm, I am not 100% sure I understand what you mean. Could you give a concrete example?
|
Can we remove semantic minimisation in |
…cy checking until after presence checking + setting value to 0
maartenflippo
left a comment
There was a problem hiding this comment.
Sorry :). More changes
| Atomic: AtomicConstraint, | ||
| { | ||
| pub fn reset_domain(&mut self, identified: Atomic::Identifier) { | ||
| let _ = self.domains.insert(identified, Domain::all_integers()); |
There was a problem hiding this comment.
If the domain is not present, let's not insert anything
| /// Decides whether to apply semantic minimisation during conflict analysis; according to the | ||
| /// idea proposed in "Semantic Learning for Lazy Clause Generation - Feydy et al. (2013)". | ||
| /// | ||
| /// If this flag is present then the minimisation is turned on. | ||
| /// | ||
| /// Possible values: bool | ||
| #[arg(long = "iterative-minimisation", verbatim_doc_comment)] | ||
| iterative_minimisation: bool, |
There was a problem hiding this comment.
Should be true by default?
| #[derive(Clone, Debug)] | ||
| struct IterativeDomain { | ||
| lb: i32, | ||
| ub: i32, | ||
| holes: Vec<i32>, | ||
| } |
There was a problem hiding this comment.
Seems like the VariableState?
There is probably a reason why this is necessary. In that case, please document it
| impl Default for ResolutionResolver { | ||
| fn default() -> Self { | ||
| ResolutionResolver::new(AnalysisMode::OneUIP, true) | ||
| ResolutionResolver::new(AnalysisMode::OneUIP, true, false) |
There was a problem hiding this comment.
Should the default be true?
| // println!("======================================================================"); | ||
| // println!("C: {conflict_nogood:?}"); |
| // println!( | ||
| // "WORKING NOGOOD: {:?}", | ||
| // self.processed_nogood_predicates | ||
| // .iter() | ||
| // .copied() | ||
| // .chain( | ||
| // self.to_process_heap | ||
| // .keys() | ||
| // .map(|id| self.predicate_id_generator.get_predicate(id)) | ||
| // ) | ||
| // .collect::<Vec<_>>() | ||
| // ); | ||
| // Replace the predicate from the nogood that has been assigned last on the trail. |
| // println!("R: {:?} -> {next_predicate}", self.reason_buffer); | ||
|
|
| }); | ||
| // Ignore root level predicates. | ||
| if dec_level == 0 { | ||
| // println!("{predicate:?} ROOT LEVEL"); |
| // println!( | ||
| // "FINAL NOGOOD: {:?}", | ||
| // self.processed_nogood_predicates | ||
| // .iter() | ||
| // .copied() | ||
| // .chain( | ||
| // self.to_process_heap | ||
| // .keys() | ||
| // .map(|id| self.predicate_id_generator.get_predicate(id)) | ||
| // ) | ||
| // .collect::<Vec<_>>() | ||
| // ); |
Closes #397.
After discussing with @maartenflippo, I implemented a very simple implementation of the
conjoinfunction from "Semantic Learning for Lazy Clause Generation - Feydy et al.".Some anecdotal examples of the effect:
For an RCPSP instance (
01.dzn), the number of failures goes from 3,711 to 3,376 and for another instance (J120_60_5), the number of failures to get to a solution of 108 is reduced from 28,303 to 27,855. Forfoxgeesecorn, the number of failures to get to an objective of 32 goes from 114,811 to 81,268.There are a few things which are not entirely clear to me:
conjoinfunction is underspecified, and it is somewhat unclear what exactly it does; for now, we assume that the elements in the working nogood are in the left side of the rewrite rules, and the added propagation reasons are on the right side of the rewrite rules. It was unclear to us what the reason for this is, but it appears to create incorrect nogoods otherwise.TODOs
Experimentation
In general, it appears to significantly improve the number of instances for which a solution is found at the cost of proving optimality on instances. This could be due to the fact that there are 24 OOM errors compared to the 42 OOM errors in
main. The MiniZinc score is also improved (even when filtering out instances where an error occurred; i.e., OOMs) quite significantly. This could be due to the fact that the average primal integral also appears to be significantly reduced.Overall Results
mainnewMiniZinc Score
Average Primal Integral