Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternative initial QAOA state. #16

Open
bgard1 opened this issue Dec 18, 2020 · 4 comments
Open

Alternative initial QAOA state. #16

bgard1 opened this issue Dec 18, 2020 · 4 comments

Comments

@bgard1
Copy link

bgard1 commented Dec 18, 2020

In place of the standard all |+> state (created by layer_of_Hadamards), one may also want to supply a different initial state. Similar in structure, I am interested in creating separable state, given by the code below.

def warm_start(self, G):
        X_rotations = [ self.solution[i][1] for i in range(len(self.solution)) ]
        Z_rotations = [ self.solution[i][0] for i in range(len(self.solution)) ]
        for (q,Xrot,Zrot) in zip(self.qubits, X_rotations, Z_rotations):
            self.apply_gate(self.operators.rx, [Xrot], q)
            self.apply_gate(self.operators.rz, [Zrot+np.pi/2], q) 

This is contained within CircuitComposer and is called the same way as layer_of_Hadamards. In this definitions case, 'solution' is supplied as a list in the form of [ [z_1,x_1],[z_2,_x_2]... ] to WeightedQAOASimulator. However, when using this initial state, the resulting energy of this initial state is not as expected. In this case I am using WeightedQAOASimulator but this particular example is an unweighted graph. Additionally, for the "standard" initial state, all cases match within numerical precision, so it's likely some issue with this different initial state.

For an example:

Qtensor Energy

rotated =[[4.872435284588963, 3.140924329249939],
 [6.2089546789130585, 0.0],
 [0.44075316687891064, 1.0512066194209708],
 [3.581626554108839, 1.046481705810185],
 [3.580582956190857, 2.0938670181912022],
 [0.441558317709732, 2.098012455304285]]
qt_sim=WeightedQAOASimulator(WeightedQAOAComposer,solution=rotated)
qt_sim.energy_expectation(G, gamma=[0], beta=[0])[0] 

This returns an energy of 5.624767271462993

Qiskit and Cirq

from qiskit.circuit import QuantumCircuit
from qiskit import execute
from qiskit import Aer
from qiskit.optimization.ising import max_cut, tsp,common
import cirq

##Cirq construction
X_rotations = [ rotated[i][1] for i in range(len(rotated)) ]
Z_rotations = [ rotated[i][0] for i in range(len(rotated)) ]
cirq1=cirq.Circuit()

for (q,Xrot,Zrot) in zip(cirq.LineQubit.range(len(rotated)),X_rotations,Z_rotations): 
    cirq1.append(cirq.rx(Xrot).on(q))
    cirq1.append(cirq.rz(Zrot+np.pi/2).on(q))
s=cirq.Simulator()
sim=s.simulate(cirq1)

##Qiskit construction
circuit = QuantumCircuit(G.number_of_nodes())
for (q,Xrot,Zrot) in zip(range(G.number_of_nodes()-1,-1,-1),X_rotations,Z_rotations): 
    circuit.rx(Xrot,q)
    circuit.rz(Zrot+np.pi/2,q)
ex1 = execute(circuit,backend=Aer.get_backend("statevector_simulator")).result()
warm_state = ex1.get_statevector()
w = np.zeros([n,n])
for i in range(n):
    for j in range(n):
        temp = G.get_edge_data(i,j,default=0)
        if temp != 0:
            w[i,j] = temp['weight'] 
qubitOp, offset = max_cut.get_operator(w)
print(-(qubitOp.evaluate_with_statevector(warm_state)[0].real+offset))
print(-(qubitOp.evaluate_with_statevector(sim.final_state_vector)[0].real+offset))

Both qiskit and cirq in this case return an energy of ~4.998846035923315 . Note that the qiskit circuit is "flipped" since qiskit defines the ordering of qubits differently than cirq.

@danlkv
Copy link
Owner

danlkv commented Dec 18, 2020

Hi, thanks for submitting the issue
The code for warm_start looks good, but did you check it actually changes anything? The solution=rotated will not end up in the constructor of the composer, see here: https://github.com/danlkv/QTensor/blob/dev/qtensor/QAOASimulator.py#L21 I'll try to add support for custom arguments in composer. Before that, you can just use something like

zz_exp = 0
for edge in G.edges:
    comp = MyCustomComposer(solution=rotated)
    comp.energy_expectation_lightcone(edge)
    zz_exp += sim.simualte(comp.circuit)
    
full_exp = 05*(G.number_of_edges - zz_exp)
    

Can you check what's the energy for |+> initial state with same gamma=beta=0? My guess is that it'll be 5.6247672

@bgard1
Copy link
Author

bgard1 commented Dec 18, 2020

Yes, it does supply the proper circuit when using the alternative initial state. I didn't list it in the above, but I also modified to various parts so that WeightedQAOASimulator(WeightedQAOAComposer,solution=rotated) forwards the relevant information to the new circuit.

With the standard initial state WeightedQAOASimulator(WeightedQAOAComposer,solution=None), the energy is 4.5 . This energy is consistent for QTensor, qiskit and cirq.

@danlkv
Copy link
Owner

danlkv commented Dec 20, 2020

I checked probability amplitudes and they are equal up to a phase shift https://github.com/danlkv/QTensor/blob/warm_start/qtensor/tests/test_warm_start.py. There is a bug is in lightcone optimization, it treats all qubits as equal, which is not the case for the warm start state. I added a monkey patch in the warm_start branch, but a proper solution will take a week or two. See the test file linked above for usage example.

Note that you can obtain amplitudes from qtensor using state_vec = sim.simulate_batch(comp.circuit, batch_vars=n_qubits), and then pass it to qubitOp.evaluate_with_statevector , but it would be very inefficient.

@bgard1
Copy link
Author

bgard1 commented Jan 7, 2021

Great! I agree that the two constructions agree in this regard.

Additionally, I recently looked at the exact p=1 analytic result and can also confirm that both the qiskit and qtensor codes faithfully generate this result as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants