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 native N-control gate support to lightning.gpu #938

Merged
merged 76 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
4f37e20
initial commit
multiphaseCFD Oct 8, 2024
dad7de8
Auto update version from '0.39.0-dev40' to '0.39.0-dev41'
ringo-but-quantum Oct 8, 2024
3d30f21
Merge branch 'master' into applyControlledMatrix_LGPU
multiphaseCFD Oct 16, 2024
dd0307a
Auto update version from '0.39.0-dev45' to '0.39.0-dev46'
ringo-but-quantum Oct 16, 2024
d81874b
fix applyControlledMatrix
multiphaseCFD Oct 16, 2024
ed2df45
update GlobalPhase and CGlobalPhase gate support
multiphaseCFD Oct 16, 2024
e06cd31
fix applyControlledMatrix
multiphaseCFD Oct 16, 2024
ad6a179
update unit tests
multiphaseCFD Oct 17, 2024
c4b6d85
make format
multiphaseCFD Oct 17, 2024
3ce16e6
update GlobalPhase support with `scaleC_CUDA`
multiphaseCFD Oct 17, 2024
008c4f3
remove global_phase_diagonal
multiphaseCFD Oct 17, 2024
015b50a
remove unused lines
multiphaseCFD Oct 17, 2024
02eb290
initial commit
multiphaseCFD Oct 17, 2024
dd2dbab
Auto update version from '0.39.0-dev45' to '0.39.0-dev46'
ringo-but-quantum Oct 17, 2024
a77fef3
add py unit tests for globalphase gate
multiphaseCFD Oct 17, 2024
dffb78f
raise error for mpi-cGlobalPhase
multiphaseCFD Oct 17, 2024
2641cfc
make format
multiphaseCFD Oct 17, 2024
56b26e2
add changelog
multiphaseCFD Oct 17, 2024
38b762e
Trigger CIs
multiphaseCFD Oct 17, 2024
a0abe2e
quick fix for the setup.py
multiphaseCFD Oct 18, 2024
2f65169
add C++ unit tests
multiphaseCFD Oct 18, 2024
d303e87
Auto update version from '0.39.0-dev46' to '0.39.0-dev47'
ringo-but-quantum Oct 18, 2024
95662ec
add more C++ unit tests
multiphaseCFD Oct 18, 2024
c035b51
update the frontend
multiphaseCFD Oct 21, 2024
faad0e9
Auto update version from '0.39.0-dev47' to '0.39.0-dev48'
ringo-but-quantum Oct 21, 2024
148b8df
update changelog
multiphaseCFD Oct 21, 2024
a87d77b
Merge branch 'master' into applyControlledMatrix_LGPU
multiphaseCFD Oct 21, 2024
7ea85d8
Auto update version from '0.39.0-dev47' to '0.39.0-dev48'
ringo-but-quantum Oct 21, 2024
388efae
Trigger CIs
multiphaseCFD Oct 21, 2024
5974b47
Merge branch 'master' into update_gphase_lgpu
multiphaseCFD Oct 21, 2024
fbae962
Auto update version from '0.39.0-dev47' to '0.39.0-dev48'
ringo-but-quantum Oct 21, 2024
7ec070e
update py CIs
multiphaseCFD Oct 21, 2024
c1a141a
add more C++ unit tests
multiphaseCFD Oct 22, 2024
b54b8ca
add checks for ctrls and tgts
multiphaseCFD Oct 22, 2024
b7ec1da
tidy up naming
multiphaseCFD Oct 22, 2024
2970625
Merge branch 'update_gphase_lgpu' into applyControlledMatrix_LGPU
multiphaseCFD Oct 22, 2024
4e69bb3
update
multiphaseCFD Oct 22, 2024
454e4e0
quick fix
multiphaseCFD Oct 22, 2024
add8525
Merge branch 'master' into applyControlledMatrix_LGPU
multiphaseCFD Oct 23, 2024
9b56685
Auto update version from '0.39.0-dev48' to '0.39.0-dev49'
ringo-but-quantum Oct 23, 2024
b0300d6
update
multiphaseCFD Oct 23, 2024
7e4a34b
quick fix
multiphaseCFD Oct 23, 2024
8c07c01
make format
multiphaseCFD Oct 23, 2024
f2306cc
apply Joseph's comments
multiphaseCFD Oct 25, 2024
e6fe638
Auto update version from '0.39.0-dev49' to '0.39.0-dev51'
ringo-but-quantum Oct 25, 2024
3da92b2
apply afredo's comments
multiphaseCFD Oct 25, 2024
c3bd58a
add todos
multiphaseCFD Oct 25, 2024
e17ab64
Merge branch 'master' into applyControlledMatrix_LGPU
multiphaseCFD Oct 25, 2024
fb8d102
Auto update version from '0.39.0-dev50' to '0.39.0-dev51'
ringo-but-quantum Oct 25, 2024
eb7e171
update pybind and C++ tests
multiphaseCFD Oct 28, 2024
e3faa62
Auto update version from '0.39.0-dev51' to '0.39.0-dev52'
ringo-but-quantum Oct 28, 2024
fb58bd1
Merge branch 'master' into applyControlledMatrix_LGPU
multiphaseCFD Oct 29, 2024
4e0d219
Auto update version from '0.39.0-dev51' to '0.39.0-dev52'
ringo-but-quantum Oct 29, 2024
8b9f972
update py unit tests to avoid lq compilations
multiphaseCFD Oct 29, 2024
bc59f43
apply some Ali's suggestions
multiphaseCFD Oct 29, 2024
40c41b1
disable adjoint tests for N-controlled gates
multiphaseCFD Oct 29, 2024
9a27d1d
update stopping conditions
multiphaseCFD Oct 30, 2024
21b3ccb
by generator pass
multiphaseCFD Oct 31, 2024
cbe31a0
update
multiphaseCFD Nov 1, 2024
cc4144a
quick fix
multiphaseCFD Nov 1, 2024
20af2d6
apply Ali's comments
multiphaseCFD Nov 1, 2024
3edd735
add fix for qml.state() LT
multiphaseCFD Nov 2, 2024
ad94229
Merge branch 'master' into applyControlledMatrix_LGPU
maliasadi Nov 5, 2024
05e2300
Auto update version from '0.39.0-dev52' to '0.39.0-dev53'
ringo-but-quantum Nov 5, 2024
fc562d2
Merge v0.39.0_rc to master (#981)
multiphaseCFD Nov 6, 2024
0372bf4
Auto update version from '0.40.0-dev0' to '0.40.0-dev1'
ringo-but-quantum Nov 6, 2024
d780231
Merge branch 'master' into applyControlledMatrix_LGPU
multiphaseCFD Nov 6, 2024
99eb201
Auto update version from '0.40.0-dev0' to '0.40.0-dev1'
ringo-but-quantum Nov 6, 2024
b3183ab
update toml file
multiphaseCFD Nov 6, 2024
c297a29
Trigger CIs
multiphaseCFD Nov 6, 2024
c067ece
Merge branch 'master' into applyControlledMatrix_LGPU
multiphaseCFD Nov 6, 2024
5b2c95f
Auto update version from '0.40.0-dev1' to '0.40.0-dev2'
ringo-but-quantum Nov 6, 2024
962be77
Trigger CIs
multiphaseCFD Nov 6, 2024
ce68bd1
revert pennylane version
multiphaseCFD Nov 6, 2024
9ff1915
Merge branch 'master' into applyControlledMatrix_LGPU
multiphaseCFD Nov 6, 2024
bc18ba1
Trigger CIs
multiphaseCFD Nov 7, 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
3 changes: 3 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

### New features since last release

* Add native N-controlled gates support to `lightning.gpu`'s single-GPU backend.
[(#938)](https://github.com/PennyLaneAI/pennylane-lightning/pull/938)

* Add `mid-circuit measurements` support to `lightning.gpu`'s single-GPU backend.
[(#931)](https://github.com/PennyLaneAI/pennylane-lightning/pull/931)

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.39.0-dev51"
__version__ = "0.39.0-dev52"

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,55 @@ using StateVectorBackends =
StateVectorCudaManaged<double>, void>;

/**
* @brief Get a gate kernel map for a statevector.
* @brief Register controlled matrix kernel.
*/
template <class StateVectorT>
void applyControlledMatrix(
StateVectorT &st,
const py::array_t<std::complex<typename StateVectorT::PrecisionT>,
py::array::c_style | py::array::forcecast> &matrix,
const std::vector<std::size_t> &controlled_wires,
const std::vector<bool> &controlled_values,
const std::vector<std::size_t> &wires, bool inverse = false) {
using ComplexT = typename StateVectorT::ComplexT;
st.applyControlledMatrix(
static_cast<const ComplexT *>(matrix.request().ptr),
static_cast<const std::size_t>(matrix.request().size), controlled_wires,
controlled_values, wires, inverse);
}

template <class StateVectorT, class PyClass>
void registerControlledGate(PyClass &pyclass) {
using PrecisionT =
typename StateVectorT::PrecisionT; // Statevector's precision
using ParamT = PrecisionT; // Parameter's data precision

using Pennylane::Gates::ControlledGateOperation;
using Pennylane::Util::for_each_enum;
namespace Constant = Pennylane::Gates::Constant;

for_each_enum<ControlledGateOperation>(
multiphaseCFD marked this conversation as resolved.
Show resolved Hide resolved
[&pyclass](ControlledGateOperation gate_op) {
using Pennylane::Util::lookup;
const auto gate_name =
std::string(lookup(Constant::controlled_gate_names, gate_op));
const std::string doc = "Apply the " + gate_name + " gate.";
auto func = [gate_name](
StateVectorT &sv,
const std::vector<std::size_t> &controlled_wires,
const std::vector<bool> &controlled_values,
const std::vector<std::size_t> &wires, bool inverse,
const std::vector<ParamT> &params) {
sv.applyOperation(gate_name, controlled_wires,
controlled_values, wires, inverse, params);
};
pyclass.def(gate_name.c_str(), func, doc.c_str());
});
}

/**
* @brief Get a gate kernel map for a statevector.
*/
template <class StateVectorT, class PyClass>
void registerBackendClassSpecificBindings(PyClass &pyclass) {
using PrecisionT =
Expand All @@ -65,6 +111,7 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) {
py::array::c_style | py::array::forcecast>;

registerGatesForStateVector<StateVectorT>(pyclass);
registerControlledGate<StateVectorT>(pyclass);

pyclass
.def(py::init<std::size_t>()) // qubits, device
Expand Down Expand Up @@ -96,6 +143,8 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) {
},
"Set State Vector on GPU with values for the state vector and "
"wires on the host memory.")
.def("applyControlledMatrix", &applyControlledMatrix<StateVectorT>,
"Apply controlled operation")
.def(
"DeviceToDevice",
[](StateVectorT &sv, const StateVectorT &other, bool async) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1105,4 +1105,257 @@ TEMPLATE_TEST_CASE("StateVectorCudaManaged::SetIthStates",

CHECK(expected_state == Pennylane::Util::approx(sv.getDataVector()));
}
}
}

TEMPLATE_TEST_CASE("StateVectorCudaManaged::applyOperation non-param "
"one-qubit with controls",
"[StateVectorCudaManaged]", float, double) {
using PrecisionT = TestType;
std::mt19937 re{1337};
const int num_qubits = 4;
const auto margin = PrecisionT{1e-5};
const std::size_t control = GENERATE(0, 1, 2, 3);
multiphaseCFD marked this conversation as resolved.
Show resolved Hide resolved
const std::size_t wire = GENERATE(0, 1, 2, 3);
auto st0 = createRandomStateVectorData<PrecisionT>(re, num_qubits);
StateVectorCudaManaged<PrecisionT> sv0(num_qubits);
StateVectorCudaManaged<PrecisionT> sv1(num_qubits);

sv0.CopyHostDataToGpu(st0.data(), st0.size());
sv1.CopyHostDataToGpu(st0.data(), st0.size());

DYNAMIC_SECTION("N-controlled PauliX - "
<< "controls = {" << control << "} "
<< ", wires = {" << wire << "} - "
<< PrecisionToName<PrecisionT>::value) {
multiphaseCFD marked this conversation as resolved.
Show resolved Hide resolved
if (control != wire) {
sv0.applyOperation("CNOT", {control, wire});
sv1.applyOperation("PauliX", std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire});
REQUIRE(sv0.getDataVector() ==
multiphaseCFD marked this conversation as resolved.
Show resolved Hide resolved
approx(sv1.getDataVector()).margin(margin));
} else {
PL_REQUIRE_THROWS_MATCHES(
sv0.applyOperation("PauliX", std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire}),
LightningException,
"`controlled_wires` and target wires must be disjoint.");
}

if (control != 0 && wire != 0 && control != wire) {
sv0.applyOperation("Toffoli", {0, control, wire});
sv1.applyOperation("PauliX", std::vector<std::size_t>{0, control},
std::vector<bool>{true, true},
std::vector<std::size_t>{wire});
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));

sv0.applyOperation("Toffoli", {control, 0, wire});
sv1.applyOperation("PauliX", std::vector<std::size_t>{control, 0},
std::vector<bool>{true, true},
std::vector<std::size_t>{wire});
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));
}
}

