lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] odd/unify_products 405d654: Unify code to generate '


From: Greg Chicares
Subject: [lmi-commits] [lmi] odd/unify_products 405d654: Unify code to generate '.database' and '.policy' files
Date: Mon, 8 Jul 2019 17:17:49 -0400 (EDT)

branch: odd/unify_products
commit 405d6548e6f1e4f35e8dd9e179841c0826f2d4a9
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>

    Unify code to generate '.database' and '.policy' files
    
    This experimental commit demonstrates a technique that probably won't
    be used in production.
    
    Inspiration: The similarity of these snippets...
        // dbdict.cpp
      class sample : public DBDictionary {public: sample();};
      class sample2finra : public sample {public: sample2finra();};
        // product_data.cpp
      class sample : public product_data {public: sample();};
      class sample2 : public sample {public: sample2();};
      class sample2finra : public sample2 {public: sample2finra();};
    ...suggests merging these two nearly-identical hierarchies, as is done
    in new file 'products.hpp'.
    
    Analysis: The new implementation of sample2finra::sample2finra() in
    'products.cpp' shows how attractive such a merger can be, given a set
    of products that differ only slightly. However, proprietary products
    more often have dozens of differences, and combining two implementations
    like
      sample::sample() // 281 lines in 'dbdict.cpp'
      sample::sample() //  78 lines in 'product_data.cpp'
    into a single 359-line function is a serious pessimization. Inheriting
    from multiple bases
      class sample : public DBDictionary, public product_data {...};
    is not a concern because unit tests show that the default ctors are
    fast; all that matters is simplicity and comprehensibility.
    
    A template alternative
      template<typename T> class sample : public T {...};
    is unattractive because every derived class would need to be a template,
    but compact declarations like
      class sample2finra : public sample2 {public: sample2finra();};
      class sample2prosp : public sample2 {public: sample2prosp();};
      class sample2gpp   : public sample2 {public: sample2gpp  ();};
    are much easier to read, especially for extensive, tangled hierarchies
    of proprietary products.
---
 objects.make |   1 +
 products.cpp | 632 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 products.hpp |  41 ++++
 3 files changed, 674 insertions(+)

diff --git a/objects.make b/objects.make
index d9172ed..90e620a 100644
--- a/objects.make
+++ b/objects.make
@@ -1166,4 +1166,5 @@ product_files$(EXEEXT): \
   my_proem.o \
   my_rnd.o \
   my_tier.o \
+  products.o \
   liblmi$(SHREXT) \
