diff --git a/netqasm/lang/instr/flavour.py b/netqasm/lang/instr/flavour.py index 15eed27..f696b75 100644 --- a/netqasm/lang/instr/flavour.py +++ b/netqasm/lang/instr/flavour.py @@ -112,3 +112,12 @@ def instrs(self): def __init__(self): super().__init__(self.instrs) + + +class REIDSFlavour(Flavour): + @property + def instrs(self): + return [] + + def __init__(self): + super().__init__(self.instrs) diff --git a/netqasm/sdk/transpile.py b/netqasm/sdk/transpile.py index d389990..b31e534 100644 --- a/netqasm/sdk/transpile.py +++ b/netqasm/sdk/transpile.py @@ -9,6 +9,7 @@ from typing import Dict, List, Optional, Set, Tuple, Union from netqasm.lang.instr import DebugInstruction, NetQASMInstruction, core, nv, vanilla +from netqasm.lang.instr.flavour import REIDSFlavour from netqasm.lang.operand import Immediate, Register, RegisterName from netqasm.lang.subroutine import Subroutine from netqasm.runtime.settings import get_is_using_hardware @@ -17,7 +18,8 @@ class SubroutineTranspiler(abc.ABC): def __init__(self, subroutine: Subroutine, debug: bool = False): - pass + self._subroutine: Subroutine = subroutine + self._debug: bool = debug @abc.abstractmethod def transpile(self) -> Subroutine: @@ -31,10 +33,9 @@ class NVSubroutineTranspiler(SubroutineTranspiler): """ def __init__(self, subroutine: Subroutine, debug=False): - self._subroutine: Subroutine = subroutine + super().__init__(subroutine, debug) self._used_registers: Set[Register] = set() self._register_values: Dict[Register, Immediate] = dict() - self._debug: bool = debug def get_reg_value(self, reg: Register) -> Immediate: """Get the value of a register at this moment""" @@ -51,10 +52,10 @@ def get_unused_register(self) -> Register: raise RuntimeError("Could not find free register") def swap( - self, - lineno: Optional[HostLine], - electron: Register, - carbon: Register, + self, + lineno: Optional[HostLine], + electron: Register, + carbon: Register, ) -> List[NetQASMInstruction]: """ Swap the states of the electron and a carbon. @@ -159,7 +160,7 @@ def transpile(self) -> Subroutine: index_changes[i] = len(new_commands) if isinstance(instr, core.SingleQubitInstruction) or isinstance( - instr, core.RotationInstruction + instr, core.RotationInstruction ): new_commands += self._handle_single_qubit_gate(instr) elif isinstance(instr, core.TwoQubitInstruction): @@ -171,9 +172,9 @@ def transpile(self) -> Subroutine: for instr in new_commands: if ( - isinstance(instr, core.BranchUnaryInstruction) - or isinstance(instr, core.BranchBinaryInstruction) - or isinstance(instr, core.JmpInstruction) + isinstance(instr, core.BranchUnaryInstruction) + or isinstance(instr, core.BranchBinaryInstruction) + or isinstance(instr, core.JmpInstruction) ): original_line = instr.line.value if original_line == len(self._subroutine.instructions): @@ -196,7 +197,7 @@ def transpile(self) -> Subroutine: return self._subroutine def _move_electron_carbon( - self, instr: vanilla.MovInstruction + self, instr: vanilla.MovInstruction ) -> List[NetQASMInstruction]: """ See https://gitlab.tudelft.nl/qinc-wehner/netqasm/netqasm-docs/-/blob/master/nv-gates-docs.md @@ -228,7 +229,7 @@ def _move_electron_carbon( ] def _move_carbon_electron( - self, instr: vanilla.MovInstruction + self, instr: vanilla.MovInstruction ) -> List[NetQASMInstruction]: """ See https://gitlab.tudelft.nl/qinc-wehner/netqasm/netqasm-docs/-/blob/master/nv-gates-docs.md @@ -266,7 +267,7 @@ def _move_carbon_electron( ] def _handle_two_qubit_gate( - self, instr: core.TwoQubitInstruction + self, instr: core.TwoQubitInstruction ) -> List[NetQASMInstruction]: try: qubit_id0 = self.get_reg_value(instr.reg0).value @@ -312,8 +313,8 @@ def _handle_two_qubit_gate( ) def _map_cphase_electron_carbon( - self, - instr: vanilla.CphaseInstruction, + self, + instr: vanilla.CphaseInstruction, ) -> List[NetQASMInstruction]: electron = instr.reg0 carbon = instr.reg1 @@ -345,7 +346,7 @@ def _map_cphase_electron_carbon( ] def _map_cphase_carbon_carbon( - self, instr: vanilla.CphaseInstruction + self, instr: vanilla.CphaseInstruction ) -> List[NetQASMInstruction]: """ See https://gitlab.tudelft.nl/qinc-wehner/netqasm/netqasm-docs/-/blob/master/nv-gates-docs.md @@ -360,15 +361,15 @@ def _map_cphase_carbon_carbon( result: List[NetQASMInstruction] = [set_electron] result += ( - self.swap(instr.lineno, electron, carbon) - + self._map_cphase_electron_carbon(instr) - + self.swap(instr.lineno, electron, carbon) + self.swap(instr.lineno, electron, carbon) + + self._map_cphase_electron_carbon(instr) + + self.swap(instr.lineno, electron, carbon) ) return result def _map_cnot_electron_carbon( - self, - instr: vanilla.CnotInstruction, + self, + instr: vanilla.CnotInstruction, ) -> List[NetQASMInstruction]: electron = instr.reg0 carbon = instr.reg1 @@ -394,8 +395,8 @@ def _map_cnot_electron_carbon( ] def _map_cnot_carbon_electron( - self, - instr: vanilla.CnotInstruction, + self, + instr: vanilla.CnotInstruction, ) -> List[NetQASMInstruction]: """ See https://gitlab.tudelft.nl/qinc-wehner/netqasm/netqasm-docs/-/blob/master/nv-gates-docs.md @@ -436,7 +437,7 @@ def _map_cnot_carbon_electron( return gates def _map_cnot_carbon_carbon( - self, instr: vanilla.CnotInstruction + self, instr: vanilla.CnotInstruction ) -> List[NetQASMInstruction]: """ See https://gitlab.tudelft.nl/qinc-wehner/netqasm/netqasm-docs/-/blob/master/nv-gates-docs.md @@ -451,21 +452,21 @@ def _map_cnot_carbon_carbon( result: List[NetQASMInstruction] = [set_electron] result += ( - self.swap(instr.lineno, electron, carbon) - + self._map_cnot_electron_carbon(instr) - + self.swap(instr.lineno, electron, carbon) + self.swap(instr.lineno, electron, carbon) + + self._map_cnot_electron_carbon(instr) + + self.swap(instr.lineno, electron, carbon) ) return result def _handle_single_qubit_gate( - self, - instr: Union[core.SingleQubitInstruction, core.RotationInstruction], + self, + instr: Union[core.SingleQubitInstruction, core.RotationInstruction], ) -> List[NetQASMInstruction]: return self._map_single_gate(instr) def _map_single_gate( - self, - instr: Union[core.SingleQubitInstruction, core.RotationInstruction], + self, + instr: Union[core.SingleQubitInstruction, core.RotationInstruction], ) -> List[NetQASMInstruction]: if isinstance(instr, vanilla.GateXInstruction): return [ @@ -614,8 +615,51 @@ def _map_single_gate( ) +class REIDSSubroutineTranspiler(SubroutineTranspiler): + """ + A transpiler that converts a subroutine with the vanilla flavour + to a subroutine with the REIDS flavour. + """ + + def __init__(self, subroutine: Subroutine, debug: bool = False): + super().__init__(subroutine, debug) + self._flavour = REIDSFlavour() + + def transpile(self) -> Subroutine: + add_no_op_at_end: bool = False + + for instr in self._subroutine.instructions: + try: + self._flavour.id_map[instr.id] + except KeyError as e: + raise ValueError( + f"Instruction {instr} not supported: Unsupported instruction for REIDS flavour." + ) from e + + if ( + isinstance(instr, core.BranchUnaryInstruction) + or isinstance(instr, core.BranchBinaryInstruction) + or isinstance(instr, core.JmpInstruction) + ): + original_line = instr.line.value + if original_line == len(self._subroutine.instructions): + # There was a label in the original subroutine at the very end. + # Since this label is now removed, we should put a "no-op" + # instruction there so there is something to jump to. + add_no_op_at_end = True + + if add_no_op_at_end: + self._subroutine.instructions += [ + core.SetInstruction( + lineno=None, reg=Register(RegisterName.C, 15), imm=Immediate(1337) + ) + ] + + return self._subroutine + + def get_hardware_num_denom( - instr: core.RotationInstruction, + instr: core.RotationInstruction, ) -> Tuple[Immediate, Immediate]: if instr.angle_denom.value not in [0, 1, 2, 3, 4]: raise ValueError( @@ -623,5 +667,5 @@ def get_hardware_num_denom( ) denom_diff = 4 - instr.angle_denom.value - angle_num = instr.angle_num.value * (2**denom_diff) + angle_num = instr.angle_num.value * (2 ** denom_diff) return (Immediate(angle_num), Immediate(4))