diff --git a/src/Mod/Sketcher/App/CMakeLists.txt b/src/Mod/Sketcher/App/CMakeLists.txt index bbb8ec66b..c4458ddc4 100644 --- a/src/Mod/Sketcher/App/CMakeLists.txt +++ b/src/Mod/Sketcher/App/CMakeLists.txt @@ -4,6 +4,14 @@ else(MSVC) add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) endif(MSVC) +find_package(OpenMP) +if (OPENMP_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() + + + include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 2b49b8275..02dff93fe 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -55,7 +55,6 @@ #include - using namespace Sketcher; using namespace Base; using namespace Part; @@ -63,7 +62,8 @@ using namespace Part; TYPESYSTEM_SOURCE(Sketcher::Sketch, Base::Persistence) Sketch::Sketch() -: GCSsys(), ConstraintsCounter(0), isInitMove(false) +: GCSsys(), ConstraintsCounter(0), isInitMove(false), + defaultSolver(GCS::DogLeg),defaultSolverRedundant(GCS::DogLeg),debugMode(GCS::Minimal) { } @@ -110,6 +110,9 @@ int Sketch::setUpSketch(const std::vector &GeoList, const std::vector &ConstraintList, int extGeoCount) { + + Base::TimeInfo start_time; + clear(); std::vector intGeoList, extGeoList; @@ -131,9 +134,16 @@ int Sketch::setUpSketch(const std::vector &GeoList, } GCSsys.clearByTag(-1); GCSsys.declareUnknowns(Parameters); - GCSsys.initSolution(); + GCSsys.initSolution(defaultSolverRedundant); GCSsys.getConflicting(Conflicting); GCSsys.getRedundant(Redundant); + + if(debugMode==GCS::Minimal || debugMode==GCS::IterationLevel) { + Base::TimeInfo end_time; + + Base::Console().Log("Sketcher::setUpSketch()-T:%s\n",Base::TimeInfo::diffTime(start_time,end_time).c_str()); + } + return GCSsys.dofsNumber(); } @@ -2086,77 +2096,137 @@ int Sketch::solve(void) GCSsys.clearByTag(-1); isFine = true; } - + int ret; bool valid_solution; - for (int soltype=0; soltype < (isInitMove ? 1 : 4); soltype++) { - std::string solvername; - switch (soltype) { - case 0: // solving with the default DogLeg solver - // (or with SQP if we are in moving mode) - solvername = isInitMove ? "SQP" : "DogLeg"; - ret = GCSsys.solve(isFine, GCS::DogLeg); - break; - case 1: // solving with the LevenbergMarquardt solver - solvername = "LevenbergMarquardt"; - ret = GCSsys.solve(isFine, GCS::LevenbergMarquardt); - break; - case 2: // solving with the BFGS solver - solvername = "BFGS"; - ret = GCSsys.solve(isFine, GCS::BFGS); - break; - case 3: // last resort: augment the system with a second subsystem and use the SQP solver - solvername = "SQP(augmented system)"; - InitParameters.resize(Parameters.size()); - int i=0; - for (std::vector::iterator it = Parameters.begin(); it != Parameters.end(); ++it, i++) { - InitParameters[i] = **it; - GCSsys.addConstraintEqual(*it, &InitParameters[i], -1); - } - GCSsys.initSolution(); - ret = GCSsys.solve(isFine); - break; + std::string solvername; + int defaultsoltype; + + if(isInitMove){ + solvername = "DogLeg"; // DogLeg is used for dragging (same as before) + ret = GCSsys.solve(isFine, GCS::DogLeg); + } + else{ + switch (defaultSolver) { + case 0: + solvername = "BFGS"; + ret = GCSsys.solve(isFine, GCS::BFGS); + defaultsoltype=2; + break; + case 1: // solving with the LevenbergMarquardt solver + solvername = "LevenbergMarquardt"; + ret = GCSsys.solve(isFine, GCS::LevenbergMarquardt); + defaultsoltype=1; + break; + case 2: // solving with the BFGS solver + solvername = "DogLeg"; + ret = GCSsys.solve(isFine, GCS::DogLeg); + defaultsoltype=0; + break; + } + } + + // if successfully solved try to write the parameters back + if (ret == GCS::Success) { + GCSsys.applySolution(); + valid_solution = updateGeometry(); + if (!valid_solution) { + GCSsys.undoSolution(); + updateGeometry(); + Base::Console().Warning("Invalid solution from %s solver.\n", solvername.c_str()); + }else + { + updateNonDrivingConstraints(); } + } else { + valid_solution = false; + if(debugMode==GCS::Minimal || debugMode==GCS::IterationLevel){ + + Base::Console().Log("Sketcher::Solve()-%s- Failed!! Falling back...\n",solvername.c_str()); + } + } - // if successfully solved try to write the parameters back - if (ret == GCS::Success) { - GCSsys.applySolution(); - valid_solution = updateGeometry(); - if (!valid_solution) { - GCSsys.undoSolution(); - updateGeometry(); - Base::Console().Warning("Invalid solution from %s solver.\n", solvername.c_str()); - }else - { - updateNonDrivingConstraints(); + if(!valid_solution && !isInitMove) { // Fall back to other solvers + for (int soltype=0; soltype < 4; soltype++) { + + if(soltype==defaultsoltype){ + continue; // skip default solver } - } else { - valid_solution = false; - //Base::Console().Log("NotSolved "); - } - - if (soltype == 3) // cleanup temporary constraints of the augmented system - GCSsys.clearByTag(-1); - - if (valid_solution) { - if (soltype == 1) - Base::Console().Log("Important: the LevenbergMarquardt solver succeeded where the DogLeg solver had failed.\n"); - else if (soltype == 2) - Base::Console().Log("Important: the BFGS solver succeeded where the DogLeg and LevenbergMarquardt solvers have failed.\n"); - else if (soltype == 3) - Base::Console().Log("Important: the SQP solver succeeded where all single subsystem solvers have failed.\n"); - - if (soltype > 0) { - Base::Console().Log("If you see this message please report a way of reproducing this result at\n"); - Base::Console().Log("http://www.freecadweb.org/tracker/main_page.php\n"); + + switch (soltype) { + case 0: + solvername = "DogLeg"; + ret = GCSsys.solve(isFine, GCS::DogLeg); + break; + case 1: // solving with the LevenbergMarquardt solver + solvername = "LevenbergMarquardt"; + ret = GCSsys.solve(isFine, GCS::LevenbergMarquardt); + break; + case 2: // solving with the BFGS solver + solvername = "BFGS"; + ret = GCSsys.solve(isFine, GCS::BFGS); + break; + case 3: // last resort: augment the system with a second subsystem and use the SQP solver + solvername = "SQP(augmented system)"; + InitParameters.resize(Parameters.size()); + int i=0; + for (std::vector::iterator it = Parameters.begin(); it != Parameters.end(); ++it, i++) { + InitParameters[i] = **it; + GCSsys.addConstraintEqual(*it, &InitParameters[i], -1); + } + GCSsys.initSolution(); + ret = GCSsys.solve(isFine); + break; } - break; - } - } // soltype + // if successfully solved try to write the parameters back + if (ret == GCS::Success) { + GCSsys.applySolution(); + valid_solution = updateGeometry(); + if (!valid_solution) { + GCSsys.undoSolution(); + updateGeometry(); + Base::Console().Warning("Invalid solution from %s solver.\n", solvername.c_str()); + }else + { + updateNonDrivingConstraints(); + } + } else { + valid_solution = false; + if(debugMode==GCS::Minimal || debugMode==GCS::IterationLevel){ + + Base::Console().Log("Sketcher::Solve()-%s- Failed!! Falling back...\n",solvername.c_str()); + } + } + + if (soltype == 3) // cleanup temporary constraints of the augmented system + GCSsys.clearByTag(-1); + + if (valid_solution) { + if (soltype == 1) + Base::Console().Log("Important: the LevenbergMarquardt solver succeeded where the DogLeg solver had failed.\n"); + else if (soltype == 2) + Base::Console().Log("Important: the BFGS solver succeeded where the DogLeg and LevenbergMarquardt solvers have failed.\n"); + else if (soltype == 3) + Base::Console().Log("Important: the SQP solver succeeded where all single subsystem solvers have failed.\n"); + + if (soltype > 0) { + Base::Console().Log("If you see this message please report a way of reproducing this result at\n"); + Base::Console().Log("http://www.freecadweb.org/tracker/main_page.php\n"); + } + + break; + } + } // soltype + } Base::TimeInfo end_time; - //Base::Console().Log("T:%s\n",Base::TimeInfo::diffTime(start_time,end_time).c_str()); + + if(debugMode==GCS::Minimal || debugMode==GCS::IterationLevel){ + + Base::Console().Log("Sketcher::Solve()-%s-T:%s\n",solvername.c_str(),Base::TimeInfo::diffTime(start_time,end_time).c_str()); + } + SolveTime = Base::TimeInfo::diffTimeF(start_time,end_time); return ret; } diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 19af9c927..9e613e973 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -374,6 +374,33 @@ protected: bool isInitMove; bool isFine; +public: + GCS::Algorithm defaultSolver; + GCS::Algorithm defaultSolverRedundant; + inline void setDebugMode(GCS::DebugMode mode) {debugMode=mode;GCSsys.debugMode=mode;} + inline GCS::DebugMode getDebugMode(void) {return debugMode;} + inline void setMaxIter(int maxiter){GCSsys.maxIter=maxiter;} + inline void setMaxIterRedundant(int maxiter){GCSsys.maxIterRedundant=maxiter;} + inline void setSketchSizeMultiplier(bool mult){GCSsys.sketchSizeMultiplier=mult;} + inline void setSketchSizeMultiplierRedundant(bool mult){GCSsys.sketchSizeMultiplierRedundant=mult;} + inline void setConvergence(double conv){GCSsys.convergence=conv;} + inline void setConvergenceRedundant(double conv){GCSsys.convergenceRedundant=conv;} + inline void setQRAlgorithm(GCS::QRAlgorithm alg){GCSsys.qrAlgorithm=alg;} + inline void setLM_eps(double val){GCSsys.LM_eps=val;} + inline void setLM_eps1(double val){GCSsys.LM_eps1=val;} + inline void setLM_tau(double val){GCSsys.LM_tau=val;} + inline void setDL_tolg(double val){GCSsys.DL_tolg=val;} + inline void setDL_tolx(double val){GCSsys.DL_tolx=val;} + inline void setDL_tolf(double val){GCSsys.DL_tolf=val;} + inline void setLM_epsRedundant(double val){GCSsys.LM_epsRedundant=val;} + inline void setLM_eps1Redundant(double val){GCSsys.LM_eps1Redundant=val;} + inline void setLM_tauRedundant(double val){GCSsys.LM_tauRedundant=val;} + inline void setDL_tolgRedundant(double val){GCSsys.DL_tolgRedundant=val;} + inline void setDL_tolxRedundant(double val){GCSsys.DL_tolxRedundant=val;} + inline void setDL_tolfRedundant(double val){GCSsys.DL_tolfRedundant=val;} + +protected: + GCS::DebugMode debugMode; private: diff --git a/src/Mod/Sketcher/App/planegcs/GCS.cpp b/src/Mod/Sketcher/App/planegcs/GCS.cpp index b1937376d..a131ed4ae 100644 --- a/src/Mod/Sketcher/App/planegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/planegcs/GCS.cpp @@ -26,15 +26,16 @@ #include "GCS.h" #include "qp_eq.h" + #include +#include +#include #undef _GCS_DEBUG #undef _GCS_DEBUG_SOLVER_JACOBIAN_QR_DECOMPOSITION_TRIANGULAR_MATRIX -#if defined(_GCS_DEBUG) || defined(_GCS_DEBUG_SOLVER_JACOBIAN_QR_DECOMPOSITION_TRIANGULAR_MATRIX) #include #include -#endif // _GCS_DEBUG #include #include @@ -153,8 +154,19 @@ System::System() c2p(), p2c(), subSystems(0), subSystemsAux(0), reference(0), - hasUnknowns(false), hasDiagnosis(false), isInit(false) + hasUnknowns(false), hasDiagnosis(false), isInit(false), + maxIter(100), maxIterRedundant(100), + sketchSizeMultiplier(true), sketchSizeMultiplierRedundant(true), + convergence(1e-10), convergenceRedundant(1e-10), + qrAlgorithm(EigenSparseQR), debugMode(Minimal), + LM_eps(1E-10), LM_eps1(1E-80), LM_tau(1E-3), + DL_tolg(1E-80), DL_tolx(1E-80), DL_tolf(1E-10), + LM_epsRedundant(1E-10), LM_eps1Redundant(1E-80), LM_tauRedundant(1E-3), + DL_tolgRedundant(1E-80), DL_tolxRedundant(1E-80), DL_tolfRedundant(1E-10) { + // currently Eigen only supports multithreading for multiplications + // There is no appreciable gain from using more threads + Eigen::setNbThreads(1); } /*DeepSOIC: seriously outdated, needs redesign @@ -860,7 +872,7 @@ void System::declareUnknowns(VEC_pD ¶ms) hasUnknowns = true; } -void System::initSolution() +void System::initSolution(Algorithm alg) { // - Stores the current parameters values in the vector "reference" // - identifies any decoupled subsystems and partitions the original @@ -881,7 +893,7 @@ void System::initSolution() // diagnose conflicting or redundant constraints if (!hasDiagnosis) { - diagnose(); + diagnose(alg); if (!hasDiagnosis) return; } @@ -1007,14 +1019,14 @@ void System::resetToReference() } } -int System::solve(VEC_pD ¶ms, bool isFine, Algorithm alg) +int System::solve(VEC_pD ¶ms, bool isFine, Algorithm alg, bool isRedundantsolving) { declareUnknowns(params); initSolution(); - return solve(isFine, alg); + return solve(isFine, alg, isRedundantsolving); } -int System::solve(bool isFine, Algorithm alg) +int System::solve(bool isFine, Algorithm alg, bool isRedundantsolving) { if (!isInit) return Failed; @@ -1029,11 +1041,11 @@ int System::solve(bool isFine, Algorithm alg) isReset = true; } if (subSystems[cid] && subSystemsAux[cid]) - res = std::max(res, solve(subSystems[cid], subSystemsAux[cid], isFine)); + res = std::max(res, solve(subSystems[cid], subSystemsAux[cid], isFine, isRedundantsolving)); else if (subSystems[cid]) - res = std::max(res, solve(subSystems[cid], isFine, alg)); + res = std::max(res, solve(subSystems[cid], isFine, alg, isRedundantsolving)); else if (subSystemsAux[cid]) - res = std::max(res, solve(subSystemsAux[cid], isFine, alg)); + res = std::max(res, solve(subSystemsAux[cid], isFine, alg, isRedundantsolving)); } if (res == Success) { for (std::set::const_iterator constr=redundant.begin(); @@ -1042,7 +1054,7 @@ int System::solve(bool isFine, Algorithm alg) //convergence, which makes no sense. Potentially I fixed bug, and //chances are low I've broken anything. double err = (*constr)->error(); - if (err*err > XconvergenceFine) { + if (err*err > (isRedundantsolving?convergenceRedundant:convergence)) { res = Converged; return res; } @@ -1051,19 +1063,19 @@ int System::solve(bool isFine, Algorithm alg) return res; } -int System::solve(SubSystem *subsys, bool isFine, Algorithm alg) +int System::solve(SubSystem *subsys, bool isFine, Algorithm alg, bool isRedundantsolving) { if (alg == BFGS) - return solve_BFGS(subsys, isFine); + return solve_BFGS(subsys, isFine, isRedundantsolving); else if (alg == LevenbergMarquardt) - return solve_LM(subsys); + return solve_LM(subsys, isRedundantsolving); else if (alg == DogLeg) - return solve_DL(subsys); + return solve_DL(subsys, isRedundantsolving); else return Failed; } -int System::solve_BFGS(SubSystem *subsys, bool isFine) +int System::solve_BFGS(SubSystem *subsys, bool isFine, bool isRedundantsolving) { int xsize = subsys->pSize(); if (xsize == 0) @@ -1092,13 +1104,17 @@ int System::solve_BFGS(SubSystem *subsys, bool isFine) subsys->getParams(x); h = x - h; // = x - xold - double convergence = isFine ? XconvergenceFine : XconvergenceRough; - int maxIterNumber = MaxIterations * xsize; + //double convergence = isFine ? convergence : XconvergenceRough; + int maxIterNumber = isRedundantsolving? + (sketchSizeMultiplierRedundant?maxIterRedundant * xsize:maxIterRedundant): + (sketchSizeMultiplier?maxIter * xsize:maxIter); + double divergingLim = 1e6*err + 1e12; + double h_norm; for (int iter=1; iter < maxIterNumber; iter++) { - - if (h.norm() <= convergence || err <= smallF) + h_norm = h.norm(); + if (h_norm <= isRedundantsolving?convergenceRedundant:convergence || err <= smallF) break; if (err > divergingLim || err != err) // check for diverging and NaN break; @@ -1127,18 +1143,30 @@ int System::solve_BFGS(SubSystem *subsys, bool isFine) h = x; subsys->getParams(x); h = x - h; // = x - xold + + if(debugMode==IterationLevel) { + std::stringstream stream; + // Iteration: 1, residual: 1e-3, tolg: 1e-5, tolx: 1e-3 + + stream << "BFGS, Iteration: " << iter + << ", err(eps): " << err + << ", h_norm: " << h_norm << "\n"; + + const std::string tmp = stream.str(); + Base::Console().Log(tmp.c_str()); + } } subsys->revertParams(); if (err <= smallF) return Success; - if (h.norm() <= convergence) + if (h.norm() <= isRedundantsolving?convergenceRedundant:convergence) return Converged; return Failed; } -int System::solve_LM(SubSystem* subsys) +int System::solve_LM(SubSystem* subsys, bool isRedundantsolving) { int xsize = subsys->pSize(); int csize = subsys->cSize(); @@ -1157,11 +1185,15 @@ int System::solve_LM(SubSystem* subsys) subsys->calcResidual(e); e*=-1; - int maxIterNumber = MaxIterations * xsize; + int maxIterNumber = isRedundantsolving? + (sketchSizeMultiplierRedundant?maxIterRedundant * xsize:maxIterRedundant): + (sketchSizeMultiplier?maxIter * xsize:maxIter); + double divergingLim = 1e6*e.squaredNorm() + 1e12; - double eps=1e-10, eps1=1e-80; - double tau=1e-3; + double eps=isRedundantsolving?LM_epsRedundant:LM_eps; + double eps1=isRedundantsolving?LM_eps1Redundant:LM_eps1; + double tau=isRedundantsolving?LM_tauRedundant:LM_tau; double nu=2, mu=0; int iter=0, stop=0; for (iter=0; iter < maxIterNumber && !stop; ++iter) { @@ -1197,6 +1229,7 @@ int System::solve_LM(SubSystem* subsys) if (iter == 0) mu = tau * diag_A.lpNorm(); + double h_norm; // determine increment using adaptive damping int k=0; while (k < 50) { @@ -1218,7 +1251,7 @@ int System::solve_LM(SubSystem* subsys) // compute par's new estimate and ||d_par||^2 x_new = x + h; - double h_norm = h.squaredNorm(); + h_norm = h.squaredNorm(); if (h_norm <= eps1*eps1*x.norm()) { // relative change in p is small, stop stop = 3; @@ -1262,6 +1295,19 @@ int System::solve_LM(SubSystem* subsys) stop = 7; break; } + + if(debugMode==IterationLevel) { + std::stringstream stream; + // Iteration: 1, residual: 1e-3, tolg: 1e-5, tolx: 1e-3 + + stream << "LM, Iteration: " << iter + << ", err(eps): " << err + << ", g_inf(eps1): " << g_inf + << ", h_norm: " << h_norm << "\n"; + + const std::string tmp = stream.str(); + Base::Console().Log(tmp.c_str()); + } } if (iter >= maxIterNumber) @@ -1273,9 +1319,11 @@ int System::solve_LM(SubSystem* subsys) } -int System::solve_DL(SubSystem* subsys) +int System::solve_DL(SubSystem* subsys, bool isRedundantsolving) { - double tolg=1e-80, tolx=1e-80, tolf=1e-10; + double tolg=isRedundantsolving?DL_tolgRedundant:DL_tolg; + double tolx=isRedundantsolving?DL_tolxRedundant:DL_tolx; + double tolf=isRedundantsolving?DL_tolfRedundant:DL_tolf; int xsize = subsys->pSize(); int csize = subsys->cSize(); @@ -1301,7 +1349,10 @@ int System::solve_DL(SubSystem* subsys) double g_inf = g.lpNorm(); double fx_inf = fx.lpNorm(); - int maxIterNumber = MaxIterations * xsize; + int maxIterNumber = isRedundantsolving? + (sketchSizeMultiplierRedundant?maxIterRedundant * xsize:maxIterRedundant): + (sketchSizeMultiplier?maxIter * xsize:maxIter); + double divergingLim = 1e6*err + 1e12; double delta=0.1; @@ -1412,7 +1463,21 @@ int System::solve_DL(SubSystem* subsys) } else reduce--; - + + if(debugMode==IterationLevel) { + std::stringstream stream; + // Iteration: 1, residual: 1e-3, tolg: 1e-5, tolx: 1e-3 + + stream << "DL, Iteration: " << iter + << ", fx_inf(tolf): " << fx_inf + << ", g_inf(tolg): " << g_inf + << ", delta(f(tolx)): " << delta + << ", err(divergingLim): " << err << "\n"; + + const std::string tmp = stream.str(); + Base::Console().Log(tmp.c_str()); + } + // count this iteration and start again iter++; } @@ -1424,7 +1489,7 @@ int System::solve_DL(SubSystem* subsys) // The following solver variant solves a system compound of two subsystems // treating the first of them as of higher priority than the second -int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) +int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine, bool isRedundantsolving) { int xsizeA = subsysA->pSize(); int xsizeB = subsysB->pSize(); @@ -1470,8 +1535,11 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) subsysA->calcJacobi(plistAB,JA); subsysA->calcResidual(resA); - double convergence = isFine ? XconvergenceFine : XconvergenceRough; - int maxIterNumber = MaxIterations; + //double convergence = isFine ? XconvergenceFine : XconvergenceRough; + int maxIterNumber = isRedundantsolving? + (sketchSizeMultiplierRedundant?maxIterRedundant * xsize:maxIterRedundant): + (sketchSizeMultiplier?maxIter * xsize:maxIter); + double divergingLim = 1e6*subsysA->error() + 1e12; double mu = 0; @@ -1565,7 +1633,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) } double err = subsysA->error(); - if (h.norm() <= convergence && err <= smallF) + if (h.norm() <= isRedundantsolving?convergenceRedundant:convergence && err <= smallF) break; if (err > divergingLim || err != err) // check for diverging and NaN break; @@ -1574,7 +1642,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) int ret; if (subsysA->error() <= smallF) ret = Success; - else if (h.norm() <= convergence) + else if (h.norm() <= isRedundantsolving?convergenceRedundant:convergence) ret = Converged; else ret = Failed; @@ -1603,7 +1671,7 @@ void System::undoSolution() resetToReference(); } -int System::diagnose() +int System::diagnose(Algorithm alg) { // Analyses the constrainess grad of the system and provides feedback // The vector "conflictingTags" will hold a group of conflicting constraints @@ -1636,6 +1704,16 @@ int System::diagnose() } } + Eigen::SparseMatrix SJ; + + if(qrAlgorithm==EigenSparseQR){ + // this creation is not optimized (done using triplets) + // however the time this takes is negligible compared to the + // time the QR decomposition itself takes + SJ = J.sparseView(); + SJ.makeCompressed(); + } + #ifdef _GCS_DEBUG // Debug code starts std::stringstream stream; @@ -1646,26 +1724,74 @@ int System::diagnose() const std::string tmp = stream.str(); - Base::Console().Warning(tmp.c_str()); + Base::Console().Log(tmp.c_str()); // Debug code ends #endif - if (J.rows() > 0) { - Eigen::FullPivHouseholderQR qrJT(J.topRows(count).transpose()); - Eigen::MatrixXd Q = qrJT.matrixQ (); - int paramsNum = qrJT.rows(); - int constrNum = qrJT.cols(); - qrJT.setThreshold(1e-13); - int rank = qrJT.rank(); + Eigen::MatrixXd R; + int paramsNum; + int constrNum; + int rank; + Eigen::FullPivHouseholderQR qrJT; + Eigen::SparseQR, Eigen::COLAMDOrdering > SqrJT; + + if(qrAlgorithm==EigenDenseQR){ + if (J.rows() > 0) { + qrJT=Eigen::FullPivHouseholderQR(J.topRows(count).transpose()); + Eigen::MatrixXd Q = qrJT.matrixQ (); + + paramsNum = qrJT.rows(); + constrNum = qrJT.cols(); + qrJT.setThreshold(1e-13); + rank = qrJT.rank(); - Eigen::MatrixXd R; - if (constrNum >= paramsNum) - R = qrJT.matrixQR().triangularView(); - else - R = qrJT.matrixQR().topRows(constrNum) - .triangularView(); - - + if (constrNum >= paramsNum) + R = qrJT.matrixQR().triangularView(); + else + R = qrJT.matrixQR().topRows(constrNum) + .triangularView(); + } + } + else if(qrAlgorithm==EigenSparseQR){ + if (SJ.rows() > 0) { + SqrJT=Eigen::SparseQR, Eigen::COLAMDOrdering >(SJ.topRows(count).transpose()); + // Do not ask for Q Matrix!! + // At Eigen 3.2 still has a bug that this only works for square matrices + // if enabled it will crash + //Eigen::SparseMatrix Q = qrJT.matrixQ(); + //qrJT.matrixQ().evalTo(Q); + + paramsNum = SqrJT.rows(); + constrNum = SqrJT.cols(); + SqrJT.setPivotThreshold(1e-13); + rank = SqrJT.rank(); + + if (constrNum >= paramsNum) + R = SqrJT.matrixR().triangularView(); + else + R = SqrJT.matrixR().topRows(constrNum) + .triangularView(); + } + } + + if(debugMode==IterationLevel) { + std::stringstream stream; + + stream << (qrAlgorithm==EigenSparseQR?"EigenSparseQR":(qrAlgorithm==EigenDenseQR?"DenseQR":"")); + stream << ", Threads: " << Eigen::nbThreads() + #ifdef EIGEN_VECTORIZE + << ", Vectorization: On" + #endif + << ", Params: " << paramsNum + << ", Constr: " << constrNum + << ", Rank: " << rank << "\n"; + + const std::string tmp = stream.str(); + Base::Console().Log(tmp.c_str()); + } + + if (J.rows() > 0) { + #ifdef _GCS_DEBUG_SOLVER_JACOBIAN_QR_DECOMPOSITION_TRIANGULAR_MATRIX // Debug code starts std::stringstream stream; @@ -1676,7 +1802,7 @@ int System::diagnose() const std::string tmp = stream.str(); - Base::Console().Warning(tmp.c_str()); + Base::Console().Log(tmp.c_str()); // Debug code ends #endif @@ -1696,11 +1822,23 @@ int System::diagnose() for (int j=rank; j < constrNum; j++) { for (int row=0; row < rank; row++) { if (fabs(R(row,j)) > 1e-10) { - int origCol = qrJT.colsPermutation().indices()[row]; + int origCol; + + if(qrAlgorithm==EigenDenseQR) + origCol=qrJT.colsPermutation().indices()[row]; + else if(qrAlgorithm==EigenSparseQR) + origCol=SqrJT.colsPermutation().indices()[row]; + conflictGroups[j-rank].push_back(clist[origCol]); } } - int origCol = qrJT.colsPermutation().indices()[j]; + int origCol; + + if(qrAlgorithm==EigenDenseQR) + origCol=qrJT.colsPermutation().indices()[j]; + else if(qrAlgorithm==EigenSparseQR) + origCol=SqrJT.colsPermutation().indices()[j]; + conflictGroups[j-rank].push_back(clist[origCol]); } @@ -1750,13 +1888,32 @@ int System::diagnose() clistTmp.push_back(*constr); SubSystem *subSysTmp = new SubSystem(clistTmp, plist); - int res = solve(subSysTmp); + int res = solve(subSysTmp,true,alg,true); + + if(debugMode==Minimal) { + std::string solvername; + switch (alg) { + case 0: + solvername = "BFGS"; + break; + case 1: // solving with the LevenbergMarquardt solver + solvername = "LevenbergMarquardt"; + break; + case 2: // solving with the BFGS solver + solvername = "DogLeg"; + break; + } + + Base::Console().Log("Sketcher::RedundantSolving-%s-\n",solvername.c_str()); + + } + if (res == Success) { subSysTmp->applySolution(); for (std::set::const_iterator constr=skipped.begin(); constr != skipped.end(); constr++) { double err = (*constr)->error(); - if (err * err < XconvergenceFine) + if (err * err < convergenceRedundant) redundant.insert(*constr); } resetToReference(); diff --git a/src/Mod/Sketcher/App/planegcs/GCS.h b/src/Mod/Sketcher/App/planegcs/GCS.h index 4baa40309..9b0a9488d 100644 --- a/src/Mod/Sketcher/App/planegcs/GCS.h +++ b/src/Mod/Sketcher/App/planegcs/GCS.h @@ -24,17 +24,15 @@ #define PLANEGCS_GCS_H #include "SubSystem.h" +#include namespace GCS { /////////////////////////////////////// - // BFGS Solver parameters + // Other BFGS Solver parameters /////////////////////////////////////// #define XconvergenceRough 1e-8 - #define XconvergenceFine 1e-10 #define smallF 1e-20 - #define MaxIterations 100 //Note that the total number of iterations allowed is MaxIterations *xLength - /////////////////////////////////////// // Solver @@ -51,6 +49,17 @@ namespace GCS LevenbergMarquardt = 1, DogLeg = 2 }; + + enum QRAlgorithm { + EigenDenseQR = 0, + EigenSparseQR = 1 + }; + + enum DebugMode { + NoDebug = 0, + Minimal = 1, + IterationLevel = 2 + }; class System { @@ -83,9 +92,31 @@ namespace GCS bool hasDiagnosis; // if dofs, conflictingTags, redundantTags are up to date bool isInit; // if plists, clists, reductionmaps are up to date - int solve_BFGS(SubSystem *subsys, bool isFine); - int solve_LM(SubSystem *subsys); - int solve_DL(SubSystem *subsys); + int solve_BFGS(SubSystem *subsys, bool isFine=true, bool isRedundantsolving=false); + int solve_LM(SubSystem *subsys, bool isRedundantsolving=false); + int solve_DL(SubSystem *subsys, bool isRedundantsolving=false); + public: + int maxIter; + int maxIterRedundant; + bool sketchSizeMultiplier; // if true note that the total number of iterations allowed is MaxIterations *xLength + bool sketchSizeMultiplierRedundant; + double convergence; + double convergenceRedundant; + QRAlgorithm qrAlgorithm; + DebugMode debugMode; + double LM_eps; + double LM_eps1; + double LM_tau; + double DL_tolg; + double DL_tolx; + double DL_tolf; + double LM_epsRedundant; + double LM_eps1Redundant; + double LM_tauRedundant; + double DL_tolgRedundant; + double DL_tolxRedundant; + double DL_tolfRedundant; + public: System(); /*System(std::vector clist_);*/ @@ -192,19 +223,22 @@ namespace GCS void rescaleConstraint(int id, double coeff); void declareUnknowns(VEC_pD ¶ms); - void initSolution(); + void initSolution(Algorithm alg=DogLeg); - int solve(bool isFine=true, Algorithm alg=DogLeg); - int solve(VEC_pD ¶ms, bool isFine=true, Algorithm alg=DogLeg); - int solve(SubSystem *subsys, bool isFine=true, Algorithm alg=DogLeg); - int solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine=true); + int solve(bool isFine=true, Algorithm alg=DogLeg, bool isRedundantsolving=false); + int solve(VEC_pD ¶ms, bool isFine=true, Algorithm alg=DogLeg, bool isRedundantsolving=false); + int solve(SubSystem *subsys, bool isFine=true, Algorithm alg=DogLeg, bool isRedundantsolving=false); + int solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine=true, bool isRedundantsolving=false); void applySolution(); void undoSolution(); + //FIXME: looks like XconvergenceFine is not the solver precision, at least in DogLeg solver. + // Note: Yes, every solver has a different way of interpreting precision + // but one has to study what is this needed for in order to decide + // what to return (this is unchanged from previous versions) + double getFinePrecision(){ return convergence;} - double getFinePrecision(){ return XconvergenceFine;}//FIXME: looks like XconvergenceFine is not the solver precision, at least in DogLeg slover. - - int diagnose(); + int diagnose(Algorithm alg=DogLeg); int dofsNumber() { return hasDiagnosis ? dofs : -1; } void getConflicting(VEC_I &conflictingOut) const { conflictingOut = hasDiagnosis ? conflictingTags : VEC_I(0); } diff --git a/src/Mod/Sketcher/Gui/CMakeLists.txt b/src/Mod/Sketcher/Gui/CMakeLists.txt index d3db16f28..8a7229697 100644 --- a/src/Mod/Sketcher/Gui/CMakeLists.txt +++ b/src/Mod/Sketcher/Gui/CMakeLists.txt @@ -32,6 +32,7 @@ set(SketcherGui_MOC_HDRS TaskSketcherCreateCommands.h TaskSketcherGeneral.h TaskSketcherMessages.h + TaskSketcherSolverAdvanced.h TaskSketcherValidation.h TaskDlgEditSketch.h SketchOrientationDialog.h @@ -48,6 +49,7 @@ set(SketcherGui_UIC_SRCS TaskSketcherElements.ui TaskSketcherGeneral.ui TaskSketcherMessages.ui + TaskSketcherSolverAdvanced.ui TaskSketcherValidation.ui InsertDatum.ui SketchOrientationDialog.ui @@ -90,6 +92,9 @@ SET(SketcherGui_SRCS TaskSketcherMessages.ui TaskSketcherMessages.cpp TaskSketcherMessages.h + TaskSketcherSolverAdvanced.ui + TaskSketcherSolverAdvanced.h + TaskSketcherSolverAdvanced.cpp TaskSketcherValidation.ui TaskSketcherValidation.cpp TaskSketcherValidation.h diff --git a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp index e65fa858f..dceb97d5c 100644 --- a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp +++ b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp @@ -47,11 +47,25 @@ TaskDlgEditSketch::TaskDlgEditSketch(ViewProviderSketch *sketchView) Elements = new TaskSketcherElements(sketchView); General = new TaskSketcherGeneral(sketchView); Messages = new TaskSketcherMessages(sketchView); + SolverAdvanced = new TaskSketcherSolverAdvanced(sketchView); Content.push_back(Messages); + Content.push_back(SolverAdvanced); Content.push_back(General); Content.push_back(Constraints); Content.push_back(Elements); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + if( !hGrp->GetBool("ShowMessagesWidget",true)) + Messages->hideGroupBox(); + if( !hGrp->GetBool("ShowSolverAdvancedWidget",false)) + SolverAdvanced->hideGroupBox(); + if( !hGrp->GetBool("ShowEditControlWidget",false)) + General->hideGroupBox(); + if( !hGrp->GetBool("ShowConstraintsWidget",true)) + Constraints->hideGroupBox(); + if( !hGrp->GetBool("ShowElementsWidget",true)) + Elements->hideGroupBox(); App::Document* document = sketchView->getObject()->getDocument(); connectUndoDocument = @@ -90,12 +104,19 @@ void TaskDlgEditSketch::clicked(int) } bool TaskDlgEditSketch::accept() -{ +{ return true; } bool TaskDlgEditSketch::reject() { + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + hGrp->SetBool("ShowMessagesWidget",Messages->isGroupVisible()); + hGrp->SetBool("ShowSolverAdvancedWidget",SolverAdvanced->isGroupVisible()); + hGrp->SetBool("ShowEditControlWidget",General->isGroupVisible()); + hGrp->SetBool("ShowConstraintsWidget",Constraints->isGroupVisible()); + hGrp->SetBool("ShowElementsWidget",Elements->isGroupVisible()); + std::string document = getDocumentName(); // needed because resetEdit() deletes this instance Gui::Command::doCommand(Gui::Command::Gui,"Gui.getDocument('%s').resetEdit()", document.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').recompute()", document.c_str()); diff --git a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h index 27a038350..bcff040f9 100644 --- a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h +++ b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h @@ -31,6 +31,7 @@ #include "TaskSketcherElements.h" #include "TaskSketcherGeneral.h" #include "TaskSketcherMessages.h" +#include "TaskSketcherSolverAdvanced.h" #include typedef boost::signals::connection Connection; @@ -75,6 +76,7 @@ protected: TaskSketcherElements *Elements; TaskSketcherGeneral *General; TaskSketcherMessages *Messages; + TaskSketcherSolverAdvanced *SolverAdvanced; Connection connectUndoDocument; Connection connectRedoDocument; }; diff --git a/src/Mod/Sketcher/Gui/TaskSketcherSolverAdvanced.cpp b/src/Mod/Sketcher/Gui/TaskSketcherSolverAdvanced.cpp new file mode 100644 index 000000000..6c8432bf9 --- /dev/null +++ b/src/Mod/Sketcher/Gui/TaskSketcherSolverAdvanced.cpp @@ -0,0 +1,466 @@ +/*************************************************************************** + * Copyright (c) 2015 Abdullah Tahiri +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include "ViewProviderSketch.h" + +using namespace SketcherGui; +using namespace Gui::TaskView; + +TaskSketcherSolverAdvanced::TaskSketcherSolverAdvanced(ViewProviderSketch *sketchView) + : TaskBox(Gui::BitmapFactory().pixmap("document-new"),tr("Advanced solver control"),true, 0) + , sketchView(sketchView) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskSketcherSolverAdvanced(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + this->groupLayout()->addWidget(proxy); + + ui->comboBoxDefaultSolver->onRestore(); + ui->spinBoxMaxIter->onRestore(); + ui->checkBoxSketchSizeMultiplier->onRestore(); + ui->lineEditCovergence->onRestore(); + ui->comboBoxQRMethod->onRestore(); + ui->comboBoxRedundantDefaultSolver->onRestore(); + ui->spinBoxRedundantSolverMaxIterations->onRestore(); + ui->checkBoxRedundantSketchSizeMultiplier->onRestore(); + ui->lineEditRedundantConvergence->onRestore(); + ui->comboBoxDebugMode->onRestore(); + + updateSketchObject(); +} + +TaskSketcherSolverAdvanced::~TaskSketcherSolverAdvanced() +{ + delete ui; +} + +void TaskSketcherSolverAdvanced::updateDefaultMethodParameters(void) +{ + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/SolverAdvanced"); + + switch(ui->comboBoxDefaultSolver->currentIndex()) + { + case 0: // BFGS + ui->labelSolverParam1->setText(QString::fromLatin1("")); + ui->labelSolverParam2->setText(QString::fromLatin1("")); + ui->labelSolverParam3->setText(QString::fromLatin1("")); + ui->lineEditSolverParam1->setDisabled(true); + ui->lineEditSolverParam2->setDisabled(true); + ui->lineEditSolverParam3->setDisabled(true); + break; + case 1: // LM + { + ui->labelSolverParam1->setText(QString::fromLatin1("Eps")); + ui->labelSolverParam2->setText(QString::fromLatin1("Eps1")); + ui->labelSolverParam3->setText(QString::fromLatin1("Tau")); + ui->lineEditSolverParam1->setEnabled(true); + ui->lineEditSolverParam2->setEnabled(true); + ui->lineEditSolverParam3->setEnabled(true); + double eps = hGrp->GetFloat("LM_eps",1E-10); + double eps1 = hGrp->GetFloat("LM_eps1",1E-80); + double tau = hGrp->GetFloat("LM_tau",1E-3); + ui->lineEditSolverParam1->setText(QString::number(eps).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + ui->lineEditSolverParam2->setText(QString::number(eps1).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + ui->lineEditSolverParam3->setText(QString::number(tau).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + sketchView->getSketchObject()->getSolvedSketch().setLM_eps(eps); + sketchView->getSketchObject()->getSolvedSketch().setLM_eps1(eps1); + sketchView->getSketchObject()->getSolvedSketch().setLM_tau(eps1); + break; + } + case 2: // DogLeg + { + ui->labelSolverParam1->setText(QString::fromLatin1("Tolg")); + ui->labelSolverParam2->setText(QString::fromLatin1("Tolx")); + ui->labelSolverParam3->setText(QString::fromLatin1("Tolf")); + ui->lineEditSolverParam1->setEnabled(true); + ui->lineEditSolverParam2->setEnabled(true); + ui->lineEditSolverParam3->setEnabled(true); + double tolg = hGrp->GetFloat("DL_tolg",1E-80); + double tolx = hGrp->GetFloat("DL_tolx",1E-80); + double tolf = hGrp->GetFloat("DL_tolf",1E-10); + ui->lineEditSolverParam1->setText(QString::number(tolg).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + ui->lineEditSolverParam2->setText(QString::number(tolx).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + ui->lineEditSolverParam3->setText(QString::number(tolf).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + sketchView->getSketchObject()->getSolvedSketch().setDL_tolg(tolg); + sketchView->getSketchObject()->getSolvedSketch().setDL_tolf(tolf); + sketchView->getSketchObject()->getSolvedSketch().setDL_tolx(tolx); + break; + } + } +} + +void TaskSketcherSolverAdvanced::updateRedundantMethodParameters(void) +{ + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/SolverAdvanced"); + + switch(ui->comboBoxRedundantDefaultSolver->currentIndex()) + { + case 0: // BFGS + ui->labelRedundantSolverParam1->setText(QString::fromLatin1("")); + ui->labelRedundantSolverParam2->setText(QString::fromLatin1("")); + ui->labelRedundantSolverParam3->setText(QString::fromLatin1("")); + ui->lineEditRedundantSolverParam1->setDisabled(true); + ui->lineEditRedundantSolverParam2->setDisabled(true); + ui->lineEditRedundantSolverParam3->setDisabled(true); + break; + case 1: // LM + { + ui->labelRedundantSolverParam1->setText(QString::fromLatin1("R.Eps")); + ui->labelRedundantSolverParam2->setText(QString::fromLatin1("R.Eps1")); + ui->labelRedundantSolverParam3->setText(QString::fromLatin1("R.Tau")); + ui->lineEditRedundantSolverParam1->setEnabled(true); + ui->lineEditRedundantSolverParam2->setEnabled(true); + ui->lineEditRedundantSolverParam3->setEnabled(true); + double eps = hGrp->GetFloat("Redundant_LM_eps",1E-10); + double eps1 = hGrp->GetFloat("Redundant_LM_eps1",1E-80); + double tau = hGrp->GetFloat("Redundant_LM_tau",1E-3); + ui->lineEditRedundantSolverParam1->setText(QString::number(eps).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + ui->lineEditRedundantSolverParam2->setText(QString::number(eps1).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + ui->lineEditRedundantSolverParam3->setText(QString::number(tau).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + sketchView->getSketchObject()->getSolvedSketch().setLM_epsRedundant(eps); + sketchView->getSketchObject()->getSolvedSketch().setLM_eps1Redundant(eps1); + sketchView->getSketchObject()->getSolvedSketch().setLM_tauRedundant(eps1); + break; + } + case 2: // DogLeg + { + ui->labelRedundantSolverParam1->setText(QString::fromLatin1("R.Tolg")); + ui->labelRedundantSolverParam2->setText(QString::fromLatin1("R.Tolx")); + ui->labelRedundantSolverParam3->setText(QString::fromLatin1("R.Tolf")); + ui->lineEditRedundantSolverParam1->setEnabled(true); + ui->lineEditRedundantSolverParam2->setEnabled(true); + ui->lineEditRedundantSolverParam3->setEnabled(true); + double tolg = hGrp->GetFloat("Redundant_DL_tolg",1E-80); + double tolx = hGrp->GetFloat("Redundant_DL_tolx",1E-80); + double tolf = hGrp->GetFloat("Redundant_DL_tolf",1E-10); + ui->lineEditRedundantSolverParam1->setText(QString::number(tolg).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + ui->lineEditRedundantSolverParam2->setText(QString::number(tolx).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + ui->lineEditRedundantSolverParam3->setText(QString::number(tolf).remove(QString::fromLatin1("+").replace(QString::fromLatin1("e0"),QString::fromLatin1("E")).toUpper())); + sketchView->getSketchObject()->getSolvedSketch().setDL_tolgRedundant(tolg); + sketchView->getSketchObject()->getSolvedSketch().setDL_tolfRedundant(tolf); + sketchView->getSketchObject()->getSolvedSketch().setDL_tolxRedundant(tolx); + break; + } + } +} + +void TaskSketcherSolverAdvanced::on_lineEditSolverParam1_editingFinished() +{ + QString text = ui->lineEditSolverParam1->text(); + double val = text.toDouble(); + QString sci = QString::number(val); + sci.remove(QString::fromLatin1("+")); + sci.replace(QString::fromLatin1("e0"),QString::fromLatin1("E")); + ui->lineEditSolverParam1->setText(sci.toUpper()); + + switch(ui->comboBoxDefaultSolver->currentIndex()) + { + case 1: // LM + { + sketchView->getSketchObject()->getSolvedSketch().setLM_eps(val); + ui->lineEditSolverParam1->setEntryName("LM_eps"); + ui->lineEditSolverParam1->onSave(); + break; + } + case 2: // DogLeg + { + sketchView->getSketchObject()->getSolvedSketch().setDL_tolg(val); + ui->lineEditSolverParam1->setEntryName("DL_tolg"); + ui->lineEditSolverParam1->onSave(); + break; + } + } +} + +void TaskSketcherSolverAdvanced::on_lineEditRedundantSolverParam1_editingFinished() +{ + QString text = ui->lineEditRedundantSolverParam1->text(); + double val = text.toDouble(); + QString sci = QString::number(val); + sci.remove(QString::fromLatin1("+")); + sci.replace(QString::fromLatin1("e0"),QString::fromLatin1("E")); + ui->lineEditRedundantSolverParam1->setText(sci.toUpper()); + + switch(ui->comboBoxDefaultSolver->currentIndex()) + { + case 1: // LM + { + sketchView->getSketchObject()->getSolvedSketch().setLM_epsRedundant(val); + ui->lineEditRedundantSolverParam1->setEntryName("Redundant_LM_eps"); + ui->lineEditRedundantSolverParam1->onSave(); + break; + } + case 2: // DogLeg + { + sketchView->getSketchObject()->getSolvedSketch().setDL_tolgRedundant(val); + ui->lineEditRedundantSolverParam1->setEntryName("Redundant_DL_tolg"); + ui->lineEditRedundantSolverParam1->onSave(); + break; + } + } +} + +void TaskSketcherSolverAdvanced::on_lineEditSolverParam2_editingFinished() +{ + QString text = ui->lineEditSolverParam2->text(); + double val = text.toDouble(); + QString sci = QString::number(val); + sci.remove(QString::fromLatin1("+")); + sci.replace(QString::fromLatin1("e0"),QString::fromLatin1("E")); + ui->lineEditSolverParam2->setText(sci.toUpper()); + + switch(ui->comboBoxDefaultSolver->currentIndex()) + { + case 1: // LM + { + sketchView->getSketchObject()->getSolvedSketch().setLM_eps1(val); + ui->lineEditSolverParam2->setEntryName("LM_eps1"); + ui->lineEditSolverParam2->onSave(); + break; + } + case 2: // DogLeg + { + sketchView->getSketchObject()->getSolvedSketch().setDL_tolx(val); + ui->lineEditSolverParam2->setEntryName("DL_tolx"); + ui->lineEditSolverParam2->onSave(); + break; + } + } +} + +void TaskSketcherSolverAdvanced::on_lineEditRedundantSolverParam2_editingFinished() +{ + QString text = ui->lineEditRedundantSolverParam2->text(); + double val = text.toDouble(); + QString sci = QString::number(val); + sci.remove(QString::fromLatin1("+")); + sci.replace(QString::fromLatin1("e0"),QString::fromLatin1("E")); + ui->lineEditRedundantSolverParam2->setText(sci.toUpper()); + + switch(ui->comboBoxDefaultSolver->currentIndex()) + { + case 1: // LM + { + sketchView->getSketchObject()->getSolvedSketch().setLM_eps1Redundant(val); + ui->lineEditRedundantSolverParam2->setEntryName("Redundant_LM_eps1"); + ui->lineEditRedundantSolverParam2->onSave(); + break; + } + case 2: // DogLeg + { + sketchView->getSketchObject()->getSolvedSketch().setDL_tolxRedundant(val); + ui->lineEditRedundantSolverParam2->setEntryName("Redundant_DL_tolx"); + ui->lineEditRedundantSolverParam2->onSave(); + break; + } + } +} + +void TaskSketcherSolverAdvanced::on_lineEditSolverParam3_editingFinished() +{ + QString text = ui->lineEditSolverParam3->text(); + double val = text.toDouble(); + QString sci = QString::number(val); + sci.remove(QString::fromLatin1("+")); + sci.replace(QString::fromLatin1("e0"),QString::fromLatin1("E")); + ui->lineEditSolverParam3->setText(sci.toUpper()); + + switch(ui->comboBoxDefaultSolver->currentIndex()) + { + case 1: // LM + { + sketchView->getSketchObject()->getSolvedSketch().setLM_tau(val); + ui->lineEditSolverParam3->setEntryName("LM_tau"); + ui->lineEditSolverParam3->onSave(); + break; + } + case 2: // DogLeg + { + sketchView->getSketchObject()->getSolvedSketch().setDL_tolf(val); + ui->lineEditSolverParam3->setEntryName("DL_tolf"); + ui->lineEditSolverParam3->onSave(); + break; + } + } +} + +void TaskSketcherSolverAdvanced::on_lineEditRedundantSolverParam3_editingFinished() +{ + QString text = ui->lineEditRedundantSolverParam3->text(); + double val = text.toDouble(); + QString sci = QString::number(val); + sci.remove(QString::fromLatin1("+")); + sci.replace(QString::fromLatin1("e0"),QString::fromLatin1("E")); + ui->lineEditRedundantSolverParam3->setText(sci.toUpper()); + + switch(ui->comboBoxDefaultSolver->currentIndex()) + { + case 1: // LM + { + sketchView->getSketchObject()->getSolvedSketch().setLM_tauRedundant(val); + ui->lineEditRedundantSolverParam3->setEntryName("Redundant_LM_tau"); + ui->lineEditRedundantSolverParam3->onSave(); + break; + } + case 2: // DogLeg + { + sketchView->getSketchObject()->getSolvedSketch().setDL_tolfRedundant(val); + ui->lineEditRedundantSolverParam3->setEntryName("Redundant_DL_tolf"); + ui->lineEditRedundantSolverParam3->onSave(); + break; + } + } +} + +void TaskSketcherSolverAdvanced::on_comboBoxDefaultSolver_currentIndexChanged(int index) +{ + ui->comboBoxDefaultSolver->onSave(); + sketchView->getSketchObject()->getSolvedSketch().defaultSolver=(GCS::Algorithm) index; + updateDefaultMethodParameters(); +} + +void TaskSketcherSolverAdvanced::on_spinBoxMaxIter_valueChanged(int i) +{ + ui->spinBoxMaxIter->onSave(); + sketchView->getSketchObject()->getSolvedSketch().setMaxIter(i); +} + +void TaskSketcherSolverAdvanced::on_checkBoxSketchSizeMultiplier_stateChanged(int state) +{ + if(state==Qt::Checked) { + ui->checkBoxSketchSizeMultiplier->onSave(); + sketchView->getSketchObject()->getSolvedSketch().setSketchSizeMultiplier(true); + } + else if (state==Qt::Unchecked) { + ui->checkBoxSketchSizeMultiplier->onSave(); + sketchView->getSketchObject()->getSolvedSketch().setSketchSizeMultiplier(false); + } +} + +void TaskSketcherSolverAdvanced::on_lineEditCovergence_editingFinished() +{ + QString text = ui->lineEditCovergence->text(); + double val = text.toDouble(); + QString sci = QString::number(val); + sci.remove(QString::fromLatin1("+")); + sci.replace(QString::fromLatin1("e0"),QString::fromLatin1("E")); + ui->lineEditCovergence->setText(sci.toUpper()); + + ui->lineEditCovergence->onSave(); + + sketchView->getSketchObject()->getSolvedSketch().setConvergence(val); +} + +void TaskSketcherSolverAdvanced::on_lineEditRedundantConvergence_editingFinished() +{ + QString text = ui->lineEditRedundantConvergence->text(); + double val = text.toDouble(); + QString sci = QString::number(val); + sci.remove(QString::fromLatin1("+")); + sci.replace(QString::fromLatin1("e0"),QString::fromLatin1("E")); + ui->lineEditRedundantConvergence->setText(sci.toUpper()); + + ui->lineEditRedundantConvergence->onSave(); + + sketchView->getSketchObject()->getSolvedSketch().setConvergenceRedundant(val); +} + +void TaskSketcherSolverAdvanced::on_comboBoxQRMethod_currentIndexChanged(int index) +{ + sketchView->getSketchObject()->getSolvedSketch().setQRAlgorithm((GCS::QRAlgorithm) index); + ui->comboBoxQRMethod->onSave(); +} + +void TaskSketcherSolverAdvanced::on_comboBoxRedundantDefaultSolver_currentIndexChanged(int index) +{ + ui->comboBoxRedundantDefaultSolver->onSave(); + sketchView->getSketchObject()->getSolvedSketch().defaultSolverRedundant=(GCS::Algorithm) index; + updateRedundantMethodParameters(); +} + +void TaskSketcherSolverAdvanced::on_spinBoxRedundantSolverMaxIterations_valueChanged(int i) +{ + ui->spinBoxRedundantSolverMaxIterations->onSave(); + sketchView->getSketchObject()->getSolvedSketch().setMaxIterRedundant(i); +} + +void TaskSketcherSolverAdvanced::on_checkBoxRedundantSketchSizeMultiplier_stateChanged(int state) +{ + if(state==Qt::Checked) { + ui->checkBoxRedundantSketchSizeMultiplier->onSave(); + sketchView->getSketchObject()->getSolvedSketch().setSketchSizeMultiplierRedundant(true); + } + else if (state==Qt::Unchecked) { + ui->checkBoxRedundantSketchSizeMultiplier->onSave(); + sketchView->getSketchObject()->getSolvedSketch().setSketchSizeMultiplierRedundant(true); + } +} + +void TaskSketcherSolverAdvanced::on_comboBoxDebugMode_currentIndexChanged(int index) +{ + ui->comboBoxDebugMode->onSave(); + sketchView->getSketchObject()->getSolvedSketch().setDebugMode((GCS::DebugMode) index); +} + +void TaskSketcherSolverAdvanced::updateSketchObject(void) +{ + sketchView->getSketchObject()->getSolvedSketch().setDebugMode((GCS::DebugMode) ui->comboBoxDebugMode->currentIndex()); + sketchView->getSketchObject()->getSolvedSketch().setSketchSizeMultiplierRedundant(ui->checkBoxRedundantSketchSizeMultiplier->isChecked()); + sketchView->getSketchObject()->getSolvedSketch().setMaxIterRedundant(ui->spinBoxRedundantSolverMaxIterations->value()); + sketchView->getSketchObject()->getSolvedSketch().defaultSolverRedundant=(GCS::Algorithm) ui->comboBoxRedundantDefaultSolver->currentIndex(); + sketchView->getSketchObject()->getSolvedSketch().setQRAlgorithm((GCS::QRAlgorithm) ui->comboBoxQRMethod->currentIndex()); + sketchView->getSketchObject()->getSolvedSketch().setConvergenceRedundant(ui->lineEditRedundantConvergence->text().toDouble()); + sketchView->getSketchObject()->getSolvedSketch().setConvergence(ui->lineEditCovergence->text().toDouble()); + sketchView->getSketchObject()->getSolvedSketch().setSketchSizeMultiplier(ui->checkBoxSketchSizeMultiplier->isChecked()); + sketchView->getSketchObject()->getSolvedSketch().setMaxIter(ui->spinBoxMaxIter->value()); + sketchView->getSketchObject()->getSolvedSketch().defaultSolver=(GCS::Algorithm) ui->comboBoxDefaultSolver->currentIndex(); + + updateDefaultMethodParameters(); + updateRedundantMethodParameters(); +} + +#include "moc_TaskSketcherSolverAdvanced.cpp" diff --git a/src/Mod/Sketcher/Gui/TaskSketcherSolverAdvanced.h b/src/Mod/Sketcher/Gui/TaskSketcherSolverAdvanced.h new file mode 100644 index 000000000..3932273e2 --- /dev/null +++ b/src/Mod/Sketcher/Gui/TaskSketcherSolverAdvanced.h @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (c) 2015 Abdullah Tahiri +#include +#include + +class Ui_TaskSketcherSolverAdvanced; + +namespace App { +class Property; +} + +namespace SketcherGui { + +class ViewProviderSketch; + +class TaskSketcherSolverAdvanced : public Gui::TaskView::TaskBox +{ + Q_OBJECT + +public: + TaskSketcherSolverAdvanced(ViewProviderSketch *sketchView); + ~TaskSketcherSolverAdvanced(); + +private Q_SLOTS: + void on_comboBoxDefaultSolver_currentIndexChanged(int index); + void on_spinBoxMaxIter_valueChanged(int i); + void on_checkBoxSketchSizeMultiplier_stateChanged(int state); + void on_lineEditCovergence_editingFinished(); + void on_comboBoxQRMethod_currentIndexChanged(int index); + void on_comboBoxRedundantDefaultSolver_currentIndexChanged(int index); + void on_lineEditRedundantConvergence_editingFinished(); + void on_spinBoxRedundantSolverMaxIterations_valueChanged(int i); + void on_checkBoxRedundantSketchSizeMultiplier_stateChanged(int state); + void on_comboBoxDebugMode_currentIndexChanged(int index); + void on_lineEditSolverParam1_editingFinished(); + void on_lineEditRedundantSolverParam1_editingFinished(); + void on_lineEditSolverParam2_editingFinished(); + void on_lineEditRedundantSolverParam2_editingFinished(); + void on_lineEditSolverParam3_editingFinished(); + void on_lineEditRedundantSolverParam3_editingFinished(); + +protected: + void updateDefaultMethodParameters(void); + void updateRedundantMethodParameters(void); + void updateSketchObject(void); +protected: + ViewProviderSketch *sketchView; + +private: + QWidget* proxy; + Ui_TaskSketcherSolverAdvanced* ui; +}; + +} //namespace SketcherGui + +#endif // GUI_TASKVIEW_TaskSketcherSolverAdvanced_H diff --git a/src/Mod/Sketcher/Gui/TaskSketcherSolverAdvanced.ui b/src/Mod/Sketcher/Gui/TaskSketcherSolverAdvanced.ui new file mode 100644 index 000000000..93eb4a71e --- /dev/null +++ b/src/Mod/Sketcher/Gui/TaskSketcherSolverAdvanced.ui @@ -0,0 +1,545 @@ + + + TaskSketcherSolverAdvanced + + + + 0 + 0 + 326 + 619 + + + + Form + + + + + + + + Default algorithm used for Sketch solving + + + Default Solver: + + + + + + + 2 + + + DefaultSolver + + + Mod/Sketcher/SolverAdvanced + + + + BFGS + + + + + LevenbergMarquardt + + + + + DogLeg + + + + + + + + + + + + Maximum number of iterations of the default algorithm + + + Maximum Iterations: + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 999 + + + 100 + + + MaxIter + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + If selected, the Maximum iterations value is multiplied by the sketch size + + + Sketch size multiplier: + + + + + + + + 0 + 0 + + + + Qt::RightToLeft + + + + + + SketchSizeMultiplier + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Error threshold under which convergence is reached + + + Convergence: + + + + + + + Qt::LeftToRight + + + 1E-10 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Covergence + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Param1 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + param + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Param2 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + param + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Param3 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + param + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Algorithm used for the rank revealing QR decomposition + + + QR Algorithm: + + + + + + + 1 + + + QRMethod + + + Mod/Sketcher/SolverAdvanced + + + + Eigen Dense QR + + + + + Eigen Sparse QR + + + + + + + + + + + + Solving algorithm used for determination of Redundant constraints + + + Redundant Solver: + + + + + + + RedundantDefaultSolver + + + Mod/Sketcher/SolverAdvanced + + + + BFGS + + + + + LevenbergMarquardt + + + + + DogLeg + + + + + + + + + + + + Maximum number of iterations of the solver used for determination of Redundant constraints + + + Red. Max Iterations: + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 999 + + + 100 + + + RedundantSolverMaxIterations + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + If selected, the Maximum iterations value for the redundant algorithm is multiplied by the sketch size + + + Red. Sketch size multiplier: + + + + + + + Qt::RightToLeft + + + + + + RedundantSketchSizeMultiplier + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Error threshold under which convergence is reached for the solving of redundant constraints + + + Red. Convergence + + + + + + + 1E-10 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + RedundantConvergence + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Red. Param1 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + param + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Red. Param2 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + param + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Red. Param3 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + param + + + Mod/Sketcher/SolverAdvanced + + + + + + + + + + + Degree of verbosity of the debug output to the console + + + Console Debug mode: + + + + + + + 1 + + + DebugMode + + + Mod/Sketcher/SolverAdvanced + + + + None + + + + + Minimum + + + + + Iteration Level + + + + + + + + + + + Gui::PrefLineEdit + QLineEdit +
Gui/PrefWidgets.h
+
+ + Gui::PrefComboBox + QComboBox +
Gui/PrefWidgets.h
+
+ + Gui::PrefCheckBox + QCheckBox +
Gui/PrefWidgets.h
+
+ + Gui::PrefSpinBox + QSpinBox +
Gui/PrefWidgets.h
+
+
+ + +