| Crates.io | wanglandau |
| lib.rs | wanglandau |
| version | 0.0.1 |
| created_at | 2025-04-21 18:39:23.934547+00 |
| updated_at | 2025-04-21 18:39:23.934547+00 |
| description | Model-agnostic Wang–Landau Monte-Carlo core driver |
| homepage | https://github.com/b-vitamins/wanglandau |
| repository | https://github.com/b-vitamins/wanglandau |
| max_upload_size | |
| id | 1643076 |
| size | 44,399 |
A minimal, model-agnostic Wang–Landau Monte Carlo sampling implementation in Rust.
The Wang-Landau algorithm is a powerful Monte Carlo technique for estimating the density of states in complex systems with rugged energy landscapes. This crate provides a generic, type-safe implementation that can be adapted to any state space and move set.
Key features:
Add this to your Cargo.toml:
[dependencies]
wanglandau = "0.0.1"
use wanglandau::prelude::*;
#[derive(Clone)]
struct Spin(i8); // ±1 Ising spin
impl State for Spin {}
struct Flip;
impl<R: rand::RngCore> Move<Spin, R> for Flip {
fn propose(&mut self, s: &mut Spin, rng: &mut R) {
use rand::Rng;
s.0 = if rng.gen() { 1 } else { -1 };
}
}
struct Energy;
impl Macrospace<Spin> for Energy {
type Bin = usize;
fn locate(&self, s: &Spin) -> usize { (s.0 + 1) as usize / 2 }
fn bins(&self) -> &[usize] { &[0, 1] }
}
fn main() {
let mut drv = WLDriver::new(
Spin(1),
Flip,
Energy,
Params::default(),
Geometric { alpha: 0.5, tol: 1e-8 },
Fraction,
rng::seeded(2025),
);
drv.run(1_000_000);
println!("{:?}", drv.ln_g());
}
The Wang-Landau algorithm (introduced by Fugao Wang and David P. Landau in 2001) estimates the density of states g(E) by performing a random walk in energy space with a dynamically modified probability. It's particularly useful for:
The core principle is to build a histogram of visited states while continuously updating an estimate of the density of states, adjusting a modification factor to ensure even sampling across all energy levels.
The library is built around several core traits:
State: Represents a microscopic configurationMove: Defines Monte Carlo move proposalsMacrospace: Maps states to macroscopic bins (typically energy levels)Schedule: Controls how the modification factor changesFlatness: Determines when a histogram is "flat enough"To apply Wang-Landau sampling to a new system, implement these traits for your model:
// 1. Define your system state
#[derive(Clone)]
struct MySystem { /* ... */ }
impl State for MySystem {}
// 2. Define your move set
struct MyMoves;
impl<R: rand::RngCore> Move<MySystem, R> for MyMoves {
fn propose(&mut self, state: &mut MySystem, rng: &mut R) {
// Propose a random modification to the state
}
}
// 3. Define your energy binning
struct MyBins;
impl Macrospace<MySystem> for MyBins {
type Bin = usize;
fn locate(&self, state: &MySystem) -> usize {
// Calculate which bin this state belongs to
}
fn bins(&self) -> &[usize] {
// Return all possible bins
}
}
Once your system is defined:
// Create a driver with your system components
let mut driver = WLDriver::new(
initial_state,
moves,
bins,
params,
schedule,
flatness_criterion,
rng,
);
// Run the simulation for a fixed number of steps
driver.run(max_steps);
// Get the resulting ln(density of states)
let ln_g = driver.ln_g();
Geometric: Reduces ln_f by a constant factor (original Wang-Landau)OneOverT: Belardinelli-Pereyra 1/t schedule for optimal convergenceFraction: Checks if min(H) ≥ flat × mean(H)RMS: Uses relative standard deviation σ/μ ≤ (1-flat)Here's a sketch of how you might implement a 2D Ising model:
#[derive(Clone)]
struct IsingLattice {
spins: Vec<bool>, // true for up, false for down
size: usize, // lattice size (N×N)
}
impl State for IsingLattice {}
// Define a random spin flip
struct FlipSite;
impl<R: rand::RngCore> Move<IsingLattice, R> for FlipSite {
fn propose(&mut self, state: &mut IsingLattice, rng: &mut R) {
let idx = rng.gen_range(0..state.spins.len());
state.spins[idx] = !state.spins[idx];
}
}
// Define energy bins
struct EnergyBins {
n_bins: usize,
}
impl Macrospace<IsingLattice> for EnergyBins {
type Bin = usize;
fn locate(&self, state: &IsingLattice) -> usize {
let energy = calculate_ising_energy(state);
// Map energy to bin index
// ...
}
fn bins(&self) -> &[usize] {
// Return array of bin indices
// ...
}
}
fn calculate_ising_energy(state: &IsingLattice) -> i32 {
// Calculate energy for the current configuration
// ...
}
For detailed documentation, visit docs.rs/wanglandau.
Licensed under either of:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.