Commit e0539b12 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Adding EigenAccelerator that simulates QPU by simply creating unitary matrix...

Adding EigenAccelerator that simulates QPU by simply creating unitary matrix and operating on Accelerator state
parent 7a23d308
......@@ -33,7 +33,7 @@ cmake_minimum_required(VERSION 2.8)
set(CMAKE_DISABLE_IN_SOURCE_BUILDS ON)
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
set(CMAKE_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
message(STATUS "C++ version ${CXX_STANDARD} configured.")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
......
......@@ -29,5 +29,11 @@
#
#**********************************************************************************/
include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/accelerators)
include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/accelerators/eigenaccelerator)
include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tpls/eigen)
include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors)
include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors/impl)
include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/utils)
add_executable(teleport_scaffold teleport_scaffold.cpp)
target_link_libraries(teleport_scaffold xacc-scaffold ${Boost_LIBRARIES})
\ No newline at end of file
......@@ -28,17 +28,17 @@
* Initial API and implementation - Alex McCaskey
*
**********************************************************************************/
#include "Program.hpp"
#include "Qubits.hpp"
#include "XACC.hpp"
#include "EigenAccelerator.hpp"
/**
* FIXME For now, create a fake accelerator
* This will later come from QVM
*/
class IBM5Qubit: public xacc::Accelerator {
class IBM5Qubit: public xacc::quantum::QPUGate<5> {
public:
virtual AcceleratorType getType() {
return AcceleratorType::qpu_gate;
virtual xacc::AcceleratorType getType() {
return xacc::AcceleratorType::qpu_gate;
}
virtual std::vector<xacc::IRTransformation> getIRTransformations() {
std::vector<xacc::IRTransformation> v;
......@@ -77,10 +77,10 @@ const std::string src("__qpu__ teleport () {\n"
int main (int argc, char** argv) {
// Create a reference to the IBM5Qubit Accelerator
auto ibm_qpu = std::make_shared<IBM5Qubit>();
auto ibm_qpu = std::make_shared<xacc::quantum::EigenAccelerator<3>>();
// Allocate some qubits, give them a unique identifier...
auto qreg = ibm_qpu->allocate<xacc::quantum::Qubits<3>>("qreg");
auto qreg = ibm_qpu->allocate("qreg");
// Construct a new Program
xacc::Program quantumProgram(ibm_qpu, src);
......@@ -95,7 +95,8 @@ int main (int argc, char** argv) {
teleport();
// Get the execution result
auto bits = qreg.toBits();
qreg->printState(std::cout);
auto bits = qreg->toBits();
return 0;
}
......
......@@ -30,8 +30,9 @@
#**********************************************************************************/
include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensor)
include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tpls/eigen)
# Gather tests
file (GLOB test_files tests/*.cpp)
add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors/impl;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tpls/eigen" "${Boost_LIBRARIES}")
add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/eigenaccelerator;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors/impl;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tpls/eigen" "${Boost_LIBRARIES}")
......@@ -28,13 +28,56 @@
* Initial API and implementation - Alex McCaskey
*
**********************************************************************************/
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE FireTensorAcceleratorTester
#ifndef QUANTUM_GATE_ACCELERATORS_QPUGATE_HPP_
#define QUANTUM_GATE_ACCELERATORS_QPU_HPP_
#include <boost/test/included/unit_test.hpp>
#include "FireTensorAccelerator.hpp"
#include "Accelerator.hpp"
#include "Qubits.hpp"
namespace xacc {
namespace quantum {
BOOST_AUTO_TEST_CASE(checkConstruction) {
}
/**
*
*/
template<const int NQubits>
class QPUGate: virtual public Accelerator<Qubits<NQubits>> {
public:
/**
* This Accelerator models QPU Gate accelerators.
* @return
*/
virtual AcceleratorType getType() {
return AcceleratorType::qpu_gate;
}
/**
* We have no need to transform the IR for this Accelerator,
* so return an empty list
* @return
*/
virtual std::vector<xacc::IRTransformation> getIRTransformations() {
std::vector<xacc::IRTransformation> v;
return v;
}
virtual ~QPUGate() {}
protected:
/**
* This Accelerator can allocate any number of
* qubits (at a great computational cost...)
*
* @param N
* @return
*/
bool canAllocate(const int N) {
return N <= NQubits;
}
};
}
}
#endif
......@@ -3,29 +3,36 @@
#include "Accelerator.hpp"
#include <complex>
#include <Eigen/Dense>
namespace xacc {
namespace quantum {
using QubitState = std::vector<std::complex<double>>;
using QubitState = Eigen::VectorXcd;
/**
*
*/
template<const int NumberOfQubits>
class Qubits: public AcceleratorBits<NumberOfQubits> {
protected:
QubitState state;
public:
Qubits() :
state((int) std::pow(2, NumberOfQubits)) {
}
QubitState& getState() {
return state;
void applyUnitary(Eigen::MatrixXcd& U) {
state = U * state;
}
};
void printState(std::ostream& stream) {
stream << state << "\n";
}
};
}
}
#endif
......@@ -28,56 +28,59 @@
* Initial API and implementation - Alex McCaskey
*
**********************************************************************************/
#ifndef QUANTUM_GATE_ACCELERATORS_FIRETENSORACCELERATOR_HPP_
#define QUANTUM_GATE_ACCELERATORS_FIRETENSORACCELERATOR_HPP_
#ifndef QUANTUM_GATE_ACCELERATORS_EIGENACCELERATOR_HPP_
#define QUANTUM_GATE_ACCELERATORS_EIGENACCELERATOR_HPP_
#include "Accelerator.hpp"
#include "Tensor.hpp"
#include "Graph.hpp"
#include "QPUGate.hpp"
#include "QasmToGraph.hpp"
#include "GraphIR.hpp"
#include <unsupported/Eigen/KroneckerProduct>
namespace xacc {
namespace quantum {
using namespace fire;
double sqrt2 = std::sqrt(2.0);
using GraphType = qci::common::Graph<CircuitNode>;
using QuantumGraphIR = xacc::GraphIR<GraphType>;
/**
*
*/
class FireTensorAccelerator : public Accelerator {
template<const int NQubits>
class EigenAccelerator : public QPUGate<NQubits> {
public:
FireTensorAccelerator() {
Tensor<2> h(2,2), cnot(4,4);
h.setValues({{1.0/sqrt2,1.0/sqrt2},{1.0/sqrt2,-1.0/sqrt2}});
cnot.setValues({{1, 0, 0, 0},{0, 1, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}});
gates.emplace("h",h);
gates.emplace("cnot",cnot);
}
virtual AcceleratorType getType() {
return AcceleratorType::qpu_gate;
}
virtual std::vector<xacc::IRTransformation> getIRTransformations() {
std::vector<xacc::IRTransformation> v;
return v;
/**
* The constructor, create tensor gates
*/
EigenAccelerator() {
Eigen::MatrixXcd h(2,2), cnot(4,4), I(2,2), x(2,2);
h << 1.0/sqrt2,1.0/sqrt2, 1.0/sqrt2,-1.0/sqrt2;
cnot << 1, 0, 0, 0,0, 1, 0, 0,0, 0, 0, 1, 0, 0, 1, 0;
x << 0, 1, 1, 0;
I << 1,0,0,1;
gates.insert(std::map<std::string, Eigen::MatrixXcd>::value_type("h",h));
gates.insert(std::map<std::string, Eigen::MatrixXcd>::value_type("cnot",cnot));
gates.insert(std::map<std::string, Eigen::MatrixXcd>::value_type("I",I));
gates.insert(std::map<std::string, Eigen::MatrixXcd>::value_type("x",x));
}
/**
*
* @param ir
*/
virtual void execute(const std::shared_ptr<xacc::IR> ir) {
using GraphType = qci::common::Graph<CircuitNode>;
auto qubitsType = std::dynamic_pointer_cast<Qubits<NQubits>>(this->bits);
// Cast to a GraphIR, if we can...
auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir);
auto graphir = std::dynamic_pointer_cast<QuantumGraphIR>(ir);
if (!graphir) {
QCIError("Invalid IR - this Accelerator on accepts GraphIR<Graph<CircuitNode>>.");
QCIError("Invalid IR - this Accelerator only accepts GraphIR<Graph<CircuitNode>>.");
}
std::vector<CircuitNode> gateOperations;
// Get the Graph
std::vector<CircuitNode> gateOperations;
auto graph = graphir->getGraph();
int nNodes = graph.order(), layer = 1;
int finalLayer = graph.getVertexProperty<1>(nNodes - 1);
......@@ -88,6 +91,10 @@ public:
gateOperations.emplace_back(n);
}
Eigen::MatrixXcd U = Eigen::MatrixXcd::Identity(std::pow(2, NQubits),
std::pow(2, NQubits));
while (layer < finalLayer) {
std::vector<CircuitNode> currentLayerGates;
......@@ -95,32 +102,63 @@ public:
std::back_inserter(currentLayerGates),
[&](const CircuitNode& c) {return std::get<1>(c.properties) == layer;});
std::vector<Eigen::MatrixXcd> productList(NQubits);
for (int i = 0; i < NQubits; i++) {
productList[i] = gates["I"];
}
// Can parallize this...
for (auto n : currentLayerGates) {
auto gateName = std::get<0>(n.properties);
auto actingQubits = std::get<3>(n.properties);
}
if (gateName != "measure") {
auto gate = gates[gateName];
if (actingQubits.size() == 1) {
productList[actingQubits[0]] = gate;
} else if (actingQubits.size() == 2) {
productList[actingQubits[0]] = gate;
productList.erase(productList.begin() + actingQubits[1]);
} else {
QCIError("Can only simulate one and two qubit gates.");
}
} else {
// Setup measurement gate
}
// Create a total unitary for this layer of the circuit
Eigen::MatrixXcd result = productList[0];
for (int i = 1; i < productList.size(); i++) {
result = kroneckerProduct(result, productList[i]).eval();
}
assert(result.rows() == std::pow(2, NQubits) && result.cols() == std::pow(2,NQubits));
// Update the circuit unitary matrix
U = result * U;
}
layer++;
}
qubitsType->applyUnitary(U);
}
virtual ~FireTensorAccelerator() {
/**
* The destructor
*/
virtual ~EigenAccelerator() {
}
protected:
bool canAllocate(const int N) {
return true;
}
std::map<std::string, Tensor<2>> gates;
std::map<std::string, Eigen::MatrixXcd> gates;
};
}
}
#endif /* QUANTUM_GATE_ACCELERATORS_FIRETENSORACCELERATOR_HPP_ */
#endif
/***********************************************************************************
* 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 FireTensorAcceleratorTester
#include <memory>
#include <boost/test/included/unit_test.hpp>
#include "EigenAccelerator.hpp"
#include "GraphIR.hpp"
using namespace xacc::quantum;
BOOST_AUTO_TEST_CASE(checkConstruction) {
EigenAccelerator<3> acc;
auto qreg = acc.allocate("qreg");
// Create a graph IR modeling a
// quantum teleportation kernel
std::string irstr = "graph G {\n"
"{\nnode [shape=box style=filled]\n"
"0 [label=\"Gate=InitialState,Circuit Layer=0,Gate Vertex Id=0,Gate Acting Qubits=[0 1 2 3 4]\"];\n"
"1 [label=\"Gate=x,Circuit Layer=1,Gate Vertex Id=1,Gate Acting Qubits=[0]\"];\n"
"2 [label=\"Gate=h,Circuit Layer=1,Gate Vertex Id=2,Gate Acting Qubits=[1]\"];\n"
"3 [label=\"Gate=cnot,Circuit Layer=2,Gate Vertex Id=3,Gate Acting Qubits=[1 2]\"];\n"
"4 [label=\"Gate=cnot,Circuit Layer=3,Gate Vertex Id=4,Gate Acting Qubits=[0 1]\"];\n"
"5 [label=\"Gate=h,Circuit Layer=4,Gate Vertex Id=5,Gate Acting Qubits=[0]\"];\n"
"6 [label=\"Gate=measure,Circuit Layer=5,Gate Vertex Id=6,Gate Acting Qubits=[0]\"];\n"
"7 [label=\"Gate=measure,Circuit Layer=5,Gate Vertex Id=7,Gate Acting Qubits=[1]\"];\n"
"8 [label=\"Gate=h,Circuit Layer=6,Gate Vertex Id=8,Gate Acting Qubits=[2]\"];\n"
"9 [label=\"Gate=cnot,Circuit Layer=7,Gate Vertex Id=9,Gate Acting Qubits=[2 1]\"];\n"
"10 [label=\"Gate=h,Circuit Layer=8,Gate Vertex Id=10,Gate Acting Qubits=[2]\"];\n"
"11 [label=\"Gate=cnot,Circuit Layer=9,Gate Vertex Id=11,Gate Acting Qubits=[2 0]\"];\n"
"12 [label=\"Gate=FinalState,Circuit Layer=10,Gate Vertex Id=12,Gate Acting Qubits=[0 1 2 3 4]\"];\n"
"}\n"
"0--1 ;\n"
"0--2 ;\n"
"2--3 ;\n"
"0--3 ;\n"
"1--4 ;\n"
"3--4 ;\n"
"4--5 ;\n"
"5--6 ;\n"
"4--7 ;\n"
"3--8 ;\n"
"8--9 ;\n"
"7--9 ;\n"
"9--10 ;\n"
"10--11 ;\n"
"6--11 ;\n"
"11--12 ;\n"
"11--12 ;\n"
"9--12 ;\n"
"}";
std::istringstream iss(irstr);
auto graphir = std::make_shared<xacc::GraphIR<qci::common::Graph<CircuitNode>>>();
graphir->read(iss);
}
......@@ -44,5 +44,5 @@ install(TARGETS ${LIBRARY_NAME} DESTINATION lib)
# Gather tests
file (GLOB test_files tests/*.cpp)
add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/../utils" "${LIBRARY_NAME}")
add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_SOURCE_DIR}/quantum/gate/utils" "${LIBRARY_NAME}")
......@@ -40,26 +40,6 @@ namespace quantum {
void ScaffoldCompiler::modifySource() {
// Execute default QuantumCompiler method
auto qubitTypeStr = std::string("qbit");
auto nBits = this->hardware->getAllocationSize();
auto varName = this->hardware->getVariableName();
std::cout << "HELLO WORLD: " << nBits << ", " << varName << "\n";
std::string qubitAllocationSrc = qubitTypeStr + " " + varName + "["
+ std::to_string(nBits) + "];\n";
std::vector<std::string> srcLines;
boost::split(srcLines, this->kernelSource, boost::is_any_of("\n"));
// First line should be function __qpu__ call, next one
// is where we should put the qubit allocation src
srcLines.insert(srcLines.begin() + 1, qubitAllocationSrc);
// Merge all into new kernel source string
std::stringstream combine;
std::for_each(srcLines.begin(), srcLines.end(), [&](const std::string& elem) { combine << elem << "\n"; });
this->kernelSource = combine.str();
// Here we assume we've been given just
// the body of the quantum code, as part
// of an xacc __qpu__ kernel function.
......
......@@ -60,6 +60,14 @@ public:
*/
virtual std::shared_ptr<IR> compile();
/**
*
* @return
*/
virtual std::string getBitType() {
return "qbit";
}
/**
* This method is intended to modify the incoming
* source code to be compiled to be amenable to the
......
......@@ -41,49 +41,19 @@
using namespace qci::common;
using namespace xacc::quantum;
template<const int n>
class FakeAccelerator: public xacc::Accelerator {
public:
virtual int getAllocationSize() {
return n;
}
virtual const std::string getVariableName() {
return "qreg";
}
virtual AcceleratorType getType() {
return AcceleratorType::qpu_gate;
}
virtual std::vector<xacc::IRTransformation> getIRTransformations() {
std::vector<xacc::IRTransformation> v;
return v;
}
virtual void execute(const std::shared_ptr<xacc::IR> ir) {
}
virtual ~FakeAccelerator() {
}
protected:
bool canAllocate(const int N) {
return true;
}
};
BOOST_AUTO_TEST_CASE(checkSimpleCompile) {
using GraphType = Graph<CircuitNode>;
auto accelerator = std::make_shared<FakeAccelerator<2>>();
auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>("compiler", "scaffold");
BOOST_VERIFY(compiler);
const std::string src("__qpu__ eprCreation () {\n"
// " qbit qs[2];\n"
" qbit qreg[2];\n"
" H(qreg[0]);\n"
" CNOT(qreg[0],qreg[1]);\n"
"}\n");
auto ir = compiler->compile(src, accelerator);
auto ir = compiler->compile(src);
BOOST_VERIFY(ir);
auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir);
BOOST_VERIFY(graphir);
......@@ -101,7 +71,6 @@ BOOST_AUTO_TEST_CASE(checkSimpleCompile) {
BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) {
using GraphType = Graph<CircuitNode>;
auto accelerator = std::make_shared<FakeAccelerator<3>>();
auto compiler =
qci::common::AbstractFactory::createAndCast<xacc::ICompiler>(
......@@ -109,7 +78,7 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) {
BOOST_VERIFY(compiler);
const std::string src("__qpu__ teleport () {\n"
// " qbit q[3];\n"
" qbit qreg[3];\n"
" H(qreg[1]);\n"
" CNOT(qreg[1],qreg[2]);\n"
" CNOT(qreg[0],qreg[1]);\n"
......@@ -124,7 +93,7 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) {
" CNOT(qreg[2], qreg[0]);\n"
"}\n");
auto ir = compiler->compile(src, accelerator);
auto ir = compiler->compile(src);
BOOST_VERIFY(ir);
auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir);
BOOST_VERIFY(graphir);
......
......@@ -31,17 +31,14 @@
#ifndef XACC_XACC_HPP_
#define XACC_XACC_HPP_
#include <iostream>
#include <memory>
#include "Accelerator.hpp"
#include "Program.hpp"
#include "AbstractFactory.hpp"
namespace xacc {
std::vector<IRTransformation> getAcceleratorIndependentTransformations(
Accelerator::AcceleratorType& accType) {
std::vector<IRTransformation> transformations;
return transformations;
}
}
......