def test_without_quilc_compilation(
    mock_qpu_implementer: Any, parametric_circuit_with_params: Tuple[cirq.Circuit, cirq.Sweepable]
) -> None:
    """test execution without quilc compilation treats the transformed cirq
    Circuit as native quil and does not pass it through quilc.
    """

    parametric_circuit, sweepable = parametric_circuit_with_params
    repetitions = 2

    param_resolvers = [r for r in cirq.to_resolvers(sweepable)]
    expected_results = [
        np.ones((repetitions,)) * (params["t"] if "t" in params else i)
        for i, params in enumerate(param_resolvers)
    ]

    quantum_computer = mock_qpu_implementer.implement_passive_quantum_computer_with_results(
        expected_results
    )
    results = executors.without_quilc_compilation(
        quantum_computer=quantum_computer,
        circuit=parametric_circuit,
        resolvers=param_resolvers,  # noqa
        repetitions=repetitions,
    )
    assert len(param_resolvers) == len(results)
    assert 0 == quantum_computer.compiler.quil_to_native_quil.call_count
    assert len(param_resolvers) == quantum_computer.compiler.native_quil_to_executable.call_count

    for i, result in enumerate(results):
        result = results[i]
        assert param_resolvers[i] == result.params
        assert np.allclose(
            result.measurements["m"], expected_results[i]
        ), "should return an ordered list of results with correct set of measurements"
def test_with_quilc_compilation_and_cirq_parameter_resolution(
    mock_qpu_implementer: Any, parametric_circuit_with_params: Tuple[cirq.Circuit, cirq.Sweepable]
) -> None:
    """test that execution with quilc compilation and cirq parameter resolution calls
    ``quil_to_native_quil`` and ``native_quil_to_executable`` for each parameter
    resolver.
    """

    parametric_circuit, sweepable = parametric_circuit_with_params
    repetitions = 2

    param_resolvers = [r for r in cirq.to_resolvers(sweepable)]
    expected_results = [
        np.ones((repetitions,)) * (params["t"] if "t" in params else i)
        for i, params in enumerate(param_resolvers)
    ]
    quantum_computer = mock_qpu_implementer.implement_passive_quantum_computer_with_results(
        expected_results
    )
    results = executors.with_quilc_compilation_and_cirq_parameter_resolution(
        quantum_computer=quantum_computer,
        circuit=parametric_circuit,
        resolvers=param_resolvers,  # ignore: type
        repetitions=repetitions,
    )
    assert len(param_resolvers) == len(results)
    assert len(param_resolvers) == quantum_computer.compiler.quil_to_native_quil.call_count
    assert len(param_resolvers) == quantum_computer.compiler.native_quil_to_executable.call_count

    for i, result in enumerate(results):
        result = results[i]
        assert param_resolvers[i] == result.params
        assert np.allclose(
            result.measurements["m"], expected_results[i]
        ), "should return an ordered list of results with correct set of measurements"
Beispiel #3
0
    def run_sweep(
        self, program: cirq.AbstractCircuit, params: cirq.Sweepable, repetitions: int = 1
    ) -> List[cirq.Result]:
        """Samples from the given Circuit.

        In contrast to run, this allows for sweeping over different parameter
        values.

        Args:
            program: The circuit to simulate.
            Should be generated using AQTSampler.generate_circuit_from_list
            params: Parameters to run with the program.
            repetitions: The number of repetitions to simulate.

        Returns:
            Result list for this run; one for each possible parameter
            resolver.
        """
        # TODO: Use measurement name from circuit.
        # Github issue: https://github.com/quantumlib/Cirq/issues/2199
        meas_name = 'm'
        assert isinstance(program.device, cirq.IonDevice)
        trial_results = []  # type: List[cirq.Result]
        for param_resolver in cirq.to_resolvers(params):
            id_str = uuid.uuid1()
            num_qubits = len(program.device.qubits)
            json_str = self._generate_json(circuit=program, param_resolver=param_resolver)
            results = self._send_json(
                json_str=json_str, id_str=id_str, repetitions=repetitions, num_qubits=num_qubits
            )
            results = results.astype(bool)
            res_dict = {meas_name: results}
            trial_results.append(cirq.Result(params=param_resolver, measurements=res_dict))
        return trial_results
Beispiel #4
0
    def compute_amplitudes_sweep(
        self,
        program: cirq.Circuit,
        bitstrings: Sequence[int],
        params: cirq.Sweepable,
        qubit_order: cirq.QubitOrderOrList = cirq.QubitOrder.DEFAULT,
    ) -> Sequence[Sequence[complex]]:

        if not isinstance(program, qsimc.QSimCircuit):
            program = qsimc.QSimCircuit(program)

        n_qubits = len(program.all_qubits())
        # qsim numbers qubits in reverse order from cirq
        bitstrings = [
            format(bitstring, "b").zfill(n_qubits)[::-1]
            for bitstring in bitstrings
        ]

        options = {"i": "\n".join(bitstrings)}
        options.update(self.qsimh_options)
        param_resolvers = cirq.to_resolvers(params)

        trials_results = []
        for prs in param_resolvers:

            solved_circuit = cirq.resolve_parameters(program, prs)

            options["c"], _ = solved_circuit.translate_cirq_to_qsim(
                qubit_order)

            options.update(self.qsimh_options)
            amplitudes = qsim.qsimh_simulate(options)
            trials_results.append(amplitudes)

        return trials_results
