def test_gap(trotter):
    """Check gap callback for adiabatic evolution model."""
    from qibo import hamiltonians
    h0 = hamiltonians.X(3, trotter=trotter)
    h1 = hamiltonians.TFIM(3, h=1.0, trotter=trotter)

    ham = lambda t: ((1 - t) * h0.matrix + t * h1.matrix).numpy()
    targets = {"ground": [], "excited": [], "gap": []}
    for t in np.linspace(0, 1, 11):
        eigvals = np.linalg.eigvalsh(ham(t)).real
        targets["ground"].append(eigvals[0])
        targets["excited"].append(eigvals[1])
        targets["gap"].append(eigvals[1] - eigvals[0])

    gap = callbacks.Gap()
    ground = callbacks.Gap(0)
    excited = callbacks.Gap(1)
    evolution = AdiabaticEvolution(h0,
                                   h1,
                                   lambda t: t,
                                   dt=1e-1,
                                   callbacks=[gap, ground, excited])
    final_state = evolution(final_time=1.0)

    np.testing.assert_allclose(ground[:], targets["ground"])
    np.testing.assert_allclose(excited[:], targets["excited"])
    np.testing.assert_allclose(gap[:], targets["gap"])
    # check not implemented for density matrices
    with pytest.raises(NotImplementedError):
        gap(np.zeros(8), is_density_matrix=True)
def test_gap(backend, dense, check_degenerate):
    from qibo import hamiltonians
    h0 = hamiltonians.X(4, dense=dense)
    if check_degenerate:
        # use h=0 to make this Hamiltonian degenerate
        h1 = hamiltonians.TFIM(4, h=0, dense=dense)
    else:
        h1 = hamiltonians.TFIM(4, h=1, dense=dense)

    ham = lambda t: (1 - t) * h0.matrix + t * h1.matrix
    targets = {"ground": [], "excited": [], "gap": []}
    for t in np.linspace(0, 1, 11):
        eigvals = np.linalg.eigvalsh(ham(t)).real
        targets["ground"].append(eigvals[0])
        targets["excited"].append(eigvals[1])
        targets["gap"].append(eigvals[1] - eigvals[0])
    if check_degenerate:
        targets["gap"][-1] = eigvals[3] - eigvals[0]

    gap = callbacks.Gap(check_degenerate=check_degenerate)
    ground = callbacks.Gap(0)
    excited = callbacks.Gap(1)
    evolution = AdiabaticEvolution(h0, h1, lambda t: t, dt=1e-1,
                                   callbacks=[gap, ground, excited])
    final_state = evolution(final_time=1.0)
    targets = {k: K.stack(v) for k, v in targets.items()}
    K.assert_allclose(ground[:], targets["ground"])
    K.assert_allclose(excited[:], targets["excited"])
    K.assert_allclose(gap[:], targets["gap"])
def test_gap(backend, trotter, check_degenerate):
    original_backend = qibo.get_backend()
    qibo.set_backend(backend)
    from qibo import hamiltonians
    h0 = hamiltonians.X(4, trotter=trotter)
    if check_degenerate:
        # use h=0 to make this Hamiltonian degenerate
        h1 = hamiltonians.TFIM(4, h=0, trotter=trotter)
    else:
        h1 = hamiltonians.TFIM(4, h=1, trotter=trotter)

    ham = lambda t: (1 - t) * h0.matrix + t * h1.matrix
    targets = {"ground": [], "excited": [], "gap": []}
    for t in np.linspace(0, 1, 11):
        eigvals = np.linalg.eigvalsh(ham(t)).real
        targets["ground"].append(eigvals[0])
        targets["excited"].append(eigvals[1])
        targets["gap"].append(eigvals[1] - eigvals[0])
    if check_degenerate:
        targets["gap"][-1] = eigvals[3] - eigvals[0]

    gap = callbacks.Gap(check_degenerate=check_degenerate)
    ground = callbacks.Gap(0)
    excited = callbacks.Gap(1)
    evolution = AdiabaticEvolution(h0,
                                   h1,
                                   lambda t: t,
                                   dt=1e-1,
                                   callbacks=[gap, ground, excited])
    final_state = evolution(final_time=1.0)
    np.testing.assert_allclose(ground[:], targets["ground"])
    np.testing.assert_allclose(excited[:], targets["excited"])
    np.testing.assert_allclose(gap[:], targets["gap"])
    qibo.set_backend(original_backend)
def test_gap_errors():
    """Check errors in gap callback instantiation."""
    # invalid string ``mode``
    with pytest.raises(ValueError):
        gap = callbacks.Gap("test")
    # invalid ``mode`` type
    with pytest.raises(TypeError):
        gap = callbacks.Gap([])
    # invalid evolution model type
    with pytest.raises(TypeError):
        gap = callbacks.Gap()
        gap.evolution = "test"
    # call before setting evolution model
    with pytest.raises(ValueError):
        gap = callbacks.Gap()
        gap(np.ones(4))
