Example #1
0
    def __init__(
            self, isa: Union[InstructionSetArchitecture, Dict[str,
                                                              Any]]) -> None:
        """Initializes a RigettiQCSAspenDevice with its Rigetti QCS `InstructionSetArchitecture`.

        Args:
            isa: The `InstructionSetArchitecture` retrieved from the QCS api.

        Raises:
            UnsupportedRigettiQCSQuantumProcessor: If the isa does not define
            an Aspen device.
        """
        if isinstance(isa, InstructionSetArchitecture):
            self.isa = isa
        else:
            self.isa = InstructionSetArchitecture.from_dict(isa)

        if self.isa.architecture.family.lower() != 'aspen':
            raise UnsupportedRigettiQCSQuantumProcessor(
                'this integration currently only supports Aspen devices, '
                f'but client provided a {self.isa.architecture.family} device')
        self.quantum_processor = QCSQuantumProcessor(
            quantum_processor_id=self.isa.name, isa=self.isa)
Example #2
0
def test_qcs_noise_model(qcs_aspen8_isa: InstructionSetArchitecture,
                         noise_model_dict: Dict[str, Any]):
    """
    Test that ``NoiseModel.from_dict`` initializes a ``NoiseModel``, which users may, in turn,
    pass to ``QCSQuantumProcessor`` for later initializing a noisy QVM.
    """

    noise_model = NoiseModel.from_dict(noise_model_dict)
    device = QCSQuantumProcessor("Aspen-8",
                                 qcs_aspen8_isa,
                                 noise_model=noise_model)
    assert device.quantum_processor_id == "Aspen-8"

    assert isinstance(device.noise_model, NoiseModel)
    assert device.noise_model == noise_model
Example #3
0
def qcs_aspen8_quantum_processor(
        qcs_aspen8_isa: InstructionSetArchitecture) -> QCSQuantumProcessor:
    return QCSQuantumProcessor(quantum_processor_id="Aspen-8",
                               isa=qcs_aspen8_isa)
Example #4
0
class RigettiQCSAspenDevice(cirq.devices.Device):
    """A cirq.Qid supporting Rigetti QCS Aspen device topology."""
    def __init__(
            self, isa: Union[InstructionSetArchitecture, Dict[str,
                                                              Any]]) -> None:
        """Initializes a RigettiQCSAspenDevice with its Rigetti QCS `InstructionSetArchitecture`.

        Args:
            isa: The `InstructionSetArchitecture` retrieved from the QCS api.

        Raises:
            UnsupportedRigettiQCSQuantumProcessor: If the isa does not define
            an Aspen device.
        """
        if isinstance(isa, InstructionSetArchitecture):
            self.isa = isa
        else:
            self.isa = InstructionSetArchitecture.from_dict(isa)

        if self.isa.architecture.family.lower() != 'aspen':
            raise UnsupportedRigettiQCSQuantumProcessor(
                'this integration currently only supports Aspen devices, '
                f'but client provided a {self.isa.architecture.family} device',
            )
        self.quantum_processor = QCSQuantumProcessor(
            quantum_processor_id=self.isa.name, isa=self.isa)

    def qubits(self) -> List['AspenQubit']:
        """Return list of `AspenQubit`s within device topology.

        Returns:
            List of `AspenQubit`s within device topology.
        """
        qubits = []
        for node in self.isa.architecture.nodes:
            qubits.append(AspenQubit.from_aspen_index(node.node_id))
        return qubits

    @property
    def qubit_topology(self) -> nx.Graph:
        """Return qubit topology indices with nx.Graph.

        Returns:
            Qubit topology as nx.Graph with each node specified with AspenQubit index.
        """
        return self.quantum_processor.qubit_topology()

    @property
    def _number_octagons(self) -> int:
        return int(np.ceil(self._maximum_qubit_number / 10))

    @property
    def _maximum_qubit_number(self) -> int:
        return max([node.node_id for node in self.isa.architecture.nodes])

    @functools.lru_cache(maxsize=2)
    def _line_qubit_mapping(self) -> List[int]:
        mapping: List[int] = []
        for i in range(self._number_octagons):
            base = i * 10
            mapping = mapping + [
                base + index for index in _forward_line_qubit_mapping
            ]
        for i in range(self._number_octagons):
            base = (self._number_octagons - i - 1) * 10
            mapping = mapping + [
                base + index for index in _reverse_line_qubit_mapping
            ]
        return mapping

    def _aspen_qubit_index(self, valid_qubit: cirq.Qid) -> int:
        if isinstance(valid_qubit, cirq.GridQubit):
            return _grid_qubit_mapping[valid_qubit]

        if isinstance(valid_qubit, cirq.LineQubit):
            return self._line_qubit_mapping()[valid_qubit.x]

        if isinstance(valid_qubit, cirq.NamedQubit):
            return int(valid_qubit.name)

        if isinstance(valid_qubit, (OctagonalQubit, AspenQubit)):
            return valid_qubit.index

        else:
            # coverage: ignore
            raise UnsupportedQubit(f'unsupported Qid type {type(valid_qubit)}')

    def validate_qubit(self, qubit: 'cirq.Qid') -> None:
        """Raises an exception if the qubit does not satisfy the topological constraints
        of the RigettiQCSAspenDevice.

        Args:
            qubit: The qubit to validate.

        Raises:
            UnsupportedQubit: The operation isn't valid for this device.
        """
        if isinstance(qubit, cirq.GridQubit):
            if self._number_octagons < 2:
                raise UnsupportedQubit(
                    'this device does not support GridQubits')
            if not (qubit.row <= 1 and qubit.col <= 1):
                raise UnsupportedQubit(
                    'Aspen devices only support square grids of 1 row and 1 column'
                )
            return

        if isinstance(qubit, cirq.LineQubit):
            if not (qubit.x <= self._number_octagons * 8):
                raise UnsupportedQubit(
                    'this Aspen device only supports line ',
                    f'qubits up to length {self._number_octagons * 8}',
                )
            return

        if isinstance(qubit, cirq.NamedQubit):
            try:
                index = int(qubit.name)
                if not (index < self._maximum_qubit_number):
                    raise UnsupportedQubit(
                        'this Aspen device only supports qubits up to index '
                        f'{self._maximum_qubit_number}')
                if not ((index % 10) <= 7):
                    raise UnsupportedQubit(
                        'this Aspen device only supports qubit indices mod 10 <= 7'
                    )
                return

            except ValueError:
                raise UnsupportedQubit(
                    'Aspen devices only support named qubits by octagonal index'
                )

        if isinstance(qubit, (OctagonalQubit, AspenQubit)):
            if not (qubit.index < self._maximum_qubit_number):
                raise UnsupportedQubit(
                    'this Aspen device only supports ',
                    f'qubits up to index {self._maximum_qubit_number}',
                )
            return

        else:
            # coverage: ignore
            raise UnsupportedQubit(f'unsupported Qid type {type(qubit)}')

    def validate_operation(self, operation: 'cirq.Operation') -> None:
        """Raises an exception if an operation does not satisfy the topological constraints
        of the device.

        Note, in case the operation is invalid, you can still use the Quil
        compiler to rewire qubits and decompose the operation to this device's
        topology.

        Additionally, this method will not attempt to decompose the operation into this
        device's native gate set. This integration, by default, uses the Quil
        compiler to do so.

        Please see the Quil Compiler
        [documentation](https://pyquil-docs.rigetti.com/en/stable/compiler.html)
        for more information.

        Args:
            operation: The operation to validate.

        Raises:
            UnsupportedRigettiQCSOperation: The operation isn't valid for this device.
        """
        qubits = operation.qubits
        for qubit in qubits:
            self.validate_qubit(qubit)
        if len(qubits) == 2:
            i = self._aspen_qubit_index(qubits[0])
            j = self._aspen_qubit_index(qubits[1])
            if j not in self.qubit_topology[i]:
                raise UnsupportedRigettiQCSOperation(
                    f'qubits {qubits[0]} and {qubits[1]} do not share an edge',
                )

    def _value_equality_values_(self):
        return self._maximum_qubit_number

    def __repr__(self):
        return f'cirq_rigetti.RigettiQCSAspenDevice(isa={self.isa!r})'

    def _json_dict_(self):
        return {
            'isa': self.isa.to_dict(),
        }

    @classmethod
    def _from_json_dict_(cls, isa, **kwargs):
        return cls(isa=InstructionSetArchitecture.from_dict(isa), )