pennylane-qrack 0.19.0__py3-none-win_amd64.whl → 0.20.1__py3-none-win_amd64.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.
Potentially problematic release.
This version of pennylane-qrack might be problematic. Click here for more details.
- pennylane_qrack/QrackAceDeviceConfig.toml +117 -0
- pennylane_qrack/QrackDeviceConfig.toml +17 -26
- pennylane_qrack/_version.py +1 -1
- pennylane_qrack/qrack_ace_device.py +452 -0
- {pennylane_qrack-0.19.0.dist-info → pennylane_qrack-0.20.1.dist-info}/METADATA +2 -1
- pennylane_qrack-0.20.1.dist-info/RECORD +13 -0
- {pennylane_qrack-0.19.0.dist-info → pennylane_qrack-0.20.1.dist-info}/entry_points.txt +1 -0
- pennylane_qrack-0.19.0.dist-info/RECORD +0 -11
- {pennylane_qrack-0.19.0.dist-info → pennylane_qrack-0.20.1.dist-info}/LICENSE +0 -0
- {pennylane_qrack-0.19.0.dist-info → pennylane_qrack-0.20.1.dist-info}/WHEEL +0 -0
- {pennylane_qrack-0.19.0.dist-info → pennylane_qrack-0.20.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
schema = 3
|
|
2
|
+
|
|
3
|
+
# The set of all gate types supported at the runtime execution interface of the
|
|
4
|
+
# device, i.e., what is supported by the `execute` method. The gate definitions
|
|
5
|
+
# should have the following format:
|
|
6
|
+
#
|
|
7
|
+
# GATE = { properties = [ PROPS ], conditions = [ CONDS ] }
|
|
8
|
+
#
|
|
9
|
+
# where PROPS and CONS are zero or more comma separated quoted strings.
|
|
10
|
+
#
|
|
11
|
+
# PROPS: additional support provided for each gate.
|
|
12
|
+
# - "controllable": if a controlled version of this gate is supported.
|
|
13
|
+
# - "invertible": if the adjoint of this operation is supported.
|
|
14
|
+
# - "differentiable": if device gradient is supported for this gate.
|
|
15
|
+
# CONDS: constraints on the support for each gate.
|
|
16
|
+
# - "analytic" or "finiteshots": if this operation is only supported in
|
|
17
|
+
# either analytic execution or with shots, respectively.
|
|
18
|
+
#
|
|
19
|
+
[operators.gates]
|
|
20
|
+
|
|
21
|
+
PauliX = { properties = [ "controllable", "invertible" ] }
|
|
22
|
+
PauliY = { properties = [ "controllable", "invertible" ] }
|
|
23
|
+
PauliZ = { properties = [ "controllable", "invertible" ] }
|
|
24
|
+
SX = { properties = [ "controllable", "invertible" ] }
|
|
25
|
+
MultiRZ = { properties = [ "controllable", "invertible" ] }
|
|
26
|
+
Hadamard = { properties = [ "controllable", "invertible" ] }
|
|
27
|
+
S = { properties = [ "controllable", "invertible" ] }
|
|
28
|
+
T = { properties = [ "controllable", "invertible" ] }
|
|
29
|
+
CNOT = { properties = [ "controllable", "invertible" ] }
|
|
30
|
+
SWAP = { properties = [ "controllable", "invertible" ] }
|
|
31
|
+
CSWAP = { properties = [ "controllable", "invertible" ] }
|
|
32
|
+
ISWAP = { properties = [ "controllable", "invertible" ] }
|
|
33
|
+
PSWAP = { properties = [ "controllable", "invertible" ] }
|
|
34
|
+
Toffoli = { properties = [ "controllable", "invertible" ] }
|
|
35
|
+
CY = { properties = [ "controllable", "invertible" ] }
|
|
36
|
+
CZ = { properties = [ "controllable", "invertible" ] }
|
|
37
|
+
PhaseShift = { properties = [ "controllable", "invertible" ] }
|
|
38
|
+
ControlledPhaseShift = { properties = [ "controllable", "invertible" ] }
|
|
39
|
+
CPhase = { properties = [ "controllable", "invertible" ] }
|
|
40
|
+
RX = { properties = [ "controllable", "invertible" ] }
|
|
41
|
+
RY = { properties = [ "controllable", "invertible" ] }
|
|
42
|
+
RZ = { properties = [ "controllable", "invertible" ] }
|
|
43
|
+
Rot = { properties = [ "controllable", "invertible" ] }
|
|
44
|
+
CRX = { properties = [ "controllable", "invertible" ] }
|
|
45
|
+
CRY = { properties = [ "controllable", "invertible" ] }
|
|
46
|
+
CRZ = { properties = [ "controllable", "invertible" ] }
|
|
47
|
+
CRot = { properties = [ "controllable", "invertible" ] }
|
|
48
|
+
U3 = { properties = [ "controllable", "invertible" ] }
|
|
49
|
+
MultiControlledX = { properties = [ "controllable", "invertible" ] }
|
|
50
|
+
Identity = { properties = [ "controllable", "invertible" ] }
|
|
51
|
+
|
|
52
|
+
# Observables supported by the device for measurements. The observables defined
|
|
53
|
+
# in this section should have the following format:
|
|
54
|
+
#
|
|
55
|
+
# OBSERVABLE = { conditions = [ CONDS ] }
|
|
56
|
+
#
|
|
57
|
+
# where CONDS is zero or more comma separated quoted strings, same as above.
|
|
58
|
+
#
|
|
59
|
+
# CONDS: constraints on the support for each observable.
|
|
60
|
+
# - "analytic" or "finiteshots": if this observable is only supported in
|
|
61
|
+
# either analytic execution or with shots, respectively.
|
|
62
|
+
# - "terms-commute": if a composite operator is only supported under the
|
|
63
|
+
# condition that its terms commute.
|
|
64
|
+
#
|
|
65
|
+
[operators.observables]
|
|
66
|
+
|
|
67
|
+
PauliX = {}
|
|
68
|
+
PauliY = {}
|
|
69
|
+
PauliZ = {}
|
|
70
|
+
Identity = {}
|
|
71
|
+
Prod = {}
|
|
72
|
+
# Hadamard = {}
|
|
73
|
+
# Hermitian = {}
|
|
74
|
+
# Projector = {}
|
|
75
|
+
# SparseHamiltonian = {}
|
|
76
|
+
# Hamiltonian = {}
|
|
77
|
+
# Sum = {}
|
|
78
|
+
# SProd = {}
|
|
79
|
+
# Exp = {}
|
|
80
|
+
|
|
81
|
+
# Types of measurement processes supported on the device. The measurements in
|
|
82
|
+
# this section should have the following format:
|
|
83
|
+
#
|
|
84
|
+
# MEASUREMENT_PROCESS = { conditions = [ CONDS ] }
|
|
85
|
+
#
|
|
86
|
+
# where CONDS is zero or more comma separated quoted strings, same as above.
|
|
87
|
+
#
|
|
88
|
+
# CONDS: constraints on the support for each measurement process.
|
|
89
|
+
# - "analytic" or "finiteshots": if this measurement is only supported
|
|
90
|
+
# in either analytic execution or with shots, respectively.
|
|
91
|
+
#
|
|
92
|
+
[measurement_processes]
|
|
93
|
+
|
|
94
|
+
ExpectationMP = { conditions = [ "finiteshots" ] }
|
|
95
|
+
VarianceMP = { conditions = [ "finiteshots" ] }
|
|
96
|
+
ProbabilityMP = { conditions = [ "finiteshots" ] }
|
|
97
|
+
StateMP = { conditions = [ "finiteshots" ] }
|
|
98
|
+
SampleMP = { conditions = [ "finiteshots" ] }
|
|
99
|
+
CountsMP = { conditions = [ "finiteshots" ] }
|
|
100
|
+
|
|
101
|
+
# Additional support that the device may provide that informs the compilation
|
|
102
|
+
# process. All accepted fields and their default values are listed below.
|
|
103
|
+
[compilation]
|
|
104
|
+
|
|
105
|
+
# Whether the device is compatible with qjit.
|
|
106
|
+
qjit_compatible = false
|
|
107
|
+
|
|
108
|
+
# Whether the device requires run time generation of the quantum circuit.
|
|
109
|
+
runtime_code_generation = false
|
|
110
|
+
|
|
111
|
+
# Whether the device supports allocating and releasing qubits during execution.
|
|
112
|
+
dynamic_qubit_management = false
|
|
113
|
+
|
|
114
|
+
# The methods of handling mid-circuit measurements that the device supports,
|
|
115
|
+
# e.g., "one-shot", "tree-traversal", "device", etc. An empty list indicates
|
|
116
|
+
# that the device does not support mid-circuit measurements.
|
|
117
|
+
supported_mcm_methods = [ "device", "one-shot" ]
|
|
@@ -21,32 +21,23 @@ schema = 3
|
|
|
21
21
|
PauliX = { properties = [ "controllable", "invertible" ] }
|
|
22
22
|
PauliY = { properties = [ "controllable", "invertible" ] }
|
|
23
23
|
PauliZ = { properties = [ "controllable", "invertible" ] }
|
|
24
|
-
SX = { properties = [ "
|
|
25
|
-
MultiRZ = { properties = [ "
|
|
26
|
-
Hadamard = { properties = [ "
|
|
27
|
-
S = { properties = [ "
|
|
28
|
-
T = { properties = [ "
|
|
29
|
-
CNOT = { properties = [ "
|
|
30
|
-
SWAP = { properties = [ "
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
RY = { properties = [ "controllable", "invertible" ] }
|
|
42
|
-
RZ = { properties = [ "controllable", "invertible" ] }
|
|
43
|
-
Rot = { properties = [ "controllable", "invertible" ] }
|
|
44
|
-
CRX = { properties = [ "controllable", "invertible" ] }
|
|
45
|
-
CRY = { properties = [ "controllable", "invertible" ] }
|
|
46
|
-
CRZ = { properties = [ "controllable", "invertible" ] }
|
|
47
|
-
CRot = { properties = [ "controllable", "invertible" ] }
|
|
48
|
-
U3 = { properties = [ "controllable", "invertible" ] }
|
|
49
|
-
MultiControlledX = { properties = [ "controllable", "invertible" ] }
|
|
24
|
+
SX = { properties = [ "invertible" ] }
|
|
25
|
+
MultiRZ = { properties = [ "invertible" ] }
|
|
26
|
+
Hadamard = { properties = [ "invertible" ] }
|
|
27
|
+
S = { properties = [ "invertible" ] }
|
|
28
|
+
T = { properties = [ "invertible" ] }
|
|
29
|
+
CNOT = { properties = [ "invertible" ] }
|
|
30
|
+
SWAP = { properties = [ "invertible" ] }
|
|
31
|
+
ISWAP = { properties = [ "invertible" ] }
|
|
32
|
+
PSWAP = { properties = [ "invertible" ] }
|
|
33
|
+
CY = { properties = [ "invertible" ] }
|
|
34
|
+
CZ = { properties = [ "invertible" ] }
|
|
35
|
+
PhaseShift = { properties = [ "invertible" ] }
|
|
36
|
+
RX = { properties = [ "invertible" ] }
|
|
37
|
+
RY = { properties = [ "invertible" ] }
|
|
38
|
+
RZ = { properties = [ "invertible" ] }
|
|
39
|
+
Rot = { properties = [ "invertible" ] }
|
|
40
|
+
U3 = { properties = [ "invertible" ] }
|
|
50
41
|
Identity = { properties = [ "controllable", "invertible" ] }
|
|
51
42
|
|
|
52
43
|
# Observables supported by the device for measurements. The observables defined
|
pennylane_qrack/_version.py
CHANGED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
# Copyright 2020 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
|
+
Base device class for PennyLane-Qrack.
|
|
16
|
+
"""
|
|
17
|
+
from functools import reduce
|
|
18
|
+
import cmath, math
|
|
19
|
+
import os
|
|
20
|
+
import pathlib
|
|
21
|
+
import sys
|
|
22
|
+
import itertools as it
|
|
23
|
+
|
|
24
|
+
import numpy as np
|
|
25
|
+
|
|
26
|
+
# PennyLane v0.42 introduced the `exceptions` module and will raise
|
|
27
|
+
# deprecation warnings if they are imported from the top-level module.
|
|
28
|
+
|
|
29
|
+
# This ensures backwards compatibility with older versions of PennyLane.
|
|
30
|
+
try:
|
|
31
|
+
from pennylane.exceptions import DeviceError, QuantumFunctionError
|
|
32
|
+
except (ModuleNotFoundError, ImportError) as import_error:
|
|
33
|
+
from pennylane import DeviceError, QuantumFunctionError
|
|
34
|
+
|
|
35
|
+
from pennylane.devices import QubitDevice
|
|
36
|
+
from pennylane.ops import (
|
|
37
|
+
BasisState,
|
|
38
|
+
Adjoint,
|
|
39
|
+
)
|
|
40
|
+
from pennylane.wires import Wires
|
|
41
|
+
|
|
42
|
+
from pyqrack import QrackAceBackend, Pauli
|
|
43
|
+
|
|
44
|
+
from ._version import __version__
|
|
45
|
+
from sys import platform as _platform
|
|
46
|
+
|
|
47
|
+
# tolerance for numerical errors
|
|
48
|
+
tolerance = 1e-10
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class QrackAceDevice(QubitDevice):
|
|
52
|
+
"""Qrack Ace device"""
|
|
53
|
+
|
|
54
|
+
name = "Qrack device"
|
|
55
|
+
short_name = "qrack.ace"
|
|
56
|
+
pennylane_requires = ">=0.11.0"
|
|
57
|
+
version = __version__
|
|
58
|
+
author = "Daniel Strano, adapted from Steven Oud and Xanadu"
|
|
59
|
+
|
|
60
|
+
_capabilities = {
|
|
61
|
+
"model": "qubit",
|
|
62
|
+
"tensor_observables": True,
|
|
63
|
+
"inverse_operations": True,
|
|
64
|
+
"returns_state": False,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_observable_map = {
|
|
68
|
+
"PauliX": Pauli.PauliX,
|
|
69
|
+
"PauliY": Pauli.PauliY,
|
|
70
|
+
"PauliZ": Pauli.PauliZ,
|
|
71
|
+
"Identity": Pauli.PauliI,
|
|
72
|
+
"Hadamard": None,
|
|
73
|
+
"Hermitian": None,
|
|
74
|
+
"Prod": None,
|
|
75
|
+
# "Sum": None,
|
|
76
|
+
# "SProd": None,
|
|
77
|
+
# "Exp": None,
|
|
78
|
+
# "Projector": None,
|
|
79
|
+
# "Hamiltonian": None,
|
|
80
|
+
# "SparseHamiltonian": None
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
observables = _observable_map.keys()
|
|
84
|
+
operations = {
|
|
85
|
+
"Identity",
|
|
86
|
+
"C(Identity)",
|
|
87
|
+
"MultiRZ",
|
|
88
|
+
"C(MultiRZ)",
|
|
89
|
+
"CRX",
|
|
90
|
+
"CRY",
|
|
91
|
+
"CRZ",
|
|
92
|
+
"CRot",
|
|
93
|
+
"SWAP",
|
|
94
|
+
"ISWAP",
|
|
95
|
+
"PSWAP",
|
|
96
|
+
"CNOT",
|
|
97
|
+
"CY",
|
|
98
|
+
"CZ",
|
|
99
|
+
"S",
|
|
100
|
+
"T",
|
|
101
|
+
"RX",
|
|
102
|
+
"RY",
|
|
103
|
+
"RZ",
|
|
104
|
+
"PauliX",
|
|
105
|
+
"C(PauliX)",
|
|
106
|
+
"PauliY",
|
|
107
|
+
"C(PauliY)",
|
|
108
|
+
"PauliZ",
|
|
109
|
+
"C(PauliZ)",
|
|
110
|
+
"Hadamard",
|
|
111
|
+
"SX",
|
|
112
|
+
"PhaseShift",
|
|
113
|
+
"C(PhaseShift)",
|
|
114
|
+
"U3",
|
|
115
|
+
"Rot",
|
|
116
|
+
"ControlledPhaseShift",
|
|
117
|
+
"CPhase",
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
config_filepath = pathlib.Path(
|
|
121
|
+
os.path.dirname(sys.modules[__name__].__file__) + "/QrackDeviceConfig.toml"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Use "hybrid" stabilizer optimization? (Default is "true"; non-Clifford circuits will fall back to near-Clifford or universal simulation)
|
|
125
|
+
isStabilizerHybrid = False
|
|
126
|
+
# Use "tensor network" optimization? (Default is "true"; prevents dynamic qubit de-allocation; might function sub-optimally with "hybrid" stabilizer enabled)
|
|
127
|
+
isTensorNetwork = False
|
|
128
|
+
# Use Schmidt decomposition optimizations? (Default is "true")
|
|
129
|
+
isSchmidtDecompose = True
|
|
130
|
+
# Distribute Schmidt-decomposed qubit subsystems to multiple GPUs or accelerators, if available? (Default is "true"; mismatched device capacities might hurt overall performance)
|
|
131
|
+
isSchmidtDecomposeMulti = True
|
|
132
|
+
# Use "quantum binary decision diagram" ("QBDD") methods? (Default is "false"; note that QBDD is CPU-only)
|
|
133
|
+
isBinaryDecisionTree = False
|
|
134
|
+
# Use GPU acceleration? (Default is "true")
|
|
135
|
+
isOpenCL = True
|
|
136
|
+
# Use multi-GPU (or "multi-page") acceleration? (Default is "false")
|
|
137
|
+
isPaged = True
|
|
138
|
+
# Use CPU/GPU method hybridization? (Default is "false")
|
|
139
|
+
isCpuGpuHybrid = True
|
|
140
|
+
# Allocate GPU buffer from general host heap? (Default is "false"; "true" might improve performance or reliability in certain cases, like if using an Intel HD as accelerator)
|
|
141
|
+
isHostPointer = True if os.environ.get("PYQRACK_HOST_POINTER_DEFAULT_ON") else False
|
|
142
|
+
# Noise parameter. (Default is "0"; depolarizing noise intensity can also be controlled by "QRACK_GATE_DEPOLARIZATION" environment variable)
|
|
143
|
+
noise = 0
|
|
144
|
+
# How many full simulation columns, between border columns
|
|
145
|
+
long_range_columns=4
|
|
146
|
+
# How many full simulation rows, between border rows
|
|
147
|
+
long_range_rows=4
|
|
148
|
+
# Whether to transpose rows and columns
|
|
149
|
+
is_transpose=False
|
|
150
|
+
|
|
151
|
+
def __init__(self, wires=0, shots=None, **kwargs):
|
|
152
|
+
options = dict(kwargs)
|
|
153
|
+
if "isStabilizerHybrid" in options:
|
|
154
|
+
self.isStabilizerHybrid = options["isStabilizerHybrid"]
|
|
155
|
+
if "isTensorNetwork" in options:
|
|
156
|
+
self.isTensorNetwork = options["isTensorNetwork"]
|
|
157
|
+
if "isSchmidtDecompose" in options:
|
|
158
|
+
self.isSchmidtDecompose = options["isSchmidtDecompose"]
|
|
159
|
+
if "isBinaryDecisionTree" in options:
|
|
160
|
+
self.isBinaryDecisionTree = options["isBinaryDecisionTree"]
|
|
161
|
+
if "isOpenCL" in options:
|
|
162
|
+
self.isOpenCL = options["isOpenCL"]
|
|
163
|
+
if "isPaged" in options:
|
|
164
|
+
self.isPaged = options["isPaged"]
|
|
165
|
+
if "isCpuGpuHybrid" in options:
|
|
166
|
+
self.isCpuGpuHybrid = options["isCpuGpuHybrid"]
|
|
167
|
+
if "isHostPointer" in options:
|
|
168
|
+
self.isHostPointer = options["isHostPointer"]
|
|
169
|
+
if "noise" in options:
|
|
170
|
+
self.noise = options["noise"]
|
|
171
|
+
if (self.noise != 0) and (shots is None):
|
|
172
|
+
raise ValueError("Shots must be finite for noisy simulation (not analytical mode).")
|
|
173
|
+
if "long_range_columns" in options:
|
|
174
|
+
self.long_range_columns = options["long_range_columns"]
|
|
175
|
+
if "long_range_rows" in options:
|
|
176
|
+
self.long_range_rows = options["long_range_rows"]
|
|
177
|
+
if "is_transpose" in options:
|
|
178
|
+
self.is_transpose = options["is_transpose"]
|
|
179
|
+
|
|
180
|
+
super().__init__(wires=wires, shots=shots)
|
|
181
|
+
self.shots = shots
|
|
182
|
+
self._state = QrackAceBackend(
|
|
183
|
+
self.num_wires,
|
|
184
|
+
long_range_columns=self.long_range_columns,
|
|
185
|
+
long_range_rows=self.long_range_rows,
|
|
186
|
+
is_transpose=self.is_transpose,
|
|
187
|
+
isStabilizerHybrid=self.isStabilizerHybrid,
|
|
188
|
+
isTensorNetwork=self.isTensorNetwork,
|
|
189
|
+
isSchmidtDecompose=self.isSchmidtDecompose,
|
|
190
|
+
isBinaryDecisionTree=self.isBinaryDecisionTree,
|
|
191
|
+
isOpenCL=self.isOpenCL,
|
|
192
|
+
isCpuGpuHybrid=self.isCpuGpuHybrid,
|
|
193
|
+
isHostPointer=self.isHostPointer,
|
|
194
|
+
noise=self.noise,
|
|
195
|
+
)
|
|
196
|
+
self.device_kwargs = {
|
|
197
|
+
"long_range_columns": self.long_range_columns,
|
|
198
|
+
"long_range_rows": self.long_range_rows,
|
|
199
|
+
"is_transpose": self.is_transpose,
|
|
200
|
+
"is_hybrid_stabilizer": self.isStabilizerHybrid,
|
|
201
|
+
"is_tensor_network": self.isTensorNetwork,
|
|
202
|
+
"is_schmidt_decompose": self.isSchmidtDecompose,
|
|
203
|
+
"is_schmidt_decompose_parallel": self.isSchmidtDecomposeMulti,
|
|
204
|
+
"is_qpdd": self.isBinaryDecisionTree,
|
|
205
|
+
"is_gpu": self.isOpenCL,
|
|
206
|
+
"is_paged": self.isPaged,
|
|
207
|
+
"is_hybrid_cpu_gpu": self.isCpuGpuHybrid,
|
|
208
|
+
"is_host_pointer": self.isHostPointer,
|
|
209
|
+
"noise": self.noise,
|
|
210
|
+
}
|
|
211
|
+
self._circuit = []
|
|
212
|
+
|
|
213
|
+
def _reverse_state(self):
|
|
214
|
+
end = self.num_wires - 1
|
|
215
|
+
mid = self.num_wires >> 1
|
|
216
|
+
for i in range(mid):
|
|
217
|
+
self._state.swap(i, end - i)
|
|
218
|
+
|
|
219
|
+
def apply(self, operations, **kwargs):
|
|
220
|
+
"""Apply the circuit operations to the state.
|
|
221
|
+
|
|
222
|
+
This method serves as an auxiliary method to :meth:`~.QrackDevice.apply`.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
operations (List[pennylane.Operation]): operations to be applied
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
self._circuit = self._circuit + operations
|
|
229
|
+
if self.noise == 0:
|
|
230
|
+
self._apply()
|
|
231
|
+
self._circuit = []
|
|
232
|
+
# else: Defer application until shots or expectation values are requested
|
|
233
|
+
|
|
234
|
+
def _apply(self):
|
|
235
|
+
for op in self._circuit:
|
|
236
|
+
if isinstance(op, BasisState):
|
|
237
|
+
self._apply_basis_state(op)
|
|
238
|
+
else:
|
|
239
|
+
self._apply_gate(op)
|
|
240
|
+
|
|
241
|
+
def _apply_basis_state(self, op):
|
|
242
|
+
"""Initialize a basis state"""
|
|
243
|
+
wires = self.map_wires(Wires(op.wires))
|
|
244
|
+
par = op.parameters[0]
|
|
245
|
+
wire_count = len(wires)
|
|
246
|
+
n_basis_state = len(par)
|
|
247
|
+
|
|
248
|
+
if not set(par).issubset({0, 1}):
|
|
249
|
+
raise ValueError("BasisState parameter must consist of 0 or 1 integers.")
|
|
250
|
+
if n_basis_state != wire_count:
|
|
251
|
+
raise ValueError("BasisState parameter and wires must be of equal length.")
|
|
252
|
+
|
|
253
|
+
for i in range(wire_count):
|
|
254
|
+
index = wires.labels[i]
|
|
255
|
+
if par[i] != self._state.m(index):
|
|
256
|
+
self._state.x(index)
|
|
257
|
+
|
|
258
|
+
def _apply_gate(self, op):
|
|
259
|
+
"""Apply native qrack gate"""
|
|
260
|
+
|
|
261
|
+
opname = op.name
|
|
262
|
+
if isinstance(op, Adjoint):
|
|
263
|
+
op = op.base
|
|
264
|
+
opname = op.name + ".inv"
|
|
265
|
+
|
|
266
|
+
par = op.parameters
|
|
267
|
+
|
|
268
|
+
if opname == "MultiRZ":
|
|
269
|
+
device_wires = self.map_wires(op.wires)
|
|
270
|
+
for q in device_wires:
|
|
271
|
+
self._state.r(Pauli.PauliZ, par[0], q)
|
|
272
|
+
return
|
|
273
|
+
|
|
274
|
+
# translate op wire labels to consecutive wire labels used by the device
|
|
275
|
+
device_wires = self.map_wires(
|
|
276
|
+
(op.control_wires + op.wires) if op.control_wires else op.wires
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
if opname in [
|
|
280
|
+
"".join(p)
|
|
281
|
+
for p in it.product(
|
|
282
|
+
[
|
|
283
|
+
"CNOT",
|
|
284
|
+
"C(PauliX)",
|
|
285
|
+
],
|
|
286
|
+
["", ".inv"],
|
|
287
|
+
)
|
|
288
|
+
]:
|
|
289
|
+
self._state.mcx(device_wires.labels[:-1], device_wires.labels[-1])
|
|
290
|
+
elif opname in ["C(PauliY)", "C(PauliY).inv"]:
|
|
291
|
+
self._state.mcy(device_wires.labels[:-1], device_wires.labels[-1])
|
|
292
|
+
elif opname in ["C(PauliZ)", "C(PauliZ).inv"]:
|
|
293
|
+
self._state.mcz(device_wires.labels[:-1], device_wires.labels[-1])
|
|
294
|
+
elif opname in ["SWAP", "SWAP.inv"]:
|
|
295
|
+
self._state.swap(device_wires.labels[0], device_wires.labels[1])
|
|
296
|
+
elif opname == "ISWAP":
|
|
297
|
+
self._state.iswap(device_wires.labels[0], device_wires.labels[1])
|
|
298
|
+
elif opname == "ISWAP.inv":
|
|
299
|
+
self._state.adjiswap(device_wires.labels[0], device_wires.labels[1])
|
|
300
|
+
elif opname in ["CY", "CY.inv", "C(CY)", "C(CY).inv"]:
|
|
301
|
+
self._state.mcy(device_wires.labels[:-1], device_wires.labels[-1])
|
|
302
|
+
elif opname in ["CZ", "CZ.inv", "C(CZ)", "C(CZ).inv"]:
|
|
303
|
+
self._state.mcz(device_wires.labels[:-1], device_wires.labels[-1])
|
|
304
|
+
elif opname == "S":
|
|
305
|
+
for label in device_wires.labels:
|
|
306
|
+
self._state.s(label)
|
|
307
|
+
elif opname == "S.inv":
|
|
308
|
+
for label in device_wires.labels:
|
|
309
|
+
self._state.adjs(label)
|
|
310
|
+
elif opname == "T":
|
|
311
|
+
for label in device_wires.labels:
|
|
312
|
+
self._state.t(label)
|
|
313
|
+
elif opname == "T.inv":
|
|
314
|
+
for label in device_wires.labels:
|
|
315
|
+
self._state.adjt(label)
|
|
316
|
+
elif opname == "RX":
|
|
317
|
+
for label in device_wires.labels:
|
|
318
|
+
self._state.r(Pauli.PauliX, par[0], label)
|
|
319
|
+
elif opname == "RX.inv":
|
|
320
|
+
for label in device_wires.labels:
|
|
321
|
+
self._state.r(Pauli.PauliX, -par[0], label)
|
|
322
|
+
elif opname == "RY":
|
|
323
|
+
for label in device_wires.labels:
|
|
324
|
+
self._state.r(Pauli.PauliY, par[0], label)
|
|
325
|
+
elif opname == "RY.inv":
|
|
326
|
+
for label in device_wires.labels:
|
|
327
|
+
self._state.r(Pauli.PauliY, -par[0], label)
|
|
328
|
+
elif opname == "RZ":
|
|
329
|
+
for label in device_wires.labels:
|
|
330
|
+
self._state.r(Pauli.PauliZ, par[0], label)
|
|
331
|
+
elif opname == "RZ.inv":
|
|
332
|
+
for label in device_wires.labels:
|
|
333
|
+
self._state.r(Pauli.PauliZ, -par[0], label)
|
|
334
|
+
elif opname in ["PauliX", "PauliX.inv"]:
|
|
335
|
+
for label in device_wires.labels:
|
|
336
|
+
self._state.x(label)
|
|
337
|
+
elif opname in ["PauliY", "PauliY.inv"]:
|
|
338
|
+
for label in device_wires.labels:
|
|
339
|
+
self._state.y(label)
|
|
340
|
+
elif opname in ["PauliZ", "PauliZ.inv"]:
|
|
341
|
+
for label in device_wires.labels:
|
|
342
|
+
self._state.z(label)
|
|
343
|
+
elif opname in ["Hadamard", "Hadamard.inv"]:
|
|
344
|
+
for label in device_wires.labels:
|
|
345
|
+
self._state.h(label)
|
|
346
|
+
elif opname == "SX":
|
|
347
|
+
half_pi = math.pi / 2
|
|
348
|
+
for label in device_wires.labels:
|
|
349
|
+
self._state.u(label, half_pi, -half_pi, half.pi)
|
|
350
|
+
elif opname == "SX.inv":
|
|
351
|
+
half_pi = math.pi / 2
|
|
352
|
+
for label in device_wires.labels:
|
|
353
|
+
self._state.u(label, -half_pi, -half.pi, half_pi)
|
|
354
|
+
elif opname == "PhaseShift":
|
|
355
|
+
half_par = par[0] / 2
|
|
356
|
+
for label in device_wires.labels:
|
|
357
|
+
self._state.u(label, 0, half_par, half_par)
|
|
358
|
+
elif opname == "PhaseShift.inv":
|
|
359
|
+
half_par = par[0] / 2
|
|
360
|
+
for label in device_wires.labels:
|
|
361
|
+
self._state.u(label, 0, -half_par, -half_par)
|
|
362
|
+
elif opname == "U3":
|
|
363
|
+
for label in device_wires.labels:
|
|
364
|
+
self._state.u(label, par[0], par[1], par[2])
|
|
365
|
+
elif opname == "U3.inv":
|
|
366
|
+
for label in device_wires.labels:
|
|
367
|
+
self._state.u(label, -par[0], -par[2], -par[1])
|
|
368
|
+
elif opname == "Rot":
|
|
369
|
+
for label in device_wires.labels:
|
|
370
|
+
self._state.r(Pauli.PauliZ, par[0], label)
|
|
371
|
+
self._state.r(Pauli.PauliY, par[1], label)
|
|
372
|
+
self._state.r(Pauli.PauliZ, par[2], label)
|
|
373
|
+
elif opname == "Rot.inv":
|
|
374
|
+
for label in device_wires.labels:
|
|
375
|
+
self._state.r(Pauli.PauliZ, -par[2], label)
|
|
376
|
+
self._state.r(Pauli.PauliY, -par[1], label)
|
|
377
|
+
self._state.r(Pauli.PauliZ, -par[0], label)
|
|
378
|
+
elif opname not in [
|
|
379
|
+
"Identity",
|
|
380
|
+
"Identity.inv",
|
|
381
|
+
"C(Identity)",
|
|
382
|
+
"C(Identity).inv",
|
|
383
|
+
]:
|
|
384
|
+
raise DeviceError(f"Operation {opname} is not supported on a {self.short_name} device.")
|
|
385
|
+
|
|
386
|
+
def analytic_probability(self, wires=None):
|
|
387
|
+
raise DeviceError(f"analytic_probability is not supported on a {self.short_name} device. (Specify a finite number of shots, instead.)")
|
|
388
|
+
|
|
389
|
+
def expval(self, observable, **kwargs):
|
|
390
|
+
if self.shots is None:
|
|
391
|
+
if isinstance(observable.name, list):
|
|
392
|
+
b = [self._observable_map[obs] for obs in observable.name]
|
|
393
|
+
elif observable.name == "Prod":
|
|
394
|
+
b = [self._observable_map[obs.name] for obs in observable.operands]
|
|
395
|
+
else:
|
|
396
|
+
b = [self._observable_map[observable.name]]
|
|
397
|
+
|
|
398
|
+
# exact expectation value
|
|
399
|
+
if callable(observable.eigvals):
|
|
400
|
+
eigvals = self._asarray(observable.eigvals(), dtype=self.R_DTYPE)
|
|
401
|
+
else: # older version of pennylane
|
|
402
|
+
eigvals = self._asarray(observable.eigvals, dtype=self.R_DTYPE)
|
|
403
|
+
prob = self.probability(wires=observable.wires)
|
|
404
|
+
return self._dot(eigvals, prob)
|
|
405
|
+
|
|
406
|
+
# estimate the ev
|
|
407
|
+
return np.mean(self.sample(observable))
|
|
408
|
+
|
|
409
|
+
def _generate_sample(self):
|
|
410
|
+
rev_sample = self._state.m_all()
|
|
411
|
+
sample = 0
|
|
412
|
+
for i in range(self.num_wires):
|
|
413
|
+
if (rev_sample & (1 << i)) > 0:
|
|
414
|
+
sample |= 1 << (self.num_wires - (i + 1))
|
|
415
|
+
return sample
|
|
416
|
+
|
|
417
|
+
def generate_samples(self):
|
|
418
|
+
if self.shots is None:
|
|
419
|
+
raise QuantumFunctionError(
|
|
420
|
+
"The number of shots has to be explicitly set on the device "
|
|
421
|
+
"when using sample-based measurements."
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
if self.noise != 0:
|
|
425
|
+
samples = []
|
|
426
|
+
for _ in range(self.shots):
|
|
427
|
+
self._state.reset_all()
|
|
428
|
+
self._apply()
|
|
429
|
+
samples.append(self._generate_sample())
|
|
430
|
+
self._samples = QubitDevice.states_to_binary(np.array(samples), self.num_wires)
|
|
431
|
+
self._circuit = []
|
|
432
|
+
|
|
433
|
+
return self._samples
|
|
434
|
+
|
|
435
|
+
if self.shots == 1:
|
|
436
|
+
self._samples = QubitDevice.states_to_binary(
|
|
437
|
+
np.array([self._generate_sample()]), self.num_wires
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
return self._samples
|
|
441
|
+
|
|
442
|
+
samples = np.array(
|
|
443
|
+
self._state.measure_shots(list(range(self.num_wires - 1, -1, -1)), self.shots)
|
|
444
|
+
)
|
|
445
|
+
self._samples = QubitDevice.states_to_binary(samples, self.num_wires)
|
|
446
|
+
|
|
447
|
+
return self._samples
|
|
448
|
+
|
|
449
|
+
def reset(self):
|
|
450
|
+
for i in range(self.num_wires):
|
|
451
|
+
if self._state.m(i):
|
|
452
|
+
self._state.x(i)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pennylane-qrack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.20.1
|
|
4
4
|
Summary: PennyLane plugin for Qrack.
|
|
5
5
|
Home-page: http://github.com/vm6502q
|
|
6
6
|
Maintainer: vm6502q
|
|
@@ -54,6 +54,7 @@ Features
|
|
|
54
54
|
|
|
55
55
|
* Provides access to a PyQrack simulator backend via the ``qrack.simulator`` device
|
|
56
56
|
* Provides access to a (C++) Qrack simulator backend for Catalyst (also) via the ``qrack.simulator`` device
|
|
57
|
+
* Provides access to a PyQrack simulator backend optimized for approximate NISQ-scale TFIM via the ``qrack.ace`` device
|
|
57
58
|
|
|
58
59
|
.. installation-start-inclusion-marker-do-not-remove
|
|
59
60
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
pennylane_qrack/QrackAceDeviceConfig.toml,sha256=aNZz65Ebnt_ncrPuGZh4WTBfqRSqTom0n97KqefMSF0,5590
|
|
2
|
+
pennylane_qrack/QrackDeviceConfig.toml,sha256=pk9Uo2-h9rPE22enIe9p3B4mO_XfamFf9YsmJ1VBYpA,4611
|
|
3
|
+
pennylane_qrack/__init__.py,sha256=5iuZ5OqhRPLxj5cs9jGaUTDv55iPXRVbcDHM6FNk-5c,689
|
|
4
|
+
pennylane_qrack/_version.py,sha256=WmutFKZg_7adOQAZWdm1835DIW5gKtwv3X9WN5Ss0aY,708
|
|
5
|
+
pennylane_qrack/qrack_ace_device.py,sha256=dAS3L07g5joEhBfI9lfHj-8Pz5rTGT1q9FkkUP9T4hA,17545
|
|
6
|
+
pennylane_qrack/qrack_device.cpp,sha256=EUfSydbidPUjnbK6KfOWUOVvtvM-B59JPJNHrYvtIpM,39004
|
|
7
|
+
pennylane_qrack/qrack_device.py,sha256=tu2QiTYqyg8yhdcgjYD5wgbWFS7WK5K9_oCutJrXITc,28973
|
|
8
|
+
pennylane_qrack-0.20.1.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
9
|
+
pennylane_qrack-0.20.1.dist-info/METADATA,sha256=2P975WwJDvaUv5JYo9WRb9T0x5MbDdYuImzhNxstdTU,5985
|
|
10
|
+
pennylane_qrack-0.20.1.dist-info/WHEEL,sha256=JMWfR_Dj7ISokcwe0cBhCfK6JKnIi-ZX11L6d_ntt6o,98
|
|
11
|
+
pennylane_qrack-0.20.1.dist-info/entry_points.txt,sha256=OrkJ6JVk-yndlQjqc-8dm8PxE-jNoNQRFXFeUBxVuCg,139
|
|
12
|
+
pennylane_qrack-0.20.1.dist-info/top_level.txt,sha256=5NFMNHqCHtVLwNkLg66xz846uUJAlnOJ5VGa6ulW1ow,16
|
|
13
|
+
pennylane_qrack-0.20.1.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
pennylane_qrack/QrackDeviceConfig.toml,sha256=M3rIJH9GlMJv6lapfSXses5qauSvezs8OqnHYLq6in0,5576
|
|
2
|
-
pennylane_qrack/__init__.py,sha256=5iuZ5OqhRPLxj5cs9jGaUTDv55iPXRVbcDHM6FNk-5c,689
|
|
3
|
-
pennylane_qrack/_version.py,sha256=noLa48ukVlqOH7jjp9r9WQx0-exX3iIi6k6S_efJbuY,708
|
|
4
|
-
pennylane_qrack/qrack_device.cpp,sha256=EUfSydbidPUjnbK6KfOWUOVvtvM-B59JPJNHrYvtIpM,39004
|
|
5
|
-
pennylane_qrack/qrack_device.py,sha256=tu2QiTYqyg8yhdcgjYD5wgbWFS7WK5K9_oCutJrXITc,28973
|
|
6
|
-
pennylane_qrack-0.19.0.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
7
|
-
pennylane_qrack-0.19.0.dist-info/METADATA,sha256=6Nu33e5Pqgv9TVFRyied_8WHQzk6BWwdod_1866m7nk,5864
|
|
8
|
-
pennylane_qrack-0.19.0.dist-info/WHEEL,sha256=JMWfR_Dj7ISokcwe0cBhCfK6JKnIi-ZX11L6d_ntt6o,98
|
|
9
|
-
pennylane_qrack-0.19.0.dist-info/entry_points.txt,sha256=V6f1sN6IZZZaEvxrI47A3K_kksp8fDUWjLWD0Met7Ww,79
|
|
10
|
-
pennylane_qrack-0.19.0.dist-info/top_level.txt,sha256=5NFMNHqCHtVLwNkLg66xz846uUJAlnOJ5VGa6ulW1ow,16
|
|
11
|
-
pennylane_qrack-0.19.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|