public void ElementPseudo() { AtomMatcher matcher = AtomMatcher.CreateElementMatcher(); var m_atom1 = new Mock <IPseudoAtom>(); var m_atom2 = new Mock <IPseudoAtom>(); Assert.IsTrue(matcher.Matches(m_atom1.Object, m_atom2.Object)); Assert.IsTrue(matcher.Matches(m_atom2.Object, m_atom1.Object)); }
public void ElementMismatch() { AtomMatcher matcher = AtomMatcher.CreateElementMatcher(); var m_atom1 = new Mock <IAtom>(); var m_atom2 = new Mock <IAtom>(); m_atom1.SetupGet(n => n.AtomicNumber).Returns(6); m_atom2.SetupGet(n => n.AtomicNumber).Returns(8); Assert.IsFalse(matcher.Matches(m_atom1.Object, m_atom2.Object)); Assert.IsFalse(matcher.Matches(m_atom2.Object, m_atom1.Object)); }
public void QueryMatch() { AtomMatcher matcher = AtomMatcher.CreateQueryMatcher(); var m_atom1 = new Mock <IQueryAtom>(); var m_atom2 = new Mock <IAtom>(); var m_atom3 = new Mock <IAtom>(); m_atom1.Setup(n => n.Matches(m_atom2.Object)).Returns(true); m_atom1.Setup(n => n.Matches(m_atom3.Object)).Returns(false); Assert.IsTrue(matcher.Matches(m_atom1.Object, m_atom2.Object)); Assert.IsFalse(matcher.Matches(m_atom1.Object, m_atom3.Object)); }
/// <summary> /// Create a state for matching subgraphs using the Ullmann refinement /// procedure. /// </summary> /// <param name="container1">query container</param> /// <param name="container2">target container</param> /// <param name="g1">query container adjacency list</param> /// <param name="g2">target container adjacency list</param> /// <param name="bonds1">query container bond map</param> /// <param name="bonds2">target container bond map</param> /// <param name="atomMatcher">method of matching atom semantics</param> /// <param name="bondMatcher">method of matching bond semantics</param> public UllmannState(IAtomContainer container1, IAtomContainer container2, int[][] g1, int[][] g2, EdgeToBondMap bonds1, EdgeToBondMap bonds2, AtomMatcher atomMatcher, BondMatcher bondMatcher) { this.bondMatcher = bondMatcher; this.g1 = g1; this.g2 = g2; this.bond1 = bonds1; this.bonds2 = bonds2; this.m1 = new int[g1.Length]; this.m2 = new int[g2.Length]; Arrays.Fill(m1, UNMAPPED); Arrays.Fill(m2, UNMAPPED); // build up compatibility matrix matrix = new CompatibilityMatrix(g1.Length, g2.Length); for (int i = 0; i < g1.Length; i++) { for (int j = 0; j < g2.Length; j++) { if (g1[i].Length <= g2[j].Length && atomMatcher.Matches(container1.Atoms[i], container2.Atoms[j])) { matrix.Set1(i, j); } } } }
public void AnyMatch() { AtomMatcher matcher = AtomMatcher.CreateAnyMatcher(); var m_atom1 = new Mock <IAtom>(); var m_atom2 = new Mock <IAtom>(); var m_atom3 = new Mock <IAtom>(); m_atom1.SetupGet(n => n.AtomicNumber).Returns(6); m_atom2.SetupGet(n => n.AtomicNumber).Returns(7); m_atom3.SetupGet(n => n.AtomicNumber).Returns(8); Assert.IsTrue(matcher.Matches(m_atom1.Object, m_atom2.Object)); Assert.IsTrue(matcher.Matches(m_atom2.Object, m_atom1.Object)); Assert.IsTrue(matcher.Matches(m_atom1.Object, m_atom3.Object)); Assert.IsTrue(matcher.Matches(m_atom3.Object, m_atom1.Object)); Assert.IsTrue(matcher.Matches(m_atom2.Object, m_atom3.Object)); Assert.IsTrue(matcher.Matches(m_atom1.Object, null)); Assert.IsTrue(matcher.Matches(null, null)); }
/// <summary> /// Check the feasibility of the candidate pair {n, m}. /// </summary> /// <remarks> /// <para> /// A candidate pair is /// syntactically feasible iff all k-look-ahead rules hold. These look ahead /// rules check adjacency relation of the mapping. If an edge is mapped in g1 /// it should also be mapped in g2 and vise-versa (0-look-ahead). If an edge /// in g1 is unmapped but the edge is adjacent to an another mapped vertex /// (terminal) then the number of such edges should be less or equal in g1 /// compared to g2 (1-look-ahead). If the edge is unmapped and non-terminal /// then the number of such edges should be less or equal in g1 compared to /// g2 (2-look-ahead). /// </para> /// <para> /// The above feasibility rules are for /// subgraph-isomorphism and have been adapted for subgraph-monomorphism. For /// a monomorphism a mapped edge in g2 does not have to be present in g1. The /// 2-look-ahead also requires summing the terminal and remaining counts (or /// sorting the vertices). /// </para> /// <para> /// The semantic feasibility verifies that the /// labels the label n, m are compatabile and that the label on each matched /// edge is compatabile. /// </para> /// </remarks> /// <param name="n">a candidate vertex from g1</param> /// <param name="m">a candidate vertex from g2</param> /// <returns>the mapping is feasible</returns> public override bool Feasible(int n, int m) { // verify atom semantic feasibility if (!atomMatcher.Matches(container1.Atoms[n], container2.Atoms[m])) { return(false); } // unmapped terminal vertices n and m are adjacent to int nTerminal1 = 0, nTerminal2 = 0; // unmapped non-terminal (remaining) vertices n and m are adjacent to int nRemain1 = 0, nRemain2 = 0; // 0-look-ahead: check each adjacent edge for being mapped, and count // terminal or remaining foreach (var n_prime in g1[n]) { var m_prime = m1[n_prime]; // v is already mapped, there should be an edge {m, w} in g2. if (m_prime != UNMAPPED) { var bond2 = bonds2[m, m_prime]; if (bond2 == null) // the bond is not present in the target { return(false); } // verify bond semantic feasibility if (!bondMatcher.Matches(bonds1[n, n_prime], bond2)) { return(false); } } else { if (t1[n_prime] > 0) { nTerminal1++; } else { nRemain1++; } } } // monomorphism: each mapped edge in g2 doesn't need to be in g1 so // only the terminal and remaining edges are counted foreach (var m_prime in g2[m]) { if (m2[m_prime] == UNMAPPED) { if (t2[m_prime] > 0) { nTerminal2++; } else { nRemain2++; } } } // 1-look-ahead : the mapping {n, m} is feasible iff the number of // terminal vertices (t1) adjacent to n is less than or equal to the // number of terminal vertices (t2) adjacent to m. // // 2-look-ahead: the mapping {n, m} is feasible iff the number of // vertices adjacent to n that are neither in m1 or t1 is less than or // equal to the number of the number of vertices adjacent to m that // are neither in m2 or t2. To allow mapping of monomorphisms we add the // number of adjacent terminal vertices. return(nTerminal1 <= nTerminal2 && (nRemain1 + nTerminal1) <= (nRemain2 + nTerminal2)); }
/// <summary> /// Check the feasibility of the candidate pair {n, m}. A candidate pair is /// syntactically feasible iff all k-look-ahead rules hold. These look ahead /// rules check adjacency relation of the mapping. If an edge is mapped in g1 /// it should also be mapped in g2 and vise-versa (0-look-ahead). If an edge /// in g1 is unmapped but the edge is adjacent to an another mapped vertex /// (terminal) then the number of such edges should be equal in g1 compared /// to g2 (1-look-ahead). If the edge is unmapped and non-terminal then the /// number of such edges should be equal in g1 compared to g2 (2-look-ahead). /// </summary> /// <param name="n">a candidate vertex from g1</param> /// <param name="m">a candidate vertex from g2</param> /// <returns>the mapping is feasible</returns> public override bool Feasible(int n, int m) { // verify atom semantic feasibility if (!atomMatcher.Matches(container1.Atoms[n], container2.Atoms[m])) { return(false); } // unmapped terminal vertices n and m are adjacent to int nTerminal1 = 0, nTerminal2 = 0; // unmapped non-terminal (remaining) vertices n and m are adjacent to int nRemain1 = 0, nRemain2 = 0; // 0-look-ahead: check each adjacent edge for being mapped, and count // terminal or remaining foreach (var n_prime in g1[n]) { int m_prime = m1[n_prime]; // v is already mapped, there should be an edge {m, w} in g2. if (m_prime != UNMAPPED) { IBond bond2 = bonds2[m, m_prime]; // the bond is not present in the target if (bond2 == null) { return(false); } // verify bond semantic feasibility if (!bondMatcher.Matches(bonds1[n, n_prime], bond2)) { return(false); } } else { if (t1[n_prime] > 0) { nTerminal1++; } else { nRemain1++; } } } // 0-look-ahead: check each adjacent edge for being mapped, and count // terminal or remaining foreach (var m_prime in g2[m]) { int n_prime = m2[m_prime]; if (n_prime != UNMAPPED) { IBond bond1 = bonds1[n, n_prime]; // the bond is not present in the query if (bond1 == null) { return(false); } // verify bond semantic feasibility if (!bondMatcher.Matches(bond1, bonds2[m, m_prime])) { return(false); } } else { if (t2[m_prime] > 0) { nTerminal2++; } else { nRemain2++; } } } // 1-look-ahead : the mapping {n, m} is feasible iff the number of // terminal vertices (t1) adjacent to n is equal to the // number of terminal vertices (t2) adjacent to m. // // 2-look-ahead: the mapping {n, m} is feasible iff the number of // vertices adjacent to n that are neither in m1 or t1 is equal to // the number of the number of vertices adjacent to m that are neither // in m2 or t2. return(nTerminal1 == nTerminal2 && nRemain1 == nRemain2); }