Create a quadratic program from a qubit operator and a shift value.
Variables are mapped to qubits in the same order, i.e.,
i-th variable is mapped to i-th qubit.
See https://github.com/Qiskit/qiskit-terra/issues/1148 for details.
Parameters:
| Name |
Type |
Description |
Default |
qubit_op |
BaseOperator
|
The qubit operator of the problem.
|
required
|
offset |
float
|
The constant term in the Ising Hamiltonian.
|
0.0
|
linear |
bool
|
If linear is True, :math:x^2 is treated as a linear term
since :math:x^2 = x for :math:x \in \{0,1\}.
Otherwise, :math:x^2 is treat as a quadratic term.
The default value is False.
|
False
|
Returns:
| Type |
Description |
QuadraticProgram
|
The quadratic program corresponding to the qubit operator.
|
Raises:
| Type |
Description |
QiskitOptimizationError
|
if there are Pauli Xs or Ys in any Pauli term
|
QiskitOptimizationError
|
if there are more than 2 Pauli Zs in any Pauli term
|
QiskitOptimizationError
|
if any Pauli term has an imaginary coefficient
|
Source code in q3as/quadratic/translators/ising.py
| def from_ising(
qubit_op: BaseOperator,
offset: float = 0.0,
linear: bool = False,
) -> QuadraticProgram:
r"""Create a quadratic program from a qubit operator and a shift value.
Variables are mapped to qubits in the same order, i.e.,
i-th variable is mapped to i-th qubit.
See https://github.com/Qiskit/qiskit-terra/issues/1148 for details.
Args:
qubit_op: The qubit operator of the problem.
offset: The constant term in the Ising Hamiltonian.
linear: If linear is True, :math:`x^2` is treated as a linear term
since :math:`x^2 = x` for :math:`x \in \{0,1\}`.
Otherwise, :math:`x^2` is treat as a quadratic term.
The default value is False.
Returns:
The quadratic program corresponding to the qubit operator.
Raises:
QiskitOptimizationError: if there are Pauli Xs or Ys in any Pauli term
QiskitOptimizationError: if there are more than 2 Pauli Zs in any Pauli term
QiskitOptimizationError: if any Pauli term has an imaginary coefficient
"""
# quantum_info
if isinstance(qubit_op, BaseOperator):
if not isinstance(qubit_op, SparsePauliOp):
qubit_op = SparsePauliOp.from_operator(Operator(qubit_op))
quad_prog = QuadraticProgram()
quad_prog.binary_var_list(qubit_op.num_qubits)
# prepare a matrix of coefficients of Pauli terms
# `pauli_coeffs_diag` is the diagonal part
# `pauli_coeffs_triu` is the upper triangular part
pauli_coeffs_diag = [0.0] * qubit_op.num_qubits
pauli_coeffs_triu = {}
for pauli_op in qubit_op:
pauli = pauli_op.paulis[0]
coeff = pauli_op.coeffs[0]
if not math.isclose(coeff.imag, 0.0, abs_tol=1e-10):
raise QiskitOptimizationError(f"Imaginary coefficient exists: {pauli_op}")
if np.any(pauli.x):
raise QiskitOptimizationError(
f"Pauli X or Y exists in the Pauli term: {pauli}"
)
# indices of Pauli Zs in the Pauli term
z_index = np.where(pauli.z)[0]
num_z = len(z_index)
if num_z == 0:
offset += coeff.real
elif num_z == 1:
pauli_coeffs_diag[z_index[0]] = coeff.real
elif num_z == 2:
pauli_coeffs_triu[z_index[0], z_index[1]] = coeff.real
else:
raise QiskitOptimizationError(
f"There are more than 2 Pauli Zs in the Pauli term: {pauli}"
)
linear_terms = {}
quadratic_terms = {}
# For quadratic pauli terms of operator
# x_i * x_j = (1 - Z_i - Z_j + Z_i * Z_j)/4
for (i, j), weight in pauli_coeffs_triu.items():
# Add a quadratic term to the objective function of `QuadraticProgram`
# The coefficient of the quadratic term in `QuadraticProgram` is
# 4 * weight of the pauli
quadratic_terms[i, j] = 4 * weight
pauli_coeffs_diag[i] += weight
pauli_coeffs_diag[j] += weight
offset -= weight
# After processing quadratic pauli terms, only linear paulis are left
# x_i = (1 - Z_i)/2
for i, weight in enumerate(pauli_coeffs_diag):
# Add a linear term to the objective function of `QuadraticProgram`
# The coefficient of the linear term in `QuadraticProgram` is
# 2 * weight of the pauli
if linear:
linear_terms[i] = -2 * weight
else:
quadratic_terms[i, i] = -2 * weight
offset += weight
quad_prog.minimize(constant=offset, linear=linear_terms, quadratic=quadratic_terms)
return quad_prog
|