Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MidMeasureMP C++ implementation #621

Closed
wants to merge 71 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
03dd421
First version of collapse() with basic test.
tomlqc Feb 28, 2024
857fba6
test collapse() branch 1
tomlqc Feb 28, 2024
8dae8e9
collapse() gets normalized
tomlqc Feb 28, 2024
5e67eca
probs() with basic test to be augmented
tomlqc Feb 28, 2024
1e15854
probs() tests
tomlqc Feb 28, 2024
fa51996
rng with seed() (no test)
tomlqc Feb 28, 2024
bed99e4
random_sample()
tomlqc Feb 28, 2024
6169ead
measure() with simple test
tomlqc Feb 28, 2024
3cf8587
Add mid_measurement in apply interface. Add MidMeasureMP bindings.
vincentmr Feb 29, 2024
1d61d8c
Add native mcm tests.
vincentmr Feb 29, 2024
28f2a35
mid-measure methods moved to QubitManaged
tomlqc Feb 29, 2024
9403ec3
WIP
vincentmr Feb 29, 2024
105a2e9
measure(..., postselect, reset) with tests
tomlqc Mar 1, 2024
e44fe36
Finalize reset option + add tests.
vincentmr Mar 1, 2024
8a932b1
Build tests against pennylane.git@feature/mid-measure-cpp
vincentmr Mar 1, 2024
9e1e2d4
Merge branch 'master' into feature/mid-measure-cpp
vincentmr Mar 1, 2024
f82e9b4
Auto update version
github-actions[bot] Mar 1, 2024
cf20d1e
mcm c++ tests moved from Qubit to QubitManaged
tomlqc Mar 1, 2024
268502f
code format
tomlqc Mar 1, 2024
292850c
minor optimization
tomlqc Mar 1, 2024
ee35bc3
authors
tomlqc Mar 1, 2024
3b02eee
Add postselection support and tests at the Python layer.
vincentmr Mar 4, 2024
c3d0732
Pin pytest
vincentmr Mar 4, 2024
c8e261d
Merge branch 'master' into feature/mid-measure-cpp
vincentmr Mar 4, 2024
66e8b05
Auto update version
github-actions[bot] Mar 4, 2024
c459d36
trigger ci
vincentmr Mar 4, 2024
4be29e8
Run native exec test with pytest-xdist.
vincentmr Mar 4, 2024
9f7b9fb
improved cast in single assignment
tomlqc Mar 4, 2024
ef1db66
normalize()
tomlqc Mar 4, 2024
d71db54
normalize() binding
tomlqc Mar 4, 2024
3835601
removed measure(), only applyMidMeasureMP() remaining
tomlqc Mar 4, 2024
dd5145d
Copyright 2024
tomlqc Mar 4, 2024
d3475c6
No zeroing of state vector if sample != postselect
tomlqc Mar 4, 2024
cd21495
CHANGELOG note
tomlqc Mar 4, 2024
a4f4ef9
Increase timeout minutes for pythontests
vincentmr Mar 4, 2024
f194665
check-tidy code style
tomlqc Mar 4, 2024
39c7ece
removed setBasisState() from Qubit and QubitRaw
tomlqc Mar 4, 2024
5e0b51d
Merge branch 'master' into feature/mid-measure-cpp
vincentmr Mar 5, 2024
d3f9bdd
Auto update version
github-actions[bot] Mar 5, 2024
bfe0090
Update CHANGELOG.md
vincentmr Mar 5, 2024
9b256aa
xdist slow?
vincentmr Mar 5, 2024
aa1a24f
Remove early/late exit conditions on mid_measurements.
vincentmr Mar 5, 2024
6aba940
Merge branch 'master' into feature/mid-measure-cpp
tomlqc Mar 5, 2024
e2ab52a
Auto update version
github-actions[bot] Mar 5, 2024
22fa135
renamed randomSample() and setSeed()
tomlqc Mar 5, 2024
0b7304f
code format on lightning_kokkos.py
tomlqc Mar 5, 2024
7fb6faa
code formatting for CodeFactor
tomlqc Mar 5, 2024
90624f6
Update pennylane_lightning/core/_version.py
vincentmr Mar 7, 2024
46878c0
Update pennylane_lightning/core/src/simulators/lightning_qubit/StateV…
vincentmr Mar 7, 2024
4e2ab46
Merge branch 'master' into feature/mid-measure-cpp
vincentmr Mar 7, 2024
0561f09
Move MidMeasureMP up in Python.
vincentmr Mar 13, 2024
d6dfe50
Merge branch 'master' into feature/mid-measure-cpp
vincentmr Mar 13, 2024
ba57243
Auto update version
github-actions[bot] Mar 13, 2024
f0ac135
trigger ci
vincentmr Mar 13, 2024
ff322d0
Merge branch 'master' into feature/mid-measure-cpp
vincentmr Mar 13, 2024
64c1235
Auto update version
github-actions[bot] Mar 13, 2024
14da052
trigger ci
vincentmr Mar 13, 2024
8366747
removed applyMidMeasure, probs, randomSample
tomlqc Mar 14, 2024
b71280d
rng to MeasurementBase with setSeed()
tomlqc Mar 14, 2024
23376d5
fix for tidy and kokkos build
tomlqc Mar 14, 2024
a038daa
normalize() throws error if vector's norm is zero
tomlqc Mar 14, 2024
5233992
Remove apply_rotations.
vincentmr Mar 14, 2024
f45cf15
Merge remote-tracking branch 'origin/master' into feature/mid-measure…
vincentmr Mar 14, 2024
4ea4b68
Auto update version
github-actions[bot] Mar 14, 2024
1943558
trigger ci
vincentmr Mar 14, 2024
d0a1568
Move mcm logic to _apply_lightning_midmeasure and fix docstrings.
vincentmr Mar 14, 2024
0d2fffb
docstring to mention LQ
tomlqc Mar 14, 2024
b2a5d9b
docstring to mention LQ
tomlqc Mar 14, 2024
9e76d5d
docstring to mention LQ
tomlqc Mar 14, 2024
30415fc
Merge branch 'master' into feature/mid-measure-cpp
vincentmr Mar 15, 2024
dd4328b
Auto update version
github-actions[bot] Mar 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

