GCS.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) Konstantinos Poulios      (logari81@gmail.com) 2011     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 #include <iostream>
00023 #include <algorithm>
00024 #include <cfloat>
00025 
00026 #include "GCS.h"
00027 #include "qp_eq.h"
00028 #include <Eigen/QR>
00029 
00030 namespace GCS
00031 {
00032 
00034 // Solver
00036 
00037 // System
00038 System::System()
00039 : clist(0),
00040   c2p(), p2c(),
00041   subsys0(0),
00042   subsys1(0),
00043   subsys2(0),
00044   reference(),
00045   init(false)
00046 {
00047 }
00048 
00049 System::System(std::vector<Constraint *> clist_)
00050 : c2p(), p2c(),
00051   subsys0(0),
00052   subsys1(0),
00053   subsys2(0),
00054   reference(),
00055   init(false)
00056 {
00057     // create own (shallow) copy of constraints
00058     for (std::vector<Constraint *>::iterator constr=clist_.begin();
00059          constr != clist_.end(); ++constr) {
00060         Constraint *newconstr;
00061         switch ((*constr)->getTypeId()) {
00062             case Equal: {
00063                 ConstraintEqual *oldconstr = static_cast<ConstraintEqual *>(*constr);
00064                 newconstr = new ConstraintEqual(*oldconstr);
00065                 break;
00066             }
00067             case Difference: {
00068                 ConstraintDifference *oldconstr = static_cast<ConstraintDifference *>(*constr);
00069                 newconstr = new ConstraintDifference(*oldconstr);
00070                 break;
00071             }
00072             case P2PDistance: {
00073                 ConstraintP2PDistance *oldconstr = static_cast<ConstraintP2PDistance *>(*constr);
00074                 newconstr = new ConstraintP2PDistance(*oldconstr);
00075                 break;
00076             }
00077             case P2PAngle: {
00078                 ConstraintP2PAngle *oldconstr = static_cast<ConstraintP2PAngle *>(*constr);
00079                 newconstr = new ConstraintP2PAngle(*oldconstr);
00080                 break;
00081             }
00082             case P2LDistance: {
00083                 ConstraintP2LDistance *oldconstr = static_cast<ConstraintP2LDistance *>(*constr);
00084                 newconstr = new ConstraintP2LDistance(*oldconstr);
00085                 break;
00086             }
00087             case PointOnLine: {
00088                 ConstraintPointOnLine *oldconstr = static_cast<ConstraintPointOnLine *>(*constr);
00089                 newconstr = new ConstraintPointOnLine(*oldconstr);
00090                 break;
00091             }
00092             case Parallel: {
00093                 ConstraintParallel *oldconstr = static_cast<ConstraintParallel *>(*constr);
00094                 newconstr = new ConstraintParallel(*oldconstr);
00095                 break;
00096             }
00097             case Perpendicular: {
00098                 ConstraintPerpendicular *oldconstr = static_cast<ConstraintPerpendicular *>(*constr);
00099                 newconstr = new ConstraintPerpendicular(*oldconstr);
00100                 break;
00101             }
00102             case L2LAngle: {
00103                 ConstraintL2LAngle *oldconstr = static_cast<ConstraintL2LAngle *>(*constr);
00104                 newconstr = new ConstraintL2LAngle(*oldconstr);
00105                 break;
00106             }
00107             case MidpointOnLine: {
00108                 ConstraintMidpointOnLine *oldconstr = static_cast<ConstraintMidpointOnLine *>(*constr);
00109                 newconstr = new ConstraintMidpointOnLine(*oldconstr);
00110                 break;
00111             }
00112             case None:
00113                 break;
00114         }
00115         if (newconstr)
00116             addConstraint(newconstr);
00117     }
00118 }
00119 
00120 System::~System()
00121 {
00122     clear();
00123 }
00124 
00125 void System::clear()
00126 {
00127     clearReference();
00128     clearSubSystems();
00129     free(clist);
00130     c2p.clear();
00131     p2c.clear();
00132 }
00133 
00134 void System::clearByTag(int tagId)
00135 {
00136     std::vector<Constraint *> constrvec;
00137     for (std::vector<Constraint *>::const_iterator
00138          constr=clist.begin(); constr != clist.end(); ++constr) {
00139         if ((*constr)->getTag() == tagId)
00140             constrvec.push_back(*constr);
00141     }
00142     for (std::vector<Constraint *>::const_iterator
00143          constr=constrvec.begin(); constr != constrvec.end(); ++constr) {
00144         removeConstraint(*constr);
00145     }
00146 }
00147 
00148 int System::addConstraint(Constraint *constr)
00149 {
00150     clearReference();
00151 
00152     clist.push_back(constr);
00153     VEC_pD constr_params = constr->params();
00154     for (VEC_pD::const_iterator param=constr_params.begin();
00155          param != constr_params.end(); ++param) {
00156 //        jacobi.set(constr, *param, 0.);
00157         c2p[constr].push_back(*param);
00158         p2c[*param].push_back(constr);
00159     }
00160     return clist.size()-1;
00161 }
00162 
00163 void System::removeConstraint(Constraint *constr)
00164 {
00165     clearReference();
00166     clearSubSystems();
00167 
00168     std::vector<Constraint *>::iterator it;
00169     it = std::find(clist.begin(), clist.end(), constr);
00170     clist.erase(it);
00171 
00172     VEC_pD constr_params = c2p[constr];
00173     for (VEC_pD::const_iterator param=constr_params.begin();
00174          param != constr_params.end(); ++param) {
00175         std::vector<Constraint *> &constraints = p2c[*param];
00176         it = std::find(constraints.begin(), constraints.end(), constr);
00177         constraints.erase(it);
00178     }
00179     c2p.erase(constr);
00180 
00181     std::vector<Constraint *> constrvec;
00182     constrvec.push_back(constr);
00183     free(constrvec);
00184 }
00185 
00186 // basic constraints
00187 
00188 int System::addConstraintEqual(double *param1, double *param2, int tagId)
00189 {
00190     Constraint *constr = new ConstraintEqual(param1, param2);
00191     constr->setTag(tagId);
00192     return addConstraint(constr);
00193 }
00194 
00195 int System::addConstraintDifference(double *param1, double *param2,
00196                                     double *difference, int tagId)
00197 {
00198     Constraint *constr = new ConstraintDifference(param1, param2, difference);
00199     constr->setTag(tagId);
00200     return addConstraint(constr);
00201 }
00202 
00203 int System::addConstraintP2PDistance(Point &p1, Point &p2, double *distance, int tagId)
00204 {
00205     Constraint *constr = new ConstraintP2PDistance(p1, p2, distance);
00206     constr->setTag(tagId);
00207     return addConstraint(constr);
00208 }
00209 
00210 int System::addConstraintP2PAngle(Point &p1, Point &p2, double *angle,
00211                                   double incr_angle, int tagId)
00212 {
00213     Constraint *constr = new ConstraintP2PAngle(p1, p2, angle, incr_angle);
00214     constr->setTag(tagId);
00215     return addConstraint(constr);
00216 }
00217 
00218 int System::addConstraintP2PAngle(Point &p1, Point &p2, double *angle, int tagId)
00219 {
00220     return addConstraintP2PAngle(p1, p2, angle, 0.);
00221 }
00222 
00223 int System::addConstraintP2LDistance(Point &p, Line &l, double *distance, int tagId)
00224 {
00225     Constraint *constr = new ConstraintP2LDistance(p, l, distance);
00226     constr->setTag(tagId);
00227     return addConstraint(constr);
00228 }
00229 
00230 int System::addConstraintPointOnLine(Point &p, Line &l, int tagId)
00231 {
00232     Constraint *constr = new ConstraintPointOnLine(p, l);
00233     constr->setTag(tagId);
00234     return addConstraint(constr);
00235 }
00236 
00237 int System::addConstraintParallel(Line &l1, Line &l2, int tagId)
00238 {
00239     Constraint *constr = new ConstraintParallel(l1, l2);
00240     constr->setTag(tagId);
00241     return addConstraint(constr);
00242 }
00243 
00244 int System::addConstraintPerpendicular(Line &l1, Line &l2, int tagId)
00245 {
00246     Constraint *constr = new ConstraintPerpendicular(l1, l2);
00247     constr->setTag(tagId);
00248     return addConstraint(constr);
00249 }
00250 
00251 int System::addConstraintPerpendicular(Point &l1p1, Point &l1p2,
00252                                        Point &l2p1, Point &l2p2, int tagId)
00253 {
00254     Constraint *constr = new ConstraintPerpendicular(l1p1, l1p2, l2p1, l2p2);
00255     constr->setTag(tagId);
00256     return addConstraint(constr);
00257 }
00258 
00259 int System::addConstraintL2LAngle(Line &l1, Line &l2, double *angle, int tagId)
00260 {
00261     Constraint *constr = new ConstraintL2LAngle(l1, l2, angle);
00262     constr->setTag(tagId);
00263     return addConstraint(constr);
00264 }
00265 
00266 int System::addConstraintL2LAngle(Point &l1p1, Point &l1p2,
00267                                   Point &l2p1, Point &l2p2, double *angle, int tagId)
00268 {
00269     Constraint *constr = new ConstraintL2LAngle(l1p1, l1p2, l2p1, l2p2, angle);
00270     constr->setTag(tagId);
00271     return addConstraint(constr);
00272 }
00273 
00274 int System::addConstraintMidpointOnLine(Line &l1, Line &l2, int tagId)
00275 {
00276     Constraint *constr = new ConstraintMidpointOnLine(l1, l2);
00277     constr->setTag(tagId);
00278     return addConstraint(constr);
00279 }
00280 
00281 int System::addConstraintMidpointOnLine(Point &l1p1, Point &l1p2,
00282                                         Point &l2p1, Point &l2p2, int tagId)
00283 {
00284     Constraint *constr = new ConstraintMidpointOnLine(l1p1, l1p2, l2p1, l2p2);
00285     constr->setTag(tagId);
00286     return addConstraint(constr);
00287 }
00288 
00289 // derived constraints
00290 
00291 int System::addConstraintP2PCoincident(Point &p1, Point &p2, int tagId)
00292 {
00293            addConstraintEqual(p1.x, p2.x, tagId);
00294     return addConstraintEqual(p1.y, p2.y, tagId);
00295 }
00296 
00297 int System::addConstraintHorizontal(Line &l, int tagId)
00298 {
00299     return addConstraintEqual(l.p1.y, l.p2.y, tagId);
00300 }
00301 
00302 int System::addConstraintHorizontal(Point &p1, Point &p2, int tagId)
00303 {
00304     return addConstraintEqual(p1.y, p2.y, tagId);
00305 }
00306 
00307 int System::addConstraintVertical(Line &l, int tagId)
00308 {
00309     return addConstraintEqual(l.p1.x, l.p2.x, tagId);
00310 }
00311 
00312 int System::addConstraintVertical(Point &p1, Point &p2, int tagId)
00313 {
00314     return addConstraintEqual(p1.x, p2.x, tagId);
00315 }
00316 
00317 int System::addConstraintCoordinateX(Point &p, double *x, int tagId)
00318 {
00319     return addConstraintEqual(p.x, x, tagId);
00320 }
00321 
00322 int System::addConstraintCoordinateY(Point &p, double *y, int tagId)
00323 {
00324     return addConstraintEqual(p.y, y, tagId);
00325 }
00326 
00327 int System::addConstraintArcRules(Arc &a, int tagId)
00328 {
00329            addConstraintP2PAngle(a.center, a.start, a.startAngle, tagId);
00330            addConstraintP2PAngle(a.center, a.end, a.endAngle, tagId);
00331            addConstraintP2PDistance(a.center, a.start, a.rad, tagId);
00332     return addConstraintP2PDistance(a.center, a.end, a.rad, tagId);
00333 }
00334 
00335 int System::addConstraintPointOnCircle(Point &p, Circle &c, int tagId)
00336 {
00337     return addConstraintP2PDistance(p, c.center, c.rad, tagId);
00338 }
00339 
00340 int System::addConstraintPointOnArc(Point &p, Arc &a, int tagId)
00341 {
00342     return addConstraintP2PDistance(p, a.center, a.rad, tagId);
00343 }
00344 
00345 int System::addConstraintTangent(Line &l, Circle &c, int tagId)
00346 {
00347     return addConstraintP2LDistance(c.center, l, c.rad, tagId);
00348 }
00349 
00350 int System::addConstraintTangent(Line &l, Arc &a, int tagId)
00351 {
00352     return addConstraintP2LDistance(a.center, l, a.rad, tagId);
00353 }
00354 
00355 int System::addConstraintTangentLine2Arc(Point &p1, Point &p2, Arc &a, int tagId)
00356 {
00357     addConstraintP2PCoincident(p2, a.start, tagId);
00358     double incr_angle = *(a.startAngle) < *(a.endAngle) ? M_PI/2 : -M_PI/2;
00359     return addConstraintP2PAngle(p1, p2, a.startAngle, incr_angle, tagId);
00360 }
00361 
00362 int System::addConstraintTangentArc2Line(Arc &a, Point &p1, Point &p2, int tagId)
00363 {
00364     addConstraintP2PCoincident(p1, a.end, tagId);
00365     double incr_angle = *(a.startAngle) < *(a.endAngle) ? M_PI/2 : -M_PI/2;
00366     return addConstraintP2PAngle(p1, p2, a.endAngle, incr_angle, tagId);
00367 }
00368 
00369 int System::addConstraintCircleRadius(Circle &c, double *radius, int tagId)
00370 {
00371     return addConstraintEqual(c.rad, radius, tagId);
00372 }
00373 
00374 int System::addConstraintArcRadius(Arc &a, double *radius, int tagId)
00375 {
00376     return addConstraintEqual(a.rad, radius, tagId);
00377 }
00378 
00379 int System::addConstraintEqualLength(Line &l1, Line &l2, double *length, int tagId)
00380 {
00381            addConstraintP2PDistance(l1.p1, l1.p2, length, tagId);
00382     return addConstraintP2PDistance(l2.p1, l2.p2, length, tagId);
00383 }
00384 
00385 int System::addConstraintEqualRadius(Circle &c1, Circle &c2, int tagId)
00386 {
00387     return addConstraintEqual(c1.rad, c2.rad, tagId);
00388 }
00389 
00390 int System::addConstraintEqualRadius(Circle &c1, Arc &a2, int tagId)
00391 {
00392     return addConstraintEqual(c1.rad, a2.rad, tagId);
00393 }
00394 
00395 int System::addConstraintEqualRadius(Arc &a1, Arc &a2, int tagId)
00396 {
00397     return addConstraintEqual(a1.rad, a2.rad, tagId);
00398 }
00399 
00400 int System::addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId)
00401 {
00402     addConstraintPerpendicular(p1, p2, l.p1, l.p2, tagId);
00403     return addConstraintMidpointOnLine(p1, p2, l.p1, l.p2, tagId);
00404 }
00405 
00406 void System::rescaleConstraint(int id, double coeff)
00407 {
00408     if (id >= clist.size() || id < 0)
00409         return;
00410     if (clist[id])
00411         clist[id]->rescale(coeff);
00412 }
00413 
00414 
00415 void System::initSolution(VEC_pD &params)
00416 {
00417     // - Stores the current parameters in the vector "reference"
00418     // - Identifies the equality constraints tagged with ids >= 0
00419     //   and prepares a corresponding system reduction
00420     // - Organizes the rest of constraints into two subsystems for
00421     //   tag ids >=0 and < 0 respectively and applies the
00422     //   system reduction specified in the previous step
00423 
00424     clearReference();
00425     for (VEC_pD::const_iterator param=params.begin();
00426          param != params.end(); ++param)
00427         reference[*param] = **param;
00428 
00429     // identification of equality constraints and parameter reduction
00430     std::set<Constraint *> eliminated;  // constraints that will be eliminated through reduction
00431     reductionmap.clear();
00432     {
00433         VEC_pD reduced_params=params;
00434         MAP_pD_I params_index;
00435         for (int i=0; i < int(params.size()); ++i)
00436             params_index[params[i]] = i;
00437 
00438         for (std::vector<Constraint *>::const_iterator constr=clist.begin();
00439             constr != clist.end(); ++constr) {
00440             if ((*constr)->getTag() >= 0 && (*constr)->getTypeId() == Equal) {
00441                 MAP_pD_I::const_iterator it1,it2;
00442                 it1 = params_index.find((*constr)->params()[0]);
00443                 it2 = params_index.find((*constr)->params()[1]);
00444                 if (it1 != params_index.end() && it2 != params_index.end()) {
00445                     eliminated.insert(*constr);
00446                     double *p_kept = reduced_params[it1->second];
00447                     double *p_replaced = reduced_params[it2->second];
00448                     for (int i=0; i < int(params.size()); ++i)
00449                        if (reduced_params[i] == p_replaced)
00450                            reduced_params[i] = p_kept;
00451                 }
00452             }
00453         }
00454         for (int i=0; i < int(params.size()); ++i)
00455             if (params[i] != reduced_params[i])
00456                 reductionmap[params[i]] = reduced_params[i];
00457     }
00458 
00459     int i=0;
00460     std::vector<Constraint *> clist0, clist1, clist2;
00461     for (std::vector<Constraint *>::const_iterator constr=clist.begin();
00462          constr != clist.end(); ++constr, i++) {
00463         if (eliminated.count(*constr) == 0) {
00464             if ((*constr)->getTag() >= 0)
00465                 clist0.push_back(*constr);
00466             else if ((*constr)->getTag() == -1) // move constraints
00467                 clist1.push_back(*constr);
00468             else // distance from reference constraints
00469                 clist2.push_back(*constr);
00470         }
00471     }
00472 
00473     clearSubSystems();
00474     if (clist0.size() > 0)
00475         subsys0 = new SubSystem(clist0, params, reductionmap);
00476     if (clist1.size() > 0)
00477         subsys1 = new SubSystem(clist1, params, reductionmap);
00478     if (clist2.size() > 0)
00479         subsys2 = new SubSystem(clist2, params, reductionmap);
00480     init = true;
00481 }
00482 
00483 void System::clearReference()
00484 {
00485     init = false;
00486     reference.clear();
00487 }
00488 
00489 void System::resetToReference()
00490 {
00491     for (MAP_pD_D::const_iterator it=reference.begin();
00492          it != reference.end(); ++it)
00493         *(it->first) = it->second;
00494 }
00495 
00496 int System::solve(VEC_pD &params, bool isFine, Algorithm alg)
00497 {
00498     initSolution(params);
00499     return solve(isFine, alg);
00500 }
00501 
00502 int System::solve(bool isFine, Algorithm alg)
00503 {
00504     if (subsys0) {
00505         resetToReference();
00506         if (subsys2) {
00507             int ret = solve(subsys0, subsys2, isFine);
00508             if (subsys1) // give subsys1 higher priority than subsys2
00509                          // in this case subsys2 acts like a preconditioner
00510                 return solve(subsys0, subsys1, isFine);
00511             else
00512                 return ret;
00513         }
00514         else if (subsys1)
00515             return solve(subsys0, subsys1, isFine);
00516         else
00517             return solve(subsys0, isFine, alg);
00518     }
00519     else if (subsys1) {
00520         resetToReference();
00521         if (subsys2)
00522             return solve(subsys1, subsys2, isFine);
00523         else
00524             return solve(subsys1, isFine, alg);
00525     }
00526     else
00527         // return success in order to permit coincidence constraints to be applied
00528         return Success;
00529 }
00530 
00531 int System::solve(SubSystem *subsys, bool isFine, Algorithm alg)
00532 {
00533     if (alg == BFGS)
00534         return solve_BFGS(subsys, isFine);
00535     else if (alg == LevenbergMarquardt)
00536         return solve_LM(subsys);
00537     else if (alg == DogLeg)
00538         return solve_DL(subsys);
00539 }
00540 
00541 int System::solve_BFGS(SubSystem *subsys, bool isFine)
00542 {
00543     int xsize = subsys->pSize();
00544     if (xsize == 0)
00545         return Success;
00546 
00547     subsys->redirectParams();
00548 
00549     Eigen::MatrixXd D = Eigen::MatrixXd::Identity(xsize, xsize);
00550     Eigen::VectorXd x(xsize);
00551     Eigen::VectorXd xdir(xsize);
00552     Eigen::VectorXd grad(xsize);
00553     Eigen::VectorXd h(xsize);
00554     Eigen::VectorXd y(xsize);
00555     Eigen::VectorXd Dy(xsize);
00556 
00557     // Initial unknowns vector and initial gradient vector
00558     subsys->getParams(x);
00559     subsys->calcGrad(grad);
00560 
00561     // Initial search direction oposed to gradient (steepest-descent)
00562     xdir = -grad;
00563     lineSearch(subsys, xdir);
00564     double err = subsys->error();
00565 
00566     h = x;
00567     subsys->getParams(x);
00568     h = x - h; // = x - xold
00569 
00570     double convergence = isFine ? XconvergenceFine : XconvergenceRough;
00571     int maxIterNumber = MaxIterations * xsize;
00572     double diverging_lim = 1e6*err + 1e12;
00573 
00574     for (int iter=1; iter < maxIterNumber; iter++) {
00575 
00576         if (h.norm() <= convergence || err <= smallF)
00577             break;
00578         if (err > diverging_lim || err != err) // check for diverging and NaN
00579             break;
00580 
00581         y = grad;
00582         subsys->calcGrad(grad);
00583         y = grad - y; // = grad - gradold
00584 
00585         double hty = h.dot(y);
00586         //make sure that hty is never 0
00587         if (hty == 0)
00588             hty = .0000000001;
00589 
00590         Dy = D * y;
00591 
00592         double ytDy = y.dot(Dy);
00593 
00594         //Now calculate the BFGS update on D
00595         D += (1.+ytDy/hty)/hty * h * h.transpose();
00596         D -= 1./hty * (h * Dy.transpose() + Dy * h.transpose());
00597 
00598         xdir = -D * grad;
00599         lineSearch(subsys, xdir);
00600         err = subsys->error();
00601 
00602         h = x;
00603         subsys->getParams(x);
00604         h = x - h; // = x - xold
00605     }
00606 
00607     subsys->revertParams();
00608 
00609     if (err <= smallF)
00610         return Success;
00611     if (h.norm() <= convergence)
00612         return Converged;
00613     return Failed;
00614 }
00615 
00616 int System::solve_LM(SubSystem* subsys)
00617 {
00618     int xsize = subsys->pSize();
00619     int csize = subsys->cSize();
00620 
00621     if (xsize == 0)
00622         return Success;
00623 
00624     Eigen::VectorXd e(csize), e_new(csize); // vector of all function errors (every constraint is one function)
00625     Eigen::MatrixXd J(csize, xsize);        // Jacobi of the subsystem
00626     Eigen::MatrixXd A(xsize, xsize);
00627     Eigen::VectorXd x(xsize), h(xsize), x_new(xsize), g(xsize), diag_A(xsize);
00628 
00629     subsys->redirectParams();
00630 
00631     subsys->getParams(x);
00632     subsys->calcResidual(e);
00633     e*=-1;
00634 
00635     int maxIterNumber = MaxIterations * xsize;
00636     double diverging_lim = 1e6*e.squaredNorm() + 1e12;
00637 
00638     double eps=1e-10, eps1=1e-80;
00639     double tau=1e-3;
00640     double nu=2, mu=0;
00641     int iter=0, stop=0;
00642     for (iter=0; iter < maxIterNumber && !stop; ++iter) {
00643 
00644         // check error
00645         double err=e.squaredNorm();
00646         if (err <= eps) { // error is small, Success
00647             stop = 1;
00648             break;
00649         }
00650         else if (err > diverging_lim || err != err) { // check for diverging and NaN
00651             stop = 6;
00652             break;
00653         }
00654 
00655         // J^T J, J^T e
00656         subsys->calcJacobi(J);;
00657 
00658         A = J.transpose()*J;
00659         g = J.transpose()*e;
00660 
00661         // Compute ||J^T e||_inf
00662         double g_inf = g.lpNorm<Eigen::Infinity>();
00663         diag_A = A.diagonal(); // save diagonal entries so that augmentation can be later canceled
00664 
00665         // check for convergence
00666         if (g_inf <= eps1) {
00667             stop = 2;
00668             break;
00669         }
00670 
00671         // compute initial damping factor
00672         if (iter == 0)
00673             mu = tau * A.diagonal().lpNorm<Eigen::Infinity>();
00674 
00675         // determine increment using adaptive damping
00676         int k=0;
00677         while (k < 50) {
00678             // augment normal equations A = A+uI
00679             for (int i=0; i < xsize; ++i)
00680                 A(i,i) += mu;
00681 
00682             //solve augmented functions A*h=-g
00683             h = A.fullPivLu().solve(g);
00684             double rel_error = (A*h - g).norm() / g.norm();
00685 
00686             // check if solving works
00687             if (rel_error < 1e-5) {
00688 
00689                 // compute par's new estimate and ||d_par||^2
00690                 x_new = x + h;
00691                 double h_norm = h.squaredNorm();
00692 
00693                 if (h_norm <= eps1*eps1*x.norm()) { // relative change in p is small, stop
00694                     stop = 3;
00695                     break;
00696                 }
00697                 else if (h_norm >= (x.norm()+eps1)/(DBL_EPSILON*DBL_EPSILON)) { // almost singular
00698                     stop = 4;
00699                     break;
00700                 }
00701 
00702                 subsys->setParams(x_new);
00703                 subsys->calcResidual(e_new);
00704                 e_new *= -1;
00705 
00706                 double dF = e.squaredNorm() - e_new.squaredNorm();
00707                 double dL = h.dot(mu*h+g);
00708 
00709                 if (dF>0. && dL>0.) { // reduction in error, increment is accepted
00710                     double tmp=2*dF/dL-1.;
00711                     mu *= std::max(1./3., 1.-tmp*tmp*tmp);
00712                     nu=2;
00713 
00714                     // update par's estimate
00715                     x = x_new;
00716                     e = e_new;
00717                     break;
00718                 }
00719             }
00720 
00721             // if this point is reached, either the linear system could not be solved or
00722             // the error did not reduce; in any case, the increment must be rejected
00723 
00724             mu*=nu;
00725             nu*=2.0;
00726             for (int i=0; i < xsize; ++i) // restore diagonal J^T J entries
00727                 A(i,i) = diag_A(i);
00728 
00729             k++;
00730         }
00731         if (k > 50) {
00732             stop = 7;
00733             break;
00734         }
00735     }
00736 
00737     if (iter >= maxIterNumber)
00738         stop = 5;
00739 
00740     subsys->revertParams();
00741 
00742     return (stop == 1) ? Success : Failed;
00743 }
00744 
00745 
00746 int System::solve_DL(SubSystem* subsys)
00747 {
00748     double tolg=1e-80, tolx=1e-80, tolf=1e-10;
00749 
00750     int xsize = subsys->pSize();
00751     int csize = subsys->cSize();
00752 
00753     Eigen::VectorXd x(xsize), x_new(xsize);
00754     Eigen::VectorXd fx(csize), fx_new(csize);
00755     Eigen::MatrixXd Jx(csize, xsize), Jx_new(csize, xsize);
00756     Eigen::VectorXd g(xsize), h_sd(xsize), h_gn(xsize), h_dl(xsize);
00757 
00758     subsys->redirectParams();
00759 
00760     double err;
00761     subsys->getParams(x);
00762     subsys->calcResidual(fx, err);
00763     subsys->calcJacobi(Jx);
00764 
00765     g = Jx.transpose()*(-fx);
00766 
00767     // get the infinity norm fx_inf and g_inf
00768     double g_inf = g.lpNorm<Eigen::Infinity>();
00769     double fx_inf = fx.lpNorm<Eigen::Infinity>();
00770 
00771     int maxIterNumber = MaxIterations * xsize;
00772     double diverging_lim = 1e6*err + 1e12;
00773 
00774     double delta=0.1;
00775     double alpha=0.;
00776     double nu=2.;
00777     int iter=0, stop=0, reduce=0;
00778     while (!stop) {
00779 
00780         // check if finished
00781         if (fx_inf <= tolf) // Success
00782             stop = 1;
00783         else if (g_inf <= tolg)
00784             stop = 2;
00785         else if (delta <= tolx*(tolx + x.norm()))
00786             stop = 2;
00787         else if (iter >= maxIterNumber)
00788             stop = 4;
00789         else if (err > diverging_lim || err != err) { // check for diverging and NaN
00790             stop = 6;
00791         }
00792         else {
00793             // get the steepest descent direction
00794             alpha = g.squaredNorm()/(Jx*g).squaredNorm();
00795             h_sd  = alpha*g;
00796 
00797             // get the gauss-newton step
00798             h_gn = Jx.fullPivLu().solve(-fx);
00799             double rel_error = (Jx*h_gn + fx).norm() / fx.norm();
00800             if (rel_error > 1e15)
00801                 break;
00802 
00803             // compute the dogleg step
00804             if (h_gn.norm() < delta) {
00805                 h_dl = h_gn;
00806                 if  (h_dl.norm() <= tolx*(tolx + x.norm())) {
00807                     stop = 5;
00808                     break;
00809                 }
00810             }
00811             else if (alpha*g.norm() >= delta) {
00812                 h_dl = (delta/(alpha*g.norm()))*h_sd;
00813             }
00814             else {
00815                 //compute beta
00816                 double beta = 0;
00817                 Eigen::VectorXd b = h_gn - h_sd;
00818                 double bb = (b.transpose()*b).norm();
00819                 double gb = (h_sd.transpose()*b).norm();
00820                 double c = (delta + h_sd.norm())*(delta - h_sd.norm());
00821 
00822                 if (gb > 0)
00823                     beta = c / (gb + sqrt(gb * gb + c * bb));
00824                 else
00825                     beta = (sqrt(gb * gb + c * bb) - gb)/bb;
00826 
00827                 // and update h_dl and dL with beta
00828                 h_dl = h_sd + beta*b;
00829             }
00830         }
00831 
00832         // see if we are already finished
00833         if (stop)
00834             break;
00835 
00836         // get the new values
00837         double err_new;
00838         x_new = x + h_dl;
00839         subsys->setParams(x_new);
00840         subsys->calcResidual(fx_new, err_new);
00841         subsys->calcJacobi(Jx_new);
00842 
00843         // calculate the linear model and the update ratio
00844         double dL = err - 0.5*(fx + Jx*h_dl).squaredNorm();
00845         double dF = err - err_new;
00846         double rho = dL/dF;
00847 
00848         if (dF > 0 && dL > 0) {
00849             x  = x_new;
00850             Jx = Jx_new;
00851             fx = fx_new;
00852             err = err_new;
00853 
00854             g = Jx.transpose()*(-fx);
00855 
00856             // get infinity norms
00857             g_inf = g.lpNorm<Eigen::Infinity>();
00858             fx_inf = fx.lpNorm<Eigen::Infinity>();
00859         }
00860         else
00861             rho = -1;
00862 
00863         // update delta
00864         if (fabs(rho-1.) < 0.2 && h_dl.norm() > delta/3. && reduce <= 0) {
00865             delta = 3*delta;
00866             nu = 2;
00867             reduce = 0;
00868         }
00869         else if (rho < 0.25) {
00870             delta = delta/nu;
00871             nu = 2*nu;
00872             reduce = 2;
00873         }
00874         else
00875             reduce--;
00876 
00877         // count this iteration and start again
00878         iter++;
00879     }
00880 
00881     subsys->revertParams();
00882 
00883     return (stop == 1) ? Success : Failed;
00884 }
00885 
00886 // The following solver variant solves a system compound of two subsystems
00887 // treating the first of them as of higher priority than the second
00888 int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
00889 {
00890     int xsizeA = subsysA->pSize();
00891     int xsizeB = subsysB->pSize();
00892     int csizeA = subsysA->cSize();
00893 
00894     VEC_pD plist(xsizeA+xsizeB);
00895     {
00896         VEC_pD plistA, plistB;
00897         subsysA->getParamList(plistA);
00898         subsysB->getParamList(plistB);
00899 
00900         std::sort(plistA.begin(),plistA.end());
00901         std::sort(plistB.begin(),plistB.end());
00902 
00903         VEC_pD::const_iterator it;
00904         it = std::set_union(plistA.begin(),plistA.end(),
00905                             plistB.begin(),plistB.end(),plist.begin());
00906         plist.resize(it-plist.begin());
00907     }
00908     int xsize = plist.size();
00909 
00910     Eigen::MatrixXd B = Eigen::MatrixXd::Identity(xsize, xsize);
00911     Eigen::MatrixXd JA(csizeA, xsize);
00912     Eigen::MatrixXd Y,Z;
00913 
00914     Eigen::VectorXd resA(csizeA);
00915     Eigen::VectorXd lambda(csizeA), lambda0(csizeA), lambdadir(csizeA);
00916     Eigen::VectorXd x(xsize), x0(xsize), xdir(xsize), xdir1(xsize);
00917     Eigen::VectorXd grad(xsize);
00918     Eigen::VectorXd h(xsize);
00919     Eigen::VectorXd y(xsize);
00920     Eigen::VectorXd Bh(xsize);
00921 
00922     // We assume that there are no common constraints in subsysA and subsysB
00923     subsysA->redirectParams();
00924     subsysB->redirectParams();
00925 
00926     subsysB->getParams(plist,x);
00927     subsysA->getParams(plist,x);
00928     subsysB->setParams(plist,x);  // just to ensure that A and B are synchronized
00929 
00930     subsysB->calcGrad(plist,grad);
00931     subsysA->calcJacobi(plist,JA);
00932     subsysA->calcResidual(resA);
00933 
00934     double convergence = isFine ? XconvergenceFine : XconvergenceRough;
00935     int maxIterNumber = MaxIterations * xsize;
00936     double diverging_lim = 1e6*subsysA->error() + 1e12;
00937 
00938     double mu = 0;
00939     lambda.setZero();
00940     for (int iter=1; iter < maxIterNumber; iter++) {
00941         int status = qp_eq(B, grad, JA, resA, xdir, Y, Z);
00942         if (status)
00943             break;
00944 
00945         x0 = x;
00946         lambda0 = lambda;
00947         lambda = Y.transpose() * (B * xdir + grad);
00948         lambdadir = lambda - lambda0;
00949 
00950         // line search
00951         {
00952             double eta=0.25;
00953             double tau=0.5;
00954             double rho=0.5;
00955             double alpha=1;
00956             alpha = std::min(alpha, subsysA->maxStep(plist,xdir));
00957 
00958             // Eq. 18.32
00959             // double mu = lambda.lpNorm<Eigen::Infinity>() + 0.01;
00960             // Eq. 18.33
00961             // double mu =  grad.dot(xdir) / ( (1.-rho) * resA.lpNorm<1>());
00962             // Eq. 18.36
00963             mu =  std::max(mu,
00964                            (grad.dot(xdir) +  std::max(0., 0.5*xdir.dot(B*xdir))) /
00965                            ( (1. - rho) * resA.lpNorm<1>() ) );
00966 
00967             // Eq. 18.27
00968             double f0 = subsysB->error() + mu * resA.lpNorm<1>();
00969 
00970             // Eq. 18.29
00971             double deriv = grad.dot(xdir) - mu * resA.lpNorm<1>();
00972 
00973             x = x0 + alpha * xdir;
00974             subsysA->setParams(plist,x);
00975             subsysB->setParams(plist,x);
00976             subsysA->calcResidual(resA);
00977             double f = subsysB->error() + mu * resA.lpNorm<1>();
00978 
00979             // line search, Eq. 18.28
00980             bool first = true;
00981             while (f > f0 + eta * alpha * deriv) {
00982                 if (first) { // try a second order step
00983 //                    xdir1 = JA.jacobiSvd(Eigen::ComputeThinU |
00984 //                                         Eigen::ComputeThinV).solve(-resA);
00985                     xdir1 = -Y*resA;
00986                     x += xdir1; // = x0 + alpha * xdir + xdir1
00987                     subsysA->setParams(plist,x);
00988                     subsysB->setParams(plist,x);
00989                     subsysA->calcResidual(resA);
00990                     f = subsysB->error() + mu * resA.lpNorm<1>();
00991                     if (f < f0 + eta * alpha * deriv)
00992                         break;
00993                 }
00994                 alpha = tau * alpha;
00995                 if (alpha < 1e-8) // let the linesearch fail
00996                     alpha = 0.;
00997                 x = x0 + alpha * xdir;
00998                 subsysA->setParams(plist,x);
00999                 subsysB->setParams(plist,x);
01000                 subsysA->calcResidual(resA);
01001                 f = subsysB->error() + mu * resA.lpNorm<1>();
01002                 if (alpha < 1e-8) // let the linesearch fail
01003                     break;
01004             }
01005             lambda = lambda0 + alpha * lambdadir;
01006 
01007         }
01008         h = x - x0;
01009 
01010         y = grad - JA.transpose() * lambda;
01011         {
01012             subsysB->calcGrad(plist,grad);
01013             subsysA->calcJacobi(plist,JA);
01014             subsysA->calcResidual(resA);
01015         }
01016         y = grad - JA.transpose() * lambda - y; // Eq. 18.13
01017 
01018         if (iter > 1) {
01019             double yTh = y.dot(h);
01020             if (yTh != 0) {
01021                 Bh = B * h;
01022                 //Now calculate the BFGS update on B
01023                 B += 1./yTh * y * y.transpose();
01024                 B -= 1./h.dot(Bh) * (Bh * Bh.transpose());
01025             }
01026         }
01027 
01028         double err = subsysA->error();
01029         if (h.norm() <= convergence && err <= smallF)
01030             break;
01031         if (err > diverging_lim || err != err) // check for diverging and NaN
01032             break;
01033     }
01034 
01035     int ret;
01036     if (subsysA->error() <= smallF)
01037         ret = Success;
01038     else if (h.norm() <= convergence)
01039         ret = Converged;
01040     else
01041         ret = Failed;
01042 
01043     subsysA->revertParams();
01044     subsysB->revertParams();
01045     return ret;
01046 
01047 }
01048 
01049 void System::getSubSystems(std::vector<SubSystem *> &subsysvec)
01050 {
01051     subsysvec.clear();
01052     if (subsys0)
01053         subsysvec.push_back(subsys0);
01054     if (subsys1)
01055         subsysvec.push_back(subsys1);
01056     if (subsys2)
01057         subsysvec.push_back(subsys2);
01058 }
01059 
01060 void System::applySolution()
01061 {
01062     if (subsys2)
01063         subsys2->applySolution();
01064     if (subsys1)
01065         subsys1->applySolution();
01066     if (subsys0)
01067         subsys0->applySolution();
01068 
01069     for (MAP_pD_pD::const_iterator it=reductionmap.begin();
01070          it != reductionmap.end(); ++it)
01071         *(it->first) = *(it->second);
01072 }
01073 
01074 void System::undoSolution()
01075 {
01076     resetToReference();
01077 }
01078 
01079 int System::diagnose(VEC_pD &params, VEC_I &conflicting)
01080 {
01081     // Analyses the constrainess grad of the system and provides feedback
01082     // The vector "conflicting" will hold a group of conflicting constraints
01083     conflicting.clear();
01084     std::vector<VEC_I> conflictingIndex;
01085     VEC_I tags;
01086     Eigen::MatrixXd J(clist.size(), params.size());
01087     int count=0;
01088     for (std::vector<Constraint *>::iterator constr=clist.begin();
01089          constr != clist.end(); ++constr) {
01090         (*constr)->revertParams();
01091         if ((*constr)->getTag() >= 0) {
01092             count++;
01093             tags.push_back((*constr)->getTag());
01094             for (int j=0; j < int(params.size()); j++)
01095                 J(count-1,j) = (*constr)->grad(params[j]);
01096         }
01097     }
01098 
01099     if (J.rows() > 0) {
01100         Eigen::FullPivHouseholderQR<Eigen::MatrixXd> qrJT(J.topRows(count).transpose());
01101         Eigen::MatrixXd Q = qrJT.matrixQ ();
01102         int params_num = qrJT.rows();
01103         int constr_num = qrJT.cols();
01104         int rank = qrJT.rank();
01105 
01106         Eigen::MatrixXd R;
01107         if (constr_num >= params_num)
01108             R = qrJT.matrixQR().triangularView<Eigen::Upper>();
01109         else
01110             R = qrJT.matrixQR().topRows(constr_num)
01111                                .triangularView<Eigen::Upper>();
01112 
01113         if (constr_num > rank) { // conflicting constraints
01114             for (int i=1; i < rank; i++) {
01115                 // eliminate non zeros above pivot
01116                 assert(R(i,i) != 0);
01117                 for (int row=0; row < i; row++) {
01118                     if (R(row,i) != 0) {
01119                         double coef=R(row,i)/R(i,i);
01120                         R.block(row,i+1,1,constr_num-i-1) -= coef * R.block(i,i+1,1,constr_num-i-1);
01121                         R(row,i) = 0;
01122                     }
01123                 }
01124             }
01125             conflictingIndex.resize(constr_num-rank);
01126             for (int j=rank; j < constr_num; j++) {
01127                 for (int row=0; row < rank; row++) {
01128                     if (R(row,j) != 0) {
01129                         int orig_col = qrJT.colsPermutation().indices()[row];
01130                         conflictingIndex[j-rank].push_back(orig_col);
01131                     }
01132                 }
01133                 int orig_col = qrJT.colsPermutation().indices()[j];
01134                 conflictingIndex[j-rank].push_back(orig_col);
01135             }
01136 
01137             SET_I tags_set;
01138             for (int i=0; i < conflictingIndex.size(); i++) {
01139                 for (int j=0; j < conflictingIndex[i].size(); j++) {
01140                     tags_set.insert(tags[conflictingIndex[i][j]]);
01141                 }
01142             }
01143             tags_set.erase(0); // exclude constraints tagged with zero
01144             conflicting.resize(tags_set.size());
01145             std::copy(tags_set.begin(), tags_set.end(), conflicting.begin());
01146 
01147             if (params_num == rank) // over-constrained
01148                 return params_num - constr_num;
01149         }
01150 
01151         return params_num - rank;
01152     }
01153     return params.size();
01154 }
01155 
01156 void System::clearSubSystems()
01157 {
01158     init = false;
01159     std::vector<SubSystem *> subsystems;
01160     getSubSystems(subsystems);
01161     free(subsystems);
01162     subsys0 = NULL;
01163     subsys1 = NULL;
01164     subsys2 = NULL;
01165 }
01166 
01167 double lineSearch(SubSystem *subsys, Eigen::VectorXd &xdir)
01168 {
01169     double f1,f2,f3,alpha1,alpha2,alpha3,alphaStar;
01170 
01171     double alphaMax = subsys->maxStep(xdir);
01172 
01173     Eigen::VectorXd x0, x;
01174 
01175     //Save initial values
01176     subsys->getParams(x0);
01177 
01178     //Start at the initial position alpha1 = 0
01179     alpha1 = 0.;
01180     f1 = subsys->error();
01181 
01182     //Take a step of alpha2 = 1
01183     alpha2 = 1.;
01184     x = x0 + alpha2 * xdir;
01185     subsys->setParams(x);
01186     f2 = subsys->error();
01187 
01188     //Take a step of alpha3 = 2*alpha2
01189     alpha3 = alpha2*2;
01190     x = x0 + alpha3 * xdir;
01191     subsys->setParams(x);
01192     f3 = subsys->error();
01193 
01194     //Now reduce or lengthen alpha2 and alpha3 until the minimum is
01195     //Bracketed by the triplet f1>f2<f3
01196     while (f2 > f1 || f2 > f3) {
01197         if (f2 > f1) {
01198             //If f2 is greater than f1 then we shorten alpha2 and alpha3 closer to f1
01199             //Effectively both are shortened by a factor of two.
01200             alpha3 = alpha2;
01201             f3 = f2;
01202             alpha2 = alpha2 / 2;
01203             x = x0 + alpha2 * xdir;
01204             subsys->setParams(x);
01205             f2 = subsys->error();
01206         }
01207         else if (f2 > f3) {
01208             if (alpha3 >= alphaMax)
01209                 break;
01210             //If f2 is greater than f3 then we increase alpha2 and alpha3 away from f1
01211             //Effectively both are lengthened by a factor of two.
01212             alpha2 = alpha3;
01213             f2 = f3;
01214             alpha3 = alpha3 * 2;
01215             x = x0 + alpha3 * xdir;
01216             subsys->setParams(x);
01217             f3 = subsys->error();
01218         }
01219     }
01220     //Get the alpha for the minimum f of the quadratic approximation
01221     alphaStar = alpha2 + ((alpha2-alpha1)*(f1-f3))/(3*(f1-2*f2+f3));
01222 
01223     //Guarantee that the new alphaStar is within the bracket
01224     if (alphaStar >= alpha3 || alphaStar <= alpha1)
01225         alphaStar = alpha2;
01226 
01227     if (alphaStar > alphaMax)
01228         alphaStar = alphaMax;
01229 
01230     if (alphaStar != alphaStar)
01231         alphaStar = 0.;
01232 
01233     //Take a final step to alphaStar
01234     x = x0 + alphaStar * xdir;
01235     subsys->setParams(x);
01236 
01237     return alphaStar;
01238 }
01239 
01240 
01241 void free(VEC_pD &doublevec)
01242 {
01243     for (VEC_pD::iterator it = doublevec.begin();
01244          it != doublevec.end(); ++it)
01245         if (*it) delete *it;
01246     doublevec.clear();
01247 }
01248 
01249 void free(std::vector<Constraint *> &constrvec)
01250 {
01251     for (std::vector<Constraint *>::iterator constr=constrvec.begin();
01252          constr != constrvec.end(); ++constr) {
01253         if (*constr) {
01254             switch ((*constr)->getTypeId()) {
01255                 case Equal:
01256                     delete static_cast<ConstraintEqual *>(*constr);
01257                     break;
01258                 case Difference:
01259                     delete static_cast<ConstraintDifference *>(*constr);
01260                     break;
01261                 case P2PDistance:
01262                     delete static_cast<ConstraintP2PDistance *>(*constr);
01263                     break;
01264                 case P2PAngle:
01265                     delete static_cast<ConstraintP2PAngle *>(*constr);
01266                     break;
01267                 case P2LDistance:
01268                     delete static_cast<ConstraintP2LDistance *>(*constr);
01269                     break;
01270                 case PointOnLine:
01271                     delete static_cast<ConstraintPointOnLine *>(*constr);
01272                     break;
01273                 case Parallel:
01274                     delete static_cast<ConstraintParallel *>(*constr);
01275                     break;
01276                 case Perpendicular:
01277                     delete static_cast<ConstraintPerpendicular *>(*constr);
01278                     break;
01279                 case L2LAngle:
01280                     delete static_cast<ConstraintL2LAngle *>(*constr);
01281                     break;
01282                 case MidpointOnLine:
01283                     delete static_cast<ConstraintMidpointOnLine *>(*constr);
01284                     break;
01285                 case None:
01286                 default:
01287                     delete *constr;
01288             }
01289         }
01290     }
01291     constrvec.clear();
01292 }
01293 
01294 void free(std::vector<SubSystem *> &subsysvec)
01295 {
01296     for (std::vector<SubSystem *>::iterator it=subsysvec.begin();
01297          it != subsysvec.end(); ++it)
01298         if (*it) delete *it;
01299 }
01300 
01301 
01302 } //namespace GCS

Generated on Wed Nov 23 19:00:15 2011 for FreeCAD by  doxygen 1.6.1