pennylane-lightning-kokkos 0.42.0__cp311-cp311-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pennylane_lightning/liblightning_kokkos_catalyst.dylib +0 -0
- pennylane_lightning/lightning_kokkos/__init__.py +18 -0
- pennylane_lightning/lightning_kokkos/_adjoint_jacobian.py +137 -0
- pennylane_lightning/lightning_kokkos/_measurements.py +97 -0
- pennylane_lightning/lightning_kokkos/_state_vector.py +340 -0
- pennylane_lightning/lightning_kokkos/lightning_kokkos.py +459 -0
- pennylane_lightning/lightning_kokkos/lightning_kokkos.toml +131 -0
- pennylane_lightning/lightning_kokkos_ops.cpython-311-darwin.so +0 -0
- pennylane_lightning_kokkos-0.42.0.dist-info/METADATA +214 -0
- pennylane_lightning_kokkos-0.42.0.dist-info/RECORD +14 -0
- pennylane_lightning_kokkos-0.42.0.dist-info/WHEEL +5 -0
- pennylane_lightning_kokkos-0.42.0.dist-info/entry_points.txt +2 -0
- pennylane_lightning_kokkos-0.42.0.dist-info/licenses/LICENSE +212 -0
- pennylane_lightning_kokkos-0.42.0.dist-info/top_level.txt +2 -0
Binary file
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright 2018-2024 Xanadu Quantum Technologies Inc.
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
"""PennyLane lightning_kokkos package."""
|
15
|
+
|
16
|
+
from pennylane_lightning.core import __version__
|
17
|
+
|
18
|
+
from .lightning_kokkos import LightningKokkos
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# Copyright 2018-2024 Xanadu Quantum Technologies Inc.
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
r"""
|
15
|
+
Internal methods for adjoint Jacobian differentiation method.
|
16
|
+
"""
|
17
|
+
|
18
|
+
from __future__ import annotations
|
19
|
+
|
20
|
+
from warnings import warn
|
21
|
+
|
22
|
+
try:
|
23
|
+
from pennylane_lightning.lightning_kokkos_ops.algorithms import (
|
24
|
+
AdjointJacobianC64,
|
25
|
+
AdjointJacobianC128,
|
26
|
+
create_ops_listC64,
|
27
|
+
create_ops_listC128,
|
28
|
+
)
|
29
|
+
|
30
|
+
try:
|
31
|
+
from pennylane_lightning.lightning_kokkos_ops.algorithmsMPI import (
|
32
|
+
AdjointJacobianMPIC64,
|
33
|
+
AdjointJacobianMPIC128,
|
34
|
+
create_ops_listMPIC64,
|
35
|
+
create_ops_listMPIC128,
|
36
|
+
)
|
37
|
+
|
38
|
+
mpi_error = None
|
39
|
+
MPI_SUPPORT = True
|
40
|
+
except ImportError as ex_mpi:
|
41
|
+
mpi_error = ex_mpi
|
42
|
+
MPI_SUPPORT = False
|
43
|
+
|
44
|
+
|
45
|
+
except ImportError as ex:
|
46
|
+
warn(str(ex), UserWarning)
|
47
|
+
|
48
|
+
import numpy as np
|
49
|
+
from pennylane.tape import QuantumTape
|
50
|
+
|
51
|
+
# pylint: disable=ungrouped-imports
|
52
|
+
from pennylane_lightning.lightning_base._adjoint_jacobian import LightningBaseAdjointJacobian
|
53
|
+
|
54
|
+
|
55
|
+
class LightningKokkosAdjointJacobian(LightningBaseAdjointJacobian):
|
56
|
+
"""Check and execute the adjoint Jacobian differentiation method.
|
57
|
+
|
58
|
+
Args:
|
59
|
+
qubit_state(LightningKokkosStateVector): State Vector to calculate the adjoint Jacobian with.
|
60
|
+
batch_obs(bool): If serialized tape is to be batched or not.
|
61
|
+
"""
|
62
|
+
|
63
|
+
# pylint: disable=too-few-public-methods
|
64
|
+
def __init__(
|
65
|
+
self,
|
66
|
+
qubit_state: LightningKokkosStateVector, # pylint: disable=undefined-variable
|
67
|
+
batch_obs: bool = False,
|
68
|
+
) -> None:
|
69
|
+
|
70
|
+
self._use_mpi = qubit_state._mpi
|
71
|
+
super().__init__(qubit_state, batch_obs)
|
72
|
+
|
73
|
+
def _adjoint_jacobian_dtype(self):
|
74
|
+
"""Binding to Lightning Kokkos Adjoint Jacobian C++ class.
|
75
|
+
|
76
|
+
Returns: A pair of the AdjointJacobian class and the create_ops_list function. Default is None.
|
77
|
+
"""
|
78
|
+
if self._use_mpi:
|
79
|
+
if not MPI_SUPPORT:
|
80
|
+
warn(str(mpi_error), UserWarning)
|
81
|
+
|
82
|
+
jacobian_lightning = (
|
83
|
+
AdjointJacobianMPIC64() if self.dtype == np.complex64 else AdjointJacobianMPIC128()
|
84
|
+
)
|
85
|
+
create_ops_list_lightning = (
|
86
|
+
create_ops_listMPIC64 if self.dtype == np.complex64 else create_ops_listMPIC128
|
87
|
+
)
|
88
|
+
|
89
|
+
return jacobian_lightning, create_ops_list_lightning
|
90
|
+
|
91
|
+
# without MPI
|
92
|
+
jacobian_lightning = (
|
93
|
+
AdjointJacobianC64() if self.dtype == np.complex64 else AdjointJacobianC128()
|
94
|
+
)
|
95
|
+
create_ops_list_lightning = (
|
96
|
+
create_ops_listC64 if self.dtype == np.complex64 else create_ops_listC128
|
97
|
+
)
|
98
|
+
return jacobian_lightning, create_ops_list_lightning
|
99
|
+
|
100
|
+
def calculate_jacobian(self, tape: QuantumTape):
|
101
|
+
"""Computes the Jacobian with the adjoint method.
|
102
|
+
|
103
|
+
.. code-block:: python
|
104
|
+
|
105
|
+
statevector = LightningKokkosStateVector(num_wires=num_wires)
|
106
|
+
statevector = statevector.get_final_state(tape)
|
107
|
+
jacobian = LightningKokkosAdjointJacobian(statevector).calculate_jacobian(tape)
|
108
|
+
|
109
|
+
Args:
|
110
|
+
tape (QuantumTape): Operations and measurements that represent instructions for execution on Lightning.
|
111
|
+
|
112
|
+
Returns:
|
113
|
+
The Jacobian of a tape.
|
114
|
+
"""
|
115
|
+
|
116
|
+
empty_array = self._handle_raises(tape, is_jacobian=True)
|
117
|
+
|
118
|
+
if empty_array:
|
119
|
+
return np.array([], dtype=self.dtype)
|
120
|
+
processed_data = self._process_jacobian_tape(tape, use_mpi=self._use_mpi)
|
121
|
+
|
122
|
+
if not processed_data: # training_params is empty
|
123
|
+
return np.array([], dtype=self.dtype)
|
124
|
+
|
125
|
+
trainable_params = processed_data["tp_shift"]
|
126
|
+
jac = self._jacobian_lightning(
|
127
|
+
processed_data["state_vector"],
|
128
|
+
processed_data["obs_serialized"],
|
129
|
+
processed_data["ops_serialized"],
|
130
|
+
trainable_params,
|
131
|
+
)
|
132
|
+
jac = np.array(jac)
|
133
|
+
jac = jac.reshape(-1, len(trainable_params)) if len(jac) else jac
|
134
|
+
jac_r = np.zeros((jac.shape[0], processed_data["all_params"]))
|
135
|
+
jac_r[:, processed_data["record_tp_rows"]] = jac
|
136
|
+
|
137
|
+
return self._adjoint_jacobian_processing(jac_r)
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Copyright 2018-2024 Xanadu Quantum Technologies Inc.
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
"""
|
15
|
+
Class implementation for state vector measurements.
|
16
|
+
"""
|
17
|
+
|
18
|
+
from __future__ import annotations
|
19
|
+
|
20
|
+
from warnings import warn
|
21
|
+
|
22
|
+
try:
|
23
|
+
from pennylane_lightning.lightning_kokkos_ops import MeasurementsC64, MeasurementsC128
|
24
|
+
|
25
|
+
try:
|
26
|
+
from pennylane_lightning.lightning_kokkos_ops import MeasurementsMPIC64, MeasurementsMPIC128
|
27
|
+
|
28
|
+
mpi_error = None
|
29
|
+
MPI_SUPPORT = True
|
30
|
+
except ImportError as ex_mpi:
|
31
|
+
mpi_error = ex_mpi
|
32
|
+
MPI_SUPPORT = False
|
33
|
+
|
34
|
+
except ImportError as error_import:
|
35
|
+
warn(str(error_import), UserWarning)
|
36
|
+
|
37
|
+
import numpy as np
|
38
|
+
import pennylane as qml
|
39
|
+
from pennylane.measurements import MeasurementProcess
|
40
|
+
|
41
|
+
# pylint: disable=ungrouped-imports
|
42
|
+
from pennylane_lightning.lightning_base._measurements import LightningBaseMeasurements
|
43
|
+
|
44
|
+
|
45
|
+
class LightningKokkosMeasurements(
|
46
|
+
LightningBaseMeasurements
|
47
|
+
): # pylint: disable=too-few-public-methods
|
48
|
+
"""Lightning Kokkos Measurements class
|
49
|
+
|
50
|
+
Measures the state provided by the LightningKokkosStateVector class.
|
51
|
+
|
52
|
+
Args:
|
53
|
+
qubit_state(LightningKokkosStateVector): Lightning state-vector class containing the state vector to be measured.
|
54
|
+
"""
|
55
|
+
|
56
|
+
def __init__(
|
57
|
+
self,
|
58
|
+
kokkos_state: LightningKokkosStateVector, # pylint: disable=undefined-variable
|
59
|
+
) -> None:
|
60
|
+
super().__init__(kokkos_state)
|
61
|
+
|
62
|
+
self._use_mpi = kokkos_state._mpi
|
63
|
+
|
64
|
+
if self._use_mpi:
|
65
|
+
self._num_local_wires = kokkos_state._qubit_state.getNumLocalWires()
|
66
|
+
|
67
|
+
self._measurement_lightning = self._measurement_dtype()(kokkos_state.state_vector)
|
68
|
+
if kokkos_state._rng:
|
69
|
+
self._measurement_lightning.set_random_seed(kokkos_state._rng.integers(0, 2**31 - 1))
|
70
|
+
|
71
|
+
def _measurement_dtype(self):
|
72
|
+
"""Binding to Lightning Kokkos Measurements C++ class.
|
73
|
+
|
74
|
+
Returns: the Measurements class
|
75
|
+
"""
|
76
|
+
if self._use_mpi:
|
77
|
+
if not MPI_SUPPORT:
|
78
|
+
warn(str(mpi_error), UserWarning)
|
79
|
+
|
80
|
+
return MeasurementsMPIC64 if self.dtype == np.complex64 else MeasurementsMPIC128
|
81
|
+
|
82
|
+
# without MPI
|
83
|
+
return MeasurementsC64 if self.dtype == np.complex64 else MeasurementsC128
|
84
|
+
|
85
|
+
def _expval_pauli_sentence(self, measurementprocess: MeasurementProcess):
|
86
|
+
"""Specialized method for computing the expectation value of a Pauli sentence.
|
87
|
+
|
88
|
+
Args:
|
89
|
+
measurementprocess (MeasurementProcess): Measurement process with pauli_rep.
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
Expectation value.
|
93
|
+
"""
|
94
|
+
pwords, coeffs = zip(*measurementprocess.obs.pauli_rep.items())
|
95
|
+
pauli_words = [qml.pauli.pauli_word_to_string(p) for p in pwords]
|
96
|
+
wires = [p.wires.tolist() for p in pwords]
|
97
|
+
return self._measurement_lightning.expval(pauli_words, wires, coeffs)
|
@@ -0,0 +1,340 @@
|
|
1
|
+
# Copyright 2018-2024 Xanadu Quantum Technologies Inc.
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
"""
|
15
|
+
Class implementation for lightning_kokkos state-vector manipulation.
|
16
|
+
"""
|
17
|
+
from warnings import warn
|
18
|
+
|
19
|
+
try:
|
20
|
+
from pennylane_lightning.lightning_kokkos_ops import (
|
21
|
+
InitializationSettings,
|
22
|
+
StateVectorC64,
|
23
|
+
StateVectorC128,
|
24
|
+
allocate_aligned_array,
|
25
|
+
print_configuration,
|
26
|
+
)
|
27
|
+
|
28
|
+
try:
|
29
|
+
from pennylane_lightning.lightning_kokkos_ops import (
|
30
|
+
MPIManagerKokkos,
|
31
|
+
StateVectorMPIC64,
|
32
|
+
StateVectorMPIC128,
|
33
|
+
)
|
34
|
+
|
35
|
+
mpi_error = None
|
36
|
+
MPI_SUPPORT = True
|
37
|
+
except ImportError as ex_mpi:
|
38
|
+
mpi_error = ex_mpi
|
39
|
+
MPI_SUPPORT = False
|
40
|
+
|
41
|
+
except ImportError as ex:
|
42
|
+
warn(str(ex), UserWarning)
|
43
|
+
|
44
|
+
from typing import Union
|
45
|
+
|
46
|
+
import numpy as np
|
47
|
+
import pennylane as qml
|
48
|
+
import scipy as sp
|
49
|
+
from numpy.random import Generator
|
50
|
+
from pennylane.measurements import MidMeasureMP
|
51
|
+
from pennylane.ops import Conditional
|
52
|
+
from pennylane.ops.op_math import Adjoint
|
53
|
+
from pennylane.wires import Wires
|
54
|
+
|
55
|
+
# pylint: disable=ungrouped-imports
|
56
|
+
from pennylane_lightning.lightning_base._state_vector import LightningBaseStateVector
|
57
|
+
|
58
|
+
from ._measurements import LightningKokkosMeasurements
|
59
|
+
|
60
|
+
|
61
|
+
class LightningKokkosStateVector(LightningBaseStateVector):
|
62
|
+
"""Lightning Kokkos state-vector class.
|
63
|
+
|
64
|
+
Interfaces with C++ python binding methods for state-vector manipulation.
|
65
|
+
|
66
|
+
Args:
|
67
|
+
num_wires (int): the number of wires to initialize the device with
|
68
|
+
dtype: Datatypes for state-vector representation. Must be one of
|
69
|
+
``np.complex64`` or ``np.complex128``. Default is ``np.complex128``
|
70
|
+
rng (Generator): random number generator to use for seeding sampling measurement.
|
71
|
+
kokkos_args (InitializationSettings): binding for Kokkos::InitializationSettings
|
72
|
+
(threading parameters).
|
73
|
+
mpi (bool): Use MPI for distributed state vector.
|
74
|
+
|
75
|
+
"""
|
76
|
+
|
77
|
+
def __init__( # pylint: disable=too-many-arguments, too-many-positional-arguments
|
78
|
+
self,
|
79
|
+
num_wires: int,
|
80
|
+
dtype: Union[np.complex128, np.complex64] = np.complex128,
|
81
|
+
rng: Generator = None,
|
82
|
+
kokkos_args=None,
|
83
|
+
mpi: bool = None,
|
84
|
+
):
|
85
|
+
|
86
|
+
super().__init__(num_wires, dtype, rng)
|
87
|
+
|
88
|
+
self._device_name = "lightning.kokkos"
|
89
|
+
|
90
|
+
self._kokkos_config = {}
|
91
|
+
|
92
|
+
self._mpi = mpi
|
93
|
+
|
94
|
+
# Initialize the state vector
|
95
|
+
|
96
|
+
sv_init_args = [self.num_wires]
|
97
|
+
if mpi:
|
98
|
+
self._mpi_manager = MPIManagerKokkos()
|
99
|
+
sv_init_args.insert(0, self._mpi_manager)
|
100
|
+
|
101
|
+
if kokkos_args is not None:
|
102
|
+
if not isinstance(kokkos_args, InitializationSettings):
|
103
|
+
raise TypeError(
|
104
|
+
f"Argument kokkos_args must be of type {type(InitializationSettings())} but it is of {type(kokkos_args)}."
|
105
|
+
)
|
106
|
+
sv_init_args.append(kokkos_args)
|
107
|
+
|
108
|
+
self._qubit_state = self._state_dtype()(*sv_init_args)
|
109
|
+
|
110
|
+
if not self._kokkos_config:
|
111
|
+
self._kokkos_config = self._kokkos_configuration()
|
112
|
+
|
113
|
+
@property
|
114
|
+
def state(self):
|
115
|
+
"""Copy the state vector data from the device to the host.
|
116
|
+
|
117
|
+
A state vector Numpy array is explicitly allocated on the host to store and return
|
118
|
+
the data.
|
119
|
+
|
120
|
+
**Example**
|
121
|
+
|
122
|
+
>>> dev = qml.device('lightning.kokkos', wires=1)
|
123
|
+
>>> dev.apply([qml.PauliX(wires=[0])])
|
124
|
+
>>> print(dev.state)
|
125
|
+
[0.+0.j 1.+0.j]
|
126
|
+
"""
|
127
|
+
if self._mpi:
|
128
|
+
self._qubit_state.reorderAllWires()
|
129
|
+
local_size = self._qubit_state.getLocalBlockSize()
|
130
|
+
state = np.zeros(local_size, dtype=self.dtype)
|
131
|
+
self.sync_d2h(state)
|
132
|
+
return state
|
133
|
+
state = np.zeros(2**self._num_wires, dtype=self.dtype)
|
134
|
+
self.sync_d2h(state)
|
135
|
+
return state
|
136
|
+
|
137
|
+
def _state_dtype(self):
|
138
|
+
"""Binding to Lightning Managed state vector C++ class.
|
139
|
+
|
140
|
+
Returns: the state vector class
|
141
|
+
"""
|
142
|
+
if self._mpi:
|
143
|
+
return StateVectorMPIC128 if self.dtype == np.complex128 else StateVectorMPIC64
|
144
|
+
|
145
|
+
return StateVectorC128 if self.dtype == np.complex128 else StateVectorC64
|
146
|
+
|
147
|
+
def sync_h2d(self, state_vector):
|
148
|
+
"""Copy the state vector data on host provided by the user to the state
|
149
|
+
vector on the device
|
150
|
+
|
151
|
+
Args:
|
152
|
+
state_vector(array[complex]): the state vector array on host.
|
153
|
+
|
154
|
+
|
155
|
+
**Example**
|
156
|
+
|
157
|
+
>>> dev = qml.device('lightning.kokkos', wires=3)
|
158
|
+
>>> obs = qml.Identity(0) @ qml.PauliX(1) @ qml.PauliY(2)
|
159
|
+
>>> obs1 = qml.Identity(1)
|
160
|
+
>>> H = qml.Hamiltonian([1.0, 1.0], [obs1, obs])
|
161
|
+
>>> state_vector = np.array([0.0 + 0.0j, 0.0 + 0.1j, 0.1 + 0.1j, 0.1 + 0.2j, 0.2 + 0.2j, 0.3 + 0.3j, 0.3 + 0.4j, 0.4 + 0.5j,], dtype=np.complex64)
|
162
|
+
>>> dev.sync_h2d(state_vector)
|
163
|
+
>>> res = dev.expval(H)
|
164
|
+
>>> print(res)
|
165
|
+
1.0
|
166
|
+
"""
|
167
|
+
self._qubit_state.HostToDevice(state_vector.ravel(order="C"))
|
168
|
+
|
169
|
+
def sync_d2h(self, state_vector):
|
170
|
+
"""Copy the state vector data on device to a state vector on the host provided
|
171
|
+
by the user
|
172
|
+
|
173
|
+
Args:
|
174
|
+
state_vector(array[complex]): the state vector array on device
|
175
|
+
|
176
|
+
|
177
|
+
**Example**
|
178
|
+
|
179
|
+
>>> dev = qml.device('lightning.kokkos', wires=1)
|
180
|
+
>>> dev.apply([qml.PauliX(wires=[0])])
|
181
|
+
>>> state_vector = np.zeros(2**dev.num_wires).astype(dev.c_dtype)
|
182
|
+
>>> dev.sync_d2h(state_vector)
|
183
|
+
>>> print(state_vector)
|
184
|
+
[0.+0.j 1.+0.j]
|
185
|
+
"""
|
186
|
+
self._qubit_state.DeviceToHost(state_vector.ravel(order="C"))
|
187
|
+
|
188
|
+
def _kokkos_configuration(self):
|
189
|
+
"""Get the default configuration of the kokkos device.
|
190
|
+
|
191
|
+
Returns: The `lightning.kokkos` device configuration
|
192
|
+
"""
|
193
|
+
return print_configuration()
|
194
|
+
|
195
|
+
# pylint: disable=unused-argument
|
196
|
+
@staticmethod
|
197
|
+
def _operation_is_sparse(operation):
|
198
|
+
"""Check if the operation is a sparse matrix operation.
|
199
|
+
|
200
|
+
Args:
|
201
|
+
operation (_): operation to check
|
202
|
+
|
203
|
+
Returns:
|
204
|
+
bool: True if the operation is a sparse matrix operation, False otherwise
|
205
|
+
"""
|
206
|
+
# Currently there is not support for sparse matrices in the LightningKokkos device.
|
207
|
+
return False
|
208
|
+
|
209
|
+
def _apply_state_vector(self, state, device_wires: Wires):
|
210
|
+
"""Initialize the internal state vector in a specified state.
|
211
|
+
Args:
|
212
|
+
state (Union[array[complex], scipy.SparseABC]): normalized input state of length ``2**len(wires)`` as a dense array or Scipy sparse array.
|
213
|
+
device_wires (Wires): wires that get initialized in the state
|
214
|
+
"""
|
215
|
+
|
216
|
+
if sp.sparse.issparse(state):
|
217
|
+
state = state.toarray().flatten()
|
218
|
+
|
219
|
+
if isinstance(state, self._qubit_state.__class__):
|
220
|
+
state_data = allocate_aligned_array(state.size, np.dtype(self.dtype), True)
|
221
|
+
state.DeviceToHost(state_data)
|
222
|
+
state = state_data
|
223
|
+
|
224
|
+
if len(device_wires) == self._num_wires and Wires(sorted(device_wires)) == device_wires:
|
225
|
+
# Initialize the entire device state with the input state
|
226
|
+
if self._mpi:
|
227
|
+
self._qubit_state.resetIndices()
|
228
|
+
myrank = self._mpi_manager.getRank()
|
229
|
+
local_size = self._qubit_state.getLocalBlockSize()
|
230
|
+
local_state = state[myrank * local_size : (myrank + 1) * local_size]
|
231
|
+
self.sync_h2d(local_state)
|
232
|
+
return
|
233
|
+
|
234
|
+
output_shape = (2,) * self._num_wires
|
235
|
+
state = np.reshape(state, output_shape).ravel(order="C")
|
236
|
+
self.sync_h2d(np.reshape(state, output_shape))
|
237
|
+
return
|
238
|
+
|
239
|
+
# This operate on device
|
240
|
+
self._qubit_state.setStateVector(state, list(device_wires))
|
241
|
+
|
242
|
+
def _apply_lightning_controlled(self, operation, adjoint):
|
243
|
+
"""Apply an arbitrary controlled operation to the state tensor.
|
244
|
+
|
245
|
+
Args:
|
246
|
+
operation (~pennylane.operation.Operation): controlled operation to apply
|
247
|
+
adjoint (bool): Apply the adjoint of the operation if True
|
248
|
+
|
249
|
+
Returns:
|
250
|
+
None
|
251
|
+
"""
|
252
|
+
state = self.state_vector
|
253
|
+
|
254
|
+
if isinstance(operation.base, Adjoint):
|
255
|
+
base_operation = operation.base.base
|
256
|
+
adjoint = not adjoint
|
257
|
+
else:
|
258
|
+
base_operation = operation.base
|
259
|
+
|
260
|
+
method = getattr(state, f"{base_operation.name}", None)
|
261
|
+
control_wires = list(operation.control_wires)
|
262
|
+
control_values = operation.control_values
|
263
|
+
target_wires = list(operation.target_wires)
|
264
|
+
if method is not None: # apply n-controlled specialized gate
|
265
|
+
param = operation.parameters
|
266
|
+
method(control_wires, control_values, target_wires, adjoint, param)
|
267
|
+
else: # apply gate as an n-controlled matrix
|
268
|
+
method = getattr(state, "applyControlledMatrix")
|
269
|
+
method(
|
270
|
+
qml.matrix(base_operation),
|
271
|
+
control_wires,
|
272
|
+
control_values,
|
273
|
+
target_wires,
|
274
|
+
adjoint,
|
275
|
+
)
|
276
|
+
|
277
|
+
def _apply_lightning(
|
278
|
+
self, operations, mid_measurements: dict = None, postselect_mode: str = None
|
279
|
+
):
|
280
|
+
"""Apply a list of operations to the state tensor.
|
281
|
+
|
282
|
+
Args:
|
283
|
+
operations (list[~pennylane.operation.Operation]): operations to apply
|
284
|
+
mid_measurements (None, dict): Dictionary of mid-circuit measurements
|
285
|
+
postselect_mode (str): Configuration for handling shots with mid-circuit measurement
|
286
|
+
postselection. Use ``"hw-like"`` to discard invalid shots and ``"fill-shots"`` to
|
287
|
+
keep the same number of shots. Default is ``None``.
|
288
|
+
|
289
|
+
Returns:
|
290
|
+
None
|
291
|
+
"""
|
292
|
+
state = self.state_vector
|
293
|
+
|
294
|
+
# Skip over identity operations instead of performing
|
295
|
+
# matrix multiplication with it.
|
296
|
+
for operation in operations:
|
297
|
+
if isinstance(operation, qml.Identity):
|
298
|
+
continue
|
299
|
+
if isinstance(operation, Adjoint):
|
300
|
+
op_adjoint_base = operation.base
|
301
|
+
invert_param = True
|
302
|
+
else:
|
303
|
+
op_adjoint_base = operation
|
304
|
+
invert_param = False
|
305
|
+
name = op_adjoint_base.name
|
306
|
+
method = getattr(state, name, None)
|
307
|
+
wires = list(operation.wires)
|
308
|
+
|
309
|
+
if isinstance(operation, Conditional):
|
310
|
+
if operation.meas_val.concretize(mid_measurements):
|
311
|
+
self._apply_lightning([operation.base])
|
312
|
+
elif isinstance(operation, MidMeasureMP):
|
313
|
+
self._apply_lightning_midmeasure(
|
314
|
+
LightningKokkosMeasurements(self).measure_final_state,
|
315
|
+
operation,
|
316
|
+
mid_measurements,
|
317
|
+
postselect_mode=postselect_mode,
|
318
|
+
)
|
319
|
+
elif isinstance(operation, qml.PauliRot):
|
320
|
+
method = getattr(state, "applyPauliRot")
|
321
|
+
paulis = operation._hyperparameters[ # pylint: disable=protected-access
|
322
|
+
"pauli_word"
|
323
|
+
]
|
324
|
+
wires = [i for i, w in zip(wires, paulis) if w != "I"]
|
325
|
+
word = "".join(p for p in paulis if p != "I")
|
326
|
+
method(wires, invert_param, operation.parameters, word)
|
327
|
+
elif method is not None: # apply specialized gate
|
328
|
+
param = operation.parameters
|
329
|
+
method(wires, invert_param, param)
|
330
|
+
elif isinstance(op_adjoint_base, qml.ops.Controlled): # apply n-controlled gate
|
331
|
+
self._apply_lightning_controlled(op_adjoint_base, invert_param)
|
332
|
+
else: # apply gate as a matrix
|
333
|
+
# Inverse can be set to False since qml.matrix(operation) is already in
|
334
|
+
# inverted form
|
335
|
+
method = getattr(state, "applyMatrix")
|
336
|
+
try:
|
337
|
+
method(qml.matrix(operation), wires, False)
|
338
|
+
except AttributeError: # pragma: no cover
|
339
|
+
# To support older versions of PL
|
340
|
+
method(operation.matrix, wires, False)
|