001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.math3.linear;
018
019 import org.apache.commons.math3.exception.DimensionMismatchException;
020 import org.apache.commons.math3.exception.MaxCountExceededException;
021 import org.apache.commons.math3.exception.NullArgumentException;
022 import org.apache.commons.math3.util.IterationManager;
023 import org.apache.commons.math3.util.MathUtils;
024
025 /**
026 * <p>
027 * This abstract class defines preconditioned iterative solvers. When A is
028 * ill-conditioned, instead of solving system A · x = b directly, it is
029 * preferable to solve either
030 * <center>
031 * (M · A) · x = M · b
032 * </center>
033 * (left preconditioning), or
034 * <center>
035 * (A · M) · y = b, followed by
036 * M · y = x
037 * </center>
038 * (right preconditioning), where M approximates in some way A<sup>-1</sup>,
039 * while matrix-vector products of the type M · y remain comparatively
040 * easy to compute. In this library, M (not M<sup>-1</sup>!) is called the
041 * <em>preconditionner</em>.
042 * </p>
043 * <p>
044 * Concrete implementations of this abstract class must be provided with the
045 * preconditioner M, as a {@link RealLinearOperator}.
046 * </p>
047 *
048 * @version $Id: PreconditionedIterativeLinearSolver.java 1416643 2012-12-03 19:37:14Z tn $
049 * @since 3.0
050 */
051 public abstract class PreconditionedIterativeLinearSolver
052 extends IterativeLinearSolver {
053
054 /**
055 * Creates a new instance of this class, with default iteration manager.
056 *
057 * @param maxIterations the maximum number of iterations
058 */
059 public PreconditionedIterativeLinearSolver(final int maxIterations) {
060 super(maxIterations);
061 }
062
063 /**
064 * Creates a new instance of this class, with custom iteration manager.
065 *
066 * @param manager the custom iteration manager
067 * @throws NullArgumentException if {@code manager} is {@code null}
068 */
069 public PreconditionedIterativeLinearSolver(final IterationManager manager)
070 throws NullArgumentException {
071 super(manager);
072 }
073
074 /**
075 * Returns an estimate of the solution to the linear system A · x =
076 * b.
077 *
078 * @param a the linear operator A of the system
079 * @param m the preconditioner, M (can be {@code null})
080 * @param b the right-hand side vector
081 * @param x0 the initial guess of the solution
082 * @return a new vector containing the solution
083 * @throws NullArgumentException if one of the parameters is {@code null}
084 * @throws NonSquareOperatorException if {@code a} or {@code m} is not
085 * square
086 * @throws DimensionMismatchException if {@code m}, {@code b} or
087 * {@code x0} have dimensions inconsistent with {@code a}
088 * @throws MaxCountExceededException at exhaustion of the iteration count,
089 * unless a custom
090 * {@link org.apache.commons.math3.util.Incrementor.MaxCountExceededCallback callback}
091 * has been set at construction of the {@link IterationManager}
092 */
093 public RealVector solve(final RealLinearOperator a,
094 final RealLinearOperator m, final RealVector b, final RealVector x0)
095 throws NullArgumentException, NonSquareOperatorException,
096 DimensionMismatchException, MaxCountExceededException {
097 MathUtils.checkNotNull(x0);
098 return solveInPlace(a, m, b, x0.copy());
099 }
100
101 /** {@inheritDoc} */
102 @Override
103 public RealVector solve(final RealLinearOperator a, final RealVector b)
104 throws NullArgumentException, NonSquareOperatorException,
105 DimensionMismatchException, MaxCountExceededException {
106 MathUtils.checkNotNull(a);
107 final RealVector x = new ArrayRealVector(a.getColumnDimension());
108 x.set(0.);
109 return solveInPlace(a, null, b, x);
110 }
111
112 /** {@inheritDoc} */
113 @Override
114 public RealVector solve(final RealLinearOperator a, final RealVector b,
115 final RealVector x0)
116 throws NullArgumentException, NonSquareOperatorException,
117 DimensionMismatchException, MaxCountExceededException {
118 MathUtils.checkNotNull(x0);
119 return solveInPlace(a, null, b, x0.copy());
120 }
121
122 /**
123 * Performs all dimension checks on the parameters of
124 * {@link #solve(RealLinearOperator, RealLinearOperator, RealVector, RealVector) solve}
125 * and
126 * {@link #solveInPlace(RealLinearOperator, RealLinearOperator, RealVector, RealVector) solveInPlace},
127 * and throws an exception if one of the checks fails.
128 *
129 * @param a the linear operator A of the system
130 * @param m the preconditioner, M (can be {@code null})
131 * @param b the right-hand side vector
132 * @param x0 the initial guess of the solution
133 * @throws NullArgumentException if one of the parameters is {@code null}
134 * @throws NonSquareOperatorException if {@code a} or {@code m} is not
135 * square
136 * @throws DimensionMismatchException if {@code m}, {@code b} or
137 * {@code x0} have dimensions inconsistent with {@code a}
138 */
139 protected static void checkParameters(final RealLinearOperator a,
140 final RealLinearOperator m, final RealVector b, final RealVector x0)
141 throws NullArgumentException, NonSquareOperatorException,
142 DimensionMismatchException {
143 checkParameters(a, b, x0);
144 if (m != null) {
145 if (m.getColumnDimension() != m.getRowDimension()) {
146 throw new NonSquareOperatorException(m.getColumnDimension(),
147 m.getRowDimension());
148 }
149 if (m.getRowDimension() != a.getRowDimension()) {
150 throw new DimensionMismatchException(m.getRowDimension(),
151 a.getRowDimension());
152 }
153 }
154 }
155
156 /**
157 * Returns an estimate of the solution to the linear system A · x =
158 * b.
159 *
160 * @param a the linear operator A of the system
161 * @param m the preconditioner, M (can be {@code null})
162 * @param b the right-hand side vector
163 * @return a new vector containing the solution
164 * @throws NullArgumentException if one of the parameters is {@code null}
165 * @throws NonSquareOperatorException if {@code a} or {@code m} is not
166 * square
167 * @throws DimensionMismatchException if {@code m} or {@code b} have
168 * dimensions inconsistent with {@code a}
169 * @throws MaxCountExceededException at exhaustion of the iteration count,
170 * unless a custom
171 * {@link org.apache.commons.math3.util.Incrementor.MaxCountExceededCallback callback}
172 * has been set at construction of the {@link IterationManager}
173 */
174 public RealVector solve(RealLinearOperator a, RealLinearOperator m,
175 RealVector b) throws NullArgumentException, NonSquareOperatorException,
176 DimensionMismatchException, MaxCountExceededException {
177 MathUtils.checkNotNull(a);
178 final RealVector x = new ArrayRealVector(a.getColumnDimension());
179 return solveInPlace(a, m, b, x);
180 }
181
182 /**
183 * Returns an estimate of the solution to the linear system A · x =
184 * b. The solution is computed in-place (initial guess is modified).
185 *
186 * @param a the linear operator A of the system
187 * @param m the preconditioner, M (can be {@code null})
188 * @param b the right-hand side vector
189 * @param x0 the initial guess of the solution
190 * @return a reference to {@code x0} (shallow copy) updated with the
191 * solution
192 * @throws NullArgumentException if one of the parameters is {@code null}
193 * @throws NonSquareOperatorException if {@code a} or {@code m} is not
194 * square
195 * @throws DimensionMismatchException if {@code m}, {@code b} or
196 * {@code x0} have dimensions inconsistent with {@code a}
197 * @throws MaxCountExceededException at exhaustion of the iteration count,
198 * unless a custom
199 * {@link org.apache.commons.math3.util.Incrementor.MaxCountExceededCallback callback}
200 * has been set at construction of the {@link IterationManager}
201 */
202 public abstract RealVector solveInPlace(RealLinearOperator a,
203 RealLinearOperator m, RealVector b, RealVector x0) throws
204 NullArgumentException, NonSquareOperatorException,
205 DimensionMismatchException, MaxCountExceededException;
206
207 /** {@inheritDoc} */
208 @Override
209 public RealVector solveInPlace(final RealLinearOperator a,
210 final RealVector b, final RealVector x0) throws
211 NullArgumentException, NonSquareOperatorException,
212 DimensionMismatchException, MaxCountExceededException {
213 return solveInPlace(a, null, b, x0);
214 }
215 }