bisimilarity working?
This commit is contained in:
174
src/rsprocess/bisimilarity.rs
Normal file
174
src/rsprocess/bisimilarity.rs
Normal file
@ -0,0 +1,174 @@
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
use petgraph::visit::{EdgeIndexable, EdgeRef, IntoEdgeReferences, IntoEdges, IntoNodeReferences, NodeIndexable};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn print_type_of<T>(_: &T) {
|
||||
println!("type: {}", std::any::type_name::<T>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct GraphPartition<'a, G>
|
||||
where
|
||||
G: EdgeIndexable + NodeIndexable + IntoEdgeReferences + IntoNodeReferences
|
||||
+ IntoEdges,
|
||||
G::NodeId: std::cmp::Eq + std::hash::Hash,
|
||||
{
|
||||
pub node_to_block: HashMap<(usize, G::NodeId), u32>,
|
||||
pub block_to_node: HashMap<u32, Vec<(usize, G::NodeId)>>,
|
||||
pub graphs: [&'a G; 2],
|
||||
last_block: u32,
|
||||
blocks: BTreeSet<u32>
|
||||
}
|
||||
|
||||
impl<'a, G> GraphPartition<'a, G>
|
||||
where
|
||||
G: EdgeIndexable + NodeIndexable + IntoEdgeReferences + IntoNodeReferences
|
||||
+ IntoEdges,
|
||||
G::NodeId: std::cmp::Eq + std::hash::Hash,
|
||||
{
|
||||
pub fn new(graph_a: &'a G, graph_b: &'a G) -> Self {
|
||||
GraphPartition { node_to_block: HashMap::new(),
|
||||
block_to_node: HashMap::new(),
|
||||
graphs: [graph_a, graph_b],
|
||||
last_block: 0,
|
||||
blocks: BTreeSet::new() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_node_last_partition(&mut self, node: G::NodeId, graph: usize) {
|
||||
self.node_to_block.insert((graph, node), self.last_block);
|
||||
self.block_to_node
|
||||
.entry(self.last_block)
|
||||
.or_default()
|
||||
.push((graph, node));
|
||||
self.blocks.insert(self.last_block);
|
||||
}
|
||||
|
||||
pub fn iterate_blocks(&self) -> Vec<u32> {
|
||||
self.blocks.iter().cloned().collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn bisimilar(&self) -> bool {
|
||||
// if there is a block that has only elements from one graph then they are
|
||||
// not bisimilar
|
||||
for (_block, node_list) in self.block_to_node.iter() {
|
||||
let graph_id = node_list.first().unwrap().0;
|
||||
if node_list.iter().all(|el| el.0 == graph_id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn reachable_blocks(
|
||||
&self,
|
||||
label: &G::EdgeRef,
|
||||
s: &(usize, G::NodeId)
|
||||
) -> Vec<(usize, G::NodeId)>
|
||||
where <G as IntoEdgeReferences>::EdgeRef: PartialEq
|
||||
{
|
||||
let mut val = vec![];
|
||||
for el in self.graphs[s.0].edges(s.1).filter(|x| x == label) {
|
||||
val.push((s.0, el.target()));
|
||||
}
|
||||
val
|
||||
}
|
||||
|
||||
pub fn split(&mut self, block: u32, label: &G::EdgeRef) -> bool
|
||||
where <G as IntoEdgeReferences>::EdgeRef: PartialEq
|
||||
{
|
||||
let Some(nodes) = self.block_to_node.get(&block)
|
||||
else {
|
||||
return true
|
||||
};
|
||||
let mut nodes = nodes.iter();
|
||||
let s = nodes.next().unwrap();
|
||||
|
||||
let mut b1 = vec![s];
|
||||
let mut b2 = vec![];
|
||||
|
||||
let reachable_blocks_s = self.reachable_blocks(label, s);
|
||||
|
||||
'outer: for t in nodes {
|
||||
let reachable_blocks_t = self.reachable_blocks(label, t);
|
||||
for rbt in reachable_blocks_t {
|
||||
if !reachable_blocks_s.contains(&rbt) {
|
||||
b2.push(*t);
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
b1.push(t);
|
||||
}
|
||||
|
||||
if b2.is_empty() {
|
||||
// all elements go to the same block with label label, so no change
|
||||
false
|
||||
} else {
|
||||
// some elements need to be split into a different block
|
||||
self.last_block += 1;
|
||||
let new_block = self.last_block;
|
||||
self.blocks.insert(new_block);
|
||||
|
||||
for b in b2 {
|
||||
self.node_to_block.entry(b).and_modify(|e| *e = new_block);
|
||||
self.block_to_node.entry(new_block).or_default().push(b);
|
||||
self.block_to_node.entry(block).and_modify(|e| {
|
||||
let index = e.iter().position(|x| *x == b).unwrap();
|
||||
e.remove(index);
|
||||
});
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bisimilarity_kanellakis_smolka<'a, G>(
|
||||
graph_a: &'a G,
|
||||
graph_b: &'a G
|
||||
) -> bool
|
||||
where
|
||||
G: EdgeIndexable + NodeIndexable + IntoEdgeReferences + IntoNodeReferences
|
||||
+ IntoEdges,
|
||||
G::NodeId: std::cmp::Eq + std::hash::Hash,
|
||||
G::EdgeRef: PartialEq
|
||||
{
|
||||
let graphs = [graph_a, graph_b];
|
||||
|
||||
let mut partition: GraphPartition<G> = GraphPartition::new(graph_a, graph_b);
|
||||
for (p, graph) in graphs.iter().enumerate() {
|
||||
for node in graph.node_identifiers() {
|
||||
partition.add_node_last_partition(node, p);
|
||||
}
|
||||
}
|
||||
|
||||
let labels =
|
||||
graph_a.edge_references()
|
||||
.chain(graph_b.edge_references())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut changed = true;
|
||||
|
||||
while changed {
|
||||
changed = false;
|
||||
|
||||
for block in partition.iterate_blocks() {
|
||||
for label in labels.iter() {
|
||||
if partition.split(block, label) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partition.bisimilar()
|
||||
}
|
||||
Reference in New Issue
Block a user