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

Worked on using lambda w/ Obj func



Handle common cases of double and vector<double> signature.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 544e72ea
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -12,13 +12,24 @@ int main() {
  });

  auto q = qalloc(2);
  auto args_translator = std::make_shared<ArgsTranslator<qreg, double>>(
      [&](const std::vector<double> x) { return std::make_tuple(q, x[0]); });
  auto objective = createObjectiveFunction(ansatz, args_translator, H, q, 1);

  auto objective = createObjectiveFunction(ansatz, H, q, 1);
  // Create a qcor Optimizer
  auto optimizer = createOptimizer("nlopt");

  // Optimize the above function
  auto [optval, opt_params] = optimizer->optimize(*objective.get());
  std::cout << "Energy: " << optval << "\n";

  auto ansatz_vec_param = qpu_lambda([](qreg q, std::vector<double> x) {
    X(q[0]);
    Ry(q[1], x[0]);
    CX(q[1], q[0]);
  });

  auto q1 = qalloc(2);
  auto objective_vec = createObjectiveFunction(ansatz_vec_param, H, q1, 1);

  // Optimize the above function
  auto [optval_vec, opt_params_vec] = optimizer->optimize(*objective.get());
  std::cout << "Energy: " << optval_vec << "\n";
}
 No newline at end of file
+30 −0
Original line number Diff line number Diff line
@@ -300,6 +300,11 @@ private:
  QJIT qjit;

public:
  // Variational information, i.e. is this lambda compatible with VQE
  // e.g. single double or single vector double input.
  enum class Variational_Arg_Type { Double, Vec_Double, None };
  Variational_Arg_Type var_type = Variational_Arg_Type::None;
  
  // Constructor, capture vars should be deduced without
  // specifying them since we're using C++17
  _qpu_lambda(std::string &&ff, std::string &&_capture_var_names,
@@ -359,6 +364,31 @@ public:
      return result;
    }(tt);


    // Determine if this lambda has a VQE-compatible type:
    // QReg then variational params.
    if (arg_type_and_names.size() == 2) {
      const auto trim_space = [](std::string &stripString) {
        while (!stripString.empty() && std::isspace(*stripString.begin())) {
          stripString.erase(stripString.begin());
        }

        while (!stripString.empty() && std::isspace(*stripString.rbegin())) {
          stripString.erase(stripString.length() - 1);
        }
      };

      auto type_name = arg_type_and_names[1].first;
      trim_space(type_name);
      // Use a relax search to handle using namespace std...
      // FIXME: this is quite hacky.
      if (type_name.find("vector<double>") != std::string::npos) {
        var_type = Variational_Arg_Type::Vec_Double;
      } else if (type_name == "double") {
        var_type = Variational_Arg_Type::Double;
      }
    }

    // Map simple type to its reference type so that the
    // we can use consistent type-forwarding
    // when casting the JIT raw function pointer.
+42 −1
Original line number Diff line number Diff line
@@ -563,4 +563,45 @@ std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
      kernel_fn, __internal__::qcor_as_shared(&observable), q,
      args_translator, helper, nParams, options);
}

// Create ObjFunc from a qpu_lambda w/o a specific args_translater
// Assume the lambda has a VQE-compatible signature
template <typename... CaptureArgs>
std::shared_ptr<ObjectiveFunction>
createObjectiveFunction(_qpu_lambda<CaptureArgs...> &lambda,
                        Observable &observable, qreg &q, const int nParams,
                        HeterogeneousMap &&options = {}) {
  if (lambda.var_type ==
      _qpu_lambda<CaptureArgs...>::Variational_Arg_Type::None) {
    error("qpu_lambda has an incompatible signature. Please provide an "
          "ArgsTranslator.");
  }
  auto helper = qcor::__internal__::get_objective("vqe");
  std::function<void(std::shared_ptr<CompositeInstruction>, qreg,
                     std::vector<double>)>
      kernel_fn = [&lambda](std::shared_ptr<CompositeInstruction> comp, qreg q,
                            std::vector<double> params) -> void {
    if (lambda.var_type ==
        _qpu_lambda<CaptureArgs...>::Variational_Arg_Type::Vec_Double) {
      return lambda.eval_with_parent(comp, q, params);
    }
    if (lambda.var_type ==
        _qpu_lambda<CaptureArgs...>::Variational_Arg_Type::Double) {
      if (params.size() != 1) {
        error("Invalid number of parameters. Expected 1, got " +
              std::to_string(params.size()));
      }
      return lambda.eval_with_parent(comp, q, params[0]);
    }
    error("Internal error: invalid qpu lambda type encountered.");
  };

  auto args_translator =
      std::make_shared<ArgsTranslator<qreg, std::vector<double>>>(
          [&](const std::vector<double> x) { return std::make_tuple(q, x); });

  return std::make_shared<ObjectiveFunctionImpl<qreg, std::vector<double>>>(
      kernel_fn, __internal__::qcor_as_shared(&observable), q, args_translator,
      helper, nParams, options);
}
} // namespace qcor
 No newline at end of file