Skip to content

Commit

Permalink
fix(solver): bug in incremental DFS of implication graph.
Browse files Browse the repository at this point in the history
  • Loading branch information
arbimo committed May 25, 2023
1 parent fbfe429 commit 1561c9f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 6 deletions.
32 changes: 31 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions solver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ env_param = { path = "../env_param" }
smallvec = "1.4.2"
num-integer = { default-features = false, version = "0.1.44" }
tracing = { workspace = true }
lru = "0.10.0"

[dev-dependencies]
rand = "0.8"
17 changes: 12 additions & 5 deletions solver/src/core/literals/implication_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl Clone for ImplicationGraph {
}
}

/// A cache of the least recently used DFS states. This reduces the cost of two subsequent reachability queries from the same source.
struct CachedDFS {
cached_states: Mutex<lru::LruCache<Lit, DFSState>>,
}
Expand All @@ -104,17 +105,20 @@ impl Default for CachedDFS {
}

impl CachedDFS {
/// Returns true if source literal is reachable (implies) the target one in the graph induces by `edges`.
/// Some intermediate computations are cached so the cache should be cleared if the edges have changed since the last invocation
pub fn reachable(&self, source: Lit, target: Lit, edges: &Watches<Lit>) -> bool {
if let Ok(ref mut mutex) = self.cached_states.try_lock() {
mutex
.get_or_insert_mut(source, || DFSState::new(source))
.reachable(target, edges)
} else {
// could not get a lock, on the cache, just proceed
// could not get a lock on the cache, just proceed
DFSState::new(source).reachable(target, edges)
}
}

/// Clear any cache result.
pub fn clear(&mut self) {
self.cached_states.lock().unwrap().clear()
}
Expand Down Expand Up @@ -146,17 +150,19 @@ impl DFSState {
}
// dfs through implications
while let Some(curr) = self.queue.pop() {
if curr.entails(target) {
return true;
}

// to ensure correctness if the search proceeds again, we need to add all elements
for next in edges.watches_on(curr) {
if !self.visited.contains(next) {
self.queue.push(next);
self.visited.insert(next);
}
}
// the state is clean for possibly continuing, check if we can stop immediately
if curr.entails(target) {
return true;
}
}
debug_assert!(self.queue.is_empty() && !self.visited.contains(target));
false
}
}
Expand Down Expand Up @@ -189,6 +195,7 @@ mod test {
assert!(!g.implies(A.leq(1), B.leq(0)));

g.add_implication(B.leq(2), C.leq(2));
assert!(g.implies(A.leq(1), B.leq(1)));
assert!(g.implies(A.leq(1), C.leq(2)));
assert!(g.implies(A.leq(1), C.leq(3)));
assert!(!g.implies(A.leq(1), C.leq(1)));
Expand Down

0 comments on commit 1561c9f

Please sign in to comment.