/******************************************************************************* * Copyright (c) 2019 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_UTILS_PAULIOPERATOR_HPP_ #define QUANTUM_UTILS_PAULIOPERATOR_HPP_ #include #include #include #include #include #include #include "Observable.hpp" #include "IR.hpp" #include "Cloneable.hpp" // Putting this here due to clang error // not able to find operator!= from operators.hpp namespace xacc { namespace quantum { class PauliOperator; } } // namespace xacc bool operator==(const xacc::quantum::PauliOperator &lhs, const xacc::quantum::PauliOperator &rhs); #include "operators.hpp" namespace xacc { namespace quantum { // A Term can be a coefficient, a variable coefficient, and the terms themselves using TermTuple = std::tuple, std::string, std::map>; using c = std::complex; using ActionResult = std::pair; enum ActionType { Bra, Ket }; class Term : public TermTuple, public tao::operators::commutative_multipliable, public tao::operators::equality_comparable { protected: // static std::map> void create_map() { // static std::map> m; pauliProducts.insert({"II", {c(1.0, 0.0), "I"}}); pauliProducts.insert({"IX", {c(1.0, 0.0), "X"}}); pauliProducts.insert({"XI", {c(1.0, 0.0), "X"}}); pauliProducts.insert({"IY", {c(1.0, 0.0), "Y"}}); pauliProducts.insert({"YI", {c(1.0, 0.0), "Y"}}); pauliProducts.insert({"ZI", {c(1.0, 0.0), "Z"}}); pauliProducts.insert({"IZ", {c(1.0, 0.0), "Z"}}); pauliProducts.insert({"XX", {c(1.0, 0.0), "I"}}); pauliProducts.insert({"YY", {c(1.0, 0.0), "I"}}); pauliProducts.insert({"ZZ", {c(1.0, 0.0), "I"}}); pauliProducts.insert({"XY", {c(0.0, 1.0), "Z"}}); pauliProducts.insert({"XZ", {c(0.0, -1.0), "Y"}}); pauliProducts.insert({"YX", {c(0.0, -1.0), "Z"}}); pauliProducts.insert({"YZ", {c(0.0, 1.0), "X"}}); pauliProducts.insert({"ZX", {c(0.0, 1.0), "Y"}}); pauliProducts.insert({"ZY", {c(0.0, -1.0), "X"}}); // return m; } std::map> pauliProducts; public: Term() { std::get<0>(*this) = std::complex(0, 0); std::get<1>(*this) = ""; std::get<2>(*this) = {}; create_map(); } Term(const Term &t) { std::get<0>(*this) = std::get<0>(t); std::get<1>(*this) = std::get<1>(t); std::get<2>(*this) = std::get<2>(t); create_map(); } Term(std::complex c) { std::get<0>(*this) = c; std::get<1>(*this) = ""; std::get<2>(*this) = {}; create_map(); } Term(double c) { std::get<0>(*this) = std::complex(c, 0); std::get<1>(*this) = ""; std::get<2>(*this) = {}; create_map(); } Term(std::complex c, std::map ops) { std::get<0>(*this) = c; std::get<1>(*this) = ""; std::get<2>(*this) = ops; create_map(); } Term(std::string var) { std::get<0>(*this) = std::complex(1, 0); std::get<1>(*this) = var; std::get<2>(*this) = {}; create_map(); } Term(std::complex c, std::string var) { std::get<0>(*this) = c; std::get<1>(*this) = var; std::get<2>(*this) = {}; create_map(); } Term(std::string var, std::map ops) { std::get<0>(*this) = std::complex(1, 0); std::get<1>(*this) = var; std::get<2>(*this) = ops; create_map(); } Term(std::complex c, std::string var, std::map ops) { std::get<0>(*this) = c; std::get<1>(*this) = var; std::get<2>(*this) = ops; create_map(); } Term(std::map ops) { std::get<0>(*this) = std::complex(1, 0); std::get<1>(*this) = ""; std::get<2>(*this) = ops; create_map(); } static const std::string id(const std::map &ops, const std::string &var = "") { std::string s; s = var; for (auto &t : ops) { if (t.second != "I") { s += t.second + std::to_string(t.first); } } if (s.empty()) { return "I"; } return s; } const std::string id() const { std::string s; s = std::get<1>(*this); for (auto &t : std::get<2>(*this)) { if (t.second != "I") { s += t.second + std::to_string(t.first); } } if (s.empty()) { return "I"; } return s; } std::map &ops() { return std::get<2>(*this); } bool isIdentity() { if (ops().empty() || (ops().size() == 1 && ops().begin()->second == "I")) { return true; } else { return false; } } std::complex &coeff() { return std::get<0>(*this); } std::string &var() { return std::get<1>(*this); } Term &operator*=(const Term &v) noexcept; bool operator==(const Term &v) noexcept { return (std::get<1>(*this) == std::get<1>(v) && ops() == std::get<2>(v)); } std::vector getSparseMatrixElements(const int nQubits); ActionResult action(const std::string &bitString, ActionType type); std::pair, std::vector> toBinaryVector(const int nQubits); }; class PauliOperator : public xacc::Observable, public xacc::Cloneable, public tao::operators::commutative_ring, public tao::operators::equality_comparable, public tao::operators::commutative_multipliable, public tao::operators::commutative_multipliable> { protected: std::map terms; public: std::shared_ptr clone() override { return std::make_shared(); } std::map::iterator begin() { return terms.begin(); } std::map::iterator end() { return terms.end(); } PauliOperator(); PauliOperator(std::complex c); PauliOperator(double c); PauliOperator(std::string fromString); PauliOperator(std::complex c, std::string var); PauliOperator(const PauliOperator &i); PauliOperator(std::map operators); PauliOperator(std::map operators, std::string var); PauliOperator(std::map operators, std::complex coeff); PauliOperator(std::map operators, double coeff); PauliOperator(std::map operators, std::complex coeff, std::string var); std::vector> observe(std::shared_ptr function) override; std::vector> observe(std::shared_ptr function, const HeterogeneousMap &grouping_options) override; std::vector> getSubTerms() override { std::vector> ret; for (auto &term : getTerms()) { ret.emplace_back( new PauliOperator(term.second.ops(), term.second.coeff())); } return ret; } std::vector> getNonIdentitySubTerms() override { std::vector> ret; for (auto &term : getTerms()) { if (term.first != "I") { ret.emplace_back( new PauliOperator(term.second.ops(), term.second.coeff())); } } return ret; } std::shared_ptr getIdentitySubTerm() override { for (auto &term : getTerms()) { if (term.first == "I") { return std::make_shared(term.second.ops(), term.second.coeff()); } } return nullptr; } std::complex coefficient() override; const std::vector>> computeActionOnKet(const std::string &bitString); const std::vector>> computeActionOnBra(const std::string &bitString); const int nTerms(); std::pair, std::vector> toBinaryVectors(const int nQubits) { return getTerms().begin()->second.toBinaryVector(nQubits); } const std::string toString() override; void fromString(const std::string str) override; bool contains(PauliOperator &op); bool commutes(PauliOperator &op); void mapQubitSites(std::map &siteMap) { PauliOperator op; for (auto &termKv : *this) { auto ops = termKv.second.ops(); std::map nops; for (auto &kv : ops) { nops.insert({siteMap[kv.first], kv.second}); } op += PauliOperator(nops, termKv.second.coeff()); } *this = op; } void clear(); std::map getTerms() const { return terms; } std::vector getSparseMatrixElements() {return to_sparse_matrix();} std::vector> toDenseMatrix(const int nQubits); std::vector to_sparse_matrix() override; std::shared_ptr toXACCIR(); void fromXACCIR(std::shared_ptr ir); PauliOperator eval(const std::map> varToValMap); bool isClose(PauliOperator &other); int nQubits(); const int nBits() override { return nQubits(); } PauliOperator &operator+=(const PauliOperator &v) noexcept; PauliOperator &operator-=(const PauliOperator &v) noexcept; PauliOperator &operator*=(const PauliOperator &v) noexcept; bool operator==(const PauliOperator &v) noexcept; PauliOperator &operator*=(const double v) noexcept; PauliOperator &operator*=(const std::complex v) noexcept; const std::string name() const override { return "pauli"; } const std::string description() const override { return ""; } void fromOptions(const HeterogeneousMap &options) override { return; } std::shared_ptr commutator(std::shared_ptr obs) override; PauliOperator hermitianConjugate() const; void normalize() override; virtual double postProcess(std::shared_ptr buffer, const std::string &postProcessTask, const HeterogeneousMap &extra_data) override; }; } // namespace quantum template const quantum::PauliOperator HeterogeneousMap::get(const std::string key) const; } // namespace xacc #endif