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

Implement support for rendering through ports #121

Merged
merged 2 commits into from
Sep 29, 2024
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
24 changes: 20 additions & 4 deletions src/qref/experimental/rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
GRAPH_ATTRS = {
"rankdir": "LR", # Draw left to right (default is top to bottom)
"fontname": "Helvetica",
"splines": "false",
}

# Keyword args passed to dag.node for drawing leaf nodes
Expand Down Expand Up @@ -100,23 +101,36 @@ def _add_nonleaf_ports(ports, parent_cluster, parent_path: str, group_name):
def _split_ports(ports):
input_ports = []
output_ports = []
through_ports = []
for port in ports:
if port.direction == "input":
input_ports.append(port)
elif port.direction == "output":
output_ports.append(port)
else:
raise ValueError("Bi-directional ports are not yet supported for rendering")
return input_ports, output_ports
through_ports.append(port)
return input_ports, output_ports, through_ports


def _add_nonleaf(routine, dag: graphviz.Digraph, parent_path: str) -> None:
input_ports, output_ports = _split_ports(routine.ports)
input_ports, output_ports, through_ports = _split_ports(routine.ports)
full_path = f"{parent_path}.{routine.name}"

with dag.subgraph(name=f"cluster_{full_path}", graph_attr={"label": routine.name, **CLUSTER_KWARGS}) as cluster:
_add_nonleaf_ports(input_ports, cluster, full_path, "inputs")
_add_nonleaf_ports(output_ports, cluster, full_path, "outputs")
_add_nonleaf_ports(through_ports, cluster, full_path, "through")

# We're adding ghost nodes and edges to position the through ports
# in the middle.
for port in through_ports:
dummy_out = f'"{full_path}.{port.name}_out"'
dummy_in = f'"{full_path}.{port.name}_in"'
pname = f'"{full_path}.{port.name}"'
cluster.node(dummy_in, label="", style="invis")
cluster.node(dummy_out, label="", style="invis")
cluster.edge(dummy_in, pname, style="invis")
cluster.edge(pname, dummy_out, style="invis")

for child in routine.children:
_add_routine(child, cluster, f"{parent_path}.{routine.name}")
Expand All @@ -133,8 +147,10 @@ def _ports_row(ports) -> str:


def _add_leaf(routine, dag: graphviz.Digraph, parent_path: str) -> None:
input_ports, output_ports = _split_ports(routine.ports)
input_ports, output_ports, through_ports = _split_ports(routine.ports)
label = f"{{{_ports_row(input_ports)}|{routine.name}|{_ports_row(output_ports)}}}"
if through_ports:
label += f"|{_ports_row(through_ports)}"
dag.node(f'"{".".join((parent_path, routine.name))}"', label=label, **LEAF_NODE_KWARGS)


Expand Down
107 changes: 107 additions & 0 deletions tests/qref/data/valid_programs/example_7.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
description: Program with a through port
input:
program:
children:
- name: child_1
ports:
- direction: input
name: in_0
size: 1
- direction: output
name: out_0
size: 1
- name: child_2
ports:
- direction: input
name: in_0
size: 1
- direction: output
name: out_0
size: 1
- name: child_3
ports:
- direction: input
name: in_0
size: 1
- direction: output
name: out_0
size: 1
- name: child_4
ports:
- direction: input
name: in_0
size: 1
- direction: output
name: out_0
size: 1
- name: child_5
ports:
- direction: input
name: in_0
size: 1
- direction: output
name: out_0
size: 1
- name: child_6
ports:
- direction: input
name: in_0
size: 1
- direction: output
name: out_0
size: 1
- direction: through
name: thru_0
size: 1
- name: child_7
ports:
- direction: input
name: in_0
size: 1
- direction: input
name: in_1
size: 1
- direction: output
name: out_0
size: 1
connections:
- source: in_0
target: child_1.in_0
- source: in_1
target: child_4.in_0
- source: in_2
target: child_5.in_0
- source: child_1.out_0
target: child_2.in_0
- source: child_2.out_0
target: child_3.in_0
- source: child_3.out_0
target: out_0
- source: child_4.out_0
target: child_6.in_0
- source: child_5.out_0
target: child_6.thru_0
- source: child_6.out_0
target: child_7.in_0
- source: child_6.thru_0
target: child_7.in_1
- source: child_7.out_0
target: out_1
name: root
ports:
- direction: input
name: in_0
size: 1
- direction: input
name: in_1
size: 1
- direction: input
name: in_2
size: 1
- direction: output
name: out_0
size: 1
- direction: output
name: out_1
size: 1
version: v1
110 changes: 110 additions & 0 deletions tests/qref/data/valid_programs/example_8.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
description: Program with several through ports in leafs and non-leafs
input:
program:
children:
- name: container
ports:
- direction: through
name: thru_0
size: 1
- direction: input
name: in_0
size: N
- direction: output
name: out_0
size: N
children:
- name: child_0
ports:
- direction: through
name: thru_0
size: N
connections:
- {source: in_0, target: child_0.thru_0}
- {source: child_0.thru_0, target: out_0}
- name: child_4
ports:
- direction: input
name: in_0
size: 1
- direction: output
name: out_0
size: 1
- name: child_5
ports:
- direction: input
name: in_0
size: 1
- direction: output
name: out_0
size: 1
- name: child_6
ports:
- direction: input
name: in_0
size: 1
- direction: output
name: out_0
size: 1
- direction: through
name: thru_0
size: 1
- name: child_7
ports:
- direction: input
name: in_0
size: 1
- direction: input
name: in_1
size: 1
- direction: output
name: out_0
size: 1

connections:
- source: in_0
target: container.thru_0
- source: in_1
target: child_4.in_0
- source: in_2
target: child_5.in_0
- source: container.thru_0
target: out_0
- source: child_4.out_0
target: child_6.in_0
- source: child_5.out_0
target: child_6.thru_0
- source: child_6.out_0
target: child_7.in_0
- source: child_6.thru_0
target: child_7.in_1
- source: child_7.out_0
target: out_1
- source: in_3
target: container.in_0
- source: container.out_0
target: out_3
name: root
ports:
- direction: input
name: in_0
size: 1
- direction: input
name: in_1
size: 1
- direction: input
name: in_2
size: 1
- direction: output
name: out_0
size: 1
- direction: output
name: out_1
size: 1
- direction: input
name: in_3
size: N
- direction: output
name: out_3
size: N
version: v1
Loading