Beispiel #1
0
def config(X):
    n = int(np.ceil(np.log2(len(X[0]))))  # pylint: disable=no-member
    n = 2**int(np.ceil(np.log2(n)))  # n tem que ser potência de 2. # pylint: disable=no-member
    N = 2**n - 1  # len(X[0])-1 # N precisa ser tal que n seja potência de 2 mais próxima de log_2(X[0]). O hierarchical exige que n seja dessa maneira.
    w = 2 * n - 1  # número de parâmetros do circuito (weights)
    X = np.c_[X, np.zeros((len(X), 2**n - len(X[0])))]  # o número de qubits necessários para codificar os dados (log_2(N)) precisa ser uma potencia de 2. # pylint: disable=no-member

    return n, N, w, X
Beispiel #2
0
def config(X):
    n = int(np.ceil(np.log2(len(X[0]))))             # pylint: disable=no-member
    n = 2**int(np.ceil(np.log2(n)))                  # n tem que ser potência de 2. # pylint: disable=no-member
    N = n                                            # número total de qubits no circuito.
    w = 2*n - 1                                      # número de parâmetros do circuito (weights)
    X = np.c_[X, np.zeros((len(X), 2**n-len(X[0])))] # o número de qubits necessários para codificar os dados (log_2(N)) precisa ser uma potencia de 2. # pylint: disable=no-member
    
    return n, N, w, X
