diff --git a/src/ErrorFunction/ErrorFunctions.cpp b/src/ErrorFunction/ErrorFunctions.cpp
index 5169a76191f99c399c209bcce25c91d8dfcf785b..f785a08651211e07fdb69c6a9b502a70640bfa27 100644
--- a/src/ErrorFunction/ErrorFunctions.cpp
+++ b/src/ErrorFunction/ErrorFunctions.cpp
@@ -151,41 +151,62 @@ namespace lib4neuro {
             outputs.at(i) = output;
         }
 
-        bool denormalize_output = false;
-        if (denormalize_data && data_set->is_normalized()) {
-            data_set->de_normalize();
-            denormalize_output = true;
-        }
+        double denormalized_output;
+        double denormalized_real_input;
+        double denormalized_real_output;
+
+//        bool denormalize_output = false;
+//        if (denormalize_data) {
+//            if(data_set->is_normalized()) {
+//                data_set->de_normalize();
+//            }
+//            denormalize_output = true;
+//        }
 
         for (auto i = 0; i < data->size(); i++) {
 
             /* Compute difference for every element of the output vector */
 #ifdef L4N_DEBUG
             std::stringstream ss_input;
-            for (auto j = 0; j < dim_in - 1; j++) {
-                ss_input << data->at(i).first.at(j) << ",";
+            std::string separator = "";
+            for (auto j = 0; j < dim_in; j++) {
+                if(denormalize_data) {
+                    denormalized_real_input = data_set->get_normalization_strategy()->de_normalize(data->at(i).first.at(j));
+                } else {
+                    denormalized_real_input = data->at(i).first.at(j);
+                }
+                ss_input << separator << denormalized_real_input;
+                separator = ",";
+            }
+            if(denormalize_data) {
+                denormalized_real_input = data_set->get_normalization_strategy()->de_normalize(data->at(i).first.back());
+            } else {
+                denormalized_real_input = data->at(i).first.back();
             }
-            ss_input << data->at(i).first.back();
 
             std::stringstream ss_real_output;
             std::stringstream ss_predicted_output;
 #endif
-            double denormalized_output;
+
             double loc_error = 0;
             output_norm = 0;
+            separator = "";
             for (size_t j = 0; j < dim_out; ++j) {
-                if (denormalize_output) {
+                if (denormalize_data) {
+                    denormalized_real_output = data_set->get_normalization_strategy()->de_normalize(data->at(i).second.at(j));
                     denormalized_output = data_set->get_normalization_strategy()->de_normalize(outputs.at(i).at(j));
                 } else {
+                    denormalized_real_output = data->at(i).second.at(j);
                     denormalized_output = outputs.at(i).at(j);
                 }
 
 #ifdef L4N_DEBUG
-                ss_real_output << data->at(i).second.at(j);
-                ss_predicted_output << denormalized_output;
+                ss_real_output << separator << denormalized_real_output;
+                ss_predicted_output << separator << denormalized_output;
+                separator = ",";
 #endif
 
-                val = denormalized_output - data->at(i).second.at(j);
+                val = denormalized_output - denormalized_real_output;
                 loc_error += val * val;
                 error += loc_error;
 
diff --git a/src/LearningMethods/ParticleSwarm.cpp b/src/LearningMethods/ParticleSwarm.cpp
index e6c21ced612026fbb0a024206bbf9dcd19bbb84d..2574935ea4b1e2849abdf3966bdc95bebc0b66a3 100644
--- a/src/LearningMethods/ParticleSwarm.cpp
+++ b/src/LearningMethods/ParticleSwarm.cpp
@@ -209,30 +209,12 @@ namespace lib4neuro {
                     "Parameters 'gamma', 'epsilon' and 'delta' must be greater than or equal to zero!");
         }
 
-        this->c1 = c1;
-
-        this->c2 = c2;
-
-        this->c3 = (c1 + c2) / 2.0;
-
-        this->w = w;
-
         this->gamma = gamma;
-
         this->epsilon = epsilon;
-
         this->delta = delta;
+        this->pst = PARTICLE_SWARM_TYPE::GENERAL;
 
-        this->n_particles = n_particles;
-
-        this->iter_max = iter_max;
-
-        this->particle_swarm = new std::vector<Particle *>(this->n_particles);
-
-        this->domain_bounds = domain_bounds;
-
-        std::fill(this->particle_swarm->begin(), this->particle_swarm->end(), nullptr);
-
+        this->init_constructor(domain_bounds, c1, c2, w, n_particles, iter_max);
     }
 
     ParticleSwarm::~ParticleSwarm() {
@@ -304,6 +286,7 @@ namespace lib4neuro {
         double max_vel_step = 0;
         double prev_max_vel_step;
         double euclidean_dist;
+        double current_err = -1;
 
         this->determine_optimal_coordinate_and_value(*this->p_min_glob, optimal_value);
 //    for(unsigned int i = 0; i < this->n_particles; ++i){
@@ -385,23 +368,41 @@ namespace lib4neuro {
 //            }
 //        }
 
+            current_err = ef.eval(this->p_min_glob);
+
             COUT_DEBUG(std::string("Iteration: ") << (unsigned int)(outer_it)
-                                                  << ". Total error: " << optimal_value
-                                                  << ".\r" );
+                                                  << ". Total error: " << current_err
+                                                  << ". Objective function value: " << optimal_value
+                                                  << ".\r");
+
+            if(this->err_thresh) {
 
-            /* Check if the particles are near to each other AND the maximal velocity is less than 'gamma' */
-            if (cluster.size() >= this->delta * this->n_particles && prev_max_vel_step <= this->gamma * max_vel_step) {
-                break;
+                /* If the error threshold is given, then check the current error */
+                if(current_err <= this->err_thresh) {
+                    break;
+                }
+            } else {
+
+                /* Check if the particles are near to each other AND the maximal velocity is less than 'gamma' */
+                if (cluster.size() >= this->delta * this->n_particles &&
+                    prev_max_vel_step <= this->gamma * max_vel_step) {
+                    break;
+                }
             }
 
             outer_it++;
+
+            //TODO parameter for inertia weight decrease?
 //        this->w *= 0.99;
+
         }
         COUT_DEBUG(std::string("Iteration: ") << (unsigned int)(outer_it)
-                                              << ". Total error: " << optimal_value
-                                              << ".\n" );
+                                              << ". Total error: " << current_err
+                                              << ". Objective function value: " << optimal_value
+                                              << "." << std::endl );
 
         this->determine_optimal_coordinate_and_value(*this->p_min_glob, optimal_value);
+        //TODO rewrite following output using COUT_INFO
         if (outer_it < this->iter_max) {
             /* Convergence reached */
             printf("\nFound optimum in %d iterations. Objective function value: %10.8f\n", (int) outer_it,
@@ -418,11 +419,30 @@ namespace lib4neuro {
 
         ef.eval( this->get_parameters() );
 
-        ef.eval( this->get_parameters() );
+//        ef.eval( this->get_parameters() );
 
         delete centroid;
     }
 
+    ParticleSwarm::ParticleSwarm(std::vector<double>* domain_bounds,
+                                 double err_thresh,
+                                 PARTICLE_SWARM_TYPE pst,
+                                 double c1,
+                                 double c2,
+                                 double w,
+                                 size_t n_particles,
+                                 size_t iter_max) {
+
+        if(err_thresh <= 0 ) {
+            THROW_INVALID_ARGUMENT_ERROR("Error threshold has to be greater then 0!");
+        }
+
+        this->err_thresh = err_thresh;
+        this->pst = pst;
+
+        this->init_constructor(domain_bounds, c1, c2, w, n_particles, iter_max);
+    }
+
     Particle *ParticleSwarm::determine_optimal_coordinate_and_value(std::vector<double> &coord, double &val) {
 
         Particle *p;
@@ -478,4 +498,21 @@ namespace lib4neuro {
         return this->p_min_glob;
     }
 
+    void ParticleSwarm::init_constructor(std::vector<double>* domain_bounds,
+                                         double c1,
+                                         double c2,
+                                         double w,
+                                         size_t n_particles,
+                                         size_t iter_max) {
+        this->c1 = c1;
+        this->c2 = c2;
+        this->c3 = (c1 + c2) / 2.0;
+        this->w = w;
+        this->n_particles = n_particles;
+        this->iter_max = iter_max;
+        this->particle_swarm = new std::vector<Particle *>(this->n_particles);
+        this->domain_bounds = domain_bounds;
+        std::fill(this->particle_swarm->begin(), this->particle_swarm->end(), nullptr);
+    }
+
 }
\ No newline at end of file
diff --git a/src/LearningMethods/ParticleSwarm.h b/src/LearningMethods/ParticleSwarm.h
index fd371b73918fb741b05fbb3a6c52ab7728445bec..82a0194b95f5ba0358538790c0b5112d9a725e75 100644
--- a/src/LearningMethods/ParticleSwarm.h
+++ b/src/LearningMethods/ParticleSwarm.h
@@ -12,6 +12,8 @@
 #include "../ErrorFunction/ErrorFunctions.h"
 #include "ILearningMethods.h"
 
+
+
 /**
  *
  */
@@ -92,6 +94,16 @@ public:
 };
 
 namespace lib4neuro {
+
+    /**
+     * Particle Swarm method type differentiating between a general version and a version expecting cost function minima
+     * to be 0!
+     */
+    enum PARTICLE_SWARM_TYPE {
+        GENERAL,
+        MIN_ZERO
+    };
+
     /**
      * Class implementing the Global Particle Swarm Optimization method
      */
@@ -154,6 +166,18 @@ namespace lib4neuro {
          */
         double delta;
 
+        /**
+         * Error threshold - determines a successful convergence
+         *
+         * Must be greater than 0!
+         */
+        double err_thresh = 0;
+
+        /**
+         * Type of particle swarm optimizer
+         */
+        PARTICLE_SWARM_TYPE pst;
+
         /**
          * Bounds for every optimized parameter (p1_lower, p1_upper, p2_lower, p2_upper...)
          */
@@ -188,6 +212,16 @@ namespace lib4neuro {
          */
         LIB4NEURO_API double get_euclidean_distance(std::vector<double> *a, std::vector<double> *b);
 
+        /**
+         *
+         */
+        void init_constructor(std::vector<double> *domain_bounds,
+                              double c1,
+                              double c2,
+                              double w,
+                              size_t n_particles,
+                              size_t iter_max);
+
     public:
 
         /**
@@ -215,6 +249,31 @@ namespace lib4neuro {
                 size_t iter_max = 1000
         );
 
+        /**
+         * Creates an instance of the Global Particle Swarm Optimizer
+         *
+         * WARNING: This constructor expects the cost function minimum to be 0!
+         *
+         * @param domain_bounds Bounds for every optimized parameter (p1_lower, p1_upper, p2_lower, p2_upper...)
+         * @param c1 Cognitive parameter
+         * @param c2 Social parameter
+         * @param w Inertia weight
+         * @param n_particles Number of particles in the swarm
+         * @param iter_max Maximal number of iterations - optimization will stop after that, even if not converged
+         * @param err_thresh Error threshold for the method to converge successfully - depending on the used
+         *                   ErrorFunction
+         */
+        LIB4NEURO_API explicit ParticleSwarm(
+                std::vector<double> *domain_bounds,
+                double err_thresh,
+                PARTICLE_SWARM_TYPE,
+                double c1 = 1.711897,
+                double c2 = 1.711897,
+                double w = 0.711897,
+                size_t n_particles = 50,
+                size_t iter_max = 1000
+        );
+
         /**
          *
          */
diff --git a/src/examples/simulator.cpp b/src/examples/simulator.cpp
index f37a4eac69843aa05192d8ac2cd12b82960e1153..f527ebf2d26199fd85e4bbc6d2a73af4b90a8880 100644
--- a/src/examples/simulator.cpp
+++ b/src/examples/simulator.cpp
@@ -12,8 +12,6 @@
 #include <assert.h>
 
 #include "4neuro.h"
-#include "../CrossValidator/CrossValidator.h"
-
 
 int main(int argc, char** argv) {
 
@@ -58,15 +56,24 @@ int main(int argc, char** argv) {
         // 7) delta Amount of particles, which has to be in the cluster for the algorithm to stop (0-1)
         // 8) n_particles Number of particles in the swarm
         // 9) iter_max Maximal number of iterations - optimization will stop after that, even if not converged
+//        l4n::ParticleSwarm ps(&domain_bounds,
+//                              0.5,
+//                              0.3,
+//                              0.7,
+//                              1.711897,
+//                              1.711897,
+//                              0.711897,
+//                              150,
+//                              200);
+
         l4n::ParticleSwarm ps(&domain_bounds,
+                              1e-4,
+                              lib4neuro::PARTICLE_SWARM_TYPE::MIN_ZERO,
                               1.711897,
                               1.711897,
                               0.711897,
-                              0.5,
-                              0.3,
-                              0.7,
-                              150,
-                              2);
+                              250,
+                              20);
 
         /* Weight and bias randomization in the network accordingly to the uniform distribution */
         nn1.randomize_parameters();
@@ -97,7 +104,7 @@ int main(int argc, char** argv) {
         // 1) Threshold for the successful ending of the optimization - deviation from minima
         // 2) Number of iterations to reset step size to tolerance/10.0
         // 3) Maximal number of iterations - optimization will stop after that, even if not converged
-        l4n::GradientDescent gs(1e-6, 150, 50000);
+        l4n::GradientDescent gs(1e-6, 150, 2000);
 
         /* Gradient Descent Optimization */
         gs.optimize(mse2);  // Network training
@@ -115,7 +122,6 @@ int main(int argc, char** argv) {
         }
 
         /* Neural network loading */
-//        std::cout << "asdf" << std::endl;
         l4n::NeuralNetwork nn3("test_net_Gradient_Descent.4n");
 
         /* Check of the saved network - write to the file */
@@ -144,6 +150,10 @@ int main(int argc, char** argv) {
         /* Error function */
         l4n::MSE mse3(&nn3, &ds3);  // First parameter - neural network, second parameter - data-set
 
+        std::cout << "Network trained only by GPS: " << std::endl;
+        mse1.eval_on_data_set(&ds3, &output_file, nullptr, true, true);
+
+        std::cout << "Network trained only by GS:" << std::endl;
         mse3.eval_on_data_set(&ds3, &output_file, nullptr, true, true);
 
         /* Close the output file for writing */