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)
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])
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)
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)
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])
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])
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])
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)
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)