Esempio n. 1
0
 def test_type_valid_2(self, an_int: int) -> None:
     circuit = Circuit(4, [2, 2, 3, 3])
     try:
         circuit.is_qudit_idle(an_int)
     except TypeError:
         assert False, 'Unexpected TypeError.'
     except BaseException:
         return
Esempio n. 2
0
 def test_type_invalid_2(self, not_an_int: Any) -> None:
     circuit = Circuit(4, [2, 2, 3, 3])
     try:
         circuit.is_qudit_idle(not_an_int)
     except TypeError:
         return
     except BaseException:
         assert False, 'Unexpected Exception.'
Esempio n. 3
0
    def test_single(self) -> None:
        circuit = Circuit(4, [2, 2, 2, 2])
        assert circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)

        circuit.append_gate(HGate(), [0])
        assert not circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)

        circuit.append_gate(HGate(), [1])
        assert not circuit.is_qudit_idle(0)
        assert not circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)

        circuit.append_gate(HGate(), [2])
        assert not circuit.is_qudit_idle(0)
        assert not circuit.is_qudit_idle(1)
        assert not circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)

        circuit.append_gate(HGate(), [3])
        assert not circuit.is_qudit_idle(0)
        assert not circuit.is_qudit_idle(1)
        assert not circuit.is_qudit_idle(2)
        assert not circuit.is_qudit_idle(3)

        circuit.pop((0, 0))
        assert circuit.is_qudit_idle(0)
        assert not circuit.is_qudit_idle(1)
        assert not circuit.is_qudit_idle(2)
        assert not circuit.is_qudit_idle(3)

        circuit.pop((0, 1))
        assert circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert not circuit.is_qudit_idle(2)
        assert not circuit.is_qudit_idle(3)

        circuit.pop((0, 2))
        assert circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert not circuit.is_qudit_idle(3)

        circuit.pop((0, 3))
        assert circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)
Esempio n. 4
0
 def test_return_type(
         self, r6_qudit_circuit: Circuit,
 ) -> None:
     for i in range(6):
         assert isinstance(r6_qudit_circuit.is_qudit_idle(i), bool)
Esempio n. 5
0
    def run(self, circuit: Circuit, data: dict[str, Any]) -> None:
        """
        Partition gates in a circuit into a series of CircuitGates.

        Args:
            circuit (Circuit): Circuit to be partitioned.

            data (dict[str,Any]): Optional data unique to specific run.
        """

        if self.block_size > circuit.get_size():
            _logger.warning(
                'Configured block size is greater than circuit size; '
                'blocking entire circuit.', )
            circuit.fold({
                qudit_index: (0, circuit.get_num_cycles())
                for qudit_index in range(circuit.get_size())
            })
            return

        # If a MachineModel is provided in the data dict, it will be used.
        # Otherwise all-to-all connectivity is assumed.
        model = None

        if 'machine_model' in data:
            model = data['machine_model']

        if (not isinstance(model, MachineModel)
                or model.num_qudits < circuit.get_size()):
            _logger.warning(
                'MachineModel not specified or invalid;'
                ' defaulting to all-to-all.', )
            model = MachineModel(circuit.get_size())

        # Find all connected, `block_size`-sized groups of qudits
        # NOTE: This assumes circuit and topology qudit numbers are equal
        qudit_groups = model.get_locations(self.block_size)
        # Prune unused qudit groups
        used_qudits = [
            q for q in range(circuit.get_size())
            if not circuit.is_qudit_idle(q)
        ]
        for qudit_group in qudit_groups:
            if all([q not in used_qudits for q in qudit_group]):
                qudit_groups.remove(qudit_group)

        # divider splits the circuit into partitioned and unpartitioned spaces.
        active_qudits = circuit.get_active_qudits()
        num_cycles = circuit.get_num_cycles()
        divider = [
            0 if q in active_qudits else num_cycles
            for q in range(circuit.get_size())
        ]

        # Form regions until there are no more gates to partition
        regions: list[CircuitRegion] = []
        while any(cycle < num_cycles for cycle in divider):

            # Move past/skip any gates that are larger than block size
            qudits_to_increment: list[int] = []
            for qudit, cycle in enumerate(divider):
                if qudit in qudits_to_increment or cycle >= num_cycles:
                    continue

                if not circuit.is_point_idle((cycle, qudit)):
                    op = circuit[cycle, qudit]
                    if len(op.location) > self.block_size:
                        if all(divider[q] == cycle for q in op.location):
                            qudits_to_increment.extend(op.location)
                            _logger.warning(
                                'Skipping gate larger than block size.', )

            if len(qudits_to_increment) > 0:
                regions.append(
                    CircuitRegion(
                        {
                            qudit: (divider[qudit], divider[qudit])
                            for qudit in qudits_to_increment
                        }, ), )

            for qudit in qudits_to_increment:
                divider[qudit] += 1

            # Skip any idle qudit-cycles
            amount_to_add_to_each_qudit = [
                0 for _ in range(circuit.get_size())
            ]
            for qudit, cycle in enumerate(divider):
                while (cycle < num_cycles and circuit.is_point_idle(
                    (cycle, qudit))):
                    amount_to_add_to_each_qudit[qudit] += 1
                    cycle += 1

            for qudit, amount in enumerate(amount_to_add_to_each_qudit):
                divider[qudit] += amount

            # Find the scores of the qudit groups.
            best_score = None
            best_region = None

            for qudit_group in qudit_groups:

                ops_and_cycles = circuit.operations_with_cycles(
                    qudits_or_region=CircuitRegion({
                        qudit_index: (divider[qudit_index], num_cycles)
                        for qudit_index in qudit_group
                    }), )

                in_qudits = list(q for q in qudit_group)
                stopped_cycles = {q: num_cycles for q in qudit_group}
                score = 0

                for cycle, op in ops_and_cycles:
                    if len(op.location.union(in_qudits)) != len(in_qudits):
                        for qudit_index in op.location.intersection(in_qudits):
                            stopped_cycles[qudit_index] = cycle
                            in_qudits.remove(qudit_index)
                    else:
                        if len(op.location) > 1:
                            score += self.multi_gate_score
                        else:
                            score += self.single_gate_score

                    if len(in_qudits) == 0:
                        break

                if best_score is None or score > best_score:
                    best_score = score
                    best_region = CircuitRegion({
                        qudit: (
                            divider[qudit],
                            # Might have errors if below is removed
                            stopped_cycles[qudit] - 1,
                        )
                        for qudit in qudit_group
                        # This statement
                        # if stopped_cycles[qudit] - 1 >= divider[qudit]
                    })

            if best_score is None or best_region is None:
                raise RuntimeError('No valid block found.')

            _logger.info('Found block with score: %d.' % (best_score))
            regions.append(best_region)

            # Update divider
            for qudit_index in best_region:
                divider[qudit_index] = best_region[qudit_index].upper + 1

        # Fold the circuit
        folded_circuit = Circuit(circuit.get_size(), circuit.get_radixes())
        # Option to keep a block's idle qudits as part of the CircuitGate
        if 'keep_idle_qudits' in data and data['keep_idle_qudits'] is True:
            for region in regions:
                small_region = circuit.downsize_region(region)
                cgc = circuit.get_slice(small_region.points)
                if len(region.location) > len(small_region.location):
                    for i in range(len(region.location)):
                        if region.location[i] not in small_region.location:
                            cgc.insert_qudit(i)
                folded_circuit.append_gate(
                    CircuitGate(cgc, True),
                    sorted(list(region.keys())),
                    list(cgc.get_params()),
                )
        else:
            for region in regions:
                region = circuit.downsize_region(region)
                if 0 < len(region) <= self.block_size:
                    cgc = circuit.get_slice(region.points)
                    folded_circuit.append_gate(
                        CircuitGate(cgc, True),
                        sorted(list(region.keys())),
                        list(cgc.get_params()),
                    )
                else:
                    folded_circuit.extend(circuit[region])
        circuit.become(folded_circuit)