givens_decomposition¶
- givens_decomposition(unitary)¶
Decomposes a unitary matrix into Givens rotations and diagonal phases.
The \(n \times n\) unitary matrix, \(U\), can be decomposed into a diagonal matrix, \(D\), and sequence of \(2 \times 2\) Givens rotations, \(G\), acting on adjacent indices. This algorithm [1] requires at most \(n (n-1) / 2\) such Givens rotations.
Each Givens rotation is defined by a 4-tuple,
(c, s, i, j), with:c: the real-valued cosines: the complex-valued sinei: the first row indexj: the second row index
which result in a matrix of the form:
\[\begin{pmatrix} c & s \\ -s^\dagger & c \end{pmatrix}\]- Parameters:
unitary – the unitary matrix, \(U\), to be decomposed.
- Returns:
A 2-tuple consisting of
the sequence of Givens rotations represented as 4-tuples as explained above
the vector of complex phases of the diagonal matrix, \(D\)
The original unitary is recovered by processing the returned rotations in reverse order and right-multiplying the diagonal matrix by the element-wise complex conjugate of each rotation matrix \(G_k\) (as defined above). That is, for \(N\) returned rotations,
\[U = D \cdot \overline{G_N} \cdot \overline{G_{N-1}} \cdots \overline{G_1},\]where \(\overline{G_k}\) denotes element-wise conjugation (not the conjugate transpose) and each \(G_k\) acts only on rows/columns \(i\) and \(j\) of its rotation.
>>> import numpy as np >>> from qiskit_fermions.linalg import givens_decomposition >>> unitary = np.array([[0.6, 0.8j], [0.8, -0.6j]], dtype=complex) >>> rotations, phases = givens_decomposition(unitary) >>> reconstructed = np.diag(phases).astype(complex) >>> for c, s, i, j in rotations[::-1]: ... givens_mat = np.eye(2, dtype=complex) ... givens_mat[np.ix_((i, j), (i, j))] = [[c, s], [-s.conjugate(), c]] ... reconstructed = reconstructed @ givens_mat.conj() >>> bool(np.allclose(reconstructed, unitary)) True