Skip to content

from_ising

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