Skip to content

Commit 778bc5c

Browse files
committed
Merge branch 'master' into fidelity
2 parents aa56f22 + a0c9226 commit 778bc5c

File tree

2 files changed

+46
-42
lines changed

2 files changed

+46
-42
lines changed

src/qibo/gates/abstract.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,16 @@ def from_dict(raw: dict):
151151
if raw["measurement_result"]["samples"] is not None:
152152
gate.result.register_samples(raw["measurement_result"]["samples"])
153153
return gate
154-
try:
155-
return gate.controlled_by(*raw["_control_qubits"])
156-
except RuntimeError as e:
157-
if "controlled" in e.args[0]:
158-
return gate
159-
raise e
154+
155+
if gate.name not in GATES_CONTROLLED_BY_DEFAULT:
156+
try:
157+
return gate.controlled_by(*raw["_control_qubits"])
158+
except RuntimeError as e: # pragma: no cover
159+
if "controlled" in e.args[0]:
160+
return gate
161+
raise e
162+
163+
return gate
160164

161165
def to_json(self):
162166
"""Dump gate to JSON.

src/qibo/hamiltonians/hamiltonians.py

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
"""Module defining Hamiltonian classes."""
22

3-
import operator
43
from functools import cache, cached_property, reduce
54
from itertools import chain
6-
from logging import warn
7-
from typing import Dict, List, Optional, Tuple
5+
from operator import add, sub
6+
from typing import Dict, List, Optional, Tuple, Union
87

98
import numpy as np
109
import sympy
10+
from numpy.typing import ArrayLike
1111

1212
from qibo.backends import Backend, _check_backend
1313
from qibo.config import log, raise_error
1414
from qibo.hamiltonians.abstract import AbstractHamiltonian
1515
from qibo.hamiltonians.terms import SymbolicTerm
16-
from qibo.symbols import PauliSymbol, Symbol, Z
16+
from qibo.symbols import PauliSymbol, Symbol
1717

1818

1919
class Hamiltonian(AbstractHamiltonian):
2020
"""Hamiltonian based on a dense or sparse matrix representation.
2121
2222
Args:
2323
nqubits (int): number of quantum bits.
24-
matrix (ndarray): Matrix representation of the Hamiltonian in the
24+
matrix (ArrayLike): Matrix representation of the Hamiltonian in the
2525
computational basis as an array of shape :math:`2^{n} \\times 2^{n}`.
2626
Sparse matrices based on ``scipy.sparse`` for ``numpy`` / ``qibojit`` backends
2727
(or on ``tf.sparse`` for the ``tensorflow`` backend) are also supported.
@@ -30,11 +30,9 @@ class Hamiltonian(AbstractHamiltonian):
3030
Defaults to ``None``.
3131
"""
3232

33-
def __init__(self, nqubits, matrix, backend=None):
34-
from qibo.backends import ( # pylint: disable=import-outside-toplevel
35-
_check_backend,
36-
)
37-
33+
def __init__(
34+
self, nqubits: int, matrix: ArrayLike, backend: Optional[Backend] = None
35+
):
3836
self._backend = _check_backend(backend)
3937

4038
if not (
@@ -55,7 +53,7 @@ def __init__(self, nqubits, matrix, backend=None):
5553
self._exp = {"a": None, "result": None}
5654

5755
@property
58-
def matrix(self):
56+
def matrix(self) -> ArrayLike:
5957
"""Returns the full matrix representation.
6058
6159
For :math:`n` qubits, can be a dense :math:`2^{n} \\times 2^{n}` array or a sparse
@@ -64,7 +62,7 @@ def matrix(self):
6462
return self._matrix
6563

