lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] master f8bfa9f: Abandon xml rate table experiment


From: Greg Chicares
Subject: [lmi-commits] [lmi] master f8bfa9f: Abandon xml rate table experiment
Date: Thu, 15 Dec 2016 22:25:39 +0000 (UTC)

branch: master
commit f8bfa9f88d3ee7e378986c5658aaba38eb55052e
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>

    Abandon xml rate table experiment
    
    Although this was an interesting idea, we never used it in practice.
    
    SOA has provided tables in several formats, including
     - flat text, which lmi uses and its 'rate_table_tool' supports;
     - binary, which 'rate_table_tool' supports;
     - xml, in a non-free format incompatible with the one removed here;
     - several spreadsheet formats, all of which (astonishingly, even
       their so-called CSV) are incompatible with gnumeric and libreoffice.
    Compared to this or any xml format, the binary format that we use for
    production is more compact and has better runtime performance, while
    the text format that we use for maintenance is much easier for humans
    to read and edit.
---
 Makefile.am              |    1 -
 actuarial_table.cpp      |  465 +++-------------------------------------------
 actuarial_table.hpp      |  132 +++----------
 actuarial_table.rnc      |   92 ---------
 actuarial_table_test.cpp |    6 +-
 objects.make             |   21 ---
 soa2xml.cpp              |  206 --------------------
 soa_helpers.hpp          |  117 ------------
 soa_stress_test.cpp      |  171 -----------------
 test_coding_rules.cpp    |    1 -
 10 files changed, 60 insertions(+), 1152 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index e120e20..c222c97 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1242,7 +1242,6 @@ noinst_HEADERS = \
     single_choice_popup_menu.hpp \
     skeleton.hpp \
     so_attributes.hpp \
-    soa_helpers.hpp \
     stl_extensions.hpp \
     stratified_algorithms.hpp \
     stratified_charges.hpp \
diff --git a/actuarial_table.cpp b/actuarial_table.cpp
index 03833b8..b2f5aae 100644
--- a/actuarial_table.cpp
+++ b/actuarial_table.cpp
@@ -26,12 +26,9 @@
 #include "alert.hpp"
 #include "assert_lmi.hpp"
 #include "deserialize_cast.hpp"
-#include "materially_equal.hpp"
 #include "miscellany.hpp"
 #include "oecumenic_enumerations.hpp"   // methuselah
 #include "path_utility.hpp"             // fs::path inserter
-#include "value_cast.hpp"
-#include "xml_lmi.hpp"
 
 #include <boost/cstdint.hpp>
 #include <boost/filesystem/convenience.hpp>
@@ -39,15 +36,11 @@
 #include <boost/filesystem/path.hpp>
 #include <boost/static_assert.hpp>
 
-#include <xmlwrapp/nodes_view.h>
-
 #include <algorithm>                    // std::max(), std::min()
 #include <cctype>                       // std::toupper()
 #include <climits>                      // CHAR_BIT
-#include <iomanip>                      // std::setprecision()
 #include <ios>
 #include <istream>
-#include <iterator>                     // std::distance()
 #include <limits>
 
 namespace
@@ -86,22 +79,39 @@ namespace
     }
 } // Unnamed namespace.
 
-actuarial_table_base::actuarial_table_base()
-    :table_type_     (-1)
+actuarial_table::actuarial_table(std::string const& filename, int table_number)
+    :filename_       (filename)
+    ,table_number_   (table_number)
+    ,table_type_     (-1)
     ,min_age_        (-1)
     ,max_age_        (-1)
     ,select_period_  (-1)
     ,max_select_age_ (-1)
+    ,table_offset_   (-1)
 {
+    if(table_number_ <= 0)
+        {
+        fatal_error()
+            << "There is no table number "
+            << table_number_
+            << " in file '"
+            << filename_
+            << "'."
+            << LMI_FLUSH
+            ;
+        }
+
+    find_table();
+    parse_table();
 }
 
-actuarial_table_base::~actuarial_table_base()
+actuarial_table::~actuarial_table()
 {
 }
 
 /// Read a given number of values for a given issue age.
 
-std::vector<double> actuarial_table_base::values(int issue_age, int length) 
const
+std::vector<double> actuarial_table::values(int issue_age, int length) const
 {
     return specific_values(issue_age, length);
 }
@@ -113,7 +123,7 @@ std::vector<double> actuarial_table_base::values(int 
issue_age, int length) cons
 /// method: method-specific adjustments are not permitted to render
 /// sane what was insane ab ovo.
 
-std::vector<double> actuarial_table_base::values_elaborated
+std::vector<double> actuarial_table::values_elaborated
     (int                      issue_age
     ,int                      length
     ,e_actuarial_table_method method
@@ -178,347 +188,6 @@ std::vector<double> 
actuarial_table_base::values_elaborated
         }
 }
 
