0

I am currently trying to replace a whole class Instruction from an external module with my own implementation NamedRoutine. I want the external module to use my re-definition instead of the original class Instruction.

In order to have the best compatibility possible, and because I don't want to re-type the Instruction class, the redefined class inherits from Instruction. The NamedRoutine implementation is:

from qiskit.circuit.instruction import Instruction

from ._interfaces import interfaces


class NamedRoutine(Instruction, interfaces.NamedRoutine):
    def __init__(self, name: str, num_qubits: int, num_clbits: int, params):
        super().__init__(
            name=name, num_qubits=num_qubits, num_clbits=num_clbits, params=params
        )
        self.name = name

    @staticmethod
    def from_Routine(rout: Instruction) -> "NamedRoutine":
        named_routine = NamedRoutine(
            rout.name, rout.num_qubits, rout.num_clbits, rout.params
        )
        named_routine.definition = rout.definition
        return named_routine

    @staticmethod
    def from_Routine_and_name(rout: Instruction, name: str) -> "NamedRoutine":
        named_routine = NamedRoutine(
            name, rout.num_qubits, rout.num_clbits, rout.params
        )
        named_routine.definition = rout.definition
        return named_routine

    def inverse(self) -> "NamedRoutine":
        return NamedRoutine.from_Routine_and_name(
            super().inverse(), name="D-" + self.name
        )

As you can see, there is no compatibility issue between the 2 classes. The NamedRoutine implementation just ensure that a proper name is set, adds 2 static methods and overloads one method of Instruction to change the instance name attribute accordingly.

In order to replace completely the definition of qiskit.circuit.instruction.Instruction by my NamedRoutine implementation, I tried to call the following function before any qiskit-related code is imported:

def _wrap_instruction_class():
    import qiskit.circuit.instruction
    from .NamedRoutine import NamedRoutine

    setattr(qiskit.circuit.instruction, "Instruction", NamedRoutine)
    setattr(qiskit.circuit, "Instruction", NamedRoutine)

Note: Instruction is imported in the __init__.py file of qiskit.circuit.

This method nearly works as I am successfully replacing the definitions of Instruction by my own implementation.

The problem I am still facing is the following: when importing qiskit.circuit.instruction, the __init__.py files of the qiskit and qiskit.circuit modules are executed, and load a ton of methods/classes with the original definition of the Instruction method (as it is still not replaced).

The number of methods/functions/classes using this Instruction class being quite huge, I don't want to track them one by one. Moreover, this solution would require me to check after each update of the qiskit library if one more routine/function/class need to be "injected".

I also searched for a solution "unimporting" everything from the qiskit library except the Instruction class, and then re-importing all the relevant parts once the Instruction class has been modified, but it appears that unimporting is not possible in Python.

One possible solution would be to recursively import all the packages/modules of the qiskit library and replace the symbol Instruction with my definition if it is defined in the module, but this would require to import all the modules from qiskit. My software is not really constrained by runtime, but this takes approximately 4 seconds on my laptop with a recent SSD and a rather clean (low number of packages) virtual environment, and it may take a lot more depending on the packages installed on the machine.

Do any of you have another solution, possibly more efficient than iterating over all the modules to find the modules in qiskit where the Instruction symbol is defined and replace it?

Adrien Suau
  • 269
  • 3
  • 11
  • Why don't you just change the `qiskit.circuit.instruction` files directly? – Akaisteph7 Aug 04 '19 at 15:48
  • I want the modification to be non-persistent. I don't want the users to have to re-install each time they need to use the library without my tool. If there is a secure way to roll-back the modifications done to the file when the Python interpreter exits, then this idea may suits my needs. – Adrien Suau Aug 04 '19 at 16:19
  • I just found the [atexit](https://docs.python.org/3.5/library/atexit.html) library. It is may suits my needs but I already see some issues: a program running in parallel will be affected by the modifications and performing IOs at program termination seems strange to me. But it may work! – Adrien Suau Aug 04 '19 at 16:23

0 Answers0