MOOS 0.2375
|
00001 //$$ solution.cpp // solve routines 00002 00003 // Copyright (C) 1994: R B Davies 00004 00005 00006 #define WANT_STREAM // include.h will get stream fns 00007 #define WANT_MATH // include.h will get math fns 00008 00009 #include "include.h" 00010 #include "boolean.h" 00011 #include "myexcept.h" 00012 00013 #include "solution.h" 00014 00015 #ifdef use_namespace 00016 namespace RBD_COMMON { 00017 #endif 00018 00019 00020 void R1_R1::Set(Real X) 00021 { 00022 if ((!minXinf && X <= minX) || (!maxXinf && X >= maxX)) 00023 Throw(SolutionException("X value out of range")); 00024 x = X; xSet = true; 00025 } 00026 00027 R1_R1::operator Real() 00028 { 00029 if (!xSet) Throw(SolutionException("Value of X not set")); 00030 Real y = operator()(); 00031 return y; 00032 } 00033 00034 unsigned long SolutionException::Select; 00035 00036 SolutionException::SolutionException(const char* a_what) : Exception() 00037 { 00038 Select = Exception::Select; 00039 AddMessage("Error detected by solution package\n"); 00040 AddMessage(a_what); AddMessage("\n"); 00041 if (a_what) Tracer::AddTrace(); 00042 }; 00043 00044 inline Real square(Real x) { return x*x; } 00045 00046 void OneDimSolve::LookAt(int V) 00047 { 00048 lim--; 00049 if (!lim) Throw(SolutionException("Does not converge")); 00050 Last = V; 00051 Real yy = function(x[V]) - YY; 00052 Finish = (fabs(yy) <= accY) || (Captured && fabs(x[L]-x[U]) <= accX ); 00053 y[V] = vpol*yy; 00054 } 00055 00056 void OneDimSolve::HFlip() { hpol=-hpol; State(U,C,L); } 00057 00058 void OneDimSolve::VFlip() 00059 { vpol = -vpol; y[0] = -y[0]; y[1] = -y[1]; y[2] = -y[2]; } 00060 00061 void OneDimSolve::Flip() 00062 { 00063 hpol=-hpol; vpol=-vpol; State(U,C,L); 00064 y[0] = -y[0]; y[1] = -y[1]; y[2] = -y[2]; 00065 } 00066 00067 void OneDimSolve::State(int I, int J, int K) { L=I; C=J; U=K; } 00068 00069 void OneDimSolve::Linear(int I, int J, int K) 00070 { 00071 x[J] = (x[I]*y[K] - x[K]*y[I])/(y[K] - y[I]); 00072 // cout << "Linear\n"; 00073 } 00074 00075 void OneDimSolve::Quadratic(int I, int J, int K) 00076 { 00077 // result to overwrite I 00078 Real YJK, YIK, YIJ, XKI, XKJ; 00079 YJK = y[J] - y[K]; YIK = y[I] - y[K]; YIJ = y[I] - y[J]; 00080 XKI = (x[K] - x[I]); 00081 XKJ = (x[K]*y[J] - x[J]*y[K])/YJK; 00082 if ( square(YJK/YIK)>(x[K] - x[J])/XKI || 00083 square(YIJ/YIK)>(x[J] - x[I])/XKI ) 00084 { 00085 x[I] = XKJ; 00086 // cout << "Quadratic - exceptional\n"; 00087 } 00088 else 00089 { 00090 XKI = (x[K]*y[I] - x[I]*y[K])/YIK; 00091 x[I] = (XKJ*y[I] - XKI*y[J])/YIJ; 00092 // cout << "Quadratic - normal\n"; 00093 } 00094 } 00095 00096 Real OneDimSolve::Solve(Real Y, Real X, Real Dev, int Lim) 00097 { 00098 enum Loop { start, captured1, captured2, binary, finish }; 00099 Tracer et("OneDimSolve::Solve"); 00100 lim=Lim; Captured = false; 00101 if (Dev==0.0) Throw(SolutionException("Dev is zero")); 00102 L=0; C=1; U=2; vpol=1; hpol=1; y[C]=0.0; y[U]=0.0; 00103 if (Dev<0.0) { hpol=-1; Dev = -Dev; } 00104 YY=Y; // target value 00105 x[L] = X; // initial trial value 00106 if (!function.IsValid(X)) 00107 Throw(SolutionException("Starting value is invalid")); 00108 Loop TheLoop = start; 00109 for (;;) 00110 { 00111 switch (TheLoop) 00112 { 00113 case start: 00114 LookAt(L); if (Finish) { TheLoop = finish; break; } 00115 if (y[L]>0.0) VFlip(); // so Y[L] < 0 00116 00117 x[U] = X + Dev * hpol; 00118 if (!function.maxXinf && x[U] > function.maxX) 00119 x[U] = (function.maxX + X) / 2.0; 00120 if (!function.minXinf && x[U] < function.minX) 00121 x[U] = (function.minX + X) / 2.0; 00122 00123 LookAt(U); if (Finish) { TheLoop = finish; break; } 00124 if (y[U] > 0.0) { TheLoop = captured1; Captured = true; break; } 00125 if (y[U] == y[L]) 00126 Throw(SolutionException("Function is flat")); 00127 if (y[U] < y[L]) HFlip(); // Change direction 00128 State(L,U,C); 00129 for (i=0; i<20; i++) 00130 { 00131 // cout << "Searching for crossing point\n"; 00132 // Have L C then crossing point, Y[L]<Y[C]<0 00133 x[U] = x[C] + Dev * hpol; 00134 if (!function.maxXinf && x[U] > function.maxX) 00135 x[U] = (function.maxX + x[C]) / 2.0; 00136 if (!function.minXinf && x[U] < function.minX) 00137 x[U] = (function.minX + x[C]) / 2.0; 00138 00139 LookAt(U); if (Finish) { TheLoop = finish; break; } 00140 if (y[U] > 0) { TheLoop = captured2; Captured = true; break; } 00141 if (y[U] < y[C]) 00142 Throw(SolutionException("Function is not monotone")); 00143 Dev *= 2.0; 00144 State(C,U,L); 00145 } 00146 if (TheLoop != start ) break; 00147 Throw(SolutionException("Cannot locate a crossing point")); 00148 00149 case captured1: 00150 // cout << "Captured - 1\n"; 00151 // We have 2 points L and U with crossing between them 00152 Linear(L,C,U); // linear interpolation 00153 // - result to C 00154 LookAt(C); if (Finish) { TheLoop = finish; break; } 00155 if (y[C] > 0.0) Flip(); // Want y[C] < 0 00156 if (y[C] < 0.5*y[L]) { State(C,L,U); TheLoop = binary; break; } 00157 00158 case captured2: 00159 // cout << "Captured - 2\n"; 00160 // We have L,C before crossing, U after crossing 00161 Quadratic(L,C,U); // quad interpolation 00162 // - result to L 00163 State(C,L,U); 00164 if ((x[C] - x[L])*hpol <= 0.0 || (x[C] - x[U])*hpol >= 0.0) 00165 { TheLoop = captured1; break; } 00166 LookAt(C); if (Finish) { TheLoop = finish; break; } 00167 // cout << "Through first stage\n"; 00168 if (y[C] > 0.0) Flip(); 00169 if (y[C] > 0.5*y[L]) { TheLoop = captured2; break; } 00170 else { State(C,L,U); TheLoop = captured1; break; } 00171 00172 case binary: 00173 // We have L, U around crossing - do binary search 00174 // cout << "Binary\n"; 00175 for (i=3; i; i--) 00176 { 00177 x[C] = 0.5*(x[L]+x[U]); 00178 LookAt(C); if (Finish) { TheLoop = finish; break; } 00179 if (y[C]>0.0) State(L,U,C); else State(C,L,U); 00180 } 00181 if (TheLoop != binary) break; 00182 TheLoop = captured1; break; 00183 00184 case finish: 00185 return x[Last]; 00186 00187 } 00188 } 00189 } 00190 00191 bool R1_R1::IsValid(Real X) 00192 { 00193 Set(X); 00194 return (minXinf || x > minX) && (maxXinf || x < maxX); 00195 } 00196 00197 #ifdef use_namespace 00198 } 00199 #endif 00200