did lots of things...
This commit is contained in:
parent
afa22cb193
commit
cfcf40b186
6 changed files with 552 additions and 117 deletions
17
Gate_test.py
17
Gate_test.py
|
|
@ -1,4 +1,5 @@
|
||||||
from QElephant.QuBit import *
|
from QElephant.QuBit import *
|
||||||
|
import pytest
|
||||||
|
|
||||||
## MuBit
|
## MuBit
|
||||||
mq = MuBit(2)
|
mq = MuBit(2)
|
||||||
|
|
@ -10,6 +11,22 @@ H(q)
|
||||||
assert mq._MuBit__state == [1/math.sqrt(2), -1/math.sqrt(2), 0, 0]
|
assert mq._MuBit__state == [1/math.sqrt(2), -1/math.sqrt(2), 0, 0]
|
||||||
CX(mq, 0, 1)
|
CX(mq, 0, 1)
|
||||||
assert mq._MuBit__state == [1/math.sqrt(2), -1/math.sqrt(2), 0, 0]
|
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
|
## QuBit
|
||||||
q = QuBit()
|
q = QuBit()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from QElephant.Matrix import *
|
from QElephant.Matrix import *
|
||||||
|
import pytest
|
||||||
|
|
||||||
m = Matrix([[1, 2, 3], [4, 5, 6]])
|
m = Matrix([[1, 2, 3], [4, 5, 6]])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ from matplotlib.patches import Rectangle, Circle
|
||||||
from QElephant.QuBit import *
|
from QElephant.QuBit import *
|
||||||
|
|
||||||
class Circuit:
|
class Circuit:
|
||||||
def __init__(self, n: int, instructions=[]):
|
def __init__(self, n: int):
|
||||||
self.__instr = instructions
|
self.__instr = []
|
||||||
self.__n = n
|
self.__n = n
|
||||||
self.__mubit = MuBit(self.__n)
|
self.__mubit = MuBit(self.__n)
|
||||||
self.__mubit._MuBit__callBack = self.__recv
|
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))
|
||||||
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:
|
def draw(self) -> None:
|
||||||
|
"""draw and display a representation of the Circuit
|
||||||
|
"""
|
||||||
n = len(self.__instr)
|
n = len(self.__instr)
|
||||||
plt.yticks(range(self.__n), [f"QuBit {i}" for i in range(self.__n)])
|
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)])
|
plt.xticks(range(1, n+1), [f"Step {i+1}" for i in range(n)])
|
||||||
|
|
@ -44,24 +55,49 @@ class Circuit:
|
||||||
self.__line((i+1.25, q_i), (i+1.5, q_i))
|
self.__line((i+1.25, q_i), (i+1.5, q_i))
|
||||||
|
|
||||||
if q_i == index:
|
if q_i == index:
|
||||||
if txt == "X":
|
match txt:
|
||||||
|
case "X":
|
||||||
self.__circle(i+1, q_i, 0.25, False)
|
self.__circle(i+1, q_i, 0.25, False)
|
||||||
self.__line((i+0.75, q_i), (i+1.25, q_i))
|
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.__line((i+1, q_i-0.25), (i+1, q_i+0.25))
|
||||||
elif txt == "SWAP":
|
case "SWAP":
|
||||||
self.__line((i+0.75, q_i), (i+1.25, q_i))
|
self.__line((i+0.75, q_i), (i+1.25, q_i))
|
||||||
self.__cross(i+1, q_i)
|
self.__cross(i+1, q_i)
|
||||||
self.__cross(i+1, neigbhor[0])
|
self.__cross(i+1, neigbhor[0])
|
||||||
self.__line((i+1, q_i), (i+1, neigbhor[0]))
|
self.__line((i+1, q_i), (i+1, neigbhor[0]))
|
||||||
elif txt == "CX":
|
case "CX":
|
||||||
self.__circle(i+1, q_i, 0.25, False)
|
self.__circle(i+1, q_i, 0.25, False)
|
||||||
self.__line((i+0.75, q_i), (i+1.25, q_i))
|
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.__line((i+1, q_i-0.25), (i+1, q_i+0.25))
|
||||||
self.__circle(i+1, neigbhor[0], 0.05)
|
self.__circle(i+1, neigbhor[0], 0.05)
|
||||||
self.__line((i+1, q_i), (i+1, neigbhor[0]))
|
self.__line((i+1, q_i), (i+1, neigbhor[0]))
|
||||||
elif txt == "obs":
|
case "obs":
|
||||||
self.__circle(i+1, q_i, 0.25, False)
|
self.__circle(i+1, q_i, 0.25, False)
|
||||||
self.__circle(i+1, q_i, 0.05)
|
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:
|
else:
|
||||||
self.__rect(i+1, q_i, txt, n)
|
self.__rect(i+1, q_i, txt, n)
|
||||||
for neig in neigbhor:
|
for neig in neigbhor:
|
||||||
|
|
@ -72,6 +108,22 @@ class Circuit:
|
||||||
self.__line((i+1, q_i-0.25), (i+1, neig))
|
self.__line((i+1, q_i-0.25), (i+1, neig))
|
||||||
else:
|
else:
|
||||||
raise ValueError("Cannot apply gate twice on the same QuBit")
|
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:
|
else:
|
||||||
self.__line((i+0.75, q_i), (i+1.25, q_i))
|
self.__line((i+0.75, q_i), (i+1.25, q_i))
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -79,4 +131,5 @@ class Circuit:
|
||||||
|
|
||||||
if __name__=="__main__":
|
if __name__=="__main__":
|
||||||
c = Circuit(3, [("CS", 0, [1]), ("CX", 2, [0]), ("TX", 1, [0, 2])])
|
c = Circuit(3, [("CS", 0, [1]), ("CX", 2, [0]), ("TX", 1, [0, 2])])
|
||||||
|
print(c.get_size())
|
||||||
c.draw()
|
c.draw()
|
||||||
|
|
@ -44,6 +44,7 @@ class Matrix:
|
||||||
return str(self.__m)
|
return str(self.__m)
|
||||||
|
|
||||||
def to_list(self) -> list[list[complex]]:
|
def to_list(self) -> list[list[complex]]:
|
||||||
|
"""convert the Matrix into a list representation"""
|
||||||
return self._Matrix__m.copy()
|
return self._Matrix__m.copy()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ import matplotlib.pyplot as plt
|
||||||
|
|
||||||
from QElephant.Matrix import *
|
from QElephant.Matrix import *
|
||||||
|
|
||||||
I = complex(0, 1)
|
|
||||||
|
|
||||||
## Classes
|
## Classes
|
||||||
|
|
||||||
class MuBit:
|
class MuBit:
|
||||||
|
|
@ -13,7 +11,7 @@ class MuBit:
|
||||||
if type(n) is not int:
|
if type(n) is not int:
|
||||||
raise TypeError(f"number of state must be an intergers, not {type(n)}")
|
raise TypeError(f"number of state must be an intergers, not {type(n)}")
|
||||||
if not n >= 2:
|
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.__n = n
|
||||||
self.__state: list[complex] = [0]*(2**self.__n)
|
self.__state: list[complex] = [0]*(2**self.__n)
|
||||||
|
|
@ -24,9 +22,6 @@ class MuBit:
|
||||||
if self.__callBack is not None:
|
if self.__callBack is not None:
|
||||||
self.__callBack(gate, target, neighbor)
|
self.__callBack(gate, target, neighbor)
|
||||||
|
|
||||||
def get_size(self) -> int:
|
|
||||||
return self.__n
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
def next(N: str) -> str:
|
def next(N: str) -> str:
|
||||||
if N == "":
|
if N == "":
|
||||||
|
|
@ -52,6 +47,7 @@ class MuBit:
|
||||||
if not value in {0, 1}:
|
if not value in {0, 1}:
|
||||||
raise ValueError(f"QuBit state must be 0 or 1, not {value}")
|
raise ValueError(f"QuBit state must be 0 or 1, not {value}")
|
||||||
|
|
||||||
|
if self.__getProb(i) != value: # when prob==1 and we want prob==0. Value is in {0, 1}
|
||||||
l = []
|
l = []
|
||||||
a, d = 1-value, value
|
a, d = 1-value, value
|
||||||
for k in range(i, self.__n-1):
|
for k in range(i, self.__n-1):
|
||||||
|
|
@ -68,6 +64,8 @@ class MuBit:
|
||||||
|
|
||||||
norm = math.sqrt(sum([abs(x)**2 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]
|
self.__state = [x/norm for x in self.__state]
|
||||||
|
else:
|
||||||
|
self.__apply(Matrix.X(), i)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter([IQuBit(i, self) for i in range(self.__n)])
|
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]
|
self.__state[A:B], self.__state[B:C] = self.__state[B:C], self.__state[A:B]
|
||||||
K += lng
|
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:
|
def next(N: str) -> str:
|
||||||
if N == "":
|
if N == "":
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -177,11 +210,19 @@ class MuBit:
|
||||||
|
|
||||||
X = [n for n in range(2**self.__n)]
|
X = [n for n in range(2**self.__n)]
|
||||||
Y = [abs(self.__state[int(k)])**2 for k in X]
|
Y = [abs(self.__state[int(k)])**2 for k in X]
|
||||||
plt.hist(X, weights=Y, bins=2**self.__n-1)
|
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])
|
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()
|
plt.show()
|
||||||
|
|
||||||
def observe(self) -> list[int]:
|
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()
|
r = rd.random()
|
||||||
s = 0
|
s = 0
|
||||||
state = 0
|
state = 0
|
||||||
|
|
@ -200,17 +241,27 @@ class MuBit:
|
||||||
l.insert(0, state%2)
|
l.insert(0, state%2)
|
||||||
state -= state%2
|
state -= state%2
|
||||||
state //= 2
|
state //= 2
|
||||||
|
|
||||||
|
self.__emit("Mobserve", 0, range(self.get_size()))
|
||||||
return l
|
return l
|
||||||
|
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
|
"""reset the state to |0...0>
|
||||||
|
"""
|
||||||
self.__state = [0]*2**self.__n
|
self.__state = [0]*2**self.__n
|
||||||
self.__state[0] = 1
|
self.__state[0] = 1
|
||||||
|
self.__emit("M-|0>", 0, range(self.get_size()))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def intricateThem(*args: "QuBit") -> "MuBit":
|
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:
|
for q in args:
|
||||||
if type(q) is IQuBit:
|
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:
|
if type(q) is not QuBit:
|
||||||
raise TypeError(f"cannot intricate QuBit and {type(q)}")
|
raise TypeError(f"cannot intricate QuBit and {type(q)}")
|
||||||
if len(args) < 2:
|
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}")
|
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.__state = [alpha, beta]
|
||||||
self.__intricated = False
|
self.__entangled = False
|
||||||
|
|
||||||
def is_intricated(self) -> bool:
|
|
||||||
return self.__intricated
|
|
||||||
|
|
||||||
def get_Mubit(self) -> None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"{round(self.__state[0], 3)} |0> + {round(self.__state[1], 3)} |1>"
|
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)
|
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]:
|
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()
|
r = rd.random()
|
||||||
if r < abs(self.__state[0])**2:
|
if r < abs(self.__state[0])**2:
|
||||||
self.__state = [1, 0]
|
self.__state = [1, 0]
|
||||||
|
|
@ -260,6 +318,8 @@ class QuBit:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
|
"""reset the state to |0>
|
||||||
|
"""
|
||||||
self.__state = [1, 0]
|
self.__state = [1, 0]
|
||||||
|
|
||||||
class IQuBit(QuBit):
|
class IQuBit(QuBit):
|
||||||
|
|
@ -275,13 +335,7 @@ class IQuBit(QuBit):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.__n = n
|
self.__n = n
|
||||||
self.__muBit = mb
|
self.__muBit = mb
|
||||||
self.__intricated = True
|
self.__entangled = True
|
||||||
|
|
||||||
def is_intricated(self) -> bool:
|
|
||||||
return self.__intricated
|
|
||||||
|
|
||||||
def get_Mubit(self) -> tuple[MuBit, int]:
|
|
||||||
return (self.__muBit, self.__n)
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
p = self.__muBit._MuBit__getProb(self.__n)
|
p = self.__muBit._MuBit__getProb(self.__n)
|
||||||
|
|
@ -293,7 +347,28 @@ class IQuBit(QuBit):
|
||||||
|
|
||||||
self.__muBit._MuBit__apply(matrix, self.__n)
|
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:
|
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()
|
r = rd.random()
|
||||||
self.__muBit._MuBit__emit("obs", self.__n, [])
|
self.__muBit._MuBit__emit("obs", self.__n, [])
|
||||||
if r < self.__muBit._MuBit__getProb(self.__n):
|
if r < self.__muBit._MuBit__getProb(self.__n):
|
||||||
|
|
@ -303,6 +378,8 @@ class IQuBit(QuBit):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
|
"""reset the state to |0>
|
||||||
|
"""
|
||||||
self.__muBit._MuBit__set(self.__n, 0)
|
self.__muBit._MuBit__set(self.__n, 0)
|
||||||
self.__muBit._MuBit__emit("|0>", self.__n, [])
|
self.__muBit._MuBit__emit("|0>", self.__n, [])
|
||||||
|
|
||||||
|
|
@ -312,70 +389,139 @@ class IQuBit(QuBit):
|
||||||
|
|
||||||
## Fonctions
|
## 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:
|
if type(q) == IQuBit:
|
||||||
q._IQuBit__apply(Matrix.H())
|
q._IQuBit__apply(Matrix.H())
|
||||||
q._IQuBit__muBit._MuBit__emit("H", q._IQuBit__n, [])
|
q._IQuBit__muBit._MuBit__emit("H", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.H())
|
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:
|
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:
|
if type(q) == IQuBit:
|
||||||
q._IQuBit__apply(Matrix.X())
|
q._IQuBit__apply(Matrix.X())
|
||||||
q._IQuBit__muBit._MuBit__emit("X", q._IQuBit__n, [])
|
q._IQuBit__muBit._MuBit__emit("X", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.X())
|
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:
|
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:
|
if type(q) == IQuBit:
|
||||||
q._IQuBit__apply(Matrix.SQRTX())
|
q._IQuBit__apply(Matrix.SQRTX())
|
||||||
q._IQuBit__muBit._MuBit__emit("√¬", q._IQuBit__n, [])
|
q._IQuBit__muBit._MuBit__emit("√¬", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.SQRTX())
|
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:
|
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:
|
if type(q) == IQuBit:
|
||||||
q._IQuBit__apply(Matrix.Y())
|
q._IQuBit__apply(Matrix.Y())
|
||||||
q._IQuBit__muBit._MuBit__emit("Y", q._IQuBit__n, [])
|
q._IQuBit__muBit._MuBit__emit("Y", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.Y())
|
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:
|
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:
|
if type(q) == IQuBit:
|
||||||
q._IQuBit__apply(Matrix.Z())
|
q._IQuBit__apply(Matrix.Z())
|
||||||
q._IQuBit__muBit._MuBit__emit("Z", q._IQuBit__n, [])
|
q._IQuBit__muBit._MuBit__emit("Z", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.Z())
|
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:
|
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:
|
if type(q) == IQuBit:
|
||||||
q._IQuBit__apply(Matrix.S())
|
q._IQuBit__apply(Matrix.S())
|
||||||
q._IQuBit__muBit._MuBit__emit("S", q._IQuBit__n, [])
|
q._IQuBit__muBit._MuBit__emit("S", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.S())
|
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:
|
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:
|
if type(q) == IQuBit:
|
||||||
q._IQuBit__apply(Matrix.T())
|
q._IQuBit__apply(Matrix.T())
|
||||||
q._IQuBit__muBit._MuBit__emit("T", q._IQuBit__n, [])
|
q._IQuBit__muBit._MuBit__emit("T", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.T())
|
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:
|
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}:
|
if type(phi) not in {int, float}:
|
||||||
raise TypeError(f"an angle must be integer or float, not {type(phi)}")
|
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, [])
|
q._IQuBit__muBit._MuBit__emit("Rx", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.Rx(phi))
|
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:
|
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}:
|
if type(phi) not in {int, float}:
|
||||||
raise TypeError(f"an angle must be integer or float, not {type(phi)}")
|
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, [])
|
q._IQuBit__muBit._MuBit__emit("Ry", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.Ry(phi))
|
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:
|
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}:
|
if type(phi) not in {int, float}:
|
||||||
raise TypeError(f"an angle must be integer or float, not {type(phi)}")
|
raise TypeError(f"an angle must be integer or float, not {type(phi)}")
|
||||||
|
|
||||||
if type(q) == IQuBit:
|
if type(q) == IQuBit:
|
||||||
q._IQuBit__apply(Matrix.Rz(phi))
|
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:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.Rz(phi))
|
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:
|
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}:
|
if type(phi) not in {int, float}:
|
||||||
raise TypeError(f"an angle must be integer or float, not {type(phi)}")
|
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, [])
|
q._IQuBit__muBit._MuBit__emit("R1", q._IQuBit__n, [])
|
||||||
elif type(q) == QuBit:
|
elif type(q) == QuBit:
|
||||||
q._QuBit__apply(Matrix.R1(phi))
|
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:
|
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:
|
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:
|
if type(q) is not MuBit:
|
||||||
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
||||||
if type(n1) is not int:
|
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")
|
raise ValueError("the CNOT gate must be applied on two differents QuBits")
|
||||||
|
|
||||||
n = q._MuBit__n
|
n = q._MuBit__n
|
||||||
SWAP(q, n-2, n1, False)
|
q._MuBit__SWAP(n-2, n1)
|
||||||
SWAP(q, n-1, n2, False)
|
q._MuBit__SWAP(n-1, n2)
|
||||||
q._MuBit__mapply(Matrix.CX(), n-2)
|
q._MuBit__mapply(Matrix.CX(), n-2)
|
||||||
SWAP(q, n-2, n1, False)
|
q._MuBit__SWAP(n-2, n1)
|
||||||
SWAP(q, n-1, n2, False)
|
q._MuBit__SWAP(n-1, n2)
|
||||||
q._MuBit__emit("CX", n1, [n2])
|
q._MuBit__emit("CX", n1, [n2])
|
||||||
|
|
||||||
def CY(q: MuBit, n1: int, n2: int) -> None:
|
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:
|
if type(q) is not MuBit:
|
||||||
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
||||||
if type(n1) is not int:
|
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")
|
raise ValueError("the CNOT gate must be applied on two differents QuBits")
|
||||||
|
|
||||||
n = q._MuBit__n
|
n = q._MuBit__n
|
||||||
SWAP(q, n-2, n1, False)
|
q._MuBit__SWAP(n-2, n1)
|
||||||
SWAP(q, n-1, n2, False)
|
q._MuBit__SWAP(n-1, n2)
|
||||||
q._MuBit__mapply(Matrix.CY(), n-2)
|
q._MuBit__mapply(Matrix.CY(), n-2)
|
||||||
SWAP(q, n-2, n1, False)
|
q._MuBit__SWAP(n-2, n1)
|
||||||
SWAP(q, n-1, n2, False)
|
q._MuBit__SWAP(n-1, n2)
|
||||||
q._MuBit__emit("Y", n1, [n2])
|
q._MuBit__emit("Y", n1, [n2])
|
||||||
|
|
||||||
def CZ(q: MuBit, n1: int, n2: int) -> None:
|
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:
|
if type(q) is not MuBit:
|
||||||
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
||||||
if type(n1) is not int:
|
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")
|
raise ValueError("the CNOT gate must be applied on two differents QuBits")
|
||||||
|
|
||||||
n = q._MuBit__n
|
n = q._MuBit__n
|
||||||
SWAP(q, n-2, n1, False)
|
q._MuBit__SWAP(n-2, n1)
|
||||||
SWAP(q, n-1, n2, False)
|
q._MuBit__SWAP(n-1, n2)
|
||||||
q._MuBit__mapply(Matrix.CZ(), n-2)
|
q._MuBit__mapply(Matrix.CZ(), n-2)
|
||||||
SWAP(q, n-2, n1, False)
|
q._MuBit__SWAP(n-2, n1)
|
||||||
SWAP(q, n-1, n2, False)
|
q._MuBit__SWAP(n-1, n2)
|
||||||
q._MuBit__emit("Z", n1, [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:
|
if type(q) is not MuBit:
|
||||||
TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
||||||
if type(n1) is not int:
|
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):
|
for i in range(nmax-2, nmin-1, -1):
|
||||||
q._MuBit__SWITCH(i)
|
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:
|
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:
|
if type(q) is not MuBit:
|
||||||
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
raise TypeError(f"a MuBit was expected, but a {type(q)} was given")
|
||||||
if type(n1) is not int:
|
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")
|
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
|
n = q._MuBit__n
|
||||||
SWAP(q, n-2, n1, False)
|
q._MuBit__SWAP(n-2, n1)
|
||||||
SWAP(q, n-1, n2,False)
|
q._MuBit__SWAP(n-1, n2)
|
||||||
q._MuBit__mapply(Matrix.Cu(u), n-2)
|
q._MuBit__mapply(Matrix.Cu(u), n-2)
|
||||||
SWAP(q, n-2, n1, False)
|
q._MuBit__SWAP(n-2, n1)
|
||||||
SWAP(q, n-1, n2, False)
|
q._MuBit__SWAP(n-1, n2)
|
||||||
q._MuBit__emit("U", n1, [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()))
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
from QElephant.QuBit import *
|
from QElephant.QuBit import *
|
||||||
|
import pytest
|
||||||
|
|
||||||
q = QuBit(0, 1)
|
q = QuBit(0, 1)
|
||||||
|
|
||||||
assert q._QuBit__state == [0, 1]
|
assert q._QuBit__state == [0, 1]
|
||||||
assert q._QuBit__intricated == False
|
assert q._QuBit__entangled == False
|
||||||
assert q.is_intricated() == False
|
assert q.is_entangled() == False
|
||||||
assert q.get_Mubit() == None
|
|
||||||
assert str(q) == "0 |0> + 1 |1>"
|
assert str(q) == "0 |0> + 1 |1>"
|
||||||
q._QuBit__apply(Matrix([[1, 2], [3, 4]]))
|
q._QuBit__apply(Matrix([[1, 2], [3, 4]]))
|
||||||
assert q._QuBit__state == [2, 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]
|
q = mq[0]
|
||||||
assert q._IQuBit__n == 0
|
assert q._IQuBit__n == 0
|
||||||
assert q._IQuBit__muBit == mq
|
assert q._IQuBit__muBit == mq
|
||||||
assert q._IQuBit__intricated == True
|
assert q._IQuBit__entangled == True
|
||||||
assert q.is_intricated() == True
|
assert q.is_entangled() == True
|
||||||
assert q.get_Mubit() == (mq, 0)
|
assert q.get_Mubit() == (mq, 0)
|
||||||
assert str(q) == "0.707 |0> + 0.707 |1>"
|
assert str(q) == "0.707 |0> + 0.707 |1>"
|
||||||
q._IQuBit__apply(Matrix([[1, 1], [1, -1]]))
|
q._IQuBit__apply(Matrix([[1, 1], [1, -1]]))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue