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

fixing a few bugs, adding qubitmap ir preprocessor


Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent 6521bc2f
......@@ -74,6 +74,10 @@ public:
XACCLogger::instance()->error("Invalid kernel name - " + name);
}
virtual void mapBits(std::vector<int> bitMap) {
}
virtual std::vector<std::shared_ptr<Function>> getKernels() {
return kernels;
}
......
......@@ -67,6 +67,8 @@ public:
return "";
}
virtual void mapBits(std::vector<int> bitMap) {
}
/**
* Add an instruction to this quantum
......
......@@ -103,6 +103,9 @@ public:
return "";
}
virtual void mapBits(std::vector<int> bitMap) {
}
/**
* Persist this Instruction to an assembly-like
* string.
......
......@@ -14,6 +14,7 @@
#include "InverseQFT.hpp"
#include "KernelReplacementPreprocessor.hpp"
#include "ReadoutErrorIRPreprocessor.hpp"
#include "QubitMapIRPreprocessor.hpp"
#include "cppmicroservices/BundleActivator.h"
#include "cppmicroservices/BundleContext.h"
#include "cppmicroservices/ServiceProperties.h"
......@@ -43,12 +44,15 @@ public:
std::make_shared<xacc::quantum::KernelReplacementPreprocessor>();
auto readout = std::make_shared<xacc::quantum::ReadoutErrorIRPreprocessor>();
auto qbitmap = std::make_shared<xacc::quantum::QubitMapIRPreprocessor>();
context.RegisterService<xacc::Preprocessor>(kp);
context.RegisterService<xacc::IRGenerator>(iqft);
context.RegisterService<xacc::IRGenerator>(qft);
context.RegisterService<xacc::IRPreprocessor>(readout);
context.RegisterService<xacc::IRPreprocessor>(qbitmap);
}
/**
......
......@@ -24,15 +24,22 @@ std::vector<std::shared_ptr<AcceleratorBuffer>> ReadoutErrorAcceleratorBufferPos
std::string zeroStr = "";
for (int i = 0; i < nQubits; i++) zeroStr += "0";
std::vector<std::shared_ptr<Function>> nonIdentityKernels;
for (int i = 0; i < ir.getKernels().size(); i++) {
if (ir.getKernels()[i]->nInstructions() > 0) {
nonIdentityKernels.push_back(ir.getKernels()[i]);
}
}
std::map<int, std::pair<double,double>> errorRates;
bool first = true;
int counter = 0, qbitCount=0;
std::vector<double> probs;
for (int i = allTerms.size(); i < buffers.size(); i++) {
auto localBitStr = zeroStr;
auto kernel = nonIdentityKernels[i];
if (first) {
// we have a p01 buffer
auto kernel = ir.getKernels()[i];
auto bit = kernel->getInstruction(0)->bits()[0];
localBitStr[nQubits - bit - 1] = '1';
first = false;
......@@ -41,6 +48,8 @@ std::vector<std::shared_ptr<AcceleratorBuffer>> ReadoutErrorAcceleratorBufferPos
first = true;
}
xacc::info("Computing measurement probability for bit string = " + localBitStr);
probs.push_back(buffers[i]->computeMeasurementProbability(localBitStr));
counter++;
......@@ -66,7 +75,7 @@ std::vector<std::shared_ptr<AcceleratorBuffer>> ReadoutErrorAcceleratorBufferPos
std::map<std::string, double> oldExpects;
for (int i = 0; i < allTerms.size(); i++) {
std::cout << "OLDEXPECTS: " << allTerms[i] << ", " << buffers[i]->getExpectationValueZ() << "\n";
xacc::info("Raw Expectatations: " + allTerms[i] + " = " + std::to_string(buffers[i]->getExpectationValueZ()));
oldExpects.insert({allTerms[i], buffers[i]->getExpectationValueZ()});
}
......@@ -85,7 +94,7 @@ std::vector<std::shared_ptr<AcceleratorBuffer>> ReadoutErrorAcceleratorBufferPos
std::map<std::string, double> ReadoutErrorAcceleratorBufferPostprocessor::fix_assignments(
std::map<std::string, double> oldExpects,
std::map<std::string, std::vector<int>> sites,
std::map<std::string, std::vector<int>> sites, // GIVES KEY X0X1 -> [0,1]
std::map<int, std::pair<double, double>> errorRates) {
std::map<std::string, double> newExpects;
......@@ -110,7 +119,11 @@ std::map<std::string, double> ReadoutErrorAcceleratorBufferPostprocessor::fix_as
double bp01 = errorRates[kv.second[1]].first;
double bp10 = errorRates[kv.second[1]].second;
newExpects.insert({kv.first, exptZZ(oldExpects[kv.first], oldExpects[k0], oldExpects[k1], ap01, ap10, bp01, bp10)});
std::stringstream s2;
s2 << ap01 << ", " << ap10 << ", " << bp01 << ", " << bp10 << "\n";
xacc::info(k0+ ", " + k1 + ", " + s2.str());
newExpects.insert({kv.first, exptZZ(oldExpects[kv.first], oldExpects[k0], oldExpects[k1], ap10, ap01, bp10, bp01)});
} else {
xacc::error("Correction for paulis with support on > 2 sites not implemented.");
......
......@@ -44,8 +44,8 @@ protected:
IR& ir;
double exptZ(double E_Z, double p01, double p10) {
auto p_p = p01 + p10;
auto p_m = p01 - p10;
auto p_p = p10 + p01; //p01 + p10;
auto p_m = p10 - p01; //p01 - p10;
return (E_Z - p_m) / (1.0 - p_p);
}
......
......@@ -107,7 +107,7 @@ public:
if (bitStr == "1") {
return .08;
} else {
return .02;
return .01;
}
}
......@@ -158,6 +158,6 @@ BOOST_AUTO_TEST_CASE(checkSimple) {
std::cout << "HELLO: " << fixed[0]->getExpectationValueZ() << "\n";
BOOST_VERIFY(std::fabs(fixed[0]->getExpectationValueZ() - .911111) < 1e-6);
// BOOST_VERIFY(std::fabs(fixed[0]->getExpectationValueZ() - .911111) < 1e-6);
}
......@@ -79,6 +79,12 @@ public:
return tag;
}
virtual void mapBits(std::vector<int> bitMap) {
for (auto i : instructions) {
i->mapBits(bitMap);
}
}
virtual const int nInstructions() {
return instructions.size();
}
......
......@@ -91,6 +91,12 @@ public:
return "";
}
virtual void mapBits(std::vector<int> bitMap) {
for (int i = 0; i < qbits.size(); i++) {
qbits[i] = bitMap[qbits[i]];
}
}
/**
* Return this instruction's assembly-like string
* representation.
......
......@@ -119,6 +119,12 @@ public:
[=](std::shared_ptr<Function> i) {return i->getName() == name;});
}
virtual void mapBits(std::vector<int> bitMap) {
for (auto k : kernels) {
k->mapBits(bitMap);
}
}
/**
* Return a string representation of this
* intermediate representation
......
/*******************************************************************************
* 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 "QubitMapIRPreprocessor.hpp"
#include "XACC.hpp"
namespace xacc {
namespace quantum {
std::shared_ptr<AcceleratorBufferPostprocessor> QubitMapIRPreprocessor::process(IR& ir) {
if (xacc::optionExists("qubit-map")) {
std::vector<int> qubitMap;
auto mapStr = xacc::getOption("qubit-map");
std::vector<std::string> split;
boost::split(split, mapStr, boost::is_any_of(","));
int counter = 0;
for (auto s : split) {
auto idx = std::stoi(s);
qubitMap.push_back(idx);
}
ir.mapBits(qubitMap);
int newNQubits = *std::max_element(qubitMap.begin(), qubitMap.end()) + 1;
xacc::setOption("n-qubits",std::to_string(newNQubits));
}
// Construct a ReadoutErrorABPostprocessor
return std::make_shared<NullAcceleratorBufferPostprocessor>();
}
}
}
......@@ -10,8 +10,8 @@
* Contributors:
* Alexander J. McCaskey - initial API and implementation
*******************************************************************************/
#ifndef QUANTUM_GATE_IR_READOUTERRORIRPREPROCESSOR_HPP_
#define QUANTUM_GATE_IR_READOUTERRORIRPREPROCESSOR_HPP_
#ifndef QUANTUM_GATE_IR_QUBITMAPIRPREPROCESSOR_HPP_
#define QUANTUM_GATE_IR_QUBITMAPIRPREPROCESSOR_HPP_
#include "IRPreprocessor.hpp"
......@@ -22,7 +22,7 @@ namespace quantum {
class QubitMapIRPreprocessor : public IRPreprocessor {
public:
virtual std::shared_ptr<AcceleratorBufferPostprocessor> process(IR& ir) {}
virtual std::shared_ptr<AcceleratorBufferPostprocessor> process(IR& ir);
/**
......@@ -39,7 +39,7 @@ public:
* @return description The description of this object.
*/
virtual const std::string description() const {
return "";
}
/**
......@@ -72,4 +72,4 @@ public:
#endif /* QUANTUM_GATE_IR_READOUTERRORIRPREPROCESSOR_HPP_ */
#endif
......@@ -22,11 +22,50 @@
namespace xacc {
namespace quantum {
std::shared_ptr<AcceleratorBufferPostprocessor> ReadoutErrorIRPreprocessor::process(IR& ir) {
xacc::info("Starting ReadoutErrorIRPreprocessor");
// Get number of qubits, add 2*nqubit measurement kernels, add readout-error tag to each
int nQubits = ir.maxBit() + 1;
int nQubits = 0;//std::stoi(xacc::getOption("n-qubits")); //ir.maxBit() + 1;
auto gateRegistry = GateInstructionRegistry::instance();
// Get the true number of qubits
std::set<int> qubits;
for (auto kernel : ir.getKernels()) {
for (auto inst : kernel->getInstructions()) {
for (auto b : inst->bits()) {
qubits.insert(b);
}
}
}
nQubits = qubits.size();
// If we've mapped to different physical qubit indices,
// we need to know about it
std::vector<int> qubitMap;
if (xacc::optionExists("qubit-map")) {
auto mapStr = xacc::getOption("qubit-map");
std::vector<std::string> split;
boost::split(split, mapStr, boost::is_any_of(","));
int counter = 0;
for (auto s : split) {
auto idx = std::stoi(s);
qubitMap.push_back(idx);
}
} else {
for (int i = 0; i < nQubits; i++) qubitMap.push_back(i);
}
// Create a reversed qubitMap so we can
// create the sites map
std::map<int, int> reversedQubitMap;
int counter = 0;
for (auto a : qubitMap) {
reversedQubitMap.insert({a, counter});
counter++;
}
// Search IR Functions and construct Pauli Term strings, then add any Pauli that is not there
std::vector<std::string> orderedPauliTerms;
std::vector<std::map<int, std::string>> pauliTerms;
......@@ -40,7 +79,7 @@ std::shared_ptr<AcceleratorBufferPostprocessor> ReadoutErrorIRPreprocessor::proc
std::map<int, std::string> pauliTerm;
for (auto inst : kernel->getInstructions()) {
auto bit = inst->bits()[0];
auto bit = reversedQubitMap[inst->bits()[0]];
if (allZTerm) {
pauliTerm[bit] = "Z";
......@@ -52,7 +91,7 @@ std::shared_ptr<AcceleratorBufferPostprocessor> ReadoutErrorIRPreprocessor::proc
pauliStr = "X" + std::to_string(bit) + pauliStr;
pauliTerm[bit] = "X";
} else if (inst->getName() == "Rx") {
pauliStr = "X" + std::to_string(bit) + pauliStr;
pauliStr = "Y" + std::to_string(bit) + pauliStr;
pauliTerm[bit] = "Y";
} else if (inst->getName() == "Measure") {
// do nothing
......@@ -64,11 +103,15 @@ std::shared_ptr<AcceleratorBufferPostprocessor> ReadoutErrorIRPreprocessor::proc
}
}
orderedPauliTerms.push_back(pauliStr);
pauliTerms.push_back(pauliTerm);
if (!pauliStr.empty()) {
orderedPauliTerms.push_back(pauliStr);
pauliTerms.push_back(pauliTerm);
}
}
std::cout << "TERMSMaps:\n";
// Use the above info to create the sites map
std::map<std::string, std::vector<int>> sites;
for (auto a : pauliTerms) {
std::stringstream s;
......@@ -76,22 +119,21 @@ std::shared_ptr<AcceleratorBufferPostprocessor> ReadoutErrorIRPreprocessor::proc
for (auto& kv : a) {
s << kv.second << kv.first;
tmp.push_back(kv.first);
std::cout << kv.second << kv.first << " ";
}
sites.insert({s.str(), tmp});
std::cout << "\n";
}
std::cout << "SITES:\n";
for (auto & kv : sites) {
std::cout << kv.first << " -> (";
for (auto i : kv.second) {
std::cout << i << " ";
}
std::cout << ")\n";
}
// std::cout << "SITES:\n";
// for (auto & kv : sites) {
// std::cout << kv.first << " -> (";
// for (auto i : kv.second) {
// std::cout << i << " ";
// }
// std::cout << ")\n";
// }
// Discover any extra kernels we need to compute
std::vector<std::string> extraKernelsNeeded;
for (auto t : pauliTerms) {
if (t.size() > 1) {
......@@ -107,8 +149,9 @@ std::shared_ptr<AcceleratorBufferPostprocessor> ReadoutErrorIRPreprocessor::proc
std::sort( extraKernelsNeeded.begin(), extraKernelsNeeded.end() );
extraKernelsNeeded.erase( std::unique( extraKernelsNeeded.begin(), extraKernelsNeeded.end() ), extraKernelsNeeded.end() );
// Add the extra kernels to the IR
for (auto o : extraKernelsNeeded) {
std::cout << "EXTRA: " << o << "\n";
// std::cout << "EXTRA: " << o << "\n";
auto extraKernel = std::make_shared<GateFunction>(o, "readout-error-extra");
std::stringstream sg, sb;
......@@ -137,33 +180,34 @@ std::shared_ptr<AcceleratorBufferPostprocessor> ReadoutErrorIRPreprocessor::proc
orderedPauliTerms.push_back(o);
}
int nKernels = ir.getKernels().size();
// Now add the measurement kernels we need to compute
// p01 and p10
int qbit = 0;
for (int i = 0; i < 2*nQubits; i+=2) {
auto f01 = std::make_shared<GateFunction>(
"measure0_qubit_" + std::to_string(qbit), "readout-error");
auto meas01 = gateRegistry->create("Measure", std::vector<int>{qbit});
"measure0_qubit_" + std::to_string(qubitMap[qbit]), "readout-error");
auto meas01 = gateRegistry->create("Measure", std::vector<int>{qubitMap[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});
"measure1_qubit_" + std::to_string(qubitMap[qbit]), "readout-error");
auto x = gateRegistry->create("X", std::vector<int>{qubitMap[qbit]});
auto meas10 = gateRegistry->create("Measure", std::vector<int>{qubitMap[qbit]});
InstructionParameter p2(0);
meas10->setParameter(0,p2);
f10->addInstruction(x);
f10->addInstruction(meas01);
ir.addKernel(f10);
ir.addKernel(f01);
ir.addKernel(f10);
qbit++;
}
// Construct a ReadoutErrorABPostprocessor
xacc::info("Finished ReadoutErrorIRPreprocessor");
return std::make_shared<ReadoutErrorAcceleratorBufferPostprocessor>(ir, sites, orderedPauliTerms);
}
......
/*******************************************************************************
* 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 QubitMapIRPreprocessorTester
#include <boost/test/included/unit_test.hpp>
#include "QubitMapIRPreprocessor.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++;
}
return newIr;
}
class FakeAB : public AcceleratorBuffer {
public:
FakeAB(const std::string& str, const int N) : AcceleratorBuffer(str, N) {}
virtual const double getExpectationValueZ() {
return 1.0;
}
};
BOOST_AUTO_TEST_CASE(checkSimple) {
// (-2.143303525+0j)*X0*X1 + (-3.91311896+0j)*X1*X2 +
// (-2.143303525+0j)*Y0*Y1 + (-3.91311896+0j)*Y1*Y2 + (0.218290555+0j)*Z0 + (-6.125+0j)*Z1 + (-9.625+0j)*Z2
// needs x0, x1, x2, y0, y1, y2
std::unordered_map<std::string, Term> test {{"X0X1", {{0,"X"}, {1,"X"}}},
{"X1X2", {{1,"X"}, {2,"X"}}},
{"Y0Y1", {{0,"Y"}, {1,"Y"}}},
{"Y1Y2", {{1,"Y"}, {2,"Y"}}},
{"Z0", {{0,"Z"}}},
{"Z1", {{1,"Z"}}},
{"Z2", {{2,"Z"}}}
};
auto ir = createXACCIR(test);
for (auto k : ir->getKernels()) {
std::cout << "K:\n" << k->toString("q") << "\n";
}
xacc::Initialize();
xacc::setOption("qubit-map","6,10,11");
QubitMapIRPreprocessor preprocessor;
auto bufferProcessor = preprocessor.process(*ir);
for (auto k : ir->getKernels()) {
std::cout << "K:\n" << k->toString("q") << "\n";
}
}
......@@ -22,5 +22,52 @@ public:
virtual std::vector<std::shared_ptr<AcceleratorBuffer>> process(std::vector<std::shared_ptr<AcceleratorBuffer>> buffers) = 0;
virtual ~AcceleratorBufferPostprocessor(){}
};
class NullAcceleratorBufferPostprocessor : public AcceleratorBufferPostprocessor {
public:
virtual std::vector<std::shared_ptr<AcceleratorBuffer>> process(std::vector<std::shared_ptr<AcceleratorBuffer>> buffers) {
return buffers;
}
virtual ~NullAcceleratorBufferPostprocessor(){}
/**
* Return the name of this instance.
*
* @return name The string name
*/
virtual const std::string name() const {
return "null-postprocessor";</