|
1 | 1 | use crate::biodivine_std::traits::Set;
|
2 | 2 | use crate::symbolic_async_graph::{GraphColoredVertices, SymbolicAsyncGraph};
|
| 3 | +use crate::{ExtendedBoolean, Space, VariableId}; |
3 | 4 |
|
4 | 5 | /// Here, we provide several basic symbolic algorithms for exploring the `SymbolicAsyncGraph`.
|
5 | 6 | /// This mainly includes reachability and similar fixed-point properties.
|
@@ -81,13 +82,67 @@ impl SymbolicAsyncGraph {
|
81 | 82 | return result;
|
82 | 83 | }
|
83 | 84 | }
|
| 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 | + } |
84 | 137 | }
|
85 | 138 |
|
86 | 139 | #[cfg(test)]
|
87 | 140 | mod tests {
|
88 | 141 | use crate::biodivine_std::traits::Set;
|
89 | 142 | 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; |
91 | 146 |
|
92 | 147 | #[test]
|
93 | 148 | pub fn basic_algorithms_test() {
|
@@ -125,4 +180,57 @@ mod tests {
|
125 | 180 | // where this is not empty -- less than in the pivot in fact.
|
126 | 181 | assert!(!repeller_basin.is_empty());
|
127 | 182 | }
|
| 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 | + } |
128 | 236 | }
|
0 commit comments