From 8afb859dd0aaec9fb0df8f40094cf44d80ee78e0 Mon Sep 17 00:00:00 2001 From: Didictateur Date: Sun, 29 Oct 2023 23:34:08 +0100 Subject: [PATCH] added circuit --- QElephant/Circuit.py | 59 ++++++++++++++++++++++++++++++++++++++++++++ QElephant/QuBit.py | 46 +++++++++++++++++++++++++--------- 2 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 QElephant/Circuit.py diff --git a/QElephant/Circuit.py b/QElephant/Circuit.py new file mode 100644 index 0000000..7c821b0 --- /dev/null +++ b/QElephant/Circuit.py @@ -0,0 +1,59 @@ +import matplotlib.pyplot as plt +from matplotlib.patches import Rectangle, Circle +from QElephant.QuBit import * + +class Circuit: + def __init__(self, n: int, instructions=[]): + self.__instr = instructions + self.__n = n + self.__mubit = MuBit(self.__n) + self.__mubit._MuBit__callBack = self.__recv + + def __recv(self, gate: str, target: int, neighbor: list[int]): + self.__instr.append((gate, target, neighbor)) + + def __rect(self, q_i: int, i: int, txt: str, size: int) -> None: + rec = Rectangle((q_i-0.25, i-0.25), 0.5, 0.5, fill=False) + if len(txt) >= 4: + plt.text(q_i, i, txt, size=min(int(40/size), int(40/self.__n)), ha='center', va='center') + else: + plt.text(q_i, i, txt, size=min(int(70/size), int(70/self.__n)), ha='center', va='center') + plt.gca().add_patch(rec) + + def __line(self, A, B) -> None: + plt.plot([A[0], B[0]], [A[1], B[1]], color='Black') + + def __circle(self, x: float, y: float, radius: float) -> None: + circ = Circle((x, y), radius, fill=True, color='Black') + plt.gca().add_patch(circ) + + def draw(self) -> None: + n = len(self.__instr) + plt.yticks(range(self.__n), [f"QuBit {i}" for i in range(self.__n)]) + plt.xticks(range(1, n+1), [f"Step {i+1}" for i in range(n)]) + + i = 0 + while i < n: + txt, index, neigbhor = self.__instr[i] + for q_i in range(self.__n): + self.__line((i+0.5, q_i), (i+0.75, q_i)) + self.__line((i+1.25, q_i), (i+1.5, q_i)) + + if q_i == index: + self.__rect(i+1, q_i, txt, n) + for neig in neigbhor: + self.__circle(i+1, neig, 0.05) + if neig > q_i: + self.__line((i+1, q_i+0.25), (i+1, neig)) + elif neig < q_i: + self.__line((i+1, q_i-0.25), (i+1, neig)) + else: + raise ValueError("Cannot apply gate twice on the same QuBit") + else: + self.__line((i+0.75, q_i), (i+1.25, q_i)) + i += 1 + plt.show() + +if __name__=="__main__": + c = Circuit(3, [("CS", 0, [1]), ("CX", 2, [0]), ("TX", 1, [0, 2])]) + c.draw() \ No newline at end of file diff --git a/QElephant/QuBit.py b/QElephant/QuBit.py index 5f1685a..d779582 100644 --- a/QElephant/QuBit.py +++ b/QElephant/QuBit.py @@ -18,6 +18,11 @@ class MuBit: self.__n = n self.__state: list[complex] = [0]*(2**self.__n) self.__state[0] = 1 + self.__callBack = None + + def __emit(self, gate: str, target: int, neighbor: list[int]=[]) -> None: + if self.__callBack is not None: + self.__callBack(gate, target, neighbor) def get_size(self) -> int: return self.__n @@ -308,6 +313,7 @@ class IQuBit(QuBit): def H(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.H()) + q._IQuBit__muBit._MuBit__emit("H", q._IQuBit__n, []) elif type(q) == QuBit: q._QuBit__apply(Matrix.H()) else: @@ -316,6 +322,7 @@ def H(q: QuBit) -> None: def X(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.X()) + q._IQuBit__muBit._MuBit__emit("X", q._IQuBit__n, []) elif type(q) == QuBit: q._QuBit__apply(Matrix.X()) else: @@ -324,6 +331,7 @@ def X(q: QuBit) -> None: def SQRTX(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.SQRTX()) + q._IQuBit__muBit._MuBit__emit("SQRTX", q._IQuBit__n, []) elif type(q) == QuBit: q._QuBit__apply(Matrix.SQRTX()) else: @@ -332,6 +340,7 @@ def SQRTX(q: QuBit) -> None: def Y(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.Y()) + q._IQuBit__muBit._MuBit__emit("Y", q._IQuBit__n, []) elif type(q) == QuBit: q._QuBit__apply(Matrix.Y()) else: @@ -340,6 +349,7 @@ def Y(q: QuBit) -> None: def Z(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.Z()) + q._IQuBit__muBit._MuBit__emit("Z", q._IQuBit__n, []) elif type(q) == QuBit: q._QuBit__apply(Matrix.Z()) else: @@ -348,6 +358,7 @@ def Z(q: QuBit) -> None: def S(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.S()) + q._IQuBit__muBit._MuBit__emit("S", q._IQuBit__n, []) elif type(q) == QuBit: q._QuBit__apply(Matrix.S()) else: @@ -356,6 +367,7 @@ def S(q: QuBit) -> None: def T(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.T()) + q._IQuBit__muBit._MuBit__emit("T", q._IQuBit__n, []) elif type(q) == QuBit: q._QuBit__apply(Matrix.T()) else: @@ -365,10 +377,11 @@ def Rx(q: QuBit, phi: float) -> None: if type(phi) not in {int, float}: raise TypeError(f"an angle must be integer or float, not {type(phi)}") - if type(q) == QuBit: - q._QuBit__apply(Matrix.Rx(phi)) - elif type(q) == IQuBit: + if type(q) == IQuBit: q._IQuBit__apply(Matrix.Rx(phi)) + q._IQuBit__muBit._MuBit__emit("Rx", q._IQuBit__n, []) + elif type(q) == QuBit: + q._QuBit__apply(Matrix.Rx(phi)) else: raise TypeError(f"a QuBit was expected, but a {type(q)} was given") @@ -376,10 +389,11 @@ def Ry(q: QuBit, phi: float) -> None: if type(phi) not in {int, float}: raise TypeError(f"an angle must be integer or float, not {type(phi)}") - if type(q) == QuBit: - q._QuBit__apply(Matrix.Ry(phi)) - elif type(q) == IQuBit: + if type(q) == IQuBit: q._IQuBit__apply(Matrix.Ry(phi)) + q._IQuBit__muBit._MuBit__emit("Ry", q._IQuBit__n, []) + elif type(q) == QuBit: + q._QuBit__apply(Matrix.Ry(phi)) else: raise TypeError(f"a QuBit was expected, but a {type(q)} was given") @@ -387,10 +401,11 @@ def Rz(q: QuBit, phi: float) -> None: if type(phi) not in {int, float}: raise TypeError(f"an angle must be integer or float, not {type(phi)}") - if type(q) == QuBit: - q._QuBit__apply(Matrix.Rz(phi)) - elif type(q) == IQuBit: + if type(q) == IQuBit: q._IQuBit__apply(Matrix.Rz(phi)) + q._IQuBit__muBit._MuBit__emit("H", q._IQuBit__n, []) + elif type(q) == QuBit: + q._QuBit__apply(Matrix.Rz(phi)) else: raise TypeError(f"a QuBit was expected, but a {type(q)} was given") @@ -398,10 +413,11 @@ def R1(q: QuBit, phi: float) -> None: if type(phi) not in {int, float}: raise TypeError(f"an angle must be integer or float, not {type(phi)}") - if type(q) == QuBit: - q._QuBit__apply(Matrix.R1(phi)) - elif type(q) == IQuBit: + if type(q) == IQuBit: q._IQuBit__apply(Matrix.R1(phi)) + q._IQuBit__muBit._MuBit__emit("R1", q._IQuBit__n, []) + elif type(q) == QuBit: + q._QuBit__apply(Matrix.R1(phi)) else: raise TypeError(f"a QuBit was expected, but a {type(q)} was given") @@ -425,6 +441,7 @@ def CX(q: MuBit, n1: int, n2: int) -> None: q._MuBit__mapply(Matrix.CX(), n-2) SWAP(q, n-2, n1) SWAP(q, n-1, n2) + q._MuBit__emit("CX", n1, [n2]) def CY(q: MuBit, n1: int, n2: int) -> None: if type(q) is not MuBit: @@ -446,6 +463,7 @@ def CY(q: MuBit, n1: int, n2: int) -> None: q._MuBit__mapply(Matrix.CY(), n-2) SWAP(q, n-2, n1) SWAP(q, n-1, n2) + q._MuBit__emit("CY", n1, [n2]) def CZ(q: MuBit, n1: int, n2: int) -> None: if type(q) is not MuBit: @@ -467,6 +485,7 @@ def CZ(q: MuBit, n1: int, n2: int) -> None: q._MuBit__mapply(Matrix.CZ(), n-2) SWAP(q, n-2, n1) SWAP(q, n-1, n2) + q._MuBit__emit("CZ", n1, [n2]) def SWAP(q: MuBit, n1: int, n2: int) -> None: if type(q) is not MuBit: @@ -487,6 +506,8 @@ def SWAP(q: MuBit, n1: int, n2: int) -> None: q._MuBit__SWITCH(i) for i in range(nmax-2, nmin-1, -1): q._MuBit__SWITCH(i) + + q._MuBit__emit("SWAP", n1, [n2]) def Cu(q: MuBit, u: list[list[complex]], n1: int, n2: int) -> None: if type(q) is not MuBit: @@ -521,3 +542,4 @@ def Cu(q: MuBit, u: list[list[complex]], n1: int, n2: int) -> None: q._MuBit__mapply(Matrix.Cu(u), n-2) SWAP(q, n-2, n1) SWAP(q, n-1, n2) + q._MuBit__emit("Cu", n1, [n2]) \ No newline at end of file