Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
apply_large_kernel_to_input.cpp
Go to the documentation of this file.
1 /*
2 Created on Fri Jun 26 14:13:26 2020
3 Copyright 2020 Peter Rakyta, Ph.D.
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 
17 @author: Peter Rakyta, Ph.D.
18 */
26 #include "tbb/tbb.h"
27 #include <algorithm>
28 #include <array>
29 #include <type_traits>
30 #include <utility>
31 
32 template<typename MatrixT>
33 using KernelLargeComplexT = typename std::remove_reference<decltype(std::declval<MatrixT&>()[0])>::type;
34 
35 template<typename MatrixT>
36 void apply_large_kernel_to_input_impl(MatrixT& unitary, MatrixT& input, std::vector<int> involved_qbits, const int& matrix_size);
37 
38 template<typename MatrixT>
39 void apply_large_kernel_from_right_impl(MatrixT& unitary, MatrixT& input, std::vector<int> involved_qbits, const int& matrix_size);
40 
41 template<typename MatrixT>
42 void apply_nqbit_kernel_to_matrix_input_from_right_impl(MatrixT& unitary, MatrixT& input, std::vector<int> involved_qbits, const int& matrix_size);
43 
44 template<typename MatrixT>
45 void apply_nqbit_kernel_to_matrix_input_impl(MatrixT& unitary, MatrixT& input, std::vector<int> involved_qbits, const int& matrix_size);
46 
47 template<typename MatrixT>
48 void apply_2qbit_kernel_to_matrix_input_impl(MatrixT& two_qbit_unitary, MatrixT& input, const int& inner_qbit, const int& outer_qbit, const int& matrix_size);
49 
50 template<typename MatrixT>
51 void apply_2qbit_kernel_to_matrix_input_from_right_impl(MatrixT& two_qbit_unitary, MatrixT& input, const int& inner_qbit, const int& outer_qbit, const int& matrix_size);
52 
53 template<typename MatrixT>
54 void apply_crot_kernel_to_matrix_input_impl(MatrixT& u3_1qbit1, MatrixT& u3_1qbit2, MatrixT& input, const int& target_qbit, const int& control_qbit, const int& matrix_size);
55 
56 template<typename MatrixT>
57 void apply_crot_kernel_to_matrix_input_from_right_impl(MatrixT& u3_1qbit1, MatrixT& u3_1qbit2, MatrixT& input, const int& target_qbit, const int& control_qbit, const int& matrix_size);
58 
59 
60 int get_grain_size(int index_step){
61  int grain_size=2;
62  for (int step=1; step<7; step++){
63  if (index_step <= 1<<step){
64  grain_size = 256/(1<<step);
65  }
66  }
67  return grain_size;
68 }
69 
70 template<typename MatrixT>
71 MatrixT transpose_local_kernel_impl(const MatrixT& unitary) {
72  MatrixT transposed = unitary.copy();
73  for (int row = 0; row < unitary.rows; ++row) {
74  for (int col = 0; col < unitary.cols; ++col) {
75  transposed[row * unitary.cols + col] = unitary[col * unitary.cols + row];
76  }
77  }
78  return transposed;
79 }
80 
81 template<typename MatrixT>
82 void apply_large_kernel_to_input_impl(MatrixT& unitary, MatrixT& input, std::vector<int> involved_qbits, const int& matrix_size){
83 
84  if (input.cols==1){
85  switch(involved_qbits.size()){
86  case 2: apply_2qbit_kernel_to_state_vector_input(unitary, input, involved_qbits[0], involved_qbits[1], matrix_size); break;
87  case 3: apply_3qbit_kernel_to_state_vector_input(unitary,input,involved_qbits,matrix_size); break;
88  case 4: apply_4qbit_kernel_to_state_vector_input(unitary,input,involved_qbits,matrix_size); break;
89  case 5: apply_5qbit_kernel_to_state_vector_input(unitary,input,involved_qbits,matrix_size); break;
90  default: throw std::invalid_argument("Unsupported number of qubits for state vector.");
91  }
92  }
93  else
94  {
95  if (involved_qbits.size() == 2) {
96  apply_2qbit_kernel_to_matrix_input_impl(unitary, input, involved_qbits[0], involved_qbits[1], matrix_size);
97  return;
98  }
99 
100  apply_nqbit_kernel_to_matrix_input_impl(unitary, input, std::move(involved_qbits), matrix_size);
101  }
102 }
103 
104 template<typename MatrixT>
105 void apply_large_kernel_from_right_impl(MatrixT& unitary, MatrixT& input, std::vector<int> involved_qbits, const int& matrix_size){
106 
107  if (input.cols == 1) {
108  throw std::invalid_argument("Right-apply is not supported for column state vectors.");
109  }
110 
111  if (involved_qbits.size() < 2 || involved_qbits.size() > 5) {
112  throw std::invalid_argument("Unsupported number of qubits for right-applied matrix input.");
113  }
114 
115  if (involved_qbits.size() == 2) {
116  apply_2qbit_kernel_to_matrix_input_from_right_impl(unitary, input, involved_qbits[0], involved_qbits[1], matrix_size);
117  return;
118  }
119 
120  apply_nqbit_kernel_to_matrix_input_from_right_impl(unitary, input, std::move(involved_qbits), matrix_size);
121 }
122 
123 template<typename MatrixT>
124 void apply_nqbit_kernel_to_matrix_input_impl(MatrixT& unitary, MatrixT& input, std::vector<int> involved_qbits, const int& matrix_size) {
125 
126  using ComplexT = KernelLargeComplexT<MatrixT>;
127 
128  const int n = static_cast<int>(involved_qbits.size());
129  const int block_size = 1 << n;
130 
131  if (input.cols == 1) {
132  throw std::invalid_argument("Left-apply large matrix-input dispatch received a column state vector.");
133  }
134 
135  if (n < 2 || n > 5) {
136  throw std::invalid_argument("Unsupported number of qubits for left-applied matrix input.");
137  }
138 
139  if (unitary.rows != block_size || unitary.cols != block_size) {
140  throw std::invalid_argument("Left-apply large-kernel dispatch received a mismatched local kernel size.");
141  }
142 
143  std::sort(involved_qbits.begin(), involved_qbits.end());
144 
145  int qubit_num = 0;
146  int dim = 1;
147  while (dim < matrix_size) {
148  dim <<= 1;
149  qubit_num++;
150  }
151 
152  std::vector<int> non_targets;
153  non_targets.reserve(qubit_num - n);
154  for (int q = 0; q < qubit_num; ++q) {
155  if (!std::binary_search(involved_qbits.begin(), involved_qbits.end(), q)) {
156  non_targets.push_back(q);
157  }
158  }
159 
160  std::vector<int> block_pattern(block_size);
161  for (int k = 0; k < block_size; ++k) {
162  int idx = 0;
163  for (int bit = 0; bit < n; ++bit) {
164  if (k & (1 << bit)) {
165  idx |= (1 << involved_qbits[bit]);
166  }
167  }
168  block_pattern[k] = idx;
169  }
170 
171  const int num_blocks = matrix_size >> n;
172  const ComplexT* unitary_data = unitary.get_data();
173  ComplexT* input_data = input.get_data();
174  const int unitary_stride = unitary.stride;
175  const int input_stride = input.stride;
176  std::array<int, 32> indices;
177  std::array<ComplexT, 32> source;
178  std::array<ComplexT, 32> out;
179 
180  for (int col = 0; col < input.cols; ++col) {
181  for (int iter_idx = 0; iter_idx < num_blocks; ++iter_idx) {
182  int base = 0;
183  for (size_t i = 0; i < non_targets.size(); ++i) {
184  if (iter_idx & (1ULL << i)) {
185  base |= (1 << non_targets[i]);
186  }
187  }
188 
189  for (int k = 0; k < block_size; ++k) {
190  indices[k] = base | block_pattern[k];
191  source[k] = input_data[indices[k] * input_stride + col];
192  }
193 
194  for (int out_idx = 0; out_idx < block_size; ++out_idx) {
195  ComplexT accum{};
196  accum.real = 0;
197  accum.imag = 0;
198 
199  for (int in_idx = 0; in_idx < block_size; ++in_idx) {
200  const ComplexT kernel_element = unitary_data[out_idx * unitary_stride + in_idx];
201  const ComplexT source_element = source[in_idx];
202  accum.real += kernel_element.real * source_element.real - kernel_element.imag * source_element.imag;
203  accum.imag += kernel_element.real * source_element.imag + kernel_element.imag * source_element.real;
204  }
205 
206  out[out_idx] = accum;
207  }
208 
209  for (int out_idx = 0; out_idx < block_size; ++out_idx) {
210  input_data[indices[out_idx] * input_stride + col] = out[out_idx];
211  }
212  }
213  }
214 }
215 
216 template<typename MatrixT>
217 void apply_nqbit_kernel_to_matrix_input_from_right_impl(MatrixT& unitary, MatrixT& input, std::vector<int> involved_qbits, const int& matrix_size) {
218 
219  using ComplexT = KernelLargeComplexT<MatrixT>;
220 
221  const int n = static_cast<int>(involved_qbits.size());
222  const int block_size = 1 << n;
223 
224  if (unitary.rows != block_size || unitary.cols != block_size) {
225  throw std::invalid_argument("Right-apply large-kernel dispatch received a mismatched local kernel size.");
226  }
227 
228  std::sort(involved_qbits.begin(), involved_qbits.end());
229 
230  int qubit_num = 0;
231  int dim = 1;
232  while (dim < matrix_size) {
233  dim <<= 1;
234  qubit_num++;
235  }
236 
237  std::vector<int> non_targets;
238  non_targets.reserve(qubit_num - n);
239  for (int q = 0; q < qubit_num; ++q) {
240  if (!std::binary_search(involved_qbits.begin(), involved_qbits.end(), q)) {
241  non_targets.push_back(q);
242  }
243  }
244 
245  std::vector<int> block_pattern(block_size);
246  for (int k = 0; k < block_size; ++k) {
247  int idx = 0;
248  for (int bit = 0; bit < n; ++bit) {
249  if (k & (1 << bit)) {
250  idx |= (1 << involved_qbits[bit]);
251  }
252  }
253  block_pattern[k] = idx;
254  }
255 
256  const int num_blocks = matrix_size >> n;
257  const ComplexT* unitary_data = unitary.get_data();
258  ComplexT* input_data = input.get_data();
259  const int unitary_stride = unitary.stride;
260  const int input_stride = input.stride;
261  std::array<int, 32> indices;
262  std::array<ComplexT, 32> source;
263  std::array<ComplexT, 32> out;
264 
265  for (int row = 0; row < input.rows; ++row) {
266  const int row_offset = row * input_stride;
267 
268  for (int iter_idx = 0; iter_idx < num_blocks; ++iter_idx) {
269  int base = 0;
270  for (size_t i = 0; i < non_targets.size(); ++i) {
271  if (iter_idx & (1ULL << i)) {
272  base |= (1 << non_targets[i]);
273  }
274  }
275 
276  for (int k = 0; k < block_size; ++k) {
277  indices[k] = base | block_pattern[k];
278  source[k] = input_data[row_offset + indices[k]];
279  }
280 
281  for (int out_idx = 0; out_idx < block_size; ++out_idx) {
282  ComplexT accum{};
283  accum.real = 0;
284  accum.imag = 0;
285 
286  for (int in_idx = 0; in_idx < block_size; ++in_idx) {
287  const ComplexT kernel_element = unitary_data[in_idx * unitary_stride + out_idx];
288  const ComplexT source_element = source[in_idx];
289  accum.real += kernel_element.real * source_element.real - kernel_element.imag * source_element.imag;
290  accum.imag += kernel_element.real * source_element.imag + kernel_element.imag * source_element.real;
291  }
292 
293  out[out_idx] = accum;
294  }
295 
296  for (int out_idx = 0; out_idx < block_size; ++out_idx) {
297  input_data[row_offset + indices[out_idx]] = out[out_idx];
298  }
299  }
300  }
301 }
302 
311 template<typename MatrixT>
312 void apply_2qbit_kernel_to_matrix_input_impl(MatrixT& two_qbit_unitary, MatrixT& input, const int& inner_qbit, const int& outer_qbit, const int& matrix_size){
313 
314  int index_step_outer = 1 << outer_qbit;
315  int index_step_inner = 1 << inner_qbit;
316  int current_idx = 0;
317 
318  for (int current_idx_pair_outer=current_idx + index_step_outer; current_idx_pair_outer<input.rows; current_idx_pair_outer=current_idx_pair_outer+(index_step_outer << 1)){
319 
320  for (int current_idx_inner = 0; current_idx_inner < index_step_outer; current_idx_inner=current_idx_inner+(index_step_inner<<1)){
321 
322  for (int idx=0; idx<index_step_inner; idx++){
323 
324  int current_idx_outer_loc = current_idx + current_idx_inner + idx;
325  int current_idx_inner_loc = current_idx + current_idx_inner + idx + index_step_inner;
326  int current_idx_outer_pair_loc = current_idx_pair_outer + idx + current_idx_inner;
327  int current_idx_inner_pair_loc = current_idx_pair_outer + idx + current_idx_inner + index_step_inner;
328 
329  int row_offset_outer = current_idx_outer_loc*input.stride;
330  int row_offset_outer_pair = current_idx_outer_pair_loc*input.stride;
331  int row_offset_inner = current_idx_inner_loc*input.stride;
332  int row_offset_inner_pair = current_idx_inner_pair_loc*input.stride;
333  //input.print_matrix();
334  for ( int col_idx=0; col_idx<input.cols; col_idx++) {
335  int index_outer = row_offset_outer+col_idx;
336  int index_outer_pair = row_offset_outer_pair+col_idx;
337  int index_inner = row_offset_inner+col_idx;
338  int index_inner_pair = row_offset_inner_pair + col_idx;
339  int indexes[4] = {index_outer,index_inner,index_outer_pair,index_inner_pair};
340  KernelLargeComplexT<MatrixT> element_outer = input[index_outer];
341  KernelLargeComplexT<MatrixT> element_outer_pair = input[index_outer_pair];
342  KernelLargeComplexT<MatrixT> element_inner = input[index_inner];
343  KernelLargeComplexT<MatrixT> element_inner_pair = input[index_inner_pair];
344 
349  for (int mult_idx=0; mult_idx<4; mult_idx++){
350 
351  tmp1 = mult(two_qbit_unitary[mult_idx*4], element_outer);
352  tmp2 = mult(two_qbit_unitary[mult_idx*4 + 1], element_inner);
353  tmp3 = mult(two_qbit_unitary[mult_idx*4 + 2], element_outer_pair);
354  tmp4 = mult(two_qbit_unitary[mult_idx*4 + 3], element_inner_pair);
355  input[indexes[mult_idx]].real = tmp1.real + tmp2.real + tmp3.real + tmp4.real;
356  input[indexes[mult_idx]].imag = tmp1.imag + tmp2.imag + tmp3.imag + tmp4.imag;
357  }
358  }
359  }
360  }
361  current_idx = current_idx + (index_step_outer << 1);
362  }
363 
364 }
365 
366 template<typename MatrixT>
367 void apply_2qbit_kernel_to_matrix_input_from_right_impl(MatrixT& two_qbit_unitary, MatrixT& input, const int& inner_qbit, const int& outer_qbit, const int& matrix_size){
368 
369  int index_step_outer = 1 << outer_qbit;
370  int index_step_inner = 1 << inner_qbit;
371 
372  for (int row_idx = 0; row_idx < input.rows; row_idx++) {
373 
374  int row_offset = row_idx * input.stride;
375  int current_idx = 0;
376 
377  for (int current_idx_pair_outer = current_idx + index_step_outer; current_idx_pair_outer < input.cols; current_idx_pair_outer = current_idx_pair_outer + (index_step_outer << 1)) {
378 
379  for (int current_idx_inner = 0; current_idx_inner < index_step_outer; current_idx_inner = current_idx_inner + (index_step_inner << 1)) {
380 
381  for (int idx = 0; idx < index_step_inner; idx++) {
382 
383  int current_idx_outer_loc = current_idx + current_idx_inner + idx;
384  int current_idx_inner_loc = current_idx + current_idx_inner + idx + index_step_inner;
385  int current_idx_outer_pair_loc = current_idx_pair_outer + idx + current_idx_inner;
386  int current_idx_inner_pair_loc = current_idx_pair_outer + idx + current_idx_inner + index_step_inner;
387 
388  int indexes[4] = {
389  row_offset + current_idx_outer_loc,
390  row_offset + current_idx_inner_loc,
391  row_offset + current_idx_outer_pair_loc,
392  row_offset + current_idx_inner_pair_loc,
393  };
394 
395  KernelLargeComplexT<MatrixT> element_outer = input[indexes[0]];
396  KernelLargeComplexT<MatrixT> element_inner = input[indexes[1]];
397  KernelLargeComplexT<MatrixT> element_outer_pair = input[indexes[2]];
398  KernelLargeComplexT<MatrixT> element_inner_pair = input[indexes[3]];
399 
404 
405  for (int out_idx = 0; out_idx < 4; out_idx++) {
406 
407  tmp1 = mult(two_qbit_unitary[out_idx], element_outer);
408  tmp2 = mult(two_qbit_unitary[4 + out_idx], element_inner);
409  tmp3 = mult(two_qbit_unitary[8 + out_idx], element_outer_pair);
410  tmp4 = mult(two_qbit_unitary[12 + out_idx], element_inner_pair);
411 
412  input[indexes[out_idx]].real = tmp1.real + tmp2.real + tmp3.real + tmp4.real;
413  input[indexes[out_idx]].imag = tmp1.imag + tmp2.imag + tmp3.imag + tmp4.imag;
414  }
415  }
416  }
417 
418  current_idx = current_idx + (index_step_outer << 1);
419  }
420  }
421 
422  (void)matrix_size;
423 }
424 
434 template<typename MatrixT>
435 void
436 apply_crot_kernel_to_matrix_input_impl(MatrixT& u3_1qbit1, MatrixT& u3_1qbit2, MatrixT& input, const int& target_qbit, const int& control_qbit, const int& matrix_size) {
437 
438  int index_step_target = 1 << target_qbit;
439  int current_idx = 0;
440 
441 
442  for ( int current_idx_pair=current_idx + index_step_target; current_idx_pair<matrix_size; current_idx_pair=current_idx_pair+(index_step_target << 1) ) {
443 
444  for(int idx=0; idx<index_step_target; idx++) {
445  //tbb::parallel_for(0, index_step_target, 1, [&](int idx) {
446 
447  int current_idx_loc = current_idx + idx;
448  int current_idx_pair_loc = current_idx_pair + idx;
449 
450  int row_offset = current_idx_loc*input.stride;
451  int row_offset_pair = current_idx_pair_loc*input.stride;
452  for ( int col_idx=0; col_idx<input.cols; col_idx++) {
453 
454  int index = row_offset+col_idx;
455  int index_pair = row_offset_pair+col_idx;
456  if ( (current_idx_loc >> control_qbit) & 1 ) {
457 
458 
459 
460  KernelLargeComplexT<MatrixT> element = input[index];
461  KernelLargeComplexT<MatrixT> element_pair = input[index_pair];
462 
463  KernelLargeComplexT<MatrixT> tmp1 = mult(u3_1qbit1[0], element);
464  KernelLargeComplexT<MatrixT> tmp2 = mult(u3_1qbit1[1], element_pair);
465 
466  input[index].real = tmp1.real + tmp2.real;
467  input[index].imag = tmp1.imag + tmp2.imag;
468 
469  tmp1 = mult(u3_1qbit1[2], element);
470  tmp2 = mult(u3_1qbit1[3], element_pair);
471 
472  input[index_pair].real = tmp1.real + tmp2.real;
473  input[index_pair].imag = tmp1.imag + tmp2.imag;
474 
475  }
476 
477  else {
478  KernelLargeComplexT<MatrixT> element = input[index];
479  KernelLargeComplexT<MatrixT> element_pair = input[index_pair];
480 
481  KernelLargeComplexT<MatrixT> tmp1 = mult(u3_1qbit2[0], element);
482  KernelLargeComplexT<MatrixT> tmp2 = mult(u3_1qbit2[1], element_pair);
483 
484  input[index].real = tmp1.real + tmp2.real;
485  input[index].imag = tmp1.imag + tmp2.imag;
486 
487  tmp1 = mult(u3_1qbit2[2], element);
488  tmp2 = mult(u3_1qbit2[3], element_pair);
489 
490  input[index_pair].real = tmp1.real + tmp2.real;
491  input[index_pair].imag = tmp1.imag + tmp2.imag;
492  }
493  }
494 
495 
496  //});
497  }
498 
499 
500  current_idx = current_idx + (index_step_target << 1);
501 
502 
503  }
504 
505 
506 
507 }
508 
509 template<typename MatrixT>
510 void
511 apply_crot_kernel_to_matrix_input_from_right_impl(MatrixT& u3_1qbit1, MatrixT& u3_1qbit2, MatrixT& input, const int& target_qbit, const int& control_qbit, const int& matrix_size) {
512 
513  int index_step_target = 1 << target_qbit;
514 
515  for (int row_idx = 0; row_idx < input.rows; ++row_idx) {
516 
517  int row_offset = row_idx * input.stride;
518  int current_idx = 0;
519  int current_idx_pair = index_step_target;
520 
521  while (current_idx_pair < input.cols) {
522 
523  for (int idx = 0; idx < index_step_target; ++idx) {
524 
525  int current_idx_loc = current_idx + idx;
526  int current_idx_pair_loc = current_idx_pair + idx;
527  int index = row_offset + current_idx_loc;
528  int index_pair = row_offset + current_idx_pair_loc;
529 
530  const MatrixT& gate = ((current_idx_loc >> control_qbit) & 1) ? u3_1qbit1 : u3_1qbit2;
531 
532  KernelLargeComplexT<MatrixT> element = input[index];
533  KernelLargeComplexT<MatrixT> element_pair = input[index_pair];
534 
535  KernelLargeComplexT<MatrixT> tmp1 = mult(gate[0], element);
536  KernelLargeComplexT<MatrixT> tmp2 = mult(gate[2], element_pair);
537  input[index].real = tmp1.real + tmp2.real;
538  input[index].imag = tmp1.imag + tmp2.imag;
539 
540  tmp1 = mult(gate[1], element);
541  tmp2 = mult(gate[3], element_pair);
542  input[index_pair].real = tmp1.real + tmp2.real;
543  input[index_pair].imag = tmp1.imag + tmp2.imag;
544  }
545 
546  current_idx += (index_step_target << 1);
547  current_idx_pair += (index_step_target << 1);
548  }
549  }
550 
551  (void)matrix_size;
552 }
553 
554 void
555 apply_crot_kernel_to_matrix_input(Matrix& u3_1qbit1, Matrix& u3_1qbit2, Matrix& input, const int& target_qbit, const int& control_qbit, const int& matrix_size) {
556  apply_crot_kernel_to_matrix_input_impl(u3_1qbit1, u3_1qbit2, input, target_qbit, control_qbit, matrix_size);
557 }
558 
559 void
560 apply_crot_kernel_to_matrix_input(Matrix_float& u3_1qbit1, Matrix_float& u3_1qbit2, Matrix_float& input, const int& target_qbit, const int& control_qbit, const int& matrix_size) {
561  apply_crot_kernel_to_matrix_input_impl(u3_1qbit1, u3_1qbit2, input, target_qbit, control_qbit, matrix_size);
562 }
563 
564 void
565 apply_crot_kernel_to_matrix_input_from_right(Matrix& u3_1qbit1, Matrix& u3_1qbit2, Matrix& input, const int& target_qbit, const int& control_qbit, const int& matrix_size) {
566  apply_crot_kernel_to_matrix_input_from_right_impl(u3_1qbit1, u3_1qbit2, input, target_qbit, control_qbit, matrix_size);
567 }
568 
569 void
571  apply_crot_kernel_to_matrix_input_from_right_impl(u3_1qbit1, u3_1qbit2, input, target_qbit, control_qbit, matrix_size);
572 }
573 
574 void apply_large_kernel_to_input(Matrix& unitary, Matrix& input, std::vector<int> involved_qbits, const int& matrix_size) {
575  apply_large_kernel_to_input_impl(unitary, input, involved_qbits, matrix_size);
576 }
577 
578 void apply_large_kernel_to_input(Matrix_float& unitary, Matrix_float& input, std::vector<int> involved_qbits, const int& matrix_size) {
579  apply_large_kernel_to_input_impl(unitary, input, involved_qbits, matrix_size);
580 }
581 
582 void apply_large_kernel_from_right(Matrix& unitary, Matrix& input, std::vector<int> involved_qbits, const int& matrix_size) {
583  apply_large_kernel_from_right_impl(unitary, input, involved_qbits, matrix_size);
584 }
585 
586 void apply_large_kernel_from_right(Matrix_float& unitary, Matrix_float& input, std::vector<int> involved_qbits, const int& matrix_size) {
587  apply_large_kernel_from_right_impl(unitary, input, involved_qbits, matrix_size);
588 }
589 
590 void apply_2qbit_kernel_to_matrix_input(Matrix& two_qbit_unitary, Matrix& input, const int& inner_qbit, const int& outer_qbit, const int& matrix_size) {
591  apply_2qbit_kernel_to_matrix_input_impl(two_qbit_unitary, input, inner_qbit, outer_qbit, matrix_size);
592 }
593 
594 void apply_2qbit_kernel_to_matrix_input(Matrix_float& two_qbit_unitary, Matrix_float& input, const int& inner_qbit, const int& outer_qbit, const int& matrix_size) {
595  apply_2qbit_kernel_to_matrix_input_impl(two_qbit_unitary, input, inner_qbit, outer_qbit, matrix_size);
596 }
597 
598 void apply_2qbit_kernel_to_matrix_input_from_right(Matrix& two_qbit_unitary, Matrix& input, const int& inner_qbit, const int& outer_qbit, const int& matrix_size) {
599  apply_2qbit_kernel_to_matrix_input_from_right_impl(two_qbit_unitary, input, inner_qbit, outer_qbit, matrix_size);
600 }
601 
602 void apply_2qbit_kernel_to_matrix_input_from_right(Matrix_float& two_qbit_unitary, Matrix_float& input, const int& inner_qbit, const int& outer_qbit, const int& matrix_size) {
603  apply_2qbit_kernel_to_matrix_input_from_right_impl(two_qbit_unitary, input, inner_qbit, outer_qbit, matrix_size);
604 }
605 
void apply_4qbit_kernel_to_state_vector_input(Matrix &unitary, Matrix &input, std::vector< int > involved_qbits, const int &matrix_size)
typename std::remove_reference< decltype(std::declval< MatrixT & >()[0])>::type KernelLargeComplexT
void apply_large_kernel_to_input(Matrix &unitary, Matrix &input, std::vector< int > involved_qbits, const int &matrix_size)
void apply_nqbit_kernel_to_matrix_input_from_right_impl(MatrixT &unitary, MatrixT &input, std::vector< int > involved_qbits, const int &matrix_size)
void apply_crot_kernel_to_matrix_input(Matrix &u3_1qbit1, Matrix &u3_1qbit2, Matrix &input, const int &target_qbit, const int &control_qbit, const int &matrix_size)
QGD_Complex16 mult(QGD_Complex16 &a, QGD_Complex16 &b)
Call to calculate the product of two complex scalars.
Definition: common.cpp:298
void apply_2qbit_kernel_to_matrix_input_impl(MatrixT &two_qbit_unitary, MatrixT &input, const int &inner_qbit, const int &outer_qbit, const int &matrix_size)
Call to apply a two-qubit gate kernel on an input matrix.
void apply_2qbit_kernel_to_state_vector_input(Matrix &two_qbit_unitary, Matrix &input, const int &inner_qbit, const int &outer_qbit, const int &matrix_size)
void apply_crot_kernel_to_matrix_input_from_right(Matrix &u3_1qbit1, Matrix &u3_1qbit2, Matrix &input, const int &target_qbit, const int &control_qbit, const int &matrix_size)
void apply_large_kernel_from_right_impl(MatrixT &unitary, MatrixT &input, std::vector< int > involved_qbits, const int &matrix_size)
MatrixT transpose_local_kernel_impl(const MatrixT &unitary)
matrix_size
[load Umtx]
Definition: example.py:58
void apply_3qbit_kernel_to_state_vector_input(Matrix &unitary, Matrix &input, std::vector< int > involved_qbits, const int &matrix_size)
void apply_nqbit_kernel_to_matrix_input_impl(MatrixT &unitary, MatrixT &input, std::vector< int > involved_qbits, const int &matrix_size)
void apply_5qbit_kernel_to_state_vector_input(Matrix &unitary, Matrix &input, std::vector< int > involved_qbits, const int &matrix_size)
void apply_crot_kernel_to_matrix_input_from_right_impl(MatrixT &u3_1qbit1, MatrixT &u3_1qbit2, MatrixT &input, const int &target_qbit, const int &control_qbit, const int &matrix_size)
void apply_2qbit_kernel_to_matrix_input_from_right(Matrix &two_qbit_unitary, Matrix &input, const int &inner_qbit, const int &outer_qbit, const int &matrix_size)
Double-precision complex matrix (float64).
Definition: matrix.h:38
void apply_crot_kernel_to_matrix_input_impl(MatrixT &u3_1qbit1, MatrixT &u3_1qbit2, MatrixT &input, const int &target_qbit, const int &control_qbit, const int &matrix_size)
Call to apply crot gate kernel on an input matrix.
void apply_2qbit_kernel_to_matrix_input_from_right_impl(MatrixT &two_qbit_unitary, MatrixT &input, const int &inner_qbit, const int &outer_qbit, const int &matrix_size)
Single-precision complex matrix (float32).
Definition: matrix_float.h:41
void apply_large_kernel_to_input_impl(MatrixT &unitary, MatrixT &input, std::vector< int > involved_qbits, const int &matrix_size)
void apply_large_kernel_from_right(Matrix &unitary, Matrix &input, std::vector< int > involved_qbits, const int &matrix_size)
int get_grain_size(int index_step)
void apply_2qbit_kernel_to_matrix_input(Matrix &two_qbit_unitary, Matrix &input, const int &inner_qbit, const int &outer_qbit, const int &matrix_size)