diff --git a/QElephant/QuBit.py b/QElephant/QuBit.py index 0e4748a..4b0d769 100644 --- a/QElephant/QuBit.py +++ b/QElephant/QuBit.py @@ -9,6 +9,11 @@ I = complex(0, 1) class MuBit: def __init__(self, n: int=2) -> None: + if type(n) is not int: + raise TypeError(f"number of state must be an intergers, not {type(n)}") + if not n >= 2: + raise ValueError("a MuBit must have at least two intricated QuBit") + self.__n = n self.__state: list[complex] = [0]*(2**self.__n) self.__state[0] = 1 @@ -34,8 +39,14 @@ class MuBit: def __set(self, i: int, value: int) -> None: """Set the nth QuBit into value""" - assert(value in {0, 1}) + if type(i) is not int: + raise TypeError(f"MuBit indices must be integers, not {type(i)}") + if i > self.__n: + raise IndexError("MuBit index out of range") + if not value in {0, 1}: + raise ValueError(f"QuBit state must be 0 or 1, not {value}") + i = i%self.__n M = Matrix([[1]]) for j in range(self.__n): if j == i: @@ -50,12 +61,26 @@ class MuBit: return iter([IQuBit(i, self) for i in range(self.__n)]) def __getitem__(self, item: int) -> "QuBit": + if type(item) is not int: + raise TypeError(f"MuBit indices must be integers, not {type(item)}") + if item > self.__n: + raise IndexError("MuBit index out of range") + + item = item%self.__n return IQuBit(item, self) def __apply(self, i: int, matrix: Matrix) -> None: + if type(i) is not int: + raise TypeError(f"MuBit indices must be integers, not {type(i)}") + if i > self.__n: + raise IndexError("MuBit index out of range") + if type(matrix) is not Matrix: + raise TypeError(f"can only manipulate MuBit with Matrix, not {type(matrix)}") + i = i%self.__n + M = Matrix([[1]]) - for j in range(self.n): + for j in range(self.__n): if j == i: M *= matrix else: @@ -64,6 +89,14 @@ class MuBit: self.__state = M._Matrix__apply(self.__state) def __mapply(self, matrix: Matrix, i: int) -> None: + if type(i) is not int: + raise TypeError(f"MuBit indices must be integers, not {type(i)}") + if i > self.__n: + raise IndexError("MuBit index out of range") + if type(matrix) is not Matrix: + raise TypeError(f"can only manipulate MuBit with Matrix, not {type(matrix)}") + i = i%self.__n + M = Matrix([[1]]) j = 0 while j < self.__n: @@ -77,6 +110,12 @@ class MuBit: def __getProb(self, i: int) -> float: """Probs for i to be zero""" + if type(i) is not int: + raise TypeError(f"MuBit indices must be integers, not {type(i)}") + if i > self.__n: + raise IndexError("MuBit index out of range") + i = i%self.__n + M = Matrix([[1]]) for j in range(self.__n): @@ -94,10 +133,33 @@ class MuBit: l.append(IQuBit(i, self).observe()) return l + @staticmethod + def intricateThem(*args: "QuBit") -> "MuBit": + for q in args: + if type(q) is IQuBit: + raise TypeError("cannot intricate QuBit that are already intricated") + if type(q) is not QuBit: + raise TypeError(f"cannot intricate QuBit and {type(q)}") + if len(args) < 2: + raise ValueError("cannot intricate less than two QuBits") + + S = Matrix([[1]]) + for q in args: + S *= Matrix([q._QuBit__state]) + + mq = MuBit(len(args)) + mq._MuBit__state = S._Matrix__m[0] + return mq + class QuBit: def __init__(self, alpha: complex=1, beta: complex=0): + if type(alpha) not in {int, float, complex}: + TypeError(f"QuBit state must be int, float or complex, not {type(alpha)}") + if type(beta) not in {int, float, complex}: + TypeError(f"QuBit state must be int, float or complex, not {type(alpha)}") if abs(alpha)**2 + abs(beta)**2 != 1: - raise Exception("The initial state must be normalized") + raise ValueError(f"the initial state must be normalized. Here, |alpha|**2+|beta|**2={abs(alpha)**2 + abs(beta)**2}") + self.__state = [alpha, beta] self.__intricated = False @@ -111,6 +173,9 @@ class QuBit: return f"{round(self.__state[0], 3)} |0> + {round(self.__state[1], 3)} |1>" def __apply(self, matrix: Matrix) -> None: + if type(matrix) is not Matrix: + raise TypeError(f"can only manipulate QuBit with Matrix, not {type(matrix)}") + self.__state = matrix._Matrix__apply(self.__state) def observe(self) -> list[int]: @@ -123,6 +188,14 @@ class QuBit: class IQuBit(QuBit): def __init__(self, n: int, mb: MuBit) -> None: + if type(n) is not int: + raise TypeError(f"MuBit indices must be interger, not {type(n)}") + if n > mb._MuBit__n: + raise ValueError(f"MuBit index out of range") + if type(mb) is not MuBit: + TypeError(f"an intricate QuBit should be associated with a MuBit, not a {type(mb)}") + n = n%mb._MuBit__n + super().__init__() self.__n = n self.__muBit = mb @@ -139,6 +212,9 @@ class IQuBit(QuBit): return str(QuBit(math.sqrt(p), math.sqrt(1-p))) def __apply(self, matrix: Matrix) -> None: + if type(matrix) is not Matrix: + raise TypeError(f"can only manipulate QuBit with Matrix, not {type(matrix)}") + self.__muBit._MuBit__apply(self.__n, matrix) def observe(self) -> int: @@ -160,62 +236,98 @@ def H(q: QuBit) -> None: q._IQuBit__apply(Matrix.H()) elif type(q) == QuBit: q._QuBit__apply(Matrix.H()) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def X(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.X()) elif type(q) == QuBit: q._QuBit__apply(Matrix.X()) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def Y(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.Y()) elif type(q) == QuBit: q._QuBit__apply(Matrix.Y()) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def Z(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.Z()) elif type(q) == QuBit: q._QuBit__apply(Matrix.Z()) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def S(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.S()) elif type(q) == QuBit: q._QuBit__apply(Matrix.S()) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def T(q: QuBit) -> None: if type(q) == IQuBit: q._IQuBit__apply(Matrix.T()) elif type(q) == QuBit: q._QuBit__apply(Matrix.T()) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def Rx(q: QuBit, phi: float) -> None: + if type(phi) not in {int, float}: + 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: q._IQuBit__apply(Matrix.Rx(phi)) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def Ry(q: QuBit, phi: float) -> None: + if type(phi) not in {int, float}: + 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: q._IQuBit__apply(Matrix.Ry(phi)) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def Rz(q: QuBit, phi: float) -> None: + if type(phi) not in {int, float}: + 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: q._IQuBit__apply(Matrix.Rz(phi)) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def R1(q: QuBit, phi: float) -> None: + if type(phi) not in {int, float}: + 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: q._IQuBit__apply(Matrix.R1(phi)) + else: + raise TypeError(f"a QuBit was expected, but a {type(q)} was given") def CNOT(q: MuBit, n1: int, n2: int) -> None: + if type(q) is not MuBit: + TypeError(f"a MuBit was expected, but a {type(q)} was given") + if type() + SWAP(q, 0, n1) SWAP(q, 1, n2) q._MuBit__mapply(Matrix.CNOT(), 0) @@ -246,5 +358,6 @@ def test(q: QuBit) -> None: print(varName) if __name__=="__main__": - q = MuBit(3) - s = q[1].get_Mubit() \ No newline at end of file + q = MuBit(2) + + print(q[0]) \ No newline at end of file diff --git a/QElephant/__pycache__/Matrix.cpython-311.pyc b/QElephant/__pycache__/Matrix.cpython-311.pyc new file mode 100644 index 0000000..423f027 Binary files /dev/null and b/QElephant/__pycache__/Matrix.cpython-311.pyc differ diff --git a/QElephant/__pycache__/QuBit.cpython-311.pyc b/QElephant/__pycache__/QuBit.cpython-311.pyc new file mode 100644 index 0000000..f8ac02a Binary files /dev/null and b/QElephant/__pycache__/QuBit.cpython-311.pyc differ diff --git a/QElephant/__pycache__/__init__.cpython-311.pyc b/QElephant/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..b9a2237 Binary files /dev/null and b/QElephant/__pycache__/__init__.cpython-311.pyc differ