Example #1
0
    def test_example(self) -> None:
        circuit = Circuit(1)

        opH = Operation(HGate(), [0])
        circuit.append(opH)
        assert circuit.point(opH).__repr__(
        ) == 'CircuitPoint(cycle=0, qudit=0)'

        opX = Operation(XGate(), [0])
        circuit.append(opX)
        assert circuit.point(opX).__repr__(
        ) == 'CircuitPoint(cycle=1, qudit=0)'
Example #2
0
    def test_correctness_2(self) -> None:
        circuit = Circuit(2)
        circuit.append_gate(HGate(), [0])
        circuit.append_gate(CNOTGate(), [0, 1])
        assert circuit.point(HGate()) == (0, 0)
        assert circuit.point(CNOTGate()) == (1, 0)
        assert circuit.point(Operation(HGate(), [0])) == (0, 0)
        assert circuit.point(Operation(CNOTGate(), [0, 1])) == (1, 0)

        try:
            circuit.point(Operation(CNOTGate(), [1, 0]))
        except ValueError:
            return
        assert False, 'Should not have reached here.'
Example #3
0
    def test_random_batch_remove(self) -> None:
        num_gates = 200
        num_q = 10

        circ = Circuit(num_q)
        for _ in range(num_gates):
            a = randint(0, num_q - 1)
            b = randint(0, num_q - 1)
            if a == b:
                b = (b + 1) % num_q
            circ.append_gate(CNOTGate(), [a, b])

        ScanPartitioner(2).run(circ, {})

        points = []
        ops = []
        for cycle, op in circ.operations_with_cycles():
            point = (cycle, op.location[0])
            ops.append(Operation(CNOTGate(), op.location))
            points.append(point)

        circ.batch_replace(points, ops)

        for op in circ:
            assert isinstance(op.gate, CNOTGate)
Example #4
0
 def test_type_valid_2(self) -> None:
     circuit = Circuit(4, [2, 2, 3, 3])
     try:
         circuit.extend([Operation(HGate(), [0])])
     except TypeError:
         assert False, 'Unexpected TypeError.'
     except BaseException:
         return
Example #5
0
 def test_type_valid_1(self) -> None:
     circuit = Circuit(1)
     try:
         circuit.append(Operation(HGate(), [0]))
     except TypeError:
         assert False, 'Unexpected TypeError.'
     except BaseException:
         return
Example #6
0
 def test_radix_mismatch_2(self, qutrit_gate: Gate) -> None:
     circuit = Circuit(qutrit_gate.get_size())
     location = list(range(qutrit_gate.get_size()))
     params = [0] * qutrit_gate.get_num_params()
     op = Operation(qutrit_gate, location, params)
     try:
         circuit.check_valid_operation(op)
     except ValueError:
         return
     except BaseException:
         assert False, 'Unexpected Exception'
     assert False
Example #7
0
    def run(self, circuit: Circuit, data: dict[str, Any]) -> None:
        """Perform the pass's operation, see BasePass for more info."""

        # Collect CircuitGate blocks
        blocks: list[tuple[CircuitPoint, Operation]] = []
        for cycle, op in circuit.operations_with_cycles():
            if isinstance(op.gate, CircuitGate):
                blocks.append((cycle, op))

        # 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())

        subdata = data.copy()

        # Perform work
        points: list[CircuitPoint] = []
        ops: list[Operation] = []
        for cycle, op in blocks:
            gate: CircuitGate = op.gate
            subcircuit = gate._circuit.copy()
            subcircuit.set_params(op.params)

            subnumbering = {op.location[i]: i for i in range(len(op.location))}
            subdata['machine_model'] = MachineModel(
                len(op.location),
                model.get_subgraph(op.location, subnumbering),
            )

            for loop_pass in self.loop_body:
                loop_pass.run(circuit, subdata)

            if self.replace_filter(subcircuit, op):
                points.append(CircuitPoint(cycle, op.location[0]))
                ops.append(
                    Operation(
                        CircuitGate(subcircuit, True),
                        op.location,
                        subcircuit.get_params(),
                    ), )

            # TODO: Load freshly written data from subdata into data

        circuit.batch_replace(points, ops)
