import numpy as np
from typing import List, Dict, Tuple, Union
from itertools import product
from scipy.linalg import expm
from quara.utils.matrix_util import (
is_hermitian,
kron,
truncate_computational_fluctuation,
)
from quara.objects.matrix_basis import SparseMatrixBasis
from quara.objects.matrix_basis import (
get_comp_basis,
get_pauli_basis,
get_normalized_pauli_basis,
get_normalized_gell_mann_basis,
get_normalized_generalized_gell_mann_basis,
)
from quara.objects.composite_system import CompositeSystem
from quara.objects.gate import Gate
from quara.objects.gate import convert_hs
from quara.objects.effective_lindbladian import _truncate_hs
[docs]def get_gate_names() -> List[str]:
"""Return the list of valid gate names."""
names = []
names.extend(["identity"])
names.extend(get_gate_names_1qubit())
names.extend(get_gate_names_2qubit())
names.extend(get_gate_names_3qubit())
names.extend(get_gate_names_1qutrit())
names.extend(get_gate_names_2qutrit())
return names
[docs]def get_gate_names_1qubit() -> List[str]:
"""Return the list of valid gate names of 1-qubit gates."""
names = []
names.append("x90")
names.append("x180")
names.append("x")
names.append("y90")
names.append("y180")
names.append("y")
names.append("z90")
names.append("z180")
names.append("z")
names.append("phase")
names.append("phase_daggered")
names.append("piover8")
names.append("piover8_daggered")
names.append("hadamard")
names.append("zm90")
return names
[docs]def get_gate_names_2qubit() -> List[str]:
"""Return the list of valid gate names of 2-qubit gates."""
names = []
names.append("cx")
names.append("cz")
names.append("swap")
names.append("zx90")
names.append("zz90")
return names
[docs]def get_gate_names_2qubit_asymmetric() -> List[str]:
"""Return the list of valid gate names of 2-qubit gates that are asymmetric with respect to ids of elemental systems."""
names = []
names.append("cx")
names.append("zx90")
return names
[docs]def get_gate_names_3qubit() -> List[str]:
"""Return the list of valid gate names of typical 3-qubit gates."""
names = []
names.append("toffoli")
names.append("fredkin")
return names
[docs]def get_gate_names_3qubit_asymmetric() -> List[str]:
"""Return the list of valid gate names of typical 3-qubit gates that are asymmetric with respect to ids of elemental systems."""
names = []
names.append("toffoli")
names.append("fredkin")
return names
[docs]def get_gate_names_1qutrit() -> List[str]:
"""return the list of valid (implemented) gate names of 1-qutrit gates."""
names = []
names.extend(get_gate_names_1qutrit_single_gellmann())
return names
[docs]def get_gate_names_1qutrit_single_gellmann() -> List[str]:
"""return the list of valid (implemented) gate names of 1-qutrit single Gell-Mann gates."""
names = []
# angle = 90
names.append("01x90")
names.append("01y90")
names.append("01z90")
names.append("12x90")
names.append("12y90")
names.append("12z90")
names.append("02x90")
names.append("02y90")
names.append("02z90")
# angle = 180
names.append("01x180")
names.append("01y180")
names.append("01z180")
names.append("12x180")
names.append("12y180")
names.append("12z180")
names.append("02x180")
names.append("02y180")
names.append("02z180")
return names
[docs]def generate_gate_object_from_gate_name_object_name(
gate_name: str,
object_name: str,
dims: List[int] = None,
ids: List[int] = None,
c_sys: CompositeSystem = None,
is_physicality_required: bool = True,
) -> Union[np.ndarray, "Gate"]:
if dims is None:
dims = []
if ids is None:
ids = []
if object_name == "unitary_mat":
obj = generate_unitary_mat_from_gate_name(gate_name, dims, ids)
elif object_name == "gate_mat":
obj = generate_gate_mat_from_gate_name(gate_name, dims, ids)
elif object_name == "gate":
obj = generate_gate_from_gate_name(
gate_name, c_sys, ids, is_physicality_required=is_physicality_required
)
else:
raise ValueError(f"object_name is out of range.")
return obj
[docs]def get_gate_names_2qutrit() -> List[str]:
"""return the list of valid (implemented) gate names of 2-qutrit gates."""
names = []
names.extend(get_gate_names_2qutrit_base_matrices())
return names
[docs]def get_gate_names_2qutrit_base_matrices() -> List[str]:
"""return the list of valid (implemented) gate names of 2-qutrit gates."""
names = []
names.extend(get_gate_names_2qutrit_single_base_matrix())
names.extend(get_gate_names_2qutrit_two_base_matrices())
return names
def _is_valid_dims_ids(dims: List[int], ids: List[int]) -> bool:
res = True
# whether components of dims are integers larger than 1
if dims:
for d in dims:
if d <= 1:
res = False
raise ValueError(f"Component of dims must be larger than 1.")
# whether components of id_sys_list are non-negative integers
if ids:
for i in ids:
if i < 0:
res = False
raise ValueError(f"Component of ids must be non-negative.")
return res
def _dim_total_from_dims(dims: List[int]) -> int:
dim_total = 1
for d in dims:
dim_total = dim_total * d
return dim_total
[docs]def generate_unitary_mat_from_gate_name(
gate_name: str, dims: List[int] = None, ids: List[int] = None
):
"""returns the unitary matrix of a gate.
Parameters
----------
gate_name : str
name of gate
dims : List[int]
list of dimentions of elemental systems that the gate acts on.
ids : List[int] (optional)
list of ids for elemental systems
Returns
----------
np.ndarray
The unitary matrix of the gate, to be complex.
"""
if dims is None:
dims = []
if ids is None:
ids = []
_is_valid_dims_ids(dims, ids)
if gate_name == "identity":
dim_total = _dim_total_from_dims(dims)
if dim_total <= 1:
raise ValueError(f"dim_total must be larger than 1.")
method_name = "generate_gate_" + gate_name + "_unitary_mat"
method = eval(method_name)
u = method(dim_total)
# 1-qubit gate
elif gate_name in get_gate_names_1qubit():
method_name = "generate_gate_" + gate_name + "_unitary_mat"
method = eval(method_name)
u = method()
# 2-qubit gate
elif gate_name in get_gate_names_2qubit():
method_name = "generate_gate_" + gate_name + "_unitary_mat"
method = eval(method_name)
if gate_name in get_gate_names_2qubit_asymmetric():
u = method(ids)
else:
u = method()
# 3-qubit gate
elif gate_name in get_gate_names_3qubit():
method_name = "generate_gate_" + gate_name + "_hamiltonian_mat"
method = eval(method_name)
h = method(ids)
u = calc_unitary_mat_from_hamiltonian_mat(h)
# 1-qutrit
elif gate_name in get_gate_names_1qutrit():
if gate_name in get_gate_names_1qutrit_single_gellmann():
method_name = "generate_gate_1qutrit_single_gellmann_unitary_mat"
method = eval(method_name)
u = method(gate_name)
# 2-qutrit
elif gate_name in get_gate_names_2qutrit():
h = generate_gate_2qutrit_hamiltonian_mat_from_gate_name(gate_name)
u = calc_unitary_mat_from_hamiltonian_mat(h)
else:
raise ValueError(f"gate_name is out of range.")
return u
[docs]def generate_gate_mat_from_gate_name(
gate_name: str, dims: List[int] = None, ids: List[int] = None
) -> np.ndarray:
"""returns the Hilbert-Schmidt representation matrix of a gate.
Parameters
----------
gate_name : str
name of gate
dims : List[int]
list of dimentions of elemental systems that the gate acts on.
ids : List[int] (optional)
list of ids for elemental systems
Returns
----------
np.ndarray
The HS matrix of the gate, to be real.
"""
if dims is None:
dims = []
if ids is None:
ids = []
_is_valid_dims_ids(dims, ids)
if gate_name == "identity":
dim_total = _dim_total_from_dims(dims)
if dim_total <= 1:
raise ValueError(f"dim_total must be larger than 1.")
method_name = "generate_gate_" + gate_name + "_mat"
method = eval(method_name)
mat = method(dim_total)
# 1-qubit gate
elif gate_name in get_gate_names_1qubit():
method_name = "generate_gate_" + gate_name + "_mat"
method = eval(method_name)
mat = method()
# 2-qubit gate
elif gate_name in get_gate_names_2qubit():
method_name = "generate_gate_" + gate_name + "_mat"
method = eval(method_name)
if gate_name in get_gate_names_2qubit_asymmetric():
mat = method(ids)
else:
mat = method()
# 3-qubit gate
elif gate_name in get_gate_names_3qubit():
basis = get_normalized_pauli_basis(n_qubit=3)
method_name = "generate_gate_" + gate_name + "_hamiltonian_mat"
method = eval(method_name)
h = method(ids)
mat = calc_gate_mat_from_hamiltonian_mat(h, to_basis=basis)
# 1-qutrit
elif gate_name in get_gate_names_1qutrit():
if gate_name in get_gate_names_1qutrit_single_gellmann():
method_name = "generate_gate_1qutrit_single_gellmann_mat"
method = eval(method_name)
mat = method(gate_name)
# 2-qutrit
elif gate_name in get_gate_names_2qutrit():
basis = get_normalized_generalized_gell_mann_basis(n_qubit=2, dim=3)
h = generate_gate_2qutrit_hamiltonian_mat_from_gate_name(gate_name, ids)
mat = calc_gate_mat_from_hamiltonian_mat(h=h, to_basis=basis)
else:
raise ValueError(f"gate_name is out of range.")
return mat
[docs]def generate_gate_from_gate_name(
gate_name: str,
c_sys: CompositeSystem,
ids: List[int] = None,
is_physicality_required: bool = True,
) -> "Gate":
"""returns gate class.
Parameters
----------
gate_name : str
name of gate
c_sys : CompositeSystem
ids : List[int] (optional)
list of ids for elemental systems
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The gate class for the input
"""
if ids is None:
ids = []
if gate_name == "identity":
method_name = "generate_gate_" + gate_name
method = eval(method_name)
gate = method(c_sys, is_physicality_required=is_physicality_required)
# 1-qubit gate
elif gate_name in get_gate_names_1qubit():
method_name = "generate_gate_" + gate_name
method = eval(method_name)
gate = method(c_sys, is_physicality_required=is_physicality_required)
# 2-qubit gate
elif gate_name in get_gate_names_2qubit():
method_name = "generate_gate_" + gate_name
method = eval(method_name)
if gate_name in get_gate_names_2qubit_asymmetric():
gate = method(c_sys, ids, is_physicality_required=is_physicality_required)
else:
gate = method(c_sys, is_physicality_required=is_physicality_required)
# 3-qubit gate
elif gate_name in get_gate_names_3qubit():
method_name = "generate_gate_" + gate_name + "_hamiltonian_mat"
method = eval(method_name)
h = method(ids)
gate = calc_gate_from_hamiltonian_mat(
c_sys=c_sys, h=h, is_physicality_required=is_physicality_required
)
# 1-qutrit gate
elif gate_name in get_gate_names_1qutrit():
if gate_name in get_gate_names_1qutrit_single_gellmann():
method_name = "generate_gate_1qutrit_single_gellmann"
method = eval(method_name)
gate = method(
c_sys, gate_name, is_physicality_required=is_physicality_required
)
# 2-qutrit gate
elif gate_name in get_gate_names_2qutrit():
mat = generate_gate_mat_from_gate_name(gate_name, ids=ids)
gate = Gate(
c_sys=c_sys, hs=mat, is_physicality_required=is_physicality_required
)
else:
raise ValueError(f"gate_name is out of range.")
return gate
[docs]def calc_gate_mat_from_unitary_mat(
from_u: np.ndarray, to_basis: SparseMatrixBasis
) -> np.ndarray:
"""Return the HS matrix for a gate represented by an unitary matrix.
Parameters
----------
from_u : np.ndarray((dim, dim), dtype=np.complex128)
The unitary matrix, to be square complex np.ndarray.
to_basis : MatrixBasis
The matrix basis for representing the HS matrix, to be orthonormal.
Returns
----------
np.ndarray((dim^2, dim^2), dtype=np.complex128)
The HS matrix of the gate corresponding to the unitary matrix.
"""
shape = from_u.shape
assert shape[0] == shape[1]
dim = shape[0]
assert to_basis.dim == dim
assert to_basis.is_orthogonal() == True
assert to_basis.is_normal() == True
hs_comp = kron(from_u, np.conjugate(from_u))
basis_comp = get_comp_basis(dim)
hs = convert_hs(from_hs=hs_comp, from_basis=basis_comp, to_basis=to_basis)
return hs
[docs]def calc_gate_mat_from_unitary_mat_with_hermitian_basis(
from_u: np.ndarray, to_basis: SparseMatrixBasis
) -> np.ndarray:
"""Return the HS matrix w.r.t. a Hermitian (orthonormal) matrix basis for a gate represented by an unitary matrix.
Parameters
----------
from_u : np.ndarray((dim, dim), dtype=np.complex128)
The unitary matrix, to be square complex np.ndarray.
to_basis : MatrixBasis
The matrix basis for representing the HS matrix
Returns
----------
np.ndarray((dim^2, dim^2), dtype=np.float64)
The HS matrix of the gate corresponding to the unitary matrix, to be real.
"""
assert to_basis.is_hermitian() == True
hs_complex = calc_gate_mat_from_unitary_mat(from_u, to_basis)
hs = _truncate_hs(hs_complex)
return hs
[docs]def calc_unitary_mat_from_hamiltonian_mat(h: np.ndarray) -> np.ndarray:
"""return the unitary matrix for a given Hamiltonian matrix.
Parameters
----------
h : np.ndarray((dim, dim), dtype=np.complex128)
Hamiltonian matrix
Returns
----------
np.ndarray((dim dim), dtype=np.complex128), U = expm-(1j * h)
"""
assert is_hermitian(h)
u = truncate_computational_fluctuation(expm(-1j * h))
return u
[docs]def calc_gate_mat_from_hamiltonian_mat(
h: np.ndarray, to_basis: SparseMatrixBasis
) -> np.ndarray:
"""return a HS matrix of a gate for a given Hamiltonian matrix.
Parameters
----------
h : np.ndarray((dim dim), dtype=np.complex128)
Hamiltonian matrix
to_basis : MatrixBasis, to be Hermitian
Returns
----------
np.ndarray((dim^2, dim^2), dtype=np.float64)
"""
u = calc_unitary_mat_from_hamiltonian_mat(h)
hs = calc_gate_mat_from_unitary_mat_with_hermitian_basis(
from_u=u, to_basis=to_basis
)
return hs
[docs]def calc_gate_from_hamiltonian_mat(
c_sys: CompositeSystem, h: np.ndarray, is_physicality_required: bool = True
) -> "Gate":
"""return a Gate class object for a given Hamiltonian matrix.
Parameters
----------
c_sys : CompositeSystem, whose basis must be Hermitian.
h : np.ndarray((dim, dim), dtype=np.complex128)
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
"""
b = c_sys.basis()
hs = calc_gate_mat_from_hamiltonian_mat(h=h, to_basis=b)
g = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return g
# Identity gate
[docs]def generate_gate_identity_unitary_mat(dim: int) -> np.ndarray:
"""Return the unitary matrix for an identity gate.
The result is the dim times dim complex identity matrix.
Parameters
----------
dim : int
The dimension of the quantum system on which the gate acts.
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.eye(dim, dtype=np.complex128)
return u
[docs]def generate_gate_identity_mat(dim: int) -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for an Identity gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is the dim^2 times dim^2 real identity matrix.
Parameters
----------
dim : int
The dimension of the quantum system on which the gate acts.
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate. It is the identity matrix in this case.
"""
size = dim * dim
mat = np.eye(size, size, dtype=np.float64)
return mat
[docs]def generate_gate_identity(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the identity gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the identity gate on the composite system.
"""
dim = c_sys.dim
hs = generate_gate_identity_mat(dim)
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# X90 gate on 1-qubit
[docs]def generate_gate_x90_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for an X90 gate.
The result is the 2 times 2 complex matrix.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array([[1 + 0j, 0 - 1j], [0 - 1j, 1 + 0j]], dtype=np.complex128) / np.sqrt(2)
return u
[docs]def generate_gate_x90_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for an X90 gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1], [0, 0, 1, 0]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_x90(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the X90 gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the X90 gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_x90_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# X180 gate on 1-qubit
[docs]def generate_gate_x180_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for an X180 gate.
The result is the 2 times 2 complex matrix, -i X.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array([[0, -1j], [-1j, 0]], dtype=np.complex128)
return u
[docs]def generate_gate_x180_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for an X180 gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_x180(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the X180 gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the identity gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_x180_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# X gate on 1-qubit
[docs]def generate_gate_x_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for an X gate.
The result is the 2 times 2 complex matrix, X.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
num_qubit = 1
b = get_pauli_basis(num_qubit)
u = b[1]
return u
[docs]def generate_gate_x_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for an X gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_x(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the X gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the X gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_x_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Y90 on 1-qubit
[docs]def generate_gate_y90_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for an Y90 gate.
The result is a 2 times 2 complex matrix.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array([[1, -1], [1, 1]], dtype=np.complex128) / np.sqrt(2)
return u
[docs]def generate_gate_y90_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Y90 gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, -1, 0, 0]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_y90(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Y90 gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Y90 gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_y90_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Y180 gate on 1-qubit
[docs]def generate_gate_y180_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a Y180 gate.
The result is the 2 times 2 complex matrix, -i Y.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array([[0, -1], [1, 0]], dtype=np.complex128)
return u
[docs]def generate_gate_y180_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Y180 gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_y180(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Y180 gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Y180 gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_y180_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Y gate on 1-qubit
[docs]def generate_gate_y_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a Y gate.
The result is the 2 times 2 complex matrix, Y.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
num_qubit = 1
b = get_pauli_basis(num_qubit)
u = b[2]
return u
[docs]def generate_gate_y_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Y gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_y(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Y gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Y gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_y_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Z90 gate on 1-qubit
[docs]def generate_gate_z90_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a Z90 gate.
The result is a 2 times 2 complex matrix.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array([[1 - 1j, 0], [0, 1 + 1j]], dtype=np.complex128) / np.sqrt(2)
return u
[docs]def generate_gate_z90_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Z90 gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_z90(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Z90 gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Z90 gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_z90_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Z(-90) gate on 1-qubit
[docs]def generate_gate_zm90_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a Z(-90) gate.
The result is a 2 times 2 complex matrix.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array([[1 + 1j, 0], [0, 1 - 1j]], dtype=np.complex128) / np.sqrt(2)
return u
[docs]def generate_gate_zm90_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Z(-90) gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, 0, 1, 0], [0, -1, 0, 0], [0, 0, 0, 1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_zm90(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Z(-90) gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Z90 gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_zm90_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Z180 gate on 1-qubit
[docs]def generate_gate_z180_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a Z180 gate.
The result is the 2 times 2 complex matrix, -i Z.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array([[-1j, 0], [0, 1j]], dtype=np.complex128)
return u
[docs]def generate_gate_z180_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Z180 gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_z180(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Z180 gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Z180 gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_z180_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Z gate on 1-qubit
[docs]def generate_gate_z_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a Z gate.
The result is the 2 times 2 complex matrix, Z.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
num_qubit = 1
b = get_pauli_basis(num_qubit)
u = b[3]
return u
[docs]def generate_gate_z_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Z gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_z(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Z gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Z gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_z_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Phase (S) gate on 1-qubit
[docs]def generate_gate_phase_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a Phase (S) gate.
The result is the 2 times 2 complex matrix, S.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array([[1, 0], [0, 1j]], dtype=np.complex128)
return u
[docs]def generate_gate_phase_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Phase (S) gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_phase(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Phase (S) gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Phase (S) gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_phase_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Phase daggered (S^dagger) gate on 1-qubit
[docs]def generate_gate_phase_daggered_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a Phase daggerd (S^dagger) gate.
The result is the 2 times 2 complex matrix, S^dagger.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array([[1, 0], [0, -1j]], dtype=np.complex128)
return u
[docs]def generate_gate_phase_daggered_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Phase daggerd (S^dagger) gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, 0, 1, 0], [0, -1, 0, 0], [0, 0, 0, 1]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_phase_daggered(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Phase daggered (S^dagger) gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Phase daggered (S^dagger) gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_phase_daggered_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# pi/8 (T) gate on 1-qubit
[docs]def generate_gate_piover8_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a pi/8 (T) gate.
The result is the 2 times 2 complex matrix, T.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array(
[[1, 0], [0, 0.50 * np.sqrt(2) + 0.50 * np.sqrt(2) * 1j]], dtype=np.complex128
)
return u
[docs]def generate_gate_piover8_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a pi/8 (T) gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [
[1, 0, 0, 0],
[0, 0.50 * np.sqrt(2), -0.50 * np.sqrt(2), 0],
[0, 0.50 * np.sqrt(2), 0.50 * np.sqrt(2), 0],
[0, 0, 0, 1],
]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_piover8(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the pi/8 (T) gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the pi/8 (T) gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_piover8_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# pi/8 daggered (T^dagger) gate on 1-qubit
[docs]def generate_gate_piover8_daggered_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a pi/8 daggerd (T^dagger) gate.
The result is the 2 times 2 complex matrix, T^dagger.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = np.array(
[[1, 0], [0, 0.50 * np.sqrt(2) - 1j * 0.50 * np.sqrt(2)]], dtype=np.complex128
)
return u
[docs]def generate_gate_piover8_daggered_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a pi/8 daggerd (T^dagger) gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [
[1, 0, 0, 0],
[0, 0.50 * np.sqrt(2), 0.50 * np.sqrt(2), 0],
[0, -0.50 * np.sqrt(2), 0.50 * np.sqrt(2), 0],
[0, 0, 0, 1],
]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_piover8_daggered(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the pi/8 daggered (T^dagger) gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the pi/8 daggered (T^dagger) gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_piover8_daggered_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Hadamard (H) gate on 1-qubit
[docs]def generate_gate_hadamard_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for an Hadamard (H) gate.
The result is the 2 times 2 complex matrix, H.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
u = 0.50 * np.sqrt(2) * np.array([[1, 1], [1, -1]], dtype=np.complex128)
return u
[docs]def generate_gate_hadamard_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for an Hadamard (H) gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 4 times 4 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
l = [[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, -1, 0], [0, 1, 0, 0]]
mat = np.array(l, dtype=np.float64)
return mat
[docs]def generate_gate_hadamard(
c_sys: CompositeSystem, is_physicality_required: bool = True
) -> "Gate":
"""Return the Gate class for the Hadamard (H) gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Hadamard (H) gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 1
hs = generate_gate_hadamard_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# 2-qubit gates
# Control-X gate on 2-qubit
[docs]def generate_gate_cx_unitary_mat(ids: List[int]) -> np.ndarray:
"""Return the unitary matrix for a Control-X (CX) gate.
The result is the 4 times 4 complex matrix.
Parameters
----------
ids : List[int]
ids[0] for control system id, and ids[1] for target system id.
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
assert len(ids) == 2
assert ids[0] != ids[1]
if ids[0] < ids[1]:
mat = np.array(
[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]],
dtype=np.complex128,
)
else:
mat = np.array(
[[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]],
dtype=np.complex128,
)
return mat
[docs]def generate_gate_cx_mat(ids: List[int]) -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Control-X (CX) gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 16 times 16 real matrix.
Parameters
----------
ids : List[int]
ids[0] for the control system id, ids[1] for the target system id.
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
assert len(ids) == 2
assert ids[0] != ids[1]
u = generate_gate_cx_unitary_mat(ids)
b = get_normalized_pauli_basis(n_qubit=2)
mat = calc_gate_mat_from_unitary_mat_with_hermitian_basis(from_u=u, to_basis=b)
return mat
[docs]def generate_gate_cx(
c_sys: "CompositeSystem", ids: List[int], is_physicality_required: bool = True
) -> Gate:
"""Return the Gate class for the Control-X (CX) gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
ids: List[int]
ids[0] for control system index
ids[1] for target system index
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Control-X (CX) gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 2
hs = generate_gate_cx_mat(ids)
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# Control-Z gate on 2-qubit
[docs]def generate_gate_cz_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a Control-Z (CZ) gate.
The result is the 4 times 4 complex matrix.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
mat = np.array(
[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]],
dtype=np.complex128,
)
return mat
[docs]def generate_gate_cz_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a Control-Z (CZ) gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 16 times 16 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
u = generate_gate_cz_unitary_mat()
b = get_normalized_pauli_basis(n_qubit=2)
mat = calc_gate_mat_from_unitary_mat_with_hermitian_basis(from_u=u, to_basis=b)
return mat
[docs]def generate_gate_cz(
c_sys: "CompositeSystem", is_physicality_required: bool = True
) -> Gate:
"""Return the Gate class for the Control-Z (CZ) gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the Control-Z (CZ) gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 2
hs = generate_gate_cz_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# SWAP gate on 2-qubit
[docs]def generate_gate_swap_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a SWAP gate.
The result is the 4 times 4 complex matrix.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
mat = np.array(
[[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]],
dtype=np.complex128,
)
return mat
[docs]def generate_gate_swap_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a SWAP gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 16 times 16 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
u = generate_gate_swap_unitary_mat()
b = get_normalized_pauli_basis(n_qubit=2)
mat = calc_gate_mat_from_unitary_mat_with_hermitian_basis(from_u=u, to_basis=b)
return mat
[docs]def generate_gate_swap(
c_sys: "CompositeSystem", is_physicality_required: bool = True
) -> Gate:
"""Return the Gate class for the SWAP gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the SWAP gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 2
hs = generate_gate_swap_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# ZX90 gate on 2-qubit system
[docs]def generate_gate_zx90_unitary_mat(ids: List[int]) -> np.ndarray:
"""Return the unitary matrix for a ZX90 gate.
The result is the 4 times 4 complex matrix.
Parameters
----------
ids : List[int]
ids[0] for control system id, and ids[1] for target system id.
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
assert len(ids) == 2
assert ids[0] != ids[1]
if ids[0] < ids[1]:
mat = (
0.50
* np.sqrt(2)
* np.array(
[[1, -1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, 1j], [0, 0, 1j, 1]],
dtype=np.complex128,
)
)
else:
mat = (
0.50
* np.sqrt(2)
* np.array(
[[1, 0, -1j, 0], [0, 1, 0, 1j], [-1j, 0, 1, 0], [0, 1j, 0, 1]],
dtype=np.complex128,
)
)
return mat
[docs]def generate_gate_zx90_mat(ids: List[int]) -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a ZX90 gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 16 times 16 real matrix.
Parameters
----------
ids : List[int]
ids[0] for the control system id, ids[1] for the target system id.
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
assert len(ids) == 2
assert ids[0] != ids[1]
u = generate_gate_zx90_unitary_mat(ids)
b = get_normalized_pauli_basis(n_qubit=2)
mat = calc_gate_mat_from_unitary_mat_with_hermitian_basis(from_u=u, to_basis=b)
return mat
[docs]def generate_gate_zx90(
c_sys: "CompositeSystem", ids: List[int], is_physicality_required: bool = True
) -> Gate:
"""Return the Gate class for the ZX90 gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
ids: List[int]
ids[0] for control system index
ids[1] for target system index
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the ZX90 gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 2
hs = generate_gate_zx90_mat(ids)
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# ZZ90 gate on 2-qubit system
[docs]def generate_gate_zz90_unitary_mat() -> np.ndarray:
"""Return the unitary matrix for a ZZ90 gate.
The result is the 4 times 4 complex matrix.
Parameters
----------
Returns
----------
np.ndarray
The unitary matrix, which is a complex matrix.
"""
mat = (
0.50
* np.sqrt(2)
* np.array(
[
[1 - 1j, 0, 0, 0],
[0, 1 + 1j, 0, 0],
[0, 0, 1 + 1j, 0],
[0, 0, 0, 1 - 1j],
],
dtype=np.complex128,
)
)
return mat
[docs]def generate_gate_zz90_mat() -> np.ndarray:
"""Return the Hilbert-Schmidt representation matrix for a ZZ90 gate with respect to the orthonormal Hermitian matrix basis with the normalized identity matrix as the 0th element.
The result is a 16 times 16 real matrix.
Parameters
----------
Returns
----------
np.ndarray
The real Hilbert-Schmidt representation matrix for the gate.
"""
u = generate_gate_zz90_unitary_mat()
b = get_normalized_pauli_basis(n_qubit=2)
mat = calc_gate_mat_from_unitary_mat_with_hermitian_basis(from_u=u, to_basis=b)
return mat
[docs]def generate_gate_zz90(
c_sys: "CompositeSystem", is_physicality_required: bool = True
) -> Gate:
"""Return the Gate class for the ZZ90 gate on the composite system.
Parameters
----------
c_sys: CompositeSystem
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
----------
Gate
The Gate class for the ZZ90 gate on the composite system.
"""
assert len(c_sys.elemental_systems) == 2
hs = generate_gate_zz90_mat()
gate = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return gate
# 3-qubit gates
[docs]def convert_1qubit_pauli_symbol_to_pauli_index(
symbol: str, mode: str
) -> Union[int, str]:
if mode == "int":
i = convert_1qubit_pauli_symbol_to_pauli_index_int(symbol)
elif mode == "str":
i = convert_1qubit_pauli_symbol_to_pauli_index_str(symbol)
else:
raise ValueError(f"mode is invalid.")
return i
[docs]def convert_1qubit_pauli_symbol_to_pauli_index_int(symbol: str) -> int:
assert symbol in ["i", "x", "y", "z"]
if symbol == "i":
i = 0
elif symbol == "x":
i = 1
elif symbol == "y":
i = 2
elif symbol == "z":
i = 3
return i
[docs]def convert_1qubit_pauli_symbol_to_pauli_index_str(symbol: str) -> str:
assert symbol in ["i", "x", "y", "z"]
if symbol == "i":
i = "0"
elif symbol == "x":
i = "1"
elif symbol == "y":
i = "2"
elif symbol == "z":
i = "3"
return i
[docs]def convert_1qubit_pauli_index_to_pauli_symbol(index: Union[int, str]) -> str:
assert index in [0, 1, 2, 3] or index in ["0", "1", "2", "3"]
if index == 0 or index == "0":
s = "i"
elif index == 1 or index == "1":
s = "x"
elif index == 2 or index == "2":
s = "y"
elif index == 3 or index == "3":
s = "z"
return s
[docs]def calc_quadrant_from_pauli_symbol(symbol: str) -> str:
"""Return the quadrant corresponding to a given pauli symbol.
Parameters
----------
symbol : str
Ex. i, x, yz, xyz.
Returns
----------
str : Ex. "0", "1", "23", "123"
"""
q = ""
for si in symbol:
qi = convert_1qubit_pauli_symbol_to_pauli_index(symbol=si, mode="str")
q = q + qi
return q
[docs]def calc_decimal_number_from_pauli_symbol(symbol: str) -> int:
"""Return the decimal number corresponding to a given pauli symbol.
Parameters
----------
symbol : str
Ex. i, x, yz, xyz.
Returns
----------
int : A decimal number
Ex. 0, 1, 11, 27
"""
q = calc_quadrant_from_pauli_symbol(symbol)
n = int(q, 4)
return n
[docs]def calc_pauli_symbol_from_quadrant(quadrant: str) -> str:
"""Return the Pauli symbol from a given quadtant.
Parameters
----------
quadrant : str
Ex. "0", "1", "23", "123".
Returns
----------
str : Ex. i, x, yz, xyz.
"""
s = ""
for qi in quadrant:
si = convert_1qubit_pauli_index_to_pauli_symbol(qi)
s = s + si
return s
[docs]def calc_quadrant_from_decimal_number(value: int) -> str:
"""Return a quadrant (4-ary) from a given decimal number.
Parameters
----------
value: int
a decimal number
Returns
----------
str : a quadrant
"""
base = 4
q = ""
tmp = int(value)
while tmp >= base:
q = str(tmp % base) + q
tmp = int(tmp / base)
q = str(tmp % base) + q
return q
[docs]def calc_pauli_symbol_from_decimal_number(decimal_number: int, num_qubit: int) -> str:
"""Return the Pauli symbol corresponding to a given decimal number and number of qubit.
Parameters
----------
decimal_number : int
num_qubit: int
Returns
----------
str: a Pauli symbol
"""
quadrant0 = calc_quadrant_from_decimal_number(value=decimal_number)
len_diff = num_qubit - len(quadrant0)
assert len_diff >= 0
quadrant = quadrant0
for i in range(len_diff):
quadrant = "0" + quadrant
symbol = calc_pauli_symbol_from_quadrant(quadrant)
return symbol
[docs]def convert_string_to_strings(s: str) -> List[str]:
l = []
for si in s:
l.append(si)
return l
[docs]def convert_strings_to_string(s_list: List[str]) -> str:
s = ""
for si in s_list:
s = s + si
return s
[docs]def convert_pauli_symbol_to_pauli_indices(symbol: str) -> List[int]:
s_list = convert_string_to_strings(symbol)
indices = []
for s in s_list:
index = convert_1qubit_pauli_symbol_to_pauli_index(s, mode="int")
indices.append(index)
return indices
[docs]def convert_pauli_indices_to_pauli_symbol(indices: List[int]) -> str:
symbol = ""
for index in indices:
s = convert_1qubit_pauli_index_to_pauli_symbol(index)
symbol = symbol + s
return symbol
[docs]def is_no_duplication_list(l: List) -> bool:
res = True
for li in l:
if l.count(li) > 1:
res = False
return res
[docs]def get_permutation_matrix_from_ascending_order(ids: List[int]) -> np.ndarray:
"""Return a permutation matrix that convert soarted(ids) to ids.
Parameters
----------
ids : List[int]
A list of integers, to have no duplication.
Returns
----------
np.ndarray
A permutation matrix that convert the sorted list in the ascending order, sorted(ids), to the original list, ids.
"""
assert is_no_duplication_list(ids)
ids_sorted = sorted(ids)
n = len(ids)
matP = np.zeros((n, n), dtype=int)
for i_sorted, id_sorted in enumerate(ids_sorted):
for i_original, id_original in enumerate(ids):
if id_sorted == id_original:
matP[i_original, i_sorted] = 1
break
return matP
[docs]def permute_pauli_symbol(symbol: str, ids: List[int]) -> str:
assert len(symbol) == len(ids)
pauli_indices = convert_pauli_symbol_to_pauli_indices(symbol)
matP = get_permutation_matrix_from_ascending_order(ids)
pauli_indices_permuted = matP @ np.array(pauli_indices) # .to_list()
symbol_permuted = convert_pauli_indices_to_pauli_symbol(pauli_indices_permuted)
return symbol_permuted
# Gate Toffoli on 3-qubit
[docs]def generate_gate_toffoli_hamiltonian_mat(ids: List[int]) -> np.ndarray:
"""Return the Hamiltonian matrix of the Toffoli gate (Controlled-Controlled-NOT).
:math:`H = \\frac{\\pi}{8} (-III + IIX + IZI - IZX + ZII - ZIX - ZZI + ZZX)`
Parameters
----------
ids : List[int]
ids[0] and ids[1] are for control, and ids[2] is for target.
Returns
----------
np.ndarray((8 8), dtype=np.complex128)
Hamiltonian matrix
"""
assert len(ids) == 3
h = np.zeros((8, 8), dtype=np.complex128)
b = get_pauli_basis(n_qubit=3)
# -III
s = "iii"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += -b[i]
# + IIX
s = "iix"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += b[i]
# + IZI
s = "izi"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += b[i]
# - IZX
s = "izx"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += -b[i]
# + ZII
s = "zii"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += b[i]
# - ZIX
s = "zix"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += -b[i]
# - ZZI
s = "zzi"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += -b[i]
# + ZZX
s = "zzx"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += b[i]
coeff = np.pi * 0.125
h = coeff * h
return h
# Gate Fredkin on 3-qubit
[docs]def generate_gate_fredkin_hamiltonian_mat(ids: List[int]) -> np.ndarray:
"""Return the Hamiltonian matrix of the Fredkin gate (Controlled-SWAP).
:math:`H = \\frac{\\pi}{8} (-III + IXX + IYY + IZZ + ZII - ZXX - ZYY - ZZZ)`
Parameters
----------
ids : List[int]
ids[0] is for control, and ids[1] and ids[2] are for target.
Returns
----------
np.ndarray((8 8), dtype=np.complex128)
Hamiltonian matrix
"""
assert len(ids) == 3
h = np.zeros((8, 8), dtype=np.complex128)
b = get_pauli_basis(n_qubit=3)
# -III
s = "iii"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += -b[i]
# + IXX
s = "ixx"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += b[i]
# + IYY
s = "iyy"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += b[i]
# + IZZ
s = "izz"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += b[i]
# + ZII
s = "zii"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += b[i]
# - ZXX
s = "zxx"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += -b[i]
# - ZYY
s = "zyy"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += -b[i]
# - ZZZ
s = "zzz"
s2 = permute_pauli_symbol(s, ids)
i = calc_decimal_number_from_pauli_symbol(s2)
h += -b[i]
coeff = np.pi * 0.125
h = coeff * h
return h
# 1-qutrit gates
# Base of Hamiltonian
[docs]def calc_base_matrix_1qutrit(levels: Union[str, bool], axis: str) -> np.ndarray:
"""Return a base matrix for 1-qutrit Hamiltonian.
Parameters
----------
axis : str
specifies "i", "x", "y", or "z".
levels : str
specifies levels for the axis, limited to ["01", "12", or "02"] for axis = "x", "y", or "z". levels = None for "i".
Returns
----------
np.ndarray((3,3), dtype=np.complex128)
The base matrix corresponding to the axis and levels, to be complex.
"""
assert axis in ["i", "x", "y", "z"]
if axis == "i":
assert levels == None
method_str = "calc_base_matrix_1qutrit_identity"
else:
assert levels in ["01", "12", "02"]
method_str = "calc_base_matrix_1qutrit_" + axis + "_" + levels
mat = eval(method_str)()
return mat
[docs]def calc_base_matrix_1qutrit_identity() -> np.ndarray:
"""Return the identity matrix on a 1-qutrit system."""
mat = np.eye(3, dtype=np.complex128)
return mat
[docs]def calc_base_matrix_1qutrit_x_01() -> np.ndarray:
"""Return the base matrix corresponding to the x-axis w.r.t. levels 0 and 1."""
l = [[0, 1, 0], [1, 0, 0], [0, 0, 0]]
mat = np.array(l, dtype=np.complex128)
return mat
[docs]def calc_base_matrix_1qutrit_y_01() -> np.ndarray:
"""Return the base matrix corresponding to the y-axis w.r.t. levels 0 and 1."""
l = [[0, -1j, 0], [1j, 0, 0], [0, 0, 0]]
mat = np.array(l, dtype=np.complex128)
return mat
[docs]def calc_base_matrix_1qutrit_z_01() -> np.ndarray:
"""Return the base matrix corresponding to the z-axis w.r.t. levels 0 and 1."""
l = [[1, 0, 0], [0, -1, 0], [0, 0, 0]]
mat = np.array(l, dtype=np.complex128)
return mat
[docs]def calc_base_matrix_1qutrit_x_12() -> np.ndarray:
"""Return the base matrix corresponding to the x-axis w.r.t. levels 1 and 2."""
l = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
mat = np.array(l, dtype=np.complex128)
return mat
[docs]def calc_base_matrix_1qutrit_y_12() -> np.ndarray:
"""Return the base matrix corresponding to the y-axis w.r.t. levels 1 and 2."""
l = [[0, 0, 0], [0, 0, -1j], [0, 1j, 0]]
mat = np.array(l, dtype=np.complex128)
return mat
[docs]def calc_base_matrix_1qutrit_z_12() -> np.ndarray:
"""Return the base matrix corresponding to the z-axis w.r.t. levels 1 and 2."""
l = [[0, 0, 0], [0, 1, 0], [0, 0, -1]]
mat = np.array(l, dtype=np.complex128)
return mat
[docs]def calc_base_matrix_1qutrit_x_02() -> np.ndarray:
"""Return the base matrix corresponding to the x-axis w.r.t. levels 0 and 2."""
l = [[0, 0, 1], [0, 0, 0], [1, 0, 0]]
mat = np.array(l, dtype=np.complex128)
return mat
[docs]def calc_base_matrix_1qutrit_y_02() -> np.ndarray:
"""Return the base matrix corresponding to the y-axis w.r.t. levels 0 and 2."""
l = [[0, 0, -1j], [0, 0, 0], [1j, 0, 0]]
mat = np.array(l, dtype=np.complex128)
return mat
[docs]def calc_base_matrix_1qutrit_z_02() -> np.ndarray:
"""Return the base matrix corresponding to the z-axis w.r.t. levels 0 and 2."""
l = [[1, 0, 0], [0, 0, 0], [0, 0, -1]]
mat = np.array(l, dtype=np.complex128)
return mat
[docs]def get_base_matrices_1qutrit() -> Dict[Tuple[Union[str, bool], str], np.ndarray]:
"""Return the dictionary object containing all base matrices for 1-qutrit Hamiltonian.
Parameters
----------
Returns
----------
Dict[Tuple[str, str], np.ndarray]
The dictionary. The first string of the Tuple is for the levels, "01", "12", or "02". The second string of the Tuple is for the axis, "x", "y", or "z".
For example, dict[("12", "x")] is the base matrix for the x-axis w.r.t. the levels 1 and 2.
"""
levels_list = ["01", "12", "02"]
axis_list = ["x", "y", "z"]
l = []
# i
mat = calc_base_matrix_1qutrit_identity()
l.append(((None, "i"), mat))
# x, y, z
for p in product(levels_list, axis_list):
levels = p[0]
axis = p[1]
mat = calc_base_matrix_1qutrit(levels, axis)
l.append(((levels, axis), mat))
d = dict(l)
return d
# gate_name -> {"levels", "axis", "angle"}
[docs]def calc_levels_axis_angle_from_gate_name_1qutrit_single_gellmann(
gate_name: str,
) -> Dict[str, str]:
"""return dictionary object containing three information for specifying a 1-qutrit Gell-Mann gate.
Parameters
----------
gate_name : str
A name of gate, e.g., "12x90".
Returns
----------
Dict[str, str]
Example: {"levels": "12", "axis": "x", "angle": "90"}
"""
levels = gate_name[0:2]
axis = gate_name[2]
angle = gate_name[3:]
res = {"levels": levels, "axis": axis, "angle": angle}
return res
# "angle" -> float
[docs]def calc_angle_from_str_to_float(angle_str: str) -> float:
"""return angle value from angle string"""
if angle_str == "90":
angle = 0.50 * np.pi
elif angle_str == "m90":
angle = -0.50 * np.pi
elif angle_str == "180":
angle = np.pi
elif angle_str == "m180":
angle = -np.pi
else:
raise ValueError(f"angle_str is invalid!")
return angle
[docs]def calc_coeff_from_angle_str(angle_str: str) -> float:
"return coeff = 0.5 * angle from angle_str."
angle = calc_angle_from_str_to_float(angle_str)
return 0.50 * angle
[docs]def calc_1qutrit_single_gellmann_hamiltonian_mat_from_levels_axis_angle(
levels: str, axis: str, angle: str
) -> np.ndarray:
"""return a 1-qutrit Hamiltonian matrix for the axis, levels, and angle."""
assert axis in ["x", "y", "z"]
assert levels in ["01", "12", "02"]
mat = calc_base_matrix_1qutrit(levels, axis)
coeff = calc_coeff_from_angle_str(angle)
h = coeff * mat
return h
[docs]def generate_gate_1qutrit_single_gellmann_hamiltonian_mat(gate_name: str) -> np.ndarray:
"""return a 1-qutrit Hamiltonian matrix for the gate name."""
res = calc_levels_axis_angle_from_gate_name_1qutrit_single_gellmann(gate_name)
levels = res["levels"]
axis = res["axis"]
angle = res["angle"]
h = calc_1qutrit_single_gellmann_hamiltonian_mat_from_levels_axis_angle(
levels=levels, axis=axis, angle=angle
)
return h
[docs]def generate_gate_1qutrit_single_gellmann_unitary_mat(gate_name: str) -> np.ndarray:
"""return the unitary matrix for the gate."""
h = generate_gate_1qutrit_single_gellmann_hamiltonian_mat(gate_name)
u = expm(-1j * h)
return u
[docs]def generate_gate_1qutrit_single_gellmann_mat(gate_name: str) -> np.ndarray:
"""return the HS matrix for the gate."""
u = generate_gate_1qutrit_single_gellmann_unitary_mat(gate_name)
to_basis = get_normalized_gell_mann_basis()
hs = calc_gate_mat_from_unitary_mat_with_hermitian_basis(
from_u=u, to_basis=to_basis
)
return hs
[docs]def generate_gate_1qutrit_single_gellmann(
c_sys: CompositeSystem, gate_name: str, is_physicality_required: bool = True
) -> Gate:
"""return the Gate for the gate."""
assert len(c_sys.elemental_systems) == 1
assert c_sys.dim == 3
hs = generate_gate_1qutrit_single_gellmann_mat(gate_name)
G = Gate(c_sys=c_sys, hs=hs, is_physicality_required=is_physicality_required)
return G
# 2-qutrit gates
[docs]def get_base_matrix_names_1qutrit() -> List[str]:
"""Return a list of base matrix names for 1-qutrit system."""
l = ["i"]
levels = ["01", "12", "02"]
axis = ["x", "y", "z"]
p = product(levels, axis)
q = [pi[0] + pi[1] for pi in p]
l.extend(q)
return l
[docs]def get_base_matrix_names_2qutrit() -> List[str]:
"""Return a list of base matrix names for 2-qutrit system."""
l = get_base_matrix_names_1qutrit()
p = product(l, repeat=2)
q = [pi[0] + pi[1] for pi in p]
return q
[docs]def get_angles_2qutrit() -> List[str]:
"""Return a list of angles for 2-qutrit gates."""
l = []
l.append("90")
l.append("180")
return l
[docs]def get_gate_names_2qutrit_single_base_matrix() -> List[str]:
"""Return a list of gate names on 2-qutirt system whose Hamiltonian consists of single base matrix."""
base_names = get_base_matrix_names_2qutrit()
base_names.remove("ii")
angles = get_angles_2qutrit()
p = product(base_names, angles)
gate_names = []
for pi in p:
base_name = pi[0]
angle = pi[1]
gate_name = base_name + angle
gate_names.append(gate_name)
return gate_names
[docs]def get_gate_names_2qutrit_two_base_matrices() -> List[str]:
"""Return a list of gate names on 2-qutrit system whose Hamiltonian consists of two base matrices."""
gate_names_single = get_gate_names_2qutrit_single_base_matrix()
gate_names = []
for name1 in gate_names_single:
for name2 in gate_names_single:
if name1 != name2:
name = name1 + "_" + name2
gate_names.append(name)
return gate_names
[docs]def split_gate_name_2qutrit_base_matrices(gate_name: str) -> List[str]:
"""Return a list of gate names that are elements of a given gate name.
Ex. "01x02z90_12yi180" -> ["01x02z90", "12yi180"]
"""
l = gate_name.split("_")
return l
[docs]def split_gate_name_2qutrit_single_base_matrix_into_base_matrix_names_angle(
gate_name: str,
) -> Dict[str, str]:
"""Return base matrix names and angle for a given 2-qutrit single base matrix name.
Parameters
----------
gate_names : str
Ex. "i01x90", "12yi180", "02z12y90"
Returns
----------
Dict[str, str]
key = "base0", "base1", "angle".
Ex.
- {'base0': 'i', 'base1': '01x', 'angle':'90'}
- {'base0': '12y', 'base1': 'i', 'angle':'180'}
- {'base0': '02z', 'base1': '12y', 'angle':'90'}
"""
l = []
a = ""
for s in gate_name:
if s in ["i", "x", "y", "z"]:
a = a + s
l.append(a)
a = ""
else:
a = a + s
l.append(a)
assert len(l) == 3
res = {"base0": l[0], "base1": l[1], "angle": l[2]}
return res
[docs]def calc_hamiltonian_mat_from_gate_name_2qutrit_single_base_matrix(
gate_name: str,
) -> np.ndarray:
"""Return a Hamiltonian matrix for a given name of gate on 2-qutrit system whose Hamiltonian consists of single base matrix.
Parameters
----------
gate_name : str
Returns
----------
np.ndarray(shape=(9,9), dtype=np.complex128)
"""
element = split_gate_name_2qutrit_single_base_matrix_into_base_matrix_names_angle(
gate_name
)
base0 = element["base0"]
base1 = element["base1"]
angle = element["angle"]
# base0
if base0 == "i":
axis = "i"
levels = None
else:
axis = base0[-1]
levels = base0.replace(axis, "")
base_mat0 = calc_base_matrix_1qutrit(levels=levels, axis=axis)
# base1
if base1 == "i":
axis = "i"
levels = None
else:
axis = base1[-1]
levels = base1.replace(axis, "")
base_mat1 = calc_base_matrix_1qutrit(levels=levels, axis=axis)
# angle
angle_coeff = calc_coeff_from_angle_str(angle)
# Hamiltonian
mat = angle_coeff * np.kron(base_mat0, base_mat1)
return mat
[docs]def calc_hamiltonian_mat_from_gate_name_2qutrit_base_matrices(
gate_name: str,
) -> np.ndarray:
"""Return a Hamiltonian matrix that corresponds to a given name of 2-qutirt gate whose Hamiltonian consists of base matrices.
Parameters
----------
gate_name : str
Ex. 01xi90, 12z01y180
Returns
----------
np.ndarray((9, 9), dtype=np.complex128)
A Hamiltonian matrix on 2-qutrit system
"""
mat = np.zeros(shape=(9, 9), dtype=np.complex128)
l = split_gate_name_2qutrit_base_matrices(gate_name)
for li in l:
mati = calc_hamiltonian_mat_from_gate_name_2qutrit_single_base_matrix(li)
mat = mat + mati
return mat
[docs]def generate_gate_2qutrit_hamiltonian_mat_from_gate_name(
gate_name: str, ids: List[int] = None
) -> np.ndarray:
"""Return a Hamiltonian of a 2-qutrit gate for a given gate name.
Parameters
----------
gate_name : str
ids: List[int] = None, Optional
a list of elemental system ids, which specifies their roles such as control or target.
Returns
----------
np.ndarray(shape=(9, 9), dtype=np.complex128)
"""
assert gate_name in get_gate_names_2qutrit()
if ids is None:
ids = []
if gate_name in get_gate_names_2qutrit_base_matrices():
h = calc_hamiltonian_mat_from_gate_name_2qutrit_base_matrices(gate_name)
# add elif here when implement new gates on 2-qutrit
else:
raise ValueError(f"gate_name ias invalid.")
return h