use crate::powl::simplify;
use crate::powl_arena::{Operator, PowlArena};
use crate::powl_process_tree::ProcessTree;
pub fn apply(tree: &ProcessTree) -> (PowlArena, u32) {
let mut arena = PowlArena::new();
let root = convert_node(&mut arena, tree);
let simplified = simplify::simplify(&mut arena, root);
(arena, simplified)
}
fn convert_node(arena: &mut PowlArena, tree: &ProcessTree) -> u32 {
match &tree.operator {
None => {
if let Some(label) = &tree.label {
arena.add_transition(Some(label.clone()))
} else {
arena.add_silent_transition()
}
}
Some(op) => {
let children: Vec<u32> = tree
.children
.iter()
.map(|c| convert_node(arena, c))
.collect();
match op {
crate::powl_process_tree::PtOperator::Xor => {
if children.len() < 2 {
children
.into_iter()
.next()
.unwrap_or(arena.add_silent_transition())
} else {
arena.add_operator(Operator::Xor, children)
}
}
crate::powl_process_tree::PtOperator::Loop => {
let mut kids = children;
while kids.len() < 2 {
kids.push(arena.add_silent_transition());
}
arena.add_operator(Operator::Loop, kids)
}
crate::powl_process_tree::PtOperator::Parallel => {
arena.add_strict_partial_order(children)
}
crate::powl_process_tree::PtOperator::Sequence => {
let spo_idx = arena.add_strict_partial_order(children.clone());
for i in 0..children.len() {
for j in (i + 1)..children.len() {
arena.add_order_edge(spo_idx, i, j).ok();
}
}
spo_idx
}
}
}
}
}
pub fn process_tree_to_powl(tree_json: &str) -> Result<(PowlArena, u32), String> {
let tree: ProcessTree =
serde_json::from_str(tree_json).map_err(|e| format!("invalid process tree JSON: {}", e))?;
Ok(apply(&tree))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_process_tree_leaf_and_operators() {
let tree = ProcessTree::leaf(Some("A".to_string()));
let (arena, root) = apply(&tree);
assert_eq!(arena.to_repr(root), "A");
let tree = ProcessTree::leaf(None);
let (arena, root) = apply(&tree);
assert_eq!(arena.to_repr(root), "tau");
let tree = ProcessTree::internal(
crate::powl_process_tree::PtOperator::Xor,
vec![
ProcessTree::leaf(Some("A".to_string())),
ProcessTree::leaf(Some("B".to_string())),
],
);
let (arena, root) = apply(&tree);
assert_eq!(arena.to_repr(root), "X ( A, B )");
let tree = ProcessTree::internal(
crate::powl_process_tree::PtOperator::Loop,
vec![
ProcessTree::leaf(Some("A".to_string())),
ProcessTree::leaf(None),
],
);
let (arena, root) = apply(&tree);
assert_eq!(arena.to_repr(root), "* ( A, tau )");
}
#[test]
fn test_process_tree_parallel_and_sequence() {
let tree = ProcessTree::internal(
crate::powl_process_tree::PtOperator::Parallel,
vec![
ProcessTree::leaf(Some("A".to_string())),
ProcessTree::leaf(Some("B".to_string())),
],
);
let (arena, root) = apply(&tree);
let repr = arena.to_repr(root);
assert!(repr.contains("A") && repr.contains("B"));
assert!(!repr.contains("-->"));
let tree = ProcessTree::internal(
crate::powl_process_tree::PtOperator::Sequence,
vec![
ProcessTree::leaf(Some("A".to_string())),
ProcessTree::leaf(Some("B".to_string())),
ProcessTree::leaf(Some("C".to_string())),
],
);
let (arena, root) = apply(&tree);
let repr = arena.to_repr(root);
assert!(repr.contains("A-->B") && repr.contains("B-->C"));
}
#[test]
fn test_process_tree_roundtrip() {
let tree = ProcessTree::internal(
crate::powl_process_tree::PtOperator::Xor,
vec![
ProcessTree::internal(
crate::powl_process_tree::PtOperator::Xor,
vec![
ProcessTree::leaf(Some("A".to_string())),
ProcessTree::leaf(Some("B".to_string())),
],
),
ProcessTree::leaf(Some("C".to_string())),
],
);
let (arena, root) = apply(&tree);
let repr = arena.to_repr(root);
assert!(repr.contains("A") && repr.contains("B") && repr.contains("C"));
use crate::powl::conversion::to_process_tree;
use crate::powl_parser::parse_powl_model_string;
let mut arena1 = PowlArena::new();
let root1 = parse_powl_model_string("X ( A, B )", &mut arena1).unwrap();
let pt = to_process_tree::apply(&arena1, root1);
let pt_json = serde_json::to_string(&pt).unwrap();
let (arena2, root2) = process_tree_to_powl(&pt_json).unwrap();
let repr = arena2.to_repr(root2);
assert!(repr.contains("A") && repr.contains("B"));
}
}