Program Listing for File MeasuresFunctors.hpp

Return to documentation for file (pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasuresFunctors.hpp)

// Copyright 2018-2023 Xanadu Quantum Technologies Inc.

// Licensed under the Apache License, Version 2.0 (the License);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an AS IS BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once

#include <Kokkos_Core.hpp>
#include <Kokkos_StdAlgorithms.hpp>

namespace Pennylane::LightningKokkos::Functors {
template <class PrecisionT> struct getProbFunctor {
    Kokkos::View<Kokkos::complex<PrecisionT> *> arr;
    Kokkos::View<PrecisionT *> probability;

    getProbFunctor(Kokkos::View<Kokkos::complex<PrecisionT> *> arr_,
                   Kokkos::View<PrecisionT *> probability_)
        : arr(arr_), probability(probability_) {}

    KOKKOS_INLINE_FUNCTION
    void operator()(const size_t k) const {
        const PrecisionT REAL = arr(k).real();
        const PrecisionT IMAG = arr(k).imag();
        probability(k) = REAL * REAL + IMAG * IMAG;
    }
};

template <class PrecisionT, template <class ExecutionSpace> class GeneratorPool,
          class ExecutionSpace = Kokkos::DefaultExecutionSpace>
struct Sampler {
    Kokkos::View<size_t *> samples;
    Kokkos::View<PrecisionT *> cdf;
    GeneratorPool<ExecutionSpace> rand_pool;

    const size_t num_qubits;
    const size_t length;

    Sampler(Kokkos::View<size_t *> samples_, Kokkos::View<PrecisionT *> cdf_,
            GeneratorPool<ExecutionSpace> rand_pool_, const size_t num_qubits_,
            const size_t length_)
        : samples(samples_), cdf(cdf_), rand_pool(rand_pool_),
          num_qubits(num_qubits_), length(length_) {}

    KOKKOS_INLINE_FUNCTION
    void operator()(const size_t k) const {
        // Get a random number state from the pool for the active thread
        auto rand_gen = rand_pool.get_state();
        PrecisionT U_rand = rand_gen.drand(0.0, 1.0);
        // Give the state back, which will allow another thread to acquire it
        rand_pool.free_state(rand_gen);
        size_t index;

        // Binary search for the bin index of cumulative probability
        // distribution that generated random number U falls into.
        if (U_rand <= cdf(1)) {
            index = 0;
        } else {
            size_t low_idx = 1, high_idx = length;
            size_t mid_idx;
            PrecisionT cdf_t;
            while (high_idx - low_idx > 1) {
                mid_idx = high_idx - ((high_idx - low_idx) >> 1U);
                if (mid_idx == length)
                    cdf_t = 1;
                else
                    cdf_t = cdf(mid_idx);
                if (cdf_t < U_rand)
                    low_idx = mid_idx;
                else
                    high_idx = mid_idx;
            }
            index = high_idx - 1;
        }
        for (size_t j = 0; j < num_qubits; j++) {
            samples(k * num_qubits + (num_qubits - 1 - j)) = (index >> j) & 1U;
        }
    }
};

struct getTransposedIndexFunctor {
    Kokkos::View<size_t *> sorted_ind_wires;
    Kokkos::View<size_t *> trans_index;
    const size_t max_index_sorted_ind_wires;
    getTransposedIndexFunctor(Kokkos::View<size_t *> sorted_ind_wires_,
                              Kokkos::View<size_t *> trans_index_,
                              const int length_sorted_ind_wires_)
        : sorted_ind_wires(sorted_ind_wires_), trans_index(trans_index_),
          max_index_sorted_ind_wires(length_sorted_ind_wires_ - 1) {}

    KOKKOS_INLINE_FUNCTION
    void operator()(const size_t i, const size_t j) const {
        const size_t axis = sorted_ind_wires(j);
        const size_t index = i / (1L << (max_index_sorted_ind_wires - j));
        const size_t sub_index = (index % 2)
                                 << (max_index_sorted_ind_wires - axis);
        Kokkos::atomic_add(&trans_index(i), sub_index);
    }
};

template <class PrecisionT> struct getTransposedFunctor {
    Kokkos::View<PrecisionT *> transProb;
    Kokkos::View<PrecisionT *> probability;
    Kokkos::View<size_t *> trans_index;
    getTransposedFunctor(Kokkos::View<PrecisionT *> transProb_,
                         Kokkos::View<PrecisionT *> probability_,
                         Kokkos::View<size_t *> trans_index_)
        : transProb(transProb_), probability(probability_),
          trans_index(trans_index_) {}

    KOKKOS_INLINE_FUNCTION
    void operator()(const size_t i) const {
        const size_t new_index = trans_index(i);
        transProb(i) = probability(new_index);
    }
};

} // namespace Pennylane::LightningKokkos::Functors