def required_predicates(self) -> List[Predicate]:
     preds = [
         NoSymbolsPredicate(),
         GateSetPredicate(_GATE_SET),
     ]
     if not self._MACHINE_DEBUG:
         assert self.device is not None
         preds.append(MaxNQubitsPredicate(len(self.device.nodes)))
     return preds
Beispiel #2
0
 def required_predicates(self) -> List[Predicate]:
     preds = [
         NoClassicalControlPredicate(),
         NoFastFeedforwardPredicate(),
         NoMidMeasurePredicate(),
         NoSymbolsPredicate(),
         GateSetPredicate(ionq_gates),
         MaxNQubitsPredicate(self._max_n_qubits),
     ]
     return preds
Beispiel #3
0
 def required_predicates(self) -> List[Predicate]:
     preds = [
         NoClassicalControlPredicate(),
         NoFastFeedforwardPredicate(),
         NoMidMeasurePredicate(),
         NoSymbolsPredicate(),
         GateSetPredicate({
             OpType.Rx, OpType.Ry, OpType.XXPhase, OpType.Measure,
             OpType.Barrier
         }),
     ]
     if self._max_n_qubits is not None:
         preds.append(MaxNQubitsPredicate(self._max_n_qubits))
     return preds
Beispiel #4
0
    def __init__(
        self,
        local: bool = False,
        s3_bucket: str = "",
        s3_folder: str = "",
        device_type: str = "quantum-simulator",
        provider: str = "amazon",
        device: str = "sv1",
    ):
        """
        Construct a new braket backend.

        If `local=True`, other parameters are ignored.

        :param local: use simulator running on local machine
        :param s3_bucket: name of S3 bucket to store results
        :param s3_folder: name of folder ("key") in S3 bucket to store results in
        :param device_type: device type from device ARN (e.g. "qpu")
        :param provider: provider name from device ARN (e.g. "ionq", "rigetti", ...)
        :paran device: device name from device ARN (e.g. "ionQdevice", "Aspen-8", ...)
        """
        super().__init__()
        if local:
            self._device = LocalSimulator()
            self._device_type = _DeviceType.LOCAL
        else:
            self._device = AwsDevice(
                "arn:aws:braket:::" +
                "/".join(["device", device_type, provider, device]))
            self._s3_dest = (s3_bucket, s3_folder)
            aws_device_type = self._device.type
            if aws_device_type == AwsDeviceType.SIMULATOR:
                self._device_type = _DeviceType.SIMULATOR
            elif aws_device_type == AwsDeviceType.QPU:
                self._device_type = _DeviceType.QPU
            else:
                raise ValueError(f"Unsupported device type {aws_device_type}")

        props = self._device.properties.dict()
        paradigm = props["paradigm"]
        n_qubits = paradigm["qubitCount"]
        connectivity_graph = None  # None means "fully connected"
        if self._device_type == _DeviceType.QPU:
            connectivity = paradigm["connectivity"]
            if connectivity["fullyConnected"]:
                self._all_qubits: List = list(range(n_qubits))
            else:
                connectivity_graph = connectivity["connectivityGraph"]
                # Convert strings to ints
                connectivity_graph = dict(
                    (int(k), [int(v) for v in l])
                    for k, l in connectivity_graph.items())
                self._all_qubits = sorted(connectivity_graph.keys())
                if n_qubits < len(self._all_qubits):
                    # This can happen, at least on rigetti devices, and causes errors.
                    # As a kludgy workaround, remove some qubits from the architecture.
                    self._all_qubits = self._all_qubits[:(
                        n_qubits - len(self._all_qubits))]
                    connectivity_graph = dict(
                        (k, [v for v in l if v in self._all_qubits])
                        for k, l in connectivity_graph.items()
                        if k in self._all_qubits)
            self._characteristics: Optional[Dict] = props["provider"]
        else:
            self._all_qubits = list(range(n_qubits))
            self._characteristics = None

        device_info = props["action"][DeviceActionType.JAQCD]
        supported_ops = set(op.lower()
                            for op in device_info["supportedOperations"])
        supported_result_types = device_info["supportedResultTypes"]
        self._result_types = set()
        for rt in supported_result_types:
            rtname = rt["name"]
            rtminshots = rt["minShots"]
            rtmaxshots = rt["maxShots"]
            self._result_types.add(rtname)
            if rtname == "StateVector":
                self._supports_state = True
                # Always use n_shots = 0 for StateVector
            elif rtname == "Amplitude":
                pass  # Always use n_shots = 0 for Amplitude
            elif rtname == "Probability":
                self._probability_min_shots = rtminshots
                self._probability_max_shots = rtmaxshots
            elif rtname == "Expectation":
                self._supports_expectation = True
                self._expectation_allows_nonhermitian = False
                self._expectation_min_shots = rtminshots
                self._expectation_max_shots = rtmaxshots
            elif rtname == "Sample":
                self._supports_shots = True
                self._supports_counts = True
                self._sample_min_shots = rtminshots
                self._sample_max_shots = rtmaxshots
            elif rtname == "Variance":
                self._variance_min_shots = rtminshots
                self._variance_max_shots = rtmaxshots

        self._multiqs = set()
        self._singleqs = set()
        if not {"cnot", "rx", "rz"} <= supported_ops:
            # This is so that we can define RebaseCustom without prior knowledge of the
            # gate set. We could do better than this, by having a few different options
            # for the CX- and tk1-replacement circuits. But it seems all existing
            # backends support these gates.
            raise NotImplementedError(
                "Device must support cnot, rx and rz gates.")
        for t in supported_ops:
            tkt = _gate_types[t]
            if tkt is not None:
                if t in _multiq_gate_types:
                    if self._device_type == _DeviceType.QPU and t in [
                            "ccnot", "cswap"
                    ]:
                        # FullMappingPass can't handle 3-qubit gates, so ignore them.
                        continue
                    self._multiqs.add(tkt)
                else:
                    self._singleqs.add(tkt)
        self._req_preds = [
            NoClassicalControlPredicate(),
            NoFastFeedforwardPredicate(),
            NoMidMeasurePredicate(),
            NoSymbolsPredicate(),
            GateSetPredicate(self._multiqs | self._singleqs),
            MaxNQubitsPredicate(n_qubits),
        ]

        if connectivity_graph is None:
            arch = FullyConnected(n_qubits)
        else:
            arch = Architecture([(k, v) for k, l in connectivity_graph.items()
                                 for v in l])
        if self._device_type == _DeviceType.QPU:
            assert self._characteristics is not None
            node_errs = {}
            edge_errs = {}
            schema = self._characteristics["braketSchemaHeader"]
            if schema == IONQ_SCHEMA:
                fid = self._characteristics["fidelity"]
                mean_1q_err = 1 - fid["1Q"]["mean"]
                mean_2q_err = 1 - fid["2Q"]["mean"]
                err_1q_cont = QubitErrorContainer(self._singleqs)
                for optype in self._singleqs:
                    err_1q_cont.add_error((optype, mean_1q_err))
                err_2q_cont = QubitErrorContainer(self._multiqs)
                for optype in self._multiqs:
                    err_2q_cont.add_error((optype, mean_2q_err))
                for node in arch.nodes:
                    node_errs[node] = err_1q_cont
                for coupling in arch.coupling:
                    edge_errs[coupling] = err_2q_cont
            elif schema == RIGETTI_SCHEMA:
                specs = self._characteristics["specs"]
                specs1q, specs2q = specs["1Q"], specs["2Q"]
                for node in arch.nodes:
                    nodespecs = specs1q[f"{node.index[0]}"]
                    err_1q_cont = QubitErrorContainer(self._singleqs)
                    for optype in self._singleqs:
                        err_1q_cont.add_error(
                            (optype, 1 - nodespecs.get("f1QRB", 1)))
                    err_1q_cont.add_readout(nodespecs.get("fRO", 1))
                    node_errs[node] = err_1q_cont
                for coupling in arch.coupling:
                    node0, node1 = coupling
                    n0, n1 = node0.index[0], node1.index[0]
                    couplingspecs = specs2q[f"{min(n0,n1)}-{max(n0,n1)}"]
                    err_2q_cont = QubitErrorContainer({OpType.CZ})
                    err_2q_cont.add_error(
                        (OpType.CZ, 1 - couplingspecs.get("fCZ", 1)))
                    edge_errs[coupling] = err_2q_cont
            self._tket_device = Device(node_errs, edge_errs, arch)
            if connectivity_graph is not None:
                self._req_preds.append(ConnectivityPredicate(
                    self._tket_device))
        else:
            self._tket_device = None

        self._rebase_pass = RebaseCustom(
            self._multiqs,
            Circuit(),
            self._singleqs,
            lambda a, b, c: Circuit(1).Rz(c, 0).Rx(b, 0).Rz(a, 0),
        )
        self._squash_pass = SquashCustom(
            self._singleqs,
            lambda a, b, c: Circuit(1).Rz(c, 0).Rx(b, 0).Rz(a, 0),
        )