Starting to convert main_do, statistics, frequency not working

frequency not working, also need to look into perpetual better
This commit is contained in:
elvis
2025-07-01 04:04:13 +02:00
parent 65d6c93424
commit 5af8cd98c2
9 changed files with 450 additions and 207 deletions

123
src/examples.rs Normal file
View File

@ -0,0 +1,123 @@
use crate::rsprocess::statistics;
use crate::rsprocess::structure::RSsystem;
use crate::rsprocess::transitions;
use crate::rsprocess::translator::Translator;
use crate::rsprocess::translator::WithTranslator;
use crate::rsprocess::perpetual;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::env;
// 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
) -> std::io::Result<RSsystem> {
// we read the file with a buffer
let f = fs::File::open(path.clone())?;
let mut buf_reader = io::BufReader::new(f);
let mut contents = String::new();
buf_reader.read_to_string(&mut contents)?;
// parse
let result = grammar::SystemParser::new().parse(translator, &contents).unwrap();
Ok(result)
}
// equivalent main_do(stat) or main_do(stat, MissingE)
pub fn stats() -> 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)?;
// print statistics to screan
println!("{}", statistics::of_RSsystem(&translator, &system));
// to write to file:
//// path = path.with_extension("stats");
//// let mut f = std::fs::File::create(path)?;
//// writeln!(f, "{}", statistics::of_RSsystem(translator, &result))?;
Ok(())
}
// equivalent to main_do(target, E)
pub fn target() -> 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)?;
// the system needs to terminate to return
let res = match transitions::target(&system) {
Ok(o) => o,
Err(e) => {println!("Error computing target: {e}"); return Ok(());}
};
println!("After {} steps we arrive at state:\n{}",
res.0,
WithTranslator::from_RSset(&translator, &res.1));
Ok(())
}
// equivalent to main_do(run,Es)
pub fn run() -> 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)?;
// the system needs to terminate to return
let res = match transitions::run_separated(&system) {
Ok(o) => o,
Err(e) => {println!("Error computing target: {e}"); return Ok(());}
};
println!("The trace is composed of the entities:");
for (e, _c, _t) in res {
println!("{}", WithTranslator::from_RSset(&translator, &e));
}
Ok(())
}
// equivalent to main_do(loop,Es)
pub fn hoop() -> 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)?;
// we retrieve the id for "x" and use it to find the corresponding loop
let res = match perpetual::lollipops_only_loop_named(system, translator.encode("x")) {
Some(o) => o,
None => {println!("No loop found."); return Ok(());}
};
println!("The loop is composed by the sets:");
for e in res {
println!("{}", WithTranslator::from_RSset(&translator, &e));
}
Ok(())
}

View File

