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

Add the state_vector, measurement class and simulate method for the LightningGPU with the new device API #892

Merged
merged 38 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
120bbed
include the new device base class
LuisAlfredoNu Sep 4, 2024
bdf4daa
add measurements
LuisAlfredoNu Sep 9, 2024
b05a6a4
State vector almos done
LuisAlfredoNu Sep 9, 2024
5dac907
tmp commit
LuisAlfredoNu Sep 9, 2024
bfd0771
Solve prop issue
LuisAlfredoNu Sep 9, 2024
a1ff6c6
ready measurenment class for LGPU
LuisAlfredoNu Sep 10, 2024
a0cfb1d
print helps for measurements
LuisAlfredoNu Sep 10, 2024
f472471
Merge gpuNewAPI_simulate
LuisAlfredoNu Sep 11, 2024
c7ac82d
grammar correction
LuisAlfredoNu Sep 11, 2024
6627913
cleaning code
LuisAlfredoNu Sep 11, 2024
6290953
apply format
LuisAlfredoNu Sep 11, 2024
219262b
delete usuless variables
LuisAlfredoNu Sep 11, 2024
bca1a74
delete prints
LuisAlfredoNu Sep 11, 2024
0f8f957
Revert change in measurenment test
LuisAlfredoNu Sep 11, 2024
a9ccf62
Merge branch 'gpuNewAPI_backend' into gpuNewAPI_simulate
LuisAlfredoNu Sep 11, 2024
a99b6e8
Merge branch 'gpuNewAPI_backend' into gpuNewAPI_simulate
LuisAlfredoNu Sep 11, 2024
0399f18
add simulate method
LuisAlfredoNu Sep 11, 2024
23d5696
apply format
LuisAlfredoNu Sep 11, 2024
585c313
Shuli suggestion
LuisAlfredoNu Sep 11, 2024
5eee8eb
apply format
LuisAlfredoNu Sep 11, 2024
92089eb
Update pennylane_lightning/lightning_gpu/_mpi_handler.py
LuisAlfredoNu Sep 12, 2024
196042a
Apply suggestions from code review Vinvent's comments
LuisAlfredoNu Sep 12, 2024
b4ed1ae
Vincent's comments
LuisAlfredoNu Sep 12, 2024
695283b
Merge branch 'gpuNewAPI_simulate' of github.com:PennyLaneAI/pennylane…
LuisAlfredoNu Sep 12, 2024
1729d06
apply format
LuisAlfredoNu Sep 12, 2024
5819efc
Apply suggestions from code review. Vincent's suggestion
LuisAlfredoNu Sep 13, 2024
2dbc7db
review comments
LuisAlfredoNu Sep 13, 2024
0630edf
apply format
LuisAlfredoNu Sep 13, 2024
3fa8409
apply format
LuisAlfredoNu Sep 13, 2024
af16b8d
Ali suggestion 1
LuisAlfredoNu Sep 13, 2024
0cb050f
add reset
LuisAlfredoNu Sep 16, 2024
54afeb5
apply_basis_state as abstract in GPU
LuisAlfredoNu Sep 16, 2024
ac87663
apply format
LuisAlfredoNu Sep 16, 2024
35270fb
Apply suggestions from code review Ali suggestion docs
LuisAlfredoNu Sep 16, 2024
f51cbb9
propagate namming suggestion
LuisAlfredoNu Sep 16, 2024
65e66e9
Apply suggestions from code review. Ali's suggestion 3
LuisAlfredoNu Sep 16, 2024
0472fdd
solve errors with kokkos
LuisAlfredoNu Sep 16, 2024
96728cb
apply format
LuisAlfredoNu Sep 16, 2024
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
10 changes: 1 addition & 9 deletions pennylane_lightning/core/_measurements_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def expval(self, measurementprocess: MeasurementProcess):
measurementprocess.obs.name, measurementprocess.obs.wires
)

@abstractmethod
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
def probs(self, measurementprocess: MeasurementProcess):
"""Probabilities of the supplied observable or wires contained in the MeasurementProcess.

Expand All @@ -139,15 +140,6 @@ def probs(self, measurementprocess: MeasurementProcess):
Returns:
Probabilities of the supplied observable or wires
"""
diagonalizing_gates = measurementprocess.diagonalizing_gates()
if diagonalizing_gates:
self._qubit_state.apply_operations(diagonalizing_gates)
results = self._measurement_lightning.probs(measurementprocess.wires.tolist())
if diagonalizing_gates:
self._qubit_state.apply_operations(
[qml.adjoint(g, lazy=False) for g in reversed(diagonalizing_gates)]
)
return results
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGPU has different behaviour in probs from LQ and LK. LGPU needs to perform an extra conversion of results due to cuQuantum returns as col-major orderings, so performing transpose on data for bit-index shuffle is needed.


