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

adding more circuit generators, rdm and vqe energy algoritms, and rdm purification decorator


Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent f9ea81c2
add_subdirectory(ibm)
#add_subdirectory(rigetti)
#add_subdirectory(cmr)
#add_subdirectory(dwave)
add_subdirectory(algorithms)
add_subdirectory(decorators)
add_subdirectory(circuits)
#add_subdirectory(scaffold)
add_subdirectory(xasm)
add_subdirectory(vqe)
add_subdirectory(rdm)
add_subdirectory(vqe-energy)
#file(GLOB PYDECORATORS ${CMAKE_CURRENT_SOURCE_DIR}/vqe/python/*.py ${CMAKE_CURRENT_SOURCE_DIR}/vqe-energy/python/*.py)
#install(FILES ${PYDECORATORS} DESTINATION ${CMAKE_INSTALL_PREFIX}/py-plugins)
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 <memory>
using namespace xacc;
namespace xacc {
namespace algorithm {
bool RDM::initialize(const HeterogeneousMap &parameters) {
if (!parameters.keyExists<std::shared_ptr<CompositeInstruction>>("ansatz")) {
return false;
} else if (!parameters.keyExists<std::shared_ptr<Accelerator>>("accelerator")) {
return false;
}
ansatz = parameters.get<std::shared_ptr<CompositeInstruction>>("ansatz");
accelerator = parameters.get<std::shared_ptr<Accelerator>>("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<CompositeInstruction>,
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->getCoefficient());
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<CompositeInstruction>> 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 tmpBuffer = xacc::qalloc(buffer->size());
accelerator->execute(tmpBuffer, fsToExecute);
auto buffers = tmpBuffer->getChildren();
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<CompositeInstruction> ansatz;
std::shared_ptr<Accelerator> accelerator;
HeterogeneousMap parameters;
public:
bool initialize(const HeterogeneousMap &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
#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(__qpu__ void f(qbit q, double t0) {
X(q[0]);
X(q[1]);
Rx(q[0],1.5707);
H(q[1]);
H(q[2]);
H(q[3]);
CNOT(q[0],q[1]);
CNOT(q[1],q[2]);
CNOT(q[2],q[3]);
Rz(q[3], t0);
CNOT(q[2],q[3]);
CNOT(q[1],q[2]);
CNOT(q[0],q[1]);
Rx(q[0],-1.5707);
H(q[1]);
H(q[2]);
H(q[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("xasm");
auto ir2 = compiler->compile(rucc, accelerator);
auto ruccsd = ir2->getComposite("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");
EXPECT_TRUE(rdmGen->initialize({std::make_pair("accelerator",accelerator ), std::make_pair("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;
}
set(LIBRARY_NAME xacc-algorithm-vqe-energy)
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 .)
target_link_libraries(${LIBRARY_NAME} PUBLIC xacc CppMicroServices)
set(_bundle_name xacc_algorithm_vqe_energy)
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 "vqe-energy.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 VQEEnergyActivator : public BundleActivator {
public:
VQEEnergyActivator() {}
/**
*/
void Start(BundleContext context) {
auto c = std::make_shared<xacc::algorithm::VQEEnergy>();
context.RegisterService<xacc::Algorithm>(c);
}
/**
*/
void Stop(BundleContext /*context*/) {}
};
} // namespace
CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(VQEEnergyActivator)
{
"bundle.symbolic_name" : "xacc_algorithm_vqe_energy",
"bundle.activator" : true,
"bundle.name" : "XACC VQE-Energy Algorithm",
"bundle.description" : ""
}
import unittest as test
import sys
import xacc
from xacc import PauliOperator
class TestPyVQE(test.TestCase):
def setUp(self):
self.qpu = xacc.getAccelerator('tnqvm')
self.buffer = self.qpu.createBuffer('q', 2)
self.ham = PauliOperator(5.906709445) + \
PauliOperator({0: 'X', 1: 'X'}, -2.1433) + \
PauliOperator({0: 'Y', 1: 'Y'}, -2.1433) + \
PauliOperator({0: 'Z'}, .21829) + \
PauliOperator({1: 'Z'}, -6.125)
def test_energy(self):
@xacc.qpu(algo='energy', accelerator=self.qpu, observable=self.ham)
def ansatz(buffer, t0):
X(0)
Ry(t0, 1)
CNOT(1, 0)
ansatz(self.buffer, 0.5)
self.assertAlmostEqual(self.buffer.getInformation("opt-val"), -1.71515, places=4)