QCOR
objective_function.hpp
1 #pragma once
2 
3 #include <functional>
4 
5 #include "gradient_function.hpp"
6 #include "qcor_observable.hpp"
7 #include "qcor_utils.hpp"
8 #include "quantum_kernel.hpp"
9 
10 namespace qcor {
11 using OptimizerFunctorNoGrad =
12  std::function<double(const std::vector<double> &)>;
13 using OptimizerFunctor =
14  std::function<double(const std::vector<double> &, std::vector<double> &)>;
15 
16 // using OptimizerFunctorNonConstValueNoGrad =
17 // std::function<double(std::vector<double>)>;
18 
19 class ObjectiveFunction : public xacc::Identifiable {
20  protected:
21  // Quantum kernel function pointer, we will use
22  // this to cast to kernel(composite, args...).
23  // Doing it this way means we don't template ObjectiveFunction
24  void *kernel_ptr;
25 
26  // CompositeInstruction representation of the
27  // evaluated quantum kernel
28  std::shared_ptr<CompositeInstruction> kernel;
29 
30  Operator observable;
31 
32  HeterogeneousMap options;
33  std::vector<double> current_iterate_parameters;
34 
35  int _dim = 0;
36  std::function<double(const std::vector<double> &, std::vector<double> &)>
37  _function;
38 
39  public:
40  bool gradients_computed = false;
41 
42  ObjectiveFunction() = default;
43  ObjectiveFunction(OptimizerFunctor f, const int d) : _function(f), _dim(d) {}
44  ObjectiveFunction(OptimizerFunctorNoGrad f, const int d)
45  : _function([&](const std::vector<double> &x, std::vector<double> &dx) {
46  return f(x);
47  }),
48  _dim(d) {}
49 
50  // ObjectiveFunction(OptimizerFunctorNonConstValueNoGrad f, const int d)
51  // : _function([&](const std::vector<double> &x, std::vector<double> &dx) {
52  // return f(x);
53  // }),
54  // _dim(d) {}
55  const std::string name() const override { return "base-objective-function"; }
56  const std::string description() const override { return ""; }
57 
58  virtual const int dimensions() const { return _dim; }
59 
60  virtual double operator()(const std::vector<double> &x) {
61  std::vector<double> unused_grad;
62  return operator()(x, unused_grad);
63  }
64 
65  virtual double operator()(const std::vector<double> &x,
66  std::vector<double> &dx) {
67  return _function(x, dx);
68  }
69 
70  virtual double operator()(xacc::internal_compiler::qreg &qreg,
71  std::vector<double> &dx) {
72  throw std::bad_function_call();
73  return 0.0;
74  }
75 
76  void update_observable(Operator updated_observable) {
77  observable = updated_observable;
78  }
79 
80  Operator get_observable() { return observable; }
81 
82  void update_kernel(std::shared_ptr<CompositeInstruction> updated_kernel) {
83  kernel = updated_kernel;
84  }
85 
86  void update_current_iterate_parameters(std::vector<double> x) {
87  current_iterate_parameters = x;
88  }
89  // Set any extra options needed for the objective function
90  virtual void set_options(HeterogeneousMap &opts) { options = opts; }
91  template <typename T>
92  void update_options(const std::string key, T value) {
93  options.insert(key, value);
94  }
95 
96  // this really shouldnt be called.
97  virtual xacc::internal_compiler::qreg get_qreg() { return qalloc(1); }
98 
99  virtual std::function<
100  std::shared_ptr<CompositeInstruction>(std::vector<double>)>
101  get_kernel_evaluator() {
102  // Derive (ObjectiveFunctionImpl) only
103  error("Illegal call to get_kernel_evaluator().");
104  return {};
105  };
106 };
107 
108 namespace __internal__ {
109 // Get the objective function from the service registry
110 std::shared_ptr<ObjectiveFunction> get_objective(const std::string &type);
111 
112 template <typename T>
113 std::shared_ptr<T> qcor_as_shared(T *t) {
114  return std::shared_ptr<T>(t, [](T *const) {});
115 }
116 
117 template <std::size_t... Is>
118 auto create_tuple_impl(std::index_sequence<Is...>,
119  const std::vector<double> &arguments) {
120  return std::make_tuple(arguments[Is]...);
121 }
122 
123 template <std::size_t N>
124 auto create_tuple(const std::vector<double> &arguments) {
125  return create_tuple_impl(std::make_index_sequence<N>{}, arguments);
126 }
127 
129  std::shared_ptr<ArgsTranslator<qreg, std::vector<double>>> operator()(
130  qreg &q, std::tuple<qreg, std::vector<double>> &&) {
131  return std::make_shared<ArgsTranslator<qreg, std::vector<double>>>(
132  [&](const std::vector<double> &x) { return std::make_tuple(q, x); });
133  }
134 
135  template <typename... DoubleTypes>
136  std::shared_ptr<ArgsTranslator<qreg, DoubleTypes...>> operator()(
137  qreg &q, std::tuple<qreg, DoubleTypes...> &&t) {
138  if constexpr ((std::is_same<DoubleTypes, double>::value && ...)) {
139  return std::make_shared<ArgsTranslator<qreg, DoubleTypes...>>(
140  [&](const std::vector<double> &x) {
141  auto qreg_tuple = std::make_tuple(q);
142  auto double_tuple = create_tuple<sizeof...(DoubleTypes)>(x);
143  return std::tuple_cat(qreg_tuple, double_tuple);
144  });
145  } else {
146  error(
147  "QCOR cannot auto-generate a ArgsTranslator for this "
148  "ObjectiveFunction. Please provide a custom ArgsTranslator to "
149  "createObjectiveFunction.");
150  return std::make_shared<ArgsTranslator<qreg, DoubleTypes...>>(
151  [&](const std::vector<double> &x) { return t; });
152  }
153  }
154 };
155 
156 } // namespace __internal__
157 
158 template <typename... KernelArgs>
160  private:
161  using LocalArgsTranslator = ArgsTranslator<KernelArgs...>;
162 
163  std::shared_ptr<CompositeInstruction> create_new_composite() {
164  // Create a composite that we can pass to the functor
165  std::stringstream name_ss;
166  name_ss << this << "_qkernel";
167  auto _kernel = qcor::__internal__::create_composite(name_ss.str());
168  return _kernel;
169  }
170 
171  protected:
172  std::shared_ptr<LocalArgsTranslator> args_translator;
173  std::shared_ptr<ObjectiveFunction> helper;
175  std::shared_ptr<GradientFunction> gradiend_method;
176  // Kernel evaluator from qpu_lambda
177  std::optional<
178  std::function<std::shared_ptr<CompositeInstruction>(std::vector<double>)>>
179  lambda_kernel_evaluator;
180 
181  public:
182  ObjectiveFunctionImpl(void *k_ptr, Operator obs,
184  std::shared_ptr<LocalArgsTranslator> translator,
185  std::shared_ptr<ObjectiveFunction> obj_helper,
186  const int dim, HeterogeneousMap opts)
187  : qreg(qq) {
188  options = opts;
189  kernel_ptr = k_ptr;
190  observable = obs;
191  args_translator = translator;
192  helper = obj_helper;
193  _dim = dim;
194  _function = *this;
195  options.insert("observable", observable);
196  helper->update_observable(observable);
197  helper->set_options(options);
198  }
199 
200  // CTOR: externally provided gradient method:
201  // e.g. custom gradient calculation method for the ansatz kernel.
202  ObjectiveFunctionImpl(void *k_ptr, Operator obs,
204  std::shared_ptr<LocalArgsTranslator> translator,
205  std::shared_ptr<ObjectiveFunction> obj_helper,
206  std::shared_ptr<GradientFunction> grad_calc,
207  const int dim, HeterogeneousMap opts)
208  : ObjectiveFunctionImpl(k_ptr, obs, qq, translator, obj_helper, dim,
209  opts) {
210  gradiend_method = grad_calc;
211  }
212 
213  ObjectiveFunctionImpl(void *k_ptr, Operator obs,
214  std::shared_ptr<ObjectiveFunction> obj_helper,
215  const int dim, HeterogeneousMap opts) {
216  qreg = ::qalloc(obs.nBits());
217  options = opts;
218  kernel_ptr = k_ptr;
219  observable = obs;
221  args_translator = auto_gen(qreg, std::tuple<KernelArgs...>());
222  // args_translator = translator;
223  helper = obj_helper;
224  _dim = dim;
225  _function = *this;
226  options.insert("observable", observable);
227  helper->update_observable(observable);
228  helper->set_options(options);
229  }
230 
232  std::function<void(std::shared_ptr<CompositeInstruction>, KernelArgs...)>
233  &functor,
235  std::shared_ptr<LocalArgsTranslator> translator,
236  std::shared_ptr<ObjectiveFunction> obj_helper, const int dim,
237  HeterogeneousMap opts)
238  : qreg(qq) {
239  options = opts;
240  // std::cout << "Constructed from lambda\n";
241  lambda_kernel_evaluator =
242  [&, functor](
243  std::vector<double> x) -> std::shared_ptr<CompositeInstruction> {
244  // std::cout << "HOWDY:\n";
245  // Create a new CompositeInstruction, and create a tuple
246  // from it so we can concatenate with the tuple args
247  auto m_kernel = create_new_composite();
248  auto kernel_composite_tuple = std::make_tuple(m_kernel);
249 
250  // Translate x parameters into kernel args (represented as a tuple)
251  auto translated_tuple = (*args_translator)(x);
252 
253  // Concatenate the two to make the args list (kernel, args...)
254  auto concatenated =
255  std::tuple_cat(kernel_composite_tuple, translated_tuple);
256  std::apply(functor, concatenated);
257  // std::cout << m_kernel->toString() << "\n";
258  return m_kernel;
259  };
260  observable = obs;
261  args_translator = translator;
262  helper = obj_helper;
263  _dim = dim;
264  _function = *this;
265  options.insert("observable", observable);
266  helper->update_observable(observable);
267  helper->set_options(options);
268  }
269 
270  void set_options(HeterogeneousMap &opts) override {
271  options = opts;
272  helper->set_options(opts);
273  }
274 
275  // Construct the kernel evaluator of this ObjectiveFunctionImpl
276  std::function<std::shared_ptr<CompositeInstruction>(std::vector<double>)>
277  get_kernel_evaluator() override {
278  // Turn kernel evaluation into a functor that we can use here
279  // and share with the helper ObjectiveFunction for gradient evaluation
280  std::function<std::shared_ptr<CompositeInstruction>(std::vector<double>)>
281  kernel_evaluator = lambda_kernel_evaluator.has_value()
282  ? lambda_kernel_evaluator.value()
283  : [&](std::vector<double> x)
284  -> std::shared_ptr<CompositeInstruction> {
285  // Define a function pointer type for the quantum kernel
286  void (*kernel_functor)(std::shared_ptr<CompositeInstruction>,
287  KernelArgs...);
288  // Cast to the function pointer type
289  if (kernel_ptr) {
290  kernel_functor = reinterpret_cast<void (*)(
291  std::shared_ptr<CompositeInstruction>, KernelArgs...)>(kernel_ptr);
292  }
293  // Create a new CompositeInstruction, and create a tuple
294  // from it so we can concatenate with the tuple args
295  auto m_kernel = create_new_composite();
296  auto kernel_composite_tuple = std::make_tuple(m_kernel);
297 
298  // Translate x parameters into kernel args (represented as a tuple)
299  auto translated_tuple = (*args_translator)(x);
300 
301  // Concatenate the two to make the args list (kernel, args...)
302  auto concatenated =
303  std::tuple_cat(kernel_composite_tuple, translated_tuple);
304 
305  // Call the functor with those arguments
306  qcor::__internal__::evaluate_function_with_tuple_args(kernel_functor,
307  concatenated);
308  return m_kernel;
309  };
310 
311  return kernel_evaluator;
312  }
313 
314  // This will not be called on this class... It will only be called
315  // on helpers...
316  double operator()(xacc::internal_compiler::qreg &qreg,
317  std::vector<double> &dx) override {
318  return 0.0;
319  }
320 
321  double operator()(const std::vector<double> &x,
322  std::vector<double> &dx) override {
323  current_iterate_parameters = x;
324  helper->update_current_iterate_parameters(x);
325 
326  // Define a function pointer type for the quantum kernel
327  void (*kernel_functor)(std::shared_ptr<CompositeInstruction>,
328  KernelArgs...);
329  // Cast to the function pointer type
330  if (kernel_ptr) {
331  kernel_functor = reinterpret_cast<void (*)(
332  std::shared_ptr<CompositeInstruction>, KernelArgs...)>(kernel_ptr);
333  }
334 
335  // Turn kernel evaluation into a functor that we can use here
336  // and share with the helper ObjectiveFunction for gradient evaluation
337  std::function<std::shared_ptr<CompositeInstruction>(std::vector<double>)>
338  kernel_evaluator = lambda_kernel_evaluator.has_value()
339  ? lambda_kernel_evaluator.value()
340  : [&](std::vector<double> x)
341  -> std::shared_ptr<CompositeInstruction> {
342  // Create a new CompositeInstruction, and create a tuple
343  // from it so we can concatenate with the tuple args
344  auto m_kernel = create_new_composite();
345  auto kernel_composite_tuple = std::make_tuple(m_kernel);
346 
347  // Translate x parameters into kernel args (represented as a tuple)
348  auto translated_tuple = (*args_translator)(x);
349 
350  // Concatenate the two to make the args list (kernel, args...)
351  auto concatenated =
352  std::tuple_cat(kernel_composite_tuple, translated_tuple);
353 
354  // Call the functor with those arguments
355  qcor::__internal__::evaluate_function_with_tuple_args(kernel_functor,
356  concatenated);
357  std::cout << m_kernel->toString() << "\n";
358  return m_kernel;
359  };
360 
361  // Give the kernel evaluator to the helper
362  helper->update_options("kernel-evaluator", kernel_evaluator);
363 
364  // Kernel is set / evaluated... run sub-type operator()
365  kernel = kernel_evaluator(x);
366  helper->update_kernel(kernel);
367 
368  // Save the input dx:
369  const auto input_dx = dx;
370 
371  auto cost_val = (*helper)(qreg, dx);
372 
373  // If we needs gradients:
374  // the optimizer requires dx (not empty)
375  // and the concrete ObjFunc sub-class doesn't calculate the gradients.
376  if (!dx.empty() && !helper->gradients_computed){
377  if (dx.size() != x.size()) {
378  error(
379  "Dimension mismatched: gradients and parameters vectors have "
380  "different size.");
381  }
382 
383  if (!gradiend_method) {
384  std::string gradient_method_name =
385  qcor::__internal__::DEFAULT_GRADIENT_METHOD;
386  // Backward compatible:
387  // If the "gradient-strategy" was specified in the option.
388  if (options.stringExists("gradient-strategy")) {
389  gradient_method_name = options.getString("gradient-strategy");
390  }
391  gradiend_method = qcor::__internal__::get_gradient_method(
392  gradient_method_name, __internal__::qcor_as_shared(this),
393  options);
394  }
395 
396  dx = (*gradiend_method)(x, cost_val);
397  }
398  kernel->clear();
399  return cost_val;
400  }
401 
402  // Return the qreg
403  xacc::internal_compiler::qreg get_qreg() override { return qreg; }
404 
405  // Provide a name and description
406  const std::string name() const override { return "objective-impl"; }
407  const std::string description() const override { return ""; }
408 };
409 
410 // Basic, takes kernel, operator, qreg, nParams
411 template <typename... Args>
412 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
413  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
414  Args...),
415  Operator &observable, qreg &q, const int nParams,
416  HeterogeneousMap &&options = {}) {
417  auto helper = qcor::__internal__::get_objective("vqe");
419  auto args_translator = auto_gen(q, std::tuple<Args...>());
420 
421  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
422 
423  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
424  kernel_ptr, observable, q, args_translator, helper, nParams, options);
425 }
426 
427 // Basic with obj_name specified
428 template <typename... Args>
429 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
430  const std::string obj_name,
431  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
432  Args...),
433  Operator observable, qreg &q, const int nParams,
434  HeterogeneousMap &&options = {}) {
435  auto helper = qcor::__internal__::get_objective(obj_name);
436  __internal__::ArgsTranslatorAutoGenerator auto_gen;
437  auto args_translator = auto_gen(q, std::tuple<Args...>());
438 
439  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
440 
441  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
442  kernel_ptr, observable, q, args_translator, helper, nParams, options);
443 }
444 
445 // create with no operator, assume allZs
446 template <typename... Args>
447 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
448  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
449  Args...),
450  qreg &q, const int nParams, HeterogeneousMap &&options = {}) {
451  auto helper = qcor::__internal__::get_objective("vqe");
452  __internal__::ArgsTranslatorAutoGenerator auto_gen;
453  auto args_translator = auto_gen(q, std::tuple<Args...>());
454 
455  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
456 
457  // std::map<int, std::string> all_zs;
458  // for (int i = 0; i < q.size(); i++) all_zs.insert({i, "Z"});
459  // auto observable = std::make_shared<PauliOperator>(all_zs);
460  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
461  kernel_ptr, allZs(q.size()), q, args_translator, helper, nParams,
462  options);
463 }
464 
465 // No observable, with obj_name
466 template <typename... Args>
467 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
468  const std::string obj_name,
469  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
470  Args...),
471  qreg &q, const int nParams, HeterogeneousMap &&options = {}) {
472  auto helper = qcor::__internal__::get_objective(obj_name);
473  __internal__::ArgsTranslatorAutoGenerator auto_gen;
474  auto args_translator = auto_gen(q, std::tuple<Args...>());
475 
476  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
477 
478  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
479  kernel_ptr, allZs(q.size()), q, args_translator, helper, nParams,
480  options);
481 }
482 
483 // /////// Now provide overloads with ArgsTranslators
484 
485 template <typename... Args>
486 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
487  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
488  Args...),
489  Operator &observable,
490  std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
491  const int nParams, HeterogeneousMap &&options = {}) {
492  auto helper = qcor::__internal__::get_objective("vqe");
493 
494  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
495 
496  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
497  kernel_ptr, observable, q, args_translator, helper, nParams, options);
498 }
499 
500 template <typename... Args>
501 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
502  const std::string obj_name,
503  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
504  Args...),
505  Operator &observable,
506  std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
507  const int nParams, HeterogeneousMap &&options = {}) {
508  auto helper = qcor::__internal__::get_objective(obj_name);
509 
510  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
511 
512  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
513  kernel_ptr, observable, q, args_translator, helper, nParams, options);
514 }
515 
516 template <typename... Args>
517 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
518  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
519  Args...),
520  std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
521  const int nParams, HeterogeneousMap &&options = {}) {
522  auto helper = qcor::__internal__::get_objective("vqe");
523 
524  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
525 
526  // std::map<int, std::string> all_zs;
527  // for (int i = 0; i < q.size(); i++) all_zs.insert({i, "Z"});
528  // auto observable = std::make_shared<PauliOperator>(all_zs);
529  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
530  kernel_ptr, allZs(q.size()), q, args_translator, helper, nParams,
531  options);
532 }
533 
534 template <typename... Args>
535 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
536  const std::string obj_name,
537  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
538  Args...),
539  std::shared_ptr<ArgsTranslator<Args...>> args_translator, qreg &q,
540  const int nParams, HeterogeneousMap &&options = {}) {
541  auto helper = qcor::__internal__::get_objective(obj_name);
542 
543  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
544 
545  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
546  kernel_ptr, allZs(q.size()), q, args_translator, helper, nParams,
547  options);
548 }
549 
550 // /// no qreg args
551 
552 template <typename... Args>
553 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
554  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
555  Args...),
556  Operator &observable, const int nParams, HeterogeneousMap &&options = {}) {
557  auto helper = qcor::__internal__::get_objective("vqe");
558 
559  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
560 
561  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
562  kernel_ptr, observable, helper, nParams, options);
563 }
564 
565 template <typename... Args>
566 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
567  const std::string obj_name,
568  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
569  Args...),
570  Operator &observable, const int nParams, HeterogeneousMap &&options = {}) {
571  auto helper = qcor::__internal__::get_objective(obj_name);
572 
573  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
574 
575  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
576  kernel_ptr, observable, helper, nParams, options);
577 }
578 
579 template <typename... CaptureArgs, typename... Args>
580 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
581  _qpu_lambda<CaptureArgs...> &lambda,
582  std::shared_ptr<ArgsTranslator<Args...>> args_translator,
583  Operator &observable, qreg &q, const int nParams,
584  HeterogeneousMap &&options = {}) {
585  auto helper = qcor::__internal__::get_objective("vqe");
586  std::function<void(std::shared_ptr<CompositeInstruction>, Args...)>
587  kernel_fn = [&lambda](std::shared_ptr<CompositeInstruction> comp,
588  Args... args) -> void {
589  return lambda.eval_with_parent(comp, args...);
590  };
591 
592  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
593  kernel_fn, observable, q, args_translator, helper, nParams, options);
594 }
595 
596 // Create ObjFunc from a qpu_lambda w/o a specific args_translater
597 // Assume the lambda has a VQE-compatible signature
598 template <typename... CaptureArgs>
599 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
600  _qpu_lambda<CaptureArgs...> &lambda, Operator &observable, qreg &q,
601  const int nParams, HeterogeneousMap &&options = {}) {
602  if (lambda.var_type ==
603  _qpu_lambda<CaptureArgs...>::Variational_Arg_Type::None) {
604  error(
605  "qpu_lambda has an incompatible signature. Please provide an "
606  "ArgsTranslator.");
607  }
608  auto helper = qcor::__internal__::get_objective("vqe");
609  std::function<void(std::shared_ptr<CompositeInstruction>, qreg,
610  std::vector<double>)>
611  kernel_fn = [&lambda](std::shared_ptr<CompositeInstruction> comp, qreg q,
612  std::vector<double> params) -> void {
613  if (lambda.var_type ==
614  _qpu_lambda<CaptureArgs...>::Variational_Arg_Type::Vec_Double) {
615  return lambda.eval_with_parent(comp, q, params);
616  }
617  if (lambda.var_type ==
618  _qpu_lambda<CaptureArgs...>::Variational_Arg_Type::Double) {
619  if (params.size() != 1) {
620  error("Invalid number of parameters. Expected 1, got " +
621  std::to_string(params.size()));
622  }
623  return lambda.eval_with_parent(comp, q, params[0]);
624  }
625  error("Internal error: invalid qpu lambda type encountered.");
626  };
627 
628  auto args_translator =
629  std::make_shared<ArgsTranslator<qreg, std::vector<double>>>(
630  [&](const std::vector<double> x) { return std::make_tuple(q, x); });
631 
632  return std::make_shared<ObjectiveFunctionImpl<qreg, std::vector<double>>>(
633  kernel_fn, observable, q, args_translator, helper, nParams, options);
634 }
635 
636 // // Objective function with gradient options:
637 // // Generic method: user provides a gradient calculation method.
638 template <typename... Args>
639 std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
640  void (*quantum_kernel_functor)(std::shared_ptr<CompositeInstruction>,
641  Args...),
642  Operator &observable, qreg &q, const int nParams,
643  std::shared_ptr<GradientFunction> gradient_method,
644  HeterogeneousMap &&options = {}) {
645  auto helper = qcor::__internal__::get_objective("vqe");
646  __internal__::ArgsTranslatorAutoGenerator auto_gen;
647  auto args_translator = auto_gen(q, std::tuple<Args...>());
648 
649  void *kernel_ptr = reinterpret_cast<void *>(quantum_kernel_functor);
650 
651  return std::make_shared<ObjectiveFunctionImpl<Args...>>(
652  kernel_ptr, observable, q, args_translator, helper, gradient_method,
653  nParams, options);
654 }
655 } // namespace qcor
qcor::Operator
Definition: qcor_observable.hpp:24
qcor::ObjectiveFunction
Definition: objective_function.hpp:19
qcor::__internal__::ArgsTranslatorAutoGenerator
Definition: objective_function.hpp:128
qcor::ObjectiveFunctionImpl
Definition: objective_function.hpp:159
qcor
Definition: qcor_syntax_handler.cpp:15
xacc::internal_compiler::qreg
Definition: qalloc.hpp:101
qcor::ArgsTranslator
Definition: qcor_utils.hpp:162