ExitTable#

ExitTable extends DecrementTable for exit / turnover tables. The governing decrement is the exit rate \(o_x\), which represents the probability that a contract or member aged \(x\) exits within one year (employment termination, withdrawal, lapse, or surrender).

Exit tables are used in persistency analysis, lapse-risk pricing, and multi-decrement models for group pension and collective insurance products. Table files carry \(o_x\) columns (prefixed ox_m, ox_f, or ox_u) and may include generational improvement factors for cohort-based exit rates.

See also

Table Taxonomy — Overview of all table types and decrement conventions.
Using Actuarial Tables — Loading and inspecting tables.
Modifying Decrements — Scaling, aggravated risk, and table_combination.
Mortality Improvement (MI) — Generational tables and improvement factors.

class lactuca.ExitTable(table_name: str | list | tuple, sex: Literal['m', 'f', 'u'] | Sequence[Literal['m', 'f', 'u']] | None = None, cohort: int | Sequence | None = None, unisex_blend: object = None, duration: int | str | Sequence | None = None, cartesian: bool = False, return_dict: bool = False, pending: bool = False, **_kw)#

Bases: DecrementTable

Concrete implementation of DecrementTable for exit/turnover tables.

ExitTable represents actuarial tables for exit/turnover probabilities (\(o_x\)), where \(o_x\) denotes the probability of exiting employment between ages \(x\) and \(x+1\). It provides all standard actuarial functions (lx, px, dx, tpx, tqx) but uses exit-specific nomenclature and blocks access to mortality and disability-specific methods.

To build combined multiple decrement models (mortality + exit + disability), use modify_qx() on the LifeTable with this ExitTable as a combination argument; ExitTable itself only combines with other ExitTable instances.

Construction accepts scalar arguments for a single instance, or sequences for vectorial creation (families, scenarios, pricing grids). See __new__() for full dispatch details.

Parameters:
  • table_name (str, list, or tuple) – Name of one or more exit table files (without .ltk extension). A list or tuple enables multi-table vectorial creation.

  • sex (str or sequence of str) – Single sex ('m', 'f', 'u') or sequence for vectorial creation.

  • cohort (int, sequence of int, or None, optional) – Birth year(s) for generational tables. If None, loads a period table. Broadcast and zip-alignment rules match __new__().

  • unisex_blend (float, list of float, or None, optional) – Male weight for unisex blending in \([0, 1]\) (0.0 = all female, 1.0 = all male). A list is accepted in zip mode (cartesian=False) to assign a distinct blend to each instance; scalar sex='u' broadcasts to the list length. See __new__().

  • duration (int, 'ult', sequence, or None, optional) – Duration slice for select-ultimate tables. Pass an integer >= start_duration for a select column, 'ult' for the ultimate column, or None for non-select tables.

  • cartesian (bool, optional) – If True, create the full Cartesian product of all table_name, sex, cohort, and duration values. All table names must share the same generational structure and the same select structure. With cartesian=True, a unisex_blend sequence is allowed only when every sex value is 'u' (fifth cartesian axis). A scalar unisex_blend is replicated uniformly to all combinations where sex='u'. Default is False (zip/broadcast alignment).

  • return_dict (bool, optional) – If True, return a dict mapping TableKey to each ExitTable instance instead of a plain tuple. Default is False.

Returns:

Single ExitTable when sex is a scalar string, table_name is a bare string (not a list/tuple), cohort and duration are scalar or None, no sequence dimensions are provided, and return_dict=False. A tuple when any parameter is a sequence or cartesian=True and return_dict=False (including length-1 tuples). A dict keyed by TableKey when return_dict=True.

Return type:

ExitTable or tuple[ExitTable, …] or dict

Notes

  • ExitTable uses \(o_x\) internally where LifeTable uses \(q_x\) and DisabilityTable uses \(i_x\).

  • All probability calculations (px, tpx, tqx) work identically to other decrement tables.

  • Can be combined with other ExitTable instances via modify_ox() for competitive exit decrements.

  • Inherits the modification system from DecrementTable.

  • Zip mode (default): table_name, sex, cohort, and duration are aligned element-wise (or broadcast when length is 1).

  • Cartesian mode (cartesian=True): every combination is created — suited to sensitivity grids and pricing studies, not sparse portfolio processing.

  • A ResourceWarning is emitted when more than 100 instances are created in a single constructor call.

Raises:
  • FileNotFoundError – If a table file does not exist in the actuarial tables directory.

  • ValueError – If the table is not an exit table; if cohort, sex, or duration sequences have incompatible lengths; if unisex_blend is out of \([0, 1]\) or provided when sex is not 'u'; if sex='u' and the table lacks a native unisex column while unisex_blend is None; if cartesian=True and table names mix generational and period tables or mix select and non-select tables; or if cartesian=True and unisex_blend is a sequence while sex contains any value other than 'u'.

  • TypeError – If cohort, duration, sex, or unisex_blend arguments have invalid types.

  • NotImplementedError – If qx(), ix(), ex(), or modify_qx() are called.

