solution.cc
Go to the documentation of this file.
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) : BaseException()
00037 {
00038    Select = BaseException::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 


rl_agent
Author(s): Todd Hester
autogenerated on Thu Jun 6 2019 22:00:13