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
use crate::{Monotonicity, Regulation, RegulatoryGraph, VariableId, ID_REGEX_STR};
use regex::Regex;

/// **(internal)** Regex which matches the regulation arrow string with `monotonicity`
/// and `observable` groups.
const REGULATION_ARROW_REGEX_STR: &str = r"-(?P<monotonicity>[|>?])(?P<observable>\??)";

lazy_static! {
    /// **(internal)** A regex which reads one line specifying a regulation.
    static ref REGULATION_REGEX: Regex = Regex::new(
        format!(
            // regulator ID, whitespace?, arrow string, whitespace?, target ID
            r"^(?P<regulator>{})\s*{}\s*(?P<target>{})$",
            ID_REGEX_STR,
            REGULATION_ARROW_REGEX_STR,
            ID_REGEX_STR,
        ).as_str()
    ).unwrap();
}

/// Basic getters.
impl Regulation {
    /// Check if the regulation is marked as observable.
    pub fn is_observable(&self) -> bool {
        self.observable
    }

    /// Return monotonicity of the regulation (if specified).
    pub fn get_monotonicity(&self) -> Option<Monotonicity> {
        self.monotonicity
    }

    /// Get the `VariableId` if the regulator.
    pub fn get_regulator(&self) -> VariableId {
        self.regulator
    }

    /// Get the `VariableId` of the target.
    pub fn get_target(&self) -> VariableId {
        self.target
    }
}

/// Serialization utility methods.
impl Regulation {
    /// Try to read all available information about a regulation from a given string
    /// in the standard format.
    ///
    /// The returned data correspond to the items as they appear in the string, i.e. `regulator`,
    /// `monotonicity`, `observability` and `target`. If the string is not valid, returns `None`.
    pub fn try_from_string(
        regulation: &str,
    ) -> Option<(String, Option<Monotonicity>, bool, String)> {
        REGULATION_REGEX
            .captures(regulation.trim())
            .map(|captures| {
                let monotonicity = match &captures["monotonicity"] {
                    "?" => None,
                    "|" => Some(Monotonicity::Inhibition),
                    ">" => Some(Monotonicity::Activation),
                    _ => unreachable!("Nothing else matches this group."),
                };
                let observable = captures["observable"].is_empty();
                (
                    captures["regulator"].to_string(),
                    monotonicity,
                    observable,
                    captures["target"].to_string(),
                )
            })
    }

    /// Convert to standard string format using variable names provided by a `RegulatoryGraph`.
    pub fn to_string(&self, context: &RegulatoryGraph) -> String {
        let monotonicity = match self.get_monotonicity() {
            None => "?",
            Some(Monotonicity::Activation) => ">",
            Some(Monotonicity::Inhibition) => "|",
        };
        let observability = if self.is_observable() { "" } else { "?" };
        format!(
            "{} -{}{} {}",
            context.get_variable_name(self.regulator),
            monotonicity,
            observability,
            context.get_variable_name(self.target)
        )
    }
}

#[cfg(test)]
mod tests {
    use crate::{BooleanNetwork, Regulation};
    use std::convert::TryFrom;

    #[test]
    fn regulation_conversion() {
        let bn = BooleanNetwork::try_from(
            r"
            a -?? b
            b -? c
            c ->? d
            d -> e
            e -|? f
            f -| g
        ",
        )
        .unwrap();

        for regulation in bn.graph.regulations() {
            let (r, m, o, t) =
                Regulation::try_from_string(&regulation.to_string(bn.as_graph())).unwrap();
            assert_eq!(&r, bn.get_variable_name(regulation.get_regulator()));
            assert_eq!(&t, bn.get_variable_name(regulation.get_target()));
            assert_eq!(m, regulation.get_monotonicity());
            assert_eq!(o, regulation.is_observable());
        }

        assert_eq!(None, Regulation::try_from_string("a --> b"));
    }
}