Beispiel #3
0
def compute_indices(wires, n_block_wires):
    """Generate a list containing the wires for each block.

    Args:
        wires (Iterable): wires that the template acts on
        n_block_wires (int): number of wires per block

    Returns:
        layers (array): array of wire labels for each block
    """

    n_wires = len(wires)

    if n_block_wires % 2 != 0:
        raise ValueError(
            f"n_block_wires must be an even integer; got {n_block_wires}")

    if n_block_wires < 2:
        raise ValueError(
            f"number of wires in each block must be larger than or equal to 2; got n_block_wires = {n_block_wires}"
        )

    if n_block_wires > n_wires:
        raise ValueError(
            f"n_block_wires must be smaller than or equal to the number of wires; "
            f"got n_block_wires = {n_block_wires} and number of wires = {n_wires}"
        )

    if not np.log2(n_wires / n_block_wires).is_integer():
        warnings.warn(
            f"The number of wires should be n_block_wires times 2^n; got n_wires/n_block_wires = {n_wires/n_block_wires}"
        )

    n_wires = 2**(int(np.log2(len(wires) / n_block_wires))) * n_block_wires
    n_layers = int(np.log2(n_wires // n_block_wires)) + 1

    layers = [[
        wires[i] for i in range(
            x + 2**(j - 1) * n_block_wires // 2 - n_block_wires // 2,
            x + n_block_wires // 2 + 2**(j - 1) * n_block_wires // 2 -
            n_block_wires // 2,
        )
    ] + [
        wires[i] for i in range(
            x + 2**(j - 1) * n_block_wires // 2 +
            2**(j - 1) * n_block_wires // 2 - n_block_wires // 2,
            x + 2**(j - 1) * n_block_wires // 2 + n_block_wires // 2 +
            2**(j - 1) * n_block_wires // 2 - n_block_wires // 2,
        )
    ] for j in range(1, n_layers + 1)
              for x in range(0, n_wires - n_block_wires // 2, 2**(j - 1) *
                             n_block_wires)]

    return layers
Beispiel #4
0
def config(X):
    n = 2**int(np.ceil(np.log2(len(X[0]))))  # len(X[0]) # número de qubits necessário para armazenar o dado codificado. # pylint: disable=no-member
    N = n  # número total de qubits no circuito.
    w = 2 * n - 1  # número de parâmetros do circuito (weights)
    X = np.c_[X, np.zeros((len(X), n - len(X[0])))]  # pylint: disable=no-member

    return n, N, w, X
def shadow_bound(error, observables, failure_rate=0.01):
    """
    Calculate the shadow bound for the Pauli measurement scheme.

    Implements Eq. (S13) from https://arxiv.org/pdf/2002.08953.pdf

    Args:
        error (float): The error on the estimator.
        observables (list) : List of matrices corresponding to the observables we intend to
            measure.
        failure_rate (float): Rate of failure for the bound to hold.

    Returns:
        An integer that gives the number of samples required to satisfy the shadow bound and
        the chunk size required attaining the specified failure rate.
    """
    M = len(observables)
    K = 2 * np.log(2 * M / failure_rate)
    shadow_norm = (
        lambda op: np.linalg.norm(
            op - np.trace(op) / 2 ** int(np.log2(op.shape[0])), ord=np.inf
        )
        ** 2
    )
    N = 34 * max(shadow_norm(o) for o in observables) / error ** 2
    return int(np.ceil(N * K)), int(K)
Beispiel #6
0
    def get_n_blocks(wires, n_block_wires):
        """Returns the expected number of blocks for a set of wires and number of wires per block.
        Args:
            wires (Sequence): number of wires the template acts on
            n_block_wires (int): number of wires per block
        Returns:
            n_blocks (int): number of blocks; expected length of the template_weights argument
        """

        n_wires = len(wires)
        if not np.log2(n_wires / n_block_wires).is_integer():
            warnings.warn(
                f"The number of wires should be n_block_wires times 2^n; got n_wires/n_block_wires = {n_wires/n_block_wires}"
            )

        if n_block_wires > n_wires:
            raise ValueError(
                f"n_block_wires must be smaller than or equal to the number of wires; got n_block_wires = {n_block_wires} and number of wires = {n_wires}"
            )

        n_blocks = 2**int(np.log2(n_wires / n_block_wires)) * 2 - 1
        return n_blocks
Beispiel #7
0
    def __init__(
        self,
        wires,
        n_block_wires,
        block,
        n_params_block,
        template_weights=None,
        do_queue=True,
        id=None,
    ):

        self.ind_gates = compute_indices(wires, n_block_wires)
        n_wires = len(wires)
        shape = qml.math.shape(template_weights)  # (n_params_block, n_blocks)
        self.n_params_block = n_params_block
        self.n_blocks = 2**int(np.log2(n_wires / n_block_wires)) * 2 - 1
        self.block = block

        if shape == ():
            self.template_weights = np.random.rand(n_params_block,
                                                   int(self.n_blocks))

        else:
            if shape[0] != self.n_blocks:
                raise ValueError(
                    f"Weights tensor must have first dimension of length {self.n_blocks}; got {shape[0]}"
                )
            if shape[-1] != self.n_params_block:
                raise ValueError(
                    f"Weights tensor must have last dimension of length {self.n_params_block}; got {shape[-1]}"
                )

        self.template_weights = template_weights

        super().__init__(template_weights,
                         wires=wires,
                         do_queue=do_queue,
                         id=id)
    dev = qml.device("default.qubit.autograd", wires=num_qubits)

    constant_hea_depth = 3

    ansatze = [
        ttn_circuit(num_qubits),
        mera_circuit(num_qubits),
        hea_circuit(num_qubits),
        hea_circuit(num_qubits),
        hea_circuit(num_qubits)
    ]
    num_params_ansatz = [
        num_params_per_gate * get_num_ttn_gates(num_qubits),
        num_params_per_gate * get_num_mera_gates(num_qubits),
        3 * (num_qubits * constant_hea_depth),
        3 * (num_qubits * int(np.floor(np.log2(num_qubits)))),
        3 * (num_qubits * num_qubits)
    ]
    ansatz_names = [
        "TTN", "MERA", "HEA (constant)", "HEA (log)", "HEA (linear)"
    ]

    for (ansatz, ansatz_name, num_params) in zip(ansatze, ansatz_names,
                                                 num_params_ansatz):
        print(f" --- {ansatz_name} ({num_params} parameters) ---")

        for init in initializations:
            print(f"  +++ {init} +++")
            mod_ansatz = ansatz
            if init in ["Random |+...+>", "Zero |+...+>"]: