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 IsingXY #303

Merged
merged 19 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion pennylane_lightning/_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.24.0-dev14"
__version__ = "0.24.0-dev15"
4 changes: 4 additions & 0 deletions pennylane_lightning/src/gates/Constant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ namespace Pennylane::Gates::Constant {
std::pair<GateOperation, std::string_view>{GateOperation::CZ, "CZ"},
std::pair<GateOperation, std::string_view>{GateOperation::IsingXX,
"IsingXX"},
std::pair<GateOperation, std::string_view>{GateOperation::IsingXY,
"IsingXY"},
std::pair<GateOperation, std::string_view>{GateOperation::IsingYY,
"IsingYY"},
std::pair<GateOperation, std::string_view>{GateOperation::IsingZZ,
Expand Down Expand Up @@ -173,6 +175,7 @@ namespace Pennylane::Gates::Constant {
std::pair<GateOperation, size_t>{GateOperation::CZ, 2},
std::pair<GateOperation, size_t>{GateOperation::SWAP, 2},
std::pair<GateOperation, size_t>{GateOperation::IsingXX, 2},
std::pair<GateOperation, size_t>{GateOperation::IsingXY, 2},
std::pair<GateOperation, size_t>{GateOperation::IsingYY, 2},
std::pair<GateOperation, size_t>{GateOperation::IsingZZ, 2},
std::pair<GateOperation, size_t>{GateOperation::ControlledPhaseShift, 2},
Expand Down Expand Up @@ -242,6 +245,7 @@ namespace Pennylane::Gates::Constant {
std::pair<GateOperation, size_t>{GateOperation::CZ, 0},
std::pair<GateOperation, size_t>{GateOperation::SWAP, 0},
std::pair<GateOperation, size_t>{GateOperation::IsingXX, 1},
std::pair<GateOperation, size_t>{GateOperation::IsingXY, 1},
std::pair<GateOperation, size_t>{GateOperation::IsingYY, 1},
std::pair<GateOperation, size_t>{GateOperation::IsingZZ, 1},
std::pair<GateOperation, size_t>{GateOperation::ControlledPhaseShift, 1},
Expand Down
1 change: 1 addition & 0 deletions pennylane_lightning/src/gates/GateOperation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum class GateOperation : uint32_t {
CZ,
SWAP,
IsingXX,
IsingXY,
IsingYY,
IsingZZ,
ControlledPhaseShift,
Expand Down
6 changes: 6 additions & 0 deletions pennylane_lightning/src/gates/OpToMemberFuncPtr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ struct GateOpToMemberFuncPtr<PrecisionT, ParamT, GateImplementation,
&GateImplementation::template applyIsingXX<PrecisionT, ParamT>;
};
template <class PrecisionT, class ParamT, class GateImplementation>
struct GateOpToMemberFuncPtr<PrecisionT, ParamT, GateImplementation,
GateOperation::IsingXY> {
constexpr static auto value =
&GateImplementation::template applyIsingXY<PrecisionT, ParamT>;
};
template <class PrecisionT, class ParamT, class GateImplementation>
struct GateOpToMemberFuncPtr<PrecisionT, ParamT, GateImplementation,
GateOperation::IsingYY> {
constexpr static auto value =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
GateOperation::CRZ,
GateOperation::CRot,
GateOperation::IsingXX,
GateOperation::IsingXY,
GateOperation::IsingYY,
GateOperation::IsingZZ,
GateOperation::SingleExcitation,
Expand Down Expand Up @@ -762,6 +763,49 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
}
}

template <class PrecisionT, class ParamT>
static void
applyIsingXY(std::complex<PrecisionT> *arr, const size_t num_qubits,
const std::vector<size_t> &wires, bool inverse, ParamT angle) {
using ComplexPrecisionT = std::complex<PrecisionT>;
using std::imag;
using std::real;
PL_ASSERT(wires.size() == 2);

const size_t rev_wire0 = num_qubits - wires[1] - 1;
const size_t rev_wire1 = num_qubits - wires[0] - 1; // Control qubit

const size_t rev_wire0_shift = static_cast<size_t>(1U) << rev_wire0;
const size_t rev_wire1_shift = static_cast<size_t>(1U) << rev_wire1;

const auto [parity_high, parity_middle, parity_low] =
revWireParity(rev_wire0, rev_wire1);

const PrecisionT cr = std::cos(angle / 2);
const PrecisionT sj =
inverse ? -std::sin(angle / 2) : std::sin(angle / 2);

for (size_t k = 0; k < Util::exp2(num_qubits - 2); k++) {
const size_t i00 = ((k << 2U) & parity_high) |
((k << 1U) & parity_middle) | (k & parity_low);
const size_t i10 = i00 | rev_wire1_shift;
const size_t i01 = i00 | rev_wire0_shift;
const size_t i11 = i00 | rev_wire0_shift | rev_wire1_shift;

const ComplexPrecisionT v00 = arr[i00];
const ComplexPrecisionT v01 = arr[i01];
const ComplexPrecisionT v10 = arr[i10];
const ComplexPrecisionT v11 = arr[i11];

arr[i00] = ComplexPrecisionT{real(v00), imag(v00)};
arr[i01] = ComplexPrecisionT{cr * real(v01) - sj * imag(v10),
cr * imag(v01) + sj * real(v10)};
arr[i10] = ComplexPrecisionT{cr * real(v10) - sj * imag(v01),
cr * imag(v10) + sj * real(v01)};
arr[i11] = ComplexPrecisionT{real(v11), imag(v11)};
}
}

template <class PrecisionT, class ParamT>
static void applyIsingYY(std::complex<PrecisionT> *arr, size_t num_qubits,
const std::vector<size_t> &wires, bool inverse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class GateImplementationsPI : public PauliGenerator<GateImplementationsPI> {
GateOperation::CZ,
GateOperation::SWAP,
GateOperation::IsingXX,
GateOperation::IsingXY,
GateOperation::IsingYY,
GateOperation::IsingZZ,
GateOperation::CRX,
Expand Down Expand Up @@ -600,6 +601,35 @@ class GateImplementationsPI : public PauliGenerator<GateImplementationsPI> {
}
}

template <class PrecisionT, class ParamT = PrecisionT>
static void applyIsingXY(std::complex<PrecisionT> *arr, size_t num_qubits,
const std::vector<size_t> &wires, bool inverse,
ParamT angle) {
using ComplexPrecisionT = std::complex<PrecisionT>;
PL_ASSERT(wires.size() == 2);
const auto [indices, externalIndices] = GateIndices(wires, num_qubits);

const PrecisionT cr = std::cos(angle / 2);
const PrecisionT sj =
inverse ? -std::sin(angle / 2) : std::sin(angle / 2);

for (const size_t &externalIndex : externalIndices) {
std::complex<PrecisionT> *shiftedState = arr + externalIndex;

const auto v0 = shiftedState[indices[0]];
const auto v1 = shiftedState[indices[1]];
const auto v2 = shiftedState[indices[2]];
const auto v3 = shiftedState[indices[3]];

shiftedState[indices[0]] = ComplexPrecisionT{real(v0), imag(v0)};
shiftedState[indices[1]] = ComplexPrecisionT{
cr * real(v1) - sj * imag(v2), cr * imag(v1) + sj * real(v2)};
shiftedState[indices[2]] = ComplexPrecisionT{
cr * real(v2) - sj * imag(v1), cr * imag(v2) + sj * real(v1)};
shiftedState[indices[3]] = ComplexPrecisionT{real(v3), imag(v3)};
}
}

template <class PrecisionT, class ParamT = PrecisionT>
static void applyIsingYY(std::complex<PrecisionT> *arr, size_t num_qubits,
const std::vector<size_t> &wires, bool inverse,
Expand Down
3 changes: 3 additions & 0 deletions pennylane_lightning/src/simulator/KernelMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ int assignDefaultKernelsForGateOp() {
instance.assignKernelForOp(GateOperation::IsingXX, all_threading,
all_memory_model, all_qubit_numbers,
Gates::KernelType::LM);
instance.assignKernelForOp(GateOperation::IsingXY, all_threading,
all_memory_model, all_qubit_numbers,
Gates::KernelType::LM);
instance.assignKernelForOp(GateOperation::IsingYY, all_threading,
all_memory_model, all_qubit_numbers,
Gates::KernelType::LM);
Expand Down
147 changes: 147 additions & 0 deletions pennylane_lightning/src/tests/Test_GateImplementations_Param.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,153 @@ void testApplyIsingXX() {
}
PENNYLANE_RUN_TEST(IsingXX);

template <typename PrecisionT, typename ParamT, class GateImplementation>
void testApplyIsingXY() {
using ComplexPrecisionT = std::complex<PrecisionT>;
using std::cos;
using std::sin;

DYNAMIC_SECTION(GateImplementation::name
<< ", IsingXY0,1 |000> -> a|000> - "
<< PrecisionToName<PrecisionT>::value) {
const size_t num_qubits = 3;
const auto ini_st = createZeroState<PrecisionT>(num_qubits);
ParamT angle = 0.312;

const std::vector<ComplexPrecisionT> expected_results{
ComplexPrecisionT{1.0, 0.0}, ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0}, ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0}, ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0}, ComplexPrecisionT{0.0, 0.0},
};

auto st = ini_st;
GateImplementation::applyIsingXY(st.data(), num_qubits, {0, 1}, false,
angle);
REQUIRE(st == approx(expected_results).margin(1e-7));
}
DYNAMIC_SECTION(GateImplementation::name
<< ", IsingXY0,1 |100> -> a|100> + b|010> - "
<< PrecisionToName<PrecisionT>::value) {
const size_t num_qubits = 3;
const auto ini_st = createProductState<PrecisionT>("100");
ParamT angle = 0.312;

const std::vector<ComplexPrecisionT> expected_results{
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, sin(angle / 2)},
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{cos(angle / 2), 0.0},
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0},
};

auto st = ini_st;
GateImplementation::applyIsingXY(st.data(), num_qubits, {0, 1}, false,
angle);
REQUIRE(st == approx(expected_results).margin(1e-7));
}

DYNAMIC_SECTION(GateImplementation::name
<< ", IsingXY0,1 |010> -> a|010> + b|100> - "
<< PrecisionToName<PrecisionT>::value) {
const size_t num_qubits = 3;
const auto ini_st = createProductState<PrecisionT>("010");
ParamT angle = 0.312;

const std::vector<ComplexPrecisionT> expected_results{
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{cos(angle / 2), 0.0},
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, sin(angle / 2)},
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0},
};

auto st = ini_st;
GateImplementation::applyIsingXY(st.data(), num_qubits, {0, 1}, false,
angle);
REQUIRE(st == approx(expected_results).margin(1e-7));
}

