Working formatting of weights for nodes and edges

This commit is contained in:
elvis
2025-07-12 15:32:21 +02:00
parent dcb1e63c35
commit 483260c2a3
5 changed files with 206 additions and 41 deletions

View File

@ -1,11 +1,12 @@
use reactionsystems::rsprocess::presets; use reactionsystems::rsprocess::presets;
fn main() { fn main() {
// let now = std::time::Instant::now(); let now = std::time::Instant::now();
// println!("{}", now.elapsed().as_micros());
match presets::run("testing/first.system".into()) { match presets::run("testing/first.system".into()) {
Ok(_) => {}, Ok(_) => {},
Err(e) => {println!("{e}")} Err(e) => {println!("{e}")}
} }
println!("{} milliseconds elapsed", now.elapsed().as_millis());
} }

View File

@ -12,6 +12,7 @@ use crate::rsprocess::structure::{RSset,
use crate::rsprocess::translator::{Translator, IdType}; use crate::rsprocess::translator::{Translator, IdType};
use crate::rsprocess::presets::Instructions; use crate::rsprocess::presets::Instructions;
use crate::rsprocess::presets; use crate::rsprocess::presets;
use crate::rsprocess::graph;
grammar(translator: &mut Translator); grammar(translator: &mut Translator);
@ -37,12 +38,17 @@ match {
"Dot", "GraphML", "Serialize", "Dot", "GraphML", "Serialize",
"Stats", "Target", "Run", "Loop", "Frequency", "LimitFrequency", "Stats", "Target", "Run", "Loop", "Frequency", "LimitFrequency",
"FastFrequency", "Digraph", "FastFrequency", "Digraph",
"Deserialize" "Deserialize",
"Hide", "Entities", "MaskEntities", "MaskContext",
"Products", "MaskProducts", "Union", "MaskUnion",
"Difference", "MaskDifference",
"EntitiesDeleted", "MaskEntitiesDeleted",
"EntitiesAdded", "MaskEntitiesAdded"
} else { } else {
r"[0-9]+" => NUMBER r"[0-9]+" => NUMBER
} else { } else {
// r"([[:alpha:]]|\p{Emoji})([[:word:]]|\p{Emoji})*" => WORD r"([[:alpha:]])([[:word:]])*" => WORD
r"(\p{L}|\p{Emoji})(\p{L}|\p{Emoji}|\p{Dash}|\p{N})*" => WORD, // r"(\p{L}|\p{Emoji})(\p{L}|\p{Emoji}|\p{Dash}|\p{N})*" => WORD,
} else { } else {
r#"".*""# => PATH, r#"".*""# => PATH,
} else { } 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" <mask: Set> =>
presets::NodeDisplay::Display(graph::GraphMapNodes::MaskEntities{ mask }),
"Context" => presets::NodeDisplay::Display(graph::GraphMapNodes::Context)
}
SeparatorNode: Vec<presets::NodeDisplay> = {
<v: NodeDisplay> => vec![v],
<v:(<NodeDisplay> <LiteralSeparatorNode>)+> <e: NodeDisplay?> =>
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" <mask: Set> =>
presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskEntities{ mask }),
"Entities" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Entities),
"MaskEntities" <mask: Set> => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskEntities{ mask }),
"Context" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Context),
"MaskContext" <mask: Set> => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskContext{ mask }),
"Union" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Union),
"MaskUnion" <mask: Set> => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskUnion{ mask }),
"Difference" => presets::EdgeDisplay::Display(graph::GraphMapEdges::Difference),
"MaskDifference" <mask: Set> => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskDifference{ mask }),
"EntitiesDeleted" => presets::EdgeDisplay::Display(graph::GraphMapEdges::EntitiesDeleted),
"MaskEntitiesDeleted" <mask: Set> => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskEntitiesDeleted{ mask }),
"EntitiesAdded" => presets::EdgeDisplay::Display(graph::GraphMapEdges::EntitiesAdded),
"MaskEntitiesAdded" <mask: Set> => presets::EdgeDisplay::Display(graph::GraphMapEdges::MaskEntitiesAdded{ mask }),
}
SeparatorEdge: Vec<presets::EdgeDisplay> = {
<v: EdgeDisplay> => vec![v],
<v:(<EdgeDisplay> <LiteralSeparatorEdge>)+> <e: EdgeDisplay?> =>
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 = { GraphSaveOptions: presets::GraphSaveOptions = {
"Dot" ">" <so: SaveOptions> => "Dot" <s_node: SeparatorNode> "|" <s_edge: SeparatorEdge> ">"
presets::GraphSaveOptions::Dot { so }, <so: SaveOptions> =>
"GraphML" ">" <so: SaveOptions> => presets::GraphSaveOptions::Dot { node_display: s_node,
presets::GraphSaveOptions::GraphML { so }, edge_display: s_edge,
so },
"GraphML" <s_node: SeparatorNode> "|" <s_edge: SeparatorEdge> ">"
<so: SaveOptions> =>
presets::GraphSaveOptions::GraphML { node_display: s_node,
edge_display: s_edge,
so },
"Serialize" "(" <path: Path> ")" => "Serialize" "(" <path: Path> ")" =>
presets::GraphSaveOptions::Serialize { path }, presets::GraphSaveOptions::Serialize { path },
} }

View File

@ -48,6 +48,7 @@ pub fn digraph(
// Nodes ----------------------------------------------------------------------- // Nodes -----------------------------------------------------------------------
/// Helper structure that specifies what information to display for nodes. /// Helper structure that specifies what information to display for nodes.
#[derive(Clone)]
pub enum GraphMapNodes { pub enum GraphMapNodes {
Hide, Hide,
Entities, Entities,
@ -55,7 +56,8 @@ pub enum GraphMapNodes {
Context, 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 /// Helper structure that holds a formatting function from node as RSsystem to
/// string /// string
pub struct GraphMapNodesTy { pub struct GraphMapNodesTy {
@ -133,6 +135,7 @@ impl From<GraphMapNodesTy> for Box<GraphMapNodesFnTy> {
// Edges ----------------------------------------------------------------------- // Edges -----------------------------------------------------------------------
/// Helper structure that specifies what information to display for edges /// Helper structure that specifies what information to display for edges
#[derive(Clone)]
pub enum GraphMapEdges { pub enum GraphMapEdges {
Hide, Hide,
Products, Products,

View File

@ -24,7 +24,6 @@ use super::*;
// Structures // Structures
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#[derive(Debug)]
pub struct SaveOptions { pub struct SaveOptions {
pub print: bool, pub print: bool,
pub save: Option<Vec<String>> pub save: Option<Vec<String>>
@ -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 { pub enum GraphSaveOptions {
Dot { so: SaveOptions }, Dot { node_display: Vec<NodeDisplay>,
GraphML { so: SaveOptions }, edge_display: Vec<EdgeDisplay>,
so: SaveOptions },
GraphML { node_display: Vec<NodeDisplay>,
edge_display: Vec<EdgeDisplay>,
so: SaveOptions },
Serialize { path: String } Serialize { path: String }
} }
#[derive(Debug)]
pub enum Instruction { pub enum Instruction {
Stats { so: SaveOptions }, Stats { so: SaveOptions },
Target { so: SaveOptions }, Target { so: SaveOptions },
@ -76,13 +89,11 @@ pub enum Instruction {
Digraph { gso: Vec<GraphSaveOptions> }, Digraph { gso: Vec<GraphSaveOptions> },
} }
#[derive(Debug)]
pub enum System { pub enum System {
Deserialize { path: String }, Deserialize { path: String },
RSsystem { sys: RSsystem } RSsystem { sys: RSsystem }
} }
#[derive(Debug)]
pub enum EvaluatedSystem { pub enum EvaluatedSystem {
Graph { graph: Graph<RSsystem, RSlabel>, Graph { graph: Graph<RSsystem, RSlabel>,
translator: Translator }, translator: Translator },
@ -93,22 +104,24 @@ pub enum EvaluatedSystem {
impl System { impl System {
pub fn compute( pub fn compute(
&self, translator: Translator &self,
translator: Translator
) -> Result<EvaluatedSystem, String> ) -> Result<EvaluatedSystem, String>
{ {
match self { match self {
Self::RSsystem { sys } => { Self::RSsystem { sys } => {
Ok(EvaluatedSystem::System { sys: sys.to_owned(), translator }) Ok(EvaluatedSystem::System { sys: sys.to_owned(),
translator })
}, },
Self::Deserialize { path } => { Self::Deserialize { path } => {
let (graph, translator) = deserialize(path.into())?; let (graph, translator) = deserialize(path.into())?;
Ok(EvaluatedSystem::Graph { graph, translator }) Ok(EvaluatedSystem::Graph { graph,
translator })
} }
} }
} }
} }
#[derive(Debug)]
pub struct Instructions { pub struct Instructions {
pub system: System, pub system: System,
pub instructions: Vec<Instruction> pub instructions: Vec<Instruction>
@ -489,29 +502,96 @@ pub fn digraph(
// Output Functions // Output Functions
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#[allow(clippy::type_complexity)]
fn generate_node_pringting_fn<'a>(
node_display: &'a Vec<NodeDisplay>,
translator: Rc<Translator>
) -> Box<dyn Fn(petgraph::prelude::NodeIndex, &'a RSsystem) -> 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<dyn Fn(petgraph::prelude::NodeIndex, &RSsystem) -> 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<EdgeDisplay>,
translator: Rc<Translator>
) -> Box<dyn Fn(petgraph::prelude::EdgeIndex, &'a RSlabel) -> 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<dyn Fn(petgraph::prelude::EdgeIndex, &RSlabel) -> 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. /// Writes the specified graph to a file in .dot format.
pub fn dot(system: &EvaluatedSystem) -> Result<String, String> { pub fn dot(
system: &EvaluatedSystem,
node_display: Vec<NodeDisplay>,
edge_display: Vec<EdgeDisplay>
) -> Result<String, String>
{
match system { match system {
EvaluatedSystem::System { sys:_, translator:_ } => EvaluatedSystem::System { sys:_, translator:_ } =>
Err("Supplied system is not a graph".into()), 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.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
// fine...
let modified_graph = graph.map( let modified_graph = graph.map(
|id, node| generate_node_pringting_fn(&node_display, Rc::clone(&rc_translator)),
graph::GraphMapNodesTy::from( generate_edge_pringting_fn(&edge_display, rc_translator)
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()
); );
let graph = Rc::new(graph.to_owned()); let graph = Rc::new(graph.to_owned());
@ -677,10 +757,10 @@ fn execute(
for save in gso { for save in gso {
digraph(system)?; digraph(system)?;
match save { match save {
GraphSaveOptions::Dot { so } => { GraphSaveOptions::Dot { node_display, edge_display, so } => {
save_options!(dot(system)?, 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); save_options!(graphml(system)?, so);
}, },
GraphSaveOptions::Serialize { path } => { GraphSaveOptions::Serialize { path } => {

View File

@ -4,4 +4,4 @@ Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)]
Reactions: ([{a,b}, {c}, {b}]) Reactions: ([{a,b}, {c}, {b}])
Digraph > Dot > Print Digraph > Dot Entities | Context "; " MaskDifference {a, b} > Print