28 #include <type_traits> 31 template<
typename MatrixT>
45 template<
typename MatrixT>
47 const std::vector<int>& control_qbits,
51 if (target_qbits.size() != 1) {
52 throw std::runtime_error(
"X gate kernel requires exactly 1 target qubit, got " +
53 std::to_string(target_qbits.size()));
60 for (
int current_idx_pair = current_idx + index_step_target;
62 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
64 for(
int idx = 0; idx < index_step_target; idx++) {
66 int current_idx_loc = current_idx + idx;
67 int current_idx_pair_loc = current_idx_pair + idx;
70 bool all_controls_active =
true;
73 all_controls_active =
false;
79 if (all_controls_active) {
81 long long row_offset = (
long long)current_idx_loc * input.stride;
82 long long row_offset_pair = (
long long)current_idx_pair_loc * input.stride;
85 input.get_data() + row_offset,
86 input.get_data() + row_offset + input.cols,
87 input.get_data() + row_offset_pair
91 current_idx = current_idx + (index_step_target << 1);
95 template<
typename MatrixT>
97 const std::vector<int>& control_qbits,
100 if (target_qbits.size() != 1) {
101 throw std::runtime_error(
"X gate kernel requires exactly 1 target qubit, got " +
102 std::to_string(target_qbits.size()));
108 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
109 long long row_offset = (
long long)row_idx * input.stride;
112 for (
int current_idx_pair = current_idx + index_step_target;
114 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
116 for (
int idx = 0; idx < index_step_target; ++idx) {
117 int current_idx_loc = current_idx + idx;
118 int current_idx_pair_loc = current_idx_pair + idx;
120 bool all_controls_active =
true;
123 all_controls_active =
false;
128 if (all_controls_active) {
129 std::swap(input[row_offset + current_idx_loc], input[row_offset + current_idx_pair_loc]);
133 current_idx = current_idx + (index_step_target << 1);
138 template<
typename MatrixT>
146 for (
int current_idx_pair = current_idx + index_step_target;
148 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
150 for(
int idx = 0; idx < index_step_target; idx++) {
152 int current_idx_loc = current_idx + idx;
153 int current_idx_pair_loc = current_idx_pair + idx;
156 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
158 int row_offset = current_idx_loc * input.stride;
159 int row_offset_pair = current_idx_pair_loc * input.stride;
161 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
162 int index = row_offset + col_idx;
163 int index_pair = row_offset_pair + col_idx;
169 input[index].real = element_pair.imag;
170 input[index].imag = -element_pair.real;
172 input[index_pair].real = -element.imag;
173 input[index_pair].imag = element.real;
177 current_idx = current_idx + (index_step_target << 1);
181 template<
typename MatrixT>
188 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
189 long long row_offset = (
long long)row_idx * input.stride;
192 for (
int current_idx_pair = current_idx + index_step_target;
194 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
196 for (
int idx = 0; idx < index_step_target; ++idx) {
197 int current_idx_loc = current_idx + idx;
198 int current_idx_pair_loc = current_idx_pair + idx;
200 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
201 int index = row_offset + current_idx_loc;
202 int index_pair = row_offset + current_idx_pair_loc;
207 input[index].real = -element_pair.imag;
208 input[index].imag = element_pair.real;
210 input[index_pair].real = element.imag;
211 input[index_pair].imag = -element.real;
215 current_idx = current_idx + (index_step_target << 1);
220 template<
typename MatrixT>
228 for (
int current_idx_pair = current_idx + index_step_target;
230 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
232 for(
int idx = 0; idx < index_step_target; idx++) {
234 int current_idx_loc = current_idx + idx;
235 int current_idx_pair_loc = current_idx_pair + idx;
238 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
240 int row_offset_pair = current_idx_pair_loc * input.stride;
242 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
243 int index_pair = row_offset_pair + col_idx;
246 input[index_pair].real = -input[index_pair].real;
247 input[index_pair].imag = -input[index_pair].imag;
251 current_idx = current_idx + (index_step_target << 1);
255 template<
typename MatrixT>
262 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
263 long long row_offset = (
long long)row_idx * input.stride;
266 for (
int current_idx_pair = current_idx + index_step_target;
268 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
270 for (
int idx = 0; idx < index_step_target; ++idx) {
271 int current_idx_loc = current_idx + idx;
272 int current_idx_pair_loc = current_idx_pair + idx;
274 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
275 int index_pair = row_offset + current_idx_pair_loc;
276 input[index_pair].real = -input[index_pair].real;
277 input[index_pair].imag = -input[index_pair].imag;
281 current_idx = current_idx + (index_step_target << 1);
286 template<
typename MatrixT>
290 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
292 for (
int current_idx_pair = current_idx + index_step_target;
294 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
296 for (
int idx = 0; idx < index_step_target; idx++) {
297 int current_idx_loc = current_idx + idx;
298 int current_idx_pair_loc = current_idx_pair + idx;
300 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
301 int row_offset = current_idx_loc * input.stride;
302 int row_offset_pair = current_idx_pair_loc * input.stride;
304 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
305 int index = row_offset + col_idx;
306 int index_pair = row_offset_pair + col_idx;
312 input[index].real = inv_sqrt2 * (element.real + element_pair.real);
313 input[index].imag = inv_sqrt2 * (element.imag + element_pair.imag);
315 input[index_pair].real = inv_sqrt2 * (element.real - element_pair.real);
316 input[index_pair].imag = inv_sqrt2 * (element.imag - element_pair.imag);
320 current_idx = current_idx + (index_step_target << 1);
324 template<
typename MatrixT>
327 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
329 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
330 long long row_offset = (
long long)row_idx * input.stride;
333 for (
int current_idx_pair = current_idx + index_step_target;
335 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
337 for (
int idx = 0; idx < index_step_target; ++idx) {
338 int current_idx_loc = current_idx + idx;
339 int current_idx_pair_loc = current_idx_pair + idx;
341 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
342 int index = row_offset + current_idx_loc;
343 int index_pair = row_offset + current_idx_pair_loc;
348 input[index].real = inv_sqrt2 * (element.real + element_pair.real);
349 input[index].imag = inv_sqrt2 * (element.imag + element_pair.imag);
351 input[index_pair].real = inv_sqrt2 * (element.real - element_pair.real);
352 input[index_pair].imag = inv_sqrt2 * (element.imag - element_pair.imag);
356 current_idx = current_idx + (index_step_target << 1);
361 template<
typename MatrixT>
366 for (
int current_idx_pair = current_idx + index_step_target;
368 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
370 for (
int idx = 0; idx < index_step_target; idx++) {
371 int current_idx_loc = current_idx + idx;
372 int current_idx_pair_loc = current_idx_pair + idx;
374 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
375 int row_offset_pair = current_idx_pair_loc * input.stride;
377 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
378 int index_pair = row_offset_pair + col_idx;
381 double real = input[index_pair].real;
382 double imag = input[index_pair].imag;
383 input[index_pair].real = -imag;
384 input[index_pair].imag =
real;
388 current_idx = current_idx + (index_step_target << 1);
392 template<
typename MatrixT>
396 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
397 long long row_offset = (
long long)row_idx * input.stride;
400 for (
int current_idx_pair = current_idx + index_step_target;
402 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
404 for (
int idx = 0; idx < index_step_target; ++idx) {
405 int current_idx_loc = current_idx + idx;
406 int current_idx_pair_loc = current_idx_pair + idx;
408 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
409 int index_pair = row_offset + current_idx_pair_loc;
410 double real = input[index_pair].real;
411 double imag = input[index_pair].imag;
412 input[index_pair].real = -imag;
413 input[index_pair].imag =
real;
417 current_idx = current_idx + (index_step_target << 1);
422 template<
typename MatrixT>
426 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
428 for (
int current_idx_pair = current_idx + index_step_target;
430 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
432 for (
int idx = 0; idx < index_step_target; idx++) {
433 int current_idx_loc = current_idx + idx;
434 int current_idx_pair_loc = current_idx_pair + idx;
436 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
437 int row_offset_pair = current_idx_pair_loc * input.stride;
439 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
440 int index_pair = row_offset_pair + col_idx;
443 double real = input[index_pair].real;
444 double imag = input[index_pair].imag;
445 input[index_pair].real = inv_sqrt2 * (real - imag);
446 input[index_pair].imag = inv_sqrt2 * (real + imag);
450 current_idx = current_idx + (index_step_target << 1);
454 template<
typename MatrixT>
457 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
459 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
460 long long row_offset = (
long long)row_idx * input.stride;
463 for (
int current_idx_pair = current_idx + index_step_target;
465 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
467 for (
int idx = 0; idx < index_step_target; ++idx) {
468 int current_idx_loc = current_idx + idx;
469 int current_idx_pair_loc = current_idx_pair + idx;
471 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
472 int index_pair = row_offset + current_idx_pair_loc;
473 double real = input[index_pair].real;
474 double imag = input[index_pair].imag;
475 input[index_pair].real = inv_sqrt2 * (real - imag);
476 input[index_pair].imag = inv_sqrt2 * (real + imag);
480 current_idx = current_idx + (index_step_target << 1);
485 template<
typename MatrixT>
489 if (target_qbits.size() != 2) {
490 throw std::runtime_error(
"SWAP gate kernel requires exactly 2 target qubits, got " +
491 std::to_string(target_qbits.size()));
494 int target_qbit1 = target_qbits[0];
495 int target_qbit2 = target_qbits[1];
497 std::vector<int> non_involved_qbits;
499 for (
int idx=0; idx<
qbit_num; idx++){
500 bool is_target = (idx == target_qbit1 || idx == target_qbit2);
501 bool is_control = std::find(control_qbits.begin(), control_qbits.end(), idx) != control_qbits.end();
502 if (!is_target && !is_control){
503 non_involved_qbits.push_back(idx);
508 int control_mask = 0;
513 for (
int block_idx=0; block_idx < matrix_size >> (qbit_num - non_involved_qbits.size()); block_idx++){
515 for (
size_t qdx=0; qdx<non_involved_qbits.size();qdx++){
516 if ((block_idx >> qdx) & 1) {
517 base |= (1<<non_involved_qbits[qdx]);
520 base |= control_mask;
521 int swap_idx = base|(1<<target_qbit1);
522 int swap_idx_pair = base|(1<<target_qbit2);
525 input.get_data() + swap_idx*input.stride,
526 input.get_data() + swap_idx*input.stride + input.cols,
527 input.get_data() + swap_idx_pair*input.stride
533 template<
typename MatrixT>
536 if (target_qbits.size() != 2) {
537 throw std::runtime_error(
"SWAP gate kernel requires exactly 2 target qubits, got " +
538 std::to_string(target_qbits.size()));
541 int target_qbit1 = target_qbits[0];
542 int target_qbit2 = target_qbits[1];
544 std::vector<int> non_involved_qbits;
546 for (
int idx = 0; idx <
qbit_num; idx++) {
547 bool is_target = (idx == target_qbit1 || idx == target_qbit2);
548 bool is_control = std::find(control_qbits.begin(), control_qbits.end(), idx) != control_qbits.end();
549 if (!is_target && !is_control) {
550 non_involved_qbits.push_back(idx);
554 int control_mask = 0;
559 int total_blocks = matrix_size >> (qbit_num - non_involved_qbits.size());
561 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
562 long long row_offset = (
long long)row_idx * input.stride;
564 for (
int block_idx = 0; block_idx < total_blocks; ++block_idx) {
566 for (
size_t qdx = 0; qdx < non_involved_qbits.size(); qdx++) {
567 if ((block_idx >> qdx) & 1) {
568 base |= (1 << non_involved_qbits[qdx]);
571 base |= control_mask;
572 int swap_idx = base | (1 << target_qbit1);
573 int swap_idx_pair = base | (1 << target_qbit2);
575 std::swap(input[row_offset + swap_idx], input[row_offset + swap_idx_pair]);
581 template<
typename MatrixT>
589 int loop_size = index_step_target < index_step_control ? index_step_target : index_step_control;
590 int iterations = control_qbit < target_qbit ?
Power_of_2(target_qbit - control_qbit - 1) :
Power_of_2(control_qbit - target_qbit - 1);
593 int idx01 = index_step_target;
594 int idx10 = index_step_control;
595 int idx11 = index_step_target + index_step_control;
597 const double phase_real = std::sqrt(3.0) / 2.0;
598 const double phase_imag = -0.5;
600 while (idx11 < matrix_size) {
601 for (
int jdx = 0; jdx < iterations; ++jdx) {
602 for (
int idx = 0; idx < loop_size; ++idx) {
603 int idx01_loc = idx01 + idx;
604 int idx10_loc = idx10 + idx;
605 int idx11_loc = idx11 + idx;
607 int offset01 = idx01_loc * input.stride;
608 int offset10 = idx10_loc * input.stride;
609 int offset11 = idx11_loc * input.stride;
611 for (
int col_idx = 0; col_idx < input.cols; ++col_idx) {
615 input[offset01 + col_idx].real = element10.imag;
616 input[offset01 + col_idx].imag = -element10.real;
618 input[offset10 + col_idx].real = element01.imag;
619 input[offset10 + col_idx].imag = -element01.real;
622 input[offset11 + col_idx].real = phase_real * element11.real - phase_imag * element11.imag;
623 input[offset11 + col_idx].imag = phase_real * element11.imag + phase_imag * element11.real;
627 idx00 += 2 * loop_size;
628 idx01 += 2 * loop_size;
629 idx10 += 2 * loop_size;
630 idx11 += 2 * loop_size;
633 idx00 += 2 * loop_size * iterations;
634 idx01 += 2 * loop_size * iterations;
635 idx10 += 2 * loop_size * iterations;
636 idx11 += 2 * loop_size * iterations;
641 template<
typename MatrixT>
649 int loop_size = index_step_target < index_step_control ? index_step_target : index_step_control;
650 int iterations = control_qbit < target_qbit ?
Power_of_2(target_qbit - control_qbit - 1) :
Power_of_2(control_qbit - target_qbit - 1);
652 const double phase_real = std::sqrt(3.0) / 2.0;
653 const double phase_imag = -0.5;
655 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
656 int offset = row_idx * input.stride;
659 int idx01 = index_step_target;
660 int idx10 = index_step_control;
661 int idx11 = index_step_target + index_step_control;
663 while (idx11 < matrix_size) {
664 for (
int jdx = 0; jdx < iterations; ++jdx) {
665 for (
int idx = 0; idx < loop_size; ++idx) {
666 int idx01_loc = idx01 + idx;
667 int idx10_loc = idx10 + idx;
668 int idx11_loc = idx11 + idx;
672 input[offset + idx01_loc].real = element10.imag;
673 input[offset + idx01_loc].imag = -element10.real;
675 input[offset + idx10_loc].real = element01.imag;
676 input[offset + idx10_loc].imag = -element01.real;
679 input[offset + idx11_loc].real = phase_real * element11.real - phase_imag * element11.imag;
680 input[offset + idx11_loc].imag = phase_real * element11.imag + phase_imag * element11.real;
683 idx00 += 2 * loop_size;
684 idx01 += 2 * loop_size;
685 idx10 += 2 * loop_size;
686 idx11 += 2 * loop_size;
689 idx00 += 2 * loop_size * iterations;
690 idx01 += 2 * loop_size * iterations;
691 idx10 += 2 * loop_size * iterations;
692 idx11 += 2 * loop_size * iterations;
699 template<
typename MatrixT>
701 const std::vector<int>& control_qbits,
704 if (target_qbits.size() != 1) {
705 throw std::runtime_error(
"X gate kernel requires exactly 1 target qubit, got " +
706 std::to_string(target_qbits.size()));
711 int total_blocks = matrix_size >> (target_qbit + 1);
713 tbb::parallel_for(tbb::blocked_range<int>(0, total_blocks, 1024),
714 [&](
const tbb::blocked_range<int>& range) {
715 for (
int block_idx = range.begin(); block_idx != range.end(); ++block_idx) {
716 int current_idx = block_idx * (index_step_target << 1);
717 int current_idx_pair = current_idx + index_step_target;
719 for(
int idx = 0; idx < index_step_target; idx++) {
720 int current_idx_loc = current_idx + idx;
721 int current_idx_pair_loc = current_idx_pair + idx;
724 bool all_controls_active =
true;
727 all_controls_active =
false;
732 if (all_controls_active) {
733 long long row_offset = (
long long)current_idx_loc * input.stride;
734 long long row_offset_pair = (
long long)current_idx_pair_loc * input.stride;
737 input.get_data() + row_offset,
738 input.get_data() + row_offset + input.cols,
739 input.get_data() + row_offset_pair
748 template<
typename MatrixT>
750 const std::vector<int>& control_qbits,
752 if (target_qbits.size() != 1) {
753 throw std::runtime_error(
"X gate kernel requires exactly 1 target qubit, got " +
754 std::to_string(target_qbits.size()));
760 tbb::parallel_for(tbb::blocked_range<int>(0, input.rows, 32),
761 [&](
const tbb::blocked_range<int>& range) {
762 for (int row_idx = range.begin(); row_idx != range.end(); ++row_idx) {
763 long long row_offset = (long long)row_idx * input.stride;
766 for (int current_idx_pair = current_idx + index_step_target;
767 current_idx_pair < matrix_size;
768 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
770 for (int idx = 0; idx < index_step_target; ++idx) {
771 int current_idx_loc = current_idx + idx;
772 int current_idx_pair_loc = current_idx_pair + idx;
774 bool all_controls_active = true;
775 for (int control_qbit : control_qbits) {
776 if (!((current_idx_loc >> control_qbit) & 1)) {
777 all_controls_active = false;
782 if (all_controls_active) {
783 std::swap(input[row_offset + current_idx_loc], input[row_offset + current_idx_pair_loc]);
787 current_idx = current_idx + (index_step_target << 1);
794 template<
typename MatrixT>
800 tbb::parallel_for(tbb::blocked_range<int>(0, matrix_size >> 1, 1024),
801 [&](
const tbb::blocked_range<int>& range) {
802 for (
int block_idx = range.begin(); block_idx != range.end(); ++block_idx) {
803 int current_idx = block_idx * (index_step_target << 1);
804 int current_idx_pair = current_idx + index_step_target;
806 if (current_idx_pair >= matrix_size)
continue;
808 for(
int idx = 0; idx < index_step_target; idx++) {
809 int current_idx_loc = current_idx + idx;
810 int current_idx_pair_loc = current_idx_pair + idx;
812 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
813 int row_offset = current_idx_loc * input.stride;
814 int row_offset_pair = current_idx_pair_loc * input.stride;
816 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
817 int index = row_offset + col_idx;
818 int index_pair = row_offset_pair + col_idx;
823 input[index].real = element_pair.imag;
824 input[index].imag = -element_pair.real;
826 input[index_pair].real = -element.imag;
827 input[index_pair].imag = element.real;
836 template<
typename MatrixT>
842 tbb::parallel_for(tbb::blocked_range<int>(0, input.rows, 32),
843 [&](
const tbb::blocked_range<int>& range) {
844 for (int row_idx = range.begin(); row_idx != range.end(); ++row_idx) {
845 long long row_offset = (long long)row_idx * input.stride;
847 for (int current_idx_pair = current_idx + index_step_target;
848 current_idx_pair < matrix_size;
849 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
850 for (int idx = 0; idx < index_step_target; ++idx) {
851 int current_idx_loc = current_idx + idx;
852 int current_idx_pair_loc = current_idx_pair + idx;
853 if ((control_qbit < 0) || ((current_idx_loc >> control_qbit) & 1)) {
854 int index = row_offset + current_idx_loc;
855 int index_pair = row_offset + current_idx_pair_loc;
856 KernelDedicatedComplexT<MatrixT> element = input[index];
857 KernelDedicatedComplexT<MatrixT> element_pair = input[index_pair];
858 input[index].real = -element_pair.imag;
859 input[index].imag = element_pair.real;
860 input[index_pair].real = element.imag;
861 input[index_pair].imag = -element.real;
864 current_idx = current_idx + (index_step_target << 1);
871 template<
typename MatrixT>
877 tbb::parallel_for(tbb::blocked_range<int>(0, matrix_size >> 1, 1024),
878 [&](
const tbb::blocked_range<int>& range) {
879 for (
int block_idx = range.begin(); block_idx != range.end(); ++block_idx) {
880 int current_idx = block_idx * (index_step_target << 1);
881 int current_idx_pair = current_idx + index_step_target;
883 if (current_idx_pair >= matrix_size)
continue;
885 for(
int idx = 0; idx < index_step_target; idx++) {
886 int current_idx_loc = current_idx + idx;
887 int current_idx_pair_loc = current_idx_pair + idx;
889 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
890 int row_offset_pair = current_idx_pair_loc * input.stride;
892 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
893 int index_pair = row_offset_pair + col_idx;
895 input[index_pair].real = -input[index_pair].real;
896 input[index_pair].imag = -input[index_pair].imag;
905 template<
typename MatrixT>
911 tbb::parallel_for(tbb::blocked_range<int>(0, input.rows, 32),
912 [&](
const tbb::blocked_range<int>& range) {
913 for (int row_idx = range.begin(); row_idx != range.end(); ++row_idx) {
914 long long row_offset = (long long)row_idx * input.stride;
916 for (int current_idx_pair = current_idx + index_step_target;
917 current_idx_pair < matrix_size;
918 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
919 for (int idx = 0; idx < index_step_target; ++idx) {
920 int current_idx_loc = current_idx + idx;
921 int current_idx_pair_loc = current_idx_pair + idx;
922 if ((control_qbit < 0) || ((current_idx_loc >> control_qbit) & 1)) {
923 int index_pair = row_offset + current_idx_pair_loc;
924 input[index_pair].real = -input[index_pair].real;
925 input[index_pair].imag = -input[index_pair].imag;
928 current_idx = current_idx + (index_step_target << 1);
935 template<
typename MatrixT>
938 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
940 tbb::parallel_for(tbb::blocked_range<int>(0, matrix_size >> 1, 1024),
941 [&](
const tbb::blocked_range<int>& range) {
942 for (
int block_idx = range.begin(); block_idx != range.end(); ++block_idx) {
943 int current_idx = block_idx * (index_step_target << 1);
944 int current_idx_pair = current_idx + index_step_target;
946 if (current_idx_pair >= matrix_size)
continue;
948 for (
int idx = 0; idx < index_step_target; idx++) {
949 int current_idx_loc = current_idx + idx;
950 int current_idx_pair_loc = current_idx_pair + idx;
952 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
953 int row_offset = current_idx_loc * input.stride;
954 int row_offset_pair = current_idx_pair_loc * input.stride;
956 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
957 int index = row_offset + col_idx;
958 int index_pair = row_offset_pair + col_idx;
963 input[index].real = inv_sqrt2 * (element.real + element_pair.real);
964 input[index].imag = inv_sqrt2 * (element.imag + element_pair.imag);
966 input[index_pair].real = inv_sqrt2 * (element.real - element_pair.real);
967 input[index_pair].imag = inv_sqrt2 * (element.imag - element_pair.imag);
976 template<
typename MatrixT>
979 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
981 tbb::parallel_for(tbb::blocked_range<int>(0, input.rows, 32),
982 [&](
const tbb::blocked_range<int>& range) {
983 for (int row_idx = range.begin(); row_idx != range.end(); ++row_idx) {
984 long long row_offset = (long long)row_idx * input.stride;
986 for (int current_idx_pair = current_idx + index_step_target;
987 current_idx_pair < matrix_size;
988 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
989 for (int idx = 0; idx < index_step_target; ++idx) {
990 int current_idx_loc = current_idx + idx;
991 int current_idx_pair_loc = current_idx_pair + idx;
992 if ((control_qbit < 0) || ((current_idx_loc >> control_qbit) & 1)) {
993 int index = row_offset + current_idx_loc;
994 int index_pair = row_offset + current_idx_pair_loc;
995 KernelDedicatedComplexT<MatrixT> element = input[index];
996 KernelDedicatedComplexT<MatrixT> element_pair = input[index_pair];
997 input[index].real = inv_sqrt2 * (element.real + element_pair.real);
998 input[index].imag = inv_sqrt2 * (element.imag + element_pair.imag);
999 input[index_pair].real = inv_sqrt2 * (element.real - element_pair.real);
1000 input[index_pair].imag = inv_sqrt2 * (element.imag - element_pair.imag);
1003 current_idx = current_idx + (index_step_target << 1);
1010 template<
typename MatrixT>
1014 tbb::parallel_for(tbb::blocked_range<int>(0, matrix_size >> 1, 1024),
1015 [&](
const tbb::blocked_range<int>& range) {
1016 for (
int block_idx = range.begin(); block_idx != range.end(); ++block_idx) {
1017 int current_idx = block_idx * (index_step_target << 1);
1018 int current_idx_pair = current_idx + index_step_target;
1020 if (current_idx_pair >= matrix_size)
continue;
1022 for (
int idx = 0; idx < index_step_target; idx++) {
1023 int current_idx_loc = current_idx + idx;
1024 int current_idx_pair_loc = current_idx_pair + idx;
1026 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1027 int row_offset_pair = current_idx_pair_loc * input.stride;
1029 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
1030 int index_pair = row_offset_pair + col_idx;
1032 double real = input[index_pair].real;
1033 double imag = input[index_pair].imag;
1034 input[index_pair].real = -imag;
1035 input[index_pair].imag =
real;
1044 template<
typename MatrixT>
1048 tbb::parallel_for(tbb::blocked_range<int>(0, input.rows, 32),
1049 [&](
const tbb::blocked_range<int>& range) {
1050 for (int row_idx = range.begin(); row_idx != range.end(); ++row_idx) {
1051 long long row_offset = (long long)row_idx * input.stride;
1052 int current_idx = 0;
1053 for (int current_idx_pair = current_idx + index_step_target;
1054 current_idx_pair < matrix_size;
1055 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
1056 for (int idx = 0; idx < index_step_target; ++idx) {
1057 int current_idx_loc = current_idx + idx;
1058 int current_idx_pair_loc = current_idx_pair + idx;
1059 if ((control_qbit < 0) || ((current_idx_loc >> control_qbit) & 1)) {
1060 int index_pair = row_offset + current_idx_pair_loc;
1061 double real = input[index_pair].real;
1062 double imag = input[index_pair].imag;
1063 input[index_pair].real = -imag;
1064 input[index_pair].imag = real;
1067 current_idx = current_idx + (index_step_target << 1);
1074 template<
typename MatrixT>
1077 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
1079 tbb::parallel_for(tbb::blocked_range<int>(0, matrix_size >> 1, 1024),
1080 [&](
const tbb::blocked_range<int>& range) {
1081 for (
int block_idx = range.begin(); block_idx != range.end(); ++block_idx) {
1082 int current_idx = block_idx * (index_step_target << 1);
1083 int current_idx_pair = current_idx + index_step_target;
1085 if (current_idx_pair >= matrix_size)
continue;
1087 for (
int idx = 0; idx < index_step_target; idx++) {
1088 int current_idx_loc = current_idx + idx;
1089 int current_idx_pair_loc = current_idx_pair + idx;
1091 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1092 int row_offset_pair = current_idx_pair_loc * input.stride;
1094 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
1095 int index_pair = row_offset_pair + col_idx;
1097 double real = input[index_pair].real;
1098 double imag = input[index_pair].imag;
1099 input[index_pair].real = inv_sqrt2 * (real - imag);
1100 input[index_pair].imag = inv_sqrt2 * (real + imag);
1109 template<
typename MatrixT>
1112 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
1114 tbb::parallel_for(tbb::blocked_range<int>(0, input.rows, 32),
1115 [&](
const tbb::blocked_range<int>& range) {
1116 for (int row_idx = range.begin(); row_idx != range.end(); ++row_idx) {
1117 long long row_offset = (long long)row_idx * input.stride;
1118 int current_idx = 0;
1119 for (int current_idx_pair = current_idx + index_step_target;
1120 current_idx_pair < matrix_size;
1121 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
1122 for (int idx = 0; idx < index_step_target; ++idx) {
1123 int current_idx_loc = current_idx + idx;
1124 int current_idx_pair_loc = current_idx_pair + idx;
1125 if ((control_qbit < 0) || ((current_idx_loc >> control_qbit) & 1)) {
1126 int index_pair = row_offset + current_idx_pair_loc;
1127 double real = input[index_pair].real;
1128 double imag = input[index_pair].imag;
1129 input[index_pair].real = inv_sqrt2 * (real - imag);
1130 input[index_pair].imag = inv_sqrt2 * (real + imag);
1133 current_idx = current_idx + (index_step_target << 1);
1140 template<
typename MatrixT>
1143 if (target_qbits.size() != 2) {
1144 throw std::runtime_error(
"SWAP gate kernel requires exactly 2 target qubits, got " +
1145 std::to_string(target_qbits.size()));
1148 int target_qbit1 = target_qbits[0];
1149 int target_qbit2 = target_qbits[1];
1151 std::vector<int> non_involved_qbits;
1153 for (
int idx=0; idx<
qbit_num; idx++){
1154 bool is_target = (idx == target_qbit1 || idx == target_qbit2);
1155 bool is_control = std::find(control_qbits.begin(), control_qbits.end(), idx) != control_qbits.end();
1156 if (!is_target && !is_control){
1157 non_involved_qbits.push_back(idx);
1162 int control_mask = 0;
1167 int total_blocks = matrix_size >> (qbit_num - non_involved_qbits.size());
1169 tbb::parallel_for(tbb::blocked_range<int>(0, total_blocks, 64),
1170 [&](
const tbb::blocked_range<int>& range) {
1171 for (
int block_idx = range.begin(); block_idx != range.end(); ++block_idx) {
1173 for (
size_t qdx=0; qdx<non_involved_qbits.size();qdx++){
1174 if ((block_idx >> qdx) & 1) {
1175 base |= (1<<non_involved_qbits[qdx]);
1178 base |= control_mask;
1179 int swap_idx = base|(1<<target_qbit1);
1180 int swap_idx_pair = base|(1<<target_qbit2);
1183 input.get_data() + swap_idx*input.stride,
1184 input.get_data() + swap_idx*input.stride + input.cols,
1185 input.get_data() + swap_idx_pair*input.stride
1193 template<
typename MatrixT>
1195 if (target_qbits.size() != 2) {
1196 throw std::runtime_error(
"SWAP gate kernel requires exactly 2 target qubits, got " +
1197 std::to_string(target_qbits.size()));
1200 int target_qbit1 = target_qbits[0];
1201 int target_qbit2 = target_qbits[1];
1203 std::vector<int> non_involved_qbits;
1205 for (
int idx = 0; idx <
qbit_num; idx++) {
1206 bool is_target = (idx == target_qbit1 || idx == target_qbit2);
1207 bool is_control = std::find(control_qbits.begin(), control_qbits.end(), idx) != control_qbits.end();
1208 if (!is_target && !is_control) {
1209 non_involved_qbits.push_back(idx);
1213 int control_mask = 0;
1218 int total_blocks = matrix_size >> (qbit_num - non_involved_qbits.size());
1220 tbb::parallel_for(tbb::blocked_range<int>(0, input.rows, 32),
1221 [&](
const tbb::blocked_range<int>& range) {
1222 for (int row_idx = range.begin(); row_idx != range.end(); ++row_idx) {
1223 long long row_offset = (long long)row_idx * input.stride;
1224 for (int block_idx = 0; block_idx < total_blocks; ++block_idx) {
1226 for (size_t qdx = 0; qdx < non_involved_qbits.size(); qdx++) {
1227 if ((block_idx >> qdx) & 1) {
1228 base |= (1 << non_involved_qbits[qdx]);
1231 base |= control_mask;
1232 int swap_idx = base | (1 << target_qbit1);
1233 int swap_idx_pair = base | (1 << target_qbit2);
1235 std::swap(input[row_offset + swap_idx], input[row_offset + swap_idx_pair]);
1243 template<
typename MatrixT>
1251 int loop_size = index_step_target < index_step_control ? index_step_target : index_step_control;
1252 int iterations = control_qbit < target_qbit ?
Power_of_2(target_qbit - control_qbit - 1) :
Power_of_2(control_qbit - target_qbit - 1);
1255 int idx01 = index_step_target;
1256 int idx10 = index_step_control;
1257 int idx11 = index_step_target + index_step_control;
1259 const double phase_real = std::sqrt(3.0) / 2.0;
1260 const double phase_imag = -0.5;
1262 while (idx11 < matrix_size) {
1263 for (
int jdx = 0; jdx < iterations; ++jdx) {
1264 tbb::parallel_for(0, loop_size, 1, [&](
int idx) {
1265 int idx01_loc = idx01 + idx;
1266 int idx10_loc = idx10 + idx;
1267 int idx11_loc = idx11 + idx;
1269 int offset01 = idx01_loc * input.stride;
1270 int offset10 = idx10_loc * input.stride;
1271 int offset11 = idx11_loc * input.stride;
1273 for (
int col_idx = 0; col_idx < input.cols; ++col_idx) {
1277 input[offset01 + col_idx].real = element10.imag;
1278 input[offset01 + col_idx].imag = -element10.real;
1280 input[offset10 + col_idx].real = element01.imag;
1281 input[offset10 + col_idx].imag = -element01.real;
1284 input[offset11 + col_idx].real = phase_real * element11.real - phase_imag * element11.imag;
1285 input[offset11 + col_idx].imag = phase_real * element11.imag + phase_imag * element11.real;
1289 idx00 += 2 * loop_size;
1290 idx01 += 2 * loop_size;
1291 idx10 += 2 * loop_size;
1292 idx11 += 2 * loop_size;
1295 idx00 += 2 * loop_size * iterations;
1296 idx01 += 2 * loop_size * iterations;
1297 idx10 += 2 * loop_size * iterations;
1298 idx11 += 2 * loop_size * iterations;
1302 template<
typename MatrixT>
1309 int loop_size = index_step_target < index_step_control ? index_step_target : index_step_control;
1310 int iterations = control_qbit < target_qbit ?
Power_of_2(target_qbit - control_qbit - 1) :
Power_of_2(control_qbit - target_qbit - 1);
1311 const double phase_real = std::sqrt(3.0) / 2.0;
1312 const double phase_imag = -0.5;
1314 tbb::parallel_for(tbb::blocked_range<int>(0, input.rows, 32),
1315 [&](
const tbb::blocked_range<int>& range) {
1316 for (int row_idx = range.begin(); row_idx != range.end(); ++row_idx) {
1317 int offset = row_idx * input.stride;
1319 int idx01 = index_step_target;
1320 int idx10 = index_step_control;
1321 int idx11 = index_step_target + index_step_control;
1323 while (idx11 < matrix_size) {
1324 for (int jdx = 0; jdx < iterations; ++jdx) {
1325 for (int idx = 0; idx < loop_size; ++idx) {
1326 int idx01_loc = idx01 + idx;
1327 int idx10_loc = idx10 + idx;
1328 int idx11_loc = idx11 + idx;
1330 KernelDedicatedComplexT<MatrixT> element01 = input[offset + idx01_loc];
1331 KernelDedicatedComplexT<MatrixT> element10 = input[offset + idx10_loc];
1332 input[offset + idx01_loc].real = element10.imag;
1333 input[offset + idx01_loc].imag = -element10.real;
1334 input[offset + idx10_loc].real = element01.imag;
1335 input[offset + idx10_loc].imag = -element01.real;
1337 KernelDedicatedComplexT<MatrixT> element11 = input[offset + idx11_loc];
1338 input[offset + idx11_loc].real = phase_real * element11.real - phase_imag * element11.imag;
1339 input[offset + idx11_loc].imag = phase_real * element11.imag + phase_imag * element11.real;
1342 idx00 += 2 * loop_size;
1343 idx01 += 2 * loop_size;
1344 idx10 += 2 * loop_size;
1345 idx11 += 2 * loop_size;
1348 idx00 += 2 * loop_size * iterations;
1349 idx01 += 2 * loop_size * iterations;
1350 idx10 += 2 * loop_size * iterations;
1351 idx11 += 2 * loop_size * iterations;
1360 template<
typename MatrixT>
1362 const std::vector<int>& control_qbits,
1365 if (target_qbits.size() != 1) {
1366 throw std::runtime_error(
"X gate kernel requires exactly 1 target qubit, got " +
1367 std::to_string(target_qbits.size()));
1372 int total_blocks = matrix_size >> (target_qbit + 1);
1374 #pragma omp parallel for schedule(static) 1375 for (
int block_idx = 0; block_idx < total_blocks; block_idx++) {
1376 int current_idx = block_idx * (index_step_target << 1);
1377 int current_idx_pair = current_idx + index_step_target;
1379 for(
int idx = 0; idx < index_step_target; idx++) {
1380 int current_idx_loc = current_idx + idx;
1381 int current_idx_pair_loc = current_idx_pair + idx;
1384 bool all_controls_active =
true;
1387 all_controls_active =
false;
1392 if (all_controls_active) {
1393 long long row_offset = (
long long)current_idx_loc * input.stride;
1394 long long row_offset_pair = (
long long)current_idx_pair_loc * input.stride;
1397 input.get_data() + row_offset,
1398 input.get_data() + row_offset + input.cols,
1399 input.get_data() + row_offset_pair
1406 template<
typename MatrixT>
1408 const std::vector<int>& control_qbits,
1410 if (target_qbits.size() != 1) {
1411 throw std::runtime_error(
"X gate kernel requires exactly 1 target qubit, got " +
1412 std::to_string(target_qbits.size()));
1418 #pragma omp parallel for schedule(static) 1419 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
1420 long long row_offset = (
long long)row_idx * input.stride;
1421 int current_idx = 0;
1423 for (
int current_idx_pair = current_idx + index_step_target;
1425 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
1427 for (
int idx = 0; idx < index_step_target; ++idx) {
1428 int current_idx_loc = current_idx + idx;
1429 int current_idx_pair_loc = current_idx_pair + idx;
1431 bool all_controls_active =
true;
1434 all_controls_active =
false;
1439 if (all_controls_active) {
1440 std::swap(input[row_offset + current_idx_loc], input[row_offset + current_idx_pair_loc]);
1444 current_idx = current_idx + (index_step_target << 1);
1449 template<
typename MatrixT>
1454 int total_blocks = matrix_size >> 1;
1456 #pragma omp parallel for schedule(static) 1457 for (
int block_idx = 0; block_idx < total_blocks; block_idx++) {
1458 int current_idx = block_idx * (index_step_target << 1);
1459 int current_idx_pair = current_idx + index_step_target;
1461 if (current_idx_pair >= matrix_size)
continue;
1463 for(
int idx = 0; idx < index_step_target; idx++) {
1464 int current_idx_loc = current_idx + idx;
1465 int current_idx_pair_loc = current_idx_pair + idx;
1467 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1468 int row_offset = current_idx_loc * input.stride;
1469 int row_offset_pair = current_idx_pair_loc * input.stride;
1471 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
1472 int index = row_offset + col_idx;
1473 int index_pair = row_offset_pair + col_idx;
1478 input[index].real = element_pair.imag;
1479 input[index].imag = -element_pair.real;
1481 input[index_pair].real = -element.imag;
1482 input[index_pair].imag = element.real;
1489 template<
typename MatrixT>
1495 #pragma omp parallel for schedule(static) 1496 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
1497 long long row_offset = (
long long)row_idx * input.stride;
1498 int current_idx = 0;
1499 for (
int current_idx_pair = current_idx + index_step_target;
1501 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
1502 for (
int idx = 0; idx < index_step_target; ++idx) {
1503 int current_idx_loc = current_idx + idx;
1504 int current_idx_pair_loc = current_idx_pair + idx;
1505 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1506 int index = row_offset + current_idx_loc;
1507 int index_pair = row_offset + current_idx_pair_loc;
1510 input[index].real = -element_pair.imag;
1511 input[index].imag = element_pair.real;
1512 input[index_pair].real = element.imag;
1513 input[index_pair].imag = -element.real;
1516 current_idx = current_idx + (index_step_target << 1);
1521 template<
typename MatrixT>
1526 int total_blocks = matrix_size >> 1;
1528 #pragma omp parallel for schedule(static) 1529 for (
int block_idx = 0; block_idx < total_blocks; block_idx++) {
1530 int current_idx = block_idx * (index_step_target << 1);
1531 int current_idx_pair = current_idx + index_step_target;
1533 if (current_idx_pair >= matrix_size)
continue;
1535 for(
int idx = 0; idx < index_step_target; idx++) {
1536 int current_idx_loc = current_idx + idx;
1537 int current_idx_pair_loc = current_idx_pair + idx;
1539 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1540 int row_offset_pair = current_idx_pair_loc * input.stride;
1542 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
1543 int index_pair = row_offset_pair + col_idx;
1545 input[index_pair].real = -input[index_pair].real;
1546 input[index_pair].imag = -input[index_pair].imag;
1553 template<
typename MatrixT>
1559 #pragma omp parallel for schedule(static) 1560 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
1561 long long row_offset = (
long long)row_idx * input.stride;
1562 int current_idx = 0;
1563 for (
int current_idx_pair = current_idx + index_step_target;
1565 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
1566 for (
int idx = 0; idx < index_step_target; ++idx) {
1567 int current_idx_loc = current_idx + idx;
1568 int current_idx_pair_loc = current_idx_pair + idx;
1569 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1570 int index_pair = row_offset + current_idx_pair_loc;
1571 input[index_pair].real = -input[index_pair].real;
1572 input[index_pair].imag = -input[index_pair].imag;
1575 current_idx = current_idx + (index_step_target << 1);
1580 template<
typename MatrixT>
1583 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
1584 int total_blocks = matrix_size >> 1;
1586 #pragma omp parallel for schedule(static) 1587 for (
int block_idx = 0; block_idx < total_blocks; block_idx++) {
1588 int current_idx = block_idx * (index_step_target << 1);
1589 int current_idx_pair = current_idx + index_step_target;
1591 if (current_idx_pair >= matrix_size)
continue;
1593 for (
int idx = 0; idx < index_step_target; idx++) {
1594 int current_idx_loc = current_idx + idx;
1595 int current_idx_pair_loc = current_idx_pair + idx;
1597 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1598 int row_offset = current_idx_loc * input.stride;
1599 int row_offset_pair = current_idx_pair_loc * input.stride;
1601 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
1602 int index = row_offset + col_idx;
1603 int index_pair = row_offset_pair + col_idx;
1608 input[index].real = inv_sqrt2 * (element.real + element_pair.real);
1609 input[index].imag = inv_sqrt2 * (element.imag + element_pair.imag);
1611 input[index_pair].real = inv_sqrt2 * (element.real - element_pair.real);
1612 input[index_pair].imag = inv_sqrt2 * (element.imag - element_pair.imag);
1619 template<
typename MatrixT>
1622 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
1624 #pragma omp parallel for schedule(static) 1625 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
1626 long long row_offset = (
long long)row_idx * input.stride;
1627 int current_idx = 0;
1628 for (
int current_idx_pair = current_idx + index_step_target;
1630 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
1631 for (
int idx = 0; idx < index_step_target; ++idx) {
1632 int current_idx_loc = current_idx + idx;
1633 int current_idx_pair_loc = current_idx_pair + idx;
1634 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1635 int index = row_offset + current_idx_loc;
1636 int index_pair = row_offset + current_idx_pair_loc;
1639 input[index].real = inv_sqrt2 * (element.real + element_pair.real);
1640 input[index].imag = inv_sqrt2 * (element.imag + element_pair.imag);
1641 input[index_pair].real = inv_sqrt2 * (element.real - element_pair.real);
1642 input[index_pair].imag = inv_sqrt2 * (element.imag - element_pair.imag);
1645 current_idx = current_idx + (index_step_target << 1);
1650 template<
typename MatrixT>
1653 int total_blocks = matrix_size >> 1;
1655 #pragma omp parallel for schedule(static) 1656 for (
int block_idx = 0; block_idx < total_blocks; block_idx++) {
1657 int current_idx = block_idx * (index_step_target << 1);
1658 int current_idx_pair = current_idx + index_step_target;
1660 if (current_idx_pair >= matrix_size)
continue;
1662 for (
int idx = 0; idx < index_step_target; idx++) {
1663 int current_idx_loc = current_idx + idx;
1664 int current_idx_pair_loc = current_idx_pair + idx;
1666 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1667 int row_offset_pair = current_idx_pair_loc * input.stride;
1669 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
1670 int index_pair = row_offset_pair + col_idx;
1672 double real = input[index_pair].real;
1673 double imag = input[index_pair].imag;
1674 input[index_pair].real = -imag;
1675 input[index_pair].imag =
real;
1682 template<
typename MatrixT>
1686 #pragma omp parallel for schedule(static) 1687 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
1688 long long row_offset = (
long long)row_idx * input.stride;
1689 int current_idx = 0;
1690 for (
int current_idx_pair = current_idx + index_step_target;
1692 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
1693 for (
int idx = 0; idx < index_step_target; ++idx) {
1694 int current_idx_loc = current_idx + idx;
1695 int current_idx_pair_loc = current_idx_pair + idx;
1696 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1697 int index_pair = row_offset + current_idx_pair_loc;
1698 double real = input[index_pair].real;
1699 double imag = input[index_pair].imag;
1700 input[index_pair].real = -imag;
1701 input[index_pair].imag =
real;
1704 current_idx = current_idx + (index_step_target << 1);
1709 template<
typename MatrixT>
1712 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
1713 int total_blocks = matrix_size >> 1;
1715 #pragma omp parallel for schedule(static) 1716 for (
int block_idx = 0; block_idx < total_blocks; block_idx++) {
1717 int current_idx = block_idx * (index_step_target << 1);
1718 int current_idx_pair = current_idx + index_step_target;
1720 if (current_idx_pair >= matrix_size)
continue;
1722 for (
int idx = 0; idx < index_step_target; idx++) {
1723 int current_idx_loc = current_idx + idx;
1724 int current_idx_pair_loc = current_idx_pair + idx;
1726 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1727 int row_offset_pair = current_idx_pair_loc * input.stride;
1729 for (
int col_idx = 0; col_idx < input.cols; col_idx++) {
1730 int index_pair = row_offset_pair + col_idx;
1732 double real = input[index_pair].real;
1733 double imag = input[index_pair].imag;
1734 input[index_pair].real = inv_sqrt2 * (real - imag);
1735 input[index_pair].imag = inv_sqrt2 * (real + imag);
1742 template<
typename MatrixT>
1745 const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
1747 #pragma omp parallel for schedule(static) 1748 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
1749 long long row_offset = (
long long)row_idx * input.stride;
1750 int current_idx = 0;
1751 for (
int current_idx_pair = current_idx + index_step_target;
1753 current_idx_pair = current_idx_pair + (index_step_target << 1)) {
1754 for (
int idx = 0; idx < index_step_target; ++idx) {
1755 int current_idx_loc = current_idx + idx;
1756 int current_idx_pair_loc = current_idx_pair + idx;
1757 if ((control_qbit < 0) || ((current_idx_loc >>
control_qbit) & 1)) {
1758 int index_pair = row_offset + current_idx_pair_loc;
1759 double real = input[index_pair].real;
1760 double imag = input[index_pair].imag;
1761 input[index_pair].real = inv_sqrt2 * (real - imag);
1762 input[index_pair].imag = inv_sqrt2 * (real + imag);
1765 current_idx = current_idx + (index_step_target << 1);
1770 template<
typename MatrixT>
1773 if (target_qbits.size() != 2) {
1774 throw std::runtime_error(
"SWAP gate kernel requires exactly 2 target qubits, got " +
1775 std::to_string(target_qbits.size()));
1778 int target_qbit1 = target_qbits[0];
1779 int target_qbit2 = target_qbits[1];
1781 std::vector<int> non_involved_qbits;
1783 for (
int idx=0; idx<
qbit_num; idx++){
1784 bool is_target = (idx == target_qbit1 || idx == target_qbit2);
1785 bool is_control = std::find(control_qbits.begin(), control_qbits.end(), idx) != control_qbits.end();
1786 if (!is_target && !is_control){
1787 non_involved_qbits.push_back(idx);
1792 int control_mask = 0;
1797 int total_blocks = matrix_size >> (qbit_num - non_involved_qbits.size());
1799 #pragma omp parallel for schedule(static) 1800 for (
int block_idx = 0; block_idx < total_blocks; block_idx++) {
1802 for (
size_t qdx=0; qdx<non_involved_qbits.size();qdx++){
1803 if ((block_idx >> qdx) & 1) {
1804 base |= (1<<non_involved_qbits[qdx]);
1807 base |= control_mask;
1808 int swap_idx = base|(1<<target_qbit1);
1809 int swap_idx_pair = base|(1<<target_qbit2);
1812 input.get_data() + swap_idx*input.stride,
1813 input.get_data() + swap_idx*input.stride + input.cols,
1814 input.get_data() + swap_idx_pair*input.stride
1819 template<
typename MatrixT>
1821 if (target_qbits.size() != 2) {
1822 throw std::runtime_error(
"SWAP gate kernel requires exactly 2 target qubits, got " +
1823 std::to_string(target_qbits.size()));
1826 int target_qbit1 = target_qbits[0];
1827 int target_qbit2 = target_qbits[1];
1829 std::vector<int> non_involved_qbits;
1831 for (
int idx = 0; idx <
qbit_num; idx++) {
1832 bool is_target = (idx == target_qbit1 || idx == target_qbit2);
1833 bool is_control = std::find(control_qbits.begin(), control_qbits.end(), idx) != control_qbits.end();
1834 if (!is_target && !is_control) {
1835 non_involved_qbits.push_back(idx);
1839 int control_mask = 0;
1844 int total_blocks = matrix_size >> (qbit_num - non_involved_qbits.size());
1846 #pragma omp parallel for schedule(static) 1847 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
1848 long long row_offset = (
long long)row_idx * input.stride;
1849 for (
int block_idx = 0; block_idx < total_blocks; ++block_idx) {
1851 for (
size_t qdx = 0; qdx < non_involved_qbits.size(); qdx++) {
1852 if ((block_idx >> qdx) & 1) {
1853 base |= (1 << non_involved_qbits[qdx]);
1856 base |= control_mask;
1857 int swap_idx = base | (1 << target_qbit1);
1858 int swap_idx_pair = base | (1 << target_qbit2);
1860 std::swap(input[row_offset + swap_idx], input[row_offset + swap_idx_pair]);
1866 template<
typename MatrixT>
1874 int loop_size = index_step_target < index_step_control ? index_step_target : index_step_control;
1875 int iterations = control_qbit < target_qbit ?
Power_of_2(target_qbit - control_qbit - 1) :
Power_of_2(control_qbit - target_qbit - 1);
1878 int idx01 = index_step_target;
1879 int idx10 = index_step_control;
1880 int idx11 = index_step_target + index_step_control;
1882 const double phase_real = std::sqrt(3.0) / 2.0;
1883 const double phase_imag = -0.5;
1885 while (idx11 < matrix_size) {
1886 for (
int jdx = 0; jdx < iterations; ++jdx) {
1887 #pragma omp parallel for schedule(static) 1888 for (
int idx = 0; idx < loop_size; ++idx) {
1889 int idx01_loc = idx01 + idx;
1890 int idx10_loc = idx10 + idx;
1891 int idx11_loc = idx11 + idx;
1893 int offset01 = idx01_loc * input.stride;
1894 int offset10 = idx10_loc * input.stride;
1895 int offset11 = idx11_loc * input.stride;
1897 for (
int col_idx = 0; col_idx < input.cols; ++col_idx) {
1901 input[offset01 + col_idx].real = element10.imag;
1902 input[offset01 + col_idx].imag = -element10.real;
1904 input[offset10 + col_idx].real = element01.imag;
1905 input[offset10 + col_idx].imag = -element01.real;
1908 input[offset11 + col_idx].real = phase_real * element11.real - phase_imag * element11.imag;
1909 input[offset11 + col_idx].imag = phase_real * element11.imag + phase_imag * element11.real;
1913 idx00 += 2 * loop_size;
1914 idx01 += 2 * loop_size;
1915 idx10 += 2 * loop_size;
1916 idx11 += 2 * loop_size;
1919 idx00 += 2 * loop_size * iterations;
1920 idx01 += 2 * loop_size * iterations;
1921 idx10 += 2 * loop_size * iterations;
1922 idx11 += 2 * loop_size * iterations;
1926 template<
typename MatrixT>
1934 int loop_size = index_step_target < index_step_control ? index_step_target : index_step_control;
1935 int iterations = control_qbit < target_qbit ?
Power_of_2(target_qbit - control_qbit - 1) :
Power_of_2(control_qbit - target_qbit - 1);
1937 const double phase_real = std::sqrt(3.0) / 2.0;
1938 const double phase_imag = -0.5;
1940 #pragma omp parallel for schedule(static) 1941 for (
int row_idx = 0; row_idx < input.rows; ++row_idx) {
1942 int offset = row_idx * input.stride;
1944 int idx01 = index_step_target;
1945 int idx10 = index_step_control;
1946 int idx11 = index_step_target + index_step_control;
1948 while (idx11 < matrix_size) {
1949 for (
int jdx = 0; jdx < iterations; ++jdx) {
1950 for (
int idx = 0; idx < loop_size; ++idx) {
1951 int idx01_loc = idx01 + idx;
1952 int idx10_loc = idx10 + idx;
1953 int idx11_loc = idx11 + idx;
1958 input[offset + idx01_loc].real = element10.imag;
1959 input[offset + idx01_loc].imag = -element10.real;
1961 input[offset + idx10_loc].real = element01.imag;
1962 input[offset + idx10_loc].imag = -element01.real;
1965 input[offset + idx11_loc].real = phase_real * element11.real - phase_imag * element11.imag;
1966 input[offset + idx11_loc].imag = phase_real * element11.imag + phase_imag * element11.real;
1969 idx00 += 2 * loop_size;
1970 idx01 += 2 * loop_size;
1971 idx10 += 2 * loop_size;
1972 idx11 += 2 * loop_size;
1975 idx00 += 2 * loop_size * iterations;
1976 idx01 += 2 * loop_size * iterations;
1977 idx10 += 2 * loop_size * iterations;
1978 idx11 += 2 * loop_size * iterations;
int Power_of_2(int n)
Calculates the n-th power of 2.
Double-precision complex matrix (float64).
Single-precision complex matrix (float32).