예제 #1
0
def test_send_possible_commands_deallocate():
    mapper = lm.LinearMapper(num_qubits=4, cyclic=False)
    backend = DummyEngine(save_commands=True)
    backend.is_last_engine = True
    mapper.next_engine = backend
    qb0 = WeakQubitRef(engine=None, idx=0)
    cmd0 = Command(engine=None, gate=Deallocate, qubits=([qb0],), controls=[], tags=[])
    mapper._stored_commands = [cmd0]
    mapper.current_mapping = {}
    mapper._currently_allocated_ids = {10}
    # not yet allocated:
    mapper._send_possible_commands()
    assert len(backend.received_commands) == 0
    assert mapper._stored_commands == [cmd0]
    # allocated:
    mapper.current_mapping = {0: 3}
    mapper._currently_allocated_ids.add(0)
    mapper._send_possible_commands()
    assert len(backend.received_commands) == 1
    assert backend.received_commands[0].gate == Deallocate
    assert backend.received_commands[0].qubits[0][0].id == 3
    assert backend.received_commands[0].tags == [LogicalQubitIDTag(0)]
    assert len(mapper._stored_commands) == 0
    assert mapper.current_mapping == {}
    assert mapper._currently_allocated_ids == {10}
예제 #2
0
def test_send_possible_commands_allocate(different_backend_ids):
    if different_backend_ids:
        map_to_backend_ids = {0: 21, 1: 32, 2: 3, 3: 4, 4: 5, 5: 6}
    else:
        map_to_backend_ids = None
    mapper = two_d.GridMapper(num_rows=3, num_columns=2, mapped_ids_to_backend_ids=map_to_backend_ids)
    backend = DummyEngine(save_commands=True)
    backend.is_last_engine = True
    mapper.next_engine = backend
    qb0 = WeakQubitRef(engine=None, idx=0)
    cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],), controls=[], tags=[])
    mapper._stored_commands = [cmd0]
    mapper._currently_allocated_ids = {10}
    # not in mapping:
    mapper.current_mapping = {}
    assert len(backend.received_commands) == 0
    mapper._send_possible_commands()
    assert len(backend.received_commands) == 0
    assert mapper._stored_commands == [cmd0]
    # in mapping:
    mapper.current_mapping = {0: 3}
    mapper._send_possible_commands()
    assert len(mapper._stored_commands) == 0
    # Only self._run() sends Allocate gates
    mapped0 = WeakQubitRef(engine=None, idx=3)
    received_cmd = Command(
        engine=mapper,
        gate=Allocate,
        qubits=([mapped0],),
        controls=[],
        tags=[LogicalQubitIDTag(0)],
    )
    assert backend.received_commands[0] == received_cmd
    assert mapper._currently_allocated_ids == {10, 0}
예제 #3
0
    def _process_cmd(self, cmd):
        current_mapping = self.current_mapping
        if current_mapping is None:
            current_mapping = {}

        if isinstance(cmd.gate, AllocateQubitGate):
            qubit_id = cmd.qubits[0][0].id
            if qubit_id in current_mapping:
                raise RuntimeError(
                    "Qubit with id {} has already been allocated!".format(
                        qubit_id))

            if self._qubit_idx >= self.max_qubits:
                raise RuntimeError(
                    "Cannot allocate more than {} qubits!".format(
                        self.max_qubits))

            new_id = self._qubit_idx
            self._qubit_idx += 1
            current_mapping[qubit_id] = new_id
            qb = WeakQubitRef(engine=self, idx=new_id)
            new_cmd = Command(
                engine=self,
                gate=AllocateQubitGate(),
                qubits=([qb], ),
                tags=[LogicalQubitIDTag(qubit_id)],
            )
            self.current_mapping = current_mapping
            self.send([new_cmd])
        elif isinstance(cmd.gate, DeallocateQubitGate):
            qubit_id = cmd.qubits[0][0].id
            if qubit_id not in current_mapping:
                raise RuntimeError(
                    "Cannot deallocate a qubit that is not already allocated!")
            qb = WeakQubitRef(engine=self, idx=current_mapping[qubit_id])
            new_cmd = Command(
                engine=self,
                gate=DeallocateQubitGate(),
                qubits=([qb], ),
                tags=[LogicalQubitIDTag(qubit_id)],
            )
            current_mapping.pop(qubit_id)
            self.current_mapping = current_mapping
            self.send([new_cmd])
        else:
            self._send_cmd_with_mapped_ids(cmd)
예제 #4
0
def test_basic_mapper_engine_send_cmd_with_mapped_ids():
    mapper = _basicmapper.BasicMapperEngine()
    mapper.current_mapping = {0: 3, 1: 2, 2: 1, 3: 0}
    backend = DummyEngine(save_commands=True)
    backend.is_last_engine = True
    mapper.next_engine = backend
    # generate a few commands
    qb0 = WeakQubitRef(engine=None, idx=0)
    qb1 = WeakQubitRef(engine=None, idx=1)
    qb2 = WeakQubitRef(engine=None, idx=2)
    qb3 = WeakQubitRef(engine=None, idx=3)
    cmd0 = Command(engine=None,
                   gate=Allocate,
                   qubits=([qb0], ),
                   controls=[],
                   tags=[])
    cmd1 = Command(engine=None,
                   gate=Deallocate,
                   qubits=([qb1], ),
                   controls=[],
                   tags=[])
    cmd2 = Command(engine=None,
                   gate=Measure,
                   qubits=([qb2], ),
                   controls=[],
                   tags=["SomeTag"])
    cmd3 = Command(
        engine=None,
        gate=BasicGate(),
        qubits=([qb0, qb1], [qb2]),
        controls=[qb3],
        tags=[],
    )
    cmd4 = Command(None, FlushGate(), ([WeakQubitRef(None, -1)], ))
    mapper._send_cmd_with_mapped_ids(cmd0)
    mapper._send_cmd_with_mapped_ids(cmd1)
    mapper._send_cmd_with_mapped_ids(cmd2)
    mapper._send_cmd_with_mapped_ids(cmd3)
    mapper._send_cmd_with_mapped_ids(cmd4)
    rcmd0 = backend.received_commands[0]
    rcmd1 = backend.received_commands[1]
    rcmd2 = backend.received_commands[2]
    rcmd3 = backend.received_commands[3]
    rcmd4 = backend.received_commands[4]
    assert rcmd0.gate == Allocate
    assert rcmd0.qubits == ([qb3], )
    assert rcmd1.gate == Deallocate
    assert rcmd1.qubits == ([qb2], )
    assert rcmd2.gate == Measure
    assert rcmd2.qubits == ([qb1], )
    assert rcmd2.tags == ["SomeTag", LogicalQubitIDTag(2)]
    assert rcmd3.gate == BasicGate()
    assert rcmd3.qubits == ([qb3, qb2], [qb1])
    assert rcmd3.control_qubits == [qb0]
    assert len(rcmd4.qubits) == 1
    assert len(rcmd4.qubits[0]) == 1
    assert rcmd4.qubits[0][0].id == -1
예제 #5
0
 def test_store_measure_gate_with_mapper(self, function_mock):
     mock_tag = 'mock_my_tag'
     function_mock.return_value = 4
     mapper = MagicMock(current_mapping={mock_tag: 0})
     self.qi_backend.main_engine = MagicMock(mapper=mapper)
     self.__store_function(self.qi_backend, 0, Allocate)
     command = [MagicMock(gate=Measure, qubits=[[MagicMock(id=0)]],
                          tags=[LogicalQubitIDTag(mock_tag)])]
     self.qi_backend.receive(command)
     self.__store_function(self.qi_backend, 0, H)
     self.assertEqual(self.qi_backend.measured_ids, [mock_tag])
     self.assertEqual(self.qi_backend.qasm, "\nmeasure q[0]\nh q[0]")
