Skip to content

Commit

Permalink
New noise modelling for qudit systems(#83) (#99)
Browse files Browse the repository at this point in the history
## Description

This pull request suggests to introduce new noise model for qudits. It
consists of two ideas: "Mathematical Noise" & "Physical Noise". There
are some limitations as follows now.

* The data structure of Noise is defined.
* It is supported by only `tnsim`, not `misim`.
  * To clear the tests, some code changes are made in `misim`.
  * However, `misim` cannot simulate neither correctly.

## Checklist:

<!---
This checklist serves as a reminder of a couple of things that ensure
your pull request will be merged swiftly.
-->

- [x] The pull request only contains commits that are related to it.
- [x] I have added appropriate tests and documentation.
- [x] I have made sure that all CI jobs on GitHub pass.
- [x] The pull request introduces no new warnings and follows the
project's style guidelines.

Co-authored-by: Yusuke Kimura <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Nov 26, 2024
1 parent b12cbb1 commit 980f666
Show file tree
Hide file tree
Showing 16 changed files with 887 additions and 63 deletions.
16 changes: 16 additions & 0 deletions src/mqt/qudits/quantum_circuit/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
CustomTwo,
GellMann,
H,
NoiseX,
NoiseY,
Perm,
R,
RandU,
Expand Down Expand Up @@ -268,6 +270,20 @@ def randu(self, qudits: list[int]) -> RandU:
def rz(self, qudit: int, parameters: list[int | float], controls: ControlData | None = None) -> Rz:
return Rz(self, "Rz" + str(self.dimensions[qudit]), qudit, parameters, self.dimensions[qudit], controls)

@add_gate_decorator
def noisex(self, qudit: int, parameters: list[int], controls: ControlData | None = None) -> NoiseX:
return NoiseX(self, "NoiseX" + str(self.dimensions[qudit]), qudit, parameters, self.dimensions[qudit], controls)

@add_gate_decorator
def noisey(self, qudit: int, parameters: list[int], controls: ControlData | None = None) -> NoiseY:
return NoiseY(self, "NoiseY" + str(self.dimensions[qudit]), qudit, parameters, self.dimensions[qudit], controls)

@add_gate_decorator
def noisez(self, qudit: int, level: int, controls: ControlData | None = None) -> VirtRz:
return VirtRz(
self, "NoiseZ" + str(self.dimensions[qudit]), qudit, [level, np.pi], self.dimensions[qudit], controls
)

@add_gate_decorator
def virtrz(self, qudit: int, parameters: list[int | float], controls: ControlData | None = None) -> VirtRz:
return VirtRz(self, "VirtRz" + str(self.dimensions[qudit]), qudit, parameters, self.dimensions[qudit], controls)
Expand Down
4 changes: 4 additions & 0 deletions src/mqt/qudits/quantum_circuit/gates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from .h import H
from .ls import LS
from .ms import MS
from .noise_x import NoiseX
from .noise_y import NoiseY
from .perm import Perm
from .r import R
from .randu import RandU
Expand All @@ -35,6 +37,8 @@
"GateTypes",
"GellMann",
"H",
"NoiseX",
"NoiseY",
"Perm",
"R",
"RandU",
Expand Down
88 changes: 88 additions & 0 deletions src/mqt/qudits/quantum_circuit/gates/noise_x.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from __future__ import annotations

from typing import TYPE_CHECKING

import numpy as np

from ..components.extensions.gate_types import GateTypes
from ..gate import Gate

if TYPE_CHECKING:
from numpy.typing import NDArray

from ..circuit import QuantumCircuit
from ..components.extensions.controls import ControlData
from ..gate import Parameter


class NoiseX(Gate):
def __init__(
self,
circuit: QuantumCircuit,
name: str,
target_qudits: int,
parameters: list[int],
dimensions: int,
controls: ControlData | None = None,
) -> None:
super().__init__(
circuit=circuit,
name=name,
gate_type=GateTypes.SINGLE,
target_qudits=target_qudits,
dimensions=dimensions,
control_set=controls,
qasm_tag="noisex",
)

if self.validate_parameter(parameters):
self.original_lev_a: int = parameters[0]
self.original_lev_b: int = parameters[1]
self.lev_a, self.lev_b = self.levels_setter(self.original_lev_a, self.original_lev_b)
self._params = parameters

def __array__(self) -> NDArray: # noqa: PLW3201
dimension = self.dimensions
matrix = np.identity(dimension, dtype="complex")

matrix[self.lev_a, self.lev_a] = 0.0
matrix[self.lev_b, self.lev_b] = 0.0
matrix[self.lev_a, self.lev_b] = 1.0
matrix[self.lev_b, self.lev_a] = 1.0

return matrix

@staticmethod
def levels_setter(la: int, lb: int) -> tuple[int, int]:
if la < lb:
return la, lb
return lb, la

def validate_parameter(self, parameter: Parameter) -> bool:
if parameter is None:
return False

if isinstance(parameter, list):
assert isinstance(parameter[0], int)
assert isinstance(parameter[1], int)
assert parameter[0] >= 0
assert parameter[0] < self.dimensions
assert parameter[1] >= 0
assert parameter[1] < self.dimensions
assert parameter[0] != parameter[1]
# Useful to remember direction of the rotation
self.original_lev_a = parameter[0]
self.original_lev_b = parameter[1]

return True

if isinstance(parameter, np.ndarray):
# Add validation for numpy array if needed
return False

return False

@property
def dimensions(self) -> int:
assert isinstance(self._dimensions, int), "Dimensions must be an integer"
return self._dimensions
88 changes: 88 additions & 0 deletions src/mqt/qudits/quantum_circuit/gates/noise_y.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from __future__ import annotations

from typing import TYPE_CHECKING

import numpy as np

from ..components.extensions.gate_types import GateTypes
from ..gate import Gate

if TYPE_CHECKING:
from numpy.typing import NDArray

from ..circuit import QuantumCircuit
from ..components.extensions.controls import ControlData
from ..gate import Parameter


class NoiseY(Gate):
def __init__(
self,
circuit: QuantumCircuit,
name: str,
target_qudits: int,
parameters: list[int],
dimensions: int,
controls: ControlData | None = None,
) -> None:
super().__init__(
circuit=circuit,
name=name,
gate_type=GateTypes.SINGLE,
target_qudits=target_qudits,
dimensions=dimensions,
control_set=controls,
qasm_tag="noisey",
)

if self.validate_parameter(parameters):
self.original_lev_a: int = parameters[0]
self.original_lev_b: int = parameters[1]
self.lev_a, self.lev_b = self.levels_setter(self.original_lev_a, self.original_lev_b)
self._params = parameters

def __array__(self) -> NDArray: # noqa: PLW3201
dimension = self.dimensions
matrix = np.identity(dimension, dtype="complex")

matrix[self.lev_a, self.lev_a] = 0.0
matrix[self.lev_b, self.lev_b] = 0.0
matrix[self.lev_a, self.lev_b] = -1j
matrix[self.lev_b, self.lev_a] = 1j

return matrix

@staticmethod
def levels_setter(la: int, lb: int) -> tuple[int, int]:
if la < lb:
return la, lb
return lb, la

def validate_parameter(self, parameter: Parameter) -> bool:
if parameter is None:
return False

if isinstance(parameter, list):
assert isinstance(parameter[0], int)
assert isinstance(parameter[1], int)
assert parameter[0] >= 0
assert parameter[0] < self.dimensions
assert parameter[1] >= 0
assert parameter[1] < self.dimensions
assert parameter[0] != parameter[1]
# Useful to remember direction of the rotation
self.original_lev_a = parameter[0]
self.original_lev_b = parameter[1]

return True

if isinstance(parameter, np.ndarray):
# Add validation for numpy array if needed
return False

return False

@property
def dimensions(self) -> int:
assert isinstance(self._dimensions, int), "Dimensions must be an integer"
return self._dimensions
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

from typing_extensions import Unpack

from mqt.qudits.simulation.noise_tools.noise import Noise

from ....core import LevelGraph
from ...noise_tools import Noise, NoiseModel
from ...noise_tools import NoiseModel
from ..tnsim import TNSim

if TYPE_CHECKING:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

from typing_extensions import Unpack

from mqt.qudits.simulation.noise_tools.noise import Noise

from ....core import LevelGraph
from ...noise_tools import Noise, NoiseModel
from ...noise_tools import NoiseModel
from ..tnsim import TNSim

if TYPE_CHECKING:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

from typing_extensions import Unpack

from mqt.qudits.simulation.noise_tools.noise import Noise

from ....core import LevelGraph
from ...noise_tools import Noise, NoiseModel
from ...noise_tools import NoiseModel
from ..tnsim import TNSim

if TYPE_CHECKING:
Expand Down
4 changes: 2 additions & 2 deletions src/mqt/qudits/simulation/noise_tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from .noise import Noise, NoiseModel
from .noise import Noise, NoiseModel, SubspaceNoise
from .noisy_circuit_factory import NoisyCircuitFactory

__all__ = ["Noise", "NoiseModel", "NoisyCircuitFactory"]
__all__ = ["Noise", "NoiseModel", "NoisyCircuitFactory", "SubspaceNoise"]
Loading

0 comments on commit 980f666

Please sign in to comment.