Skip to content

Commit

Permalink
Switch public API to a cleaner version.
Browse files Browse the repository at this point in the history
  • Loading branch information
Cap. Hindsight committed Jul 8, 2018
1 parent 42b0d7c commit 6c9ec9c
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 38 deletions.
31 changes: 15 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ struct MySample {
}
```

Implement the trait `ergothic::simulation::Sample` for your sample. You will need to implement the following 3 methods:
Implement the trait `ergothic::Sample` for your sample. You will need to implement the following 3 methods:

```rust
trait Sample {
fn prepare_randomized() -> Self;
fn prepare() -> Self;
fn thermalize(&mut self) { ... }
fn mutate(&mut self);
}
Expand Down Expand Up @@ -58,7 +58,7 @@ Usually it can be implemented by applying a fixed number (10-20) of mutations to
However, ergothic lets you implement your own thermalization algorithm.

#### In code
Implement the `prepare_randomized` method of the `Sample` trait.
Implement the `prepare` method of the `Sample` trait.

Optionally, you can implement the `thermalize` method. The default implementation applies `mutate` 20 times.

Expand All @@ -67,12 +67,12 @@ Optionally, you can implement the `thermalize` method. The default implementatio
The purpose of any ergothic simulation is to establish expectation values and statistical uncertainties for a given list of measures.

#### In code
Create a `MeasureRegistry` and register measures in it. All measures must be given unique human-readable names.
Create a `Simulation` and add measures to it. All measures must be given unique human-readable names.

```rust
fn main() {
let mut reg = ergothic::measure::MeasureRegistry::new();
let ground_state_energy = reg.register("Energy of the ground state".to_string());
let mut simulation = ergothic::Simulation::new("Lattice QCD");
let ground_state_energy = simulation.add_measure("Energy of the ground state");
...
}
```
Expand All @@ -82,11 +82,10 @@ When your simulation runs, on each step you have a sample configuration.
Measuring the values of physical observables of interest and accumulating those values in the statistical counters is done by the measurement function.

#### In code
Pass a lambda to the entry-point function `ergothic::run_simulation`.
Pass a lambda to the entry-point function `ergothic::Simulation::run`.

