Commit 3e62f823 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Merge branch 'master' into tnguyen/pyxasm

parents 50b2fa57 0083c54d
Loading
Loading
Loading
Loading
+47 −15
Original line number Diff line number Diff line
@@ -118,7 +118,8 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction {
  const std::string name() const override { return "py-objective-impl"; }
  const std::string description() const override { return ""; }
  PyObjectiveFunction(py::object q, qcor::PauliOperator &qq, const int n_dim,
                      const std::string &helper_name)
                      const std::string &helper_name,
                      xacc::HeterogeneousMap opts = {})
      : py_kernel(q) {
    // Set the OptFunction dimensions
    _dim = n_dim;
@@ -128,6 +129,9 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction {

    // Store the observable pointer and give it to the helper
    observable = xacc::as_shared_ptr(&qq);
    options = opts;
    options.insert("observable", observable);
    helper->set_options(options);
    helper->update_observable(observable);

    // Extract the QJIT source code
@@ -141,21 +145,29 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction {

  // Evaluate this ObjectiveFunction at the dictionary of kernel args,
  // return the scalar value
  double operator()(const KernelArgDict args) {
  double operator()(const KernelArgDict args, std::vector<double> &dx) {
    std::function<std::shared_ptr<CompositeInstruction>(std::vector<double>)>
        kernel_evaluator = [&](std::vector<double> x) {
          qreg = ::qalloc(observable->nBits());
          auto _args =
              py_kernel.attr("translate")(qreg, x).cast<KernelArgDict>();
          // Map the kernel args to a hetmap
          xacc::HeterogeneousMap m;
    for (auto &item : args) {
          for (auto &item : _args) {
            KernelArgDictToHeterogeneousMap vis(m, item.first);
            mpark::visit(vis, item.second);
          }

          // Get the kernel as a CompositeInstruction
    auto kernel_name = py_kernel.attr("kernel_name")().cast<std::string>();
    kernel = qjit.extract_composite_with_hetmap(kernel_name, m);
          auto kernel_name =
              py_kernel.attr("kernel_name")().cast<std::string>();
          return qjit.extract_composite_with_hetmap(kernel_name, m);
        };

    kernel = kernel_evaluator(current_iterate_parameters);
    helper->update_kernel(kernel);
    helper->update_options("kernel-evaluator", kernel_evaluator);

    // FIXME, handle gradients
    std::vector<double> dx;
    return (*helper)(qreg, dx);
  }

@@ -169,7 +181,7 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction {
    qreg = ::qalloc(observable->nBits());
    auto args = py_kernel.attr("translate")(qreg, x).cast<KernelArgDict>();
    // args will be a dictionary, arg_name to arg
    return operator()(args);
    return operator()(args, dx);
  }

  virtual double operator()(xacc::internal_compiler::qreg &qreg,
@@ -324,6 +336,14 @@ PYBIND11_MODULE(_pyqcor, m) {
          [](qcor::ObjectiveFunction &obj, std::vector<double> x) {
            return obj(x);
          },
          "")
      .def(
          "__call__",
          [](qcor::ObjectiveFunction &obj, std::vector<double> x,
             std::vector<double> &dx) {
            auto val = obj(x, dx);
            return std::make_pair(val, dx);
          },
          "");

  m.def(
@@ -336,6 +356,18 @@ PYBIND11_MODULE(_pyqcor, m) {
        return obj;
      },
      "");
  m.def(
      "createObjectiveFunction",
      [](py::object kernel, qcor::PauliOperator &obs, const int n_params,
         PyHeterogeneousMap &options) {
        auto nativeHetMap = heterogeneousMapConvert(options);
        auto q = ::qalloc(obs.nBits());
        std::shared_ptr<qcor::ObjectiveFunction> obj =
            std::make_shared<qcor::PyObjectiveFunction>(kernel, obs, n_params,
                                                        "vqe", nativeHetMap);
        return obj;
      },
      "");

  // qsim sub-module bindings:
  {
+18 −0
Original line number Diff line number Diff line
@@ -32,6 +32,24 @@ class TestVQEObjectiveFunction(unittest.TestCase):

        print(ansatz.openqasm(q, [2.2]))

    def test_simple_deuteron_with_grad(self):

        @qjit
        def ansatz(q: qreg, theta: float):
            X(q[0])
            Ry(q[1], theta)
            CX(q[1], q[0])
        
        H = -2.1433 * X(0) * X(1) - 2.1433 * \
            Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907
        
        n_params = 1
        obj = createObjectiveFunction(ansatz, H, n_params, {'gradient-strategy':'parameter-shift'})
        optimizer = createOptimizer('nlopt', {'nlopt-optimizer':'l-bfgs'})
        results = optimizer.optimize(obj)
        self.assertAlmostEqual(results[0], -1.74, places=1)
        print(results)


if __name__ == '__main__':
    unittest.main()
+146 −78
Original line number Diff line number Diff line
#pragma once

#include <functional>

#include "qcor_observable.hpp"
#include "qcor_utils.hpp"
#include "quantum_kernel.hpp"
#include <functional>

namespace qcor {

@@ -50,7 +51,8 @@ public:
  }
  // Set any extra options needed for the objective function
  virtual void set_options(HeterogeneousMap &opts) { options = opts; }
  template <typename T> void update_options(const std::string key, T value) {
  template <typename T>
  void update_options(const std::string key, T value) {
    options.insert(key, value);
  }

@@ -61,6 +63,56 @@ public:
  }
};

namespace __internal__ {
// Get the objective function from the service registry
std::shared_ptr<ObjectiveFunction> get_objective(const std::string &type);

template <typename T>
std::shared_ptr<T> qcor_as_shared(T *t) {
  return std::shared_ptr<T>(t, [](T *const) {});
}

template <std::size_t... Is>
auto create_tuple_impl(std::index_sequence<Is...>,
                       const std::vector<double> &arguments) {
  return std::make_tuple(arguments[Is]...);
}

template <std::size_t N>
auto create_tuple(const std::vector<double> &arguments) {
  return create_tuple_impl(std::make_index_sequence<N>{}, arguments);
}

struct ArgsTranslatorAutoGenerator {
  std::shared_ptr<ArgsTranslator<qreg, std::vector<double>>> operator()(
      qreg &q, std::tuple<qreg, std::vector<double>> &&) {
    return std::make_shared<ArgsTranslator<qreg, std::vector<double>>>(
        [&](const std::vector<double> &x) { return std::make_tuple(q, x); });
  }

  template <typename... DoubleTypes>
  std::shared_ptr<ArgsTranslator<qreg, DoubleTypes...>> operator()(
      qreg &q, std::tuple<qreg, DoubleTypes...> &&t) {
    if constexpr ((std::is_same<DoubleTypes, double>::value && ...)) {
      return std::make_shared<ArgsTranslator<qreg, DoubleTypes...>>(
          [&](const std::vector<double> &x) {
            auto qreg_tuple = std::make_tuple(q);
            auto double_tuple = create_tuple<sizeof...(DoubleTypes)>(x);
            return std::tuple_cat(qreg_tuple, double_tuple);
          });
    } else {
      error(
          "QCOR cannot auto-generate a ArgsTranslator for this "
          "ObjectiveFunction. Please provide a custom ArgsTranslator to "
          "createObjectiveFunction.");
      return std::make_shared<ArgsTranslator<qreg, DoubleTypes...>>(
          [&](const std::vector<double> &x) { return t; });
    }
  }
};

}  // namespace __internal__

template <typename... KernelArgs>
class ObjectiveFunctionImpl : public ObjectiveFunction {
 private:
@@ -77,7 +129,7 @@ private:
 protected:
  std::shared_ptr<LocalArgsTranslator> args_translator;
  std::shared_ptr<ObjectiveFunction> helper;
  xacc::internal_compiler::qreg &qreg;
  xacc::internal_compiler::qreg qreg;

 public:
  ObjectiveFunctionImpl(void *k_ptr, std::shared_ptr<Observable> obs,
@@ -97,6 +149,25 @@ public:
    helper->update_observable(observable);
    helper->set_options(options);
  }

  ObjectiveFunctionImpl(void *k_ptr, std::shared_ptr<Observable> obs,
                        std::shared_ptr<ObjectiveFunction> obj_helper,
                        const int dim, HeterogeneousMap opts) {
    qreg = ::qalloc(obs->nBits());
    kernel_ptr = k_ptr;
    observable = obs;
    __internal__::ArgsTranslatorAutoGenerator auto_gen;
    args_translator = auto_gen(qreg, std::tuple<KernelArgs...>());
    // args_translator = translator;
    helper = obj_helper;
    _dim = dim;
    _function = *this;
    options = opts;
    options.insert("observable", observable);
    helper->update_observable(observable);
    helper->set_options(options);
  }

  void set_options(HeterogeneousMap &opts) override {
    options = opts;
    helper->set_options(opts);
@@ -164,62 +235,12 @@ public:
  const std::string description() const override { return ""; }
};

namespace __internal__ {
// Get the objective function from the service registry
std::shared_ptr<ObjectiveFunction> get_objective(const std::string &type);

template <typename T> std::shared_ptr<T> qcor_as_shared(T *t) {
  return std::shared_ptr<T>(t, [](T *const) {});
}

template <std::size_t... Is>
auto create_tuple_impl(std::index_sequence<Is...>,
                       const std::vector<double> &arguments) {
  return std::make_tuple(arguments[Is]...);
}

template <std::size_t N>
auto create_tuple(const std::vector<double> &arguments) {
  return create_tuple_impl(std::make_index_sequence<N>{}, arguments);
}

struct ArgsTranslatorAutoGenerator {

  std::shared_ptr<ArgsTranslator<qreg, std::vector<double>>>
  operator()(qreg &q, std::tuple<qreg, std::vector<double>> &&) {
    return std::make_shared<ArgsTranslator<qreg, std::vector<double>>>(
        [&](const std::vector<double> &x) { return std::make_tuple(q, x); });
  }

  template <typename... DoubleTypes>
  std::shared_ptr<ArgsTranslator<qreg, DoubleTypes...>>
  operator()(qreg &q, std::tuple<qreg, DoubleTypes...> &&t) {
    if constexpr ((std::is_same<DoubleTypes, double>::value && ...)) {
      return std::make_shared<ArgsTranslator<qreg, DoubleTypes...>>(
          [&](const std::vector<double> &x) {
            auto qreg_tuple = std::make_tuple(q);
            auto double_tuple = create_tuple<sizeof...(DoubleTypes)>(x);
            return std::tuple_cat(qreg_tuple, double_tuple);
          });
    } else {
      error("QCOR cannot auto-generate a ArgsTranslator for this "
            "ObjectiveFunction. Please provide a custom ArgsTranslator to "
            "createObjectiveFunction.");
      return std::make_shared<ArgsTranslator<qreg, DoubleTypes...>>(
          [&](const std::vector<double> &x) { return t; });
    }
  }
};

} // namespace __internal__

template <typename... Args>
std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
                                   Args...),
    std::shared_ptr<Observable> observable, qreg &q, const int nParams,
    HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective("vqe");
  __internal__::ArgsTranslatorAutoGenerator auto_gen;
  auto args_translator = auto_gen(q, std::tuple<Args...>());
@@ -237,7 +258,6 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
                                   Args...),
    std::shared_ptr<Observable> observable, qreg &q, const int nParams,
    HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective(obj_name);
  __internal__::ArgsTranslatorAutoGenerator auto_gen;
  auto args_translator = auto_gen(q, std::tuple<Args...>());
@@ -254,7 +274,6 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
                                   Args...),
    Observable &observable, qreg &q, const int nParams,
    HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective("vqe");
  __internal__::ArgsTranslatorAutoGenerator auto_gen;
  auto args_translator = auto_gen(q, std::tuple<Args...>());
@@ -273,7 +292,6 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
                                   Args...),
    Observable &observable, qreg &q, const int nParams,
    HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective(obj_name);
  __internal__::ArgsTranslatorAutoGenerator auto_gen;
  auto args_translator = auto_gen(q, std::tuple<Args...>());
@@ -290,7 +308,6 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
                                   Args...),
    qreg &q, const int nParams, HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective("vqe");
  __internal__::ArgsTranslatorAutoGenerator auto_gen;
  auto args_translator = auto_gen(q, std::tuple<Args...>());
@@ -298,8 +315,7 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);

  std::map<int, std::string> all_zs;
  for (int i = 0; i < q.size(); i++)
    all_zs.insert({i, "Z"});
  for (int i = 0; i < q.size(); i++) all_zs.insert({i, "Z"});
  auto observable = std::make_shared<PauliOperator>(all_zs);
  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
      kernel_ptr, observable, q, args_translator, helper, nParams, options);