-xml_actuarial_table::xml_actuarial_table(std::string const& filename, int 
table_number)
-{
-    // SOA !! This is temporary code for API compatibility with 
soa_actuarial_table.
-    // It should be changed so that the constructor takes only a single
-    // argument, filename of the XML table file.
-    std::string xmlfile(filename, 0, filename.rfind('.'));
-    xmlfile += "_";
-    xmlfile += value_cast<std::string>(table_number);
-    xmlfile += ".xtable";
-    load_xml_table(xmlfile);
-}
-
-xml_actuarial_table::~xml_actuarial_table()
-{
-}
-
-void xml_actuarial_table::load_xml_table(std::string const& filename)
-{
-    xml_lmi::dom_parser parser(filename);
-    xml::element root(parser.root_node("table"));
-
-    // SOA !! Implement loading of multi-dimensional tables as well.
-    // SOA !! Upgrade xmlwrapp:
-    // XMLWRAPP !! This should be const_iterator, but xmlwrapp < 0.7 lacks the
-    // necessary operator!= for comparing const and non-const iterators.
-    xml::node::iterator i;
-
-    if (root.end() != (i = root.find("aggregate")))
-        {
-        load_xml_aggregate_table(*i);
-        }
-    else if (root.end() != (i = root.find("duration")))
-        {
-        load_xml_duration_table(*i);
-        }
-    else if (root.end() != (i = root.find("select")))
-        {
-        load_xml_select_table(*i);
-        }
-    else if (root.end() != (i = root.find("select-and-ultimate")))
-        {
-        load_xml_select_and_ultimate_table(*i);
-        }
-    else
-        {
-        fatal_error()
-            << "Required data element not found."
-            << LMI_FLUSH
-            ;
-        }
-}
-
-void xml_actuarial_table::load_xml_table_with_ages
-    (xml::element const& node
-    ,std::vector<double>& data
-    ,int& min_age
-    ,int& max_age
-    )
-{
-    xml::const_nodes_view const values = node.elements("value");
-
-    data.reserve(std::distance(values.begin(), values.end()));
-
-    min_age = max_age = -1;
-
-    typedef xml::const_nodes_view::const_iterator cnvi;
-    for(cnvi i = values.begin(); i != values.end(); ++i)
-        {
-        data.push_back(value_cast<double>(xml_lmi::get_content(*i)));
-        int age;
-        if(!xml_lmi::get_attr(*i, "age", age))
-            {
-            fatal_error()
-                << "XML <value> node doesn't have 'age' attribute."
-                << LMI_FLUSH
-                ;
-            }
-        if(-1 == min_age)
-            {
-            min_age = age;
-            }
-        else
-            {
-            if(max_age + 1 != age)
-                {
-                fatal_error()
-                    << "XML <value> node has 'age' attribute value '"
-                    << age
-                    << "' but '"
-                    << max_age + 1
-                    << "' was expected."
-                    << LMI_FLUSH
-                    ;
-                }
-            }
-        max_age = age;
-        }
-
-    LMI_ASSERT(data.size() == size_t(max_age - min_age + 1));
-}
-
-void xml_actuarial_table::load_xml_aggregate_table(xml::element const& node)
-{
-    load_xml_table_with_ages
-        (node
-        ,data_
-        ,min_age_
-        ,max_age_
-        );
-
-    table_type_ = e_table_aggregate;
-}
-
-void xml_actuarial_table::load_xml_duration_table(xml::element const& node)
-{
-    xml::const_nodes_view const values = node.elements("value");
-
-    data_.reserve(std::distance(values.begin(), values.end()));
-
-    typedef xml::const_nodes_view::const_iterator cnvi;
-    for(cnvi i = values.begin(); i != values.end(); ++i)
-        {
-        data_.push_back(value_cast<double>(xml_lmi::get_content(*i)));
-        }
-
-    table_type_ = e_table_duration;
-}
-
-void xml_actuarial_table::load_xml_select_table(xml::element const& node)
-{
-    xml::const_nodes_view const rows = node.elements("row");
-
-    if(!xml_lmi::get_attr(node, "period", select_period_))
-        {
-        fatal_error()
-            << "XML <select> node doesn't have 'period' attribute."
-            << LMI_FLUSH
-            ;
-        }
-
-    data_.reserve(std::distance(rows.begin(), rows.end()) * select_period_);
-
-    min_age_ = max_age_ = -1;
-
-    typedef xml::const_nodes_view::const_iterator cnvi;
-    for(cnvi i = rows.begin(); i != rows.end(); ++i)
-        {
-        int age;
-        if(!xml_lmi::get_attr(*i, "age", age))
-            {
-            fatal_error()
-                << "XML <row> node doesn't have 'age' attribute."
-                << LMI_FLUSH
-                ;
-            }
-        if(-1 == min_age_)
-            {
-            min_age_ = age;
-            }
-        else
-            {
-            if(max_age_ + 1 != age)
-                {
-                fatal_error()
-                    << "XML <row> node has 'age' attribute value '"
-                    << age
-                    << "' but '"
-                    << max_age_ + 1
-                    << "' was expected."
-                    << LMI_FLUSH
-                    ;
-                }
-            }
-        max_age_ = age;
-
-        xml::const_nodes_view const values = i->elements("value");
-        if(select_period_ != std::distance(values.begin(), values.end()))
-            {
-            fatal_error()
-                << "XML <row> node has "
-                << std::distance(values.begin(), values.end())
-                << " values but select period is "
-                << select_period_
-                << "."
-                << LMI_FLUSH
-                ;
-            }
-
-        for(cnvi v = values.begin(); v != values.end(); ++v)
-            {
-            data_.push_back(value_cast<double>(xml_lmi::get_content(*v)));
-            }
-        }
-
-    max_select_age_ = max_age_;
-
-    LMI_ASSERT(data_.size() == size_t((max_age_ - min_age_ + 1) * 
select_period_));
-
-    // Use the same type for select and select & ultimate tables: selected
-    // table is just a special case of the latter where max_age_ ==
-    // max_select_age_ and the ultimate table is empty.
-    table_type_ = e_table_select_and_ultimate;
-}
-
-void xml_actuarial_table::load_xml_select_and_ultimate_table(xml::element 
const& node)
-{
-    load_xml_select_table(*xml_lmi::retrieve_element(node, "select"));
-
-    int ultimate_min_age;
-    load_xml_table_with_ages
-        (*xml_lmi::retrieve_element(node, "ultimate")
-        ,ultimate_
-        ,ultimate_min_age
-        ,max_age_
-        );
-
-    if(ultimate_min_age != min_age_ + select_period_)
-        {
-        fatal_error()
-            << "Ultimate table should have min. age "
-            << min_age_
-            << ", but has "
-            << ultimate_min_age
-            << "."
-            << LMI_FLUSH
-            ;
-        }
-
-    table_type_ = e_table_select_and_ultimate;
-}
-
-std::vector<double> xml_actuarial_table::specific_values
-    (int issue_age
-    ,int length
-    ) const
-{
-    if(table_type_ != e_table_duration)
-        {
-        // min_age_ and max_age_ are invalid for duration tables
-        LMI_ASSERT(min_age_ <= issue_age && issue_age <= max_age_);
-        LMI_ASSERT(0 <= length && length <= 1 + max_age_ - issue_age);
-        }
-
-    std::vector<double> v;
-    switch(table_type_)
-        {
-        case e_table_aggregate:
-            {
-            // Parenthesize the offsets--addition in C and C++ is
-            // in effect left associative:
-            //   data_.begin() + issue_age - min_age_
-            // means
-            //   (data_.begin() + issue_age) - min_age_
-            // but the subexpression
-            //   (data_.begin() + issue_age)
-            // is likely to return a past-the-end iterator, which
-            // libstdc++'s debug mode will dislike.
-            //
-            v = std::vector<double>
-                (data_.begin() + (issue_age - min_age_)
-                ,data_.begin() + (issue_age - min_age_ + length)
-                );
-            }
-            break;
-        case e_table_duration:
-            {
-            v = std::vector<double>
-                (data_.begin()
-                ,data_.begin() + length
-                );
-            }
-            break;
-        case e_table_select_and_ultimate:
-            {
-            v.resize(length);
-            std::vector<double>::iterator cursor = v.begin();
-
-            int row_to_start_at;
-
-            // Write select portion:
-            if(issue_age < max_select_age_ + select_period_)
-                {
-                row_to_start_at = (std::min(max_select_age_, issue_age) - 
min_age_);
-                int offset_in_row = std::max(0, issue_age - max_select_age_);
-                int k = offset_in_row
-                    +   row_to_start_at * select_period_
-                    ;
-                for(int i = offset_in_row; cursor != v.end() && i < 
select_period_; i++, k++)
-                    *(cursor++) = data_[k];
-                }
-            else
-                {
-                const int min_ultimate_age = min_age_ + select_period_;
-                row_to_start_at = issue_age - min_ultimate_age;
-                }
-
-            // And ultimate:
-            for(int k = row_to_start_at; cursor != v.end(); k++)
-                *(cursor++) = ultimate_[k];
-            }
-            break;
-
-        default:
-            {
-            fatal_error()
-                << "Table type '"
-                << table_type_
-                << "' not recognized: must be one of 'A', 'D', or 'S'."
-                << LMI_FLUSH
-                ;
-            }
-        }
-    LMI_ASSERT(v.size() == static_cast<unsigned int>(length));
-    return v;
-}
-
-soa_actuarial_table::soa_actuarial_table(std::string const& filename, int 
table_number)
-    :filename_       (filename)
-    ,table_number_   (table_number)
-    ,table_offset_   (-1)
-{
-    if(table_number_ <= 0)
-        {
-        fatal_error()
-            << "There is no table number "
-            << table_number_
-            << " in file '"
-            << filename_
-            << "'."
-            << LMI_FLUSH
-            ;
-        }
-
-    find_table();
-    parse_table();
-}
-
-soa_actuarial_table::~soa_actuarial_table()
-{
-}
-
 /// Find the table specified by table_number_.
 ///
 /// SOA documentation does not specify the domain of table numbers,