Example #8
0
    def gate(self, args: Any) -> None:
        gate_name = args.children[0]
        param_list = None if len(args.children) == 2 else args.children[1]
        if len(args.children) == 2:
            var_list = args.children[1]
        else:
            var_list = args.children[2]

        if gate_name not in self.gate_defs:
            raise LangException('Unrecognized gate: %s.' % gate_name)

        gate_def = self.gate_defs[gate_name]

        # Calculate params
        params = []
        if param_list is not None:
            if is_iterable(eval_explist(param_list)):
                params = [float(i) for i in eval_explist(param_list)]
            else:
                params = [float(eval_explist(param_list))]

        if len(params) != gate_def.num_params:
            raise LangException(
                'Expected %d params got %d params for gate %s.' %
                (gate_def.num_params, len(params), gate_name), )

        # Calculate location
        location = []
        for reg_name, reg_idx in qubits_from_list(var_list):
            outer_idx = 0
            for reg in self.qubit_regs:
                if reg.name == reg_name:
                    location.append(outer_idx + reg_idx)
                    break
                outer_idx += reg.size

        if len(location) != gate_def.num_vars:
            raise LangException(
                'Gate acts on %d qubits, got %d qubit variables.' %
                (gate_def.num_vars, len(location)), )

        # Calculate operation
        self.op_list.append(Operation(gate_def.gate, location, params))
Example #9
0
    def test_batch_replace(self) -> None:
        circ = Circuit(4)
        op_1a = Operation(CNOTGate(), [0, 1])
        op_2a = Operation(CNOTGate(), [2, 3])
        op_3a = Operation(CNOTGate(), [1, 2])
        op_4a = Operation(CNOTGate(), [0, 1])
        op_5a = Operation(CNOTGate(), [0, 1])
        op_6a = Operation(CNOTGate(), [2, 3])
        list_a = [op_1a, op_2a, op_3a, op_4a, op_5a, op_6a]

        op_1b = Operation(CNOTGate(), [1, 0])
        op_2b = Operation(CNOTGate(), [3, 2])
        op_3b = Operation(CNOTGate(), [2, 1])
        op_4b = Operation(CNOTGate(), [1, 0])
        op_5b = Operation(CNOTGate(), [1, 0])
        op_6b = Operation(CNOTGate(), [3, 2])
        list_b = [op_1b, op_2b, op_3b, op_4b, op_5b, op_6b]

        for op in list_a:
            circ.append(op)

        assert circ.get_operation((0, 0), ) == op_1a and circ.get_operation(
            (0, 1), ) == op_1a
        assert circ.get_operation((0, 2), ) == op_2a and circ.get_operation(
            (0, 3), ) == op_2a

        assert circ.get_operation((1, 1), ) == op_3a and circ.get_operation(
            (1, 2), ) == op_3a

        assert circ.get_operation((2, 0), ) == op_4a and circ.get_operation(
            (2, 1), ) == op_4a
        assert circ.get_operation((2, 2), ) == op_6a and circ.get_operation(
            (2, 3), ) == op_6a

        assert circ.get_operation((3, 0), ) == op_5a and circ.get_operation(
            (3, 1), ) == op_5a
        for i in range(4):
            for j in range(4):
                print(f'({i},{j}): {circ._circuit[i][j]}')

        points = [(0, 0), (0, 2), (1, 1), (2, 0), (3, 1), (2, 3)]
        new_ops = list_b
        circ.batch_replace(points, new_ops)

        assert circ.get_operation((0, 0), ) == op_1b and circ.get_operation(
            (0, 1), ) == op_1b
        assert circ.get_operation((0, 2), ) == op_2b and circ.get_operation(
            (0, 3), ) == op_2b

        assert circ.get_operation((1, 1), ) == op_3b and circ.get_operation(
            (1, 2), ) == op_3b

        assert circ.get_operation((2, 0), ) == op_4b and circ.get_operation(
            (2, 1), ) == op_4b
        assert circ.get_operation((2, 2), ) == op_6b and circ.get_operation(
            (2, 3), ) == op_6b

        assert circ.get_operation((3, 0), ) == op_5b and circ.get_operation(
            (3, 1), ) == op_5b