def _build_service_results(
    mock_qpu_implementer: Any,
    circuit: cirq.Circuit,
    sweepable: cirq.Sweepable,
    *,
    executor: executors.CircuitSweepExecutor = _default_executor,
    transformer: transformers.CircuitTransformer = transformers.default,
) -> Tuple[Sequence[cirq.Result], QuantumComputer,
           List["np.ndarray[Any, np.dtype[np.float_]]"],
           List[cirq.ParamResolver], ]:
    repetitions = 2
    param_resolvers = [r for r in cirq.to_resolvers(sweepable)]
    param_resolver_index = min(1, len(param_resolvers) - 1)
    param_resolver = param_resolvers[param_resolver_index]

    expected_results = [
        np.ones(
            (repetitions, )) * (param_resolver["t"] if "t" in param_resolver
                                else param_resolver_index)
    ]
    quantum_computer = mock_qpu_implementer.implement_passive_quantum_computer_with_results(
        expected_results)
    service = RigettiQCSService(quantum_computer=quantum_computer,
                                executor=executor,
                                transformer=transformer)

    result = service.run(circuit=circuit,
                         param_resolver=param_resolver,
                         repetitions=repetitions)
    return [result], quantum_computer, expected_results, [param_resolver]
Beispiel #6
0
    def run_sweep(
        self,
        program: cirq.AbstractCircuit,
        params: cirq.Sweepable,
        repetitions: int = 1,
    ) -> Sequence[cirq.Result]:
        """Runs a sweep for the given Circuit.

        Note that this creates jobs for each of the sweeps in the given sweepable, and then
        blocks until all of the jobs are complete.

        See `cirq.Sampler` for documentation on args.

        For use of the `sample` method, see the documentation of `cirq.Sampler`.
        """
        resolvers = [r for r in cirq.to_resolvers(params)]
        jobs = [
            self._service.create_job(
                circuit=cirq.resolve_parameters(program, resolver),
                repetitions=repetitions,
                target=self._target,
            )
            for resolver in resolvers
        ]
        job_results = [job.results() for job in jobs]
        cirq_results = []
        for result, params in zip(job_results, resolvers):
            if isinstance(result, results.QPUResult):
                cirq_results.append(result.to_cirq_result(params=params))
            else:
                cirq_results.append(result.to_cirq_result(params=params, seed=self._seed))
        return cirq_results
Beispiel #7
0
    def run_sweep(self,
                  program: cirq.AbstractCircuit,
                  params: cirq.Sweepable,
                  repetitions: int = 1) -> Sequence[cirq.Result]:
        """This will evaluate results on the circuit for every set of parameters in `params`.

        Args:
            program: Circuit to evaluate for each set of parameters in `params`.
            params: `cirq.Sweepable` of parameters which this function passes to
                `cirq.protocols.resolve_parameters` for evaluating the circuit.
            repetitions: Number of times to run each iteration through the `params`. For a given
                set of parameters, the `cirq.Result` will include a measurement for each repetition.

        Returns:
            A list of `cirq.Result` s.
        """

        resolvers = [r for r in cirq.to_resolvers(params)]
        return self.executor(
            quantum_computer=self._quantum_computer,
            circuit=program.unfreeze(copy=False),
            resolvers=resolvers,
            repetitions=repetitions,
            transformer=self.transformer,
        )
def _build_sampler_results(
    mock_qpu_implementer: Any,
    circuit: cirq.Circuit,
    sweepable: cirq.Sweepable,
    *,
    executor: executors.CircuitSweepExecutor = _default_executor,
    transformer: transformers.CircuitTransformer = transformers.default,
) -> Tuple[Sequence[cirq.Result], QuantumComputer,
           List["np.ndarray[Any, np.dtype[np.float_]]"], cirq.Sweepable, ]:
    repetitions = 2

    param_resolvers = [r for r in cirq.to_resolvers(sweepable)]
    expected_results = [
        np.ones((repetitions, )) * (params["t"] if "t" in params else i)
        for i, params in enumerate(param_resolvers)
    ]
    quantum_computer = mock_qpu_implementer.implement_passive_quantum_computer_with_results(
        expected_results)
    service = RigettiQCSService(quantum_computer=quantum_computer,
                                executor=executor,
                                transformer=transformer)

    sampler = service.sampler()

    results = sampler.run_sweep(program=circuit,
                                params=param_resolvers,
                                repetitions=repetitions)
    return results, quantum_computer, expected_results, param_resolvers
