Commit 78d58e8b authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Support qcor kernel



Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent c3ae8325
Loading
Loading
Loading
Loading
+103 −0
Original line number Diff line number Diff line
#pragma once

#include "objective_function.hpp"
#include "qcor_observable.hpp"
#include "qcor_utils.hpp"
#include "quantum_kernel.hpp"

#include <functional>

namespace qcor {

class KernelFunctor {
protected:
  // Quantum kernel function pointer, we will use
  // this to cast to kernel(composite, args...).
  // Doing it this way means we don't template KernelFunctor
  void *kernel_ptr;

  size_t nbParams;

  // CompositeInstruction representation of the
  // evaluated quantum kernel
  std::shared_ptr<CompositeInstruction> kernel;
  qreg q;

public:
  KernelFunctor(qreg qReg) : q(qReg){};
  qreg &getQreg() { return q; }
  size_t nParams() const { return nbParams; }
  virtual std::shared_ptr<CompositeInstruction>
  evaluate_kernel(const std::vector<double> &in_params) {
    return nullptr;
  }
};

template <typename... KernelArgs>
class KernelFunctorImpl : public KernelFunctor {
private:
  using LocalArgsTranslator = ArgsTranslator<KernelArgs...>;

  std::shared_ptr<CompositeInstruction> create_new_composite() {
    // Create a composite that we can pass to the functor
    std::stringstream name_ss;
    name_ss << this << "_qkernel";
    auto _kernel = qcor::__internal__::create_composite(name_ss.str());
    return _kernel;
  }

protected:
  std::shared_ptr<LocalArgsTranslator> args_translator;
  std::shared_ptr<KernelFunctor> helper;

public:
  KernelFunctorImpl(void *k_ptr,
                    std::shared_ptr<LocalArgsTranslator> translator,
                    std::shared_ptr<KernelFunctor> obj_helper, qreg qReg,
                    size_t nParams)
      : KernelFunctor(qReg) {
    kernel_ptr = k_ptr;
    args_translator = translator;
    helper = obj_helper;
    nbParams = nParams;
  }

  std::shared_ptr<CompositeInstruction>
  evaluate_kernel(const std::vector<double> &in_params) override {
    // Create a new CompositeInstruction, and create a tuple
    // from it so we can concatenate with the tuple args
    auto m_kernel = create_new_composite();
    auto kernel_composite_tuple = std::make_tuple(m_kernel);
    // Translate x parameters into kernel args (represented as a tuple)
    auto translated_tuple = (*args_translator)(in_params);

    // Concatenate the two to make the args list (kernel, args...)
    auto concatenated =
        std::tuple_cat(kernel_composite_tuple, translated_tuple);
    auto kernel_functor = reinterpret_cast<void (*)(
        std::shared_ptr<CompositeInstruction>, KernelArgs...)>(kernel_ptr);
    // Call the functor with those arguments
    qcor::__internal__::evaluate_function_with_tuple_args(kernel_functor,
                                                          concatenated);

    return m_kernel;
  }
};

template <typename... Args>
std::shared_ptr<KernelFunctor> createKernelFunctor(
    void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
                                   Args...),
    size_t nQubits, size_t nParams) {

  auto q = qalloc(nQubits);
  auto helper = std::make_shared<KernelFunctor>(q);
  __internal__::ArgsTranslatorAutoGenerator auto_gen;
  auto args_translator = auto_gen(helper->getQreg(), std::tuple<Args...>());

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

  return std::make_shared<KernelFunctorImpl<Args...>>(
      kernel_ptr, args_translator, helper, q, nParams);
}
} // namespace qcor
 No newline at end of file
+22 −12
Original line number Diff line number Diff line
@@ -2,11 +2,13 @@
#include "Accelerator.hpp"
#include "AcceleratorBuffer.hpp"
#include "Circuit.hpp"
#include "kernel_evaluator.hpp"
#include "qcor.hpp"
#include "qcor_utils.hpp"
#include "qrt.hpp"
#include <memory>
#include <xacc_internal_compiler.hpp>

using CompositeInstruction = xacc::CompositeInstruction;
using Accelerator = xacc::Accelerator;
using Identifiable = xacc::Identifiable;
@@ -61,7 +63,9 @@ using TdObservable = std::function<PauliOperator(double)>;

// Capture a quantum chemistry problem.
// TODO: generalize this to capture all potential use cases.