@ -1,201 +1,25 @@
#![allow(unused_imports)]
mod rsprocess;
use lalrpop_util::lalrpop_mod;
mod examples;
use std::{hash::Hash, rc::Rc};
use rsprocess::translator::WithTranslator;
// use std::io;
fn main() -> Result<(), Box<dyn std::error::Error>> {
lalrpop_mod!(grammar, "/rsprocess/grammar.rs");
lalrpop_util::lalrpop_mod!(#[allow(clippy::uninlined_format_args)] pub grammar, "/rsprocess/grammar.rs");
let mut translator = rsprocess::translator::Translator::new();
fn main() -> std::io::Result<()> {
// let mut buffer = String::new();
// let i = io::stdin();
// i.read_line(&mut buffer).expect("Can't read stdin");
// let now = std::time::Instant::now();
// std::thread::sleep(std::time::Duration::new(2, 0));
// println!("{}", now.elapsed().as_micros());
// let result = grammar::SetParser::new().parse(&mut translator, &buffer).unwrap();
examples::stats()?;
examples::hoop()?;
// -------------------------------------------------------------------------
// let reactants = grammar::SetParser::new().parse(&mut translator, "{a}").unwrap();
// let inihibitors = grammar::SetParser::new().parse(&mut translator, "{c}").unwrap();
// let products = grammar::SetParser::new().parse(&mut translator, "{a,c}").unwrap();
examples::target()?;
// let process1 = rsprocess::structure::RSreaction::from(reactants, inihibitors, products);
examples::run()?;
// let reactants = grammar::SetParser::new().parse(&mut translator, "{b}").unwrap();
// let inihibitors = grammar::SetParser::new().parse(&mut translator, "{c}").unwrap();
// let products = grammar::SetParser::new().parse(&mut translator, "{b,c}").unwrap();
// let process2 = rsprocess::structure::RSreaction::from(reactants, inihibitors, products);
// let current_state = grammar::SetParser::new().parse(&mut translator, "{b}").unwrap();
// println!("{:?}", rsprocess::classical::compute_all(&current_state, vec![&process1, &process2]));
// -------------------------------------------------------------------------
// let env = grammar::EnvironmentParser::new().parse(&mut translator, "[x = {a}.{b}.x , y = ({a,c}.y + {b,c}.y)]").unwrap();
// let process = grammar::ContextParser::new().parse(&mut translator, "[({a}.nil + x + y)]").unwrap();
// println!("{:?}", rsprocess::transitions::unfold(&env, &process));
// println!("--------------------");
// println!("{:?}", env);
// -------------------------------------------------------------------------
// allTransitions(sys([],[a,b],[],[react([a],[c],[a]),react([b],[d],[b])]) , Moves).
// let env = grammar::EnvironmentParser::new().parse(&mut translator, "[]").unwrap();
// let process = grammar::ContextParser::new().parse(&mut translator, "[]").unwrap();
// let sys = rsprocess::structure::RSsystem::from(Rc::new(*env),
// rsprocess::structure::RSset::from(vec![translator.encode("a"),
// translator.encode("b")]),
// *process,
// Rc::new(vec![
// rsprocess::structure::RSreaction::from(
// rsprocess::structure::RSset::from(vec![translator.encode("a")]),
// rsprocess::structure::RSset::from(vec![translator.encode("c")]),
// rsprocess::structure::RSset::from(vec![translator.encode("a")])
// ),
// rsprocess::structure::RSreaction::from(
// rsprocess::structure::RSset::from(vec![translator.encode("b")]),
// rsprocess::structure::RSset::from(vec![translator.encode("d")]),
// rsprocess::structure::RSset::from(vec![translator.encode("b")])
// )
// ]));
// println!("all_transitions: {:?}", rsprocess::transitions::all_transitions(&sys));
// -------------------------------------------------------------------------
// parse_ctx("[({a}.nil + {b}.nil)]",Ks) , allTransitions(sys([],[],Ks,[react([a],[c],[a]),react([b],[d],[b])]),Moves).
// let env = grammar::EnvironmentParser::new().parse(&mut translator, "[]").unwrap();
// let process = grammar::ContextParser::new().parse(&mut translator, "[({a}.nil + {b}.nil)]").unwrap();
// let sys = rsprocess::structure::RSsystem::from(Rc::new(*env),
// rsprocess::structure::RSset::from(vec![]),
// *process,
// Rc::new(vec![
// rsprocess::structure::RSreaction::from(
// rsprocess::structure::RSset::from(vec![translator.encode("a")]),
// rsprocess::structure::RSset::from(vec![translator.encode("c")]),
// rsprocess::structure::RSset::from(vec![translator.encode("a")])
// ),
// rsprocess::structure::RSreaction::from(
// rsprocess::structure::RSset::from(vec![translator.encode("b")]),
// rsprocess::structure::RSset::from(vec![translator.encode("d")]),
// rsprocess::structure::RSset::from(vec![translator.encode("b")])
// )
// ]));
// println!("all_transitions: {:?}", rsprocess::transitions::all_transitions(&sys));
// -------------------------------------------------------------------------
// parse_ctx("[({a}.nil + {b}.nil),({c}.nil + {d}.nil)]",Ks) , allTransitions(sys([],[],Ks,[react([a],[c],[a]),react([b],[d],[b])]),Moves).
// let env = grammar::EnvironmentParser::new().parse(&mut translator, "[]").unwrap();
// let process = grammar::ContextParser::new().parse(&mut translator, "[({a}.nil + {b}.nil),({c}.nil + {d}.nil)]").unwrap();
// let sys = rsprocess::structure::RSsystem::from(Rc::new(*env),
// rsprocess::structure::RSset::from(vec![]),
// *process,
// Rc::new(vec![
// rsprocess::structure::RSreaction::from(
// rsprocess::structure::RSset::from(vec![translator.encode("a")]),
// rsprocess::structure::RSset::from(vec![translator.encode("c")]),
// rsprocess::structure::RSset::from(vec![translator.encode("a")])
// ),
// rsprocess::structure::RSreaction::from(
// rsprocess::structure::RSset::from(vec![translator.encode("b")]),
// rsprocess::structure::RSset::from(vec![translator.encode("d")]),
// rsprocess::structure::RSset::from(vec![translator.encode("b")])
// )
// ]));
// let it = rsprocess::transitions::iterator_transitions(&sys)?;
// for (n, i) in it.into_iter().enumerate() {
// println!("next i - {n}: {:?}", i);
// println!("--------------------");
// }
// -------------------------------------------------------------------------
// let env = grammar::EnvironmentParser::new().parse(&mut translator, "[]").unwrap();
// let process = grammar::ContextParser::new().parse(&mut translator, "[({a}.nil + {b}.nil),({c}.nil + {d}.nil)]").unwrap();
// let sys = rsprocess::structure::RSsystem::from(Rc::new(*env),
// rsprocess::structure::RSset::from(vec![]),
// *process,
// Rc::new(vec![
// rsprocess::structure::RSreaction::from(
// rsprocess::structure::RSset::from(vec![translator.encode("a")]),
// rsprocess::structure::RSset::from(vec![translator.encode("c")]),
// rsprocess::structure::RSset::from(vec![translator.encode("a")])
// ),
// rsprocess::structure::RSreaction::from(
// rsprocess::structure::RSset::from(vec![translator.encode("b")]),
// rsprocess::structure::RSset::from(vec![translator.encode("d")]),
// rsprocess::structure::RSset::from(vec![translator.encode("b")])
// )
// ]));
// println!("{:?}", rsprocess::transitions::run_separated(&sys));
// -------------------------------------------------------------------------
// list_to_assoc([x-pre([a, b], rec(x)), y-pre([d, e], rec(y))], Ass),
// lollipop(sys(Ass, [a, b, c, d], [], [react([a], [c], [a]), react([d], [f], [d])]), Prefix, Loop).
let env = grammar::EnvironmentParser::new().parse(&mut translator, "[x = {a,b}.x]").unwrap();
let process = grammar::ContextParser::new().parse(&mut translator, "[]").unwrap();
let sys = rsprocess::structure::RSsystem::from(Rc::new(*env),
rsprocess::structure::RSset::from(vec![translator.encode("a"),
translator.encode("b"),
translator.encode("c"),
translator.encode("d")]),
*process,
Rc::new(vec![
rsprocess::structure::RSreaction::from(
rsprocess::structure::RSset::from(vec![translator.encode("a")]),
rsprocess::structure::RSset::from(vec![translator.encode("c")]),
rsprocess::structure::RSset::from(vec![translator.encode("a")])
),
rsprocess::structure::RSreaction::from(
rsprocess::structure::RSset::from(vec![translator.encode("d")]),
rsprocess::structure::RSset::from(vec![translator.encode("f")]),
rsprocess::structure::RSset::from(vec![translator.encode("d")])
)
]));
let res = rsprocess::perpetual::lollipops(sys.clone());
println!("res:");
for (prefix, hoop) in res {
print!("prefix: ");
for p in prefix {
print!("{}, ", WithTranslator::from_RSset(&translator, &p));
}
print!("\nhoop: ");
for l in hoop {
print!("{}, ", WithTranslator::from_RSset(&translator, &l));
}
println!();
}
let res = rsprocess::perpetual::lollipops_only_loop(sys);
println!("res:");
for hoop in res {
print!("hoop: ");
for l in hoop {
print!("{}, ", WithTranslator::from_RSset(&translator, &l));
}
println!();
}
// -------------------------------------------------------------------------
Ok(())
}

View File

@ -1,11 +1,22 @@
use std::rc::Rc;
use std::str::FromStr;
use lalrpop_util::ParseError;
use crate::rsprocess::structure::{RSset, RSprocess, RSenvironment, RSassert, RSassertOp, RSBHML};
use crate::rsprocess::structure::{RSset,
RSprocess,
RSenvironment,
RSassert,
RSassertOp,
RSBHML,
RSsystem,
RSreaction};
use crate::rsprocess::translator::{Translator, IdType};
grammar(translator: &mut Translator);
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
// matches words (letter followed by numbers, letters or _)
Literal = { r"[[:alpha:]][[:word:]]*" };
@ -26,7 +37,9 @@ Separeted<T, C>: Vec<T> = {
}
};
// ----- SetParser -----
// -----------------------------------------------------------------------------
// SetParser
// -----------------------------------------------------------------------------
pub Set: RSset = {
<s: Set_of_entities> => s
};
@ -38,18 +51,31 @@ Set_of_entities: RSset = {
RSset::from(t.into_iter().map(|t| translator.encode(t)).collect::<Vec<_>>())
};
// ----- ContextParser -----
pub Context: Box<RSprocess> = {
// "[" "]" => Box::new(RSprocess::Nill),
// "[" <t: CTX_process> "]" => Box::new(t),
// "[" <t: Separeted<Boxed_CTX_process, ",">> "]" =>
// Box::new(RSprocess::NondeterministicChoice{ children: t })
"[" "]" => Box::new(RSprocess::NondeterministicChoice{ children: vec![] }),
// -----------------------------------------------------------------------------
// ReactionParser
// -----------------------------------------------------------------------------
pub Reactions: Vec<RSreaction> = {
"(" ")" => vec![],
"(" <r: Reaction> ")" => vec![r],
"(" <s: Separeted<Reaction, ";">> ")" => s
}
Reaction: RSreaction = {
"[" <r: Set> "," <i: Set> "," <p: Set> "]" => RSreaction::from(r, i, p),
"[" "r:" <r: Set> "," "i:" <i: Set> "," "p:" <p: Set> "]" => RSreaction::from(r, i, p),
}
// -----------------------------------------------------------------------------
// ContextParser
// -----------------------------------------------------------------------------
pub Context: RSprocess = {
"[" "]" => RSprocess::NondeterministicChoice{ children: vec![] },
"[" <t: CTX_process> "]" =>
Box::new(RSprocess::NondeterministicChoice{children: vec![Rc::new(t)]}),
RSprocess::NondeterministicChoice{children: vec![Rc::new(t)]},
"[" <t: Separeted<Boxed_CTX_process, ",">> "]" =>
Box::new(RSprocess::NondeterministicChoice{ children: t })
RSprocess::NondeterministicChoice{ children: t }
};
Boxed_CTX_process: Rc<RSprocess> = {
@ -71,7 +97,9 @@ CTX_process: RSprocess = {
RSprocess::RecursiveIdentifier{ identifier: translator.encode(identifier) }
};
// ----- EnvironmentParser -----
// -----------------------------------------------------------------------------
// EnvironmentParser
// -----------------------------------------------------------------------------
pub Environment: Box<RSenvironment> = {
"[" "]" => Box::new(RSenvironment::new()),
"[" <t:Env_term> "]" => Box::new(RSenvironment::from(vec![t])),
@ -83,7 +111,9 @@ Env_term: (IdType, RSprocess) = {
(translator.encode(identifier), k)
};
// ----- AssertParser -----
// -----------------------------------------------------------------------------
// AssertParser
// -----------------------------------------------------------------------------
pub Assert: Box<RSassert> = {
<f: Formula_Assert> => Box::new(f)
};
@ -104,7 +134,9 @@ Formula_Assert: RSassert = {
"?" "inP" => RSassert::NonEmpty(RSassertOp::InP),
};
// ----- BHMLParser -----
// -----------------------------------------------------------------------------
// BHMLParser
// -----------------------------------------------------------------------------
pub BHML: Box<RSBHML> = {
<g: Formula_BHML> => Box::new(g)
};
@ -119,3 +151,19 @@ Formula_BHML: RSBHML = {
"[" <f: Formula_Assert> "]" <g: Formula_BHML> =>
RSBHML::Box(Box::new(f), Box::new(g)),
};
// -----------------------------------------------------------------------------
// File Parsing
// -----------------------------------------------------------------------------
// system
// a system is an environment, a set of entities as initial state, a context and
// a set of reaction rules.
pub System: RSsystem = {
"Environment:" <delta: Environment>
"Initial Entities:" <available_entities: Set>
"Context:" <context_process: Context>
"Reactions:" <reaction_rules: Reactions>
=> RSsystem::from(delta.into(), available_entities, context_process, Rc::new(reaction_rules))
}

View File

@ -6,3 +6,4 @@ pub mod transitions;
pub mod perpetual;
pub mod confluence;
pub mod frequency;
pub mod statistics;

134
src/rsprocess/statistics.rs Normal file
View File

@ -0,0 +1,134 @@
#![allow(dead_code)]
use super::structure::RSset;
use super::structure::RSsystem;
use super::translator::{Translator, WithTranslator};
#[allow(non_snake_case)]
pub fn of_RSsystem<'a>(translator: &'a Translator, system: &'a RSsystem) -> String {
let mut result: String = "Statistics:\n".into();
result.push_str(
"=============================================================\n"
);
result.push_str(
&format!("the initial state has {} entities:\n",
system.get_available_entities().len())
);
result.push_str(
&format!("{}\n",
WithTranslator::from_RSset(translator,
system.get_available_entities()))
);
let reactants =
system
.get_reaction_rules()
.iter()
.fold(RSset::new(), |acc, new| acc.union(new.reactants()));
result.push_str(
&format!("The reactants are {}:\n{}\n",
reactants.len(),
WithTranslator::from_RSset(translator, &reactants))
);
let inhibitors =
system
.get_reaction_rules()
.iter()
.fold(RSset::new(), |acc, new| acc.union(new.inihibitors()));
result.push_str(
&format!("The inhibitors are {}:\n{}\n",
inhibitors.len(),
WithTranslator::from_RSset(translator, &inhibitors))
);
let products =
system
.get_reaction_rules()
.iter()
.fold(RSset::new(), |acc, new| acc.union(new.products()));
result.push_str(
&format!("The products are {}:\n{}\n",
products.len(),
WithTranslator::from_RSset(translator, &products))
);
let total = reactants.union(&inhibitors.union(&products));
result.push_str(
&format!("The reactions involve {} entities:\n{}\n",
total.len(),
WithTranslator::from_RSset(translator, &total))
);
let entities_env = system.get_delta().all_elements();
result.push_str(
&format!("The environment involves {} entities:\n{}\n",
entities_env.len(),
WithTranslator::from_RSset(translator, &entities_env))
);
let entities_context = system.get_context_process().all_elements();
result.push_str(
&format!("The context involves {} entities:\n{}\n",
entities_context.len(),
WithTranslator::from_RSset(translator, &entities_context))
);
let entities_all = total.union(&entities_env)
.union(&entities_context)
.union(system.get_available_entities());
result.push_str(
&format!("The whole RS involves {} entities:\n{}\n",
entities_all.len(),
WithTranslator::from_RSset(translator, &entities_all))
);
let possible_e = products.union(system.get_available_entities())
.union(&entities_context);
let missing_e = reactants.subtraction(&possible_e);
result.push_str(
&format!("There are {} reactants that will never be available:\n{}\n",
missing_e.len(),
WithTranslator::from_RSset(translator, &missing_e))
);
let entities_not_needed = entities_context.subtraction(&total);
result.push_str(
&format!("The context can provide {} entities that will never be used:\n{}\n",
entities_not_needed.len(),
WithTranslator::from_RSset(translator, &entities_not_needed))
);
result.push_str(
&format!("There are {} reactions in total.\n",
system.get_reaction_rules().len())
);
let mut admissible_reactions = vec![];
let mut nonadmissible_reactions = vec![];
for reaction in system.get_reaction_rules().iter() {
if reaction.reactants().is_disjoint(&missing_e) {
admissible_reactions.push(reaction);
} else {
nonadmissible_reactions.push(reaction);
}
}
result.push_str(
&format!("- the applicable reactions are {}.\n",
admissible_reactions.len())
);
result.push_str(
&format!("- there are {} reactions that will never be enabled.\n",
nonadmissible_reactions.len())
);
result.push_str(
"============================================================="
);
result
}

View File

@ -1,6 +1,6 @@
#![allow(dead_code)]
use std::collections::{BTreeSet, HashMap, HashSet};
use std::collections::{BTreeSet, HashMap, HashSet, VecDeque};
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use super::translator::{IdType};
@ -75,13 +75,31 @@ impl RSset {
RSset { identifiers: res }
}
pub fn hashset(&self) -> &BTreeSet<IdType> {
pub fn set(&self) -> &BTreeSet<IdType> {
&self.identifiers
}
pub fn iter(&self) -> std::collections::btree_set::Iter<'_, IdType> {
self.identifiers.iter()
}
pub fn len(&self) -> usize {
self.identifiers.len()
}
pub fn insert(&mut self, el: IdType) -> bool {
self.identifiers.insert(el)
}
pub fn push(&mut self, b: &RSset) {
self.identifiers.extend(b.iter())
}
}
impl Default for RSset {
fn default() -> Self {
RSset::new()
}
}
impl IntoIterator for RSset {
@ -140,6 +158,12 @@ impl RSreaction {
}
}
impl Default for RSreaction {
fn default() -> Self {
RSreaction::new()
}
}
// -----------------------------------------------------------------------------
@ -183,8 +207,42 @@ impl RSprocess {
}
}
}
pub fn all_elements(&self) -> RSset {
let mut queue = VecDeque::from([self]);
let mut elements = RSset::new();
while let Some(el) = queue.pop_front() {
match el {
Self::Nill => {}
Self::RecursiveIdentifier { identifier: _ } => {}
Self::EntitySet { entities, next_process } => {
elements.push(entities);
queue.push_back(next_process);
}
Self::WaitEntity { repeat: _, repeated_process, next_process } => {
queue.push_back(repeated_process);
queue.push_back(next_process);
}
Self::Summation { children } => {
for c in children {
queue.push_back(c);
}
}
Self::NondeterministicChoice { children } => {
for c in children {
queue.push_back(c);
}
}
}
}
elements
}
}
// -----------------------------------------------------------------------------
// RSchoices
// -----------------------------------------------------------------------------
#[derive(Clone, Debug)]
pub struct RSchoices {
context_moves: Vec<(Rc<RSset>, Rc<RSprocess>)>
@ -284,6 +342,20 @@ impl RSenvironment {
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, u32, RSprocess> {
self.definitions.iter()
}
pub fn all_elements(&self) -> RSset {
let mut acc = RSset::new();
for (_, process) in self.definitions.iter() {
acc.push(&process.all_elements());
}
acc
}
}
impl Default for RSenvironment {
fn default() -> Self {
RSenvironment::new()
}
}
impl<const N: usize> From<[(IdType, RSprocess); N]> for RSenvironment {
@ -352,6 +424,12 @@ impl RSsystem {
}
}
impl Default for RSsystem {
fn default() -> Self {
RSsystem::new()
}
}
// -----------------------------------------------------------------------------
// RSsystem
// -----------------------------------------------------------------------------
@ -361,9 +439,9 @@ pub struct RSlabel {
pub context: RSset,
pub t: RSset, /// union of available_entities and context
pub reactants: RSset,
pub reactantsi: RSset,
pub reactantsi: RSset, // reactants absent
pub inihibitors: RSset,
pub ireactants: RSset,
pub ireactants: RSset, // inhibitors present
pub products: RSset,
}
@ -399,7 +477,7 @@ impl RSlabel {
}
pub fn get_context(&self) -> (RSset, RSset, RSset) {
// FIXME clone?
// TODO remove clone?
(self.available_entities.clone(), self.context.clone(), self.t.clone())
}
}

View File

@ -20,6 +20,12 @@ impl Translator {
}
}
impl Default for Translator {
fn default() -> Self {
Translator::new()
}
}
impl Translator {
pub fn encode(&mut self, s: impl Into<String>) -> IdType {
let s = s.into();
@ -144,7 +150,7 @@ fn print_set(
set: &RSset
) -> fmt::Result {
write!(f, "{{")?;
let mut it = set.hashset().iter().peekable();
let mut it = set.iter().peekable();
while let Some(el) = it.next() {
if it.peek().is_none() {
write!(f, "{}", translator.decode(*el))?;