Disposable<Array> qrSolve(const Matrix& a, const Array& b, bool pivot, const Array& d) { const Size m = a.rows(); const Size n = a.columns(); QL_REQUIRE(b.size() == m, "dimensions of A and b don't match"); QL_REQUIRE(d.size() == n || d.empty(), "dimensions of A and d don't match"); Matrix q(m, n), r(n, n); std::vector<Size> lipvt = qrDecomposition(a, q, r, pivot); boost::scoped_array<int> ipvt(new int[n]); std::copy(lipvt.begin(), lipvt.end(), ipvt.get()); Matrix rT = transpose(r); boost::scoped_array<Real> sdiag(new Real[n]); boost::scoped_array<Real> wa(new Real[n]); Array ld(n, 0.0); if (!d.empty()) { std::copy(d.begin(), d.end(), ld.begin()); } Array x(n); Array qtb = transpose(q)*b; MINPACK::qrsolv(n, rT.begin(), n, ipvt.get(), ld.begin(), qtb.begin(), x.begin(), sdiag.get(), wa.get()); return x; }
EndCriteria::Type LevenbergMarquardt::minimize(Problem& P, const EndCriteria& endCriteria) { EndCriteria::Type ecType = EndCriteria::None; P.reset(); Array x_ = P.currentValue(); currentProblem_ = &P; initCostValues_ = P.costFunction().values(x_); int m = initCostValues_.size(); int n = x_.size(); boost::scoped_array<double> xx(new double[n]); std::copy(x_.begin(), x_.end(), xx.get()); boost::scoped_array<double> fvec(new double[m]); boost::scoped_array<double> diag(new double[n]); int mode = 1; double factor = 1; int nprint = 0; int info = 0; int nfev =0; boost::scoped_array<double> fjac(new double[m*n]); int ldfjac = m; boost::scoped_array<int> ipvt(new int[n]); boost::scoped_array<double> qtf(new double[n]); boost::scoped_array<double> wa1(new double[n]); boost::scoped_array<double> wa2(new double[n]); boost::scoped_array<double> wa3(new double[n]); boost::scoped_array<double> wa4(new double[m]); // requirements; check here to get more detailed error messages. QL_REQUIRE(n > 0, "no variables given"); QL_REQUIRE(m >= n, "less functions (" << m << ") than available variables (" << n << ")"); QL_REQUIRE(endCriteria.functionEpsilon() >= 0.0, "negative f tolerance"); QL_REQUIRE(xtol_ >= 0.0, "negative x tolerance"); QL_REQUIRE(gtol_ >= 0.0, "negative g tolerance"); QL_REQUIRE(endCriteria.maxIterations() > 0, "null number of evaluations"); // call lmdif to minimize the sum of the squares of m functions // in n variables by the Levenberg-Marquardt algorithm. MINPACK::LmdifCostFunction lmdifCostFunction = boost::bind(&LevenbergMarquardt::fcn, this, _1, _2, _3, _4, _5); MINPACK::lmdif(m, n, xx.get(), fvec.get(), static_cast<double>(endCriteria.functionEpsilon()), static_cast<double>(xtol_), static_cast<double>(gtol_), static_cast<int>(endCriteria.maxIterations()), static_cast<double>(epsfcn_), diag.get(), mode, factor, nprint, &info, &nfev, fjac.get(), ldfjac, ipvt.get(), qtf.get(), wa1.get(), wa2.get(), wa3.get(), wa4.get(), lmdifCostFunction); info_ = info; // check requirements & endCriteria evaluation QL_REQUIRE(info != 0, "MINPACK: improper input parameters"); //QL_REQUIRE(info != 6, "MINPACK: ftol is too small. no further " // "reduction in the sum of squares " // "is possible."); if (info != 6) ecType = QuantLib::EndCriteria::StationaryFunctionValue; //QL_REQUIRE(info != 5, "MINPACK: number of calls to fcn has " // "reached or exceeded maxfev."); endCriteria.checkMaxIterations(nfev, ecType); QL_REQUIRE(info != 7, "MINPACK: xtol is too small. no further " "improvement in the approximate " "solution x is possible."); QL_REQUIRE(info != 8, "MINPACK: gtol is too small. fvec is " "orthogonal to the columns of the " "jacobian to machine precision."); // set problem std::copy(xx.get(), xx.get()+n, x_.begin()); P.setCurrentValue(x_); P.setFunctionValue(P.costFunction().value(x_)); return ecType; }
Disposable<std::vector<Size> > qrDecomposition(const Matrix& M, Matrix& q, Matrix& r, bool pivot) { Matrix mT = transpose(M); const Size m = M.rows(); const Size n = M.columns(); boost::scoped_array<int> lipvt(new int[n]); boost::scoped_array<Real> rdiag(new Real[n]); boost::scoped_array<Real> wa(new Real[n]); MINPACK::qrfac(m, n, mT.begin(), 0, (pivot)?1:0, lipvt.get(), n, rdiag.get(), rdiag.get(), wa.get()); if (r.columns() != n || r.rows() !=n) r = Matrix(n, n); for (Size i=0; i < n; ++i) { std::fill(r.row_begin(i), r.row_begin(i)+i, 0.0); r[i][i] = rdiag[i]; if (i < m) { std::copy(mT.column_begin(i)+i+1, mT.column_end(i), r.row_begin(i)+i+1); } else { std::fill(r.row_begin(i)+i+1, r.row_end(i), 0.0); } } if (q.rows() != m || q.columns() != n) q = Matrix(m, n); if (m > n) { std::fill(q.begin(), q.end(), 0.0); Integer u = std::min(n,m); for (Size i=0; i < u; ++i) q[i][i] = 1.0; Array v(m); for (Integer i=u-1; i >=0; --i) { if (std::fabs(mT[i][i]) > QL_EPSILON) { const Real tau = 1.0/mT[i][i]; std::fill(v.begin(), v.begin()+i, 0.0); std::copy(mT.row_begin(i)+i, mT.row_end(i), v.begin()+i); Array w(n, 0.0); for (Size l=0; l < n; ++l) w[l] += std::inner_product( v.begin()+i, v.end(), q.column_begin(l)+i, 0.0); for (Size k=i; k < m; ++k) { const Real a = tau*v[k]; for (Size l=0; l < n; ++l) q[k][l] -= a*w[l]; } } } } else { Array w(m); for (Size k=0; k < m; ++k) { std::fill(w.begin(), w.end(), 0.0); w[k] = 1.0; for (Size j=0; j < std::min(n, m); ++j) { const Real t3 = mT[j][j]; if (t3 != 0.0) { const Real t = std::inner_product(mT.row_begin(j)+j, mT.row_end(j), w.begin()+j, 0.0)/t3; for (Size i=j; i<m; ++i) { w[i]-=mT[j][i]*t; } } q[k][j] = w[j]; } std::fill(q.row_begin(k) + std::min(n, m), q.row_end(k), 0.0); } } std::vector<Size> ipvt(n); if (pivot) { std::copy(lipvt.get(), lipvt.get()+n, ipvt.begin()); } else { for (Size i=0; i < n; ++i) ipvt[i] = i; } return ipvt; }