Beispiel #9
0
def estimate_run_sweep_time(
    program: cirq.AbstractCircuit,
    params: cirq.Sweepable = None,
    repetitions: int = 1000,
    latency: Optional[float] = _BASE_LATENCY,
) -> float:
    """Compute the estimated time for running a parameter sweep across a single Circuit.

    This should approximate, in seconds, the time for the execution of a batch of circuits
    using Engine.run_sweep() on QCS at a time where there is no queue (such as a reserved slot).
    This estimation should be considered a rough approximation.  Many factors can contribute to
    the execution time of a circuit, and the run time can also vary as the service's code changes
    frequently.

    Args:
        program: circuit to be executed
        params: a parameter sweep of variable resolvers to use with the circuit
        repetitions: number of repetitions to execute per parameter sweep
        latency: Optional latency to add (defaults to 1.5 seconds)
    """
    width = len(program.all_qubits())
    depth = len(program)
    sweeps = len(list(cirq.to_resolvers(params)))
    return _estimate_run_time_seconds(width, depth, sweeps, repetitions,
                                      latency)
Beispiel #10
0
def _verify_reps(
    sweeps: Sequence[cirq.Sweepable],
    repetitions: Union[int, List[int]],
    max_repetitions: int = MAX_TOTAL_REPETITIONS,
) -> None:
    """Verify that the total number of repetitions is under the limit."""
    total_reps = 0
    for idx, sweep in enumerate(sweeps):
        if isinstance(repetitions, List):
            total_reps += len(list(
                cirq.to_resolvers(sweep))) * repetitions[idx]
        else:
            total_reps += len(list(cirq.to_resolvers(sweep))) * repetitions
    if total_reps > max_repetitions:
        raise RuntimeError(
            f'No requested processors currently support the number of requested total repetitions.'
        )
Beispiel #11
0
 def run_sweep(
     self, program: 'cirq.AbstractCircuit', params: 'cirq.Sweepable', repetitions: int = 1
 ) -> Sequence['cirq.Result']:
     results: List[cirq.Result] = []
     for param_resolver in cirq.to_resolvers(params):
         resolved_circuit = cirq.resolve_parameters(program, param_resolver)
         measurements = self._run(resolved_circuit, repetitions=repetitions)
         results.append(cirq.ResultDict(params=param_resolver, measurements=measurements))
     return results
Beispiel #12
0
 def run_sweep(self, program, params, repetitions):
     """Returns all ones in the correct sample shape."""
     return [
         cirq.TrialResult(
             params=param,
             measurements={
                 'tfq':
                     np.array([[1] * len(program.all_qubits())] *
                              repetitions,
                              dtype=np.int32),
             }) for param in cirq.to_resolvers(params)
     ]
    def __init__(self, *, circuit: cirq.Circuit, parameter: str,
                 values: Sequence[float], repetitions: int):
        self.next_index = 0
        self.circuit = circuit
        self.sweep = cirq.Points(parameter, values)
        self.resolvers = list(cirq.to_resolvers(self.sweep))
        self.reps = repetitions

        self.unstarted_xs = list(values)
        self.started_xs: List[float] = []
        self.result_xs: List[float] = []
        self.result_ys: Mapping[str, List[float]] = collections.defaultdict(
            list)

        self.fig = plt.figure()
        self.last_redraw_time = time.monotonic()
Beispiel #14
0
def estimate_run_batch_time(
    programs: Sequence[cirq.AbstractCircuit],
    params_list: List[cirq.Sweepable],
    repetitions: int = 1000,
    latency: float = _BASE_LATENCY,
) -> float:
    """Compute the estimated time for running a batch of programs.

    This should approximate, in seconds, the time for the execution of a batch of circuits
    using Engine.run_batch() on QCS at a time where there is no queue (such as a reserved slot).
    This estimation should be considered a rough approximation.  Many factors can contribute to
    the execution time of a circuit, and the run time can also vary as the service's code changes
    frequently.

    Args:
        programs: a sequence of circuits to be executed
        params_list: a parameter sweep for each circuit
        repetitions: number of repetitions to execute per parameter sweep
        latency: Optional latency to add (defaults to 1.5 seconds)
    """
    total_time = 0.0
    current_width = None
    total_depth = 0
    total_sweeps = 0
    num_circuits = 0
    for idx, program in enumerate(programs):
        width = len(program.all_qubits())
        if width != current_width:
            if num_circuits > 0:
                total_time += _estimate_run_time_seconds(
                    width, total_depth // num_circuits, total_sweeps,
                    repetitions, 0.25)
            num_circuits = 0
            total_depth = 0
            total_sweeps = 0
            current_width = width
        total_depth += len(program)
        num_circuits += 1
        total_sweeps += len(list(cirq.to_resolvers(params_list[idx])))
    if num_circuits > 0:
        total_time += _estimate_run_time_seconds(width,
                                                 total_depth // num_circuits,
                                                 total_sweeps, repetitions,
                                                 0.0)

    return total_time + latency
