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 */
017package org.apache.commons.math4.legacy.linear;
018
019import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
020import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
021import org.apache.commons.math4.legacy.exception.NullArgumentException;
022
023/**
024 * <p>
025 * This abstract class defines preconditioned iterative solvers. When A is
026 * ill-conditioned, instead of solving system A &middot; x = b directly, it is
027 * preferable to solve either
028 * <pre>
029 * (M &middot; A) &middot; x = M &middot; b
030 * </pre>
031 * (left preconditioning), or
032 * <pre>
033 * (A &middot; M) &middot; y = b, &nbsp;&nbsp;&nbsp;&nbsp;followed by
034 * M &middot; y = x
035 * </pre>
036 * (right preconditioning), where M approximates in some way A<sup>-1</sup>,
037 * while matrix-vector products of the type M &middot; y remain comparatively
038 * easy to compute. In this library, M (not M<sup>-1</sup>!) is called the
039 * <em>preconditionner</em>.
040 *
041 * <p>
042 * Concrete implementations of this abstract class must be provided with the
043 * preconditioner M, as a {@link RealLinearOperator}.
044 * </p>
045 *
046 * @since 3.0
047 */
048public abstract class PreconditionedIterativeLinearSolver
049    extends IterativeLinearSolver {
050
051    /**
052     * Creates a new instance of this class, with default iteration manager.
053     *
054     * @param maxIterations the maximum number of iterations
055     */
056    public PreconditionedIterativeLinearSolver(final int maxIterations) {
057        super(maxIterations);
058    }
059
060    /**
061     * Creates a new instance of this class, with custom iteration manager.
062     *
063     * @param manager the custom iteration manager
064     * @throws NullArgumentException if {@code manager} is {@code null}
065     */
066    public PreconditionedIterativeLinearSolver(final IterationManager manager)
067        throws NullArgumentException {
068        super(manager);
069    }
070
071    /**
072     * Returns an estimate of the solution to the linear system A &middot; x =
073     * b.
074     *
075     * @param a the linear operator A of the system
076     * @param m the preconditioner, M (can be {@code null})
077     * @param b the right-hand side vector
078     * @param x0 the initial guess of the solution
079     * @return a new vector containing the solution
080     * @throws NullArgumentException if one of the parameters is {@code null}
081     * @throws NonSquareOperatorException if {@code a} or {@code m} is not
082     * square
083     * @throws DimensionMismatchException if {@code m}, {@code b} or
084     * {@code x0} have dimensions inconsistent with {@code a}
085     * @throws MaxCountExceededException at exhaustion of the iteration count,
086     * unless a custom
087     * {@link org.apache.commons.math4.legacy.core.IntegerSequence.Incrementor.MaxCountExceededCallback callback}
088     * has been set at construction of the {@link IterationManager}
089     */
090    public RealVector solve(final RealLinearOperator a,
091        final RealLinearOperator m, final RealVector b, final RealVector x0)
092        throws NullArgumentException, NonSquareOperatorException,
093        DimensionMismatchException, MaxCountExceededException {
094        NullArgumentException.check(x0);
095        return solveInPlace(a, m, b, x0.copy());
096    }
097
098    /** {@inheritDoc} */
099    @Override
100    public RealVector solve(final RealLinearOperator a, final RealVector b)
101        throws NullArgumentException, NonSquareOperatorException,
102        DimensionMismatchException, MaxCountExceededException {
103        NullArgumentException.check(a);
104        final RealVector x = new ArrayRealVector(a.getColumnDimension());
105        x.set(0.);
106        return solveInPlace(a, null, b, x);
107    }
108
109    /** {@inheritDoc} */
110    @Override
111    public RealVector solve(final RealLinearOperator a, final RealVector b,
112                            final RealVector x0)
113        throws NullArgumentException, NonSquareOperatorException,
114        DimensionMismatchException, MaxCountExceededException {
115        NullArgumentException.check(x0);
116        return solveInPlace(a, null, b, x0.copy());
117    }
118
119    /**
120     * Performs all dimension checks on the parameters of
121     * {@link #solve(RealLinearOperator, RealLinearOperator, RealVector, RealVector) solve}
122     * and
123     * {@link #solveInPlace(RealLinearOperator, RealLinearOperator, RealVector, RealVector) solveInPlace},
124     * and throws an exception if one of the checks fails.
125     *
126     * @param a the linear operator A of the system
127     * @param m the preconditioner, M (can be {@code null})
128     * @param b the right-hand side vector
129     * @param x0 the initial guess of the solution
130     * @throws NullArgumentException if one of the parameters is {@code null}
131     * @throws NonSquareOperatorException if {@code a} or {@code m} is not
132     * square
133     * @throws DimensionMismatchException if {@code m}, {@code b} or
134     * {@code x0} have dimensions inconsistent with {@code a}
135     */
136    protected static void checkParameters(final RealLinearOperator a,
137        final RealLinearOperator m, final RealVector b, final RealVector x0)
138        throws NullArgumentException, NonSquareOperatorException,
139        DimensionMismatchException {
140        checkParameters(a, b, x0);
141        if (m != null) {
142            if (m.getColumnDimension() != m.getRowDimension()) {
143                throw new NonSquareOperatorException(m.getColumnDimension(),
144                                                     m.getRowDimension());
145            }
146            if (m.getRowDimension() != a.getRowDimension()) {
147                throw new DimensionMismatchException(m.getRowDimension(),
148                                                     a.getRowDimension());
149            }
150        }
151    }
152
153    /**
154     * Returns an estimate of the solution to the linear system A &middot; x =
155     * b.
156     *
157     * @param a the linear operator A of the system
158     * @param m the preconditioner, M (can be {@code null})
159     * @param b the right-hand side vector
160     * @return a new vector containing the solution
161     * @throws NullArgumentException if one of the parameters is {@code null}
162     * @throws NonSquareOperatorException if {@code a} or {@code m} is not
163     * square
164     * @throws DimensionMismatchException if {@code m} or {@code b} 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.math4.legacy.core.IntegerSequence.Incrementor.MaxCountExceededCallback callback}
169     * has been set at construction of the {@link IterationManager}
170     */
171    public RealVector solve(RealLinearOperator a, RealLinearOperator m,
172        RealVector b) throws NullArgumentException, NonSquareOperatorException,
173        DimensionMismatchException, MaxCountExceededException {
174        NullArgumentException.check(a);
175        final RealVector x = new ArrayRealVector(a.getColumnDimension());
176        return solveInPlace(a, m, b, x);
177    }
178
179    /**
180     * Returns an estimate of the solution to the linear system A &middot; x =
181     * b. The solution is computed in-place (initial guess is modified).
182     *
183     * @param a the linear operator A of the system
184     * @param m the preconditioner, M (can be {@code null})
185     * @param b the right-hand side vector
186     * @param x0 the initial guess of the solution
187     * @return a reference to {@code x0} (shallow copy) updated with the
188     * solution
189     * @throws NullArgumentException if one of the parameters is {@code null}
190     * @throws NonSquareOperatorException if {@code a} or {@code m} is not
191     * square
192     * @throws DimensionMismatchException if {@code m}, {@code b} or
193     * {@code x0} have dimensions inconsistent with {@code a}
194     * @throws MaxCountExceededException at exhaustion of the iteration count,
195     * unless a custom
196     * {@link org.apache.commons.math4.legacy.core.IntegerSequence.Incrementor.MaxCountExceededCallback callback}
197     * has been set at construction of the {@link IterationManager}
198     */
199    public abstract RealVector solveInPlace(RealLinearOperator a,
200        RealLinearOperator m, RealVector b, RealVector x0) throws
201        NullArgumentException, NonSquareOperatorException,
202        DimensionMismatchException, MaxCountExceededException;
203
204    /** {@inheritDoc} */
205    @Override
206    public RealVector solveInPlace(final RealLinearOperator a,
207        final RealVector b, final RealVector x0) throws
208        NullArgumentException, NonSquareOperatorException,
209        DimensionMismatchException, MaxCountExceededException {
210        return solveInPlace(a, null, b, x0);
211    }
212}