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

Works on qcor gradients



Start pulling out gradients from VQE and making it a more standardized impl.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent f9e9ac33
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
#define US_BUNDLE_NAME
#include "gradient_function.hpp"
#include "AlgorithmGradientStrategy.hpp"
#include "cppmicroservices/ServiceProperties.h"
#include "qcor.hpp"
#include "xacc.hpp"
#include "xacc_internal_compiler.hpp"
#include "xacc_plugin.hpp"
#include "xacc_service.hpp"
using namespace cppmicroservices;

namespace qcor {
KernelForwardDifferenceGradient::KernelForwardDifferenceGradient(
    std::function<std::shared_ptr<xacc::CompositeInstruction>(
        std::vector<double>)> &kernel_evaluator,
    std::shared_ptr<xacc::Observable> observable, double step_size)
    : m_kernelEval(kernel_evaluator), m_step(step_size), m_obs(observable) {
  gradient_func = [&](const std::vector<double> &x,
                      double cost_val) -> std::vector<double> {
    std::vector<double> gradients(x.size(), 0.0);
    // TODO: port the implementation here as well.
    auto gradient_strategy =
        xacc::getService<xacc::AlgorithmGradientStrategy>("forward");

    if (gradient_strategy->isNumerical() && m_obs->getIdentitySubTerm()) {
      gradient_strategy->setFunctionValue(
          cost_val - std::real(m_obs->getIdentitySubTerm()->coefficient()));
    }
    auto kernel = m_kernelEval(x);
    gradient_strategy->initialize({{"observable", m_obs}, {"step", m_step}});
    auto grad_kernels = gradient_strategy->getGradientExecutions(kernel, x);
    const size_t nb_qubits =
        std::max(static_cast<size_t>(m_obs->nBits()), kernel->nPhysicalBits());
    auto tmp_grad = qalloc(nb_qubits);
    xacc::internal_compiler::execute(tmp_grad.results(), grad_kernels);
    auto tmp_grad_children = tmp_grad.results()->getChildren();
    gradient_strategy->compute(gradients, tmp_grad_children);
    return gradients;
  };
}
} // namespace qcor
+44 −0
Original line number Diff line number Diff line
#pragma once
#include <memory>
#include <vector>
#include <functional>

namespace xacc {
class CompositeInstruction;
class Observable;
}
namespace qcor {
// Gradient function type:
// Input: set of current parameters (std::vector<double>) and the current
// objective (cost) function value. Output: gradients (std::vector<double>)
// Requirements: size(parameters) == size (gradients)
using GradientFunctionType =
    std::function<std::vector<double>(const std::vector<double> &, double)>;
class GradientFunction {
protected:
  GradientFunctionType gradient_func;

public:
  GradientFunction() {}
  GradientFunction(GradientFunctionType func) : gradient_func(func) {}
  std::vector<double> operator()(const std::vector<double> &x,
                                 double current_val) {
    return gradient_func(x, current_val);
  }
};

// Evaluate the Forward Difference gradients of a variational kernel.
class KernelForwardDifferenceGradient : public GradientFunction {
protected:
  std::function<std::shared_ptr<xacc::CompositeInstruction>(std::vector<double>)>
      &m_kernelEval;
  double m_step;
  std::shared_ptr<xacc::Observable> m_obs;

public:
  KernelForwardDifferenceGradient(
      std::function<std::shared_ptr<xacc::CompositeInstruction>(std::vector<double>)>
          &kernel_evaluator,
      std::shared_ptr<xacc::Observable> observable, double step_size = 1.0e-7);
};
} // namespace qcor
 No newline at end of file
+34 −2
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

#include <functional>

#include "gradient_function.hpp"
#include "qcor_observable.hpp"
#include "qcor_utils.hpp"
#include "quantum_kernel.hpp"
@@ -130,6 +131,7 @@ class ObjectiveFunctionImpl : public ObjectiveFunction {
  std::shared_ptr<LocalArgsTranslator> args_translator;
  std::shared_ptr<ObjectiveFunction> helper;
  xacc::internal_compiler::qreg qreg;
  std::shared_ptr<GradientFunction> gradiend_method;
  // Kernel evaluator from qpu_lambda
  std::optional<
      std::function<std::shared_ptr<CompositeInstruction>(std::vector<double>)>>
@@ -182,7 +184,8 @@ public:
      : qreg(qq) {
    // std::cout << "Constructed from lambda\n";
    lambda_kernel_evaluator =
        [&, functor](std::vector<double> x) -> std::shared_ptr<CompositeInstruction> {
        [&, functor](
            std::vector<double> x) -> std::shared_ptr<CompositeInstruction> {
      // std::cout << "HOWDY:\n";
      // Create a new CompositeInstruction, and create a tuple
      // from it so we can concatenate with the tuple args
@@ -268,7 +271,17 @@ public:
    // Kernel is set / evaluated... run sub-type operator()
    kernel = kernel_evaluator(x);
    helper->update_kernel(kernel);
    return (*helper)(qreg, dx);

    auto cost_val = (*helper)(qreg, dx);
    // If we needs gradients:
    if (!dx.empty()) {
      if (dx.size() != x.size()) {
        error("Dimension mismatched: gradients and parameters vectors have "
              "different size.");
      }
      dx = (*gradiend_method)(x, cost_val);
    }
    return cost_val;
  }

  // Return the qreg
@@ -604,4 +617,23 @@ createObjectiveFunction(_qpu_lambda<CaptureArgs...> &lambda,
      kernel_fn, __internal__::qcor_as_shared(&observable), q, args_translator,
      helper, nParams, options);
}

// Objective function with gradient options:
// Generic method: user provides a gradient calculation method.
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,
    std::shared_ptr<GradientFunction> gradient_method,
    HeterogeneousMap &&options = {}) {
  auto helper = qcor::__internal__::get_objective("vqe");
  __internal__::ArgsTranslatorAutoGenerator auto_gen;
  auto args_translator = auto_gen(q, std::tuple<Args...>());

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

  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
      kernel_ptr, observable, q, args_translator, helper, nParams, options);
}
} // namespace qcor
 No newline at end of file