Program Listing for File StateVectorLQubitManaged.hpp

Return to documentation for file (pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.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 <algorithm> // fill
#include <complex>
#include <vector>

#include "BitUtil.hpp"        // log2PerfectPower, isPerfectPowerOf2
#include "CPUMemoryModel.hpp" // bestCPUMemoryModel
#include "Error.hpp"
#include "KernelType.hpp"
#include "Memory.hpp"
#include "StateVectorLQubit.hpp"
#include "Threading.hpp"
#include "Util.hpp" // exp2

namespace {
using Pennylane::Util::AlignedAllocator;
using Pennylane::Util::bestCPUMemoryModel;
using Pennylane::Util::exp2;
using Pennylane::Util::isPerfectPowerOf2;
using Pennylane::Util::log2PerfectPower;
} // namespace

namespace Pennylane::LightningQubit {
template <class fp_t = double>
class StateVectorLQubitManaged final
    : public StateVectorLQubit<fp_t, StateVectorLQubitManaged<fp_t>> {
  public:
    using PrecisionT = fp_t;
    using ComplexT = std::complex<PrecisionT>;
    using CFP_t = ComplexT;
    using MemoryStorageT = Pennylane::Util::MemoryStorageLocation::Internal;

  private:
    using BaseType =
        StateVectorLQubit<PrecisionT, StateVectorLQubitManaged<PrecisionT>>;
    std::vector<ComplexT, AlignedAllocator<ComplexT>> data_;

  public:
    explicit StateVectorLQubitManaged(
        std::size_t num_qubits, Threading threading = Threading::SingleThread,
        CPUMemoryModel memory_model = bestCPUMemoryModel())
        : BaseType{num_qubits, threading, memory_model},
          data_{exp2(num_qubits), ComplexT{0.0, 0.0},
                getAllocator<ComplexT>(this->memory_model_)} {
        setBasisState(0U);
    }

    template <class OtherDerived>
    explicit StateVectorLQubitManaged(
        const StateVectorLQubit<PrecisionT, OtherDerived> &other)
        : BaseType(other.getNumQubits(), other.threading(),
                   other.memoryModel()),
          data_{other.getData(), other.getData() + other.getLength(),
                getAllocator<ComplexT>(this->memory_model_)} {}

    StateVectorLQubitManaged(const ComplexT *other_data, std::size_t other_size,
                             Threading threading = Threading::SingleThread,
                             CPUMemoryModel memory_model = bestCPUMemoryModel())
        : BaseType(log2PerfectPower(other_size), threading, memory_model),
          data_{other_data, other_data + other_size,
                getAllocator<ComplexT>(this->memory_model_)} {
        PL_ABORT_IF_NOT(isPerfectPowerOf2(other_size),
                        "The size of provided data must be a power of 2.");
    }

    template <class Alloc>
    explicit StateVectorLQubitManaged(
        const std::vector<std::complex<PrecisionT>, Alloc> &other,
        Threading threading = Threading::SingleThread,
        CPUMemoryModel memory_model = bestCPUMemoryModel())
        : StateVectorLQubitManaged(other.data(), other.size(), threading,
                                   memory_model) {}

    StateVectorLQubitManaged(const StateVectorLQubitManaged &rhs) = default;
    StateVectorLQubitManaged(StateVectorLQubitManaged &&) noexcept = default;

    StateVectorLQubitManaged &
    operator=(const StateVectorLQubitManaged &) = default;
    StateVectorLQubitManaged &
    operator=(StateVectorLQubitManaged &&) noexcept = default;

    ~StateVectorLQubitManaged() = default;

    void setBasisState(const std::size_t index) {
        std::fill(data_.begin(), data_.end(), 0);
        data_[index] = {1, 0};
    }

    void setStateVector(const std::vector<std::size_t> &indices,
                        const std::vector<ComplexT> &values) {
        for (std::size_t n = 0; n < indices.size(); n++) {
            data_[indices[n]] = values[n];
        }
    }

    void resetStateVector() {
        if (this->getLength() > 0) {
            setBasisState(0U);
        }
    }

    [[nodiscard]] auto getData() -> ComplexT * { return data_.data(); }

    [[nodiscard]] auto getData() const -> const ComplexT * {
        return data_.data();
    }

    [[nodiscard]] auto getDataVector()
        -> std::vector<ComplexT, AlignedAllocator<ComplexT>> & {
        return data_;
    }

    [[nodiscard]] auto getDataVector() const
        -> const std::vector<ComplexT, AlignedAllocator<ComplexT>> & {
        return data_;
    }

    void updateData(const ComplexT *new_data, std::size_t new_size) {
        PL_ASSERT(data_.size() == new_size);
        std::copy(new_data, new_data + new_size, data_.data());
    }

    template <class Alloc>
    void updateData(const std::vector<ComplexT, Alloc> &new_data) {
        updateData(new_data.data(), new_data.size());
    }

    AlignedAllocator<ComplexT> allocator() const {
        return data_.get_allocator();
    }
};
} // namespace Pennylane::LightningQubit