matt-lourens / hierarqcal

Generate hierarchical quantum circuits for Neural Architecture Search.
https://matt-lourens.github.io/hierarqcal/
BSD 3-Clause "New" or "Revised" License
41 stars 15 forks source link

Add functionality to visualise hypergraphs (N-ary edges for digraphs) #27

Closed matt-lourens closed 1 year ago

matt-lourens commented 1 year ago

Summary

Every primitive (Qcycle, Qmask, Qpermute) is a directed graph, with nodes corresponding to qubits and edges to unitaries applied between them. Currently, only 2 qubit primitives get plotted, for example, Qcycle with different stride values:

sc1 = Qinit(8) + Qcycle(stride=1, mapping=u2) # plot_motif(sc1[1])
sc3 = Qinit(8) + Qcycle(stride=3, mapping=u2) # plot_motif(sc3[1])
sc5 = Qinit(8) + Qcycle(stride=5, mapping=u2) # plot_motif(sc5[1])
sc7 = Qinit(8) + Qcycle(stride=7, mapping=u2) # plot_motif(sc7[1])

image It is however possible to provide a N-qubit unitary to a primitive, these correspond to hypergraphs (3-qubit unitary means the underlying graph has 3-tuple edges ex. primitive.E = [(1,2,3),(5,4,3),...]). These need to be visualised with bands, and should look as follows:

m1 = Qinit(15) + Qcycle(stride=1, step=3, offset=0, mapping=Qunitary(arity=3)) # plot_motif(m1[1])
m2 = Qinit(15) + Qcycle(stride=1, step=3, offset=2, mapping=Qunitary(arity=3))  # plot_motif(m2[1])
m3 = Qinit(15) + Qcycle(stride=3, step=1, offset=0, mapping=Qunitary(arity=3)) # plot_motif(m3[1])

image

The plot motif function in utils.py already receives the primitive with the correct edges produced for N-qubit unitaries (i.e. you receive a graph with nodes and N-tuple edges). For the example above, m1[1].E=[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, 15)]. The task is to plot this graph, as shown above. The hypergraphs above were produced with https://github.com/pnnl/HyperNetX but I don't want to add it as a dependency to the package (to keep the package lightweight, we only want to visualise graphs not interact with them). This is the reason why networkx isn't a dependency and the digraphs for 2-qubit unitaries are drawn with matplotlib. Use the 2-tuple case as a reference to implement the N-qubit case, the goal is to produce graphs similar to the ones above. We have the node radius and center position information, so we have to draw a path around the nodes (without touching them). I think this is a fun problem that can be solved with a little bit of linear algebra (see the 2-tuple case for how the arrowhead positions are determined).

metalcyanide commented 1 year ago

Hi @matt-lourens, I'm interested to take this up.