|
| 1 | +# Implementation |
| 2 | + |
| 3 | +## Expval kernels |
| 4 | + |
| 5 | +The general multi-qubit operator kernel requires a private variable `coeffs_in` to store state vector coefficients. |
| 6 | +In the Kokkos framework, this variable cannot be a private member of the functor, say, because all threads will overwrite it. |
| 7 | +One must then use `TeamPolicy`s together with `scratch_memory_space` which allows creating and manipulating thread-local variables. |
| 8 | +This implementation however appears suboptimal compared with the straightforward `RangePolicy` with bit-injection one. |
| 9 | + |
| 10 | +The last being more verbose, it is only implemented for 1- and 2-qubit observables. |
| 11 | +It is however possible to generate the code automatically for higher qubit counts with the following Python script. |
| 12 | + |
| 13 | +```python |
| 14 | +for n_wires in range(1, 6): |
| 15 | + name = f"getExpVal{n_wires}QubitOpFunctor" |
| 16 | + nU = 2**n_wires |
| 17 | + |
| 18 | + print( |
| 19 | + f"""template <class PrecisionT, std::size_t n_wires> struct {name} {{ |
| 20 | + |
| 21 | + using ComplexT = Kokkos::complex<PrecisionT>; |
| 22 | + using KokkosComplexVector = Kokkos::View<ComplexT *>; |
| 23 | + using KokkosIntVector = Kokkos::View<std::size_t *>; |
| 24 | +
|
| 25 | + KokkosComplexVector arr; |
| 26 | + KokkosComplexVector matrix; |
| 27 | + KokkosIntVector wires; |
| 28 | + std::size_t dim; |
| 29 | + std::size_t num_qubits; |
| 30 | +
|
| 31 | + {name}(const KokkosComplexVector &arr_, |
| 32 | + const std::size_t num_qubits_, |
| 33 | + const KokkosComplexVector &matrix_, |
| 34 | + const KokkosIntVector &wires_) {{ |
| 35 | + wires = wires_; |
| 36 | + arr = arr_; |
| 37 | + matrix = matrix_; |
| 38 | + num_qubits = num_qubits_; |
| 39 | + dim = 1U << wires.size(); |
| 40 | + }} |
| 41 | + |
| 42 | + KOKKOS_INLINE_FUNCTION |
| 43 | + void operator()(const std::size_t k, PrecisionT &expval) const {{ |
| 44 | + const std::size_t kdim = k * dim; |
| 45 | + """ |
| 46 | + ) |
| 47 | + |
| 48 | + for k in range(nU): |
| 49 | + print( |
| 50 | + f""" |
| 51 | + std::size_t i{k:0{n_wires}b} = kdim | {k}; |
| 52 | + for (std::size_t pos = 0; pos < n_wires; pos++) {{ |
| 53 | + std::size_t x = |
| 54 | + ((i{k:0{n_wires}b} >> (n_wires - pos - 1)) ^ |
| 55 | + (i{k:0{n_wires}b} >> (num_qubits - wires(pos) - 1))) & |
| 56 | + 1U; |
| 57 | + i{k:0{n_wires}b} = i{k:0{n_wires}b} ^ ((x << (n_wires - pos - 1)) | |
| 58 | + (x << (num_qubits - wires(pos) - 1))); |
| 59 | + }} |
| 60 | + """ |
| 61 | + ) |
| 62 | + |
| 63 | + # print("expval += real(") |
| 64 | + for k in range(nU): |
| 65 | + tmp = f"expval += real(conj(arr(i{k:0{n_wires}b})) * (" |
| 66 | + tmp += f"matrix(0B{k:0{n_wires}b}{0:0{n_wires}b}) * arr(i{0:0{n_wires}b})" |
| 67 | + for j in range(1, nU): |
| 68 | + tmp += ( |
| 69 | + f" + matrix(0B{k:0{n_wires}b}{j:0{n_wires}b}) * arr(i{j:0{n_wires}b})" |
| 70 | + ) |
| 71 | + print(tmp, end="") |
| 72 | + print("));") |
| 73 | + print("}") |
| 74 | + print("};") |
| 75 | +``` |
0 commit comments