| 1 | //$$ solution.cpp                    // solve routines | 
|---|
| 2 |  | 
|---|
| 3 | // Copyright (C) 1994: R B Davies | 
|---|
| 4 |  | 
|---|
| 5 |  | 
|---|
| 6 | #define WANT_STREAM                  // include.h will get stream fns | 
|---|
| 7 | #define WANT_MATH                    // include.h will get math fns | 
|---|
| 8 |  | 
|---|
| 9 | #include "include.h" | 
|---|
| 10 | #include "boolean.h" | 
|---|
| 11 | #include "myexcept.h" | 
|---|
| 12 |  | 
|---|
| 13 | #include "solution.h" | 
|---|
| 14 |  | 
|---|
| 15 | #ifdef use_namespace | 
|---|
| 16 | namespace RBD_COMMON { | 
|---|
| 17 | #endif | 
|---|
| 18 |  | 
|---|
| 19 |  | 
|---|
| 20 | void R1_R1::Set(Real X) | 
|---|
| 21 | { | 
|---|
| 22 |    if ((!minXinf && X <= minX) || (!maxXinf && X >= maxX)) | 
|---|
| 23 |        Throw(SolutionException("X value out of range")); | 
|---|
| 24 |    x = X; xSet = true; | 
|---|
| 25 | } | 
|---|
| 26 |  | 
|---|
| 27 | R1_R1::operator Real() | 
|---|
| 28 | { | 
|---|
| 29 |    if (!xSet) Throw(SolutionException("Value of X not set")); | 
|---|
| 30 |    Real y = operator()(); | 
|---|
| 31 |    return y; | 
|---|
| 32 | } | 
|---|
| 33 |  | 
|---|
| 34 | unsigned long SolutionException::Select; | 
|---|
| 35 |  | 
|---|
| 36 | SolutionException::SolutionException(const char* a_what) : Exception() | 
|---|
| 37 | { | 
|---|
| 38 |    Select = Exception::Select; | 
|---|
| 39 |    AddMessage("Error detected by solution package\n"); | 
|---|
| 40 |    AddMessage(a_what); AddMessage("\n"); | 
|---|
| 41 |    if (a_what) Tracer::AddTrace(); | 
|---|
| 42 | }; | 
|---|
| 43 |  | 
|---|
| 44 | inline Real square(Real x) { return x*x; } | 
|---|
| 45 |  | 
|---|
| 46 | void OneDimSolve::LookAt(int V) | 
|---|
| 47 | { | 
|---|
| 48 |    lim--; | 
|---|
| 49 |    if (!lim) Throw(SolutionException("Does not converge")); | 
|---|
| 50 |    Last = V; | 
|---|
| 51 |    Real yy = function(x[V]) - YY; | 
|---|
| 52 |    Finish = (fabs(yy) <= accY) || (Captured && fabs(x[L]-x[U]) <= accX ); | 
|---|
| 53 |    y[V] = vpol*yy; | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | void OneDimSolve::HFlip() { hpol=-hpol; State(U,C,L); } | 
|---|
| 57 |  | 
|---|
| 58 | void OneDimSolve::VFlip() | 
|---|
| 59 |    { vpol = -vpol; y[0] = -y[0]; y[1] = -y[1]; y[2] = -y[2]; } | 
|---|
| 60 |  | 
|---|
| 61 | void OneDimSolve::Flip() | 
|---|
| 62 | { | 
|---|
| 63 |    hpol=-hpol; vpol=-vpol; State(U,C,L); | 
|---|
| 64 |    y[0] = -y[0]; y[1] = -y[1]; y[2] = -y[2]; | 
|---|
| 65 | } | 
|---|
| 66 |  | 
|---|
| 67 | void OneDimSolve::State(int I, int J, int K) { L=I; C=J; U=K; } | 
|---|
| 68 |  | 
|---|
| 69 | void OneDimSolve::Linear(int I, int J, int K) | 
|---|
| 70 | { | 
|---|
| 71 |    x[J] = (x[I]*y[K] - x[K]*y[I])/(y[K] - y[I]); | 
|---|
| 72 |    // cout << "Linear\n"; | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | void OneDimSolve::Quadratic(int I, int J, int K) | 
|---|
| 76 | { | 
|---|
| 77 |    // result to overwrite I | 
|---|
| 78 |    Real YJK, YIK, YIJ, XKI, XKJ; | 
|---|
| 79 |    YJK = y[J] - y[K]; YIK = y[I] - y[K]; YIJ = y[I] - y[J]; | 
|---|
| 80 |    XKI = (x[K] - x[I]); | 
|---|
| 81 |    XKJ = (x[K]*y[J] - x[J]*y[K])/YJK; | 
|---|
| 82 |    if ( square(YJK/YIK)>(x[K] - x[J])/XKI || | 
|---|
| 83 |       square(YIJ/YIK)>(x[J] - x[I])/XKI ) | 
|---|
| 84 |    { | 
|---|
| 85 |       x[I] = XKJ; | 
|---|
| 86 |       // cout << "Quadratic - exceptional\n"; | 
|---|
| 87 |    } | 
|---|
| 88 |    else | 
|---|
| 89 |    { | 
|---|
| 90 |       XKI = (x[K]*y[I] - x[I]*y[K])/YIK; | 
|---|
| 91 |       x[I] = (XKJ*y[I] - XKI*y[J])/YIJ; | 
|---|
| 92 |       // cout << "Quadratic - normal\n"; | 
|---|
| 93 |    } | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | Real OneDimSolve::Solve(Real Y, Real X, Real Dev, int Lim) | 
|---|
| 97 | { | 
|---|
| 98 |    enum Loop { start, captured1, captured2, binary, finish }; | 
|---|
| 99 |    Tracer et("OneDimSolve::Solve"); | 
|---|
| 100 |    lim=Lim; Captured = false; | 
|---|
| 101 |    if (Dev==0.0) Throw(SolutionException("Dev is zero")); | 
|---|
| 102 |    L=0; C=1; U=2; vpol=1; hpol=1; y[C]=0.0; y[U]=0.0; | 
|---|
| 103 |    if (Dev<0.0) { hpol=-1; Dev = -Dev; } | 
|---|
| 104 |    YY=Y;                                // target value | 
|---|
| 105 |    x[L] = X;                            // initial trial value | 
|---|
| 106 |    if (!function.IsValid(X)) | 
|---|
| 107 |       Throw(SolutionException("Starting value is invalid")); | 
|---|
| 108 |    Loop TheLoop = start; | 
|---|
| 109 |    for (;;) | 
|---|
| 110 |    { | 
|---|
| 111 |       switch (TheLoop) | 
|---|
| 112 |       { | 
|---|
| 113 |       case start: | 
|---|
| 114 |          LookAt(L); if (Finish) { TheLoop = finish; break; } | 
|---|
| 115 |          if (y[L]>0.0) VFlip();               // so Y[L] < 0 | 
|---|
| 116 |  | 
|---|
| 117 |          x[U] = X + Dev * hpol; | 
|---|
| 118 |          if (!function.maxXinf && x[U] > function.maxX) | 
|---|
| 119 |             x[U] = (function.maxX + X) / 2.0; | 
|---|
| 120 |          if (!function.minXinf && x[U] < function.minX) | 
|---|
| 121 |             x[U] = (function.minX + X) / 2.0; | 
|---|
| 122 |  | 
|---|
| 123 |          LookAt(U); if (Finish) { TheLoop = finish; break; } | 
|---|
| 124 |          if (y[U] > 0.0) { TheLoop = captured1; Captured = true; break; } | 
|---|
| 125 |          if (y[U] == y[L]) | 
|---|
| 126 |             Throw(SolutionException("Function is flat")); | 
|---|
| 127 |          if (y[U] < y[L]) HFlip();             // Change direction | 
|---|
| 128 |          State(L,U,C); | 
|---|
| 129 |          for (i=0; i<20; i++) | 
|---|
| 130 |          { | 
|---|
| 131 |             // cout << "Searching for crossing point\n"; | 
|---|
| 132 |             // Have L C then crossing point, Y[L]<Y[C]<0 | 
|---|
| 133 |             x[U] = x[C] + Dev * hpol; | 
|---|
| 134 |             if (!function.maxXinf && x[U] > function.maxX) | 
|---|
| 135 |             x[U] = (function.maxX + x[C]) / 2.0; | 
|---|
| 136 |             if (!function.minXinf && x[U] < function.minX) | 
|---|
| 137 |             x[U] = (function.minX + x[C]) / 2.0; | 
|---|
| 138 |  | 
|---|
| 139 |             LookAt(U); if (Finish) { TheLoop = finish; break; } | 
|---|
| 140 |             if (y[U] > 0) { TheLoop = captured2; Captured = true; break; } | 
|---|
| 141 |             if (y[U] < y[C]) | 
|---|
| 142 |                 Throw(SolutionException("Function is not monotone")); | 
|---|
| 143 |             Dev *= 2.0; | 
|---|
| 144 |             State(C,U,L); | 
|---|
| 145 |          } | 
|---|
| 146 |          if (TheLoop != start ) break; | 
|---|
| 147 |          Throw(SolutionException("Cannot locate a crossing point")); | 
|---|
| 148 |  | 
|---|
| 149 |       case captured1: | 
|---|
| 150 |          // cout << "Captured - 1\n"; | 
|---|
| 151 |          // We have 2 points L and U with crossing between them | 
|---|
| 152 |          Linear(L,C,U);                   // linear interpolation | 
|---|
| 153 |                                           // - result to C | 
|---|
| 154 |          LookAt(C); if (Finish) { TheLoop = finish; break; } | 
|---|
| 155 |          if (y[C] > 0.0) Flip();            // Want y[C] < 0 | 
|---|
| 156 |          if (y[C] < 0.5*y[L]) { State(C,L,U); TheLoop = binary; break; } | 
|---|
| 157 |  | 
|---|
| 158 |       case captured2: | 
|---|
| 159 |          // cout << "Captured - 2\n"; | 
|---|
| 160 |          // We have L,C before crossing, U after crossing | 
|---|
| 161 |          Quadratic(L,C,U);                // quad interpolation | 
|---|
| 162 |                                           // - result to L | 
|---|
| 163 |          State(C,L,U); | 
|---|
| 164 |          if ((x[C] - x[L])*hpol <= 0.0 || (x[C] - x[U])*hpol >= 0.0) | 
|---|
| 165 |             { TheLoop = captured1; break; } | 
|---|
| 166 |          LookAt(C); if (Finish) { TheLoop = finish; break; } | 
|---|
| 167 |          // cout << "Through first stage\n"; | 
|---|
| 168 |          if (y[C] > 0.0) Flip(); | 
|---|
| 169 |          if (y[C] > 0.5*y[L]) { TheLoop = captured2; break; } | 
|---|
| 170 |          else { State(C,L,U); TheLoop = captured1; break; } | 
|---|
| 171 |  | 
|---|
| 172 |       case binary: | 
|---|
| 173 |          // We have L, U around crossing - do binary search | 
|---|
| 174 |          // cout << "Binary\n"; | 
|---|
| 175 |          for (i=3; i; i--) | 
|---|
| 176 |          { | 
|---|
| 177 |             x[C] = 0.5*(x[L]+x[U]); | 
|---|
| 178 |             LookAt(C); if (Finish) { TheLoop = finish; break; } | 
|---|
| 179 |             if (y[C]>0.0) State(L,U,C); else State(C,L,U); | 
|---|
| 180 |          } | 
|---|
| 181 |          if (TheLoop != binary) break; | 
|---|
| 182 |          TheLoop = captured1; break; | 
|---|
| 183 |  | 
|---|
| 184 |       case finish: | 
|---|
| 185 |          return x[Last]; | 
|---|
| 186 |  | 
|---|
| 187 |       } | 
|---|
| 188 |    } | 
|---|
| 189 | } | 
|---|
| 190 |  | 
|---|
| 191 | bool R1_R1::IsValid(Real X) | 
|---|
| 192 | { | 
|---|
| 193 |    Set(X); | 
|---|
| 194 |    return (minXinf || x > minX) && (maxXinf || x < maxX); | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 | #ifdef use_namespace | 
|---|
| 198 | } | 
|---|
| 199 | #endif | 
|---|
| 200 |  | 
|---|