@@ -534,7 +203,7 @@ soa_actuarial_table::~soa_actuarial_table()
 /// Asserting that the table number is nonzero makes it safe to use
 /// zero as a sentry.
 
-void soa_actuarial_table::find_table()
+void actuarial_table::find_table()
 {
     LMI_ASSERT(0 != table_number_);
 
@@ -569,9 +238,7 @@ void soa_actuarial_table::find_table()
     BOOST_STATIC_ASSERT(sizeof(boost::int32_t) <= sizeof(int));
     while(index_ifs)
         {
-        int index_table_number =
-            deserialize_cast<boost::int32_t>(index_record)
-            ;
+        int index_table_number = 
deserialize_cast<boost::int32_t>(index_record);
         if(table_number_ == index_table_number)
             {
             char* p = 54 + index_record;
@@ -629,7 +296,7 @@ void soa_actuarial_table::find_table()
 ///   15   2-byte integer:  Maximum select age (if zero, then it's max age)
 ///   17   8-byte doubles:  Table values
 
-void soa_actuarial_table::parse_table()
+void actuarial_table::parse_table()
 {
     LMI_ASSERT(-1 == table_type_    );
     LMI_ASSERT(-1 == min_age_       );
@@ -774,7 +441,7 @@ void soa_actuarial_table::parse_table()
 /// taken as unlimited, so its value should be max_age_; this
 /// implementation makes it so after the fact.
 
-void soa_actuarial_table::read_values(std::istream& is, int nominal_length)
+void actuarial_table::read_values(std::istream& is, int nominal_length)
 {
     if('S' != table_type_)
         {
@@ -831,7 +498,7 @@ void soa_actuarial_table::read_values(std::istream& is, int 
nominal_length)
 /// considered preferable to throw an exception, in case permitting
 /// issue age to exceed max_select_age_ is an inadvertent mistake.
 
-std::vector<double> soa_actuarial_table::specific_values
+std::vector<double> actuarial_table::specific_values
     (int issue_age
     ,int length
     ) const
@@ -842,7 +509,7 @@ std::vector<double> soa_actuarial_table::specific_values
     std::vector<double> v;
     switch(table_type_)
         {
-        case e_table_aggregate:
+        case 'A':
             {
             // Parenthesize the offsets--addition in C and C++ is
             // in effect left associative:
@@ -860,7 +527,7 @@ std::vector<double> soa_actuarial_table::specific_values
                 );
             }
             break;
-        case e_table_duration:
+        case 'D':
             {
             v = std::vector<double>
                 (data_.begin()
@@ -868,7 +535,7 @@ std::vector<double> soa_actuarial_table::specific_values
                 );
             }
             break;
-        case e_table_select_and_ultimate:
+        case 'S':
             {
             int const stride = 1 + select_period_;
             int k =
@@ -903,38 +570,6 @@ std::vector<double> soa_actuarial_table::specific_values
     return v;
 }
 
-#if defined LMI_USE_XML_TABLES
-namespace
-{
-    bool almost_equal_doubles(std::vector<double> const& a, 
std::vector<double> const& b)
-    {
-        if(a.size() != b.size())
-            return false;
-
-        size_t const size = a.size();
-        for(size_t i = 0; i < size; i++)
-            {
-            if(!materially_equal(a[i], b[i], 2.0E-15L))
-                {
-                warning()
-                    << i << " i\n"
-                    << value_cast<std::string>(a[i]) << " ... a[i]\n"
-                    << value_cast<std::string>(b[i]) << " ... b[i]\n"
-                    << std::setprecision(20)
-                    << a[i] << " a[i]\n"
-                    << b[i] << " b[i]\n"
-                    << value_cast<std::string>((b[i] - a[i]) / b[i]) << " 
(b[i] - a[i]) / b[i]\n"
-                    << LMI_FLUSH
-                    ;
-                return false;
-                }
-            }
-
-        return true;
-    }
-} // Unnamed namespace.
-#endif // defined LMI_USE_XML_TABLES
-
 std::vector<double> actuarial_table_rates
     (std::string const& table_filename
     ,int                table_number
@@ -942,22 +577,8 @@ std::vector<double> actuarial_table_rates
     ,int                length
     )
 {
-#if defined LMI_USE_XML_TABLES
-    xml_actuarial_table     z(table_filename, table_number);
-    soa_actuarial_table z_soa(table_filename, table_number);
-
-    std::vector<double> values    (z.values(issue_age, length));
-    std::vector<double> values_soa(z_soa.values(issue_age, length));
-
-    // SOA !! Temporarily verify correctness of XML implementation,
-    // remove this once satisfied
-    LMI_ASSERT(almost_equal_doubles(values, values_soa));
-    return values;
-#else  // !defined LMI_USE_XML_TABLES
-// SOA !! Ultimately, there will be only one class:
     actuarial_table z(table_filename, table_number);
     return z.values(issue_age, length);
-#endif // !defined LMI_USE_XML_TABLES
 }
 
 std::vector<double> actuarial_table_rates_elaborated
@@ -970,31 +591,6 @@ std::vector<double> actuarial_table_rates_elaborated
     ,int                      reset_duration
     )
 {
-#if defined LMI_USE_XML_TABLES
-    xml_actuarial_table     z(table_filename, table_number);
-    soa_actuarial_table z_soa(table_filename, table_number);
-
-    std::vector<double> values(z.values_elaborated
-        (issue_age
-        ,length
-        ,method
-        ,inforce_duration
-        ,reset_duration
-        ));
-    std::vector<double> values_soa(z_soa.values_elaborated
-        (issue_age
-        ,length
-        ,method
-        ,inforce_duration
-        ,reset_duration
-        ));
-
-    // SOA !! Temporarily verify correctness of XML implementation,
-    // remove this once satisfied
-    LMI_ASSERT(almost_equal_doubles(values, values_soa));
-    return values;
-#else  // !defined LMI_USE_XML_TABLES
-// SOA !! Ultimately, there will be only one class:
     actuarial_table z(table_filename, table_number);
     return z.values_elaborated
         (issue_age
@@ -1003,6 +599,5 @@ std::vector<double> actuarial_table_rates_elaborated
         ,inforce_duration
         ,reset_duration
         );
-#endif // !defined LMI_USE_XML_TABLES
 }
 
diff --git a/actuarial_table.hpp b/actuarial_table.hpp
index 526b03c..20f367a 100644
--- a/actuarial_table.hpp
+++ b/actuarial_table.hpp
@@ -26,7 +26,6 @@
 
 #include "obstruct_slicing.hpp"
 #include "uncopyable_lmi.hpp"
-#include "xml_lmi_fwd.hpp"
 
 #include <iosfwd>
 #include <string>
@@ -114,98 +113,9 @@ enum e_actuarial_table_method
     ,e_reenter_upon_rate_reset     = 2
     };
 
-/// Types of actuarial tables.
-
-enum e_table_type
-    {e_table_invalid               = -1
-    ,e_table_aggregate             = 'A'
-    ,e_table_duration              = 'D'
-    ,e_table_select_and_ultimate   = 'S'
-    };
-
-/// Base class for actuarial tables, both XML and binary.
-/// SOA !! This is only temporary, merge with xml_actuarial_table into
-/// single class once we remove binary SOA format support
-
-class actuarial_table_base
-{
-  public:
-    actuarial_table_base();
-    virtual ~actuarial_table_base();
-
-    std::vector<double> values(int issue_age, int length) const;
-    std::vector<double> values_elaborated
-        (int                      issue_age
-        ,int                      length
-        ,e_actuarial_table_method method
-        ,int                      inforce_duration
-        ,int                      reset_duration
-        ) const;
-
-    char               table_type     () const {return table_type_     ;}
-    int                min_age        () const {return min_age_        ;}
-    int                max_age        () const {return max_age_        ;}
-    int                select_period  () const {return select_period_  ;}
-    int                max_select_age () const {return max_select_age_ ;}
-
-  protected:
-    virtual std::vector<double> specific_values(int issue_age, int length) 
const = 0;
-
-    // Table parameters, in order read from table header.
-    char table_type_     ;
-    int  min_age_        ;
-    int  max_age_        ;
-    int  select_period_  ;
-    int  max_select_age_ ;
-};
-
-/// Read actuarial table from XML file.
-
-class xml_actuarial_table
-    :        public  actuarial_table_base
-    ,        private lmi::uncopyable <xml_actuarial_table>
-    ,virtual private obstruct_slicing<xml_actuarial_table>
-{
-  public:
-    xml_actuarial_table(std::string const& filename, int table_number);
-    virtual ~xml_actuarial_table();
-
-  protected:
-    std::vector<double> specific_values(int issue_age, int length) const;
-
-  private:
-    void load_xml_table                    (std::string const& filename);
-    void load_xml_aggregate_table          (xml::element const& node);
-    void load_xml_duration_table           (xml::element const& node);
-    void load_xml_select_table             (xml::element const& node);
-    void load_xml_select_and_ultimate_table(xml::element const& node);
-    void load_xml_table_with_ages
-        (xml::element const& node
-        ,std::vector<double>& data
-        ,int& min_age
-        ,int& max_age
-        );
-
-    // Table data. For 1D tables (e_table_aggregate and e_table_duration), this
-    // is the vector of values from min_age_ to max_age_.
-    // For e_table_select_and_ultimate, the content is organized by rows, with
-    // select_period_ entries per row, with rows ranging from min_age_ to
-    // max_select_age_.
-    std::vector<double> data_;
-
-    // For e_table_select_and_ultimate, this vector contains the ultimate
-    // column. The first value, ultimate_[0], is for min_age_+select_period_,
-    // the last is for max_select_age_.
-    std::vector<double> ultimate_;
-};
-
 /// Read a table from a database in the binary format designed by the
 /// Society of Actuaries (SOA) and used for the tables SOA publishes.
 ///
-/// This is deprecated, old format, this class' code is left in only
-/// temporarily for the purpose of validating the new XML-based format
-/// loader's correctness.
-///
 /// Do not check CRCs of these tables as the SOA software does. Tests
 /// show that CRC checking makes the illustration system considerably
 /// slower. Data should generally be validated against published
@@ -218,16 +128,30 @@ class xml_actuarial_table
 /// has apparently chosen to leave them that way for backward
 /// compatibility.
 
-class soa_actuarial_table
-    :        public  actuarial_table_base
-    ,        private lmi::uncopyable <soa_actuarial_table>
-    ,virtual private obstruct_slicing<soa_actuarial_table>
+class actuarial_table
+    :        private lmi::uncopyable <actuarial_table>
+    ,virtual private obstruct_slicing<actuarial_table>
 {
   public:
-    soa_actuarial_table(std::string const& filename, int table_number);
-    virtual ~soa_actuarial_table();
+    actuarial_table(std::string const& filename, int table_number);
+    ~actuarial_table();
+
+    std::vector<double> values(int issue_age, int length) const;
+    std::vector<double> values_elaborated
+        (int                      issue_age
+        ,int                      length
+        ,e_actuarial_table_method method
+        ,int                      inforce_duration
+        ,int                      reset_duration
+        ) const;
 
     std::string const& filename       () const {return filename_       ;}
+    int                table_number   () const {return table_number_   ;}
+    char               table_type     () const {return table_type_     ;}
+    int                min_age        () const {return min_age_        ;}
+    int                max_age        () const {return max_age_        ;}
+    int                select_period  () const {return select_period_  ;}
+    int                max_select_age () const {return max_select_age_ ;}
 
   private:
     void find_table();
@@ -239,7 +163,13 @@ class soa_actuarial_table
     std::string filename_     ;
     int         table_number_ ;
 
-    // Table data.
+    // Table parameters, in order read from table header.
+    char table_type_     ;
+    int  min_age_        ;
+    int  max_age_        ;
+    int  select_period_  ;
+    int  max_select_age_ ;
+
     std::vector<double> data_;
 
     std::streampos table_offset_;
@@ -268,13 +198,5 @@ std::vector<double> actuarial_table_rates_elaborated
     ,int                      reset_duration
     );
 
-// #define LMI_USE_XML_TABLES
-
-#if defined LMI_USE_XML_TABLES
-typedef xml_actuarial_table actuarial_table;
-#else  // !defined LMI_USE_XML_TABLES
-typedef soa_actuarial_table actuarial_table;
-#endif // !defined LMI_USE_XML_TABLES
-
 #endif // actuarial_table_hpp
 
diff --git a/actuarial_table.rnc b/actuarial_table.rnc
deleted file mode 100644
index 5157657..0000000
--- a/actuarial_table.rnc
+++ /dev/null
@@ -1,92 +0,0 @@
-# RELAX NG schema for '.xtable' files (class actuarial_table).
-#
-# Copyright (C) 2012, 2013, 2014, 2015, 2016 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
-
-start =
-    element table
-        {element description {text}?
-        ,(basic_table
-         |smoking_element
-         |gender_element
-         )
-        }
-
-smoking_element =
-    element smoking
-        {element item
-            {attribute for {smoking}
-            ,(basic_table|gender_element)
-            }+
-        }
-
-gender_element =
-    element gender
-        {element item
-            {attribute for {gender}
-            ,basic_table
-            }+
-        }
-
-basic_table =
-         aggregate_element
-        |duration_element
-        |select_element
-        |select_and_ultimate_element
-
-aggregate_element =
-    element aggregate {aggregate_content}
-
-aggregate_content =
-    element value
-        {attribute age {table_age_int}
-        ,proportion_double
-        }+
-
-duration_element =
-    element duration {duration_content}
-
-duration_content =
-    element value {proportion_double}+
-
-select_element =
-    element select
-        {attribute period  {xsd:positiveInteger}
-        ,element row
-            {attribute age {table_age_int}
-            ,element value
-                {proportion_double
-                }+
-            }+
-        }
-
-select_and_ultimate_element =
-    element select-and-ultimate
-        {select_element
-        ,element ultimate {aggregate_content}
-        }
-
-## Attained age (deliberately less restrictive than the similar type in 
'types.rnc').
-table_age_int      = xsd:nonNegativeInteger
-
-## Time interval in years (deliberately less restrictive than the similar type 
in 'types.rnc').
-table_duration_int = xsd:nonNegativeInteger
-
-include "types.rnc"
-
diff --git a/actuarial_table_test.cpp b/actuarial_table_test.cpp
index 4256325..07b08ff 100644
--- a/actuarial_table_test.cpp
+++ b/actuarial_table_test.cpp
@@ -244,14 +244,14 @@ void test_precondition_failures()
         (actuarial_table("nonexistent", 0)
         ,std::runtime_error
         ,"There is no table number 0 in file 'nonexistent'."
-        ); // SOA !! Revise for xml.
+        );
 
     BOOST_TEST_THROW
         (actuarial_table("nonexistent", 1)
         ,std::runtime_error
         ,"File 'nonexistent.ndx' is required but could not be found."
          " Try reinstalling."
-        ); // SOA !! Revise for xml.
+        );
 
     std::ifstream ifs((qx_cso + ".ndx").c_str(), ios_in_binary());
     std::ofstream ofs("eraseme.ndx", ios_out_trunc_binary());