DYNAMIC_SECTION("N-controlled PauliY - "
<< "controls = {" << control << "} "
<< ", wires = {" << wire << "} - "
<< PrecisionToName<PrecisionT>::value) {
if (control != wire) {
sv0.applyOperation("CY", {control, wire});
sv1.applyOperation("PauliY", std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire});
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));
}
}

DYNAMIC_SECTION("N-controlled PauliZ - "
<< "controls = {" << control << "} "
<< ", wires = {" << wire << "} - "
<< PrecisionToName<PrecisionT>::value) {
if (control != wire) {
sv0.applyOperation("CZ", {control, wire});
sv1.applyOperation("PauliZ", std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire});
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));
}
}

DYNAMIC_SECTION("N-controlled Hadamard - "
<< "controls = {" << control << "} "
<< ", wires = {" << wire << "} - "
<< PrecisionToName<PrecisionT>::value) {
if (control != wire) {
const auto matrix = getHadamard<std::complex, PrecisionT>();

sv0.applyControlledMatrix(
matrix.data(), matrix.size(), std::vector<std::size_t>{control},
std::vector<bool>{true}, std::vector<std::size_t>{wire});
sv1.applyOperation("Hadamard", std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire});
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));
}
}
DYNAMIC_SECTION("N-controlled S - "
<< "controls = {" << control << "} "
<< ", wires = {" << wire << "} - "
<< PrecisionToName<PrecisionT>::value) {
if (control != wire) {
const auto matrix = getS<std::complex, PrecisionT>();

sv0.applyControlledMatrix(
matrix.data(), matrix.size(), std::vector<std::size_t>{control},
std::vector<bool>{true}, std::vector<std::size_t>{wire});
sv1.applyOperation("S", std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire});
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));
}
}

