def convert(
        self,
        operator: OperatorBase,
        params: Optional[Dict[Union[ParameterExpression, ParameterVector],
                              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. The dictionary can also contain pairs of ParameterVectors with
                lists of parameters or lists of lists of parameters to bind to them.

        Returns:
            The converted Operator with CircuitStateFns replaced by DictStateFns or VectorStateFns.
        """
        if self._last_op is None or id(operator) != id(self._last_op):
            # Clear caches
            self._last_op = operator
            self._reduced_op_cache = None
            self._circuit_ops_cache = None
            self._transpiled_circ_cache = None
            self._transpile_before_bind = True

        if not self._reduced_op_cache:
            operator_dicts_replaced = operator.to_circuit_op()
            self._reduced_op_cache = operator_dicts_replaced.reduce()

        if not self._circuit_ops_cache:
            self._circuit_ops_cache = {}
            self._extract_circuitstatefns(self._reduced_op_cache)

        if params:
            num_parameterizations = len(list(params.values())[0])
            param_bindings = [{
                param: value_list[i]
                for (param, value_list) in params.items()
            } for i in range(num_parameterizations)]
        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
        sampled_statefn_dicts = self.sample_circuits(
            circuit_sfns=circs, param_bindings=param_bindings)

        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

        if params:
            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)
Exemple #2
0
    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:
            AquaError: if extracted circuits are empty.
        """
        if self._last_op is None or id(operator) != id(self._last_op):
            # Clear caches
            self._last_op = operator
            self._reduced_op_cache = None
            self._circuit_ops_cache = None
            self._transpiled_circ_cache = None
            self._transpile_before_bind = True

        if not self._reduced_op_cache:
            operator_dicts_replaced = operator.to_circuit_op()
            self._reduced_op_cache = operator_dicts_replaced.reduce()

        if not self._circuit_ops_cache:
            self._circuit_ops_cache = {}
            self._extract_circuitstatefns(self._reduced_op_cache)
            if not self._circuit_ops_cache:
                raise AquaError(
                    'Circuits are empty. '
                    'Check that the operator is an instance of CircuitStateFn or its ListOp.'
                )

        if params is not None and len(params.keys()) > 0:
            p_0 = list(params.values())[0]  # type: ignore
            if isinstance(p_0, (list, np.ndarray)):
                num_parameterizations = len(cast(List, p_0))
                param_bindings = [
                    {
                        param: value_list[i]  # type: ignore
                        for (param, value_list) in params.items()
                    } for i in range(num_parameterizations)
                ]
            else:
                num_parameterizations = 1
                param_bindings = [params]  # type: ignore

        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

        if params:
            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)