Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
dberthault committed Nov 26, 2024
1 parent bbfa223 commit 9b4d875
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 11 deletions.
2 changes: 1 addition & 1 deletion documentation/src/circuits/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ qoqo/roqoqo distinguishes between:

* Definitions: Operations that declare (and initialize) classical register values ([see also here](readout.md))
* Gate Operations: Unitary operations that can be executed on every unitary quantum computer (but might need to be decomposed into a sequence of native operations) ([see also here](unitary.md))
* Pragma operations that are not generally available on all universal quantum computers (see [pragma operations](pragma.md) and [noise operations](noise.md) )
* Pragma operations that provide additional functionality to a quantum program, and are not generally available on all universal quantum computers (see [pragma operations](pragma.md) and [noise operations](noise.md) )

In order to create a useful result, a Circuit in qoqo/roqoqo must contain:

Expand Down
5 changes: 3 additions & 2 deletions documentation/src/circuits/pragma.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# Pragma Operations

Pragma operations in qoqo/roqoqo are operations that are _not_ part of the set of operations that can run on all universal quantum computers.
Pragma operations in qoqo/roqoqo are special types of operations that provide additional metadata or functionality to a quantum program.
Unlike standard quantum operations such as gate or measurements, these are _not_ part of the set of operations that can run on all universal quantum computers but these augment, control or guide the execution of quantum programs.

Pragma operations can be used to:

* Annotate a quantum circuit with additional information that is not necessary for execution (e.g. `PragmaGlobalPhase`, `PragmaStartDecompositionBlock`)
* Apply operations that lead to a repeated execution of a circuit (`PragmaRepeatedMeasurement`, `PragmaSetNumberOfMeasurements`)
* Apply operations that are only available on specific hardware (e.g. `PragmaChangeDevice`, `PragmaSleep`)
* Apply operations that are only available on a simulator (e.g. `PragmaSetStateVector`, `PragmaGetStateVector`)
* Model noise ([see also](noise.md))
* Model noise (e.g. `PragmaDamping`, `PragmaDephasing`, [see also](noise.md))
* Model error sources (`PragmaOverrotation`)

For a full list of available Pragma operations see the API documentation of [roqoqo](https://docs.rs/roqoqo/latest/roqoqo/operations/index.html)
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/circuits/readout.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Information is written to registers by the `MeasureQubit` operation or Pragma op
* On _simulators_ one can also read out the full state vector or density matrix into a complex register.

`MeasureQubit` corresponds directly to a _projectivce_ measurement. By definition, projective measurements are available on universal quantum computers.
`PragmaRepeatedMeasurement` is shorthand for repeatedly running the circuit and applying a projective measurement each time. While it is not necessarily available on every [backend](backends.md) it is compatible with hardware quantum computers.
`PragmaRepeatedMeasurement` is shorthand for repeatedly running the circuit and applying a projective measurement each time. While it is not necessarily available on every [backend](backends.md), it is compatible with hardware quantum computers.

As shown in the example below, the operation `MeasureQubit` can be used to provide measurement instructions for each individual qubit. The input parameter `qubit` specifies the qubit to be measured, whereas the parameter `readout_index` defines the position in the classical register `readout` where the measurement value of the `qubit` is stored. The explicit assignment of a qubit measurement to a readout register index can be used to handle qubit remapping in a quantum circuit.

Expand Down
73 changes: 66 additions & 7 deletions documentation/src/high-level/pauliz.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,80 @@

The `PauliZProduct` measurement is based on measuring the product of PauliZ operators for given qubits. Combined with a basis rotation of the measured qubits, it can be used to measure arbitrary expectation values. It uses projective qubit readouts like `MeasureQubit` or `PragmaRepeatedMeasurement`. It can be run on real quantum computer hardware and simulators.

The `PauliZProduct` measurement takes as inputs:
* `constant_circuit`: circuit that is always executed first. This circuit can be used to prepare the inital state from the \\(Z\\)-basis state, \\(|0...00\rangle\\).
* `circuits`: list of circuits to perform computations.
* `input`: Post-processing of measurements. It prescribes how readout registers from `circuits` are combined to generate the required expectation value.

```python
measurement = PauliZProduct(
constant_circuit=init_circuit,
circuits=[computation_circuit1, computation_circuit2, ... ],
input=measurement_input)
```

As an example, let us consider the measurement of the following Hamiltonian
\\[
\hat{H} = 0.1\cdot X + 0.2\cdot Z
\\] where `X` and `Z` are Pauli operators. The target is to measure \\(\hat{H} \\) with respect to a state
\hat{H} = 0.1\cdot X + 0.2\cdot Z \\:,
\\] where \\(X\\) and \\(Z\\) are Pauli operators. The target is to measure \\(\hat{H} \\) with respect to a state
\\[
|\psi> = (|0> + |1>)/\sqrt{2}.
\\].
|\psi\rangle = \frac{1}{\sqrt{2}}\Big(|0\rangle + |1\rangle\Big)\\:.
\\]

