// This file is part of libhedra, a library for polyhedral mesh processing // // Copyright (C) 2016 Amir Vaxman // // This Source Code Form is subject to the terms of the Mozilla Public License // v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. #ifndef HEDRA_LEVENBERG_MARQUADT_SOLVER_H #define HEDRA_LEVENBERG_MARQUADT_SOLVER_H #include #include #include #include #include #include #include #include namespace hedra { namespace optimization { template class LMSolver{ public: Eigen::VectorXd x; //current solution; always updated Eigen::VectorXd prevx; //the solution of the previous iteration Eigen::VectorXd x0; //the initial solution to the system Eigen::VectorXd d; //the direction taken. Eigen::VectorXd currEnergy; //the current value of the energy Eigen::VectorXd prevEnergy; //the previous value of the energy Eigen::VectorXi HRows, HCols; //(row,col) pairs for H=J^T*J matrix Eigen::VectorXd HVals; //values for H matrix Eigen::MatrixXi S2D; //single J to J^J indices LinearSolver* LS; SolverTraits* ST; int maxIterations; double xTolerance; double fooTolerance; /*void TestMatrixOperations(){ using namespace Eigen; using namespace std; int RowSize=1000; int ColSize=1000; int TriSize=4000; VectorXi Rows; VectorXi Cols; VectorXd Vals=VectorXd::Random(TriSize); VectorXd dRows=VectorXd::Random(TriSize); VectorXd dCols=VectorXd::Random(TriSize); cout<<"dRows Range: "<(); Cols=((dCols+MatrixXd::Constant(dRows.size(),1,1.0))*500.0).cast(); VectorXi SortRows, stub; VectorXi MRows, MCols; VectorXd MVals; igl::sortrows(Rows, true, SortRows, stub); MatrixXi S2D; double miu=15.0; MatrixPattern(SortRows, Cols, MRows, MCols, S2D); MVals.resize(MRows.size()); MatrixValues(MRows, MCols, Vals, S2D, miu, MVals); //testing multiplyadjoint SparseMatrix M(SortRows.maxCoeff()+1,Cols.maxCoeff()+1); //cout<<"Our I"< > Tris; for (int i=0;i(SortRows(i), Cols(i), Vals(i))); M.setFromTriplets(Tris.begin(), Tris.end()); Tris.clear(); SparseMatrix I; igl::speye(M.cols(),M.cols(),I); SparseMatrix MtM1=M.transpose()*M+miu*I; SparseMatrix MtM2(MtM1.rows(), MtM1.cols()); for (int i=0;i(MRows(i), MCols(i), MVals(i))); MtM2.setFromTriplets(Tris.begin(), Tris.end()); bool Discrepancy=false; SparseMatrix DiffMat=MtM1-MtM2; for (int k=0; k::InnerIterator it(DiffMat,k); it; ++it){ if ((abs(it.value())>10e-6)&&(it.row()<=it.col())){ cout<<"Discrepancy at ("< oIlist; std::vector oJlist; std::vector > S2Dlist; do{ int CurrRow=iI(CurrTri); int NumCurrTris=0; while ((CurrTri+NumCurrTris=iJ(i)){ oIlist.push_back(iJ(i)); oJlist.push_back(iJ(j)); S2Dlist.push_back(std::pair(i,j)); } } } CurrTri+=NumCurrTris; }while (CurrTri!=iI.size()); //triplets for miu for (int i=0;iJRows, ST->JCols,HRows,HCols,S2D); HVals.resize(HRows.size()); LS->analyze(HRows,HCols, true); d.resize(ST->xSize); x.resize(ST->xSize); x0.resize(ST->xSize); prevx.resize(ST->xSize); currEnergy.resize(ST->EVec.size()); prevEnergy.resize(ST->EVec.size()); //TestMatrixOperations(); } bool solve(const bool verbose) { using namespace Eigen; using namespace std; ST->initial_solution(x0); prevx<xSize); VectorXd direction; if (verbose) cout<<"******Beginning Optimization******"<update_jacobian(prevx); MatrixValues(HRows, HCols, ST->JVals, S2D, miu, HVals); for (int i=0;ipre_iteration(prevx); ST->update_energy(prevx); ST->update_jacobian(prevx); if (verbose) cout<<"Initial Energy for Iteration "<EVec.template squaredNorm()<JVals, S2D, miu, HVals); MultiplyAdjointVector(ST->JRows, ST->JCols, ST->JVals, -ST->EVec, rhs); double firstOrderOptimality=rhs.template lpNorm(); if (verbose) cout<<"firstOrderOptimality: "<factorize(HVals, true)) { // decomposition failed cout<<"Solver Failed to factorize! "<solve(mRhs,mDirection); direction=mDirection.col(0); if (verbose) cout<<"direction magnitude: "<update_energy(prevx); double prevE=ST->EVec.squaredNorm(); ST->update_energy(tryx); double currE=ST->EVec.squaredNorm(); double rho=(prevE-currE)/(direction.dot(miu*direction+rhs)); if (rho>0){ x=tryx; //if (verbose){ //cout<<"Energy: "< 1.0-(beta-1.0)*pow(2.0*rho-1.0,3) ? 1.0/gamma : 1.0-(beta-1.0)*pow(2.0*rho-1.0,3)); nu=beta; //if (verbose) // cout<<"rho, miu, nu: "<post_iteration(x)){ if (verbose) cout<<"ST->Post_iteration() gave a stop"<post_optimization(x)); return true; } }; } } #endif