Documentation
¶
Overview ¶
Package statevector implements a full statevector quantum simulator supporting up to 28 qubits.
The simulator stores the full quantum state as a []complex128 slice of length 2^n, where each element is the probability amplitude for the corresponding computational basis state. Gates are applied in-place via the block-stride pattern: for a gate on qubit k, the 2^n amplitudes are partitioned into blocks of size 2^(k+1). Within each block, the first 2^k indices have bit k = 0 and the second 2^k have bit k = 1. Each index i in the first half pairs with i + 2^k in the second half, and the gate's 2x2 unitary is applied to that (amplitude[i], amplitude[i+2^k]) pair. This pattern generalizes to 2-qubit gates via nested block strides over two bit positions, and to N-qubit gates via bitmask-based index construction.
For circuits with 17 or more qubits (2^17 = 131,072 amplitudes), gate application is automatically parallelized across available cores. Below that threshold, goroutine scheduling overhead exceeds the benefit of parallelism for the simple multiply-accumulate inner loop, so a single goroutine is used.
Entry points:
- Sim.Run resets the state to |0...0>, evolves through the circuit, then samples measurement outcomes via inverse-CDF sampling.
- Sim.Evolve resets and evolves without measuring, leaving the statevector accessible via Sim.StateVector for inspection, expectation values, or further manipulation.
- Sim.StateVector returns a defensive copy of the current amplitudes.
Package statevector implements a full statevector quantum simulator.
Index ¶
- type Sim
- func (s *Sim) Apply(c *ir.Circuit) error
- func (s *Sim) Close() error
- func (s *Sim) Evolve(c *ir.Circuit) error
- func (s *Sim) ExpectPauliString(ps pauli.PauliString) float64
- func (s *Sim) ExpectPauliSum(ps pauli.PauliSum) float64
- func (s *Sim) ExpectationValue(qubits []int) float64
- func (s *Sim) Reset()
- func (s *Sim) Run(c *ir.Circuit, shots int) (map[string]int, error)
- func (s *Sim) RunDynamic(c *ir.Circuit, shots int) (map[string]int, error)
- func (s *Sim) StateVector() []complex128
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Sim ¶
type Sim struct {
// contains filtered or unexported fields
}
Sim simulates a circuit via full statevector evolution.
func (*Sim) Apply ¶ added in v1.2.0
Apply applies the circuit's gate operations to the current state without resetting. Use this to compose circuits incrementally:
sim.Evolve(circuitA) // resets to |0>, then applies A sim.Apply(circuitB) // applies B to the state left by A
func (*Sim) Close ¶ added in v1.2.0
Close is a no-op for the CPU statevector simulator. It satisfies sim.Simulator.
func (*Sim) Evolve ¶
Evolve resets the state to |0...0> and then applies the circuit's gate operations without measuring. The resulting statevector is accessible via Sim.StateVector. To apply gates without resetting (e.g. to compose circuits incrementally), use Sim.Apply instead.
Example ¶
package main
import (
"fmt"
"math"
"github.com/splch/goqu/circuit/builder"
"github.com/splch/goqu/sim/statevector"
)
func main() {
// Build a Bell circuit and inspect the statevector.
c, err := builder.New("bell", 2).
H(0).
CNOT(0, 1).
Build()
if err != nil {
panic(err)
}
sim := statevector.New(2)
if err := sim.Evolve(c); err != nil {
panic(err)
}
// The Bell state has non-zero amplitudes only for |00> and |11>.
sv := sim.StateVector()
for i, amp := range sv {
p := real(amp)*real(amp) + imag(amp)*imag(amp)
if p > 1e-10 {
fmt.Printf("|%02b|^2 = %.1f\n", i, math.Round(p*10)/10)
}
}
}
Output: |00|^2 = 0.5 |11|^2 = 0.5
func (*Sim) ExpectPauliString ¶
func (s *Sim) ExpectPauliString(ps pauli.PauliString) float64
ExpectPauliString computes Re(⟨psi|P|psi⟩) for a Pauli string P. For Hermitian observables (real coefficients), the imaginary part is zero. For non-Hermitian observables, use pauli.Expect directly for complex128.
func (*Sim) ExpectPauliSum ¶
ExpectPauliSum computes Re(⟨psi|H|psi⟩) for a Hamiltonian H (sum of Pauli strings). For Hermitian observables (real coefficients), the imaginary part is zero. For non-Hermitian observables, use pauli.ExpectSum directly for complex128.
func (*Sim) ExpectationValue ¶
ExpectationValue computes <psi|O|psi> for a diagonal Pauli-Z observable specified as a list of qubit indices. For example, [0, 1] computes <Z0 Z1>. The result is rounded to 14 decimal places to clean up floating-point noise.
func (*Sim) Reset ¶ added in v1.2.0
func (s *Sim) Reset()
Reset returns the simulator state to |0...0>.
func (*Sim) Run ¶
Run executes the circuit and returns measurement counts. For dynamic circuits (mid-circuit measurement, feed-forward, reset), it automatically uses per-shot simulation with state collapse.
Example ¶
package main
import (
"fmt"
"github.com/splch/goqu/circuit/builder"
"github.com/splch/goqu/sim/statevector"
)
func main() {
// Build a circuit that always produces |11>.
c, err := builder.New("x2", 2).
X(0).
X(1).
MeasureAll().
Build()
if err != nil {
panic(err)
}
sim := statevector.New(2)
counts, err := sim.Run(c, 100)
if err != nil {
panic(err)
}
fmt.Printf("11: %d shots\n", counts["11"])
}
Output: 11: 100 shots
func (*Sim) RunDynamic ¶
RunDynamic executes a dynamic circuit (mid-circuit measurement, feed-forward, reset) by simulating each shot independently with projective measurement and state collapse.
func (*Sim) StateVector ¶
func (s *Sim) StateVector() []complex128
StateVector returns a copy of the current statevector.