Frequency struct for positive rs
Also loops now in LoopEnvironment trait
This commit is contained in:
@ -9,7 +9,7 @@ fn main() {
|
|||||||
|
|
||||||
match presets::run(input) {
|
match presets::run(input) {
|
||||||
Ok(()) => {},
|
Ok(()) => {},
|
||||||
Err(e) => {println!("{e}")}
|
Err(e) => println!("{e}")
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{} milliseconds elapsed", now.elapsed().as_millis());
|
println!("{} milliseconds elapsed", now.elapsed().as_millis());
|
||||||
|
|||||||
@ -308,8 +308,7 @@ where S: PrintableWithTranslator {
|
|||||||
write!(f, "{}", Formatter::from(translator, &**l)),
|
write!(f, "{}", Formatter::from(translator, &**l)),
|
||||||
Self::Set(set) => write!(f, "{}", Formatter::from(translator, set)),
|
Self::Set(set) => write!(f, "{}", Formatter::from(translator, set)),
|
||||||
Self::Element(el) =>
|
Self::Element(el) =>
|
||||||
write!(f, "'{}'",
|
write!(f, "'{}'", Formatter::from(translator, el)),
|
||||||
translator.decode(*el).unwrap_or("Missing".into())),
|
|
||||||
Self::String(s) => write!(f, r#""{s}""#),
|
Self::String(s) => write!(f, r#""{s}""#),
|
||||||
Self::Var(v) => write!(f, "{}", Formatter::from(translator, v)),
|
Self::Var(v) => write!(f, "{}", Formatter::from(translator, v)),
|
||||||
Self::Unary(u, exp) => {
|
Self::Unary(u, exp) => {
|
||||||
@ -452,8 +451,7 @@ impl PrintableWithTranslator for AssertReturnValue {
|
|||||||
Self::Set(set) =>
|
Self::Set(set) =>
|
||||||
write!(f, "{}", Formatter::from(translator, set)),
|
write!(f, "{}", Formatter::from(translator, set)),
|
||||||
Self::Element(el) =>
|
Self::Element(el) =>
|
||||||
write!(f, "{}",
|
write!(f, "{}", Formatter::from(translator, el)),
|
||||||
translator.decode(*el).unwrap_or("Missing".into())),
|
|
||||||
Self::Edge(edge) => write!(f, "{{edge: {edge:?}}}"),
|
Self::Edge(edge) => write!(f, "{{edge: {edge:?}}}"),
|
||||||
Self::Node(node) => write!(f, "{{node: {node:?}}}"),
|
Self::Node(node) => write!(f, "{{node: {node:?}}}"),
|
||||||
Self::Neighbours(node) =>
|
Self::Neighbours(node) =>
|
||||||
|
|||||||
@ -5,6 +5,17 @@ use super::translator::PrintableWithTranslator;
|
|||||||
|
|
||||||
pub type IdType = u32;
|
pub type IdType = u32;
|
||||||
|
|
||||||
|
impl PrintableWithTranslator for IdType {
|
||||||
|
fn print(&self,
|
||||||
|
f: &mut fmt::Formatter,
|
||||||
|
translator: &super::translator::Translator
|
||||||
|
) -> fmt::Result {
|
||||||
|
write!(f, "{}", translator.decode(*self).unwrap_or("Missing".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub enum IdState {
|
pub enum IdState {
|
||||||
Positive,
|
Positive,
|
||||||
@ -31,7 +42,6 @@ impl std::ops::Not for IdState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct PositiveType {
|
pub struct PositiveType {
|
||||||
pub id: IdType,
|
pub id: IdType,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use super::choices::{BasicChoices, Choices, PositiveChoices};
|
use super::choices::{BasicChoices, Choices, PositiveChoices};
|
||||||
use super::process::{BasicProcess, PositiveProcess, Process};
|
use super::process::{BasicProcess, PositiveProcess, Process};
|
||||||
use super::reaction::{Reaction, BasicReaction, ExtensionReaction};
|
use super::reaction::{BasicReaction, ExtensionReaction, PositiveReaction, Reaction};
|
||||||
use super::set::{BasicSet, PositiveSet, Set};
|
use super::set::{BasicSet, PositiveSet, Set};
|
||||||
use super::element::IdType;
|
use super::element::IdType;
|
||||||
use super::translator::{Translator, PrintableWithTranslator, Formatter};
|
use super::translator::{Translator, PrintableWithTranslator, Formatter};
|
||||||
@ -18,6 +18,7 @@ for<'a> Self: Deserialize<'a> {
|
|||||||
type Set: BasicSet;
|
type Set: BasicSet;
|
||||||
type Choices: BasicChoices;
|
type Choices: BasicChoices;
|
||||||
type Process: BasicProcess<Set = Self::Set, Id = Self::Id>;
|
type Process: BasicProcess<Set = Self::Set, Id = Self::Id>;
|
||||||
|
type Reaction: BasicReaction<Set = Self::Set>;
|
||||||
|
|
||||||
fn get(&self, k: Self::Id) -> Option<&Self::Process>;
|
fn get(&self, k: Self::Id) -> Option<&Self::Process>;
|
||||||
fn all_elements(&self) -> Self::Set;
|
fn all_elements(&self) -> Self::Set;
|
||||||
@ -28,6 +29,229 @@ for<'a> Self: Deserialize<'a> {
|
|||||||
) -> Result<Self::Choices, String>;
|
) -> Result<Self::Choices, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ExtensionsEnvironment: BasicEnvironment {
|
||||||
|
fn iter(
|
||||||
|
&self
|
||||||
|
) -> <&Self as IntoIterator>::IntoIter
|
||||||
|
where for<'b> &'b Self: IntoIterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BasicEnvironment> ExtensionsEnvironment for T {
|
||||||
|
fn iter(
|
||||||
|
&self
|
||||||
|
) -> <&Self as IntoIterator>::IntoIter
|
||||||
|
where for<'b> &'b Self: IntoIterator {
|
||||||
|
self.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Loops
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
pub trait LoopEnvironment: BasicEnvironment {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn lollipops_decomposed(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
) -> Vec<(Vec<Self::Set>, Vec<Self::Set>)>;
|
||||||
|
|
||||||
|
fn lollipops_prefix_len_loop_decomposed(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
) -> Vec<(usize, Vec<Self::Set>)>;
|
||||||
|
|
||||||
|
fn lollipops_only_loop_decomposed(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
) -> Vec<Vec<Self::Set>>;
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn lollipops_decomposed_named(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
symb: Self::Id,
|
||||||
|
) -> Option<(Vec<Self::Set>, Vec<Self::Set>)>;
|
||||||
|
|
||||||
|
fn lollipops_prefix_len_loop_decomposed_named(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
symb: Self::Id,
|
||||||
|
) -> Option<(usize, Vec<Self::Set>)>;
|
||||||
|
|
||||||
|
fn lollipops_only_loop_decomposed_named(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
symb: Self::Id,
|
||||||
|
) -> Option<Vec<Self::Set>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T: BasicEnvironment + ExtensionsEnvironment> LoopEnvironment for T
|
||||||
|
where for<'a> &'a T: IntoIterator<Item = (&'a T::Id, &'a T::Process)>,
|
||||||
|
T::Id: Eq
|
||||||
|
{
|
||||||
|
/// A special case of systems is when the context recursively provides
|
||||||
|
/// always the same set of entities. The corresponding computation is
|
||||||
|
/// infinite. It consists of a finite sequence of states followed by a
|
||||||
|
/// looping sequence. IMPORTANT: We return all loops for all X = Q.X, by
|
||||||
|
/// varing X. The set of reactions Rs and the context x are constant. Each
|
||||||
|
/// state of the computation is distinguished by the current entities E.
|
||||||
|
/// Under these assumptions, the predicate lollipop finds the Prefixes and
|
||||||
|
/// the Loops sequences of entities.
|
||||||
|
/// see lollipop
|
||||||
|
fn lollipops_decomposed(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
) -> Vec<(Vec<Self::Set>, Vec<Self::Set>)> {
|
||||||
|
// FIXME: i think we are only interested in "x", not all symbols that
|
||||||
|
// satisfy X = pre(Q, rec(X))
|
||||||
|
let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0));
|
||||||
|
|
||||||
|
let find_loop_fn =
|
||||||
|
|q| T::Reaction::find_loop(reaction_rules,
|
||||||
|
available_entities.clone(),
|
||||||
|
q);
|
||||||
|
|
||||||
|
filtered.map(find_loop_fn).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn lollipops_prefix_len_loop_decomposed(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
) -> Vec<(usize, Vec<Self::Set>)> {
|
||||||
|
let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0));
|
||||||
|
|
||||||
|
let find_loop_fn =
|
||||||
|
|q| T::Reaction::find_prefix_len_loop(reaction_rules,
|
||||||
|
available_entities.clone(),
|
||||||
|
q);
|
||||||
|
|
||||||
|
filtered.map(find_loop_fn).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// see loop
|
||||||
|
fn lollipops_only_loop_decomposed(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
) -> Vec<Vec<Self::Set>> {
|
||||||
|
let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0));
|
||||||
|
|
||||||
|
let find_loop_fn =
|
||||||
|
|q| T::Reaction::find_only_loop(reaction_rules,
|
||||||
|
available_entities,
|
||||||
|
q);
|
||||||
|
|
||||||
|
filtered.map(find_loop_fn).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// A special case of systems is when the context recursively provides
|
||||||
|
/// always the same set of entities. The corresponding computation is
|
||||||
|
/// infinite. It consists of a finite sequence of states followed by a
|
||||||
|
/// looping sequence. IMPORTANT: We return all loops for all X = Q.X, by
|
||||||
|
/// varing X. The set of reactions Rs and the context x are constant. Each
|
||||||
|
/// state of the computation is distinguished by the current entities E.
|
||||||
|
/// Under these assumptions, the predicate lollipop finds the Prefixes and
|
||||||
|
/// the Loops sequences of entities.
|
||||||
|
/// see lollipop
|
||||||
|
fn lollipops_decomposed_named(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
symb: Self::Id,
|
||||||
|
) -> Option<(Vec<Self::Set>, Vec<Self::Set>)> {
|
||||||
|
let filtered = self
|
||||||
|
.iter()
|
||||||
|
.filter_map(
|
||||||
|
|l|
|
||||||
|
if *l.0 == symb {
|
||||||
|
l.1.filter_delta(&symb)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.next();
|
||||||
|
|
||||||
|
let find_loop_fn = |q| T::Reaction::find_loop(reaction_rules,
|
||||||
|
available_entities.clone(),
|
||||||
|
q);
|
||||||
|
|
||||||
|
filtered.map(find_loop_fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn lollipops_prefix_len_loop_decomposed_named(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
symb: Self::Id,
|
||||||
|
) -> Option<(usize, Vec<Self::Set>)> {
|
||||||
|
let filtered = self
|
||||||
|
.iter()
|
||||||
|
.filter_map(
|
||||||
|
|l|
|
||||||
|
if *l.0 == symb {
|
||||||
|
l.1.filter_delta(&symb)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.next();
|
||||||
|
|
||||||
|
let find_loop_fn = |q|
|
||||||
|
T::Reaction::find_prefix_len_loop(reaction_rules,
|
||||||
|
available_entities.clone(),
|
||||||
|
q);
|
||||||
|
|
||||||
|
filtered.map(find_loop_fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// see loop
|
||||||
|
fn lollipops_only_loop_decomposed_named(
|
||||||
|
&self,
|
||||||
|
reaction_rules: &[Self::Reaction],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
symb: Self::Id,
|
||||||
|
) -> Option<Vec<Self::Set>> {
|
||||||
|
let filtered = self
|
||||||
|
.iter()
|
||||||
|
.filter_map(
|
||||||
|
|l|
|
||||||
|
if *l.0 == symb {
|
||||||
|
l.1.filter_delta(&symb)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.next();
|
||||||
|
|
||||||
|
let find_loop_fn =
|
||||||
|
|q| T::Reaction::find_only_loop(reaction_rules,
|
||||||
|
available_entities,
|
||||||
|
q);
|
||||||
|
|
||||||
|
filtered.map(find_loop_fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
definitions: HashMap<IdType, Process>,
|
definitions: HashMap<IdType, Process>,
|
||||||
@ -38,6 +262,7 @@ impl BasicEnvironment for Environment {
|
|||||||
type Set = Set;
|
type Set = Set;
|
||||||
type Choices = Choices;
|
type Choices = Choices;
|
||||||
type Id = IdType;
|
type Id = IdType;
|
||||||
|
type Reaction = Reaction;
|
||||||
|
|
||||||
fn get(&self, k: IdType) -> Option<&Process> {
|
fn get(&self, k: IdType) -> Option<&Process> {
|
||||||
self.definitions.get(&k)
|
self.definitions.get(&k)
|
||||||
@ -148,14 +373,14 @@ impl PrintableWithTranslator for Environment {
|
|||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"({} -> {})",
|
"({} -> {})",
|
||||||
translator.decode(*el.0).unwrap_or("Missing".into()),
|
Formatter::from(translator, el.0),
|
||||||
Formatter::from(translator, el.1)
|
Formatter::from(translator, el.1)
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"({} -> {}), ",
|
"({} -> {}), ",
|
||||||
translator.decode(*el.0).unwrap_or("Missing".into()),
|
Formatter::from(translator, el.0),
|
||||||
Formatter::from(translator, el.1)
|
Formatter::from(translator, el.1)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -164,8 +389,20 @@ impl PrintableWithTranslator for Environment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Environment {
|
impl IntoIterator for Environment {
|
||||||
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, u32, Process> {
|
type Item = (IdType, Process);
|
||||||
|
type IntoIter = std::collections::hash_map::IntoIter<IdType, Process>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.definitions.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a Environment {
|
||||||
|
type Item = (&'a IdType, &'a Process);
|
||||||
|
type IntoIter = std::collections::hash_map::Iter<'a, IdType, Process>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.definitions.iter()
|
self.definitions.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,166 +432,6 @@ impl From<Vec<(IdType, Process)>> for Environment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Loops
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
impl Environment {
|
|
||||||
/// A special case of systems is when the context recursively provides
|
|
||||||
/// always the same set of entities. The corresponding computation is
|
|
||||||
/// infinite. It consists of a finite sequence of states followed by a
|
|
||||||
/// looping sequence. IMPORTANT: We return all loops for all X = Q.X, by
|
|
||||||
/// varing X. The set of reactions Rs and the context x are constant. Each
|
|
||||||
/// state of the computation is distinguished by the current entities E.
|
|
||||||
/// Under these assumptions, the predicate lollipop finds the Prefixes and
|
|
||||||
/// the Loops sequences of entities.
|
|
||||||
/// see lollipop
|
|
||||||
pub fn lollipops_decomposed(
|
|
||||||
&self,
|
|
||||||
reaction_rules: &[Reaction],
|
|
||||||
available_entities: &Set,
|
|
||||||
) -> Vec<(Vec<Set>, Vec<Set>)> {
|
|
||||||
// FIXME: i think we are only interested in "x", not all symbols that
|
|
||||||
// satisfy X = pre(Q, rec(X))
|
|
||||||
let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0));
|
|
||||||
|
|
||||||
let find_loop_fn =
|
|
||||||
|q| Reaction::find_loop(reaction_rules,
|
|
||||||
available_entities.clone(),
|
|
||||||
q);
|
|
||||||
|
|
||||||
filtered.map(find_loop_fn).collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn lollipops_prefix_len_loop_decomposed(
|
|
||||||
&self,
|
|
||||||
reaction_rules: &[Reaction],
|
|
||||||
available_entities: &Set,
|
|
||||||
) -> Vec<(usize, Vec<Set>)> {
|
|
||||||
let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0));
|
|
||||||
|
|
||||||
let find_loop_fn =
|
|
||||||
|q| Reaction::find_prefix_len_loop(reaction_rules,
|
|
||||||
available_entities.clone(),
|
|
||||||
q);
|
|
||||||
|
|
||||||
filtered.map(find_loop_fn).collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// see loop
|
|
||||||
pub fn lollipops_only_loop_decomposed(
|
|
||||||
&self,
|
|
||||||
reaction_rules: &[Reaction],
|
|
||||||
available_entities: &Set,
|
|
||||||
) -> Vec<Vec<Set>> {
|
|
||||||
let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0));
|
|
||||||
|
|
||||||
let find_loop_fn =
|
|
||||||
|q| Reaction::find_only_loop(reaction_rules,
|
|
||||||
available_entities.clone(),
|
|
||||||
q);
|
|
||||||
|
|
||||||
filtered.map(find_loop_fn).collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// A special case of systems is when the context recursively provides
|
|
||||||
/// always the same set of entities. The corresponding computation is
|
|
||||||
/// infinite. It consists of a finite sequence of states followed by a
|
|
||||||
/// looping sequence. IMPORTANT: We return all loops for all X = Q.X, by
|
|
||||||
/// varing X. The set of reactions Rs and the context x are constant. Each
|
|
||||||
/// state of the computation is distinguished by the current entities E.
|
|
||||||
/// Under these assumptions, the predicate lollipop finds the Prefixes and
|
|
||||||
/// the Loops sequences of entities.
|
|
||||||
/// see lollipop
|
|
||||||
pub fn lollipops_decomposed_named(
|
|
||||||
&self,
|
|
||||||
reaction_rules: &[Reaction],
|
|
||||||
available_entities: &Set,
|
|
||||||
symb: IdType,
|
|
||||||
) -> Option<(Vec<Set>, Vec<Set>)> {
|
|
||||||
let filtered = self
|
|
||||||
.iter()
|
|
||||||
.filter_map(
|
|
||||||
|l|
|
|
||||||
if *l.0 == symb {
|
|
||||||
l.1.filter_delta(&symb)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.next();
|
|
||||||
|
|
||||||
let find_loop_fn = |q| Reaction::find_loop(reaction_rules,
|
|
||||||
available_entities.clone(),
|
|
||||||
q);
|
|
||||||
|
|
||||||
filtered.map(find_loop_fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn lollipops_prefix_len_loop_decomposed_named(
|
|
||||||
&self,
|
|
||||||
reaction_rules: &[Reaction],
|
|
||||||
available_entities: &Set,
|
|
||||||
symb: IdType,
|
|
||||||
) -> Option<(usize, Vec<Set>)> {
|
|
||||||
let filtered = self
|
|
||||||
.iter()
|
|
||||||
.filter_map(
|
|
||||||
|l|
|
|
||||||
if *l.0 == symb {
|
|
||||||
l.1.filter_delta(&symb)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.next();
|
|
||||||
|
|
||||||
let find_loop_fn = |q|
|
|
||||||
Reaction::find_prefix_len_loop(reaction_rules,
|
|
||||||
available_entities.clone(),
|
|
||||||
q);
|
|
||||||
|
|
||||||
filtered.map(find_loop_fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// see loop
|
|
||||||
pub fn lollipops_only_loop_decomposed_named(
|
|
||||||
&self,
|
|
||||||
reaction_rules: &[Reaction],
|
|
||||||
available_entities: &Set,
|
|
||||||
symb: IdType,
|
|
||||||
) -> Option<Vec<Set>> {
|
|
||||||
let filtered = self
|
|
||||||
.iter()
|
|
||||||
.filter_map(
|
|
||||||
|l|
|
|
||||||
if *l.0 == symb {
|
|
||||||
l.1.filter_delta(&symb)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.next();
|
|
||||||
|
|
||||||
let find_loop_fn =
|
|
||||||
|q| Reaction::find_only_loop(reaction_rules,
|
|
||||||
available_entities.clone(),
|
|
||||||
q);
|
|
||||||
|
|
||||||
filtered.map(find_loop_fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Confluence
|
// Confluence
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -536,6 +613,7 @@ impl BasicEnvironment for PositiveEnvironment {
|
|||||||
type Set = PositiveSet;
|
type Set = PositiveSet;
|
||||||
type Choices = PositiveChoices;
|
type Choices = PositiveChoices;
|
||||||
type Process = PositiveProcess;
|
type Process = PositiveProcess;
|
||||||
|
type Reaction = PositiveReaction;
|
||||||
|
|
||||||
fn get(&self, k: Self::Id) -> Option<&Self::Process> {
|
fn get(&self, k: Self::Id) -> Option<&Self::Process> {
|
||||||
self.definitions.get(&k)
|
self.definitions.get(&k)
|
||||||
@ -646,14 +724,14 @@ impl PrintableWithTranslator for PositiveEnvironment {
|
|||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"({} -> {})",
|
"({} -> {})",
|
||||||
translator.decode(*el.0).unwrap_or("Missing".into()),
|
Formatter::from(translator, el.0),
|
||||||
Formatter::from(translator, el.1)
|
Formatter::from(translator, el.1)
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"({} -> {}), ",
|
"({} -> {}), ",
|
||||||
translator.decode(*el.0).unwrap_or("Missing".into()),
|
Formatter::from(translator, el.0),
|
||||||
Formatter::from(translator, el.1)
|
Formatter::from(translator, el.1)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -662,10 +740,20 @@ impl PrintableWithTranslator for PositiveEnvironment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PositiveEnvironment {
|
impl IntoIterator for PositiveEnvironment {
|
||||||
pub fn iter(
|
type Item = (IdType, PositiveProcess);
|
||||||
&self
|
type IntoIter = std::collections::hash_map::IntoIter<IdType, PositiveProcess>;
|
||||||
) -> impl std::iter::Iterator<Item = (&u32, &PositiveProcess)> {
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.definitions.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a PositiveEnvironment {
|
||||||
|
type Item = (&'a IdType, &'a PositiveProcess);
|
||||||
|
type IntoIter = std::collections::hash_map::Iter<'a, IdType, PositiveProcess>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.definitions.iter()
|
self.definitions.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,44 @@
|
|||||||
//! Definitions and structure for frequency of elements in a simulation
|
//! Definitions and structure for frequency of elements in a simulation
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::reaction::{Reaction, ExtensionReaction};
|
use super::element::{IdType, PositiveType};
|
||||||
use super::set::{Set, ExtensionsSet};
|
use super::environment::{BasicEnvironment, Environment, PositiveEnvironment};
|
||||||
use super::system::{System, ExtensionsSystem};
|
use super::reaction::{BasicReaction, ExtensionReaction, PositiveReaction, Reaction};
|
||||||
use super::element::IdType;
|
use super::set::{BasicSet, ExtensionsSet, PositiveSet, Set};
|
||||||
use super::translator::{Translator, PrintableWithTranslator, PRECISION};
|
use super::system::{BasicSystem, ExtensionsSystem, LoopSystem, PositiveSystem, System};
|
||||||
|
use super::translator::{Translator, PrintableWithTranslator, PRECISION,
|
||||||
|
Formatter};
|
||||||
|
|
||||||
/// structure that holds the frequency of elements of a run or multiple runs,
|
pub trait BasicFrequency: Debug + Clone + Default + PrintableWithTranslator {
|
||||||
|
type Set: BasicSet;
|
||||||
|
type Sys: BasicSystem<Set = Self::Set>
|
||||||
|
+ LoopSystem<Env = Self::Env, Reaction = Self::R>;
|
||||||
|
type Env: BasicEnvironment<Set = Self::Set,
|
||||||
|
Reaction = Self::R,
|
||||||
|
Id = Self::Id>;
|
||||||
|
type R: BasicReaction<Set = Self::Set>;
|
||||||
|
type Id;
|
||||||
|
|
||||||
|
fn naive_frequency(system: &Self::Sys) -> Result<Self, String>;
|
||||||
|
|
||||||
|
fn loop_frequency(system: &Self::Sys,
|
||||||
|
symb: Self::Id) -> Self;
|
||||||
|
|
||||||
|
fn limit_frequency(q: &[Self::Set],
|
||||||
|
reactions: &[Self::R],
|
||||||
|
available_entities: &Self::Set) -> Option<Self>;
|
||||||
|
|
||||||
|
fn fast_frequency(q: &[Self::Set],
|
||||||
|
reactions: &[Self::R],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
weights: &[u32]) -> Option<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Structure that holds the frequency of elements of a run or multiple runs,
|
||||||
/// weighted. To print use ```translator::FrequencyDisplay```.
|
/// weighted. To print use ```translator::FrequencyDisplay```.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct Frequency {
|
pub struct Frequency {
|
||||||
pub frequency_map: HashMap<IdType, Vec<u32>>,
|
pub frequency_map: HashMap<IdType, Vec<u32>>,
|
||||||
pub totals: Vec<usize>,
|
pub totals: Vec<usize>,
|
||||||
@ -18,42 +46,28 @@ pub struct Frequency {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Frequency {
|
impl Frequency {
|
||||||
pub fn new() -> Self {
|
fn add(&mut self, e: Set, run: usize) {
|
||||||
Frequency {
|
for el in e.iter() {
|
||||||
frequency_map: HashMap::new(),
|
|
||||||
totals: vec![],
|
|
||||||
weights: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&mut self, e: &Set, run: usize) {
|
|
||||||
for &el in e.iter() {
|
|
||||||
let entry =
|
let entry =
|
||||||
self.frequency_map.entry(el).or_insert(vec![0; run + 1]);
|
self.frequency_map.entry(*el).or_insert(vec![0; run + 1]);
|
||||||
if entry.len() < run +1 {
|
if entry.len() < run +1 {
|
||||||
entry.resize(run + 1, 0);
|
entry.resize(run + 1, 0);
|
||||||
}
|
}
|
||||||
entry[run] += 1
|
entry[run] += 1
|
||||||
}
|
}
|
||||||
// TODO resize clones all prev values, replace with in place method
|
// TODO resize clones all prev values, replace with in place method
|
||||||
if self.totals.len() < run + 1 {
|
if self.totals.len() < run + 1 {
|
||||||
self.totals.resize(run + 1, 0);
|
self.totals.resize(run + 1, 0);
|
||||||
}
|
}
|
||||||
self.totals[run] += 1
|
self.totals[run] += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_weight(&mut self, new_weight: u32) {
|
fn append_weight(&mut self, new_weight: u32) {
|
||||||
self.weights.push(new_weight)
|
self.weights.push(new_weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn total_weights(&self) -> u32 {
|
fn total_weights(&self) -> u32 {
|
||||||
self.weights.iter().sum()
|
self.weights.iter().sum()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Frequency {
|
|
||||||
fn default() -> Self {
|
|
||||||
Frequency::new()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,9 +83,9 @@ impl PrintableWithTranslator for Frequency {
|
|||||||
let weights = &self.weights;
|
let weights = &self.weights;
|
||||||
|
|
||||||
while let Some((e, freq)) = freq_it.next() {
|
while let Some((e, freq)) = freq_it.next() {
|
||||||
write!(f, "{} -> ", translator.decode(*e).unwrap_or("Missing".into()))?;
|
write!(f, "{} -> ", Formatter::from(translator, e))?;
|
||||||
|
|
||||||
let mut total_freq = 0.;
|
let mut total_freq = 0.;
|
||||||
|
|
||||||
let end = max(freq.len(), max(totals.len(), weights.len()));
|
let end = max(freq.len(), max(totals.len(), weights.len()));
|
||||||
|
|
||||||
@ -91,36 +105,36 @@ impl PrintableWithTranslator for Frequency {
|
|||||||
total_freq += weighted_freq;
|
total_freq += weighted_freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_freq /= self.total_weights() as f32;
|
total_freq /= self.total_weights() as f32;
|
||||||
|
|
||||||
#[allow(clippy::uninlined_format_args)]
|
#[allow(clippy::uninlined_format_args)]
|
||||||
write!(f, " (total: {total_freq:.*})", PRECISION)?;
|
write!(f, " (total: {total_freq:.*})", PRECISION)?;
|
||||||
|
|
||||||
if freq_it.peek().is_some() {
|
if freq_it.peek().is_some() {
|
||||||
writeln!(f, ",")?;
|
writeln!(f, ",")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
impl BasicFrequency for Frequency {
|
||||||
|
type Set = Set;
|
||||||
|
type Sys = System;
|
||||||
|
type Env = Environment;
|
||||||
|
type R = Reaction;
|
||||||
|
type Id = IdType;
|
||||||
|
|
||||||
|
|
||||||
impl Frequency {
|
|
||||||
/// Assuming the system is finite, calculates the frequency of each symbol
|
/// Assuming the system is finite, calculates the frequency of each symbol
|
||||||
/// in all traversed states.
|
/// in all traversed states.
|
||||||
/// see naiveFreq
|
/// see naiveFreq
|
||||||
pub fn naive_frequency(
|
fn naive_frequency(system: &Self::Sys) -> Result<Self, String> {
|
||||||
system: &System
|
|
||||||
) -> Result<Self, String> {
|
|
||||||
let ect = system.run_separated()?;
|
let ect = system.run_separated()?;
|
||||||
let es = ect.iter().map(|(e, _, _)| e).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let mut freq = Frequency::new();
|
let mut freq = Self::default();
|
||||||
freq.append_weight(1);
|
freq.append_weight(1);
|
||||||
|
|
||||||
es.iter().for_each(|e| freq.add(e, 0));
|
ect.into_iter().for_each(|(e, _, _)| freq.add(e, 0));
|
||||||
|
|
||||||
Ok(freq)
|
Ok(freq)
|
||||||
}
|
}
|
||||||
@ -128,15 +142,12 @@ impl Frequency {
|
|||||||
/// Assume the system stabilizes in a loop, calculates the frequency of each
|
/// Assume the system stabilizes in a loop, calculates the frequency of each
|
||||||
/// symbol in all states of the loop.
|
/// symbol in all states of the loop.
|
||||||
/// see loopFreq
|
/// see loopFreq
|
||||||
pub fn loop_frequency(
|
fn loop_frequency(system: &Self::Sys, symb: Self::Id) -> Self {
|
||||||
system: &System,
|
let mut freq = Self::default();
|
||||||
symb: IdType
|
|
||||||
) -> Self {
|
|
||||||
let mut freq = Frequency::new();
|
|
||||||
freq.append_weight(1);
|
freq.append_weight(1);
|
||||||
|
|
||||||
if let Some(hoop) = system.lollipops_only_loop_named(symb) {
|
if let Some(hoop) = system.lollipops_only_loop_named(symb) {
|
||||||
hoop.iter().for_each(|e| freq.add(e, 0));
|
hoop.iter().for_each(|e| freq.add(e.clone(), 0));
|
||||||
}
|
}
|
||||||
freq
|
freq
|
||||||
}
|
}
|
||||||
@ -145,29 +156,30 @@ impl Frequency {
|
|||||||
/// stabilizes in a loop, calculates the frequency of the symbols in any
|
/// stabilizes in a loop, calculates the frequency of the symbols in any
|
||||||
/// state in the last loop.
|
/// state in the last loop.
|
||||||
/// see limitFreq
|
/// see limitFreq
|
||||||
pub fn limit_frequency(
|
fn limit_frequency(
|
||||||
q: &[Set],
|
q: &[Self::Set],
|
||||||
reaction_rules: &[Reaction],
|
reaction_rules: &[Self::R],
|
||||||
available_entities: &Set,
|
available_entities: &Self::Set,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let mut available_entities = available_entities.clone();
|
let mut available_entities = available_entities.clone();
|
||||||
|
|
||||||
for q in q.iter().rev().skip(1).rev() {
|
for q in q.iter().rev().skip(1).rev() {
|
||||||
let res =
|
let res =
|
||||||
Reaction::lollipops_only_loop_decomposed_q(reaction_rules,
|
Self::R::lollipops_only_loop_decomposed_q(reaction_rules,
|
||||||
q,
|
q,
|
||||||
&available_entities);
|
&available_entities);
|
||||||
available_entities = res.into_iter().next()?;
|
available_entities = res.into_iter().next()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut freq = Frequency::new();
|
let mut freq = Self::default();
|
||||||
freq.append_weight(1);
|
freq.append_weight(1);
|
||||||
|
|
||||||
Reaction::lollipops_only_loop_decomposed_q(reaction_rules,
|
Self::R::lollipops_only_loop_decomposed_q(reaction_rules,
|
||||||
q.last().unwrap(),
|
q.last().unwrap(),
|
||||||
&available_entities)
|
&available_entities)
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|e| freq.add(e, 0));
|
.cloned()
|
||||||
|
.for_each(|e| freq.add(e, 0));
|
||||||
Some(freq)
|
Some(freq)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,25 +187,204 @@ impl Frequency {
|
|||||||
/// stabilizes in a loop, calculates the frequency of the symbols in any
|
/// stabilizes in a loop, calculates the frequency of the symbols in any
|
||||||
/// state in any loop, weighted.
|
/// state in any loop, weighted.
|
||||||
/// see fastFreq
|
/// see fastFreq
|
||||||
pub fn fast_frequency(
|
fn fast_frequency(
|
||||||
q: &[Set],
|
q: &[Self::Set],
|
||||||
reaction_rules: &[Reaction],
|
reaction_rules: &[Self::R],
|
||||||
available_entities: &Set,
|
available_entities: &Self::Set,
|
||||||
weights: &[u32],
|
weights: &[u32],
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
// FIXME: we return the empty frequency or do we not return anything?
|
// FIXME: we return the empty frequency or do we not return anything?
|
||||||
let mut available_entities = available_entities.clone();
|
let mut available_entities = available_entities.clone();
|
||||||
|
|
||||||
let mut freq = Frequency::new();
|
let mut freq = Self::default();
|
||||||
|
|
||||||
for (pos, (q, &w)) in q.iter().zip(weights).enumerate() {
|
for (pos, (q, &w)) in q.iter().zip(weights).enumerate() {
|
||||||
freq.append_weight(w);
|
freq.append_weight(w);
|
||||||
let hoop =
|
let hoop =
|
||||||
Reaction::lollipops_only_loop_decomposed_q(reaction_rules,
|
Self::R::lollipops_only_loop_decomposed_q(reaction_rules,
|
||||||
q,
|
q,
|
||||||
&available_entities);
|
&available_entities);
|
||||||
hoop.iter().for_each(|e| freq.add(e, pos));
|
hoop.iter().cloned().for_each(|e| freq.add(e, pos));
|
||||||
available_entities = hoop.into_iter().next()?;
|
available_entities = hoop.into_iter().next()?;
|
||||||
|
}
|
||||||
|
Some(freq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Structure that holds the frequency of positive or negative elements of a run
|
||||||
|
/// or multiple runs, weighted. To print use ```translator::FrequencyDisplay```.
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct PositiveFrequency {
|
||||||
|
pub frequency_map: HashMap<PositiveType, Vec<u32>>,
|
||||||
|
pub totals: Vec<usize>,
|
||||||
|
pub weights: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PositiveFrequency {
|
||||||
|
fn add(&mut self, e: PositiveSet, run: usize) {
|
||||||
|
for (&id, &state) in e.iter() {
|
||||||
|
let entry =
|
||||||
|
self.frequency_map
|
||||||
|
.entry(PositiveType { id, state })
|
||||||
|
.or_insert(vec![0; run + 1]);
|
||||||
|
if entry.len() < run +1 {
|
||||||
|
entry.resize(run + 1, 0);
|
||||||
|
}
|
||||||
|
entry[run] += 1
|
||||||
|
}
|
||||||
|
// TODO resize clones all prev values, replace with in place method
|
||||||
|
if self.totals.len() < run + 1 {
|
||||||
|
self.totals.resize(run + 1, 0);
|
||||||
|
}
|
||||||
|
self.totals[run] += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_weight(&mut self, new_weight: u32) {
|
||||||
|
self.weights.push(new_weight)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn total_weights(&self) -> u32 {
|
||||||
|
self.weights.iter().sum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrintableWithTranslator for PositiveFrequency {
|
||||||
|
fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator)
|
||||||
|
-> std::fmt::Result {
|
||||||
|
use std::cmp::max;
|
||||||
|
|
||||||
|
write!(f, "[")?;
|
||||||
|
let mut freq_it = self.frequency_map.iter().peekable();
|
||||||
|
|
||||||
|
let totals = &self.totals;
|
||||||
|
let weights = &self.weights;
|
||||||
|
|
||||||
|
while let Some((e, freq)) = freq_it.next() {
|
||||||
|
write!(f, "{} -> ", Formatter::from(translator, e))?;
|
||||||
|
|
||||||
|
let mut total_freq = 0.;
|
||||||
|
|
||||||
|
let end = max(freq.len(), max(totals.len(), weights.len()));
|
||||||
|
|
||||||
|
for pos in 0..end {
|
||||||
|
let freq_e = freq.get(pos).copied().unwrap_or(0) as f32;
|
||||||
|
let weight = weights.get(pos).copied().unwrap_or(1) as f32;
|
||||||
|
let total = totals.get(pos).copied().unwrap_or(1) as f32;
|
||||||
|
|
||||||
|
let weighted_freq = (freq_e * weight * 100.) / (total);
|
||||||
|
if pos == end-1 {
|
||||||
|
#[allow(clippy::uninlined_format_args)]
|
||||||
|
write!(f, "{weighted_freq:.*}", PRECISION)?;
|
||||||
|
} else {
|
||||||
|
#[allow(clippy::uninlined_format_args)]
|
||||||
|
write!(f, "{weighted_freq:.*}, ", PRECISION)?;
|
||||||
|
}
|
||||||
|
total_freq += weighted_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_freq /= self.total_weights() as f32;
|
||||||
|
|
||||||
|
#[allow(clippy::uninlined_format_args)]
|
||||||
|
write!(f, " (total: {total_freq:.*})", PRECISION)?;
|
||||||
|
|
||||||
|
if freq_it.peek().is_some() {
|
||||||
|
writeln!(f, ",")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BasicFrequency for PositiveFrequency {
|
||||||
|
type Set = PositiveSet;
|
||||||
|
type Sys = PositiveSystem;
|
||||||
|
type Env = PositiveEnvironment;
|
||||||
|
type R = PositiveReaction;
|
||||||
|
type Id = IdType;
|
||||||
|
|
||||||
|
/// Assuming the system is finite, calculates the frequency of each symbol
|
||||||
|
/// in all traversed states.
|
||||||
|
/// see naiveFreq
|
||||||
|
fn naive_frequency(system: &Self::Sys) -> Result<Self, String> {
|
||||||
|
let ect = system.run_separated()?;
|
||||||
|
|
||||||
|
let mut freq = Self::default();
|
||||||
|
freq.append_weight(1);
|
||||||
|
|
||||||
|
ect.into_iter().for_each(|(e, _, _)| freq.add(e, 0));
|
||||||
|
|
||||||
|
Ok(freq)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assume the system stabilizes in a loop, calculates the frequency of each
|
||||||
|
/// symbol in all states of the loop.
|
||||||
|
/// see loopFreq
|
||||||
|
fn loop_frequency(system: &Self::Sys, symb: Self::Id) -> Self {
|
||||||
|
let mut freq = Self::default();
|
||||||
|
freq.append_weight(1);
|
||||||
|
|
||||||
|
if let Some(hoop) = system.lollipops_only_loop_named(symb) {
|
||||||
|
hoop.iter().for_each(|e| freq.add(e.clone(), 0));
|
||||||
|
}
|
||||||
|
freq
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assuming ```q[i]``` is given enough times such that the system
|
||||||
|
/// stabilizes in a loop, calculates the frequency of the symbols in any
|
||||||
|
/// state in the last loop.
|
||||||
|
/// see limitFreq
|
||||||
|
fn limit_frequency(
|
||||||
|
q: &[Self::Set],
|
||||||
|
reaction_rules: &[Self::R],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
) -> Option<Self> {
|
||||||
|
let mut available_entities = available_entities.clone();
|
||||||
|
|
||||||
|
for q in q.iter().rev().skip(1).rev() {
|
||||||
|
let res =
|
||||||
|
Self::R::lollipops_only_loop_decomposed_q(reaction_rules,
|
||||||
|
q,
|
||||||
|
&available_entities);
|
||||||
|
available_entities = res.into_iter().next()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut freq = Self::default();
|
||||||
|
freq.append_weight(1);
|
||||||
|
|
||||||
|
Self::R::lollipops_only_loop_decomposed_q(reaction_rules,
|
||||||
|
q.last().unwrap(),
|
||||||
|
&available_entities)
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.for_each(|e| freq.add(e, 0));
|
||||||
|
Some(freq)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assuming ```q[i]``` is given enough times such that the system
|
||||||
|
/// stabilizes in a loop, calculates the frequency of the symbols in any
|
||||||
|
/// state in any loop, weighted.
|
||||||
|
/// see fastFreq
|
||||||
|
fn fast_frequency(
|
||||||
|
q: &[Self::Set],
|
||||||
|
reaction_rules: &[Self::R],
|
||||||
|
available_entities: &Self::Set,
|
||||||
|
weights: &[u32],
|
||||||
|
) -> Option<Self> {
|
||||||
|
// FIXME: we return the empty frequency or do we not return anything?
|
||||||
|
let mut available_entities = available_entities.clone();
|
||||||
|
|
||||||
|
let mut freq = Self::default();
|
||||||
|
|
||||||
|
for (pos, (q, &w)) in q.iter().zip(weights).enumerate() {
|
||||||
|
freq.append_weight(w);
|
||||||
|
let hoop =
|
||||||
|
Self::R::lollipops_only_loop_decomposed_q(reaction_rules,
|
||||||
|
q,
|
||||||
|
&available_entities);
|
||||||
|
hoop.iter().cloned().for_each(|e| freq.add(e, pos));
|
||||||
|
available_entities = hoop.into_iter().next()?;
|
||||||
}
|
}
|
||||||
Some(freq)
|
Some(freq)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -399,6 +399,8 @@ pub fn hoop(
|
|||||||
system: &EvaluatedSystem,
|
system: &EvaluatedSystem,
|
||||||
symbol: String
|
symbol: String
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
|
use system::LoopSystem;
|
||||||
|
|
||||||
let (res, translator) = match system {
|
let (res, translator) = match system {
|
||||||
EvaluatedSystem::System { sys, translator } => (sys, translator),
|
EvaluatedSystem::System { sys, translator } => (sys, translator),
|
||||||
EvaluatedSystem::Graph { graph, translator } => {
|
EvaluatedSystem::Graph { graph, translator } => {
|
||||||
@ -436,6 +438,8 @@ pub fn hoop(
|
|||||||
/// (deterministic) terminating Reaction System.
|
/// (deterministic) terminating Reaction System.
|
||||||
/// equivalent to main_do(freq, PairList)
|
/// equivalent to main_do(freq, PairList)
|
||||||
pub fn freq(system: &EvaluatedSystem) -> Result<String, String> {
|
pub fn freq(system: &EvaluatedSystem) -> Result<String, String> {
|
||||||
|
use frequency::BasicFrequency;
|
||||||
|
|
||||||
let (sys, translator) = match system {
|
let (sys, translator) = match system {
|
||||||
EvaluatedSystem::System { sys, translator } => (sys, translator),
|
EvaluatedSystem::System { sys, translator } => (sys, translator),
|
||||||
EvaluatedSystem::Graph { graph, translator } => {
|
EvaluatedSystem::Graph { graph, translator } => {
|
||||||
@ -461,6 +465,8 @@ pub fn limit_freq(
|
|||||||
system: &mut EvaluatedSystem,
|
system: &mut EvaluatedSystem,
|
||||||
experiment: String
|
experiment: String
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
|
use frequency::BasicFrequency;
|
||||||
|
|
||||||
let (sys, translator): (&system::System, &mut Translator) = match system {
|
let (sys, translator): (&system::System, &mut Translator) = match system {
|
||||||
EvaluatedSystem::System { sys, translator } => (sys, translator),
|
EvaluatedSystem::System { sys, translator } => (sys, translator),
|
||||||
EvaluatedSystem::Graph { graph, translator } => {
|
EvaluatedSystem::Graph { graph, translator } => {
|
||||||
@ -499,8 +505,9 @@ pub fn limit_freq(
|
|||||||
pub fn fast_freq(
|
pub fn fast_freq(
|
||||||
system: &mut EvaluatedSystem,
|
system: &mut EvaluatedSystem,
|
||||||
experiment: String
|
experiment: String
|
||||||
) -> Result<String, String>
|
) -> Result<String, String> {
|
||||||
{
|
use frequency::BasicFrequency;
|
||||||
|
|
||||||
let (sys, translator): (&system::System, &mut Translator) = match system {
|
let (sys, translator): (&system::System, &mut Translator) = match system {
|
||||||
EvaluatedSystem::System { sys, translator } => (sys, translator),
|
EvaluatedSystem::System { sys, translator } => (sys, translator),
|
||||||
EvaluatedSystem::Graph { graph, translator } => {
|
EvaluatedSystem::Graph { graph, translator } => {
|
||||||
@ -513,17 +520,18 @@ pub fn fast_freq(
|
|||||||
|
|
||||||
let (weights, sets) = read_file(translator, experiment, parser_experiment)?;
|
let (weights, sets) = read_file(translator, experiment, parser_experiment)?;
|
||||||
|
|
||||||
let res = match frequency::Frequency::fast_frequency(
|
let res =
|
||||||
&sets,
|
match frequency::Frequency::fast_frequency(
|
||||||
&sys.reaction_rules,
|
&sets,
|
||||||
&sys.available_entities,
|
&sys.reaction_rules,
|
||||||
&weights,
|
&sys.available_entities,
|
||||||
) {
|
&weights,
|
||||||
Some(e) => e,
|
) {
|
||||||
None => {
|
Some(e) => e,
|
||||||
return Err("Error calculating frequency.".into());
|
None => {
|
||||||
}
|
return Err("Error calculating frequency.".into());
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"Frequency of encountered symbols:\n{}",
|
"Frequency of encountered symbols:\n{}",
|
||||||
|
|||||||
@ -14,134 +14,131 @@ pub trait BasicReaction:
|
|||||||
Clone + Default + Eq + Hash + Serialize + PrintableWithTranslator
|
Clone + Default + Eq + Hash + Serialize + PrintableWithTranslator
|
||||||
where for<'de> Self: Deserialize<'de>,
|
where for<'de> Self: Deserialize<'de>,
|
||||||
{
|
{
|
||||||
type Set: BasicSet;
|
type Set: BasicSet;
|
||||||
fn enabled(&self, state: &Self::Set) -> bool;
|
fn enabled(&self, state: &Self::Set) -> bool;
|
||||||
fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set>;
|
fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ExtensionReaction: Sized {
|
pub trait ExtensionReaction: Sized {
|
||||||
type Set: BasicSet;
|
type Set: BasicSet;
|
||||||
|
|
||||||
fn compute_all(reactions: &[Self], state: &Self::Set) -> Self::Set;
|
fn compute_all(reactions: &[Self], state: &Self::Set) -> Self::Set;
|
||||||
|
|
||||||
fn find_loop(
|
fn find_loop(
|
||||||
reactions: &[Self],
|
reactions: &[Self],
|
||||||
entities: Self::Set,
|
entities: Self::Set,
|
||||||
q: &Self::Set
|
q: &Self::Set
|
||||||
) -> (Vec<Self::Set>, Vec<Self::Set>);
|
) -> (Vec<Self::Set>, Vec<Self::Set>);
|
||||||
|
|
||||||
fn find_only_loop(
|
fn find_only_loop(
|
||||||
reactions: &[Self],
|
reactions: &[Self],
|
||||||
entities: Self::Set,
|
entities: &Self::Set,
|
||||||
q: &Self::Set
|
q: &Self::Set
|
||||||
) -> Vec<Self::Set>;
|
) -> Vec<Self::Set>;
|
||||||
|
|
||||||
fn find_prefix_len_loop(
|
fn find_prefix_len_loop(
|
||||||
reactions: &[Self],
|
reactions: &[Self],
|
||||||
entities: Self::Set,
|
entities: Self::Set,
|
||||||
q: &Self::Set
|
q: &Self::Set
|
||||||
) -> (usize, Vec<Self::Set>);
|
) -> (usize, Vec<Self::Set>);
|
||||||
|
|
||||||
fn lollipops_only_loop_decomposed_q(
|
fn lollipops_only_loop_decomposed_q(
|
||||||
reactions: &[Self],
|
reactions: &[Self],
|
||||||
entities: &Self::Set,
|
entities: &Self::Set,
|
||||||
q: &Self::Set
|
q: &Self::Set
|
||||||
) -> Vec<Self::Set>;
|
) -> Vec<Self::Set>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementations for all reactions.
|
/// Implementations for all reactions.
|
||||||
impl<T: BasicReaction<Set = Set>, Set: BasicSet> ExtensionReaction for T {
|
impl<T: BasicReaction<Set = Set>, Set: BasicSet> ExtensionReaction for T {
|
||||||
type Set = Set;
|
type Set = Set;
|
||||||
|
|
||||||
/// Computes the result of a series of reactions. Returns the union of all
|
/// Computes the result of a series of reactions. Returns the union of all
|
||||||
/// products.
|
/// products.
|
||||||
/// see result
|
/// see result
|
||||||
fn compute_all(
|
fn compute_all(
|
||||||
reactions: &[Self],
|
reactions: &[Self],
|
||||||
state: &Set
|
state: &Set
|
||||||
) -> Set
|
) -> Set
|
||||||
where Self: Sized {
|
where Self: Sized {
|
||||||
reactions.iter().fold(Set::default(), |mut acc: Set, r| {
|
reactions.iter().fold(Set::default(), |mut acc: Set, r| {
|
||||||
acc.extend(r.compute_step(state));
|
acc.extend(r.compute_step(state));
|
||||||
acc
|
acc
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds the loops by simulating the system.
|
||||||
|
fn find_loop(
|
||||||
|
reactions: &[Self],
|
||||||
|
entities: Set,
|
||||||
|
q: &Set
|
||||||
|
) -> (Vec<Set>, Vec<Set>) {
|
||||||
|
let mut entities = entities;
|
||||||
|
let mut trace = vec![];
|
||||||
|
loop {
|
||||||
|
if let Some((prefix, hoop)) = entities.split(&trace) {
|
||||||
|
return (prefix.to_vec(), hoop.to_vec());
|
||||||
|
} else {
|
||||||
|
let t = entities.union(q);
|
||||||
|
let products = Self::compute_all(reactions, &t);
|
||||||
|
trace.push(entities.clone());
|
||||||
|
entities = products;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Finds the loops by simulating the system.
|
/// Finds the loops by simulating the system.
|
||||||
fn find_loop(
|
fn find_only_loop(
|
||||||
reactions: &[Self],
|
reactions: &[Self],
|
||||||
entities: Set,
|
entities: &Set,
|
||||||
q: &Set
|
q: &Set
|
||||||
) -> (Vec<Set>, Vec<Set>) {
|
) -> Vec<Set> {
|
||||||
let mut entities = entities;
|
let mut entities = entities.clone();
|
||||||
let mut trace = vec![];
|
let mut trace = vec![];
|
||||||
loop {
|
loop {
|
||||||
if let Some((prefix, hoop)) = entities.split(&trace) {
|
if let Some((_prefix, hoop)) = entities.split(&trace) {
|
||||||
return (prefix.to_vec(), hoop.to_vec());
|
return hoop.to_vec();
|
||||||
} else {
|
} else {
|
||||||
let t = entities.union(q);
|
let t = entities.union(q);
|
||||||
let products = Self::compute_all(reactions, &t);
|
let products = Self::compute_all(reactions, &t);
|
||||||
trace.push(entities.clone());
|
trace.push(entities.clone());
|
||||||
entities = products;
|
entities = products;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds the loops and the length of the prefix by simulating the system.
|
||||||
/// Finds the loops by simulating the system.
|
fn find_prefix_len_loop(
|
||||||
fn find_only_loop(
|
reactions: &[Self],
|
||||||
reactions: &[Self],
|
entities: Set,
|
||||||
entities: Set,
|
q: &Set
|
||||||
q: &Set
|
) -> (usize, Vec<Set>) {
|
||||||
) -> Vec<Set> {
|
let mut entities = entities;
|
||||||
let mut entities = entities;
|
let mut trace = vec![];
|
||||||
let mut trace = vec![];
|
loop {
|
||||||
loop {
|
if let Some((prefix, hoop)) = entities.split(&trace) {
|
||||||
if let Some((_prefix, hoop)) = entities.split(&trace) {
|
return (prefix.len(), hoop.to_vec());
|
||||||
return hoop.to_vec();
|
} else {
|
||||||
} else {
|
let t = entities.union(q);
|
||||||
let t = entities.union(q);
|
let products = Self::compute_all(reactions, &t);
|
||||||
let products = Self::compute_all(reactions, &t);
|
trace.push(entities.clone());
|
||||||
trace.push(entities.clone());
|
entities = products;
|
||||||
entities = products;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// see loop/5
|
||||||
/// Finds the loops and the length of the prefix by simulating the system.
|
fn lollipops_only_loop_decomposed_q(
|
||||||
fn find_prefix_len_loop(
|
reactions: &[Self],
|
||||||
reactions: &[Self],
|
entities: &Set,
|
||||||
entities: Set,
|
q: &Set,
|
||||||
q: &Set
|
) -> Vec<Set> {
|
||||||
) -> (usize, Vec<Set>) {
|
let find_loop_fn =
|
||||||
let mut entities = entities;
|
|q| Self::find_only_loop(reactions,
|
||||||
let mut trace = vec![];
|
entities,
|
||||||
loop {
|
q);
|
||||||
if let Some((prefix, hoop)) = entities.split(&trace) {
|
find_loop_fn(q)
|
||||||
return (prefix.len(), hoop.to_vec());
|
}
|
||||||
} else {
|
|
||||||
let t = entities.union(q);
|
|
||||||
let products = Self::compute_all(reactions, &t);
|
|
||||||
trace.push(entities.clone());
|
|
||||||
entities = products;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// see loop/5
|
|
||||||
fn lollipops_only_loop_decomposed_q(
|
|
||||||
reactions: &[Self],
|
|
||||||
entities: &Set,
|
|
||||||
q: &Set,
|
|
||||||
) -> Vec<Set> {
|
|
||||||
let find_loop_fn =
|
|
||||||
|q| Self::find_only_loop(reactions,
|
|
||||||
entities.clone(),
|
|
||||||
q);
|
|
||||||
find_loop_fn(q)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -152,121 +149,121 @@ impl<T: BasicReaction<Set = Set>, Set: BasicSet> ExtensionReaction for T {
|
|||||||
/// Basic structure for a reaction.
|
/// Basic structure for a reaction.
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||||
pub struct Reaction {
|
pub struct Reaction {
|
||||||
pub reactants: Set,
|
pub reactants: Set,
|
||||||
pub inhibitors: Set,
|
pub inhibitors: Set,
|
||||||
pub products: Set,
|
pub products: Set,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasicReaction for Reaction {
|
impl BasicReaction for Reaction {
|
||||||
type Set = Set;
|
type Set = Set;
|
||||||
|
|
||||||
/// returns true if ```current_state``` enables the reaction
|
/// returns true if ```current_state``` enables the reaction
|
||||||
/// see enable
|
/// see enable
|
||||||
fn enabled(&self, current_state: &Self::Set) -> bool {
|
fn enabled(&self, current_state: &Self::Set) -> bool {
|
||||||
self.reactants.is_subset(current_state)
|
self.reactants.is_subset(current_state)
|
||||||
&& self.inhibitors.is_disjoint(current_state)
|
&& self.inhibitors.is_disjoint(current_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the result of a single reaction (if enabled returns the
|
/// Computes the result of a single reaction (if enabled returns the
|
||||||
/// products) otherwise returns None.
|
/// products) otherwise returns None.
|
||||||
/// see result
|
/// see result
|
||||||
fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> {
|
fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> {
|
||||||
if self.enabled(state) {
|
if self.enabled(state) {
|
||||||
Some(&self.products)
|
Some(&self.products)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrintableWithTranslator for Reaction {
|
impl PrintableWithTranslator for Reaction {
|
||||||
fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator)
|
fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator)
|
||||||
-> std::fmt::Result {
|
-> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"(r: {}, i: {}, p: {})",
|
"(r: {}, i: {}, p: {})",
|
||||||
Formatter::from(translator, &self.reactants),
|
Formatter::from(translator, &self.reactants),
|
||||||
Formatter::from(translator, &self.inhibitors),
|
Formatter::from(translator, &self.inhibitors),
|
||||||
Formatter::from(translator, &self.products)
|
Formatter::from(translator, &self.products)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reaction {
|
impl Reaction {
|
||||||
pub fn from(reactants: Set, inhibitors: Set, products: Set) -> Self {
|
pub fn from(reactants: Set, inhibitors: Set, products: Set) -> Self {
|
||||||
Reaction { reactants, inhibitors, products }
|
Reaction { reactants, inhibitors, products }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_products(reactions: &[Self]) -> Set {
|
pub fn all_products(reactions: &[Self]) -> Set {
|
||||||
reactions.iter().fold(
|
reactions.iter().fold(
|
||||||
Set::default(),
|
Set::default(),
|
||||||
|acc, r|
|
|acc, r|
|
||||||
acc.union(&r.products)
|
acc.union(&r.products)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_reactions_with_product<'a>(
|
pub fn all_reactions_with_product<'a>(
|
||||||
reactions: &'a [Self],
|
reactions: &'a [Self],
|
||||||
el: &IdType
|
el: &IdType
|
||||||
) -> Vec<&'a Self> {
|
) -> Vec<&'a Self> {
|
||||||
reactions.iter().fold(
|
reactions.iter().fold(
|
||||||
vec![],
|
vec![],
|
||||||
|mut acc, r| {
|
|mut acc, r| {
|
||||||
if r.products.contains(el) {
|
if r.products.contains(el) {
|
||||||
acc.push(r);
|
acc.push(r);
|
||||||
}
|
}
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||||
pub struct PositiveReaction {
|
pub struct PositiveReaction {
|
||||||
pub reactants: PositiveSet,
|
pub reactants: PositiveSet,
|
||||||
pub products: PositiveSet
|
pub products: PositiveSet
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasicReaction for PositiveReaction {
|
impl BasicReaction for PositiveReaction {
|
||||||
type Set = PositiveSet;
|
type Set = PositiveSet;
|
||||||
|
|
||||||
fn enabled(&self, state: &Self::Set) -> bool {
|
fn enabled(&self, state: &Self::Set) -> bool {
|
||||||
self.reactants.is_subset(state)
|
self.reactants.is_subset(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> {
|
fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> {
|
||||||
if self.enabled(state) {
|
if self.enabled(state) {
|
||||||
Some(&self.products)
|
Some(&self.products)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrintableWithTranslator for PositiveReaction {
|
impl PrintableWithTranslator for PositiveReaction {
|
||||||
fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator)
|
fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator)
|
||||||
-> std::fmt::Result {
|
-> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"(r: {}, p: {})",
|
"(r: {}, p: {})",
|
||||||
Formatter::from(translator, &self.reactants),
|
Formatter::from(translator, &self.reactants),
|
||||||
Formatter::from(translator, &self.products),
|
Formatter::from(translator, &self.products),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PositiveReaction {
|
impl PositiveReaction {
|
||||||
pub fn from(reactants: PositiveSet, products: PositiveSet) -> Self {
|
pub fn from(reactants: PositiveSet, products: PositiveSet) -> Self {
|
||||||
Self { reactants, products }
|
Self { reactants, products }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(reactants: Set, inhibitors: Set, products: Set) -> Self {
|
pub fn create(reactants: Set, inhibitors: Set, products: Set) -> Self {
|
||||||
Self { reactants:
|
Self { reactants:
|
||||||
reactants.to_positive_set(IdState::Positive).union(
|
reactants.to_positive_set(IdState::Positive).union(
|
||||||
&inhibitors.to_positive_set(IdState::Negative)
|
&inhibitors.to_positive_set(IdState::Negative)
|
||||||
),
|
),
|
||||||
products: products.to_positive_set(IdState::Positive) }
|
products: products.to_positive_set(IdState::Positive) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -170,13 +170,9 @@ impl PrintableWithTranslator for Set {
|
|||||||
let mut it = self.iter().peekable();
|
let mut it = self.iter().peekable();
|
||||||
while let Some(el) = it.next() {
|
while let Some(el) = it.next() {
|
||||||
if it.peek().is_none() {
|
if it.peek().is_none() {
|
||||||
write!(f,
|
write!(f, "{}", Formatter::from(translator, el))?;
|
||||||
"{}",
|
|
||||||
translator.decode(*el).unwrap_or("Missing".into()))?;
|
|
||||||
} else {
|
} else {
|
||||||
write!(f,
|
write!(f, "{}, ", Formatter::from(translator, el))?;
|
||||||
"{}, ",
|
|
||||||
translator.decode(*el).unwrap_or("Missing".into()))?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
|
|||||||
@ -5,12 +5,13 @@ use std::fmt::Debug;
|
|||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::environment::{Environment, BasicEnvironment, PositiveEnvironment};
|
use super::environment::{Environment, BasicEnvironment, PositiveEnvironment,
|
||||||
|
ExtensionsEnvironment, LoopEnvironment};
|
||||||
use super::label::{BasicLabel, Label, PositiveLabel};
|
use super::label::{BasicLabel, Label, PositiveLabel};
|
||||||
use super::process::{BasicProcess, PositiveProcess, Process};
|
use super::process::{BasicProcess, PositiveProcess, Process};
|
||||||
use super::reaction::{BasicReaction, ExtensionReaction, PositiveReaction, Reaction};
|
use super::reaction::{BasicReaction, ExtensionReaction, PositiveReaction, Reaction};
|
||||||
use super::set::{BasicSet, PositiveSet, Set};
|
use super::set::{BasicSet, PositiveSet, Set};
|
||||||
use super::element::{IdState, IdType};
|
use super::element::IdState;
|
||||||
use super::transitions::TransitionsIterator;
|
use super::transitions::TransitionsIterator;
|
||||||
use super::translator::{Translator, PrintableWithTranslator, Formatter};
|
use super::translator::{Translator, PrintableWithTranslator, Formatter};
|
||||||
|
|
||||||
@ -233,6 +234,129 @@ impl<T: BasicSystem> ExtensionsSystem for T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Loop
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
pub trait LoopSystem: BasicSystem {
|
||||||
|
type Env: BasicEnvironment;
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn lollipops(&self) -> Vec<(Vec<Self::Set>, Vec<Self::Set>)>;
|
||||||
|
|
||||||
|
fn lollipops_only_loop(self) -> Vec<Vec<Self::Set>>;
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn lollipops_named(
|
||||||
|
&self,
|
||||||
|
symb: <Self::Env as BasicEnvironment>::Id
|
||||||
|
) -> Option<(Vec<Self::Set>, Vec<Self::Set>)>;
|
||||||
|
|
||||||
|
fn lollipops_only_loop_named(
|
||||||
|
&self,
|
||||||
|
symb: <Self::Env as BasicEnvironment>::Id
|
||||||
|
) -> Option<Vec<Self::Set>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, E, R: ExtensionReaction<Set = S>,
|
||||||
|
T: BasicSystem<Reaction = R, Environment = E, Set = S>>
|
||||||
|
LoopSystem for T
|
||||||
|
where E: BasicEnvironment<Reaction = R, Set = S> + ExtensionsEnvironment,
|
||||||
|
for<'a> &'a E: IntoIterator<Item = (&'a E::Id, &'a E::Process)>,
|
||||||
|
E::Id: Eq,
|
||||||
|
{
|
||||||
|
type Env = E;
|
||||||
|
|
||||||
|
/// A special case of systems is when the context recursively provides
|
||||||
|
/// always the same set of entities. The corresponding computation is
|
||||||
|
/// infinite. It consists of a finite sequence of states followed by a
|
||||||
|
/// looping sequence. IMPORTANT: We return all loops for all X = Q.X, by
|
||||||
|
/// varing X. The set of reactions Rs and the context x are constant. Each
|
||||||
|
/// state of the computation is distinguished by the current entities E.
|
||||||
|
/// Under these assumptions, the predicate lollipop finds the Prefixes and
|
||||||
|
/// the Loops sequences of entities.
|
||||||
|
/// see lollipop
|
||||||
|
fn lollipops(
|
||||||
|
&self
|
||||||
|
) -> Vec<(Vec<Self::Set>, Vec<Self::Set>)> {
|
||||||
|
self.environment().lollipops_decomposed(
|
||||||
|
self.reactions(),
|
||||||
|
self.available_entities(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only returns the loop part of the lollipop, returns for all X, where
|
||||||
|
/// X = Q.X
|
||||||
|
/// see loop
|
||||||
|
fn lollipops_only_loop(
|
||||||
|
self
|
||||||
|
) -> Vec<Vec<Self::Set>> {
|
||||||
|
let filtered =
|
||||||
|
self.environment().iter().filter_map(
|
||||||
|
|l|
|
||||||
|
l.1.filter_delta(l.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
let find_loop_fn = |q| {
|
||||||
|
R::find_only_loop(self.reactions(),
|
||||||
|
self.available_entities(),
|
||||||
|
q)
|
||||||
|
};
|
||||||
|
|
||||||
|
filtered.map(find_loop_fn).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A special case of systems is when the context recursively provides
|
||||||
|
/// always the same set of entities. The corresponding computation is
|
||||||
|
/// infinite. It consists of a finite sequence of states followed by a
|
||||||
|
/// looping sequence. IMPORTANT: We return all loops for all X = Q.X, by
|
||||||
|
/// varing X. The set of reactions Rs and the context x are constant. Each
|
||||||
|
/// state of the computation is distinguished by the current entities E.
|
||||||
|
/// Under these assumptions, the predicate lollipop finds the Prefixes and
|
||||||
|
/// the Loops sequences of entities.
|
||||||
|
/// see lollipop
|
||||||
|
fn lollipops_named(
|
||||||
|
&self,
|
||||||
|
symb: E::Id
|
||||||
|
) -> Option<(Vec<Self::Set>, Vec<Self::Set>)> {
|
||||||
|
self.environment().lollipops_decomposed_named(
|
||||||
|
self.reactions(),
|
||||||
|
self.available_entities(),
|
||||||
|
symb,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only returns the loop part of the lollipop, returns for all X, where
|
||||||
|
/// X = Q.X
|
||||||
|
/// see loop
|
||||||
|
fn lollipops_only_loop_named(
|
||||||
|
&self,
|
||||||
|
symb: E::Id
|
||||||
|
) -> Option<Vec<Self::Set>> {
|
||||||
|
let filtered = self
|
||||||
|
.environment()
|
||||||
|
.iter()
|
||||||
|
.filter_map(
|
||||||
|
|l|
|
||||||
|
if *l.0 == symb {
|
||||||
|
l.1.filter_delta(&symb)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.next();
|
||||||
|
|
||||||
|
let find_loop_fn = |q| {
|
||||||
|
R::find_only_loop(self.reactions(),
|
||||||
|
self.available_entities(),
|
||||||
|
q)
|
||||||
|
};
|
||||||
|
|
||||||
|
filtered.map(find_loop_fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
@ -348,103 +472,6 @@ impl System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Loops
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl System {
|
|
||||||
/// A special case of systems is when the context recursively provides
|
|
||||||
/// always the same set of entities. The corresponding computation is
|
|
||||||
/// infinite. It consists of a finite sequence of states followed by a
|
|
||||||
/// looping sequence. IMPORTANT: We return all loops for all X = Q.X, by
|
|
||||||
/// varing X. The set of reactions Rs and the context x are constant. Each
|
|
||||||
/// state of the computation is distinguished by the current entities E.
|
|
||||||
/// Under these assumptions, the predicate lollipop finds the Prefixes and
|
|
||||||
/// the Loops sequences of entities.
|
|
||||||
/// see lollipop
|
|
||||||
pub fn lollipops(
|
|
||||||
&self
|
|
||||||
) -> Vec<(Vec<Set>, Vec<Set>)> {
|
|
||||||
self.delta.lollipops_decomposed(
|
|
||||||
&self.reaction_rules,
|
|
||||||
&self.available_entities,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Only returns the loop part of the lollipop, returns for all X, where
|
|
||||||
/// X = Q.X
|
|
||||||
/// see loop
|
|
||||||
pub fn lollipops_only_loop(
|
|
||||||
self
|
|
||||||
) -> Vec<Vec<Set>> {
|
|
||||||
let filtered =
|
|
||||||
self.delta.iter().filter_map(
|
|
||||||
|l|
|
|
||||||
l.1.filter_delta(l.0)
|
|
||||||
);
|
|
||||||
|
|
||||||
let find_loop_fn = |q| {
|
|
||||||
Reaction::find_only_loop(&self.reaction_rules,
|
|
||||||
self.available_entities.clone(),
|
|
||||||
q)
|
|
||||||
};
|
|
||||||
|
|
||||||
filtered.map(find_loop_fn).collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// A special case of systems is when the context recursively provides
|
|
||||||
/// always the same set of entities. The corresponding computation is
|
|
||||||
/// infinite. It consists of a finite sequence of states followed by a
|
|
||||||
/// looping sequence. IMPORTANT: We return all loops for all X = Q.X, by
|
|
||||||
/// varing X. The set of reactions Rs and the context x are constant. Each
|
|
||||||
/// state of the computation is distinguished by the current entities E.
|
|
||||||
/// Under these assumptions, the predicate lollipop finds the Prefixes and
|
|
||||||
/// the Loops sequences of entities.
|
|
||||||
/// see lollipop
|
|
||||||
pub fn lollipops_named(
|
|
||||||
&self,
|
|
||||||
symb: IdType
|
|
||||||
) -> Option<(Vec<Set>, Vec<Set>)> {
|
|
||||||
self.delta.lollipops_decomposed_named(
|
|
||||||
&self.reaction_rules,
|
|
||||||
&self.available_entities,
|
|
||||||
symb,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Only returns the loop part of the lollipop, returns for all X, where
|
|
||||||
/// X = Q.X
|
|
||||||
/// see loop
|
|
||||||
pub fn lollipops_only_loop_named(
|
|
||||||
&self,
|
|
||||||
symb: IdType
|
|
||||||
) -> Option<Vec<Set>> {
|
|
||||||
let filtered = self
|
|
||||||
.delta
|
|
||||||
.iter()
|
|
||||||
.filter_map(
|
|
||||||
|l|
|
|
||||||
if *l.0 == symb {
|
|
||||||
l.1.filter_delta(&symb)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.next();
|
|
||||||
|
|
||||||
let find_loop_fn = |q| {
|
|
||||||
Reaction::find_only_loop(&self.reaction_rules,
|
|
||||||
self.available_entities.clone(),
|
|
||||||
q)
|
|
||||||
};
|
|
||||||
|
|
||||||
filtered.map(find_loop_fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Statistics
|
// Statistics
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user