Example #10
0
 def test_valid_3(self) -> None:
     circuit = Circuit(2, [3, 2])
     gate = ConstantUnitaryGate(np.identity(6), [2, 3])
     circuit.check_valid_operation(Operation(gate, [1, 0]))
Example #11
0
 def test_valid_2(self, gate: Gate) -> None:
     circuit = Circuit(gate.get_size() + 2, (2, 2) + gate.get_radixes())
     location = [x + 2 for x in list(range(gate.get_size()))]
     params = [0] * gate.get_num_params()
     circuit.check_valid_operation(Operation(gate, location, params))
Example #12
0
 def test_valid_1(self, gate: Gate) -> None:
     circuit = Circuit(gate.get_size(), gate.get_radixes())
     location = list(range(gate.get_size()))
     params = [0] * gate.get_num_params()
     circuit.check_valid_operation(Operation(gate, location, params))
Example #13
0
class TestCheckValidOperation:
    """This tests `circuit.check_valid_operation`."""

    @pytest.mark.parametrize(
        ('circuit', 'op'),
        [
            (Circuit(1), Operation(HGate(), [0])),
            (Circuit(1), Operation(CNOTGate(), [0, 1])),
            (Circuit(1), Operation(CPIGate(), [2, 3])),
            (Circuit(4, [2, 2, 3, 3]), Operation(HGate(), [0])),
            (Circuit(4, [2, 2, 3, 3]), Operation(CNOTGate(), [0, 1])),
            (Circuit(4, [2, 2, 3, 3]), Operation(CPIGate(), [2, 3])),
        ],
    )
    def test_type_valid(self, circuit: Circuit, op: Operation) -> None:
        try:
            circuit.check_valid_operation(op)
        except TypeError:
            assert False, 'Unexpected Exception.'
        except BaseException:
            return

    @pytest.mark.parametrize(
        ('circuit', 'op'),
        [
            (Circuit(1), 'A'),
            (Circuit(1), 0),
            (Circuit(1), np.int64(1234)),
            (Circuit(4, [2, 2, 3, 3]), 'A'),
            (Circuit(4, [2, 2, 3, 3]), 0),
            (Circuit(4, [2, 2, 3, 3]), np.int64(1234)),
        ],
    )
    def test_type_invalid(self, circuit: Circuit, op: Operation) -> None:
        try:
            circuit.check_valid_operation(op)
        except TypeError:
            return
        except BaseException:
            assert False, 'Unexpected Exception.'

    def test_location_mismatch_1(self, qubit_gate: Gate) -> None:
        circuit = Circuit(qubit_gate.get_size())
        location = list(range(qubit_gate.get_size()))
        location[-1] += 1
        params = [0] * qubit_gate.get_num_params()
        op = Operation(qubit_gate, location, params)
        try:
            circuit.check_valid_operation(op)
        except ValueError:
            return
        except BaseException:
            assert False, 'Unexpected Exception'
        assert False

    def test_location_mismatch_2(self, qutrit_gate: Gate) -> None:
        circuit = Circuit(qutrit_gate.get_size(), qutrit_gate.get_radixes())
        location = list(range(qutrit_gate.get_size()))
        location[-1] += 1
        params = [0] * qutrit_gate.get_num_params()
        op = Operation(qutrit_gate, location, params)
        try:
            circuit.check_valid_operation(op)
        except ValueError:
            return
        except BaseException:
            assert False, 'Unexpected Exception'
        assert False

    def test_radix_mismatch_1(self, qubit_gate: Gate) -> None:
        circuit = Circuit(qubit_gate.get_size(), [3] * qubit_gate.get_size())
        location = list(range(qubit_gate.get_size()))
        params = [0] * qubit_gate.get_num_params()
        op = Operation(qubit_gate, location, params)
        try:
            circuit.check_valid_operation(op)
        except ValueError:
            return
        except BaseException:
            assert False, 'Unexpected Exception'
        assert False

    def test_radix_mismatch_2(self, qutrit_gate: Gate) -> None:
        circuit = Circuit(qutrit_gate.get_size())
        location = list(range(qutrit_gate.get_size()))
        params = [0] * qutrit_gate.get_num_params()
        op = Operation(qutrit_gate, location, params)
        try:
            circuit.check_valid_operation(op)
        except ValueError:
            return
        except BaseException:
            assert False, 'Unexpected Exception'
        assert False

    def test_valid_1(self, gate: Gate) -> None:
        circuit = Circuit(gate.get_size(), gate.get_radixes())
        location = list(range(gate.get_size()))
        params = [0] * gate.get_num_params()
        circuit.check_valid_operation(Operation(gate, location, params))

    def test_valid_2(self, gate: Gate) -> None:
        circuit = Circuit(gate.get_size() + 2, (2, 2) + gate.get_radixes())
        location = [x + 2 for x in list(range(gate.get_size()))]
        params = [0] * gate.get_num_params()
        circuit.check_valid_operation(Operation(gate, location, params))

    def test_valid_3(self) -> None:
        circuit = Circuit(2, [3, 2])
        gate = ConstantUnitaryGate(np.identity(6), [2, 3])
        circuit.check_valid_operation(Operation(gate, [1, 0]))
