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 00034 // optimization for GCC compiler 00035 #ifdef __GNUG__ 00036 #pragma implementation "Monomial.h" 00037 #endif 00038 00039 // includes 00040 #include "mc/mcprec.h" 00041 #ifdef __BORLANDC__ 00042 #pragma hdrstop 00043 #endif 00044 00045 #ifndef mcPRECOMP 00046 #include "mc/MathUtils.h" 00047 #include "mc/Monomial.h" 00048 #include "mc/Number.h" 00049 #include "mc/Fraction.h" 00050 #include "mc/Bracket.h" 00051 #include "mc/Text.h" 00052 #include "mc/Symbol.h" 00053 #include "mc/AddSubOp.h" 00054 #include "mc/MultDivOp.h" 00055 #include "mc/Function.h" 00056 #include "mc/Radical.h" 00057 #endif 00058 00059 00060 mcIMPLEMENT_MAIN_CLASS(mcMonomial, mcElementArray); 00061 00062 00063 00064 // setup customizable variables 00065 int mcMonomialHelpers::sgui_nSpaceBetween = 1; 00066 00067 mcMonomial *mcMonomialHelpers::smath_pOne = NULL; 00068 mcMonomial *mcMonomialHelpers::smath_pZero = NULL; 00069 00070 bool mcMonomialHelpers::sgui_bEmptyBoxReplacing = TRUE; 00071 bool mcMonomialHelpers::sgui_bFunctionScanEnabled = TRUE; 00072 bool mcMonomialHelpers::sgui_bTransformDivInFractions = TRUE; 00073 bool mcMonomialHelpers::sio_bAutoConvertDivOpToFractions = TRUE; 00074 00075 00076 // global objects 00077 mcMonomial mcEmptyMonomial(NULL); 00078 00079 00080 00081 00082 // ---------------------------------------- 00083 // mcMONOMIAL 00084 // ---------------------------------------- 00085 00086 bool isMonomialOkay(const mcElement &p) 00087 { 00088 if (p.data_GetType() == mcET_POLYNOMIAL) 00089 return FALSE; 00090 return TRUE; 00091 } 00092 00093 mcMonomial::mcMonomial(const mcFraction &towrap) 00094 { data_SetRefData(new mcMonomialHelpers); data_AddElements(&towrap, 1); } 00095 mcMonomial::mcMonomial(const mcSymbol &towrap) 00096 { data_SetRefData(new mcMonomialHelpers); data_AddElements(&towrap, 1); } 00097 mcMonomial::mcMonomial(const mcNumber &towrap) 00098 { data_SetRefData(new mcMonomialHelpers); data_AddElements(&towrap, 1); } 00099 mcMonomial::mcMonomial(const mcBracket &towrap) 00100 { data_SetRefData(new mcMonomialHelpers); data_AddElements(&towrap, 1); } 00101 mcMonomial::mcMonomial(const mcRadical &towrap) 00102 { data_SetRefData(new mcMonomialHelpers); data_AddElements(&towrap, 1); } 00103 00104 00105 00106 00107 // ---------------------------------------- 00108 // mcMONOMIALDATA 00109 // ---------------------------------------- 00110 00111 #ifdef __MCDEBUG__ 00112 00113 void mcMonomialHelpers::data_Check() const 00114 { 00115 // this MUST be true... it's an important prerequisite of math functions 00116 mcASSERT(data_GetCount() == 0 || (!data_isOp(0) && !data_isOp(data_GetCount()-1)), 00117 wxT("The expression must always start and end with a non-operator element")); 00118 00119 // be also sure that this array doesn't contain mcPolynomials as subelements 00120 mcASSERT(data_ScanArray(isMonomialOkay, TRUE), 00121 wxT("Found a mcPolynomial nested in a mcMonomial")); 00122 00123 // do basic checks 00124 mcElementArrayHelpers::data_Check(); 00125 } 00126 00127 #endif // __MCDEBUG__ 00128 00129 void mcMonomialHelpers::data_Repair() 00130 { 00131 if (data_isArrayEmpty()) 00132 return; 00133 00134 // data_Delete the operators placed immediately at the beginning... 00135 if (data_isOp(0)) { 00136 data_Delete(0); 00137 data_MoveElemLeft(0); 00138 } 00139 00140 // ...or at the end 00141 if (data_isOp(data_GetCount()-1)) 00142 data_DeleteLast(1); 00143 00144 // add/remove mcMultOp when required 00145 for (int i=0; i < data_GetCount(); i++) { 00146 00147 if (i < data_GetCount()-1 && 00148 !data_Get(i).data_isAllowedBefore(data_Get(i+1).data_GetType())) { 00149 00150 if (data_isOp(i)) { 00151 00152 // two operators are adiacent: 432**43 00153 // data_Delete the first one 00154 data_Delete(i); 00155 data_MoveElemLeft(i); 00156 00157 // and recheck this entry 00158 i--; 00159 00160 } else { 00161 00162 // two elements which cannot coexist in adiacent positions 00163 // must be divided: 123 456 must become 123*456 00164 // separate these two elements adding a mcMultOp 00165 data_MoveElemRight(i+1); 00166 data_AddNewOp(mcET_MULTOP, i+1); 00167 } 00168 } 00169 00170 if (i > 0 && 00171 !data_Get(i).data_isAllowedAfter(data_Get(i-1).data_GetType())) { 00172 00173 // two elements which cannot be one after the other: 00174 // (...)123 should become (...)*123 00175 // this kind of reparation is usually unnecessary 00176 // if Reorder() is executed before. 00177 data_MoveElemRight(i); 00178 data_AddNewOp(mcET_MULTOP, i); 00179 } 00180 } 00181 00182 // now, check if we made a good work... 00183 data_Check(); 00184 } 00185 00186 void mcMonomialHelpers::data_TransformDivOp() 00187 { 00188 mcLOG(wxT("mcMonomialHelpers::data_TransformDivOp [%s]"), mcTXTTHIS); 00189 00190 // begin the array scan 00191 int begin = -1; 00192 for (int i=0; i < data_GetCount(); i++) { 00193 00194 if (!data_isOp(i) && begin == -1) 00195 begin = i; 00196 if (data_Get(i).data_GetType() != mcET_DIVOP) 00197 continue; 00198 00199 // we've found a mcDivOp 00200 mcFraction f; 00201 mcPolynomial &num = f.data_GetNum(); 00202 mcPolynomial &den = f.data_GetDen(); 00203 00204 // all the elements preceding it have been placed in "num" 00205 num.data_AddNewMonomialContaining(data_GetArray(begin), i-begin, -1, TRUE); 00206 00207 // if we have a sequence like: 00208 // abc 00209 // abc/d/e/f/g/h it should become: ------- 00210 // defgh 00211 // 00212 // so, just count how many mcDivOp are immediately 00213 // following the i-th one 00214 int end = i+1; 00215 int j = i+1; 00216 while (j < data_GetCount()) { 00217 00218 if (data_Get(j).data_GetType() == mcET_MULTOP) { 00219 00220 // we have reached a point like 00221 // i j 00222 // abcd/d/e*f 00223 // ^---------- this 00224 end = j-1; 00225 break; 00226 00227 } else if (data_Get(j).data_GetType() != mcET_DIVOP) { 00228 00229 if (!data_isOp(j-1)) { 00230 end = j-1; 00231 break; 00232 } 00233 } 00234 00235 // go on scanning 00236 j++; 00237 } 00238 00239 // create tmp objects 00240 mcMonomial tmp; 00241 00242 // ok, now create the "den" polynomial 00243 for (j=i+1; j <= end; j++) { 00244 00245 // in the monomial which will be used as denominator, 00246 // don't copy the mcDivOps !!! 00247 if (!data_isOp(j)) 00248 tmp.data_AddElements(data_GetArray(j), 1); 00249 } 00250 00251 den.data_AddNewMonomial(tmp, -1, TRUE); 00252 00253 // finally, we can complete our process replacing all the 00254 // elements embedded in wxT("f") with "f" itself 00255 for (j=begin; j < end; j++) { 00256 data_Delete(begin); 00257 data_MoveElemLeft(begin); 00258 } 00259 00260 data_AddElements((mcElement *)(&f), 1, begin, TRUE); 00261 00262 // prepare everything for a new cycle 00263 i = begin++; 00264 begin = -1; 00265 tmp.data_DeleteAll(); 00266 00267 mcLOG(wxT("mcMonomialHelpers::data_TransformDivOp [%s]"), mcTXTTHIS); 00268 } 00269 } 00270 00271 00272 00273 00274 // ---------------------------------------- 00275 // mcMONOMIALGUI 00276 // ---------------------------------------- 00277 00278 int mcMonomialHelpers::gui_Draw(wxDC &dc, int x, int y, long flags, const wxPoint &pt, int cl) const 00279 { 00280 mcGUILOG(wxT("mcMonomialHelpers::gui_Draw")); 00281 00282 // if a selection is present in the monomial.... 00283 if (this->gui_isSelected()) { 00284 00285 // ... and the selection is limited to this 00286 // monomial (that is, it's not extended to other monomials, it's just 00287 // inside this one and thus our parent gave us the mcDRW_ALLOW_TOTAL_SELECTION) 00288 // flag), then draw everything + selection rectangle 00289 int w, n; 00290 if (flags & mcDRW_ALLOW_TOTAL_SELECTION) { 00291 00292 // draw everything except selected elements 00293 n = mcElementArrayHelpers::gui_ExDraw(dc, x, y, flags, pt, cl); 00294 00295 // the parent is a mcPolynomial and this is the only selected monomial 00296 // contained inside it... we can draw selection ourself 00297 if ((w=gui_DrawSelection(dc, x, y, flags, pt, cl)) != mcDRW_NOACTIVEELEM) 00298 n = w; 00299 00300 return n; 00301 } 00302 } 00303 00304 // ... maybe that: 00305 // 1) selection is not present and thus everything must be drawn 00306 // 2) an "extended" selection (a selection among two or more monomials) is 00307 // present and, anyway, everything must be drawn (also selected elements): 00308 // parent will care about selection rectangle... 00309 return mcElementArrayHelpers::gui_ExDraw(dc, x, y, flags, pt, cl, 0, -1, TRUE); 00310 } 00311 00312 void mcMonomialHelpers::gui_CheckCursorPos() const 00313 { 00314 if (data_GetCount() > 0) { 00315 00316 // if the array exists, the cursor cannot be placed over an operator 00317 mcASSERT(!data_isOp(mgui_nCursorPos), wxT("Cursor cannot be placed on an operator")); 00318 } 00319 } 00320 00321 int mcMonomialHelpers::gui_AddNewElement(mcElementType type, const mcKey &key, int pos) 00322 { 00323 if (pos == -1) pos = data_GetCount(); 00324 00325 // add the requested element 00326 int idx = mcElementArrayHelpers::gui_AddNewElement(type, key, pos); 00327 00328 // check if we must also add a new empty box 00329 if (mcOperatorHelpers::data_isOp(type)) { 00330 if (pos == data_GetCount()-1 || data_isOp(pos+1)) { 00331 00332 // ok, we are at the end of the array and an operator was 00333 // added (or an operator was added immediately before another 00334 // operator): we must add an empty box 00335 data_MoveElemRight(pos+1); 00336 mcElementArrayHelpers::gui_AddNewEmptyBox(pos+1); 00337 00338 } else if (pos > 0 && data_isOp(pos-1)) { 00339 00340 // an operator was added immediately after another operator: 00341 // insert an empty box between them 00342 data_MoveElemRight(pos); 00343 mcElementArrayHelpers::gui_AddNewEmptyBox(pos); 00344 } 00345 pos++; 00346 } 00347 00348 // now that the array is okay, do a special check for mcDivOps... 00349 if (sgui_bTransformDivInFractions && type == mcET_DIVOP) { 00350 00351 // we must create a mcFraction containing 00352 // the factors placed on the left of this op as numerator, 00353 // the factors on the right as denominator... 00354 mcFraction p; 00355 00356 // this is the index of this operator inside the monomial 00357 // which owns this element... 00358 //int idx = pos;//data_GetIndex(hlp()->data_GetID()); 00359 00360 // copy in the numerator elements from zero to this op... 00361 mcMonomial num(this); 00362 num.data_DeleteLast(num.data_GetCount()-idx); 00363 p.data_AddElements(TRUE, &num, 1, -1, TRUE); 00364 p.data_GetNum().data_Check(); 00365 00366 // copy in the denominator elements from this op to the end... 00367 mcMonomial den(this); 00368 den.data_DeleteFirst(idx+1); 00369 p.data_AddElements(FALSE, &den, 1, -1, TRUE); 00370 p.gui_SetCursorOnDen(); 00371 p.data_GetDen().data_Check(); 00372 00373 // now, remove everything from this array and replace all with this fraction... 00374 data_DeleteAll(); 00375 data_AddElements(&p, 1, -1, TRUE); 00376 data_Check(); 00377 00378 pos = 0; 00379 } 00380 00381 // size should have changed !!! 00382 gui_RecalcSize(); 00383 return pos; 00384 } 00385 00386 mcInputRes mcMonomialHelpers::gui_BackInput(const mcKey &key, mcElement *pnewelem, int n) 00387 { 00388 int rightidx; 00389 bool b1, b2; 00390 00391 // the focused element asked us to data_Delete itself 00392 switch (n) { 00393 case mcIR_OKAY: 00394 break; 00395 00396 case mcIR_DIRECT_DELETE: 00397 00398 // an empty box asked us to data_Delete it... is it the only element 00399 // in the array ??? 00400 if (data_GetCount() == 1) { 00401 00402 // we don't need to check the bEmptyBoxReplacing value 00403 // (see the mcIR_DELETE_THIS handler): we must data_Delete 00404 // this array in any case. 00405 return mcIR_DELETE_THIS; 00406 } 00407 00408 // the empty box is not the last element of the array: proceed 00409 // as it is a normal element: DON'T BREAK HERE 00410 00411 case mcIR_DELETE_THIS: 00412 00413 // data_Delete the focused element 00414 data_Delete(mgui_nCursorPos); 00415 00416 // if the array is now empty, the mdata_nElements variable is set 00417 // to one: we have data_Deleted the focused element but we don't 00418 // have shifted left the array yet !!! 00419 // And it MUST be so, because the following piece of code 00420 // needs the array not shifted yet. 00421 if (data_GetCount() == 1) { 00422 00423 if (sgui_bEmptyBoxReplacing) { 00424 00425 // the element that we data_Deleted surely was not a mcEmptyBox 00426 // (they return mcIR_DIRECT_DELETE as data_Delete flag): it must 00427 // be another element type; if the EMPTY BOX REPLACING 00428 // feature is active, we must replace it with an empty box. 00429 data_AddNewEmptyBox(0); 00430 return mcIR_OKAY; 00431 00432 } else { 00433 00434 // the element that we data_Deleted was not an mcEmptyBox, but 00435 // we must ask to data_Delete us in any case.... 00436 return mcIR_DELETE_THIS; 00437 } 00438 } 00439 00440 // if bEmptyBoxReplacing is set, then try to replace 00441 // the old element with an empty box 00442 if (sgui_bEmptyBoxReplacing && n != mcIR_DIRECT_DELETE) { 00443 00444 // if the element is following/preceding an operator... 00445 b1 = (mgui_nCursorPos > 0 && data_isOp(mgui_nCursorPos-1)); 00446 b2 = (mgui_nCursorPos < data_GetCount()-1 && 00447 data_isOp(mgui_nCursorPos+1)); 00448 00449 // ... or it is at the end/begin of the array... 00450 b1 |= (mgui_nCursorPos == 0); 00451 b2 |= (mgui_nCursorPos == data_GetCount()-1); 00452 00453 if (b1 && b2) { 00454 00455 // ...then, create a replacement empty box 00456 data_AddNewEmptyBox(mgui_nCursorPos); 00457 return mcIR_OKAY; 00458 } 00459 } 00460 00461 // to avoid to leave operators scattered, we must perform different 00462 // checks for different keypresses: 00463 if (mcMathCore::Get()->m_pCancelKey->MatchKey(key)) { 00464 00465 // handle the following case: 00466 // |a*bc user presses CANCEL 00467 // 00468 // in this case we need to data_Delete also 00469 // the FOLLOWING operator (if present) !!! 00470 gui_DeleteNextOp(); 00471 00472 // handle the following case: 00473 // ab*|c user presses CANCEL 00474 // 00475 // in this case we need to data_Delete also 00476 // the PREVIOUS operator (if present) !!! 00477 gui_DeletePreviousOp(); 00478 00479 } else if (mcMathCore::Get()->m_pDeleteKey->MatchKey(key)) { 00480 00481 // handle the following case: 00482 // a|*b user presses BACKSPACE 00483 // 00484 // in this case we need to data_Delete also 00485 // the FOLLOWING operator (if present) !!! 00486 gui_DeleteNextOp(); 00487 00488 // handle the following case: 00489 // a*b|c user presses BACKSPACE 00490 // 00491 // in this case we need to data_Delete also 00492 // the PREVIOUS operator (if present) !!! 00493 gui_DeletePreviousOp(); 00494 } 00495 00496 // this shift must be done AFTER the previous operations 00497 // (which addresses the array)... 00498 data_MoveElemLeft(mgui_nCursorPos); 00499 00500 // there must be still some element present in the monomial (we checked 00501 // for empty array before) and, in this case, we must be aware that 00502 // when the cursor is placed on the first element, it must remain 00503 // placed on it. 00504 if (mgui_nCursorPos > 0) { 00505 00506 mgui_nCursorPos--; 00507 if (mcMathCore::Get()->m_pCancelKey->MatchKey(key)) 00508 data_Get(mgui_nCursorPos).gui_SetCursorPos(mcCP_BEGIN); 00509 else if (mcMathCore::Get()->m_pDeleteKey->MatchKey(key)) 00510 data_Get(mgui_nCursorPos).gui_SetCursorPos(mcCP_END); 00511 00512 } else { 00513 00514 // this is required if the user, for example, types: 00515 // [A][B][C][D] -. abcd| 00516 // [HOME] -. |abcd 00517 // [CANC] -. |bcd 00518 // if this is not done, then last line becomes: 00519 // [CANC] -. b|cd 00520 gui_SetCursorPos(mcCP_BEGIN); 00521 } 00522 00523 // maybe we need to merge the two elements that are now adiacent ? 00524 rightidx = mgui_nCursorPos+1; // both for BACKSPACE & CANCEL 00525 00526 // a typical example of this case is: 00527 // 00528 // 123a|456 user presses the BACKSPACE 00529 // or 00530 // 123|a456 user presses the CANCEL 00531 // 00532 if (rightidx > 0 && rightidx < data_GetCount()) { 00533 00534 // the left element's index is assumed to be rightidx-1 00535 bool b = FALSE; 00536 if (!data_Get(rightidx-1).data_isAllowedBefore( 00537 data_Get(rightidx).data_GetType())) { 00538 00539 // the two elements cannot be adiacent: merge them !!!! 00540 b = data_Get(rightidx-1).gui_MergeWith(data_Get(rightidx)); 00541 if (b) { 00542 00543 // the two elements was merged successfully: data_Delete 00544 // the second half.... 00545 data_MoveElemLeft(rightidx); 00546 00547 // cursor position should be already in the right position... 00548 } 00549 } 00550 00551 // if the two elements cannot be merged, add a mcMultOp 00552 // between them.... 00553 if (!b) { 00554 00555 data_Repair(); // hope this will solve everything 00556 } 00557 } 00558 00559 // we have finished (finally)... 00560 break; 00561 00562 00563 case mcIR_DELETE_PREVIOUS: 00564 00565 // the focused element asked us to data_Delete the previous one 00566 if (mgui_nCursorPos == 0) { 00567 00568 // user is trying to data_Delete the previous operator of this monomial... 00569 // we must merge this monomial with the previous one. 00570 mcASSERT(data_GetCount() > 0, wxT("If we received an mcIR_data_Delete_PREVIOUS code, ") 00571 wxT("there must still be some element which sent it !!!")); 00572 00573 // the parent element (normally a mcPolynomial) will care about 00574 // the fusion of the two monomials 00575 return mcIR_DELETE_PREVIOUS; 00576 00577 } else { 00578 00579 if (!data_isOp(mgui_nCursorPos-1)) { 00580 00581 // this trick should work 00582 gui_MoveCursorLeft(); 00583 mcKey tmp = mcMathCore::Get()->m_pDeleteKey->GetEvent(); 00584 gui_Input(tmp, NULL); 00585 00586 } else { 00587 00588 if (mgui_nCursorPos > 1 && 00589 !data_Get(mgui_nCursorPos-2).data_isAllowedBefore( 00590 data_Get(mgui_nCursorPos).data_GetType())) { 00591 00592 // oooooooooops 00593 mcMathCore::Get()->SyntaxError(wxT("Cannot data_Delete this operator...")); 00594 break; 00595 } 00596 00597 // the previous element is a mcMultOp or a mcDivOp... data_Delete it 00598 data_Delete(mgui_nCursorPos-1); 00599 data_MoveElemLeft(mgui_nCursorPos-1); 00600 00601 // try to move the cursor 00602 if (mgui_nCursorPos > 1) 00603 mgui_nCursorPos -= 2; 00604 else 00605 mgui_nCursorPos--; 00606 00607 // this will add mcMultOp that we could accidentally have data_Deleted 00608 data_Repair(); 00609 } 00610 } 00611 break; 00612 00613 00614 case mcIR_DELETE_NEXT: 00615 00616 // the focused element asked us to data_Delete the next one 00617 if (mgui_nCursorPos == data_GetCount()-1) { 00618 00619 // user is trying to data_Delete the previous operator of this monomial... 00620 // we must merge this monomial with the previous one. 00621 mcASSERT(data_GetCount() > 0, wxT("If we received an mcIR_data_Delete_NEXT code, ") 00622 wxT("there must still be some element which sent it !!!")); 00623 00624 // the parent element (normally a mcPolynomial) will care about 00625 // the fusion of the two monomials 00626 return mcIR_DELETE_NEXT; 00627 00628 } else { 00629 00630 if (!data_isOp(mgui_nCursorPos+1)) { 00631 00632 gui_MoveCursorRight(); 00633 mcKey tmp = mcMathCore::Get()->m_pCancelKey->GetEvent(); 00634 gui_Input(tmp, NULL); 00635 00636 // we don't want to move cursor 00637 gui_MoveCursorLeft(); 00638 00639 } else { 00640 00641 if (mgui_nCursorPos < data_GetCount()-2 && 00642 !data_Get(mgui_nCursorPos).data_isAllowedBefore( 00643 data_Get(mgui_nCursorPos+2).data_GetType())) { 00644 00645 // oooooooooops 00646 mcMathCore::Get()->SyntaxError(wxT("Cannot data_Delete this operator...")); 00647 break; 00648 } 00649 00650 // the next element is a mcMultOp or a mcDivOp... data_Delete it 00651 data_Delete(mgui_nCursorPos+1); 00652 data_MoveElemLeft(mgui_nCursorPos+1); 00653 00654 // this will add mcMultOp that we could accidentally have data_Deleted 00655 data_Repair(); 00656 00657 // we don't need to move cursor 00658 } 00659 } 00660 break; 00661 00662 00663 case mcIR_REPLACE_THIS: 00664 gui_Replace(pnewelem); 00665 break; 00666 00667 case mcIR_DISTRIBUTE: 00668 00669 // we cannot handle this flag but mcPolynomial can... 00670 return mcIR_DISTRIBUTE; 00671 00672 default: 00673 mcASSERT(0, wxT("Unhandled return flag")); 00674 } 00675 00676 // just hope that everything has gone well... 00677 return mcIR_OKAY; 00678 } 00679 00680 void mcMonomialHelpers::gui_DoSplit(mcElementType type, const mcKey &key) 00681 { 00682 mcElement ptmp = mcEmptyElement; 00683 mcKey splitkey(key); 00684 00685 // split the element in two parts; by now, this function 00686 // can be used only by mcNumbers & mcMonomials... 00687 // thus, this function has been tested only with mcNumber; 00688 // that is, in such situations: 00689 // 00690 // aaaaaaaaa | 543|210 | bbbbbbbbb user creates an operator 00691 // mgui_nCursorPos-1 | mgui_nCursorPos | mgui_nCursorPos+1 or something else... 00692 // 00693 // which is transformed in: 00694 // 00695 // aaaaaaaaa | 543 | new element | 210 | bbbbbbbbb 00696 // mgui_nCursorPos-1 | mgui_nCursorPos | mgui_nCursorPos+1 | mgui_nCursorPos+2 | mgui_nCursorPos+3 00697 // 00698 mcASSERT(!data_Get(mgui_nCursorPos).gui_Split(&ptmp), 00699 wxT("Such case (the first half asked to data_Delete itself) is not handled yet")); 00700 00701 // go on only if the element to split support that function 00702 mcASSERT(ptmp != mcEmptyElement, wxT("Tried to split an element which does not support splitting")); 00703 00704 // create an hole in the array 00705 data_MoveElemRight(mgui_nCursorPos+1); 00706 data_Set(mgui_nCursorPos+1, ptmp); 00707 00708 // create another hole 00709 data_MoveElemRight(mgui_nCursorPos+1); 00710 00711 // and fill it with the splitting element: the element wich has been 00712 // created inside the element which is now split... 00713 mgui_nCursorPos = gui_AddNewElement(type, key, mgui_nCursorPos+1); 00714 } 00715 00716 bool mcMonomialHelpers::gui_Split(mcElement *p) 00717 { 00718 // the user pressed an end char while the cursor is still inside 00719 // the digits... this element must be split in two parts divided 00720 // by the operator or the element typed in. The first one will be 00721 // stored here, in this number, the second half, instead, must be 00722 // returned as a pointer to a new element 00723 mcMonomial pnew; 00724 00725 // try to split the focused element 00726 mcElement ptmp; 00727 bool b = data_Get(mgui_nCursorPos).gui_Split(&ptmp); 00728 00729 // if the element request us to data_Delete it, do it... 00730 if (b) { 00731 data_Delete(mgui_nCursorPos); 00732 data_MoveElemLeft(mgui_nCursorPos); 00733 } 00734 00735 // copy the elements placed after the cursor in the new monomial 00736 if (ptmp != mcEmptyElement) 00737 pnew.data_AddElements(&ptmp, 1); 00738 00739 if (mgui_nCursorPos < data_GetCount()-1) { 00740 00741 // insert them in the new monomial 00742 pnew.data_AddElements(data_GetArray(mgui_nCursorPos+1), 00743 data_GetCount()-mgui_nCursorPos-1); 00744 00745 // detach them from this one 00746 data_DetachLastElem(data_GetCount()-mgui_nCursorPos-1); 00747 } 00748 00749 // add & remove eventually required/not needed operators 00750 data_Repair(); 00751 pnew.data_Repair(); 00752 00753 // adjust cursor position 00754 this->mgui_nCursorPos = data_GetCount()-1; 00755 data_Get(mgui_nCursorPos).gui_SetCursorPos(mcCP_END); 00756 00757 pnew.hlp()->mgui_nCursorPos = 0; 00758 pnew.data_Get(pnew.hlp()->mgui_nCursorPos).gui_SetCursorPos(mcCP_BEGIN); 00759 00760 // size should have changed 00761 gui_RecalcSize(); 00762 *p = pnew; 00763 00764 return TRUE; 00765 } 00766 00767 bool mcMonomialHelpers::gui_MergeWith(const mcElement &p) 00768 { 00769 if (p.data_GetType() != mcET_MONOMIAL) 00770 return FALSE; 00771 00772 mcMonomial m(p); 00773 00774 // check if the end & begin elements support splitting/merging 00775 if (data_GetLast().gui_isSplittable() && 00776 m.data_Get(0).gui_isSplittable() && 00777 data_GetLast().data_isAllowedBefore( 00778 m.data_GetLast().data_GetType())) { 00779 00780 // then, we must merge the two elements 00781 bool okay = data_GetLast().gui_MergeWith(m.data_Get(0)); 00782 00783 if (okay) { 00784 00785 // and data_Delete the second half from the given element 00786 m.data_Delete(0); 00787 m.data_MoveElemLeft(0); 00788 if (!m.data_isArrayEmpty() && m.data_isOp(0)) { 00789 m.data_Delete(0); 00790 m.data_MoveElemLeft(0); 00791 } 00792 } 00793 } 00794 00795 // now, merge with the given element & check if all the operators 00796 // required for array consistency are present 00797 data_Merge(m); 00798 data_Repair(); 00799 00800 // size should have changed 00801 gui_RecalcSize(); 00802 00803 // merge was okay... 00804 return TRUE; 00805 } 00806 00807 mcInputRes mcMonomialHelpers::gui_Input(const mcKey &ev, mcElement *newelem) 00808 { 00809 mcInputRes n = mcElementArrayHelpers::gui_Input(ev, newelem); 00810 00811 // if the 'function scan' feature is active, try to recognize 00812 // registered functions inside the current mcSymbol sequences... 00813 if (sgui_bFunctionScanEnabled) 00814 gui_ScanArrayForFunctions(); 00815 00816 return n; 00817 } 00818 00819 void mcMonomialHelpers::gui_ScanArrayForFunctions() 00820 { 00821 // SPECIAL CODE FOR CFUNCTION 00822 // check if in the array is present a sequence of mcSymbols which hides a function... 00823 int f, i; 00824 for (int n=0; n < data_GetCount(); n++) { 00825 if (data_Get(n).data_GetType() == mcET_SYMBOL) { 00826 00827 // check how long is the sequence of mcSymbols... 00828 for (i=n; i < data_GetCount(); i++) 00829 if (data_Get(i).data_GetType() != mcET_SYMBOL) 00830 break; 00831 00832 // if the aray of mcSymbols compose the name of a registered 00833 // function, then replace those mcSymbols with a mcFunction... 00834 f=mcFunction::data_GetFunctionType(data_GetArray(n), i-n); 00835 if (f != mcFUNCTION_TYPE_NOTFOUND) 00836 gui_ReplaceSymbolsWithFunction(n, f); 00837 } 00838 } 00839 } 00840 00841 void mcMonomialHelpers::gui_ReplaceSymbolsWithFunction(int idx, int fnc) 00842 { 00843 // found a function inside this list of mcSymbols; 00844 // replace the symbols with the function... 00845 mcFunction pnew; 00846 data_AddElements((mcElement *)(&pnew), 1, idx, TRUE); 00847 00848 // special initialization is required... 00849 pnew.gui_Setup(fnc); 00850 mgui_nCursorPos = idx++; 00851 00852 // delete the other mcSymbols 00853 int max = (int)(pnew.data_GetName().Len()-1); 00854 for (int i=0; i < max; i++) { 00855 data_Delete(idx); 00856 data_MoveElemLeft(idx); 00857 } 00858 00859 gui_RecalcSize(); 00860 } 00861 00862 void mcMonomialHelpers::gui_Replace(mcElement *pnewelem) 00863 { 00864 // the focused element asked us to replace itself with 'pnewelem' 00865 // a quick check 00866 mcASSERT(pnewelem != NULL && data_isValidElem(*pnewelem), 00867 wxT("Cannot replace the focused element with an invalid pointer")); 00868 00869 // check filter permissions 00870 if (!data_isElementAllowed((*pnewelem).data_GetType())) { 00871 00872 // sorry... 00873 mcMathCore::Get()->SyntaxError(wxT("Cannot create such an element !!!")); 00874 //break; 00875 } 00876 00877 // these cannot be created even if the filter allow us !!! 00878 if ((*pnewelem).data_GetType() == mcET_ADDOP || 00879 (*pnewelem).data_GetType() == mcET_SUBOP) { 00880 00881 mcASSERT(0, wxT("A monomial cannot contain a mcAddOp or a mcSubOp")); 00882 } 00883 00884 // for operators, we need special checks !!! 00885 if ((*pnewelem).data_GetType() == mcET_MULTOP || 00886 (*pnewelem).data_GetType() == mcET_DIVOP) { 00887 00888 // tested only if the element wh 00889 data_AddNewEmptyBox(mgui_nCursorPos); 00890 data_AddElements(pnewelem, 1, mgui_nCursorPos+1, TRUE); 00891 data_AddNewEmptyBox(mgui_nCursorPos+2); 00892 mgui_nCursorPos += 2; 00893 00894 } else { 00895 00896 // insert the given element, without copying it, overwriting the previous one 00897 data_AddElements(pnewelem, 1, mgui_nCursorPos, TRUE); 00898 (*pnewelem) = NULL; 00899 } 00900 } 00901 00902 mcInsertRes mcMonomialHelpers::gui_Insert(const mcElement &toinsert, mcElement *) 00903 { 00904 mcCursorPos cp(data_Get(mgui_nCursorPos).gui_GetCursorPos()); 00905 mcElement replacement; 00906 00907 // if (cp.isInside()) { 00908 00909 mcInsertRes r = data_Get(mgui_nCursorPos).gui_Insert(toinsert, &replacement); 00910 00911 switch (r) { 00912 case mcINSR_OKAY: 00913 return mcINSR_OKAY; 00914 00915 case mcINSR_REPLACE_THIS: 00916 gui_Replace(&replacement); 00917 break; 00918 } 00919 // } 00920 00921 return mcINSR_OKAY; 00922 /* switch (toinsert.data_GetType()) { 00923 case mcET_POLYNOMIAL: 00924 case mcET_MATHMNG: 00925 case mcET_MATHANDSYSTEM: 00926 case mcET_MATHORSYSTEM: 00927 return FALSE; 00928 00929 case mcET_MONOMIAL: 00930 return gui_Insert((const mcMonomial &)toinsert); 00931 00932 default: 00933 { 00934 mcMonomial mon; 00935 mon.data_AddElements(&toinsert, 1); 00936 return gui_Insert((const mcMonomial &)mon); 00937 } 00938 }*/ 00939 } 00940 00941 mcInsertRes mcMonomialHelpers::gui_Insert(const mcElement *arr, int n) 00942 { 00943 /* mcCursorPos cp(data_Get(mgui_nCursorPos).gui_GetCursorPos()); 00944 00945 if (cp.isBegin() || cp.isEnd()) { 00946 00947 data_AddElements(toinsert.data_GetArray(), 00948 toinsert.data_GetCount(), 00949 mgui_nCursorPos, FALSE); 00950 data_Repair(); 00951 00952 return TRUE; 00953 } 00954 00955 if (cp.isInside()) { 00956 00957 return data_Get(mgui_nCursorPos).gui_Insert(toinsert); 00958 } 00959 */ 00960 return mcINSR_OKAY; 00961 } 00962 00963 00964 00965 00966 00967 00968 // ---------------------------------------- 00969 // mcMONOMIALIO 00970 // ---------------------------------------- 00971 00972 wxXml2Node mcMonomialHelpers::io_GetMathML(bool bGetPresentation) const 00973 { 00974 if (data_GetCount() == 1) {// && data_Get(0)->data_hasProperty(mcEP_HIDDEN)) { 00975 // just return the presentation MathML associated with the first children 00976 return data_Get(0).io_GetMathML(bGetPresentation); 00977 } 00978 00979 // begin another mrow section 00980 wxXml2Node maintag(wxXML_ELEMENT_NODE, wxXml2EmptyDoc, wxT("mrow")); 00981 00982 // skip first op: it should have been exported by the mcPolynomial 00983 for (int i=0, max=data_GetCount(); i < max; i++) { 00984 00985 // adds the i-th element's MathML to the main container 00986 wxXml2Node tmp(data_Get(i).io_GetMathML(bGetPresentation)); 00987 maintag.AddChild(tmp); 00988 00989 // if there is no operator following this element, then we must 00990 // add a mcMultOp (which is the operator used by default in a monomial) 00991 if (i < max-1 && !data_isOp(i) && !data_isOp(i+1)) { 00992 00993 wxXml2Node mult(wxXML_TEXT_NODE, wxXml2EmptyDoc, wxT("mo"), wxT("⁢")); 00994 maintag.AddChild(mult); 00995 } 00996 } 00997 00998 return maintag; 00999 } 01000 01001 bool mcMonomialHelpers::io_ImportPresentationMathML(wxXml2Node tag, wxString &err) 01002 { 01003 mcASSERT(tag.GetName() == wxT("mrow") || 01004 tag.GetName() == wxT("mo"), wxT("Error in mcMonomialHelpers::io_isBeginTag")); 01005 01006 wxXml2Node p = tag.GetChildren(); 01007 mcElementType n; 01008 01009 // BE SURE TO data_Delete EVERYTHING BEFORE IMPORTING !!!! 01010 data_DeleteAll(); 01011 01012 // check if the given node is an MROW containing as first child an MO 01013 // (which must be a + or -) or if this is directly an MO (a + or -) sent 01014 // to this monomial as "initialization" node by a mcPolynomial. 01015 if (tag.GetName() == wxT("mo") || (tag.GetName() == wxT("mrow") && p.GetName() == wxT("mo"))) { 01016 01017 // check data 01018 wxXml2Node mo = (tag.GetName() == wxT("mo")) ? tag : p; 01019 n = mcElementHelpers::io_isTagBeginTag(mo); 01020 mcASSERT(n == mcET_ADDOP || n == mcET_SUBOP, 01021 wxT("The given node should be, or contain (as first child), a + or -")); 01022 01023 // init this monomial with this operator 01024 data_DeleteAll(); 01025 mcElement pnew = mcElementHelpers::data_NewElem(n); 01026 if (!pnew.io_ImportPresentationMathML(mo, err)) 01027 return FALSE; 01028 data_AddElements(&pnew, 1); 01029 01030 // skip this operator if it is the first of the given MROW; 01031 // if tag is just an MO, then tag will be NULL & the function will return 01032 // waiting for the next real node to parse. 01033 p = p.GetNext(); 01034 } 01035 01036 if (tag.GetName() == wxT("mrow")) { 01037 01038 // by now, p couldn't be the first child of pTag; maybe p is pointing to 01039 // the sencond; we must always use p 01040 /*wxXml2Node optag; 01041 mcAddSubOp addop(hlp(), mcOperator::io_); 01042 mcSubOp subop(this); 01043 01044 // check that the operators contained in the given node are okay 01045 optag = addop.io_GetMathML(TRUE); 01046 mcASSERT(!tag->math_Contains(optag), wxT("A monomial cannot contain + or - !!!")); 01047 optag = subop.io_GetMathML(TRUE); 01048 mcASSERT(!tag->math_Contains(optag), wxT("A monomial cannot contain + or - !!!")); 01049 */ 01050 // check if this monomial already has a first operator 01051 if (data_GetCount() != 1 || 01052 (data_Get(0).data_GetType() != mcET_ADDOP && 01053 data_Get(0).data_GetType() != mcET_SUBOP)) { 01054 01055 data_DeleteAll(); // clean this object 01056 01057 // do not use math_AddNewOp() because it would also add an empty box 01058 mcEmptyBox first; 01059 data_AddElements(&first, 1); 01060 } 01061 01062 // now, import data 01063 while (p != wxXml2EmptyNode) { 01064 01065 // is k the begin char of a mcElement derived class ? 01066 n = mcElementHelpers::io_isTagBeginTag(p); 01067 if (n != FALSE) { 01068 01069 mcElement pnew = mcElementHelpers::data_NewElem(n); 01070 if (!pnew.io_ImportPresentationMathML(p, err)) 01071 return FALSE; 01072 data_AddElements(&pnew, 1); 01073 } 01074 01075 p = p.GetNext(); 01076 } 01077 } 01078 01079 // extra-work required ? 01080 io_PostProcessChildren(); 01081 01082 return TRUE; 01083 } 01084 01085 bool mcMonomialHelpers::io_ImportInlinedExpr(const wxString &todecode, int *c, wxString &pErr) 01086 { 01087 wxString token(todecode); 01088 mcElementType n; 01089 int count; 01090 01091 // BE SURE TO data_Delete EVERYTHING BEFORE IMPORTING !!!! 01092 data_DeleteAll(); 01093 01094 while (!token.IsEmpty()) { 01095 01096 // as in mcMonomialHelpers::gui_Input(), we have to do a special check 01097 // here for mcFunction recognition... 01098 n = mcFunctionHelpers::io_isFunctionBeginChar(token) ? mcET_FUNCTION : mcET_INVALID; 01099 01100 // ... also mcRadical have a mcFunction-like inlined expression... 01101 if (n == mcET_INVALID) 01102 n = mcRadicalHelpers::io_isRadicalBeginChar(token) ? mcET_RADICAL : mcET_INVALID; 01103 01104 // is the token's first letter a begin char of some element ? 01105 if (n == mcET_INVALID) 01106 n = mcElementHelpers::io_isCharBeginChar(token.GetChar(0)); 01107 01108 // does this monomial end here ? 01109 if (n == mcET_ADDOP || n == mcET_SUBOP) 01110 break; // yes 01111 01112 if (n != mcET_INVALID) { 01113 01114 mcElement pnew = mcElementHelpers::data_NewElem(n); 01115 //mcElement pnew = *mcElement::data_GetInstanceOf(n); 01116 01117 // import this element 01118 if (!pnew.io_ImportInlinedExpr(token, &count, pErr)) 01119 return FALSE; 01120 01121 // add it to this monomial 01122 data_AddElements(&pnew, 1); 01123 //delete pnew; 01124 01125 // update the token string 01126 token = token.Right(token.Len()-count); 01127 01128 } else { 01129 01130 pErr = wxT("Could not recognize the first element ") 01131 wxT("encoded in this token: ") + token; 01132 return FALSE; 01133 } 01134 } 01135 01136 // we should have imported the entire token... except when we find 01137 // a mcAddOp or mcSubOp... 01138 if (c) *c = todecode.Len()-token.Len(); 01139 01140 // be sure to add operators between those elements that 01141 // require them to be present (e.g. two mcNumbers adiacents...) 01142 data_Repair(); 01143 01144 // extra-work required ? 01145 io_PostProcessChildren(); 01146 01147 mcIOLOG(wxT("mcMonomialHelpers::io_ImportInlinedExpr - we've imported [%s]"), mcTXTTHIS); 01148 01149 return TRUE; 01150 } 01151 01152 void mcMonomialHelpers::io_PostProcess() 01153 { 01154 // this cannot be done in mcMonomialHelpers::io_ImportInlinedExpr and 01155 // mcMonomialHelpers::io_ImportPresentationMathML since mcPolynomial 01156 // must remove all mcParenthesis, first... consider: 01157 // 01158 // 2ax(E/2) 01159 // if we convert divop to fractions before the conversion, 01160 // performed by mcPolynomial::io_ImportInlinedExpr, of mcParenthesis 01161 // to mcBrackets, we would get a mcFraction with 01162 // 01163 // the numerator set to wxT("2ax(E") and the denominator set to "2)" 01164 // 01165 if (mcMonomialHelpers::sio_bAutoConvertDivOpToFractions) 01166 data_TransformDivOp(); 01167 } 01168 /* 01169 wxString mcMonomialHelpers::io_GetContentMathML(int indent) 01170 { 01171 wxString dest; 01172 01174 01175 // if this monomial is composed of only one element, we don't need 01176 // to create a nested APPLY section; just remember that element 0 01177 // is the add (or sub) op. 01178 if (data_GetCount() == 2) 01179 return data_Get(1).GetContentMathML(indent); 01180 01181 // begin APPLY section and the TIMES chain 01182 dest += wxString(wxT(' '), indent) + wxT("<apply>\n") + wxString(wxT(' '), indent+mcMathCore::Get()->m_nIndentationStep) + wxT("<times/>\n"); 01183 01184 // insert the content mathML for each factor 01185 for (int i=1; i < data_GetCount(); i+=2) { 01186 dest += data_Get(i).GetContentMathML(indent+mcMathCore::Get()->m_nIndentationStep); 01187 } 01188 01189 // close APPLY section 01190 dest += wxString(wxT(' '), indent) + wxT("</apply>\n"); 01191 01192 // return our work 01193 return dest; 01194 }*/ 01195 01196 01197 01198 01199 01200 01201 01202 01203 01204 01205 // ---------------------------------------- 01206 // mcMONOMIALMATH 01207 // ---------------------------------------- 01208 01209 int mcMonomialHelpers::math_MathToDataIdx(int mathindex) const 01210 { 01211 if (mathindex < 0 || mathindex >= math_GetCount()) { 01212 01213 mcMATHLOG(wxT("mcMonomialHelpers::math_MathToDataIdx [%s] - ") 01214 wxT("invalid conversion required"), mcTXTTHIS); 01215 return -1; // no conversion is possible 01216 } 01217 01218 return data_GetNonOpElemIndex(mathindex); 01219 } 01220 01221 int mcMonomialHelpers::math_DataToMathIdx(int dataindex) const 01222 { 01223 data_CheckIndex(dataindex); 01224 01225 int elements=0; 01226 for (int n=0; n < dataindex; n++) 01227 if (!data_isOp(n)) 01228 elements++; 01229 01230 return elements; 01231 } 01232 01233 mcBasicOpRes mcMonomialHelpers::math_RaiseTo(const mcPolynomial &p) 01234 { 01235 mcMATHLOG(wxT("mcMonomialHelpers::math_RaiseTo [%s] - raising %d elements to [%s]"), 01236 mcTXTTHIS, math_GetCount(), mcTXT(p)); 01237 01238 // math_Get() returns a mcExpElement and thus makes easier our task 01239 for (int i=0,max=math_GetCount(); i < max; i++) { 01240 01241 mcBasicOpRes r = math_Get(i).math_RaiseTo(p); 01242 01243 switch (r) { 01244 case mcBOR_REMOVE_OPERAND: 01245 continue; 01246 01247 case mcBOR_INVALID: 01248 default: 01249 mcASSERT(0, wxT("invalid raise !")); 01250 } 01251 } 01252 01253 return mcBOR_REMOVE_OPERAND; 01254 } 01255 01256 mcExpSimRes mcMonomialHelpers::math_HandleExpSimFlag(mcExpSimRes r, mcElement *newelem, int i) 01257 { 01258 // we must check for a special case that mcElementArrayMath 01259 // cannot handle itself: when the just simplified element 01260 // returns mcESR_REPLACE_THIS with a "newelem" of type 01261 // mcET_POLYNOMIAL: 01262 if (r == mcESR_REPLACE_THIS && 01263 (*newelem).data_GetType() == mcET_POLYNOMIAL) { 01264 01265 // if we don't have a mcPolynomial as parent, then 01266 //if (hlp()->GetParent().data_GetType() != mcET_POLYNOMIAL) 01267 // return mcESR_DONE; 01268 01269 // FIXME: what if this monomial does not contain only the i-th 01270 // element ??? Where do we put all those elements if we replace 01271 // ourselves with the given newelem ? 01272 01273 // this mcMonomial must be replaced with the polynomial 01274 // given by the the math_Simplify(long flags) function of the i-th element of the array... 01275 return mcESR_REPLACE_THIS; 01276 } 01277 01278 // mcMonomialHelpers cannot handle this flag; return it to mcPolynomial 01279 if (r == mcESR_DISTRIBUTE) 01280 return mcESR_DISTRIBUTE; 01281 if (r == mcESR_CHANGE_SIGN) 01282 return mcESR_CHANGE_SIGN; 01283 01284 return mcElementArrayHelpers::math_HandleExpSimFlag(r, newelem, i); 01285 } 01286 01287 void mcMonomialHelpers::math_Abs() 01288 { 01289 // replace first op with a mcAddOp 01290 //math_ReplaceElement(mcET_OPERATOR, mcET_ADDOP, wxT('+'), '+', 0); 01291 mcNumber oldcoeff(math_GetCoeff()); 01292 oldcoeff.math_Abs(); 01293 01294 math_SetCoeff(oldcoeff); 01295 } 01296 01297 mcExpSimRes mcMonomialHelpers::math_Reorder() 01298 { 01299 // be sure there are no mcDivOp 01300 mcASSERT(data_GetNumOfElemType(mcET_DIVOP) == 0, 01301 wxT("This function cannot work with mcDivOp scattered in the array")); 01302 01303 // now remove also all other operators 01304 math_RemoveAllOp(); 01305 01306 // reorder elements 01307 int n = math_ReorderElements(data_GetArray(), data_GetCount()); 01308 01309 // re-add those required mcMultOps 01310 data_Repair(); 01311 01312 return (n == 0 ? mcESR_DONE : mcESR_NOTFINISHED); 01313 } 01314 01315 int mcMonomialHelpers::math_GetOrderPos() const 01316 { 01317 mcMATHLOG(wxT("mcMonomialHelpers::math_GetOrderPos - retrieving order position for [%s]"), mcTXTTHIS); 01318 01319 mcIntegerValue unk = math_GetMaxDegreeForSymbolArray(&mcSymbol::arrUnknowns); 01320 if (unk != *mcIntegerValue::pNAN) 01321 return -(int)(unk.GetInt()*10000); // unknown-ordering have absolute precedence 01322 01323 // if there are no unknowns in this monomial, then take in consideration 01324 // the parameters & the constants 01325 mcIntegerValue par = math_GetMaxDegreeForSymbolArray(&mcSymbol::arrParameters); 01326 if (par == *mcIntegerValue::pNAN) par = 0; 01327 mcIntegerValue con = math_GetMaxDegreeForSymbolArray(&mcSymbol::arrConstants); 01328 if (con == *mcIntegerValue::pNAN) con = 0; 01329 01330 // give different importance to the various type of symbols 01331 par *= 1; 01332 con /= 2; 01333 01334 // the cast and GetInt() are used to avoid warnings 01335 return -(int)(par.GetInt()+con.GetInt()); 01336 } 01337 01338 mcIntegerValue mcMonomialHelpers::math_GetMaxDegreeFor(const mcSymbolProperties *p) const 01339 { 01340 mcMATHLOG(wxT("mcMonomialHelpers::math_GetMaxDegreeFor [%s]"), mcTXTTHIS); 01341 mcSymbol s(p->data_GetSafeLinkedSym()); 01342 mcIntegerValue res = 0; 01343 01344 // scan this monomial searching for symbols of the given type 01345 for (int i=0,max=math_GetCountOf(s); i < max; i++) { 01346 01347 mcSymbol sym(math_Find(i, s)); 01348 mcASSERT(sym.data_isLinkedWith(p), wxT("The math_Find() function did not work")); 01349 01350 // get its exponent 01351 const mcPolynomial exp = sym.math_GetConstExp(); 01352 mcMATHLOG(wxT("mcMonomialHelpers::math_GetMaxDegreeFor - symbol [%s] have [%s] as exp"), 01353 mcTXT(sym), mcTXT(exp)); 01354 mcIntegerValue tmp = 0; 01355 01356 // and if it exist, unwrap the number it contains 01357 if (exp != mcEmptyElement) 01358 tmp = mcIntegerValue(exp.math_GetWrappedNumber()); 01359 01360 // the exponent exists but it does not contain a single number ? 01361 if (!tmp.isValid()) 01362 return tmp; 01363 01364 res = res.GetMax(tmp); 01365 mcMATHLOG(wxT("mcMonomialHelpers::math_GetMaxDegreeFor - currently it's [%s]"), 01366 res.GetStr().c_str()); 01367 } 01368 01369 // if we did not find anything, we must return zero 01370 return res; 01371 } 01372 01373 mcIntegerValue mcMonomialHelpers::math_GetMaxDegreeForSymbolArray(const mcSymbolArray *p) const 01374 { 01375 mcIntegerValue res = 0; 01376 for (int i=0; i < p->data_GetCount(); i++) { 01377 01378 // get the max degree for the i-th symbol 01379 mcIntegerValue tmp = math_GetMaxDegreeFor(p->data_GetSymbol(i)); 01380 if (tmp == *mcIntegerValue::pNAN) 01381 return *mcIntegerValue::pNAN; 01382 01383 // proceed 01384 res += tmp; 01385 } 01386 01387 return res; 01388 } 01389 01390 01391 01392 // ----------------------------------------------------- 01393 // mcMONOMIALMATH - overridden mcElementMath functions 01394 // ----------------------------------------------------- 01395 01396 mcPolynomial mcMonomialHelpers::math_GetPolynomialWrapper() const 01397 { 01398 // create a polynomial... 01399 mcPolynomial res; 01400 mcElement copy(this); 01401 copy.data_MakePrivateCopy(); 01402 01403 // wrap ourselves into it... 01404 res.data_AddElements(©, 1); 01405 01406 // and return it 01407 return res; 01408 } 01409 01410 mcArrayEntry mcMonomialHelpers::math_WrapMonomial(const mcMonomial &mon) 01411 { 01412 mcASSERT(0, wxT("bad use of this function !")); 01413 01414 // just copy the given monomial into this one... 01415 data_DeepCopy(mon.hlp()); 01416 01417 // cannot return a pointer to the mcMonomial which holds us ! 01418 return mcArrayEntry(this, -1); 01419 } 01420 01421 mcArrayEntry mcMonomialHelpers::math_WrapSimple(const mcElement &p) 01422 { 01423 mcASSERT(p.data_GetType() != mcET_MONOMIAL && 01424 p.data_GetType() != mcET_POLYNOMIAL, wxT("cannot nest arrays !!")); 01425 01426 int idx = data_AddElements(&p, 1); 01427 return mcArrayEntry(this, idx); 01428 } 01429 01430 void mcMonomialHelpers::math_PrepareForComparison(mcElementArray &p) const 01431 { 01432 // the given pointer should point to a work copy !!! 01433 01434 // first of all, simplify to the maximum level the monomial: 01435 // this will make all the following operations easier to perform 01436 // for the math engine... 01437 p.math_MaxSimplify(mcEXPSIM_NOFLAGS); 01438 01439 // ...then, for a mcMonomial, we must remove all the mcDivOp 01440 // (and also useless mcMultOp) to avoid problems. 01441 if (p.data_GetType() == mcET_MONOMIAL) 01442 mcMonomial(p).math_RemoveAllOp(); 01443 } 01444 01445 mcExpSimRes mcMonomialHelpers::math_BeginSimSteps() 01446 { 01447 // be sure arrays is repaired 01448 data_Repair(); 01449 01450 // transform all the div ops in mult ops 01451 math_TransformDivOp(); 01452 01453 // those first steps usually do little or nothing 01454 return mcESR_DONE; 01455 } 01456 01457 void mcMonomialHelpers::math_EndSimSteps() 01458 { 01459 // we *always* need to repair the array 01460 data_Repair(); 01461 } 01462 01463 01464 01465 01466 // ------------------------------------ 01467 // mcMONOMIALMATH - basic operations 01468 // ------------------------------------ 01469 01470 bool mcMonomialHelpers::math_CanBeAddedWith(const mcElement &p) const 01471 { 01472 const mcMonomial &m = (mcMonomial &)p; 01473 01474 // better allow additions/subtractions between monomials 01475 // only if they are similar... 01476 if (p.data_GetType() == mcET_MONOMIAL) { 01477 01478 if (math_GetCount() == 1 && 01479 m.math_GetCount() == 1) { 01480 01481 // we contain only one element, and this is true also for the "m" monomial... 01482 // perform check on the contained elements 01483 bool res = data_Get(0).math_CanBeAddedWith(m.math_Get(0)); 01484 01485 // if the two elements can be summed so that the result 01486 // is contained in the first one, they return TRUE, but 01487 // if the result cannot be contained in the first one, 01488 // then math_CanBeAddedWith() will return FALSE but this does not 01489 // mean that they cannot be added in a mcMonomial-context... 01490 // 01491 // Example: 01492 // x + x <-- two mcSymbols cannot be added 01493 // so that the result is contained 01494 // in the first mcSymbol 01495 // 2x <-- two mcSymbols can be added in a mcMonomial 01496 // 01497 if (res) return TRUE; 01498 } 01499 01500 // if two monomials are similars, then they can always be added... 01501 // see the #isSimilarTo function for a definition of "similarity" 01502 if (math_isSimilarTo(m)) 01503 return TRUE; 01504 } 01505 01506 return FALSE; 01507 } 01508 01509 mcBasicOpRes mcMonomialHelpers::math_Add(const mcElement &p, mcElement *pp, bool add) 01510 { 01511 const mcMonomial &m = (const mcMonomial &)p; 01512 mcASSERT(p.data_GetType() == mcET_MONOMIAL, wxT("Cannot add non-monomials")); 01513 01514 // the prerequisite for this algorithm to work is that this array 01515 // contains only mcMultOp and none mcDivOp 01516 math_RemoveAllOp(); 01517 01518 // this is the only difference between addition/subtraction 01519 //mcElementType optoinsert = (add ? mcET_ADDOP : mcET_SUBOP); 01520 01521 // if we are containing a single element and this is true also for 01522 // the other addend, then, first of all check if the two contained elements can 01523 // be added (and the result can be stored in one of the two mcElements) 01524 if (math_GetCount() == 1 && m.math_GetCount() == 1) { 01525 01526 mcElement operand = m.math_Get(0); 01527 01528 // suppose we have two mcSymbols to add: the result cannot 01529 // be stored inside one of the two but as mcMonomial we can 01530 // still store it... 01531 if (math_Get(0).math_CanBeAddedWith(operand)) { 01532 //mcASSERT(math_Get(0).math_CanBeAddedWith(operand), 01533 // "Error in mcMonomialHelpers::math_CanBeAddedWith"); 01534 01535 // just store the result in our first element... 01536 mcMATHLOG(wxT("mcMonomialHelpers::math_Add - %s [%s] and [%s]"), 01537 (add ? wxT("adding") : wxT("subtracting")), mcTXT(math_Get(0)), mcTXT(operand)); 01538 return math_Get(0).math_Add(operand, NULL, add); 01539 } 01540 } 01541 01542 // now, we can do two things: 01543 // 1) sum up the coefficients of the two monomials 01544 // 2) pick up the non-common factors of the two monomials 01545 mcASSERT(math_isSimilarTo(m), wxT("math_CanBeAddedWith() is buggy")); 01546 //mcLOG("mcMonomialHelpers::math_Add - The two monomials are similar = %d", b); 01547 01548 // just find the coefficients and sum/subtract them 01549 mcRealValue thiscoeff = math_GetCoeff(); 01550 mcRealValue mcoeff = m.math_GetCoeff(); 01551 mcMATHLOG(wxT("mcMonomialHelpers::math_Add - the two coeff to %s are: [%s] and [%s]"), 01552 (add ? wxT("ADD") : wxT("SUBTRACT")), mcTXTV(thiscoeff), mcTXTV(mcoeff)); 01553 01554 if (add) 01555 thiscoeff += mcoeff; 01556 else 01557 thiscoeff -= mcoeff; 01558 01559 mcMATHLOG(wxT("mcMonomialHelpers::math_Add - the result is [%s]"), mcTXTV(thiscoeff)); 01560 math_SetCoeff(mcNumber(thiscoeff)); 01561 01562 // re-add those operators which are required 01563 data_Repair(); 01564 01565 // in all the cases, the second addend must be set to zero... 01566 return mcBOR_REMOVE_OPERAND; 01567 } 01568 01569 mcBasicOpRes mcMonomialHelpers::math_MultiplyBy(const mcElement &e, mcElement *pp) 01570 { 01571 mcASSERT(e.data_GetType() == mcET_MONOMIAL, 01572 wxT("Only monomials can be used here; use math_MultiplyBySimple() instead")); 01573 01574 mcMonomial &m = (mcMonomial &)e; 01575 01576 mcElement num(mcEmptyElement); 01577 if ((num=data_GetWrapped(mcET_NUMBER)) != mcEmptyElement && 01578 mcNumber(num).data_Get() == 1.0) { 01579 01580 // replace with the elements in the given monomial the simple "1" 01581 // contained into this monomial 01582 data_DeleteAll(); 01583 data_Merge(m); 01584 01585 } else { 01586 01587 // put the new factors just after the end of this monomial 01588 data_Merge(m); 01589 } 01590 01591 // check that everything is okay (and add mcMultOp where required) 01592 data_Repair(); 01593 01594 // the second operand has been completely merged: it can be removed 01595 return mcBOR_REMOVE_OPERAND; 01596 } 01597 01598 mcBasicOpRes mcMonomialHelpers::math_DivideBy(const mcElement &e, mcElement *pp) 01599 { 01600 mcASSERT(e.data_GetType() == mcET_MONOMIAL, 01601 wxT("Only monomials can be used here; use math_DivideBySimple() instead")); 01602 01603 // just create a fraction... 01604 mcPolynomial &den = math_EmbedInFraction(FALSE).data_GetFraction().data_GetDen(); 01605 01606 // ...and set its denominator to the given element 01607 mcMonomial towrap(e); 01608 den.data_DeleteAll(); 01609 den.math_WrapMonomial(towrap); 01610 01611 // the second operand has been embedded in a fraction 01612 return mcBOR_REMOVE_OPERAND; 01613 } 01614 01615 01616 01617 01618 01619 01620 // ----------------------------------------------------- 01621 // mcMONOMIALMATH - helper functions 01622 // ----------------------------------------------------- 01623 01624 bool mcMonomialHelpers::math_isSimilarTo(const mcMonomial &m) const 01625 { 01626 // scan the two arrays when they are simplified at the most level 01627 mcMonomial m1(this); 01628 mcMonomial m2(m); 01629 01630 // remove the coefficients of the monomials... 01631 m1.math_RemoveCoeff(); 01632 m2.math_RemoveCoeff(); 01633 01634 // do the real comparison 01635 mcMATHLOG(wxT("mcMonomialHelpers::math_isSimilarTo - are [%s] and [%s] similar ?"), 01636 mcTXT(m1), mcTXT(m2)); 01637 bool res = m1.math_Compare(m2, mcFIND_NOFLAGS); 01638 mcMATHLOG(wxT("mcMonomialHelpers::math_isSimilarTo - %s"), 01639 (res == TRUE ? wxT("yes they are") : wxT("no they aren't"))); 01640 01641 // data_Delete the temporary backups... 01642 //data_Delete m1; 01643 //data_Delete m2; 01644 01645 return res; 01646 } 01647 01648 void mcMonomialHelpers::math_TransformDivOp() 01649 { 01650 // scans the array and replaces mcMultDivOps with mcFractions... 01651 for (int i=0; i < data_GetCount()-1; i++) { 01652 01653 // convert from mcDivOp to mcMultOp 01654 if (data_Get(i).data_GetType() == mcET_DIVOP) { 01655 01656 // make the reciprocal of the elements which follows this mcDivOp.... 01657 mcElement replacement = NULL; 01658 data_Get(i+1).math_MakeReciprocal(&replacement); 01659 01660 if (replacement != mcEmptyElement) { 01661 01662 // we must replace the i+1-th element with the given pointer... 01663 data_AddElements(&replacement, 1, i+1, TRUE); 01664 } 01665 01666 // and replace the div op with a mult op 01667 data_AddNewOp(mcET_MULTOP, i); 01668 } 01669 } 01670 } 01671 01672 void mcMonomialHelpers::math_RemoveAllOp() 01673 { 01674 // turn div ops into mult ops 01675 math_TransformDivOp(); 01676 01677 // remove all mult operators 01678 for (int i=0; i < data_GetCount(); i++) { 01679 01680 if (data_isOp(i)) { // this should be a mcMultOp 01681 01682 data_Delete(i); 01683 data_MoveElemLeft(i); 01684 } 01685 } 01686 } 01687 01688 void mcMonomialHelpers::math_RemoveCoeff() 01689 { 01690 for (int i=0; i < math_GetCount(); i++) { 01691 01692 #ifdef EXTENDED_COEFF 01693 if (!data_Get(i).math_ContainsUnknowns(NULL)) 01694 if (!Remove(i, TRUE)) 01695 i--; // recheck this element 01696 #else 01697 // find all free mcNumbers, and data_Delete them... 01698 if (math_Get(i).data_GetType() == mcET_NUMBER) { 01699 01700 // #Remove will return TRUE if a mcNumber intialized with zero 01701 // was added to the array to avoid to leave it empty... in this 01702 // case we must avoid to recheck that mcNumber 01703 if (!math_Remove(i, TRUE)) 01704 i--; // recheck this element 01705 } 01706 #endif 01707 } 01708 } 01709 01710 mcMonomial mcMonomialHelpers::math_DetachNonCommonFactors(const mcMonomial &m) 01711 { 01712 // create an empty monomial which will be filled with the 01713 // non common factors 01714 mcMonomial res; 01715 01716 // scan the entire array 01717 for (int i=0; i < data_GetCount(); i++) { 01718 01719 mcElementType t = data_Get(i).data_GetType(); 01720 int n = -1; 01721 01722 // check the i-th element of this array 01723 // against the elements of the same type 01724 // in the given monomial 01725 for (int j=0; j < m.math_GetCount(); j++) 01726 if (t == m.math_Get(j).data_GetType()) 01727 if (data_Get(i).math_Compare(m.math_Get(j), TRUE)) 01728 n = j; 01729 01730 if (n == -1) { 01731 01732 // add this element to the array to return 01733 res.data_AddElements(data_GetArray(i), 1, -1, TRUE); 01734 01735 // and remove that element from this array 01736 data_Delete(i); 01737 data_MoveElemLeft(i); 01738 i--; 01739 } 01740 } 01741 01742 return res; 01743 } 01744 01745 void mcMonomialHelpers::math_SimplifyCoeff() 01746 { 01747 mcMATHLOG(wxT("mcMonomialHelpers::math_SimplifyCoeff [%s] - process starting"), mcTXTTHIS); 01748 01749 // all mcNumber which are tied by multiplications, are cumulated here: 01750 mcNumber num = *mcNumberHelpers::smath_pOne; 01751 01752 // all mcNumbers preceded by mcDivOp will be cumulated here: 01753 mcNumber den = *mcNumberHelpers::smath_pOne; 01754 01755 for (int i=0, max=data_GetNumOfElemType(mcET_NUMBER); i < max; i++) { 01756 01757 int n = data_GetElemIndexOfType(i, mcET_NUMBER); 01758 01759 // merge these two mcNumbers (which is not granted are adiacent) 01760 // using the operator which is 01761 mcElementType t = mcET_MULTOP; 01762 01763 // if there is nothing before or there is a non-operator, 01764 // then a mcMultOp must be used... 01765 if (n >= 0) { 01766 if (n > 0 && data_isOp(n-1)) 01767 t = data_Get(n-1).data_GetType(); 01768 01769 // the two mcNumbers are separated by one operator: use it to 01770 // merge them... 01771 if (t == mcET_MULTOP) 01772 num.math_SimpleMultiplyBy(data_Get(n)); 01773 else if (t == mcET_DIVOP) 01774 den.math_SimpleMultiplyBy(data_Get(n)); 01775 } 01776 } 01777 01778 // now, add the num/den at the beginning of the array... 01779 math_ApplyOpSimple(mcET_DIVOP, num, den); 01780 01781 // remove old coefficient and add the new one at the beginning of 01782 // the array... 01783 math_SetCoeff(num); 01784 mcMATHLOG(wxT("mcMonomialHelpers::math_SimplifyCoeff [%s] - coeff simplified"), mcTXTTHIS); 01785 } 01786 01787 //mcMonomial 01788 mcRealValue mcMonomialHelpers::math_GetCoeff() const 01789 { 01790 #ifdef EXTENDED_COEFF 01791 01792 mcMonomial &coeff = (mcMonomial &)mcNewMonomial(); 01793 01794 // return everything which doesn't contain any unknown 01795 for (int i=0, max=data_GetCount(); i < max; i++) { 01796 01797 mcElement p = data_Get(i); 01798 if (!p->math_ContainsUnknowns(NULL)) 01799 coeff->data_AddElements(&p, 1, -1); 01800 } 01801 01802 if (coeff->data_GetCount() > 0) 01803 return coeff; 01804 return *mcNumberHelpers::smath_pOne; 01805 01806 #else 01807 01808 int n = data_GetNumOfElemType(mcET_NUMBER); 01809 mcMonomial touse(this); 01810 01811 if (n > 1) { 01812 mcMonomial copy(this); 01813 01814 // reduce to one mcNumber all the various mcNumbers 01815 // scattered in the array... 01816 copy.math_SimplifyCoeff(); 01817 01818 // instead of *this, use the temporary "copy" to get the coeff.... 01819 touse.data_Ref(copy); 01820 01821 // we should not need to check the new count of mcNumbers 01822 #ifdef __MCDEBUG__ 01823 n = touse.data_GetNumOfElemType(mcET_NUMBER); 01824 #else 01825 n = 1; 01826 #endif 01827 } 01828 01829 mcASSERT(n <= 1, wxT("Something wrong in math_SimplifyCoeff")); 01830 01831 // if we have our mcNumber we just have to return a copy of it... 01832 if (n > 0) 01833 return mcNumber(touse.data_GetElemOfType(0, mcET_NUMBER)).data_Get();//*mdata_sign; 01834 01835 // no mcNumbers in the array means a simple "1.0" 01836 return mcRealValue(1);//*mdata_sign; 01837 01838 #endif 01839 } 01840 01841 void mcMonomialHelpers::math_SetCoeff(const mcNumber &coeff)//mcMonomial &n) 01842 { 01843 mcNumber n(coeff); 01844 01845 // remove old coeff 01846 math_RemoveCoeff(); 01847 01848 // update the sign variable 01849 /*if (n.data_Get() >= 0) 01850 mdata_sign = 1; 01851 else { 01852 01853 // we must always store only positive coefficients ! 01854 mdata_sign = -1; 01855 n.math_Abs(); 01856 }*/ 01857 01858 // in some cases (when the array would be empty otherwise) 01859 // the #RemoveCoeff() function leaves one mcNumber at the 01860 // beginning of the array... 01861 bool overwrite = FALSE; 01862 if (data_GetCount() > 0 && data_Get(0).data_GetType() == mcET_NUMBER) 01863 overwrite = TRUE; 01864 01865 // add the new coefficient (eventually overwriting last one) 01866 data_AddElements((mcElement *)(&n), 1, 0, overwrite); 01867 } 01868 01869 void mcMonomialHelpers::math_ChangeCoeffSign() 01870 { 01871 // this function cannot be put in the header file !!!! 01872 math_SetCoeff(mcNumber(math_GetCoeff().ChangeSign())); 01873 } 01874 01875 /* 01876 mcMonomial mcMonomialHelpers::math_GetFactors() const 01877 { 01878 01879 for (int i=0,max=math_GetCount(); i<max; i++) 01880 math_Get(i)->math_GetFactors(); 01881 }*/ 01882 01883 mcMonomial mcMonomialHelpers::math_GetLCM(const mcElement &p) const 01884 { 01885 mcMATHLOG(wxT("mcMonomialHelpers::math_GetLCM - computing lcm between [%s] and [%s]"), 01886 mcTXTTHIS, mcTXT(p)); 01887 01888 mcMonomial arr(p); 01889 mcMonomial res(this); 01890 01891 if (arr.math_GetCount() == 1 && math_GetCount() == 1) { 01892 01893 mcElement a(arr.math_Get(0)); 01894 mcElement b(math_Get(0)); 01895 01896 // the lowest common multiple simply is the product 01897 // of a and b if a and b are different 01898 if (!a.math_Compare(b, TRUE)) { 01899 01900 res.math_SimpleMultiplyBy(a); 01901 } 01902 01903 } else { 01904 01905 for (int j=0,max=arr.math_GetCount(); j < max; j++) { 01906 01907 mcElement tofind(arr.math_Get(j)); 01908 mcMATHLOG(wxT("mcMonomialHelpers::math_GetLCM - now processing [%s]"), mcTXT(tofind)); 01909 01910 // find the first occurrence of 'tofind' 01911 int idx=res.math_GetIndexOf(0, tofind); 01912 01913 if (idx > -1) { 01914 01915 // get the LCM between the j-th element of "arr" 01916 // and the idx-th element of "res" 01917 mcElement &tmp = res.math_Get(idx); 01918 mcMonomial mon(tmp.math_GetLCM(tofind)); 01919 01920 // remove the old factor and add the contents 01921 // of the new monomial containing the LCM just computed 01922 res.math_Remove(idx); 01923 res.math_SimpleMultiplyBy(mon); 01924 01925 // this algorithm requires no more than one element 01926 // with the same base of the "tofind" element... 01927 mcASSERT(res.math_GetIndexOf(1, tofind) == -1, 01928 wxT("Cannot be present more than a factor of 'tofind'...")); 01929 01930 } else { 01931 01932 // the j-th factor of wxT("arr") is not present in "res": 01933 // we must add it... 01934 res.math_SimpleMultiplyBy(tofind); 01935 } 01936 01937 mcMATHLOG(wxT("mcMonomialHelpers::math_GetLCM - final lcm now is [%s]"), mcTXT(res)); 01938 } 01939 } 01940 01941 mcMATHLOG(wxT("mcMonomialHelpers::math_GetLCM - lcm is [%s]"), mcTXT(res)); 01942 return res; 01943 } 01944 01945 mcMonomial mcMonomialHelpers::math_GetGCD(const mcElement &p) const 01946 { 01947 mcMATHLOG(wxT("mcMonomialHelpers::math_GetGCD - computing gcd between [%s] and [%s]"), 01948 mcTXTTHIS, mcTXT(p)); 01949 01950 // create the monomial used to compute GCD and to return the result: 01951 //mcMonomial arr1(this); 01952 mcMonomial arr2(p); 01953 mcMonomial res; 01954 01955 // to compute the GCD we must be sure that arr1 & arr2 01956 // do no contain the same factors with same exponents 01957 //arr2.math_MaxSimplify(); 01958 01959 if (arr2.math_GetCount() == 1 && math_GetCount() == 1) { 01960 01961 mcElement a(arr2.math_Get(0)); 01962 mcElement b(math_Get(0)); 01963 01964 if (a.data_GetType() != b.data_GetType()) 01965 return *mcMonomialHelpers::smath_pOne; 01966 01967 // we have two simple elements and we just need their GCD 01968 return a.math_GetGCD(b); 01969 01970 } else { 01971 01972 res.math_ResetToOne(); 01973 for (int i=0; i < math_GetCount(); i++) { 01974 for (int j=0; j < arr2.math_GetCount(); j++) { 01975 01976 // we've got two elements: 01977 // 01978 // idx | 0 | 1 | 2 | 3 | 01979 // |---|---|---|---| 01980 // *this | a | b | c | d | 01981 // 01982 // i ------------^ 01983 // 01984 // idx | 0 | 1 | 2 | 01985 // |---|---|---| 01986 // m | c | d | e | 01987 // 01988 // j ----^ 01989 // 01990 01991 mcElement tmp(math_Get(i).hlp()->math_GetGCD(arr2.math_Get(j))); 01992 if (!mcMonomial(tmp).math_isWrappingOnly(1.0)) 01993 res.math_SimpleMultiplyBy(tmp); 01994 01995 mcMATHLOG(wxT("mcMonomialHelpers::math_GetGCD - gcd currently is [%s]"), 01996 mcTXT(res)); 01997 } 01998 } 01999 } 02000 02001 mcMATHLOG(wxT("mcMonomialHelpers::math_GetGCD - final gcd is [%s]"), mcTXT(res)); 02002 return res; 02003 } 02004 02005 02006
[ Top ] |