Commit 1f97ecdb authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Added ir transformation to handle ibm cnot connectivity

parent ce69d956
......@@ -40,6 +40,7 @@
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
#include "IBMAccelerator.hpp"
#include "IBMIRTransformation.hpp"
using namespace utility;
using namespace web;
......@@ -96,6 +97,30 @@ bool IBMAccelerator::isValidBufferSize(const int NBits) {
return NBits > 0 && NBits < 31;
}
std::vector<std::shared_ptr<IRTransformation>> IBMAccelerator::getIRTransformations() {
std::vector<std::shared_ptr<IRTransformation>> transformations;
std::string backendName = "ibmqx_qasm_simulator";
if (xacc::optionExists("ibm-backend")) {
backendName = xacc::getOption("ibm-backend");
}
if (!availableBackends.count(backendName)) {
XACCError(backendName + " is not available.");
}
auto backend = availableBackends[backendName];
if (!backend.couplers.empty()) {
auto transform = std::make_shared<IBMIRTransformation>(
backend.couplers);
transformations.push_back(transform);
}
return transformations;
}
void IBMAccelerator::initialize() {
std::string jsonStr = "", apiKey = "";
auto options = RuntimeOptions::instance();
......@@ -143,7 +168,7 @@ void IBMAccelerator::initialize() {
if (!isSimulator) {
auto couplers = b["couplingMap"].GetArray();
for (int j = 0; j < couplers.Size(); j++) {
backend.edges.push_back(
backend.couplers.push_back(
std::make_pair(couplers[j][0].GetInt(),
couplers[j][1].GetInt()));
}
......@@ -286,7 +311,6 @@ void IBMAccelerator::execute(std::shared_ptr<AcceleratorBuffer> buffer,
}
std::shared_ptr<AcceleratorGraph> IBMAccelerator::getAcceleratorConnectivity() {
auto options = RuntimeOptions::instance();
std::string backendName = "ibmqx_qasm_simulator";
if (xacc::optionExists("ibm-backend")) {
......@@ -300,8 +324,8 @@ std::shared_ptr<AcceleratorGraph> IBMAccelerator::getAcceleratorConnectivity() {
auto backend = availableBackends[backendName];
auto graph = std::make_shared<AcceleratorGraph>(backend.nQubits);
if (!backend.edges.empty()) {
for (auto es : backend.edges) {
if (!backend.couplers.empty()) {
for (auto es : backend.couplers) {
graph->addEdge(es.first, es.second);
}
} else {
......
......@@ -53,7 +53,7 @@ struct IBMBackend {
std::string name;
std::string description;
int nQubits;
std::vector<std::pair<int,int>> edges;
std::vector<std::pair<int,int>> couplers;
};
/**
......@@ -117,10 +117,7 @@ public:
* so return an empty list, for now.
* @return
*/
virtual std::vector<std::shared_ptr<IRTransformation>> getIRTransformations() {
std::vector<std::shared_ptr<IRTransformation>> v;
return v;
}
virtual std::vector<std::shared_ptr<IRTransformation>> getIRTransformations();
/**
* Return all relevant IBMAccelerator runtime options.
......
#include "IBMIRTransformation.hpp"
namespace xacc {
namespace quantum {
std::shared_ptr<IR> IBMIRTransformation::transform(std::shared_ptr<IR> ir) {
XACCInfo("Executing IBM IR Transformation - Modifying CNOT connectivity.");
auto newir = std::make_shared<GateQIR>();
for (auto kernel : ir->getKernels()) {
currentKernelInstructionIdx = 0;
InstructionIterator it(kernel);
while (it.hasNext()) {
// Get the next node in the tree
auto nextInst = it.next();
if (!nextInst->isComposite() && nextInst->isEnabled()) {
nextInst->accept(this);
if (!nextInst->isEnabled() && "CNOT" == nextInst->getName()) {
kernel->removeInstruction(currentKernelInstructionIdx);
int count = 0;
for (auto inst : newInstructions) {
kernel->insertInstruction(
currentKernelInstructionIdx + count, inst);
count++;
}
currentKernelInstructionIdx += count - 1;
}
newInstructions.clear();
currentKernelInstructionIdx++;
}
}
newir->addKernel(kernel);
}
return newir;
}
void IBMIRTransformation::visit(CNOT& cnot) {
auto source = cnot.bits()[0];
auto target = cnot.bits()[1];
if (!isCouplingAvailable(source, target)) {
auto gateRegistry = GateInstructionRegistry::instance();
// Disable this cnot
cnot.disable();
// Here I know that this cnot is at
// the currentKernelInstructionIdx, so I want
// to insert 2 Hadamards, a reversed cnot, then 2 hadamards
auto h0 = gateRegistry->create("H", std::vector<int> { source });
auto h1 = gateRegistry->create("H", std::vector<int> { target });
auto revCnot = gateRegistry->create("CNOT", std::vector<int> { target,
source });
newInstructions.push_back(h0);
newInstructions.push_back(h1);
newInstructions.push_back(revCnot);
newInstructions.push_back(h0);
newInstructions.push_back(h1);
}
}
bool IBMIRTransformation::isCouplingAvailable(const int src, const int tgt) {
return tgt == _couplers[src].first || tgt == _couplers[src].second;
}
}
}
#ifndef QUANTUM_GATE_IR_TRANSFORMATIONS_SWAPINSERTIONIRTRANSFORMATION_HPP_
#define QUANTUM_GATE_IR_TRANSFORMATIONS_SWAPINSERTIONIRTRANSFORMATION_HPP_
#ifndef QUANTUM_GATE_ACCELERATORS_IBMIRTransformation_HPP_
#define QUANTUM_GATE_ACCELERATORS_IBMIRTransformation_HPP_
#include "Accelerator.hpp"
#include "IRTransformation.hpp"
#include "GateQIR.hpp"
#include "CNOT.hpp"
namespace xacc {
namespace quantum {
class SwapInsertionIRTransformation : public IRTransformation {
class IBMIRTransformation: public IRTransformation,
public BaseInstructionVisitor,
public InstructionVisitor<CNOT> {
protected:
std::shared_ptr<AcceleratorGraph> graph;
std::vector<std::pair<int, int>> _couplers;
int currentKernelInstructionIdx;
std::vector<std::shared_ptr<Instruction>> newInstructions;
bool isCouplingAvailable(const int src, const int tgt);
public:
SwapInsertionIRTransformation(std::shared_ptr<AcceleratorGraph> g) :graph(g) {}
IBMIRTransformation(std::vector<std::pair<int, int>> couplers) :
_couplers(couplers), currentKernelInstructionIdx(0) {
}
virtual std::shared_ptr<IR> transform(std::shared_ptr<IR> ir);
void visit(CNOT& cnot);
virtual const std::string name() const {
return "swap-insertion";
return "ibm-ir-transformations";
}
virtual const std::string description() const {
......
/***********************************************************************************
* Copyright (c) 2016, UT-Battelle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the xacc nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* Initial API and implementation - Alex McCaskey
*
**********************************************************************************/
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE SwapInsertionIRTransformationTester
#include <boost/test/included/unit_test.hpp>
#include "IBMIRTransformation.hpp"
using namespace xacc;
using namespace xacc::quantum;
BOOST_AUTO_TEST_CASE(checkCreation) {
std::vector<std::pair<int,int>> couplers {{0,1},{0,2},{1,2},{2,3},{2,4},{3,4}};
IBMIRTransformation t(couplers);
auto f = std::make_shared<GateFunction>("foo");
auto x = std::make_shared<X>(0);
auto h = std::make_shared<Hadamard>(1);
auto cn0 = std::make_shared<CNOT>(1, 2);
auto cn1 = std::make_shared<CNOT>(2, 3);
auto h2 = std::make_shared<Hadamard>(0);
auto m0 = std::make_shared<Measure>(0, 0);
auto m1 = std::make_shared<Measure>(1,1);
auto m2 = std::make_shared<Measure>(2,2);
auto cn2 = std::make_shared<CNOT>(2, 0);
f->addInstruction(x);
f->addInstruction(h);
f->addInstruction(cn0);
f->addInstruction(cn1);
f->addInstruction(h2);
f->addInstruction(cn2);
f->addInstruction(m0);
f->addInstruction(m1);
f->addInstruction(m2);
auto ir = std::make_shared<GateQIR>();
ir->addKernel(f);
auto newir = t.transform(ir);
std::stringstream ss;
newir->persist(ss);
const std::string expected = R"expected({
"kernels": [
{
"function": "foo",
"instructions": [
{
"gate": "X",
"enabled": true,
"qubits": [
0
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
1
]
},
{
"gate": "CNOT",
"enabled": true,
"qubits": [
1,
2
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
2
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
3
]
},
{
"gate": "CNOT",
"enabled": true,
"qubits": [
3,
2
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
2
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
3
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
0
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
2
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
0
]
},
{
"gate": "CNOT",
"enabled": true,
"qubits": [
0,
2
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
2
]
},
{
"gate": "H",
"enabled": true,
"qubits": [
0
]
},
{
"gate": "Measure",
"enabled": true,
"qubits": [
0
],
"classicalBitIdx": 0
},
{
"gate": "Measure",
"enabled": true,
"qubits": [
1
],
"classicalBitIdx": 1
},
{
"gate": "Measure",
"enabled": true,
"qubits": [
2
],
"classicalBitIdx": 2
}
]
}
]
})expected";
BOOST_VERIFY(expected == ss.str());
}
......@@ -325,8 +325,8 @@ public:
std::stringstream ss;
ss << rZGate.getParameter(0);
double angle = std::stod(ss.str());//boost::get<double>(rZGate.getParameter(0));
auto matElement11 = std::exp(-1.0 * i * angle);
auto matElement12 = std::exp(i * angle);
auto matElement11 = std::exp(-0.5 * i * angle);
auto matElement12 = std::exp(0.5 * i * angle);
Eigen::MatrixXcd rz(2,2);
rz << matElement11, 0.0, 0.0, matElement12;
......
......@@ -78,6 +78,10 @@ public:
functionName(name), parameters(params) {
}
GateFunction(const GateFunction& other) :
functionName(other.functionName), parameters(other.parameters) {
}
virtual const int nInstructions() {
return instructions.size();
}
......
#include "SwapInsertionIRTransformation.hpp"
namespace xacc {
namespace quantum {
std::shared_ptr<IR> SwapInsertionIRTransformation::transform(std::shared_ptr<IR> ir) {
auto newir = std::make_shared<GateQIR>();
for (auto kernel : ir->getKernels()) {
for (auto inst : kernel->getInstructions()) {
auto qbits = inst->bits();
// If we have 2 qubit gate that does not have a corresponding
// connection in the hardware, then we need to add swaps
if (qbits.size() == 2 && !graph->edgeExists(qbits[0], qbits[1])) {
std::vector<int> paths;
std::vector<double> distances;
graph->computeShortestPath(qbits[0], distances, paths);
}
}
}
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment