Skip to content

Commit

Permalink
feat(cvqnn): CVQNN module
Browse files Browse the repository at this point in the history
A module has been written to support CVQNN-related computations.
`tf_cvnn_benchmark.py` has been rewritten using this module.
  • Loading branch information
Kolarovszki committed Feb 14, 2024
1 parent 66bc621 commit 1144365
Show file tree
Hide file tree
Showing 6 changed files with 446 additions and 81 deletions.
112 changes: 31 additions & 81 deletions benchmarks/tf_cvnn_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,20 @@
import pytest

import numpy as np
import tensorflow as tf

import tensorflow as tf
import strawberryfields as sf

import piquasso as pq
from piquasso import cvqnn


np.set_printoptions(suppress=True, linewidth=200)


@pytest.fixture
def cutoff():
return 10
return 20


@pytest.fixture
Expand All @@ -44,7 +49,7 @@ def d():

@pytest.fixture
def weights(layer_count, d):
active_sd = 0.0001
active_sd = 0.01
passive_sd = 0.1

M = int(d * (d - 1)) + max(1, d - 1)
Expand All @@ -69,104 +74,49 @@ def weights(layer_count, d):
return weights


def piquasso_benchmark(benchmark, weights, d, cutoff, layer_count):
benchmark(lambda: _calculate_piquasso_results(weights, d, cutoff, layer_count))
def piquasso_benchmark(benchmark, weights, cutoff):
benchmark(lambda: _calculate_piquasso_results(weights, cutoff))


def strawberryfields_benchmark(benchmark, weights, d, cutoff, layer_count):
benchmark(
lambda: _calculate_strawberryfields_results(weights, d, cutoff, layer_count)
)
def strawberryfields_benchmark(benchmark, weights, cutoff):
benchmark(lambda: _calculate_strawberryfields_results(weights, cutoff))


def test_state_vector_and_jacobian(weights, d, cutoff, layer_count):
pq_state_vector, pq_jacobian = _calculate_piquasso_results(
weights, d, cutoff, layer_count
)
sf_state_vector, sf_jacobian = _calculate_strawberryfields_results(
weights, d, cutoff, layer_count
)
def test_state_vector_and_jacobian(weights, cutoff):
pq_state_vector, pq_jacobian = _calculate_piquasso_results(weights, cutoff)
sf_state_vector, sf_jacobian = _calculate_strawberryfields_results(weights, cutoff)

assert np.allclose(pq_state_vector, sf_state_vector)
assert np.allclose(pq_jacobian, sf_jacobian)
assert np.sum(np.abs(pq_state_vector - sf_state_vector) ** 2) < 1e-10
assert np.sum(np.abs(pq_jacobian - sf_jacobian) ** 2) < 1e-10


def _calculate_piquasso_results(weights, d, cutoff, layer_count):
def _pq_state_vector(weights, cutoff):
d = cvqnn.get_number_of_modes(weights.shape[1])

simulator = pq.PureFockSimulator(
d=d,
config=pq.Config(cutoff=cutoff, dtype=weights.dtype, normalize=False),
config=pq.Config(cutoff=cutoff, normalize=False),
calculator=pq.TensorflowCalculator(),
)

with tf.GradientTape() as tape:
instructions = []
program = cvqnn.create_program(weights)

for i in range(layer_count):
instructions.extend(_pq_layer(weights[i], d))
state = simulator.execute(program).state

program = pq.Program(instructions=[pq.Vacuum()] + instructions)

state = simulator.execute(program).state
state_vector = state.get_tensor_representation()

return state_vector, tape.jacobian(state_vector, weights)


def _pq_interferometer(params, d):
instructions = []

theta = params[: d * (d - 1) // 2]
phi = params[d * (d - 1) // 2 : d * (d - 1)]
rphi = params[-d + 1 :]

if d == 1:
return [pq.Phaseshifter(rphi[0]).on_modes(0)]

n = 0
return state.get_tensor_representation()

q = tuple(range(d))

for j in range(d):
for k, (q1, q2) in enumerate(zip(q[:-1], q[1:])):
if (j + k) % 2 != 1:
instructions.append(
pq.Beamsplitter(theta=theta[n], phi=phi[n]).on_modes(q1, q2)
)
n += 1

instructions.extend(
[pq.Phaseshifter(rphi[i]).on_modes(i) for i in range(max(1, d - 1))]
)

return instructions


def _pq_layer(params, d):
M = int(d * (d - 1)) + max(1, d - 1)

int1 = params[:M]
s = params[M : M + d]
int2 = params[M + d : 2 * M + d]
dr = params[2 * M + d : 2 * M + 2 * d]
dp = params[2 * M + 2 * d : 2 * M + 3 * d]
k = params[2 * M + 3 * d : 2 * M + 4 * d]

instructions = []

instructions.extend(_pq_interferometer(int1, d))

instructions.extend([pq.Squeezing(s[i]).on_modes(i) for i in range(d)])

instructions.extend(_pq_interferometer(int2, d))

instructions.extend([pq.Displacement(dr[i], dp[i]).on_modes(i) for i in range(d)])
def _calculate_piquasso_results(weights, cutoff):
with tf.GradientTape() as tape:
state_vector = _pq_state_vector(weights, cutoff)

instructions.extend([pq.Kerr(k[i]).on_modes(i) for i in range(d)])
return state_vector, tape.jacobian(state_vector, weights)

return instructions

def _calculate_strawberryfields_results(weights, cutoff):
layer_count = weights.shape[0]
d = cvqnn.get_number_of_modes(weights.shape[1])

def _calculate_strawberryfields_results(weights, d, cutoff, layer_count):
eng = sf.Engine(backend="tf", backend_options={"cutoff_dim": cutoff})
qnn = sf.Program(d)

Expand Down
7 changes: 7 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,10 @@ One could easily install Piquasso with the following command:
api/instruction
api/result
api/exceptions

.. toctree::
:maxdepth: 3
:caption: Miscellaneous:
:hidden:

misc/cvqnn
8 changes: 8 additions & 0 deletions docs/misc/cvqnn.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CVQNN Module
============

Some tools for simulating CVQNN (Continuous-Variable Quantum Neural Networks) are also
available in Piquasso.

.. automodule:: piquasso.cvqnn
:members:
4 changes: 4 additions & 0 deletions piquasso/api/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ class InvalidSimulation(PiquassoException):

class NotImplementedCalculation(PiquassoException):
"""Raiesed when a calculation is not implemented."""


class CVQNNException(PiquassoException):
"""Exception raised from the `cvqnn` module."""
Loading

0 comments on commit 1144365

Please sign in to comment.