def allocate_qureg(self, n, init=0.0): """ Allocate n qubits and return them as a quantum register, which is a list of qubit objects. Args: n (int): Number of qubits to allocate init (complex): Assign this value to every amplitude Returns: Qureg of length n, a list of n newly allocated qubits. """ cmd = Command(self, AllocateQuregGate(init), ()) if self.backend.is_available(cmd): qubits = Qureg() for i in range(n): new_id = self.main_engine.get_new_qubit_id() qb = Qubit(self, new_id) qubits.append(qb) self.main_engine.active_qubits.add(qb) cmd = Command(self, AllocateQuregGate(init), (qubits, )) self.send([cmd]) return qubits else: return super(MainEngine, self).allocate_qureg(n)
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}
def test_return_new_mapping_too_many_qubits(): mapper = lm.LinearMapper(num_qubits=3, cyclic=False) qb0 = WeakQubitRef(engine=None, idx=0) qb1 = WeakQubitRef(engine=None, idx=1) qb2 = WeakQubitRef(engine=None, idx=2) cmd0 = Command(None, QFT, qubits=([qb0], [qb1, qb2])) mapper._stored_commands = [cmd0] with pytest.raises(Exception): mapper.return_new_mapping( num_qubits=mapper.num_qubits, cyclic=mapper.cyclic, currently_allocated_ids=mapper._currently_allocated_ids, stored_commands=mapper._stored_commands, current_mapping=mapper.current_mapping, ) cmd1 = Command(None, BasicGate(), qubits=([],)) mapper._stored_commands = [cmd1] with pytest.raises(Exception): mapper.return_new_mapping( num_qubits=mapper.num_qubits, cyclic=mapper.cyclic, currently_allocated_ids=mapper._currently_allocated_ids, stored_commands=mapper._stored_commands, current_mapping=mapper.current_mapping, )
def test_controlled_gate_or(): saving_backend = DummyEngine(save_commands=True) main_engine = MainEngine(backend=saving_backend, engine_list=[DummyEngine()]) gate = Rx(0.6) qubit0 = Qubit(main_engine, 0) qubit1 = Qubit(main_engine, 1) qubit2 = Qubit(main_engine, 2) qubit3 = Qubit(main_engine, 3) expected_cmd = Command(main_engine, gate, ([qubit3], )) expected_cmd.add_control_qubits([qubit0, qubit1, qubit2]) received_commands = [] # Option 1: _metagates.ControlledGate(gate, 3) | ([qubit1], [qubit0], [qubit2 ], [qubit3]) # Option 2: _metagates.ControlledGate(gate, 3) | (qubit1, qubit0, qubit2, qubit3) # Option 3: _metagates.ControlledGate(gate, 3) | ([qubit1, qubit0], qubit2, qubit3) # Option 4: _metagates.ControlledGate(gate, 3) | (qubit1, [qubit0, qubit2], qubit3) # Wrong option 5: with pytest.raises(_metagates.ControlQubitError): _metagates.ControlledGate(gate, 3) | (qubit1, [qubit0, qubit2, qubit3]) # Remove Allocate and Deallocate gates for cmd in saving_backend.received_commands: if not (isinstance(cmd.gate, FastForwardingGate) or isinstance(cmd.gate, ClassicalInstructionGate)): received_commands.append(cmd) assert len(received_commands) == 4 for cmd in received_commands: assert cmd == expected_cmd
def deallocate_qubit(self, qubit): """ Deallocate a qubit (and sends the deallocation command down the pipeline). If the qubit was allocated as a dirty qubit, add DirtyQubitTag() to Deallocate command. Args: qubit (BasicQubit): Qubit to deallocate. """ if qubit.id != -1: if qubit.id not in self.main_engine.dirty_qubits: self.send([Command(self, Deallocate, ([qubit], ))]) else: from projectq.meta import DirtyQubitTag oldnext = self.next_engine def cmd_modifier(cmd): assert (cmd.gate == Deallocate) cmd.tags += [DirtyQubitTag()] return cmd self.next_engine = projectq.cengines.CommandModifier( cmd_modifier) self.next_engine.next_engine = oldnext self.send([Command(self, Deallocate, ([qubit], ))]) self.next_engine = oldnext
def test_aqt_backend_is_available_control_not(num_ctrl_qubits, is_available): eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()]) qubit1 = eng.allocate_qubit() qureg = eng.allocate_qureg(num_ctrl_qubits) aqt_backend = _aqt.AQTBackend() cmd = Command(eng, Rx(0.5), (qubit1, ), controls=qureg) assert aqt_backend.is_available(cmd) == is_available cmd = Command(eng, Rxx(0.5), (qubit1, ), controls=qureg) assert aqt_backend.is_available(cmd) == is_available
def test_wrong_final_state(): qb0 = WeakQubitRef(engine=None, idx=0) qb1 = WeakQubitRef(engine=None, idx=1) cmd = Command(None, StatePreparation([0, 1j]), qubits=([qb0, qb1], )) with pytest.raises(ValueError): stateprep2cnot._decompose_state_preparation(cmd) cmd2 = Command(None, StatePreparation([0, 0.999j]), qubits=([qb0], )) with pytest.raises(ValueError): stateprep2cnot._decompose_state_preparation(cmd2)
def test_ibm_backend_is_available_negative_control(): backend = _ibm.IBMBackend() qb0 = WeakQubitRef(engine=None, idx=0) qb1 = WeakQubitRef(engine=None, idx=1) assert backend.is_available(Command(None, NOT, qubits=([qb0],), controls=[qb1])) assert backend.is_available(Command(None, NOT, qubits=([qb0],), controls=[qb1], control_state='1')) assert not backend.is_available(Command(None, NOT, qubits=([qb0],), controls=[qb1], control_state='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
def test_openqasm_is_available(gate, is_available): eng = MainEngine(backend=DummyEngine(), engine_list=[OpenQASMEngine()]) qubit1 = eng.allocate_qubit() cmd = Command(eng, gate, (qubit1, )) eng.is_available(cmd) == is_available eng = MainEngine(backend=OpenQASMEngine(), engine_list=[]) qubit1 = eng.allocate_qubit() cmd = Command(eng, gate, (qubit1, )) eng.is_available(cmd) == is_available
def test_sqrtswap_invalid(): qb0 = WeakQubitRef(engine=None, idx=0) qb1 = WeakQubitRef(engine=None, idx=1) qb2 = WeakQubitRef(engine=None, idx=2) with pytest.raises(ValueError): sqrtswap2cnot._decompose_sqrtswap( Command(None, SqrtSwap, ([qb0], [qb1], [qb2]))) with pytest.raises(ValueError): sqrtswap2cnot._decompose_sqrtswap( Command(None, SqrtSwap, ([qb0], [qb1, qb2])))
def test_openqasm_is_available_2control(gate, is_available): eng = MainEngine(backend=DummyEngine(), engine_list=[OpenQASMEngine()]) qubit1 = eng.allocate_qubit() qureg = eng.allocate_qureg(2) cmd = Command(eng, gate, (qubit1, ), controls=qureg) assert eng.is_available(cmd) == is_available eng = MainEngine(backend=OpenQASMEngine(), engine_list=[]) qubit1 = eng.allocate_qubit() qureg = eng.allocate_qureg(2) cmd = Command(eng, gate, (qubit1, ), controls=qureg) assert eng.is_available(cmd) == is_available
def test_is_available(): mapper = two_d.GridMapper(num_rows=2, num_columns=2) qb0 = WeakQubitRef(engine=None, idx=0) qb1 = WeakQubitRef(engine=None, idx=1) qb2 = WeakQubitRef(engine=None, idx=2) cmd0 = Command(None, BasicGate(), qubits=([qb0],)) assert mapper.is_available(cmd0) cmd1 = Command(None, BasicGate(), qubits=([qb0],), controls=[qb1]) assert mapper.is_available(cmd1) cmd2 = Command(None, BasicGate(), qubits=([qb0], [qb1, qb2])) assert not mapper.is_available(cmd2) cmd3 = Command(None, BasicGate(), qubits=([qb0], [qb1]), controls=[qb2]) assert not mapper.is_available(cmd3)
def test_is_available(): mapper = lm.LinearMapper(num_qubits=5, cyclic=False) qb0 = WeakQubitRef(engine=None, idx=0) qb1 = WeakQubitRef(engine=None, idx=1) qb2 = WeakQubitRef(engine=None, idx=2) cmd0 = Command(None, BasicGate(), qubits=([qb0],)) assert mapper.is_available(cmd0) cmd1 = Command(None, BasicGate(), qubits=([qb0],), controls=[qb1]) assert mapper.is_available(cmd1) cmd2 = Command(None, BasicGate(), qubits=([qb0], [qb1, qb2])) assert not mapper.is_available(cmd2) cmd3 = Command(None, BasicGate(), qubits=([qb0], [qb1]), controls=[qb2]) assert not mapper.is_available(cmd3)
def test_run_infinite_loop_detection(): mapper = lm.LinearMapper(num_qubits=1, cyclic=False) 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]) qb2 = WeakQubitRef(engine=None, idx=-1) cmd_flush = Command(engine=None, gate=FlushGate(), qubits=([qb2],)) with pytest.raises(RuntimeError): mapper.receive([cmd0, cmd1, cmd2, cmd_flush])
def allocate_qubit(self, dirty=False): """ Return a new qubit as a list containing 1 qubit object (quantum register of size 1). Allocates a new qubit by getting a (new) qubit id from the MainEngine, creating the qubit object, and then sending an AllocateQubit command down the pipeline. If dirty=True, the fresh qubit can be replaced by a pre-allocated one (in an unknown, dirty, initial state). Dirty qubits must be returned to their initial states before they are deallocated / freed. All allocated qubits are added to the MainEngine's set of active qubits as weak references. This allows proper clean-up at the end of the Python program (using atexit), deallocating all qubits which are still alive. Qubit ids of dirty qubits are registered in MainEngine's dirty_qubits set. Args: dirty (bool): If True, indicates that the allocated qubit may be dirty (i.e., in an arbitrary initial state). Returns: Qureg of length 1, where the first entry is the allocated qubit. """ new_id = self.main_engine.get_new_qubit_id() qb = Qureg([Qubit(self, new_id)]) if dirty: from projectq.meta import DirtyQubitTag if self.is_meta_tag_supported(DirtyQubitTag): oldnext = self.next_engine def cmd_modifier(cmd): assert (cmd.gate == Allocate) cmd.tags += [DirtyQubitTag()] return cmd self.next_engine = projectq.cengines.CommandModifier( cmd_modifier) self.next_engine.next_engine = oldnext self.send([Command(self, Allocate, (qb, ))]) self.next_engine = oldnext self.main_engine.active_qubits.add(qb[0]) self.main_engine.dirty_qubits.add(qb[0].id) return qb self.send([Command(self, Allocate, (qb, ))]) self.main_engine.active_qubits.add(qb[0]) return qb
def test_send_possible_cmds_before_new_mapping(): mapper = two_d.GridMapper(num_rows=3, num_columns=1) backend = DummyEngine(save_commands=True) backend.is_last_engine = True mapper.next_engine = backend def dont_call_mapping(): raise Exception mapper._return_new_mapping = dont_call_mapping mapper.current_mapping = {0: 1} qb0 = WeakQubitRef(engine=None, idx=0) cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],)) qb2 = WeakQubitRef(engine=None, idx=-1) cmd_flush = Command(engine=None, gate=FlushGate(), qubits=([qb2],)) mapper.receive([cmd0, cmd_flush])
def test_send_possible_commands_keep_remaining_gates(): 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) qb1 = WeakQubitRef(engine=None, idx=1) cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],), controls=[], tags=[]) cmd1 = Command(engine=None, gate=Deallocate, qubits=([qb0],), controls=[], tags=[]) cmd2 = Command(engine=None, gate=Allocate, qubits=([qb1],), controls=[], tags=[]) mapper._stored_commands = [cmd0, cmd1, cmd2] mapper.current_mapping = {0: 0} mapper._send_possible_commands() assert mapper._stored_commands == [cmd2]
def test_filter_engine(): def my_filter(self, cmd): if cmd.gate == H: return True return False filter_eng = _replacer.InstructionFilter(my_filter) eng = MainEngine(backend=DummyEngine(), engine_list=[filter_eng]) qubit = eng.allocate_qubit() cmd = Command(eng, H, (qubit, )) cmd2 = Command(eng, X, (qubit, )) assert eng.is_available(cmd) assert not eng.is_available(cmd2) assert filter_eng.is_available(cmd) assert not filter_eng.is_available(cmd2)
def test_control_engine_has_compute_tag(): eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()]) qubit = eng.allocate_qubit() test_cmd0 = Command(eng, H, (qubit,)) test_cmd1 = Command(eng, H, (qubit,)) test_cmd2 = Command(eng, H, (qubit,)) test_cmd0.tags = [DirtyQubitTag(), ComputeTag(), DirtyQubitTag()] test_cmd1.tags = [DirtyQubitTag(), UncomputeTag(), DirtyQubitTag()] test_cmd2.tags = [DirtyQubitTag()] assert _control._has_compute_uncompute_tag(test_cmd0) assert _control._has_compute_uncompute_tag(test_cmd1) assert not _control._has_compute_uncompute_tag(test_cmd2)
def test_drawer_measurement(): drawer = CircuitDrawerMatplotlib(default_measure=0) eng = MainEngine(drawer, []) qubit = eng.allocate_qubit() Measure | qubit assert int(qubit) == 0 drawer = CircuitDrawerMatplotlib(default_measure=1) eng = MainEngine(drawer, []) qubit = eng.allocate_qubit() Measure | qubit assert int(qubit) == 1 drawer = CircuitDrawerMatplotlib(accept_input=True) eng = MainEngine(drawer, []) qubit = eng.allocate_qubit() old_input = _drawer.input _drawer.input = lambda x: '1' Measure | qubit assert int(qubit) == 1 _drawer.input = old_input qb1 = WeakQubitRef(engine=eng, idx=1) qb2 = WeakQubitRef(engine=eng, idx=2) with pytest.raises(ValueError): eng.backend._process(Command(engine=eng, gate=Measure, qubits=([qb1],), controls=[qb2]))
def deallocate_qubit(self, qubit): """ Deallocate a qubit (and sends the deallocation command down the pipeline). If the qubit was allocated as a dirty qubit, add DirtyQubitTag() to Deallocate command. Args: qubit (BasicQubit): Qubit to deallocate. Raises: ValueError: Qubit already deallocated. Caller likely has a bug. """ if qubit.id == -1: raise ValueError("Already deallocated.") is_dirty = qubit.id in self.dirty_qubits weak_copy = WeakQubitRef(qubit.engine, qubit.id) if not isinstance(qubit, WeakQubitRef): if qubit in self.active_qubits: self.active_qubits.remove(qubit) qubit.id = -1 from projectq.meta import DirtyQubitTag self.send([ Command(self, Deallocate, (Qureg([weak_copy]), ), tags=[DirtyQubitTag()] if is_dirty else []) ])
def deallocate_qubit(self, qubit): """ Deallocate a qubit (and sends the deallocation command down the pipeline). If the qubit was allocated as a dirty qubit, add DirtyQubitTag() to Deallocate command. Args: qubit (BasicQubit): Qubit to deallocate. Raises: ValueError: Qubit already deallocated. Caller likely has a bug. """ if qubit.id == -1: raise ValueError("Already deallocated.") from projectq.meta import ( # pylint: disable=import-outside-toplevel DirtyQubitTag, ) is_dirty = qubit.id in self.main_engine.dirty_qubits self.send([ Command( self, Deallocate, ([WeakQubitRef(engine=qubit.engine, idx=qubit.id)], ), tags=[DirtyQubitTag()] if is_dirty else [], ) ]) # Mark qubit as deallocated qubit.id = -1
def test_send_possible_commands_deallocate(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=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 len(mapper._stored_commands) == 0 assert mapper.current_mapping == {} assert mapper._currently_allocated_ids == {10}
def test_aqt_invalid_command(): backend = _aqt.AQTBackend(verbose=True) qb = WeakQubitRef(None, 1) cmd = Command(None, gate=S, qubits=[(qb, )]) with pytest.raises(Exception): backend.receive([cmd])
def test_ibm_backend_is_available_control_not(num_ctrl_qubits, is_available): eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()]) qubit1 = eng.allocate_qubit() qureg = eng.allocate_qureg(num_ctrl_qubits) ibm_backend = _ibm.IBMBackend() cmd = Command(eng, NOT, (qubit1, ), controls=qureg) assert ibm_backend.is_available(cmd) == is_available
def test_controlled_gate_empty_controls(): rec = DummyEngine(save_commands=True) eng = MainEngine(backend=rec, engine_list=[]) a = eng.allocate_qureg(1) _metagates.ControlledGate(Y, 0) | ((), a) assert rec.received_commands[-1] == Command(eng, Y, [a])
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}
def test_command_printer_is_available(): inline_cmd_printer = _printer.CommandPrinter() cmd_printer = _printer.CommandPrinter() def available_cmd(self, cmd): return cmd.gate == H filter = InstructionFilter(available_cmd) eng = MainEngine(backend=cmd_printer, engine_list=[inline_cmd_printer, filter]) qubit = eng.allocate_qubit() cmd0 = Command(eng, H, (qubit,)) cmd1 = Command(eng, T, (qubit,)) assert inline_cmd_printer.is_available(cmd0) assert not inline_cmd_printer.is_available(cmd1) assert cmd_printer.is_available(cmd0) assert cmd_printer.is_available(cmd1)
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