Example #14
0
    def run(self, circuit: Circuit, data: dict[str, Any]) -> None:
        """Perform the pass's operation, see BasePass for more info."""

        # Collect synthesizable operations
        ops_to_syn: list[tuple[int, Operation]] = []
        for cycle, op in circuit.operations_with_cycles():
            if self.collection_filter(op):
                ops_to_syn.append((cycle, op))

        # 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())

        sub_data = data.copy()
        structure_list: list[Sequence[int]] = []

        # Synthesize operations
        errors: list[float] = []
        points: list[CircuitPoint] = []
        new_ops: list[Operation] = []
        num_blocks = len(ops_to_syn)

        for block_num, (cycle, op) in enumerate(ops_to_syn):
            sub_numbering = {op.location[i]: i for i in range(op.size)}
            sub_data['machine_model'] = MachineModel(
                len(op.location),
                model.get_subgraph(op.location, sub_numbering),
            )
            structure_list.append([op.location[i] for i in range(op.size)])
            syn_circuit = self.synthesize(op.get_unitary(), sub_data)
            if self.checkpoint_dir is not None:
                save_checkpoint(syn_circuit, self.checkpoint_dir, block_num)
            if self.replace_filter(syn_circuit, op):
                # Calculate errors
                new_utry = syn_circuit.get_unitary()
                old_utry = op.get_unitary()
                error = new_utry.get_distance_from(old_utry)
                errors.append(error)
                points.append(CircuitPoint(cycle, op.location[0]))
                new_ops.append(
                    Operation(
                        CircuitGate(syn_circuit, True),
                        op.location,
                        list(syn_circuit.get_params()),  # TODO: RealVector
                    ),
                )
                _logger.info(
                    f'Error in synthesized CircuitGate {block_num+1} of '
                    f'{num_blocks}: {error}',
                )
        data['synthesispass_error_sum'] = sum(errors)  # TODO: Might be replaced
        _logger.info(
            'Synthesis pass completed. Upper bound on '
            f"circuit error is {data['synthesispass_error_sum']}",
        )
        if self.checkpoint_dir is not None:
            with open(f'{self.checkpoint_dir}/structure.pickle', 'wb') as f:
                dump(structure_list, f)

        circuit.batch_replace(points, new_ops)