did lots of things...

This commit is contained in:
Didictateur 2023-11-06 20:52:19 +01:00
parent afa22cb193
commit cfcf40b186
6 changed files with 552 additions and 117 deletions

View file

@ -1,4 +1,5 @@
from QElephant.QuBit import *
import pytest
## MuBit
mq = MuBit(2)
@ -10,6 +11,22 @@ H(q)
assert mq._MuBit__state == [1/math.sqrt(2), -1/math.sqrt(2), 0, 0]
CX(mq, 0, 1)
assert mq._MuBit__state == [1/math.sqrt(2), -1/math.sqrt(2), 0, 0]
Bell(mq, 0, 1, "phi+")
assert mq._MuBit__state == [1/math.sqrt(2), 0, 0, 1/math.sqrt(2)]
Bell(mq, 0, 1, "phi-")
assert mq._MuBit__state == [1/math.sqrt(2), 0, 0, -1/math.sqrt(2)]
Bell(mq, 0, 1, "psi+")
assert mq._MuBit__state == [0, 1/math.sqrt(2), 1/math.sqrt(2), 0]
Bell(mq, 0, 1, "psi-")
assert mq._MuBit__state == [0, 1/math.sqrt(2), -1/math.sqrt(2), 0]
mq = MuBit(3)
H(mq[1])
CZ(mq, 1, 2)
GHZ(mq)
assert mq._MuBit__state == [1/math.sqrt(2), 0, 0, 0, 0, 0, 0, 1/math.sqrt(2)]
W(mq)
assert mq._MuBit__state == [0, 1/math.sqrt(3), 1/math.sqrt(3), 0, 1/math.sqrt(3), 0, 0, 0]
## QuBit
q = QuBit()

View file

@ -1,4 +1,5 @@
from QElephant.Matrix import *
import pytest
m = Matrix([[1, 2, 3], [4, 5, 6]])

View file

