Polynomial.cpp

00001 #include "Polynomial.h"
00002 
00003 #include <iomanip>
00004 #include <math.h>
00005 
00006 #include "complex.h"
00007 
00008 #define DOUBLE_ZERO_THRESHOLD 0.000000001
00009 #define NOOPT -1
00010 double PBIGVALUE = 1010101;
00011 
00012 bool pldbg = false;
00013 
00014 bool DoubleEqual(const double& d1, const double& d2, const double& threshold) {
00015         if (fabs(d1 - d2) < threshold) {
00016                 return true;
00017         }
00018         return false;
00019 }
00020 
00021 // Analytical solution to quadratic polynomials exists. This function could return the optimal solution to quadratic polynomials with one or two variables.
00022 // Return value: indicator variable for solution status, NOOPT
00023 int PolyNomial::Optimize2(Array<double>* vars, double* optValue)
00024 {
00025         vars->clear();
00026         if (1 == numVar_)  // There is only 1 variable in the polynomial.
00027         {
00028                 double a = 0, b = 0;  // Get parameters for the Gaussian representation.
00029                 for(int i = 0; i < items_.size(); ++i) {
00030                         map<int, double>::const_iterator citer = items_[i].begin();
00031                         if (DoubleEqual(citer->second, 2.0, DOUBLE_ZERO_THRESHOLD)) {
00032                                 a = coef_[i];
00033                         }
00034 
00035                         if (DoubleEqual(citer->second, 1.0, DOUBLE_ZERO_THRESHOLD)) {
00036                                 b = coef_[i];
00037                         }
00038                 }
00039 
00040                 // ERROR: The quadratic term is empty.
00041                 if (fabs(a) < DOUBLE_ZERO_THRESHOLD) {
00042                         cout << "The quadratic term is empty" << endl;
00043                         exit(0);
00044                 }
00045 
00046                 vars->append(-b/(2*a));
00047                 *optValue = ComputePlValue(*vars);
00048                 return 0;
00049         }
00050 
00051         // Two-var quadratic polynomial representation: a*x1^2 + b*x2^2 + c*x1*x2 + d*x1 + e*x2.
00052         double a = 0, b = 0, c = 0, d = 0, e = 0;
00053         //normalize and assume each polynomial are 2-var poly.
00054         for(int i = 0; i < items_.size(); ++i) {
00055                 map<int, double>::const_iterator citer = items_[i].begin();
00056                 if (citer->first == 0 && DoubleEqual(citer->second, 2.0, DOUBLE_ZERO_THRESHOLD)) //x1^2
00057                 {
00058                         a = coef_[i];
00059                 }
00060                 if (citer->first == 1 && DoubleEqual(citer->second, 2.0, DOUBLE_ZERO_THRESHOLD)) //x2^2
00061                 {
00062                         b = coef_[i];
00063                 }
00064                 if (citer->first == 0 && DoubleEqual(citer->second, 1.0, DOUBLE_ZERO_THRESHOLD) && items_[i].size() == 2) //x1*x2
00065                 {
00066                         c = coef_[i];
00067                 }
00068                 if (citer->first == 0 && DoubleEqual(citer->second, 1.0, DOUBLE_ZERO_THRESHOLD) && items_[i].size() == 1) //x1
00069                 {
00070                         d = coef_[i];
00071                 }
00072                 if (citer->first == 1 && DoubleEqual(citer->second, 1.0, DOUBLE_ZERO_THRESHOLD) && items_[i].size() == 1)//x2
00073                 {
00074                         e = coef_[i];
00075                 }
00076                 if (citer->first == 1 && DoubleEqual(citer->second, 1.0, DOUBLE_ZERO_THRESHOLD) && items_[i].size() > 1) //wrong
00077                 {
00078                         cout << "shouldn't be here," << endl;
00079                 }
00080         }
00081 
00082         vars->clear();
00083         double delta = 4 * a * b - c * c;
00084         //cout << "delta: " << delta << endl;
00085         // delta == 0, |a| > 0, |b| > 0
00086         if (fabs(delta) < DOUBLE_ZERO_THRESHOLD) {
00087                 if (fabs(a)> DOUBLE_ZERO_THRESHOLD) {
00088                         vars->append(-d / 2 * a);
00089                         vars->append(0.0);
00090                 } else if (fabs(a)> DOUBLE_ZERO_THRESHOLD) {
00091                         vars->append(0.0);
00092                         vars->append(-e / 2 * b);
00093                 } else {
00094                         // In this case, there is no appropriate optimum
00095                         PrintTo(cout); cout << endl;
00096                         cout << "delta = 0, no optimums2" << endl;
00097                         exit(0);
00098                 }
00099                 *optValue = ComputePlValue(*vars);
00100                 return NOOPT;
00101         }
00102 
00103         vars->append((e * c-2 * b * d)/delta);
00104         vars->append((d * c-2 * a * e)/delta);
00105         *optValue = ComputePlValue(*vars);
00106         return 0;
00107 }
00108 
00109 // Solve quadratic constraint which is of the form: f(x) > 0
00110 // c != 0, constraint type a + b*x +c*x^2 >= d
00111 DoubleRange PolyNomial::SolvePoly2(double a, double b, double c, double d)
00112 {
00113         DoubleRange r;
00114         if (c == 0)
00115         {
00116                 if (b == 0)
00117                 {
00118                         if(a - d >= 0) //any value will do
00119                         {
00120                                 r.low = - PBIGVALUE;
00121                                 r.high = PBIGVALUE;
00122                                 r.iType = 0;
00123                         }
00124                         else
00125                         {
00126                                 r.iType = 3;
00127                         }
00128                 }
00129                 else
00130                 {
00131                         if (b > 0)
00132                         {
00133                                 r.low = d/b;
00134                                 r.high = PBIGVALUE;
00135                                 r.iType = 0;
00136                         }
00137                         else
00138                         {
00139                                 r.high = d/b;
00140                                 r.low = -PBIGVALUE;
00141                                 r.iType = 0;
00142                         }
00143                 }
00144                 return r;
00145         }
00146         
00147         double za = a/c;
00148         double zb = b/c;
00149         double zd = d/c;
00150         double delta = zd - za + zb * zb/4;
00151 
00152         if (delta < 0) {   
00153                 r.iType = 3;
00154         } else if (delta == 0) {
00155                 r.low = r.high = -zb/2;
00156                 r.iType = 2;
00157         } else {
00158                 r.low = -zb/2 - sqrt(delta);
00159                 r.high = -zb/2 + sqrt(delta);
00160                 if (c > 0) {
00161                         r.iType = 1;
00162                 } else {
00163                         r.iType = 0;
00164                 }
00165         }
00166         return r;
00167 }
00168 
00169 DoubleRange PolyNomial::SolvePoly2(double d)
00170 {
00171         DoubleRange r;
00172         if (!NormalizeGaussian())
00173         {
00174                 cout << "unsolvable" << endl;
00175                 r.low = 1;
00176                 r.high = 0;
00177                 r.iType = 3;
00178                 return r;
00179         }
00180 
00181         return SolvePoly2(gpara_.a, gpara_.b, gpara_.c, d);
00182 }
00183 
00184 PolyNomial::PolyNomial()
00185 {
00186         numVar_ = 0;
00187         constValue_ = 0;
00188         numItems_ = 0;
00189 }
00190 
00191 PolyNomial::PolyNomial(const PolyNomial& pl)
00192 {
00193         numVar_ = pl.numVar_;
00194         var_ = pl.var_;
00195         coef_ =  pl.coef_;
00196         numItems_ = pl.numItems_;
00197         strItems_ = pl.strItems_;
00198         items_ = pl.items_;
00199         constValue_ = pl.constValue_;
00200         varValue_ = pl.varValue_;
00201 
00202         varsearch_.clear();
00203 
00204         const map<string, int>& varsearch = pl.varsearch_;
00205         map<string, int>::const_iterator iter = varsearch.begin(); 
00206         for(;iter != varsearch.end(); ++iter) {
00207                 varsearch_.insert(map<string, int>::value_type(iter->first, iter->second));
00208         }
00209 }
00210 
00211 PolyNomial::PolyNomial(PolyNomial& pl)
00212 {
00213         numVar_ = pl.numVar_;
00214         var_ = pl.var_;
00215         coef_ =  pl.coef_;
00216         numItems_ = pl.numItems_;
00217         strItems_ = pl.strItems_;
00218         items_ = pl.items_;
00219         constValue_ = pl.constValue_;
00220         varValue_ = pl.varValue_;
00221 
00222         varsearch_.clear();
00223 
00224         const map<string, int>& varsearch = pl.varsearch_;
00225         map<string, int>::const_iterator iter = varsearch.begin(); 
00226         for(;iter != varsearch.end(); ++iter)
00227         {
00228                 varsearch_.insert(map<string, int>::value_type(iter->first, iter->second));
00229         }
00230 }
00231 
00232 double PolyNomial::QuadraticOptimization()
00233 {
00234         if (!NormalizeGaussian())
00235         {
00236                 cout << "unsolvable" << endl;
00237                 return PBIGVALUE;
00238         }
00239 
00240         return -gpara_.b / (2 * gpara_.c);
00241 }
00242 
00243 void PolyNomial::Copy(PolyNomial& pl)
00244 {
00245         numVar_ = pl.numVar_;
00246         var_ = pl.var_;
00247         coef_ =  pl.coef_;
00248         numItems_ = pl.numItems_;
00249         strItems_ = pl.strItems_;
00250         items_ = pl.items_;
00251         constValue_ = pl.constValue_;
00252         varValue_ = pl.varValue_;
00253 
00254         varsearch_.clear();
00255 
00256         const map<string, int>& varsearch = pl.varsearch_;
00257         map<string, int>::const_iterator iter = varsearch.begin(); 
00258         for(;iter != varsearch.end(); ++iter)
00259         {
00260                 varsearch_.insert(map<string, int>::value_type(iter->first, iter->second));
00261         }
00262 }
00263 
00264 
00265 void PolyNomial::Copy(const PolyNomial& pl)
00266 {
00267         numVar_ = pl.numVar_;
00268         var_ = pl.var_;
00269         coef_ =  pl.coef_;
00270         numItems_ = pl.numItems_;
00271         strItems_ = pl.strItems_;
00272         items_ = pl.items_;
00273         constValue_ = pl.constValue_;
00274         varValue_ = pl.varValue_;
00275 
00276         varsearch_.clear();
00277 
00278         const map<string, int>& varsearch = pl.varsearch_;
00279         map<string, int>::const_iterator iter = varsearch.begin(); 
00280         for(;iter != varsearch.end(); ++iter)
00281         {
00282                 varsearch_.insert(map<string, int>::value_type(iter->first, iter->second));
00283         }
00284 }
00285 
00286 void PolyNomial::operator=(PolyNomial& pl)
00287 {
00288         Copy(pl);
00289 }
00290 
00291 void PolyNomial::operator=(const PolyNomial& pl)
00292 {
00293         Copy(pl);
00294 }
00295 
00296 PolyNomial::~PolyNomial()
00297 {
00298 
00299 }
00300 
00301 void PolyNomial::Clear()
00302 {
00303         numVar_ = 0;
00304         constValue_ = 0;
00305         var_.clear();
00306         varsearch_.clear();
00307         coef_.clear();
00308         varValue_.clear();
00309         items_.clear(); 
00310         strItems_.clear();
00311         numItems_ = 0;
00312 }
00313 
00314 double PolyNomial::ComputeItem(int itemIdx)
00315 {
00316         double v = coef_[itemIdx];
00317         map<int, double>::const_iterator citer;
00318         for(citer = items_[itemIdx].begin(); citer !=items_[itemIdx].end(); ++citer)
00319         {
00320                 v = v * pow(varValue_[citer->first], double(citer->second));
00321         }
00322         return v;
00323 }
00324 
00325 void PolyNomial::ReduceToOneVar(int varIdx)
00326 {
00327         if (pldbg)
00328         {
00329                 cout << "Entering ReduceToOneVar" << endl;
00330         }
00331         
00332         assert(0<= varIdx && varIdx < var_.size());
00333 
00334         map<double, double> new_order_coef;
00335         double new_const_value = constValue_;   
00336 
00337         // Record the order and new coefficients for the given variable. Leave the old stuff unchanged.
00338         for(int i = 0; i < items_.size(); ++i)
00339         {
00340                 VarCont& vc = items_[i];
00341                 // This polynomial item does not contain the variable.
00342                 VarCont::const_iterator cit = vc.find(varIdx);
00343                 if ( cit == vc.end())
00344                 {
00345                         new_const_value += ComputeItem(i);
00346                         //remove corresponding item
00347                 } else {
00348                         double coef = coef_[i];
00349                         double order = cit->second;
00350                         map<int, double>::const_iterator citer;
00351                         for(citer = vc.begin(); citer != vc.end(); ++citer)
00352                         {
00353                                 if (citer->first != varIdx)
00354                                 {
00355                                         coef *= pow(varValue_[citer->first], citer->second);
00356                                 }
00357                         }
00358                         new_order_coef[order] += coef;
00359                 }
00360         }
00361 
00362         // Clear and reconstruct the old stuff.
00363         constValue_ = new_const_value;
00364         numVar_ = 1;
00365         double v = varValue_[varIdx];
00366         varValue_.clear();
00367         varValue_.append(v);
00368         string str = var_[varIdx];
00369         var_.clear();
00370         var_.append(str);
00371         varsearch_.clear();
00372         varsearch_[str] = 0;
00373 
00374         numItems_ = new_order_coef.size();
00375         items_.clear();
00376         strItems_.clear();
00377         coef_.clear();
00378         map<double, double>::const_iterator cit = new_order_coef.begin();
00379         for (; cit != new_order_coef.end(); ++cit) {
00380                 coef_.append(cit->second);
00381                 VarCont item;
00382                 item[0] = cit->first;
00383                 items_.append(item);
00384                 strItems_.append(GenerateItemString(item));
00385         }
00386 
00387         if (pldbg)
00388         {
00389                 cout << "Leaving ReduceToOneVar" << endl;
00390         }       
00391 }
00392 
00393 
00394 //void PolyNomial::ReduceToOneVar(int varIdx)
00395 //{
00396 //      cout << "Entering ReduceToOneVar" << endl;
00397 //      assert(0<= varIdx && varIdx < var_.size());
00398 //
00399 //      for(int i = 0; i < items_.size(); i++)
00400 //      {
00401 //              cout << "Checking item " << i << ", " << strItems_[i] << endl;
00402 //              VarCont& vc = items_[i];
00403 //              // This polynomial item does not contain the variable.
00404 //              if (vc.find(varIdx) == vc.end())
00405 //              {
00406 //                      cout << "Not contain var " << var_[varIdx] << ", removing item .." << endl;
00407 //                      constValue_ += ComputeItem(i);
00408 //                      //remove corresponding item
00409 //                      items_.removeItem(i);
00410 //                      coef_.removeItem(i);
00411 //                      strItems_.removeItem(i);
00412 //                      numItems_ --;
00413 //                      i--;
00414 //              } else {
00415 //                      cout << "Contain var " << var_[varIdx] << endl;
00416 //                      map<int, double>::iterator citer;
00417 //                      double coef = coef_[i];
00418 //                      for(citer = vc.begin(); citer != vc.end(); )
00419 //                      {
00420 //                              if (citer->first == varIdx)
00421 //                              {
00422 //                                      ++citer;
00423 //                              }
00424 //                              else
00425 //                              {
00426 //                                      coef *= pow(varValue_[citer->first], double(citer->second));
00427 //                                      vc.erase(citer++);                                      
00428 //                              }
00429 //                      }
00430 //
00431 //                      double pow = vc.begin()->second;
00432 //                      vc.clear();
00433 //                      vc.insert(map<int,double>::value_type(0, pow));
00434 //
00435 //                      coef_[i] = coef;
00436 //                      strItems_[i] = GenerateItemString(vc);
00437 //              }
00438 //      }
00439 //
00440 //      numVar_ = 1;
00441 //      double v = varValue_[varIdx];
00442 //      varValue_.shrinkToSize(1);
00443 //      varValue_[0] = v;
00444 //      string str = var_[varIdx];
00445 //      var_.shrinkToSize(1);
00446 //      var_[0] = str;
00447 //      varsearch_.clear();
00448 //      varsearch_.insert(map<string,int>::value_type(str, 0));
00449 //      Normalize();
00450 //      numItems_ = items_.size();      
00451 //      cout << "Leaving ReduceToOneVar" << endl;
00452 //}
00453 
00454 
00455 
00456 void PolyNomial::ReduceToOneVar(const Array<double>& vars, int varIdx)
00457 {
00458         SetVarValue(vars);
00459         ReduceToOneVar(varIdx);
00460 }
00461 
00462 double PolyNomial::ComputePlValue(const Array<double>& vars)
00463 {
00464         assert(vars.size() == numVar_);
00465         
00466         Array<double> varValueBak_;
00467 
00468         varValueBak_.copyFrom(varValue_);
00469 
00470         varValue_.copyFrom(vars);
00471 
00472         double plValue = ComputePlValue();
00473 
00474         varValue_.copyFrom(varValueBak_);
00475 
00476         return plValue;
00477 }
00478 
00479 double PolyNomial::ComputePlValue()
00480 {
00481         double plValue = 0;
00482         plValue = constValue_;
00483         for(int i = 0; i < items_.size(); i++)
00484         {
00485                 plValue += ComputeItem(i);
00486         }
00487         return plValue;
00488 }
00489 
00490 // Get the highest order number for the variable at varInIdx.
00491 double PolyNomial::GetHighestOrder(int varInIdx) {
00492         // find the highest order item
00493         double highest = 0;
00494         int size = items_.size();
00495         for(int i = 0; i < size; i++)
00496         {
00497                 VarCont::const_iterator citer;
00498                 for(citer = items_[i].begin(); citer != items_[i].end(); ++citer)
00499                 {
00500                         if(citer->first == varInIdx)
00501                         {
00502                                 if (citer->second > highest)
00503                                 {
00504                                         highest = citer->second;
00505                                 }
00506                         }
00507                 }
00508         }
00509         return highest;
00510 }
00511 
00512 void PolyNomial::Normalize()
00513 {
00514         if (pldbg)
00515         {
00516                 cout << "Entering Normalize" << endl;
00517         }
00518         
00519         map<string, int> tmpCont;
00520         map<string, int>::const_iterator citer;
00521         for(int i = 0; i < numItems_; i++)
00522         {
00523                 if ((citer = tmpCont.find(strItems_[i])) != tmpCont.end())
00524                 {
00525                         coef_[citer->second] += coef_[i];
00526                         strItems_.removeItem(i);
00527                         items_.removeItem(i);
00528                         coef_.removeItem(i);
00529                         numItems_ --;
00530                         i--;
00531                 } else {
00532                         tmpCont.insert(map<string, int>::value_type(strItems_[i], i));
00533                 }
00534         }
00535         if (pldbg)
00536         {
00537                 cout << "Leaving Normalize" << endl;
00538         }       
00539 }
00540 
00541 bool PolyNomial::NormalizeGaussian()
00542 {
00543         //do nth here
00544         if (!IsQuadratic())
00545         {
00546                 return false;
00547         }
00548         
00549         Normalize();
00550 
00551         if (numItems_ > 2)
00552         {
00553                 return false;
00554         }
00555 
00556         if (numItems_ == 1)
00557         {
00558                 VarCont& vc = items_[0];
00559                 VarCont::const_iterator citer = vc.begin();
00560                 if (citer->second != 2)
00561                 {
00562                         return false;
00563                 }
00564 
00565                 gpara_.a = constValue_; 
00566                 gpara_.b = 0;
00567                 gpara_.c = coef_[0];
00568                 assert(gpara_.c != 0);
00569         }
00570         else //numitems == 2
00571         {
00572                 gpara_.a = constValue_;
00573                 for(int i = 0; i < numItems_; i++)
00574                 {
00575                         VarCont& vc = items_[i];
00576                         assert(vc.size() == 1);
00577 
00578                         VarCont::const_iterator citer = vc.begin();
00579 
00580                         if (citer->second == 1)
00581                         {
00582                                 gpara_.b = coef_[i];
00583                         }
00584                         else
00585                         {
00586                                 gpara_.c = coef_[i];
00587                         }
00588 
00589                 }
00590         }
00591         return true;
00592 }
00593 
00594 
00595 string PolyNomial::GenerateItemString(const VarCont& vc)
00596 {
00597         string str;
00598         VarCont::const_iterator citer;
00599         for(citer = vc.begin(); citer != vc.end(); ++citer) {
00600            char a[100];    
00601            sprintf(a, "(%d,%f)", citer->first, citer->second);
00602            str += string(a);
00603         }
00604         return str;
00605 }
00606 
00607 // Read polynomial from an input stream of the form:
00608 // CONST_VALUE/var_1;var_2;...;var_n/coef_1,(var_idx_1,var_order_1)...()/coef_2,(var_idx_2,var_order_2)...()/
00609 void PolyNomial::ReadFrom(istream& is)
00610 {
00611         Clear();
00612         string str;
00613         getline(is, str, '/');
00614         constValue_ = atof(str.c_str());
00615         getline(is, str, '/');
00616         stringstream ss(str);
00617         string strVar;
00618         int i = 0;
00619         while(getline(ss, strVar, ';'))
00620         {
00621                 assert(varsearch_.find(strVar) == varsearch_.end());
00622                 var_.append(strVar);
00623                 varsearch_.insert(map<string, int>::value_type(strVar, i));
00624                 i++;
00625         }
00626 
00627         i = 0;
00628         map<string, int> strngItems;
00629         while (getline(is, str, '/'))
00630         {
00631                 VarCont vc;
00632                 int varIdx;
00633                 double varOrder;
00634                 stringstream as(str);
00635                 string strTmp;
00636                 getline(as, strTmp, ',');
00637 
00638                 double coef = atof(strTmp.c_str());
00639 
00640                 while (getline(as, strTmp, '('))
00641                 {
00642                         getline(as, strTmp, ',');
00643                         varIdx = atoi(strTmp.c_str());
00644                         getline(as, strTmp, ')');
00645                         varOrder  = atof(strTmp.c_str());
00646                         vc.insert(map<int,double>::value_type(varIdx, varOrder));
00647                 }
00648 
00649                 string strItem = GenerateItemString(vc);
00650                 map<string, int>::const_iterator citer = strngItems.find(strItem);
00651                 if (citer != strngItems.end())
00652                 {
00653                         int itemIdx = citer->second;
00654                         coef_[itemIdx] += coef; //dedup & merge
00655                         continue;
00656                 }
00657 
00658                 strItems_.append(strItem);
00659                 strngItems.insert(map<string, int>::value_type(strItem, i++));
00660 
00661                 coef_.append(coef);
00662                 items_.append(vc);  
00663         }
00664 
00665         numVar_ = var_.size();
00666         varValue_.growToSize(numVar_, 0);
00667         numItems_ = strItems_.size();
00668 }
00669 
00670 void PolyNomial::PrintVars(ostream& os) const
00671 {
00672         for(int i = 0; i < numVar_; i++) {
00673                 os << var_[i] << ":" << varValue_[i] << "\t";
00674         }
00675         os << endl;
00676 }
00677 
00678 void PolyNomial::PrintTo(ostream& os) const
00679 {
00680         os.setf(ios::fixed, ios::floatfield);
00681         os.setf(ios::showpoint);
00682 
00683         os << setprecision(20) << constValue_  << '/';
00684         for(int i = 0; i < var_.size(); i++) {
00685                 os << var_[i] << ';';
00686         }
00687         os << '/';
00688         for(int i = 0; i < items_.size(); i++) {
00689                 os << setprecision(20) <<coef_[i] << ',';
00690                 map<int,double>::const_iterator citer;
00691                 for(citer = items_[i].begin(); citer != items_[i].end(); ++citer) {
00692                         os << '(' << citer->first << ',' << setprecision(20) <<citer->second << ')' ;
00693                 }
00694                 os << '/';
00695         }
00696 }
00697 
00698 // Check if it's quadratic.
00699 bool PolyNomial::IsQuadratic()
00700 {
00701         if (numVar_ != 1)
00702         {
00703                 return false;
00704         }
00705 
00706         double highorder = -1;
00707         for(int i = 0; i < items_.size(); i++)
00708         {
00709                 VarCont& vc = items_[i];
00710                 map<int, double>::const_iterator citer = vc.begin();
00711                 if (citer->second > highorder)
00712                 {
00713                         highorder = citer->second;
00714                 }
00715         }
00716 
00717         if (highorder != 2)
00718         {
00719                 return false;
00720         }
00721 
00722         return true;
00723 }
00724 
00725 void PolyNomial::PrintCoef(ostream& os, double coef) const
00726 {
00727         if (coef < 0)
00728         {
00729                 os << setprecision(20) <<coef;
00730         } else {
00731                 os << "+"<< setprecision(20)<< coef;
00732         }
00733 }
00734 
00735 
00736 void PolyNomial::MultiplyConst(double coef)
00737 {
00738         constValue_ *= coef;
00739         for(int i = 0; i < numItems_; i++)
00740         {
00741            coef_[i] *= coef;
00742         }
00743 }
00744 
00745 //Assume two pls have the same set of variables.
00746 void PolyNomial::AddPl(const PolyNomial& pl)
00747 {                               
00748         if (pldbg)
00749         {
00750                 cout << "Entering AddPl" << endl;
00751         }
00752         if (numVar_ == 0 && pl.numVar_ > 0)
00753         {
00754                 numVar_ = pl.numVar_;
00755                 constValue_ += pl.constValue_;
00756                 var_.copyFrom(pl.var_);
00757                 items_.copyFrom(pl.items_);
00758                 coef_.copyFrom(pl.coef_);
00759                 varValue_.copyFrom(pl.varValue_);
00760                 strItems_.copyFrom(pl.strItems_);
00761                 map<string,int>::const_iterator citer = pl.varsearch_.begin();
00762                 for(;citer!= pl.varsearch_.end(); ++citer)
00763                 {
00764                         varsearch_.insert(map<string,int>::value_type(citer->first, citer->second));
00765                 }
00766         } else if (pl.numVar_ == 0) {
00767                 constValue_ += pl.constValue_;
00768         } else if (numVar_ > 0 && pl.numVar_> 0) {
00769                 constValue_ += pl.constValue_;
00770                 map<string, int> itemCont;
00771                 for(int i = 0; i < strItems_.size(); i++) {
00772                         itemCont.insert(map<string, int>::value_type(strItems_[i],i));
00773                 }
00774                 map<string,int>::const_iterator citer;
00775                 for(int i = 0; i < pl.strItems_.size(); i++)
00776                 {
00777                         if ((citer = itemCont.find(pl.strItems_[i])) != itemCont.end())
00778                         {
00779                                 coef_[citer->second] += pl.coef_[i];
00780                         } else {
00781                                 items_.append(pl.items_[i]);
00782                                 strItems_.append(pl.strItems_[i]);
00783                                 coef_.append(pl.coef_[i]);
00784                         }
00785                 }
00786                 numItems_ = items_.size();
00787         }
00788         if (pldbg)
00789         {
00790                 cout << "Leaving AddPl" << endl;
00791         }
00792 }
00793 void PolyNomial::GetGaussianPara(double* miu, double* stdev)
00794 {       
00795         if (numVar_ == 1)  // Only 1 variable
00796         {
00797                 double a = 0, b = 0;
00798                 for(int i = 0; i < items_.size(); i++)
00799                 {
00800                         map<int, double>::const_iterator citer = items_[i].begin();
00801                         if (citer->second == 2) {
00802                                 a = coef_[i];
00803                         }
00804                         if (citer->second == 1) {
00805                                 b = coef_[i];
00806                         }
00807                 }
00808                 assert(a < 0);
00809                 *miu = -b/(2.0 * a);
00810                 *stdev = sqrt(-1.0/(2.0 * a));          
00811         } else {
00812                 cout << "can not handle multivariate Gaussian now" << endl;
00813                 exit(0);
00814         }
00815 }
00816 
00817 PolyNomial PolyNomial::GetGradient(int varInIdx)
00818 {
00819         PolyNomial gradient;
00820         gradient.Copy(*this);
00821         //gradient.PrintTo(cout);       cout << endl;
00822         gradient.ReduceToOneVar(varValue_, varInIdx);
00823         //gradient.PrintTo(cout); cout << endl;
00824         gradient.constValue_ = 0;
00825         
00826         if(0 == numItems_)
00827         {
00828                 gradient.Clear();
00829                 return gradient;                
00830         }
00831 
00832         for (int i = 0; i < gradient.numItems_; i++)
00833         {
00834                 //double coef = gradient.coef_[i];
00835                 
00836                 map<int,double>::iterator it = gradient.items_[i].begin();
00837                 if(it->second == 1)
00838                 {
00839                         double coef = gradient.coef_[i];
00840                         gradient.items_.removeItem(i);
00841                         gradient.coef_.removeItem(i);
00842                         gradient.strItems_.removeItem(i);
00843                         gradient.numItems_ --;
00844                         i--;
00845                         gradient.constValue_ += coef;
00846                 } else {
00847                         gradient.coef_[i] *= it->second;
00848                         it->second = it->second - 1;
00849                         gradient.strItems_[i] = gradient.GenerateItemString(gradient.items_[i]);
00850                 }               
00851         }
00852         return gradient;
00853 }
00854 Array<double> PolyNomial::GetGradient()
00855 {
00856         Array<double> var;
00857 
00858         for(int i = 0; i < numVar_; i++) {
00859                 var.append(GetGradient(i).ComputePlValue());
00860         }
00861         return var;
00862 }
00863 
00864 // This routine solves order 3 polynomial equation, assumed to be of the following canonical format:
00865 //      x^3   +   ax^2   +   bx   +   c   =   0;  
00866 //      Let x=y-a/3, we have:
00867 //      y^3   +   py   +   q   =   0;  
00868 //Then we introduce the following auxilliary variables:
00869 //      w1   =   (-1+sqrt(-3))/2;
00870 //      w2   =   (-1-sqrt(-3))/2;  
00871 //      z1   ��   pow((-q/2 + sqrt(q*q/4+p*p*p/27)), (1/3))
00872 //      z2   ��   pow((-q/2-sqrt(q*q/4+p*p*p/27)), (1/3))
00873 //      y1   =   z1 + z2;  
00874 //      y2   =   w1*z1 + w2*z2;  
00875 //      y3   =   w2*z1 + s2*z2;  
00876 //      Then compute x from y1 y2 and y3.
00877 //  Solving function for order 3 polynomials.
00878 Array<Complex> solvePolyEq3(double a, double b, double c)
00879 {
00880         Array<Complex> root;
00881         Complex w1,w2;
00882 
00883         w1.Set(-0.5,sqrt(3.0) / 2);
00884         w2.Set(-0.5,-sqrt(3.0) / 2);
00885 
00886         double p = b-(1.0/3) * a * a;
00887         double q = 2.0 / 27.0 * a * a * a - a * b / 3.0 + c;
00888 
00889         double delta = q * q / 4.0 + p * p * p / 27.0;  
00890 
00891         // if delta < 0, too complex, we don't handle it now
00892         if (delta < 0)
00893         {
00894                 // if delta < 0, too complex, we don't handle it now
00895                 Complex cDelta(delta, 0.0);
00896                 Array<Complex> ar = cDelta.Root(2);
00897 
00898                 // pick the same square root here
00899                 Complex zz1 = ar[0] - q / 2;
00900                 Complex zz2 = ar[0] * (-1.0) - q/2;
00901 
00902                 // pick the cubic root with 120 degree phase discrepancy
00903                 ar.clear();
00904                 ar = zz1.Root(3);
00905                 Complex z1 = ar[0];
00906 
00907                 ar.clear();
00908                 ar = zz2.Root(3);
00909                 Complex z2 = ar[2];
00910 
00911                 Complex y1 = z1 + z2;
00912                 Complex y2 = w1 * z1 + w2 * z2;
00913                 Complex y3 = w2 * z1 + w1 * z2;
00914 
00915                 Complex x1 = y1 - a / 3;
00916                 Complex x2 = y2 - a / 3;
00917                 Complex x3 = y3 - a / 3;
00918 
00919                 root.append(x1);
00920                 root.append(x2);
00921                 root.append(x3);
00922         } else {
00923                 double sqrtDelta = sqrt(delta);
00924                 double v1 = q * (-0.5) + sqrtDelta;
00925                 double v2 = q * (-0.5) - sqrtDelta;
00926 
00927                 double z1;
00928                 if (v1 >= 0)
00929                 {
00930                         z1 = pow(v1, 1.0 / 3.0);
00931                 }
00932                 else 
00933                 {
00934                         z1 = - pow(-v1, 1.0 / 3.0);
00935                 }
00936 
00937                 double z2 = pow(q * (-0.5) - sqrtDelta, 1.0 / 3.0);
00938                 if (v2 >= 0)
00939                 {
00940                         z2 = pow(v2, 1.0 / 3.0);
00941                 }
00942                 else 
00943                 {
00944                         z2 = - pow(-v2, 1.0 / 3.0);
00945                 }
00946 
00947                 Complex y1; y1.Set(z1 + z2, 0);
00948                 Complex y2 = w1 * z1 + w2 * z2;
00949                 Complex y3 = w2 * z1 + w1 * z2;                 
00950 
00951                 root.append(y1 - a / 3);
00952                 root.append(y2 - a / 3);
00953                 root.append(y3 - a / 3);
00954         }
00955 
00956         return root;
00957 }

Generated on Sun Jun 7 11:55:17 2009 for Alchemy by  doxygen 1.5.1