Clarification on applying individual transformations
Opened this issue · 5 comments
My goal is to apply a single transformation to a graph that satisfies the 'graph-like' precondition.
First approach
I tried to apply the following transformations mentioned in #199 (to_gh
and spider_simp
):
fname = os.path.join('..','circuits','Fast', 'mod5_4_before')
circ = zx.Circuit.load(fname).to_basic_gates()
x = circ.to_graph() # We first have to convert the circuit into a ZX-graph
initial_graph = copy.deepcopy(x)
# turn all red spiders into green spiders
zx.to_gh(initial_graph)
# simplify: remove excess HAD's, fuse along non-HAD edges, remove parallel edges and self-loops
zx.simplify.spider_simp(initial_graph, quiet=True)
# checking transformed graph
print(f'zx.simplify.is_graph_like:{zx.simplify.is_graph_like(initial_graph)}')
Output:
zx.simplify.is_graph_like:False
But the graph was not 'graph-like'.
Second approach
My second approach was using specific functions to convert to 'graph-like'.
I converted the 'mod5_4_before' circuit to a graph, and later to a 'graph-like' graph using the 'to_graph_like' function.
I have to say that to_graph_like
function appears in a code block with a note:
"#The functions below haven't been updated in a while. Use at your own risk.", although the function appears to implement the requirements necessary for a graph to satisfy the 'graph-like' condition according to 'Hybrid quantum-classical circuit simplification
with the ZX-calculus'. (page 6).
After this, I applied the transformation 'zx.rules.remove_ids' to the graph of type 'graph-like', and checked the type of graph using the 'is_graph_like' function, this function returned False
-> so, it was not a graph of type 'graph-like'.
fname = os.path.join('.','circuits','Fast', 'mod5_4_before')
circ = zx.Circuit.load(fname).to_basic_gates()
x = circ.to_graph() # We first have to convert the circuit into a ZX-graph
graph = copy.deepcopy(x)
print('--------------------------------------')
graph_aux = copy.deepcopy(graph)
zx.simplify.to_graph_like(graph_aux)
print(f'zx.simplify.is_graph_like(graph_aux):{zx.simplify.is_graph_like(graph_aux)}')
print('--------------------------------------')
zx.draw(graph_aux, labels=True)
print('--------------------------------------')
matcher_params = zx.rules.match_ids_parallel(graph_aux)
print(f'matcher_params[0]:{matcher_params[0]}')
print('--------------------------------------')
zx.rules.apply_rule(graph_aux, zx.rules.remove_ids,[matcher_params[0]])
zx.draw(graph_aux, labels=True)
print(f'zx.simplify.is_graph_like:{zx.simplify.is_graph_like(graph_aux)}')
Output:
As I said at the beginning of this comment, my goal is to apply a transform to a circuit.
In this case, I tested the 'zx.rules.remove_ids' transformation, and the result does not seem to be satisfactory.
I am very confused, please:
- Could someone explain to me this result?
And - Could someone tell me how can I apply any transformation individually without getting errors?
The first thing seems to be a bug, potentially in the is_graph_like
function.
The second one is because removing an identity breaks the graph being graph like. You can see this in your last picture: there is a regular edge between vertices 38 and 48. If you want to make it graph like then you should fuse the spiders again.
I've now changed the default behaviour to is_graph_like
so that it makes sense here. The old behaviour you can get by setting the new parameter strict=True.
Thanks @jvdwetering.
-
In the first case, the result is now a "graph-like" (strict=False) graph according to the default behavior of the modified function.
-
In the second case, yes, if I only fuse the spiders again, the resulting graph is 'graph-like', as indicated by the
is_graph_like
function.
Taking these results into account:
- Should I generalize and believe that every time I apply a transformation (any) to a 'graph-like' graph, it is enough to fuse the spiders immediately afterwards to still get a 'graph-like' graph?
- Or should I also take into account the other conditions present in the
to_graph_like
function relating to:
-#ensure all I/O are connected to a Z-spider
Line 463 in b2bb047
-#each Z-spider can only be connected to at most 1 I/O
Line 491 in b2bb047
It depends on what you want to do with your graph-like diagram. But yes, fusing all spiders is definitely a necessity.
What I would like to do with my graph-type diagram is to be able to apply a set of transformations to a circuit, making sure that I do not modify the functionality/semantics of the graph corresponding to the circuit.
So this is my question, taking into account the new parameter in the function I can apply to a circuit:
- the least restrictive call -> is_graph_like(g, strict=False)
or - the most strict call -> is_graph_like(g, strict=True)
Which one should I apply?