QCOR
qcor_utils.hpp
1 #pragma once
2 
3 #include <argparse.hpp>
4 // #include <complex>
5 #include <iostream>
6 #include <memory>
7 #include <tuple>
8 #include <vector>
9 #include <Eigen/Dense>
10 
11 #include "qcor_ir.hpp"
12 
13 namespace xacc {
14 class IRProvider;
15 class IRTransformation;
16 class AcceleratorBuffer;
17 namespace internal_compiler {
18  class qreg;
19 }
20 } // namespace xacc
21 
22 namespace qcor {
23 
24 namespace constants {
25 static constexpr double pi = 3.141592653589793238;
26 }
27 
28 namespace arg {
29 // Expose ArgumentParser for custom instantiation
30 using ArgumentParser = argparse::ArgumentParser;
31 
32 // Default argument parser
33 ArgumentParser &get_parser();
34 
35 // Parameter packing
36 // Call add_argument with variadic number of string arguments
37 template <typename... Targs>
38 argparse::Argument &add_argument(Targs... Fargs) {
39  return get_parser().add_argument(Fargs...);
40 }
41 
42 // Getter for options with default values.
43 // @throws std::logic_error if there is no such option
44 // @throws std::logic_error if the option has no value
45 // @throws std::bad_any_cast if the option is not of type T
46 //
47 template <typename T = std::string>
48 T get_argument(std::string_view argument_name) {
49  return get_parser().get<T>(argument_name);
50 }
51 
52 // Main entry point for parsing command-line arguments using this
53 // ArgumentParser
54 // @throws std::runtime_error in case of any invalid argument
55 //
56 void parse_args(int argc, const char *const argv[]);
57 } // namespace arg
58 
59 
60 template <typename T>
61 using PairList = std::vector<std::pair<T, T>>;
62 using HeterogeneousMap = xacc::HeterogeneousMap;
63 using IRTransformation = xacc::IRTransformation;
64 using IRProvider = xacc::IRProvider;
66 using UnitaryMatrix = Eigen::MatrixXcd;
67 using DenseMatrix = Eigen::MatrixXcd;
68 
69 // The ResultsBuffer is returned upon completion of
70 // the taskInitiate async call, it contains the buffer,
71 // the optimal value for the objective function, and the
72 // optimal parameters
73 // class ResultsBuffer {
74 // public:
75 // xacc::internal_compiler::qreg q_buffer;
76 // double opt_val;
77 // std::vector<double> opt_params;
78 // double value;
79 // };
80 
81 // A Handle is just a future on ResultsBuffer
82 // using Handle = std::future<ResultsBuffer>;
83 
84 // Sync up a Handle
85 // ResultsBuffer sync(Handle &handle);
86 
87 // Indicate we have an error with the given message.
88 // This should abort execution
89 void error(const std::string &msg);
90 std::vector<std::string> split(const std::string &str, char delimiter);
91 
92 void persist_var_to_qreg(const std::string &key, double &val, qreg &q);
93 void persist_var_to_qreg(const std::string &key, int &val, qreg &q);
94 
95 template <typename T>
96 std::vector<T> linspace(T a, T b, size_t N) {
97  T h = (b - a) / static_cast<T>(N - 1);
98  std::vector<T> xs(N);
99  typename std::vector<T>::iterator x;
100  T val;
101  for (x = xs.begin(), val = a; x != xs.end(); ++x, val += h) *x = val;
102  return xs;
103 }
104 
105 inline std::vector<int> range(int N) {
106  std::vector<int> vec(N);
107  std::iota(vec.begin(), vec.end(), 0);
108  return vec;
109 }
110 
111 inline std::vector<int> range(int start, int stop, int step) {
112  if (step == 0) {
113  error("step for range must be non-zero.");
114  }
115 
116  int i = start;
117  std::vector<int> vec;
118  while ((step > 0) ? (i < stop) : (i > stop)) {
119  vec.push_back(i);
120  i += step;
121  }
122  return vec;
123 }
124 
125 inline std::vector<int> range(int start, int stop) {
126  return range(start, stop, 1);
127 }
128 
129 // Get size() of any types that have size() implemented.
130 template <typename T>
131 int len(const T &countable) {
132  return countable.size();
133 }
134 
135 template <typename T>
136 int len(T &countable) {
137  return countable.size();
138 }
139 
140 // Python-like print instructions:
141 inline void print() { std::cout << "\n"; }
142 template <typename T, typename... TAIL>
143 void print(const T &t, TAIL... tail) {
144  std::cout << t << " ";
145  print(tail...);
146 }
147 
148 std::shared_ptr<qcor::IRTransformation> createTransformation(
149  const std::string &transform_type);
150 
151 // The TranslationFunctor maps vector<double> to a tuple of Args...
152 template <typename... Args>
153 using TranslationFunctor =
154  std::function<std::tuple<Args...>(const std::vector<double> &)>;
155 
156 // ArgsTranslator takes a std function that maps a
157 // vector<double> argument to a tuple corresponding to
158 // the arguments for the quantum kernel in question
159 //
160 // FIXME provide example here
161 template <typename... Args>
163  protected:
164  TranslationFunctor<Args...> functor;
165 
166  public:
167  ArgsTranslator(TranslationFunctor<Args...> ts) : functor(ts) {}
168 
169  std::tuple<Args...> operator()(const std::vector<double> &x) {
170  return functor(x);
171  }
172 };
173 
174 template <typename... Args>
175 std::shared_ptr<ArgsTranslator<Args...>> createArgsTranslator(
176  TranslationFunctor<Args...> functor) {
177  return std::make_shared<ArgsTranslator<Args...>>(functor);
178 }
179 
180 // The GradientEvaluator is user-provided function that sets the
181 // gradient dx for a given variational iteration at parameter set x
182 using GradientEvaluator =
183  std::function<void(std::vector<double> x, std::vector<double> &dx)>;
184 
185 namespace __internal__ {
186 
187 UnitaryMatrix map_composite_to_unitary_matrix(
188  std::shared_ptr<CompositeInstruction> composite);
189 
190 std::string translate(const std::string compiler,
191  std::shared_ptr<CompositeInstruction> program);
192 
193 void append_plugin_path(const std::string path);
194 
195 // Internal function for creating a CompositeInstruction, this lets us
196 // keep XACC out of the include headers here and put it in the cpp.
197 std::shared_ptr<qcor::CompositeInstruction> create_composite(std::string name);
198 
199 // Return the CTRL-U CompositeInstruction generator
200 std::shared_ptr<qcor::CompositeInstruction> create_ctrl_u();
201 std::shared_ptr<qcor::CompositeInstruction> create_and_expand_ctrl_u(
202  HeterogeneousMap &&m);
203 
204 // Return the IR Transformation
205 std::shared_ptr<qcor::IRTransformation> get_transformation(
206  const std::string &transform_type);
207 
208 // return the IR Provider
209 std::shared_ptr<qcor::IRProvider> get_provider();
210 
211 // Decompose the given unitary matrix with the specified decomposition
212 // algorithm.
213 std::shared_ptr<qcor::CompositeInstruction>
214 decompose_unitary(const std::string algorithm, UnitaryMatrix &mat,
215  qreg &buffer);
216 
217 // Decompose the given unitary matrix with the specified decomposition algorithm
218 // and optimizer
219 // std::shared_ptr<qcor::CompositeInstruction>
220 // decompose_unitary(const std::string algorithm, UnitaryMatrix &mat, qreg &buffer,
221 // std::shared_ptr<xacc::Optimizer> optimizer);
222 
223 // Utility for calling a Functor via mapping a tuple of Args to
224 // a sequence of Args...
225 template <typename Function, typename Tuple, size_t... I>
226 auto evaluate_shared_ptr_fn_with_tuple_args(Function f, Tuple t,
227  std::index_sequence<I...>) {
228  return f->operator()(std::get<I>(t)...);
229 }
230 
231 // Utility for calling a Functor via mapping a tuple of Args to
232 // a sequence of Args...
233 template <typename Function, typename Tuple>
234 auto evaluate_shared_ptr_fn_with_tuple_args(Function f, Tuple t) {
235  static constexpr auto size = std::tuple_size<Tuple>::value;
236  return evaluate_shared_ptr_fn_with_tuple_args(
237  f, t, std::make_index_sequence<size>{});
238 }
239 
240 // Utility for calling a Functor via mapping a tuple of Args to
241 // a sequence of Args...
242 template <typename Function, typename Tuple, size_t... I>
243 auto evaluate_function_with_tuple_args(Function f, Tuple t,
244  std::index_sequence<I...>) {
245  return f(std::get<I>(t)...);
246 }
247 
248 // Utility for calling a Functor via mapping a tuple of Args to
249 // a sequence of Args...
250 template <typename Function, typename Tuple>
251 auto evaluate_function_with_tuple_args(Function f, Tuple t) {
252  static constexpr auto size = std::tuple_size<Tuple>::value;
253  return evaluate_function_with_tuple_args(f, t,
254  std::make_index_sequence<size>{});
255 }
256 
257 // This internal utility class enables the merging of all
258 // quantum kernel double or std::vector<double> parameters
259 // into a single std::vector<double> (these correspond to circuit
260 // rotation parameters)
262  public:
263  std::vector<double> &vec;
264  ConvertDoubleLikeToVectorDouble(std::vector<double> &v) : vec(v) {}
265  void operator()(std::vector<double> tuple_element_vec) {
266  for (auto &e : tuple_element_vec) {
267  vec.push_back(e);
268  }
269  }
270  void operator()(double tuple_element_double) {
271  vec.push_back(tuple_element_double);
272  }
273  template <typename T>
274  void operator()(T &) {}
275 };
276 
277 // Utility function for looping over tuple elements
278 template <typename TupleType, typename FunctionType>
279 void tuple_for_each(
280  TupleType &&, FunctionType,
281  std::integral_constant<
282  size_t, std::tuple_size<
283  typename std::remove_reference<TupleType>::type>::value>) {}
284 // Utility function for looping over tuple elements
285 template <std::size_t I, typename TupleType, typename FunctionType,
286  typename = typename std::enable_if<
287  I != std::tuple_size<typename std::remove_reference<
288  TupleType>::type>::value>::type>
289 // Utility function for looping over tuple elements
290 void tuple_for_each(TupleType &&t, FunctionType f,
291  std::integral_constant<size_t, I>) {
292  f(std::get<I>(t));
293  __internal__::tuple_for_each(std::forward<TupleType>(t), f,
294  std::integral_constant<size_t, I + 1>());
295 }
296 // Utility function for looping over tuple elements
297 template <typename TupleType, typename FunctionType>
298 void tuple_for_each(TupleType &&t, FunctionType f) {
299  __internal__::tuple_for_each(std::forward<TupleType>(t), f,
300  std::integral_constant<size_t, 0>());
301 }
302 } // namespace __internal__
303 
304 // Create and return a random vector<ScalarType> of the given size
305 // where all elements are within the given range
306 std::vector<double> random_vector(const double l_range, const double r_range,
307  const std::size_t size);
308 
309 // Take a function and return a TranslationFunctor
310 template <typename... Args>
311 auto args_translator(
312  std::function<std::tuple<Args...>(const std::vector<double>)>
313  &&functor_lambda) {
314  return TranslationFunctor<Args...>(functor_lambda);
315 }
316 
317 // C++17 python-like enumerate utility function
318 template <typename T, typename TIter = decltype(std::begin(std::declval<T>())),
319  typename = decltype(std::end(std::declval<T>()))>
320 constexpr auto enumerate(T &&iterable) {
321  struct iterator {
322  size_t i;
323  TIter iter;
324  bool operator!=(const iterator &other) const { return iter != other.iter; }
325  void operator++() {
326  ++i;
327  ++iter;
328  }
329  auto operator*() const { return std::tie(i, *iter); }
330  };
331  struct iterable_wrapper {
332  T iterable;
333  auto begin() { return iterator{0, std::begin(iterable)}; }
334  auto end() { return iterator{0, std::end(iterable)}; }
335  };
336  return iterable_wrapper{std::forward<T>(iterable)};
337 }
338 
339 // Set the backend that quantum kernels are targeting
340 void set_backend(const std::string &backend);
341 
342 // Utility function to expose the XASM xacc Compiler
343 // from the cpp implementation and not include it in the header list above.
344 std::shared_ptr<CompositeInstruction> compile(const std::string &src);
345 
346 // Toggle verbose mode
347 void set_verbose(bool verbose);
348 
349 // Get if we are verbose or not
350 bool get_verbose();
351 
352 // Set the shots for a given quantum kernel execution
353 void set_shots(const int shots);
354 
355 // constexpr std::complex<double> I{0.0, 1.0};
356 // // Note: cannot use std::complex_literal
357 // // because https://gcc.gnu.org/onlinedocs/gcc/Complex.html#Complex
358 // inline constexpr std::complex<double> operator"" _i(long double x) noexcept {
359 // return {0., static_cast<double>(x)};
360 // }
361 
362 #define qcor_expect(test_condition) \
363  { \
364  if (!(test_condition)) { \
365  std::stringstream ss; \
366  ss << __FILE__ << ":" << __LINE__ << ": Assertion failed: '" \
367  << #test_condition << "'."; \
368  error(ss.str()); \
369  } \
370  }
371 } // namespace qcor
qcor
Definition: qcor_syntax_handler.cpp:15
xacc::internal_compiler::qreg
Definition: qalloc.hpp:101
qcor::ArgsTranslator
Definition: qcor_utils.hpp:162
qcor::__internal__::ConvertDoubleLikeToVectorDouble
Definition: qcor_utils.hpp:261