See also

DecrementTable

Abstract base class providing core decrement logic.

TableKey

Structured lookup key for return_dict=True results.

LifeTable

Mortality table implementation.

DisabilityTable

Disability incidence table implementation.

Examples

>>> from lactuca import ExitTable, TableKey
>>> et = ExitTable('DummyEXIT', sex='m')
>>> et.ox(30) >= 0.0
True
>>> # Zip mode: two sexes
>>> et_m, et_f = ExitTable('DummyEXIT', ('m', 'f'))
>>> # Cartesian product: 2 sexes → 2 instances (scalar cohort)
>>> tables = ExitTable('DummyEXIT', ('m', 'f'), cartesian=True)
>>> len(tables)
2
>>> # Dict return keyed by TableKey
>>> d = ExitTable('DummyEXIT', ('m', 'f'), return_dict=True)
>>> et_m = d[TableKey('DummyEXIT', 'm')]
ex(x: object = None, m: Literal[1, 2, 3, 4, 6, 12, 14, 24, 26, 52, 365] = 1) None#

Blocked method: not available for ExitTable.

Raises:

NotImplementedError – Always raised. Life expectancy (ex) is not applicable to exit tables.

Notes

  • Life expectancy is a mortality-specific concept.

  • ExitTable focuses on exit/turnover probabilities, not life expectancy.

  • For life expectancy calculations, use LifeTable.

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable('DummyEXIT', sex='m')
>>> try:
...     et.ex(30)
... except NotImplementedError:
...     pass

See also

LifeTable

Mortality table class with ex (life expectancy) support.

ex_curtate(x: object = None) None#

Blocked method: not available for ExitTable.

Raises:

NotImplementedError – Always raised. Curtate life expectancy (ex_curtate) is not applicable to exit tables.

Notes

  • Life expectancy is a mortality-specific concept.

  • ExitTable focuses on exit/turnover probabilities, not life expectancy.

  • For curtate life expectancy, use LifeTable.

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable('DummyEXIT', sex='m')
>>> try:
...     et.ex_curtate(30)
... except NotImplementedError:
...     pass

See also

LifeTable

Mortality table class with ex_curtate support.

ix(x: object = None, m: Literal[1, 2, 3, 4, 6, 12, 14, 24, 26, 52, 365] = 1) None#

Blocked method: not available for ExitTable.

Raises:

NotImplementedError – Always raised. Use ox() instead for exit probabilities.

Notes

  • ExitTable does not support disability incidence rates (ix).

  • Use ox for exit/turnover probabilities.

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable('DummyEXIT', sex='m')
>>> try:
...     et.ix(30)
... except NotImplementedError as exc:
...     'ox' in str(exc)
True

See also

ExitTable.ox

Exit probability.

DisabilityTable

Use DisabilityTable class for disability incidence (\(i_x\)).

modify_ox(modifications: ModifyDecrement) None#

Apply modifications to exit rates (ox) for turnover/exit tables.

This method allows actuarial adjustments to the base exit table, such as scaling rates, shifting ages, applying aggravated risk factors, or combining with other ExitTable instances using independent competitive risks. All modifications are applied to a copy of the base rates and can be reset with reset_modifications().

Parameters:

modifications (dict) –

Dictionary specifying one or more modification operations. See ModifyDecrement TypedDict for supported keys:

  • ’age_shift’int

    Shift all ages by N years (drops first N ages).

  • ’decrement_multiplier’float

    Multiply all \(o_x\) values by a constant factor.

  • ’decrement_geometric_increase’tuple[float, int]

    Apply geometric growth to tail: (growth_rate, start_age).

  • ’aggravated_risk’float

    Apply aggravated risk transform: \(p_x \to p_x^f\), where \(f\) is the aggravated risk factor value.

  • ’table_combination’Union[ExitTable, list, tuple]

    Combine with one or more ExitTables using independent competitive risks (default) or UDD when combination_mode='udd'. ExitTable can only combine with ExitTable (e.g., voluntary vs. involuntary turnover). Age alignment, host length, implicit zero beyond shorter tables, and rejection rules are identical to modify_qx() — see Modifying Decrements.

  • ’combination_mode’'independent' or 'udd'

    Optional actuarial assumption for table_combination; see modify_qx().

Raises:
  • ValueError – If modification parameters are invalid or produce non-actuarial results.

  • TypeError – If modification keys or values have incorrect types.

