- exception elizur.life.InvalidAge
Raised when an actuarial age input (x) is invalid.
- exception elizur.life.InvalidEPVInputs
Custom exception raised for invalid expected present value inputs.
- exception elizur.life.InvalidInterval
Raised when an actuarial interval input (n or t) is invalid.
- class elizur.life.LifeTable(table: Iterable[float] | ndarray, name: str = '', description: str = '', initial_pop: int = 100000)
Single-decrement life table for actuarial calculations.
Computes standard actuarial functions including qx, px, lx, dx, ex, mx, commutation functions (Dx, Nx, Sx, Cx, Mx, Rx), and actuarial present values of annuities and insurances.
- Parameters:
table – Iterable of annual failure probabilities (qx values) in sequential order starting from age 0, e.g. (q0, q1, …, qω).
name – Optional descriptive name for the table.
description – Optional extended description of the table.
initial_pop – Radix (l0) — the starting population size.
initial_pop – the size of the initial population (l0)
- Ax(x: int, i: float) float
- Parameters:
x – start age
i – interest rate
- Returns:
Actuarial present value of level whole insurance
- Axn(x: int, i: float, n: int) float
- Parameters:
x – start age
i – interest rate
n – number of periods in the temporary insurance
- Returns:
Actuarial present value of level temporary insurance
- Cx(x: int, i: float) float
Actuarial commutation function Cx
- Parameters:
x – start age
i – interest rate
- Returns:
Failures between x and x + 1 discounted for x years
- Dx(x: int, i: float) float
Actuarial commutation function Dx
- Parameters:
x – start age
i – interest rate
- Returns:
Population at age x discounted for x years
- IAx(x: int, i: float) float
- Parameters:
x – start age
i – interest rate
- Returns:
Actuarial present value of increasing whole insurance
- IAxn(x: int, i: float, n: int) float
- Parameters:
x – start age
i – interest rate
n – number of periods in the temporary insurance
- Returns:
Actuarial present value of increasing temporary insurance
- Mx(x: int, i: float) float
Actuarial commutation function Mx
- Parameters:
x – start age
i – interest rate
- Returns:
Sum of Cs from age x and onward
- Nx(x: int, i: float) float
Actuarial commutation function Nx
- Parameters:
x – start age
i – interest rate
- Returns:
Sum of Ds from age x and onward
- Rx(x: int, i: float) float
Actuarial commutation function Rx
- Parameters:
x – start age
i – interest rate
- Returns:
Sum of Ms from age x and onward
- Sx(x: int, i: float) float
Actuarial commutation function Sx
- Parameters:
x – start age
i – interest rate
- Returns:
Sum of Ns from age x and onward
- ax(x: int, i: float) float
- Parameters:
x – start age
i – interest rate
- Returns:
Actuarial present value of a level perpetuity
- ax_due(x: int, i: float) float
- Parameters:
x – start age
i – interest rate
- Returns:
Actuarial present value of a level perpetuity due
- axn(x: int, i: float, n: int) float
- Parameters:
x – start age
i – interest rate
n – length of payments
- Returns:
Actuarial present value of a temporary annuity
- axn_due(x: int, i: float, n: int) float
- Parameters:
x – start age
i – interest rate
n – length of payments
- Returns:
Actuarial present value of a temporary annuity due
- dx(x: int) float
- Parameters:
x – start age
- Returns:
The number of failures between ages x and x + 1
- get_lxs() tuple[float, ...]
This method is deprecated and will be removed in v1.0.0
The recommended method is to use the ‘lxs’ property
- Returns:
A tuple of the population counts (lxs)
- get_pxs() tuple[float, ...]
This method is deprecated and will be removed in v1.0.0
The recommended method is to use the ‘pxs’ property
- Returns:
A tuple of the survival probabilities (pxs), e.g., (0p1, 2p1, …, 100p99)
- get_qxs() tuple[float, ...]
This method is deprecated and will be removed in v1.0.0
The recommended method is to use the ‘qxs’ property
- Returns:
A tuple of the failure probabilities (qxs), e.g., (0q1, 2q1, …, 100q99)
- lx(x: int) float
- Parameters:
x – age
- Returns:
The population size at time x. This is the same thing as the number of person years lived between age x and x + 1.
- mx(x: int) float
- Parameters:
x – start age
- Returns:
The central failure rate between ages x and x + 1
- ndx(n: int, x: int) float
- Parameters:
n – width of failure interval in years
x – start age
- Returns:
The number of failures between ages x and x + n
- nlx(n: int, x: int) float
- Parameters:
n – width of failure interval in years
x – start age
- Returns:
The number of person years lived between ages x and x + n
- nmx(n: int, x: int) float
- Parameters:
x – start age
- Returns:
The central failure rate between ages x and x + n
- npx(n: int, x: int) float
- Parameters:
n – width of survival interval in years
x – start age
- Returns:
The probability of survival between ages x and x + n
- npxs(n: int) ndarray
- Parameters:
n – width of survival interval in years
- Returns:
The probability of survival between ages x and x + n for all ages
- nqx(n: int, x: int) float
- Parameters:
n – width of failure interval in years
x – start age
- Returns:
The probability of failure between ages x and x + n
- nqxs(n: int) ndarray
- Parameters:
n – width of failure interval in years
- Returns:
The probability of failure between ages x and x + n for all ages
- px(x: int) float
- Parameters:
x – start age
- Returns:
The probability of survival between the ages x and x + 1
- qx(x: int) float
- Parameters:
x – start age
- Returns:
The probability of failure between the ages x and x + 1
- to_frame() DataFrame
Export the life table as a Polars DataFrame.
Each row represents one age from 0 to ω-1. The resulting DataFrame is suitable for joining against policy-level DataFrames on the
agecolumn in actuarial projection engines (e.g. IFRS 17 cashflow models).- Returns:
age: integer age from 0 to table_size - 1qx: probability of death between age x and x + 1px: probability of survival between age x and x + 1lx: expected number of lives at age x (radix = initial_pop)dx: expected number of deaths between age x and x + 1mx: central death rate between age x and x + 1
- Return type:
A Polars DataFrame with columns
- tqxn(t: int, n: int, x: int) float
- Parameters:
t – width of the failure interval in years
n – width of the survival interval in years
x – start age
- Returns:
The probability of surviving from age x to x + n and then failing between age x + n and age x + n + t
- class elizur.life.MultiDecrementTable(mortality: LifeTable, lapse_rates: Iterable[float] | ndarray)
Two-decrement life table combining mortality and lapse decrements.
Applies the independent decrements assumption with the UDD (Uniform Distribution of Deaths) approximation to convert single-decrement probabilities into multi-decrement probabilities. This is the standard actuarial approach for IFRS 17 cashflow projection models where policies exit either by death or voluntary lapse.
Under UDD, the multi-decrement probabilities are approximated as:
q^(d)_x ≈ q’(d)_x × (1 - q’(w)_x / 2) q^(w)_x ≈ q’(w)_x × (1 - q’(d)_x / 2) q^(τ)_x = 1 - (1 - q’(d)_x) × (1 - q’(w)_x)
where q’(d) and q’(w) are the single-decrement (independent) mortality and lapse probabilities respectively.
- Parameters:
mortality – Single-decrement mortality
LifeTable. The lapse rates must be aligned to the same age indices as this table.lapse_rates – Annual lapse (withdrawal) rates indexed by age, starting from age 0. Must have the same length as the mortality table.
- Raises:
ValueError – If
lapse_rateslength does not match the mortality table size.
- dx_d(x: int) float
Expected deaths between age x and x + 1 in the multi-decrement table.
- Parameters:
x – Attained age.
- Returns:
Expected number of deaths between age x and x + 1.
- Raises:
InvalidAge – If x is negative.
- dx_w(x: int) float
Expected lapses between age x and x + 1 in the multi-decrement table.
- Parameters:
x – Attained age.
- Returns:
Expected number of lapses between age x and x + 1.
- Raises:
InvalidAge – If x is negative.
- lx_tau(x: int) float
Expected number of lives in the multi-decrement table at age x.
- Parameters:
x – Attained age.
- Returns:
Expected lives at age x under both mortality and lapse decrements.
- Raises:
InvalidAge – If x is negative.
- npx_tau(n: int, x: int) float
Probability of surviving all decrements for n years from age x.
- Parameters:
n – Number of years.
x – Starting age.
- Returns:
Probability of surviving both mortality and lapse decrements from age x to age x + n.
- Raises:
InvalidAge – If x is negative.
InvalidInterval – If n is not positive.
- px_tau(x: int) float
Total multi-decrement survival probability at age x.
- Parameters:
x – Attained age.
- Returns:
Probability of surviving all decrements between age x and x + 1.
- Raises:
InvalidAge – If x is negative.
- qx_d(x: int) float
Multi-decrement probability of death at age x.
- Parameters:
x – Attained age.
- Returns:
Probability of decrement by death between age x and x + 1 in the multi-decrement table.
- Raises:
InvalidAge – If x is negative.
- qx_tau(x: int) float
Total multi-decrement probability at age x.
- Parameters:
x – Attained age.
- Returns:
Probability of decrement by any cause between age x and x + 1.
- Raises:
InvalidAge – If x is negative.
- qx_w(x: int) float
Multi-decrement probability of lapse at age x.
- Parameters:
x – Attained age.
- Returns:
Probability of decrement by lapse between age x and x + 1 in the multi-decrement table.
- Raises:
InvalidAge – If x is negative.
- to_frame() DataFrame
Export the multi-decrement table as a Polars DataFrame.
Each row represents one age from 0 to ω-1. The resulting DataFrame includes both the original single-decrement rates and the computed multi-decrement probabilities, making it suitable for joining against policy-level DataFrames in projection engines.
- Returns:
age: integer age from 0 to table_size - 1qx_prime_d: single-decrement mortality rate q’(d)_xqx_prime_w: single-decrement lapse rate q’(w)_xqx_d: multi-decrement mortality probability q^(d)_xqx_w: multi-decrement lapse probability q^(w)_xqx_tau: total decrement probability q^(τ)_xpx_tau: total survival probability p^(τ)_xlx_tau: expected lives in multi-decrement tabledx_d: expected deaths in multi-decrement tabledx_w: expected lapses in multi-decrement table
- Return type:
A Polars DataFrame with columns
- elizur.life.annuity_due_fv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Future value of annuity of n years with an interest rate of i
- elizur.life.annuity_due_pv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Present value of annuity of n years with an interest rate of i
- elizur.life.annuity_fv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Future value of annuity of n years with an interest rate of i
- elizur.life.annuity_pv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Present value of annuity of n years with an interest rate of i
- elizur.life.decreasing_annuity_due_fv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Future value of a decreasing annuity due of n years with an interest rate of i. It is assumed that the annuity payment decrements by 1 each period.
- elizur.life.decreasing_annuity_due_pv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Present value of a decreasing annuity due of n years with an interest rate of i. It is assumed that the annuity payment decrements by 1 each period.
- elizur.life.decreasing_annuity_fv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Future value of a decreasing annuity of n years with an interest rate of i. It is assumed that the annuity payment decrements by 1 each period.
- elizur.life.decreasing_annuity_pv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Present value of a decreasing annuity of n years with an interest rate of i. It is assumed that the annuity payment decrements by 1 each period.
- elizur.life.discount_factor(i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
i – interest rate in decimal form
- Returns:
The related discount factor
- elizur.life.discount_rate(i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
i – interest rate in decimal form
- Returns:
The related discount rate
- elizur.life.expected_present_value(cash_flows: Iterable | ndarray, probabilities: Iterable | ndarray, interest_rates: Iterable | ndarray) float | ndarray
This function is useful for calculating variable streams of cash flows, interest rates, and probabilities.
- Parameters:
cash_flows – payouts from time 0 to n, where time n is the last
payout (possible)
e.g. (cf0, cf1, cf2, ..., cfn-1, cfn)
:param : :type : cf0, cf1, cf2, …, cfn-1, cfn :param probabilities: probability of a cash flow occuring from time
0 to n, e.g., (1p0, 2p1, 3p2, …, npn-1)
- Parameters:
interest_rates – collection of interest rates to use for discounting, where each interest rate is for one period, e.g., (i0to1, i1to2, …, in-1ton)
- Returns:
The expected present value
Example
Given the probabilities: 1p0 = 0.98, 2p1=0.94, 3p2=0.91
annuity(x=0, i=0.07, n=3)
expected_present_value((1, 1, 1), (0.98, 0.94, 0.91), (0.07, 0.07, 0.07))
The two methods of calculating the present value of an annuity are the same
Additionally a two-dimensional arrays of inputs can be provided to perform multiple expected present values at once. The work flows below produce the same results:
expected_present_value((1, 1, 1), (0.98, 0.94, 0.91), (0.07, 0.07, 0.07))
expected_present_value((1, 1, 1), (0.88, 0.84, 0.81), (0.06, 0.06, 0.06))
expected_present_value((1, 1, 1), (0.78, 0.74, 0.71), (0.05, 0.05, 0.05))
- expected_present_value(
- np.array([
[1, 1, 1], [1, 1, 1], [1, 1, 1]
]), np.array([
[0.98, 0.96, 0.91], [0.88, 0.86, 0.81], [0.78, 0.76, 0.71]
]), np.array([
[0.07, 0.07, 0.07], [0.06, 0.06, 0.06], [0.05, 0.05, 0.05]
])
)
- elizur.life.geo_increasing_annuity_pv(n: int | Iterable | ndarray, i: int | Iterable | ndarray, k: int | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
k – periodic payment growth rate
- Returns:
Present value of a geometrically increasing annuity of n years with an interest rate of i and payment growth rate of k.
- elizur.life.increasing_annuity_due_fv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Future value of an increasing annuity due of n years with an interest rate of i. It is assumed that the annuity payment increments by 1 each period.
- elizur.life.increasing_annuity_due_pv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Present value of an increasing annuity due of n years with an interest rate of i. It is assumed that the annuity payment increments by 1 each period.
- elizur.life.increasing_annuity_fv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Future value of an increasing annuity of n years with an interest rate of i. It is assumed that the annuity payment increments by 1 each period.
- elizur.life.increasing_annuity_pv(n: int | Iterable | ndarray, i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
n – years
i – periodic interest rate in decimal form
- Returns:
Present value of an increasing annuity of n years with an interest rate of i. It is assumed that the annuity payment increments by 1 each period.
- elizur.life.interest_rate(d: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
d – discount rate in decimal form
- Returns:
The related interest rate in decimal form
- elizur.life.perpetuity_due_pv(i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
i – periodic interest rate in decimal form
- Returns:
Present value of a perpetuity due with an interest rate of i
- elizur.life.perpetuity_pv(i: float | Iterable | ndarray) float | Iterable | ndarray
- Parameters:
i – periodic interest rate in decimal form
- Returns:
Present value of a perpetuity with an interest rate of i
- elizur.life.read_soa_csv_mort_table(file_path: str, encoding: str = 'Windows-1252', delimiter: str = ',') SoaTable
Parse an SOA CSV mortality table file.
- Parameters:
file_path – The full file system path to the csv.
encoding – The text encoding of the csv data. Defaults to ‘Windows-1252’.
delimiter – The delimiter of the csv data. Defaults to ‘,’.
- Returns:
A SoaTable with ‘metadata’ and ‘values’ keys.
- elizur.life.validate_age(func: F) F
Validate that the age argument
xis non-negative.- Parameters:
func – A method that accepts an age parameter named
x.- Returns:
The wrapped function with age validation applied.
- Raises:
InvalidAge – If
xis less than 0.
- elizur.life.validate_interval(func: F) F
Validate that the interval argument
nis positive.- Parameters:
func – A method that accepts an interval parameter named
n.- Returns:
The wrapped function with interval validation applied.
- Raises:
InvalidInterval – If
nis less than or equal to 0.
- elizur.life.validate_t_interval(func: F) F
Validate that the failure interval argument
tis positive.- Parameters:
func – A method that accepts a failure interval parameter named
t.- Returns:
The wrapped function with failure interval validation applied.
- Raises:
InvalidInterval – If
tis less than or equal to 0.
Life
- Annuity
annuity_due_fv()annuity_due_pv()annuity_fv()annuity_pv()decreasing_annuity_due_fv()decreasing_annuity_due_pv()decreasing_annuity_fv()decreasing_annuity_pv()discount_factor()discount_rate()geo_increasing_annuity_pv()increasing_annuity_due_fv()increasing_annuity_due_pv()increasing_annuity_fv()increasing_annuity_pv()interest_rate()perpetuity_due_pv()perpetuity_pv()
- Table
- LifeTable
LifeTableLifeTable.qx()LifeTable.px()LifeTable.lx()LifeTable.dx()LifeTable.ex()LifeTable.mx()LifeTable.nqx()LifeTable.nqxs()LifeTable.npx()LifeTable.npxs()LifeTable.nlx()LifeTable.ndx()LifeTable.nmx()LifeTable.tqxn()LifeTable.tqxns()LifeTable.Dx()LifeTable.Nx()LifeTable.Sx()LifeTable.Cx()LifeTable.Mx()LifeTable.Rx()LifeTable.Ax()LifeTable.Axn()LifeTable.IAx()LifeTable.IAxn()LifeTable.ax()LifeTable.axn()LifeTable.ax_due()LifeTable.axn_due()LifeTable.to_frame()LifeTable.get_lxs()LifeTable.get_qxs()LifeTable.w
- MultiDecrementTable
- LifeTable
- Util