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
114
115
116
117
118
119
120
121
122
123
124
125
//! *Legacy* semi-symbolic representation of the coloured asynchronous state-transition graph.
//!
//! It represents states explicitly (see `IdState`), but uses symbolic representation (`BddParams`)
//! for sets of parameters.
//!
//! **`AsyncGraph` in its current form and the related structures are deprecated in favour of
//! `SymbolicAsyncGraph`. We may re-implement it later under a new name and a new API, because
//! in some niche use cases it seems to be faster and/or easier to use than a fully symbolic
//! approach. However, try not to rely on this implementation too much.**
//!
#![allow(deprecated)]

use crate::bdd_params::{BddParameterEncoder, BddParams};
use crate::biodivine_std::structs::{IdState, IdStateRange};
use crate::biodivine_std::traits::{Graph, InvertibleGraph, Set};
use crate::{BooleanNetwork, VariableId, VariableIdIterator};

mod _impl_async_graph;
mod _impl_default_edge_params;
mod _impl_evolution_operators;

/// An asynchronous transition system of a `BooleanNetwork`. The states of the graph
/// are standard `IdState`s. The parameter sets are given by the associated `AsyncGraphEdgeParams`.
///
/// Async graph implements the standard "asynchronous update", i.e. every variable can be
/// non-deterministically updated at any time, but the actual parameters for which this
/// happens are determined by the `AsyncGraphEdgeParams`.
///
/// This actually hides a lot of complexity, because implementing `AsyncGraphEdgeParams` is typically
/// much easier than re-implementing the whole async graph structure.
///
/// **`AsyncGraph` in its current form and the related structures are deprecated in favour of
/// `SymbolicAsyncGraph`. We may re-implement it later under a new name and a new API, because
/// in some niche use cases it seems to be faster than fully symbolic approach. However,
/// try not to rely on this implementation too much.**
#[deprecated]
pub struct AsyncGraph<P: AsyncGraphEdgeParams> {
    edges: P,
}

/// Default implementation for edge parameters which adheres to the monotonicity and observability
/// constraints  of the network, but poses no other restrictions.
pub struct DefaultEdgeParams {
    network: BooleanNetwork,
    encoder: BddParameterEncoder,
    /// The parameter valuations which satisfy the static regulation constraints.
    unit_set: BddParams,
    empty_set: BddParams,
}

/// Async graph edges implement the edge colouring (parametrisation) of a graph. Instances of
/// this trait are used together with the `AsyncGraph` to produce a semantic coloured graph
/// of a parametrised Boolean network.
///
/// See `DefaultEdgeParams` for default implementation of edge colours.
///
/// This trait is especially useful when constructing things like wrappers of existing graphs,
/// which need to modify the behaviour of the graph. Another option are various custom
/// parameter encoders, where we simply do not want to re-implement the whole graph trait
/// front scratch.
pub trait AsyncGraphEdgeParams {
    type ParamSet: Set;
    // A reference to the underlying Boolean network.
    fn network(&self) -> &BooleanNetwork;
    /// Create a new empty set of parameters.
    fn empty_params(&self) -> &Self::ParamSet;
    /// Create a new full set of parameters.
    fn unit_params(&self) -> &Self::ParamSet;
    /// Create parameters for the edge starting in the given `state`,
    /// flipping the given `variable`.
    fn edge_params(&self, state: IdState, variable: VariableId) -> Self::ParamSet;
    /// Construct a witness network for the given set of parameters.
    ///
    /// TODO: It is not really essential in this trait. Think of a way to move it elsewhere.
    fn make_witness(&self, params: &Self::ParamSet) -> BooleanNetwork;
}

/// A forward `EvolutionOperator` of the `AsyncGraph`.
pub struct Fwd<'a, Edges: AsyncGraphEdgeParams> {
    graph: &'a AsyncGraph<Edges>,
}

/// A backward `EvolutionOperator` of the `AsyncGraph`.
pub struct Bwd<'a, Edges: AsyncGraphEdgeParams> {
    graph: &'a AsyncGraph<Edges>,
}

/// An iterator over successors of a state in the `AsyncGraph`.
pub struct FwdIterator<'a, Edges: AsyncGraphEdgeParams> {
    graph: &'a AsyncGraph<Edges>,
    state: IdState,
    variables: VariableIdIterator,
}

/// An iterator over predecessors of a state in the `AsyncGraph`.
pub struct BwdIterator<'a, Edges: AsyncGraphEdgeParams> {
    graph: &'a AsyncGraph<Edges>,
    state: IdState,
    variables: VariableIdIterator,
}

impl<'a, Edges: AsyncGraphEdgeParams> Graph for &'a AsyncGraph<Edges> {
    type State = IdState;
    type Params = Edges::ParamSet;
    type States = IdStateRange;
    type FwdEdges = Fwd<'a, Edges>;
    type BwdEdges = Bwd<'a, Edges>;

    fn states(&self) -> Self::States {
        IdStateRange::new(self.num_states())
    }

    fn fwd(&self) -> Self::FwdEdges {
        Fwd { graph: self }
    }

    fn bwd(&self) -> Self::BwdEdges {
        Bwd { graph: self }
    }
}

impl<'a, Edges: AsyncGraphEdgeParams> InvertibleGraph for &'a AsyncGraph<Edges> {
    type FwdEdges = Fwd<'a, Edges>;
    type BwdEdges = Bwd<'a, Edges>;
}