SIMLIB/C++ 3.09
Loading...
Searching...
No Matches
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
32namespace simlib3 {
33
35
36////////////////////////////////////////////////////////////////////////////
37// AlgLoop -- constructor
38//
39AlgLoop::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//
63void 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//
83void 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
98const 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
#define dbgprnt(x)
Definition: algloop.cc:25
AlgLoop(Input i, double eps, unsigned long max_it, double t_min, double t_max, double t0)
Definition: algloop.cc:39
void Set(double eps, unsigned long max_it, double t_min, double t_max, double t0)
Definition: algloop.cc:63
unsigned long MaxIt
Definition: simlib.h:1649
virtual double Value() override
get block output value this method should be defined in classes derived from aContiBlock
Definition: algloop.cc:179
continuous block connection (transparent reference) wrapper for pointer to objects of aContiBlock der...
Definition: simlib.h:895
virtual double Value() override
get block output value this method should be defined in classes derived from aContiBlock
Definition: algloop.cc:114
double prev_root
Definition: simlib.h:1717
virtual double Value() override
get block output value this method should be defined in classes derived from aContiBlock
Definition: algloop.cc:402
double eps_root
Definition: simlib.h:1716
virtual double Value() override
get block output value this method should be defined in classes derived from aContiBlock
Definition: algloop.cc:285
bool HasName() const
Definition: simlib.h:321
virtual std::string Name() const
get object name
Definition: object.cc:134
base for continuous blocks with single input and algebraic loop check
Definition: simlib.h:940
double InputValue()
Definition: simlib.h:944
@ AL_Diverg
Definition: errors.h:75
@ AL_BadInitVal
Definition: errors.h:74
@ AL_NotInLoop
Definition: errors.h:77
@ AL_BadBounds
Definition: errors.h:73
@ AL_MaxCount
Definition: errors.h:76
Internal header file for SIMLIB/C++.
Implementation of class CalendarList interface is static - using global functions in SQS namespace.
Definition: algloop.cc:32
void SIMLIB_error(const enum _ErrEnum N)
print error message and abort program
Definition: error.cc:38
SIMLIB_IMPLEMENTATION
Definition: algloop.cc:34
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
void SIMLIB_warning(const enum _ErrEnum N)
print warning message and continue
Definition: error.cc:74
Main SIMLIB/C++ interface.