Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Downstream LightningSimulator C++ API to the pennylane-lightning repository #960

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pennylane_lightning/core/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.39.0-dev49"
__version__ = "0.39.0-dev50"
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ set_property(TARGET lightning_qubit PROPERTY POSITION_INDEPENDENT_CODE ON)
###############################################################################
set(COMPONENT_SUBDIRS algorithms
bindings
catalyst
gates
measurements
observables
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
cmake_minimum_required(VERSION 3.20)

project(lightning_qubit_catalyst LANGUAGES CXX)

set(LQ_CATALYST_FILES LightningSimulator.cpp CACHE INTERNAL "")
add_library(lightning_qubit_catalyst SHARED ${LQ_CATALYST_FILES})

include(FetchContent)

if(LIGHTNING_CATALYST_SRC_PATH)
if(NOT IS_ABSOLUTE ${LIGHTNING_CATALYST_SRC_PATH})
message(FATAL_ERROR " LIGHTNING_CATALYST_SRC_PATH=${LIGHTNING_CATALYST_SRC_PATH} must be set to an absolute path")
endif()
if(CATALYST_GIT_TAG)
message(WARN " Setting `LIGHTNING_CATALYST_SRC_PATH=${LIGHTNING_CATALYST_SRC_PATH}` overrides `CATALYST_GIT_TAG=${CATALYST_GIT_TAG}`")
endif()

# Acquire local git hash and use for CATALYST_GIT_TAG
execute_process(COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${LIGHTNING_CATALYST_SRC_PATH}
OUTPUT_VARIABLE CATALYST_GIT_TAG
)
message(INFO " Building against local Catalyst - path: ${LIGHTNING_CATALYST_SRC_PATH} - GIT TAG: ${CATALYST_GIT_TAG}")

target_include_directories(lightning_qubit_catalyst PUBLIC ${LIGHTNING_CATALYST_SRC_PATH}/runtime/lib/backend/common)
target_include_directories(lightning_qubit_catalyst PUBLIC ${LIGHTNING_CATALYST_SRC_PATH}/runtime/include)

else()
if(NOT CATALYST_GIT_TAG)
set(CATALYST_GIT_TAG "main" CACHE STRING "GIT_TAG value to build Catalyst")
endif()
message(INFO " Building against Catalyst GIT TAG ${CATALYST_GIT_TAG}")

# Fetching /lib/backend/common hpp headers
set(LIB_BACKEND_COMMON_HEADERS CacheManager.hpp
QubitManager.hpp
Utils.hpp
)

foreach(HEADER ${LIB_BACKEND_COMMON_HEADERS})
string(REGEX REPLACE "\\.[^.]*$" "" HEADER_NAME ${HEADER})
FetchContent_Declare(
${HEADER_NAME}
URL https://raw.githubusercontent.com/PennyLaneAI/catalyst/${CATALYST_GIT_TAG}/runtime/lib/backend/common/${HEADER}
DOWNLOAD_NO_EXTRACT True
SOURCE_DIR include
)

FetchContent_MakeAvailable(${HEADER_NAME})
endforeach()

# Fetching include hpp headers
set(INCLUDE_HEADERS DataView.hpp
Exception.hpp
QuantumDevice.hpp
RuntimeCAPI.h
Types.h
)

foreach(HEADER ${INCLUDE_HEADERS})
string(REGEX REPLACE "\\.[^.]*$" "" HEADER_NAME ${HEADER})
FetchContent_Declare(
${HEADER_NAME}
URL https://raw.githubusercontent.com/PennyLaneAI/catalyst/${CATALYST_GIT_TAG}/runtime/include/${HEADER}
DOWNLOAD_NO_EXTRACT True
SOURCE_DIR include
)

FetchContent_MakeAvailable(${HEADER_NAME})
endforeach()

target_include_directories(lightning_qubit_catalyst PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include)

endif()

target_include_directories(lightning_qubit_catalyst INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(lightning_qubit_catalyst PUBLIC lightning_compile_options
lightning_external_libs
lightning_base
lightning_gates
lightning_utils
lightning_qubit
lightning_qubit_algorithms
lightning_qubit_gates
lightning_qubit_measurements
lightning_qubit_observables
lightning_qubit_utils
)

if (BUILD_TESTS)
enable_testing()
add_subdirectory("tests")
endif()
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
// 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 <array>
#include <stdexcept>
#include <tuple>
#include <utility>

#include "Exception.hpp"
#include "Types.h"
#include "Utils.hpp"

#include "ObservablesLQubit.hpp"
#include "StateVectorLQubitDynamic.hpp"

namespace {
using Pennylane::LightningQubit::StateVectorLQubitDynamic;
using Pennylane::LightningQubit::Observables::HermitianObs;
using Pennylane::LightningQubit::Observables::NamedObs;
using Pennylane::LightningQubit::Observables::TensorProdObs;
using Pennylane::Observables::Observable;
} // namespace

namespace Catalyst::Runtime::Simulator {

/**
* @brief The LightningObsManager caches observables of a program at runtime
* and maps each one to a const unique index (`int64_t`) in the scope
* of the global context manager.
*/
template <typename PrecisionT> class LightningObsManager {
private:
using VectorStateT = StateVectorLQubitDynamic<PrecisionT>;
using ObservablePairType = std::pair<std::shared_ptr<Observable<VectorStateT>>, ObsType>;
std::vector<ObservablePairType> observables_{};

public:
LightningObsManager() = default;
~LightningObsManager() = default;

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

/**
* @brief A helper function to clear constructed observables in the program.
*/
void clear() { observables_.clear(); }

/**
* @brief Check the validity of observable keys.
*
* @param obsKeys The vector of observable keys
* @return bool
*/
[[nodiscard]] auto isValidObservables(const std::vector<ObsIdType> &obsKeys) const -> bool
{
return std::all_of(obsKeys.begin(), obsKeys.end(), [this](auto i) {
return (i >= 0 && static_cast<size_t>(i) < observables_.size());
});
}

/**
* @brief Get the constructed observable instance.
*
* @param key The observable key
* @return std::shared_ptr<Observable<VectorStateT>>
*/
[[nodiscard]] auto getObservable(ObsIdType key) -> std::shared_ptr<Observable<VectorStateT>>
{
RT_FAIL_IF(!isValidObservables({key}), "Invalid observable key");
return std::get<0>(observables_[key]);
}

/**
* @brief Get the number of observables.
*
* @return size_t
*/
[[nodiscard]] auto numObservables() const -> size_t { return observables_.size(); }

/**
* @brief Create and cache a new NamedObs instance.
*
* @param obsId The named observable id of type ObsId
* @param wires The vector of wires the observable acts on
* @return ObsIdType
*/
[[nodiscard]] auto createNamedObs(ObsId obsId, const std::vector<size_t> &wires) -> ObsIdType
{
auto &&obs_str =
std::string(Lightning::lookup_obs<Lightning::simulator_observable_support_size>(
Lightning::simulator_observable_support, obsId));

observables_.push_back(std::make_pair(
std::make_shared<NamedObs<VectorStateT>>(obs_str, wires), ObsType::Basic));
return static_cast<ObsIdType>(observables_.size() - 1);
}

/**
* @brief Create and cache a new HermitianObs instance.
*
* @param matrix The row-wise Hermitian matrix
* @param wires The vector of wires the observable acts on
* @return ObsIdType
*/
[[nodiscard]] auto createHermitianObs(const std::vector<std::complex<PrecisionT>> &matrix,
const std::vector<size_t> &wires) -> ObsIdType
{
observables_.push_back(std::make_pair(
std::make_shared<HermitianObs<VectorStateT>>(HermitianObs<VectorStateT>{matrix, wires}),
ObsType::Basic));

return static_cast<ObsIdType>(observables_.size() - 1);
}

/**
* @brief Create and cache a new TensorProd instance.
*
* @param obsKeys The vector of observable keys
* @return ObsIdType
*/
[[nodiscard]] auto createTensorProdObs(const std::vector<ObsIdType> &obsKeys) -> ObsIdType
{
const auto key_size = obsKeys.size();
const auto obs_size = observables_.size();

std::vector<std::shared_ptr<Observable<VectorStateT>>> obs_vec;
obs_vec.reserve(key_size);

for (const auto &key : obsKeys) {
RT_FAIL_IF(static_cast<size_t>(key) >= obs_size || key < 0, "Invalid observable key");

auto &&[obs, type] = observables_[key];
obs_vec.push_back(obs);
}

observables_.push_back(
std::make_pair(TensorProdObs<VectorStateT>::create(obs_vec), ObsType::TensorProd));

return static_cast<ObsIdType>(obs_size);
}

/**
* @brief Create and cache a new HamiltonianObs instance.
*
* @param coeffs The vector of coefficients
* @param obsKeys The vector of observable keys
* @return ObsIdType
*/
[[nodiscard]] auto createHamiltonianObs(const std::vector<PrecisionT> &coeffs,
const std::vector<ObsIdType> &obsKeys) -> ObsIdType
{
const auto key_size = obsKeys.size();
const auto obs_size = observables_.size();

RT_FAIL_IF(key_size != coeffs.size(),
"Incompatible list of observables and coefficients; "
"Number of observables and number of coefficients must be equal");

std::vector<std::shared_ptr<Observable<VectorStateT>>> obs_vec;
obs_vec.reserve(key_size);

for (auto key : obsKeys) {
RT_FAIL_IF(static_cast<size_t>(key) >= obs_size || key < 0, "Invalid observable key");

auto &&[obs, type] = observables_[key];
obs_vec.push_back(obs);
}

observables_.push_back(std::make_pair(
std::make_shared<Pennylane::LightningQubit::Observables::Hamiltonian<VectorStateT>>(
Pennylane::LightningQubit::Observables::Hamiltonian<VectorStateT>(
coeffs, std::move(obs_vec))),
ObsType::Hamiltonian));

return static_cast<ObsIdType>(obs_size);
}
};
} // namespace Catalyst::Runtime::Simulator
Loading
Loading