Skip to content

Commit

Permalink
feat(benchmarks): Running with pytest-benchmark
Browse files Browse the repository at this point in the history
The existing `homodyne.py` benchmark under `benchmarks` has been
refactored into two parts: one for the state preparation, and one for
the measurement.

Some differences were notices between the SF and PQ programs mostly due
to the different definitions for the beamsplitter gates.

Instead of an executable, the `pytest-benchmark` plugin is used.

The `benchmark` CI/CD stage has been deleted, since benchmarks are now
the responsibility of `pytest`.
  • Loading branch information
kolarovszki-elte committed Mar 19, 2021
1 parent c0ee423 commit a8d3ac1
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 155 deletions.
10 changes: 0 additions & 10 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ before_script:

stages:
- test
- benchmark
- publish
- docs

Expand Down Expand Up @@ -38,15 +37,6 @@ test-py38:
only:
- web

benchmark:
stage: benchmark
script:
- apt update
- apt-get install libeigen3-dev
- poetry install
- echo "Piquasso vs. StrawberryFields vacuum homodyne benchmark"
- poetry run python benchmarks/homodyne.py

publish:
stage: publish
script:
Expand Down
78 changes: 78 additions & 0 deletions benchmarks/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#
# Copyright (C) 2020 by TODO - All rights reserved.
#

import pytest
import numpy as np

import strawberryfields as sf
import piquasso as pq


@pytest.fixture
def d():
return 5


@pytest.fixture
def example_gaussian_pq_program(d):
with pq.Program() as program:
pq.Q() | pq.GaussianState.create_vacuum(d=d)

pq.Q(0) | pq.S(amp=0.1) | pq.D(alpha=1)
pq.Q(1) | pq.S(amp=0.1) | pq.D(alpha=1)
pq.Q(2) | pq.S(amp=0.1) | pq.D(alpha=1)
pq.Q(3) | pq.S(amp=0.1) | pq.D(alpha=1)
pq.Q(4) | pq.S(amp=0.1) | pq.D(alpha=1)

# NOTE: we need to tweak the parameters here a bit, because we use a different
# definition for the beamsplitter.
pq.Q(0, 1) | pq.B(0.0959408065906761, np.pi - 0.06786053071484363)
pq.Q(2, 3) | pq.B(0.7730047654405018, np.pi - 1.453770233324797)
pq.Q(1, 2) | pq.B(1.0152680371119776, np.pi - 1.2863559998816205)
pq.Q(3, 4) | pq.B(1.3205517879465705, np.pi - 0.5236836466492961)
pq.Q(0, 1) | pq.B(4.394480318177715, np.pi - 4.481575657714487)
pq.Q(2, 3) | pq.B(2.2300919706807534, np.pi - 1.5073556513699888)
pq.Q(1, 2) | pq.B(2.2679037068773673, np.pi - 1.9550229282085838)
pq.Q(3, 4) | pq.B(3.340269832485504, np.pi - 3.289367083610399)

yield program

# TODO: The state has to be reset, because the setup runs only once at the beginning
# of the calculations, therefore the same `GaussianState` instance will be used.
program.state.reset()


@pytest.fixture
def example_gaussian_sf_program_and_engine(d):
"""
NOTE: the covariance matrix SF is returning is half of ours...
It seems that our implementation is OK, however.
"""

program = sf.Program(d)
engine = sf.Engine(backend="gaussian")

with program.context as q:
sf.ops.Sgate(0.1) | q[0]
sf.ops.Sgate(0.1) | q[1]
sf.ops.Sgate(0.1) | q[2]
sf.ops.Sgate(0.1) | q[3]
sf.ops.Sgate(0.1) | q[4]

sf.ops.Dgate(1) | q[0]
sf.ops.Dgate(1) | q[1]
sf.ops.Dgate(1) | q[2]
sf.ops.Dgate(1) | q[3]
sf.ops.Dgate(1) | q[4]

sf.ops.BSgate(0.0959408065906761, 0.06786053071484363) | (q[0], q[1])
sf.ops.BSgate(0.7730047654405018, 1.453770233324797) | (q[2], q[3])
sf.ops.BSgate(1.0152680371119776, 1.2863559998816205) | (q[1], q[2])
sf.ops.BSgate(1.3205517879465705, 0.5236836466492961) | (q[3], q[4])
sf.ops.BSgate(4.394480318177715, 4.481575657714487) | (q[0], q[1])
sf.ops.BSgate(2.2300919706807534, 1.5073556513699888) | (q[2], q[3])
sf.ops.BSgate(2.2679037068773673, 1.9550229282085838) | (q[1], q[2])
sf.ops.BSgate(3.340269832485504, 3.289367083610399) | (q[3], q[4])

return program, engine
46 changes: 46 additions & 0 deletions benchmarks/gaussian_homodyne_benchmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#
# Copyright (C) 2020 by TODO - All rights reserved.
#

import pytest

import piquasso as pq
import strawberryfields as sf


pytestmark = pytest.mark.benchmark(
group="gaussian-homodyne-measurement",
)


def piquasso_benchmark(
benchmark, example_gaussian_pq_program
):
example_gaussian_pq_program.execute()

with pq.Program() as new_program:
pq.Q() | example_gaussian_pq_program.state

# TODO: Support rotation by an angle, too.
pq.Q(0) | pq.MeasureHomodyne()

results = benchmark(new_program.execute)

assert results


def strawberryfields_benchmark(
benchmark, example_gaussian_sf_program_and_engine, d
):
program, engine = example_gaussian_sf_program_and_engine

results = engine.run(program)

new_program = sf.Program(d)

new_program.state = results.state

with new_program.context as q:
sf.ops.MeasureHomodyne(phi=0) | q[0]

benchmark(engine.run, new_program)
22 changes: 22 additions & 0 deletions benchmarks/gaussian_preparation_benchmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# Copyright (C) 2020 by TODO - All rights reserved.
#

import pytest


pytestmark = pytest.mark.benchmark(
group="gaussian-preparation",
)


def simple_piquasso_benchmark(benchmark, example_gaussian_pq_program):
benchmark(example_gaussian_pq_program.execute)


def simple_strawberryfields_benchmark(
benchmark, example_gaussian_sf_program_and_engine
):
program, engine = example_gaussian_sf_program_and_engine

benchmark(engine.run, program)
134 changes: 0 additions & 134 deletions benchmarks/homodyne.py

This file was deleted.

Loading

0 comments on commit a8d3ac1

Please sign in to comment.