diff --git a/src/examples.rs b/src/examples.rs index eccf0f2..642dbf5 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -1,7 +1,9 @@ #![allow(dead_code)] +use petgraph::dot::Dot; + use crate::rsprocess::structure::{RSset, RSsystem}; -use crate::rsprocess::translator; +use crate::rsprocess::{graph, translator}; use crate::rsprocess::translator::Translator; use crate::rsprocess::{frequency, perpetual, statistics, transitions}; @@ -229,3 +231,33 @@ pub fn fast_freq() -> std::io::Result<()> { Ok(()) } + +// equivalent to main_do(digraph, Arcs) +pub fn digraph() -> 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_file(&mut translator, path, parser_system)?; + + // the system needs to terminate to return + let res = match graph::digraph(system) { + Ok(o) => o, + Err(e) => { + println!("Error computing target: {e}"); + return Ok(()); + } + }; + + println!("Generated graph in dot notation:\n{:?}\n", Dot::new(&res)); + + let res = res.map(|_, node| format!("{}; {}", + translator::RSsetDisplay::from(&translator, node.get_available_entities()), + translator::RSprocessDisplay::from(&translator, node.get_context_process())), + |_, edge| translator::RSsetDisplay::from(&translator, &edge.context)); + + println!("Generated graph in dot notation:\n{}", Dot::new(&res)); + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 56c36c3..e7317c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ fn main() -> std::io::Result<()> { // examples::stats()?; - examples::freq()?; + // examples::freq()?; // examples::hoop()?; @@ -25,5 +25,7 @@ fn main() -> std::io::Result<()> { // examples::fast_freq()?; + examples::digraph()?; + Ok(()) } diff --git a/src/rsprocess/graph.rs b/src/rsprocess/graph.rs new file mode 100644 index 0000000..52ca3ef --- /dev/null +++ b/src/rsprocess/graph.rs @@ -0,0 +1,39 @@ +#![allow(dead_code)] + +use petgraph::Graph; +use std::collections::HashMap; +use super::structure::{RSlabel, RSsystem}; +use super::support_structures::TransitionsIterator; + +pub fn digraph( + system: RSsystem +) -> Result, String> { + let mut graph: Graph = Graph::new(); + let node = graph.add_node(system.clone()); + + let mut association = HashMap::new(); + association.insert(system.clone(), node); + + let mut stack = vec![system]; + let mut current; + + + while !stack.is_empty() { + // depth first + current = stack.pop().unwrap(); + let current_node = *association.get(¤t).unwrap(); + + // cycle through all next nodes + let tr = TransitionsIterator::from(¤t)?; + + for (label, next) in tr { + // if not already visited + let next_node = association.entry(next.clone()).or_insert_with(|| { + stack.push(next.clone()); + graph.add_node(next) + }); + graph.add_edge(current_node, *next_node, label); + } + } + Ok(graph) +} diff --git a/src/rsprocess/mod.rs b/src/rsprocess/mod.rs index 0d88a94..52662b0 100644 --- a/src/rsprocess/mod.rs +++ b/src/rsprocess/mod.rs @@ -7,3 +7,4 @@ pub mod structure; pub mod support_structures; pub mod transitions; pub mod translator; +pub mod graph; diff --git a/src/rsprocess/structure.rs b/src/rsprocess/structure.rs index dd97d35..077dde1 100644 --- a/src/rsprocess/structure.rs +++ b/src/rsprocess/structure.rs @@ -182,7 +182,7 @@ impl Default for RSreaction { // ----------------------------------------------------------------------------- // RSprocess // ----------------------------------------------------------------------------- -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum RSprocess { Nill, RecursiveIdentifier { @@ -475,6 +475,24 @@ impl RSsystem { } } +impl PartialEq for RSsystem { + // we ignore delta and reaction rules + fn eq(&self, other: &RSsystem) -> bool { + self.available_entities == other.available_entities && + self.context_process == other.context_process + } +} + +impl Eq for RSsystem {} + +impl Hash for RSsystem { + // ignores delta and reaction rules + fn hash(&self, state: &mut H) { + self.available_entities.hash(state); + self.context_process.hash(state); + } +} + impl Default for RSsystem { fn default() -> Self { RSsystem::new() diff --git a/src/rsprocess/translator.rs b/src/rsprocess/translator.rs index 3f86d34..16da0d2 100644 --- a/src/rsprocess/translator.rs +++ b/src/rsprocess/translator.rs @@ -141,7 +141,7 @@ fn print_process( use super::structure::RSprocess::*; match process { Nill => { - write!(f, "[Nill]") + write!(f, "Nill") } RecursiveIdentifier { identifier } => { write!(f, @@ -154,7 +154,7 @@ fn print_process( } => { write!( f, - "[entities: {}, next_process: {}]", + "{}.{}", RSsetDisplay::from(translator, entities), RSprocessDisplay::from(translator, next_process) ) @@ -166,7 +166,7 @@ fn print_process( } => { write!( f, - "[repeat: {repeat}, repeated_process: {}, next_process: {}]", + "({})^{repeat}.{}", RSprocessDisplay::from(translator, repeated_process), RSprocessDisplay::from(translator, next_process) ) diff --git a/testing/first.system b/testing/first.system index 3314710..aadc18c 100644 --- a/testing/first.system +++ b/testing/first.system @@ -1,4 +1,4 @@ -Environment: [x = {a}.y, y =({a}.nill + {b}.nill)] +Environment: [x = {a}.y, y =({a}.x + {b}.y)] Initial Entities: {a, b} Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)] Reactions: ([r: {a,b}, i: {c}, p: {b}])