@@ -311,7 +327,6 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
                                   Args...),
    qreg &q, const int nParams, HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective(obj_name);
  __internal__::ArgsTranslatorAutoGenerator auto_gen;
  auto args_translator = auto_gen(q, std::tuple<Args...>());
@@ -319,8 +334,7 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);

  std::map<int, std::string> all_zs;
  for (int i = 0; i < q.size(); i++)
    all_zs.insert({i, "Z"});
  for (int i = 0; i < q.size(); i++) all_zs.insert({i, "Z"});
  auto observable = std::make_shared<PauliOperator>(all_zs);
  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
      kernel_ptr, observable, q, args_translator, helper, nParams, options);
@@ -335,7 +349,6 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    std::shared_ptr<Observable> observable,
    std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
    const int nParams, HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective("vqe");

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
@@ -352,7 +365,6 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    std::shared_ptr<Observable> observable,
    std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
    const int nParams, HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective(obj_name);

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
@@ -368,7 +380,6 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    Observable &observable,
    std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
    const int nParams, HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective("vqe");

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
@@ -386,7 +397,6 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    Observable &observable,
    std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
    const int nParams, HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective(obj_name);

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
@@ -402,14 +412,12 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
                                   Args...),
    std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
    const int nParams, HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective("vqe");

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);

  std::map<int, std::string> all_zs;
  for (int i = 0; i < q.size(); i++)
    all_zs.insert({i, "Z"});
  for (int i = 0; i < q.size(); i++) all_zs.insert({i, "Z"});
  auto observable = std::make_shared<PauliOperator>(all_zs);
  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
      kernel_ptr, observable, q, args_translator, helper, nParams, options);
