Skip to content

Commit d4f1d35

Browse files
committed
Add basic percolation method.
1 parent e340393 commit d4f1d35

File tree

2 files changed

+123
-2
lines changed

2 files changed

+123
-2
lines changed

src/_impl_space.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
use crate::symbolic_async_graph::SymbolicContext;
12
use crate::ExtendedBoolean::{Any, One, Zero};
23
use crate::{BooleanNetwork, ExtendedBoolean, Space, VariableId};
4+
use biodivine_lib_bdd::BddVariable;
35
use std::cmp::Ordering;
46
use std::fmt::{Display, Formatter};
57
use std::ops::{Index, IndexMut};
@@ -75,7 +77,18 @@ impl Space {
7577
let mut result = Vec::new();
7678
for (k, v) in self.0.iter().enumerate() {
7779
if let Some(v) = v.try_as_bool() {
78-
result.push((VariableId::from_index(k), v))
80+
result.push((VariableId::from_index(k), v));
81+
}
82+
}
83+
result
84+
}
85+
86+
/// The same as [Self::to_values], but uses [BddVariable] instead of [VariableId]. Internal for now.
87+
pub(crate) fn to_symbolic_values(&self, context: &SymbolicContext) -> Vec<(BddVariable, bool)> {
88+
let mut result = Vec::new();
89+
for (k, v) in self.0.iter().enumerate() {
90+
if let Some(v) = v.try_as_bool() {
91+
result.push((context.state_variables()[k], v));
7992
}
8093
}
8194
result

src/symbolic_async_graph/_impl_symbolic_async_graph_algorithm.rs

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::biodivine_std::traits::Set;
22
use crate::symbolic_async_graph::{GraphColoredVertices, SymbolicAsyncGraph};
3+
use crate::{ExtendedBoolean, Space, VariableId};
34

45
/// Here, we provide several basic symbolic algorithms for exploring the `SymbolicAsyncGraph`.
56
/// This mainly includes reachability and similar fixed-point properties.
@@ -81,13 +82,67 @@ impl SymbolicAsyncGraph {
8182
return result;
8283
}
8384
}
85+
86+
/// Returns `true` if the update function of [VariableId] can evaluate to `false` in the given space.
87+
pub fn space_has_var_false(&self, var: VariableId, space: &Space) -> bool {
88+
let space = space.to_symbolic_values(self.symbolic_context());
89+
!self.get_symbolic_fn_update(var).restrict(&space).is_true()
90+
}
91+
92+
/// Returns `true` if the update function of [VariableId] can evaluate to `true` in the given space.
93+
pub fn space_has_var_true(&self, var: VariableId, space: &Space) -> bool {
94+
let space = space.to_symbolic_values(self.symbolic_context());
95+
!self.get_symbolic_fn_update(var).restrict(&space).is_false()
96+
}
97+
98+
/// Compute a percolation of the given space.
99+
///
100+
/// The method has two modes: If `fix_subspace` is set to `true`, the method will only try to update
101+
/// variables that are not fixed yet. If `fix_subspace` is `false`, the method can also update variables
102+
/// that are fixed in the original space.
103+
///
104+
/// If the input is a trap space, these two modes should give the same result.
105+
pub fn percolate_space(&self, space: &Space, fix_subspace: bool) -> Space {
106+
let mut result = space.clone();
107+
'percolate: loop {
108+
let symbolic_space = result.to_symbolic_values(self.symbolic_context());
109+
for var in self.variables().rev() {
110+
if fix_subspace && space[var].is_fixed() {
111+
// In fixed mode, we do not propagate values that are fixed in the original space.
112+
continue;
113+
}
114+
115+
let update = self.get_symbolic_fn_update(var);
116+
let restricted = update.restrict(&symbolic_space);
117+
let new_value = if restricted.is_true() {
118+
ExtendedBoolean::One
119+
} else if restricted.is_false() {
120+
ExtendedBoolean::Zero
121+
} else {
122+
ExtendedBoolean::Any
123+
};
124+
125+
if result[var] != new_value {
126+
// If we can update result, we do it and restart the percolation process.
127+
result[var] = new_value;
128+
continue 'percolate;
129+
}
130+
}
131+
// If nothing changed, we are done.
132+
break;
133+
}
134+
135+
result
136+
}
84137
}
85138

86139
#[cfg(test)]
87140
mod tests {
88141
use crate::biodivine_std::traits::Set;
89142
use crate::symbolic_async_graph::SymbolicAsyncGraph;
90-
use crate::BooleanNetwork;
143+
use crate::ExtendedBoolean::Zero;
144+
use crate::{BooleanNetwork, ExtendedBoolean, Space};
145+
use ExtendedBoolean::One;
91146

92147
#[test]
93148
pub fn basic_algorithms_test() {
@@ -125,4 +180,57 @@ mod tests {
125180
// where this is not empty -- less than in the pivot in fact.
126181
assert!(!repeller_basin.is_empty());
127182
}
183+
184+
#[test]
185+
fn basic_percolation_test() {
186+
let bn = BooleanNetwork::try_from_bnet(
187+
r"
188+
targets,factors
189+
a, a | b
190+
b, c & a
191+
c, (a & b) | (a & c)
192+
",
193+
)
194+
.unwrap();
195+
let stg = SymbolicAsyncGraph::new(&bn).unwrap();
196+
197+
let a = bn.as_graph().find_variable("a").unwrap();
198+
let b = bn.as_graph().find_variable("b").unwrap();
199+
let c = bn.as_graph().find_variable("c").unwrap();
200+
201+
let mut a_true = Space::new(&bn);
202+
a_true[a] = One;
203+
204+
let mut a_false = Space::new(&bn);
205+
a_false[a] = Zero;
206+
207+
let a_true_percolated = stg.percolate_space(&a_true, false);
208+
assert_eq!(a_true, a_true_percolated);
209+
210+
let a_false_percolated = stg.percolate_space(&a_false, false);
211+
let mut expected = Space::new(&bn);
212+
expected[a] = Zero;
213+
expected[b] = Zero;
214+
expected[c] = Zero;
215+
assert_eq!(expected, a_false_percolated);
216+
217+
let mut unstable = Space::new(&bn);
218+
unstable[b] = One;
219+
let mut expected = Space::new(&bn);
220+
assert_eq!(expected, stg.percolate_space(&unstable, false));
221+
expected[b] = One;
222+
expected[a] = One;
223+
expected[c] = One;
224+
assert_eq!(expected, stg.percolate_space(&unstable, true));
225+
226+
assert!(stg.space_has_var_false(b, &a_true));
227+
assert!(stg.space_has_var_true(b, &a_true));
228+
assert!(stg.space_has_var_false(c, &a_true));
229+
assert!(stg.space_has_var_true(c, &a_true));
230+
231+
assert!(stg.space_has_var_false(b, &a_false));
232+
assert!(!stg.space_has_var_true(b, &a_false));
233+
assert!(stg.space_has_var_false(c, &a_false));
234+
assert!(!stg.space_has_var_true(c, &a_false));
235+
}
128236
}

0 commit comments

Comments
 (0)