struct QuatumSimulationModel {
  QuatumSimulationModel() : observable(nullptr) {}
  // Model name.
  std::string name;

@@ -73,7 +77,7 @@ struct QuatumSimulationModel {
  TdObservable hamiltonian;

  // QuatumSimulationModel also support a user-defined (fixed) ansatz.
  std::shared_ptr<CompositeInstruction> user_defined_ansatz;
  std::shared_ptr<KernelFunctor> user_defined_ansatz;
};

// Generic model builder (factory)
@@ -100,7 +104,8 @@ public:
  //  - format: key to look up module/plugin to digest the input data.
  //  - data: model descriptions in plain-text format, e.g. load from file.
  //  - params: extra parameters to pass to the parser/generator,
  //            e.g. any transformations required in order to generate the Observable.
  //            e.g. any transformations required in order to generate the
  //            Observable.
  static QuatumSimulationModel createModel(const std::string &format,
                                           const std::string &data,
                                           const HeterogeneousMap &params = {});
@@ -111,9 +116,13 @@ public:
  static inline QuatumSimulationModel createModel(
      void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
                                     Args...),
      Observable *obs) {
      Observable *obs, size_t nbQubits, size_t nbParams) {
    auto kernel_functor =
        createKernelFunctor(quantum_kernel_functor, nbQubits, nbParams);

    QuatumSimulationModel model;
    std::cout << "HOWDY\n";
    model.observable = obs;
    model.user_defined_ansatz = kernel_functor;
    return model;
  }
};
@@ -127,13 +136,14 @@ using QuatumSimulationResult = HeterogeneousMap;
class QuatumSimulationWorkflow : public Identifiable {
public:
  virtual bool initialize(const HeterogeneousMap &params) = 0;
  virtual QuatumSimulationResult execute(const QuatumSimulationModel &model) = 0;
  virtual QuatumSimulationResult
  execute(const QuatumSimulationModel &model) = 0;

protected:
  CostFunctionEvaluator *evaluator;
};

// Get workflow by name:
std::shared_ptr<QuatumSimulationWorkflow> getWorkflow(const std::string &name,
                                          const HeterogeneousMap &init_params);
std::shared_ptr<QuatumSimulationWorkflow>
getWorkflow(const std::string &name, const HeterogeneousMap &init_params);
} // namespace qcor
 No newline at end of file
+51 −0
Original line number Diff line number Diff line
#include "qsim_impl.hpp"
#include "xacc_service.hpp"
#include "xacc.hpp"

namespace qcor {
Ansatz TrotterEvolution::create_ansatz(Observable *obs,
@@ -81,6 +82,54 @@ TimeDependentWorkflow::execute(const QuatumSimulationModel &model) {
  return result;
}

bool VqeWorkflow::initialize(const HeterogeneousMap &params) {
  const std::string DEFAULT_OPTIMIZER = "nlopt";
  optimizer.reset();
  if (params.pointerLikeExists<Optimizer>("optimizer")) {
    optimizer =
        xacc::as_shared_ptr(params.getPointerLike<Optimizer>("optimizer"));
  } else {
    optimizer = createOptimizer(DEFAULT_OPTIMIZER);
  }
  // VQE workflow requires an optimizer
  return (optimizer != nullptr);
}

QuatumSimulationResult
VqeWorkflow::execute(const QuatumSimulationModel &model) {
  // If the model includes a concrete variational ansatz:
  if (model.user_defined_ansatz) {
    auto nParams = model.user_defined_ansatz->nParams();
    auto vqe = xacc::getAlgorithm("vqe");
    auto qpu = xacc::internal_compiler::get_qpu();

    OptFunction f(
        [&](const std::vector<double> &x, std::vector<double> &dx) {
          auto kernel = model.user_defined_ansatz->evaluate_kernel(x);
          // std::cout << "Kernel:\n" << kernel->toString() << "\n";
          auto success = vqe->initialize({{"ansatz", kernel},
                                          {"accelerator", qpu},
                                          {"observable", model.observable}});
          if (!success) {
            xacc::error("QCOR VQE Workflow Error - could not initialize "
                        "internal xacc vqe algorithm.");
          }
          auto tmp_child = qalloc(model.user_defined_ansatz->getQreg().size());
          auto energy =
              vqe->execute(xacc::as_shared_ptr(tmp_child.results()), {})[0];
          return energy;
        },
        nParams);

    auto result = optimizer->optimize(f);
    std::cout << "Min energy = " << result.first << "\n";
    return {{"energy", result.first}, {"opt-params", result.second}};
  }

  // TODO: support ansatz generation methods:
  return {};
}

std::shared_ptr<QuatumSimulationWorkflow>
getWorkflow(const std::string &name, const HeterogeneousMap &init_params) {
  auto qsim_workflow = xacc::getService<QuatumSimulationWorkflow>(name);
@@ -105,6 +154,8 @@ public:
  void Start(BundleContext context) {
    context.RegisterService<qcor::QuatumSimulationWorkflow>(
        std::make_shared<qcor::TimeDependentWorkflow>());
    context.RegisterService<qcor::QuatumSimulationWorkflow>(
        std::make_shared<qcor::VqeWorkflow>());
  }

  void Stop(BundleContext) {}
+1 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ public:
  virtual const std::string name() const override { return "vqe"; }
  virtual const std::string description() const override { return ""; }
private:
  Optimizer *optimizer;
  std::shared_ptr<Optimizer> optimizer;
};


+1 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ int main(int argc, char **argv) {
  auto H = createObservable(
      "5.907 - 2.1433 X0X1 - 2.1433 Y0Y1 + .21829 Z0 - 6.125 Z1");

  auto problemModel = ModelBuilder::createModel(ansatz, H.get());
  auto problemModel = ModelBuilder::createModel(ansatz, H.get(), q.size(), 1);
  auto optimizer = createOptimizer("nlopt");

  auto workflow = qcor::getWorkflow("vqe", {{"optimizer", optimizer}});