Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
Heisenberg_VQE.py
Go to the documentation of this file.
1 from scipy.stats import unitary_group
2 import numpy as np
3 from squander import Variational_Quantum_Eigensolver
4 from squander import utils as utils
5 import time
6 import sys
7 import scipy as sp
8 import pytest
9 from networkx.generators.random_graphs import random_regular_graph
10 from qiskit.quantum_info import SparsePauliOp
11 
12 np.set_printoptions(linewidth=200)
13 
14 import pickle
15 
16 
17 
18 topology = []
19 
21 
22  topology = [[0,1],[0,4],[0,8],
23  [1,2],[1,5],
24  [2,3],[2,4],
25  [3,6],[3,9],
26  [4,5],
27  [5,6],
28  [6,7],
29  [7,8],[7,9],
30  [8,9]]
31 
32  oplist = []
33  for i in topology:
34  oplist.append(("XX",[i[0],i[1]],1))
35  oplist.append(("YY",[i[0],i[1]],1))
36  oplist.append(("ZZ",[i[0],i[1]],1))
37  for i in range(n):
38  oplist.append(("Z",[i],1))
39  return SparsePauliOp.from_sparse_list(oplist,num_qubits=n).to_matrix(True)
40 
41 
42 
44  topology = random_regular_graph(3,n,seed=31415).edges
45  oplist = []
46  for i in topology:
47  oplist.append(("XX",[i[0],i[1]],1))
48  oplist.append(("YY",[i[0],i[1]],1))
49  oplist.append(("ZZ",[i[0],i[1]],1))
50  for i in range(n):
51  oplist.append(("Z",[i],1))
52  return SparsePauliOp.from_sparse_list(oplist,num_qubits=n).to_matrix(True)
53 
54 
55 
56 
57 
58 # The number of circuit layers
59 layers = 500
60 
61 # the number of subblocks in a single layer
62 inner_blocks = 1
63 
64 # The number of qubits
65 qbit_num = 16
66 
67 
68 
69 # generate the Hamiltonian
70 Hamiltonian = generate_hamiltonian_tmp( qbit_num )
71 
72 
73 # obtain the groud state energy of the Hamitonian
74 [eigvals, eigvecs] = sp.sparse.linalg.eigs( Hamiltonian, k=10, which='SR' )
75 eigval = np.real(eigvals[0])
76 eigvec = eigvecs[:,0]
77 
78 print( 'The target eigenvalue is: ', eigval )
79 
80 
81 # generate configuration dictionary for the solver
82 config = {"max_inner_iterations":800,
83  "batch_size": 128,
84  "convergence_length": 20}
85 
86 # initiate the VQE object with the Hamiltonian
87 VQE_Heisenberg = Variational_Quantum_Eigensolver(Hamiltonian, qbit_num, config, accelerator_num=1)
88 
89 # set the optimization engine to agents
90 VQE_Heisenberg.set_Optimizer("COSINE")
91 
92 # set the ansatz variant (U3 rotations and CNOT gates)
93 VQE_Heisenberg.set_Ansatz("HEA_ZYZ")
94 
95 # generate the circuit ansatz for the optimization
96 VQE_Heisenberg.Generate_Circuit( layers, inner_blocks)
97 
98 # create random initial parameters
99 param_num = VQE_Heisenberg.get_Parameter_Num()
100 print('The number of free parameters is: ', str(param_num) )
101 
102 
103 parameters = np.random.randn( param_num )*2*np.pi#np.zeros( (param_num,) )
104 parameters[0] = 1.2
105 VQE_Heisenberg.set_Optimized_Parameters(parameters)
106 
107 #VQE_Heisenberg.set_Initial_State( eigvec )
108 
109 
110 # calculate the entropy of the exact ground state
111 page_entropy = 2 * np.log(2.0) - 1.0/( pow(2, qbit_num-2*2+1) )
112 entropy_exact_gs = VQE_Heisenberg.get_Second_Renyi_Entropy( parameters=np.array([]), qubit_list=[0,1], input_state=eigvec )
113 normalized_entropy_exact_gs = entropy_exact_gs/page_entropy
114 print('The normalized entropy of the exact ground state evaluated on qubits 0 and 1 is:', normalized_entropy_exact_gs)
115 print(' ')
116 print(' ')
117 print(' ', flush=True)
118 
119 for iter_idx in range(400):
120 
121  # start an etap of the optimization (max_inner_iterations iterations)
122  VQE_Heisenberg.Start_Optimization()
123 
124  # retrieve the current parameter set
125  parameters = VQE_Heisenberg.get_Optimized_Parameters()
126 
127  # retrive the current VQE energy after max_inner_iterations iterations
128  VQE_energy = VQE_Heisenberg.Optimization_Problem( parameters )
129 
130  # calculate the Renyi entropy after max_inner_iterations iterations on the subsystem made of the 0-th and the 1st qubits
131  qubit_list = [0,1]
132 
133  page_entropy = len(qubit_list) * np.log(2.0) - 1.0/( pow(2, qbit_num-2*len(qubit_list)+1) )
134  entropy = VQE_Heisenberg.get_Second_Renyi_Entropy( parameters=parameters, qubit_list=qubit_list )
135  normalized_entropy = entropy/page_entropy
136 
137 
138  print('Current VQE energy: ', VQE_energy, ' normalized entropy: ', normalized_entropy)
139 
140  np.save( 'Heisenberg_VQE_data.npy', parameters, topology )
141 
142  initial_state = np.zeros( (1 << qbit_num), dtype=np.complex128 )
143  initial_state[0] = 1.0 + 0j
144 
145 
146  state_to_transform = initial_state.copy()
147  VQE_Heisenberg.apply_to( parameters, state_to_transform );
148 
149  overlap = state_to_transform.transpose().conjugate() @ eigvecs
150  overlap_norm = np.real(overlap * overlap.conjugate())
151 
152  for idx in range( overlap_norm.size) :
153  print('The overlap integral with the exact eigenstates of energy ', eigvals[idx], ' is: ', overlap_norm[idx] )
154 
155  print('The sum of the calculated overlaps: ', np.sum(overlap_norm ) )
156 
157 
158  if ( VQE_energy < 0.99*eigval):
159  break
160 
161 
def generate_hamiltonian(n)
def generate_hamiltonian_tmp(n)