From 990942c586ffa74a9a2001b8e282278eff069974 Mon Sep 17 00:00:00 2001 From: madcpf Date: Sun, 29 Oct 2023 20:44:26 -0700 Subject: [PATCH 1/7] add two functions --- unitary/alpha/quantum_world.py | 126 ++++++++++++++++++++++++++++ unitary/alpha/quantum_world_test.py | 61 +++++++++----- 2 files changed, 166 insertions(+), 21 deletions(-) diff --git a/unitary/alpha/quantum_world.py b/unitary/alpha/quantum_world.py index d1b34c70..9fb22cee 100644 --- a/unitary/alpha/quantum_world.py +++ b/unitary/alpha/quantum_world.py @@ -19,6 +19,8 @@ from unitary.alpha.quantum_object import QuantumObject from unitary.alpha.sparse_vector_simulator import PostSelectOperation, SparseSimulator from unitary.alpha.qudit_state_transform import qudit_to_qubit_unitary, num_bits +import numpy as np +import itertools class QuantumWorld: @@ -484,6 +486,35 @@ def get_histogram( histogram[idx][cast(int, result[idx])] += 1 return histogram + def get_histogram_with_all_objects_as_key( + self, objects: Optional[Sequence[QuantumObject]] = None, count: int = 100 + ) -> Dict[Tuple[int], int]: + """Creates histogram of the whole quantum world (or `objects` if specified) + based on measurements (peeks) carried out. Comparing to get_histogram(), + this statistics contains entanglement information accross quantum objects. + + Parameters: + objects: List of QuantumObjects + count: Number of measurements + + Returns: + A dictionary, with the keys being each possible state of the whole quantum + world (or `objects` if specified) in terms of tuple, and the values being + the count of that state. + """ + if not objects: + objects = self.public_objects + peek_results = self.peek(objects=objects, convert_to_enum=False, count=count) + histogram = {} + for result in peek_results: + # Convert the list to tuple so that it could be the key of a dictionary. + key = tuple(result) + if key not in histogram: + histogram[key] = 1 + else: + histogram[key] += 1 + return histogram + def get_probabilities( self, objects: Optional[Sequence[QuantumObject]] = None, count: int = 100 ) -> List[Dict[int, float]]: @@ -526,6 +557,101 @@ def get_binary_probabilities( binary_probs.append(1 - one_probs[0]) return binary_probs + # TODO(pengfeichen): make this function work for compile_to_qubits==True. + def get_binary_probabilities_from_state_vector( + self, objects: Optional[Sequence[QuantumObject]] = None, decimals: int = 2 + ) -> List[float]: + """Calculates the total probabilities for all non-zero states + based on simulating the state vector. + + Parameters: + objects: List of QuantumObjects + decimals: Number of rounding decimals of the real and imaginary coefficients + of the state vector. + + Returns: + A list with one element for each object which contains the probability + for the event state!=0. Which is the same as 1.0-Probability(state==0). + """ + if objects is None: + objects = self.public_objects + + simulator = cirq.Simulator() + result = simulator.simulate(self.circuit, initial_state=0) + state_vector = result.state_vector() + # qubit_map gives the mapping from object to its index in (the dirac notation of) + # the state vector. + qubit_map = result.qubit_map + # We support quantum objects in different dimensions. + qid_shape = tuple([obj.dimension for obj in qubit_map.keys()]) + # Calculate all permutations, as the basis of the state vector. + perm_list = [ + "".join(seq) + for seq in itertools.product( + *((str(i) for i in range(d)) for d in qid_shape) + ) + ] + # Round each real/imaginary coefficient up to `decimals`, before judging if it's zero. + coefficients = [ + round(x.real, decimals) + 1j * round(x.imag, decimals) for x in state_vector + ] + # Build map from all post selected objects' corresponding index in the + # permutations to its post selected value. + post_selection_filter = {} + for post_selection_obj, post_selection_value in self.post_selection.items(): + for obj, index in qubit_map.items(): + if obj.name == post_selection_obj.name: + post_selection_filter[index] = post_selection_value + break + if len(post_selection_filter) != len(self.post_selection): + raise ValueError("Missing post selection qubits!") + + # Apply the post selection to trim the state vector. + filtered_indices = [] + for index in np.nonzero(coefficients)[0]: + perm = perm_list[index] + satisfied = True + # Check that all post selection criteria are satisfied. + for filter_index, value in post_selection_filter.items(): + if int(perm[filter_index]) != value: + satisfied = False + break + if satisfied: + filtered_indices.append(index) + + # We need to renormalize the state vector since it's been trimed. + prob_sum = 0 + for index in filtered_indices: + prob_sum += abs(coefficients[index]) ** 2 + + # Calculate the probability of each world scenario. + final_world_distribution = {} + for index in filtered_indices: + # Convert the permutation string into tuple of int, + # i.e. "101" into (1, 0, 1). + key = tuple(map(int, tuple(perm_list[index]))) + final_world_distribution[key] = abs(coefficients[index]) ** 2 / prob_sum + # TODO(pengfeichen): make the above calculation a seperate function, which calculates + # the distribution of the whole world (or specified objects) by state vector. + + # Calculate the distribution of all objects. + final_object_distribution = {} + for obj, index in qubit_map.items(): + final_object_distribution[obj.name] = 0 + for key, value in final_world_distribution.items(): + # We sum up all non-zero probabilities. + if key[index] > 0: + final_object_distribution[obj.name] += value + + # Shrink the dictionary above to a list of probabilities of the + # desired/specified objects. + binary_probs = [] + for obj in objects: + if obj.name not in final_object_distribution: + raise ValueError(f"{obj.name} not found.") + binary_probs.append(final_object_distribution[obj.name]) + return binary_probs + def __getitem__(self, name: str) -> QuantumObject: quantum_object = self.object_name_dict.get(name, None) if not quantum_object: diff --git a/unitary/alpha/quantum_world_test.py b/unitary/alpha/quantum_world_test.py index 75dc9b56..bb8c2022 100644 --- a/unitary/alpha/quantum_world_test.py +++ b/unitary/alpha/quantum_world_test.py @@ -176,7 +176,7 @@ def test_pop(simulator, compile_to_qubits): compile_to_qubits=compile_to_qubits, ) alpha.Split()(light, light2, light3) - results = board.peek([light2, light3], count=200, convert_to_enum=False) + results = board.peek([light2, light3], count=200) assert all(result[0] != result[1] for result in results) assert not all(result[0] == 0 for result in results) assert not all(result[0] == 1 for result in results) @@ -189,26 +189,6 @@ def test_pop(simulator, compile_to_qubits): assert all(result[1] != popped for result in results) -@pytest.mark.parametrize("compile_to_qubits", [False, True]) -@pytest.mark.parametrize("simulator", [cirq.Simulator, alpha.SparseSimulator]) -def test_unhook(simulator, compile_to_qubits): - light = alpha.QuantumObject("l1", Light.GREEN) - light2 = alpha.QuantumObject("l2", Light.RED) - light3 = alpha.QuantumObject("l3", Light.RED) - board = alpha.QuantumWorld( - [light, light2, light3], - sampler=simulator(), - compile_to_qubits=compile_to_qubits, - ) - alpha.Split()(light, light2, light3) - board.unhook(light2) - results = board.peek([light2, light3], count=200, convert_to_enum=False) - print(results) - assert all(result[0] == 0 for result in results) - assert not all(result[1] == 0 for result in results) - assert not all(result[1] == 1 for result in results) - - # TODO: Consider moving to qudit_effects.py if this can be broadly useful. class QuditSwapEffect(alpha.QuantumEffect): def __init__(self, dimension): @@ -656,23 +636,35 @@ def test_get_histogram_and_get_probabilities_one_binary_qobject( ) histogram = world.get_histogram() assert histogram == [{0: 0, 1: 100}] + histogram = world.get_histogram_with_all_objects_as_key() + assert histogram == {(1,): 100} probs = world.get_probabilities() assert probs == [{0: 0.0, 1: 1.0}] bin_probs = world.get_binary_probabilities() assert bin_probs == [1.0] + bin_probs = world.get_binary_probabilities_from_state_vector() + assert bin_probs == [1.0] alpha.Flip()(l1) histogram = world.get_histogram() assert histogram == [{0: 100, 1: 0}] + histogram = world.get_histogram_with_all_objects_as_key() + assert histogram == {(0,): 100} probs = world.get_probabilities() assert probs == [{0: 1.0, 1: 0.0}] bin_probs = world.get_binary_probabilities() assert bin_probs == [0.0] + bin_probs = world.get_binary_probabilities_from_state_vector() + assert bin_probs == [0.0] alpha.Superposition()(l1) histogram = world.get_histogram() assert len(histogram) == 1 assert len(histogram[0]) == 2 assert histogram[0][0] > 10 assert histogram[0][1] > 10 + histogram = world.get_histogram_with_all_objects_as_key() + assert len(histogram) == 2 + assert histogram[(0,)] > 10 + assert histogram[(1,)] > 10 probs = world.get_probabilities() assert len(probs) == 1 assert len(probs[0]) == 2 @@ -680,6 +672,8 @@ def test_get_histogram_and_get_probabilities_one_binary_qobject( assert probs[0][1] > 0.1 bin_probs = world.get_binary_probabilities() assert 0.1 <= bin_probs[0] <= 1.0 + bin_probs = world.get_binary_probabilities_from_state_vector() + assert 0.1 <= bin_probs[0] <= 1.0 @pytest.mark.parametrize( @@ -700,12 +694,21 @@ def test_get_histogram_and_get_probabilities_one_trinary_qobject( ) histogram = world.get_histogram() assert histogram == [{0: 0, 1: 100, 2: 0}] + histogram = world.get_histogram_with_all_objects_as_key() + assert histogram == {(1,): 100} probs = world.get_probabilities() assert probs == [{0: 0.0, 1: 1.0, 2: 0.0}] bin_probs = world.get_binary_probabilities() assert bin_probs == [1.0] +def test_get_binary_probabilities_from_state_vector_one_trinary_qobject(): + l1 = alpha.QuantumObject("l1", StopLight.YELLOW) + world = alpha.QuantumWorld([l1], sampler=cirq.Simulator(), compile_to_qubits=False) + bin_probs = world.get_binary_probabilities_from_state_vector() + assert bin_probs == [1.0] + + @pytest.mark.parametrize( ("simulator", "compile_to_qubits"), [ @@ -723,13 +726,29 @@ def test_get_histogram_and_get_probabilities_two_qobjects(simulator, compile_to_ ) histogram = world.get_histogram() assert histogram == [{0: 0, 1: 100}, {0: 0, 1: 100, 2: 0}] + histogram = world.get_histogram_with_all_objects_as_key() + assert histogram == {(1, 1): 100} probs = world.get_probabilities() assert probs == [{0: 0.0, 1: 1.0}, {0: 0.0, 1: 1.0, 2: 0.0}] bin_probs = world.get_binary_probabilities() assert bin_probs == [1.0, 1.0] histogram = world.get_histogram(objects=[l2], count=1000) assert histogram == [{0: 0, 1: 1000, 2: 0}] + histogram = world.get_histogram_with_all_objects_as_key(objects=[l2], count=1000) + assert histogram == {(1,): 1000} probs = world.get_probabilities(objects=[l2], count=1000) assert probs == [{0: 0.0, 1: 1.0, 2: 0.0}] bin_probs = world.get_binary_probabilities(objects=[l2], count=1000) assert bin_probs == [1.0] + + +def test_get_binary_probabilities_from_state_vector_two_qobjects(): + l1 = alpha.QuantumObject("l1", Light.GREEN) + l2 = alpha.QuantumObject("l2", StopLight.GREEN) + world = alpha.QuantumWorld( + [l1, l2], sampler=cirq.Simulator(), compile_to_qubits=False + ) + bin_probs = world.get_binary_probabilities_from_state_vector() + assert bin_probs == [1.0, 1.0] + bin_probs = world.get_binary_probabilities_from_state_vector(objects=[l2]) + assert bin_probs == [1.0] From 07f384213bcceb16e637c9efc2863faba8e485c5 Mon Sep 17 00:00:00 2001 From: madcpf Date: Sun, 29 Oct 2023 20:47:49 -0700 Subject: [PATCH 2/7] up --- unitary/alpha/quantum_world_test.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/unitary/alpha/quantum_world_test.py b/unitary/alpha/quantum_world_test.py index bb8c2022..0d230c7b 100644 --- a/unitary/alpha/quantum_world_test.py +++ b/unitary/alpha/quantum_world_test.py @@ -176,7 +176,7 @@ def test_pop(simulator, compile_to_qubits): compile_to_qubits=compile_to_qubits, ) alpha.Split()(light, light2, light3) - results = board.peek([light2, light3], count=200) + results = board.peek([light2, light3], count=200, convert_to_enum=False) assert all(result[0] != result[1] for result in results) assert not all(result[0] == 0 for result in results) assert not all(result[0] == 1 for result in results) @@ -189,6 +189,26 @@ def test_pop(simulator, compile_to_qubits): assert all(result[1] != popped for result in results) +@pytest.mark.parametrize("compile_to_qubits", [False, True]) +@pytest.mark.parametrize("simulator", [cirq.Simulator, alpha.SparseSimulator]) +def test_unhook(simulator, compile_to_qubits): + light = alpha.QuantumObject("l1", Light.GREEN) + light2 = alpha.QuantumObject("l2", Light.RED) + light3 = alpha.QuantumObject("l3", Light.RED) + board = alpha.QuantumWorld( + [light, light2, light3], + sampler=simulator(), + compile_to_qubits=compile_to_qubits, + ) + alpha.Split()(light, light2, light3) + board.unhook(light2) + results = board.peek([light2, light3], count=200, convert_to_enum=False) + print(results) + assert all(result[0] == 0 for result in results) + assert not all(result[1] == 0 for result in results) + assert not all(result[1] == 1 for result in results) + + # TODO: Consider moving to qudit_effects.py if this can be broadly useful. class QuditSwapEffect(alpha.QuantumEffect): def __init__(self, dimension): From 211101b1220b1a89c63d470df48f7f5071aff428 Mon Sep 17 00:00:00 2001 From: madcpf Date: Sun, 29 Oct 2023 21:02:58 -0700 Subject: [PATCH 3/7] up --- unitary/alpha/quantum_world.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/unitary/alpha/quantum_world.py b/unitary/alpha/quantum_world.py index 9fb22cee..23aeb9b0 100644 --- a/unitary/alpha/quantum_world.py +++ b/unitary/alpha/quantum_world.py @@ -571,7 +571,7 @@ def get_binary_probabilities_from_state_vector( Returns: A list with one element for each object which contains the probability - for the event state!=0. Which is the same as 1.0-Probability(state==0). + for the event state!=0, which is the same as 1.0-Probability(state==0). """ if objects is None: objects = self.public_objects @@ -630,7 +630,9 @@ def get_binary_probabilities_from_state_vector( # Convert the permutation string into tuple of int, # i.e. "101" into (1, 0, 1). key = tuple(map(int, tuple(perm_list[index]))) + # Renormalize. final_world_distribution[key] = abs(coefficients[index]) ** 2 / prob_sum + # TODO(pengfeichen): make the above calculation a seperate function, which calculates # the distribution of the whole world (or specified objects) by state vector. From dfd50cd8cd9c68077eb41f8940a2442b74a9c284 Mon Sep 17 00:00:00 2001 From: madcpf Date: Thu, 9 Nov 2023 20:03:12 -0800 Subject: [PATCH 4/7] update --- unitary/alpha/quantum_world.py | 7 +++---- unitary/alpha/quantum_world_test.py | 12 ++++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/unitary/alpha/quantum_world.py b/unitary/alpha/quantum_world.py index 23aeb9b0..340d7c7f 100644 --- a/unitary/alpha/quantum_world.py +++ b/unitary/alpha/quantum_world.py @@ -486,7 +486,7 @@ def get_histogram( histogram[idx][cast(int, result[idx])] += 1 return histogram - def get_histogram_with_all_objects_as_key( + def get_correlated_histogram( self, objects: Optional[Sequence[QuantumObject]] = None, count: int = 100 ) -> Dict[Tuple[int], int]: """Creates histogram of the whole quantum world (or `objects` if specified) @@ -576,8 +576,7 @@ def get_binary_probabilities_from_state_vector( if objects is None: objects = self.public_objects - simulator = cirq.Simulator() - result = simulator.simulate(self.circuit, initial_state=0) + result = cirq.Simulator().simulate(self.circuit, initial_state=0) state_vector = result.state_vector() # qubit_map gives the mapping from object to its index in (the dirac notation of) # the state vector. @@ -633,7 +632,7 @@ def get_binary_probabilities_from_state_vector( # Renormalize. final_world_distribution[key] = abs(coefficients[index]) ** 2 / prob_sum - # TODO(pengfeichen): make the above calculation a seperate function, which calculates + # TODO(pengfeichen): make the above calculation a separate function, which calculates # the distribution of the whole world (or specified objects) by state vector. # Calculate the distribution of all objects. diff --git a/unitary/alpha/quantum_world_test.py b/unitary/alpha/quantum_world_test.py index 0d230c7b..0d21719a 100644 --- a/unitary/alpha/quantum_world_test.py +++ b/unitary/alpha/quantum_world_test.py @@ -656,7 +656,7 @@ def test_get_histogram_and_get_probabilities_one_binary_qobject( ) histogram = world.get_histogram() assert histogram == [{0: 0, 1: 100}] - histogram = world.get_histogram_with_all_objects_as_key() + histogram = world.get_correlated_histogram() assert histogram == {(1,): 100} probs = world.get_probabilities() assert probs == [{0: 0.0, 1: 1.0}] @@ -667,7 +667,7 @@ def test_get_histogram_and_get_probabilities_one_binary_qobject( alpha.Flip()(l1) histogram = world.get_histogram() assert histogram == [{0: 100, 1: 0}] - histogram = world.get_histogram_with_all_objects_as_key() + histogram = world.get_correlated_histogram() assert histogram == {(0,): 100} probs = world.get_probabilities() assert probs == [{0: 1.0, 1: 0.0}] @@ -681,7 +681,7 @@ def test_get_histogram_and_get_probabilities_one_binary_qobject( assert len(histogram[0]) == 2 assert histogram[0][0] > 10 assert histogram[0][1] > 10 - histogram = world.get_histogram_with_all_objects_as_key() + histogram = world.get_correlated_histogram() assert len(histogram) == 2 assert histogram[(0,)] > 10 assert histogram[(1,)] > 10 @@ -714,7 +714,7 @@ def test_get_histogram_and_get_probabilities_one_trinary_qobject( ) histogram = world.get_histogram() assert histogram == [{0: 0, 1: 100, 2: 0}] - histogram = world.get_histogram_with_all_objects_as_key() + histogram = world.get_correlated_histogram() assert histogram == {(1,): 100} probs = world.get_probabilities() assert probs == [{0: 0.0, 1: 1.0, 2: 0.0}] @@ -746,7 +746,7 @@ def test_get_histogram_and_get_probabilities_two_qobjects(simulator, compile_to_ ) histogram = world.get_histogram() assert histogram == [{0: 0, 1: 100}, {0: 0, 1: 100, 2: 0}] - histogram = world.get_histogram_with_all_objects_as_key() + histogram = world.get_correlated_histogram() assert histogram == {(1, 1): 100} probs = world.get_probabilities() assert probs == [{0: 0.0, 1: 1.0}, {0: 0.0, 1: 1.0, 2: 0.0}] @@ -754,7 +754,7 @@ def test_get_histogram_and_get_probabilities_two_qobjects(simulator, compile_to_ assert bin_probs == [1.0, 1.0] histogram = world.get_histogram(objects=[l2], count=1000) assert histogram == [{0: 0, 1: 1000, 2: 0}] - histogram = world.get_histogram_with_all_objects_as_key(objects=[l2], count=1000) + histogram = world.get_correlated_histogram(objects=[l2], count=1000) assert histogram == {(1,): 1000} probs = world.get_probabilities(objects=[l2], count=1000) assert probs == [{0: 0.0, 1: 1.0, 2: 0.0}] From ea3805c8023a696acd6c443ac08892afe57d85e7 Mon Sep 17 00:00:00 2001 From: Pengfei Chen Date: Tue, 14 Nov 2023 10:31:39 -0800 Subject: [PATCH 5/7] update --- unitary/alpha/quantum_world.py | 96 ----------------------------- unitary/alpha/quantum_world_test.py | 25 -------- 2 files changed, 121 deletions(-) diff --git a/unitary/alpha/quantum_world.py b/unitary/alpha/quantum_world.py index 340d7c7f..29639348 100644 --- a/unitary/alpha/quantum_world.py +++ b/unitary/alpha/quantum_world.py @@ -557,102 +557,6 @@ def get_binary_probabilities( binary_probs.append(1 - one_probs[0]) return binary_probs - # TODO(pengfeichen): make this function work for compile_to_qubits==True. - def get_binary_probabilities_from_state_vector( - self, objects: Optional[Sequence[QuantumObject]] = None, decimals: int = 2 - ) -> List[float]: - """Calculates the total probabilities for all non-zero states - based on simulating the state vector. - - Parameters: - objects: List of QuantumObjects - decimals: Number of rounding decimals of the real and imaginary coefficients - of the state vector. - - Returns: - A list with one element for each object which contains the probability - for the event state!=0, which is the same as 1.0-Probability(state==0). - """ - if objects is None: - objects = self.public_objects - - result = cirq.Simulator().simulate(self.circuit, initial_state=0) - state_vector = result.state_vector() - # qubit_map gives the mapping from object to its index in (the dirac notation of) - # the state vector. - qubit_map = result.qubit_map - # We support quantum objects in different dimensions. - qid_shape = tuple([obj.dimension for obj in qubit_map.keys()]) - # Calculate all permutations, as the basis of the state vector. - perm_list = [ - "".join(seq) - for seq in itertools.product( - *((str(i) for i in range(d)) for d in qid_shape) - ) - ] - # Round each real/imaginary coefficient up to `decimals`, before judging if it's zero. - coefficients = [ - round(x.real, decimals) + 1j * round(x.imag, decimals) for x in state_vector - ] - # Build map from all post selected objects' corresponding index in the - # permutations to its post selected value. - post_selection_filter = {} - for post_selection_obj, post_selection_value in self.post_selection.items(): - for obj, index in qubit_map.items(): - if obj.name == post_selection_obj.name: - post_selection_filter[index] = post_selection_value - break - if len(post_selection_filter) != len(self.post_selection): - raise ValueError("Missing post selection qubits!") - - # Apply the post selection to trim the state vector. - filtered_indices = [] - for index in np.nonzero(coefficients)[0]: - perm = perm_list[index] - satisfied = True - # Check that all post selection criteria are satisfied. - for filter_index, value in post_selection_filter.items(): - if int(perm[filter_index]) != value: - satisfied = False - break - if satisfied: - filtered_indices.append(index) - - # We need to renormalize the state vector since it's been trimed. - prob_sum = 0 - for index in filtered_indices: - prob_sum += abs(coefficients[index]) ** 2 - - # Calculate the probability of each world scenario. - final_world_distribution = {} - for index in filtered_indices: - # Convert the permutation string into tuple of int, - # i.e. "101" into (1, 0, 1). - key = tuple(map(int, tuple(perm_list[index]))) - # Renormalize. - final_world_distribution[key] = abs(coefficients[index]) ** 2 / prob_sum - - # TODO(pengfeichen): make the above calculation a separate function, which calculates - # the distribution of the whole world (or specified objects) by state vector. - - # Calculate the distribution of all objects. - final_object_distribution = {} - for obj, index in qubit_map.items(): - final_object_distribution[obj.name] = 0 - for key, value in final_world_distribution.items(): - # We sum up all non-zero probabilities. - if key[index] > 0: - final_object_distribution[obj.name] += value - - # Shrink the dictionary above to a list of probabilities of the - # desired/specified objects. - binary_probs = [] - for obj in objects: - if obj.name not in final_object_distribution: - raise ValueError(f"{obj.name} not found.") - binary_probs.append(final_object_distribution[obj.name]) - return binary_probs - def __getitem__(self, name: str) -> QuantumObject: quantum_object = self.object_name_dict.get(name, None) if not quantum_object: diff --git a/unitary/alpha/quantum_world_test.py b/unitary/alpha/quantum_world_test.py index 0d21719a..e3b0ce1b 100644 --- a/unitary/alpha/quantum_world_test.py +++ b/unitary/alpha/quantum_world_test.py @@ -662,8 +662,6 @@ def test_get_histogram_and_get_probabilities_one_binary_qobject( assert probs == [{0: 0.0, 1: 1.0}] bin_probs = world.get_binary_probabilities() assert bin_probs == [1.0] - bin_probs = world.get_binary_probabilities_from_state_vector() - assert bin_probs == [1.0] alpha.Flip()(l1) histogram = world.get_histogram() assert histogram == [{0: 100, 1: 0}] @@ -673,8 +671,6 @@ def test_get_histogram_and_get_probabilities_one_binary_qobject( assert probs == [{0: 1.0, 1: 0.0}] bin_probs = world.get_binary_probabilities() assert bin_probs == [0.0] - bin_probs = world.get_binary_probabilities_from_state_vector() - assert bin_probs == [0.0] alpha.Superposition()(l1) histogram = world.get_histogram() assert len(histogram) == 1 @@ -692,8 +688,6 @@ def test_get_histogram_and_get_probabilities_one_binary_qobject( assert probs[0][1] > 0.1 bin_probs = world.get_binary_probabilities() assert 0.1 <= bin_probs[0] <= 1.0 - bin_probs = world.get_binary_probabilities_from_state_vector() - assert 0.1 <= bin_probs[0] <= 1.0 @pytest.mark.parametrize( @@ -722,13 +716,6 @@ def test_get_histogram_and_get_probabilities_one_trinary_qobject( assert bin_probs == [1.0] -def test_get_binary_probabilities_from_state_vector_one_trinary_qobject(): - l1 = alpha.QuantumObject("l1", StopLight.YELLOW) - world = alpha.QuantumWorld([l1], sampler=cirq.Simulator(), compile_to_qubits=False) - bin_probs = world.get_binary_probabilities_from_state_vector() - assert bin_probs == [1.0] - - @pytest.mark.parametrize( ("simulator", "compile_to_qubits"), [ @@ -760,15 +747,3 @@ def test_get_histogram_and_get_probabilities_two_qobjects(simulator, compile_to_ assert probs == [{0: 0.0, 1: 1.0, 2: 0.0}] bin_probs = world.get_binary_probabilities(objects=[l2], count=1000) assert bin_probs == [1.0] - - -def test_get_binary_probabilities_from_state_vector_two_qobjects(): - l1 = alpha.QuantumObject("l1", Light.GREEN) - l2 = alpha.QuantumObject("l2", StopLight.GREEN) - world = alpha.QuantumWorld( - [l1, l2], sampler=cirq.Simulator(), compile_to_qubits=False - ) - bin_probs = world.get_binary_probabilities_from_state_vector() - assert bin_probs == [1.0, 1.0] - bin_probs = world.get_binary_probabilities_from_state_vector(objects=[l2]) - assert bin_probs == [1.0] From 32b893c859fb570c3b8e4789c4c81a1aeaf4fbac Mon Sep 17 00:00:00 2001 From: Pengfei Chen Date: Wed, 29 Nov 2023 15:31:22 -0800 Subject: [PATCH 6/7] update --- unitary/alpha/quantum_world_test.py | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/unitary/alpha/quantum_world_test.py b/unitary/alpha/quantum_world_test.py index e3b0ce1b..352ab038 100644 --- a/unitary/alpha/quantum_world_test.py +++ b/unitary/alpha/quantum_world_test.py @@ -747,3 +747,33 @@ def test_get_histogram_and_get_probabilities_two_qobjects(simulator, compile_to_ assert probs == [{0: 0.0, 1: 1.0, 2: 0.0}] bin_probs = world.get_binary_probabilities(objects=[l2], count=1000) assert bin_probs == [1.0] + + +@pytest.mark.parametrize( + ("simulator", "compile_to_qubits"), + [ + (cirq.Simulator, False), + (cirq.Simulator, True), + # Cannot use SparseSimulator without `compile_to_qubits` due to issue #78. + (alpha.SparseSimulator, True), + ], +) +def test_get_correlated_histogram_with_entangled_qobjects(simulator, compile_to_qubits): + light1 = alpha.QuantumObject("l1", Light.GREEN) + light2 = alpha.QuantumObject("l2", Light.RED) + light3 = alpha.QuantumObject("l3", Light.RED) + light4 = alpha.QuantumObject("l4", Light.GREEN) + light5 = alpha.QuantumObject("l5", Light.RED) + + world = alpha.QuantumWorld( + [light1, light2, light3, light4, light5], + sampler=simulator(), + compile_to_qubits=compile_to_qubits, + ) + alpha.Split()(light1, light2, light3) + alpha.quantum_if(light2).equals(1).apply(alpha.Move())(light4, light5) + + # histogram = world.get_histogram() + # assert histogram == [{0: 0, 1: 100}, {0: 0, 1: 100, 2: 0}] + histogram = world.get_correlated_histogram() + assert histogram.keys() == [(0, 0, 1, 1, 0), (0, 1, 0, 0, 1)] From e7274bdbc5e34a4c4e5e71b84d0aef10b777e24b Mon Sep 17 00:00:00 2001 From: Pengfei Chen Date: Wed, 29 Nov 2023 15:39:19 -0800 Subject: [PATCH 7/7] update --- unitary/alpha/quantum_world.py | 7 ++++--- unitary/alpha/quantum_world_test.py | 4 +--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/unitary/alpha/quantum_world.py b/unitary/alpha/quantum_world.py index 29639348..5cd70617 100644 --- a/unitary/alpha/quantum_world.py +++ b/unitary/alpha/quantum_world.py @@ -498,9 +498,10 @@ def get_correlated_histogram( count: Number of measurements Returns: - A dictionary, with the keys being each possible state of the whole quantum - world (or `objects` if specified) in terms of tuple, and the values being - the count of that state. + A dictionary, with the keys being tuples representing each possible state of + the whole quantum world (or, if `objects` is specified, the key is a tuple of + the results of each object in `objects` and in the order of `objects`), and + the values being the count of that state. """ if not objects: objects = self.public_objects diff --git a/unitary/alpha/quantum_world_test.py b/unitary/alpha/quantum_world_test.py index 352ab038..30b02941 100644 --- a/unitary/alpha/quantum_world_test.py +++ b/unitary/alpha/quantum_world_test.py @@ -773,7 +773,5 @@ def test_get_correlated_histogram_with_entangled_qobjects(simulator, compile_to_ alpha.Split()(light1, light2, light3) alpha.quantum_if(light2).equals(1).apply(alpha.Move())(light4, light5) - # histogram = world.get_histogram() - # assert histogram == [{0: 0, 1: 100}, {0: 0, 1: 100, 2: 0}] histogram = world.get_correlated_histogram() - assert histogram.keys() == [(0, 0, 1, 1, 0), (0, 1, 0, 0, 1)] + assert histogram.keys() == {(0, 0, 1, 1, 0), (0, 1, 0, 0, 1)}