Initializing quantum states¶
YAQS separates what you specify (a State) from how evolution runs (AnalogSimParams, Hamiltonian, noise).
Layer |
Role |
|---|---|
|
User-facing initial condition: length, preset name, optional raw data, and which representation to evolve in ( |
|
Internal tensor network; used by the simulator when needed. Prefer |
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 |
|
|---|---|
Preset only ( |
Default |
|
Inferred |
|
Inferred |
|
Inferred |
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:
|
Backend (analog) |
|---|---|
|
TJM ( |
|
MCWF |
|
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
vectorscales as \(2^N\);density_matrixas \(2^{2N}\). Preferrepresentation="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 withrepresentation="mps".get_state: when supported,result.output_stateis aState(use.mpsfor the underlying MPS). Not supported withrepresentation="density_matrix"or with stochastic noise.
For MPO/TJM details without State, see Noisy Analog Simulation and the MPS API reference.