diff --git a/products.cpp b/products.cpp
new file mode 100644
index 0000000..face6a3
--- /dev/null
+++ b/products.cpp
@@ -0,0 +1,632 @@
+// Product parameters.
+//
+// Copyright (C) 1998, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 
2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+#include "pchfile.hpp"
+
+#include "products.hpp"
+
+#include "dbnames.hpp"
+#include "premium_tax.hpp"              // 
premium_tax_rates_for_life_insurance()
+
+/// The 'sample' product DWISOTT. Its values, where specified at all
+/// (rather than defaulted to empty strings), are intended to be
+/// plausible, if perhaps whimsical.
+
+sample::sample()
+{
+    // Numeric data.
+
+    Add({DB_MinIssAge           , 15});
+    Add({DB_MaxIssAge           , 70});
+    Add({DB_MaxIncrAge          , 99});
+    Add({DB_AllowFullUw         , true});
+    Add({DB_AllowParamedUw      , true});
+    Add({DB_AllowNonmedUw       , true});
+    Add({DB_AllowSimpUw         , true});
+    Add({DB_AllowGuarUw         , true});
+    Add({DB_SmokeOrTobacco      , oe_tobacco_nontobacco});
+    Add({DB_AllowPreferredClass , true});
+    Add({DB_AllowUltraPrefClass , false});
+
+    // Forbid substandard table ratings with simplified or guaranteed issue.
+    int uw_dims[e_number_of_axes] = {1, 1, 1, 1, 5, 1, 1};
+    //                              med  para nonmed   SI     GI
+    double allow_substd_table[] = {true, true, true, false, false};
+    Add({DB_AllowSubstdTable, e_number_of_axes, uw_dims, allow_substd_table});
+
+    Add({DB_AllowFlatExtras     , true});
+    Add({DB_AllowRatedWp        , false});
+    Add({DB_AllowRatedAdb       , false});
+    Add({DB_AllowRatedTerm      , true});
+    Add({DB_AllowRetirees       , true});
+    Add({DB_AllowUnisex         , true});
+    Add({DB_AllowSexDistinct    , true});
+    Add({DB_AllowUnismoke       , true});
+    Add({DB_AllowSmokeDistinct  , true});
+    Add({DB_StateApproved       , true});
+    Add({DB_AllowStateXX        , true});
+    Add({DB_AllowForeign        , true});
+    Add({DB_GroupIndivSelection , false});
+    Add({DB_Allowable           , true});
+    Add({DB_AllowCvat           , true});
+    Add({DB_AllowGpt            , true});
+    Add({DB_AllowNo7702         , false});
+    Add({DB_CorridorWhence      , oe_7702_corr_from_table});
+    Add({DB_Irc7702NspWhence    , oe_7702_nsp_reciprocal_cvat_corridor});
+    Add({DB_SevenPayWhence      , oe_7702_7pp_from_table});
+    Add({DB_Irc7702QWhence      , oe_7702_q_external_table});
+
+    // This is just a sample product, so make do with plausible
+    // all-male seven-pay premiums, and use GPT corridor factors for
+    // CVAT. 'Irc7702NspWhence' specifies that NSP is calculated as
+    // the reciprocal of CVAT corridor, so no NSP table is needed.
+    Add({DB_CorridorTable       , 7});
+    Add({DB_Irc7702NspTable     , 0});
+    Add({DB_SevenPayTable       , 10});
+
+    Add({DB_CsoEra              , oe_1980cso});
+    // Following IRS Notice 88-128, use only the male and female
+    // tables with no smoker distinction, and a unisex table where
+    // required by state law.
+    //
+    // US 1980 CSO age last, not smoker distinct. Unisex = table D.
+    // Male uses table E, which is correct, as opposed to table F,
+    // which contains a numerical error but was adopted by NAIC.
+    int dims311[e_number_of_axes] = {3, 1, 1, 1, 1, 1, 1}; // gender
+    double T7702q[3] = {35, 41, 107,}; // Female, male, unisex.
+    Add({DB_Irc7702QTable, e_number_of_axes, dims311, T7702q});
+    Add({DB_Irc7702QAxisGender  , true});
+    Add({DB_Irc7702QAxisSmoking , false});
+
+    Add({DB_CvatMatChangeDefn   , 
mce_earlier_of_increase_or_unnecessary_premium});
+    Add({DB_GptMatChangeDefn    , 0});
+    Add({DB_Irc7702BftIsSpecAmt , 0});
+
+    // US 1980 CSO age last; unisex = table D.
+    // Male uses table E, which is correct, as opposed to table F,
+    // which contains a numerical error but was adopted by NAIC.
+    int dims313[e_number_of_axes] = {3, 1, 3, 1, 1, 1, 1}; // gender, smoker
+    double TgCOI[9] =
+        {
+         39,  37,  35, // female: sm ns us
+         45,  57,  41, // male:   sm ns us
+        111, 109, 107, // unisex: sm ns us
+        };
+    Add({DB_GuarCoiTable, e_number_of_axes, dims313, TgCOI});
+
+    Add({DB_GuarCoiIsAnnual     , true});
+
+    // For now at least, just use (a multiple of) guaranteed COI rates
+    // as current.
+    Add({DB_CurrCoiTable, e_number_of_axes, dims313, TgCOI});
+
+    Add({DB_CurrCoiIsAnnual     , true});
+
+    double coimult[9] =
+        {
+        0.40, 0.30, 0.35, // female: sm ns us
+        0.60, 0.50, 0.55, // male:   sm ns us
+        0.50, 0.40, 0.45, // unisex: sm ns us
+        };
+    Add({DB_CurrCoiMultiplier, e_number_of_axes, dims313, coimult});
+
+    Add({DB_MdptCoiIsAnnual     , true});
+    Add({DB_UseNyCoiFloor       , 0.0});
+    Add({DB_GuarCoiCeiling      , false});
+    Add({DB_CoiGuarIsMin        , false});
+    Add({DB_AllowMortBlendSex   , true});
+    Add({DB_AllowMortBlendSmoke , true});
+    Add({DB_GuarInt             , 0.03});
+    Add({DB_NaarDiscount        , 0.00246627});
+    Add({DB_GuarMandE           , 0.009});
+    Add({DB_CurrIntSpread       , 0.01});
+    Add({DB_CurrMandE           , 0.009});
+    Add({DB_GenAcctIntBonus     , 0.0});
+    Add({DB_BonusInt            , 0.0});
+    Add({DB_IntFloor            , 0.0});
+    Add({DB_AllowGenAcct        , true});
+    Add({DB_AllowSepAcct        , true});
+    Add({DB_AllowGenAcctEarnRate, true});
+    Add({DB_AllowSepAcctNetRate , true});
+    Add({DB_MaxGenAcctRate      , 0.06});
+    Add({DB_MaxSepAcctRate      , 0.12});
+    Add({DB_SepAcctSpreadMethod , mce_spread_is_effective_annual});
+    Add({DB_IntSpreadMode       , mce_spread_daily});
+    Add({DB_DynamicMandE        , false});
+    Add({DB_AllowAmortPremLoad  , false});
+    Add({DB_LoadAmortFundCharge , 0.0030});
+    Add({DB_AllowImfOverride    , false});
+    Add({DB_AssetChargeType     , oe_asset_charge_spread});
+    Add({DB_StableValFundCharge , 0.0});
+    Add({DB_GuarFundAdminChg    , 0.0});
+    Add({DB_CurrFundAdminChg    , 0.0});
+    Add({DB_FundCharge          , 0.0});
+    Add({DB_GuarMonthlyPolFee   , 8.00});
+    Add({DB_GuarAnnualPolFee    , 0.0});
+    Add({DB_GuarPremLoadTgt     , 0.07});
+    Add({DB_GuarPremLoadExc     , 0.04});
+    Add({DB_GuarPremLoadTgtRfd  , 0.00});
+    Add({DB_GuarPremLoadExcRfd  , 0.00});
+    Add({DB_GuarSpecAmtLoad     , 0.0});
+    Add({DB_GuarAcctValLoad     , 0.0});
+    Add({DB_CurrMonthlyPolFee   , 5.00});
+    Add({DB_CurrAnnualPolFee    , 0.0});
+    Add({DB_CurrPremLoadTgt     , 0.05});
+    Add({DB_CurrPremLoadExc     , 0.02});
+    Add({DB_CurrPremLoadTgtRfd  , 0.00});
+    Add({DB_CurrPremLoadExcRfd  , 0.00});
+    Add({DB_CurrSpecAmtLoad     , 0.0});
+    Add({DB_CurrAcctValLoad     , 0.0});
+    Add({DB_TgtPremMonthlyPolFee, 0.0});
+    Add({DB_LoadRfdProportion   , 0.0});
+    Add({DB_SpecAmtLoadLimit    , 10000000.0});
+    Add({DB_DynamicSepAcctLoad  , false});
+    Add({DB_DacTaxFundCharge    , 0.0});
+    Add({DB_DacTaxPremLoad      , 0.01});
+    Add({DB_PremTaxFundCharge   , 0.0});
+
+    // Pass through premium tax.
+    int ptd[e_number_of_axes] = {1, 1, 1, 1, 1, e_max_dim_state, 1};
+    std::vector<int> premium_tax_dimensions(ptd, ptd + e_number_of_axes);
+    Add({DB_PremTaxLoad, premium_tax_dimensions, 
premium_tax_rates_for_life_insurance()});
+
+    Add({DB_WaivePremTaxInt1035 , true});
+    Add({DB_PremTaxAmortPeriod  , 0});
+    Add({DB_PremTaxAmortIntRate , 0.0});
+
+    Add({DB_PremTaxRate, premium_tax_dimensions, 
premium_tax_rates_for_life_insurance()});
+
+    Add({DB_PremTaxState        , oe_ee_state});
+    Add({DB_AllowSpecAmtIncr    , true});
+    Add({DB_MinSpecAmtIncr      , 0.0});
+    Add({DB_EnforceNaarLimit    , true});
+    Add({DB_MinSpecAmt          , 100000.0});
+    Add({DB_MinIssSpecAmt       , 50000.0});
+    Add({DB_MinIssBaseSpecAmt   , 50000.0});
+    Add({DB_MinRenlSpecAmt      , 50000.0});
+    Add({DB_MinRenlBaseSpecAmt  , 50000.0});
+    Add({DB_AllowDboLvl         , true});
+    Add({DB_AllowDboInc         , true});
+    Add({DB_AllowDboRop         , true});
+    Add({DB_AllowDboMdb         , true});
+    Add({DB_DboLvlChangeToWhat  , 0b1111});
+    Add({DB_DboLvlChangeMethod  , 0b1111});
+    Add({DB_DboIncChangeToWhat  , 0b1111});
+    Add({DB_DboIncChangeMethod  , 0b1111});
+    Add({DB_DboRopChangeToWhat  , 0b1111});
+    Add({DB_DboRopChangeMethod  , 0b1111});
+    Add({DB_DboMdbChangeToWhat  , 0b1111});
+    Add({DB_DboMdbChangeMethod  , 0b1111});
+    Add({DB_AllowChangeToDbo2   , true});
+    Add({DB_DboChgCanIncrSpecAmt, true});
+    Add({DB_DboChgCanDecrSpecAmt, true});
+    Add({DB_AllowExtEndt        , true});
+    Add({DB_AllowTerm           , true});
+
+    int dims143[e_number_of_axes] = {1, 4, 3, 1, 1, 1, 1}; // uw_class, smoker
+    double TtCOI[12] =
+        {
+        3, 2, 1, // pref:  sm ns us
+        6, 5, 4, // std:   sm ns us
+        6, 5, 4, // rated: sm ns us [same as std]
+        0, 0, 0, // ultra: sm ns us [zero: error message--no ultrapref class]
+        };
+    Add({DB_GuarTermTable, e_number_of_axes, dims143, TtCOI});
+    Add({DB_TermTable    , e_number_of_axes, dims143, TtCOI});
+
+    Add({DB_TermMinIssAge       , 15});
+    Add({DB_TermMaxIssAge       , 65});
+    Add({DB_TermForcedConvAge   , 70});
+    Add({DB_TermForcedConvDur   , 10});
+    Add({DB_MaxTermProportion   , 0.0});
+    Add({DB_AllowWp             , true});
+    Add({DB_WpTable             , 8});
+    Add({DB_WpMinIssAge         , 18});
+    Add({DB_WpMaxIssAge         , 64});
+    Add({DB_AllowAdb            , true});
+    Add({DB_AdbTable            , 708});   // 70-75 US ADB experience
+    Add({DB_AdbMinIssAge        , 15});
+    Add({DB_AdbMaxIssAge        , 70});
+    Add({DB_AdbLimit            , 1000000.0});
+    Add({DB_AllowSpouseRider    , true});
+    Add({DB_SpouseRiderMinAmt   , 10000.0});
+    Add({DB_SpouseRiderMaxAmt   , 1000000.0});
+    Add({DB_SpouseRiderMinIssAge, 20});
+    Add({DB_SpouseRiderMaxIssAge, 65});
+    Add({DB_SpouseRiderGuarTable, 305});   // arbitrarily use 1960 CSG
+    Add({DB_SpouseRiderTable    , 305});   // arbitrarily use 1960 CSG
+    Add({DB_AllowChildRider     , true});
+    Add({DB_ChildRiderMinAmt    , 25000}); // for testing, min==max
+    Add({DB_ChildRiderMaxAmt    , 25000}); // for testing, min==max
+    Add({DB_ChildRiderTable     , 305});   // arbitrarily use 1960 CSG
+    Add({DB_AllowWd             , true});
+    Add({DB_WdFee               , 25.0});
+    Add({DB_WdFeeRate           , 0.02});
+    Add({DB_MinWd               , 100.0});
+    Add({DB_MaxWdDed            , mce_to_next_anniversary});
+    Add({DB_WdDecrSpecAmtDboLvl , true});
+    Add({DB_WdDecrSpecAmtDboInc , true});
+    Add({DB_WdDecrSpecAmtDboRop , true});
+    Add({DB_FirstWdMonth        , 0.0});
+    Add({DB_AllowLoan           , true});
+    Add({DB_AllowPrefLoan       , false});
+    Add({DB_AllowFixedLoan      , true});
+    Add({DB_AllowVlr            , true});
+    Add({DB_FixedLoanRate       , 0.06});
+    Add({DB_MinVlrRate          , 0.04});
+    Add({DB_MaxLoanAcctValMult  , 1.0});
+    Add({DB_MaxLoanDed          , mce_to_next_anniversary});
+    Add({DB_GuarPrefLoanSpread  , 0.0});
+    Add({DB_GuarRegLoanSpread   , 0.04});
+    Add({DB_CurrPrefLoanSpread  , 0.0});
+    Add({DB_CurrRegLoanSpread   , 0.02});
+    Add({DB_FirstLoanMonth      , 0.0});
+    Add({DB_MinPremType         , oe_monthly_deduction});
+    Add({DB_TgtPremType         , oe_modal_nonmec});
+    Add({DB_TgtPremTable        , 10});    // use seven-pay as target
+    Add({DB_TgtPremFixedAtIssue , false});
+    Add({DB_TgtPremIgnoreSubstd , true});
+    Add({DB_MinPmt              , 0.0});
+    Add({DB_NoLapseMinDur       , 0.0});
+    Add({DB_NoLapseMinAge       , 0.0});
+    Add({DB_NoLapseUnratedOnly  , false});
+    Add({DB_NoLapseDboLvlOnly   , false});
+    Add({DB_NoLapseAlwaysActive , false});
+    Add({DB_AllowHoneymoon      , true});
+    Add({DB_AllowExtraAssetComp , true});
+    Add({DB_AllowExtraPremComp  , true});
+    Add({DB_AllowExpRating      , false});
+    Add({DB_AllowExpRating      , true});
+    Add({DB_ExpRatStdDevMult    , 0.0});
+    Add({DB_ExpRatIbnrMult      , 0.0});
+    Add({DB_ExpRatIbnrMult      , 6.0});
+    Add({DB_ExpRatCoiRetention  , 0.0});
+    Add({DB_ExpRatRiskCoiMult   , 0});
+    Add({DB_ExpRatAmortPeriod   , 4.0});
+    Add({DB_LedgerType          , mce_ill_reg});
+    Add({DB_AgeLastOrNearest    , oe_age_last_birthday});
+    Add({DB_MaturityAge         , 100});
+    Add({DB_GroupProxyRateTable , 305});   // 1960 CSG (gender-indistinct)
+
+    // 1983 GAM; unisex=male because no unisex table was published.
+    double T83Gam[3] = {825, 826, 826,}; // f, m, u
+    Add({DB_PartialMortTable, e_number_of_axes, dims311, T83Gam});
+
+    // Use alternative policy form name in states beginning with "K".
+    std::vector<double> alt_form(e_max_dim_state);
+    alt_form[mce_s_KS] = true;
+    alt_form[mce_s_KY] = true;
+    Add({DB_UsePolicyFormAlt, premium_tax_dimensions, alt_form});
+
+    // String data.
+
+    // Names of lmi product files.
+    item("DatabaseFilename")           = glossed_string("sample.database");
+    item("FundFilename")               = glossed_string("sample.funds");
+    item("RoundingFilename")           = glossed_string("sample.rounding");
+    item("TierFilename")               = glossed_string("sample.strata");
+
+    // Base names of mortality-table databases.
+    item("CvatCorridorFilename")       = glossed_string("sample");
+    item("Irc7702NspFilename")         = glossed_string("sample");
+    item("CurrCOIFilename")            = glossed_string("qx_cso");
+    item("GuarCOIFilename")            = glossed_string("qx_cso");
+    item("WPFilename")                 = glossed_string("sample");
+    item("ADDFilename")                = glossed_string("qx_ins", "Specimen 
gloss.");
+    item("ChildRiderFilename")         = glossed_string("qx_ins");
+    item("CurrSpouseRiderFilename")    = glossed_string("qx_ins");
+    item("GuarSpouseRiderFilename")    = glossed_string("qx_ins");
+    item("CurrTermFilename")           = glossed_string("sample");
+    item("GuarTermFilename")           = glossed_string("sample");
+    item("GroupProxyFilename")         = glossed_string("qx_ins");
+    item("SevenPayFilename")           = glossed_string("sample");
+    item("TgtPremFilename")            = glossed_string("sample");
+    item("Irc7702QFilename")           = glossed_string("qx_cso");
+    item("PartialMortalityFilename")   = glossed_string("qx_ann");
+    item("SubstdTblMultFilename")      = glossed_string("sample");
+    item("CurrSpecAmtLoadFilename")    = glossed_string("sample");
+    item("GuarSpecAmtLoadFilename")    = glossed_string("sample");
+
+    // Other data that affect calculations.
+    item("InsCoDomicile")              = glossed_string("WI");
+
+    // Substitutable strings.
+    item("PolicyForm")                 = glossed_string("UL32768-NY");
+    item("PolicyFormAlternative")      = glossed_string("UL32768-X");
+    item("PolicyMktgName")             = glossed_string("UL Supreme");
+    item("PolicyLegalName")            = glossed_string("Flexible Premium 
Adjustable Life Insurance Policy");
+    item("InsCoShortName")             = glossed_string("Superior Life");
+    item("InsCoName")                  = glossed_string("Superior Life 
Insurance Company");
+    item("InsCoAddr")                  = glossed_string("Superior, WI 12345");
+    item("InsCoStreet")                = glossed_string("246 Main Street");
+    item("InsCoPhone")                 = glossed_string("(800) 555-1212");
+    item("MainUnderwriter")            = glossed_string("Superior Securities");
+    item("MainUnderwriterAddress")     = glossed_string("246-M Main Street, 
Superior, WI 12345");
+    item("CoUnderwriter")              = glossed_string("Superior Investors");
+    item("CoUnderwriterAddress")       = glossed_string("246-C Main Street, 
Superior, WI 12345");
+    item("AvName")                     = glossed_string("Account");
+    item("CsvName")                    = glossed_string("Cash Surrender");
+    item("CsvHeaderName")              = glossed_string("Cash Surr");
+    item("NoLapseProvisionName")       = glossed_string("No-lapse Provision");
+    item("ContractName")               = glossed_string("contract"); // 
Alternatively, "policy" or "certificate".
+    item("DboNameLevel")               = glossed_string("A");
+    item("DboNameIncreasing")          = glossed_string("B");
+    item("DboNameReturnOfPremium")     = glossed_string("ROP");
+    item("DboNameMinDeathBenefit")     = glossed_string("MDB");
+    item("MarketingNameFootnote")      = glossed_string("Policy form 
UL32768-NY is marketed as 'UL Supreme'.");
+
+    item("ADDTerseName")               = glossed_string("Accident");
+    item("InsurabilityTerseName")      = glossed_string("Insurability");
+    item("ChildTerseName")             = glossed_string("Child");
+    item("SpouseTerseName")            = glossed_string("Spouse");
+    item("TermTerseName")              = glossed_string("Term");
+    item("WaiverTerseName")            = glossed_string("Waiver");
+    item("AccelBftRiderTerseName")     = glossed_string("Acceleration");
+    item("OverloanRiderTerseName")     = glossed_string("Overloan");
+
+    item("GroupQuoteShortProductName") = glossed_string("UL SUPREMEĀ®");
+    item("GroupQuoteIsNotAnOffer")     = glossed_string("This is not an offer 
of insurance.");
+    item("GroupQuoteRidersFooter")     = glossed_string("Available riders: 
accident and waiver.");
+    item("GroupQuotePolicyFormId")     = glossed_string("Policy form 
UL32768-NY is a flexible premium contract.");
+    item("GroupQuoteStateVariations")  = glossed_string("Not available in all 
states.");
+    item("GroupQuoteProspectus")       = glossed_string("Read the prospectus 
carefully.");
+    item("GroupQuoteUnderwriter")      = glossed_string("Securities 
underwritten by Superior Securities.");
+    item("GroupQuoteBrokerDealer")     = glossed_string("Securities offered 
through Superior Brokerage.");
+    item("GroupQuoteRubricMandatory")  = glossed_string("Mandatory");
+    item("GroupQuoteRubricVoluntary")  = glossed_string("Voluntary");
+    item("GroupQuoteRubricFusion")     = glossed_string("Fusion");
+    item("GroupQuoteFooterMandatory")  = glossed_string("The employer pays all 
premiums.");
+    item("GroupQuoteFooterVoluntary")  = glossed_string("The employee pays all 
premiums.");
+    item("GroupQuoteFooterFusion")     = glossed_string("The employer and 
employee pay their respective premiums.");
+}
+
+/// The 'sample2*' products are designed to facilitate testing.
+/// There is one for each supported ledger type:
+///   sample2naic  mce_ill_reg
+///   sample2finra mce_finra
+///   sample2prosp mce_prospectus_abeyed ['emit_test_data' only]
+///   sample2gpp   mce_group_private_placement
+///   sample2ipp   mce_individual_private_placement
+/// and one for exotica:
+///   sample2xyz   mce_finra
+///
+/// "*Filename" members are names of actual lmi product files, or
+/// basenames of mortality-table databases, and their values must
+/// nominate actual files. Member 'InsCoDomicile' is used to
+/// determine retaliatory premium-tax rates, and must be a two-letter
+/// USPS abbreviation. All other members represent text that is used
+/// for report formatting; in order to make 'sample2*' more useful for
+/// developing and testing reports, each has a nonempty value that is
+/// its member name enclosed in braces ("{}"). Braces aren't otherwise
+/// used in values, so any output substring like "{contract}" here:
+///   "This {contract} provides valuable protection"
+/// necessarily represents a substitutable value, while everything
+/// else in a report is just literal text.
+
+sample2::sample2()
+{
+    // Numeric data: none, deliberately.
+
+    // String data.
+
+    for(auto const& i : product_data::member_names())
+        {
+        product_data::operator[](i) = '{' + i + '}';
+        }
+
+    // Names of lmi product files.
+    item("DatabaseFilename")           = glossed_string("sample.database");
+    item("FundFilename")               = glossed_string("sample.funds");
+    item("RoundingFilename")           = glossed_string("sample.rounding");
+    item("TierFilename")               = glossed_string("sample.strata");
+
+    // Base names of mortality-table databases.
+    item("CvatCorridorFilename")       = glossed_string("sample");
+    item("Irc7702NspFilename")         = glossed_string("sample");
+    item("CurrCOIFilename")            = glossed_string("qx_cso");
+    item("GuarCOIFilename")            = glossed_string("qx_cso");
+    item("WPFilename")                 = glossed_string("sample");
+    item("ADDFilename")                = glossed_string("qx_ins", "Specimen 
gloss.");
+    item("ChildRiderFilename")         = glossed_string("qx_ins");
+    item("CurrSpouseRiderFilename")    = glossed_string("qx_ins");
+    item("GuarSpouseRiderFilename")    = glossed_string("qx_ins");
+    item("CurrTermFilename")           = glossed_string("sample");
+    item("GuarTermFilename")           = glossed_string("sample");
+    item("GroupProxyFilename")         = glossed_string("qx_ins");
+    item("SevenPayFilename")           = glossed_string("sample");
+    item("TgtPremFilename")            = glossed_string("sample");
+    item("Irc7702QFilename")           = glossed_string("qx_cso");
+    item("PartialMortalityFilename")   = glossed_string("qx_ann");
+    item("SubstdTblMultFilename")      = glossed_string("sample");
+    item("CurrSpecAmtLoadFilename")    = glossed_string("sample");
+    item("GuarSpecAmtLoadFilename")    = glossed_string("sample");
+
+    // Other data that affect calculations.
+    item("InsCoDomicile")              = glossed_string("WI");
+}
+
+sample2naic::sample2naic()
+{
+    // Deliberately empty implementation.
+}
+
+sample2finra::sample2finra()
+{
+    // Numeric data.
+
+    Add({DB_LedgerType          , mce_finra});
+
+    // String data.
+
+    item("DatabaseFilename")           = 
glossed_string("sample2finra.database");
+}
+
+sample2prosp::sample2prosp()
+{
+    // Numeric data.
+
+    Add({DB_LedgerType          , mce_prospectus_abeyed});
+
+    // String data.
+
+    item("DatabaseFilename")           = 
glossed_string("sample2prosp.database");
+}
+
+sample2gpp::sample2gpp()
+{
+    // Numeric data.
+
+    Add({DB_LedgerType          , mce_group_private_placement});
+
+    // String data.
+
+    item("DatabaseFilename")           = glossed_string("sample2gpp.database");
+}
+
+/// This specimen product
+///   https://lists.nongnu.org/archive/html/lmi/2018-09/msg00039.html
+/// | has deliberately overlong footnotes
+/// for pagination testing.
+
+sample2ipp::sample2ipp()
+{
+    // Numeric data.
+
+    Add({DB_LedgerType          , mce_individual_private_placement});
+
+    // String data.
+
+    item("DatabaseFilename")           = glossed_string("sample2ipp.database");
+    item("IrrDbFootnote") = glossed_string
+        ("The \"Red Death\" had long devastated the country. No pestilence"
+         " had ever been so fatal, or so hideous. Blood was its Avatar and"
+         " its seal--the redness and the horror of blood. There were sharp"
+         " pains, and sudden dizziness, and then profuse bleeding at the"
+         " pores, with dissolution. The scarlet stains upon the body and"
+         " especially upon the face of the victim, were the pest ban which"
+         " shut him out from the aid and from the sympathy of his fellow-men."
+         " And the whole seizure, progress and termination of the disease,"
+         " were the incidents of half an hour."
+        );
+    item("IrrCsvFootnote") = glossed_string
+        ("But the Prince Prospero was happy and dauntless and sagacious. When"
+         " his dominions were half depopulated, he summoned to his presence a"
+         " thousand hale and light-hearted friends from among the knights and"
+         " dames of his court, and with these retired to the deep seclusion"
+         " of one of his castellated abbeys. This was an extensive and"
+         " magnificent structure, the creation of the prince's own eccentric"
+         " yet august taste. A strong and lofty wall girdled it in. This wall"
+         " had gates of iron. The courtiers, having entered, brought furnaces"
+         " and massy hammers and welded the bolts. They resolved to leave"
+         " means neither of ingress nor egress to the sudden impulses of"
+         " despair or of frenzy from within. The abbey was amply provisioned."
+         " With such precautions the courtiers might bid defiance to 
contagion."
+         " The external world could take care of itself. In the meantime it"
+         " was folly to grieve, or to think. The prince had provided all the"
+         " appliances of pleasure. There were buffoons, there were"
+         " improvisatori, there were ballet-dancers, there were musicians,"
+         " there was Beauty, there was wine. All these and security were"
+         " within. Without was the \"Red Death\"."
+        );
+    item("MortalityChargesFootnote") = glossed_string
+        ("It was towards the close of the fifth or sixth month of his"
+         " seclusion, and while the pestilence raged most furiously abroad,"
+         " that the Prince Prospero entertained his thousand friends at a"
+         " masked ball of the most unusual magnificence."
+        );
+    item("PolicyYearFootnote") = glossed_string
+        ("It was a voluptuous scene, that masquerade. But first let me tell"
+         " of the rooms in which it was held. These were seven--an imperial"
+         " suite. In many palaces, however, such suites form a long and"
+         " straight vista, while the folding doors slide back nearly to the"
+         " walls on either hand, so that the view of the whole extent is"
+         " scarcely impeded. Here the case was very different, as might have"
+         " been expected from the duke's love of the _bizarre_. The apartments"
+         " were so irregularly disposed that the vision embraced but little"
+         " more than one at a time. There was a sharp turn at every twenty or"
+         " thirty yards, and at each turn a novel effect. To the right and"
+         " left, in the middle of each wall, a tall and narrow Gothic window"
+         " looked out upon a closed corridor which pursued the windings of the"
+         " suite. These windows were of stained glass whose color varied in"
+         " accordance with the prevailing hue of the decorations of the"
+         " chamber into which it opened. That at the eastern extremity was"
+         " hung, for example in blue--and vividly blue were its windows. The"
+         " second chamber was purple in its ornaments and tapestries, and here"
+         " the panes were purple. The third was green throughout, and so were"
+         " the casements. The fourth was furnished and lighted with 
orange--the"
+         " fifth with white--the sixth with violet. The seventh apartment was"
+         " closely shrouded in black velvet tapestries that hung all over the"
+         " ceiling and down the walls, falling in heavy folds upon a carpet of"
+         " the same material and hue. But in this chamber only, the color of"
+         " the windows failed to correspond with the decorations. The panes"
+         " here were scarlet--a deep blood color. Now in no one of the seven"
+         " apartments was there any lamp or candelabrum, amid the profusion of"
+         " golden ornaments that lay scattered to and fro or depended from the"
+         " roof. There was no light of any kind emanating from lamp or candle"
+         " within the suite of chambers. But in the corridors that followed 
the"
+         " suite, there stood, opposite to each window, a heavy tripod, 
bearing"
+         " a brazier of fire, that projected its rays through the tinted glass"
+         " and so glaringly illumined the room. And thus were produced a"
+         " multitude of gaudy and fantastic appearances. But in the western or"
+         " black chamber the effect of the fire-light that streamed upon the"
+         " dark hangings through the blood-tinted panes, was ghastly in the"
+         " extreme, and produced so wild a look upon the countenances of those"
+         " who entered, that there were few of the company bold enough to set"
+         " foot within its precincts at all."
+        );
+}
+
+sample2xyz::sample2xyz()
+{
+    // Numeric data.
+
+    // Exotica.
+#if 0
+    // US 1980 CSO age last, not gender distinct. Unisex = table D.
+    // This deviation from the 'sample' family should necessitate
+    // different 7pp and corridor tables. Enable this deliberate
+    // inconsistency as an optional test of the product verifier.
+    int dims113[e_number_of_axes] = {1, 1, 3, 1, 1, 1, 1}; // smoking
+    double T7702q[3] = {111, 109, 107,}; // Smoker, nonsmoker, unismoke.
+    Add({DB_Irc7702QTable, e_number_of_axes, dims113, T7702q});
+    Add({DB_Irc7702QAxisGender  , false});
+    Add({DB_Irc7702QAxisSmoking , true});
+#endif // 0
+    // Arguably the most complex ledger type.
+    Add({DB_LedgerType          , mce_finra});
+    // Certain group-quote columns are available only when these two
+    // entities are 'true':
+    Add({DB_SplitMinPrem        , true});
+    Add({DB_TermIsNotRider      , true});
+    // Certain illustration columns are controlled by this:
+    Add({DB_ErNotionallyPaysTerm, true});
+    Add({DB_TxCallsGuarUwSubstd , true});
+    // This fixed loan rate varies by duration.
+    int dims_1111113[e_number_of_axes] = {1, 1, 1, 1, 1, 1, 3};
+    double loanrate[3] = {0.06, 0.05, 0.04};
+    Add({DB_FixedLoanRate, e_number_of_axes, dims_1111113, loanrate});
+    double cv_enh[3] = {0.10, 0.05, 0.00};
+    Add({DB_CashValueEnhMult, e_number_of_axes, dims_1111113, cv_enh});
+
+    // String data.
+
+    item("DatabaseFilename")           = glossed_string("sample2xyz.database");
+}
diff --git a/products.hpp b/products.hpp
new file mode 100644
index 0000000..b5d265d
--- /dev/null
+++ b/products.hpp
@@ -0,0 +1,41 @@
+// Product parameters.
+//
+// Copyright (C) 1998, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 
2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+#ifndef products_hpp
+#define products_hpp
+
+#include "config.hpp"
+
+#include "dbdict.hpp"
+#include "product_data.hpp"
+
+class sample : public DBDictionary, public product_data {public: sample();};
+
+class sample2 : public sample {public: sample2();};
+
+class sample2naic  : public sample2 {public: sample2naic ();};
+class sample2finra : public sample2 {public: sample2finra();};
+class sample2prosp : public sample2 {public: sample2prosp();};
+class sample2gpp   : public sample2 {public: sample2gpp  ();};
+class sample2ipp   : public sample2 {public: sample2ipp  ();};
+class sample2xyz   : public sample2 {public: sample2xyz  ();};
+
+#endif // products_hpp



reply via email to

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