Esempio n. 1
0
    def compose(self,
                other: OperatorBase,
                permutation: Optional[List[int]] = None,
                front: bool = False) -> OperatorBase:

        new_self, other = self._expand_shorter_operator_and_permute(
            other, permutation)
        new_self = cast(ComposedOp, new_self)

        if front:
            return other.compose(new_self)
        # Try composing with last element in list
        if isinstance(other, ComposedOp):
            return ComposedOp(new_self.oplist + other.oplist,
                              coeff=new_self.coeff * other.coeff)

        # Try composing with last element of oplist. We only try
        # this if that last element isn't itself an
        # ComposedOp, so we can tell whether composing the
        # two elements directly worked. If it doesn't,
        # continue to the final return statement below, appending other to the oplist.
        if not isinstance(new_self.oplist[-1], ComposedOp):
            comp_with_last = new_self.oplist[-1].compose(other)
            # Attempt successful
            if not isinstance(comp_with_last, ComposedOp):
                new_oplist = new_self.oplist[0:-1] + [comp_with_last]
                return ComposedOp(new_oplist, coeff=new_self.coeff)

        return ComposedOp(new_self.oplist + [other], coeff=new_self.coeff)
Esempio n. 2
0
    def compose(self,
                other: OperatorBase,
                permutation: Optional[List[int]] = None,
                front: bool = False) -> OperatorBase:
        if not self.is_measurement and not front:
            raise ValueError(
                'Composition with a Statefunctions in the first operand is not defined.'
            )
        new_self, other = self._expand_shorter_operator_and_permute(
            other, permutation)

        if front:
            return other.compose(new_self)

        if isinstance(other, (PauliOp, CircuitOp, MatrixOp)):
            op_circuit_self = CircuitOp(self.primitive)

            # Avoid reimplementing compose logic
            composed_op_circs = cast(
                CircuitOp, op_circuit_self.compose(other.to_circuit_op()))

            # Returning CircuitStateFn
            return CircuitStateFn(composed_op_circs.primitive,
                                  is_measurement=self.is_measurement,
                                  coeff=self.coeff * other.coeff)

        if isinstance(other, CircuitStateFn) and self.is_measurement:
            # pylint: disable=cyclic-import
            from ..operator_globals import Zero
            return self.compose(CircuitOp(
                other.primitive, other.coeff)).compose(Zero ^ self.num_qubits)

        return ComposedOp([new_self, other])
Esempio n. 3
0
    def compose(
        self, other: OperatorBase, permutation: Optional[List[int]] = None, front: bool = False
    ) -> OperatorBase:

        new_self, other = self._expand_shorter_operator_and_permute(other, permutation)
        new_self = cast(PauliOp, new_self)

        if front:
            return other.compose(new_self)
        # If self is identity, just return other.
        if not any(new_self.primitive.x + new_self.primitive.z):
            return other * new_self.coeff

        # Both Paulis
        if isinstance(other, PauliOp):
            product = new_self.primitive.dot(other.primitive)
            return PrimitiveOp(product, coeff=new_self.coeff * other.coeff)

        # pylint: disable=cyclic-import
        from .pauli_sum_op import PauliSumOp

        if isinstance(other, PauliSumOp):
            return PauliSumOp(
                SparsePauliOp(new_self.primitive).dot(other.primitive),
                coeff=new_self.coeff * other.coeff,
            )

        # pylint: disable=cyclic-import
        from ..state_fns.circuit_state_fn import CircuitStateFn
        from .circuit_op import CircuitOp

        if isinstance(other, (CircuitOp, CircuitStateFn)):
            return new_self.to_circuit_op().compose(other)

        return super(PauliOp, new_self).compose(other)
Esempio n. 4
0
    def compose(self,
                other: OperatorBase,
                permutation: Optional[List[int]] = None,
                front: bool = False) -> OperatorBase:

        new_self, other = self._expand_shorter_operator_and_permute(
            other, permutation)
        new_self = cast(CircuitOp, new_self)

        if front:
            return other.compose(new_self)
        # pylint: disable=cyclic-import
        from ..operator_globals import Zero
        from ..state_fns import CircuitStateFn
        from .pauli_op import PauliOp
        from .matrix_op import MatrixOp

        if other == Zero ^ new_self.num_qubits:
            return CircuitStateFn(new_self.primitive, coeff=new_self.coeff)

        if isinstance(other, (PauliOp, CircuitOp, MatrixOp)):
            other = other.to_circuit_op()

        if isinstance(other, (CircuitOp, CircuitStateFn)):
            new_qc = other.primitive.compose(new_self.primitive)
            if isinstance(other, CircuitStateFn):
                return CircuitStateFn(new_qc,
                                      is_measurement=other.is_measurement,
                                      coeff=new_self.coeff * other.coeff)
            else:
                return CircuitOp(new_qc, coeff=new_self.coeff * other.coeff)

        return super(CircuitOp, new_self).compose(other)