Notes

  • Modifications are applied in iteration order (dict order in Python 3.7+).

  • ExitTable can only combine with ExitTable (e.g., voluntary vs. involuntary turnover). For combined Life+Exit or Life+Exit+Disability (Masa Activa) models, use modify_qx on the LifeTable.

  • Combined tables must have matching sex.

  • Final results are rounded to configured decimals (config.decimals.ox).

  • Use reset_modifications() to restore original base rates.

  • Non-accumulative: each call to modify_ox replaces any previous modification entirely — it always restarts from the unmodified base rates. To accumulate multiple operations, pass all keys in a single call as a dict, or call reset_modifications() explicitly between independent experiments.

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable("DummyEXIT", sex="m")
>>> base = et.ox(30)
>>> et.modify_ox({"decrement_multiplier": 0.8})
>>> et.ox(30) <= base
True

See also

DecrementTable.reset_modifications

Restore original base rates.

modify_qx(modifications: object = None) None#

Blocked method: not available for ExitTable.

Raises:

NotImplementedError – Always raised. Use modify_ox() instead for exit rate modifications.

Notes

  • ExitTable uses modify_ox for actuarial adjustments.

  • All modification functionality available via modify_ox.

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable('DummyEXIT', sex='m')
>>> try:
...     et.modify_qx({'decrement_multiplier': 0.9})
... except NotImplementedError as exc:
...     'modify_ox' in str(exc)
True

See also

ExitTable.modify_ox

Apply actuarial modifications to exit rates.

ox(x: object = None, m: Literal[1, 2, 3, 4, 6, 12, 14, 24, 26, 52, 365] = 1) object#

Return exit/turnover probability at age x.

Computes the probability that an active employee aged \(x\) exits (terminates employment) before age \(x + 1/m\), using \(o_x = 1 - p_x\) where \(p_x\) is the probability of retention. For fractional periods, uses \(\ell_x\) interpolation.

Parameters:
  • x (float, int, sequence of float, NDArray[np.float64], or None, optional) – Entry age(s). Pandas and Polars Series are accepted. If None, returns ox for all integer ages in the table.

  • m (PaymentFrequencyLiteral, optional) – Number of periods per year (1, 2, 3, 4, 6, 12, 14, 24, 26, 52, or 365). Default is 1.

Returns:

Exit probability(ies). Returns scalar if x is scalar, otherwise array matching x shape.

Return type:

float or np.ndarray

Notes

  • For integer ages and m=1, returns the precomputed \(o_x\) value from the table.

  • For fractional ages or m>1, uses \(\ell_x\) interpolation: \(o_x = 1 - \ell_{x+1/m} / \ell_x\)

  • If x is None, returns the full rounded decrement array (ages 0 to \(\omega\)).

  • All results rounded to config.decimals.ox.

  • Consistent with international actuarial practice.

Raises:
  • ValueError – If any age in x is negative.

  • TypeError – If x is not numeric, or if m is not a scalar integer.

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable('DummyEXIT', sex='m')
>>> et.ox(30) >= 0.0
True
>>> bool(et.ox(30, m=12) >= 0.0)
True
>>> vals = et.ox([25, 30, 35])
>>> vals.shape
(3,)

See also

DecrementTable.px

Probability of retention (complement of \(o_x\)).

DecrementTable.lx

Number of active employees at age \(x\).

DecrementTable.tqx

Probability of exit within t years.

qx(x: object = None, m: Literal[1, 2, 3, 4, 6, 12, 14, 24, 26, 52, 365] = 1) None#

Blocked method: not available for ExitTable.

Raises:

NotImplementedError – Always raised. Use ox() instead for exit probabilities.

Notes

  • ExitTable uses \(o_x\) (exit probability) instead of \(q_x\) (mortality).

  • All qx-related functionality is replaced by ox methods.

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable('DummyEXIT', sex='m')
>>> try:
...     et.qx(30)
... except NotImplementedError as exc:
...     'ox' in str(exc)
True

See also

ExitTable.ox

Exit probability (replacement for \(q_x\)).

LifeTable

Use LifeTable class for mortality rates.

summary() str#

Return a formatted summary of the exit table state and sample ox values.

Calls summary() for the common header block, then appends:

  • Decimals: ox=<n>

  • Sample ox values for the first and last 5 ages. When a modification is active, each line shows both the current and the original base value:

    ox(30) = 0.064 (original: 0.080)
    

    Without a modification the parenthetical is omitted.

Returns:

Multi-line summary string.

Return type:

str

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable("DummyEXIT", sex="m")
>>> summary = et.summary()
>>> "Decimals: ox=" in summary
True
>>> "Sample ox values (first 5):" in summary
True

See also

DecrementTable.reset_modifications

Restore base rates and clear modification state.

ExitTable.modify_ox

Apply modifications.

property decimals: _DecimalsConfig#

Access decimal precision settings for exit table actuarial functions.

