5 #include "gradient_function.hpp"
6 #include "qcor_jit.hpp"
7 #include "qcor_observable.hpp"
8 #include "qcor_utils.hpp"
12 enum class QrtType { NISQ, FTQC };
15 template <
typename... Args>
22 template <
typename... Args>
23 void apply_control(std::shared_ptr<CompositeInstruction> parent_kernel,
24 const std::vector<qubit> &ctrl_qbits,
27 template <
typename... Args>
28 void apply_adjoint(std::shared_ptr<CompositeInstruction> parent_kernel,
31 template <
typename... Args>
35 template <
typename... Args>
38 template <
typename... Args>
41 template <
typename... Args>
45 template <
typename... Args>
74 template <
typename Derived,
typename... Args>
78 std::tuple<Args...> args_tuple;
82 std::shared_ptr<qcor::CompositeInstruction> parent_kernel;
86 bool is_callable =
true;
90 bool disable_destructor =
false;
95 bool optimize_only =
false;
96 QrtType runtime_env = QrtType::NISQ;
98 QuantumKernel(Args... args) : args_tuple(std::forward_as_tuple(args...)) {
99 runtime_env = (__qrt_env ==
"ftqc") ? QrtType::FTQC : QrtType::NISQ;
105 QuantumKernel(std::shared_ptr<qcor::CompositeInstruction> _parent_kernel,
107 : args_tuple(std::forward_as_tuple(args...)),
108 parent_kernel(_parent_kernel),
110 runtime_env = (__qrt_env ==
"ftqc") ? QrtType::FTQC : QrtType::NISQ;
114 static void print_kernel(std::ostream &os, Args... args) {
115 Derived derived(args...);
117 return internal::print_kernel<Args...>(callable, os, args...);
120 static void print_kernel(Args... args) { print_kernel(std::cout, args...); }
123 static std::size_t n_instructions(Args... args) {
124 Derived derived(args...);
126 return internal::n_instructions<Args...>(callable, args...);
130 static void adjoint(std::shared_ptr<CompositeInstruction> parent_kernel,
132 Derived derived(args...);
134 return internal::apply_adjoint<Args...>(parent_kernel, callable, args...);
138 static void ctrl(std::shared_ptr<CompositeInstruction> parent_kernel,
139 const std::vector<int> &ctrlIdx, Args... args) {
140 std::vector<qubit> ctrl_qubit_vec;
141 for (
int i = 0; i < ctrlIdx.size(); i++) {
142 ctrl_qubit_vec.push_back({
"q",
static_cast<size_t>(ctrlIdx[i]),
nullptr});
144 ctrl(parent_kernel, ctrl_qubit_vec, args...);
148 static void ctrl(std::shared_ptr<CompositeInstruction> parent_kernel,
149 int ctrlIdx, Args... args) {
150 ctrl(parent_kernel, std::vector<int>{ctrlIdx}, args...);
153 static void ctrl(std::shared_ptr<CompositeInstruction> parent_kernel,
154 qreg ctrl_qbits, Args... args) {
155 std::vector<qubit> ctrl_qubit_vec;
156 for (
int i = 0; i < ctrl_qbits.size(); i++)
157 ctrl_qubit_vec.push_back(ctrl_qbits[i]);
159 ctrl(parent_kernel, ctrl_qubit_vec, args...);
162 static void ctrl(std::shared_ptr<CompositeInstruction> parent_kernel,
163 const std::vector<qubit> &ctrl_qbits, Args... args) {
165 Derived derived(args...);
167 internal::apply_control<Args...>(parent_kernel, ctrl_qbits, callable,
172 static void ctrl(std::shared_ptr<CompositeInstruction> parent_kernel,
173 qubit ctrl_qbit, Args... args) {
174 ctrl(parent_kernel, std::vector<qubit>{ctrl_qbit}, args...);
177 static UnitaryMatrix as_unitary_matrix(Args... args) {
178 Derived derived(args...);
180 return internal::as_unitary_matrix<Args...>(callable, args...);
183 static double observe(
Operator &obs, Args... args) {
184 Derived derived(args...);
186 return internal::observe<Args...>(obs, callable, args...);
189 static double observe(std::shared_ptr<Operator> obs, Args... args) {
190 return observe(*obs, args...);
195 static double autograd(
Operator &obs, std::vector<double> &dx,
qreg q,
197 std::function<std::shared_ptr<CompositeInstruction>(std::vector<double>)>
198 kernel_eval = [q](std::vector<double> x) {
200 qcor::__internal__::create_composite(
"__temp__autograd__");
201 Derived derived(q, x[0]);
202 derived.disable_destructor =
true;
204 tempKernel->addInstructions(derived.parent_kernel->getInstructions());
208 auto gradiend_method = qcor::__internal__::get_gradient_method(
209 qcor::__internal__::DEFAULT_GRADIENT_METHOD, kernel_eval, obs);
210 const double cost_val = observe(obs, q, x);
211 dx = (*gradiend_method)({x}, cost_val);
215 static double autograd(
Operator &obs, std::vector<double> &dx,
qreg q,
216 std::vector<double> x) {
217 std::function<std::shared_ptr<CompositeInstruction>(std::vector<double>)>
218 kernel_eval = [q](std::vector<double> x) {
220 qcor::__internal__::create_composite(
"__temp__autograd__");
221 Derived derived(q, x);
222 derived.disable_destructor =
true;
224 tempKernel->addInstructions(derived.parent_kernel->getInstructions());
228 auto gradiend_method = qcor::__internal__::get_gradient_method(
229 qcor::__internal__::DEFAULT_GRADIENT_METHOD, kernel_eval, obs);
230 const double cost_val = observe(obs, q, x);
231 dx = (*gradiend_method)(x, cost_val);
235 static double autograd(
Operator &obs, std::vector<double> &dx,
236 std::vector<double> x,
238 std::function<std::shared_ptr<CompositeInstruction>(std::vector<double>)>
239 kernel_eval = [&](std::vector<double> x_vec) {
240 auto eval_lambda = [&](Args... args) {
242 qcor::__internal__::create_composite(
"__temp__autograd__");
243 Derived derived(args...);
244 derived.disable_destructor =
true;
246 tempKernel->addInstructions(
247 derived.parent_kernel->getInstructions());
250 auto args_tuple = args_translator(x_vec);
251 return std::apply(eval_lambda, args_tuple);
254 auto gradiend_method = qcor::__internal__::get_gradient_method(
255 qcor::__internal__::DEFAULT_GRADIENT_METHOD, kernel_eval, obs);
257 auto kernel_observe = [&](Args... args) {
return observe(obs, args...); };
259 auto args_tuple = args_translator(x);
260 const double cost_val = std::apply(kernel_observe, args_tuple);
261 dx = (*gradiend_method)(x, cost_val);
265 static std::string openqasm(Args... args) {
266 Derived derived(args...);
268 return internal::openqasm<Args...>(callable, args...);
273 template <
typename... ArgTypes>
279 template <
typename Derived>
282 #define ONE_QUBIT_KERNEL_CTRL_ENABLER(CLASSNAME, QRTNAME) \
283 class CLASSNAME : public OneQubitKernel<class CLASSNAME> { \
285 CLASSNAME(qubit q) : OneQubitKernel<CLASSNAME>(q) {} \
286 CLASSNAME(std::shared_ptr<qcor::CompositeInstruction> _parent_kernel, \
288 : OneQubitKernel<CLASSNAME>(_parent_kernel, q) { \
289 throw std::runtime_error("you cannot call this."); \
291 void operator()(qubit q) { \
292 parent_kernel = qcor::__internal__::create_composite( \
293 "__tmp_one_qubit_ctrl_enabler"); \
294 quantum::set_current_program(parent_kernel); \
295 if (runtime_env == QrtType::FTQC) { \
296 quantum::set_current_buffer(q.results()); \
298 ::quantum::QRTNAME(q); \
301 virtual ~CLASSNAME() {} \
304 ONE_QUBIT_KERNEL_CTRL_ENABLER(X, x)
305 ONE_QUBIT_KERNEL_CTRL_ENABLER(Y, y)
306 ONE_QUBIT_KERNEL_CTRL_ENABLER(Z, z)
307 ONE_QUBIT_KERNEL_CTRL_ENABLER(H, h)
308 ONE_QUBIT_KERNEL_CTRL_ENABLER(T, t)
309 ONE_QUBIT_KERNEL_CTRL_ENABLER(Tdg, tdg)
310 ONE_QUBIT_KERNEL_CTRL_ENABLER(S, s)
311 ONE_QUBIT_KERNEL_CTRL_ENABLER(Sdg, sdg)
326 template <
typename... CaptureArgs>
331 class TupleToTypeArgString {
334 std::vector<std::string> var_names;
338 std::string type_name() {
339 typedef typename std::remove_reference<T>::type TR;
340 std::unique_ptr<char, void (*)(
void *)> own(
341 abi::__cxa_demangle(
typeid(TR).name(),
nullptr,
nullptr,
nullptr),
343 std::string r = own !=
nullptr ? own.get() :
typeid(TR).name();
348 TupleToTypeArgString(std::string &t) : tmp(t) {}
349 TupleToTypeArgString(std::string &t, std::vector<std::string> &_var_names)
350 : tmp(t), var_names(_var_names) {}
351 template <
typename T>
352 void operator()(T &t) {
353 tmp += type_name<decltype(t)>() +
"& " +
354 (var_names.empty() ?
"arg_" + std::to_string(counter)
355 : var_names[counter]) +
362 std::string &src_str;
365 std::string &capture_var_names;
368 std::tuple<CaptureArgs &...> capture_vars;
380 std::optional<std::tuple<CaptureArgs...>> optional_copy_capture_vars;
388 enum class Variational_Arg_Type { Double, Vec_Double, None };
389 Variational_Arg_Type var_type = Variational_Arg_Type::None;
393 _qpu_lambda(std::string &&ff, std::string &&_capture_var_names,
394 CaptureArgs &..._capture_vars)
396 capture_var_names(_capture_var_names),
397 capture_vars(std::forward_as_tuple(_capture_vars...)) {
399 auto first = src_str.find_first_of(
"(");
400 auto last = src_str.find_first_of(
")");
401 auto tt = src_str.substr(first, last - first + 1);
403 const auto arg_type_and_names = [](
const std::string &arg_string_decl)
404 -> std::vector<std::pair<std::string, std::string>> {
406 std::vector<std::pair<std::string, std::string>> result;
407 const auto args_string =
408 arg_string_decl.substr(1, arg_string_decl.size() - 2);
409 std::stack<char> grouping_chars;
410 std::string type_name;
411 std::string var_name;
414 for (
int i = 0; i < args_string.size(); ++i) {
415 if (isspace(args_string[i]) && grouping_chars.empty()) {
418 }
else if (args_string[i] ==
',') {
420 if (var_name[0] ==
'&') {
422 var_name = var_name.substr(1);
424 result.emplace_back(std::make_pair(type_name, var_name));
429 temp.push_back(args_string[i]);
432 if (args_string[i] ==
'<') {
433 grouping_chars.push(args_string[i]);
435 if (args_string[i] ==
'>') {
437 grouping_chars.pop();
443 if (var_name[0] ==
'&') {
445 var_name = var_name.substr(1);
447 result.emplace_back(std::make_pair(type_name, var_name));
453 if (arg_type_and_names.size() == 2) {
454 const auto trim_space = [](std::string &stripString) {
455 while (!stripString.empty() && std::isspace(*stripString.begin())) {
456 stripString.erase(stripString.begin());
459 while (!stripString.empty() && std::isspace(*stripString.rbegin())) {
460 stripString.erase(stripString.length() - 1);
464 auto type_name = arg_type_and_names[1].first;
465 trim_space(type_name);
468 if (type_name.find(
"vector<double>") != std::string::npos) {
469 var_type = Variational_Arg_Type::Vec_Double;
470 }
else if (type_name ==
"double") {
471 var_type = Variational_Arg_Type::Double;
482 static const std::unordered_map<std::string, std::string>
483 FORWARD_TYPE_CONVERSION_MAP{{
"int",
"int&"}, {
"double",
"double&"}};
484 std::vector<std::pair<std::string, std::string>> forward_types;
486 std::vector<std::string> byval_casted_arg_names;
487 for (
const auto &[type, name] : arg_type_and_names) {
489 if (FORWARD_TYPE_CONVERSION_MAP.find(type) !=
490 FORWARD_TYPE_CONVERSION_MAP.end()) {
491 auto iter = FORWARD_TYPE_CONVERSION_MAP.find(type);
492 forward_types.emplace_back(std::make_pair(iter->second, name));
493 byval_casted_arg_names.emplace_back(name);
495 forward_types.emplace_back(std::make_pair(type, name));
501 std::string arg_clause_new;
502 arg_clause_new.push_back(
'(');
503 for (
const auto &[type, name] : forward_types) {
504 arg_clause_new.append(type);
505 arg_clause_new.push_back(
' ');
506 arg_clause_new.append(name);
507 arg_clause_new.push_back(
',');
510 arg_clause_new.pop_back();
516 const auto first_square_bracket = src_str.find_first_of(
"[");
517 const auto last_square_bracket = src_str.find_first_of(
"]");
518 const auto capture_type = src_str.substr(
519 first_square_bracket, last_square_bracket - first_square_bracket + 1);
520 if (!capture_type.empty() && capture_type ==
"[=]") {
526 if constexpr (std::conjunction_v<
527 std::is_copy_assignable<CaptureArgs>...>) {
529 optional_copy_capture_vars = std::forward_as_tuple(_capture_vars...);
532 "Capture variable type is non-copyable. Cannot use capture by "
538 std::string capture_preamble =
"";
539 const auto replaceVarName = [](std::string &str,
const std::string &from,
540 const std::string &to) {
541 size_t start_pos = str.find(from);
542 if (start_pos != std::string::npos) {
543 str.replace(start_pos, from.length(), to);
546 if (!capture_var_names.empty()) {
547 std::string args_string =
"";
548 TupleToTypeArgString co(args_string);
549 __internal__::tuple_for_each(capture_vars, co);
550 args_string =
"," + args_string.substr(0, args_string.length() - 1);
557 for (
auto [i, capture_name] :
558 qcor::enumerate(qcor::split(capture_var_names,
','))) {
559 const auto old_name =
"arg_" + std::to_string(i);
560 replaceVarName(args_string, old_name, capture_name);
563 tt.insert(last - capture_type.size(), args_string);
564 arg_clause_new.append(args_string);
568 first = src_str.find_first_of(
"{");
569 last = src_str.find_last_of(
"}");
570 auto rr = src_str.substr(first, last - first + 1);
571 arg_clause_new.push_back(
')');
575 std::stringstream ss;
576 ss <<
"__qpu__ void foo" << arg_clause_new << rr;
580 auto jit_src = ss.str();
581 first = jit_src.find_first_of(
"{");
582 if (!capture_var_names.empty()) jit_src.insert(first + 1, capture_preamble);
584 if (!byval_casted_arg_names.empty()) {
585 std::stringstream cache_string, restore_string;
586 for (
const auto &var : byval_casted_arg_names) {
587 cache_string <<
"auto __" << var <<
"__cached__ = " << var <<
";\n";
588 restore_string << var <<
" = __" << var <<
"__cached__;\n";
590 const auto begin = jit_src.find_first_of(
"{");
591 jit_src.insert(begin + 1, cache_string.str());
592 const auto end = jit_src.find_last_of(
"}");
593 jit_src.insert(end, restore_string.str());
596 std::cout <<
"JITSRC:\n" << jit_src <<
"\n";
598 qjit.jit_compile(jit_src);
601 template <
typename... FunctionArgs>
602 void eval_with_parent(std::shared_ptr<CompositeInstruction> parent,
603 FunctionArgs &&...args) {
604 this->operator()(parent, std::forward<FunctionArgs>(args)...);
607 template <
typename... FunctionArgs>
608 void operator()(std::shared_ptr<CompositeInstruction> parent,
609 FunctionArgs &&...args) {
611 auto kernel_args_tuple = std::forward_as_tuple(args...);
613 if (!optional_copy_capture_vars.has_value()) {
616 auto final_args_tuple = std::tuple_cat(kernel_args_tuple, capture_vars);
618 [&](
auto &&...args) {
619 qjit.invoke_with_parent_forwarding(
"foo", parent, args...);
622 }
else if constexpr (std::conjunction_v<
623 std::is_copy_assignable<CaptureArgs>...>) {
627 auto final_args_tuple =
628 std::tuple_cat(kernel_args_tuple, optional_copy_capture_vars.value());
630 [&](
auto &&...args) {
631 qjit.invoke_with_parent_forwarding(
"foo", parent, args...);
637 template <
typename... FunctionArgs>
638 void operator()(FunctionArgs &&...args) {
640 auto kernel_args_tuple = std::forward_as_tuple(args...);
641 if (!optional_copy_capture_vars.has_value()) {
644 auto final_args_tuple = std::tuple_cat(kernel_args_tuple, capture_vars);
646 [&](
auto &&...args) { qjit.invoke_forwarding(
"foo", args...); },
648 }
else if constexpr (std::conjunction_v<
649 std::is_copy_assignable<CaptureArgs>...>) {
651 auto final_args_tuple =
652 std::tuple_cat(kernel_args_tuple, optional_copy_capture_vars.value());
654 [&](
auto &&...args) { qjit.invoke_forwarding(
"foo", args...); },
659 template <
typename... FunctionArgs>
660 double observe(std::shared_ptr<Operator> obs, FunctionArgs... args) {
661 return observe(*obs.get(), args...);
664 template <
typename... FunctionArgs>
665 double observe(
Operator &obs, FunctionArgs... args) {
667 return internal::observe<FunctionArgs...>(obs, callable, args...);
670 template <
typename... FunctionArgs>
671 void ctrl(std::shared_ptr<CompositeInstruction> ir,
672 const std::vector<qubit> &ctrl_qbits, FunctionArgs... args) {
674 internal::apply_control<FunctionArgs...>(ir, ctrl_qbits, callable, args...);
677 template <
typename... FunctionArgs>
678 void ctrl(std::shared_ptr<CompositeInstruction> ir,
679 const std::vector<int> &ctrl_idxs, FunctionArgs... args) {
680 std::vector<qubit> ctrl_qubit_vec;
681 for (
int i = 0; i < ctrl_idxs.size(); i++) {
682 ctrl_qubit_vec.push_back(
683 {
"q",
static_cast<size_t>(ctrl_idxs[i]),
nullptr});
685 ctrl(ir, ctrl_qubit_vec, args...);
688 template <
typename... FunctionArgs>
689 void ctrl(std::shared_ptr<CompositeInstruction> ir,
int ctrl_qbit,
690 FunctionArgs... args) {
691 ctrl(ir, std::vector<int>{ctrl_qbit}, args...);
694 template <
typename... FunctionArgs>
695 void ctrl(std::shared_ptr<CompositeInstruction> ir,
qubit ctrl_qbit,
696 FunctionArgs... args) {
697 ctrl(ir, std::vector<qubit>{ctrl_qbit}, args...);
700 template <
typename... FunctionArgs>
701 void ctrl(std::shared_ptr<CompositeInstruction> ir,
qreg ctrl_qbits,
702 FunctionArgs... args) {
703 std::vector<qubit> ctrl_qubit_vec;
704 for (
int i = 0; i < ctrl_qbits.size(); i++) {
705 ctrl_qubit_vec.push_back(ctrl_qbits[i]);
707 ctrl(ir, ctrl_qubit_vec, args...);
710 template <
typename... FunctionArgs>
711 void adjoint(std::shared_ptr<CompositeInstruction> parent_kernel,
712 FunctionArgs... args) {
714 return internal::apply_adjoint<FunctionArgs...>(parent_kernel, callable,
718 template <
typename... FunctionArgs>
719 void print_kernel(std::ostream &os, FunctionArgs... args) {
721 return internal::print_kernel<FunctionArgs...>(callable, os, args...);
724 template <
typename... FunctionArgs>
725 void print_kernel(FunctionArgs... args) {
726 print_kernel(std::cout, args...);
729 template <
typename... FunctionArgs>
730 std::size_t n_instructions(FunctionArgs... args) {
732 return internal::n_instructions<FunctionArgs...>(callable, args...);
735 template <
typename... FunctionArgs>
736 UnitaryMatrix as_unitary_matrix(FunctionArgs... args) {
738 return internal::as_unitary_matrix<FunctionArgs...>(callable, args...);
741 template <
typename... FunctionArgs>
742 std::string openqasm(FunctionArgs... args) {
744 return internal::openqasm<FunctionArgs...>(callable, args...);
748 #define qpu_lambda(EXPR, ...) _qpu_lambda(#EXPR, #__VA_ARGS__, ##__VA_ARGS__)
750 template <
typename... Args>
751 using callable_function_ptr = void (*)(std::shared_ptr<CompositeInstruction>,
754 template <
typename... Args>
757 callable_function_ptr<Args...> *readOnly = 0;
758 callable_function_ptr<Args...> &function_pointer;
759 std::function<void(std::shared_ptr<CompositeInstruction>, Args...)>
761 std::shared_ptr<CompositeInstruction> parent_kernel;
767 template <
typename... CaptureArgs>
769 : function_pointer(*readOnly),
774 KernelSignature(callable_function_ptr<Args...> &&f) : function_pointer(f) {}
780 std::is_base_of_v<QuantumKernel<KernelType, Args...>, KernelType>,
782 KernelSignature(KernelType &kernel)
783 : function_pointer(*readOnly),
784 lambda_func([&](std::shared_ptr<CompositeInstruction> pp, Args... a) {
787 kernel.disable_destructor =
true;
789 pp->addInstructions(kernel.parent_kernel->getInstructions());
795 KernelSignature(
void *&f_ptr)
796 : function_pointer((callable_function_ptr<Args...> &)f_ptr) {}
798 void operator()(std::shared_ptr<CompositeInstruction> ir, Args... args) {
800 lambda_func(ir, args...);
804 function_pointer(ir, args...);
807 void operator()(Args... args) { operator()(parent_kernel, args...); }
809 void set_parent_kernel(std::shared_ptr<CompositeInstruction> ir) {
813 void ctrl(std::shared_ptr<CompositeInstruction> ir,
814 const std::vector<qubit> &ctrl_qbits, Args... args) {
815 internal::apply_control<Args...>(ir, ctrl_qbits, *
this, args...);
818 void ctrl(std::shared_ptr<CompositeInstruction> ir,
819 const std::vector<int> ctrl_idxs, Args... args) {
820 std::vector<qubit> ctrl_qubit_vec;
821 for (
int i = 0; i < ctrl_idxs.size(); i++) {
822 ctrl_qubit_vec.push_back(
823 {
"q",
static_cast<size_t>(ctrl_idxs[i]),
nullptr});
825 ctrl(ir, ctrl_qubit_vec, args...);
827 void ctrl(std::shared_ptr<CompositeInstruction> ir,
int ctrl_qbit,
829 ctrl(ir, std::vector<int>{ctrl_qbit}, args...);
832 void ctrl(std::shared_ptr<CompositeInstruction> ir,
qubit ctrl_qbit,
834 ctrl(ir, std::vector<qubit>{ctrl_qbit}, args...);
837 void ctrl(std::shared_ptr<CompositeInstruction> ir,
qreg ctrl_qbits,
839 std::vector<qubit> ctrl_qubit_vec;
840 for (
int i = 0; i < ctrl_qbits.size(); i++) {
841 ctrl_qubit_vec.push_back(ctrl_qbits[i]);
843 ctrl(ir, ctrl_qubit_vec, args...);
846 void adjoint(std::shared_ptr<CompositeInstruction> ir, Args... args) {
847 internal::apply_adjoint<Args...>(ir, *
this, args...);
850 void print_kernel(std::ostream &os, Args... args) {
851 return internal::print_kernel<Args...>(*
this, os, args...);
854 void print_kernel(Args... args) { print_kernel(std::cout, args...); }
856 std::size_t n_instructions(Args... args) {
857 return internal::n_instructions<Args...>(*
this, args...);
860 UnitaryMatrix as_unitary_matrix(Args... args) {
861 return internal::as_unitary_matrix<Args...>(*
this, args...);
864 std::string openqasm(Args... args) {
865 return internal::openqasm<Args...>(*
this, args...);
868 double observe(std::shared_ptr<Operator> obs, Args... args) {
869 return observe(*obs.get(), args...);
872 double observe(Operator &obs, Args... args) {
873 return internal::observe<Args...>(obs, *
this, args...);
888 inline void init_kernel_signature_args_impl(
889 std::shared_ptr<CompositeInstruction> ir) {}
890 template <
typename T,
typename... ArgsType>
891 void init_kernel_signature_args_impl(std::shared_ptr<CompositeInstruction> ir,
892 T &t, ArgsType &...Args);
896 template <
typename... T>
897 void init_kernel_signature_args(std::shared_ptr<CompositeInstruction> ir,
898 T &...multi_inputs) {
899 init_kernel_signature_args_impl(ir, multi_inputs...);
904 template <
typename T,
typename... ArgsType>
905 void init_kernel_signature_args_impl(std::shared_ptr<CompositeInstruction> ir,
906 T &t, ArgsType &...Args) {
907 init_kernel_signature_args(ir, Args...);
912 template <
typename T,
typename... ArgsType>
913 void init_kernel_signature_args_impl(std::shared_ptr<CompositeInstruction> ir,
914 std::vector<T> &vec_arg,
916 for (
auto &el : vec_arg) {
918 init_kernel_signature_args_impl(ir, el);
921 init_kernel_signature_args(ir, Args...);
925 template <
typename... ArgsType>
926 void init_kernel_signature_args_impl(
927 std::shared_ptr<CompositeInstruction> ir,
928 KernelSignature<ArgsType...> &kernel_signature) {
929 kernel_signature.set_parent_kernel(ir);
937 template <
typename... Args>
938 void apply_control(std::shared_ptr<CompositeInstruction> parent_kernel,
939 const std::vector<qubit> &ctrl_qbits,
940 KernelSignature<Args...> &kernelCallable, Args... args) {
941 std::vector<std::pair<std::string, size_t>> ctrl_qubits;
942 for (
const auto &qb : ctrl_qbits) {
943 ctrl_qubits.emplace_back(std::make_pair(qb.first, qb.second));
950 const bool cached_is_compute_section =
951 ::quantum::qrt_impl->isComputeSection();
952 if (cached_is_compute_section) {
953 ::quantum::qrt_impl->__end_mark_segment_as_compute();
957 auto tempKernel = qcor::__internal__::create_composite(
"temp_control");
958 kernelCallable(tempKernel, args...);
960 if (cached_is_compute_section) {
961 ::quantum::qrt_impl->__begin_mark_segment_as_compute();
964 auto ctrlKernel = qcor::__internal__::create_and_expand_ctrl_u(
965 {{
"U", tempKernel}, {
"control-idx", ctrl_qubits}});
972 if (cached_is_compute_section) {
973 for (
int instId = 0; instId < ctrlKernel->nInstructions(); ++instId) {
974 ctrlKernel->attachMetadata(instId,
975 {{
"__qcor__compute__segment__",
true}});
979 for (
int instId = 0; instId < ctrlKernel->nInstructions(); ++instId) {
980 parent_kernel->addInstruction(ctrlKernel->getInstruction(instId));
983 quantum::set_current_program(parent_kernel);
986 bool is_not_measure(std::shared_ptr<xacc::Instruction> inst);
987 std::vector<std::shared_ptr<xacc::Instruction>> handle_adjoint_instructions(
988 std::vector<std::shared_ptr<xacc::Instruction>>,
989 std::shared_ptr<CompositeInstruction>);
991 template <
typename... Args>
992 void apply_adjoint(std::shared_ptr<CompositeInstruction> parent_kernel,
993 KernelSignature<Args...> &kernelCallable, Args... args) {
994 auto tempKernel = qcor::__internal__::create_composite(
"temp_adjoint");
995 kernelCallable(tempKernel, args...);
998 auto instructions = tempKernel->getInstructions();
999 std::shared_ptr<CompositeInstruction> program = tempKernel;
1002 if (!std::all_of(instructions.cbegin(), instructions.cend(),
1003 [](
const auto &inst) { return is_not_measure(inst); })) {
1004 error(
"Unable to create Adjoint for kernels that have Measure operations.");
1007 auto new_instructions =
1008 internal::handle_adjoint_instructions(instructions, tempKernel);
1011 parent_kernel->addInstructions(std::move(new_instructions),
false);
1013 ::quantum::set_current_program(parent_kernel);
1016 template <
typename... Args>
1017 double observe(Operator &obs, KernelSignature<Args...> &kernelCallable,
1019 auto tempKernel = qcor::__internal__::create_composite(
"temp_observe");
1020 kernelCallable(tempKernel, args...);
1021 auto instructions = tempKernel->getInstructions();
1023 if (!std::all_of(instructions.cbegin(), instructions.cend(),
1024 [](
const auto &inst) { return is_not_measure(inst); })) {
1025 error(
"Unable to observe kernels that already have Measure operations.");
1028 xacc::internal_compiler::execute_pass_manager();
1031 Operator observable;
1032 auto obs_str = obs.toString();
1033 std::hash<std::string> hasher;
1034 auto operator_hash = hasher(obs_str);
1035 if (__internal__::cached_observables.count(operator_hash)) {
1036 observable = __internal__::cached_observables[operator_hash];
1038 if (obs_str.find(
"^") != std::string::npos) {
1039 auto fermionObservable = createOperator(
"fermion", obs_str);
1040 observable = operatorTransform(
"jw", fermionObservable);
1042 }
else if (obs_str.find(
"X") != std::string::npos ||
1043 obs_str.find(
"Y") != std::string::npos ||
1044 obs_str.find(
"Z") != std::string::npos) {
1045 observable = createOperator(
"pauli", obs_str);
1047 __internal__::cached_observables.insert({operator_hash, observable});
1051 std::tuple<Args...> tmp(std::forward_as_tuple(args...));
1052 auto q = std::get<qreg>(tmp);
1053 return qcor::observe(tempKernel, observable, q);
1056 template <
typename... Args>
1057 UnitaryMatrix as_unitary_matrix(KernelSignature<Args...> &kernelCallable,
1059 auto tempKernel = qcor::__internal__::create_composite(
"temp_as_unitary");
1060 kernelCallable(tempKernel, args...);
1061 auto instructions = tempKernel->getInstructions();
1063 if (!std::all_of(instructions.cbegin(), instructions.cend(),
1064 [](
const auto &inst) { return is_not_measure(inst); })) {
1066 "Unable to compute unitary matrix for kernels that already have "
1067 "Measure operations.");
1070 return __internal__::map_composite_to_unitary_matrix(tempKernel);
1073 template <
typename... Args>
1074 std::string openqasm(KernelSignature<Args...> &kernelCallable, Args... args) {
1075 auto tempKernel = qcor::__internal__::create_composite(
"temp_as_openqasm");
1076 kernelCallable(tempKernel, args...);
1077 xacc::internal_compiler::execute_pass_manager();
1078 return __internal__::translate(
"staq", tempKernel);
1081 template <
typename... Args>
1082 void print_kernel(KernelSignature<Args...> &kernelCallable, std::ostream &os,
1084 auto tempKernel = qcor::__internal__::create_composite(
"temp_print");
1085 kernelCallable(tempKernel, args...);
1086 xacc::internal_compiler::execute_pass_manager();
1087 os << tempKernel->toString() <<
"\n";
1090 template <
typename... Args>
1091 std::size_t n_instructions(KernelSignature<Args...> &kernelCallable,
1093 auto tempKernel = qcor::__internal__::create_composite(
"temp_count_insts");
1094 kernelCallable(tempKernel, args...);
1095 return tempKernel->nInstructions();