Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

BisectSolver.cpp

Go to the documentation of this file.
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 


Documentation generated with Doxygen on Sun Feb 6 17:10:45 2005
Visit MathStudio home page for more info

[ Top ]