### New features since last release

* `lightning.qubit` supports mid-circuit measurements.
tomlqc marked this conversation as resolved.
Show resolved Hide resolved
[(#621)](https://github.com/PennyLaneAI/pennylane-lightning/pull/621)

* Add two new python classes (LightningStateVector and LightningMeasurements) to support `lightning.qubit2`.
[(#613)](https://github.com/PennyLaneAI/pennylane-lightning/pull/613)

Expand Down Expand Up @@ -32,7 +35,7 @@

This release contains contributions from (in alphabetical order):

Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux
Ali Asadi, Amintor Dusko, Thomas Germain, Vincent Michaud-Rioux

---

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests_gpu_kokkos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ jobs:
OMP_PROC_BIND: false
run: |
cd main/
PL_DEVICE=lightning.qubit python -m pytest tests/ $COVERAGE_FLAGS
PL_DEVICE=lightning.qubit python -m pytest tests/ -k "not test_native_mcm" $COVERAGE_FLAGS
pl-device-test --device lightning.qubit --skip-ops --shots=20000 $COVERAGE_FLAGS --cov-append
pl-device-test --device lightning.qubit --shots=None --skip-ops $COVERAGE_FLAGS --cov-append
PL_DEVICE=lightning.kokkos python -m pytest tests/ $COVERAGE_FLAGS
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/tests_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ jobs:
matrix:
os: [ubuntu-22.04]
pl_backend: ["lightning_qubit"]
timeout-minutes: 30
timeout-minutes: 60
name: Python tests
runs-on: ${{ matrix.os }}

Expand Down Expand Up @@ -184,7 +184,8 @@ jobs:
run: |
cd main/
DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"`
PL_DEVICE=${DEVICENAME} python -m pytest tests/ $COVERAGE_FLAGS
PL_DEVICE=${DEVICENAME} python -m pytest tests/ -k "not test_native_mcm" $COVERAGE_FLAGS
OMP_NUM_THREADS=1 PL_DEVICE=${DEVICENAME} python -m pytest -n auto tests/test_native_mcm.py $COVERAGE_FLAGS
tomlqc marked this conversation as resolved.
Show resolved Hide resolved
pl-device-test --device ${DEVICENAME} --skip-ops --shots=20000 $COVERAGE_FLAGS --cov-append
pl-device-test --device ${DEVICENAME} --shots=None --skip-ops $COVERAGE_FLAGS --cov-append
mv .coverage .coverage-${{ github.job }}-${{ matrix.pl_backend }}
Expand Down Expand Up @@ -392,7 +393,7 @@ jobs:
run: |
cd main/
DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"`
PL_DEVICE=${DEVICENAME} python -m pytest tests/ $COVERAGE_FLAGS
PL_DEVICE=${DEVICENAME} python -m pytest tests/ -k "not test_native_mcm" $COVERAGE_FLAGS
pl-device-test --device ${DEVICENAME} --skip-ops --shots=20000 $COVERAGE_FLAGS --cov-append
pl-device-test --device ${DEVICENAME} --shots=None --skip-ops $COVERAGE_FLAGS --cov-append
mv .coverage .coverage-${{ github.job }}-${{ matrix.pl_backend }}
Expand Down Expand Up @@ -590,7 +591,7 @@ jobs:
run: |
cd main/
DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"`
PL_DEVICE=${DEVICENAME} python -m pytest tests/ $COVERAGE_FLAGS
PL_DEVICE=${DEVICENAME} python -m pytest tests/ -k "not test_native_mcm" $COVERAGE_FLAGS
tomlqc marked this conversation as resolved.
Show resolved Hide resolved
pl-device-test --device ${DEVICENAME} --skip-ops --shots=20000 $COVERAGE_FLAGS --cov-append
pl-device-test --device ${DEVICENAME} --shots=None --skip-ops $COVERAGE_FLAGS --cov-append
mv .coverage .coverage-${{ github.job }}-${{ matrix.pl_backend }}
Expand All @@ -609,10 +610,10 @@ jobs:
if: ${{ matrix.pl_backend == 'all' }}
run: |
cd main/
PL_DEVICE=lightning.qubit python -m pytest tests/ $COVERAGE_FLAGS
PL_DEVICE=lightning.qubit python -m pytest tests/ -k "not test_native_mcm" $COVERAGE_FLAGS
pl-device-test --device lightning.qubit --skip-ops --shots=20000 $COVERAGE_FLAGS --cov-append
pl-device-test --device lightning.qubit --shots=None --skip-ops $COVERAGE_FLAGS --cov-append
PL_DEVICE=lightning.kokkos python -m pytest tests/ $COVERAGE_FLAGS
PL_DEVICE=lightning.kokkos python -m pytest tests/ -k "not test_native_mcm" $COVERAGE_FLAGS
pl-device-test --device lightning.kokkos --skip-ops --shots=20000 $COVERAGE_FLAGS --cov-append
pl-device-test --device lightning.kokkos --shots=None --skip-ops $COVERAGE_FLAGS --cov-append
mv .coverage .coverage-${{ github.job }}-${{ matrix.pl_backend }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests_without_binary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ jobs:
run: |
cd main/
DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"`
PL_DEVICE=${DEVICENAME} python -m pytest tests/ $COVERAGE_FLAGS
PL_DEVICE=${DEVICENAME} python -m pytest tests/ -k "not test_native_mcm" $COVERAGE_FLAGS
tomlqc marked this conversation as resolved.
Show resolved Hide resolved
pl-device-test --device ${DEVICENAME} --skip-ops --shots=20000 $COVERAGE_FLAGS --cov-append
pl-device-test --device ${DEVICENAME} --shots=None --skip-ops $COVERAGE_FLAGS --cov-append

Expand Down
2 changes: 1 addition & 1 deletion pennylane_lightning/core/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.36.0-dev9"
__version__ = "0.36.0-dev10"
19 changes: 19 additions & 0 deletions pennylane_lightning/core/src/measurements/MeasurementsBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
#pragma once

#include <random>
#include <string>
#include <vector>

Expand Down Expand Up @@ -55,6 +56,7 @@ template <class StateVectorT, class Derived> class MeasurementsBase {
#else
const StateVectorT &_statevector;
#endif
std::mt19937 rng;

public:
#ifdef _ENABLE_PLGPU
Expand All @@ -65,6 +67,23 @@ template <class StateVectorT, class Derived> class MeasurementsBase {
: _statevector{statevector} {};
#endif

/**
* @brief Set the seed of the internal random generator
*
* @param seed Seed
*/
void setSeed(const size_t seed) { rng.seed(seed); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! So the seed has to be set on each measurement object right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the current way in LQubit or GPU implementations (set randomly).


/**
* @brief Randomly set the seed of the internal random generator
*
* @param seed Seed
*/
void setRandomSeed() {
std::random_device rd;
setSeed(rd());
}

/**
* @brief Calculate the expectation value for a general Observable.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,10 @@ class Measurements final
data_type = CUDA_C_32F;
}

std::mt19937 gen(std::random_device{}());
this->setRandomSeed();
std::uniform_real_distribution<PrecisionT> dis(0.0, 1.0);
for (size_t n = 0; n < num_samples; n++) {
rand_nums[n] = dis(gen);
rand_nums[n] = dis(this->rng);
}
std::vector<size_t> samples(num_samples * num_qubits, 0);
std::unordered_map<size_t, size_t> cache;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace {
using Pennylane::LightningQubit::Util::Threading;
using Pennylane::Util::CPUMemoryModel;
using Pennylane::Util::exp2;
using Pennylane::Util::squaredNorm;
using namespace Pennylane::LightningQubit::Gates;
} // namespace
/// @endcond
Expand Down Expand Up @@ -632,5 +633,53 @@ class StateVectorLQubit : public StateVectorBase<PrecisionT, Derived> {

applyMatrix(matrix.data(), wires, inverse);
}

/**
* @brief Collapse the state vector as after having measured one of the
vincentmr marked this conversation as resolved.
Show resolved Hide resolved
* qubits.
*
* The branch parameter imposes the measurement result on the given wire.
*
* @param wire Wire to collapse.
* @param branch Branch 0 or 1.
*/
void collapse(const std::size_t wire, const bool branch) {
tomlqc marked this conversation as resolved.
Show resolved Hide resolved
auto *arr = this->getData();
const size_t stride = pow(2, this->num_qubits_ - (1 + wire));
const size_t vec_size = pow(2, this->num_qubits_);
const auto section_size = vec_size / stride;
const auto half_section_size = section_size / 2;

// zero half the entries
// the "half" entries depend on the stride
// *_*_*_*_ for stride 1
// **__**__ for stride 2
// ****____ for stride 4
const size_t k = branch ? 0 : 1;
for (size_t idx = 0; idx < half_section_size; idx++) {
const size_t offset = stride * (k + 2 * idx);
for (size_t ids = 0; ids < stride; ids++) {
arr[offset + ids] = {0., 0.};
}
}

normalize();
}

/**
* @brief Normalize vector (to have norm 1).
*/
void normalize() {
tomlqc marked this conversation as resolved.
Show resolved Hide resolved
auto *arr = this->getData();
PrecisionT norm = std::sqrt(squaredNorm(arr, this->getLength()));

PL_ABORT_IF(norm < std::numeric_limits<PrecisionT>::epsilon() * 1e2,
"vector has norm close to zero and can't be normalized");

std::complex<PrecisionT> inv_norm = 1. / norm;
for (size_t k = 0; k < this->getLength(); k++) {
arr[k] *= inv_norm;
}
}
};
} // namespace Pennylane::LightningQubit
} // namespace Pennylane::LightningQubit
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) {
}
},
"Copy StateVector data into a Numpy array.")
.def("collapse", &StateVectorT::collapse,
"Collapse the statevector onto the 0 or 1 branch of a given wire.")
.def("normalize", &StateVectorT::normalize,
"Normalizes the statevector to norm 1.")
.def("applyControlledMatrix", &applyControlledMatrix<StateVectorT>,
"Apply controlled operation")
.def("kernel_map", &svKernelMap<StateVectorT>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,11 +466,10 @@ class Measurements final
generate_samples_metropolis(const std::string &kernelname,
size_t num_burnin, size_t num_samples) {
size_t num_qubits = this->_statevector.getNumQubits();
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<PrecisionT> distrib(0.0, 1.0);
std::vector<size_t> samples(num_samples * num_qubits, 0);
std::unordered_map<size_t, size_t> cache;
this->setRandomSeed();

TransitionKernelType transition_kernel = TransitionKernelType::Local;
if (kernelname == "NonZeroRandom") {
Expand All @@ -484,13 +483,14 @@ class Measurements final

// Burn In
for (size_t i = 0; i < num_burnin; i++) {
idx = metropolis_step(this->_statevector, tk, gen, distrib,
idx = metropolis_step(this->_statevector, tk, this->rng, distrib,
idx); // Burn-in.
}

// Sample
for (size_t i = 0; i < num_samples; i++) {
idx = metropolis_step(this->_statevector, tk, gen, distrib, idx);
idx = metropolis_step(this->_statevector, tk, this->rng, distrib,
idx);

if (cache.contains(idx)) {
size_t cache_id = cache[idx];
Expand Down Expand Up @@ -562,9 +562,9 @@ class Measurements final
auto &&probabilities = probs();

std::vector<size_t> samples(num_samples * num_qubits, 0);
std::mt19937 generator(std::random_device{}());
std::uniform_real_distribution<PrecisionT> distribution(0.0, 1.0);
std::unordered_map<size_t, size_t> cache;
this->setRandomSeed();

const size_t N = probabilities.size();
std::vector<double> bucket(N);
Expand Down Expand Up @@ -611,7 +611,7 @@ class Measurements final

// Pick samples
for (size_t i = 0; i < num_samples; i++) {
PrecisionT pct = distribution(generator) * N;
PrecisionT pct = distribution(this->rng) * N;
auto idx = static_cast<size_t>(pct);
if (pct - idx > bucket[idx]) {
idx = bucket_partner[idx];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,38 @@ TEMPLATE_PRODUCT_TEST_CASE("StateVectorLQubit::applyOperations",
LightningException, "must all be equal"); // invalid parameters
}
}

TEMPLATE_PRODUCT_TEST_CASE("StateVectorLQubit::collapse", "[StateVectorLQubit]",
(StateVectorLQubitManaged, StateVectorLQubitRaw),
(float, double)) {
using StateVectorT = TestType;
using PrecisionT = typename StateVectorT::PrecisionT;
using ComplexT = typename StateVectorT::ComplexT;
using TestVectorT = TestVector<ComplexT>;

const std::size_t num_qubits = 3;

SECTION("Collapse the state vector as after having measured one of the "
"qubits.") {
TestVectorT init_state = createPlusState<PrecisionT>(num_qubits);

const ComplexT coef{0.5, PrecisionT{0.0}};
const ComplexT zero{PrecisionT{0.0}, PrecisionT{0.0}};

std::vector<std::vector<std::vector<ComplexT>>> expected_state = {
{{coef, coef, coef, coef, zero, zero, zero, zero},
{coef, coef, zero, zero, coef, coef, zero, zero},
{coef, zero, coef, zero, coef, zero, coef, zero}},
{{zero, zero, zero, zero, coef, coef, coef, coef},
{zero, zero, coef, coef, zero, zero, coef, coef},
{zero, coef, zero, coef, zero, coef, zero, coef}},
};

std::size_t wire = GENERATE(0, 1, 2);
std::size_t branch = GENERATE(0, 1);
StateVectorLQubitManaged<PrecisionT> sv(init_state);
sv.collapse(wire, branch);

REQUIRE(sv.getDataVector() == approx(expected_state[branch][wire]));
}
}
2 changes: 1 addition & 1 deletion pennylane_lightning/lightning_kokkos/lightning_kokkos.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
from pennylane.ops.op_math import Adjoint
from pennylane.wires import Wires

# pylint: disable=import-error, no-name-in-module, ungrouped-imports
# pylint: disable=ungrouped-imports
from pennylane_lightning.lightning_kokkos_ops.algorithms import (
tomlqc marked this conversation as resolved.
Show resolved Hide resolved
AdjointJacobianC64,
AdjointJacobianC128,
Expand Down
Loading