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