Skip to content

Commit

Permalink
New, more versatile stability analysis module.
Browse files Browse the repository at this point in the history
  • Loading branch information
daemontus committed Mar 13, 2021
1 parent 2adcfa1 commit 0d29ea2
Show file tree
Hide file tree
Showing 9 changed files with 633 additions and 169 deletions.
309 changes: 173 additions & 136 deletions src/main.rs

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions src/scc/_impl_behaviour.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::scc::Behaviour;
use std::convert::TryFrom;

impl TryFrom<&str> for Behaviour {
type Error = String;

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"S" => Ok(Behaviour::Stability),
"D" => Ok(Behaviour::Disorder),
"O" => Ok(Behaviour::Oscillation),
_ => Err(format!("Invalid behaviour string `{}`.", value)),
}
}
}
12 changes: 12 additions & 0 deletions src/scc/_impl_classifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ impl Classifier {
(*data).clone()
}

/// Export only components that have the specified behaviour.
pub fn export_components_with_class(&self, class: Behaviour) -> Vec<GraphColoredVertices> {
let data = self.attractors.lock().unwrap().clone();
data.into_iter()
.filter_map(|(attractor, behaviour)| {
behaviour
.get(&class)
.map(|colors| attractor.intersect_colors(colors))
})
.collect()
}

/// Static function to classify just one component and immediately obtain results.
pub fn classify_component(
component: &GraphColoredVertices,
Expand Down
62 changes: 62 additions & 0 deletions src/scc/algo_stability_analysis/_impl_attractor_stability_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::scc::algo_stability_analysis::{AttractorStabilityData, Stability};
use crate::util::functional::Functional;
use biodivine_lib_param_bn::biodivine_std::traits::Set;
use biodivine_lib_param_bn::symbolic_async_graph::{
GraphColoredVertices, GraphColors, SymbolicAsyncGraph,
};
use biodivine_lib_param_bn::VariableId;
use std::ops::Index;

impl Index<Stability> for AttractorStabilityData {
type Output = GraphColors;

fn index(&self, index: Stability) -> &Self::Output {
match index {
Stability::True => &self.stability_true,
Stability::False => &self.stability_false,
Stability::Unstable => &self.unstable,
}
}
}

impl AttractorStabilityData {
/// Perform stability analysis for one attractor and one variable.
pub fn for_attractor(
graph: &SymbolicAsyncGraph,
attractor: &GraphColoredVertices,
variable: VariableId,
) -> AttractorStabilityData {
let var_is_true = graph.fix_network_variable(variable, true);
let var_is_false = graph.fix_network_variable(variable, false);
let colors_with_true = attractor.intersect(&var_is_true).colors();
let colors_with_false = attractor.intersect(&var_is_false).colors();
let colors_with_both = colors_with_true.intersect(&colors_with_false);
AttractorStabilityData {
stability_true: colors_with_true.minus(&colors_with_both),
stability_false: colors_with_false.minus(&colors_with_both),
unstable: colors_with_both,
}
.also(|data| {
let all = data
.stability_true
.union(&data.stability_false)
.union(&data.unstable);
if all != attractor.colors() {
panic!("Mismatched attractor colors.");
}
if !data
.stability_true
.intersect(&data.stability_false)
.is_empty()
{
panic!("FAIL");
}
if !data.stability_false.intersect(&data.unstable).is_empty() {
panic!("FAIL");
}
if !data.unstable.intersect(&data.stability_true).is_empty() {
panic!("FAIL");
}
})
}
}
49 changes: 49 additions & 0 deletions src/scc/algo_stability_analysis/_impl_stability.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use crate::scc::algo_stability_analysis::Stability;
use std::convert::TryFrom;
use std::fmt::{Display, Formatter};

impl Display for Stability {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Stability::True => write!(f, "true"),
Stability::False => write!(f, "false"),
Stability::Unstable => write!(f, "unstable"),
}
}
}

impl TryFrom<&str> for Stability {
type Error = String;

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"true" => Ok(Stability::True),
"false" => Ok(Stability::False),
"unstable" => Ok(Stability::Unstable),
_ => Err(format!("Invalid stability value `{}`.", value)),
}
}
}

