From bd01378d92663f45772e6bb7cd9dc4a086a533a5 Mon Sep 17 00:00:00 2001 From: Katherine Mantel Date: Thu, 7 Jul 2022 17:16:11 -0400 Subject: [PATCH] Composition: add_projection: also detect feedback from node roles (#2429) Node roles may be specified in various places, including when specifying a Pathway. These roles can imply that some projections should be feedback, and it can be cumbersome to check for these in any place add_projection may be called to pass feedback=True. This checks for these roles in Composition.add_projection when adding an edge to the Graph. Fixes #2004 --- psyneulink/core/compositions/composition.py | 9 +++++++++ tests/composition/test_composition.py | 14 ++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/psyneulink/core/compositions/composition.py b/psyneulink/core/compositions/composition.py index 40a25c27ab1..b720ef3921e 100644 --- a/psyneulink/core/compositions/composition.py +++ b/psyneulink/core/compositions/composition.py @@ -5816,6 +5816,15 @@ def add_projection(self, projection.is_processing = False # KDM 5/24/19: removing below rename because it results in several existing_projections # projection.name = f'{sender} to {receiver}' + + # check for required role specification of feedback projections + for node, role in self.required_node_roles: + if ( + (node == projection.sender.owner and role == NodeRole.FEEDBACK_SENDER) + or (node == projection.receiver.owner and role == NodeRole.FEEDBACK_RECEIVER) + ): + feedback = True + self.graph.add_component(projection, feedback=feedback) try: diff --git a/tests/composition/test_composition.py b/tests/composition/test_composition.py index e85810b219d..230af9f4c34 100644 --- a/tests/composition/test_composition.py +++ b/tests/composition/test_composition.py @@ -7362,6 +7362,20 @@ def test_inactive_terminal_projection(self): assert comp.nodes_to_roles[A] == {NodeRole.INPUT, NodeRole.OUTPUT, NodeRole.SINGLETON, NodeRole.ORIGIN, NodeRole.TERMINAL} + def test_feedback_projection_added_by_pathway(self): + A = pnl.ProcessingMechanism(name='A') + B = pnl.ProcessingMechanism(name='B') + C = pnl.ProcessingMechanism(name='C') + + icomp = pnl.Composition(pathways=[C]) + ocomp = pnl.Composition(pathways=[A, icomp, (B, pnl.NodeRole.FEEDBACK_SENDER), A]) + + assert ocomp.nodes_to_roles == { + A: {NodeRole.ORIGIN, NodeRole.INPUT, NodeRole.FEEDBACK_RECEIVER}, + icomp: {NodeRole.INTERNAL}, + B: {NodeRole.TERMINAL, NodeRole.OUTPUT, NodeRole.FEEDBACK_SENDER}, + } + class TestMisc: