lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master 59860e3 14/14: Move partial mortality into ba


From: Greg Chicares
Subject: [lmi-commits] [lmi] master 59860e3 14/14: Move partial mortality into base class
Date: Sun, 6 Sep 2020 07:50:39 -0400 (EDT)

branch: master
commit 59860e392dcf6af1d6e71c91cc3a95348839b153
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>

    Move partial mortality into base class
    
    Partial mortality doesn't depend on monthiversary processing, so it
    doesn't belong in class AccountValue.
    
    Moving it to class BasicValues prevents the problems with order and
    indeed multiplicity of initialization discussed in recent commits.
---
 account_value.hpp         | 11 --------
 basic_values.hpp          | 13 ++++++++++
 ihs_acctval.cpp           | 65 -----------------------------------------------
 ihs_basicval.cpp          | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 ledger_invariant_init.cpp |  2 ++
 5 files changed, 79 insertions(+), 76 deletions(-)

diff --git a/account_value.hpp b/account_value.hpp
index 525378c..7bb7b52 100644
--- a/account_value.hpp
+++ b/account_value.hpp
@@ -91,10 +91,6 @@ class LMI_SO AccountValue final
 
     std::shared_ptr<Ledger const> ledger_from_av() const;
 
-    auto const& partial_mortality_qx () const {return partial_mortality_qx_ ;}
-    auto const& partial_mortality_tpx() const {return partial_mortality_tpx_;}
-    auto const& partial_mortality_lx () const {return partial_mortality_lx_ ;}
-
   private:
     AccountValue(AccountValue const&) = delete;
     AccountValue& operator=(AccountValue const&) = delete;
@@ -214,9 +210,6 @@ class LMI_SO AccountValue final
 
     double SolveGuarPremium        ();
 
-    void set_partial_mortality     ();
-    double GetPartMortQ            (int year) const;
-
     void PerformSpecAmtStrategy();
     void PerformSupplAmtStrategy();
     double CalculateSpecAmtFromStrategy
@@ -588,10 +581,6 @@ class LMI_SO AccountValue final
     double  YearsTotalSpecAmtLoad;
     double  YearsTotalSepAcctLoad;
 
-    std::vector<double> partial_mortality_qx_;
-    std::vector<double> partial_mortality_tpx_;
-    std::vector<double> partial_mortality_lx_;
-
     // For experience rating.
     double  CoiRetentionRate;
     double  ExperienceRatingAmortizationYears;
diff --git a/basic_values.hpp b/basic_values.hpp
index 1501151..ce3816f 100644
--- a/basic_values.hpp
+++ b/basic_values.hpp
@@ -109,6 +109,11 @@ class LMI_SO BasicValues
     mcenum_state          GetStateOfJurisdiction()     const;
     mcenum_state          GetStateOfDomicile()         const;
     mcenum_state          GetPremiumTaxState()         const;
+
+    auto const& partial_mortality_qx () const {return partial_mortality_qx_ ;}
+    auto const& partial_mortality_tpx() const {return partial_mortality_tpx_;}
+    auto const& partial_mortality_lx () const {return partial_mortality_lx_ ;}
+
     double                InvestmentManagementFee()    const;
 
     yare_input                          yare_input_;
@@ -382,6 +387,9 @@ class LMI_SO BasicValues
     BasicValues(BasicValues const&) = delete;
     BasicValues& operator=(BasicValues const&) = delete;
 