@@ -262,7 +262,7 @@ void test_precondition_failures()
         ,std::runtime_error
         ,"File 'eraseme.dat' is required but could not be found."
          " Try reinstalling."
-        ); // SOA !! Revise for xml.
+        );
     BOOST_TEST(0 == std::remove("eraseme.ndx"));
 
     actuarial_table z(qx_ins, 256);
diff --git a/objects.make b/objects.make
index 7e17a46..69327c8 100644
--- a/objects.make
+++ b/objects.make
@@ -1034,27 +1034,6 @@ bcc_rc$(EXEEXT): \
   system_command.o \
   system_command_non_wx.o \
 
-# Temporary tools for migration from binary to xml actuarial tables.
-# SOA !! Expunge after migration.
-
-soa2xml$(EXEEXT): \
-  $(boost_filesystem_objects) \
-  $(xmlwrapp_objects) \
-  actuarial_table.o \
-  alert.o \
-  alert_cli.o \
-  soa2xml.o \
-  xml_lmi.o \
-
-soa_stress_test$(EXEEXT): \
-  $(boost_filesystem_objects) \
-  $(xmlwrapp_objects) \
-  actuarial_table.o \
-  alert.o \
-  alert_cli.o \
-  soa_stress_test.o \
-  xml_lmi.o \
-
 