Beispiel #15
0
def test_with_quilc_parametric_compilation(
    mock_qpu_implementer: Any,
    parametric_circuit_with_params: Tuple[cirq.Circuit, cirq.Linspace],
    pass_dict: bool,
) -> None:
    """test that execution with quilc parametric compilation only compiles only once and
    parameters are properly resolved before execution.
    """

    parametric_circuit, sweepable = parametric_circuit_with_params
    repetitions = 2

    param_resolvers: List[Union[cirq.ParamResolver, cirq.ParamDictType]]
    if pass_dict:
        param_resolvers = [params.param_dict for params in sweepable]
    else:
        param_resolvers = [r for r in cirq.to_resolvers(sweepable)]
    expected_results = [
        np.ones((repetitions, )) * (params["t"] if "t" in params else i)
        for i, params in enumerate(param_resolvers)
    ]
    quantum_computer = mock_qpu_implementer.implement_passive_quantum_computer_with_results(
        expected_results)
    results = executors.with_quilc_parametric_compilation(
        quantum_computer=quantum_computer,
        circuit=parametric_circuit,
        resolvers=param_resolvers,  # noqa
        repetitions=repetitions,
    )
    assert len(param_resolvers) == len(results)
    assert 1 == quantum_computer.compiler.quil_to_native_quil.call_count
    assert 1 == quantum_computer.compiler.native_quil_to_executable.call_count

    for i, result in enumerate(results):
        result = results[i]
        assert param_resolvers[i] == result.params
        assert np.allclose(
            result.measurements["m"],
            expected_results[i],
        ), "should return an ordered list of results with correct set of measurements"
Beispiel #16
0
def test_invalid_pyquil_region_measurement(
    mock_qpu_implementer: Any,
    parametric_circuit_with_params: Tuple[cirq.Circuit, cirq.Sweepable],
) -> None:
    """test that executors raise `ValueError` if the measurement_id_map
    does not exist.
    """

    parametric_circuit, sweepable = parametric_circuit_with_params
    repetitions = 2

    param_resolvers = [r for r in cirq.to_resolvers(sweepable)]
    expected_results = [
        np.ones((repetitions, )) * (params["t"] if "t" in params else i)
        for i, params in enumerate(param_resolvers)
    ]
    quantum_computer = mock_qpu_implementer.implement_passive_quantum_computer_with_results(
        expected_results)

    def broken_hook(
            program: Program,
            measurement_id_map: Dict[str,
                                     str]) -> Tuple[Program, Dict[str, str]]:
        return program, {
            cirq_key: f'{cirq_key}-doesnt-exist'
            for cirq_key in measurement_id_map
        }

    transformer = circuit_transformers.build(
        post_transformation_hooks=[broken_hook],  # type: ignore
    )

    with pytest.raises(ValueError):
        _ = executors.with_quilc_compilation_and_cirq_parameter_resolution(
            transformer=transformer,
            quantum_computer=quantum_computer,
            circuit=parametric_circuit,
            resolvers=param_resolvers,  # ignore: type
            repetitions=repetitions,
        )
Beispiel #17
0
    def run_sweep(
        self,
        program: cirq.Circuit,
        params: cirq.Sweepable,
        repetitions: int = 1,
    ) -> list[cirq.Result]:
        # verify that qubit_mapping covers all qubits in the circuit
        circuit_qubits = set(qubit.name for qubit in program.all_qubits())
        diff = circuit_qubits - set(self._qubit_mapping)
        if diff:
            raise ValueError(
                f'The qubits {diff} are not found in the provided qubit mapping.'
            )

        # apply qubit_mapping
        qubit_map = {
            cirq.NamedQubit(k): cirq.NamedQubit(v)
            for k, v in self._qubit_mapping.items()
        }
        mapped = program.transform_qubits(qubit_map)

        # validate the circuit for the device
        # check that the circuit connectivity fits in the device connectivity
        self._device.validate_circuit(mapped)

        resolvers = list(cirq.to_resolvers(params))

        circuits = [
            cirq.protocols.resolve_parameters(program, res)
            for res in resolvers
        ] if resolvers else [program]

        measurements = self._send_circuits(circuits, repetitions=repetitions)
        return [
            study.ResultDict(params=res, measurements=mes)
            for res, mes in zip(resolvers, measurements)
        ]
Beispiel #18
0
    def run_sweep(
        self,
        program: cirq.Circuit,
        params: cirq.Sweepable,
        repetitions: int = 1,
    ) -> List[cirq.Result]:
        trial_results: List[cirq.Result] = []
        for param_resolver in cirq.to_resolvers(params):
            # Request samples from stim.
            instance = cirq.resolve_parameters(program, param_resolver)
            converted_circuit, key_ranges = cirq_circuit_to_stim_data(instance)
            samples = converted_circuit.compile_sampler().sample(repetitions)

            # Convert unlabelled samples into keyed results.
            k = 0
            measurements = {}
            for key, length in key_ranges:
                p = k
                k += length
                measurements[key] = samples[:, p:k]
            trial_results.append(
                cirq.Result(params=param_resolver, measurements=measurements))

        return trial_results
Beispiel #19
0
def test_to_resolvers_iterable_sweeps():
    sweeps = [cirq.Linspace('a', 0, 1, 10), cirq.Linspace('b', 0, 1, 10)]
    assert cirq.to_resolvers(sweeps) == list(itertools.chain(*sweeps))
