odatse.algorithm.pamc module#

class odatse.algorithm.pamc.Algorithm(info: Info, runner: Runner = None, run_mode: str = 'initial')[source]#

Bases: AlgorithmBase

Population Annealing Monte Carlo (PAMC) Algorithm Implementation.

PAMC is an advanced Monte Carlo method that combines features of simulated annealing and population-based methods. It maintains a population of walkers that evolves through a sequence of temperatures, using both Monte Carlo updates and resampling.

Key Features:
  • Maintains a population of walkers that evolves through temperature steps

  • Uses importance sampling with weight-based resampling

  • Supports both fixed and variable population sizes

  • Calculates free energy differences between temperature steps

  • Provides error estimates through population statistics

Algorithm Flow:
  1. Initialize walker population at highest temperature

  2. For each temperature step:

  1. Perform Monte Carlo updates at current temperature

  2. Calculate weights for next temperature

  3. Resample population based on weights

  4. Update statistical estimates

  1. Track best solutions and maintain system statistics

logweights#

Log of importance weights for each walker

Type:

np.ndarray

fx#

Current energy/objective values

Type:

np.ndarray

nreplicas#

Number of replicas at each temperature

Type:

np.ndarray

betas#

Inverse temperatures (β = 1/T)

Type:

np.ndarray

Tindex#

Current temperature index

Type:

int

Fmeans#

Mean free energy at each temperature

Type:

np.ndarray

Ferrs#

Free energy error estimates

Type:

np.ndarray

walker_ancestors#

Tracks genealogy of walkers for analysis

Type:

np.ndarray

Initialize the Algorithm class.

Parameters:
  • info (odatse.Info) – Information object containing algorithm parameters.

  • runner (odatse.Runner, optional) – Runner object for executing the algorithm, by default None.

  • run_mode (str, optional) – Mode in which to run the algorithm, by default “initial”.

__init__(info: Info, runner: Runner = None, run_mode: str = 'initial') None[source]#

Initialize the Algorithm class.

Parameters:
  • info (odatse.Info) – Information object containing algorithm parameters.

  • runner (odatse.Runner, optional) – Runner object for executing the algorithm, by default None.

  • run_mode (str, optional) – Mode in which to run the algorithm, by default “initial”.

_apply_state(data: dict, mode: str = 'resume', restore_rng: bool = True) None[source]#

Restore algorithm state from a checkpoint snapshot.

Delegates MPI validation, RNG restore, and MC-layer fields to the base class, then handles PAMC-specific fields explicitly. Simple scalar fields are set directly; array fields that may be shorter than the current schedule (logZs, Fmeans, etc.) are written with slice assignment after re-initialisation.

The logweight update, optional resampling, and Tindex increment for continue mode are performed in prepare() after this method returns, so that the run-phase timers are already initialised.

Parameters:
  • data (dict) – Snapshot previously produced by __getstate__.

  • mode (str) – "resume" — validate that the temperature schedule is identical to the one stored in data. "continue" — concatenate the stored schedule with the new one (the stored last beta must equal the new first beta).

  • restore_rng (bool) – When True (default) the RNG state is restored from data; when False a fresh RNG state is kept (--reset_rand mode).

_calc_participation_ratio() float[source]#

Calculate the participation ratio of the current walker population.

The participation ratio is a measure of the effective sample size and indicates how evenly distributed the weights are among walkers. It is calculated as (sum(w))²/sum(w²), where w are the normalized weights.

A value close to the total number of walkers indicates well-distributed weights, while a small value indicates that only a few walkers dominate the population.

To avoid numerical issues with large log-weights, we normalize by subtracting the maximum log-weight before exponentiation.

Parameters:

None – Uses the current state of self.logweights

Returns:

The participation ratio, a value between 1 and the total number of walkers

Return type:

float

Notes

In parallel execution, this method aggregates weights across all processes to calculate the global participation ratio.

_find_scheduling(info_pamc) int[source]#

Determine the temperature schedule and number of steps.

The schedule can be specified in three ways:
  1. Total steps and steps per temperature

  2. Total steps and number of temperatures

  3. Steps per temperature and number of temperatures

The method ensures even distribution of computational effort across temperature steps while respecting the specified constraints.

Parameters:

info_pamc (dict) –

