def test_symbolic_hamiltonian_operator_add_and_sub(backend, nqubits, calcterms, calcdense): """Test addition and subtraction between Trotter Hamiltonians.""" local_ham1 = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=1.0)) local_ham2 = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=0.5)) if calcterms: _ = local_ham1.terms _ = local_ham2.terms if calcdense: _ = local_ham1.dense _ = local_ham2.dense local_ham = local_ham1 + local_ham2 target_ham = (hamiltonians.TFIM(nqubits, h=1.0) + hamiltonians.TFIM(nqubits, h=0.5)) dense = local_ham.dense K.assert_allclose(dense.matrix, target_ham.matrix) local_ham1 = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=1.0)) local_ham2 = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=0.5)) if calcterms: _ = local_ham1.terms _ = local_ham2.terms if calcdense: _ = local_ham1.dense _ = local_ham2.dense local_ham = local_ham1 - local_ham2 target_ham = (hamiltonians.TFIM(nqubits, h=1.0) - hamiltonians.TFIM(nqubits, h=0.5)) dense = local_ham.dense K.assert_allclose(dense.matrix, target_ham.matrix)
def test_trotter_hamiltonian_operation_errors(): """Test errors in ``SymbolicHamiltonian`` addition and subtraction.""" h1 = hamiltonians.SymbolicHamiltonian(symbolic_tfim(3, h=1.0)) h2 = hamiltonians.SymbolicHamiltonian(symbolic_tfim(4, h=1.0)) with pytest.raises(RuntimeError): h = h1 + h2 with pytest.raises(RuntimeError): h = h1 - h2 with pytest.raises(NotImplementedError): h = h1 + "test" with pytest.raises(NotImplementedError): h = "test" + h1 with pytest.raises(NotImplementedError): h = h1 - "test" with pytest.raises(NotImplementedError): h = "test" - h1 with pytest.raises(NotImplementedError): h = h1 * "test" with pytest.raises(NotImplementedError): h = h1 @ "test" with pytest.raises(NotImplementedError): h = h1 @ np.ones((2, 2, 2, 2)) h2 = hamiltonians.XXZ(3, dense=False) with pytest.raises(NotImplementedError): h = h1 @ h2
def test_trotter_hamiltonian_three_qubit_term(backend): """Test creating ``TrotterHamiltonian`` with three qubit term.""" from scipy.linalg import expm from qibo.core.terms import HamiltonianTerm m1 = random_hermitian(3) m2 = random_hermitian(2) m3 = random_hermitian(1) terms = [HamiltonianTerm(m1, 0, 1, 2), HamiltonianTerm(m2, 2, 3), HamiltonianTerm(m3, 1)] ham = hamiltonians.SymbolicHamiltonian() ham.terms = terms # Test that the `TrotterHamiltonian` dense matrix is correct eye = np.eye(2, dtype=m1.dtype) mm1 = np.kron(m1, eye) mm2 = np.kron(np.kron(eye, eye), m2) mm3 = np.kron(np.kron(eye, m3), np.kron(eye, eye)) target_ham = hamiltonians.Hamiltonian(4, mm1 + mm2 + mm3) K.assert_allclose(ham.matrix, target_ham.matrix) dt = 1e-2 initial_state = random_state(4) if K.op is not None: with pytest.raises(NotImplementedError): circuit = ham.circuit(dt=dt) else: circuit = ham.circuit(dt=dt) final_state = circuit(np.copy(initial_state)) u = [expm(-0.5j * dt * (mm1 + mm3)), expm(-0.5j * dt * mm2)] target_state = u[1].dot(u[0].dot(initial_state)) target_state = u[0].dot(u[1].dot(target_state)) K.assert_allclose(final_state, target_state)
def test_tfim_hamiltonian_from_symbols(nqubits, hamtype, calcterms): """Check creating TFIM Hamiltonian using sympy.""" if hamtype == "symbolic": from qibo.symbols import X, Z h = 0.5 symham = sum(Z(i) * Z(i + 1) for i in range(nqubits - 1)) symham += Z(0) * Z(nqubits - 1) symham += h * sum(X(i) for i in range(nqubits)) ham = hamiltonians.SymbolicHamiltonian(-symham) else: h = 0.5 z_symbols = sympy.symbols(" ".join((f"Z{i}" for i in range(nqubits)))) x_symbols = sympy.symbols(" ".join((f"X{i}" for i in range(nqubits)))) symham = sum(z_symbols[i] * z_symbols[i + 1] for i in range(nqubits - 1)) symham += z_symbols[0] * z_symbols[-1] symham += h * sum(x_symbols) symmap = {z: (i, matrices.Z) for i, z in enumerate(z_symbols)} symmap.update({x: (i, matrices.X) for i, x in enumerate(x_symbols)}) ham = hamiltonians.Hamiltonian.from_symbolic(-symham, symmap) if calcterms: _ = ham.terms final_matrix = ham.matrix target_matrix = hamiltonians.TFIM(nqubits, h=h).matrix K.assert_allclose(final_matrix, target_matrix)
def test_from_symbolic_with_power(hamtype, calcterms): """Check ``from_symbolic`` when the expression contains powers.""" if hamtype == "symbolic": from qibo.symbols import Symbol matrix = random_hermitian(1) symham = (Symbol(0, matrix) ** 2 - Symbol(1, matrix) ** 2 + 3 * Symbol(1, matrix) - 2 * Symbol(0, matrix) * Symbol(2, matrix) + 1) ham = hamiltonians.SymbolicHamiltonian(symham) else: z = sympy.symbols(" ".join((f"Z{i}" for i in range(3)))) symham = z[0] ** 2 - z[1] ** 2 + 3 * z[1] - 2 * z[0] * z[2] + 1 matrix = random_hermitian(1) symmap = {x: (i, matrix) for i, x in enumerate(z)} ham = hamiltonians.Hamiltonian.from_symbolic(symham, symmap) if calcterms: _ = ham.terms final_matrix = ham.matrix matrix2 = matrix.dot(matrix) eye = np.eye(2, dtype=matrix.dtype) target_matrix = np.kron(np.kron(matrix2, eye), eye) target_matrix -= np.kron(np.kron(eye, matrix2), eye) target_matrix += 3 * np.kron(np.kron(eye, matrix), eye) target_matrix -= 2 * np.kron(np.kron(matrix, eye), matrix) target_matrix += np.eye(8, dtype=matrix.dtype) K.assert_allclose(final_matrix, target_matrix)
def test_symbolic_hamiltonian_hamiltonianmatmul(backend, nqubits, calcterms, calcdense): local_ham1 = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=1.0)) local_ham2 = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=0.5)) dense_ham1 = hamiltonians.TFIM(nqubits, h=1.0) dense_ham2 = hamiltonians.TFIM(nqubits, h=0.5) if calcterms: _ = local_ham1.terms _ = local_ham2.terms if calcdense: _ = local_ham1.dense _ = local_ham2.dense local_matmul = local_ham1 @ local_ham2 target_matmul = dense_ham1 @ dense_ham2 K.assert_allclose(local_matmul.matrix, target_matmul.matrix)
def test_symbolic_hamiltonian_errors(): # Wrong type of Symbol matrix from qibo.symbols import Symbol with pytest.raises(TypeError): s = Symbol(0, "test") # Wrong type of symbolic expression with pytest.raises(TypeError): ham = hamiltonians.SymbolicHamiltonian("test") # Passing form with symbol that is not in ``symbol_map`` from qibo import matrices Z, X = sympy.Symbol("Z"), sympy.Symbol("X") symbol_map = {Z: (0, matrices.Z)} with pytest.raises(ValueError): ham = hamiltonians.SymbolicHamiltonian(Z * X, symbol_map) # Invalid operation in Hamiltonian expresion ham = hamiltonians.SymbolicHamiltonian(sympy.cos(Z), symbol_map) with pytest.raises(TypeError): dense = ham.dense
def test_symbolic_hamiltonian_scalar_add(backend, nqubits, calcterms, calcdense): """Test addition of Trotter Hamiltonian with scalar.""" local_ham = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=1.0)) target_ham = 2 + hamiltonians.TFIM(nqubits, h=1.0) if calcterms: _ = local_ham.terms if calcdense: _ = local_ham.dense local_dense = (2 + local_ham).dense K.assert_allclose(local_dense.matrix, target_ham.matrix) local_ham = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=1.0)) if calcterms: _ = local_ham.terms if calcdense: _ = local_ham.dense local_dense = (local_ham + 2).dense K.assert_allclose(local_dense.matrix, target_ham.matrix)
def test_symbolicxxz_hamiltonian_to_dense(backend, nqubits, calcterms): from qibo.symbols import X, Y, Z sham = sum(X(i) * X(i + 1) for i in range(nqubits - 1)) sham += sum(Y(i) * Y(i + 1) for i in range(nqubits - 1)) sham += 0.5 * sum(Z(i) * Z(i + 1) for i in range(nqubits - 1)) sham += X(0) * X(nqubits - 1) + Y(0) * Y(nqubits - 1) + 0.5 * Z(0) * Z(nqubits - 1) final_ham = hamiltonians.SymbolicHamiltonian(sham) target_ham = hamiltonians.XXZ(nqubits) if calcterms: _ = final_ham.terms K.assert_allclose(final_ham.matrix, target_ham.matrix, atol=1e-15)
def test_from_symbolic_application_hamiltonian(calcterms): """Check ``from_symbolic`` for a specific four-qubit Hamiltonian.""" z1, z2, z3, z4 = sympy.symbols("z1 z2 z3 z4") symmap = {z: (i, matrices.Z) for i, z in enumerate([z1, z2, z3, z4])} symham = (z1 * z2 - 0.5 * z1 * z3 + 2 * z2 * z3 + 0.35 * z2 + 0.25 * z3 * z4 + 0.5 * z3 + z4 - z1) # Check that Trotter dense matrix agrees will full Hamiltonian matrix fham = hamiltonians.Hamiltonian.from_symbolic(symham, symmap) from qibo.symbols import Z symham = (Z(0) * Z(1) - 0.5 * Z(0) * Z(2) + 2 * Z(1) * Z(2) + 0.35 * Z(1) + 0.25 * Z(2) * Z(3) + 0.5 * Z(2) + Z(3) - Z(0)) sham = hamiltonians.SymbolicHamiltonian(symham) if calcterms: _ = sham.terms K.assert_allclose(sham.matrix, fham.matrix)
def test_symbolic_hamiltonian_abstract_symbol_ev(backend, density_matrix, calcterms): from qibo.symbols import X, Symbol matrix = np.random.random((2, 2)) form = X(0) * Symbol(1, matrix) + Symbol(0, matrix) * X(1) local_ham = hamiltonians.SymbolicHamiltonian(form) if calcterms: _ = local_ham.terms if density_matrix: state = K.cast(random_complex((4, 4))) else: state = K.cast(random_complex((4, ))) local_ev = local_ham.expectation(state) target_ev = local_ham.dense.expectation(state) K.assert_allclose(local_ev, target_ev)
def test_hamiltonian_with_identity_symbol(calcterms): """Check creating Hamiltonian from expression which contains the identity symbol.""" from qibo.symbols import I, X, Y, Z symham = X(0) * I(1) * Z(2) + 0.5 * Y(0) * Z(1) * I(3) + Z(0) * I(1) * X(2) ham = hamiltonians.SymbolicHamiltonian(symham) if calcterms: _ = ham.terms final_matrix = ham.matrix target_matrix = np.kron(np.kron(matrices.X, matrices.I), np.kron(matrices.Z, matrices.I)) target_matrix += 0.5 * np.kron(np.kron(matrices.Y, matrices.Z), np.kron(matrices.I, matrices.I)) target_matrix += np.kron(np.kron(matrices.Z, matrices.I), np.kron(matrices.X, matrices.I)) K.assert_allclose(final_matrix, target_matrix)
def test_x_hamiltonian_from_symbols(nqubits, hamtype, calcterms): """Check creating sum(X) Hamiltonian using sympy.""" if hamtype == "symbolic": from qibo.symbols import X symham = -sum(X(i) for i in range(nqubits)) ham = hamiltonians.SymbolicHamiltonian(symham) else: x_symbols = sympy.symbols(" ".join((f"X{i}" for i in range(nqubits)))) symham = -sum(x_symbols) symmap = {x: (i, matrices.X) for i, x in enumerate(x_symbols)} ham = hamiltonians.Hamiltonian.from_symbolic(symham, symmap) if calcterms: _ = ham.terms final_matrix = ham.matrix target_matrix = hamiltonians.X(nqubits).matrix K.assert_allclose(final_matrix, target_matrix)
def test_symbolic_hamiltonian_matmul(backend, nqubits, density_matrix, calcterms): if density_matrix: from qibo.core.states import MatrixState shape = (2**nqubits, 2**nqubits) state = MatrixState.from_tensor(random_complex(shape)) else: from qibo.core.states import VectorState shape = (2**nqubits, ) state = VectorState.from_tensor(random_complex(shape)) local_ham = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=1.0)) dense_ham = hamiltonians.TFIM(nqubits, h=1.0) if calcterms: _ = local_ham.terms local_matmul = local_ham @ state target_matmul = dense_ham @ state K.assert_allclose(local_matmul, target_matmul)
def test_symbolic_hamiltonian_state_ev(backend, nqubits, normalize, calcterms, calcdense): local_ham = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=1.0)) + 2 if calcterms: _ = local_ham.terms if calcdense: _ = local_ham.dense dense_ham = hamiltonians.TFIM(nqubits, h=1.0) + 2 state = K.cast(random_complex((2**nqubits, ))) local_ev = local_ham.expectation(state, normalize) target_ev = dense_ham.expectation(state, normalize) K.assert_allclose(local_ev, target_ev) state = random_complex((2**nqubits, )) local_ev = local_ham.expectation(state, normalize) target_ev = dense_ham.expectation(state, normalize) K.assert_allclose(local_ev, target_ev)
def test_three_qubit_term_hamiltonian_from_symbols(hamtype, calcterms): """Check creating Hamiltonian with three-qubit interaction using sympy.""" if hamtype == "symbolic": from qibo.symbols import X, Y, Z symham = X(0) * Y(1) * Z(2) + 0.5 * Y(0) * Z(1) * X(3) + Z(0) * X(2) symham += Y(2) + 1.5 * Z(1) - 2 - 3 * X(1) * Y(3) ham = hamiltonians.SymbolicHamiltonian(symham) else: x_symbols = sympy.symbols(" ".join((f"X{i}" for i in range(4)))) y_symbols = sympy.symbols(" ".join((f"Y{i}" for i in range(4)))) z_symbols = sympy.symbols(" ".join((f"Z{i}" for i in range(4)))) symmap = {x: (i, matrices.X) for i, x in enumerate(x_symbols)} symmap.update({x: (i, matrices.Y) for i, x in enumerate(y_symbols)}) symmap.update({x: (i, matrices.Z) for i, x in enumerate(z_symbols)}) symham = x_symbols[0] * y_symbols[1] * z_symbols[2] symham += 0.5 * y_symbols[0] * z_symbols[1] * x_symbols[3] symham += z_symbols[0] * x_symbols[2] symham += -3 * x_symbols[1] * y_symbols[3] symham += y_symbols[2] symham += 1.5 * z_symbols[1] symham -= 2 ham = hamiltonians.Hamiltonian.from_symbolic(symham, symmap) if calcterms: _ = ham.terms final_matrix = ham.matrix target_matrix = np.kron(np.kron(matrices.X, matrices.Y), np.kron(matrices.Z, matrices.I)) target_matrix += 0.5 * np.kron(np.kron(matrices.Y, matrices.Z), np.kron(matrices.I, matrices.X)) target_matrix += np.kron(np.kron(matrices.Z, matrices.I), np.kron(matrices.X, matrices.I)) target_matrix += -3 * np.kron(np.kron(matrices.I, matrices.X), np.kron(matrices.I, matrices.Y)) target_matrix += np.kron(np.kron(matrices.I, matrices.I), np.kron(matrices.Y, matrices.I)) target_matrix += 1.5 * np.kron(np.kron(matrices.I, matrices.Z), np.kron(matrices.I, matrices.I)) target_matrix -= 2 * np.eye(2**4, dtype=target_matrix.dtype) K.assert_allclose(final_matrix, target_matrix)
def test_from_symbolic_with_complex_numbers(hamtype, calcterms): """Check ``from_symbolic`` when the expression contains imaginary unit.""" if hamtype == "symbolic": from qibo.symbols import X, Y symham = (1 + 2j) * X(0) * X(1) + 2 * Y(0) * Y(1) - 3j * X(0) * Y(1) + 1j * Y(0) * X(1) ham = hamiltonians.SymbolicHamiltonian(symham) else: x = sympy.symbols(" ".join((f"X{i}" for i in range(2)))) y = sympy.symbols(" ".join((f"Y{i}" for i in range(2)))) symham = (1 + 2j) * x[0] * x[1] + 2 * y[0] * y[1] - 3j * x[0] * y[1] + 1j * y[0] * x[1] symmap = {s: (i, matrices.X) for i, s in enumerate(x)} symmap.update({s: (i, matrices.Y) for i, s in enumerate(y)}) ham = hamiltonians.Hamiltonian.from_symbolic(symham, symmap) if calcterms: _ = ham.terms final_matrix = ham.matrix target_matrix = (1 + 2j) * np.kron(matrices.X, matrices.X) target_matrix += 2 * np.kron(matrices.Y, matrices.Y) target_matrix -= 3j * np.kron(matrices.X, matrices.Y) target_matrix += 1j * np.kron(matrices.Y, matrices.X) K.assert_allclose(final_matrix, target_matrix)
def main(nqubits, instance, T, dt, solver, plot, dense, 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. dense (bool): decides if the full Hamiltonian matrix 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 = functions.h_initial(nqubits, times) sh1 = functions.h_problem(nqubits, clauses) gs = lambda: functions.ground_state(nqubits) H0 = hamiltonians.SymbolicHamiltonian(sh0, ground_state=gs) H1 = hamiltonians.SymbolicHamiltonian(sh1) if dense: print('Using the full Hamiltonian evolution\n') H0, H1 = H0.dense, H1.dense else: print('Using Trotter decomposition for the Hamiltonian\n') 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(K.to_numpy(final_state))**2).argmax() max_output = "{0:0{bits}b}".format(output_dec, bits=nqubits) max_prob = (np.abs(K.to_numpy(final_state))**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')
def test_symbolictfim_hamiltonian_to_dense(backend, nqubits, calcterms): final_ham = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=1)) target_ham = hamiltonians.TFIM(nqubits, h=1) if calcterms: _ = final_ham.terms K.assert_allclose(final_ham.matrix, target_ham.matrix, atol=1e-15)