@ -3,8 +3,8 @@ from matplotlib.patches import Rectangle, Circle
from QElephant.QuBit import *
class Circuit:
def __init__(self, n: int, instructions=[]):
self.__instr = instructions
def __init__(self, n: int):
self.__instr = []
self.__n = n
self.__mubit = MuBit(self.__n)
self.__mubit._MuBit__callBack = self.__recv
@ -31,7 +31,18 @@ class Circuit:
self.__line((x-0.25, y-0.25), (x+0.25, y+0.25))
self.__line((x-0.25, y+0.25), (x+0.25, y-0.25))
def get_MuBit(self) -> MuBit:
"""returns the MuBit of the Circuit
"""
return self.__mubit
def get_size(self) -> int:
"""returns the number of entangled QuBit in the Circuit"""
return self.__n
def draw(self) -> None:
"""draw and display a representation of the Circuit
"""
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)])
@ -44,34 +55,75 @@ class Circuit:
self.__line((i+1.25, q_i), (i+1.5, q_i))
if q_i == index:
if txt == "X":
self.__circle(i+1, q_i, 0.25, False)
self.__line((i+0.75, q_i), (i+1.25, q_i))
self.__line((i+1, q_i-0.25), (i+1, q_i+0.25))
elif txt == "SWAP":
self.__line((i+0.75, q_i), (i+1.25, q_i))
self.__cross(i+1, q_i)
self.__cross(i+1, neigbhor[0])
self.__line((i+1, q_i), (i+1, neigbhor[0]))
elif txt == "CX":
self.__circle(i+1, q_i, 0.25, False)
self.__line((i+0.75, q_i), (i+1.25, q_i))
self.__line((i+1, q_i-0.25), (i+1, q_i+0.25))
self.__circle(i+1, neigbhor[0], 0.05)
self.__line((i+1, q_i), (i+1, neigbhor[0]))
elif txt == "obs":
self.__circle(i+1, q_i, 0.25, False)
self.__circle(i+1, q_i, 0.05)
else:
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))
match txt:
case "X":
self.__circle(i+1, q_i, 0.25, False)
self.__line((i+0.75, q_i), (i+1.25, q_i))
self.__line((i+1, q_i-0.25), (i+1, q_i+0.25))
case "SWAP":
self.__line((i+0.75, q_i), (i+1.25, q_i))
self.__cross(i+1, q_i)
self.__cross(i+1, neigbhor[0])
self.__line((i+1, q_i), (i+1, neigbhor[0]))
case "CX":
self.__circle(i+1, q_i, 0.25, False)
self.__line((i+0.75, q_i), (i+1.25, q_i))
self.__line((i+1, q_i-0.25), (i+1, q_i+0.25))
self.__circle(i+1, neigbhor[0], 0.05)
self.__line((i+1, q_i), (i+1, neigbhor[0]))
case "obs":
self.__circle(i+1, q_i, 0.25, False)
self.__circle(i+1, q_i, 0.05)
case "Φ⁺" | "Φ⁻" | "Ψ⁺" | "Ψ⁻":
self.__rect(i+1, q_i, txt, n)
if neigbhor[0] > q_i:
self.__line((i+1, q_i+0.25), (i+1, neigbhor[0]-0.25))
elif neigbhor[0] < q_i:
self.__line((i+1, q_i-0.25), (i+1, neigbhor[0]+0.25))
else:
raise ValueError("Cannot apply gate twice on the same QuBit")
case "Mobserve":
self.__circle(i+1, q_i, 0.25, False)
self.__circle(i+1, q_i, 0.05)
for k in range(1, self.__n):
self.__line((i+1, k-0.75), (i+1, k-0.25))
case "MX":
self.__circle(i+1, q_i, 0.25, False)
self.__line((i+0.75, q_i), (i+1.25, q_i))
self.__line((i+1, q_i-0.25), (i+1, q_i+0.25))
for k in range(1, self.__n):
self.__line((i+1, k-1), (i+1, k))
case _:
if txt[:2] == "M-":
self.__rect(i+1, q_i, txt[2:], n)
for k in range(1, self.__n):
self.__line((i+1, k-0.75), (i+1, k-0.25))
else:
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")
elif q_i in neigbhor:
match txt:
case "Φ⁺" | "Φ⁻" | "Ψ⁺" | "Ψ⁻":
self.__rect(i+1, q_i, txt, n)
case "Mobserve":
self.__circle(i+1, q_i, 0.25, False)
self.__circle(i+1, q_i, 0.05)
case "MX":
self.__circle(i+1, q_i, 0.25, False)
self.__line((i+0.75, q_i), (i+1.25, q_i))
self.__line((i+1, q_i-0.25), (i+1, q_i+0.25))
case _:
if txt[:2] == "M-":
self.__rect(i+1, q_i, txt[2:], n)
else:
self.__line((i+0.75, q_i), (i+1.25, q_i))
else:
self.__line((i+0.75, q_i), (i+1.25, q_i))
i += 1
@ -79,4 +131,5 @@ class Circuit:
if __name__=="__main__":
c = Circuit(3, [("CS", 0, [1]), ("CX", 2, [0]), ("TX", 1, [0, 2])])
print(c.get_size())
c.draw()

View file

@ -44,6 +44,7 @@ class Matrix:
return str(self.__m)
def to_list(self) -> list[list[complex]]:
"""convert the Matrix into a list representation"""
return self._Matrix__m.copy()
@staticmethod

View file

