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
[ Top ] |