Skip to content

Commit 61284df

Browse files
authored
Merge branch 'develop' into develop
2 parents e55355f + 0058d6b commit 61284df

File tree

15 files changed

+182
-11
lines changed

15 files changed

+182
-11
lines changed

mrmustard/lab/gates.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ class Amplifier(Channel):
933933
"""
934934

935935
is_gaussian = True
936-
short_name = "Amp"
936+
short_name = "Amp~"
937937
parallelizable = True
938938

939939
def __init__(

mrmustard/lab_dev/states/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
from ..circuit_components import CircuitComponent
5353
from ..circuit_components_utils import BtoPS
5454

55+
5556
__all__ = ["State"]
5657

5758
# ~~~~~~~
@@ -333,6 +334,7 @@ def phase_space(self, s: float) -> tuple:
333334
Returns:
334335
The covariance matrix, the mean vector and the coefficient of the state in s-parametrized phase space.
335336
"""
337+
336338
if not isinstance(self.ansatz, PolyExpAnsatz):
337339
raise ValueError("Can calculate phase space only for Bargmann states.")
338340

mrmustard/lab_dev/states/dm.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from .base import State, _validate_operator, OperatorType
3737
from ..circuit_components import CircuitComponent
3838
from ..circuit_components_utils import BtoQ, TraceOut
39+
3940
from ..utils import shape_check
4041

