2025-07-10 15:02:14 +02:00
|
|
|
//! Definitions and structure for frequency of elements in a simulation
|
|
|
|
|
|
2025-07-01 19:22:50 +02:00
|
|
|
use std::collections::HashMap;
|
2025-09-05 13:13:35 +02:00
|
|
|
use std::fmt::Debug;
|
|
|
|
|
|
|
|
|
|
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};
|
2025-09-07 17:55:53 +02:00
|
|
|
use super::translator::{Formatter, PRECISION, PrintableWithTranslator, Translator};
|
2025-09-05 13:13:35 +02:00
|
|
|
|
|
|
|
|
pub trait BasicFrequency: Debug + Clone + Default + PrintableWithTranslator {
|
|
|
|
|
type Set: BasicSet;
|
2025-09-07 17:55:53 +02:00
|
|
|
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>;
|
2025-09-05 13:13:35 +02:00
|
|
|
type R: BasicReaction<Set = Self::Set>;
|
|
|
|
|
type Id;
|
|
|
|
|
|
|
|
|
|
fn naive_frequency(system: &Self::Sys) -> Result<Self, String>;
|
|
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
fn loop_frequency(system: &Self::Sys, symb: Self::Id) -> Self;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
fn limit_frequency(
|
|
|
|
|
q: &[Self::Set],
|
|
|
|
|
reactions: &[Self::R],
|
|
|
|
|
available_entities: &Self::Set,
|
|
|
|
|
) -> Option<Self>;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
fn fast_frequency(
|
|
|
|
|
q: &[Self::Set],
|
|
|
|
|
reactions: &[Self::R],
|
|
|
|
|
available_entities: &Self::Set,
|
|
|
|
|
weights: &[u32],
|
|
|
|
|
) -> Option<Self>;
|
2025-09-05 13:13:35 +02:00
|
|
|
}
|
2025-06-24 18:56:04 +02:00
|
|
|
|
2025-09-05 13:13:35 +02:00
|
|
|
/// Structure that holds the frequency of elements of a run or multiple runs,
|
2025-07-10 15:02:14 +02:00
|
|
|
/// weighted. To print use ```translator::FrequencyDisplay```.
|
2025-09-05 13:13:35 +02:00
|
|
|
#[derive(Debug, Clone, Default)]
|
2025-06-24 18:56:04 +02:00
|
|
|
pub struct Frequency {
|
2025-07-01 18:00:27 +02:00
|
|
|
pub frequency_map: HashMap<IdType, Vec<u32>>,
|
|
|
|
|
pub totals: Vec<usize>,
|
2025-07-01 19:22:50 +02:00
|
|
|
pub weights: Vec<u32>,
|
2025-06-24 18:56:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Frequency {
|
2025-09-05 13:13:35 +02:00
|
|
|
fn add(&mut self, e: Set, run: usize) {
|
2025-09-07 17:55:53 +02:00
|
|
|
for el in e.iter() {
|
|
|
|
|
let entry = self.frequency_map.entry(*el).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
|
2025-06-24 18:56:04 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-05 13:13:35 +02:00
|
|
|
fn append_weight(&mut self, new_weight: u32) {
|
2025-09-07 17:55:53 +02:00
|
|
|
self.weights.push(new_weight)
|
2025-07-01 18:00:27 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-05 13:13:35 +02:00
|
|
|
fn total_weights(&self) -> u32 {
|
2025-09-07 17:55:53 +02:00
|
|
|
self.weights.iter().sum()
|
2025-06-24 18:56:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-24 02:01:24 +02:00
|
|
|
impl PrintableWithTranslator for Frequency {
|
2025-09-07 17:55:53 +02:00
|
|
|
fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result {
|
|
|
|
|
use std::cmp::max;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
write!(f, "[")?;
|
|
|
|
|
let mut freq_it = self.frequency_map.iter().peekable();
|
2025-08-24 02:01:24 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
let totals = &self.totals;
|
|
|
|
|
let weights = &self.weights;
|
2025-08-24 02:01:24 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
while let Some((e, freq)) = freq_it.next() {
|
|
|
|
|
write!(f, "{} -> ", Formatter::from(translator, e))?;
|
2025-08-24 02:01:24 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
let mut total_freq = 0.;
|
2025-08-24 02:01:24 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
let end = max(freq.len(), max(totals.len(), weights.len()));
|
2025-08-24 02:01:24 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
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;
|
2025-08-24 02:01:24 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2025-08-24 02:01:24 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
total_freq /= self.total_weights() as f32;
|
2025-08-24 02:01:24 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
#[allow(clippy::uninlined_format_args)]
|
|
|
|
|
write!(f, " (total: {total_freq:.*})", PRECISION)?;
|
2025-08-24 02:01:24 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
if freq_it.peek().is_some() {
|
|
|
|
|
writeln!(f, ",")?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
write!(f, "]")
|
2025-08-24 02:01:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-05 13:13:35 +02:00
|
|
|
impl BasicFrequency for Frequency {
|
|
|
|
|
type Set = Set;
|
|
|
|
|
type Sys = System;
|
|
|
|
|
type Env = Environment;
|
|
|
|
|
type R = Reaction;
|
|
|
|
|
type Id = IdType;
|
2025-06-24 18:56:04 +02:00
|
|
|
|
2025-08-23 23:40:19 +02:00
|
|
|
/// Assuming the system is finite, calculates the frequency of each symbol
|
|
|
|
|
/// in all traversed states.
|
|
|
|
|
/// see naiveFreq
|
2025-09-05 13:13:35 +02:00
|
|
|
fn naive_frequency(system: &Self::Sys) -> Result<Self, String> {
|
2025-09-07 17:55:53 +02:00
|
|
|
let ect = system.run_separated()?;
|
2025-06-24 18:56:04 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
let mut freq = Self::default();
|
|
|
|
|
freq.append_weight(1);
|
2025-06-24 18:56:04 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
ect.into_iter().for_each(|(e, _, _)| freq.add(e, 0));
|
2025-06-24 18:56:04 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
Ok(freq)
|
2025-06-24 18:56:04 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-23 23:40:19 +02:00
|
|
|
/// Assume the system stabilizes in a loop, calculates the frequency of each
|
|
|
|
|
/// symbol in all states of the loop.
|
|
|
|
|
/// see loopFreq
|
2025-09-05 13:13:35 +02:00
|
|
|
fn loop_frequency(system: &Self::Sys, symb: Self::Id) -> Self {
|
2025-09-07 17:55:53 +02:00
|
|
|
let mut freq = Self::default();
|
|
|
|
|
freq.append_weight(1);
|
2025-08-23 23:40:19 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
if let Some(hoop) = system.lollipops_only_loop_named(symb) {
|
|
|
|
|
hoop.iter().for_each(|e| freq.add(e.clone(), 0));
|
|
|
|
|
}
|
|
|
|
|
freq
|
2025-06-24 18:56:04 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-23 23:40:19 +02:00
|
|
|
/// 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
|
2025-09-05 13:13:35 +02:00
|
|
|
fn limit_frequency(
|
2025-09-07 17:55:53 +02:00
|
|
|
q: &[Self::Set],
|
|
|
|
|
reaction_rules: &[Self::R],
|
|
|
|
|
available_entities: &Self::Set,
|
2025-08-23 23:40:19 +02:00
|
|
|
) -> Option<Self> {
|
2025-09-07 17:55:53 +02:00
|
|
|
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)
|
2025-09-05 13:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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(
|
2025-09-07 17:55:53 +02:00
|
|
|
q: &[Self::Set],
|
|
|
|
|
reaction_rules: &[Self::R],
|
|
|
|
|
available_entities: &Self::Set,
|
|
|
|
|
weights: &[u32],
|
2025-09-05 13:13:35 +02:00
|
|
|
) -> Option<Self> {
|
2025-09-07 17:55:53 +02:00
|
|
|
// 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)
|
2025-09-05 13:13:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/// 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) {
|
2025-09-07 17:55:53 +02:00
|
|
|
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
|
2025-09-05 13:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn append_weight(&mut self, new_weight: u32) {
|
2025-09-07 17:55:53 +02:00
|
|
|
self.weights.push(new_weight)
|
2025-09-05 13:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn total_weights(&self) -> u32 {
|
2025-09-07 17:55:53 +02:00
|
|
|
self.weights.iter().sum()
|
2025-09-05 13:13:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PrintableWithTranslator for PositiveFrequency {
|
2025-09-07 17:55:53 +02:00
|
|
|
fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result {
|
|
|
|
|
use std::cmp::max;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
write!(f, "[")?;
|
|
|
|
|
let mut freq_it = self.frequency_map.iter().peekable();
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
let totals = &self.totals;
|
|
|
|
|
let weights = &self.weights;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
while let Some((e, freq)) = freq_it.next() {
|
|
|
|
|
write!(f, "{} -> ", Formatter::from(translator, e))?;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
let mut total_freq = 0.;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
let end = max(freq.len(), max(totals.len(), weights.len()));
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
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;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
total_freq /= self.total_weights() as f32;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
#[allow(clippy::uninlined_format_args)]
|
|
|
|
|
write!(f, " (total: {total_freq:.*})", PRECISION)?;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
if freq_it.peek().is_some() {
|
|
|
|
|
writeln!(f, ",")?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
write!(f, "]")
|
2025-09-05 13:13:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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> {
|
2025-09-07 17:55:53 +02:00
|
|
|
let ect = system.run_separated()?;
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
let mut freq = Self::default();
|
|
|
|
|
freq.append_weight(1);
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
ect.into_iter().for_each(|(e, _, _)| freq.add(e, 0));
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
Ok(freq)
|
2025-09-05 13:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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 {
|
2025-09-07 17:55:53 +02:00
|
|
|
let mut freq = Self::default();
|
|
|
|
|
freq.append_weight(1);
|
2025-09-05 13:13:35 +02:00
|
|
|
|
2025-09-07 17:55:53 +02:00
|
|
|
if let Some(hoop) = system.lollipops_only_loop_named(symb) {
|
|
|
|
|
hoop.iter().for_each(|e| freq.add(e.clone(), 0));
|
|
|
|
|
}
|
|
|
|
|
freq
|
2025-09-05 13:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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(
|
2025-09-07 17:55:53 +02:00
|
|
|
q: &[Self::Set],
|
|
|
|
|
reaction_rules: &[Self::R],
|
|
|
|
|
available_entities: &Self::Set,
|
2025-09-05 13:13:35 +02:00
|
|
|
) -> Option<Self> {
|
2025-09-07 17:55:53 +02:00
|
|
|
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)
|
2025-08-23 23:40:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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
|
2025-09-05 13:13:35 +02:00
|
|
|
fn fast_frequency(
|
2025-09-07 17:55:53 +02:00
|
|
|
q: &[Self::Set],
|
|
|
|
|
reaction_rules: &[Self::R],
|
|
|
|
|
available_entities: &Self::Set,
|
|
|
|
|
weights: &[u32],
|
2025-08-23 23:40:19 +02:00
|
|
|
) -> Option<Self> {
|
2025-09-07 17:55:53 +02:00
|
|
|
// 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)
|
2025-06-24 18:56:04 +02:00
|
|
|
}
|
|
|
|
|
}
|