#[cfg(test)]
mod tests {
use crate::scc::algo_stability_analysis::Stability;
use std::convert::TryFrom;

#[test]
pub fn stability_serialisation() {
assert_eq!(
Stability::True,
Stability::try_from(Stability::True.to_string().as_str()).unwrap()
);
assert_eq!(
Stability::False,
Stability::try_from(Stability::False.to_string().as_str()).unwrap()
);
assert_eq!(
Stability::Unstable,
Stability::try_from(Stability::Unstable.to_string().as_str()).unwrap()
);
assert!(Stability::try_from("TRUE").is_err());
}
}
155 changes: 155 additions & 0 deletions src/scc/algo_stability_analysis/_impl_stability_vector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
use crate::scc::algo_stability_analysis::{Stability, StabilityVector};
use crate::util::functional::Functional;
use json::JsonValue;
use std::convert::TryFrom;
use std::fmt::{Display, Formatter};
use std::ops::Shr;

impl Display for StabilityVector {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
if self.has_true {
if self.has_false || self.has_unstable {
write!(f, "true,")?;
} else {
write!(f, "true")?;
}
}
if self.has_false {
if self.has_unstable {
write!(f, "false,")?;
} else {
write!(f, "false")?;
}
}
if self.has_unstable {
write!(f, "unstable")?;
}
write!(f, "]")
}
}

impl From<StabilityVector> for usize {
fn from(vector: StabilityVector) -> Self {
0usize.apply(|id| {
if vector.has_true {
*id |= 0b1;
}
if vector.has_false {
*id |= 0b10;
}
if vector.has_unstable {
*id |= 0b100;
}
})
}
}

impl TryFrom<usize> for StabilityVector {
type Error = String;

fn try_from(value: usize) -> Result<Self, Self::Error> {
let mut vector = StabilityVector::default();
if value.shr(3) != 0usize {
return Err(format!("Invalid stability vector id: `{}`.", value));
}
vector.has_true = (value & 0b1) != 0;
vector.has_false = (value & 0b10) != 0;
vector.has_unstable = (value & 0b100) != 0;
Ok(vector)
}
}

impl TryFrom<&str> for StabilityVector {
type Error = String;

fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.starts_with('[') && value.ends_with(']') {
let value = &value[1..value.len() - 1];
let mut vector = StabilityVector::default();
for part in value.split(',') {
match part {
"true" => {
if vector.has_true {
return Err("Duplicate `true` in a stability vector.".to_string());
}
vector.has_true = true
}
"false" => {
if vector.has_false {
return Err("Duplicate `false` in a stability vector.".to_string());
}
vector.has_false = true
}
"unstable" => {
if vector.has_unstable {
return Err("Duplicate `unstable` in a stability vector.".to_string());
}
vector.has_unstable = true
}
_ => {
if !part.is_empty() {
return Err(format!("Unexpected `{}` in a stability vector.", part));
}
}
}
}
Ok(vector)
} else {
Err(format!("Invalid stability vector: `{}`.", value))
}
}
}

impl StabilityVector {
/// Create a new stability vector which includes the given stability value.
///
/// If the value is already present, current vector is only copied.
pub fn add(&self, stability: Stability) -> StabilityVector {
self.clone().apply(|out| match stability {
Stability::True => out.has_true = true,
Stability::False => out.has_false = true,
Stability::Unstable => out.has_unstable = true,
})
}

pub fn is_empty(&self) -> bool {
!(self.has_unstable || self.has_false || self.has_true)
}

pub fn to_json(&self) -> JsonValue {
JsonValue::new_array().apply(|array| {
if self.has_true {
array.push("true").unwrap();
}
if self.has_false {
array.push("false").unwrap();
}
if self.has_unstable {
array.push("unstable").unwrap();
}
})
}
}

#[cfg(test)]
mod tests {
use crate::scc::algo_stability_analysis::StabilityVector;
use std::convert::TryFrom;

#[test]
fn stability_to_string() {
for id in 0..8usize {
let vector = StabilityVector::try_from(id).unwrap();
assert_eq!(
vector,
StabilityVector::try_from(vector.to_string().as_str()).unwrap()
);
}
assert!(StabilityVector::try_from("true").is_err());
assert!(StabilityVector::try_from("[true,true]").is_err());
assert!(StabilityVector::try_from("[true-false]").is_err());
assert!(StabilityVector::try_from("[true,false,false]").is_err());
assert!(StabilityVector::try_from("[unstable,unstable,true]").is_err());
}
}
Loading

0 comments on commit 0d29ea2

Please sign in to comment.