Author: celestin
Date: Sat Jan 28 15:10:42 2012
New Revision: 1237069
URL: http://svn.apache.org/viewvc?rev=1237069&view=rev
Log:
Added method o.a.c.m.linear.IterativeLinearSolverEvent.getNormOfResidual()
(MATH-735).
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ConjugateGradient.java
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/IterativeLinearSolverEvent.java
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SymmLQ.java
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ConjugateGradientTest.java
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SymmLQTest.java
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ConjugateGradient.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ConjugateGradient.java?rev=1237069&r1=1237068&r2=1237069&view=diff
==============================================================================
---
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ConjugateGradient.java
(original)
+++
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ConjugateGradient.java
Sat Jan 28 15:10:42 2012
@@ -99,6 +99,9 @@ public class ConjugateGradient
/** The current estimate of the residual. */
private final RealVector r;
+ /** The current estimate of the norm of the residual. */
+ private final double rnorm;
+
/** The current estimate of the solution. */
private final RealVector x;
@@ -112,12 +115,22 @@ public class ConjugateGradient
* @param x the current estimate of the solution
* @param b the right-hand side vector
* @param r the current estimate of the residual
+ * @param rnorm the norm of the current estimate of the residual
*/
- public ConjugateGradientEvent(final Object source, final int
iterations, final RealVector x, final RealVector b, final RealVector r) {
+ public ConjugateGradientEvent(final Object source, final int
iterations,
+ final RealVector x, final RealVector b, final RealVector r,
+ final double rnorm) {
super(source, iterations);
this.x = RealVector.unmodifiableRealVector(x);
this.b = RealVector.unmodifiableRealVector(b);
this.r = RealVector.unmodifiableRealVector(r);
+ this.rnorm = rnorm;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getNormOfResidual() {
+ return rnorm;
}
/** {@inheritDoc} */
@@ -206,7 +219,7 @@ public class ConjugateGradient
final IterationManager manager = getIterationManager();
// Initialization of default stopping criterion
manager.resetIterationCount();
- final double r2max = delta * delta * b.dotProduct(b);
+ final double rmax = delta * b.getNorm();
// Initialization phase counts as one iteration.
manager.incrementIterationCount();
@@ -218,7 +231,7 @@ public class ConjugateGradient
RealVector q = a.operate(p);
final RealVector r = b.combine(1, -1, q);
- double r2 = r.dotProduct(r);
+ double rnorm = r.getNorm();
RealVector z;
if (m == null) {
z = r;
@@ -226,16 +239,16 @@ public class ConjugateGradient
z = null;
}
IterativeLinearSolverEvent evt;
- evt = new ConjugateGradientEvent(this, manager.getIterations(), x, b,
r);
+ evt = new ConjugateGradientEvent(this, manager.getIterations(), x, b,
r, rnorm);
manager.fireInitializationEvent(evt);
- if (r2 <= r2max) {
+ if (rnorm <= rmax) {
manager.fireTerminationEvent(evt);
return x;
}
double rhoPrev = 0.;
while (true) {
manager.incrementIterationCount();
- evt = new ConjugateGradientEvent(this, manager.getIterations(), x,
b, r);
+ evt = new ConjugateGradientEvent(this, manager.getIterations(), x,
b, r, rnorm);
manager.fireIterationStartedEvent(evt);
if (m != null) {
z = m.solve(r);
@@ -268,10 +281,10 @@ public class ConjugateGradient
x.combineToSelf(1., alpha, p);
r.combineToSelf(1., -alpha, q);
rhoPrev = rhoNext;
- r2 = r.dotProduct(r);
- evt = new ConjugateGradientEvent(this, manager.getIterations(), x,
b, r);
+ rnorm = r.getNorm();
+ evt = new ConjugateGradientEvent(this, manager.getIterations(), x,
b, r, rnorm);
manager.fireIterationPerformedEvent(evt);
- if (r2 <= r2max) {
+ if (rnorm <= rmax) {
manager.fireTerminationEvent(evt);
return x;
}
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/IterativeLinearSolverEvent.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/IterativeLinearSolverEvent.java?rev=1237069&r1=1237068&r2=1237069&view=diff
==============================================================================
---
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/IterativeLinearSolverEvent.java
(original)
+++
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/IterativeLinearSolverEvent.java
Sat Jan 28 15:10:42 2012
@@ -54,6 +54,23 @@ public abstract class IterativeLinearSol
public abstract RealVector getRightHandSideVector();
/**
+ * Returns the norm of the residual. The returned value is not required to
+ * be <em>exact</em>. Instead, the norm of the so-called <em>updated</em>
+ * residual (if available) should be returned. For example, the
+ * {@link ConjugateGradient conjugate gradient} method computes a sequence
+ * of residuals, the norm of which is cheap to compute. However, due to
+ * accumulation of round-off errors, this residual might differ from the
+ * true residual after some iterations. See e.g. A. Greenbaum and
+ * Z. Strakos, <em>Predicting the Behavior of Finite Precision Lanzos and
+ * Conjugate Gradient Computations</em>, Technical Report 538, Department
of
+ * Computer Science, New York University, 1991 (available
+ * <a
href="http://www.archive.org/details/predictingbehavi00gree">here</a>).
+ *
+ * @return an estimate of the norm of the residual
+ */
+ public abstract double getNormOfResidual();
+
+ /**
* Returns the current estimate of the solution to the linear system to be
* solved. This method should return an unmodifiable view, or a deep copy
of
* the actual current solution, in order not to compromise subsequent
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SymmLQ.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SymmLQ.java?rev=1237069&r1=1237068&r2=1237069&view=diff
==============================================================================
---
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SymmLQ.java
(original)
+++
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SymmLQ.java
Sat Jan 28 15:10:42 2012
@@ -664,7 +664,7 @@ public class SymmLQ
*/
/** */
- private static final long serialVersionUID = 20120128L;
+ private static final long serialVersionUID = 2012012801L;
/** A reference to the state of this solver. */
private final State state;
@@ -681,6 +681,7 @@ public class SymmLQ
this.state = state;
}
+ /** {@inheritDoc} */
@Override
public int getIterations() {
return getIterationManager().getIterations();
@@ -688,6 +689,12 @@ public class SymmLQ
/** {@inheritDoc} */
@Override
+ public double getNormOfResidual() {
+ return FastMath.min(state.cgnorm, state.lqnorm);
+ }
+
+ /** {@inheritDoc} */
+ @Override
public RealVector getRightHandSideVector() {
return RealVector.unmodifiableRealVector(state.b);
}
Modified:
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ConjugateGradientTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ConjugateGradientTest.java?rev=1237069&r1=1237068&r2=1237069&view=diff
==============================================================================
---
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ConjugateGradientTest.java
(original)
+++
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ConjugateGradientTest.java
Sat Jan 28 15:10:42 2012
@@ -20,6 +20,7 @@ import java.util.Arrays;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.exception.MaxCountExceededException;
+import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.util.IterationEvent;
import org.apache.commons.math.util.IterationListener;
import org.junit.Assert;
@@ -175,7 +176,7 @@ public class ConjugateGradientTest {
}
public void iterationPerformed(final IterationEvent e) {
- RealVector v = ((ProvidesResidual)e).getResidual();
+ RealVector v = ((ProvidesResidual) e).getResidual();
r.setSubVector(0, v);
v = ((IterativeLinearSolverEvent) e).getSolution();
x.setSubVector(0, v);
@@ -463,7 +464,6 @@ public class ConjugateGradientTest {
*/
final int[] count = new int[] {0, 0, 0, 0};
final IterationListener listener = new IterationListener() {
-
public void initializationPerformed(final IterationEvent e) {
++count[0];
}
@@ -498,4 +498,97 @@ public class ConjugateGradientTest {
Assert.assertEquals(msg, 1, count[3]);
}
}
+
+ @Test
+ public void testUnpreconditionedNormOfResidual() {
+ final int n = 5;
+ final int maxIterations = 100;
+ final RealLinearOperator a = new HilbertMatrix(n);
+ final IterativeLinearSolver solver;
+ final IterationListener listener = new IterationListener() {
+
+ private void doTestNormOfResidual(final IterationEvent e) {
+ final IterativeLinearSolverEvent evt;
+ evt = (IterativeLinearSolverEvent) e;
+ final RealVector x = evt.getSolution();
+ final RealVector b = evt.getRightHandSideVector();
+ final RealVector r = b.subtract(a.operate(x));
+ final double rnorm = r.getNorm();
+ Assert.assertEquals("iteration performed (residual)",
+ rnorm, evt.getNormOfResidual(),
+ FastMath.max(1E-5 * rnorm, 1E-10));
+ }
+
+ public void initializationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void iterationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void iterationStarted(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void terminationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+ };
+ solver = new ConjugateGradient(maxIterations, 1E-10, true);
+ solver.getIterationManager().addIterationListener(listener);
+ final RealVector b = new ArrayRealVector(n);
+ for (int j = 0; j < n; j++) {
+ b.set(0.);
+ b.setEntry(j, 1.);
+ solver.solve(a, b);
+ }
+ }
+
+ @Test
+ public void testPreconditionedNormOfResidual() {
+ final int n = 5;
+ final int maxIterations = 100;
+ final RealLinearOperator a = new HilbertMatrix(n);
+ final InvertibleRealLinearOperator m = JacobiPreconditioner.create(a);
+ final PreconditionedIterativeLinearSolver solver;
+ final IterationListener listener = new IterationListener() {
+
+ private void doTestNormOfResidual(final IterationEvent e) {
+ final IterativeLinearSolverEvent evt;
+ evt = (IterativeLinearSolverEvent) e;
+ final RealVector x = evt.getSolution();
+ final RealVector b = evt.getRightHandSideVector();
+ final RealVector r = b.subtract(a.operate(x));
+ final double rnorm = r.getNorm();
+ Assert.assertEquals("iteration performed (residual)",
+ rnorm, evt.getNormOfResidual(),
+ FastMath.max(1E-5 * rnorm, 1E-10));
+ }
+
+ public void initializationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void iterationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void iterationStarted(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void terminationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+ };
+ solver = new ConjugateGradient(maxIterations, 1E-10, true);
+ solver.getIterationManager().addIterationListener(listener);
+ final RealVector b = new ArrayRealVector(n);
+ for (int j = 0; j < n; j++) {
+ b.set(0.);
+ b.setEntry(j, 1.);
+ solver.solve(a, m, b);
+ }
+ }
}
Modified:
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SymmLQTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SymmLQTest.java?rev=1237069&r1=1237068&r2=1237069&view=diff
==============================================================================
---
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SymmLQTest.java
(original)
+++
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SymmLQTest.java
Sat Jan 28 15:10:42 2012
@@ -624,4 +624,98 @@ public class SymmLQTest {
});
new SymmLQ(100, 1., true).solve(a, m, b);
}
+
+ @Test
+ public void testUnpreconditionedNormOfResidual() {
+ final int n = 5;
+ final int maxIterations = 100;
+ final RealLinearOperator a = new HilbertMatrix(n);
+ final IterativeLinearSolver solver;
+ final IterationListener listener = new IterationListener() {
+
+ private void doTestNormOfResidual(final IterationEvent e) {
+ final IterativeLinearSolverEvent evt;
+ evt = (IterativeLinearSolverEvent) e;
+ final RealVector x = evt.getSolution();
+ final RealVector b = evt.getRightHandSideVector();
+ final RealVector r = b.subtract(a.operate(x));
+ final double rnorm = r.getNorm();
+ Assert.assertEquals("iteration performed (residual)",
+ rnorm, evt.getNormOfResidual(),
+ FastMath.max(1E-5 * rnorm, 1E-10));
+ }
+
+ public void initializationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void iterationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void iterationStarted(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void terminationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+ };
+ solver = new ConjugateGradient(maxIterations, 1E-10, true);
+ solver.getIterationManager().addIterationListener(listener);
+ final RealVector b = new ArrayRealVector(n);
+ for (int j = 0; j < n; j++) {
+ b.set(0.);
+ b.setEntry(j, 1.);
+ solver.solve(a, b);
+ }
+ }
+
+ @Test
+ public void testPreconditionedNormOfResidual() {
+ final int n = 5;
+ final int maxIterations = 100;
+ final RealLinearOperator a = new HilbertMatrix(n);
+ final InvertibleRealLinearOperator m = JacobiPreconditioner.create(a);
+ final PreconditionedIterativeLinearSolver solver;
+ final IterationListener listener = new IterationListener() {
+
+ private void doTestNormOfResidual(final IterationEvent e) {
+ final IterativeLinearSolverEvent evt;
+ evt = (IterativeLinearSolverEvent) e;
+ final RealVector x = evt.getSolution();
+ final RealVector b = evt.getRightHandSideVector();
+ final RealVector r = b.subtract(a.operate(x));
+ final double rnorm = r.getNorm();
+ Assert.assertEquals("iteration performed (residual)",
+ rnorm, evt.getNormOfResidual(),
+ FastMath.max(1E-5 * rnorm, 1E-10));
+ }
+
+ public void initializationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void iterationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void iterationStarted(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+
+ public void terminationPerformed(final IterationEvent e) {
+ doTestNormOfResidual(e);
+ }
+ };
+ solver = new ConjugateGradient(maxIterations, 1E-10, true);
+ solver.getIterationManager().addIterationListener(listener);
+ final RealVector b = new ArrayRealVector(n);
+ for (int j = 0; j < n; j++) {
+ b.set(0.);
+ b.setEntry(j, 1.);
+ solver.solve(a, m, b);
+ }
+ }
}
+