Skip to content

Commit 15e43a2

Browse files
authored
Adding interface for single zone heuristic noise models (#196)
This PR sketches an interface for building a heuristic noise model for a single zone layout. The only requirement is implementing a method that calculates the time for reconfiguration of the atoms to do the CZ gates and forwards that to that duration to the idle error of the qubits that are not moved.
1 parent 29b8e4d commit 15e43a2

File tree

1 file changed

+77
-3
lines changed

1 file changed

+77
-3
lines changed

src/bloqade/noise/native/model.py

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ class GateNoiseParams:
4848

4949
@dataclass(frozen=True)
5050
class MoveNoiseParams:
51+
idle_px_rate: float = field(default=1e-6, kw_only=True)
52+
"""The error rate (prob/microsecond) for a Pauli-X error during an idle operation."""
53+
idle_py_rate: float = field(default=1e-6, kw_only=True)
54+
"""The error rate (prob/microsecond) for a Pauli-Y error during an idle operation."""
55+
idle_pz_rate: float = field(default=1e-6, kw_only=True)
56+
"""The error rate (prob/microsecond) for a Pauli-Z error during an idle operation."""
57+
idle_loss_rate: float = field(default=1e-6, kw_only=True)
58+
"""The error rate (prob/microsecond) for a loss during an idle operation."""
59+
5160
move_px_rate: float = field(default=1e-6, kw_only=True)
5261
"""The error rate (prob/microsecond) for a Pauli-X error during a move operation."""
5362
move_py_rate: float = field(default=1e-6, kw_only=True)
@@ -259,14 +268,79 @@ def parallel_cz_errors(
259268
px_time = self.poisson_pauli_prob(self.params.move_px_rate, move_duration)
260269
py_time = self.poisson_pauli_prob(self.params.move_py_rate, move_duration)
261270
px_time = self.poisson_pauli_prob(self.params.move_pz_rate, move_duration)
262-
p_loss_time = self.poisson_pauli_prob(self.params.move_loss_rate, move_duration)
271+
move_p_loss_time = self.poisson_pauli_prob(
272+
self.params.move_loss_rate, move_duration
273+
)
263274

264-
errors = {(px_time, py_time, px_time, p_loss_time): rest}
275+
errors = {(px_time, py_time, px_time, move_p_loss_time): rest}
265276

266277
px_moved = self.join_binary_probs(self.params.pick_px, px_time)
267278
py_moved = self.join_binary_probs(self.params.pick_py, py_time)
268279
pz_moved = self.join_binary_probs(self.params.pick_pz, px_time)
269-
p_loss_moved = self.join_binary_probs(self.params.pick_loss_prob, p_loss_time)
280+
p_loss_moved = self.join_binary_probs(
281+
self.params.pick_loss_prob, move_p_loss_time
282+
)
283+
284+
errors[(px_moved, py_moved, pz_moved, p_loss_moved)] = sorted(ctrls + qargs)
285+
286+
return errors
287+
288+
289+
@dataclass
290+
class SingleZoneLayoutABC(MoveNoiseModelABC):
291+
gate_noise_params: GateNoiseParams = field(
292+
default_factory=GateNoiseParams, kw_only=True
293+
)
294+
295+
@abc.abstractmethod
296+
def calculate_move_duration(self, ctrls: List[int], qargs: List[int]) -> float:
297+
"""Calculate the time it takes to reconfigure the atom for executing the CZ gates."""
298+
299+
def parallel_cz_errors(
300+
self, ctrls: List[int], qargs: List[int], rest: List[int]
301+
) -> Dict[Tuple[float, float, float, float], List[int]]:
302+
"""Apply parallel gates by moving ctrl qubits to qarg qubits."""
303+
304+
move_duration = self.calculate_move_duration(ctrls, qargs)
305+
306+
# idle errors during atom moves
307+
idle_px_time = self.poisson_pauli_prob(self.params.idle_px_rate, move_duration)
308+
idle_py_time = self.poisson_pauli_prob(self.params.idle_py_rate, move_duration)
309+
idle_pz_time = self.poisson_pauli_prob(self.params.idle_pz_rate, move_duration)
310+
idle_p_loss_time = self.poisson_pauli_prob(
311+
self.params.idle_loss_rate, move_duration
312+
)
313+
314+
# even qubits not involved in the gate can still experience unpaired errors
315+
idle_px = self.join_binary_probs(
316+
self.gate_noise_params.cz_unpaired_gate_px, idle_px_time
317+
)
318+
idle_py = self.join_binary_probs(
319+
self.gate_noise_params.cz_unpaired_gate_py, idle_py_time
320+
)
321+
idle_pz = self.join_binary_probs(
322+
self.gate_noise_params.cz_unpaired_gate_pz, idle_pz_time
323+
)
324+
idle_p_loss = self.join_binary_probs(
325+
self.gate_noise_params.cz_unpaired_loss_prob, idle_p_loss_time
326+
)
327+
328+
errors = {(idle_px, idle_py, idle_pz, idle_p_loss): rest}
329+
330+
# error during the move
331+
move_px_time = self.poisson_pauli_prob(self.params.move_px_rate, move_duration)
332+
move_py_time = self.poisson_pauli_prob(self.params.move_py_rate, move_duration)
333+
move_pz_time = self.poisson_pauli_prob(self.params.move_pz_rate, move_duration)
334+
move_p_loss_time = self.poisson_pauli_prob(
335+
self.params.move_loss_rate, move_duration
336+
)
337+
# error coming from picking up the qubits
338+
px_moved = self.join_binary_probs(self.params.pick_px, move_px_time)
339+
py_moved = self.join_binary_probs(self.params.pick_py, move_py_time)
340+
pz_moved = self.join_binary_probs(self.params.pick_pz, move_pz_time)
341+
p_loss_moved = self.join_binary_probs(
342+
self.params.pick_loss_prob, move_p_loss_time
343+
)
270344

271345
errors[(px_moved, py_moved, pz_moved, p_loss_moved)] = sorted(ctrls + qargs)
272346

0 commit comments

Comments
 (0)