partial measurement
This commit is contained in:
parent
06ac6dc6e8
commit
66cbe6f971
94
lib.py
94
lib.py
@ -264,17 +264,28 @@ class State(Vector):
|
|||||||
"""If the inner (dot) product is zero, this vector is orthogonal to other"""
|
"""If the inner (dot) product is zero, this vector is orthogonal to other"""
|
||||||
return self.inner(other) == 0
|
return self.inner(other) == 0
|
||||||
|
|
||||||
def get_prob(self, j):
|
def get_prob_from_measurement_op(self, m_op):
|
||||||
"""pr(j) = |<e_j|self>|^2"""
|
assert type(m_op) is MeasurementOperator
|
||||||
# j_th basis vector
|
return m_op.get_prob(self)
|
||||||
e_j = State([[1] if i == int(j) else [0] for i in range(len(self.m))])
|
|
||||||
return np.absolute((e_j.inner(self)).m.item(0)) ** 2
|
def get_computational_basis_vector(self, j):
|
||||||
|
return Vector([[1] if i == int(j) else [0] for i in range(len(self.m))])
|
||||||
|
|
||||||
|
def get_prob(self, j, basis=None):
|
||||||
|
"""pr(j) = |<e_j|self>|^2
|
||||||
|
"""
|
||||||
|
if basis is None:
|
||||||
|
basis = self.get_computational_basis_vector(j)
|
||||||
|
m = MeasurementOperator.create_from_basis(basis)
|
||||||
|
return m.get_prob(self)
|
||||||
|
|
||||||
def get_fmt_of_element(self):
|
def get_fmt_of_element(self):
|
||||||
return "{:0" + str(int(np.ceil(np.log2(len(self))))) + "b}"
|
return "{:0" + str(int(np.ceil(np.log2(len(self))))) + "b}"
|
||||||
|
|
||||||
def measure(self):
|
def measure(self, basis=None):
|
||||||
"""
|
"""
|
||||||
|
m_ops: a set of MeasurementOperators.
|
||||||
|
e.g. for computational basis, the m_ops is [|0><0|, |1><1|]
|
||||||
Measures in the computational basis.
|
Measures in the computational basis.
|
||||||
Irreversable operation. Measuring again will result in the same result
|
Irreversable operation. Measuring again will result in the same result
|
||||||
TODO: Generalize the method so it takes a basis
|
TODO: Generalize the method so it takes a basis
|
||||||
@ -289,12 +300,26 @@ class State(Vector):
|
|||||||
"""
|
"""
|
||||||
if self.measurement_result:
|
if self.measurement_result:
|
||||||
return self.measurement_result
|
return self.measurement_result
|
||||||
weights = [self.get_prob(j) for j in range(len(self))]
|
weights = []
|
||||||
|
if not basis:
|
||||||
|
basis = []
|
||||||
|
for j in range(len(self)):
|
||||||
|
# Default is computational basis
|
||||||
|
e_j = self.get_computational_basis_vector(j)
|
||||||
|
m = MeasurementOperator.create_from_basis(e_j)
|
||||||
|
basis.append(m)
|
||||||
|
|
||||||
|
for i in range(len(basis)):
|
||||||
|
m_op = basis[i]
|
||||||
|
prob = self.get_prob_from_measurement_op(m_op)
|
||||||
|
weights += [prob]
|
||||||
|
|
||||||
empty_prob = 1.0 - sum(weights)
|
empty_prob = 1.0 - sum(weights)
|
||||||
format_str = self.get_fmt_of_element()
|
format_str = self.get_fmt_of_element()
|
||||||
choices = [REPR_EMPTY_SET] + [format_str.format(i) for i in range(len(weights))]
|
choices = [REPR_EMPTY_SET] + [format_str.format(i) for i in range(len(weights))]
|
||||||
weights = [empty_prob] + weights
|
weights = [empty_prob] + weights
|
||||||
self.measurement_result = random.choices(choices, weights)[0]
|
self.measurement_result = random.choices(choices, weights)[0]
|
||||||
|
|
||||||
return self.measurement_result
|
return self.measurement_result
|
||||||
|
|
||||||
def measure_with_op(self, mo):
|
def measure_with_op(self, mo):
|
||||||
@ -321,19 +346,16 @@ class State(Vector):
|
|||||||
# [0, 0, 1, 1, 0, 0, 1, 1]
|
# [0, 0, 1, 1, 0, 0, 1, 1]
|
||||||
partial_measurement_of_qbit = [int(b[qubit_n - 1]) for b in bin_repr]
|
partial_measurement_of_qbit = [int(b[qubit_n - 1]) for b in bin_repr]
|
||||||
# [0, 1, 4, 5]
|
# [0, 1, 4, 5]
|
||||||
indexes_for_p_0 = [i for i, index in enumerate(partial_measurement_of_qbit) if index == 0]
|
weights, choices = defaultdict(list), defaultdict(list)
|
||||||
weights_0 = [self.get_prob(j) for j in indexes_for_p_0]
|
for result in [1, 0]:
|
||||||
choices_0 = [format_str.format(i) for i in indexes_for_p_0]
|
indexes_for_p_0 = [i for i, index in enumerate(partial_measurement_of_qbit) if index == result]
|
||||||
measurement_result = random.choices(choices_0, weights_0)[0][qubit_n - 1]
|
weights[result] = [self.get_prob(j) for j in indexes_for_p_0]
|
||||||
# TODO: Verify if this is the correct collapse to lower dimension after partial measurement
|
choices[result] = [format_str.format(i) for i in indexes_for_p_0]
|
||||||
# https://www.youtube.com/watch?v=MG_9JWsrKtM&list=PL1826E60FD05B44E4&index=16
|
weights_01 = [sum(weights[0]), sum(weights[1])]
|
||||||
normalization_factor = np.sqrt(np.sum(np.abs([self.m[i][0] for i in indexes_for_p_0]) ** 2))
|
measurement_result = random.choices([0, 1], weights_01)[0]
|
||||||
# TODO: This can be 0...
|
normalization_factor = np.sqrt(sum([np.abs(i) ** 2 for i in weights[measurement_result]]))
|
||||||
post_measurement_state = [
|
new_m = weights[measurement_result] / normalization_factor
|
||||||
[self.m[i][0] / normalization_factor] for i in indexes_for_p_0
|
return str(measurement_result), State(new_m.reshape((len(new_m), 1)))
|
||||||
]
|
|
||||||
self.m = s('|' + measurement_result + '>') * State(post_measurement_state)
|
|
||||||
return measurement_result
|
|
||||||
|
|
||||||
def pretty_print(self):
|
def pretty_print(self):
|
||||||
format_str = self.get_fmt_of_element() + " | {}"
|
format_str = self.get_fmt_of_element() + " | {}"
|
||||||
@ -808,7 +830,7 @@ class MeasurementOperator(HermitianOperator):
|
|||||||
"""Measurement operators are Hermitians: <ψ|M†_m M_m|ψ>"""
|
"""Measurement operators are Hermitians: <ψ|M†_m M_m|ψ>"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_from_prob(cls, matrix: Matrix, *args, **kwargs):
|
def create_from_basis(cls, matrix: Matrix, *args, **kwargs):
|
||||||
"""returns |M†_m><M_m|"""
|
"""returns |M†_m><M_m|"""
|
||||||
return cls(matrix.conjugate_transpose().x(matrix).m, *args, **kwargs)
|
return cls(matrix.conjugate_transpose().x(matrix).m, *args, **kwargs)
|
||||||
|
|
||||||
@ -821,8 +843,8 @@ class MeasurementOperator(HermitianOperator):
|
|||||||
return state_ct.m.dot(self.m.dot(state.m)).item()
|
return state_ct.m.dot(self.m.dot(state.m)).item()
|
||||||
|
|
||||||
|
|
||||||
m0 = MeasurementOperator.create_from_prob(_0)
|
m0 = MeasurementOperator.create_from_basis(_0)
|
||||||
m1 = MeasurementOperator.create_from_prob(_1)
|
m1 = MeasurementOperator.create_from_basis(_1)
|
||||||
|
|
||||||
|
|
||||||
def test_measurement_ops():
|
def test_measurement_ops():
|
||||||
@ -930,6 +952,20 @@ def test():
|
|||||||
assert np.isclose(_p.get_prob(0), 0.5) # Probability for |+> in 0 is 0.5
|
assert np.isclose(_p.get_prob(0), 0.5) # Probability for |+> in 0 is 0.5
|
||||||
assert np.isclose(_p.get_prob(1), 0.5) # Probability for |+> in 1 is 0.5
|
assert np.isclose(_p.get_prob(1), 0.5) # Probability for |+> in 1 is 0.5
|
||||||
|
|
||||||
|
assert _0.measure() == '0'
|
||||||
|
assert _1.measure() == '1'
|
||||||
|
|
||||||
|
assert s("|10>").measure() == '10'
|
||||||
|
assert s("|10>").measure_partial(1) == ("1", _0)
|
||||||
|
assert s("|10>").measure_partial(2) == ("0", _1)
|
||||||
|
|
||||||
|
# Maximally entangled
|
||||||
|
result, pms = b_phi_p.measure_partial(1)
|
||||||
|
if result == "0":
|
||||||
|
assert pms == _0
|
||||||
|
elif result == "1":
|
||||||
|
assert pms == _1
|
||||||
|
|
||||||
# Test measurement operators
|
# Test measurement operators
|
||||||
test_measurement_ops()
|
test_measurement_ops()
|
||||||
|
|
||||||
@ -1223,9 +1259,9 @@ def test_quantum_processor():
|
|||||||
|
|
||||||
def test_light():
|
def test_light():
|
||||||
# http://alienryderflex.com/polarizer/
|
# http://alienryderflex.com/polarizer/
|
||||||
hor_filter = MeasurementOperator.create_from_prob(Matrix(_0.m), name='h')
|
hor_filter = MeasurementOperator.create_from_basis(Matrix(_0.m), name='h')
|
||||||
diag_filter = MeasurementOperator.create_from_prob(Matrix(_p.m), name='d')
|
diag_filter = MeasurementOperator.create_from_basis(Matrix(_p.m), name='d')
|
||||||
ver_filter = MeasurementOperator.create_from_prob(Matrix(_1.m), name='v')
|
ver_filter = MeasurementOperator.create_from_basis(Matrix(_1.m), name='v')
|
||||||
|
|
||||||
def random_light():
|
def random_light():
|
||||||
random_pol = Vector([[np.random.uniform(0, 1)], [np.random.uniform(0, 1)]])
|
random_pol = Vector([[np.random.uniform(0, 1)], [np.random.uniform(0, 1)]])
|
||||||
@ -1261,12 +1297,12 @@ def test_light():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test()
|
test()
|
||||||
test_quantum_processor()
|
# test_quantum_processor()
|
||||||
test_light()
|
# test_light()
|
||||||
|
|
||||||
# Partial measurement - I want to measure just the first qubit...
|
# Partial measurement - I want to measure just the first qubit...
|
||||||
# TODO - makes sense???
|
# TODO - makes sense???
|
||||||
# m0_ = m0 * I
|
# m0_ = m0 * I
|
||||||
# post_measurement = b_phi_m.measure_with_op(m0_)
|
# s("|10>").measure_partial(1)
|
||||||
# result_0 = post_measurement.measure()
|
# result_0 = post_measurement.measure()
|
||||||
# test_measure_partial()
|
# test_measure_partial()
|
||||||
|
Loading…
Reference in New Issue
Block a user