Skip to content

Simulation

Simulation(config)

High-level interface to Ising model Monte Carlo simulation.

Parameters:

Name Type Description Default
config SimulationConfig

Complete simulation configuration.

required

Examples:

>>> from mcising import Simulation, SimulationConfig, LatticeConfig
>>> config = SimulationConfig(
...     lattice=LatticeConfig(size=16, j1=1.0),
...     temperatures=(3.0, 2.269, 1.5),
...     n_sweeps=500,
... )
>>> sim = Simulation(config)
>>> results = sim.run(show_progress=False)
>>> sorted(results.energy) == [1.5, 2.269, 3.0]
True

num_sites property

Total number of spins N in the simulated lattice.

spins property writable

Current spin configuration as a 2D NumPy array.

energy property

Current energy per site.

magnetization property

Current magnetization per site.

reset()

Discard all evolved state and return to the initial condition.

The spin configuration and RNG stream are restored to exactly what a fresh Simulation(config) starts with; manual sweep() calls and spins assignments are forgotten.

run(*, reset=True, show_progress=True, on_temperature_complete=None, skip_temperatures=None)

Execute the full simulation across all temperatures.

run() first resets the simulation to its deterministic initial condition (see reset()), so repeated calls on the same object return identical results, and any prior manual sweep() or spins assignment has no effect on the run. Pass reset=False to continue from the current core state instead (checkpoint resume uses this).

Behavior depends on config.mode:

  • COOLDOWN (default): Temperatures processed sequentially in descending order. Spins carried from high T to low T.
  • INDEPENDENT: Each temperature runs in parallel from random initialization. Uses all CPU cores via Rayon.
  • PARALLEL_TEMPERING: All temperatures run as one coupled replica-exchange ensemble with periodic swap attempts.

Parameters:

Name Type Description Default
reset bool

When True (default), rebuild the core from the configuration before running. When False, keep the current spins and RNG state (only meaningful in cooldown mode — the parallel modes build fresh Rust replicas per call regardless).

True
show_progress bool

Whether to display a Rich progress bar.

True
on_temperature_complete callable

Called once per completed temperature. In cooldown mode it fires as each temperature finishes; in the parallel modes the batch computes every temperature first and the callback then fires once per temperature.

None
skip_temperatures frozenset[float]

Temperatures to leave out of this run (e.g. already completed in a checkpoint). In independent mode the remaining temperatures keep the RNG streams they would have had in a full run. In parallel tempering only skipping every temperature (or none) is allowed — the replicas form one coupled ensemble.

None

Returns:

Type Description
SimulationResults

Collected measurements across all temperatures.

Raises:

Type Description
ConfigurationError

In parallel tempering, when skip_temperatures covers a non-empty proper subset of the configured temperatures.

sweep(n_sweeps=1, *, temperature)

Perform sweeps at a given temperature and return observables.

One sweep is num_sites attempted-flip equivalents for Metropolis and Swendsen-Wang, but ONE cluster update for Wolff — measuring at a per-sweep flip-budget boundary is size-biased (P10 exact-enumeration rejection), so Wolff callers scale n_sweeps by roughly num_sites over the expected cluster size instead. The returned counters report the work honestly.

Parameters:

Name Type Description Default
n_sweeps int

Number of MC sweeps to perform.

1
temperature float

Simulation temperature (must be > 0). Keyword-only, so a pre-1.0 positional beta can never be silently reinterpreted as a temperature.

required

Returns:

Type Description
dict[str, float]

Dictionary with keys 'energy', 'magnetization', 'acceptance_rate', and 'n_cluster_flips' (0.0 for Metropolis). 'acceptance_rate' is the classic acceptance fraction for Metropolis, the flipped-spin fraction for Swendsen-Wang, and identically 1.0 for Wolff (rejection-free).


