From 483260c2a3e1c09bf9eea9111ab42b3416588d02 Mon Sep 17 00:00:00 2001 From: elvis Date: Sat, 12 Jul 2025 15:32:21 +0200 Subject: [PATCH] Working formatting of weights for nodes and edges --- src/main.rs | 5 +- src/rsprocess/grammar.lalrpop | 95 +++++++++++++++++++++-- src/rsprocess/graph.rs | 5 +- src/rsprocess/presets.rs | 140 ++++++++++++++++++++++++++-------- testing/first.system | 2 +- 5 files changed, 206 insertions(+), 41 deletions(-) diff --git a/src/main.rs b/src/main.rs index 912121c..bfe917b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,12 @@ use reactionsystems::rsprocess::presets; fn main() { - // let now = std::time::Instant::now(); - // println!("{}", now.elapsed().as_micros()); + let now = std::time::Instant::now(); match presets::run("testing/first.system".into()) { Ok(_) => {}, Err(e) => {println!("{e}")} } + + println!("{} milliseconds elapsed", now.elapsed().as_millis()); } diff --git a/src/rsprocess/grammar.lalrpop b/src/rsprocess/grammar.lalrpop index 1770446..17a92a2 100644 --- a/src/rsprocess/grammar.lalrpop +++ b/src/rsprocess/grammar.lalrpop @@ -12,6 +12,7 @@ use crate::rsprocess::structure::{RSset, use crate::rsprocess::translator::{Translator, IdType}; use crate::rsprocess::presets::Instructions; use crate::rsprocess::presets; +use crate::rsprocess::graph; grammar(translator: &mut Translator); @@ -37,12 +38,17 @@ match { "Dot", "GraphML", "Serialize", "Stats", "Target", "Run", "Loop", "Frequency", "LimitFrequency", "FastFrequency", "Digraph", - "Deserialize" + "Deserialize", + "Hide", "Entities", "MaskEntities", "MaskContext", + "Products", "MaskProducts", "Union", "MaskUnion", + "Difference", "MaskDifference", + "EntitiesDeleted", "MaskEntitiesDeleted", + "EntitiesAdded", "MaskEntitiesAdded" } else { r"[0-9]+" => NUMBER } else { - // r"([[:alpha:]]|\p{Emoji})([[:word:]]|\p{Emoji})*" => WORD - r"(\p{L}|\p{Emoji})(\p{L}|\p{Emoji}|\p{Dash}|\p{N})*" => WORD, + r"([[:alpha:]])([[:word:]])*" => WORD + // r"(\p{L}|\p{Emoji})(\p{L}|\p{Emoji}|\p{Dash}|\p{N})*" => WORD, } else { r#"".*""# => PATH, } else { @@ -245,11 +251,86 @@ SaveOptions: presets::SaveOptions = { } } + +LiteralSeparatorNode: presets::NodeDisplay = { + PATH => + presets::NodeDisplay::Separator( + <>.trim_end_matches("\"").trim_start_matches("\"").to_string() + ) +}; + +LiteralSeparatorEdge: presets::EdgeDisplay = { + PATH => + presets::EdgeDisplay::Separator( + <>.trim_end_matches("\"").trim_start_matches("\"").to_string() + ) +}; + +NodeDisplay: presets::NodeDisplay = { + "Hide" => presets::NodeDisplay::Display(graph::GraphMapNodes::Hide), + "Entities" => presets::NodeDisplay::Display(graph::GraphMapNodes::Entities), + "MaskEntities" => + presets::NodeDisplay::Display(graph::GraphMapNodes::MaskEntities{ mask }), + "Context" => presets::NodeDisplay::Display(graph::GraphMapNodes::Context) +} + +SeparatorNode: Vec = { + => vec![v], + )+> => + match e { + None => v.iter().fold(vec![], |mut acc, (a, b)| {acc.push(a.clone()); acc.push(b.clone()); acc.clone()}), + Some(e) => { + let mut v = v.iter().fold(vec![], |mut acc, (a, b)| {acc.push(a.clone()); acc.push(b.clone()); acc.clone()}); + v.push(e); + v + } + } +} + +EdgeDisplay: presets::EdgeDisplay = { + "Hide" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Hide), + "Products" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Products), + "MaskProducts" => + presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskEntities{ mask }), + "Entities" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Entities), + "MaskEntities" => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskEntities{ mask }), + "Context" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Context), + "MaskContext" => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskContext{ mask }), + "Union" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Union), + "MaskUnion" => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskUnion{ mask }), + "Difference" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Difference), + "MaskDifference" => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskDifference{ mask }), + "EntitiesDeleted" => presets::EdgeDisplay::Display(graph::GraphMapEdges::EntitiesDeleted), + "MaskEntitiesDeleted" => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskEntitiesDeleted{ mask }), + "EntitiesAdded" => presets::EdgeDisplay::Display(graph::GraphMapEdges::EntitiesAdded), + "MaskEntitiesAdded" => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskEntitiesAdded{ mask }), +} + +SeparatorEdge: Vec = { + => vec![v], + )+> => + match e { + None => v.iter().fold(vec![], |mut acc, (a, b)| {acc.push(a.clone()); acc.push(b.clone()); acc.clone()}), + Some(e) => { + let mut v = v.iter().fold(vec![], |mut acc, (a, b)| {acc.push(a.clone()); acc.push(b.clone()); acc.clone()}); + v.push(e); + v + } + } +} + + GraphSaveOptions: presets::GraphSaveOptions = { - "Dot" ">" => - presets::GraphSaveOptions::Dot { so }, - "GraphML" ">" => - presets::GraphSaveOptions::GraphML { so }, + "Dot" "|" ">" + => + presets::GraphSaveOptions::Dot { node_display: s_node, + edge_display: s_edge, + so }, + "GraphML" "|" ">" + => + presets::GraphSaveOptions::GraphML { node_display: s_node, + edge_display: s_edge, + so }, "Serialize" "(" ")" => presets::GraphSaveOptions::Serialize { path }, } diff --git a/src/rsprocess/graph.rs b/src/rsprocess/graph.rs index bfd2927..233ffc2 100644 --- a/src/rsprocess/graph.rs +++ b/src/rsprocess/graph.rs @@ -48,6 +48,7 @@ pub fn digraph( // Nodes ----------------------------------------------------------------------- /// Helper structure that specifies what information to display for nodes. +#[derive(Clone)] pub enum GraphMapNodes { Hide, Entities, @@ -55,7 +56,8 @@ pub enum GraphMapNodes { Context, } -type GraphMapNodesFnTy = dyn Fn(petgraph::prelude::NodeIndex, &RSsystem) -> String; +type GraphMapNodesFnTy = + dyn Fn(petgraph::prelude::NodeIndex, &RSsystem) -> String; /// Helper structure that holds a formatting function from node as RSsystem to /// string pub struct GraphMapNodesTy { @@ -133,6 +135,7 @@ impl From for Box { // Edges ----------------------------------------------------------------------- /// Helper structure that specifies what information to display for edges +#[derive(Clone)] pub enum GraphMapEdges { Hide, Products, diff --git a/src/rsprocess/presets.rs b/src/rsprocess/presets.rs index 096863a..0aabd0b 100644 --- a/src/rsprocess/presets.rs +++ b/src/rsprocess/presets.rs @@ -24,7 +24,6 @@ use super::*; // Structures // ----------------------------------------------------------------------------- -#[derive(Debug)] pub struct SaveOptions { pub print: bool, pub save: Option> @@ -57,14 +56,28 @@ impl Default for SaveOptions { } } -#[derive(Debug)] +#[derive(Clone)] +pub enum NodeDisplay { + Separator(String), + Display(graph::GraphMapNodes) +} + +#[derive(Clone)] +pub enum EdgeDisplay { + Separator(String), + Display(graph::GraphMapEdges) +} + pub enum GraphSaveOptions { - Dot { so: SaveOptions }, - GraphML { so: SaveOptions }, + Dot { node_display: Vec, + edge_display: Vec, + so: SaveOptions }, + GraphML { node_display: Vec, + edge_display: Vec, + so: SaveOptions }, Serialize { path: String } } -#[derive(Debug)] pub enum Instruction { Stats { so: SaveOptions }, Target { so: SaveOptions }, @@ -76,13 +89,11 @@ pub enum Instruction { Digraph { gso: Vec }, } -#[derive(Debug)] pub enum System { Deserialize { path: String }, RSsystem { sys: RSsystem } } -#[derive(Debug)] pub enum EvaluatedSystem { Graph { graph: Graph, translator: Translator }, @@ -93,22 +104,24 @@ pub enum EvaluatedSystem { impl System { pub fn compute( - &self, translator: Translator + &self, + translator: Translator ) -> Result { match self { Self::RSsystem { sys } => { - Ok(EvaluatedSystem::System { sys: sys.to_owned(), translator }) + Ok(EvaluatedSystem::System { sys: sys.to_owned(), + translator }) }, Self::Deserialize { path } => { let (graph, translator) = deserialize(path.into())?; - Ok(EvaluatedSystem::Graph { graph, translator }) + Ok(EvaluatedSystem::Graph { graph, + translator }) } } } } -#[derive(Debug)] pub struct Instructions { pub system: System, pub instructions: Vec @@ -489,29 +502,96 @@ pub fn digraph( // Output Functions // ----------------------------------------------------------------------------- +#[allow(clippy::type_complexity)] +fn generate_node_pringting_fn<'a>( + node_display: &'a Vec, + translator: Rc +) -> Box String + 'a> { + // The type cannot be aliased since rust doesnt like generics. + // We are iterating over the node_display and constructing a function + // (accumulator) that prints out our formatted nodes. So at each step we + // call the previous function and add the next string or function. + let mut accumulator: + Box String> + = Box::new(|_, _| String::new()); + for nd in node_display { + accumulator = + match nd { + NodeDisplay::Display(d) => { // retrieve from the graph module + // the correct formatting function + let val = translator.clone(); + Box::new( + move |i, n| (accumulator)(i, n) + + &graph::GraphMapNodesTy::from( + d.clone(), + val.clone() + ).get()(i, n)) + }, + NodeDisplay::Separator(s) => { // we have a string so simply + // add it at the end + Box::new( + move |i, n| (accumulator)(i, n) + s + ) + } + }; + } + accumulator +} + +#[allow(clippy::type_complexity)] +fn generate_edge_pringting_fn<'a>( + edge_display: &'a Vec, + translator: Rc +) -> Box String + 'a> { + // The type cannot be aliased since rust doesnt like generics. + // We are iterating over the edge_display and constructing a function + // (accumulator) that prints out our formatted nodes. So at each step we + // call the previous function and add the next string or function. + let mut accumulator: + Box String> + = Box::new(|_, _| String::new()); + for nd in edge_display { + accumulator = + match nd { + EdgeDisplay::Display(d) => { // retrieve from the graph module + // the correct formatting function + let val = translator.clone(); + Box::new( + move |i, n| (accumulator)(i, n) + + &graph::GraphMapEdgesTy::from( + d.clone(), + val.clone() + ).get()(i, n)) + }, + EdgeDisplay::Separator(s) => { // we have a string so simply + // add it at the end + Box::new( + move |i, n| (accumulator)(i, n) + s + ) + } + }; + } + accumulator +} + /// Writes the specified graph to a file in .dot format. -pub fn dot(system: &EvaluatedSystem) -> Result { +pub fn dot( + system: &EvaluatedSystem, + node_display: Vec, + edge_display: Vec +) -> Result +{ match system { EvaluatedSystem::System { sys:_, translator:_ } => Err("Supplied system is not a graph".into()), EvaluatedSystem::Graph { graph, translator } => { - let rc_translator = Rc::new(translator.to_owned()); + let rc_translator = Rc::new(translator.clone()); // map each value to the corresponding value we want to display + // this is awful but rust is not a functional language so its all + // fine... let modified_graph = graph.map( - |id, node| - graph::GraphMapNodesTy::from( - graph::GraphMapNodes::Entities, - Rc::clone(&rc_translator) - ).get()(id, node) - + "; " + - &graph::GraphMapNodesTy::from( - graph::GraphMapNodes::Context, - Rc::clone(&rc_translator) - ).get()(id, node), - graph::GraphMapEdgesTy::from( - graph::GraphMapEdges::EntitiesAdded, - Rc::clone(&rc_translator) - ).get() + generate_node_pringting_fn(&node_display, Rc::clone(&rc_translator)), + generate_edge_pringting_fn(&edge_display, rc_translator) ); let graph = Rc::new(graph.to_owned()); @@ -677,10 +757,10 @@ fn execute( for save in gso { digraph(system)?; match save { - GraphSaveOptions::Dot { so } => { - save_options!(dot(system)?, so); + GraphSaveOptions::Dot { node_display, edge_display, so } => { + save_options!(dot(system, node_display, edge_display)?, so); }, - GraphSaveOptions::GraphML { so } => { + GraphSaveOptions::GraphML { node_display:_, edge_display:_, so } => { save_options!(graphml(system)?, so); }, GraphSaveOptions::Serialize { path } => { diff --git a/testing/first.system b/testing/first.system index 39e9322..fc24bf4 100644 --- a/testing/first.system +++ b/testing/first.system @@ -4,4 +4,4 @@ Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)] Reactions: ([{a,b}, {c}, {b}]) -Digraph > Dot > Print \ No newline at end of file +Digraph > Dot Entities | Context "; " MaskDifference {a, b} > Print \ No newline at end of file