@@ -422,17 +430,77 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
                                   Args...),
    std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
    const int nParams, HeterogeneousMap &&options = {}) {

  auto helper = qcor::__internal__::get_objective(obj_name);

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);

  std::map<int, std::string> all_zs;
  for (int i = 0; i < q.size(); i++)
    all_zs.insert({i, "Z"});
  for (int i = 0; i < q.size(); i++) all_zs.insert({i, "Z"});
  auto observable = std::make_shared<PauliOperator>(all_zs);
  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
      kernel_ptr, observable, q, args_translator, helper, nParams, options);
}

/// no qreg args

template <typename... Args>
std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
                                   Args...),
    std::shared_ptr<Observable> observable, const int nParams,
    HeterogeneousMap &&options = {}) {
  auto helper = qcor::__internal__::get_objective("vqe");

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);

  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
      kernel_ptr, observable, helper, nParams, options);
}

template <typename... Args>
std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    const std::string obj_name,
    void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
                                   Args...),
    std::shared_ptr<Observable> observable, const int nParams,
    HeterogeneousMap &&options = {}) {
  auto helper = qcor::__internal__::get_objective(obj_name);

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);

  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
      kernel_ptr, observable, helper, nParams, options);
}

template <typename... Args>
std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
                                   Args...),
    Observable &observable, const int nParams,
    HeterogeneousMap &&options = {}) {
  auto helper = qcor::__internal__::get_objective("vqe");

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);

  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
      kernel_ptr, __internal__::qcor_as_shared(&observable), helper, nParams,
      options);
}

