Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autodifferentiation support for PytorchBackend #1276

Merged
merged 77 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
1d8ba4a
add test
Simone-Bordoni Mar 19, 2024
fa1df66
Merge branch 'master' into pytorch_autodiff
Simone-Bordoni Mar 28, 2024
f1b8ac2
fic psr for pytorch backend
Simone-Bordoni Mar 28, 2024
7b1e711
Merge branch 'master' into pytorch_autodiff
Simone-Bordoni Apr 15, 2024
7fcda88
model_variational test fix
Simone-Bordoni Apr 15, 2024
fbd00a2
sgd for pytorch
Simone-Bordoni Apr 16, 2024
1e688fc
cast matrix parameters
Simone-Bordoni Apr 22, 2024
ed5ce73
fixed gradients problem in variational model
Simone-Bordoni Apr 24, 2024
f537f00
Merge branch 'master' into pytorch_autodiff
renatomello Apr 27, 2024
684948e
Merge branch 'master' into pytorch_autodiff
Simone-Bordoni May 21, 2024
0e4d242
solved errors
Simone-Bordoni May 21, 2024
9200c07
Merge branch 'master' into pytorch_autodiff
Simone-Bordoni May 23, 2024
7949ab7
corrections
Simone-Bordoni May 23, 2024
86510a9
corrections
Simone-Bordoni May 23, 2024
8a4408d
corrections
Simone-Bordoni May 28, 2024
dd2dcb9
corrections quantum info
Simone-Bordoni May 29, 2024
c95a9ef
maybe all tests passing
Simone-Bordoni May 29, 2024
07437fb
Merge branch 'master' into pytorch_autodiff
Simone-Bordoni May 29, 2024
abd9382
improve coverage
Simone-Bordoni May 29, 2024
8bbde0c
remove prints
Simone-Bordoni May 30, 2024
b81b0e2
corrections
Simone-Bordoni May 30, 2024
238e0a8
improve coverage
Simone-Bordoni May 30, 2024
df58676
solve conflicts
Simone-Bordoni Jun 6, 2024
2455cd9
solved errors
Simone-Bordoni Jun 6, 2024
60caf19
merge master
Simone-Bordoni Jun 19, 2024
0e0c955
fix error in dbi_utils and variational
Simone-Bordoni Jun 19, 2024
2b920a1
hopefully solved all errors
Simone-Bordoni Jun 19, 2024
5399ba7
Merge branch 'master' into pytorch_autodiff
renatomello Jun 21, 2024
778d2de
fix cast parameters in new prx gate
Simone-Bordoni Jun 21, 2024
8d49d48
Merge branch 'master' into pytorch_autodiff
renatomello Jun 25, 2024
0a376bb
Merge branch 'master' into pytorch_autodiff
renatomello Jun 27, 2024
2978b1e
fix `cupy` test
renatomello Jun 27, 2024
1388dcb
fix test
Simone-Bordoni Jun 27, 2024
b61f770
fix GPU test
renatomello Jun 28, 2024
a8fb367
Merge branch 'master' into pytorch_autodiff
renatomello Jun 28, 2024
65e9a1c
Merge branch 'master' into pytorch_autodiff
renatomello Jun 28, 2024
49994cd
Fix GPU tests
renatomello Jun 28, 2024
97bcf61
fix GPU tests
renatomello Jun 28, 2024
d06e832
revert changes + remove imports
renatomello Jun 28, 2024
ecfb54a
encodings
renatomello Jun 28, 2024
7646e62
entropies
renatomello Jun 28, 2024
7c64744
`lint`
renatomello Jun 28, 2024
dc6af83
first corrections
Simone-Bordoni Jul 1, 2024
04a524e
pylint error
Simone-Bordoni Jul 1, 2024
888f846
Update src/qibo/quantum_info/basis.py
Simone-Bordoni Jul 1, 2024
e0f376e
Apply suggestions from code review
Simone-Bordoni Jul 1, 2024
c70d191
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 1, 2024
558bc9b
solve error in entropies
Simone-Bordoni Jul 1, 2024
f6a87b7
code improvements
Simone-Bordoni Jul 2, 2024
a9ee2dd
lint error
Simone-Bordoni Jul 2, 2024
f23615e
solved precision problem
Simone-Bordoni Jul 2, 2024
48b7171
.
Simone-Bordoni Jul 2, 2024
f5a3029
try to solve eigenvalues decomposition error
Simone-Bordoni Jul 2, 2024
e1f5407
corrections
Simone-Bordoni Jul 2, 2024
b400891
linalg.qr for all backends
Simone-Bordoni Jul 2, 2024
0af2c62
linalg module in tensorflow
Simone-Bordoni Jul 2, 2024
c698558
solved errors
Simone-Bordoni Jul 2, 2024
205cd83
Merge branch 'master' into pytorch_autodiff
renatomello Jul 3, 2024
3e9f2e7
remove import
renatomello Jul 3, 2024
2027b21
try to fix issue in unitary decompositions
Simone-Bordoni Jul 3, 2024
13a2969
corrections by renato
Simone-Bordoni Jul 3, 2024
98248f8
Merge branch 'master' into pytorch_autodiff
renatomello Jul 4, 2024
8e740de
solve gradients problem
Simone-Bordoni Jul 4, 2024
363ceae
Merge branch 'master' into pytorch_autodiff
renatomello Jul 5, 2024
c4db6f7
use torch stack in cast to keep gradiets
Simone-Bordoni Jul 5, 2024
18910fb
fix_tests
Simone-Bordoni Jul 5, 2024
e66ff87
fix tests
Simone-Bordoni Jul 5, 2024
5bc0a85
fix tests
Simone-Bordoni Jul 5, 2024
46e12c9
corrections by andrea
Simone-Bordoni Jul 8, 2024
038459e
solved error
Simone-Bordoni Jul 8, 2024
ef5c097
corrections by andrea
Simone-Bordoni Jul 10, 2024
a6dc07f
Merge branch 'master' into pytorch_autodiff
renatomello Jul 12, 2024
e3f6c45
Merge branch 'master' into pytorch_autodiff
renatomello Jul 13, 2024
6e7c8c0
Merge branch 'master' into pytorch_autodiff
Simone-Bordoni Jul 16, 2024
85ae474
solved error
Simone-Bordoni Jul 16, 2024
9550312
Merge branch 'master' into pytorch_autodiff
renatomello Jul 16, 2024
6cc64b3
Merge branch 'pytorch_autodiff' of github.com:qiboteam/qibo into pyto…
renatomello Jul 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 66 additions & 24 deletions src/qibo/backends/npmatrices.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import cmath
Simone-Bordoni marked this conversation as resolved.
Show resolved Hide resolved
import math
from functools import cached_property

