Program Listing for File QuantumDevice.hpp

Return to documentation for file (runtime/include/QuantumDevice.hpp)

// Copyright 2022-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 <complex>
#include <memory>
#include <optional>
#include <random>
#include <vector>

#include "DataView.hpp"
#include "Types.h"

// A helper template macro to generate the <IDENTIFIER>Factory method by
// calling <CONSTRUCTOR>(kwargs). Check the Custom Devices guideline for details:
// https://docs.pennylane.ai/projects/catalyst/en/stable/dev/custom_devices.html
#define GENERATE_DEVICE_FACTORY(IDENTIFIER, CONSTRUCTOR)                                           \
    extern "C" Catalyst::Runtime::QuantumDevice *IDENTIFIER##Factory(const char *kwargs)           \
    {                                                                                              \
        return new CONSTRUCTOR(std::string(kwargs));                                               \
    }

namespace Catalyst::Runtime {

struct QuantumDevice {
    QuantumDevice() = default;          // LCOV_EXCL_LINE
    virtual ~QuantumDevice() = default; // LCOV_EXCL_LINE

    QuantumDevice &operator=(const QuantumDevice &) = delete;
    QuantumDevice(const QuantumDevice &) = delete;
    QuantumDevice(QuantumDevice &&) = delete;
    QuantumDevice &operator=(QuantumDevice &&) = delete;

    virtual auto AllocateQubit() -> QubitIdType = 0;

    virtual auto AllocateQubits(size_t num_qubits) -> std::vector<QubitIdType> = 0;

    virtual void ReleaseQubit(QubitIdType qubit) = 0;

    virtual void ReleaseAllQubits() = 0;

    [[nodiscard]] virtual auto GetNumQubits() const -> size_t = 0;

    virtual void SetDeviceShots(size_t shots) = 0;

    [[nodiscard]] virtual auto GetDeviceShots() const -> size_t = 0;

    virtual void SetDevicePRNG([[maybe_unused]] std::mt19937 *gen){};

    virtual void StartTapeRecording() = 0;

    virtual void StopTapeRecording() = 0;

    [[nodiscard]] virtual auto Zero() const -> Result = 0;

    [[nodiscard]] virtual auto One() const -> Result = 0;

    virtual void PrintState() = 0;

    virtual void SetState([[maybe_unused]] DataView<std::complex<double>, 1> &state,
                          [[maybe_unused]] std::vector<QubitIdType> &wires)
    {
        RT_FAIL("Unsupported functionality");
    }

    virtual void SetBasisState([[maybe_unused]] DataView<int8_t, 1> &n,
                               [[maybe_unused]] std::vector<QubitIdType> &wires)
    {
        RT_FAIL("Unsupported functionality");
    }

    virtual void
    NamedOperation(const std::string &name, const std::vector<double> &params,
                   const std::vector<QubitIdType> &wires, [[maybe_unused]] bool inverse = false,
                   [[maybe_unused]] const std::vector<QubitIdType> &controlled_wires = {},
                   [[maybe_unused]] const std::vector<bool> &controlled_values = {}) = 0;

    virtual void
    MatrixOperation(const std::vector<std::complex<double>> &matrix,
                    const std::vector<QubitIdType> &wires, [[maybe_unused]] bool inverse = false,
                    [[maybe_unused]] const std::vector<QubitIdType> &controlled_wires = {},
                    [[maybe_unused]] const std::vector<bool> &controlled_values = {}) = 0;

    virtual auto Observable(ObsId id, const std::vector<std::complex<double>> &matrix,
                            const std::vector<QubitIdType> &wires) -> ObsIdType = 0;

    virtual auto TensorObservable(const std::vector<ObsIdType> &obs) -> ObsIdType = 0;

    virtual auto HamiltonianObservable(const std::vector<double> &coeffs,
                                       const std::vector<ObsIdType> &obs) -> ObsIdType = 0;

    virtual auto Expval(ObsIdType obsKey) -> double = 0;

    virtual auto Var(ObsIdType obsKey) -> double = 0;

    virtual void State(DataView<std::complex<double>, 1> &state) = 0;

    virtual void Probs(DataView<double, 1> &probs) = 0;

    virtual void PartialProbs(DataView<double, 1> &probs,
                              const std::vector<QubitIdType> &wires) = 0;

    virtual void Sample(DataView<double, 2> &samples, size_t shots) = 0;

    virtual void PartialSample(DataView<double, 2> &samples, const std::vector<QubitIdType> &wires,
                               size_t shots) = 0;

    virtual void Counts(DataView<double, 1> &eigvals, DataView<int64_t, 1> &counts,
                        size_t shots) = 0;

    virtual void PartialCounts(DataView<double, 1> &eigvals, DataView<int64_t, 1> &counts,
                               const std::vector<QubitIdType> &wires, size_t shots) = 0;

    virtual auto Measure(QubitIdType wire, std::optional<int32_t> postselect) -> Result = 0;

    virtual void Gradient(std::vector<DataView<double, 1>> &gradients,
                          const std::vector<size_t> &trainParams) = 0;
};
} // namespace Catalyst::Runtime