00001 00002 // MathCore = a WYSIWYG equation editor + a powerful math engine // 00003 // Copyright (C) 2003 by Francesco Montorsi // 00004 // // 00005 // This library is free software; you can redistribute it and/or // 00006 // modify it under the terms of the GNU Lesser General Public // 00007 // License as published by the Free Software Foundation; either // 00008 // version 2.1 of the License, or (at your option) any later // 00009 // version. // 00010 // // 00011 // This library is distributed in the hope that it will be useful, // 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of // 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // 00014 // GNU Lesser General Public License for more details. // 00015 // // 00016 // You should have received a copy of the GNU Lesser General Public // 00017 // License along with this program; if not, write to the Free // 00018 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, // 00019 // MA 02111-1307, USA. // 00020 // // 00021 // For any comment, suggestion or feature request, please contact // 00022 // the administrator of the project at frm@users.sourceforge.net // 00023 // // 00030 00031 00032 00033 // optimization for GCC compiler 00034 #ifdef __GNUG__ 00035 #pragma implementation "BisectSolver.h" 00036 #endif 00037 00038 // includes 00039 #include "mc/mcprec.h" 00040 #ifdef __BORLANDC__ 00041 #pragma hdrstop 00042 #endif 00043 00044 #ifndef mcPRECOMP 00045 #include "mc/MathUtils.h" // for the mcLOG macro 00046 #include "mc/BisectSolver.h" 00047 #include "mc/MathSystem.h" 00048 #include "mc/MathAndSystem.h" 00049 #include "mc/MathOrSystem.h" 00050 #include "mc/Symbol.h" 00051 #include "mc/Monomial.h" 00052 #endif 00053 00054 00055 00056 00057 00058 // ---------------------------------------- 00059 // mcBISECTSOLVER 00060 // ---------------------------------------- 00061 00062 bool mcBisectSolver::math_WorksOn(const mcMathOrSystem &m) const 00063 { 00064 if (m.math_GetMathSystemType().m_tMath1 != mcMSTL1_EQUATIONS) 00065 return FALSE; 00066 00067 // the given system must contain a single unknown 00068 // (which will be the unknown we are going to solve for) 00069 // and it must be non-parametric 00070 if (m.math_ContainsParameters() || 00071 m.math_GetCountOfSymbolsType(&mcSymbol::arrUnknowns) > 1) 00072 return FALSE; 00073 00074 // mcBisectSolver accepts any type of equation systems... 00075 return TRUE; 00076 } 00077 00078 mcRealValue mcBisectSolver::math_Bisect(mcMathLine &tosolve, const mcSymbolProperties *unk, 00079 const mcRealValue &a, const mcRealValue &b) 00080 { 00081 // evaluate the function in the two given points 00082 mcRealValue fa = tosolve.math_EvaluateAt(unk, a); 00083 mcRealValue fb = tosolve.math_EvaluateAt(unk, b); 00084 00085 return math_Bisect(tosolve, unk, a, b, fa, fb); 00086 } 00087 00088 mcRealValue mcBisectSolver::math_Bisect(mcMathLine &tosolve, const mcSymbolProperties *unk, 00089 const mcRealValue &a, const mcRealValue &b, 00090 const mcRealValue &fa, const mcRealValue &fb) 00091 { 00092 mcSOLVERLOG(wxT("mcBisectSolver::Bisect - bisecting in [%s,%s] where the ") 00093 wxT("function evaluates to [%s,%s]"), mcTXTV(a), mcTXTV(b), 00094 mcTXTV(fa), mcTXTV(fb)); 00095 00096 #ifdef __MCDEBUG__ 00097 bool check = (a != *mcRealValue::pNAN) && (b != *mcRealValue::pNAN) && 00098 (fa != *mcRealValue::pNAN) && (fb != *mcRealValue::pNAN); 00099 mcASSERT(check && ((fa*fb) < 0), wxT("Invalid arguments")); 00100 #endif 00101 00102 mcRealValue c = (a+b)/2.0; 00103 if (a == c || b == c) 00104 return c; // we've found an exact solution !!! 00105 00106 mcRealValue err = a-b; 00107 if (err.abs() < m_fDelta) 00108 return c; // error is small enough for us... :-) 00109 00110 mcRealValue fc = tosolve.math_EvaluateAt(unk, c); 00111 mcASSERT(fc != *mcRealValue::pNAN, wxT("Something wrong !!!")); 00112 00113 // continue bisection in range [a;c] or [c;a] 00114 if (fa*fc < 0) 00115 return math_Bisect(tosolve, unk, a, c, fa, fc); 00116 return math_Bisect(tosolve, unk, c, b, fc, fb); 00117 } 00118 00119 bool mcBisectSolver::math_SolveLine(mcMathLine &p, const mcSymbolProperties *unk, 00120 mcSystemStepArray &steps) 00121 { 00122 // no unknowns set by mcSolver::math_PreSolve ? 00123 mcASSERT(unk != NULL, wxT("We need the main unknown !!")); 00124 mcSOLVERLOG(wxT("mcBisectSolver::math_SolveLine - The unknown is [%s]."), mcTXTP(unk)); 00125 00126 // okay; we can start with the real resolution of the given data, 00127 // storing all the steps in the given array... 00128 00129 // STEP #1: find the first a,b 00130 mcRealValue a = m_rStart.data_GetRange(0)->math_GetLowerLimitValue(), 00131 b = m_rStart.data_GetRange(0)->math_GetUpperLimitValue(); 00132 mcSOLVERLOG(wxT("mcBisectSolver::math_SolveLine - the start range is [%s,%s]."), 00133 mcTXTV(a), mcTXTV(b)); 00134 00135 // STEP #2: begin bisection there 00136 mcRealValue res = math_Bisect(p, unk, a, b); 00137 mcSOLVERLOG(wxT("mcBisectSolver::math_SolveLine - Approximated solution is %s"), 00138 mcTXTV(res)); 00139 00140 // STEP #3: store the solution found in a new step... 00141 p.math_SetMathType(mcMMT_EQUATION); 00142 p.data_GetLeftMem().math_WrapSymbol(unk); 00143 p.data_GetRightMem().math_WrapNumber(res); 00144 steps.data_AddLine(p); 00145 00146 // we managed to find a (approximated) solution... 00147 return TRUE; 00148 } 00149 00150 bool mcBisectSolver::math_isReady() const 00151 { 00152 if (m_rStart.math_isFinite()) 00153 return TRUE; 00154 return FALSE; 00155 } 00156 00157 bool mcBisectSolver::math_SetStartRange(const mcRange &r, const mcMathLine &p, 00158 const mcSymbolProperties *sym) 00159 { 00160 const mcSymbolProperties *unk=sym; 00161 00162 // if the given mcSymbolProperties pointer is NULL, 00163 // then we have to find the unknown ourselves... 00164 if (!unk) { 00165 00166 for (int i=0; i<mcSymbol::arrUnknowns.data_GetCount(); i++) { 00167 mcSymbolProperties *curr = mcSymbol::arrUnknowns.data_GetSymbol(i); 00168 if (p.math_ContainsSymbol(curr)) 00169 unk = curr; 00170 } 00171 00172 if (!unk) 00173 return FALSE; 00174 } 00175 00176 // TODO: check that the function is continue 00177 00178 // check that at the extremes of the given range, the function 00179 // assumes values with different signs... 00180 mcRealValue a = r.math_GetLowerLimitValue(), 00181 b = r.math_GetUpperLimitValue(); 00182 mcRealValue fa = p.math_EvaluateAt(unk, a); 00183 mcRealValue fb = p.math_EvaluateAt(unk, b); 00184 00185 if (fa*fb > 0) 00186 return FALSE; // if does not change sign in the given range 00187 00188 // it is okay 00189 m_rStart.data_DeepCopy(r); 00190 return TRUE; 00191 } 00192 00193
[ Top ] |