예제 #6
0
 def test_store_measure_gate_with_mapper(self, function_mock):
     mock_tag = 'mock_my_tag'
     api = MockApiClient()
     function_mock.return_value = 4
     backend = QIBackend(quantum_inspire_api=api)
     command = MagicMock(gate=Measure,
                         qubits=[[MagicMock(id=0)]],
                         control_qubits=[MagicMock(id=2),
                                         MagicMock(id=3)],
                         tags=[LogicalQubitIDTag(mock_tag)])
     backend.main_engine = MagicMock(mapper="mapper")
     backend._store(command)
     self.assertEqual(backend._measured_ids, [mock_tag])
def test_manualmapper_mapping():
    backend = DummyEngine(save_commands=True)

    def mapping(qubit_id):
        return (qubit_id + 1) & 1

    eng = MainEngine(backend=backend, engine_list=[ManualMapper(mapping)])
    qb0 = eng.allocate_qubit()
    qb1 = eng.allocate_qubit()
    H | qb0
    H | qb1
    All(Measure) | (qb0 + qb1)
    eng.flush()

    num_measurements = 0
    for cmd in backend.received_commands:
        if cmd.gate == Measure:
            tag = LogicalQubitIDTag(mapping(cmd.qubits[0][0].id))
            assert tag in cmd.tags
            wrong_tag = LogicalQubitIDTag(cmd.qubits[0][0].id)
            assert wrong_tag not in cmd.tags
            num_measurements += 1
    assert num_measurements == 2
예제 #8
0
def test_logical_id_tags_allocate_and_deallocate():
    mapper = two_d.GridMapper(num_rows=2, num_columns=2)
    backend = DummyEngine(save_commands=True)
    backend.is_last_engine = True
    mapper.next_engine = backend
    qb0 = WeakQubitRef(engine=None, idx=0)
    qb1 = WeakQubitRef(engine=None, idx=1)
    cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],))
    cmd1 = Command(engine=None, gate=Allocate, qubits=([qb1],))
    cmd2 = Command(None, X, qubits=([qb0],), controls=[qb1])
    cmd3 = Command(engine=None, gate=Deallocate, qubits=([qb0],))
    cmd4 = Command(engine=None, gate=Deallocate, qubits=([qb1],))
    mapper.current_mapping = {0: 0, 1: 3}
    qb_flush = WeakQubitRef(engine=None, idx=-1)
    cmd_flush = Command(engine=None, gate=FlushGate(), qubits=([qb_flush],))
    mapper.receive([cmd0, cmd1, cmd2, cmd_flush])
    assert backend.received_commands[0].gate == Allocate
    assert backend.received_commands[0].qubits[0][0].id == 0
    assert backend.received_commands[0].tags == [LogicalQubitIDTag(0)]
    assert backend.received_commands[1].gate == Allocate
    assert backend.received_commands[1].qubits[0][0].id == 3
    assert backend.received_commands[1].tags == [LogicalQubitIDTag(1)]
    for cmd in backend.received_commands[2:]:
        if cmd.gate == Allocate:
            assert cmd.tags == []
        elif cmd.gate == Deallocate:
            assert cmd.tags == []
    mapped_id_for_0 = mapper.current_mapping[0]
    mapped_id_for_1 = mapper.current_mapping[1]
    mapper.receive([cmd3, cmd4, cmd_flush])
    assert backend.received_commands[-3].gate == Deallocate
    assert backend.received_commands[-3].qubits[0][0].id == mapped_id_for_0
    assert backend.received_commands[-3].tags == [LogicalQubitIDTag(0)]
    assert backend.received_commands[-2].gate == Deallocate
    assert backend.received_commands[-2].qubits[0][0].id == mapped_id_for_1
    assert backend.received_commands[-2].tags == [LogicalQubitIDTag(1)]
