Change VF2++ to VF2

This commit is contained in:
Owen Troke-Billard 2024-09-16 10:46:47 -06:00
parent 8a4c88eff9
commit da151176fe
4 changed files with 47 additions and 54 deletions

View File

@ -1,6 +1,6 @@
# `gb_vf2pp` — VF2++ in Rust # `vf2` — VF2 subgraph isomorphism algorithm in Rust
This crate implements the VF2++ subgraph isomorphism algorithm [1]. This crate implements the VF2 subgraph isomorphism algorithm [1].
It can find It can find
[graph isomorphisms](https://en.wikipedia.org/wiki/Graph_isomorphism), [graph isomorphisms](https://en.wikipedia.org/wiki/Graph_isomorphism),
[subgraph isomorphisms](https://en.wikipedia.org/wiki/Subgraph_isomorphism_problem), [subgraph isomorphisms](https://en.wikipedia.org/wiki/Subgraph_isomorphism_problem),
@ -8,35 +8,28 @@ and [induced subgraph isomorphisms](https://en.wikipedia.org/wiki/Induced_subgra
# Features # Features
This is a work in progress. Some features are not yet implemented.
- [x] Enumerate graph isomorphisms - [x] Enumerate graph isomorphisms
- [x] Enumerate subgraph isomorphisms - [x] Enumerate subgraph isomorphisms
- [x] Enumerate induced subgraph isomorphisms - [x] Enumerate induced subgraph isomorphisms
- [ ] Find minimum cost isomorphism
- [x] Support directed graphs - [x] Support directed graphs
- [x] Support undirected graphs - [x] Support undirected graphs
- [x] Support disconnected graphs - [x] Support disconnected graphs
- [x] Support node labels - [x] Support node labels
- [x] Support edge labels - [x] Support edge labels
- [x] Graph trait - [x] Graph trait
- [ ] Performance benchmarks
- [ ] Test databases
- [ ] Examples
# Remaining work # Remaining work
- [ ] Implement VF2 cutting rules - [ ] Implement VF2 cutting rules
- [ ] Implement all of VF2++ (only VF2 implemented so far)
# References # References
[1] A. Jüttner and P. Madarasi, [1] L. P. Cordella, P. Foggia, C. Sansone, and M. Vento,
“VF2++—An improved subgraph isomorphism algorithm,”
Discrete Applied Mathematics, vol. 242, pp. 6981,
Jun. 2018, doi: https://doi.org/10.1016/j.dam.2018.02.018.
[2] L. P. Cordella, P. Foggia, C. Sansone, and M. Vento,
“A (sub)graph isomorphism algorithm for matching large graphs,” “A (sub)graph isomorphism algorithm for matching large graphs,”
IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 26, no. 10, pp. 13671372, IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 26, no. 10, pp. 13671372,
Oct. 2004, doi: https://doi.org/10.1109/tpami.2004.75. Oct. 2004, doi: https://doi.org/10.1109/tpami.2004.75.
[2] A. Jüttner and P. Madarasi,
“VF2++—An improved subgraph isomorphism algorithm,”
Discrete Applied Mathematics, vol. 242, pp. 6981,
Jun. 2018, doi: https://doi.org/10.1016/j.dam.2018.02.018.

View File

@ -1,72 +1,72 @@
use crate::{Graph, Isomorphism, IsomorphismIter}; use crate::{Graph, Isomorphism, IsomorphismIter};
use std::fmt::Debug; use std::fmt::Debug;
/// Creates a new [`Vf2ppBuilder`] to find /// Creates a new [`Vf2Builder`] to find
/// isomorphisms from `query` to `data`. /// isomorphisms from `query` to `data`.
/// ///
/// Node and edge equality are not checked by default. /// Node and edge equality are not checked by default.
/// Use [`node_eq`], [`edge_eq`], and [`default_eq`] /// Use [`node_eq`], [`edge_eq`], and [`default_eq`]
/// on the builder to set equality functions. /// on the builder to set equality functions.
/// ///
/// [`node_eq`]: Vf2ppBuilder::node_eq /// [`node_eq`]: Vf2Builder::node_eq
/// [`edge_eq`]: Vf2ppBuilder::edge_eq /// [`edge_eq`]: Vf2Builder::edge_eq
/// [`default_eq`]: Vf2ppBuilder::default_eq /// [`default_eq`]: Vf2Builder::default_eq
pub fn isomorphisms<'a, Query, Data>( pub fn isomorphisms<'a, Query, Data>(
query: &'a Query, query: &'a Query,
data: &'a Data, data: &'a Data,
) -> DefaultVf2ppBuilder<'a, Query, Data> ) -> DefaultVf2Builder<'a, Query, Data>
where where
Query: Graph, Query: Graph,
Data: Graph, Data: Graph,
{ {
DefaultVf2ppBuilder::new(Problem::Isomorphism, query, data) DefaultVf2Builder::new(Problem::Isomorphism, query, data)
} }
/// Creates a new [`Vf2ppBuilder`] to find /// Creates a new [`Vf2Builder`] to find
/// subgraph isomorphisms from `query` to `data`. /// subgraph isomorphisms from `query` to `data`.
/// ///
/// Node and edge equality are not checked by default. /// Node and edge equality are not checked by default.
/// Use [`node_eq`], [`edge_eq`], and [`default_eq`] /// Use [`node_eq`], [`edge_eq`], and [`default_eq`]
/// on the builder to set equality functions. /// on the builder to set equality functions.
/// ///
/// [`node_eq`]: Vf2ppBuilder::node_eq /// [`node_eq`]: Vf2Builder::node_eq
/// [`edge_eq`]: Vf2ppBuilder::edge_eq /// [`edge_eq`]: Vf2Builder::edge_eq
/// [`default_eq`]: Vf2ppBuilder::default_eq /// [`default_eq`]: Vf2Builder::default_eq
pub fn subgraph_isomorphisms<'a, Query, Data>( pub fn subgraph_isomorphisms<'a, Query, Data>(
query: &'a Query, query: &'a Query,
data: &'a Data, data: &'a Data,
) -> DefaultVf2ppBuilder<'a, Query, Data> ) -> DefaultVf2Builder<'a, Query, Data>
where where
Query: Graph, Query: Graph,
Data: Graph, Data: Graph,
{ {
DefaultVf2ppBuilder::new(Problem::SubgraphIsomorphism, query, data) DefaultVf2Builder::new(Problem::SubgraphIsomorphism, query, data)
} }
/// Creates a new [`Vf2ppBuilder`] to find /// Creates a new [`Vf2Builder`] to find
/// induced subgraph isomorphisms from `query` to `data`. /// induced subgraph isomorphisms from `query` to `data`.
/// ///
/// Node and edge equality are not checked by default. /// Node and edge equality are not checked by default.
/// Use [`node_eq`], [`edge_eq`], and [`default_eq`] /// Use [`node_eq`], [`edge_eq`], and [`default_eq`]
/// on the builder to set equality functions. /// on the builder to set equality functions.
/// ///
/// [`node_eq`]: Vf2ppBuilder::node_eq /// [`node_eq`]: Vf2Builder::node_eq
/// [`edge_eq`]: Vf2ppBuilder::edge_eq /// [`edge_eq`]: Vf2Builder::edge_eq
/// [`default_eq`]: Vf2ppBuilder::default_eq /// [`default_eq`]: Vf2Builder::default_eq
pub fn induced_subgraph_isomorphisms<'a, Query, Data>( pub fn induced_subgraph_isomorphisms<'a, Query, Data>(
query: &'a Query, query: &'a Query,
data: &'a Data, data: &'a Data,
) -> DefaultVf2ppBuilder<'a, Query, Data> ) -> DefaultVf2Builder<'a, Query, Data>
where where
Query: Graph, Query: Graph,
Data: Graph, Data: Graph,
{ {
DefaultVf2ppBuilder::new(Problem::InducedSubgraphIsomorphism, query, data) DefaultVf2Builder::new(Problem::InducedSubgraphIsomorphism, query, data)
} }
/// A VF2++ builder. /// A VF2 builder.
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Vf2ppBuilder<'a, Query, Data, NodeEq, EdgeEq> { pub struct Vf2Builder<'a, Query, Data, NodeEq, EdgeEq> {
/// Problem type. /// Problem type.
problem: Problem, problem: Problem,
/// Query graph. /// Query graph.
@ -79,11 +79,11 @@ pub struct Vf2ppBuilder<'a, Query, Data, NodeEq, EdgeEq> {
edge_eq: Option<EdgeEq>, edge_eq: Option<EdgeEq>,
} }
/// Default VF2++ builder type. /// Default VF2 builder type.
/// ///
/// This is [`Vf2ppBuilder`] with function pointers as /// This is [`Vf2Builder`] with function pointers as
/// the node and edge equality function types. /// the node and edge equality function types.
pub type DefaultVf2ppBuilder<'a, Query, Data> = Vf2ppBuilder< pub type DefaultVf2Builder<'a, Query, Data> = Vf2Builder<
'a, 'a,
Query, Query,
Data, Data,
@ -91,12 +91,12 @@ pub type DefaultVf2ppBuilder<'a, Query, Data> = Vf2ppBuilder<
fn(&<Query as Graph>::EdgeLabel, &<Data as Graph>::EdgeLabel) -> bool, fn(&<Query as Graph>::EdgeLabel, &<Data as Graph>::EdgeLabel) -> bool,
>; >;
impl<'a, Query, Data> DefaultVf2ppBuilder<'a, Query, Data> impl<'a, Query, Data> DefaultVf2Builder<'a, Query, Data>
where where
Query: Graph, Query: Graph,
Data: Graph, Data: Graph,
{ {
/// Creates a new [`Vf2ppBuilder`] that does not check /// Creates a new [`Vf2Builder`] that does not check
/// node and edge equality. /// node and edge equality.
fn new(problem: Problem, query: &'a Query, data: &'a Data) -> Self { fn new(problem: Problem, query: &'a Query, data: &'a Data) -> Self {
Self { Self {
@ -109,21 +109,21 @@ where
} }
} }
impl<'a, Query, Data, NodeEq, EdgeEq> Vf2ppBuilder<'a, Query, Data, NodeEq, EdgeEq> impl<'a, Query, Data, NodeEq, EdgeEq> Vf2Builder<'a, Query, Data, NodeEq, EdgeEq>
where where
Query: Graph, Query: Graph,
Data: Graph, Data: Graph,
NodeEq: Fn(&Query::NodeLabel, &Data::NodeLabel) -> bool, NodeEq: Fn(&Query::NodeLabel, &Data::NodeLabel) -> bool,
EdgeEq: Fn(&Query::EdgeLabel, &Data::EdgeLabel) -> bool, EdgeEq: Fn(&Query::EdgeLabel, &Data::EdgeLabel) -> bool,
{ {
/// Configures VF2++ to use the [`PartialEq`] implementations /// Configures VF2 to use the [`PartialEq`] implementations
/// for node and edge equalities. /// for node and edge equalities.
pub fn default_eq(self) -> DefaultVf2ppBuilder<'a, Query, Data> pub fn default_eq(self) -> DefaultVf2Builder<'a, Query, Data>
where where
Query::NodeLabel: PartialEq<Data::NodeLabel>, Query::NodeLabel: PartialEq<Data::NodeLabel>,
Query::EdgeLabel: PartialEq<Data::EdgeLabel>, Query::EdgeLabel: PartialEq<Data::EdgeLabel>,
{ {
Vf2ppBuilder { Vf2Builder {
problem: self.problem, problem: self.problem,
query: self.query, query: self.query,
data: self.data, data: self.data,
@ -132,15 +132,15 @@ where
} }
} }
/// Configures VF2++ to use `node_eq` as the node equality function. /// Configures VF2 to use `node_eq` as the node equality function.
pub fn node_eq<NewNodeEq>( pub fn node_eq<NewNodeEq>(
self, self,
node_eq: NewNodeEq, node_eq: NewNodeEq,
) -> Vf2ppBuilder<'a, Query, Data, NewNodeEq, EdgeEq> ) -> Vf2Builder<'a, Query, Data, NewNodeEq, EdgeEq>
where where
NewNodeEq: Fn(&Query::NodeLabel, &Data::NodeLabel) -> bool, NewNodeEq: Fn(&Query::NodeLabel, &Data::NodeLabel) -> bool,
{ {
Vf2ppBuilder { Vf2Builder {
problem: self.problem, problem: self.problem,
query: self.query, query: self.query,
data: self.data, data: self.data,
@ -149,15 +149,15 @@ where
} }
} }
/// Configures VF2++ to use `edge_eq` as the edge equality function. /// Configures VF2 to use `edge_eq` as the edge equality function.
pub fn edge_eq<NewEdgeEq>( pub fn edge_eq<NewEdgeEq>(
self, self,
edge_eq: NewEdgeEq, edge_eq: NewEdgeEq,
) -> Vf2ppBuilder<'a, Query, Data, NodeEq, NewEdgeEq> ) -> Vf2Builder<'a, Query, Data, NodeEq, NewEdgeEq>
where where
NewEdgeEq: Fn(&Query::EdgeLabel, &Data::EdgeLabel) -> bool, NewEdgeEq: Fn(&Query::EdgeLabel, &Data::EdgeLabel) -> bool,
{ {
Vf2ppBuilder { Vf2Builder {
problem: self.problem, problem: self.problem,
query: self.query, query: self.query,
data: self.data, data: self.data,

View File

@ -24,13 +24,13 @@ pub trait Graph {
/// Returns `true` if there is an edge from `source` to `target`. /// Returns `true` if there is an edge from `source` to `target`.
/// ///
/// If the graph is directed, the edge must must go from `source` to `target`. /// If the graph is directed, the edge must go from `source` to `target`.
/// If undirected, an edge must exist between `source` and `target`. /// If undirected, an edge must exist between `source` and `target`.
fn contains_edge(&self, source: NodeIndex, target: NodeIndex) -> bool; fn contains_edge(&self, source: NodeIndex, target: NodeIndex) -> bool;
/// Returns a reference to the label of the edge from `source` to `target`. /// Returns a reference to the label of the edge from `source` to `target`.
/// ///
/// If the graph is directed, the edge must must go from `source` to `target`. /// If the graph is directed, the edge must go from `source` to `target`.
/// If undirected, the edge must be between `source` and `target`. /// If undirected, the edge must be between `source` and `target`.
fn edge_label(&self, source: NodeIndex, target: NodeIndex) -> Option<&Self::EdgeLabel>; fn edge_label(&self, source: NodeIndex, target: NodeIndex) -> Option<&Self::EdgeLabel>;
} }

View File

@ -261,9 +261,9 @@ fn isomorphisms_same_size() {
vf2::isomorphisms(&query, &data).vec(); vf2::isomorphisms(&query, &data).vec();
} }
/// Tests that [`Debug`] is implemented for [`Vf2ppBuilder`]. /// Tests that [`Debug`] is implemented for [`Vf2Builder`].
/// ///
/// [`Vf2ppBuilder`]: vf2::Vf2ppBuilder /// [`Vf2Builder`]: vf2::Vf2Builder
#[test] #[test]
fn builder_debug() { fn builder_debug() {
let (query, data) = small_graphs::<Directed>(); let (query, data) = small_graphs::<Directed>();