Quandela / Perceval

An open source framework for programming photonic quantum computers
https://perceval.quandela.net
Other
133 stars 63 forks source link

Rendering: incorrect size of circuit box #414

Open burlemarxiste opened 3 weeks ago

burlemarxiste commented 3 weeks ago

When a processor contains nested circuits (created with the merge=False argument passed to add), the blue box enclosing each subblock is of the wrong size.

The reason is that the drawing of elements stops at one level of recursion, whereas the get_size call goes to the full depth.

This is a circuit from a tutorial:

import perceval as pcvl
from perceval.components import core_catalog
from perceval.rendering import format

from perceval.components.unitary_components import PS, BS, PERM

pre_MZI = (pcvl.Circuit(4, name="Bell State Prep")
           .add(0, BS())
           .add(2, BS())
           .add(1, PERM([1, 0])))

upper_MZI = (pcvl.Circuit(2, name="upper MZI")
             .add(0, PS(phi=pcvl.P('phi_0')))
             .add(0, BS())
             .add(0, PS(phi=pcvl.P('phi_2')))
             .add(0, BS()))

lower_MZI = (pcvl.Circuit(2, name="lower MZI")
             .add(0, PS(phi=pcvl.P('phi_1')))
             .add(0, BS())
             .add(0, PS(phi=pcvl.P('phi_3')))
             .add(0, BS()))

chip = (pcvl.Circuit(4)
              .add(0, pre_MZI, merge=False)
              .add(0, upper_MZI, merge=False)
              .add(2, lower_MZI, merge=False))

processor = pcvl.Processor('SLOS', chip)
output_format = format.Format.MPLOT
extension = "pdf"

pcvl.pdisplay_to_file(processor, 'pdisplay_multiblocks.' + extension, output_format, recursive=True)

By changing some of the merge=False arguments to True, one can get circuits with various degrees of nesting. In all the following examples, the size of the blue circuit box is the same, and corresponds to the size of the fully flattened circuit.

Screenshot 2024-06-11 at 10 49 48 Screenshot 2024-06-11 at 10 50 27 Screenshot 2024-06-11 at 10 50 47

In ICircuitRenderer.render_circuit, the call to self.get_circuit_size(c, recursive=True) is the culprit since it will always return the same value, (9, 4), corresponding to the size of a completely flattened circuit.

Possible fixes:

  1. Add a recursion_level parameter to all functions recursively traversing circuits (flatten, get_size, get_circuit_size, render_circuit, pdisplay_processor, pdisplay_circuit...), and make sure they consistently traverse the circuit graph at the appropriate depth.
  2. Assume that one should never draw anything deeper than one level of recursion, and thus set recursive=False in the function call retrieving the size of a block. A similar change has to be done to the herald positioning code (it should flatten only one level deep to attach the heralds to the elements that are actually going to be drawn).
  3. Assume that setting recursive=True should always go to the full recursion depth, at the risk of getting large diagrams. Thus render_circuit should pass its recursive argument when calling itself.