An `init_circuit` will be used to prepare the state \\( |\psi\rangle \\) by applying the Hadamard gate.

```python
# initialize |psi>
init_circuit = Circuit()
init_circuit += ops.Hadamard(0)
```

The given Hamiltonian includes \\(X\\) and \\(Z\\) terms that cannot be measured at the same time, since they are measured using different bases. Thus, we need to create a list of `circuits` for each type of measurement, \\( \langle Z \rangle\\) and \\( \langle X \rangle\\). The circuit for measuring \\( \langle X \rangle\\) requires an additional `Hadamard` gate that rotates the qubit basis into the \\(X\\)-basis. In this example, each measured Pauli product contains only one Pauli operator. In general, one can measure the expectation values of the products of local Pauli operators, *e.g.* \\(\langle Z_0 \rangle\\), \\(\langle Z_1 \rangle\\), \\(\langle X_0 Z_1 \rangle\\), \\(\langle X_0 X_3 \rangle\\), *etc.*

The `constant_circuit` will be used to prepare the state \\( |\psi> \\) by applying the Hadamard gate. The given Hamiltonian includes `X` and `Z` terms that cannot be measured at the same time, since they are measured using different bases. The `circuits` list includes one quantum circuit that does not apply any additional gate and one circuit that rotates the qubit basis into the X-basis so that the expectation value `<X>` is equivalent to the measurement of `<Z>` in the new basis. In this example, each measured Pauli product contains only one Pauli operator. For the post-processing of the measured results, the `PauliZProduct` measurement needs two more inputs provided by the object `PauliZProductInput`:
We define bit-registers `"ro_z"` and `"ro_x"` to store the measurements in the \\(Z\\)- and \\(X\\)-basis respectively. The `PragmaRepeatedMeasurement` operation is used to declare that we are making `1000` measurements of each circuit.

```python
# Z-basis measurement circuit with 1000 shots
z_circuit = Circuit()
z_circuit += ops.DefinitionBit("ro_z", 1, is_output=True)
z_circuit += ops.PragmaRepeatedMeasurement("ro_z", 1000, None)

# X-basis measurement circuit with 1000 shots
x_circuit = Circuit()
x_circuit += ops.DefinitionBit("ro_x", 1, is_output=True)
# Changing to the X basis with a Hadamard gate
x_circuit += ops.Hadamard(0)
x_circuit += ops.PragmaRepeatedMeasurement("ro_x", 1000, None)
```

For the post-processing of the measured results, the `PauliZProduct` measurement needs two more inputs provided by the object `PauliZProductInput`:

* The definition of the measured Pauli products after basis transformations (`add_pauliz_product()`),
* The weights of the Pauli product expectation values in the final expectation values (`add_linear_exp_val()`).

In general, one can measure the expectation values of the products of local Z operators, *e.g.* `<Z0>`, `<Z1>`, `<Z0*Z1>`, `<Z0*Z3>`, *etc.* The `PauliZProductInput` needs to define all of the products that are measured. In the given example, we will measure two products `<Z0>` after a rotation in the X basis (corresponding to `<X0>`) and `<Z0>` _without_ a rotation before the measurement.
The `PauliZProductInput` also defines the weights of the products in the final result. In the example below, 0.1 is the coefficient for the first product and 0.2 for the second.
The `PauliZProductInput` needs to define all of the products that are measured. In the given example, we will measure two products \\(\langle Z_0 \rangle\\) - one after a rotation in the \\(X\\)-basis (corresponding to \\(\langle X_0 \rangle\\)) and \\(\langle Z_0 \rangle\\) _without_ a rotation before the measurement.

We prepare the measurement input for one qubit. The `PauliZProductInput` starts with just the number of qubits. The option `use_flipped_measurement` is used to specify whether the endianess is flipped.
```python
measurement_input = PauliZProductInput(1, use_flipped_measurement=False)
```
Next, pauli products are added to the `PauliZProductInput`, using `add_pauliz_product` where we specify the register and list of qubits measured.
```python
# Read out product of Z on site 0 for register ro_z (no basis change)
z_basis_index = measurement_input.add_pauliz_product("ro_z", [0,])
# Read out product of Z on site 0 for register ro_x
# (after basis change effectively a <X> measurement)
x_basis_index = measurement_input.add_pauliz_product("ro_x", [0,])
```
Last, instructions on how to combine the single expectation values into the total result are provided. In this example, \\(0.1\\) is the coefficient of the first product and \\(0.2\\) of the second.
```Python
# Add a result (the expectation value of H) that is a combination of
# the PauliProduct expectation values.
measurement_input.add_linear_exp_val(
"<H>", {x_basis_index: 0.1, z_basis_index: 0.2},
)
```
We can now define a qoqo measurement that can be seamlessly supplied into a quantum program for execution on either a simulator or quantum hardware. Below is the complete code for creating this measurement.

```python
from qoqo import Circuit
Expand Down

0 comments on commit 9b4d875

Please sign in to comment.