@ -4,8 +4,6 @@ import matplotlib.pyplot as plt
from QElephant.Matrix import *
I = complex(0, 1)
## Classes
class MuBit:
@ -13,7 +11,7 @@ class MuBit:
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")
raise ValueError("a MuBit must have at least two entangled QuBit")
self.__n = n
self.__state: list[complex] = [0]*(2**self.__n)
@ -24,9 +22,6 @@ class MuBit:
if self.__callBack is not None:
self.__callBack(gate, target, neighbor)
def get_size(self) -> int:
return self.__n
def __str__(self) -> str:
def next(N: str) -> str:
if N == "":
@ -52,22 +47,25 @@ class MuBit:
if not value in {0, 1}:
raise ValueError(f"QuBit state must be 0 or 1, not {value}")
l = []
a, d = 1-value, value
for k in range(i, self.__n-1):
self.__SWITCH(k)
j = 0
while j < 2**self.__n:
x1, x2 = self.__state[j], self.__state[j+1]
l.append(a*x1)
l.append(d*x2)
j += 2
self.__state = l
for k in range(self.__n-2, i-1, -1):
self.__SWITCH(k)
if self.__getProb(i) != value: # when prob==1 and we want prob==0. Value is in {0, 1}
l = []
a, d = 1-value, value
for k in range(i, self.__n-1):
self.__SWITCH(k)
j = 0
while j < 2**self.__n:
x1, x2 = self.__state[j], self.__state[j+1]
l.append(a*x1)
l.append(d*x2)
j += 2
self.__state = l
for k in range(self.__n-2, i-1, -1):
self.__SWITCH(k)
norm = math.sqrt(sum([abs(x)**2 for x in self.__state]))
self.__state = [x/norm for x in self.__state]
norm = math.sqrt(sum([abs(x)**2 for x in self.__state]))
self.__state = [x/norm for x in self.__state]
else:
self.__apply(Matrix.X(), i)
def __iter__(self):
return iter([IQuBit(i, self) for i in range(self.__n)])
@ -160,7 +158,42 @@ class MuBit:
self.__state[A:B], self.__state[B:C] = self.__state[B:C], self.__state[A:B]
K += lng
def draw(self) -> None:
def __SWAP(self, n1: int, n2: int) -> None:
"""exchange the place between the two targeted QuBit
Args:
n1 (int): index of the first QuBit
n2 (int): index of the second QuBit
emit (bool):
"""
if type(n1) is not int:
TypeError(f"MuBit indices must be intergers, not {type(n1)}")
if type(n2) is not int:
TypeError(f"MuBit indices must be intergers, not {type(n2)}")
if n1 > self.__n or n2 > self.__n:
raise ValueError("Mubit index out of range")
n1 = n1%self.__n
n2 = n2%self.__n
if n1 != n2:
nmin = min(n1, n2)
nmax = max(n1, n2)
for i in range(nmin, nmax):
self.__SWITCH(i)
for i in range(nmax-2, nmin-1, -1):
self.__SWITCH(i)
def get_size(self) -> int:
"""returns the number of entangled QuBits
"""
return self.__n
def draw(self, show_state=False) -> None:
"""draw in a histogram the probability of each state in the order from |0...0> to |1...1>
Args:
show_state (bool, optional): if True, shows the name of each state in the histogram. Defaults to False.
"""
def next(N: str) -> str:
if N == "":
return ""
@ -177,11 +210,19 @@ class MuBit:
X = [n for n in range(2**self.__n)]
Y = [abs(self.__state[int(k)])**2 for k in X]
plt.hist(X, weights=Y, bins=2**self.__n-1)
plt.xticks([x+0.5 for x in X], [f"|{xlab}>" for xlab in xlabels])
plt.hist(X+[2**self.__n], weights=Y+[0], bins=2**self.__n)
if show_state:
plt.xticks([x+0.5 for x in X], [f"|{xlab}>" for xlab in xlabels])
else:
plt.xticks([0, 2**self.__n-1], ["", ""])
plt.show()
def observe(self) -> list[int]:
"""fixe all the QuBit in one state according their probabilities
Returns:
list[int]: the list of the fixed state of the QuBits
"""
r = rd.random()
s = 0
state = 0
@ -200,17 +241,27 @@ class MuBit:
l.insert(0, state%2)
state -= state%2
state //= 2
self.__emit("Mobserve", 0, range(self.get_size()))
return l
def reset(self) -> None:
"""reset the state to |0...0>
"""
self.__state = [0]*2**self.__n
self.__state[0] = 1
self.__emit("M-|0>", 0, range(self.get_size()))
@staticmethod
def intricateThem(*args: "QuBit") -> "MuBit":
"""creates a situation where all the given QuBit are now entangled
Returns:
MuBit: a copy of the given QuBits, but entangled
"""
for q in args:
if type(q) is IQuBit:
raise TypeError("cannot intricate QuBit that are already intricated")
raise TypeError("cannot intricate QuBit that are already entangled")
if type(q) is not QuBit:
raise TypeError(f"cannot intricate QuBit and {type(q)}")
if len(args) < 2:
@ -234,13 +285,7 @@ class QuBit:
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
def is_intricated(self) -> bool:
return self.__intricated
def get_Mubit(self) -> None:
return None
self.__entangled = False
def __str__(self) -> str:
return f"{round(self.__state[0], 3)} |0> + {round(self.__state[1], 3)} |1>"
@ -251,7 +296,20 @@ class QuBit:
self.__state = matrix._Matrix__apply(self.__state)
def is_entangled(self) -> bool:
"""tells if the corresponding QuBit is entangled
Returns:
bool: True if this is the case, or else False
"""
return self.__entangled
def observe(self) -> list[int]:
"""set the state to |0> or |1> according its probabilities
Returns:
int: the new state of the QuBit
"""
r = rd.random()
if r < abs(self.__state[0])**2:
self.__state = [1, 0]
@ -260,6 +318,8 @@ class QuBit:
return 1
def reset(self) -> None:
"""reset the state to |0>
"""
self.__state = [1, 0]
class IQuBit(QuBit):
@ -275,13 +335,7 @@ class IQuBit(QuBit):
super().__init__()
self.__n = n
self.__muBit = mb
self.__intricated = True
def is_intricated(self) -> bool:
return self.__intricated
def get_Mubit(self) -> tuple[MuBit, int]:
return (self.__muBit, self.__n)
self.__entangled = True
def __str__(self) -> str:
p = self.__muBit._MuBit__getProb(self.__n)
@ -293,7 +347,28 @@ class IQuBit(QuBit):
self.__muBit._MuBit__apply(matrix, self.__n)
def is_entangled(self) -> bool:
"""tells if the corresponding QuBit is entangled
Returns:
bool: True if this is the case, or else False
"""
return self.__entangled
def get_Mubit(self) -> tuple[MuBit, int]:
"""returns the MuBit in wich the MuBit is stocked
Returns:
tuple[MuBit, int]: the corresponding MuBit and its place among all the QuBits contained in the same MuBit
"""
return (self.__muBit, self.__n)
def observe(self) -> int:
"""set the state to |0> or |1> according its probabilities
Returns:
int: the new state of the QuBit
"""
r = rd.random()
self.__muBit._MuBit__emit("obs", self.__n, [])
if r < self.__muBit._MuBit__getProb(self.__n):
@ -303,6 +378,8 @@ class IQuBit(QuBit):
return 1
def reset(self) -> None:
"""reset the state to |0>
"""
self.__muBit._MuBit__set(self.__n, 0)
self.__muBit._MuBit__emit("|0>", self.__n, [])
@ -312,70 +389,139 @@ class IQuBit(QuBit):
## Fonctions
def H(q: QuBit) -> None:
def H(q: (QuBit | MuBit)) -> None:
"""apply the gate H to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
"""
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())
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.H())
q._MuBit__emit("M-H", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def X(q: QuBit) -> None:
def X(q: (QuBit | MuBit)) -> None:
"""apply the gate X to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
"""
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())
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.X())
q._MuBit__emit("MX", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def SQRTX(q: QuBit) -> None:
def SQRTX(q: (QuBit | MuBit)) -> None:
"""apply the gate corresponding of the square root of the X-gate to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
"""
if type(q) == IQuBit:
q._IQuBit__apply(Matrix.SQRTX())
q._IQuBit__muBit._MuBit__emit("√¬", q._IQuBit__n, [])
elif type(q) == QuBit:
q._QuBit__apply(Matrix.SQRTX())
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.SQRTX())
q._MuBit__emit("M-√¬", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def Y(q: QuBit) -> None:
def Y(q: (QuBit | MuBit)) -> None:
"""apply the gate Y to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
"""
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())
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.Y())
q._MuBit__emit("M-Y", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def Z(q: QuBit) -> None:
def Z(q: (QuBit | MuBit)) -> None:
"""apply the gate Z to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
"""
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())
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.Z())
q._MuBit__emit("M-Z", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def S(q: QuBit) -> None:
def S(q: (QuBit | MuBit)) -> None:
"""apply the gate S to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
"""
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())
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.S())
q._MuBit__emit("M-S", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def T(q: QuBit) -> None:
def T(q: (QuBit | MuBit)) -> None:
"""apply the gate T to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
"""
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())
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.T())
q._MuBit__emit("M-T", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def Rx(q: QuBit, phi: float) -> None:
def Rx(q: (QuBit | MuBit), phi: float) -> None:
"""apply a rotation around the x-axis to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
phi (float): the angle or the rotation
"""
if type(phi) not in {int, float}:
raise TypeError(f"an angle must be integer or float, not {type(phi)}")
@ -384,10 +530,20 @@ def Rx(q: QuBit, phi: float) -> None:
q._IQuBit__muBit._MuBit__emit("Rx", q._IQuBit__n, [])
elif type(q) == QuBit:
q._QuBit__apply(Matrix.Rx(phi))
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.Rx(phi))
q._MuBit__emit("M-Rx", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def Ry(q: QuBit, phi: float) -> None:
def Ry(q: (QuBit | MuBit), phi: float) -> None:
"""apply a rotation around the y-axis to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
phi (float): the angle or the rotation
"""
if type(phi) not in {int, float}:
raise TypeError(f"an angle must be integer or float, not {type(phi)}")
@ -396,22 +552,42 @@ def Ry(q: QuBit, phi: float) -> None:
q._IQuBit__muBit._MuBit__emit("Ry", q._IQuBit__n, [])
elif type(q) == QuBit:
q._QuBit__apply(Matrix.Ry(phi))
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.Ry(phi))
q._MuBit__emit("M-Ry", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def Rz(q: QuBit, phi: float) -> None:
def Rz(q: (QuBit | MuBit), phi: float) -> None:
"""apply a rotation around the z-axis to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
phi (float): the angle or the rotation
"""
if type(phi) not in {int, float}:
raise TypeError(f"an angle must be integer or float, not {type(phi)}")
if type(q) == IQuBit:
q._IQuBit__apply(Matrix.Rz(phi))
q._IQuBit__muBit._MuBit__emit("H", q._IQuBit__n, [])
q._IQuBit__muBit._MuBit__emit("Rz", q._IQuBit__n, [])
elif type(q) == QuBit:
q._QuBit__apply(Matrix.Rz(phi))
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.Rz(phi))
q._MuBit__emit("M-Rz", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def R1(q: QuBit, phi: float) -> None:
def R1(q: (QuBit | MuBit), phi: float) -> None:
"""apply the gate R1(phi) to the QuBit or all the QuBit of a MuBit
Args:
q (QuBit | MuBit): the target
phi (float): the angle or the rotation
"""
if type(phi) not in {int, float}:
raise TypeError(f"an angle must be integer or float, not {type(phi)}")
@ -420,10 +596,141 @@ def R1(q: QuBit, phi: float) -> None:
q._IQuBit__muBit._MuBit__emit("R1", q._IQuBit__n, [])
elif type(q) == QuBit:
q._QuBit__apply(Matrix.R1(phi))
elif type(q) == MuBit:
for i in range(q.get_size()):
q[i]._IQuBit__apply(Matrix.R1(phi))
q._MuBit__emit("M-R1", 0, range(q._MuBit__n))
else:
raise TypeError(f"a QuBit was expected, but a {type(q)} was given")
raise TypeError(f"a QuBit or a MuBit was expected, but a {type(q)} was given")
def Bell(q: MuBit, n1: int, n2: int, phase: str="phi+") -> None:
"""set the state of the two QuBits to:
- |00> + |11> if phase = 'phi+'
- |00> - |11> if phase = 'phi-'
- |01> + |10> if phase = 'psi+'
- |01> - |10> if phase = 'psi-'
Args:
q (MuBit): the MuBit containing the targeted QuBits
n1 (int): index of the first QuBit
n2 (int): index of the second QuBit
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
if type(n1) is not int:
raise TypeError(f"MuBit indices must be intergers, not {type(n1)}")
if type(n2) is not int:
raise TypeError(f"MuBit indices must be intergers, not {type(n2)}")
if n1 >= q._MuBit__n or n2 >= q._MuBit__n:
raise ValueError("Mubit index out of range")
if type(phase) is not str:
raise TypeError(f"expected a str for a phase, not {type(phase)}")
if phase not in {"phi+", "phi-", "psi+", "psi-"}:
raise ValueError("phase must be a value among 'phi+', 'phi-', 'psi+', 'psi-'")
n = q._MuBit__n
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
q._MuBit__set(n-2, 0)
q._MuBit__set(n-1, 0)
q._MuBit__apply(Matrix.H(), n-2)
q._MuBit__mapply(Matrix.CX(), n-2)
if phase[-1] == '-':
q._MuBit__apply(Matrix.Z(), n-1)
if phase[1] == "s":
q._MuBit__apply(Matrix.X(), n-1)
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
match phase:
case "phi+":
q._MuBit__emit("Φ⁺", n1, [n2])
case "phi-":
q._MuBit__emit("Φ⁻", n1, [n2])
case "psi+":
q._MuBit__emit("Ψ⁺", n1, [n2])
case "psi-":
q._MuBit__emit("Ψ⁻", n1, [n2])
def Dicke(q: MuBit, k: int) -> None:
"""set the state to |1,K>|0,n-k>
Args:
q (MuBit): the targeted QuBits
k (int): number of 1. If out of range, set k to 0 or n
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
if type(k) is not int:
raise TypeError(f"MuBit indices must be intergers, not {type(k)}")
k = min(k, q._MuBit__n)
k = max(0, k)
state = [0]*(q._MuBit__n-k) + [1]*k
i = 0
for j in range(len(state)):
i += state[j]*2**j
q._MuBit__state = [0]*2**q._MuBit__n
q._MuBit__state[i] = 1
q._MuBit__emit(f"M-|D({q._MuBit__n}, {k})>", 0, range(q._MuBit__n))
def Wigner(q: MuBit, a: complex) -> None:
"""set the state given a complexe formula
Args:
q (MuBit): the targeted QuBits
a (complex): complexe ratio of the serie
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
if type(a) not in {int, float, complex}:
raise TypeError(f"QuBit state must be int, float or complex, not {type(a)}")
state = [a**k/math.sqrt(math.factorial(k)) for k in range(2**q._MuBit__n)]
norm = sum(abs(x)**2 for x in state)
q._MuBit__state = [x/norm for x in state]
q._MuBit__emit("M-W(α)", 0, range(q._MuBit__n))
def Cat(q: MuBit, a: complex, parity: int=0) -> None:
"""set the state given a complexe formula
Args:
q (MuBit): the targeted QuBits
a (complex): complexe ratio of the serie
parity (int, optional): give the parity of the chossen terms. Defaults to 0.
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
if parity not in {0, 1}:
raise ValueError(f"parity must be 0 or 1, not {parity}")
if type(a) not in {int, float, complex}:
raise TypeError(f"QuBit state must be int, float or complex, not {type(a)}")
state = [((k+1+parity)%2)*a**k/math.sqrt(math.factorial(k)) for k in range(2**q._MuBit__n)]
norm = sum(abs(x)**2 for x in state)
q._MuBit__state = [x/norm for x in state]
if parity==0:
q._MuBit__emit("M-Catₑ(α)", 0, range(q._MuBit__n))
else:
q._MuBit__emit("M-Cat₀(α)", 0, range(q._MuBit__n))
# def
def CX(q: MuBit, n1: int, n2: int) -> None:
"""apply the controlled gate X to the two given QuBits
Args:
q (MuBit): the MuBit containing the targeted QuBits
n1 (int): index of the controller QuBit
n2 (int): index of the controlled QuBit
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
if type(n1) is not int:
@ -438,14 +745,21 @@ def CX(q: MuBit, n1: int, n2: int) -> None:
raise ValueError("the CNOT gate must be applied on two differents QuBits")
n = q._MuBit__n
SWAP(q, n-2, n1, False)
SWAP(q, n-1, n2, False)
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
q._MuBit__mapply(Matrix.CX(), n-2)
SWAP(q, n-2, n1, False)
SWAP(q, n-1, n2, False)
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
q._MuBit__emit("CX", n1, [n2])
def CY(q: MuBit, n1: int, n2: int) -> None:
"""apply the controlled gate Y to the two given QuBits
Args:
q (MuBit): the MuBit containing the targeted QuBits
n1 (int): index of the controller QuBit
n2 (int): index of the controlled QuBit
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
if type(n1) is not int:
@ -460,14 +774,21 @@ def CY(q: MuBit, n1: int, n2: int) -> None:
raise ValueError("the CNOT gate must be applied on two differents QuBits")
n = q._MuBit__n
SWAP(q, n-2, n1, False)
SWAP(q, n-1, n2, False)
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
q._MuBit__mapply(Matrix.CY(), n-2)
SWAP(q, n-2, n1, False)
SWAP(q, n-1, n2, False)
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
q._MuBit__emit("Y", n1, [n2])
def CZ(q: MuBit, n1: int, n2: int) -> None:
"""apply the controlled gate Z to the two given QuBits
Args:
q (MuBit): the MuBit containing the targeted QuBits
n1 (int): index of the controller QuBit
n2 (int): index of the controlled QuBit
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
if type(n1) is not int:
@ -482,14 +803,21 @@ def CZ(q: MuBit, n1: int, n2: int) -> None:
raise ValueError("the CNOT gate must be applied on two differents QuBits")
n = q._MuBit__n
SWAP(q, n-2, n1, False)
SWAP(q, n-1, n2, False)
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
q._MuBit__mapply(Matrix.CZ(), n-2)
SWAP(q, n-2, n1, False)
SWAP(q, n-1, n2, False)
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
q._MuBit__emit("Z", n1, [n2])
def SWAP(q: MuBit, n1: int, n2: int, emit: bool=True) -> None:
def SWAP(q: MuBit, n1: int, n2: int) -> None:
"""exchange the place between the two given QuBits
Args:
q (MuBit): the MuBit containing the targeted QuBits
n1 (int): index of the controller QuBit
n2 (int): index of the controlled QuBit
"""
if type(q) is not MuBit:
TypeError(f"a MuBit was expected, but a {type(q)} was given")
if type(n1) is not int:
@ -509,10 +837,17 @@ def SWAP(q: MuBit, n1: int, n2: int, emit: bool=True) -> None:
for i in range(nmax-2, nmin-1, -1):
q._MuBit__SWITCH(i)
if emit:
q._MuBit__emit("SWAP", n1, [n2])
q._MuBit__emit("SWAP", n1, [n2])
def Cu(q: MuBit, u: list[list[complex]], n1: int, n2: int) -> None:
"""apply the controlled gate u
Args:
q (MuBit): the MuBit containing the targeted QuBit
u (list[list[complex]]): matrix representation of the gate u
n1 (int): index of the controller QuBit
n2 (int): index of the controlled QuBit
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
if type(n1) is not int:
@ -540,9 +875,37 @@ def Cu(q: MuBit, u: list[list[complex]], n1: int, n2: int) -> None:
raise ValueError(f"the size of the matrix was expected to be (2, 2). A matrix of size ({len(u)}, {u[0]}) has been given")
n = q._MuBit__n
SWAP(q, n-2, n1, False)
SWAP(q, n-1, n2,False)
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
q._MuBit__mapply(Matrix.Cu(u), n-2)
SWAP(q, n-2, n1, False)
SWAP(q, n-1, n2, False)
q._MuBit__SWAP(n-2, n1)
q._MuBit__SWAP(n-1, n2)
q._MuBit__emit("U", n1, [n2])
def GHZ(q: MuBit):
"""set the state to |0...0> + |1...1>
Args:
q (MuBit): the targeted QuBit
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
q._MuBit__state = [1/math.sqrt(2)] + [0]*(2**q.get_size()-2) + [1/math.sqrt(2)]
q._MuBit__emit("M-GHZ", 0, range(q.get_size()))
def W(q: MuBit) -> None:
"""set the state to |10...0> + |010...0> +...+ |0...01>
Args:
q (MuBit): the targeted QuBit
"""
if type(q) is not MuBit:
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
q._MuBit__state = [0]*(2**q.get_size())
for k in range(q.get_size()):
q._MuBit__state[2**k] = 1/math.sqrt(q.get_size())
q._MuBit__emit("M-W", 0, range(q.get_size()))

View file

@ -1,11 +1,11 @@
from QElephant.QuBit import *
import pytest
q = QuBit(0, 1)
assert q._QuBit__state == [0, 1]
assert q._QuBit__intricated == False
assert q.is_intricated() == False
assert q.get_Mubit() == None
assert q._QuBit__entangled == False
assert q.is_entangled() == False
assert str(q) == "0 |0> + 1 |1>"
q._QuBit__apply(Matrix([[1, 2], [3, 4]]))
assert q._QuBit__state == [2, 4]
@ -25,8 +25,8 @@ assert mq._MuBit__state == [0, 1/math.sqrt(2), 0, 1/math.sqrt(2)]
q = mq[0]
assert q._IQuBit__n == 0
assert q._IQuBit__muBit == mq
assert q._IQuBit__intricated == True
assert q.is_intricated() == True
assert q._IQuBit__entangled == True
assert q.is_entangled() == True
assert q.get_Mubit() == (mq, 0)
assert str(q) == "0.707 |0> + 0.707 |1>"
q._IQuBit__apply(Matrix([[1, 1], [1, -1]]))