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

Solver.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 "Solver.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/Solver.h"
00046  #include "mc/MathSystem.h"
00047  #include "mc/MathAndSystem.h"
00048  #include "mc/MathOrSystem.h"
00049  #include "mc/Symbol.h"
00050 #endif
00051 
00052 
00053 
00054 
00055 // ---------------
00056 // mcSOLVER
00057 // ---------------
00058 
00059 void mcSolver::math_ResetUnkArray()
00060 {
00061  for (int i=0; i < mcSOLVER_MAXLINES; i++)
00062   m_pUnkArr[i] = NULL;
00063 }
00064 
00065 void mcSolver::math_SplitInTwoEquations(const mcPolynomial &lfirsteq, const mcPolynomial &rfirsteq, 
00066           const mcPolynomial &lseceq, const mcPolynomial &rseceq, 
00067           mcSystemStepArray &steps, mcLogicOperator conn)
00068 {
00069  mcMathLine *equ1 = new mcMathLine(lfirsteq, rfirsteq);
00070  mcMathLine *equ2 = new mcMathLine(lseceq, rseceq);
00071 
00072  // just call the overloaded version
00073  math_SplitInTwoEquations(equ1, equ2, steps, conn);
00074 }
00075 
00076 
00077 void mcSolver::math_SplitInTwoEquations(const mcMathLine &equ1, const mcMathLine &equ2,
00078           mcSystemStepArray &steps, mcLogicOperator conn)
00079 {
00080  // just call the overloaded version
00081  math_SplitInTwoEquations(new mcMathLine(equ1), new mcMathLine(equ2), steps, conn);
00082 }
00083 
00084 void mcSolver::math_SplitInTwoEquations(mcMathLine *equ1, mcMathLine *equ2,
00085           mcSystemStepArray &steps, mcLogicOperator conn)
00086 {
00087  mcMathOrSystem *step = new mcMathOrSystem();
00088  
00089  if (conn == mcLO_OR) {
00090   
00091   // create two equations connected by a logical OR
00092   step->data_AddLineToNewAndSystem(equ1);
00093   step->data_AddLineToNewAndSystem(equ2);
00094   
00095  } else {
00096   
00097   // create two equations connected by a logical AND
00098   step->data_AddLineToLastAndSystem(equ1);
00099   step->data_AddLineToLastAndSystem(equ2);
00100  }
00101 
00102  // add this step to the steparray
00103  steps.data_Add(step);
00104 }
00105 
00106 
00107 /*mcMathMng *mcSolver::math_GetNewStep(const mcMathMng *last)
00108 {
00109  mcMathMng *newstep = new mcMathMng(*last);
00110 
00111  // update current line pointer...
00112  //m_pCurrLine = newstep->GetLine(0);
00113 
00114  // and return it
00115  return newstep;
00116 }
00117 
00118 mcMathMng *mcSolver::math_GetNewSmartStep(const mcMathMng *last)
00119 {
00120  mcRealValue ll = last->math_GetTotalLenght();
00121 
00122  // a negative value of m_fLastLenght means this is the first time
00123  // this function is used...
00124  if (m_fLastLenght > 0 &&
00125   ll-m_fLastLenght < mcMathCore::Get()->GetStepThreshold()) {
00126 
00127   // the required setp should not be created since the complexity
00128   // of the data is not diminuished enough...
00129   return (mcMathMng *)last;
00130  }
00131 
00132  // store this step's lenght
00133  m_fLastLenght = ll;
00134  return math_GetNewStep(last);
00135 }
00136 */
00137 #define mcDEFINE_EXPSIM_STEP(x, y)         \
00138  void mcSolver::x(long flags, long rflags, mcMathLine &tosimp, \
00139        mcSystemStepArray &steps,    \
00140                  mcExpSimRes *result) {     \
00141   /* simplify & (eventually) store simplification result */ \
00142   mcExpSimRes res = tosimp.y(flags, rflags);     \
00143   if (result) *result = res;         \
00144   steps.data_AddLine(tosimp);         \
00145  }
00146 
00147 #define mcDEFINE_EXPSIM_COMPLETE(x, y)        \
00148  void mcSolver::x(long flags, long rflags,       \
00149      mcMathLine &last, mcSystemStepArray &steps) { \
00150   mcExpSimRes res;           \
00151   int cycles = 0;            \
00152                  \
00153   /* do first simplification step */       \
00154   y(flags, rflags, last, steps, &res);      \
00155   mcSOLVERLOG(wxT("mcSolver::") wxT(#x)      \
00156     wxT(" - completed 0-th step [%s]"), mcTXT(last)); \
00157   cycles++;             \
00158                  \
00159   /* add steps until the process is complete;         */  \
00160   /* the mcELEMENTMATH_MAX_PROCESS_CYCLES limit is    */  \
00161   /* used to avoid to get trapped in an infinite loop */  \
00162   while (res != mcESR_DONE &&         \
00163     cycles < mcELEMENTMATH_MAX_PROCESS_CYCLES) {   \
00164                   \
00165    /* do another step */         \
00166    y(flags, rflags, last, steps, &res);     \
00167    mcSOLVERLOG(wxT("mcSolver::") wxT(#x)     \
00168      wxT(" - completed %d-th step [%s]"),   \
00169         cycles, mcTXT(last));    \
00170    cycles++;            \
00171   }               \
00172  }
00173 
00174 mcDEFINE_EXPSIM_STEP(math_DoSimplifyStep, math_Simplify)
00175 mcDEFINE_EXPSIM_STEP(math_DoExpandStep, math_Expand)
00176 mcDEFINE_EXPSIM_COMPLETE(math_DoCompleteSimplification, math_DoSimplifyStep)
00177 mcDEFINE_EXPSIM_COMPLETE(math_DoCompleteExpansion, math_DoExpandStep)
00178 /*
00179 mcSymbolProperties *mcSolver::math_GetUnknown(const mcMathOrSystem *sys, int n) const
00180 {
00181  mcSymbol sym;
00182 
00183  // cycle through registered unknowns and find the first
00184  // contained in this line...
00185  mcSymbolProperties *unk = NULL;
00186 /* for (int i=0; i < mcSymbol::arrUnknowns.data_GetCount(); i++) {
00187   unk = mcSymbol::arrUnknowns.GetSymbol(i);
00188   sym.hlp()->data_LinkWith(unk);
00189 
00190   if (m_pCurrLine->math_Find(0, sym, FALSE) != mcEmptyElement) {
00191 
00192    if (n == 0)
00193     break;  // this is the unknown we're searching
00194    n--;  // try with next
00195   }
00196 
00197   unk = NULL;  // reset the pointer
00198  }
00199 *
00200  return unk;
00201 }*/
00202 
00203 void mcSolver::data_Check() const
00204 {
00205  // name is like a unique identification string
00206  mcASSERT(!m_strName.IsEmpty(), wxT("Invalid name"));
00207 }
00208 
00209 bool mcSolver::math_PreSolve(const mcMathOrSystem &p, mcSystemStepArray &steps)
00210 {
00211  // make a first step identic to the given system
00212  steps.data_AddSys(new mcMathOrSystem(p));
00213 
00214  // decide the unknowns to use to solve each line
00215  for (int i=0; i < p.data_GetCount(); i++) {
00216   for (int k=0; k < p.data_GetSys(i).data_GetCount(); k++) {
00217    
00218    const mcMathLine &line = p.data_GetSys(i).data_GetLine(k);
00219    
00220    // scan the array of unknowns searching a valid one
00221    for (int j=0; j < mcSymbol::arrUnknowns.data_GetCount(); j++) {
00222     
00223     const mcSymbolProperties *sym = mcSymbol::arrUnknowns.data_GetSymbol(j);
00224     if (line.math_ContainsSymbol(sym)) {
00225      
00226      // we've found what we're searching for...
00227      m_pUnkArr[i] = sym;
00228 
00229      // and check again, it can be solved for *this* unknown
00230      if (math_WorksOn(p, sym))
00231       break;
00232     }
00233    }
00234    
00235    if (m_pUnkArr[i] == NULL) {
00236     
00237     // we did not find any unknown...
00238     m_strLastErr = wxString::Format(wxT("The %d-th line [%s] does not contain")
00239      wxT("any unknown... cannot proceed"), i, mcTXT(line));
00240     return FALSE;
00241    }
00242    
00243    mcMATHLOG(wxT("mcSolver::PreSolve - line %d will be solved for [%s]"), 
00244     i, mcTXTP(m_pUnkArr[i]));
00245   }
00246  }
00247 
00248  return TRUE;
00249 }
00250 
00251 bool mcSolver::math_PostSolve(const mcMathOrSystem &p, mcSystemStepArray &steps)
00252 {
00253  mcMATHLOG(wxT("mcSolver::math_PostSolve - the step array is [%s]"), mcTXT(steps));
00254 
00255  // remove identic steps
00256  int removed = steps.math_RemoveIdenticSteps();
00257  //removed += steps.data_RemoveSimpleSteps();
00258 #ifdef __MCDEBUG__
00259  mcMATHLOG(wxT("mcSolver::math_PostSolve - Removed %d useless steps."), removed);
00260 #else
00261  mcUNUSED(removed);
00262 #endif
00263 
00264  return TRUE;
00265 }
00266 
00267 bool mcSolver::math_Solve(const mcMathOrSystem &p, mcSystemStepArray &steps)
00268 {
00269  // Solve() will return FALSE only on errors or problems with the
00270  // given system (which is user-dependent); programming errors
00271  // will be catched instead with ASSERTs: call the Solve() function
00272  // before setting all the options of this solver is a programming error
00273  mcASSERT(math_isReady(), wxT("Cannot work yet"));
00274  mcASSERT(math_WorksOn(p), wxT("Invalid data for this type of solver"));
00275  mcMATHLOG(wxT("mcSolver::math_Solve - this solver is ready to work"));
00276 
00277  // ...while trying to solve a constant data is not
00278  if (p.math_isConstant()) {
00279   m_strLastErr = wxT("The entire expression is constant; nothing to solve");
00280   return FALSE;
00281  }
00282 
00283  if (!p.math_isValidMath()) {
00284   m_strLastErr = wxT("The expression contains invalid data");
00285   return FALSE;
00286  }
00287 
00288 
00289  // do any preparatory step...
00290  if (!math_PreSolve(p, steps))
00291   return FALSE;
00292 
00293  // do solve each line 
00294  mcMATHLOG(wxT("mcSolver::math_Solve - the step array has %d steps"), steps.data_GetCount()); 
00295  for (int i=0; i < p.data_GetCount(); i++) {
00296   for (int j=0; j < p.data_GetSys(i).data_GetCount(); j++) {
00297    
00298    mcMathLine tosolve(p.data_GetSys(i).data_GetLine(j));
00299    if (!math_SolveLine(tosolve, m_pUnkArr[i], steps))
00300     return FALSE;
00301   
00302    // remove simple steps
00303    steps.math_RemoveSimpleSteps();
00304    steps.data_Check();
00305 
00306    mcMATHLOG(wxT("mcSolver::math_Solve - the step array for the resolution ")
00307      wxT("of the %d-th line contains [%d] steps:\n%s"), i*j, 
00308      steps.data_GetCount(), mcTXT(steps));
00309   }
00310  }
00311 
00312  // and make last operations...
00313  return math_PostSolve(p, steps);
00314 }
00315 
00316 
00317 
00318 
00319 
00320 // ---------------
00321 // mcSOLVERARRAY
00322 // ---------------
00323 
00324 bool mcSolverArray::math_Add(mcSolver *solver)
00325 {
00326  if (math_Contains(solver))
00327   return FALSE;  // don't make duplicates
00328 
00329  // ok; we can add it
00330  mcAbstractArray::data_Add(solver);
00331  return TRUE;
00332 }
00333 
00334 wxArrayString mcSolverArray::io_GetDescArray() const
00335 {
00336  wxArrayString arr;
00337  for (int i=0; i < (int)data_GetCount(); i++)
00338   arr.Add(data_Get(i)->math_GetDesc());
00339  return arr;
00340 }
00341 
00342 void mcSolverArray::data_Check() const
00343 {
00344  mcAbstractArray::data_Check();
00345  for (int i=0; i < data_GetCount(); i++)
00346   data_Get(i)->data_Check();
00347 }
00348 
00349 bool mcSolverArray::math_Contains(const mcSolver *p) const
00350 {
00351  for (int i=0; i < data_GetCount(); i++)
00352   if (data_Get(i)->math_GetName() == p->math_GetName())
00353    return TRUE;
00354  return FALSE;
00355 }
00356 
00357 
00358 
00359 
00360 
00361 // --------------------
00362 // mcSYSTEMSTEPARRAY
00363 // --------------------
00364 /*
00365 void mcSystemStepArray::data_AddLine(const mcMathLine &p)
00366 {
00367  // create a new mcMathOrSystem() and add to it the given line
00368  mcMathOrSystem *s=new mcMathOrSystem();
00369  s->data_AddLineToLastAndSystem(new mcMathLine(p));
00370 
00371  // then, add the system to this array
00372  data_Add(s);
00373 }
00374 */
00375 void mcSystemStepArray::data_AddLine(const mcMathLine &p)
00376 {
00377  // see m_nFlags for more info
00378  if (m_nFlags & mcSYSTEMSTEPARR_DISCARD_SIMPLE) {
00379   data_AddLineOnlyIfComplexEnough(p);
00380   return;
00381  }
00382 
00383  mcMathOrSystem *s=new mcMathOrSystem();
00384  s->data_AddLineToLastAndSystem(new mcMathLine(p));
00385 
00386  // then, add the system to this array
00387  data_Add(s);
00388 }
00389 
00390 void mcSystemStepArray::data_AddKeyLine(const mcMathLine &p)
00391 {
00392  mcMathOrSystem *s=new mcMathOrSystem();
00393  s->data_AddLineToLastAndSystem(new mcMathLine(p));
00394 
00395  // then, add the system to this array
00396  data_Add(s);
00397 }
00398 
00399 void mcSystemStepArray::data_AddSys(mcMathOrSystem *pointer)
00400 {
00401  // see m_nFlags for more info
00402  if (m_nFlags & mcSYSTEMSTEPARR_DISCARD_SIMPLE) {
00403   data_AddSysOnlyIfComplexEnough(pointer);
00404   return;
00405  }
00406 
00407  mcAbstractArray::data_Add(pointer); 
00408 }
00409 
00410 void mcSystemStepArray::data_AddFinalSys(mcMathOrSystem *pointer)
00411 { mcAbstractArray::data_Add(pointer); }
00412 
00413 void mcSystemStepArray::data_AddLineOnlyIfComplexEnough(const mcMathLine &p)
00414 {
00415  mcMathOrSystem *s=new mcMathOrSystem();
00416  s->data_AddLineToLastAndSystem(new mcMathLine(p));
00417 
00418  // then, add the system to this array
00419  data_AddSysOnlyIfComplexEnough(s);
00420 }
00421 
00422 void mcSystemStepArray::data_AddSysOnlyIfComplexEnough(mcMathOrSystem *p)
00423 {
00424  if (data_GetCount() < 1) {
00425   mcAbstractArray::data_Add(p); 
00426   return;
00427  }
00428 
00429  int i=data_GetCount()-1;
00430  mcRealValue last = data_Get(i)->math_GetTotalLenght();
00431  mcRealValue diff = p->math_GetTotalLenght()-last;
00432 
00433  // add this step only if the difference of lenght is less than
00434  // the step threshold...
00435  if (diff > mcMathCore::Get()->GetStepThreshold())
00436   mcAbstractArray::data_Add(p);
00437  else
00438   delete p;  // discard it
00439 }
00440 
00441 int mcSystemStepArray::math_RemoveIdenticSteps()
00442 {
00443  int removed = 0;
00444 
00445  // discard checks on the first step
00446  for (int i=1; i < data_GetCount(); i++) {
00447 
00448   // use the math_Compare() function; hasSameContentOf should
00449   // always return TRUE...
00450   if (data_Get(i)->math_Compare(*data_Get(i-1), FALSE)) {
00451 
00452    // this step is exactly identic to the i-th step of the array
00453    // or it is the identic to the original system...
00454    // remove it and return a new pointer as new step
00455    data_RemoveAt(i);
00456    removed++;
00457 
00458    // check this entry again
00459    i--;
00460   }
00461  }
00462 
00463  return removed;
00464 }
00465 
00466 int mcSystemStepArray::math_RemoveSimpleSteps()
00467 {
00468  int removed = 0;
00469 
00470  if (data_GetCount() == 0) return 0;
00471  mcRealValue last = data_Get(0)->math_GetTotalLenght();
00472 
00473  // discard checks on the first & last step
00474  // (last step, even if very very simple must always be kept)
00475  for (int i=1; i < data_GetCount()-1; i++) {
00476   
00477   // check if the difference of lenght is great enough
00478   mcRealValue currlenght = data_Get(i)->math_GetTotalLenght();  // compute only once (slow)
00479   mcRealValue diff = currlenght-last;
00480 
00481   if (diff < mcMathCore::Get()->GetStepThreshold()) {
00482 
00483    // it's not: remove this step
00484    data_RemoveAt(i);
00485    removed++;
00486 
00487    // check this entry again
00488    i--;
00489 
00490   } else {
00491 
00492    last = currlenght;
00493   }
00494 
00495   data_Check();
00496  }
00497 
00498  return removed;
00499 }
00500 
00501 void mcSystemStepArray::data_Check() const
00502 {
00503  mcAbstractArray::data_Check();
00504  for (int i=0; i < data_GetCount(); i++)
00505   data_Get(i)->data_Check();
00506 }
00507 
00508 void mcSystemStepArray::data_Delete(int n)
00509 { 
00510  // this one cannot be placed in the header (since mcMathOrSystem must be defined)
00511  delete data_Get(n); 
00512 }
00513 
00514 wxString mcSystemStepArray::io_GetInlinedExpr() const
00515 {
00516  wxString res;
00517  
00518  for (int i=0; i < data_GetCount(); i++) {
00519 
00520   // just leave some space between a step and the next one...
00521   if (i>0) res+=wxT("    ");
00522   res += data_Get(i)->io_GetInlinedExpr();
00523  }
00524 
00525  return res;
00526 }
00527 
00528 void mcSystemStepArray::math_AppendCombinationOf(const mcSystemStepArray &arr1,
00529             const mcSystemStepArray &arr2,
00530             mcLogicOperator lo)
00531 {
00532  mcMATHLOG(wxT("mcSystemStepArray::math_AppendCombinationOf - merging\n\n%s\n\nwith\n\n%s"),
00533     mcTXT(arr1), mcTXT(arr2));
00534  int arr1idx=0, arr2idx=0;
00535 
00536  for (int i=0,max=mcMAX(arr1.data_GetCount(), arr2.data_GetCount()); i<max; i++) {
00537 
00538   // merge each step of the first array with the relative step of the
00539   // second array...
00540   mcMathOrSystem *toadd = new mcMathOrSystem();
00541   const mcMathOrSystem &first = *arr1.data_Get(arr1idx);
00542   const mcMathOrSystem &second = *arr2.data_Get(arr2idx);
00543 
00544   switch (lo) {
00545   case mcLO_AND:
00546    toadd->math_AndMerge(first, second);
00547    break;
00548 
00549   case mcLO_OR:
00550    toadd->math_OrMerge(first, second);
00551    break;
00552 
00553   default:
00554    mcASSERT(0, wxT("Unhandled logical operator"));
00555   }
00556 
00557   // then, add the result to this array
00558   data_Add(toadd);
00559 
00560   // now, advance array indexes
00561   arr1idx++;
00562   arr2idx++;
00563 
00564   // just check they do not exceed the array end... in this case, 
00565   // we must point the index of the array containing the lower
00566   // number of steps to its last step; in this way, the remaining
00567   // steps of the other array will be merged always with it:
00568   //
00569   // arr1:  A1, B1, C1, D1, E1, F1
00570   // arr2:  A1, B2, C2
00571   //
00572   // result of arr1+arr2:
00573   //            A1^A2, B1^B2, C1^C2, D1^C2, E1^C2, F1^C2
00574   //
00575   // where:
00576   // - the comma separes the various steps
00577   // - the wxT("^") symbol means "merged with"
00578   // 
00579   if (arr1idx >= arr1.data_GetCount()) arr1idx = arr1.data_GetCount()-1;
00580   if (arr2idx >= arr2.data_GetCount()) arr2idx = arr2.data_GetCount()-1;
00581  }
00582 }
00583 
00584 
00585 
00586 
00587 
00588 // --------------------
00589 // mcLINESTEPARRAY
00590 // --------------------
00591 /*
00592 void mcLineStepArray::data_Check() const
00593 {
00594  for (int i=0; i < data_GetCount(); i++)
00595   data_Get(i)->data_Check();
00596 }
00597 
00598 int mcLineStepArray::data_RemoveSimpleSteps()
00599 {
00600  int removed = 0;
00601 
00602  if (data_GetCount() == 0) return 0;
00603  mcRealValue last = data_Get(0)->math_GetTotalLenght();
00604 
00605  // discard checks on the first & last step
00606  // (last step, even if very very simple must always be kept)
00607  for (int i=1; i < data_GetCount()-1; i++) {
00608   
00609   // check if the difference of lenght is great enough
00610   mcRealValue currlenght = data_Get(i)->math_GetTotalLenght();  // compute only once (slow)
00611   mcRealValue diff = currlenght-last;
00612 
00613   if (diff < mcMathCore::Get()->GetStepThreshold()) {
00614 
00615    // it's not: remove this step
00616    data_RemoveAt(i);
00617    removed++;
00618 
00619    // check this entry again
00620    i--;
00621 
00622   } else {
00623 
00624    last = currlenght;
00625   }
00626  
00627   data_Check();
00628  }
00629 
00630  return removed;
00631 }
00632 */
00633 
00634 


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

[ Top ]