//! QR Solve /*! This implementation is based on MINPACK * (<http://www.netlib.org/minpack>, * <http://www.netlib.org/cephes/linalg.tgz>) * * Given an m by n matrix A, an n by n diagonal matrix d, * and an m-vector b, the problem is to determine an x which * solves the system * * A*x = b , d*x = 0 , * * in the least squares sense. * * d is an input array of length n which must contain the * diagonal elements of the matrix d. * * See lmdiff.cpp for further details. */ public static Vector qrSolve(Matrix a, Vector b, bool pivot = true, Vector d = null) { int m = a.rows(); int n = a.columns(); if (d == null) { d = new Vector(); } Utils.QL_REQUIRE(b.Count == m, () => "dimensions of A and b don't match"); Utils.QL_REQUIRE(d.Count == n || d.empty(), () => "dimensions of A and d don't match"); Matrix q = new Matrix(m, n), r = new Matrix(n, n); List <int> lipvt = MatrixUtilities.qrDecomposition(a, ref q, ref r, pivot); List <int> ipvt = new List <int>(n); ipvt = lipvt; //std::copy(lipvt.begin(), lipvt.end(), ipvt.get()); Matrix aT = Matrix.transpose(a); Matrix rT = Matrix.transpose(r); Vector sdiag = new Vector(n); Vector wa = new Vector(n); Vector ld = new Vector(n, 0.0); if (!d.empty()) { ld = d; //std::copy(d.begin(), d.end(), ld.begin()); } Vector x = new Vector(n); Vector qtb = Matrix.transpose(q) * b; MINPACK.qrsolv(n, rT, n, ipvt, ld, qtb, x, sdiag, wa); return(x); }
//! QR decompoisition /*! This implementation is based on MINPACK * (<http://www.netlib.org/minpack>, * <http://www.netlib.org/cephes/linalg.tgz>) * * This subroutine uses householder transformations with column * pivoting (optional) to compute a qr factorization of the * m by n matrix A. That is, qrfac determines an orthogonal * matrix q, a permutation matrix p, and an upper trapezoidal * matrix r with diagonal elements of nonincreasing magnitude, * such that A*p = q*r. * * Return value ipvt is an integer array of length n, which * defines the permutation matrix p such that A*p = q*r. * Column j of p is column ipvt(j) of the identity matrix. * * See lmdiff.cpp for further details. */ //public static List<int> qrDecomposition(Matrix A, Matrix q, Matrix r, bool pivot = true) { public static List <int> qrDecomposition(Matrix M, Matrix q, Matrix r, bool pivot) { Matrix mT = Matrix.transpose(M); int m = M.rows(); int n = M.columns(); List <int> lipvt = new InitializedList <int>(n); Vector rdiag = new Vector(n); Vector wa = new Vector(n); MINPACK.qrfac(m, n, mT, 0, (pivot)?1:0, ref lipvt, n, ref rdiag, ref rdiag, wa); if (r.columns() != n || r.rows() != n) { r = new Matrix(n, n); } for (int 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 = new Matrix(m, n); } Vector w = new Vector(m); //for (int k=0; k < m; ++k) { // std::fill(w.begin(), w.end(), 0.0); // w[k] = 1.0; // for (int j=0; j < Math.Min(n, m); ++j) { // double t3 = mT[j,j]; // if (t3 != 0.0) { // double t // = std::inner_product(mT.row_begin(j)+j, mT.row_end(j), // w.begin()+j, 0.0)/t3; // for (int i=j; i<m; ++i) { // w[i]-=mT[j,i]*t; // } // } // q[k,j] = w[j]; // } // std::fill(q.row_begin(k) + Math.Min(n, m), q.row_end(k), 0.0); //} List <int> ipvt = new InitializedList <int>(n); //if (pivot) { // std::copy(lipvt.get(), lipvt.get()+n, ipvt.begin()); //} //else { // for (int i=0; i < n; ++i) // ipvt[i] = i; //} return(ipvt); }
//! QR decompoisition /*! This implementation is based on MINPACK * (<http://www.netlib.org/minpack>, * <http://www.netlib.org/cephes/linalg.tgz>) * * This subroutine uses householder transformations with column * pivoting (optional) to compute a qr factorization of the * m by n matrix A. That is, qrfac determines an orthogonal * matrix q, a permutation matrix p, and an upper trapezoidal * matrix r with diagonal elements of nonincreasing magnitude, * such that A*p = q*r. * * Return value ipvt is an integer array of length n, which * defines the permutation matrix p such that A*p = q*r. * Column j of p is column ipvt(j) of the identity matrix. * * See lmdiff.cpp for further details. */ //public static List<int> qrDecomposition(Matrix A, Matrix q, Matrix r, bool pivot = true) { public static List <int> qrDecomposition(Matrix M, ref Matrix q, ref Matrix r, bool pivot) { Matrix mT = Matrix.transpose(M); int m = M.rows(); int n = M.columns(); List <int> lipvt = new InitializedList <int>(n); Vector rdiag = new Vector(n); Vector wa = new Vector(n); MINPACK.qrfac(m, n, mT, 0, (pivot)?1:0, ref lipvt, n, ref rdiag, ref rdiag, wa); if (r.columns() != n || r.rows() != n) { r = new Matrix(n, n); } for (int i = 0; i < n; ++i) { r[i, i] = rdiag[i]; if (i < m) { for (int j = i; j < mT.rows() - 1; j++) { r[i, j + 1] = mT[j + 1, i]; } } } if (q.rows() != m || q.columns() != n) { q = new Matrix(m, n); } Vector w = new Vector(m); for (int k = 0; k < m; ++k) { w.Erase(); w[k] = 1.0; for (int j = 0; j < Math.Min(n, m); ++j) { double t3 = mT[j, j]; if (t3 != 0.0) { double t = 0; for (int kk = j; kk < mT.columns(); kk++) { t += (mT[j, kk] * w[kk]) / t3; } for (int i = j; i < m; ++i) { w[i] -= mT[j, i] * t; } } q[k, j] = w[j]; } } List <int> ipvt = new InitializedList <int>(n); if (pivot) { for (int i = 0; i < n; ++i) { ipvt[i] = lipvt[i]; } } else { for (int i = 0; i < n; ++i) { ipvt[i] = i; } } return(ipvt); }
public override EndCriteria.Type minimize(Problem P, EndCriteria endCriteria) { EndCriteria.Type ecType = EndCriteria.Type.None; P.reset(); Vector x_ = P.currentValue(); currentProblem_ = P; initCostValues_ = P.costFunction().values(x_); int m = initCostValues_.size(); int n = x_.size(); if (useCostFunctionsJacobian_) { initJacobian_ = new Matrix(m, n); P.costFunction().jacobian(initJacobian_, x_); } Vector xx = new Vector(x_); Vector fvec = new Vector(m), diag = new Vector(n); int mode = 1; double factor = 1; int nprint = 0; int info = 0; int nfev = 0; Matrix fjac = new Matrix(m, n); int ldfjac = m; List <int> ipvt = new InitializedList <int>(n); Vector qtf = new Vector(n), wa1 = new Vector(n), wa2 = new Vector(n), wa3 = new Vector(n), wa4 = new Vector(m); // call lmdif to minimize the sum of the squares of m functions // in n variables by the Levenberg-Marquardt algorithm. Func <int, int, Vector, int, Matrix> j = null; if (useCostFunctionsJacobian_) { j = jacFcn; } // requirements; check here to get more detailed error messages. Utils.QL_REQUIRE(n > 0, () => "no variables given"); Utils.QL_REQUIRE(m >= n, () => $"less functions ({m}) than available variables ({n})"); Utils.QL_REQUIRE(endCriteria.functionEpsilon() >= 0.0, () => "negative f tolerance"); Utils.QL_REQUIRE(xtol_ >= 0.0, () => "negative x tolerance"); Utils.QL_REQUIRE(gtol_ >= 0.0, () => "negative g tolerance"); Utils.QL_REQUIRE(endCriteria.maxIterations() > 0, () => "null number of evaluations"); MINPACK.lmdif(m, n, xx, ref fvec, endCriteria.functionEpsilon(), xtol_, gtol_, endCriteria.maxIterations(), epsfcn_, diag, mode, factor, nprint, ref info, ref nfev, ref fjac, ldfjac, ref ipvt, ref qtf, wa1, wa2, wa3, wa4, fcn, j); info_ = info; // check requirements & endCriteria evaluation Utils.QL_REQUIRE(info != 0, () => "MINPACK: improper input parameters"); if (info != 6) { ecType = EndCriteria.Type.StationaryFunctionValue; } endCriteria.checkMaxIterations(nfev, ref ecType); Utils.QL_REQUIRE(info != 7, () => "MINPACK: xtol is too small. no further " + "improvement in the approximate " + "solution x is possible."); Utils.QL_REQUIRE(info != 8, () => "MINPACK: gtol is too small. fvec is " + "orthogonal to the columns of the " + "jacobian to machine precision."); // set problem x_ = new Vector(xx.GetRange(0, n)); P.setCurrentValue(x_); P.setFunctionValue(P.costFunction().value(x_)); return(ecType); }
public override EndCriteria.Type minimize(Problem P, EndCriteria endCriteria) { EndCriteria.Type ecType = EndCriteria.Type.None; P.reset(); Vector x_ = P.currentValue(); currentProblem_ = P; initCostValues_ = P.costFunction().values(x_); int m = initCostValues_.size(); int n = x_.size(); if (useCostFunctionsJacobian_) { initJacobian_ = new Matrix(m, n); P.costFunction().jacobian(initJacobian_, x_); } Vector xx = new Vector(x_); Vector fvec = new Vector(m), diag = new Vector(n); int mode = 1; double factor = 1; int nprint = 0; int info = 0; int nfev = 0; Matrix fjac = new Matrix(m, n); int ldfjac = m; List <int> ipvt = new InitializedList <int>(n); Vector qtf = new Vector(n), wa1 = new Vector(n), wa2 = new Vector(n), wa3 = new Vector(n), wa4 = new Vector(m); // call lmdif to minimize the sum of the squares of m functions // in n variables by the Levenberg-Marquardt algorithm. Func <int, int, Vector, int, Matrix> j = null; if (useCostFunctionsJacobian_) { j = jacFcn; } MINPACK.lmdif(m, n, xx, ref fvec, endCriteria.functionEpsilon(), xtol_, gtol_, endCriteria.maxIterations(), epsfcn_, diag, mode, factor, nprint, ref info, ref nfev, ref fjac, ldfjac, ref ipvt, ref qtf, wa1, wa2, wa3, wa4, fcn, j); info_ = info; // check requirements & endCriteria evaluation if (info == 0) { throw new ApplicationException("MINPACK: improper input parameters"); } //if(info == 6) throw new ApplicationException("MINPACK: ftol is too small. no further " + // "reduction in the sum of squares is possible."); if (info != 6) { ecType = EndCriteria.Type.StationaryFunctionValue; } //QL_REQUIRE(info != 5, "MINPACK: number of calls to fcn has reached or exceeded maxfev."); endCriteria.checkMaxIterations(nfev, ref ecType); if (info == 7) { throw new ApplicationException("MINPACK: xtol is too small. no further " + "improvement in the approximate " + "solution x is possible."); } if (info == 8) { throw new ApplicationException("MINPACK: gtol is too small. fvec is " + "orthogonal to the columns of the " + "jacobian to machine precision."); } // set problem x_ = new Vector(xx.GetRange(0, n)); P.setCurrentValue(x_); P.setFunctionValue(P.costFunction().value(x_)); return(ecType); }