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

adding FermionOperator Observable implementation


Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent d02da5ca
Pipeline #47287 failed with stages
in 4 minutes and 54 seconds
set (PACKAGE_NAME "PauliOperator Parser")
set (LIBRARY_NAME xacc-pauli)
file (GLOB_RECURSE HEADERS *.hpp generated/*.hpp)
file (GLOB SRC *.cpp generated/*.cpp)
add_library(${LIBRARY_NAME} SHARED ${SRC})
target_include_directories(${LIBRARY_NAME}
PUBLIC
.
${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/generated
${CMAKE_SOURCE_DIR}/tpls/taocpp
${CMAKE_SOURCE_DIR}/tpls/eigen
${CMAKE_BINARY_DIR})
add_dependencies(${LIBRARY_NAME} antlr4_shared)
target_link_libraries(${LIBRARY_NAME} PUBLIC xacc PRIVATE CppMicroServices ${CMAKE_SOURCE_DIR}/dist/libantlr4-runtime.so)
if(APPLE)
set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "@loader_path")
set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
else()
set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN")
set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared")
endif()
if(XACC_BUILD_TESTS)
add_subdirectory(tests)
endif()
file (GLOB HEADERS *.hpp)
install(FILES ${HEADERS} DESTINATION include/quantum/gate)
install(TARGETS ${LIBRARY_NAME} DESTINATION lib)
add_subdirectory(pauli)
add_subdirectory(fermion)
add_subdirectory(transforms)
\ No newline at end of file
set (PACKAGE_NAME "FermionOperator Parser")
set (LIBRARY_NAME xacc-fermion)
file (GLOB_RECURSE HEADERS *.hpp generated/*.hpp)
file (GLOB SRC *.cpp generated/*.cpp)
add_library(${LIBRARY_NAME} SHARED ${SRC})
target_include_directories(${LIBRARY_NAME}
PUBLIC
.
${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/generated
${CMAKE_SOURCE_DIR}/tpls/taocpp
#${CMAKE_SOURCE_DIR}/tpls/eigen
${CMAKE_BINARY_DIR})
add_dependencies(${LIBRARY_NAME} antlr4_shared)
target_link_libraries(${LIBRARY_NAME} PUBLIC xacc PRIVATE CppMicroServices ${CMAKE_SOURCE_DIR}/dist/libantlr4-runtime.so)
if(APPLE)
set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "@loader_path")
set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
else()
set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN")
set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared")
endif()
if(XACC_BUILD_TESTS)
add_subdirectory(tests)
endif()
file (GLOB HEADERS *.hpp)
install(FILES ${HEADERS} DESTINATION include/quantum/gate)
install(TARGETS ${LIBRARY_NAME} DESTINATION lib)
#include "FermionListenerImpl.hpp"
namespace xacc {
namespace quantum {
void FermionListenerImpl::enterPlusorminus(FermionOperatorParser::PlusorminusContext * ctx) {
isMinus = ctx->getText() == "-";
}
void FermionListenerImpl::enterTerm(FermionOperatorParser::TermContext * ctx) {
// std::cout << "ENTER TERM: " << ctx->getText() << ", " << ctx->fermion().size() << "\n";
std::complex<double> coeff(1.0,0.0);
if (ctx->coeff() != nullptr) {
if (ctx->coeff()->complex() != nullptr) {
auto complexAsStr = ctx->coeff()->complex()->getText();
complexAsStr = complexAsStr.substr(1, complexAsStr.length() - 2);
auto split = xacc::split(complexAsStr, ',');
coeff = std::complex<double>(std::stod(split[0]), std::stod(split[1]));
} else if (ctx->coeff()->real() != nullptr) {
auto realAsStr = ctx->coeff()->real()->getText();
coeff = std::complex<double>(std::stod(realAsStr), 0.0);
}
}
if (isMinus) {
coeff *= -1.0;
isMinus=false;
}
Operators term;
for (int i = 0; i < ctx->fermion().size(); i++) {
auto str = ctx->fermion(i)->getText();
bool creation = false;
if (str.find("^") != std::string::npos) {
creation = true;
}
term.push_back({std::stoi(ctx->fermion(i)->op()->INT()->getText()), creation});
// std::cout << "HI: " << ctx->fermion(i)->getText() << ", " << "\n";
}
// std::cout << "SIZE OF TERMS: " << term.size() << "\n";
_op += FermionOperator(term, coeff);
// std::cout << "ENTER TERM: " << ctx->getText() << ", " << ctx->fermion().size() << "\n";
}
}
}
\ No newline at end of file
#include "FermionOperatorBaseListener.h"
#include "Utils.hpp"
#include "FermionOperator.hpp"
using namespace fermion;
namespace xacc {
namespace quantum {
class FermionOperatorErrorListener : public antlr4::BaseErrorListener {
public:
void syntaxError(antlr4::Recognizer *recognizer,
antlr4::Token *offendingSymbol, size_t line,
size_t charPositionInLine, const std::string &msg,
std::exception_ptr e) override {
std::ostringstream output;
output << "Invalid Pauli Operator source: ";
output << "line " << line << ":" << charPositionInLine << " " << msg;
xacc::XACCLogger::instance()->error(output.str());
}
};
class FermionListenerImpl : public FermionOperatorBaseListener {
protected:
FermionOperator _op;
bool isMinus = false;
public:
void enterPlusorminus(FermionOperatorParser::PlusorminusContext * ctx) override;
void enterTerm(FermionOperatorParser::TermContext * ctx) override;
FermionOperator getOperator() {return _op;}
};
}
}
\ No newline at end of file
#include "FermionOperator.hpp"
#include "FermionOperatorLexer.h"
#include "FermionListenerImpl.hpp"
#include "ObservableTransform.hpp"
#include "xacc_service.hpp"
namespace xacc {
namespace quantum {
FermionTerm &FermionTerm::operator*=(const FermionTerm &v) noexcept {
coeff() *= std::get<0>(v);
// std::cout << "FermionTerm: " << id() << ", " << FermionTerm::id(std::get<1>(v)) << "\n";
auto otherOps = std::get<1>(v);
for (auto &kv : otherOps) {
auto site = kv.first;
auto c_or_a = kv.second;
// std::cout << "HELLO: " << site << ", " << std::boolalpha << c_or_a << "\n";
Operators o = ops();
if (!o.empty()) {
auto it = std::find_if(o.begin(), o.end(),
[&](const std::pair<int, bool> &element) {
return element.first == site;
});
// std::cout << it->first << ", " << std::boolalpha << it->second << "\n";
if (it->first == site) {
if (it->second && c_or_a) {
// zero out this FermionTerm
ops().clear();
}
} else {
ops().push_back({site, c_or_a});
}
}
// This means, we have a op on same qubit in both
}
return *this;
}
FermionOperator::FermionOperator() {}
FermionOperator::FermionOperator(std::complex<double> c) {
terms.emplace(std::make_pair("I", c));
}
FermionOperator::FermionOperator(double c) {
terms.emplace(std::make_pair("I", c));
}
FermionOperator::FermionOperator(std::string fromStr) { fromString(fromStr); }
FermionOperator::FermionOperator(const FermionOperator &i) : terms(i.terms) {}
FermionOperator::FermionOperator(Operators operators) {
terms.emplace(std::make_pair(FermionTerm::id(operators), operators));
}
FermionOperator::FermionOperator(Operators operators,
std::complex<double> coeff) {
terms.emplace(std::piecewise_construct,
std::forward_as_tuple(FermionTerm::id(operators)),
std::forward_as_tuple(coeff, operators));
}
FermionOperator::FermionOperator(Operators operators, double coeff)
: FermionOperator(operators, std::complex<double>(coeff, 0)) {}
void FermionOperator::clear() { terms.clear(); }
std::vector<std::shared_ptr<Function>>
FermionOperator::observe(std::shared_ptr<Function> function) {
auto transform = xacc::getService<ObservableTransform>("jw");
return transform->transform(shared_from_this())->observe(function);
}
const std::string FermionOperator::toString() {
std::stringstream s;
for (auto &kv : terms) {
std::complex<double> c = std::get<0>(kv.second);
s << c << " ";
Operators ops = std::get<1>(kv.second);
std::vector<int> creations, annhilations;
for (auto &t : ops) {
// std::cout << "tostring " << t.first << ", " << t.second << "\n";
if (t.second) {
creations.push_back(t.first);
} else {
annhilations.push_back(t.first);
}
}
std::sort(creations.rbegin(), creations.rend());
std::sort(annhilations.rbegin(), annhilations.rend());
for (auto &t : creations) {
s << t << "^" << std::string(" ");
}
for (auto &t : annhilations) {
s << t << std::string(" ");
}
s << "+ ";
}
// std::cout << "tostring " << s.str() << "\n";
auto r = s.str().substr(0, s.str().size() - 2);
xacc::trim(r);
return r;
}
void FermionOperator::fromString(const std::string str) {
using namespace antlr4;
using namespace fermion;
ANTLRInputStream input(str);
FermionOperatorLexer lexer(&input);
lexer.removeErrorListeners();
lexer.addErrorListener(new FermionOperatorErrorListener());
CommonTokenStream tokens(&lexer);
FermionOperatorParser parser(&tokens);
parser.removeErrorListeners();
parser.addErrorListener(new FermionOperatorErrorListener());
// Walk the Abstract Syntax Tree
tree::ParseTree *tree = parser.fermionSrc();
FermionListenerImpl listener;
tree::ParseTreeWalker::DEFAULT.walk(&listener, tree);
clear();
operator+=(listener.getOperator());
}
const int FermionOperator::nBits() { return 0; }
FermionOperator &
FermionOperator::operator+=(const FermionOperator &v) noexcept {
for (auto &kv : v.terms) {
auto termId = kv.first;
auto otherTerm = kv.second;
if (terms.count(termId)) {
terms.at(termId).coeff() += otherTerm.coeff();
} else {
terms.insert({termId, otherTerm});
}
if (std::abs(terms[termId].coeff()) < 1e-12) {
terms.erase(termId);
}
}
return *this;
}
FermionOperator &
FermionOperator::operator-=(const FermionOperator &v) noexcept {
return operator+=(-1.0 * v);
}
FermionOperator &
FermionOperator::operator*=(const FermionOperator &v) noexcept {
std::unordered_map<std::string, FermionTerm> newTerms;
for (auto &kv : terms) {
for (auto &vkv : v.terms) {
auto multTerm = kv.second * vkv.second;
if (!multTerm.ops().empty()) {
auto id = multTerm.id();
if (!newTerms.insert({id, multTerm}).second) {
newTerms.at(id).coeff() += multTerm.coeff();
}
if (std::abs(newTerms.at(id).coeff()) < 1e-12) {
newTerms.erase(id);
}
}
}
}
terms = newTerms;
return *this;
}
bool FermionOperator::operator==(const FermionOperator &v) noexcept {
if (terms.size() != v.terms.size()) {
return false;
}
for (auto &kv : terms) {
bool found = false;
for (auto &vkv : v.terms) {
if (kv.second.operator==(vkv.second)) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
FermionOperator &FermionOperator::operator*=(const double v) noexcept {
return operator*=(std::complex<double>(v, 0));
}
FermionOperator &
FermionOperator::operator*=(const std::complex<double> v) noexcept {
for (auto &kv : terms) {
std::get<0>(kv.second) *= v;
}
return *this;
}
} // namespace quantum
} // namespace xacc
bool operator==(const xacc::quantum::FermionOperator &lhs,
const xacc::quantum::FermionOperator &rhs) {
if (lhs.getTerms().size() != rhs.getTerms().size()) {
return false;
}
for (auto &kv : lhs.getTerms()) {
bool found = false;
for (auto &vkv : rhs.getTerms()) {
if (kv.second.operator==(vkv.second)) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
\ No newline at end of file
grammar FermionOperator;
fermionSrc : term(plusorminus term) *;
plusorminus : '+' | '-';
term : coeff ? (fermion) *;
fermion : op;
op : INT '^' | INT;
coeff : complex | real;
complex : '('(real | INT)','(real | INT)')';
real : REAL;
comment : COMMENT;
COMMENT : '#' ~[\r\n] * EOL;
/* Real number */
REAL : ('-') ? INT ? '.' INT;
/* Non-negative integer */
INT : ('0'..'9') + ;
/* Strings include numbers and slashes */
/* Whitespaces, we skip'em */
WS : [ \t\r\n]->skip;
/* This is the end of the line, boys */
EOL : '\r' ? '\n';
#ifndef XACC_FERMIONOPERATOR_HPP_
#define XACC_FERMIONOPERATOR_HPP_
#include "Observable.hpp"
#include "operators.hpp"
#include <memory>
#include <unordered_map>
namespace xacc {
namespace quantum {
class FermionOperator;
}
} // namespace xacc
bool operator==(const xacc::quantum::FermionOperator &lhs,
const xacc::quantum::FermionOperator &rhs);
namespace xacc {
namespace quantum {
using Operator = std::pair<int, bool>;
using Operators = std::vector<Operator>;
// using SiteMap = std::map<Operators, std::complex<double>>;
using FermionTermTuple = std::tuple<std::complex<double>, Operators>;
class FermionTerm : public FermionTermTuple,
public tao::operators::commutative_multipliable<FermionTerm>,
public tao::operators::equality_comparable<FermionTerm> {
public:
FermionTerm() {
std::get<0>(*this) = std::complex<double>(1.0, 0.0);
std::get<1>(*this) = {};
}
FermionTerm(const FermionTerm &t) {
std::get<0>(*this) = std::get<0>(t);
std::get<1>(*this) = std::get<1>(t);
}
FermionTerm(std::complex<double> c) {
std::get<0>(*this) = c;
std::get<1>(*this) = {};
}
FermionTerm(std::complex<double> c, Operators ops) {
std::get<0>(*this) = c;
std::get<1>(*this) = ops;
}
FermionTerm(Operators ops) {
std::get<0>(*this) = std::complex<double>(1.0, 0.0);
std::get<1>(*this) = ops;
}
static const std::string id(const Operators &ops) {
std::vector<int> creations, annhilations;
for (auto &t : ops) {
if (t.second) {
creations.push_back(t.first);
} else {
annhilations.push_back(t.first);
}
}
std::sort(creations.rbegin(), creations.rend());
std::sort(annhilations.rbegin(), annhilations.rend());
std::stringstream s;
for (auto &t : creations) {
s << t << "^" << std::string(" ");
}
for (auto &t : annhilations) {
s << t << std::string(" ");
}
if (s.str().empty()) {
return "I";
}
return s.str();
}
const std::string id() {
std::vector<int> creations, annhilations;
for (auto &t : ops()) {
if (t.second) {
creations.push_back(t.first);
} else {
annhilations.push_back(t.first);
}
}
std::sort(creations.rbegin(), creations.rend());
std::sort(annhilations.rbegin(), annhilations.rend());
std::stringstream s;
for (auto &t : creations) {
s << t << "^" << std::string(" ");
}
for (auto &t : annhilations) {
s << t << std::string(" ");
}
if (s.str().empty()) {
return "I";
}
return s.str();
}
Operators &ops() { return std::get<1>(*this); }
std::complex<double> &coeff() { return std::get<0>(*this); }
FermionTerm &operator*=(const FermionTerm &v) noexcept;
bool operator==(const FermionTerm &v) noexcept {
return (std::get<1>(*this) == std::get<1>(v));
}
};
class FermionOperator
: public Observable,
public std::enable_shared_from_this<FermionOperator>,
public tao::operators::commutative_ring<FermionOperator>,
public tao::operators::equality_comparable<FermionOperator>,
public tao::operators::commutative_multipliable<FermionOperator, double>,
public tao::operators::commutative_multipliable<FermionOperator,
std::complex<double>> {