lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [5546] Prepare to expunge 'SpecamtHistory'


From: Greg Chicares
Subject: [lmi-commits] [5546] Prepare to expunge 'SpecamtHistory'
Date: Mon, 20 Aug 2012 17:11:41 +0000

Revision: 5546
          http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=5546
Author:   chicares
Date:     2012-08-20 17:11:40 +0000 (Mon, 20 Aug 2012)
Log Message:
-----------
Prepare to expunge 'SpecamtHistory'

Modified Paths:
--------------
    lmi/trunk/input.hpp
    lmi/trunk/input_realization.cpp
    lmi/trunk/input_test.cpp
    lmi/trunk/input_xml_io.cpp

Modified: lmi/trunk/input.hpp
===================================================================
--- lmi/trunk/input.hpp 2012-08-18 11:49:20 UTC (rev 5545)
+++ lmi/trunk/input.hpp 2012-08-20 17:11:40 UTC (rev 5546)
@@ -212,6 +212,12 @@
     std::string RealizeAmountsPaidHistory         ();
     std::string RealizeSpecamtHistory             ();
 
+    int must_overwrite_specamt_with_obsolete_history
+        (std::string specamt
+        ,std::string history
+        ,bool        hide_errors = false
+        ) const;
+
     void make_term_rider_consistent(bool aggressively = true);
 
     boost::scoped_ptr<product_database> database_;

Modified: lmi/trunk/input_realization.cpp
===================================================================
--- lmi/trunk/input_realization.cpp     2012-08-18 11:49:20 UTC (rev 5545)
+++ lmi/trunk/input_realization.cpp     2012-08-20 17:11:40 UTC (rev 5546)
@@ -34,23 +34,24 @@
 #include "database.hpp"
 #include "dbnames.hpp"
 #include "global_settings.hpp"
+#include "handle_exceptions.hpp"
 #include "input_seq_helpers.hpp"
-#include "miscellany.hpp"     // minmax<T>()
+#include "miscellany.hpp"               // minmax<T>()
 #include "round_to.hpp"
-#include "stl_extensions.hpp" // nonstd::is_sorted()
+#include "stl_extensions.hpp"           // nonstd::is_sorted()
 #include "value_cast.hpp"
 
 #include <boost/bind.hpp>
 
 #include <algorithm>
 #include <sstream>
-#include <utility>            // std::pair
+#include <utility>                      // std::pair
 
 //============================================================================
 // Realize sequence strings with only numeric values.
 template<typename T>
 std::string realize_sequence_string
