Skip to content

Commit

Permalink
Add macro edge aliases (#121)
Browse files Browse the repository at this point in the history
* Add working simple named edge constraints in macros

* Add support for dynamic edge constraints in a macro

* Add all constraints (but not using them yet)

* Begin hunting down the broken part of nested macros

* Remove deep-nesting tests

* Update changelog
  • Loading branch information
j6k4m8 authored Jun 7, 2022
1 parent 07e3b7c commit 4320a8b
Show file tree
Hide file tree
Showing 5 changed files with 415 additions and 34 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Changelog

- **?.?.?** (Unreleased)
- **0.12.0** (June 7 2022)
- Housekeeping:
- Removed old, deprecated code like the v1 parser (deprecated in `v0.5.0`) and some unused ingest tools (#113)
- Features:
- Added edge aliases and inter-edge attribute constraints
- **0.11.0** (April 12 2022)
- Features:
- Added support for attributes that include spaces and other non-word/variable characters, and updated Cypher syntax for these attributes when searching with Neo4j and neuPrint (#112)
Expand Down
208 changes: 193 additions & 15 deletions dotmotif/executors/test_grandisoexecutor.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,34 @@ def test_automorphism_flag_triangle(self):
res = GrandIsoExecutor(graph=G).find(motif)
self.assertEqual(len(res), 1)

def test_nested_macros(self):
G = nx.DiGraph()
G.add_edge("A", "B")
G.add_edge("B", "C")
G.add_edge("C", "A")

motif = dotmotif.Motif(
"""
tri(A, B, C) {
A -> B
B -> C
C -> A
}
tri2(A, B, C) {
tri(A, B, C)
}
tri3(A, B, C) {
tri2(A, B, C)
}
tri3(A, B, C)
"""
)
res = GrandIsoExecutor(graph=G).find(motif)
self.assertEqual(len(res), 3)


class TestDynamicNodeConstraints(unittest.TestCase):
def test_dynamic_constraints_zero_results(self):
Expand Down Expand Up @@ -475,30 +503,180 @@ def test_aliased_edge_comparisons_with_different_edge_attributes(self):
self.assertEqual(len(res), 2)


# class TestEdgeConstraintsInMacros(unittest.TestCase):
# def test_edge_comparison_in_macro(self):
class TestEdgeConstraintsInMacros(unittest.TestCase):
def test_edge_comparison_in_macro(self):
host = nx.DiGraph()
host.add_edge("A", "B", foo=1)
host.add_edge("B", "C", foo=0.5)
host.add_edge("C", "D", foo=0.25)
E = GrandIsoExecutor(graph=host)

M = Motif(
"""
descending(a, b) {
a -> b as Edge1
Edge1.foo >= 1
}
descending(real_a, real_b)
"""
)
assert E.count(M) == 1

def test_dynamic_edge_comparison_in_macro(self):
host = nx.DiGraph()
host.add_edge("A", "B", foo=1)
host.add_edge("B", "C", foo=0.5)
host.add_edge("C", "D", foo=0.25)
host.add_edge("D", "C", foo=1)
host.add_edge("C", "B", foo=2)
host.add_edge("B", "A", foo=2)
E = GrandIsoExecutor(graph=host)

M = Motif(
"""
descending(a, b, c) {
a -> b as Edge1
b -> c as Edge2
Edge1.foo > Edge2.foo
}
descending(a, b, c)
descending(b, c, d)
"""
)
assert E.count(M) == 1

def test_nested_macro_edge_constraints(self):
host = nx.DiGraph()
M = Motif(
"""
a(a1, b1) {
b1 -> a1
a1 -> b1 as ab
ab.weight == 1
}
a(A, B)
"""
)

host.add_edge("A", "B", weight=1)
host.add_edge("B", "A", weight=0.5)
E = GrandIsoExecutor(graph=host)
assert E.count(M) == 1

def test_self_edge_constraints(self):
host = nx.DiGraph()
host.add_edge("A", "B", weight=1, length=2)
host.add_edge("B", "A", weight=1, length=1)

M = Motif(
"""
a(a1, b1) {
b1 -> a1
a1 -> b1 as ab
ab.length > ab.weight
}
a(A, B)
"""
)

E = GrandIsoExecutor(graph=host)
assert E.count(M) == 1


# class TestDeepNestingMacros(unittest.TestCase):

# def test_nested_macros_with_node_constraint(self):
# G = nx.DiGraph()
# G.add_edge("A", "B")
# G.add_edge("B", "C")
# G.add_edge("C", "A")
# G.add_node("A", type="foo")
# G.add_node("B", type="foo")
# G.add_node("C", type="foo")

# motif = dotmotif.Motif(
# """
# tri(A, B, C) {
# A -> B
# B -> C
# C -> A
# A.type = "foo"
# }

# tri2(A1, B1, C1) {
# tri(A1, B1, C1)
# }

# tri3(A2, B2, C2) {
# tri2(A2, B2, C2)
# }

# tri3(A3, B3, C3)
# """
# )
# res = GrandIsoExecutor(graph=G).find(motif)
# self.assertEqual(len(res), 3)


# def test_deep_nested_macro_edge_constraints(self):
# host = nx.DiGraph()
# host.add_edge("A", "B", foo=1)
# host.add_edge("A", "C", foo=2)
# host.add_edge("B", "C", foo=0.5)
# host.add_edge("C", "D", foo=0.25)
# host.add_edge("D", "C", foo=1)
# host.add_edge("C", "B", foo=2)
# host.add_edge("B", "A", foo=2)
# M = Motif(
# """
# a(a1, b1) {
# b1 -> a1
# a1 -> b1 as ab
# ab.weight == 1
# }

# b(a2, b2) {
# a(a2, b2)
# }

# c(a3, b3) {
# b(a3, b3)
# }

# c(A, B)
# """
# )

# host.add_edge("A", "B", weight=1)
# host.add_edge("B", "A", weight=0.5)
# E = GrandIsoExecutor(graph=host)
# assert E.count(M) == 1

# def test_deep_self_edge_constraints(self):
# host = nx.DiGraph()
# host.add_edge("A", "B", weight=1, length=2)
# host.add_edge("B", "A", weight=1, length=1)

# M = Motif(
# """
# a(a1, b1) {
# b1 -> a1
# a1 -> b1 as ab
# ab.length > ab.weight
# }

# descending(a, b, c) {
# a -> b as Edge1
# b -> c as Edge2
# Edge1.foo > Edge2.foo
# b(a2, b2) {
# a(a2, b2)
# }

# descending(a, b, c)
# descending(b, c, d)
# c(a3, b3) {
# b(a3, b3)
# }

# c(A, B)
# """
# )

# E = GrandIsoExecutor(graph=host)
# assert E.count(M) == 1
Loading

0 comments on commit 4320a8b

Please sign in to comment.