double GradientProjection::computeSteepestDescentVector( valarray<double> const &b, valarray<double> const &x, valarray<double> &g) const { // find steepest descent direction // g = 2 ( b - A x ) // where: A = denseQ + sparseQ // g = 2 ( b - denseQ x) - 2 sparseQ x // // except the 2s don't matter because we compute // the optimal stepsize anyway COLA_ASSERT(x.size()==b.size() && b.size()==g.size()); g = b; for (unsigned i=0; i<denseSize; i++) { for (unsigned j=0; j<denseSize; j++) { g[i] -= (*denseQ)[i*denseSize+j]*x[j]; } } // sparse part: if(sparseQ) { valarray<double> r(x.size()); sparseQ->rightMultiply(x,r); g-=r; } return computeStepSize(g,g); }
LOCA::Abstract::Iterator::StepStatus LOCA::Stepper::preprocess(LOCA::Abstract::Iterator::StepStatus stepStatus) { if (stepStatus == LOCA::Abstract::Iterator::Unsuccessful) { // Restore previous step information curGroupPtr->copy(*prevGroupPtr); } else { // Save previous successful step information prevGroupPtr->copy(*curGroupPtr); } // Compute step size stepStatus = computeStepSize(stepStatus, stepSize); // Set step size in current solution group curGroupPtr->setStepSize(stepSize); // Set previous solution vector in current solution group curGroupPtr->setPrevX(prevGroupPtr->getX()); // Take step in predictor direction curGroupPtr->computeX(*prevGroupPtr, *curPredictorPtr, stepSize); // Allow continuation group to preprocess the step curGroupPtr->preProcessContinuationStep(stepStatus); // Reset solver to compute new solution solverPtr = NOX::Solver::buildSolver(curGroupPtr, noxStatusTestPtr, parsedParams->getSublist("NOX")); return stepStatus; }
/* * Use gradient-projection to solve an instance of * the Variable Placement with Separation Constraints problem. */ unsigned GradientProjection::solve( valarray<double> const &linearCoefficients, valarray<double> &x) { COLA_ASSERT(linearCoefficients.size()==x.size()); COLA_ASSERT(x.size()==denseSize); COLA_ASSERT(numStaticVars>=denseSize); COLA_ASSERT(sparseQ==nullptr || (sparseQ!=nullptr && (vars.size()==sparseQ->rowSize())) ); if(max_iterations==0) return 0; bool converged=false; solver = setupVPSC(); #ifdef MOSEK_AVAILABLE if(solveWithMosek==Outer) { float* ba=new float[vars.size()]; float* xa=new float[vars.size()]; for(unsigned i=0;i<vars.size();i++) { ba[i]=-linearCoefficients[i]; } mosek_quad_solve_sep(menv,ba,xa); for(unsigned i=0;i<vars.size();i++) { //printf("mosek result x[%d]=%f\n",i,xa[i]); x[i]=xa[i]; } delete [] ba; delete [] xa; return 1; } #endif // it may be that we have to consider dummy vars, which the caller didn't know // about. Thus vars.size() may not equal x.size() unsigned n = vars.size(); valarray<double> b(n); result.resize(n); // load desired positions into vars, note that we keep desired positions // already calculated for dummy vars for (unsigned i=0;i<x.size();i++) { COLA_ASSERT(!isNaN(x[i])); COLA_ASSERT(isFinite(x[i])); b[i]=i<linearCoefficients.size()?linearCoefficients[i]:0; result[i]=x[i]; if(scaling) { b[i]*=vars[i]->scale; result[i]/=vars[i]->scale; } if(!vars[i]->fixedDesiredPosition) vars[i]->desiredPosition=result[i]; } runSolver(result); valarray<double> g(n); /* gradient */ valarray<double> previous(n); /* stored positions */ valarray<double> d(n); /* actual descent vector */ #ifdef CHECK_CONVERGENCE_BY_COST double previousCost = DBL_MAX; #endif unsigned counter=0; double stepSize; for (; counter<max_iterations&&!converged; counter++) { previous=result; stepSize=0; double alpha=computeSteepestDescentVector(b,result,g); //printf("Iteration[%d]\n",counter); // move to new unconstrained position for (unsigned i=0; i<n; i++) { // dividing by variable weight is a cheap trick to make these // weights mean something in terms of the descent vector double step=alpha*g[i]/vars[i]->weight; result[i]+=step; //printf(" after unconstrained step: x[%d]=%f\n",i,result[i]); stepSize+=step*step; COLA_ASSERT(!isNaN(result[i])); COLA_ASSERT(isFinite(result[i])); if(!vars[i]->fixedDesiredPosition) vars[i]->desiredPosition=result[i]; } //project to constraint boundary bool constrainedOptimum = false; constrainedOptimum=runSolver(result); stepSize=0; for (unsigned i=0;i<n;i++) { double step = previous[i]-result[i]; stepSize+=step*step; } //constrainedOptimum=false; // beta seems, more often than not, to be >1! if(constrainedOptimum) { // The following step limits the step-size in the feasible // direction d = result - previous; const double beta = 0.5*computeStepSize(g, d); // beta > 1.0 takes us back outside the feasible region // beta < 0 clearly not useful and may happen due to numerical imp. //printf("beta=%f\n",beta); if(beta>0&&beta<0.99999) { stepSize=0; for (unsigned i=0; i<n; i++) { double step=beta*d[i]; result[i]=previous[i]+step; stepSize+=step*step; } } } #ifdef CHECK_CONVERGENCE_BY_COST /* This would be the slow way to detect convergence */ //if(counter%2) { double cost = computeCost(b,result); printf(" gp[%d] %.15f %.15f\n",counter,previousCost,cost); //COLA_ASSERT(previousCost>cost); if(fabs(previousCost - cost) < tolerance) { converged = true; } previousCost = cost; //} #else if(stepSize<tolerance) converged = true; #endif } //printf("GP[%d] converged after %d iterations.\n",k,counter); for(unsigned i=0;i<x.size();i++) { x[i]=result[i]; if(scaling) { x[i]*=vars[i]->scale; } } destroyVPSC(solver); return counter; }