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