Commit 5831a7e2 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

adding some docs to the c++ side

parent 8767ce7a
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -50,10 +50,16 @@ struct visit_helper<mpark::variant> {

namespace {

// We only allow certain argument types for quantum kernel functors in python
// Here we enumerate them as a Variant
using AllowedKernelArgTypes =
    xacc::Variant<bool, int, double, std::string, xacc::internal_compiler::qreg,
                  std::vector<double>>;

// We will take as input a mapping of arg variable names to the argument itself.
using KernelArgDict = std::map<std::string, AllowedKernelArgTypes>;

// Utility for mapping KernelArgDict to a HeterogeneousMap
class KernelArgDictToHeterogeneousMap {
 protected:
  xacc::HeterogeneousMap &m;
@@ -90,6 +96,16 @@ xacc::HeterogeneousMap heterogeneousMapConvert(

namespace qcor {

// PyObjectiveFunction implements ObjectiveFunction to 
// enable the utility of pythonic quantum kernels with the 
// existing qcor ObjectiveFunction infrastructure. This class 
// keeps track of the quantum kernel as a py::object, which it uses 
// in tandem with the QCOR QJIT engine to create an executable 
// functor representation of the quantum code at runtime. It exposes 
// the ObjectiveFunction operator()() overloads to map vector<double> 
// x to the correct pythonic argument structure. It delegates to the 
// usual helper ObjectiveFunction (like vqe) for execution of the 
// actual pre-, execution, and post-processing. 
class PyObjectiveFunction : public qcor::ObjectiveFunction {
 protected:
  py::object py_kernel;
@@ -103,28 +119,46 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction {
  PyObjectiveFunction(py::object q, qcor::PauliOperator &qq, const int n_dim,
                      const std::string &helper_name)
      : py_kernel(q) {
    
    // Set the OptFunction dimensions
    _dim = n_dim;

    // Set the helper objective
    helper = xacc::getService<qcor::ObjectiveFunction>(helper_name);

    // Store the observable pointer and give it to the helper
    observable = xacc::as_shared_ptr(&qq);
    helper->update_observable(observable);

    // Extract the QJIT source code
    auto src = py_kernel.attr("get_internal_src")().cast<std::string>();

    // QJIT compile
    // this will be fast if already done, and we just do it once
    qjit.jit_compile(src, true);
  }

  // Evaluate this ObjectiveFunction at the dictionary of kernel args, 
  // return the scalar value 
  double operator()(const KernelArgDict args) {
    // Map the kernel args to a hetmap
    xacc::HeterogeneousMap m;
    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);
    helper->update_kernel(kernel);

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

  // Evaluate this ObjectiveFunction at the parameters x
  double operator()(const std::vector<double> &x,
                    std::vector<double> &dx) override {
    current_iterate_parameters = x;
@@ -136,6 +170,7 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction {
    // args will be a dictionary, arg_name to arg
    return operator()(args);
  }

  virtual double operator()(xacc::internal_compiler::qreg &qreg,
                            std::vector<double> &dx) {
    throw std::bad_function_call();
@@ -143,6 +178,11 @@ class PyObjectiveFunction : public qcor::ObjectiveFunction {
  }
};

// PyKernelFunctor is a subtype of KernelFunctor from the qsim library 
// that returns a CompositeInstruction representation of a pythonic 
// quantum kernel given a vector of parameters x. This will 
// leverage the QJIT infrastructure to create executable functor 
// representation of the python kernel. 
class PyKernelFunctor : public qcor::KernelFunctor {
 protected:
  py::object py_kernel;
@@ -158,6 +198,8 @@ class PyKernelFunctor : public qcor::KernelFunctor {
    qjit.jit_compile(src, true);
  }

  // Delegate to QJIT to create a CompositeInstruction representation 
  // of the pythonic quantum kernel. 
  std::shared_ptr<xacc::CompositeInstruction> evaluate_kernel(
      const std::vector<double> &x) override {
    // Translate x into kernel args