Frequency struct for positive rs
Also loops now in LoopEnvironment trait
This commit is contained in:
@ -9,7 +9,7 @@ fn main() {
|
||||
|
||||
match presets::run(input) {
|
||||
Ok(()) => {},
|
||||
Err(e) => {println!("{e}")}
|
||||
Err(e) => println!("{e}")
|
||||
}
|
||||
|
||||
println!("{} milliseconds elapsed", now.elapsed().as_millis());
|
||||
|
||||
@ -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) =>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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{}",
|
||||
|
||||
@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -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, "}}")
|
||||
|
||||
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user