SimulationResults(temperatures=list(), energy=dict(), magnetization=dict(), configurations=dict(), correlation_function=None, correlation_length=None, n_cluster_flips=dict(), adaptive_diagnostics=None, metadata=dict(), _statistics_cache=dict()) dataclass

Container for simulation results across temperatures.

Attributes:

Name Type Description
temperatures list[float]

Temperature values that were simulated.

energy dict[float, NDArray[float64]]

Energy per site measurements at each temperature.

magnetization dict[float, NDArray[float64]]

Magnetization per site measurements at each temperature.

configurations dict[float, NDArray[int8]]

Spin configurations at each temperature, shape (n_samples, *lattice_shape): (L, L) for the square and triangular lattices, (L, L, 2) for the honeycomb, (L, L, L) for the cubic lattice and (L,) for the chain.

correlation_function dict[float, tuple[NDArray, NDArray]] | None

(distances, correlations) at each temperature, or None if not computed.

correlation_length dict[float, NDArray[float64]] | None

Correlation length measurements at each temperature, or None.

n_cluster_flips dict[float, int]

Cluster flips during the measurement sweeps at each temperature (thermalization excluded). 0 for Metropolis; for Wolff this is the number of cluster updates (one per sweep), the honest work record behind the n_sweeps accounting.

metadata dict[str, object]

Provenance and timing: the SimulationConfig object under "config", plus version, schema_version, seed, mode, algorithm, optional git_commit, and elapsed_seconds. Loaded legacy files (mcising <= 0.23.0) carry whatever subset their file recorded.

num_sites cached property

Total number of spins N, resolved from provenance.

Prefers the restored :class:~mcising.config.SimulationConfig (present for every run and every loaded file with provenance); falls back to the shape of stored spin configurations for config-less legacy files. Never guesses: a wrong N silently mis-scales specific heat and susceptibility (B11).

Raises:

Type Description
ConfigurationError

If neither the config metadata nor stored configurations can supply the site count.

statistics(temperature)

Observable estimates with standard errors at one temperature.

Computed lazily from the stored measurement series and memoized. Means (E, M, |M|) carry blocking standard errors; specific heat, susceptibility, and the Binder cumulant carry delete-one-block jackknife errors (see :mod:mcising.statistics). Total: a temperature with no or degenerate data yields nan estimates rather than an exception.

Parameters:

Name Type Description Default
temperature float

Temperature to compute statistics at.

required

Returns:

Type Description
ObservableStatistics

Per-temperature estimates; errors are nan where the series is too short to quote a principled uncertainty.

specific_heat(temperature)

Specific heat per site: Cv = N * Var(E) / T^2.

Parameters:

Name Type Description Default
temperature float

Temperature to compute Cv at.

required

Returns:

Type Description
float

Specific heat per site. For the standard error use statistics(temperature).specific_heat.error.

susceptibility(temperature, *, kind='connected')

Magnetic susceptibility per site.

