Skip to content

Commit 4320a8b

Browse files
authored
Add macro edge aliases (#121)
* 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
1 parent 07e3b7c commit 4320a8b

File tree

5 files changed

+415
-34
lines changed

5 files changed

+415
-34
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Changelog
22

3-
- **?.?.?** (Unreleased)
3+
- **0.12.0** (June 7 2022)
44
- Housekeeping:
55
- Removed old, deprecated code like the v1 parser (deprecated in `v0.5.0`) and some unused ingest tools (#113)
6+
- Features:
7+
- Added edge aliases and inter-edge attribute constraints
68
- **0.11.0** (April 12 2022)
79
- Features:
810
- 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)

dotmotif/executors/test_grandisoexecutor.py

Lines changed: 193 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,34 @@ def test_automorphism_flag_triangle(self):
229229
res = GrandIsoExecutor(graph=G).find(motif)
230230
self.assertEqual(len(res), 1)
231231

232+
def test_nested_macros(self):
233+
G = nx.DiGraph()
234+
G.add_edge("A", "B")
235+
G.add_edge("B", "C")
236+
G.add_edge("C", "A")
237+
238+
motif = dotmotif.Motif(
239+
"""
240+
tri(A, B, C) {
241+
A -> B
242+
B -> C
243+
C -> A
244+
}
245+
246+
tri2(A, B, C) {
247+
tri(A, B, C)
248+
}
249+
250+
tri3(A, B, C) {
251+
tri2(A, B, C)
252+
}
253+
254+
tri3(A, B, C)
255+
"""
256+
)
257+
res = GrandIsoExecutor(graph=G).find(motif)
258+
self.assertEqual(len(res), 3)
259+
232260

233261
class TestDynamicNodeConstraints(unittest.TestCase):
234262
def test_dynamic_constraints_zero_results(self):
@@ -475,30 +503,180 @@ def test_aliased_edge_comparisons_with_different_edge_attributes(self):
475503
self.assertEqual(len(res), 2)
476504

477505

478-
# class TestEdgeConstraintsInMacros(unittest.TestCase):
479-
# def test_edge_comparison_in_macro(self):
506+
class TestEdgeConstraintsInMacros(unittest.TestCase):
507+
def test_edge_comparison_in_macro(self):
508+
host = nx.DiGraph()
509+
host.add_edge("A", "B", foo=1)
510+
host.add_edge("B", "C", foo=0.5)
511+
host.add_edge("C", "D", foo=0.25)
512+
E = GrandIsoExecutor(graph=host)
513+
514+
M = Motif(
515+
"""
516+
517+
descending(a, b) {
518+
a -> b as Edge1
519+
Edge1.foo >= 1
520+
}
521+
522+
descending(real_a, real_b)
523+
524+
"""
525+
)
526+
assert E.count(M) == 1
527+
528+
def test_dynamic_edge_comparison_in_macro(self):
529+
host = nx.DiGraph()
530+
host.add_edge("A", "B", foo=1)
531+
host.add_edge("B", "C", foo=0.5)
532+
host.add_edge("C", "D", foo=0.25)
533+
host.add_edge("D", "C", foo=1)
534+
host.add_edge("C", "B", foo=2)
535+
host.add_edge("B", "A", foo=2)
536+
E = GrandIsoExecutor(graph=host)
537+
538+
M = Motif(
539+
"""
540+
541+
descending(a, b, c) {
542+
a -> b as Edge1
543+
b -> c as Edge2
544+
Edge1.foo > Edge2.foo
545+
}
546+
547+
descending(a, b, c)
548+
descending(b, c, d)
549+
550+
"""
551+
)
552+
assert E.count(M) == 1
553+
554+
def test_nested_macro_edge_constraints(self):
555+
host = nx.DiGraph()
556+
M = Motif(
557+
"""
558+
a(a1, b1) {
559+
b1 -> a1
560+
a1 -> b1 as ab
561+
ab.weight == 1
562+
}
563+
564+
a(A, B)
565+
"""
566+
)
567+
568+
host.add_edge("A", "B", weight=1)
569+
host.add_edge("B", "A", weight=0.5)
570+
E = GrandIsoExecutor(graph=host)
571+
assert E.count(M) == 1
572+
573+
def test_self_edge_constraints(self):
574+
host = nx.DiGraph()
575+
host.add_edge("A", "B", weight=1, length=2)
576+
host.add_edge("B", "A", weight=1, length=1)
577+
578+
M = Motif(
579+
"""
580+
a(a1, b1) {
581+
b1 -> a1
582+
a1 -> b1 as ab
583+
ab.length > ab.weight
584+
}
585+
586+
a(A, B)
587+
"""
588+
)
589+
590+
E = GrandIsoExecutor(graph=host)
591+
assert E.count(M) == 1
592+
593+
594+
# class TestDeepNestingMacros(unittest.TestCase):
595+
596+
# def test_nested_macros_with_node_constraint(self):
597+
# G = nx.DiGraph()
598+
# G.add_edge("A", "B")
599+
# G.add_edge("B", "C")
600+
# G.add_edge("C", "A")
601+
# G.add_node("A", type="foo")
602+
# G.add_node("B", type="foo")
603+
# G.add_node("C", type="foo")
604+
605+
# motif = dotmotif.Motif(
606+
# """
607+
# tri(A, B, C) {
608+
# A -> B
609+
# B -> C
610+
# C -> A
611+
# A.type = "foo"
612+
# }
613+
614+
# tri2(A1, B1, C1) {
615+
# tri(A1, B1, C1)
616+
# }
617+
618+
# tri3(A2, B2, C2) {
619+
# tri2(A2, B2, C2)
620+
# }
621+
622+
# tri3(A3, B3, C3)
623+
# """
624+
# )
625+
# res = GrandIsoExecutor(graph=G).find(motif)
626+
# self.assertEqual(len(res), 3)
627+
628+
629+
# def test_deep_nested_macro_edge_constraints(self):
480630
# host = nx.DiGraph()
481-
# host.add_edge("A", "B", foo=1)
482-
# host.add_edge("A", "C", foo=2)
483-
# host.add_edge("B", "C", foo=0.5)
484-
# host.add_edge("C", "D", foo=0.25)
485-
# host.add_edge("D", "C", foo=1)
486-
# host.add_edge("C", "B", foo=2)
487-
# host.add_edge("B", "A", foo=2)
631+
# M = Motif(
632+
# """
633+
# a(a1, b1) {
634+
# b1 -> a1
635+
# a1 -> b1 as ab
636+
# ab.weight == 1
637+
# }
638+
639+
# b(a2, b2) {
640+
# a(a2, b2)
641+
# }
642+
643+
# c(a3, b3) {
644+
# b(a3, b3)
645+
# }
646+
647+
# c(A, B)
648+
# """
649+
# )
650+
651+
# host.add_edge("A", "B", weight=1)
652+
# host.add_edge("B", "A", weight=0.5)
488653
# E = GrandIsoExecutor(graph=host)
654+
# assert E.count(M) == 1
655+
656+
# def test_deep_self_edge_constraints(self):
657+
# host = nx.DiGraph()
658+
# host.add_edge("A", "B", weight=1, length=2)
659+
# host.add_edge("B", "A", weight=1, length=1)
489660

490661
# M = Motif(
491662
# """
663+
# a(a1, b1) {
664+
# b1 -> a1
665+
# a1 -> b1 as ab
666+
# ab.length > ab.weight
667+
# }
492668

493-
# descending(a, b, c) {
494-
# a -> b as Edge1
495-
# b -> c as Edge2
496-
# Edge1.foo > Edge2.foo
669+
# b(a2, b2) {
670+
# a(a2, b2)
497671
# }
498672

499-
# descending(a, b, c)
500-
# descending(b, c, d)
673+
# c(a3, b3) {
674+
# b(a3, b3)
675+
# }
501676

677+
# c(A, B)
502678
# """
503679
# )
680+
681+
# E = GrandIsoExecutor(graph=host)
504682
# assert E.count(M) == 1

0 commit comments

Comments
 (0)