Multiple life functions

In this blog post, we explore the topic of multiple life functions within actuarial science. Up until now, our focus has been on insurance products that revolved around the life of an individual. However, in this exploration, we direct our focus to insurance products that involve multiple insured persons. We'll begin by exploring the various types of such products and then roll up our sleeves to construct a basic model using Python, leveraging the cashflower package.

List of content:

  1. Multiple life functions
  2. The joint-life status
  3. The last-survivor status
  4. Modelling example

Multiple life functions

Expanding upon the concept of life insurance beyond an individual, we enter the realm of multiple life functions. These calculations find practical applications, particularly in pension scenarios. For instance, consider a married couple receiving payments as long as at least one of them survives. Another example involves group life insurance with benefits paid at the first death.

In single life insurance, we use the term "life", but in the context of multiple lives, we employ the term "status". The status can either "survive" or "fail".

There are two main types of statuses:

  • the joint-life status ("first death"),
  • the last-survivor status ("last death").

Before exploring these status types, it's essential to note that, while it's generally uncommon for the lives covered in a policy to be entirely independent, quantifying this dependence proves challenging. As a practical simplification, we often assume independence for calculation purposes.

The joint-life status

The joint-life status is a status that exists as long as all members survive and fails upon the first death. This status is denoted as:

$$ (x_{1} x_{2} ... x_{m}) $$

Here, \( x_{i} \) represents the age of member \( i \) of the group and \( m \) represents the total number of members. For instance, \( {}_{t} {p}_{xy} \) denotes the probability that a group of two people aged \( x \) and \( y \) both survives \( t \) periods. Let's denote \( T \) as the time until failure os a status. The status fails as soon as the first of the group members dies.

In the case of two lives, the probability of failure can be expressed as:

\( {}_{t} {q}_{xy} = \)

\( P(T \leq t) = \)

\( P(min(T_{x}, T_{y}) \leq t) = \)

\( 1 - P(T_{x} > t \; and \; T_{y} > t) = \)

\( 1 - P(T_{x} > 1) \cdot P(T_{y} > t) = \)

\( 1 - {}_{t} {p}_{x} \cdot {}_{t} {p}_{y} \)

The probability that at least one of them died is one minus the probability that both of them survived. We "change" \( and \) into \( \cdot \) because of the independence assumption.


$$ {}_{t} {p}_{xy} = {}_{t} {p}_{x} \cdot {}_{t} {p}_{y} $$

Thus, the joint-life status probability \( {}_{t} {p}_{xy} \) is the product of the individual probabilities \( {}_{t} {p}_{x} \) and \( {}_{t} {p}_{y} \).

The last-survivor status

The last-survivor status is a status that exists as long as at least one member is alive and fails upon the last death. The last-survivor status is denoted as:

$$ \overline{ (x_{1} x_{2} ... x_{m}) } $$

The last-survivor status fails when the last member dies.

In the case of two lives, the probability of failure can be expressed as:

\( {}_{t} {q}_{\overline{xy}} = \)

\( P(T \leq t) = \)

\( P(max(T_{x}, T_{y}) \leq t) = \)

\( P(T_{x} \leq t \; and \; T_{y} \leq t) = \)

\( P(T_{x} \leq t) \cdot P(T_{y} \leq t) = \)

\( {}_{t} {q}_{x} \cdot {}_{t} {q}_{y} \)


$$ {}_{t} {p}_{\overline{xy}} = {}_{t} {p}_{x} + {}_{t} {p}_{y} - {}_{t} {p}_{x} \cdot {}_{t} {p}_{y}$$

Modelling example

Now, let's put the theory into action by constructing a simple model using Python's cashflower package. If you are not yet familiar with cashflower, you can get started here.


Consider a married couple, aged 75 and 70, receiving a pension payment of 3000 as long as at least one of them is alive. Basing on the illustrative life tables and assuming monthly interest rate of 0.005, calculate the actuarial present value of this annuity.


Let's start with preparing model point data and assumptions.
main = ModelPointSet(data=pd.DataFrame({
    "id": [1],
    "age_at_entry_1": [75],
    "age_at_entry_2": [70],
    "payment": [3_000]

assumption = {
    "illustrative_life_table": pd.read_csv("./input/illustrative_life_table.csv", index_col="age"),
    "interest_rate": 0.005


Since we have two lives, we need to firstly model survival rates separately for the first and the second life.
def age_1(t):
    if t == 0:
        return main.get("age_at_entry_1")
    elif t % 12 == 0:
        return age_1(t-1) + 1
        return age_1(t-1)

def age_2(t):
    if t == 0:
        return main.get("age_at_entry_2")
    elif t % 12 == 0:
        return age_2(t-1) + 1
        return age_2(t-1)

def yearly_mortality_rate_1(t):
    if age_1(t) > 110:
        return 1
    return assumption["illustrative_life_table"].loc[age_1(t)]["qx"]

def monthly_mortality_rate_1(t):
    if age_1(t) > 110:
        return 1
    return 1 - (1 - yearly_mortality_rate_1(t))**(1/12)

def survival_for_t_periods_1(t):
    if t == 0:
        return 1
        return survival_for_t_periods_1(t-1) * (1 - monthly_mortality_rate_1(t))

def yearly_mortality_rate_2(t):
    if age_2(t) > 110:
        return 1
    return assumption["illustrative_life_table"].loc[age_2(t)]["qx"]

def monthly_mortality_rate_2(t):
    if age_2(t) > 110:
        return 1
    return 1 - (1 - yearly_mortality_rate_2(t))**(1/12)

def survival_for_t_periods_2(t):
    if t == 0:
        return 1
        return survival_for_t_periods_2(t-1) * (1 - monthly_mortality_rate_2(t))

For the joint survival, we will use the formula we have derived in the previous section.
def survival_for_t_periods(t):
    # the last-survivor status
    return survival_for_t_periods_1(t) + survival_for_t_periods_2(t) - survival_for_t_periods_1(t) * survival_for_t_periods_2(t)

The calculation of the actuarial present value follows a similar approach to that of a single life.
def expected_payment(t):
    if t == 0:
        return 0
    return survival_for_t_periods(t) * main.get("payment")

def actuarial_present_value(t):
    if t == settings["T_MAX_CALCULATION"]:
        return expected_payment(t)
    return expected_payment(t) + actuarial_present_value(t+1) * 1/(1+assumption["interest_rate"])

This modeling example provides a practical application of the concepts discussed earlier.

Thanks for exploring the topic of multiple life functions! If you found the information useful or have any questions, feel free to drop your thoughts in the comments.

Read also:

Log in to add your comment.