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

Monomial.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 
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("&InvisibleTimes;"));
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(&copy, 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 


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

[ Top ]