Constructing Parity Phase Gates
The parity phase gate, generated by a multi-qubit \(Z\) interaction, can be written as
where \(\gamma\) denotes the target phase.
We express this operation in terms of the following primitive gates:
single-qubit \(Z\) rotations, \(R_Z(\phi) = e^{-i \frac{\phi}{2} Z}\), and
\(k\)-qubit controlled-phase gates (\(k \ge 2\)) acting on a subset \(S = \{i_1,\dots,i_k\}\),
\[\mathrm{CP}^{(k)}_S(\phi)=\exp\!\left(i \phi \, |1\cdots1\rangle\langle 1\cdots1|_S\right).\]This formulation enables the use of built-in tools in RydOpt to design optimal pulse sequences for implementing the parity gate.
The construction is based on expressing Pauli-\(Z\) operators in terms of projectors onto the computational basis state \(|1\rangle\). Using
A Pauli-\(Z\) string can be written as
Expanding this product yields
which, upon exponentiation, decomposes into a product of commuting phase gates: single-qubit \(R_Z\) rotations from the \(k=1\) terms and \(k\)-qubit controlled-phase gates for \(k \ge 2\).
For a general \(n\)-qubit parity operator, the resulting decomposition is
As a concrete example, for \(n=3\),
The coefficients (\(-2, 4, -8, \dots\)) arise from the powers of two in the projector expansion and exhibit an alternating sign structure. Interestingly, at the special value \(\gamma=\pi/4\), corresponding to the maximally entangling parity phase gate, all controlled-phase gates acting on three or more qubits acquire phases that are integer multiples of \(2\pi\) and thus reduce to identities. As a result, \(U_n(\pi/4)\) can be realized entirely using single-qubit \(R_Z\) gates and two-qubit \(\mathrm{CP}(\pi)=\mathrm{CZ}\) gates. In contrast, any deviation from \(\gamma=\pi/4\) necessarily reintroduces genuine many-body controlled-phase interactions.
Fixed–Target-Phase Optimization of the Parity Gate
We seek the shortest-duration pulse that implements a three-atom parity gate in the strong Rydberg blockade regime, using a fixed set of 10 pulse parameters. To this end, we carry out multiple random initializations of the pulse parameters, optimize each candidate pulse, and select the fastest one that achieves a gate fidelity exceeding the target threshold.
First, we create the target gate object. The Rydberg decay strength is set to \(10^{-4}\), and we assume uniform interaction strengths between atoms, \(V_{nn} = V_{nnn} = 32\).
[1]:
# %pip install -q --progress-bar off rydopt # Uncomment for installation on Colab
import rydopt as ro
import numpy as np
phase = np.pi / 4
gate = ro.gates.ThreeQubitGateIsosceles(
phi=None,
theta=4 * phase,
theta_prime=4 * phase,
lamb=-8 * phase,
Vnn=32,
Vnnn=32,
decay=0.0001,
)
Next, we create the pulse ansatz and specify upper and lower bounds for the random initialization of pulse parameters.
[2]:
# Pulse ansatz: constant detuning, sweep of the laser phase according to sin_crab ansatz
n_params = 12
pulse_ansatz = ro.pulses.SinglePhotonPulseAnsatz(
detuning_ansatz=ro.pulses.Const(), phase_ansatz=ro.pulses.SinCrab(n_params)
)
# Bounds for the initial pulse parameter guesses
min_initial_params = ro.pulses.PulseParams(15, [-1], -2 * np.ones(n_params), [])
max_initial_params = ro.pulses.PulseParams(20, [1], 2 * np.ones(n_params), [])
Perform 800 random parameter initializations, running in parallel on 4 CPU cores.
[3]:
opt_result = ro.optimization.multi_start_optimize(
gate,
pulse_ansatz,
min_initial_params,
max_initial_params,
num_steps=100,
tol=1e-8,
num_initializations=100,
num_processes=4,
return_history=True,
return_all=True,
)
Started optimization using 4 processes
=== Optimization finished using multi-start Adam ===
Runtime: 84.140 seconds
Gates with infidelity below tol=1.0e-08: 0
Best gate:
> infidelity = 8.786351e-04
PulseParams(
duration = [20.71079392],
detuning_params = [-0.1509117],
phase_params = [ 0.97312533, 0.86651396, -0.58884901, 1.71954182, 1.78016487, -0.71903126, -1.21707987,
-0.21997073, 0.05350197, -0.07214252, -0.78337956, 1.40456329],
rabi_params = []
)
We plot the history of all optimization runs;
[4]:
ro.characterization.plot_optimization_history(opt_result);
Also, we analyze the best performing gate;
[5]:
optimized_params = opt_result.params[0]
infidelity, infidelity_nodecay, ryd_time = ro.characterization.analyze_gate(
gate,
pulse_ansatz,
optimized_params,
tol=1e-8,
)
print(f"Gate infidelity: {infidelity:.4e}")
print(f"Gate infidelity (no decay): {infidelity_nodecay:.4e}")
print(f"Rydberg time: {ryd_time:.4f}")
Gate infidelity: 8.7864e-04
Gate infidelity (no decay): 7.5724e-06
Rydberg time: 8.7149
Finally, we plot the optimal pulse and its spectrum.
[6]:
ro.characterization.plot_spectrum(pulse_ansatz, optimized_params)
fig, ax = ro.characterization.plot_pulse(pulse_ansatz, optimized_params)
Parity gate family
Here, we aim to optimize the parity gate over a range of target gate phases. To this end, we express the trainable parameters of the laser phase ansatz as polynomial functions of \(\theta=4\gamma\). We begin by defining a gate family with a list of target phases and a corresponding pulse family using a polynomial map. Duration and other pulse parameters can be treated analogously by assigning them nonzero polynomial degrees.
[ ]:
target_phases = np.linspace(0.05, 0.25, 5) * np.pi
sampled_gates = [
ro.gates.ThreeQubitGateIsosceles(
phi=None,
theta=4 * phase,
theta_prime=4 * phase,
lamb=-8 * phase,
Vnn=32,
Vnnn=32,
decay=0.0001,
)
for phase in target_phases
]
gate_family = ro.gates.GateFamily(
fixed_argument_gates=sampled_gates,
argument_values=target_phases,
)
# Family pulse ansatz (pulse ansatze + polynomial mapping)
degrees = [1, 0, 3, 0]
pulse_mal = ro.pulses.PolynomialPulseMap(degrees=degrees)
pulse_family = ro.pulses.PulseFamilyAnsatz(
detuning_ansatz=ro.pulses.Const(),
phase_ansatz=ro.pulses.SinCrab(n_params),
pulse_map=pulse_mal,
)
With all components in place, we proceed to the optimization stage. We then assess the individual properties of each optimal pulse in the pulse family and visualize them.
[ ]:
min_initial_params = ro.pulses.PulseFamilyParams(
[10.0, *[0.0] * degrees[0]],
-1.0 * np.ones(degrees[1] + 1),
-2 * np.ones((n_params, degrees[2] + 1)),
[],
)
max_initial_params = ro.pulses.PulseFamilyParams(
[20.0, *[34.0] * degrees[0]],
1.0 * np.ones(degrees[1] + 1),
2 * np.ones((n_params, degrees[2] + 1)),
[],
)
opt_result_gate_family = ro.optimization.multi_start_optimize(
gate_family,
pulse_family,
min_initial_params,
max_initial_params,
tol=1e-8,
num_initializations=200,
num_steps=150,
num_processes=4,
return_history=False,
)
optimized_params_gate_family = opt_result_gate_family.params
# Print the gate family performance measures
print("\n=== Performance analysis of the best/fastest optimized gate pulse ===\n")
pulse = pulse_family.pulse_ansatz
for gate, value in zip(gate_family.gates, gate_family.argument_values):
params = pulse_family.generate_pulse_params(optimized_params_gate_family, value)
infidelity, infidelity_nodecay, ryd_time = ro.characterization.analyze_gate(
gate,
pulse,
params,
tol=1e-8,
)
print(f"Target phase: {value / np.pi:.2f}")
print(f"Gate infidelity: {infidelity:.4e}")
print(f"Gate infidelity (no decay): {infidelity_nodecay:.4e}")
print(f"Rydberg time: {ryd_time:.4f}\n")
# plot the optimal pulse family
ro.characterization.plot_pulse_family(
pulse_family,
optimized_params_gate_family,
gate_family,
plot_detuning=False,
plot_rabi=False,
);
Started optimization using 4 processes
=== Optimization finished using multi-start Adam ===
Runtime: 1103.771 seconds
Gates with infidelity below tol=1.0e-08: 0
Best gate:
> infidelity = 2.732546e-03
PulseFamilyParams(
duration_params = [12.84145951, 34.47266429],
detuning_params = [-0.05502751],
phase_params = [[-5.47386302e-01, -2.29527937e+00, -1.58147493e+00, -3.15964634e+00],
[ 6.77653106e-03, -3.33171846e-02, 1.87366803e+00, 8.05054874e-01],
[-6.73267840e-01, -3.07006390e+00, -2.10001072e+00, -2.29809882e+00],
[ 6.45083313e-01, -3.82129397e+00, -5.50096907e+00, -4.37885098e+00],
[-1.85643027e+00, -1.56008148e+00, -2.18351522e+00, -2.53363948e+00],
[ 1.69460568e+00, -1.83068212e+00, -1.54980447e+00, -5.69337972e+00],
[-2.73743996e+00, 6.78249197e-01, -2.94002464e-03, -1.05033156e+00],
[ 2.42528651e-01, -3.35988491e+00, -1.41548146e+00, -4.81971892e+00],
[-3.86351009e-01, -2.85876933e-01, -1.06333581e-01, -1.61964379e+00],
[-5.05386413e-01, 1.70948026e+00, 3.53570634e+00, 2.55074031e+00],
[ 4.90904401e-01, 6.65822663e-01, 9.46753687e-01, 2.17052155e-01],
[-1.27182955e-01, 2.23905222e+00, 3.03157212e+00, 5.24091678e+00]],
rabi_params = []
)
=== Performance analysis of the best/fastest optimized gate pulse ===
Target phase: 0.05
Gate infidelity: 3.2741e-03
Gate infidelity (no decay): 2.7420e-03
Rydberg time: 5.3374
Target phase: 0.10
Gate infidelity: 9.4576e-04
Gate infidelity (no decay): 3.9159e-04
Rydberg time: 5.5464
Target phase: 0.15
Gate infidelity: 3.0473e-03
Gate infidelity (no decay): 2.4631e-03
Rydberg time: 5.8609
Target phase: 0.20
Gate infidelity: 2.5053e-03
Gate infidelity (no decay): 1.8813e-03
Rydberg time: 6.2547
Target phase: 0.25
Gate infidelity: 3.8902e-03
Gate infidelity (no decay): 3.2233e-03
Rydberg time: 6.6996