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     * This abstract class defines an iterative solver for the linear system A
027     * &middot; x = b. In what follows, the <em>residual</em> r is defined as r = b
028     * - A &middot; x, where A is the linear operator of the linear system, b is the
029     * right-hand side vector, and x the current estimate of the solution.
030     *
031     * @version $Id: IterativeLinearSolver.java 1416643 2012-12-03 19:37:14Z tn $
032     * @since 3.0
033     */
034    public abstract class IterativeLinearSolver {
035    
036        /** The object in charge of managing the iterations. */
037        private final IterationManager manager;
038    
039        /**
040         * Creates a new instance of this class, with default iteration manager.
041         *
042         * @param maxIterations the maximum number of iterations
043         */
044        public IterativeLinearSolver(final int maxIterations) {
045            this.manager = new IterationManager(maxIterations);
046        }
047    
048        /**
049         * Creates a new instance of this class, with custom iteration manager.
050         *
051         * @param manager the custom iteration manager
052         * @throws NullArgumentException if {@code manager} is {@code null}
053         */
054        public IterativeLinearSolver(final IterationManager manager)
055            throws NullArgumentException {
056            MathUtils.checkNotNull(manager);
057            this.manager = manager;
058        }
059    
060        /**
061         * Performs all dimension checks on the parameters of
062         * {@link #solve(RealLinearOperator, RealVector, RealVector) solve} and
063         * {@link #solveInPlace(RealLinearOperator, RealVector, RealVector) solveInPlace},
064         * and throws an exception if one of the checks fails.
065         *
066         * @param a the linear operator A of the system
067         * @param b the right-hand side vector
068         * @param x0 the initial guess of the solution
069         * @throws NullArgumentException if one of the parameters is {@code null}
070         * @throws NonSquareOperatorException if {@code a} is not square
071         * @throws DimensionMismatchException if {@code b} or {@code x0} have
072         * dimensions inconsistent with {@code a}
073         */
074        protected static void checkParameters(final RealLinearOperator a,
075            final RealVector b, final RealVector x0) throws
076            NullArgumentException, NonSquareOperatorException,
077            DimensionMismatchException {
078            MathUtils.checkNotNull(a);
079            MathUtils.checkNotNull(b);
080            MathUtils.checkNotNull(x0);
081            if (a.getRowDimension() != a.getColumnDimension()) {
082                throw new NonSquareOperatorException(a.getRowDimension(),
083                                                           a.getColumnDimension());
084            }
085            if (b.getDimension() != a.getRowDimension()) {
086                throw new DimensionMismatchException(b.getDimension(),
087                                                     a.getRowDimension());
088            }
089            if (x0.getDimension() != a.getColumnDimension()) {
090                throw new DimensionMismatchException(x0.getDimension(),
091                                                     a.getColumnDimension());
092            }
093        }
094    
095        /**
096         * Returns the iteration manager attached to this solver.
097         *
098         * @return the manager
099         */
100        public IterationManager getIterationManager() {
101            return manager;
102        }
103    
104        /**
105         * Returns an estimate of the solution to the linear system A &middot; x =
106         * b.
107         *
108         * @param a the linear operator A of the system
109         * @param b the right-hand side vector
110         * @return a new vector containing the solution
111         * @throws NullArgumentException if one of the parameters is {@code null}
112         * @throws NonSquareOperatorException if {@code a} is not square
113         * @throws DimensionMismatchException if {@code b} has dimensions
114         * inconsistent with {@code a}
115         * @throws MaxCountExceededException at exhaustion of the iteration count,
116         * unless a custom
117         * {@link org.apache.commons.math3.util.Incrementor.MaxCountExceededCallback callback}
118         * has been set at construction of the {@link IterationManager}
119         */
120        public RealVector solve(final RealLinearOperator a, final RealVector b)
121            throws NullArgumentException, NonSquareOperatorException,
122            DimensionMismatchException, MaxCountExceededException {
123            MathUtils.checkNotNull(a);
124            final RealVector x = new ArrayRealVector(a.getColumnDimension());
125            x.set(0.);
126            return solveInPlace(a, b, x);
127        }
128    
129        /**
130         * Returns an estimate of the solution to the linear system A &middot; x =
131         * b.
132         *
133         * @param a the linear operator A of the system
134         * @param b the right-hand side vector
135         * @param x0 the initial guess of the solution
136         * @return a new vector containing the solution
137         * @throws NullArgumentException if one of the parameters is {@code null}
138         * @throws NonSquareOperatorException if {@code a} is not square
139         * @throws DimensionMismatchException if {@code b} or {@code x0} have
140         * dimensions inconsistent with {@code a}
141         * @throws MaxCountExceededException at exhaustion of the iteration count,
142         * unless a custom
143         * {@link org.apache.commons.math3.util.Incrementor.MaxCountExceededCallback callback}
144         * has been set at construction of the {@link IterationManager}
145         */
146        public RealVector solve(RealLinearOperator a, RealVector b, RealVector x0)
147            throws NullArgumentException, NonSquareOperatorException,
148            DimensionMismatchException, MaxCountExceededException {
149            MathUtils.checkNotNull(x0);
150            return solveInPlace(a, b, x0.copy());
151        }
152    
153        /**
154         * Returns an estimate of the solution to the linear system A &middot; x =
155         * b. The solution is computed in-place (initial guess is modified).
156         *
157         * @param a the linear operator A of the system
158         * @param b the right-hand side vector
159         * @param x0 initial guess of the solution
160         * @return a reference to {@code x0} (shallow copy) updated with the
161         * solution
162         * @throws NullArgumentException if one of the parameters is {@code null}
163         * @throws NonSquareOperatorException if {@code a} is not square
164         * @throws DimensionMismatchException if {@code b} or {@code x0} have
165         * dimensions inconsistent with {@code a}
166         * @throws MaxCountExceededException at exhaustion of the iteration count,
167         * unless a custom
168         * {@link org.apache.commons.math3.util.Incrementor.MaxCountExceededCallback callback}
169         * has been set at construction of the {@link IterationManager}
170         */
171        public abstract RealVector solveInPlace(RealLinearOperator a, RealVector b,
172            RealVector x0) throws NullArgumentException, NonSquareOperatorException,
173            DimensionMismatchException, MaxCountExceededException;
174    }