[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 72a51b5 4/5: Improve physical separation of c
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 72a51b5 4/5: Improve physical separation of concerns |
Date: |
Fri, 5 Oct 2018 20:32:47 -0400 (EDT) |
branch: master
commit 72a51b5296b1b29112448ec1f9ae8ca2053ececb
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>
Improve physical separation of concerns
Split ledger_[in]variant implementations into two parts, isolating
initialization that uses class BasicValues into standalone TUs.
---
Makefile.am | 2 +
ledger_invariant.cpp | 507 +-------------------------------------------
ledger_invariant_init.cpp | 530 ++++++++++++++++++++++++++++++++++++++++++++++
ledger_variant.cpp | 99 +--------
ledger_variant_init.cpp | 118 +++++++++++
objects.make | 2 +
6 files changed, 655 insertions(+), 603 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index bd2fcdb..0d74f88 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -341,10 +341,12 @@ liblmi_common_sources = \
ledger_base.cpp \
ledger_evaluator.cpp \
ledger_invariant.cpp \
+ ledger_invariant_init.cpp \
ledger_pdf.cpp \
ledger_pdf_generator.cpp \
ledger_text_formats.cpp \
ledger_variant.cpp \
+ ledger_variant_init.cpp \
ledger_xml_io.cpp \
ledger_xsl.cpp \
ledgervalues.cpp \
diff --git a/ledger_invariant.cpp b/ledger_invariant.cpp
index 4de177a..c20ba0e 100644
--- a/ledger_invariant.cpp
+++ b/ledger_invariant.cpp
@@ -23,33 +23,17 @@
#include "ledger_invariant.hpp"
-#include "alert.hpp"
#include "assert_lmi.hpp"
-#include "basic_values.hpp"
#include "bourn_cast.hpp"
#include "contains.hpp"
#include "crc32.hpp"
-#include "database.hpp"
-#include "dbnames.hpp"
-#include "death_benefits.hpp"
#include "financial.hpp" // for CalculateIrrs()
-#include "fund_data.hpp"
-#include "input.hpp"
-#include "interest_rates.hpp"
#include "ledger.hpp" // for CalculateIrrs()
#include "ledger_variant.hpp" // for CalculateIrrs()
-#include "loads.hpp"
#include "mc_enum_aux.hpp" // mc_e_vector_to_string_vector()
-#include "mc_enum_types_aux.hpp" // mc_str()
-#include "miscellany.hpp" // each_equal()
-#include "outlay.hpp"
-#include "premium_tax.hpp"
-#include "product_data.hpp"
-#include "ssize_lmi.hpp"
-
-#include <algorithm>
+
+#include <algorithm> // max(), min()
#include <ostream>
-#include <stdexcept>
//============================================================================
LedgerInvariant::LedgerInvariant(int len)
@@ -461,493 +445,6 @@ void LedgerInvariant::Init()
}
//============================================================================
-void LedgerInvariant::Init(BasicValues const* b)
-{
- // Zero-initialize almost everything.
- Init();
-
- irr_precision_ = b->round_irr().decimals();
-
-// TODO ?? These names are confusing. EePmt and ErPmt are *input* values.
-// If they're entered as $1000 for all years, then they have that value
-// every year, even after lapse. Variables whose names end in -'GrossPmt'
-// hold the results of transaction processing, e.g. $0 after lapse.
-// EePmt and ErPmt are used e.g. in premium-strategy calculations.
-
- EePmt = b->Outlay_->ee_modal_premiums();
- ErPmt = b->Outlay_->er_modal_premiums();
-// TgtPrem =
-// GrossPmt =
-// EeGrossPmt =
-// ErGrossPmt =
- // These must be set dynamically because they may be changed,
- // e.g. to respect guideline limits.
-// External1035Amount;
-// Internal1035Amount;
-// Dumpin =
-
- InforceUnloanedAV =
- b->yare_input_.InforceGeneralAccountValue
- + b->yare_input_.InforceSeparateAccountValue
- ;
- InforceTaxBasis = b->yare_input_.InforceTaxBasis ;
-
- // Certain data members, including but almost certainly not
- // limited to these, should not be initialized to any non-zero
- // value here. Actual values are inserted in account-value
- // processing, subject to various restrictions that often cause
- // them to differ from input values. Notably, values need to be
- // zero after lapse.
-// NetWD =
-// NewCashLoan =
-// GptForceout =
-// NaarForceout =
-// ModalMinimumPremium =
-// EeModalMinimumPremium =
-// ErModalMinimumPremium =
-// ProducerCompensation =
-
- HasSupplSpecAmt = false;
- if(b->yare_input_.TermRider)
- {
- TermSpecAmt .assign(Length, b->yare_input_.TermRiderAmount);
- }
- else if(b->Database_->Query(DB_TermIsNotRider))
- {
- TermSpecAmt = b->DeathBfts_->supplamt();
- if(!each_equal(TermSpecAmt, 0.0))
- {
- HasSupplSpecAmt = true;
- }
- }
- else
- {
- TermSpecAmt .assign(Length, 0.0);
- }
- SpecAmt = b->DeathBfts_->specamt();
- for(int j = 0; j < Length; ++j)
- {
- EeMode[j] = b->Outlay_->ee_premium_modes()[j];
- ErMode[j] = b->Outlay_->er_premium_modes()[j];
- DBOpt [j] = b->DeathBfts_->dbopt()[j];
- }
-
- IndvTaxBracket = b->yare_input_.TaxBracket ;
- CorpTaxBracket = b->yare_input_.CorporationTaxBracket ;
- Salary = b->yare_input_.ProjectedSalary ;
- AnnualFlatExtra = b->yare_input_.FlatExtra ;
- HoneymoonValueSpread = b->yare_input_.HoneymoonValueSpread ;
- AddonMonthlyFee = b->yare_input_.ExtraMonthlyCustodialFee ;
- AddonCompOnAssets = b->yare_input_.ExtraCompensationOnAssets ;
- AddonCompOnPremium = b->yare_input_.ExtraCompensationOnPremium;
- CorridorFactor = b->GetCorridorFactor();
- AnnLoanDueRate = b->InterestRates_->RegLnDueRate
- (mce_gen_curr
- ,mce_annual_rate
- );
- InitAnnLoanDueRate = AnnLoanDueRate[0];
- CurrMandE = b->InterestRates_->MAndERate(mce_gen_curr);
- TotalIMF = b->InterestRates_->InvestmentManagementFee();
- RefundableSalesLoad = b->Loads_->refundable_sales_load_proportion();
-
- std::vector<double> coimult;
- b->Database_->Query(coimult, DB_CurrCoiMultiplier);
- CurrentCoiMultiplier =
- coimult [b->yare_input_.InforceYear]
- * b->yare_input_.CurrentCoiMultiplier[b->yare_input_.InforceYear]
- * b->yare_input_.CountryCoiMultiplier
- ;
-
- CountryIso3166Abbrev = mc_str(b->yare_input_.Country);
- Comments = b->yare_input_.Comments;
-
- FundNumbers .resize(0);
- FundNames .resize(0);
- FundAllocs .resize(0);
- FundAllocations .resize(0);
-
- // The antediluvian branch has a null FundData_ object.
- int number_of_funds(0);
- if(b->FundData_)
- {
- number_of_funds = b->FundData_->GetNumberOfFunds();
- }
-
-// enum{NumberOfFunds = 30}; // DEPRECATED
- int const NumberOfFunds = 30; // DEPRECATED
- int expected_number_of_funds = std::max(number_of_funds, NumberOfFunds);
- std::vector<double> v(b->yare_input_.FundAllocations);
- if(lmi::ssize(v) < expected_number_of_funds)
- {
- v.insert(v.end(), expected_number_of_funds - v.size(), 0.0);
- }
-
- for(int j = 0; j < number_of_funds; ++j)
- {
- FundNumbers.push_back(j);
- FundNames.push_back(b->FundData_->GetFundInfo(j).LongName());
-
- // TODO ?? InputParms::NumberOfFunds is defectively hardcocded
- // as thirty as this is written, but we need to support a product
- // with more than thirty funds. The input routines respect that
- // hardcoded limit and are difficult to change, so funds after
- // the thirtieth cannot be selected individually; but if the
- // rule 'equal initial fund allocations' is chosen instead of
- // specifying individual allocations, then the average fund fee
- // is calculated reflecting all funds, even past the thirtieth:
- // thus, calculations are correct for any input, and the defect
- // in the program itself is just that some legitimate inputs are
- // not allowed, though the output spreadsheet has its own
- // hardcoded limit (due to space), which is a separate defect.
- // Here we pass a zero allocation to the output spreadsheet for
- // all funds past the thirtieth, which is correct because no
- // nonzero allocation can be selected. That's correct even if
- // the 'equal initial allocations' rule is chosen, in which
- // case the allocations are not explicitly shown, but are instead
- // stated in words to be equal--because the spreadsheet layout
- // otherwise shows allocations as integer percentages, and
- // something like '.3333333...' would overflow the space available.
- //
- // As of 2008, most of the foregoing is no longer applicable,
- // except for the hardcoded limit, which is copied above.
- FundAllocs .push_back(static_cast<int>(v[j]));
- FundAllocations.push_back(0.01 * v[j]);
- }
-
- GenAcctAllocation = 1.0 - premium_allocation_to_sepacct(b->yare_input_);
-
- SplitFundAllocation =
- (0.0 != GenAcctAllocation && 1.0 != GenAcctAllocation)
- ||
- ( 0.0 != b->yare_input_.InforceGeneralAccountValue
- && 0.0 != b->yare_input_.InforceSeparateAccountValue
- )
- ;
-
- NoLapseAlwaysActive = b->Database_->Query(DB_NoLapseAlwaysActive);
- NoLapseMinDur = b->Database_->Query(DB_NoLapseMinDur);
- NoLapseMinAge = b->Database_->Query(DB_NoLapseMinAge);
- Has1035ExchCharge = b->Database_->Query(DB_Has1035ExchCharge);
-
- // SOMEDAY !! Things indexed with '[0]' should probably use inforce year
instead.
- InitBaseSpecAmt = b->DeathBfts_->specamt()[0];
- InitTermSpecAmt = TermSpecAmt[0];
- ChildRiderAmount = b->yare_input_.ChildRiderAmount;
- SpouseRiderAmount = b->yare_input_.SpouseRiderAmount;
-
-// InitPrem = 0;
-// GuarPrem = 0;
-// InitSevenPayPrem =
-// InitTgtPrem =
-// InitMinPrem =
-// ListBillPremium =
-// EeListBillPremium =
-// ErListBillPremium =
-// ModalMinimumDumpin =
-
- MaleProportion = b->yare_input_.MaleProportion;
- NonsmokerProportion = b->yare_input_.NonsmokerProportion;
- PartMortTableMult = b->yare_input_.PartialMortalityMultiplier;
-
- // Assert this because the illustration currently prints a scalar
- // guaranteed max, assuming that it's the same for all years.
- std::vector<double> const& guar_m_and_e_rate = b->InterestRates_->MAndERate
- (mce_gen_guar
- );
- LMI_ASSERT(each_equal(guar_m_and_e_rate, guar_m_and_e_rate.front()));
- GuarMaxMandE = guar_m_and_e_rate[0];
- InitDacTaxRate =
b->Loads_->dac_tax_load()[b->yare_input_.InforceYear];
- InitPremTaxRate = b->PremiumTax_->maximum_load_rate();
-// GenderDistinct = 0;
- GenderBlended = b->yare_input_.BlendGender;
-// SmokerDistinct = 0;
- SmokerBlended = b->yare_input_.BlendSmoking;
-
- SubstdTable = b->yare_input_.SubstandardTable;
-
- Age = b->yare_input_.IssueAge;
- RetAge = b->yare_input_.RetirementAge;
- EndtAge = b->yare_input_.IssueAge + b->GetLength();
- GroupIndivSelection = b->Database_->Query(DB_GroupIndivSelection);
- UseExperienceRating = b->yare_input_.UseExperienceRating;
- UsePartialMort = b->yare_input_.UsePartialMortality;
- AvgFund = b->yare_input_.UseAverageOfAllFunds;
- CustomFund = b->yare_input_.OverrideFundManagementFee;
-
- HasWP = b->yare_input_.WaiverOfPremiumBenefit;
- HasADD = b->yare_input_.AccidentalDeathBenefit;
- HasTerm = b->yare_input_.TermRider;
- HasChildRider = b->yare_input_.ChildRider;
- HasSpouseRider = b->yare_input_.SpouseRider;
- SpouseIssueAge = b->yare_input_.SpouseIssueAge;
-
- HasHoneymoon = b->yare_input_.HoneymoonEndorsement;
- PostHoneymoonSpread = b->yare_input_.PostHoneymoonSpread;
- SplitMinPrem = b->Database_->Query(DB_SplitMinPrem);
- AllowDbo3 = b->Database_->Query(DB_AllowDbo3);
-
- // These are reassigned below based on product data if available.
- std::string dbo_name_option1 = mc_str(mce_option1);
- std::string dbo_name_option2 = mc_str(mce_option2);
- std::string dbo_name_rop = mc_str(mce_rop );
- std::string dbo_name_mdb = mc_str(mce_mdb ); // DBO3 !! reconsider
-
- // The antediluvian branch has a null ProductData_ object.
- if(b->ProductData_)
- {
- product_data const& p = *b->ProductData_;
- // Accommodate one alternative policy-form name.
- // DATABASE !! It would be much better, of course, to let all
- // strings in class product_data vary across the same axes as
- // database_entity objects.
- bool alt_form = b->Database_->Query(DB_UsePolicyFormAlt);
- dbo_name_option1 = p.datum("DboNameLevel"
);
- dbo_name_option2 = p.datum("DboNameIncreasing"
);
- dbo_name_rop = p.datum("DboNameReturnOfPremium"
);
-// dbo_name_mdb = // DBO3 !! reconsider
- PolicyForm = p.datum(alt_form ? "PolicyFormAlternative" :
"PolicyForm");
- PolicyMktgName = p.datum("PolicyMktgName"
);
- PolicyLegalName = p.datum("PolicyLegalName"
);
- InsCoShortName = p.datum("InsCoShortName"
);
- InsCoName = p.datum("InsCoName"
);
- InsCoAddr = p.datum("InsCoAddr"
);
- InsCoStreet = p.datum("InsCoStreet"
);
- InsCoPhone = p.datum("InsCoPhone"
);
- MainUnderwriter = p.datum("MainUnderwriter"
);
- MainUnderwriterAddress = p.datum("MainUnderwriterAddress"
);
- CoUnderwriter = p.datum("CoUnderwriter"
);
- CoUnderwriterAddress = p.datum("CoUnderwriterAddress"
);
-
- AvName = p.datum("AvName"
);
- CsvName = p.datum("CsvName"
);
- CsvHeaderName = p.datum("CsvHeaderName"
);
- NoLapseProvisionName = p.datum("NoLapseProvisionName"
);
- ContractName = p.datum("ContractName"
);
-
- AccountValueFootnote = p.datum("AccountValueFootnote"
);
- AttainedAgeFootnote = p.datum("AttainedAgeFootnote"
);
- CashSurrValueFootnote = p.datum("CashSurrValueFootnote"
);
- DeathBenefitFootnote = p.datum("DeathBenefitFootnote"
);
- InitialPremiumFootnote = p.datum("InitialPremiumFootnote"
);
- NetPremiumFootnote = p.datum("NetPremiumFootnote"
);
- GrossPremiumFootnote = p.datum("GrossPremiumFootnote"
);
- OutlayFootnote = p.datum("OutlayFootnote"
);
- PolicyYearFootnote = p.datum("PolicyYearFootnote"
);
-
- ADDTerseName = p.datum("ADDTerseName"
);
- InsurabilityTerseName = p.datum("InsurabilityTerseName"
);
- ChildTerseName = p.datum("ChildTerseName"
);
- SpouseTerseName = p.datum("SpouseTerseName"
);
- TermTerseName = p.datum("TermTerseName"
);
- WaiverTerseName = p.datum("WaiverTerseName"
);
- AccelBftRiderTerseName = p.datum("AccelBftRiderTerseName"
);
- OverloanRiderTerseName = p.datum("OverloanRiderTerseName"
);
-
- ADDFootnote = p.datum("ADDFootnote"
);
- ChildFootnote = p.datum("ChildFootnote"
);
- SpouseFootnote = p.datum("SpouseFootnote"
);
- TermFootnote = p.datum("TermFootnote"
);
- WaiverFootnote = p.datum("WaiverFootnote"
);
- AccelBftRiderFootnote = p.datum("AccelBftRiderFootnote"
);
- OverloanRiderFootnote = p.datum("OverloanRiderFootnote"
);
-
- GroupQuoteShortProductName = p.datum("GroupQuoteShortProductName"
);
- GroupQuoteIsNotAnOffer = p.datum("GroupQuoteIsNotAnOffer"
);
- GroupQuoteRidersFooter = p.datum("GroupQuoteRidersFooter"
);
- GroupQuotePolicyFormId = p.datum("GroupQuotePolicyFormId"
);
- GroupQuoteStateVariations = p.datum("GroupQuoteStateVariations"
);
- GroupQuoteProspectus = p.datum("GroupQuoteProspectus"
);
- GroupQuoteUnderwriter = p.datum("GroupQuoteUnderwriter"
);
- GroupQuoteBrokerDealer = p.datum("GroupQuoteBrokerDealer"
);
- GroupQuoteRubricMandatory = p.datum("GroupQuoteRubricMandatory"
);
- GroupQuoteRubricVoluntary = p.datum("GroupQuoteRubricVoluntary"
);
- GroupQuoteRubricFusion = p.datum("GroupQuoteRubricFusion"
);
- GroupQuoteFooterMandatory = p.datum("GroupQuoteFooterMandatory"
);
- GroupQuoteFooterVoluntary = p.datum("GroupQuoteFooterVoluntary"
);
- GroupQuoteFooterFusion = p.datum("GroupQuoteFooterFusion"
);
-
- MinimumPremiumFootnote = p.datum("MinimumPremiumFootnote"
);
- PremAllocationFootnote = p.datum("PremAllocationFootnote"
);
-
- InterestDisclaimer = p.datum("InterestDisclaimer"
);
- GuarMortalityFootnote = p.datum("GuarMortalityFootnote"
);
- ProductDescription = p.datum("ProductDescription"
);
- StableValueFootnote = p.datum("StableValueFootnote"
);
- NoVanishPremiumFootnote = p.datum("NoVanishPremiumFootnote"
);
- RejectPremiumFootnote = p.datum("RejectPremiumFootnote"
);
- ExpRatingFootnote = p.datum("ExpRatingFootnote"
);
- MortalityBlendFootnote = p.datum("MortalityBlendFootnote"
);
- HypotheticalRatesFootnote = p.datum("HypotheticalRatesFootnote"
);
- SalesLoadRefundFootnote = p.datum("SalesLoadRefundFootnote"
);
- NoLapseFootnote = p.datum("NoLapseFootnote"
);
- MarketValueAdjFootnote = p.datum("MarketValueAdjFootnote"
);
- ExchangeChargeFootnote0 = p.datum("ExchangeChargeFootnote0"
);
- CurrentValuesFootnote = p.datum("CurrentValuesFootnote"
);
- DBOption1Footnote = p.datum("DBOption1Footnote"
);
- DBOption2Footnote = p.datum("DBOption2Footnote"
);
- ExpRatRiskChargeFootnote = p.datum("ExpRatRiskChargeFootnote"
);
- ExchangeChargeFootnote1 = p.datum("ExchangeChargeFootnote1"
);
- FlexiblePremiumFootnote = p.datum("FlexiblePremiumFootnote"
);
- GuaranteedValuesFootnote = p.datum("GuaranteedValuesFootnote"
);
- CreditingRateFootnote = p.datum("CreditingRateFootnote"
);
- GrossRateFootnote = p.datum("GrossRateFootnote"
);
- NetRateFootnote = p.datum("NetRateFootnote"
);
- MecFootnote = p.datum("MecFootnote"
);
- GptFootnote = p.datum("GptFootnote"
);
- MidpointValuesFootnote = p.datum("MidpointValuesFootnote"
);
- SinglePremiumFootnote = p.datum("SinglePremiumFootnote"
);
- MonthlyChargesFootnote = p.datum("MonthlyChargesFootnote"
);
- UltCreditingRateFootnote = p.datum("UltCreditingRateFootnote"
);
- MaxNaarFootnote = p.datum("MaxNaarFootnote"
);
- PremTaxSurrChgFootnote = p.datum("PremTaxSurrChgFootnote"
);
- PolicyFeeFootnote = p.datum("PolicyFeeFootnote"
);
- AssetChargeFootnote = p.datum("AssetChargeFootnote"
);
- InvestmentIncomeFootnote = p.datum("InvestmentIncomeFootnote"
);
- IrrDbFootnote = p.datum("IrrDbFootnote"
);
- IrrCsvFootnote = p.datum("IrrCsvFootnote"
);
- MortalityChargesFootnote = p.datum("MortalityChargesFootnote"
);
- LoanAndWithdrawalFootnote = p.datum("LoanAndWithdrawalFootnote"
);
- LoanFootnote = p.datum("LoanFootnote"
);
- ImprimaturPresale = p.datum("ImprimaturPresale"
);
- ImprimaturPresaleComposite = p.datum("ImprimaturPresaleComposite"
);
- ImprimaturInforce = p.datum("ImprimaturInforce"
);
- ImprimaturInforceComposite = p.datum("ImprimaturInforceComposite"
);
- StateMarketingImprimatur = p.datum("StateMarketingImprimatur"
);
- InforceNonGuaranteedFootnote0 =
p.datum("InforceNonGuaranteedFootnote0" );
- InforceNonGuaranteedFootnote1 =
p.datum("InforceNonGuaranteedFootnote1" );
- InforceNonGuaranteedFootnote2 =
p.datum("InforceNonGuaranteedFootnote2" );
- InforceNonGuaranteedFootnote3 =
p.datum("InforceNonGuaranteedFootnote3" );
- NonGuaranteedFootnote = p.datum("NonGuaranteedFootnote"
);
- MonthlyChargesPaymentFootnote =
p.datum("MonthlyChargesPaymentFootnote" );
- SurrenderFootnote = p.datum("SurrenderFootnote"
);
- PortabilityFootnote = p.datum("PortabilityFootnote"
);
- FundRateFootnote = p.datum("FundRateFootnote"
);
- FundRateFootnote0 = p.datum("FundRateFootnote0"
);
- FundRateFootnote1 = p.datum("FundRateFootnote1"
);
- IssuingCompanyFootnote = p.datum("IssuingCompanyFootnote"
);
- SubsidiaryFootnote = p.datum("SubsidiaryFootnote"
);
- PlacementAgentFootnote = p.datum("PlacementAgentFootnote"
);
- MarketingNameFootnote = p.datum("MarketingNameFootnote"
);
- }
-
- ProductName = b->yare_input_.ProductName;
- ProducerName = b->yare_input_.AgentName;
-
- std::string agent_city = b->yare_input_.AgentCity;
- std::string agent_state = mc_str(b->yare_input_.AgentState);
- std::string agent_zip_code = b->yare_input_.AgentZipCode;
- std::string agent_city_etc(agent_city + ", " + agent_state);
- if(!agent_zip_code.empty())
- {
- agent_city_etc += " ";
- }
- agent_city_etc += agent_zip_code;
-
- ProducerStreet = b->yare_input_.AgentAddress;
- ProducerCity = agent_city_etc;
- CorpName = b->yare_input_.CorporationName;
-
- MasterContractNumber = b->yare_input_.MasterContractNumber;
- ContractNumber = b->yare_input_.ContractNumber;
-
- Insured1 = b->yare_input_.InsuredName;
- Gender = mc_str(b->yare_input_.Gender);
- UWType = mc_str(b->yare_input_.GroupUnderwritingType);
-
- // This could be factored out if it ever needs to be reused.
- //
- // DATABASE !! It would make sense to handle it in the product
- // database if class product_data is rewritten to encompass
- // variation across axes (as class DBDictionary does).
- //
- oenum_smoking_or_tobacco smoke_or_tobacco =
- static_cast<oenum_smoking_or_tobacco>
- (static_cast<int>(b->Database_->Query(DB_SmokeOrTobacco))
- );
- if(oe_tobacco_nontobacco == smoke_or_tobacco)
- {
- switch(b->yare_input_.Smoking)
- {
- case mce_smoker: Smoker = "Tobacco"; break;
- case mce_nonsmoker: Smoker = "Nontobacco"; break;
- case mce_unismoke: Smoker = "Unitobacco"; break;
- }
- }
- else if(oe_smoker_nonsmoker == smoke_or_tobacco)
- {
- Smoker = mc_str(b->yare_input_.Smoking);
- }
- else
- {
- throw std::logic_error("Unknown oe_smoker_nonsmoker convention.");
- }
-
- UWClass = mc_str(b->yare_input_.UnderwritingClass);
- SubstandardTable = mc_str(b->yare_input_.SubstandardTable);
-
- EffDate = calendar_date(b->yare_input_.EffectiveDate
).str();
- EffDateJdn = calendar_date(b->yare_input_.EffectiveDate
).julian_day_number();
- DateOfBirth = calendar_date(b->yare_input_.DateOfBirth
).str();
- DateOfBirthJdn = calendar_date(b->yare_input_.DateOfBirth
).julian_day_number();
- ListBillDate = calendar_date(b->yare_input_.ListBillDate
).str();
- ListBillDateJdn = calendar_date(b->yare_input_.ListBillDate
).julian_day_number();
- InforceAsOfDate =
calendar_date(b->yare_input_.InforceAsOfDate).str();
- InforceAsOfDateJdn =
calendar_date(b->yare_input_.InforceAsOfDate).julian_day_number();
- InitErMode = mc_str(b->Outlay_->er_premium_modes()[0]);
-
- mcenum_dbopt const init_dbo = b->DeathBfts_->dbopt()[0];
- InitDBOpt =
- (mce_option1 == init_dbo) ? dbo_name_option1
- :(mce_option2 == init_dbo) ? dbo_name_option2
- :(mce_rop == init_dbo) ? dbo_name_rop
- :(mce_mdb == init_dbo) ? dbo_name_mdb
- :throw std::logic_error("Unrecognized initial death benefit option.")
- ;
-
- DefnLifeIns = mc_str(b->yare_input_.DefinitionOfLifeInsurance);
- DefnMaterialChange =
mc_str(b->yare_input_.DefinitionOfMaterialChange);
- AvoidMec = mc_str(b->yare_input_.AvoidMecMethod);
- PartMortTableName = "1983 GAM"; // TODO ?? Hardcoded.
- StatePostalAbbrev = mc_str(b->GetStateOfJurisdiction());
- PremiumTaxState = mc_str(b->GetPremiumTaxState());
-
- IsInforce = b->yare_input_.EffectiveDate != b->yare_input_.InforceAsOfDate;
-
- // This test is probably redundant because it is already performed
- // in class Input. But it's difficult to prove that it is actually
- // redundant and will always remain so, while repeating it here
- // costs little and gives a stronger guarantee that illustrations
- // that would violate this rule cannot be produced.
- if(IsInforce && (0 == b->yare_input_.InforceYear && 0 ==
b->yare_input_.InforceMonth))
- {
- alarum()
- << "Inforce illustrations not permitted during month of issue."
- << LMI_FLUSH
- ;
- }
-
- WriteTsvFile = contains(b->yare_input_.Comments, "idiosyncrasyY");
-
- SupplementalReport = b->yare_input_.CreateSupplementalReport;
- SupplementalReportColumn00 =
mc_str(b->yare_input_.SupplementalReportColumn00);
- SupplementalReportColumn01 =
mc_str(b->yare_input_.SupplementalReportColumn01);
- SupplementalReportColumn02 =
mc_str(b->yare_input_.SupplementalReportColumn02);
- SupplementalReportColumn03 =
mc_str(b->yare_input_.SupplementalReportColumn03);
- SupplementalReportColumn04 =
mc_str(b->yare_input_.SupplementalReportColumn04);
- SupplementalReportColumn05 =
mc_str(b->yare_input_.SupplementalReportColumn05);
- SupplementalReportColumn06 =
mc_str(b->yare_input_.SupplementalReportColumn06);
- SupplementalReportColumn07 =
mc_str(b->yare_input_.SupplementalReportColumn07);
- SupplementalReportColumn08 =
mc_str(b->yare_input_.SupplementalReportColumn08);
- SupplementalReportColumn09 =
mc_str(b->yare_input_.SupplementalReportColumn09);
- SupplementalReportColumn10 =
mc_str(b->yare_input_.SupplementalReportColumn10);
- SupplementalReportColumn11 =
mc_str(b->yare_input_.SupplementalReportColumn11);
-
- // irr_initialized_ is deliberately not set here: it's not
- // encompassed by 'FullyInitialized'.
- FullyInitialized = true;
-}
-
-//============================================================================
LedgerInvariant& LedgerInvariant::PlusEq(LedgerInvariant const& a_Addend)
{
LedgerBase::PlusEq(a_Addend, a_Addend.InforceLives);
diff --git a/ledger_invariant_init.cpp b/ledger_invariant_init.cpp
new file mode 100644
index 0000000..0cdfda5
--- /dev/null
+++ b/ledger_invariant_init.cpp
@@ -0,0 +1,530 @@
+// Ledger data that do not vary by basis--initialization.
+//
+// Copyright (C) 1998, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 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 "ledger_invariant.hpp"
+
+#include "alert.hpp"
+#include "assert_lmi.hpp"
+#include "basic_values.hpp"
+#include "contains.hpp"
+#include "database.hpp"
+#include "dbnames.hpp"
+#include "death_benefits.hpp"
+#include "fund_data.hpp"
+#include "interest_rates.hpp"
+#include "loads.hpp"
+#include "mc_enum_types_aux.hpp" // mc_str()
+#include "miscellany.hpp" // each_equal()
+#include "outlay.hpp"
+#include "premium_tax.hpp"
+#include "product_data.hpp"
+#include "ssize_lmi.hpp"
+
+#include <algorithm> // max()
+#include <stdexcept>
+
+void LedgerInvariant::Init(BasicValues const* b)
+{
+ // Zero-initialize almost everything.
+ Init();
+
+ irr_precision_ = b->round_irr().decimals();
+
+// TODO ?? These names are confusing. EePmt and ErPmt are *input* values.
+// If they're entered as $1000 for all years, then they have that value
+// every year, even after lapse. Variables whose names end in -'GrossPmt'
+// hold the results of transaction processing, e.g. $0 after lapse.
+// EePmt and ErPmt are used e.g. in premium-strategy calculations.
+
+ EePmt = b->Outlay_->ee_modal_premiums();
+ ErPmt = b->Outlay_->er_modal_premiums();
+// TgtPrem =
+// GrossPmt =
+// EeGrossPmt =
+// ErGrossPmt =
+ // These must be set dynamically because they may be changed,
+ // e.g. to respect guideline limits.
+// External1035Amount;
+// Internal1035Amount;
+// Dumpin =
+
+ InforceUnloanedAV =
+ b->yare_input_.InforceGeneralAccountValue
+ + b->yare_input_.InforceSeparateAccountValue
+ ;
+ InforceTaxBasis = b->yare_input_.InforceTaxBasis ;
+
+ // Certain data members, including but almost certainly not
+ // limited to these, should not be initialized to any non-zero
+ // value here. Actual values are inserted in account-value
+ // processing, subject to various restrictions that often cause
+ // them to differ from input values. Notably, values need to be
+ // zero after lapse.
+// NetWD =
+// NewCashLoan =
+// GptForceout =
+// NaarForceout =
+// ModalMinimumPremium =
+// EeModalMinimumPremium =
+// ErModalMinimumPremium =
+// ProducerCompensation =
+
+ HasSupplSpecAmt = false;
+ if(b->yare_input_.TermRider)
+ {
+ TermSpecAmt .assign(Length, b->yare_input_.TermRiderAmount);
+ }
+ else if(b->Database_->Query(DB_TermIsNotRider))
+ {
+ TermSpecAmt = b->DeathBfts_->supplamt();
+ if(!each_equal(TermSpecAmt, 0.0))
+ {
+ HasSupplSpecAmt = true;
+ }
+ }
+ else
+ {
+ TermSpecAmt .assign(Length, 0.0);
+ }
+ SpecAmt = b->DeathBfts_->specamt();
+ for(int j = 0; j < Length; ++j)
+ {
+ EeMode[j] = b->Outlay_->ee_premium_modes()[j];
+ ErMode[j] = b->Outlay_->er_premium_modes()[j];
+ DBOpt [j] = b->DeathBfts_->dbopt()[j];
+ }
+
+ IndvTaxBracket = b->yare_input_.TaxBracket ;
+ CorpTaxBracket = b->yare_input_.CorporationTaxBracket ;
+ Salary = b->yare_input_.ProjectedSalary ;
+ AnnualFlatExtra = b->yare_input_.FlatExtra ;
+ HoneymoonValueSpread = b->yare_input_.HoneymoonValueSpread ;
+ AddonMonthlyFee = b->yare_input_.ExtraMonthlyCustodialFee ;
+ AddonCompOnAssets = b->yare_input_.ExtraCompensationOnAssets ;
+ AddonCompOnPremium = b->yare_input_.ExtraCompensationOnPremium;
+ CorridorFactor = b->GetCorridorFactor();
+ AnnLoanDueRate = b->InterestRates_->RegLnDueRate
+ (mce_gen_curr
+ ,mce_annual_rate
+ );
+ InitAnnLoanDueRate = AnnLoanDueRate[0];
+ CurrMandE = b->InterestRates_->MAndERate(mce_gen_curr);
+ TotalIMF = b->InterestRates_->InvestmentManagementFee();
+ RefundableSalesLoad = b->Loads_->refundable_sales_load_proportion();
+
+ std::vector<double> coimult;
+ b->Database_->Query(coimult, DB_CurrCoiMultiplier);
+ CurrentCoiMultiplier =
+ coimult [b->yare_input_.InforceYear]
+ * b->yare_input_.CurrentCoiMultiplier[b->yare_input_.InforceYear]
+ * b->yare_input_.CountryCoiMultiplier
+ ;
+
+ CountryIso3166Abbrev = mc_str(b->yare_input_.Country);
+ Comments = b->yare_input_.Comments;
+
+ FundNumbers .resize(0);
+ FundNames .resize(0);
+ FundAllocs .resize(0);
+ FundAllocations .resize(0);
+
+ // The antediluvian branch has a null FundData_ object.
+ int number_of_funds(0);
+ if(b->FundData_)
+ {
+ number_of_funds = b->FundData_->GetNumberOfFunds();
+ }
+
+// enum{NumberOfFunds = 30}; // DEPRECATED
+ int const NumberOfFunds = 30; // DEPRECATED
+ int expected_number_of_funds = std::max(number_of_funds, NumberOfFunds);
+ std::vector<double> v(b->yare_input_.FundAllocations);
+ if(lmi::ssize(v) < expected_number_of_funds)
+ {
+ v.insert(v.end(), expected_number_of_funds - v.size(), 0.0);
+ }
+
+ for(int j = 0; j < number_of_funds; ++j)
+ {
+ FundNumbers.push_back(j);
+ FundNames.push_back(b->FundData_->GetFundInfo(j).LongName());
+
+ // TODO ?? InputParms::NumberOfFunds is defectively hardcocded
+ // as thirty as this is written, but we need to support a product
+ // with more than thirty funds. The input routines respect that
+ // hardcoded limit and are difficult to change, so funds after
+ // the thirtieth cannot be selected individually; but if the
+ // rule 'equal initial fund allocations' is chosen instead of
+ // specifying individual allocations, then the average fund fee
+ // is calculated reflecting all funds, even past the thirtieth:
+ // thus, calculations are correct for any input, and the defect
+ // in the program itself is just that some legitimate inputs are
+ // not allowed, though the output spreadsheet has its own
+ // hardcoded limit (due to space), which is a separate defect.
+ // Here we pass a zero allocation to the output spreadsheet for
+ // all funds past the thirtieth, which is correct because no
+ // nonzero allocation can be selected. That's correct even if
+ // the 'equal initial allocations' rule is chosen, in which
+ // case the allocations are not explicitly shown, but are instead
+ // stated in words to be equal--because the spreadsheet layout
+ // otherwise shows allocations as integer percentages, and
+ // something like '.3333333...' would overflow the space available.
+ //
+ // As of 2008, most of the foregoing is no longer applicable,
+ // except for the hardcoded limit, which is copied above.
+ FundAllocs .push_back(static_cast<int>(v[j]));
+ FundAllocations.push_back(0.01 * v[j]);
+ }
+
+ GenAcctAllocation = 1.0 - premium_allocation_to_sepacct(b->yare_input_);
+
+ SplitFundAllocation =
+ (0.0 != GenAcctAllocation && 1.0 != GenAcctAllocation)
+ ||
+ ( 0.0 != b->yare_input_.InforceGeneralAccountValue
+ && 0.0 != b->yare_input_.InforceSeparateAccountValue
+ )
+ ;
+
+ NoLapseAlwaysActive = b->Database_->Query(DB_NoLapseAlwaysActive);
+ NoLapseMinDur = b->Database_->Query(DB_NoLapseMinDur);
+ NoLapseMinAge = b->Database_->Query(DB_NoLapseMinAge);
+ Has1035ExchCharge = b->Database_->Query(DB_Has1035ExchCharge);
+
+ // SOMEDAY !! Things indexed with '[0]' should probably use inforce year
instead.
+ InitBaseSpecAmt = b->DeathBfts_->specamt()[0];
+ InitTermSpecAmt = TermSpecAmt[0];
+ ChildRiderAmount = b->yare_input_.ChildRiderAmount;
+ SpouseRiderAmount = b->yare_input_.SpouseRiderAmount;
+
+// InitPrem = 0;
+// GuarPrem = 0;
+// InitSevenPayPrem =
+// InitTgtPrem =
+// InitMinPrem =
+// ListBillPremium =
+// EeListBillPremium =
+// ErListBillPremium =
+// ModalMinimumDumpin =
+
+ MaleProportion = b->yare_input_.MaleProportion;
+ NonsmokerProportion = b->yare_input_.NonsmokerProportion;
+ PartMortTableMult = b->yare_input_.PartialMortalityMultiplier;
+
+ // Assert this because the illustration currently prints a scalar
+ // guaranteed max, assuming that it's the same for all years.
+ std::vector<double> const& guar_m_and_e_rate = b->InterestRates_->MAndERate
+ (mce_gen_guar
+ );
+ LMI_ASSERT(each_equal(guar_m_and_e_rate, guar_m_and_e_rate.front()));
+ GuarMaxMandE = guar_m_and_e_rate[0];
+ InitDacTaxRate =
b->Loads_->dac_tax_load()[b->yare_input_.InforceYear];
+ InitPremTaxRate = b->PremiumTax_->maximum_load_rate();
+// GenderDistinct = 0;
+ GenderBlended = b->yare_input_.BlendGender;
+// SmokerDistinct = 0;
+ SmokerBlended = b->yare_input_.BlendSmoking;
+
+ SubstdTable = b->yare_input_.SubstandardTable;
+
+ Age = b->yare_input_.IssueAge;
+ RetAge = b->yare_input_.RetirementAge;
+ EndtAge = b->yare_input_.IssueAge + b->GetLength();
+ GroupIndivSelection = b->Database_->Query(DB_GroupIndivSelection);
+ UseExperienceRating = b->yare_input_.UseExperienceRating;
+ UsePartialMort = b->yare_input_.UsePartialMortality;
+ AvgFund = b->yare_input_.UseAverageOfAllFunds;
+ CustomFund = b->yare_input_.OverrideFundManagementFee;
+
+ HasWP = b->yare_input_.WaiverOfPremiumBenefit;
+ HasADD = b->yare_input_.AccidentalDeathBenefit;
+ HasTerm = b->yare_input_.TermRider;
+ HasChildRider = b->yare_input_.ChildRider;
+ HasSpouseRider = b->yare_input_.SpouseRider;
+ SpouseIssueAge = b->yare_input_.SpouseIssueAge;
+
+ HasHoneymoon = b->yare_input_.HoneymoonEndorsement;
+ PostHoneymoonSpread = b->yare_input_.PostHoneymoonSpread;
+ SplitMinPrem = b->Database_->Query(DB_SplitMinPrem);
+ AllowDbo3 = b->Database_->Query(DB_AllowDbo3);
+
+ // These are reassigned below based on product data if available.
+ std::string dbo_name_option1 = mc_str(mce_option1);
+ std::string dbo_name_option2 = mc_str(mce_option2);
+ std::string dbo_name_rop = mc_str(mce_rop );
+ std::string dbo_name_mdb = mc_str(mce_mdb ); // DBO3 !! reconsider
+
+ // The antediluvian branch has a null ProductData_ object.
+ if(b->ProductData_)
+ {
+ product_data const& p = *b->ProductData_;
+ // Accommodate one alternative policy-form name.
+ // DATABASE !! It would be much better, of course, to let all
+ // strings in class product_data vary across the same axes as
+ // database_entity objects.
+ bool alt_form = b->Database_->Query(DB_UsePolicyFormAlt);
+ dbo_name_option1 = p.datum("DboNameLevel"
);
+ dbo_name_option2 = p.datum("DboNameIncreasing"
);
+ dbo_name_rop = p.datum("DboNameReturnOfPremium"
);
+// dbo_name_mdb = // DBO3 !! reconsider
+ PolicyForm = p.datum(alt_form ? "PolicyFormAlternative" :
"PolicyForm");
+ PolicyMktgName = p.datum("PolicyMktgName"
);
+ PolicyLegalName = p.datum("PolicyLegalName"
);
+ InsCoShortName = p.datum("InsCoShortName"
);
+ InsCoName = p.datum("InsCoName"
);
+ InsCoAddr = p.datum("InsCoAddr"
);
+ InsCoStreet = p.datum("InsCoStreet"
);
+ InsCoPhone = p.datum("InsCoPhone"
);
+ MainUnderwriter = p.datum("MainUnderwriter"
);
+ MainUnderwriterAddress = p.datum("MainUnderwriterAddress"
);
+ CoUnderwriter = p.datum("CoUnderwriter"
);
+ CoUnderwriterAddress = p.datum("CoUnderwriterAddress"
);
+
+ AvName = p.datum("AvName"
);
+ CsvName = p.datum("CsvName"
);
+ CsvHeaderName = p.datum("CsvHeaderName"
);
+ NoLapseProvisionName = p.datum("NoLapseProvisionName"
);
+ ContractName = p.datum("ContractName"
);
+
+ AccountValueFootnote = p.datum("AccountValueFootnote"
);
+ AttainedAgeFootnote = p.datum("AttainedAgeFootnote"
);
+ CashSurrValueFootnote = p.datum("CashSurrValueFootnote"
);
+ DeathBenefitFootnote = p.datum("DeathBenefitFootnote"
);
+ InitialPremiumFootnote = p.datum("InitialPremiumFootnote"
);
+ NetPremiumFootnote = p.datum("NetPremiumFootnote"
);
+ GrossPremiumFootnote = p.datum("GrossPremiumFootnote"
);
+ OutlayFootnote = p.datum("OutlayFootnote"
);
+ PolicyYearFootnote = p.datum("PolicyYearFootnote"
);
+
+ ADDTerseName = p.datum("ADDTerseName"
);
+ InsurabilityTerseName = p.datum("InsurabilityTerseName"
);
+ ChildTerseName = p.datum("ChildTerseName"
);
+ SpouseTerseName = p.datum("SpouseTerseName"
);
+ TermTerseName = p.datum("TermTerseName"
);
+ WaiverTerseName = p.datum("WaiverTerseName"
);
+ AccelBftRiderTerseName = p.datum("AccelBftRiderTerseName"
);
+ OverloanRiderTerseName = p.datum("OverloanRiderTerseName"
);
+
+ ADDFootnote = p.datum("ADDFootnote"
);
+ ChildFootnote = p.datum("ChildFootnote"
);
+ SpouseFootnote = p.datum("SpouseFootnote"
);
+ TermFootnote = p.datum("TermFootnote"
);
+ WaiverFootnote = p.datum("WaiverFootnote"
);
+ AccelBftRiderFootnote = p.datum("AccelBftRiderFootnote"
);
+ OverloanRiderFootnote = p.datum("OverloanRiderFootnote"
);
+
+ GroupQuoteShortProductName = p.datum("GroupQuoteShortProductName"
);
+ GroupQuoteIsNotAnOffer = p.datum("GroupQuoteIsNotAnOffer"
);
+ GroupQuoteRidersFooter = p.datum("GroupQuoteRidersFooter"
);
+ GroupQuotePolicyFormId = p.datum("GroupQuotePolicyFormId"
);
+ GroupQuoteStateVariations = p.datum("GroupQuoteStateVariations"
);
+ GroupQuoteProspectus = p.datum("GroupQuoteProspectus"
);
+ GroupQuoteUnderwriter = p.datum("GroupQuoteUnderwriter"
);
+ GroupQuoteBrokerDealer = p.datum("GroupQuoteBrokerDealer"
);
+ GroupQuoteRubricMandatory = p.datum("GroupQuoteRubricMandatory"
);
+ GroupQuoteRubricVoluntary = p.datum("GroupQuoteRubricVoluntary"
);
+ GroupQuoteRubricFusion = p.datum("GroupQuoteRubricFusion"
);
+ GroupQuoteFooterMandatory = p.datum("GroupQuoteFooterMandatory"
);
+ GroupQuoteFooterVoluntary = p.datum("GroupQuoteFooterVoluntary"
);
+ GroupQuoteFooterFusion = p.datum("GroupQuoteFooterFusion"
);
+
+ MinimumPremiumFootnote = p.datum("MinimumPremiumFootnote"
);
+ PremAllocationFootnote = p.datum("PremAllocationFootnote"
);
+
+ InterestDisclaimer = p.datum("InterestDisclaimer"
);
+ GuarMortalityFootnote = p.datum("GuarMortalityFootnote"
);
+ ProductDescription = p.datum("ProductDescription"
);
+ StableValueFootnote = p.datum("StableValueFootnote"
);
+ NoVanishPremiumFootnote = p.datum("NoVanishPremiumFootnote"
);
+ RejectPremiumFootnote = p.datum("RejectPremiumFootnote"
);
+ ExpRatingFootnote = p.datum("ExpRatingFootnote"
);
+ MortalityBlendFootnote = p.datum("MortalityBlendFootnote"
);
+ HypotheticalRatesFootnote = p.datum("HypotheticalRatesFootnote"
);
+ SalesLoadRefundFootnote = p.datum("SalesLoadRefundFootnote"
);
+ NoLapseFootnote = p.datum("NoLapseFootnote"
);
+ MarketValueAdjFootnote = p.datum("MarketValueAdjFootnote"
);
+ ExchangeChargeFootnote0 = p.datum("ExchangeChargeFootnote0"
);
+ CurrentValuesFootnote = p.datum("CurrentValuesFootnote"
);
+ DBOption1Footnote = p.datum("DBOption1Footnote"
);
+ DBOption2Footnote = p.datum("DBOption2Footnote"
);
+ ExpRatRiskChargeFootnote = p.datum("ExpRatRiskChargeFootnote"
);
+ ExchangeChargeFootnote1 = p.datum("ExchangeChargeFootnote1"
);
+ FlexiblePremiumFootnote = p.datum("FlexiblePremiumFootnote"
);
+ GuaranteedValuesFootnote = p.datum("GuaranteedValuesFootnote"
);
+ CreditingRateFootnote = p.datum("CreditingRateFootnote"
);
+ GrossRateFootnote = p.datum("GrossRateFootnote"
);
+ NetRateFootnote = p.datum("NetRateFootnote"
);
+ MecFootnote = p.datum("MecFootnote"
);
+ GptFootnote = p.datum("GptFootnote"
);
+ MidpointValuesFootnote = p.datum("MidpointValuesFootnote"
);
+ SinglePremiumFootnote = p.datum("SinglePremiumFootnote"
);
+ MonthlyChargesFootnote = p.datum("MonthlyChargesFootnote"
);
+ UltCreditingRateFootnote = p.datum("UltCreditingRateFootnote"
);
+ MaxNaarFootnote = p.datum("MaxNaarFootnote"
);
+ PremTaxSurrChgFootnote = p.datum("PremTaxSurrChgFootnote"
);
+ PolicyFeeFootnote = p.datum("PolicyFeeFootnote"
);
+ AssetChargeFootnote = p.datum("AssetChargeFootnote"
);
+ InvestmentIncomeFootnote = p.datum("InvestmentIncomeFootnote"
);
+ IrrDbFootnote = p.datum("IrrDbFootnote"
);
+ IrrCsvFootnote = p.datum("IrrCsvFootnote"
);
+ MortalityChargesFootnote = p.datum("MortalityChargesFootnote"
);
+ LoanAndWithdrawalFootnote = p.datum("LoanAndWithdrawalFootnote"
);
+ LoanFootnote = p.datum("LoanFootnote"
);
+ ImprimaturPresale = p.datum("ImprimaturPresale"
);
+ ImprimaturPresaleComposite = p.datum("ImprimaturPresaleComposite"
);
+ ImprimaturInforce = p.datum("ImprimaturInforce"
);
+ ImprimaturInforceComposite = p.datum("ImprimaturInforceComposite"
);
+ StateMarketingImprimatur = p.datum("StateMarketingImprimatur"
);
+ InforceNonGuaranteedFootnote0 =
p.datum("InforceNonGuaranteedFootnote0" );
+ InforceNonGuaranteedFootnote1 =
p.datum("InforceNonGuaranteedFootnote1" );
+ InforceNonGuaranteedFootnote2 =
p.datum("InforceNonGuaranteedFootnote2" );
+ InforceNonGuaranteedFootnote3 =
p.datum("InforceNonGuaranteedFootnote3" );
+ NonGuaranteedFootnote = p.datum("NonGuaranteedFootnote"
);
+ MonthlyChargesPaymentFootnote =
p.datum("MonthlyChargesPaymentFootnote" );
+ SurrenderFootnote = p.datum("SurrenderFootnote"
);
+ PortabilityFootnote = p.datum("PortabilityFootnote"
);
+ FundRateFootnote = p.datum("FundRateFootnote"
);
+ FundRateFootnote0 = p.datum("FundRateFootnote0"
);
+ FundRateFootnote1 = p.datum("FundRateFootnote1"
);
+ IssuingCompanyFootnote = p.datum("IssuingCompanyFootnote"
);
+ SubsidiaryFootnote = p.datum("SubsidiaryFootnote"
);
+ PlacementAgentFootnote = p.datum("PlacementAgentFootnote"
);
+ MarketingNameFootnote = p.datum("MarketingNameFootnote"
);
+ }
+
+ ProductName = b->yare_input_.ProductName;
+ ProducerName = b->yare_input_.AgentName;
+
+ std::string agent_city = b->yare_input_.AgentCity;
+ std::string agent_state = mc_str(b->yare_input_.AgentState);
+ std::string agent_zip_code = b->yare_input_.AgentZipCode;
+ std::string agent_city_etc(agent_city + ", " + agent_state);
+ if(!agent_zip_code.empty())
+ {
+ agent_city_etc += " ";
+ }
+ agent_city_etc += agent_zip_code;
+
+ ProducerStreet = b->yare_input_.AgentAddress;
+ ProducerCity = agent_city_etc;
+ CorpName = b->yare_input_.CorporationName;
+
+ MasterContractNumber = b->yare_input_.MasterContractNumber;
+ ContractNumber = b->yare_input_.ContractNumber;
+
+ Insured1 = b->yare_input_.InsuredName;
+ Gender = mc_str(b->yare_input_.Gender);
+ UWType = mc_str(b->yare_input_.GroupUnderwritingType);
+
+ // This could be factored out if it ever needs to be reused.
+ //
+ // DATABASE !! It would make sense to handle it in the product
+ // database if class product_data is rewritten to encompass
+ // variation across axes (as class DBDictionary does).
+ //
+ oenum_smoking_or_tobacco smoke_or_tobacco =
+ static_cast<oenum_smoking_or_tobacco>
+ (static_cast<int>(b->Database_->Query(DB_SmokeOrTobacco))
+ );
+ if(oe_tobacco_nontobacco == smoke_or_tobacco)
+ {
+ switch(b->yare_input_.Smoking)
+ {
+ case mce_smoker: Smoker = "Tobacco"; break;
+ case mce_nonsmoker: Smoker = "Nontobacco"; break;
+ case mce_unismoke: Smoker = "Unitobacco"; break;
+ }
+ }
+ else if(oe_smoker_nonsmoker == smoke_or_tobacco)
+ {
+ Smoker = mc_str(b->yare_input_.Smoking);
+ }
+ else
+ {
+ throw std::logic_error("Unknown oe_smoker_nonsmoker convention.");
+ }
+
+ UWClass = mc_str(b->yare_input_.UnderwritingClass);
+ SubstandardTable = mc_str(b->yare_input_.SubstandardTable);
+
+ EffDate = calendar_date(b->yare_input_.EffectiveDate
).str();
+ EffDateJdn = calendar_date(b->yare_input_.EffectiveDate
).julian_day_number();
+ DateOfBirth = calendar_date(b->yare_input_.DateOfBirth
).str();
+ DateOfBirthJdn = calendar_date(b->yare_input_.DateOfBirth
).julian_day_number();
+ ListBillDate = calendar_date(b->yare_input_.ListBillDate
).str();
+ ListBillDateJdn = calendar_date(b->yare_input_.ListBillDate
).julian_day_number();
+ InforceAsOfDate =
calendar_date(b->yare_input_.InforceAsOfDate).str();
+ InforceAsOfDateJdn =
calendar_date(b->yare_input_.InforceAsOfDate).julian_day_number();
+ InitErMode = mc_str(b->Outlay_->er_premium_modes()[0]);
+
+ mcenum_dbopt const init_dbo = b->DeathBfts_->dbopt()[0];
+ InitDBOpt =
+ (mce_option1 == init_dbo) ? dbo_name_option1
+ :(mce_option2 == init_dbo) ? dbo_name_option2
+ :(mce_rop == init_dbo) ? dbo_name_rop
+ :(mce_mdb == init_dbo) ? dbo_name_mdb
+ :throw std::logic_error("Unrecognized initial death benefit option.")
+ ;
+
+ DefnLifeIns = mc_str(b->yare_input_.DefinitionOfLifeInsurance);
+ DefnMaterialChange =
mc_str(b->yare_input_.DefinitionOfMaterialChange);
+ AvoidMec = mc_str(b->yare_input_.AvoidMecMethod);
+ PartMortTableName = "1983 GAM"; // TODO ?? Hardcoded.
+ StatePostalAbbrev = mc_str(b->GetStateOfJurisdiction());
+ PremiumTaxState = mc_str(b->GetPremiumTaxState());
+
+ IsInforce = b->yare_input_.EffectiveDate != b->yare_input_.InforceAsOfDate;
+
+ // This test is probably redundant because it is already performed
+ // in class Input. But it's difficult to prove that it is actually
+ // redundant and will always remain so, while repeating it here
+ // costs little and gives a stronger guarantee that illustrations
+ // that would violate this rule cannot be produced.
+ if(IsInforce && (0 == b->yare_input_.InforceYear && 0 ==
b->yare_input_.InforceMonth))
+ {
+ alarum()
+ << "Inforce illustrations not permitted during month of issue."
+ << LMI_FLUSH
+ ;
+ }
+
+ WriteTsvFile = contains(b->yare_input_.Comments, "idiosyncrasyY");
+
+ SupplementalReport = b->yare_input_.CreateSupplementalReport;
+ SupplementalReportColumn00 =
mc_str(b->yare_input_.SupplementalReportColumn00);
+ SupplementalReportColumn01 =
mc_str(b->yare_input_.SupplementalReportColumn01);
+ SupplementalReportColumn02 =
mc_str(b->yare_input_.SupplementalReportColumn02);
+ SupplementalReportColumn03 =
mc_str(b->yare_input_.SupplementalReportColumn03);
+ SupplementalReportColumn04 =
mc_str(b->yare_input_.SupplementalReportColumn04);
+ SupplementalReportColumn05 =
mc_str(b->yare_input_.SupplementalReportColumn05);
+ SupplementalReportColumn06 =
mc_str(b->yare_input_.SupplementalReportColumn06);
+ SupplementalReportColumn07 =
mc_str(b->yare_input_.SupplementalReportColumn07);
+ SupplementalReportColumn08 =
mc_str(b->yare_input_.SupplementalReportColumn08);
+ SupplementalReportColumn09 =
mc_str(b->yare_input_.SupplementalReportColumn09);
+ SupplementalReportColumn10 =
mc_str(b->yare_input_.SupplementalReportColumn10);
+ SupplementalReportColumn11 =
mc_str(b->yare_input_.SupplementalReportColumn11);
+
+ // irr_initialized_ is deliberately not set here: it's not
+ // encompassed by 'FullyInitialized'.
+ FullyInitialized = true;
+}
diff --git a/ledger_variant.cpp b/ledger_variant.cpp
index 52b04be..23f73f1 100644
--- a/ledger_variant.cpp
+++ b/ledger_variant.cpp
@@ -24,15 +24,9 @@
#include "ledger_variant.hpp"
#include "assert_lmi.hpp"
-#include "basic_values.hpp"
-#include "database.hpp" // Used only for initial loan rate.
-#include "dbnames.hpp" // Used only for initial loan rate.
-#include "interest_rates.hpp"
-#include "loads.hpp"
#include "mc_enum_types_aux.hpp" // mc_str()
-#include "outlay.hpp"
-#include <algorithm>
+#include <algorithm> // max()
#include <ostream>
//============================================================================
@@ -187,97 +181,6 @@ void LedgerVariant::Init()
}
//============================================================================
-void LedgerVariant::Init
- (BasicValues const& bv
- ,mcenum_gen_basis gen_basis
- ,mcenum_sep_basis sep_basis
- )
-{
- Init(); // Zero out (almost) everything to start.
-
- GenBasis_ = gen_basis;
- SepBasis_ = sep_basis;
-
-// EOYDeathBft =
-// AcctVal =
-// CSVNet =
-// CV7702 =
-// COICharge =
-// RiderCharges =
-// ExpenseCharges =
- MlySAIntRate = bv.InterestRates_->SepAcctNetRate
- (SepBasis_
- ,GenBasis_
- ,mce_monthly_rate
- );
- MlyGAIntRate = bv.InterestRates_->GenAcctNetRate
- (GenBasis_
- ,mce_monthly_rate
- );
- MlyHoneymoonValueRate = bv.InterestRates_->HoneymoonValueRate
- (GenBasis_
- ,mce_monthly_rate
- );
- MlyPostHoneymoonRate = bv.InterestRates_->PostHoneymoonGenAcctRate
- (GenBasis_
- ,mce_monthly_rate
- );
- AnnSAIntRate = bv.InterestRates_->SepAcctNetRate
- (SepBasis_
- ,GenBasis_
- ,mce_annual_rate
- );
- AnnGAIntRate = bv.InterestRates_->GenAcctNetRate
- (GenBasis_
- ,mce_annual_rate
- );
- AnnHoneymoonValueRate = bv.InterestRates_->HoneymoonValueRate
- (GenBasis_
- ,mce_annual_rate
- );
- AnnPostHoneymoonRate = bv.InterestRates_->PostHoneymoonGenAcctRate
- (GenBasis_
- ,mce_annual_rate
- );
-
-// PrefLoanBalance =
-// TotalLoanBalance=
-// AvgDeathBft =
-// SurrChg =
-// TermPurchased =
-// BaseDeathBft =
-// ProjectedCoiCharge =
-// KFactor =
-
- InitAnnLoanCredRate = bv.InterestRates_->RegLnCredRate
- (GenBasis_
- ,mce_annual_rate
- )[0];
-
- InitAnnGenAcctInt = bv.InterestRates_->GenAcctNetRate
- (GenBasis_
- ,mce_annual_rate
- )
- [0]
- ;
-
- InitAnnSepAcctGrossInt = bv.InterestRates_->SepAcctGrossRate(SepBasis_)[0];
-
- InitAnnSepAcctNetInt = bv.InterestRates_->SepAcctNetRate
- (SepBasis_
- ,GenBasis_
- ,mce_annual_rate
- )
- [0]
- ;
-
- InitTgtPremHiLoadRate =
bv.Loads_->target_premium_load_maximum_premium_tax()[bv.yare_input_.InforceYear];
- InitMlyPolFee = bv.Loads_->monthly_policy_fee(GenBasis_)
[bv.yare_input_.InforceYear];
-
- FullyInitialized = true;
-}
-
-//============================================================================
void LedgerVariant::set_run_basis(mcenum_run_basis b)
{
set_cloven_bases_from_run_basis(b, GenBasis_, SepBasis_);
diff --git a/ledger_variant_init.cpp b/ledger_variant_init.cpp
new file mode 100644
index 0000000..36b4c95
--- /dev/null
+++ b/ledger_variant_init.cpp
@@ -0,0 +1,118 @@
+// Ledger data that vary by basis--initialization.
+//
+// Copyright (C) 1998, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 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 "ledger_variant.hpp"
+
+#include "basic_values.hpp"
+#include "interest_rates.hpp"
+#include "loads.hpp"
+
+void LedgerVariant::Init
+ (BasicValues const& bv
+ ,mcenum_gen_basis gen_basis
+ ,mcenum_sep_basis sep_basis
+ )
+{
+ Init(); // Zero out (almost) everything to start.
+
+ GenBasis_ = gen_basis;
+ SepBasis_ = sep_basis;
+
+// EOYDeathBft =
+// AcctVal =
+// CSVNet =
+// CV7702 =
+// COICharge =
+// RiderCharges =
+// ExpenseCharges =
+ MlySAIntRate = bv.InterestRates_->SepAcctNetRate
+ (SepBasis_
+ ,GenBasis_
+ ,mce_monthly_rate
+ );
+ MlyGAIntRate = bv.InterestRates_->GenAcctNetRate
+ (GenBasis_
+ ,mce_monthly_rate
+ );
+ MlyHoneymoonValueRate = bv.InterestRates_->HoneymoonValueRate
+ (GenBasis_
+ ,mce_monthly_rate
+ );
+ MlyPostHoneymoonRate = bv.InterestRates_->PostHoneymoonGenAcctRate
+ (GenBasis_
+ ,mce_monthly_rate
+ );
+ AnnSAIntRate = bv.InterestRates_->SepAcctNetRate
+ (SepBasis_
+ ,GenBasis_
+ ,mce_annual_rate
+ );
+ AnnGAIntRate = bv.InterestRates_->GenAcctNetRate
+ (GenBasis_
+ ,mce_annual_rate
+ );
+ AnnHoneymoonValueRate = bv.InterestRates_->HoneymoonValueRate
+ (GenBasis_
+ ,mce_annual_rate
+ );
+ AnnPostHoneymoonRate = bv.InterestRates_->PostHoneymoonGenAcctRate
+ (GenBasis_
+ ,mce_annual_rate
+ );
+
+// PrefLoanBalance =
+// TotalLoanBalance=
+// AvgDeathBft =
+// SurrChg =
+// TermPurchased =
+// BaseDeathBft =
+// ProjectedCoiCharge =
+// KFactor =
+
+ InitAnnLoanCredRate = bv.InterestRates_->RegLnCredRate
+ (GenBasis_
+ ,mce_annual_rate
+ )[0];
+
+ InitAnnGenAcctInt = bv.InterestRates_->GenAcctNetRate
+ (GenBasis_
+ ,mce_annual_rate
+ )
+ [0]
+ ;
+
+ InitAnnSepAcctGrossInt = bv.InterestRates_->SepAcctGrossRate(SepBasis_)[0];
+
+ InitAnnSepAcctNetInt = bv.InterestRates_->SepAcctNetRate
+ (SepBasis_
+ ,GenBasis_
+ ,mce_annual_rate
+ )
+ [0]
+ ;
+
+ InitTgtPremHiLoadRate =
bv.Loads_->target_premium_load_maximum_premium_tax()[bv.yare_input_.InforceYear];
+ InitMlyPolFee = bv.Loads_->monthly_policy_fee(GenBasis_)
[bv.yare_input_.InforceYear];
+
+ FullyInitialized = true;
+}
diff --git a/objects.make b/objects.make
index 964b70e..20fb150 100644
--- a/objects.make
+++ b/objects.make
@@ -225,10 +225,12 @@ common_common_objects := \
ledger_base.o \
ledger_evaluator.o \
ledger_invariant.o \
+ ledger_invariant_init.o \
ledger_pdf.o \
ledger_pdf_generator.o \
ledger_text_formats.o \
ledger_variant.o \
+ ledger_variant_init.o \
ledger_xml_io.o \
ledger_xsl.o \
ledgervalues.o \
- [lmi-commits] [lmi] master updated (36ab1d5 -> 081bb55), Greg Chicares, 2018/10/05
- [lmi-commits] [lmi] master 75ce7bd 2/5: Replace operator() with value() for clarity, Greg Chicares, 2018/10/05
- [lmi-commits] [lmi] master 081bb55 5/5: Add a ledger unit test, Greg Chicares, 2018/10/05
- [lmi-commits] [lmi] master a510f95 3/5: Rewrite an empty unit test, Greg Chicares, 2018/10/05
- [lmi-commits] [lmi] master 276c4ff 1/5: In TSV, show scalars' names and values in two columns only, Greg Chicares, 2018/10/05
- [lmi-commits] [lmi] master 72a51b5 4/5: Improve physical separation of concerns,
Greg Chicares <=