Skip to content

Commit

Permalink
Add CPhaseShiftGate with tests (#112) (#114)
Browse files Browse the repository at this point in the history
* Add CPhaseShiftGate with tests (#112)

* Add CPhaseShiftGate with tests (#112)

* Update support for ControlledPhaseShift Gate (#114)

* Update test-cases for ControlledPhaseShift Gate (#114)

* Update test-cases and formatting with clang-format-12 (#114)

Co-authored-by: Lee James O'Riordan <mlxd@users.noreply.github.com>
  • Loading branch information
maliasadi and mlxd authored Jul 28, 2021
1 parent 515166e commit 550ee8a
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 10 deletions.
7 changes: 5 additions & 2 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

### Improvements

- Move changelog to `.github` and add a changelog reminder.
* Move changelog to `.github` and add a changelog reminder.

* Add support for Controlled Phase Gate (CPhaseShift).
[(#112)](https://github.com/PennyLaneAI/pennylane-lightning/issues/112)

### Breaking changes

Expand All @@ -14,7 +17,7 @@

This release contains contributions from (in alphabetical order):

Thomas Bromley
Ali Asadi, Thomas Bromley

---

Expand Down
1 change: 1 addition & 0 deletions pennylane_lightning/lightning_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class LightningQubit(DefaultQubit):
"CRY",
"CRZ",
"CRot",
"ControlledPhaseShift",
}

observables = {"PauliX", "PauliY", "PauliZ", "Hadamard", "Hermitian", "Identity"}
Expand Down
45 changes: 44 additions & 1 deletion pennylane_lightning/src/Gates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ Pennylane::PhaseShiftGate::PhaseShiftGate(double rotationAngle)
void Pennylane::PhaseShiftGate::applyKernel(
const StateVector &state, const std::vector<size_t> &indices,
const std::vector<size_t> &externalIndices, bool inverse) {
CplxType s = (inverse == true) ? conj(shift) : shift;
const CplxType s = (inverse == true) ? conj(shift) : shift;

for (const size_t &externalIndex : externalIndices) {
CplxType *shiftedState = state.arr + externalIndex;
Expand Down Expand Up @@ -682,6 +682,48 @@ void Pennylane::CGeneralRotationGate::applyKernel(

// -------------------------------------------------------------------------------------------------------------

const string Pennylane::CPhaseShiftGate::label = "ControlledPhaseShift";

Pennylane::CPhaseShiftGate
Pennylane::CPhaseShiftGate::create(const vector<double> &parameters) {
validateLength(Pennylane::CPhaseShiftGate::label, parameters, 1);
return Pennylane::CPhaseShiftGate(parameters[0]);
}

Pennylane::CPhaseShiftGate::CPhaseShiftGate(double phi)
: shift(std::pow(M_E, CplxType(0, phi))), matrix{1, 0, 0, 0, 0, 1,
0, 0, 0, 0, 1, 0,
0, 0, 0, shift} {}

void Pennylane::CPhaseShiftGate::applyKernel(
const StateVector &state, const std::vector<size_t> &indices,
const std::vector<size_t> &externalIndices, bool inverse) {
const CplxType s = inverse ? conj(shift) : shift;

for (const size_t &externalIndex : externalIndices) {
CplxType *shiftedState = state.arr + externalIndex;
shiftedState[indices[3]] *= s;
}
}

const double Pennylane::CPhaseShiftGate::generatorScalingFactor{1.0};

void Pennylane::CPhaseShiftGate::applyGenerator(
const StateVector &state,

const std::vector<size_t> &indices,
const std::vector<size_t> &externalIndices) {

for (const size_t &externalIndex : externalIndices) {
CplxType *shiftedState = state.arr + externalIndex;
shiftedState[indices[0]] = 0;
shiftedState[indices[1]] = 0;
shiftedState[indices[2]] = 0;
}
}

// -------------------------------------------------------------------------------------------------------------

Pennylane::ThreeQubitGate::ThreeQubitGate() : AbstractGate(3) {}

// -------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -771,6 +813,7 @@ createDispatchTable() {
addToDispatchTable<Pennylane::CRotationYGate>(dispatchTable);
addToDispatchTable<Pennylane::CRotationZGate>(dispatchTable);
addToDispatchTable<Pennylane::CGeneralRotationGate>(dispatchTable);
addToDispatchTable<Pennylane::CPhaseShiftGate>(dispatchTable);
addToDispatchTable<Pennylane::ToffoliGate>(dispatchTable);
addToDispatchTable<Pennylane::CSWAPGate>(dispatchTable);
return dispatchTable;
Expand Down
20 changes: 19 additions & 1 deletion pennylane_lightning/src/Gates.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,26 @@ class CGeneralRotationGate : public TwoQubitGate {
const std::vector<size_t> &externalIndices, bool inverse);
};

// Three-qubit gates
class CPhaseShiftGate : public TwoQubitGate {
private:
const CplxType shift;
const std::vector<CplxType> matrix;

public:
static const std::string label;
static CPhaseShiftGate create(const std::vector<double> &parameters);
CPhaseShiftGate(double phi);
inline const std::vector<CplxType> &asMatrix() { return matrix; }
void applyKernel(const StateVector &state,
const std::vector<size_t> &indices,
const std::vector<size_t> &externalIndices, bool inverse);
void applyGenerator(const StateVector &state,
const std::vector<size_t> &indices,
const std::vector<size_t> &externalIndices);
static const double generatorScalingFactor;
};

// Three-qubit gates
class ThreeQubitGate : public AbstractGate {
protected:
ThreeQubitGate();
Expand Down
9 changes: 9 additions & 0 deletions pennylane_lightning/src/tests/GateData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ vector<CplxType> PhaseShift(const vector<double> &pars) {
return {1, 0, 0, shift};
}

vector<CplxType> CPhaseShift(const vector<double> &pars) {
double parameter = pars.at(0);

const std::complex<double> phase(0, parameter);
const std::complex<double> shift = std::pow(M_E, phase);

return {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, shift};
}

vector<CplxType> Rot(const vector<double> &pars) {
double phi = pars.at(0);
double theta = pars.at(1);
Expand Down
9 changes: 6 additions & 3 deletions pennylane_lightning/src/tests/lightning_gates_unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ INSTANTIATE_TEST_SUITE_P(
std::make_tuple("CRX", CRX, ONE_PARAM),
std::make_tuple("CRY", CRY, ONE_PARAM),
std::make_tuple("CRZ", CRZ, ONE_PARAM),
std::make_tuple("CRot", CRot, THREE_PARAMS)));
std::make_tuple("CRot", CRot, THREE_PARAMS),
std::make_tuple("ControlledPhaseShift", CPhaseShift,
ONE_PARAM)));

// -------------------------------------------------------------------------------------------------------------
// Parameter length validation
Expand All @@ -112,8 +114,9 @@ INSTANTIATE_TEST_SUITE_P(
::testing::Combine(::testing::ValuesIn(non_param_gates),
::testing::ValuesIn(many_params)));

const vector<string> param_gates = {"RX", "RY", "RZ", "PhaseShift", "Rot",
"CRX", "CRY", "CRZ", "CRot"};
const vector<string> param_gates = {
"RX", "RY", "RZ", "PhaseShift", "Rot",
"CRX", "CRY", "CRZ", "CRot", "ControlledPhaseShift"};
const vector<vector<double>> zero_params = {ZERO_PARAM};

INSTANTIATE_TEST_SUITE_P(ParametrizedGateChecks, NumParamsThrowsFixture,
Expand Down
1 change: 0 additions & 1 deletion pennylane_lightning/src/typedefs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,4 @@
namespace Pennylane {

using CplxType = std::complex<double>;

}
34 changes: 32 additions & 2 deletions tests/test_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ def test_apply_operation_state_preparation(

assert np.allclose(qubit_device_2_wires.state, np.array(expected_output), atol=tol, rtol=0)

""" operation,input,expected_output,par """
test_data_single_wire_with_parameters = [
(qml.PhaseShift, [1, 0], [1, 0], [math.pi / 2]),
(qml.PhaseShift, [0, 1], [0, 1j], [math.pi / 2]),
Expand Down Expand Up @@ -277,6 +278,7 @@ def test_apply_operation_single_wire_with_parameters(

assert np.allclose(qubit_device_1_wire.state, np.array(expected_output), atol=tol, rtol=0)

""" operation,input,expected_output,par """
test_data_two_wires_with_parameters = [
(qml.CRX, [0, 1, 0, 0], [0, 1, 0, 0], [math.pi / 2]),
(qml.CRX, [0, 0, 0, 1], [0, 0, -1j, 0], [math.pi]),
Expand Down Expand Up @@ -327,6 +329,30 @@ def test_apply_operation_single_wire_with_parameters(
[0, 1 / math.sqrt(2), 0, -1 / 2 + 1j / 2],
[-math.pi / 2, math.pi, math.pi],
),
(
qml.ControlledPhaseShift,
[1, 0, 0, 0],
[1, 0, 0, 0],
[math.pi / 2],
),
(
qml.ControlledPhaseShift,
[0, 1, 0, 0],
[0, 1, 0, 0],
[math.pi / 2],
),
(
qml.ControlledPhaseShift,
[0, 0, 1, 0],
[0, 0, 1, 0],
[math.pi / 2],
),
(
qml.ControlledPhaseShift,
[1 / math.sqrt(2), 1 / math.sqrt(2), 1 / math.sqrt(2), 1 / math.sqrt(2)],
[1 / math.sqrt(2), 1 / math.sqrt(2), 1 / math.sqrt(2), 1 / 2 + 1j / 2],
[math.pi / 4],
),
]

@pytest.mark.parametrize(
Expand Down Expand Up @@ -859,7 +885,7 @@ def circuit():
# This test is ran against the state 1/2|00>+sqrt(3)/2|11> with two Z expvals
@pytest.mark.parametrize(
"name,par,expected_output",
[
[
("CRX", [0], [-1 / 2, -1 / 2]),
("CRX", [-math.pi], [-1 / 2, 1]),
("CRX", [math.pi / 2], [-1 / 2, 1 / 4]),
Expand All @@ -875,12 +901,16 @@ def circuit():
("CRot", [math.pi / 2, 0, -math.pi], [-1 / 2, -1 / 2]),
("CRot", [0, math.pi / 2, -math.pi], [-1 / 2, 1 / 4]),
("CRot", [-math.pi, 0, math.pi / 2], [-1 / 2, -1 / 2]),
("ControlledPhaseShift", [0], [-1 / 2, -1 / 2]),
("ControlledPhaseShift", [-math.pi], [-1 / 2, -1 / 2]),
("ControlledPhaseShift", [math.pi / 2], [-1 / 2, -1 / 2]),
("ControlledPhaseShift", [math.pi], [-1 / 2, -1 / 2]),
],
)
def test_supported_gate_two_wires_with_parameters(
self, qubit_device_2_wires, tol, name, par, expected_output
):
"""Tests supported gates that act on two wires wires that are parameterized"""
"""Tests supported gates that act on two wires that are parameterized"""

op = getattr(qml.ops, name)

Expand Down

0 comments on commit 550ee8a

Please sign in to comment.