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) {
Ok(()) => {},
Err(e) => {println!("{e}")}
Err(e) => println!("{e}")
}
println!("{} milliseconds elapsed", now.elapsed().as_millis());

View File

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

View File

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

View File

@ -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<Set = Self::Set, Id = Self::Id>;
type Reaction: BasicReaction<Set = Self::Set>;
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<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)]
pub struct Environment {
definitions: HashMap<IdType, Process>,
@ -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<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()
}
}
@ -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
// -----------------------------------------------------------------------------
@ -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<Item = (&u32, &PositiveProcess)> {
impl IntoIterator for PositiveEnvironment {
type Item = (IdType, PositiveProcess);
type IntoIter = std::collections::hash_map::IntoIter<IdType, 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()
}
}

View File

@ -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<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```.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct Frequency {
pub frequency_map: HashMap<IdType, Vec<u32>>,
pub totals: Vec<usize>,
@ -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<Self, String> {
fn naive_frequency(system: &Self::Sys) -> Result<Self, String> {
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);
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<Self> {
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<Self> {
// 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<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)
}

View File

@ -399,6 +399,8 @@ pub fn hoop(
system: &EvaluatedSystem,
symbol: String
) -> Result<String, String> {
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<String, String> {
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<String, String> {
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<String, String>
{
) -> Result<String, String> {
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{}",

View File

@ -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<Self::Set>, Vec<Self::Set>);
fn find_loop(
reactions: &[Self],
entities: Self::Set,
q: &Self::Set
) -> (Vec<Self::Set>, Vec<Self::Set>);
fn find_only_loop(
reactions: &[Self],
entities: Self::Set,
q: &Self::Set
) -> Vec<Self::Set>;
fn find_only_loop(
reactions: &[Self],
entities: &Self::Set,
q: &Self::Set
) -> Vec<Self::Set>;
fn find_prefix_len_loop(
reactions: &[Self],
entities: Self::Set,
q: &Self::Set
) -> (usize, Vec<Self::Set>);
fn find_prefix_len_loop(
reactions: &[Self],
entities: Self::Set,
q: &Self::Set
) -> (usize, Vec<Self::Set>);
fn lollipops_only_loop_decomposed_q(
reactions: &[Self],
entities: &Self::Set,
q: &Self::Set
) -> Vec<Self::Set>;
fn lollipops_only_loop_decomposed_q(
reactions: &[Self],
entities: &Self::Set,
q: &Self::Set
) -> Vec<Self::Set>;
}
/// Implementations for all reactions.
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
/// 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<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.
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.
fn find_only_loop(
reactions: &[Self],
entities: &Set,
q: &Set
) -> Vec<Set> {
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<Set> {
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<Set>) {
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<Set>) {
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<Set> {
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<Set> {
let find_loop_fn =
|q| Self::find_only_loop(reactions,
entities,
q);
find_loop_fn(q)
}
}
@ -152,121 +149,121 @@ impl<T: BasicReaction<Set = Set>, 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) }
}
}

View File

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

View File

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