run_monte_carlo_adaptive_seeded

Function run_monte_carlo_adaptive_seeded 

Source
pub fn run_monte_carlo_adaptive_seeded(
    base_inputs: &BallisticInputs,
    base_wind: &WindConditions,
    params: &MonteCarloParams,
    convergence: &McConvergence,
    hit_radius_m: f64,
    seed: u64,
) -> Result<AdaptiveMcReportV1, String>
Expand description

Runs a Monte Carlo hit-probability estimate that decides its own sample size, from an explicit seed.

§What this buys over the fixed-count path

run_monte_carlo_with_wind_and_direction_std_dev_seeded runs exactly params.num_simulations trials and reports a point estimate; whether that count was enough is left to the caller to guess. This instead runs until the answer is as precise as the caller asked for, and reports the achieved precision either way. params.num_simulations is ignored here – the sample count comes from convergence, and McConvergence::min_samples defaults to the same 1_000 so the floor matches the legacy default.

§Why the interval is anytime-valid

Stopping when the interval looks tight enough is optional stopping, and a fixed-n interval (Wilson, Wald, anything) checked repeatedly that way has no coverage guarantee: the error rate grows with the number of peeks. BernoulliConfidenceSequence is instead valid at every n simultaneously, so a data-dependent stopping rule is legitimate. The price is a strictly wider interval at any given n than the fixed-n MonteCarloResults::hit_probability_wilson would report on the same counts. Paying it is the point.

§The trial is the same trial

Each trial is MonteCarloTrialSampler::sample_one_trial (crate-internal), the same body and the same six-draw sequence the legacy loop runs, and the hit test is MonteCarloResults::position_is_hit, the same predicate MonteCarloResults::hit_probability counts with. A trial that never reached the target plane is a definite miss and stays in the denominator, exactly as it does there. Wind direction is not dispersed: MonteCarloParams has no direction-sigma field, so this passes 0.0, matching run_monte_carlo_with_wind.

§Sample accounting

Trials are run in batches of McConvergence::batch_size (the last batch truncated so the ceiling is never overshot), and the stopping rule is evaluated after each batch: stop with McStopReason::TargetHalfWidthMet once at least min_samples trials are in and the half-width is at or below target_half_width; stop with McStopReason::MaxSamplesReached once max_samples trials have been attempted.

The report carries three cardinalities, and they are three different numbers:

  • attempts – trials drawn. This is what max_samples caps.
  • samples – trials that produced an outcome, i.e. the n behind hit_probability and the confidence interval.
  • arrivals – trials that reached the target plane, i.e. the n behind the three at-target statistics.

attempts >= samples >= arrivals always. A trial whose solve fails is dropped rather than counted as a miss – the legacy loop’s behaviour, preserved so the two paths cannot disagree about what a solver failure means – but it still consumes an attempt, so it shows up as attempts > samples. With no dropped trials the two are equal, which is the normal case; when they differ, samples can finish below min_samples, and the honest report of that is MaxSamplesReached with the smaller n and the correspondingly wider interval. A trial that solved but fell short of the target plane is a definite miss: it is a sample (in hit_probability’s denominator) but not an arrival, so it shows up as samples > arrivals. A run in which every trial was dropped is an error, not a report.

§hit_radius_m is not validated

Every McConvergence field is Err-checked up front, but hit_radius_m itself is not: a NaN or negative radius makes MonteCarloResults::position_is_hit false for every trial, yielding p = 0.0 with a tight interval and (usually) a McStopReason::TargetHalfWidthMet stop rather than an error. This is deliberate, not an oversight – it matches MonteCarloResults::hit_probability’s equally lenient legacy posture on the same input, so this path cannot diverge from the fixed-count one over how a bad radius is treated.

§Errors

Returns Err if convergence is not usable (McConvergence::validate, which names the offending field), if the baseline solve or an input distribution is invalid, or if no trial at all produced an outcome.