Getting started: Your First Simulation

In this tutorial, you will learn the complete, end-to-end workflow for simulating a quantum circuit with pyrauli. We will build a Bell state, one of the most fundamental entangled states in quantum computing, and measure a property of it.

By the end, you will understand how to construct circuits, define observables, and interpret the results of a simulation that uses the Heisenberg picture.

Installation

pyrauli requires Python 3.9 or later. You can install it directly from PyPI using pip.

Standard Installation

For core functionality, install the package as follows:

pip install pyrauli

Installation with Qiskit Support

To use pyrauli as a Qiskit backend, install it with the [qiskit] extra:

pip install 'pyrauli[qiskit]'

Simulating a Bell State

Let’s simulate a 2-qubit circuit that prepares a Bell state. This circuit first applies a Hadamard gate to create a superposition, then entangles the qubits with a CNOT gate. Finally, we will calculate the expectation value of the \(Z \otimes I\) observable.

This example demonstrates the complete basic workflow:

  1. Initialize a Circuit: We start by defining the number of qubits our circuit will have.

  2. Add quantum operations: We add gates to the circuit in the order they should be applied.

  3. Define an Observable: We specify the physical quantity we want to measure at the end of the computation.

  4. Run the simulation: This is where pyrauli’s unique approach comes into play. Instead of evolving the state, we evolve the observable.

  5. Retrieve the final expectation value: We calculate the expectation value of the final, evolved observable with respect to the initial \(|00...0\rangle\) state.

Here is the complete code:

# Create a 2-qubit circuit
qc = pyrauli.Circuit(2)

# Add gates
qc.add_operation("H", 0)
qc.add_operation("CX", 0, 1)

# Define an observable and run the circuit
observable = pyrauli.Observable("ZI")
final_observable = qc.run(observable)

print(f"Expectation value of ZI: {final_observable.expectation_value()}")

Dissecting the Simulation

Let’s look at the key lines more closely.

observable = pyrauli.Observable("ZI")

Here, we define the physical quantity we want to measure. The string "ZI" tells pyrauli that we are interested in the Pauli-Z operator acting on qubit 0 and the identity operator acting on all other qubits (in this case, qubit 1).

In the standard Schrödinger picture, this would be the measurement we perform at the end of the circuit. In the Heisenberg picture used by pyrauli, this observable is our starting point.

final_observable = circuit.run(observable)

This is the core of the pyrauli simulation. Instead of evolving a state vector forward through the circuit, the run() method evolves our observable backward. The final_observable represents what our initial observable ZI becomes after being transformed by all the gates in the circuit.

expectation_value = final_observable.expectation_value()

The final step is to calculate the expectation value of this transformed observable with respect to the simple, known initial state of all qubits in the \(|0\rangle\) state. The result, 0.0, is the same value you would get from a statevector simulation.

Next Steps

You now have a foundational understanding of the pyrauli workflow. To learn how to solve specific problems, head to our Build and Run Circuits. To understand the theory behind the Heisenberg picture and Pauli back-propagation, see our Core Concepts.