The default connected convention is chi = N * (<m**2> - <|m|>**2) / T (standard for finite-size scaling; breaking default since P10, #39). kind="signed" selects the pre-1.0 N * Var(m) / T form — see :func:mcising.statistics.susceptibility.

Parameters:

Name Type Description Default
temperature float

Temperature to compute chi at.

required
kind ('connected', 'signed')

Susceptibility convention.

"connected"

Returns:

Type Description
float

Susceptibility per site. For the standard error (connected convention) use statistics(temperature).susceptibility.error.

binder_cumulant(temperature)

Binder cumulant U4 = 1 - / (3 ^2).

Parameters:

Name Type Description Default
temperature float

Temperature to compute U4 at.

required

Returns:

Type Description
float

Binder cumulant (dimensionless; no site count needed). For the standard error use statistics(temperature).binder_cumulant.error.

summary()

Print a Rich table summarizing results per temperature.

Shows mean energy, magnetization, specific heat, susceptibility, and Binder cumulant with standard errors (value ± error; n/a where the series is too short to quote one).

to_dataframe()

Convert results to a pandas DataFrame.

Returns a DataFrame with columns: T, E_mean, E_err, E_std, M_mean, M_err, M_std, Cv, Cv_err, chi, chi_err, U4, U4_err, tau_int, samples. The *_err columns are standard errors of the mean/estimator (blocking for means, jackknife for derived quantities); E_std/M_std remain the sample spread of the series (not an uncertainty). Errors are nan where the series is too short to quote one.

Returns:

Type Description
DataFrame

Summary statistics per temperature.

Raises:

Type Description
ImportError

If pandas is not installed.


AdaptiveDiagnostics(thermalization_sweeps=0, truncation_point=0, is_thermalized=True, tau_int=0.5, measurement_interval=1, production_sweeps=0, n_samples=0, stationary_sweeps=0) dataclass

Per-temperature diagnostics from the adaptive measurement scheme.

Attributes:

Name Type Description
thermalization_sweeps int

Total thermalization sweeps used (annealing ramp + all fixed-temperature diagnostic sweeps).

stationary_sweeps int

Fixed-temperature sweeps analyzed for stationarity and tau_int. Never includes the cool-down ramp: the ramp's energy trace is non-stationary by construction and is excluded from all estimation (B9, #20).

truncation_point int

MSER truncation point within the fixed-temperature series.

is_thermalized bool

Whether the fixed-temperature series was detected as stationary.

tau_int float

Integrated autocorrelation time, estimated on the stationary tail of the fixed-temperature series only.

measurement_interval int

Measurement interval used for production (tau_multiplier * tau_int).

production_sweeps int

Total production sweeps used.

n_samples int

Number of measurement samples collected.


IsingSimulation

Core Ising model simulation engine (Rust/PyO3).

One lattice, one coupling set, one update algorithm and one random-number stream. :class:mcising.Simulation drives it for the high-level API; use it directly for sweep-level control — custom temperature schedules, per-sweep observables, or exact state round-trips through :meth:get_spins / :meth:get_rng_state.

The Hamiltonian is H = -J1 Σ s_i s_j - J2 Σ s_i s_j - J3 Σ s_i s_j - h Σ s_i over nearest, next-nearest and third-nearest neighbour pairs (each bond once); positive couplings are ferromagnetic.

Constructor arguments (positional, in this order):

  • lattice_size — linear size L: sites per side (the honeycomb has two sites per cell, the chain L sites in total).
  • j1, j2, j3 — nearest-, next-nearest- and third-nearest-neighbour couplings; the cluster algorithms require j1 > 0 and j2 = j3 = h = 0.
  • h — external field.
  • seed — seed of the Xoshiro256** generator that draws the initial configuration and every update.
  • algorithm"metropolis" (default), "wolff" or "swendsen_wang".
  • lattice_type"square" (default), "triangular", "honeycomb", "cubic" or "chain"; periodic boundaries in every direction.

lattice_size property

Linear lattice size L passed at construction.

num_sites property

Number of spins.

(square, triangular), 2L² (honeycomb), (cubic) or L (chain).

j1 property

Nearest-neighbour coupling J1.

j2 property

Next-nearest-neighbour coupling J2.

j3 property

Third-nearest-neighbour coupling J3.

h property

External field h.

algorithm_name property

"metropolis", "wolff" or "swendsen_wang".

__new__(lattice_size, j1, j2, j3, h, seed, algorithm='metropolis', lattice_type='square')

Construct a simulation; the parameters are documented on the class.

sweep(n_sweeps=1, *, temperature)

Run n_sweeps Monte Carlo sweeps at temperature.

One Metropolis sweep attempts every site once in a sequential scan; one Wolff sweep grows and flips a single cluster; one Swendsen-Wang sweep rebuilds every bond and gives every cluster an independent flip decision.

Parameters:

Name Type Description Default
n_sweeps int

Number of sweeps.

1
temperature float

Temperature T (k_B = 1); must be positive and finite.

required

Returns:

Type Description
tuple[int, int, int]

(accepted, attempted, cluster_flips) summed over the sweeps, with honest work accounting per algorithm. Metropolis: accepted single-spin flips, n_sweeps * num_sites attempts, no clusters. Wolff: accepted and attempted are both the total cluster size (the update is rejection-free) and cluster_flips is n_sweeps. Swendsen-Wang: spins flipped, n_sweeps * num_sites decisions, and the number of clusters whose coin came up "flip".

energy()

Energy per site of the current configuration, H / num_sites.

magnetization()

Signed magnetization per site, Σ s_i / num_sites.

get_spins()

Copy of the spin configuration as an int8 array in the lattice's shape.

(L, L) for the square and triangular lattices, (L, L, 2) for the honeycomb, (L, L, L) for the cubic lattice and (L,) for the chain.

set_spins(spins)

Replace the configuration.

The array must hold exactly num_sites values, each +1 or -1; it is read in row-major order, so any shape with the right size is accepted. Raises ValueError otherwise.

flip_spin(site)

Flip one spin, addressed by its flat row-major site index.

Flat indexing is the one scheme every lattice shares (a (row, col) pair cannot address cubic or honeycomb sites). Raises ValueError for an index outside range(num_sites).

spin_energy(site)

Local energy of one spin, by flat site index.

-s_i (J1 Σ_nn s_j + J2 Σ_nnn s_j + J3 Σ_tnn s_j + h) — flipping the spin changes the total energy by -2 * spin_energy(site).

correlation_function()

Spin-spin correlation C(r) = <s_0 s_r> of the current configuration.

A full O(N²) pair sum binned by distance; returns (distances, correlations) as two float arrays.

correlation_length()

Second-moment correlation length of the current configuration.

Derived from the same C(r) as :meth:correlation_function.

anneal(temp_schedule)

Thermalization ramp: one sweep at each positive entry of temp_schedule.

Nothing is recorded; non-positive entries are skipped.

extend_thermalization(n_sweeps, *, temperature)

Sweep n_sweeps times at temperature, recording the energy.

Returns the energy per site after every sweep — the series that adaptive thermalization analyses with :meth:analyze_thermalization_series.

analyze_thermalization_series(series, c_window, tau_multiplier) staticmethod

Stationarity and autocorrelation analysis of an energy series.

Parameters:

Name Type Description Default
series NDArray[float64]

Energy per site after each sweep.

required
c_window float

Automatic-windowing constant for the integrated autocorrelation time (Sokal's c).

required
tau_multiplier float

Measurement interval recommended as tau_multiplier * tau_int.

required

Returns:

Type Description
dict[str, Any]

truncation_point (index where MSER stationarity begins), is_thermalized (the truncation point lies in the first half), tau_int (integrated autocorrelation time in sweeps, estimated on the stationary part), window (the windowing cutoff used) and recommended_interval (sweeps between measurements, at least 1).

production_sweeps(n_measurements, interval, *, temperature, store_configs, compute_correlation=False, correlation_interval=1)

Run a production block of n_measurements measurements.

One FFI crossing for the whole block, with the GIL released while sweeping. Energy and magnetization are measured after each block of interval sweeps, a configuration snapshot is stored when store_configs and the correlation observables are evaluated at every correlation_interval-th measurement when compute_correlation. The random-number stream is consumed exactly as n_measurements separate sweep(interval) calls would consume it.

Returns:

Type Description
dict[str, Any]

The per-temperature dict the parallel runners return: temperature, energies, magnetizations, n_cluster_flips, plus configurations when store_configs and correlation_distances / correlation_function / correlation_length when compute_correlation. Raises ValueError for a non-positive temperature or a zero interval.

get_rng_state()

Serialized generator state (JSON bytes as ints).

Lets a checkpoint continue the exact random-number stream through :meth:set_rng_state.

set_rng_state(state)

Restore a state returned by :meth:get_rng_state.

Malformed input raises ValueError.