def optimize(alpha, beta): """Define a function that optimizes theta_A0, theta_A1, theta_B0, theta_B1 to maximize the probability of winning the game Args: - alpha (float): real coefficient of |00> - beta (float): real coefficient of |11> Returns: - (float): Probability of winning """ def cost(params): """Define a cost function that only depends on params, given alpha and beta fixed""" return -winning_prob(params, alpha, beta) # QHACK # #Initialize parameters, choose an optimization method and number of steps init_params = np.ones(4) opt = qml.AdagradOptimizer() steps = 2000 # QHACK # # set the initial parameter values params = init_params for i in range(steps): # update the circuit parameters # QHACK # params = opt.step(cost, params) # QHACK # return winning_prob(params, alpha, beta)
def run_vqe(H): """Runs the variational quantum eigensolver on the problem Hamiltonian using the variational ansatz specified above. Fill in the missing parts between the # QHACK # markers below to run the VQE. Args: H (qml.Hamiltonian): The input Hamiltonian Returns: The ground state energy of the Hamiltonian. """ # Initialize parameters num_qubits = len(H.wires) num_param_sets = (2 ** num_qubits) - 1 params = np.random.uniform(low=-np.pi / 2, high=np.pi / 2, size=(num_param_sets, 3)) energy = 0 # QHACK # # Create a quantum device, set up a cost funtion and optimizer, and run the VQE. # (We recommend ~500 iterations to ensure convergence for this problem, # or you can design your own convergence criteria) dev = qml.device('default.qubit', wires=num_qubits) cost_fn = qml.ExpvalCost(variational_ansatz, H, dev) opt = qml.AdagradOptimizer(0.2) max_iterations = 500 conv_tol = 1e-06 for n in range(max_iterations): params, prev_energy = opt.step_and_cost(cost_fn, params) energy = cost_fn(params) conv = np.abs(energy - prev_energy) if n % 20 == 0: print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, energy)) if conv <= conv_tol: break # QHACK # # Return the ground state energy return energy
def optimize_ada(init_params): ada = qml.AdagradOptimizer(0.4) var = init_params var_ada = [var] for it in range(100): var = ada.step(cost, var) if (it + 1) % 5 == 0: var_ada.append(var) print('Objective after step {:5d}: {: .7f} | Angles: {}'.format( it + 1, cost(var), var)) print('Optimized rotation angles: {}, {}'.format(var, cost(var))) return var_ada
def optimize_circuit(params): """Minimize the variational circuit and return its minimum value. The code you write for this challenge should be completely contained within this function between the # QHACK # comment markers. You should create a device and convert the variational_circuit function into an executable QNode. Next, you should minimize the variational circuit using gradient-based optimization to update the input params. Return the optimized value of the QNode as a single floating-point number. Args: params (np.ndarray): Input parameters to be optimized, of dimension 30 Returns: float: the value of the optimized QNode """ optimal_value = 0.0 # QHACK # # Initialize the device dev = qml.device("default.qubit", wires=2) # Instantiate the QNode circuit = qml.QNode(variational_circuit, dev) # Minimize the circuit opt = qml.AdagradOptimizer(stepsize=0.4) max_iterations = 500 conv_tol = 1e-6 for n in range(max_iterations): params, prev_optimal_value = opt.step_and_cost(circuit, params) optimal_value = circuit(params) conv = np.abs(optimal_value - prev_optimal_value) # if n % 20 == 0: # print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, optimal_value)) if conv <= conv_tol: break # QHACK # # Return the value of the minimized QNode return optimal_value
def run_vqe(H): """Runs the variational quantum eigensolver on the problem Hamiltonian using the variational ansatz specified above. Fill in the missing parts between the # QHACK # markers below to run the VQE. Args: H (qml.Hamiltonian): The input Hamiltonian Returns: The ground state energy of the Hamiltonian. """ energy = 0 # QHACK # num_qubits = len(H.wires) num_params = num_qubits - 1 # Initialize the quantum device dev = qml.device("default.qubit", wires=num_qubits) # Randomly choose initial parameters (how many do you need?) params = np.random.uniform(low=-np.pi / 2, high=np.pi / 2, size=num_params) # Set up a cost function cost_fn = qml.ExpvalCost(variational_ansatz, H, dev) # Set up an optimizer opt = qml.AdagradOptimizer(stepsize=0.4) # Run the VQE by iterating over many steps of the optimizer max_iterations = 500 conv_tol = 1e-6 for n in range(max_iterations): params, prev_energy = opt.step_and_cost(cost_fn, params) energy = cost_fn(params) conv = np.abs(energy - prev_energy) # if n % 20 == 0: # print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, energy)) if conv <= conv_tol: break # QHACK # # Return the ground state energy return energy
def qaoa_maxcut(n_layers=1): print("\np={:d}".format(n_layers)) # initialize the parameters near zero init_params = 0.01 * np.random.rand(2, 2) # minimize the negative of the objective function def objective(params): gammas = params[0] betas = params[1] neg_obj = 0 for edge in graph: # objective for the MaxCut problem neg_obj -= 0.5 * ( 1 - circuit(gammas, betas, edge=edge, n_layers=n_layers)) return neg_obj # initialize optimizer: Adagrad works well empirically opt = qml.AdagradOptimizer(stepsize=0.5) # optimize parameters in objective params = init_params steps = 30 for i in range(steps): params = opt.step(objective, params) if (i + 1) % 5 == 0: print("Objective after step {:5d}: {: .7f}".format( i + 1, -objective(params))) # sample measured bitstrings 100 times bit_strings = [] n_samples = 100 for i in range(0, n_samples): bit_strings.append( int(circuit(params[0], params[1], edge=None, n_layers=n_layers))) # print optimal parameters and most frequently sampled bitstring counts = np.bincount(np.array(bit_strings)) most_freq_bit_string = np.argmax(counts) print("Optimized (gamma, beta) vectors:\n{}".format(params[:, :n_layers])) print("Most frequently sampled bit string is: {:04b}".format( most_freq_bit_string)) return -objective(params), bit_strings
def run_vqe(H, ansatz, params=None, gs_params=None): num_qubits = len(H.wires) num_param_sets = (2 ** num_qubits) - 1 if params is None: params = np.random.uniform(low=-np.pi / 2, high=np.pi / 2, size=(num_param_sets, 3)) H_cost_fn = qml.ExpvalCost(ansatz, H, dev) cost_fn = H_cost_fn if gs_params is not None: @qml.qnode(dev) def overlap(params, wires): variational_ansatz(gs_params, wires) qml.inv(qml.template(variational_ansatz)(params, wires)) # obs = qml.expval(qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliZ(2)) return qml.probs([0, 1, 2]) cost_fn = lambda p: H_cost_fn(p) + overlap(p, gs_params)[0] opt = qml.AdagradOptimizer(stepsize=0.4) max_iterations = 500 conv_tol = 1e-6 energy = 0 for n in range(max_iterations): params, prev_energy = opt.step_and_cost(cost_fn, params) energy = cost_fn(params) conv = np.abs(energy - prev_energy) if n % 20 == 0: print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, energy)) if conv <= conv_tol: break return energy, params
cost_fn = qml.ExpvalCost(ansatz, H, dev, optimize=True) num_params_per_gate = 15 # The number of parameters in each two-qubit gate. depth = int(np.floor(np.log2(num_qubits))) # The depth of the TTN. num_gates = num_qubits - 1 # The number of two-qubit gates in the TTN. if fix_layers: num_params = num_params_per_gate * depth else: num_params = num_params_per_gate * num_gates # The total number of parameters in the TTN. # Initialize the parameters. np.random.seed(1) params = np.pi*(np.random.rand(num_params) - 1.0) # Perform VQE. opt = qml.AdagradOptimizer(stepsize=0.2) # The optimizer to use. # Optimizer parameters. rtol = 1e-5 atol = 1e-9 maxiter = 100 print_results = True prev_obj = 0.0 for step in range(maxiter): params, obj = opt.step_and_cost(cost_fn, params) diff_obj = np.abs(prev_obj - obj) rel_obj = diff_obj/np.abs(prev_obj + 1e-15) prev_obj = obj
############################################################################## # We are now ready to perform the optimization. We will initialize the weights # at random. Then we make use of the `Adagrad <https://pennylane.readthedocs.io/en/stable/introduction/optimizers.html>`_ # optimizer. Adaptive gradient descent methods are advantageous as the optimization # of quantum sensing protocols is very sensitive to the step size. def opt_cost(weights, phi=phi, gamma=gamma, J=J, W=W): return cost(weights, phi, gamma, J, W) # Seed for reproducible results np.random.seed(395) weights = np.random.uniform(0, 2 * np.pi, NUM_ANSATZ_PARAMETERS + NUM_MEASUREMENT_PARAMETERS) opt = qml.AdagradOptimizer(stepsize=0.1) print("Initialization: Cost = {:6.4f}".format(opt_cost(weights))) for i in range(20): weights, cost_ = opt.step_and_cost(opt_cost, weights) if (i + 1) % 5 == 0: print("Iteration {:>4}: Cost = {:6.4f}".format(i + 1, cost_)) ############################################################################## # Comparison with the standard protocol # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Now we want to see how our protocol compares to the standard Ramsey interferometry protocol. # The probe state in this case is a tensor product of three separate :math:`|+\rangle` states # while the encoded state is measured in the :math:`|+\rangle / |-\rangle` basis.
ansatz = ansatz_f else: raise NotImplementedError("Not found initial state!") # The circuit for computing the expectation value of H. cost_fn = qml.ExpvalCost(ansatz, H, dev, optimize=True) print(f"Total # of Parameters={num_params}") # Perform VQE. step_size = args.step if args.opt == "qng": opt = qml.QNGOptimizer(stepsize=step_size, diag_approx=True, lam=0.1) elif args.opt == "adagrad": opt = qml.AdagradOptimizer(stepsize=step_size) elif args.opt == "adam": opt = qml.AdamOptimizer(stepsize=step_size) else: raise NotImplementedError("Optimizer not found") # Initialize the parameters. np.random.seed(1) if args.randomize == 1: params = np.pi * (np.random.rand(num_params) - 1.0) elif args.randomize == 2: params = np.loadtxt( f"params_{args.ansatz}_{args.two_qubit}_{num_qubits}_{h}_{args.opt}_{step_size}_{initState}{1}.txt" ) print(len(params), num_params) assert len(params) == num_params else:
def qft_U_loss(thetas): print(thetas[0].val if type(thetas[0]) is Variable else thetas[0]) loss = 0 for i in range(2**n_qubits): input_state_vector = I16[i] exp_output_eigenvalues = basisvector2eigenvalues(input_state_vector) output_eigenvalues = qft_U_iqft(thetas, input_state=input_state_vector) # Calculate loss as the sum of the squared diff. btw. eigenvalues of expected output and actual (PauliZ) loss += np.sum((np.array(exp_output_eigenvalues) - np.array(output_eigenvalues))**2) return loss # Actual optimazation opt = qml.AdagradOptimizer() # Init parameters in the U-gates rng_seed = 0 np.random.seed(rng_seed) # thetas = 2*π * np.random.randn(6) thetas = np.array([π, π, π, π, π, π]) # Test run the loss function print('Loss test:', qft_U_loss(thetas), qft_U_loss(thetas * 0.2)) # Perform optimazation cost_history = [] steps = 10 for it in range(steps): thetas = opt.step(qft_U_loss, thetas)
np.random.seed(1) params0 = np.pi*(np.random.rand(num_params) - 1.0) # Optimizer parameters. rtol = 1e-5 atol = 1e-9 maxiter = 50 stepsize = 0.05 print_results = True # The different optimizers to test. opt_names = ["QNG", "Grad", "AdaGrad", "Adam"] opts = [qml.QNGOptimizer(stepsize=stepsize, diag_approx=True, lam=0.1), qml.GradientDescentOptimizer(stepsize=stepsize), qml.AdagradOptimizer(stepsize=stepsize), qml.AdamOptimizer(stepsize=stepsize)] # Perform VQE. times_opts = [] objs_opts = [] for (opt, opt_name) in zip(opts, opt_names): times = [] objs = [] print(f"OPTIMIZER {opt_name}") params = np.copy(params0) prev_obj = 0.0 for step in range(maxiter): start = time.time() params, obj = opt.step_and_cost(cost_fn, params)
def run_vqe(H): """Runs the variational quantum eigensolver on the problem Hamiltonian using the variational ansatz specified above. Fill in the missing parts between the # QHACK # markers below to run the VQE. Args: H (qml.Hamiltonian): The input Hamiltonian Returns: The ground state energy of the Hamiltonian. """ energy = 0 # QHACK # size = (2**(len(H.wires) + 1) - 2, ) #len(H.wires),3) dev = qml.device('default.qubit', wires=len(H.wires)) # Initialize the quantum device np.random.seed(0) #params = np.random.uniform(low=-np.pi / 2, high=np.pi , size=size) params = np.random.normal(0.001, 0.01, size) #params = np.random.normal(0.01, np.pi, size) # Randomly choose initial parameters (how many do you need?) cost_fn = qml.ExpvalCost(variational_ansatz, H, dev, optimize=True) # Set up a cost function #opt = qml.GradientDescentOptimizer(stepsize=0.01) opt = qml.AdagradOptimizer(stepsize=0.2) # Set up an optimizer # max_iterations=500 #previous = 0 #for i in range(500): #index = 0 while True: #previous = energy params = opt.step(cost_fn, params) if time.time() - start_time > 55: break #if index % 25 == 0: #if round(energy, 7) == round(previous, 7): # break #print(energy) #print(i) #index += 1 energy = cost_fn(params) '''n=0 while True: params = opt.step(cost_fn, params) prev = float(energy) energy = cost_fn(params) #if n%20==0: # print(energy) if round(float(energy), 8) == round(prev, 8) or n == 500: break n+=1''' # conv_tol = 1e-06 # print(params) # for n in range(max_iterations): # params, prev_energy = opt.step_and_cost(cost_fn, params) # energy = cost_fn(params) # conv = np.abs(energy - prev_energy) # if n % 20 == 0: # print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, energy)) # if conv <= conv_tol: # break # Run the VQE by iterating over many steps of the optimizer # QHACK # return energy
def find_excited_states(H): """ Fill in the missing parts between the # QHACK # markers below. Implement a variational method that can find the three lowest energies of the provided Hamiltonian. Args: H (qml.Hamiltonian): The input Hamiltonian Returns: The lowest three eigenenergies of the Hamiltonian as a comma-separated string, sorted from smallest to largest. """ energies = np.zeros(3) # QHACK # np.random.seed(52) def variational_ansatz(params, wires): for k in range(len(params)): for i in range(len(params[k])): qml.Rot(params[k][i][0], params[k][i][1], params[k][i][2], wires=i) for i in range(len(params[k]) - 1): qml.CNOT(wires=[i, i + 1]) qml.CNOT(wires=[len(wires) - 1, 0]) def variational_ansatz1(params, wires): qml.PauliX(wires=1) for k in range(len(params)): for i in range(len(params[k])): qml.Rot(params[k][i][0], params[k][i][1], params[k][i][2], wires=i) for i in range(len(params[k]) - 1): qml.CNOT(wires=[i, i + 1]) qml.CNOT(wires=[len(wires) - 1, 0]) def variational_ansatz2(params, wires): qml.PauliX(wires=0) for k in range(len(params)): for i in range(len(params[k])): qml.Rot(params[k][i][0], params[k][i][1], params[k][i][2], wires=i) for i in range(len(params[k]) - 1): qml.CNOT(wires=[i, i + 1]) qml.CNOT(wires=[len(wires) - 1, 0]) num_qubits = len(H.wires) energy = 0 opt = qml.AdagradOptimizer(0.2) max_iterations = 500 conv_tol = 1e-04 dev = qml.device('default.qubit', wires=num_qubits) dev1 = qml.device('default.qubit', wires=num_qubits) dev2 = qml.device('default.qubit', wires=num_qubits) cost_fn = qml.ExpvalCost(variational_ansatz, H, dev) cost_fn1 = qml.ExpvalCost(variational_ansatz1, H, dev1) cost_fn2 = qml.ExpvalCost(variational_ansatz2, H, dev2) def cost(params): return 0.55 * cost_fn2(params) + 0.65 * cost_fn1(params) + cost_fn( params) prev_energy = 100 params = np.random.uniform(low=-np.pi / 2, high=np.pi / 2, size=(6, num_qubits, 3)) for n in range(max_iterations): params, c = opt.step_and_cost(cost, params) energy = cost(params) conv = np.abs(energy - prev_energy) prev_energy = energy #if n % 20 == 0: # print(energy) # print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, cost_fn(params))) # print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, cost_fn1(params))) # print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, cost_fn2(params))) if conv <= conv_tol: break energies[0] = cost_fn(params) energies[1] = cost_fn1(params) energies[2] = cost_fn2(params) # QHACK # return ",".join([str(E) for E in energies])
from cost_functions import m_vqe_cost, ExpvalH from Ansatz import variational_ansatz from hamiltonians import hamiltonian_XXZ # Creating training data train_deltas = np.random.uniform(low=-1.1, high=1.1, size=5) # Hyperparameters eta = 0.75 n_layers = 2 # One encoding and one processing L = 2 * n_layers # Training Parameters epochs = 50 optimizer = qml.AdagradOptimizer() samples = 100 qubits = [2, 3, 4, 5] var = [] mean = [] for n_qubits in qubits: dev = qml.device("default.qubit", wires=n_qubits) v_gradient = [] for _ in tqdm(range(samples)): # Applyies train_deltas for the Meta-VQE cost function
def find_excited_states(H): """ Fill in the missing parts between the # QHACK # markers below. Implement a variational method that can find the three lowest energies of the provided Hamiltonian. Args: H (qml.Hamiltonian): The input Hamiltonian Returns: The lowest three eigenenergies of the Hamiltonian as a comma-separated string, sorted from smallest to largest. """ energies = np.zeros(3) # QHACK # s_wires = [[0, 1, 2], [1, 2, 3]] d_wires = [[[0, 1], [2, 3]]] hfstate = [1, 1, 0, 0] dev = qml.device("default.qubit", wires=len(H.wires)) #def new_ansatz(params, wires): # qml.templates.UCCSD(weights=params,wires=H.wires,s_wires=s_wires,d_wires=d_wires,init_state=hfstate) def ansatz(params, wires): qml.templates.state_preparations.ArbitraryStatePreparation(params, wires=wires) cost_fn = qml.ExpvalCost(ansatz, H, dev, optimize=True) #opt = qml.GradientDescentOptimizer(stepsize=0.1) opt = qml.AdagradOptimizer(stepsize=0.4) # opt = qml.optimize.QNGOptimizer(stepsize=0.1) np.random.seed(0) # for reproducibility size = (2**(len(H.wires) + 1) - 2, ) #len(H.wires),3) #params = np.random.normal(0, np.pi, len(singles) + len(doubles)) params = np.random.normal(0.001, 0.01, size=size) print(params) max_iterations = 140 # conv_tol = 1e-06 # index=0 energy = 0 for n in range(max_iterations): params, prev_energy = opt.step_and_cost(cost_fn, params) energy = cost_fn(params) conv = np.abs(energy - prev_energy) if n % 20 == 0: print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, energy)) if float(energy) == float(prev_energy) or n == 100: break gs = energy excited_f_state = (np.linalg.multi_dot(gs, qml.Hamiltonian, gs)) / np.vdot(gs, gs) excited_s_state = (np.linalg.multi_dot( excited_f_state, qml.Hamiltonian, excited_f_state)) / np.vdot( excited_f_state, excited_f_state)