|
MagickCore
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % M M AAA TTTTT RRRR IIIII X X % 00007 % MM MM A A T R R I X X % 00008 % M M M AAAAA T RRRR I X % 00009 % M M A A T R R I X X % 00010 % M M A A T R R IIIII X X % 00011 % % 00012 % % 00013 % MagickCore Matrix Methods % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % August 2007 % 00018 % % 00019 % % 00020 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % 00021 % dedicated to making software imaging solutions freely available. % 00022 % % 00023 % You may not use this file except in compliance with the License. You may % 00024 % obtain a copy of the License at % 00025 % % 00026 % http://www.imagemagick.org/script/license.php % 00027 % % 00028 % Unless required by applicable law or agreed to in writing, software % 00029 % distributed under the License is distributed on an "AS IS" BASIS, % 00030 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00031 % See the License for the specific language governing permissions and % 00032 % limitations under the License. % 00033 % % 00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00035 % 00036 % 00037 */ 00038 00039 /* 00040 Include declarations. 00041 */ 00042 #include "MagickCore/studio.h" 00043 #include "MagickCore/matrix.h" 00044 #include "MagickCore/matrix-private.h" 00045 #include "MagickCore/memory_.h" 00046 00047 /* 00048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00049 % % 00050 % % 00051 % % 00052 % A c q u i r e M a g i c k M a t r i x % 00053 % % 00054 % % 00055 % % 00056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00057 % 00058 % AcquireMagickMatrix() allocates and returns a matrix in the form of an 00059 % array of pointers to an array of doubles, with all values pre-set to zero. 00060 % 00061 % This used to generate the two dimensional matrix, that can be referenced 00062 % using the simple C-code of the form "matrix[y][x]". 00063 % 00064 % This matrix is typically used for perform for the GaussJordanElimination() 00065 % method below, solving some system of simultanious equations. 00066 % 00067 % The format of the AcquireMagickMatrix method is: 00068 % 00069 % double **AcquireMagickMatrix(const size_t number_rows, 00070 % const size_t size) 00071 % 00072 % A description of each parameter follows: 00073 % 00074 % o number_rows: the number pointers for the array of pointers 00075 % (first dimension). 00076 % 00077 % o size: the size of the array of doubles each pointer points to 00078 % (second dimension). 00079 % 00080 */ 00081 MagickExport double **AcquireMagickMatrix(const size_t number_rows, 00082 const size_t size) 00083 { 00084 double 00085 **matrix; 00086 00087 register ssize_t 00088 i, 00089 j; 00090 00091 matrix=(double **) AcquireQuantumMemory(number_rows,sizeof(*matrix)); 00092 if (matrix == (double **) NULL) 00093 return((double **) NULL); 00094 for (i=0; i < (ssize_t) number_rows; i++) 00095 { 00096 matrix[i]=(double *) AcquireQuantumMemory(size,sizeof(*matrix[i])); 00097 if (matrix[i] == (double *) NULL) 00098 { 00099 for (j=0; j < i; j++) 00100 matrix[j]=(double *) RelinquishMagickMemory(matrix[j]); 00101 matrix=(double **) RelinquishMagickMemory(matrix); 00102 return((double **) NULL); 00103 } 00104 for (j=0; j < (ssize_t) size; j++) 00105 matrix[i][j]=0.0; 00106 } 00107 return(matrix); 00108 } 00109 00110 /* 00111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00112 % % 00113 % % 00114 % % 00115 % G a u s s J o r d a n E l i m i n a t i o n % 00116 % % 00117 % % 00118 % % 00119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00120 % 00121 % GaussJordanElimination() returns a matrix in reduced row echelon form, 00122 % while simultaneously reducing and thus solving the augumented results 00123 % matrix. 00124 % 00125 % See also http://en.wikipedia.org/wiki/Gauss-Jordan_elimination 00126 % 00127 % The format of the GaussJordanElimination method is: 00128 % 00129 % MagickBooleanType GaussJordanElimination(double **matrix, 00130 % double **vectors,const size_t rank,const size_t number_vectors) 00131 % 00132 % A description of each parameter follows: 00133 % 00134 % o matrix: the matrix to be reduced, as an 'array of row pointers'. 00135 % 00136 % o vectors: the additional matrix argumenting the matrix for row reduction. 00137 % Producing an 'array of column vectors'. 00138 % 00139 % o rank: The size of the square matrix (both rows and columns). 00140 % Also represents the number terms that need to be solved. 00141 % 00142 % o number_vectors: Number of vectors columns, argumenting the above matrix. 00143 % Usally 1, but can be more for more complex equation solving. 00144 % 00145 % Note that the 'matrix' is given as a 'array of row pointers' of rank size. 00146 % That is values can be assigned as matrix[row][column] where 'row' is 00147 % typically the equation, and 'column' is the term of the equation. 00148 % That is the matrix is in the form of a 'row first array'. 00149 % 00150 % However 'vectors' is a 'array of column pointers' which can have any number 00151 % of columns, with each column array the same 'rank' size as 'matrix'. 00152 % It is assigned vector[column][row] where 'column' is the specific 00153 % 'result' and 'row' is the 'values' for that answer. After processing 00154 % the same vector array contains the 'weights' (answers) for each of the 00155 % 'separatable' results. 00156 % 00157 % This allows for simpler handling of the results, especially is only one 00158 % column 'vector' is all that is required to produce the desired solution 00159 % for that specific set of equations. 00160 % 00161 % For example, the 'vectors' can consist of a pointer to a simple array of 00162 % doubles. when only one set of simultanious equations is to be solved from 00163 % the given set of coefficient weighted terms. 00164 % 00165 % double **matrix = AcquireMagickMatrix(8UL,8UL); 00166 % double coefficents[8]; 00167 % ... 00168 % GaussJordanElimination(matrix, &coefficents, 8UL, 1UL); 00169 % 00170 % However by specifing more 'columns' (as an 'array of vector columns'), 00171 % you can use this function to solve multiple sets of 'separable' equations. 00172 % 00173 % For example a distortion function where u = U(x,y) v = V(x,y) 00174 % And the functions U() and V() have separate coefficents, but are being 00175 % generated from a common x,y->u,v data set. 00176 % 00177 % Another example is generation of a color gradient from a set of colors 00178 % at specific coordients, such as a list x,y -> r,g,b,a 00179 % 00180 % See LeastSquaresAddTerms() below for such an example. 00181 % 00182 % You can also use the 'vectors' to generate an inverse of the given 'matrix' 00183 % though as a 'column first array' rather than a 'row first array' (matrix 00184 % is transposed). 00185 % 00186 % For details of this process see... 00187 % http://en.wikipedia.org/wiki/Gauss-Jordan_elimination 00188 % 00189 */ 00190 MagickPrivate MagickBooleanType GaussJordanElimination(double **matrix, 00191 double **vectors,const size_t rank,const size_t number_vectors) 00192 { 00193 #define GaussJordanSwap(x,y) \ 00194 { \ 00195 if ((x) != (y)) \ 00196 { \ 00197 (x)+=(y); \ 00198 (y)=(x)-(y); \ 00199 (x)=(x)-(y); \ 00200 } \ 00201 } 00202 00203 double 00204 max, 00205 scale; 00206 00207 register ssize_t 00208 i, 00209 j, 00210 k; 00211 00212 ssize_t 00213 column, 00214 *columns, 00215 *pivots, 00216 row, 00217 *rows; 00218 00219 columns=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*columns)); 00220 rows=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*rows)); 00221 pivots=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*pivots)); 00222 if ((rows == (ssize_t *) NULL) || (columns == (ssize_t *) NULL) || 00223 (pivots == (ssize_t *) NULL)) 00224 { 00225 if (pivots != (ssize_t *) NULL) 00226 pivots=(ssize_t *) RelinquishMagickMemory(pivots); 00227 if (columns != (ssize_t *) NULL) 00228 columns=(ssize_t *) RelinquishMagickMemory(columns); 00229 if (rows != (ssize_t *) NULL) 00230 rows=(ssize_t *) RelinquishMagickMemory(rows); 00231 return(MagickFalse); 00232 } 00233 (void) ResetMagickMemory(columns,0,rank*sizeof(*columns)); 00234 (void) ResetMagickMemory(rows,0,rank*sizeof(*rows)); 00235 (void) ResetMagickMemory(pivots,0,rank*sizeof(*pivots)); 00236 column=0; 00237 row=0; 00238 for (i=0; i < (ssize_t) rank; i++) 00239 { 00240 max=0.0; 00241 for (j=0; j < (ssize_t) rank; j++) 00242 if (pivots[j] != 1) 00243 { 00244 for (k=0; k < (ssize_t) rank; k++) 00245 if (pivots[k] != 0) 00246 { 00247 if (pivots[k] > 1) 00248 return(MagickFalse); 00249 } 00250 else 00251 if (fabs(matrix[j][k]) >= max) 00252 { 00253 max=fabs(matrix[j][k]); 00254 row=j; 00255 column=k; 00256 } 00257 } 00258 pivots[column]++; 00259 if (row != column) 00260 { 00261 for (k=0; k < (ssize_t) rank; k++) 00262 GaussJordanSwap(matrix[row][k],matrix[column][k]); 00263 for (k=0; k < (ssize_t) number_vectors; k++) 00264 GaussJordanSwap(vectors[k][row],vectors[k][column]); 00265 } 00266 rows[i]=row; 00267 columns[i]=column; 00268 if (matrix[column][column] == 0.0) 00269 return(MagickFalse); /* singularity */ 00270 scale=1.0/matrix[column][column]; 00271 matrix[column][column]=1.0; 00272 for (j=0; j < (ssize_t) rank; j++) 00273 matrix[column][j]*=scale; 00274 for (j=0; j < (ssize_t) number_vectors; j++) 00275 vectors[j][column]*=scale; 00276 for (j=0; j < (ssize_t) rank; j++) 00277 if (j != column) 00278 { 00279 scale=matrix[j][column]; 00280 matrix[j][column]=0.0; 00281 for (k=0; k < (ssize_t) rank; k++) 00282 matrix[j][k]-=scale*matrix[column][k]; 00283 for (k=0; k < (ssize_t) number_vectors; k++) 00284 vectors[k][j]-=scale*vectors[k][column]; 00285 } 00286 } 00287 for (j=(ssize_t) rank-1; j >= 0; j--) 00288 if (columns[j] != rows[j]) 00289 for (i=0; i < (ssize_t) rank; i++) 00290 GaussJordanSwap(matrix[i][rows[j]],matrix[i][columns[j]]); 00291 pivots=(ssize_t *) RelinquishMagickMemory(pivots); 00292 rows=(ssize_t *) RelinquishMagickMemory(rows); 00293 columns=(ssize_t *) RelinquishMagickMemory(columns); 00294 return(MagickTrue); 00295 } 00296 00297 /* 00298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00299 % % 00300 % % 00301 % % 00302 % L e a s t S q u a r e s A d d T e r m s % 00303 % % 00304 % % 00305 % % 00306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00307 % 00308 % LeastSquaresAddTerms() adds one set of terms and associate results to the 00309 % given matrix and vectors for solving using least-squares function fitting. 00310 % 00311 % The format of the AcquireMagickMatrix method is: 00312 % 00313 % void LeastSquaresAddTerms(double **matrix,double **vectors, 00314 % const double *terms,const double *results,const size_t rank, 00315 % const size_t number_vectors); 00316 % 00317 % A description of each parameter follows: 00318 % 00319 % o matrix: the square matrix to add given terms/results to. 00320 % 00321 % o vectors: the result vectors to add terms/results to. 00322 % 00323 % o terms: the pre-calculated terms (without the unknown coefficent 00324 % weights) that forms the equation being added. 00325 % 00326 % o results: the result(s) that should be generated from the given terms 00327 % weighted by the yet-to-be-solved coefficents. 00328 % 00329 % o rank: the rank or size of the dimentions of the square matrix. 00330 % Also the length of vectors, and number of terms being added. 00331 % 00332 % o number_vectors: Number of result vectors, and number or results being 00333 % added. Also represents the number of separable systems of equations 00334 % that is being solved. 00335 % 00336 % Example of use... 00337 % 00338 % 2 dimensional Affine Equations (which are separable) 00339 % c0*x + c2*y + c4*1 => u 00340 % c1*x + c3*y + c5*1 => v 00341 % 00342 % double **matrix = AcquireMagickMatrix(3UL,3UL); 00343 % double **vectors = AcquireMagickMatrix(2UL,3UL); 00344 % double terms[3], results[2]; 00345 % ... 00346 % for each given x,y -> u,v 00347 % terms[0] = x; 00348 % terms[1] = y; 00349 % terms[2] = 1; 00350 % results[0] = u; 00351 % results[1] = v; 00352 % LeastSquaresAddTerms(matrix,vectors,terms,results,3UL,2UL); 00353 % ... 00354 % if ( GaussJordanElimination(matrix,vectors,3UL,2UL) ) { 00355 % c0 = vectors[0][0]; 00356 % c2 = vectors[0][1]; %* weights to calculate u from any given x,y *% 00357 % c4 = vectors[0][2]; 00358 % c1 = vectors[1][0]; 00359 % c3 = vectors[1][1]; %* weights for calculate v from any given x,y *% 00360 % c5 = vectors[1][2]; 00361 % } 00362 % else 00363 % printf("Matrix unsolvable\n); 00364 % RelinquishMagickMatrix(matrix,3UL); 00365 % RelinquishMagickMatrix(vectors,2UL); 00366 % 00367 % More examples can be found in "distort.c" 00368 % 00369 */ 00370 MagickPrivate void LeastSquaresAddTerms(double **matrix,double **vectors, 00371 const double *terms,const double *results,const size_t rank, 00372 const size_t number_vectors) 00373 { 00374 register ssize_t 00375 i, 00376 j; 00377 00378 for (j=0; j < (ssize_t) rank; j++) 00379 { 00380 for (i=0; i < (ssize_t) rank; i++) 00381 matrix[i][j]+=terms[i]*terms[j]; 00382 for (i=0; i < (ssize_t) number_vectors; i++) 00383 vectors[i][j]+=results[i]*terms[j]; 00384 } 00385 } 00386 00387 /* 00388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00389 % % 00390 % % 00391 % % 00392 % R e l i n q u i s h M a g i c k M a t r i x % 00393 % % 00394 % % 00395 % % 00396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00397 % 00398 % RelinquishMagickMatrix() frees the previously acquired matrix (array of 00399 % pointers to arrays of doubles). 00400 % 00401 % The format of the RelinquishMagickMatrix method is: 00402 % 00403 % double **RelinquishMagickMatrix(double **matrix, 00404 % const size_t number_rows) 00405 % 00406 % A description of each parameter follows: 00407 % 00408 % o matrix: the matrix to relinquish 00409 % 00410 % o number_rows: the first dimension of the acquired matrix (number of 00411 % pointers) 00412 % 00413 */ 00414 MagickExport double **RelinquishMagickMatrix(double **matrix, 00415 const size_t number_rows) 00416 { 00417 register ssize_t 00418 i; 00419 00420 if (matrix == (double **) NULL ) 00421 return(matrix); 00422 for (i=0; i < (ssize_t) number_rows; i++) 00423 matrix[i]=(double *) RelinquishMagickMemory(matrix[i]); 00424 matrix=(double **) RelinquishMagickMemory(matrix); 00425 return(matrix); 00426 }