DYNAMIC_SECTION("N-controlled T - "
<< "controls = {" << control << "} "
<< ", wires = {" << wire << "} - "
<< PrecisionToName<PrecisionT>::value) {
if (control != wire) {
const std::vector<std::complex<PrecisionT>> matrix =
getT<std::complex, PrecisionT>();

sv0.applyControlledMatrix(
matrix.data(), matrix.size(), std::vector<std::size_t>{control},
std::vector<bool>{true}, std::vector<std::size_t>{wire});
sv1.applyOperation("T", std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire});
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));
}
}
}

TEMPLATE_TEST_CASE("StateVectorCudaManaged::applyOperation non-param "
"two-qubit with controls",
"[StateVectorCudaManaged]", float, double) {
using PrecisionT = TestType;
std::mt19937 re{1337};
const int num_qubits = 4;
const auto margin = PrecisionT{1e-5};
const std::size_t control = GENERATE(0, 1, 2, 3);
const std::size_t wire0 = GENERATE(0, 1, 2, 3);
const std::size_t wire1 = GENERATE(0, 1, 2, 3);
auto st0 = createRandomStateVectorData<PrecisionT>(re, num_qubits);
StateVectorCudaManaged<PrecisionT> sv0(num_qubits);
StateVectorCudaManaged<PrecisionT> sv1(num_qubits);

sv0.CopyHostDataToGpu(st0.data(), st0.size());
sv1.CopyHostDataToGpu(st0.data(), st0.size());

DYNAMIC_SECTION("N-controlled SWAP - "
<< "controls = {" << control << "} "
<< ", wires = {" << wire0 << ", " << wire1 << "} - "
<< PrecisionToName<PrecisionT>::value) {
if (control != wire0 && control != wire1 && wire0 != wire1) {
sv0.applyOperation("CSWAP", {control, wire0, wire1});
sv1.applyOperation("SWAP", std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire0, wire1});
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));
}
}

