mod tps_shoot

module tps_shoot

Transition-path / shooting moves adapted from pnastps (TYCeTS / PNAS 2019).

Source algorithm (pnastps-master/code/tps-only_pnas/main.cpp): 1. Maintain a path of K+1 frames connecting reactant basin A to product

basin B, distinguished by an order parameter with thresholds (structOP_a, structOP_b).

  1. Shooting: pick a random interior frame, re-propagate forward or backward (backward uses reversed velocities), accept if the trial path remains reactive (still connects A to B).

  2. Shifting: extend one end and drop the other while preserving reactivity.

Continuous-box analogue for black-box optimization (no LAMMPS / MD): - Path frames are points in the box; the path is a linear (or noisy)

interpolation between two archived endpoints from distinct basins.

  • Order parameter defaults to true objective value along the path (lower is better): basin A is “trapped / high”, basin B is “good / low”. Geometric reactivity is also available: endpoints stay near the archived A/B seeds.

  • Shooting re-propagates half-paths by isotropic noise + optional local descent; accept iff the trial path is reactive (uniform prior on the reactive ensemble, matching pnastps).

  • Every evaluated frame is charged to the true objective; the best true-F point found on accepted or trial paths is available to the caller for incumbent updates.

Pure functions below have no I/O and are unit-tested without CUTEst.

Functions

fn accept_reactive_shoot(trial_reactive: bool) -> bool

TPS accept rule for shooting under a flat prior on reactive paths: accept the trial if and only if it is reactive (pnastps forward/backward shoot). Non-reactive trials are rejected with probability 1.

fn apply_shoot<R, F>(path: &[Array1<f64>], shoot: usize, direction: ShootDirection, x_a: ArrayView1<f64>, x_b: ArrayView1<f64>, noise_scale: f64, rng: &mut R, mut reflect: F) -> Vec<Array1<f64>>
where
    R: Rng + ?Sized,
    F: FnMut(Array1<f64>) -> Array1<f64>

Apply a shooting move: keep one half of the path, replace the other half by linear segments from a noisy shoot point toward the free endpoint seed.

noise_scale is absolute coordinate noise at the shoot point. reflect maps a point into the feasible box (caller supplies reflection).

fn best_frame_index(ops: &[f64]) -> Option<usize>

Index of the best (lowest) finite order-parameter frame.

fn linear_path(x_a: ArrayView1<f64>, x_b: ArrayView1<f64>, n_frames: usize) -> Vec<Array1<f64>>

Linear path of n_frames points from x_a to x_b (inclusive).

fn path_is_reactive(ops: &[f64], basin_a_max: f64, basin_b_min: f64) -> bool

Classical TPS reactivity on a scalar order-parameter series.

Matches pnastps: start in reactant (op[0] <= a) and end in product (op[last] >= b`) with a < b`. For objective-as-OP where lower is better, pass negated values or use ``path_reactive_objective.

fn path_reactive_geometric(path: &[Array1<f64>], x_a: ArrayView1<f64>, x_b: ArrayView1<f64>, tol: f64) -> bool

Geometric reactivity: endpoints stay near the archived seeds.

fn path_reactive_objective(ops: &[f64], high_threshold: f64, low_threshold: f64) -> bool

Reactivity when the order parameter is the objective (lower is better).

Path starts “bad” (ops[0] >= a`) and ends “good” (``ops[last] <= b`) with a > b (high-to-low).

fn pick_shoot_direction<R: Rng + ?Sized>(rng: &mut R) -> ShootDirection

Uniform random shoot direction.

fn pick_shoot_index<R: Rng + ?Sized>(n_frames: usize, rng: &mut R) -> usize

Pick a uniform interior shooting index in 1..K-1 for a path of length K+1 frames (pnastps random_shootpoint(1, K-1)).

Enums

enum ShootDirection

Shooting direction: forward keeps the left half and re-propagates right; backward keeps the right half and re-propagates left (pnastps velocity reversal is represented as re-propagating the opposite segment).

Forward

Re-propagate frames shoot..end.

Backward

Re-propagate frames 0..shoot.