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

ex(x: int) float
Parameters:

x – start age

Returns:

The curtate life expectation at age x

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 age column in actuarial projection engines (e.g. IFRS 17 cashflow models).

Returns:

  • age: integer age from 0 to table_size - 1

  • qx: probability of death between age x and x + 1

  • px: probability of survival between age x and x + 1

  • lx: expected number of lives at age x (radix = initial_pop)

  • dx: expected number of deaths between age x and x + 1

  • mx: 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

tqxns(t: int, n: int) ndarray
Parameters:
  • t – width of the failure interval in years

  • n – width of the survival interval in years

Returns:

The probability of surviving from age x to x + n and then failing between age x + n and age x + n + t for all ages

property w: int

Returns: The limiting age of the life table

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_rates length 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:
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.

property table_size: int

Number of ages in the table.

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 - 1

  • qx_prime_d: single-decrement mortality rate q’(d)_x

  • qx_prime_w: single-decrement lapse rate q’(w)_x

  • qx_d: multi-decrement mortality probability q^(d)_x

  • qx_w: multi-decrement lapse probability q^(w)_x

  • qx_tau: total decrement probability q^(τ)_x

  • px_tau: total survival probability p^(τ)_x

  • lx_tau: expected lives in multi-decrement table

  • dx_d: expected deaths in multi-decrement table

  • dx_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 x is non-negative.

Parameters:

func – A method that accepts an age parameter named x.

Returns:

The wrapped function with age validation applied.

Raises:

InvalidAge – If x is less than 0.

elizur.life.validate_interval(func: F) F

Validate that the interval argument n is positive.

Parameters:

func – A method that accepts an interval parameter named n.

Returns:

The wrapped function with interval validation applied.

Raises:

InvalidInterval – If n is less than or equal to 0.

elizur.life.validate_t_interval(func: F) F

Validate that the failure interval argument t is 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 t is less than or equal to 0.

Life