Beispiel #20
0
def test_to_resolvers_iterable():
    resolvers = [cirq.ParamResolver({'a': 2}), cirq.ParamResolver({'a': 1})]
    assert cirq.to_resolvers(resolvers) == resolvers
Beispiel #21
0
def test_to_resolvers_none():
    assert list(cirq.to_resolvers(None)) == [cirq.ParamResolver({})]
Beispiel #22
0
def test_to_resolvers_single():
    resolver = cirq.ParamResolver({})
    assert cirq.to_resolvers(resolver) == [resolver]
Beispiel #23
0
    def simulate_expectation_values_sweep(
        self,
        program: 'cirq.Circuit',
        observables: Union['cirq.PauliSum', List['cirq.PauliSum']],
        params: 'cirq.Sweepable',
        qubit_order: cirq.QubitOrderOrList = cirq.QubitOrder.DEFAULT,
        initial_state: Any = None,
        permit_terminal_measurements: bool = True,
    ) -> List[List[float]]:
        """Simulates the supplied circuit and calculates exact expectation
        values for the given observables on its final state, sweeping over the
        given params.
        This method has no perfect analogy in hardware. Instead compare with
        Sampler.sample_expectation_values, which calculates estimated
        expectation values by sampling multiple times.
        Args:
            program: The circuit to simulate.
            observables: An observable or list of observables.
            params: Parameters to run with the program.
            qubit_order: Determines the canonical ordering of the qubits. This
                is often used in specifying the initial state, i.e. the
                ordering of the computational basis states.
            initial_state: The initial state for the simulation. The form of
                this state depends on the simulation implementation. See
                documentation of the implementing class for details.
            permit_terminal_measurements: If the provided circuit ends in a
                measurement, this method will generate an error unless this
                is set to True. This is meant to prevent measurements from
                ruining expectation value calculations.
        Returns:
            A list of expectation-value lists. The outer index determines the
            sweep, and the inner index determines the observable. For instance,
            results[1][3] would select the fourth observable measured in the
            second sweep.
        Raises:
            ValueError if 'program' has terminal measurement(s) and
            'permit_terminal_measurements' is False.
        """

        if len(program.all_qubits()) < 26:
            raise ValueError(
                'Expectations are currently only supported on num_qubits'
                ' >= 26')
        if qubit_order is not cirq.QubitOrder.DEFAULT:
            raise ValueError(
                'A non-default qubit order is currently not supported')
        if initial_state is not None:
            raise ValueError('An initial state is currently not supported')
        if permit_terminal_measurements is not True:
            raise ValueError('Terminal measurements are always allowed and'
                             ' will always be removed automatically')
        if not isinstance(observables, cirq.PauliSum):
            if not all([isinstance(op, cirq.PauliSum) for op in observables]):
                raise TypeError(
                    'Observables must be Union[cirq.PauliSum, Iterable[cirq.PauliSum]]'
                )

        expectation_values = []
        for param_resolver in cirq.to_resolvers(params):
            expectation_values.append(
                self._expectation(
                    circuit=program,
                    observables=observables,
                    param_resolver=param_resolver,
                ))
        return expectation_values
Beispiel #24
0
    def compute_amplitudes_sweep(
        self,
        program: cirq.Circuit,
        bitstrings: Sequence[int],
        params: cirq.Sweepable,
        qubit_order: cirq.QubitOrderOrList = cirq.QubitOrder.DEFAULT,
    ) -> Sequence[Sequence[complex]]:
        """Computes the desired amplitudes using qsim.

        The initial state is assumed to be the all zeros state.

        Args:
            program: The circuit to simulate.
            bitstrings: The bitstrings whose amplitudes are desired, input as an
              string array where each string is formed from measured qubit values
              according to `qubit_order` from most to least significant qubit,
              i.e. in big-endian ordering.
            param_resolver: Parameters to run with the program.
            qubit_order: Determines the canonical ordering of the qubits. This is
              often used in specifying the initial state, i.e. the ordering of the
              computational basis states.

        Returns:
            List of amplitudes.
        """

        # Add noise to the circuit if a noise model was provided.
        all_qubits = program.all_qubits()
        program = qsimc.QSimCircuit(
            self.noise.noisy_moments(program, sorted(all_qubits))
            if self.noise is not cirq.NO_NOISE else program, )

        # qsim numbers qubits in reverse order from cirq
        cirq_order = cirq.QubitOrder.as_qubit_order(qubit_order).order_for(
            all_qubits)
        num_qubits = len(cirq_order)
        bitstrings = [
            format(bitstring, "b").zfill(num_qubits)[::-1]
            for bitstring in bitstrings
        ]

        options = {"i": "\n".join(bitstrings)}
        options.update(self.qsim_options)

        param_resolvers = cirq.to_resolvers(params)

        trials_results = []
        if _needs_trajectories(program):
            translator_fn_name = "translate_cirq_to_qtrajectory"
            simulator_fn = self._sim_module.qtrajectory_simulate
        else:
            translator_fn_name = "translate_cirq_to_qsim"
            simulator_fn = self._sim_module.qsim_simulate

        for prs in param_resolvers:
            solved_circuit = cirq.resolve_parameters(program, prs)
            options["c"], _ = self._translate_circuit(
                solved_circuit,
                translator_fn_name,
                cirq_order,
            )
            options["s"] = self.get_seed()
            amplitudes = simulator_fn(options)
            trials_results.append(amplitudes)

        return trials_results
