-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New, more versatile stability analysis module.
- Loading branch information
Showing
9 changed files
with
633 additions
and
169 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
src/scc/algo_stability_analysis/_impl_attractor_stability_data.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
155
src/scc/algo_stability_analysis/_impl_stability_vector.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | ||
} | ||
} |
Oops, something went wrong.