Esempio n. 5
0
    def compose(self, other: OperatorBase,
                permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase:
        new_self, other = self._expand_shorter_operator_and_permute(other, permutation)
        if front:
            return other.compose(new_self)
        if isinstance(other, ComposedOp):
            return ComposedOp([new_self] + other.oplist)

        return ComposedOp([new_self, other])
Esempio n. 6
0
    def compose(self, other: OperatorBase,
                permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase:

        new_self, other = self._expand_shorter_operator_and_permute(other, permutation)
        new_self = cast(ListOp, new_self)

        if front:
            return other.compose(new_self)
        # Avoid circular dependency
        # pylint: disable=cyclic-import
        from .composed_op import ComposedOp
        return ComposedOp([new_self, other])
Esempio n. 7
0
    def compose(self,
                other: OperatorBase,
                permutation: Optional[List[int]] = None,
                front: bool = False) -> OperatorBase:
        r"""
        Composition (Linear algebra-style: A@B(x) = A(B(x))) is not well defined for states
        in the binary function model, but is well defined for measurements.

        Args:
            other: The Operator to compose with self.
            permutation: ``List[int]`` which defines permutation on other operator.
            front: If front==True, return ``other.compose(self)``.

        Returns:
            An Operator equivalent to the function composition of self and other.

        Raises:
            ValueError: If self is not a measurement, it cannot be composed from the right.
        """
        # TODO maybe allow outers later to produce density operators or projectors, but not yet.
        if not self.is_measurement and not front:
            raise ValueError(
                "Composition with a Statefunction in the first operand is not defined."
            )

        new_self, other = self._expand_shorter_operator_and_permute(
            other, permutation)

        if front:
            return other.compose(self)
        # TODO maybe include some reduction here in the subclasses - vector and Op, op and Op, etc.
        from ..primitive_ops.circuit_op import CircuitOp

        if self.primitive == {
                "0" * self.num_qubits: 1.0
        } and isinstance(other, CircuitOp):
            # Returning CircuitStateFn
            return StateFn(other.primitive,
                           is_measurement=self.is_measurement,
                           coeff=self.coeff * other.coeff)

        from ..list_ops.composed_op import ComposedOp

        if isinstance(other, ComposedOp):
            return ComposedOp([new_self] + other.oplist,
                              coeff=new_self.coeff * other.coeff)

        return ComposedOp([new_self, other])
Esempio n. 8
0
    def compose(
        self, other: OperatorBase, permutation: Optional[List[int]] = None, front: bool = False
    ) -> OperatorBase:

        new_self, other = self._expand_shorter_operator_and_permute(other, permutation)
        new_self = cast(MatrixOp, new_self)

        if front:
            return other.compose(new_self)
        if isinstance(other, MatrixOp):
            return MatrixOp(
                new_self.primitive.compose(other.primitive, front=True),
                coeff=new_self.coeff * other.coeff,
            )

        return super(MatrixOp, new_self).compose(other)
Esempio n. 9
0
    def compose(
        self,
        other: OperatorBase,
        permutation: Optional[List[int]] = None,
        front: bool = False,
    ) -> OperatorBase:

        new_self, other = self._expand_shorter_operator_and_permute(
            other, permutation)
        new_self = cast(PauliSumOp, new_self)

        if front:
            return other.compose(new_self)
        # If self is identity, just return other.
        if not np.any(
                np.logical_or(new_self.primitive.paulis.x,
                              new_self.primitive.paulis.z)):
            return other * new_self.coeff * sum(new_self.primitive.coeffs)

        # Both PauliSumOps
        if isinstance(other, PauliSumOp):
            return PauliSumOp(
                new_self.primitive.dot(other.primitive),
                coeff=new_self.coeff * other.coeff,
            )
        if isinstance(other, PauliOp):
            other_primitive = SparsePauliOp(other.primitive)
            return PauliSumOp(
                new_self.primitive.dot(other_primitive),
                coeff=new_self.coeff * other.coeff,
            )

        # pylint: disable=cyclic-import
        from ..state_fns.circuit_state_fn import CircuitStateFn
        from .circuit_op import CircuitOp

        if isinstance(other, (CircuitOp, CircuitStateFn)):
            pauli_op = cast(Union[PauliOp, SummedOp], new_self.to_pauli_op())
            return pauli_op.to_circuit_op().compose(other)

        return super(PauliSumOp, new_self).compose(other)