OpenNN  2.2
Open Neural Networks Library
ordinary_differential_equations.cpp
1 /****************************************************************************************************************/
2 /* */
3 /* OpenNN: Open Neural Networks Library */
4 /* www.artelnics.com/opennn */
5 /* */
6 /* O R D I N A R Y D I F F E R E N T I A L E Q U A T I O N S C L A S S */
7 /* */
8 /* Roberto Lopez */
9 /* Artelnics - Making intelligent use of data */
11 /* */
12 /****************************************************************************************************************/
13 
14 // OpenNN includes
15 
16 #include "ordinary_differential_equations.h"
17 
18 namespace OpenNN
19 {
20 
21 // GENERAL CONSTRUCTOR
22 
25 
27 {
28  set_default();
29 }
30 
31 
32 // XML CONSTRUCTOR
33 
37 
38 OrdinaryDifferentialEquations::OrdinaryDifferentialEquations(const tinyxml2::XMLDocument& ordinary_differential_equations_document)
39 : MathematicalModel(ordinary_differential_equations_document)
40 {
41  set_default();
42 }
43 
44 
45 // FILE CONSTRUCTOR
46 
50 
52 : MathematicalModel(file_name)
53 {
54  set_default();
55 }
56 
57 
58 // COPY CONSTRUCTOR
59 
63 
66 {
67  set(other_ordinary_differential_equations);
68 }
69 
70 
71 // DESTRUCTOR
72 
75 
77 {
78 }
79 
80 
81 // ASSIGNMENT OPERATOR
82 
83 // OrdinaryDifferentialEquations& operator = (const OrdinaryDifferentialEquations&) method
84 
88 
90 {
91  if(this != &other_ordinary_differential_equations)
92  {
93  initial_independent_variable = other_ordinary_differential_equations.initial_independent_variable;
94  final_independent_variable = other_ordinary_differential_equations.final_independent_variable;
95  initial_dependent_variables = other_ordinary_differential_equations.initial_dependent_variables;
96  }
97 
98  return(*this);
99 }
100 
101 
102 // EQUAL TO OPERATOR
103 
104 // bool operator == (const OrdinaryDifferentialEquations&) const method
105 
110 
111 bool OrdinaryDifferentialEquations::operator == (const OrdinaryDifferentialEquations& other_ordinary_differential_equations) const
112 {
113  if(initial_independent_variable == other_ordinary_differential_equations.initial_independent_variable
114  && final_independent_variable == other_ordinary_differential_equations.final_independent_variable
115  && initial_dependent_variables == other_ordinary_differential_equations.initial_dependent_variables)
116  {
117  return(true);
118  }
119  else
120  {
121  return(false);
122  }
123 }
124 
125 
126 // METHODS
127 
128 // const double& get_initial_independent_variable(void) const method
129 
131 
133 {
135 }
136 
137 
138 // const double& get_final_independent_variable(void) const method
139 
141 
143 {
145 }
146 
147 
148 // const Vector<double>& get_initial_dependent_variables(void) const method
149 
151 
153 {
155 }
156 
157 
158 // const double& get_initial_dependent_variable(const size_t&) const method
159 
162 
164 {
165  return(initial_dependent_variables[i]);
166 }
167 
168 
169 // const SolutionMethod& get_solution_method(void) const method
170 
172 
174 {
175  return(solution_method);
176 }
177 
178 
179 // std::string write_solution_method(void) const method
180 
182 
184 {
185  if(solution_method == RungeKutta)
186  {
187  return("RungeKutta");
188  }
189  else if(solution_method == RungeKuttaFehlberg)
190  {
191  return("RungeKuttaFehlberg");
192  }
193  else
194  {
195  std::ostringstream buffer;
196 
197  buffer << "OpenNN Exception: OrdinaryDifferentialEquations class.\n"
198  << "std::string write_solution_method(void) const method.\n"
199  << "Unknown solution method.\n";
200 
201  throw std::logic_error(buffer.str());
202  }
203 }
204 
205 
206 // const size_t& get_points_number(void) const method
207 
209 
211 {
212  return(points_number);
213 }
214 
215 
216 // const double& get_tolerance(void) const method
217 
219 
221 {
222  return(tolerance);
223 }
224 
225 
226 // const size_t& get_initial_size(void) const method
227 
229 
231 {
232  return(initial_size);
233 }
234 
235 
236 // const size_t& get_warning_size(void) const method
237 
239 
241 {
242  return(warning_size);
243 }
244 
245 
246 // const size_t& get_error_size(void) const method
247 
249 
251 {
252  return(error_size);
253 }
254 
255 
256 // void set(const OrdinaryDifferentialEquations&) method
257 
260 
261 void OrdinaryDifferentialEquations::set(const OrdinaryDifferentialEquations& other_ordinary_differential_equations)
262 {
263  independent_variables_number = other_ordinary_differential_equations.independent_variables_number;
264  dependent_variables_number = other_ordinary_differential_equations.dependent_variables_number;
265 
266  initial_independent_variable = other_ordinary_differential_equations.initial_independent_variable;
267  final_independent_variable = other_ordinary_differential_equations.final_independent_variable;
268 
269  initial_dependent_variables = other_ordinary_differential_equations.initial_dependent_variables;
270 
271  solution_method = other_ordinary_differential_equations.solution_method;
272 
273  points_number = other_ordinary_differential_equations.points_number;
274 
275  tolerance = other_ordinary_differential_equations.tolerance;
276 
277  initial_size = other_ordinary_differential_equations.initial_size;
278  warning_size = other_ordinary_differential_equations.warning_size;
279  error_size = other_ordinary_differential_equations.error_size;
280 
281  display = other_ordinary_differential_equations.display;
282 }
283 
284 
285 // void set_initial_independent_variable(const double&) method
286 
289 
290 void OrdinaryDifferentialEquations::set_initial_independent_variable(const double& new_initial_independent_variable)
291 {
292  initial_independent_variable = new_initial_independent_variable;
293 }
294 
295 
296 // void set_final_independent_variable(const double&) method
297 
300 
301 void OrdinaryDifferentialEquations::set_final_independent_variable(const double& new_final_independent_variable)
302 {
303  final_independent_variable = new_final_independent_variable;
304 }
305 
306 
307 // void set_initial_dependent_variables(const Vector<double>&) const method
308 
311 
313 {
314  initial_dependent_variables = new_initial_dependent_variables;
315 }
316 
317 
318 // void set_initial_dependent_variable(const size_t&, const double&) const method
319 
323 
324 void OrdinaryDifferentialEquations::set_initial_dependent_variable(const size_t& i, const double& new_initial_dependent_variable)
325 {
326  initial_dependent_variables[i] = new_initial_dependent_variable;
327 }
328 
329 
330 // void set_solution_method(const SolutionMethod&) method
331 
335 
337 {
338  solution_method = new_solution_method;
339 }
340 
341 
342 // void set_solution_method(const std::string&) method
343 
347 
348 void OrdinaryDifferentialEquations::set_solution_method(const std::string& new_solution_method)
349 {
350  if(new_solution_method == "RungeKutta")
351  {
352  set_solution_method(RungeKutta);
353  }
354  else if(new_solution_method == "RungeKuttaFehlberg")
355  {
356  set_solution_method(RungeKuttaFehlberg);
357  }
358  else
359  {
360  std::ostringstream buffer;
361 
362  buffer << "OpenNN Exception: OrdinaryDifferentialEquations class.\n"
363  << "void set_solution_method(const std::string&) method.\n"
364  << "Unknown solution method: " << new_solution_method << ".\n";
365 
366  throw std::logic_error(buffer.str());
367  }
368 }
369 
370 
371 // void set_points_number(const size_t&) method
372 
375 
376 void OrdinaryDifferentialEquations::set_points_number(const size_t& new_points_number)
377 {
378  points_number = new_points_number;
379 }
380 
381 
382 // void set_tolerance(const double&) method
383 
386 
387 void OrdinaryDifferentialEquations::set_tolerance(const double& new_tolerance)
388 {
389  tolerance = new_tolerance;
390 }
391 
392 
393 // void set_initial_size(const size_t&) method
394 
397 
398 void OrdinaryDifferentialEquations::set_initial_size(const size_t& new_initial_size)
399 {
400  initial_size = new_initial_size;
401 }
402 
403 
404 // void set_warning_size(const size_t&) method
405 
408 
409 void OrdinaryDifferentialEquations::set_warning_size(const size_t& new_warning_size)
410 {
411  warning_size = new_warning_size;
412 }
413 
414 
415 // void set_error_size(const size_t&) method
416 
419 
420 void OrdinaryDifferentialEquations::set_error_size(const size_t& new_error_size)
421 {
422  error_size = new_error_size;
423 }
424 
425 
426 // void set_default(void) method
427 
440 
442 {
445 
446  solution_method = RungeKuttaFehlberg;
447 
448  points_number = 101;
449 
450  tolerance = 1.0e-6;
451 
452  initial_size = (size_t)1.0e3;
453  warning_size = (size_t)1.0e6;
454  error_size = (size_t)1.0e9;
455 
456  display = true;
457 
458 }
459 
460 
461 // Matrix<double> calculate_Runge_Kutta_solution(const NeuralNetwork& neural_network, const double& xi, const double& xf, const Vector<double>& yi) const method
462 
465 
467 {
468  const size_t variables_number = count_variables_number();
469 
471 
472  // Fourth order Runge-Kutta coefficients
473 
474  Vector< Vector<double> > c(4);
475 
476  Matrix<double> solution(points_number, variables_number);
477 
478  Vector<double> variables(variables_number);
479 
480  // Initial variables
481 
482  solution(0,0) = initial_independent_variable;
483 
484  for(size_t j = 0; j < dependent_variables_number; j++)
485  {
486  solution(0,1+j) = initial_dependent_variables[j];
487  }
488 
489  // Main loop
490 
491  for(size_t i = 0; i < points_number-1; i++)
492  {
493  solution(i+1,0) = solution(i,0) + h;
494 
495  // First coefficient
496 
497  variables[0] = solution(i,0);
498 
499  for(size_t j = 0; j < dependent_variables_number; j++)
500  {
501  variables[1+j] = solution(i,1+j);
502  }
503 
504  c[0] = calculate_dependent_variables_dots(neural_network, variables);
505 
506  // Second coefficient
507 
508  variables[0] = solution(i,0) + h/2.0;
509 
510  for(size_t j = 0; j < dependent_variables_number; j++)
511  {
512  variables[1+j] = solution(i,1+j) + h*c[0][j]/2.0;
513  }
514 
515  c[1] = calculate_dependent_variables_dots(neural_network, variables);
516 
517  // Third coefficient
518 
519  variables[0] = solution(i,0) + h/2.0;
520 
521  for(size_t j = 0; j < dependent_variables_number; j++)
522  {
523  variables[1+j] = solution(i,1+j) + h*c[1][j]/2.0;
524  }
525 
526  c[2] = calculate_dependent_variables_dots(neural_network, variables);
527 
528  // Fourth coefficient
529 
530  variables[0] = solution(i+1,0);
531 
532  for(size_t j = 0; j < dependent_variables_number; j++)
533  {
534  variables[1+j] = solution(i,1+j) + h*c[2][j]/2.0;
535  }
536 
537  c[3] = calculate_dependent_variables_dots(neural_network, variables);
538 
539  // Dependent variables
540 
541  for(size_t j = 0; j < dependent_variables_number; j++)
542  {
543  solution(i+1,1+j) = solution(i,1+j) + h*(c[0][j] + 2.0*c[1][j] + 2.0*c[2][j] + c[3][j])/6.0;
544  }
545  }
546 
547  solution(points_number-1,0) = final_independent_variable;
548 
549  return(solution);
550 }
551 
552 
553 // Matrix<double> calculate_Runge_Kutta_final_solution(const NeuralNetwork& neural_network) const method
554 
557 
559 {
560  const size_t variables_number = count_variables_number();
561 
563 
564  // Fourth order Runge-Kutta coefficients
565 
566  Vector< Vector<double> > c(4);
567 
568  Vector<double> final_solution(variables_number);
569 
570  Vector<double> variables(variables_number);
571 
572  // Initial variables
573 
574  final_solution[0] = initial_independent_variable;
575 
576  for(size_t j = 0; j < dependent_variables_number; j++)
577  {
578  final_solution[0] = initial_dependent_variables[j];
579  }
580 
581  // Main loop
582 
583  for(size_t i = 0; i < points_number-1; i++)
584  {
585  final_solution[0] = final_solution[0] + h;
586 
587  // First coefficient
588 
589  variables[0] = final_solution[0];
590 
591  for(size_t j = 0; j < dependent_variables_number; j++)
592  {
593  variables[1+j] = final_solution[1+j];
594  }
595 
596  c[0] = calculate_dependent_variables_dots(neural_network, variables);
597 
598  // Second coefficient
599 
600  variables[0] = final_solution[0] + h/2.0;
601 
602  for(size_t j = 0; j < dependent_variables_number; j++)
603  {
604  variables[1+j] = final_solution[1+j] + h*c[0][j]/2.0;
605  }
606 
607  c[1] = calculate_dependent_variables_dots(neural_network, variables);
608 
609  // Third coefficient
610 
611  variables[0] = final_solution[0] + h/2.0;
612 
613  for(size_t j = 0; j < dependent_variables_number; j++)
614  {
615  variables[1+j] = final_solution[1+j] + h*c[1][j]/2.0;
616  }
617 
618  c[2] = calculate_dependent_variables_dots(neural_network, variables);
619 
620  // Fourth coefficient
621 
622  variables[0] = final_solution[0];
623 
624  for(size_t j = 0; j < dependent_variables_number; j++)
625  {
626  variables[1+j] = final_solution[1+j] + h*c[2][j]/2.0;
627  }
628 
629  c[3] = calculate_dependent_variables_dots(neural_network, variables);
630 
631  // Dependent variables
632 
633  for(size_t j = 0; j < dependent_variables_number; j++)
634  {
635  final_solution[1+j] = final_solution[1+j] + h*(c[0][j] + 2.0*c[1][j] + 2.0*c[2][j] + c[3][j])/6.0;
636  }
637  }
638 
639  return(final_solution);
640 }
641 
642 
643 // Matrix<double> calculate_Runge_Kutta_Fehlberg_solution(const NeuralNetwork&) const method
644 
647 
649 {
650  const double epsilon = 1.0e-12;//std::numeric_limits<double>::epsilon();
651 
652  const double a2 = 1.0/5.0;
653  const double a3 = 3.0/10.0;
654  const double a4 = 3.0/5.0;
655  const double a5 = 1.0;
656  const double a6 = 7.0/8.0;
657 
658  const double b21 = 1.0/5.0;
659  const double b31 = 3.0/40.0;
660  const double b32 = 9.0/40.0;
661  const double b41 = 3.0/10.0;
662  const double b42 = -9.0/10.0;
663  const double b43 = 6.0/5.0;
664  const double b51 = -11.0/54.0;
665  const double b52 = 5.0/2.0;
666  const double b53 = -70.0/27.0;
667  const double b54 = 35.0/27.0;
668  const double b61 = 1631.0/55296.0;
669  const double b62 = 175.0/512.0;
670  const double b63 = 575.0/13824.0;
671  const double b64 = 44275.0/110592.0;
672  const double b65 = 253.0/4096.0;
673 
674  const double c41 = 37.0/378.0;
675  const double c42 = 0.0;
676  const double c43 = 250.0/621.0;
677  const double c44 = 125.0/594.0;
678  const double c45 = 0.0;
679  const double c46 = 512.0/1771.0;
680 
681  const double c51 = 2825.0/27648.0;
682  const double c52 = 0.0;
683  const double c53 = 18575.0/48384.0;
684  const double c54 = 13525.0/55296.0;
685  const double c55 = 277.0/14336.0;
686  const double c56 = 1.0/4.0;
687 
688  const double d1 = c41 - c51;
689  const double d2 = c42 - c52;
690  const double d3 = c43 - c53;
691  const double d4 = c44 - c54;
692  const double d5 = c45 - c55;
693  const double d6 = c46 - c56;
694 
695  const size_t variables_number = count_variables_number();
696 
697  size_t size = initial_size;
698 
700 
701  double error = 0.0;
702 
703  Vector< Vector<double> > c(6);
704 
705  double hmin = 0.0;
707 
708  Vector<double> variables(variables_number);
709 
710  Matrix<double> solution(size, variables_number);
711 
712  size_t point_index = 0;
713 
714  // Initial values
715 
716  solution(0,0) = initial_independent_variable;
717 
718  for(size_t j = 0; j < dependent_variables_number; j++)
719  {
720  solution(0,1+j) = initial_dependent_variables[j];
721  }
722 
723  // Main loop
724 
725  while(solution(point_index,0) < final_independent_variable)
726  {
727  // Set smallest allowable stepsize
728 
729  hmin = 32.0*epsilon*fabs(solution(point_index,0));
730 
731  if(h < hmin)
732  {
733  if(display)
734  {
735  std::cout << "OpenNN Warning: OrdinaryDifferentialEquations class.\n"
736  << "calculate_Runge_Kutta_Fehlberg_solution() method.\n"
737  << "Step size is less than smallest allowable." << std::endl;
738  }
739 
740  h = hmin;
741  }
742 
743  if(solution(point_index,0) + h > final_independent_variable)
744  {
745  h = final_independent_variable - solution(point_index,0);
746  }
747 
748  // First coefficient
749 
750  variables[0] = solution(point_index,0);
751 
752  for(size_t j = 0; j < dependent_variables_number; j++)
753  {
754  variables[1+j] = solution(point_index,1+j);
755  }
756 
757  c[0] = calculate_dependent_variables_dots(neural_network, variables)*h;
758 
759  // Second coefficient
760 
761  variables[0] = solution(point_index,0) + a2*h;
762 
763  for(size_t j = 0; j < dependent_variables_number; j++)
764  {
765  variables[1+j] = solution(point_index,1+j)+ b21*c[0][j];
766  }
767 
768  c[1] = calculate_dependent_variables_dots(neural_network, variables)*h;
769 
770  // Third coefficient
771 
772  variables[0] = solution(point_index,0) + a3*h;
773 
774  for(size_t j = 0; j < dependent_variables_number; j++)
775  {
776  variables[1+j] = solution(point_index,1+j) + b31*c[0][j] + b32*c[1][j];
777  }
778 
779  c[2] = calculate_dependent_variables_dots(neural_network, variables)*h;
780 
781  // Fourth coefficient
782 
783  variables[0] = solution(point_index,0) + a4*h;
784 
785  for(size_t j = 0; j < dependent_variables_number; j++)
786  {
787  variables[1+j] = solution(point_index,1+j) + b41*c[0][j] + b42*c[1][j] + b43*c[2][j];
788  }
789 
790  c[3] = calculate_dependent_variables_dots(neural_network, variables)*h;
791 
792  // Fifth coefficient
793 
794  variables[0] = solution(point_index,0) + a5*h;
795 
796  for(size_t j = 0; j < dependent_variables_number; j++)
797  {
798  variables[1+j] = solution(point_index,1+j) + b51*c[0][j] + b52*c[1][j] + b53*c[2][j] + b54*c[3][j];
799  }
800 
801  c[4] = calculate_dependent_variables_dots(neural_network, variables)*h;
802 
803  // Sixth coefficient
804 
805  variables[0] = solution(point_index,0) + a6*h;
806 
807  for(size_t j = 0; j < dependent_variables_number; j++)
808  {
809  variables[1+j] = solution(point_index,1+j) + b61*c[0][j] + b62*c[1][j] + b63*c[2][j] + b64*c[3][j] + b65*c[4][j];
810  }
811 
812  c[5] = calculate_dependent_variables_dots(neural_network, variables)*h;
813 
814  // Error estimate
815 
816  for(size_t j = 0; j < dependent_variables_number; j++)
817  {
818  errors[j] = fabs(d1*c[0][j] + d2*c[1][j] + d3*c[2][j] + d4*c[3][j] + d5*c[4][j] + d6*c[5][j]);
819  }
820 
821  error = errors.calculate_maximum();
822 
823  if(error <= tolerance)
824  {
825  solution(point_index+1,0) = solution(point_index,0) + h;
826 
827  for(size_t j = 0; j < dependent_variables_number; j++)
828  {
829  solution(point_index+1,1+j) = solution(point_index,1+j) + c51*c[0][j] + c52*c[1][j] + c53*c[2][j] + c54*c[3][j] + c55*c[4][j] + c56*c[5][j];
830  }
831 
832  point_index++;
833 
834  if(error != 0.0)
835  {
836  h *= 0.9*pow(fabs(tolerance/error), 0.2);
837  }
838 
839  if(point_index >= size)
840  {
841  size *= 2;
842 
843  if(display && size > warning_size)
844  {
845  std::cout << "OpenNN Warning: OrdinaryDifferentialEquations class." << std::endl
846  << "calculate_Runge_Kutta_Fehlberg_solution() method." << std::endl
847  << "Solution size is " << size << std::endl;
848  }
849  else if(size > error_size)
850  {
851  std::ostringstream buffer;
852 
853  buffer << "OpenNN Exception: OrdinaryDifferentialEquations class." << std::endl
854  << "calculate_Runge_Kutta_Fehlberg_solution() method." << std::endl
855  << "Solution size is bigger than greatest allowable." << std::endl;
856 
857  throw std::logic_error(buffer.str());
858  }
859 
860  // @todo Substitute resize method
861 
862  //solution.resize(size, variables_number);
863  }
864  }
865  else
866  {
867  h *= 0.9*pow(fabs(tolerance/error), 0.25);
868  }
869  } // end while loop
870 
871  // @todo Substitute resize method
872 
873  //solution.resize(point_index+1, variables_number);
874 
875  return(solution);
876 }
877 
878 
879 // Vector<double> calculate_Runge_Kutta_Fehlberg_final_solution(const NeuralNetwork&) const method
880 
883 
885 {
886  const double epsilon = 1.0e-12;//std::numeric_limits<double>::epsilon();
887 
888  const double a2 = 1.0/5.0;
889  const double a3 = 3.0/10.0;
890  const double a4 = 3.0/5.0;
891  const double a5 = 1.0;
892  const double a6 = 7.0/8.0;
893 
894  const double b21 = 1.0/5.0;
895  const double b31 = 3.0/40.0;
896  const double b32 = 9.0/40.0;
897  const double b41 = 3.0/10.0;
898  const double b42 = -9.0/10.0;
899  const double b43 = 6.0/5.0;
900  const double b51 = -11.0/54.0;
901  const double b52 = 5.0/2.0;
902  const double b53 = -70.0/27.0;
903  const double b54 = 35.0/27.0;
904  const double b61 = 1631.0/55296.0;
905  const double b62 = 175.0/512.0;
906  const double b63 = 575.0/13824.0;
907  const double b64 = 44275.0/110592.0;
908  const double b65 = 253.0/4096.0;
909 
910  const double c41 = 37.0/378.0;
911  const double c42 = 0.0;
912  const double c43 = 250.0/621.0;
913  const double c44 = 125.0/594.0;
914  const double c45 = 0.0;
915  const double c46 = 512.0/1771.0;
916 
917  const double c51 = 2825.0/27648.0;
918  const double c52 = 0.0;
919  const double c53 = 18575.0/48384.0;
920  const double c54 = 13525.0/55296.0;
921  const double c55 = 277.0/14336.0;
922  const double c56 = 1.0/4.0;
923 
924  const double d1 = c41 - c51;
925  const double d2 = c42 - c52;
926  const double d3 = c43 - c53;
927  const double d4 = c44 - c54;
928  const double d5 = c45 - c55;
929  const double d6 = c46 - c56;
930 
931  const size_t variables_number = count_variables_number();
932 
934 
935  double error = 0.0;
936 
937  Vector< Vector<double> > c(6);
938 
939  double hmin = 0.0;
941 
942  Vector<double> variables(variables_number);
943 
944  Vector<double> final_solution(variables_number);
945 
946  // Initial values
947 
948  final_solution[0] = initial_independent_variable;
949 
950  for(size_t j = 0; j < dependent_variables_number; j++)
951  {
952  final_solution[1+j] = initial_dependent_variables[j];
953  }
954 
955  // Main loop
956 
957  while(final_solution[0] < final_independent_variable)
958  {
959  // Set smallest allowable stepsize
960 
961  hmin = 32.0*epsilon*fabs(final_solution[0]);
962 
963  if(h < hmin)
964  {
965  if(display)
966  {
967  std::cout << "OpenNN Warning: OrdinaryDifferentialEquations class.\n"
968  << "calculate_Runge_Kutta_Fehlberg_solution() method.\n"
969  << "Step size is less than smallest allowable." << std::endl;
970  }
971 
972  h = hmin;
973  }
974 
975  if(final_solution[0] + h > final_independent_variable)
976  {
977  h = final_independent_variable - final_solution[0];
978  }
979 
980  // First coefficient
981 
982  variables[0] = final_solution[0];
983 
984  for(size_t j = 0; j < dependent_variables_number; j++)
985  {
986  variables[1+j] = final_solution[1+j];
987  }
988 
989  c[0] = calculate_dependent_variables_dots(neural_network, variables)*h;
990 
991  // Second coefficient
992 
993  variables[0] = final_solution[0] + a2*h;
994 
995  for(size_t j = 0; j < dependent_variables_number; j++)
996  {
997  variables[1+j] = final_solution[1+j]+ b21*c[0][j];
998  }
999 
1000  c[1] = calculate_dependent_variables_dots(neural_network, variables)*h;
1001 
1002  // Third coefficient
1003 
1004  variables[0] = final_solution[0] + a3*h;
1005 
1006  for(size_t j = 0; j < dependent_variables_number; j++)
1007  {
1008  variables[1+j] = final_solution[1+j] + b31*c[0][j] + b32*c[1][j];
1009  }
1010 
1011  c[2] = calculate_dependent_variables_dots(neural_network, variables)*h;
1012 
1013  // Fourth coefficient
1014 
1015  variables[0] = final_solution[0] + a4*h;
1016 
1017  for(size_t j = 0; j < dependent_variables_number; j++)
1018  {
1019  variables[1+j] = final_solution[1+j] + b41*c[0][j] + b42*c[1][j] + b43*c[2][j];
1020  }
1021 
1022  c[3] = calculate_dependent_variables_dots(neural_network, variables)*h;
1023 
1024  // Fifth coefficient
1025 
1026  variables[0] = final_solution[0] + a5*h;
1027 
1028  for(size_t j = 0; j < dependent_variables_number; j++)
1029  {
1030  variables[1+j] = final_solution[1+j] + b51*c[0][j] + b52*c[1][j] + b53*c[2][j] + b54*c[3][j];
1031  }
1032 
1033  c[4] = calculate_dependent_variables_dots(neural_network, variables)*h;
1034 
1035  // Sixth coefficient
1036 
1037  variables[0] = final_solution[0] + a6*h;
1038 
1039  for(size_t j = 0; j < dependent_variables_number; j++)
1040  {
1041  variables[1+j] = final_solution[1+j] + b61*c[0][j] + b62*c[1][j] + b63*c[2][j] + b64*c[3][j] + b65*c[4][j];
1042  }
1043 
1044  c[5] = calculate_dependent_variables_dots(neural_network, variables)*h;
1045 
1046  // Error estimate
1047 
1048  for(size_t j = 0; j < dependent_variables_number; j++)
1049  {
1050  errors[j] = fabs(d1*c[0][j] + d2*c[1][j] + d3*c[2][j] + d4*c[3][j] + d5*c[4][j] + d6*c[5][j]);
1051  }
1052 
1053  error = errors.calculate_maximum();
1054 
1055  if(error <= tolerance)
1056  {
1057  final_solution[0] += h;
1058 
1059  for(size_t j = 0; j < dependent_variables_number; j++)
1060  {
1061  final_solution[1+j] += c51*c[0][j] + c52*c[1][j] + c53*c[2][j] + c54*c[3][j] + c55*c[4][j] + c56*c[5][j];
1062  }
1063 
1064  if(error != 0.0)
1065  {
1066  h *= 0.9*pow(fabs(tolerance/error), 0.2);
1067  }
1068  }
1069  else
1070  {
1071  h *= 0.9*pow(fabs(tolerance/error), 0.25);
1072  }
1073  } // end while loop
1074 
1075 
1076  return(final_solution);
1077 }
1078 
1079 
1080 // Matrix<double> calculate_solutions(const NeuralNetwork&) const method
1081 
1083 {
1084  switch(solution_method)
1085  {
1086  case RungeKutta:
1087  {
1088  return(calculate_Runge_Kutta_solution(neural_network));
1089  }
1090  break;
1091 
1092  case RungeKuttaFehlberg:
1093  {
1094  return(calculate_Runge_Kutta_Fehlberg_solution(neural_network));
1095  }
1096  break;
1097 
1098  default:
1099  {
1100  std::ostringstream buffer;
1101 
1102  buffer << "OpenNN Error: OrdinaryDifferentialEquations class\n"
1103  << "Vector<double> calculate_solutions(const NeuralNetwork&) const method.\n"
1104  << "Unknown solution method.\n";
1105 
1106  throw std::logic_error(buffer.str());
1107  }
1108  break;
1109  }
1110 }
1111 
1112 
1113 // Vector<double> calculate_final_solutions(const NeuralNetwork&) const method
1114 
1116 {
1117  switch(solution_method)
1118  {
1119  case RungeKutta:
1120  {
1121  return(calculate_Runge_Kutta_final_solution(neural_network));
1122  }
1123  break;
1124 
1125  case RungeKuttaFehlberg:
1126  {
1127  return(calculate_Runge_Kutta_Fehlberg_final_solution(neural_network));
1128  }
1129  break;
1130 
1131  default:
1132  {
1133  std::ostringstream buffer;
1134 
1135  buffer << "OpenNN Exception: ScalingLayer class\n"
1136  << "Vector<double> calculate_final_solutions(const NeuralNetwork&) const method.\n"
1137  << "Unknown solution method.\n";
1138 
1139  throw std::logic_error(buffer.str());
1140  }
1141  break;
1142  }
1143 }
1144 
1145 
1146 // std::string to_string(void) const method
1147 
1149 
1151 {
1152  std::ostringstream buffer;
1153 
1154  buffer << "Mathematical model\n"
1155  << "Independent variables number: " << independent_variables_number << "\n"
1156  << "Dependent variables number: " << dependent_variables_number << "\n"
1157  << "Initial independent variable: " << initial_independent_variable << "\n"
1158  << "Final independent variable: " << final_independent_variable << "\n"
1159  << "Initial dependent variables: " << initial_dependent_variables << "\n"
1160  << "Solution method: " << write_solution_method() << "\n"
1161  << "Points number: " << points_number << "\n"
1162  << "Tolerance" << tolerance << "\n"
1163  << "Initial size: " << initial_size << "\n"
1164  << "Warning size: " << warning_size << "\n"
1165  << "Error size: " << error_size << "\n"
1166  << "Display: " << display << std::endl;
1167 
1168  return(buffer.str());
1169 }
1170 
1171 
1172 // tinyxml2::XMLDocument* to_XML(void) const method
1173 
1176 
1177 tinyxml2::XMLDocument* OrdinaryDifferentialEquations::to_XML(void) const
1178 {
1179  tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument;
1180 
1181  std::ostringstream buffer;
1182 
1183  tinyxml2::XMLElement* ordinary_differential_equations_element = document->NewElement("OrdinaryDifferentialEquations");
1184 
1185  document->InsertFirstChild(ordinary_differential_equations_element);
1186 
1187  // Independent variables number
1188  {
1189  tinyxml2::XMLElement* element = document->NewElement("IndependentVariablesNumber");
1190  ordinary_differential_equations_element->LinkEndChild(element);
1191 
1192  buffer.str("");
1193  buffer << independent_variables_number;
1194 
1195  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1196  element->LinkEndChild(text);
1197  }
1198 
1199  // Dependent variables number
1200  {
1201  tinyxml2::XMLElement* element = document->NewElement("DependentVariablesNumber");
1202  ordinary_differential_equations_element->LinkEndChild(element);
1203 
1204  buffer.str("");
1205  buffer << dependent_variables_number;
1206 
1207  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1208  element->LinkEndChild(text);
1209  }
1210 
1211  // Initial independent variable
1212  {
1213  tinyxml2::XMLElement* element = document->NewElement("InitialIndependentVariable");
1214  ordinary_differential_equations_element->LinkEndChild(element);
1215 
1216  buffer.str("");
1217  buffer << initial_independent_variable;
1218 
1219  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1220  element->LinkEndChild(text);
1221  }
1222 
1223  // Final independent variable
1224  {
1225  tinyxml2::XMLElement* element = document->NewElement("FinalIndependentVariable");
1226  ordinary_differential_equations_element->LinkEndChild(element);
1227 
1228  buffer.str("");
1229  buffer << final_independent_variable;
1230 
1231  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1232  element->LinkEndChild(text);
1233  }
1234 
1235  // Initial dependent variables
1236  {
1237  tinyxml2::XMLElement* element = document->NewElement("InitialDependentVariables");
1238  ordinary_differential_equations_element->LinkEndChild(element);
1239 
1240  buffer.str("");
1241  buffer << initial_dependent_variables;
1242 
1243  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1244  element->LinkEndChild(text);
1245  }
1246 
1247  // Solution method
1248  {
1249  tinyxml2::XMLElement* element = document->NewElement("SolutionMethod");
1250  ordinary_differential_equations_element->LinkEndChild(element);
1251 
1252  tinyxml2::XMLText* text = document->NewText(write_solution_method().c_str());
1253  element->LinkEndChild(text);
1254  }
1255 
1256  // Points number
1257  {
1258  tinyxml2::XMLElement* element = document->NewElement("PointsNumber");
1259  ordinary_differential_equations_element->LinkEndChild(element);
1260 
1261  buffer.str("");
1262  buffer << points_number;
1263 
1264  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1265  element->LinkEndChild(text);
1266  }
1267 
1268  // Tolerance
1269  {
1270  tinyxml2::XMLElement* element = document->NewElement("Tolerance");
1271  ordinary_differential_equations_element->LinkEndChild(element);
1272 
1273  buffer.str("");
1274  buffer << tolerance;
1275 
1276  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1277  element->LinkEndChild(text);
1278  }
1279 
1280  // Initial size
1281  {
1282  tinyxml2::XMLElement* element = document->NewElement("InitialSize");
1283  ordinary_differential_equations_element->LinkEndChild(element);
1284 
1285  buffer.str("");
1286  buffer << initial_size;
1287 
1288  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1289  element->LinkEndChild(text);
1290  }
1291 
1292  // Warning size
1293  {
1294  tinyxml2::XMLElement* element = document->NewElement("WarningSize");
1295  ordinary_differential_equations_element->LinkEndChild(element);
1296 
1297  buffer.str("");
1298  buffer << warning_size;
1299 
1300  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1301  element->LinkEndChild(text);
1302  }
1303 
1304  // Error size
1305  {
1306  tinyxml2::XMLElement* element = document->NewElement("ErrorSize");
1307  ordinary_differential_equations_element->LinkEndChild(element);
1308 
1309  buffer.str("");
1310  buffer << error_size;
1311 
1312  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1313  element->LinkEndChild(text);
1314  }
1315 
1316  // Display
1317  {
1318  tinyxml2::XMLElement* element = document->NewElement("Display");
1319  ordinary_differential_equations_element->LinkEndChild(element);
1320 
1321  buffer.str("");
1322  buffer << display;
1323 
1324  tinyxml2::XMLText* text = document->NewText(buffer.str().c_str());
1325  element->LinkEndChild(text);
1326  }
1327 
1328  return(document);
1329 }
1330 
1331 
1332 // void from_XML(const tinyxml2::XMLDocument&) method
1333 
1336 
1337 void OrdinaryDifferentialEquations::from_XML(const tinyxml2::XMLDocument& document)
1338 {
1339  // Dependent variables number
1340  {
1341  const tinyxml2::XMLElement* element = document.FirstChildElement("DependentVariablesNumber");
1342 
1343  if(element)
1344  {
1345  const char* text = element->GetText();
1346 
1347  if(text)
1348  {
1349  try
1350  {
1351  set_dependent_variables_number(atoi(text));
1352  }
1353  catch(const std::logic_error& e)
1354  {
1355  std::cout << e.what() << std::endl;
1356  }
1357  }
1358  }
1359  }
1360 
1361  // Initial independent variable
1362  {
1363  const tinyxml2::XMLElement* element = document.FirstChildElement("InitialIndependentVariable");
1364 
1365  if(element)
1366  {
1367  const char* text = element->GetText();
1368 
1369  if(text)
1370  {
1371  try
1372  {
1374  }
1375  catch(const std::logic_error& e)
1376  {
1377  std::cout << e.what() << std::endl;
1378  }
1379  }
1380  }
1381  }
1382 
1383  // Final independent variable
1384  {
1385  const tinyxml2::XMLElement* element = document.FirstChildElement("FinalIndependentVariable");
1386 
1387  if(element)
1388  {
1389  const char* text = element->GetText();
1390 
1391  if(text)
1392  {
1393  try
1394  {
1395  set_final_independent_variable(atof(text));
1396  }
1397  catch(const std::logic_error& e)
1398  {
1399  std::cout << e.what() << std::endl;
1400  }
1401  }
1402  }
1403  }
1404 
1405  // Initial dependent variables
1406  {
1407  const tinyxml2::XMLElement* element = document.FirstChildElement("InitialDependentVariables");
1408 
1409  if(element)
1410  {
1411  const char* text = element->GetText();
1412 
1413  if(text)
1414  {
1415  try
1416  {
1417  Vector<double> new_initial_dependent_variables;
1418  new_initial_dependent_variables.parse(text);
1419 
1420  set_initial_dependent_variables(new_initial_dependent_variables);
1421  }
1422  catch(const std::logic_error& e)
1423  {
1424  std::cout << e.what() << std::endl;
1425  }
1426  }
1427  }
1428  }
1429 
1430  // Solution method
1431  {
1432  const tinyxml2::XMLElement* element = document.FirstChildElement("SolutionMethod");
1433 
1434  if(element)
1435  {
1436  const char* text = element->GetText();
1437 
1438  if(text)
1439  {
1440  try
1441  {
1442  std::string new_solution_method(text);
1443 
1444  set_solution_method(new_solution_method);
1445  }
1446  catch(const std::logic_error& e)
1447  {
1448  std::cout << e.what() << std::endl;
1449  }
1450  }
1451  }
1452  }
1453 
1454  // Points number
1455  {
1456  const tinyxml2::XMLElement* element = document.FirstChildElement("PointsNumber");
1457 
1458  if(element)
1459  {
1460  const char* text = element->GetText();
1461 
1462  if(text)
1463  {
1464  try
1465  {
1466  set_points_number(atoi(text));
1467  }
1468  catch(const std::logic_error& e)
1469  {
1470  std::cout << e.what() << std::endl;
1471  }
1472  }
1473  }
1474  }
1475 
1476  // Tolerance
1477  {
1478  const tinyxml2::XMLElement* element = document.FirstChildElement("Tolerance");
1479 
1480  if(element)
1481  {
1482  const char* text = element->GetText();
1483 
1484  if(text)
1485  {
1486  try
1487  {
1488  set_tolerance(atof(text));
1489  }
1490  catch(const std::logic_error& e)
1491  {
1492  std::cout << e.what() << std::endl;
1493  }
1494  }
1495  }
1496  }
1497 
1498  // Initial size
1499  {
1500  const tinyxml2::XMLElement* element = document.FirstChildElement("InitialSize");
1501 
1502  if(element)
1503  {
1504  const char* text = element->GetText();
1505 
1506  if(text)
1507  {
1508  try
1509  {
1510  set_initial_size(atoi(text));
1511  }
1512  catch(const std::logic_error& e)
1513  {
1514  std::cout << e.what() << std::endl;
1515  }
1516  }
1517  }
1518  }
1519 
1520  // Warning size
1521  {
1522  const tinyxml2::XMLElement* element = document.FirstChildElement("WarningSize");
1523 
1524  if(element)
1525  {
1526  const char* text = element->GetText();
1527 
1528  if(text)
1529  {
1530  try
1531  {
1532  set_warning_size(atoi(text));
1533  }
1534  catch(const std::logic_error& e)
1535  {
1536  std::cout << e.what() << std::endl;
1537  }
1538  }
1539  }
1540  }
1541 
1542  // Error size
1543  {
1544  const tinyxml2::XMLElement* element = document.FirstChildElement("ErrorSize");
1545 
1546  if(element)
1547  {
1548  const char* text = element->GetText();
1549 
1550  if(text)
1551  {
1552  try
1553  {
1554  set_error_size(atoi(text));
1555  }
1556  catch(const std::logic_error& e)
1557  {
1558  std::cout << e.what() << std::endl;
1559  }
1560  }
1561  }
1562  }
1563 
1564  // Display
1565  {
1566  const tinyxml2::XMLElement* display_element = document.FirstChildElement("Display");
1567 
1568  if(display_element)
1569  {
1570  const char* display_text = display_element->GetText();
1571 
1572  if(display_text)
1573  {
1574  try
1575  {
1576  std::string display_string(display_text);
1577 
1578  set_display(display_string != "0");
1579  }
1580  catch(const std::logic_error& e)
1581  {
1582  std::cout << e.what() << std::endl;
1583  }
1584  }
1585  }
1586  }
1587 }
1588 
1589 
1590 // void save_data(const NeuralNetwork&, const std::string&) const method
1591 
1595 
1596 void OrdinaryDifferentialEquations::save_data(const NeuralNetwork& neural_network, const std::string& file_name) const
1597 {
1598  const Matrix<double> solution = calculate_Runge_Kutta_solution(neural_network);
1599 
1600  solution.save(file_name);
1601 }
1602 
1603 }
1604 
1605 
1606 // OpenNN: Open Neural Networks Library.
1607 // Copyright (c) 2005-2015 Roberto Lopez.
1608 //
1609 // This library is free software; you can redistribute it and/or
1610 // modify it under the terms of the GNU Lesser General Public
1611 // License as published by the Free Software Foundation; either
1612 // version 2.1 of the License, or any later version.
1613 //
1614 // This library is distributed in the hope that it will be useful,
1615 // but WITHOUT ANY WARRANTY; without even the implied warranty of
1616 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1617 // Lesser General Public License for more details.
1618 
1619 // You should have received a copy of the GNU Lesser General Public
1620 // License along with this library; if not, write to the Free Software
1621 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
void parse(const std::string &)
Definition: vector.h:5217
double final_independent_variable
Final value for the only independent variable.
const double & get_initial_independent_variable(void) const
Returns the initial value of the independent variable.
Vector< double > calculate_Runge_Kutta_final_solution(const NeuralNetwork &) const
SolutionMethod
Enumeration of available methods for numerical integration of ordinary differential equations...
virtual Vector< double > calculate_final_solutions(const NeuralNetwork &) const
const size_t & get_error_size(void) const
Returns an error size for the solutions in the Runge-Kutta-Fehlberg method.
std::string write_solution_method(void) const
Returns a string with the name of the numerical method to be used for integration of the ordinary dif...
void set_initial_dependent_variable(const size_t &, const double &)
void save(const std::string &) const
Definition: matrix.h:6417
Matrix< double > calculate_Runge_Kutta_Fehlberg_solution(const NeuralNetwork &) const
const size_t & get_initial_size(void) const
Returns the initial size to be reserved for the solutions in the Runge-Kutta-Fehlberg method...
virtual Vector< double > calculate_dependent_variables_dots(const NeuralNetwork &, const Vector< double > &) const =0
This pure virtual method calculates the derivatives of the dependent variables with respect to the in...
double initial_independent_variable
Initial value for the only independent variable.
size_t warning_size
Number of points at which the the Runge-Kutta-Fehlberg method displays a warning message.
void set_initial_dependent_variables(const Vector< double > &)
size_t error_size
Number of points at which the the Runge-Kutta-Fehlberg method throws an exception.
size_t count_variables_number(void) const
Matrix< double > calculate_Runge_Kutta_solution(const NeuralNetwork &) const
virtual void from_XML(const tinyxml2::XMLDocument &)
std::string to_string(void) const
Returns a string representation of the current ordinary differential equations object.
double tolerance
Tolerance in the Runge-Kutta-Fehlberg method.
virtual Matrix< double > calculate_solutions(const NeuralNetwork &) const
const SolutionMethod & get_solution_method(void) const
Returns the numerical method to be used for integration of the ordinary differential equation...
size_t points_number
Number of points in the Runge-Kutta method.
size_t initial_size
Initial number of points in the Runge-Kutta-Fehlberg method.
OrdinaryDifferentialEquations & operator=(const OrdinaryDifferentialEquations &)
const double & get_final_independent_variable(void) const
Returns the final value of the independent variable.
size_t dependent_variables_number
Number of dependent variables defining the mathematical model.
bool display
Flag for displaying warnings.
void set_dependent_variables_number(const size_t &)
const double & get_tolerance(void) const
Returns the tolerance in the Runge-Kutta-Fehlberg method.
T calculate_maximum(void) const
Returns the largest element in the vector.
Definition: vector.h:1265
const double & get_initial_dependent_variable(const size_t &) const
Vector< double > initial_dependent_variables
Initial values for the dependent variables.
const size_t & get_points_number(void) const
Returns the number of integration points in the Runge-Kutta method.
void set(const OrdinaryDifferentialEquations &)
SolutionMethod solution_method
Numerical integration method (Runge-Kutta or Runge-Kutta-Fehlberg).
virtual void save_data(const NeuralNetwork &, const std::string &) const
const Vector< double > & get_initial_dependent_variables(void) const
Returns the initial values of the independent variables.
size_t independent_variables_number
Number of independent variables defining the mathematical model.
Vector< double > calculate_Runge_Kutta_Fehlberg_final_solution(const NeuralNetwork &) const
const size_t & get_warning_size(void) const
Returns a warning size for the solutions in the Runge-Kutta-Fehlberg method.
bool operator==(const OrdinaryDifferentialEquations &) const
virtual tinyxml2::XMLDocument * to_XML(void) const