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

Polynomial.cpp

Go to the documentation of this file.
00001 
00002 // MathCore = a WYSIWYG equation editor + a powerful math engine     //
00003 // Copyright (C) 2003 by Francesco Montorsi                          //
00004 //                                                                   //
00005 // This library is free software; you can redistribute it and/or     //
00006 // modify it under the terms of the GNU Lesser General Public        //
00007 // License as published by the Free Software Foundation; either      //
00008 // version 2.1 of the License, or (at your option) any later         //
00009 // version.                                                          //
00010 //                                                                   //
00011 // This library is distributed in the hope that it will be useful,   //
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of    //
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the      //
00014 // GNU Lesser General Public License for more details.               //
00015 //                                                                   //
00016 // You should have received a copy of the GNU Lesser General Public  //
00017 // License along with this program; if not, write to the Free        //
00018 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,   //
00019 // MA 02111-1307, USA.                                               //
00020 //                                                                   //
00021 // For any comment, suggestion or feature request, please contact    //
00022 // the administrator of the project at frm@users.sourceforge.net     //
00023 //                                                                   //
00030 
00031 
00032 
00033 // optimization for GCC compiler
00034 #ifdef __GNUG__
00035 #pragma implementation "Polynomial.h"
00036 #endif
00037 
00038 
00039 // includes
00040 #include "mc/mcprec.h"
00041 #ifdef __BORLANDC__
00042     #pragma hdrstop
00043 #endif
00044 
00045 #ifndef mcPRECOMP
00046  #include <wx/tokenzr.h>
00047  #include "mc/Polynomial.h"
00048  #include "mc/Monomial.h"
00049  #include "mc/MathUtils.h"
00050 #endif
00051 
00052 
00053 
00054 // these are required by mcPolynomialMath functions
00055 #include "mc/Bracket.h"
00056 #include "mc/Number.h"
00057 #include "mc/Fraction.h"
00058 #include "mc/Parenthesis.h"
00059 #include "mc/Symbol.h"
00060 
00061 
00062 mcIMPLEMENT_MAIN_CLASS(mcPolynomial, mcElementArray);
00063 
00064 
00065 
00066 // setup customizable variables
00067 int mcPolynomialHelpers::sgui_nSpaceBetween = 2;
00068 mcPolynomial *mcPolynomialHelpers::smath_pOne = NULL;
00069 mcPolynomial *mcPolynomialHelpers::smath_pEmpty = NULL;
00070 
00071 
00072 // global objects
00073 mcPolynomial mcEmptyPolynomial((mcPolynomialHelpers*)NULL);
00074 
00075 
00076 
00077 
00078 // ----------------------------------------
00079 // mcPOLENTRY
00080 // ----------------------------------------
00081 
00082 /*int mcPolEntry::math_GetMonIdx(const mcPolynomial &owner)
00083 { return owner.math_DataToMathIdx(mdata_midx); }
00084 
00085 int mcPolEntry::math_GetElemIdx(const mcPolynomial &owner)
00086 { return owner.math_DataToMathIdx(mdata_eidx); }*/
00087 
00088 
00089 
00092 bool isPolynomialOkay(const mcElement &p)
00093 {
00094  static bool lastwasop = FALSE;
00095 
00096  if (p.data_GetType() != mcET_MONOMIAL && 
00097   p.data_GetType() != mcET_ADDOP && 
00098   p.data_GetType() != mcET_SUBOP) {
00099 
00100   // only monomials, add & sub operators are supported
00101   return FALSE;
00102  }
00103 
00104  if ((p.data_GetType() == mcET_ADDOP || 
00105   p.data_GetType() == mcET_SUBOP) && !lastwasop) {
00106 
00107   lastwasop = TRUE;
00108 
00109  } else if (p.data_GetType() == mcET_MONOMIAL && lastwasop) {
00110 
00111   lastwasop = FALSE;
00112 
00113  } else {
00114 
00115   // this array is containing something which is not a operator
00116   // nor a mcMonomial... or it contains one of these elements
00117   // but in an invalid order...
00118   return FALSE;
00119  }
00120 
00121  return TRUE; 
00122 }
00123 
00124 
00125 
00126 
00127 
00128 
00129 // ----------------------------------------
00130 // mcPOLYNOMIALDATA
00131 // ----------------------------------------
00132 
00133 #ifdef __MCDEBUG__
00134 
00135 void mcPolynomialHelpers::data_Check() const
00136 {   
00137  // check that a + or - is separing all the monomials in the array
00138  bool b = FALSE;
00139  if (data_GetCount() > 0 && data_isOp(0))
00140   b = TRUE;
00141 
00142  // if we say to ScanArray to check only even elements, the first would
00143  // be skipped !!! check it here....
00144  if (!b && data_GetCount() > 0) {
00145 
00146   mcASSERT(!data_isOp(0), 
00147    wxT("If 'b' is FALSE, the first element should be a non-op !!!"));
00148   mcASSERT(data_Get(0).data_GetType() == mcET_MONOMIAL, 
00149    wxT("If the first element is not an op, then it should be a mcMonomial !!!"));
00150  }
00151  
00152 #ifdef mcENABLE_VERBOSE_CHECK
00153  mcLOG(wxT("mcPolynomialHelpers::data_Check - checking [%s]"), mcTXTTHIS);
00154 #endif
00155  mcASSERT(data_ScanArray(isPolynomialOkay, b), 
00156   wxT("Not all the monomials in the array are ") \
00157   wxT("separed by a mcAddOp or a mcSubOp"));
00158 
00159  // this MUST be true... it's an important prerequisite of math functions
00160  //mcASSERT(data_GetCount() == 0 || data_isOp(0), "The expression must always start with a + or -");
00161  mcElementArrayHelpers::data_Check();
00162 }
00163 
00164 #endif
00165 
00166 bool mcPolynomialHelpers::data_isWrappingOnly(mcElementType t) const
00167 {
00168  if (data_GetCount() > 1)  // more than an element ?
00169   return FALSE;
00170 
00171  // check if we are directly containing the given element type...
00172  // (which can be only a mcOperator or mcMonomial, in this case)
00173  if (data_Get(0).data_GetType() == t)
00174   return TRUE;
00175 
00176  // EXTENDED FEATURE mcPOLYNOMIAL-SPECIFIC:
00177  // if we're containing a single monomial, then check if it's
00178  // wrapping only the required element type: data_GetWrapped
00179  // will allow the programmer to extract it...
00180  if (data_Get(0).data_GetType() == mcET_MONOMIAL &&
00181   ((const mcMonomial &)data_Get(0)).data_isWrappingOnly(t))
00182   return TRUE;
00183  return FALSE;
00184 }
00185 
00186 const mcElement &mcPolynomialHelpers::data_GetWrapped(mcElementType t) const
00187 {
00188  // we need to call this function to be sure that we
00189  // do not have more than one monomial...
00190  if (!data_isWrappingOnly(t))
00191   return mcEmptyElement;
00192 
00193  // if t is the identifier of a mcMonomial or a mcOperator, we can directly
00194  // return it here
00195  if (data_Get(0).data_GetType() == t)
00196   return data_Get(0);
00197 
00198  // otherwise we can extract here from the single monomial we contain...
00199  return ((const mcMonomial &)data_GetElemOfType(0, mcET_MONOMIAL)).data_GetWrapped(t);
00200 }
00201 
00202 bool mcPolynomialHelpers::math_isWrappingOnly(mcElementType t) const
00203 {
00204  // see data_isWrappingOnly for details.... 
00205  if (math_GetCount() != 1)
00206   return FALSE;
00207  if (math_Get(0).data_GetType() == t)
00208   return TRUE;
00209  if (math_Get(0).math_isWrappingOnly(t))
00210   return TRUE;
00211  return FALSE;
00212 }
00213 
00214 const mcElement &mcPolynomialHelpers::math_GetWrapped(mcElementType t) const
00215 {
00216  // see data_isWrappingOnly for details....
00217  if (!math_isWrappingOnly(t))
00218   return mcEmptyElement;
00219  if (math_Get(0).data_GetType() == t)
00220   return math_Get(0);
00221  return math_Get(0).math_GetWrapped(t);
00222 }
00223 
00224 bool mcPolynomialHelpers::data_CreateFirstOp()
00225 {
00226  if (!data_isArrayEmpty() && data_isOp(0))
00227   return FALSE;   // one is already present...
00228  
00229  // if the first element of the this polynomial is *not* an operator
00230  // we must add one !!!
00231  data_MoveElemRight(0);
00232  data_AddNewOp(mcET_ADDOP, 0);  // by default, add a +
00233  return TRUE;
00234 }
00235 
00236 void mcPolynomialHelpers::data_DeleteFirstOp()
00237 {
00238  if (data_isArrayEmpty() || !data_isOp(0))
00239   return;  // there is no a first operator to data_Delete
00240 
00241  data_DeleteFirst(1);  // just remove first element
00242 }
00243 
00244 mcElement &mcPolynomialHelpers::data_AddNewWrappedElement(mcElementType t, 
00245                 bool bOverwrite, int pos)
00246 {
00247  mcASSERT(t != mcET_MONOMIAL, wxT("Cannot nest monomials"));
00248 
00249  // create an element of type "t" and create a monomial containing it
00250  mcElement res = mcElementHelpers::data_NewElem(t);
00251  int n = data_AddNewMonomialContaining(&res, pos, bOverwrite);
00252  if (n == -1) return mcEmptyElement;
00253 
00254  // then return the index of the new monomial
00255  mcMonomial &m = (mcMonomial &)data_Get(pos);
00256  return m.data_Get(n);
00257 }
00258 
00259 void mcPolynomialHelpers::data_DetachAndShiftMonomial(int n)
00260 {
00261  // be sure the n-th element is a monomial
00262  mcASSERT(data_Get(n).data_GetType() == mcET_MONOMIAL, 
00263   wxT("This function works on monomials only"));
00264 
00265  // data_Detach the n-th monomial and its sign
00266  data_Detach(n);
00267  data_MoveElemLeft(n);
00268 
00269  if (n > 0 && data_isOp(n-1)) {
00270   data_Detach(n-1);
00271   data_MoveElemLeft(n-1);
00272  }
00273 }
00274 
00275 int mcPolynomialHelpers::data_AddNewMonomialContaining(mcElement *contents, 
00276                 int n, int pos, bool bOverwrite)
00277 {
00278  // create the new monomial
00279  mcMonomial m;
00280  
00281  // add to it the given elements
00282  mcASSERT(n > 0, wxT("Cannot add zero elements"));
00283  int idx = m.data_AddElements(contents, n);
00284  
00285  // and then add the monomial to this array
00286  data_AddElements((mcElement *)(&m), 1, pos, bOverwrite);
00287  return idx;
00288 }
00289 
00290 bool mcPolynomialHelpers::data_ReplaceParentheses(int leftm, int leftidx, 
00291               int rightm, int rightidx, 
00292               bool bMoveOnBracketEnd)
00293 {
00294  const mcMonomial &left = (const mcMonomial &)data_Get(leftm);
00295  const mcMonomial &right = (const mcMonomial &)data_Get(rightm);
00296  const mcParenthesis &rightp = (const mcParenthesis &)right.data_Get(rightidx);
00297  mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ")
00298   wxT("the monomial containing the left bracket is [%s]"), mcTXT(left));
00299  mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ")
00300   wxT("the monomial containing the right bracket is [%s]"), mcTXT(right));
00301  
00302  // ok, we have found a right bracket and we can thus
00303  // create our new mcBracket...
00304  mcPolynomial contents;
00305     
00306  // if the monomial containing the left bracket contains something
00307  // which follows the left parenthesis, then copy it in our
00308  // brand-new polynomial... 
00309  if (left.data_GetCount() - leftidx > 0) {
00310   
00311   int n = left.data_GetCount() - leftidx - 1;
00312   
00313   if (rightm == leftm) {
00314    
00315    // if the monomial containing the LEFT and the RIGHT
00316    // parentheses are the same, then we must adjust n
00317    n -= left.data_GetCount()-rightidx;
00318   }
00319   
00320   if (n > 0)
00321    contents.data_AddNewMonomialContaining(
00322     left.data_GetArray(leftidx+1),
00323     n, 
00324     -1,
00325     TRUE);
00326  }
00327     
00328  // now add all the monomials placed between the monomial
00329  // containing the LEFT parenthesis and the one containing
00330  // the RIGHT one...
00331  if (rightm-leftm > 0) {
00332   
00333   contents.data_AddElements(
00334    data_GetArray(leftm+1),
00335    rightm-leftm-1);
00336  }
00337     
00338  // finally, add the elements ,which are placed in the monomial
00339  // containing the RIGHT bracket, which precede the parenthesis...
00340  if (rightm != leftm && rightidx > 0) {
00341   
00342   contents.data_AddNewMonomialContaining(
00343    right.data_GetArray(),
00344    rightidx); 
00345    //TRUE);
00346  }
00347     
00348  // don't create empty polynomials !!!
00349  if (contents.data_isArrayEmpty()) {
00350   
00351   // add a simple empty box; the result will be:
00352   //
00353   //     (--)     where -- is the empty box !!!!
00354   //
00355   contents.data_AddNewEmptyMonomial();
00356  }
00357 
00358  // don't create empty monomials !!!
00359  /*const mcMonomial &m = contents.data_Get(0);*/
00360  if (((const mcMonomial &)contents.data_GetElemOfType(0, mcET_MONOMIAL)).data_isArrayEmpty()) {
00361   
00362   // in these cases:
00363   //
00364   //          (   + ... )
00365   //            ^- empty monomial  
00366   //
00367   // we cannot just add an empty box: we must
00368   // instead remove the first monomial; in this
00369   // way, the operator between 1th and 2nd, becomes
00370   // the first operator of the bracket's polynomial...
00371   contents.data_DeleteFirst(1);
00372  }
00373  
00374  // complete bracket creation...
00375  mcBracket br;
00376  br.data_SetContent(contents);
00377     
00378  // eventually set the bracket's exponent
00379  // (stored in a temporary field of mcParenthesis) 
00380  if (rightp.hlp()->mdata_pTmpExp != mcEmptyElement &&
00381   !rightp.hlp()->mdata_pTmpExp.data_isArrayEmpty()) {
00382     
00383   mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ")
00384    wxT("the exponent of the bracket is [%s]"), mcTXT(rightp.hlp()->mdata_pTmpExp));
00385   br.data_SetExpSub(TRUE, rightp.hlp()->mdata_pTmpExp);
00386  }
00387     
00388  mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ")
00389   wxT("the new bracket is [%s]"), mcTXT(br));
00390  br.data_Check();
00391     
00392  // ok, now we have our new bracket; but it must replace
00393  // ALL the elements that we have copied inside the bracket...
00394  mcMonomial &m = (mcMonomial &)left;
00395     
00396  // data_Delete the useless elements contained in the first monomial
00397  int cursoridx = -1;
00398  if (rightm != leftm) {
00399      
00400   m.data_DeleteLast(m.data_GetCount()-leftidx);
00401   m.data_AddElements((mcElement*)(&br), 1);
00402   cursoridx = m.data_GetCount()-1;
00403   
00404  } else {
00405      
00406   // both the LEFT and the RIGHT parentheses are contained
00407   // in the same monomial; special code is required in this case...
00408   m.data_AddElements((mcElement*)(&br), 1, leftidx, TRUE);
00409   cursoridx = leftidx;
00410      
00411   // remove the elements placed between the bracket we have
00412   // just added and the right parenthesis...
00413   for (int g=leftidx+1; g < rightidx+1; g++) {
00414       
00415    m.data_Delete(leftidx+1);
00416    m.data_MoveElemLeft(leftidx+1);
00417   }
00418  }
00419     
00420  // place the cursor of the monomial at the end of the
00421  // bracket we have created...
00422  if (mcMathCore::Get()->isGUIEnabled()) {
00423   if (bMoveOnBracketEnd) {
00424       
00425    // end of the monomial is the end of the bracket, too:
00426    //     ... (...)| ...     <-- final pos of cursor
00427    m.gui_SetCursorPos(mcCP_END);
00428       
00429   } else {
00430       
00431    m.gui_SetCursorOnElemBegin(cursoridx);
00432    
00433    // this will set the cursor here:
00434    //     ... (|...) ...
00435    // instead of
00436    //     ... |(...) ...
00437    // thus simulating the real input of the parenthesis
00438    m.gui_MoveCursor(mcMCF_RIGHT, mcMCF_NOMODIFIERS);
00439   }
00440  }
00441     
00442  // finally, add to the first monomial the useful elements 
00443  // contained in the right monomial...
00444  if (rightm != leftm) {
00445   
00446   m.data_AddElements(
00447    right.data_GetArray(rightidx+1),
00448    right.data_GetCount()-rightidx-1);
00449   
00450   // and last, remove the right monomial...
00451   data_Delete(leftm+1);
00452   data_MoveElemLeft(leftm+1);
00453  }
00454  
00455  // remove the monomials placed between the two containing
00456  // the LEFT and the RIGHT bracket...
00457  for (int g=leftm+1; g < rightm; g++) {
00458   
00459   data_Delete(leftm+1);
00460   data_MoveElemLeft(leftm+1);
00461  }
00462     
00463  mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ")
00464   wxT("after removing replaced elements, I'm set to [%s]"), mcTXTTHIS); 
00465     
00466  // move cursor to a valid position
00467  if (mcMathCore::Get()->isGUIEnabled())
00468   mgui_nCursorPos = leftm;
00469     
00470  // stop here
00471  data_Check();
00472  return TRUE;  // a pair of mcParenthesis have been replaced
00473 }
00474     
00475 bool mcPolynomialHelpers::data_ReplaceParentheses(bool bMoveOnBracketEnd)
00476 {
00477  bool bFoundFirst = FALSE; // TRUE if the LEFT bracket has already been found
00478 
00479  int monomialidx = -1, // the index of the monomial containing the LEFT bracket
00480   bracketidx = -1; // the bracket's index of the LEFT bracket
00481 
00482  int bridx = -1,   // the current bracket's index in the current monomial
00483   i;     // the index of the current monomial
00484  
00485  for (i=0; i < data_GetCount(); i++) {
00486   
00487   // skip non-monomials...
00488   if (data_Get(i).data_GetType() != mcET_MONOMIAL)
00489    continue;
00490   
00491   // ok, process this monomial...
00492   const mcMonomial &m = (const mcMonomial &)data_Get(i);
00493   
00494   // ...scanning all its elements...
00495   for (int j=0, max=m.data_GetCount(); j < max; j++) {
00496    
00497    const mcElement &curr = m.data_Get(j);
00498    if (curr.data_GetType() != mcET_PARENTHESIS)
00499     continue;
00500     
00501    // get a pointer to the just found parenthesis
00502    bridx = j;
00503    const mcParenthesis &p = m.data_Get(bridx);
00504    
00505    if (!bFoundFirst) {
00506     
00507     // wait for the next...
00508     if (!p.data_isLeftBracket())
00509      continue;
00510     
00511     // ok, we have found the left parenthesis... now,
00512     // we can go on searching its counterpart...
00513     bFoundFirst = TRUE;
00514     monomialidx = i;
00515     bracketidx = bridx;
00516     
00517     // copy the elements which are contained in the current
00518     // monomial and which follow the parenthesis in the
00519     // polynomial which will be used as the content array
00520     // for the new bracket element we are trying to create...
00521     
00522    } else {
00523     
00524     
00525     if (p.data_isLeftBracket()) {
00526      
00527      // hmmmm, we have find a left bracket instead of
00528      // a right bracket... update our indexes because
00529      // inner brackets must be solved as firsts
00530      monomialidx = i;
00531      bracketidx = bridx;
00532      continue;
00533     }
00534     
00535     // proceed with replacement
00536     return data_ReplaceParentheses(monomialidx, bracketidx, i, 
00537             bridx, bMoveOnBracketEnd);
00538    }
00539   }
00540  }
00541  
00542  // no mcParenthesis have been replaced
00543  return FALSE;
00544 }
00545 
00546 void mcPolynomialHelpers::data_ReplaceAllParentheses()
00547 {
00548  bool exit = FALSE;
00549  while (!exit) {
00550 
00551   // higly probably, cursor position will be invalid
00552   // after this operations...
00553   exit = !data_ReplaceParentheses(FALSE);
00554  }
00555 }
00556 
00557 void mcPolynomialHelpers::gui_ReplaceBracket(const mcBracket &br, bool left)
00558 {
00559  mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - replacing the %s of [%s]"),
00560     (left ? wxT("left") : wxT("right")), mcTXT(br));
00561  mcPolynomial contents(br.data_GetConstContent());
00562  mcMonomial &m = mcEmptyMonomial;
00563 
00564  int monomialidx = -1, // the index of the monomial containing 'br'
00565   pcursoridx = -1, // a copy of the index of the previous monomial
00566   bridx = -1,   // the "br"'s index inside data_Get(monomialidx)
00567   mcursoridx = -1; // the index of the element preceding "br"
00568 
00569  // this is a prerequisite...
00570  mcASSERT(contents.data_GetCount() > 0, wxT("Cannot break an empty bracket..."));
00571 
00572  // first of all, find the monomial which contains the bracket which
00573  // must be replaced by mcParenthesis + its contents...
00574  for (int i=0; i < data_GetCount(); i++) {
00575 
00576   // discard non-monomial elements
00577   if (data_Get(i).data_GetType() != mcET_MONOMIAL)
00578    continue;
00579   const mcMonomial &tocheck = (const mcMonomial &)data_GetConst(i);
00580   
00581   // does this monomial contains the bracket to replace ?
00582   if ((bridx = tocheck.data_GetIndexOf(br)) != -1) {
00583    monomialidx = i;  // save these info
00584    pcursoridx = monomialidx;
00585    mcursoridx = bridx-1;
00586    m = tocheck;
00587    break;
00588   }
00589  }
00590 
00591  mcASSERT(m != mcEmptyElement, wxT("Something wrong"));
00592  mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - the monomial ")
00593    wxT("with the bracket to replace is [%s]"), mcTXT(m));
00594  m.data_Delete(bridx);
00595  m.data_MoveElemLeft(bridx);
00596 
00597  // ok, add the left parenthesis if the parenthesis which had been removed
00598  // is the RIGHT one...
00599  if (!left) {
00600 
00601   mcParenthesis left;
00602   left.data_SetAsLeftBracket();
00603   left.data_AddProperty(mcEP_INITIALIZED);
00604   m.data_AddElements(&left, 1, bridx);
00605   bridx++;
00606 
00607   mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - the monomial is [%s]"), mcTXT(m));
00608  }
00609 
00610  // maybe that the first element of the bracket is not a monomial but a
00611  // mcAddOp or a mcSubOp... better check...
00612  mcMonomial &first = (mcMonomial &)contents.data_GetElemOfType(0, mcET_MONOMIAL);
00613  if (contents.data_Get(0).data_GetType() == mcET_MONOMIAL) {
00614   m.data_AddElements(first.data_GetArray(), 
00615        first.data_GetCount(), bridx);
00616   //bridx = m.data_GetIndexOf(br);
00617 
00618   // delete this monomial since it's already been added
00619   contents.data_Delete(0);
00620   contents.data_MoveElemLeft(0);
00621  }
00622 
00623  mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - the monomial is [%s]"), mcTXT(m));
00624 
00625  // add the monomials contained in the just-removed bracket
00626  if (contents.data_GetCount() > 1) {
00627  
00628   data_Merge(contents);
00629   monomialidx += contents.data_GetCount();
00630  }
00631  
00632  m = (mcMonomialHelpers *)data_Get(monomialidx).hlp();
00633 
00634  // if the parenthesis which must result as the removed one is the
00635  // LEFT, we must add the RIGHT one...
00636  if (left) {
00637   mcParenthesis right;
00638   right.data_SetAsRightBracket();
00639   right.data_AddProperty(mcEP_INITIALIZED);
00640   m.data_AddElements(&right, 1, bridx+1);
00641 
00642   mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - the monomial is [%s]"), mcTXT(m));
00643  }
00644 
00645 
00646  // set the cursor in the right position
00647  if (!left) {
00648   mgui_nCursorPos = monomialidx;
00649 
00650   // move the monomial cursor too
00651   if (bridx+1 >= m.data_GetCount())
00652    m.gui_SetCursorPos(mcCP_END);
00653   else
00654    m.gui_SetCursorOnElemEnd(bridx+1);
00655  }
00656 
00657  if (left) {
00658 
00659   // move cursor
00660   mgui_nCursorPos = pcursoridx;
00661   m = (mcMonomialHelpers *)data_Get(pcursoridx).hlp();
00662 
00663   if (mcursoridx < 0) {
00664 
00665    // there were no elements before the bracket; the cursor
00666    // must be placed at the beginning of the monomial...
00667    m.gui_SetCursorPos(mcCP_BEGIN);
00668 
00669   } else {
00670 
00671    // place the cursor on the element which was preceding the
00672    // bracket we replaced...
00673    m.gui_SetCursorOnElemEnd(mcursoridx);
00674   }
00675  }
00676 
00677  // ok, we have finished....
00678  data_Check(); 
00679  mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - we are now ")
00680    wxT("set to [%s]"), mcTXTTHIS);
00681 }
00682 
00683 int mcPolynomialHelpers::data_FindMonomialContaining(int occ, const mcElement &elem) const
00684 {
00685  int n = -1;
00686 
00687  for (int i=0; i < data_GetCount(); i++) {
00688   
00689   // skip non monomial elements
00690   if (data_Get(i).data_GetType() != mcET_MONOMIAL) continue;
00691 
00692   // search, non-recursively, in this monomial
00693   if ((n = mcMonomial(data_Get(i)).data_GetIndexOf(elem)) != -1) {   
00694    if (occ == 0)
00695     return n;
00696    occ--;  // try with next occurrence
00697   }
00698  }
00699 
00700  // could not find any result
00701  return -1;
00702 }
00703 
00704 
00705 
00706 
00707 
00708 
00709 
00710 // ----------------------------------------
00711 // mcPOLYNOMIALGUI
00712 // ----------------------------------------
00713 
00714 bool mcPolynomialHelpers::gui_isArrayEmpty()
00715 {
00716  if (data_isArrayEmpty() || (data_GetCount() == 1 && data_isOp(0)))
00717   return TRUE;
00718  return FALSE;
00719 }
00720 
00721 int mcPolynomialHelpers::gui_ExDraw(wxDC &dc, int x, int y, long flags, const wxPoint &pt, int cl) const
00722 {
00723  mcGUILOG(wxT("mcPolynomialHelpers::gui_ExDraw [%s]"), mcTXTTHIS);
00724  int a = gui_GetSelElemCount();
00725  
00726  // if a selection among two or more monomials is present in the polynomial, 
00727  // draw it ourselves, if a selection is present but it is limited to one
00728  // monomial only, let that monomial draw it...
00729  if (a > 1) {
00730 
00731   // we will care about the selection rectangle drawing...
00732   int mflags = flags & ~mcDRW_ALLOW_TOTAL_SELECTION;
00733 
00734   // the selection is "extended": draw only non-selected monomials
00735   int w, n = mcElementArrayHelpers::gui_ExDraw(dc, x, y, mflags, pt, cl);
00736 
00737   // draw selection rectangle + selected monomials & 
00738   // check if we must change return code
00739   if ((w=gui_DrawSelection(dc, x, y, flags, pt, cl)) != mcDRW_NOACTIVEELEM)
00740    n = w;
00741   return n;
00742  } 
00743 
00744  return mcElementArrayHelpers::gui_ExDraw(dc, x, y, flags, pt, cl, FALSE, -1, TRUE);
00745 }
00746 
00747 void mcPolynomialHelpers::gui_ExOnSelect(wxDC &dc, wxRect &rc, int cl)
00748 {
00749  // select elements using the mcElementArray function
00750  mcElementArrayHelpers::gui_ExOnSelect(dc, rc, cl);
00751 
00752  // adjust selection if required, selecting the operators which are
00753  // placed before completely selected monomials
00754  for (int a=gui_GetSelStart(), b=gui_GetSelEnd(); a < b; a++)
00755   if (data_Get(a).gui_isAllSelected())
00756    if (a > 0 && data_isOp(a-1))
00757     data_Get(a-1).gui_SelectAll();
00758 }
00759 
00760 int mcPolynomialHelpers::gui_AddNewElement(mcElementType type, const mcKey &key, int pos)
00761 {
00762  //mcElementType m = mcMathCore::Get().isKeyBeginKey(key);
00763  if (pos == -1) pos = data_GetCount();
00764 
00765  // check we are going to add the right type of element !!!
00766  mcASSERT(type == mcET_MONOMIAL || type == mcET_ADDOP || type == mcET_SUBOP, 
00767   wxT("Cannot create something which is not a mcOperator or a mcMonomial !!!!"));
00768  mcElementArrayHelpers::gui_AddNewElement(type, key, pos);
00769 
00770  // check if we have added a new operator
00771  if (type == mcET_ADDOP || type == mcET_SUBOP) {
00772   if (pos == data_GetCount()-1 || data_isOp(pos+1)) {
00773 
00774    // handle the case:
00775    //     ... ab| ...     user creates a mcAddOp or a mcSubOp
00776    // which is also the case of:
00777    //     ... ab|+c ...   user creates a mcAddOp or a mcSubOp
00778    pos++;
00779    data_MoveElemRight(pos);
00780    gui_AddNewEmptyMonomial(pos);
00781    
00782   } else if (pos > 0 && data_isOp(pos-1)) {
00783    
00784    // handle the case:
00785    //    ... ab+|bc ...     user creates a mcAddOp or a mcSubOp
00786    //
00787    // In this case cursor must not be moved: it is
00788    // already placed on the new monomial !!!
00789    //
00790    data_MoveElemRight(pos);
00791    gui_AddNewEmptyMonomial(pos);
00792 
00793   } else if (pos == 0) {
00794 
00795    // handle the case:
00796    //        |ab+bc+cd ...  user creates a mcAddOp or a mcSubOp
00797    // 
00798    // In this case, we are going to add an operator in the
00799    // first position of the array !!!   
00800    pos++;
00801   }
00802  }
00803 
00804  gui_RecalcSize();
00805  return pos;
00806 }
00807 
00808 mcInputRes mcPolynomialHelpers::gui_Input(const mcKey &ev, mcElement *newelem)
00809 {
00810  // in this function we must handle ONLY a special case: a mcAddSubOp
00811  // placed in the first entry of the array, thus working 
00812  // as unary operator.
00813  //
00814  // NOTE: if we are wrapping only a mcEmptyBox, then the mcCP_END and
00815  //       mcCP_BEGIN flags coincide: since we don't know what mcEmptyBoxes
00816  //       return as cursor position (the cursor can be placed only in a
00817  //       single position inside a mcEmptyBox and thus it does not make
00818  //       sense to refer to a leftmost or rightmost position)
00819  //
00820  if (gui_GetCursorPos().isBegin() || data_isWrappingOnly(mcET_EMPTYBOX)) {
00821   mcElementType n = mcElementHelpers::gui_isKeyBeginKey(ev);
00822 
00823   if (n == mcET_ADDOP || n == mcET_SUBOP) {
00824 
00825    bool replace = FALSE;
00826 
00827    // don't send this to the first (eventually present) monomial...
00828    // instead, add it at the beginning of the array (eventually
00829    // replacing a previously present first operator...)
00830    if (data_GetCount() > 0 && data_isOp(0))
00831     replace = TRUE;
00832    mcElement &e = data_AddNewElement(n, replace, 0);
00833 
00834    // need to recalc the size
00835    e.gui_RecalcSize();
00836 
00837    // do not forget the cursor set on a mcOperator...
00838    if (!replace) mgui_nCursorPos++;
00839    gui_CheckCursorPos();
00840 
00841    gui_RecalcSize();
00842    return mcIR_OKAY;
00843   }
00844 
00845  }
00846 
00847  // UNTESTED !!!
00848  mcElementType n = mcElementHelpers::gui_isKeyBeginKey(ev);
00849  if (n == mcET_PARENTHESIS)
00850   gui_OnNewParenthesis(mcBracketHelpers::gui_isLeftParenthesis(ev.GetKeyCode()));
00851 
00852  // let the base class function handle everything...
00853  mcInputRes r = mcElementArrayHelpers::gui_Input(ev, newelem);
00854 
00855  // this is a special routine for mcParenthesis
00856  if (mgui_bRemoveParenthesis) {
00857   data_ReplaceParentheses(!mgui_bMoveCursorAtBracketBegin);
00858   mgui_bRemoveParenthesis = FALSE;
00859   gui_DeepRecalcSize();
00860  }
00861 
00862  if (mgui_pBracketToReplace != mcEmptyElement) {
00863   gui_ReplaceBracket(mgui_pBracketToReplace, mgui_bRemoveLeftParenthesis);
00864   mgui_pBracketToReplace = NULL;
00865   gui_DeepRecalcSize();
00866  }
00867 
00868  return r;
00869 }
00870 
00871 mcInputRes mcPolynomialHelpers::gui_BackInput(const mcKey &key, mcElement *pnewelem, int n)
00872 {
00873  int last;
00874  bool b;
00875 
00876  switch (n) {
00877  case mcIR_OKAY:
00878   break;
00879 
00880  case mcIR_REPLACE_THIS:
00881   if (mgui_nCursorPos == 0) {
00882    mcMathCore::Get()->SyntaxError(wxT("Cannot data_Delete this element"));
00883    return mcIR_OKAY;
00884   }
00885 
00886   // data_Delete the focused element & shift left to close the hole in the array
00887   data_Delete(mgui_nCursorPos);
00888   data_MoveElemLeft(mgui_nCursorPos);
00889 
00890   // close last hole with the new element overwriting the old one
00891   data_AddElements(pnewelem, 1, mgui_nCursorPos-1, TRUE);
00892   mgui_nCursorPos--;
00893   (*pnewelem) = NULL;
00894 
00895   // do not continue processing of other flags
00896   return mcIR_OKAY;
00897 
00898  case mcIR_DELETE_THIS:
00899 
00900   if (mgui_nCursorPos == 0 && data_GetCount() > 1) {
00901    // handle the case:
00902    //     __|__ + abc ...        user data_Deletes the empty box
00903    //
00904    return mcIR_DELETE_PREVIOUS;
00905   }
00906   
00907   // data_Delete the current monomial
00908   data_Delete(mgui_nCursorPos);
00909   data_MoveElemLeft(mgui_nCursorPos);
00910   
00911   if (mgui_nCursorPos > 0) {
00912    
00913    // data_Delete the + or - operator which precedes the data_Deleted monomial
00914    mcASSERT(data_isOp(mgui_nCursorPos-1), wxT("An operator was expected"));
00915    data_Delete(mgui_nCursorPos-1);
00916    data_MoveElemLeft(mgui_nCursorPos-1);
00917    mgui_nCursorPos--;
00918    
00919    // check if we have just data_Deleted the first operator of the array
00920    if (mgui_nCursorPos == 0) {
00921     
00922     // if we had an operator placed at the beginning of the array,
00923     // and the user want to data_Delete it when the cursor is placed
00924     // over the 
00925     data_MoveElemRight(0);
00926     gui_AddNewEmptyMonomial(0);
00927     return mcIR_OKAY;
00928    }
00929   }
00930   
00931   // move cursor left (this must be done AFTER the eventual
00932   // remotion of the previous operator !!!!)
00933   mgui_nCursorPos--;
00934 
00935   if (mgui_nCursorPos >= 0) {
00936    if (mcMathCore::Get()->m_pCancelKey->MatchKey(key))
00937     data_Get(mgui_nCursorPos).gui_SetCursorPos(mcCP_BEGIN);
00938    else if (mcMathCore::Get()->m_pDeleteKey->MatchKey(key))
00939     data_Get(mgui_nCursorPos).gui_SetCursorPos(mcCP_END);  
00940   }
00941   
00942   // was it the last monomial of the array (and was it containing 
00943   // an emptybox) ?
00944   if (data_isArrayEmpty())
00945    return mcIR_DELETE_THIS;  // the array is empty !!!
00946   break;
00947 
00948  case mcIR_DELETE_PREVIOUS:
00949 
00950   // the focused monomial asked us to data_Delete the previous element, which is
00951   // sure an operator + or -. This means that we must merge the focused
00952   // monomials with the previous one.
00953   
00954   if (mgui_nCursorPos == 0) {
00955 
00956    // cannot data_Delete the previous element because it doesn't exist !!!
00957    return mcIR_DELETE_PREVIOUS;
00958   }
00959 
00960   // what if the monomial asked to data_Delete the first operator in the array ?
00961   if (mgui_nCursorPos == 1) {
00962    
00963    // the user can see the first operator and he wants to data_Delete it;
00964    // we cannot data_Delete first operator but we can reset it to a +
00965    // and hid it...
00966    // the user will think that an operator does not exist anymore
00967    // but the appearances deceive... :-)
00968    mcASSERT(data_isOp(0), wxT("If the first element is not an operator, cursor")
00969     wxT("is acutally placed on an operator..."));
00970    data_Delete(0);
00971    data_MoveElemLeft(0);
00972    mgui_nCursorPos--;
00973    return mcIR_OKAY;
00974   }
00975 
00976   // merge the two monomials
00977   b = mcMonomial(data_Get(mgui_nCursorPos-2)).gui_MergeWith(data_Get(mgui_nCursorPos));
00978   mcASSERT(b, wxT("Two monomials should always be able to merge..."));
00979 
00980   // data_Delete the old monomial and its operator
00981   data_Delete(mgui_nCursorPos-1);
00982   data_Delete(mgui_nCursorPos);
00983   data_MoveElemLeft(mgui_nCursorPos);
00984   data_MoveElemLeft(mgui_nCursorPos-1);
00985 
00986   // move cursor to the monomial
00987   mgui_nCursorPos -= 2;
00988 
00989   // do some checks
00990   data_Check();
00991   gui_CheckCursorPos();
00992   break;
00993 
00994  case mcIR_DELETE_NEXT:
00995     
00996   // the focused monomial asked us to data_Delete the next element, which is
00997   // sure an operator + or -. This means that we must merge the focused
00998   // monomials with the next one.
00999 
01000   last = data_GetCount()-1;
01001   if (mgui_nCursorPos == last) {
01002 
01003    // no elements following...
01004    return mcIR_DELETE_NEXT;
01005   }
01006 
01007   // cursor check
01008   mcASSERT(mgui_nCursorPos < last-1, wxT("If the monomial cannot end with an operator ")
01009     wxT("and the cursor is not on the last monomial, it must be placed ")
01010     wxT("on the previous monomial, which should be at data_GetCount()-2"));
01011 
01012   // merge the two monomials
01013   b = mcMonomial(data_Get(mgui_nCursorPos)).gui_MergeWith(data_Get(mgui_nCursorPos+2));
01014   mcASSERT(b, wxT("Two monomials should always be able to merge..."));
01015   mcUNUSED(b);
01016 
01017   // data_Delete the old monomial and its operator
01018   data_Delete(mgui_nCursorPos+1);
01019   data_Delete(mgui_nCursorPos+2);
01020   data_MoveElemLeft(mgui_nCursorPos+1);
01021   data_MoveElemLeft(mgui_nCursorPos+1);
01022 
01023   // do some checks
01024   data_Check();
01025   gui_CheckCursorPos();
01026   break;
01027 
01028  case mcIR_DISTRIBUTE:
01029   mcASSERT(pnewelem != NULL && *pnewelem != mcEmptyElement, 
01030    wxT("No element to distribute !!"));
01031 
01032   if (pnewelem->data_GetType() == mcET_BRACKET) {
01033 
01034    // this is the case when the user tries to delete the right
01035    // or left parenthesis of a mcBracket element...
01036    bool left = ((const mcBracket *)pnewelem)->hlp()->mgui_bRemoveLeftBracket;
01037    gui_SetBracketToReplace(*pnewelem, left);
01038   }
01039   break;
01040 
01041  default:
01042   mcASSERT(0, wxT("Unhandled return flag"));
01043  }
01044 
01045  return mcIR_OKAY;
01046 }
01047 
01048 mcInsertRes mcPolynomialHelpers::gui_Insert(const mcElement &toinsert, mcElement *)
01049 {
01050  mcCursorPos cp(data_Get(mgui_nCursorPos).gui_GetCursorPos());
01051 
01052  //if (cp.isInside() || cp.isBeginEnd()) {
01053   
01054   mcInsertRes r = data_Get(mgui_nCursorPos).gui_Insert(toinsert, NULL);
01055 
01056  /* switch (r) {
01057   case mcINSR_OKAY:
01058    return mcINSR_OKAY;
01059 
01060   case mcINSR_REPLACE_THIS:
01061    break;
01062   }
01063  }*/
01064 
01065  return mcINSR_OKAY;
01066 
01067  /*if (toinsert.data_GetType() != mcET_POLYNOMIAL)
01068   return data_Get(mgui_nCursorPos).gui_Insert(toinsert, NULL);
01069 */
01070  return mcINSR_OKAY;
01071 }
01072 
01073 void mcPolynomialHelpers::gui_SetCursorPos(const mcCursorPos &code)
01074 {
01075  // do not use default mcElementArrayHelpers::gui_SetCursorPos: it works for the
01076  // all the elements without doing any distinction between operators and
01077  // non operators elements: we need mcElementArrayHelpers::gui_SetCursorPosSkippingOp()...
01078  mcElementArrayHelpers::gui_SetCursorPos/*SkippingOp*/(code);
01079 }
01080 
01081 void mcPolynomialHelpers::gui_CheckCursorPos() const
01082 {
01083  // check that cursor is not beyond upper and lower limit
01084  if (data_GetCount() > 0) {
01085 
01086   // cursor position must be a valid integer in the range 0, data_GetCount()-1
01087   mcASSERT(data_isValidElem(mgui_nCursorPos), 
01088     wxT("Cursor placed on an invalid element !"));
01089   mcASSERT(mgui_nCursorPos >= 0, 
01090     wxT("Cursor position undefined"));
01091   mcASSERT(mgui_nCursorPos < data_GetCount(), 
01092     wxT("Cursor position is beyond upper limit"));
01093 
01094   mcASSERT(!data_Get(mgui_nCursorPos).gui_GetCursorPos().isUndefined(),
01095      wxT("Cursor position undefined"));
01096 
01097  } else {
01098 
01099   // array is empty; cursor position should be 0
01100   mcASSERT(mgui_nCursorPos == -1, wxT("Array is empty, wrong cursor position"));
01101  }
01102  
01103  // check that cursor is not inside an operator
01104  if (!data_isArrayEmpty()) {
01105   mcASSERT(!data_isEmptyEntry(mgui_nCursorPos), wxT("Cursor position is wrong"));
01106   mcASSERT(!data_isOp(mgui_nCursorPos), wxT("Cursor position is wrong"));
01107  } 
01108 }
01109 
01110 void mcPolynomialHelpers::gui_DoSplit(mcElementType type, const mcKey &key)
01111 {
01112  mcElement ptmp = mcEmptyElement;
01113 
01114  mcASSERT(type == mcET_ADDOP || type == mcET_SUBOP, 
01115   wxT("The splitter elements can be only mcAddOp or mcSubOp"));
01116 
01117  // split the element in two parts; by now, this function
01118  // can be used only by mcNumbers & mcMonomials...
01119  bool b = data_Get(mgui_nCursorPos).gui_Split(&ptmp);
01120  mcASSERT(!b, wxT("A monomial asked us to be deleted ?"));
01121  mcUNUSED(b);  // to avoid warnings
01122  
01123  // go on only if the element to split support that function
01124  mcASSERT(ptmp != mcEmptyElement, wxT("Tried to split an element which does not support splitting"));
01125  
01126  // create an hole in the array and fill it with the second part of
01127  // the splitted monomial
01128  data_MoveElemRight(mgui_nCursorPos+1);
01129  data_Set(mgui_nCursorPos+1, ptmp);
01130  
01131  // create another hole between the old and the new monomial
01132  data_MoveElemRight(mgui_nCursorPos+1);
01133  
01134  // and fill it with the splitter operator
01135  data_AddNewOp(type, mgui_nCursorPos+1);
01136  
01137  // adjust cursor on the new monomial
01138  mgui_nCursorPos +=2;
01139 }
01140 
01141 int mcPolynomialHelpers::data_AddNewEmptyMonomial(int pos)
01142 {
01143  // this function uses the begin key of a mcEmptyBox to create
01144  // the new empty monomial: in this way we can use all the
01145  // GUI input rules encoded in mcPolynomialHelpers::gui_math_AddNewElement 
01146  // for free....
01147  if (pos == -1) pos = data_GetCount();
01148 
01149  // add a new monomial containing only an empty box
01150  mcMonomial m;  // create a new
01151  mcElement &box = m.data_AddNewElement(mcET_EMPTYBOX);
01152  box.data_AddProperty(mcEP_INITIALIZED);
01153 
01154  data_AddElements(&m, 1, pos);
01155  data_Check();
01156 
01157  return pos;
01158 }
01159 
01160 void mcPolynomialHelpers::gui_AddNewEmptyMonomial(int pos)
01161 {
01162  // this function uses the begin key of a mcEmptyBox to create
01163  // the new empty monomial: in this way we can use all the
01164  // GUI input rules encoded in mcPolynomialGUI::AddNewElement 
01165  // for free....
01166  mcKey fake(mcEmptyBoxHelpers::sgui_pNewEmptyBox->GetEvent(), TRUE);
01167  if (pos == -1) pos = data_GetCount();
01168 
01169  // add a new monomial containing only an empty box
01170  mgui_nCursorPos = gui_AddNewElement(mcET_MONOMIAL, fake, pos);
01171 }
01172 
01173 
01174 
01175 
01176 
01177 
01178 
01179 // ----------------------------------------
01180 // mcPOLYNOMIALIO
01181 // ----------------------------------------
01182 
01183 wxXml2Node mcPolynomialHelpers::io_GetMathML(bool bdata_GetPresentation) const
01184 {
01185  // if this mcPolynomial contains just one element, we can just return
01186  // the MathML piece of that element without using an MROW
01187  if (data_GetCount() == 1) {
01188   
01189   // too easy... :-)
01190   return data_Get(0).io_GetMathML(bdata_GetPresentation);
01191  }
01192   
01193  // begin MROW section
01194  wxXml2Node maintag;
01195  maintag.CreateTemp(wxXML_ELEMENT_NODE, wxXml2EmptyDoc, wxT("mrow"));
01196 
01197  // for each monomial, also take in count its first operator
01198  for (int i=0; i < data_GetCount(); i++) {
01199 
01200   // THIS PIECE OF CODE SHOULD BE USED IF THE OPERATORS WHICH LINK
01201   // THE MONOMIALS ARE CONTAINED IN THE MONOMIAL'S ARRAY: THIS IS
01202   // NOT THE BEHAVIOUR OF THE CURRENT MATH'S STRUCTURE but I do not 
01203   // want to data_Delete this code because it could still be useful in
01204   // future !!!
01205   /* data_Get the + or - from this monomial
01206   mcElement p = ((mcMonomial &)data_Get(i))->data_Get(0);
01207   if (i != 0 || p.data_GetType() != mcET_OPERATOR || p->data_GetSubType() != mcET_ADDOP) {
01208 
01209    // it's really necessary to insert this operator....
01210    maintag.math_AddChild(p.io_GetMathML(bdata_GetPresentation));
01211   }*/
01212 
01213   // get the mrow section from this monomial
01214   wxXml2Node node(data_Get(i).io_GetMathML(bdata_GetPresentation));
01215   maintag.AddChild(node);
01216  }
01217 
01218  return maintag;
01219 }
01220 
01221 wxString mcPolynomialHelpers::io_GetInlinedExpr() const
01222 {
01223  wxString str;
01224 
01225  // concatenate the inlined expressions which compose the math contents
01226  for (int i=0; i < data_GetCount(); i++) {
01227   
01228   // A LITTLE POLYNOMIAL-SPECIFIC BEHAVIOUR:
01229   // since the sign of a monomial is stored both in the monomial's
01230   // coefficient 
01231   wxString tmp = data_Get(i).io_GetInlinedExpr();
01232   //if (!data_isOp(i) && tmp.StartsWith("-")) tmp.Remove(0, 1);
01233 
01234   str += tmp;
01235  }
01236 
01237 
01238  return str;
01239 }
01240 
01241 bool mcPolynomialHelpers::io_ImportPresentationMathML(wxXml2Node tag, wxString &err)
01242 {
01243  wxXml2Node p, toinsert = wxXml2EmptyNode;
01244  //mcElement ptmp = NULL;
01245  //int res = mcIR_OKAY;
01246 
01247  // BE SURE TO data_Delete EVERYTHING BEFORE IMPORTING !!!!
01248  data_DeleteAll();
01249 
01250  p = tag.GetChildren();
01251  while (p != wxXml2EmptyNode) {
01252   
01253   if (p.GetType() == wxXML_ELEMENT_NODE && p.GetName() == wxT("mo")) {
01254    
01255    // this is an operator, like + or -, separing two monomials;
01256    // send it as init tag to the monomial
01257    toinsert = p;
01258 
01259   } else if (p.GetType() == wxXML_ELEMENT_NODE && p.GetName() != wxT("mrow")) {
01260    
01261    // mcMonomial requires everything to be encapsulated in an MROW,
01262    // but this monomial is not; let's do ourselves
01263    /*wxXml2Node tmp(wxXML_ELEMENT_NODE, wxT("mrow"));
01264    wxXml2Node *firstchild = new wxXml2Node(*p);
01265    tmp.data_SetChildren(firstchild);
01266    
01267      if (!pnew.io_ImportPresentationMathML(&tmp, err))
01268    return FALSE;*/
01269    p.Encapsulate(wxT("mrow"));
01270   }
01271   
01272   if (p.GetType() == wxXML_ELEMENT_NODE && p.GetName() == wxT("mrow")) {
01273    
01274    // create a new monomial to parse this node
01275    mcMonomial pnew;
01276    
01277    // adds the last MO child of the main tag if it was present
01278    if (toinsert != wxXml2EmptyNode) {
01279     p.GetChildren().AddPrevious(toinsert);
01280     toinsert = wxXml2EmptyNode;
01281    }
01282    
01283    // just a normal MROW representing a monomial...
01284    if (!pnew.io_ImportPresentationMathML(p, err))
01285     return FALSE;
01286    
01287    // add our new monomial in this array
01288    data_AddElements(&pnew, 1);
01289   }
01290   
01291   // proceed with next
01292   p = p.GetNext();
01293  }
01294 
01295  return TRUE;
01296 }
01297 
01298 bool mcPolynomialHelpers::io_ImportInlinedExpr(const wxString &todecode, int *c, 
01299             wxString &pErr, int mlimit)
01300 {
01301  wxString token(todecode);
01302  int count, n = 0;
01303 
01304  // BE SURE TO data_Delete EVERYTHING BEFORE IMPORTING !!!!
01305  data_DeleteAll();
01306 
01307  while (!token.IsEmpty() && (mlimit < 0 || n < mlimit))
01308  {
01309   // now, check if we must add an operator...  
01310   wxString str = token.GetChar(0);  
01311   mcElementType newop = mcElementHelpers::io_isCharBeginChar(str);
01312   if (mcOperatorHelpers::data_isOp(newop)) {
01313    
01314    // add the operator and remove it from the token string
01315    data_AddNewElement(newop);
01316    token.Remove(0, 1);
01317    
01318   } else {
01319    
01320    // if this is not the first time this while() cycle has
01321    // been run and there is no operator to separe previously
01322    // imported monomial from the next one.... then there's a
01323    // BIG problem...
01324    mcASSERT(data_isArrayEmpty(), 
01325     wxT("A mcPolynomial must contain mcMonomials *always* ")
01326     wxT("interleaved with mcAddOp/mcSubOps"));   
01327   }
01328   
01329   // and add it to this array
01330   mcMonomial pnew;
01331   n++;
01332 
01333   // import a new monomial
01334   if (!pnew.io_ImportInlinedExpr(token, &count, pErr))
01335    return FALSE;
01336    
01337   // update the token string
01338   data_AddElements(&pnew, 1);
01339   token = token.Right(token.Len()-count);
01340  }
01341 
01342  // store the number of characters imported
01343  if (c) *c = todecode.Len()-token.Len();
01344 
01345  // a little exception for parentheses:
01346  // try to replace all mcParenthesis with mcBrackets... 
01347  mcIOLOG(wxT("mcPolynomialHelpers::io_ImportInlinedExpr - before pruning brackets: [%s]"), mcTXTTHIS);
01348  data_ReplaceAllParentheses();
01349 
01350  // remove all the mcParenthesis which could not be replaced with
01351  // mcBrackets....
01352  for (int i=0, max=data_GetNumOfElemType(mcET_MONOMIAL); i < max; i++) {
01353   mcMonomial &m = (mcMonomial &)data_GetElemOfType(i, mcET_MONOMIAL);
01354 
01355   // do the hard work...
01356   m.data_DeleteAllElemType(mcET_PARENTHESIS);
01357   m.data_Repair();
01358  }
01359 
01360  mcIOLOG(wxT("mcPolynomialHelpers::io_ImportInlinedExpr - after pruning brackets: [%s]"), mcTXTTHIS);
01361 
01362  // extra-work required ?
01363  io_PostProcessChildren();
01364 
01365  return TRUE;
01366 }
01367 
01368 
01369 
01370 
01371 
01372 // ----------------------------------------
01373 // mcPOLYNOMIALMATH
01374 // ----------------------------------------
01375 
01376 mcPolynomial mcPolynomialHelpers::math_GetPolynomialWrapper() const
01377 {
01378  mcPolynomial pol(this);
01379 
01380  // it is very important to detach pol from us:
01381  // we could modify ourselves, later and this would
01382  // result in an automatic modification of the polynomial
01383  // which we are returning now...
01384  pol.data_MakePrivateCopy();
01385 
01386  return pol;
01387 }
01388 
01389 mcArrayEntry mcPolynomialHelpers::math_WrapMonomial(const mcMonomial &mon)
01390 {
01391  // TOTEST:
01392  data_DeleteAll();
01393 
01394  // just add the given monomial to this array
01395  int midx = data_AddElements((mcElement *)(&mon), 1); 
01396 
01397  // and return a reference to its entry in the array...
01398  data_Check();
01399  return mcArrayEntry(this, mcMAKEPOL_IDX(midx, 0));
01400 }
01401 
01402 mcArrayEntry mcPolynomialHelpers::math_WrapSimple(const mcElement &p)
01403 {
01404  // we have to do just a little check...
01405  if (p.data_GetType() != mcET_MONOMIAL) {
01406 
01407   // create a monomial wrapper for the given element
01408   mcMonomial m;
01409   int idx = m.data_AddElements(&p, 1);
01410 
01411   // add the monomial to the array and then return a reference
01412   // not to the monomial we've added but to the element which
01413   // was wrapped into the monomial we wrapped...
01414   mcArrayEntry ret = math_WrapMonomial(m);
01415   ret.data_SetIdx((ret.mdata_idx << 16) | idx);  
01416   return ret;
01417  }
01418 
01419  // we don't need to wrap anything: it's already a mcMonomial...
01420  return math_WrapMonomial(mcMonomial(p));
01421 }
01422 
01423 mcElementArray mcPolynomialHelpers::math_CreateWrapperFor(const mcElement &toembed) const
01424 {
01425  if (toembed.data_GetType() != mcET_MONOMIAL && 
01426   toembed.data_GetType() != mcET_POLYNOMIAL) {
01427   
01428   // before creating a mcPolynomial and adding to it "toembed" 
01429   // (as mcElementArrayHelpers::CreateWrapperFor does),
01430   // wrap "toembed" in a mcMonomial...
01431   mcMonomial tmp;
01432   tmp.math_WrapSimple(toembed);
01433   return mcElementArrayHelpers::math_CreateWrapperFor(tmp);
01434  }
01435 
01436  return mcElementArrayHelpers::math_CreateWrapperFor(toembed);
01437 }
01438 
01439 int mcPolynomialHelpers::math_DataToMathIdx(int dataindex) const
01440 {
01441  // discard invalid cases
01442  data_CheckIndex(dataindex);
01443  if (data_isOp(dataindex)) // op are not mapped in math coord
01444   return -1;
01445 
01446  // using the shift we are sure that both 4/2 and 5/2 will give as result 2.
01447  // This is required when the array begins with an operator and thus
01448  // the given index can be odd and nonetheless referring to a mcMonomial...
01449  return (dataindex >> 1);
01450 }
01451 
01452 int mcPolynomialHelpers::math_MathToDataIdx(int mathindex) const
01453 {
01454  if (mathindex < 0 || mathindex >= math_GetCount()) {
01455 
01456   mcMATHLOG(wxT("mcPolynomialHelpers::math_MathToDataIdx [%s] - ")
01457    wxT("invalid conversion required"), mcTXTTHIS);
01458   return -1;  // no conversion is possible
01459  }
01460 
01461  // Perform a quick conversion taking in count the rule which 
01462  // is respected in each valid mcPolynomial: between two monomials
01463  // there is *always* a mcAddOp/mcSubOp which divides them.
01464  // Also takes in count that the operator may contain an operator
01465  // as first entry which could alter the formula...
01466  return mathindex*2 + (int)(data_isOp(0));
01467 }
01468 
01469 
01470 
01471 
01472 
01473 
01474 
01475 
01476 
01477 // ------------------------------------
01478 // mcPOLYNOMIALMATH - sign management
01479 // ------------------------------------
01480 
01481 int mcPolynomialHelpers::math_GetSign(int n) const
01482 {
01483  // get the index of the n-th monomial
01484  n = math_MathToDataIdx(n);
01485  mcASSERT(n != -1, wxT("Invalid index !!"));
01486  
01487  // if there is no operator at the begin of the array, it's by default +.
01488  if (n == 0) return 1;
01489  mcASSERT(data_isAddSubOp(n-1),
01490   wxT("A polynomial must contain monomials always separated by mcAddOp or mcSubOp"));
01491  
01492  return (data_Get(n-1).data_GetType() == mcET_ADDOP) ? 1 : -1;
01493 }
01494 
01495 void mcPolynomialHelpers::math_SetSign(int n, int sgn)
01496 {
01497  int i = math_MathToDataIdx(n);
01498  
01499  if (i > 0) {
01500   
01501   // we are sure that the i-th monomial is not the first
01502   // element of the array: an operator is sure preceding it...
01503   mcASSERT(data_isOp(i-1), wxT("A monomial should always be preceded by an op"));
01504   
01505   // change the previous operator
01506   data_AddNewOp(((sgn < 0) ? mcET_SUBOP : mcET_ADDOP), i-1);
01507   
01508  } else {
01509   
01510   if (sgn < 0) {
01511 
01512    // add a new mcSubOp operator at the beginning of the array
01513    data_MoveElemRight(0);
01514    data_AddNewOp(mcET_SUBOP, 0);
01515    //mcMATHLOG("[%s]", mcTXTTHIS);
01516    
01517   } else {
01518    
01519    // we should add a mcAddOp at the beginning of the array:
01520    // quite useless; just do nothing
01521   }
01522  }
01523 }
01524 bool mcPolynomialHelpers::math_DeleteFirstOp()
01525 {
01526  if (data_isArrayEmpty() || 
01527   !data_isOp(0))
01528   return FALSE;   // there is no first operator
01529  
01530  if (data_isOp(0) && 
01531   data_Get(0).data_GetType() != math_GetNeutralOpType())
01532   return FALSE;   // nothing to delete/that can be deleted
01533 
01534  // the first element of the array is a mcAddOp; we can safely remove it
01535  data_Delete(0);
01536  data_MoveElemLeft(0);
01537  return TRUE;
01538 }
01539 
01540 mcExpSimRes mcPolynomialHelpers::math_Reorder()
01541 {
01542  mcMATHLOG(wxT("mcPolynomialHelpers::math_Reorder - going to reorder [%s]"), mcTXTTHIS);
01543 
01544  // we need to have an array containing *everywhere*
01545  // the pattern OPERATOR + MONOMIAL: the ReorderElements function
01546  // cannot work with variable-lenght patterns...
01547  data_CreateFirstOp();
01548  int n = math_ReorderElements(data_GetArray(), data_GetCount(), 1, 2);
01549  data_Check();
01550 
01551  // eventually remove the first operator we were forced to add
01552  math_DeleteFirstOp();
01553  mcMATHLOG(wxT("mcPolynomialHelpers::math_Reorder - result is [%s]"), mcTXTTHIS);
01554  
01555  // did we moved anything ?
01556  return (n == 0 ? mcESR_DONE : mcESR_NOTFINISHED);
01557 }
01558 
01559 void mcPolynomialHelpers::math_ChangeAllSigns()
01560 {
01561  for (int i=0; i < math_GetCount(); i++)
01562   math_ChangeSign(i);
01563 }
01564 
01565 void mcPolynomialHelpers::math_SyncCoeffWithSigns()
01566 {
01567  // scan the array resetting signs
01568  for (int i=0,max=math_GetCount(); i < max; i++) {
01569 
01570   mcRealValue coeff = math_Get(i).math_GetCoeff();
01571   
01572   if (coeff < 0) {
01573 
01574    // since the coefficient of the monomial is negative,
01575    // we must change not only the mcOperator in front of it,
01576    // but also its coefficient...
01577    math_SetSign(i, -1);  // this changes the operator before the monomial
01578    //math_Get(i).math_Abs();
01579 
01580    mcMATHLOG(wxT("mcPolynomialHelpers::math_SyncCoeffWithSigns - I set ")
01581     wxT("the sign of the [%s] monomial (which has coeff [%s]) to NEGATIVE"), 
01582     mcTXT(math_Get(i)), mcTXTV(coeff));
01583 
01584   } else if (coeff > 0) {
01585 
01586    // the coeff of the monomial is positive
01587    math_SetSign(i, +1);  // this changes the operator before the monomial   
01588 
01589    mcMATHLOG(wxT("mcPolynomialHelpers::math_SyncCoeffWithSigns - I set ")
01590     wxT("the sign of the [%s] monomial (which has coeff [%s]) to POSITIVE"), 
01591     mcTXT(math_Get(i)), mcTXTV(coeff));
01592 
01593   } else {
01594 
01595    // the coeff of the monomial is exactly zero...
01596    // do nothing since this monomial is useless
01597   }
01598  }
01599 }
01600 
01601 const mcNumber &mcPolynomialHelpers::math_GetNumSign(const mcMonomial &tofind, int n) const
01602 {
01603  int pos = math_NonRecursiveFindInChildren(n, tofind.hlp());
01604  if (pos < 0) return mcEmptyNumber;
01605 
01606  // we've found the given monomial, now gets its sign
01607  int sign = math_GetSign(pos);
01608  return (sign == 1 ? *mcNumberHelpers::smath_pOne : *mcNumberHelpers::smath_pMinusOne);
01609 }
01610 
01611 void mcPolynomialHelpers::math_PackSign(mcMonomial &m, int occ) const
01612 {
01613 #ifdef EXTENDED_COEFF
01614  mcMonomial num = m.math_GetCoeff();
01615 #else
01616  mcNumber num = m.math_GetCoeff();
01617 #endif
01618  mcNumber mult = math_GetNumSign(m, occ);
01619  mcASSERT(mult != mcEmptyElement, wxT("We could not find 'm'"));
01620 
01621  num.math_SimpleMultiplyBy(mult);
01622  m.math_SetCoeff(num);
01623 }
01624 
01625 
01626 
01627 
01628 
01629 // ---------------------------------------
01630 // mcPOLYNOMIALMATH - monomial management
01631 // ---------------------------------------
01632 
01633 int mcPolynomialHelpers::math_FindMonomialContaining(const mcElement &elem, 
01634               int occ, int *res) const
01635 {
01636  int n = -1;
01637  for (int i=0,max=math_GetCount(); i < max; i++) {
01638   
01639   // search, non-recursively, in this monomial
01640   n = math_Get(i).math_GetIndexOf(occ, elem);
01641   if (n != -1) {
01642 
01643    // so we need to store the entry of the element we've found ?
01644    if (res) *res = n;
01645    return i;
01646   }
01647  }
01648 
01649  // could not find any result
01650  return -1;
01651 }
01652 
01653 const mcMonomial &mcPolynomialHelpers::math_GetMonomialContaining(const mcElement &elem, 
01654                  int occ, int *res) const
01655 {
01656  int idx = math_FindMonomialContaining(elem, occ, res);
01657 
01658  if (idx != -1)
01659   return math_Get(idx);
01660  return mcEmptyMonomial;
01661 }
01662 
01663 mcMonomial mcPolynomialHelpers::math_GetCoeffOf(int mathidx, const mcElement *toremove, 
01664             int ntoremove) const
01665 {
01666  // data_Get a copy of the monomial...
01667  mcMonomial res = math_Get(mathidx);
01668 
01669  // ...remove all the elements required from the copy
01670  for (int i=0; i < ntoremove; i++)
01671   res.math_Delete(0, toremove[i], FALSE);
01672 
01673  // and pack the sign of the monomial inside it if it's required
01674  if (math_GetSign(mathidx) == -1) math_PackSign(res);
01675 
01676  return res;
01677 }
01678 
01679 mcMonomial mcPolynomialHelpers::math_GetCoeffOf(const mcSymbolProperties *sym, 
01680            const mcPolynomial &exp, int occ) const
01681 {
01682  mcMATHLOG(wxT("mcPolynomialHelpers::math_GetCoeffOf [%s] - searching [%s]^[%s]"),
01683     mcTXTTHIS, mcTXTP(sym), mcTXT(exp));
01684 
01685  // create a temporary object linked to the given symbol
01686  // and with the given exponent
01687  mcSymbol s(sym->data_GetSafeLinkedSym());
01688 
01689  if (exp.math_isWrappingOnly(0.0)) {
01690 
01691   int n = -1;
01692 
01693   // search the zero-degree term
01694   for (int i=0; i < math_GetCount(); i++) {
01695    if (!math_Get(i).math_Contains(s)) {
01696 
01697     n++;
01698 
01699     // copy this monomial, which should be the only
01700     // one not to contain the given symbol,
01701     if (n == occ) return mcMonomial(math_Get(i));
01702    }
01703   }
01704 
01705   return mcEmptyMonomial;
01706  }
01707 
01708  s.math_SetExp(exp);
01709 
01710  // then, find it 
01711  int n = -1;
01712  const mcMonomial &res = math_GetMonomialContaining(s, occ, &n);
01713  if (res == mcEmptyMonomial) return mcEmptyMonomial;
01714 
01715  // copy it (don't modify the array !!)
01716  mcMonomial m(res);
01717 
01718  // we could use data_GetCoeffOf in this way:
01719  // mcMonomial &ret = data_GetCoeffOf(pos, (const mcElement &*)&s, 1);
01720  // mcSAFE_data_Delete(s);
01721  // but since we already know where s is placed (at n-th pos), proceed
01722  // without using the other data_GetCoeffOf (and repeating some code):
01723  m.math_Remove(n, FALSE);
01724 
01725  //if (m.math_math_GetSign() == -1) PackSign(m);
01726  //mcASSERT(0, "");
01727 
01728  return m;
01729 }
01730 
01731 mcMonomial mcPolynomialHelpers::math_GetCoeffOf(const mcSymbolProperties *sym, 
01732             const mcRealValue &exp, int occ) const
01733 {
01734  mcPolynomial tmp;
01735  tmp.math_WrapNumber(exp);
01736 
01737  // data_Get a copy of the monomial and remove the symbol we've just found
01738  mcMonomial ret = math_GetCoeffOf(sym, tmp, occ);
01739  //mcSAFE_data_Delete(tmp);
01740 
01741  return ret;
01742 }
01743 
01744 mcIntegerValue mcPolynomialHelpers::math_GetMaxDegreeFor(const mcSymbolProperties *sym) const
01745 {
01746  mcIntegerValue max = 0;
01747 
01748  for (int i=0; i < math_GetCount(); i++) {
01749   
01750   // collect the max degree for this symbol from the i-th monomial
01751   mcIntegerValue d = math_Get(i).math_GetMaxDegreeFor(sym);
01752   if (!d.isValid()) return *mcIntegerValue::pNAN;
01753 
01754   // and check it against the max degree for all previous monomials
01755   max = max.GetMax(d);
01756  }
01757 
01758  mcASSERT(max.isValid(), wxT("Something really wrong"));
01759  return max;
01760 }
01761 
01762 mcExpSimRes mcPolynomialHelpers::math_SimplifySolveOp(long flags)
01763 {
01764  bool stilltowork = FALSE;
01765 
01766  mcMATHLOG(wxT("mcPolynomialHelpers::math_SimplifySolveOp"));
01767 
01768  // cannot store data_GetCount()-1 because elements maybe removed in the loop
01769  for (int i=0; i < math_GetCount(); i++) {
01770   
01771   // get left operand
01772   mcMonomial &left = math_Get(i);
01773   mcOperator &lp = math_GetOpPreceding(i);
01774   
01775   for (int j=0; j < math_GetCount(); j++) {
01776 
01777    // get right one
01778    mcMonomial &right = math_Get(j);
01779    if (i == j) continue;
01780    
01781    // get the i-th operator of the array
01782    mcOperator &rp = math_GetOpPreceding(j);
01783    if (rp == mcEmptyElement) continue;
01784    mcMATHLOG(wxT("mcPolynomialHelpers::math_SimplifySolveOp - I'm trying to apply ")
01785     wxT("the op [%s] between the [%s] and [%s] elements"), 
01786     mcTXT(rp), mcTXT(left), mcTXT(right));
01787 
01788    // apply the op
01789    mcElement rep = mcEmptyElement;
01790    mcBasicOpRes res;
01791    int sign=1;
01792    
01793    if (lp.data_GetType() == rp.data_GetType()) {
01794 
01795     mcOperator *op = (mcOperator *)mcElementHelpers::data_GetInstanceOf(mcET_ADDOP);
01796     res = op->math_Apply(left, right, &rep);
01797     if (res == mcBOR_INVALID)
01798      continue;
01799 
01800    } else {
01801 
01802     mcOperator *op = (mcOperator *)mcElementHelpers::data_GetInstanceOf(mcET_SUBOP);
01803     res = op->math_Apply(left, right, &rep);
01804     if (lp.data_GetType() == mcET_SUBOP)
01805      sign=-1;
01806     if (res == mcBOR_INVALID)
01807      continue;
01808 
01809     // set the monomial's sign accordingly to the
01810     // result of the ADD/SUBTRACT operation and
01811     // accordingly with the sign of the monomial
01812     // before the operation
01813     if (left.math_GetCoeff() < 0) {
01814      math_SetSign(i, -1*sign);
01815      math_Get(i).math_Abs();
01816     } else {
01817      math_SetSign(i, 1*sign);
01818     }
01819    }
01820    
01821    // the operator could be applied...
01822    stilltowork = TRUE;
01823    mcMATHLOG(wxT("mcPolynomialHelpers::math_SimplifySolveOp - applied ")
01824     wxT("the op [%s] between the [%s] and [%s] elements"), 
01825     mcTXT(rp), mcTXT(left), mcTXT(right));
01826    
01827    // handle res
01828    math_HandleBasicOpRes(res, rep, j);
01829   }
01830  }
01831 
01832  if (stilltowork)
01833   return mcESR_NOTFINISHED;
01834  return mcESR_DONE;
01835  //return mcElementArrayHelpers::math_SimplifySolveOp(flags);
01836 }
01837 
01838 mcExpSimRes mcPolynomialHelpers::math_Simplify(long flags, mcElement *newelem)
01839 {
01840  mcLOG(wxT("mcPolynomialHelpers::math_Simplify"));
01841  
01842  // perform array simplification 
01843  mcExpSimRes r = mcElementArrayHelpers::math_Simplify(flags, newelem);
01844  math_DeleteFirstOp();
01845  if (r != mcESR_DONE) return r;
01846  
01847  // additional simplification step:
01848  //if (math_DeleteFirstOp())  // remove the first op when it's useless (+)
01849  // return mcESR_NOTFINISHED; 
01850 
01851  // additional simplification step #2:
01852  //math_FactoreOut();
01853   
01854  return mcESR_DONE;  // there was no first operator to data_Delete...
01855 }
01856 
01857 
01858 
01859 
01860 
01861 // ---------------------------------------
01862 // mcPOLYNOMIALMATH - basic operations
01863 // ---------------------------------------
01864 
01865 mcBasicOpRes mcPolynomialHelpers::math_Add(const mcElement &e, mcElement *pp, bool add)
01866 {
01867  mcMATHLOG(wxT("mcPolynomialHelpers::math_Add [%s] - I'm %s [%s]"), mcTXTTHIS, 
01868   (add == TRUE ? wxT("adding") : wxT("subtracting")), mcTXT(e));
01869  mcPolynomial p(e);
01870  
01871  if (p.data_isArrayEmpty())
01872   return mcBOR_REMOVE_OPERAND;
01873  
01874  if (add) {
01875 
01876   // don't force the creation of the "+" operator if this array is empty
01877   // or if the given array already has a first op...
01878   if (!this->data_isArrayEmpty() &&
01879    !p.data_isOp(0)) {
01880    
01881    data_AddNewOp(mcET_ADDOP);
01882   }
01883   
01884   // now we can merge with the given polynomial
01885   data_Merge(p);
01886   
01887  } else {
01888   
01889   mcPolynomial p2(p);
01890   
01891   // a - b = a + (-b) .....
01892   p2.math_ChangeAllSigns();
01893   mcMATHLOG(wxT("[%s]"), mcTXT(p2));
01894   math_SimpleAdd(p2);
01895  }
01896  
01897  data_Check();
01898  
01899  return mcBOR_REMOVE_OPERAND;
01900 }
01901 
01902 mcBasicOpRes mcPolynomialHelpers::math_MultiplyBy(const mcElement &e, mcElement *pp)
01903 {
01904  if (data_isArrayEmpty())
01905   return mcBOR_REMOVE_OPERAND;
01906 
01907  mcPolynomial p(e);
01908  mcPolynomial pnew = mcEmptyElement;
01909 
01910  // if this array contains more than one monomial,
01911  // or just a negative element, bracket it.
01912  if (math_GetCount() > 1 || math_GetSign(0) == -1) {
01913   
01914   // bracketize everything
01915   mcElementArrayHelpers::math_EmbedInBracket();
01916  }
01917 
01918  // if the given array to multiply contains more than one 
01919  // monomial, bracket a copy of it
01920  if (p.math_GetCount() > 1) {
01921 
01922   // we cannot modify the given element !!!!
01923   pnew = p;
01924   p = pnew;
01925 
01926   // bracket the copy of the given array
01927   p.math_EmbedInBracket();
01928   //p.math_data_DeleteFirstOp();
01929  }
01930 
01931  // now, both the operands contains one monomial only....
01932  mcASSERT(p.math_GetCount() == 1, wxT("Something wrong"));
01933  mcASSERT(this->math_GetCount() == 1, wxT("Something wrong"));
01934 
01935  // ... and we can now multiply them
01936  mcBasicOpRes r = math_Get(0).math_MultiplyBy(p.math_Get(0), pp);
01937 
01938  // clean up if necessary
01939  //if (pnew) data_Delete pnew;
01940 
01941  // check that everything is okay
01942  data_Check();
01943 
01944  // handle the returned flag....
01945  switch (r) {
01946  case mcBOR_INVALID:
01947  case mcBOR_REPLACE_OPERAND:
01948  case mcBOR_REPLACE_BOTH:
01949   mcASSERT(0, wxT("Two monomials which cannot be multiplied ?"));
01950 
01951  case mcBOR_REMOVE_OPERAND:
01952   return mcBOR_REMOVE_OPERAND;
01953 
01954  default:
01955   mcASSERT(0, wxT("TODO"));
01956  }
01957 
01958  return mcBOR_REMOVE_OPERAND;
01959 }
01960 
01961 mcBasicOpRes mcPolynomialHelpers::math_DivideBy(const mcElement &pol, mcElement *pp)
01962 {
01963  if (data_isArrayEmpty())
01964   return mcBOR_REMOVE_OPERAND;
01965 
01966  // create a fraction with the current contents as numerator,
01967  // the given polynomial as denominator
01968  mcASSERT(pol.data_GetType() == mcET_POLYNOMIAL, wxT("see math_DivideBy() description..."));
01969  math_EmbedInFraction().data_GetFraction().data_SetDen(pol);
01970 
01971  mcMATHLOG(wxT("mcPolynomialHelpers::math_DivideBy - dividing by [%s], result is [%s]"),
01972     mcTXT(pol), mcTXTTHIS);
01973 
01974  return mcBOR_REMOVE_OPERAND;
01975 }
01976 
01977 
01978 
01979 
01980 
01981 
01982 // ---------------------------------------
01983 // mcPOLYNOMIALMATH - miscellaneous
01984 // ---------------------------------------
01985 
01986 /*
01987 mcElement mcPolynomialHelpers::math_GetLCM(const mcElement &p) const
01988 {
01989  // work on copies
01990  mcPolynomial b(p);
01991  b.math_EmbedInBracket();
01992 
01993  math_SimpleMultiplyBy(b);
01994  //data_Delete b;
01995 
01996  return b;
01997 }
01998 */
01999 
02000 void mcPolynomialHelpers::math_DeleteSelection()
02001 {
02002  // data_Delete the elements selected
02003  gui_DeleteSelection();
02004  data_Check();
02005 }
02006 
02007 mcIntegerValue mcPolynomialHelpers::math_RaiseGetCoeff(int *indexes, int m)
02008 {
02009  mcIntegerValue res = 1;
02010  
02011  // we must calculate the coefficient in this way:
02012  //
02013  //  ( indexes[0] ) ( indexes[1] ) ( indexes[2] )  
02014  //  (            ) (            ) (            ) ....
02015  //  ( indexes[1] ) ( indexes[2] ) ( indexes[3] ) 
02016  //
02017  for (int x=0; x < m; x++)
02018   res *= mcIntegerValue::GetComb(indexes[x], indexes[x+1]);
02019  
02020  return res;
02021 }
02022 
02023 bool mcPolynomialHelpers::math_CanBeRaisedTo(const mcPolynomial &pol) const
02024 {
02025  int count = math_GetCount();
02026 
02027  // see mcPolynomialHelpers::math_RaiseChildrenTo about
02028  // the way these cases are handled
02029  if (count == 0 || count == 1)
02030   return TRUE;
02031 
02032  // for more children, then we need that the given exponent
02033  // contains just a number
02034  if (!pol.math_isWrappingNumOnly())
02035   return FALSE;
02036 
02037  mcRealValue r(pol.math_GetWrappedNumber());
02038 
02039  if (r.isInteger())
02040   return TRUE;
02041  return FALSE;
02042 }
02043 
02044 void mcPolynomialHelpers::math_RaiseTo(const mcRealValue &r)
02045 {
02046  mcMATHLOG(wxT("mcPolynomialHelpers::math_RaiseChildrenTo [%s] - raising to [%s]"),
02047     mcTXTTHIS, mcTXTV(r));
02048  mcIntegerValue n = r;
02049 
02050  // first of all, handle the simplest cases
02051  if (math_GetCount() == 0) 
02052   return;   // no elements to modify
02053 
02054  if (math_GetCount() == 1) {
02055 
02056   // we contain only a single monomial:
02057   // (a)^1432.4432423[...] = a^1432.4432423[...]
02058   math_Get(0).math_RaiseTo(r);
02059   return;
02060  }
02061 
02062  // then, check if the given value is okay
02063  if (!r.isInteger()) {
02064 
02065   // we are in such a situation:
02066   //     (a+b+c+d+...z)^1432.4432423[...]
02067   // that is, we cannot raise this polynomial to a real value:
02068   // we can just bracketize the polynomial and set that value
02069   // as the exponent of the bracket...
02070   math_EmbedInBracketAndRaiseTo(r);
02071   return;
02072 
02073  } else if (n == 1) {
02074 
02075   // we are raising something to one...
02076   // (a+b+c+...)^1 = a+b+c+...
02077   return;
02078  }
02079 
02080  mcMATHLOG(wxT("mcPolynomialHelpers::math_RaiseTo - raising %d monomials to %s"),
02081           math_GetCount(), n.GetStr().c_str());
02082  int x, m = math_GetCount(), *indexes = new int[m+2];
02083  
02084  // first index must be n, last must be zero
02085  // (like also all other indexes, even if these ones
02086  // will be incremented at the end of the while cycle)
02087  indexes[0] = n.GetInt();
02088  for (x=1; x < m+2; x++)
02089   indexes[x] = 0;
02090  
02091  mcPolynomial res;
02092  bool exit = FALSE;
02093  int level = 1;
02094  while (!exit) {
02095   
02096   mcMonomial mx;
02097 
02098   // this is the sign of the "mx" monomial: 1=+   -1=-
02099   int sign = 1;
02100   
02101   // calc the coeff for this new monomial through the
02102   // formula explained in the "Formulas & Algorithms used"
02103   // section in the docs
02104   mcIntegerValue coeff = math_RaiseGetCoeff(indexes, m);
02105   mx.math_WrapNumber(coeff);
02106   mcMATHLOG(wxT("mcPolynomialHelpers::math_RaiseTo - the coeff of the %d-th monomial is %s"),
02107       res.math_GetCount(), coeff.GetStr().c_str());
02108   for (int y=0; y < m; y++) {
02109    
02110    // get the y-th monomial of *this
02111    mcMonomial tmp(math_Get(y));
02112    
02113    // raise it (update global monomial sign)
02114    int exp = indexes[y]-indexes[y+1];
02115 
02116    // do not create a lot of a^0, b^0 and...
02117    if (exp != 0) {
02118 
02119     // ... do not create a lot of a^1, b^1 (create a, b)
02120     if (exp != 1) tmp.math_RaiseTo(mcPolynomial(exp));
02121     sign *= (int)pow(math_GetSign(y), exp);
02122 
02123     // and add it to the new polynomial we are building
02124     mx.math_MultiplyBy(tmp, NULL);
02125    }
02126   }
02127   
02128   res.math_SimpleAdd(mx, (sign == 1 ? TRUE : FALSE));
02129   
02130   // advance indexes 
02131   if (level < m) {
02132    
02133    // advance index level
02134    indexes[level]++;
02135    if (level+1 < m || indexes[level] == indexes[level-1])
02136     level++;
02137 
02138   } else if (level == m) {
02139    
02140    // reset those levels which have been completed
02141    level--;
02142    bool startcycle = FALSE;
02143    while (indexes[level-1] <= indexes[level]) {
02144     indexes[level] = 0;
02145     level--;
02146     startcycle = TRUE;
02147     
02148     if (level == 0) {
02149      
02150      // we have completed the
02151      // outermost cicle and thus
02152      // we have done our duty
02153      exit = TRUE;
02154      break;
02155     }
02156    }
02157    
02158    // ok, we can start a new cycle at a new level
02159    if (startcycle) {
02160     indexes[level]++;
02161     level++;
02162    }
02163   }
02164  }
02165 
02166  delete indexes;
02167  data_DeepCopy(res.chlp());
02168 }
02169 
02170 mcBasicOpRes mcPolynomialHelpers::math_RaiseTo(const mcPolynomial &p)
02171 {
02172  if (math_CanBeRaisedTo(p)) {
02173 
02174   if (math_GetCount() == 0) 
02175    return mcBOR_REMOVE_OPERAND;  // no elements to modify
02176 
02177   if (math_GetCount() == 1)
02178    return math_Get(0).math_RaiseTo(p);
02179 
02180   // unwrap the number contained in the given polynomial and
02181   // raise everything to it...
02182   math_RaiseTo(p.math_GetWrappedNumber());
02183   return mcBOR_REMOVE_OPERAND;
02184  }
02185 
02186  // cannot do anything else...
02187  math_EmbedInBracketAndRaiseTo(p);
02188  return mcBOR_REMOVE_OPERAND;
02189 }
02190 /*
02191 void mcPolynomialHelpers::math_Bracketize(int *n, int count)
02192 { 
02193  mcBracket br;
02194 
02195  int max = math_GetCount();
02196  for (int i=0; i < count; i++) {
02197 
02198   mcASSERT(n[i] < max, wxT("Invalid index"));
02199  
02200   // collect this monomial
02201   mcMATHLOG(wxT("mcPolynomialHelpers::math_Factorize - factorizing [%s]"), mcTXT(math_Get(n[i])));
02202   bool add = (math_GetSign(n[i]) == 1 ? TRUE : FALSE);
02203   br.data_GetContent().math_SimpleAdd(math_Get(n[i]), add);  
02204  }
02205 
02206  // now remove those monomials added to the bracket
02207  for (int j=0; j < count; j++) {
02208 
02209   mcMATHLOG(wxT("mcPolynomialHelpers::math_Factorize - removing [%s]"), mcTXT(math_Get(n[j]-j)));
02210 
02211   // we need to offset this index by j since each time we remove
02212   // a monomial all the other ones are shifted left
02213   math_Remove(n[j]-j);
02214  }
02215 
02216  // add the bracket to replace them
02217  math_SimpleAdd(br);
02218 }*/
02219 /*
02220 mcMonomial mcPolynomialHelpers::math_GetFactors() const
02221 {
02222  mcPolynomial res;
02223 
02224  res.math_ResetToOne();
02225  for (int i=0,max=math_GetCount(); i<max; i++) {
02226   mcMonomial factor = math_Get(i).math_GetFactors();
02227   res.math_Get(0).math_GetLCM(factor);
02228  }
02229 
02230  return res;
02231 }
02232 */
02233 void mcPolynomialHelpers::math_Factorize(int *n, int count)
02234 {
02235 
02236 }
02237 
02238 mcMonomial mcPolynomialHelpers::math_GetGCDFor(int *n, int count) const
02239 {
02240  mcMonomial gcd(mcEmptyElement);
02241  bool all = FALSE;
02242 
02243  if (math_GetCount() == 0)
02244   return mcEmptyElement;
02245 
02246  if (count==-1) { 
02247 
02248   // we want to get the GCD among *all* the monomials
02249   count = math_GetCount(); 
02250   all = TRUE;
02251 
02252   // take initially as the GCD of the array the first monomial... 
02253   gcd = math_Get(0);
02254 
02255  } else {
02256 
02257   // get as GCD the first given index
02258   mcASSERT(count >= 1, wxT("Invalid count of elements"));
02259   gcd = math_Get(n[0]);
02260  }
02261 
02262  for (int i=1; i<count; i++) {
02263 
02264   mcMonomial m(mcEmptyElement);
02265   if (all)
02266    m = math_Get(i);
02267   else
02268    m = math_Get(n[i]);
02269  
02270   // ... then compute the GCD between the first (i-1)-th already
02271   // processed monomials and the i-th
02272   gcd = gcd.math_GetGCD(m);
02273  }
02274 
02275  return gcd;
02276 }
02277 
02278 void mcPolynomialHelpers::math_FactoreOut(int *n, int count, bool bForceUseless)
02279 {
02280  // we need at least two monomials...
02281  if (math_GetCount() <= 1) return;
02282 
02283  // we've got the GCD for all the monomials of the array:
02284  // we should do nothing if it is 1.0
02285  mcMonomial gcd(math_GetGCDFor(n, count));
02286  bool gcdisone = gcd.math_isWrappingOnly(1.0);
02287  if (gcdisone && !bForceUseless)
02288   return;
02289  mcMATHLOG(wxT("mcPolynomialHelpers::math_FactoreOut - the GCD ")
02290     wxT("among all my monomials is [%s]"), mcTXT(gcd));
02291 
02292  // BEFORE:
02293  //                a + b + c + d ...
02294  // AFTER:
02295  //         n*(a/n + b/n + c/n + d/n ...)
02296  //
02297  // where n = GCD(a,b,c,d,...)
02298  // 
02299  mcArrayEntry br = math_EmbedInBracket(n, count);
02300  mcPolynomial &contents = br.data_GetBracket().data_GetContent();
02301 
02302  if (gcdisone || contents.math_GetCount() <= 1)
02303   return;
02304  
02305  // divide _all_ bracket's monomials by the GCD we've computed...
02306  for (int j=0,max=contents.math_GetCount(); j<max; j++)
02307   contents.math_Get(j).math_SimpleDivideBy(gcd); 
02308 
02309  // last touch: the factor we've just created must
02310  // multiply the bracket.
02311  mcMonomial &m = (mcMonomial &)math_GetMonomialContaining(br.data_GetRef());
02312  m.math_SimpleMultiplyBy(gcd);
02313 
02314  data_Check();
02315 }
02316 
02317 void mcPolynomialHelpers::math_FactoreOut(const mcSymbolProperties *unk,
02318             const mcPolynomial &pol,
02319             bool bForceUseless)
02320 {
02321  // stop here and avoid a lot of calculus if we contain a single monomial...
02322  if (math_GetCount() <= 1) return;
02323 
02324  // we'll create an array as large as this array so we are
02325  // sure that we won't need to extend it...
02326  int *arr = new int[math_GetCount()];
02327  int count=0;
02328 
02329  // fill the array with the indexes of those monomials containing
02330  // the given symbol...
02331  for (int i=0,max=math_GetCount(); i < max; i++)
02332   if (math_Get(i).math_ContainsSymbol(unk, pol))
02333    arr[count++] = i;
02334 
02335  // then, just factore out everything possible from those monomials...
02336  if (count == 0) {
02337   delete [] arr;
02338   return;  // no such symbol found
02339  }
02340 
02341  math_FactoreOut(arr, count, bForceUseless);
02342  delete [] arr;
02343 }
02344 
02345 void mcPolynomialHelpers::math_FactoreOutFreeOf(const mcSymbolProperties *unk,
02346             const mcPolynomial &pol,
02347             bool bForceUseless)
02348 {
02349  // stop here and avoid a lot of calculus if we contain a single monomial...
02350  if (math_GetCount() <= 1) return;
02351 
02352  // we'll create an array as large as this array so we are
02353  // sure that we won't need to extend it...
02354  int *arr = new int[math_GetCount()];
02355  int count=0;
02356 
02357  // fill the array with the indexes of those monomials containing
02358  // the given symbol...
02359  for (int i=0,max=math_GetCount(); i < max; i++)
02360   if (!math_Get(i).math_ContainsSymbol(unk, pol))
02361    arr[count++] = i;
02362 
02363  // then, just factore out everything possible from those monomials...
02364  if (count == 0) {
02365   delete [] arr;
02366   return;  // no such symbol found
02367  }
02368 
02369  math_FactoreOut(arr, count, bForceUseless);
02370  delete [] arr;
02371 }
02372 
02373 void mcPolynomialHelpers::math_FactoreOut(const mcSymbolArray *arr)
02374 {
02375  // just factore out all the symbols contained in the given array
02376  for (int i=0; i < arr->data_GetCount(); i++)
02377   math_FactoreOut(arr->data_GetSymbol(i), mcEmptyPolynomial, FALSE);
02378 }
02379 
02380 void mcPolynomialHelpers::math_FactoreOutConstants()
02381 { math_FactoreOut(&mcSymbol::arrConstants); }
02382 
02383 void mcPolynomialHelpers::math_FactoreOutUnknowns()
02384 { math_FactoreOut(&mcSymbol::arrUnknowns); }
02385 
02386 void mcPolynomialHelpers::math_FactoreOutParameters()
02387 { math_FactoreOut(&mcSymbol::arrParameters); }
02388 
02389 mcExpSimRes mcPolynomialHelpers::math_HandleExpSimFlag(mcExpSimRes r, mcElement *pnew, int i)
02390 {
02391  // only mcPolynomials can handle this flag...
02392  if (r == mcESR_DISTRIBUTE) {
02393 
02394   mcMonomial &m = (mcMonomial &)data_Get(i);
02395   int pnewidx = m.data_GetIndexOf(*pnew);
02396 
02397   // this is a flag returned only by a few elements: handle it with
02398   // some specialized code...
02399   if (pnew->data_GetType() == mcET_BRACKET)
02400    math_DistributeBracket(i, pnewidx);
02401   else {
02402 
02403    // we have specialized code for this case but this
02404    // one is missing....
02405    mcASSERT(0, wxT("Unhandled case..."));
02406   }
02407 
02408   return mcESR_NOTFINISHED;
02409  }
02410 
02411  // only mcPolynomials can handle this flag...
02412  if (r == mcESR_CHANGE_SIGN) {
02413 
02414   math_ChangeSign(math_DataToMathIdx(i));
02415   return mcESR_NOTFINISHED;
02416  }
02417 
02418  return mcElementArrayHelpers::math_HandleExpSimFlag(r, pnew, i);
02419 }
02420 
02421 void mcPolynomialHelpers::math_DistributeBracket(int mdataidx, int bridx)
02422 {
02423  mcASSERT(data_Get(mdataidx).data_GetType() == mcET_MONOMIAL, 
02424   wxT("the first parameter is the data index of the monomial with the bracket to expand")); 
02425  int signbeforebr = 1;
02426 
02427  // extract the monomial with the bracket to expand
02428  mcMonomial m = data_Detach(mdataidx);   // the monomial containing the bracket
02429  data_MoveElemLeft(mdataidx);
02430  mcASSERT(m.data_GetElemIndexOfType(0, mcET_BRACKET) == m.math_MathToDataIdx(bridx),
02431   wxT("the given monomial should contain the bracket to expand at the given math idx"));
02432 
02433  // extract the bracket and its contents
02434  mcBracket br = m.math_Get(bridx);    // the bracket to distribute
02435  mcPolynomial brcontents = br.data_GetContent();
02436  mcMATHLOG(wxT("mcPolynomialHelpers::math_DistributeBracket - the bracket's contents are [%s]"), mcTXT(brcontents));
02437 
02438  // remember the type of operator placed before the bracket
02439  if (mdataidx > 0 && data_isAddSubOp(mdataidx-1)) {
02440   signbeforebr = (data_Get(mdataidx-1).data_GetType() == mcET_ADDOP) ? 1 : -1;
02441   data_MoveElemLeft(mdataidx-1);
02442   mdataidx--;
02443  }
02444 
02445  // if we are contained in a monomial, then we can use
02446  // the DISTRIBUTIVE property to create a new polynomial 
02447  // that we can use to replace our parent:
02448  //
02449  //   P + Q + XY(a + b + c)WZ + R + S           superparent
02450  //           XY(a + b + c)WZ                   parent
02451  //
02452  // final results:
02453  //
02454  //   P + Q + XYaWZ + XYbWZ + XYcWZ + R + S     superparent
02455  //           XYaWZ + XYbWZ + XYcWZ             (*newelem)
02456  //
02457 
02458  // second, create pnewcount monomials inside of pnew
02459  int pnewcount = brcontents.math_GetCount();
02460  int mcount = m.math_GetCount();
02461  for (int n=0; n < pnewcount; n++) {
02462 
02463   // third, init the n-th monomial with a simple "1"
02464   mcMonomial newm;
02465   newm.math_ResetToOne();
02466   int add = 1;
02467 
02468   // four, fill each monomial with the factors of the parent
02469   for (int i=0; i < mcount; i++) {
02470 
02471    mcElement tomult = m.data_Get(i);
02472    if (tomult == br) {
02473 
02474     // do not multiply by this bracket, but by the n-th element 
02475     // contained _inside_ this bracket
02476     tomult = brcontents.math_Get(n);
02477 
02478     // remember the sign which is preceding that monomial
02479     add = brcontents.math_GetSign(n);
02480 
02481     // multiply by an entire monomial, not just a simple element
02482     newm.math_SimpleMultiplyBy(tomult);
02483     
02484    } else {
02485     
02486     // tomult should not be a mcElementArray-derived class:
02487     // it should be a simple element.
02488     newm.math_SimpleMultiplyBy(tomult);
02489    }
02490   }
02491 
02492   // be sure that the monomial is okay
02493   newm.data_Check();
02494 
02495   // last, add this monomial to the newp
02496   //newp.math_SimpleAdd(&newm, add);
02497   mcElementType t = (add*signbeforebr == 1) ? mcET_ADDOP : mcET_SUBOP;
02498   data_MoveElemRight(mdataidx);
02499   data_Set(mdataidx, mcElementHelpers::data_NewElem(t));
02500   data_MoveElemRight(mdataidx+1);
02501   data_Set(mdataidx+1, newm);
02502   mdataidx+=2;
02503  }
02504 
02505  // ok, tell the parent to use "newp" as replacement
02506  data_Check();
02507 
02508  mcMATHLOG(wxT("mcPolynomialHelpers::math_DistributeBracket - result is [%s]"), mcTXTTHIS);
02509 }
02510 
02511 mcMonomial mcPolynomialHelpers::math_GetGCD(const mcElement &p) const
02512 { 
02513  mcPolynomial arr(p);
02514 
02515  // if we are both containing a single element, our work is quite easy...
02516  if (math_isFactorized() && arr.math_isFactorized())
02517   return math_Get(0).hlp()->math_GetGCD(arr.math_Get(0));
02518 
02519  // at least one of the two arrays (*this or arr) is containing
02520  // more than a single monomial: GCD has no sense in this case....
02521  //return *mcMonomialHelpers::smath_pOne;
02522  return math_GetGCDFor(NULL, -1);
02523 }
02524 
02525 mcMonomial mcPolynomialHelpers::math_GetLCM(const mcElement &p) const
02526 { 
02527  mcPolynomial arr(p);
02528 
02529  // if we are both containing a single element, our work is quite easy...
02530  if (math_isFactorized() && arr.math_isFactorized())
02531   return math_Get(0).hlp()->math_GetLCM(arr.math_Get(0));
02532 
02533  // at least one of the two arrays (*this or arr) is containing
02534  // more than a single monomial: LCM is then the product of these
02535  // two polynomials
02536  mcBracket br1(mcPolynomial(this).math_EmbedInBracket().data_GetRef());
02537  mcBracket br2(arr.math_EmbedInBracket().data_GetRef());
02538  
02539  mcMonomial res;
02540  res.data_AddElements(&br1, 1);
02541  res.math_SimpleMultiplyBy(br2);
02542 
02543  return res;
02544 }
02545 
02546 
02547 
02548 mcArrayEntry mcPolynomialHelpers::math_EmbedInBracket(int *n, int count)
02549 {
02550  if (count == -1)
02551   return mcElementArrayHelpers::math_EmbedInBracket();
02552 
02553  mcPolynomial pol;
02554  mcBracket br;
02555 
02556  // select only the given monomials 
02557  for (int i=0; i < count; i++) {
02558 
02559   // add/subtract the required monomials
02560   bool add = (math_GetSign(n[i]) == 1) ? TRUE : FALSE;
02561   pol.math_SimpleAdd(math_Get(n[i]), add);
02562 
02563   // cannot remove now the n[i]-th monomial since otherwise
02564   // we would make invalid the n[i+1], n[i+2]... indexes
02565   math_Remove(n[i]);
02566   for (int j=i+1; j < count; j++)
02567    n[j]--;
02568  }
02569 
02570 
02571  // allocate a new mcBracket
02572  br.data_SetContent(pol);
02573  
02574  // this object will take care of the bracket...
02575  math_SimpleAdd(br);
02576  
02577  mcArrayEntry ourb(this, mcMAKEPOL_IDX(data_GetCount()-1, 0));
02578  mcASSERT(ourb.data_GetRef().data_GetType() == mcET_BRACKET, wxT("What is this ?!?!?"));
02579  
02580  return ourb;
02581 }
02582 
02583 mcArrayEntry mcPolynomialHelpers::math_GetIndexOf(int occ, const mcMonomial &tofind, 
02584               bool positivesign) const
02585 {
02586  // scan the array
02587  for (int i=0,max=math_GetCount(); i<max; i++) {
02588 
02589   // not only compare the given monomial with our i-th one,
02590   // but also do check the sign of that monomial
02591   if (math_Get(i).math_Compare(tofind, TRUE) &&
02592    positivesign == (math_GetSign(0) != 0)) {
02593 
02594    occ--;
02595    if (occ == -1)
02596     return mcArrayEntry(this, mcMAKEPOL_IDX(math_MathToDataIdx(i), 0));
02597 
02598    // search the next occurrence
02599   }
02600  }
02601 
02602  return mcEmptyArrayEntry;
02603 }


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

[ Top ]