Configuration dictionary containing:
  • numsteps: Total number of Monte Carlo steps

  • numsteps_annealing: Steps per temperature

  • Tnum: Number of temperature points

Returns:

Number of temperature steps in the schedule

Return type:

int

Raises:

odatse.exception.InputError – If the scheduling parameters are inconsistent

_gather_information(numT: int = None) dict[str, ndarray][source]#

Collect and organize statistical information across all processes.

Gathers data needed for:
  1. Free energy calculations

  2. Error estimation

  3. Population statistics

  4. Acceptance rate monitoring

Parameters:

numT (int, optional) – Number of temperature steps to gather data for

Returns:

Contains:
  • fxs: Energy values for all walkers

  • logweights: Log of importance weights

  • ns: Number of walkers per process

  • ancestors: Genealogical tracking data

  • acceptance ratio: MC acceptance rates

Return type:

dict[str, np.ndarray]

_initialize() None[source]#

Initialize the Monte Carlo simulation state.

For continuous problems:
  • Uses domain.initialize to generate valid initial positions

  • Respects any additional limitations from the runner

For discrete problems:
  • Randomly assigns walkers to valid nodes

  • Maps node indices to actual coordinate positions

Also initializes:
  • Objective function values (fx) to zero

  • Best solution tracking variables

  • Acceptance counters for monitoring convergence

_post() dict[source]#

Post-processing after the algorithm execution.

Gathers the best solution across all processes and writes it to best_result.txt, and writes the per-temperature statistics (free energy, errors, partition function) to fx.txt and the participation ratios to pr.txt. (Splitting of trial/result into per-temperature files is done in _run, not here.)

_prepare() None[source]#

Prepare the algorithm for execution.

Initialises the run-phase timers, then for continue mode applies the logweight update and advances Tindex to the next temperature. This must run after _apply_state() has extended the beta schedule (done inside _prepare() dispatch) and after the timers are ready.

_resample(at_init: bool = False) None[source]#

Perform population resampling between temperature steps.

This is a key component of PAMC that:
  1. Gathers current population statistics (unless at_init)

  2. Calculates importance weights for the temperature change

  3. Resamples walkers based on their weights

  4. Updates population statistics and free energy estimates (unless at_init)

Parameters:
  • at_init (bool, optional) – If True, use current logweights only and skip gather/save_stats (used when resampling at init with anneal_from_beta0). self.logZ is updated in this case.

  • modes (The resampling can be done in two) –

    • Fixed: Maintains constant population size

    • Varied: Allows population size to fluctuate based on weights

  • Details (Implementation) –

    • Uses log-weights to prevent numerical overflow

    • Maintains walker genealogy for analysis

    • Updates free energy estimates using resampling data

    • Handles MPI communication for parallel execution

_resample_fixed(weights: ndarray) None[source]#

Perform resampling with fixed weights.

This method resamples the walkers based on the provided weights and updates the state of the algorithm accordingly.

Parameters:

weights (np.ndarray) – Array of weights for resampling.

_resample_varied(weights: ndarray, offset: int) None[source]#

Resample population allowing size variation.

Uses Poisson resampling:
  1. Calculates expected number of copies from weights

  2. Samples actual copies using Poisson distribution

  3. Creates new population with variable size

  4. Updates all walker properties

Parameters:
  • weights (np.ndarray) – Importance weights for resampling

  • offset (int) – Process-specific offset in global population

_run() None[source]#

Execute the main algorithm loop.

For init mode, perform the initial evaluation here before entering the main loop. Call _save_state() at the appropriate points inside the loop.

_save_stats(info: dict[str, ndarray]) None[source]#

Calculate and save statistical measures from the simulation.

Performs:
  1. Free energy calculations using weighted averages

  2. Error estimation using jackknife resampling

  3. Population size tracking

  4. Acceptance rate monitoring

  5. Partition function estimation

Uses bias-corrected jackknife for reliable error estimates of weighted averages in the presence of correlations.

Parameters:

info (dict[str, np.ndarray]) –

Dictionary containing the following keys:
  • fxs: Objective function of each walker over all processes.

  • logweights: Logarithm of weights.

  • ns: Number of walkers in each process.

  • ancestors: Ancestor (origin) of each walker.

  • acceptance ratio: Acceptance ratio for each temperature.