-    (Input               & input
+    (Input          const& input
     ,std::vector<T>      & v
     ,datum_sequence const& sequence_string
     ,int                   index_origin = 0
@@ -73,7 +74,7 @@
 // Realize sequence strings with only enumerative-string values.
 template<typename T>
 std::string realize_sequence_string
-    (Input                  & input
+    (Input             const& input
     ,std::vector<T>         & v
     ,datum_sequence    const& sequence_string
     ,detail::stringmap const& keyword_dictionary
@@ -106,7 +107,7 @@
 // Realize sequence strings with both numeric and enumerative-string values.
 template<typename Numeric, typename Enumerative>
 std::string realize_sequence_string
-    (Input                    & input
+    (Input               const& input
     ,std::vector<Numeric>     & vn
     ,std::vector<Enumerative> & ve
     ,datum_sequence      const& sequence_string
@@ -905,6 +906,86 @@
         );
 }
 
+/// Determine whether specamt must be overwritten with history.
+///
+/// 'SpecifiedAmount' gives values for all policy years since issue,
+/// so 'SpecamtHistory' ought never to been created. Given that it did
+/// exist, it ought to have included only a subset of the values given
+/// by 'SpecifiedAmount'; but some extracts provide only a scalar for
+/// 'SpecifiedAmount', which must therefore be overwritten with the
+/// contents of the obsolete history entity. A warning is given if
+/// this backward-compatibility measure would lose any additional
+/// information given in 'SpecifiedAmount'--e.g., if a user saved an
+/// extract after modifying it to change future specamt without
+/// copying history into 'SpecifiedAmount'.
+///
+/// One of these four values is returned:
+///  0 'SpecifiedAmount' already matches 'SpecamtHistory' through the
+///    inforce as-of date, so 'SpecamtHistory' can be discarded.
+///  1 'SpecifiedAmount' matches 'SpecamtHistory' for future durations
+///    but not for historical durations, so 'SpecifiedAmount' should
+///    be overwritten with 'SpecamtHistory'.
+///  2 Otherwise, they're inconsistent, so a warning is displayed. The
+///    warning may also be displayed when 'SpecifiedAmount' contains
+///    a keyword, in which case consistency is either difficult or
+///    impossible to determine.
+///  3 An unexpected exception occurred in parsing an argument string;
+///    it's trapped, and passed to report_exception().
+/// As the function's name implies, it's used as though it returned a
+/// boolean, but returning an int facilitates unit testing, as does
+/// the last argument.
+
+int Input::must_overwrite_specamt_with_obsolete_history
+    (std::string specamt
+    ,std::string history
+    ,bool        hide_errors
+    ) const
+{
+    std::vector<tnr_unrestricted_double> u;
+    std::vector<tnr_unrestricted_double> v;
+    try
+        {
+        realize_sequence_string(*this, u, numeric_sequence(specamt));
+        realize_sequence_string(*this, v, numeric_sequence(history));
+        }
+    catch(...)
+        {
+        report_exception();
+        return 3;
+        }
+
+    bool history_differs = false;
+    bool future_differs  = false;
+    int const years_of_history = InforceYear.value() + (0 != 
InforceMonth.value());
+    for(int j = 0; j < years_of_history; ++j)
+        {
+        if(u[j] != v[j])
+            {
+            history_differs = true;
+            break;
+            }
+        }
+    for(int j = years_of_history; j < years_to_maturity(); ++j)
+        {
+        if(u[j] != v[j])
+            {
+            future_differs = true;
+            break;
+            }
+        }
+    if(history_differs && future_differs && !hide_errors)
+        {
+        warning()
+            << "Possible conflict between specified amount and history."
+            << " Merge them manually into the specified-amount field."
+            << "\nSpecified amount: " << specamt
+            << "\nHistory: " << history
+            << LMI_FLUSH
+            ;
+        }
+    return history_differs + (history_differs && future_differs);
+}
+
 // TODO ?? More attention could be paid to term-rider rounding.
 // This would be preferable:
 //

Modified: lmi/trunk/input_test.cpp
===================================================================
--- lmi/trunk/input_test.cpp    2012-08-18 11:49:20 UTC (rev 5545)
+++ lmi/trunk/input_test.cpp    2012-08-20 17:11:40 UTC (rev 5546)
@@ -62,6 +62,7 @@
         test_product_database();
         test_input_class();
         test_document_classes();
+        test_obsolete_history();
         assay_speed();
         }
 
@@ -69,6 +70,7 @@
     static void test_product_database();
     static void test_input_class();
     static void test_document_classes();
+    static void test_obsolete_history();
     static void assay_speed();
 
     template<typename DocumentClass>
@@ -342,6 +344,52 @@
     test_document_io<S>("sample.ill", "replica.ill", __FILE__, __LINE__, 
false);
 }
 
+void input_test::test_obsolete_history()
+{
+    Input z;
+    z.InforceYear  = 0;
+    z.InforceMonth = 0;
+    // For new business, history is irrelevant.
+    BOOST_TEST(0 == z.must_overwrite_specamt_with_obsolete_history("0"    , 
"1"           , true));
+    // Year 0, month 1: one year of history.
+    z.InforceYear  = 0;
+    z.InforceMonth = 1;
+    BOOST_TEST(2 == z.must_overwrite_specamt_with_obsolete_history("0"    , 
"1"           , true));
+    BOOST_TEST(0 == z.must_overwrite_specamt_with_obsolete_history("1"    , 
"1"           , true));
+    // Year 1, month 0: one year of history.
+    z.InforceYear  = 1;
+    z.InforceMonth = 0;
+    BOOST_TEST(2 == z.must_overwrite_specamt_with_obsolete_history("0"    , 
"1"           , true));
+    BOOST_TEST(0 == z.must_overwrite_specamt_with_obsolete_history("1"    , 
"1"           , true));
+    BOOST_TEST(0 == z.must_overwrite_specamt_with_obsolete_history("1"    , 
"1;2"         , true));
+    BOOST_TEST(1 == z.must_overwrite_specamt_with_obsolete_history("1;2"  , 
"2"           , true));
+    // "History" after first year doesn't matter.
+    BOOST_TEST(0 == z.must_overwrite_specamt_with_obsolete_history("1;2"  , 
"1"           , true));
+    // Year 1, month 1: two years of history.
+    z.InforceYear  = 1;
+    z.InforceMonth = 1;
+    BOOST_TEST(0 == z.must_overwrite_specamt_with_obsolete_history("1"    , 
"1"           , true));
+    // No conflict: history is a "subset" of specamt.
+    BOOST_TEST(0 == z.must_overwrite_specamt_with_obsolete_history("1;2"  , 
"1;2;3"       , true));
+    BOOST_TEST(2 == z.must_overwrite_specamt_with_obsolete_history("1;2"  , 
"1"           , true));
+    BOOST_TEST(1 == z.must_overwrite_specamt_with_obsolete_history("1;2"  , 
"2"           , true));
+    BOOST_TEST(2 == z.must_overwrite_specamt_with_obsolete_history("1"    , 
"1;2"         , true));
+    BOOST_TEST(2 == z.must_overwrite_specamt_with_obsolete_history("1;2"  , 
"2;3"         , true));
+    BOOST_TEST(0 == z.must_overwrite_specamt_with_obsolete_history("1;2;3", 
"1;2;3"       , true));
+    // Warn if a keyword is used--this one's meaning depends on context.
+    BOOST_TEST(2 == z.must_overwrite_specamt_with_obsolete_history("1;2"  , 
"1;corridor"  , true));
+    // Keyword may engender "obvious" false positives.
+    BOOST_TEST(2 == z.must_overwrite_specamt_with_obsolete_history("1;2"  , 
"1;2;corridor", true));
+    // This would have been forbidden: history was numeric only.
+//  BOOST_TEST(2 == z.must_overwrite_specamt_with_obsolete_history("X"    , 
"1"           , true));
+    BOOST_TEST(2 == z.must_overwrite_specamt_with_obsolete_history("1"    , 
"X"           , true));
+    // This case differs little from the preceding one, but has a different
+    // outcome. Reason: non-numeric substrings are interepreted as zero.
+    // This oddity doesn't matter, because specified amount by its nature
+    // must be positive, and zero is returned so that nothing is changed.
+    BOOST_TEST(0 == z.must_overwrite_specamt_with_obsolete_history("0"    , 
"X"           , true));
+}
+
 void input_test::assay_speed()
 {
     Input raw_data;

Modified: lmi/trunk/input_xml_io.cpp
===================================================================
--- lmi/trunk/input_xml_io.cpp  2012-08-18 11:49:20 UTC (rev 5545)
+++ lmi/trunk/input_xml_io.cpp  2012-08-20 17:11:40 UTC (rev 5546)
@@ -35,11 +35,12 @@
 #include "database.hpp"
 #include "global_settings.hpp"
 #include "map_lookup.hpp"
-#include "miscellany.hpp" // lmi_array_size()
+#include "miscellany.hpp"               // lmi_array_size()
 #include "oecumenic_enumerations.hpp"
 
-#include <algorithm>      // std::min()
+#include <algorithm>                    // std::min()
 #include <stdexcept>
+#include <utility>                      // std::pair
 
 template class xml_serializable<Input>;
 
@@ -528,6 +529,49 @@
         InforceCumulativeGptPremiumsPaid = 
InforceCumulativeNoLapsePayments.value();
         InforceCumulativeRopPayments     = 
InforceCumulativeNoLapsePayments.value();
         }