```rust
ergothic::run_simulation("My simulation",
/*takes ownership of measure registry*/ reg, |s: &MyState, ms| {
simulation.run(|s: &MyState, ms| {
// Calculate the values of relevant observables in state `s` and accumulate them in `ms`.
// Accumulating values is easy: just call
// ms.accumulate(ground_state_energy, value);
Expand All @@ -106,8 +105,8 @@ struct MySample {
x: f64, // Random variable within [0 .. 1].
}

impl ergothic::simulation::Sample for MySample {
fn prepare_randomized() -> MySample {
impl ergothic::Sample for MySample {
fn prepare() -> MySample {
MySample{x: rand::random()}
}

Expand All @@ -117,11 +116,11 @@ impl ergothic::simulation::Sample for MySample {
}

fn main() {
let mut reg = ergothic::measure::MeasureRegistry::new();
let x = reg.register("Mean X".to_string()); // Mean value of the random variable x.
let x2 = reg.register("Mean X^2".to_string()); // Mean value of the square of x.
ergothic::run_simulation("Computing expectations of random variable and its square",
reg, |s: &MySample, ms| {
let mut simulation = ergothic::Simulation::new(
"Computing expectations of random variable and its square");
let x = simulation.add_measure("Mean X"); // Mean value of the random variable x.
let x2 = simulation.add_measure("Mean X^2"); // Mean value of the square of x.
simulation.run(|s: &MySample, ms| {
ms.accumulate(x, s.x); // Accumulate the value of x in the statistical counter for the corresponding measure.
ms.accumulate(x2, s.x.powi(2)); // Accumulate the value of x^2 in the statistical counter for the corresponding measure.
});
Expand Down
2 changes: 1 addition & 1 deletion ergothic/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ergothic"
version = "0.1.1"
version = "0.1.2"
authors = ["Cap. Hindsight <[email protected]>"]
description = "Rust library for setting up and running distributed Monte-Carlo statistical simulations. Designed primarily for lattice QCD."
homepage = "https://github.com/caphindsight/ergothic"
Expand Down
51 changes: 44 additions & 7 deletions ergothic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,58 @@ extern crate structopt;
/// Utilities related to accumulating mean values and statistical errors for
/// physical observables measured on sample configurations drawn from the
/// ergodic distribution.
pub mod accumulate;
mod accumulate;

/// Exporters provide interfaces for sending the measured expectation values to
/// different types of data sinks.
pub mod export;
mod export;

/// Helper classes for measures and measure registries.
pub mod measure;
mod measure;

/// The simulation orchestration engine is the core part of *ergothic*.
pub mod simulation;
mod simulation;

/// Helpers for assembling binaries capable of running the same simulation in
/// development and production modes.
pub mod startup;
mod startup;

/// Entry-point function for all simulations.
pub use startup::run_simulation;

// Following are the elements of the public API.

/// Sample trait defines an object acting as a statistical sample.
pub use simulation::Sample;

/// Positional index of a measure in the measure registry. Indices are wrapped
/// in `MeasureIdx` type for type safety.
pub use measure::MeasureIdx;

/// Public interface to measure registry and the entry point function.
pub struct Simulation {
name: String,
measure_registry: measure::MeasureRegistry,
}

impl Simulation {
/// Constructs a new simulation.
pub fn new<N: ToString>(name: N) -> Simulation {
Simulation {
name: name.to_string(),
measure_registry: measure::MeasureRegistry::new(),
}
}

/// Registers a measure in the underlying measure registry and returns its
/// positional index safely wrapped in the `MeasureIdx` type.
pub fn add_measure<N: ToString>(&mut self, name: N) -> MeasureIdx {
self.measure_registry.register(name.to_string())
}

/// Entry point function. All ergothic simulations should call this function.
/// Consumes `self` to indicate that the simulation runs in an infinite loop
/// and never returns.
pub fn run<S: simulation::Sample, F>(self, f: F)
where F: Fn(&S, &mut measure::Measures) {
startup::run_simulation(&self.name, self.measure_registry, f);
}
}
4 changes: 2 additions & 2 deletions ergothic/src/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ::std::time::SystemTime;
/// trait in order to be used in the *ergothic* simulation.
pub trait Sample {
/// Creates a new configuration sample with randomized degrees of freedom.
fn prepare_randomized() -> Self;
fn prepare() -> Self;

/// Generally, randomized samples are highly atypical. In order to improve the
/// quality of simulation results, a configuration sample has to be
Expand Down Expand Up @@ -60,7 +60,7 @@ pub fn run<S: Sample, F>(mut parameters: Parameters, measure_fn: F)
where F: Fn(&S, &mut Measures) {
info!("Running ergothic simulation \"{}\".", &parameters.name);
// Prepare and thermalize a sample.
let mut sample = S::prepare_randomized();
let mut sample = S::prepare();
sample.thermalize();
let mut last_export_timestamp = SystemTime::now();
let mut export_errors_in_row: usize = 0;
Expand Down
10 changes: 8 additions & 2 deletions ergothic/src/startup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ pub struct CmdArgs {

/// Relative magnitude of the flush interval randomization. Allowed range is
/// [0, 1). The real interval will be chosen at random within this fraction of
/// the --flush_interval_secs. Has effect only in production mode.
/// the --flush_interval_secs. The purpose is to avoid contention in the
/// storage service coming from all nodes reporting data points at the same
/// time. Has effect only in production mode.
/// Example: --flush_interval_randomization 0.2 (randomize within 20%).
#[structopt(long="flush_interval_randomization", default_value="0.5")]
pub flush_interval_randomization: f64,
Expand All @@ -47,7 +49,7 @@ pub struct CmdArgs {
}

/// Parses the command line arguments and produces simulation parameters.
pub fn construct_parameters(name: String, measures: Measures, args: CmdArgs)
pub fn construct_parameters(name: String, measures: Measures, mut args: CmdArgs)
-> Parameters {
let mut rng = ::rand::thread_rng();
use ::rand::distributions::Distribution;
Expand Down Expand Up @@ -88,6 +90,10 @@ pub fn construct_parameters(name: String, measures: Measures, args: CmdArgs)
panic!("Argument --path_integral_randomization should lie within [0, 1).");
}

if !args.production_mode {
args.flush_interval_randomization = 0.0;
}

let flush_interval_min = ::std::cmp::max(1,
(flush_interval_secs as f64 * (1.0 - args.flush_interval_randomization))
.round() as u64);
Expand Down
4 changes: 2 additions & 2 deletions examples/mean_powers_of_x/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 7 additions & 8 deletions examples/mean_powers_of_x/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ struct MySample {
unif: rand::distributions::Uniform<f64>,
}

impl ergothic::simulation::Sample for MySample {
impl ergothic::Sample for MySample {
// Prepare a randomized configuration. In our simple case, setting initial `x`
// to zero is enough.
fn prepare_randomized() -> MySample {
fn prepare() -> MySample {
MySample {
x: 0.0,
rng: rand::thread_rng(),
Expand Down Expand Up @@ -60,19 +60,18 @@ impl ergothic::simulation::Sample for MySample {
}

fn main() {
// Initialize the registry of measures (physical observables).
let mut measures = ergothic::measure::MeasureRegistry::new();

let mut simulation = ergothic::Simulation::new(
"mean values of powers of [0..1]");
let mut powers_of_x = Vec::with_capacity(10);
for i in 0..10 {
// Register a measure corresponding to X to the power of `i`.
powers_of_x.push(measures.register(format!("Mean X^{}", i)));
powers_of_x.push(simulation.add_measure(format!("Mean X^{}", i)));
}

// The entry-point function. It will parse the command line arguments and
// set up the simulation parameters.
ergothic::run_simulation(
"mean values of powers of [0..1]", measures, |s: &MySample, ms| {
simulation.run(|s: &MySample, ms| {
// This is the measurement lambda. Its job is to measure the registered
// measures in a given statisticle sample `s` and record the values in `ms`.
for i in 0..10 {
Expand Down

0 comments on commit 6c9ec9c

Please sign in to comment.