-
Notifications
You must be signed in to change notification settings - Fork 11
Alternate equality logic theory solver. #199
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
Open
matthiasgreen
wants to merge
50
commits into
feature/coloring
Choose a base branch
from
feature/eq-logic
base: feature/coloring
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 45 commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
00c4dd1
feat(eq): Add Directed Eq/Neq graph with specific algorithms
matthiasgreen 7bea240
feat(eq): Graph edge removal
matthiasgreen b18484e
feat(eq): Implement eq propagation
matthiasgreen e4fc873
fix(eq): handle activation events
matthiasgreen 30c562c
fix(eq): Fix and test backtracking
matthiasgreen 02b7278
fix(eq): Add inference causes
matthiasgreen 2caba47
refactor(eq): Refactor a couple functions
matthiasgreen 53c659f
feat(eq): Explain first draft
matthiasgreen c1f5ef6
fix(eq): Fix explanations and propagation, first working impl
matthiasgreen 5d26032
fix(eq): Add stats, change dft to bft, switch to cycle propagation
matthiasgreen 59dd5be
fix(eq): Small improvements
matthiasgreen 7aed0b5
fix(eq): Add correct constraints in solver_impl for eq and neq
matthiasgreen f598dc2
fix(eq): Improve AltEqTheory unit tests
matthiasgreen 5f607cd
refactor(eq): Reorganize modules
matthiasgreen 6b0d34e
feat(eq): Add propagation checking algorithm
matthiasgreen 8e2043f
fix(eq): Improve propagation algorithm
matthiasgreen 259c98f
fix(eq): fix infinite loop in path restitution
matthiasgreen a01c7f1
fix(eq): Remove undecided graph, replace with constraint hashmap, imp…
matthiasgreen 7f213b1
refactor(eq): Simplify generics, remove hashset of undecided props
matthiasgreen 71e3864
perf(eq): Greatly improve paths_requiring algorithm
matthiasgreen 59b4107
perf(eq): Multiple smaller optimisations
matthiasgreen 1000e09
fix(eq): Fix error with Neq diff expr
matthiasgreen 450b0ca
feat(eq): Replace HashMaps with RefMaps
matthiasgreen 1816877
feat(eq): Add graph statistics
matthiasgreen 932637e
perf(eq): Improve propagator addition
matthiasgreen cb34988
perf(ref): Improve ref collection allocation efficiency
matthiasgreen a9b7096
refactor(eq): Clean up theory
matthiasgreen 80c7295
feat(eq): Add id to node map with union-find
matthiasgreen 5c1651f
feat(eq): Rework graph traversal API and handle node groups
matthiasgreen c5bae7b
test(eq): Improve unit tests
matthiasgreen 8a0011f
fix(eq): Bug fixes and small performance improvements
matthiasgreen 8a98878
perf(eq): Improved graph node merging
matthiasgreen 1aa3910
chore(eq): Clean up
matthiasgreen 9dda90a
fix(eq): Fix tests and path enumerating algorithm
matthiasgreen 4e9fffe
fix(eq): Bugfixes and stats
matthiasgreen 1d992a8
refactor(eq): Simplify propagation
matthiasgreen c7849b4
perf(eq): Improve propagator handling
matthiasgreen 184c030
refactor(eq): Replace graph subset + fold with graph transform, add m…
matthiasgreen f7424b3
perf(eq): Add reusable scratches for fast graph traversal
matthiasgreen c0b0312
doc(eq): Lots of documentation
matthiasgreen c2933df
doc(eq): Finish documentation and clean up
matthiasgreen 0e95f51
chore(eq): Fix CI failures
matthiasgreen b31629b
feat(eq): Use BFS for explanations
matthiasgreen 970b67e
refactor(eq): Small improvements
matthiasgreen 310c2e1
feat(eq): Add edge deactivation propagation type
matthiasgreen f85df35
chore(eq): Fix reviewed changes
matthiasgreen 0a4836c
doc(eq): Add some high level documentation
matthiasgreen 8c5a7f6
perf(eq): Avoid allocations while collecting activations
matthiasgreen dacd024
test(eq): Add fuzzing tests for eq solver
matthiasgreen 80496df
test(eq): Add scopes to fuzz tests
matthiasgreen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,3 +12,4 @@ aries_fzn/share/aries_fzn | |
| __pycache__/ | ||
| *.profraw | ||
| lcov.info | ||
| profile.json.gz | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| use hashbrown::HashMap; | ||
| use std::fmt::Debug; | ||
|
|
||
| use crate::{ | ||
| collections::ref_store::RefVec, | ||
| core::{literals::Watches, Lit}, | ||
| create_ref_type, | ||
| }; | ||
|
|
||
| use super::{node::Node, relation::EqRelation}; | ||
|
|
||
| // TODO: Identical to STN, maybe identify some other common logic and bump up to reasoner module | ||
|
|
||
| /// Enabling information for a propagator. | ||
| /// A propagator should be enabled iff both literals `active` and `valid` are true. | ||
| #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] | ||
| pub struct Enabler { | ||
| /// A literal that is true (but not necessarily present) when the propagator must be active if present | ||
| pub active: Lit, | ||
| /// A literal that is true when the propagator is within its validity scope, i.e., | ||
| /// when is known to be sound to propagate a change from the source to the target. | ||
| /// | ||
| /// In the simplest case, we have `valid = presence(active)` since by construction | ||
| /// `presence(active)` is true iff both variables of the constraint are present. | ||
| /// | ||
| /// `valid` might a more specific literal but always with the constraints that | ||
| /// `presence(active) => valid` | ||
| pub valid: Lit, | ||
| } | ||
|
|
||
| impl Enabler { | ||
| pub fn new(active: Lit, valid: Lit) -> Enabler { | ||
| Enabler { active, valid } | ||
| } | ||
| } | ||
|
|
||
| #[derive(Debug, Clone, Copy)] | ||
| pub struct ActivationEvent { | ||
| /// the edge to enable | ||
| pub prop_id: ConstraintId, | ||
| } | ||
|
|
||
| impl ActivationEvent { | ||
| pub(crate) fn new(prop_id: ConstraintId) -> Self { | ||
| Self { prop_id } | ||
| } | ||
| } | ||
|
|
||
| create_ref_type!(ConstraintId); | ||
|
|
||
| impl Debug for ConstraintId { | ||
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
| writeln!(f, "Propagator {}", self.to_u32()) | ||
| } | ||
| } | ||
|
|
||
| /// One direction of a semi-reified eq or neq constraint. | ||
| /// | ||
| /// Formally enabler.active => a (relation) b | ||
| /// with enabler.valid = presence(b) => presence(a) | ||
| #[derive(Clone, Hash, Debug, PartialEq, Eq)] | ||
| pub struct Constraint { | ||
| pub a: Node, | ||
| pub b: Node, | ||
| pub relation: EqRelation, | ||
| pub enabler: Enabler, | ||
| } | ||
|
|
||
| impl Constraint { | ||
| pub fn new(a: Node, b: Node, relation: EqRelation, active: Lit, valid: Lit) -> Self { | ||
| Self { | ||
| a, | ||
| b, | ||
| relation, | ||
| enabler: Enabler::new(active, valid), | ||
| } | ||
| } | ||
|
|
||
| pub fn new_pair(a: Node, b: Node, relation: EqRelation, active: Lit, ab_valid: Lit, ba_valid: Lit) -> (Self, Self) { | ||
| ( | ||
| Self::new(a, b, relation, active, ab_valid), | ||
| Self::new(b, a, relation, active, ba_valid), | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| // #[derive(Debug, Clone, Copy)] | ||
| // enum Event { | ||
| // PropagatorAdded, | ||
| // WatchAdded(ConstraintId, Lit), | ||
| // } | ||
|
|
||
| /// Data structures to store propagators. | ||
| #[derive(Clone, Default)] | ||
| pub struct ConstraintStore { | ||
| constraints: RefVec<ConstraintId, Constraint>, | ||
| // constraint_lookup: HashMap<(Node, Node), Vec<ConstraintId>>, | ||
| in_constraints: HashMap<Node, Vec<ConstraintId>>, | ||
| out_constraints: HashMap<Node, Vec<ConstraintId>>, | ||
| watches: Watches<(Enabler, ConstraintId)>, | ||
| // trail: Trail<Event>, | ||
| } | ||
|
|
||
| impl ConstraintStore { | ||
| pub fn add_constraint(&mut self, constraint: Constraint) -> ConstraintId { | ||
| // assert_eq!(self.current_decision_level(), DecLvl::ROOT); | ||
| // self.trail.push(Event::PropagatorAdded); | ||
| let id = self.constraints.len().into(); | ||
| self.constraints.push(constraint.clone()); | ||
| self.out_constraints | ||
| .entry(constraint.a) | ||
| .and_modify(|v| v.push(id)) | ||
| .or_insert(vec![id]); | ||
| self.in_constraints | ||
| .entry(constraint.b) | ||
| .and_modify(|v| v.push(id)) | ||
| .or_insert(vec![id]); | ||
| id | ||
| } | ||
|
|
||
| pub fn add_watch(&mut self, id: ConstraintId, literal: Lit) { | ||
| let enabler = self.constraints[id].enabler; | ||
| self.watches.add_watch((enabler, id), literal); | ||
| // self.trail.push(Event::WatchAdded(id, literal)); | ||
| } | ||
|
|
||
| pub fn get_constraint(&self, constraint_id: ConstraintId) -> &Constraint { | ||
| &self.constraints[constraint_id] | ||
| } | ||
|
|
||
| // Get valid propagators by source and target | ||
| // pub fn get_constraints_between(&self, source: Node, target: Node) -> Vec<ConstraintId> { | ||
| // self.constraint_lookup.get(&(source, target)).cloned().unwrap_or(vec![]) | ||
| // } | ||
|
|
||
| pub fn get_out_constraints(&self, source: Node) -> Vec<ConstraintId> { | ||
| self.out_constraints.get(&source).cloned().unwrap_or_default() | ||
| } | ||
|
|
||
| pub fn get_in_constraints(&self, source: Node) -> Vec<ConstraintId> { | ||
| self.in_constraints.get(&source).cloned().unwrap_or_default() | ||
| } | ||
|
|
||
| pub fn enabled_by(&self, literal: Lit) -> impl Iterator<Item = (Enabler, ConstraintId)> + '_ { | ||
| self.watches.watches_on(literal) | ||
| } | ||
|
|
||
| pub fn iter(&self) -> impl Iterator<Item = (ConstraintId, &Constraint)> + use<'_> { | ||
| self.constraints.entries() | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| use std::fmt::{Debug, Formatter}; | ||
|
|
||
| use crate::collections::ref_store::IterableRefMap; | ||
|
|
||
| use super::{Edge, NodeId}; | ||
|
|
||
| #[derive(Default, Clone)] | ||
| pub struct EqAdjList(IterableRefMap<NodeId, Vec<Edge>>); | ||
|
|
||
| impl Debug for EqAdjList { | ||
| fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
| writeln!(f)?; | ||
| for (node, edges) in self.0.entries() { | ||
| if !edges.is_empty() { | ||
| writeln!(f, "{:?}:", node)?; | ||
| for edge in edges { | ||
| writeln!(f, " -> {:?} {:?}", edge.target, edge)?; | ||
| } | ||
| } | ||
| } | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| impl EqAdjList { | ||
| /// Insert a node if not present | ||
| fn insert_node(&mut self, node: NodeId) { | ||
| if !self.0.contains(node) { | ||
| self.0.insert(node, Default::default()); | ||
| } | ||
| } | ||
|
|
||
| /// Possibly insert an edge and both nodes | ||
| /// Returns true if edge was inserted | ||
| pub fn insert_edge(&mut self, edge: Edge) -> bool { | ||
| self.insert_node(edge.source); | ||
| self.insert_node(edge.target); | ||
| let edges = self.get_edges_mut(edge.source).unwrap(); | ||
| if edges.contains(&edge) { | ||
| false | ||
| } else { | ||
| edges.push(edge); | ||
| true | ||
| } | ||
| } | ||
|
|
||
| pub fn iter_edges(&self, node: NodeId) -> impl Iterator<Item = &Edge> { | ||
| self.0.get(node).into_iter().flat_map(|v| v.iter()) | ||
| } | ||
|
|
||
| pub fn get_edges_mut(&mut self, node: NodeId) -> Option<&mut Vec<Edge>> { | ||
| self.0.get_mut(node) | ||
| } | ||
|
|
||
| pub fn iter_all_edges(&self) -> impl Iterator<Item = Edge> + use<'_> { | ||
| self.0.entries().flat_map(|(_, e)| e.iter().cloned()) | ||
| } | ||
|
|
||
| pub fn iter_nodes(&self) -> impl Iterator<Item = NodeId> + use<'_> { | ||
| self.0.entries().map(|(n, _)| n) | ||
| } | ||
|
|
||
| pub fn remove_edge(&mut self, edge: Edge) { | ||
| if let Some(set) = self.0.get_mut(edge.source) { | ||
| set.retain(|e| *e != edge) | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.