11"""Module defining Hamiltonian classes."""
22
3- import operator
43from functools import cache , cached_property , reduce
54from 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
98import numpy as np
109import sympy
10+ from numpy .typing import ArrayLike
1111
1212from qibo .backends import Backend , _check_backend
1313from qibo .config import log , raise_error
1414from qibo .hamiltonians .abstract import AbstractHamiltonian
1515from qibo .hamiltonians .terms import SymbolicTerm
16- from qibo .symbols import PauliSymbol , Symbol , Z
16+ from qibo .symbols import PauliSymbol , Symbol
1717
1818
1919class 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