template <typename... Args>
std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    const std::string obj_name,
    void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
                                   Args...),
    Observable &observable, const int nParams,
    HeterogeneousMap &&options = {}) {
  auto helper = qcor::__internal__::get_objective(obj_name);

  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);

  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
      kernel_ptr, __internal__::qcor_as_shared(&observable), helper, nParams,
      options);
}

}  // namespace qcor
 No newline at end of file
+4 −0
Original line number Diff line number Diff line
@@ -62,6 +62,10 @@ def main(argv=None):
        sys.argv.remove('-qpu')
        sys.argv += ['-D__internal__qcor__compile__backend=\"'+accName+'\"']
        sHandlerArgs = ['-Xclang', '-plugin-arg-qcor-args', '-Xclang', '-qpu', '-Xclang', '-plugin-arg-qcor-args', '-Xclang', accName]
    else:
        accName = 'qpp'
        sys.argv += ['-D__internal__qcor__compile__backend=\"'+accName+'\"']
        sHandlerArgs = ['-Xclang', '-plugin-arg-qcor-args', '-Xclang', '-qpu', '-Xclang', '-plugin-arg-qcor-args', '-Xclang', accName]

    # Get the shots if necessary
    shots = 0
+5 −1
Original line number Diff line number Diff line
@@ -59,6 +59,10 @@ def main(argv=None):
        sys.argv.remove('-qpu')
        sys.argv += ['-D__internal__qcor__compile__backend=\"'+accName+'\"']
        sHandlerArgs = ['-Xclang', '-plugin-arg-qcor-args', '-Xclang', '-qpu', '-Xclang', '-plugin-arg-qcor-args', '-Xclang', accName]
    else:
        accName = 'qpp'
        sys.argv += ['-D__internal__qcor__compile__backend=\"'+accName+'\"']
        sHandlerArgs = ['-Xclang', '-plugin-arg-qcor-args', '-Xclang', '-qpu', '-Xclang', '-plugin-arg-qcor-args', '-Xclang', accName]
        
    # Get the shots if necessary
    shots = 0