mimiqcircuits.noisemodel¶
Noise model definitions and application.
This module implements rule-based noise injection for mimiqcircuits circuits.
Rules are evaluated by priority (lower value means higher priority), and the first
matching rule is applied to each instruction.
Functions
|
Apply a noise model to a circuit and return a new circuit. |
Classes
Abstract base class for all noise rules. |
|
|
|
|
|
|
|
|
|
|
|
|
Collection of prioritized noise rules. |
|
|
|
|
|
|
|
- class mimiqcircuits.noisemodel.AbstractNoiseRule[source]¶
Bases:
objectAbstract base class for all noise rules.
- class mimiqcircuits.noisemodel.GlobalReadoutNoise(noise: 'mc.ReadoutErr')[source]¶
Bases:
AbstractNoiseRule- noise: ReadoutErr¶
- __init__(noise)¶
- class mimiqcircuits.noisemodel.ExactQubitReadoutNoise(qubits: 'Sequence[int]', noise: 'mc.ReadoutErr')[source]¶
Bases:
AbstractNoiseRule- noise: ReadoutErr¶
- __init__(qubits, noise)¶
- class mimiqcircuits.noisemodel.SetQubitReadoutNoise(qubits: 'Iterable[int]', noise: 'mc.ReadoutErr')[source]¶
Bases:
AbstractNoiseRule- noise: ReadoutErr¶
- __init__(qubits, noise)¶
- class mimiqcircuits.noisemodel.OperationInstanceNoise(operation: 'mc.Operation', noise: 'Union[mc.krauschannel, mc.Gate]', before: 'bool' = False, replace: 'bool' = False)[source]¶
Bases:
AbstractNoiseRule- __init__(operation, noise, before=False, replace=False)¶
- class mimiqcircuits.noisemodel.ExactOperationInstanceQubitNoise(operation: 'mc.Operation', qubits: 'Sequence[int]', noise: 'Union[mc.krauschannel, mc.Gate]', before: 'bool' = False, replace: 'bool' = False)[source]¶
Bases:
AbstractNoiseRule- __init__(operation, qubits, noise, before=False, replace=False)¶
- class mimiqcircuits.noisemodel.SetOperationInstanceQubitNoise(operation: 'mc.Operation', qubits: 'Iterable[int]', noise: 'Union[mc.krauschannel, mc.Gate]', before: 'bool' = False, replace: 'bool' = False)[source]¶
Bases:
AbstractNoiseRule- __init__(operation, qubits, noise, before=False, replace=False)¶
- class mimiqcircuits.noisemodel.IdleNoise(relation: 'Union[tuple, mc.Operation]')[source]¶
Bases:
AbstractNoiseRule- __init__(relation)¶
- class mimiqcircuits.noisemodel.SetIdleQubitNoise(relation: 'Union[tuple, mc.Operation]', qubits: 'Iterable[int]')[source]¶
Bases:
AbstractNoiseRule- __init__(relation, qubits)¶
- class mimiqcircuits.noisemodel.CustomNoiseRule(matcher: 'Callable[[mc.Instruction], bool]', generator: 'Callable[[mc.Instruction], mc.Instruction]', priority_val: 'int' = 0, before: 'bool' = False, replace: 'bool' = False)[source]¶
Bases:
AbstractNoiseRule- matcher: Callable[[Instruction], bool]¶
- generator: Callable[[Instruction], Instruction]¶
- __init__(matcher, generator, priority_val=0, before=False, replace=False)¶
- class mimiqcircuits.noisemodel.NoiseModel(rules=<factory>, name='')[source]¶
Bases:
objectCollection of prioritized noise rules.
Rules are always kept sorted by
priority()so more specific rules win over generic fallbacks.Priority order (lower number = higher priority): -
CustomNoiseRule(defaultPRIORITY_USER_OVERRIDE) -ExactOperationInstanceQubitNoise(PRIORITY_EXACT_OPERATION) -ExactQubitReadoutNoise(PRIORITY_EXACT_READOUT) -SetOperationInstanceQubitNoise(PRIORITY_SET_OPERATION) -SetQubitReadoutNoise(PRIORITY_SET_READOUT) -OperationInstanceNoise(PRIORITY_GLOBAL_OPERATION) -GlobalReadoutNoise(PRIORITY_GLOBAL_READOUT) -SetIdleQubitNoise(PRIORITY_SET_IDLE) -IdleNoise(PRIORITY_IDLE)- Parameters:
rules (List[AbstractNoiseRule]) – Initial list of rules.
name (str) – Optional model name.
Example
>>> import mimiqcircuits as mc >>> from symengine import symbols, pi >>> theta = symbols("theta") >>> model = mc.NoiseModel( ... [ ... mc.OperationInstanceNoise(mc.GateRX(theta), mc.Depolarizing(1, theta / pi)), ... mc.ExactOperationInstanceQubitNoise(mc.GateCX(), [0, 1], mc.Depolarizing(2, 0.01)), ... mc.GlobalReadoutNoise(mc.ReadoutErr(0.01, 0.02)), ... mc.IdleNoise(mc.AmplitudeDamping(1e-4)), ... ], ... name="angle-dependent", ... )
- rules: List[AbstractNoiseRule]¶
- add_readout_noise(noise, *, qubits=None, exact=False)[source]¶
Add a readout-noise rule.
Behavior: -
qubits is None: addGlobalReadoutNoise. -qubitswithexact=False: addSetQubitReadoutNoise. -qubitswithexact=True: addExactQubitReadoutNoise.- Parameters:
noise (ReadoutErr) – Readout error channel.
qubits – Optional qubit targets.
exact – When
True, qubit order must match exactly.
- Returns:
self(for chaining).
Example
>>> import mimiqcircuits as mc >>> model = mc.NoiseModel() >>> model.add_readout_noise(mc.ReadoutErr(0.01, 0.02)) NoiseModel(rules=[GlobalReadoutNoise(noise=RErr(0.01,0.02))], name='') >>> model.add_readout_noise(mc.ReadoutErr(0.03, 0.04), qubits=[0, 2]) NoiseModel(rules=[SetQubitReadoutNoise(qubits=(0, 2), noise=RErr(0.03,0.04)), GlobalReadoutNoise(noise=RErr(0.01,0.02))], name='') >>> model.add_readout_noise(mc.ReadoutErr(0.05, 0.06), qubits=[2, 0], exact=True) NoiseModel(rules=[ExactQubitReadoutNoise(qubits=(2, 0), noise=RErr(0.05,0.06)), SetQubitReadoutNoise(qubits=(0, 2), noise=RErr(0.03,0.04)), GlobalReadoutNoise(noise=RErr(0.01,0.02))], name='')
- add_operation_noise(operation, noise, *, qubits=None, exact=False, before=False, replace=False)[source]¶
Add operation-instance noise.
operationcan be concrete (exact parameter match) or symbolic (match by operation type and substitute parameters intonoise).- Parameters:
operation – Operation pattern to match.
noise – Noise operation/channel to inject.
qubits – Optional qubit restriction.
exact – If
True, qubits must match the exact ordered tuple.before – If
True, insert noise before the matched instruction.replace – If
True, replace the matched instruction with noise.
- Returns:
self(for chaining).- Raises:
ValueError – If operation target is unsupported or arguments are invalid.
Examples
>>> import mimiqcircuits as mc >>> from symengine import symbols, pi >>> theta, alpha, beta = symbols("theta alpha beta") >>> model = mc.NoiseModel() >>> _ = model.add_operation_noise(mc.GateRX(pi / 2), mc.AmplitudeDamping(0.001)) >>> _ = model.add_operation_noise(mc.GateRX(theta), mc.Depolarizing(1, theta / pi)) >>> _ = model.add_operation_noise( ... mc.GateU(alpha, beta, 0), ... mc.Depolarizing(1, (alpha**2 + beta**2) / (2 * pi**2)), ... ) >>> _ = model.add_operation_noise( ... mc.GateRX(theta), ... mc.Depolarizing(1, theta / pi), ... qubits=[0, 1, 2], ... ) >>> _ = model.add_operation_noise( ... mc.GateRX(theta), ... mc.Depolarizing(1, theta / pi), ... qubits=[0], ... exact=True, ... ) >>> _ = model.add_operation_noise(mc.Measure(), mc.PauliX(0.02), before=True) >>> _ = model.add_operation_noise(mc.Reset(), mc.Depolarizing(1, 0.01)) >>> _ = model.add_operation_noise(mc.GateH(), mc.AmplitudeDamping(0.001), replace=True)
- add_idle_noise(noise, qubits=None)[source]¶
Add idle-noise rule(s) for
Delayinstructions.noisecan be a constant operation or a relation tuple(time_symbol, target_operation_expr).- Parameters:
noise – Idle noise operation or symbolic relation.
qubits – Optional qubit subset where idle noise is allowed.
- Returns:
self(for chaining).
Example
>>> import mimiqcircuits as mc >>> from symengine import symbols >>> t = symbols("t") >>> model = mc.NoiseModel() >>> model.add_idle_noise(mc.AmplitudeDamping(1e-4)) NoiseModel(rules=[IdleNoise(relation=AmplitudeDamping(0.0001))], name='') >>> model.add_idle_noise((t, mc.AmplitudeDamping(t / 1000)), qubits=[0, 1, 2]) NoiseModel(rules=[SetIdleQubitNoise(relation=(t, AmplitudeDamping((1/1000)*t)), qubits=frozenset({0, 1, 2})), IdleNoise(relation=AmplitudeDamping(0.0001))], name='')
- apply_noise_model(circuit)[source]¶
Apply this noise model and return a new noisy circuit.
This is a convenience wrapper around module-level
apply_noise_model.
- __init__(rules=<factory>, name='')¶
- mimiqcircuits.noisemodel.apply_noise_model(circuit, model)[source]¶
Apply a noise model to a circuit and return a new circuit.
Rules are evaluated in priority order. For each instruction, only the first matching rule is applied.
Wrapper operations are traversed recursively:
Block,IfStatement,Parallel,Repeat, andGateCall.- Parameters:
circuit (Circuit) – Input circuit.
model (NoiseModel) – Noise model to apply.
- Returns:
A new circuit with injected noise.
Examples
>>> import mimiqcircuits as mc >>> from symengine import symbols, pi >>> theta = symbols("theta") >>> c = mc.Circuit() >>> c.push(mc.GateRX(0.4), 0) 1-qubit circuit with 1 instruction: └── RX(0.4) @ q[0] >>> c.push(mc.GateRX(0.8), 1) 2-qubit circuit with 2 instructions: ├── RX(0.4) @ q[0] └── RX(0.8) @ q[1] >>> c.push(mc.Measure(), 0, 0) 2-qubit, 1-bit circuit with 3 instructions: ├── RX(0.4) @ q[0] ├── RX(0.8) @ q[1] └── M @ q[0], c[0] >>> c.push(mc.Measure(), 1, 1) 2-qubit, 2-bit circuit with 4 instructions: ├── RX(0.4) @ q[0] ├── RX(0.8) @ q[1] ├── M @ q[0], c[0] └── M @ q[1], c[1] >>> model = mc.NoiseModel([mc.OperationInstanceNoise(mc.GateRX(theta), mc.Depolarizing(1, theta / pi)), ... mc.GlobalReadoutNoise(mc.ReadoutErr(0.01, 0.02)),]) >>> noisy = mc.apply_noise_model(c, model)
- Recursive wrapper examples:
>>> model = mc.NoiseModel([mc.OperationInstanceNoise(mc.GateH(), mc.AmplitudeDamping(0.01))]) >>> inner = mc.Circuit().push(mc.GateH(), 0) >>> c_block = mc.Circuit().push(mc.Block(inner), 0) >>> noisy_block= mc.apply_noise_model(c_block, model) >>> noisy_block.decompose() 1-qubit circuit with 2 instructions: ├── H @ q[0] └── AmplitudeDamping(0.01) @ q[0] >>> decl = mc.GateDecl("local_h", (), inner) >>> c_call = mc.Circuit().push(mc.GateCall(decl, ()), 0) >>> noisy_call = mc.apply_noise_model(c_call, model) >>> noisy_call.decompose() 1-qubit circuit with 2 instructions: ├── H @ q[0] └── AmplitudeDamping(0.01) @ q[0] >>> c_parallel = mc.Circuit().push(mc.Parallel(2, mc.GateH()), 0, 1) >>> noisy_parallel = mc.apply_noise_model(c_parallel, model) >>> noisy_parallel.decompose() 2-qubit circuit with 4 instructions: ├── H @ q[0] ├── AmplitudeDamping(0.01) @ q[0] ├── H @ q[1] └── AmplitudeDamping(0.01) @ q[1] >>> c_repeat = mc.Circuit().push(mc.Repeat(2, mc.GateH()), 0) >>> noisy_repeat = mc.apply_noise_model(c_repeat, model) >>> noisy_repeat.decompose() 1-qubit circuit with 4 instructions: ├── H @ q[0] ├── AmplitudeDamping(0.01) @ q[0] ├── H @ q[0] └── AmplitudeDamping(0.01) @ q[0] >>> c_if = mc.Circuit().push(mc.IfStatement(mc.GateH(), mc.BitString("1")), 0, 0) >>> noisy_if = mc.apply_noise_model(c_if, model) >>> noisy_if.decompose() 1-qubit, 1-bit circuit with 2 instructions: ├── IF(c==1) H @ q[0], condition[0] └── IF(c==1) AmplitudeDamping(0.01) @ q[0], condition[0]
>>> decl_inner = mc.GateDecl("inner_h", (), inner) >>> middle = mc.Circuit().push(mc.GateCall(decl_inner, ()), 0) >>> decl_outer = mc.GateDecl("outer_call", (), middle) >>> c_nested = mc.Circuit().push(mc.GateCall(decl_outer, ()), 0) >>> noisy_nested = mc.apply_noise_model(c_nested, model) >>> noisy_nested.decompose().decompose() 1-qubit circuit with 2 instructions: ├── H @ q[0] └── AmplitudeDamping(0.01) @ q[0]
- Recursive wrapper examples deeply nested:
>>> c_nested2 = mc.Circuit().push(mc.GateCall(decl_outer, ()), 0).push(mc.GateCall(decl_outer, ()), 1) >>> c_nested2.decompose() 2-qubit circuit with 2 instructions: ├── inner_h() @ q[0] └── inner_h() @ q[1] >>> noisy_nested2 = mc.apply_noise_model(c_nested2, model) >>> noisy_nested2.decompose().decompose() 2-qubit circuit with 4 instructions: ├── H @ q[0] ├── AmplitudeDamping(0.01) @ q[0] ├── H @ q[1] └── AmplitudeDamping(0.01) @ q[1]