################################################################################
 
 # Product files.
diff --git a/soa2xml.cpp b/soa2xml.cpp
deleted file mode 100644
index ec18d54..0000000
--- a/soa2xml.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-// Convert SOA tables to xml.
-//
-// Copyright (C) 2012, 2013, 2014, 2015, 2016 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 "actuarial_table.hpp"
-#include "soa_helpers.hpp"
-#include "value_cast.hpp"
-
-#include <xmlwrapp/attributes.h>
-#include <xmlwrapp/document.h>
-#include <xmlwrapp/node.h>
-
-#include <ios>
-#include <iostream>
-#include <istream>
-#include <ostream>
-
-/************************************************************************
- misc helpers
- ************************************************************************/
-
-template<typename T>
-inline char const* as_str(T x)
-{
-    static std::string tmp;
-    tmp = value_cast<std::string>(x);
-    return tmp.c_str();
-}
-
-/************************************************************************
- conversion code
- ************************************************************************/
-
-xml::node xml_for_aggregate_table(soa_actuarial_table const& t)
-{
-    xml::node n("aggregate");
-
-    std::vector<double> const values =
-        t.values(t.min_age(), t.max_age() - t.min_age() + 1);
-
-    for(unsigned int i = 0; i < values.size(); i++)
-        {
-        xml::node v("value", as_str(values[i]));
-        v.get_attributes().insert("age", as_str(t.min_age() + i));
-        n.insert(v);
-        }
-
-    return n;
-}
-
-xml::node xml_for_duration_table(soa_actuarial_table const& t)
-{
-    xml::node n("duration");
-
-    std::vector<double> const values =
-        t.values(t.min_age(), t.max_age() - t.min_age() + 1);
-
-    for(unsigned int i = 0; i < values.size(); i++)
-        {
-        xml::node v("value", as_str(values[i]));
-        n.insert(v);
-        }
-
-    return n;
-}
-
-xml::node xml_for_select_and_ultimate_table(soa_actuarial_table const& t)
-{
-    xml::node n("select-and-ultimate");
-
-    xml::node n_select("select");
-    xml::node n_ultimate("ultimate");
-
-    // Write the <select> portion:
-    n_select.get_attributes().insert("period", as_str(t.select_period()));
-    for(int age = t.min_age(); age <= t.max_select_age(); age++)
-        {
-            std::vector<double> data = t.values(age, t.select_period());
-            xml::node n_row("row");
-            n_row.get_attributes().insert("age", as_str(age));
-            for (int s = 0; s < t.select_period(); s++)
-                {
-                xml::node v("value", as_str(data[s]));
-                n_row.insert(v);
-                }
-
-            n_select.insert(n_row);
-        }
-
-    // Write the <ultimate> portion:
-    for(int age = t.min_age(); age <= t.max_select_age(); age++)
-        {
-        std::vector<double> data = t.values(age, t.select_period() + 1);
-        xml::node v("value", as_str(data.back()));
-        v.get_attributes().insert("age", as_str(age + t.select_period()));
-        n_ultimate.insert(v);
-        }
-    for(int age = t.max_select_age() + t.select_period() + 1; age <= 
t.max_age(); age++)
-        {
-        std::vector<double> data = t.values(age, 1);
-        xml::node v("value", as_str(data.back()));
-        v.get_attributes().insert("age", as_str(age));
-        n_ultimate.insert(v);
-        }
-
-    n.insert(n_select);
-    n.insert(n_ultimate);
-
-    return n;
-}
-
-void export_single_table(char const* filename, int index, char const* 
description)
-{
-    fs::path table_path(filename);
-    soa_actuarial_table table(filename, index);
-
-    std::cout
-        << table.table_type()
-        << " table #"
-        << index
-        << ":\t"
-        << description
-        << std::endl;
-
-    xml::node root("table");
-    root.insert(xml::node("description", description));
-
-    switch(table.table_type())
-        {
-        case 'A':
-            root.insert(xml_for_aggregate_table(table));
-            break;
-
-        case 'D':
-            root.insert(xml_for_duration_table(table));
-            break;
-
-        case 'S':
-            root.insert(xml_for_select_and_ultimate_table(table));
-            break;
-
-        default:
-            fatal_error()
-                << "Unknown table type '"
-                << table.table_type()
-                << "'."
-                << LMI_FLUSH
-                ;
-        }
-
-    xml::document doc(root);
-
-    char xmlsuffix[64];
-    sprintf(xmlsuffix, "_%d.xtable", index);
-    std::string const xmlfile = fs::basename(table_path) + xmlsuffix;
-    doc.save_to_file(xmlfile.c_str());
-}
-
-void export_soa_file(char const* filename)
-{
-    std::vector<soa_record_info> const tables = list_soa_file_tables(filename);
-
-    for(std::vector<soa_record_info>::const_iterator i = tables.begin()
-        ;i != tables.end()
-        ;++i)
-        {
-        export_single_table(filename, i->index, i->name.c_str());
-        }
-}
-
-int main(int argc, char* argv[])
-{
-    try
-        {
-        for(int i = 1; i < argc; i++)
-            {
-            export_soa_file(argv[i]);
-            }
-        return 0;
-        }
-    catch(std::exception const& e)
-        {
-        std::cerr << "Error: " << e.what() << std::endl;
-        return 1;
-        }
-}
-
diff --git a/soa_helpers.hpp b/soa_helpers.hpp
deleted file mode 100644
index 8fd425c..0000000
--- a/soa_helpers.hpp
+++ /dev/null
@@ -1,117 +0,0 @@
-// Auxiliary routines for tables in deprecated SOA format.
-//
-// Copyright (C) 2012, 2013, 2014, 2015, 2016 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 soa_helpers_hpp
-#define soa_helpers_hpp
-
-#include "config.hpp"
-
-#include "actuarial_table.hpp"
-#include "alert.hpp"
-#include "deserialize_cast.hpp"
-#include "miscellany.hpp"
-#include "path_utility.hpp"             // fs::path inserter
-
-#include <boost/cstdint.hpp>
-#include <boost/filesystem/convenience.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/filesystem/path.hpp>
-#include <boost/static_assert.hpp>
-
-#include <climits>                      // CHAR_BIT
-#include <exception>
-#include <string>
-#include <vector>
-
-// SOA actuarial table format helpers.
-
-struct soa_record_info
-{
-    int         index;
-    std::string name;
-};
-
-std::vector<soa_record_info> list_soa_file_tables(char const* filename)
-{
-    std::vector<soa_record_info> v;
-
-    fs::path index_path(filename);
-    index_path = fs::change_extension(index_path, ".ndx");
-    fs::ifstream index_ifs(index_path, ios_in_binary());
-    if(!index_ifs)
-        {
-        fatal_error()
-            << "File '"
-            << index_path
-            << "' is required but could not be found. Try reinstalling."
-            << LMI_FLUSH
-            ;
-        }
-
-    // Index records have fixed length:
-    //   4-byte integer:     table number
-    //   50-byte char array: table name
-    //   4-byte integer:     byte offset into '.dat' file
-    // Table numbers are not necessarily consecutive or sorted.
-
-    // SOA !! Assert endianness too? SOA tables are not portable;
-    // probably they can easily be read only on x86 hardware.
-
-    BOOST_STATIC_ASSERT(8 == CHAR_BIT);
-    BOOST_STATIC_ASSERT(4 == sizeof(int));
-    BOOST_STATIC_ASSERT(2 == sizeof(short int));
-
-    int const index_record_length(58);
-    char index_record[index_record_length] = {0};
-
-    BOOST_STATIC_ASSERT(sizeof(boost::int32_t) <= sizeof(int));
-    while(index_ifs)
-        {
-        index_ifs.read(index_record, index_record_length);
-        if(index_record_length != index_ifs.gcount())
-            {
-            if(!index_ifs)
-                {
-                break;
-                }
-            fatal_error()
-                << "Index file '"
-                << index_path.string()
-                << "': attempted to read "
-                << index_record_length
-                << " bytes, but got "
-                << index_ifs.gcount()
-                << " bytes instead."
-                << LMI_FLUSH
-                ;
-            }
-
-        soa_record_info rec;
-        rec.index = deserialize_cast<boost::int32_t>(index_record);
-        rec.name.assign(index_record + 4);
-        v.push_back(rec);
-        }
-
-    return v;
-}
-
-#endif // soa_helpers_hpp
-
diff --git a/soa_stress_test.cpp b/soa_stress_test.cpp
deleted file mode 100644
index cd14218..0000000
--- a/soa_stress_test.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-// Test SOA tables against xml equivalents.
-//
-// Copyright (C) 2012, 2013, 2014, 2015, 2016 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 "actuarial_table.hpp"
-#include "assert_lmi.hpp"
-#include "materially_equal.hpp"
-#include "soa_helpers.hpp"
-
-#include <cmath>
-#include <iomanip>                      // std::setprecision(), std::setw()
-#include <ios>
-#include <iostream>
-#include <istream>
-#include <ostream>
-
-inline bool almost_equal_doubles(double a, double b)
-{
-    return materially_equal(a, b, 2.0E-15L);
-}
-
-// Functions almost_equal_doubles() and report_vector_difference()
-// here differ gratuitously from function almost_equal_doubles()
-// in 'actuarial_table.cpp'. SOMEDAY !! Rectify this.
-
-inline bool almost_equal_doubles(std::vector<double> const& a, 
std::vector<double> const& b)
-{
-    if(a.size() != b.size())
-        return false;
-
-    size_t const size = a.size();
-    for(size_t i = 0; i < size; i++)
-        {
-        if(!almost_equal_doubles(a[i], b[i]))
-            return false;
-        }
-
-    return true;
-}
-
-void report_vector_difference
-    (int start
-    ,std::vector<double> const& data_xml
-    ,std::vector<double> const& data_soa
-    )
-{
-    std::cerr
-        << "Results differ for "
-        << data_xml.size()
-        << " values starting at "
-        << start
-        << ":"
-        << std::endl
-        ;
-
-    std::cerr
-        << "   \t" << std::setw(25) << "xml"
-        << "   \t" << std::setw(25) << "soa"
-        << std::endl;
-    for(unsigned int i = 0; i < data_xml.size(); i++)
-        {
-        if(!almost_equal_doubles(data_xml[i], data_soa[i]))
-            {
-            std::cerr
-                << std::setw(3) << i
-                << std::setprecision(20) << std::setw(25) << data_xml[i]
-                << std::setprecision(20) << std::setw(25) << data_soa[i]
-                << std::endl
-                ;
-            }
-        }
-    throw std::runtime_error("XML table data are incorrect");
-}
-
-void test_single_table(char const* filename, int index)
-{
-    soa_actuarial_table soa(filename, index);
-    xml_actuarial_table xml(filename, index);
-
-    LMI_ASSERT( soa.table_type() == xml.table_type()         );
-
-    if (xml.table_type() != e_table_duration)
-        {
-        LMI_ASSERT( soa.min_age() == xml.min_age()               );
-        LMI_ASSERT( soa.max_age() == xml.max_age()               );
-        }
-
-    if(xml.table_type() == e_table_select_and_ultimate)
-        {
-        LMI_ASSERT( soa.select_period() == xml.select_period()   );
-        LMI_ASSERT( soa.max_select_age() == xml.max_select_age() );
-        }
-
-    for(int start = xml.min_age(); start < xml.max_age(); start++)
-        {
-        for(int length = 1; length <= xml.max_age() - start; length++)
-            {
-            std::vector<double> result_xml = xml.values(start, length);
-            std::vector<double> result_soa = soa.values(start, length);
-            LMI_ASSERT(result_xml.size() == static_cast<unsigned int>(length));
-            LMI_ASSERT(result_soa.size() == static_cast<unsigned int>(length));
-            if(!almost_equal_doubles(result_xml, result_soa))
-                report_vector_difference(start, result_xml, result_soa);
-            }
-        }
-}
-
-void stress_test(char const* filename)
-{
-    std::vector<soa_record_info> const tables = list_soa_file_tables(filename);
-
-    for(std::vector<soa_record_info>::const_iterator i = tables.begin()
-        ;i != tables.end()
-        ;++i)
-        {
-        try
-            {
-            std::cout << "Testing " << filename << ", " << i->index  << 
std::endl;
-            test_single_table(filename, i->index);
-            }
-        catch(std::exception const& e)
-            {
-            fatal_error()
-                << "In file '"
-                << filename
-                << "', table "
-                << i->index
-                << ":\n"
-                << e.what()
-                << LMI_FLUSH
-                ;
-            }
-        }
-}
-
-int main(int argc, char* argv[])
-{
-    try
-        {
-        for(int i = 1; i < argc; i++)
-            {
-            stress_test(argv[i]);
-            }
-        return 0;
-        }
-    catch(std::exception const& e)
-        {
-        std::cerr << "Error:" << std::endl << e.what() << std::endl;
-        return 1;
-        }
-}
-
diff --git a/test_coding_rules.cpp b/test_coding_rules.cpp
index e109142..c499a59 100644
--- a/test_coding_rules.cpp
+++ b/test_coding_rules.cpp
@@ -603,7 +603,6 @@ void check_defect_markers(file const& f)
             &&  "INELEGANT "   != z[1]
             &&  "INPUT "       != z[1]
             &&  "PORT "        != z[1]
-            &&  "SOA "         != z[1]
             &&  "SOMEDAY "     != z[1]
             &&  "TAXATION "    != z[1]
             &&  "THIRD_PARTY " != z[1]



reply via email to

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