Exemplo n.º 1
0
    def compose(self, other, qargs=None, front=False):
        """Return the composition channel self∘other.

        Args:
            other (SparsePauliOp): an operator object.
            qargs (list or None): a list of subsystem positions to compose other on.
            front (bool or None): If False compose in standard order other(self(input))
                          otherwise compose in reverse order self(other(input))
                          [default: False]

        Returns:
            SparsePauliOp: The composed operator.

        Raises:
            QiskitError: if other cannot be converted to an Operator or has
            incompatible dimensions.
        """
        # pylint: disable=invalid-name
        if qargs is None:
            qargs = getattr(other, 'qargs', None)

        if not isinstance(other, SparsePauliOp):
            other = SparsePauliOp(other)

        # Validate composition dimensions and qargs match
        self._op_shape.compose(other._op_shape, qargs, front)

        # Implement composition of the Pauli table
        x1, x2 = PauliTable._block_stack(self.table.X, other.table.X)
        z1, z2 = PauliTable._block_stack(self.table.Z, other.table.Z)
        c1, c2 = PauliTable._block_stack(self.coeffs, other.coeffs)

        if qargs is not None:
            ret_x, ret_z = x1.copy(), z1.copy()
            x1 = x1[:, qargs]
            z1 = z1[:, qargs]
            ret_x[:, qargs] = x1 ^ x2
            ret_z[:, qargs] = z1 ^ z2
            table = np.hstack([ret_x, ret_z])
        else:
            table = np.hstack((x1 ^ x2, z1 ^ z2))

        # Take product of coefficients and add phase correction
        coeffs = c1 * c2
        # We pick additional phase terms for the products
        # X.Y = i * Z, Y.Z = i * X, Z.X = i * Y
        # Y.X = -i * Z, Z.Y = -i * X, X.Z = -i * Y
        if front:
            plus_i = (x1 & ~z1 & x2 & z2) | (x1 & z1 & ~x2 & z2) | (~x1 & z1
                                                                    & x2 & ~z2)
            minus_i = (x2 & ~z2 & x1 & z1) | (x2 & z2 & ~x1
                                              & z1) | (~x2 & z2 & x1 & ~z1)
        else:
            minus_i = (x1 & ~z1 & x2 & z2) | (x1 & z1 & ~x2
                                              & z2) | (~x1 & z1 & x2 & ~z2)
            plus_i = (x2 & ~z2 & x1 & z1) | (x2 & z2 & ~x1 & z1) | (~x2 & z2
                                                                    & x1 & ~z1)
        coeffs *= 1j**np.array(np.sum(plus_i, axis=1), dtype=int)
        coeffs *= (-1j)**np.array(np.sum(minus_i, axis=1), dtype=int)
        return SparsePauliOp(table, coeffs)
Exemplo n.º 2
0
    def compose(self, other, qargs=None, front=False):
        if qargs is None:
            qargs = getattr(other, "qargs", None)

        if not isinstance(other, SparsePauliOp):
            other = SparsePauliOp(other)

        # Validate composition dimensions and qargs match
        self._op_shape.compose(other._op_shape, qargs, front)

        # Implement composition of the Pauli table
        x1, x2 = PauliTable._block_stack(self.table.X, other.table.X)
        z1, z2 = PauliTable._block_stack(self.table.Z, other.table.Z)
        c1, c2 = PauliTable._block_stack(self.coeffs, other.coeffs)

        if qargs is not None:
            ret_x, ret_z = x1.copy(), z1.copy()
            x1 = x1[:, qargs]
            z1 = z1[:, qargs]
            ret_x[:, qargs] = x1 ^ x2
            ret_z[:, qargs] = z1 ^ z2
            table = np.hstack([ret_x, ret_z])
        else:
            table = np.hstack((x1 ^ x2, z1 ^ z2))

        # Take product of coefficients and add phase correction
        coeffs = c1 * c2
        # We pick additional phase terms for the products
        # X.Y = i * Z, Y.Z = i * X, Z.X = i * Y
        # Y.X = -i * Z, Z.Y = -i * X, X.Z = -i * Y
        if front:
            plus_i = (x1 & ~z1 & x2 & z2) | (x1 & z1 & ~x2 & z2) | (~x1 & z1
                                                                    & x2 & ~z2)
            minus_i = (x2 & ~z2 & x1 & z1) | (x2 & z2 & ~x1
                                              & z1) | (~x2 & z2 & x1 & ~z1)
        else:
            minus_i = (x1 & ~z1 & x2 & z2) | (x1 & z1 & ~x2
                                              & z2) | (~x1 & z1 & x2 & ~z2)
            plus_i = (x2 & ~z2 & x1 & z1) | (x2 & z2 & ~x1 & z1) | (~x2 & z2
                                                                    & x1 & ~z1)
        coeffs *= 1j**np.array(np.sum(plus_i, axis=1), dtype=int)
        coeffs *= (-1j)**np.array(np.sum(minus_i, axis=1), dtype=int)
        return SparsePauliOp(table, coeffs)