SIMLIB/C++  3.07
algloop.cc
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 //! \file algloop.cc Algebraic loop solver blocks
3 //
4 // Copyright (c) 1997 David Leška
5 // Copyright (c) 1998-2016 Petr Peringer
6 //
7 // This library is licensed under GNU Library GPL. See the file COPYING.
8 //
9 
10 //
11 // Methods for solving algebraic loops
12 //
13 
14 #include "simlib.h"
15 #include "internal.h"
16 
17 #include <cmath>
18 
19 //#define LOOP_DEBUG
20 
21 #ifdef LOOP_DEBUG
22 #include <cstdio>
23 #define dbgprnt(x) { printf x; }
24 #else
25 #define dbgprnt(x)
26 #endif
27 
28 ////////////////////////////////////////////////////////////////////////////
29 // implementation
30 //
31 
32 namespace simlib3 {
33 
35 
36 ////////////////////////////////////////////////////////////////////////////
37 // AlgLoop -- constructor
38 //
39 AlgLoop::AlgLoop(Input i, double eps, unsigned long max_it,
40  double t_min, double t_max, double t0) :
41  aContiBlock1(i),
42  Eps(eps),
43  MaxIt(max_it),
44  TA(t_min),
45  TB(t_max),
46  T0(t0),
47  was_cycle(false),
48  phase(0), // automaton state
49  root(0)
50 {
51  if(t_min>=t_max) { // check boundary points
53  }
54  if(t0>t_max || t0<t_min) { // is initial value between t_min,t_max?
56  }
57 }; // AlgLoop::AlgLoop
58 
59 
60 ////////////////////////////////////////////////////////////////////////////
61 // AlgLoop -- set parameters
62 //
63 void AlgLoop::Set(double eps, unsigned long max_it,
64  double t_min, double t_max, double t0)
65 {
66  if(t_min>=t_max) { // check boundary points
68  }
69  if(t0>t_max || t0<t_min) { // is initial value betveen t_min,t_max?
71  }
72  Eps=eps;
73  MaxIt=max_it;
74  TA=t_min;
75  TB=t_max;
76  T0=t0;
77 }; // AlgLoop::Set1
78 
79 
80 ////////////////////////////////////////////////////////////////////////////
81 // AlgLoop -- set parameters, for methods without initial value
82 //
83 void AlgLoop::Set(double eps, unsigned long max_it,
84  double t_min, double t_max)
85 {
86  if(t_min>=t_max) { // check boundary points
88  }
89  Eps=eps;
90  MaxIt=max_it;
91  TA=t_min;
92  TB=t_max;
93  T0=t_min;
94 }; // AlgLoop::Set2
95 
96 #if 0
97 /// get name of object
98 const char *AlgLoop::Name() const
99 {
100  if (HasName())
101  return Name();
102  else
103  return SIMLIB_create_tmp_name("AlgLoop{%p}", this);
104 }
105 #endif
106 
107 ////////////////////////////////////////////////////////////////////////////
108 // Iterations -- returned value
109 //
110 /* Formula:
111 
112  f(t)=t ... t[n+1]=f(t[n])
113 */
115 {
116  unsigned long count=0; // counter of iterations
117  double prev_root; // root from previous iteration step
118 
119  /* take fresh initial value */
120 
121  if(phase==0) {
122  root=T0;
123  phase=1;
124  }
125 
126  /* iterate */
127 
128  do {
129  prev_root=root;
130  /* compute t=f(t) */
131  if(!was_cycle) {
132  was_cycle=true;
133  root=InputValue(); // go through loop
134  if(was_cycle) { // test if block is in loop
136  }
137  } else {
138  was_cycle=false;
139  return root; // end of walk
140  }
141  /* check for number of loops */
142  if(count>=MaxIt) {
144  break;
145  }
146  /* convergency test */
147  if(root<TA || root>TB) {
149  break;
150  }
151  count++;
152  } while(fabs(root-prev_root)>Eps); // accuracy has been achieved
153 
154  /* restore values */
155 
156  dbgprnt(("Iterations-count: %lu\n",count));
157  was_cycle=false;
158  phase=0;
159  return root;
160 } // Iterations::Value
161 
162 
163 ////////////////////////////////////////////////////////////////////////////
164 // Bisect -- returned value
165 //
166 /* Formula:
167 
168  t:=(ta+tb)/2
169  ft:=f(t)
170  if (ft*fb<0) -- select interval for next step
171  then
172  ta:=t;
173  fa:=ft;
174  else
175  tb:=t;
176  fb:=ft;
177  end if;
178 */
180 {
181  unsigned long count=0; // counter of iterations
182  //TODO this code needs checking
183  double fa = 0; // start function value
184  double fb = 0; // end function value
185  double ft = 0; // function value in middle of the interval
186  double ta = 0; // start point
187  double tb = 0; // end point
188 
189  /* now compute fa=f(ta) */
190 
191  // TODO automaton state named "phase" ? This code needs cleaning!
192  // TODO use switch(state)
193  if(phase==0) {
194  if(!was_cycle) { // this means object.Value() call level 0
195  was_cycle=true;
196  ta=TA;
197  fa=ta-InputValue(); // go through loop
198  if(was_cycle) { // test if block is in loop
200  }
201  } else {
202  was_cycle=false;
203  return TA; // end of walk
204  }
205  dbgprnt(("ta: %g\n",ta));
206  dbgprnt(("fa: %g\n",fa));
207  was_cycle=false;
208  phase=1;
209  } // if phase0
210 
211  /* compute fb=f(tb) */
212 
213  if(phase==1) {
214  if(!was_cycle) {
215  was_cycle=true;
216  tb=TB;
217  fb=tb-InputValue(); // go through loop
218  } else {
219  was_cycle=false;
220  return TB; // end of walk
221  }
222  dbgprnt(("tb: %g\n",tb));
223  dbgprnt(("fb: %g\n",fb));
224  was_cycle=false;
225  phase=2;
226  } // phase1
227 
228  /* iterate */
229 
230  if(phase==2) {
231  do {
232  /* compute ft=f(t) */
233  if(!was_cycle) {
234  was_cycle=true;
235  root=0.5*(ta+tb);
236  dbgprnt(("root: %g\n",root));
237  ft=root-InputValue(); // go through loop
238  dbgprnt(("ft: %g\n",ft));
239  } else {
240  was_cycle=false;
241  return root; // end of walk
242  }
243  /* check for number of loops */
244  if(count>=MaxIt) {
246  break;
247  }
248  /* select interval for next step */
249  if(ft*fb<0) { // in which half is root?
250  ta=root;
251  fa=ft;
252  } else {
253  tb=root;
254  fb=ft;
255  }
256  count++;
257  } while(fabs(ft)>Eps && 0.5*(tb-ta)>Eps); // accuracy has been achieved
258  } // phase2
259 
260  /* restore values */
261 
262  dbgprnt(("Bisect-count: %lu\n",count));
263  was_cycle=false;
264  phase=0;
265  return root;
266 } // Bisect::Value
267 
268 
269 ////////////////////////////////////////////////////////////////////////////
270 // RegulaFalsi -- returned value
271 //
272 /* Formula:
273 
274  t:=(ta*fb-tb*fa)/(fb-fa)
275  ft:=f(t)
276  if (ft*fb<0) -- select interval for next step
277  then
278  ta:=t;
279  fa:=ft;
280  else
281  tb:=t;
282  fb:=ft;
283  end if;
284 */
286 {
287  unsigned long count=0; // counter of iterations
288  //## repair
289  double feps = 0; // function value for force precision test
290  double prev_root = 0; // root from previous iteration step
291  double fa = 0; // function value in boundary point
292  double fb = 0; // - "" -
293  double ft = 0; // in middle of interval
294  double ta = 0; // boundary point
295  double tb = 0; // - "" -
296 
297  /* compute fa=f(ta) */
298 
299  if(phase==0) {
300  if(!was_cycle) {
301  was_cycle=true;
302  root=ta=TA;
303  fa=ta-InputValue(); // go through loop
304  if(was_cycle) { // test if block is in loop
306  }
307  } else {
308  was_cycle=false;
309  return TA; // end of walk
310  }
311  dbgprnt(("ta: %g\n",ta));
312  dbgprnt(("fa: %g\n",fa));
313  was_cycle=false;
314  phase=1;
315  } // phase0
316 
317  /* compute fb=f(tb) */
318 
319  if(phase==1) {
320  if(!was_cycle) {
321  was_cycle=true;
322  tb=TB;
323  fb=tb-InputValue(); // go through loop
324  } else {
325  was_cycle=false;
326  return TB; // end of walk
327  }
328  dbgprnt(("tb: %g\n",tb));
329  dbgprnt(("fb: %g\n",fb));
330  was_cycle=false;
331  phase=2;
332  } // phase1
333 
334  /* iterate */
335 
336  if(phase>=2) {
337  do {
338  if(phase==2) {
339  /* compute ft=f(t) */
340  if(!was_cycle) {
341  was_cycle=true;
342  prev_root=root;
343  root=(ta*fb-tb*fa)/(fb-fa);
344  ft=root-InputValue(); // go through loop
345  dbgprnt(("ft: %12.9g\n",ft));
346  } else {
347  was_cycle=false;
348  dbgprnt(("root: %12.9g\n",root));
349  return root; // end of walk
350  }
351  /* check for number of loops */
352  if(count>=MaxIt) {
354  break;
355  }
356  /* select interval for next step */
357  if(ft*fb<0) { // in which part is root?
358  ta=root;
359  fa=ft;
360  } else {
361  tb=root;
362  fb=ft;
363  }
364  phase=3;
365  } // phase2
366  if(phase==3) {
367  /* force accuracy test */
368  if(!was_cycle) {
369  was_cycle=true;
370  eps_root=((prev_root<root) ? (root+Eps) : (root-Eps));
371  feps=eps_root-InputValue(); // go through loop
372  dbgprnt(("feps: %12.9g\n",feps));
373  } else {
374  was_cycle=false;
375  dbgprnt(("eps_root: %12.9g\n",eps_root));
376  return eps_root; // end of walk
377  }
378  phase=2;
379  } // phase3
380  count++;
381  // has been achieved required accuracy?
382  } while((fabs(ft)>Eps && fabs(root-prev_root)>Eps) || feps*ft>0);
383  } // phase2,3
384 
385  /* restore values */
386 
387  dbgprnt(("RegulaFalsi-count: %lu\n",count));
388  was_cycle=false;
389  phase=0;
390  return root;
391 } // RegulaFalsi::Value
392 
393 
394 ////////////////////////////////////////////////////////////////////////////
395 // Newton -- returned value
396 //
397 /* Formula:
398 
399  t[n+1]:=(t[n-1]*f[t]-t[n]*f[n-1])/(f[n]-f[n-1])
400  f[n+1]:=f(t[n+1])
401 */
403 {
404  unsigned long count=0; // counter of iterations
405  double trat=1.0+(TB-TA)*1.0e-3; // small step ratio
406  double feps = 0; // function value for force precision test
407  double ft = 0; // function value in root
408  double prev_ft = 0; // function value in previous root
409  double aux_root = 0; // auxiliary variables
410  double aux_ft = 0; // to store values
411 
412  /* compute ft=f(root) */
413 
414  if(phase==0) {
415  if(!was_cycle) {
416  was_cycle=true;
417  root=T0;
418  ft=root-InputValue(); // go through loop
419  if(was_cycle) { // test if block is in loop
421  }
422  dbgprnt(("f[0]: %g\n",ft));
423  } else {
424  was_cycle=false;
425  dbgprnt(("root[0]: %g\n",root));
426  return root; // end of walk
427  }
428  was_cycle=false;
429  phase=1;
430  } // phase0
431 
432  /* compute prev_ft=f(prev_root) */
433 
434  if(phase==1) {
435  if(!was_cycle) {
436  was_cycle=true;
437  prev_root=T0*trat;
438  prev_ft=prev_root-InputValue(); // go through loop
439  dbgprnt(("f[-1]: %g\n",prev_ft));
440  } else {
441  was_cycle=false;
442  dbgprnt(("root[-1]: %g\n",prev_root));
443  return prev_root; // end of walk
444  }
445  was_cycle=false;
446  phase=2;
447  } // phase1
448 
449  /* iterate */
450 
451  if(phase>=2) {
452  do {
453  if(phase==2) {
454  /* compute ft=f(t) */
455  if(!was_cycle) {
456  was_cycle=true;
457  aux_root=root;
458  aux_ft=ft;
459  root=(prev_root*ft - root*prev_ft) / (ft - prev_ft);
460  ft=root-InputValue(); // go through loop
461  prev_root=aux_root;
462  prev_ft=aux_ft;
463  dbgprnt(("ft: %g\n",ft));
464  } else {
465  was_cycle=false;
466  dbgprnt(("root: %g\n",root));
467  return root; // end of walk
468  }
469  /* check for number of loops */
470  if(count>=MaxIt) {
472  break;
473  }
474  /* convergency test */
475  if(root<TA || root>TB) {
477  break;
478  }
479  phase=3;
480  } // phase2
481  if(phase==3) {
482  /* force accuracy test */
483  if(!was_cycle) {
484  was_cycle=true;
485  eps_root=((prev_root<root) ? (root+Eps) : (root-Eps));
486  feps=eps_root-InputValue(); // go through loop
487  dbgprnt(("feps: %g\n",feps));
488  } else {
489  was_cycle=false;
490  dbgprnt(("eps_root: %g\n",eps_root));
491  return eps_root; // end of walk
492  }
493  phase=2;
494  } // phase3
495  count++;
496  // has been achieved required accuracy?
497  } while((fabs(ft)>Eps && fabs(root-prev_root)>Eps) || feps*ft>0);
498  } // phase2,3
499 
500  /* restore values */
501 
502  dbgprnt(("Newton-count: %lu\n",count));
503  was_cycle=false;
504  phase=0;
505  return root;
506 } // Newton::Value
507 
508 }
509 
510 // end
virtual double Value() override
get block output value this method should be defined in classes derived from aContiBlock ...
Definition: algloop.cc:179
void Set(double eps, unsigned long max_it, double t_min, double t_max, double t0)
Definition: algloop.cc:63
void SIMLIB_error(const enum _ErrEnum N)
print error message and abort program
Definition: error.cc:38
continuous block connection (transparent reference) wrapper for pointer to objects of aContiBlock der...
Definition: simlib.h:895
bool HasName() const
Definition: simlib.h:321
virtual double Value() override
get block output value this method should be defined in classes derived from aContiBlock ...
Definition: algloop.cc:402
Implementation of class CalendarList interface is static - using global functions in SQS namespace...
Definition: algloop.cc:32
void SIMLIB_warning(const enum _ErrEnum N)
print warning message and continue
Definition: error.cc:74
std::string SIMLIB_create_tmp_name(const char *fmt,...)
printf-like function to create temporary name (the length of temporary names is limited) used only ...
Definition: name.cc:80
AlgLoop(Input i, double eps, unsigned long max_it, double t_min, double t_max, double t0)
Definition: algloop.cc:39
virtual double Value() override
get block output value this method should be defined in classes derived from aContiBlock ...
Definition: algloop.cc:114
Internal header file for SIMLIB/C++.
virtual double Value() override
get block output value this method should be defined in classes derived from aContiBlock ...
Definition: algloop.cc:285
Main SIMLIB/C++ interface.
virtual std::string Name() const
get object name
Definition: object.cc:134
SIMLIB_IMPLEMENTATION
Definition: algloop.cc:34
double InputValue()
Definition: simlib.h:944
base for continuous blocks with single input and algebraic loop check
Definition: simlib.h:940
#define dbgprnt(x)
Definition: algloop.cc:25
unsigned long MaxIt
Definition: simlib.h:1649