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
00022
00023 int PolyNomial::Optimize2(Array<double>* vars, double* optValue)
00024 {
00025 vars->clear();
00026 if (1 == numVar_)
00027 {
00028 double a = 0, b = 0;
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
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
00052 double a = 0, b = 0, c = 0, d = 0, e = 0;
00053
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))
00057 {
00058 a = coef_[i];
00059 }
00060 if (citer->first == 1 && DoubleEqual(citer->second, 2.0, DOUBLE_ZERO_THRESHOLD))
00061 {
00062 b = coef_[i];
00063 }
00064 if (citer->first == 0 && DoubleEqual(citer->second, 1.0, DOUBLE_ZERO_THRESHOLD) && items_[i].size() == 2)
00065 {
00066 c = coef_[i];
00067 }
00068 if (citer->first == 0 && DoubleEqual(citer->second, 1.0, DOUBLE_ZERO_THRESHOLD) && items_[i].size() == 1)
00069 {
00070 d = coef_[i];
00071 }
00072 if (citer->first == 1 && DoubleEqual(citer->second, 1.0, DOUBLE_ZERO_THRESHOLD) && items_[i].size() == 1)
00073 {
00074 e = coef_[i];
00075 }
00076 if (citer->first == 1 && DoubleEqual(citer->second, 1.0, DOUBLE_ZERO_THRESHOLD) && items_[i].size() > 1)
00077 {
00078 cout << "shouldn't be here," << endl;
00079 }
00080 }
00081
00082 vars->clear();
00083 double delta = 4 * a * b - c * c;
00084
00085
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
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
00110
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)
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
00338 for(int i = 0; i < items_.size(); ++i)
00339 {
00340 VarCont& vc = items_[i];
00341
00342 VarCont::const_iterator cit = vc.find(varIdx);
00343 if ( cit == vc.end())
00344 {
00345 new_const_value += ComputeItem(i);
00346
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
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
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
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
00491 double PolyNomial::GetHighestOrder(int varInIdx) {
00492
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
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
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
00608
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;
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
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
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)
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
00822 gradient.ReduceToOneVar(varValue_, varInIdx);
00823
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
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
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
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
00892 if (delta < 0)
00893 {
00894
00895 Complex cDelta(delta, 0.0);
00896 Array<Complex> ar = cDelta.Root(2);
00897
00898
00899 Complex zz1 = ar[0] - q / 2;
00900 Complex zz2 = ar[0] * (-1.0) - q/2;
00901
00902
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 }