Skip to content

Commit

Permalink
Merge pull request Budapest-Quantum-Computing-Group#155 from Budapest…
Browse files Browse the repository at this point in the history
…-Quantum-Computing-Group/scalable-fock-gates

feat(fock) enabling scaling for kerr gate: 

- Now the user can apply the kerr gate to multiple qumodes with
  a single instruction.
- Test cases have been added accordingly.
  • Loading branch information
kareem1925 authored Jan 17, 2022
2 parents aee6e03 + c49e95b commit 18c584c
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 18 deletions.
20 changes: 11 additions & 9 deletions piquasso/_backends/fock/general/calculations.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,18 @@ def annihilate(state: FockState, instruction: Instruction, shots: int) -> Result
def kerr(state: FockState, instruction: Instruction, shots: int) -> Result:
mode = instruction.modes[0]
xi = instruction._all_params["xi"]
for x in xi:
for index, (basis, dual_basis) in state._space.operator_basis:
number = basis[mode]
dual_number = dual_basis[mode]

coefficient = np.exp(
1j
* x
* (number * (2 * number + 1) - dual_number * (2 * dual_number + 1))
)

for index, (basis, dual_basis) in state._space.operator_basis:
number = basis[mode]
dual_number = dual_basis[mode]

coefficient = np.exp(
1j * xi * (number * (2 * number + 1) - dual_number * (2 * dual_number + 1))
)

state._density_matrix[index] *= coefficient
state._density_matrix[index] *= coefficient

return Result(state=state)

Expand Down
11 changes: 6 additions & 5 deletions piquasso/_backends/fock/pure/calculations.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,19 @@ def kerr(state: PureFockState, instruction: Instruction, shots: int) -> Result:
mode = instruction.modes[0]
xi = instruction._all_params["xi"]

for index, basis in state._space.basis:
number = basis[mode]
coefficient = np.exp(1j * xi * number * (2 * number + 1))
state._state_vector[index] *= coefficient
for x in xi:

for index, basis in state._space.basis:
number = basis[mode]
coefficient = np.exp(1j * x.squeeze() * number * (2 * number + 1))
state._state_vector[index] *= coefficient

return Result(state=state)


def cross_kerr(state: PureFockState, instruction: Instruction, shots: int) -> Result:
modes = instruction.modes
xi = instruction._all_params["xi"]

for index, basis in state._space.basis:
coefficient = np.exp(1j * xi * basis[modes[0]] * basis[modes[1]])
state._state_vector[index] *= coefficient
Expand Down
22 changes: 18 additions & 4 deletions piquasso/instructions/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ def __init__(self, p: float) -> None:

class _ScalableFockGates(Gate, _mixins.ScalingMixin):
def __init__(
self, *, params: dict = None, gamma: np.ndarray = None, xi: float = None
self, *, params: dict = None, gamma: np.ndarray = None, xi: np.ndarray = None
):
params = params or {}
super().__init__(params=params, extra_params=dict(gamma=gamma, xi=xi))
Expand All @@ -665,10 +665,24 @@ def __init__(

def _autoscale(self) -> None:
gamma = self._extra_params["gamma"]
xi = self._extra_params["xi"]
if gamma is not None and len(gamma) == len(self.modes):
pass
elif gamma is None:
pass
elif len(gamma) == 1:
self._extra_params["gamma"] = block_diag(*[gamma] * len(self.modes))
self._extra_params["gamma"] = np.array([gamma] * len(self.modes))
else:
raise InvalidParameter(
self.ERROR_MESSAGE_TEMPLATE.format(instruction=self, modes=self.modes)
)

if xi is not None and len(xi) == len(self.modes):
pass
elif xi is None:
pass
elif len(xi) == 1:
self._extra_params["xi"] = np.array([xi] * len(self.modes))
else:
raise InvalidParameter(
self.ERROR_MESSAGE_TEMPLATE.format(instruction=self, modes=self.modes)
Expand Down Expand Up @@ -709,7 +723,7 @@ def __init__(self, gamma: float) -> None:
super().__init__(params=dict(gamma=gamma), gamma=np.atleast_1d(gamma))


class Kerr(Gate):
class Kerr(_ScalableFockGates):
r"""Kerr gate.
The definition of the Kerr gate is
Expand All @@ -734,7 +748,7 @@ def __init__(self, xi: float) -> None:
Args:
xi (float): The magnitude of the Kerr nonlinear term.
"""
super().__init__(params=dict(xi=xi))
super().__init__(params=dict(xi=xi), xi=np.atleast_1d(xi))


class CrossKerr(Gate):
Expand Down
28 changes: 28 additions & 0 deletions tests/backends/test_backend_equivalence.py
Original file line number Diff line number Diff line change
Expand Up @@ -919,3 +919,31 @@ def test_cubic_phase_equivalency(SimulatorClass):

assert np.isclose(fidelity, 1.0)
assert np.isclose(fidelity, state_2.fidelity(state_1))


@pytest.mark.parametrize(
"SimulatorClass",
(
pq.PureFockSimulator,
pq.FockSimulator,
),
)
def test_kerr_equivalency(SimulatorClass):
with pq.Program() as program_1:
pq.Q() | pq.Vacuum()
pq.Q(0) | pq.Squeezing(r=0.05)
pq.Q(0, 1) | pq.Kerr(xi=[-1, 1])

with pq.Program() as program_2:
pq.Q() | pq.Vacuum()
pq.Q(0) | pq.Squeezing(r=0.05)
pq.Q(all) | pq.Kerr(xi=[-1, 1])

generic_simulator = SimulatorClass(d=2, config=pq.Config(cutoff=10))

state_1 = generic_simulator.execute(program_1).state
state_2 = generic_simulator.execute(program_2).state
fidelity = state_1.fidelity(state_2)

assert np.isclose(fidelity, 1.0)
assert np.isclose(fidelity, state_2.fidelity(state_1))
48 changes: 48 additions & 0 deletions tests/backends/test_instruction_autoscaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,51 @@ def test_cubic_phase_autoscaling_invalid(SimulatorClass):
simulator.execute(program_2)

assert "is not applicable to modes" in str(excinfo.value)


@pytest.mark.parametrize(
"SimulatorClass",
(
pq.PureFockSimulator,
pq.FockSimulator,
),
)
def test_kerr_autoscaling_invalid(SimulatorClass):
with pq.Program() as program_1:
pq.Q() | pq.Vacuum()
pq.Q(0) | pq.Kerr(xi=[0, 1])

with pq.Program() as program_2:
pq.Q() | pq.Vacuum()
pq.Q(0, 1) | pq.Kerr(xi=[0, 1, 2])

simulator = SimulatorClass(d=2)

with pytest.raises(pq.api.errors.InvalidParameter) as excinfo:
simulator.execute(program_1)

assert "is not applicable to modes" in str(excinfo.value)

with pytest.raises(pq.api.errors.InvalidParameter) as excinfo:
simulator.execute(program_2)

assert "is not applicable to modes" in str(excinfo.value)


@pytest.mark.parametrize(
"SimulatorClass",
(
pq.PureFockSimulator,
pq.FockSimulator,
),
)
def test_kerr_autoscaling_valid(SimulatorClass):
with pq.Program() as program:
pq.Q() | pq.Vacuum()
pq.Q(all) | pq.Kerr(xi=2)

simulator = SimulatorClass(d=3)

state = simulator.execute(program).state

state.validate()

0 comments on commit 18c584c

Please sign in to comment.