Commit 8f46bf37 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Adding AcceleratorParameters variant map to initialize(). Added RDM algorithm...


Adding AcceleratorParameters variant map to initialize(). Added RDM algorithm and RDM purification decorator
Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent 8048a6cb
Pipeline #65797 passed with stage
in 6 minutes and 51 seconds
......@@ -59,12 +59,12 @@ public:
return names;
}
virtual void initialize() {}
virtual void initialize(AcceleratorParameters params) {}
virtual void execute(std::shared_ptr<xacc::AcceleratorBuffer> buffer,
const std::shared_ptr<xacc::Function> function) {}
virtual std::vector<std::shared_ptr<xacc::AcceleratorBuffer>>
execute(std::shared_ptr<xacc::AcceleratorBuffer> buffer,
const std::vector<std::shared_ptr<xacc::Function>> functions) {}
const std::vector<std::shared_ptr<xacc::Function>> functions) {return {};}
virtual std::shared_ptr<xacc::AcceleratorBuffer>
createBuffer(const std::string &varId, const int size) {
......@@ -109,7 +109,10 @@ TEST(PyXACCCompilerTester, checkIRGen) {
auto acc = std::make_shared<FakePyAcc>();
auto ir = compiler->compile(uccsdSrc, acc);
auto ir = compiler->compile(R"(def foo(buffer, *args):
uccsd(n_qubits=4, n_electrons=2)
)", acc);
auto f = ir->getKernel("foo");
EXPECT_EQ("foo", f->name());
EXPECT_EQ(f->nParameters(), 2);
......
......@@ -75,7 +75,7 @@ public:
const std::string description() const override { return ""; }
void initialize() override { return; }
void initialize(AcceleratorParameters params = {}) override { return; }
AcceleratorType getType() override {
return Accelerator::AcceleratorType::qpu_gate;
......@@ -143,7 +143,7 @@ PYBIND11_MODULE(_pyxacc, m) {
.def("bits", &xacc::Instruction::bits, "")
.def("getParameter", &xacc::Instruction::getParameter, "")
.def("getParameters", &xacc::Instruction::getParameters, "")
.def("setParameter", &xacc::Instruction::setParameter, "")
.def("setParameter", ( void ( xacc::Instruction::*)(const int, InstructionParameter &) ) &xacc::Instruction::setParameter, "")
.def("mapBits", &xacc::Instruction::mapBits, "")
.def("name", &xacc::Instruction::name, "")
.def("description", &xacc::Instruction::description, "");
......@@ -173,7 +173,7 @@ PYBIND11_MODULE(_pyxacc, m) {
.def("enable", &xacc::Function::enable, "")
.def("getParameter", &xacc::Function::getParameter, "")
.def("getParameters", &xacc::Function::getParameters, "")
.def("setParameter", &xacc::Function::setParameter, "")
.def("setParameter", ( void ( xacc::Instruction::*)(const int, InstructionParameter &) )&xacc::Function::setParameter, "")
.def("depth", &xacc::Function::depth, "")
.def("persistGraph", &xacc::Function::persistGraph, "")
.def("mapBits", &xacc::Function::mapBits, "");
......@@ -471,7 +471,7 @@ PYBIND11_MODULE(_pyxacc, m) {
"Initialize the framework from Python.");
// m.def("help", )
m.def("getAccelerator",
(std::shared_ptr<xacc::Accelerator>(*)(const std::string &)) &
(std::shared_ptr<xacc::Accelerator>(*)(const std::string &, AcceleratorParameters)) &
xacc::getAccelerator,
py::return_value_policy::reference,
"Return the accelerator with given name.");
......
......@@ -375,7 +375,6 @@ void GateFunction::addInstruction(InstPtr instruction) {
}
if (instruction->isComposite()) {
std::cout << "GateFunction Adding composite instruction\n";
for (auto p : instruction->getParameters()) {
// these have to be variable params
bool dupParam = false;
......
......@@ -97,9 +97,7 @@ PauliOperator::observe(std::shared_ptr<Function> function) {
gateFunction->setOption("coefficient", spinInst.coeff());
for (auto& inst : function->getInstructions()) {
gateFunction->addInstruction(inst);
}
gateFunction->addInstruction(function);
// Loop over all terms in the Spin Instruction
// and create instructions to run on the Gate QPU.
......
......@@ -2,4 +2,5 @@ add_subdirectory(ibm)
add_subdirectory(rigetti)
add_subdirectory(cmr)
add_subdirectory(dwave)
add_subdirectory(algorithms)
\ No newline at end of file
add_subdirectory(algorithms)
add_subdirectory(decorators)
\ No newline at end of file
add_subdirectory(vqe)
\ No newline at end of file
add_subdirectory(vqe)
add_subdirectory(rdm)
\ No newline at end of file
set(LIBRARY_NAME xacc-algorithm-rdm)
file(GLOB SRC *.cpp)
usfunctiongetresourcesource(TARGET ${LIBRARY_NAME} OUT SRC)
usfunctiongeneratebundleinit(TARGET ${LIBRARY_NAME} OUT SRC)
add_library(${LIBRARY_NAME} SHARED ${SRC})
target_include_directories(
${LIBRARY_NAME}
PUBLIC . ${CMAKE_SOURCE_DIR}/tpls/eigen)
target_link_libraries(${LIBRARY_NAME} PUBLIC xacc CppMicroServices xacc-fermion)
set(_bundle_name xacc_algorithm_rdm)
set_target_properties(${LIBRARY_NAME}
PROPERTIES COMPILE_DEFINITIONS
US_BUNDLE_NAME=${_bundle_name}
US_BUNDLE_NAME
${_bundle_name})
usfunctionembedresources(TARGET
${LIBRARY_NAME}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
FILES
manifest.json)
if(APPLE)
set_target_properties(${LIBRARY_NAME}
PROPERTIES INSTALL_RPATH "@loader_path/../lib")
set_target_properties(${LIBRARY_NAME}
PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
else()
set_target_properties(${LIBRARY_NAME}
PROPERTIES INSTALL_RPATH "$ORIGIN/../lib")
set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared")
endif()
if(XACC_BUILD_TESTS)
add_subdirectory(tests)
endif()
install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins)
#include "rdm.hpp"
#include "cppmicroservices/BundleActivator.h"
#include "cppmicroservices/BundleContext.h"
#include "cppmicroservices/ServiceProperties.h"
#include <memory>
#include <set>
using namespace cppmicroservices;
namespace {
/**
*/
class US_ABI_LOCAL RDMActivator : public BundleActivator {
public:
RDMActivator() {}
/**
*/
void Start(BundleContext context) {
auto c = std::make_shared<xacc::algorithm::RDM>();
context.RegisterService<xacc::Algorithm>(c);
}
/**
*/
void Stop(BundleContext /*context*/) {}
};
} // namespace
CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(RDMActivator)
{
"bundle.symbolic_name" : "xacc_algorithm_rdm",
"bundle.activator" : true,
"bundle.name" : "XACC RDM Generation Algorithm",
"bundle.description" : ""
}
#include "rdm.hpp"
#include "Observable.hpp"
#include "XACC.hpp"
#include "FermionOperator.hpp"
#include <unsupported/Eigen/CXX11/Tensor>
#include <unsupported/Eigen/CXX11/TensorSymmetry>
#include "InstructionParameter.hpp"
#include <memory>
using namespace xacc;
namespace xacc {
namespace algorithm {
bool RDM::initialize(const AlgorithmParameters &parameters) {
if (!parameters.count("ansatz")) {
return false;
} else if (!parameters.count("accelerator")) {
return false;
}
ansatz = parameters.at("ansatz").as<std::shared_ptr<Function>>();
accelerator = parameters.at("accelerator").as<std::shared_ptr<Accelerator>>();
return true;
}
const std::vector<std::string> RDM::requiredParameters() const {
return {"accelerator", "ansatz"};
}
void RDM::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const {
// Reset
int nQubits = buffer->size(), nExecs = 0;
Eigen::Tensor<std::complex<double>, 4> rho_pqrs(nQubits, nQubits, nQubits,
nQubits);
rho_pqrs.setZero();
// Get the Accelerator we're running on, the
// number of orbitals/qubits in the problem,
// the MPIProvider Communicator reference, and the
// VQE state preparation ansatz.
Eigen::DynamicSGroup rho_pq_Sym, rho_pqrs_Sym;
rho_pq_Sym.addHermiticity(0, 1);
rho_pqrs_Sym.addAntiSymmetry(0, 1);
rho_pqrs_Sym.addAntiSymmetry(2, 3);
// Map p,q,r,s indices to a coefficient for all
// identity terms encountered
std::map<std::vector<int>, double> rho_element_2_identity_coeff;
// Map function names to the actual function and all
// p,q,r,s and coefficients that contribute to that element
std::map<std::string,
std::pair<std::shared_ptr<Function>,
std::vector<std::pair<std::vector<int>, double>>>>
functions;
// Generate the 2-RDM circuits for executiong
for (int m = 0; m < nQubits; m++) {
for (int n = m + 1; n < nQubits; n++) {
for (int v = m; v < nQubits; v++) {
for (int w = v + 1; w < nQubits; w++) {
std::stringstream xx;
xx << "0.5 " << m << "^ " << n << "^ " << w << " " << v << " + "
<< "0.5 " << w << "^ " << v << "^ " << m << " " << n;
auto op = std::make_shared<xacc::quantum::FermionOperator>(xx.str());
auto hpqrs_ir = op->observe(ansatz);
for (auto &kernel : hpqrs_ir) {
auto t = std::real(
kernel->getOption("coefficient").as<std::complex<double>>());
int nFunctionInstructions = 0;
if (kernel->getInstruction(0)->isComposite()) {
nFunctionInstructions =
ansatz->nInstructions() + kernel->nInstructions() - 1;
} else {
nFunctionInstructions = kernel->nInstructions();
}
if (nFunctionInstructions > ansatz->nInstructions()) {
// if (kernel->nInstructions() > ansatz->nInstructions()) {
auto name = kernel->name();
if (functions.count(name)) {
functions[name].second.push_back({{m, n, v, w}, t});
} else {
functions.insert({name, {kernel, {{{m, n, v, w}, t}}}});
}
} else {
rho_element_2_identity_coeff.insert({{m, n, v, w}, t});
}
}
}
}
}
}
std::vector<std::shared_ptr<Function>> fsToExecute;
for (auto &kv : functions) {
fsToExecute.push_back(kv.second.first);
}
int nPhysicalQubits =
nQubits; //*std::max_element(qubitMap.begin(), qubitMap.end()) + 1;
// Execute all nontrivial circuits
xacc::info("[RDM] Executing " + std::to_string(fsToExecute.size()) +
" circuits to compute rho_pqrs.");
auto buffers = accelerator->execute(buffer, fsToExecute);
bool useROExps = false;
if (accelerator->name() == "ro-error") {
useROExps = true;
}
// Create a mapping of rho_pqrs elements to summed expectation values for
// each circuit contributing to it
std::map<std::vector<int>, double> sumMap;
for (int i = 0; i < buffers.size(); i++) {
auto fName = fsToExecute[i]->name();
auto p = functions[fName];
std::vector<std::string> contributingIndices;
std::vector<double> contributingCoeffs;
for (auto &l : p.second) {
auto elements = l.first;
std::stringstream s;
s << elements[0] << "," << elements[1] << "," << elements[2] << ","
<< elements[3];
contributingIndices.push_back(s.str());
double value;
if (useROExps) {
value = l.second * mpark::get<double>(buffers[i]->getInformation(
"ro-fixed-exp-val-z"));
} else {
value = l.second * buffers[i]->getExpectationValueZ();
}
contributingCoeffs.push_back(value);
if (!sumMap.count(elements)) {
sumMap.insert({elements, value});
} else {
sumMap[elements] += value;
}
}
buffers[i]->addExtraInfo("kernel", ExtraInfo(fName));
buffers[i]->addExtraInfo("contributing_rho_pqrs",
ExtraInfo(contributingIndices));
buffers[i]->addExtraInfo("contributing_coeffs",
ExtraInfo(contributingCoeffs));
buffer->appendChild(fName, buffers[i]);
}
// Add all identity terms, we don't execute them
// but we still have to add their contribution
for (auto &kv : rho_element_2_identity_coeff) {
sumMap[kv.first] += kv.second;
}
// Set rho_pqrs. This is all we need
// to get rho_pq as well
for (auto &kv : sumMap) {
auto elements = kv.first;
rho_pqrs_Sym(rho_pqrs, elements[0], elements[1], elements[2], elements[3]) =
kv.second;
rho_pqrs_Sym(rho_pqrs, elements[2], elements[3], elements[0], elements[1]) =
kv.second;
}
Eigen::Tensor<double, 4> realt = rho_pqrs.real();
auto real = realt.data();
std::vector<double> rho_pqrs_data(real, real + rho_pqrs.size());
for (auto &a : rho_pqrs_data)
if (std::fabs(a) < 1e-12)
a = 0;
buffer->addExtraInfo("2-rdm", ExtraInfo(rho_pqrs_data));
return;
}
} // namespace algorithm
} // namespace xacc
\ No newline at end of file
#ifndef XACC_ALGORITHM_RDM_HPP_
#define XACC_ALGORITHM_RDM_HPP_
#include "Algorithm.hpp"
namespace xacc {
namespace algorithm {
class RDM : public Algorithm {
protected:
std::shared_ptr<Function> ansatz;
std::shared_ptr<Accelerator> accelerator;
AlgorithmParameters parameters;
public:
bool initialize(const AlgorithmParameters &parameters) override;
const std::vector<std::string> requiredParameters() const override;
void execute(const std::shared_ptr<AcceleratorBuffer> buffer) const override;
const std::string name() const override { return "rdm"; }
const std::string description() const override { return ""; }
};
} // namespace algorithm
} // namespace xacc
#endif
\ No newline at end of file
include_directories(${CMAKE_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/tpls/eigen)
add_xacc_test(RDM)
target_link_libraries(RDMTester xacc CppMicroServices xacc-fermion)
\ No newline at end of file
/***********************************************************************************
* Copyright (c) 2017, 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
*
**********************************************************************************/
#include "IRGenerator.hpp"
#include "Instruction.hpp"
#include "XACC.hpp"
#include <gtest/gtest.h>
#include "xacc_service.hpp"
#include "FermionOperator.hpp"
#include <unsupported/Eigen/CXX11/Tensor>
using namespace xacc;
const std::string src = R"src(0.7080240949826064
- 1.248846801817026 0^ 0
- 1.248846801817026 1^ 1
- 0.4796778151607899 2^ 2
- 0.4796778151607899 3^ 3
+ 0.33667197218932576 0^ 1^ 1 0
+ 0.0908126658307406 0^ 1^ 3 2
+ 0.09081266583074038 0^ 2^ 0 2
+ 0.331213646878486 0^ 2^ 2 0
+ 0.09081266583074038 0^ 3^ 1 2
+ 0.331213646878486 0^ 3^ 3 0
+ 0.33667197218932576 1^ 0^ 0 1
+ 0.0908126658307406 1^ 0^ 2 3
+ 0.09081266583074038 1^ 2^ 0 3
+ 0.331213646878486 1^ 2^ 2 1
+ 0.09081266583074038 1^ 3^ 1 3
+ 0.331213646878486 1^ 3^ 3 1
+ 0.331213646878486 2^ 0^ 0 2
+ 0.09081266583074052 2^ 0^ 2 0
+ 0.331213646878486 2^ 1^ 1 2
+ 0.09081266583074052 2^ 1^ 3 0
+ 0.09081266583074048 2^ 3^ 1 0
+ 0.34814578469185886 2^ 3^ 3 2
+ 0.331213646878486 3^ 0^ 0 3
+ 0.09081266583074052 3^ 0^ 2 1
+ 0.331213646878486 3^ 1^ 1 3
+ 0.09081266583074052 3^ 1^ 3 1
+ 0.09081266583074048 3^ 2^ 0 1
+ 0.34814578469185886 3^ 2^ 2 3)src";
const std::string rucc = R"rucc(def f(buffer, theta):
X(0)
X(1)
Rx(1.5707,0)
H(1)
H(2)
H(3)
CNOT(0,1)
CNOT(1,2)
CNOT(2,3)
Rz(theta,3)
CNOT(2,3)
CNOT(1,2)
CNOT(0,1)
Rx(-1.5707,0)
H(1)
H(2)
H(3)
)rucc";
TEST(RDMGeneratorTester, checkGround) {
if (xacc::hasAccelerator("tnqvm")) {
// Get the user-specified Accelerator,
// or TNQVM if none specified
auto accelerator = xacc::getAccelerator("tnqvm");
int nQubits = 4;
xacc::quantum::FermionOperator op(src);
Eigen::Tensor<double,2> hpq(4,4); hpq.setZero();
Eigen::Tensor<double,4> hpqrs(4,4,4,4);hpqrs.setZero();
double enuc = 0.0;
auto terms = op.getTerms();
for (auto& kv : terms) {
auto ops = kv.second.ops();
if (ops.size() == 4) {
hpqrs(ops[0].first,ops[1].first,ops[2].first, ops[3].first) = std::real(kv.second.coeff());
} else if (ops.size() == 2) {
hpq(ops[0].first,ops[1].first) = std::real(kv.second.coeff());
} else {
enuc = std::real(kv.second.coeff());
}
}
// Create the UCCSD ansatz and evaluate
// at the known optimal angles
auto compiler = xacc::getCompiler("xacc-py");
auto ir2 = compiler->compile(rucc, accelerator);
auto ruccsd = ir2->getKernel("f");
std::vector<double> parameters{.22984};
ruccsd = (*ruccsd.get())(parameters);
// Create the 2-RDM
// std::vector<int> qubitMap {1,3,5,7}; // map to physical qubits
// ruccsd->mapBits(qubitMap);
auto rdmGen = xacc::getAlgorithm("rdm");
rdmGen->initialize({{"accelerator",accelerator }, {"ansatz", ruccsd}});
auto buffer = xacc::qalloc(4);
rdmGen->execute(buffer);
// auto buffers = generator.generate(ruccsd, qubitMap);
auto data = buffer->getInformation("2-rdm").as<std::vector<double>>();
// EXPECT_EQ(buffers.size(), 54);
Eigen::TensorMap<Eigen::Tensor<double,4>> rho_pqrs(data.data(), 4,4,4,4);
// // Get the 1 rdm from the 2 rdm
Eigen::array<int, 2> cc2({1, 3});
Eigen::Tensor<double, 2> rho_pq = rho_pqrs.trace(cc2);
double energy = enuc;
// Compute the 2 rdm contribution to the energy
for (int p = 0; p < nQubits; p++) {
for (int q = 0; q < nQubits; q++) {
for (int r = 0; r < nQubits; r++) {
for (int s = 0; s < nQubits; s++) {
energy +=
0.5 * std::real(hpqrs(p, q, r, s) *
(rho_pqrs(p, q, s, r) + rho_pqrs(r, s, q, p)));
}
}
}
}
// Compute the 1 rdm contribution to the energy
for (int p = 0; p < nQubits; p++) {
for (int q = 0; q < nQubits; q++) {
energy += 0.5 * std::real(hpq(p, q) * (rho_pq(p, q) + rho_pq(q, p)));
}
}
std::cout << "ENERGY: " << energy << "\n";
// // auto energy = rhoGen.energy();
EXPECT_NEAR(energy, -1.1371, 1e-4);
}
}
int main(int argc, char **argv) {
xacc::Initialize();
int ret = 0;
::testing::InitGoogleTest(&argc, argv);
ret = RUN_ALL_TESTS();
xacc::Finalize();
return ret;
}
......@@ -55,7 +55,14 @@ void VQE::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const {
InstructionParameter p = f->getOption("coefficient");
std::complex<double> coeff = p.as<std::complex<double>>();
if (f->nInstructions() > kernel->nInstructions()) {
int nFunctionInstructions = 0;
if (f->getInstruction(0)->isComposite()) {
nFunctionInstructions = kernel->nInstructions() + f->nInstructions() - 1;