quantumlib / Cirq

A Python framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
Apache License 2.0
4.24k stars 1.01k forks source link

`cirq.Simulator` final_state_vector is not normalized #6402

Closed NoureldinYosri closed 5 months ago

NoureldinYosri commented 8 months ago

Description of the issue The final state vector of cirq.Simulator.simulate may acccumulate enough numerical error that it may not have unit norm. similar to #5916

How to reproduce the issue

q0 = cirq.LineQubit(0)
circuit = cirq.Circuit(
    cirq.S(q0),
    cirq.H(q0),
    cirq.S(q0),
    cirq.Y(q0),
    cirq.S(q0),
    cirq.H(q0),
    cirq.S(q0),
    cirq.measure(q0),
)

state_vector_simulator = cirq.Simulator()
state_vector_simulator.simulate(circuit).final_state_vector
array([0.+0.j        , 0.+0.99999994j], dtype=complex64)

Cirq version 1.2.0

sid-112 commented 8 months ago

import cirq

q0 = cirq.LineQubit(0) circuit = cirq.Circuit( cirq.S(q0), cirq.H(q0), cirq.S(q0), cirq.Y(q0), cirq.S(q0), cirq.H(q0), cirq.S(q0), cirq.measure(q0), )

state_vector_simulator = cirq.Simulator() final_state = state_vector_simulator.simulate(circuit).final_state_vector

Normalize the final state vector

normalized_final_state = final_state / cirq.linalg.norm(final_state)

Now you can use the normalized_final_state for further analysis

NoureldinYosri commented 8 months ago

cirq-cync: proposed solution to normalize the output when we call final_state_vector

smburdick commented 8 months ago

I can take this on.

NoureldinYosri commented 8 months ago

@smburdick thanks for volunteering to help with this, assigned to you

StrangeM4tter commented 7 months ago

Hi hello. I was looking into some first issues for Cirq and came across this issue. I hope it is okay to give my two cents. I think the origin of this stems from a float precision problem, which I'll demonstrate using the given code block from @NoureldinYosri


q0 = cirq.LineQubit(0)
circuit = cirq.Circuit(
    cirq.S(q0),
    cirq.H(q0),
    cirq.S(q0),
    cirq.Y(q0),
    cirq.S(q0),
    cirq.H(q0),
    cirq.S(q0),
    cirq.measure(q0),
)

state_vector_simulator_c64 = cirq.Simulator() #default dtype for Simulator() is np.complex64, two 32-bit precision floats
state_vector_simulator_c128 = cirq.Simulator(dtype=np.complex128) #now two 64-bit precision floats

sim64 = state_vector_simulator_c64.simulate(circuit).final_state_vector
sim128 = state_vector_simulator_c128.simulate(circuit).final_state_vector

print(sim64)
print(sim128) 
[0.+0.j         0.+0.99999994j]  #issues with precision
[0.+0.j 0.+1.j]                  #no issues with precision, normalization is fine 

Note that the same issue occurs with cirq.final_density_matrix as mentioned in #5916, or just with np.matmul using equivalent matrices if you wanted (not shown).

fin_64 = cirq.final_density_matrix(circuit, dtype=np.complex64)
fin_128 = cirq.final_density_matrix(circuit, dtype=np.complex128)

print(fin_64)
print(fin_128)
[[0.       +0.j 0.       +0.j]
 [0.       +0.j 0.9999999+0.j]] #issues with precision

[[0.+0.j 0.+0.j]
 [0.+0.j 1.+0.j]]               #no issues with precision

It is mentioned that np.complex128 is an accepted dtype for the Simulator class, should this be the default to circumvent this issue?

NoureldinYosri commented 7 months ago

As per https://github.com/quantumlib/Cirq/issues/6402#issuecomment-1896371184 the decision here was to normalize the final_state_vector.

Regardless of the precision of the type used in simulation there will always be numbers that can't be represented exactly leading to an accumulation of errors. The final normalization step should make the output look nicer and closer to what we expect.

github-actions[bot] commented 6 months ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days

pavoljuhas commented 6 months ago

Perhaps the simulator could provide an estimate for the accumulated round-off errors given the simulation dtype - then we could raise some warning if the state vector norm was too far off. As a quick estimate, the example above has 7 non-measure operations, there are 6 flops per matrix-vector multiplication so the epsilon on state vector coefficient would be ~ sqrt(7 * 6 * eps**2) = 8e-7 (for np.finfo(np.complex64).eps = 1.2e-7). The difference of the state vector norm from 1 is 6e-8, well below the round-offs estimate.

That said, I currently don't see a quick and easy API to add this in.

github-actions[bot] commented 5 months ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days