예제 #9
0
def test_resource_counter_measurement():
    eng = MainEngine(ResourceCounter(), [])
    qb1 = WeakQubitRef(engine=eng, idx=1)
    qb2 = WeakQubitRef(engine=eng, idx=2)
    cmd0 = Command(engine=eng, gate=Allocate, qubits=([qb1],))
    cmd1 = Command(engine=eng, gate=Measure, qubits=([qb1],), controls=[],
                   tags=[LogicalQubitIDTag(2)])
    with pytest.raises(NotYetMeasuredError):
        int(qb1)
    with pytest.raises(NotYetMeasuredError):
        int(qb2)
    eng.send([cmd0, cmd1])
    eng.flush()
    with pytest.raises(NotYetMeasuredError):
        int(qb1)
    assert int(qb2) == 0
예제 #10
0
def test_ibm_errors():
    backend = _ibm.IBMBackend(verbose=True, num_runs=1000)
    mapper = BasicMapperEngine()
    mapper.current_mapping = {0: 0}
    eng = MainEngine(backend=backend, engine_list=[mapper])

    qb0 = WeakQubitRef(engine=None, idx=0)

    # No LogicalQubitIDTag
    with pytest.raises(RuntimeError):
        eng.backend._store(Command(engine=eng, gate=Measure, qubits=([qb0],)))

    eng = MainEngine(backend=backend, engine_list=[])

    # No mapper
    with pytest.raises(RuntimeError):
        eng.backend._store(Command(engine=eng, gate=Measure, qubits=([qb0],), tags=(LogicalQubitIDTag(1),)))
예제 #11
0
def test_command_printer_measure_mapped_qubit():
    eng = MainEngine(_printer.CommandPrinter(accept_input=False), [])
    qb1 = WeakQubitRef(engine=eng, idx=1)
    qb2 = WeakQubitRef(engine=eng, idx=2)
    cmd0 = Command(engine=eng, gate=Allocate, qubits=([qb1], ))
    cmd1 = Command(engine=eng,
                   gate=Measure,
                   qubits=([qb1], ),
                   controls=[],
                   tags=[LogicalQubitIDTag(2)])
    with pytest.raises(NotYetMeasuredError):
        int(qb1)
    with pytest.raises(NotYetMeasuredError):
        int(qb2)
    eng.send([cmd0, cmd1])
    eng.flush()
    with pytest.raises(NotYetMeasuredError):
        int(qb1)
    assert int(qb2) == 0
예제 #12
0
def test_cannot_reallocate_same_qubit():
    engine = MainEngine(
        Simulator(),
        engine_list=[BoundedQubitMapper(1)],
        verbose=True,
    )
    qureg = engine.allocate_qubit()
    qubit = qureg[0]
    qubit_id = qubit.id
    with pytest.raises(RuntimeError) as excinfo:
        allocate_cmd = Command(
            engine=engine,
            gate=AllocateQubitGate(),
            qubits=([WeakQubitRef(engine=engine, idx=qubit_id)], ),
            tags=[LogicalQubitIDTag(qubit_id)],
        )
        engine.send([allocate_cmd])

    assert str(excinfo.value) == "Qubit with id 0 has already been allocated!"
예제 #13
0
def test_simulator_measure_mapped_qubit(sim):
    eng = MainEngine(sim, [])
    qb1 = WeakQubitRef(engine=eng, idx=1)
    qb2 = WeakQubitRef(engine=eng, idx=2)
    cmd0 = Command(engine=eng, gate=Allocate, qubits=([qb1], ))
    cmd1 = Command(engine=eng, gate=X, qubits=([qb1], ))
    cmd2 = Command(engine=eng,
                   gate=Measure,
                   qubits=([qb1], ),
                   controls=[],
                   tags=[LogicalQubitIDTag(2)])
    with pytest.raises(NotYetMeasuredError):
        int(qb1)
    with pytest.raises(NotYetMeasuredError):
        int(qb2)
    eng.send([cmd0, cmd1, cmd2])
    eng.flush()
    with pytest.raises(NotYetMeasuredError):
        int(qb1)
    assert int(qb2) == 1
예제 #14
0
def test_cannot_deallocate_same_qubit():
    mapper = BoundedQubitMapper(1)
    engine = MainEngine(
        Simulator(),
        engine_list=[mapper],
        verbose=True,
    )
    qureg = engine.allocate_qubit()
    qubit_id = qureg[0].id
    engine.deallocate_qubit(qureg[0])

    with pytest.raises(RuntimeError) as excinfo:
        deallocate_cmd = Command(
            engine=engine,
            gate=DeallocateQubitGate(),
            qubits=([WeakQubitRef(engine=engine, idx=qubit_id)], ),
            tags=[LogicalQubitIDTag(qubit_id)],
        )
        engine.send([deallocate_cmd])

    assert str(excinfo.value
               ) == "Cannot deallocate a qubit that is not already allocated!"
예제 #15
0
def test_cannot_deallocate_unknown_qubit():
    engine = MainEngine(
        Simulator(),
        engine_list=[BoundedQubitMapper(1)],
        verbose=True,
    )
    qureg = engine.allocate_qubit()
    with pytest.raises(RuntimeError) as excinfo:
        deallocate_cmd = Command(
            engine=engine,
            gate=DeallocateQubitGate(),
            qubits=([WeakQubitRef(engine=engine, idx=1)], ),
            tags=[LogicalQubitIDTag(1)],
        )
        engine.send([deallocate_cmd])
    assert str(excinfo.value
               ) == "Cannot deallocate a qubit that is not already allocated!"

    # but we can still deallocate an already allocated one
    engine.deallocate_qubit(qureg[0])
    del qureg
    del engine
예제 #16
0
    def _send_possible_commands(self):
        """
        Sends the stored commands possible without changing the mapping.

        Note: self.current_mapping must exist already
        """
        active_ids = deepcopy(self._currently_allocated_ids)
        for logical_id in self.current_mapping:
            active_ids.add(logical_id)

        new_stored_commands = []
        for i in range(len(self._stored_commands)):
            cmd = self._stored_commands[i]
            if len(active_ids) == 0:
                new_stored_commands += self._stored_commands[i:]
                break
            if isinstance(cmd.gate, AllocateQubitGate):
                if cmd.qubits[0][0].id in self.current_mapping:
                    self._currently_allocated_ids.add(cmd.qubits[0][0].id)
                    qb = WeakQubitRef(
                        engine=self,
                        idx=self.current_mapping[cmd.qubits[0][0].id])
                    new_cmd = Command(
                        engine=self,
                        gate=AllocateQubitGate(),
                        qubits=([qb], ),
                        tags=[LogicalQubitIDTag(cmd.qubits[0][0].id)])
                    self.send([new_cmd])
                else:
                    new_stored_commands.append(cmd)
            elif isinstance(cmd.gate, DeallocateQubitGate):
                if cmd.qubits[0][0].id in active_ids:
                    qb = WeakQubitRef(
                        engine=self,
                        idx=self.current_mapping[cmd.qubits[0][0].id])
                    new_cmd = Command(
                        engine=self,
                        gate=DeallocateQubitGate(),
                        qubits=([qb], ),
                        tags=[LogicalQubitIDTag(cmd.qubits[0][0].id)])
                    self._currently_allocated_ids.remove(cmd.qubits[0][0].id)
                    active_ids.remove(cmd.qubits[0][0].id)
                    self._current_mapping.pop(cmd.qubits[0][0].id)
                    self.send([new_cmd])
                else:
                    new_stored_commands.append(cmd)
            else:
                send_gate = True
                mapped_ids = set()
                for qureg in cmd.all_qubits:
                    for qubit in qureg:
                        if qubit.id not in active_ids:
                            send_gate = False
                            break
                        mapped_ids.add(self.current_mapping[qubit.id])
                # Check that mapped ids are nearest neighbour
                if len(mapped_ids) == 2:
                    mapped_ids = list(mapped_ids)
                    diff = abs(mapped_ids[0] - mapped_ids[1])
                    if self.cyclic:
                        if diff != 1 and diff != self.num_qubits - 1:
                            send_gate = False
                    else:
                        if diff != 1:
                            send_gate = False
                if send_gate:
                    self._send_cmd_with_mapped_ids(cmd)
                else:
                    for qureg in cmd.all_qubits:
                        for qubit in qureg:
                            active_ids.discard(qubit.id)
                    new_stored_commands.append(cmd)
        self._stored_commands = new_stored_commands
