tequila-basic 1.9.11__tar.gz → 1.9.12__tar.gz
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.
- {tequila_basic-1.9.11/src/tequila_basic.egg-info → tequila_basic-1.9.12}/PKG-INFO +4 -3
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/README.md +1 -1
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/requirements.txt +3 -2
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/__init__.py +7 -2
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/krylov/krylov.py +41 -4
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/circuit.py +19 -48
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/compiler.py +126 -9
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/gates.py +5 -8
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/gradient.py +84 -4
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/postselection.py +40 -5
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/grouping/fermionic_functions.py +3 -3
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/objective/__init__.py +8 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/objective/objective.py +420 -42
- tequila_basic-1.9.12/src/tequila/objective/quantum_arg.py +39 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/optimizers/__init__.py +18 -3
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/optimizers/optimizer_base.py +5 -1
- tequila_basic-1.9.12/src/tequila/optimizers/optimizer_excsolve.py +142 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/quantumchemistry/chemistry_tools.py +81 -23
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/quantumchemistry/psi4_interface.py +2 -2
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/quantumchemistry/pyscf_interface.py +6 -6
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/quantumchemistry/qc_base.py +109 -82
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_api.py +86 -76
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_base.py +130 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_cudaq.py +16 -16
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_qiskit.py +29 -39
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_qulacs.py +119 -2
- tequila_basic-1.9.12/src/tequila/utils/objective_graph.py +1672 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/version.py +1 -1
- {tequila_basic-1.9.11 → tequila_basic-1.9.12/src/tequila_basic.egg-info}/PKG-INFO +4 -3
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila_basic.egg-info/SOURCES.txt +3 -1
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila_basic.egg-info/requires.txt +2 -1
- tequila_basic-1.9.12/tests/test_braket.py +524 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_chemistry.py +36 -38
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_circuit_unitary.py +3 -7
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_gates.py +13 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_recompilation_routines.py +51 -1
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_scipy.py +1 -45
- tequila_basic-1.9.11/src/tequila/objective/braket.py +0 -192
- tequila_basic-1.9.11/tests/test_braket.py +0 -274
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/LICENSE +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/MANIFEST.in +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/setup.cfg +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/setup.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/_unary_state_prep_impl.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/adapt/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/adapt/adapt.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/krylov/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/robustness/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/robustness/helpers.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/robustness/interval.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/apps/unary_state_prep.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/autograd_imports.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/_gates_impl.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/noise.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/pyzx.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/qasm.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/circuit/qpic.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/grouping/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/grouping/binary_rep.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/grouping/binary_utils.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/grouping/compile_groups.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/grouping/ev_utils.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/grouping/fermionic_methods.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/grouping/overlapping_methods.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/hamiltonian/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/hamiltonian/paulis.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/hamiltonian/paulistring.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/hamiltonian/qubit_hamiltonian.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/ml/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/ml/interface_torch.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/ml/ml_api.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/ml/utils_ml.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/objective/qtensor.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/optimizers/_containers.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/optimizers/optimizer_gd.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/optimizers/optimizer_gpyopt.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/optimizers/optimizer_scipy.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/quantumchemistry/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/quantumchemistry/encodings.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/quantumchemistry/madness_interface.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/quantumchemistry/orbital_optimizer.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_aqt.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_cirq.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_ddsim.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_mqp.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_pyquil.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_qibo.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_qiskit_gpu.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_qlm.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_qulacs_gpu.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_spex.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/simulator_symbolic.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/simulators/test_spex_simulator.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/tools/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/tools/convenience.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/tools/qng.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/tools/random_generators.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/utils/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/utils/bitstrings.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/utils/exceptions.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/utils/joined_transformation.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/utils/keymap.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/utils/misc.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/wavefunction/__init__.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/wavefunction/density_matrix.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila/wavefunction/qubit_wavefunction.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila_basic.egg-info/dependency_links.txt +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/src/tequila_basic.egg-info/top_level.txt +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_TrotErr.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_adapt.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_array.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_binary_pauli.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_binary_utils.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_bitstrings.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_chemistry_f12.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_chemistry_madness.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_circuits.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_fermionic_meas.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_gd_optimizer.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_gpyopt.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_gradient.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_hamiltonian_arithmetic.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_krylov.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_mappings.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_noise.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_noise_opt.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_objectives.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_postselection.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_pyzx.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_qasm.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_qtensor.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_simulator_backends.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_symbolic_simulator.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_torch_interface.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_unary_state_prep.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_variable.py +0 -0
- {tequila_basic-1.9.11 → tequila_basic-1.9.12}/tests/test_zzz_cleanup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tequila-basic
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.12
|
|
4
4
|
Summary: A High-Level Abstraction Framework for Quantum Algorithms
|
|
5
5
|
Home-page: https://github.com/tequilahub/tequila
|
|
6
6
|
Author: Tequila Developers
|
|
@@ -13,7 +13,8 @@ Requires-Dist: sympy
|
|
|
13
13
|
Requires-Dist: autograd
|
|
14
14
|
Requires-Dist: setuptools
|
|
15
15
|
Requires-Dist: pytest
|
|
16
|
-
Requires-Dist: openfermion
|
|
16
|
+
Requires-Dist: openfermion>=1.0
|
|
17
|
+
Requires-Dist: excitationsolve
|
|
17
18
|
Requires-Dist: dataclasses; python_version < "3.7"
|
|
18
19
|
Dynamic: author
|
|
19
20
|
Dynamic: author-email
|
|
@@ -45,7 +46,7 @@ Further sources:
|
|
|
45
46
|
- [talks and slides](https://kottmanj.github.io/talks_and_material/)
|
|
46
47
|
|
|
47
48
|
# Installation
|
|
48
|
-
Recommended Python version is 3.
|
|
49
|
+
Recommended Python version is 3.11 (3.10 or 3.12 shouldn't be a problem either).
|
|
49
50
|
Tequila supports linux, osx and windows. However, not all optional dependencies (especially chemistry) are supported on windows.
|
|
50
51
|
|
|
51
52
|
## Install from PyPi
|
|
@@ -18,7 +18,7 @@ Further sources:
|
|
|
18
18
|
- [talks and slides](https://kottmanj.github.io/talks_and_material/)
|
|
19
19
|
|
|
20
20
|
# Installation
|
|
21
|
-
Recommended Python version is 3.
|
|
21
|
+
Recommended Python version is 3.11 (3.10 or 3.12 shouldn't be a problem either).
|
|
22
22
|
Tequila supports linux, osx and windows. However, not all optional dependencies (especially chemistry) are supported on windows.
|
|
23
23
|
|
|
24
24
|
## Install from PyPi
|
|
@@ -7,9 +7,10 @@ sympy
|
|
|
7
7
|
autograd # autograd works better on OSX-ARM64 (M1 and M2) and Windows, feel free to try jax however (no big differences)
|
|
8
8
|
setuptools
|
|
9
9
|
pytest
|
|
10
|
-
openfermion
|
|
10
|
+
openfermion >= 1.0 # can not be smaller than 1.0
|
|
11
11
|
#cmake # needed by #qulacs, can be removed otherwise, now in #qulacs requirements
|
|
12
12
|
#qulacs # default simulator (best integration), remove if the installation gives you trouble and just install one of the other supported backend. Version restriction only for noise models, otherwise the new version is fine
|
|
13
|
+
excitationsolve
|
|
13
14
|
|
|
14
15
|
#optional quantum backends
|
|
15
16
|
#cirq >= 0.9.2 #
|
|
@@ -18,7 +19,6 @@ openfermion ~= 1.0 # can not be smaller than 1.0
|
|
|
18
19
|
#pyquil<3.0 # you also need to install the forest-sdk
|
|
19
20
|
##qulacs-gpu # you can't have #qulacs and #qulacs-gpu at the same time
|
|
20
21
|
#qibo <= 0.1.1 # can not be installed in the same environment as gpyopt
|
|
21
|
-
#quimb
|
|
22
22
|
#mqt.ddsim == 2.0.0b2 # requires qiskit < 2
|
|
23
23
|
|
|
24
24
|
#optional optimizers
|
|
@@ -28,3 +28,4 @@ openfermion ~= 1.0 # can not be smaller than 1.0
|
|
|
28
28
|
#pyzx
|
|
29
29
|
#pyscf # if used also restrict h5py version untill the issue is fixed upstream in pyscf
|
|
30
30
|
#h5py <= 3.1 # version 3.3.0 leads to crashes when pyscf is imported
|
|
31
|
+
#pygridsynth # used to compile Pauli rotations into Clifford + T gates
|
|
@@ -5,14 +5,19 @@ from tequila.objective import (
|
|
|
5
5
|
Objective,
|
|
6
6
|
VectorObjective,
|
|
7
7
|
ExpectationValue,
|
|
8
|
+
BraKet,
|
|
9
|
+
RealBraKet,
|
|
10
|
+
ImagBraKet,
|
|
8
11
|
Variable,
|
|
9
12
|
assign_variable,
|
|
10
13
|
format_variable_dictionary,
|
|
11
14
|
vectorize,
|
|
15
|
+
make_transition,
|
|
16
|
+
make_overlap,
|
|
17
|
+
Overlap,
|
|
18
|
+
Fidelity,
|
|
12
19
|
)
|
|
13
20
|
from tequila.objective import QTensor
|
|
14
|
-
from tequila.objective.braket import BraKet, make_transition, make_overlap, Overlap, Fidelity
|
|
15
|
-
|
|
16
21
|
from tequila.optimizers import INSTALLED_OPTIMIZERS, show_available_optimizers
|
|
17
22
|
from tequila.optimizers import minimize, minimize_scipy, minimize_gd, optimizer_scipy
|
|
18
23
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import scipy
|
|
3
|
-
from tequila import
|
|
3
|
+
from tequila import QTensor, simulate
|
|
4
|
+
from tequila.objective import BraKetImpl, RealBraKet
|
|
4
5
|
from tequila.hamiltonian.qubit_hamiltonian import QubitHamiltonian
|
|
5
6
|
|
|
6
7
|
|
|
@@ -37,13 +38,13 @@ def krylov_method(
|
|
|
37
38
|
for i in range(n_krylov_states):
|
|
38
39
|
for j in range(i, n_krylov_states):
|
|
39
40
|
if assume_real:
|
|
40
|
-
h_real =
|
|
41
|
+
h_real = BraKetImpl(bra=krylov_circs_x[i], ket=krylov_circs_x[j], operator=H).compile()[0]
|
|
41
42
|
h_im = 0
|
|
42
43
|
else:
|
|
43
|
-
h_real, h_im =
|
|
44
|
+
h_real, h_im = BraKetImpl(bra=krylov_circs_x[i], ket=krylov_circs_x[j], operator=H).compile()
|
|
44
45
|
HM[i, j] = h_real + 1j * h_im
|
|
45
46
|
HM[j, i] = h_real - 1j * h_im
|
|
46
|
-
s_real, s_im =
|
|
47
|
+
s_real, s_im = BraKetImpl(bra=krylov_circs_x[i], ket=krylov_circs_x[j]).compile()
|
|
47
48
|
SM[i, j] = s_real + 1j * s_im
|
|
48
49
|
SM[j, i] = s_real - 1j * s_im
|
|
49
50
|
|
|
@@ -53,3 +54,39 @@ def krylov_method(
|
|
|
53
54
|
v, vv = scipy.linalg.eigh(h, s)
|
|
54
55
|
|
|
55
56
|
return v, vv
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# Improved version
|
|
60
|
+
|
|
61
|
+
# def krylov_method(
|
|
62
|
+
# krylov_circs: list, H: QubitHamiltonian, variables: dict = None, assume_real: bool = False, *args, **kwargs
|
|
63
|
+
# ) -> tuple:
|
|
64
|
+
# n_krylov_states = len(krylov_circs)
|
|
65
|
+
|
|
66
|
+
# if variables is not None:
|
|
67
|
+
# krylov_circs_x = [U.map_variables(variables) for U in krylov_circs]
|
|
68
|
+
# else:
|
|
69
|
+
# krylov_circs_x = copy.deepcopy(krylov_circs)
|
|
70
|
+
|
|
71
|
+
# HM = numpy.zeros((n_krylov_states, n_krylov_states), dtype=complex)
|
|
72
|
+
# SM = numpy.zeros((n_krylov_states, n_krylov_states), dtype=complex)
|
|
73
|
+
|
|
74
|
+
# for i in range(n_krylov_states):
|
|
75
|
+
# for j in range(i, n_krylov_states):
|
|
76
|
+
# h_bk = BraKetImpl(bra=krylov_circs_x[i], ket=krylov_circs_x[j], operator=H)
|
|
77
|
+
# s_bk = BraKetImpl(bra=krylov_circs_x[i], ket=krylov_circs_x[j], operator=None)
|
|
78
|
+
|
|
79
|
+
# h_val = simulate(h_bk, *args, **kwargs)
|
|
80
|
+
# s_val = simulate(s_bk, *args, **kwargs)
|
|
81
|
+
|
|
82
|
+
# if assume_real:
|
|
83
|
+
# h_val = h_val.real
|
|
84
|
+
|
|
85
|
+
# HM[i, j] = h_val
|
|
86
|
+
# HM[j, i] = h_val.conjugate()
|
|
87
|
+
|
|
88
|
+
# SM[i, j] = s_val
|
|
89
|
+
# SM[j, i] = s_val.conjugate()
|
|
90
|
+
|
|
91
|
+
# v, vv = scipy.linalg.eigh(HM, SM)
|
|
92
|
+
# return v, vv
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
from tequila.circuit._gates_impl import QGateImpl, assign_variable, list_assignment, GlobalPhaseGateImpl, PhaseGateImpl
|
|
3
3
|
from tequila.utils.exceptions import TequilaException, TequilaWarning
|
|
4
|
-
from tequila.utils.bitstrings import BitNumbering
|
|
4
|
+
from tequila.utils.bitstrings import BitNumbering, reverse_int_bits
|
|
5
5
|
import typing
|
|
6
6
|
import copy
|
|
7
7
|
from collections import defaultdict
|
|
@@ -449,7 +449,7 @@ class QCircuit:
|
|
|
449
449
|
else:
|
|
450
450
|
return QCircuit(gates=[gate])
|
|
451
451
|
|
|
452
|
-
def to_matrix(self, variables=None):
|
|
452
|
+
def to_matrix(self, variables=None, numbering: BitNumbering = BitNumbering.MSB, backend: str = None):
|
|
453
453
|
"""
|
|
454
454
|
take the circuit and return the unitary matrix corresponding to it.
|
|
455
455
|
Parameters
|
|
@@ -464,60 +464,31 @@ class QCircuit:
|
|
|
464
464
|
np.ndarray:
|
|
465
465
|
the unitary matrix corresponding to the circuit.
|
|
466
466
|
"""
|
|
467
|
-
import
|
|
468
|
-
|
|
469
|
-
from tequila import compile_circuit
|
|
467
|
+
from tequila import format_variable_dictionary
|
|
468
|
+
from tequila.simulators.simulator_api import compile_circuit
|
|
470
469
|
|
|
471
|
-
|
|
470
|
+
variables = format_variable_dictionary(variables)
|
|
472
471
|
|
|
473
|
-
if
|
|
474
|
-
variables = {}
|
|
475
|
-
elif variables is None:
|
|
472
|
+
if variables is None and not (len(self.extract_variables()) == 0):
|
|
476
473
|
raise TequilaException(
|
|
477
|
-
|
|
474
|
+
"You called simulate for a parametrized type but forgot to pass down the variables: {}".format(
|
|
475
|
+
self.extract_variables()
|
|
476
|
+
)
|
|
478
477
|
)
|
|
479
478
|
|
|
480
|
-
|
|
481
|
-
self,
|
|
479
|
+
compiled = compile_circuit(
|
|
480
|
+
abstract_circuit=self,
|
|
481
|
+
variables=variables,
|
|
482
|
+
backend=backend,
|
|
482
483
|
)
|
|
483
|
-
compiled_circuit = compiled_circuit.map_variables(variables)
|
|
484
|
-
|
|
485
|
-
gate_mapping = {"Rx": "RX", "Ry": "RY", "Rz": "RZ", "H": "H", "X": "X"}
|
|
486
|
-
|
|
487
|
-
quimb_circuit = qtn.Circuit(self.n_qubits)
|
|
488
|
-
|
|
489
|
-
# quimb uses MSB convention, so we need to modify the qubit indices
|
|
490
|
-
# to LSB
|
|
491
|
-
for g in compiled_circuit.gates:
|
|
492
|
-
if g.name not in gate_mapping:
|
|
493
|
-
raise TequilaException(
|
|
494
|
-
f"Gate {g.name} is not supported for conversion to matrix. "
|
|
495
|
-
f"Supported gates: {list(gate_mapping.keys())}"
|
|
496
|
-
)
|
|
497
|
-
|
|
498
|
-
if g.is_parameterized():
|
|
499
|
-
quimb_circuit.apply_gate(
|
|
500
|
-
gate_mapping[g.name],
|
|
501
|
-
params=[float(g.parameter())],
|
|
502
|
-
qubits=[abs(t - self.n_qubits + 1) for t in list(g.target)],
|
|
503
|
-
parameterize=True,
|
|
504
|
-
)
|
|
505
|
-
elif g.is_controlled():
|
|
506
|
-
quimb_circuit.apply_gate(
|
|
507
|
-
gate_mapping[g.name],
|
|
508
|
-
qubits=[abs(t - self.n_qubits + 1) for t in list(g.target)],
|
|
509
|
-
controls=[abs(c - self.n_qubits + 1) for c in list(g.control)],
|
|
510
|
-
)
|
|
511
|
-
else:
|
|
512
|
-
quimb_circuit.apply_gate(
|
|
513
|
-
gate_mapping[g.name],
|
|
514
|
-
qubits=[abs(t - self.n_qubits + 1) for t in list(g.target)],
|
|
515
|
-
)
|
|
516
484
|
|
|
517
|
-
|
|
518
|
-
|
|
485
|
+
columns = []
|
|
486
|
+
for i in range(2**self.n_qubits):
|
|
487
|
+
initial_state = reverse_int_bits(i, nbits=self.n_qubits) if numbering == BitNumbering.LSB else i
|
|
488
|
+
output = compiled.simulate(variables=variables, initial_state=initial_state).to_array(numbering, copy=False)
|
|
489
|
+
columns.append(output)
|
|
519
490
|
|
|
520
|
-
return
|
|
491
|
+
return np.column_stack(columns)
|
|
521
492
|
|
|
522
493
|
def to_networkx(self):
|
|
523
494
|
"""
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import numbers
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
1
4
|
from tequila import TequilaException
|
|
2
5
|
from tequila.circuit.circuit import QCircuit
|
|
3
|
-
from tequila.circuit.gates import Rx, Ry, H, X, Rz, ExpPauli, CNOT, Phase, T, Z, GlobalPhase
|
|
6
|
+
from tequila.circuit.gates import Rx, Ry, H, X, S, Rz, ExpPauli, CNOT, Phase, T, Z, GlobalPhase
|
|
4
7
|
from tequila.circuit._gates_impl import (
|
|
5
8
|
RotationGateImpl,
|
|
6
9
|
PhaseGateImpl,
|
|
@@ -12,7 +15,7 @@ from tequila.circuit._gates_impl import (
|
|
|
12
15
|
from tequila.utils import to_float
|
|
13
16
|
from tequila.objective.objective import Variable, FixedVariable
|
|
14
17
|
from tequila.objective.objective import Objective
|
|
15
|
-
from tequila.objective.objective import ExpectationValueImpl
|
|
18
|
+
from tequila.objective.objective import BraKetImpl, ExpectationValueImpl
|
|
16
19
|
import numpy
|
|
17
20
|
from numpy import pi as pi
|
|
18
21
|
|
|
@@ -70,6 +73,7 @@ class CircuitCompiler:
|
|
|
70
73
|
c.gradient_mode = False
|
|
71
74
|
c.y_gate = False
|
|
72
75
|
c.ry_gate = False
|
|
76
|
+
c.pauli_rotations = False
|
|
73
77
|
|
|
74
78
|
for k, v in kwargs.items():
|
|
75
79
|
if k in c.__dict__:
|
|
@@ -79,6 +83,13 @@ class CircuitCompiler:
|
|
|
79
83
|
c.cc_max = False
|
|
80
84
|
return c
|
|
81
85
|
|
|
86
|
+
@classmethod
|
|
87
|
+
def error_correctable_gate_set(cls, epsilon, *args, **kwargs):
|
|
88
|
+
c = cls.all_flags_true(args, kwargs)
|
|
89
|
+
c.pauli_rotations = True
|
|
90
|
+
c.epsilon = epsilon
|
|
91
|
+
return c
|
|
92
|
+
|
|
82
93
|
def __init__(
|
|
83
94
|
self,
|
|
84
95
|
multitarget=False,
|
|
@@ -102,9 +113,10 @@ class CircuitCompiler:
|
|
|
102
113
|
y_gate=False,
|
|
103
114
|
ch_gate=False,
|
|
104
115
|
hadamard=False,
|
|
116
|
+
pauli_rotations=False,
|
|
117
|
+
epsilon=1e-6,
|
|
105
118
|
):
|
|
106
119
|
"""
|
|
107
|
-
all parameters are booleans.
|
|
108
120
|
Parameters
|
|
109
121
|
----------
|
|
110
122
|
multitarget:
|
|
@@ -145,6 +157,11 @@ class CircuitCompiler:
|
|
|
145
157
|
whether or not to break down all y gates
|
|
146
158
|
ch_gate:
|
|
147
159
|
whether or not to break down all controlled-H gates
|
|
160
|
+
pauli_rotations:
|
|
161
|
+
whether or not to approximate rotations with Clifford and T gates
|
|
162
|
+
epsilon:
|
|
163
|
+
The maximum absolute error when compilations are not exact.
|
|
164
|
+
Currently only applies to the rotations compilation.
|
|
148
165
|
"""
|
|
149
166
|
self.multitarget = multitarget
|
|
150
167
|
self.multicontrol = multicontrol
|
|
@@ -167,6 +184,8 @@ class CircuitCompiler:
|
|
|
167
184
|
self.ry_gate = ry_gate
|
|
168
185
|
self.y_gate = y_gate
|
|
169
186
|
self.ch_gate = ch_gate
|
|
187
|
+
self.pauli_rotations = pauli_rotations
|
|
188
|
+
self.epsilon = epsilon
|
|
170
189
|
|
|
171
190
|
def __call__(
|
|
172
191
|
self, objective: typing.Union[Objective, QCircuit, ExpectationValueImpl], variables=None, *args, **kwargs
|
|
@@ -249,7 +268,21 @@ class CircuitCompiler:
|
|
|
249
268
|
the arg, compiled
|
|
250
269
|
"""
|
|
251
270
|
|
|
252
|
-
if isinstance(arg,
|
|
271
|
+
if isinstance(arg, BraKetImpl):
|
|
272
|
+
# a braket has U and H as well, but its U is only the ket: compiling it like an
|
|
273
|
+
# expectation value below would silently drop the bra
|
|
274
|
+
ket = self.compile_circuit(abstract_circuit=arg.ket, *args, **kwargs)
|
|
275
|
+
return BraKetImpl(
|
|
276
|
+
ket=ket,
|
|
277
|
+
bra=ket if arg.bra is arg.ket else self.compile_circuit(abstract_circuit=arg.bra, *args, **kwargs),
|
|
278
|
+
operator=arg.operator,
|
|
279
|
+
contraction=arg._contraction,
|
|
280
|
+
shape=arg._shape,
|
|
281
|
+
samples=arg.samples,
|
|
282
|
+
*arg._args,
|
|
283
|
+
**arg._kwargs,
|
|
284
|
+
)
|
|
285
|
+
elif isinstance(arg, ExpectationValueImpl) or (hasattr(arg, "U") and hasattr(arg, "H")):
|
|
253
286
|
return ExpectationValueImpl(H=arg.H, U=self.compile_circuit(abstract_circuit=arg.U, *args, **kwargs))
|
|
254
287
|
elif hasattr(arg, "abstract_expectationvalue"):
|
|
255
288
|
E = arg.abstract_expectationvalue
|
|
@@ -296,6 +329,9 @@ class CircuitCompiler:
|
|
|
296
329
|
|
|
297
330
|
compiled_gates = []
|
|
298
331
|
|
|
332
|
+
# Keep a dicitionary of compiled pauli_rotations
|
|
333
|
+
pauli_dict = {}
|
|
334
|
+
|
|
299
335
|
for idx, gate in gatelist:
|
|
300
336
|
cg = gate
|
|
301
337
|
controlled = gate.is_controlled()
|
|
@@ -333,6 +369,10 @@ class CircuitCompiler:
|
|
|
333
369
|
if self.ry_gate:
|
|
334
370
|
cg = compile_ry(gate=cg, controlled_rotation=self.controlled_rotation)
|
|
335
371
|
if controlled:
|
|
372
|
+
if self.toffoli:
|
|
373
|
+
cg = compile_toffoli(gate=cg)
|
|
374
|
+
if self.phase:
|
|
375
|
+
cg = compile_phase(gate=cg)
|
|
336
376
|
if self.cc_max or self.multicontrol:
|
|
337
377
|
cg = compile_to_single_control(gate=cg)
|
|
338
378
|
if self.controlled_exponential_pauli:
|
|
@@ -343,12 +383,10 @@ class CircuitCompiler:
|
|
|
343
383
|
cg = compile_controlled_phase(gate=cg)
|
|
344
384
|
if self.phase:
|
|
345
385
|
cg = compile_phase(gate=cg)
|
|
346
|
-
if self.toffoli:
|
|
347
|
-
cg = compile_toffoli(gate=cg)
|
|
348
|
-
if self.phase:
|
|
349
|
-
cg = compile_phase(gate=cg)
|
|
350
386
|
if self.controlled_rotation:
|
|
351
387
|
cg = compile_controlled_rotation(gate=cg)
|
|
388
|
+
if self.pauli_rotations:
|
|
389
|
+
cg = compile_pauli_rotations(gate=cg, epsilon=self.epsilon, pauli_dict=pauli_dict)
|
|
352
390
|
|
|
353
391
|
compiled_gates.append((idx, cg))
|
|
354
392
|
|
|
@@ -586,7 +624,7 @@ def compile_toffoli(gate) -> QCircuit:
|
|
|
586
624
|
A QCircuit; the result of compilation.
|
|
587
625
|
"""
|
|
588
626
|
|
|
589
|
-
if gate.name.lower
|
|
627
|
+
if not (gate.name.lower() == "x" and len(gate.control) == 2):
|
|
590
628
|
return QCircuit.wrap_gate(gate)
|
|
591
629
|
control = gate.control
|
|
592
630
|
c1 = control[1]
|
|
@@ -1039,3 +1077,82 @@ def compile_ch(gate: QGateImpl) -> QCircuit:
|
|
|
1039
1077
|
)
|
|
1040
1078
|
else:
|
|
1041
1079
|
return QCircuit.wrap_gate(gate)
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
@compiler
|
|
1083
|
+
def compile_pauli_rotations(gate: QGateImpl, epsilon: float, pauli_dict: dict) -> QCircuit:
|
|
1084
|
+
"""
|
|
1085
|
+
Compile uncontrolled Pauli rotations gates into Clifford + T gates.
|
|
1086
|
+
|
|
1087
|
+
Parameters
|
|
1088
|
+
----------
|
|
1089
|
+
gate:
|
|
1090
|
+
the gate.
|
|
1091
|
+
epsilon:
|
|
1092
|
+
the maximum absolute error of the compilation.
|
|
1093
|
+
|
|
1094
|
+
Returns
|
|
1095
|
+
-------
|
|
1096
|
+
QCircuit, the result of compilation.
|
|
1097
|
+
"""
|
|
1098
|
+
from pygridsynth import gridsynth_gates
|
|
1099
|
+
|
|
1100
|
+
# In principle, we could compile controlled Pauli rotations with the same method by making all
|
|
1101
|
+
# the resulting gates controlled, but then this compilation makes no sense, since its point is
|
|
1102
|
+
# to compile to a Clifford + T gateset. Compiling controlled rotations to uncontrolled ones
|
|
1103
|
+
# should be handled by other compiler passes.
|
|
1104
|
+
if gate.name.lower() in ["rx", "ry", "rz"] and not gate.is_controlled():
|
|
1105
|
+
if not isinstance(gate.parameter, numbers.Number):
|
|
1106
|
+
raise TequilaCompilerException("Can't compile parametrized rotations to Clifford + T gates")
|
|
1107
|
+
|
|
1108
|
+
# Compute bucket by rounding to the next multiple of epsilon
|
|
1109
|
+
bucket = int(numpy.round(gate.parameter / (2 * epsilon)))
|
|
1110
|
+
rounded_parameter = bucket * (2 * epsilon)
|
|
1111
|
+
if bucket in pauli_dict:
|
|
1112
|
+
result = pauli_dict[bucket]
|
|
1113
|
+
elif bucket == 0:
|
|
1114
|
+
result = QCircuit()
|
|
1115
|
+
else:
|
|
1116
|
+
with warnings.catch_warnings():
|
|
1117
|
+
# Silence warning about using floats
|
|
1118
|
+
warnings.simplefilter(action="ignore", category=UserWarning, lineno=362)
|
|
1119
|
+
gates = gridsynth_gates(theta=rounded_parameter, epsilon=epsilon, up_to_phase=True)
|
|
1120
|
+
|
|
1121
|
+
result = QCircuit()
|
|
1122
|
+
v = numpy.array([1, 0], dtype=complex)
|
|
1123
|
+
H_mat = numpy.array([[1, 1], [1, -1]]) / numpy.sqrt(2)
|
|
1124
|
+
T_val = numpy.exp(pi / 4 * 1j)
|
|
1125
|
+
for g in reversed(gates):
|
|
1126
|
+
match g:
|
|
1127
|
+
case "X":
|
|
1128
|
+
result += X(target=0)
|
|
1129
|
+
v = v[::-1]
|
|
1130
|
+
case "H":
|
|
1131
|
+
result += H(target=0)
|
|
1132
|
+
v = H_mat @ v
|
|
1133
|
+
case "S":
|
|
1134
|
+
result += S(target=0)
|
|
1135
|
+
v[1] *= 1j
|
|
1136
|
+
case "T":
|
|
1137
|
+
result += T(target=0)
|
|
1138
|
+
v[1] *= T_val
|
|
1139
|
+
case c:
|
|
1140
|
+
raise ValueError(f"Got unexpected gate {c}")
|
|
1141
|
+
|
|
1142
|
+
global_phase = -rounded_parameter / 2 - numpy.angle(v[0])
|
|
1143
|
+
result += GlobalPhase(angle=global_phase)
|
|
1144
|
+
pauli_dict[bucket] = result
|
|
1145
|
+
|
|
1146
|
+
result = result.map_qubits({0: gate.target[0]})
|
|
1147
|
+
|
|
1148
|
+
if gate.name.lower() in ["rx", "ry"]:
|
|
1149
|
+
result = H(target=gate.target) + result + H(target=gate.target)
|
|
1150
|
+
|
|
1151
|
+
if gate.name.lower() == "ry":
|
|
1152
|
+
result = (
|
|
1153
|
+
S(target=gate.target) + S(target=gate.target) + S(target=gate.target) + result + S(target=gate.target)
|
|
1154
|
+
)
|
|
1155
|
+
|
|
1156
|
+
return result
|
|
1157
|
+
else:
|
|
1158
|
+
return QCircuit.wrap_gate(gate)
|
|
@@ -85,19 +85,16 @@ def Phase(
|
|
|
85
85
|
return QCircuit.wrap_gate(gates)
|
|
86
86
|
|
|
87
87
|
|
|
88
|
-
def I(
|
|
89
|
-
target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs
|
|
90
|
-
) -> QCircuit:
|
|
88
|
+
def I(target: typing.Union[list, int], control: typing.Union[list, int] = None, *args, **kwargs) -> QCircuit:
|
|
91
89
|
"""
|
|
92
90
|
A gate that has no effect, but can be used to mark a qubit as being used.
|
|
93
91
|
This can for example be useful if a qubit is only being used in some variants
|
|
94
92
|
of a circuit, but you want to prevent the output format from changing.
|
|
95
93
|
"""
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
)
|
|
94
|
+
target = list_assignment(target)
|
|
95
|
+
control = list_assignment(control) if control is not None else None
|
|
96
|
+
gates = [impl.QGateImpl(name="I", target=q, control=control) for q in target]
|
|
97
|
+
return QCircuit.wrap_gate(gates)
|
|
101
98
|
|
|
102
99
|
|
|
103
100
|
def S(target: typing.Union[list, int], control: typing.Union[list, int] = None) -> QCircuit:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from tequila.circuit.compiler import CircuitCompiler
|
|
2
2
|
from tequila.objective.objective import (
|
|
3
3
|
Objective,
|
|
4
|
+
BraKetImpl,
|
|
4
5
|
ExpectationValueImpl,
|
|
5
6
|
Variable,
|
|
6
7
|
assign_variable,
|
|
@@ -11,8 +12,10 @@ from tequila import TequilaException
|
|
|
11
12
|
from tequila.objective import QTensor
|
|
12
13
|
from tequila.simulators.simulator_api import compile
|
|
13
14
|
import typing
|
|
14
|
-
from numpy import vectorize
|
|
15
|
+
from numpy import vectorize, isclose
|
|
16
|
+
from copy import deepcopy
|
|
15
17
|
from tequila.autograd_imports import jax, __AUTOGRAD__BACKEND__
|
|
18
|
+
from tequila.circuit._gates_impl import DifferentiableGateImpl
|
|
16
19
|
|
|
17
20
|
|
|
18
21
|
def grad(objective: typing.Union[Objective, QTensor], variable: Variable = None, no_compile=False, *args, **kwargs):
|
|
@@ -78,7 +81,9 @@ def grad(objective: typing.Union[Objective, QTensor], variable: Variable = None,
|
|
|
78
81
|
|
|
79
82
|
if isinstance(objective, ExpectationValueImpl):
|
|
80
83
|
return __grad_expectationvalue(E=objective, variable=variable)
|
|
81
|
-
elif objective.is_expectationvalue():
|
|
84
|
+
elif objective.is_expectationvalue() and not isinstance(compiled.args[-1], BraKetImpl):
|
|
85
|
+
# is_expectationvalue() only tests for a quantum argument, and a braket is not an
|
|
86
|
+
# expectation value: let it fall through to __grad_objective/__grad_inner
|
|
82
87
|
return __grad_expectationvalue(E=compiled.args[-1], variable=variable)
|
|
83
88
|
elif isinstance(compiled, Objective) or (hasattr(compiled, "args") and hasattr(compiled, "transformation")):
|
|
84
89
|
return __grad_objective(objective=compiled, variable=variable)
|
|
@@ -91,12 +96,20 @@ def __grad_objective(objective: Objective, variable: Variable):
|
|
|
91
96
|
transformation = objective.transformation
|
|
92
97
|
dO = None
|
|
93
98
|
|
|
99
|
+
# an objective holding a braket is complex valued, and the plain autograd gradient only
|
|
100
|
+
# accepts real output. the arithmetic combining the arguments (sums, products, quotients)
|
|
101
|
+
# is holomorphic, so the outer derivative is well defined and just has to be asked for
|
|
102
|
+
holomorphic = any(isinstance(arg, BraKetImpl) for arg in args)
|
|
103
|
+
|
|
94
104
|
processed_expectationvalues = {}
|
|
95
105
|
for i, arg in enumerate(args):
|
|
96
106
|
if __AUTOGRAD__BACKEND__ == "jax":
|
|
97
|
-
df = jax.grad(transformation, argnums=i)
|
|
107
|
+
df = jax.grad(transformation, argnums=i, holomorphic=holomorphic)
|
|
98
108
|
elif __AUTOGRAD__BACKEND__ == "autograd":
|
|
99
|
-
|
|
109
|
+
if holomorphic:
|
|
110
|
+
df = jax.holomorphic_grad(transformation, i)
|
|
111
|
+
else:
|
|
112
|
+
df = jax.grad(transformation, argnum=i)
|
|
100
113
|
else:
|
|
101
114
|
raise TequilaException("Can't differentiate without autograd or jax")
|
|
102
115
|
|
|
@@ -206,6 +219,10 @@ def __grad_inner(arg, variable):
|
|
|
206
219
|
E = arg.abstract_expectationvalue
|
|
207
220
|
dE = __grad_expectationvalue(E, variable=variable)
|
|
208
221
|
return compile(dE, **arg._input_args)
|
|
222
|
+
elif isinstance(arg, BraKetImpl):
|
|
223
|
+
# real, imaginary = arg.compile()
|
|
224
|
+
# return grad(real, variable) + 1.0j * grad(imaginary, variable)
|
|
225
|
+
return __grad_braKet(objective=arg, variable=variable)
|
|
209
226
|
elif hasattr(arg, "grad"):
|
|
210
227
|
return arg.grad(variable)
|
|
211
228
|
else:
|
|
@@ -267,3 +284,66 @@ def __grad_shift_rule(unitary, g, i, variable, hamiltonian):
|
|
|
267
284
|
return dOinc
|
|
268
285
|
else:
|
|
269
286
|
raise TequilaException("No shift found for gate {}\nWas the compiler called?".format(g))
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def __grad_braKet(objective: BraKetImpl, variable: Variable = None) -> Objective:
|
|
290
|
+
r"""
|
|
291
|
+
Gradient of <bra|H|ket> by differentiating the amplitudes of bra and ket directly,
|
|
292
|
+
instead of differentiating the Hadamard tests that BraKetImpl.compile() produces.
|
|
293
|
+
Every term of the result is again a BraKetImpl with one gate of bra or ket modified.
|
|
294
|
+
:param objective: the BraKetImpl to differentiate
|
|
295
|
+
:param variable: the variable to differentiate with respect to. None gives a dict with all of them
|
|
296
|
+
:return: an Objective (or dict of Objectives) whose simulation gives the gradient
|
|
297
|
+
"""
|
|
298
|
+
# <U|U> = 1 does not depend on anything
|
|
299
|
+
if variable not in objective.extract_variables() or objective.is_self_overlap:
|
|
300
|
+
return Objective()
|
|
301
|
+
if objective.is_diagonal:
|
|
302
|
+
return __grad_expectationvalue(objective, variable)
|
|
303
|
+
|
|
304
|
+
if not (objective.bra.verify()):
|
|
305
|
+
raise TequilaException("error in grad_braket unitary is {}".format(objective.bra))
|
|
306
|
+
if not (objective.ket.verify()):
|
|
307
|
+
raise TequilaException("error in grad_braket unitary is {}".format(objective.ket))
|
|
308
|
+
|
|
309
|
+
def make_braket(bra, ket):
|
|
310
|
+
return Objective(
|
|
311
|
+
args=[
|
|
312
|
+
BraKetImpl(
|
|
313
|
+
ket=ket,
|
|
314
|
+
bra=bra,
|
|
315
|
+
operator=objective.operator,
|
|
316
|
+
contraction=objective._contraction,
|
|
317
|
+
shape=objective._shape,
|
|
318
|
+
samples=objective.samples,
|
|
319
|
+
*objective._args,
|
|
320
|
+
**objective._kwargs,
|
|
321
|
+
)
|
|
322
|
+
]
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
dO = Objective()
|
|
326
|
+
for is_bra, U in [(False, deepcopy(objective.ket)), (True, deepcopy(objective.bra))]:
|
|
327
|
+
for i, g in U._parameter_map.get(variable, []):
|
|
328
|
+
if hasattr(g, "shifted_gates"):
|
|
329
|
+
g = deepcopy(g)
|
|
330
|
+
if not g.is_controlled() and type(g).shifted_gates is DifferentiableGateImpl.shifted_gates:
|
|
331
|
+
shifted = g.shifted_gates(r=g.eigenvalues_magnitude / 2)
|
|
332
|
+
else:
|
|
333
|
+
shifted = g.shifted_gates()
|
|
334
|
+
g.assume_real = False
|
|
335
|
+
inner = __grad_inner(g.parameter, variable)
|
|
336
|
+
if isinstance(inner, float) and isclose(inner, 0, atol=1.0e-6):
|
|
337
|
+
continue
|
|
338
|
+
for x in shifted:
|
|
339
|
+
w, g = x
|
|
340
|
+
Ux = U.replace_gates(positions=[i], circuits=[g])
|
|
341
|
+
if is_bra:
|
|
342
|
+
# the bra enters complex conjugated
|
|
343
|
+
dO += w.conjugate() * inner * make_braket(bra=Ux, ket=objective.ket)
|
|
344
|
+
else:
|
|
345
|
+
dO += w * inner * make_braket(bra=objective.bra, ket=Ux)
|
|
346
|
+
else:
|
|
347
|
+
raise TequilaException("No shift found for gate {}\nWas the compiler called?".format(g))
|
|
348
|
+
assert dO is not None
|
|
349
|
+
return dO
|