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

Constistent simulator output #89

Open
mhinkie opened this issue Aug 1, 2023 · 3 comments
Open

Constistent simulator output #89

mhinkie opened this issue Aug 1, 2023 · 3 comments

Comments

@mhinkie
Copy link

mhinkie commented Aug 1, 2023

Simulator Plugins (i.e., Qiskit Simulator) have the ability to produce histograms for measurement frequencies and statevector outputs. The contents of the statevector output in particular depends on whether the measurement of the circuit has been performed or not. This issue documents the expected behaviour and (if necessary) fixes the behaviour in the existing simulator.

Expected Behavior

The simulator plugins accept QASM code that might contain measurements. The QASM code should be exectued as is (i.e., including possible measurements). The measurement output (the frequency histogram) should reflect the measurements in the classical registers as specified in the QASM code. The statevector output should contain the statevector over the whole system after the whole QASM input is executed.

Why?

  • This way, the QASM file decides which qubits are measured: If a QASM file specifies a 3 qubit circuit and only 2 classical bits for measurement results, it is assumed that only these 2 bits are relevant outputs of the circuit. If, for example, measure_all() is performed, there could be outputs that are unexpected for the user.
  • This way, it is possible to inspect partial statevectors: If a QASM file specifies a measurement on only a subset of the qubits, this setup allows us to return the statevector after it has been affected by the partial measurement. If this is not wanted, the user can adapt the QASM file by for example removing the measurements to obtain the full statevector.
  • By respecting the measurements as they are specified in the QASM file it is possible to perform reorderings of the measurements directly in the QASM code (e.g., qubit 0 is measured into classical bit 2). This would not be possible if we enforce a measurement of all qubits manually.

Examples

Note that the statevector output might differ in its format from the examples here (i.e. list of string, oder dict: index -> complex...). This issue does not specify this format.

Measurement of all qubits

OPENQASM 2.0;
include "qelib1.inc";
qreg q19[3];
creg meas[3];
h q19[0];
x q19[1];
cx q19[0],q19[1];
measure q19[0] -> meas[0];
measure q19[1] -> meas[1];
measure q19[2] -> meas[2];

Output Histogram: {'010': 514, '001': 510}
Output Statevector*:

Statevector([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
             0.+0.j],
            dims=(2, 2, 2))

Measurement of a subset of qubits

OPENQASM 2.0;
include "qelib1.inc";
qreg q59[3];
creg c5[2];
h q59[0];
h q59[1];
cx q59[1],q59[2];
measure q59[1] -> c5[0];
measure q59[2] -> c5[1];

Output Histogram: {'11': 513, '00': 511}
Output Statevector*:

Statevector([0.        +0.j, 0.        +0.j, 0.        +0.j,
             0.        +0.j, 0.        +0.j, 0.        +0.j,
             0.70710678+0.j, 0.70710678+0.j],
            dims=(2, 2, 2))

No measurement (but classical register is defined => there is an output histogram)

OPENQASM 2.0;
include "qelib1.inc";
qreg q66[3];
creg c7[2];
h q66[0];
h q66[1];
cx q66[1],q66[2];

Output Histogram: {'00': 1024}
Output Statevector:

Statevector([0.5+0.j, 0.5+0.j, 0. +0.j, 0. +0.j, 0. +0.j, 0. +0.j, 0.5+0.j,
             0.5+0.j],
            dims=(2, 2, 2))

No measurement (and classical register is not defined)

OPENQASM 2.0;
include "qelib1.inc";
qreg q72[3];
h q72[0];
h q72[1];
cx q72[1],q72[2];

Output Statevector:

Statevector([0.5+0.j, 0.5+0.j, 0. +0.j, 0. +0.j, 0. +0.j, 0. +0.j, 0.5+0.j,
             0.5+0.j],
            dims=(2, 2, 2))

The output histogram for this case is somewhat undefined: Since there is no classical register, it is not clear what should be returned. For example, Qiskit then returns a list of measurment probabilities for the histogram (i.e., not the frequencies w.r.t. the shots but actual probabilities): {'000': 0.25, '001': 0.25, '110': 0.25, '111': 0.25}. However, it can not be assumed that every simulator library behaves this way. Therefore, this case should be further specified in this issue (see dicsussion).

*The statevector for these examples depends the measurement operation. I.e., there could be other statevectors obtained from this quantumcircuit since the measurement collapses the superposition to multiple possible statevectors.

@mhinkie
Copy link
Author

mhinkie commented Aug 1, 2023

Possibilites to the undefined histogram in the last example:

  • Leave it in this specification undefined: The qiskit simulator could then return the probabilities as it does now and the behaviour for other simulator can be arbitrary.
  • Return an empty dictionary (as there are no classical bits to return): "{}". This can be handled in the Qiskit case by inspecting "num_clbits" in the simulator results:
Result(backend_name='aer_simulator', backend_version='0.11.1', qobj_id='99446ff4-2313-4432-bb7a-1d97c3097d3c', job_id='ddd94370-ed71-4f5c-bd31-fa3ac07d789c', success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, data=ExperimentResultData(statevector=Statevector([0.5+0.j, 0.5+0.j, 0. +0.j, 0. +0.j, 0. +0.j, 0. +0.j, 0.5+0.j,
             0.5+0.j],
            dims=(2, 2, 2))), header=QobjExperimentHeader(clbit_labels=[], creg_sizes=[], global_phase=0.0, memory_slots=0, metadata={}, n_qubits=3, name='circuit-381', qreg_sizes=[['q72', 3]], qubit_labels=[['q72', 0], ['q72', 1], ['q72', 2]]), status=DONE, seed_simulator=1016333041, metadata={'noise': 'ideal', 'batched_shots_optimization': False, 'measure_sampling': True, 'parallel_shots': 1, 'remapped_qubits': False, 'active_input_qubits': [0, 1, 2], 'num_clbits': 0, 'parallel_state_update': 8, 'num_qubits': 3, 'device': 'CPU', 'input_qubit_map': [[2, 2], [1, 1], [0, 0]], 'method': 'statevector', 'result_subtypes': {'statevector': 'single'}, 'result_types': {'statevector': 'save_statevector'}, 'fusion': {'applied': False, 'max_fused_qubits': 5, 'threshold': 14, 'enabled': True}}, time_taken=0.0001913)], date=2023-08-01T12:40:38.295698, status=COMPLETED, header=QobjHeader(backend_name='aer_simulator', backend_version='0.11.1'), metadata={'time_taken': 0.0004567, 'time_taken_execute': 0.0002692, 'mpi_rank': 0, 'num_mpi_processes': 1, 'max_gpu_memory_mb': 0, 'max_memory_mb': 31938, 'parallel_experiments': 1, 'time_taken_load_qobj': 0.0001765, 'num_processes_per_experiments': 1, 'omp_enabled': True}, time_taken=0.0007145404815673828)

@buehlefs
Copy link
Contributor

buehlefs commented Aug 1, 2023

The empty dictionary sounds like the best solution. The counts should always be present (to have at least one reliable output), but in this case there never was a measurement to produce such a count, so empty counts seem right. Maybe use an empty string and assign it the number of shots as value {"": 1024}.
The statevector was only ever meant as an additional output, that will be present if supported by the simulator. We could handle probability distributions the same way and just add them as an output if they are available. The biggest problem is probably differentiating them from counts in Qiskit.

This issue should stay open until it is included in the documentation (either as an ADR or as part of the general documentation on writing plugins, but on its own page).

@buehlefs
Copy link
Contributor

The main issue is now resolved through documentation: https://qhana-plugin-runner.readthedocs.io/en/latest/plugin-types/circuit-executor.html

Keeping the issue open, as some simulators do not output the statevector after all measurements. For now, these plugins should output a statevector with a different file name.

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