1# Copyright 2018 The Cirq Developers 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15from typing import Union, TYPE_CHECKING 16 17import abc 18 19from cirq import circuits, devices, ops 20from cirq.contrib.acquaintance.gates import AcquaintanceOpportunityGate, SwapNetworkGate 21from cirq.contrib.acquaintance.bipartite import BipartiteSwapNetworkGate 22from cirq.contrib.acquaintance.shift_swap_network import ShiftSwapNetworkGate 23from cirq.contrib.acquaintance.permutation import PermutationGate 24 25if TYPE_CHECKING: 26 import cirq 27 28 29class AcquaintanceDevice(devices.Device, metaclass=abc.ABCMeta): 30 """A device that contains only acquaintance and permutation gates.""" 31 32 gate_types = (AcquaintanceOpportunityGate, PermutationGate) 33 34 def validate_operation(self, operation: 'cirq.Operation') -> None: 35 if not ( 36 isinstance(operation, ops.GateOperation) and isinstance(operation.gate, self.gate_types) 37 ): 38 raise ValueError( 39 'not (isinstance({0!r}, {1!r}) and ' 40 'ininstance({0!r}.gate, {2!r})'.format(operation, ops.Operation, self.gate_types) 41 ) 42 43 44def is_acquaintance_strategy(circuit: 'cirq.Circuit') -> bool: 45 return isinstance(circuit._device, AcquaintanceDevice) 46 47 48def get_acquaintance_size(obj: Union[circuits.Circuit, ops.Operation]) -> int: 49 """The maximum number of qubits to be acquainted with each other.""" 50 if isinstance(obj, circuits.Circuit): 51 if not is_acquaintance_strategy(obj): 52 raise TypeError('not is_acquaintance_strategy(circuit)') 53 return max(tuple(get_acquaintance_size(op) for op in obj.all_operations()) or (0,)) 54 if not isinstance(obj, ops.Operation): 55 raise TypeError('not isinstance(obj, (Circuit, Operation))') 56 if not isinstance(obj, ops.GateOperation): 57 return 0 58 if isinstance(obj.gate, AcquaintanceOpportunityGate): 59 return len(obj.qubits) 60 if isinstance(obj.gate, BipartiteSwapNetworkGate): 61 return 2 62 if isinstance(obj.gate, ShiftSwapNetworkGate): 63 return obj.gate.acquaintance_size() 64 if isinstance(obj.gate, SwapNetworkGate): 65 if obj.gate.acquaintance_size is None: 66 return sum(sorted(obj.gate.part_lens)[-2:]) 67 if (obj.gate.acquaintance_size - 1) in obj.gate.part_lens: 68 return obj.gate.acquaintance_size 69 sizer = getattr(obj.gate, '_acquaintance_size_', None) 70 return 0 if sizer is None else sizer(len(obj.qubits)) 71 72 73class _UnconstrainedAcquaintanceDevice(AcquaintanceDevice): 74 """An acquaintance device with no constraints other than of the gate types.""" 75 76 def __repr__(self) -> str: 77 return 'UnconstrainedAcquaintanceDevice' # coverage: ignore 78 79 80UnconstrainedAcquaintanceDevice = _UnconstrainedAcquaintanceDevice() 81