Commit 10a00204 authored by Adams, Austin Joel's avatar Adams, Austin Joel
Browse files

Add one-qubit IRTransformation for ion trap backend


Signed-off-by: Adams, Austin Joel's avatarAustin Adams <aja@gatech.edu>
parent c3faf15a
......@@ -15,6 +15,7 @@ set(LIBRARY_NAME xacc-iontrap)
file(GLOB SRC
*.cpp
decomp/*.cpp
transformations/*.cpp)
usfunctiongetresourcesource(TARGET ${LIBRARY_NAME} OUT SRC)
......@@ -24,6 +25,7 @@ add_library(${LIBRARY_NAME} SHARED ${SRC})
target_include_directories(${LIBRARY_NAME}
PUBLIC .
./decomp
./transformations
${CMAKE_SOURCE_DIR}/tpls/ensmallen
${CMAKE_SOURCE_DIR}/tpls/armadillo)
......
......@@ -15,6 +15,7 @@
#include "cppmicroservices/BundleActivator.h"
#include "cppmicroservices/BundleContext.h"
#include "cppmicroservices/ServiceProperties.h"
#include "IonTrapOneQubitPass.hpp"
#include "IonTrapTwoQubitPass.hpp"
using namespace cppmicroservices;
......@@ -26,6 +27,9 @@ public:
void Start(BundleContext context) {
auto twoQubitPass = std::make_shared<xacc::quantum::IonTrapTwoQubitPass>();
context.RegisterService<xacc::IRTransformation>(twoQubitPass);
auto oneQubitPass = std::make_shared<xacc::quantum::IonTrapOneQubitPass>();
context.RegisterService<xacc::IRTransformation>(oneQubitPass);
}
void Stop(BundleContext context) {}
......
/*******************************************************************************
* Copyright (c) 2021 UT-Battelle, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompanies this
* distribution. The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
* License is available at https://eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Austin Adams - initial implementation
*******************************************************************************/
#include <cassert>
#include "IonTrapDecomp.hpp"
namespace xacc {
namespace quantum {
std::string decompName(const Decomp decomp) {
switch (decomp) {
case Decomp::Exact:
return "exact";
case Decomp::RX:
return "Rx";
case Decomp::RZ:
return "Rz";
case Decomp::RZExact:
return "RzExact";
case Decomp::RZRX:
return "RzRx";
case Decomp::RZRZ:
return "RzRz";
default:
assert(0);
return "";
}
}
Decomp decompNextToTry(const Decomp decomp) {
switch (decomp) {
case Decomp::RX:
case Decomp::RZ:
case Decomp::RZExact:
return Decomp::Exact;
case Decomp::RZRX:
return Decomp::RX;
case Decomp::RZRZ:
return Decomp::RZ;
default:
// Exact should never call this function. If exact fails, we are
// in bad shape and should handle it differently
assert(0);
return Decomp::Exact;
}
}
bool decompShouldSkip(const Decomp decomp, const int rotations) {
// Rx(phi2).Rz(phi1) needs two angles. One can be 0, that's fine.
// Also, Rz(phi2).Rz(phi1) = Rz(phi2 + phi1) is really just 1 angle.
return (decomp == Decomp::RZRX && rotations == 1)
|| (decomp == Decomp::RZRZ && rotations == 2);
}
std::size_t decompFromRotationCount(const Decomp decomp) {
// The first 1 entry of the array of rotations is an Rz for
// Decomp::RZ{Exact,RX,RZ}, but in the case of plain
// old Decomp::{Exact,RX,RZ}, there are 0 such entries
return decomp != Decomp::Exact && decomp != Decomp::RX && decomp != Decomp::RZ;
}
std::size_t decompCount(const Decomp decomp) {
// The last 1 entry of the array of rotations is an Rx/Rz for
// Decomp::RX/RZ, but in the case of Decomp::Exact,
// there are 0 such entries
return decomp != Decomp::Exact && decomp != Decomp::RZExact;
}
bool decompShouldTrack(const Decomp decomp) {
// We only care about tracking Rx rotations (across XX gates)
return decomp == Decomp::RX || decomp == Decomp::RZRX;
}
arma::cx_mat decompFromMat(const Decomp decomp, const double phi) {
const auto i = std::complex<double>(0, 1);
if (decomp == Decomp::Exact || decomp == Decomp::RX || decomp == Decomp::RZ) {
return arma::eye<arma::cx_mat>(2,2);
} else if (decomp == Decomp::RZExact || decomp == Decomp::RZRX || decomp == Decomp::RZRZ) {
// Reuse RZ rotation code from decompMat()
return decompMat(Decomp::RZ, phi);
} else {
assert(0);
return {};
}
}
arma::cx_mat decompMat(const Decomp decomp, const double phi) {
const auto i = std::complex<double>(0, 1);
if (decomp == Decomp::Exact || decomp == Decomp::RZExact) {
return arma::eye<arma::cx_mat>(2,2);
} else if (decomp == Decomp::RX || decomp == Decomp::RZRX) {
arma::cx_mat rx({std::cos(phi/2.0), -i*std::sin(phi/2.0),
-i*std::sin(phi/2.0), std::cos(phi/2.0)});
rx.reshape(2, 2);
return rx;
} else if (decomp == Decomp::RZ || decomp == Decomp::RZRZ) {
arma::cx_mat rz({std::exp(-i*phi/2.0), 0,
0, std::exp(i*phi/2.0)});
rz.reshape(2, 2);
return rz;
} else {
assert(0);
return {};
}
}
} // namespace quantum
} // namespace xacc
/*******************************************************************************
* Copyright (c) 2021 UT-Battelle, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompanies this
* distribution. The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
* License is available at https://eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Alexander J. McCaskey - initial API and implementation
* Austin Adams - adapted for GTRI testbed
*******************************************************************************/
#ifndef QUANTUM_ACCELERATORS_IONTRAPDECOMP_HPP_
#define QUANTUM_ACCELERATORS_IONTRAPDECOMP_HPP_
#include <armadillo>
namespace xacc {
namespace quantum {
enum class Decomp : int { Exact, RX, RZ, RZExact, RZRX, RZRZ };
std::size_t decompFromRotationCount(const Decomp);
arma::cx_mat decompFromMat(const Decomp, const double);
arma::cx_mat decompMat(const Decomp, const double);
std::size_t decompCount(const Decomp);
Decomp decompNextToTry(const Decomp);
bool decompShouldSkip(const Decomp, const int);
std::string decompName(const Decomp);
bool decompShouldTrack(const Decomp);
} // namespace quantum
} // namespace xacc
#endif
This diff is collapsed.
/*******************************************************************************
* Copyright (c) 2021 UT-Battelle, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompanies this
* distribution. The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
* License is available at https://eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Alexander J. McCaskey - initial API and implementation
* Austin Adams - adapted for GTRI testbed
*******************************************************************************/
#ifndef QUANTUM_ACCELERATORS_IONTRAPOPTFUNCTION_HPP_
#define QUANTUM_ACCELERATORS_IONTRAPOPTFUNCTION_HPP_
#include <armadillo>
#include "IonTrapDecomp.hpp"
namespace xacc {
namespace quantum {
class IonTrapOptFunction {
public:
IonTrapOptFunction(Decomp decomp, const arma::cx_mat &goalUnitary)
: decomp(decomp), goal(goalUnitary) {}
double Evaluate(const arma::mat &phi);
double EvaluateWithGradient(const arma::mat &phi, arma::mat &g);
private:
typedef void (IonTrapOptFunction::*NablaMethod)(const arma::mat &, arma::cx_mat &);
const Decomp decomp;
const arma::cx_mat &goal;
std::complex<double> H(const arma::mat &phi);
void nablaHExact_1(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRx_1(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRz_1(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRzExact_1(const arma::mat &phi, arma::cx_mat &gh);
// No nablaHRzRx_1() because Rx(phi2).Rz(phi1) needs two angles. One can be 0, that's fine
void nablaHRzRz_1(const arma::mat &phi, arma::cx_mat &gh);
void nablaHExact_2(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRx_2(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRz_2(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRzExact_2(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRzRx_2(const arma::mat &phi, arma::cx_mat &gh);
// No nablaHRzRz_2() because Rz(phi2).Rz(phi1) = Rz(phi2 + phi1) is really just 1 angle
void nablaHExact_3(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRx_3(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRz_3(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRzExact_3(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRzRx_3(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRzRz_3(const arma::mat &phi, arma::cx_mat &gh);
void nablaHExact_4(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRx_4(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRz_4(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRzExact_4(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRzRx_4(const arma::mat &phi, arma::cx_mat &gh);
void nablaHRzRz_4(const arma::mat &phi, arma::cx_mat &gh);
};
} // namespace quantum
} // namespace xacc
#endif
......@@ -13,5 +13,8 @@
# Austin Adams - adaption for GTRI testbed
# *******************************************************************************/
add_xacc_test(IonTrapOneQubitPass)
target_link_libraries(IonTrapOneQubitPassTester xacc-iontrap)
add_xacc_test(IonTrapTwoQubitPass)
target_link_libraries(IonTrapTwoQubitPassTester xacc-iontrap)
/*******************************************************************************
* Copyright (c) 2019-2021 UT-Battelle, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompanies this
* distribution. The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
* License is available at https://eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Thien Nguyen - initial API and implementation
* Daniel Strano - adaption from Quantum++ to Qrack
* Austin Adams - adaption for GTRI testbed
*******************************************************************************/
#include <gtest/gtest.h>
#include "xacc.hpp"
#include "xacc_service.hpp"
#include "IonTrapOneQubitPass.hpp"
#include "IonTrapTwoQubitPass.hpp"
namespace {
// Give us some nice breathing room
const double ERR = 1e-4;
const double THRESHOLD = 1e-3;
}
//
// Single-qubit pass tests
//
TEST(IonTrapOneQubitPassTester, oneQubitPassExactX)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto ir = c->compile(R"(__qpu__ void my_x(qbit q) {
X(q[0]);
})")->getComposites()[0];
auto oneQubitPass = xacc::getService<xacc::IRTransformation>("iontrap-1q-pass");
oneQubitPass->apply(ir, nullptr, {{"threshold", THRESHOLD},
{"keep-trailing-gates", true},
{"keep-rz-before-meas", true},
{"keep-rx-before-xx", true},
{"keep-leading-rz", true}});
std::vector<std::size_t> bits0({0});
EXPECT_EQ(2, ir->nInstructions());
EXPECT_EQ("Rphi", ir->getInstruction(0)->name());
EXPECT_EQ(bits0, ir->getInstruction(0)->bits());
EXPECT_NEAR(0.0,
xacc::InstructionParameterToDouble(ir->getInstruction(0)->getParameter(0)),
ERR);
EXPECT_EQ("Rphi", ir->getInstruction(1)->name());
EXPECT_EQ(bits0, ir->getInstruction(1)->bits());
EXPECT_NEAR(0.0,
xacc::InstructionParameterToDouble(ir->getInstruction(1)->getParameter(0)),
ERR);
}
TEST(IonTrapOneQubitPassTester, oneQubitPassCommuteXAroundXX)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto ir = c->compile(R"(__qpu__ void xx_x_test(qbit q) {
X(q[0]);
X(q[1]);
XX(q[0], q[1], pi/4);
X(q[0]);
X(q[1]);
})")->getComposites()[0];
auto oneQubitPass = xacc::getService<xacc::IRTransformation>("iontrap-1q-pass");
oneQubitPass->apply(ir, nullptr, {{"threshold", THRESHOLD},
{"keep-trailing-gates", true},
{"keep-rz-before-meas", true},
{"keep-rx-before-xx", false},
{"keep-leading-rz", true}});
std::vector<std::size_t> bits01({0, 1});
EXPECT_EQ(1, ir->nInstructions());
EXPECT_EQ("XX", ir->getInstruction(0)->name());
EXPECT_EQ(bits01, ir->getInstruction(0)->bits());
EXPECT_NEAR(M_PI/4,
xacc::InstructionParameterToDouble(ir->getInstruction(0)->getParameter(0)),
ERR);
}
TEST(IonTrapOneQubitPassTester, oneQubitPassUpToZ)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto ir = c->compile(R"(__qpu__ void upToZ(qbit q) {
H(q[0]);
Measure(q[0]);
})")->getComposites()[0];
auto oneQubitPass = xacc::getService<xacc::IRTransformation>("iontrap-1q-pass");
oneQubitPass->apply(ir, nullptr, {{"threshold", THRESHOLD},
{"keep-trailing-gates", true},
{"keep-rz-before-meas", false},
{"keep-rx-before-xx", true},
{"keep-leading-rz", true}});
std::vector<std::size_t> bits0({0});
EXPECT_EQ(2, ir->nInstructions());
EXPECT_EQ("Rphi", ir->getInstruction(0)->name());
EXPECT_EQ(bits0, ir->getInstruction(0)->bits());
EXPECT_NEAR(-M_PI/2,
xacc::InstructionParameterToDouble(ir->getInstruction(0)->getParameter(0)),
ERR);
EXPECT_EQ("Measure", ir->getInstruction(1)->name());
EXPECT_EQ(bits0, ir->getInstruction(1)->bits());
}
TEST(IonTrapOneQubitPassTester, oneQubitPassFromZ)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto ir = c->compile(R"(__qpu__ void fromZ(qbit q) {
H(q[0]);
})")->getComposites()[0];
auto oneQubitPass = xacc::getService<xacc::IRTransformation>("iontrap-1q-pass");
oneQubitPass->apply(ir, nullptr, {{"threshold", THRESHOLD},
{"keep-trailing-gates", true},
{"keep-rz-before-meas", true},
{"keep-rx-before-xx", true},
{"keep-leading-rz", false}});
std::vector<std::size_t> bits0({0});
EXPECT_EQ(1, ir->nInstructions());
EXPECT_EQ("Rphi", ir->getInstruction(0)->name());
EXPECT_EQ(bits0, ir->getInstruction(0)->bits());
EXPECT_NEAR(M_PI/2,
xacc::InstructionParameterToDouble(ir->getInstruction(0)->getParameter(0)),
ERR);
}
TEST(IonTrapOneQubitPassTester, oneQubitPassFromZtoX)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto ir = c->compile(R"(__qpu__ void fromZtoX(qbit q) {
Y(q[0]);
XX(q[0], q[1], pi/4);
})")->getComposites()[0];
auto oneQubitPass = xacc::getService<xacc::IRTransformation>("iontrap-1q-pass");
oneQubitPass->apply(ir, nullptr, {{"threshold", THRESHOLD},
{"keep-trailing-gates", true},
{"keep-rz-before-meas", true},
{"keep-rx-before-xx", false},
{"keep-leading-rz", false}});
std::vector<std::size_t> bits0({0});
std::vector<std::size_t> bits01({0,1});
EXPECT_EQ(3, ir->nInstructions());
EXPECT_EQ("XX", ir->getInstruction(0)->name());
EXPECT_EQ(bits01, ir->getInstruction(0)->bits());
EXPECT_NEAR(M_PI/4,
xacc::InstructionParameterToDouble(ir->getInstruction(0)->getParameter(0)),
ERR);
EXPECT_EQ("Rphi", ir->getInstruction(1)->name());
EXPECT_EQ(bits0, ir->getInstruction(1)->bits());
EXPECT_NEAR(0,
xacc::InstructionParameterToDouble(ir->getInstruction(1)->getParameter(0)),
ERR);
EXPECT_EQ("Rphi", ir->getInstruction(2)->name());
EXPECT_EQ(bits0, ir->getInstruction(2)->bits());
EXPECT_NEAR(0,
xacc::InstructionParameterToDouble(ir->getInstruction(2)->getParameter(0)),
ERR);
}
TEST(IonTrapOneQubitPassTester, oneQubitPassFromZtoZ)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto ir = c->compile(R"(__qpu__ void fromZtoZ(qbit q) {
Z(q[0]);
})")->getComposites()[0];
auto oneQubitPass = xacc::getService<xacc::IRTransformation>("iontrap-1q-pass");
oneQubitPass->apply(ir, nullptr, {{"threshold", THRESHOLD},
{"keep-trailing-gates", true},
{"keep-rz-before-meas", false},
{"keep-rx-before-xx", true},
{"keep-leading-rz", false}});
std::vector<std::size_t> bits0({0});
EXPECT_EQ(0, ir->nInstructions());
}
TEST(IonTrapOneQubitPassTester, oneQubitPassTrailingGates)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto ir = c->compile(R"(__qpu__ void fromZtoZ(qbit q) {
XX(q[0], q[1], pi/4);
X(q[1]);
Y(q[0]);
Measure(q[0]);
})")->getComposites()[0];
auto oneQubitPass = xacc::getService<xacc::IRTransformation>("iontrap-1q-pass");
oneQubitPass->apply(ir, nullptr, {{"threshold", THRESHOLD},
{"keep-trailing-gates", false},
{"keep-rz-before-meas", true},
{"keep-rx-before-xx", true},
{"keep-leading-rz", true}});
std::vector<std::size_t> bits0({0});
std::vector<std::size_t> bits01({0,1});
EXPECT_EQ(4, ir->nInstructions());
EXPECT_EQ("XX", ir->getInstruction(0)->name());
EXPECT_EQ(bits01, ir->getInstruction(0)->bits());
EXPECT_NEAR(M_PI/4,
xacc::InstructionParameterToDouble(ir->getInstruction(0)->getParameter(0)),
ERR);
EXPECT_EQ("Rphi", ir->getInstruction(1)->name());
EXPECT_EQ(bits0, ir->getInstruction(1)->bits());
EXPECT_NEAR(M_PI/2,
xacc::InstructionParameterToDouble(ir->getInstruction(1)->getParameter(0)),
ERR);
EXPECT_EQ("Rphi", ir->getInstruction(2)->name());
EXPECT_EQ(bits0, ir->getInstruction(2)->bits());
EXPECT_NEAR(M_PI/2,
xacc::InstructionParameterToDouble(ir->getInstruction(2)->getParameter(0)),
ERR);
EXPECT_EQ("Measure", ir->getInstruction(3)->name());
EXPECT_EQ(bits0, ir->getInstruction(3)->bits());
}
TEST(IonTrapOneQubitPassTester, oneQubitPassIdentity)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto ir = c->compile(R"(__qpu__ void identityTest(qbit q) {
X(q[0]);
XX(q[0], q[1], pi/4);
X(q[0]);
H(q[1]);
H(q[1]);
})")->getComposites()[0];
auto oneQubitPass = xacc::getService<xacc::IRTransformation>("iontrap-1q-pass");
oneQubitPass->apply(ir, nullptr, {{"threshold", THRESHOLD},
{"keep-trailing-gates", true},
{"keep-rz-before-meas", true},
{"keep-rx-before-xx", false},
{"keep-leading-rz", true}});
std::vector<std::size_t> bits01({0,1});
EXPECT_EQ(1, ir->nInstructions());
EXPECT_EQ("XX", ir->getInstruction(0)->name());
EXPECT_EQ(bits01, ir->getInstruction(0)->bits());
EXPECT_NEAR(M_PI/4,
xacc::InstructionParameterToDouble(ir->getInstruction(0)->getParameter(0)),
ERR);
}
int main(int argc, char **argv) {
xacc::Initialize();
::testing::InitGoogleTest(&argc, argv);
const auto result = RUN_ALL_TESTS();
xacc::Finalize();
return result;
}
/*******************************************************************************
* Copyright (c) 2021 UT-Battelle, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompanies this
* distribution. The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
*License is available at https://eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Alexander J. McCaskey - initial API and implementation
* Austin Adams - adapted for GTRI testbed
*******************************************************************************/
#include <limits>
#include "xacc.hpp"
#include "xacc_service.hpp"
#include <ensmallen.hpp>
#include "IonTrapOneQubitPass.hpp"
#include "IonTrapOptFunction.hpp"
#include "Accelerator.hpp"
#include "CommonGates.hpp"
#include "GateFusion.hpp"