Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/show graph/cim #2280

Merged
merged 16 commits into from
Jan 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -232,29 +232,29 @@ def remove_ports(self, ports, context=None):
output_ports_marked_for_deletion.add(port)
self.user_added_ports[OUTPUT_PORTS] = self.user_added_ports[OUTPUT_PORTS] - output_ports_marked_for_deletion

def _get_source_node_for_input_CIM(self, port, start_comp=None, end_comp=None):
"""Return Port, Node and Composition for source of projection to input_CIM from (possibly nested) outer comp
**port** should be an InputPort or OutputPort of the CompositionInterfaceMechanism;
**comp** specifies the Composition at which to begin the search (or continue it when called recursively;
assumes the current CompositionInterfaceMechanism's Composition by default
"""
# Ensure method is being called on an output_CIM
assert self == self.composition.input_CIM
# CIM MAP ENTRIES: [SENDER PORT, [output_CIM InputPort, output_CIM OutputPort]]
# Get sender to input_port of output_CIM
comp = start_comp or self.composition
port_map = port.owner.port_map
idx = 0 if isinstance(port, InputPort) else 1
input_port = [port_map[k][0] for k in port_map if port_map[k][idx] is port]
assert len(input_port)==1, f"PROGRAM ERROR: Expected exactly 1 input_port for {port.name} " \
f"in port_map for {port.owner}; found {len(input_port)}."
# assert len(input_port[0].path_afferents)==1, f"PROGRAM ERROR: Port ({input_port.name}) expected to have " \
# f"just one path_afferent; has {len(input_port.path_afferents)}."
if not input_port[0].path_afferents or comp == end_comp:
return input_port[0], input_port[0].owner, comp
sender = input_port[0].path_afferents[0].sender
# if not isinstance(sender.owner, CompositionInterfaceMechanism):
return self._get_source_node_for_input_CIM(sender, sender.owner.composition)
# def _get_source_node_for_input_CIM(self, port, start_comp=None, end_comp=None):
# """Return Port, Node and Composition for source of projection to input_CIM from (possibly nested) outer comp
# **port** should be an InputPort or OutputPort of the CompositionInterfaceMechanism;
# **comp** specifies the Composition at which to begin the search (or continue it when called recursively;
# assumes the current CompositionInterfaceMechanism's Composition by default
# """
# # Ensure method is being called on an output_CIM
# assert self == self.composition.input_CIM
# # CIM MAP ENTRIES: [SENDER PORT, [output_CIM InputPort, output_CIM OutputPort]]
# # Get sender to input_port of output_CIM
# comp = start_comp or self.composition
# port_map = port.owner.port_map
# idx = 0 if isinstance(port, InputPort) else 1
# input_port = [port_map[k][0] for k in port_map if port_map[k][idx] is port]
# assert len(input_port)==1, f"PROGRAM ERROR: Expected exactly 1 input_port for {port.name} " \
# f"in port_map for {port.owner}; found {len(input_port)}."
# # assert len(input_port[0].path_afferents)==1, f"PROGRAM ERROR: Port ({input_port.name}) expected to have " \
# # f"just one path_afferent; has {len(input_port.path_afferents)}."
# if not input_port[0].path_afferents or comp == end_comp:
# return input_port[0], input_port[0].owner, comp
# sender = input_port[0].path_afferents[0].sender
# # if not isinstance(sender.owner, CompositionInterfaceMechanism):
# return self._get_source_node_for_input_CIM(sender, sender.owner.composition)