Beispiel #25
0
def test_to_resolvers_iterable():
    resolvers = [cirq.ParamResolver({'a': 2}), cirq.ParamResolver({'a': 1})]
    assert list(cirq.to_resolvers(resolvers)) == resolvers
    assert list(cirq.to_resolvers([{'a': 2}, {'a': 1}])) == resolvers
Beispiel #26
0
def test_to_resolvers_sweep():
    sweep = cirq.Linspace('a', 0, 1, 10)
    assert cirq.to_resolvers(sweep) == list(sweep)
Beispiel #27
0
    def simulate_expectation_values_sweep(
        self,
        program: cirq.Circuit,
        observables: Union[cirq.PauliSumLike, List[cirq.PauliSumLike]],
        params: cirq.Sweepable,
        qubit_order: cirq.QubitOrderOrList = cirq.QubitOrder.DEFAULT,
        initial_state: Any = None,
        permit_terminal_measurements: bool = False,
    ) -> List[List[float]]:
        """Simulates the supplied circuit and calculates exact expectation
        values for the given observables on its final state.

        This method has no perfect analogy in hardware. Instead compare with
        Sampler.sample_expectation_values, which calculates estimated
        expectation values by sampling multiple times.

        Args:
            program: The circuit to simulate.
            observables: An observable or list of observables.
            params: Parameters to run with the program.
            qubit_order: Determines the canonical ordering of the qubits. This
                is often used in specifying the initial state, i.e. the
                ordering of the computational basis states.
            initial_state: The initial state for the simulation. The form of
                this state depends on the simulation implementation. See
                documentation of the implementing class for details.
            permit_terminal_measurements: If the provided circuit ends with
                measurement(s), this method will generate an error unless this
                is set to True. This is meant to prevent measurements from
                ruining expectation value calculations.

        Returns:
            A list of expectation values, with the value at index `n`
            corresponding to `observables[n]` from the input.

        Raises:
            ValueError if 'program' has terminal measurement(s) and
            'permit_terminal_measurements' is False. (Note: We cannot test this
            until Cirq's `are_any_measurements_terminal` is released.)
        """
        if not permit_terminal_measurements and program.are_any_measurements_terminal(
        ):
            raise ValueError(
                "Provided circuit has terminal measurements, which may "
                "skew expectation values. If this is intentional, set "
                "permit_terminal_measurements=True.")
        if not isinstance(observables, List):
            observables = [observables]
        psumlist = [cirq.PauliSum.wrap(pslike) for pslike in observables]

        all_qubits = program.all_qubits()
        cirq_order = cirq.QubitOrder.as_qubit_order(qubit_order).order_for(
            all_qubits)
        qsim_order = list(reversed(cirq_order))
        num_qubits = len(qsim_order)
        qubit_map = {qubit: index for index, qubit in enumerate(qsim_order)}

        opsums_and_qubit_counts = []
        for psum in psumlist:
            opsum = []
            opsum_qubits = set()
            for pstr in psum:
                opstring = qsim.OpString()
                opstring.weight = pstr.coefficient
                for q, pauli in pstr.items():
                    op = pauli.on(q)
                    opsum_qubits.add(q)
                    qsimc.add_op_to_opstring(op, qubit_map, opstring)
                opsum.append(opstring)
            opsums_and_qubit_counts.append((opsum, len(opsum_qubits)))

        if initial_state is None:
            initial_state = 0
        if not isinstance(initial_state, (int, np.ndarray)):
            raise TypeError("initial_state must be an int or state vector.")

        # Add noise to the circuit if a noise model was provided.
        program = qsimc.QSimCircuit(
            self.noise.noisy_moments(program, sorted(all_qubits))
            if self.noise is not cirq.NO_NOISE else program, )

        options = {}
        options.update(self.qsim_options)

        param_resolvers = cirq.to_resolvers(params)
        if isinstance(initial_state, np.ndarray):
            if initial_state.dtype != np.complex64:
                raise TypeError(
                    f"initial_state vector must have dtype np.complex64.")
            input_vector = initial_state.view(np.float32)
            if len(input_vector) != 2**num_qubits * 2:
                raise ValueError(
                    f"initial_state vector size must match number of qubits."
                    f"Expected: {2**num_qubits * 2} Received: {len(input_vector)}"
                )

        results = []
        if _needs_trajectories(program):
            translator_fn_name = "translate_cirq_to_qtrajectory"
            ev_simulator_fn = self._sim_module.qtrajectory_simulate_expectation_values
        else:
            translator_fn_name = "translate_cirq_to_qsim"
            ev_simulator_fn = self._sim_module.qsim_simulate_expectation_values

        for prs in param_resolvers:
            solved_circuit = cirq.resolve_parameters(program, prs)
            options["c"], _ = self._translate_circuit(
                solved_circuit,
                translator_fn_name,
                cirq_order,
            )
            options["s"] = self.get_seed()

            if isinstance(initial_state, int):
                evs = ev_simulator_fn(options, opsums_and_qubit_counts,
                                      initial_state)
            elif isinstance(initial_state, np.ndarray):
                evs = ev_simulator_fn(options, opsums_and_qubit_counts,
                                      input_vector)
            results.append(evs)

        return results
