1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski /** This method eliminates elements below main diagonal in the given
25*b1cdbd2cSJim Jagielski     matrix by gaussian elimination.
26*b1cdbd2cSJim Jagielski 
27*b1cdbd2cSJim Jagielski     @param matrix
28*b1cdbd2cSJim Jagielski     The matrix to operate on. Last column is the result vector (right
29*b1cdbd2cSJim Jagielski     hand side of the linear equation). After successful termination,
30*b1cdbd2cSJim Jagielski     the matrix is upper triangular. The matrix is expected to be in
31*b1cdbd2cSJim Jagielski     row major order.
32*b1cdbd2cSJim Jagielski 
33*b1cdbd2cSJim Jagielski     @param rows
34*b1cdbd2cSJim Jagielski     Number of rows in matrix
35*b1cdbd2cSJim Jagielski 
36*b1cdbd2cSJim Jagielski     @param cols
37*b1cdbd2cSJim Jagielski     Number of columns in matrix
38*b1cdbd2cSJim Jagielski 
39*b1cdbd2cSJim Jagielski     @param minPivot
40*b1cdbd2cSJim Jagielski     If the pivot element gets lesser than minPivot, this method fails,
41*b1cdbd2cSJim Jagielski     otherwise, elimination succeeds and true is returned.
42*b1cdbd2cSJim Jagielski 
43*b1cdbd2cSJim Jagielski     @return true, if elimination succeeded.
44*b1cdbd2cSJim Jagielski  */
45*b1cdbd2cSJim Jagielski template <class Matrix, typename BaseType>
eliminate(Matrix & matrix,int rows,int cols,const BaseType & minPivot)46*b1cdbd2cSJim Jagielski bool eliminate( 	Matrix&			matrix,
47*b1cdbd2cSJim Jagielski                     int				rows,
48*b1cdbd2cSJim Jagielski                     int				cols,
49*b1cdbd2cSJim Jagielski                     const BaseType& minPivot	)
50*b1cdbd2cSJim Jagielski {
51*b1cdbd2cSJim Jagielski 	BaseType	temp;
52*b1cdbd2cSJim Jagielski 	int			max, i, j, k;	/* *must* be signed, when looping like: j>=0 ! */
53*b1cdbd2cSJim Jagielski 
54*b1cdbd2cSJim Jagielski 	/* eliminate below main diagonal */
55*b1cdbd2cSJim Jagielski 	for(i=0; i<cols-1; ++i)
56*b1cdbd2cSJim Jagielski 	{
57*b1cdbd2cSJim Jagielski 		/* find best pivot */
58*b1cdbd2cSJim Jagielski 		max = i;
59*b1cdbd2cSJim Jagielski 		for(j=i+1; j<rows; ++j)
60*b1cdbd2cSJim Jagielski 			if( fabs(matrix[ j*cols + i ]) > fabs(matrix[ max*cols + i ]) )
61*b1cdbd2cSJim Jagielski 				max = j;
62*b1cdbd2cSJim Jagielski 
63*b1cdbd2cSJim Jagielski 		/* check pivot value */
64*b1cdbd2cSJim Jagielski 		if( fabs(matrix[ max*cols + i ]) < minPivot )
65*b1cdbd2cSJim Jagielski 			return false;	/* pivot too small! */
66*b1cdbd2cSJim Jagielski 
67*b1cdbd2cSJim Jagielski 		/* interchange rows 'max' and 'i' */
68*b1cdbd2cSJim Jagielski 		for(k=0; k<cols; ++k)
69*b1cdbd2cSJim Jagielski 		{
70*b1cdbd2cSJim Jagielski 			temp = matrix[ i*cols + k ];
71*b1cdbd2cSJim Jagielski 			matrix[ i*cols + k ] = matrix[ max*cols + k ];
72*b1cdbd2cSJim Jagielski 			matrix[ max*cols + k ] = temp;
73*b1cdbd2cSJim Jagielski 		}
74*b1cdbd2cSJim Jagielski 
75*b1cdbd2cSJim Jagielski 		/* eliminate column */
76*b1cdbd2cSJim Jagielski 		for(j=i+1; j<rows; ++j)
77*b1cdbd2cSJim Jagielski 			for(k=cols-1; k>=i; --k)
78*b1cdbd2cSJim Jagielski 				matrix[ j*cols + k ] -= matrix[ i*cols + k ] *
79*b1cdbd2cSJim Jagielski 					matrix[ j*cols + i ] / matrix[ i*cols + i ];
80*b1cdbd2cSJim Jagielski 	}
81*b1cdbd2cSJim Jagielski 
82*b1cdbd2cSJim Jagielski 	/* everything went well */
83*b1cdbd2cSJim Jagielski 	return true;
84*b1cdbd2cSJim Jagielski }
85*b1cdbd2cSJim Jagielski 
86*b1cdbd2cSJim Jagielski 
87*b1cdbd2cSJim Jagielski /** Retrieve solution vector of linear system by substituting backwards.
88*b1cdbd2cSJim Jagielski 
89*b1cdbd2cSJim Jagielski 	This operation _relies_ on the previous successful
90*b1cdbd2cSJim Jagielski     application of eliminate()!
91*b1cdbd2cSJim Jagielski 
92*b1cdbd2cSJim Jagielski     @param matrix
93*b1cdbd2cSJim Jagielski     Matrix in upper diagonal form, as e.g. generated by eliminate()
94*b1cdbd2cSJim Jagielski 
95*b1cdbd2cSJim Jagielski     @param rows
96*b1cdbd2cSJim Jagielski     Number of rows in matrix
97*b1cdbd2cSJim Jagielski 
98*b1cdbd2cSJim Jagielski     @param cols
99*b1cdbd2cSJim Jagielski     Number of columns in matrix
100*b1cdbd2cSJim Jagielski 
101*b1cdbd2cSJim Jagielski     @param result
102*b1cdbd2cSJim Jagielski     Result vector. Given matrix must have space for one column (rows entries).
103*b1cdbd2cSJim Jagielski 
104*b1cdbd2cSJim Jagielski     @return true, if back substitution was possible (i.e. no division
105*b1cdbd2cSJim Jagielski     by zero occured).
106*b1cdbd2cSJim Jagielski  */
107*b1cdbd2cSJim Jagielski template <class Matrix, class Vector, typename BaseType>
substitute(const Matrix & matrix,int rows,int cols,Vector & result)108*b1cdbd2cSJim Jagielski bool substitute(	const Matrix&	matrix,
109*b1cdbd2cSJim Jagielski                     int				rows,
110*b1cdbd2cSJim Jagielski                     int				cols,
111*b1cdbd2cSJim Jagielski                     Vector&			result	)
112*b1cdbd2cSJim Jagielski {
113*b1cdbd2cSJim Jagielski 	BaseType	temp;
114*b1cdbd2cSJim Jagielski 	int			j,k;	/* *must* be signed, when looping like: j>=0 ! */
115*b1cdbd2cSJim Jagielski 
116*b1cdbd2cSJim Jagielski 	/* substitute backwards */
117*b1cdbd2cSJim Jagielski 	for(j=rows-1; j>=0; --j)
118*b1cdbd2cSJim Jagielski 	{
119*b1cdbd2cSJim Jagielski 		temp = 0.0;
120*b1cdbd2cSJim Jagielski 		for(k=j+1; k<cols-1; ++k)
121*b1cdbd2cSJim Jagielski 			temp += matrix[ j*cols + k ] * result[k];
122*b1cdbd2cSJim Jagielski 
123*b1cdbd2cSJim Jagielski 		if( matrix[ j*cols + j ] == 0.0 )
124*b1cdbd2cSJim Jagielski 			return false;	/* imminent division by zero! */
125*b1cdbd2cSJim Jagielski 
126*b1cdbd2cSJim Jagielski 		result[j] = (matrix[ j*cols + cols-1 ] - temp) / matrix[ j*cols + j ];
127*b1cdbd2cSJim Jagielski 	}
128*b1cdbd2cSJim Jagielski 
129*b1cdbd2cSJim Jagielski 	/* everything went well */
130*b1cdbd2cSJim Jagielski 	return true;
131*b1cdbd2cSJim Jagielski }
132*b1cdbd2cSJim Jagielski 
133*b1cdbd2cSJim Jagielski 
134*b1cdbd2cSJim Jagielski /** This method determines solution of given linear system, if any
135*b1cdbd2cSJim Jagielski 
136*b1cdbd2cSJim Jagielski 	This is a wrapper for eliminate and substitute, given matrix must
137*b1cdbd2cSJim Jagielski 	contain right side of equation as the last column.
138*b1cdbd2cSJim Jagielski 
139*b1cdbd2cSJim Jagielski     @param matrix
140*b1cdbd2cSJim Jagielski     The matrix to operate on. Last column is the result vector (right
141*b1cdbd2cSJim Jagielski     hand side of the linear equation). After successful termination,
142*b1cdbd2cSJim Jagielski     the matrix is upper triangular. The matrix is expected to be in
143*b1cdbd2cSJim Jagielski     row major order.
144*b1cdbd2cSJim Jagielski 
145*b1cdbd2cSJim Jagielski     @param rows
146*b1cdbd2cSJim Jagielski     Number of rows in matrix
147*b1cdbd2cSJim Jagielski 
148*b1cdbd2cSJim Jagielski     @param cols
149*b1cdbd2cSJim Jagielski     Number of columns in matrix
150*b1cdbd2cSJim Jagielski 
151*b1cdbd2cSJim Jagielski     @param minPivot
152*b1cdbd2cSJim Jagielski     If the pivot element gets lesser than minPivot, this method fails,
153*b1cdbd2cSJim Jagielski     otherwise, elimination succeeds and true is returned.
154*b1cdbd2cSJim Jagielski 
155*b1cdbd2cSJim Jagielski     @return true, if elimination succeeded.
156*b1cdbd2cSJim Jagielski  */
157*b1cdbd2cSJim Jagielski template <class Matrix, class Vector, typename BaseType>
solve(Matrix & matrix,int rows,int cols,Vector & result,BaseType minPivot)158*b1cdbd2cSJim Jagielski bool solve(	Matrix&		matrix,
159*b1cdbd2cSJim Jagielski             int			rows,
160*b1cdbd2cSJim Jagielski             int			cols,
161*b1cdbd2cSJim Jagielski             Vector&		result,
162*b1cdbd2cSJim Jagielski             BaseType	minPivot	)
163*b1cdbd2cSJim Jagielski {
164*b1cdbd2cSJim Jagielski 	if( eliminate<Matrix,BaseType>(matrix, rows, cols, minPivot) )
165*b1cdbd2cSJim Jagielski 		return substitute<Matrix,Vector,BaseType>(matrix, rows, cols, result);
166*b1cdbd2cSJim Jagielski 
167*b1cdbd2cSJim Jagielski 	return false;
168*b1cdbd2cSJim Jagielski }
169