def var(self, measurementprocess: MeasurementProcess):
"""Variance of the supplied observable contained in the MeasurementProcess.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ class Measurements final
PL_CUSTATEVEC_IS_SUCCESS(custatevecSamplerSample(
this->_statevector.getCusvHandle(), sampler, bitStrings.data(),
bitOrdering.data(), bitStringLen, rand_nums.data(), num_samples,
CUSTATEVEC_SAMPLER_OUTPUT_ASCENDING_ORDER));
CUSTATEVEC_SAMPLER_OUTPUT_RANDNUM_ORDER));
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(
this->_statevector.getDataBuffer().getDevTag().getStreamID()));

Expand Down
117 changes: 117 additions & 0 deletions pennylane_lightning/lightning_gpu/_measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,30 @@
Class implementation for state vector measurements.
"""

from warnings import warn

try:
from pennylane_lightning.lightning_gpu_ops import MeasurementsC64, MeasurementsC128

try:
from pennylane_lightning.lightning_gpu_ops import MeasurementsMPIC64, MeasurementsMPIC128

MPI_SUPPORT = True

Check warning on line 26 in pennylane_lightning/lightning_gpu/_measurements.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_measurements.py#L26

Added line #L26 was not covered by tests
except ImportError as ex:
warn(str(ex), UserWarning)

MPI_SUPPORT = False

except ImportError as ex:
warn(str(ex), UserWarning)

pass

from typing import List

import numpy as np
import pennylane as qml
from pennylane.measurements import CountsMP, MeasurementProcess, SampleMeasurement, Shots
from pennylane.typing import TensorLike

from pennylane_lightning.core._measurements_base import LightningBaseMeasurements
Expand All @@ -37,3 +59,98 @@
) -> TensorLike:

super().__init__(lgpu_state)

self._measurement_lightning = self._measurement_dtype()(lgpu_state.state_vector)

def _measurement_dtype(self):
"""Binding to Lightning GPU Measurements C++ class.

Returns: the Measurements class
"""
return MeasurementsC64 if self.dtype == np.complex64 else MeasurementsC128

def _measure_with_samples_diagonalizing_gates(
self,
mps: List[SampleMeasurement],
shots: Shots,
) -> TensorLike:
"""
Returns the samples of the measurement process performed on the given state,
by rotating the state into the measurement basis using the diagonalizing gates
given by the measurement process.

Args:
mps (~.measurements.SampleMeasurement): The sample measurements to perform
shots (~.measurements.Shots): The number of samples to take

Returns:
TensorLike[Any]: Sample measurement results
"""
# apply diagonalizing gates
self._apply_diagonalizing_gates(mps)

# Specific for LGPU:
total_indices = self._qubit_state.num_wires
wires = qml.wires.Wires(range(total_indices))

def _process_single_shot(samples):
processed = []
for mp in mps:
res = mp.process_samples(samples, wires)
if not isinstance(mp, CountsMP):
res = qml.math.squeeze(res)

processed.append(res)

return tuple(processed)

try:
samples = self._measurement_lightning.generate_samples(
len(wires), shots.total_shots
).astype(int, copy=False)

except ValueError as e:
if str(e) != "probabilities contain NaN":
raise e
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
samples = qml.math.full((shots.total_shots, len(wires)), 0)

Check warning on line 115 in pennylane_lightning/lightning_gpu/_measurements.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_measurements.py#L112-L115

Added lines #L112 - L115 were not covered by tests

self._apply_diagonalizing_gates(mps, adjoint=True)

# if there is a shot vector, use the shots.bins generator to
# split samples w.r.t. the shots
processed_samples = []
for lower, upper in shots.bins():
result = _process_single_shot(samples[..., lower:upper, :])
processed_samples.append(result)

return (
tuple(zip(*processed_samples)) if shots.has_partitioned_shots else processed_samples[0]
)

def probs(self, measurementprocess: MeasurementProcess):
"""Probabilities of the supplied observable or wires contained in the MeasurementProcess.

Args:
measurementprocess (StateMeasurement): measurement to apply to the state

Returns:
Probabilities of the supplied observable or wires
"""
diagonalizing_gates = measurementprocess.diagonalizing_gates()

if diagonalizing_gates:
self._qubit_state.apply_operations(diagonalizing_gates)

results = self._measurement_lightning.probs(measurementprocess.wires.tolist())

if diagonalizing_gates:
self._qubit_state.apply_operations(
[qml.adjoint(g, lazy=False) for g in reversed(diagonalizing_gates)]
)

# Device returns as col-major orderings, so perform transpose on data for bit-index shuffle for now.
if len(results) > 0:
num_local_wires = len(results).bit_length() - 1 if len(results) > 0 else 0
return results.reshape([2] * num_local_wires).transpose().reshape(-1)

return results

Check warning on line 156 in pennylane_lightning/lightning_gpu/_measurements.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_measurements.py#L156

Added line #L156 was not covered by tests
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
120 changes: 120 additions & 0 deletions pennylane_lightning/lightning_gpu/_mpi_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Copyright 2022-2024 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.
"""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new file and class will be used to keep the device implementation similar between LQ, LK, and LGPU. Also, in case of future implementation of MPI resources in other devices.

This module contains the :class:`~.LightningGPU_MPIHandler` class, a MPI handler to use LightningGPU device with multi-GPU on multi-node system.
"""

LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
try:
# pylint: disable=no-name-in-module
from pennylane_lightning.lightning_gpu_ops import DevTag, MPIManager

MPI_SUPPORT = True

Check warning on line 22 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L22

Added line #L22 was not covered by tests
except ImportError:
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
MPI_SUPPORT = False
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved

from typing import Callable, Union

import numpy as np


# MPI options
class LightningGPU_MPIHandler:
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
"""MPI handler for PennyLane Lightning GPU device

MPI handler to use a GPU-backed Lightning device using NVIDIA cuQuantum SDK with parallel capabilities.

Use the MPI library is necessary to initialize different variables and methods to handle the data across nodes and perform checks for memory allocation on each device.

Args:
mpi (bool): declare if the device will use the MPI support.
mpi_buf_size (int): size of GPU memory (in MiB) set for MPI operation and its default value is 64 MiB.
dev_pool (Callable): Method to handle the GPU devices available.
num_wires (int): the number of wires to initialize the device with.
c_dtype (np.complex64, np.complex128): Datatypes for statevector representation
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
"""

def __init__(
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
self,
mpi: bool,
mpi_buf_size: int,
dev_pool: Callable,
num_wires: int,
c_dtype: Union[np.complex64, np.complex128],
) -> None:

self.use_mpi = mpi
self.mpi_but_size = mpi_buf_size
self._dp = dev_pool

if self.use_mpi:

if not MPI_SUPPORT:
raise ImportError("MPI related APIs are not found.")

Check warning on line 63 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L62-L63

Added lines #L62 - L63 were not covered by tests

if mpi_buf_size < 0:
raise TypeError(f"Unsupported mpi_buf_size value: {mpi_buf_size}, should be >= 0")

Check warning on line 66 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L65-L66

Added lines #L65 - L66 were not covered by tests

if mpi_buf_size > 0 and (mpi_buf_size & (mpi_buf_size - 1)):
raise ValueError(

Check warning on line 69 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L68-L69

Added lines #L68 - L69 were not covered by tests
f"Unsupported mpi_buf_size value: {mpi_buf_size}. mpi_buf_size should be power of 2."
)

# After check if all MPI parameters are ok
self.mpi_manager, self.devtag = self._mpi_init_helper(num_wires)

Check warning on line 74 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L74

Added line #L74 was not covered by tests

# set the number of global and local wires
commSize = self._mpi_manager.getSize()
self.num_global_wires = commSize.bit_length() - 1
self.num_local_wires = num_wires - self._num_global_wires

Check warning on line 79 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L77-L79

Added lines #L77 - L79 were not covered by tests
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved

# Memory size in bytes
sv_memsize = np.dtype(c_dtype).itemsize * (1 << self.num_local_wires)
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
if self._mebibytesToBytes(mpi_buf_size) > sv_memsize:
raise ValueError("The MPI buffer size is larger than the local state vector size.")

Check warning on line 84 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L82-L84

Added lines #L82 - L84 were not covered by tests

if not self.use_mpi:
self.num_local_wires = num_wires
self.num_global_wires = num_wires

def _mebibytesToBytes(mebibytes):
return mebibytes * 1024 * 1024

Check warning on line 91 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L91

Added line #L91 was not covered by tests

def _mpi_init_helper(self, num_wires):
"""Set up MPI checks and initializations."""

# initialize MPIManager and config check in the MPIManager ctor
mpi_manager = MPIManager()

Check warning on line 97 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L97

Added line #L97 was not covered by tests

# check if number of GPUs per node is larger than number of processes per node
numDevices = self._dp.getTotalDevices()
numProcsNode = mpi_manager.getSizeNode()

Check warning on line 101 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L100-L101

Added lines #L100 - L101 were not covered by tests

if numDevices < numProcsNode:
raise ValueError(

Check warning on line 104 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L103-L104

Added lines #L103 - L104 were not covered by tests
"Number of devices should be larger than or equal to the number of processes on each node."
)

# check if the process number is larger than number of statevector elements
if mpi_manager.getSize() > (1 << (num_wires - 1)):
raise ValueError(

Check warning on line 110 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L109-L110

Added lines #L109 - L110 were not covered by tests
"Number of processes should be smaller than the number of statevector elements."
)

# set GPU device
rank = self._mpi_manager.getRank()
LuisAlfredoNu marked this conversation as resolved.
Show resolved Hide resolved
deviceid = rank % numProcsNode
self._dp.setDeviceID(deviceid)
devtag = DevTag(deviceid)

Check warning on line 118 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L115-L118

Added lines #L115 - L118 were not covered by tests

return (mpi_manager, devtag)

Check warning on line 120 in pennylane_lightning/lightning_gpu/_mpi_handler.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_gpu/_mpi_handler.py#L120

Added line #L120 was not covered by tests
Loading
Loading