from qibo.config import raise_error
Expand All @@ -15,9 +17,13 @@ def __init__(self, dtype):
def _cast(self, x, dtype):
return self.np.array(x, dtype=dtype)

# This method is used to cast the parameters of the gates to the right type for other backends
def _cast_parameter(self, x):
return x
Simone-Bordoni marked this conversation as resolved.
Show resolved Hide resolved

@cached_property
def H(self):
return self._cast([[1, 1], [1, -1]], dtype=self.dtype) / self.np.sqrt(2)
return self._cast([[1, 1], [1, -1]], dtype=self.dtype) / math.sqrt(2)

@cached_property
def X(self):
Expand Down Expand Up @@ -50,19 +56,17 @@ def SDG(self):
@cached_property
def T(self):
return self._cast(
[[1, 0], [0, self.np.exp(1j * self.np.pi / 4.0)]], dtype=self.dtype
[[1 + 0j, 0], [0, cmath.exp(1j * math.pi / 4.0)]], dtype=self.dtype
)

@cached_property
def TDG(self):
return self._cast(
[[1, 0], [0, self.np.exp(-1j * self.np.pi / 4.0)]], dtype=self.dtype
[[1 + 0j, 0], [0, cmath.exp(-1j * math.pi / 4.0)]], dtype=self.dtype
)

def I(self, n=2):
# dtype=complex is necessary for pytorch backend,
# _cast will take care of casting in the right dtype for all the backends
return self._cast(self.np.eye(n, dtype=complex), dtype=self.dtype)
return self._cast(self.np.eye(n), dtype=self.dtype)

def Align(self, delay, n=2):
return self._cast(self.I(n), dtype=self.dtype)
Expand All @@ -71,20 +75,25 @@ def M(self): # pragma: no cover
raise_error(NotImplementedError)

def RX(self, theta):
theta = self._cast_parameter(theta)
cos = self.np.cos(theta / 2.0) + 0j
isin = -1j * self.np.sin(theta / 2.0)
return self._cast([[cos, isin], [isin, cos]], dtype=self.dtype)
Simone-Bordoni marked this conversation as resolved.
Show resolved Hide resolved

def RY(self, theta):
theta = self._cast_parameter(theta)
cos = self.np.cos(theta / 2.0) + 0j
sin = self.np.sin(theta / 2.0) + 0j
return self._cast([[cos, -sin], [sin, cos]], dtype=self.dtype)

def RZ(self, theta):
theta = self._cast_parameter(theta)
phase = self.np.exp(0.5j * theta)
return self._cast([[self.np.conj(phase), 0], [0, phase]], dtype=self.dtype)

def PRX(self, theta, phi):
theta = self._cast_parameter(theta)
phi = self._cast_parameter(phi)
cos = self.np.cos(theta / 2)
sin = self.np.sin(theta / 2)
exponent1 = -1.0j * self.np.exp(-1.0j * phi)
Expand All @@ -95,29 +104,36 @@ def PRX(self, theta, phi):
)

def GPI(self, phi):
phi = self._cast_parameter(phi)
phase = self.np.exp(1.0j * phi)
return self._cast([[0, self.np.conj(phase)], [phase, 0]], dtype=self.dtype)

def GPI2(self, phi):
phi = self._cast_parameter(phi)
phase = self.np.exp(1.0j * phi)
return self._cast(
[[1, -1.0j * self.np.conj(phase)], [-1.0j * phase, 1]], dtype=self.dtype
) / self.np.sqrt(2)
) / math.sqrt(2)

def U1(self, theta):
theta = self._cast_parameter(theta)
phase = self.np.exp(1j * theta)
return self._cast([[1, 0], [0, phase]], dtype=self.dtype)

def U2(self, phi, lam):
phi = self._cast_parameter(phi)
lam = self._cast_parameter(lam)
eplus = self.np.exp(1j * (phi + lam) / 2.0)
eminus = self.np.exp(1j * (phi - lam) / 2.0)
return self._cast(
[[self.np.conj(eplus), -self.np.conj(eminus)], [eminus, eplus]]
/ self.np.sqrt(2),
[[self.np.conj(eplus), -self.np.conj(eminus)], [eminus, eplus]],
dtype=self.dtype,
)
) / math.sqrt(2)

def U3(self, theta, phi, lam):
theta = self._cast_parameter(theta)
phi = self._cast_parameter(phi)
lam = self._cast_parameter(lam)
cost = self.np.cos(theta / 2)
sint = self.np.sin(theta / 2)
eplus = self.np.exp(1j * (phi + lam) / 2.0)
Expand All @@ -131,8 +147,10 @@ def U3(self, theta, phi, lam):
)

def U1q(self, theta, phi):
theta = self._cast_parameter(theta)
phi = self._cast_parameter(phi)
return self._cast(
self.U3(theta, phi - self.np.pi / 2, self.np.pi / 2 - phi), dtype=self.dtype
self.U3(theta, phi - math.pi / 2, math.pi / 2 - phi), dtype=self.dtype
)

@cached_property
Expand Down Expand Up @@ -161,7 +179,7 @@ def CZ(self):

@cached_property
def CSX(self):
a = (1 + 1j) / 2
a = self._cast_parameter((1 + 1j) / 2)
b = self.np.conj(a)
return self._cast(
[
Expand All @@ -175,7 +193,7 @@ def CSX(self):

@cached_property
def CSXDG(self):
a = (1 - 1j) / 2
a = self._cast_parameter((1 - 1j) / 2)
b = self.np.conj(a)
return self._cast(
[
Expand All @@ -188,6 +206,7 @@ def CSXDG(self):
)

def CRX(self, theta):
theta = self._cast_parameter(theta)
cos = self.np.cos(theta / 2.0) + 0j
isin = -1j * self.np.sin(theta / 2.0)
matrix = [
Expand All @@ -199,12 +218,14 @@ def CRX(self, theta):
return self._cast(matrix, dtype=self.dtype)

def CRY(self, theta):
theta = self._cast_parameter(theta)
cos = self.np.cos(theta / 2.0) + 0j
sin = self.np.sin(theta / 2.0) + 0j
matrix = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, cos, -sin], [0, 0, sin, cos]]
return self._cast(matrix, dtype=self.dtype)

def CRZ(self, theta):
theta = self._cast_parameter(theta)
phase = self.np.exp(0.5j * theta)
matrix = [
[1, 0, 0, 0],
Expand All @@ -215,6 +236,7 @@ def CRZ(self, theta):
return self._cast(matrix, dtype=self.dtype)

def CU1(self, theta):
theta = self._cast_parameter(theta)
phase = self.np.exp(1j * theta)
matrix = [
[1, 0, 0, 0],
Expand All @@ -225,8 +247,10 @@ def CU1(self, theta):
return self._cast(matrix, dtype=self.dtype)

def CU2(self, phi, lam):
eplus = self.np.exp(1j * (phi + lam) / 2.0) / self.np.sqrt(2)
eminus = self.np.exp(1j * (phi - lam) / 2.0) / self.np.sqrt(2)
phi = self._cast_parameter(phi)
lam = self._cast_parameter(lam)
eplus = self.np.exp(1j * (phi + lam) / 2.0) / math.sqrt(2)
eminus = self.np.exp(1j * (phi - lam) / 2.0) / math.sqrt(2)
matrix = [
[1, 0, 0, 0],
[0, 1, 0, 0],
Expand All @@ -236,6 +260,9 @@ def CU2(self, phi, lam):
return self._cast(matrix, dtype=self.dtype)

def CU3(self, theta, phi, lam):
theta = self._cast_parameter(theta)
phi = self._cast_parameter(phi)
lam = self._cast_parameter(lam)
cost = self.np.cos(theta / 2)
sint = self.np.sin(theta / 2)
eplus = self.np.exp(1j * (phi + lam) / 2.0)
Expand Down Expand Up @@ -271,8 +298,8 @@ def SiSWAP(self):
return self._cast(
[
[1 + 0j, 0j, 0j, 0j],
[0j, 1 / self.np.sqrt(2) + 0j, 1j / self.np.sqrt(2), 0j],
[0j, 1j / self.np.sqrt(2), 1 / self.np.sqrt(2) + 0j, 0j],
[0j, 1 / math.sqrt(2) + 0j, 1j / math.sqrt(2), 0j],
[0j, 1j / math.sqrt(2), 1 / math.sqrt(2) + 0j, 0j],
[0j, 0j, 0j, 1 + 0j],
],
dtype=self.dtype,
Expand All @@ -283,8 +310,8 @@ def SiSWAPDG(self):
return self._cast(
[
[1 + 0j, 0j, 0j, 0j],
[0j, 1 / self.np.sqrt(2) + 0j, -1j / self.np.sqrt(2), 0j],
[0j, -1j / self.np.sqrt(2), 1 / self.np.sqrt(2) + 0j, 0j],
[0j, 1 / math.sqrt(2) + 0j, -1j / math.sqrt(2), 0j],
[0j, -1j / math.sqrt(2), 1 / math.sqrt(2) + 0j, 0j],
[0j, 0j, 0j, 1 + 0j],
],
dtype=self.dtype,
Expand All @@ -297,6 +324,8 @@ def FSWAP(self):
)

def fSim(self, theta, phi):
theta = self._cast_parameter(theta)
phi = self._cast_parameter(phi)
cost = self.np.cos(theta) + 0j
isint = -1j * self.np.sin(theta)
phase = self.np.exp(-1j * phi)
Expand All @@ -312,12 +341,12 @@ def fSim(self, theta, phi):

@cached_property
def SYC(self):
cost = self.np.cos(self.np.pi / 2) + 0j
isint = -1j * self.np.sin(self.np.pi / 2)
phase = self.np.exp(-1j * self.np.pi / 6)
cost = math.cos(math.pi / 2) + 0j
isint = -1j * math.sin(math.pi / 2)
phase = cmath.exp(-1j * math.pi / 6)
return self._cast(
[
[1, 0, 0, 0],
[1 + 0j, 0, 0, 0],
[0, cost, isint, 0],
[0, isint, cost, 0],
[0, 0, 0, phase],
Expand All @@ -326,6 +355,7 @@ def SYC(self):
)

def GeneralizedfSim(self, u, phi):
phi = self._cast_parameter(phi)
phase = self.np.exp(-1j * phi)
return self._cast(
[
Expand All @@ -338,6 +368,7 @@ def GeneralizedfSim(self, u, phi):
)

def RXX(self, theta):
theta = self._cast_parameter(theta)
cos = self.np.cos(theta / 2.0) + 0j
isin = -1j * self.np.sin(theta / 2.0)
return self._cast(
Expand All @@ -351,6 +382,7 @@ def RXX(self, theta):
)

def RYY(self, theta):
theta = self._cast_parameter(theta)
cos = self.np.cos(theta / 2.0) + 0j
isin = -1j * self.np.sin(theta / 2.0)
return self._cast(
Expand All @@ -364,6 +396,7 @@ def RYY(self, theta):
)

def RZZ(self, theta):
theta = self._cast_parameter(theta)
phase = self.np.exp(0.5j * theta)
return self._cast(
[
Expand All @@ -376,6 +409,7 @@ def RZZ(self, theta):
)

def RZX(self, theta):
theta = self._cast_parameter(theta)
cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j
return self._cast(
[
Expand All @@ -388,6 +422,7 @@ def RZX(self, theta):
)

def RXXYY(self, theta):
theta = self._cast_parameter(theta)
cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j
return self._cast(
[
Expand All @@ -400,6 +435,11 @@ def RXXYY(self, theta):
)

def MS(self, phi0, phi1, theta):
phi0, phi1, theta = (
self._cast_parameter(phi0),
self._cast_parameter(phi1),
self._cast_parameter(theta),
)
plus = self.np.exp(1.0j * (phi0 + phi1))
minus = self.np.exp(1.0j * (phi0 - phi1))
cos = self.np.cos(theta / 2) + 0j
Expand All @@ -415,6 +455,7 @@ def MS(self, phi0, phi1, theta):
)

def GIVENS(self, theta):
theta = self._cast_parameter(theta)
return self._cast(
[
[1, 0, 0, 0],
Expand All @@ -438,7 +479,7 @@ def ECR(self):
[-1j, 1 + 0j, 0j, 0j],
],
dtype=self.dtype,
) / self.np.sqrt(2)
) / math.sqrt(2)

@cached_property
def TOFFOLI(self):
Expand Down Expand Up @@ -473,6 +514,7 @@ def CCZ(self):
)

def DEUTSCH(self, theta):
theta = self._cast_parameter(theta)
sin = self.np.sin(theta) + 0j # 0j necessary for right tensorflow dtype
cos = self.np.cos(theta) + 0j
return self._cast(
Expand Down
17 changes: 11 additions & 6 deletions src/qibo/backends/numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ def matrix_fused(self, fgate):
return self.cast(matrix.toarray())

def apply_gate(self, gate, state, nqubits):
state = self.cast(state)
state = self.np.reshape(state, nqubits * (2,))
matrix = gate.matrix(self)
if gate.is_controlled_by:
Expand Down Expand Up @@ -718,31 +717,37 @@ def calculate_norm_density_matrix(self, state, order="nuc"):
return self.np.linalg.norm(state, ord=order)

def calculate_overlap(self, state1, state2):
return self.np.abs(self.np.sum(np.conj(self.cast(state1)) * self.cast(state2)))
return self.np.abs(
self.np.sum(self.np.conj(self.cast(state1)) * self.cast(state2))
)

def calculate_overlap_density_matrix(self, state1, state2):
return self.np.trace(
self.np.matmul(self.np.conj(self.cast(state1)).T, self.cast(state2))
)

def calculate_eigenvalues(self, matrix, k=6):
def calculate_eigenvalues(self, matrix, k=6, hermitian=True):
if self.issparse(matrix):
log.warning(
"Calculating sparse matrix eigenvectors because "
"sparse modules do not provide ``eigvals`` method."
)
return self.calculate_eigenvectors(matrix, k=k)[0]
return np.linalg.eigvalsh(matrix)
if hermitian:
return np.linalg.eigvalsh(matrix)
return np.linalg.eigvals(matrix)

def calculate_eigenvectors(self, matrix, k=6):
def calculate_eigenvectors(self, matrix, k=6, hermitian=True):
if self.issparse(matrix):
if k < matrix.shape[0]:
from scipy.sparse.linalg import eigsh

return eigsh(matrix, k=k, which="SA")
else: # pragma: no cover
matrix = self.to_numpy(matrix)
return np.linalg.eigh(matrix)
if hermitian:
return np.linalg.eigh(matrix)
return np.linalg.eig(matrix)

def calculate_matrix_exp(self, a, matrix, eigenvectors=None, eigenvalues=None):
if eigenvectors is None or self.issparse(matrix):
Expand Down
Loading