def _get_destination_node_for_input_CIM(self, port, comp=None):
"""Return Port, Node and Composition for destination of projection from input_CIM to (possibly nested) node
Expand Down Expand Up @@ -286,7 +286,8 @@ def _get_source_node_for_output_CIM(self, port, comp=None):
assumes the current CompositionInterfaceMechanism's Composition by default
"""
# Ensure method is being called on an output_CIM
assert self == self.composition.output_CIM
assert self == self.composition.output_CIM, f"_get_source_node_for_output_CIM called on {self.name} " \
f"which is not an output_CIM"
# CIM MAP ENTRIES: [SENDER PORT, [output_CIM InputPort, output_CIM OutputPort]]
# Get sender to input_port of output_CIM
comp = comp or self.composition
Expand Down
58 changes: 47 additions & 11 deletions psyneulink/core/compositions/showgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -1842,6 +1842,14 @@ def find_rcvr_comp(r, c, l):
# incoming edges (from monitored mechs to objective mechanism)
for input_port in objmech.input_ports:
for projection in input_port.path_afferents:
# MODIFIED 1/6/22 NEW:
# Get nested source node for direct projection to objective mechanism
if isinstance(projection.sender.owner, CompositionInterfaceMechanism) and not show_cim:
cim_output_port = projection.sender
proj_sndr, node, comp = cim_output_port.owner._get_source_node_for_output_CIM(cim_output_port)
else:
proj_sndr = projection.sender
# MODIFIED 1/6/22 END
if objmech in active_items:
if self.active_color == BOLD:
proj_color = self.controller_color
Expand All @@ -1854,12 +1862,15 @@ def find_rcvr_comp(r, c, l):
proj_width = str(self.default_width)
if show_node_structure:
sndr_proj_label = self._get_graph_node_label(composition,
projection.sender.owner,
proj_sndr.owner,
show_types,
show_dimensions)
if projection.sender.owner not in composition.nodes:
if (proj_sndr.owner not in composition.nodes
# MODIFIED 1/6/22 NEW:
and isinstance(proj_sndr.owner, CompositionInterfaceMechanism)):
# MODIFIED 1/6/22 END
num_nesting_levels = self.num_nesting_levels or 0
nested_comp = projection.sender.owner.composition
nested_comp = proj_sndr.owner.composition
try:
nesting_depth = next((k for k, v in comp_hierarchy.items() if v == nested_comp))
sender_visible = nesting_depth <= num_nesting_levels
Expand All @@ -1868,11 +1879,11 @@ def find_rcvr_comp(r, c, l):
else:
sender_visible = True
if sender_visible:
sndr_proj_label += ':' + objmech._get_port_name(projection.sender)
sndr_proj_label += ':' + objmech._get_port_name(proj_sndr)
objmech_proj_label = objmech_label + ':' + objmech._get_port_name(input_port)
else:
sndr_proj_label = self._get_graph_node_label(composition,
projection.sender.owner,
proj_sndr.owner,
show_types,
show_dimensions)
objmech_proj_label = self._get_graph_node_label(composition,
Expand All @@ -1891,7 +1902,12 @@ def find_rcvr_comp(r, c, l):
# incoming edges (from monitored mechs directly to controller)
for outcome_input_port in controller.outcome_input_ports:
for projection in outcome_input_port.path_afferents:
if show_node_structure:
# MODIFIED 1/6/22 NEW:
# Handled by _assign_cim_components()
if isinstance(projection.sender.owner, CompositionInterfaceMechanism) and not show_cim:
continue
# MODIFIED 1/6/22 END
if show_node_structure and show_cim:
sndr_proj_label = self._get_graph_node_label(composition,
projection.sender.owner,
show_types,
Expand Down Expand Up @@ -1953,12 +1969,19 @@ def find_rcvr_comp(r, c, l):
g.edge(agent_rep_label, ctlr_label, color=agent_rep_color, penwidth=agent_rep_width)
g.edge(ctlr_label, agent_rep_label, color=agent_rep_color, penwidth=agent_rep_width)

# get any other incoming edges to controller (i.e., other than from ObjectiveMechanism)
# get any other incoming edges to controller
# (i.e., other than from ObjectiveMechanism or directly monitored nodes)
senders = set()
# FIX: 11/3/21 - NEED TO MODIFY ONCE OUTCOME InputPorts ARE MOVED
for i in controller.input_ports[controller.num_outcome_input_ports:]:
for p in i.path_afferents:
senders.add(p.sender.owner)
# MODIFIED 1/6/22 NEW:
sender = p.sender.owner
if isinstance(sender, CompositionInterfaceMechanism) and not show_cim:
pass # FIX: 1/6/22 - PLACEMARKER FOR RELABELING INPUT_CIM AS SHADOWING INPUT OF SHADOWED NODE
assert True
# MODIFIED 1/6/22 END
senders.add(sender)
self._assign_incoming_edges(g,
controller,
ctlr_label,
Expand Down Expand Up @@ -2189,7 +2212,7 @@ def _assign_incoming_edges(self,
and isinstance(proj.sender.owner, CompositionInterfaceMechanism)
and proj.sender.owner in {composition.input_CIM, composition.parameter_CIM})])
senders.update(cims)
# HACK: FIX 6/13/20 - ADD USER-SPECIFIED TARGET NODE FOR INNER COMOSITION (NOT IN processing_graph)
# HACK: FIX 6/13/20 - ADD USER-SPECIFIED TARGET NODE FOR INNER COMPOSITION (NOT IN processing_graph)

def assign_sender_edge(sndr:Union[Mechanism, Composition],
proj_color:str, proj_arrowhead:str
Expand Down Expand Up @@ -2360,7 +2383,7 @@ def assign_sender_edge(sndr:Union[Mechanism, Composition],
if not sender.afferents and rcvr is not composition.controller:
continue
# FIX: LOOP HERE OVER sndr_spec IF THERE ARE SEVERAL
# Get node(s) from enclosing Comopsition that is/are source(s) of sender(s)
# Get node(s) from enclosing Composition that is/are source(s) of sender(s)
sndrs_specs = self._trace_senders_for_original_sender_mechanism(proj, nesting_level)
if not sndrs_specs:
continue
Expand All @@ -2371,11 +2394,15 @@ def assign_sender_edge(sndr:Union[Mechanism, Composition],
enclosing_comp = comp_hierarchy[sndr_nesting_level]
enclosing_g = enclosing_comp._show_graph.G
# Skip:
# - cims as sources (handled in _assign_cim_componoents)
# - cims as sources (handled in _assign_cim_components)
# unless it is the input_CIM for the outermost Composition and show_cim is not true
# - controller (handled in _assign_controller_components)
if (isinstance(sndr, CompositionInterfaceMechanism) and
rcvr is not enclosing_comp.controller
and rcvr is not composition.controller
# MODIFIED 1/6/22 NEW:
and not sndr.afferents and show_cim
# MODIFIED 1/6/22 END
or self._is_composition_controller(sndr, enclosing_comp)):
continue
if sender is composition.parameter_CIM:
Expand Down Expand Up @@ -2563,7 +2590,12 @@ def _trace_senders_for_original_sender_mechanism(self,
nesting_level -= 1
num_afferents = len(owner.port_map[proj.receiver][0].path_afferents)
if num_afferents == 0:
# MODIFIED 1/6/22 OLD:
return None
# # MODIFIED 1/6/22 NEW:
# # Presumably outermost Composition, so return CIM itself
# return [(owner, sender, nesting_level)]
# MODIFIED 1/6/22 END
# # FIX: ITERATE OVER ALL AFFERENTS TO relevant InputPort of cim:
# # MODIFIED 4/5/21 OLD:
# outer_proj = owner.port_map[proj.receiver][0].path_afferents[0]
Expand All @@ -2576,6 +2608,10 @@ def _trace_senders_for_original_sender_mechanism(self,
sndrs = enclosing_showgraph._trace_senders_for_original_sender_mechanism(outer_proj, nesting_level)
if sndrs is not None:
senders.extend(sndrs)
# MODIFIED 1/6/22 NEW:
else:
senders.append((outer_proj.sender.owner, sender, nesting_level))
# MODIFIED 1/6/22 END
return senders
# MODIFIED 4/5/21 END
# FIX: RECEIVERS OF THIS RETURN NEED TO HANDLE LIST
Expand Down
Loading