diff --git a/src/examples.rs b/src/examples.rs index a3f854b..6b0bb90 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -1,20 +1,19 @@ -use crate::rsprocess::statistics; +use crate::rsprocess::{frequency, + statistics, + transitions, + perpetual}; use crate::rsprocess::structure::RSsystem; -use crate::rsprocess::transitions; -use crate::rsprocess::translator::Translator; -use crate::rsprocess::translator::WithTranslator; -use crate::rsprocess::perpetual; +use crate::rsprocess::translator::{Translator, WithTranslator}; -use std::fs; -use std::io; -use std::io::prelude::*; use std::env; +use std::fs; +use std::io::prelude::*; +use std::io; // grammar is defined in main.rs, calling lalrpop_mod! twice, generates twice // the code use super::grammar; - fn read_system( translator: &mut Translator, path: std::path::PathBuf @@ -121,3 +120,21 @@ pub fn hoop() -> std::io::Result<()> { Ok(()) } + +pub fn freq() -> std::io::Result<()> { + let mut translator = Translator::new(); + + let mut path = env::current_dir()?; + // file to read is inside testing/ + path = path.join("testing/first.system"); + let system = read_system(&mut translator, path)?; + + let res = match frequency::naive_frequency(&system) { + Ok(f) => f, + Err(e) => {println!("Error computing target: {e}"); return Ok(());} + }; + + println!("Frequency of encountered symbols:\n{}", WithTranslator::from_Frequency(&translator, &res)); + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index b985a7d..0ecfb0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,20 @@ -#![allow(unused_imports)] mod rsprocess; mod examples; -use std::{hash::Hash, rc::Rc}; -use rsprocess::translator::WithTranslator; - -lalrpop_util::lalrpop_mod!(#[allow(clippy::uninlined_format_args)] pub grammar, "/rsprocess/grammar.rs"); +lalrpop_util::lalrpop_mod!( + #[allow(clippy::uninlined_format_args)] pub grammar, // name of module + "/rsprocess/grammar.rs" // location of parser +); fn main() -> std::io::Result<()> { - // let now = std::time::Instant::now(); // std::thread::sleep(std::time::Duration::new(2, 0)); // println!("{}", now.elapsed().as_micros()); examples::stats()?; + examples::freq()?; + examples::hoop()?; examples::target()?; diff --git a/src/rsprocess/confluence.rs b/src/rsprocess/confluence.rs index 2ce83df..f5ef28b 100644 --- a/src/rsprocess/confluence.rs +++ b/src/rsprocess/confluence.rs @@ -2,9 +2,6 @@ use super::perpetual::{ lollipops_decomposed_named, - lollipops_named, - lollipops_only_loop_decomposed, - lollipops_only_loop_decomposed_named, lollipops_prefix_len_loop_decomposed, lollipops_prefix_len_loop_decomposed_named }; @@ -85,19 +82,20 @@ pub fn invariant_named( symb: IdType ) -> Option<(Vec, Vec)> { let (prefix, hoop) = lollipops_decomposed_named(delta, - reaction_rules, - entities.first()?, - symb)?; + reaction_rules, + entities.first()?, + symb)?; let mut invariant = vec![]; invariant.append(&mut prefix.clone()); invariant.append(&mut hoop.clone()); let dimension = hoop.len(); for available_entities in entities { - let (new_prefix, new_hoop) = lollipops_decomposed_named(delta, - reaction_rules, - available_entities, - symb)?; + let (new_prefix, new_hoop) = + lollipops_decomposed_named(delta, + reaction_rules, + available_entities, + symb)?; if new_hoop.len() != dimension || !hoop.contains(new_hoop.first()?) { return None } diff --git a/src/rsprocess/frequency.rs b/src/rsprocess/frequency.rs index 9b64114..d387cff 100644 --- a/src/rsprocess/frequency.rs +++ b/src/rsprocess/frequency.rs @@ -3,90 +3,83 @@ 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::perpetual::lollipops_only_loop_named; +use super::structure::{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 + pub frequency_map: HashMap>, + pub totals: Vec, + pub weights: Vec } impl Frequency { - pub fn new(weight: u32) -> Self { - Frequency { frequency_map: HashMap::new(), total_runs: 0, weight } + pub fn new() -> Self { + Frequency { frequency_map: HashMap::new(), totals: vec![], weights: vec![] } } - pub fn add(&mut self, e: &RSset) { + pub fn add(&mut self, e: &RSset, run: usize) { for &el in e.iter() { - *self.frequency_map.entry(el).or_default() += 1 + self.frequency_map.entry(el).or_insert(vec![0; run+1])[run] += 1 } - self.total_runs += 1 + self.totals[run] += 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; + pub 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() } } // ----------------------------------------------------------------------------- -// see naiveFreq +// see naiveFreq, assume the system is finite, calculate the frequency of +// each symbol in all traversed states 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); + let mut freq = Frequency::new(); + freq.append_weight(1); - es.iter().for_each(|e| freq.add(e)); + es.iter().for_each(|e| freq.add(e, 0)); 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); +// see loopFreq, assume the system stabilizes in a loop, calculate the frequency +// of each symbol in all states of the loop +pub fn loop_frequency(system: &RSsystem, symb: IdType) -> Frequency { + let mut freq = Frequency::new(); + freq.append_weight(1); if let Some(hoop) = lollipops_only_loop_named(system.clone(), symb) { - hoop.iter().for_each(|e| freq.add(e)); + hoop.iter().for_each(|e| freq.add(e, 0)); } freq } -// see limitFreq +// see limitFreq, q[i] is given enough times such that the stabilizes in a loop, +// calculate the frequency of the symbols in any state in the last loop pub fn limit_frequency( q: &[RSset], reaction_rules: &[RSreaction], - available_entities: &RSset, - weight: u32 + available_entities: &RSset ) -> 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, @@ -94,19 +87,21 @@ pub fn limit_frequency( available_entities = res.into_iter().next()?; } - let mut freq = Frequency::new(weight); + let mut freq = Frequency::new(); + freq.append_weight(1); lollipops_only_loop_decomposed_q(q.last().unwrap(), reaction_rules, &available_entities) - .iter().for_each(|e| freq.add(e)); + .iter().for_each(|e| freq.add(e, 0)); Some(freq) } -// see fastFreq +// see fastFreq, q[i] is given enough times such that the stabilizes in a loop, +// calculate the frequency of the symbols in any state in any loop, weighted. pub fn fast_frequency( - q: &[&[RSset]], + q: &[RSset], reaction_rules: &[RSreaction], available_entities: &RSset, weights: &[u32] @@ -114,24 +109,15 @@ pub fn fast_frequency( // 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); + let mut freq = Frequency::new(); - 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); + for (pos, (q, &w)) in q.iter().zip(weights).enumerate() { + freq.append_weight(w); + let hoop = lollipops_only_loop_decomposed_q(q, + reaction_rules, + &available_entities); + hoop.iter().for_each(|e| freq.add(e, pos)); + available_entities = hoop.into_iter().next()?; } Some(freq) } diff --git a/src/rsprocess/perpetual.rs b/src/rsprocess/perpetual.rs index 63da4a4..018c698 100644 --- a/src/rsprocess/perpetual.rs +++ b/src/rsprocess/perpetual.rs @@ -1,6 +1,5 @@ #![allow(dead_code)] -use std::rc::Rc; use super::classical::compute_all_owned; use super::translator::IdType; use super::structure::{RSenvironment, RSprocess, RSreaction, RSset, RSsystem}; diff --git a/src/rsprocess/structure.rs b/src/rsprocess/structure.rs index 811601a..cdd083b 100644 --- a/src/rsprocess/structure.rs +++ b/src/rsprocess/structure.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] -use std::collections::{BTreeSet, HashMap, HashSet, VecDeque}; -use std::hash::{Hash, Hasher}; +use std::collections::{BTreeSet, HashMap, VecDeque}; +use std::hash::Hash; use std::rc::Rc; use super::translator::{IdType}; diff --git a/src/rsprocess/translator.rs b/src/rsprocess/translator.rs index 04ac2be..42517e8 100644 --- a/src/rsprocess/translator.rs +++ b/src/rsprocess/translator.rs @@ -47,7 +47,7 @@ impl Translator { } // ----------------------------------------------------------------------------- -use super::{frequency::{self, Frequency}, structure::{ +use super::{frequency::Frequency, structure::{ RSassert, RSassertOp, RSchoices, RSenvironment, RSlabel, RSprocess, RSreaction, RSset, RSsystem, RSBHML, }}; @@ -385,17 +385,35 @@ fn print_frequency( frequency: &Frequency, ) -> fmt::Result { write!(f, "[")?; - let mut it = frequency.frequency_map.iter().peekable(); + let mut freq_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))?; + while let Some((e, freq)) = freq_it.next() { + write!(f, "{} -> ", translator.decode(*e))?; + + let mut iter = freq.iter() + .zip(frequency.totals.iter() + .zip(frequency.weights.iter())) + .peekable(); + + let mut total_freq = 0.; + + while let Some((freq_e, (total, weight))) = iter.next() { + let weighted_freq = (*freq_e as f32 * *weight as f32 * 100.)/(*total as f32); + + if iter.peek().is_none() { + write!(f, "{weighted_freq:.2}")?; + } else { + write!(f, "{weighted_freq:.2}, ")?; + } + total_freq += weighted_freq; + } + + total_freq /= frequency.total_weights() as f32; + + write!(f, "(total: {total_freq:.2})")?; + + if freq_it.peek().is_some() { + writeln!(f, ",")?; } } write!(f, "]")