This property provides convenient attribute-based access to global decimal precision configuration. All values are proxied dynamically from the Config singleton — no state is stored locally in the table instance. Commutation functions, mortality, life-expectancy, and disability-rate attributes are blocked and raise AttributeError.

Returns:

Decimal-precision proxy with attributes for exit-table actuarial columns. Available attributes:

  • ox : int — Exit rate \(o_x\) precision

  • lx : int — Survival function \(\ell_x\) precision

  • dx : int — Decrements \(d_x\) precision

  • px : int — Survival probability \(p_x\) precision

  • tpx : int — Multi-year survival \({}_t p_x\) precision

  • tqx : int — Multi-year decrement \({}_t q_x\) precision

Return type:

object

Raises:

AttributeError – If accessing a blocked property: qx, ix, ex, Lx, Tx, Dx, Nx, Sx, Cx, Mx, Rx, annuities, or insurances.

Notes

  • Read-only proxy: self.decimals.xxx = value raises AttributeError by design; use Config().decimals.xxx = value to change precision globally.

  • Global scope: Changes to Config.decimals are immediately visible through all table instances.

  • For permanent changes, use Config().decimals.ox = value or Config().set('decimals_ox', value).

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable('DummyEXIT', sex='m')
>>> isinstance(et.decimals.ox, int)
True
>>> isinstance(et.decimals.px, int)
True

See also

Config.decimals

Global decimal precision configuration.

property table_type: str#

Return the type identifier for this decrement table.

Returns:

Always returns ‘exit’ for ExitTable instances.

Return type:

str

Notes

  • Immutable property; cannot be modified after instantiation.

Examples

>>> from lactuca import ExitTable
>>> et = ExitTable('DummyEXIT', sex='m')
>>> et.table_type
'exit'

See also

DecrementTable

Base class providing core decrement logic.

ExitTable-specific members#

These members are defined on ExitTable itself and are not present on DecrementTable.

Actuarial methods#

ox

Return exit/turnover probability at age x.

Modification#

modify_ox

Apply modifications to exit rates (ox) for turnover/exit tables.

Inherited from DecrementTable#

The following members are inherited from DecrementTable. See the DecrementTable reference for full documentation of each member.

Note

qx, ix, ex, ex_curtate, and modify_qx are not available on ExitTable — the primary decrement is ox (exit / turnover rate). Calling any of the blocked methods raises NotImplementedError.

Actuarial methods#

lx

Return lx values (number of lives at age x) for the specified age(s).

px

Return probability of surviving one period (px) at age x.

tpx

Return interval survival probability tpx for all (x, t) combinations.

tqx

Return interval death probability tqx for all (x, t) combinations.

dx

Return \(d_x\) values (number of decrements between ages \(x\) and \(x+1\)).

Modification#

reset_modifications

Restore decrement to the original base values and clear all caches.

copy

Return a deep copy of the instance.

Display#

view_data

Return the computed instance data, optionally excluding normalized padding rows.

head

Return the first n rows of the computed instance data.

tail

Return the last n rows of the computed instance data, always ending at w.

State#

sex

Current sex used for calculations.

cohort

Current cohort (year of birth) for generational tables.

duration

Return the current policy duration for select or non-select tables.

unisex_blend

Male weight used to blend male/female rates into unisex rates.

w

Current upper age limit (omega), accounting for modifications.

modified

True if a modification is currently active on this table.

modifications_applied

List of modification descriptors applied in the current call.

is_select

Return True if the underlying table is a select-ultimate table.

metadata_pending

True when required metadata has not yet been supplied via configure() or setters.

Deferred construction#

configure

Configure table metadata atomically with a single rebuild.

batch_update

Context manager to batch multiple setter assignments into one rebuild.

See also TableRegistry and configure_all() in Table registry utilities and Deferred construction: pending, configure, and TableRegistry in Using Actuarial Tables.

Table metadata#

table_name

Name of the underlying actuarial table.

table

Access the underlying TableSource instance with table data and metadata.

generational

Whether the table includes cohort-based improvement factors.

base_year

Base year for generational improvement.

omega

Original terminal age from metadata (immutable).

start_age

Minimum defined age in the original table.

description

Human-readable table description from metadata.

valid_sexes

Valid sexes for this table (e.g. ['m', 'f']).

sex_independent

Whether rates are identical for both sexes.

generational_formula_type

Generational improvement formula type.

select

Whether this is a select-ultimate table.

select_period

Select period in years.

select_improvement_diagonal

Calendar-year index for generational improvement on select columns.

start_duration

Minimum integer duration.

mi_by_duration

Whether improvement factors are stored by policy duration.

mi_structure

Mortality improvement column layout tag.

grid_years

Projection calendar years for year-indexed MI tables.

file_name

Basename of the loaded table file.

file_path

Absolute path to the loaded table file.

data

Raw underlying table data (all columns, all sexes).

metadata

Raw metadata dictionary from the table file.