// Copyright 2026 hua1104. Apache-2.0.
//
// Typed access to the six published CL(2010-2013) tables.
///|
/// One of the six tables published as the China Life Insurance Mortality Table
/// (2010-2013). The three business lines differ substantially in observed
/// longevity and are mandated for different product types: pension business
/// carries the longest expected lifetimes and so the highest reserves.
pub enum ChinaTable {
/// CL1: 非养老类业务一表(男), protection-type business, table I, male.
NonPensionIMale
/// CL2: 非养老类业务一表(女), protection-type business, table I, female.
NonPensionIFemale
/// CL3: 非养老类业务二表(男), protection-type business, table II, male.
NonPensionIIMale
/// CL4: 非养老类业务二表(女), protection-type business, table II, female.
NonPensionIIFemale
/// CL5: 养老类业务表(男), pension business, male.
PensionMale
/// CL6: 养老类业务表(女), pension business, female.
PensionFemale
}
///|
/// All six tables, in publication order.
pub fn all_china_tables() -> Array[ChinaTable] {
[
NonPensionIMale,
NonPensionIFemale,
NonPensionIIMale,
NonPensionIIFemale,
PensionMale,
PensionFemale,
]
}
///|
/// The short code used by the regulator, for example "CL1".
pub fn ChinaTable::code(self : ChinaTable) -> String {
match self {
NonPensionIMale => "CL1"
NonPensionIFemale => "CL2"
NonPensionIIMale => "CL3"
NonPensionIIFemale => "CL4"
PensionMale => "CL5"
PensionFemale => "CL6"
}
}
///|
/// The Chinese name of the table.
pub fn ChinaTable::chinese_name(self : ChinaTable) -> String {
match self {
NonPensionIMale => "非养老类业务一表(男)"
NonPensionIFemale => "非养老类业务一表(女)"
NonPensionIIMale => "非养老类业务二表(男)"
NonPensionIIFemale => "非养老类业务二表(女)"
PensionMale => "养老类业务表(男)"
PensionFemale => "养老类业务表(女)"
}
}
///|
/// The English name of the table.
pub fn ChinaTable::english_name(self : ChinaTable) -> String {
match self {
NonPensionIMale => "Non-pension business table I (Male)"
NonPensionIFemale => "Non-pension business table I (Female)"
NonPensionIIMale => "Non-pension business table II (Male)"
NonPensionIIFemale => "Non-pension business table II (Female)"
PensionMale => "Pension business table (Male)"
PensionFemale => "Pension business table (Female)"
}
}
///|
/// Whether the table is intended for pension (养老) business, which exhibits
/// the longest observed lifetimes of the three business lines.
pub fn ChinaTable::is_pension(self : ChinaTable) -> Bool {
match self {
PensionMale | PensionFemale => true
_ => false
}
}
///|
/// Look a table up by its regulator code, accepting "CL1" through "CL6" in
/// either case. `all_china_tables` remains the way to enumerate them.
pub fn ChinaTable::of_code(code : String) -> ChinaTable? {
for candidate in all_china_tables() {
if candidate.code().to_upper() == code.to_upper() {
return Some(candidate)
}
}
None
}
///|
/// The raw annual mortality rates qx for ages 0 through 105.
pub fn ChinaTable::qx(self : ChinaTable) -> Array[Double] {
match self {
NonPensionIMale => cl1_qx
NonPensionIFemale => cl2_qx
NonPensionIIMale => cl3_qx
NonPensionIIFemale => cl4_qx
PensionMale => cl5_qx
PensionFemale => cl6_qx
}
}
///|
/// Build a full `LifeTable` from this table. The default radix of 1,000,000
/// reproduces the survivorship columns published alongside CL(2010-2013).
pub fn ChinaTable::table(
self : ChinaTable,
radix~ : Double = 1000000.0,
fraction~ : FractionalAge = UniformDeaths,
) -> LifeTable {
LifeTable::from_qx(
qx=self.qx(),
id=self.code(),
label=self.chinese_name() + " / " + self.english_name(),
radix~,
fraction~,
)
}