Beispiel #28
0
def test_to_resolvers_iterable_sweeps():
    sweeps = [cirq.Linspace('a', 0, 1, 10), cirq.Linspace('b', 0, 1, 10)]
    assert cirq.to_resolvers(sweeps) == sum(
        [list(sweeps[0]), list(sweeps[1])], [])
Beispiel #29
0
    def simulate_sweep(
        self,
        program: cirq.Circuit,
        params: cirq.Sweepable,
        qubit_order: cirq.QubitOrderOrList = cirq.QubitOrder.DEFAULT,
        initial_state: Optional[Union[int, np.ndarray]] = None,
    ) -> List["SimulationTrialResult"]:
        """Simulates the supplied Circuit.

        This method returns a result which allows access to the entire
        wave function. In contrast to simulate, this allows for sweeping
        over different parameter values.

        Avoid using this method with `use_gpu=True` in the simulator options;
        when used with GPU this method must copy state from device to host memory
        multiple times, which can be very slow. This issue is not present in
        `simulate_expectation_values_sweep`.

        Args:
            program: The circuit to simulate.
            params: Parameters to run with the program.
            qubit_order: Determines the canonical ordering of the qubits. This is
              often used in specifying the initial state, i.e. the ordering of the
              computational basis states.
            initial_state: The initial state for the simulation. This can either
              be an integer representing a pure state (e.g. 11010) or a numpy
              array containing the full state vector. If none is provided, this
              is assumed to be the all-zeros state.

        Returns:
            List of SimulationTrialResults for this run, one for each
            possible parameter resolver.

        Raises:
            TypeError: if an invalid initial_state is provided.
        """
        if initial_state is None:
            initial_state = 0
        if not isinstance(initial_state, (int, np.ndarray)):
            raise TypeError("initial_state must be an int or state vector.")

        # Add noise to the circuit if a noise model was provided.
        all_qubits = program.all_qubits()
        program = qsimc.QSimCircuit(
            self.noise.noisy_moments(program, sorted(all_qubits))
            if self.noise is not cirq.NO_NOISE else program, )

        options = {}
        options.update(self.qsim_options)

        param_resolvers = cirq.to_resolvers(params)
        # qsim numbers qubits in reverse order from cirq
        cirq_order = cirq.QubitOrder.as_qubit_order(qubit_order).order_for(
            all_qubits)
        qsim_order = list(reversed(cirq_order))
        num_qubits = len(qsim_order)
        if isinstance(initial_state, np.ndarray):
            if initial_state.dtype != np.complex64:
                raise TypeError(
                    f"initial_state vector must have dtype np.complex64.")
            input_vector = initial_state.view(np.float32)
            if len(input_vector) != 2**num_qubits * 2:
                raise ValueError(
                    f"initial_state vector size must match number of qubits."
                    f"Expected: {2**num_qubits * 2} Received: {len(input_vector)}"
                )

        trials_results = []
        if _needs_trajectories(program):
            translator_fn_name = "translate_cirq_to_qtrajectory"
            fullstate_simulator_fn = self._sim_module.qtrajectory_simulate_fullstate
        else:
            translator_fn_name = "translate_cirq_to_qsim"
            fullstate_simulator_fn = self._sim_module.qsim_simulate_fullstate

        for prs in param_resolvers:
            solved_circuit = cirq.resolve_parameters(program, prs)

            options["c"], _ = self._translate_circuit(
                solved_circuit,
                translator_fn_name,
                cirq_order,
            )
            options["s"] = self.get_seed()
            qubit_map = {
                qubit: index
                for index, qubit in enumerate(qsim_order)
            }

            if isinstance(initial_state, int):
                qsim_state = fullstate_simulator_fn(options, initial_state)
            elif isinstance(initial_state, np.ndarray):
                qsim_state = fullstate_simulator_fn(options, input_vector)
            assert qsim_state.dtype == np.float32
            assert qsim_state.ndim == 1
            final_state = QSimSimulatorState(qsim_state, qubit_map)
            # create result for this parameter
            # TODO: We need to support measurements.
            result = QSimSimulatorTrialResult(
                params=prs, measurements={}, final_simulator_state=final_state)
            trials_results.append(result)

        return trials_results
