This commit is contained in:
elvis
2025-07-12 15:41:10 +02:00
parent 483260c2a3
commit 9207d588b8

View File

@ -19,34 +19,36 @@ use super::structure::{RSset, RSsystem};
use super::translator::Translator; use super::translator::Translator;
use super::*; use super::*;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Structures // Structures
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
pub struct SaveOptions { pub struct SaveOptions {
pub print: bool, pub print: bool,
pub save: Option<Vec<String>> pub save: Option<Vec<String>>,
} }
impl SaveOptions { impl SaveOptions {
pub fn combine(&mut self, other: &mut Self) { pub fn combine(&mut self, other: &mut Self) {
self.print = self.print || other.print; self.print = self.print || other.print;
match (self.save.is_some(), other.save.is_some()) { match (self.save.is_some(), other.save.is_some()) {
(false, false) | (false, false) | (true, false) => {}
(true, false) => {}
(false, true) => { (false, true) => {
self.save = other.save.to_owned(); self.save = other.save.to_owned();
}, }
(true, true) => { (true, true) => {
self.save self.save
.as_mut() .as_mut()
.unwrap() .unwrap()
.append(other.save.as_mut().unwrap());} .append(other.save.as_mut().unwrap());
}
} }
} }
pub fn new() -> Self { pub fn new() -> Self {
SaveOptions { print: false, save: None } SaveOptions {
print: false,
save: None,
}
} }
} }
@ -59,23 +61,29 @@ impl Default for SaveOptions {
#[derive(Clone)] #[derive(Clone)]
pub enum NodeDisplay { pub enum NodeDisplay {
Separator(String), Separator(String),
Display(graph::GraphMapNodes) Display(graph::GraphMapNodes),
} }
#[derive(Clone)] #[derive(Clone)]
pub enum EdgeDisplay { pub enum EdgeDisplay {
Separator(String), Separator(String),
Display(graph::GraphMapEdges) Display(graph::GraphMapEdges),
} }
pub enum GraphSaveOptions { pub enum GraphSaveOptions {
Dot { node_display: Vec<NodeDisplay>, Dot {
node_display: Vec<NodeDisplay>,
edge_display: Vec<EdgeDisplay>, edge_display: Vec<EdgeDisplay>,
so: SaveOptions }, so: SaveOptions,
GraphML { node_display: Vec<NodeDisplay>, },
GraphML {
node_display: Vec<NodeDisplay>,
edge_display: Vec<EdgeDisplay>, edge_display: Vec<EdgeDisplay>,
so: SaveOptions }, so: SaveOptions,
Serialize { path: String } },
Serialize {
path: String,
},
} }
pub enum Instruction { pub enum Instruction {
@ -91,17 +99,20 @@ pub enum Instruction {
pub enum System { pub enum System {
Deserialize { path: String }, Deserialize { path: String },
RSsystem { sys: RSsystem } RSsystem { sys: RSsystem },
} }
pub enum EvaluatedSystem { pub enum EvaluatedSystem {
Graph { graph: Graph<RSsystem, RSlabel>, Graph {
translator: Translator }, graph: Graph<RSsystem, RSlabel>,
System { sys: RSsystem, translator: Translator,
translator: Translator } },
System {
sys: RSsystem,
translator: Translator,
},
} }
impl System { impl System {
pub fn compute( pub fn compute(
&self, &self,
@ -109,14 +120,13 @@ impl System {
) -> Result<EvaluatedSystem, String> ) -> Result<EvaluatedSystem, String>
{ {
match self { match self {
Self::RSsystem { sys } => { Self::RSsystem { sys } => Ok(EvaluatedSystem::System {
Ok(EvaluatedSystem::System { sys: sys.to_owned(), sys: sys.to_owned(),
translator }) translator,
}, }),
Self::Deserialize { path } => { Self::Deserialize { path } => {
let (graph, translator) = deserialize(path.into())?; let (graph, translator) = deserialize(path.into())?;
Ok(EvaluatedSystem::Graph { graph, Ok(EvaluatedSystem::Graph { graph, translator })
translator })
} }
} }
} }
@ -124,7 +134,7 @@ impl System {
pub struct Instructions { pub struct Instructions {
pub system: System, pub system: System,
pub instructions: Vec<Instruction> pub instructions: Vec<Instruction>,
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -137,25 +147,25 @@ fn read_file<T, F>(
parser: F parser: F
) -> Result<T, String> ) -> Result<T, String>
where where
F: Fn(&mut Translator, String) -> Result<T, String> F: Fn(&mut Translator, String) -> Result<T, String>,
{ {
// relative path // relative path
let mut path = match env::current_dir() { let mut path = match env::current_dir() {
Ok(p) => p, Ok(p) => p,
Err(_) => return Err("Error getting current directory.".into()) Err(_) => return Err("Error getting current directory.".into()),
}; };
path = path.join(path_string); path = path.join(path_string);
// we read the file with a buffer // we read the file with a buffer
let f = match fs::File::open(path) { let f = match fs::File::open(path) {
Ok(f) => f, Ok(f) => f,
Err(_) => return Err("Error opening file.".into()) Err(_) => return Err("Error opening file.".into()),
}; };
let mut buf_reader = io::BufReader::new(f); let mut buf_reader = io::BufReader::new(f);
let mut contents = String::new(); let mut contents = String::new();
match buf_reader.read_to_string(&mut contents) { match buf_reader.read_to_string(&mut contents) {
Ok(_) => {}, Ok(_) => {}
Err(_) => return Err("Error reading file.".into()) Err(_) => return Err("Error reading file.".into()),
} }
// parse // parse
@ -168,86 +178,73 @@ fn reformat_error<T, S>(
e: ParseError<usize, T, &'static str> e: ParseError<usize, T, &'static str>
) -> Result<S, String> ) -> Result<S, String>
where where
T: Display T: Display,
{ {
match e { match e {
ParseError::ExtraToken { token: (l, t, r) } => { ParseError::ExtraToken { token: (l, t, r) } => Err(format!(
Err(format!(
"Unexpected token \"{t}\" \ "Unexpected token \"{t}\" \
between positions {l} and {r}." between positions {l} and {r}."
)) )),
}, ParseError::UnrecognizedEof {
ParseError::UnrecognizedEof { location: _, expected: _ } => { location: _,
Err("End of file encountered while parsing.".into()) expected: _,
}, } => Err("End of file encountered while parsing.".into()),
ParseError::InvalidToken { location } => { ParseError::InvalidToken { location } => {
Err(format!("Invalid token at position {location}.")) Err(format!("Invalid token at position {location}."))
}, }
ParseError::UnrecognizedToken { token: (l, t, r), expected } ParseError::UnrecognizedToken {
=> { token: (l, t, r),
Err(format!( expected,
} => Err(format!(
"Unrecognized token \"{t}\" \ "Unrecognized token \"{t}\" \
between positions {l} and {r}. Expected: {expected:?}" between positions {l} and {r}. Expected: {expected:?}"
)) )),
}, ParseError::User { error } => Err(error.to_string()),
ParseError::User { error } => {
Err(error.to_string())
}
} }
} }
fn parser_experiment( fn parser_experiment(
translator: &mut Translator, translator: &mut Translator,
contents: String contents: String,
) -> Result<(Vec<u32>, Vec<RSset>), String> ) -> Result<(Vec<u32>, Vec<RSset>), String> {
{ match grammar::ExperimentParser::new().parse(translator, &contents) {
match grammar::ExperimentParser::new()
.parse(translator, &contents)
{
Ok(sys) => Ok(sys), Ok(sys) => Ok(sys),
Err(e) => reformat_error(e) Err(e) => reformat_error(e),
} }
} }
fn parser_instructions( fn parser_instructions(
translator: &mut Translator, translator: &mut Translator,
contents: String contents: String,
) -> Result<Instructions, String> ) -> Result<Instructions, String> {
{ match grammar::RunParser::new().parse(translator, &contents) {
match grammar::RunParser::new()
.parse(translator, &contents)
{
Ok(sys) => Ok(sys), Ok(sys) => Ok(sys),
Err(e) => reformat_error(e) Err(e) => reformat_error(e),
} }
} }
fn save_file( fn save_file(contents: &String, path_string: String) -> Result<(), String> {
contents: &String,
path_string: String
) -> Result<(), String>
{
// relative path // relative path
let mut path = match env::current_dir() { let mut path = match env::current_dir() {
Ok(p) => p, Ok(p) => p,
Err(_) => return Err("Error getting current directory.".into()) Err(_) => return Err("Error getting current directory.".into()),
}; };
path = path.join(path_string); path = path.join(path_string);
let mut f = match fs::File::create(&path) { let mut f = match fs::File::create(&path) {
Ok(f) => f, Ok(f) => f,
Err(_) => return Err(format!("Error creating file {}.", Err(_) =>
path.to_str().unwrap())) return Err(
format!("Error creating file {}.", path.to_str().unwrap())
),
}; };
match write!(f, "{contents}") { match write!(f, "{contents}") {
Ok(_) => {} Ok(_) => {}
Err(_) => return Err("Error writing to file.".into()) Err(_) => return Err("Error writing to file.".into()),
} }
Ok(()) Ok(())
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// main_do // main_do
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -256,12 +253,10 @@ fn save_file(
/// Equivalent main_do(stat) or main_do(stat, MissingE) /// Equivalent main_do(stat) or main_do(stat, MissingE)
pub fn stats(system: &EvaluatedSystem) -> Result<String, String> { pub fn stats(system: &EvaluatedSystem) -> Result<String, String> {
match system { match system {
EvaluatedSystem::System { sys, translator } => { EvaluatedSystem::System { sys, translator } =>
Ok(statistics::of_RSsystem(translator, sys)) Ok(statistics::of_RSsystem(translator, sys)),
},
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
let Some(sys) = graph.node_weights().next() let Some(sys) = graph.node_weights().next() else {
else {
return Err("No node found in graph".into()); return Err("No node found in graph".into());
}; };
Ok(statistics::of_RSsystem(translator, sys)) Ok(statistics::of_RSsystem(translator, sys))
@ -269,18 +264,15 @@ pub fn stats(system: &EvaluatedSystem) -> Result<String, String> {
} }
} }
/// Prints a final set of entities in a terminating Reaction System. /// Prints a final set of entities in a terminating Reaction System.
/// The system needs to terminate to return. /// The system needs to terminate to return.
/// Equivalent to main_do(target, E) /// Equivalent to main_do(target, E)
pub fn target(system: &EvaluatedSystem) -> Result<String, String> { pub fn target(system: &EvaluatedSystem) -> Result<String, String> {
let (res, translator) = match system { let (res, translator) = match system {
EvaluatedSystem::System { sys, translator } => { EvaluatedSystem::System { sys, translator } =>
(transitions::target(sys)?, translator) (transitions::target(sys)?, translator),
},
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
let Some(sys) = graph.node_weights().next() let Some(sys) = graph.node_weights().next() else {
else {
return Err("No node found in graph".into()); return Err("No node found in graph".into());
}; };
(transitions::target(sys)?, translator) (transitions::target(sys)?, translator)
@ -293,7 +285,6 @@ pub fn target(system: &EvaluatedSystem) -> Result<String, String> {
)) ))
} }
/// Finds the list of traversed states in a (deterministic) terminating /// Finds the list of traversed states in a (deterministic) terminating
/// reaction. /// reaction.
/// The system needs to terminate to return. /// The system needs to terminate to return.
@ -302,10 +293,9 @@ pub fn traversed(system: &EvaluatedSystem) -> Result<String, String> {
let (res, translator) = match system { let (res, translator) = match system {
EvaluatedSystem::System { sys, translator } => { EvaluatedSystem::System { sys, translator } => {
(transitions::run_separated(sys)?, translator) (transitions::run_separated(sys)?, translator)
}, }
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
let Some(sys) = graph.node_weights().next() let Some(sys) = graph.node_weights().next() else {
else {
return Err("No node found in graph".into()); return Err("No node found in graph".into());
}; };
(transitions::run_separated(sys)?, translator) (transitions::run_separated(sys)?, translator)
@ -316,45 +306,36 @@ pub fn traversed(system: &EvaluatedSystem) -> Result<String, String> {
output.push_str("The trace is composed by the set of entities:"); output.push_str("The trace is composed by the set of entities:");
for (e, _c, _t) in res { for (e, _c, _t) in res {
output.push_str( output.push_str(&format!(
&format!(
"{}", "{}",
translator::RSsetDisplay::from(translator, &e) translator::RSsetDisplay::from(translator, &e)
) ));
);
} }
Ok(output) Ok(output)
} }
/// Finds the looping list of states in a reaction system with a perpetual /// Finds the looping list of states in a reaction system with a perpetual
/// context. IMPORTANT: for loops, we assume Delta defines the process constant /// context. IMPORTANT: for loops, we assume Delta defines the process constant
/// x = Q.x and the context process is x . /// x = Q.x and the context process is x .
/// equivalent to main_do(loop,Es) /// equivalent to main_do(loop,Es)
pub fn hoop( pub fn hoop(
system: &EvaluatedSystem, symbol: String system: &EvaluatedSystem,
) -> Result<String, String> symbol: String
{ ) -> Result<String, String> {
let (res, translator) = match system { let (res, translator) = match system {
EvaluatedSystem::System { sys, translator } => { EvaluatedSystem::System { sys, translator } => (sys, translator),
(sys, translator)
},
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
let Some(sys) = graph.node_weights().next() let Some(sys) = graph.node_weights().next() else {
else {
return Err("No node found in graph".into()); return Err("No node found in graph".into());
}; };
(sys, translator) (sys, translator)
} }
}; };
// we retrieve the id for "x" and use it to find the corresponding loop // we retrieve the id for "x" and use it to find the corresponding loop
let Some(id) = translator.encode_not_mut(&symbol) let Some(id) = translator.encode_not_mut(&symbol) else {
else {
return Err(format!("Symbol {symbol} not found")); return Err(format!("Symbol {symbol} not found"));
}; };
let res = let res = match perpetual::lollipops_only_loop_named(res, id) {
match perpetual::lollipops_only_loop_named(res, id) {
Some(o) => o, Some(o) => o,
None => { None => {
return Err("No loop found.".into()); return Err("No loop found.".into());
@ -365,9 +346,10 @@ pub fn hoop(
output.push_str("The loop is composed by the sets:"); output.push_str("The loop is composed by the sets:");
for e in res { for e in res {
output.push_str( output.push_str(&format!(
&format!( "{}", translator::RSsetDisplay::from(translator, &e)) "{}",
); translator::RSsetDisplay::from(translator, &e)
));
} }
Ok(output) Ok(output)
@ -376,16 +358,11 @@ pub fn hoop(
/// Finds the frequency of each entity in the traversed states for a /// Finds the frequency of each entity in the traversed states for a
/// (deterministic) terminating Reaction System. /// (deterministic) terminating Reaction System.
/// equivalent to main_do(freq, PairList) /// equivalent to main_do(freq, PairList)
pub fn freq( pub fn freq(system: &EvaluatedSystem) -> Result<String, String> {
system: &EvaluatedSystem
) -> Result<String, String> {
let (sys, translator) = match system { let (sys, translator) = match system {
EvaluatedSystem::System { sys, translator } => { EvaluatedSystem::System { sys, translator } => (sys, translator),
(sys, translator)
},
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
let Some(sys) = graph.node_weights().next() let Some(sys) = graph.node_weights().next() else {
else {
return Err("No node found in graph".into()); return Err("No node found in graph".into());
}; };
(sys, translator) (sys, translator)
@ -400,37 +377,35 @@ pub fn freq(
)) ))
} }
/// Finds the frequency of each entity in the limit loop of a nonterminating /// Finds the frequency of each entity in the limit loop of a nonterminating
/// Reaction System whose context has the form Q1 ... Q1.Q2 ... Q2 ... Qn ... /// Reaction System whose context has the form Q1 ... Q1.Q2 ... Q2 ... Qn ...
/// equivalent to main_do(limitfreq, PairList) /// equivalent to main_do(limitfreq, PairList)
pub fn limit_freq( pub fn limit_freq(
system: &mut EvaluatedSystem, system: &mut EvaluatedSystem,
experiment: String experiment: String
) -> Result<String, String> ) -> Result<String, String> {
{
let (sys, translator): (&RSsystem, &mut Translator) = match system { let (sys, translator): (&RSsystem, &mut Translator) = match system {
EvaluatedSystem::System { sys, translator } => { EvaluatedSystem::System { sys, translator } => (sys, translator),
(sys, translator)
},
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
let Some(sys) = graph.node_weights().next() let Some(sys) = graph.node_weights().next() else {
else {
return Err("No node found in graph".into()); return Err("No node found in graph".into());
}; };
(sys, translator) (sys, translator)
} }
}; };
let (_, sets) = read_file(translator, let (_, sets) = read_file(translator, experiment, parser_experiment)?;
experiment,
parser_experiment)?;
let res = match frequency::limit_frequency(&sets, let res =
match frequency::limit_frequency(
&sets,
&sys.reaction_rules, &sys.reaction_rules,
&sys.available_entities) { &sys.available_entities)
{
Some(e) => e, Some(e) => e,
None => {return Err("Error calculating frequency.".into());} None => {
return Err("Error calculating frequency.".into());
}
}; };
Ok(format!( Ok(format!(
@ -439,7 +414,6 @@ pub fn limit_freq(
)) ))
} }
/// Finds the frequency of each entity in the traversed loops of a terminating /// Finds the frequency of each entity in the traversed loops of a terminating
/// reaction system whose context has the form /// reaction system whose context has the form
/// Q1 ... Q1.Q2 ... Q2 ... Qn ... Qn.nil and each Qi is repeated Wi times /// Q1 ... Q1.Q2 ... Q2 ... Qn ... Qn.nil and each Qi is repeated Wi times
@ -451,28 +425,27 @@ pub fn fast_freq(
) -> Result<String, String> ) -> Result<String, String>
{ {
let (sys, translator): (&RSsystem, &mut Translator) = match system { let (sys, translator): (&RSsystem, &mut Translator) = match system {
EvaluatedSystem::System { sys, translator } => { EvaluatedSystem::System { sys, translator } => (sys, translator),
(sys, translator)
},
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
let Some(sys) = graph.node_weights().next() let Some(sys) = graph.node_weights().next() else {
else {
return Err("No node found in graph".into()); return Err("No node found in graph".into());
}; };
(sys, translator) (sys, translator)
} }
}; };
let (weights, sets) = read_file(translator, let (weights, sets) = read_file(translator, experiment, parser_experiment)?;
experiment,
parser_experiment)?;
let res = match frequency::fast_frequency(&sets, let res = match frequency::fast_frequency(
&sets,
&sys.reaction_rules, &sys.reaction_rules,
&sys.available_entities, &sys.available_entities,
&weights) { &weights,
) {
Some(e) => e, Some(e) => e,
None => {return Err("Error calculating frequency.".into());} None => {
return Err("Error calculating frequency.".into());
}
}; };
Ok(format!( Ok(format!(
@ -483,13 +456,11 @@ pub fn fast_freq(
/// Computes the LTS. /// Computes the LTS.
/// equivalent to main_do(digraph, Arcs) or to main_do(advdigraph, Arcs) /// equivalent to main_do(digraph, Arcs) or to main_do(advdigraph, Arcs)
pub fn digraph( pub fn digraph(system: &mut EvaluatedSystem) -> Result<(), String> {
system: &mut EvaluatedSystem
) -> Result<(), String> {
*system = if let EvaluatedSystem::System { sys, translator } = system { *system = if let EvaluatedSystem::System { sys, translator } = system {
EvaluatedSystem::Graph { EvaluatedSystem::Graph {
graph: graph::digraph(sys.clone())?, graph: graph::digraph(sys.clone())?,
translator: translator.to_owned() translator: translator.to_owned(),
} }
} else { } else {
return Ok(()); return Ok(());
@ -497,7 +468,6 @@ pub fn digraph(
Ok(()) Ok(())
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Output Functions // Output Functions
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -505,33 +475,28 @@ pub fn digraph(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn generate_node_pringting_fn<'a>( fn generate_node_pringting_fn<'a>(
node_display: &'a Vec<NodeDisplay>, node_display: &'a Vec<NodeDisplay>,
translator: Rc<Translator> translator: Rc<Translator>,
) -> Box<dyn Fn(petgraph::prelude::NodeIndex, &'a RSsystem) -> String + 'a> { ) -> Box<dyn Fn(petgraph::prelude::NodeIndex, &'a RSsystem) -> String + 'a> {
// The type cannot be aliased since rust doesnt like generics. // The type cannot be aliased since rust doesnt like generics.
// We are iterating over the node_display and constructing a function // We are iterating over the node_display and constructing a function
// (accumulator) that prints out our formatted nodes. So at each step we // (accumulator) that prints out our formatted nodes. So at each step we
// call the previous function and add the next string or function. // call the previous function and add the next string or function.
let mut accumulator: let mut accumulator: Box<dyn Fn(petgraph::prelude::NodeIndex, &RSsystem) -> String> =
Box<dyn Fn(petgraph::prelude::NodeIndex, &RSsystem) -> String> Box::new(|_, _| String::new());
= Box::new(|_, _| String::new());
for nd in node_display { for nd in node_display {
accumulator = accumulator = match nd {
match nd { NodeDisplay::Display(d) => {
NodeDisplay::Display(d) => { // retrieve from the graph module // retrieve from the graph module the correct formatting
// the correct formatting function // function
let val = translator.clone(); let val = translator.clone();
Box::new( Box::new(move |i, n| {
move |i, n| (accumulator)(i, n) + (accumulator)(i, n)
&graph::GraphMapNodesTy::from( + &graph::GraphMapNodesTy::from(d.clone(), val.clone()).get()(i, n)
d.clone(), })
val.clone() }
).get()(i, n)) NodeDisplay::Separator(s) => {
}, // we have a string so simply add it at the end
NodeDisplay::Separator(s) => { // we have a string so simply Box::new(move |i, n| (accumulator)(i, n) + s)
// add it at the end
Box::new(
move |i, n| (accumulator)(i, n) + s
)
} }
}; };
} }
@ -541,33 +506,28 @@ fn generate_node_pringting_fn<'a>(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn generate_edge_pringting_fn<'a>( fn generate_edge_pringting_fn<'a>(
edge_display: &'a Vec<EdgeDisplay>, edge_display: &'a Vec<EdgeDisplay>,
translator: Rc<Translator> translator: Rc<Translator>,
) -> Box<dyn Fn(petgraph::prelude::EdgeIndex, &'a RSlabel) -> String + 'a> { ) -> Box<dyn Fn(petgraph::prelude::EdgeIndex, &'a RSlabel) -> String + 'a> {
// The type cannot be aliased since rust doesnt like generics. // The type cannot be aliased since rust doesnt like generics.
// We are iterating over the edge_display and constructing a function // We are iterating over the edge_display and constructing a function
// (accumulator) that prints out our formatted nodes. So at each step we // (accumulator) that prints out our formatted nodes. So at each step we
// call the previous function and add the next string or function. // call the previous function and add the next string or function.
let mut accumulator: let mut accumulator: Box<dyn Fn(petgraph::prelude::EdgeIndex, &RSlabel) -> String> =
Box<dyn Fn(petgraph::prelude::EdgeIndex, &RSlabel) -> String> Box::new(|_, _| String::new());
= Box::new(|_, _| String::new());
for nd in edge_display { for nd in edge_display {
accumulator = accumulator = match nd {
match nd { EdgeDisplay::Display(d) => {
EdgeDisplay::Display(d) => { // retrieve from the graph module // retrieve from the graph module the correct formatting
// the correct formatting function // function
let val = translator.clone(); let val = translator.clone();
Box::new( Box::new(move |i, n| {
move |i, n| (accumulator)(i, n) + (accumulator)(i, n)
&graph::GraphMapEdgesTy::from( + &graph::GraphMapEdgesTy::from(d.clone(), val.clone()).get()(i, n)
d.clone(), })
val.clone() }
).get()(i, n)) EdgeDisplay::Separator(s) => {
}, // we have a string so simply add it at the end
EdgeDisplay::Separator(s) => { // we have a string so simply Box::new(move |i, n| (accumulator)(i, n) + s)
// add it at the end
Box::new(
move |i, n| (accumulator)(i, n) + s
)
} }
}; };
} }
@ -578,30 +538,31 @@ fn generate_edge_pringting_fn<'a>(
pub fn dot( pub fn dot(
system: &EvaluatedSystem, system: &EvaluatedSystem,
node_display: Vec<NodeDisplay>, node_display: Vec<NodeDisplay>,
edge_display: Vec<EdgeDisplay> edge_display: Vec<EdgeDisplay>,
) -> Result<String, String> ) -> Result<String, String> {
{
match system { match system {
EvaluatedSystem::System { sys:_, translator:_ } => EvaluatedSystem::System {
Err("Supplied system is not a graph".into()), sys: _,
translator: _,
} => Err("Supplied system is not a graph".into()),
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
let rc_translator = Rc::new(translator.clone()); let rc_translator = Rc::new(translator.clone());
// map each value to the corresponding value we want to display // map each value to the corresponding value we want to display
// this is awful but rust is not a functional language so its all // this is awful but rust is not a functional language so its all
// fine... // fine...
let modified_graph = graph.map( let modified_graph = graph.map(
generate_node_pringting_fn(&node_display, Rc::clone(&rc_translator)), generate_node_pringting_fn(&node_display,
generate_edge_pringting_fn(&edge_display, rc_translator) Rc::clone(&rc_translator)),
generate_edge_pringting_fn(&edge_display,
rc_translator),
); );
let graph = Rc::new(graph.to_owned()); let graph = Rc::new(graph.to_owned());
let edge_formatter = graph::default_edge_formatter( let edge_formatter =
Rc::clone(&graph) graph::default_edge_formatter(Rc::clone(&graph));
); let node_formatter =
let node_formatter = graph::default_node_formatter( graph::default_node_formatter(Rc::clone(&graph));
Rc::clone(&graph)
);
let dot = rsdot::RSDot::with_attr_getters( let dot = rsdot::RSDot::with_attr_getters(
&modified_graph, &modified_graph,
@ -618,25 +579,33 @@ pub fn dot(
/// Writes the specified graph to a file in .graphml format. /// Writes the specified graph to a file in .graphml format.
pub fn graphml(system: &EvaluatedSystem) -> Result<String, String> { pub fn graphml(system: &EvaluatedSystem) -> Result<String, String> {
match system { match system {
EvaluatedSystem::System { sys:_, translator:_ } => EvaluatedSystem::System {
Err("Supplied system is not a graph".into()), sys: _,
translator: _,
} => Err("Supplied system is not a graph".into()),
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
let rc_translator = Rc::new(translator.to_owned()); let rc_translator = Rc::new(translator.to_owned());
// map each value to the corresponding value we want to display // map each value to the corresponding value we want to display
let modified_graph = graph.map( let modified_graph = graph.map(
|id, node| |id, node| {
graph::GraphMapNodesTy::from( graph::GraphMapNodesTy::from(
graph::GraphMapNodes::Entities, graph::GraphMapNodes::Entities,
Rc::clone(&rc_translator) Rc::clone(&rc_translator),
).get()(id, node) )
+ "; " + .get()(id, node)
&graph::GraphMapNodesTy::from( + "; "
+ &graph::GraphMapNodesTy::from(
graph::GraphMapNodes::Context, graph::GraphMapNodes::Context,
Rc::clone(&rc_translator) Rc::clone(&rc_translator),
).get()(id, node), )
graph::GraphMapEdgesTy::from(graph::GraphMapEdges::EntitiesAdded, .get()(id, node)
Rc::clone(&rc_translator)).get() },
graph::GraphMapEdgesTy::from(
graph::GraphMapEdges::EntitiesAdded,
Rc::clone(&rc_translator),
)
.get(),
); );
use petgraph_graphml::GraphMl; use petgraph_graphml::GraphMl;
@ -653,14 +622,12 @@ pub fn graphml(system: &EvaluatedSystem) -> Result<String, String> {
/// Writes the specified graph, translator tuple to file. /// Writes the specified graph, translator tuple to file.
/// N.B. graph size in memory might be much larger after serialization and /// N.B. graph size in memory might be much larger after serialization and
/// deserialization. /// deserialization.
pub fn serialize( pub fn serialize(system: &EvaluatedSystem, path: String) -> Result<(), String> {
system: &EvaluatedSystem,
path: String
) -> Result<(), String>
{
match system { match system {
EvaluatedSystem::System { sys:_, translator:_ } => EvaluatedSystem::System {
Err("Supplied system is not a graph".into()), sys: _,
translator: _,
} => Err("Supplied system is not a graph".into()),
EvaluatedSystem::Graph { graph, translator } => { EvaluatedSystem::Graph { graph, translator } => {
// relative path // relative path
let mut path = std::path::PathBuf::from(path); let mut path = std::path::PathBuf::from(path);
@ -669,12 +636,12 @@ pub fn serialize(
let f = match fs::File::create(&path) { let f = match fs::File::create(&path) {
Ok(f) => f, Ok(f) => f,
Err(_) => return Err(format!("Error creating file {}.", Err(_) => return Err(format!("Error creating file {}.",
path.to_str().unwrap())) path.to_str().unwrap())),
}; };
match serialize::ser(f, graph, translator) { match serialize::ser(f, graph, translator) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(_) => Err("Error during serialization.".into()) Err(_) => Err("Error during serialization.".into()),
} }
} }
} }
@ -690,7 +657,7 @@ pub fn deserialize(
// relative path // relative path
let mut path = match env::current_dir() { let mut path = match env::current_dir() {
Ok(p) => p, Ok(p) => p,
Err(_) => return Err("Error getting current directory.".into()) Err(_) => return Err("Error getting current directory.".into()),
}; };
path = path.join(input_path); path = path.join(input_path);
path.set_extension("cbor"); path.set_extension("cbor");
@ -698,16 +665,15 @@ pub fn deserialize(
let f = match fs::File::open(&path) { let f = match fs::File::open(&path) {
Ok(f) => f, Ok(f) => f,
Err(_) => return Err(format!("Error opening file {}.", Err(_) => return Err(format!("Error opening file {}.",
path.to_str().unwrap())) path.to_str().unwrap())),
}; };
match serialize::de(f) { match serialize::de(f) {
Ok(a) => Ok(a), Ok(a) => Ok(a),
Err(_) => Err("Error during deserialization.".into()) Err(_) => Err("Error during deserialization.".into()),
} }
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Interpreting Instructions // Interpreting Instructions
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -737,32 +703,40 @@ fn execute(
} }
Instruction::Target { so } => { Instruction::Target { so } => {
save_options!(target(system)?, so); save_options!(target(system)?, so);
}, }
Instruction::Run { so } => { Instruction::Run { so } => {
save_options!(traversed(system)?, so); save_options!(traversed(system)?, so);
}, }
Instruction::Loop { symbol, so } => { Instruction::Loop { symbol, so } => {
save_options!(hoop(system, symbol)?, so); save_options!(hoop(system, symbol)?, so);
}, }
Instruction::Frequency { so } => { Instruction::Frequency { so } => {
save_options!(freq(system)?, so); save_options!(freq(system)?, so);
}, }
Instruction::LimitFrequency { experiment, so } => { Instruction::LimitFrequency { experiment, so } => {
save_options!(limit_freq(system, experiment)?, so); save_options!(limit_freq(system, experiment)?, so);
}, }
Instruction::FastFrequency { experiment, so } => { Instruction::FastFrequency { experiment, so } => {
save_options!(fast_freq(system, experiment)?, so); save_options!(fast_freq(system, experiment)?, so);
}, }
Instruction::Digraph { gso } => { Instruction::Digraph { gso } => {
for save in gso { for save in gso {
digraph(system)?; digraph(system)?;
match save { match save {
GraphSaveOptions::Dot { node_display, edge_display, so } => { GraphSaveOptions::Dot {
save_options!(dot(system, node_display, edge_display)?, so); node_display: nd,
}, edge_display: ed,
GraphSaveOptions::GraphML { node_display:_, edge_display:_, so } => { so,
} => {
save_options!(dot(system, nd, ed)?, so);
}
GraphSaveOptions::GraphML {
node_display: _,
edge_display: _,
so,
} => {
save_options!(graphml(system)?, so); save_options!(graphml(system)?, so);
}, }
GraphSaveOptions::Serialize { path } => { GraphSaveOptions::Serialize { path } => {
serialize(system, path)?; serialize(system, path)?;
} }
@ -776,8 +750,10 @@ fn execute(
pub fn run(path: String) -> Result<(), String> { pub fn run(path: String) -> Result<(), String> {
let mut translator = Translator::new(); let mut translator = Translator::new();
let Instructions { system, instructions } = let Instructions {
read_file(&mut translator, path, parser_instructions)?; system,
instructions,
} = read_file(&mut translator, path, parser_instructions)?;
let mut system = system.compute(translator)?; let mut system = system.compute(translator)?;