Commit 5156d6a9 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

starting on readout error correction IRPreprocessor



Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent fb1967d1
...@@ -41,6 +41,10 @@ public: ...@@ -41,6 +41,10 @@ public:
return; return;
} }
virtual const int maxBit() {
return 0;
}
/** /**
* Create this IR instance from the given input * Create this IR instance from the given input
* stream. * stream.
......
...@@ -63,6 +63,11 @@ public: ...@@ -63,6 +63,11 @@ public:
instructions.remove(getInstruction(idx)); instructions.remove(getInstruction(idx));
} }
virtual const std::string getTag() {
return "";
}
/** /**
* Add an instruction to this quantum * Add an instruction to this quantum
* intermediate representation. * intermediate representation.
......
...@@ -98,7 +98,10 @@ public: ...@@ -98,7 +98,10 @@ public:
virtual const std::string getName() { virtual const std::string getName() {
return "dw-qmi"; return "dw-qmi";
} }
;
virtual const std::string getTag() {
return "";
}
/** /**
* Persist this Instruction to an assembly-like * Persist this Instruction to an assembly-like
......
...@@ -21,9 +21,10 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/compiler) ...@@ -21,9 +21,10 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/compiler)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ir/instructions) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ir/instructions)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ir/algorithms) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ir/algorithms)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ir/transformations) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ir/transformations)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/accelerator)
file (GLOB_RECURSE HEADERS *.hpp) file (GLOB_RECURSE HEADERS *.hpp)
file (GLOB SRC *.cpp compiler/*.cpp ir/*.cpp ir/instructions/*.cpp utils/*.cpp ir/algorithms/*.cpp ir/transformations/*.cpp) file (GLOB SRC *.cpp accelerator/*.cpp compiler/*.cpp ir/*.cpp ir/instructions/*.cpp utils/*.cpp ir/algorithms/*.cpp ir/transformations/*.cpp)
# Set up dependencies to resources to track changes # Set up dependencies to resources to track changes
usFunctionGetResourceSource(TARGET ${LIBRARY_NAME} OUT SRC) usFunctionGetResourceSource(TARGET ${LIBRARY_NAME} OUT SRC)
......
/*******************************************************************************
* Copyright (c) 2017 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
*******************************************************************************/
#include "ReadoutErrorAcceleratorBufferPostprocessor.hpp"
#include <boost/algorithm/string.hpp>
#include "XACC.hpp"
namespace xacc {
namespace quantum {
std::vector<std::shared_ptr<AcceleratorBuffer>> ReadoutErrorAcceleratorBufferPostprocessor::process(
std::vector<std::shared_ptr<AcceleratorBuffer>> buffers) {
// Goal here is to get all ap01, ap10, ..., and fix all expectation values
int nQubits = ir.maxBit() + 1;
std::string zeroStr = "";
for (int i = 0; i < nQubits; i++) zeroStr += "0";
std::map<std::string, double> errorRates;
for (auto& kv : measurements) {
auto kernelIdx = kv.second;
auto localBitStr = zeroStr;
std::stringstream s;
s << kv.first[1] << kv.first[2];
if (boost::contains(s.str(), "01")) {
auto kernel = ir.getKernels()[kernelIdx];
auto bit = kernel->getInstruction(0)->bits()[0];
localBitStr[nQubits - bit - 1] = '1';
}
std::cout << "HI: " << kv.first << ", " << kv.second << ", " << localBitStr << "\n";
// get bit string from
auto prob = buffers[kv.second]->computeMeasurementProbability(localBitStr);
errorRates.insert({kv.first, std::isnan(prob) ? 0.0 : prob});
}
for (auto& kv : errorRates) {
std::stringstream s, s2;
s2 << kv.first[1] << kv.first[2];
s << kv.first[0]
<< (s2.str() == "01" ?
" probability expected 0 but got 1 error rate = " :
" probability expected 1 but got 0 error rate = ");
xacc::info("Qubit " + s.str() + std::to_string(kv.second));
}
// Return new AcceleratorBuffers subtype, StaticExpValAcceleratorBuffer that has static
// constant fixed expectation value from the calculation
return std::vector<std::shared_ptr<AcceleratorBuffer>>{};
}
}
}
/*******************************************************************************
* Copyright (c) 2018 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
*******************************************************************************/
#ifndef QUANTUM_GATE_ACCELERATOR_READOUTERRORACCELERATORBUFFERPOSTPROCESSOR_HPP_
#define QUANTUM_GATE_ACCELERATOR_READOUTERRORACCELERATORBUFFERPOSTPROCESSOR_HPP_
#include "IR.hpp"
#include "AcceleratorBufferPostprocessor.hpp"
namespace xacc {
namespace quantum {
class StaticExpectationValueBuffer : public AcceleratorBuffer {
protected:
double expectationValue = 0.0;
public:
StaticExpectationValueBuffer(const std::string& name, const int nBits,
const double e) :
AcceleratorBuffer(name, nBits), expectationValue(e) {
}
virtual const double getExpectationValueZ() {
return expectationValue;
}
};
class ReadoutErrorAcceleratorBufferPostprocessor : public AcceleratorBufferPostprocessor {
protected:
std::map<std::string, int> measurements;
std::map<std::string, int> extraKernels;
IR& ir;
public:
ReadoutErrorAcceleratorBufferPostprocessor(IR& i,
std::map<std::string, int> extraKernelIndexMap,
std::map<std::string, int> measurementIndexMap) : ir(i),
extraKernels(extraKernelIndexMap), measurements(measurementIndexMap) {
}
virtual std::vector<std::shared_ptr<AcceleratorBuffer>> process(std::vector<std::shared_ptr<AcceleratorBuffer>> buffers);
};
}
}
#endif
...@@ -38,6 +38,8 @@ protected: ...@@ -38,6 +38,8 @@ protected:
std::vector<InstructionParameter> parameters; std::vector<InstructionParameter> parameters;
std::string tag = "";
/** /**
* Map of Instruction Index to ( Instruction's Runtime Parameter Index, Dependent Variable name) * Map of Instruction Index to ( Instruction's Runtime Parameter Index, Dependent Variable name)
*/ */
...@@ -60,10 +62,23 @@ public: ...@@ -60,10 +62,23 @@ public:
functionName(name), parameters(params) { functionName(name), parameters(params) {
} }
GateFunction(const std::string& name, const std::string& _tag) :
functionName(name), parameters(
std::vector<InstructionParameter> { }), tag(_tag) {
}
GateFunction(const std::string& name, const std::string& _tag,
std::vector<InstructionParameter> params) :
functionName(name), parameters(params), tag(_tag) {
}
GateFunction(const GateFunction& other) : GateFunction(const GateFunction& other) :
functionName(other.functionName), parameters(other.parameters) { functionName(other.functionName), parameters(other.parameters) {
} }
virtual const std::string getTag() {
return tag;
}
virtual const int nInstructions() { virtual const int nInstructions() {
return instructions.size(); return instructions.size();
} }
......
...@@ -87,6 +87,10 @@ public: ...@@ -87,6 +87,10 @@ public:
return qbits; return qbits;
} }
virtual const std::string getTag() {
return "";
}
/** /**
* Return this instruction's assembly-like string * Return this instruction's assembly-like string
* representation. * representation.
......
...@@ -79,6 +79,20 @@ public: ...@@ -79,6 +79,20 @@ public:
*/ */
virtual void generateGraph(const std::string& kernelName); virtual void generateGraph(const std::string& kernelName);
virtual const int maxBit() {
int maxBit = 0;
for (auto k : kernels) {
for (auto inst : k->getInstructions()) {
for (auto b : inst->bits()) {
if (b > maxBit) {
maxBit = b;
}
}
}
}
return maxBit;
}
/** /**
* Add a quantum function to this intermediate representation. * Add a quantum function to this intermediate representation.
* @param kernel * @param kernel
......
/*******************************************************************************
* Copyright (c) 2018 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
*******************************************************************************/
#ifndef QUANTUM_GATE_IR_READOUTERRORIRPREPROCESSOR_HPP_
#define QUANTUM_GATE_IR_READOUTERRORIRPREPROCESSOR_HPP_
#include "IRPreprocessor.hpp"
namespace xacc {
namespace quantum {
class QubitMapIRPreprocessor : public IRPreprocessor {
public:
virtual std::shared_ptr<AcceleratorBufferPostprocessor> process(IR& ir) {}
};
}
}
#endif /* QUANTUM_GATE_IR_READOUTERRORIRPREPROCESSOR_HPP_ */
/*******************************************************************************
* Copyright (c) 2018 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
*******************************************************************************/
#include "ReadoutErrorIRPreprocessor.hpp"
#include "XACC.hpp"
#include "GateFunction.hpp"
#include "GateInstruction.hpp"
#include "CountGatesOfTypeVisitor.hpp"
#include "Measure.hpp"
#include <boost/math/constants/constants.hpp>
#include "ReadoutErrorAcceleratorBufferPostprocessor.hpp"
namespace xacc {
namespace quantum {
std::shared_ptr<AcceleratorBufferPostprocessor> ReadoutErrorIRPreprocessor::process(IR& ir) {
// Get number of qubits, add 2*nqubit measurement kernels, add readout-error tag to each
int nQubits = ir.maxBit() + 1;
auto gateRegistry = GateInstructionRegistry::instance();
// Search IR Functions and construct Pauli Term strings, then add any Pauli that is not there
std::vector<std::string> pauliTerms;
for (auto kernel : ir.getKernels()) {
CountGatesOfTypeVisitor<Measure> v(kernel);
bool allZTerm = false;
if (kernel->nInstructions() == v.countGates()) {
allZTerm = true;
}
std::string pauliTerm = "";
for (auto inst : kernel->getInstructions()) {
auto bit = inst->bits()[0];
if (allZTerm) {
pauliTerm = "Z" + std::to_string(bit) + " " + pauliTerm;
continue;
}
if (inst->getName() == "H") {
pauliTerm = "X" + std::to_string(bit) + " " + pauliTerm;
} else if (inst->getName() == "Rx") {
pauliTerm = "Y" + std::to_string(bit) + " " + pauliTerm;
} else if (inst->getName() == "Measure") {
// do nothing
continue;
} else {
xacc::error("ReadoutErrorIRPreprocessor only can be "
"applied to kernels generated from a Pauli "
"Hamiltonian, cannot have " + inst->getName() + " gate");
}
}
boost::trim(pauliTerm);
pauliTerms.push_back(pauliTerm);
}
std::vector<std::string> extraKernelsNeeded;
for (auto t : pauliTerms) {
std::vector<std::string> ops;
boost::split(ops, t, boost::is_any_of(" "));
if (ops.size() > 1) {
for (auto o : ops) {
if (std::find(pauliTerms.begin(), pauliTerms.end(), o) == pauliTerms.end()) {
extraKernelsNeeded.push_back(o);
}
}
}
}
std::sort( extraKernelsNeeded.begin(), extraKernelsNeeded.end() );
extraKernelsNeeded.erase( std::unique( extraKernelsNeeded.begin(), extraKernelsNeeded.end() ), extraKernelsNeeded.end() );
std::map<std::string, int> extraKernelsMap, measureMap;
for (auto o : extraKernelsNeeded) {
int nKernels = ir.getKernels().size();
auto extraKernel = std::make_shared<GateFunction>(o, "readout-error-extra");
std::stringstream sg, sb;
sg << o[0];
sb << o[1];
auto gate = sg.str();
auto bit = std::stoi(sb.str());
if (gate == "X") {
auto h = gateRegistry->create("H", std::vector<int>{bit});
extraKernel->addInstruction(h);
} else if (gate == "Y") {
auto rx = gateRegistry->create("Rx", std::vector<int>{bit});
InstructionParameter p(boost::math::constants::pi<double>() / 2.0);
rx->setParameter(0,p);
extraKernel->addInstruction(rx);
}
auto meas = gateRegistry->create("Measure", std::vector<int> { bit });
InstructionParameter m(0);
meas->setParameter(0, m);
extraKernel->addInstruction(meas);
ir.addKernel(extraKernel);
extraKernelsMap.insert({o, nKernels});
}
int nKernels = ir.getKernels().size();
int qbit = 0;
for (int i = 0; i < 2*nQubits; i+=2) {
int nKernels = ir.getKernels().size();
auto f01 = std::make_shared<GateFunction>(
"measure0_qubit_" + std::to_string(qbit), "readout-error");
auto meas01 = gateRegistry->create("Measure", std::vector<int>{qbit});
InstructionParameter p(0);
meas01->setParameter(0,p);
f01->addInstruction(meas01);
auto f10 = std::make_shared<GateFunction>(
"measure1_qubit_" + std::to_string(qbit), "readout-error");
auto x = gateRegistry->create("X", std::vector<int>{qbit});
auto meas10 = gateRegistry->create("Measure", std::vector<int>{qbit});
InstructionParameter p2(0);
meas10->setParameter(0,p2);
f10->addInstruction(x);
f10->addInstruction(meas01);
ir.addKernel(f10);
ir.addKernel(f01);
measureMap.insert({std::to_string(qbit) + "01", nKernels});
measureMap.insert({std::to_string(qbit) + "10", nKernels+1});
qbit++;
}
for (auto& kv : extraKernelsMap) {
std::cout << kv.first << ", " << kv.second << "\n";
}
for (auto& kv : measureMap) {
std::cout << kv.first << ", " << kv.second << "\n";
}
// Construct a ReadoutErrorABPostprocessor
return std::make_shared<ReadoutErrorAcceleratorBufferPostprocessor>(ir, extraKernelsMap, measureMap);
}
}
}
/*******************************************************************************
* Copyright (c) 2018 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
*******************************************************************************/
#ifndef QUANTUM_GATE_IR_READOUTERRORIRPREPROCESSOR_HPP_
#define QUANTUM_GATE_IR_READOUTERRORIRPREPROCESSOR_HPP_
#include "IRPreprocessor.hpp"
namespace xacc {
namespace quantum {
class ReadoutErrorIRPreprocessor : public IRPreprocessor {
public:
virtual std::shared_ptr<AcceleratorBufferPostprocessor> process(IR& ir);
};
}
}
#endif
/*******************************************************************************
* Copyright (c) 2017 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
*******************************************************************************/
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE ReadoutErrorIRPreprocessorTester
#include <boost/test/included/unit_test.hpp>
#include "ReadoutErrorIRPreprocessor.hpp"
#include "GateQIR.hpp"
#include <boost/math/constants/constants.hpp>
#include "XACC.hpp"
using namespace xacc;
using namespace xacc::quantum;
using Term = std::map<int, std::string>;
std::shared_ptr<IR> createXACCIR(std::unordered_map<std::string, Term> terms) {
// Create a new GateQIR to hold the spin based terms
auto newIr = std::make_shared<xacc::quantum::GateQIR>();
int counter = 0;
auto pi = boost::math::constants::pi<double>();
// Populate GateQIR now...
for (auto& inst : terms) {
Term spinInst = inst.second;
// Create a GateFunction and specify that it has
// a parameter that is the Spin Instruction coefficient
// that will help us get it to the user for their purposes.
auto gateFunction = std::make_shared<xacc::quantum::GateFunction>(
"term" + std::to_string(counter));
// Loop over all terms in the Spin Instruction
// and create instructions to run on the Gate QPU.
std::vector<std::shared_ptr<xacc::quantum::GateInstruction>> measurements;
std::vector<std::pair<int, std::string>> terms;
for (auto& kv : spinInst) {
if (kv.second != "I" && !kv.second.empty()) {
terms.push_back( { kv.first, kv.second });
}
}
for (int i = terms.size() - 1; i >= 0; i--) {
auto qbit = terms[i].first;
auto gateName = terms[i].second;
auto gateRegistry =
xacc::quantum::GateInstructionRegistry::instance();
auto meas = gateRegistry->create("Measure",
std::vector<int> { qbit });
xacc::InstructionParameter classicalIdx(qbit);
meas->setParameter(0, classicalIdx);
measurements.push_back(meas);
if (gateName == "X") {
auto hadamard = gateRegistry->create("H", std::vector<int> {
qbit });
gateFunction->addInstruction(hadamard);
} else if (gateName == "Y") {
auto rx = gateRegistry->create("Rx", std::vector<int> { qbit });
InstructionParameter p(pi / 2.0);
rx->setParameter(0, p);
gateFunction->addInstruction(rx);
}
}
for (auto m : measurements) {
gateFunction->addInstruction(m);
}
newIr->addKernel(gateFunction);
counter++;
}