+
+    if(file_version < 7 && !contains(residuary_names, "SpecamtHistory"))
+        {
+        // Merge obsolete 'SpecamtHistory' into 'SpecifiedAmount'.
+        //
+        // Prior to version 7, 'SpecamtHistory' and 'SpecifiedAmount'
+        // were distinct. Some version-0 files had the history entity,
+        // but others did not; if it's not present, then of course it
+        // cannot be merged.
+        //
+        // Function must_overwrite_specamt_with_obsolete_history(),
+        // called below, requires 'InforceYear' and 'InforceMonth',
+        // which some "deficient" extracts omit. DoTransmogrify()
+        // sets those members downstream, but the "obsolete history"
+        // function needs them now. This requires version 5, which
+        // introduced 'InforceAsOfDate'; no "deficient" extract
+        // should have an earlier version.
+        if(deficient_extract && EffectiveDate.value() != 
InforceAsOfDate.value())
+            {
+            LMI_ASSERT(4 < file_version);
+            std::pair<int,int> ym0 = years_and_months_since
+                (EffectiveDate  .value()
+                ,InforceAsOfDate.value()
+                );
+            InforceYear  = ym0.first;
+            InforceMonth = ym0.second;
+            }
+        // Requiring 'deficient_extract' here wouldn't be right,
+        // because an extract file that has been modified and saved
+        // is no longer detectably "deficient".
+        if(0 != InforceYear || 0 != InforceMonth)
+            {
+            if
+                (must_overwrite_specamt_with_obsolete_history
+                    (SpecifiedAmount.value()
+                    ,SpecamtHistory .value()
+                    )
+                )
+                {
+                SpecifiedAmount = SpecamtHistory.value();
+                }
+            }
+        }
 }
 
 void Input::redintegrate_ad_terminum()




reply via email to

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