2025-07-09 19:34:15 +02:00
|
|
|
//! Module for translation and keeping track of strings.
|
2025-07-10 15:02:14 +02:00
|
|
|
|
2025-07-03 11:09:58 +02:00
|
|
|
use std::{cmp::max, collections::HashMap};
|
2025-07-09 21:44:04 +02:00
|
|
|
use serde::{Serialize, Deserialize};
|
2025-07-03 11:09:58 +02:00
|
|
|
|
2025-07-09 19:34:15 +02:00
|
|
|
/// precision for printing frequencies
|
2025-07-03 11:09:58 +02:00
|
|
|
static PRECISION: &usize = &2;
|
2025-06-16 14:46:04 +02:00
|
|
|
|
|
|
|
|
pub type IdType = u32;
|
|
|
|
|
|
2025-07-10 15:02:14 +02:00
|
|
|
/// Structure that keeps track of association string and id. Ids given
|
|
|
|
|
/// sequentially from 0.
|
2025-07-09 21:44:04 +02:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
2025-06-16 14:46:04 +02:00
|
|
|
pub struct Translator {
|
|
|
|
|
strings: HashMap<String, IdType>,
|
2025-06-18 11:28:04 +02:00
|
|
|
reverse: HashMap<IdType, String>,
|
|
|
|
|
last_id: IdType,
|
2025-06-16 14:46:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Translator {
|
|
|
|
|
pub fn new() -> Self {
|
2025-06-18 11:28:04 +02:00
|
|
|
Translator {
|
|
|
|
|
strings: HashMap::new(),
|
2025-06-19 23:48:16 +02:00
|
|
|
reverse: HashMap::new(),
|
2025-06-18 11:28:04 +02:00
|
|
|
last_id: 0,
|
|
|
|
|
}
|
2025-06-16 14:46:04 +02:00
|
|
|
}
|
2025-06-18 11:28:04 +02:00
|
|
|
}
|
2025-06-16 14:46:04 +02:00
|
|
|
|
2025-07-01 04:04:13 +02:00
|
|
|
impl Default for Translator {
|
|
|
|
|
fn default() -> Self {
|
2025-07-01 19:22:50 +02:00
|
|
|
Translator::new()
|
2025-07-01 04:04:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-18 11:28:04 +02:00
|
|
|
impl Translator {
|
2025-07-09 19:34:15 +02:00
|
|
|
/// converts a string into an id
|
2025-06-18 11:28:04 +02:00
|
|
|
pub fn encode(&mut self, s: impl Into<String>) -> IdType {
|
2025-06-19 23:48:16 +02:00
|
|
|
let s = s.into();
|
|
|
|
|
let id = *(self.strings.entry(s.clone()).or_insert({
|
2025-06-18 11:28:04 +02:00
|
|
|
self.last_id += 1;
|
|
|
|
|
self.last_id
|
|
|
|
|
}));
|
2025-06-19 23:48:16 +02:00
|
|
|
self.reverse.insert(id, s.clone());
|
|
|
|
|
id
|
2025-06-18 11:28:04 +02:00
|
|
|
}
|
2025-06-16 14:46:04 +02:00
|
|
|
|
2025-07-09 19:34:15 +02:00
|
|
|
/// converts an id into the corresponding string
|
2025-07-02 07:30:05 +02:00
|
|
|
pub fn decode(&self, el: IdType) -> Option<String> {
|
2025-06-19 23:48:16 +02:00
|
|
|
self.reverse
|
|
|
|
|
.get(&el)
|
|
|
|
|
.map(|x| x.to_string())
|
2025-06-18 11:28:04 +02:00
|
|
|
}
|
2025-06-16 14:46:04 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// print structures
|
2025-06-18 11:28:04 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
2025-07-01 19:22:50 +02:00
|
|
|
use super::{
|
|
|
|
|
frequency::Frequency,
|
|
|
|
|
structure::{
|
|
|
|
|
RSBHML, RSassert, RSassertOp, RSchoices, RSenvironment, RSlabel,
|
|
|
|
|
RSprocess, RSreaction, RSset, RSsystem,
|
|
|
|
|
},
|
|
|
|
|
};
|
2025-06-18 11:28:04 +02:00
|
|
|
use std::fmt;
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
macro_rules! translator_structure {
|
|
|
|
|
($name:ident, $type:ty, $dataname:ident, $print_func:ident) => {
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub struct $name<'a> {
|
|
|
|
|
translator: &'a Translator,
|
|
|
|
|
$dataname: &'a $type,
|
2025-06-19 23:48:16 +02:00
|
|
|
}
|
2025-07-02 10:37:29 +02:00
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
impl <'a>$name<'a> {
|
|
|
|
|
pub fn from(translator: &'a Translator, $dataname: &'a $type) -> Self {
|
|
|
|
|
$name { translator, $dataname }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> fmt::Display for $name<'a> {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
$print_func(f, self.translator, self.$dataname)
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-18 11:28:04 +02:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
// RSset
|
2025-06-18 11:28:04 +02:00
|
|
|
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_set(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
set: &RSset
|
|
|
|
|
) -> fmt::Result {
|
2025-06-18 11:28:04 +02:00
|
|
|
write!(f, "{{")?;
|
2025-07-01 04:04:13 +02:00
|
|
|
let mut it = set.iter().peekable();
|
2025-06-18 11:28:04 +02:00
|
|
|
while let Some(el) = it.next() {
|
2025-06-19 23:48:16 +02:00
|
|
|
if it.peek().is_none() {
|
2025-07-02 07:30:05 +02:00
|
|
|
write!(f,
|
|
|
|
|
"{}",
|
|
|
|
|
translator.decode(*el).unwrap_or("Missing".into()))?;
|
2025-06-19 23:48:16 +02:00
|
|
|
} else {
|
2025-07-02 07:30:05 +02:00
|
|
|
write!(f,
|
|
|
|
|
"{}, ",
|
|
|
|
|
translator.decode(*el).unwrap_or("Missing".into()))?;
|
2025-06-19 23:48:16 +02:00
|
|
|
}
|
2025-06-18 11:28:04 +02:00
|
|
|
}
|
|
|
|
|
write!(f, "}}")
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSsetDisplay, RSset, set, print_set);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RSreaction
|
|
|
|
|
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_reaction(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
reaction: &RSreaction,
|
|
|
|
|
) -> fmt::Result {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"(r: {}, i: {}, p: {})",
|
2025-07-09 16:12:22 +02:00
|
|
|
RSsetDisplay::from(translator, &reaction.reactants),
|
|
|
|
|
RSsetDisplay::from(translator, &reaction.inihibitors),
|
|
|
|
|
RSsetDisplay::from(translator, &reaction.products)
|
2025-06-19 23:48:16 +02:00
|
|
|
)
|
2025-06-18 11:28:04 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSreactionDisplay, RSreaction, reaction, print_reaction);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RSprocess
|
|
|
|
|
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_process(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
process: &RSprocess,
|
|
|
|
|
) -> fmt::Result {
|
2025-06-18 11:28:04 +02:00
|
|
|
use super::structure::RSprocess::*;
|
|
|
|
|
match process {
|
2025-06-19 23:48:16 +02:00
|
|
|
Nill => {
|
2025-07-05 14:54:43 +02:00
|
|
|
write!(f, "Nill")
|
2025-06-19 23:48:16 +02:00
|
|
|
}
|
|
|
|
|
RecursiveIdentifier { identifier } => {
|
2025-07-02 07:30:05 +02:00
|
|
|
write!(f,
|
|
|
|
|
"[{}]",
|
|
|
|
|
translator.decode(*identifier).unwrap_or("Missing".into()))
|
2025-06-19 23:48:16 +02:00
|
|
|
}
|
|
|
|
|
EntitySet {
|
|
|
|
|
entities,
|
|
|
|
|
next_process,
|
|
|
|
|
} => {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
2025-07-05 14:54:43 +02:00
|
|
|
"{}.{}",
|
2025-07-02 10:37:29 +02:00
|
|
|
RSsetDisplay::from(translator, entities),
|
|
|
|
|
RSprocessDisplay::from(translator, next_process)
|
2025-06-19 23:48:16 +02:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
WaitEntity {
|
|
|
|
|
repeat,
|
|
|
|
|
repeated_process,
|
|
|
|
|
next_process,
|
|
|
|
|
} => {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
2025-07-05 14:54:43 +02:00
|
|
|
"({})^{repeat}.{}",
|
2025-07-02 10:37:29 +02:00
|
|
|
RSprocessDisplay::from(translator, repeated_process),
|
|
|
|
|
RSprocessDisplay::from(translator, next_process)
|
2025-06-19 23:48:16 +02:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
Summation { children } => {
|
|
|
|
|
write!(f, "[")?;
|
|
|
|
|
let mut it = children.iter().peekable();
|
|
|
|
|
while let Some(child) = it.next() {
|
|
|
|
|
if it.peek().is_none() {
|
2025-07-01 19:22:50 +02:00
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"{}",
|
2025-07-02 10:37:29 +02:00
|
|
|
RSprocessDisplay::from(translator, child)
|
2025-07-01 19:22:50 +02:00
|
|
|
)?;
|
2025-06-19 23:48:16 +02:00
|
|
|
} else {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"{} + ",
|
2025-07-02 10:37:29 +02:00
|
|
|
RSprocessDisplay::from(translator, child)
|
2025-06-19 23:48:16 +02:00
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
write!(f, "]")
|
|
|
|
|
}
|
|
|
|
|
NondeterministicChoice { children } => {
|
|
|
|
|
write!(f, "[")?;
|
|
|
|
|
let mut it = children.iter().peekable();
|
|
|
|
|
while let Some(child) = it.next() {
|
|
|
|
|
if it.peek().is_none() {
|
2025-07-01 19:22:50 +02:00
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"{}",
|
2025-07-02 10:37:29 +02:00
|
|
|
RSprocessDisplay::from(translator, child)
|
2025-07-01 19:22:50 +02:00
|
|
|
)?;
|
2025-06-19 23:48:16 +02:00
|
|
|
} else {
|
2025-07-01 19:22:50 +02:00
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"{}, ",
|
2025-07-02 10:37:29 +02:00
|
|
|
RSprocessDisplay::from(translator, child)
|
2025-07-01 19:22:50 +02:00
|
|
|
)?;
|
2025-06-19 23:48:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
write!(f, "]")
|
|
|
|
|
}
|
2025-06-18 11:28:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSprocessDisplay, RSprocess, process, print_process);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RSchoices
|
|
|
|
|
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_choices(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
choices: &RSchoices,
|
|
|
|
|
) -> fmt::Result {
|
2025-06-18 11:28:04 +02:00
|
|
|
write!(f, "[")?;
|
|
|
|
|
let mut it = choices.iter().peekable();
|
|
|
|
|
while let Some(el) = it.next() {
|
2025-06-19 23:48:16 +02:00
|
|
|
if it.peek().is_none() {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"[set: {}, process: {}]",
|
2025-07-02 10:37:29 +02:00
|
|
|
RSsetDisplay::from(translator, &el.0),
|
|
|
|
|
RSprocessDisplay::from(translator, &el.1)
|
2025-06-19 23:48:16 +02:00
|
|
|
)?;
|
|
|
|
|
} else {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"[set: {}, process: {}], ",
|
2025-07-02 10:37:29 +02:00
|
|
|
RSsetDisplay::from(translator, &el.0),
|
|
|
|
|
RSprocessDisplay::from(translator, &el.1)
|
2025-06-19 23:48:16 +02:00
|
|
|
)?;
|
|
|
|
|
}
|
2025-06-16 14:46:04 +02:00
|
|
|
}
|
2025-06-18 11:28:04 +02:00
|
|
|
write!(f, "]")
|
2025-06-16 14:46:04 +02:00
|
|
|
}
|
2025-06-18 11:28:04 +02:00
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSchoicesDisplay, RSchoices, choices, print_choices);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RSenvironment
|
|
|
|
|
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_environment(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
environment: &RSenvironment,
|
|
|
|
|
) -> fmt::Result {
|
2025-06-18 11:28:04 +02:00
|
|
|
write!(f, "{{env:")?;
|
|
|
|
|
let mut it = environment.iter().peekable();
|
|
|
|
|
while let Some(el) = it.next() {
|
2025-06-19 23:48:16 +02:00
|
|
|
if it.peek().is_none() {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"({} -> {})",
|
2025-07-02 07:30:05 +02:00
|
|
|
translator.decode(*el.0).unwrap_or("Missing".into()),
|
2025-07-02 10:37:29 +02:00
|
|
|
RSprocessDisplay::from(translator, el.1)
|
2025-06-19 23:48:16 +02:00
|
|
|
)?;
|
|
|
|
|
} else {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"({} -> {}), ",
|
2025-07-02 07:30:05 +02:00
|
|
|
translator.decode(*el.0).unwrap_or("Missing".into()),
|
2025-07-02 10:37:29 +02:00
|
|
|
RSprocessDisplay::from(translator, el.1)
|
2025-06-19 23:48:16 +02:00
|
|
|
)?;
|
|
|
|
|
}
|
2025-06-18 11:28:04 +02:00
|
|
|
}
|
|
|
|
|
write!(f, "}}")
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSenvironmentDisplay, RSenvironment, environment, print_environment);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RSsystem
|
|
|
|
|
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_system(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
system: &RSsystem
|
|
|
|
|
) -> fmt::Result {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"[delta: {}, available_entities: {}, context_process: {}, reaction_rules: [",
|
2025-07-09 16:12:22 +02:00
|
|
|
RSenvironmentDisplay::from(translator, &system.delta),
|
|
|
|
|
RSsetDisplay::from(translator, &system.available_entities),
|
|
|
|
|
RSprocessDisplay::from(translator, &system.context_process)
|
2025-06-18 11:28:04 +02:00
|
|
|
)?;
|
2025-07-09 16:12:22 +02:00
|
|
|
let mut it = system.reaction_rules.iter().peekable();
|
2025-06-18 11:28:04 +02:00
|
|
|
while let Some(el) = it.next() {
|
2025-06-19 23:48:16 +02:00
|
|
|
if it.peek().is_none() {
|
2025-07-02 10:37:29 +02:00
|
|
|
write!(f, "{}", RSreactionDisplay::from(translator, el))?;
|
2025-06-19 23:48:16 +02:00
|
|
|
} else {
|
2025-07-02 10:37:29 +02:00
|
|
|
write!(f, "{}, ", RSreactionDisplay::from(translator, el))?;
|
2025-06-19 23:48:16 +02:00
|
|
|
}
|
2025-06-18 11:28:04 +02:00
|
|
|
}
|
|
|
|
|
write!(f, "] ]")
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSsystemDisplay, RSsystem, system, print_system);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RSlabel
|
|
|
|
|
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_label(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
label: &RSlabel
|
|
|
|
|
) -> fmt::Result {
|
2025-07-01 19:22:50 +02:00
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"{{available_entities: {}, context: {}, t: {}, reactants: {}, reactantsi: {}, inihibitors: {}, ireactants: {}, products: {}}}",
|
2025-07-02 10:37:29 +02:00
|
|
|
RSsetDisplay::from(translator, &label.available_entities),
|
|
|
|
|
RSsetDisplay::from(translator, &label.context),
|
|
|
|
|
RSsetDisplay::from(translator, &label.t),
|
|
|
|
|
RSsetDisplay::from(translator, &label.reactants),
|
2025-07-09 16:12:22 +02:00
|
|
|
RSsetDisplay::from(translator, &label.reactants_absent),
|
2025-07-02 10:37:29 +02:00
|
|
|
RSsetDisplay::from(translator, &label.inihibitors),
|
2025-07-09 16:12:22 +02:00
|
|
|
RSsetDisplay::from(translator, &label.inihibitors_present),
|
2025-07-02 10:37:29 +02:00
|
|
|
RSsetDisplay::from(translator, &label.products),
|
2025-06-18 11:28:04 +02:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSlabelDisplay, RSlabel, label, print_label);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RSassertOp
|
|
|
|
|
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_assert_op(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
_translator: &Translator,
|
|
|
|
|
assert_op: &RSassertOp,
|
|
|
|
|
) -> fmt::Result {
|
2025-06-18 11:28:04 +02:00
|
|
|
use super::structure::RSassertOp::*;
|
|
|
|
|
match assert_op {
|
2025-06-19 23:48:16 +02:00
|
|
|
InW => {
|
|
|
|
|
write!(f, "InW")
|
|
|
|
|
}
|
|
|
|
|
InR => {
|
|
|
|
|
write!(f, "InR")
|
|
|
|
|
}
|
|
|
|
|
InI => {
|
|
|
|
|
write!(f, "InI")
|
|
|
|
|
}
|
|
|
|
|
InP => {
|
|
|
|
|
write!(f, "InP")
|
|
|
|
|
}
|
2025-06-18 11:28:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSassertOpDisplay, RSassertOp, assert_op, print_assert_op);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RSassert
|
|
|
|
|
|
2025-06-18 11:28:04 +02:00
|
|
|
#[allow(unused_variables)]
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_assert(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
assert: &RSassert
|
|
|
|
|
) -> fmt::Result {
|
2025-06-18 11:28:04 +02:00
|
|
|
todo!()
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSassertDisplay, RSassert, assert, print_assert);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RSBHML
|
|
|
|
|
|
2025-06-18 11:28:04 +02:00
|
|
|
#[allow(unused_variables)]
|
2025-06-19 23:48:16 +02:00
|
|
|
fn print_bhml(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
bhml: &RSBHML
|
|
|
|
|
) -> fmt::Result {
|
2025-06-18 11:28:04 +02:00
|
|
|
todo!()
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(RSBHMLDisplay, RSBHML, bhml, print_bhml);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Frequency
|
|
|
|
|
|
2025-06-24 18:56:04 +02:00
|
|
|
fn print_frequency(
|
|
|
|
|
f: &mut fmt::Formatter,
|
|
|
|
|
translator: &Translator,
|
|
|
|
|
frequency: &Frequency,
|
|
|
|
|
) -> fmt::Result {
|
|
|
|
|
write!(f, "[")?;
|
2025-07-01 18:00:27 +02:00
|
|
|
let mut freq_it = frequency.frequency_map.iter().peekable();
|
|
|
|
|
|
2025-07-03 11:09:58 +02:00
|
|
|
let totals = &frequency.totals;
|
|
|
|
|
let weights = &frequency.weights;
|
|
|
|
|
|
2025-07-01 18:00:27 +02:00
|
|
|
while let Some((e, freq)) = freq_it.next() {
|
2025-07-02 07:30:05 +02:00
|
|
|
write!(f, "{} -> ", translator.decode(*e).unwrap_or("Missing".into()))?;
|
2025-07-01 18:00:27 +02:00
|
|
|
|
2025-07-01 19:22:50 +02:00
|
|
|
let mut total_freq = 0.;
|
2025-07-01 18:00:27 +02:00
|
|
|
|
2025-07-03 11:09:58 +02:00
|
|
|
let end = max(freq.len(), max(totals.len(), weights.len()));
|
2025-07-01 18:00:27 +02:00
|
|
|
|
2025-07-03 11:09:58 +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;
|
|
|
|
|
|
|
|
|
|
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-07-01 19:22:50 +02:00
|
|
|
|
|
|
|
|
total_freq /= frequency.total_weights() as f32;
|
2025-07-01 18:00:27 +02:00
|
|
|
|
2025-07-03 11:09:58 +02:00
|
|
|
#[allow(clippy::uninlined_format_args)]
|
|
|
|
|
write!(f, " (total: {total_freq:.*})", PRECISION)?;
|
2025-07-01 18:00:27 +02:00
|
|
|
|
2025-07-01 19:22:50 +02:00
|
|
|
if freq_it.peek().is_some() {
|
|
|
|
|
writeln!(f, ",")?;
|
|
|
|
|
}
|
2025-06-24 18:56:04 +02:00
|
|
|
}
|
|
|
|
|
write!(f, "]")
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 10:37:29 +02:00
|
|
|
translator_structure!(FrequencyDisplay, Frequency, frequency, print_frequency);
|
|
|
|
|
|