/*
* Copyright (c) 2012-2013, Peter Abeles. All Rights Reserved.
*
* This file is part of DDogleg (http://ddogleg.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ddogleg.optimization.impl;
import org.ejml.UtilEjml;
import org.ejml.alg.dense.mult.VectorVectorMult;
import org.ejml.data.DenseMatrix64F;
import org.ejml.ops.CommonOps;
import org.ejml.ops.NormOps;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Peter Abeles
*/
public class TestCauchyStep {
DenseMatrix64F J,x,residuals,gradient;
public TestCauchyStep() {
J = new DenseMatrix64F(3,2,true,1,0,0,Math.sqrt(2),0,0);
x = new DenseMatrix64F(2,1,true,0.5,1.5);
residuals = new DenseMatrix64F(3,1,true,-1,-2,-3);
gradient = new DenseMatrix64F(2,1);
CommonOps.multTransA(J, residuals, gradient);
}
/**
* The optimal solution falls inside the trust region
*/
@Test
public void computeStep_inside() {
CauchyStep alg = new CauchyStep();
alg.init(2,3);
alg.setInputs(x,residuals,J,gradient,-1);
DenseMatrix64F step = new DenseMatrix64F(2,1);
alg.computeStep(10,step);
// empirical test to see if it is a local minimum
double a = cost(residuals,J,step,0);
double b = cost(residuals, J, step, 0.01);
double c = cost(residuals,J,step,-0.01);
assertTrue(a < b);
assertTrue(a < c);
}
public static double cost( DenseMatrix64F residuals , DenseMatrix64F J , DenseMatrix64F h , double delta )
{
// adjust the value of h along the gradient's direction
DenseMatrix64F direction = h.copy();
CommonOps.scale(1.0/ NormOps.normF(h),direction);
h = h.copy();
for( int i = 0; i < h.numRows; i++ )
h.data[i] += delta*direction.data[i];
DenseMatrix64F B = new DenseMatrix64F(J.numCols,J.numCols);
CommonOps.multTransA(J,J,B);
double left = VectorVectorMult.innerProd(residuals, residuals);
double middle = VectorVectorMult.innerProdA(residuals, J, h);
double right = VectorVectorMult.innerProdA(h, B, h);
// double cost = 0.5*left + middle + 0.5*right;
//
// SimpleMatrix _r = SimpleMatrix.wrap(residuals);
// SimpleMatrix _J = SimpleMatrix.wrap(J);
// SimpleMatrix _h = SimpleMatrix.wrap(h);
//
// double v = _r.plus(_J.mult(_h)).normF();
//
// double alt = 0.5*v*v;
//
// if( Math.abs(alt-cost) > 1e-8 )
// throw new RuntimeException("Oh crap");
return 0.5*left + middle + 0.5*right;
}
/**
* The optimal solution falls outside the trust region
*/
@Test
public void computeStep_outside() {
CauchyStep alg = new CauchyStep();
alg.init(2,3);
alg.setInputs(x,residuals,J,gradient,-1);
DenseMatrix64F step = new DenseMatrix64F(2,1);
alg.computeStep(1,step);
// make sure it on he trust region border
double l = NormOps.normF(step);
assertTrue(Math.abs(l - 1) <= UtilEjml.EPS);
// empirical test to see if it is a local minimum
double a = cost(residuals,J,step,0);
double c = cost(residuals,J,step,-0.01);
assertTrue(a < c);
}
/**
* Check predicted reduction against direct computation
*/
@Test
public void predictedReduction_inside() {
CauchyStep alg = new CauchyStep();
alg.init(2,3);
alg.setInputs(x,residuals,J,gradient,-1);
DenseMatrix64F step = new DenseMatrix64F(2,1);
alg.computeStep(10,step);
// empirical calculation of the reduction
double a = VectorVectorMult.innerProd(residuals,residuals)*0.5;
double c = cost(residuals,J,step,0);
assertEquals(a-c,alg.predictedReduction(),1e-8);
}
/**
* Check predicted reduction against direct computation
*/
@Test
public void predictedReduction_outside() {
CauchyStep alg = new CauchyStep();
alg.init(2,3);
alg.setInputs(x,residuals,J,gradient,-1);
DenseMatrix64F step = new DenseMatrix64F(2,1);
alg.computeStep(1,step);
// empirical calculation of the reduction
double a = VectorVectorMult.innerProd(residuals,residuals)*0.5;
double c = cost(residuals,J,step,0);
assertEquals(a-c,alg.predictedReduction(),1e-8);
}
}
Ads help maintain this website.