blob: 483416e9cd7d625c984678a235e11bd500ec65a2 [file] [log] [blame]
mod matching;
mod semantic;
mod state;
use alloc::vec::Vec;
use petgraph_core::deprecated::{
data::DataMap,
visit::{
EdgeCount, GetAdjacencyMatrix, GraphProp, IntoEdgesDirected, IntoNeighborsDirected,
NodeCompactIndexable,
},
};
use crate::isomorphism::{semantic::NoSemanticMatch, state::Vf2State};
/// \[Generic\] Return `true` if the graphs `g0` and `g1` are isomorphic.
///
/// Using the VF2 algorithm, only matching graph syntactically (graph
/// structure).
///
/// The graphs should not be multigraphs.
///
/// **Reference**
///
/// * Luigi P. Cordella, Pasquale Foggia, Carlo Sansone, Mario Vento; *A (Sub)Graph Isomorphism
/// Algorithm for Matching Large Graphs*
pub fn is_isomorphic<G0, G1>(g0: G0, g1: G1) -> bool
where
G0: NodeCompactIndexable + EdgeCount + GetAdjacencyMatrix + GraphProp + IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoNeighborsDirected,
{
if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
matching::try_match(&mut st, &mut NoSemanticMatch, &mut NoSemanticMatch, false).unwrap_or(false)
}
/// \[Generic\] Return `true` if the graphs `g0` and `g1` are isomorphic.
///
/// Using the VF2 algorithm, examining both syntactic and semantic
/// graph isomorphism (graph structure and matching node and edge weights).
///
/// The graphs should not be multigraphs.
pub fn is_isomorphic_matching<G0, G1, NM, EM>(
g0: G0,
g1: G1,
mut node_match: NM,
mut edge_match: EM,
) -> bool
where
G0: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp
+ IntoEdgesDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoEdgesDirected,
NM: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
EM: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
matching::try_match(&mut st, &mut node_match, &mut edge_match, false).unwrap_or(false)
}
/// \[Generic\] Return `true` if `g0` is isomorphic to a subgraph of `g1`.
///
/// Using the VF2 algorithm, only matching graph syntactically (graph
/// structure).
///
/// The graphs should not be multigraphs.
///
/// # Subgraph isomorphism
///
/// (adapted from [`networkx` documentation](https://networkx.github.io/documentation/stable/reference/algorithms/isomorphism.vf2.html))
///
/// Graph theory literature can be ambiguous about the meaning of the above statement,
/// and we seek to clarify it now.
///
/// In the VF2 literature, a mapping **M** is said to be a *graph-subgraph isomorphism*
/// iff **M** is an isomorphism between **G2** and a subgraph of **G1**. Thus, to say
/// that **G1** and **G2** are graph-subgraph isomorphic is to say that a subgraph of
/// **G1** is isomorphic to **G2**.
///
/// Other literature uses the phrase ‘subgraph isomorphic’ as in
/// ‘**G1** does not have a subgraph isomorphic to **G2**’. Another use is as an in adverb
/// for isomorphic. Thus, to say that **G1** and **G2** are subgraph isomorphic is to say
/// that a subgraph of **G1** is isomorphic to **G2**.
///
/// Finally, the term ‘subgraph’ can have multiple meanings. In this context,
/// ‘subgraph’ always means a ‘node-induced subgraph’. Edge-induced subgraph
/// isomorphisms are not directly supported. For subgraphs which are not
/// induced, the term ‘monomorphism’ is preferred over ‘isomorphism’.
///
/// **Reference**
///
/// * Luigi P. Cordella, Pasquale Foggia, Carlo Sansone, Mario Vento; *A (Sub)Graph Isomorphism
/// Algorithm for Matching Large Graphs*
pub fn is_isomorphic_subgraph<G0, G1>(g0: G0, g1: G1) -> bool
where
G0: NodeCompactIndexable + EdgeCount + GetAdjacencyMatrix + GraphProp + IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoNeighborsDirected,
{
if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
matching::try_match(&mut st, &mut NoSemanticMatch, &mut NoSemanticMatch, true).unwrap_or(false)
}
/// \[Generic\] Return `true` if `g0` is isomorphic to a subgraph of `g1`.
///
/// Using the VF2 algorithm, examining both syntactic and semantic
/// graph isomorphism (graph structure and matching node and edge weights).
///
/// The graphs should not be multigraphs.
pub fn is_isomorphic_subgraph_matching<G0, G1, NM, EM>(
g0: G0,
g1: G1,
mut node_match: NM,
mut edge_match: EM,
) -> bool
where
G0: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp
+ IntoEdgesDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoEdgesDirected,
NM: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
EM: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
matching::try_match(&mut st, &mut node_match, &mut edge_match, true).unwrap_or(false)
}
/// Using the VF2 algorithm, examine both syntactic and semantic graph
/// isomorphism (graph structure and matching node and edge weights) and,
/// if `g0` is isomorphic to a subgraph of `g1`, return the mappings between
/// them.
///
/// The graphs should not be multigraphs.
pub fn subgraph_isomorphisms_iter<'a, G0, G1, NM, EM>(
g0: &'a G0,
g1: &'a G1,
node_match: &'a mut NM,
edge_match: &'a mut EM,
) -> Option<impl Iterator<Item = Vec<usize>> + 'a>
where
G0: 'a
+ NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp
+ IntoEdgesDirected,
G1: 'a
+ NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoEdgesDirected,
NM: 'a + FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
EM: 'a + FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
return None;
}
Some(matching::GraphMatcher::new(
g0, g1, node_match, edge_match, true,
))
}