Source code for qnetvo.information

from pennylane import math
from .qnodes import joint_probs_qnode
from .utilities import mixed_base_num, ragged_reshape
from pennylane import numpy as np


[docs]def behavior_fn(network_ansatz, postmap=np.array([]), qnode_kwargs={}): """Creates an ansatz-specific function for constructing the behavior matrix. A behavior function is created as ``P_Net = behavior(network_ansatz)`` and called as ``P_Net(ansatz_settings)``. The network behavior ``P_Net`` is a column stochastic matrix containing the conditional probabilities, .. math:: \\mathbf{P}_{Net} = \\sum_{\\{x_i\\}_i,y}P(y|\\{x_i\\}_i)|y\\rangle\\langle \\{x_i\\}_i|, where :math:`P(y|\\{x_i\\}_i)` is evaluated by a qnode for each set of inputs :math:`\\{x_i\\}_i`. The number of outputs :math:`y` is :math:`2^N` where :math:`N` is the number of qubits. A post-processing map :math:`\\mathbf{L}` may optionally be applied as :math:`\\mathbf{L}\\mathbf{P}_{Net}` where .. math:: \\mathbf{L} = \\sum_{z,y}P(z|y)|z\\rangle\\langle y|. In the above expression, :math:`z` is a new output drawn from a new alphabet. :param network_ansatz: A class describing the particular quantum network. :type network_ansatz: NetworkAnsatz :param postmap: A post-processing map applied to the bitstrings output from the quantum circuit. The ``postmap`` matrix is column stochastic, that is, each column sums to one and contains only positive values. :type postmap: *optional* np.ndarray :returns: A function ``P_Net(network_settings)`` that evaluates the behavior matrix for a given set of settings. :rtype: function """ # num_in_prep_nodes = [node.num_in for node in network_ansatz.layers[0]] # num_in_meas_nodes = [node.num_in for node in network_ansatz.layers[-1]] # base_digits = num_in_prep_nodes + num_in_meas_nodes # net_num_in = math.prod(base_digits) # raw_net_num_out = 2 ** len(network_ansatz.layers_wires[-1]) probs_qnode = joint_probs_qnode(network_ansatz, **qnode_kwargs) net_num_in = math.prod(network_ansatz.layers_total_num_in) num_inputs_list = math.concatenate(network_ansatz.layers_node_num_in).tolist() node_input_ids = [ ragged_reshape(mixed_base_num(i, num_inputs_list), network_ansatz.layers_num_nodes) for i in range(net_num_in) ] raw_net_num_out = 2 ** len(network_ansatz.layers_wires[-1]) has_postmap = len(postmap) != 0 if has_postmap: if postmap.shape[1] != raw_net_num_out: raise ValueError("The `postmap` must have " + str(raw_net_num_out) + " columns.") # node_input_ids = [mixed_base_num(i, base_digits) for i in range(net_num_in)] # probs_qnode = joint_probs_qnode(network_ansatz, **qnode_kwargs) def behavior(network_settings): raw_behavior = np.zeros((raw_net_num_out, net_num_in)) for i, input_id_set in enumerate(node_input_ids): settings = network_ansatz.qnode_settings(network_settings, input_id_set) raw_behavior[:, i] += probs_qnode(settings) return postmap @ raw_behavior if has_postmap else raw_behavior return behavior
[docs]def shannon_entropy(probs): """Evaluates the Shannon entropy for the given marginal probability distribution ``probs``. .. math:: H(X) = -\\sum_{x\\in X}P(x)\\log_2(P(x)) :param probs: A normalized probability vector. :type probs: np.array :returns: The Shannon entropy. :rtype: float """ return -( math.sum( [px * math.log2(px) if px != 0 and not (math.isclose(px, 0)) else 0 for px in probs] ) )