Initializing quantum states

YAQS separates what you specify (a State) from how evolution runs (AnalogSimParams, Hamiltonian, noise).

Layer

Role

State

User-facing initial condition: length, preset name, optional raw data, and which representation to evolve in ("mps", "vector", or "density_matrix").

MPS

Internal tensor network; used by the simulator when needed. Prefer State in application code.

Workflow: build a State and a Hamiltonian once (both materialize at construction), then pass them to Simulator.run — including in parameter loops.

1from mqt.yaqs.core.data_structures.state import State
2
3preset = State(4, initial="x+")
4print("preset representation:", preset.representation)  # default "mps"
5
6mcwf_state = State(4, initial="zeros", representation="vector")
7print("MCWF representation:", mcwf_state.representation)
preset representation: mps
MCWF representation: vector

State versus MPS

Use State in Simulator.run. Use MPS directly only for low-level tensor-network code, or wrap an existing MPS with State.from_mps.

Circuit simulation requires representation="mps" (the preset default). Simulator.run with StrongSimParams / WeakSimParams rejects vector and density-matrix states.

How representation is chosen

How you build State

representation

Preset only (length, initial=, …)

Default "mps"; override with representation="vector" or "density_matrix"

tensors= (MPS cores)

Inferred "mps" — do not pass representation=

vector=

Inferred "vector"

density_matrix=

Inferred "density_matrix"

1import numpy as np
2
3vec = np.array([1.0, 0.0, 0.0, 0.0], dtype=np.complex128)
4from_vector = State(vector=vec)
5print(from_vector.representation)
6
7lindblad_ready = State(2, initial="zeros", representation="density_matrix")
8print(lindblad_ready.representation)
vector
density_matrix

Preset product states

Presets match MPS(..., state=...) names: "zeros", "ones", "x+", "Neel", "wall", "basis", "random", etc.

For MCWF or Lindblad, set representation on the State and call Simulator.run — no extra steps:

1neel_mcwf = State(4, initial="Neel", representation="vector")
2print(neel_mcwf.representation)
vector

Product presets can evolve in dense form without ever building an MPS in memory. Entangled presets (e.g. "haar-random") may still require an internal MPS when you choose a dense representation.

Reproducible "random" presets: pass seed= on State.

1a = State(3, initial="random", seed=7, representation="vector")
2b = State(3, initial="random", seed=7, representation="vector")
3# Same specification; run() will evolve both consistently.

Manual initialization

Pass exactly one of tensors, vector, or density_matrix. Representation is inferred; do not pass representation=. Preset-only kwargs (initial, pad, basis_string, seed) cannot be combined with manual data.

MPS cores (tensors=)

1from mqt.yaqs.core.data_structures.mps import MPS
2
3mps_ref = MPS(3, state="zeros")
4spec = State(tensors=list(mps_ref.tensors))
5print(spec.representation)
mps

Dense state vector (vector=)

length is inferred when the Hilbert-space dimension is a power of two.

1vec = np.array([1.0, 0.0, 0.0, 0.0], dtype=np.complex128)  # |00>
2spec = State(vector=vec)
3print(spec.length, spec.representation)
2 vector

Density matrix (density_matrix=)

1rho = np.diag([1.0, 0.0, 0.0, 0.0]).astype(np.complex128)
2spec = State(density_matrix=rho)
3print(spec.representation)
density_matrix

A State created only with vector= or density_matrix= cannot be used for circuit simulation; use tensors= or a preset with representation="mps" instead.

Representation and backends (analog)

Set representation on State, not on AnalogSimParams. Simulator.run materializes the correct internal form and dispatches:

representation

Backend (analog)

"mps" (default)

TJM (analog_tjm_1 / analog_tjm_2)

"vector"

MCWF

"density_matrix"

Lindblad (small systems)

Default: MPS / TJM

 1from mqt.yaqs import Simulator
 2from mqt.yaqs.core.data_structures.hamiltonian import Hamiltonian
 3from mqt.yaqs.core.data_structures.simulation_parameters import AnalogSimParams, Observable
 4
 5sim = Simulator(show_progress=False)
 6
 7L = 3
 8H = Hamiltonian.ising(L, J=1.0, g=0.5)
 9obs = Observable("z", sites=[0])
10
11state_mps = State(L, initial="zeros")  # representation="mps" by default
12params = AnalogSimParams(
13    observables=[obs],
14    elapsed_time=0.2,
15    dt=0.05,
16)
17result = sim.run(state_mps, H, params, noise_model=None)
18print("TJM Z_0:", result.expectation_values[0][-1])
TJM Z_0: 0.9803307657532518

MCWF (representation="vector")

1state_vec = State(L, initial="zeros", representation="vector")
2obs_vec = Observable("z", sites=[0])
3params_vec = AnalogSimParams(
4    observables=[obs_vec],
5    elapsed_time=0.2,
6    dt=0.05,
7)
8result = sim.run(state_vec, H, params_vec, None)
9print("MCWF Z_0:", result.expectation_values[0][-1])
MCWF Z_0: 0.9803307672661907

Lindblad (representation="density_matrix")

1state_dm = State(L, initial="zeros", representation="density_matrix")
2obs_dm = Observable("z", sites=[0])
3params_dm = AnalogSimParams(
4    observables=[obs_dm],
5    elapsed_time=0.2,
6    dt=0.05,
7)
8result = sim.run(state_dm, H, params_dm, None)
9print("Lindblad Z_0:", result.expectation_values[0][-1])
Lindblad Z_0: 0.9803307672661925

See Representation Comparison for a side-by-side comparison of the three representations on the same Hamiltonian.

Passing dense data directly

If you already have \(|\psi\rangle\) or \(\rho\), pass vector= or density_matrix= — representation is inferred:

1psi = np.zeros(2**L, dtype=np.complex128)
2psi[0] = 1.0
3state_from_vec = State(vector=psi)
4result = sim.run(state_from_vec, H, params_vec, None)
5print("From vector=, MCWF Z_0:", result.expectation_values[0][-1])
From vector=, MCWF Z_0: 0.9803307672661907

Practical limits

  • Memory: dense vector scales as \(2^N\); density_matrix as \(2^{2N}\). Prefer representation="mps" for longer chains.

  • Entangled presets: "haar-random" may need an internal MPS for dense representations.

  • Circuits: use State(..., representation="mps") (default); vector= / density_matrix= states cannot run circuits.

  • Ensemble runs: list[State] for deterministic unitary ensembles requires each member with representation="mps".

  • get_state: when supported, result.output_state is a State (use .mps for the underlying MPS). Not supported with representation="density_matrix" or with stochastic noise.

For MPO/TJM details without State, see Noisy Analog Simulation and the MPS API reference.