    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    }