4142
__all__ = ["DM"]
@@ -196,6 +197,7 @@ def from_quadrature(
196197
ValueError: If the given triple has shapes that are inconsistent
197198
with the number of modes.
198199
"""
200+
199201
QtoB = BtoQ(modes, phi).inverse()
200202
Q = DM.from_ansatz(modes, PolyExpAnsatz(*triple))
201203
return DM.from_ansatz(modes, (Q >> QtoB).ansatz, name)
@@ -302,6 +304,7 @@ def expectation(self, operator: CircuitComponent):
302304
ValueError: If ``operator`` is defined over a set of modes that is not a subset of the
303305
modes of this state.
304306
"""
307+
305308
op_type, msg = _validate_operator(operator)
306309
if op_type is OperatorType.INVALID_TYPE:
307310
raise ValueError(msg)
@@ -413,6 +416,7 @@ def __rshift__(self, other: CircuitComponent) -> CircuitComponent:
413416
Returns a ``DM`` when the wires of the resulting components are compatible with
414417
those of a ``DM``, a ``CircuitComponent`` otherwise, and a scalar if there are no wires left.
415418
"""
419+
416420
result = super().__rshift__(other)
417421
if not isinstance(result, CircuitComponent):
418422
return result # scalar case handled here

mrmustard/lab_dev/states/ket.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ def from_quadrature(
152152
phi: float = 0.0,
153153
name: str | None = None,
154154
) -> State:
155+
155156
QtoB = BtoQ(modes, phi).inverse()
156157
Q = Ket.from_ansatz(modes, PolyExpAnsatz(*triple))
157158
return Ket.from_ansatz(modes, (Q >> QtoB).ansatz, name)
@@ -263,6 +264,7 @@ def expectation(self, operator: CircuitComponent):
263264
ValueError: If ``operator`` is defined over a set of modes that is not a subset of the
264265
modes of this state.
265266
"""
267+
266268
op_type, msg = _validate_operator(operator)
267269
if op_type is OperatorType.INVALID_TYPE:
268270
raise ValueError(msg)
@@ -371,6 +373,7 @@ def __rshift__(self, other: CircuitComponent | Scalar) -> CircuitComponent | Bat
371373
with those of a ``DM`` or of a ``Ket``. Returns a ``CircuitComponent`` in general,
372374
and a (batched) scalar if there are no wires left, for convenience.
373375
"""
376+
374377
result = super().__rshift__(other)
375378
if not isinstance(result, CircuitComponent):
376379
return result # scalar case handled here

mrmustard/lab_dev/transformations/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from .ggate import *
2727
from .gaussrandnoise import *
2828
from .identity import *
29+
from .phasenoise import *
2930
from .rgate import *
3031
from .s2gate import *
3132
from .sgate import *

mrmustard/lab_dev/transformations/amplifier.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def __init__(
8484
gain_trainable: bool = False,
8585
gain_bounds: tuple[float | None, float | None] = (1.0, None),
8686
):
87-
super().__init__(name="Amp")
87+
super().__init__(name="Amp~")
8888
(gs,) = list(reshape_params(len(modes), gain=gain))
8989
self._add_parameter(
9090
make_parameter(

mrmustard/lab_dev/transformations/attenuator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class Attenuator(Channel):
7575
c &= 1\:.
7676
"""
7777

78-
short_name = "Att"
78+
short_name = "Att~"
7979

8080
def __init__(
8181
self,
@@ -84,7 +84,7 @@ def __init__(
8484
transmissivity_trainable: bool = False,
8585
transmissivity_bounds: tuple[float | None, float | None] = (0.0, 1.0),
8686
):
87-
super().__init__(name="Att")
87+
super().__init__(name="Att~")
8888
(etas,) = list(reshape_params(len(modes), transmissivity=transmissivity))
8989
self._add_parameter(
9090
make_parameter(

mrmustard/lab_dev/transformations/gaussrandnoise.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def __init__(
7474
if (math.real(math.eigvals(Y)) >= -settings.ATOL).min() == 0:
7575
raise ValueError("The input Y matrix has negative eigen-values.")
7676

77-
super().__init__(name="GRN")
77+
super().__init__(name="GRN~")
7878
self._add_parameter(make_parameter(Y_trainable, value=Y, name="Y", bounds=(None, None)))
7979
self._representation = self.from_ansatz(
8080
modes_in=modes,
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Copyright 2024 Xanadu Quantum Technologies Inc.
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
The class representing a Phase noise channel.
17+
"""
18+
19+
from __future__ import annotations
20+
from typing import Sequence
21+
from mrmustard.lab_dev.circuit_components import CircuitComponent
22+
from mrmustard.physics.ansatz.array_ansatz import ArrayAnsatz
23+
from mrmustard.physics.representations import Representation
24+
from mrmustard import math
25+
import numpy as np
26+
from .base import Channel
27+
from ..utils import make_parameter
28+
29+
__all__ = ["PhaseNoise"]
30+
31+
32+
class PhaseNoise(Channel):
33+
r"""
34+
The Phase noise channel.
35+
36+
This class represents the application of a random phase. The distributiuon of the phase
37+
is assumed to be a Gaussian with mean zero, and standard deviation `phase_stdev`.
38+
39+
Args:
40+
modes: The modes the channel is applied to
41+
phase_stdev: The standard deviation of the random phase noise.
42+
43+
..details::
44+
The Fock representation is connected to the Fourier coefficients of the distribution.
45+
"""
46+
47+
short_name = "P~"
48+
49+
def __init__(
50+
self,
51+
modes: Sequence[int],
52+
phase_stdev: float | Sequence[float],
53+
phase_stdev_trainable: bool = False,
54+
phase_stdev_bounds: tuple[float | None, float | None] = (0.0, None),
55+
):
56+
super().__init__(name="PhaseNoise")
57+
self._add_parameter(
58+
make_parameter(phase_stdev_trainable, phase_stdev, "phase_stdev", phase_stdev_bounds)
59+
)
60+
self._representation = self.from_ansatz(
61+
modes_in=modes, modes_out=modes, ansatz=None
62+
).representation
63+
64+
def __custom_rrshift__(self, other: CircuitComponent) -> CircuitComponent:
65+
r"""
66+
Since PhaseNoise admits a particularly nice form in the Fock basis, we have implemented its right-shift operation separately.
67+
68+
Args:
69+
other: the component other than the PhaseNoise object that is present in the contraction
70+
71+
Output:
72+
the result of the contraction.
73+
"""
74+
75+
if not other.wires.bra or not other.wires.ket:
76+
other = other @ other.adjoint
77+
array = math.asnumpy(other.fock_array())
78+
mode_indices = np.indices(array.shape)
79+
for mode in self.modes:
80+
phase_factors = np.exp(
81+
-0.5
82+
* (mode_indices[mode] - mode_indices[other.n_modes + mode]) ** 2
83+
* self.phase_stdev.value**2
84+
)
85+
array *= phase_factors
86+
return CircuitComponent(Representation(ArrayAnsatz(array, False), other.wires), self.name)

mrmustard/physics/triples.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ def XY_to_channel_Abc(X: RealMatrix, Y: RealMatrix, d: Vector | None = None) ->
835835

836836
A = math.Xmat(2 * m) @ R @ xi_inv_in_blocks @ math.conj(R).T
837837
temp = math.block([[(xi_inv @ d).reshape(2 * m, 1)], [(-X.T @ xi_inv @ d).reshape((2 * m, 1))]])
838-
b = 1 / math.sqrt(settings.HBAR) * math.conj(R) @ temp
838+
b = 1 / math.sqrt(complex(settings.HBAR)) * math.conj(R) @ temp
839839
c = math.exp(-0.5 / settings.HBAR * d @ xi_inv @ d) / math.sqrt(math.det(xi))
840840

841841
return A, b, c

0 commit comments

Comments
 (0)