Skip to content

Population histories¤

Population histories specify effective population sizes and interval durations. A demographic transition combines a history, frequency map, backend, and evolution method to propagate distributions across the history.

drifft.Demography(equinox.Module) [source] ¤

A population history specified at successive generation boundaries.

Sizes run from oldest to newest. Each interval holds the source size for generations[i] - 1 generations, then changes size on the final generation. Repeated sizes are valid; a single size with no durations is an identity history. No equilibrium initialization is implied.

initial_ne property ¤

Initial diploid effective population size, ne[0], as a Python integer.

final_ne property ¤

Final diploid effective population size, ne[-1], as a Python integer.

total_generations property ¤

Total interval duration as a Python integer; zero for an identity history.

__init__(self, ne: collections.abc.Iterable[int] | jax.Array, generations: collections.abc.Iterable[int] | jax.Array) -> None ¤

Initialize Demography.

Arguments:

  • ne: Nonempty sequence of positive integer diploid effective population sizes, ordered oldest to newest. Each size represents 2 * ne gene copies.
  • generations: Positive integer durations between successive sizes, with exactly one fewer entry than ne.

Lists and concrete one-dimensional integer arrays are converted to host tuples. Construct outside JIT.

Returns:

None.

Raises:

ValueError for invalid lengths, noninteger entries, or nonpositive entries. Population sizes and durations are structural, not differentiable parameters.


drifft.DemographicTransition(equinox.Module) [source] ¤

Compose constant-size evolution and rectangular boundary transitions.

An interval of g generations holds its source size for g-1 generations, then changes size on its last generation. Sequential provides a matched expectation transpose. Both Krylov methods support all backends for forward evolution only. Frequency-map parameters remain differentiable array leaves.

__init__(self, demography: Demography, *, backend: collections.abc.Callable[[int], drifft._backend._base.AbstractTransitionBackend], frequency_map: AbstractFrequencyMap, boundary_backend: collections.abc.Callable[[int], drifft._backend._base.AbstractTransitionBackend] | None = None, method: drifft._evolution.methods.AbstractEpochMethod | None = None) -> None ¤

Prepare reusable geometry outside JIT.

Arguments:

  • demography: Population history, oldest to newest.
  • backend: Factory receiving a gene-copy count for constant-size geometry.
  • frequency_map: Process shared by every generation.
  • boundary_backend: Factory for rectangular transitions; defaults to the hold geometry for all backends.
  • method: Geometry-free epoch algorithm; defaults to Sequential().

Returns:

None. Prepares one geometry per distinct size, sharing hold and boundary geometry when the same factory is used.

Raises:

TypeError for unsupported combinations, including histories without holds; ValueError for incorrect backend sizes. RationalKrylov selects dense LU for Jacobi and GMRES for other transition backends. Dense is intended for small reference calculations; optimized backends avoid a dense population matrix.

advance(self, distribution: Array, *, throw: bool = True) -> DemographicResult ¤

Propagate full population mass to the final generation boundary.

Arguments:

  • distribution: Real vector of length 2 * initial_ne + 1, converted to float64.
  • throw: Raise on numerical failure; False returns status and diagnostics. Under vmap a failure with True may fail the whole batch.

Returns:

DemographicResult containing final mass and each interval's outcome.

Raises:

ValueError for incompatible shapes; runtime errors for invalid process domains or, with throw=True, numerical failure. No mass normalization occurs.

advance_segregating(self, distribution: Array, *, mutation_rate: float | jax.Array = 0.0, throw: bool = True) -> DemographicResult ¤

Evolve interior mass with singleton immigration after every generation.

Arguments:

  • distribution: Real interior mass of length 2 * initial_ne - 1.
  • mutation_rate: Finite nonnegative scalar per-copy rate. Each generation adds 2 * destination_ne * mutation_rate at count one.
  • throw: Raise on numerical failure; under vmap may fail the whole batch.

Returns:

DemographicResult; the distribution has length 2 * final_ne - 1.

Raises:

ValueError for invalid shapes. Invalid mutation rates and process domains raise even with throw=False; numerical failures otherwise return status.

expect(self, values: Array) -> Array ¤

Compute the matched expectation transpose for Sequential histories.

Arguments:

  • values: Real vector of length 2 * final_ne + 1, converted to float64.

Returns:

Float64 expectations of length 2 * initial_ne + 1.

Raises:

ValueError for incompatible shapes or a non-Sequential method, which does not provide a matched transpose of its input-dependent approximation.


drifft.DemographicResult(builtins.tuple) [source] ¤

Final mass and per-interval numerical outcomes, without a total error certificate.

status retains the first numerical failure. Identity histories have empty diagnostics and still check mass finiteness. No factorization or basis is retained.

Fields:

  • distribution: Float64 mass of length 2 * final_ne + 1, or 2 * final_ne - 1 for segregating evolution; not normalized.
  • converged: Scalar boolean, true when the entire history succeeded.
  • status: First numerical failure in chronological order, or success.
  • diagnostics: Tuple of IntervalDiagnostics, one per interval in order. Local error estimates are not a bound on the total propagated error.

drifft.IntervalDiagnostics(builtins.tuple) [source] ¤

Numerical outcome for one complete demographic interval.

source_ne and destination_ne are diploid population sizes; generations includes both the hold and final boundary generation. error_estimate covers only the hold power approximation, while converged and status also account for nonfinite boundary output.

Fields:

  • source_ne, destination_ne: Python integers giving diploid sizes.
  • generations: Interval duration, including its final boundary generation.
  • error_estimate: Scalar absolute L1 hold-power estimate, zero without a hold.
  • converged: Scalar boolean for the complete interval.
  • status: First hold or boundary failure, or successful EvolutionStatus.