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 &middot; x = b directly, it is
029     * preferable to solve either
030     * <center>
031     * (M &middot; A) &middot; x = M &middot; b
032     * </center>
033     * (left preconditioning), or
034     * <center>
035     * (A &middot; M) &middot; y = b, &nbsp;&nbsp;&nbsp;&nbsp;followed by
036     * M &middot; 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 &middot; 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 &middot; 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 &middot; 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 &middot; 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    }