Beispiel #30
0
    def simulate_moment_expectation_values(
        self,
        program: cirq.Circuit,
        indexed_observables: Union[Dict[int, Union[cirq.PauliSumLike,
                                                   List[cirq.PauliSumLike]]],
                                   cirq.PauliSumLike,
                                   List[cirq.PauliSumLike], ],
        param_resolver: cirq.ParamResolver,
        qubit_order: cirq.QubitOrderOrList = cirq.QubitOrder.DEFAULT,
        initial_state: Any = None,
    ) -> List[List[float]]:
        """Calculates expectation values at each moment of a circuit.

        Args:
            program: The circuit to simulate.
            indexed_observables: A map of moment indices to an observable
                or list of observables to calculate after that moment. As a
                convenience, users can instead pass in a single observable
                or observable list to calculate after ALL moments.
            param_resolver: Parameters to run with the program.
            qubit_order: Determines the canonical ordering of the qubits. This
                is often used in specifying the initial state, i.e. the
                ordering of the computational basis states.
            initial_state: The initial state for the simulation. The form of
                this state depends on the simulation implementation. See
                documentation of the implementing class for details.
            permit_terminal_measurements: If the provided circuit ends with
                measurement(s), this method will generate an error unless this
                is set to True. This is meant to prevent measurements from
                ruining expectation value calculations.

        Returns:
            A list of expectation values for each moment m in the circuit,
            where value `n` corresponds to `indexed_observables[m][n]`.

        Raises:
            ValueError if 'program' has terminal measurement(s) and
            'permit_terminal_measurements' is False. (Note: We cannot test this
            until Cirq's `are_any_measurements_terminal` is released.)
        """
        if not isinstance(indexed_observables, Dict):
            if not isinstance(indexed_observables, List):
                indexed_observables = [(i, [indexed_observables])
                                       for i, _ in enumerate(program)]
            else:
                indexed_observables = [(i, indexed_observables)
                                       for i, _ in enumerate(program)]
        else:
            indexed_observables = [(i, obs) if isinstance(obs, List) else
                                   (i, [obs])
                                   for i, obs in indexed_observables.items()]
        indexed_observables.sort(key=lambda x: x[0])
        psum_pairs = [(i, [cirq.PauliSum.wrap(pslike) for pslike in obs_list])
                      for i, obs_list in indexed_observables]

        all_qubits = program.all_qubits()
        cirq_order = cirq.QubitOrder.as_qubit_order(qubit_order).order_for(
            all_qubits)
        qsim_order = list(reversed(cirq_order))
        num_qubits = len(qsim_order)
        qubit_map = {qubit: index for index, qubit in enumerate(qsim_order)}

        opsums_and_qcount_map = {}
        for i, psumlist in psum_pairs:
            opsums_and_qcount_map[i] = []
            for psum in psumlist:
                opsum = []
                opsum_qubits = set()
                for pstr in psum:
                    opstring = qsim.OpString()
                    opstring.weight = pstr.coefficient
                    for q, pauli in pstr.items():
                        op = pauli.on(q)
                        opsum_qubits.add(q)
                        qsimc.add_op_to_opstring(op, qubit_map, opstring)
                    opsum.append(opstring)
                opsums_and_qcount_map[i].append((opsum, len(opsum_qubits)))

        if initial_state is None:
            initial_state = 0
        if not isinstance(initial_state, (int, np.ndarray)):
            raise TypeError("initial_state must be an int or state vector.")

        # Add noise to the circuit if a noise model was provided.
        program = qsimc.QSimCircuit(
            self.noise.noisy_moments(program, sorted(all_qubits))
            if self.noise is not cirq.NO_NOISE else program, )

        options = {}
        options.update(self.qsim_options)

        param_resolver = cirq.to_resolvers(param_resolver)
        if isinstance(initial_state, np.ndarray):
            if initial_state.dtype != np.complex64:
                raise TypeError(
                    f"initial_state vector must have dtype np.complex64.")
            input_vector = initial_state.view(np.float32)
            if len(input_vector) != 2**num_qubits * 2:
                raise ValueError(
                    f"initial_state vector size must match number of qubits."
                    f"Expected: {2**num_qubits * 2} Received: {len(input_vector)}"
                )

        is_noisy = _needs_trajectories(program)
        if is_noisy:
            translator_fn_name = "translate_cirq_to_qtrajectory"
            ev_simulator_fn = (self._sim_module.
                               qtrajectory_simulate_moment_expectation_values)
        else:
            translator_fn_name = "translate_cirq_to_qsim"
            ev_simulator_fn = self._sim_module.qsim_simulate_moment_expectation_values

        solved_circuit = cirq.resolve_parameters(program, param_resolver)
        options["c"], opsum_reindex = self._translate_circuit(
            solved_circuit,
            translator_fn_name,
            cirq_order,
        )
        opsums_and_qubit_counts = []
        for m, opsum_qc in opsums_and_qcount_map.items():
            pair = (opsum_reindex[m], opsum_qc)
            opsums_and_qubit_counts.append(pair)
        options["s"] = self.get_seed()

        if isinstance(initial_state, int):
            return ev_simulator_fn(options, opsums_and_qubit_counts,
                                   initial_state)
        elif isinstance(initial_state, np.ndarray):
            return ev_simulator_fn(options, opsums_and_qubit_counts,
                                   input_vector)