Frequency struct for positive rs

Also loops now in LoopEnvironment trait
This commit is contained in:
elvis
2025-09-05 13:13:35 +02:00
parent aa0f795fae
commit fd33af456a
9 changed files with 879 additions and 564 deletions

View File

@ -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());

View File

@ -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) =>

View File

@ -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,

View File

@ -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()
} }
} }

View File

@ -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)
} }

View File

@ -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{}",

View File

@ -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) }
} }
} }

View File

@ -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, "}}")

View File

@ -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
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------