I have two questions / feature request regarding template matching and arrays.
Below there is a code example that uses a blackbird template to extract the gate parameters a user might request in a blackbird program.
float array squeezing_amplitudes[1, 4] =
{squeezing_amplitudes}
I couldn't get it working with a 1-D array, and did not find anything related in the docs. Is there a way to define a 1-D array instead?
float array squeezing_amplitudes[4] =
{squeezing_amplitudes}
Q2: Q2: While my template defines an array parameter (e.g. squeezing_ampltidues
), the template matching returns the individual elements (squeezing_ampltidutes_0_0
, ..._0_1
, and so on). Is there a trick to get an array or list back from the template matching?
import blackbird
from blackbird.utils import match_template
prog = blackbird.loads("""
name prog
version 1.0
target X8 (shots=1)
S2gate(0, 0.0) | [0, 4]
S2gate(0, 0.0) | [1, 5]
S2gate(0, 0.0) | [2, 6]
S2gate(0, 0.0) | [3, 7]
MZgate(1.1, 1.1) | [0, 1]
MZgate(1.1, 1.1) | [2, 3]
MZgate(1.1, 1.1) | [1, 2]
MZgate(1.1, 1.1) | [0, 1]
MZgate(1.1, 1.1) | [2, 3]
MZgate(1.1, 1.1) | [1, 2]
MZgate(1.1, 1.1) | [4, 5]
MZgate(1.1, 1.1) | [6, 7]
MZgate(1.1, 1.1) | [5, 6]
MZgate(1.1, 1.1) | [4, 5]
MZgate(1.1, 1.1) | [6, 7]
MZgate(1.1, 1.1) | [5, 6]
Rgate(0.2) | 0
Rgate(0.2) | 1
Rgate(0.2) | 2
Rgate(0.2) | 3
Rgate(0.2) | 4
Rgate(0.2) | 5
Rgate(0.2) | 6
Rgate(0.2) | 7
MeasureFock() | [0, 1, 2, 3, 4, 5, 6, 7]
""")
template = blackbird.loads(
"""
name template
version 1.0
target X8 (shots=1)
float array squeezing_amplitudes[1, 4] =
{squeezing_amplitudes}
float array phases[1, 12] =
{phases}
float array final_phases[1, 8] =
{final_phases}
# for n spatial degrees, first n signal modes, then n idler modes, all phases zero
S2gate(squeezing_amplitudes[0], 0.0) | [0, 4]
S2gate(squeezing_amplitudes[1], 0.0) | [1, 5]
S2gate(squeezing_amplitudes[2], 0.0) | [2, 6]
S2gate(squeezing_amplitudes[3], 0.0) | [3, 7]
# standard 4x4 interferometer for the signal modes (the lower ones in frequency)
# even phase indices correspond to internal Mach-Zehnder interferometer phases
# odd phase indices correspond to external Mach-Zehnder interferometer phases
MZgate(phases[0], phases[1]) | [0, 1]
MZgate(phases[2], phases[3]) | [2, 3]
MZgate(phases[4], phases[5]) | [1, 2]
MZgate(phases[6], phases[7]) | [0, 1]
MZgate(phases[8], phases[9]) | [2, 3]
MZgate(phases[10], phases[11]) | [1, 2]
# duplicate the interferometer for the idler modes (the higher ones in frequency)
MZgate(phases[0], phases[1]) | [4, 5]
MZgate(phases[2], phases[3]) | [6, 7]
MZgate(phases[4], phases[5]) | [5, 6]
MZgate(phases[6], phases[7]) | [4, 5]
MZgate(phases[8], phases[9]) | [6, 7]
MZgate(phases[10], phases[11]) | [5, 6]
# add final dummy phases to allow mapping any unitary to this template (these do not
# affect the photon number measurement)
Rgate(final_phases[0]) | [0]
Rgate(final_phases[1]) | [1]
Rgate(final_phases[2]) | [2]
Rgate(final_phases[3]) | [3]
Rgate(final_phases[4]) | [4]
Rgate(final_phases[5]) | [5]
Rgate(final_phases[6]) | [6]
Rgate(final_phases[7]) | [7]
# measurement in Fock basis
MeasureFock() | [0, 1, 2, 3, 4, 5, 6, 7]
""")
match_template(template, prog)
{'squeezing_amplitudes_0_0': 0,
'phases_0_0': 1.1,
'phases_0_1': 1.1,
'phases_0_6': 1.1,
'phases_0_7': 1.1,
'final_phases_0_0': 0.2,
'final_phases_0_4': 0.2,
'phases_0_4': 1.1,
...