Source code for qnetvo.cost.I_3322_bell_inequality

from pennylane import math
from ..postprocessing import even_parity_ids
from ..qnodes import joint_probs_qnode, local_parity_expval_qnode


[docs]def post_process_I_3322_joint_probs(probs_vec): """Applies post-processing to multi-qubit probabilities in order to coarse-grain them into the dichotomic parity observables required by the :math:`I_{3322}` inequality. An :math:`N`-qubit circuit has :math:`2^N` measurement outcomes. To construct the joint probabilitye :math:`P(00|xy)` for binary outputs, the joint probabilities can be partitioned into two sets, :math:`\\{Even\\}` and :math`\\{Odd\\}` which denote the set of *Even* and *Odd* parity bit strings. The :math:`2^N` joint probabilities are expressed as :math:`P(\\vec{a},\\vec{b}|x,y)` where :math:`\\vec{a}` and :math:`\\vec{b}` are each :math:`N`-bit strings. Since the :math:`I_{3322}` inequality only requires dichotomic probabilities :math:`P(00|xy)`, our post-processing only needs to calculate this value. To reduce the joint probabilities :math:`P(\\vec{a},\\vec{b}|x,y)` to dichotomic probabilities :math:`P(00|x,y)` we aggregate the probabilities of even parity bit strings with .. math:: P(00|xy) = \\{Even\\}_A\\{Even\\}_B = \\sum_{\\vec{a}\\in \\{Even\\}} \\sum_{\\vec{b}\\in\\{Even\\}} P(\\vec{a},\\vec{b}|x,y). :param n_qubits: The number of wires measured to obtained the joint probabilites. :type n_qubits: int :param probs_vec: A probability vector obtained by measuring all wires in the computational basis. :type probs_vec: list[float] :returns: The dichotomic probability :math:`P(00|xy)`. """ n_local_qubits = int(math.log2(len(probs_vec)) / 2) probs = math.reshape(probs_vec, (2**n_local_qubits, 2**n_local_qubits)) even_ids = even_parity_ids(n_local_qubits) return sum([sum([probs[a, b] for b in even_ids]) for a in even_ids])
[docs]def I_3322_bell_inequality_cost_fn(network_ansatz, **qnode_kwargs): """Constructs a cost function that maximizes the score of the :math:`I_{3322}` Bell inequality. :param network_ansatz: A ``NetworkAnsatz`` class specifying the quantum network simulation. :type network_ansatz: NetworkAnsatz :returns: A cost function evaluated as ``cost(*network_settings)`` where the ``network_settings`` are obtained from the provided ``network_ansatz`` class. """ I_3322_joint_probs_qnode = joint_probs_qnode(network_ansatz, **qnode_kwargs) I_3322_local_expval_qnode = local_parity_expval_qnode(network_ansatz, **qnode_kwargs) static_prep_inputs = [[0] * len(layer_nodes) for layer_nodes in network_ansatz.layers[0:-1]] def cost(*network_settings): score = 0 for x, y, mult in [ (0, 0, 1), (0, 1, 1), (0, 2, 1), (1, 0, 1), (1, 1, 1), (1, 2, -1), (2, 0, 1), (2, 1, -1), ]: settings = network_ansatz.qnode_settings( network_settings, static_prep_inputs + [[x, y]] ) probs_vec_xy = I_3322_joint_probs_qnode(settings) prob00_xy = post_process_I_3322_joint_probs(probs_vec_xy) score += mult * prob00_xy settings_00 = network_ansatz.qnode_settings(network_settings, static_prep_inputs + [[0, 0]]) settings_11 = network_ansatz.qnode_settings(network_settings, static_prep_inputs + [[1, 1]]) expval_00 = I_3322_local_expval_qnode(settings_00) expval_11 = I_3322_local_expval_qnode(settings_11) # - P_A(0|0) score += -1 * (expval_00[0] + 1) / 2 # - 2 * P_B(0|0) score += -2 * (expval_00[1] + 1) / 2 # - P_B(0|1) score += -1 * (expval_11[1] + 1) / 2 return -(score) return cost