def test_adiabatic_evolution_execute_errors(): h0 = hamiltonians.X(3) h1 = hamiltonians.TFIM(3) # Non-zero ``start_time`` adev = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=1e-2) with pytest.raises(NotImplementedError): final_state = adev(final_time=2, start_time=1) # execute without specifying variational parameters sp = lambda t, p: (1 - p) * np.sqrt(t) + p * t adevp = models.AdiabaticEvolution(h0, h1, sp, dt=1e-1) with pytest.raises(RuntimeError): final_state = adevp(final_time=1)
def test_adiabatic_evolution_schedule(): h0 = hamiltonians.X(3) h1 = hamiltonians.TFIM(3) adev = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=1e-2) assert adev.schedule(0.2) == 0.2 # pylint: disable=E1102 assert adev.schedule(0.8) == 0.8 # pylint: disable=E1102 # s(0) != 0 with pytest.raises(ValueError): adev = models.AdiabaticEvolution(h0, h1, lambda t: t + 1, dt=1e-2) # s(T) != 0 with pytest.raises(ValueError): adev = models.AdiabaticEvolution(h0, h1, lambda t: t / 2, dt=1e-2)
def test_set_scheduling_parameters(): """Test ``AdiabaticEvolution.set_parameters``.""" h0 = hamiltonians.X(3) h1 = hamiltonians.TFIM(3) sp = lambda t, p: (1 - p[0]) * np.sqrt(t) + p[0] * t adevp = models.AdiabaticEvolution(h0, h1, sp, 1e-2) adevp.set_parameters([0.5, 1]) final_psi = adevp(final_time=1) s = lambda t: 0.5 * np.sqrt(t) + 0.5 * t adev = models.AdiabaticEvolution(h0, h1, s, 1e-2) target_psi = adev(final_time=1) np.testing.assert_allclose(final_psi, target_psi)
def test_trotter_hamiltonian_t(nqubits, h=1.0, dt=1e-3): """Test using ``TrotterHamiltonian`` in adiabatic evolution model.""" dense_h0 = hamiltonians.X(nqubits) dense_h1 = hamiltonians.TFIM(nqubits, h=h) dense_adev = models.AdiabaticEvolution(dense_h0, dense_h1, lambda t: t, dt) local_h0 = hamiltonians.X(nqubits, trotter=True) local_h1 = hamiltonians.TFIM(nqubits, h=h, trotter=True) local_adev = models.AdiabaticEvolution(local_h0, local_h1, lambda t: t, dt) for t in np.random.random(10): local_matrix = local_adev.hamiltonian(t, total_time=1).dense.matrix target_matrix = dense_adev.hamiltonian(t, total_time=1).matrix np.testing.assert_allclose(local_matrix, target_matrix)
def test_adiabatic_evolution_errors(): """Test errors of ``AdiabaticEvolution`` model.""" # Hamiltonians of bad type h0 = hamiltonians.X(3) s = lambda t: t with pytest.raises(TypeError): adev = models.AdiabaticEvolution(h0, lambda t: h0, s, dt=1e-2) h1 = hamiltonians.TFIM(2) with pytest.raises(TypeError): adev = models.AdiabaticEvolution(lambda t: h1, h1, s, dt=1e-2) # Hamiltonians with different number of qubits with pytest.raises(ValueError): adev = models.AdiabaticEvolution(h0, h1, s, dt=1e-2) # s with three arguments h0 = hamiltonians.X(2) s = lambda t, a, b: t + a + b with pytest.raises(ValueError): adev = models.AdiabaticEvolution(h0, h1, s, dt=1e-2) # s(0) != 0 with pytest.raises(ValueError): adev = models.AdiabaticEvolution(h0, h1, lambda t: t + 1, dt=1e-2) # s(T) != 0 with pytest.raises(ValueError): adev = models.AdiabaticEvolution(h0, h1, lambda t: t / 2, dt=1e-2) # Non-zero ``start_time`` adev = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=1e-2) with pytest.raises(NotImplementedError): final_state = adev(final_time=2, start_time=1) # execute without specifying variational parameters sp = lambda t, p: (1 - p) * np.sqrt(t) + p * t adevp = models.AdiabaticEvolution(h0, h1, sp, dt=1e-1) with pytest.raises(ValueError): final_state = adevp(final_time=1)
def main(nqubits_list, dt, solver, trotter=False, accelerators=None): """Performs adiabatic evolution with critical TFIM as the "hard" Hamiltonian.""" if accelerators is not None: trotter = True solver = "exp" print(f"Using {solver} solver and dt = {dt}.") print(f"Accelerators: {accelerators}") for nqubits in nqubits_list: start_time = time.time() h0 = hamiltonians.X(nqubits, trotter=trotter) h1 = hamiltonians.TFIM(nqubits, h=1.0, trotter=trotter) ham_creation_time = time.time() - start_time print(f"\nnqubits = {nqubits}, solver = {solver}") print(f"trotter = {trotter}, accelerators = {accelerators}") print("Hamiltonians created in:", ham_creation_time) start_time = time.time() evolution = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=dt, solver=solver, accelerators=accelerators) creation_time = time.time() - start_time print("Evolution model created in:", creation_time) start_time = time.time() final_psi = evolution(final_time=1.0) simulation_time = time.time() - start_time print("Simulation time:", simulation_time)
def test_energy_callback(solver, dt, atol): """Test using energy callback in adiabatic evolution.""" h0 = hamiltonians.X(2) h1 = hamiltonians.TFIM(2) energy = callbacks.Energy(h1) adev = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=dt, callbacks=[energy], solver=solver) final_psi = adev(final_time=1) target_psi = np.ones(4) / 2 calc_energy = lambda psi: psi.conj().dot(K.to_numpy(h1.matrix).dot(psi)) target_energies = [calc_energy(target_psi)] ham = lambda t: h0 * (1 - t) + h1 * t for n in range(int(1 / dt)): prop = K.to_numpy(ham(n * dt).exp(dt)) target_psi = prop.dot(target_psi) target_energies.append(calc_energy(target_psi)) assert_states_equal(final_psi, target_psi, atol=atol) target_energies = K.cast(target_energies) K.assert_allclose(energy[:], target_energies, atol=atol)
def test_adiabatic_evolution_hamiltonian(backend, dense): """Test adiabatic evolution hamiltonian as a function of time.""" h0 = hamiltonians.X(2, dense=dense) h1 = hamiltonians.TFIM(2, dense=dense) adev = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=1e-2) # try accessing hamiltonian before setting it with pytest.raises(RuntimeError): adev.hamiltonian(0.1) m1 = np.array([[0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]]) m2 = np.diag([2, -2, -2, 2]) ham = lambda t, T: -(1 - t / T) * m1 - (t / T) * m2 adev.hamiltonian.total_time = 1 for t in [0, 0.3, 0.7, 1.0]: if dense: matrix = adev.hamiltonian(t).matrix else: matrix = adev.hamiltonian(t).dense.matrix K.assert_allclose(matrix, ham(t, 1)) #try using a different total time adev.hamiltonian.total_time = 2 for t in [0, 0.3, 0.7, 1.0]: if dense: matrix = adev.hamiltonian(t).matrix else: matrix = adev.hamiltonian(t).dense.matrix K.assert_allclose(matrix, ham(t, 2))
def test_initial_state(): """Test that adiabatic evolution initial state is the ground state of H0.""" h0 = hamiltonians.X(3) h1 = hamiltonians.TFIM(3) adev = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=1e-2) target_psi = np.ones(8) / np.sqrt(8) init_psi = adev.get_initial_state() assert_states_equal(init_psi, target_psi)
def main(nqubits, hfield, T, dt, solver, save): """Performs adiabatic evolution with critical TFIM as the "hard" Hamiltonian. Plots how the <H1> energy and the overlap with the actual ground state changes during the evolution. Linear scheduling is used. Args: nqubits (int): Number of qubits in the system. hfield (float): Transverse field Ising model h-field h value. T (float): Total time of the adiabatic evolution. dt (float): Time step used for integration. solver (str): Solver used for integration. save (bool): Whether to save the plots. """ h0 = hamiltonians.X(nqubits) h1 = hamiltonians.TFIM(nqubits, h=hfield) # Calculate target values (H1 ground state) target_state = h1.ground_state() target_energy = h1.eigenvalues()[0].numpy().real # Check ground state state_energy = callbacks.Energy(h1)(target_state).numpy() np.testing.assert_allclose(state_energy.real, target_energy) energy = callbacks.Energy(h1) overlap = callbacks.Overlap(target_state) evolution = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=dt, solver=solver, callbacks=[energy, overlap]) final_psi = evolution(final_time=T) # Plots tt = np.linspace(0, T, int(T / dt) + 1) plt.figure(figsize=(12, 4)) plt.subplot(121) plt.plot(tt, energy[:], linewidth=2.0, label="Evolved state") plt.axhline(y=target_energy, color="red", linewidth=2.0, label="Ground state") plt.xlabel("$t$") plt.ylabel("$H_1$") plt.legend() plt.subplot(122) plt.plot(tt, overlap[:], linewidth=2.0) plt.xlabel("$t$") plt.ylabel("Overlap") if save: plt.savefig(f"images/dynamics_n{nqubits}T{T}.png", bbox_inches="tight") else: plt.show()
def test_adiabatic_evolution_init(): # Hamiltonians of bad type h0 = hamiltonians.X(3) s = lambda t: t with pytest.raises(TypeError): adev = models.AdiabaticEvolution(h0, lambda t: h0, s, dt=1e-2) h1 = hamiltonians.TFIM(2) with pytest.raises(TypeError): adev = models.AdiabaticEvolution(lambda t: h1, h1, s, dt=1e-2) # Hamiltonians with different number of qubits with pytest.raises(ValueError): adev = models.AdiabaticEvolution(h0, h1, s, dt=1e-2) # Adiabatic Hamiltonian with bad hamiltonian types from qibo.core.adiabatic import AdiabaticHamiltonian with pytest.raises(TypeError): h = AdiabaticHamiltonian("a", "b") # pylint: disable=E0110 # s with three arguments h0 = hamiltonians.X(2) s = lambda t, a, b: t + a + b with pytest.raises(ValueError): adev = models.AdiabaticEvolution(h0, h1, s, dt=1e-2)
def main(nqubits, hfield, params, dt, solver, method, maxiter, save): """Optimizes the scheduling of the adiabatic evolution. The ansatz for s(t) is a polynomial whose order is defined by the length of ``params`` given. Args: nqubits (int): Number of qubits in the system. hfield (float): Transverse field Ising model h-field h value. params (str): Initial guess for the free parameters. dt (float): Time step used for integration. solver (str): Solver used for integration. method (str): Which scipy optimizer to use. maxiter (int): Maximum iterations for scipy optimizer. save (str): Name to use for saving optimization history. If ``None`` history will not be saved. """ h0 = hamiltonians.X(nqubits) h1 = hamiltonians.TFIM(nqubits, h=hfield) # Calculate target values (H1 ground state) target_state = h1.ground_state() target_energy = h1.eigenvalues()[0].numpy().real # Check ground state state_energy = callbacks.Energy(h1)(target_state).numpy() np.testing.assert_allclose(state_energy.real, target_energy) evolution = models.AdiabaticEvolution(h0, h1, spolynomial, dt=dt, solver=solver) options = {"maxiter": maxiter, "disp": True} energy, parameters, _ = evolution.minimize(params, method=method, options=options, messages=True) print("\nBest energy found:", energy) print("Final parameters:", parameters) final_state = evolution(parameters[-1]) overlap = callbacks.Overlap(target_state)(final_state).numpy() print("Target energy:", target_energy) print("Overlap:", overlap) if save: evolution.opt_history["loss"].append(target_energy) np.save(f"optparams/{save}_n{nqubits}_loss.npy", evolution.opt_history["loss"]) np.save(f"optparams/{save}_n{nqubits}_params.npy", evolution.opt_history["params"])
def test_scheduling_optimization(method, options, messages, trotter, filename): """Test optimization of s(t).""" h0 = hamiltonians.X(3, trotter=trotter) h1 = hamiltonians.TFIM(3, trotter=trotter) sp = lambda t, p: (1 - p) * np.sqrt(t) + p * t adevp = models.AdiabaticEvolution(h0, h1, sp, dt=1e-1) best, params = adevp.minimize([0.5, 1], method=method, options=options, messages=messages) if filename is not None: utils.assert_regression_fixture(params, filename)
def main(nqubits, dt, solver, backend, dense=False, accelerators=None, filename=None): """Performs adiabatic evolution with critical TFIM as the "hard" Hamiltonian.""" qibo.set_backend(backend) if accelerators is not None: dense = False solver = "exp" logs = BenchmarkLogger(filename) logs.append({ "nqubits": nqubits, "dt": dt, "solver": solver, "dense": dense, "backend": qibo.get_backend(), "precision": qibo.get_precision(), "device": qibo.get_device(), "threads": qibo.get_threads(), "accelerators": accelerators }) print(f"Using {solver} solver and dt = {dt}.") print(f"Accelerators: {accelerators}") print("Backend:", logs[-1]["backend"]) start_time = time.time() h0 = hamiltonians.X(nqubits, dense=dense) h1 = hamiltonians.TFIM(nqubits, h=1.0, dense=dense) logs[-1]["hamiltonian_creation_time"] = time.time() - start_time print(f"\nnqubits = {nqubits}, solver = {solver}") print(f"dense = {dense}, accelerators = {accelerators}") print("Hamiltonians created in:", logs[-1]["hamiltonian_creation_time"]) start_time = time.time() evolution = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=dt, solver=solver, accelerators=accelerators) logs[-1]["creation_time"] = time.time() - start_time print("Evolution model created in:", logs[-1]["creation_time"]) start_time = time.time() final_psi = evolution(final_time=1.0) logs[-1]["simulation_time"] = time.time() - start_time print("Simulation time:", logs[-1]["simulation_time"]) logs.dump()
def test_set_scheduling_parameters(): """Test ``AdiabaticEvolution.set_parameters``.""" h0 = hamiltonians.X(3) h1 = hamiltonians.TFIM(3) sp = lambda t, p: (1 - p[0]) * np.sqrt(t) + p[0] * t adevp = models.AdiabaticEvolution(h0, h1, sp, 1e-2) # access parametrized scheduling before setting parameters with pytest.raises(ValueError): s = adevp.schedule adevp.set_parameters([0.5, 1]) target_s = lambda t: 0.5 * np.sqrt(t) + 0.5 * t for t in np.random.random(10): assert adevp.schedule(t) == target_s(t) # pylint: disable=E1102
def test_adiabatic_evolution(dt): """Test adiabatic evolution with exponential solver.""" h0 = hamiltonians.X(2) h1 = hamiltonians.TFIM(2) adev = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=dt) m1 = np.array([[0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]]) m2 = np.diag([2, -2, -2, 2]) ham = lambda t: -(1 - t) * m1 - t * m2 target_psi = np.ones(4) / 2 nsteps = int(1 / dt) for n in range(nsteps): target_psi = expm(-1j * dt * ham(n * dt)).dot(target_psi) final_psi = adev(final_time=1) assert_states_equal(final_psi, target_psi)
def test_rk4_evolution(solver, dt=1e-3): """Test adiabatic evolution with Runge-Kutta solver.""" h0 = hamiltonians.X(3) h1 = hamiltonians.TFIM(3) target_psi = [np.ones(8) / np.sqrt(8)] ham = lambda t: h0 * (1 - t) + h1 * t for n in range(int(1 / dt)): prop = ham(n * dt).exp(dt).numpy() target_psi.append(prop.dot(target_psi[-1])) checker = TimeStepChecker(target_psi, atol=dt) adev = models.AdiabaticEvolution(h0, h1, lambda t: t, dt, solver="rk4", callbacks=[checker]) final_psi = adev(final_time=1, initial_state=np.copy(target_psi[0]))
def test_trotterized_adiabatic_evolution(nqubits, accelerators, dt): """Test adiabatic evolution using trotterization of ``TrotterHamiltonian``.""" dense_h0 = hamiltonians.X(nqubits) dense_h1 = hamiltonians.TFIM(nqubits) target_psi = [np.ones(2**nqubits) / np.sqrt(2**nqubits)] ham = lambda t: dense_h0 * (1 - t) + dense_h1 * t for n in range(int(1 / dt)): prop = ham(n * dt).exp(dt).numpy() target_psi.append(prop.dot(target_psi[-1])) local_h0 = hamiltonians.X(nqubits, trotter=True) local_h1 = hamiltonians.TFIM(nqubits, trotter=True) checker = TimeStepChecker(target_psi, atol=dt) adev = models.AdiabaticEvolution(local_h0, local_h1, lambda t: t, dt, callbacks=[checker], accelerators=accelerators) final_psi = adev(final_time=1)
def test_hamiltonian_t(): """Test adiabatic evolution hamiltonian as a function of time.""" h0 = hamiltonians.X(2) h1 = hamiltonians.TFIM(2) adev = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=1e-2) # try accessing hamiltonian before setting it with pytest.raises(RuntimeError): adev.hamiltonian() m1 = np.array([[0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]]) m2 = np.diag([2, -2, -2, 2]) ham = lambda t, T: -(1 - t / T) * m1 - (t / T) * m2 adev.set_hamiltonian(total_time=1) for t in [0, 0.3, 0.7, 1.0]: matrix = adev.hamiltonian(t).matrix np.testing.assert_allclose(matrix, ham(t, 1)) #try using a different total time for t in [0, 0.3, 0.7, 1.0]: matrix = adev.hamiltonian(t, total_time=2).matrix np.testing.assert_allclose(matrix, ham(t, 2))
def test_scheduling_optimization(method, options, messages, dense, filename): """Test optimization of s(t).""" from qibo.tests.test_models_variational import assert_regression_fixture h0 = hamiltonians.X(3, dense=dense) h1 = hamiltonians.TFIM(3, dense=dense) sp = lambda t, p: (1 - p) * np.sqrt(t) + p * t adevp = models.AdiabaticEvolution(h0, h1, sp, dt=1e-1) if method == "sgd": from qibo import K if not K.supports_gradients: with pytest.raises(RuntimeError): best, params, _ = adevp.minimize([0.5, 1], method=method, options=options, messages=messages) else: best, params, _ = adevp.minimize([0.5, 1], method=method, options=options, messages=messages) if filename is not None: assert_regression_fixture(params, filename)
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')