DYNAMIC_SECTION(GateImplementation::name
<< ", IsingXY0,1 |110> -> a|110> - "
<< PrecisionToName<PrecisionT>::value) {
const size_t num_qubits = 3;
const auto ini_st = createProductState<PrecisionT>("110");
ParamT angle = 0.312;

const std::vector<ComplexPrecisionT> expected_results{
ComplexPrecisionT{0.0, 0.0}, ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0}, ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{0.0, 0.0}, ComplexPrecisionT{0.0, 0.0},
ComplexPrecisionT{1.0, 0.0}, ComplexPrecisionT{0.0, 0.0},
};

auto st = ini_st;
GateImplementation::applyIsingXY(st.data(), num_qubits, {0, 1}, false,
angle);
REQUIRE(st == approx(expected_results).margin(1e-7));
}

DYNAMIC_SECTION(GateImplementation::name
<< ", IsingXY0,1 - "
<< PrecisionToName<PrecisionT>::value) {
const size_t num_qubits = 4;

std::vector<ComplexPrecisionT> ini_st{
ComplexPrecisionT{0.267462841882, 0.010768564798},
ComplexPrecisionT{0.228575129706, 0.010564590956},
ComplexPrecisionT{0.099492749900, 0.260849823392},
ComplexPrecisionT{0.093690204310, 0.189847108173},
ComplexPrecisionT{0.033390732374, 0.203836830144},
ComplexPrecisionT{0.226979395737, 0.081852150975},
ComplexPrecisionT{0.031235505729, 0.176933497281},
ComplexPrecisionT{0.294287602843, 0.145156781198},
ComplexPrecisionT{0.152742706049, 0.111628061129},
ComplexPrecisionT{0.012553863703, 0.120027860480},
ComplexPrecisionT{0.237156555364, 0.154658769755},
ComplexPrecisionT{0.117001120872, 0.228059505033},
ComplexPrecisionT{0.041495873225, 0.065934827444},
ComplexPrecisionT{0.089653239407, 0.221581340372},
ComplexPrecisionT{0.217892322429, 0.291261296999},
ComplexPrecisionT{0.292993251871, 0.186570798697},
};

const std::vector<size_t> wires = {0, 1};
const ParamT angle = 0.312;

std::vector<ComplexPrecisionT> expected{
ComplexPrecisionT{0.267462849617, 0.010768564418},
ComplexPrecisionT{0.228575125337, 0.010564590804},
ComplexPrecisionT{0.099492751062, 0.260849833488},
ComplexPrecisionT{0.093690201640, 0.189847111702},
ComplexPrecisionT{0.015641822883, 0.225092900621},
ComplexPrecisionT{0.205574608177, 0.082808663337},
ComplexPrecisionT{0.006827173322, 0.211631480575},
ComplexPrecisionT{0.255280800811, 0.161572331669},
ComplexPrecisionT{0.119218164572, 0.115460377284},
ComplexPrecisionT{-0.000315789761, 0.153835664378},
ComplexPrecisionT{0.206786872079, 0.157633689097},
ComplexPrecisionT{0.093027614553, 0.271012980118},
ComplexPrecisionT{0.041495874524, 0.065934829414},
ComplexPrecisionT{0.089653238654, 0.221581339836},
ComplexPrecisionT{0.217892318964, 0.291261285543},
ComplexPrecisionT{0.292993247509, 0.186570793390},
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this the result from default.qubit?

Copy link
Member Author

Choose a reason for hiding this comment

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

Is this the result from default.qubit?

Yes


auto st = ini_st;
GateImplementation::applyIsingXY(st.data(), num_qubits, wires, false,
angle);
REQUIRE(st == approx(expected).margin(1e-5));
}
}
PENNYLANE_RUN_TEST(IsingXY);

template <typename PrecisionT, typename ParamT, class GateImplementation>
void testApplyIsingYY() {
using ComplexPrecisionT = std::complex<PrecisionT>;
Expand Down
1 change: 1 addition & 0 deletions pennylane_lightning/src/tests/Test_OpToMemberFuncPtr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ class DummyImplementation {
PENNYLANE_TESTS_DEFINE_GATE_OP(SWAP, 0)
PENNYLANE_TESTS_DEFINE_GATE_OP(ControlledPhaseShift, 1)
PENNYLANE_TESTS_DEFINE_GATE_OP(IsingXX, 1)
PENNYLANE_TESTS_DEFINE_GATE_OP(IsingXY, 1)
PENNYLANE_TESTS_DEFINE_GATE_OP(IsingYY, 1)
PENNYLANE_TESTS_DEFINE_GATE_OP(IsingZZ, 1)
PENNYLANE_TESTS_DEFINE_GATE_OP(CRX, 1)
Expand Down
7 changes: 7 additions & 0 deletions tests/test_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,13 @@ def test_apply_operation_preserve_pointer_single_wire_with_parameters(
[-0.5j, 0.5, -0.5j, 0.5],
[math.pi / 2],
),
(qml.IsingXY, [1, 0, 0, 0], [1, 0, 0, 0], [math.pi / 2]),
(
qml.IsingXY,
[0, 1 / math.sqrt(2), 0, 1 / math.sqrt(2)],
[0, 0.5, 0.5j, 1 / math.sqrt(2)],
[math.pi / 2],
),
(qml.IsingYY, [1, 0, 0, 0], [1 / math.sqrt(2), 0, 0, 1j / math.sqrt(2)], [math.pi / 2]),
(
qml.IsingYY,
Expand Down
1 change: 1 addition & 0 deletions tests/test_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def op(op_name):
"CSWAP": qml.CSWAP(wires=[0, 1, 2]),
"PauliRot": qml.PauliRot(0.123, "Y", wires=0),
"IsingXX": qml.IsingXX(0.123, wires=[0, 1]),
"IsingXY": qml.IsingXY(0.123, wires=[0, 1]),
"IsingYY": qml.IsingYY(0.123, wires=[0, 1]),
"IsingZZ": qml.IsingZZ(0.123, wires=[0, 1]),
"Identity": qml.Identity(wires=0),
Expand Down