def test_to_networkx(): graph = Graph({ '!i': [0, 1, 2], 'open': [True, False, True] }, { '!i': [0, 0], '!j': [1, 2], 'length': [0.5, 1.5], 'label': ['x', 'y'] }, title='test') ngraph = graph.to_networkx() assert (len(ngraph.nodes) == len(graph.nodes)) assert (len(ngraph.edges) == len(graph.edges)) for _, n in ngraph.nodes.items(): assert ('open' in n) for _, e in ngraph.edges.items(): assert ('length' in e) assert ('label' in e) for k in range(len(graph.nodes)): i = graph.nodes['!i'][k] assert (graph.nodes['open'][k] == ngraph.nodes[i]['open']) for k in range(len(graph.edges)): i = graph.edges['!i'][k] j = graph.edges['!j'][k] assert (graph.edges['length'][k] == ngraph[i][j]['length']) assert (graph.edges['label'][k] == ngraph[i][j]['label'])
def __call__(self, atoms1, atoms2): args = dict(use_charge=self.use_charge, adjacency=self.adjacency) g1 = Graph.from_ase(atoms1, **args) g2 = Graph.from_ase(atoms2, **args) R1 = self._mlgk(g1, g1).diagonal()**-0.5 R2 = self._mlgk(g2, g2).diagonal()**-0.5 R12 = self._mlgk(g1, g2) K = R1[:, None] * R12 * R2[None, :] D = np.sqrt(np.maximum(2 - 2 * K, 0)) return max(D.min(axis=1).max(), D.min(axis=0).max())
def test_graph_cache_invalidation(inplace): G = [Graph.from_networkx(nx.cycle_graph(4)) for _ in range(2)] backend = CUDABackend() cached = [backend._register_graph(g) for g in G] if inplace: Graph.unify_datatype(G, inplace=inplace) H = G else: H = Graph.unify_datatype(G, inplace=inplace) for h in H: _, h_cached = backend._register_graph(h) for _, g_cached in cached: assert (h_cached is not g_cached)
def test_dict_init(): G = Graph(nodes={ 'order': { 0: 1, 1: -2 }, 'conjugate': { 0: True, 1: False } }, edges={ '!ij': { 0: (0, 1) }, 'length': { 0: 3.2 }, 'weight': { 0: 1 } }, title='graph') for g in [G, eval(repr(G).strip('><'))]: assert (g.title == 'graph') assert (len(g.nodes) == 2) assert (len(g.nodes.columns) == 2) assert (len(g.edges) == 1) assert (len(g.edges.columns) == 3)
def test_from_rdkit_linear_hydrocarbon(): for i in range(2, 10): smi = 'C' * i mol = Chem.MolFromSmiles(smi) g = Graph.from_rdkit(mol) assert(len(g.nodes) == i) assert(len(g.edges) == i - 1)
def test_permute(inplace): nxg = nx.Graph(title='Simple') f = [np.pi, np.e, np.sqrt(2), -1.0, 2.0] nxg.add_node(0, f=f[0]) nxg.add_node(1, f=f[1]) nxg.add_node(2, f=f[2]) nxg.add_node(3, f=f[3]) nxg.add_node(4, f=f[4]) nxg.add_edge(0, 1, h=f[0] * f[1]) nxg.add_edge(0, 2, h=f[0] * f[2]) nxg.add_edge(0, 4, h=f[0] * f[4]) nxg.add_edge(1, 2, h=f[1] * f[2]) nxg.add_edge(1, 3, h=f[1] * f[3]) nxg.add_edge(2, 3, h=f[2] * f[3]) nxg.add_edge(3, 4, h=f[3] * f[4]) g = Graph.from_networkx(nxg) for perm in it.permutations(range(len(g.nodes))): g1 = g.copy(deep=True) g2 = g1.permute(perm, inplace=inplace) if inplace: assert (g1 is g2) m = {idx: i for i, idx in enumerate(g2.nodes['!i'])} for i in range(len(g2.edges)): i1 = m[g2.edges['!i'][i]] i2 = m[g2.edges['!j'][i]] assert (g2.edges.h[i] == pytest.approx(g2.nodes.f[i1] * g2.nodes.f[i2]))
def test_copy(deep): nxg = nx.Graph(title='Simple') nxg.add_node(0, f=0, g='a') nxg.add_node(1, f=1, g='b') nxg.add_node(2, f=2, g='c') nxg.add_edge(0, 1, h=1.0) nxg.add_edge(0, 2, h=2.0) g1 = Graph.from_networkx(nxg) g1.custom_attributes = (1.5, 'hello', False) g2 = g1.copy(deep=deep) assert (hasattr(g2, 'custom_attributes')) assert (g1.custom_attributes == g2.custom_attributes) assert (g1.title == g2.title) assert (len(g1.nodes) == len(g2.nodes)) assert (len(g1.edges) == len(g2.edges)) for n1, n2 in zip(g1.nodes.rows(), g2.nodes.rows()): assert (n1 == n2) for e1, e2 in zip(g1.edges.rows(), g2.edges.rows()): assert (e1 == e2) # Changes in one graph should reflect in its shallow copy, but should not # affect its deep copy. for i in range(len(g1.nodes)): g1.nodes.f[i] += 10.0 for n1, n2 in zip(g1.nodes.rows(), g2.nodes.rows()): if deep: assert (n1 != n2) else: assert (n1 == n2)
def test_rcm_fancy_graphs(n, gen): nxg = gen(n) if nxg.number_of_edges() > 0: g = Graph.from_networkx(nxg) p = rcm(g) assert (np.min(p) == 0) assert (np.max(p) == n - 1) assert (len(np.unique(p)) == n)
def test_attribute_consistency_from_networkx(): nxg1 = nx.Graph(title='H2O') nxg1.add_node(0, label1=3.14) nxg1.add_node(1, label2=True) with pytest.raises(TypeError): Graph.from_networkx(nxg1) nxg2 = nx.Graph(title='H2O') nxg2.add_node(0) nxg2.add_node(1) nxg2.add_node(2) nxg2.add_edge(0, 1, weight=1) nxg2.add_edge(0, 2, multi=2) with pytest.raises(TypeError): Graph.from_networkx(nxg2)
def test_empty_init(): G = Graph(nodes=[], edges=[]) for g in [G, eval(repr(G).strip('><'))]: assert (g.title == '') assert (len(g.nodes) == 0) assert (len(g.nodes.columns) == 0) assert (len(g.edges) == 0) assert (len(g.edges.columns) == 0)
def test_graph_cache(): G = [Graph.from_networkx(nx.cycle_graph(4)) for _ in range(2)] backend = CUDABackend() i1, cached1 = backend._register_graph(G[0]) i2, cached2 = backend._register_graph(G[0]) i3, cached3 = backend._register_graph(G[1]) assert (i1 == i2) assert (cached1 is cached2) assert (i1 != i3) assert (cached1 is not cached3)
def test_rcm_fancy_graphs(n, gen): nxg = gen(n) if nxg.number_of_edges() > 0: g = Graph.from_networkx(nxg) p = pbr(g) assert(np.min(p) == 0) assert(np.max(p) == n - 1) assert(len(np.unique(p)) == n) g_perm = g.permute(p) assert(n_tiles(g.adjacency_matrix) >= n_tiles(g_perm.adjacency_matrix))
def test_empty_from_networkx(): nxg = nx.Graph(title='Null') G = Graph.from_networkx(nxg) for g in [G, eval(repr(G).strip('><'))]: assert (g.title == 'Null') assert (len(g.nodes) == 0) assert (len(g.nodes.columns) == 0) assert (len(g.edges) == 0) assert (len(g.edges.columns) == 1) # +1 for the hidden edge index
def test_adjacency_matrix_full(): for n in [2, 3, 5, 7, 8, 11, 13, 16, 17, 23, 25]: g = Graph.from_networkx(nx.complete_graph(n)) A = g.adjacency_matrix.todense() assert (A.shape[0] == n) assert (A.shape[1] == n) for i in range(n): for j in range(n): if i == j: assert (A[i, j] == 0) else: assert (A[i, j] == 1)
def test_adjacency_matrix_regular(): for d in [2, 3, 4]: for n in [8, 12, 16]: g = Graph.from_networkx(nx.random_regular_graph(d, n)) A = g.adjacency_matrix.todense() assert (A.shape[0] == n) assert (A.shape[1] == n) D = A.sum(axis=0) for deg in D.flat: assert (deg == d) for i in range(n): for j in range(n): assert (A[i, j] == A[j, i])
def test_weighted_from_networkx(): nxg = nx.Graph(title='Simple') nxg.add_node(0) nxg.add_node(1) nxg.add_edge(0, 1, w=1.0) G = Graph.from_networkx(nxg, weight='w') for g in [G, eval(repr(G).strip('><'))]: assert (g.title == 'Simple') assert (len(g.nodes) == 2) assert (len(g.nodes.columns) == 0) assert (len(g.edges) == 1) assert (len(g.edges.columns) == 2) # +2 for edge index and weight assert ('!ij' in g.edges.columns) assert ('!w' in g.edges.columns)
def test_molecular_kernel_on_organics(benchmark): graphs = [ Graph.from_ase(molecule(name)) for name in g2.names if len(molecule(name)) > 1 ] kernel = Tang2019MolecularKernel() def fun(kernel, graphs): return kernel(graphs, nodal=True) benchmark.pedantic(fun, args=(kernel, graphs), iterations=3, rounds=3, warmup_rounds=1)
def test_molecule_from_networkx(): nxg = nx.Graph(title='H2O') nxg.add_node('O1', charge=1, conjugate=False, mass=8.0) nxg.add_node('H1', charge=-1, conjugate=True, mass=1.0) nxg.add_node('H2', charge=2, conjugate=True, mass=1.0) nxg.add_edge('O1', 'H1', order=1, length=0.5, weight=3.2) nxg.add_edge('O1', 'H2', order=2, length=1.0, weight=0.5) G = Graph.from_networkx(nxg) for g in [G, eval(repr(G).strip('><'))]: assert (g.title == 'H2O') assert (len(g.nodes) == 3) assert (len(g.nodes.columns) == 3) assert (len(g.edges) == 2) assert (len(g.edges.columns) == 3 + 1) # +1 for the hidden edge index
def test_simple_from_networkx(): nxg = nx.Graph(title='Simple') nxg.add_node(0) nxg.add_node('c') nxg.add_node('X') nxg.add_node(3.14) nxg.add_edge(0, 'c') nxg.add_edge(3.14, 'X') G = Graph.from_networkx(nxg) for g in [G, eval(repr(G).strip('><'))]: assert (g.title == 'Simple') assert (len(g.nodes) == 4) assert (len(g.nodes.columns) == 0) assert (len(g.edges) == 2) assert (len(g.edges.columns) == 1) # +1 for the hidden edge index
def test_adjacency_matrix_cycle(): for n in [2, 3, 5, 7, 8, 11, 13, 16, 17, 23, 25]: g = Graph.from_networkx(nx.cycle_graph(n)) A = g.adjacency_matrix.todense() assert (A.shape[0] == n) assert (A.shape[1] == n) for i in range(n): for j in range(n): d = i - j if d > n / 2: d -= n elif d < -n / 2: d += n if abs(d) == 1: assert (A[i, j] == 1) else: assert (A[i, j] == 0)
def test_large_from_networkx(): nxg = nx.Graph(title='Large') nn = 1000 ne = 100000 np.random.seed(0) for i in range(nn): nxg.add_node(i, label=np.random.randn()) for _ in range(ne): i, j = np.random.randint(nn, size=2) nxg.add_edge(i, j, weight=np.random.rand()) G = Graph.from_networkx(nxg) for g in [G, eval(repr(G).strip('><'))]: assert (g.title == 'Large') assert (len(g.nodes) == nn) assert (len(g.edges) <= ne)
def test_from_rdkit_options(): m = Chem.MolFromSmiles('CCOCC') g = Graph.from_rdkit(m, bond_type='order') assert('order' in g.edges.columns) g = Graph.from_rdkit(m, bond_type='type') assert('type' in g.edges.columns) g = Graph.from_rdkit(m, set_ring_list=True) assert('ring_list' in g.nodes.columns) g = Graph.from_rdkit(m, set_ring_list=False) assert('ring_list' not in g.nodes.columns) g = Graph.from_rdkit(m, set_ring_stereo=True) assert('ring_stereo' in g.edges.columns) g = Graph.from_rdkit(m, set_ring_stereo=False) assert('ring_stereo' not in g.edges.columns)
def test_dict_init(): G = Graph(nodes={ '!i': [0, 1], 'order': [1, -2], 'conjugate': [True, False] }, edges={ '!i': [0], '!j': [1], 'length': [3.2], 'weight': [1] }, title='graph') for g in [G, eval(repr(G).strip('><'))]: assert (g.title == 'graph') assert (len(g.nodes) == 2) assert (len(g.nodes.columns) == 3) # +1 for the hidden !i index assert (len(g.edges) == 1) assert (len(g.edges.columns) == 4) # +2 for the hidden !i, !j index
def __call__(self, X, ij, lmin=0, timing=False): """Compute a list of pairwise similarities between graphs. Parameters ---------- X: list of N graphs The graphs must all have same node and edge attributes. ij: list of pairs of ints Pair indices for which the graph kernel is to be evaluated. lmin: 0 or 1 Number of steps to skip in each random walk path before similarity is computed. (lmin + 1) corresponds to the starting value of l in the summation of Eq. 1 in Tang & de Jong, 2019 https://doi.org/10.1063/1.5078640 (or the first unnumbered equation in Section 3.3 of Kashima, Tsuda, and Inokuchi, 2003). Returns ------- gramian: ndarray A vector with the same length as ij """ timer = Timer() backend = self.backend traits = self.traits(lmin=lmin, ) ''' assert graph attributes are compatible with each other ''' pred_or_tuple = Graph.has_unified_types(X) if pred_or_tuple is not True: group, first, second = pred_or_tuple raise TypeError( f'The two graphs have mismatching {group} attributes or ' 'attribute types. If the attributes match in name but differ ' 'in type, try `Graph.unify_datatype` as an automatic fix.\n' f'First graph: {first}\n' f'Second graph: {second}\n') ''' generate jobs ''' timer.tic('generating jobs') jobs = backend.array( np.array(ij, dtype=np.uint32).ravel().view( dtype=np.dtype([('i', np.uint32), ('j', np.uint32)]))) timer.toc('generating jobs') ''' create output buffer ''' timer.tic('creating output buffer') gramian = backend.empty(len(jobs), np.float32) timer.toc('creating output buffer') ''' call GPU kernel ''' timer.tic('calling GPU kernel (overall)') backend( X, self.node_kernel, self.edge_kernel, self.p, self.q, self.eps, self.ftol, self.gtol, jobs, gramian, traits, timer, ) timer.toc('calling GPU kernel (overall)') ''' collect result ''' timer.tic('collecting result') gramian = gramian.astype(self.element_dtype) timer.toc('collecting result') if timing: timer.report(unit='ms') timer.reset() return gramian
def test_from_rdkit_feature_atom_aromatic(testset): smi, aromatic = testset g = Graph.from_rdkit(Chem.MolFromSmiles(smi)) for n in g.nodes.rows(): assert(n.aromatic == aromatic)
def test_from_rdkit_feature_atom_hybridization(testset): smi, hybridization = testset g = Graph.from_rdkit(Chem.MolFromSmiles(smi)) for n in g.nodes.rows(): assert(n.hybridization == hybridization)
def test_from_rdkit_feature_atom_hcount(testset): smi, hcount = testset g = Graph.from_rdkit(Chem.MolFromSmiles(smi)) for n in g.nodes.rows(): assert(n.hcount == hcount)
def test_from_rdkit_feature_atom_charge(testset): smi, charge = testset g = Graph.from_rdkit(Chem.MolFromSmiles(smi)) assert(g.nodes.charge[0] == charge)
def test_from_rdkit_feature_atomic_number(testset): smi, atomic_number = testset g = Graph.from_rdkit(Chem.MolFromSmiles(smi)) for n in g.nodes.rows(): assert(n.atomic_number == atomic_number)
def test_from_rdkit_feature_bond_stereo(testset): smi, stereo = testset g = Graph.from_rdkit(Chem.MolFromSmiles(smi)) assert(g.edges.stereo[1] == stereo)