Commit 60d6dd02 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Setup pyxasm to support for i,var in enumerate(..), added createOperator to map OpenFermion to qcor

parent 4410d6e2
Loading
Loading
Loading
Loading
+8 −9
Original line number Diff line number Diff line
@@ -69,15 +69,14 @@ void PyXasmTokenCollector::collect(clang::Preprocessor &PP,
    line += PP.getSpelling(Toks[i]);
    if (Toks[i].is(clang::tok::TokenKind::kw_for)) {
      // Right now we only assume 'for var in range'
      line += " ";
      // add var space
      i += 1;
      line += PP.getSpelling(Toks[i]);
      line += " ";
      // add 'in space'
      i += 1;
      line += PP.getSpelling(Toks[i]);
      line += " ";
      // or 'for i , var in enumerate( list_var ):
      // Slurp all elements of the for loop stmt, separate with spaces
      std::string for_stmt = " "; i++;
      while(Toks[i].isNot(clang::tok::TokenKind::colon)) {
        for_stmt += PP.getSpelling(Toks[i]) + " ";
        i++;
      }
      line += for_stmt;
    }

    // If statement:
+16 −6
Original line number Diff line number Diff line
@@ -3,9 +3,9 @@

#include "IRProvider.hpp"
#include "pyxasmBaseVisitor.h"
#include "qcor_utils.hpp"
#include "qrt.hpp"
#include "xacc.hpp"
#include "qcor_utils.hpp"

using namespace pyxasm;

@@ -216,14 +216,25 @@ class pyxasm_visitor : public pyxasmBaseVisitor {
  }

  antlrcpp::Any visitFor_stmt(pyxasmParser::For_stmtContext *context) override {
    auto counter_expr = context->exprlist()->expr()[0];
    auto iter_container = context->testlist()->test()[0]->getText();
    // Rewrite:
    // Python: "for <var> in <expr>:"
    // C++: for (auto& var: <expr>) {}
    // C++: for (auto var: <expr>) {}
    // Note: we add range(int) as a C++ function to support this common pattern.
    // or
    // Python: "for <idx>,<var> in enumerate(<listvar>):"
    // C++: for (auto [idx, var] : enumerate(listvar))
    auto iter_container = context->testlist()->test()[0]->getText();
    std::string counter_expr = context->exprlist()->expr()[0]->getText();
    if (context->exprlist()->expr().size() > 1) {
      counter_expr = "[" + counter_expr;
      for (int i = 1; i < context->exprlist()->expr().size(); i++) {
        counter_expr += ", " + context->exprlist()->expr()[i]->getText();
      }
      counter_expr += "]";
    }

    std::stringstream ss;
    ss << "for (auto &" << counter_expr->getText() << " : " << iter_container
    ss << "for (auto " << counter_expr << " : " << iter_container
       << ") {\n";
    result.first = ss.str();
    in_for_loop = true;
@@ -232,7 +243,6 @@ class pyxasm_visitor : public pyxasmBaseVisitor {

  antlrcpp::Any visitExpr_stmt(pyxasmParser::Expr_stmtContext *ctx) override {
    if (ctx->ASSIGN().size() == 1 && ctx->testlist_star_expr().size() == 2) {

      // Handle simple assignment: a = expr
      std::stringstream ss;
      const std::string lhs = ctx->testlist_star_expr(0)->getText();
+3 −4
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ from qcor import *
@qjit
def ansatz(q: qreg, x: List[float], exp_args: List[FermionOperator]):
    X(q[0])
    for i in range(len(exp_args)):
    for i, exp_arg in enumerate(exp_args):
        exp_i_theta(q, x[i], exp_args[i])

exp_args = [adag(0) * a(1) - adag(1)*a(0), adag(0)*a(2) - adag(2)*a(0)]
@@ -28,11 +28,10 @@ H = createOperator(

# Create the ObjectiveFunction, specify central finite diff gradient
obj = createObjectiveFunction(
    ansatz, H, 2)
    #, {'gradient-strategy': 'central', 'step': 1e-1})
    ansatz, H, 2, {'gradient-strategy': 'central', 'step': 1e-2})

# create the lbfgs optimizer
optimizer = createOptimizer('nlopt')#, {'algorithm': 'l-bfgs', 'ftol': 1e-3})
optimizer = createOptimizer('nlopt', {'algorithm': 'l-bfgs', 'ftol': 1e-3})

# Run VQE...
results = optimizer.optimize(obj)
+18 −6
Original line number Diff line number Diff line
@@ -56,7 +56,8 @@ using AllowedKernelArgTypes =
    xacc::Variant<bool, int, double, std::string, xacc::internal_compiler::qreg,
                  std::vector<double>, std::vector<int>, qcor::PauliOperator,
                  qcor::FermionOperator, qcor::PairList<int>,
                  std::vector<qcor::PauliOperator>, std::vector<qcor::FermionOperator>>;
                  std::vector<qcor::PauliOperator>,
                  std::vector<qcor::FermionOperator>>;

// We will take as input a mapping of arg variable names to the argument itself.
using KernelArgDict = std::map<std::string, AllowedKernelArgTypes>;
@@ -96,7 +97,8 @@ xacc::HeterogeneousMap heterogeneousMapConvert(
  return result;
}

std::shared_ptr<qcor::Observable> convertToPauliOperator(py::object op) {
std::shared_ptr<qcor::Observable> convertToQCOROperator(
    py::object op, bool keep_fermion = false) {
  if (py::hasattr(op, "terms")) {
    // this is from openfermion
    if (py::hasattr(op, "is_two_body_number_conserving")) {
@@ -134,9 +136,16 @@ std::shared_ptr<qcor::Observable> convertToPauliOperator(py::object op) {
        }
      }
      auto obs_tmp = qcor::createOperator("fermion", ss.str());
      if (keep_fermion) {
        return obs_tmp;
      } else {
        return qcor::operatorTransform("jw", obs_tmp);
      }

    } else {
      if (keep_fermion) {
        xacc::error("Error - you asked for a qcor::FermionOperator, but this is an OpenFermion QubitOperator.");
      }
      // this is a qubit  operator
      auto terms = op.attr("terms");
      // terms is a list of tuples
@@ -528,7 +537,7 @@ PYBIND11_MODULE(_pyqcor, m) {
  m.def(
      "createObjectiveFunction",
      [](py::object kernel, py::object &py_obs, const int n_params) {
        auto obs = convertToPauliOperator(py_obs);
        auto obs = convertToQCOROperator(py_obs);
        auto q = ::qalloc(obs->nBits());
        std::shared_ptr<qcor::ObjectiveFunction> obj =
            std::make_shared<qcor::PyObjectiveFunction>(kernel, obs, n_params,
@@ -553,7 +562,7 @@ PYBIND11_MODULE(_pyqcor, m) {
      [](py::object kernel, py::object &py_obs, const int n_params,
         PyHeterogeneousMap &options) {
        auto nativeHetMap = heterogeneousMapConvert(options);
        auto obs = convertToPauliOperator(py_obs);
        auto obs = convertToQCOROperator(py_obs);
        auto q = ::qalloc(obs->nBits());
        std::shared_ptr<qcor::ObjectiveFunction> obj =
            std::make_shared<qcor::PyObjectiveFunction>(kernel, obs, n_params,
@@ -578,6 +587,9 @@ PYBIND11_MODULE(_pyqcor, m) {
        return qcor::createOperator(type, nativeHetMap);
      },
      "");
  m.def("createOperator", [](const std::string &type, py::object pyobject) {
    return convertToQCOROperator(pyobject, type == "fermion");
  });
  m.def(
      "createObservable",
      [](const std::string &repr) { return qcor::createOperator(repr); }, "");
@@ -612,7 +624,7 @@ PYBIND11_MODULE(_pyqcor, m) {
  m.def(
      "internal_observe",
      [](std::shared_ptr<CompositeInstruction> kernel, py::object obs) {
        auto observable = convertToPauliOperator(obs);
        auto observable = convertToQCOROperator(obs);
        auto q = ::qalloc(observable->nBits());
        return qcor::observe(kernel, observable, q);
      },
+13 −1
Original line number Diff line number Diff line
@@ -252,6 +252,18 @@ class TestKernelJIT(unittest.TestCase):
        comp = testFor.extract_composite(q)
        self.assertEqual(comp.nInstructions(), 5)   

    def test_for_loop_enumerate(self):
        @qjit
        def ansatz(q: qreg, x: List[float], exp_args: List[FermionOperator]):
            X(q[0])
            for i, exp_arg in enumerate(exp_args):
                exp_i_theta(q, x[i], exp_args[i])

        exp_args = [adag(0) * a(1) - adag(1)*a(0), adag(0)*a(2) - adag(2)*a(0)]
        H = createOperator('5.907 - 2.1433 X0X1 - 2.1433 Y0Y1 + .21829 Z0 - 6.125 Z1 + 9.625 - 9.625 Z2 - 3.91 X1 X2 - 3.91 Y1 Y2')
        energy = ansatz.observe(H, qalloc(3), [0.7118083109334505, 0.27387413138588135], exp_args)
        self.assertAlmostEqual(energy, -2.044, places=1)

    def test_multiple_kernels(self):
        @qjit
        def apply_H(q : qreg):
Loading