Beispiel #1
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 #2
0
    def run_sweep(
        self, program: cirq.AbstractCircuit, params: cirq.Sweepable, repetitions: int = 1
    ) -> Sequence[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'
        trial_results: List[cirq.Result] = []
        for param_resolver in cirq.to_resolvers(params):
            id_str = uuid.uuid1()
            num_qubits = len(program.all_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.ResultDict(params=param_resolver, measurements=res_dict))
        return trial_results
Beispiel #3
0
    def __init__(
        self,
        circuit: cirq.AbstractCircuit,
        measurement: BitstringsMeasurement,
        params: Union[Sequence[TParamPair], cirq.ParamResolverOrSimilarType] = None,
        spec: Optional[ExecutableSpec] = None,
        problem_topology: Optional[cirq.NamedTopology] = None,
        initial_state: Optional[cirq.ProductState] = None,
    ):
        """Initialize the quantum executable.

        The actual fields in this class are immutable, but we allow more liberal input types
        which will be frozen in this __init__ method.

        Args:
            circuit: The circuit. This will be frozen before being set as an attribute.
            measurement: A description of the measurement properties or process.
            params: A cirq.ParamResolverOrSimilarType which will be frozen into a tuple of
                key value pairs.
            spec: Specification metadata about this executable that is not used by the quantum
                runtime, but is persisted in result objects to associate executables with results.
            problem_topology: Description of the multiqubit gate topology present in the circuit.
                If not specified, the circuit must be compatible with the device topology.
            initial_state: How to initialize the quantum system before running `circuit`. If not
                specified, the device will be initialized into the all-zeros state.
        """

        # We care a lot about mutability in this class. No object is truly immutable in Python,
        # but we can get pretty close by following the example of dataclass(frozen=True), which
        # deletes this class's __setattr__ magic method. To set values ever, we use
        # object.__setattr__ in this __init__ function.
        #
        # We write our own __init__ function to be able to accept a wider range of input formats
        # that can be easily converted to our native, immutable format.
        object.__setattr__(self, 'circuit', circuit.freeze())
        object.__setattr__(self, 'measurement', measurement)

        if isinstance(params, tuple) and all(
            isinstance(param_kv, tuple) and len(param_kv) == 2 for param_kv in params
        ):
            frozen_params = params
        elif isinstance(params, Sequence) and all(
            isinstance(param_kv, Sequence) and len(param_kv) == 2 for param_kv in params
        ):
            frozen_params = tuple((k, v) for k, v in params)
        elif study.resolver._is_param_resolver_or_similar_type(params):
            param_resolver = cirq.ParamResolver(cast(cirq.ParamResolverOrSimilarType, params))
            frozen_params = tuple(param_resolver.param_dict.items())
        else:
            raise ValueError(f"`params` should be a ParamResolverOrSimilarType, not {params}.")
        object.__setattr__(self, 'params', frozen_params)

        object.__setattr__(self, 'spec', spec)
        object.__setattr__(self, 'problem_topology', problem_topology)
        object.__setattr__(self, 'initial_state', initial_state)

        # Hash may be expensive to compute, especially for large circuits.
        # This should be safe since this class should be immutable. This line will
        # also check for hashibility of members at construction time.
        object.__setattr__(self, '_hash', hash(dataclasses.astuple(self)))
Beispiel #4
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 func(
     circuit: cirq.AbstractCircuit,
     *,
     context: Optional[cirq.TransformerContext] = cirq.TransformerContext(),
     atol: float = 1e-4,
     custom_arg: CustomArg = CustomArg(),
 ) -> cirq.FrozenCircuit:
     my_mock(circuit, context, atol, custom_arg)
     return circuit.freeze()
def t3(
    circuit: cirq.AbstractCircuit, context: Optional[cirq.TransformerContext] = None
) -> cirq.Circuit:
    assert context is not None
    context.logger.log("First INFO Log", "of T3 Start")
    circuit = t1(circuit, context=context)
    context.logger.log("Second INFO Log", "of T3 Middle")
    circuit = t2(circuit, context=context)
    context.logger.log("Third INFO Log", "of T3 End")
    return circuit.unfreeze()
Beispiel #7
0
    def _generate_json(
        self,
        circuit: cirq.AbstractCircuit,
        param_resolver: cirq.ParamResolverOrSimilarType,
    ) -> str:
        """Generates the JSON string from a Circuit.

        The json format is defined as follows:

        [[op_string,gate_exponent,qubits]]

        which is a list of sequential quantum operations,
        each operation defined by:

        op_string: str that specifies the operation type: "X","Y","Z","MS"
        gate_exponent: float that specifies the gate_exponent of the operation
        qubits: list of qubits where the operation acts on.

        Args:
            circuit: Circuit to be run.
            param_resolver: Param resolver for resolving parameters in circuit.

        Returns:
            json formatted string of the sequence.

        Raises:
            RuntimeError: If the circuit is empty.
        """

        seq_list: List[
            Union[Tuple[str, float, List[int]], Tuple[str, float, float, List[int]]]
        ] = []
        circuit = cirq.resolve_parameters(circuit, param_resolver)
        for op in circuit.all_operations():
            line_qubit = cast(Tuple[cirq.LineQubit], op.qubits)
            op = cast(cirq.GateOperation, op)
            qubit_idx = [obj.x for obj in line_qubit]
            op_str = get_op_string(op)
            gate: Union[cirq.EigenGate, cirq.PhasedXPowGate]
            if op_str == 'R':
                gate = cast(cirq.PhasedXPowGate, op.gate)
                seq_list.append(
                    (op_str, float(gate.exponent), float(gate.phase_exponent), qubit_idx)
                )
            else:
                gate = cast(cirq.EigenGate, op.gate)
                seq_list.append((op_str, float(gate.exponent), qubit_idx))
        if len(seq_list) == 0:
            raise RuntimeError('Cannot send an empty circuit')
        json_str = json.dumps(seq_list)
        return json_str
Beispiel #8
0
def estimate_run_time(program: cirq.AbstractCircuit,
                      repetitions: int,
                      latency: Optional[float] = _BASE_LATENCY) -> float:
    """Compute the estimated time for running a single circuit.

    This should approximate, in seconds, the time for the execution of a batch of circuits
    using Engine.run() 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
        repetitions: number of repetitions to execute
        latency: Optional latency to add (defaults to 1.5 seconds)
    """
    width = len(program.all_qubits())
    depth = len(program)
    return _estimate_run_time_seconds(width, depth, 1, repetitions, latency)
Beispiel #9
0
    def serialize(self, circuit: cirq.AbstractCircuit) -> SerializedProgram:
        """Serialize the given circuit.

        Raises:
            ValueError: if the circuit has gates that are not supported or is otherwise invalid.
        """
        self._validate_circuit(circuit)
        num_qubits = self._validate_qubits(circuit.all_qubits())

        serialized_ops = self._serialize_circuit(circuit)

        # IonQ API does not support measurements, so we pass the measurement keys through
        # the metadata field.  Here we split these out of the serialized ops.
        body = {
            'qubits': num_qubits,
            'circuit': [op for op in serialized_ops if op['gate'] != 'meas'],
        }
        metadata = self._serialize_measurements(op for op in serialized_ops if op['gate'] == 'meas')
        return SerializedProgram(body=body, metadata=metadata)
Beispiel #10
0
    def place_circuit(
        self,
        circuit: cirq.AbstractCircuit,
        problem_topology: NamedTopology,
        shared_rt_info: 'cg.SharedRuntimeInfo',
        rs: np.random.RandomState,
    ) -> Tuple[cirq.FrozenCircuit, Dict[Any, cirq.Qid]]:
        """Place a circuit according to the hardcoded placements.

        Args:
            circuit: The circuit.
            problem_topology: The topologies (i.e. connectivity) of the circuit, use to look
                up the placement in `self.mapping`.
            shared_rt_info: A `cg.SharedRuntimeInfo` object; ignored for hardcoded placement.
            rs: A `RandomState`; ignored for hardcoded placement.

        Returns:
            A tuple of a new frozen circuit with the qubits placed and a mapping from input
            qubits or nodes to output qubits.

        Raises:
            CouldNotPlaceError: if the given problem_topology is not present in the hardcoded
                mapping.
        """
        try:
            nt_mapping = self._mapping[problem_topology]
        except KeyError as e:
            raise CouldNotPlaceError(str(e))

        circuit_mapping = {
            self.topo_node_to_qubit_func(nt_node): gridq
            for nt_node, gridq in nt_mapping.items()
        }

        circuit = circuit.unfreeze().transform_qubits(circuit_mapping).freeze()
        return circuit, circuit_mapping
Beispiel #11
0
 def validate_circuit(self, circuit: cirq.AbstractCircuit):
     super().validate_circuit(circuit)
     _verify_unique_measurement_keys(circuit.all_operations())
 def mock_tranformer_func(
     circuit: cirq.AbstractCircuit, *, context: Optional[cirq.TransformerContext] = None
 ) -> cirq.Circuit:
     my_mock(circuit, context)
     return circuit.unfreeze()
 def __call__(
     self, circuit: cirq.AbstractCircuit, *, context: Optional[cirq.TransformerContext] = None
 ) -> cirq.Circuit:
     self.mock(circuit, context)
     return circuit.unfreeze()
Beispiel #14
0
 def _validate_circuit(self, circuit: cirq.AbstractCircuit):
     if len(circuit) == 0:
         raise ValueError('Cannot serialize empty circuit.')
     if not circuit.are_all_measurements_terminal():
         raise ValueError('All measurements in circuit must be at end of circuit.')