From 8de7352d3ff2ce8aadd2b73155e0a6e9613f8f81 Mon Sep 17 00:00:00 2001
From: Michal Kravcenko <michal.kravcenko@vsb.cz>
Date: Wed, 5 Sep 2018 16:59:17 +0200
Subject: [PATCH] ADD: added a new example for harmonic oscilator problem FIX:
 fixed an issue with ExprtkWrapper being incorrectly destryed before being
 used in the NetworkSum class

---
 src/General/ExprtkWrapper.cpp                |  35 +++--
 src/General/ExprtkWrapper.h                  |   8 +-
 src/Network/NeuralNetworkSum.cpp             |  16 +-
 src/Network/NeuralNetworkSum.h               |   2 +-
 src/examples/net_test_harmonic_oscilator.cpp | 156 +++++++++++++++++++
 5 files changed, 202 insertions(+), 15 deletions(-)

diff --git a/src/General/ExprtkWrapper.cpp b/src/General/ExprtkWrapper.cpp
index 9ec67262..03738f64 100644
--- a/src/General/ExprtkWrapper.cpp
+++ b/src/General/ExprtkWrapper.cpp
@@ -10,26 +10,41 @@
 
 ExprtkWrapper::ExprtkWrapper( std::string expression_string ) {
 
+    this->expression_str = expression_string;
+
     this->symbol_table = new symbol_table_t( );
 
-    symbol_table->add_variable("x", this->t);
-    symbol_table->add_variable("y", this->y);
-    symbol_table->add_variable("z", this->z);
-    symbol_table->add_variable("t", this->t);
+    this->symbol_table->add_variable("x", this->x);
+    this->symbol_table->add_variable("y", this->y);
+    this->symbol_table->add_variable("z", this->z);
+    this->symbol_table->add_variable("t", this->t);
+    this->symbol_table->add_variable("f", this->z);
 
     this->expression = new expression_t( );
     this->expression->register_symbol_table( *this->symbol_table );
 
     this->parser = new parser_t( );
-    parser->compile(expression_string, *this->expression );
+    parser->compile(this->expression_str, *this->expression );
 }
 
-ExprtkWrapper::ExprtkWrapper( ) {
 
+ExprtkWrapper::~ExprtkWrapper() {
 
-}
+    if( this->expression ){
+        delete this->expression;
+        this->expression = nullptr;
+    }
+
+    if( this->symbol_table ){
+        delete this->symbol_table;
+        this->symbol_table = nullptr;
+    }
+
+    if( this->parser ){
+        delete this->parser;
+        this->parser = nullptr;
+    }
 
-ExprtkWrapper::~ExprtkWrapper() {
 }
 
 double ExprtkWrapper::eval(double x1, double x2, double x3, double x4) {
@@ -58,5 +73,7 @@ double ExprtkWrapper::eval(std::vector<double> &p) {
         this->t = p[3];
     }
 
-    return this->expression->value();
+    double result = this->expression->value();
+
+    return result;
 }
\ No newline at end of file
diff --git a/src/General/ExprtkWrapper.h b/src/General/ExprtkWrapper.h
index 2d38fa03..df58142e 100644
--- a/src/General/ExprtkWrapper.h
+++ b/src/General/ExprtkWrapper.h
@@ -74,7 +74,13 @@ private:
     /*
      * variables
      */
-    double x, y, z, t;
+    double x, y, z, t, f;
+
+    /**
+     * referential expression string
+     */
+
+    std::string expression_str;
 
 };
 #endif //LIB4NEURO_EXPRTKWRAPPER_H
diff --git a/src/Network/NeuralNetworkSum.cpp b/src/Network/NeuralNetworkSum.cpp
index 8aee1806..2b665fe7 100644
--- a/src/Network/NeuralNetworkSum.cpp
+++ b/src/Network/NeuralNetworkSum.cpp
@@ -15,9 +15,16 @@ NeuralNetworkSum::NeuralNetworkSum(){
 NeuralNetworkSum::~NeuralNetworkSum() {
     if( this->summand ){
         delete this->summand;
+        this->summand = nullptr;
     }
     if( this->summand_coefficient ){
+
+        for(auto el: *this->summand_coefficient){
+            delete el;
+        }
+
         delete this->summand_coefficient;
+        this->summand_coefficient = nullptr;
     }
 }
 
@@ -28,9 +35,9 @@ void NeuralNetworkSum::add_network( NeuralNetwork *net, std::string expression_s
     this->summand->push_back( net );
 
     if(!this->summand_coefficient){
-        this->summand_coefficient = new std::vector<ExprtkWrapper>(0);
+        this->summand_coefficient = new std::vector<ExprtkWrapper*>(0);
     }
-    this->summand_coefficient->push_back( ExprtkWrapper( expression_string ) );
+    this->summand_coefficient->push_back( new ExprtkWrapper( expression_string ) );
 }
 
 void NeuralNetworkSum::eval_single(std::vector<double> &input, std::vector<double> &output, std::vector<double> *custom_weights_and_biases) {
@@ -45,7 +52,7 @@ void NeuralNetworkSum::eval_single(std::vector<double> &input, std::vector<doubl
         if( SUM ){
             this->summand->at(ni)->eval_single(input, mem_output, custom_weights_and_biases);
 
-            double alpha = this->summand_coefficient->at(ni).eval(input);
+            double alpha = this->summand_coefficient->at(ni)->eval(input);
 
             for(size_t j = 0; j < output.size(); ++j){
                 output[j] += mem_output[j] * alpha;
@@ -53,7 +60,8 @@ void NeuralNetworkSum::eval_single(std::vector<double> &input, std::vector<doubl
         }
         else{
             //TODO assume the result can be a vector of doubles
-            double alpha = this->summand_coefficient->at(ni).eval(input);
+            double alpha = this->summand_coefficient->at(ni)->eval(input);
+
             for(size_t j = 0; j < output.size(); ++j){
                 output[j] += alpha;
             }
diff --git a/src/Network/NeuralNetworkSum.h b/src/Network/NeuralNetworkSum.h
index 3c366430..30f272b4 100644
--- a/src/Network/NeuralNetworkSum.h
+++ b/src/Network/NeuralNetworkSum.h
@@ -19,7 +19,7 @@ private:
     friend class boost::serialization::access;
 
     std::vector<NeuralNetwork*> * summand;
-    std::vector<ExprtkWrapper> * summand_coefficient;
+    std::vector<ExprtkWrapper*> * summand_coefficient;
 
     template <class Archive>
     void serialize(Archive & ar, const unsigned int version) {
diff --git a/src/examples/net_test_harmonic_oscilator.cpp b/src/examples/net_test_harmonic_oscilator.cpp
index 69290d67..17fddd01 100644
--- a/src/examples/net_test_harmonic_oscilator.cpp
+++ b/src/examples/net_test_harmonic_oscilator.cpp
@@ -14,7 +14,163 @@
 #include "../../include/4neuro.h"
 #include "../Solvers/DESolver.h"
 
+void test_harmonic_oscilator_fixed_E(double EE, double accuracy, size_t n_inner_neurons, size_t train_size, double ds, double de, size_t n_test_points, double ts, double te, size_t max_iters, size_t n_particles){
+    std::cout << "Finding a solution via the Particle Swarm Optimization" << std::endl;
+    std::cout << "********************************************************************************************************************************************" <<std::endl;
+
+    /* SOLVER SETUP */
+    size_t n_inputs = 1;
+    size_t n_equations = 1;
+    DESolver solver( n_equations, n_inputs, n_inner_neurons );
+
+    /* SETUP OF THE EQUATIONS */
+    MultiIndex alpha_0( n_inputs );
+    MultiIndex alpha_2( n_inputs );
+    alpha_2.set_partial_derivative(0, 2);
+
+    /* the governing differential equation */
+    char buff[255];
+    std::sprintf(buff, "%f", -EE);
+    std::string eigenvalue(buff);
+    solver.add_to_differential_equation( 0, alpha_2, "-1.0" );
+    solver.add_to_differential_equation( 0, alpha_0, "x^2" );
+    solver.add_to_differential_equation( 0, alpha_0, eigenvalue );
+
+    /* SETUP OF THE TRAINING DATA */
+    std::vector<double> inp, out;
+
+    double d1_s = ds, d1_e = de, frac;
+
+    /* TRAIN DATA FOR THE GOVERNING DE */
+    std::vector<std::pair<std::vector<double>, std::vector<double>>> data_vec_g;
+
+
+    /* ISOTROPIC TRAIN SET */
+    frac = (d1_e - d1_s) / (train_size - 1);
+    for(unsigned int i = 0; i < train_size; ++i){
+        inp = {frac * i + d1_s};
+        out = {0.0};
+        data_vec_g.emplace_back(std::make_pair(inp, out));
+    }
+//    inp = {0.0};
+//    out = {1.0};
+//    data_vec_g.emplace_back(std::make_pair(inp, out));
+
+    DataSet ds_00(&data_vec_g);
+
+    /* Placing the conditions into the solver */
+    solver.set_error_function( 0, ErrorFunctionType::ErrorFuncMSE, &ds_00 );
+
+    /* PARTICLE SWARM TRAINING METHOD SETUP */
+    size_t total_dim = (2 + n_inputs) * n_inner_neurons;
+
+    std::vector<double> params(total_dim), params_analytical(total_dim);
+    std::random_device seeder;
+    std::mt19937 gen(seeder());
+    std::uniform_real_distribution<double> dist(-10.0, 10.0);
+
+    std::vector<double> input(1);
+    //must encapsulate each of the partial error functions
+    std::vector<double> domain_bounds(2 * total_dim);
+    for(unsigned int i = 0; i < total_dim; ++i){
+        domain_bounds[2 * i] = -10.0;
+        domain_bounds[2 * i + 1] = 10.0;
+    }
+
+
+    double c1 = 1.7, c2 = 1.7, w = 0.7;
+    /* if the maximal velocity from the previous step is less than 'gamma' times the current maximal velocity, then one
+     * terminating criterion is met */
+    double gamma = 0.5;
+
+    /* if 'delta' times 'n' particles are in the centroid neighborhood given by the radius 'epsilon', then the second
+     * terminating criterion is met ('n' is the total number of particles) */
+    double epsilon = 0.02;
+    double delta = 0.9;
+    solver.solve_via_particle_swarm( &domain_bounds, c1, c2, w, n_particles, max_iters, gamma, epsilon, delta );
+
+    NeuralNetwork *solution = solver.get_solution( alpha_0 );
+    std::vector<double> parameters(total_dim);//w1, a1, b1, w2, a2, b2, ... , wm, am, bm
+    std::vector<double> *weight_params = solution->get_parameter_ptr_weights();
+    std::vector<double> *biases_params = solution->get_parameter_ptr_biases();
+    for(size_t i = 0; i < n_inner_neurons; ++i){
+        parameters[3 * i] = weight_params->at(i);
+        parameters[3 * i + 1] = weight_params->at(i + n_inner_neurons);
+        parameters[3 * i + 2] = biases_params->at(i);
+
+        printf("Path %3d. w%d = %15.8f, b%d = %15.8f, a%d = %15.8f\n", (int)(i + 1), (int)(i + 1), parameters[3 * i], (int)(i + 1), parameters[3 * i + 2], (int)(i + 1), parameters[3 * i + 1]);
+    }
+
+    /* ISOTROPIC TEST SET FOR BOUNDARY CONDITIONS */
+    /* first boundary condition & its error */
+    std::ofstream ofs("data_1d_osc.txt", std::ofstream::out);
+    printf("Exporting files 'data_1d_osc.txt': %7.3f%%\r", 0.0);
+    frac = (te - ts) / (n_test_points - 1);
+
+    for(size_t i = 0; i < n_test_points; ++i){
+        double x = frac * i + ts;
+
+        inp[0] = x;
+        solution->eval_single(inp, out);
+        ofs << i + 1 << " " << x << " " << out[0] << " " << std::endl;
+
+        printf("Exporting files 'data_1d_osc.txt': %7.3f%%\r", (100.0 * i) / (n_test_points - 1));
+        std::cout.flush();
+    }
+    printf("Exporting files 'data_1d_osc.txt': %7.3f%%\n", 100.0);
+    std::cout.flush();
+    ofs.close();
+
+    inp[0] = -1.0;
+    solution->eval_single(inp, out);
+    printf("y(-1) = %f\n", out[0]);
+    inp[0] = 0.0;
+    solution->eval_single(inp, out);
+    printf("y( 0) = %f\n", out[0]);
+    inp[0] = 1.0;
+    solution->eval_single(inp, out);
+    printf("y( 1) = %f\n", out[0]);
+    std::cout << "********************************************************************************************************************************************" <<std::endl;
+}
+
 int main() {
+    std::cout << "Running lib4neuro harmonic Oscilator example   1" << std::endl;
+    std::cout << "********************************************************************************************************************************************" <<std::endl;
+    std::cout << "          Governing equation: -y''(x) + x^2 * y(x) = E * y(x)" << std::endl;
+    std::cout << "********************************************************************************************************************************************" <<std::endl;
+    std::cout << "Expressing solution as y(x) = sum over [a_i / (1 + exp(bi - wxi*x ))], i in [1, n], where n is the number of hidden neurons" <<std::endl;
+    std::cout << "********************************************************************************************************************************************" <<std::endl;
+
+    double EE = -1.0;
+    unsigned int n_inner_neurons = 2;
+    unsigned int train_size = 10;
+    double accuracy = 1e-3;
+    double ds = -5.0;
+    double de = 5.0;
+
+    unsigned int test_size = 300;
+    double ts = -6.0;
+    double te = 6.0;
+
+    size_t particle_swarm_max_iters = 1000;
+    size_t n_particles = 100;
+    test_harmonic_oscilator_fixed_E(EE, accuracy, n_inner_neurons, train_size, ds, de, test_size, ts, te, particle_swarm_max_iters, n_particles);
 
+//    std::string expression_string = "-x";
+//    std::string expression_string_1 = "1.0";
+//    ExprtkWrapper f(expression_string);
+//    ExprtkWrapper f1(expression_string_1);
+//
+//
+//    f1.eval();
+//
+//    std::vector<double> inp(1);
+//
+//    inp = {150};
+//    double result = f.eval(inp);
+//
+//    f1.eval();
+//    inp = {15};
+//    result = f.eval(inp);
     return 0;
 }
\ No newline at end of file
-- 
GitLab