+    void set_partial_mortality();
+    double GetPartMortQ(int year) const;
+
     double mly_ded_discount_factor(int year, mcenum_mode mode) const;
     std::pair<double,double> approx_mly_ded
         (int    year
@@ -424,6 +432,11 @@ class LMI_SO BasicValues
     mcenum_state        StateOfJurisdiction_;
     mcenum_state        StateOfDomicile_;
     mcenum_state        PremiumTaxState_;
+
+    std::vector<double> partial_mortality_qx_;
+    std::vector<double> partial_mortality_tpx_;
+    std::vector<double> partial_mortality_lx_;
+
     mutable double      InitialTargetPremium;
 
     void                Init7702();
diff --git a/ihs_acctval.cpp b/ihs_acctval.cpp
index 0834349..decc40f 100644
--- a/ihs_acctval.cpp
+++ b/ihs_acctval.cpp
@@ -106,9 +106,6 @@ AccountValue::AccountValue(Input const& input)
     PerformSupplAmtStrategy();
     InvariantValues().Init(this);
 
-    set_partial_mortality();
-    InvariantValues().InforceLives = partial_mortality_lx();
-
     // Explicitly initialize antediluvian members. It's generally
     // better to do this in the initializer-list, but here they can
     // all be kept together.
@@ -1431,68 +1428,6 @@ void AccountValue::SetAnnualInvariants()
     YearsDacTaxLoadRate     = Loads_->dac_tax_load                    ()[Year];
 }
 
-/// Calculate and store actuarial functions for partial mortality.
-///
-/// Iff partial mortality is used, save qx, tpx, and lx in vectors
-/// for use elsewhere in this class and for compositing ledgers.
-/// The radix for lx is the number of identical lives that an input
-/// cell represents, and qx is forced to unity at the survivorship
-/// limit (if any). If partial mortality is not used, then qx is
-/// uniformly zero, tpx is one, and lx is the radix.
-///
-/// tpx and lx both have one more element than qx; dropping the first
-/// or last element gives EOY and BOY vectors, respectively.
-///
-/// Whether a contract continues after its normal maturity date does
-/// not matter. It is treated as not expiring on that date because
-/// year-end composite values are multiplied by this lx.
-///
-/// These actuarial functions reflect survivorship only, not lapses.
-/// Use AccountValue::InforceLives{E,B}oy() where lapses should be
-/// taken into account; cf. Ledger::ZeroInforceAfterLapse().
-
-void AccountValue::set_partial_mortality()
-{
-    double const inforce_lives = yare_input_.NumberOfIdenticalLives;
-    partial_mortality_qx_ .resize(    BasicValues::GetLength());
-    partial_mortality_tpx_.resize(1 + BasicValues::GetLength(), 1.0);
-    partial_mortality_lx_ .resize(1 + BasicValues::GetLength(), inforce_lives);
-    if(yare_input_.UsePartialMortality)
-        {
-        // The first elements of lx and tpx were set above.
-        for(int j = 0; j < BasicValues::GetLength(); ++j)
-            {
-            partial_mortality_qx_[j] = GetPartMortQ(j);
-            double const px = 1.0 - partial_mortality_qx_[j];
-            partial_mortality_tpx_[1 + j] = px * partial_mortality_tpx_[j];
-            partial_mortality_lx_ [1 + j] = px * partial_mortality_lx_ [j];
-            }
-        }
-}
-
-//============================================================================
-double AccountValue::GetPartMortQ(int a_year) const
-{
-    LMI_ASSERT(a_year <= BasicValues::GetLength());
-    if(!yare_input_.UsePartialMortality)
-        {
-        return 0.0;
-        }
-    if
-        (   MaxSurvivalDur <= a_year
-        ||  a_year == BasicValues::GetLength()
-        )
-        {
-        return 1.0;
-        }
-
-    double z =
-          MortalityRates_->PartialMortalityQ()[a_year]
-        * yare_input_.PartialMortalityMultiplier[a_year]
-        ;
-    return std::max(0.0, std::min(1.0, z));
-}
-
 //============================================================================
 double AccountValue::GetSepAcctAssetsInforce() const
 {
diff --git a/ihs_basicval.cpp b/ihs_basicval.cpp
index 592cd35..21aa86e 100644
--- a/ihs_basicval.cpp
+++ b/ihs_basicval.cpp
@@ -243,6 +243,7 @@ void BasicValues::Init()
     InitialTargetPremium = 0.0;
 
     SetMaxSurvivalDur();
+    set_partial_mortality();
 
     Init7702();
     Init7702A();
@@ -323,6 +324,7 @@ void BasicValues::GPTServerInit()
     Loads_         .reset(new Loads          (*this));
 
     SetMaxSurvivalDur();
+//  set_partial_mortality(); // Not needed here.
 
     Init7702();
 }
