1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! # SCC Detection Algorithm
//!
//! Finally, let us examine a very basic algorithm built using this library:
//! symbolic detection of SCC components.
//!
//! First, we need to define simple forward/backward reachability procedures:
//!
//! ```rust
//! use biodivine_lib_param_bn::symbolic_async_graph::{GraphColoredVertices, SymbolicAsyncGraph};
//! use biodivine_lib_param_bn::biodivine_std::traits::Set;
//!
//! fn fwd(graph: &SymbolicAsyncGraph, initial: &GraphColoredVertices) -> GraphColoredVertices {
//!     let mut result = initial.clone();
//!     loop {
//!         let post = graph.post(&result);
//!         if post.is_subset(&result) {
//!             return result;
//!         } else {
//!             result = result.union(&post);
//!         }
//!     }
//! }
//!
//! fn bwd(graph: &SymbolicAsyncGraph, initial: &GraphColoredVertices) -> GraphColoredVertices {
//!     let mut result = initial.clone();
//!     loop {
//!         let post = graph.pre(&result);
//!         if post.is_subset(&result) {
//!             return result;
//!         } else {
//!             result = result.union(&post);
//!         }
//!     }
//! }
//! ```
//!
//! Note that in practice, it would be much better to use something like *saturation*, where
//! the transitions which are applied are selected greedily one at a time, instead of applying
//! them all at once using full `post` or `pre`. However, for the purpose of this tutorial, this
//! should be sufficient.
//!
//! Now we can observe that an SCC of vertex `v` is always the intersection of forward and backward
//! reachable vertices from `v`. Hence we can write the following simple algorithm:
//!
//! ```rust
//! # use biodivine_lib_param_bn::symbolic_async_graph::{SymbolicAsyncGraph, GraphColoredVertices};
//! # use biodivine_lib_param_bn::BooleanNetwork;
//! # use std::convert::TryFrom;
//! # use biodivine_lib_param_bn::biodivine_std::traits::Set;
//! # fn fwd(graph: &SymbolicAsyncGraph, initial: &GraphColoredVertices) -> GraphColoredVertices {
//! #     let mut result = initial.clone();
//! #     loop {
//! #         let post = graph.post(&result);
//! #         if post.is_subset(&result) {
//! #             return result;
//! #         } else {
//! #             result = result.union(&post);
//! #         }
//! #     }
//! # }
//!
//! # fn bwd(graph: &SymbolicAsyncGraph, initial: &GraphColoredVertices) -> GraphColoredVertices {
//! #     let mut result = initial.clone();
//! #     loop {
//! #         let post = graph.pre(&result);
//! #         if post.is_subset(&result) {
//! #             return result;
//! #         } else {
//! #             result = result.union(&post);
//! #         }
//! #     }
//! # }
//! fn scc(graph: &SymbolicAsyncGraph) -> Vec<GraphColoredVertices> {
//!     let mut universe = graph.mk_unit_colored_vertices();
//!     let mut components = Vec::new();
//!     while !universe.is_empty() {
//!         // Pick one vertex in universe for every color in universe
//!         let pivots = universe.pick_vertex();
//!         let fwd = fwd(graph, &pivots);
//!         let bwd = bwd(graph, &pivots);
//!         let scc = fwd.intersect(&bwd);
//!         universe = universe.minus(&scc);
//!         components.push(scc);
//!     }
//!     return components;
//! }
//! // Boolean network from the previous tutorial:
//! let bn = BooleanNetwork::try_from(r"
//!     A -> B
//!     C -|? B
//!     $B: A
//!     C -> A
//!     B -> A
//!     A -| A
//!     $A: C | f(A, B)
//! ").unwrap();
//! let stg = SymbolicAsyncGraph::new(bn).unwrap();
//!
//! // Note that since the symbolic graph contains different transitions for different colors,
//! // this will create SCCs that overlap for some colors but are completely different for others.
//! // Hence the same vertex can appear in multiple SCCs for different colors.
//! let components = scc(&stg);
//! assert_eq!(7, components.len());
//! assert_eq!(2.0, components[0].vertices().approx_cardinality());
//! assert_eq!(1.0, components[1].vertices().approx_cardinality());
//! assert_eq!(2.0, components[2].vertices().approx_cardinality());
//! assert_eq!(1.0, components[3].vertices().approx_cardinality());
//! assert_eq!(2.0, components[4].vertices().approx_cardinality());
//! assert_eq!(2.0, components[5].vertices().approx_cardinality());
//! assert_eq!(1.0, components[6].vertices().approx_cardinality());
//! ```
//!
//!