diff --git a/src/main.rs b/src/main.rs index fbd5677..a9b4efa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ #![allow(unused_imports)] mod rsprocess; use lalrpop_util::lalrpop_mod; -use std::rc::Rc; +use std::{hash::Hash, rc::Rc}; use rsprocess::translator::WithTranslator; // use std::io; @@ -195,5 +195,7 @@ fn main() -> Result<(), Box> { } println!(); } + + // ------------------------------------------------------------------------- Ok(()) } diff --git a/src/rsprocess/confluence.rs b/src/rsprocess/confluence.rs index cd70278..2ce83df 100644 --- a/src/rsprocess/confluence.rs +++ b/src/rsprocess/confluence.rs @@ -77,6 +77,7 @@ pub fn confluent_named( // ----------------------------------------------------------------------------- +// see invariant pub fn invariant_named( delta: &RSenvironment, reaction_rules: &[RSreaction], @@ -116,6 +117,7 @@ pub fn invariant_named( // ----------------------------------------------------------------------------- +// see loop_confluent pub fn loop_confluent_named( deltas: &[RSenvironment], reaction_rules: &[RSreaction], @@ -127,6 +129,7 @@ pub fn loop_confluent_named( .collect::>>() } +// see strong_confluent #[allow(clippy::type_complexity)] pub fn strong_confluent_named( deltas: &[RSenvironment], diff --git a/src/rsprocess/frequency.rs b/src/rsprocess/frequency.rs new file mode 100644 index 0000000..9b64114 --- /dev/null +++ b/src/rsprocess/frequency.rs @@ -0,0 +1,137 @@ +#![allow(dead_code)] + +use std::collections::HashMap; +use crate::rsprocess::perpetual::lollipops_only_loop_decomposed_q; + +use super::perpetual::{lollipops_decomposed_named, lollipops_only_loop_decomposed_named, lollipops_only_loop_named}; +use super::structure::{RSenvironment, RSreaction, RSset, RSsystem}; +use super::transitions::run_separated; +use super::translator::IdType; + +#[derive(Debug, Clone)] +pub struct Frequency { + pub frequency_map: HashMap, + pub total_runs: usize, + pub weight: u32 +} + +impl Frequency { + pub fn new(weight: u32) -> Self { + Frequency { frequency_map: HashMap::new(), total_runs: 0, weight } + } + + pub fn add(&mut self, e: &RSset) { + for &el in e.iter() { + *self.frequency_map.entry(el).or_default() += 1 + } + self.total_runs += 1 + } + + pub fn merge(&mut self, other: Frequency) { + let mut count = 0; + other.frequency_map.iter().for_each( + |(&k, &v)| { + *self.frequency_map.entry(k) + .or_insert_with(|| {count+=1; 0}) += v; + } + ); + self.total_runs += count; + // FIXME: ??? + self.weight += other.weight; + } +} + + +// ----------------------------------------------------------------------------- + +// see naiveFreq +pub fn naive_frequency(system: &RSsystem) -> Result { + let ect = run_separated(system)?; + let es = ect.iter().map(|(e, _, _)| e).collect::>(); + + let mut freq = Frequency::new(1); + + es.iter().for_each(|e| freq.add(e)); + + Ok(freq) +} + +// see naiveFreq +pub fn naive_frequency_weighted(system: &RSsystem, weight: u32) -> Result { + let ect = run_separated(system)?; + let es = ect.iter().map(|(e, _, _)| e).collect::>(); + + let mut freq = Frequency::new(weight); + + es.iter().for_each(|e| freq.add(e)); + + Ok(freq) +} + +// see loopFreq +pub fn loop_frequency(system: &RSsystem, symb: IdType, weight: u32) -> Frequency { + // FIXME: we return the empty frequency or do we not return anything? + let mut freq = Frequency::new(weight); + + if let Some(hoop) = lollipops_only_loop_named(system.clone(), symb) { + hoop.iter().for_each(|e| freq.add(e)); + } + freq +} + +// see limitFreq +pub fn limit_frequency( + q: &[RSset], + reaction_rules: &[RSreaction], + available_entities: &RSset, + weight: u32 +) -> Option { + let mut available_entities = available_entities.clone(); + for q in q.iter().rev().skip(1).rev() { + let res = lollipops_only_loop_decomposed_q(q, + reaction_rules, + &available_entities); + available_entities = res.into_iter().next()?; + } + + let mut freq = Frequency::new(weight); + + lollipops_only_loop_decomposed_q(q.last().unwrap(), + reaction_rules, + &available_entities) + .iter().for_each(|e| freq.add(e)); + Some(freq) +} + + +// see fastFreq +pub fn fast_frequency( + q: &[&[RSset]], + reaction_rules: &[RSreaction], + available_entities: &RSset, + weights: &[u32] +) -> Option { + // FIXME: we return the empty frequency or do we not return anything? + let mut available_entities = available_entities.clone(); + + let mut freq = Frequency::new(1); + + for (&q, &w) in q.iter().zip(weights) { + let mut new_freq = Frequency::new(w); + for q in q.iter().rev().skip(1).rev() { + let hoop = lollipops_only_loop_decomposed_q(q, + reaction_rules, + &available_entities); + hoop.iter().for_each(|e| freq.add(e)); + available_entities = hoop.into_iter().next()?; + } + + lollipops_only_loop_decomposed_q(q.last().unwrap(), + reaction_rules, + &available_entities) + .iter().for_each(|e| new_freq.add(e)); + + freq.merge(new_freq); + } + Some(freq) +} diff --git a/src/rsprocess/mod.rs b/src/rsprocess/mod.rs index 4ffb7a3..0525a43 100644 --- a/src/rsprocess/mod.rs +++ b/src/rsprocess/mod.rs @@ -5,3 +5,4 @@ pub mod classical; pub mod transitions; pub mod perpetual; pub mod confluence; +pub mod frequency; diff --git a/src/rsprocess/perpetual.rs b/src/rsprocess/perpetual.rs index 23a9ca4..63da4a4 100644 --- a/src/rsprocess/perpetual.rs +++ b/src/rsprocess/perpetual.rs @@ -80,17 +80,15 @@ fn find_prefix_len_loop( fn filter_delta<'a>(x: (&IdType, &'a RSprocess)) -> Option<&'a RSset> { use super::structure::RSprocess::*; let (id, rest) = x; - match rest { - EntitySet{ entities, next_process} => { - match &**next_process { - RecursiveIdentifier{ identifier } if identifier == id => { - Some(entities) - }, - _ => None + + if let EntitySet{ entities, next_process} = rest { + if let RecursiveIdentifier{ identifier } = &**next_process { + if identifier == id { + return Some(entities); } - }, - _ => None + } } + None } @@ -180,17 +178,15 @@ fn filter_delta_named<'a>( if id != symb { return None; } - match rest { - EntitySet{ entities, next_process} => { - match &**next_process { - RecursiveIdentifier{ identifier } if identifier == id => { - Some(entities) - }, - _ => None + + if let EntitySet{ entities, next_process} = rest { + if let RecursiveIdentifier{ identifier } = &**next_process { + if identifier == id { + return Some(entities); } - }, - _ => None + } } + None } // see lollipop @@ -200,8 +196,6 @@ pub fn lollipops_decomposed_named( available_entities: &RSset, symb: IdType ) -> Option<(Vec, Vec)> { - // FIXME: i think we are only interested in "x", not all symbols that - // satisfy X = pre(Q, rec(X)) let filtered = delta.iter().filter_map(|x| filter_delta_named(x, &symb)).next(); let find_loop_fn = |q| find_loop(reaction_rules, @@ -227,8 +221,6 @@ pub fn lollipops_only_loop_named( system: RSsystem, symb: IdType ) -> Option> { - // FIXME: i think we are only interested in "x", not all symbols that - // satisfy X = pre(Q, rec(X)) let filtered = system.get_delta().iter() .filter_map(|x| filter_delta_named(x, &symb)).next(); @@ -246,8 +238,6 @@ pub fn lollipops_prefix_len_loop_decomposed_named( available_entities: &RSset, symb: IdType ) -> Option<(usize, Vec)> { - // FIXME: i think we are only interested in "x", not all symbols that - // satisfy X = pre(Q, rec(X)) let filtered = delta.iter() .filter_map(|x| filter_delta_named(x, &symb)).next(); @@ -265,8 +255,6 @@ pub fn lollipops_only_loop_decomposed_named( available_entities: &RSset, symb: IdType ) -> Option> { - // FIXME: i think we are only interested in "x", not all symbols that - // satisfy X = pre(Q, rec(X)) let filtered = delta.iter() .filter_map(|x| filter_delta_named(x, &symb)).next(); @@ -276,3 +264,16 @@ pub fn lollipops_only_loop_decomposed_named( filtered.map(find_loop_fn) } + +// see loop/5 +pub fn lollipops_only_loop_decomposed_q( + q: &RSset, + reaction_rules: &[RSreaction], + available_entities: &RSset, +) -> Vec { + let find_loop_fn = |q| find_only_loop(reaction_rules, + available_entities.clone(), + q); + + find_loop_fn(q) +} diff --git a/src/rsprocess/structure.rs b/src/rsprocess/structure.rs index d5ceb2e..5452024 100644 --- a/src/rsprocess/structure.rs +++ b/src/rsprocess/structure.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::hash::{Hash, Hasher}; use std::rc::Rc; use super::translator::{IdType}; @@ -8,32 +8,32 @@ use super::translator::{IdType}; // ----------------------------------------------------------------------------- // RSset // ----------------------------------------------------------------------------- -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct RSset { - identifiers: HashSet + identifiers: BTreeSet } impl From<[IdType; N]> for RSset { fn from(arr: [IdType; N]) -> Self { - RSset{identifiers: HashSet::from(arr)} + RSset{identifiers: BTreeSet::from(arr)} } } impl From<&[IdType]> for RSset { fn from(arr: &[IdType]) -> Self { - RSset{identifiers: HashSet::from_iter(arr.to_vec())} + RSset{identifiers: BTreeSet::from_iter(arr.to_vec())} } } impl From> for RSset { fn from(arr: Vec) -> Self { - RSset{identifiers: HashSet::from_iter(arr)} + RSset{identifiers: BTreeSet::from_iter(arr)} } } impl RSset { pub fn new() -> Self { - RSset{identifiers: HashSet::new()} + RSset{identifiers: BTreeSet::new()} } pub fn is_subset(&self, b: &RSset) -> bool { @@ -61,7 +61,7 @@ impl RSset { pub fn intersection(&self, b: &RSset) -> RSset { // TODO maybe find more efficient way without copy/clone - let res: HashSet<_> = b.identifiers.intersection(&self.identifiers) + let res: BTreeSet<_> = b.identifiers.intersection(&self.identifiers) .copied() .collect(); RSset { identifiers: res } @@ -69,28 +69,31 @@ impl RSset { pub fn subtraction(&self, b: &RSset) -> RSset { // TODO maybe find more efficient way without copy/clone - let res: HashSet<_> = self.identifiers.difference(&b.identifiers) + let res: BTreeSet<_> = self.identifiers.difference(&b.identifiers) .copied() .collect(); RSset { identifiers: res } } - pub fn hashset(&self) -> &HashSet { + pub fn hashset(&self) -> &BTreeSet { &self.identifiers } -} -impl Hash for RSset { - fn hash(&self, state: &mut H) { - let mut a: Vec<&_> = self.identifiers.iter().collect(); - a.sort(); - for s in a.iter() { - s.hash(state); - } + pub fn iter(&self) -> std::collections::btree_set::Iter<'_, IdType> { + self.identifiers.iter() } - } +impl IntoIterator for RSset { + type Item = IdType; + type IntoIter = std::collections::btree_set::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.identifiers.into_iter() + } +} + + // ----------------------------------------------------------------------------- // RSreaction // ----------------------------------------------------------------------------- diff --git a/src/rsprocess/translator.rs b/src/rsprocess/translator.rs index 3bc895c..009a0ad 100644 --- a/src/rsprocess/translator.rs +++ b/src/rsprocess/translator.rs @@ -41,10 +41,10 @@ impl Translator { } // ----------------------------------------------------------------------------- -use super::structure::{ +use super::{frequency::{self, Frequency}, structure::{ RSassert, RSassertOp, RSchoices, RSenvironment, RSlabel, RSprocess, RSreaction, RSset, RSsystem, RSBHML, -}; +}}; use std::fmt; #[allow(clippy::large_enum_variant)] @@ -91,6 +91,10 @@ pub enum WithTranslator<'a> { translator: &'a Translator, bhml: &'a RSBHML, }, + Frequency { + translator: &'a Translator, + frequency: &'a Frequency, + } } macro_rules! from_RS { @@ -126,6 +130,8 @@ impl<'a> WithTranslator<'a> { from_RS!(from_RSassert, RSassert, assert, RSassert); from_RS!(from_RSBHML, RSBHML, bhml, RSBHML); + + from_RS!(from_Frequency, Frequency, frequency, Frequency); } // ----------------------------------------------------------------------------- @@ -367,6 +373,28 @@ fn print_bhml( todo!() } +fn print_frequency( + f: &mut fmt::Formatter, + translator: &Translator, + frequency: &Frequency, +) -> fmt::Result { + write!(f, "[")?; + let mut it = frequency.frequency_map.iter().peekable(); + + while let Some((e, freq)) = it.next() { + if it.peek().is_none() { + write!(f, "{} -> {:.2}", + translator.decode(*e), + (*freq as f32 * frequency.weight as f32 * 100.)/(frequency.total_runs as f32))?; + } else { + write!(f, "{} -> {:.2}, ", + translator.decode(*e), + (*freq as f32 * frequency.weight as f32 * 100.)/(frequency.total_runs as f32))?; + } + } + write!(f, "]") +} + impl<'a> fmt::Display for WithTranslator<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -390,6 +418,8 @@ impl<'a> fmt::Display for WithTranslator<'a> { print_assert(f, translator, assert), WithTranslator::RSBHML { translator, bhml, } => print_bhml(f, translator, bhml), + WithTranslator::Frequency { translator, frequency } => + print_frequency(f, translator, frequency), } } }