@@ -838,6 +840,68 @@ void BasicValues::SetMaxSurvivalDur()
     LMI_ASSERT(MaxSurvivalDur <= EndtAge);
 }
 
+/// Calculate and store actuarial functions for partial mortality.
+///
+/// Iff partial mortality is used, save qx, tpx, and lx in vectors
+/// for use elsewhere in this class and for compositing ledgers.
+/// The radix for lx is the number of identical lives that an input
+/// cell represents, and qx is forced to unity at the survivorship
+/// limit (if any). If partial mortality is not used, then qx is
+/// uniformly zero, tpx is one, and lx is the radix.
+///
+/// tpx and lx both have one more element than qx; dropping the first
+/// or last element gives EOY and BOY vectors, respectively.
+///
+/// Whether a contract continues after its normal maturity date does
+/// not matter. It is treated as not expiring on that date because
+/// year-end composite values are multiplied by this lx.
+///
+/// These actuarial functions reflect survivorship only, not lapses.
+/// Use AccountValue::InforceLives{E,B}oy() where lapses should be
+/// taken into account; cf. Ledger::ZeroInforceAfterLapse().
+
+void BasicValues::set_partial_mortality()
+{
+    double const inforce_lives = yare_input_.NumberOfIdenticalLives;
+    partial_mortality_qx_ .resize(    BasicValues::GetLength());
+    partial_mortality_tpx_.resize(1 + BasicValues::GetLength(), 1.0);
+    partial_mortality_lx_ .resize(1 + BasicValues::GetLength(), inforce_lives);
+    if(yare_input_.UsePartialMortality)
+        {
+        // The first elements of lx and tpx were set above.
+        for(int j = 0; j < BasicValues::GetLength(); ++j)
+            {
+            partial_mortality_qx_[j] = GetPartMortQ(j);
+            double const px = 1.0 - partial_mortality_qx_[j];
+            partial_mortality_tpx_[1 + j] = px * partial_mortality_tpx_[j];
+            partial_mortality_lx_ [1 + j] = px * partial_mortality_lx_ [j];
+            }
+        }
+}
+
+//============================================================================
+double BasicValues::GetPartMortQ(int a_year) const
+{
+    LMI_ASSERT(a_year <= BasicValues::GetLength());
+    if(!yare_input_.UsePartialMortality)
+        {
+        return 0.0;
+        }
+    if
+        (   MaxSurvivalDur <= a_year
+        ||  a_year == BasicValues::GetLength()
+        )
+        {
+        return 1.0;
+        }
+
+    double z =
+          MortalityRates_->PartialMortalityQ()[a_year]
+        * yare_input_.PartialMortalityMultiplier[a_year]
+        ;
+    return std::max(0.0, std::min(1.0, z));
+}
+
 /// Ascertain modal payment for a minimum-premium strategy.
 ///
 /// The term "minimum premium" is overloaded. It may mean the lowest
diff --git a/ledger_invariant_init.cpp b/ledger_invariant_init.cpp
index 2900000..a174184 100644
--- a/ledger_invariant_init.cpp
+++ b/ledger_invariant_init.cpp
@@ -74,6 +74,8 @@ void LedgerInvariant::Init(BasicValues const* b)
     // Zero-initialize almost everything.
     Init();
 
+    InforceLives = b->partial_mortality_lx();
+
     irr_precision_ = b->round_irr().decimals();
 
     // BOY vectors.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]