diff --git a/src/main.rs b/src/main.rs index 8f62dbf..3390062 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ fn main() { match presets::run(input) { Ok(()) => {}, - Err(e) => {println!("{e}")} + Err(e) => println!("{e}") } println!("{} milliseconds elapsed", now.elapsed().as_millis()); diff --git a/src/rsprocess/assert/fmt.rs b/src/rsprocess/assert/fmt.rs index a4c3545..4dd1c4f 100644 --- a/src/rsprocess/assert/fmt.rs +++ b/src/rsprocess/assert/fmt.rs @@ -308,8 +308,7 @@ where S: PrintableWithTranslator { write!(f, "{}", Formatter::from(translator, &**l)), Self::Set(set) => write!(f, "{}", Formatter::from(translator, set)), Self::Element(el) => - write!(f, "'{}'", - translator.decode(*el).unwrap_or("Missing".into())), + write!(f, "'{}'", Formatter::from(translator, el)), Self::String(s) => write!(f, r#""{s}""#), Self::Var(v) => write!(f, "{}", Formatter::from(translator, v)), Self::Unary(u, exp) => { @@ -452,8 +451,7 @@ impl PrintableWithTranslator for AssertReturnValue { Self::Set(set) => write!(f, "{}", Formatter::from(translator, set)), Self::Element(el) => - write!(f, "{}", - translator.decode(*el).unwrap_or("Missing".into())), + write!(f, "{}", Formatter::from(translator, el)), Self::Edge(edge) => write!(f, "{{edge: {edge:?}}}"), Self::Node(node) => write!(f, "{{node: {node:?}}}"), Self::Neighbours(node) => diff --git a/src/rsprocess/element.rs b/src/rsprocess/element.rs index 45b0a06..a8bf568 100644 --- a/src/rsprocess/element.rs +++ b/src/rsprocess/element.rs @@ -5,6 +5,17 @@ use super::translator::PrintableWithTranslator; 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)] pub enum IdState { Positive, @@ -31,7 +42,6 @@ impl std::ops::Not for IdState { } } - #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct PositiveType { pub id: IdType, diff --git a/src/rsprocess/environment.rs b/src/rsprocess/environment.rs index eb9917d..817a00f 100644 --- a/src/rsprocess/environment.rs +++ b/src/rsprocess/environment.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use super::choices::{BasicChoices, Choices, PositiveChoices}; 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::element::IdType; use super::translator::{Translator, PrintableWithTranslator, Formatter}; @@ -18,6 +18,7 @@ for<'a> Self: Deserialize<'a> { type Set: BasicSet; type Choices: BasicChoices; type Process: BasicProcess; + type Reaction: BasicReaction; fn get(&self, k: Self::Id) -> Option<&Self::Process>; fn all_elements(&self) -> Self::Set; @@ -28,6 +29,229 @@ for<'a> Self: Deserialize<'a> { ) -> Result; } +pub trait ExtensionsEnvironment: BasicEnvironment { + fn iter( + &self + ) -> <&Self as IntoIterator>::IntoIter + where for<'b> &'b Self: IntoIterator; +} + +impl 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, Vec)>; + + fn lollipops_prefix_len_loop_decomposed( + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + ) -> Vec<(usize, Vec)>; + + fn lollipops_only_loop_decomposed( + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + ) -> Vec>; + + #[allow(clippy::type_complexity)] + fn lollipops_decomposed_named( + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + symb: Self::Id, + ) -> Option<(Vec, Vec)>; + + fn lollipops_prefix_len_loop_decomposed_named( + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + symb: Self::Id, + ) -> Option<(usize, Vec)>; + + fn lollipops_only_loop_decomposed_named( + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + symb: Self::Id, + ) -> Option>; +} + + +impl LoopEnvironment for T +where for<'a> &'a T: IntoIterator, + 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, Vec)> { + // 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::>() + } + + + fn lollipops_prefix_len_loop_decomposed( + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + ) -> Vec<(usize, Vec)> { + 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::>() + } + + + /// see loop + fn lollipops_only_loop_decomposed( + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + ) -> Vec> { + 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::>() + } + + + + /// 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, Vec)> { + 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)> { + 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> { + 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)] pub struct Environment { definitions: HashMap, @@ -38,6 +262,7 @@ impl BasicEnvironment for Environment { type Set = Set; type Choices = Choices; type Id = IdType; + type Reaction = Reaction; fn get(&self, k: IdType) -> Option<&Process> { self.definitions.get(&k) @@ -148,14 +373,14 @@ impl PrintableWithTranslator for Environment { write!( f, "({} -> {})", - translator.decode(*el.0).unwrap_or("Missing".into()), + Formatter::from(translator, el.0), Formatter::from(translator, el.1) )?; } else { write!( f, "({} -> {}), ", - translator.decode(*el.0).unwrap_or("Missing".into()), + Formatter::from(translator, el.0), Formatter::from(translator, el.1) )?; } @@ -164,8 +389,20 @@ impl PrintableWithTranslator for Environment { } } -impl Environment { - pub fn iter(&self) -> std::collections::hash_map::Iter<'_, u32, Process> { +impl IntoIterator for Environment { + type Item = (IdType, Process); + type IntoIter = std::collections::hash_map::IntoIter; + + 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() } } @@ -195,166 +432,6 @@ impl From> 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, Vec)> { - // 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::>() - } - - - pub fn lollipops_prefix_len_loop_decomposed( - &self, - reaction_rules: &[Reaction], - available_entities: &Set, - ) -> Vec<(usize, Vec)> { - 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::>() - } - - - /// see loop - pub fn lollipops_only_loop_decomposed( - &self, - reaction_rules: &[Reaction], - available_entities: &Set, - ) -> Vec> { - 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::>() - } - - - - /// 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, Vec)> { - 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)> { - 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> { - 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 // ----------------------------------------------------------------------------- @@ -536,6 +613,7 @@ impl BasicEnvironment for PositiveEnvironment { type Set = PositiveSet; type Choices = PositiveChoices; type Process = PositiveProcess; + type Reaction = PositiveReaction; fn get(&self, k: Self::Id) -> Option<&Self::Process> { self.definitions.get(&k) @@ -646,14 +724,14 @@ impl PrintableWithTranslator for PositiveEnvironment { write!( f, "({} -> {})", - translator.decode(*el.0).unwrap_or("Missing".into()), + Formatter::from(translator, el.0), Formatter::from(translator, el.1) )?; } else { write!( f, "({} -> {}), ", - translator.decode(*el.0).unwrap_or("Missing".into()), + Formatter::from(translator, el.0), Formatter::from(translator, el.1) )?; } @@ -662,10 +740,20 @@ impl PrintableWithTranslator for PositiveEnvironment { } } -impl PositiveEnvironment { - pub fn iter( - &self - ) -> impl std::iter::Iterator { +impl IntoIterator for PositiveEnvironment { + type Item = (IdType, PositiveProcess); + type IntoIter = std::collections::hash_map::IntoIter; + + 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() } } diff --git a/src/rsprocess/frequency.rs b/src/rsprocess/frequency.rs index 7db8983..9409f89 100644 --- a/src/rsprocess/frequency.rs +++ b/src/rsprocess/frequency.rs @@ -1,16 +1,44 @@ //! Definitions and structure for frequency of elements in a simulation use std::collections::HashMap; +use std::fmt::Debug; -use super::reaction::{Reaction, ExtensionReaction}; -use super::set::{Set, ExtensionsSet}; -use super::system::{System, ExtensionsSystem}; -use super::element::IdType; -use super::translator::{Translator, PrintableWithTranslator, PRECISION}; +use super::element::{IdType, PositiveType}; +use super::environment::{BasicEnvironment, Environment, PositiveEnvironment}; +use super::reaction::{BasicReaction, ExtensionReaction, PositiveReaction, Reaction}; +use super::set::{BasicSet, ExtensionsSet, PositiveSet, Set}; +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 + + LoopSystem; + type Env: BasicEnvironment; + type R: BasicReaction; + type Id; + + fn naive_frequency(system: &Self::Sys) -> Result; + + fn loop_frequency(system: &Self::Sys, + symb: Self::Id) -> Self; + + fn limit_frequency(q: &[Self::Set], + reactions: &[Self::R], + available_entities: &Self::Set) -> Option; + + fn fast_frequency(q: &[Self::Set], + reactions: &[Self::R], + available_entities: &Self::Set, + weights: &[u32]) -> Option; +} + +/// Structure that holds the frequency of elements of a run or multiple runs, /// weighted. To print use ```translator::FrequencyDisplay```. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct Frequency { pub frequency_map: HashMap>, pub totals: Vec, @@ -18,42 +46,28 @@ pub struct Frequency { } impl Frequency { - pub fn new() -> Self { - Frequency { - frequency_map: HashMap::new(), - totals: vec![], - weights: vec![], - } - } - - pub fn add(&mut self, e: &Set, run: usize) { - for &el in e.iter() { + fn add(&mut self, e: Set, run: usize) { + for el in e.iter() { 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 { entry.resize(run + 1, 0); } - entry[run] += 1 - } + 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 + self.totals[run] += 1 } - pub fn append_weight(&mut self, new_weight: u32) { - self.weights.push(new_weight) + fn append_weight(&mut self, new_weight: u32) { + self.weights.push(new_weight) } - pub fn total_weights(&self) -> u32 { - self.weights.iter().sum() - } -} - -impl Default for Frequency { - fn default() -> Self { - Frequency::new() + fn total_weights(&self) -> u32 { + self.weights.iter().sum() } } @@ -61,7 +75,7 @@ impl PrintableWithTranslator for Frequency { 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(); @@ -69,9 +83,9 @@ impl PrintableWithTranslator for Frequency { let weights = &self.weights; 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())); @@ -91,36 +105,36 @@ impl PrintableWithTranslator for Frequency { total_freq += weighted_freq; } - total_freq /= self.total_weights() as f32; + total_freq /= self.total_weights() as f32; #[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, ",")?; - } + } } 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 /// in all traversed states. /// see naiveFreq - pub fn naive_frequency( - system: &System - ) -> Result { + fn naive_frequency(system: &Self::Sys) -> Result { let ect = system.run_separated()?; - let es = ect.iter().map(|(e, _, _)| e).collect::>(); - let mut freq = Frequency::new(); + let mut freq = Self::default(); 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) } @@ -128,15 +142,12 @@ impl Frequency { /// Assume the system stabilizes in a loop, calculates the frequency of each /// symbol in all states of the loop. /// see loopFreq - pub fn loop_frequency( - system: &System, - symb: IdType - ) -> Self { - let mut freq = Frequency::new(); + 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, 0)); + hoop.iter().for_each(|e| freq.add(e.clone(), 0)); } freq } @@ -145,29 +156,30 @@ impl Frequency { /// stabilizes in a loop, calculates the frequency of the symbols in any /// state in the last loop. /// see limitFreq - pub fn limit_frequency( - q: &[Set], - reaction_rules: &[Reaction], - available_entities: &Set, + fn limit_frequency( + q: &[Self::Set], + reaction_rules: &[Self::R], + available_entities: &Self::Set, ) -> Option { let mut available_entities = available_entities.clone(); for q in q.iter().rev().skip(1).rev() { - let res = - Reaction::lollipops_only_loop_decomposed_q(reaction_rules, - q, - &available_entities); - available_entities = res.into_iter().next()?; + let res = + Self::R::lollipops_only_loop_decomposed_q(reaction_rules, + q, + &available_entities); + available_entities = res.into_iter().next()?; } - let mut freq = Frequency::new(); + let mut freq = Self::default(); freq.append_weight(1); - Reaction::lollipops_only_loop_decomposed_q(reaction_rules, + Self::R::lollipops_only_loop_decomposed_q(reaction_rules, q.last().unwrap(), &available_entities) - .iter() - .for_each(|e| freq.add(e, 0)); + .iter() + .cloned() + .for_each(|e| freq.add(e, 0)); Some(freq) } @@ -175,25 +187,204 @@ impl Frequency { /// stabilizes in a loop, calculates the frequency of the symbols in any /// state in any loop, weighted. /// see fastFreq - pub fn fast_frequency( - q: &[Set], - reaction_rules: &[Reaction], - available_entities: &Set, + fn fast_frequency( + q: &[Self::Set], + reaction_rules: &[Self::R], + available_entities: &Self::Set, weights: &[u32], ) -> Option { // FIXME: we return the empty frequency or do we not return anything? 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() { - freq.append_weight(w); - let hoop = - Reaction::lollipops_only_loop_decomposed_q(reaction_rules, + freq.append_weight(w); + let hoop = + Self::R::lollipops_only_loop_decomposed_q(reaction_rules, q, &available_entities); - hoop.iter().for_each(|e| freq.add(e, pos)); - available_entities = hoop.into_iter().next()?; + hoop.iter().cloned().for_each(|e| freq.add(e, pos)); + 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>, + pub totals: Vec, + pub weights: Vec, +} + +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 { + 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 { + 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 { + // 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) } diff --git a/src/rsprocess/presets.rs b/src/rsprocess/presets.rs index 9909129..192bc97 100644 --- a/src/rsprocess/presets.rs +++ b/src/rsprocess/presets.rs @@ -399,6 +399,8 @@ pub fn hoop( system: &EvaluatedSystem, symbol: String ) -> Result { + use system::LoopSystem; + let (res, translator) = match system { EvaluatedSystem::System { sys, translator } => (sys, translator), EvaluatedSystem::Graph { graph, translator } => { @@ -436,6 +438,8 @@ pub fn hoop( /// (deterministic) terminating Reaction System. /// equivalent to main_do(freq, PairList) pub fn freq(system: &EvaluatedSystem) -> Result { + use frequency::BasicFrequency; + let (sys, translator) = match system { EvaluatedSystem::System { sys, translator } => (sys, translator), EvaluatedSystem::Graph { graph, translator } => { @@ -461,6 +465,8 @@ pub fn limit_freq( system: &mut EvaluatedSystem, experiment: String ) -> Result { + use frequency::BasicFrequency; + let (sys, translator): (&system::System, &mut Translator) = match system { EvaluatedSystem::System { sys, translator } => (sys, translator), EvaluatedSystem::Graph { graph, translator } => { @@ -499,8 +505,9 @@ pub fn limit_freq( pub fn fast_freq( system: &mut EvaluatedSystem, experiment: String -) -> Result -{ +) -> Result { + use frequency::BasicFrequency; + let (sys, translator): (&system::System, &mut Translator) = match system { EvaluatedSystem::System { sys, translator } => (sys, translator), EvaluatedSystem::Graph { graph, translator } => { @@ -513,17 +520,18 @@ pub fn fast_freq( let (weights, sets) = read_file(translator, experiment, parser_experiment)?; - let res = match frequency::Frequency::fast_frequency( - &sets, - &sys.reaction_rules, - &sys.available_entities, - &weights, - ) { - Some(e) => e, - None => { - return Err("Error calculating frequency.".into()); - } - }; + let res = + match frequency::Frequency::fast_frequency( + &sets, + &sys.reaction_rules, + &sys.available_entities, + &weights, + ) { + Some(e) => e, + None => { + return Err("Error calculating frequency.".into()); + } + }; Ok(format!( "Frequency of encountered symbols:\n{}", diff --git a/src/rsprocess/reaction.rs b/src/rsprocess/reaction.rs index b46cc49..96a3843 100644 --- a/src/rsprocess/reaction.rs +++ b/src/rsprocess/reaction.rs @@ -14,134 +14,131 @@ pub trait BasicReaction: Clone + Default + Eq + Hash + Serialize + PrintableWithTranslator where for<'de> Self: Deserialize<'de>, { - type Set: BasicSet; - fn enabled(&self, state: &Self::Set) -> bool; - fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set>; + type Set: BasicSet; + fn enabled(&self, state: &Self::Set) -> bool; + fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set>; } 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( - reactions: &[Self], - entities: Self::Set, - q: &Self::Set - ) -> (Vec, Vec); + fn find_loop( + reactions: &[Self], + entities: Self::Set, + q: &Self::Set + ) -> (Vec, Vec); - fn find_only_loop( - reactions: &[Self], - entities: Self::Set, - q: &Self::Set - ) -> Vec; + fn find_only_loop( + reactions: &[Self], + entities: &Self::Set, + q: &Self::Set + ) -> Vec; - fn find_prefix_len_loop( - reactions: &[Self], - entities: Self::Set, - q: &Self::Set - ) -> (usize, Vec); + fn find_prefix_len_loop( + reactions: &[Self], + entities: Self::Set, + q: &Self::Set + ) -> (usize, Vec); - fn lollipops_only_loop_decomposed_q( - reactions: &[Self], - entities: &Self::Set, - q: &Self::Set - ) -> Vec; + fn lollipops_only_loop_decomposed_q( + reactions: &[Self], + entities: &Self::Set, + q: &Self::Set + ) -> Vec; } /// Implementations for all reactions. impl, Set: BasicSet> ExtensionReaction for T { - type Set = Set; + type Set = Set; - /// Computes the result of a series of reactions. Returns the union of all - /// products. - /// see result - fn compute_all( - reactions: &[Self], - state: &Set - ) -> Set - where Self: Sized { - reactions.iter().fold(Set::default(), |mut acc: Set, r| { - acc.extend(r.compute_step(state)); - acc - }) + /// Computes the result of a series of reactions. Returns the union of all + /// products. + /// see result + fn compute_all( + reactions: &[Self], + state: &Set + ) -> Set + where Self: Sized { + reactions.iter().fold(Set::default(), |mut acc: Set, r| { + acc.extend(r.compute_step(state)); + acc + }) + } + + /// Finds the loops by simulating the system. + fn find_loop( + reactions: &[Self], + entities: Set, + q: &Set + ) -> (Vec, Vec) { + 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. - fn find_loop( - reactions: &[Self], - entities: Set, - q: &Set - ) -> (Vec, Vec) { - 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. + fn find_only_loop( + reactions: &[Self], + entities: &Set, + q: &Set + ) -> Vec { + let mut entities = entities.clone(); + let mut trace = vec![]; + loop { + if let Some((_prefix, hoop)) = entities.split(&trace) { + return 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. - fn find_only_loop( - reactions: &[Self], - entities: Set, - q: &Set - ) -> Vec { - let mut entities = entities; - let mut trace = vec![]; - loop { - if let Some((_prefix, hoop)) = entities.split(&trace) { - return 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 and the length of the prefix by simulating the system. + fn find_prefix_len_loop( + reactions: &[Self], + entities: Set, + q: &Set + ) -> (usize, Vec) { + let mut entities = entities; + let mut trace = vec![]; + loop { + if let Some((prefix, hoop)) = entities.split(&trace) { + 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; + } } + } - - /// Finds the loops and the length of the prefix by simulating the system. - fn find_prefix_len_loop( - reactions: &[Self], - entities: Set, - q: &Set - ) -> (usize, Vec) { - let mut entities = entities; - let mut trace = vec![]; - loop { - if let Some((prefix, hoop)) = entities.split(&trace) { - 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 { - let find_loop_fn = - |q| Self::find_only_loop(reactions, - entities.clone(), - q); - find_loop_fn(q) - } + /// see loop/5 + fn lollipops_only_loop_decomposed_q( + reactions: &[Self], + entities: &Set, + q: &Set, + ) -> Vec { + let find_loop_fn = + |q| Self::find_only_loop(reactions, + entities, + q); + find_loop_fn(q) + } } @@ -152,121 +149,121 @@ impl, Set: BasicSet> ExtensionReaction for T { /// Basic structure for a reaction. #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)] pub struct Reaction { - pub reactants: Set, - pub inhibitors: Set, - pub products: Set, + pub reactants: Set, + pub inhibitors: Set, + pub products: Set, } impl BasicReaction for Reaction { - type Set = Set; + type Set = Set; - /// returns true if ```current_state``` enables the reaction - /// see enable - fn enabled(&self, current_state: &Self::Set) -> bool { - self.reactants.is_subset(current_state) - && self.inhibitors.is_disjoint(current_state) - } + /// returns true if ```current_state``` enables the reaction + /// see enable + fn enabled(&self, current_state: &Self::Set) -> bool { + self.reactants.is_subset(current_state) + && self.inhibitors.is_disjoint(current_state) + } - /// Computes the result of a single reaction (if enabled returns the - /// products) otherwise returns None. - /// see result - fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> { - if self.enabled(state) { - Some(&self.products) - } else { - None - } + /// Computes the result of a single reaction (if enabled returns the + /// products) otherwise returns None. + /// see result + fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> { + if self.enabled(state) { + Some(&self.products) + } else { + None } + } } impl PrintableWithTranslator for Reaction { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!( - f, - "(r: {}, i: {}, p: {})", - Formatter::from(translator, &self.reactants), - Formatter::from(translator, &self.inhibitors), - Formatter::from(translator, &self.products) - ) - } + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) + -> std::fmt::Result { + write!( + f, + "(r: {}, i: {}, p: {})", + Formatter::from(translator, &self.reactants), + Formatter::from(translator, &self.inhibitors), + Formatter::from(translator, &self.products) + ) + } } impl Reaction { - pub fn from(reactants: Set, inhibitors: Set, products: Set) -> Self { - Reaction { reactants, inhibitors, products } - } + pub fn from(reactants: Set, inhibitors: Set, products: Set) -> Self { + Reaction { reactants, inhibitors, products } + } - pub fn all_products(reactions: &[Self]) -> Set { - reactions.iter().fold( - Set::default(), - |acc, r| - acc.union(&r.products) - ) - } + pub fn all_products(reactions: &[Self]) -> Set { + reactions.iter().fold( + Set::default(), + |acc, r| + acc.union(&r.products) + ) + } - pub fn all_reactions_with_product<'a>( - reactions: &'a [Self], - el: &IdType - ) -> Vec<&'a Self> { - reactions.iter().fold( - vec![], - |mut acc, r| { - if r.products.contains(el) { - acc.push(r); - } - acc - } - ) - } + pub fn all_reactions_with_product<'a>( + reactions: &'a [Self], + el: &IdType + ) -> Vec<&'a Self> { + reactions.iter().fold( + vec![], + |mut acc, r| { + if r.products.contains(el) { + acc.push(r); + } + acc + } + ) + } } // ----------------------------------------------------------------------------- #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)] pub struct PositiveReaction { - pub reactants: PositiveSet, - pub products: PositiveSet + pub reactants: PositiveSet, + pub products: PositiveSet } impl BasicReaction for PositiveReaction { - type Set = PositiveSet; + type Set = PositiveSet; - fn enabled(&self, state: &Self::Set) -> bool { - self.reactants.is_subset(state) - } + fn enabled(&self, state: &Self::Set) -> bool { + self.reactants.is_subset(state) + } - fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> { - if self.enabled(state) { - Some(&self.products) - } else { - None - } + fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> { + if self.enabled(state) { + Some(&self.products) + } else { + None } + } } impl PrintableWithTranslator for PositiveReaction { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!( - f, - "(r: {}, p: {})", - Formatter::from(translator, &self.reactants), - Formatter::from(translator, &self.products), - ) - } + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) + -> std::fmt::Result { + write!( + f, + "(r: {}, p: {})", + Formatter::from(translator, &self.reactants), + Formatter::from(translator, &self.products), + ) + } } impl PositiveReaction { - pub fn from(reactants: PositiveSet, products: PositiveSet) -> Self { - Self { reactants, products } - } + pub fn from(reactants: PositiveSet, products: PositiveSet) -> Self { + Self { reactants, products } + } - pub fn create(reactants: Set, inhibitors: Set, products: Set) -> Self { - Self { reactants: - reactants.to_positive_set(IdState::Positive).union( - &inhibitors.to_positive_set(IdState::Negative) - ), - products: products.to_positive_set(IdState::Positive) } - } + pub fn create(reactants: Set, inhibitors: Set, products: Set) -> Self { + Self { reactants: + reactants.to_positive_set(IdState::Positive).union( + &inhibitors.to_positive_set(IdState::Negative) + ), + products: products.to_positive_set(IdState::Positive) } + } } diff --git a/src/rsprocess/set.rs b/src/rsprocess/set.rs index 72eea1e..a2be930 100644 --- a/src/rsprocess/set.rs +++ b/src/rsprocess/set.rs @@ -170,13 +170,9 @@ impl PrintableWithTranslator for Set { let mut it = self.iter().peekable(); while let Some(el) = it.next() { if it.peek().is_none() { - write!(f, - "{}", - translator.decode(*el).unwrap_or("Missing".into()))?; + write!(f, "{}", Formatter::from(translator, el))?; } else { - write!(f, - "{}, ", - translator.decode(*el).unwrap_or("Missing".into()))?; + write!(f, "{}, ", Formatter::from(translator, el))?; } } write!(f, "}}") diff --git a/src/rsprocess/system.rs b/src/rsprocess/system.rs index 8462eb1..72243ad 100644 --- a/src/rsprocess/system.rs +++ b/src/rsprocess/system.rs @@ -5,12 +5,13 @@ use std::fmt::Debug; use std::hash::Hash; 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::process::{BasicProcess, PositiveProcess, Process}; use super::reaction::{BasicReaction, ExtensionReaction, PositiveReaction, Reaction}; use super::set::{BasicSet, PositiveSet, Set}; -use super::element::{IdState, IdType}; +use super::element::IdState; use super::transitions::TransitionsIterator; use super::translator::{Translator, PrintableWithTranslator, Formatter}; @@ -233,6 +234,129 @@ impl ExtensionsSystem for T { } } +// ----------------------------------------------------------------------------- +// Loop +// ----------------------------------------------------------------------------- + +pub trait LoopSystem: BasicSystem { + type Env: BasicEnvironment; + + #[allow(clippy::type_complexity)] + fn lollipops(&self) -> Vec<(Vec, Vec)>; + + fn lollipops_only_loop(self) -> Vec>; + + #[allow(clippy::type_complexity)] + fn lollipops_named( + &self, + symb: ::Id + ) -> Option<(Vec, Vec)>; + + fn lollipops_only_loop_named( + &self, + symb: ::Id + ) -> Option>; +} + +impl, + T: BasicSystem> + LoopSystem for T +where E: BasicEnvironment + ExtensionsEnvironment, +for<'a> &'a E: IntoIterator, + 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, Vec)> { + 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> { + 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::>() + } + + /// 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, Vec)> { + 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> { + 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)] @@ -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, Vec)> { - 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> { - 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::>() - } - - - /// 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, Vec)> { - 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> { - 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 // -----------------------------------------------------------------------------