6664
@matrix.setter
67-
def matrix(self, mat):
65+
def matrix(self, mat: ArrayLike) -> None:
6866
shape = tuple(mat.shape)
6967
if shape != 2 * (2**self.nqubits,):
7068
raise_error(
@@ -75,27 +73,27 @@ def matrix(self, mat):
7573
self._matrix = mat
7674

7775
@property
78-
def backend(self):
76+
def backend(self) -> Backend:
7977
return self._backend
8078

8179
@backend.setter
82-
def backend(self, new_backend: Backend):
80+
def backend(self, new_backend: Backend) -> None:
8381
self._backend = new_backend
8482
self._matrix = new_backend.cast(self._matrix, new_backend.dtype)
8583

86-
def eigenvalues(self, k=6):
84+
def eigenvalues(self, k: int = 6) -> ArrayLike:
8785
if self._eigenvalues is None:
8886
self._eigenvalues = self.backend.eigenvalues(self.matrix, k=k)
8987
return self._eigenvalues
9088

91-
def eigenvectors(self, k=6):
89+
def eigenvectors(self, k: int = 6) -> ArrayLike:
9290
if self._eigenvectors is None:
9391
self._eigenvalues, self._eigenvectors = self.backend.eigenvectors(
9492
self.matrix, k=k
9593
)
9694
return self._eigenvectors
9795

98-
def exp(self, a):
96+
def exp(self, a: ArrayLike) -> ArrayLike:
9997
if self._exp.get("a") != a:
10098
self._exp["a"] = a
10199
self._exp["result"] = self.backend.matrix_exp(
@@ -106,7 +104,9 @@ def exp(self, a):
106104
)
107105
return self._exp.get("result")
108106

109-
def expectation(self, circuit, nshots=None, qubit_map=None):
107+
def expectation(
108+
self, circuit, nshots: int = None, qubit_map: Optional[dict] = None
109+
) -> float:
110110
"""Computes the expectation value for a given circuit. This works only for diagonal
111111
observables if ``nshots != None``.
112112
@@ -121,7 +121,7 @@ def expectation(self, circuit, nshots=None, qubit_map=None):
121121
float: The expectation value.
122122
"""
123123
if not circuit.__class__.__name__ == "Circuit": # pragma: no cover
124-
warn(
124+
log.warning(
125125
"Calculation of expectation values starting from the state is deprecated, "
126126
+ "use the ``expectation_from_state`` method if you really need it, "
127127
+ "or simply pass the circuit you want to calculate the expectation value from."
@@ -143,7 +143,7 @@ def expectation_from_samples(
143143
self,
144144
frequencies: Dict[str | int, int],
145145
qubit_map: Optional[Tuple[int, ...]] = None,
146-
):
146+
) -> float:
147147
"""Compute the expectation value starting from some samples, works only for diagonal
148148
observables.
149149
@@ -167,7 +167,7 @@ def frequencies(self):
167167
circuit, self.matrix, self.nqubits, nshots=1, qubit_map=qubit_map
168168
)
169169

170-
def energy_fluctuation(self, circuit):
170+
def energy_fluctuation(self, circuit) -> float:
171171
"""
172172
Evaluate energy fluctuation:
173173
@@ -368,15 +368,15 @@ def __init__(
368368
)
369369
self._matrix = None
370370

371-
def __repr__(self):
371+
def __repr__(self) -> str:
372372
return str(self.form)
373373

374374
@property
375-
def backend(self):
375+
def backend(self) -> Backend:
376376
return self._backend
377377

378378
@backend.setter
379-
def backend(self, new_backend: Backend):
379+
def backend(self, new_backend: Backend) -> None:
380380
self._backend = new_backend
381381
if self._matrix is not None:
382382
self._matrix = new_backend.cast(self._matrix, new_backend.dtype)
@@ -402,7 +402,7 @@ def form(self, form):
402402
self.nqubits = _calculate_nqubits_from_form(form)
403403

404404
@cached_property
405-
def terms(self):
405+
def terms(self) -> list:
406406
"""List of terms of which the Hamiltonian is a sum of.
407407
408408
Terms will be objects of type :class:`qibo.core.terms.HamiltonianTerm`.
@@ -500,7 +500,7 @@ def diagonal_simple_terms(
500500
return terms_coefficients, terms_observables, terms_qubits
501501

502502
@property
503-
def matrix(self):
503+
def matrix(self) -> ArrayLike:
504504
"""Returns the full matrix representation.
505505
506506
Consisting of :math:`2^{n} \\times 2^{n}`` elements.
@@ -509,16 +509,16 @@ def matrix(self):
509509
self._matrix = self._get_symbol_matrix(self.form)
510510
return self._matrix
511511

512-
def eigenvalues(self, k=6):
512+
def eigenvalues(self, k: int = 6) -> ArrayLike:
513513
return self.dense.eigenvalues(k)
514514

515-
def eigenvectors(self, k=6):
515+
def eigenvectors(self, k: int = 6) -> ArrayLike:
516516
return self.dense.eigenvectors(k)
517517

518-
def ground_state(self):
518+
def ground_state(self) -> ArrayLike:
519519
return self.eigenvectors()[:, 0]
520520

521-
def exp(self, a):
521+
def exp(self, a: ArrayLike) -> ArrayLike:
522522
return self.dense.exp(a)
523523

524524
@cache
@@ -617,7 +617,7 @@ def expectation(self, circuit: "Circuit", nshots: Optional[int] = None) -> float
617617
float: The expectation value.
618618
"""
619619
if not circuit.__class__.__name__ == "Circuit": # pragma: no cover
620-
warn(
620+
log.warning(
621621
"Calculation of expectation values starting from the state is deprecated, "
622622
+ "use the ``expectation_from_state`` method if you really need it, "
623623
+ "or simply pass the circuit you want to calculate the expectation value from."
@@ -650,7 +650,7 @@ def expectation_from_samples(
650650
self,
651651
frequencies: Dict[str | int, int],
652652
qubit_map: Optional[Tuple[int, ...]] = None,
653-
):
653+
) -> float:
654654
"""Compute the expectation value starting from some samples, works only for diagonal
655655
observables.
656656
@@ -717,18 +717,18 @@ def _compose(self, other, operator):
717717
return self.__class__(form=form, nqubits=self.nqubits, backend=self.backend)
718718

719719
def __add__(self, other):
720-
return self._compose(other, operator.add)
720+
return self._compose(other, add)
721721

722722
def __sub__(self, other):
723-
return self._compose(other, operator.sub)
723+
return self._compose(other, sub)
724724

725725
def __rsub__(self, other):
726726
return self._compose(other, lambda x, y: y - x)
727727

728728
def __mul__(self, other):
729729
return self._compose(other, lambda x, y: y * x)
730730

731-
def apply_gates(self, state, density_matrix=False):
731+
def apply_gates(self, state: ArrayLike, density_matrix: bool = False):
732732
"""Applies gates corresponding to the Hamiltonian terms.
733733
734734
Gates are applied to the given state.
@@ -779,7 +779,7 @@ def __matmul__(self, other):
779779

780780
return self.apply_gates(other, density_matrix=True)
781781

782-
def circuit(self, dt, accelerators=None):
782+
def circuit(self, dt: Union[float, int], accelerators: Optional[dict] = None):
783783
"""Circuit that implements a Trotter step of this Hamiltonian.
784784
785785
Args:

0 commit comments

Comments
 (0)