DYNAMIC_SECTION("N-controlled SWAP with matrix- "
<< "controls = {" << control << "} "
<< ", wires = {" << wire0 << ", " << wire1 << "} - "
<< PrecisionToName<PrecisionT>::value) {
if (control != wire0 && control != wire1 && wire0 != wire1) {
const std::vector<std::complex<PrecisionT>> matrix =
getSWAP<std::complex, PrecisionT>();
sv0.applyControlledMatrix(matrix.data(), matrix.size(),
std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire0, wire1});
sv1.applyOperation("SWAP", std::vector<std::size_t>{control},
std::vector<bool>{true},
std::vector<std::size_t>{wire0, wire1});
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));
}
}
}

TEMPLATE_TEST_CASE("StateVectorCudaManaged::controlled Toffoli",
"[StateVectorCudaManaged]", float, double) {
using PrecisionT = TestType;
std::mt19937 re{1337};
const int num_qubits = 6;
const auto margin = PrecisionT{1e-5};
const std::size_t control = GENERATE(0, 1, 2);
auto st0 = createRandomStateVectorData<PrecisionT>(re, num_qubits);

StateVectorCudaManaged<PrecisionT> sv0(num_qubits);
StateVectorCudaManaged<PrecisionT> sv1(num_qubits);

sv0.CopyHostDataToGpu(st0.data(), st0.size());
sv1.CopyHostDataToGpu(st0.data(), st0.size());

const std::vector<std::complex<PrecisionT>> matrix =
getToffoli<std::complex, PrecisionT>();
sv0.applyControlledMatrix(
matrix.data(), matrix.size(), std::vector<std::size_t>{control},
std::vector<bool>{true}, std::vector<std::size_t>{3, 4, 5});
sv1.applyOperation("PauliX", std::vector<std::size_t>{control, 3, 4},
std::vector<bool>{true, true, true},
std::vector<std::size_t>{5});
REQUIRE(sv0.getDataVector() == approx(sv1.getDataVector()).margin(margin));
}

