From 269cc496a835a3cbd37c6c758b5c75f27195a610 Mon Sep 17 00:00:00 2001 From: Open Risk Date: Thu, 22 Feb 2024 22:13:31 +0100 Subject: [PATCH] Added lognormal test; Initialize with sample; Improved histogram; Closes #1 --- README.md | 7 +-- src/CMakeLists.txt | 20 +++--- src/conanfile.txt | 6 ++ src/main.cpp | 26 +++++++- src/random_var.cpp | 29 +++++++-- src/random_var.h | 59 +++++++++-------- testing.cpp | 44 ------------- .../test_random_var_bernulli.cpp | 7 ++- .../rnd_statistics/test_random_var_beta.cpp | 7 ++- .../test_random_var_binomial.cpp | 7 ++- .../test_random_var_exponential.cpp | 7 ++- .../test_random_var_lognormal.cpp | 63 +++++++++++++++++++ .../rnd_statistics/test_random_var_normal.cpp | 2 +- .../test_random_var_uniform.cpp | 7 ++- testing/test_histogram.cpp | 2 +- 15 files changed, 195 insertions(+), 98 deletions(-) delete mode 100644 testing.cpp create mode 100644 testing/rnd_statistics/test_random_var_lognormal.cpp diff --git a/README.md b/README.md index b023b18..c8ee9b3 100644 --- a/README.md +++ b/README.md @@ -7,18 +7,17 @@ A C++ library for the calculation of various tail risk measures * Implemented [Risk Measures](RiskMeasures.md) * Mathematical Documentation available [here](https://www.openriskmanual.org/wiki/Category:Tail_Risk) - ## Dependencies -* Eigen (Data container and calculation library) -* Poco (For parsing JSON inputs) +* Eigen (Data container and linear algebra calculation library) +* Poco (For parsing JSON inputs and other utilities) * Stats (A C++ header-only library of statistical distribution functions.) ## Example The data directory contains sample datafiles with various sampled distributions ```c++ - // Read in some data for a type 0 representation (discrete distribution) +// Read in some data for a type 0 representation (discrete distribution) int LossGrid = 1000; int DataType = 0; RandomVar L(LossGrid, DataType); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ab5cb90..18aec6a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## @@ -36,7 +36,7 @@ include_directories(..) include_directories(.) # tailRisk version -set(VERSION 0.1.0) +set(VERSION 0.2.0) set(SOURCE_FILES random_var.cpp @@ -49,10 +49,10 @@ set(TEST_FILES ../testing/rnd_statistics/test_random_var_normal.cpp ../testing/rnd_statistics/test_random_var_uniform.cpp ../testing/rnd_statistics/test_random_var_exponential.cpp - ../testing/test_histogram.cpp - ../testing.cpp) + ../testing/rnd_statistics/test_random_var_lognormal.cpp + ../testing/test_histogram.cpp) -find_package(Poco REQUIRED COMPONENTS Foundation Net NetSSL Util Data DataSQLite) +find_package(Poco REQUIRED COMPONENTS Foundation Net Util Data) find_package(Catch2 REQUIRED) find_package(Eigen3 REQUIRED) find_package(statslib REQUIRED) @@ -65,8 +65,9 @@ target_include_directories(tailRisk PRIVATE ${statslib_INCLUDE_DIRS}) target_include_directories(tailRisk PRIVATE ${gcem_INCLUDE_DIRS}) target_link_libraries(tailRisk Poco::Foundation + Poco::Data + Poco::JSON Poco::Net - Poco::NetSSL Poco::Util) # CATCH2 TESTING @@ -81,11 +82,10 @@ target_include_directories(unit_testing PRIVATE ${Catch2_INCLUDE_DIRS}) target_include_directories(unit_testing PRIVATE ${Eigen3_INCLUDE_DIRS}) target_include_directories(unit_testing PRIVATE ${statslib_INCLUDE_DIRS}) target_include_directories(unit_testing PRIVATE ${gcem_INCLUDE_DIRS}) -target_link_libraries(unit_testing +target_link_libraries(unit_testing Catch2::Catch2WithMain Poco::Data - Poco::DataSQLite Poco::Foundation Poco::Net - Poco::NetSSL - Catch2::Catch2WithMain) + Poco::Util + Poco::JSON) diff --git a/src/conanfile.txt b/src/conanfile.txt index e67882e..a48ec1d 100644 --- a/src/conanfile.txt +++ b/src/conanfile.txt @@ -5,6 +5,12 @@ statslib/3.2.0 gcem/1.16.0 catch2/3.4.0 +[options] +poco*:enable_data_odbc=False +poco*:enable_data_mysql=False +poco*:enable_mongodb=False +poco*:enable_redis=False + [generators] CMakeDeps CMakeToolchain \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0fc4b66..cd3ef39 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## @@ -30,11 +30,23 @@ int main(int argc, char *argv[]) { + // Example 1 + int Grid = 1; + int DataType = 0; + RandomVar D(Grid, DataType); + std::string filename = "../data/example1.json"; + D.ReadFromJSON(filename); + D.Print(); + D.Cumulative(); + D.Probability(); + + // Example 5 // Reading in some data for a type 0 representation (discrete distribution) int LossGrid = 1000; - int DataType = 0; + DataType = 0; RandomVar L(LossGrid, DataType); - std::string filename = "../../data/example5.json"; + // ATTN: Make sure this points to the correct path versus your executable! + filename = "../data/example5.json"; L.ReadFromJSON(filename); L.Print(); @@ -54,5 +66,13 @@ int main(int argc, char *argv[]) { std::cout << "Exceedance Probability: " << L.ExceedanceProbability(threshold) << std::endl; std::cout << "Mean Excess: " << L.MeanExcess(threshold ) << std::endl; + // Working with type 1 representations + int SampleSize = 10000; + DataType = 1; + RandomVar myR(SampleSize, DataType); + myR.Seed(); + RandomVar H = myR.Histogram(10); + H.Print(); + return 0; } \ No newline at end of file diff --git a/src/random_var.cpp b/src/random_var.cpp index 0f900c1..f602cbc 100644 --- a/src/random_var.cpp +++ b/src/random_var.cpp @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## @@ -30,6 +30,7 @@ #include +#include "stats.hpp" #include "random_var.h" using namespace Poco; @@ -57,7 +58,7 @@ RandomVar &RandomVar::operator=(const RandomVar &R) { }; /** - * Sort the sampling data + * Sort the sampling data if Type 1, else do nothing */ void RandomVar::Sort() { if (m_type == 1) { @@ -74,21 +75,27 @@ void RandomVar::Sort() { * Bins are assumed equal and represented by their mid-point values */ RandomVar RandomVar::Histogram(int Bins) { - RandomVar H(Bins+1,0); + RandomVar H(Bins,0); if (m_type == 1) { std::sort(m_S.begin(), m_S.end()); double min_value = m_S[0]; double max_value = m_S[m_S.size()-1]; double bin_width = (max_value - min_value)/ (double) Bins; double sample_p = 1.0 / m_size; - for (int i = 0; i < Bins + 1; i++) { - H.setX(i, min_value + bin_width / 2.0 + (double) (i) * bin_width); + for (int i = 0; i < Bins; i++) { + double x = min_value + bin_width / 2.0 + (double) (i) * bin_width; + H.setX(i, x); H.setP(i, 0.0); + H.setC(i, 0.0); } for (int j = 0; j < m_size; j++) { int observation_bin = (int) ( (m_S[j] - min_value) / bin_width ); + if (observation_bin > Bins - 1) { + observation_bin = Bins - 1; + } H.addP(observation_bin, sample_p); } + H.Cumulative(); } return H; } @@ -361,3 +368,15 @@ void RandomVar::ReadFromJSON(std::string &filename) { this->setC(i, object->getValue("cumulative")); } } + +/** + * Seed with a sampled distribution + */ +void RandomVar::Seed() { + if (m_type == 1) { + stats::rand_engine_t engine(12376); + for (int i = 0; i < this->m_size; i++) { + this->setS(i, stats::runif(0.0, 1.0, engine)); + } + } +} diff --git a/src/random_var.h b/src/random_var.h index a1b3547..a5151ce 100644 --- a/src/random_var.h +++ b/src/random_var.h @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-20223 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## @@ -35,9 +35,9 @@ class RandomVar { public: - // constructor with size and empirical distribution type - // Type 0 -> histogram storage - // Type 1 -> sample storage + // Constructor with size and empirical distribution type + // Type 0 -> Histogram type Storage + // Type 1 -> Sample type Storage RandomVar(size_t S, int type) { if (type == 0) { @@ -51,12 +51,11 @@ class RandomVar { m_S.resize(S); m_size = S; } else { - std::cout << "Error in random variable representation type" << std::endl; + std::cout << "Error in Random Variable representation type: Must be 0 or 1" << std::endl; } } // constructor directly from existing data - // TODO generalize data type to accommodate different accuracy requirements RandomVar(Eigen::ArrayXd x, Eigen::ArrayXd p, const int size) { m_type = 0; @@ -86,6 +85,8 @@ class RandomVar { return m_type; }; + // Getters and Setters + [[nodiscard]] double getP(int index) const { return m_P[index]; }; @@ -102,6 +103,30 @@ class RandomVar { return m_S[index]; }; + void setP(int index, double arg) { + m_P[index] = arg; + }; + + void setC(int index, double arg) { + m_C[index] = arg; + }; + + void setX(int index, double arg) { + m_X[index] = arg; + }; + + void setS(int index, double arg) { + m_S[index] = arg; + }; + + // Increment probability mass + + void addP(int index, double arg) { + m_P[index] += arg; + }; + + // Statistical Measures + [[nodiscard]] double Average(); [[nodiscard]] double Mean(); @@ -130,25 +155,7 @@ class RandomVar { [[nodiscard]] int Quantile_Index(double alpha); - void setP(int index, double arg) { - m_P[index] = arg; - }; - - void setC(int index, double arg) { - m_C[index] = arg; - }; - - void addP(int index, double arg) { - m_P[index] += arg; - }; - - void setX(int index, double arg) { - m_X[index] = arg; - }; - - void setS(int index, double arg) { - m_S[index] = arg; - }; + // Various Operations void Sort(); @@ -162,6 +169,8 @@ class RandomVar { void Print(); + void Seed(); + private: // 0 Type: exact representation (discrete probabilities view) // 1 Type: sampling representation (distribution sampling view) diff --git a/testing.cpp b/testing.cpp deleted file mode 100644 index 59e489f..0000000 --- a/testing.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/*################################################################################ - ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) - ## - ## This file is part of the tailRisk C++ library. - ## - ## Licensed under the Apache License, Version 2.0 (the "License"); - ## you may not use this file except in compliance with the License. - ## You may obtain a copy of the License at - ## - ## http://www.apache.org/licenses/LICENSE-2.0 - ## - ## Unless required by applicable law or agreed to in writing, software - ## distributed under the License is distributed on an "AS IS" BASIS, - ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ## See the License for the specific language governing permissions and - ## limitations under the License. - ## - ################################################################################*/ - - -/** - * File: testing.cpp - * Date: Apr 16 2021 - */ - -#include "stats.hpp" -#include "src/random_var.h" - -int main(int argc, char *argv[]) { - - int SampleSize = 100; - int DataType = 1; - RandomVar myR(SampleSize, DataType); - - std::cout << "Testing" << std::endl; - for (int i = 0; i < myR.size(); i++) { - double rval = stats::rt(30); - myR.setS(i, rval); - } - - myR.Print(); - -} diff --git a/testing/rnd_statistics/test_random_var_bernulli.cpp b/testing/rnd_statistics/test_random_var_bernulli.cpp index 03ad7e6..3f5c7d0 100644 --- a/testing/rnd_statistics/test_random_var_bernulli.cpp +++ b/testing/rnd_statistics/test_random_var_bernulli.cpp @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## @@ -41,6 +41,11 @@ double bernulli_var(size_t number, double param) { return myR.Variance(); } +/* + * Numbers based on the Stats test + * https://github.com/kthohr/stats/blob/master/tests/rand/rbern.cpp +*/ + double prob_par = 0.75; double m_bernulli_mean = prob_par; double m_bernulli_var = prob_par * (1.0 - prob_par); diff --git a/testing/rnd_statistics/test_random_var_beta.cpp b/testing/rnd_statistics/test_random_var_beta.cpp index 6a38ee3..7db4a02 100644 --- a/testing/rnd_statistics/test_random_var_beta.cpp +++ b/testing/rnd_statistics/test_random_var_beta.cpp @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## @@ -50,6 +50,11 @@ double beta_quantile(size_t number, double param1, double param2, double param3) return myR.Quantile(param3); } +/* + * Numbers based on the Stats test + * https://github.com/kthohr/stats/blob/master/tests/rand/rbeta.cpp +*/ + double a_par = 3.0; double b_par = 2.0; diff --git a/testing/rnd_statistics/test_random_var_binomial.cpp b/testing/rnd_statistics/test_random_var_binomial.cpp index c24d47c..be939f3 100644 --- a/testing/rnd_statistics/test_random_var_binomial.cpp +++ b/testing/rnd_statistics/test_random_var_binomial.cpp @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## @@ -41,6 +41,11 @@ double binomial_var(size_t number, int param1, double param2) { return myR.Variance(); } +/* + * Numbers based on the Stats test + * https://github.com/kthohr/stats/blob/master/tests/rand/rbinom.cpp +*/ + int n_trials = 10; double prob_par1 = 0.75; diff --git a/testing/rnd_statistics/test_random_var_exponential.cpp b/testing/rnd_statistics/test_random_var_exponential.cpp index f9a1146..2749eb2 100644 --- a/testing/rnd_statistics/test_random_var_exponential.cpp +++ b/testing/rnd_statistics/test_random_var_exponential.cpp @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## @@ -50,6 +50,11 @@ double exponential_quantile(size_t number, double param1, double param3) { return myR.Quantile(param3); } +/* + * Numbers based on the Stats test + * https://github.com/kthohr/stats/blob/master/tests/rand/rexp.cpp +*/ + double rate_par = 0.8; double a_par1 = rate_par; double m_exponential_mean = 1.0 / rate_par; diff --git a/testing/rnd_statistics/test_random_var_lognormal.cpp b/testing/rnd_statistics/test_random_var_lognormal.cpp new file mode 100644 index 0000000..ce1a1fd --- /dev/null +++ b/testing/rnd_statistics/test_random_var_lognormal.cpp @@ -0,0 +1,63 @@ +/*################################################################################ + ## + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) + ## + ## This file is part of the tailRisk C++ library. + ## + ## Licensed under the Apache License, Version 2.0 (the "License"); + ## you may not use this file except in compliance with the License. + ## You may obtain a copy of the License at + ## + ## http://www.apache.org/licenses/LICENSE-2.0 + ## + ## Unless required by applicable law or agreed to in writing, software + ## distributed under the License is distributed on an "AS IS" BASIS, + ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ## See the License for the specific language governing permissions and + ## limitations under the License. + ## + ################################################################################*/ + +#include +#include +#include "stats.hpp" +#include "../../src/random_var.h" + +double lognormal_mean(size_t number, double param1, double param2) { + RandomVar myR(number, 1); + stats::rand_engine_t engine(123776); + for (int i = 0; i < number; i++) { + myR.setS(i, stats::rlnorm(param1, param2, engine)); + } + return myR.Mean(); +} + +double lognormal_var(size_t number, double param1, double param2) { + RandomVar myR(number, 1); + stats::rand_engine_t engine(123776); + for (int i = 0; i < number; i++) { + myR.setS(i, stats::rlnorm(param1, param2, engine)); + } + return myR.Variance(); +} + +/* + * Numbers based on the Stats test + * https://github.com/kthohr/stats/blob/master/tests/rand/rlnorm.cpp +*/ + +double mu2 = 0.1; +double sigma2 = 1; +double a_par4 = mu2; +double b_par4 = sigma2; + +double m_lnorm_mean = std::exp(mu2 + sigma2 * sigma2 / 2.0); +double m_lnorm_var = (std::exp(sigma2 * sigma2) - 1.0) * std::exp(2 * mu2 + sigma2 * sigma2); + +TEST_CASE("LogNormal", "[statistics]") { + SECTION("Mean") { + REQUIRE_THAT(lognormal_mean(100000, a_par4, b_par4), Catch::Matchers::WithinAbs(m_lnorm_mean, 0.01)); + }SECTION("Variance") { + REQUIRE_THAT(lognormal_var(100000, a_par4, b_par4), Catch::Matchers::WithinAbs(m_lnorm_var, 0.1)); + } +} \ No newline at end of file diff --git a/testing/rnd_statistics/test_random_var_normal.cpp b/testing/rnd_statistics/test_random_var_normal.cpp index 017d695..ea52aef 100644 --- a/testing/rnd_statistics/test_random_var_normal.cpp +++ b/testing/rnd_statistics/test_random_var_normal.cpp @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## diff --git a/testing/rnd_statistics/test_random_var_uniform.cpp b/testing/rnd_statistics/test_random_var_uniform.cpp index 7f7bc30..d1dda82 100644 --- a/testing/rnd_statistics/test_random_var_uniform.cpp +++ b/testing/rnd_statistics/test_random_var_uniform.cpp @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ## @@ -53,6 +53,11 @@ double uniform_quantile(size_t number, double param1, double param2, double para //double a_par3 = -1; //double b_par3 = 3; +/* + * Numbers based on the Stats test + * https://github.com/kthohr/stats/blob/master/tests/rand/runif.cpp +*/ + double a_par3 = 0; double b_par3 = 1; diff --git a/testing/test_histogram.cpp b/testing/test_histogram.cpp index ab3fab7..efd7d81 100644 --- a/testing/test_histogram.cpp +++ b/testing/test_histogram.cpp @@ -1,6 +1,6 @@ /*################################################################################ ## - ## Copyright (C) 2020-2023 Open Risk (www.openriskmanagement.com) + ## Copyright (C) 2020-2024 Open Risk (www.openriskmanagement.com) ## ## This file is part of the tailRisk C++ library. ##