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(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 tensor(self, other: OperatorBase) -> Union["CircuitOp", TensoredOp]: # pylint: disable=cyclic-import from .pauli_op import PauliOp from .matrix_op import MatrixOp if isinstance(other, (PauliOp, CircuitOp, MatrixOp)): other = other.to_circuit_op() if isinstance(other, CircuitOp): new_qc = QuantumCircuit(self.num_qubits + other.num_qubits) # NOTE!!! REVERSING QISKIT ENDIANNESS HERE new_qc.append(other.to_instruction(), qargs=new_qc.qubits[0:other.primitive.num_qubits]) new_qc.append(self.to_instruction(), qargs=new_qc.qubits[other.primitive.num_qubits:]) new_qc = new_qc.decompose() return CircuitOp(new_qc, coeff=self.coeff * other.coeff) return TensoredOp([self, other])
def convert( self, operator: OperatorBase, params: Optional[Dict[Parameter, Union[float, List[float], List[List[float]]]]] = None, ) -> OperatorBase: r""" Converts the Operator to one in which the CircuitStateFns are replaced by DictStateFns or VectorStateFns. Extracts the CircuitStateFns out of the Operator, caches them, calls ``sample_circuits`` below to get their converted replacements, and replaces the CircuitStateFns in operator with the replacement StateFns. Args: operator: The Operator to convert params: A dictionary mapping parameters to either single binding values or lists of binding values. Returns: The converted Operator with CircuitStateFns replaced by DictStateFns or VectorStateFns. Raises: OpflowError: if extracted circuits are empty. """ # check if the operator should be cached op_id = operator.instance_id # op_id = id(operator) if op_id not in self._cached_ops.keys(): # delete cache if we only want to cache one operator if self._caching == "last": self.clear_cache() # convert to circuit and reduce operator_dicts_replaced = operator.to_circuit_op() self._reduced_op_cache = operator_dicts_replaced.reduce() # extract circuits self._circuit_ops_cache = {} self._extract_circuitstatefns(self._reduced_op_cache) if not self._circuit_ops_cache: raise OpflowError( "Circuits are empty. " "Check that the operator is an instance of CircuitStateFn or its ListOp." ) self._transpiled_circ_cache = None self._transpile_before_bind = True else: # load the cached circuits self._reduced_op_cache = self._cached_ops[op_id].reduced_op_cache self._circuit_ops_cache = self._cached_ops[op_id].circuit_ops_cache self._transpiled_circ_cache = self._cached_ops[op_id].transpiled_circ_cache self._transpile_before_bind = self._cached_ops[op_id].transpile_before_bind self._transpiled_circ_templates = self._cached_ops[op_id].transpiled_circ_templates return_as_list = False if params is not None and len(params.keys()) > 0: p_0 = list(params.values())[0] if isinstance(p_0, (list, np.ndarray)): num_parameterizations = len(p_0) param_bindings = [ {param: value_list[i] for param, value_list in params.items()} # type: ignore for i in range(num_parameterizations) ] return_as_list = True else: num_parameterizations = 1 param_bindings = [params] else: param_bindings = None num_parameterizations = 1 # Don't pass circuits if we have in the cache, the sampling function knows to use the cache circs = list(self._circuit_ops_cache.values()) if not self._transpiled_circ_cache else None p_b = cast(List[Dict[Parameter, float]], param_bindings) sampled_statefn_dicts = self.sample_circuits(circuit_sfns=circs, param_bindings=p_b) def replace_circuits_with_dicts(operator, param_index=0): if isinstance(operator, CircuitStateFn): return sampled_statefn_dicts[id(operator)][param_index] elif isinstance(operator, ListOp): return operator.traverse( partial(replace_circuits_with_dicts, param_index=param_index) ) else: return operator # store the operator we constructed, if it isn't stored already if op_id not in self._cached_ops.keys(): op_cache = OperatorCache() op_cache.reduced_op_cache = self._reduced_op_cache op_cache.circuit_ops_cache = self._circuit_ops_cache op_cache.transpiled_circ_cache = self._transpiled_circ_cache op_cache.transpile_before_bind = self._transpile_before_bind op_cache.transpiled_circ_templates = self._transpiled_circ_templates self._cached_ops[op_id] = op_cache if return_as_list: return ListOp( [ replace_circuits_with_dicts(self._reduced_op_cache, param_index=i) for i in range(num_parameterizations) ] ) else: return replace_circuits_with_dicts(self._reduced_op_cache, param_index=0)