def test_gap_errors():
    """Check errors in gap callback instantiation."""
    # invalid string ``mode``
    with pytest.raises(ValueError):
        gap = callbacks.Gap("test")
    # invalid ``mode`` type
    with pytest.raises(TypeError):
        gap = callbacks.Gap([])

    gap = callbacks.Gap()
    # invalid evolution model type
    with pytest.raises(TypeError):
        gap.evolution = "test"
    # call before setting evolution model
    with pytest.raises(ValueError):
        gap(np.ones(4))
    # not implemented for density matrices
    gap.density_matrix = True
    with pytest.raises(NotImplementedError):
        gap(np.zeros(8))
    # for coverage
    _ = gap.density_matrix
    gap.density_matrix = False
Exemple #6
0
def main(nqubits, instance, T, dt, solver, plot, trotter, params, method,
         maxiter):
    """Adiabatic evoluition to find the solution of an exact cover instance.

    Args:
        nqubits (int): number of qubits for the file that contains the
            information of an Exact Cover instance.
        instance (int): intance used for the desired number of qubits.
        T (float): maximum schedule time. The larger T, better final results.
        dt (float): time interval for the evolution.
        solver (str): solver used for the adiabatic evolution.
        plot (bool): decides if plots of the energy and gap will be returned.
        trotter (bool): decides if a Trotter Hamiltonian will be used.
        params (list): list of polynomial coefficients for scheduling function.
            Default is linear scheduling.
        method (str): Method to use for scheduling optimization (optional).
        maxiter (bool): Maximum iterations for scheduling optimization (optional).

    Returns:
        Result of the most probable outcome after the adiabatic evolution.
        Plots of the ground and excited state energies and the underlying gap
        during the adiabatic evolution. The plots are created only if the
        ``--plot`` option is enabled.
    """
    # Read 3SAT clauses from file
    control, solution, clauses = functions.read_file(nqubits, instance)
    nqubits = int(control[0])
    # Define "easy" and "problem" Hamiltonians
    times = functions.times(nqubits, clauses)
    sh0, smap0 = functions.h_initial(nqubits, times)
    sh1, smap1 = functions.h_problem(nqubits, clauses)
    if trotter:
        print('Using Trotter decomposition for the Hamiltonian\n')
        gs = lambda: functions.ground_state(nqubits)
        H0 = hamiltonians.TrotterHamiltonian.from_symbolic(sh0,
                                                           smap0,
                                                           ground_state=gs)
        H1 = hamiltonians.TrotterHamiltonian.from_symbolic(sh1, smap1)
    else:
        print('Using the full Hamiltonian evolution\n')
        H0 = hamiltonians.Hamiltonian.from_symbolic(sh0, smap0)
        H1 = hamiltonians.Hamiltonian.from_symbolic(sh1, smap1)

    print('-' * 20 + '\n')
    if plot and nqubits >= 14:
        print('Currently not possible to calculate gap energy for {} qubits.'
              '\n Proceeding to adiabatic evolution without plotting data.\n'
              ''.format(nqubits))
        plot = False
    if plot and method is not None:
        print('Not possible to calculate gap energy during optimization.')
        plot = False

    # Define scheduling according to given params
    if params is None:
        # default is linear scheduling
        s = lambda t: t
    else:
        if method is None:
            s = lambda t: functions.spolynomial(t, params)
        else:
            s = functions.spolynomial

    # Define evolution model and (optionally) callbacks
    if plot:
        ground = callbacks.Gap(0)
        excited = callbacks.Gap(1)
        gap = callbacks.Gap()
        evolve = models.AdiabaticEvolution(H0,
                                           H1,
                                           s,
                                           dt,
                                           solver=solver,
                                           callbacks=[gap, ground, excited])
    else:
        evolve = models.AdiabaticEvolution(H0, H1, s, dt, solver=solver)

    if method is not None:
        print(f'Optimizing scheduling using {method}.\n')
        if params is None:
            params = [T]
        else:
            params.append(T)
        if method == "sgd":
            options = {"nepochs": maxiter}
        else:
            options = {"maxiter": maxiter, "disp": True}
        energy, params, _ = evolve.minimize(params,
                                            method=method,
                                            options=options)
        T = params[-1]

    # Perform evolution
    initial_state = np.ones(2**nqubits) / np.sqrt(2**nqubits)
    final_state = evolve(final_time=T, initial_state=initial_state)
    output_dec = (np.abs(final_state.numpy())**2).argmax()
    max_output = "{0:0{bits}b}".format(output_dec, bits=nqubits)
    max_prob = (np.abs(final_state.numpy())**2).max()
    print("Exact cover instance with {} qubits.\n".format(nqubits))
    if solution:
        print('Known solution: {}\n'.format(''.join(solution)))
    print('-' * 20 + '\n')
    print(f'Adiabatic evolution with total time {T}, evolution step {dt} and '
          f'solver {solver}.\n')
    print(f'Most common solution after adiabatic evolution: {max_output}.\n')
    print(f'Found with probability: {max_prob}.\n')
    if plot:
        print('-' * 20 + '\n')
        functions.plot(nqubits, ground[:], excited[:], gap[:], dt, T)
        print('Plots finished.\n')