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);
}
Example #2
0
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;
}