예제 #17
0
 def add_logical_id(command, old_tags=deepcopy(cmd.tags)):
     command.tags = (old_tags +
                     [LogicalQubitIDTag(cmd.qubits[0][0].id)])
     return command
예제 #18
0
    def _send_possible_commands(self):  # pylint: disable=too-many-branches
        """
        Send the stored commands possible without changing the mapping.

        Note: self._current_row_major_mapping (hence also self.current_mapping) must exist already
        """
        active_ids = deepcopy(self._currently_allocated_ids)
        for logical_id in self._current_row_major_mapping:
            # So that loop doesn't stop before AllocateGate applied
            active_ids.add(logical_id)

        new_stored_commands = []
        for i, cmd in enumerate(self._stored_commands):
            if len(active_ids) == 0:
                new_stored_commands += self._stored_commands[i:]
                break
            if isinstance(cmd.gate, AllocateQubitGate):
                if cmd.qubits[0][0].id in self._current_row_major_mapping:
                    self._currently_allocated_ids.add(cmd.qubits[0][0].id)

                    mapped_id = self._current_row_major_mapping[cmd.qubits[0]
                                                                [0].id]
                    qb = WeakQubitRef(
                        engine=self,
                        idx=self._mapped_ids_to_backend_ids[mapped_id])
                    new_cmd = Command(
                        engine=self,
                        gate=AllocateQubitGate(),
                        qubits=([qb], ),
                        tags=[LogicalQubitIDTag(cmd.qubits[0][0].id)],
                    )
                    self.send([new_cmd])
                else:
                    new_stored_commands.append(cmd)
            elif isinstance(cmd.gate, DeallocateQubitGate):
                if cmd.qubits[0][0].id in active_ids:
                    mapped_id = self._current_row_major_mapping[cmd.qubits[0]
                                                                [0].id]
                    qb = WeakQubitRef(
                        engine=self,
                        idx=self._mapped_ids_to_backend_ids[mapped_id])
                    new_cmd = Command(
                        engine=self,
                        gate=DeallocateQubitGate(),
                        qubits=([qb], ),
                        tags=[LogicalQubitIDTag(cmd.qubits[0][0].id)],
                    )
                    self._currently_allocated_ids.remove(cmd.qubits[0][0].id)
                    active_ids.remove(cmd.qubits[0][0].id)
                    self._current_row_major_mapping.pop(cmd.qubits[0][0].id)
                    self._current_mapping.pop(cmd.qubits[0][0].id)
                    self.send([new_cmd])
                else:
                    new_stored_commands.append(cmd)
            else:
                send_gate = True
                mapped_ids = set()
                for qureg in cmd.all_qubits:
                    for qubit in qureg:
                        if qubit.id not in active_ids:
                            send_gate = False
                            break
                        mapped_ids.add(
                            self._current_row_major_mapping[qubit.id])
                # Check that mapped ids are nearest neighbour on 2D grid
                if len(mapped_ids) == 2:
                    qb0, qb1 = sorted(mapped_ids)
                    send_gate = False
                    if qb1 - qb0 == self.num_columns:
                        send_gate = True
                    elif qb1 - qb0 == 1 and qb1 % self.num_columns != 0:
                        send_gate = True
                if send_gate:
                    # Note: This sends the cmd correctly with the backend ids as it looks up the mapping in
                    #       self.current_mapping and not our internal mapping self._current_row_major_mapping
                    self._send_cmd_with_mapped_ids(cmd)
                else:
                    for qureg in cmd.all_qubits:
                        for qubit in qureg:
                            active_ids.discard(qubit.id)
                    new_stored_commands.append(cmd)
        self._stored_commands = new_stored_commands