TEMPLATE_TEST_CASE(
"StateVectorCudaManaged::controlled_gate_direct_matrix_offload",
"[StateVectorCudaManaged]", float, double) {
using PrecisionT = TestType;
std::mt19937 re{1337};
const int num_qubits = 6;
const auto margin = PrecisionT{1e-5};
const std::size_t control = GENERATE(0, 1, 2);
auto st0 = createRandomStateVectorData<PrecisionT>(re, num_qubits);

StateVectorCudaManaged<PrecisionT> sv0(num_qubits);
StateVectorCudaManaged<PrecisionT> sv1(num_qubits);

sv0.CopyHostDataToGpu(st0.data(), st0.size());
sv1.CopyHostDataToGpu(st0.data(), st0.size());

SECTION("Catch failures caused by unsupported named gates") {
PL_CHECK_THROWS_MATCHES(
sv0.applyOperation("paulix",
std::vector<std::size_t>{control, 3, 4},
std::vector<bool>{true, true, true},
std::vector<std::size_t>{5}),
LightningException, "Currently unsupported gate: paulix");
}

SECTION("direct base matrix offload") {
const std::vector<std::complex<PrecisionT>> matrix = {
{0.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}};
sv0.applyControlledMatrix(matrix.data(), matrix.size(),
std::vector<std::size_t>{control, 3, 4},
std::vector<bool>{true, true, true},
std::vector<std::size_t>{5});
sv1.applyOperation("Paulix", std::vector<std::size_t>{control, 3, 4},
std::vector<bool>{true, true, true},
std::vector<std::size_t>{5}, false, {0.0}, matrix);
REQUIRE(sv0.getDataVector() ==
approx(sv1.getDataVector()).margin(margin));
}
}
Loading
Loading