cmatrix.c

Go to the documentation of this file.
00001 /**
00002 \file     cmatrix.c
00003 \brief    'c' functions for vector and matrix operations.
00004 \author   Glenn D. MacGougan (GDM)
00005 \date     2009-01-08
00006 \version  0.07 Beta
00007 
00008 \b Version \b Information \n
00009 This is the open source version (BSD license). The Professional Version
00010 is avaiable via http://www.zenautics.com. The Professional Version
00011 is highly optimized using SIMD and includes optimization for multi-core 
00012 processors.
00013 
00014 \b License \b Information \n
00015 Copyright (c) 2009, Glenn D. MacGougan \n
00016 
00017 Redistribution and use in source and binary forms, with or without
00018 modification, of the specified files is permitted provided the following 
00019 conditions are met: \n
00020 
00021 - Redistributions of source code must retain the above copyright
00022   notice, this list of conditions and the following disclaimer. \n
00023 - Redistributions in binary form must reproduce the above copyright
00024   notice, this list of conditions and the following disclaimer in the
00025   documentation and/or other materials provided with the distribution. \n
00026 - The name(s) of the contributor(s) may not be used to endorse or promote 
00027   products derived from this software without specific prior written 
00028   permission. \n
00029 
00030 THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 
00031 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00032 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00033 DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00034 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00035 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00036 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00037 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00038 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00039 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00040 SUCH DAMAGE.
00041 
00042 \b NOTES: \n
00043 This code was developed using rigourous unit testing for every function 
00044 and operation. Despite any rigorous development process, bugs are
00045 inevitable. Please report bugs and suggested fixes to glenn @ zenautics.com.\n
00046 */
00047 #include <stdio.h>  // for FILE*
00048 #include <stdlib.h> // for calloc, malloc, free
00049 #include <string.h> // for strlen, sprintf, strstr, strcmp, and others
00050 #include <ctype.h>  // for isalpha
00051 #include <math.h>
00052 #include <float.h>
00053 #include <errno.h>
00054 
00055 #include "cmatrix.h"
00056 
00057 #ifndef _MATRIX_NO_PLOTTING
00058 #include "cplot.h"   // for CPLOT - plotting capabilities directly to an image file.
00059 #endif
00060 
00061 // deal with msvc empty projects
00062 #ifndef WIN32
00063   #ifdef _WIN32
00064     #define WIN32
00065   #endif
00066 #endif
00067 
00068 #if defined _MSC_VER && _MSC_VER < 1400
00069 #define _CRT_SECURE_NO_DEPRECATE
00070 #endif
00071 
00072 #ifndef _MSC_VER
00073 #define _CRT_SECURE_NO_DEPRECATE
00074 #endif
00075 
00076 #include "kiss_fft.h" // Use kiss FFT, when INTEL_IPPS is disabled
00077 
00078 //#define MTX_DEBUG
00079 #ifdef MTX_DEBUG
00080 #include <time.h>
00081 #endif
00082 
00083 
00084 #ifndef PI
00085 #define PI (3.1415926535897932384626433832795) //!< better value
00086 #endif
00087 
00088 #ifndef TWOPI
00089 #define TWOPI (6.283185307179586476925286766559) //!< 2.0*PI
00090 #endif
00091 
00092 #ifndef HALFPI
00093 #define HALFPI (1.5707963267948966192313216916398) //!< PI/2.0
00094 #endif
00095 
00096 
00097 #define MTX_MAX_READFROMFILE_BUFFER (65536)
00098 #define MATRIX_MIN_RLE_TOLERANCE (1.0e-16)
00099 #define MTX_MAX_COMMENT_LENGTH (1024*6)
00100 
00101 // binary version identifiers
00102 #define MTX_ID_SIZE (8)
00103 #define MTX_ID_COMPRESSED_01 ("MTX01\n") //!< identifier used to indicate a file stored using SaveCompressed (version 1)
00104 #define MTX_ID_LEGACY_V01 ("Matrix\n") //!< legacy identifier used to indicate a file stored using Save with imprecise double RLE
00105 #define MTX_ID_LEGACY_V02 ("MTXV02\n") //!< legacy identifier used to indicate a file stored using Save with imprecise double RLE
00106 
00107 #define MTX_VERSION_NR_DEFAULT (101) //!< identifier used to indicate a file stored using basic Save
00108 #define MTX_VERSION_NR_COMPRESSED_01 (102) //!< identifier used to indicate a file stored using SaveCompressed (version 1)
00109 #define MTX_VERSION_NR_LEGACY_V01 (1) //!< legacy identifier used to indicate a file stored using Save with imprecise double RLE
00110 #define MTX_VERSION_NR_LEGACY_V02 (2) //!< legacy identifier used to indicate a file stored using Save with imprecise double RLE
00111 
00112 #define MTX_NK (8) //!< the number of byte columns used to represent a column of doubles when using MTX_ID_COMPRESSED_01
00113 
00114 #define MTX_NAN     (sqrt(-1.0))
00115 #define MTX_POS_INF (-log(0.0))
00116 #define MTX_NEG_INF ( log(0.0))
00117 
00118 
00119 /// \brief This static global variable indicates whether matrix
00120 /// operations for single elements are treated as scalar
00121 /// operations.
00122 /// e.g. A = B*C, B is 1x1 C is 10x10. If this was disabled, this
00123 /// operation would return FALSE as an error. When enabled, A, is
00124 /// treated as a scalar and is multiplied into every element of C.
00125 BOOL MTX_static_global_treat_1x1_as_scalar = TRUE;
00126 
00127 
00128 typedef struct
00129 {
00130   char id[8];
00131   unsigned headersize;
00132   unsigned isReal;
00133   unsigned nrows;
00134   unsigned ncols;
00135   unsigned filesize;
00136   unsigned crc;
00137   char *comment;
00138 }_MTX_STRUCT_FileHeader;
00139 
00140 typedef struct
00141 {
00142   unsigned length[MTX_NK]; // length of compressed data column
00143   unsigned char isCompressed[MTX_NK]; // indicates which columns are compressed using RLE
00144   unsigned totalLength; // total length of MTX_NK data columns
00145 }_MTX_STRUCT_CompressedColumnHeader;
00146 
00147 
00148 /// struct specific for MTX_ReadFromFile and related functions (a simple linked list)
00149 typedef struct _MTX_listItemCplx
00150 {
00151   BOOL isReal; //!< A boolean to indicate if real data or complex data is attached to this item.
00152   double *rowptr; //!< The pointer to real data.
00153   stComplex *rowptr_cplx; //!< The pointer to complex data.
00154   struct _MTX_listItemCplx *next; //!< The pointer to the next item in the list.
00155 }_MTX_STRUCT_ReadFromFileListElem;
00156 
00157 
00158 /// static function for matrix memory allocation
00159 static BOOL MTX_static_alloc( MTX *M, const unsigned nrows, const unsigned ncols, const BOOL setToZero, const BOOL isReal );
00160 
00161 /// static function for converting a complex stored matrix to a real matrix (either all real component or all imaginary component)
00162 static BOOL MTX_static_ConvertComplexTo( MTX *M, BOOL useReal );
00163 
00164 static BOOL MTX_static_get_row_array_from_string( char *datastr, _MTX_STRUCT_ReadFromFileListElem *L, const unsigned ncols );
00165 
00166 /// This function gets the next valid line of data. Whitespace lines are skipped.
00167 static BOOL MTX_static_get_next_valid_data_line(
00168   FILE *in, //!< The input file pointer (input).
00169   char *linebuf, //!< A exisiting buffer to store the input line (input/output).
00170   unsigned *line_length, //!< The length of the line read (output).
00171   BOOL *atEOF //!< A boolean to indicate if EOF has been reached.
00172   );
00173 
00174 /// This function gets the next valid line of data from a matrix string. Whitespace lines are skipped.
00175 static BOOL MTX_static_get_next_valid_data_line_from_matrix_string(
00176   const char *strMatrix, //!< The matrix string pointer (input).
00177   const unsigned strLength, //!< The length of the matrix string (input).
00178   unsigned *index, //!< The starting/(next line) index into the matrix string pointer (input/output).
00179   char *linebuf, //!< A exisiting buffer to store the input line (input/output).
00180   unsigned *line_length, //!< The length of the line read (output).
00181   BOOL *atEndOfString //!< A boolean to indicate if the end of the strMatrix string has been reached.
00182   );
00183 
00184 
00185 /// Extract a complex value from a string with a leading digit.
00186 /// The string is either bi or a+bi.
00187 static BOOL MTX_static_extract_cplx_from_string_with_leading_digit(
00188   char *datastr, //!< The entire input data string.
00189   const unsigned indexS, //!< The start index of the complex element.
00190   const unsigned indexE, //!< The inclusive end index of the complex element.
00191   double *re, //!< The extracted real component.
00192   double *im //!< The extracted imag component.
00193   );
00194 
00195 
00196 static BOOL MTX_static_extract_real_into_cplx_from_string(
00197   char *datastr, //!< The entire input data string.
00198   const unsigned indexS, //!< The start index of the complex element.
00199   double *re, //!< The extracted real component.
00200   double *im //!< The extracted imag component.
00201   );
00202 
00203 /// This static function looks for complex data in a line string.
00204 static BOOL MTX_static_look_for_complex_data(
00205   char *linebuf, //!< A string containing a line of data (input).
00206   const unsigned line_length, //!< The length of the string (input).
00207   BOOL *hasComplex //!< A boolean indicating if there is any complex data (output).
00208   );
00209 
00210 
00211 
00212 /// static function, rounds a value to an integer
00213 static BOOL MTX_static_round_value_to_integer( double *value );
00214 
00215 /// static function, rounds a value at the specified precision
00216 static BOOL MTX_static_round_value( double *value, const unsigned precision );
00217 
00218 ////
00219 // functions for quicksorting
00220 static void MTX_static_quicksort( double *a, unsigned start, unsigned end ); //!< The normal quicksort function
00221 static void MTX_static_swap_doubles( double *a, double *b ); //!< swap two doubles a and b
00222 static int MTX_static_partition( double *a, unsigned start, unsigned end ); //!< partition the vector
00223 static void MTX_static_quicksort_indexed( double *a, double *index, unsigned start, unsigned end ); //!< quicksort that also returns a sorted indexing vector
00224 static void MTX_static_swap_doubles_indexed( double *a, double *b, double *index_a, double *index_b ); //!< swap the doubles and indexes
00225 static int MTX_static_partition_indexed( double *a, double *index, unsigned start, unsigned end ); //!< partition the vectors
00226 
00227 
00228 /// Compute the sqrt of a complex value.
00229 static void MTX_static_quick_sqrt( const double *a_re, const double *a_im, double *re, double *im );
00230 
00231 
00232 /// A static function to multiply a*b complex values
00233 static void MTX_static_quick_complex_mult_ab(
00234   const double* a_re,
00235   const double* a_im,
00236   const double* b_re,
00237   const double* b_im,
00238   double *re,
00239   double *im );
00240 
00241 /// A static function to multiply a*b*c complex values
00242 static void MTX_static_quick_complex_mult_abc(
00243   const double* a_re,
00244   const double* a_im,
00245   const double* b_re,
00246   const double* b_im,
00247   const double* c_re,
00248   const double* c_im,
00249   double *re,
00250   double *im );
00251 
00252 
00253 /// A static function to compute the complex result of a/b.
00254 static void MTX_static_quick_complex_divide(
00255                                      const double* a_re, //!< The real part of a (input).
00256                                      const double* a_im, //!< The imag part of a (input).
00257                                      const double* b_re, //!< The real part of b (input).
00258                                      const double* b_im, //!< The imag part of b (input).
00259                                      double *re, //!< The real part of the result.
00260                                      double *im ); //!< The imag part of the result.
00261 
00262 
00263 
00264 /// Calculate a CRC value to be used by CRC calculation functions.
00265 static unsigned MTX_static_CRC32(unsigned ulCRC);
00266 
00267 /// Updates the 32 bit CRC with a block of data.
00268 /// This function can be called once (with uiCRC initialized to zero) to get the crc
00269 /// for a single byte vector or multiple times to apply the crc calculation to multiple
00270 /// bytes vectors.
00271 static void MTX_static_updateCRC( unsigned char *pBytes, const unsigned nBytes, unsigned *uiCRC );
00272 
00273 /// closes the file and frees memory used by MTX_SaveCompressed and MTX_Load
00274 static void MTX_static_SaveAndLoadCleanUp( FILE *fid, unsigned char **bytes, unsigned char **compressed, const unsigned nk );
00275 
00276 /// loads a legacy verison of a .mtx binary matrix file
00277 static BOOL MTX_static_ReadCompressed_LegacyVersion( MTX* M, const char *path );
00278 
00279 
00280 /// Performs factorization by gaussian elimination with scaled parital pivoting
00281 /// /b Reference /n
00282 /// [1] Chaney, Ward & David Kincaid, "Numerical Mathematics and Computing, 3rd Edition",
00283 /// Cole Publishing Co., 1994, Belmont, CA, p.237)
00284 static BOOL MTX_static_Factorize( BOOL *isFullRank, const unsigned n, unsigned* index, MTX *A );
00285 
00286 /// Solve AX=b
00287 /// factorized A is obtained from MTX_static_Factorize
00288 static BOOL MTX_static_SolveByGaussianElimination(
00289   const MTX *b,
00290   MTX *X,
00291   const MTX *A, // factorized A
00292   unsigned *index );
00293 
00294 /// Clean up dynamic memory used in MTX_Det.
00295 static void MTX_static_Det_cleanup( unsigned *index, double *scale, MTX *U, MTX *magMtx );
00296 
00297 
00298 
00299 /// Perform the FFT or IFFT of the columns in the src matrix and
00300 /// store the result in the dst matrix. If the number of rows in the
00301 /// src matrix is not a power of two, the DFT or IDFT is performed.
00302 static BOOL MTX_static_fft(
00303                            const MTX *src, //!< The source matrix.
00304                            MTX *dst, //!< The result matrix (always complex).
00305                            BOOL isFwd //!< A boolean to indicate if this is a fwd transform or the inverse transform
00306                            );
00307 
00308 /// Perform the FFT or IFFT of the columns in the src matrix inplace.
00309 /// If the number of rows in the src matrix is not a power of two, the DFT or IDFT is performed.
00310 static BOOL MTX_static_fft_inplace(
00311                                    MTX *src, //!< The source matrix.
00312                                    BOOL isFwd //!< A boolean to indicate if this is a fwd transform or the inverse transform
00313                                    );
00314 
00315 
00316 
00317 
00318 /// \brief  Get a value from the uniform distribution [0,1].
00319 /// \pre srand(seed) has been called.
00320 static double MTX_static_get_rand_value();
00321 
00322 /// \brief  Get a value from the standard normal gaussian distribution.
00323 ///
00324 /// \pre srand(seed) has been called.
00325 ///
00326 /// REFERENCE: \n
00327 /// Scheinerman, E. R (2006). "C++ for Mathematicians: An Introduction for Students and Professionals."
00328 /// Chapman and Hall/CRC, Taylor and Francis Group. pp 61-63.
00329 static double MTX_static_get_randn_value();
00330 
00331 
00332 
00333 BOOL MTX_Initialize_MTXEngine()
00334 {
00335   return TRUE;
00336 }
00337 
00338 BOOL MTX_Enable1x1MatricesForTreatmentAsScalars( BOOL enable )
00339 {
00340   MTX_static_global_treat_1x1_as_scalar = enable;
00341   return TRUE;
00342 }
00343 
00344 BOOL MTX_isNull( const MTX *M )
00345 {
00346   if( !M )
00347     return TRUE;
00348 
00349   if( M->data == NULL && M->cplx == NULL )
00350     return TRUE;
00351 
00352   return FALSE;
00353 }
00354 
00355 BOOL MTX_isConformalForMultiplication( const MTX *A, const MTX *B )
00356 {
00357   if( MTX_isNull( A ) )
00358   {
00359     return FALSE;
00360   }
00361   if( MTX_isNull( B ) )
00362   {
00363     return FALSE;
00364   }
00365 
00366   return( A->ncols == B->nrows );
00367 }
00368 
00369 BOOL MTX_isConformalForAddition( const MTX *A, const MTX *B )
00370 {
00371   if( MTX_isNull( A ) )
00372   {
00373     return FALSE;
00374   }
00375   if( MTX_isNull( B ) )
00376   {
00377     return FALSE;
00378   }
00379 
00380   return( A->nrows == B->nrows && A->ncols == B->ncols );
00381 }
00382 
00383 
00384 BOOL MTX_isSquare( const MTX *A )
00385 {
00386   if( MTX_isNull( A ) )
00387   {
00388     return FALSE;
00389   }
00390 
00391   return( A->nrows == A->ncols );
00392 }
00393 
00394 BOOL MTX_isSameSize( const MTX *A, const MTX *B )
00395 {
00396   return MTX_isConformalForAddition( A, B );
00397 }
00398 
00399 
00400 BOOL MTX_Init( MTX *M )
00401 {
00402   if( !M )
00403   {
00404     MTX_ERROR_MSG( "Cannot initialize NULL pointer." )
00405       return FALSE;
00406   }
00407 
00408   M->ncols = 0;
00409   M->nrows = 0;
00410   M->isReal = TRUE;
00411   M->cplx = NULL;
00412   M->data = NULL;
00413   M->comment = NULL;
00414 
00415   return TRUE;
00416 }
00417 
00418 BOOL MTX_SetComment( MTX *M, const char *comment )
00419 {
00420   unsigned length;
00421 
00422   if( !M )
00423   {
00424     MTX_ERROR_MSG( "Cannot initialize NULL pointer." );
00425     return FALSE;
00426   }
00427 
00428   if( !comment )
00429   {
00430     MTX_ERROR_MSG( "if( !comment )" );
00431     return FALSE;
00432   }
00433 
00434   if( M->comment )
00435     free( M->comment );
00436 
00437   length = (unsigned int)strlen(comment);
00438   if( length == 0 )
00439   {
00440     MTX_ERROR_MSG( "strlen returned 0." );
00441     return FALSE;
00442   }
00443 
00444   M->comment = (char*)malloc( (length+1)*sizeof(char) ); // +1 for the null terminator
00445   if( !M->comment )
00446   {
00447     // memory allocation failure
00448     MTX_ERROR_MSG( "malloc returned NULL." );
00449     return FALSE;
00450   }
00451 
00452 #ifndef _CRT_SECURE_NO_DEPRECATE
00453   if( strcpy_s( M->comment, length+1, comment ) != 0 )
00454   {
00455     MTX_ERROR_MSG( "strcpy_s returned 0." );
00456     free(M->comment);
00457     M->comment = NULL;
00458     return FALSE;
00459   }
00460 #else
00461   strcpy( M->comment, comment );
00462 #endif
00463 
00464   return TRUE;
00465 }
00466 
00467 BOOL MTX_Free( MTX *M )
00468 {
00469   unsigned j = 0;
00470 
00471   if( !M )
00472   {
00473     MTX_ERROR_MSG( "Cannot free NULL pointer." );
00474     return FALSE;
00475   }
00476 
00477   if( M->isReal )
00478   {
00479     if( M->data == NULL )
00480     {
00481       if( M->comment )
00482         free( M->comment );
00483 
00484       M->comment = NULL;
00485       M->nrows = 0;
00486       M->ncols = 0;
00487       return TRUE;
00488     }
00489   }
00490   else
00491   {
00492     if( M->cplx == NULL )
00493     {
00494       if( M->comment )
00495         free( M->comment );
00496 
00497       M->comment = NULL;
00498       M->nrows = 0;
00499       M->ncols = 0;
00500       return TRUE;
00501     }
00502   }
00503 
00504 
00505   if( M->isReal )
00506   {
00507     for( j = 0; j < M->ncols; j++ )
00508     {
00509       free( M->data[j] );
00510     }
00511   }
00512   else
00513   {
00514     for( j = 0; j < M->ncols; j++ )
00515     {
00516       free( M->cplx[j] );
00517     }
00518   }
00519 
00520   // free the array of pointers
00521   if( M->isReal )
00522     free( M->data );
00523   else
00524     free( M->cplx );
00525 
00526   M->nrows = 0;
00527   M->ncols = 0;
00528   M->isReal = TRUE;
00529   M->cplx = NULL;
00530   M->data = NULL;
00531 
00532   if( M->comment )
00533     free( M->comment );
00534   M->comment = NULL;
00535   return TRUE;
00536 }
00537 
00538 
00539 BOOL MTX_Malloc( MTX *M, const unsigned nrows, const unsigned ncols, const BOOL isReal )
00540 {
00541   return MTX_static_alloc( M, nrows, ncols, FALSE, isReal );
00542 }
00543 
00544 BOOL MTX_Calloc( MTX *M, const unsigned nrows, const unsigned ncols, const BOOL isReal )
00545 {
00546   return MTX_static_alloc( M, nrows, ncols, TRUE, isReal );
00547 }
00548 
00549 BOOL MTX_static_alloc( MTX *M, const unsigned nrows, const unsigned ncols, const BOOL setToZero, const BOOL isReal )
00550 {
00551   unsigned i = 0;
00552   unsigned j = 0;
00553 
00554   // invalid call
00555   if( nrows == 0 || ncols == 0 )
00556   {
00557     MTX_ERROR_MSG( "if( nrows == 0 || ncols == 0 )" );
00558     return FALSE;
00559   }
00560   if( !M )
00561   {
00562     MTX_ERROR_MSG( "Cannot set a NULL pointer." );
00563     return FALSE;
00564   }
00565 
00566   // Check if the matrix is already the right size and type.
00567   if( M->isReal == isReal )
00568   {
00569     if( M->nrows > 0 && M->ncols > 0 )
00570     {
00571       if( M->nrows == nrows && M->ncols == ncols )
00572       {
00573         // already the right size and type
00574         if( setToZero )
00575         {
00576           if( !MTX_Zero( M ) )
00577           {
00578             MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
00579             return FALSE;
00580           }
00581           return TRUE;
00582         }
00583         else
00584         {
00585           return TRUE;
00586         }
00587       }
00588       else if( M->nrows == nrows && M->ncols < ncols )
00589       {
00590         if( setToZero )
00591         {
00592           if( !MTX_Zero( M ) )
00593           {
00594             MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
00595             return FALSE;
00596           }
00597         }
00598         if( !MTX_AddZeroValuedColumns( M, ncols-M->ncols ) )
00599         {
00600           MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
00601           return FALSE;
00602         }
00603         return TRUE;
00604       }
00605       else if( M->nrows == nrows && M->ncols > ncols )
00606       {
00607         if( MTX_RemoveColumnsAfterIndex( M, ncols-1 ) == FALSE )
00608         {
00609           MTX_ERROR_MSG( "MTX_RemoveColumnsAfterIndex returned FALSE." );
00610           return FALSE;
00611         }
00612         if( setToZero )
00613         {
00614           if( !MTX_Zero( M ) )
00615           {
00616             MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
00617             return FALSE;
00618           }
00619         }
00620         return TRUE;
00621       }
00622     }    
00623   }
00624 
00625   // The matrix must be built from scratch.
00626   MTX_Free( M );
00627 
00628   M->isReal = isReal;
00629   M->nrows = nrows;
00630   M->ncols = 0;
00631 
00632   // allocate the column array
00633   if( isReal )
00634   {
00635     M->data = (double**)malloc( ncols*sizeof(double*) );
00636     if( !M->data )
00637     {
00638       MTX_ERROR_MSG( "malloc returned NULL." );
00639       return FALSE;
00640     }
00641   }
00642   else
00643   {
00644     M->cplx = (stComplex**)malloc( ncols*sizeof(stComplex*) );
00645     if( !M->cplx )
00646     {
00647       MTX_ERROR_MSG( "malloc returned NULL." );
00648       return FALSE;
00649     }
00650   }
00651 
00652 
00653   // for each column allocate the rows
00654   if( isReal )
00655   {
00656     for( j = 0; j < ncols; j++ )
00657     {
00658       if( setToZero )
00659         M->data[j] = (double*)calloc( nrows, sizeof(double) );
00660       else
00661         M->data[j] = (double*)malloc( nrows*sizeof(double) );
00662       if( !M->data[j] )
00663       {
00664         // this is most likely to occur if allocating more memory than available
00665         MTX_ERROR_MSG( "malloc or calloc returned NULL." );
00666         MTX_Free( M );
00667         return FALSE;
00668       }
00669       M->ncols++;
00670     }
00671   }
00672   else
00673   {
00674     for( j = 0; j < ncols; j++ )
00675     {
00676       M->cplx[j] = (stComplex*)malloc( nrows*sizeof(stComplex) );
00677       if( !M->cplx[j] )
00678       {
00679         // this is most likely to occur if allocating more memory than available
00680         MTX_ERROR_MSG( "malloc returned NULL." );
00681         MTX_Free( M );
00682         return FALSE;
00683       }
00684       if( setToZero )
00685       {
00686         for( i = 0; i < nrows; i++ )
00687         {
00688           M->cplx[j][i].re = 0.0;
00689           M->cplx[j][i].im = 0.0;
00690         }
00691       }
00692       M->ncols++;
00693     }    
00694   }
00695 
00696   return TRUE;
00697 }
00698 
00699 // Set a scalar value in the matrix.
00700 BOOL MTX_SetValue( MTX *M, const unsigned row, const unsigned col, const double value )
00701 {
00702   if( MTX_isNull( M ) )
00703   {
00704     MTX_ERROR_MSG( "NULL Matrix" );
00705     return FALSE;
00706   }
00707 
00708   if( row >= M->nrows )
00709   {
00710     MTX_ERROR_MSG( "if( row >= M->nrows )" );
00711     return FALSE;
00712   }
00713 
00714   if( col >= M->ncols )
00715   {
00716     MTX_ERROR_MSG( "if( col >= M->ncols )" );
00717     return FALSE;
00718   }
00719 
00720   if( M->isReal )
00721   {
00722     M->data[col][row] = value;
00723   }
00724   else
00725   {
00726     M->cplx[col][row].re = value;
00727     M->cplx[col][row].im = 0.0;
00728   }
00729 
00730   return TRUE;
00731 }
00732 
00733 // Set a complex value in the matrix.
00734 BOOL MTX_SetComplexValue( MTX *M, const unsigned row, const unsigned col, const double re, const double im )
00735 {
00736   if( MTX_isNull( M ) )
00737   {
00738     MTX_ERROR_MSG( "NULL Matrix" );
00739     return FALSE;
00740   }
00741 
00742   if( row >= M->nrows )
00743   {
00744     MTX_ERROR_MSG( "if( row >= M->nrows )" );
00745     return FALSE;
00746   }
00747 
00748   if( col >= M->ncols )
00749   {
00750     MTX_ERROR_MSG( "if( col >= M->ncols )" );
00751     return FALSE;
00752   }
00753 
00754   if( M->isReal && im != 0.0 )
00755   {
00756     if( !MTX_ConvertRealToComplex( M ) )
00757     {
00758       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
00759       return FALSE;
00760     }
00761   }
00762 
00763   if( M->isReal )
00764   {
00765     // im == 0.0
00766     M->data[col][row] = re;
00767   }
00768   else
00769   {
00770     M->cplx[col][row].re = re;
00771     M->cplx[col][row].im = im;
00772   }
00773 
00774   return TRUE;
00775 }
00776 
00777 
00778 // Matrix M = Re + Im*i, where Re and Im are real matrices.
00779 BOOL MTX_Complex( MTX *M, const MTX *Re, const MTX *Im )
00780 {
00781   unsigned i = 0;
00782   unsigned j = 0;
00783 
00784   if( MTX_isNull( Re ) )
00785   {
00786     MTX_ERROR_MSG( "NULL Matrix" );
00787     return FALSE;
00788   }
00789   if( MTX_isNull( Im ) )
00790   {
00791     MTX_ERROR_MSG( "NULL Matrix" );
00792     return FALSE;
00793   }
00794   if( !MTX_isSameSize( Re, Im ) )
00795   {
00796     MTX_ERROR_MSG( "MTX_isSameSize returned FALSE." );
00797     return FALSE;
00798   }
00799 
00800   if( !Re->isReal )
00801   {
00802     MTX_ERROR_MSG( "if( !Re->isReal )" );
00803     return FALSE;
00804   }
00805   if( !Im->isReal )
00806   {
00807     MTX_ERROR_MSG( "if( !Im->isReal )" );
00808     return FALSE;
00809   }
00810 
00811   if( M->isReal )
00812   {
00813     if( !MTX_Malloc( M, Re->nrows, Re->ncols, FALSE ) )
00814     {
00815       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
00816       return FALSE;
00817     }
00818   }
00819   else
00820   {
00821     if( !MTX_Resize( M, Re->nrows, Re->ncols, FALSE ) )
00822     {
00823       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
00824       return FALSE;
00825     }
00826   }
00827 
00828   for( j = 0; j < M->ncols; j++ )
00829   {
00830     for( i = 0; i < M->nrows; i++ )
00831     {
00832       M->cplx[j][i].re = Re->data[j][i];
00833       M->cplx[j][i].im = Im->data[j][i];
00834     }
00835   }
00836   return TRUE;
00837 }
00838 
00839 
00840 // Set the specified column in Matrix M to Re + Im*i, where Re and Im are real matrices.
00841 // The dimensions of M must already be valid.
00842 BOOL MTX_SetComplexColumn( MTX *M, const unsigned col, const MTX *Re, const MTX *Im )
00843 {
00844   unsigned i = 0;
00845   
00846   // check that M is complex
00847   if( M->isReal )
00848   {
00849     MTX_ERROR_MSG( "if( M->isReal )" );
00850     return FALSE;
00851   }
00852 
00853   if( MTX_isNull( Re ) )
00854   {
00855     MTX_ERROR_MSG( "NULL Matrix" );
00856     return FALSE;
00857   }
00858   if( MTX_isNull( Im ) )
00859   {
00860     MTX_ERROR_MSG( "NULL Matrix" );
00861     return FALSE;
00862   }
00863   if( Re->ncols != 1 )
00864   {
00865     MTX_ERROR_MSG( "if( Re->ncols != 1 )" );
00866     return FALSE;
00867   }
00868   if( !MTX_isSameSize( Re, Im ) )
00869   {
00870     MTX_ERROR_MSG( "MTX_isSameSize returned FALSE." );
00871     return FALSE;
00872   }
00873 
00874   if( !Re->isReal )
00875   {
00876     MTX_ERROR_MSG( "if( !Re->isReal )" );
00877     return FALSE;
00878   }
00879   if( !Im->isReal )
00880   {
00881     MTX_ERROR_MSG( "if( !Im->isReal )" );
00882     return FALSE;
00883   }
00884 
00885   // check that M has the right dimension
00886   if( M->nrows != Re->nrows )
00887   {
00888     MTX_ERROR_MSG( "if( M->nrows != Re->nrows )" );
00889     return FALSE;
00890   }
00891   if( col >= M->ncols )
00892   {
00893     MTX_ERROR_MSG( "if( col >= M->ncols )" );
00894     return FALSE;
00895   }
00896 
00897   for( i = 0; i < M->nrows; i++ )
00898   {
00899     M->cplx[col][i].re = Re->data[0][i];
00900     M->cplx[col][i].im = Im->data[0][i];
00901   }
00902   return TRUE;
00903 }
00904 
00905 
00906 BOOL MTX_ConvertRealToComplex( MTX *M )
00907 {
00908   unsigned i = 0;
00909   unsigned j = 0;
00910   unsigned k = 0;
00911 
00912   if( MTX_isNull( M ) )
00913   {
00914     MTX_ERROR_MSG( "NULL Matrix" );
00915     return FALSE;
00916   }
00917 
00918   if( !M->isReal )
00919     return TRUE; // already complex, nothing to do
00920 
00921   // allocate the complex column vector pointers
00922   M->cplx = (stComplex**)malloc( M->ncols*sizeof(stComplex*) );
00923   if( !M->cplx )
00924   {
00925     MTX_ERROR_MSG( "malloc retuned NULL." );
00926     return FALSE;
00927   }
00928 
00929   for( j = 0; j < M->ncols; j++ )
00930   {
00931     M->cplx[j] = (stComplex*)malloc( sizeof(stComplex)*(M->nrows) );
00932     if( !(M->cplx[j]) )
00933     {
00934       // this is most likely to occur if allocating more memory than available
00935       for( k = 0; k < j; k++ ) // delete the complex column data already allocated
00936       {
00937         free( M->cplx[k] );
00938       }
00939       // delete the complex column pointer array
00940       free( M->cplx );
00941       M->cplx = NULL;
00942       MTX_ERROR_MSG( "malloc retuned NULL." );
00943       return FALSE; // note, the matrix M is still valid as a real matrix
00944     }
00945     // now copy the real data to the complex
00946     for( i = 0; i < M->nrows; i++ )
00947     {
00948       M->cplx[j][i].re = M->data[j][i];
00949       M->cplx[j][i].im = 0.0;
00950     }
00951   }
00952 
00953   // free the real data
00954   for( j = 0; j < M->ncols; j++ )
00955   {
00956     free( M->data[j] );
00957   }
00958   // free the array of real pointers
00959   free( M->data );
00960   M->data = NULL;
00961   M->isReal = FALSE;
00962 
00963   // successfully converted the matrix from real to complex
00964   return TRUE;
00965 }
00966 
00967 
00968 BOOL MTX_ConvertComplexToReal( MTX *M )
00969 {
00970   return MTX_static_ConvertComplexTo( M, TRUE );
00971 }
00972 
00973 BOOL MTX_ConvertComplexToImag( MTX *M )
00974 {
00975   return MTX_static_ConvertComplexTo( M, FALSE );
00976 }
00977 
00978 BOOL MTX_static_ConvertComplexTo( MTX *M, BOOL useReal )
00979 {
00980   unsigned i = 0;
00981   unsigned j = 0;
00982   unsigned k = 0;
00983 
00984   if( MTX_isNull( M ) )
00985   {
00986     MTX_ERROR_MSG( "NULL Matrix" );
00987     return FALSE;
00988   }
00989 
00990   // Deal with special case of already real values.
00991   if( useReal )
00992   {
00993     if( M->isReal )
00994       return TRUE; // already real, nothing to do
00995   }
00996 
00997   // Deal with special case of trying to get complex values from a real matrix.
00998   if( !useReal && M->isReal )
00999   {
01000     if( !MTX_Zero(M) )
01001     {
01002       MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
01003       return FALSE;
01004     }
01005     return TRUE;
01006   }
01007 
01008   // allocate the complex column vector pointers
01009   M->data = (double**)malloc( (M->ncols)*sizeof(double*) );
01010   if( !M->data )
01011   {
01012     MTX_ERROR_MSG( "if( !M->data )" );
01013     return FALSE;
01014   }
01015 
01016   for( j = 0; j < M->ncols; j++ )
01017   {
01018     M->data[j] = (double*)malloc( sizeof(double)*(M->nrows) );
01019     if( !(M->data[j]) )
01020     {
01021       // this is most likely to occur if allocating more memory than available
01022       for( k = 0; k < j; k++ ) // delete the real column data already allocated
01023       {
01024         free( M->data[k] );
01025       }
01026       // delete the real column pointer array
01027       free( M->data );
01028       M->data = NULL;
01029       MTX_ERROR_MSG( "malloc returned NULL." );
01030       return FALSE; // note, the matrix M is still valid as a complex matrix
01031     }
01032     // now copy the complex real component of the data to the real data.
01033     for( i = 0; i < M->nrows; i++ )
01034     {
01035       if( useReal )
01036         M->data[j][i] = M->cplx[j][i].re;
01037       else
01038         M->data[j][i] = M->cplx[j][i].im;
01039     }
01040   }
01041 
01042   // free the complex data
01043   for( j = 0; j < M->ncols; j++ )
01044   {
01045     free( M->cplx[j] );
01046   }
01047   // free the array of real pointers
01048   free( M->cplx );
01049   M->cplx = NULL;
01050   M->isReal = TRUE;
01051 
01052   // successfully converted the matrix from complex to real
01053   return TRUE;
01054 }
01055 
01056 
01057 // Extract the real component of matrix M
01058 BOOL MTX_Real( const MTX *M, MTX *Re )
01059 {
01060   unsigned i = 0;
01061   unsigned j = 0;
01062 
01063   if( MTX_isNull( M ) )
01064   {
01065     MTX_ERROR_MSG( "NULL Matrix" );
01066     return FALSE;
01067   }
01068 
01069   if( M->isReal )
01070     return MTX_Copy( M, Re );
01071 
01072   if( !MTX_Malloc( Re, M->nrows, M->ncols, TRUE ) )
01073   {
01074     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
01075     return FALSE;
01076   }
01077 
01078   for( j = 0; j < M->ncols; j++ )
01079   {
01080     for( i = 0; i < M->nrows; i++ )
01081     {
01082       Re->data[j][i] = M->cplx[j][i].re;
01083     }
01084   }
01085   return TRUE;
01086 }
01087 
01088 
01089 BOOL MTX_isReal( MTX *M, BOOL *isReal )
01090 {
01091   if( MTX_isNull( M ) )
01092   {
01093     *isReal = TRUE;
01094     return TRUE; // A null matrix is real by default.
01095   }
01096 
01097   if( M->isReal )
01098   {
01099     *isReal = TRUE;
01100   }
01101   else
01102   {
01103     double maxabs;
01104     MTX imagM;
01105 
01106     MTX_Init(&imagM);
01107 
01108     if( !MTX_Imag(M,&imagM) )
01109     {
01110       MTX_ERROR_MSG( "MTX_Imag returned FALSE." );
01111       return FALSE;
01112     }
01113 
01114     if( !MTX_MaxAbs(&imagM,&maxabs) )
01115     {
01116       MTX_ERROR_MSG( "MTX_MaxAbs returned FALSE." );
01117       return FALSE;
01118     }
01119 
01120     if( maxabs == 0.0 )
01121     {
01122       if( !MTX_ConvertComplexToReal(M) )
01123       {
01124         MTX_ERROR_MSG( "MTX_ConvertComplexToReal returned FALSE." );
01125         return FALSE;
01126       }
01127       *isReal = TRUE;
01128     }
01129     else
01130     {
01131       *isReal = FALSE;
01132     }
01133 
01134     MTX_Free(&imagM);
01135   }
01136 
01137   return TRUE;
01138 }
01139 
01140 BOOL MTX_RealColumn( const MTX *M, const unsigned col, MTX *Re )
01141 {
01142   unsigned i = 0;
01143 
01144   if( MTX_isNull( M ) )
01145   {
01146     MTX_ERROR_MSG( "NULL Matrix" );
01147     return FALSE;
01148   }
01149 
01150   if( col >= M->ncols )
01151   {
01152     MTX_ERROR_MSG( "if( col >= M->ncols )" );
01153     return FALSE;
01154   }
01155 
01156   if( M->isReal )
01157     return MTX_CopyColumn( M, col, Re );
01158 
01159   if( !MTX_Malloc( Re, M->nrows, 1, TRUE ) )
01160   {
01161     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
01162     return FALSE;
01163   }
01164 
01165   for( i = 0; i < M->nrows; i++ )
01166   {
01167     Re->data[0][i] = M->cplx[col][i].re;
01168   }
01169 
01170   return TRUE;
01171 }
01172 
01173 BOOL MTX_Imag( const MTX *M, MTX *Im )
01174 {
01175   unsigned i = 0;
01176   unsigned j = 0;
01177 
01178   if( MTX_isNull( M ) )
01179   {
01180     MTX_ERROR_MSG( "NULL Matrix" );
01181     return FALSE;
01182   }
01183 
01184   if( M->isReal )
01185     return MTX_Calloc( Im, M->nrows, M->ncols, TRUE ); // return a zero matrix
01186 
01187   if( !MTX_Malloc( Im, M->nrows, M->ncols, TRUE ) )
01188   {
01189     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
01190     return FALSE;
01191   }
01192 
01193   for( j = 0; j < M->ncols; j++ )
01194   {
01195     for( i = 0; i < M->nrows; i++ )
01196     {
01197       Im->data[j][i] = M->cplx[j][i].im;
01198     }
01199   }
01200   return TRUE;
01201 }
01202 
01203 BOOL MTX_ImagColumn( const MTX *M, const unsigned col, MTX *Im )
01204 {
01205   unsigned i = 0;
01206 
01207   if( MTX_isNull( M ) )
01208   {
01209     MTX_ERROR_MSG( "NULL Matrix" );
01210     return FALSE;
01211   }
01212 
01213   if( col >= M->ncols )
01214   {
01215     MTX_ERROR_MSG( "if( col >= M->ncols )" );
01216     return FALSE;
01217   }
01218 
01219   if( M->isReal )
01220     return MTX_Calloc( Im, M->nrows, 1, TRUE ); // return a zero column
01221 
01222   if( !MTX_Malloc( Im, M->nrows, 1, TRUE ) )
01223   {
01224     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
01225     return FALSE;
01226   }
01227 
01228   for( i = 0; i < M->nrows; i++ )
01229   {
01230     Im->data[0][i] = M->cplx[col][i].im;
01231   }
01232   return TRUE;
01233 }
01234 
01235 BOOL MTX_Magnitude( const MTX *M, MTX *Magnitude )
01236 {
01237   unsigned i = 0;
01238   unsigned j = 0;
01239   double re;
01240   double im;
01241 
01242   if( MTX_isNull( M ) )
01243   {
01244     MTX_ERROR_MSG( "NULL Matrix" );
01245     return FALSE;
01246   }
01247 
01248   if( M->isReal )
01249   {
01250     if( !MTX_Copy( M, Magnitude ) )
01251     {
01252       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
01253       return FALSE;
01254     }
01255     if( !MTX_Abs( Magnitude ) )
01256     {
01257       MTX_ERROR_MSG( "MTX_Abs returned FALSE." );
01258       return FALSE;
01259     }
01260     return TRUE;
01261   }
01262 
01263   if( !MTX_Malloc( Magnitude, M->nrows, M->ncols, TRUE ) )
01264   {
01265     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
01266     return FALSE;
01267   }
01268 
01269   for( j = 0; j < M->ncols; j++ )
01270   {
01271     for( i = 0; i < M->nrows; i++ )
01272     {
01273       re = M->cplx[j][i].re;
01274       im = M->cplx[j][i].im;
01275       Magnitude->data[j][i] = sqrt( re*re + im*im );
01276     }
01277   }
01278   return TRUE;
01279 }
01280 
01281 BOOL MTX_Phase( const MTX *M, MTX *Phase )
01282 {
01283   unsigned i = 0;
01284   unsigned j = 0;
01285 
01286   if( MTX_isNull( M ) )
01287   {
01288     MTX_ERROR_MSG( "NULL Matrix" );
01289     return FALSE;
01290   }
01291 
01292   if( !MTX_Calloc( Phase, M->nrows, M->ncols, TRUE ) )
01293   {
01294     MTX_ERROR_MSG( "MTX_Calloc returned FALSE." );
01295     return FALSE;
01296   }
01297 
01298   if( M->isReal )
01299   {
01300     for( j = 0; j < M->ncols; j++ )
01301     {
01302       for( i = 0; i < M->nrows; i++ )
01303       {
01304         if( M->data[j][i] < 0.0 )
01305         {
01306           Phase->data[j][i] = PI;
01307         }
01308         else
01309         {
01310           Phase->data[j][i] = 0.0;
01311         }
01312       }
01313     }
01314     return TRUE;
01315   }
01316 
01317   for( j = 0; j < M->ncols; j++ )
01318   {
01319     for( i = 0; i < M->nrows; i++ )
01320     {
01321       Phase->data[j][i] = atan2( M->cplx[j][i].im, M->cplx[j][i].re );
01322     }
01323   }
01324   return TRUE;
01325 }
01326 
01327 
01328 BOOL MTX_Conjugate( MTX *M )
01329 {
01330   unsigned i=0;
01331   unsigned j=0;
01332 
01333   if( MTX_isNull( M ) )
01334   {
01335     MTX_ERROR_MSG( "NULL Matrix" );
01336     return FALSE;
01337   }
01338 
01339   if( M->isReal )
01340     return TRUE;
01341 
01342   for( j = 0; j < M->ncols; j++ )
01343   {
01344     for( i = 0; i < M->nrows; i++ )
01345     {
01346       M->cplx[j][i].im = -M->cplx[j][i].im;
01347     }
01348   }
01349   return TRUE;
01350 }
01351 
01352 BOOL MTX_RemoveColumn( MTX *M, const unsigned col )
01353 {
01354   unsigned j = 0;
01355   unsigned k = 0;
01356   double **dptr = NULL;
01357   stComplex **cptr = NULL;
01358 
01359   if( MTX_isNull( M ) )
01360   {
01361     MTX_ERROR_MSG( "NULL Matrix" );
01362     return FALSE;
01363   }
01364 
01365   if( col >= M->ncols )
01366   {
01367     MTX_ERROR_MSG( "if( col >= M->ncols )" );
01368     return FALSE;
01369   }
01370 
01371   // special case
01372   if( M->ncols == 1 )
01373   {
01374     return MTX_Free( M );
01375   }
01376 
01377   // allocate a new array of column vectors
01378   if( M->isReal )
01379   {
01380     dptr = (double**)malloc( (M->ncols-1)*sizeof(double*) );
01381     if( !dptr )
01382     {
01383       MTX_ERROR_MSG( "malloc returned NULL." );
01384       return FALSE;
01385     }
01386   }
01387   else
01388   {
01389     cptr = (stComplex**)malloc( (M->ncols-1)*sizeof(stComplex*) );
01390     if( !cptr )
01391     {
01392       MTX_ERROR_MSG( "malloc returned NULL." );
01393       return FALSE;
01394     }
01395   }
01396 
01397   // copy the previous array of pointers
01398   // except the one to remove
01399   k = 0;
01400   for( j = 0; j < M->ncols; j++ )
01401   {
01402     if( j != col )
01403     {
01404       if( M->isReal )
01405         dptr[k] = M->data[j];
01406       else
01407         cptr[k] = M->cplx[j];
01408       k++;
01409     }
01410     else
01411     {
01412       if( M->isReal )
01413         free( M->data[j] );
01414       else
01415         free( M->cplx[j] );
01416     }
01417   }
01418 
01419   // free the old column array, and copy the new
01420   if( M->isReal )
01421   {
01422     free( M->data );
01423     M->data = dptr;
01424   }
01425   else
01426   {
01427     free( M->cplx );
01428     M->cplx = cptr;
01429   }
01430   M->ncols--;
01431 
01432   return TRUE;
01433 }
01434 
01435 BOOL MTX_RemoveColumnsAfterIndex( MTX *dst, const unsigned col )
01436 {
01437   unsigned ncols;
01438   unsigned j = 0;
01439   double **dptr = NULL;
01440   stComplex **cptr = NULL;
01441 
01442   if( MTX_isNull( dst ) )
01443   {
01444     MTX_ERROR_MSG( "NULL Matrix" );
01445     return FALSE;
01446   }
01447 
01448   if( col >= dst->ncols )
01449   {
01450     MTX_ERROR_MSG( "if( col >= dst->ncols )" );
01451     return FALSE;
01452   }
01453 
01454   // special case
01455   if( dst->ncols == 1 )
01456   {
01457     return MTX_Free( dst );
01458   }
01459 
01460   ncols = col+1;
01461 
01462   // allocate a new array of column vectors
01463   if( dst->isReal )
01464   {
01465     dptr = (double**)malloc( ncols*sizeof(double*) );
01466     if( !dptr )
01467     {
01468       MTX_ERROR_MSG( "malloc returned NULL." );
01469       return FALSE;
01470     }
01471   }
01472   else
01473   {
01474     cptr = (stComplex**)malloc( ncols*sizeof(stComplex*) );
01475     if( !cptr )
01476     {
01477       MTX_ERROR_MSG( "malloc returned NULL." );
01478       return FALSE;
01479     }
01480   }
01481 
01482   for( j = 0; j < dst->ncols; j++ )
01483   {
01484     if( j < ncols )
01485     {
01486       if( dst->isReal )
01487         dptr[j] = dst->data[j];
01488       else
01489         cptr[j] = dst->cplx[j];
01490     }
01491     else
01492     {
01493       if( dst->isReal )
01494         free( dst->data[j] );
01495       else
01496         free( dst->cplx[j] );
01497     }
01498   }
01499 
01500   // free the old column array, and copy the new
01501   if( dst->isReal )
01502   {
01503     free( dst->data );
01504     dst->data = dptr;
01505   }
01506   else
01507   {
01508     free( dst->cplx );
01509     dst->cplx = cptr;
01510   }
01511   dst->ncols = ncols;
01512 
01513   return TRUE;
01514 }
01515 
01516 
01517 BOOL MTX_InsertColumn( MTX *dst, const MTX *src, const unsigned dst_col, const unsigned src_col )
01518 {
01519   unsigned i = 0;
01520   unsigned j = 0;
01521   unsigned k = 0;
01522   unsigned m = 0;
01523   double **dptr = NULL;
01524   stComplex **cptr = NULL;
01525 
01526   if( MTX_isNull( dst ) )
01527   {
01528     MTX_ERROR_MSG( "NULL Matrix" );
01529     return FALSE;
01530   }
01531 
01532   if( MTX_isNull( src ) )
01533   {
01534     MTX_ERROR_MSG( "NULL Matrix" );
01535     return FALSE;
01536   }
01537 
01538   if( dst->nrows != src->nrows )
01539   {
01540     MTX_ERROR_MSG( "if( dst->nrows != src->nrows )" );
01541     return FALSE;
01542   }
01543 
01544   // note the missing '=' here, a column can be inserted at the end (i.e. AddColumn )
01545   if( dst_col > dst->ncols )
01546   {
01547     MTX_ERROR_MSG( "if( dst_col > dst->ncols )" );
01548     return FALSE;
01549   }
01550 
01551   if( src_col >= src->ncols )
01552   {
01553     MTX_ERROR_MSG( "if( src_col >= src->ncols )" );
01554     return FALSE;
01555   }
01556 
01557   if( !src->isReal && dst->isReal )
01558   {
01559     // convert the destination matrix to complex
01560     if( !MTX_ConvertRealToComplex( dst ) )
01561     {
01562       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
01563       return FALSE;
01564     }
01565   }
01566 
01567   // allocate a new array of column vectors
01568   if( dst->isReal )
01569   {
01570     dptr = (double**)malloc( (dst->ncols+1)*sizeof(double*) );
01571     if( !dptr )
01572     {
01573       MTX_ERROR_MSG( "malloc returned NULL." );
01574       return FALSE;
01575     }
01576   }
01577   else
01578   {
01579     cptr = (stComplex**)malloc( (dst->ncols+1)*sizeof(stComplex*) );
01580     if( !cptr )
01581     {
01582       MTX_ERROR_MSG( "malloc returned NULL." );
01583       return FALSE;
01584     }
01585   }
01586 
01587   // copy the previous array of pointers
01588   // and add the new column
01589   k = 0;
01590   for( j = 0; j <= dst->ncols; j++ )
01591   {
01592     if( j == dst_col )
01593     {
01594       // allocate a new column vector
01595       if( dst->isReal )
01596         dptr[k] = (double*)malloc( dst->nrows*sizeof(double) );
01597       else
01598         cptr[k] = (stComplex*)malloc( dst->nrows*sizeof(stComplex) );
01599       if( dst->isReal )
01600       {
01601         if( !dptr[k] )
01602         {
01603           // this is most likely to occur if allocating more memory than available
01604           for( m = 0; m < k; m++ )
01605           {
01606             free( dptr[m] );
01607           }
01608 
01609           MTX_ERROR_MSG( "malloc returned NULL." );
01610           free( dptr );
01611           return FALSE;
01612         }
01613       }
01614       else
01615       {
01616         if( !cptr[k] )
01617         {
01618           // this is most likely to occur if allocating more memory than available
01619           for( m = 0; m < k; m++ )
01620           {
01621             free( cptr[m] );
01622           }
01623           MTX_ERROR_MSG( "malloc returned NULL." );
01624           free( cptr );
01625           return FALSE;
01626         }
01627       }
01628 
01629       // copy the src column vector
01630       for( i = 0; i < dst->nrows; i++ )
01631       {
01632         if( dst->isReal )
01633         {
01634           dptr[k][i] = src->data[src_col][i];
01635         }
01636         else
01637         {
01638           if( src->isReal )
01639           {
01640             cptr[k][i].re = src->data[src_col][i];
01641             cptr[k][i].im = 0;
01642           }
01643           else
01644           {
01645             cptr[k][i] = src->cplx[src_col][i];
01646           }
01647         }
01648       }
01649       // copy the data that was at the insertion index
01650       // unless this is the after the last column
01651       if( j != dst->ncols )
01652       {
01653         k++;
01654         if( dst->isReal )
01655           dptr[k] = dst->data[j];
01656         else
01657           cptr[k] = dst->cplx[j];
01658       }
01659     }
01660     else
01661     {
01662       if( j != dst->ncols )
01663       {
01664         if( dst->isReal )
01665           dptr[k] = dst->data[j];
01666         else
01667           cptr[k] = dst->cplx[j];
01668       }
01669     }
01670     k++;
01671   }
01672 
01673   // free the old column array, and copy the new
01674   if( dst->isReal )
01675   {
01676     free( dst->data );
01677     dst->data = dptr;
01678   }
01679   else
01680   {
01681     free( dst->cplx );
01682     dst->cplx = cptr;
01683   }
01684   dst->ncols++;
01685 
01686   return TRUE;
01687 }
01688 
01689 BOOL MTX_AddColumn( MTX *dst, const MTX *src, const unsigned src_col )
01690 {
01691   return MTX_InsertColumn( dst, src, dst->ncols, src_col );
01692 }
01693 
01694 BOOL MTX_Concatonate( MTX *dst, const MTX *src )
01695 {
01696   unsigned i = 0;
01697   unsigned j = 0;
01698   unsigned ncols;
01699   unsigned m = 0;
01700   double **dptr = NULL;
01701   stComplex **cptr = NULL;
01702 
01703   if( dst == NULL )
01704   {
01705     MTX_ERROR_MSG( "dst is a NULL Matrix" );
01706     return FALSE;
01707   }
01708 
01709   if( MTX_isNull( src ) )
01710   {
01711     MTX_ERROR_MSG( "NULL Matrix" );
01712     return FALSE;
01713   }
01714 
01715   if( dst->nrows == 0 && dst->ncols == 0 )
01716   {
01717     return MTX_Copy( src, dst );
01718   }
01719   else if( dst->nrows != src->nrows )
01720   {
01721     MTX_ERROR_MSG( "if( dst->nrows != src->nrows )" );
01722     return FALSE;
01723   }
01724 
01725   ncols = dst->ncols+src->ncols;
01726 
01727   if( dst->isReal && !src->isReal )
01728   {
01729     // Convert dst to complex
01730     if( !MTX_ConvertRealToComplex( dst ) )
01731     {
01732       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
01733       return FALSE;
01734     }
01735   }
01736 
01737   // allocate a new array of column vectors
01738   if( dst->isReal )
01739   {
01740     dptr = (double**)malloc( ncols*sizeof(double*) );
01741     if( !dptr )
01742     {
01743       MTX_ERROR_MSG( "malloc returned NULL." );
01744       return FALSE;
01745     }
01746   }
01747   else
01748   {
01749     cptr = (stComplex**)malloc( ncols*sizeof(stComplex*) );
01750     if( !cptr )
01751     {
01752       MTX_ERROR_MSG( "malloc returned NULL." );
01753       return FALSE;
01754     }
01755   }
01756 
01757   for( j = 0; j < ncols; j++ )
01758   {
01759     if( j < dst->ncols )
01760     {
01761       // keep the original data
01762       if( dst->isReal )
01763         dptr[j] = dst->data[j];
01764       else
01765         cptr[j] = dst->cplx[j];
01766     }
01767     else
01768     {
01769       // copy the new data
01770       if( dst->isReal )
01771         dptr[j] = (double*)malloc( dst->nrows*sizeof(double) );
01772       else
01773         cptr[j] = (stComplex*)malloc( dst->nrows*sizeof(stComplex) );
01774       if( dst->isReal )
01775       {
01776         if( !(dptr[j]) )
01777         {
01778           // this is most likely to occur if allocating more memory than available
01779           for( m = 0; m < j; m++ )
01780           {
01781             free( dptr[m] );
01782           }
01783 
01784           MTX_ERROR_MSG( "malloc returned NULL." );
01785           free( dptr );
01786           return FALSE;
01787         }
01788       }
01789       else
01790       {
01791         if( !(cptr[j]) )
01792         {
01793           // this is most likely to occur if allocating more memory than available
01794           for( m = 0; m < j; m++ )
01795           {
01796             free( cptr[m] );
01797           }
01798           free( cptr );
01799           MTX_ERROR_MSG( "malloc returned NULL." );
01800           return FALSE;
01801         }
01802       }
01803       // copy the src column vector
01804       for( i = 0; i < dst->nrows; i++ )
01805       {
01806         if( dst->isReal )
01807         {
01808           dptr[j][i] = src->data[j-dst->ncols][i];
01809         }
01810         else
01811         {
01812           if( src->isReal )
01813           {
01814             cptr[j][i].re = src->data[j-dst->ncols][i];
01815             cptr[j][i].im = 0;
01816           }
01817           else
01818           {
01819             cptr[j][i] = src->cplx[j-dst->ncols][i];
01820           }
01821         }
01822       }
01823     }
01824   }
01825 
01826   // free the old column array, and copy the new
01827   if( dst->isReal )
01828   {
01829     free( dst->data );
01830     dst->data = dptr;
01831   }
01832   else
01833   {
01834     free( dst->cplx );
01835     dst->cplx = cptr;
01836   }
01837   dst->ncols = ncols;
01838 
01839   return TRUE;
01840 }
01841 
01842 
01843 
01844 // A becomes A|0|0|0|.. etc
01845 BOOL MTX_AddZeroValuedColumns( MTX *dst, const unsigned nr_new_cols )
01846 {
01847   unsigned j = 0;
01848   unsigned ncols;
01849   unsigned m = 0;
01850   double **dptr = NULL;
01851   stComplex **cptr = NULL;
01852 
01853   if( MTX_isNull( dst ) )
01854   {
01855     MTX_ERROR_MSG( "NULL Matrix" );
01856     return FALSE;
01857   }
01858 
01859   ncols = dst->ncols + nr_new_cols;
01860 
01861   // allocate a new array of column vectors
01862   if( dst->isReal )
01863   {
01864     dptr = (double**)malloc( ncols*sizeof(double*) );
01865     if( !dptr )
01866     {
01867       MTX_ERROR_MSG( "malloc returned NULL." );
01868       return FALSE;
01869     }
01870   }
01871   else
01872   {
01873     cptr = (stComplex**)malloc( ncols*sizeof(stComplex*) );
01874     if( !cptr )
01875     {
01876       MTX_ERROR_MSG( "malloc returned NULL." );
01877       return FALSE;
01878     }
01879   }
01880 
01881   for( j = 0; j < ncols; j++ )
01882   {
01883     if( j < dst->ncols )
01884     {
01885       // keep the original data
01886       if( dst->isReal )
01887         dptr[j] = dst->data[j];
01888       else
01889         cptr[j] = dst->cplx[j];
01890     }
01891     else
01892     {
01893       // copy the new data
01894       if( dst->isReal )
01895       {
01896         dptr[j] = (double*)calloc( dst->nrows, sizeof(double) );
01897       }
01898       else
01899       {
01900         cptr[j] = (stComplex*)calloc( dst->nrows, sizeof(stComplex) );
01901       }
01902       if( dst->isReal )
01903       {
01904         if( !(dptr[j]) )
01905         {
01906           // this is most likely to occur if allocating more memory than available
01907           for( m = 0; m < j; m++ )
01908           {
01909             free( dptr[m] );
01910           }
01911           free( dptr );
01912 
01913           MTX_ERROR_MSG( "calloc returned NULL." );
01914           return FALSE;
01915         }
01916       }
01917       else
01918       {
01919         if( !(cptr[j]) )
01920         {
01921           // this is most likely to occur if allocating more memory than available
01922           for( m = 0; m < j; m++ )
01923           {
01924             free( cptr[m] );
01925           }
01926           free( cptr );
01927 
01928           MTX_ERROR_MSG( "calloc returned NULL." );
01929           return FALSE;
01930         }
01931       }
01932 
01933     }
01934   }
01935 
01936   // free the old column array, and copy the new
01937   if( dst->isReal )
01938   {
01939     free( dst->data );
01940     dst->data = dptr;
01941   }
01942   else
01943   {
01944     free( dst->cplx );
01945     dst->cplx = cptr;
01946   }
01947   dst->ncols = ncols;
01948 
01949   return TRUE;
01950 }
01951 
01952 BOOL MTX_Redim( MTX *dst, const unsigned nrows, const unsigned ncols )
01953 {
01954   unsigned j = 0;
01955   unsigned nc;
01956   unsigned nr;
01957   MTX copy;
01958   const BOOL isReal = dst->isReal;
01959 
01960   MTX_Init( &copy );
01961 
01962   if( !dst )
01963   {
01964     MTX_ERROR_MSG( "dst is a NULL pointer." );
01965     return FALSE;
01966   }
01967 
01968   if( nrows == 0 || ncols == 0 )
01969   {
01970     MTX_ERROR_MSG( "if( nrows == 0 || ncols == 0 )" );
01971     return FALSE;
01972   }
01973 
01974   // special case - calling Redim with a null matrix
01975   if( dst->ncols == 0 && dst->nrows == 0 )
01976     return MTX_Calloc( dst, nrows, ncols, dst->isReal );
01977 
01978 
01979   // check same size
01980   if( dst->nrows == nrows && dst->ncols == ncols )
01981     return TRUE;
01982 
01983   // special cases, adding or removing columns
01984   if( dst->nrows == nrows )
01985   {
01986     if( ncols < dst->ncols )
01987     {
01988       if( MTX_RemoveColumnsAfterIndex( dst, ncols-1 ) == FALSE )
01989       {
01990         MTX_ERROR_MSG( "MTX_RemoveColumnsAfterIndex returned FALSE." );
01991         return FALSE;
01992       }
01993 
01994       return TRUE;
01995     }
01996     else
01997     {
01998       // Add the extra columns
01999       if( !MTX_AddZeroValuedColumns( dst, ncols-dst->ncols ) )
02000       {
02001         MTX_ERROR_MSG( "MTX_AddZeroValuedColumns returned FALSE." );
02002         return FALSE;
02003       }
02004       return TRUE;
02005     }
02006   }
02007 
02008   // make a copy of the previous data
02009   if( !MTX_Malloc( &copy, dst->nrows, dst->ncols, isReal ) )
02010   {
02011     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
02012     return FALSE;
02013   }
02014   if( !MTX_Copy( dst, &copy ) )
02015   {
02016     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
02017     MTX_Free( &copy );
02018     return FALSE;
02019   }
02020 
02021   // must reallocate the matrix
02022   MTX_Free( dst );
02023 
02024   if( !MTX_Calloc( dst, nrows, ncols, isReal ) )
02025   {
02026     MTX_ERROR_MSG( "MTX_Calloc returned FALSE." );
02027     MTX_Free( &copy );
02028     return FALSE;
02029   }
02030 
02031   // Copy the previous data.
02032   if( dst->ncols < copy.ncols )
02033     nc = dst->ncols;
02034   else
02035     nc = copy.ncols;
02036 
02037   if( dst->nrows < copy.nrows )
02038     nr = dst->nrows;
02039   else
02040     nr = copy.nrows;
02041 
02042   if( isReal )
02043   {
02044     for( j = 0; j < nc; j++ )
02045     {
02046       memcpy( dst->data[j], copy.data[j], sizeof(double)*nr );
02047     }
02048   }
02049   else
02050   {
02051     for( j = 0; j < nc; j++ )
02052     {
02053       memcpy( dst->cplx[j], copy.cplx[j], sizeof(stComplex)*nr );
02054     }
02055   }
02056   MTX_Free( &copy );
02057   return TRUE;
02058 }
02059 
02060 BOOL MTX_Resize( MTX *dst, const unsigned nrows, const unsigned ncols, const BOOL isReal )
02061 {
02062   if( !dst )
02063   {
02064     MTX_ERROR_MSG( "dst is a NULL pointer." );
02065     return FALSE;
02066   }
02067 
02068   if( nrows == 0 || ncols == 0 )
02069   {
02070     MTX_ERROR_MSG( "if( nrows == 0 || ncols == 0 )" );
02071     return FALSE;
02072   }
02073 
02074   // MTX_Calloc is smart. It only re-allocates memory if it needs to
02075   // and always sets the data to zero.
02076   if( !MTX_Calloc( dst, nrows, ncols, isReal ) )
02077   {
02078     MTX_ERROR_MSG( "MTX_Calloc returned FALSE." );
02079     return FALSE;
02080   }
02081 
02082   return TRUE;
02083 }
02084 
02085 BOOL MTX_Copy( const MTX *src, MTX *dst )
02086 {
02087   unsigned j = 0;
02088 
02089   if( MTX_isNull( src ) )
02090   {
02091     MTX_ERROR_MSG( "NULL Matrix" );
02092     return FALSE;
02093   }
02094   if( !dst )
02095   {
02096     MTX_ERROR_MSG( "dst is a NULL pointer." );
02097     return FALSE;
02098   }
02099 
02100   // both must be real or both must be complex
02101   if( dst->isReal != src->isReal )
02102   {
02103     if( !MTX_Resize( dst, src->nrows, src->ncols, src->isReal ) )
02104     {
02105       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02106       return FALSE;
02107     }
02108   }
02109 
02110   if( !MTX_isSameSize( src, dst ) )
02111   {
02112     if( !MTX_Resize( dst, src->nrows, src->ncols, src->isReal ) )
02113     {
02114       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02115       return FALSE;
02116     }
02117   }
02118   
02119 
02120   if( src->isReal )
02121   {  
02122     for( j = 0; j < dst->ncols; j++ )
02123     {
02124       memcpy( dst->data[j], src->data[j], sizeof(double)*(dst->nrows) );
02125     }
02126   }
02127   else
02128   {
02129     for( j = 0; j < dst->ncols; j++ )
02130     {
02131       memcpy( dst->cplx[j], src->cplx[j], sizeof(stComplex)*(dst->nrows) );
02132     }
02133   }
02134   
02135   return TRUE;
02136 }
02137 
02138 BOOL MTX_CopyIntoColumnWiseVector( const MTX *src, MTX *dst )
02139 {
02140   unsigned j = 0;
02141 
02142   if( MTX_isNull( src ) )
02143   {
02144     MTX_ERROR_MSG( "NULL Matrix" );
02145     return FALSE;
02146   }
02147   if( !dst )
02148   {
02149     MTX_ERROR_MSG( "dst is a NULL pointer." );
02150     return FALSE;
02151   }
02152 
02153   // both must be real or both must be complex
02154   if( dst->isReal != src->isReal )
02155   {
02156     if( !MTX_Resize( dst, src->nrows*src->ncols, 1, src->isReal ) )
02157     {
02158       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02159       return FALSE;
02160     }
02161   }
02162 
02163   if( dst->nrows != src->nrows*src->ncols )
02164   {
02165     if( !MTX_Resize( dst, src->nrows*src->ncols, 1, src->isReal ) )
02166     {
02167       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02168       return FALSE;
02169     }
02170   }
02171 
02172   if( src->isReal )
02173   {
02174     for( j = 0; j < src->ncols; j++ )
02175     {
02176       memcpy( &(dst->data[0][j*src->nrows]), src->data[j], sizeof(double)*src->nrows );
02177     }
02178   }
02179   else
02180   {
02181     for( j = 0; j < src->ncols; j++ )
02182     {
02183       memcpy( &(dst->cplx[0][j*src->nrows]), src->cplx[j], sizeof(stComplex)*src->nrows );
02184     }
02185   }
02186 
02187   return TRUE;
02188 }
02189 
02190 
02191 BOOL MTX_SetFromStaticMatrix( MTX *dst, const double mat[], const unsigned nrows, const unsigned ncols )
02192 {
02193   unsigned i = 0;
02194   unsigned j = 0;
02195 
02196   if( !dst )
02197   {
02198     MTX_ERROR_MSG( "dst is a NULL pointer." );
02199     return FALSE;
02200   }
02201 
02202   if( !mat )
02203   {
02204     MTX_ERROR_MSG( "mat is a NULL pointer." );
02205     return FALSE;
02206   }
02207 
02208   if( dst->nrows != nrows || dst->ncols != ncols )
02209   {
02210     if( !MTX_Resize( dst, nrows, ncols, TRUE ) )
02211     {
02212       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02213       return FALSE;
02214     }
02215   }
02216 
02217   for( j = 0; j < ncols; j++ )
02218     for( i = 0; i < nrows; i++ )
02219       dst->data[j][i] = mat[i*ncols + j];
02220 
02221   return TRUE;
02222 }
02223 
02224 BOOL MTX_CopyColumn( const MTX *src, const unsigned col, MTX *dst )
02225 {
02226   if( MTX_isNull( src ) )
02227   {
02228     MTX_ERROR_MSG( "NULL Matrix" );
02229     return FALSE;
02230   }
02231   if( !dst )
02232   {
02233     MTX_ERROR_MSG( "dst is a NULL pointer." );
02234     return FALSE;
02235   }
02236   if( col >= src->ncols )
02237   {
02238     MTX_ERROR_MSG( "if( col >= src->ncols )" );
02239     return FALSE;
02240   }
02241 
02242   if( src->isReal != dst->isReal )
02243   {
02244     if( !MTX_Malloc( dst, src->nrows, 1, src->isReal ) )
02245     {
02246       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02247       return FALSE;
02248     }
02249   }
02250   else if( dst->nrows != src->nrows || dst->ncols != 1 )
02251   {
02252     if( !MTX_Malloc( dst, src->nrows, 1, src->isReal ) )
02253     {
02254       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02255       return FALSE;
02256     }
02257   }
02258 
02259   if( src->isReal )
02260   {
02261     memcpy( dst->data[0], src->data[col], sizeof(double)*(dst->nrows) );
02262   }
02263   else
02264   {
02265     memcpy( dst->cplx[0], src->cplx[col], sizeof(stComplex)*(dst->nrows) );
02266   }
02267 
02268   return TRUE;
02269 }
02270 
02271 BOOL MTX_CopyRow( const MTX *src, const unsigned row, MTX *dst )
02272 {
02273   unsigned i = 0;
02274 
02275   if( MTX_isNull( src ) )
02276   {
02277     MTX_ERROR_MSG( "NULL Matrix" );
02278     return FALSE;
02279   }
02280   if( !dst )
02281   {
02282     MTX_ERROR_MSG( "dst is a NULL pointer." );
02283     return FALSE;
02284   }
02285   if( row >= src->nrows )
02286   {
02287     MTX_ERROR_MSG( "if( row >= src->nrows )" );
02288     return FALSE;
02289   }
02290 
02291   if( dst->nrows != 1 || dst->ncols != src->ncols )
02292   {
02293     if( !MTX_Resize( dst, 1, src->ncols, src->isReal ) )
02294     {
02295       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02296       return FALSE;
02297     }
02298   }
02299 
02300   for( i = 0; i < dst->ncols; i++ )
02301   {
02302     if( src->isReal )
02303       dst->data[i][0] = src->data[i][row];
02304     else
02305       dst->cplx[i][0] = src->cplx[i][row];
02306   }
02307 
02308   return TRUE;
02309 }
02310 
02311 BOOL MTX_CopyRowIntoAColumnMatrix( const MTX *src, const unsigned row, MTX *dst )
02312 {
02313   unsigned i = 0;
02314 
02315   if( MTX_isNull( src ) )
02316   {
02317     MTX_ERROR_MSG( "NULL Matrix" );
02318     return FALSE;
02319   }
02320   if( !dst )
02321   {
02322     MTX_ERROR_MSG( "dst is a NULL pointer." );
02323     return FALSE;
02324   }
02325   if( row >= src->nrows )
02326   {
02327     MTX_ERROR_MSG( "if( row >= src->nrows )" );
02328     return FALSE;
02329   }
02330 
02331   if( dst->nrows != src->ncols || dst->ncols != 1 )
02332   {
02333     if( !MTX_Resize( dst, src->ncols, 1, src->isReal ) )
02334     {
02335       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02336       return FALSE;
02337     }
02338   }
02339 
02340   for( i = 0; i < dst->nrows; i++ )
02341   {
02342     if( src->isReal )
02343       dst->data[0][i] = src->data[i][row];
02344     else
02345       dst->cplx[0][i] = src->cplx[i][row];
02346   }
02347 
02348   return TRUE;
02349 }
02350 
02351 BOOL MTX_InsertSubMatrix( MTX *dst, const MTX *src, const unsigned dst_row, const unsigned dst_col )
02352 {
02353   unsigned i = 0;
02354   unsigned j = 0;
02355 
02356   if( !dst )
02357   {
02358     MTX_ERROR_MSG( "dst is a NULL pointer." );
02359     return FALSE;
02360   }
02361 
02362   if( MTX_isNull( src ) )
02363   {
02364     MTX_ERROR_MSG( "NULL Matrix" );
02365     return FALSE;
02366   }
02367 
02368   // check that the submatrix doesn't exceed the bounds of the matrix
02369   if( dst_row + src->nrows > dst->nrows )
02370   {
02371     MTX_ERROR_MSG( "if( dst_row + src->nrows > dst->nrows )" );
02372     return FALSE;
02373   }
02374   if( dst_col + src->ncols > dst->ncols )
02375   {
02376     MTX_ERROR_MSG( "if( dst_col + src->ncols > dst->ncols )" );
02377     return FALSE;
02378   }
02379 
02380   if( !src->isReal && dst->isReal )
02381   {
02382     // convert the matrix to complex if the src matrix is complex
02383     if( !MTX_ConvertRealToComplex( dst ) )
02384     {
02385       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
02386       return FALSE;
02387     }
02388   }
02389 
02390   // insert the submatrix
02391   if( dst->isReal )
02392   {
02393     for( j = 0; j < src->ncols; j++ )
02394     {
02395       memcpy( &(dst->data[dst_col+j][dst_row]), src->data[j], sizeof(double)*src->nrows );
02396     }
02397   }
02398   else
02399   {
02400     if( src->isReal )
02401     {
02402       for( j = 0; j < src->ncols; j++ )
02403       {
02404         for( i = 0; i < src->nrows; i++ )
02405         {
02406           dst->cplx[dst_col+j][dst_row+i].re = src->data[j][i];
02407           dst->cplx[dst_col+j][dst_row+i].im = 0.0;
02408         }
02409       }
02410     }
02411     else
02412     {
02413       for( j = 0; j < src->ncols; j++ )
02414       {
02415         memcpy( &(dst->cplx[dst_col+j][dst_row]), src->cplx[j], sizeof(stComplex)*src->nrows );
02416       }
02417     }
02418   }
02419   return TRUE;
02420 }
02421 
02422 BOOL MTX_ExtractSubMatrix( 
02423   const MTX* src,          //!< The source matrix.                        
02424   MTX* dst,                //!< The destination matrix to contain the submatrix.
02425   const unsigned from_row, //!< The zero-based index for the from row.
02426   const unsigned from_col, //!< The zero-based index for the from column.
02427   const unsigned to_row,   //!< The zero-based index for the to row.
02428   const unsigned to_col    //!< The zero-based index for the to column.
02429   )
02430 {
02431   unsigned i;
02432   unsigned j;
02433   unsigned k;
02434   unsigned m;
02435 
02436   if( src == NULL )
02437   {
02438     MTX_ERROR_MSG( "NULL source matrix" );
02439     return FALSE;
02440   }
02441   if( dst == NULL )
02442   {
02443     MTX_ERROR_MSG( "NULL destination matrix" );
02444     return FALSE;
02445   }
02446   if( MTX_isNull( src ) )
02447   {
02448     MTX_ERROR_MSG( "NULL source matrix" );
02449     return FALSE;
02450   }
02451 
02452   if( to_row - from_row < 0 )
02453   {
02454     MTX_ERROR_MSG( "The destination matrix has invalid dimension. to_row - from_row < 0" );
02455     return FALSE;
02456   }
02457   if( to_col - from_col < 0 )
02458   {
02459     MTX_ERROR_MSG( "The destination matrix has invalid dimension. to_col - from_col < 0" );
02460     return FALSE;
02461   }
02462 
02463   if( from_row >= src->nrows )
02464   {
02465     MTX_ERROR_MSG( "from_row > number of source rows" );
02466     return FALSE;
02467   }
02468   if( from_col >= src->ncols )
02469   {
02470     MTX_ERROR_MSG( "from_col > number of source columns" );
02471     return FALSE;
02472   }
02473   if( to_row >= src->nrows )
02474   {
02475     MTX_ERROR_MSG( "to_row > number of source rows" );
02476     return FALSE;
02477   }
02478   if( to_col >= src->ncols )
02479   {
02480     MTX_ERROR_MSG( "to_col > number of source columns" );
02481     return FALSE;
02482   }
02483 
02484   if( !MTX_Malloc( dst, to_row-from_row+1, to_col-from_col+1, src->isReal ) )
02485   {
02486     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
02487     return FALSE;
02488   }
02489 
02490   m = 0;
02491   for( j = from_col; j <= to_col; j++ )
02492   {
02493     k = 0;
02494     for( i = from_row; i <= to_row; i++ )
02495     {
02496       if( src->isReal )
02497       {
02498         dst->data[m][k] = src->data[j][i];
02499       }
02500       else
02501       {
02502         dst->cplx[m][k].re = src->cplx[j][i].re;
02503         dst->cplx[m][k].im = src->cplx[j][i].im;
02504       }
02505       k++;
02506     }
02507     m++;
02508   }
02509 
02510   return TRUE;
02511 }
02512 
02513 BOOL MTX_Zero( MTX *dst )
02514 {
02515   unsigned j = 0;
02516 
02517   if( MTX_isNull( dst ) )
02518   {
02519     MTX_ERROR_MSG( "NULL Matrix" );
02520     return FALSE;
02521   }
02522 
02523   for( j = 0; j < dst->ncols; j++ )
02524   {
02525     if( dst->isReal )
02526     {
02527       memset( dst->data[j], 0, sizeof(double)*dst->nrows );
02528     }
02529     else
02530     {
02531       memset( dst->cplx[j], 0, sizeof(stComplex)*dst->nrows );
02532     }
02533   }
02534   return TRUE;
02535 }
02536 
02537 BOOL MTX_ZeroColumn( MTX *dst, const unsigned col )
02538 {
02539   if( MTX_isNull( dst ) )
02540   {
02541     MTX_ERROR_MSG( "NULL Matrix" );
02542     return FALSE;
02543   }
02544 
02545   if( col >= dst->ncols )
02546   {
02547     MTX_ERROR_MSG( "if( col >= dst->ncols )" );
02548     return FALSE;
02549   }
02550 
02551   if( dst->isReal )
02552   {
02553     memset( dst->data[col], 0, sizeof(double)*dst->nrows );
02554   }
02555   else
02556   {
02557     memset( dst->cplx[col], 0, sizeof(stComplex)*dst->nrows );
02558   }
02559 
02560   return TRUE;
02561 }
02562 
02563 BOOL MTX_ZeroRow( MTX *dst, const unsigned row )
02564 {
02565   return MTX_FillRow( dst, row, 0.0 );
02566 }
02567 
02568 BOOL MTX_Fill( MTX *dst, const double value )
02569 {
02570   unsigned i = 0;
02571   unsigned j = 0;
02572 
02573   if( MTX_isNull( dst ) )
02574   {
02575     MTX_ERROR_MSG( "NULL Matrix" );
02576     return FALSE;
02577   }
02578 
02579   // use memcpy after the first column is set for efficiency and speed.
02580   if( dst->isReal )
02581   {
02582     j = 0;
02583     for( i = 0; i < dst->nrows; i++ )
02584     {
02585       dst->data[j][i] = value;          
02586     }
02587     for( j = 1; j < dst->ncols; j++ )
02588     {
02589       memcpy( dst->data[j], dst->data[j-1], sizeof(double)*dst->nrows );
02590     }
02591   }
02592   else
02593   {
02594     j = 0;
02595     for( i = 0; i < dst->nrows; i++ )
02596     {
02597       dst->cplx[j][i].re = value;
02598       dst->cplx[j][i].im = 0.0;
02599     }
02600     for( j = 1; j < dst->ncols; j++ )
02601     {
02602       memcpy( dst->cplx[j], dst->cplx[j-1], sizeof(stComplex)*dst->nrows );
02603     }
02604   }
02605 
02606   return TRUE;
02607 }
02608 
02609 BOOL MTX_FillComplex( MTX *dst, const double re, const double im )
02610 {
02611   unsigned i = 0;
02612   unsigned j = 0;
02613 
02614   if( MTX_isNull( dst ) )
02615   {
02616     MTX_ERROR_MSG( "NULL Matrix" );
02617     return FALSE;
02618   }
02619 
02620   if( dst->isReal )
02621   {
02622     if( !MTX_ConvertRealToComplex( dst ) )
02623     {
02624       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
02625       return FALSE;
02626     }
02627   }
02628 
02629   for( j = 0; j < dst->ncols; j++ )
02630   {
02631     if( j == 0 )
02632     {
02633       for( i = 0; i < dst->nrows; i++ )
02634       {
02635         dst->cplx[j][i].re = re;
02636         dst->cplx[j][i].im = im;
02637       }
02638     }
02639     else
02640     {
02641       memcpy( dst->cplx[j], dst->cplx[j-1], sizeof(stComplex)*dst->nrows );
02642     }
02643   }
02644   return TRUE;
02645 }
02646 
02647 BOOL MTX_FillColumn( MTX *dst, const unsigned col, const double value )
02648 {
02649   unsigned i = 0;  
02650 
02651   if( MTX_isNull( dst ) )
02652   {
02653     MTX_ERROR_MSG( "NULL Matrix" );
02654     return FALSE;
02655   }
02656 
02657   if( col >= dst->ncols )
02658   {
02659     MTX_ERROR_MSG( "if( col >= dst->ncols )" );
02660     return FALSE;
02661   }
02662 
02663   if( dst->isReal )
02664   {
02665     for( i = 0; i < dst->nrows; i++ )
02666     {
02667       dst->data[col][i] = value;
02668     }
02669   }
02670   else
02671   {
02672     for( i = 0; i < dst->nrows; i++ )
02673     {
02674       dst->cplx[col][i].re = value;
02675       dst->cplx[col][i].im = 0;
02676     }
02677   }
02678 
02679   return TRUE;
02680 }
02681 
02682 BOOL MTX_FillColumnComplex( MTX *dst, const unsigned col, const double re, const double im )
02683 {
02684   unsigned i = 0;  
02685 
02686   if( MTX_isNull( dst ) )
02687   {
02688     MTX_ERROR_MSG( "NULL Matrix" );
02689     return FALSE;
02690   }
02691 
02692   if( col >= dst->ncols )
02693   {
02694     MTX_ERROR_MSG( "if( col >= dst->ncols )" );
02695     return FALSE;
02696   }
02697 
02698   if( dst->isReal )
02699   {
02700     if( !MTX_ConvertRealToComplex( dst ) )
02701     {
02702       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
02703       return FALSE;
02704     }
02705   }
02706 
02707   for( i = 0; i < dst->nrows; i++ )
02708   {
02709     dst->cplx[col][i].re = re;
02710     dst->cplx[col][i].im = im;
02711   }
02712 
02713   return TRUE;
02714 }
02715 
02716 BOOL MTX_FillRow( MTX *dst, const unsigned row, const double value )
02717 {
02718   unsigned j = 0;
02719 
02720   if( MTX_isNull( dst ) )
02721   {
02722     MTX_ERROR_MSG( "NULL Matrix" );
02723     return FALSE;
02724   }
02725 
02726   if( row >= dst->nrows )
02727   {
02728     MTX_ERROR_MSG( "if( row >= dst->nrows )" );
02729     return FALSE;
02730   }
02731 
02732   for( j = 0; j < dst->ncols; j++ )
02733   {
02734     if( dst->isReal )
02735     {
02736       dst->data[j][row] = value;
02737     }
02738     else
02739     {
02740       dst->cplx[j][row].re = value;
02741       dst->cplx[j][row].im = value;
02742     }
02743   }
02744 
02745   return TRUE;
02746 }
02747 
02748 BOOL MTX_FillRowComplex( MTX *dst, const unsigned row, const double re, const double im )
02749 {
02750   unsigned j = 0;
02751 
02752   if( MTX_isNull( dst ) )
02753   {
02754     MTX_ERROR_MSG( "NULL Matrix" );
02755     return FALSE;
02756   }
02757 
02758   if( row >= dst->nrows )
02759   {
02760     MTX_ERROR_MSG( "if( row >= dst->nrows )" );
02761     return FALSE;
02762   }
02763 
02764   if( dst->isReal )
02765   {
02766     if( !MTX_ConvertRealToComplex( dst ) )
02767     {
02768       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
02769       return FALSE;
02770     }
02771   }
02772 
02773   for( j = 0; j < dst->ncols; j++ )
02774   {
02775     dst->cplx[j][row].re = re;
02776     dst->cplx[j][row].im = im;
02777   }
02778 
02779   return TRUE;
02780 }
02781 
02782 
02783 // set the matrix to an identity
02784 BOOL MTX_Identity( MTX *dst )
02785 {
02786   unsigned j = 0;
02787 
02788   if( MTX_isNull( dst ) )
02789   {
02790     MTX_ERROR_MSG( "NULL Matrix" );
02791     return FALSE;
02792   }
02793 
02794   if( !MTX_isSquare( dst ) )
02795   {
02796     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
02797     return FALSE;
02798   }
02799 
02800   if( !dst->isReal )
02801   {
02802     if( !MTX_Calloc( dst, dst->nrows, dst->ncols, TRUE ) )
02803     {
02804       MTX_ERROR_MSG( "MTX_Calloc returned FALSE." );
02805       return FALSE;
02806     }
02807   }
02808   else
02809   {
02810     if( !MTX_Zero( dst ) )
02811     {
02812       MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
02813       return FALSE;
02814     }
02815   }
02816 
02817   for( j = 0; j < dst->ncols; j++ )
02818   {
02819     dst->data[j][j] = 1.0;
02820   }
02821   return TRUE;
02822 }
02823 
02824 BOOL MTX_ForceSymmetric( MTX *M )
02825 {
02826   unsigned i = 0;
02827   unsigned j = 0;
02828   double tmp = 0.0;
02829   stComplex cplxval;
02830 
02831   if( MTX_isNull( M ) )
02832   {
02833     MTX_ERROR_MSG( "NULL Matrix" );
02834     return FALSE;
02835   }
02836   if( !MTX_isSquare( M ) )
02837   {
02838     MTX_ERROR_MSG( "The matrix is not square.");
02839     return FALSE;
02840   }
02841 
02842   for( j = 0; j < M->ncols; j++ )
02843   {
02844     for( i = 0; i < M->nrows; i++ )
02845     {
02846       if( i == j )
02847         break; // only need to go halfway
02848 
02849       if( M->isReal )
02850       {
02851         tmp = M->data[j][i] + M->data[i][j];
02852         tmp /= 2.0;
02853         M->data[j][i] = tmp;
02854         M->data[i][j] = tmp;
02855       }
02856       else
02857       {
02858         cplxval.re = M->cplx[j][i].re + M->cplx[i][j].re;
02859         cplxval.im = M->cplx[j][i].im + M->cplx[i][j].im;
02860         cplxval.re /= 2.0;
02861         cplxval.im /= 2.0;
02862 
02863         M->cplx[j][i].re = cplxval.re;
02864         M->cplx[j][i].im = cplxval.im;
02865         M->cplx[i][j].re = cplxval.re;
02866         M->cplx[i][j].im = cplxval.im;
02867       }
02868     }
02869   }
02870   return TRUE;
02871 }
02872 
02873 // Transpose the matrix src into the matrix dst.
02874 BOOL MTX_Transpose( const MTX *src, MTX *dst )
02875 {
02876   unsigned i = 0;
02877   unsigned j = 0;
02878 
02879   if( !dst )
02880   {
02881     MTX_ERROR_MSG( "dst is a NULL pointer." );
02882     return FALSE;
02883   }
02884 
02885   if( MTX_isNull( src ) )
02886   {
02887     MTX_ERROR_MSG( "NULL Matrix" );
02888     return FALSE;
02889   }
02890 
02891   // special case inplace transpose
02892   if( dst == src )
02893   {
02894     return MTX_TransposeInplace( dst );
02895   }
02896 
02897   // complex/real mixed cases
02898   if( !src->isReal && dst->isReal )
02899   {
02900     MTX_Free( dst );
02901 
02902     if( !MTX_Malloc( dst, src->ncols, src->nrows, src->isReal ) )
02903     {
02904       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
02905       return FALSE;
02906     }
02907   }
02908   else if( src->isReal && !dst->isReal )
02909   {
02910     MTX_Free( dst );
02911 
02912     if( !MTX_Malloc( dst, src->ncols, src->nrows, src->isReal ) )
02913     {
02914       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
02915       return FALSE;
02916     }
02917   }
02918 
02919 
02920   // resize if needed
02921   if( dst->nrows != src->ncols || dst->ncols != src->nrows )
02922   {
02923     if( !MTX_Resize( dst, src->ncols, src->nrows, src->isReal ) )
02924     {
02925       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
02926       return FALSE;
02927     }
02928   }
02929 
02930   if( dst->isReal )
02931   {
02932     for( j = 0; j < src->ncols; j++ )
02933     {
02934       for( i = 0; i < src->nrows; i++ )
02935       {
02936         dst->data[i][j] = src->data[j][i];        
02937       }
02938     }
02939   }
02940   else
02941   {
02942     for( j = 0; j < src->ncols; j++ )
02943     {
02944       for( i = 0; i < src->nrows; i++ )
02945       {
02946         dst->cplx[i][j].re = src->cplx[j][i].re;
02947         dst->cplx[i][j].im = src->cplx[j][i].im;
02948       }
02949     }
02950   }
02951   return TRUE;
02952 }
02953 
02954 BOOL MTX_TransposeInplace( MTX *M )
02955 {
02956   unsigned i = 0;
02957   unsigned j = 0;
02958   double tmp = 0.0;
02959   stComplex cplxval;
02960 
02961   if( MTX_isNull( M ) )
02962   {
02963     MTX_ERROR_MSG( "NULL Matrix" );
02964     return FALSE;
02965   }
02966 
02967   // special case, square matrix
02968   if( MTX_isSquare( M ) )
02969   {
02970     for( j = 0; j < M->ncols; j++ )
02971     {
02972       for( i = 0; i < M->nrows; i++ )
02973       {
02974         if( i == j )
02975           break; // only need to go halfway
02976 
02977         if( M->isReal )
02978         {
02979           tmp = M->data[j][i];
02980           M->data[j][i] = M->data[i][j];
02981           M->data[i][j] = tmp;
02982         }
02983         else
02984         {
02985           cplxval.re = M->cplx[j][i].re;
02986           cplxval.im = M->cplx[j][i].im;
02987           M->cplx[j][i].re = M->cplx[i][j].re;
02988           M->cplx[j][i].im = M->cplx[i][j].im;
02989           M->cplx[i][j].re = cplxval.re;
02990           M->cplx[i][j].im = cplxval.im;
02991         }
02992       }
02993     }
02994   }
02995   else
02996   {
02997     MTX copy;
02998     MTX_Init( &copy );
02999 
03000     if( !MTX_Malloc( &copy, M->nrows, M->ncols, M->isReal ) )
03001     {
03002       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
03003       return FALSE;
03004     }
03005     if( !MTX_Copy( M, &copy ) )
03006     {
03007       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
03008       return FALSE;
03009     }
03010 
03011     // resize the matrix from nxm to mxn
03012     if( !MTX_Resize( M, copy.ncols, copy.nrows, copy.isReal ) )
03013     {
03014       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
03015       return FALSE;
03016     }
03017 
03018     for( j = 0; j < copy.ncols; j++ )
03019     {
03020       for( i = 0; i < copy.nrows; i++ )
03021       {
03022         if( M->isReal )
03023         {
03024           M->data[i][j] = copy.data[j][i];
03025         }
03026         else
03027         {
03028           M->cplx[i][j].re = copy.cplx[j][i].re;
03029           M->cplx[i][j].im = copy.cplx[j][i].im;
03030         }
03031       }
03032     }
03033 
03034     MTX_Free( &copy );
03035   }
03036   return TRUE;
03037 }
03038 
03039 // round the matrix elements to the specified presision
03040 // e.g. precision = 0 1.8 -> 2
03041 // e.g. precision = 1, 1.45 -> 1.5
03042 // e.g. precision = 2 1.456 -> 1.46
03043 // e.g. precision = 3, 1.4566 -> 1.457
03044 BOOL MTX_Round( MTX *M, const unsigned precision )
03045 {
03046   unsigned i = 0;
03047   unsigned j = 0;
03048 
03049   if( MTX_isNull( M ) )
03050   {
03051     MTX_ERROR_MSG( "NULL Matrix" );
03052     return FALSE;
03053   }
03054 
03055   if( precision > 32 )
03056     return TRUE;
03057 
03058   if( precision == 0 )
03059   {
03060     if( M->isReal )
03061     {
03062       for( j = 0; j < M->ncols; j++ )
03063       {
03064         for( i = 0; i < M->nrows; i++ )
03065         {
03066           MTX_static_round_value_to_integer( &(M->data[j][i]) );
03067         }
03068       }
03069     }
03070     else
03071     {
03072       for( j = 0; j < M->ncols; j++ )
03073       {
03074         for( i = 0; i < M->nrows; i++ )
03075         {
03076           MTX_static_round_value_to_integer( &(M->cplx[j][i].re) );
03077           MTX_static_round_value_to_integer( &(M->cplx[j][i].im) );
03078         }
03079       }
03080     }
03081   }
03082   else
03083   {
03084     if( M->isReal )
03085     {
03086       for( j = 0; j < M->ncols; j++ )
03087       {
03088         for( i = 0; i < M->nrows; i++ )
03089         {
03090           MTX_static_round_value( &(M->data[j][i]), precision );
03091         }
03092       }
03093     }
03094     else
03095     {
03096       for( j = 0; j < M->ncols; j++ )
03097       {
03098         for( i = 0; i < M->nrows; i++ )
03099         {
03100           MTX_static_round_value( &(M->cplx[j][i].re), precision );
03101           MTX_static_round_value( &(M->cplx[j][i].im), precision );
03102         }
03103       }
03104     }
03105   }
03106   return TRUE;
03107 }
03108 
03109 BOOL MTX_static_round_value_to_integer( double *value )
03110 {
03111   if( *value < 0 )
03112     *value = ceil( *value - 0.5 );
03113   else
03114     *value = floor( *value + 0.5 );
03115   return TRUE;
03116 }
03117 
03118 BOOL MTX_static_round_value( double *value, const unsigned precision )
03119 {
03120   double pow10;
03121 
03122   pow10 = pow( 10.0, (double)(precision) );
03123 
03124   *value *= pow10;
03125   if( *value < 0 )
03126     *value = ceil( *value - 0.5 );
03127   else
03128     *value = floor( *value + 0.5 );
03129   *value /= pow10;
03130 
03131   return TRUE;
03132 }
03133 
03134 BOOL MTX_Floor( MTX *M )
03135 {
03136   unsigned i = 0;
03137   unsigned j = 0;
03138 
03139   if( MTX_isNull( M ) )
03140   {
03141     MTX_ERROR_MSG( "NULL Matrix" );
03142     return FALSE;
03143   }
03144 
03145   if( M->isReal )
03146   {
03147     for( j = 0; j < M->ncols; j++ )
03148     {
03149       for( i = 0; i < M->nrows; i++ )
03150       {      
03151         M->data[j][i] = floor(M->data[j][i]);
03152       }
03153     }
03154   }
03155   else
03156   {
03157     for( j = 0; j < M->ncols; j++ )
03158     {
03159       for( i = 0; i < M->nrows; i++ )
03160       {                  
03161         M->cplx[j][i].re = floor(M->cplx[j][i].re);
03162         M->cplx[j][i].im = floor(M->cplx[j][i].im);
03163       }
03164     }
03165   }
03166 
03167   return TRUE;
03168 }
03169 
03170 BOOL MTX_Ceil( MTX *M )
03171 {
03172   unsigned i = 0;
03173   unsigned j = 0;
03174 
03175   if( MTX_isNull( M ) )
03176   {
03177     MTX_ERROR_MSG( "NULL Matrix" );
03178     return FALSE;
03179   }
03180 
03181   if( M->isReal )
03182   {
03183     for( j = 0; j < M->ncols; j++ )
03184     {
03185       for( i = 0; i < M->nrows; i++ )
03186       {
03187         M->data[j][i] = ceil(M->data[j][i]);
03188       }
03189     }
03190   }
03191   else
03192   {
03193     for( j = 0; j < M->ncols; j++ )
03194     {
03195       for( i = 0; i < M->nrows; i++ )
03196       {
03197         M->cplx[j][i].re = ceil(M->cplx[j][i].re);
03198         M->cplx[j][i].im = ceil(M->cplx[j][i].im);
03199       }
03200     }
03201   }
03202 
03203   return TRUE;
03204 }
03205 
03206 BOOL MTX_Fix( MTX *M )
03207 {
03208   unsigned i = 0;
03209   unsigned j = 0;
03210 
03211   if( MTX_isNull( M ) )
03212   {
03213     MTX_ERROR_MSG( "NULL Matrix" );
03214     return FALSE;
03215   }
03216 
03217   if( M->isReal )
03218   {
03219     for( j = 0; j < M->ncols; j++ )
03220     {
03221       for( i = 0; i < M->nrows; i++ )
03222       {
03223         if( M->data[j][i] < 0 )
03224           M->data[j][i] = ceil(M->data[j][i]);
03225         else
03226           M->data[j][i] = floor(M->data[j][i]);
03227       }
03228     }
03229   }
03230   else
03231   {
03232     for( j = 0; j < M->ncols; j++ )
03233     {
03234       for( i = 0; i < M->nrows; i++ )
03235       {
03236         if( M->cplx[j][i].re < 0 )
03237           M->cplx[j][i].re = ceil(M->cplx[j][i].re);
03238         else
03239           M->cplx[j][i].re = floor(M->cplx[j][i].re);
03240 
03241         if( M->cplx[j][i].im < 0 )
03242           M->cplx[j][i].im = ceil(M->cplx[j][i].im);
03243         else
03244           M->cplx[j][i].im = floor(M->cplx[j][i].im);
03245       }
03246     }
03247   }
03248   return TRUE;
03249 }
03250 
03251 
03252 BOOL MTX_OneMinus( const MTX* src, MTX *dst )
03253 {
03254   if( MTX_isNull( src ) )
03255   {
03256     MTX_ERROR_MSG( "NULL Matrix" );
03257     return FALSE;
03258   }
03259   if( dst == NULL )
03260   {
03261     MTX_ERROR_MSG( "if( dst == NULL )" );
03262     return FALSE;
03263   }
03264 
03265   if( !(dst->isReal == src->isReal &&
03266     dst->nrows == src->nrows &&
03267     dst->ncols == src->ncols ) )
03268   {
03269     if( !MTX_Malloc( dst, src->nrows, src->ncols, src->isReal ) )
03270     {
03271       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
03272       return FALSE;
03273     }
03274   }
03275   if( !MTX_Fill( dst, 1.0 ) )
03276   {
03277     MTX_ERROR_MSG( "MTX_Fill returned FALSE." );
03278     return FALSE;
03279   }
03280   if( !MTX_Subtract_Inplace( dst, src ) )
03281   {
03282     MTX_ERROR_MSG( "MTX_Subtract_Inplace returned FALSE." );
03283     return FALSE;
03284   }
03285   return TRUE;
03286 }
03287 
03288 
03289 BOOL MTX_DetermineFileDelimiter(
03290                                 const char *path, //!< path to the input file
03291                                 char *delimiter, //!< delimiter, 'b' is binary
03292                                 BOOL *hasComment, //!< BOOL to indicate if a comment line is present
03293                                 char **comment //!< pointer to a string to store the comment line, *comment memory must be freed later.
03294                                 )
03295 {
03296   unsigned i = 0;
03297   unsigned line_length = 0;
03298   char line[MTX_MAX_READFROMFILE_BUFFER];
03299   char *linebuf;
03300   FILE *in;
03301   BOOL atEOF = FALSE;
03302 
03303   *hasComment = FALSE;
03304 
03305   // open the input file
03306 #ifndef _CRT_SECURE_NO_DEPRECATE
03307   if( fopen_s( &in, path, "r" ) != 0 )
03308   {
03309     MTX_ERROR_MSG( "fopen_s returned failure." );
03310     return FALSE;
03311   }
03312 #else
03313   in = fopen( path, "r" );
03314 #endif
03315   if( !in )
03316   {
03317 #ifndef _CRT_SECURE_NO_DEPRECATE
03318     if( sprintf_s( line, MTX_MAX_READFROMFILE_BUFFER, "Unable to open %s.", path ) > 0 )
03319       MTX_ERROR_MSG( line );
03320 #else
03321     if( sprintf( line, "Unable to open %s.", path ) > 0 )
03322       MTX_ERROR_MSG( line );
03323 #endif
03324     return FALSE;
03325   }
03326 
03327   // get the first line of data (or the comment line)
03328   if( !MTX_static_get_next_valid_data_line( in, line, &line_length, &atEOF ) )
03329   {
03330     MTX_ERROR_MSG( "MTX_static_get_next_valid_data_line returned FALSE." );
03331     return FALSE;
03332   }
03333   if( atEOF )
03334   {
03335     MTX_ERROR_MSG( "Unexpected end of file." );
03336     return FALSE;
03337   }
03338 
03339   // check is this is a binary compressed matrix
03340   if( strcmp( line, MTX_ID_COMPRESSED_01 ) == 0 )
03341   {
03342     *delimiter = 'b'; // binary
03343     fclose( in );
03344     return TRUE;
03345   }
03346 
03347   // check is this is a legacy binary compressed matrix
03348   if( strcmp( line, MTX_ID_LEGACY_V01 ) == 0 )
03349   {
03350     *delimiter = 'b'; // binary
03351     fclose( in );
03352     return TRUE;
03353   }
03354 
03355   // check is this is a legacy binary compressed matrix
03356   if( strcmp( line, MTX_ID_LEGACY_V02 ) == 0 )
03357   {
03358     *delimiter = 'b'; // binary
03359     fclose( in );
03360     return TRUE;
03361   }
03362 
03363   // check the first line with isalpha (the first line might be the comment line
03364   linebuf = (char *)line;
03365   for( i = 0; i < line_length; i++ )
03366   {
03367     if( isalpha( line[i] ) )
03368     {
03369       if( line[i] == 'e' || line[i] == 'E' || line[i] == '-' || line[i] == '+' || line[i] == '.' || line[i] == 'i' || line[i] == 'j' )
03370         continue;
03371 
03372       // first line is likely a comment line, store this for decoding later
03373       *hasComment = TRUE;
03374 
03375       // allocate the comment line
03376       (*comment) = (char*)malloc( (line_length+1)*sizeof(char) );
03377       if( !(*comment) )
03378       {
03379         // memory allocation failure
03380         fclose(in);
03381         MTX_ERROR_MSG( "malloc returned NULL." );
03382         return FALSE;
03383       }
03384 #ifndef _CRT_SECURE_NO_DEPRECATE
03385       if( strcpy_s( *comment, line_length+1, line ) != 0 )
03386       {
03387         MTX_ERROR_MSG( "strcpy_s returned failure." );
03388         return FALSE;
03389       }
03390 #else
03391       strcpy( *comment, line );
03392 
03393 #endif
03394 
03395       if( !MTX_static_get_next_valid_data_line( in, line, &line_length, &atEOF ) )
03396       {
03397         MTX_ERROR_MSG( "MTX_static_get_next_valid_data_line returned FALSE." );
03398         return FALSE;
03399       }
03400       if( atEOF )
03401       {
03402         MTX_ERROR_MSG( "Unexpected end of file." );
03403         return FALSE;
03404       }
03405 
03406       linebuf = (char *)line;
03407       break;
03408     }
03409   }
03410   fclose( in );
03411 
03412   // default is whitespace
03413   *delimiter = 'w';
03414 
03415   if( strstr( linebuf, "," ) ) { *delimiter = ','; return TRUE; }
03416   if( strstr( linebuf, ":" ) ) { *delimiter = ':'; return TRUE; }
03417   if( strstr( linebuf, ";" ) ) { *delimiter = ';'; return TRUE; }
03418   if( strstr( linebuf, "|" ) ) { *delimiter = '|'; return TRUE; }
03419   if( strstr( linebuf, "`" ) ) { *delimiter = '`'; return TRUE; }
03420   if( strstr( linebuf, "~" ) ) { *delimiter = '~'; return TRUE; }
03421   if( strstr( linebuf, "!" ) ) { *delimiter = '!'; return TRUE; }
03422   if( strstr( linebuf, "@" ) ) { *delimiter = '@'; return TRUE; }
03423   if( strstr( linebuf, "#" ) ) { *delimiter = '#'; return TRUE; }
03424   if( strstr( linebuf, "$" ) ) { *delimiter = '$'; return TRUE; }
03425   if( strstr( linebuf, "%%" ) ) { *delimiter = '%'; return TRUE; }
03426   if( strstr( linebuf, "^" ) ) { *delimiter = '^'; return TRUE; }
03427   if( strstr( linebuf, "&" ) ) { *delimiter = '&'; return TRUE; }
03428   if( strstr( linebuf, "*" ) ) { *delimiter = '*'; return TRUE; }
03429   if( strstr( linebuf, "(" ) ) { *delimiter = '('; return TRUE; }
03430   if( strstr( linebuf, ")" ) ) { *delimiter = ')'; return TRUE; }
03431   if( strstr( linebuf, "_" ) ) { *delimiter = '_'; return TRUE; }
03432   if( strstr( linebuf, "=" ) ) { *delimiter = '='; return TRUE; }
03433   if( strstr( linebuf, "{" ) ) { *delimiter = '{'; return TRUE; }
03434   if( strstr( linebuf, "}" ) ) { *delimiter = '}'; return TRUE; }
03435   if( strstr( linebuf, "[" ) ) { *delimiter = '['; return TRUE; }
03436   if( strstr( linebuf, "]" ) ) { *delimiter = ']'; return TRUE; }
03437   if( strstr( linebuf, "\\" ) ) { *delimiter = '\\'; return TRUE; }
03438   if( strstr( linebuf, "\'" ) ) { *delimiter = '\''; return TRUE; }
03439   if( strstr( linebuf, "<" ) ) { *delimiter = '<'; return TRUE; }
03440   if( strstr( linebuf, "<" ) ) { *delimiter = '<'; return TRUE; }
03441   if( strstr( linebuf, ">" ) ) { *delimiter = '>'; return TRUE; }
03442   if( strstr( linebuf, "?" ) ) { *delimiter = '?'; return TRUE; }
03443   if( strstr( linebuf, "/" ) ) { *delimiter = '/'; return TRUE; }
03444 
03445   return TRUE;
03446 }
03447 
03448 // determine the size of the file indicated
03449 BOOL MTX_DetermineFileSize( const char *path, unsigned *size )
03450 {
03451   FILE* in;
03452   unsigned fstart;
03453   unsigned fend;
03454   char msg[512];
03455 
03456   *size = 0;
03457 
03458   // check path
03459   if( !path )
03460   {
03461     MTX_ERROR_MSG( "path is NULL." );
03462     return FALSE;
03463   }
03464 
03465   // open the file and check path exists
03466 #ifndef _CRT_SECURE_NO_DEPRECATE
03467   if( fopen_s( &in, path, "r" ) != 0 )
03468   {
03469     MTX_ERROR_MSG( "fopen_s returned failure." );
03470     return FALSE;
03471   }
03472 #else
03473   in = fopen( path, "r" );
03474 #endif
03475   if( !in )
03476   {
03477 #ifndef _CRT_SECURE_NO_DEPRECATE
03478     if( sprintf_s( msg, 512, "Unable to open %s", path ) > 0 )
03479       MTX_ERROR_MSG( msg );
03480 #else
03481     if( sprintf( msg, "Unable to open %s", path ) > 0 )
03482       MTX_ERROR_MSG( msg );
03483 #endif
03484     return FALSE;
03485   }
03486 
03487   fstart = ftell( in );
03488   fseek( in, 0, SEEK_END );
03489   fend = ftell( in );
03490 
03491   *size = fend - fstart;
03492   fclose(in);
03493 
03494   return TRUE;
03495 }
03496 
03497 
03498 BOOL MTX_DetermineNumberOfColumnsInDataString( const char *datastr, unsigned *ncols )
03499 {
03500   unsigned i = 0;
03501   unsigned line_length;
03502   char c;
03503   BOOL wasLastCharData = FALSE;
03504   double dtmp;
03505   int rv;
03506 
03507   if( !datastr )
03508   {
03509     MTX_ERROR_MSG( "datastr is NULL." );
03510     return FALSE;
03511   }
03512 
03513   line_length = (unsigned int)strlen(datastr);
03514   if( line_length == 0 )
03515   {
03516     MTX_ERROR_MSG( "if( line_length == 0 )" );
03517     return FALSE;
03518   }
03519 
03520   // intialize ncols
03521   *ncols = 0;
03522 
03523   // advance over whitespace to the first data element
03524   for( i = 0; i < line_length; i++ )
03525   {
03526     if( isspace(datastr[i]) )
03527       continue;
03528     else
03529       break;
03530   }
03531   if( i == line_length )
03532   {
03533     // no data in the string
03534     MTX_ERROR_MSG( "if( i == line_length ) - no data in the string." );
03535     return FALSE;
03536   }
03537 
03538   // determine the number of columns in the matrix
03539   for( /*i*/; i < line_length; i++ )
03540   {
03541     c = datastr[i];
03542     if( isdigit(c) || c == '.' || c == '-' || c == '+' )
03543     {
03544       if( !wasLastCharData )
03545       {
03546         // try to read in the data to be sure the element is valid
03547 #ifndef _CRT_SECURE_NO_DEPRECATE
03548         rv = sscanf_s( &(datastr[i]), "%lf", &dtmp );
03549 #else
03550         rv = sscanf( &(datastr[i]), "%lf", &dtmp );
03551 #endif
03552         if( rv == 0 || rv == EOF )
03553         {
03554           // invalid element, file or data string is corrupt
03555           (*ncols) = 0;
03556           MTX_ERROR_MSG( "Invalid element found." );
03557           return FALSE;
03558         }
03559         (*ncols)++;
03560       }
03561       wasLastCharData = TRUE;
03562     }
03563     else if( c == 'e' || c == 'E' )
03564     {
03565       if( !wasLastCharData )
03566       {
03567         // the exponent should not be the leading character in
03568         // a data element
03569         (*ncols) = 0;
03570         MTX_ERROR_MSG( "Exponent cannot be a leading character." );
03571         return FALSE;
03572       }
03573       continue;
03574     }
03575     else
03576     {
03577       wasLastCharData = FALSE;
03578     }
03579   }
03580 
03581   return TRUE;
03582 }
03583 
03584 
03585 
03586 
03587 BOOL MTX_DetermineNumberOfColumnsInDataStringCplx( const char *datastr, const char delimiter, unsigned *ncols )
03588 {
03589   unsigned i = 0;
03590   unsigned line_length;
03591   char c;
03592 
03593   BOOL isElementOnlyReal;
03594   BOOL isElementOnlyComplex;
03595   BOOL isComplexMix;
03596 
03597   if( !datastr )
03598   {
03599     MTX_ERROR_MSG( "datastr is NULL." );
03600     return FALSE;
03601   }
03602 
03603   line_length = (unsigned int)strlen(datastr);
03604   if( line_length == 0 )
03605   {
03606     MTX_ERROR_MSG( "if( line_length == 0 )" );
03607     return FALSE;
03608   }
03609 
03610   // intialize ncols
03611   *ncols = 0;
03612 
03613   // advance over whitespace to the first data element
03614   for( i = 0; i < line_length; i++ )
03615   {
03616     if( isspace(datastr[i]) )
03617       continue;
03618     else
03619       break;
03620   }
03621   if( i == line_length )
03622   {
03623     // no data in the string
03624     MTX_ERROR_MSG( "if( i == line_length ) - No data in the string." );
03625     return FALSE;
03626   }
03627 
03628   isElementOnlyComplex = FALSE;
03629   isElementOnlyReal = FALSE;
03630   isComplexMix = FALSE;
03631 
03632   for( /*i*/; i < line_length; i++ )
03633   {
03634     c = datastr[i];
03635 
03636     // looking for a digit
03637     if( isdigit(c) )
03638     {
03639       i++;
03640       // actually found a value
03641       // now search for an imag component
03642       for( /*i*/; i < line_length; i++ )
03643       {
03644         c = datastr[i];
03645         if( c == 'i' || c == 'j' )
03646         {
03647           // found one of bi, -bi, +bi, a+bi or a-bi element
03648           isComplexMix = TRUE;
03649           break;
03650         }
03651         else if( delimiter == 'w' )
03652         {
03653           if( isspace(c) )
03654           {
03655             // we have reached the next delimiter and no imag component was found
03656             isElementOnlyReal = TRUE;
03657             break;
03658           }
03659         }
03660         else if( c == delimiter )
03661         {
03662           // we have reached the next delimiter and no imag component was found
03663           isElementOnlyReal = TRUE;
03664           break;
03665         }
03666         // continue searching
03667       }
03668 
03669       (*ncols)++;
03670       isComplexMix = FALSE;
03671       isElementOnlyReal = FALSE;
03672     }
03673     else
03674     {
03675       if( c == 'i' || c == 'j' )
03676       {
03677         isElementOnlyComplex = TRUE;
03678         (*ncols)++;
03679         isElementOnlyComplex = FALSE;
03680       }
03681     }
03682   }
03683 
03684   return TRUE;
03685 }
03686 
03687 
03688 
03689 BOOL MTX_static_extract_cplx_from_string_with_leading_digit(
03690   char *datastr, //!< The entire input data string.
03691   const unsigned indexS, //!< The start index of the complex element.
03692   const unsigned indexE, //!< The inclusive end index of the complex element.
03693   double *re, //!< The extracted real component.
03694   double *im //!< The extracted imag component.
03695   )
03696 {
03697   unsigned i = 0;
03698   int rv;
03699   unsigned len = indexE - indexS + 1;
03700   char str[128];
03701 
03702   for( i = 0; i < len && i < 128; i++ )
03703   {
03704     str[i] = datastr[indexS+i];
03705     if( i != 0 )
03706     {
03707       if( (str[i-1] == '+' || str[i-1] == '-') && (str[i] == 'i' || str[i] == 'j') )
03708       {
03709         str[i] = '1';
03710       }
03711     }
03712   }
03713   str[i] = '\0';
03714 
03715   // try to read two value
03716 #ifndef _CRT_SECURE_NO_DEPRECATE
03717   rv = sscanf_s( str, "%lf%lf", re, im );
03718 #else
03719   rv = sscanf( str, "%lf%lf", re, im );
03720 #endif
03721   if( rv == 2 )
03722   {
03723     return TRUE;
03724   }
03725   else if( rv == 1 )
03726   {
03727     *im = *re;
03728     *re = 0;
03729     return TRUE;
03730   }
03731   else
03732   {
03733 #ifndef _CRT_SECURE_NO_DEPRECATE
03734     MTX_ERROR_MSG( "sscanf_s returned failure." );
03735 #else
03736     MTX_ERROR_MSG( "sscanf returned failure." );
03737 #endif
03738     return FALSE;
03739   }
03740 }
03741 
03742 
03743 BOOL MTX_static_extract_real_into_cplx_from_string(
03744   char *datastr, //!< The entire input data string.
03745   const unsigned indexS, //!< The start index of the complex element.
03746   double *re, //!< The extracted real component.
03747   double *im //!< The extracted imag component.
03748   )
03749 {
03750   int rv;
03751 
03752   // try to read two value
03753 #ifndef _CRT_SECURE_NO_DEPRECATE
03754   rv = sscanf_s( &(datastr[indexS]), "%lf", re );
03755 #else
03756   rv = sscanf( &(datastr[indexS]), "%lf", re );
03757 #endif
03758   if( rv == 1 )
03759   {
03760     *im = 0;
03761     return TRUE;
03762   }
03763   else
03764   {
03765 #ifndef _CRT_SECURE_NO_DEPRECATE
03766     MTX_ERROR_MSG( "sscanf_s returned failure." );
03767 #else
03768     MTX_ERROR_MSG( "sscanf returned failure." );
03769 #endif
03770     return FALSE;
03771   }
03772 }
03773 
03774 
03775 
03776 
03777 BOOL MTX_static_get_row_array_from_string_cplx( char *datastr, const char delimiter, _MTX_STRUCT_ReadFromFileListElem *L, const unsigned ncols )
03778 {
03779   unsigned i = 0;
03780   int j = 0;
03781   unsigned line_length;
03782   char c;
03783 
03784   unsigned indexS; // index of the start of an element
03785   unsigned indexE; // index of the end of an element
03786 
03787   BOOL isElementOnlyReal;
03788   BOOL isElementOnlyComplex;
03789   BOOL isComplexMix;
03790 
03791   unsigned n = 0;
03792 
03793   if( !datastr )
03794   {
03795     MTX_ERROR_MSG( "datastr is NULL." );
03796     return FALSE;
03797   }
03798 
03799   line_length = (unsigned int)strlen(datastr);
03800   if( line_length == 0 )
03801   {
03802     MTX_ERROR_MSG( "if( line_length == 0 )" );
03803     return FALSE;
03804   }
03805 
03806   // advance over whitespace to the first data element
03807   for( i = 0; i < line_length; i++ )
03808   {
03809     if( isspace(datastr[i]) )
03810       continue;
03811     else
03812       break;
03813   }
03814   if( i == line_length )
03815   {
03816     // no data in the string
03817     MTX_ERROR_MSG( "if( i == line_length ) - No data in the string." );
03818     return FALSE;
03819   }
03820 
03821   isElementOnlyComplex = FALSE;
03822   isElementOnlyReal = FALSE;
03823   isComplexMix = FALSE;
03824 
03825   for( /*i*/; i < line_length; i++ )
03826   {
03827     c = datastr[i];
03828 
03829     // looking for a digit
03830     if( isdigit(c) || ((c == '+' || c == '-') && isdigit(datastr[i+1]) ) )
03831     {
03832       indexS = i;
03833       i++;
03834       // actually found a value
03835       // now search for an imag component
03836       for( /*i*/; i <= line_length; i++ ) // notice the <= (this algorithm is made easier by allowing this)
03837       {
03838         c = datastr[i];
03839         if( c == 'i' || c == 'j' )
03840         {
03841           // found one of bi, -bi, +bi, a+i, a-i, a+bi or a-bi element (or with 'j')
03842           indexE = i;
03843           isComplexMix = TRUE;
03844 
03845           // don't allow invalid indexing
03846           if( n < ncols )
03847           {
03848             if( !MTX_static_extract_cplx_from_string_with_leading_digit(
03849               datastr,
03850               indexS,
03851               indexE,
03852               &(L->rowptr_cplx[n].re),
03853               &(L->rowptr_cplx[n].im) ) )
03854             {
03855               MTX_ERROR_MSG( "MTX_static_extract_cplx_from_string_with_leading_digit returned FALSE." );
03856               return FALSE;
03857             }
03858           }
03859 
03860           break;
03861         }
03862         else if( delimiter == 'w' )
03863         {
03864           if( isspace(c) || c == 0 )
03865           {
03866             // we have reached the next delimiter and no imag component was found
03867             isElementOnlyReal = TRUE;
03868 
03869             // don't allow invalid indexing
03870             if( n < ncols )
03871             {
03872               if( !MTX_static_extract_real_into_cplx_from_string(
03873                 datastr,
03874                 indexS,
03875                 &(L->rowptr_cplx[n].re),
03876                 &(L->rowptr_cplx[n].im) ) )
03877               {
03878                 MTX_ERROR_MSG( "MTX_static_extract_real_into_cplx_from_string returned FALSE." );
03879                 return FALSE;
03880               }
03881             }
03882             break;
03883           }
03884         }
03885         else if( c == delimiter || c == 0 )
03886         {
03887           // we have reached the next delimiter and no imag component was found
03888           isElementOnlyReal = TRUE;
03889 
03890           // don't allow invalid indexing
03891           if( n < ncols )
03892           {
03893 
03894             if( !MTX_static_extract_real_into_cplx_from_string(
03895               datastr,
03896               indexS,
03897               &(L->rowptr_cplx[n].re),
03898               &(L->rowptr_cplx[n].im) ) )
03899             {
03900               MTX_ERROR_MSG( "MTX_static_extract_real_into_cplx_from_string returned FALSE." );
03901               return FALSE;
03902             }
03903           }
03904           break;
03905         }
03906         // continue searching
03907       }
03908 
03909       n++;
03910       if( n > ncols )
03911         break; // no sense in continuing
03912       isComplexMix = FALSE;
03913       isElementOnlyReal = FALSE;
03914     }
03915     else
03916     {
03917       if( c == 'i' || c == 'j' )
03918       {
03919         isElementOnlyComplex = TRUE;
03920 
03921         // don't allow invalid indexing
03922         if( n < ncols )
03923         {
03924           // figure if it is signed
03925           L->rowptr_cplx[n].re = 0;
03926           L->rowptr_cplx[n].im = 1.0;
03927           j = i-1;
03928           while( j >= 0 )
03929           {
03930             c = datastr[j];
03931             if( c == '-' )
03932             {
03933               L->rowptr_cplx[n].im = -1.0;
03934               break;
03935             }
03936             else if( c == '+' )
03937             {
03938               break;
03939             }
03940             else if( c == 'i' || c == 'j' )
03941             {
03942               break;
03943             }
03944             else if( isdigit(c) )
03945             {
03946               break;
03947             }
03948             j--;
03949           }
03950         }
03951         n++;
03952         if( n > ncols )
03953           break; // no sense in continuing
03954         isElementOnlyComplex = FALSE;
03955       }
03956     }
03957   }
03958 
03959   if( n != ncols )
03960   {
03961     MTX_ERROR_MSG( "if( n != ncols )" );
03962     return FALSE;
03963   }
03964   else
03965   {
03966     return TRUE;
03967   }
03968 }
03969 
03970 
03971 BOOL MTX_static_get_row_array_from_string( char *datastr, _MTX_STRUCT_ReadFromFileListElem *L, const unsigned ncols )
03972 {
03973   unsigned i = 0;
03974   unsigned n; // number of columns read successfully
03975   unsigned line_length;
03976   char c;
03977   BOOL wasLastCharData = FALSE;
03978   int rv;
03979 
03980   if( !datastr )
03981   {
03982     MTX_ERROR_MSG( "datastr is NULL." );
03983     return FALSE;
03984   }
03985 
03986   if( !L )
03987   {
03988     MTX_ERROR_MSG( "L is NULL." );
03989     return FALSE;
03990   }
03991 
03992   if( !L->rowptr )
03993   {
03994     MTX_ERROR_MSG( "L->rowptr is NULL." );
03995     return FALSE;
03996   }
03997 
03998   line_length = (unsigned int)strlen(datastr);
03999   if( line_length == 0 )
04000   {
04001     MTX_ERROR_MSG( "if( line_length == 0 )" );
04002     return FALSE;
04003   }
04004 
04005   // advance over whitespace to the first data element
04006   for( i = 0; i < line_length; i++ )
04007   {
04008     if( isspace(datastr[i]) )
04009       continue;
04010     else
04011       break;
04012   }
04013   if( i == line_length )
04014   {
04015     // no data in the string
04016     MTX_ERROR_MSG( "if( i == line_length ) - No data in the string." );
04017     return FALSE;
04018   }
04019 
04020   // read in one row of data
04021   n = 0;
04022   for( /*i*/; i < line_length; i++ )
04023   {
04024     c = datastr[i];
04025     if( isdigit(c) || c == '.' || c == '-' || c == '+' )
04026     {
04027       if( !wasLastCharData )
04028       {
04029         // try to read in the data to be sure the element is valid
04030 #ifndef _CRT_SECURE_NO_DEPRECATE
04031         rv = sscanf_s( &(datastr[i]), "%lf", &(L->rowptr[n]) );
04032 #else
04033         rv = sscanf( &(datastr[i]), "%lf", &(L->rowptr[n]) );
04034 #endif
04035         if( rv == 0 || rv == EOF )
04036         {
04037           // invalid element, file is corrupt
04038           MTX_ERROR_MSG( "Invalid element found." );
04039           return FALSE;
04040         }
04041         n++;
04042         if( n == ncols )
04043           break;
04044       }
04045       wasLastCharData = TRUE;
04046     }
04047     else if( c == 'e' || c == 'E' )
04048     {
04049       if( !wasLastCharData )
04050       {
04051         // the exponent should not be the leading character in
04052         // a data element
04053         MTX_ERROR_MSG( "Invalid element found. Exponent cannot be leading character." );
04054         return FALSE;
04055       }
04056       continue;
04057     }
04058     else
04059     {
04060       wasLastCharData = FALSE;
04061     }
04062   }
04063 
04064   if( n != ncols )
04065   {
04066     // the number of columns does not match
04067     MTX_ERROR_MSG( "if( n != ncols ) - The number of columns do not match." );
04068     return FALSE;
04069   }
04070 
04071   return TRUE;
04072 }
04073 
04074 
04075 BOOL MTX_static_get_next_valid_data_line(
04076   FILE *in, //!< The input file pointer (input).
04077   char *linebuf, //!< A exisiting buffer to store the input line (input/output).
04078   unsigned *line_length, //!< The length of the line read (output).
04079   BOOL *atEOF //!< A boolean to indicate if EOF has been reached.
04080   )
04081 {
04082   unsigned i = 0;
04083   i = 0;
04084   *line_length = 0;
04085   while( i == *line_length )
04086   {
04087     if( fgets( linebuf, MTX_MAX_READFROMFILE_BUFFER, in ) == NULL )
04088     {
04089       *atEOF = TRUE;
04090       if( feof(in) )
04091       {
04092         // reached the end of the file properly
04093         fclose(in);
04094         return TRUE;
04095       }
04096       else if( ferror(in) != 0 )
04097       {
04098         // error in reading the datafile
04099         fclose(in);
04100         MTX_ERROR_MSG( "Error reading in the data." );
04101         return FALSE;
04102       }
04103       else
04104       {
04105         // error in reading the datafile
04106         fclose(in);
04107         MTX_ERROR_MSG( "Error reading in the data." );
04108         return FALSE;
04109       }
04110     }
04111 
04112     *line_length = (unsigned int)strlen(linebuf);
04113     for( i = 0; i < *line_length; i++ )
04114     {
04115       if( !isspace(linebuf[i]) )
04116         break;
04117     }
04118   }
04119 
04120   // provide some buffer room, in case of overreading the linebuffer.
04121   if( *line_length < MTX_MAX_READFROMFILE_BUFFER-2 )
04122   {
04123     linebuf[*line_length] = '\0';
04124     linebuf[(*line_length)+1] = '\0';
04125   }
04126 
04127   return TRUE;
04128 }
04129 
04130 
04131 
04132 BOOL MTX_static_get_next_valid_data_line_from_matrix_string(
04133   const char *strMatrix, //!< The matrix string pointer (input).
04134   const unsigned strLength, //!< The length of the matrix string (input).
04135   unsigned *index, //!< The starting/(next line) index into the matrix string pointer (input/output).
04136   char *linebuf, //!< A exisiting buffer to store the input line (input/output).
04137   unsigned *line_length, //!< The length of the line read (output).
04138   BOOL *atEndOfString //!< A boolean to indicate if the end of the strMatrix string has been reached.
04139   )
04140 {
04141   unsigned i = 0;
04142   unsigned j = 0;
04143   *line_length = 0;
04144   *atEndOfString = FALSE;
04145 
04146   // sanity checks
04147   if( strMatrix == NULL )
04148   {
04149     MTX_ERROR_MSG( "strMatrix is NULL." );
04150     return FALSE;
04151   }
04152   if( index == NULL )
04153   {
04154     MTX_ERROR_MSG( "index is NULL." );
04155     return FALSE;
04156   }
04157   if( *index == strLength )
04158   {
04159     *atEndOfString = TRUE;
04160     return TRUE;
04161   }
04162   if( *index > strLength )
04163   {
04164     MTX_ERROR_MSG( "if( *index > strLength )" );
04165     return FALSE;
04166   }
04167 
04168   while( i == *line_length )
04169   {
04170     *line_length = 0;
04171     for( j = *index; j < strLength; j++ )
04172     {
04173       linebuf[j-(*index)] = strMatrix[j];
04174       *line_length = *line_length + 1;
04175       if( strMatrix[j] == '\n' )
04176         break;
04177     }
04178     linebuf[*line_length] = '\0';
04179 
04180     if( *line_length == 0 )
04181     {
04182       *atEndOfString = TRUE;
04183       *index = strLength;
04184       break;
04185     }
04186 
04187     for( i = 0; i < *line_length; i++ )
04188     {
04189       if( !isspace(linebuf[i]) )
04190         break;
04191     }
04192     *index += *line_length;
04193   }
04194 
04195   // provide some buffer room, in case of overreading the linebuffer.
04196   if( *line_length < MTX_MAX_READFROMFILE_BUFFER-2 )
04197   {
04198     linebuf[*line_length] = '\0';
04199     linebuf[(*line_length)+1] = '\0';
04200   }
04201 
04202   return TRUE;
04203 }
04204 
04205 BOOL MTX_static_look_for_complex_data(
04206                                       char *linebuf, //!< A string containing a line of data (input).
04207                                       const unsigned line_length, //!< The length of the string (input).
04208                                       BOOL *hasComplex //!< A boolean indicating if there is any complex data (output).
04209                                       )
04210 {
04211   unsigned i;
04212 
04213   *hasComplex = FALSE;
04214   if( linebuf == NULL )
04215   {
04216     MTX_ERROR_MSG( "linebuf is NULL." );
04217     return FALSE;
04218   }
04219 
04220   for( i = 0; i < line_length; i++ )
04221   {
04222     if( linebuf[i] == 'i' || linebuf[i] == 'j' )
04223     {
04224       *hasComplex = TRUE;
04225       break;
04226     }
04227   }
04228   return TRUE;
04229 }
04230 
04231 
04232 
04233 
04234 
04235 // Reads in the matrix M->data from the specified file using the indicated *delimiter
04236 // ReadFromFile is 'read smart' (it determines the size of the input matrix on its own)
04237 // The number of columns are first determined then all M->data is read into linked lists
04238 // untill end of file is reached. Data is then stored in the matrix.
04239 BOOL MTX_ReadFromFileRealOnly( MTX *M, const char *path )
04240 {
04241   unsigned i = 0;
04242   FILE *in = NULL;
04243   char delimiter = 0;
04244   char linebuf[MTX_MAX_READFROMFILE_BUFFER];
04245   unsigned ncols = 0;
04246   unsigned nrows = 0;
04247   unsigned fsize = 0;
04248   unsigned line_length = 0;
04249   BOOL hasCommentLine = FALSE;
04250   BOOL errorInReadingDataFile = FALSE;
04251   BOOL errorInTranspose = FALSE;
04252   BOOL atEOF = FALSE;
04253   MTX RowMatrix;
04254 
04255   // a linked list of row arrays
04256   _MTX_STRUCT_ReadFromFileListElem *L = NULL;
04257   _MTX_STRUCT_ReadFromFileListElem *nL = NULL;
04258   _MTX_STRUCT_ReadFromFileListElem head;
04259   head.next = NULL;
04260   head.rowptr = NULL;
04261 
04262   if( M == NULL )
04263   {
04264     MTX_ERROR_MSG( "M is NULL." );
04265     return FALSE;
04266   }
04267 
04268   // check path
04269   if( !path )
04270   {
04271     MTX_ERROR_MSG( "path is NULL." );
04272     return FALSE;
04273   }
04274 
04275   // check path exists
04276 #ifndef _CRT_SECURE_NO_DEPRECATE
04277   if( fopen_s( &in, path, "r" ) != 0 )
04278   {
04279     MTX_ERROR_MSG( "fopen_s returned failure." );
04280     return FALSE;
04281   }
04282 #else
04283   in = fopen( path, "r" );
04284 #endif
04285   if( !in )
04286   {
04287 #ifndef _CRT_SECURE_NO_DEPRECATE
04288     if( sprintf_s( linebuf, MTX_MAX_READFROMFILE_BUFFER, "Unable to open %s.", path ) > 0 )
04289       MTX_ERROR_MSG( linebuf );
04290 #else
04291     if( sprintf( linebuf, "Unable to open %s.", path ) > 0 )
04292       MTX_ERROR_MSG( linebuf );
04293 #endif
04294     return FALSE;
04295   }
04296   fclose(in);
04297 
04298   MTX_Init( &RowMatrix );
04299 
04300   // determine the file delimiter
04301   if( MTX_DetermineFileDelimiter( path, &delimiter, &hasCommentLine, &(M->comment) ) == FALSE )
04302   {
04303     MTX_ERROR_MSG( "MTX_DetermineFileDelimiter returned FALSE." );
04304     return FALSE;
04305   }
04306 
04307   // check if this is a binary compressed matrix
04308   if( delimiter == 'b' )
04309   {
04310     if( MTX_ReadCompressed( M, path ) )
04311     {
04312       return TRUE;
04313     }
04314     else
04315     {
04316       MTX_ERROR_MSG( "MTX_ReadCompressed returned FALSE." );
04317       return FALSE;
04318     }
04319   }
04320 
04321   // determine the size of the file
04322   if( MTX_DetermineFileSize( path, &fsize ) == FALSE )
04323   {
04324     MTX_ERROR_MSG( "MTX_DetermineFileSize returned FALSE." );
04325     return FALSE;
04326   }
04327 
04328   // open the input file for full input operations
04329 #ifndef _CRT_SECURE_NO_DEPRECATE
04330   if( fopen_s( &in, path, "r" ) != 0 )
04331   {
04332     MTX_ERROR_MSG( "fopen_s returned failure." );
04333     return FALSE;
04334   }
04335 #else
04336   in = fopen( path, "r" );
04337 #endif
04338   if( !in )
04339   {
04340 #ifndef _CRT_SECURE_NO_DEPRECATE
04341     if( sprintf_s( linebuf, MTX_MAX_READFROMFILE_BUFFER, "Unable to open %s.", path ) > 0 )
04342       MTX_ERROR_MSG( linebuf );
04343 #else
04344     if( sprintf( linebuf, "Unable to open %s.", path ) > 0 )
04345       MTX_ERROR_MSG( linebuf );
04346 #endif
04347     return FALSE;
04348   }
04349 
04350   // advance over whitespace lines at the beginning of the file
04351   if( !MTX_static_get_next_valid_data_line( in, linebuf, &line_length, &atEOF ) )
04352   {
04353     MTX_ERROR_MSG( "MTX_static_get_next_valid_data_line returned FALSE." );
04354     return FALSE;
04355   }
04356   if( atEOF )
04357   {
04358     MTX_ERROR_MSG( "Unexpected end of file." );
04359     return FALSE;
04360   }
04361 
04362   if( hasCommentLine )
04363   {
04364     if( !MTX_static_get_next_valid_data_line( in, linebuf, &line_length, &atEOF ) )
04365     {
04366       MTX_ERROR_MSG( "MTX_static_get_next_valid_data_line returned FALSE." );
04367       return FALSE;
04368     }
04369     if( atEOF )
04370     {
04371       MTX_ERROR_MSG( "Unexpected end of file." );
04372       return FALSE;
04373     }
04374   }
04375 
04376   // determine the number of columns in the first line of data
04377   if( MTX_DetermineNumberOfColumnsInDataString( linebuf, &ncols ) == FALSE )
04378   {
04379     MTX_ERROR_MSG( "MTX_DetermineNumberOfColumnsInDataString returned FALSE." );
04380     return FALSE;
04381   }
04382 
04383 
04384   // super fast rowwise input routine
04385   // a rowwise matrix is constructed using a linked list approach
04386   // line by line input
04387   nrows = 0;
04388   head.rowptr = (double*)malloc( ncols*sizeof(double) );
04389   // get the row data from the string and store it in the list item row array
04390   if( MTX_static_get_row_array_from_string( linebuf, &head, ncols ) == FALSE )
04391   {
04392     // must free head's rowarray
04393     free( head.rowptr );
04394     MTX_ERROR_MSG( "MTX_static_get_row_array_from_string returned FALSE." );
04395     return FALSE;
04396   }
04397   nrows++;
04398   nL = &head;
04399 
04400   while(1)
04401   {
04402     // get the next string of data
04403     if( !MTX_static_get_next_valid_data_line( in, linebuf, &line_length, &atEOF ) )
04404     {
04405       errorInReadingDataFile = TRUE;
04406       break;
04407     }
04408     if( atEOF )
04409     {
04410       break;
04411     }
04412 
04413     // the 'current' list itme
04414     L = nL;
04415 
04416     // allocate the next list item
04417     nL = (_MTX_STRUCT_ReadFromFileListElem*)malloc( sizeof( _MTX_STRUCT_ReadFromFileListElem ) );
04418     if( !nL )
04419     {
04420       // memory allocate failure
04421       // must free the linked list
04422       errorInReadingDataFile = TRUE;
04423       // must free head's rowarray
04424       free( head.rowptr );
04425       MTX_ERROR_MSG( "if( !nL )" );
04426       return FALSE;
04427     }
04428     // intialize the row
04429     nL->rowptr = NULL;
04430     nL->next = NULL;
04431     // allocate the row
04432     nL->rowptr = (double*)malloc( ncols*sizeof(double) );
04433     if( !nL->rowptr )
04434     {
04435       // memory allocate failure
04436       // must free the linked list
04437       errorInReadingDataFile = TRUE;
04438       break;
04439     }
04440 
04441     // store the pointer to the next list item
04442     // in the 'current'
04443     L->next = nL;
04444 
04445     // get the row data from the string and store it in the list item row array
04446     if( MTX_static_get_row_array_from_string( linebuf, nL, ncols ) == FALSE )
04447     {
04448       // must free the linked list
04449       errorInReadingDataFile = TRUE;
04450       break;
04451     }
04452     nrows++;
04453   }
04454 
04455   if( errorInReadingDataFile )
04456   {
04457     // free the list
04458     L = head.next;
04459     while( L!=NULL )
04460     {
04461       nL = L->next;
04462       free( L->rowptr );
04463       free(L);
04464       L = nL;
04465     }
04466     free( head.rowptr );
04467 
04468     MTX_ERROR_MSG( "if( errorInReadingDataFile )" );
04469     return FALSE;
04470   }
04471 
04472   // copy the list into a MTX object
04473 
04474   // allocate the row array of pointers
04475   RowMatrix.data = (double**)malloc( nrows*sizeof(double*) );
04476   if( !RowMatrix.data )
04477   {
04478     MTX_ERROR_MSG( "malloc returned NULL." );
04479     return FALSE;
04480   }
04481 
04482   // looks weird but this is rowwise input
04483   RowMatrix.ncols = nrows;
04484   RowMatrix.nrows = ncols;
04485 
04486   L = &head;
04487   for( i = 0; i < nrows; i++ )
04488   {
04489     if( L == NULL )
04490     {
04491       // this should never happen
04492       free(RowMatrix.data);
04493       RowMatrix.data = NULL;
04494       MTX_ERROR_MSG( "if( L == NULL )" );
04495       return FALSE;
04496     }
04497     RowMatrix.data[i] = L->rowptr; // only copying a pointer!
04498     L = L->next;
04499   }
04500 
04501   // copy the data by means of transpose
04502   // this places the data in the correct MTX storage format
04503   // only one copy operation
04504   if( !MTX_Transpose( &RowMatrix, M ) )
04505   {
04506     errorInTranspose = TRUE;
04507   }
04508 
04509   // free the list data and the list items
04510   L = head.next;
04511   while( L!=NULL )
04512   {
04513     nL = L->next;
04514     free( L->rowptr );
04515     free(L);
04516     L = nL;
04517   }
04518   // free the head data
04519   free( head.rowptr );
04520 
04521   // free the RowMatrix data ptr
04522   free( RowMatrix.data );
04523 
04524   if( errorInTranspose )
04525   {
04526     MTX_ERROR_MSG( "if( errorInTranspose )" );
04527     return FALSE;
04528   }
04529   else
04530   {
04531     return TRUE;
04532   }
04533 }
04534 
04535 // Reads in the matrix (real or complex) from the specified file using the indicated *delimiter
04536 // ReadFromFile is 'read smart' (it determines the size of the input matrix on its own)
04537 // The number of columns are first determined then all data is read into linked lists
04538 // untill end of file is reached. Data is then stored in the matrix. The input is treated as
04539 // complex.
04540 BOOL MTX_ReadFromFile( MTX *M, const char *path )
04541 {
04542   unsigned i;
04543   FILE *in = NULL; // The input file pointer.
04544   char delimiter = 0; // The file delimiter ('b' is a binary file, 'w' is whitespace delimited).
04545   char linebuf[MTX_MAX_READFROMFILE_BUFFER]; // A fairly large line buffer.
04546   unsigned ncols = 0; // The number of columns determined in the matrix.
04547   unsigned nrows = 0; // The number of rows determined in the matrix.
04548   unsigned fsize = 0; // The size of the input file [bytes].
04549   unsigned line_length = 0; // The length of the linebuf buffer.
04550   BOOL hasCommentLine = FALSE; // A boolean to indicate if the file has a comment line for the first line.
04551   BOOL errorInReadingDataFile = FALSE; // A boolean to indicate an error in reading the data file.
04552   BOOL errorInTranspose = FALSE; // A boolean to indicate an error in the transpose operation at the end.
04553   BOOL atEOF = FALSE; // A boolean to indicate when EOF is reached.
04554   BOOL isReal = TRUE; // A boolean to indicate if the matrix is real or complex.
04555   BOOL complexDetected = FALSE; // A boolean to indicate that complex data has been detected.
04556   BOOL needToConvertRealToComplex = FALSE; // A boolean to indicate if the matrix was real and needs to be converted to complex.
04557   MTX RowMatrix; // A rowwise storage version of the matrix. The transpose of this matrix is the final result.
04558   char *commentLine = NULL; // The comment line if one is found.
04559 
04560   // A linked list of row arrays (of either real or complex data).
04561   _MTX_STRUCT_ReadFromFileListElem *L = NULL; // The current list item.
04562   _MTX_STRUCT_ReadFromFileListElem *nL = NULL; // The next list item.
04563   _MTX_STRUCT_ReadFromFileListElem head; // The head of the list.
04564   head.next = NULL;
04565   head.rowptr = NULL;
04566 
04567   // check path
04568   if( !path )
04569   {
04570     MTX_ERROR_MSG( "path is NULL." );
04571     return FALSE;
04572   }
04573 
04574   // check path exists
04575 #ifndef _CRT_SECURE_NO_DEPRECATE
04576   if( fopen_s( &in, path, "r" ) != 0 )
04577   {
04578     MTX_ERROR_MSG( "fopen_s returned failure." );
04579     return FALSE;
04580   }
04581 #else
04582   in = fopen( path, "r" );
04583 #endif
04584   if( !in )
04585   {
04586 #ifndef _CRT_SECURE_NO_DEPRECATE
04587     if( sprintf_s( linebuf, MTX_MAX_READFROMFILE_BUFFER, "Unable to open %s.", path ) > 0 )
04588       MTX_ERROR_MSG( linebuf );
04589 #else
04590     if( sprintf( linebuf, "Unable to open %s.", path ) > 0 )
04591       MTX_ERROR_MSG( linebuf );
04592 #endif
04593     return FALSE;
04594   }
04595   fclose(in);
04596 
04597   // initialize the single row container
04598   MTX_Init( &RowMatrix );
04599 
04600   // determine the file delimiter
04601   if( MTX_DetermineFileDelimiter( path, &delimiter, &hasCommentLine, &commentLine ) == FALSE )
04602   {
04603     MTX_ERROR_MSG( "MTX_DetermineFileDelimiter returned FALSE." );
04604     return FALSE;
04605   }
04606 
04607   // check if this is a binary compressed matrix
04608   if( delimiter == 'b' )
04609   {
04610     // fill in later
04611     if( MTX_ReadCompressed( M, path ) )
04612     {
04613       return TRUE;
04614     }
04615     else
04616     {
04617       MTX_ERROR_MSG( "MTX_ReadCompressed returned FALSE." );
04618       return FALSE;
04619     }
04620   }
04621 
04622   // determine the size of the file
04623   if( MTX_DetermineFileSize( path, &fsize ) == FALSE )
04624   {
04625     MTX_ERROR_MSG( "MTX_DetermineFileSize returned FALSE." );
04626     return FALSE;
04627   }
04628 
04629   // open the input file for full input operations
04630 #ifndef _CRT_SECURE_NO_DEPRECATE
04631   if( fopen_s( &in, path, "r" ) != 0 )
04632   {
04633     MTX_ERROR_MSG( "fopen_s returned failure." );
04634     return FALSE;
04635   }
04636 #else
04637   in = fopen( path, "r" );
04638 #endif
04639   if( !in )
04640   {
04641 #ifndef _CRT_SECURE_NO_DEPRECATE
04642     if( sprintf_s( linebuf, MTX_MAX_READFROMFILE_BUFFER, "Unable to open %s.", path ) > 0 )
04643       MTX_ERROR_MSG( linebuf );
04644 #else
04645     if( sprintf( linebuf, "Unable to open %s.", path ) > 0 )
04646       MTX_ERROR_MSG( linebuf );
04647 #endif
04648     return FALSE;
04649   }
04650 
04651   // advance over whitespace lines at the beginning of the file
04652   if( !MTX_static_get_next_valid_data_line( in, linebuf, &line_length, &atEOF ) )
04653   {
04654     MTX_ERROR_MSG( "MTX_static_get_next_valid_data_line returned FALSE." );
04655     return FALSE;
04656   }
04657   if( atEOF )
04658   {
04659     MTX_ERROR_MSG( "Unexpected end of file." );
04660     return FALSE;
04661   }
04662 
04663   if( hasCommentLine )
04664   {
04665     if( !MTX_static_get_next_valid_data_line( in, linebuf, &line_length, &atEOF ) )
04666     {
04667       MTX_ERROR_MSG( "MTX_static_get_next_valid_data_line returned FALSE." );
04668       return FALSE;
04669     }
04670     if( atEOF )
04671     {
04672       MTX_ERROR_MSG( "Unexpected end of file." );
04673       return FALSE;
04674     }
04675   }
04676 
04677   // check the first line for complex data
04678   if( !MTX_static_look_for_complex_data( linebuf, line_length, &complexDetected ) )
04679   {
04680     MTX_ERROR_MSG( "MTX_static_look_for_complex_data returned FALSE." );
04681     return FALSE;
04682   }
04683   if( complexDetected )
04684   {
04685     needToConvertRealToComplex = FALSE; // no need to convert, the entire matrix will be read in as complex.
04686     isReal = FALSE;
04687     // no need to convert anything though
04688   }
04689 
04690   // determine the number of columns in the matrix
04691   if( isReal )
04692   {
04693     if( !MTX_DetermineNumberOfColumnsInDataString( linebuf, &ncols ) )
04694     {
04695       MTX_ERROR_MSG( "MTX_DetermineNumberOfColumnsInDataString returned FALSE." );
04696       return FALSE;
04697     }
04698   }
04699   else
04700   {
04701     if( !MTX_DetermineNumberOfColumnsInDataStringCplx( linebuf, delimiter, &ncols ) )
04702     {
04703       MTX_ERROR_MSG( "MTX_DetermineNumberOfColumnsInDataStringCplx returned FALSE." );
04704       return FALSE;
04705     }
04706   }
04707 
04708 
04709   // super fast rowwise input routine
04710   // a rowwise matrix is constructed using a linked list approach
04711   // line by line input.
04712   // The matrix can even be entirely real for all but the last line.
04713   // The matrix will treat it's input as real until complex data is
04714   // detected. The ensuing data will all be read as complex. Once
04715   // all data is read in, any initial real row arrays are converted
04716   // into complex data. In this was all real matrices are very efficiently
04717   // read and so are complex matrices. The file is only read once.
04718   nrows = 0;
04719   if( isReal )
04720   {
04721     head.isReal = TRUE;
04722     head.rowptr = (double*)malloc( ncols*sizeof(double) );
04723 
04724     // get the row data from the string and store it in the list item row array
04725     if( !MTX_static_get_row_array_from_string( linebuf, &head, ncols ) )
04726     {
04727       // must free head's rowarray
04728       free( head.rowptr );
04729       MTX_ERROR_MSG( "MTX_static_get_row_array_from_string returned false." );
04730       return FALSE;
04731     }
04732   }
04733   else
04734   {
04735     head.isReal = FALSE;
04736     head.rowptr_cplx = (stComplex*)malloc( ncols*sizeof(stComplex) );
04737 
04738     // get the row data from the string and store it in the list item row array
04739     if( MTX_static_get_row_array_from_string_cplx( linebuf, delimiter, &head, ncols ) == FALSE )
04740     {
04741       // must free head's rowarray
04742       free( head.rowptr_cplx );
04743       MTX_ERROR_MSG( "MTX_static_get_row_array_from_string_cplx returned false." );
04744       return FALSE;
04745     }
04746   }
04747   nrows++;
04748   nL = &head;
04749 
04750   while(1)
04751   {
04752     // get the next string of data
04753     if( !MTX_static_get_next_valid_data_line( in, linebuf, &line_length, &atEOF ) )
04754     {
04755       errorInReadingDataFile = TRUE;
04756       break;
04757     }
04758     if( atEOF )
04759     {
04760       break;
04761     }
04762 
04763     // If the matrix is currently real, check this line for complex data.
04764     if( isReal )
04765     {
04766       if( !MTX_static_look_for_complex_data( linebuf, line_length, &complexDetected ) )
04767       {
04768         MTX_ERROR_MSG( "MTX_static_look_for_complex_data returned FALSE." );
04769         return FALSE;
04770       }
04771 
04772       if( complexDetected )
04773       {
04774         isReal = FALSE;
04775         needToConvertRealToComplex = TRUE; // there is mixed real rows and complex rows, so conversion is needed.
04776       }
04777     }
04778 
04779     // the 'current' list itme
04780     L = nL;
04781 
04782     // allocate the next list item
04783     nL = (_MTX_STRUCT_ReadFromFileListElem*)malloc( sizeof( _MTX_STRUCT_ReadFromFileListElem ) );
04784     if( !nL )
04785     {
04786       // memory allocate failure
04787       // must free the linked list
04788       errorInReadingDataFile = TRUE;
04789       MTX_ERROR_MSG( "if( !nL )" );
04790       return FALSE;
04791     }
04792 
04793     // intialize the row
04794     nL->isReal = isReal;
04795     nL->rowptr = NULL;
04796     nL->rowptr_cplx = NULL;
04797     nL->next = NULL;
04798 
04799     // allocate the row
04800     if( isReal )
04801     {
04802       nL->rowptr = (double*)malloc( ncols*sizeof(double) );
04803       if( !nL->rowptr )
04804       {
04805         // memory allocate failure
04806         // must free the linked list
04807         errorInReadingDataFile = TRUE;
04808         break;
04809       }
04810     }
04811     else
04812     {
04813       nL->rowptr_cplx = (stComplex*)malloc( ncols*sizeof(stComplex) );
04814       if( !nL->rowptr_cplx )
04815       {
04816         // memory allocate failure
04817         // must free the linked list
04818         errorInReadingDataFile = TRUE;
04819         break;
04820       }
04821     }
04822 
04823     // store the pointer to the next list item
04824     // in the 'current'
04825     L->next = nL;
04826 
04827     if( isReal )
04828     {
04829       // get the row data from the string and store it in the list item row array
04830       if( MTX_static_get_row_array_from_string( linebuf, nL, ncols ) == FALSE )
04831       {
04832         // must free the linked list
04833         errorInReadingDataFile = TRUE;
04834         break;
04835       }
04836     }
04837     else
04838     {
04839       // get the row data from the string and store it in the list item row array
04840       if( MTX_static_get_row_array_from_string_cplx( linebuf, delimiter, nL, ncols ) == FALSE )
04841       {
04842         // must free the linked list
04843         errorInReadingDataFile = TRUE;
04844         break;
04845       }
04846     }
04847     nrows++;
04848   }
04849 
04850   if( errorInReadingDataFile )
04851   {
04852     // free the list
04853     L = head.next;
04854     while( L!=NULL )
04855     {
04856       nL = L->next;
04857       if( L->isReal )
04858       {
04859         free( L->rowptr );
04860       }
04861       else
04862       {
04863         free( L->rowptr_cplx );
04864       }
04865       free(L);
04866       L = nL;
04867     }
04868     if( head.isReal )
04869     {
04870       free( head.rowptr );
04871     }
04872     else
04873     {
04874       free( head.rowptr_cplx );
04875     }
04876 
04877     MTX_ERROR_MSG( "if( errorInReadingDataFile )" );
04878     return FALSE;
04879   }
04880 
04881 
04882   // If there are mixed real and complex rows, the real rows must be converted to complex.
04883   if( needToConvertRealToComplex )
04884   {
04885     L = &head;
04886     // go through the linked list until the data changes from real to complex
04887 
04888     while( L->isReal )
04889     {
04890       L->rowptr_cplx = (stComplex*)malloc( ncols*sizeof(stComplex) );
04891       if( !L->rowptr_cplx )
04892       {
04893         // memory allocate failure
04894         // must free the linked list
04895         errorInReadingDataFile = TRUE;
04896         break;
04897       }
04898 
04899       // copy the data from the real row vector to the complex row vector
04900       for( i = 0; i < ncols; i++ )
04901       {
04902         L->rowptr_cplx[i].re = L->rowptr[i];
04903         L->rowptr_cplx[i].im = 0.0;
04904       }
04905 
04906       // free the real vector
04907       if( L->isReal )
04908       {
04909         free( L->rowptr );
04910       }
04911       L->rowptr = NULL;
04912 
04913       // move to the next item
04914       L = L->next;
04915 
04916       // break at the end of the list, this shouldn't ever happen though.
04917       if( L == NULL )
04918         break;
04919     }
04920   }
04921 
04922 
04923 
04924   /////
04925   // copy the list into a MTX object
04926 
04927   // first allocate the row array of pointers
04928   if( isReal )
04929   {
04930     RowMatrix.isReal = TRUE;
04931     RowMatrix.data = (double**)malloc( nrows*sizeof(double*) );
04932     if( !RowMatrix.data )
04933     {
04934       MTX_ERROR_MSG( "malloc returned NULL." );
04935       return FALSE;
04936     }
04937   }
04938   else
04939   {
04940     RowMatrix.isReal = FALSE;
04941     RowMatrix.cplx = (stComplex**)malloc( nrows*sizeof(stComplex*) );
04942     if( !RowMatrix.cplx )
04943     {
04944       MTX_ERROR_MSG( "malloc returned NULL." );
04945       return FALSE;
04946     }
04947   }
04948   // looks weird but this is rowwise input
04949   RowMatrix.ncols = nrows;
04950   RowMatrix.nrows = ncols;
04951 
04952   L = &head;
04953   for( i = 0; i < nrows; i++ )
04954   {
04955     if( L == NULL )
04956     {
04957       // this should never happen
04958       MTX_ERROR_MSG( "if( L == NULL ) - This should never happen." );
04959       return FALSE;
04960     }
04961     if( isReal )
04962     {
04963       RowMatrix.data[i] = L->rowptr; // only copying a pointer!
04964     }
04965     else
04966     {
04967       RowMatrix.cplx[i] = L->rowptr_cplx; // only copying a pointer!
04968     }
04969     L = L->next;
04970   }
04971 
04972   // copy the data by means of transpose
04973   // this places the data in the correct MTX storage format
04974   // only one copy operation
04975   if( !MTX_Transpose( &RowMatrix, M ) )
04976   {
04977     errorInTranspose = TRUE;
04978   }
04979 
04980   if( commentLine != NULL )
04981   {
04982     // Set the comment line.
04983     M->comment = commentLine;
04984   }
04985 
04986   // free the list data and the list items
04987   L = head.next;
04988   while( L!=NULL )
04989   {
04990     nL = L->next;
04991     if( isReal )
04992     {
04993       free( L->rowptr );
04994     }
04995     else
04996     {
04997       free( L->rowptr_cplx );
04998     }
04999     free(L);
05000     L = nL;
05001   }
05002   // free the head data
05003   if( isReal )
05004   {
05005     free( head.rowptr );
05006   }
05007   else
05008   {
05009     free( head.rowptr_cplx );
05010   }
05011 
05012   // free the RowMatrix data ptr
05013   if( isReal )
05014   {
05015     free( RowMatrix.data );
05016   }
05017   else
05018   {
05019     free( RowMatrix.cplx );
05020   }
05021 
05022   if( errorInTranspose )
05023   {
05024     MTX_ERROR_MSG( "if( errorInTranspose )" );
05025     return FALSE;
05026   }
05027   else
05028   {
05029     return TRUE;
05030   }
05031 }
05032 
05033 // Reads in the matrix (real or complex) from the specified file using the indicated *delimiter
05034 // ReadFromFile is 'read smart' (it determines the size of the input matrix on its own)
05035 // The number of columns are first determined then all data is read into linked lists
05036 // untill end of file is reached. Data is then stored in the matrix. The input is treated as
05037 // complex.
05038 BOOL MTX_SetFromMatrixString( MTX *M, const char *strMatrix )
05039 {
05040   unsigned i;
05041   const char delimiter = 'w'; // The file delimiter ('w' is whitespace delimited). Comma delimters are replace with whitespace.
05042   char strMatrixCopy[MTX_MAX_READFROMFILE_BUFFER]; // A fairly large buffer for copying the strMatrix.
05043   char linebuf[MTX_MAX_READFROMFILE_BUFFER]; // A fairly large line buffer.
05044   unsigned ncols = 0; // The number of columns determined in the matrix.
05045   unsigned nrows = 0; // The number of rows determined in the matrix.
05046   unsigned line_length = 0; // The length of the linebuf buffer.
05047   unsigned strMatrixLength = 0; // The length of the input string matrix.
05048   unsigned strMatrixIndex = 0; // An index into the copy of the strMatrix string.
05049   BOOL errorInReadingData = FALSE; // A boolean to indicate an error in reading the data file.
05050   BOOL errorInTranspose = FALSE; // A boolean to indicate an error in the transpose operation at the end.
05051   BOOL atEndOfString = FALSE; // A boolean to indicate when end of string is reached.
05052   BOOL isReal = TRUE; // A boolean to indicate if the matrix is real or complex.
05053   BOOL complexDetected = FALSE; // A boolean to indicate that complex data has been detected.
05054   BOOL needToConvertRealToComplex = FALSE; // A boolean to indicate if the matrix was real and needs to be converted to complex.
05055   MTX RowMatrix; // A rowwise storage version of the matrix. The transpose of this matrix is the final result.
05056 
05057   // A linked list of row arrays (of either real or complex data).
05058   _MTX_STRUCT_ReadFromFileListElem *L = NULL; // The current list item.
05059   _MTX_STRUCT_ReadFromFileListElem *nL = NULL; // The next list item.
05060   _MTX_STRUCT_ReadFromFileListElem head; // The head of the list.
05061   head.next = NULL;
05062   head.rowptr = NULL;
05063 
05064   // sanity check
05065   if( strMatrix == NULL )
05066   {
05067     MTX_ERROR_MSG( "strMatrix is NULL." );
05068     return FALSE;
05069   }
05070 
05071   strMatrixLength = (unsigned int)strlen( strMatrix );
05072   if( strMatrixLength == 0 )
05073   {
05074     MTX_ERROR_MSG( "if( strMatrixLength == 0 )" );
05075     return FALSE;
05076   }
05077 
05078   // overrun check
05079   if( strMatrixLength+1 > MTX_MAX_READFROMFILE_BUFFER ) // plus one for the null terminator
05080   {
05081     MTX_ERROR_MSG( "if( strMatrixLength+1 > MTX_MAX_READFROMFILE_BUFFER )" );
05082     return FALSE;
05083   }
05084 
05085   // initialize the single row container
05086   MTX_Init( &RowMatrix );
05087 
05088   // operate on a copy of strMatrix
05089 #ifndef _CRT_SECURE_NO_DEPRECATE
05090   if( strncpy_s( strMatrixCopy, MTX_MAX_READFROMFILE_BUFFER, strMatrix, strMatrixLength ) != 0 )
05091   {
05092     MTX_ERROR_MSG( "strncpy_s returned failure." );
05093     return FALSE;
05094   }
05095 #else
05096   strncpy( strMatrixCopy, strMatrix, strMatrixLength );
05097 #endif
05098   strMatrixCopy[strMatrixLength] = '\0';
05099 
05100   // replace ;'s with the newline character and ',' with ' '
05101   // replace '[' and ']' with ' '
05102   for( i = 0; i < strMatrixLength; i++ )
05103   {
05104     if( strMatrixCopy[i] == ',' )
05105     {
05106       strMatrixCopy[i] = ' ';
05107     }
05108     else if( strMatrixCopy[i] == ';' )
05109     {
05110       strMatrixCopy[i] = '\n';
05111     }
05112     else if( strMatrixCopy[i] == '[' )
05113     {
05114       strMatrixCopy[i] = ' ';
05115     }
05116     else if( strMatrixCopy[i] == ']' )
05117     {
05118       strMatrixCopy[i] = ' ';
05119     }
05120   }
05121 
05122   // advance over whitespace lines at the beginning of the matrix in the string
05123   if( !MTX_static_get_next_valid_data_line_from_matrix_string(
05124     strMatrixCopy,
05125     strMatrixLength,
05126     &strMatrixIndex,
05127     linebuf,
05128     &line_length,
05129     &atEndOfString ) )
05130   {
05131     MTX_ERROR_MSG( "MTX_static_get_next_valid_data_line_from_matrix_string returned FALSE." );
05132     return FALSE;
05133   }
05134   if( atEndOfString )
05135   {
05136     MTX_ERROR_MSG( "Unexpected end of string." );
05137     return FALSE;
05138   }
05139 
05140   // check the first line for complex data
05141   if( !MTX_static_look_for_complex_data( linebuf, line_length, &complexDetected ) )
05142   {
05143     MTX_ERROR_MSG( "MTX_static_look_for_complex_data returned FALSE." );
05144     return FALSE;
05145   }
05146   if( complexDetected )
05147   {
05148     needToConvertRealToComplex = FALSE; // no need to convert, the entire matrix will be read in as complex.
05149     isReal = FALSE;
05150     // no need to convert anything though
05151   }
05152 
05153   // determine the number of columns in the matrix
05154   if( isReal )
05155   {
05156     if( !MTX_DetermineNumberOfColumnsInDataString( linebuf, &ncols ) )
05157     {
05158       MTX_ERROR_MSG( "MTX_DetermineNumberOfColumnsInDataString returned FALSE." );
05159       return FALSE;
05160     }
05161   }
05162   else
05163   {
05164     if( !MTX_DetermineNumberOfColumnsInDataStringCplx( linebuf, delimiter, &ncols ) )
05165     {
05166       MTX_ERROR_MSG( "MTX_DetermineNumberOfColumnsInDataStringCplx returned FALSE." );
05167       return FALSE;
05168     }
05169   }
05170 
05171   // super fast rowwise input routine
05172   // a rowwise matrix is constructed using a linked list approach
05173   // line by line input.
05174   // The matrix can even be entirely real for all but the last line.
05175   // The matrix will treat it's input as real until complex data is
05176   // detected. The ensuing data will all be read as complex. Once
05177   // all data is read in, any initial real row arrays are converted
05178   // into complex data. In this was all real matrices are very efficiently
05179   // read and so are complex matrices. The file is only read once.
05180   nrows = 0;
05181   if( isReal )
05182   {
05183     head.isReal = TRUE;
05184     head.rowptr = (double*)malloc( ncols*sizeof(double) );
05185 
05186     // get the row data from the string and store it in the list item row array
05187     if( !MTX_static_get_row_array_from_string( linebuf, &head, ncols ) )
05188     {
05189       // must free head's rowarray
05190       free( head.rowptr );
05191       MTX_ERROR_MSG( "malloc returned NULL." );
05192       return FALSE;
05193     }
05194   }
05195   else
05196   {
05197     head.isReal = FALSE;
05198     head.rowptr_cplx = (stComplex*)malloc( ncols*sizeof(stComplex) );
05199 
05200     // get the row data from the string and store it in the list item row array
05201     if( MTX_static_get_row_array_from_string_cplx( linebuf, delimiter, &head, ncols ) == FALSE )
05202     {
05203       // must free head's rowarray
05204       free( head.rowptr_cplx );
05205       MTX_ERROR_MSG( "malloc returned NULL." );
05206       return FALSE;
05207     }
05208   }
05209   nrows++;
05210   nL = &head;
05211 
05212   while(1)
05213   {
05214     // get the next string of data
05215     if( !MTX_static_get_next_valid_data_line_from_matrix_string(
05216       strMatrixCopy,
05217       strMatrixLength,
05218       &strMatrixIndex,
05219       linebuf,
05220       &line_length,
05221       &atEndOfString ) )
05222     {
05223       errorInReadingData = TRUE;
05224       break;
05225     }
05226     if( atEndOfString )
05227     {
05228       break;
05229     }
05230 
05231     // If the matrix is currently real, check this line for complex data.
05232     if( isReal )
05233     {
05234       if( !MTX_static_look_for_complex_data( linebuf, line_length, &complexDetected ) )
05235       {
05236         MTX_ERROR_MSG( "MTX_static_look_for_complex_data returned FALSE." );
05237         return FALSE;
05238       }
05239 
05240       if( complexDetected )
05241       {
05242         isReal = FALSE;
05243         needToConvertRealToComplex = TRUE; // there is mixed real rows and complex rows, so conversion is needed.
05244       }
05245     }
05246 
05247     // the 'current' list itme
05248     L = nL;
05249 
05250     // allocate the next list item
05251     nL = (_MTX_STRUCT_ReadFromFileListElem*)malloc( sizeof( _MTX_STRUCT_ReadFromFileListElem ) );
05252     if( !nL )
05253     {
05254       // memory allocate failure
05255       // must free the linked list
05256       errorInReadingData = TRUE;
05257       break;
05258     }
05259 
05260     // intialize the row
05261     nL->isReal = isReal;
05262     nL->rowptr = NULL;
05263     nL->rowptr_cplx = NULL;
05264     nL->next = NULL;
05265 
05266     // allocate the row
05267     if( isReal )
05268     {
05269       nL->rowptr = (double*)malloc( ncols*sizeof(double) );
05270       if( !nL->rowptr )
05271       {
05272         // memory allocate failure
05273         // must free the linked list
05274         errorInReadingData = TRUE;
05275         break;
05276       }
05277     }
05278     else
05279     {
05280       nL->rowptr_cplx = (stComplex*)malloc( ncols*sizeof(stComplex) );
05281       if( !nL->rowptr_cplx )
05282       {
05283         // memory allocate failure
05284         // must free the linked list
05285         errorInReadingData = TRUE;
05286         break;
05287       }
05288     }
05289 
05290     // store the pointer to the next list item
05291     // in the 'current'
05292     L->next = nL;
05293 
05294     if( isReal )
05295     {
05296       // get the row data from the string and store it in the list item row array
05297       if( MTX_static_get_row_array_from_string( linebuf, nL, ncols ) == FALSE )
05298       {
05299         // must free the linked list
05300         errorInReadingData = TRUE;
05301         break;
05302       }
05303     }
05304     else
05305     {
05306       // get the row data from the string and store it in the list item row array
05307       if( MTX_static_get_row_array_from_string_cplx( linebuf, delimiter, nL, ncols ) == FALSE )
05308       {
05309         // must free the linked list
05310         errorInReadingData = TRUE;
05311         break;
05312       }
05313     }
05314     nrows++;
05315   }
05316 
05317   if( errorInReadingData )
05318   {
05319     // free the list
05320     L = head.next;
05321     while( L!=NULL )
05322     {
05323       nL = L->next;
05324       if( L->isReal )
05325       {
05326         free( L->rowptr );
05327       }
05328       else
05329       {
05330         free( L->rowptr_cplx );
05331       }
05332       free(L);
05333       L = nL;
05334     }
05335     if( head.isReal )
05336     {
05337       free( head.rowptr );
05338     }
05339     else
05340     {
05341       free( head.rowptr_cplx );
05342     }
05343     MTX_ERROR_MSG( "if( errorInReadingData )" );
05344     return FALSE;
05345   }
05346 
05347 
05348   // If there are mixed real and complex rows, the real rows must be converted to complex.
05349   if( needToConvertRealToComplex )
05350   {
05351     L = &head;
05352     // go through the linked list until the data changes from real to complex
05353 
05354     while( L->isReal )
05355     {
05356       L->rowptr_cplx = (stComplex*)malloc( ncols*sizeof(stComplex) );
05357       if( !L->rowptr_cplx )
05358       {
05359         // memory allocate failure
05360         // must free the linked list
05361         errorInReadingData = TRUE;
05362         break;
05363       }
05364 
05365       // copy the data from the real row vector to the complex row vector
05366       for( i = 0; i < ncols; i++ )
05367       {
05368         L->rowptr_cplx[i].re = L->rowptr[i];
05369         L->rowptr_cplx[i].im = 0.0;
05370       }
05371 
05372       // free the real vector
05373       if( L->isReal )
05374       {
05375         free( L->rowptr );
05376       }
05377       L->rowptr = NULL;
05378 
05379       // move to the next item
05380       L = L->next;
05381 
05382       // break at the end of the list, this shouldn't ever happen though.
05383       if( L == NULL )
05384         break;
05385     }
05386   }
05387 
05388 
05389 
05390   /////
05391   // copy the list into a MTX object
05392 
05393   // first allocate the row array of pointers
05394   if( isReal )
05395   {
05396     RowMatrix.isReal = TRUE;
05397     RowMatrix.data = (double**)malloc( nrows*sizeof(double*) );
05398     if( !RowMatrix.data )
05399     {
05400       MTX_ERROR_MSG( "malloc returned FALSE." );
05401       return FALSE;
05402     }
05403   }
05404   else
05405   {
05406     RowMatrix.isReal = FALSE;
05407     RowMatrix.cplx = (stComplex**)malloc( nrows*sizeof(stComplex*) );
05408     if( !RowMatrix.cplx )
05409     {
05410       MTX_ERROR_MSG( "malloc returned FALSE." );
05411       return FALSE;
05412     }
05413   }
05414   // looks weird but this is rowwise input
05415   RowMatrix.ncols = nrows;
05416   RowMatrix.nrows = ncols;
05417 
05418   L = &head;
05419   for( i = 0; i < nrows; i++ )
05420   {
05421     if( L == NULL )
05422     {
05423       // this should never happen
05424       MTX_ERROR_MSG( "if( L == NULL ) - this should never happen." );
05425       return FALSE;
05426     }
05427     if( isReal )
05428     {
05429       RowMatrix.data[i] = L->rowptr; // only copying a pointer!
05430     }
05431     else
05432     {
05433       RowMatrix.cplx[i] = L->rowptr_cplx; // only copying a pointer!
05434     }
05435     L = L->next;
05436   }
05437 
05438   // copy the data by means of transpose
05439   // this places the data in the correct MTX storage format
05440   // only one copy operation
05441   // If M previously held other data, it is dealt with accordingly.
05442   if( !MTX_Transpose( &RowMatrix, M ) )
05443   {
05444     errorInTranspose = TRUE;
05445   }
05446 
05447   // free the list data and the list items
05448   L = head.next;
05449   while( L!=NULL )
05450   {
05451     nL = L->next;
05452     if( isReal )
05453     {
05454       free( L->rowptr );
05455     }
05456     else
05457     {
05458       free( L->rowptr_cplx );
05459     }
05460     free(L);
05461     L = nL;
05462   }
05463   // free the head data
05464   if( isReal )
05465   {
05466     free( head.rowptr );
05467   }
05468   else
05469   {
05470     free( head.rowptr_cplx );
05471   }
05472 
05473   // free the RowMatrix data ptr
05474   if( isReal )
05475   {
05476     free( RowMatrix.data );
05477   }
05478   else
05479   {
05480     free( RowMatrix.cplx );
05481   }
05482 
05483   if( errorInTranspose )
05484   {
05485     MTX_ERROR_MSG( "if( errorInTranspose )" );
05486     return FALSE;
05487   }
05488   else
05489   {
05490     return TRUE;
05491   }
05492 }
05493 
05494 
05495 
05496 
05497 
05498 BOOL MTX_ValueToString(
05499                        const double value, //!< The double value to output.
05500                        const unsigned width, //!< The width of the field.
05501                        const unsigned precision, //!< The precision, %g style.
05502                        const BOOL isReal, //!< The the value the real part or the imaginary part.
05503                        const BOOL alignLeft, //!< Align the output left (for real data only).
05504                        char *ValueBuffer, //!< The output buffer.
05505                        const unsigned ValueBufferSize //!< The size of the output buffer.
05506                        )
05507 {
05508   char format[16];
05509   char valbuf[512];
05510 #ifdef _CRT_SECURE_NO_DEPRECATE
05511   char tmpbuf[1024];
05512 #endif
05513   char* strptr;
05514 
05515   if( width == 0 )
05516   {
05517     MTX_ERROR_MSG( "if( width == 0 )" );
05518     return FALSE;
05519   }
05520 
05521   valbuf[0] = '\0';
05522 
05523 #ifndef _CRT_SECURE_NO_DEPRECATE
05524   // special case, only output rounded integer data
05525   if( precision == 0 )
05526   {
05527     if( isReal )
05528     {
05529       if( value < 0 )
05530       {
05531         if( sprintf_s( valbuf, 512, "%d", (int)(-floor( -value + 0.5 )) ) < 0 )
05532         {
05533           MTX_ERROR_MSG( "sprintf_s returned failure." );
05534           return FALSE;
05535         }
05536       }
05537       else
05538       {
05539         if( sprintf_s( valbuf, 512, " %d", (int)(floor( value + 0.5 )) ) < 0 )
05540         {
05541           MTX_ERROR_MSG( "sprintf_s returned failure." );
05542           return FALSE;
05543         }
05544       }
05545     }
05546     else
05547     {
05548       if( value < 0 )
05549       {
05550         if( sprintf_s( valbuf, 512, "%+di", (int)(-floor( -value + 0.5 )) ) < 0 )
05551         {
05552           MTX_ERROR_MSG( "sprintf_s returned failure." );
05553           return FALSE;
05554         }
05555       }
05556       else
05557       {
05558         if( sprintf_s( valbuf, 512, "%+di", (int)(floor( value + 0.5 )) ) < 0 )
05559         {
05560           MTX_ERROR_MSG( "sprintf_s returned failure." );
05561           return FALSE;
05562         }
05563       }
05564     }
05565   }
05566   else
05567   {
05568     if( isReal )
05569     {
05570       if( sprintf_s( format, 16, "%% .%dg", precision ) < 0 ) // using the 'blank' flag
05571       {
05572         MTX_ERROR_MSG( "sprintf_s returned failure." );
05573         return FALSE;
05574       }
05575       if( sprintf_s( valbuf, 512, format, value ) < 0 )
05576       {
05577         MTX_ERROR_MSG( "sprintf_s returned failure." );
05578         return FALSE;
05579       }
05580     }
05581     else
05582     {
05583       if( sprintf_s( format, 16, "%%+.%dgi", precision ) < 0 )
05584       {
05585         MTX_ERROR_MSG( "sprintf_s returned failure." );
05586         return FALSE;
05587       }
05588       if( sprintf_s( valbuf, 512, format, value ) < 0 )
05589       {
05590         MTX_ERROR_MSG( "sprintf_s returned failure." );
05591         return FALSE;
05592       }
05593     }
05594   }
05595 
05596   if( alignLeft )
05597   {
05598     if( sprintf_s( format, 16, "%%-%ds", width ) < 0 ) // left align flag
05599     {
05600       MTX_ERROR_MSG( "sprintf_s returned failure." );
05601       return FALSE;
05602     }
05603   }
05604   else
05605   {
05606     if( sprintf_s( format, 16, "%%%ds", width ) < 0 )
05607     {
05608       MTX_ERROR_MSG( "sprintf_s returned failure." );
05609       return FALSE;
05610     }
05611   }
05612 
05613   if( sprintf_s( ValueBuffer, ValueBufferSize, format, valbuf ) < 0 )
05614   {
05615     MTX_ERROR_MSG( "sprintf_s returned failure." );
05616     return FALSE;
05617   }
05618 
05619 #else
05620   // special case, only output rounded integer data
05621   if( precision == 0 )
05622   {
05623     if( isReal )
05624     {
05625       if( value < 0 )
05626       {
05627         if( sprintf( valbuf, "%d", (int)(-floor( -value + 0.5 )) ) < 0 )
05628         {
05629           MTX_ERROR_MSG( "sprintf returned failure." );
05630           return FALSE;
05631         }
05632       }
05633       else
05634       {
05635         if( sprintf( valbuf, " %d", (int)(floor( value + 0.5 )) ) < 0 )
05636         {
05637           MTX_ERROR_MSG( "sprintf returned failure." );
05638           return FALSE;
05639         }
05640       }
05641     }
05642     else
05643     {
05644       if( value < 0 )
05645       {
05646         if( sprintf( valbuf, "%+di", (int)(-floor( -value + 0.5 )) ) < 0 )
05647         {
05648           MTX_ERROR_MSG( "sprintf returned failure." );
05649           return FALSE;
05650         }
05651       }
05652       else
05653       {
05654         if( sprintf( valbuf, "%+di", (int)(floor( value + 0.5 )) ) < 0 )
05655         {
05656           MTX_ERROR_MSG( "sprintf returned failure." );
05657           return FALSE;
05658         }
05659       }
05660     }
05661   }
05662   else
05663   {
05664     if( isReal )
05665     {
05666       if( sprintf( format, "%% .%dg", precision ) < 0 ) // using the 'blank' flag
05667       {
05668         MTX_ERROR_MSG( "sprintf returned failure." );
05669         return FALSE;
05670       }
05671       if( sprintf( valbuf, format, value ) < 0 )
05672       {
05673         MTX_ERROR_MSG( "sprintf returned failure." );
05674         return FALSE;
05675       }
05676     }
05677     else
05678     {
05679       if( sprintf( format, "%%+.%dgi", precision ) < 0 )
05680       {
05681         MTX_ERROR_MSG( "sprintf returned failure." );
05682         return FALSE;
05683       }
05684       if( sprintf( valbuf, format, value ) < 0 )
05685       {
05686         MTX_ERROR_MSG( "sprintf returned failure." );
05687         return FALSE;
05688       }
05689     }
05690   }
05691 
05692   if( alignLeft )
05693   {
05694     if( sprintf( format, "%%-%ds", width ) < 0 ) // left align flag
05695     {
05696       MTX_ERROR_MSG( "sprintf returned failure." );
05697       return FALSE;
05698     }
05699   }
05700   else
05701   {
05702     if( sprintf( format, "%%%ds", width ) < 0 )
05703     {
05704       MTX_ERROR_MSG( "sprintf returned failure." );
05705       return FALSE;
05706     }
05707   }
05708 
05709   if( sprintf( tmpbuf, format, valbuf ) < 0 )
05710   {
05711     MTX_ERROR_MSG( "sprintf returned failure." );
05712     return FALSE;
05713   }
05714   if( strlen(tmpbuf) >= ValueBufferSize )
05715   {
05716     MTX_ERROR_MSG( "ValueBufferSize not sufficient." );
05717     return FALSE;
05718   }
05719   strcpy( ValueBuffer, tmpbuf );  
05720 
05721 #endif
05722 
05723   // deal with "-0 " or "-0" output values.
05724   strptr = strstr( ValueBuffer, "-0" );
05725   if( strptr != NULL )
05726   {
05727     if( strptr[2] == '\0' || strptr[2] == ' ' )
05728       strptr[0] = ' '; // get rid of the negative value.
05729   }  
05730 
05731   return TRUE;
05732 }
05733 
05734 
05735 BOOL MTX_Print( const MTX *M, const char *path, const unsigned width, const unsigned precision, const BOOL append )
05736 {
05737   unsigned i = 0;
05738   unsigned j = 0;
05739   unsigned k = 0;
05740   char ValueBuffer[512];
05741   FILE* out;
05742 
05743   if( MTX_isNull( M ) )
05744   {
05745     MTX_ERROR_MSG( "NULL Matrix" );
05746     return FALSE;
05747   }
05748 
05749   if( M->ncols == 0 || M->nrows == 0 )
05750   {
05751     MTX_ERROR_MSG( "if( M->ncols == 0 || M->nrows == 0 )" );
05752     return FALSE;
05753   }
05754 
05755   if( precision > 200 )
05756   {
05757     MTX_ERROR_MSG( "if( precision > 200 )" );
05758     return FALSE;
05759   }
05760 
05761   if( width > 511 )
05762   {
05763     MTX_ERROR_MSG( "if( width > 511 )" );
05764     return FALSE;
05765   }
05766 
05767   ValueBuffer[0] = '\0';
05768 
05769   if( append )
05770   {
05771 #ifndef _CRT_SECURE_NO_DEPRECATE
05772     if( fopen_s( &out, path, "at+" ) != 0 )
05773     {
05774       MTX_ERROR_MSG( "fopen_s returned failure." );
05775       return FALSE;
05776     }
05777 #else
05778     out = fopen( path, "at+" );
05779 #endif
05780   }
05781   else
05782   {
05783 #ifndef _CRT_SECURE_NO_DEPRECATE
05784     if( fopen_s( &out, path, "w" ) != 0 )
05785     {
05786       MTX_ERROR_MSG( "fopen_s returned failure." );
05787       return FALSE;
05788     }
05789 #else
05790     out = fopen( path, "w" );
05791 #endif
05792   }
05793   if( !out )
05794   {
05795 #ifndef _CRT_SECURE_NO_DEPRECATE
05796     if( sprintf_s( ValueBuffer, 512, "Unable to open %s.", path ) > 0 )
05797       MTX_ERROR_MSG( ValueBuffer );
05798 #else
05799     if( sprintf( ValueBuffer, "Unable to open %s.", path ) > 0 )
05800       MTX_ERROR_MSG( ValueBuffer );
05801 #endif
05802     return FALSE;
05803   }
05804 
05805   if( M->isReal )
05806   {
05807     for( i = 0; i < M->nrows; i++ )
05808     {
05809       for( j = 0; j < M->ncols; j++ )
05810       {
05811         MTX_ValueToString( M->data[j][i], width, precision, TRUE, TRUE, ValueBuffer, 512 );
05812         fprintf( out, ValueBuffer );
05813       }
05814       fprintf( out, "\n" );
05815     }
05816   }
05817   else
05818   {
05819     for( i = 0; i < M->nrows; i++ )
05820     {
05821       for( j = 0; j < M->ncols; j++ )
05822       {
05823         if( M->cplx[j][i].im == 0 )
05824         {
05825           // output only the real component
05826           MTX_ValueToString( M->cplx[j][i].re, width, precision, TRUE, FALSE, ValueBuffer, 512 );
05827           fprintf( out, ValueBuffer );
05828           for( k = 0; k < width; k++ )
05829             fprintf( out, " " );
05830         }
05831         else
05832         {
05833           // output both
05834           MTX_ValueToString( M->cplx[j][i].re, width, precision, TRUE, FALSE, ValueBuffer, 512 );
05835           fprintf( out, ValueBuffer );
05836           MTX_ValueToString( M->cplx[j][i].im, width, precision, FALSE, TRUE, ValueBuffer, 512 );
05837           fprintf( out, ValueBuffer );
05838         }
05839       }
05840       fprintf( out, "\n" );
05841     }    
05842   }
05843   fclose(out);
05844 
05845   return TRUE;
05846 }
05847 
05848 BOOL MTX_Print_ToBuffer( const MTX *M, char *buffer, const unsigned maxlength, const unsigned width, const unsigned precision )
05849 {
05850   unsigned i = 0;
05851   unsigned j = 0;
05852   unsigned k = 0;
05853   unsigned scount = 0;
05854   unsigned dcount = 0;
05855   BOOL endOfBuffer = FALSE;
05856   char ValueBuffer[512];
05857 
05858   if( MTX_isNull( M ) )
05859   {
05860     MTX_ERROR_MSG( "NULL Matrix" );
05861     return FALSE;
05862   }
05863 
05864   if( M->ncols == 0 || M->nrows == 0 )
05865   {
05866     MTX_ERROR_MSG( "if( M->ncols == 0 || M->nrows == 0 )" );
05867     return FALSE;
05868   }
05869 
05870   if( buffer == NULL )
05871   {
05872     MTX_ERROR_MSG( "buffer is NULL." );
05873     return FALSE;
05874   }
05875 
05876   if( maxlength == 0 )
05877   {
05878     MTX_ERROR_MSG( "if( maxlength == 0 )" );
05879     return FALSE;
05880   }
05881 
05882   if( precision > 200 )
05883   {
05884     MTX_ERROR_MSG( "if( precision > 200 )" );
05885     return FALSE;
05886   }
05887 
05888   if( width > 511 )
05889   {
05890     MTX_ERROR_MSG( "if( width > 511 )" );
05891     return FALSE;
05892   }
05893 
05894   ValueBuffer[0] = '\0';
05895 
05896   for( i = 0; i < M->nrows; i++ )
05897   {
05898     for( j = 0; j < M->ncols; j++ )
05899     {
05900       if( M->isReal )
05901       {
05902         MTX_ValueToString( M->data[j][i], width, precision, TRUE, TRUE, ValueBuffer, 512 );
05903         if( scount + width >= maxlength )
05904         {
05905           endOfBuffer = TRUE;
05906           break;
05907         }
05908 #ifndef _CRT_SECURE_NO_DEPRECATE
05909         dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
05910         if( dcount < 0 )
05911         {
05912           MTX_ERROR_MSG( "sprintf_s returned failure." );
05913           return FALSE;
05914         }
05915         scount += dcount;
05916 #else
05917         dcount = sprintf( buffer+scount, "%s", ValueBuffer );
05918         if( dcount < 0 )
05919         {
05920           MTX_ERROR_MSG( "sprintf returned failure." );
05921           return FALSE;
05922         }
05923         scount += dcount;
05924 #endif
05925       }
05926       else
05927       {
05928         if( M->cplx[j][i].im == 0 )
05929         {
05930           // output only the real component
05931           MTX_ValueToString( M->cplx[j][i].re, width, precision, TRUE, FALSE, ValueBuffer, 512 );
05932           if( scount + width >= maxlength )
05933           {
05934             endOfBuffer = TRUE;
05935             break;
05936           }
05937 #ifndef _CRT_SECURE_NO_DEPRECATE
05938           dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
05939           if( dcount < 0 )
05940           {
05941             MTX_ERROR_MSG( "sprintf_s returned failure." );
05942             return FALSE;
05943           }
05944           scount += dcount;
05945 
05946           for( k = 0; k < width; k++ )
05947           {
05948             dcount = sprintf_s( buffer+scount, maxlength-scount, " " );
05949             if( dcount < 0 )
05950             {
05951               MTX_ERROR_MSG( "sprintf_s returned failure." );
05952               return FALSE;
05953             }
05954             scount += dcount;
05955           }
05956 #else
05957           dcount = sprintf( buffer+scount, "%s", ValueBuffer );
05958           if( dcount < 0 )
05959           {
05960             MTX_ERROR_MSG( "sprintf returned failure." );
05961             return FALSE;
05962           }
05963           scount += dcount;
05964 
05965           for( k = 0; k < width; k++ )
05966           {
05967             dcount = sprintf( buffer+scount, " " );
05968             if( dcount < 0 )
05969             {
05970               MTX_ERROR_MSG( "sprintf returned failure." );
05971               return FALSE;
05972             }
05973             scount += dcount;
05974           }
05975 #endif
05976         }
05977         else
05978         {
05979           // output both components
05980           MTX_ValueToString( M->cplx[j][i].re, width, precision, TRUE, FALSE, ValueBuffer, 512 );
05981           if( scount + width >= maxlength )
05982           {
05983             endOfBuffer = TRUE;
05984             break;
05985           }
05986 
05987 #ifndef _CRT_SECURE_NO_DEPRECATE
05988           dcount = sprintf_s( buffer+scount, maxlength - scount, "%s", ValueBuffer );
05989           if( dcount < 0 )
05990           {
05991             MTX_ERROR_MSG( "sprintf_s returned failure." );
05992             return FALSE;
05993           }
05994           scount += dcount;
05995 #else
05996           dcount = sprintf( buffer+scount, "%s", ValueBuffer );
05997           if( dcount < 0 )
05998           {
05999             MTX_ERROR_MSG( "sprintf returned failure." );
06000             return FALSE;
06001           }
06002           scount += dcount;
06003 #endif
06004 
06005           MTX_ValueToString( M->cplx[j][i].im, width, precision, FALSE, TRUE, ValueBuffer, 512 );
06006           if( scount + width >= maxlength )
06007           {
06008             endOfBuffer = TRUE;
06009             break;
06010           }
06011 
06012 #ifndef _CRT_SECURE_NO_DEPRECATE
06013           dcount = sprintf_s( buffer+scount, maxlength - scount, "%s", ValueBuffer );
06014           if( dcount < 0 )
06015           {
06016             MTX_ERROR_MSG( "sprintf_s returned failure." );
06017             return FALSE;
06018           }
06019           scount += dcount;
06020 #else
06021           dcount = sprintf( buffer+scount, "%s", ValueBuffer );
06022           if( dcount < 0 )
06023           {
06024             MTX_ERROR_MSG( "sprintf returned failure." );
06025             return FALSE;
06026           }
06027           scount += dcount;
06028 #endif
06029         }
06030       }
06031     }
06032     if( endOfBuffer )
06033       break;
06034     if( scount + 2 >= maxlength )
06035       break;
06036 
06037 #ifndef _CRT_SECURE_NO_DEPRECATE
06038     dcount = sprintf_s( buffer+scount, maxlength - scount, "\n" );
06039     if( dcount < 0 )
06040     {
06041       MTX_ERROR_MSG( "sprintf returned failure." );
06042       return FALSE;
06043     }
06044     scount += dcount;
06045 #else
06046     dcount = sprintf( buffer+scount, "\n" );
06047     if( dcount < 0 )
06048     {
06049       MTX_ERROR_MSG( "sprintf returned failure." );
06050       return FALSE;
06051     }
06052     scount += dcount;
06053 #endif
06054   }
06055 
06056   return TRUE;
06057 }
06058 
06059 
06060 
06061 
06062 
06063 BOOL MTX_PrintAutoWidth( const MTX *M, const char *path, const unsigned precision, const BOOL append )
06064 {
06065   unsigned i = 0;
06066   unsigned j = 0;
06067   unsigned k = 0;
06068   unsigned n = 0;
06069   unsigned maxwidth = 0;
06070   unsigned maxwidth_im = 0;
06071   unsigned length = 0;
06072   unsigned *maxColumnWidth;
06073   char format[16];
06074   char ValueBuffer[512];
06075   FILE* out;
06076 
06077   if( MTX_isNull( M ) )
06078   {
06079     MTX_ERROR_MSG( "NULL Matrix" );
06080     return FALSE;
06081   }
06082 
06083   if( M->ncols == 0 || M->nrows == 0 )
06084   {
06085     MTX_ERROR_MSG( "if( M->ncols == 0 || M->nrows == 0 )" );
06086     return FALSE;
06087   }
06088 
06089   if( precision > 200 )
06090   {
06091     MTX_ERROR_MSG( "if( precision > 200 )" );
06092     return FALSE;
06093   }
06094 
06095   ValueBuffer[0] = '\0';
06096 
06097   if( append )
06098   {
06099 #ifndef _CRT_SECURE_NO_DEPRECATE
06100     if( fopen_s( &out, path, "at+" ) != 0 )
06101     {
06102       MTX_ERROR_MSG( "fopen_s failed to open the file." );
06103       return FALSE;
06104     }
06105 #else
06106     out = fopen( path, "at+" );
06107 #endif
06108   }
06109   else
06110   {
06111 #ifndef _CRT_SECURE_NO_DEPRECATE
06112     if( fopen_s( &out, path, "w" ) != 0 )
06113     {
06114       MTX_ERROR_MSG( "fopen_s failed to open the file." );
06115       return FALSE;
06116     }
06117 #else
06118     out = fopen( path, "w" );
06119 #endif
06120   }
06121   if( !out )
06122   {
06123 #ifndef _CRT_SECURE_NO_DEPRECATE
06124     if( sprintf_s( ValueBuffer, 512, "Unable to open %s.", path ) > 0 )
06125       MTX_ERROR_MSG( ValueBuffer );
06126 #else
06127     if( sprintf( ValueBuffer, "Unable to open %s.", path ) > 0 )
06128       MTX_ERROR_MSG( ValueBuffer );
06129 #endif
06130     return FALSE;
06131   }
06132 
06133   if( M->isReal )
06134     n = M->ncols;
06135   else
06136     n = M->ncols*2;
06137 
06138   maxColumnWidth = (unsigned*)malloc( sizeof(unsigned)*n );
06139   if( !maxColumnWidth )
06140   {
06141     fclose(out);
06142     MTX_ERROR_MSG( "malloc returned NULL." );
06143     return FALSE;
06144   }
06145 
06146   if( M->isReal )
06147   {
06148     for( j = 0; j < M->ncols; j++ )
06149     {
06150       // determine the maximum width needed for the given precision
06151       maxwidth = 0;
06152       for( i = 0; i < M->nrows; i++ )
06153       {
06154 #ifndef _CRT_SECURE_NO_DEPRECATE
06155         if( sprintf_s( format, 16, "%% .%dg", precision ) < 0 )
06156         {
06157           MTX_ERROR_MSG( "sprintf_s returned failure." );
06158           return FALSE;
06159         }
06160         if( sprintf_s( ValueBuffer, 512, format, M->data[j][i] ) < 0 )
06161         {
06162           MTX_ERROR_MSG( "sprintf_s returned failure." );
06163           return FALSE;
06164         }
06165 #else
06166         if( sprintf( format, "%% .%dg", precision ) < 0 )
06167         {
06168           MTX_ERROR_MSG( "sprintf returned failure." );
06169           return FALSE;
06170         }
06171         if( sprintf( ValueBuffer, format, M->data[j][i] ) < 0 )
06172         {
06173           MTX_ERROR_MSG( "sprintf returned failure." );
06174           return FALSE;
06175         }
06176 #endif
06177         length = (unsigned int)strlen( ValueBuffer );
06178         if( length > maxwidth )
06179           maxwidth = length;
06180       }
06181       maxColumnWidth[j] = maxwidth+1;
06182     }
06183   }
06184   else
06185   {
06186     k = 0;
06187     for( j = 0; j < M->ncols; j++ )
06188     {
06189       // determine the maximum width needed for the given precision
06190       maxwidth = 0;
06191       maxwidth_im = 0;
06192       for( i = 0; i < M->nrows; i++ )
06193       {
06194 #ifndef _CRT_SECURE_NO_DEPRECATE
06195         if( sprintf_s( format, 16, "%% .%dg", precision ) < 0 )
06196         {
06197           MTX_ERROR_MSG( "sprintf_s returned failure." );
06198           return FALSE;
06199         }
06200         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
06201         {
06202           MTX_ERROR_MSG( "sprintf_s returned failure." );
06203           return FALSE;
06204         }
06205 #else
06206         if( sprintf( format, "%% .%dg", precision ) < 0 )
06207         {
06208           MTX_ERROR_MSG( "sprintf returned failure." );
06209           return FALSE;
06210         }
06211         if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
06212         {
06213           MTX_ERROR_MSG( "sprintf returned failure." );
06214           return FALSE;
06215         }
06216 #endif
06217 
06218         length = (unsigned int)strlen( ValueBuffer );
06219         if( length > maxwidth )
06220           maxwidth = length;
06221 
06222 #ifndef _CRT_SECURE_NO_DEPRECATE
06223         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].im ) < 0 )
06224         {
06225           MTX_ERROR_MSG( "sprintf_s returned failure." );
06226           return FALSE;
06227         }
06228 #else
06229         if( sprintf( ValueBuffer, format, M->cplx[j][i].im ) < 0 )
06230         {
06231           MTX_ERROR_MSG( "sprintf returned failure." );
06232           return FALSE;
06233         }
06234 #endif
06235         length = (unsigned int)strlen( ValueBuffer );
06236         if( length > maxwidth_im )
06237           maxwidth_im = length;
06238       }
06239       maxColumnWidth[k] = maxwidth+1;
06240       k++;
06241       maxColumnWidth[k] = maxwidth_im+1;
06242       k++;
06243     }
06244 
06245   }
06246 
06247   if( M->isReal )
06248   {
06249     for( i = 0; i < M->nrows; i++ )
06250     {
06251       for( j = 0; j < M->ncols; j++ )
06252       {
06253         MTX_ValueToString( M->data[j][i], maxColumnWidth[j], precision, TRUE, TRUE, ValueBuffer, 512 );
06254         fprintf( out, ValueBuffer );
06255       }
06256       fprintf( out, "\n" );
06257     }
06258   }
06259   else
06260   {
06261     for( i = 0; i < M->nrows; i++ )
06262     {
06263       for( j = 0; j < M->ncols; j++ )
06264       {
06265         if( M->cplx[j][i].im == 0 )
06266         {
06267           // output only the real component
06268           MTX_ValueToString( M->cplx[j][i].re, maxColumnWidth[j*2], precision, TRUE, FALSE, ValueBuffer, 512 );
06269           fprintf( out, ValueBuffer );
06270           for( k = 0; k < maxColumnWidth[j*2+1]; k++ )
06271             fprintf( out, " " );
06272         }
06273         else
06274         {
06275           // output both
06276           MTX_ValueToString( M->cplx[j][i].re, maxColumnWidth[j*2], precision, TRUE, FALSE, ValueBuffer, 512 );
06277           fprintf( out, ValueBuffer );
06278           MTX_ValueToString( M->cplx[j][i].im, maxColumnWidth[j*2+1], precision, FALSE, TRUE, ValueBuffer, 512 );
06279           fprintf( out, ValueBuffer );
06280         }
06281       }
06282       fprintf( out, "\n" );
06283     }
06284   }
06285 
06286   fclose(out);
06287 
06288   free(maxColumnWidth);
06289 
06290   return TRUE;
06291 }
06292 
06293 
06294 BOOL MTX_PrintStdoutAutoWidth( const MTX *M, const unsigned precision )
06295 {
06296   unsigned i = 0;
06297   unsigned j = 0;
06298   unsigned k = 0;
06299   unsigned n = 0;
06300   unsigned maxwidth = 0;
06301   unsigned maxwidth_im = 0;
06302   unsigned length = 0;
06303   unsigned *maxColumnWidth;
06304   char format[16];
06305   char ValueBuffer[512];
06306 
06307   if( MTX_isNull( M ) )
06308   {
06309     MTX_ERROR_MSG( "NULL Matrix" );
06310     return FALSE;
06311   }
06312 
06313   if( M->ncols == 0 || M->nrows == 0 )
06314   {
06315     MTX_ERROR_MSG( "if( M->ncols == 0 || M->nrows == 0 )" );
06316     return FALSE;
06317   }
06318 
06319   if( precision > 200 )
06320   {
06321     MTX_ERROR_MSG( "if( precision > 200 )" );
06322     return FALSE;
06323   }
06324 
06325   ValueBuffer[0] = '\0';
06326 
06327   if( M->isReal )
06328     n = M->ncols;
06329   else
06330     n = M->ncols*2;
06331 
06332   maxColumnWidth = (unsigned*)malloc( sizeof(unsigned)*n );
06333   if( !maxColumnWidth )
06334   {
06335     MTX_ERROR_MSG( "if( !maxColumnWidth )" );
06336     return FALSE;
06337   }
06338 
06339   if( M->isReal )
06340   {
06341     for( j = 0; j < M->ncols; j++ )
06342     {
06343       // determine the maximum width needed for the given precision
06344       maxwidth = 0;
06345       for( i = 0; i < M->nrows; i++ )
06346       {
06347 #ifndef _CRT_SECURE_NO_DEPRECATE
06348         if( sprintf_s( format, 16, "%% .%dg", precision ) < 0 )
06349         {
06350           MTX_ERROR_MSG( "sprintf_s returned failure." );
06351           return FALSE;
06352         }
06353         if( sprintf_s( ValueBuffer, 512, format, M->data[j][i] ) < 0 )
06354         {
06355           MTX_ERROR_MSG( "sprintf_s returned failure." );
06356           return FALSE;
06357         }
06358 #else
06359         if( sprintf( format, "%% .%dg", precision ) < 0 )
06360         {
06361           MTX_ERROR_MSG( "sprintf returned failure." );
06362           return FALSE;
06363         }
06364         if( sprintf( ValueBuffer, format, M->data[j][i] ) < 0 )
06365         {
06366           MTX_ERROR_MSG( "sprintf returned failure." );
06367           return FALSE;
06368         }
06369 #endif
06370         length = (unsigned int)strlen( ValueBuffer );
06371         if( length > maxwidth )
06372           maxwidth = length;
06373       }
06374       maxColumnWidth[j] = maxwidth+1;
06375     }
06376   }
06377   else
06378   {
06379     k = 0;
06380     for( j = 0; j < M->ncols; j++ )
06381     {
06382       // determine the maximum width needed for the given precision
06383       maxwidth = 0;
06384       maxwidth_im = 0;
06385       for( i = 0; i < M->nrows; i++ )
06386       {
06387 #ifndef _CRT_SECURE_NO_DEPRECATE
06388         if( sprintf_s( format, 16, "%% .%dg", precision ) < 0 )
06389         {
06390           MTX_ERROR_MSG( "sprintf_s returned failure." );
06391           return FALSE;
06392         }
06393         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
06394         {
06395           MTX_ERROR_MSG( "sprintf_s returned failure." );
06396           return FALSE;
06397         }
06398 #else
06399         if( sprintf( format, "%% .%dg", precision ) < 0 )
06400         {
06401           MTX_ERROR_MSG( "sprintf returned failure." );
06402           return FALSE;
06403         }
06404         if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
06405         {
06406           MTX_ERROR_MSG( "sprintf returned failure." );
06407           return FALSE;
06408         }
06409 #endif
06410 
06411         length = (unsigned int)strlen( ValueBuffer );
06412         if( length > maxwidth )
06413           maxwidth = length;
06414 
06415 #ifndef _CRT_SECURE_NO_DEPRECATE
06416         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].im ) < 0 )
06417         {
06418           MTX_ERROR_MSG( "sprintf_s returned failure." );
06419           return FALSE;
06420         }
06421 #else
06422         if( sprintf( ValueBuffer, format, M->cplx[j][i].im ) < 0 )
06423         {
06424           MTX_ERROR_MSG( "sprintf returned failure." );
06425           return FALSE;
06426         }
06427 #endif
06428         length = (unsigned int)strlen( ValueBuffer );
06429         if( length > maxwidth_im )
06430           maxwidth_im = length;
06431       }
06432       maxColumnWidth[k] = maxwidth+1;
06433       k++;
06434       maxColumnWidth[k] = maxwidth_im+1;
06435       k++;
06436     }
06437 
06438   }
06439 
06440   if( M->isReal )
06441   {
06442     for( i = 0; i < M->nrows; i++ )
06443     {
06444       for( j = 0; j < M->ncols; j++ )
06445       {
06446         MTX_ValueToString( M->data[j][i], maxColumnWidth[j], precision, TRUE, TRUE, ValueBuffer, 512 );
06447         printf( ValueBuffer );
06448       }
06449       printf( "\n" );
06450     }
06451   }
06452   else
06453   {
06454     for( i = 0; i < M->nrows; i++ )
06455     {
06456       for( j = 0; j < M->ncols; j++ )
06457       {
06458         if( M->cplx[j][i].im == 0 )
06459         {
06460           // output only the real component
06461           MTX_ValueToString( M->cplx[j][i].re, maxColumnWidth[j*2], precision, TRUE, FALSE, ValueBuffer, 512 );
06462           printf( ValueBuffer );
06463           for( k = 0; k < maxColumnWidth[j*2+1]; k++ )
06464             printf( " " );
06465         }
06466         else
06467         {
06468           // output both
06469           MTX_ValueToString( M->cplx[j][i].re, maxColumnWidth[j*2], precision, TRUE, FALSE, ValueBuffer, 512 );
06470           printf( ValueBuffer );
06471           MTX_ValueToString( M->cplx[j][i].im, maxColumnWidth[j*2+1], precision, FALSE, TRUE, ValueBuffer, 512 );
06472           printf( ValueBuffer );
06473         }
06474       }
06475       printf( "\n" );
06476     }
06477   }
06478 
06479   free(maxColumnWidth);
06480 
06481   return TRUE;
06482 }
06483 
06484 
06485 
06486 BOOL MTX_PrintAutoWidth_ToBuffer( const MTX *M, char *buffer, const unsigned maxlength, const unsigned precision )
06487 {
06488   unsigned i = 0;
06489   unsigned j = 0;
06490   unsigned k = 0;
06491   unsigned n = 0;
06492   unsigned maxwidth = 0;
06493   unsigned maxwidth_im = 0;
06494   unsigned length = 0;
06495   unsigned scount = 0; // count into buffer
06496   unsigned dcount = 0;
06497   BOOL endOfBuffer = FALSE;
06498   unsigned *maxColumnWidth;
06499   char format[16];
06500   char ValueBuffer[512];
06501 
06502   if( MTX_isNull( M ) )
06503   {
06504     MTX_ERROR_MSG( "NULL Matrix" );
06505     return FALSE;
06506   }
06507 
06508   if( buffer == NULL )
06509   {
06510     MTX_ERROR_MSG( "buffer is a NULL pointer." );
06511     return FALSE;
06512   }
06513 
06514   if( maxlength == 0 )
06515   {
06516     MTX_ERROR_MSG( "if( maxlength == 0 )" );
06517     return FALSE;
06518   }
06519 
06520   if( M->ncols == 0 || M->nrows == 0 )
06521   {
06522     MTX_ERROR_MSG( "if( M->ncols == 0 || M->nrows == 0 )" );
06523     return FALSE;
06524   }
06525 
06526   if( precision > 200 )
06527   {
06528     MTX_ERROR_MSG( "if( precision > 200 )" );
06529     return FALSE;
06530   }
06531 
06532   ValueBuffer[0] = '\0';
06533 
06534   if( M->isReal )
06535     n = M->ncols;
06536   else
06537     n = M->ncols*2;
06538 
06539   maxColumnWidth = (unsigned*)malloc( sizeof(unsigned)*n );
06540   if( !maxColumnWidth )
06541   {
06542     MTX_ERROR_MSG( "malloc returned NULL." );
06543     return FALSE;
06544   }
06545 
06546   if( M->isReal )
06547   {
06548     for( j = 0; j < M->ncols; j++ )
06549     {
06550       // determine the maximum width needed for the given precision
06551       maxwidth = 0;
06552       for( i = 0; i < M->nrows; i++ )
06553       {
06554 #ifndef _CRT_SECURE_NO_DEPRECATE
06555         if( sprintf_s( format, 16, "%% .%dg", precision ) < 0 )
06556         {
06557           MTX_ERROR_MSG( "sprintf_s returned failure." );
06558           return FALSE;
06559         }
06560         if( sprintf_s( ValueBuffer, 512, format, M->data[j][i] ) < 0 )
06561         {
06562           MTX_ERROR_MSG( "sprintf_s returned failure." );
06563           return FALSE;
06564         }
06565 #else
06566         if( sprintf( format, "%% .%dg", precision ) < 0 )
06567         {
06568           MTX_ERROR_MSG( "sprintf returned failure." );
06569           return FALSE;
06570         }
06571         if( sprintf( ValueBuffer, format, M->data[j][i] ) < 0 )
06572         {
06573           MTX_ERROR_MSG( "sprintf returned failure." );
06574           return FALSE;
06575         }
06576 #endif
06577         length = (unsigned int)strlen( ValueBuffer );
06578         if( length > maxwidth )
06579           maxwidth = length;
06580       }
06581       maxColumnWidth[j] = maxwidth+1;
06582     }
06583   }
06584   else
06585   {
06586     k = 0;
06587     for( j = 0; j < M->ncols; j++ )
06588     {
06589       // determine the maximum width needed for the given precision
06590       maxwidth = 0;
06591       maxwidth_im = 0;
06592       for( i = 0; i < M->nrows; i++ )
06593       {
06594 #ifndef _CRT_SECURE_NO_DEPRECATE
06595         if( sprintf_s( format, 16, "%% .%dg", precision ) < 0 )
06596         {
06597           MTX_ERROR_MSG( "sprintf_s returned failure." );
06598           return FALSE;
06599         }
06600         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
06601         {
06602           MTX_ERROR_MSG( "sprintf_s returned failure." );
06603           return FALSE;
06604         }
06605 #else
06606         if( sprintf( format, "%% .%dg", precision ) < 0 )
06607         {
06608           MTX_ERROR_MSG( "sprintf returned failure." );
06609           return FALSE;
06610         }
06611         if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
06612         {
06613           MTX_ERROR_MSG( "sprintf returned failure." );
06614           return FALSE;
06615         }
06616 #endif
06617         length = (unsigned int)strlen( ValueBuffer );
06618         if( length > maxwidth )
06619           maxwidth = length;
06620 
06621 #ifndef _CRT_SECURE_NO_DEPRECATE
06622         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].im ) < 0 )
06623         {
06624           MTX_ERROR_MSG( "sprintf_s returned failure." );
06625           return FALSE;
06626         }
06627 #else
06628         if( sprintf( ValueBuffer, format, M->cplx[j][i].im ) < 0 )
06629         {
06630           MTX_ERROR_MSG( "sprintf returned failure." );
06631           return FALSE;
06632         }
06633 #endif
06634         length = (unsigned int)strlen( ValueBuffer );
06635         if( length > maxwidth_im )
06636           maxwidth_im = length;
06637       }
06638       maxColumnWidth[k] = maxwidth+1;
06639       k++;
06640       maxColumnWidth[k] = maxwidth_im+1;
06641       k++;
06642     }
06643   }
06644 
06645   if( M->isReal )
06646   {
06647     for( i = 0; i < M->nrows; i++ )
06648     {
06649       for( j = 0; j < M->ncols; j++ )
06650       {
06651         MTX_ValueToString( M->data[j][i], maxColumnWidth[j], precision, TRUE, TRUE, ValueBuffer, 512 );
06652         if( scount+maxColumnWidth[j] >= maxlength )
06653         {
06654           endOfBuffer = TRUE;
06655           break;
06656         }
06657 #ifndef _CRT_SECURE_NO_DEPRECATE
06658         dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
06659         if( dcount < 0 )
06660         {
06661           MTX_ERROR_MSG( "sprintf_s returned failure." );
06662           return FALSE;
06663         }
06664         scount += dcount;
06665 #else
06666         dcount = sprintf( buffer+scount, "%s", ValueBuffer );
06667         if( dcount < 0 )
06668         {
06669           MTX_ERROR_MSG( "sprintf returned failure." );
06670           return FALSE;
06671         }
06672         scount += dcount;
06673 #endif
06674       }
06675       if( endOfBuffer )
06676         break;
06677       if( scount+2 >= maxlength )
06678         break;
06679 #ifndef _CRT_SECURE_NO_DEPRECATE
06680       dcount = sprintf_s( buffer+scount, maxlength-scount, "\n" );
06681       if( dcount < 0 )
06682       {
06683         MTX_ERROR_MSG( "sprintf_s returned failure." );
06684         return FALSE;
06685       }
06686       scount += dcount;
06687 #else
06688       dcount = sprintf( buffer+scount, "\n" );
06689       if( dcount < 0 )
06690       {
06691         MTX_ERROR_MSG( "sprintf returned failure." );
06692         return FALSE;
06693       }
06694       scount += dcount;
06695 #endif
06696     }
06697   }
06698   else
06699   {
06700     for( i = 0; i < M->nrows; i++ )
06701     {
06702       for( j = 0; j < M->ncols; j++ )
06703       {
06704         if( M->cplx[j][i].im == 0 )
06705         {
06706           // output only the real component
06707           MTX_ValueToString( M->cplx[j][i].re, maxColumnWidth[j*2], precision, TRUE, FALSE, ValueBuffer, 512 );
06708           if( scount+maxColumnWidth[j] >= maxlength )
06709           {
06710             endOfBuffer = TRUE;
06711             break;
06712           }
06713 #ifndef _CRT_SECURE_NO_DEPRECATE
06714           dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
06715           if( dcount < 0 )
06716           {
06717             MTX_ERROR_MSG( "sprintf_s returned failure." );
06718             return FALSE;
06719           }
06720           scount += dcount;
06721 
06722           for( k = 0; k < maxColumnWidth[j*2+1]; k++ )
06723           {
06724             dcount = sprintf_s( buffer+scount, maxlength-scount, " " );
06725             if( dcount < 0 )
06726             {
06727               MTX_ERROR_MSG( "sprintf_s returned failure." );
06728               return FALSE;
06729             }
06730             scount += dcount;
06731           }
06732 #else
06733           dcount = sprintf( buffer+scount, "%s", ValueBuffer );
06734           if( dcount < 0 )
06735           {
06736             MTX_ERROR_MSG( "sprintf returned failure." );
06737             return FALSE;
06738           }
06739           scount += dcount;
06740 
06741           for( k = 0; k < maxColumnWidth[j*2+1]; k++ )
06742           {
06743             dcount = sprintf( buffer+scount, " " );
06744             if( dcount < 0 )
06745             {
06746               MTX_ERROR_MSG( "sprintf returned failure." );
06747               return FALSE;
06748             }
06749             scount += dcount;
06750           }
06751 #endif
06752         }
06753         else
06754         {
06755           // output both
06756           MTX_ValueToString( M->cplx[j][i].re, maxColumnWidth[j*2], precision, TRUE, FALSE, ValueBuffer, 512 );
06757           if( scount+maxColumnWidth[j] >= maxlength )
06758           {
06759             endOfBuffer = TRUE;
06760             break;
06761           }
06762 #ifndef _CRT_SECURE_NO_DEPRECATE
06763           dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
06764           if( dcount < 0 )
06765           {
06766             MTX_ERROR_MSG( "sprintf_s returned failure." );
06767             return FALSE;
06768           }
06769           scount += dcount;
06770 #else
06771           dcount = sprintf( buffer+scount, "%s", ValueBuffer );
06772           if( dcount < 0 )
06773           {
06774             MTX_ERROR_MSG( "sprintf returned failure." );
06775             return FALSE;
06776           }
06777           scount += dcount;
06778 #endif
06779 
06780           MTX_ValueToString( M->cplx[j][i].im, maxColumnWidth[j*2+1], precision, FALSE, TRUE, ValueBuffer, 512 );
06781           if( scount+maxColumnWidth[j] >= maxlength )
06782           {
06783             endOfBuffer = TRUE;
06784             break;
06785           }
06786 #ifndef _CRT_SECURE_NO_DEPRECATE
06787           dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
06788           if( dcount < 0 )
06789           {
06790             MTX_ERROR_MSG( "sprintf_s returned failure." );
06791             return FALSE;
06792           }
06793           scount += dcount;
06794 #else
06795           dcount = sprintf( buffer+scount, "%s", ValueBuffer );
06796           if( dcount < 0 )
06797           {
06798             MTX_ERROR_MSG( "sprintf returned failure." );
06799             return FALSE;
06800           }
06801           scount += dcount;
06802 #endif
06803         }
06804       }
06805       if( endOfBuffer )
06806         break;
06807       if( scount+2 >= maxlength )
06808         break;
06809 
06810 #ifndef _CRT_SECURE_NO_DEPRECATE
06811       dcount = sprintf_s( buffer+scount, maxlength-scount, "\n" );
06812       if( dcount < 0 )
06813       {
06814         MTX_ERROR_MSG( "sprintf_s returned failure." );
06815         return FALSE;
06816       }
06817       scount += dcount;
06818 #else
06819       dcount = sprintf( buffer+scount, "\n" );
06820       if( dcount < 0 )
06821       {
06822         MTX_ERROR_MSG( "sprintf returned failure." );
06823         return FALSE;
06824       }
06825       scount += dcount;
06826 #endif
06827     }
06828   }
06829 
06830   free(maxColumnWidth);
06831 
06832   return TRUE;
06833 }
06834 
06835 BOOL MTX_PrintDelimited( const MTX *M, const char *path, const unsigned precision, const char delimiter, const BOOL append )
06836 {
06837   unsigned i = 0;
06838   unsigned j = 0;
06839   char format[16];
06840   char ValueBuffer[512];
06841   FILE* out;
06842 
06843   if( MTX_isNull( M ) )
06844   {
06845     MTX_ERROR_MSG( "NULL Matrix" );
06846     return FALSE;
06847   }
06848 
06849   if( M->ncols == 0 || M->nrows == 0 )
06850   {
06851     MTX_ERROR_MSG( "if( M->ncols == 0 || M->nrows == 0 )" );
06852     return FALSE;
06853   }
06854 
06855   if( precision > 200 )
06856   {
06857     MTX_ERROR_MSG( "if( precision > 200 )" );
06858     return FALSE;
06859   }
06860 
06861   ValueBuffer[0] = '\0';
06862 
06863   if( append )
06864   {
06865 #ifndef _CRT_SECURE_NO_DEPRECATE
06866     if( fopen_s( &out, path, "at+" ) != 0 )
06867     {
06868       MTX_ERROR_MSG( "fopen_s failed to open the file." );
06869       return FALSE;
06870     }
06871 #else
06872     out = fopen( path, "at+" );
06873 #endif
06874   }
06875   else
06876   {
06877 #ifndef _CRT_SECURE_NO_DEPRECATE
06878     if( fopen_s( &out, path, "w" ) != 0 )
06879     {
06880       MTX_ERROR_MSG( "fopen_s failed to open the file." );
06881       return FALSE;
06882     }
06883 #else
06884     out = fopen( path, "w" );
06885 #endif
06886   }
06887   if( !out )
06888   {
06889 #ifndef _CRT_SECURE_NO_DEPRECATE
06890     if( sprintf_s( ValueBuffer, 512, "Unable to open %s", path ) > 0 )
06891       MTX_ERROR_MSG( ValueBuffer );
06892 #else
06893     if( sprintf( ValueBuffer, "Unable to open %s", path ) > 0 )
06894       MTX_ERROR_MSG( ValueBuffer );
06895 #endif
06896     return FALSE;
06897   }
06898 
06899   if( M->isReal )
06900   {
06901     for( i = 0; i < M->nrows; i++ )
06902     {
06903       for( j = 0; j < M->ncols-1; j++ )
06904       {
06905 #ifndef _CRT_SECURE_NO_DEPRECATE
06906         if( sprintf_s( format, 16, "%%.%dg%c", precision, delimiter ) < 0 )
06907         {
06908           MTX_ERROR_MSG( "sprintf_s returned failure." );
06909           return FALSE;
06910         }
06911         if( sprintf_s( ValueBuffer, 512, format, M->data[j][i] ) < 0 )
06912         {
06913           MTX_ERROR_MSG( "sprintf_s returned failure." );
06914           return FALSE;
06915         }
06916 #else
06917         if( sprintf( format, "%%.%dg%c", precision, delimiter ) < 0 )
06918         {
06919           MTX_ERROR_MSG( "sprintf returned failure." );
06920           return FALSE;
06921         }
06922         if( sprintf( ValueBuffer, format, M->data[j][i] ) < 0 )
06923         {
06924           MTX_ERROR_MSG( "sprintf returned failure." );
06925           return FALSE;
06926         }
06927 #endif
06928         fprintf( out, ValueBuffer );
06929       }
06930 #ifndef _CRT_SECURE_NO_DEPRECATE
06931       if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
06932       {
06933         MTX_ERROR_MSG( "sprintf_s returned failure." );
06934         return FALSE;
06935       }
06936       if( sprintf_s( ValueBuffer, 512, format, M->data[j][i] ) < 0 )
06937       {
06938         MTX_ERROR_MSG( "sprintf_s returned failure." );
06939         return FALSE;
06940       }
06941 #else
06942       if( sprintf( format, "%%.%dg", precision ) < 0 )
06943       {
06944         MTX_ERROR_MSG( "sprintf returned failure." );
06945         return FALSE;
06946       }
06947       if( sprintf( ValueBuffer, format, M->data[j][i] ) < 0 )
06948       {
06949         MTX_ERROR_MSG( "sprintf returned failure." );
06950         return FALSE;
06951       }
06952 #endif
06953       fprintf( out, ValueBuffer );
06954       fprintf( out, "\n" );
06955     }
06956   }
06957   else
06958   {
06959     for( i = 0; i < M->nrows; i++ )
06960     {
06961       for( j = 0; j < M->ncols-1; j++ )
06962       {
06963         if( M->cplx[j][i].im == 0 )
06964         {
06965           // output only the real component
06966 #ifndef _CRT_SECURE_NO_DEPRECATE
06967           if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
06968           {
06969             MTX_ERROR_MSG( "sprintf_s returned failure." );
06970             return FALSE;
06971           }
06972           if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
06973           {
06974             MTX_ERROR_MSG( "sprintf_s returned failure." );
06975             return FALSE;
06976           }
06977 #else
06978           if( sprintf( format, "%%.%dg", precision ) < 0 )
06979           {
06980             MTX_ERROR_MSG( "sprintf returned failure." );
06981             return FALSE;
06982           }
06983           if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
06984           {
06985             MTX_ERROR_MSG( "sprintf returned failure." );
06986             return FALSE;
06987           }
06988 #endif
06989           fprintf( out, ValueBuffer );
06990         }
06991         else
06992         {
06993           // output both
06994 #ifndef _CRT_SECURE_NO_DEPRECATE
06995           if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
06996           {
06997             MTX_ERROR_MSG( "sprintf_s returned failure." );
06998             return FALSE;
06999           }
07000           if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
07001           {
07002             MTX_ERROR_MSG( "sprintf_s returned failure." );
07003             return FALSE;
07004           }
07005 #else
07006           if( sprintf( format, "%%.%dg", precision ) < 0 )
07007           {
07008             MTX_ERROR_MSG( "sprintf returned failure." );
07009             return FALSE;
07010           }
07011           if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
07012           {
07013             MTX_ERROR_MSG( "sprintf returned failure." );
07014             return FALSE;
07015           }
07016 #endif
07017           fprintf( out, ValueBuffer );
07018 
07019 #ifndef _CRT_SECURE_NO_DEPRECATE
07020           if( sprintf_s( format, 16, "%%+.%dgi%c", precision, delimiter ) < 0 )
07021           {
07022             MTX_ERROR_MSG( "sprintf_s returned failure." );
07023             return FALSE;
07024           }
07025           if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].im ) < 0 )
07026           {
07027             MTX_ERROR_MSG( "sprintf_s returned failure." );
07028             return FALSE;
07029           }
07030 #else
07031           if( sprintf( format, "%%+.%dgi%c", precision, delimiter ) < 0 )
07032           {
07033             MTX_ERROR_MSG( "sprintf returned failure." );
07034             return FALSE;
07035           }
07036           if( sprintf( ValueBuffer, format, M->cplx[j][i].im ) < 0 )
07037           {
07038             MTX_ERROR_MSG( "sprintf returned failure." );
07039             return FALSE;
07040           }
07041 #endif
07042           fprintf( out, ValueBuffer );
07043         }
07044       }
07045       if( M->cplx[j][i].im == 0 )
07046       {
07047         // output only the real component
07048 #ifndef _CRT_SECURE_NO_DEPRECATE
07049         if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
07050         {
07051           MTX_ERROR_MSG( "sprintf_s returned failure." );
07052           return FALSE;
07053         }
07054         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
07055         {
07056           MTX_ERROR_MSG( "sprintf_s returned failure." );
07057           return FALSE;
07058         }
07059 #else
07060         if( sprintf( format, "%%.%dg", precision ) < 0 )
07061         {
07062           MTX_ERROR_MSG( "sprintf returned failure." );
07063           return FALSE;
07064         }
07065         if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
07066         {
07067           MTX_ERROR_MSG( "sprintf returned failure." );
07068           return FALSE;
07069         }
07070 #endif
07071         fprintf( out, ValueBuffer );
07072       }
07073       else
07074       {
07075         // output both
07076 #ifndef _CRT_SECURE_NO_DEPRECATE
07077         if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
07078         {
07079           MTX_ERROR_MSG( "sprintf_s returned failure." );
07080           return FALSE;
07081         }
07082         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
07083         {
07084           MTX_ERROR_MSG( "sprintf_s returned failure." );
07085           return FALSE;
07086         }
07087 #else
07088         if( sprintf( format, "%%.%dg", precision ) < 0 )
07089         {
07090           MTX_ERROR_MSG( "sprintf returned failure." );
07091           return FALSE;
07092         }
07093         if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
07094         {
07095           MTX_ERROR_MSG( "sprintf returned failure." );
07096           return FALSE;
07097         }
07098 #endif
07099         fprintf( out, ValueBuffer );
07100 
07101 #ifndef _CRT_SECURE_NO_DEPRECATE
07102         if( sprintf_s( format, 16, "%%+.%dgi", precision ) < 0 )
07103         {
07104           MTX_ERROR_MSG( "sprintf_s returned failure." );
07105           return FALSE;
07106         }
07107         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].im ) < 0 )
07108         {
07109           MTX_ERROR_MSG( "sprintf_s returned failure." );
07110           return FALSE;
07111         }
07112 #else
07113         if( sprintf( format, "%%+.%dgi", precision ) < 0 )
07114         {
07115           MTX_ERROR_MSG( "sprintf returned failure." );
07116           return FALSE;
07117         }
07118         if( sprintf( ValueBuffer, format, M->cplx[j][i].im ) < 0 )
07119         {
07120           MTX_ERROR_MSG( "sprintf returned failure." );
07121           return FALSE;
07122         }
07123 #endif
07124         fprintf( out, ValueBuffer );
07125       }
07126       fprintf( out, "\n" );
07127     }
07128   }
07129 
07130   fclose(out);
07131 
07132   return TRUE;
07133 }
07134 
07135 BOOL MTX_PrintDelimited_ToBuffer( const MTX *M, char *buffer, const unsigned maxlength, const unsigned precision, const char delimiter )
07136 {
07137   unsigned i = 0;
07138   unsigned j = 0;
07139   unsigned scount = 0;
07140   unsigned dcount = 0;
07141   BOOL endOfBuffer = FALSE;
07142   char format[16];
07143   char ValueBuffer[512];
07144 
07145   if( MTX_isNull( M ) )
07146   {
07147     MTX_ERROR_MSG( "NULL Matrix" );
07148     return FALSE;
07149   }
07150 
07151   if( M->ncols == 0 || M->nrows == 0 )
07152   {
07153     MTX_ERROR_MSG( "if( M->ncols == 0 || M->nrows == 0 )" );
07154     return FALSE;
07155   }
07156 
07157   if( buffer == NULL )
07158   {
07159     MTX_ERROR_MSG( "if( buffer == NULL )" );
07160     return FALSE;
07161   }
07162 
07163   if( maxlength == 0 )
07164   {
07165     MTX_ERROR_MSG( "if( maxlength == 0 )" );
07166     return FALSE;
07167   }
07168 
07169   if( precision > 200 )
07170   {
07171     MTX_ERROR_MSG( "if( precision > 200 )" );
07172     return FALSE;
07173   }
07174 
07175   ValueBuffer[0] = '\0';
07176 
07177 #ifndef _CRT_SECURE_NO_DEPRECATE
07178   if( M->isReal )
07179   {
07180     for( i = 0; i < M->nrows; i++ )
07181     {
07182       for( j = 0; j < M->ncols-1; j++ )
07183       {
07184         if( sprintf_s( format, 16, "%%.%dg%c", precision, delimiter ) < 0 )
07185         {
07186           MTX_ERROR_MSG( "sprintf_s returned failure." );
07187           return FALSE;
07188         }
07189         if( sprintf_s( ValueBuffer, 512, format, M->data[j][i] ) < 0 )
07190         {
07191           MTX_ERROR_MSG( "sprintf_s returned failure." );
07192           return FALSE;
07193         }
07194         if( scount + strlen(ValueBuffer) >= maxlength )
07195         {
07196           endOfBuffer = TRUE;
07197           break;
07198         }
07199         dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
07200         if( dcount < 0 )
07201         {
07202           MTX_ERROR_MSG( "sprintf_s returned failure." );
07203           return FALSE;
07204         }
07205         scount += dcount;
07206       }
07207       if( endOfBuffer )
07208         break;
07209       if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
07210       {
07211         MTX_ERROR_MSG( "sprintf_s returned failure." );
07212         return FALSE;
07213       }
07214       if( sprintf_s( ValueBuffer, 512, format, M->data[j][i] ) < 0 )
07215       {
07216         MTX_ERROR_MSG( "sprintf_s returned failure." );
07217         return FALSE;
07218       }
07219       if( scount + strlen(ValueBuffer) >= maxlength )
07220         break;
07221       dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
07222       if( dcount < 0 )
07223       {
07224         MTX_ERROR_MSG( "sprintf_s returned failure." );
07225         return FALSE;
07226       }
07227       scount += dcount;
07228 
07229       if( scount + 2 >= maxlength )
07230         break;
07231       dcount = sprintf_s( buffer+scount, maxlength-scount, "\n" );
07232       if( dcount < 0 )
07233       {
07234         MTX_ERROR_MSG( "sprintf_s returned failure." );
07235         return FALSE;
07236       }
07237       scount += dcount;
07238     }
07239   }
07240   else
07241   {
07242     for( i = 0; i < M->nrows; i++ )
07243     {
07244       for( j = 0; j < M->ncols-1; j++ )
07245       {
07246         if( M->cplx[j][i].im == 0 )
07247         {
07248           // output only the real component
07249           if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
07250           {
07251             MTX_ERROR_MSG( "sprintf_s returned failure." );
07252             return FALSE;
07253           }
07254           if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
07255           {
07256             MTX_ERROR_MSG( "sprintf_s returned failure." );
07257             return FALSE;
07258           }
07259           if( scount + strlen(ValueBuffer) >= maxlength )
07260           {
07261             endOfBuffer = TRUE;
07262             break;
07263           }
07264           dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
07265           if( dcount < 0 )
07266           {
07267             MTX_ERROR_MSG( "sprintf_s returned failure." );
07268             return FALSE;
07269           }
07270           scount += dcount;
07271         }
07272         else
07273         {
07274           // output both
07275           if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
07276           {
07277             MTX_ERROR_MSG( "sprintf_s returned failure." );
07278             return FALSE;
07279           }
07280           if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
07281           {
07282             MTX_ERROR_MSG( "sprintf_s returned failure." );
07283             return FALSE;
07284           }
07285           if( scount + strlen(ValueBuffer) >= maxlength )
07286           {
07287             endOfBuffer = TRUE;
07288             break;
07289           }
07290           dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
07291           if( dcount < 0 )
07292           {
07293             MTX_ERROR_MSG( "sprintf_s returned failure." );
07294             return FALSE;
07295           }
07296           scount += dcount;
07297 
07298           if( sprintf_s( format, 16, "%%+.%dgi%c", precision, delimiter ) < 0 )
07299           {
07300             MTX_ERROR_MSG( "sprintf_s returned failure." );
07301             return FALSE;
07302           }
07303           if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].im ) < 0 )
07304           {
07305             MTX_ERROR_MSG( "sprintf_s returned failure." );
07306             return FALSE;
07307           }
07308           if( scount + strlen(ValueBuffer) >= maxlength )
07309           {
07310             endOfBuffer = TRUE;
07311             break;
07312           }
07313           dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
07314           if( dcount < 0 )
07315           {
07316             MTX_ERROR_MSG( "sprintf_s returned failure." );
07317             return FALSE;
07318           }
07319           scount += dcount;
07320         }
07321       }
07322       if( endOfBuffer )
07323         break;
07324 
07325       if( M->cplx[j][i].im == 0 )
07326       {
07327         // output only the real component
07328         if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
07329         {
07330           MTX_ERROR_MSG( "sprintf_s returned failure." );
07331           return FALSE;
07332         }
07333         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
07334         {
07335           MTX_ERROR_MSG( "sprintf_s returned failure." );
07336           return FALSE;
07337         }
07338         if( scount + strlen(ValueBuffer) >= maxlength )
07339           break;
07340         dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
07341         if( dcount < 0 )
07342         {
07343           MTX_ERROR_MSG( "sprintf_s returned failure." );
07344           return FALSE;
07345         }
07346         scount += dcount;
07347       }
07348       else
07349       {
07350         // output both
07351         if( sprintf_s( format, 16, "%%.%dg", precision ) < 0 )
07352         {
07353           MTX_ERROR_MSG( "sprintf_s returned failure." );
07354           return FALSE;
07355         }
07356         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].re ) < 0 )
07357         {
07358           MTX_ERROR_MSG( "sprintf_s returned failure." );
07359           return FALSE;
07360         }
07361         if( scount + strlen(ValueBuffer) >= maxlength )
07362           break;
07363         dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
07364         if( dcount < 0 )
07365         {
07366           MTX_ERROR_MSG( "sprintf_s returned failure." );
07367           return FALSE;
07368         }
07369         scount += dcount;
07370 
07371         if( sprintf_s( format, 16, "%%+.%dgi", precision ) < 0 )
07372         {
07373           MTX_ERROR_MSG( "sprintf_s returned failure." );
07374           return FALSE;
07375         }
07376         if( sprintf_s( ValueBuffer, 512, format, M->cplx[j][i].im ) < 0 )
07377         {
07378           MTX_ERROR_MSG( "sprintf_s returned failure." );
07379           return FALSE;
07380         }
07381         if( scount + strlen(ValueBuffer) >= maxlength )
07382           break;
07383         dcount = sprintf_s( buffer+scount, maxlength-scount, "%s", ValueBuffer );
07384         if( dcount < 0 )
07385         {
07386           MTX_ERROR_MSG( "sprintf_s returned failure." );
07387           return FALSE;
07388         }
07389         scount += dcount;
07390       }
07391 
07392       if( scount + 2 >= maxlength )
07393         break;
07394 
07395       dcount = sprintf_s( buffer+scount, maxlength-scount, "\n" );
07396       if( dcount < 0 )
07397       {
07398         MTX_ERROR_MSG( "sprintf_s returned failure." );
07399         return FALSE;
07400       }
07401       scount += dcount;
07402     }
07403   }
07404 #else
07405   if( M->isReal )
07406   {
07407     for( i = 0; i < M->nrows; i++ )
07408     {
07409       for( j = 0; j < M->ncols-1; j++ )
07410       {
07411         if( sprintf( format, "%%.%dg%c", precision, delimiter ) < 0 )
07412         {
07413           MTX_ERROR_MSG( "sprintf returned failure." );
07414           return FALSE;
07415         }
07416         if( sprintf( ValueBuffer, format, M->data[j][i] ) < 0 )
07417         {
07418           MTX_ERROR_MSG( "sprintf returned failure." );
07419           return FALSE;
07420         }
07421         if( scount + strlen(ValueBuffer) >= maxlength )
07422         {
07423           endOfBuffer = TRUE;
07424           break;
07425         }
07426         dcount = sprintf( buffer+scount, "%s", ValueBuffer );
07427         if( dcount < 0 )
07428         {
07429           MTX_ERROR_MSG( "sprintf returned failure." );
07430           return FALSE;
07431         }
07432         scount += dcount;
07433       }
07434       if( endOfBuffer )
07435         break;
07436       if( sprintf( format, "%%.%dg", precision ) < 0 )
07437       {
07438         MTX_ERROR_MSG( "sprintf returned failure." );
07439         return FALSE;
07440       }
07441       if( sprintf( ValueBuffer, format, M->data[j][i] ) < 0 )
07442       {
07443         MTX_ERROR_MSG( "sprintf returned failure." );
07444         return FALSE;
07445       }
07446       if( scount + strlen(ValueBuffer) >= maxlength )
07447         break;
07448       dcount = sprintf( buffer+scount, "%s", ValueBuffer );
07449       if( dcount < 0 )
07450       {
07451         MTX_ERROR_MSG( "sprintf returned failure." );
07452         return FALSE;
07453       }
07454       scount += dcount;
07455 
07456       if( scount + 2 >= maxlength )
07457         break;
07458       dcount = sprintf( buffer+scount, "\n" );
07459       if( dcount < 0 )
07460       {
07461         MTX_ERROR_MSG( "sprintf returned failure." );
07462         return FALSE;
07463       }
07464       scount += dcount;
07465     }
07466   }
07467   else
07468   {
07469     for( i = 0; i < M->nrows; i++ )
07470     {
07471       for( j = 0; j < M->ncols-1; j++ )
07472       {
07473         if( M->cplx[j][i].im == 0 )
07474         {
07475           // output only the real component
07476           if( sprintf( format, "%%.%dg", precision ) < 0 )
07477           {
07478             MTX_ERROR_MSG( "sprintf returned failure." );
07479             return FALSE;
07480           }
07481           if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
07482           {
07483             MTX_ERROR_MSG( "sprintf returned failure." );
07484             return FALSE;
07485           }
07486           if( scount + strlen(ValueBuffer) >= maxlength )
07487           {
07488             endOfBuffer = TRUE;
07489             break;
07490           }
07491           dcount = sprintf( buffer+scount, "%s", ValueBuffer );
07492           if( dcount < 0 )
07493           {
07494             MTX_ERROR_MSG( "sprintf returned failure." );
07495             return FALSE;
07496           }
07497           scount += dcount;
07498         }
07499         else
07500         {
07501           // output both
07502           if( sprintf( format, "%%.%dg", precision ) < 0 )
07503           {
07504             MTX_ERROR_MSG( "sprintf returned failure." );
07505             return FALSE;
07506           }
07507           if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
07508           {
07509             MTX_ERROR_MSG( "sprintf returned failure." );
07510             return FALSE;
07511           }
07512           if( scount + strlen(ValueBuffer) >= maxlength )
07513           {
07514             endOfBuffer = TRUE;
07515             break;
07516           }
07517           dcount = sprintf( buffer+scount, "%s", ValueBuffer );
07518           if( dcount < 0 )
07519           {
07520             MTX_ERROR_MSG( "sprintf returned failure." );
07521             return FALSE;
07522           }
07523           scount += dcount;
07524 
07525           if( sprintf( format, "%%+.%dgi%c", precision, delimiter ) < 0 )
07526           {
07527             MTX_ERROR_MSG( "sprintf returned failure." );
07528             return FALSE;
07529           }
07530           if( sprintf( ValueBuffer, format, M->cplx[j][i].im ) < 0 )
07531           {
07532             MTX_ERROR_MSG( "sprintf returned failure." );
07533             return FALSE;
07534           }
07535           if( scount + strlen(ValueBuffer) >= maxlength )
07536           {
07537             endOfBuffer = TRUE;
07538             break;
07539           }
07540           dcount = sprintf( buffer+scount, "%s", ValueBuffer );
07541           if( dcount < 0 )
07542           {
07543             MTX_ERROR_MSG( "sprintf returned failure." );
07544             return FALSE;
07545           }
07546           scount += dcount;
07547         }
07548       }
07549       if( endOfBuffer )
07550         break;
07551 
07552       if( M->cplx[j][i].im == 0 )
07553       {
07554         // output only the real component
07555         if( sprintf( format, "%%.%dg", precision ) < 0 )
07556         {
07557           MTX_ERROR_MSG( "sprintf returned failure." );
07558           return FALSE;
07559         }
07560         if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
07561         {
07562           MTX_ERROR_MSG( "sprintf returned failure." );
07563           return FALSE;
07564         }
07565         if( scount + strlen(ValueBuffer) >= maxlength )
07566           break;
07567         dcount = sprintf( buffer+scount, "%s", ValueBuffer );
07568         if( dcount < 0 )
07569         {
07570           MTX_ERROR_MSG( "sprintf returned failure." );
07571           return FALSE;
07572         }
07573         scount += dcount;
07574       }
07575       else
07576       {
07577         // output both
07578         if( sprintf( format, "%%.%dg", precision ) < 0 )
07579         {
07580           MTX_ERROR_MSG( "sprintf returned failure." );
07581           return FALSE;
07582         }
07583         if( sprintf( ValueBuffer, format, M->cplx[j][i].re ) < 0 )
07584         {
07585           MTX_ERROR_MSG( "sprintf returned failure." );
07586           return FALSE;
07587         }
07588         if( scount + strlen(ValueBuffer) >= maxlength )
07589           break;
07590         dcount = sprintf( buffer+scount, "%s", ValueBuffer );
07591         if( dcount < 0 )
07592         {
07593           MTX_ERROR_MSG( "sprintf returned failure." );
07594           return FALSE;
07595         }
07596         scount += dcount;
07597 
07598         if( sprintf( format, "%%+.%dgi", precision ) < 0 )
07599         {
07600           MTX_ERROR_MSG( "sprintf returned failure." );
07601           return FALSE;
07602         }
07603         if( sprintf( ValueBuffer, format, M->cplx[j][i].im ) < 0 )
07604         {
07605           MTX_ERROR_MSG( "sprintf returned failure." );
07606           return FALSE;
07607         }
07608         if( scount + strlen(ValueBuffer) >= maxlength )
07609           break;
07610         dcount = sprintf( buffer+scount, "%s", ValueBuffer );
07611         if( dcount < 0 )
07612         {
07613           MTX_ERROR_MSG( "sprintf returned failure." );
07614           return FALSE;
07615         }
07616         scount += dcount;
07617       }
07618 
07619       if( scount + 2 >= maxlength )
07620         break;
07621 
07622       dcount = sprintf( buffer+scount, "\n" );
07623       if( dcount < 0 )
07624       {
07625         MTX_ERROR_MSG( "sprintf returned failure." );
07626         return FALSE;
07627       }
07628       scount += dcount;
07629     }
07630   }
07631 #endif
07632 
07633   return TRUE;
07634 }
07635 
07636 BOOL MTX_PrintRowToString( const MTX *M, const unsigned row, char *buffer, const unsigned maxlength, const int width, const int precision )
07637 {
07638   unsigned j = 0;
07639   int k = 0;
07640   unsigned len = 0;
07641   unsigned scount = 0;
07642   unsigned dcount = 0;
07643 
07644   char ValueBuffer[512];
07645   ValueBuffer[0] = '\0';
07646 
07647   if( !buffer )
07648   {
07649     MTX_ERROR_MSG( "buffer is a NULL pointer." );
07650     return FALSE;
07651   }
07652 
07653   if( MTX_isNull( M ) )
07654   {
07655     MTX_ERROR_MSG( "NULL Matrix" );
07656     return FALSE;
07657   }
07658 
07659   if( M->ncols == 0 || M->nrows == 0 )
07660   {
07661     MTX_ERROR_MSG( "if( M->ncols == 0 || M->nrows == 0 )" );
07662     return FALSE;
07663   }
07664 
07665   if( row >= M->nrows )
07666   {
07667     MTX_ERROR_MSG( "if( row >= M->nrows )" );
07668     return FALSE;
07669   }
07670 
07671   if( precision > 200 )
07672   {
07673     MTX_ERROR_MSG( "if( precision > 200 )" );
07674     return FALSE;
07675   }
07676 
07677 #ifndef _CRT_SECURE_NO_DEPRECATE
07678   for( j = 0; j < M->ncols; j++ )
07679   {
07680     if( M->isReal )
07681     {
07682       MTX_ValueToString( M->data[j][row], width, precision, TRUE, TRUE, ValueBuffer, 512 );
07683       len = (unsigned int)strlen( ValueBuffer );
07684       if( len + scount >= maxlength )
07685       {
07686         MTX_ERROR_MSG( "if( len + scount >= maxlength )" );
07687         return FALSE;
07688       }
07689       dcount = sprintf_s( buffer+scount, maxlength-scount, ValueBuffer );
07690       if( dcount < 0 )
07691       {
07692         MTX_ERROR_MSG( "sprintf_s returned failure." );
07693         return FALSE;
07694       }
07695       scount += dcount;
07696     }
07697     else
07698     {
07699       if( M->cplx[j][row].im == 0 )
07700       {
07701         // output only the real component
07702         MTX_ValueToString( M->cplx[j][row].re, width, precision, TRUE, FALSE, ValueBuffer, 512 );
07703         len = (unsigned int)strlen( ValueBuffer );
07704         if( len + scount >= maxlength )
07705         {
07706           MTX_ERROR_MSG( "if( len + scount >= maxlength )" );
07707           return FALSE;
07708         }
07709         dcount = sprintf_s( buffer+scount, maxlength-scount, ValueBuffer );
07710         if( dcount < 0 )
07711         {
07712           MTX_ERROR_MSG( "sprintf_s returned failure." );
07713           return FALSE;
07714         }
07715         scount += dcount;
07716         for( k = 0; k < width; k++ )
07717         {
07718           dcount = sprintf_s( buffer+scount, maxlength-scount, " " );
07719           if( dcount < 0 )
07720           {
07721             MTX_ERROR_MSG( "sprintf_s returned failure." );
07722             return FALSE;
07723           }
07724           scount += dcount;
07725         }
07726       }
07727       else
07728       {
07729         // output both
07730         MTX_ValueToString( M->cplx[j][row].re, width, precision, TRUE, FALSE, ValueBuffer, 512 );
07731         len = (unsigned int)strlen( ValueBuffer );
07732         if( len + scount >= maxlength )
07733         {
07734           MTX_ERROR_MSG( "if( len + scount >= maxlength )" );
07735           return FALSE;
07736         }
07737         dcount = sprintf_s( buffer+scount, maxlength-scount, ValueBuffer );
07738         if( dcount < 0 )
07739         {
07740           MTX_ERROR_MSG( "sprintf_s returned failure." );
07741           return FALSE;
07742         }
07743         scount += dcount;
07744 
07745         MTX_ValueToString( M->cplx[j][row].im, width, precision, FALSE, TRUE, ValueBuffer, 512 );
07746         len = (unsigned int)strlen( ValueBuffer );
07747         if( len + scount >= maxlength )
07748         {
07749           MTX_ERROR_MSG( "if( len + scount >= maxlength )" );
07750           return FALSE;
07751         }
07752         dcount = sprintf_s( buffer+scount, maxlength-scount, ValueBuffer );
07753         if( dcount < 0 )
07754         {
07755           MTX_ERROR_MSG( "sprintf_s returned failure." );
07756           return FALSE;
07757         }
07758         scount += dcount;
07759       }
07760     }
07761   }
07762   if( sprintf_s( buffer+scount, maxlength-scount, "\n" ) < 0 )
07763   {
07764     MTX_ERROR_MSG( "sprintf_s returned failure." );
07765     return FALSE;
07766   }
07767 #else
07768   for( j = 0; j < M->ncols; j++ )
07769   {
07770     if( M->isReal )
07771     {
07772       MTX_ValueToString( M->data[j][row], width, precision, TRUE, TRUE, ValueBuffer, 512 );
07773       len = (unsigned int)strlen( ValueBuffer );
07774       if( len + scount >= maxlength )
07775       {
07776         MTX_ERROR_MSG( "if( len + scount >= maxlength )" );
07777         return FALSE;
07778       }
07779       dcount = sprintf( buffer+scount, ValueBuffer );
07780       if( dcount < 0 )
07781       {
07782         MTX_ERROR_MSG( "sprintf returned failure." );
07783         return FALSE;
07784       }
07785       scount += dcount;
07786     }
07787     else
07788     {
07789       if( M->cplx[j][row].im == 0 )
07790       {
07791         // output only the real component
07792         MTX_ValueToString( M->cplx[j][row].re, width, precision, TRUE, FALSE, ValueBuffer, 512 );
07793         len = (unsigned int)strlen( ValueBuffer );
07794         if( len + scount >= maxlength )
07795         {
07796           MTX_ERROR_MSG( "if( len + scount >= maxlength )" );
07797           return FALSE;
07798         }
07799         dcount = sprintf( buffer+scount, ValueBuffer );
07800         if( dcount < 0 )
07801         {
07802           MTX_ERROR_MSG( "sprintf returned failure." );
07803           return FALSE;
07804         }
07805         scount += dcount;
07806         for( k = 0; k < width; k++ )
07807         {
07808           dcount = sprintf( buffer+scount, " " );
07809           if( dcount < 0 )
07810           {
07811             MTX_ERROR_MSG( "sprintf returned failure." );
07812             return FALSE;
07813           }
07814           scount += dcount;
07815         }
07816       }
07817       else
07818       {
07819         // output both
07820         MTX_ValueToString( M->cplx[j][row].re, width, precision, TRUE, FALSE, ValueBuffer, 512 );
07821         len = (unsigned int)strlen( ValueBuffer );
07822         if( len + scount >= maxlength )
07823         {
07824           MTX_ERROR_MSG( "if( len + scount >= maxlength )" );
07825           return FALSE;
07826         }
07827         dcount = sprintf( buffer+scount, ValueBuffer );
07828         if( dcount < 0 )
07829         {
07830           MTX_ERROR_MSG( "sprintf returned failure." );
07831           return FALSE;
07832         }
07833         scount += dcount;
07834 
07835         MTX_ValueToString( M->cplx[j][row].im, width, precision, FALSE, TRUE, ValueBuffer, 512 );
07836         len = (unsigned int)strlen( ValueBuffer );
07837         if( len + scount >= maxlength )
07838         {
07839           MTX_ERROR_MSG( "if( len + scount >= maxlength )" );
07840           return FALSE;
07841         }
07842         dcount = sprintf( buffer+scount, ValueBuffer );
07843         if( dcount < 0 )
07844         {
07845           MTX_ERROR_MSG( "sprintf returned failure." );
07846           return FALSE;
07847         }
07848         scount += dcount;
07849       }
07850     }
07851   }
07852   if( sprintf( buffer+scount, "\n" ) < 0 )
07853   {
07854     MTX_ERROR_MSG( "sprintf returned failure." );
07855     return FALSE;
07856   }
07857 #endif
07858   return TRUE;
07859 }
07860 
07861 
07862 
07863 
07864 //-----------------------------------------------------------------------------------------------------------------//
07865 //-----------------------------------------------------------------------------------------------------------------//
07866 //-----------------------------------------------------------------------------------------------------------------//
07867 // Math Operations
07868 //-----------------------------------------------------------------------------------------------------------------//
07869 //-----------------------------------------------------------------------------------------------------------------//
07870 //-----------------------------------------------------------------------------------------------------------------//
07871 
07872 BOOL MTX_Add_Scalar( MTX *M, const double scalar )
07873 {
07874   unsigned i = 0;
07875   unsigned j = 0;
07876 
07877   if( scalar == 0.0 )
07878     return TRUE;
07879 
07880   if( M->isReal )
07881   {
07882     for( j = 0; j < M->ncols; j++ )
07883     {
07884       for( i = 0; i < M->nrows; i++ )
07885       {
07886         M->data[j][i] += scalar;
07887       }
07888     }
07889   }
07890   else
07891   {
07892     for( j = 0; j < M->ncols; j++ )
07893     {
07894       for( i = 0; i < M->nrows; i++ )
07895       {
07896         M->cplx[j][i].re += scalar;
07897       }
07898     }
07899   }
07900   return TRUE;
07901 }
07902 
07903 BOOL MTX_Add_ScalarComplex( MTX *M, const double re, const double im )
07904 {
07905   unsigned i = 0;
07906   unsigned j = 0;
07907 
07908   // special cases
07909   if( re == 0.0 && im == 0.0 )
07910   {
07911     return TRUE;
07912   }
07913   if( im == 0.0 )
07914   {
07915     return MTX_Add_Scalar( M, re );
07916   }
07917 
07918   if( M->isReal )
07919   {
07920     if( !MTX_ConvertRealToComplex( M ) )
07921     {
07922       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
07923       return FALSE;
07924     }
07925   }
07926 
07927   if( re == 0.0 )
07928   {
07929     for( j = 0; j < M->ncols; j++ )
07930     {
07931       for( i = 0; i < M->nrows; i++ )
07932       {
07933         M->cplx[j][i].im += im;
07934       }
07935     }
07936   }
07937   else
07938   {
07939     for( j = 0; j < M->ncols; j++ )
07940     {
07941       for( i = 0; i < M->nrows; i++ )
07942       {
07943         M->cplx[j][i].re += re;
07944         M->cplx[j][i].im += im;
07945       }
07946     }
07947   }
07948   return TRUE;
07949 }
07950 
07951 BOOL MTX_Subtract_Scalar( MTX *M, const double scalar )
07952 {
07953   unsigned i = 0;
07954   unsigned j = 0;
07955 
07956   if( MTX_isNull( M ) )
07957   {
07958     MTX_ERROR_MSG( "NULL Matrix" );
07959     return FALSE;
07960   }
07961 
07962   if( scalar == 0.0 )
07963     return TRUE;
07964 
07965   if( M->isReal )
07966   {
07967     for( j = 0; j < M->ncols; j++ )
07968     {
07969       for( i = 0; i < M->nrows; i++ )
07970       {
07971         M->data[j][i] -= scalar;
07972       }
07973     }
07974   }
07975   else
07976   {
07977     for( j = 0; j < M->ncols; j++ )
07978     {
07979       for( i = 0; i < M->nrows; i++ )
07980       {      
07981         M->cplx[j][i].re -= scalar;
07982       }
07983     }
07984   }
07985   return TRUE;
07986 }
07987 
07988 BOOL MTX_Subtract_ScalarComplex( MTX *M, const double re, const double im )
07989 {
07990   unsigned i = 0;
07991   unsigned j = 0;
07992 
07993   // special cases
07994   if( re == 0.0 && im == 0.0 )
07995   {
07996     return TRUE;
07997   }
07998   if( im == 0.0 )
07999   {
08000     return MTX_Subtract_Scalar( M, re );
08001   }
08002 
08003   if( M->isReal )
08004   {
08005     if( !MTX_ConvertRealToComplex( M ) )
08006     {
08007       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
08008       return FALSE;
08009     }
08010   }
08011 
08012   if( re == 0.0 )
08013   {
08014     for( j = 0; j < M->ncols; j++ )
08015     {
08016       for( i = 0; i < M->nrows; i++ )
08017       {
08018         M->cplx[j][i].im -= im;        
08019       }
08020     }
08021   }
08022   else
08023   {
08024     for( j = 0; j < M->ncols; j++ )
08025     {
08026       for( i = 0; i < M->nrows; i++ )
08027       {
08028         M->cplx[j][i].re -= re;
08029         M->cplx[j][i].im -= im;
08030       }
08031     }
08032   }
08033   return TRUE;
08034 }
08035 
08036 BOOL MTX_Multiply_Scalar( MTX *M, const double scalar )
08037 {
08038   unsigned i = 0;
08039   unsigned j = 0;
08040 
08041   if( MTX_isNull( M ) )
08042   {
08043     MTX_ERROR_MSG( "NULL Matrix" );
08044     return FALSE;
08045   }
08046 
08047   if( scalar == 0.0 )
08048   {
08049     return MTX_Zero( M );
08050   }
08051 
08052   if( M->isReal )
08053   {
08054     for( j = 0; j < M->ncols; j++ )
08055     {
08056       for( i = 0; i < M->nrows; i++ )
08057       {
08058         M->data[j][i] *= scalar;      
08059       }
08060     }
08061   }
08062   else
08063   {
08064     for( j = 0; j < M->ncols; j++ )
08065     {
08066       for( i = 0; i < M->nrows; i++ )
08067       {
08068         M->cplx[j][i].re *= scalar;
08069         M->cplx[j][i].im *= scalar;
08070       }
08071     }
08072   }
08073   return TRUE;
08074 }
08075 
08076 BOOL MTX_Multiply_ScalarComplex( MTX *M, const double re, const double im )
08077 {
08078   unsigned i = 0;
08079   unsigned j = 0;
08080   double tre = 0;
08081   double tim = 0;
08082 
08083   if( MTX_isNull( M ) )
08084   {
08085     MTX_ERROR_MSG( "NULL Matrix" );
08086     return FALSE;
08087   }
08088 
08089   // special cases
08090   if( re == 0.0 && im == 0.0 )
08091   {
08092     return TRUE;
08093   }
08094   if( im == 0.0 )
08095   {
08096     return MTX_Multiply_Scalar( M, re );
08097   }
08098 
08099   if( M->isReal )
08100   {
08101     if( !MTX_ConvertRealToComplex( M ) )
08102     {
08103       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
08104       return FALSE;
08105     }
08106   }
08107 
08108   for( j = 0; j < M->ncols; j++ )
08109   {
08110     for( i = 0; i < M->nrows; i++ )
08111     {
08112       tre = M->cplx[j][i].re * re - M->cplx[j][i].im * im;
08113       tim = M->cplx[j][i].re * im + M->cplx[j][i].im * re;
08114       M->cplx[j][i].re = tre;
08115       M->cplx[j][i].im = tim;
08116     }
08117   }
08118   return TRUE;
08119 }
08120 
08121 BOOL MTX_Divide_Scalar( MTX *M, const double scalar )
08122 {
08123   unsigned i = 0;
08124   unsigned j = 0;
08125 
08126   if( MTX_isNull( M ) )
08127   {
08128     MTX_ERROR_MSG( "NULL Matrix" );
08129     return FALSE;
08130   }
08131 
08132   if( M->isReal )
08133   {
08134     for( j = 0; j < M->ncols; j++ )
08135     {
08136       for( i = 0; i < M->nrows; i++ )
08137       { 
08138         M->data[j][i] /= scalar;
08139       }
08140     }
08141   }
08142   else
08143   {
08144     for( j = 0; j < M->ncols; j++ )
08145     {
08146       for( i = 0; i < M->nrows; i++ )
08147       { 
08148         M->cplx[j][i].re /= scalar;
08149         M->cplx[j][i].im /= scalar;
08150       }
08151     }
08152   }
08153   return TRUE;
08154 }
08155 
08156 BOOL MTX_Divide_ScalarComplex( MTX *M, const double re, const double im )
08157 {
08158   unsigned i = 0;
08159   unsigned j = 0;
08160   double mag = 0;
08161   double tre = 0;
08162   double tim = 0;
08163 
08164   if( MTX_isNull( M ) )
08165   {
08166     MTX_ERROR_MSG( "NULL Matrix" );
08167     return FALSE;
08168   }
08169 
08170   // special case
08171   if( im == 0.0 )
08172   {
08173     return MTX_Divide_Scalar( M, re );
08174   }
08175 
08176   if( M->isReal )
08177   {
08178     if( !MTX_ConvertRealToComplex( M ) )
08179     {
08180       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
08181       return FALSE;
08182     }
08183   }
08184 
08185   for( j = 0; j < M->ncols; j++ )
08186   {
08187     for( i = 0; i < M->nrows; i++ )
08188     {
08189       mag = re*re + im*im;
08190 
08191       tre = (M->cplx[j][i].re * re + M->cplx[j][i].im * im )/mag;
08192       tim = (M->cplx[j][i].im * re - M->cplx[j][i].re * im )/mag;
08193 
08194       M->cplx[j][i].re = tre;
08195       M->cplx[j][i].im = tim;
08196     }
08197   }
08198   return TRUE;
08199 }
08200 
08201 BOOL MTX_Negate( MTX *M )
08202 {
08203   unsigned i = 0;
08204   unsigned j;  
08205   if( MTX_isNull( M ) )
08206   {
08207     MTX_ERROR_MSG( "NULL Matrix" );
08208     return FALSE;
08209   }
08210 
08211   if( M->isReal )
08212   {
08213     for( j = 0; j < M->ncols; j++ )
08214     {
08215       for( i = 0; i < M->nrows; i++ )
08216       {
08217         M->data[j][i] = -M->data[j][i];
08218       }
08219     }
08220   }
08221   else
08222   {
08223     for( j = 0; j < M->ncols; j++ )
08224     {
08225       for( i = 0; i < M->nrows; i++ )
08226       {
08227         M->cplx[j][i].re = -M->cplx[j][i].re;
08228         M->cplx[j][i].im = -M->cplx[j][i].im;
08229       }
08230     }
08231   }
08232   return TRUE;
08233 }
08234 
08235 BOOL MTX_Abs( MTX *M )
08236 {
08237   unsigned i = 0;
08238   unsigned j = 0;
08239   unsigned k = 0;
08240 
08241   if( MTX_isNull( M ) )
08242   {
08243     MTX_ERROR_MSG( "NULL Matrix" );
08244     return FALSE;
08245   }
08246 
08247   if( !M->isReal )
08248   {
08249     // special case for optimization, both the data and complex
08250     // pointers are used. i.e. the matrix is real and complex
08251     // at the same time
08252     M->data = (double**)calloc( (M->ncols), sizeof(double*) );
08253     if( !M->data )
08254     {
08255       MTX_ERROR_MSG( "calloc returned NULL." );
08256       MTX_Free( M );
08257       return FALSE;
08258     }
08259   }
08260 
08261   if( M->isReal )
08262   {
08263     for( j = 0; j < M->ncols; j++ )
08264       for( i = 0; i < M->nrows; i++ )
08265         M->data[j][i] = fabs(M->data[j][i]);
08266   }
08267   else
08268   {
08269     for( j = 0; j < M->ncols; j++ )
08270     {
08271       // allocate the real data
08272       M->data[j] = (double*)malloc( sizeof(double)*(M->nrows) );
08273       if( !M->data[j] )
08274       {
08275         for( k = 0; k < j; k++ )
08276         {
08277           if( M->data[j] )
08278             free( M->data[j] );
08279         }
08280         free( M->data );
08281         M->data = NULL;
08282         MTX_Free( M );
08283         MTX_ERROR_MSG( "malloc returned NULL." );
08284         return FALSE;
08285       }
08286 
08287       for( i = 0; i < M->nrows; i++ )
08288       {
08289         M->data[j][i] = sqrt( M->cplx[j][i].re*M->cplx[j][i].re + M->cplx[j][i].im*M->cplx[j][i].im );
08290       }
08291 
08292       // free the complex data
08293       free( M->cplx[j] );
08294     }
08295   }
08296 
08297   if( !M->isReal )
08298   {
08299     // free the complex matrix pointer
08300     free( M->cplx );
08301     M->cplx = NULL;
08302     M->isReal = TRUE;
08303   }
08304 
08305   return TRUE;
08306 }
08307 
08308 
08309 BOOL MTX_acos( MTX *M )
08310 {
08311   unsigned i = 0;
08312   unsigned j = 0;  
08313   double maxabs = 0;
08314 
08315   if( MTX_isNull( M ) )
08316   {
08317     MTX_ERROR_MSG( "NULL Matrix" );
08318     return FALSE;
08319   }
08320 
08321 
08322   if( M->isReal )
08323   {
08324     // check the input range of the data, -1<=x<=1
08325     if( !MTX_MaxAbs( M, &maxabs ) )
08326     {
08327       MTX_ERROR_MSG( "MTX_MaxAbs returned FALSE." );
08328       return FALSE;
08329     }
08330 
08331     if( maxabs > 1.0 )
08332     {
08333       if( !MTX_ConvertRealToComplex( M ) )
08334       {
08335         MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
08336         return FALSE;
08337       }
08338     }
08339   }
08340 
08341   if( M->isReal )
08342   {
08343     // The data is real and well bounded.
08344     for( j = 0; j < M->ncols; j++ )
08345     {
08346       for( i = 0; i < M->nrows; i++ )
08347       {
08348         M->data[j][i] = acos(M->data[j][i]);
08349       }
08350     }
08351   }
08352   else
08353   {
08354     // refer http://idlastro.gsfc.nasa.gov/idl_html_help/ACOS.html
08355     double Xp2;
08356     double Xm2;
08357     double Y2;
08358     double A;
08359     double B;
08360 
08361     for( j = 0; j < M->ncols; j++ )
08362     {
08363       for( i = 0; i < M->nrows; i++ )
08364       {
08365         Xp2 = M->cplx[j][i].re + 1.0;
08366         Xp2*= Xp2;
08367 
08368         Xm2 = M->cplx[j][i].re - 1.0;
08369         Xm2*= Xm2;
08370 
08371         Y2 = M->cplx[j][i].im;
08372         Y2 *= Y2;
08373 
08374         //A = 0.5 * sqrt((X + 1.0)*(X + 1.0) + Y*Y) + 0.5 * sqrt((X - 1.0)*(X - 1.0) + Y*Y)
08375         //B = 0.5 * sqrt((X + 1.0)*(X + 1.0) + Y*Y) - 0.5 * sqrt((X - 1.0)*(X - 1.0) + Y*Y)
08376 
08377         A = 0.5 * ( sqrt(Xp2 + Y2) + sqrt(Xm2 + Y2) );
08378         B = 0.5 * ( sqrt(Xp2 + Y2) - sqrt(Xm2 + Y2) );
08379 
08380         if( M->cplx[j][i].im >= 0 )
08381         {
08382           M->cplx[j][i].re = acos(B);
08383           M->cplx[j][i].im = -log( A + sqrt( A*A-1.0 ) );
08384         }
08385         else
08386         {
08387           M->cplx[j][i].re = acos(B);
08388           M->cplx[j][i].im = log( A + sqrt( A*A-1.0 ) );
08389         }
08390       }
08391     }
08392   }
08393   return TRUE;
08394 }
08395 
08396 BOOL MTX_angle( MTX *M )
08397 {
08398   MTX copyM;
08399 
08400   if( MTX_isNull( M ) )
08401   {
08402     MTX_ERROR_MSG( "NULL Matrix" );
08403     return FALSE;
08404   }
08405 
08406   MTX_Init(&copyM);
08407 
08408   if( !MTX_Copy(M,&copyM) )
08409   {
08410     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
08411     return FALSE;
08412   }
08413 
08414   if( !MTX_Phase(&copyM,M) )
08415   {
08416     MTX_ERROR_MSG( "MTX_Phase returned FALSE." );
08417     return FALSE;
08418   }
08419 
08420   MTX_Free(&copyM);
08421 
08422   return TRUE;
08423 }
08424 
08425 BOOL MTX_asin( MTX *M )
08426 {
08427   unsigned i = 0;
08428   unsigned j = 0;
08429 
08430   if( MTX_isNull( M ) )
08431   {
08432     MTX_ERROR_MSG( "NULL Matrix" );
08433     return FALSE;
08434   }
08435 
08436 
08437   if( M->isReal )
08438   {
08439     double maxabs;
08440     // check the input range of the data, -1<=x<=1
08441     if( !MTX_MaxAbs( M, &maxabs ) )
08442     {
08443       MTX_ERROR_MSG( "MTX_MaxAbs returned FALSE." );
08444       return FALSE;
08445     }
08446 
08447     if( maxabs > 1.0 )
08448     {
08449       if( !MTX_ConvertRealToComplex( M ) )
08450       {
08451         MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
08452         return FALSE;
08453       }
08454     }
08455   }
08456 
08457   if( M->isReal )
08458   {
08459     // The data is real and well bounded.
08460     for( j = 0; j < M->ncols; j++ )
08461     {
08462       for( i = 0; i < M->nrows; i++ )
08463       {
08464         M->data[j][i] = asin(M->data[j][i]);
08465       }
08466     }
08467   }
08468   else
08469   {
08470     // refer http://idlastro.gsfc.nasa.gov/idl_html_help/ASIN.html
08471     double Xp2;
08472     double Xm2;
08473     double Y2;
08474     double A;
08475     double B;
08476 
08477     for( j = 0; j < M->ncols; j++ )
08478     {
08479       for( i = 0; i < M->nrows; i++ )
08480       {
08481         Xp2 = M->cplx[j][i].re + 1.0;
08482         Xp2*= Xp2;
08483 
08484         Xm2 = M->cplx[j][i].re - 1.0;
08485         Xm2*= Xm2;
08486 
08487         Y2 = M->cplx[j][i].im;
08488         Y2 *= Y2;
08489 
08490         //A = 0.5 * sqrt((X + 1.0)*(X + 1.0) + Y*Y) + 0.5 * sqrt((X - 1.0)*(X - 1.0) + Y*Y)
08491         //B = 0.5 * sqrt((X + 1.0)*(X + 1.0) + Y*Y) - 0.5 * sqrt((X - 1.0)*(X - 1.0) + Y*Y)
08492 
08493         A = 0.5 * ( sqrt(Xp2 + Y2) + sqrt(Xm2 + Y2) );
08494         B = 0.5 * ( sqrt(Xp2 + Y2) - sqrt(Xm2 + Y2) );
08495 
08496         if( M->cplx[j][i].im >= 0 )
08497         {
08498           M->cplx[j][i].re = asin(B);
08499           M->cplx[j][i].im = log( A + sqrt( A*A-1.0 ) );
08500         }
08501         else
08502         {
08503           M->cplx[j][i].re = asin(B);
08504           M->cplx[j][i].im = -log( A + sqrt( A*A-1.0 ) );
08505         }
08506       }
08507     }
08508   }
08509   return TRUE;
08510 }
08511 
08512 BOOL MTX_Sqr( MTX *M )
08513 {
08514   unsigned i = 0;
08515   unsigned j = 0;
08516   double re = 0;
08517   double im = 0;
08518 
08519   if( MTX_isNull( M ) )
08520   {
08521     MTX_ERROR_MSG( "NULL Matrix" );
08522     return FALSE;
08523   }
08524 
08525   if( M->isReal )
08526   {
08527     for( j = 0; j < M->ncols; j++ )
08528     {
08529       for( i = 0; i < M->nrows; i++ )
08530       {
08531         M->data[j][i] *= M->data[j][i];
08532       }
08533     }
08534   }
08535   else
08536   {
08537     for( j = 0; j < M->ncols; j++ )
08538     {
08539       for( i = 0; i < M->nrows; i++ )
08540       {      
08541         re = M->cplx[j][i].re*M->cplx[j][i].re - M->cplx[j][i].im*M->cplx[j][i].im;
08542         im = 2.0 * M->cplx[j][i].re*M->cplx[j][i].im;
08543         M->cplx[j][i].re = re;
08544         M->cplx[j][i].im = im;
08545       }
08546     }
08547   }
08548   return TRUE;
08549 }
08550 
08551 void MTX_static_quick_sqrt( const double *a_re, const double *a_im, double *re, double *im )
08552 {
08553   double mag;
08554   if( *a_im == 0.0 )
08555   {
08556     if( *a_re < 0 )
08557     {
08558       *re = 0.0;
08559       *im = sqrt( -(*a_re) );
08560     }
08561     else
08562     {
08563       *re = sqrt( *a_re );
08564       *im = 0.0;
08565     }
08566   }
08567   else
08568   {
08569     mag = sqrt( (*a_re)*(*a_re) + (*a_im)*(*a_im) );
08570 
08571     *re = sqrt( (mag + (*a_re))/2.0 );
08572     if( *a_im < 0 )
08573       *im = -1.0*sqrt( (mag - (*a_re))/2.0 );
08574     else
08575       *im = sqrt( (mag - (*a_re))/2.0 );
08576   }
08577 }
08578 
08579 BOOL MTX_Sqrt( MTX *M )
08580 {
08581   unsigned i = 0;
08582   unsigned j = 0;
08583   double re = 0;
08584   double im = 0;
08585   BOOL convert = FALSE;
08586 
08587   if( MTX_isNull( M ) )
08588   {
08589     MTX_ERROR_MSG( "NULL Matrix" );
08590     return FALSE;
08591   }
08592 
08593   if( M->isReal )
08594   {
08595     // check every element in a real matrix for negative values
08596     for( j = 0; j < M->ncols; j++ )
08597     {
08598       for( i = 0; i < M->nrows; i++ )
08599       {
08600         if( M->data[j][i] < 0 )
08601         {
08602           convert = TRUE;
08603           break;
08604         }
08605       }
08606       if( convert )
08607         break;
08608     }
08609 
08610     if( convert )
08611     {
08612       if( !MTX_ConvertRealToComplex( M ) )
08613       {
08614         MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
08615         return FALSE;
08616       }
08617     }
08618   }
08619 
08620   if( M->isReal )
08621   {
08622     for( j = 0; j < M->ncols; j++ )
08623     {
08624       for( i = 0; i < M->nrows; i++ )
08625       { 
08626         M->data[j][i] = sqrt(M->data[j][i]);
08627       }
08628     }
08629   }
08630   else
08631   {
08632     for( j = 0; j < M->ncols; j++ )
08633     {
08634       for( i = 0; i < M->nrows; i++ )
08635       { 
08636         MTX_static_quick_sqrt( &(M->cplx[j][i].re), &(M->cplx[j][i].im), &re, &im );
08637         M->cplx[j][i].re = re;
08638         M->cplx[j][i].im = im;
08639       }
08640     }
08641   }
08642   return TRUE;
08643 }
08644 
08645 BOOL MTX_Exp( MTX *M )
08646 {
08647   unsigned i = 0;
08648   unsigned j = 0;
08649 
08650   if( MTX_isNull( M ) )
08651   {
08652     MTX_ERROR_MSG( "NULL Matrix" );
08653     return FALSE;
08654   }
08655 
08656   if( M->isReal )
08657   {
08658     for( j = 0; j < M->ncols; j++ )
08659     {
08660       for( i = 0; i < M->nrows; i++ )
08661       {
08662         M->data[j][i] = exp(M->data[j][i]);
08663       }
08664     }
08665   }
08666   else
08667   {
08668     // exp(M) = exp(real)*(cos(imag)+i*sin(imag)).
08669     MTX Re;
08670     MTX Im;
08671     double real_part;
08672     double imag_part;
08673 
08674     MTX_Init( &Re );
08675     MTX_Init( &Im );
08676 
08677     if( !MTX_Real( M, &Re ) )
08678     {
08679       MTX_ERROR_MSG( "MTX_Real returned FALSE." );
08680       MTX_Free( &Re );
08681       MTX_Free( &Im );
08682       return FALSE;
08683     }
08684 
08685     if( !MTX_Imag( M, &Im ) )
08686     {
08687       MTX_ERROR_MSG( "MTX_Imag returned FALSE." );
08688       MTX_Free( &Re );
08689       MTX_Free( &Im );      
08690       return FALSE;
08691     }
08692 
08693     if( !MTX_Exp(&Re) )
08694     {
08695       MTX_ERROR_MSG( "MTX_Exp returned FALSE." );
08696       MTX_Free( &Re );
08697       MTX_Free( &Im );      
08698       return FALSE;
08699     }
08700 
08701     for( j = 0; j < M->ncols; j++ )
08702     {
08703       for( i = 0; i < M->nrows; i++ )
08704       {
08705         real_part = Re.data[j][i];
08706         imag_part = Im.data[j][i];
08707         M->cplx[j][i].re = real_part * cos( imag_part );
08708         M->cplx[j][i].im = real_part * sin( imag_part );
08709       }
08710     }
08711     MTX_Free( &Re );
08712     MTX_Free( &Im );      
08713   }
08714   return TRUE;
08715 }
08716 
08717 BOOL MTX_Eye( MTX *M, const unsigned nrows, const unsigned ncols )
08718 {
08719   unsigned i = 0;
08720   unsigned j = 0;
08721 
08722   if( !MTX_Calloc( M, nrows, ncols, TRUE ) )
08723   {
08724     MTX_ERROR_MSG( "MTX_Calloc returned FALSE." );
08725     return FALSE;
08726   }
08727 
08728   if( nrows < ncols )
08729   {
08730     for( i = 0; i < nrows; i++ )
08731       M->data[i][i] = 1.0;
08732   }
08733   else
08734   {
08735     for( j = 0; j < ncols; j++ )
08736       M->data[j][j] = 1.0;
08737   }
08738 
08739   return TRUE;
08740 }
08741 
08742 BOOL MTX_Ln( MTX *M )
08743 {
08744   unsigned i = 0;
08745   unsigned j = 0;  
08746   double re;
08747   double im;  
08748   MTX lnmag;
08749   MTX phase;
08750   MTX_Init( &lnmag );
08751   MTX_Init( &phase );
08752 
08753   if( MTX_isNull( M ) )
08754   {
08755     MTX_ERROR_MSG( "NULL Matrix" );
08756     return FALSE;
08757   }
08758 
08759   if( !MTX_Min( M, &re, &im ) )
08760   {
08761     MTX_ERROR_MSG( "MTX_Min returned FALSE." );
08762     return FALSE;
08763   }
08764 
08765   if( M->isReal && re >= 0 )
08766   {
08767     for( j = 0; j < M->ncols; j++ )
08768     {
08769       for( i = 0; i < M->nrows; i++ )
08770       {
08771         M->data[j][i] = log(M->data[j][i]);
08772       }
08773     }
08774     return TRUE;
08775   }
08776   if( !MTX_Magnitude( M, &lnmag ) )
08777   {
08778     MTX_ERROR_MSG( "MTX_Magnitude returned FALSE." );
08779     MTX_Free(&lnmag);
08780     return FALSE;
08781   }
08782   if( !MTX_Phase( M, &phase ) )
08783   {
08784     MTX_ERROR_MSG( "MTX_Phase returned FALSE." );
08785     MTX_Free(&lnmag);
08786     MTX_Free(&phase);
08787     return FALSE;
08788   }
08789 
08790   if( !MTX_Ln( &lnmag ) )
08791   {
08792     MTX_ERROR_MSG( "MTX_Ln returned FALSE." );
08793     MTX_Free(&lnmag);
08794     MTX_Free(&phase);
08795     return FALSE;
08796   }
08797 
08798   if( !MTX_Complex( M, &lnmag, &phase ) )
08799   {
08800     MTX_ERROR_MSG( "MTX_Complex returned FALSE." );
08801     MTX_Free(&lnmag);
08802     MTX_Free(&phase);
08803     return FALSE;
08804   }
08805 
08806   MTX_Free(&lnmag);
08807   MTX_Free(&phase);
08808   return TRUE;
08809 }
08810 
08811 
08812 BOOL MTX_Pow( const MTX *src, MTX *dst, const double power_re, const double power_im )
08813 {
08814   unsigned i = 0;
08815   unsigned j = 0;  
08816 
08817   if( MTX_isNull( src ) )
08818   {
08819     MTX_ERROR_MSG( "NULL Matrix" );
08820     return FALSE;
08821   }
08822   if( !dst )
08823   {
08824     MTX_ERROR_MSG( "NULL Matrix" );
08825     return FALSE;
08826   }
08827 
08828   if( power_im == 0.0 )
08829   {
08830     // if real, assume destination will be real initially.
08831     if( !MTX_Malloc( dst, src->nrows, src->ncols, src->isReal ) )
08832     {
08833       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
08834       return FALSE;
08835     }
08836   }
08837   else
08838   {
08839     if( !MTX_Malloc( dst, src->nrows, src->ncols, FALSE ) )
08840     {
08841       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
08842       return FALSE;
08843     }
08844   }
08845 
08846   // deal with real-real case first
08847   if( src->isReal && power_im == 0 && power_re >= 1.0 )
08848   {
08849     for( j = 0; j < src->ncols; j++ )
08850       for( i = 0; i < src->nrows; i++ )
08851         dst->data[j][i] = pow(src->data[j][i],power_re);
08852   }
08853   else
08854   {
08855     // x^y, can be expressed as e^(y*ln(x))
08856     MTX yLnX;
08857     stComplex cplxval;
08858 
08859     MTX_Init( &yLnX );
08860     cplxval.re = power_re;
08861     cplxval.im = power_im;
08862 
08863     if( !MTX_Copy( src, &yLnX ) )
08864     {
08865       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
08866       return FALSE;
08867     }
08868 
08869     if( !MTX_Ln( &yLnX ) )
08870     {
08871       MTX_ERROR_MSG( "MTX_Ln returned FALSE." );
08872       return FALSE;
08873     }
08874 
08875     if( cplxval.im == 0 )
08876     {
08877       if( !MTX_Multiply_Scalar( &yLnX, cplxval.re ) )
08878       {
08879         MTX_ERROR_MSG( "MTX_Multiply_Scalar returned FALSE." );
08880         return FALSE;
08881       }
08882     }
08883     else
08884     {
08885       if( !MTX_Multiply_ScalarComplex( &yLnX, cplxval.re, cplxval.im ) )
08886       {
08887         MTX_ERROR_MSG( "MTX_Multiply_ScalarComplex returned FALSE." );
08888         return FALSE;
08889       }
08890     }
08891 
08892     if( !MTX_Copy( &yLnX, dst ) )
08893     {
08894       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
08895       return FALSE;
08896     }
08897 
08898     if( !MTX_Exp( dst ) )
08899     {
08900       MTX_ERROR_MSG( "MTX_Exp returned FALSE." );
08901       return FALSE;
08902     }
08903 
08904     MTX_Free( &yLnX );
08905   }
08906 
08907   return TRUE;
08908 }
08909 
08910 
08911 BOOL MTX_PowInplace( MTX *src, const double power_re, const double power_im )
08912 {
08913   MTX copy;
08914   MTX_Init( &copy );
08915   
08916   if( MTX_isNull( src ) )
08917   {
08918     MTX_ERROR_MSG( "NULL Matrix" );
08919     return FALSE;
08920   }
08921 
08922   if( !MTX_Copy( src, &copy ) )
08923   {
08924     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
08925     MTX_Free( &copy );
08926     return FALSE;
08927   }
08928 
08929   if( !MTX_Pow( src, &copy, power_re, power_im ) )
08930   {
08931     MTX_ERROR_MSG( "MTX_Pow returned FALSE." );
08932     MTX_Free( &copy );
08933     return FALSE;
08934   }
08935 
08936   if( !MTX_Copy( &copy, src ) )
08937   {
08938     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
08939     MTX_Free( &copy );
08940     return FALSE;
08941   }
08942 
08943   MTX_Free( &copy );
08944   return TRUE;
08945 }
08946 
08947 
08948 
08949 BOOL MTX_atan( MTX *M )
08950 {
08951   unsigned i = 0;
08952   unsigned j = 0;
08953 
08954   if( MTX_isNull( M ) )
08955   {
08956     MTX_ERROR_MSG( "NULL Matrix" );
08957     return FALSE;
08958   }
08959 
08960   if( M->isReal )
08961   {
08962     for( j = 0; j < M->ncols; j++ )
08963     {
08964       for( i = 0; i < M->nrows; i++ )
08965       {
08966         M->data[j][i] = atan( M->data[j][i] );
08967       }
08968     }
08969   }
08970   else
08971   {
08972     // complex arctan!
08973     // arctan( z ) = 1/2 * i * ( ln( 1-iz ) - ln(1+iz) ), where z is complex
08974     MTX LnOneMinusZ;
08975     MTX LnOnePlusZ;
08976     stComplex halfi;
08977 
08978     halfi.re = 0;
08979     halfi.im = 0.5;
08980 
08981     MTX_Init( &LnOneMinusZ );
08982     MTX_Init( &LnOnePlusZ );
08983 
08984     // copy M to LnOnePlusZ
08985     if( !MTX_Copy( M, &LnOnePlusZ ) )
08986     {
08987       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
08988       return FALSE;
08989     }
08990     // make LnOnePlusZ = M*i
08991     if( !MTX_Multiply_ScalarComplex( &LnOnePlusZ, 0.0, 1.0 ) )
08992     {
08993       MTX_ERROR_MSG( "MTX_Multiply_ScalarComplex returned FALSE." );
08994       MTX_Free( &LnOnePlusZ );
08995       return FALSE;
08996     }
08997     // make LnOneMinusZ = M*i
08998     if( !MTX_Copy( &LnOnePlusZ, &LnOneMinusZ ) )
08999     {
09000       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09001       MTX_Free( &LnOnePlusZ );
09002       return FALSE;
09003     }
09004 
09005     // compute 1-iz
09006     for( j = 0; j < LnOneMinusZ.ncols; j++ )
09007     {
09008       for( i = 0; i < LnOneMinusZ.nrows; i++ )
09009       {
09010         LnOneMinusZ.cplx[j][i].re = 1.0 - LnOneMinusZ.cplx[j][i].re;
09011         LnOneMinusZ.cplx[j][i].im = -LnOneMinusZ.cplx[j][i].im;
09012       }
09013     }
09014 
09015     if( !MTX_Increment( &LnOnePlusZ ) )
09016     {
09017       MTX_ERROR_MSG( "MTX_Increment returned FALSE." );
09018       MTX_Free( &LnOneMinusZ );
09019       MTX_Free( &LnOnePlusZ );
09020       return FALSE;
09021     }
09022 
09023     if( !MTX_Ln( &LnOneMinusZ ) )
09024     {
09025       MTX_ERROR_MSG( "MTX_Ln returned FALSE." );
09026       MTX_Free( &LnOneMinusZ );
09027       MTX_Free( &LnOnePlusZ );
09028       return FALSE;
09029     }
09030     if( !MTX_Ln( &LnOnePlusZ ) )
09031     {
09032       MTX_ERROR_MSG( "MTX_Ln returned FALSE." );
09033       MTX_Free( &LnOneMinusZ );
09034       MTX_Free( &LnOnePlusZ );
09035       return FALSE;
09036     }
09037 
09038     if( !MTX_Subtract( M, &LnOneMinusZ, &LnOnePlusZ ) )
09039     {
09040       MTX_ERROR_MSG( "MTX_Subtract returned FALSE." );
09041       MTX_Free( &LnOneMinusZ );
09042       MTX_Free( &LnOnePlusZ );
09043       return FALSE;
09044     }
09045 
09046     if( !MTX_Multiply_ScalarComplex( M, halfi.re, halfi.im ) )
09047     {
09048       MTX_ERROR_MSG( "MTX_Multiply_ScalarComplex returned FALSE." );
09049       MTX_Free( &LnOneMinusZ );
09050       MTX_Free( &LnOnePlusZ );
09051       return FALSE;
09052     }
09053 
09054     MTX_Free( &LnOneMinusZ );
09055     MTX_Free( &LnOnePlusZ );
09056   }
09057   return TRUE;
09058 }
09059 
09060 BOOL MTX_Increment( MTX *M )
09061 {
09062   return MTX_Add_Scalar( M, 1.0 );
09063 }
09064 
09065 BOOL MTX_Decrement( MTX *M )
09066 {
09067   return MTX_Subtract_Scalar( M, 1.0 );
09068 }
09069 
09070 BOOL MTX_Add_Inplace( MTX *A, const MTX* B )
09071 {
09072   unsigned i = 0;
09073   unsigned j = 0;
09074   double re = 0.0;
09075   double im = 0.0;
09076 
09077   if( MTX_isNull( A ) )
09078   {
09079     MTX_ERROR_MSG( "NULL Matrix" );
09080     return FALSE;
09081   }
09082 
09083   if( MTX_isNull( B ) )
09084   {
09085     MTX_ERROR_MSG( "NULL Matrix" );
09086     return FALSE;
09087   }
09088 
09089   if( MTX_static_global_treat_1x1_as_scalar )
09090   {
09091     if( A->nrows == 1 && A->ncols == 1 )
09092     {
09093       if( A->isReal )
09094       {
09095         re = A->data[0][0];
09096         if( !MTX_Copy( B, A ) )
09097         {
09098           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09099           return FALSE;
09100         }
09101         return MTX_Add_Scalar( A, re );
09102       }
09103       else
09104       {
09105         re = A->cplx[0][0].re;
09106         im = A->cplx[0][0].im;
09107         if( !MTX_Copy( B, A ) )
09108         {
09109           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09110           return FALSE;
09111         }
09112         return MTX_Add_ScalarComplex( A, re, im );
09113       }
09114     }
09115     else if( B->nrows == 1 && B->ncols == 1 )
09116     {
09117       if( B->isReal )
09118       {
09119         return MTX_Add_Scalar( A, B->data[0][0] );
09120       }
09121       else
09122       {
09123         return MTX_Add_ScalarComplex( A, B->cplx[0][0].re, B->cplx[0][0].im );
09124       }
09125     }
09126   }
09127 
09128   if( !MTX_isConformalForAddition( A, B ) )
09129   {
09130     MTX_ERROR_MSG( "MTX_isConformalForAddition returned FALSE." );
09131     return FALSE;
09132   }
09133 
09134   if( A->isReal && !B->isReal )
09135   {
09136     if( !MTX_ConvertRealToComplex( A ) )
09137     {
09138       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
09139       return FALSE;
09140     }
09141   }
09142   
09143   if( A->isReal && B->isReal )
09144   {
09145     for( j = 0; j < A->ncols; j++ )
09146     {    
09147       for( i = 0; i < A->nrows; i++ )
09148       {
09149         A->data[j][i] += B->data[j][i];
09150       }
09151     }
09152   }
09153   else if( !A->isReal && !B->isReal )
09154   {
09155     for( j = 0; j < A->ncols; j++ )
09156     {  
09157       for( i = 0; i < A->nrows; i++ )
09158       {
09159         A->cplx[j][i].re += B->cplx[j][i].re;
09160         A->cplx[j][i].im += B->cplx[j][i].im;
09161       }
09162     }
09163   }
09164   else
09165   {
09166     for( j = 0; j < A->ncols; j++ )
09167     {  
09168       for( i = 0; i < A->nrows; i++ )
09169       {
09170         A->cplx[j][i].re += B->data[j][i];
09171       }
09172     }
09173   }
09174   return TRUE;
09175 }
09176 
09177 BOOL MTX_Subtract_Inplace( MTX *A, const MTX* B )
09178 {
09179   unsigned i = 0;
09180   unsigned j = 0;
09181   double re = 0.0;
09182   double im = 0.0;
09183 
09184   if( MTX_isNull( A ) )
09185   {
09186     MTX_ERROR_MSG( "NULL Matrix" );
09187     return FALSE;
09188   }
09189 
09190   if( MTX_isNull( B ) )
09191   {
09192     MTX_ERROR_MSG( "NULL Matrix" );
09193     return FALSE;
09194   }
09195 
09196   if( MTX_static_global_treat_1x1_as_scalar )
09197   {
09198     if( A->nrows == 1 && A->ncols == 1 )
09199     {
09200       // Set tmp = A; A=-B; A+=tmp;
09201       if( A->isReal )
09202       {
09203         re = A->data[0][0];
09204         if( !MTX_Copy( B, A ) )
09205         {
09206           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09207           return FALSE;
09208         }
09209         if( !MTX_Negate( A ) )
09210         {
09211           MTX_ERROR_MSG( "MTX_Negate returned FALSE." );
09212           return FALSE;
09213         }
09214         return MTX_Add_Scalar( A, re );
09215       }
09216       else
09217       {
09218         re = A->cplx[0][0].re;
09219         im = A->cplx[0][0].im;
09220         if( !MTX_Copy( B, A ) )
09221         {
09222           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09223           return FALSE;
09224         }
09225         if( !MTX_Negate( A ) )
09226         {
09227           MTX_ERROR_MSG( "MTX_Negate returned FALSE." );
09228           return FALSE;
09229         }
09230         return MTX_Add_ScalarComplex( A, re, im );
09231       }
09232     }
09233     else if( B->nrows == 1 && B->ncols == 1 )
09234     {
09235       if( B->isReal )
09236       {
09237         return MTX_Subtract_Scalar( A, B->data[0][0] );
09238       }
09239       else
09240       {
09241         return MTX_Subtract_ScalarComplex( A, B->cplx[0][0].re, B->cplx[0][0].im );
09242       }
09243     }
09244   }
09245 
09246   if( !MTX_isConformalForAddition( A, B ) )
09247   {
09248     MTX_ERROR_MSG( "MTX_isConformalForAddition returned FALSE." );
09249     return FALSE;
09250   }
09251 
09252   if( A->isReal && !B->isReal )
09253   {
09254     if( !MTX_ConvertRealToComplex( A ) )
09255     {
09256       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
09257       return FALSE;
09258     }
09259   }
09260 
09261   if( A->isReal && B->isReal )
09262   {
09263     for( j = 0; j < A->ncols; j++ )
09264     {
09265       for( i = 0; i < A->nrows; i++ )
09266       {
09267         A->data[j][i] -= B->data[j][i];
09268       }
09269     }
09270   }
09271   else if( !A->isReal && !B->isReal )
09272   {
09273     for( j = 0; j < A->ncols; j++ )
09274     {
09275       for( i = 0; i < A->nrows; i++ )      
09276       {
09277         A->cplx[j][i].re -= B->cplx[j][i].re;
09278         A->cplx[j][i].im -= B->cplx[j][i].im;
09279       }
09280     }
09281   }
09282   else
09283   {
09284     for( j = 0; j < A->ncols; j++ )
09285     {
09286       for( i = 0; i < A->nrows; i++ )      
09287       {
09288         A->cplx[j][i].re -= B->data[j][i];
09289       }
09290     }
09291   }
09292   return TRUE;
09293 }
09294 
09295 // multiply A = A*B, inplace
09296 BOOL MTX_PostMultiply_Inplace( MTX *A, const MTX* B )
09297 {
09298   MTX M;
09299   MTX_Init( &M );
09300 
09301   if( !MTX_Multiply( &M, A, B ) )
09302   {
09303     MTX_ERROR_MSG( "MTX_Multiply returned FALSE." );
09304     MTX_Free( &M );
09305     return FALSE;
09306   }
09307   if( !MTX_Copy( &M, A ) )
09308   {
09309     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09310     MTX_Free( &M );
09311     return FALSE;
09312   }
09313   MTX_Free( &M );
09314   return TRUE;
09315 }
09316 
09317 // multiply A = A*transpose(B), inplace
09318 BOOL MTX_PostMultiplyTranspose_Inplace( MTX *A, const MTX* B )
09319 {
09320   MTX M;
09321   MTX_Init( &M );
09322 
09323   if( !MTX_MultiplyTranspose( &M, A, B ) )
09324   {
09325     MTX_ERROR_MSG( "MTX_MultiplyTranspose returned FALSE." );
09326     MTX_Free( &M );
09327     return FALSE;
09328   }
09329   if( !MTX_Copy( &M, A ) )
09330   {
09331     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09332     MTX_Free( &M );
09333     return FALSE;
09334   }
09335   MTX_Free( &M );
09336   return TRUE;
09337 }
09338 
09339 
09340 
09341 // multiply A = B*A, inplace
09342 BOOL MTX_PreMultiply_Inplace( MTX *A, const MTX* B )
09343 {
09344   MTX M;
09345   MTX_Init( &M );
09346 
09347   if( !MTX_Multiply( &M, B, A ) )
09348   {
09349     MTX_ERROR_MSG( "MTX_Multiply returned FALSE." );
09350     MTX_Free( &M );
09351     return FALSE;
09352   }
09353   if( !MTX_Copy( &M, A ) )
09354   {
09355     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09356     MTX_Free( &M );
09357     return FALSE;
09358   }
09359   MTX_Free( &M );
09360   return TRUE;
09361 }
09362 
09363 BOOL MTX_TransposePreMultiply_Inplace( MTX *A, const MTX *B )
09364 {
09365   MTX M;
09366   MTX_Init( &M );
09367 
09368   if( !MTX_TransposeMultiply( &M, B, A ) )
09369   {
09370     MTX_ERROR_MSG( "MTX_TransposeMultiply returned FALSE." );
09371     MTX_Free( &M );
09372     return FALSE;
09373   }
09374   if( !MTX_Copy( &M, A ) )
09375   {
09376     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09377     MTX_Free( &M );
09378     return FALSE;
09379   }
09380   MTX_Free( &M );
09381   return TRUE;
09382 }
09383 
09384 BOOL MTX_DotMultiply_Inplace( MTX *A, const MTX* B )
09385 {
09386   unsigned i = 0;
09387   unsigned j = 0;
09388   double re = 0;
09389   double im = 0;
09390 
09391   if( MTX_isNull( A ) )
09392   {
09393     MTX_ERROR_MSG( "NULL Matrix" );
09394     return FALSE;
09395   }
09396   if( MTX_isNull( B ) )
09397   {
09398     MTX_ERROR_MSG( "NULL Matrix" );
09399     return FALSE;
09400   }
09401 
09402   if( MTX_static_global_treat_1x1_as_scalar )
09403   {
09404     if( A->nrows == 1 && A->ncols == 1 )
09405     {
09406       if( A->isReal )
09407       {
09408         re = A->data[0][0];
09409         if( !MTX_Copy( B, A ) )
09410         {
09411           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09412           return FALSE;
09413         }
09414         return MTX_Multiply_Scalar( A, re );
09415       }
09416       else
09417       {
09418         re = A->cplx[0][0].re;
09419         im = A->cplx[0][0].im;
09420         if( !MTX_Copy( B, A ) )
09421         {
09422           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09423           return FALSE;
09424         }
09425         return MTX_Multiply_ScalarComplex( A, re, im );
09426       }
09427     }
09428     else if( B->nrows == 1 && B->ncols == 1 )
09429     {
09430       if( B->isReal )
09431       {
09432         return MTX_Multiply_Scalar( A, B->data[0][0] );
09433       }
09434       else
09435       {
09436         return MTX_Multiply_ScalarComplex( A, B->cplx[0][0].re, B->cplx[0][0].im );
09437       }
09438     }
09439   }
09440 
09441   if( !MTX_isConformalForAddition( A, B ) )
09442   {
09443     MTX_ERROR_MSG( "MTX_isConformalForAddition returned FALSE." );
09444     return FALSE;
09445   }
09446 
09447   if( A->isReal && !B->isReal )
09448   {
09449     if( !MTX_ConvertRealToComplex( A ) )
09450     {
09451       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
09452       return FALSE;
09453     }
09454   }
09455   
09456   if( A->isReal && B->isReal )
09457   {
09458     for( j = 0; j < A->ncols; j++ )    
09459       for( i = 0; i < A->nrows; i++ )
09460         A->data[j][i] *= B->data[j][i];
09461   }
09462   else if( !A->isReal && !B->isReal )
09463   {
09464     for( j = 0; j < A->ncols; j++ )    
09465     {
09466       for( i = 0; i < A->nrows; i++ )
09467       {
09468         re = A->cplx[j][i].re * B->cplx[j][i].re - A->cplx[j][i].im * B->cplx[j][i].im;
09469         im = A->cplx[j][i].re * B->cplx[j][i].im + A->cplx[j][i].im * B->cplx[j][i].re;
09470         A->cplx[j][i].re = re;
09471         A->cplx[j][i].im = im;
09472       }
09473     }
09474   }
09475   else // !A->isReal && B->isReal
09476   {
09477     for( j = 0; j < A->ncols; j++ )    
09478     {
09479       for( i = 0; i < A->nrows; i++ )
09480       {
09481         A->cplx[j][i].re *= B->data[j][i];
09482         A->cplx[j][i].im *= B->data[j][i];
09483       }
09484     }
09485   }
09486 
09487   return TRUE;
09488 }
09489 
09490 BOOL MTX_DotDivide_Inplace( MTX *A, const MTX* B )
09491 {
09492   unsigned i = 0;
09493   unsigned j = 0;
09494   double re = 0;
09495   double im = 0;
09496   double mag = 0;
09497 
09498   if( MTX_isNull( A ) )
09499   {
09500     MTX_ERROR_MSG( "NULL Matrix" );
09501     return FALSE;
09502   }
09503 
09504   if( MTX_isNull( B ) )
09505   {
09506     MTX_ERROR_MSG( "NULL Matrix" );
09507     return FALSE;
09508   }
09509 
09510   if( A->nrows == 1 && A->ncols == 1 && B->nrows == 1 && B->ncols == 1 )
09511   {
09512     if( !A->isReal && !B->isReal )
09513     {
09514       re = A->cplx[0][0].re;
09515       im = A->cplx[0][0].im;
09516       MTX_static_quick_complex_divide( &re, &im, &B->cplx[0][0].re, &B->cplx[0][0].im, &A->cplx[0][0].re, &A->cplx[0][0].im );
09517       return TRUE;
09518     }
09519     else if( A->isReal && B->isReal )
09520     {
09521       A->data[0][0] /= B->data[0][0];
09522       return TRUE;
09523     }
09524     else
09525     {
09526       if( A->isReal )
09527       {
09528         // B is complex
09529         re = A->data[0][0];
09530         mag = B->cplx[0][0].re*B->cplx[0][0].re + B->cplx[0][0].im*B->cplx[0][0].im;
09531         if( !MTX_Malloc(A,1,1,FALSE) )
09532         {
09533           MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
09534           return FALSE;
09535         }
09536 
09537         A->cplx[0][0].re = re*B->cplx[0][0].re / mag;
09538         A->cplx[0][0].im = -re*B->cplx[0][0].im / mag;
09539       }
09540       else
09541       {
09542         re = B->data[0][0];
09543         // B is real
09544         A->cplx[0][0].re /= re;
09545         A->cplx[0][0].im /= re;
09546       }
09547     }
09548     return TRUE;
09549   }
09550 
09551   if( MTX_static_global_treat_1x1_as_scalar )
09552   {
09553     if( A->nrows == 1 && A->ncols == 1 )
09554     {
09555       // Make A the same dimensions as B and filled with A's scalar value.
09556       // Then compute A./B.
09557       if( A->isReal )
09558       {
09559         // make A the same dimensions as B and filled with A's scalar value
09560         re = A->data[0][0];
09561         if( !MTX_Malloc( A, B->nrows, B->ncols, B->isReal ) )
09562         {
09563           MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
09564           return FALSE;
09565         }
09566         if( !MTX_Fill( A, re ) )
09567         {
09568           MTX_ERROR_MSG( "MTX_Fill returned FALSE." );
09569           return FALSE;
09570         }
09571         return MTX_DotDivide_Inplace( A, B );
09572       }
09573       else
09574       {
09575         re = A->cplx[0][0].re;
09576         im = A->cplx[0][0].im;
09577         if( !MTX_Malloc( A, B->nrows, B->ncols, FALSE ) )
09578         {
09579           MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
09580           return FALSE;
09581         }
09582         if( !MTX_FillComplex( A, re, im ) )
09583         {
09584           MTX_ERROR_MSG( "MTX_FillComplex returned FALSE." );
09585           return FALSE;
09586         }
09587         return MTX_DotDivide_Inplace( A, B );
09588       }
09589     }
09590     else if( B->nrows == 1 && B->ncols == 1 )
09591     {
09592       if( B->isReal )
09593       {
09594         return MTX_Divide_Scalar( A, B->data[0][0] );
09595       }
09596       else
09597       {
09598         return MTX_Divide_ScalarComplex( A, B->cplx[0][0].re, B->cplx[0][0].im );
09599       }
09600     }
09601   }
09602 
09603   if( !MTX_isConformalForAddition( A, B ) )
09604   {
09605     MTX_ERROR_MSG( "MTX_isConformalForAddition returned FALSE." );
09606     return FALSE;
09607   }
09608 
09609   if( A->isReal && !B->isReal )
09610   {
09611     if( !MTX_ConvertRealToComplex( A ) )
09612     {
09613       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
09614       return FALSE;
09615     }
09616   }
09617 
09618   if( A->isReal && B->isReal )
09619   {
09620     for( j = 0; j < A->ncols; j++ )
09621     {
09622       for( i = 0; i < A->nrows; i++ )
09623       {
09624         A->data[j][i] /= B->data[j][i];
09625       }
09626     }
09627   }
09628   else if( !A->isReal && !B->isReal )
09629   {
09630     for( j = 0; j < A->ncols; j++ )
09631     {
09632       for( i = 0; i < A->nrows; i++ )
09633       {
09634         mag = B->cplx[j][i].re*B->cplx[j][i].re + B->cplx[j][i].im*B->cplx[j][i].im;
09635 
09636         re = (A->cplx[j][i].re * B->cplx[j][i].re + A->cplx[j][i].im * B->cplx[j][i].im ) / mag;
09637         im = (A->cplx[j][i].im * B->cplx[j][i].re - A->cplx[j][i].re * B->cplx[j][i].im ) / mag;
09638 
09639         A->cplx[j][i].re = re;
09640         A->cplx[j][i].im = im;
09641       }
09642     }
09643   }
09644   else // !A->isReal && B->isReal
09645   {
09646     for( j = 0; j < A->ncols; j++ )
09647     {    
09648       for( i = 0; i < A->nrows; i++ )
09649       {
09650         A->cplx[j][i].re /= B->data[j][i];
09651         A->cplx[j][i].im /= B->data[j][i];
09652       }
09653     }
09654   }
09655   return TRUE;
09656 }
09657 
09658 BOOL MTX_Add( MTX *A, const MTX* B, const MTX* C )
09659 {
09660   unsigned i = 0;
09661   unsigned j = 0;
09662 
09663   if( MTX_isNull( B ) )
09664   {
09665     MTX_ERROR_MSG( "NULL Matrix" );
09666     return FALSE;
09667   }
09668 
09669   if( MTX_isNull( C ) )
09670   {
09671     MTX_ERROR_MSG( "NULL Matrix" );
09672     return FALSE;
09673   }
09674 
09675   if( MTX_static_global_treat_1x1_as_scalar )
09676   {
09677     if( B->nrows == 1 && B->ncols == 1 )
09678     {
09679       if( B->isReal )
09680       {
09681         if( !MTX_Copy( C, A ) )
09682         {
09683           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09684           return FALSE;
09685         }
09686         return MTX_Add_Scalar( A, B->data[0][0] );
09687       }
09688       else
09689       {
09690         if( !MTX_Copy( C, A ) )
09691         {
09692           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09693           return FALSE;
09694         }
09695         return MTX_Add_ScalarComplex( A, B->cplx[0][0].re, B->cplx[0][0].im );
09696       }
09697     }
09698     else if( C->nrows == 1 && C->ncols == 1 )
09699     {
09700       if( C->isReal )
09701       {
09702         if( !MTX_Copy( B, A ) )
09703         {
09704           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09705           return FALSE;
09706         }
09707         return MTX_Add_Scalar( A, C->data[0][0] );
09708       }
09709       else
09710       {
09711         if( !MTX_Copy( B, A ) )
09712         {
09713           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09714           return FALSE;
09715         }
09716         return MTX_Add_ScalarComplex( A, C->cplx[0][0].re, C->cplx[0][0].im );
09717       }
09718     }
09719   }
09720 
09721 
09722   if( !MTX_isConformalForAddition( B, C ) )
09723   {
09724     MTX_ERROR_MSG( "MTX_isConformalForAddition returned FALSE." );
09725     return FALSE;
09726   }
09727 
09728   if( !B->isReal || !C->isReal )
09729   {
09730     // A will be complex
09731     if( !A->isReal )
09732     {
09733       if( !MTX_Resize( A, B->nrows, B->ncols, FALSE ) )
09734       {
09735         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
09736         return FALSE;
09737       }
09738     }
09739     else
09740     {
09741       if( !MTX_Malloc( A, B->nrows, B->ncols, FALSE ) )
09742       {
09743         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
09744         return FALSE;
09745       }
09746     }
09747   }
09748   else // A will be real
09749   {
09750     if( !A->isReal )
09751     {
09752       if( !MTX_Malloc( A, B->nrows, B->ncols, TRUE ) )
09753       {
09754         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
09755         return FALSE;
09756       }
09757     }
09758     else
09759     {
09760       if( !MTX_Resize( A, B->nrows, B->ncols, TRUE ) )
09761       {
09762         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
09763         return FALSE;
09764       }
09765     }
09766   }
09767   
09768   if( B->isReal && C->isReal )
09769   {
09770     for( j = 0; j < B->ncols; j++ )    
09771       for( i = 0; i < A->nrows; i++ )
09772         A->data[j][i] = B->data[j][i] + C->data[j][i];
09773   }
09774   else if( !B->isReal && !C->isReal )
09775   {
09776     for( j = 0; j < B->ncols; j++ )
09777     {
09778       for( i = 0; i < A->nrows; i++ )
09779       {
09780         A->cplx[j][i].re = B->cplx[j][i].re + C->cplx[j][i].re;
09781         A->cplx[j][i].im = B->cplx[j][i].im + C->cplx[j][i].im;
09782       }
09783     }
09784   }
09785   else if( !B->isReal && C->isReal )
09786   {
09787     for( j = 0; j < B->ncols; j++ )
09788     {    
09789       for( i = 0; i < A->nrows; i++ )
09790       {
09791         A->cplx[j][i].re = B->cplx[j][i].re + C->data[j][i];
09792         A->cplx[j][i].im = B->cplx[j][i].im;
09793       }
09794     }
09795   }
09796   else // ( B->isReal && !C->isReal )
09797   {
09798     for( j = 0; j < B->ncols; j++ )
09799     {    
09800       for( i = 0; i < A->nrows; i++ )
09801       {
09802         A->cplx[j][i].re = B->data[j][i] + C->cplx[j][i].re;
09803         A->cplx[j][i].im = C->cplx[j][i].im;
09804       }
09805     }
09806   }
09807   return TRUE;
09808 }
09809 
09810 BOOL MTX_Subtract( MTX *A, const MTX* B, const MTX* C )
09811 {
09812   unsigned i = 0;
09813   unsigned j = 0;
09814 
09815   if( MTX_isNull( B ) )
09816   {
09817     MTX_ERROR_MSG( "NULL Matrix" );
09818     return FALSE;
09819   }
09820 
09821   if( MTX_isNull( C ) )
09822   {
09823     MTX_ERROR_MSG( "NULL Matrix" );
09824     return FALSE;
09825   }
09826 
09827   if( MTX_static_global_treat_1x1_as_scalar )
09828   {
09829     if( B->nrows == 1 && B->ncols == 1 )
09830     {
09831       // Set A = -C then add B as a scalar.
09832       if( B->isReal )
09833       {
09834         if( !MTX_Copy( C, A ) )
09835         {
09836           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09837           return FALSE;
09838         }
09839         if( !MTX_Negate( A ) )
09840         {
09841           MTX_ERROR_MSG( "MTX_Negate returned FALSE." );
09842           return FALSE;
09843         }
09844         return MTX_Add_Scalar( A, B->data[0][0] );
09845       }
09846       else
09847       {
09848         if( !MTX_Copy( C, A ) )
09849         {
09850           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09851           return FALSE;
09852         }
09853         if( !MTX_Negate( A ) )
09854         {
09855           MTX_ERROR_MSG( "MTX_Negate returned FALSE." );
09856           return FALSE;
09857         }
09858         return MTX_Add_ScalarComplex( A, B->cplx[0][0].re, B->cplx[0][0].im );
09859       }
09860     }
09861     else if( C->nrows == 1 && C->ncols == 1 )
09862     {
09863       // Set A = B, then subtract C as a scalar.
09864       if( C->isReal )
09865       {
09866         if( !MTX_Copy( B, A ) )
09867         {
09868           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09869           return FALSE;
09870         }
09871         return MTX_Subtract_Scalar( A, C->data[0][0] );
09872       }
09873       else
09874       {
09875         if( !MTX_Copy( B, A ) )
09876         {
09877           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
09878           return FALSE;
09879         }
09880         return MTX_Subtract_ScalarComplex( A, C->cplx[0][0].re, C->cplx[0][0].im );
09881       }
09882     }
09883   }
09884 
09885   if( !MTX_isConformalForAddition( B, C ) )
09886   {
09887     MTX_ERROR_MSG( "MTX_isConformalForAddition returned FALSE." );
09888     return FALSE;
09889   }
09890 
09891   if( !B->isReal || !C->isReal )
09892   {
09893     // A will be complex
09894     if( !A->isReal )
09895     {
09896       // and is currently complex, so resize
09897       if( !MTX_Resize( A, B->nrows, B->ncols, FALSE ) )
09898       {
09899         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
09900         return FALSE;
09901       }
09902     }
09903     else
09904     {
09905       if( !MTX_Malloc( A, B->nrows, B->ncols, FALSE ) )
09906       {
09907         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
09908         return FALSE;
09909       }
09910     }
09911   }
09912   else
09913   {
09914     // A will be real
09915     if( !A->isReal )
09916     {
09917       if( !MTX_Malloc( A, B->nrows, B->ncols, TRUE ) )
09918       {
09919         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
09920         return FALSE;
09921       }
09922     }
09923     else
09924     {
09925       // and is currently real, so resize
09926       if( !MTX_Resize( A, B->nrows, B->ncols, TRUE ) )
09927       {
09928         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
09929         return FALSE;
09930       }
09931     }
09932   }
09933   
09934   if( B->isReal && C->isReal )
09935   {
09936     for( j = 0; j < B->ncols; j++ )        
09937       for( i = 0; i < A->nrows; i++ )
09938         A->data[j][i] = B->data[j][i] - C->data[j][i];
09939   }
09940   else if( !B->isReal && !C->isReal )
09941   {
09942     for( j = 0; j < B->ncols; j++ )
09943     {        
09944       for( i = 0; i < A->nrows; i++ )
09945       {
09946         A->cplx[j][i].re = B->cplx[j][i].re - C->cplx[j][i].re;
09947         A->cplx[j][i].im = B->cplx[j][i].im - C->cplx[j][i].im;
09948       }
09949     }
09950   }
09951   else if( !B->isReal && C->isReal )
09952   {
09953     for( j = 0; j < B->ncols; j++ )
09954     {        
09955       for( i = 0; i < A->nrows; i++ )
09956       {
09957         A->cplx[j][i].re = B->cplx[j][i].re - C->data[j][i];
09958         A->cplx[j][i].im = B->cplx[j][i].im;
09959       }
09960     }
09961   }
09962   else // ( B->isReal && !C->isReal )
09963   {
09964     for( j = 0; j < B->ncols; j++ )
09965     {    
09966       for( i = 0; i < A->nrows; i++ )
09967       {
09968         A->cplx[j][i].re = B->data[j][i] - C->cplx[j][i].re;
09969         A->cplx[j][i].im = -1.0*C->cplx[j][i].im;
09970       }
09971     }
09972   }
09973   return TRUE;
09974 }
09975 
09976 BOOL MTX_Multiply( MTX *A, const MTX* B, const MTX* C )
09977 {
09978   unsigned i = 0;
09979   unsigned j = 0;
09980   unsigned k = 0;
09981 
09982   if( MTX_isNull( B ) )
09983   {
09984     MTX_ERROR_MSG( "NULL Matrix" );
09985     return FALSE;
09986   }
09987   if( MTX_isNull( C ) )
09988   {
09989     MTX_ERROR_MSG( "NULL Matrix" );
09990     return FALSE;
09991   }
09992 
09993   if( MTX_static_global_treat_1x1_as_scalar )
09994   {
09995     if( B->nrows == 1 && B->ncols == 1 )
09996     {
09997       // Set A = C then multiply B as a scalar.
09998       if( B->isReal )
09999       {
10000         if( !MTX_Copy( C, A ) )
10001         {
10002           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10003           return FALSE;
10004         }
10005         return MTX_Multiply_Scalar( A, B->data[0][0] );
10006       }
10007       else
10008       {
10009         if( !MTX_Copy( C, A ) )
10010         {
10011           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10012           return FALSE;
10013         }
10014         return MTX_Multiply_ScalarComplex( A, B->cplx[0][0].re, B->cplx[0][0].im );
10015       }
10016     }
10017     else if( C->nrows == 1 && C->ncols == 1 )
10018     {
10019       // Set A = B, then multiply C as a scalar.
10020       if( C->isReal )
10021       {
10022         if( !MTX_Copy( B, A ) )
10023         {
10024           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10025           return FALSE;
10026         }
10027         return MTX_Multiply_Scalar( A, C->data[0][0] );
10028       }
10029       else
10030       {
10031         if( !MTX_Copy( B, A ) )
10032         {
10033           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10034           return FALSE;
10035         }
10036         return MTX_Multiply_ScalarComplex( A, C->cplx[0][0].re, C->cplx[0][0].im );
10037       }
10038     }
10039   }
10040 
10041 
10042   if( !MTX_isConformalForMultiplication( B, C ) )
10043   {
10044     MTX_ERROR_MSG( "MTX_isConformalForMultiplication returned FALSE." );
10045     return FALSE;
10046   }
10047 
10048   if( !B->isReal || !C->isReal )
10049   {
10050     // A will be complex
10051     if( !A->isReal )
10052     {
10053       // and is currently complex, so resize
10054       if( !MTX_Resize( A, B->nrows, C->ncols, FALSE ) )
10055       {
10056         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10057         return FALSE;
10058       }
10059     }
10060     else
10061     {
10062       if( !MTX_Malloc( A, B->nrows, C->ncols, FALSE ) )
10063       {
10064         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
10065         return FALSE;
10066       }
10067     }
10068   }
10069   else
10070   {
10071     // A will be real
10072     if( !A->isReal )
10073     {
10074       if( !MTX_Malloc( A, B->nrows, C->ncols, TRUE ) )
10075       {
10076         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
10077         return FALSE;
10078       }
10079     }
10080     else
10081     {
10082       // and is currently real, so resize
10083       if( !MTX_Resize( A, B->nrows, C->ncols, TRUE ) )
10084       {
10085         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10086         return FALSE;
10087       }
10088     }
10089   }
10090 
10091 
10092 
10093   if( B->isReal && C->isReal )
10094   {
10095     for( i = 0; i < B->nrows; i++ )
10096     {
10097       for( j = 0; j < C->ncols; j++ )
10098       {
10099         k = 0;
10100         A->data[j][i] = B->data[k][i] * C->data[j][k];
10101         for( k = 1; k < B->ncols; k++ )
10102         {
10103           A->data[j][i] += B->data[k][i] * C->data[j][k];
10104         }
10105       }
10106     }
10107   }
10108   else if( !B->isReal && !C->isReal )
10109   {
10110     for( i = 0; i < B->nrows; i++ )
10111     {
10112       for( j = 0; j < C->ncols; j++ )
10113       {
10114         k = 0;
10115         A->cplx[j][i].re = B->cplx[k][i].re * C->cplx[j][k].re - B->cplx[k][i].im * C->cplx[j][k].im;
10116         A->cplx[j][i].im = B->cplx[k][i].re * C->cplx[j][k].im + B->cplx[k][i].im * C->cplx[j][k].re;
10117         for( k = 1; k < B->ncols; k++ )
10118         {
10119           A->cplx[j][i].re += B->cplx[k][i].re * C->cplx[j][k].re - B->cplx[k][i].im * C->cplx[j][k].im;
10120           A->cplx[j][i].im += B->cplx[k][i].re * C->cplx[j][k].im + B->cplx[k][i].im * C->cplx[j][k].re;
10121         }
10122       }
10123     }
10124   }
10125   else if( !B->isReal && C->isReal )
10126   {
10127     for( i = 0; i < B->nrows; i++ )
10128     {
10129       for( j = 0; j < C->ncols; j++ )
10130       {
10131         k = 0;
10132         A->cplx[j][i].re = B->cplx[k][i].re * C->data[j][k];
10133         A->cplx[j][i].im = B->cplx[k][i].im * C->data[j][k];
10134         for( k = 1; k < B->ncols; k++ )
10135         {
10136           A->cplx[j][i].re += B->cplx[k][i].re * C->data[j][k];
10137           A->cplx[j][i].im += B->cplx[k][i].im * C->data[j][k];
10138         }
10139       }
10140     }
10141   }
10142   else if( B->isReal && !C->isReal )
10143   {
10144     for( i = 0; i < B->nrows; i++ )
10145     {
10146       for( j = 0; j < C->ncols; j++ )
10147       {
10148         k = 0;
10149         A->cplx[j][i].re = B->data[k][i] * C->cplx[j][k].re;
10150         A->cplx[j][i].im = B->data[k][i] * C->cplx[j][k].im;
10151         for( k = 1; k < B->ncols; k++ )
10152         {
10153           A->cplx[j][i].re += B->data[k][i] * C->cplx[j][k].re;
10154           A->cplx[j][i].im += B->data[k][i] * C->cplx[j][k].im;
10155         }
10156       }
10157     }
10158   }
10159 
10160   return TRUE;
10161 }
10162 
10163 BOOL MTX_TransposeMultiply( MTX *A, const MTX* B, const MTX* C ) // A = trans(B) x C
10164 {
10165   unsigned i = 0;
10166   unsigned j = 0;
10167   unsigned k = 0;
10168   MTX vec;
10169   MTX_Init( &vec );
10170 
10171   if( MTX_isNull( B ) )
10172   {
10173     MTX_ERROR_MSG( "NULL Matrix" );
10174     return FALSE;
10175   }
10176   if( MTX_isNull( C ) )
10177   {
10178     MTX_ERROR_MSG( "NULL Matrix" );
10179     return FALSE;
10180   }
10181 
10182   if( MTX_static_global_treat_1x1_as_scalar )
10183   {
10184     if( B->nrows == 1 && B->ncols == 1 )
10185     {
10186       // Set A = C then multiply B as a scalar.
10187       if( B->isReal )
10188       {
10189         if( !MTX_Copy( C, A ) )
10190         {
10191           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10192           return FALSE;
10193         }
10194         return MTX_Multiply_Scalar( A, B->data[0][0] );
10195       }
10196       else
10197       {
10198         if( !MTX_Copy( C, A ) )
10199         {
10200           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10201           return FALSE;
10202         }
10203         return MTX_Multiply_ScalarComplex( A, B->cplx[0][0].re, B->cplx[0][0].im );
10204       }
10205     }
10206     else if( C->nrows == 1 && C->ncols == 1 )
10207     {
10208       // Set A = B, then multiply C as a scalar.
10209       if( C->isReal )
10210       {
10211         if( !MTX_Copy( B, A ) )
10212         {
10213           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10214           return FALSE;
10215         }
10216         return MTX_Multiply_Scalar( A, C->data[0][0] );
10217       }
10218       else
10219       {
10220         if( !MTX_Copy( B, A ) )
10221         {
10222           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10223           return FALSE;
10224         }
10225         return MTX_Multiply_ScalarComplex( A, C->cplx[0][0].re, C->cplx[0][0].im );
10226       }
10227     }
10228   }
10229 
10230   // Check conformal for multiplication
10231   if( B->nrows != C->nrows ) 
10232   {
10233     MTX_ERROR_MSG( "Not conformal for multiplication." );
10234     return FALSE;
10235   }
10236 
10237   if( !B->isReal || !C->isReal )
10238   {
10239     // A will be complex
10240     if( !A->isReal )
10241     {
10242       // and is currently complex, so resize
10243       if( !MTX_Resize( A, B->ncols, C->ncols, FALSE ) )
10244       {
10245         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10246         return FALSE;
10247       }
10248     }
10249     else
10250     {
10251       if( !MTX_Malloc( A, B->ncols, C->ncols, FALSE ) )
10252       {
10253         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
10254         return FALSE;
10255       }
10256     }
10257   }
10258   else
10259   {
10260     // A will be real
10261     if( !A->isReal )
10262     {
10263       if( !MTX_Malloc( A, B->ncols, C->ncols, TRUE ) )
10264       {
10265         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
10266         return FALSE;
10267       }
10268     }
10269     else
10270     {
10271       // and is currently real, so resize
10272       if( !MTX_Resize( A, B->ncols, C->ncols, TRUE ) )
10273       {
10274         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10275         return FALSE;
10276       }
10277     }
10278   }
10279 
10280 
10281 
10282   if( B->isReal && C->isReal )
10283   {
10284     for( i = 0; i < B->ncols; i++ )
10285     {
10286       for( j = 0; j < C->ncols; j++ )
10287       {
10288         k = 0;
10289         A->data[j][i] = B->data[i][k] * C->data[j][k];
10290         for( k = 1; k < B->nrows; k++ )
10291         {
10292           A->data[j][i] += B->data[i][k] * C->data[j][k];
10293         }
10294       }
10295     }
10296   }
10297   else if( !B->isReal && !C->isReal )
10298   {
10299     for( i = 0; i < B->ncols; i++ )
10300     {
10301       for( j = 0; j < C->ncols; j++ )
10302       {
10303         k = 0;
10304         A->cplx[j][i].re = B->cplx[i][k].re * C->cplx[j][k].re - B->cplx[i][k].im * C->cplx[j][k].im;
10305         A->cplx[j][i].im = B->cplx[i][k].re * C->cplx[j][k].im + B->cplx[i][k].im * C->cplx[j][k].re;
10306         for( k = 1; k < B->nrows; k++ )
10307         {
10308           A->cplx[j][i].re += B->cplx[i][k].re * C->cplx[j][k].re - B->cplx[i][k].im * C->cplx[j][k].im;
10309           A->cplx[j][i].im += B->cplx[i][k].re * C->cplx[j][k].im + B->cplx[i][k].im * C->cplx[j][k].re;
10310         }
10311       }
10312     }
10313   }
10314   else if( !B->isReal && C->isReal )
10315   {
10316     for( i = 0; i < B->ncols; i++ )
10317     {
10318       for( j = 0; j < C->ncols; j++ )
10319       {
10320         k = 0;
10321         A->cplx[j][i].re = B->cplx[i][k].re * C->data[j][k];
10322         A->cplx[j][i].im = B->cplx[i][k].im * C->data[j][k];
10323         for( k = 1; k < B->nrows; k++ )
10324         {
10325           A->cplx[j][i].re += B->cplx[i][k].re * C->data[j][k];
10326           A->cplx[j][i].im += B->cplx[i][k].im * C->data[j][k];
10327         }
10328       }
10329     }
10330   }
10331   else if( B->isReal && !C->isReal )
10332   {
10333     for( i = 0; i < B->ncols; i++ )
10334     {
10335       for( j = 0; j < C->ncols; j++ )
10336       {
10337         k = 0;
10338         A->cplx[j][i].re = B->data[i][k] * C->cplx[j][k].re;
10339         A->cplx[j][i].im = B->data[i][k] * C->cplx[j][k].im;
10340         for( k = 1; k < B->nrows; k++ )
10341         {
10342           A->cplx[j][i].re += B->data[i][k] * C->cplx[j][k].re;
10343           A->cplx[j][i].im += B->data[i][k] * C->cplx[j][k].im;
10344         }
10345       }
10346     }
10347   }
10348 
10349   return TRUE;
10350 }
10351 
10352 
10353 BOOL MTX_MultiplyTranspose( MTX *A, const MTX* B, const MTX* C ) // A = B*transpose(C)
10354 {
10355   unsigned i = 0;
10356   unsigned j = 0;
10357   unsigned k = 0;
10358 
10359   if( MTX_isNull( B ) )
10360   {
10361     MTX_ERROR_MSG( "NULL Matrix" );
10362     return FALSE;
10363   }
10364   if( MTX_isNull( C ) )
10365   {
10366     MTX_ERROR_MSG( "NULL Matrix" );
10367     return FALSE;
10368   }
10369 
10370   if( MTX_static_global_treat_1x1_as_scalar )
10371   {
10372     if( B->nrows == 1 && B->ncols == 1 )
10373     {
10374       // Set A = C then multiply B as a scalar.
10375       if( B->isReal )
10376       {
10377         if( !MTX_Copy( C, A ) )
10378         {
10379           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10380           return FALSE;
10381         }
10382         return MTX_Multiply_Scalar( A, B->data[0][0] );
10383       }
10384       else
10385       {
10386         if( !MTX_Copy( C, A ) )
10387         {
10388           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10389           return FALSE;
10390         }
10391         return MTX_Multiply_ScalarComplex( A, B->cplx[0][0].re, B->cplx[0][0].im );
10392       }
10393     }
10394     else if( C->nrows == 1 && C->ncols == 1 )
10395     {
10396       // Set A = B, then multiply C as a scalar.
10397       if( C->isReal )
10398       {
10399         if( !MTX_Copy( B, A ) )
10400         {
10401           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10402           return FALSE;
10403         }
10404         return MTX_Multiply_Scalar( A, C->data[0][0] );
10405       }
10406       else
10407       {
10408         if( !MTX_Copy( B, A ) )
10409         {
10410           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
10411           return FALSE;
10412         }
10413         return MTX_Multiply_ScalarComplex( A, C->cplx[0][0].re, C->cplx[0][0].im );
10414       }
10415     }
10416   }
10417 
10418   // check conformal for multiplication
10419   if( B->ncols != C->ncols )
10420   {
10421     MTX_ERROR_MSG( "Not conformal for multiplication." );
10422     return FALSE;
10423   }
10424 
10425 
10426 
10427   if( !B->isReal || !C->isReal )
10428   {
10429     // A will be complex
10430     if( !A->isReal )
10431     {
10432       // and is currently complex, so resize
10433       if( !MTX_Resize( A, B->nrows, C->nrows, FALSE ) )
10434       {
10435         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10436         return FALSE;
10437       }
10438     }
10439     else
10440     {
10441       if( !MTX_Malloc( A, B->nrows, C->nrows, FALSE ) )
10442       {
10443         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
10444         return FALSE;
10445       }
10446     }
10447   }
10448   else
10449   {
10450     // A will be real
10451     if( !A->isReal )
10452     {
10453       if( !MTX_Malloc( A, B->nrows, C->nrows, TRUE ) )
10454       {
10455         MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
10456         return FALSE;
10457       }
10458     }
10459     else
10460     {
10461       // and is currently real, so resize
10462       if( !MTX_Resize( A, B->nrows, C->nrows, TRUE ) )
10463       {
10464         MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10465         return FALSE;
10466       }
10467     }
10468   }
10469 
10470   if( B->isReal && C->isReal )
10471   {
10472     for( i = 0; i < B->nrows; i++ )
10473     {
10474       for( j = 0; j < C->nrows; j++ )
10475       {
10476         k = 0;
10477         A->data[j][i] = B->data[k][i] * C->data[k][j];
10478         for( k = 1; k < B->ncols; k++ )
10479         {
10480           A->data[j][i] += B->data[k][i] * C->data[k][j];
10481         }
10482       }
10483     }
10484   }
10485   else if( !B->isReal && !C->isReal )
10486   {
10487     for( i = 0; i < B->nrows; i++ )
10488     {
10489       for( j = 0; j < C->nrows; j++ )
10490       {
10491         k = 0;
10492         A->cplx[j][i].re = B->cplx[k][i].re * C->cplx[k][j].re - B->cplx[k][i].im * C->cplx[k][j].im;
10493         A->cplx[j][i].im = B->cplx[k][i].re * C->cplx[k][j].im + B->cplx[k][i].im * C->cplx[k][j].re;
10494         for( k = 1; k < B->ncols; k++ )
10495         {
10496           A->cplx[j][i].re += B->cplx[k][i].re * C->cplx[k][j].re - B->cplx[k][i].im * C->cplx[k][j].im;
10497           A->cplx[j][i].im += B->cplx[k][i].re * C->cplx[k][j].im + B->cplx[k][i].im * C->cplx[k][j].re;
10498         }
10499       }
10500     }
10501   }
10502   else if( !B->isReal && C->isReal )
10503   {
10504     for( i = 0; i < B->nrows; i++ )
10505     {
10506       for( j = 0; j < C->nrows; j++ )
10507       {
10508         k = 0;
10509         A->cplx[j][i].re = B->cplx[k][i].re * C->data[k][j];
10510         A->cplx[j][i].im = B->cplx[k][i].im * C->data[k][j];
10511         for( k = 1; k < B->ncols; k++ )
10512         {
10513           A->cplx[j][i].re += B->cplx[k][i].re * C->data[k][j];
10514           A->cplx[j][i].im += B->cplx[k][i].im * C->data[k][j];
10515         }
10516       }
10517     }
10518   }
10519   else if( B->isReal && !C->isReal )
10520   {
10521     for( i = 0; i < B->nrows; i++ )
10522     {
10523       for( j = 0; j < C->nrows; j++ )
10524       {
10525         k = 0;
10526         A->cplx[j][i].re = B->data[k][i] * C->cplx[k][j].re;
10527         A->cplx[j][i].im = B->data[k][i] * C->cplx[k][j].im;
10528         for( k = 1; k < B->ncols; k++ )
10529         {
10530           A->cplx[j][i].re += B->data[k][i] * C->cplx[k][j].re;
10531           A->cplx[j][i].im += B->data[k][i] * C->cplx[k][j].im;
10532         }
10533       }
10534     }
10535   }
10536   return TRUE;
10537 }
10538 
10539 
10540 
10541 BOOL MTX_IsEqual( const MTX *A, const MTX *B, const double tolerance, BOOL *isEqual )
10542 {
10543   unsigned i = 0;
10544   unsigned j = 0;
10545   double fabsval;
10546 
10547   if( MTX_isNull( A ) )
10548   {
10549     MTX_ERROR_MSG( "NULL Matrix" );
10550     return FALSE;
10551   }
10552 
10553   if( MTX_isNull( B ) )
10554   {
10555     MTX_ERROR_MSG( "NULL Matrix" );
10556     return FALSE;
10557   }
10558 
10559 
10560   if( MTX_static_global_treat_1x1_as_scalar )
10561   {
10562     if( A->nrows == 1 && A->ncols == 1 )
10563     {
10564       if( A->isReal )
10565       {
10566         if( B->isReal )
10567         {
10568           for( j = 0; j < B->ncols; j++ )
10569           {
10570             for( i = 0; i < B->nrows; i++ )
10571             {
10572               fabsval = fabs( A->data[0][0] - B->data[j][i] );
10573               if( fabsval > tolerance )
10574               {
10575                 *isEqual = FALSE;
10576                 return TRUE;
10577               }
10578             }
10579           }
10580           *isEqual = TRUE;
10581           return TRUE;
10582         }
10583         else
10584         {
10585           // Check if there are any complex values larger than the tolerance.
10586           for( j = 0; j < B->ncols; j++ )
10587           {
10588             for( i = 0; i < B->nrows; i++ )
10589             {
10590               fabsval = fabs( A->data[0][0] - B->cplx[j][i].re );
10591               if( fabsval > tolerance )
10592               {
10593                 *isEqual = FALSE;
10594                 return TRUE;
10595               }
10596 
10597               fabsval = fabs( B->cplx[j][i].im );
10598               if( fabsval > tolerance )
10599               {
10600                 *isEqual = FALSE;
10601                 return TRUE;
10602               }
10603             }
10604           }
10605           *isEqual = TRUE;
10606           return TRUE;
10607         }
10608       }
10609       else
10610       {
10611         if( B->isReal )
10612         {
10613           fabsval = fabs( A->cplx[0][0].im );
10614           if( fabsval > tolerance )
10615           {
10616             *isEqual = FALSE;
10617             return TRUE;
10618           }
10619 
10620           for( j = 0; j < B->ncols; j++ )
10621           {
10622             for( i = 0; i < B->nrows; i++ )
10623             {
10624               fabsval = fabs( A->cplx[0][0].re - B->data[j][i] );
10625               if( fabsval > tolerance )
10626               {
10627                 *isEqual = FALSE;
10628                 return TRUE;
10629               }
10630             }
10631           }
10632           *isEqual = TRUE;
10633           return TRUE;
10634         }
10635         else
10636         {
10637           // Check if there are any complex values larger than the tolerance.
10638           for( j = 0; j < B->ncols; j++ )
10639           {
10640             for( i = 0; i < B->nrows; i++ )
10641             {
10642               fabsval = fabs( A->cplx[0][0].re - B->cplx[j][i].re );
10643               if( fabsval > tolerance )
10644               {
10645                 *isEqual = FALSE;
10646                 return TRUE;
10647               }
10648 
10649               fabsval = fabs( A->cplx[0][0].im - B->cplx[j][i].im );
10650               if( fabsval > tolerance )
10651               {
10652                 *isEqual = FALSE;
10653                 return TRUE;
10654               }
10655             }
10656           }
10657           *isEqual = TRUE;
10658           return TRUE;
10659         }
10660       } // if( A->isReal ) else
10661     }
10662     else if( B->nrows == 1 && B->ncols == 1 )
10663     {
10664       // Cheat a little by calling this function again but reorder the arguments.
10665       return MTX_IsEqual( B, A, tolerance, isEqual );
10666     }
10667   }
10668 
10669   if( !MTX_isConformalForAddition( A, B ) )
10670   {
10671     MTX_ERROR_MSG( "MTX_isConformalForAddition returned FALSE." );
10672     return FALSE;
10673   }
10674 
10675   *isEqual = TRUE;
10676 
10677   if( A->isReal && B->isReal )
10678   {
10679     for( j = 0; j < A->ncols; j++ )
10680     {
10681       for( i = 0; i < A->nrows; i++ )
10682       {
10683         fabsval = fabs( A->data[j][i] - B->data[j][i] );
10684         if( fabsval > tolerance )
10685         {
10686           *isEqual = FALSE;
10687           return TRUE;
10688         }
10689       }
10690     }
10691   }
10692   else if( !A->isReal && !B->isReal )
10693   {
10694     for( j = 0; j < A->ncols; j++ )
10695     {
10696       for( i = 0; i < A->nrows; i++ )
10697       {
10698         fabsval = fabs( A->cplx[j][i].re - B->cplx[j][i].re );
10699         if( fabsval > tolerance )
10700         {
10701           *isEqual = FALSE;
10702           return TRUE;
10703         }
10704         fabsval = fabs( A->cplx[j][i].im - B->cplx[j][i].im );
10705         if( fabsval > tolerance )
10706         {
10707           *isEqual = FALSE;
10708           return TRUE;
10709         }
10710       }
10711     }
10712   }
10713   else if( !A->isReal && B->isReal )
10714   {
10715     for( j = 0; j < A->ncols; j++ )
10716     {
10717       for( i = 0; i < A->nrows; i++ )
10718       {
10719         fabsval = fabs( A->cplx[j][i].re - B->data[j][i] );
10720         if( fabsval > tolerance )
10721         {
10722           *isEqual = FALSE;
10723           return TRUE;
10724         }
10725         fabsval = fabs( A->cplx[j][i].im );
10726         if( fabsval > tolerance )
10727         {
10728           *isEqual = FALSE;
10729           return TRUE;
10730         }
10731       }
10732     }
10733   }
10734   else if( A->isReal && !B->isReal )
10735   {
10736     for( j = 0; j < A->ncols; j++ )
10737     {
10738       for( i = 0; i < A->nrows; i++ )
10739       {
10740         fabsval = fabs( A->data[j][i] - B->cplx[j][i].re );
10741         if( fabsval > tolerance )
10742         {
10743           *isEqual = FALSE;
10744           return TRUE;
10745         }
10746         fabsval = fabs( B->cplx[j][i].im );
10747         if( fabsval > tolerance )
10748         {
10749           *isEqual = FALSE;
10750           return TRUE;
10751         }
10752       }
10753     }
10754   }
10755 
10756   return TRUE;
10757 }
10758 
10759 BOOL MTX_ColumnDiff( const MTX *M, MTX *Diff, const unsigned col )
10760 {
10761   unsigned i = 0;
10762 
10763   if( MTX_isNull( M ) )
10764   {
10765     MTX_ERROR_MSG( "NULL Matrix" );
10766     return FALSE;
10767   }
10768 
10769   if( col >= M->ncols )
10770   {
10771     MTX_ERROR_MSG( "if( col >= M->ncols )" );
10772     return FALSE;
10773   }
10774 
10775   if( M->nrows == 1 )
10776   {
10777     MTX_ERROR_MSG( "if( M->nrows == 1 )" );
10778     return FALSE;
10779   }
10780 
10781   if( M->isReal != Diff->isReal )
10782   {
10783     if( !MTX_Resize( Diff, M->nrows-1, 1, M->isReal ) )
10784     {
10785       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10786       return FALSE;
10787     }
10788   }
10789   else if( Diff->nrows != M->nrows-1 || Diff->ncols != 1 )
10790   {
10791     if( !MTX_Resize( Diff, M->nrows-1, 1, M->isReal ) )
10792     {
10793       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10794       return FALSE;
10795     }
10796   }
10797   
10798   if( M->isReal )
10799   {
10800     for( i = 0; i < M->nrows-1; i++ )
10801     {
10802       Diff->data[0][i] = M->data[col][i+1] - M->data[col][i];
10803     }
10804   }
10805   else
10806   {
10807     for( i = 0; i < M->nrows-1; i++ )
10808     {
10809       Diff->cplx[0][i].re = M->cplx[col][i+1].re - M->cplx[col][i].re;
10810       Diff->cplx[0][i].im = M->cplx[col][i+1].im - M->cplx[col][i].im;
10811     }
10812   }
10813 
10814   return TRUE;
10815 }
10816 
10817 BOOL MTX_Diff( const MTX *M, MTX *Diff )
10818 {
10819   unsigned i = 0;
10820   unsigned j = 0;
10821 
10822   if( MTX_isNull( M ) )
10823   {
10824     MTX_ERROR_MSG( "NULL Matrix" );
10825     return FALSE;
10826   }
10827 
10828   if( M->nrows == 1 )
10829   {
10830     MTX_ERROR_MSG( "if( M->nrows == 1 )" );
10831     return FALSE;
10832   }
10833 
10834   if( M->isReal != Diff->isReal )
10835   {
10836     if( !MTX_Resize( Diff, M->nrows-1, M->ncols, M->isReal ) )
10837     {
10838       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10839       return FALSE;
10840     }
10841   }
10842   else if( Diff->nrows != M->nrows-1 || Diff->ncols != M->ncols )
10843   {
10844     if( !MTX_Resize( Diff, M->nrows-1, M->ncols, M->isReal ) )
10845     {
10846       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
10847       return FALSE;
10848     }
10849   }
10850 
10851 
10852   if( M->isReal )
10853   {
10854     for( j = 0; j < M->ncols; j++ )
10855     {
10856       for( i = 0; i < M->nrows-1; i++ )
10857       {
10858         Diff->data[j][i] = M->data[j][i+1] - M->data[j][i];
10859       }
10860     }
10861   }
10862   else
10863   {
10864     for( j = 0; j < M->ncols; j++ )
10865     {
10866       for( i = 0; i < M->nrows-1; i++ )
10867       {
10868         Diff->cplx[j][i].re = M->cplx[j][i+1].re - M->cplx[j][i].re;
10869         Diff->cplx[j][i].im = M->cplx[j][i+1].im - M->cplx[j][i].im;
10870       }
10871     }
10872   }
10873 
10874   return TRUE;
10875 }
10876 
10877 
10878 
10879 
10880 
10881 //-----------------------------------------------------------------------------------------------------------------//
10882 //-----------------------------------------------------------------------------------------------------------------//
10883 //-----------------------------------------------------------------------------------------------------------------//
10884 // Statistics Operations
10885 //-----------------------------------------------------------------------------------------------------------------//
10886 //-----------------------------------------------------------------------------------------------------------------//
10887 //-----------------------------------------------------------------------------------------------------------------//
10888 
10889 
10890 BOOL MTX_MaxColIndex( const MTX *M, const unsigned col, double *re, double *im, unsigned *row )
10891 {
10892   unsigned i = 0;
10893 
10894   if( MTX_isNull( M ) )
10895   {
10896     MTX_ERROR_MSG( "NULL Matrix" );
10897     return FALSE;
10898   }
10899 
10900   if( col >= M->ncols )
10901   {
10902     MTX_ERROR_MSG( "if( col >= M->ncols )" );
10903     return FALSE;
10904   }
10905 
10906   if( M->isReal )
10907   {
10908     *im = 0;
10909     *re = M->data[col][0];
10910     *row = 0;
10911     for( i = 1; i < M->nrows; i++ )
10912     {
10913       if( M->data[col][i] > *re )
10914       {
10915         *re = M->data[col][i];
10916         *row = i;
10917       }
10918     }
10919   }
10920   else
10921   {
10922     MTX C; // the column to search
10923     MTX mag; // the magnitude of that column
10924     MTX_Init( &C );
10925     MTX_Init( &mag );
10926 
10927     if( !MTX_CopyColumn( M, col, &C ) )
10928     {
10929       MTX_ERROR_MSG( "MTX_CopyColumn returned FALSE." );
10930       return FALSE;
10931     }
10932     if( !MTX_Magnitude( &C, &mag ) )
10933     {
10934       MTX_ERROR_MSG( "MTX_Magnitude returned FALSE." );
10935       MTX_Free( &C );
10936       return FALSE;
10937     }
10938 
10939     *re = 0;
10940     *im = 0;
10941     *re = mag.data[0][0];
10942     *row = 0;
10943     for( i = 1; i < mag.nrows; i++ )
10944     {
10945       if( mag.data[0][i] > *re )
10946       {
10947         *re = mag.data[0][i];
10948         *row = i;
10949       }
10950     }
10951 
10952     *re = C.cplx[0][*row].re;
10953     *im = C.cplx[0][*row].im;
10954 
10955     MTX_Free( &C );
10956     MTX_Free( &mag );
10957   }
10958 
10959   return TRUE;
10960 }
10961 
10962 BOOL MTX_MaxRowIndex( const MTX *M, const unsigned row, double *re, double *im, unsigned *col )
10963 {
10964   unsigned i = 0;
10965 
10966   if( MTX_isNull( M ) )
10967   {
10968     MTX_ERROR_MSG( "NULL Matrix" );
10969     return FALSE;
10970   }
10971 
10972   if( row >= M->nrows )
10973   {
10974     MTX_ERROR_MSG( "if( row >= M->nrows )" );
10975     return FALSE;
10976   }
10977 
10978   if( M->isReal )
10979   {
10980     *im = 0;
10981     *re = M->data[0][row];
10982     *col = 0;
10983     for( i = 1; i < M->ncols; i++ )
10984     {
10985       if( M->data[i][row] > *re )
10986       {
10987         *re = M->data[i][row];
10988         *col = i;
10989       }
10990     }
10991   }
10992   else
10993   {
10994     MTX C; // A column matrix (nx1) that is 1xn row of M (transposed).
10995     MTX mag; // The magnitude of that column.
10996     MTX_Init( &C );
10997     MTX_Init( &mag );
10998 
10999     if( !MTX_CopyRowIntoAColumnMatrix( M, row, &C ) )
11000     {
11001       MTX_ERROR_MSG( "MTX_CopyRowIntoAColumnMatrix returned FALSE." );
11002       return FALSE;
11003     }
11004     if( !MTX_Magnitude( &C, &mag ) )
11005     {
11006       MTX_ERROR_MSG( "MTX_Magnitude returned FALSE." );
11007       MTX_Free( &C );
11008       return FALSE;
11009     }
11010 
11011     *re = 0;
11012     *im = 0;
11013     *re = mag.data[0][0];
11014     *col = 0;
11015     for( i = 1; i < mag.nrows; i++ )
11016     {
11017       if( mag.data[0][i] > *re )
11018       {
11019         *re = mag.data[0][i];
11020         *col = i;
11021       }
11022     }
11023 
11024     *re = M->cplx[*col][row].re;
11025     *im = M->cplx[*col][row].im;
11026 
11027     MTX_Free( &C );
11028     MTX_Free( &mag );
11029   }
11030 
11031   return TRUE;
11032 }
11033 
11034 BOOL MTX_MinColIndex( const MTX *M, const unsigned col, double *re, double *im, unsigned *row )
11035 {
11036   unsigned i = 0;
11037 
11038   if( MTX_isNull( M ) )
11039   {
11040     MTX_ERROR_MSG( "NULL Matrix" );
11041     return FALSE;
11042   }
11043 
11044   if( col >= M->ncols )
11045   {
11046     MTX_ERROR_MSG( "if( col >= M->ncols )" );
11047     return FALSE;
11048   }
11049 
11050   if( M->isReal )
11051   {
11052     *im = 0;
11053     *re = M->data[col][0];
11054     *row = 0;
11055     for( i = 1; i < M->nrows; i++ )
11056     {
11057       if( M->data[col][i] < *re )
11058       {
11059         *re = M->data[col][i];
11060         *row = i;
11061       }
11062     }
11063   }
11064   else
11065   {
11066     MTX C; // the column to search
11067     MTX mag; // the magnitude of that column
11068     MTX_Init( &C );
11069     MTX_Init( &mag );
11070 
11071     if( !MTX_CopyColumn( M, col, &C ) )
11072     {
11073       MTX_ERROR_MSG( "MTX_CopyColumn returned FALSE." );
11074       return FALSE;
11075     }
11076     if( !MTX_Magnitude( &C, &mag ) )
11077     {
11078       MTX_ERROR_MSG( "MTX_Magnitude returned FALSE." );
11079       MTX_Free( &C );
11080       return FALSE;
11081     }
11082 
11083     *re = 0;
11084     *im = 0;
11085     *re = mag.data[0][0];
11086     *row = 0;
11087     for( i = 1; i < mag.nrows; i++ )
11088     {
11089       if( mag.data[0][i] < *re )
11090       {
11091         *re = mag.data[0][i];
11092         *row = i;
11093       }
11094     }
11095 
11096     *re = C.cplx[0][*row].re;
11097     *im = C.cplx[0][*row].im;
11098 
11099     MTX_Free( &C );
11100     MTX_Free( &mag );
11101   }
11102 
11103   return TRUE;
11104 }
11105 
11106 BOOL MTX_MinRowIndex( const MTX *M, const unsigned row, double *re, double *im, unsigned *col )
11107 {
11108   unsigned i = 0;
11109 
11110   if( MTX_isNull( M ) )
11111   {
11112     MTX_ERROR_MSG( "NULL Matrix" );
11113     return FALSE;
11114   }
11115 
11116   if( row >= M->nrows )
11117   {
11118     MTX_ERROR_MSG( "if( row >= M->nrows )" );
11119     return FALSE;
11120   }
11121 
11122   if( M->isReal )
11123   {
11124     *im = 0;
11125     *re = M->data[0][row];
11126     *col = 0;
11127     for( i = 1; i < M->ncols; i++ )
11128     {
11129       if( M->data[i][row] < *re )
11130       {
11131         *re = M->data[i][row];
11132         *col = i;
11133       }
11134     }
11135   }
11136   else
11137   {
11138     MTX C; // A column matrix (nx1) that is 1xn row of M (transposed).
11139     MTX mag; // The magnitude of that column.
11140     MTX_Init( &C );
11141     MTX_Init( &mag );
11142 
11143     if( !MTX_CopyRowIntoAColumnMatrix( M, row, &C ) )
11144     {
11145       MTX_ERROR_MSG( "MTX_CopyRowIntoAColumnMatrix returned FALSE." );
11146       return FALSE;
11147     }
11148     if( !MTX_Magnitude( &C, &mag ) )
11149     {
11150       MTX_ERROR_MSG( "MTX_Magnitude returned FALSE." );
11151       MTX_Free( &C );
11152       return FALSE;
11153     }
11154 
11155     *re = 0;
11156     *im = 0;
11157     *re = mag.data[0][0];
11158     *col = 0;
11159     for( i = 1; i < mag.nrows; i++ )
11160     {
11161       if( mag.data[0][i] < *re )
11162       {
11163         *re = mag.data[0][i];
11164         *col = i;
11165       }
11166     }
11167 
11168     *re = M->cplx[*col][row].re;
11169     *im = M->cplx[*col][row].im;
11170 
11171     MTX_Free( &C );
11172     MTX_Free( &mag );
11173   }
11174 
11175   return TRUE;
11176 }
11177 
11178 BOOL MTX_MaxAbsColIndex( const MTX *M, const unsigned col, double *value, unsigned *row )
11179 {
11180   double re;
11181   double im;
11182   MTX copyCol; // A copy of the column to search.
11183 
11184   if( MTX_isNull( M ) )
11185   {
11186     MTX_ERROR_MSG( "NULL Matrix" );
11187     return FALSE;
11188   }
11189 
11190   if( col >= M->ncols )
11191   {
11192     MTX_ERROR_MSG( "if( col >= M->ncols )" );
11193     return FALSE;
11194   }
11195 
11196   // init the copy
11197   MTX_Init( &copyCol );
11198 
11199   // make a copy
11200   if( !MTX_CopyColumn( M, col, &copyCol ) )
11201   {
11202     MTX_ERROR_MSG( "MTX_CopyColumn returned FALSE." );
11203     return FALSE;
11204   }
11205 
11206   // take the abs
11207   if( !MTX_Abs( &copyCol ) )
11208   {
11209     MTX_ERROR_MSG( "MTX_Abs returned FALSE." );
11210     MTX_Free( &copyCol );
11211     return FALSE;
11212   }
11213 
11214   // find the maximum
11215   if( !MTX_MaxColIndex( &copyCol, 0, &re, &im, row ) )
11216   {
11217     MTX_ERROR_MSG( "MTX_MaxColIndex returned FALSE." );
11218     MTX_Free( &copyCol );
11219     return FALSE;
11220   }
11221 
11222   *value = re;
11223 
11224   MTX_Free( &copyCol );
11225   return TRUE;
11226 }
11227 
11228 BOOL MTX_MaxAbsRowIndex( const MTX *M, const unsigned row, double *value, unsigned *col )
11229 {
11230   double re;
11231   double im;
11232   MTX copyCol; // A copy of the row to search transposed into a column.
11233 
11234   if( MTX_isNull( M ) )
11235   {
11236     MTX_ERROR_MSG( "NULL Matrix" );
11237     return FALSE;
11238   }
11239 
11240   if( row >= M->nrows )
11241   {
11242     MTX_ERROR_MSG( "if( row >= M->nrows )" );
11243     return FALSE;
11244   }
11245 
11246   // init the copy
11247   MTX_Init( &copyCol );
11248 
11249   // make a copy or the row into a column matrix for faster searching.
11250   if( !MTX_CopyRowIntoAColumnMatrix( M, row, &copyCol ) )
11251   {
11252     MTX_ERROR_MSG( "MTX_CopyRowIntoAColumnMatrix returned FALSE." );
11253     MTX_Free( &copyCol );
11254     return FALSE;
11255   }
11256 
11257   // take the abs
11258   if( !MTX_Abs( &copyCol ) )
11259   {
11260     MTX_ERROR_MSG( "MTX_Abs returned FALSE." );
11261     MTX_Free( &copyCol );
11262     return FALSE;
11263   }
11264 
11265   // find the maximum
11266   if( !MTX_MaxColIndex( &copyCol, 0, &re, &im, col ) )
11267   {
11268     MTX_ERROR_MSG( "MTX_MaxColIndex returned FALSE." );
11269     MTX_Free( &copyCol );
11270     return FALSE;
11271   }
11272 
11273   *value = re;
11274 
11275   MTX_Free( &copyCol );
11276   return TRUE;
11277 }
11278 
11279 BOOL MTX_MinAbsColIndex( const MTX *M, const unsigned col, double *value, unsigned *row )
11280 {
11281   double re;
11282   double im;
11283   MTX copyCol; // A copy of the column to search.
11284 
11285   if( MTX_isNull( M ) )
11286   {
11287     MTX_ERROR_MSG( "NULL Matrix" );
11288     return FALSE;
11289   }
11290 
11291   if( col >= M->ncols )
11292   {
11293     MTX_ERROR_MSG( "if( col >= M->ncols )" );
11294     return FALSE;
11295   }
11296 
11297   // init the copy
11298   MTX_Init( &copyCol );
11299 
11300   // make a copy
11301   if( !MTX_CopyColumn( M, col, &copyCol ) )
11302   {
11303     MTX_ERROR_MSG( "MTX_CopyColumn returned FALSE." );
11304     MTX_Free( &copyCol );
11305     return FALSE;
11306   }
11307 
11308   // take the abs
11309   if( !MTX_Abs( &copyCol ) )
11310   {
11311     MTX_ERROR_MSG( "MTX_Abs returned FALSE." );
11312     MTX_Free( &copyCol );
11313     return FALSE;
11314   }
11315 
11316   // find the maximum
11317   if( !MTX_MinColIndex( &copyCol, 0, &re, &im, row ) )
11318   {
11319     MTX_ERROR_MSG( "MTX_MinColIndex returned FALSE." );
11320     MTX_Free( &copyCol );
11321     return FALSE;
11322   }
11323 
11324   *value = re;
11325 
11326   MTX_Free( &copyCol );
11327   return TRUE;
11328 }
11329 
11330 BOOL MTX_MinAbsRowIndex( const MTX *M, const unsigned row, double *value, unsigned *col )
11331 {
11332   double re;
11333   double im;
11334   MTX copyCol; // A copy of the row to search transposed into a column.
11335 
11336   if( MTX_isNull( M ) )
11337   {
11338     MTX_ERROR_MSG( "NULL Matrix" );
11339     return FALSE;
11340   }
11341 
11342   if( row >= M->nrows )
11343   {
11344     MTX_ERROR_MSG( "if( row >= M->nrows )" );
11345     return FALSE;
11346   }
11347 
11348   // init the copy
11349   MTX_Init( &copyCol );
11350 
11351   // make a copy or the row into a column matrix for faster searching.
11352   if( !MTX_CopyRowIntoAColumnMatrix( M, row, &copyCol ) )
11353   {
11354     MTX_ERROR_MSG( "MTX_CopyRowIntoAColumnMatrix returned FALSE." );
11355     MTX_Free( &copyCol );
11356     return FALSE;
11357   }
11358 
11359   // take the abs
11360   if( !MTX_Abs( &copyCol ) )
11361   {
11362     MTX_ERROR_MSG( "MTX_Abs returned FALSE." );
11363     MTX_Free( &copyCol );
11364     return FALSE;
11365   }
11366 
11367   // find the maximum
11368   if( !MTX_MinColIndex( &copyCol, 0, &re, &im, col ) )
11369   {
11370     MTX_ERROR_MSG( "MTX_MinColIndex returned FALSE." );
11371     MTX_Free( &copyCol );
11372     return FALSE;
11373   }
11374 
11375   *value = re;
11376 
11377   MTX_Free( &copyCol );
11378   return TRUE;
11379 }
11380 
11381 BOOL MTX_MaxColumn( const MTX *M, const unsigned col, double *re, double *im )
11382 {
11383   unsigned row;
11384   return MTX_MaxColIndex( M, col, re, im, &row );
11385 }
11386 
11387 BOOL MTX_MaxRow( const MTX *M, const unsigned row, double *re, double *im )
11388 {
11389   unsigned col;
11390   return MTX_MaxRowIndex( M, row, re, im, &col );
11391 }
11392 
11393 BOOL MTX_MinColumn( const MTX *M, const unsigned col, double *re, double *im )
11394 {
11395   unsigned row;
11396   return MTX_MinColIndex( M, col, re, im, &row );
11397 }
11398 
11399 BOOL MTX_MinRow( const MTX *M, const unsigned row, double *re, double *im )
11400 {
11401   unsigned col;
11402   return MTX_MinRowIndex( M, row, re, im, &col );
11403 }
11404 
11405 BOOL MTX_MaxAbsColumn( const MTX *M, const unsigned col, double *value )
11406 {
11407   unsigned row;
11408   return MTX_MaxAbsColIndex( M, col, value, &row );
11409 }
11410 
11411 BOOL MTX_MaxAbsRow( const MTX *M, const unsigned row, double *value )
11412 {
11413   unsigned col;
11414   return MTX_MaxAbsRowIndex( M, row, value, &col );
11415 }
11416 
11417 BOOL MTX_MinAbsColumn( const MTX *M, const unsigned col, double *value )
11418 {
11419   unsigned row;
11420   return MTX_MinAbsColIndex( M, col, value, &row );
11421 }
11422 
11423 BOOL MTX_MinAbsRow( const MTX *M, const unsigned row, double *value )
11424 {
11425   unsigned col;
11426   return MTX_MinAbsRowIndex( M, row, value, &col );
11427 }
11428 
11429 BOOL MTX_MaxAbsIndex( const MTX *M, double* value, unsigned *row, unsigned *col )
11430 {
11431   unsigned j = 0;
11432   unsigned trow = 0;
11433   double tval = 0.0;
11434 
11435   if( MTX_isNull( M ) )
11436   {
11437     MTX_ERROR_MSG( "NULL Matrix" );
11438     return FALSE;
11439   }
11440 
11441   *col = 0;
11442   if( !MTX_MaxAbsColIndex( M, 0, value, row ) )
11443   {
11444     MTX_ERROR_MSG( "MTX_MaxAbsColIndex returned FALSE." );
11445     return FALSE;
11446   }
11447 
11448   for( j = 1; j < M->ncols; j++ )
11449   {
11450     if( !MTX_MaxAbsColIndex( M, j, &tval, &trow ) )
11451     {
11452       MTX_ERROR_MSG( "MTX_MaxAbsColIndex returned FALSE." );
11453       return FALSE;
11454     }
11455 
11456     if( tval > *value )
11457     {
11458       *value = tval;
11459       *row = trow;
11460       *col = j;
11461     }
11462   }
11463   return TRUE;
11464 }
11465 
11466 
11467 BOOL MTX_MaxIndex( const MTX *M, double *re, double *im, unsigned *row, unsigned *col )
11468 {
11469   unsigned j = 0;
11470   unsigned trow = 0;
11471   double tre = 0.0;
11472   double tim = 0.0;
11473   double tmp = 0.0;
11474 
11475   if( MTX_isNull( M ) )
11476   {
11477     MTX_ERROR_MSG( "NULL Matrix" );
11478     return FALSE;
11479   }
11480 
11481   *col = 0;
11482   if( !MTX_MaxColIndex( M, 0, re, im, row ) )
11483   {
11484     MTX_ERROR_MSG( "MTX_MaxColIndex returned FALSE." );
11485     return FALSE;
11486   }
11487 
11488   if( M->isReal )
11489     tmp = *re;
11490   else
11491     tmp = (*re)*(*re) + (*im)*(*im);
11492 
11493   for( j = 1; j < M->ncols; j++ )
11494   {
11495     if( !MTX_MaxColIndex( M, j, &tre, &tim, &trow ) )
11496     {
11497       MTX_ERROR_MSG( "MTX_MaxColIndex returned FALSE." );
11498       return FALSE;
11499     }
11500 
11501     if( M->isReal )
11502     {
11503       if( tre > tmp )
11504       {
11505         *re = tre;
11506         tmp = *re;
11507         *row = trow;
11508         *col = j;
11509       }
11510     }
11511     else
11512     {
11513       if( (tre*tre+tim*tim) > tmp )
11514       {
11515         *re = tre;
11516         *im = tim;
11517         tmp = (*re)*(*re) + (*im)*(*im);
11518         *row = trow;
11519         *col = j;
11520       }
11521     }
11522   }
11523   return TRUE;
11524 }
11525 
11526 
11527 BOOL MTX_MaxAbs( const MTX *M, double* value )
11528 {
11529   unsigned row;
11530   unsigned col;
11531   return MTX_MaxAbsIndex( M, value, &row, &col );
11532 }
11533 
11534 
11535 BOOL MTX_Max( const MTX *M, double *re, double *im )
11536 {
11537   unsigned j = 0;
11538   double tre = 0.0;
11539   double tim = 0.0;
11540   double tmp = 0.0;
11541 
11542   if( MTX_isNull( M ) )
11543   {
11544     MTX_ERROR_MSG( "NULL Matrix" );
11545     return FALSE;
11546   }
11547 
11548   if( !MTX_MaxColumn( M, 0, re, im ) )
11549   {
11550     MTX_ERROR_MSG( "MTX_MaxColumn returned FALSE." );
11551     return FALSE;
11552   }
11553   if( M->isReal )
11554     tmp = *re;
11555   else
11556     tmp = (*re)*(*re) + (*im)*(*im);
11557 
11558   for( j = 1; j < M->ncols; j++ )
11559   {
11560     if( !MTX_MaxColumn( M, j, &tre, &tim ) )
11561     {
11562       MTX_ERROR_MSG( "MTX_MaxColumn returned FALSE." );
11563       return FALSE;
11564     }
11565 
11566     if( M->isReal )
11567     {
11568       if( tre > tmp )
11569       {
11570         *re = tre;
11571         tmp = *re;
11572       }
11573     }
11574     else
11575     {
11576       if( (tre*tre+tim*tim) > tmp )
11577       {
11578         *re = tre;
11579         *im = tim;
11580         tmp = (*re)*(*re) + (*im)*(*im);
11581       }
11582     }
11583   }
11584   return TRUE;
11585 }
11586 
11587 
11588 BOOL MTX_MinAbsIndex( const MTX *M, double* value, unsigned *row, unsigned *col )
11589 {
11590   unsigned j = 0;
11591   unsigned trow = 0;
11592   double tval = 0.0;
11593 
11594   if( MTX_isNull( M ) )
11595   {
11596     MTX_ERROR_MSG( "NULL Matrix" );
11597     return FALSE;
11598   }
11599 
11600   *col = 0;
11601   if( !MTX_MinAbsColIndex( M, 0, value, row ) )
11602   {
11603     MTX_ERROR_MSG( "MTX_MinAbsColIndex returned FALSE." );
11604     return FALSE;
11605   }
11606 
11607   for( j = 1; j < M->ncols; j++ )
11608   {
11609     if( !MTX_MinAbsColIndex( M, j, &tval, &trow ) )
11610     {
11611       MTX_ERROR_MSG( "MTX_MinAbsColIndex returned FALSE." );
11612       return FALSE;
11613     }
11614 
11615     if( tval < *value )
11616     {
11617       *value = tval;
11618       *row = trow;
11619       *col = j;
11620     }
11621   }
11622   return TRUE;
11623 }
11624 
11625 BOOL MTX_MinAbs( const MTX *M, double* value )
11626 {
11627   unsigned row;
11628   unsigned col;
11629   return MTX_MinAbsIndex( M, value, &row, &col );
11630 }
11631 
11632 BOOL MTX_MinIndex( const MTX *M, double *re, double *im, unsigned *row, unsigned *col )
11633 {
11634   unsigned j = 0;
11635   unsigned trow = 0;
11636   double tre = 0.0;
11637   double tim = 0.0;
11638   double tmp = 0.0;
11639 
11640   if( MTX_isNull( M ) )
11641   {
11642     MTX_ERROR_MSG( "NULL Matrix" );
11643     return FALSE;
11644   }
11645 
11646   *col = 0;
11647   if( !MTX_MinColIndex( M, 0, re, im, row ) )
11648   {
11649     MTX_ERROR_MSG( "MTX_MinColIndex returned FALSE." );
11650     return FALSE;
11651   }
11652   if( M->isReal )
11653     tmp = *re;
11654   else
11655     tmp = (*re)*(*re) + (*im)*(*im);
11656 
11657   for( j = 1; j < M->ncols; j++ )
11658   {
11659     if( !MTX_MinColIndex( M, j, &tre, &tim, &trow ) )
11660     {
11661       MTX_ERROR_MSG( "MTX_MinColIndex returned FALSE." );
11662       return FALSE;
11663     }
11664 
11665     if( M->isReal )
11666     {
11667       if( tre < tmp )
11668       {
11669         *re = tre;
11670         tmp = *re;
11671         *row = trow;
11672         *col = j;
11673       }
11674     }
11675     else
11676     {
11677       if( (tre*tre+tim*tim) < tmp )
11678       {
11679         *re = tre;
11680         *im = tim;
11681         tmp = (*re)*(*re) + (*im)*(*im);
11682         *row = trow;
11683         *col = j;
11684       }
11685     }
11686   }
11687   return TRUE;
11688 }
11689 
11690 BOOL MTX_Min( const MTX *M, double *re, double *im )
11691 {
11692   unsigned j = 0;
11693   double tre = 0.0;
11694   double tim = 0.0;
11695   double tmp = 0.0;
11696 
11697   if( MTX_isNull( M ) )
11698   {
11699     MTX_ERROR_MSG( "NULL Matrix" );
11700     return FALSE;
11701   }
11702 
11703   if( !MTX_MinColumn( M, 0, re, im ) )
11704   {
11705     MTX_ERROR_MSG( "MTX_MinColumn returned FALSE." );
11706     return FALSE;
11707   }
11708 
11709   if( M->isReal )
11710     tmp = *re;
11711   else
11712     tmp = (*re)*(*re) + (*im)*(*im);
11713 
11714   for( j = 1; j < M->ncols; j++ )
11715   {
11716     if( !MTX_MinColumn( M, j, &tre, &tim ) )
11717     {
11718       MTX_ERROR_MSG( "MTX_MinColumn returned FALSE." );
11719       return FALSE;
11720     }
11721 
11722     if( M->isReal )
11723     {
11724       if( tre < tmp )
11725       {
11726         *re = tre;
11727         tmp = *re;
11728       }
11729     }
11730     else
11731     {
11732       if( (tre*tre+tim*tim) < tmp )
11733       {
11734         *re = tre;
11735         *im = tim;
11736         tmp = (*re)*(*re) + (*im)*(*im);
11737       }
11738     }
11739   }
11740   return TRUE;
11741 }
11742 
11743 BOOL MTX_ColumnRange( const MTX *M, const unsigned col, double *re, double *im )
11744 {
11745   double re_maxval = 0;
11746   double im_maxval = 0;
11747   double re_minval = 0;
11748   double im_minval = 0;  
11749 
11750   if( MTX_isNull( M ) )
11751   {
11752     MTX_ERROR_MSG( "NULL Matrix" );
11753     return FALSE;
11754   }
11755 
11756   if( !MTX_MinColumn( M, col, &re_minval, &im_minval ) )
11757   {
11758     MTX_ERROR_MSG( "MTX_MinColumn returned FALSE." );
11759     return FALSE;
11760   }
11761   if( !MTX_MaxColumn( M, col, &re_maxval, &im_maxval ) )
11762   {
11763     MTX_ERROR_MSG( "MTX_MaxColumn returned FALSE." );
11764     return FALSE;
11765   }
11766 
11767   *re = re_maxval - re_minval;
11768   *im = im_maxval - im_minval;
11769   return TRUE;
11770 }
11771 
11772 BOOL MTX_RowRange( const MTX *M, const unsigned row, double *re, double *im )
11773 {
11774   double re_maxval = 0;
11775   double im_maxval = 0;
11776   double re_minval = 0;
11777   double im_minval = 0;
11778 
11779   if( MTX_isNull( M ) )
11780   {
11781     MTX_ERROR_MSG( "NULL Matrix" );
11782     return FALSE;
11783   }
11784 
11785 
11786   if( !MTX_MinRow( M, row, &re_minval, &im_minval ) )
11787   {
11788     MTX_ERROR_MSG( "MTX_MinRow returned FALSE." );
11789     return FALSE;
11790   }
11791   if( !MTX_MaxRow( M, row, &re_maxval, &im_maxval ) )
11792   {
11793     MTX_ERROR_MSG( "MTX_MaxRow returned FALSE." );
11794     return FALSE;
11795   }
11796 
11797   *re = re_maxval - re_minval;
11798   *im = im_maxval - im_minval;
11799   return TRUE;
11800 }
11801 
11802 
11803 BOOL MTX_Range( const MTX *M, double *re, double *im )
11804 {
11805   double re_maxval = 0;
11806   double im_maxval = 0;
11807   double re_minval = 0;
11808   double im_minval = 0;
11809 
11810   if( MTX_isNull( M ) )
11811   {
11812     MTX_ERROR_MSG( "NULL Matrix" );
11813     return FALSE;
11814   }
11815 
11816   if( !MTX_Min( M, &re_minval, &im_minval ) )
11817   {
11818     MTX_ERROR_MSG( "MTX_Min returned FALSE." );
11819     return FALSE;
11820   }
11821   if( !MTX_Max( M, &re_maxval, &im_maxval ) )
11822   {
11823     MTX_ERROR_MSG( "MTX_Max returned FALSE." );
11824     return FALSE;
11825   }
11826 
11827   *re = re_maxval - re_minval;
11828   *im = im_maxval - im_minval;
11829   return TRUE;
11830 }
11831 
11832 
11833 BOOL MTX_ColumnSum( const MTX *M, const unsigned col, double *re, double *im )
11834 {
11835   unsigned i = 0;
11836 
11837   if( MTX_isNull( M ) )
11838   {
11839     MTX_ERROR_MSG( "NULL Matrix" );
11840     return FALSE;
11841   }
11842 
11843   if( col >= M->ncols )
11844   {
11845     MTX_ERROR_MSG( "if( col >= M->ncols )" );
11846     return FALSE;
11847   }
11848 
11849   *re = 0;
11850   *im = 0;
11851 
11852   if( M->isReal )
11853   {
11854     for( i = 0; i < M->nrows; i++ )
11855     {
11856       *re += M->data[col][i];
11857     }
11858   }
11859   else
11860   {
11861     for( i = 0; i < M->nrows; i++ )
11862     {
11863       *re += M->cplx[col][i].re;
11864       *im += M->cplx[col][i].im;
11865     }
11866   }
11867   return TRUE;
11868 }
11869 
11870 
11871 BOOL MTX_ColumnSumAbs( const MTX *M, const unsigned col, double *value )
11872 {
11873   unsigned i = 0;
11874   MTX copyCol;
11875 
11876   if( MTX_isNull( M ) )
11877   {
11878     MTX_ERROR_MSG( "NULL Matrix" );
11879     return FALSE;
11880   }
11881 
11882   if( col >= M->ncols )
11883   {
11884     MTX_ERROR_MSG( "if( col >= M->ncols )" );
11885     return FALSE;
11886   }
11887 
11888   MTX_Init(&copyCol);
11889 
11890   if( !MTX_CopyColumn( M, col, &copyCol ) )
11891   {
11892     MTX_ERROR_MSG( "MTX_CopyColumn returned FALSE." );
11893     MTX_Free( &copyCol );
11894     return FALSE;
11895   }
11896 
11897   *value = 0;
11898 
11899   if( M->isReal )
11900   {
11901     for( i = 0; i < M->nrows; i++ )
11902     {
11903       *value += fabs(M->data[col][i]);
11904     }
11905   }
11906   else
11907   {
11908     for( i = 0; i < M->nrows; i++ )
11909     {
11910       *value += sqrt( M->cplx[col][i].re*M->cplx[col][i].re + M->cplx[col][i].im*M->cplx[col][i].im );
11911     }
11912   }
11913   return TRUE;
11914 }
11915 
11916 
11917 
11918 BOOL MTX_RowSum( const MTX *M, const unsigned row, double *re, double *im )
11919 {
11920   unsigned j = 0;
11921 
11922   if( MTX_isNull( M ) )
11923   {
11924     MTX_ERROR_MSG( "NULL Matrix" );
11925     return FALSE;
11926   }
11927 
11928   if( row >= M->nrows )
11929   {
11930     MTX_ERROR_MSG( "if( row >= M->nrows )" );
11931     return FALSE;
11932   }
11933 
11934   *re = 0;
11935   *im = 0;
11936 
11937   if( M->isReal )
11938   {
11939     for( j = 0; j < M->ncols; j++ )
11940     {
11941       *re += M->data[j][row];
11942     }
11943   }
11944   else
11945   {
11946     for( j = 0; j < M->ncols; j++ )
11947     {
11948       *re += M->cplx[j][row].re;
11949       *im += M->cplx[j][row].im;
11950     }
11951   }
11952   return TRUE;
11953 }
11954 
11955 BOOL MTX_Sum( const MTX *M, double *re, double *im )
11956 {
11957   unsigned j = 0;
11958   double sumre = 0.0;
11959   double sumim = 0.0;
11960 
11961   if( MTX_isNull( M ) )
11962   {
11963     MTX_ERROR_MSG( "NULL Matrix" );
11964     return FALSE;
11965   }
11966 
11967   *re = 0;
11968   *im = 0;
11969 
11970   for( j = 0; j < M->ncols; j++ )
11971   {
11972     if( !MTX_ColumnSum( M, j, &sumre, &sumim ) )
11973     {
11974       MTX_ERROR_MSG( "MTX_ColumnSum returned FALSE." );
11975       return FALSE;
11976     }
11977 
11978     *re += sumre;
11979     *im += sumim;
11980   }
11981   return TRUE;
11982 }
11983 
11984 
11985 BOOL MTX_ColumnMean( const MTX *M, const unsigned col, double *re, double *im )
11986 {
11987   unsigned i = 0;
11988 
11989   if( MTX_isNull( M ) )
11990   {
11991     MTX_ERROR_MSG( "NULL Matrix" );
11992     return FALSE;
11993   }
11994 
11995   if( col >= M->ncols )
11996   {
11997     MTX_ERROR_MSG( "if( col >= M->ncols )" );
11998     return FALSE;
11999   }
12000 
12001   *re = 0;
12002   *im = 0;
12003 
12004   if( M->isReal )
12005   {
12006     for( i = 0; i < M->nrows; i++ )
12007     {
12008       *re += M->data[col][i];
12009     }
12010     *re /= (double)(M->nrows);
12011   }
12012   else
12013   {
12014     for( i = 0; i < M->nrows; i++ )
12015     {
12016       *re += M->cplx[col][i].re;
12017       *im += M->cplx[col][i].im;
12018     }
12019     *re /= (double)(M->nrows);
12020     *im /= (double)(M->nrows);
12021   }
12022   return TRUE;
12023 }
12024 
12025 BOOL MTX_RowMean( const MTX *M, const unsigned row, double *re, double *im )
12026 {
12027   unsigned j = 0;
12028 
12029   if( MTX_isNull( M ) )
12030   {
12031     MTX_ERROR_MSG( "NULL Matrix" );
12032     return FALSE;
12033   }
12034 
12035   if( row >= M->nrows )
12036   {
12037     MTX_ERROR_MSG( "if( row >= M->nrows )" );
12038     return FALSE;
12039   }
12040 
12041   *re = 0;
12042   *im = 0;
12043 
12044   if( M->isReal )
12045   {
12046     for( j = 0; j < M->ncols; j++ )
12047     {
12048       *re += M->data[j][row];
12049     }
12050     *re /= (double)(M->ncols);
12051   }
12052   else
12053   {
12054     for( j = 0; j < M->ncols; j++ )
12055     {
12056       *re += M->cplx[j][row].re;
12057       *im += M->cplx[j][row].im;
12058     }
12059     *re /= (double)(M->ncols);
12060     *im /= (double)(M->ncols);
12061   }
12062 
12063   return TRUE;
12064 }
12065 
12066 
12067 BOOL MTX_Mean( const MTX *M, double *re, double *im )
12068 {
12069   double sumre = 0.0;
12070   double sumim = 0.0;
12071   double n = (double)(M->nrows*M->ncols);
12072 
12073   if( MTX_isNull( M ) )
12074   {
12075     MTX_ERROR_MSG( "NULL Matrix" );
12076     return FALSE;
12077   }
12078 
12079   *re = 0;
12080   *im = 0;
12081 
12082   if( !MTX_Sum( M, &sumre, &sumim ) )
12083   {
12084     MTX_ERROR_MSG( "MTX_Sum returned FALSE." );
12085     return FALSE;
12086   }
12087 
12088   *re = sumre/n;
12089   *im = sumim/n;
12090 
12091   return TRUE;
12092 }
12093 
12094 BOOL MTX_ColumnStdev( const MTX *M, const unsigned col, double *value )
12095 {
12096   unsigned i = 0;
12097   double n = 0;
12098   double sumx2 = 0;
12099   double sumx_re = 0;
12100   double sumx_im = 0;
12101   double var = 0;
12102 
12103   if( MTX_isNull( M ) )
12104   {
12105     MTX_ERROR_MSG( "NULL Matrix" );
12106     return FALSE;
12107   }
12108 
12109   if( col >= M->ncols )
12110   {
12111     MTX_ERROR_MSG( "if( col >= M->ncols )" );
12112     return FALSE;
12113   }
12114 
12115   // special case
12116   if( M->nrows == 1 )
12117   {
12118     *value = 0.0;
12119     return TRUE;
12120   }
12121 
12122   if( M->isReal)
12123   {
12124     n = M->nrows;
12125     for( i = 0; i < M->nrows; i++ )
12126     {
12127       sumx_re += M->data[col][i];
12128       sumx2 += M->data[col][i]*M->data[col][i];
12129     }
12130     if( MTX_IsPostiveINF( sumx2 ) )
12131     {
12132       *value = MTX_POS_INF;
12133     }
12134     else
12135     {
12136       var = (n*sumx2 - sumx_re*sumx_re) / (n*(n-1.0));
12137       *value = sqrt(var);
12138     }
12139   }
12140   else
12141   {
12142     n = M->nrows;
12143     for( i = 0; i < M->nrows; i++ )
12144     {
12145       sumx_re += M->cplx[col][i].re;
12146       sumx_im += M->cplx[col][i].im;
12147       sumx2 += M->cplx[col][i].re*M->cplx[col][i].re + M->cplx[col][i].im*M->cplx[col][i].im;
12148     }
12149     if( MTX_IsPostiveINF( sumx2 ) )
12150     {
12151       *value = MTX_POS_INF;
12152     }
12153     else
12154     {
12155       sumx_re = sqrt( sumx_re*sumx_re + sumx_im*sumx_im );
12156       var = (n*sumx2 - sumx_re*sumx_re) / (n*(n-1.0));
12157       *value = sqrt(var);
12158     }
12159   }
12160   return TRUE;
12161 }
12162 
12163 BOOL MTX_RowStdev( const MTX *M, const unsigned row, double *value )
12164 {
12165   MTX copyCol; // A column copy = row vector of M, i.e. row tranposed
12166   MTX_Init( &copyCol );
12167   if( !MTX_CopyRowIntoAColumnMatrix( M, row, &copyCol ) )
12168   {
12169     MTX_ERROR_MSG( "MTX_CopyRowIntoAColumnMatrix returned FALSE." );
12170     MTX_Free( &copyCol );
12171     return FALSE;
12172   }
12173 
12174   if( !MTX_ColumnStdev( &copyCol, 0, value ) )
12175   {
12176     MTX_ERROR_MSG( "MTX_ColumnStdev returned FALSE." );
12177     MTX_Free( &copyCol );
12178     return FALSE;
12179   }
12180   MTX_Free( &copyCol );
12181   return TRUE;
12182 }
12183 
12184 BOOL MTX_Stdev( const MTX *M, double *value )
12185 {
12186   unsigned i = 0;
12187   unsigned j = 0;
12188   double n = M->nrows*M->ncols;
12189   double sumx2 = 0;
12190   double sumx_re = 0;
12191   double sumx_im = 0;
12192   double var = 0;
12193 
12194   *value = 0.0;
12195 
12196   if( MTX_isNull( M ) )
12197   {
12198     MTX_ERROR_MSG( "NULL Matrix" );
12199     return FALSE;
12200   }
12201 
12202   // special case
12203   if( M->nrows == 1 && M->ncols == 1 )
12204     return TRUE;
12205 
12206 
12207 
12208   if( M->isReal)
12209   {
12210     for( j = 0; j < M->ncols; j++ )
12211     {
12212       for( i = 0; i < M->nrows; i++ )
12213       {
12214         sumx_re += M->data[j][i];
12215         sumx2 += M->data[j][i]*M->data[j][i];
12216       }
12217     }
12218     var = (n*sumx2 - sumx_re*sumx_re) / (n*(n-1.0));
12219     *value = sqrt(var);
12220   }
12221   else
12222   {
12223     for( j = 0; j < M->ncols; j++ )
12224     {
12225       for( i = 0; i < M->nrows; i++ )
12226       {
12227         sumx_re += M->cplx[j][i].re;
12228         sumx_im += M->cplx[j][i].im;
12229         sumx2 += M->cplx[j][i].re*M->cplx[j][i].re + M->cplx[j][i].im*M->cplx[j][i].im;
12230       }
12231     }
12232     sumx_re = sqrt( sumx_re*sumx_re + sumx_im*sumx_im );
12233     var = (n*sumx2 - sumx_re*sumx_re) / (n*(n-1.0));
12234     *value = sqrt(var);
12235   }
12236 
12237 
12238   return TRUE;
12239 }
12240 
12241 BOOL MTX_ColumnVar( const MTX *M, const unsigned col, double *value )
12242 {
12243   if( !MTX_ColumnStdev( M, col, value ) )
12244   {
12245     MTX_ERROR_MSG( "MTX_ColumnStdev returned FALSE." );
12246     return FALSE;
12247   }
12248   // square the result
12249   *value *= *value;
12250   return TRUE;
12251 }
12252 
12253 BOOL MTX_RowVar( const MTX *M, const unsigned row, double *value )
12254 {
12255   if( !MTX_RowStdev( M, row, value ) )
12256   {
12257     MTX_ERROR_MSG( "MTX_RowStdev returned FALSE." );
12258     return FALSE;
12259   }
12260   // square the result
12261   *value *= *value;
12262   return TRUE;
12263 }
12264 
12265 BOOL MTX_Var( const MTX *M, double *value )
12266 {
12267   if( !MTX_Stdev( M, value ) )
12268   {
12269     MTX_ERROR_MSG( "MTX_Stdev returned FALSE." );
12270     return FALSE;
12271   }
12272   // square the result
12273   *value *= *value;
12274   return TRUE;
12275 }
12276 
12277 BOOL MTX_ColumnNorm( const MTX *M, const unsigned col, double *value )
12278 {
12279   unsigned i = 0;
12280 
12281   if( MTX_isNull( M ) )
12282   {
12283     MTX_ERROR_MSG( "NULL Matrix" );
12284     return FALSE;
12285   }
12286 
12287   if( col >= M->ncols )
12288   {
12289     MTX_ERROR_MSG( "if( col >= M->ncols )" );
12290     return FALSE;
12291   }
12292 
12293   *value = 0;
12294   if( M->isReal )
12295   {
12296     for( i = 0; i < M->nrows; i++ )
12297     {
12298       *value += M->data[col][i] * M->data[col][i];
12299     }
12300     *value = sqrt(*value);
12301   }
12302   else
12303   {
12304     for( i = 0; i < M->nrows; i++ )
12305     {
12306       *value += M->cplx[col][i].re * M->cplx[col][i].re + M->cplx[col][i].im * M->cplx[col][i].im;
12307     }
12308     *value = sqrt(*value);
12309   }
12310   return TRUE;
12311 }
12312 
12313 BOOL MTX_RowNorm( const MTX *M, const unsigned row, double *value )
12314 {
12315   MTX copyCol; // A column copy = row vector of M, i.e. row tranposed
12316   MTX_Init( &copyCol );
12317   if( !MTX_CopyRowIntoAColumnMatrix( M, row, &copyCol ) )
12318   {
12319     MTX_ERROR_MSG( "MTX_CopyRowIntoAColumnMatrix returned FALSE." );
12320     MTX_Free( &copyCol );
12321     return FALSE;
12322   }
12323 
12324   if( !MTX_ColumnNorm( &copyCol, 0, value ) )
12325   {
12326     MTX_ERROR_MSG( "MTX_ColumnNorm returned FALSE." );
12327     MTX_Free( &copyCol );
12328     return FALSE;
12329   }
12330   MTX_Free( &copyCol );
12331   return TRUE;
12332 }
12333 
12334 
12335 BOOL MTX_Norm( const MTX *M, double *value )
12336 {
12337   unsigned i = 0;
12338   unsigned j = 0;
12339 
12340   *value = 0;
12341 
12342   if( MTX_isNull( M ) )
12343   {
12344     MTX_ERROR_MSG( "NULL Matrix" );
12345     return FALSE;
12346   }
12347 
12348 
12349   *value = 0;
12350   if( M->isReal )
12351   {
12352     for( j = 0; j < M->ncols; j++ )
12353     {
12354       for( i = 0; i < M->nrows; i++ )
12355       {
12356         *value += M->data[j][i] * M->data[j][i];
12357       }
12358     }
12359     *value = sqrt(*value);
12360   }
12361   else
12362   {
12363     for( j = 0; j < M->ncols; j++ )
12364     {
12365       for( i = 0; i < M->nrows; i++ )
12366       {
12367         *value += M->cplx[j][i].re * M->cplx[j][i].re + M->cplx[j][i].im * M->cplx[j][i].im;
12368       }
12369     }
12370     *value = sqrt(*value);
12371   }
12372 
12373 
12374   return TRUE;
12375 }
12376 
12377 BOOL MTX_ColumnRMS( const MTX *M, const unsigned col, double *value )
12378 {
12379   if( !MTX_ColumnNorm( M, col, value ) )
12380   {
12381     MTX_ERROR_MSG( "MTX_ColumnNorm returned FALSE." );
12382     return FALSE;
12383   }
12384 
12385   // redundant but better to be sure
12386   if( M->nrows == 0 )
12387   {
12388     MTX_ERROR_MSG( "if( M->nrows == 0 )" );
12389     return FALSE;
12390   }
12391 
12392   *value /= sqrt( (double)(M->nrows) );
12393   return TRUE;
12394 }
12395 
12396 BOOL MTX_RowRMS( const MTX *M, const unsigned row, double *value )
12397 {
12398   if( !MTX_RowNorm( M, row, value ) )
12399   {
12400     MTX_ERROR_MSG( "MTX_RowNorm returned FALSE." );
12401     return FALSE;
12402   }
12403 
12404   // redundant but better to be sure
12405   if( M->nrows == 0 )
12406   {
12407     MTX_ERROR_MSG( "if( M->nrows == 0 )" );
12408     return FALSE;
12409   }
12410 
12411   *value /= sqrt( M->ncols );
12412   return TRUE;
12413 }
12414 
12415 BOOL MTX_RMS( const MTX *M, double *value )
12416 {
12417   const int n = M->nrows*M->ncols;
12418   const double nd = n;
12419 
12420   if( !MTX_Norm( M, value ) )
12421   {
12422     MTX_ERROR_MSG( "MTX_Norm returned FALSE." );
12423     return FALSE;
12424   }
12425 
12426   // redundant but better to be sure
12427   if( n == 0 )
12428   {
12429     MTX_ERROR_MSG( "if( n == 0 )" );
12430     return FALSE;
12431   }
12432 
12433   *value /= sqrt( nd );
12434   return TRUE;
12435 }
12436 
12437 BOOL MTX_ColumnSkewness( const MTX *M, const unsigned col, double *re, double* im )
12438 {
12439   unsigned i = 0;
12440 
12441   double dtmp = 0.0;
12442 
12443   double sum = 0.0,
12444     meanval_re = 0.0,
12445     meanval_im = 0.0,
12446     stdev = 0.0;
12447 
12448   const double n = (double)M->nrows;
12449 
12450   if( MTX_isNull( M ) )
12451   {
12452     MTX_ERROR_MSG( "NULL Matrix" );
12453     return FALSE;
12454   }
12455 
12456   if( col >= M->ncols )
12457   {
12458     MTX_ERROR_MSG( "if( col >= M->ncols )" );
12459     return FALSE;
12460   }
12461 
12462   if( M->nrows < 3 )
12463   {
12464     MTX_ERROR_MSG( "if( M->nrows < 3 )" );
12465     return FALSE;
12466   }
12467 
12468   if( !MTX_ColumnMean( M, col, &meanval_re, &meanval_im ) )
12469   {
12470     MTX_ERROR_MSG( "MTX_ColumnMean returned FALSE." );
12471     return FALSE;
12472   }
12473 
12474   *re = 0;
12475   *im = 0;
12476 
12477   if( M->isReal )
12478   {
12479     if( !MTX_ColumnStdev( M, col, &stdev ) )
12480     {
12481       MTX_ERROR_MSG( "MTX_ColumnStdev returned FALSE." );
12482       return FALSE;
12483     }
12484 
12485     for( i = 0; i < M->nrows; i++ )
12486     {
12487       dtmp = M->data[col][i] - meanval_re;
12488       sum += dtmp*dtmp*dtmp;
12489     }
12490     *re = n*sum / ((n-1.0)*(n-2.0)*stdev*stdev*stdev);
12491   }
12492   else
12493   {
12494     // REFERENCE: http://en.wikipedia.org/wiki/Skewness, sample skewness
12495     double a;
12496     double b;
12497     double a2;
12498     double b2;
12499     stComplex cplxSum2;
12500     stComplex cplxSum3;
12501     cplxSum2.re = 0;
12502     cplxSum2.im = 0;
12503     cplxSum3.re = 0;
12504     cplxSum3.im = 0;
12505 
12506     // (a+bi)^2 = (a^2-b^2) + 2abi
12507     // (a+bi)^3 = (a^3-3ab^2) + (3a^2b - b^3)i
12508     for( i = 0; i < M->nrows; i++ )
12509     {
12510       a = M->cplx[col][i].re - meanval_re;
12511       b = M->cplx[col][i].im - meanval_im;
12512       a2 = a*a;
12513       b2 = b*b;
12514 
12515       cplxSum2.re += a2-b2;
12516       cplxSum2.im += 2*a*b;
12517 
12518       cplxSum3.re += a2*a - 3.0*a*b2;
12519       cplxSum3.im += 3.0*a2*b - b2*b;
12520     }
12521 
12522     // compute (cplxSum2)^(3/2)
12523     a = cplxSum2.re;
12524     b = cplxSum2.im;
12525     a2 = a*a;
12526     b2 = b*b;
12527     cplxSum2.re = a2*a - 3.0*a*b2;
12528     cplxSum2.im = 3.0*a2*b - b2*b;
12529     a = cplxSum2.re;
12530     b = cplxSum2.im;
12531 
12532     dtmp = sqrt( a*a + b*b ); // magnitude
12533     cplxSum2.re = sqrt( (dtmp + a)/2.0 );
12534     if( b < 0 )
12535       cplxSum2.im = -1.0*sqrt( (dtmp - a)/2.0 );
12536     else
12537       cplxSum2.im = sqrt( (dtmp - a)/2.0 );
12538 
12539 
12540     // compute cplxSum3/cplxSum2
12541 
12542     dtmp = cplxSum2.re*cplxSum2.re + cplxSum2.im*cplxSum2.im;
12543 
12544     if( dtmp == 0.0 )
12545     {
12546       MTX_ERROR_MSG( "Divide by zero not allowed." );
12547       return FALSE;
12548     }
12549 
12550     a = (cplxSum3.re * cplxSum2.re + cplxSum3.im * cplxSum2.im )/dtmp;
12551     b = (cplxSum3.im * cplxSum2.re - cplxSum3.re * cplxSum2.im )/dtmp;
12552 
12553     cplxSum3.re = a;
12554     cplxSum3.im = b;
12555 
12556     dtmp = sqrt(n); // n*sqrt(n-1.0)/(n-2.0); use the commented term to remove bias
12557 
12558     *re = dtmp*cplxSum3.re;
12559     *im = dtmp*cplxSum3.im;
12560   }
12561   return TRUE;
12562 }
12563 
12564 BOOL MTX_RowSkewness( const MTX *M, const unsigned row, double *re, double *im )
12565 {
12566   unsigned i = 0;
12567 
12568   double dtmp = 0.0;
12569 
12570   double sum = 0.0,
12571     meanval_re = 0.0,
12572     meanval_im = 0.0,
12573     stdev = 0.0;
12574 
12575   const double n = (double)M->ncols;
12576 
12577   if( MTX_isNull( M ) )
12578   {
12579     MTX_ERROR_MSG( "NULL Matrix" );
12580     return FALSE;
12581   }
12582   if( row >= M->nrows )
12583   {
12584     MTX_ERROR_MSG( "if( row >= M->nrows )" );
12585     return FALSE;
12586   }
12587 
12588   if( M->ncols < 3 )
12589   {
12590     MTX_ERROR_MSG( "if( M->ncols < 3 )" );
12591     return FALSE;
12592   }
12593 
12594   if( !MTX_RowMean( M, row, &meanval_re, &meanval_im ) )
12595   {
12596     MTX_ERROR_MSG( "MTX_RowMean returned FALSE." );
12597     return FALSE;
12598   }
12599 
12600   if( !MTX_RowStdev( M, row, &stdev ) )
12601   {
12602     MTX_ERROR_MSG( "MTX_RowStdev returned FALSE." );
12603     return FALSE;
12604   }
12605 
12606   *re = 0;
12607   *im = 0;
12608 
12609   if( M->isReal )
12610   {
12611     for( i = 0; i < M->ncols; i++ )
12612     {
12613       dtmp = M->data[i][row] - meanval_re;
12614       sum += dtmp*dtmp*dtmp;
12615     }
12616     *re = n*sum / ((n-1.0)*(n-2.0)*stdev*stdev*stdev);
12617   }
12618   else
12619   {
12620     // REFERENCE: http://en.wikipedia.org/wiki/Skewness, sample skewness
12621     double a;
12622     double b;
12623     double a2;
12624     double b2;
12625     stComplex cplxSum2;
12626     stComplex cplxSum3;
12627     cplxSum2.re = 0;
12628     cplxSum2.im = 0;
12629     cplxSum3.re = 0;
12630     cplxSum3.im = 0;
12631 
12632     // (a+bi)^2 = (a^2-b^2) + 2abi
12633     // (a+bi)^3 = (a^3-3ab^2) + (3a^2b - b^3)i
12634     for( i = 0; i < M->ncols; i++ )
12635     {
12636       a = M->cplx[i][row].re - meanval_re;
12637       b = M->cplx[i][row].im - meanval_im;
12638       a2 = a*a;
12639       b2 = b*b;
12640 
12641       cplxSum2.re += a2-b2;
12642       cplxSum2.im += 2*a*b;
12643 
12644       cplxSum3.re += a2*a - 3.0*a*b2;
12645       cplxSum3.im += 3.0*a2*b - b2*b;
12646     }
12647 
12648     // compute (cplxSum2)^(3/2)
12649     a = cplxSum2.re;
12650     b = cplxSum2.im;
12651     a2 = a*a;
12652     b2 = b*b;
12653     cplxSum2.re = a2*a - 3.0*a*b2;
12654     cplxSum2.im = 3.0*a2*b - b2*b;
12655     a = cplxSum2.re;
12656     b = cplxSum2.im;
12657 
12658     dtmp = sqrt( a*a + b*b ); // magnitude
12659     cplxSum2.re = sqrt( (dtmp + a)/2.0 );
12660     if( b < 0 )
12661       cplxSum2.im = -1.0*sqrt( (dtmp - a)/2.0 );
12662     else
12663       cplxSum2.im = sqrt( (dtmp - a)/2.0 );
12664 
12665 
12666     // compute cplxSum3/cplxSum2
12667 
12668     dtmp = cplxSum2.re*cplxSum2.re + cplxSum2.im*cplxSum2.im;
12669 
12670     if( dtmp == 0.0 )
12671     {
12672       MTX_ERROR_MSG( "Divide by zero not allowed." );
12673       return FALSE;
12674     }
12675 
12676     a = (cplxSum3.re * cplxSum2.re + cplxSum3.im * cplxSum2.im )/dtmp;
12677     b = (cplxSum3.im * cplxSum2.re - cplxSum3.re * cplxSum2.im )/dtmp;
12678 
12679     cplxSum3.re = a;
12680     cplxSum3.im = b;
12681 
12682     dtmp = sqrt(n); // n*sqrt(n-1.0)/(n-2.0);
12683 
12684     *re = dtmp*cplxSum3.re;
12685     *im = dtmp*cplxSum3.im;
12686   }
12687   return TRUE;
12688 }
12689 
12690 
12691 BOOL MTX_Skewness( const MTX *M, double *re, double* im )
12692 {
12693   unsigned j = 0;
12694   unsigned i = 0;
12695   double dtmp = 0.0;
12696   double sum = 0.0;
12697   double meanval_re = 0.0;
12698   double meanval_im = 0.0;
12699   double stdev = 0.0;
12700 
12701   const double n = (double)(M->nrows*M->ncols);
12702 
12703   if( MTX_isNull( M ) )
12704   {
12705     MTX_ERROR_MSG( "NULL Matrix" );
12706     return FALSE;
12707   }
12708 
12709   if( n < 3 )
12710   {
12711     MTX_ERROR_MSG( "if( n < 3 )" );
12712     return FALSE;
12713   }
12714 
12715 
12716 
12717   if( !MTX_Mean( M, &meanval_re, &meanval_im ) )
12718   {
12719     MTX_ERROR_MSG( "MTX_Mean returned FALSE." );
12720     return FALSE;
12721   }
12722 
12723   *re = 0;
12724   *im = 0;
12725 
12726   if( M->isReal )
12727   {
12728     if( !MTX_Stdev( M, &stdev ) )
12729     {
12730       MTX_ERROR_MSG( "MTX_Stdev returned FALSE." );
12731       return FALSE;
12732     }
12733 
12734     for( j = 0; j < M->ncols; j++ )
12735     {
12736       for( i = 0; i < M->nrows; i++ )
12737       {
12738         dtmp = M->data[j][i] - meanval_re;
12739         sum += dtmp*dtmp*dtmp;
12740       }
12741     }
12742     *re = n*sum / ((n-1.0)*(n-2.0)*stdev*stdev*stdev);
12743   }
12744   else
12745   {
12746     // REFERENCE: http://en.wikipedia.org/wiki/Skewness, sample skewness
12747     double a;
12748     double b;
12749     double a2;
12750     double b2;
12751     stComplex cplxSum2;
12752     stComplex cplxSum3;
12753     cplxSum2.re = 0;
12754     cplxSum2.im = 0;
12755     cplxSum3.re = 0;
12756     cplxSum3.im = 0;
12757 
12758     // (a+bi)^2 = (a^2-b^2) + 2abi
12759     // (a+bi)^3 = (a^3-3ab^2) + (3a^2b - b^3)i
12760     for( j = 0; j < M->ncols; j++ )
12761     {
12762       for( i = 0; i < M->nrows; i++ )
12763       {
12764         a = M->cplx[j][i].re - meanval_re;
12765         b = M->cplx[j][i].im - meanval_im;
12766         a2 = a*a;
12767         b2 = b*b;
12768 
12769         cplxSum2.re += a2-b2;
12770         cplxSum2.im += 2*a*b;
12771 
12772         cplxSum3.re += a2*a - 3.0*a*b2;
12773         cplxSum3.im += 3.0*a2*b - b2*b;
12774       }
12775     }
12776 
12777     // compute (cplxSum2)^(3/2)
12778     a = cplxSum2.re;
12779     b = cplxSum2.im;
12780     a2 = a*a;
12781     b2 = b*b;
12782     cplxSum2.re = a2*a - 3.0*a*b2;
12783     cplxSum2.im = 3.0*a2*b - b2*b;
12784     a = cplxSum2.re;
12785     b = cplxSum2.im;
12786 
12787     dtmp = sqrt( a*a + b*b ); // magnitude
12788     cplxSum2.re = sqrt( (dtmp + a)/2.0 );
12789     if( b < 0 )
12790       cplxSum2.im = -1.0*sqrt( (dtmp - a)/2.0 );
12791     else
12792       cplxSum2.im = sqrt( (dtmp - a)/2.0 );
12793 
12794 
12795     // compute cplxSum3/cplxSum2
12796 
12797     dtmp = cplxSum2.re*cplxSum2.re + cplxSum2.im*cplxSum2.im;
12798 
12799     if( dtmp == 0.0 )
12800     {
12801       MTX_ERROR_MSG( "Divide by zero not allowed." );
12802       return FALSE;
12803     }
12804 
12805     a = (cplxSum3.re * cplxSum2.re + cplxSum3.im * cplxSum2.im )/dtmp;
12806     b = (cplxSum3.im * cplxSum2.re - cplxSum3.re * cplxSum2.im )/dtmp;
12807 
12808     cplxSum3.re = a;
12809     cplxSum3.im = b;
12810 
12811     dtmp = sqrt(n); // n*sqrt(n-1.0)/(n-2.0); use the commented term to remove bias
12812 
12813     *re = dtmp*cplxSum3.re;
12814     *im = dtmp*cplxSum3.im;
12815   }
12816 
12817 
12818   return TRUE;
12819 }
12820 
12821 BOOL MTX_ColumnKurtosis( const MTX *M, const unsigned col, double *re, double *im )
12822 {
12823   unsigned i = 0;
12824 
12825   double dtmp = 0.0;
12826 
12827   double sum = 0.0,
12828     meanval_re = 0.0,
12829     meanval_im = 0.0,
12830     stdev = 0.0;
12831 
12832   const double n = (double)M->nrows;
12833 
12834   if( MTX_isNull( M ) )
12835   {
12836     MTX_ERROR_MSG( "NULL Matrix" );
12837     return FALSE;
12838   }
12839 
12840   if( col >= M->ncols )
12841   {
12842     MTX_ERROR_MSG( "if( col >= M->ncols )" );
12843     return FALSE;
12844   }
12845 
12846   if( M->nrows < 4 )
12847   {
12848     MTX_ERROR_MSG( "if( M->nrows < 4 )" );
12849     return FALSE;
12850   }
12851 
12852   if( !MTX_ColumnMean( M, col, &meanval_re, &meanval_im ) )
12853   {
12854     MTX_ERROR_MSG( "MTX_ColumnMean returned FALSE." );
12855     return FALSE;
12856   }
12857 
12858   if( M->isReal )
12859   {
12860     if( !MTX_ColumnStdev( M, col, &stdev ) )
12861     {
12862       MTX_ERROR_MSG( "MTX_ColumnStdev returned FALSE." );
12863       return FALSE;
12864     }
12865 
12866     for( i = 0; i < M->nrows; i++ )
12867     {
12868       dtmp = M->data[col][i] - meanval_re;
12869       sum += dtmp*dtmp*dtmp*dtmp;
12870     }
12871     dtmp = 1.0 / (stdev*stdev*stdev*stdev);
12872     dtmp *= n*(n+1) / ((n-1.0)*(n-2.0)*(n-3.0));
12873     dtmp *= sum;
12874     dtmp -= 3.0*(n-1.0)*(n-1.0) / ((n-2.0)*(n-3.0));
12875     *re = dtmp;
12876   }
12877   else
12878   {
12879     double a;
12880     double b;
12881     double a2;
12882     double b2;
12883     stComplex cplxSum2;
12884     stComplex cplxSum4;
12885     cplxSum2.re = 0;
12886     cplxSum2.im = 0;
12887     cplxSum4.re = 0;
12888     cplxSum4.im = 0;
12889 
12890     // g_2 = \frac{m_4}{m_{2}^2} -3 = \frac{n\,\sum_{i=1}^n (x_i - \overline{x})^4}{\left(\sum_{i=1}^n (x_i - \overline{x})^2\right)^2}
12891     // (a+bi)^2 = (a^2-b^2) + 2abi
12892     // (a+bi)^4 = (a^4 - 6*a^2*b^2 + b^4) + (4*a^3*b - 4*a*b^3)i
12893     for( i = 0; i < M->nrows; i++ )
12894     {
12895       a = M->cplx[col][i].re - meanval_re;
12896       b = M->cplx[col][i].im - meanval_im;
12897       a2 = a*a;
12898       b2 = b*b;
12899 
12900       cplxSum2.re += a2-b2;
12901       cplxSum2.im += 2.0*a*b;
12902 
12903       cplxSum4.re += a2*a2 - 6.0*a2*b2 + b2*b2;
12904       cplxSum4.im += 4.0*a2*a*b - 4.0*a*b2*b;
12905     }
12906 
12907     // compute (cplxSum2)^(2)
12908     a = cplxSum2.re * cplxSum2.re - cplxSum2.im * cplxSum2.im;
12909     b = 2.0*cplxSum2.re * cplxSum2.im;
12910     cplxSum2.re = a;
12911     cplxSum2.im = b;
12912 
12913     // compute cplxSum4 = cplxSum4/cplxSum2
12914 
12915     dtmp = cplxSum2.re*cplxSum2.re + cplxSum2.im*cplxSum2.im;
12916 
12917     if( dtmp == 0.0 )
12918     {
12919       MTX_ERROR_MSG( "Divide by zero not allowed." );
12920       return FALSE;
12921     }
12922 
12923     a = (cplxSum4.re * cplxSum2.re + cplxSum4.im * cplxSum2.im )/dtmp;
12924     b = (cplxSum4.im * cplxSum2.re - cplxSum4.re * cplxSum2.im )/dtmp;
12925 
12926     cplxSum4.re = a;
12927     cplxSum4.im = b;
12928 
12929     *re = n*cplxSum4.re;
12930     *im = n*cplxSum4.im;
12931   }
12932 
12933   return TRUE;
12934 }
12935 
12936 BOOL MTX_RowKurtosis( const MTX *M, const unsigned row, double *re, double *im )
12937 {
12938   unsigned j = 0;
12939 
12940   double dtmp = 0.0;
12941 
12942   double sum = 0.0,
12943     meanval_re = 0.0,
12944     meanval_im = 0.0,
12945     stdev = 0.0;
12946 
12947   const double n = (double)M->ncols;
12948 
12949   if( MTX_isNull( M ) )
12950   {
12951     MTX_ERROR_MSG( "NULL Matrix" );
12952     return FALSE;
12953   }
12954 
12955   if( row >= M->nrows )
12956   {
12957     MTX_ERROR_MSG( "if( row >= M->nrows )" );
12958     return FALSE;
12959   }
12960 
12961   if( M->ncols < 4 )
12962   {
12963     MTX_ERROR_MSG( "if( M->ncols < 4 )" );
12964     return FALSE;
12965   }
12966 
12967   if( !MTX_RowMean( M, row, &meanval_re, &meanval_im ) )
12968   {
12969     MTX_ERROR_MSG( "MTX_RowMean returned FALSE." );
12970     return FALSE;
12971   }
12972 
12973   if( M->isReal )
12974   {
12975     if( !MTX_RowStdev( M, row, &stdev ) )
12976     {
12977       MTX_ERROR_MSG( "MTX_RowStdev returned FALSE." );
12978       return FALSE;
12979     }
12980 
12981     for( j = 0; j < M->ncols; j++ )
12982     {
12983       dtmp = M->data[j][row] - meanval_re;
12984       sum += dtmp*dtmp*dtmp*dtmp;
12985     }
12986     dtmp = 1.0 / (stdev*stdev*stdev*stdev);
12987     dtmp *= n*(n+1) / ((n-1.0)*(n-2.0)*(n-3.0));
12988     dtmp *= sum;
12989     dtmp -= 3.0*(n-1.0)*(n-1.0) / ((n-2.0)*(n-3.0));
12990     *re = dtmp;
12991   }
12992   else
12993   {
12994     double a;
12995     double b;
12996     double a2;
12997     double b2;
12998     stComplex cplxSum2;
12999     stComplex cplxSum4;
13000     cplxSum2.re = 0;
13001     cplxSum2.im = 0;
13002     cplxSum4.re = 0;
13003     cplxSum4.im = 0;
13004 
13005     // g_2 = \frac{m_4}{m_{2}^2} -3 = \frac{n\,\sum_{i=1}^n (x_i - \overline{x})^4}{\left(\sum_{i=1}^n (x_i - \overline{x})^2\right)^2}
13006     // (a+bi)^2 = (a^2-b^2) + 2abi
13007     // (a+bi)^4 = (a^4 - 6*a^2*b^2 + b^4) + (4*a^3*b - 4*a*b^3)i
13008     for( j = 0; j < M->ncols; j++ )
13009     {
13010       a = M->cplx[j][row].re - meanval_re;
13011       b = M->cplx[j][row].im - meanval_im;
13012       a2 = a*a;
13013       b2 = b*b;
13014 
13015       cplxSum2.re += a2-b2;
13016       cplxSum2.im += 2.0*a*b;
13017 
13018       cplxSum4.re += a2*a2 - 6.0*a2*b2 + b2*b2;
13019       cplxSum4.im += 4.0*a2*a*b - 4.0*a*b2*b;
13020     }
13021 
13022     // compute (cplxSum2)^(2)
13023     a = cplxSum2.re * cplxSum2.re - cplxSum2.im * cplxSum2.im;
13024     b = 2.0*cplxSum2.re * cplxSum2.im;
13025     cplxSum2.re = a;
13026     cplxSum2.im = b;
13027 
13028     // compute cplxSum4 = cplxSum4/cplxSum2
13029 
13030     dtmp = cplxSum2.re*cplxSum2.re + cplxSum2.im*cplxSum2.im;
13031 
13032     if( dtmp == 0.0 )
13033     {
13034       MTX_ERROR_MSG( "if( dtmp == 0.0 )" );
13035       return FALSE;
13036     }
13037 
13038     a = (cplxSum4.re * cplxSum2.re + cplxSum4.im * cplxSum2.im )/dtmp;
13039     b = (cplxSum4.im * cplxSum2.re - cplxSum4.re * cplxSum2.im )/dtmp;
13040 
13041     cplxSum4.re = a;
13042     cplxSum4.im = b;
13043 
13044     *re = n*cplxSum4.re;
13045     *im = n*cplxSum4.im;
13046   }
13047 
13048   return TRUE;
13049 }
13050 
13051 BOOL MTX_Kurtosis( const MTX *M, double *re, double *im )
13052 {
13053   unsigned j = 0;
13054   unsigned i = 0;
13055   double dtmp = 0.0;
13056   double sum = 0.0;
13057   double meanval_re = 0.0;
13058   double meanval_im = 0.0;
13059   double stdev = 0.0;
13060 
13061   const double n = (double)(M->nrows*M->ncols);
13062 
13063   if( MTX_isNull( M ) )
13064   {
13065     MTX_ERROR_MSG( "NULL Matrix" );
13066     return FALSE;
13067   }
13068 
13069   if( n < 4 )
13070   {
13071     MTX_ERROR_MSG( "if( n < 4 )" );
13072     return FALSE;
13073   }
13074 
13075 
13076   if( !MTX_Mean( M, &meanval_re, &meanval_im ) )
13077   {
13078     MTX_ERROR_MSG( "MTX_Mean returned FALSE." );
13079     return FALSE;
13080   }
13081 
13082   if( M->isReal )
13083   {
13084     if( !MTX_Stdev( M, &stdev ) )
13085     {
13086       MTX_ERROR_MSG( "MTX_Stdev returned FALSE." );
13087       return FALSE;
13088     }
13089 
13090     for( j = 0; j < M->ncols; j++ )
13091     {
13092       for( i = 0; i < M->nrows; i++ )
13093       {
13094         dtmp = M->data[j][i] - meanval_re;
13095         sum += dtmp*dtmp*dtmp*dtmp;
13096       }
13097     }
13098     dtmp = 1.0 / (stdev*stdev*stdev*stdev);
13099     dtmp *= n*(n+1) / ((n-1.0)*(n-2.0)*(n-3.0));
13100     dtmp *= sum;
13101     dtmp -= 3.0*(n-1.0)*(n-1.0) / ((n-2.0)*(n-3.0));
13102     *re = dtmp;
13103   }
13104   else
13105   {
13106     double a;
13107     double b;
13108     double a2;
13109     double b2;
13110     stComplex cplxSum2;
13111     stComplex cplxSum4;
13112     cplxSum2.re = 0;
13113     cplxSum2.im = 0;
13114     cplxSum4.re = 0;
13115     cplxSum4.im = 0;
13116 
13117     // g_2 = \frac{m_4}{m_{2}^2} -3 = \frac{n\,\sum_{i=1}^n (x_i - \overline{x})^4}{\left(\sum_{i=1}^n (x_i - \overline{x})^2\right)^2}
13118     // (a+bi)^2 = (a^2-b^2) + 2abi
13119     // (a+bi)^4 = (a^4 - 6*a^2*b^2 + b^4) + (4*a^3*b - 4*a*b^3)i
13120     for( j = 0; j < M->ncols; j++ )
13121     {
13122       for( i = 0; i < M->nrows; i++ )
13123       {
13124         a = M->cplx[j][i].re - meanval_re;
13125         b = M->cplx[j][i].im - meanval_im;
13126         a2 = a*a;
13127         b2 = b*b;
13128 
13129         cplxSum2.re += a2-b2;
13130         cplxSum2.im += 2.0*a*b;
13131 
13132         cplxSum4.re += a2*a2 - 6.0*a2*b2 + b2*b2;
13133         cplxSum4.im += 4.0*a2*a*b - 4.0*a*b2*b;
13134       }
13135     }
13136 
13137     // compute (cplxSum2)^(2)
13138     a = cplxSum2.re * cplxSum2.re - cplxSum2.im * cplxSum2.im;
13139     b = 2.0*cplxSum2.re * cplxSum2.im;
13140     cplxSum2.re = a;
13141     cplxSum2.im = b;
13142 
13143     // compute cplxSum4 = cplxSum4/cplxSum2
13144 
13145     dtmp = cplxSum2.re*cplxSum2.re + cplxSum2.im*cplxSum2.im;
13146 
13147     if( dtmp == 0.0 )
13148     {
13149       MTX_ERROR_MSG( "Divide by zero not allowed." );
13150       return FALSE;
13151     }
13152 
13153     a = (cplxSum4.re * cplxSum2.re + cplxSum4.im * cplxSum2.im )/dtmp;
13154     b = (cplxSum4.im * cplxSum2.re - cplxSum4.re * cplxSum2.im )/dtmp;
13155 
13156     cplxSum4.re = a;
13157     cplxSum4.im = b;
13158 
13159     *re = n*cplxSum4.re;
13160     *im = n*cplxSum4.im;
13161   }
13162 
13163 
13164   return TRUE;
13165 }
13166 
13167 BOOL MTX_Trace( const MTX *M, double *re, double *im )
13168 {
13169   unsigned i = 0;
13170 
13171   if( !MTX_isSquare(M) )
13172   {
13173     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
13174     return FALSE;
13175   }
13176 
13177   *re = 0.0;
13178   *im = 0.0;
13179 
13180   if( M->isReal )
13181   {
13182     for( i = 0; i < M->nrows; i++ )
13183       *re += M->data[i][i];
13184   }
13185   else
13186   {
13187     for( i = 0; i < M->nrows; i++ )
13188     {
13189       *re += M->cplx[i][i].re;
13190       *im += M->cplx[i][i].im;
13191     }
13192   }
13193 
13194   return TRUE;
13195 }
13196 
13197 BOOL MTX_Diagonal( const MTX *M, MTX *D )
13198 {
13199   unsigned i = 0;
13200 
13201   if( MTX_isNull( M ) )
13202   {
13203     MTX_ERROR_MSG( "NULL Matrix" );
13204     return FALSE;
13205   }
13206 
13207   if( !MTX_Resize( D, M->nrows, 1, M->isReal ) )    
13208   {
13209     MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
13210     return FALSE;
13211   }
13212 
13213   for( i = 0; i < M->nrows; i++ )
13214   {
13215     if( i < M->ncols )
13216     {
13217       if( M->isReal )
13218       {
13219         D->data[0][i] = M->data[i][i];
13220       }
13221       else
13222       {
13223         D->cplx[0][i].re = M->cplx[i][i].re;
13224         D->cplx[0][i].im = M->cplx[i][i].im;
13225       }
13226     }
13227   }
13228   return TRUE;
13229 }
13230 
13231 BOOL MTX_FlipColumn( MTX *M, const unsigned col )
13232 {
13233   unsigned i = 0;
13234   double re = 0;
13235   double im = 0;
13236 
13237   if( MTX_isNull( M ) )
13238   {
13239     MTX_ERROR_MSG( "NULL Matrix" );
13240     return FALSE;
13241   }
13242 
13243   if( col >= M->ncols )
13244   {
13245     MTX_ERROR_MSG( "if( col >= M->ncols )" );
13246     return FALSE;
13247   }
13248 
13249   if( M->isReal )
13250   {
13251     for( i = 0; i < (M->nrows/2); i++ )
13252     {
13253       re = M->data[col][i];
13254       M->data[col][i] = M->data[col][M->nrows - i - 1];
13255       M->data[col][M->nrows - i - 1] = re;
13256     }
13257   }
13258   else
13259   {
13260     for( i = 0; i < (M->nrows/2); i++ )
13261     {
13262       re = M->cplx[col][i].re;
13263       im = M->cplx[col][i].im;
13264       M->cplx[col][i].re = M->cplx[col][M->nrows - i - 1].re;
13265       M->cplx[col][i].im = M->cplx[col][M->nrows - i - 1].im;
13266       M->cplx[col][M->nrows - i - 1].re = re;
13267       M->cplx[col][M->nrows - i - 1].im = im;
13268     }
13269   }
13270   return TRUE;
13271 }
13272 
13273 BOOL MTX_FlipRow( MTX *M, const unsigned row )
13274 {
13275   unsigned i = 0;
13276   double re = 0;
13277   double im = 0;
13278 
13279   if( MTX_isNull( M ) )
13280   {
13281     MTX_ERROR_MSG( "NULL Matrix" );
13282     return FALSE;
13283   }
13284 
13285   if( row >= M->nrows )
13286   {
13287     MTX_ERROR_MSG( "if( row >= M->nrows )" );
13288     return FALSE;
13289   }
13290 
13291   if( M->isReal )
13292   {
13293     for( i = 0; i < (M->ncols/2); i++ )
13294     {
13295       re = M->data[i][row];
13296       M->data[i][row] = M->data[M->ncols - i - 1][row];
13297       M->data[M->ncols - i - 1][row] = re;
13298     }
13299   }
13300   else
13301   {
13302     for( i = 0; i < (M->ncols/2); i++ )
13303     {
13304       re = M->cplx[i][row].re;
13305       im = M->cplx[i][row].im;
13306       M->cplx[i][row].re = M->cplx[M->ncols - i - 1][row].re;
13307       M->cplx[i][row].im = M->cplx[M->ncols - i - 1][row].im;
13308       M->cplx[M->ncols - i - 1][row].re = re;
13309       M->cplx[M->ncols - i - 1][row].im = im;
13310     }
13311   }
13312   return TRUE;
13313 }
13314 
13315 BOOL MTX_SortAscending( MTX *M )
13316 {
13317   unsigned j = 0;
13318 
13319   if( MTX_isNull( M ) )
13320   {
13321     MTX_ERROR_MSG( "NULL Matrix" );
13322     return FALSE;
13323   }
13324 
13325   if( M->isReal )
13326   {
13327     for( j = 0; j < M->ncols; j++ )
13328     {
13329       MTX_static_quicksort( M->data[j], 0, M->nrows-1 );
13330     }
13331   }
13332   else
13333   {
13334     MTX indexvec;
13335     MTX_Init( &indexvec );
13336 
13337     for( j = 0; j < M->ncols; j++ )
13338     {
13339       if( !MTX_SortColumnIndexed( M, j, &indexvec ) )
13340       {
13341         MTX_ERROR_MSG( "MTX_SortColumnIndexed returned FALSE." );
13342         MTX_Free( &indexvec );
13343         return FALSE;
13344       }
13345     }
13346 
13347     MTX_Free( &indexvec );
13348   }
13349 
13350   return TRUE;
13351 }
13352 
13353 BOOL MTX_SortDescending( MTX *M )
13354 {
13355   unsigned j = 0;
13356 
13357   if( MTX_isNull( M ) )
13358   {
13359     MTX_ERROR_MSG( "NULL Matrix" );
13360     return FALSE;
13361   }
13362 
13363   if( M->isReal )
13364   {
13365     for( j = 0; j < M->ncols; j++ )
13366     {
13367       MTX_static_quicksort( M->data[j], 0, M->nrows-1 );
13368       if( !MTX_FlipColumn( M, j ) )
13369       {
13370         MTX_ERROR_MSG( "MTX_FlipColumn returned FALSE." );
13371         return FALSE;
13372       }
13373     }
13374   }
13375   else
13376   {
13377     if( !MTX_SortAscending( M ) )
13378     {
13379       MTX_ERROR_MSG( "MTX_SortAscending returned FALSE." );
13380       return FALSE;
13381     }
13382 
13383     for( j = 0; j < M->ncols; j++ )
13384     {
13385       if( !MTX_FlipColumn( M, j ) )
13386       {
13387         MTX_ERROR_MSG( "MTX_FlipColumn returned FALSE." );
13388         return FALSE;
13389       }
13390     }
13391   }
13392 
13393   return TRUE;
13394 }
13395 
13396 BOOL MTX_SortColumnAscending( MTX *M, const unsigned col )
13397 {
13398   if( MTX_isNull( M ) )
13399   {
13400     MTX_ERROR_MSG( "NULL Matrix" );
13401     return FALSE;
13402   }
13403 
13404   if( col >= M->ncols )
13405   {
13406     MTX_ERROR_MSG( "if( col >= M->ncols )" );
13407     return FALSE;
13408   }
13409 
13410   if( M->isReal )
13411   {
13412     MTX_static_quicksort( M->data[col], 0, M->nrows-1 );
13413   }
13414   else
13415   {
13416     MTX indexvec;
13417     MTX_Init( &indexvec );
13418 
13419     if( !MTX_SortColumnIndexed( M, col, &indexvec ) )
13420     {
13421       MTX_ERROR_MSG( "MTX_SortColumnIndexed returned FALSE." );
13422       MTX_Free( &indexvec );
13423       return FALSE;
13424     }
13425 
13426     MTX_Free( &indexvec );
13427   }
13428 
13429   return TRUE;
13430 }
13431 
13432 BOOL MTX_SortColumnDescending( MTX *M, const unsigned col )
13433 {
13434   if( MTX_isNull( M ) )
13435   {
13436     MTX_ERROR_MSG( "NULL Matrix" );
13437     return FALSE;
13438   }
13439 
13440   if( col >= M->ncols )
13441   {
13442     MTX_ERROR_MSG( "if( col >= M->ncols )" );
13443     return FALSE;
13444   }
13445 
13446   if( M->isReal )
13447   {
13448     MTX_static_quicksort( M->data[col], 0, M->nrows-1 );
13449     if( !MTX_FlipColumn( M, col ) )
13450     {
13451       MTX_ERROR_MSG( "MTX_FlipColumn returned FALSE." );
13452       return FALSE;
13453     }
13454   }
13455   else
13456   {
13457     if( !MTX_SortColumnAscending( M, col ) )
13458     {
13459       MTX_ERROR_MSG( "MTX_SortColumnAscending returned FALSE." );
13460       return FALSE;
13461     }
13462 
13463     if( !MTX_FlipColumn( M, col ) )
13464     {
13465       MTX_ERROR_MSG( "MTX_FlipColumn returned FALSE." );
13466       return FALSE;
13467     }
13468   }
13469 
13470   return TRUE;
13471 }
13472 
13473 BOOL MTX_SortColumnIndexed( MTX *M, const unsigned col, MTX *index )
13474 {
13475   unsigned i = 0;
13476   int k;
13477 
13478   if( MTX_isNull( M ) )
13479   {
13480     MTX_ERROR_MSG( "NULL Matrix" );
13481     return FALSE;
13482   }
13483 
13484   if( col >= M->ncols )
13485   {
13486     MTX_ERROR_MSG( "if( col >= M->ncols )" );
13487     return FALSE;
13488   }
13489 
13490   if( index->ncols != 1 || index->nrows != M->nrows || !(index->isReal) )
13491   {
13492     if( !MTX_Resize( index, M->nrows, 1, TRUE ) )
13493     {
13494       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
13495       return FALSE;
13496     }
13497   }
13498 
13499   for( i = 0; i < M->nrows; i++ )
13500     index->data[0][i] = i;
13501 
13502   if( M->isReal )
13503   {
13504     MTX_static_quicksort_indexed( M->data[col], index->data[0], 0, M->nrows-1 );
13505   }
13506   else
13507   {
13508     double re;
13509     double im;
13510     MTX colM;
13511     MTX mag;
13512 
13513     MTX_Init( &colM );
13514     MTX_Init( &mag );
13515 
13516     // make a copy of the column data
13517     if( !MTX_CopyColumn( M, col, &colM ) )
13518     {
13519       MTX_ERROR_MSG( "MTX_CopyColumn returned FALSE." );
13520       MTX_Free( &colM );
13521       return FALSE;
13522     }
13523 
13524     // get the magnitude
13525     if( !MTX_Magnitude( &colM, &mag ) )
13526     {
13527       MTX_ERROR_MSG( "MTX_Magnitude returned FALSE." );
13528       MTX_Free( &colM );
13529       MTX_Free( &mag );
13530       return FALSE;
13531     }
13532 
13533     // sort the magnitude of column j, and get the indexing vector
13534     MTX_static_quicksort_indexed( mag.data[0], index->data[0], 0, M->nrows-1 );
13535 
13536     // make a copy of the indexing vector (because colM is used and some values are set to -1)
13537     if( !MTX_Copy( index, &colM ) )
13538     {
13539       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
13540       MTX_Free( &colM );
13541       MTX_Free( &mag );
13542       return FALSE;
13543     }
13544 
13545     // sort the original data in the right order
13546     for( i = 0; i < M->nrows; i++ )
13547     {
13548       k = (int)(colM.data[0][i]);
13549       if( k >= 0 )
13550       {
13551         colM.data[0][k] = -1.0; // don't allow the reverse indexing
13552         if( i == (unsigned)k )
13553           continue;
13554 
13555         re = M->cplx[col][i].re;
13556         im = M->cplx[col][i].im;
13557         M->cplx[col][i].re = M->cplx[col][k].re;
13558         M->cplx[col][i].im = M->cplx[col][k].im;
13559         M->cplx[col][k].re = re;
13560         M->cplx[col][k].im = im;
13561       }
13562     }
13563 
13564     MTX_Free( &colM );
13565     MTX_Free( &mag );
13566   }
13567 
13568   return TRUE;
13569 }
13570 
13571 BOOL MTX_SortByColumn( MTX *M, const unsigned col )
13572 {
13573   unsigned i = 0;
13574   unsigned j = 0;
13575   int k = 0;
13576   MTX indexvec;
13577   MTX vec;
13578 
13579   MTX_Init( &indexvec );
13580   MTX_Init( &vec );
13581 
13582   if( MTX_isNull( M ) )
13583   {
13584     MTX_ERROR_MSG( "NULL Matrix" );
13585     return FALSE;
13586   }
13587 
13588   if( col >= M->ncols )
13589   {
13590     MTX_ERROR_MSG( "if( col >= M->ncols )" );
13591     return FALSE;
13592   }
13593 
13594   if( !MTX_SortColumnIndexed( M, col, &indexvec ) )
13595   {
13596     MTX_ERROR_MSG( "MTX_SortColumnIndexed returned FALSE." );
13597     MTX_Free( &indexvec );
13598     return FALSE;
13599   }
13600 
13601   for( j = 0; j < M->ncols; j++ )
13602   {
13603     if( j == col )
13604       continue; // already sorted
13605 
13606     if( !MTX_CopyColumn( M, j, &vec ) )
13607     {
13608       MTX_ERROR_MSG("MTX_Copy returned FALSE." );
13609       return FALSE;
13610     }
13611 
13612     for( i = 0; i < M->nrows; i++ )
13613     {
13614       k = (int)(indexvec.data[0][i]);
13615       if( k >= 0 )
13616       {
13617         if( i == (unsigned)k )
13618           continue;
13619 
13620         if( M->isReal )
13621         {
13622           M->data[j][i] = vec.data[0][k];          
13623         }
13624         else
13625         {
13626           M->cplx[j][i].re = vec.cplx[0][k].re;
13627           M->cplx[j][i].im = vec.cplx[0][k].im;
13628         }
13629       }
13630     }
13631   }
13632 
13633   MTX_Free( &indexvec );
13634   MTX_Free( &vec );
13635   return TRUE;
13636 }
13637 
13638 ///////////////////////////////////////////////////////////////////////////
13639 // The following the functions are used in a recursive quicksort
13640 // algorith for double arrays
13641 //
13642 //
13643 // The normal quicksort function
13644 void MTX_static_quicksort( double *a, unsigned start, unsigned end )
13645 {
13646   int split;
13647   if( start < end )
13648   {
13649     split = MTX_static_partition(a, start, end);
13650     MTX_static_quicksort(a, start, split);
13651     MTX_static_quicksort(a, split + 1, end);
13652   }
13653 }
13654 
13655 // swap two doubles a and b
13656 void MTX_static_swap_doubles( double *a, double *b )
13657 {
13658   double temp = *a;
13659   *a = *b;
13660   *b = temp;
13661 }
13662 
13663 // partition the vector
13664 int MTX_static_partition( double *a, unsigned start, unsigned end )
13665 {
13666   int right = end + 1;
13667   int left = start - 1;
13668   double pivot = a[start];
13669 
13670   while( right > left )
13671   {
13672     do{ left++; } while(a[left] < pivot);
13673     do{ right--; } while(a[right] > pivot);
13674     MTX_static_swap_doubles( &(a[left]), (&a[right]) );
13675   }
13676   MTX_static_swap_doubles( &(a[left]), &(a[right]) );
13677   return right;
13678 }
13679 
13680 // quicksort that also returns a sorted indexing vector
13681 void MTX_static_quicksort_indexed( double *a, double *index, unsigned start, unsigned end )
13682 {
13683   int split;
13684   if( start < end )
13685   {
13686     split = MTX_static_partition_indexed( a, index, start, end );
13687     MTX_static_quicksort_indexed( a, index, start, split );
13688     MTX_static_quicksort_indexed( a, index, split + 1, end );
13689   }
13690 }
13691 
13692 
13693 // swap the doubles
13694 void MTX_static_swap_doubles_indexed( double *a, double *b, double *index_a, double *index_b )
13695 {
13696   double temp = *a;
13697   double temp_ind = *index_a;
13698   *a = *b;
13699   *index_a = *index_b;
13700   *b = temp;
13701   *index_b = temp_ind;
13702 }
13703 
13704 // partition the vectors
13705 int MTX_static_partition_indexed( double *a, double *index, unsigned start, unsigned end )
13706 {
13707   int right = end + 1;
13708   int left = start - 1;
13709   double pivot = a[start];
13710   while( right > left )
13711   {
13712     do{ left++; } while(a[left] < pivot);
13713     do{ right--; } while(a[right] > pivot);
13714     MTX_static_swap_doubles_indexed( &(a[left]), &(a[right]), &(index[left]), &(index[right]) );
13715   }
13716   MTX_static_swap_doubles_indexed( &(a[left]), &(a[right]), &(index[left]), &(index[right]) );
13717   return right;
13718 }
13719 //
13720 //
13721 ///////////////////////////////////////////////////////////////////////////
13722 
13723 
13724 
13725 
13726 
13727 // Compression works as follows:
13728 // take a column of doubles
13729 // take each 8 bytes of a double
13730 // and RLE encode with the next 8 bytes of the next double
13731 // [ xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx ] a double
13732 // [ byte0_0 byte1_0 byte2_0 byte3_0 byte4_0 byte5_0 byte6_0 byte7_0 ] as bytes
13733 // [ .. .. .. .. .. .. .. .. ]
13734 // [ .. .. .. .. .. .. .. .. ]
13735 // [ byte0_n byte1_n byte2_n byte3_n byte4_n byte5_n byte6_n byte7_n ] as bytes
13736 //
13737 // RLE encode byte0_0:n, byte1_0:n, etc
13738 // in this way one column becomes 8 columns
13739 //
13740 // this process takes advantage of the similarities in the data of each column
13741 // and the RLE methods available with INTEL_IPPS
13742 //
13743 // Note: The INTEL_IPPS RLE encoding method did not prove significantly faster in testing.
13744 //
13745 // aaabbbbaaaaabbabbbbbb
13746 // compressed becomes
13747 // aa1bb2aa3bb0abb4
13748 //
13749 // Columns where compression does not provide benefit are written without compression
13750 BOOL MTX_SaveCompressed( const MTX *M, const char *path )
13751 {
13752   unsigned i = 0;
13753   unsigned j = 0;
13754   unsigned k = 0;
13755   unsigned ncols = 0; // number of columns if real, number of columns * 2 if complex.
13756 
13757   MTX MtxCol; // The current column for complex matrices only. Either real part or imag part.
13758 
13759 #ifdef MTX_DEBUG
13760   time_t t0, t1; /* time_t is defined on <time.h> and <sys/types.h> as long */
13761   clock_t c0, c1; /* clock_t is defined on <time.h> and <sys/types.h> as int */
13762   unsigned total_length = 0;
13763 #endif
13764 
13765   const unsigned nk = MTX_NK; // number of byte columns per double column
13766 
13767 
13768   unsigned char prevByte = 0;
13769   unsigned char currByte = 0;
13770   unsigned n = 0; // number of times the byte repeats (256 is upper bound!!)
13771   unsigned p = 0; // counter  
13772 
13773   unsigned char* bytes[MTX_NK];
13774   unsigned char* compressed[MTX_NK];
13775   unsigned char curr[MTX_NK];
13776 
13777   char msg[512];
13778 
13779   FILE* fid = NULL; // the output file pointer
13780 
13781   unsigned commentLength = 0; // the length of the matrix comment if any
13782   long filemark = 0; // a file position
13783 
13784   double col_stdev = 0; // The variance of a column.
13785   size_t count = 0;
13786 
13787   _MTX_STRUCT_FileHeader fileHeader;
13788   _MTX_STRUCT_CompressedColumnHeader columnHeader;
13789 
13790   // initialize MtxCol
13791   MTX_Init( &MtxCol );
13792 
13793   memset( &fileHeader, 0, sizeof(fileHeader) );
13794   memset( &columnHeader, 0, sizeof(columnHeader) );
13795 
13796 
13797   // initialize the file header information
13798 #ifndef _CRT_SECURE_NO_DEPRECATE
13799   if( strcpy_s( fileHeader.id, 8, MTX_ID_COMPRESSED_01 ) != 0 )
13800   {
13801     MTX_ERROR_MSG( "strcpy_s returned an error condition." );
13802     return FALSE;
13803   }
13804 #else
13805   strcpy( fileHeader.id, MTX_ID_COMPRESSED_01 );
13806 #endif
13807 
13808   if( M->comment != NULL )
13809   {
13810     fileHeader.comment = M->comment;
13811     commentLength = (unsigned int)strlen( fileHeader.comment );
13812   }
13813   fileHeader.headersize = MTX_ID_SIZE + 6*sizeof(unsigned int) + commentLength;
13814   fileHeader.isReal = M->isReal;
13815   fileHeader.nrows = M->nrows;
13816   fileHeader.ncols = M->ncols;
13817   fileHeader.filesize = 0;
13818   fileHeader.crc = 0;
13819 
13820   // open the output binary file
13821 #ifndef _CRT_SECURE_NO_DEPRECATE
13822   if( fopen_s( &fid, path, "wb" ) != 0 )
13823   {
13824     MTX_ERROR_MSG( "fopen_s returned an error condition." );
13825     return FALSE;
13826   }
13827 #else
13828   fid = fopen( path, "wb" );
13829 #endif
13830   if( fid == NULL )
13831   {
13832 #ifndef _CRT_SECURE_NO_DEPRECATE
13833     if( sprintf_s( msg, 512, "Unable to open %s", path ) > 0 )
13834       MTX_ERROR_MSG( msg );
13835 #else
13836     if( sprintf( msg, "Unable to open %s", path ) > 0 )
13837       MTX_ERROR_MSG( msg );
13838 #endif
13839     return FALSE;
13840   }
13841 
13842   // allocate memory for the RLE byte vectors
13843   // at most twice as long is possible with RLE
13844   for( k = 0; k < nk; k++ )
13845   {
13846     bytes[k] = (unsigned char*)malloc( M->nrows*sizeof(unsigned char) );
13847     if( bytes[k] == NULL )
13848     {
13849       MTX_ERROR_MSG( "malloc returned NULL." );
13850       fclose(fid);
13851       return FALSE;
13852     }
13853     compressed[k] = (unsigned char*)malloc( M->nrows*sizeof(unsigned char)*2 );
13854     if( compressed[k] == NULL )
13855     {
13856       MTX_ERROR_MSG( "malloc returned NULL." );
13857       fclose(fid);
13858       return FALSE;
13859     }
13860   }
13861 
13862   // write the matrix file identifier
13863   // in this case the compressed binary matrix version 01
13864   count = fwrite( fileHeader.id, sizeof(char), MTX_ID_SIZE, fid );
13865   if( count != MTX_ID_SIZE )
13866   {
13867     MTX_ERROR_MSG( "fwrite returned an error condition." );
13868     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13869     return FALSE;
13870   }
13871   // write the header size
13872   count = fwrite( &fileHeader.headersize, sizeof(unsigned), 1, fid );
13873   if( count != 1 )
13874   {
13875     MTX_ERROR_MSG( "fwrite returned an error condition." );
13876     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13877     return FALSE;
13878   }
13879   // write is the matrix is real or complex
13880   count = fwrite( &fileHeader.isReal, sizeof(unsigned), 1, fid );
13881   if( count != 1 )
13882   {
13883     MTX_ERROR_MSG( "fwrite returned an error condition." );
13884     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13885     return FALSE;
13886   }
13887   // write the size of the matrix
13888   count = fwrite( &M->nrows, sizeof(unsigned), 1, fid );
13889   if( count != 1 )
13890   {
13891     MTX_ERROR_MSG( "fwrite returned an error condition." );
13892     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13893     return FALSE;
13894   }
13895   count = fwrite( &M->ncols, sizeof(unsigned), 1, fid );
13896   if( count != 1 )
13897   {
13898     MTX_ERROR_MSG( "fwrite returned an error condition." );
13899     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13900     return FALSE;
13901   }
13902 
13903 
13904   // store the file position where the filesize and crc are written
13905   // after writing the data, we'll come back to this position to
13906   // rewrite this information correctly
13907   filemark = ftell( fid );
13908   count = fwrite( &fileHeader.filesize, sizeof(unsigned), 1, fid );
13909   if( count != 1 )
13910   {
13911     MTX_ERROR_MSG( "fwrite returned an error condition." );
13912     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13913     return FALSE;
13914   }
13915   count = fwrite( &fileHeader.crc, sizeof(unsigned), 1, fid );
13916   if( count != 1 )
13917   {
13918     MTX_ERROR_MSG( "fwrite returned an error condition." );
13919     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13920     return FALSE;
13921   }
13922   // write the matrix comment if any
13923   if( commentLength )
13924   {
13925     count = fwrite( fileHeader.comment, sizeof(char), commentLength, fid );
13926     if( count != commentLength )
13927     {
13928       MTX_ERROR_MSG( "fwrite returned an error condition." );
13929       MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13930       return FALSE;
13931     }
13932   }
13933 
13934 
13935 #ifdef MTX_DEBUG
13936   t0 = time(NULL);
13937   c0 = clock();
13938 #endif
13939 
13940   if( M->isReal )
13941     ncols = M->ncols;
13942   else
13943     ncols = M->ncols*2;
13944 
13945   for( j = 0; j < ncols; j++ )
13946   {
13947     // complex matrices are treated as re,im,re,im, etc so the matrix is stored as M->ncols*2 columns
13948     if( !M->isReal )
13949     {
13950       if( j == 0 || j%2 == 0 )
13951       {
13952         if( !MTX_RealColumn( M, j/2, &MtxCol ) )
13953         {
13954           MTX_ERROR_MSG( "MTX_RealColumn returned FALSE." );
13955           MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13956           return FALSE;
13957         }
13958       }
13959       else
13960       {
13961         if( !MTX_ImagColumn( M, j/2, &MtxCol ) )
13962         {
13963           MTX_ERROR_MSG( "MTX_ImagColumn returned FALSE." );
13964           MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13965           return FALSE;
13966         }
13967       }
13968     }
13969 
13970     // initialize lengths
13971     for( k = 0; k < nk; k++ )
13972     {
13973       columnHeader.length[k] = 0;
13974       columnHeader.isCompressed[k] = 0;
13975     }
13976     columnHeader.totalLength = 0;
13977 
13978 
13979     col_stdev = 1.0; // A non zero default value.
13980     if( M->isReal )
13981     {
13982       if( !MTX_ColumnStdev( M, j, &col_stdev ) )
13983       {
13984         MTX_ERROR_MSG( "MTX_ColumnStdev returned FALSE." );
13985         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13986         return FALSE;
13987       }
13988     }
13989     else
13990     {
13991       if( !MTX_ColumnStdev( &MtxCol, 0, &col_stdev ) )
13992       {
13993         MTX_ERROR_MSG( "MTX_ColumnStdev returned FALSE." );
13994         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
13995         return FALSE;
13996       }
13997     }
13998 
13999     if( col_stdev == 0.0 )
14000     {
14001       // output a single 0 for the first length indicating that a single double value represents this column
14002       count = fwrite( &(columnHeader.length[0]), sizeof(unsigned), 1, fid );
14003       if( count != 1 )
14004       {
14005         MTX_ERROR_MSG( "fwrite returned an error condition." );
14006         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14007         return FALSE;
14008       }
14009       MTX_static_updateCRC( (unsigned char*)(columnHeader.length), 4, &(fileHeader.crc) );
14010 
14011       // output the double
14012       if( M->isReal )
14013       {
14014         count = fwrite( &M->data[j][0], sizeof(double), 1, fid );
14015         if( count != 1 )
14016         {
14017           MTX_ERROR_MSG( "fwrite returned an error condition." );
14018           MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14019           return FALSE;
14020         }
14021       }
14022       else
14023       {
14024         count = fwrite( &MtxCol.data[0][0], sizeof(double), 1, fid );
14025         if( count != 1 )
14026         {
14027           MTX_ERROR_MSG( "fwrite returned an error condition." );
14028           MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14029           return FALSE;
14030         }
14031       }
14032 
14033       // copy the double's bytes to update the crc
14034       if( M->isReal )
14035       {
14036         memcpy( curr, &(M->data[j][0]), sizeof(double) );
14037         MTX_static_updateCRC( curr, 8, &(fileHeader.crc) );
14038       }
14039       else
14040       {
14041         memcpy( curr, &(MtxCol.data[0][0]), sizeof(double) );
14042         MTX_static_updateCRC( curr, 8, &(fileHeader.crc) );
14043       }
14044 
14045       continue;
14046     }
14047 
14048     // form the bytes vector for RLE input
14049     for( i = 0; i < M->nrows; i++ )
14050     {
14051       if( M->isReal )
14052         memcpy( curr, &(M->data[j][i]), sizeof(double) );
14053       else
14054         memcpy( curr, &(MtxCol.data[0][i]), sizeof(double) );
14055 
14056       for( k = 0; k < nk; k++ )
14057       {
14058         bytes[k][i] = curr[k];
14059       }
14060     }
14061 
14062 
14063     // quick test code
14064     /*
14065     k = 0;
14066     bytes[k][0] = 'a';
14067     bytes[k][1] = 'b';
14068     bytes[k][2] = 'b';
14069     bytes[k][3] = 'a';
14070     bytes[k][4] = 'b';
14071     bytes[k][5] = 'a';
14072 
14073     bytes[k][6] = 'a';
14074     bytes[k][7] = 'a';
14075     bytes[k][8] = 'b';
14076     bytes[k][9] = 'b';
14077     bytes[k][10] = 'b';
14078     bytes[k][11] = 'b';
14079 
14080     bytes[k][12] = 'a';
14081     bytes[k][13] = 'a';
14082     bytes[k][14] = 'a';
14083     bytes[k][15] = 'a';
14084     bytes[k][16] = 'a';
14085     bytes[k][17] = 'b';
14086 
14087     bytes[k][18] = 'b';
14088     bytes[k][19] = 'a';
14089     bytes[k][20] = 'b';
14090     bytes[k][21] = 'b';
14091     bytes[k][22] = 'a';
14092     */
14093 
14094     for( k = 0; k < nk; k++ )
14095     {
14096       // abbabaaabbbbaaaaabbabba
14097       // compressed becomes
14098       // abb0abaa1bb2aa3bb0abb0a
14099       i = 0;
14100       n = 0;
14101       p = 0;
14102       prevByte = bytes[k][i];
14103       i++;
14104       compressed[k][p] = prevByte;
14105       p++;
14106 
14107       while( i < M->nrows )
14108       {
14109         currByte = bytes[k][i];
14110         i++;
14111 
14112         if( currByte == prevByte )
14113         {
14114           n++;
14115           if( n == 256 )
14116           {
14117             compressed[k][p] = prevByte;
14118             p++;
14119             compressed[k][p] = (unsigned char)(n-1);
14120             p++;
14121             n = 0;
14122 
14123             prevByte = bytes[k][i];
14124             i++;
14125             compressed[k][p] = prevByte;
14126             p++;
14127             if( i == M->nrows )
14128               break;
14129           }
14130         }
14131         else
14132         {
14133           if( n > 0 )
14134           {
14135             compressed[k][p] = prevByte;
14136             p++;
14137             compressed[k][p] = (unsigned char)(n-1);
14138             p++;
14139             n = 0;
14140           }
14141           compressed[k][p] = currByte;
14142           p++;
14143           prevByte = currByte;
14144         }
14145       }
14146       if( n > 0 )
14147       {
14148         compressed[k][p] = prevByte;
14149         p++;
14150         compressed[k][p] = (unsigned char)(n-1);
14151         p++;
14152         n = 0;
14153       }
14154 
14155       columnHeader.length[k] = p;
14156       columnHeader.totalLength += columnHeader.length[k];
14157     }
14158 
14159     /*
14160     for( k = 0; k < nk; k++ )
14161     {
14162     for( n = 0; n < p; n++ )
14163     {
14164     if( compressed[k][p] != compressed_intel[k][p] )
14165     {
14166     count = 99;
14167     }
14168     }
14169     }
14170     */
14171 
14172 #ifdef MTX_DEBUG
14173     total_length += columnHeader.totalLength;
14174 #endif
14175 
14176     // test the compressed data lengths to determine if the compressed version should be output
14177     for( k = 0; k < nk; k++ )
14178     {
14179       if( columnHeader.length[k] >= M->nrows )
14180       {
14181         columnHeader.length[k] = M->nrows;
14182         columnHeader.isCompressed[k] = 0;
14183       }
14184       else
14185       {
14186         columnHeader.isCompressed[k] = 1;
14187       }
14188     }
14189 
14190     // output the data lengths
14191     for( k = 0; k < nk; k++ )
14192     {
14193       count = fwrite( &(columnHeader.length[k]), sizeof(unsigned), 1, fid );
14194       if( count != 1 )
14195       {
14196         MTX_ERROR_MSG( "fwrite returned an error condition." );
14197         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14198         return FALSE;
14199       }
14200       MTX_static_updateCRC( (unsigned char*)(&(columnHeader.length[k])), 4, &(fileHeader.crc) );
14201     }
14202 
14203     // output the compression indication
14204     for( k = 0; k < nk; k++ )
14205     {
14206       count = fwrite( &(columnHeader.isCompressed[k]), sizeof(unsigned char), 1, fid );
14207       if( count != 1 )
14208       {
14209         MTX_ERROR_MSG( "fwrite returned an error condition." );
14210         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14211         return FALSE;
14212       }
14213       MTX_static_updateCRC( &(columnHeader.isCompressed[k]), 1, &(fileHeader.crc) );
14214     }
14215 
14216     // output the data or compressed data
14217     for( k = 0; k < nk; k++ )
14218     {
14219       if( columnHeader.isCompressed[k] )
14220       {
14221         count = fwrite( compressed[k], sizeof(unsigned char), columnHeader.length[k], fid );
14222       }
14223       else
14224       {
14225         count = fwrite( bytes[k], sizeof(unsigned char), columnHeader.length[k], fid );
14226       }
14227       if( count != columnHeader.length[k] )
14228       {
14229         MTX_ERROR_MSG( "fwrite returned an error condition." );
14230         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14231         return FALSE;
14232       }
14233       if( columnHeader.isCompressed[k] )
14234       {
14235         MTX_static_updateCRC( compressed[k], columnHeader.length[k], &(fileHeader.crc) );
14236       }
14237       else
14238       {
14239         MTX_static_updateCRC( bytes[k], columnHeader.length[k], &(fileHeader.crc) );
14240       }
14241     }
14242   }
14243 
14244   // determine the filesize
14245   fileHeader.filesize = ftell(fid);
14246   fseek( fid, 0, SEEK_SET );
14247   fileHeader.filesize -= ftell(fid);
14248 
14249   // write the filesize and the crc back to the header position in the file
14250   fseek( fid, filemark, SEEK_SET );
14251   count = fwrite( &fileHeader.filesize, sizeof(unsigned), 1, fid );
14252   if( count != 1 )
14253   {
14254     MTX_ERROR_MSG( "fwrite returned an error condition." );
14255     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14256     return FALSE;
14257   }
14258   count = fwrite( &fileHeader.crc, sizeof(unsigned), 1, fid );
14259   if( count != 1 )
14260   {
14261     MTX_ERROR_MSG( "fwrite returned an error condition." );
14262     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14263     return FALSE;
14264   }
14265 
14266 #ifdef MTX_DEBUG
14267   t1 = time(NULL);
14268   c1 = clock();
14269   printf("\n%s compressed to: %.1lf (%%) of the original size.\n", path, 100.0*total_length/(M->nrows*M->ncols*8) );
14270 
14271   printf("Compression (GDM's) RLE: %.2f (s)\n", (float) (c1 - c0)/CLOCKS_PER_SEC);
14272 
14273 #endif
14274 
14275   // cleanup
14276   MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14277 
14278   return TRUE;
14279 }
14280 
14281 
14282 unsigned MTX_static_CRC32(unsigned ulCRC)
14283 {
14284 #define CRC32_POLYNOMIAL 0xEDB88320L
14285   int k;
14286   for( k = 8 ; k > 0; k-- )
14287   {
14288     if( ulCRC & 1 )
14289       ulCRC = ( ulCRC >> 1 ) ^ CRC32_POLYNOMIAL;
14290     else
14291       ulCRC >>= 1;
14292   }
14293   return ulCRC;
14294 }
14295 
14296 
14297 void MTX_static_updateCRC( unsigned char *pBytes, const unsigned nBytes, unsigned *uiCRC )
14298 {
14299   unsigned tmp1;
14300   unsigned tmp2;
14301   unsigned char *CRCData = pBytes;
14302   unsigned byteCount = nBytes;
14303 
14304   while( byteCount-- != 0 )
14305   {
14306     tmp1 = ( (*uiCRC) >> 8 ) & 0x00FFFFFFL;
14307     tmp2 = MTX_static_CRC32( ((unsigned) (*uiCRC) ^ *CRCData++ ) & 0xff );
14308     *uiCRC = tmp1 ^ tmp2;
14309   }
14310 }
14311 
14312 void MTX_static_SaveAndLoadCleanUp( FILE *fid, unsigned char **bytes, unsigned char **compressed, const unsigned nk )
14313 {
14314   unsigned k;
14315   if( fid != NULL )
14316     fclose(fid);
14317 
14318   // cleanup
14319   for( k = 0; k < nk; k++ )
14320   {
14321     if( bytes[k] != NULL )
14322       free( bytes[k] );
14323     if( compressed[k] != NULL )
14324       free( compressed[k] );
14325   }
14326 }
14327 
14328 
14329 BOOL MTX_GetCompressedFileAttributes(
14330                                      const char *path,
14331                                      unsigned* nrows,
14332                                      unsigned* ncols,
14333                                      BOOL* isReal
14334                                      )
14335 {
14336   FILE* fid = NULL;
14337   char msg[512];
14338 
14339   int version = 0; // matrix file version nr (0 is invalid)
14340   size_t count = 0;
14341 
14342   _MTX_STRUCT_FileHeader fileHeader; // file header information
14343 
14344 #ifndef _CRT_SECURE_NO_DEPRECATE
14345   if( fopen_s( &fid, path, "rb" ) != 0 )
14346   {
14347     MTX_ERROR_MSG( "fopen_s returned an error condition." );
14348     return FALSE;
14349   }
14350 #else
14351   fid = fopen( path, "rb" );
14352 #endif
14353   if( !fid )
14354   {
14355 #ifndef _CRT_SECURE_NO_DEPRECATE
14356     if( sprintf_s( msg, 512, "Unable to open %s.", path ) > 0 )
14357       MTX_ERROR_MSG( msg );
14358 #else
14359     if( sprintf( msg, "Unable to open %s.", path ) > 0 )
14360       MTX_ERROR_MSG( msg );
14361 #endif
14362     return FALSE;
14363   }
14364 
14365   // read the file identifiers
14366   count = fread( fileHeader.id, sizeof(char), MTX_ID_SIZE, fid );
14367   if( count != MTX_ID_SIZE )
14368   {
14369     MTX_ERROR_MSG( "fread returned an error condition." );
14370     fclose(fid);
14371     return FALSE;
14372   }
14373 
14374   if( strcmp( fileHeader.id, MTX_ID_COMPRESSED_01 ) == 0 ){ version = MTX_VERSION_NR_COMPRESSED_01; }
14375   else if( strcmp( fileHeader.id, MTX_ID_LEGACY_V01 ) == 0 ){ version = MTX_VERSION_NR_LEGACY_V01; }
14376   else if( strcmp( fileHeader.id, MTX_ID_LEGACY_V02 ) == 0 ){ version = MTX_VERSION_NR_LEGACY_V02; }
14377 
14378   if( version == 0 )
14379   {
14380     MTX_ERROR_MSG( "Unsupported compressed Matrix version." );
14381     fclose(fid);
14382     return FALSE;
14383   }
14384 
14385   if( version == MTX_VERSION_NR_LEGACY_V01 || version == MTX_VERSION_NR_LEGACY_V01 )
14386   {
14387     // NOT SUPPORTED HERE
14388     MTX_ERROR_MSG( "Unsupported compressed Matrix version." );
14389     fclose(fid);
14390     *nrows = 0;
14391     *ncols = 0;
14392     return FALSE;
14393   }
14394 
14395   // get the size of the header
14396   count = fread( &(fileHeader.headersize), sizeof(unsigned), 1, fid );
14397   if( count != 1 )
14398   {
14399     MTX_ERROR_MSG( "fread returned an error condition." );
14400     fclose(fid);
14401     return FALSE;
14402   }
14403 
14404   // get if the matrix is real or complex
14405   count = fread( &(fileHeader.isReal), sizeof(unsigned), 1, fid );
14406   if( count != 1 )
14407   {
14408     MTX_ERROR_MSG( "fread returned an error condition." );
14409     fclose(fid);
14410     return FALSE;
14411   }
14412 
14413   // get nrows
14414   count = fread( &(fileHeader.nrows), sizeof(unsigned), 1, fid );
14415   if( count != 1 )
14416   {
14417     MTX_ERROR_MSG( "fread returned an error condition." );
14418     fclose(fid);
14419     return FALSE;
14420   }
14421   if( fileHeader.nrows == 0 )
14422   {
14423     MTX_ERROR_MSG( "if( fileHeader.nrows == 0 )" );
14424     fclose(fid);
14425     return FALSE;
14426   }
14427   // get ncols
14428   count = fread( &(fileHeader.ncols), sizeof(unsigned), 1, fid );
14429   if( count != 1 )
14430   {
14431     MTX_ERROR_MSG( "fread returned an error condition." );
14432     fclose(fid);
14433     return FALSE;
14434   }
14435   if( fileHeader.ncols == 0 )
14436   {
14437     MTX_ERROR_MSG( "if( fileHeader.ncols == 0 )" );
14438     fclose(fid);
14439     return FALSE;
14440   }
14441 
14442   fclose(fid);
14443   *nrows = fileHeader.nrows;
14444   *ncols = fileHeader.ncols;
14445   *isReal = fileHeader.isReal;
14446   return TRUE;
14447 }
14448 
14449 
14450 BOOL MTX_ReadCompressed( MTX *M, const char *path )
14451 {
14452   unsigned i = 0;
14453   unsigned j = 0;
14454   unsigned k = 0;
14455   unsigned ncols = 0; // The number of compressed columns to read. if(M->isReal ) M->ncols else M->ncols*2.
14456 
14457 #ifdef MTX_DEBUG
14458   time_t t0, t1; // time_t is defined on <time.h> and <sys/types.h> as long
14459   clock_t c0, c1; // clock_t is defined on <time.h> and <sys/types.h> as int
14460 #endif
14461 
14462   const unsigned nk = MTX_NK; // number of byte columns per double column
14463 
14464   unsigned char prevByte = 0;
14465   unsigned char currByte = 0;
14466   unsigned nRepeatBytes = 0;
14467   unsigned n = 0; // counter
14468   unsigned p = 0; // counter
14469 
14470   unsigned char* bytes[MTX_NK];
14471   unsigned char* compressed[MTX_NK];
14472   unsigned char curr[MTX_NK];
14473   size_t count = 0; // number of bytes returned by fread
14474 
14475   char msg[512];
14476 
14477   FILE* fid = NULL;
14478 
14479   unsigned crc = 0; // the calculated crc
14480   unsigned filesize = 0; // the calculated file size
14481   unsigned commentLength = 0; // the length of the comment if present
14482 
14483   int version = 0; // matrix file version nr (0 is invalid)
14484 
14485   double dtmp; // a temporary double
14486   unsigned doubleWords[2] = {0,0}; // two 32 bit words that form a double
14487 
14488   _MTX_STRUCT_CompressedColumnHeader columnHeader; // column header information, just easier encapsulation
14489 
14490   _MTX_STRUCT_FileHeader fileHeader; // file header information
14491 
14492   MTX MtxRe; // For complex input, the real component column vector.
14493   MTX MtxIm; // For complex input, the imag component column vector.
14494   MTX *MtxCol = NULL; // A pointer to either MtxRe or MtxIm.
14495 
14496   // initializing
14497   MTX_Init( &MtxRe );
14498   MTX_Init( &MtxIm );
14499 
14500   if( !MTX_DetermineFileSize( path, &filesize ) )
14501   {
14502     MTX_ERROR_MSG( "MTX_DetermineFileSize returned FALSE." );
14503     return FALSE;
14504   }
14505 
14506 #ifndef _CRT_SECURE_NO_DEPRECATE
14507   if( fopen_s( &fid, path, "rb" ) != 0 )
14508   {
14509     MTX_ERROR_MSG( "fopen_s returned an error condition." );
14510     return FALSE;
14511   }
14512 #else
14513   fid = fopen( path, "rb" );
14514 #endif
14515   if( !fid )
14516   {
14517 #ifndef _CRT_SECURE_NO_DEPRECATE
14518     if( sprintf_s( msg, 512, "Unable to open %s.", path ) > 0 )
14519       MTX_ERROR_MSG( msg );
14520 #else
14521     if( sprintf( msg, "Unable to open %s.", path ) > 0 )
14522       MTX_ERROR_MSG( msg );
14523 #endif
14524     return FALSE;
14525   }
14526 
14527   // read the file identifiers
14528   count = fread( fileHeader.id, sizeof(char), MTX_ID_SIZE, fid );
14529   if( count != MTX_ID_SIZE )
14530   {
14531     MTX_ERROR_MSG( "fread returned an error condition." );
14532     fclose(fid);
14533     return FALSE;
14534   }
14535 
14536   if( strcmp( fileHeader.id, MTX_ID_COMPRESSED_01 ) == 0 ){ version = MTX_VERSION_NR_COMPRESSED_01; }
14537   else if( strcmp( fileHeader.id, MTX_ID_LEGACY_V01 ) == 0 ){ version = MTX_VERSION_NR_LEGACY_V01; }
14538   else if( strcmp( fileHeader.id, MTX_ID_LEGACY_V02 ) == 0 ){ version = MTX_VERSION_NR_LEGACY_V02; }
14539 
14540   if( version == 0 )
14541   {
14542     MTX_ERROR_MSG( "Unsupported compressed matrix version." );
14543     fclose(fid);
14544     return FALSE;
14545   }
14546 
14547   if( version == MTX_VERSION_NR_LEGACY_V01 || version == MTX_VERSION_NR_LEGACY_V01 )
14548   {
14549     fclose(fid);
14550     return MTX_static_ReadCompressed_LegacyVersion( M, path );
14551   }
14552 
14553   // get the size of the header
14554   count = fread( &(fileHeader.headersize), sizeof(unsigned), 1, fid );
14555   if( count != 1 )
14556   {
14557     MTX_ERROR_MSG( "fread returned an error condition." );
14558     fclose(fid);
14559     return FALSE;
14560   }
14561 
14562   // get if the matrix is real or complex
14563   count = fread( &(fileHeader.isReal), sizeof(unsigned), 1, fid );
14564   if( count != 1 )
14565   {
14566     MTX_ERROR_MSG( "fread returned an error condition." );
14567     fclose(fid);
14568     return FALSE;
14569   }
14570 
14571   // get nrows
14572   count = fread( &(fileHeader.nrows), sizeof(unsigned), 1, fid );
14573   if( count != 1 )
14574   {
14575     MTX_ERROR_MSG( "fread returned an error condition." );
14576     fclose(fid);
14577     return FALSE;
14578   }
14579   if( fileHeader.nrows == 0 )
14580   {
14581     MTX_ERROR_MSG( "if( fileHeader.nrows == 0 )" );
14582     fclose(fid);
14583     return FALSE;
14584   }
14585   // get ncols
14586   count = fread( &(fileHeader.ncols), sizeof(unsigned), 1, fid );
14587   if( count != 1 )
14588   {
14589     MTX_ERROR_MSG( "fread returned an error condition." );
14590     fclose(fid);
14591     return FALSE;
14592   }
14593   if( fileHeader.ncols == 0 )
14594   {
14595     MTX_ERROR_MSG( "if( fileHeader.ncols == 0 )" );
14596     fclose(fid);
14597     return FALSE;
14598   }
14599 
14600   // get the filesize
14601   count = fread( &(fileHeader.filesize), sizeof(unsigned), 1, fid );
14602   if( count != 1 )
14603   {
14604     MTX_ERROR_MSG( "fread returned an error condition." );
14605     fclose(fid);
14606     return FALSE;
14607   }
14608   // check the filesize
14609   if( filesize != fileHeader.filesize )
14610   {
14611     MTX_ERROR_MSG( "if( filesize != fileHeader.filesize )" );
14612     fclose(fid);
14613     return FALSE;
14614   }
14615 
14616   // get the crc
14617   count = fread( &(fileHeader.crc), sizeof(unsigned), 1, fid );
14618   if( count != 1 )
14619   {
14620     MTX_ERROR_MSG( "fread returned an error condition." );
14621     fclose(fid);
14622     return FALSE;
14623   }
14624 
14625   // get the matrix comment if any
14626   commentLength = fileHeader.headersize - MTX_ID_SIZE - 6*sizeof(unsigned);
14627   if( commentLength != 0 && commentLength < MTX_MAX_COMMENT_LENGTH )
14628   {
14629     fileHeader.comment = (char*)malloc( sizeof(char)*(commentLength+1) );
14630     if( fileHeader.comment == NULL )
14631     {
14632       MTX_ERROR_MSG( "malloc returned NULL." );
14633       fclose(fid);
14634       return FALSE;
14635     }
14636     count = fread( fileHeader.comment, sizeof(unsigned char), commentLength, fid );
14637     if( count != commentLength )
14638     {
14639       MTX_ERROR_MSG( "fread returned an error condition." );
14640       fclose(fid);
14641       return FALSE;
14642     }
14643     M->comment = fileHeader.comment;
14644   }
14645   else
14646   {
14647     if( M->comment )
14648       free( M->comment );
14649     M->comment = NULL;
14650   }
14651 
14652   // If the input is complex, the real and imag component vectors are input.
14653   if( !fileHeader.isReal )
14654   {
14655     if( !MTX_Malloc( &MtxRe, fileHeader.nrows, 1, TRUE ) )
14656     {
14657       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
14658       return FALSE;
14659     }
14660     if( !MTX_Malloc( &MtxIm, fileHeader.nrows, 1, TRUE ) )
14661     {
14662       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
14663       MTX_Free( &MtxRe );
14664       MTX_Free( &MtxIm );
14665       return FALSE;
14666     }
14667   }
14668 
14669   // resize the matrix if needed
14670   if( M->nrows != fileHeader.nrows || M->ncols != fileHeader.ncols || (M->isReal != (int)fileHeader.isReal) )
14671   {
14672     if( !MTX_Resize( M, fileHeader.nrows, fileHeader.ncols, fileHeader.isReal ) )
14673     {
14674       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
14675       fclose(fid);
14676       MTX_Free( &MtxRe );
14677       MTX_Free( &MtxIm );
14678       return FALSE;
14679     }
14680   }
14681 
14682   // allocate memory for the RLE byte vectors
14683   // at most twice as long is possible with RLE
14684   for( k = 0; k < nk; k++ )
14685   {
14686     bytes[k] = (unsigned char*)malloc( M->nrows*sizeof(unsigned char)*2 );
14687     if( !bytes[k] )
14688     {
14689       MTX_ERROR_MSG( "malloc returned NULL." );
14690       fclose(fid);
14691       MTX_Free( &MtxRe );
14692       MTX_Free( &MtxIm );
14693       return FALSE;
14694     }
14695     compressed[k] = (unsigned char*)malloc( M->nrows*sizeof(unsigned char)*2 );
14696     if( !compressed[k] )
14697     {
14698       MTX_ERROR_MSG( "malloc returned NULL." );
14699       fclose(fid);
14700       MTX_Free( &MtxRe );
14701       MTX_Free( &MtxIm );
14702       return FALSE;
14703     }
14704   }
14705 
14706 
14707 
14708 #ifdef MTX_DEBUG
14709   t0 = time(NULL);
14710   c0 = clock();
14711 #endif
14712 
14713   if( M->isReal )
14714     ncols = M->ncols;
14715   else
14716     ncols = M->ncols*2;
14717 
14718   for( j = 0; j < ncols; j++ )
14719   {
14720     if( !M->isReal )
14721     {
14722       if( j == 0 || j%2 == 0 )
14723       {
14724         MtxCol = &MtxRe;
14725       }
14726       else
14727       {
14728         MtxCol = &MtxIm;
14729       }
14730     }
14731 
14732     // check for special case of a single valued column
14733     // get first compressed vector length
14734     count = fread( &(columnHeader.length[0]), sizeof(unsigned), 1, fid );
14735     if( count != 1 )
14736     {
14737       MTX_ERROR_MSG( "fread returned an error condition." );
14738       MTX_Free( &MtxRe );
14739       MTX_Free( &MtxIm );
14740       MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14741       return FALSE;
14742     }
14743     MTX_static_updateCRC( (unsigned char*)&(columnHeader.length[0]), 4, &crc );
14744     if( columnHeader.length[0] == 0 )
14745     {
14746       count = fread( &dtmp, sizeof(double), 1, fid );
14747       if( count != 1 )
14748       {
14749         MTX_ERROR_MSG( "fread returned an error condition." );
14750         MTX_Free( &MtxRe );
14751         MTX_Free( &MtxIm );
14752         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14753         return FALSE;
14754       }
14755       memcpy( curr, &dtmp, sizeof(double) );
14756       MTX_static_updateCRC( curr, 8, &crc );
14757 
14758       if( M->isReal )
14759       {
14760         for( i = 0; i < M->nrows; i++ )
14761           M->data[j][i] = dtmp;
14762       }
14763       else
14764       {
14765         for( i = 0; i < M->nrows; i++ )
14766         {
14767           MtxCol->data[0][i] = dtmp;
14768         }
14769         if( j%2 != 0 && j != 0 )
14770         {
14771           if( !MTX_SetComplexColumn( M, j/2, &MtxRe, &MtxIm ) )
14772           {
14773             MTX_ERROR_MSG( "MTX_SetComplexColumn returned FALSE." );
14774             MTX_Free( &MtxRe );
14775             MTX_Free( &MtxIm );
14776             return FALSE;
14777           }
14778         }
14779       }
14780       continue;
14781     }
14782 
14783     // get the rest of the compressed vector lengths
14784     for( k = 1; k < nk; k++ )
14785     {
14786       count = fread( &(columnHeader.length[k]), sizeof(unsigned), 1, fid );
14787       if( count != 1 )
14788       {
14789         MTX_ERROR_MSG( "fread returned an error condition." );
14790         MTX_Free( &MtxRe );
14791         MTX_Free( &MtxIm );
14792         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14793         return FALSE;
14794       }
14795       MTX_static_updateCRC( (unsigned char*)&(columnHeader.length[k]), 4, &crc );
14796     }
14797 
14798     // get the indication that compression was used
14799     for( k = 0; k < nk; k++ )
14800     {
14801       count = fread( &(columnHeader.isCompressed[k]), sizeof(unsigned char), 1, fid );
14802       if( count != 1 )
14803       {
14804         MTX_ERROR_MSG( "fread returned an error condition." );
14805         MTX_Free( &MtxRe );
14806         MTX_Free( &MtxIm );
14807         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14808         return FALSE;
14809       }
14810       MTX_static_updateCRC( &(columnHeader.isCompressed[k]), 1, &crc );
14811     }
14812 
14813     // get the compressed data
14814     for( k = 0; k < nk; k++ )
14815     {
14816       if( columnHeader.isCompressed[k] )
14817       {
14818         count = fread( compressed[k], sizeof(unsigned char), columnHeader.length[k], fid );
14819       }
14820       else
14821       {
14822         count = fread( bytes[k], sizeof(unsigned char), columnHeader.length[k], fid );
14823       }
14824       if( count != columnHeader.length[k] )
14825       {
14826         MTX_ERROR_MSG( "if( count != columnHeader.length[k] )" );
14827         MTX_Free( &MtxRe );
14828         MTX_Free( &MtxIm );
14829         MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14830         return FALSE;
14831       }
14832       if( columnHeader.isCompressed[k] )
14833       {
14834         MTX_static_updateCRC( compressed[k], columnHeader.length[k], &crc );
14835       }
14836       else
14837       {
14838         MTX_static_updateCRC( bytes[k], columnHeader.length[k], &crc );
14839       }
14840     }
14841 
14842 
14843     // decompress the data
14844     // aa1bb2aa3bb0abb4
14845     // decompressed becomes
14846     // aaabbbbaaaaabbabbbbbb
14847     for( k = 0; k < nk; k++ )
14848     {
14849       if( columnHeader.isCompressed[k] )
14850       {
14851         n = 0;
14852         p = 0;
14853         prevByte = compressed[k][p]; p++;
14854         bytes[k][n] = prevByte; n++;
14855         while( p < columnHeader.length[k] )
14856         {
14857           currByte = compressed[k][p]; p++;
14858           bytes[k][n] = currByte; n++;
14859 
14860           if( currByte == prevByte )
14861           {
14862             nRepeatBytes = compressed[k][p];
14863             p++;
14864 
14865             nRepeatBytes = n+nRepeatBytes;
14866             for( n; n < nRepeatBytes; n++ )
14867             {
14868               if( n >= M->nrows )
14869               {
14870                 MTX_ERROR_MSG( "if( n >= M->nrows ) - BAD DATA IN COMPRESSED MATRIX FILE." );
14871                 // bad data!, this should not happen
14872                 MTX_Free( &MtxRe );
14873                 MTX_Free( &MtxIm );
14874                 MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14875                 return FALSE;
14876               }
14877               bytes[k][n] = currByte;
14878             }
14879             if( p == columnHeader.length[k] )
14880               break;
14881             if( n >= M->nrows )
14882             {
14883               MTX_ERROR_MSG( "if( n >= M->nrows ) - BAD DATA IN COMPRESSED MATRIX FILE." );
14884               // bad data!, this should not happen
14885               MTX_Free( &MtxRe );
14886               MTX_Free( &MtxIm );
14887               MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14888               return FALSE;
14889             }
14890             prevByte = compressed[k][p]; p++;
14891             bytes[k][n] = prevByte; n++;
14892           }
14893           else
14894           {
14895             prevByte = currByte;
14896           }
14897         }
14898 
14899         // check that the bytes vector is fully populated
14900         if( n != M->nrows )
14901         {
14902           MTX_ERROR_MSG( "if( n >= M->nrows ) - BAD DATA IN COMPRESSED MATRIX FILE." );
14903           MTX_Free( &MtxRe );
14904           MTX_Free( &MtxIm );
14905           MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14906           return FALSE;
14907         }
14908       }
14909     }
14910 
14911     // reform the doubles using the byte data
14912     for( i = 0; i < M->nrows; i++ )
14913     {
14914       doubleWords[0] = bytes[3][i] << 24;
14915       doubleWords[0] |= bytes[2][i] << 16;
14916       doubleWords[0] |= bytes[1][i] << 8;
14917       doubleWords[0] |= bytes[0][i];
14918 
14919       doubleWords[1] = bytes[7][i] << 24;
14920       doubleWords[1] |= bytes[6][i] << 16;
14921       doubleWords[1] |= bytes[5][i] << 8;
14922       doubleWords[1] |= bytes[4][i];
14923 
14924       if( M->isReal )
14925       {
14926         memcpy( &(M->data[j][i]), doubleWords, sizeof(double) );
14927       }
14928       else
14929       {
14930         memcpy( &(MtxCol->data[0][i]), doubleWords, sizeof(double) );
14931       }
14932     }
14933 
14934     if( !M->isReal )
14935     {
14936       if( j%2 != 0 && j != 0 )
14937       {
14938         if( !MTX_SetComplexColumn( M, j/2, &MtxRe, &MtxIm ) )
14939         {
14940           MTX_ERROR_MSG( "MTX_SetComplexColumn returned FALSE." );
14941           MTX_Free( &MtxRe );
14942           MTX_Free( &MtxIm );
14943           return FALSE;
14944         }
14945       }
14946     }
14947   }
14948 
14949   // check the crc
14950   if( fileHeader.crc != crc )
14951   {
14952     MTX_ERROR_MSG( "if( fileHeader.crc != crc )" );
14953     MTX_Free( &MtxRe );
14954     MTX_Free( &MtxIm );
14955     MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14956     return FALSE;
14957   }
14958 
14959 #ifdef MTX_DEBUG
14960   t1 = time(NULL);
14961   c1 = clock();
14962   printf("File Loaded and decompression RLE in: %.2f (s) (GDM)\n", (float) (c1 - c0)/CLOCKS_PER_SEC);
14963 #endif
14964 
14965   // Cleanup
14966   MTX_Free( &MtxRe );
14967   MTX_Free( &MtxIm );
14968   MTX_static_SaveAndLoadCleanUp( fid, bytes, compressed, nk );
14969 
14970   return TRUE;
14971 }
14972 
14973 
14974 BOOL MTX_static_ReadCompressed_LegacyVersion( MTX* M, const char *path )
14975 {
14976   unsigned i = 0;
14977   unsigned j = 0;
14978   int version = 0;
14979 
14980   FILE* fid = NULL;
14981 
14982   unsigned g = 0; // counter
14983   unsigned p = 0; // counter
14984   unsigned k = 0; // counter
14985   unsigned char nrepeat = 0;
14986   unsigned char method = 0;
14987   double d = 0.0;
14988   const unsigned kCompressionByDouble = 1;
14989 
14990   unsigned char* columnBuffer = NULL;
14991   unsigned char* compressedBuffer = NULL;
14992   unsigned char ucTmp[2];
14993   unsigned columnBufSize = 0;
14994   unsigned compressedSize = 0;
14995 
14996   char msg[512];
14997 
14998   size_t count = 0;
14999 
15000   _MTX_STRUCT_FileHeader fileHeader;
15001 
15002   fileHeader.nrows = 0;
15003   fileHeader.ncols = 0;
15004   fileHeader.filesize = 0;
15005   fileHeader.headersize = 0;
15006   fileHeader.crc = 0;
15007   fileHeader.comment = NULL;
15008 
15009 #ifndef _CRT_SECURE_NO_DEPRECATE
15010   if( fopen_s( &fid, path, "rb" ) != 0 )
15011   {
15012     MTX_ERROR_MSG( "fopen_s returned an error condition." );
15013     return FALSE;
15014   }
15015 #else
15016   fid = fopen(path,"rb");
15017 #endif
15018   if( !fid )
15019   {
15020 #ifndef _CRT_SECURE_NO_DEPRECATE
15021     if( sprintf_s( msg, 512, "Unable to open %s.", path ) > 0 )
15022       MTX_ERROR_MSG( msg );
15023 #else
15024     if( sprintf( msg, "Unable to open %s.", path ) > 0 )
15025       MTX_ERROR_MSG( msg );
15026 #endif
15027     return FALSE;
15028   }
15029 
15030   // write the file identifiers
15031   count = fread( fileHeader.id, sizeof(char), MTX_ID_SIZE, fid );
15032   if( count != MTX_ID_SIZE )
15033   {
15034     MTX_ERROR_MSG( "fread returned an error condition." );
15035     fclose(fid);
15036     return FALSE;
15037   }
15038 
15039   if( strcmp( fileHeader.id, MTX_ID_LEGACY_V01 ) == 0 )
15040   {
15041     version = MTX_VERSION_NR_LEGACY_V01;
15042   }
15043   else if( strcmp( fileHeader.id, MTX_ID_LEGACY_V02 ) == 0 )
15044   {
15045     version = MTX_VERSION_NR_LEGACY_V02;
15046   }
15047   else // version == 0
15048   {
15049     MTX_ERROR_MSG( "Unsupported compressed matrix version." );
15050     fclose(fid);
15051     return FALSE;
15052   }
15053 
15054   count = fread( &(fileHeader.nrows), sizeof(unsigned), 1, fid );
15055   if( count != 1 )
15056   {
15057     MTX_ERROR_MSG( "fread returned an error condition." );
15058     fclose(fid);
15059     return FALSE;
15060   }
15061   count = fread( &(fileHeader.ncols), sizeof(unsigned), 1, fid );
15062   if( count != 1 )
15063   {
15064     MTX_ERROR_MSG( "fread returned an error condition." );
15065     fclose(fid);
15066     return FALSE;
15067   }
15068 
15069   if( fileHeader.nrows == 0 || fileHeader.ncols == 0 )
15070   {
15071     MTX_ERROR_MSG( "if( fileHeader.nrows == 0 || fileHeader.ncols == 0 )" );
15072     fclose(fid);
15073     return FALSE;
15074   }
15075 
15076   // read in version 2 header info
15077   if( version == 2 )
15078   {
15079     // info was used for column width determination, no longer needed
15080     // with better code :D
15081     for( j = 0; j < fileHeader.ncols; j++ )
15082     {
15083       count = fread( ucTmp, sizeof(unsigned char), 2, fid );
15084       if( count != 2 )
15085       {
15086         MTX_ERROR_MSG( "fread returned an error condition." );
15087         fclose(fid);
15088         return FALSE;
15089       }
15090     }
15091   }
15092 
15093   // resize the matrix accordingly
15094   if( M->nrows != fileHeader.nrows || M->ncols != fileHeader.ncols )
15095   {
15096     if( !MTX_Resize( M, fileHeader.nrows, fileHeader.ncols, TRUE ) ) //!!!! adress complex/real
15097     {
15098       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
15099       fclose(fid);
15100       return FALSE;
15101     }
15102   }
15103 
15104 
15105   // here's where we go crazy
15106   // Run Length Encoding is used in decompressing the matrix
15107   // on a column by column basis
15108 
15109   // allocate a buffer large enough to store one column completely
15110   columnBufSize = sizeof(double)*(M->nrows);
15111   columnBuffer = (unsigned char*)malloc( columnBufSize );
15112   if( columnBuffer == NULL )
15113   {
15114     MTX_ERROR_MSG( "malloc returned NULL." );
15115     fclose(fid);
15116     return FALSE;
15117   }
15118 
15119   for( j = 0; j < M->ncols; j++ )
15120   {
15121     // get the size of the compressedBuffer
15122     count = fread( &compressedSize, sizeof(unsigned), 1, fid );
15123     if( count != 1 )
15124     {
15125       MTX_ERROR_MSG( "fread returned an error condition." );
15126       if( columnBuffer ) 
15127         free(columnBuffer);
15128       fclose(fid);
15129       return FALSE;
15130     }
15131 
15132     if( compressedSize == columnBufSize )
15133     {
15134       // no compression just read in the doubles
15135       count = fread( M->data[j], sizeof(double), M->nrows, fid );
15136       if( count != M->nrows )
15137       {
15138         MTX_ERROR_MSG( "fread returned an error condition." );
15139         if( columnBuffer )
15140           free(columnBuffer);
15141         fclose(fid);
15142         return FALSE;
15143       }
15144       continue;
15145     }
15146 
15147     // allocate the compressedBuffer
15148     compressedBuffer = (unsigned char*)malloc( compressedSize );
15149     if( compressedBuffer == NULL )
15150     {
15151       MTX_ERROR_MSG( "malloc returned NULL." );
15152       if( columnBuffer )
15153         free(columnBuffer);
15154       fclose(fid);      
15155       return FALSE;
15156     }
15157 
15158     memcpy( &(compressedBuffer[0]), &compressedSize, sizeof(unsigned) );
15159 
15160     // read in the compressed data
15161     count = fread( &(compressedBuffer[sizeof(unsigned)]), 1, (compressedSize - sizeof(unsigned)), fid );
15162     if( count != (compressedSize - sizeof(unsigned)) )
15163     {
15164       MTX_ERROR_MSG( "fread returned an error condition." );
15165       if( compressedBuffer )
15166         free(compressedBuffer);
15167       if( columnBuffer )
15168         free(columnBuffer);
15169       fclose(fid);
15170       return FALSE;
15171     }
15172 
15173     // determine compression method
15174     memcpy( &method, &(compressedBuffer[sizeof(unsigned)]), 1 );
15175     if( method != kCompressionByDouble )
15176     {
15177       MTX_ERROR_MSG( "if( method != kCompressionByDouble )" );
15178       if( compressedBuffer )
15179         free(compressedBuffer);
15180       if( columnBuffer )
15181         free(columnBuffer);
15182       fclose(fid);
15183       return FALSE;
15184     }
15185 
15186     // simple double RLE decompression
15187     k = 0;
15188     for( g = sizeof(unsigned)+1; g < compressedSize-sizeof(double); g+=sizeof(double) )
15189     {
15190       nrepeat = compressedBuffer[g];
15191       g++;
15192       memcpy( &d, &(compressedBuffer[g]), sizeof(double) );
15193       for( p = 0; p < nrepeat; p++)
15194       {
15195         memcpy( &(columnBuffer[k]), &d, sizeof(double) );
15196         k+=sizeof(double);
15197       }
15198     }
15199 
15200     // set the data
15201     for( i = 0; i < M->nrows; i++ )
15202       memcpy( &(M->data[j][i]), &(columnBuffer[i*sizeof(double)]), sizeof(double) );
15203 
15204     // remember to free the compressed buffer
15205     free(compressedBuffer);
15206     compressedBuffer = NULL;
15207     compressedSize = 0;
15208   }
15209 
15210   // remember to delete the columnBuffer
15211   free(columnBuffer);
15212 
15213   // we're done
15214   fclose(fid);
15215 
15216   return TRUE;
15217 }
15218 
15219 BOOL MTX_LoadAndSave( const char* infilepath, const char* outfilepath )
15220 {
15221   MTX M;
15222   MTX_Init( &M );
15223 
15224   if( !MTX_ReadFromFile( &M, infilepath ) )
15225   {
15226     MTX_ERROR_MSG( "MTX_ReadFromFile returned FALSE." );
15227     MTX_Free( &M );
15228     return FALSE;
15229   }
15230 
15231   if( !MTX_SaveCompressed( &M, outfilepath ) )
15232   {
15233     MTX_ERROR_MSG( "MTX_SaveCompressed returned FALSE." );
15234     MTX_Free( &M );
15235     return FALSE;
15236   }
15237 
15238   MTX_Free( &M );
15239   return TRUE;
15240 }
15241 
15242 BOOL MTX_LoadAndSaveQuick( const char* infilepath )
15243 {
15244   unsigned k;
15245   unsigned p;
15246   unsigned length;
15247   char outfilepath[1024];
15248   char *strptr = NULL;
15249 
15250   MTX M;
15251   MTX_Init( &M );
15252 
15253   if( !MTX_ReadFromFile( &M, infilepath ) )
15254   {
15255     MTX_ERROR_MSG( "MTX_ReadFromFile returned FALSE." );
15256     MTX_Free( &M );
15257     return FALSE;
15258   }
15259 
15260   length = (unsigned int)strlen(infilepath);
15261   if( length >= 1024 )
15262   {
15263     MTX_ERROR_MSG( "if( length >= 1024 )" );
15264     MTX_Free( &M );
15265     return FALSE;
15266   }
15267 
15268 #ifndef _CRT_SECURE_NO_DEPRECATE
15269   if( strcpy_s( outfilepath, 1024, infilepath ) != 0 )
15270   {
15271     MTX_ERROR_MSG( "strcpy_s returned an error condition." );
15272     MTX_Free( &M );
15273     return FALSE;
15274   }
15275 #else
15276   strcpy( outfilepath, infilepath );
15277 #endif
15278   // find the last instance of '.' in the input file name
15279   for( k = 0; k < length; k++ )
15280   {
15281     if( outfilepath[k] == '.' )
15282     {
15283       strptr = &(outfilepath[k]);
15284       p = k;
15285     }
15286   }
15287 #ifndef _CRT_SECURE_NO_DEPRECATE
15288   if( sprintf_s( strptr, length-p+1, ".mtx" ) < 0 )
15289   {
15290     MTX_ERROR_MSG( "sprintf_s returned failure." );
15291     MTX_Free( &M );
15292     return FALSE;
15293   }
15294 #else
15295   if( sprintf( strptr, ".mtx" ) < 0 )
15296   {
15297     MTX_ERROR_MSG( "sprintf returned failure." );
15298     return FALSE;
15299   }
15300 #endif
15301 
15302   // save the data
15303   if( !MTX_SaveCompressed( &M, outfilepath ) )
15304   {
15305     MTX_ERROR_MSG( "MTX_SaveCompressed returned FALSE." );
15306     MTX_Free( &M );
15307     return FALSE;
15308   }
15309 
15310   MTX_Free( &M );
15311   return TRUE;
15312 }
15313 
15314 BOOL MTX_TimeWindow(
15315                     MTX* M, //!< Matrix to be altered
15316                     const unsigned timeColumn, //!< The column containing time
15317                     const double startTime, //!< The specified start time (inclusive)
15318                     const double duration, //!< The duration to include
15319                     const double rolloverTime )//!< The potential time at which system time rolls over
15320 {
15321   unsigned i = 0;
15322   unsigned j = 0;
15323   const double endTime = startTime + duration;
15324   unsigned index = 0;
15325   double time;
15326   double dt;
15327 
15328   if( MTX_isNull( M ) )
15329   {
15330     MTX_ERROR_MSG( "NULL Matrix" );
15331     return FALSE;
15332   }
15333 
15334   if( timeColumn >= M->ncols )
15335   {
15336     MTX_ERROR_MSG( "if( timeColumn >= M->ncols )" );
15337     return FALSE;
15338   }
15339 
15340   i = 0;
15341   if( M->isReal )
15342     time = M->data[timeColumn][i];
15343   else
15344     time = M->cplx[timeColumn][i].re;
15345 
15346   i++;
15347   if( time >= startTime && time <= endTime )
15348   {
15349     // no need to copy the 0th row to the 0th row
15350     index++;
15351   }
15352 
15353   if( time < endTime )
15354   {
15355     while( i < M->nrows )
15356     {
15357       if( M->isReal )
15358         dt = M->data[timeColumn][i] - time;
15359       else
15360         dt = M->cplx[timeColumn][i].re - time;
15361 
15362       if( dt < 0.0 )
15363       {
15364         if( rolloverTime == 0.0 )
15365           break;
15366         dt += rolloverTime;
15367       }
15368 
15369       time += dt;
15370 
15371       if( time > endTime )
15372         break;
15373 
15374       if( time >= startTime && time <= endTime )
15375       {
15376         // copy this row if needed
15377         if( index != i )
15378         {
15379           for( j = 0; j < M->ncols; j++ )
15380           {
15381             if( M->isReal )
15382             {
15383               M->data[j][index] = M->data[j][i];
15384             }
15385             else
15386             {
15387               M->cplx[j][index].re = M->cplx[j][i].re;
15388               M->cplx[j][index].im = M->cplx[j][i].im;
15389             }
15390           }
15391         }
15392         index++;
15393       }
15394       i++;
15395     }
15396   }
15397 
15398   if( index == 0 )
15399   {
15400     MTX_Free( M );
15401   }
15402   else
15403   {
15404     // redimension the matrix accordingly
15405     if( !MTX_Redim( M, index, M->ncols ) )
15406     {
15407       MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
15408       return FALSE;
15409     }
15410   }
15411 
15412   return TRUE;
15413 }
15414 
15415 BOOL MTX_TimeLimit(
15416                    MTX* M, //!< Matrix to be altered
15417                    const unsigned timeColumn, //!< The column containing time
15418                    const double startTime, //!< The specified start time (inclusive)
15419                    const double endTime )//!< The duration to include
15420 {
15421   double duration = endTime - startTime;
15422 
15423   if( duration < 0 )
15424   {
15425     MTX_ERROR_MSG( "if( duration < 0 )" );
15426     return FALSE;
15427   }
15428 
15429   return MTX_TimeWindow( M, timeColumn, startTime, duration, 0.0 );
15430 }
15431 
15432 BOOL MTX_TimeMatch(
15433                    MTX *A,
15434                    const unsigned timeColumnA,
15435                    MTX *B,
15436                    const unsigned timeColumnB,
15437                    const unsigned precision,
15438                    const double rolloverTime )
15439 {
15440   unsigned index = 0; // index into the final time matched matrices
15441   unsigned indexA = 0; // index into matrix A
15442   unsigned indexB = 0; // index into matrix B
15443   unsigned col;
15444 
15445   double time1; // current time rounded to the specified precision for matrix A
15446   double time2; // current time rounded to the specified precision for matrix B
15447   double time1_prev; // previous time rounded to the specified precision for matrix A
15448   double time2_prev; // previous time rounded to the specified precision for matrix B
15449   double ctime1; // continuous time without rollovers equivalent for time1
15450   double ctime2; // continuous time without rollovers equivalent for time2
15451   double dt; // delta time
15452 
15453   if( MTX_isNull( A ) )
15454   {
15455     MTX_ERROR_MSG( "NULL Matrix" );
15456     return FALSE;
15457   }
15458   if( MTX_isNull( B ) )
15459   {
15460     MTX_ERROR_MSG( "NULL Matrix" );
15461     return FALSE;
15462   }
15463 
15464   if( timeColumnA >= A->ncols || timeColumnB >= B->ncols )
15465   {
15466     MTX_ERROR_MSG( "if( timeColumnA >= A->ncols || timeColumnB >= B->ncols )" );
15467     return FALSE;
15468   }
15469 
15470   if( A->isReal )
15471     time1 = A->data[timeColumnA][indexA];
15472   else
15473     time1 = A->cplx[timeColumnA][indexA].re;
15474 
15475   MTX_static_round_value( &time1, precision );
15476   ctime1 = time1;
15477 
15478   if( B->isReal )
15479     time2 = B->data[timeColumnB][indexB];
15480   else
15481     time2 = B->cplx[timeColumnB][indexB].re;
15482 
15483   MTX_static_round_value( &time2, precision );
15484   ctime2 = time2;
15485 
15486   while( indexA < A->nrows && indexB < B->nrows )
15487   {
15488     if( ctime1 == ctime2 )
15489     {
15490       // copy row to A
15491       if( index != indexA )
15492       {
15493         for( col = 0; col < A->ncols; col++ )
15494         {
15495           if( A->isReal )
15496           {
15497             A->data[col][index] = A->data[col][indexA];
15498           }
15499           else
15500           {
15501             A->cplx[col][index].re = A->cplx[col][indexA].re;
15502             A->cplx[col][index].im = A->cplx[col][indexA].im;
15503           }
15504         }
15505       }
15506 
15507       // copy row to B
15508       if( index != indexB )
15509       {
15510         for( col = 0; col < B->ncols; col++ )
15511         {
15512           if( B->isReal )
15513           {
15514             B->data[col][index] = B->data[col][indexB];
15515           }
15516           else
15517           {
15518             B->cplx[col][index].re = B->cplx[col][indexB].re;
15519             B->cplx[col][index].im = B->cplx[col][indexB].im;
15520           }
15521         }
15522       }
15523       index++;
15524       indexA++;
15525       indexB++;
15526 
15527       time1_prev = time1;
15528       if( A->isReal )
15529         time1 = A->data[timeColumnA][indexA];
15530       else
15531         time1 = A->cplx[timeColumnA][indexA].re;
15532 
15533       MTX_static_round_value( &time1, precision );
15534       dt = time1 - time1_prev;
15535       if( dt < 0.0 )
15536       {
15537         if( rolloverTime == 0.0 )
15538           break; // rollovers not allowed
15539         dt += rolloverTime;
15540       }
15541       ctime1 += dt;
15542 
15543       time2_prev = time2;
15544       if( B->isReal )
15545         time2 = B->data[timeColumnB][indexB];
15546       else
15547         time2 = B->cplx[timeColumnB][indexB].re;
15548 
15549       MTX_static_round_value( &time2, precision );
15550       dt = time2 - time2_prev;
15551       if( dt < 0.0 )
15552       {
15553         if( rolloverTime == 0.0 )
15554           break; // rollovers not allowed
15555         dt += rolloverTime;
15556       }
15557       ctime2 += dt;
15558     }
15559     else if( ctime1 < ctime2 )
15560     {
15561       indexA++;
15562 
15563       time1_prev = time1;
15564       if( A->isReal )
15565         time1 = A->data[timeColumnA][indexA];
15566       else
15567         time1 = A->cplx[timeColumnA][indexA].re;
15568 
15569       MTX_static_round_value( &time1, precision );
15570       dt = time1 - time1_prev;
15571       if( dt < 0.0 )
15572       {
15573         if( rolloverTime == 0.0 )
15574           break; // rollovers not allowed
15575         dt += rolloverTime;
15576       }
15577       ctime1 += dt;
15578     }
15579     else
15580     {
15581       indexB++;
15582 
15583       time2_prev = time2;
15584       if( B->isReal )
15585         time2 = B->data[timeColumnB][indexB];
15586       else
15587         time2 = B->cplx[timeColumnB][indexB].re;
15588 
15589       MTX_static_round_value( &time2, precision );
15590       dt = time2 - time2_prev;
15591       if( dt < 0.0 )
15592       {
15593         if( rolloverTime == 0.0 )
15594           break; // rollovers not allowed
15595         dt += rolloverTime;
15596       }
15597       ctime2 += dt;
15598     }
15599   }
15600 
15601   // special case
15602   if( index == 0 )
15603   {
15604     MTX_Free( A );
15605     MTX_Free( B );
15606     return TRUE;
15607   }
15608 
15609   // redimension appropriately
15610   if( !MTX_Redim( A, index, A->ncols ) )
15611   {
15612     MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
15613     return FALSE;
15614   }
15615   if( !MTX_Redim( B, index, B->ncols ) )
15616   {
15617     MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
15618     return FALSE;
15619   }
15620 
15621   return TRUE;
15622 }
15623 
15624 BOOL MTX_Interpolate(
15625                      MTX *A, //!< The matrix with interpolation times
15626                      const unsigned timeColumnA, //!< The zero based column index for matrix A
15627                      MTX *B, //!< The matrix to be interpolated
15628                      const unsigned timeColumnB, //!< The zero based column index for matrix B
15629                      const double maxInterpolationInterval, //!< The largest interpolation interval allowed
15630                      const double rolloverTime )//!< The rollover time, e.g. 60 s for minute based timing, 0.0 means rollovers not allowed
15631 {
15632   unsigned j = 0;
15633 
15634   unsigned index = 0,
15635     indexA = 0,
15636     indexB = 0;
15637 
15638   double time = 0.0,
15639     prev = 0.0,
15640     next = 0.0,
15641     interval = 0.0,
15642     slope = 0.0,
15643     slope_im = 0.0;
15644 
15645   indexA = 0;
15646   indexB = 1;
15647   while( indexA < A->nrows && indexB < B->nrows )
15648   {
15649     if( A->isReal )
15650       time = A->data[timeColumnA][indexA];
15651     else
15652       time = A->cplx[timeColumnA][indexA].re;
15653 
15654     if( B->isReal )
15655       prev = B->data[timeColumnB][indexB-1];
15656     else
15657       prev = B->cplx[timeColumnB][indexB-1].re;
15658 
15659     if( B->isReal )
15660       next = B->data[timeColumnB][indexB];
15661     else
15662       next = B->cplx[timeColumnB][indexB].re;
15663 
15664     interval = next - prev;
15665     if( interval < 0 ) // a rollover occurred
15666     {
15667       if( rolloverTime == 0.0 )
15668         break;
15669       interval += rolloverTime;
15670       next += rolloverTime;
15671     }
15672 
15673     if( time >= prev &&
15674       time <= next )
15675     {
15676       if( interval > maxInterpolationInterval )
15677       {
15678         indexB++;
15679         continue;
15680       }
15681 
15682       if( index != indexA )
15683       {
15684         if( A->isReal )
15685         {
15686           A->data[timeColumnA][index] = time;
15687         }
15688         else
15689         {
15690           A->cplx[timeColumnA][index].re = time;
15691         }
15692 
15693         // copy row to other A matrix
15694         for( j = 0; j < A->ncols; j++ )
15695         {
15696           if( A->isReal )
15697           {
15698             A->data[j][index] = A->data[j][indexA];
15699           }
15700           else
15701           {
15702             A->cplx[j][index].re = A->cplx[j][indexA].re;
15703             A->cplx[j][index].im = A->cplx[j][indexA].im;
15704           }
15705         }
15706       }
15707 
15708       // perform the interpolation
15709       for( j = 0; j < B->ncols; j++ )
15710       {
15711         if( j == timeColumnB )
15712         {
15713           if( B->isReal )
15714             B->data[timeColumnB][index] = time;
15715           else
15716             B->cplx[timeColumnB][index].re = time;
15717 
15718           continue;
15719         }
15720         if( B->isReal )
15721         {
15722           slope = (B->data[j][indexB] - B->data[j][indexB-1]) / interval;
15723           B->data[j][index] = slope * (time-prev) + B->data[j][indexB-1];
15724         }
15725         else
15726         {
15727           slope = (B->cplx[j][indexB].re - B->cplx[j][indexB-1].re) / interval;
15728           slope_im = (B->cplx[j][indexB].im - B->cplx[j][indexB-1].im) / interval;
15729 
15730           B->cplx[j][index].re = slope * (time-prev) + B->cplx[j][indexB-1].re;
15731           B->cplx[j][index].im = slope_im * (time-prev) + B->cplx[j][indexB-1].im;
15732         }
15733       }
15734       index++;
15735       indexA++;
15736       indexB++;
15737       continue;
15738     }
15739 
15740     if( time < prev )
15741       indexA++;
15742     else if( time > next )
15743       indexB++;
15744   }
15745   if( !MTX_Redim( A, index, A->ncols ) )
15746   {
15747     MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
15748     return FALSE;
15749   }
15750   if( !MTX_Redim( B, index, B->ncols ) )
15751   {
15752     MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
15753     return FALSE;
15754   }
15755 
15756   return TRUE;
15757 }
15758 
15759 
15760 BOOL MTX_InvertInPlaceClosedForm( MTX *M )
15761 {
15762   unsigned n;
15763   double dtmp;
15764   
15765   if( MTX_isNull( M ) )
15766   {
15767     MTX_ERROR_MSG( "NULL Matrix" );
15768     return FALSE;
15769   }
15770   if( !MTX_isSquare( M ) )
15771   {
15772     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
15773     return FALSE;
15774   }
15775   n = M->nrows;
15776   if( n > 3 )
15777   {
15778     MTX_ERROR_MSG( "if( M->nrows > 3 )" );
15779     return FALSE;
15780   }  
15781 
15782   if( M->isReal )
15783   {
15784     ////
15785     // quick special cases, (closed forms)
15786     // 1x1
15787     if( n == 1 )
15788     {
15789       // Note: No divide by zero check.
15790       M->data[0][0] = 1.0/M->data[0][0];
15791       return TRUE;
15792     }
15793     // 2x2
15794     if( n == 2 )
15795     {
15796       // A = [a b; c d]
15797       // A^-1 = 1.0/(ad-bc) * [d -b; -c a]
15798       double invdet;
15799       invdet = M->data[0][0] * M->data[1][1] - M->data[1][0] * M->data[0][1];
15800       
15801       // Note: No divide by zero check.
15802       invdet = 1.0/invdet;
15803 
15804       dtmp = M->data[0][0];
15805       M->data[0][0] = invdet * M->data[1][1];
15806       M->data[1][1] = invdet * dtmp;
15807       M->data[1][0] *= -invdet;
15808       M->data[0][1] *= -invdet;
15809 
15810       return TRUE;
15811     }
15812     // 3x3
15813     if( n == 3 )
15814     {
15815       // M = [r s t;
15816       // u v w;
15817       // x y z]
15818       //
15819       // det(M) = r(vz-yw) - s(uz-xw) + t(uy-xv)
15820       // det(M) = r(vz-yw) + s(xw-uz) + t(uy-xv)
15821       //
15822       // A = [a11 a12 a13;
15823       // a21 a22 a23;
15824       // a31 a32 a33];
15825       //
15826       // a11 = vz-yw a12 = ty-zs a13 = sw-vt
15827       // a21 = wx-uz a22 = rz-xt a23 = ut-rw
15828       // a31 = uy-xv a32 = xs-ry a33 = rv-us
15829       //
15830       // inv(M) = 1/det(M) * A
15831       double invdet;
15832       double r,s,t,u,v,w,x,y,z; // elements of original M for ease of use
15833       double vzyw; // redudant shared calculations
15834       double xwuz; // redudant shared calculations
15835       double uyxv; // redudant shared calculations
15836 
15837       r = M->data[0][0]; s = M->data[1][0]; t = M->data[2][0];
15838       u = M->data[0][1]; v = M->data[1][1]; w = M->data[2][1];
15839       x = M->data[0][2]; y = M->data[1][2]; z = M->data[2][2];
15840 
15841       // shared calculations
15842       vzyw = v*z - y*w;
15843       xwuz = x*w - u*z;
15844       uyxv = u*y - x*v;
15845 
15846       invdet = r*vzyw + s*xwuz + t*uyxv;
15847 
15848       // Note: No divide by zero check.
15849       invdet = 1.0/invdet;
15850 
15851       M->data[0][0] = invdet*vzyw; M->data[1][0] = invdet*(t*y-z*s); M->data[2][0] = invdet*(s*w-v*t);
15852       M->data[0][1] = invdet*xwuz; M->data[1][1] = invdet*(r*z-x*t); M->data[2][1] = invdet*(u*t-r*w);
15853       M->data[0][2] = invdet*uyxv; M->data[1][2] = invdet*(x*s-r*y); M->data[2][2] = invdet*(r*v-u*s);
15854 
15855       return TRUE;
15856     }
15857   }
15858   else
15859   {
15860     ////
15861     // quick special cases, (closed forms)
15862     // 1x1
15863     if( n == 1 )
15864     {
15865       // Note: No divide by zero check.
15866       dtmp = M->cplx[0][0].re*M->cplx[0][0].re + M->cplx[0][0].im*M->cplx[0][0].im;
15867       M->cplx[0][0].re = M->cplx[0][0].re / dtmp;
15868       M->cplx[0][0].im = -M->cplx[0][0].im / dtmp;
15869       return TRUE;
15870     }
15871     // 2x2
15872     if( n == 2 )
15873     {
15874       // A = [a b; c d]
15875       // A^-1 = 1.0/(ad-bc) * [d -b; -c a]
15876 
15877       stComplex invdet; // complex inverse determinant
15878       stComplex tmpcplx;
15879 
15880       // compute 1/det(M)
15881       if( !MTX_Det( M, &tmpcplx.re, &tmpcplx.im ) )
15882       {
15883         MTX_ERROR_MSG( "MTX_Det returned FALSE." );
15884         return FALSE;
15885       }
15886       // Note: No divide by zero check.
15887       dtmp = tmpcplx.re*tmpcplx.re + tmpcplx.im*tmpcplx.im;
15888       invdet.re = tmpcplx.re / dtmp;
15889       invdet.im = -tmpcplx.im / dtmp;
15890 
15891       // A = [d -b; -c a]
15892       tmpcplx.re = M->cplx[0][0].re;
15893       tmpcplx.im = M->cplx[0][0].im;
15894       M->cplx[0][0].re = M->cplx[1][1].re;
15895       M->cplx[0][0].im = M->cplx[1][1].im;
15896       M->cplx[1][1].re = tmpcplx.re;
15897       M->cplx[1][1].re = tmpcplx.im;
15898       M->cplx[1][0].re *= -1.0;
15899       M->cplx[1][0].im *= -1.0;
15900       M->cplx[0][1].re *= -1.0;
15901       M->cplx[0][1].im *= -1.0;
15902 
15903       // then A *= invdet
15904       if( !MTX_Multiply_ScalarComplex( M, invdet.re, invdet.im ) )
15905       {
15906         MTX_ERROR_MSG( "MTX_Multiply_ScalarComplex returned FALSE." );
15907         return FALSE;
15908       }
15909 
15910       return TRUE;
15911     }
15912     // 3x3
15913     if( n == 3 )
15914     {
15915       // M = [r s t;
15916       // u v w;
15917       // x y z]
15918       //
15919       // det(M) = r(vz-yw) - s(uz-xw) + t(uy-xv)
15920       // det(M) = r(vz-yw) + s(xw-uz) + t(uy-xv)
15921       //
15922       // A = [a11 a12 a13;
15923       // a21 a22 a23;
15924       // a31 a32 a33];
15925       //
15926       // a11 = vz-yw a12 = ty-zs a13 = sw-vt
15927       // a21 = wx-uz a22 = rz-xt a23 = ut-rw
15928       // a31 = uy-xv a32 = xs-ry a33 = rv-us
15929       //
15930       // inv(M) = 1/det(M) * A
15931       stComplex invdet;
15932       stComplex r,s,t,u,v,w,x,y,z; // elements of original M for ease of use
15933       stComplex vzyw; // redudant shared calculations
15934       stComplex xwuz; // redudant shared calculations
15935       stComplex uyxv; // redudant shared calculations
15936       stComplex cplxA; // tmp cplx
15937       stComplex cplxB; // tmp cplx
15938 
15939       r.re = M->cplx[0][0].re; s.re = M->cplx[1][0].re; t.re = M->cplx[2][0].re;
15940       u.re = M->cplx[0][1].re; v.re = M->cplx[1][1].re; w.re = M->cplx[2][1].re;
15941       x.re = M->cplx[0][2].re; y.re = M->cplx[1][2].re; z.re = M->cplx[2][2].re;
15942 
15943       r.im = M->cplx[0][0].im; s.im = M->cplx[1][0].im; t.im = M->cplx[2][0].im;
15944       u.im = M->cplx[0][1].im; v.im = M->cplx[1][1].im; w.im = M->cplx[2][1].im;
15945       x.im = M->cplx[0][2].im; y.im = M->cplx[1][2].im; z.im = M->cplx[2][2].im;
15946 
15947       // shared calculations
15948 
15949       // vzyw
15950       MTX_static_quick_complex_mult_ab( &v.re, &v.im, &z.re, &z.im, &cplxA.re, &cplxA.im ); // vz
15951       MTX_static_quick_complex_mult_ab( &y.re, &y.im, &w.re, &w.im, &cplxB.re, &cplxB.im ); // yw
15952       vzyw.re = cplxA.re - cplxB.re;
15953       vzyw.im = cplxA.im - cplxB.im;
15954 
15955       // xwuz
15956       MTX_static_quick_complex_mult_ab( &x.re, &x.im, &w.re, &w.im, &cplxA.re, &cplxA.im ); // xw
15957       MTX_static_quick_complex_mult_ab( &u.re, &u.im, &z.re, &z.im, &cplxB.re, &cplxB.im ); // uz
15958       xwuz.re = cplxA.re - cplxB.re;
15959       xwuz.im = cplxA.im - cplxB.im;
15960 
15961       // uyxv
15962       MTX_static_quick_complex_mult_ab( &u.re, &u.im, &y.re, &y.im, &cplxA.re, &cplxA.im ); // uy
15963       MTX_static_quick_complex_mult_ab( &x.re, &x.im, &v.re, &v.im, &cplxB.re, &cplxB.im ); // xv
15964       uyxv.re = cplxA.re - cplxB.re;
15965       uyxv.im = cplxA.im - cplxB.im;
15966 
15967       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &vzyw.re, &vzyw.im, &cplxA.re, &cplxA.im ); // r*vzyw
15968       MTX_static_quick_complex_mult_ab( &s.re, &s.im, &xwuz.re, &xwuz.im, &cplxB.re, &cplxB.im ); // s*xwuz
15969       MTX_static_quick_complex_mult_ab( &t.re, &t.im, &uyxv.re, &uyxv.im, &invdet.re, &invdet.im ); // invdet = t*uyxv
15970 
15971       // invdet += r*vzyw + s*xwuz;
15972       invdet.re += cplxA.re + cplxB.re;
15973       invdet.im += cplxA.im + cplxB.im;
15974       // Note: No divide by zero check.
15975       // compute invdet = 1/det
15976       dtmp = invdet.re*invdet.re + invdet.im*invdet.im;
15977       invdet.re = invdet.re/dtmp;
15978       invdet.im = -invdet.im/dtmp;
15979 
15980       M->cplx[0][0].re = vzyw.re;
15981       M->cplx[0][1].re = xwuz.re;
15982       M->cplx[0][2].re = uyxv.re;
15983 
15984       M->cplx[0][0].im = vzyw.im;
15985       M->cplx[0][1].im = xwuz.im;
15986       M->cplx[0][2].im = uyxv.im;
15987 
15988       // (t*y-z*s);
15989       MTX_static_quick_complex_mult_ab( &t.re, &t.im, &y.re, &y.im, &cplxA.re, &cplxA.im ); // ty
15990       MTX_static_quick_complex_mult_ab( &z.re, &z.im, &s.re, &s.im, &cplxB.re, &cplxB.im ); // zs
15991       M->cplx[1][0].re = cplxA.re - cplxB.re;
15992       M->cplx[1][0].im = cplxA.im - cplxB.im;
15993 
15994       // (r*z-x*t);
15995       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &z.re, &z.im, &cplxA.re, &cplxA.im ); // rz
15996       MTX_static_quick_complex_mult_ab( &x.re, &x.im, &t.re, &t.im, &cplxB.re, &cplxB.im ); // xt
15997       M->cplx[1][1].re = cplxA.re - cplxB.re;
15998       M->cplx[1][1].im = cplxA.im - cplxB.im;
15999 
16000       // (x*s-r*y);
16001       MTX_static_quick_complex_mult_ab( &x.re, &x.im, &s.re, &s.im, &cplxA.re, &cplxA.im ); // xs
16002       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &y.re, &y.im, &cplxB.re, &cplxB.im ); // ry
16003       M->cplx[1][2].re = cplxA.re - cplxB.re;
16004       M->cplx[1][2].im = cplxA.im - cplxB.im;
16005 
16006       // (s*w-v*t);
16007       MTX_static_quick_complex_mult_ab( &s.re, &s.im, &w.re, &w.im, &cplxA.re, &cplxA.im ); // sw
16008       MTX_static_quick_complex_mult_ab( &v.re, &v.im, &t.re, &t.im, &cplxB.re, &cplxB.im ); // vt
16009       M->cplx[2][0].re = cplxA.re - cplxB.re;
16010       M->cplx[2][0].im = cplxA.im - cplxB.im;
16011 
16012       // (u*t-r*w);
16013       MTX_static_quick_complex_mult_ab( &u.re, &u.im, &t.re, &t.im, &cplxA.re, &cplxA.im ); // ut
16014       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &w.re, &w.im, &cplxB.re, &cplxB.im ); // rw
16015       M->cplx[2][1].re = cplxA.re - cplxB.re;
16016       M->cplx[2][1].im = cplxA.im - cplxB.im;
16017 
16018       // (r*v-u*s);
16019       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &v.re, &v.im, &cplxA.re, &cplxA.im ); // rv
16020       MTX_static_quick_complex_mult_ab( &u.re, &u.im, &s.re, &s.im, &cplxB.re, &cplxB.im ); // us
16021       M->cplx[2][2].re = cplxA.re - cplxB.re;
16022       M->cplx[2][2].im = cplxA.im - cplxB.im;
16023 
16024       if( !MTX_Multiply_ScalarComplex( M, invdet.re, invdet.im ) )
16025       {
16026         MTX_ERROR_MSG( "MTX_Multiply_ScalarComplex returned FALSE." );
16027         return FALSE;
16028       }
16029 
16030       return TRUE;
16031     }
16032   }
16033 
16034   MTX_ERROR_MSG( "Unexpected." );
16035   return FALSE;
16036 }
16037 
16038 
16039 BOOL MTX_InvertClosedForm( const MTX *src, MTX *dst )
16040 {
16041   unsigned n;
16042   double dtmp;
16043 
16044   if( dst == NULL )
16045   {
16046     MTX_ERROR_MSG( "NULL input matrix." );
16047     return FALSE;
16048   }
16049   if( MTX_isNull( src ) )
16050   {
16051     MTX_ERROR_MSG( "NULL Matrix" );
16052     return FALSE;
16053   }
16054   n = src->nrows;
16055   if( !MTX_isSquare( src ) )
16056   {
16057     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
16058     return FALSE;
16059   }
16060   if( src->nrows > 3 )
16061   {
16062     MTX_ERROR_MSG( "if( src->nrows > 3 )" );
16063     return FALSE;
16064   }
16065   if( !MTX_Malloc( dst, src->nrows, src->ncols, src->isReal ) )
16066   {
16067     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
16068     return FALSE;
16069   }
16070 
16071   if( src->isReal )
16072   {
16073     ////
16074     // quick special cases, (closed forms)
16075     // 1x1
16076     if( n == 1 )
16077     {
16078       // Note: No divide by zero check.
16079       dst->data[0][0] = 1.0/src->data[0][0];
16080       return TRUE;
16081     }
16082     // 2x2
16083     if( n == 2 )
16084     {
16085       // A = [a b; c d]
16086       // A^-1 = 1.0/(ad-bc) * [d -b; -c a]
16087 
16088       double invdet;
16089       invdet = src->data[0][0] * src->data[1][1] - src->data[1][0] * src->data[0][1];
16090       
16091       // Note: No divide by zero check.
16092       invdet = 1.0/invdet;
16093 
16094       dst->data[0][0] =  invdet * src->data[1][1];
16095       dst->data[1][1] =  invdet * src->data[0][0];
16096       dst->data[1][0] = -invdet * src->data[1][0];
16097       dst->data[0][1] = -invdet * src->data[0][1];
16098 
16099       return TRUE;
16100     }
16101     // 3x3
16102     if( n == 3 )
16103     {
16104       // M = [r s t;
16105       // u v w;
16106       // x y z]
16107       //
16108       // det(M) = r(vz-yw) - s(uz-xw) + t(uy-xv)
16109       // det(M) = r(vz-yw) + s(xw-uz) + t(uy-xv)
16110       //
16111       // A = [a11 a12 a13;
16112       // a21 a22 a23;
16113       // a31 a32 a33];
16114       //
16115       // a11 = vz-yw a12 = ty-zs a13 = sw-vt
16116       // a21 = wx-uz a22 = rz-xt a23 = ut-rw
16117       // a31 = uy-xv a32 = xs-ry a33 = rv-us
16118       //
16119       // inv(M) = 1/det(M) * A
16120       double invdet;
16121       double r,s,t,u,v,w,x,y,z; // elements of original M for ease of use
16122       double vzyw; // redudant shared calculations
16123       double xwuz; // redudant shared calculations
16124       double uyxv; // redudant shared calculations
16125 
16126       r = src->data[0][0]; s = src->data[1][0]; t = src->data[2][0];
16127       u = src->data[0][1]; v = src->data[1][1]; w = src->data[2][1];
16128       x = src->data[0][2]; y = src->data[1][2]; z = src->data[2][2];
16129 
16130       // shared calculations
16131       vzyw = v*z - y*w;
16132       xwuz = x*w - u*z;
16133       uyxv = u*y - x*v;
16134 
16135       invdet = r*vzyw + s*xwuz + t*uyxv;
16136 
16137       // Note: No divide by zero check.
16138       invdet = 1.0/invdet;
16139 
16140       dst->data[0][0] = invdet*vzyw; dst->data[1][0] = invdet*(t*y-z*s); dst->data[2][0] = invdet*(s*w-v*t);
16141       dst->data[0][1] = invdet*xwuz; dst->data[1][1] = invdet*(r*z-x*t); dst->data[2][1] = invdet*(u*t-r*w);
16142       dst->data[0][2] = invdet*uyxv; dst->data[1][2] = invdet*(x*s-r*y); dst->data[2][2] = invdet*(r*v-u*s);
16143 
16144       return TRUE;
16145     }
16146   }
16147   else
16148   {
16149     ////
16150     // quick special cases, (closed forms)
16151     // 1x1
16152     if( n == 1 )
16153     {
16154       // Note: No divide by zero check.
16155       dtmp = src->cplx[0][0].re*src->cplx[0][0].re + src->cplx[0][0].im*src->cplx[0][0].im;
16156       dst->cplx[0][0].re = src->cplx[0][0].re / dtmp;
16157       dst->cplx[0][0].im = -src->cplx[0][0].im / dtmp;
16158       return TRUE;
16159     }
16160     // 2x2
16161     if( n == 2 )
16162     {
16163       // A = [a b; c d]
16164       // A^-1 = 1.0/(ad-bc) * [d -b; -c a]
16165 
16166       stComplex invdet; // complex inverse determinant
16167       stComplex tmpcplx;
16168 
16169       // compute 1/det(src)
16170       if( !MTX_Det( src, &tmpcplx.re, &tmpcplx.im ) )
16171       {
16172         MTX_ERROR_MSG( "MTX_Det returned FALSE." );
16173         return FALSE;
16174       }
16175       // Note: No divide by zero check.
16176       dtmp = tmpcplx.re*tmpcplx.re + tmpcplx.im*tmpcplx.im;
16177       invdet.re = tmpcplx.re / dtmp;
16178       invdet.im = -tmpcplx.im / dtmp;
16179 
16180       // A = [d -b; -c a]
16181       dst->cplx[0][0].re =  src->cplx[1][1].re;
16182       dst->cplx[0][0].im =  src->cplx[1][1].im;
16183       dst->cplx[1][1].re =  src->cplx[0][0].re;
16184       dst->cplx[1][1].re =  src->cplx[0][0].im;
16185       dst->cplx[1][0].re = -src->cplx[1][0].re;
16186       dst->cplx[1][0].im = -src->cplx[1][0].im;
16187       dst->cplx[0][1].re = -src->cplx[0][1].re;
16188       dst->cplx[0][1].im = -src->cplx[0][1].im;
16189 
16190       // then A *= invdet
16191       if( !MTX_Multiply_ScalarComplex( dst, invdet.re, invdet.im ) )
16192       {
16193         MTX_ERROR_MSG( "MTX_Multiply_ScalarComplex returned FALSE." );
16194         return FALSE;
16195       }
16196 
16197       return TRUE;
16198     }
16199     // 3x3
16200     if( n == 3 )
16201     {
16202       // M = [r s t;
16203       // u v w;
16204       // x y z]
16205       //
16206       // det(M) = r(vz-yw) - s(uz-xw) + t(uy-xv)
16207       // det(M) = r(vz-yw) + s(xw-uz) + t(uy-xv)
16208       //
16209       // A = [a11 a12 a13;
16210       // a21 a22 a23;
16211       // a31 a32 a33];
16212       //
16213       // a11 = vz-yw a12 = ty-zs a13 = sw-vt
16214       // a21 = wx-uz a22 = rz-xt a23 = ut-rw
16215       // a31 = uy-xv a32 = xs-ry a33 = rv-us
16216       //
16217       // inv(src) = 1/det(src) * A
16218       stComplex invdet;
16219       stComplex r,s,t,u,v,w,x,y,z; // elements of original M for ease of use
16220       stComplex vzyw; // redudant shared calculations
16221       stComplex xwuz; // redudant shared calculations
16222       stComplex uyxv; // redudant shared calculations
16223       stComplex cplxA; // tmp cplx
16224       stComplex cplxB; // tmp cplx
16225 
16226       r.re = src->cplx[0][0].re; s.re = src->cplx[1][0].re; t.re = src->cplx[2][0].re;
16227       u.re = src->cplx[0][1].re; v.re = src->cplx[1][1].re; w.re = src->cplx[2][1].re;
16228       x.re = src->cplx[0][2].re; y.re = src->cplx[1][2].re; z.re = src->cplx[2][2].re;
16229 
16230       r.im = src->cplx[0][0].im; s.im = src->cplx[1][0].im; t.im = src->cplx[2][0].im;
16231       u.im = src->cplx[0][1].im; v.im = src->cplx[1][1].im; w.im = src->cplx[2][1].im;
16232       x.im = src->cplx[0][2].im; y.im = src->cplx[1][2].im; z.im = src->cplx[2][2].im;
16233 
16234       // shared calculations
16235 
16236       // vzyw
16237       MTX_static_quick_complex_mult_ab( &v.re, &v.im, &z.re, &z.im, &cplxA.re, &cplxA.im ); // vz
16238       MTX_static_quick_complex_mult_ab( &y.re, &y.im, &w.re, &w.im, &cplxB.re, &cplxB.im ); // yw
16239       vzyw.re = cplxA.re - cplxB.re;
16240       vzyw.im = cplxA.im - cplxB.im;
16241 
16242       // xwuz
16243       MTX_static_quick_complex_mult_ab( &x.re, &x.im, &w.re, &w.im, &cplxA.re, &cplxA.im ); // xw
16244       MTX_static_quick_complex_mult_ab( &u.re, &u.im, &z.re, &z.im, &cplxB.re, &cplxB.im ); // uz
16245       xwuz.re = cplxA.re - cplxB.re;
16246       xwuz.im = cplxA.im - cplxB.im;
16247 
16248       // uyxv
16249       MTX_static_quick_complex_mult_ab( &u.re, &u.im, &y.re, &y.im, &cplxA.re, &cplxA.im ); // uy
16250       MTX_static_quick_complex_mult_ab( &x.re, &x.im, &v.re, &v.im, &cplxB.re, &cplxB.im ); // xv
16251       uyxv.re = cplxA.re - cplxB.re;
16252       uyxv.im = cplxA.im - cplxB.im;
16253 
16254       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &vzyw.re, &vzyw.im, &cplxA.re, &cplxA.im ); // r*vzyw
16255       MTX_static_quick_complex_mult_ab( &s.re, &s.im, &xwuz.re, &xwuz.im, &cplxB.re, &cplxB.im ); // s*xwuz
16256       MTX_static_quick_complex_mult_ab( &t.re, &t.im, &uyxv.re, &uyxv.im, &invdet.re, &invdet.im ); // invdet = t*uyxv
16257 
16258       // invdet += r*vzyw + s*xwuz;
16259       invdet.re += cplxA.re + cplxB.re;
16260       invdet.im += cplxA.im + cplxB.im;
16261       // Note: No divide by zero check.
16262       // compute invdet = 1/det
16263       dtmp = invdet.re*invdet.re + invdet.im*invdet.im;
16264       invdet.re = invdet.re/dtmp;
16265       invdet.im = -invdet.im/dtmp;
16266 
16267       dst->cplx[0][0].re = vzyw.re;
16268       dst->cplx[0][1].re = xwuz.re;
16269       dst->cplx[0][2].re = uyxv.re;
16270 
16271       dst->cplx[0][0].im = vzyw.im;
16272       dst->cplx[0][1].im = xwuz.im;
16273       dst->cplx[0][2].im = uyxv.im;
16274 
16275       // (t*y-z*s);
16276       MTX_static_quick_complex_mult_ab( &t.re, &t.im, &y.re, &y.im, &cplxA.re, &cplxA.im ); // ty
16277       MTX_static_quick_complex_mult_ab( &z.re, &z.im, &s.re, &s.im, &cplxB.re, &cplxB.im ); // zs
16278       dst->cplx[1][0].re = cplxA.re - cplxB.re;
16279       dst->cplx[1][0].im = cplxA.im - cplxB.im;
16280 
16281       // (r*z-x*t);
16282       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &z.re, &z.im, &cplxA.re, &cplxA.im ); // rz
16283       MTX_static_quick_complex_mult_ab( &x.re, &x.im, &t.re, &t.im, &cplxB.re, &cplxB.im ); // xt
16284       dst->cplx[1][1].re = cplxA.re - cplxB.re;
16285       dst->cplx[1][1].im = cplxA.im - cplxB.im;
16286 
16287       // (x*s-r*y);
16288       MTX_static_quick_complex_mult_ab( &x.re, &x.im, &s.re, &s.im, &cplxA.re, &cplxA.im ); // xs
16289       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &y.re, &y.im, &cplxB.re, &cplxB.im ); // ry
16290       dst->cplx[1][2].re = cplxA.re - cplxB.re;
16291       dst->cplx[1][2].im = cplxA.im - cplxB.im;
16292 
16293       // (s*w-v*t);
16294       MTX_static_quick_complex_mult_ab( &s.re, &s.im, &w.re, &w.im, &cplxA.re, &cplxA.im ); // sw
16295       MTX_static_quick_complex_mult_ab( &v.re, &v.im, &t.re, &t.im, &cplxB.re, &cplxB.im ); // vt
16296       dst->cplx[2][0].re = cplxA.re - cplxB.re;
16297       dst->cplx[2][0].im = cplxA.im - cplxB.im;
16298 
16299       // (u*t-r*w);
16300       MTX_static_quick_complex_mult_ab( &u.re, &u.im, &t.re, &t.im, &cplxA.re, &cplxA.im ); // ut
16301       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &w.re, &w.im, &cplxB.re, &cplxB.im ); // rw
16302       dst->cplx[2][1].re = cplxA.re - cplxB.re;
16303       dst->cplx[2][1].im = cplxA.im - cplxB.im;
16304 
16305       // (r*v-u*s);
16306       MTX_static_quick_complex_mult_ab( &r.re, &r.im, &v.re, &v.im, &cplxA.re, &cplxA.im ); // rv
16307       MTX_static_quick_complex_mult_ab( &u.re, &u.im, &s.re, &s.im, &cplxB.re, &cplxB.im ); // us
16308       dst->cplx[2][2].re = cplxA.re - cplxB.re;
16309       dst->cplx[2][2].im = cplxA.im - cplxB.im;
16310 
16311       if( !MTX_Multiply_ScalarComplex( dst, invdet.re, invdet.im ) )
16312       {
16313         MTX_ERROR_MSG( "MTX_Multiply_ScalarComplex returned FALSE." );
16314         return FALSE;
16315       }
16316 
16317       return TRUE;
16318     }
16319   }
16320 
16321   MTX_ERROR_MSG( "Unexpected." );
16322   return FALSE;
16323 }
16324 
16325 
16326 
16327 
16328 
16329 BOOL MTX_InvertInPlace( MTX *M )
16330 {
16331   unsigned i = 0;
16332   unsigned j = 0;
16333   unsigned k = 0;
16334   BOOL isPositiveDefinite = TRUE;
16335   unsigned n;
16336   double **ptrptrData;
16337   double val;
16338   double dtmp;
16339   double maxdif; // the maximum symmetric difference 
16340   MTX copyM;  
16341 
16342   // always init copyM
16343   MTX_Init( &copyM );
16344 
16345   if( MTX_isNull( M ) )
16346   {
16347     MTX_ERROR_MSG( "NULL Matrix" );
16348     return FALSE;
16349   }
16350   n = M->nrows;
16351   if( !MTX_isSquare( M ) )
16352   {
16353     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
16354     return FALSE;
16355   }
16356   if( n == 0 )
16357   {
16358     MTX_ERROR_MSG( "if( n == 0 )" );
16359     return FALSE;
16360   }
16361 
16362   // use the closed form solutions for dimensions smaller than 4x4
16363   if( n < 4 )
16364   {
16365     return MTX_InvertInPlaceClosedForm( M );
16366   }
16367 
16368   if( M->isReal )
16369   {    
16370     // check diagonal for positive definiteness
16371     for( j = 0; j < n; j++ )
16372     {
16373       // checks for diagonal elements at or less than zero
16374       if( M->data[j][j] <= 0.0 )
16375       {
16376         isPositiveDefinite = FALSE;
16377         break;
16378       }
16379     }
16380     if( !isPositiveDefinite )
16381     {
16382       // use inplace robust inversion
16383       return MTX_InvertInPlaceRobust( M );
16384     }
16385 
16386     // check symmetric
16387     for( i = 0; i < n; i++ )
16388     {
16389       for( j = i+1; j < n; j++ )
16390       {
16391         val = M->data[j][i];
16392         maxdif = fabs( val )*1e-14;
16393         // Why 1e-14? it works well for most matrices expected.
16394         // Worst case is that some positive definite matrices will be inverted
16395         // using the robust algorithm.
16396 
16397         dtmp = fabs( val - M->data[i][j] );
16398         if( dtmp > maxdif )
16399         {
16400           // Why 1e-14? it works well for most matrices expected.
16401           // Worst case is that some positive definite matrices will be inverted
16402           // using the robust algorithm.
16403           isPositiveDefinite = FALSE;
16404           break;
16405         }
16406       }
16407       if( !isPositiveDefinite )
16408         break;
16409     }
16410     if( !isPositiveDefinite )
16411     {
16412       // use inplace robust inversion
16413       return MTX_InvertInPlaceRobust( M );
16414     }
16415 
16416     // make a copy to use in case robust inversion is needed
16417     if( !MTX_Copy( M, &copyM ) )
16418     {
16419       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
16420       MTX_Free( &copyM );
16421       return FALSE;
16422     }
16423 
16424     // Perform Choleski decomposition
16425     for( j = 0; j < n; j++ )
16426     {
16427       for( k = 0; k < j; k++ )
16428       {
16429         val = M->data[k][j];
16430         M->data[j][j] -= val * val;
16431       }
16432 
16433       val = M->data[j][j];
16434       if( val < 0.0 )
16435       {
16436         // use robust inversion on the copy
16437         if( !MTX_InvertInPlaceRobust( &copyM ) )
16438         {
16439           MTX_ERROR_MSG( "MTX_InvertInPlaceRobust returned FALSE." );
16440           MTX_Free(&copyM);
16441           return FALSE;
16442         }
16443 
16444         // switching the pointers rather than copying the result
16445         ptrptrData = M->data;
16446         M->data = copyM.data;
16447         copyM.data = ptrptrData;
16448         MTX_Free( &copyM );
16449         return TRUE;
16450       }
16451 
16452       M->data[j][j] = sqrt( val );
16453 
16454       for( i = j + 1; i < n; i++ )
16455       {
16456         for( k = 0; k < j; k++ )
16457           M->data[j][i] -= M->data[k][i] * M->data[k][j];
16458 
16459         val = M->data[j][j];
16460         if( fabs(val) < 1.0E-20 )
16461         {
16462           // use Robust Inversion
16463           if( !MTX_InvertInPlaceRobust( &copyM ) )
16464           {
16465             MTX_ERROR_MSG( "MTX_InvertInPlaceRobust returned FALSE." );
16466             MTX_Free(&copyM);
16467             return FALSE;
16468           }
16469 
16470           // switching the pointers rather than copying the result
16471           ptrptrData = M->data;
16472           M->data = copyM.data;
16473           copyM.data = ptrptrData;
16474           MTX_Free( &copyM );
16475           return TRUE;
16476         }
16477 
16478         M->data[j][i] /= val;
16479       }
16480     }
16481 
16482     // inversion of lower triangular matrix
16483     for( j = 0; j < n; j++ )
16484     {
16485       M->data[j][j] = 1.0 / M->data[j][j];
16486 
16487       for( i = j + 1; i < n; i++ )
16488       {
16489         M->data[j][i] *= -M->data[j][j] / M->data[i][i];
16490 
16491         val = M->data[i][i];
16492         for( k = j + 1; k < i; k++ )
16493           M->data[j][i] -= M->data[k][i] * M->data[j][k] / val;
16494       }
16495     }
16496 
16497     // construction of lower triangular inverse matrix
16498     for( j = 0; j < n; j++ )
16499     {
16500       for( i = j; i < n; i++ )
16501       {
16502         M->data[j][i] *= M->data[i][i];
16503 
16504         for( k = i + 1; k < n; k++ )
16505           M->data[j][i] += M->data[i][k] * M->data[j][k];
16506       }
16507     }
16508 
16509     // fill upper diagonal
16510     for( i = 1; i < n; i++ )
16511     {
16512       for( j = 0; j < i; j++ )
16513         M->data[i][j] = M->data[j][i];
16514     }
16515 
16516     MTX_Free(&copyM);
16517   }
16518   else
16519   {
16520     // use inplace robust inversion
16521     return MTX_InvertInPlaceRobust( M );
16522   }
16523   return TRUE;
16524 }
16525 
16526 
16527 
16528 BOOL MTX_Invert( const MTX *src, MTX *dst )
16529 {
16530   unsigned i = 0;
16531   unsigned j = 0;
16532   unsigned k = 0;
16533   BOOL isPositiveDefinite = TRUE;
16534   unsigned n;
16535   double val;
16536   double dtmp;
16537   double maxdif; // the maximum symmetric difference
16538   
16539   if( dst == NULL )
16540   {
16541     MTX_ERROR_MSG( "NULL input matrix." );
16542     return FALSE;
16543   }
16544   if( MTX_isNull( src ) )
16545   {
16546     MTX_ERROR_MSG( "NULL Matrix" );
16547     return FALSE;
16548   }
16549   n = src->nrows;
16550   if( !MTX_isSquare( src ) )
16551   {
16552     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
16553     return FALSE;
16554   }
16555   if( n == 0 )
16556   {
16557     MTX_ERROR_MSG( "if( n == 0 )" );
16558     return FALSE;
16559   }
16560   
16561   // use the closed form solutions for dimensions smaller than 4x4
16562   if( n < 4 )
16563   {
16564     return MTX_InvertClosedForm( src, dst );
16565   }
16566 
16567   // make dst a copy.
16568   if( !MTX_Copy( src, dst ) )
16569   {
16570     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
16571     return FALSE;
16572   }
16573 
16574   if( src->isReal )
16575   {
16576     // check diagonal for positive definiteness
16577     for( j = 0; j < n; j++ )
16578     {
16579       // checks for diagonal elements close to zero or less than zero
16580       if( src->data[j][j] <= 0.0 )
16581       {
16582         isPositiveDefinite = FALSE;
16583         break;
16584       }
16585     }
16586     if( !isPositiveDefinite )
16587     {
16588       // use inplace robust inversion      
16589       return MTX_InvertInPlaceRobust( dst );
16590     }
16591 
16592     // check symmetric
16593     for( i = 0; i < n; i++ )
16594     {
16595       for( j = i+1; j < n; j++ )
16596       {
16597         val = src->data[j][i];
16598         maxdif = fabs( val )*1e-14;
16599         // Why 1e-14? it works well for most matrices expected.
16600         // Worst case is that some positive definite matrices will be inverted
16601         // using the robust algorithm.
16602 
16603         dtmp = fabs( val - src->data[i][j] );
16604         if( dtmp > maxdif )
16605         {
16606           // Why 1e-14? it works well for most matrices expected.
16607           // Worst case is that some positive definite matrices will be inverted
16608           // using the robust algorithm.
16609           isPositiveDefinite = FALSE;
16610           break;
16611         }
16612       }
16613       if( !isPositiveDefinite )
16614         break;
16615     }
16616     if( !isPositiveDefinite )
16617     {
16618       // use inplace robust inversion
16619       return MTX_InvertInPlaceRobust( dst );
16620     }
16621 
16622     // Perform Choleski decomposition on dst inplace
16623     for( j = 0; j < n; j++ )
16624     {
16625       for( k = 0; k < j; k++ )
16626       {
16627         val = dst->data[k][j];
16628         dst->data[j][j] -= val*val;
16629       }
16630 
16631       val = dst->data[j][j];
16632       if( val < 0.0 )
16633       {
16634         // use robust inversion
16635         if( !MTX_Copy( src, dst ) )
16636         {
16637           MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
16638           return FALSE;
16639         }
16640         if( !MTX_InvertInPlaceRobust( dst ) )
16641         {
16642           MTX_ERROR_MSG( "MTX_InvertInPlaceRobust returned FALSE." );          
16643           return FALSE;
16644         }
16645         return TRUE;
16646       }
16647 
16648       dst->data[j][j] = sqrt( val );
16649 
16650       for( i = j + 1; i < n; i++ )
16651       {
16652         for( k = 0; k < j; k++ )
16653           dst->data[j][i] -= dst->data[k][i] * dst->data[k][j];
16654 
16655         val = dst->data[j][j];
16656         if( fabs(val) < 1.0E-20 )
16657         {
16658           // use Robust Inversion
16659           if( !MTX_Copy( src, dst ) )
16660           {
16661             MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
16662             return FALSE;
16663           }
16664           if( !MTX_InvertInPlaceRobust( dst ) )
16665           {
16666             MTX_ERROR_MSG( "MTX_InvertInPlaceRobust returned FALSE." );            
16667             return FALSE;
16668           }
16669           return TRUE;
16670         }
16671 
16672         dst->data[j][i] /= val;
16673       }
16674     }
16675 
16676     // inversion of lower triangular matrix
16677     for( j = 0; j < n; j++ )
16678     {
16679       dst->data[j][j] = 1.0 / dst->data[j][j];
16680 
16681       for( i = j + 1; i < n; i++ )
16682       {
16683         dst->data[j][i] *= -dst->data[j][j] / dst->data[i][i];
16684 
16685         val = dst->data[i][i];
16686         for( k = j + 1; k < i; k++ )
16687           dst->data[j][i] -= dst->data[k][i] * dst->data[j][k] / val;
16688       }
16689     }
16690 
16691     // construction of lower triangular inverse matrix
16692     for( j = 0; j < n; j++ )
16693     {
16694       for( i = j; i < n; i++ )
16695       {
16696         dst->data[j][i] *= dst->data[i][i];
16697 
16698         for( k = i + 1; k < n; k++ )
16699           dst->data[j][i] += dst->data[i][k] * dst->data[j][k];
16700       }
16701     }
16702 
16703     // fill upper diagonal
16704     for( i = 1; i < n; i++ )
16705     {
16706       for( j = 0; j < i; j++ )
16707         dst->data[i][j] = dst->data[j][i];
16708     }    
16709   }
16710   else
16711   {
16712     // use inplace robust inversion
16713     return MTX_InvertInPlaceRobust( dst );
16714   }
16715   return TRUE;
16716 }
16717 
16718 
16719 BOOL MTX_InvertInPlaceRobust( MTX *M )
16720 {
16721   unsigned i = 0;
16722   const unsigned n = M->nrows;
16723   BOOL isFullRank = FALSE;
16724   unsigned *index = NULL;
16725   MTX A; // nxn, M is nxn
16726   MTX ColumnI; // nx1
16727   MTX X; // nx1
16728 
16729   // make A a copy of this matrix
16730   // A will be factorized
16731   MTX_Init( &A);
16732 
16733   if( MTX_isNull( M ) )
16734   {
16735     MTX_ERROR_MSG( "NULL Matrix" );
16736     return FALSE;
16737   }
16738   if( !MTX_isSquare( M ) )
16739   {
16740     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
16741     return FALSE;
16742   }
16743   if( n == 0 )
16744   {
16745     MTX_ERROR_MSG( "if( n == 0 )" );
16746     return FALSE;
16747   }
16748 
16749   // use the closed form solutions for dimensions smaller than 4x4
16750   if( n < 4 )
16751   {
16752     return MTX_InvertInPlaceClosedForm( M );
16753   }
16754 
16755 
16756   if( !MTX_Copy( M, &A) )
16757   {
16758     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
16759     MTX_Free( &A );
16760     return FALSE;
16761   }
16762   
16763   index = (unsigned*)calloc( n, sizeof(unsigned) );
16764   if( !index )
16765   {
16766     MTX_ERROR_MSG( "calloc returned NULL." );
16767     MTX_Free( &A );
16768     return FALSE;
16769   }
16770 
16771   // need to get the index and Factorized A
16772   if( !MTX_static_Factorize( &isFullRank, n, index, &A ) )
16773   {
16774     MTX_ERROR_MSG( "MTX_static_Factorize returned FALSE." );
16775     MTX_Free( &A );
16776     if( index )
16777       free(index);
16778     return FALSE;
16779   }
16780   if( !isFullRank )
16781   {
16782     MTX_Free( &A );
16783     if( index )
16784       free(index);
16785     return FALSE;
16786   }
16787 
16788   MTX_Init( &ColumnI );
16789   MTX_Init( &X );
16790 
16791   // X is used to just point to data already
16792   // allocated in M so no need to call MTX_Free.
16793   X.nrows = n;
16794   X.ncols = 1;
16795 
16796   if( M->isReal )
16797   {
16798     X.isReal = TRUE;
16799     if( !MTX_Calloc( &ColumnI, n, 1, TRUE ) )
16800     {
16801       MTX_ERROR_MSG( "MTX_Calloc returned FALSE." );
16802       MTX_Free( &A );
16803       MTX_Free( &ColumnI );
16804       if(index)
16805         free(index);
16806       return FALSE;
16807     }
16808 
16809     for( i = 0; i < n; i++ )
16810     {
16811       // make X point to a data column in M
16812       X.data = &(M->data[i]);
16813 
16814       if( i != 0 )
16815         ColumnI.data[0][i-1] = 0.0;
16816       ColumnI.data[0][i] = 1.0;
16817 
16818       if( !MTX_static_SolveByGaussianElimination( &ColumnI, &X, &A, index ) )
16819       {
16820         MTX_ERROR_MSG( "MTX_static_SolveByGaussianElimination returned FALSE." );
16821         MTX_Free( &A );
16822         MTX_Free( &ColumnI );
16823         if(index)
16824           free(index);
16825         return FALSE;
16826       }
16827     }
16828   }
16829   else
16830   {
16831     X.isReal = FALSE;
16832     if( !MTX_Calloc( &ColumnI, n, 1, FALSE ) )
16833     {
16834       MTX_ERROR_MSG( "MTX_Calloc returned FALSE." );
16835       MTX_Free( &A );
16836       MTX_Free( &ColumnI );
16837       if(index)
16838         free(index);
16839       return FALSE;
16840     }
16841 
16842     for( i = 0; i < n; i++ )
16843     {
16844       // make X point to a data column in M
16845       X.cplx = &(M->cplx[i]);
16846 
16847       if( i != 0 )
16848       {
16849         ColumnI.cplx[0][i-1].re = 0.0;
16850         ColumnI.cplx[0][i-1].im = 0.0;
16851       }
16852       ColumnI.cplx[0][i].re = 1.0;
16853       ColumnI.cplx[0][i].im = 0.0;
16854 
16855       if( !MTX_static_SolveByGaussianElimination( &ColumnI, &X, &A, index ) )
16856       {
16857         MTX_ERROR_MSG( "MTX_static_SolveByGaussianElimination returned FALSE." );
16858         MTX_Free( &A );
16859         MTX_Free( &ColumnI );
16860         if(index)
16861           free(index);
16862         return FALSE;
16863       }
16864     }
16865   }
16866 
16867   if(index)
16868     free(index);
16869 
16870   MTX_Free( &A );
16871   MTX_Free( &ColumnI );
16872 
16873   return TRUE;
16874 }
16875 
16876 BOOL MTX_static_Factorize( BOOL *isFullRank, const unsigned n, unsigned* index, MTX *A )
16877 {
16878   // [1] Chaney, Ward & David Kincaid, "Numerical Mathematics and Computing, 3rd Edition",
16879   // Cole Publishing Co., 1994, Belmont, CA, p.237)
16880   unsigned i = 0;
16881   unsigned j = 0;
16882   unsigned k = 0;
16883   unsigned tempi = 0;
16884   double *scale;
16885 
16886   double r = 0.0;
16887   double rmax = 0.0;
16888   double xmult = 0.0;
16889   
16890   stComplex cplx_xmult = {0.0,0.0};
16891   stComplex cplx = {0.0,0.0};
16892 
16893   BOOL isFullRankTmp = FALSE;
16894 
16895   if( MTX_isNull( A ) )
16896   {
16897     MTX_ERROR_MSG( "NULL Matrix" );
16898     return FALSE;
16899   }
16900   if( !MTX_isSquare( A ) )
16901   {
16902     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
16903     return FALSE;
16904   }
16905 
16906   if( n == 0 )
16907   {
16908     MTX_ERROR_MSG( "if( n == 0 )" );
16909     return FALSE;
16910   }
16911 
16912   scale = (double*)malloc( sizeof(double)*n );
16913   if( !scale )
16914   {
16915     MTX_ERROR_MSG( "malloc returned NULL." );
16916     return FALSE;
16917   }
16918 
16919   // The first loop determines the maximum element
16920   // in each column and the index of its first occurance
16921   for( i = 0; i < n; i++ )
16922   {
16923     if( !MTX_MaxAbsRowIndex( A, i, &(scale[i]), &k ) )
16924     {
16925       MTX_ERROR_MSG( "MTX_MaxAbsRowIndex returned FALSE." );
16926       if( scale )
16927         free(scale);
16928       return FALSE;
16929     }
16930     index[i] = i;
16931   }
16932 
16933   if( A->isReal )
16934   {
16935     // Second Loop
16936     // perform gaussian elimination to form the Lower and Upper matrices
16937     for( k = 0; k < n - 1; k++ )
16938     {
16939       // select the pivot row, j, based on rmax, the first occurance of the largest ratio
16940       rmax = 0;
16941       j = 0;
16942       for( i = k; i < n; i++ )
16943       {
16944         r = fabs( A->data[k][index[i]] ) / scale[index[i]];
16945         if( r > rmax )
16946         {
16947           rmax = r;
16948           j = i;
16949         }
16950       }
16951 
16952       tempi = index[j];
16953       index[j] = index[k];
16954       index[k] = tempi;
16955 
16956       for( i = k + 1; i < n; i++ )
16957       {
16958         xmult = A->data[k][index[i]] / A->data[k][index[k]];
16959         A->data[k][index[i]] = xmult;
16960 
16961         isFullRankTmp = FALSE;
16962         for( j = k + 1; j < n; j++ )
16963         {
16964           A->data[j][index[i]] = A->data[j][index[i]] - xmult*(A->data[j][index[k]]);
16965 
16966           // if the upper matrix every has all zeros in one row, no solution is available
16967           if( A->data[j][index[i]] != 0.0 )
16968             isFullRankTmp = TRUE;
16969         }
16970         if( !isFullRankTmp )
16971         {
16972           *isFullRank = FALSE;
16973           if( scale )
16974             free(scale);
16975           return TRUE;
16976         }
16977       }
16978     }
16979   }
16980   else
16981   {
16982     // Second Loop
16983     // perform gaussian elimination to form the Lower and Upper matrices
16984     for( k = 0; k < n - 1; k++ )
16985     {
16986       // select the pivot row, j, based on rmax, the first occurance of the largest ratio
16987       rmax = 0;
16988       j = 0;
16989       for( i = k; i < n; i++ )
16990       {
16991         r = sqrt( A->cplx[k][index[i]].re*A->cplx[k][index[i]].re + A->cplx[k][index[i]].im*A->cplx[k][index[i]].im );
16992         r = r / scale[index[i]];
16993         if( r > rmax )
16994         {
16995           rmax = r;
16996           j = i;
16997         }
16998       }
16999 
17000       tempi = index[j];
17001       index[j] = index[k];
17002       index[k] = tempi;
17003 
17004       for( i = k + 1; i < n; i++ )
17005       {
17006         MTX_static_quick_complex_divide(
17007           &(A->cplx[k][index[i]].re),
17008           &(A->cplx[k][index[i]].im),
17009           &(A->cplx[k][index[k]].re),
17010           &(A->cplx[k][index[k]].im),
17011           &cplx_xmult.re,
17012           &cplx_xmult.im );
17013 
17014         A->cplx[k][index[i]] = cplx_xmult;
17015 
17016         isFullRankTmp = FALSE;
17017         for( j = k + 1; j < n; j++ )
17018         {
17019           MTX_static_quick_complex_mult_ab(
17020             &cplx_xmult.re,
17021             &cplx_xmult.im,
17022             &(A->cplx[j][index[k]].re),
17023             &(A->cplx[j][index[k]].im),
17024             &cplx.re,
17025             &cplx.im );
17026 
17027           A->cplx[j][index[i]].re = A->cplx[j][index[i]].re - cplx.re;
17028           A->cplx[j][index[i]].im = A->cplx[j][index[i]].im - cplx.im;
17029 
17030           // if the upper matrix every has all zeros in one row, no solution is available
17031           if( A->cplx[j][index[i]].re != 0.0 || A->cplx[j][index[i]].im != 0.0 )
17032             isFullRankTmp = TRUE;
17033         }
17034         if( !isFullRankTmp )
17035         {
17036           *isFullRank = FALSE;
17037           if( scale )
17038             free(scale);
17039           return TRUE;
17040         }
17041       }
17042     }
17043   }
17044 
17045   if( scale )
17046     free(scale);
17047 
17048   *isFullRank = TRUE;
17049   return TRUE;
17050 }
17051 
17052 
17053 BOOL MTX_static_SolveByGaussianElimination(
17054   const MTX *b,
17055   MTX *X,
17056   const MTX *A, // factorized A
17057   unsigned *index )
17058 {
17059   int i = 0; // signed value is needed for the reverse for loop
17060   int j = 0;
17061   int k = 0;
17062   double sum = 0.0;
17063   const int n = A->nrows;
17064   MTX B;
17065   stComplex cplx = {0.0,0.0};
17066   stComplex sum_cplx = {0.0,0.0};
17067 
17068   // make B a copy of b
17069   MTX_Init( &B);
17070 
17071   if( !MTX_Copy( b, &B ) )
17072   {
17073     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
17074     MTX_Free( &B );
17075     return FALSE;
17076   }
17077 
17078   if( A->isReal )
17079   {
17080     for( k = 0; k < n - 1; k++ )
17081     {
17082       for( i = k + 1; i < n; i++ )
17083       {
17084         B.data[0][index[i]] = B.data[0][index[i]] - A->data[k][index[i]]*B.data[0][index[k]];
17085       }
17086     }
17087     X->data[0][n-1] = B.data[0][index[n-1]] / A->data[n-1][index[n-1]];
17088 
17089     for( i = n - 2; i >= 0; i-- )
17090     {
17091       sum = B.data[0][index[i]];
17092       for( j = i + 1; j < n; j++ )
17093       {
17094         sum = sum - A->data[j][index[i]]*X->data[0][j];
17095       }
17096       X->data[0][i] = sum / A->data[i][index[i]];
17097     }
17098   }
17099   else
17100   {
17101     for( k = 0; k < n - 1; k++ )
17102     {
17103       for( i = k + 1; i < n; i++ )
17104       {
17105         MTX_static_quick_complex_mult_ab(
17106           &(A->cplx[k][index[i]].re),
17107           &(A->cplx[k][index[i]].im),
17108           &(B.cplx[0][index[k]].re),
17109           &(B.cplx[0][index[k]].im),
17110           &cplx.re,
17111           &cplx.im );
17112 
17113         B.cplx[0][index[i]].re = B.cplx[0][index[i]].re - cplx.re;
17114         B.cplx[0][index[i]].im = B.cplx[0][index[i]].im - cplx.im;
17115       }
17116     }
17117 
17118     MTX_static_quick_complex_divide(
17119       &(B.cplx[0][index[n-1]].re),
17120       &(B.cplx[0][index[n-1]].im),
17121       &(A->cplx[n-1][index[n-1]].re),
17122       &(A->cplx[n-1][index[n-1]].im),
17123       &(X->cplx[0][n-1].re),
17124       &(X->cplx[0][n-1].im) );
17125 
17126     for( i = n - 2; i >= 0; i-- )
17127     {
17128       sum_cplx.re = B.cplx[0][index[i]].re;
17129       sum_cplx.im = B.cplx[0][index[i]].im;
17130 
17131       for( j = i + 1; j < n; j++ )
17132       {
17133         MTX_static_quick_complex_mult_ab(
17134           &(A->cplx[j][index[i]].re),
17135           &(A->cplx[j][index[i]].im),
17136           &(X->cplx[0][j].re),
17137           &(X->cplx[0][j].im),
17138           &cplx.re,
17139           &cplx.im );
17140 
17141         sum_cplx.re = sum_cplx.re - cplx.re;
17142         sum_cplx.im = sum_cplx.im - cplx.im;
17143       }
17144 
17145       MTX_static_quick_complex_divide(
17146         &sum_cplx.re,
17147         &sum_cplx.im,
17148         &(A->cplx[i][index[i]].re),
17149         &(A->cplx[i][index[i]].im),
17150         &(X->cplx[0][i].re),
17151         &(X->cplx[0][i].im) );
17152     }
17153   }
17154 
17155   MTX_Free( &B );
17156   return TRUE;
17157 }
17158 
17159 BOOL MTX_ColumnMovAvg( const MTX *src, const unsigned col, const unsigned nlead, const unsigned nlag, MTX *dst )
17160 {
17161   unsigned i = 0;
17162   unsigned k = 0;
17163   unsigned count = 0;
17164 
17165   double sum = 0.0;
17166   double sum_im = 0.0;
17167 
17168   if( MTX_isNull( src ) )
17169   {
17170     MTX_ERROR_MSG( "NULL Matrix" );
17171     return FALSE;
17172   }
17173 
17174   if( col >= src->ncols )
17175   {
17176     MTX_ERROR_MSG( "if( col >= src->ncols )" );
17177     return FALSE;
17178   }
17179 
17180   if( nlead+nlag > src->nrows )
17181   {
17182     MTX_ERROR_MSG( "if( nlead+nlag > src->nrows )" );
17183     return FALSE;
17184   }
17185 
17186   // resize or make real/complex as needed
17187   if( dst->isReal != src->isReal )
17188   {
17189     if( !MTX_Resize( dst, src->nrows, 1, src->isReal ) )
17190     {
17191       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
17192       return FALSE;
17193     }
17194   }
17195   else if( dst->nrows != src->nrows || dst->ncols != 1 )
17196   {
17197     if( !MTX_Resize( dst, src->nrows, 1, src->isReal ) )
17198     {
17199       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
17200       return FALSE;
17201     }
17202   }
17203 
17204   if( src->isReal )
17205   {
17206     for( i = 0; i < src->nrows; i++ )
17207     {
17208       sum = src->data[col][i];
17209       count = 1;
17210       for( k = 1; k <= nlead; k++ )
17211       {
17212         if( i >= k )
17213         {
17214           sum += src->data[col][i-k];
17215           count++;
17216         }
17217       }
17218       for( k = 1; k <= nlag; k++ )
17219       {
17220         if( i < src->nrows-k )
17221         {
17222           sum += src->data[col][i+k];
17223           count++;
17224         }
17225       }
17226       dst->data[0][i] = sum / ((double)(count));
17227     }
17228   }
17229   else
17230   {
17231     for( i = 0; i < src->nrows; i++ )
17232     {
17233       sum = src->cplx[col][i].re;
17234       sum_im = src->cplx[col][i].im;
17235       count = 1;
17236       for( k = 1; k <= nlead; k++ )
17237       {
17238         if( i >= k )
17239         {
17240           sum += src->cplx[col][i-k].re;
17241           sum_im += src->cplx[col][i-k].im;
17242           count++;
17243         }
17244       }
17245       for( k = 1; k <= nlag; k++ )
17246       {
17247         if( i < src->nrows-k )
17248         {
17249           sum += src->cplx[col][i+k].re;
17250           sum_im += src->cplx[col][i+k].im;
17251           count++;
17252         }
17253       }
17254       dst->cplx[0][i].re = sum / ((double)(count));
17255       dst->cplx[0][i].im = sum / ((double)(count));
17256     }
17257   }
17258 
17259   return TRUE;
17260 }
17261 
17262 
17263 BOOL MTX_MovAvg( const MTX *src, const unsigned nlead, const unsigned nlag, MTX *dst )
17264 {
17265   unsigned j = 0;
17266 
17267   MTX column;
17268 
17269   if( MTX_isNull( src ) )
17270   {
17271     MTX_ERROR_MSG( "NULL Matrix" );
17272     return FALSE;
17273   }
17274 
17275   MTX_Init( &column );
17276 
17277   if( src->isReal != dst->isReal )
17278   {
17279     if( !MTX_Redim( dst, src->nrows, src->ncols ) )
17280     {
17281       MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
17282       return FALSE;
17283     }
17284   }
17285   else if( !MTX_isSameSize( src, dst ) )
17286   {
17287     if( !MTX_Redim( dst, src->nrows, src->ncols ) )
17288     {
17289       MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
17290       return FALSE;
17291     }
17292   }
17293 
17294   // Column is a fixed container that will point to dst data.
17295   column.isReal = dst->isReal;
17296   column.nrows = dst->nrows;
17297   column.ncols = 1;
17298 
17299   for( j = 0; j < src->ncols; j++ )
17300   {
17301     if( dst->isReal )
17302       column.data = &(dst->data[j]);
17303     else
17304       column.data = &(dst->data[j]);
17305 
17306     if( !MTX_ColumnMovAvg( src, j, nlead, nlag, &column ) ) // this is acting on dst indirectly
17307     {
17308       MTX_ERROR_MSG( "MTX_ColumnMovAvg returned FALSE." );
17309       return FALSE;
17310     }
17311   }
17312 
17313   // Note: No need to MTX_Free column.
17314 
17315   return TRUE;
17316 }
17317 
17318 
17319 
17320 
17321 
17322 BOOL MTX_ATAInverse( const MTX *A, MTX *InvATA )
17323 {
17324   unsigned i = 0;
17325   unsigned j = 0;
17326   unsigned k = 0;
17327   MTX colA;
17328 
17329   if( MTX_isNull( A ) )
17330   {
17331     MTX_ERROR_MSG( "NULL Matrix" );
17332     return FALSE;
17333   }
17334 
17335   // resize InvATA if needed
17336   if( MTX_isNull( InvATA ) )
17337   {
17338     if( !MTX_Resize( InvATA, A->ncols, A->ncols, A->isReal ) )
17339     {
17340       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
17341       return FALSE;
17342     }
17343   }
17344   else if( InvATA->nrows != A->ncols || InvATA->ncols != A->ncols )
17345   {
17346     if( !MTX_Resize( InvATA, A->ncols, A->ncols, A->isReal ) )
17347     {
17348       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
17349       return FALSE;
17350     }
17351   }
17352 
17353   // make a copy and a vector
17354   MTX_Init( &colA );
17355 
17356   for( i = 0; i < A->ncols; i++ )
17357   {
17358     for( j = 0; j < A->ncols; j++ )
17359     {
17360       if( i > j )
17361       {
17362         InvATA->data[j][i] = InvATA->data[i][j];
17363       }
17364       else
17365       {
17366         InvATA->data[j][i] = 0;
17367         for( k = 0; k < A->nrows; k++ )
17368         {
17369           InvATA->data[j][i] += A->data[i][k] * A->data[j][k];
17370         }
17371       }
17372     }
17373   }
17374 
17375   return MTX_InvertInPlace( InvATA );
17376 }
17377 
17378 
17379 BOOL MTX_LowerTriangularInverseInplace( MTX *src )
17380 {
17381   unsigned i = 0;
17382   unsigned j = 0;
17383   unsigned k = 0;
17384 
17385   if( MTX_isNull( src ) )
17386   {
17387     MTX_ERROR_MSG( "NULL Matrix" );
17388     return FALSE;
17389   }
17390 
17391   if( !MTX_isSquare( src ) )
17392   {
17393     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
17394     return FALSE;
17395   }
17396 
17397   // inversion of lower triangular matrix
17398   for( j = 0; j < src->nrows; j++ )
17399   {
17400     if( src->data[j][j] == 0.0 )
17401     {
17402       MTX_ERROR_MSG( "if( src->data[j][j] == 0.0 )" );
17403       return FALSE;
17404     }
17405 
17406     src->data[j][j] = 1.0 / src->data[j][j];
17407 
17408     for( i = j + 1; i < src->nrows; i++ )
17409     {
17410       if( src->data[i][i] == 0.0 )
17411       {
17412         MTX_ERROR_MSG( "if( src->data[j][j] == 0.0 )" );
17413         return FALSE;
17414       }
17415 
17416       src->data[j][i] *= -src->data[j][j] / src->data[i][i];
17417 
17418       for( k = j + 1; k < i; k++ )
17419         src->data[j][i] -= src->data[k][i] * src->data[j][k] / src->data[i][i];
17420     }
17421   }
17422   return TRUE;
17423 }
17424 
17425 
17426 void MTX_static_quick_complex_mult_ab(
17427                                       const double* a_re,
17428                                       const double* a_im,
17429                                       const double* b_re,
17430                                       const double* b_im,
17431                                       double *re,
17432                                       double *im )
17433 {
17434   *re = (*a_re)*(*b_re) - (*a_im)*(*b_im);
17435   *im = (*a_re)*(*b_im) + (*a_im)*(*b_re);
17436 }
17437 
17438 
17439 void MTX_static_quick_complex_mult_abc(
17440                                        const double* a_re,
17441                                        const double* a_im,
17442                                        const double* b_re,
17443                                        const double* b_im,
17444                                        const double* c_re,
17445                                        const double* c_im,
17446                                        double *re,
17447                                        double *im )
17448 {
17449   double r,i; // temps
17450 
17451   r = (*a_re)*(*b_re) - (*a_im)*(*b_im);
17452   i = (*a_re)*(*b_im) + (*a_im)*(*b_re);
17453 
17454   *re = r*(*c_re) - i*(*c_im);
17455   *im = r*(*c_im) + i*(*c_re);
17456 }
17457 
17458 void MTX_static_quick_complex_divide(
17459                                      const double* a_re, //!< The real part of a (input).
17460                                      const double* a_im, //!< The imag part of a (input).
17461                                      const double* b_re, //!< The real part of b (input).
17462                                      const double* b_im, //!< The imag part of b (input).
17463                                      double *re, //!< The real part of the result.
17464                                      double *im )//!< The imag part of the result.
17465 {
17466   double dtmp;
17467   dtmp = (*b_re)*(*b_re) + (*b_im)*(*b_im);
17468   *re = ((*a_re) * (*b_re) + (*a_im) * (*b_im) ) / dtmp;
17469   *im = ((*a_im) * (*b_re) - (*a_re) * (*b_im) ) / dtmp;
17470 }
17471 
17472 
17473 // static
17474 void MTX_static_Det_cleanup( unsigned *index, double *scale, MTX *U, MTX *magMtx )
17475 {
17476   if( index )
17477   {
17478     free( index );
17479     index = NULL;
17480   }
17481   if( scale )
17482   {
17483     free( scale );
17484     scale = NULL;
17485   }
17486   if( U != NULL )
17487   {
17488     MTX_Free( U );
17489   }
17490   if( magMtx != NULL )
17491   {
17492     MTX_Free( magMtx );
17493   }
17494 }
17495 
17496 // Computes the determinant of the square matrix M.
17497 // det(M) = det(LU) = det(L)*det(U)
17498 BOOL MTX_Det( const MTX *M, double *re, double *im )
17499 {
17500   unsigned n; // the number of rows in M
17501   double tmpre;
17502   double tmpim;
17503   int s; // a sign value 1 or -1.
17504 
17505   unsigned *index = NULL;
17506   double *scale = NULL;
17507 
17508   MTX U; // An Upper triangular matrix (may be permutated).
17509   MTX magMtx; // A matrix with magnitude of M.
17510 
17511   MTX_Init( &U );
17512   MTX_Init( &magMtx );
17513 
17514   if( MTX_isNull( M ) )
17515   {
17516     MTX_ERROR_MSG( "NULL Matrix" );
17517     return FALSE;
17518   }
17519   if( !MTX_isSquare( M ) )
17520   {
17521     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
17522     return FALSE;
17523   }
17524 
17525   n = M->nrows;
17526 
17527   *re = 0.0;
17528   *im = 0.0;
17529 
17530   // special cases
17531   // use the direct solution for rank up to 3
17532   if( n == 1 )
17533   {
17534     if( M->isReal )
17535     {
17536       *re = M->data[0][0];
17537     }
17538     else
17539     {
17540       *re = M->cplx[0][0].re;
17541       *im = M->cplx[0][0].im;
17542     }
17543     return TRUE;
17544   }
17545   else if( n == 2 )
17546   {
17547     if( M->isReal )
17548     {
17549       *re = M->data[0][0]*M->data[1][1] - M->data[0][1]*M->data[1][0];
17550     }
17551     else
17552     {
17553       *re = M->cplx[0][0].re*M->cplx[1][1].re - M->cplx[0][0].im*M->cplx[1][1].im;
17554       *im = M->cplx[0][0].re*M->cplx[1][1].im + M->cplx[0][0].im*M->cplx[1][1].re;
17555 
17556       *re -= M->cplx[0][1].re*M->cplx[1][0].re - M->cplx[0][1].im*M->cplx[1][0].im;
17557       *im -= M->cplx[0][1].re*M->cplx[1][0].im + M->cplx[0][1].im*M->cplx[1][0].re;
17558     }
17559     return TRUE;
17560   }
17561 
17562   
17563   // special cases
17564   // use the direct solution for rank up to 3
17565   if( n == 3)
17566   {
17567     // det = a11*a22*a33 + a13*a21*a32 + a12*a23*a31 - a13*a22*a31 - a11*a23*a32 - a12*a21*a33 // row-column
17568     // det = a00*a11*a22 + a02*a10*a21 + a01*a12*a20 - a02*a11*a20 - a00*a12*a21 - a01*a10*a22 // row-column, zero-based
17569     // det = a00*a11*a22 + a20*a01*a12 + a10*a21*a02 - a20*a11*a02 - a00*a21*a12 - a10*a01*a22 // column-row
17570 
17571     if( M->isReal )
17572     {
17573       *re = M->data[0][0]*M->data[1][1]*M->data[2][2] +
17574         M->data[2][0]*M->data[0][1]*M->data[1][2] +
17575         M->data[1][0]*M->data[2][1]*M->data[0][2] -
17576         M->data[2][0]*M->data[1][1]*M->data[0][2] -
17577         M->data[0][0]*M->data[2][1]*M->data[1][2] -
17578         M->data[1][0]*M->data[0][1]*M->data[2][2];
17579     }
17580     else
17581     {
17582       MTX_static_quick_complex_mult_abc(
17583         &(M->cplx[0][0].re), &(M->cplx[0][0].im),
17584         &(M->cplx[1][1].re), &(M->cplx[1][1].im),
17585         &(M->cplx[2][2].re), &(M->cplx[2][2].im),
17586         &tmpre, &tmpim );
17587       *re = tmpre;
17588       *im = tmpim;
17589 
17590       MTX_static_quick_complex_mult_abc(
17591         &(M->cplx[2][0].re), &(M->cplx[2][0].im),
17592         &(M->cplx[0][1].re), &(M->cplx[0][1].im),
17593         &(M->cplx[1][2].re), &(M->cplx[1][2].im),
17594         &tmpre, &tmpim );
17595       *re += tmpre;
17596       *im += tmpim;
17597 
17598       MTX_static_quick_complex_mult_abc(
17599         &(M->cplx[1][0].re), &(M->cplx[1][0].im),
17600         &(M->cplx[2][1].re), &(M->cplx[2][1].im),
17601         &(M->cplx[0][2].re), &(M->cplx[0][2].im),
17602         &tmpre, &tmpim );
17603       *re += tmpre;
17604       *im += tmpim;
17605 
17606       MTX_static_quick_complex_mult_abc(
17607         &(M->cplx[2][0].re), &(M->cplx[2][0].im),
17608         &(M->cplx[1][1].re), &(M->cplx[1][1].im),
17609         &(M->cplx[0][2].re), &(M->cplx[0][2].im),
17610         &tmpre, &tmpim );
17611       *re -= tmpre;
17612       *im -= tmpim;
17613 
17614       MTX_static_quick_complex_mult_abc(
17615         &(M->cplx[0][0].re), &(M->cplx[0][0].im),
17616         &(M->cplx[2][1].re), &(M->cplx[2][1].im),
17617         &(M->cplx[1][2].re), &(M->cplx[1][2].im),
17618         &tmpre, &tmpim );
17619       *re -= tmpre;
17620       *im -= tmpim;
17621 
17622       MTX_static_quick_complex_mult_abc(
17623         &(M->cplx[1][0].re), &(M->cplx[1][0].im),
17624         &(M->cplx[0][1].re), &(M->cplx[0][1].im),
17625         &(M->cplx[2][2].re), &(M->cplx[2][2].im),
17626         &tmpre, &tmpim );
17627       *re -= tmpre;
17628       *im -= tmpim;
17629     }
17630     return TRUE;
17631   }
17632   else
17633   {
17634     stComplex det;
17635     stComplex xmult;
17636 
17637     unsigned i;
17638     unsigned j;
17639     unsigned k;
17640     unsigned tempi;    
17641 
17642     double r = 0.0,
17643       rmax = 0.0,
17644       smax = 0.0,
17645       tempd = 0.0;
17646 
17647     BOOL isFullRankTmp = FALSE;
17648     BOOL isFullRank = TRUE;
17649 
17650     // factorization by naive gaussian elimination (to perform LUFactorization)
17651     // The product of the columns of the U matrix is the determinant.
17652     // Reference
17653     // Chaney, Ward & David Kincaid, "Numerical Mathematics and Computing, 3rd Edition", Cole
17654     // Publishing Co., 1994, Belmont, CA
17655 
17656     // operate on a copy
17657     if( !MTX_Copy( M, &U ) )
17658     {
17659       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
17660       MTX_static_Det_cleanup( index, scale, &U, &magMtx );
17661       return FALSE;
17662     }
17663 
17664     index = (unsigned*)malloc( sizeof(unsigned)*n );
17665     if( !index )
17666     {
17667       MTX_ERROR_MSG( "malloc returned NULL." );
17668       MTX_static_Det_cleanup( index, scale, &U, &magMtx );
17669       return FALSE;
17670     }
17671 
17672     scale = (double*)malloc( sizeof(double)*n );
17673     if( !index )
17674     {
17675       MTX_ERROR_MSG( "malloc returned NULL." );
17676       MTX_static_Det_cleanup( index, scale, &U, &magMtx );
17677       return FALSE;
17678     }
17679 
17680     // deal with the real and complex cases separately
17681     if( M->isReal )
17682     {
17683       // First Loop
17684       // initial form of the indexArray is determined
17685       // the scale factor array scaleArray is also determined
17686       // The indexArray will become [0 1 2.... n-1]
17687       // The scale factor array is the first absolue largest element of each row.
17688       for( i = 0; i < n; i++ )
17689       {
17690         index[i] = i;
17691         smax = 0;
17692         for( j = 0; j < n; j++ )
17693         {
17694           tempd = fabs( U.data[j][i] );
17695           if( smax < tempd )
17696           {
17697             smax = tempd;
17698           }
17699         }
17700         scale[i] = smax;
17701         if( scale[i] == 0.0 )
17702         {
17703           *re = 0.0;
17704           *im = 0.0;
17705 
17706           MTX_static_Det_cleanup( index, scale, &U, &magMtx );
17707 
17708           return TRUE;
17709         }
17710       }
17711 
17712       // Second Loop
17713       // perform gaussian elimination to form the Lower and Upper matrices
17714       for( k = 0; k < n - 1; k++ )
17715       {
17716         // select the pivot row, j, based on rmax, the last occurance of the largest ratio (last instead of first to match Matlab results)
17717         j = 0;
17718         rmax = 0;
17719         for( i = k; i < n; i++ )
17720         {
17721           r = fabs( U.data[k][index[i]] ) / scale[index[i]];
17722 
17723           if( r >= rmax )
17724           {
17725             rmax = r;
17726             j = i;
17727           }
17728         }
17729 
17730         tempi = index[j];
17731         index[j] = index[k];
17732         index[k] = tempi;
17733 
17734         for( i = k + 1; i < n; i++ )
17735         {
17736           xmult.re = U.data[k][index[i]] / U.data[k][index[k]];
17737 
17738           isFullRankTmp = FALSE;
17739           for( j = k + 1; j < n; j++ )
17740           {
17741             U.data[j][index[i]] = U.data[j][index[i]] - xmult.re*U.data[j][index[k]];
17742 
17743             // if the upper matrix every has all zeros in one row, no solution is available
17744             if( U.data[j][index[i]] != 0 )
17745               isFullRankTmp = TRUE;
17746           }
17747           if( !isFullRankTmp )
17748           {
17749             *re = 0.0;
17750             *im = 0.0;
17751 
17752             MTX_static_Det_cleanup( index, scale, &U, &magMtx );
17753 
17754             return TRUE;
17755           }
17756         }
17757       }
17758 
17759       //MTX_PrintAutoWidth( &U, "U.txt", 10, FALSE ); 
17760 
17761       // compute the product of the psychologically 'diagonal' terms
17762       det.re = 1;
17763       det.im = 0;
17764       for( j = 0; j < n; j++ )
17765       {
17766         det.re *= U.data[j][index[j]];        
17767       }
17768 
17769       /*
17770       since permutations change the sign of the determinant, calculate det(P)
17771       e.g. 
17772       P = [1 0 0 0 0;
17773            0 0 0 1 0;
17774            0 0 0 0 1;
17775            0 0 1 0 0;
17776            0 1 0 0 0];
17777       The following code uses the +/- rule recursively and to determine if 
17778       there is a sign change. 
17779       */
17780       s = 1; // det(P) is either 1 or -1
17781       for( j = 0; j < n-1; j++ )
17782       {
17783         if( index[j]%2!=0 )
17784           s *= -1;
17785         for( i=j+1; i < n; i++ )
17786         {
17787           if( index[i] > j )
17788             index[i]--;
17789         }
17790       }
17791       det.re *= s;
17792 
17793       *re = det.re;
17794       // *im is already 0
17795     }
17796     else
17797     {
17798       // Compute the magnitude of M.
17799       if( !MTX_Magnitude( M, &magMtx ) )
17800       {
17801         MTX_ERROR_MSG( "MTX_Magnitude returned FALSE." );
17802         MTX_static_Det_cleanup( index, scale, &U, &magMtx );
17803         return FALSE;
17804       }
17805 
17806       // First Loop
17807       // initial form of the indexArray is determined
17808       // the scale factor array scaleArray is also determined
17809       // The indexArray will become [0 1 2.... n-1]
17810       // The scale factor array is the first absolute largest element of each row.
17811       for( i = 0; i < n; i++ )
17812       {
17813         index[i] = i;
17814         smax = 0;
17815         for( j = 0; j < n; j++ )
17816         {
17817           if( smax < magMtx.data[j][i] )
17818           {
17819             smax = magMtx.data[j][i];
17820           }
17821         }
17822         scale[i] = smax;
17823         if( scale[i] == 0.0 )
17824         {
17825           *re = 0.0;
17826           *im = 0.0;
17827 
17828           MTX_static_Det_cleanup( index, scale, &U, &magMtx );
17829 
17830           return TRUE;
17831         }
17832       }
17833 
17834       // Second Loop
17835       // perform gaussian elimination to form the Lower and Upper matrices
17836       for( k = 0; k < n - 1; k++ )
17837       {
17838         // select the pivot row, j, based on rmax, the last occurance of the largest ratio (last instead of first to match Matlab results)
17839         j = 0;
17840         rmax = 0;
17841         for( i = k; i < n; i++ )
17842         {
17843           r = magMtx.data[k][index[i]] / scale[index[i]];
17844 
17845           if( r >= rmax )
17846           {
17847             rmax = r;
17848             j = i;
17849           }
17850         }
17851 
17852         tempi = index[j];
17853         index[j] = index[k];
17854         index[k] = tempi;
17855 
17856         for( i = k + 1; i < n; i++ )
17857         {
17858           // compute: xmult = U.cplx[k][index[i]] / U.cplx[k][index[k]];
17859           MTX_static_quick_complex_divide(
17860             &(U.cplx[k][index[i]].re),
17861             &(U.cplx[k][index[i]].im),
17862             &(U.cplx[k][index[k]].re),
17863             &(U.cplx[k][index[k]].im),
17864             &(xmult.re),
17865             &(xmult.im)
17866             );
17867 
17868           isFullRankTmp = FALSE;
17869           for( j = k + 1; j < n; j++ )
17870           {
17871             // compute: xmult*U.cplx[j][index[k]]
17872             tmpre = xmult.re * U.cplx[j][index[k]].re - xmult.im * U.cplx[j][index[k]].im;
17873             tmpim = xmult.re * U.cplx[j][index[k]].im + xmult.im * U.cplx[j][index[k]].re;
17874 
17875             U.cplx[j][index[i]].re = U.cplx[j][index[i]].re - tmpre;
17876             U.cplx[j][index[i]].im = U.cplx[j][index[i]].im - tmpim;
17877 
17878             // if the upper matrix every has all zeros in one row, no solution is available
17879             if( U.cplx[j][index[i]].re != 0 )
17880               isFullRankTmp = TRUE;
17881             if( U.cplx[j][index[i]].im != 0 )
17882               isFullRankTmp = TRUE;
17883           }
17884           if( !isFullRankTmp )
17885           {
17886             *re = 0.0;
17887             *im = 0.0;
17888 
17889             MTX_static_Det_cleanup( index, scale, &U, &magMtx );
17890             return TRUE;
17891           }
17892         }
17893       }
17894 
17895       // compute the product of the psychologically 'diagonal' terms
17896       j = 0;
17897       det.re = U.cplx[j][index[j]].re;
17898       det.im = U.cplx[j][index[j]].im;
17899       for( j = 1; j < n; j++ )
17900       {
17901         tmpre = det.re * U.cplx[j][index[j]].re - det.im * U.cplx[j][index[j]].im;
17902         tmpim = det.re * U.cplx[j][index[j]].im + det.im * U.cplx[j][index[j]].re;
17903 
17904         det.re = tmpre;
17905         det.im = tmpim;        
17906       }
17907 
17908       /*
17909       since permutations change the sign of the determinant, calculate det(P)
17910       e.g. 
17911       P = [1 0 0 0 0;
17912            0 0 0 1 0;
17913            0 0 0 0 1;
17914            0 0 1 0 0;
17915            0 1 0 0 0];
17916       The following code uses the +/- rule recursively and to determine if 
17917       there is a sign change. 
17918       */
17919       s = 1; // det(P) is either 1 or -1
17920       for( j = 0; j < n-1; j++ )
17921       {
17922         if( index[j]%2!=0 )
17923           s *= -1;
17924         for( i=j+1; i < n; i++ )
17925         {
17926           if( index[i] > j )
17927             index[i]--;
17928         }
17929       }
17930       det.re *= s;
17931       det.im *= s;
17932 
17933       // the final result (output)
17934       *re = det.re;
17935       *im = det.im;
17936     }
17937 
17938     MTX_static_Det_cleanup( index, scale, &U, &magMtx );
17939 
17940     isFullRank = TRUE;
17941   }
17942 
17943   return TRUE;
17944 }
17945 
17946 BOOL MTX_LUFactorization( const MTX *src, BOOL *IsFullRank, MTX *P, MTX *L, MTX *U )
17947 {
17948   // factorization by naive gaussian elimination
17949   // Reference
17950   // Chaney, Ward & David Kincaid, "Numerical Mathematics and Computing, 3rd Edition", Cole
17951   // Publishing Co., 1994, Belmont, CA
17952   unsigned n;
17953   unsigned i = 0;
17954   unsigned j = 0;
17955   unsigned k = 0;
17956   unsigned tempi = 0;
17957   unsigned *index = NULL;
17958   double *scale = NULL;
17959   double r = 0.0,
17960     rmax = 0.0,
17961     smax = 0.0,
17962     tempd = 0.0;
17963 
17964   stComplex xmult; // a real/complex row multiplier value.
17965 
17966   BOOL isFullRankTmp = FALSE;
17967 
17968 
17969   if( MTX_isNull( src ) )
17970   {
17971     MTX_ERROR_MSG( "NULL Matrix" );
17972     return FALSE;
17973   }
17974 
17975   if( !MTX_isSquare( src ) )
17976   {
17977     MTX_ERROR_MSG( "MTX_isSquare returned FALSE." );
17978     return FALSE;
17979   }
17980 
17981   n = src->nrows;
17982 
17983   // resize appropriately
17984   if( P->nrows != n || P->ncols != n || !P->isReal )
17985   {
17986     if( !MTX_Resize( P, n, n, TRUE ) ) // always real
17987     {
17988       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
17989       return FALSE;
17990     }
17991   }
17992   if( L->nrows != n || L->ncols != n || (L->isReal != src->isReal) )
17993   {
17994     if( !MTX_Resize( L, n, n, src->isReal ) )
17995     {
17996       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
17997       return FALSE;
17998     }
17999   }
18000   if( U->nrows != n || U->ncols != n || (U->isReal != src->isReal) )
18001   {
18002     if( !MTX_Resize( U, n, n, src->isReal ) )
18003     {
18004       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
18005       return FALSE;
18006     }
18007   }
18008 
18009   if( !MTX_Zero( P ) )
18010   {
18011     MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18012     return FALSE;
18013   }
18014   if( !MTX_Zero( L ) )
18015   {
18016     MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18017     return FALSE;
18018   }
18019 
18020   if( !MTX_Copy( src, U ) )
18021   {
18022     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
18023     return FALSE;
18024   }
18025 
18026   index = (unsigned*)malloc( sizeof(unsigned)*n );
18027   if( !index )
18028   {
18029     MTX_ERROR_MSG( "malloc returned NULL." );
18030     return FALSE;
18031   }
18032 
18033   scale = (double*)malloc( sizeof(double)*n );
18034   if( !scale )
18035   {
18036     MTX_ERROR_MSG( "malloc returned NULL." );
18037     if( index )
18038       free( index );
18039     return FALSE;
18040   }
18041 
18042   if( src->isReal )
18043   {
18044     // First Loop
18045     // initial form of the indexArray is determined
18046     // the scale factor array scaleArray is also determined
18047     // The indexArray will become [0 1 2.... n-1]
18048     // The scale factor array is the first absolue largest element of each row.
18049     for( i = 0; i < n; i++ )
18050     {
18051       index[i] = i;
18052       smax = 0;
18053       for( j = 0; j < n; j++ )
18054       {
18055         tempd = fabs( U->data[j][i] );
18056         if( smax < tempd )
18057         {
18058           smax = tempd;
18059         }
18060       }
18061       scale[i] = smax;
18062       if( scale[i] == 0.0 )
18063       {
18064         *IsFullRank = FALSE;
18065         if(index)
18066           free(index);
18067         if(scale)
18068           free(scale);
18069         if( !MTX_Zero(L) )
18070         {
18071           MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18072           return FALSE;
18073         }
18074         if( !MTX_Zero(U) )
18075         {
18076           MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18077           return FALSE;
18078         }
18079 
18080         return TRUE;
18081       }
18082     }
18083 
18084     // Second Loop
18085     // perform gaussian elimination to form the Lower and Upper matrices
18086     for( k = 0; k < n - 1; k++ )
18087     {
18088       // select the pivot row, j, based on rmax, the last occurance of the largest ratio (last instead of first to match Matlab results)
18089       j = 0;
18090       rmax = 0;
18091       for( i = k; i < n; i++ )
18092       {
18093         r = fabs( U->data[k][index[i]] ) / scale[index[i]];
18094 
18095         if( r >= rmax )
18096         {
18097           rmax = r;
18098           j = i;
18099         }
18100       }
18101 
18102       tempi = index[j];
18103       index[j] = index[k];
18104       index[k] = tempi;
18105 
18106       for( i = k + 1; i < n; i++ )
18107       {
18108         xmult.re = U->data[k][index[i]] / U->data[k][index[k]];
18109         L->data[k][index[i]] = xmult.re;
18110 
18111         isFullRankTmp = FALSE;
18112         for( j = k + 1; j < n; j++ )
18113         {
18114           U->data[j][index[i]] = U->data[j][index[i]] - xmult.re*U->data[j][index[k]];
18115 
18116           // if the upper matrix every has all zeros in one row, no solution is available
18117           if( U->data[j][index[i]] != 0 )
18118             isFullRankTmp = TRUE;
18119         }
18120         if( !isFullRankTmp )
18121         {
18122           *IsFullRank = FALSE;
18123           if(index)
18124             free(index);
18125           if(scale)
18126             free(scale);
18127           if( !MTX_Zero(L) )
18128           {
18129             MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18130             return FALSE;
18131           }
18132           if( !MTX_Zero(U) )
18133           {
18134             MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18135             return FALSE;
18136           }
18137 
18138           return TRUE;
18139         }
18140         U->data[k][index[i]] = 0.0;
18141       }
18142     }
18143   }
18144   else // deal with the complex case
18145   {
18146     double tmpre;
18147     double tmpim;
18148     MTX magMtx; // A matrix with magnitude of the src matrix.
18149     MTX_Init( &magMtx );
18150 
18151     // Compute the magnitude of the src matrix.
18152     if( !MTX_Magnitude( src, &magMtx ) )
18153     {
18154       MTX_ERROR_MSG( "MTX_Magnitude returned FALSE." );
18155       MTX_Free( &magMtx );
18156       if(index)
18157         free(index);
18158       if(scale)
18159         free(scale);
18160       return FALSE;
18161     }
18162 
18163     // First Loop
18164     // initial form of the indexArray is determined
18165     // the scale factor array scaleArray is also determined
18166     // The indexArray will become [0 1 2.... n-1]
18167     // The scale factor array is the first absolute largest element of each row.
18168     for( i = 0; i < n; i++ )
18169     {
18170       index[i] = i;
18171       smax = 0;
18172       for( j = 0; j < n; j++ )
18173       {
18174         if( smax < magMtx.data[j][i] )
18175         {
18176           smax = magMtx.data[j][i];
18177         }
18178       }
18179       scale[i] = smax;
18180       if( scale[i] == 0.0 )
18181       {
18182         *IsFullRank = FALSE;
18183 
18184         if(index)
18185           free(index);
18186         if(scale)
18187           free(scale);
18188         MTX_Free(&magMtx);
18189 
18190         if( !MTX_Zero(L) )
18191         {
18192           MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18193           return FALSE;
18194         }
18195         if( !MTX_Zero(U) )
18196         {
18197           MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18198           return FALSE;
18199         }
18200         return TRUE;
18201       }
18202     }
18203 
18204     // Second Loop
18205     // perform gaussian elimination to form the Lower and Upper matrices
18206     for( k = 0; k < n - 1; k++ )
18207     {
18208       // select the pivot row, j, based on rmax, the last occurance of the largest ratio
18209       j = 0;
18210       rmax = 0;
18211       for( i = k; i < n; i++ )
18212       {
18213         r = magMtx.data[k][index[i]] / scale[index[i]];
18214 
18215         if( r >= rmax )
18216         {
18217           rmax = r;
18218           j = i;
18219         }
18220       }
18221 
18222       tempi = index[j];
18223       index[j] = index[k];
18224       index[k] = tempi;
18225 
18226       for( i = k + 1; i < n; i++ )
18227       {
18228         // compute: xmult = U->cplx[k][index[i]] / U->cplx[k][index[k]];
18229         MTX_static_quick_complex_divide(
18230           &(U->cplx[k][index[i]].re),
18231           &(U->cplx[k][index[i]].im),
18232           &(U->cplx[k][index[k]].re),
18233           &(U->cplx[k][index[k]].im),
18234           &(xmult.re),
18235           &(xmult.im)
18236           );
18237         L->cplx[k][index[i]].re = xmult.re;
18238         L->cplx[k][index[i]].im = xmult.im;
18239 
18240         isFullRankTmp = FALSE;
18241         for( j = k + 1; j < n; j++ )
18242         {
18243           // compute: xmult*U->cplx[j][index[k]]
18244           tmpre = xmult.re * U->cplx[j][index[k]].re - xmult.im * U->cplx[j][index[k]].im;
18245           tmpim = xmult.re * U->cplx[j][index[k]].im + xmult.im * U->cplx[j][index[k]].re;
18246 
18247           U->cplx[j][index[i]].re = U->cplx[j][index[i]].re - tmpre;
18248           U->cplx[j][index[i]].im = U->cplx[j][index[i]].im - tmpim;
18249 
18250           // if the upper matrix every has all zeros in one row, no solution is available
18251           if( U->cplx[j][index[i]].re != 0 )
18252             isFullRankTmp = TRUE;
18253           if( U->cplx[j][index[i]].im != 0 )
18254             isFullRankTmp = TRUE;
18255         }
18256         if( !isFullRankTmp )
18257         {
18258           *IsFullRank = FALSE;
18259 
18260           if(index)
18261             free(index);
18262           if(scale)
18263             free(scale);
18264           MTX_Free(&magMtx);
18265 
18266           if( !MTX_Zero(L) )
18267           {
18268             MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18269             return FALSE;
18270           }
18271           if( !MTX_Zero(U) )
18272           {
18273             MTX_ERROR_MSG( "MTX_Zero returned FALSE." );
18274             return FALSE;
18275           }
18276 
18277           return TRUE;
18278         }
18279         U->cplx[k][index[i]].re = 0.0;
18280         U->cplx[k][index[i]].im = 0.0;
18281       }
18282     }
18283 
18284     MTX_Free(&magMtx);
18285   }
18286 
18287   for( j = 0; j < n; j++ )
18288   {
18289     P->data[index[j]][j] = 1.0;
18290 
18291     if( L->isReal )
18292       L->data[j][index[j]] = 1.0;
18293     else
18294       L->cplx[j][index[j]].re = 1.0;
18295   }
18296 
18297   if(index)
18298     free(index);
18299 
18300   if(scale)
18301     free(scale);
18302 
18303   if( !MTX_PreMultiply_Inplace( L, P ) )
18304   {
18305     MTX_ERROR_MSG( "MTX_PreMultiply_Inplace returned FALSE." );
18306     return FALSE;
18307   }
18308 
18309   if( !MTX_PreMultiply_Inplace( U, P ) )
18310   {
18311     MTX_ERROR_MSG( "MTX_PreMultiply_Inplace returned FALSE." );
18312     return FALSE;
18313   }
18314 
18315   *IsFullRank = TRUE;
18316 
18317   return TRUE;
18318 }
18319 
18320 BOOL MTX_IndexedValues( const MTX *src, const MTX *row_index, const MTX *col_index, MTX *dst )
18321 {
18322   unsigned i = 0;
18323   unsigned j = 0;
18324   unsigned row = 0;
18325   unsigned col = 0;
18326 
18327   if( MTX_isNull( row_index ) )
18328   {
18329     MTX_ERROR_MSG( "NULL Matrix" );
18330     return FALSE;
18331   }
18332 
18333   if( MTX_isNull( col_index ) )
18334   {
18335     MTX_ERROR_MSG( "NULL Matrix" );
18336     return FALSE;
18337   }
18338 
18339   if( dst->isReal != src->isReal || dst->nrows != row_index->nrows || dst->ncols != col_index->nrows )
18340   {
18341     if( !MTX_Malloc( dst, row_index->nrows, col_index->nrows, src->isReal ) )
18342     {
18343       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
18344       return FALSE;
18345     }
18346   }
18347 
18348   for( j = 0; j < col_index->nrows; j++ )
18349   {
18350     for( i = 0; i < row_index->nrows; i++ )
18351     {
18352       if( col_index->data[0][j] < 0 )
18353       {
18354         MTX_ERROR_MSG( "if( col_index->data[0][j] < 0 )" );
18355         return FALSE;
18356       }
18357       col = (unsigned) col_index->data[0][j];
18358       if( col >= src->ncols )
18359       {
18360         MTX_ERROR_MSG( "if( col >= src->ncols )" );
18361         return FALSE;
18362       }
18363 
18364       if( row_index->data[0][i] < 0 )
18365       {
18366         MTX_ERROR_MSG( "if( row_index->data[0][i] < 0 )" );
18367         return FALSE;
18368       }
18369       row = (unsigned) row_index->data[0][i];
18370       if( row >= src->nrows )
18371       {
18372         MTX_ERROR_MSG( "if( row >= src->nrows )" );
18373         return FALSE;
18374       }
18375 
18376       if( dst->isReal )
18377       {
18378         dst->data[j][i] = src->data[col][row];
18379       }
18380       else
18381       {
18382         dst->cplx[j][i].re = src->cplx[col][row].re;
18383         dst->cplx[j][i].im = src->cplx[col][row].im;
18384       }
18385     }
18386   }
18387 
18388   return TRUE;
18389 }
18390 
18391 
18392 BOOL MTX_SetIndexedValues( MTX *dst, const MTX *row_index, const MTX *col_index, const MTX *src )
18393 {
18394   unsigned i = 0;
18395   unsigned j = 0;
18396   unsigned row = 0;
18397   unsigned col = 0;
18398   unsigned maxrow = 0;
18399   unsigned maxcol = 0;
18400   double maxrow_d = 0.0;
18401   double maxcol_d = 0.0;
18402   double dumd;
18403 
18404   if( MTX_isNull( row_index ) )
18405   {
18406     MTX_ERROR_MSG( "NULL Matrix" );
18407     return FALSE;
18408   }
18409 
18410   if( MTX_isNull( col_index ) )
18411   {
18412     MTX_ERROR_MSG( "NULL Matrix" );
18413     return FALSE;
18414   }
18415 
18416   if( MTX_isNull( src ) )
18417   {
18418     MTX_ERROR_MSG( "NULL Matrix" );
18419     return FALSE;
18420   }
18421 
18422   // Check that the dimensions of the src matrix match the number of elemens in row_index and col_index.
18423   if( row_index->nrows != src->nrows )
18424   {
18425     MTX_ERROR_MSG( "if( row_index->nrows != src->nrows )" );
18426     return FALSE;
18427   }
18428   if( col_index->nrows != src->ncols )
18429   {
18430     MTX_ERROR_MSG( "if( col_index->nrows != src->ncols )" );
18431     return FALSE;
18432   }
18433 
18434   // Check the dimension of the destination matrix and resize if needed.
18435   if( !MTX_MaxColumn( row_index, 0, &maxrow_d, &dumd ) )
18436   {
18437     MTX_ERROR_MSG( "MTX_MaxColumn returned FALSE." );
18438     return FALSE;
18439   }
18440   if( maxrow_d < 0.0 )
18441   {
18442     MTX_ERROR_MSG( "if( maxrow_d < 0.0 )" );
18443     return FALSE;
18444   }
18445   maxrow = (unsigned) maxrow_d;
18446   if( !MTX_MaxColumn( col_index, 0, &maxcol_d, &dumd ) )
18447   {
18448     MTX_ERROR_MSG( "MTX_MaxColumn returned FALSE." );
18449     return FALSE;
18450   }
18451   if( maxcol_d < 0 )
18452   {
18453     MTX_ERROR_MSG( "if( maxcol_d < 0 )" );
18454     return FALSE;
18455   }
18456   maxcol = (unsigned) maxcol_d;
18457   if( maxrow >= dst->nrows )
18458   {
18459     if( maxcol >= dst->ncols )
18460     {
18461       if( !MTX_Redim( dst, maxrow+1, maxcol+1 ) )
18462       {
18463         MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
18464         return FALSE;
18465       }
18466     }
18467     else
18468     {
18469       if( !MTX_Redim( dst, maxrow+1, dst->ncols ) )
18470       {
18471         MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
18472         return FALSE;
18473       }
18474     }
18475   }
18476   else
18477   {
18478     if( maxcol >= dst->ncols )
18479     {
18480       if( !MTX_Redim( dst, dst->nrows, maxcol+1 ) )
18481       {
18482         MTX_ERROR_MSG( "MTX_Redim returned FALSE." );
18483         return FALSE;
18484       }
18485     }
18486   }
18487 
18488   if( !src->isReal && dst->isReal )
18489   {
18490     if( !MTX_ConvertRealToComplex( dst ) )
18491     {
18492       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
18493       return FALSE;
18494     }
18495   }
18496 
18497   for( j = 0; j < col_index->nrows; j++ )
18498   {
18499     for( i = 0; i < row_index->nrows; i++ )
18500     {
18501       if( col_index->data[0][j] < 0 )
18502       {
18503         MTX_ERROR_MSG( "if( col_index->data[0][j] < 0 )" );
18504         return FALSE;
18505       }
18506       col = (unsigned) col_index->data[0][j];
18507       if( col >= dst->ncols )
18508       {
18509         MTX_ERROR_MSG( "if( col >= dst->ncols )" );
18510         return FALSE;
18511       }
18512 
18513       if( row_index->data[0][i] < 0 )
18514       {
18515         MTX_ERROR_MSG( "if( row_index->data[0][i] < 0 )" );
18516         return FALSE;
18517       }
18518       row = (unsigned) row_index->data[0][i];
18519       if( row >= dst->nrows )
18520       {
18521         MTX_ERROR_MSG( "if( row >= dst->nrows )" );
18522         return FALSE;
18523       }
18524 
18525       if( dst->isReal )
18526       {
18527         dst->data[col][row] = src->data[j][i];
18528       }
18529       else
18530       {
18531         if( src->isReal )
18532         {
18533           dst->cplx[col][row].re = src->data[j][i];
18534           dst->cplx[col][row].im = 0.0;
18535         }
18536         else
18537         {
18538           dst->cplx[col][row].re = src->cplx[j][i].re;
18539           dst->cplx[col][row].im = src->cplx[j][i].im;
18540         }
18541       }
18542     }
18543   }
18544 
18545   return TRUE;
18546 }
18547 
18548 BOOL MTX_FFT2( const MTX *src, MTX *dst )
18549 {
18550   MTX M;
18551   MTX W;
18552   MTX_Init( &M );
18553   MTX_Init( &W );
18554 
18555   if( MTX_isNull( src ) )
18556   {
18557     MTX_ERROR_MSG( "src is a NULL matrix." );
18558     return FALSE;
18559   }
18560   if( dst == NULL )
18561   {
18562     MTX_ERROR_MSG( "dst is NULL." );
18563     return FALSE;
18564   }
18565 
18566   if( !MTX_FFT( src, dst ) )
18567   {
18568     MTX_ERROR_MSG( "MTX_FFT returned FALSE." );
18569     MTX_Free( &M );
18570     MTX_Free( &W );
18571     return FALSE;
18572   }
18573   if( !MTX_Transpose( dst, &M ) )
18574   {
18575     MTX_ERROR_MSG( "MTX_Transpose returned FALSE." );
18576     MTX_Free( &M );
18577     MTX_Free( &W );
18578     return FALSE;
18579   }
18580   if( !MTX_FFT( &M, &W ) )
18581   {
18582     MTX_ERROR_MSG( "MTX_FFT returned FALSE." );
18583     MTX_Free( &M );
18584     MTX_Free( &W );
18585     return FALSE;
18586   }
18587   if( !MTX_Transpose( &W, dst ) )
18588   {
18589     MTX_ERROR_MSG( "MTX_Transpose returned FALSE." );
18590     MTX_Free( &M );
18591     MTX_Free( &W );
18592     return FALSE;
18593   }
18594   MTX_Free( &M );
18595   MTX_Free( &W );
18596   return TRUE;
18597 }
18598 
18599 BOOL MTX_FFT2_Inplace( MTX *src )
18600 {
18601   MTX M;
18602   MTX W;
18603   MTX_Init( &M );
18604   MTX_Init( &W );
18605 
18606   if( MTX_isNull( src ) )
18607   {
18608     MTX_ERROR_MSG( "src is a NULL matrix." );
18609     return FALSE;
18610   }
18611 
18612   if( !MTX_FFT_Inplace( src ) )
18613   {
18614     MTX_ERROR_MSG( "MTX_FFT returned FALSE." );
18615     MTX_Free( &M );
18616     MTX_Free( &W );
18617     return FALSE;
18618   }
18619   if( !MTX_Transpose( src, &M ) )
18620   {
18621     MTX_ERROR_MSG( "MTX_Transpose returned FALSE." );
18622     MTX_Free( &M );
18623     MTX_Free( &W );
18624     return FALSE;
18625   }
18626   if( !MTX_FFT( &M, &W ) )
18627   {
18628     MTX_ERROR_MSG( "MTX_FFT returned FALSE." );
18629     MTX_Free( &M );
18630     MTX_Free( &W );
18631     return FALSE;
18632   }
18633   if( !MTX_Transpose( &W, src ) )
18634   {
18635     MTX_ERROR_MSG( "MTX_Transpose returned FALSE." );
18636     MTX_Free( &M );
18637     MTX_Free( &W );
18638     return FALSE;
18639   }
18640   MTX_Free( &M );
18641   MTX_Free( &W );
18642   return TRUE;
18643 }
18644 
18645 
18646 BOOL MTX_IFFT2( const MTX *src, MTX *dst )
18647 {
18648   MTX M;
18649   MTX W;
18650   MTX_Init( &M );
18651   MTX_Init( &W );
18652 
18653   if( MTX_isNull( src ) )
18654   {
18655     MTX_ERROR_MSG( "src is a NULL matrix." );
18656     return FALSE;
18657   }
18658   if( dst == NULL )
18659   {
18660     MTX_ERROR_MSG( "dst is NULL." );
18661     return FALSE;
18662   }
18663 
18664   if( !MTX_IFFT( src, dst ) )
18665   {
18666     MTX_ERROR_MSG( "MTX_IFFT returned FALSE." );
18667     MTX_Free( &M );
18668     MTX_Free( &W );
18669     return FALSE;
18670   }
18671   if( !MTX_Transpose( dst, &M ) )
18672   {
18673     MTX_ERROR_MSG( "MTX_Transpose returned FALSE." );
18674     MTX_Free( &M );
18675     MTX_Free( &W );
18676     return FALSE;
18677   }
18678   if( !MTX_IFFT( &M, &W ) )
18679   {
18680     MTX_ERROR_MSG( "MTX_IFFT returned FALSE." );
18681     MTX_Free( &M );
18682     MTX_Free( &W );
18683     return FALSE;
18684   }
18685   if( !MTX_Transpose( &W, dst ) )
18686   {
18687     MTX_ERROR_MSG( "MTX_Transpose returned FALSE." );
18688     MTX_Free( &M );
18689     MTX_Free( &W );
18690     return FALSE;
18691   }
18692   MTX_Free( &M );
18693   MTX_Free( &W );
18694   return TRUE;
18695 }
18696 
18697 
18698 BOOL MTX_IFFT2_Inplace( MTX *src )
18699 {
18700   MTX M;
18701   MTX W;
18702   MTX_Init( &M );
18703   MTX_Init( &W );
18704 
18705   if( MTX_isNull( src ) )
18706   {
18707     MTX_ERROR_MSG( "src is a NULL matrix." );
18708     return FALSE;
18709   }
18710 
18711   if( !MTX_IFFT_Inplace( src ) )
18712   {
18713     MTX_ERROR_MSG( "MTX_IFFT returned FALSE." );
18714     MTX_Free( &M );
18715     MTX_Free( &W );
18716     return FALSE;
18717   }
18718   if( !MTX_Transpose( src, &M ) )
18719   {
18720     MTX_ERROR_MSG( "MTX_Transpose returned FALSE." );
18721     MTX_Free( &M );
18722     MTX_Free( &W );
18723     return FALSE;
18724   }
18725   if( !MTX_IFFT( &M, &W ) )
18726   {
18727     MTX_ERROR_MSG( "MTX_IFFT returned FALSE." );
18728     MTX_Free( &M );
18729     MTX_Free( &W );
18730     return FALSE;
18731   }
18732   if( !MTX_Transpose( &W, src ) )
18733   {
18734     MTX_ERROR_MSG( "MTX_Transpose returned FALSE." );
18735     MTX_Free( &M );
18736     MTX_Free( &W );
18737     return FALSE;
18738   }
18739   MTX_Free( &M );
18740   MTX_Free( &W );
18741   return TRUE;
18742 }
18743 
18744 
18745 BOOL MTX_FFT( const MTX *src, MTX *dst )
18746 {
18747   return MTX_static_fft( src, dst, TRUE );
18748 }
18749 
18750 BOOL MTX_IFFT( const MTX *src, MTX *dst )
18751 {
18752   return MTX_static_fft( src, dst, FALSE );
18753 }
18754 
18755 BOOL MTX_FFT_Inplace( MTX *src )
18756 {
18757   return MTX_static_fft_inplace( src, TRUE );
18758 }
18759 
18760 BOOL MTX_IFFT_Inplace( MTX *src )
18761 {
18762   return MTX_static_fft_inplace( src, FALSE );
18763 }
18764 
18765 
18766 
18767 
18768 
18769 // static
18770 BOOL MTX_static_fft(
18771                     const MTX *src, //!< The source matrix.
18772                     MTX *dst, //!< The result matrix (always complex).
18773                     BOOL isFwd //!< A boolean to indicate if this is a fwd transform or the inverse transform
18774                     )
18775 {
18776 
18777   if( !MTX_Copy( src, dst ) )
18778   {
18779     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
18780     return FALSE;
18781   }
18782 
18783   // Use the inplace KISS FFT function.
18784   return MTX_static_fft_inplace( dst, isFwd );
18785 
18786 }
18787 
18788 
18789 
18790 
18791 
18792 // static
18793 BOOL MTX_static_fft_inplace(
18794                             MTX *src, //!< The source matrix.
18795                             BOOL isFwd //!< A boolean to indicate if this is a fwd transform or the inverse transform
18796                             )
18797 {
18798   unsigned j = 0;
18799   double length = 0.0; // The length of the fft to be performed (as a double).
18800 
18801 
18802   // This is the configuration for the KISS FFT. (it's a pointer)
18803   kiss_fft_cfg fft_config;
18804 
18805   // This is the data type pointer used by KISS FFT.
18806   // It is the same as stComplex*
18807   kiss_fft_cpx *pKissComplexData = NULL;
18808 
18809   // Get the fft length.
18810   length = src->nrows;
18811 
18812 
18813   // KISS will work inplace.
18814   if( src->isReal )
18815   {
18816     if( !MTX_ConvertRealToComplex( src ) )
18817     {
18818       MTX_ERROR_MSG( "MTX_ConvertRealToComplex returned FALSE." );
18819       return FALSE;
18820     }
18821   }
18822 
18823   // special case
18824   if( length == 1 )
18825   {
18826     return TRUE;
18827   }
18828 
18829   // Set up the FFT engine
18830   //
18831   if( isFwd )
18832   {
18833     // for FFT
18834     fft_config = kiss_fft_alloc( (unsigned)length, 0, 0, 0 );
18835   }
18836   else
18837   {
18838     // for IFFT
18839     fft_config = kiss_fft_alloc( (unsigned)length, 1, 0, 0 );
18840   }
18841   if( fft_config == NULL )
18842   {
18843     MTX_ERROR_MSG( "if( fft_config == NULL )" );
18844     return FALSE;
18845   }
18846 
18847   // Compute the fft of each of the columns.
18848   for( j = 0; j < src->ncols; j++ )
18849   {
18850     // The casting into the kiss struct pointer is allowed because the  
18851     // structs are defined identically.
18852     pKissComplexData = (kiss_fft_cpx *)src->cplx[j];
18853 
18854     // inplace FFT is allowed for kiss fft
18855     kiss_fft( fft_config, pKissComplexData, pKissComplexData );    
18856   }
18857 
18858   if( !isFwd )
18859   {
18860     // scaling must be done
18861     if( !MTX_Multiply_Scalar( src, 1.0/length ) )
18862     {
18863       MTX_ERROR_MSG( "MTX_Multiply_Scalar returned FALSE." );
18864       return FALSE;
18865     }
18866   }
18867 
18868   // Free the KISS FFT configuration
18869   if( fft_config )
18870   {
18871     kiss_fft_free( fft_config );
18872     fft_config = NULL;
18873   }
18874 
18875 
18876   return TRUE;
18877 }
18878 
18879 
18880 BOOL MTX_sin( MTX *src )
18881 {
18882   unsigned i = 0;
18883   unsigned j = 0;
18884   double re;
18885   double im;
18886 
18887   if( MTX_isNull( src ) )
18888   {
18889     MTX_ERROR_MSG( "NULL Matrix" );
18890     return FALSE;
18891   }
18892 
18893 
18894   if( src->isReal )
18895   {
18896     for( j = 0; j < src->ncols; j++ )
18897     {
18898       for( i = 0; i < src->nrows; i++ )
18899       {
18900         src->data[j][i] = sin( src->data[j][i] );
18901       }
18902     }
18903   }
18904   else
18905   {
18906     for( j = 0; j < src->ncols; j++ )
18907     {
18908       for( i = 0; i < src->nrows; i++ )
18909       {      
18910         re = src->cplx[j][i].re;
18911         im = src->cplx[j][i].im;
18912         src->cplx[j][i].re = sin(re)*cosh(im);
18913         src->cplx[j][i].im = cos(re)*sinh(im);
18914       }
18915     }
18916   }
18917   return TRUE;
18918 
18919 }
18920 
18921 BOOL MTX_sinc( MTX *src )
18922 {
18923   unsigned i = 0;
18924   unsigned j = 0;
18925   MTX copysrc;
18926   double re = 0.0;
18927   double im = 0.0;
18928 
18929   MTX_Init( &copysrc );
18930 
18931   if( MTX_isNull( src ) )
18932   {
18933     MTX_ERROR_MSG( "NULL Matrix" );
18934     return FALSE;
18935   }
18936 
18937   if( !MTX_Multiply_Scalar( src, PI ) )
18938   {
18939     MTX_ERROR_MSG( "MTX_Multiply_Scalar returned FALSE." );
18940     return FALSE;
18941   }
18942 
18943 
18944   // make a copy
18945   if( !MTX_Copy( src, &copysrc ) )
18946   {
18947     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
18948     return FALSE;
18949   }
18950 
18951   // compute the sin of the values
18952   if( !MTX_sin( src ) )
18953   {
18954     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
18955     MTX_Free( &copysrc );
18956     return FALSE;
18957   }
18958 
18959   if( src->isReal )
18960   {
18961     for( j = 0; j < src->ncols; j++ )
18962     {
18963       for( i = 0; i < src->nrows; i++ )
18964       {
18965         if( copysrc.data[j][i] == 0.0 )
18966           src->data[j][i] = 1.0;
18967         else
18968           src->data[j][i] /= copysrc.data[j][i];
18969       }
18970     }
18971   }
18972   else
18973   {
18974     for( j = 0; j < src->ncols; j++ )
18975     {
18976       for( i = 0; i < src->nrows; i++ )
18977       {
18978         if( copysrc.cplx[j][i].re == 0.0 && copysrc.cplx[j][i].im == 0.0 )
18979         {
18980           src->cplx[j][i].re = 1.0;
18981           src->cplx[j][i].im = 0.0;
18982         }
18983         else
18984         {
18985           MTX_static_quick_complex_divide( &src->cplx[j][i].re, &src->cplx[j][i].im, &copysrc.cplx[j][i].re, &copysrc.cplx[j][i].im, &re, &im );
18986           src->cplx[j][i].re = re;
18987           src->cplx[j][i].im = im;
18988         }
18989       }
18990     }
18991   }
18992 
18993   MTX_Free(&copysrc);
18994   return TRUE;
18995 }
18996 
18997 BOOL MTX_sinh( MTX *src )
18998 {
18999   unsigned i = 0;
19000   unsigned j = 0;
19001 
19002 
19003   if( MTX_isNull( src ) )
19004   {
19005     MTX_ERROR_MSG( "NULL Matrix" );
19006     return FALSE;
19007   }
19008 
19009 
19010   if( src->isReal )
19011   {
19012     for( j = 0; j < src->ncols; j++ )
19013     {
19014       for( i = 0; i < src->nrows; i++ )
19015       {
19016         src->data[j][i] = sinh( src->data[j][i] );
19017       }
19018     }    
19019   }
19020   else
19021   {
19022     // sinh = (exp(x) - exp(-x))/2.0
19023     MTX epX; // e^x
19024     MTX emX; // e-x
19025 
19026     MTX_Init( &epX );
19027     MTX_Init( &emX );
19028 
19029     if( !MTX_Copy( src, &epX ) )
19030     {
19031       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19032       MTX_Free(&epX);
19033       return FALSE;
19034     }
19035     if( !MTX_Copy( src, &emX ) )
19036     {
19037       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19038       MTX_Free(&epX);
19039       MTX_Free(&emX);
19040       return FALSE;
19041     }
19042     if( !MTX_Negate( &emX ) )
19043     {
19044       MTX_ERROR_MSG( "MTX_Negate returned FALSE." );
19045       MTX_Free(&epX);
19046       MTX_Free(&emX);
19047       return FALSE;
19048     }
19049 
19050     if( !MTX_Exp( &epX ) )
19051     {
19052       MTX_ERROR_MSG( "MTX_Exp returned FALSE." );
19053       MTX_Free(&epX);
19054       MTX_Free(&emX);
19055       return FALSE;
19056     }
19057     if( !MTX_Exp( &emX ) )
19058     {
19059       MTX_ERROR_MSG( "MTX_Exp returned FALSE." );
19060       MTX_Free(&epX);
19061       MTX_Free(&emX);
19062       return FALSE;
19063     }
19064 
19065     if( !MTX_Subtract( src, &epX, &emX ) )
19066     {
19067       MTX_ERROR_MSG( "MTX_Subtract returned FALSE." );
19068       MTX_Free(&epX);
19069       MTX_Free(&emX);
19070       return FALSE;
19071     }
19072     if( !MTX_Multiply_Scalar( src, 0.5 ) )
19073     {
19074       MTX_ERROR_MSG( "MTX_Multiply_Scalar returned FALSE." );
19075       MTX_Free(&epX);
19076       MTX_Free(&emX);
19077       return FALSE;
19078     }
19079 
19080     MTX_Free(&epX);
19081     MTX_Free(&emX);
19082   }
19083   return TRUE;
19084 }
19085 
19086 BOOL MTX_asinh( MTX *src )
19087 {
19088   // asinh = ln (x+sqrt(1+x^2))
19089   MTX sqrtOnePlusX2;
19090   MTX_Init( &sqrtOnePlusX2 );
19091 
19092   if( MTX_isNull( src ) )
19093   {
19094     MTX_ERROR_MSG( "NULL Matrix" );
19095     return FALSE;
19096   }
19097 
19098 
19099   if( !MTX_Copy(src,&sqrtOnePlusX2) )
19100   {
19101     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19102     MTX_Free(&sqrtOnePlusX2);
19103     return FALSE;
19104   }
19105   if( !MTX_Sqr(&sqrtOnePlusX2) )
19106   {
19107     MTX_ERROR_MSG( "MTX_Sqr returned FALSE." );
19108     MTX_Free(&sqrtOnePlusX2);
19109     return FALSE;
19110   }
19111   if( !MTX_Increment(&sqrtOnePlusX2) )
19112   {
19113     MTX_ERROR_MSG( "MTX_Increment returned FALSE." );
19114     MTX_Free(&sqrtOnePlusX2);
19115     return FALSE;
19116   }
19117   if( !MTX_Sqrt(&sqrtOnePlusX2) )
19118   {
19119     MTX_ERROR_MSG( "MTX_Sqrt returned FALSE." );
19120     MTX_Free(&sqrtOnePlusX2);
19121     return FALSE;
19122   }
19123   if( !MTX_Add_Inplace( src, &sqrtOnePlusX2 ) )
19124   {
19125     MTX_ERROR_MSG( "MTX_Add_Inplace returned FALSE." );
19126     MTX_Free(&sqrtOnePlusX2);
19127     return FALSE;
19128   }
19129   if( !MTX_Ln( src ) )
19130   {
19131     MTX_ERROR_MSG( "MTX_Ln returned FALSE." );
19132     MTX_Free(&sqrtOnePlusX2);
19133     return FALSE;
19134   }
19135 
19136   MTX_Free(&sqrtOnePlusX2);
19137   return TRUE;
19138 }
19139 
19140 
19141 BOOL MTX_cos( MTX *src )
19142 {
19143   unsigned i = 0;
19144   unsigned j = 0;
19145   double re;
19146   double im;
19147 
19148   if( MTX_isNull( src ) )
19149   {
19150     MTX_ERROR_MSG( "NULL Matrix" );
19151     return FALSE;
19152   }
19153 
19154 
19155   if( src->isReal )
19156   {
19157     for( j = 0; j < src->ncols; j++ )
19158     {
19159       for( i = 0; i < src->nrows; i++ )
19160       {
19161         src->data[j][i] = cos( src->data[j][i] );
19162       }
19163     }
19164   }
19165   else
19166   {
19167     for( j = 0; j < src->ncols; j++ )
19168     {
19169       for( i = 0; i < src->nrows; i++ )
19170       {      
19171         re = src->cplx[j][i].re;
19172         im = src->cplx[j][i].im;
19173         src->cplx[j][i].re = cos(re)*cosh(im);
19174         src->cplx[j][i].im = -sin(re)*sinh(im);
19175       }
19176     }
19177   }
19178   return TRUE;
19179 
19180 }
19181 
19182 BOOL MTX_cosh( MTX *src )
19183 {
19184   unsigned i = 0;
19185   unsigned j = 0;
19186 
19187   if( MTX_isNull( src ) )
19188   {
19189     MTX_ERROR_MSG( "NULL Matrix" );
19190     return FALSE;
19191   }
19192 
19193   if( src->isReal )
19194   {
19195     for( j = 0; j < src->ncols; j++ )
19196     {
19197       for( i = 0; i < src->nrows; i++ )
19198       {
19199         src->data[j][i] = cosh( src->data[j][i] );        
19200       }
19201     }
19202     return TRUE;
19203   }
19204   else
19205   {
19206     // cosh = (exp(x) + exp(-x))/2.0
19207     MTX epX; // e^x
19208     MTX emX; // e-x
19209 
19210     MTX_Init( &epX );
19211     MTX_Init( &emX );
19212 
19213     if( !MTX_Copy( src, &epX ) )
19214     {
19215       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19216       MTX_Free( &epX );
19217       MTX_Free( &emX );
19218       return FALSE;
19219     }
19220     if( !MTX_Copy( src, &emX ) )
19221     {
19222       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19223       MTX_Free( &epX );
19224       MTX_Free( &emX );
19225       return FALSE;
19226     }
19227     if( !MTX_Negate( &emX ) )
19228     {
19229       MTX_ERROR_MSG( "MTX_Negate returned FALSE." );
19230       MTX_Free( &epX );
19231       MTX_Free( &emX );
19232       return FALSE;
19233     }
19234 
19235     if( !MTX_Exp( &epX ) )
19236     {
19237       MTX_ERROR_MSG( "MTX_Exp returned FALSE." );
19238       MTX_Free( &epX );
19239       MTX_Free( &emX );
19240       return FALSE;
19241     }
19242     if( !MTX_Exp( &emX ) )
19243     {
19244       MTX_ERROR_MSG( "MTX_Exp returned FALSE." );
19245       MTX_Free( &epX );
19246       MTX_Free( &emX );
19247       return FALSE;
19248     }
19249 
19250     if( !MTX_Add( src, &epX, &emX ) )
19251     {
19252       MTX_ERROR_MSG( "MTX_Add returned FALSE." );
19253       MTX_Free( &epX );
19254       MTX_Free( &emX );
19255       return FALSE;
19256     }
19257     if( !MTX_Multiply_Scalar( src, 0.5 ) )
19258     {
19259       MTX_ERROR_MSG( "MTX_Multiply_Scalar returned FALSE." );
19260       MTX_Free( &epX );
19261       MTX_Free( &emX );
19262       return FALSE;
19263     }
19264 
19265     MTX_Free(&epX);
19266     MTX_Free(&emX);
19267   }
19268   return TRUE;
19269 }
19270 
19271 BOOL MTX_acosh( MTX *src )
19272 {  
19273   // acosh = ln( z + sqrt(z+1)*sqrt(z-1) )
19274   MTX sXp1;
19275   MTX sXm1;
19276   MTX_Init( &sXp1 );
19277   MTX_Init( &sXm1 );
19278 
19279   if( MTX_isNull( src ) )
19280   {
19281     MTX_ERROR_MSG( "NULL Matrix" );
19282     return FALSE;
19283   }
19284 
19285 
19286   if( !MTX_Copy(src,&sXp1) )
19287   {
19288     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19289     MTX_Free(&sXp1);
19290     return FALSE;
19291   }
19292   if( !MTX_Copy(src,&sXm1) )
19293   {
19294     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19295     MTX_Free(&sXp1);
19296     MTX_Free(&sXm1);
19297     return FALSE;
19298   }
19299 
19300   // acosh = ln( z + sqrt(z+1)*sqrt(z-1) )
19301 
19302   if( !MTX_Increment(&sXp1) )
19303   {
19304     MTX_ERROR_MSG( "MTX_Increment returned FALSE." );
19305     MTX_Free(&sXp1);
19306     MTX_Free(&sXm1);
19307     return FALSE;
19308   }
19309   if( !MTX_Decrement(&sXm1) )
19310   {
19311     MTX_ERROR_MSG( "MTX_Decrement returned FALSE." );
19312     MTX_Free(&sXp1);
19313     MTX_Free(&sXm1);
19314     return FALSE;
19315   }
19316   if( !MTX_Sqrt(&sXp1) )
19317   {
19318     MTX_ERROR_MSG( "MTX_Sqrt returned FALSE." );
19319     MTX_Free(&sXp1);
19320     MTX_Free(&sXm1);
19321     return FALSE;
19322   }
19323   if( !MTX_Sqrt(&sXm1) )
19324   {
19325     MTX_ERROR_MSG( "MTX_Sqrt returned FALSE." );
19326     MTX_Free(&sXp1);
19327     MTX_Free(&sXm1);
19328     return FALSE;
19329   }
19330   if( !MTX_DotMultiply_Inplace( &sXp1, &sXm1 ) )
19331   {
19332     MTX_ERROR_MSG( "MTX_DotMultiply_Inplace returned FALSE." );
19333     MTX_Free(&sXp1);
19334     MTX_Free(&sXm1);
19335     return FALSE;
19336   }
19337   if( !MTX_Add_Inplace( src, &sXp1 ) )
19338   {
19339     MTX_ERROR_MSG( "MTX_Add_Inplace returned FALSE." );
19340     MTX_Free(&sXp1);
19341     MTX_Free(&sXm1);
19342     return FALSE;
19343   }
19344   MTX_Free(&sXp1);
19345   MTX_Free(&sXm1);
19346 
19347   if( !MTX_Ln( src ) )
19348   {
19349     MTX_ERROR_MSG( "MTX_Ln returned FALSE." );
19350     return FALSE;
19351   }
19352   return TRUE;
19353 }
19354 
19355 
19356 BOOL MTX_tan( MTX *src )
19357 {
19358   unsigned i = 0;
19359   unsigned j = 0;
19360 
19361   if( MTX_isNull( src ) )
19362   {
19363     MTX_ERROR_MSG( "NULL Matrix" );
19364     return FALSE;
19365   }
19366 
19367   if( src->isReal )
19368   {
19369     for( j = 0; j < src->ncols; j++ )
19370     {
19371       for( i = 0; i < src->nrows; i++ )
19372       {
19373         src->data[j][i] = tan( src->data[j][i] );        
19374       }
19375     }
19376     return TRUE;
19377   }
19378   else
19379   {
19380     MTX cos_src;
19381     MTX_Init(&cos_src);
19382 
19383     if( !MTX_Copy(src,&cos_src) )
19384     {
19385       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19386       MTX_Free(&cos_src);
19387       return FALSE;
19388     }
19389 
19390     if( !MTX_cos(&cos_src) )
19391     {
19392       MTX_ERROR_MSG( "MTX_cos returned FALSE." );
19393       MTX_Free(&cos_src);
19394       return FALSE;
19395     }
19396 
19397     if( !MTX_sin(src) )
19398     {
19399       MTX_ERROR_MSG( "MTX_sin returned FALSE." );
19400       MTX_Free(&cos_src);
19401       return FALSE;
19402     }
19403 
19404     if( !MTX_DotDivide_Inplace( src, &cos_src ) )
19405     {
19406       MTX_ERROR_MSG( "MTX_DotDivide_Inplace returned FALSE." );
19407       MTX_Free(&cos_src);
19408       return FALSE;
19409     }
19410 
19411     MTX_Free(&cos_src);
19412   }
19413   return TRUE;
19414 }
19415 
19416 BOOL MTX_tanh( MTX *src )
19417 {
19418   unsigned i = 0;
19419   unsigned j = 0;
19420 
19421   if( MTX_isNull( src ) )
19422   {
19423     MTX_ERROR_MSG( "NULL Matrix" );
19424     return FALSE;
19425   }
19426 
19427   if( src->isReal )
19428   {
19429     for( j = 0; j < src->ncols; j++ )
19430     {
19431       for( i = 0; i < src->nrows; i++ )
19432       {
19433         src->data[j][i] = tanh( src->data[j][i] );        
19434       }
19435     }
19436     return TRUE;
19437   }
19438   else
19439   {
19440     // tanh = (exp(2x)-1)/(exp(2x)+1)
19441     MTX e2Xm1; // exp(2x)-1
19442     MTX e2Xp1; // exp(2x)+1
19443 
19444     MTX_Init( &e2Xm1 );
19445     MTX_Init( &e2Xp1 );
19446 
19447     if( !MTX_Copy( src, &e2Xm1 ) )
19448     {
19449       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19450       MTX_Free( &e2Xm1 );
19451       MTX_Free( &e2Xp1 );
19452       return FALSE;
19453     }
19454     if( !MTX_Multiply_Scalar( &e2Xm1, 2.0 ) )
19455     {
19456       MTX_ERROR_MSG( "MTX_Multiply_Scalar returned FALSE." );
19457       MTX_Free( &e2Xm1 );
19458       MTX_Free( &e2Xp1 );
19459       return FALSE;
19460     }
19461 
19462     if( !MTX_Exp( &e2Xm1 ) )
19463     {
19464       MTX_ERROR_MSG( "MTX_Exp returned FALSE." );
19465       MTX_Free( &e2Xm1 );
19466       MTX_Free( &e2Xp1 );
19467       return FALSE;
19468     }
19469     if( !MTX_Copy( &e2Xm1, &e2Xp1 ) )
19470     {
19471       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19472       MTX_Free( &e2Xm1 );
19473       MTX_Free( &e2Xp1 );
19474       return FALSE;
19475     }
19476 
19477     if( !MTX_Decrement( &e2Xm1 ) )
19478     {
19479       MTX_ERROR_MSG( "MTX_Decrement returned FALSE." );
19480       MTX_Free( &e2Xm1 );
19481       MTX_Free( &e2Xp1 );
19482       return FALSE;
19483     }
19484     if( !MTX_Increment( &e2Xp1 ) )
19485     {
19486       MTX_ERROR_MSG( "MTX_Increment returned FALSE." );
19487       MTX_Free( &e2Xm1 );
19488       MTX_Free( &e2Xp1 );
19489       return FALSE;
19490     }
19491 
19492     if( !MTX_DotDivide_Inplace( &e2Xm1, &e2Xp1 ) )
19493     {
19494       MTX_ERROR_MSG( "MTX_DotDivide_Inplace returned FALSE." );
19495       MTX_Free( &e2Xm1 );
19496       MTX_Free( &e2Xp1 );
19497       return FALSE;
19498     }
19499 
19500     if( !MTX_Copy( &e2Xm1, src ) )
19501     {
19502       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19503       MTX_Free( &e2Xm1 );
19504       MTX_Free( &e2Xp1 );
19505       return FALSE;
19506     }
19507 
19508     MTX_Free(&e2Xm1);
19509     MTX_Free(&e2Xp1);
19510   }
19511   return TRUE;
19512 }
19513 
19514 
19515 BOOL MTX_atanh( MTX *src )
19516 {  
19517   // atanh = 0.5*( ln((1+z)/(1-z)) )
19518   MTX oneMx; // 1-x
19519 
19520   if( MTX_isNull( src ) )
19521   {
19522     MTX_ERROR_MSG( "NULL Matrix" );
19523     return FALSE;
19524   }
19525 
19526 
19527   // atanh = 0.5*( ln((1+z)/(1-z)) )
19528   MTX_Init( &oneMx );
19529 
19530   if( !MTX_Copy( src, &oneMx ) )
19531   {
19532     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19533     return FALSE;
19534   }
19535   if( !MTX_Increment( src ) )
19536   {
19537     MTX_ERROR_MSG( "MTX_Increment returned FALSE." );
19538     MTX_Free(&oneMx);
19539     return FALSE;
19540   }
19541   if( !MTX_Negate( &oneMx ) )
19542   {
19543     MTX_ERROR_MSG( "MTX_Negate returned FALSE." );
19544     MTX_Free(&oneMx);
19545     return FALSE;
19546   }
19547   if( !MTX_Increment( &oneMx ) )
19548   {
19549     MTX_ERROR_MSG( "MTX_Increment returned FALSE." );
19550     MTX_Free(&oneMx);
19551     return FALSE;
19552   }
19553 
19554   if( !MTX_DotDivide_Inplace( src, &oneMx ) )
19555   {
19556     MTX_ERROR_MSG( "MTX_DotDivide_Inplace returned FALSE." );
19557     MTX_Free(&oneMx);
19558     return FALSE;
19559   }
19560 
19561   MTX_Free(&oneMx);
19562 
19563   if( !MTX_Ln(src) )
19564   {
19565     MTX_ERROR_MSG( "MTX_Ln returned FALSE." );
19566     return FALSE;
19567   }
19568   if( !MTX_Multiply_Scalar( src, 0.5 ) )
19569   {
19570     MTX_ERROR_MSG( "MTX_Multiply_Scalar returned FALSE." );
19571     return FALSE;
19572   }
19573 
19574   return TRUE;
19575 }
19576 
19577 
19578 BOOL MTX_cot( MTX *src )
19579 {
19580   if( !MTX_tan( src ) )
19581   {
19582     MTX_ERROR_MSG( "MTX_tan returned FALSE." );
19583     return FALSE;
19584   }
19585 
19586   if( !MTX_Inv( src ) )
19587   {
19588     MTX_ERROR_MSG( "MTX_Inv returned FALSE." );
19589     return FALSE;
19590   }
19591 
19592   return TRUE;
19593 }
19594 
19595 BOOL MTX_coth( MTX *src )
19596 {
19597   if( !MTX_tanh( src ) )
19598   {
19599     MTX_ERROR_MSG( "MTX_tanh returned FALSE." );
19600     return FALSE;
19601   }
19602 
19603   if( !MTX_Inv( src ) )
19604   {
19605     MTX_ERROR_MSG( "MTX_Inv returned FALSE." );
19606     return FALSE;
19607   }
19608 
19609   return TRUE;
19610 }
19611 
19612 BOOL MTX_Inv( MTX *src )
19613 {
19614   unsigned i = 0;
19615   unsigned j = 0;
19616 
19617   if( MTX_isNull(src) )
19618   {
19619     MTX_ERROR_MSG( "NULL Matrix" );
19620     return FALSE;
19621   }
19622 
19623   if( src->isReal )
19624   {
19625     for( j = 0; j < src->ncols; j++ )
19626     {
19627       for( i = 0; i < src->nrows; i++ )
19628       {
19629         src->data[j][i] = 1.0 / src->data[j][i];
19630       }
19631     }
19632   }
19633   else
19634   {
19635     // 1/(A+Bi) = 1/(A+Bi) * (A-Bi)/(A-Bi) = conj/mag^2
19636     MTX magSrc;
19637     MTX_Init(&magSrc);
19638 
19639     if( !MTX_Magnitude(src,&magSrc) )
19640     {
19641       MTX_ERROR_MSG( "MTX_Magnitude returned FALSE." );
19642       MTX_Free(&magSrc);
19643       return FALSE;
19644     }
19645     if( !MTX_Sqr(&magSrc) )
19646     {
19647       MTX_ERROR_MSG( "MTX_Sqr returned FALSE." );
19648       MTX_Free(&magSrc);
19649       return FALSE;
19650     }
19651     if( !MTX_Conjugate(src) )
19652     {
19653       MTX_ERROR_MSG( "MTX_Conjugate returned FALSE." );
19654       MTX_Free(&magSrc);
19655       return FALSE;
19656     }
19657     if( !MTX_DotDivide_Inplace(src,&magSrc) )
19658     {
19659       MTX_ERROR_MSG( "MTX_DotDivide_Inplace returned FALSE." );
19660       MTX_Free(&magSrc);
19661       return FALSE;
19662     }
19663 
19664     MTX_Free(&magSrc);
19665   }
19666   return TRUE;
19667 }
19668 
19669 
19670 BOOL MTX_Colon( MTX *dst, const double start, const double increment, const double end )
19671 {
19672   unsigned i = 0;
19673   unsigned nrows = 0;
19674 
19675   if( increment == 0.0 )
19676   {
19677     MTX_ERROR_MSG( "if( increment == 0.0 )" );
19678     return FALSE;
19679   }
19680 
19681   if( increment > 0.0 )
19682   {
19683     if( end < start )
19684     {
19685       MTX_ERROR_MSG( "if( end < start )" );
19686       return FALSE;
19687     }
19688 
19689     // Determine the number of rows needed.
19690     nrows = (unsigned)floor( (end-start)/increment ) + 1;
19691 
19692     if( !MTX_Malloc( dst, nrows, 1, TRUE ) )
19693     {
19694       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
19695       return FALSE;
19696     }
19697 
19698     for( i = 0; i < nrows; i++ )
19699     {
19700       dst->data[0][i] = start + i*increment;
19701     }
19702   }
19703   else
19704   {
19705     if( start < end )
19706     {
19707       MTX_ERROR_MSG( "if( start < end )" );
19708       return FALSE;
19709     }
19710 
19711     // Determine the number of rows needed.
19712     nrows = abs((unsigned)floor( (end-start)/increment )) + 1;
19713 
19714     if( !MTX_Malloc( dst, nrows, 1, TRUE ) )
19715     {
19716       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
19717       return FALSE;
19718     }
19719 
19720     for( i = 0; i < nrows; i++ )
19721     {
19722       dst->data[0][i] = start + i*increment;
19723     }
19724   }
19725 
19726   return TRUE;
19727 }
19728 
19729 BOOL MTX_RemoveRowsAndColumns(
19730                               MTX *src, //!< The pointer to the matrix object.
19731                               const unsigned nrows, //!< The number of rows to remove (the length of the rows array).
19732                               const unsigned rows[], //!< The array of row indices to remove.
19733                               const unsigned ncols, //!< The number of columns to remove (the length of hte cols array).
19734                               const unsigned cols[]
19735 )
19736 {
19737   unsigned i = 0;
19738   unsigned j = 0;
19739   unsigned k = 0;
19740   unsigned col_index = 0;
19741   unsigned row_index = 0;
19742   MTX srcCopy;
19743   BOOL skip_row = FALSE;
19744   //char buffer[1024];
19745 
19746   if( MTX_isNull( src ) )
19747   {
19748     MTX_ERROR_MSG( "NULL Matrix" );
19749     return FALSE;
19750   }
19751 
19752   MTX_Init( &srcCopy );
19753 
19754   if( nrows > 0 )
19755   {
19756     if( rows == NULL )
19757     {
19758       MTX_ERROR_MSG( "rows is a NULL pointer." );
19759       return FALSE;
19760     }
19761   }
19762 
19763   if( ncols > 0 )
19764   {
19765     if( cols == NULL )
19766     {
19767       MTX_ERROR_MSG( "cols is a NULL pointer." );
19768       return FALSE;
19769     }
19770   }
19771 
19772   //MTX_PrintAutoWidth_ToBuffer( src, buffer, 1024, 6 );
19773   //printf( buffer );
19774 
19775   // First remove all the columns specified.
19776   for( j = 0; j < ncols; j++ )
19777   {
19778     col_index = cols[j];
19779     if( col_index-j >= src->ncols )
19780     {
19781       MTX_ERROR_MSG( "if( col_index-j >= src->ncols )" );
19782       return FALSE;
19783     }
19784 
19785     // The removal of columns is very efficient.
19786     // The index changes stepwise (minus j is needed).
19787     if( !MTX_RemoveColumn( src, col_index-j ) )
19788     {
19789       MTX_ERROR_MSG( "MTX_RemoveColumn returned FALSE." );
19790       return FALSE;
19791     }
19792   }
19793 
19794   //MTX_PrintAutoWidth_ToBuffer( src, buffer, 1024, 6 );
19795   //printf( buffer );
19796 
19797   // Make a copy of the src matrix (columns already removed).
19798   if( !MTX_Copy( src, &srcCopy ) )
19799   {
19800     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
19801     return FALSE;
19802   }
19803 
19804   // Check the indices of the rows specified for removal.
19805   for( i = 0; i < nrows; i++ )
19806   {
19807     if( rows[i] >= src->nrows )
19808     {
19809       MTX_ERROR_MSG( "if( rows[i] >= src->nrows )" );
19810       return FALSE;
19811     }
19812   }
19813 
19814   // Resize the original matrix accordingly.
19815   if( !MTX_Resize( src, src->nrows-nrows, src->ncols, src->isReal ) )
19816   {
19817     MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
19818     return FALSE;
19819   }
19820 
19821   // Copy back the data with the specified rows removed.
19822   for( i = 0; i < srcCopy.nrows; i++ )
19823   {
19824     skip_row = FALSE;
19825     for( row_index = 0; row_index < nrows; row_index++ )
19826     {
19827       if( i == rows[row_index] )
19828       {
19829         skip_row = TRUE;
19830         break;
19831       }
19832     }
19833 
19834     if( !skip_row )
19835     {
19836       if( src->isReal )
19837       {
19838         for( j = 0; j < src->ncols; j++ )
19839         {
19840           src->data[j][k] = srcCopy.data[j][i];
19841         }
19842       }
19843       else
19844       {
19845         for( j = 0; j < src->ncols; j++ )
19846         {
19847           src->cplx[j][k].re = srcCopy.cplx[j][i].re;
19848           src->cplx[j][k].im = srcCopy.cplx[j][i].im;
19849         }
19850       }
19851       k++;
19852     }
19853   }
19854 
19855   //MTX_PrintAutoWidth_ToBuffer( src, buffer, 1024, 6 );
19856   //printf( buffer );
19857 
19858   MTX_Free( &srcCopy );
19859 
19860   return TRUE;
19861 }
19862 
19863 
19864 // static
19865 BOOL MTX_IsNAN( double value )
19866 {
19867 #ifdef WIN32
19868   if( _isnan( value ) )
19869     return TRUE;
19870   else
19871     return FALSE;
19872 #else
19873   if( isnan( value ) )
19874     return TRUE;
19875   else
19876     return FALSE;
19877 #endif
19878 }
19879 
19880 
19881 // static
19882 BOOL MTX_IsPostiveINF( double value )
19883 {
19884 #ifdef WIN32
19885   if( _finite( value ) )
19886   {
19887     return FALSE;
19888   }
19889   else
19890   {
19891     if( value > 0 )
19892       return TRUE;
19893     else
19894       return FALSE;
19895   }
19896 #else
19897   if( isfinite( value ) )
19898   {
19899     return FALSE;
19900   }
19901   else
19902   {
19903     if( value > 0 )
19904       return TRUE;
19905     else
19906       return FALSE;
19907   }
19908 #endif
19909 }
19910 
19911 
19912 // static
19913 BOOL MTX_IsNegativeINF( double value )
19914 {
19915 #ifdef WIN32
19916   if( _finite( value ) )
19917   {
19918     return FALSE;
19919   }
19920   else
19921   {
19922     if( value < 0 )
19923       return TRUE;
19924     else
19925       return FALSE;
19926   }
19927 #else
19928   if( isfinite( value ) )
19929   {
19930     return FALSE;
19931   }
19932   else
19933   {
19934     if( value < 0 )
19935       return TRUE;
19936     else
19937       return FALSE;
19938   }
19939 #endif
19940 }
19941 
19942 // Get a value from the uniform distribution between 0 and 1.
19943 double MTX_static_get_rand_value()
19944 {
19945   double val;
19946   val = ((double)rand()) / ((double)RAND_MAX);
19947   return val;
19948 }
19949 
19950 // REFERENCE: 
19951 // Scheinerman, E. R (2006). "C++ for Mathematicians: An Introduction for Students and Professionals."
19952 // Chapman and Hall/CRC, Taylor and Francis Group. pp 61-63.
19953 //
19954 // static 
19955 double MTX_static_get_randn_value()
19956 {
19957   /*
19958   "The do-while loop generates points (x,y) uniformly in the square [-1,1]^2
19959   until one that is interior to the unit dist is found. Each pass through
19960   the loop has a pi/4 chance of succeeding, so after just a few iterations
19961   we are assured of finding a point chosed uniformly from the unit disk.
19962   Once the point (x,y) has been found, the rest of the algorithm follows the 
19963   Box-Muller method." 
19964   ...
19965   "The algorithm is capable of producing two independant normal random variables." (mu*x and mu*y) 
19966   Thus, the use of the static values.
19967   */
19968   static BOOL has_saved = FALSE;
19969   static double saved;
19970   double x;
19971   double y;
19972   double r;
19973   double mu;
19974 
19975   if( has_saved )
19976   {
19977     has_saved = FALSE;
19978     return saved;
19979   }
19980 
19981   do
19982   {
19983     x = MTX_static_get_rand_value()*2.0 - 1.0;
19984     y = MTX_static_get_rand_value()*2.0 - 1.0;
19985     r = x*x + y*y;
19986   } while( r >= 1.0 );
19987 
19988   mu = sqrt( -2.0 * log( r ) / r );
19989 
19990   saved = mu*y;
19991   has_saved = TRUE;
19992 
19993   return mu*x;
19994 }
19995 
19996 BOOL MTX_randn(
19997   MTX* M,
19998   const unsigned nrows,
19999   const unsigned ncols,  
20000   const unsigned seed
20001   )
20002 {
20003   unsigned j;
20004   unsigned i;
20005 
20006   if( M == NULL )
20007   {
20008     MTX_ERROR_MSG( "NULL input matrix." );
20009     return FALSE;
20010   }
20011   if( nrows == 0 || ncols == 0 )
20012   {
20013     MTX_ERROR_MSG( "if( nrows == 0 || ncols == 0 )" );
20014     return FALSE;
20015   }
20016   if( !MTX_Malloc( M, nrows, ncols, TRUE ) )
20017   {
20018     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
20019     return FALSE;
20020   }
20021   srand( seed ); // seed the rand function.
20022 
20023   for( j = 0; j < ncols; j++ )  
20024   {
20025     for( i = 0; i < nrows; i++ )    
20026     {
20027       M->data[j][i] = MTX_static_get_randn_value();
20028     }
20029   }
20030   
20031   return TRUE;
20032 }
20033 
20034 BOOL MTX_rand(
20035   MTX* M,
20036   const unsigned nrows,
20037   const unsigned ncols,  
20038   const unsigned seed
20039   )
20040 {  
20041   unsigned j;
20042   unsigned i;
20043 
20044   if( M == NULL )
20045   {
20046     MTX_ERROR_MSG( "NULL input matrix." );
20047     return FALSE;
20048   }
20049   if( nrows == 0 || ncols == 0 )
20050   {
20051     MTX_ERROR_MSG( "if( nrows == 0 || ncols == 0 )" );
20052     return FALSE;
20053   }
20054   if( !MTX_Malloc( M, nrows, ncols, TRUE ) )
20055   {
20056     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
20057     return FALSE;
20058   }
20059   srand( seed ); // seed the rand function.
20060 
20061   for( j = 0; j < ncols; j++ )  
20062   {
20063     for( i = 0; i < nrows; i++ )    
20064     {
20065       M->data[j][i] = MTX_static_get_rand_value();
20066     }
20067   }
20068   
20069   return TRUE;
20070 }
20071 
20072 
20073 
20074 
20075 #ifndef _MATRIX_NO_PLOTTING
20076 
20077 BOOL MTX_PlotQuick( MTX* M, const char* bmpfilename, const unsigned x_col, const unsigned y_col )
20078 {
20079   CPLOT_structSeries s; // The deep level series struct.
20080   CPLOT_structPlotOptions opt; // The plotting options.
20081   CPLOT P; // The plot 'object'.
20082   char xlabel[128];
20083   char ylabel[128];
20084   char slabel[128];
20085 
20086   if( MTX_isNull(M) )
20087   {
20088     MTX_ERROR_MSG( "NULL Matrix" );
20089     return FALSE;
20090   }
20091   if( bmpfilename == NULL )
20092   {
20093     MTX_ERROR_MSG( "bmpfilename is a NULL pointer." );
20094     return FALSE;
20095   }
20096 
20097   if( x_col > M->ncols )
20098   {
20099     MTX_ERROR_MSG( "if( x_col > M->ncols )" );
20100     return FALSE;
20101   }
20102   if( y_col > M->ncols )
20103   {
20104     MTX_ERROR_MSG( "if( y_col > M->ncols )" );
20105     return FALSE;
20106   }
20107 
20108   memset( &s, 0, sizeof(CPLOT_structSeries) );
20109   memset( &opt, 0, sizeof(CPLOT_structPlotOptions) );
20110 
20111   if( !CPLOT_PlotOptionsInit( &opt ) )
20112   {
20113     MTX_ERROR_MSG( "CPLOT_PlotOptionsInit returned FALSE." );
20114     return FALSE;
20115   }
20116 
20117   if( !CPLOT_Init( &P ) )
20118   {
20119     MTX_ERROR_MSG( "CPLOT_Init returned FALSE." );
20120     return FALSE;
20121   }
20122 
20123   opt.numberOfSeries = 1;
20124   opt.PlotSize_Height_cm = 8;
20125   opt.PlotSize_Width_cm = 10;
20126   opt.plotStatistics = 1;
20127   opt.title = (char*)bmpfilename;
20128 #ifndef _CRT_SECURE_NO_DEPRECATE
20129   if( sprintf_s( xlabel, 128, "column %d", x_col ) < 0 )
20130   {
20131     MTX_ERROR_MSG( "sprintf_s returned failure." );
20132     return FALSE;
20133   }
20134 #else
20135   if( sprintf( xlabel, "column %d", x_col ) < 0 )
20136   {
20137     MTX_ERROR_MSG( "sprintf returned failure." );
20138     return FALSE;
20139   }
20140 #endif
20141   opt.x.label = xlabel;
20142   opt.x.isGridOn = TRUE;
20143 #ifndef _CRT_SECURE_NO_DEPRECATE
20144   if( sprintf_s( ylabel, 128, "column %d", y_col ) < 0 )
20145   {
20146     MTX_ERROR_MSG( "sprintf_s returned failure." );
20147     return FALSE;
20148   }
20149 #else
20150   if( sprintf( ylabel, "column %d", y_col ) < 0 )
20151   {
20152     MTX_ERROR_MSG( "sprintf returned failure." );
20153     return FALSE;
20154   }
20155 #endif
20156   opt.y.label = ylabel;
20157   opt.y.isGridOn = TRUE;
20158 
20159   if( !CPLOT_SetPlotOptions( &P, &opt ) )
20160   {
20161     MTX_ERROR_MSG( "CPLOT_SetPlotOptions returned FALSE." );
20162     return FALSE;
20163   }
20164 
20165   s.color = CPLOT_BLUE;
20166   s.connected = TRUE;
20167 #ifndef _CRT_SECURE_NO_DEPRECATE
20168   if( sprintf_s( slabel, 128, "col %d vs %d", x_col, y_col ) < 0 )
20169   {
20170     MTX_ERROR_MSG( "sprintf_s returned failure." );
20171     return FALSE;
20172   }
20173 #else
20174   if( sprintf( slabel, "col %d vs %d", x_col, y_col ) < 0 )
20175   {
20176     MTX_ERROR_MSG( "sprintf returned failure." );
20177     return FALSE;
20178   }
20179 #endif
20180   s.label = slabel;
20181   s.markOutlierData = TRUE;
20182   s.n = M->nrows;
20183   s.precision = 6;
20184   s.units = NULL;
20185   s.X = M->data[x_col];
20186   s.Y = M->data[y_col];
20187 
20188   if( !CPLOT_Plot( &P, &s ) )
20189   {
20190     MTX_ERROR_MSG( "CPLOT_Plot returned FALSE." );
20191     return FALSE;
20192   }
20193 
20194   if( !CPLOT_SaveToFile( &P, bmpfilename ) )
20195   {
20196     MTX_ERROR_MSG( "CPLOT_SaveToFile returned FALSE." );
20197     return FALSE;
20198   }
20199 
20200   return TRUE;
20201 }
20202 
20203 
20204 BOOL MTX_Plot(
20205               const char* bmpfilename, //!< The output RLE compressed BITMAP filename.
20206               const char* title, //!< The plot title (NULL if not used).
20207               const unsigned plot_height_cm, //!< The plot height in cm.
20208               const unsigned plot_width_cm, //!< The plot width in cm.
20209               const BOOL includeStats, //!< A boolean to indicate if statistics info should be included on the plot.
20210               const BOOL isXGridOn, //!< A boolean to indicate if the x grid lines are on.
20211               const BOOL isYGridOn, //!< A boolean to indicate if the y grid lines are on.
20212               const char* xlabel, //!< The x axis label (NULL if not used).
20213               const char* ylabel, //!< The y axis label (NULL if not used).
20214               const MTX_structAxisOptions opt_x, //!< Limits and ticks for x.
20215               const MTX_structAxisOptions opt_y, //!< Limits and ticks for y.
20216               const MTX_PLOT_structSeries* series, //!< A pointer to an array of series structs.
20217               const unsigned nrSeries //!< The number of series.
20218               )
20219 {
20220   unsigned i = 0;
20221 
20222   CPLOT_structSeries s; // The deep level series struct.
20223   CPLOT_structPlotOptions opt; // The plotting options.
20224   CPLOT P; // The plot 'object'.
20225 
20226   double val = 0;
20227   double re = 0;
20228   double im = 0;
20229   double xmin = DBL_MAX;
20230   double xmax = -DBL_MAX;
20231   double ymin = DBL_MAX;
20232   double ymax = -DBL_MAX;
20233 
20234   typedef struct
20235   {
20236     double lowerlimit;
20237     double upperlimit;
20238     double tickstart;
20239     double ticksize;
20240     double tickend;
20241   }_structAxis;
20242   _structAxis x;
20243   _structAxis y;
20244 
20245   if( bmpfilename == NULL )
20246   {
20247     MTX_ERROR_MSG( "bmpfilename is a NULL pointer." );
20248     return FALSE;
20249   }
20250 
20251   if( plot_height_cm > 50 || plot_width_cm > 50 )
20252   {
20253     MTX_ERROR_MSG( "if( plot_height_cm > 50 || plot_width_cm > 50 )" );
20254     return FALSE;
20255   }
20256 
20257   memset( &s, 0, sizeof(CPLOT_structSeries) );
20258   memset( &opt, 0, sizeof(CPLOT_structPlotOptions) );
20259 
20260   if( !CPLOT_PlotOptionsInit( &opt ) )
20261   {
20262     MTX_ERROR_MSG( "CPLOT_PlotOptionsInit returned FALSE." );
20263     return FALSE;
20264   }
20265 
20266   if( !CPLOT_Init( &P ) )
20267   {
20268     MTX_ERROR_MSG( "CPLOT_Init returned FALSE." );
20269     return FALSE;
20270   }
20271 
20272   if( series == NULL )
20273   {
20274     MTX_ERROR_MSG( "series is a NULL pointer." );
20275     return FALSE;
20276   }
20277 
20278   if( nrSeries == 0 )
20279   {
20280     MTX_ERROR_MSG( "if( nrSeries == 0 )" );
20281     return FALSE;
20282   }
20283 
20284   // Check the input.
20285   for( i = 0; i < nrSeries; i++ )
20286   {
20287     if( MTX_isNull(series[i].M) )
20288     {
20289       MTX_ERROR_MSG( "NULL Matrix" );
20290       return FALSE;
20291     }
20292     if( !series[i].M->isReal )
20293     {
20294       MTX_ERROR_MSG( "if( !series[i].M->isReal )" );
20295       return FALSE; // only plot real data
20296     }
20297 
20298     if( series[i].x_col >= series[i].M->ncols )
20299     {
20300       MTX_ERROR_MSG( "if( series[i].x_col >= series[i].M->ncols )" );
20301       return FALSE;
20302     }
20303     if( series[i].y_col >= series[i].M->ncols )
20304     {
20305       MTX_ERROR_MSG( "if( series[i].y_col >= series[i].M->ncols )" );
20306       return FALSE;
20307     }
20308   }
20309 
20310   for( i = 0; i < nrSeries; i++ )
20311   {
20312     // Determine the maximum and minimum values for this series.
20313     // Why? because if we are plotting multiple series, we first have to
20314     // determine the windows maximum, minimums.
20315     if( !MTX_MinColumn( series[i].M, series[i].x_col, &re, &im ) )
20316     {
20317       MTX_ERROR_MSG( "MTX_MinColumn returned FALSE." );
20318       return FALSE;
20319     }
20320     if( re < xmin )
20321       xmin = re;
20322     if( !MTX_MaxColumn( series[i].M, series[i].x_col, &re, &im ) )
20323     {
20324       MTX_ERROR_MSG( "MTX_MaxColumn returned FALSE." );
20325       return FALSE;
20326     }
20327     if( re > xmax )
20328       xmax = re;
20329 
20330     if( !MTX_MinColumn( series[i].M, series[i].y_col, &re, &im ) )
20331     {
20332       MTX_ERROR_MSG( "MTX_MinColumn returned FALSE." );
20333       return FALSE;
20334     }
20335     if( re < ymin )
20336       ymin = re;
20337     if( !MTX_MaxColumn( series[i].M, series[i].y_col, &re, &im ) )
20338     {
20339       MTX_ERROR_MSG( "MTX_MaxColumn returned FALSE." );
20340       return FALSE;
20341     }
20342     if( re > ymax )
20343       ymax = re;
20344   }
20345 
20346 
20347   // First deal with determining the full window size
20348   // use the max min values already determined for all series if needed.
20349   // We do this because otherwise the plot window dimensions are determined
20350   // by the first series to be plotted.
20351 
20352   // Special case - all defaults indicated
20353   if( !opt_x.lowerlimit.doNotUseDefault &&
20354     !opt_x.upperlimit.doNotUseDefault &&
20355     !opt_x.tickstart.doNotUseDefault &&
20356     !opt_x.tickend.doNotUseDefault )
20357   {
20358     val = xmin;
20359     if( val < 0 )
20360     {
20361       val = -ceil( -val * 10.0 ) / 10.0;
20362     }
20363     else
20364     {
20365       val = floor( val * 10.0 ) / 10.0;
20366     }
20367     x.lowerlimit = val;
20368 
20369     val = xmax;
20370     if( val < 0 )
20371     {
20372       val = -floor( -val * 10.0 ) / 10.0;
20373     }
20374     else
20375     {
20376       val = ceil( val * 10.0 ) / 10.0;
20377     }
20378     x.upperlimit = val;
20379 
20380 
20381     if( x.lowerlimit == x.upperlimit )
20382     {
20383       x.lowerlimit -= x.lowerlimit/100.0;
20384       x.upperlimit += x.upperlimit/100.0;
20385     }
20386 
20387     x.tickstart = x.lowerlimit;
20388     x.ticksize = (x.upperlimit-x.lowerlimit)/5.0;
20389     x.tickend = x.upperlimit;
20390   }
20391   else
20392   {
20393     // deal with mixed or all user specified case
20394 
20395     if( opt_x.lowerlimit.doNotUseDefault )
20396       x.lowerlimit = opt_x.lowerlimit.val;
20397     else
20398       x.lowerlimit = xmin;
20399 
20400     if( opt_x.upperlimit.doNotUseDefault )
20401       x.upperlimit = opt_x.upperlimit.val;
20402     else
20403       x.upperlimit = xmax;
20404 
20405     if( opt_x.tickstart.doNotUseDefault )
20406       x.tickstart = opt_x.tickstart.val;
20407     else
20408       x.tickstart = x.lowerlimit;
20409 
20410     if( opt_x.tickend.doNotUseDefault )
20411       x.tickend = opt_x.tickend.val;
20412     else
20413       x.tickend = x.upperlimit;
20414 
20415     if( opt_x.ticksize.doNotUseDefault )
20416       x.ticksize = opt_x.ticksize.val;
20417     else
20418       x.ticksize = (x.tickend - x.tickstart)/5.0;
20419   }
20420   if( x.lowerlimit == x.upperlimit )
20421   {
20422     MTX_ERROR_MSG( "if( x.lowerlimit == x.upperlimit )" );
20423     return FALSE;
20424   }
20425   if( x.tickstart == x.tickend )
20426   {
20427     MTX_ERROR_MSG( "if( x.tickstart == x.tickend )" );
20428     return FALSE;
20429   }
20430   if( x.ticksize <= 0.0 )
20431   {
20432     MTX_ERROR_MSG( "if( x.ticksize <= 0.0 )" );
20433     return FALSE;
20434   }
20435 
20436 
20437 
20438   // Special case - all defaults indicated
20439   if( !opt_y.lowerlimit.doNotUseDefault &&
20440     !opt_y.upperlimit.doNotUseDefault &&
20441     !opt_y.tickstart.doNotUseDefault &&
20442     !opt_y.tickend.doNotUseDefault )
20443   {
20444     val = ymin;
20445     if( val < 0 )
20446     {
20447       val = -ceil( -val * 10.0 ) / 10.0;
20448     }
20449     else
20450     {
20451       val = floor( val * 10.0 ) / 10.0;
20452     }
20453     y.lowerlimit = val;
20454 
20455     val = ymax;
20456     if( val < 0 )
20457     {
20458       val = -floor( -val * 10.0 ) / 10.0;
20459     }
20460     else
20461     {
20462       val = ceil( val * 10.0 ) / 10.0;
20463     }
20464     y.upperlimit = val;
20465 
20466 
20467     if( y.lowerlimit == y.upperlimit )
20468     {
20469       y.lowerlimit -= y.lowerlimit/100.0;
20470       y.upperlimit += y.upperlimit/100.0;
20471     }
20472 
20473     y.tickstart = y.lowerlimit;
20474     y.ticksize = (y.upperlimit-y.lowerlimit)/10.0;
20475     y.tickend = y.upperlimit;
20476   }
20477   else
20478   {
20479     // deal with mixed or all user specified case
20480 
20481     if( opt_y.lowerlimit.doNotUseDefault )
20482       y.lowerlimit = opt_y.lowerlimit.val;
20483     else
20484       y.lowerlimit = ymin;
20485 
20486     if( opt_y.upperlimit.doNotUseDefault )
20487       y.upperlimit = opt_y.upperlimit.val;
20488     else
20489       y.upperlimit = ymax;
20490 
20491     if( opt_y.tickstart.doNotUseDefault )
20492       y.tickstart = opt_y.tickstart.val;
20493     else
20494       y.tickstart = y.lowerlimit;
20495 
20496     if( opt_y.tickend.doNotUseDefault )
20497       y.tickend = opt_y.tickend.val;
20498     else
20499       y.tickend = y.upperlimit;
20500 
20501     if( opt_y.ticksize.doNotUseDefault )
20502       y.ticksize = opt_y.ticksize.val;
20503     else
20504       y.ticksize = (y.tickend - y.tickstart)/10.0;
20505   }
20506   if( y.lowerlimit == y.upperlimit )
20507   {
20508     MTX_ERROR_MSG( "if( y.lowerlimit == y.upperlimit )" );
20509     return FALSE;
20510   }
20511   if( y.tickstart == y.tickend )
20512   {
20513     MTX_ERROR_MSG( "if( y.tickstart == y.tickend )" );
20514     return FALSE;
20515   }
20516   if( y.ticksize <= 0.0 )
20517   {
20518     MTX_ERROR_MSG( "if( y.ticksize <= 0.0 )" );
20519     return FALSE;
20520   }
20521 
20522   // All the values for lower, upper, and ticks are now set.
20523 
20524   opt.x.lowerlimit.val = x.lowerlimit;
20525   opt.x.upperlimit.val = x.upperlimit;
20526   opt.x.tickstart.val = x.tickstart;
20527   opt.x.ticksize.val = x.ticksize;
20528   opt.x.tickend.val = x.tickend;
20529 
20530   opt.x.lowerlimit.doNotUseDefault = TRUE;
20531   opt.x.upperlimit.doNotUseDefault = TRUE;
20532   opt.x.tickstart.doNotUseDefault = TRUE;
20533   opt.x.ticksize.doNotUseDefault = TRUE;
20534   opt.x.tickend.doNotUseDefault = TRUE;
20535 
20536   opt.y.lowerlimit.val = y.lowerlimit;
20537   opt.y.upperlimit.val = y.upperlimit;
20538   opt.y.tickstart.val = y.tickstart;
20539   opt.y.ticksize.val = y.ticksize;
20540   opt.y.tickend.val = y.tickend;
20541 
20542   opt.y.lowerlimit.doNotUseDefault = TRUE;
20543   opt.y.upperlimit.doNotUseDefault = TRUE;
20544   opt.y.tickstart.doNotUseDefault = TRUE;
20545   opt.y.ticksize.doNotUseDefault = TRUE;
20546   opt.y.tickend.doNotUseDefault = TRUE;
20547 
20548   opt.title = (char*)title;
20549   opt.x.label = (char*)xlabel;
20550   opt.y.label = (char*)ylabel;
20551   opt.x.isGridOn = isXGridOn;
20552   opt.y.isGridOn = isYGridOn;
20553   opt.plotStatistics = includeStats;
20554   opt.PlotSize_Height_cm = plot_height_cm;
20555   opt.PlotSize_Width_cm = plot_width_cm;
20556   opt.numberOfSeries = nrSeries;
20557 
20558   if( !CPLOT_SetPlotOptions( &P, &opt ) )
20559   {
20560     MTX_ERROR_MSG( "CPLOT_SetPlotOptions returned FALSE." );
20561     return FALSE;
20562   }
20563 
20564   for( i = 0; i < nrSeries; i++ )
20565   {
20566     s.color = (CPLOT_enumColor) series[i].color;
20567     s.connected = series[i].connected;
20568     s.label = series[i].label;
20569     s.markOutlierData = series[i].markOutlierData;
20570     s.precision = series[i].precision;
20571     s.units = series[i].units;
20572     s.n = series[i].M->nrows;
20573     s.X = series[i].M->data[series[i].x_col];
20574     s.Y = series[i].M->data[series[i].y_col];
20575 
20576     if( !CPLOT_Plot( &P, &s ) )
20577     {
20578       MTX_ERROR_MSG( "CPLOT_Plot returned FALSE." );
20579       return FALSE;
20580     }
20581   }
20582 
20583   if( !CPLOT_SaveToFile( &P, bmpfilename ) )
20584   {
20585     MTX_ERROR_MSG( "CPLOT_SaveToFile returned FALSE." );
20586     return FALSE;
20587   }
20588 
20589   return TRUE;
20590 }
20591 
20592 #endif // ifndef _MATRIX_NO_PLOTTING
20593 
20594 #ifdef _DEBUG
20595 /* 
20596  Take a filename and return a pointer to its final element.  This
20597  function is called on __FILE__ to fix a MSVC nit where __FILE__
20598  contains the full path to the file.  This is bad, because it
20599  confuses users to find the home directory of the person who
20600  compiled the binary in their warrning messages.
20601 */
20602 const char* _shortfile(const char *fname)
20603 {
20604   const char *cp1, *cp2, *r;
20605   cp1 = strrchr(fname, '/');
20606   cp2 = strrchr(fname, '\\');
20607   if (cp1 && cp2) 
20608   {
20609     r = (cp1<cp2)?(cp2+1):(cp1+1);
20610   } 
20611   else if (cp1) 
20612   {
20613     r = cp1+1;
20614   } 
20615   else if (cp2) 
20616   {
20617     r = cp2+1;
20618   } 
20619   else 
20620   {
20621     r = fname;
20622   }
20623   return r;
20624 }
20625 #else
20626 const char* nullstring = "NULL";
20627 const char* _shortfile(const char *fname)
20628 {
20629   return nullstring;
20630 }
20631 #endif
20632 
20633 BOOL MTX_AddIdentity( const MTX *src, MTX *dst )
20634 {
20635   unsigned i;
20636   if( MTX_isNull( src ) )
20637   {
20638     MTX_ERROR_MSG( "NULL Matrix" );
20639     return FALSE;
20640   }
20641   if( !MTX_Copy( src, dst ) )
20642   {
20643     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
20644     return FALSE;
20645   }
20646   if( src->isReal )
20647   {
20648     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20649       dst->data[i][i] += 1.0;
20650   }
20651   else
20652   {
20653     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20654       dst->cplx[i][i].re += 1.0;
20655   }
20656   return TRUE;  
20657 }
20658 
20659 BOOL MTX_AddIdentity_Inplace( MTX *src )
20660 {
20661   unsigned i;
20662   if( MTX_isNull( src ) )
20663   {
20664     MTX_ERROR_MSG( "NULL Matrix" );
20665     return FALSE;
20666   }
20667   if( src->isReal )
20668   {
20669     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20670       src->data[i][i] += 1.0;
20671   }
20672   else
20673   {
20674     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20675       src->cplx[i][i].re += 1.0;
20676   }
20677   return TRUE;  
20678 }
20679 
20680 
20681 BOOL MTX_MinusIdentity( const MTX *src, MTX *dst )
20682 {
20683   unsigned i;
20684   if( MTX_isNull( src ) )
20685   {
20686     MTX_ERROR_MSG( "NULL Matrix" );
20687     return FALSE;
20688   }
20689   if( !MTX_Copy( src, dst ) )
20690   {
20691     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
20692     return FALSE;
20693   }
20694   if( src->isReal )
20695   {
20696     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20697       dst->data[i][i] -= 1.0;
20698   }
20699   else
20700   {
20701     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20702       dst->cplx[i][i].re -= 1.0;
20703   }
20704   return TRUE;  
20705 }
20706 
20707 BOOL MTX_MinusIdentity_Inplace( MTX *src )
20708 {
20709   unsigned i;
20710   if( MTX_isNull( src ) )
20711   {
20712     MTX_ERROR_MSG( "NULL Matrix" );
20713     return FALSE;
20714   }
20715   if( src->isReal )
20716   {
20717     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20718       src->data[i][i] -= 1.0;
20719   }
20720   else
20721   {
20722     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20723       src->cplx[i][i].re -= 1.0;
20724   }
20725   return TRUE;  
20726 }
20727 
20728 BOOL MTX_IdentityMinus( const MTX *src, MTX *dst )
20729 {
20730   unsigned i;
20731 
20732   if( MTX_isNull( src ) )
20733   {
20734     MTX_ERROR_MSG( "NULL Matrix" );
20735     return FALSE;
20736   }
20737   if( !MTX_Copy( src, dst ) )
20738   {
20739     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
20740     return FALSE;
20741   }
20742   if( !MTX_Negate( dst ) )
20743   {
20744     MTX_ERROR_MSG( "MTX_Negate returned FALSE." );
20745     return FALSE;
20746   } 
20747   if( dst->isReal )
20748   {
20749     for( i = 0; i < dst->nrows && i < dst->ncols; i++ )
20750       dst->data[i][i] += 1.0;
20751   }
20752   else
20753   {
20754     for( i = 0; i < dst->nrows && i < dst->ncols; i++ )
20755       dst->cplx[i][i].re += 1.0;
20756   }
20757   return TRUE;  
20758 }
20759 
20760 BOOL MTX_IdentityMinus_Inplace( MTX *src )
20761 {
20762   unsigned i;
20763 
20764   if( MTX_isNull( src ) )
20765   {
20766     MTX_ERROR_MSG( "NULL Matrix" );
20767     return FALSE;
20768   }
20769   if( !MTX_Negate( src ) )
20770   {
20771     MTX_ERROR_MSG( "MTX_Negate returned FALSE." );
20772     return FALSE;
20773   } 
20774   if( src->isReal )
20775   {
20776     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20777       src->data[i][i] += 1.0;
20778   }
20779   else
20780   {
20781     for( i = 0; i < src->nrows && i < src->ncols; i++ )
20782       src->cplx[i][i].re += 1.0;
20783   }
20784   return TRUE;  
20785 }
20786 
20787 BOOL MTX_Hilbert( MTX *src, const unsigned N )
20788 {
20789   unsigned i;
20790   unsigned j;
20791 
20792   if( !src )
20793   {
20794     MTX_ERROR_MSG( "NULL pointer input." );
20795     return FALSE;
20796   }
20797 
20798   if( src->nrows != N || src->ncols != N || !src->isReal )
20799   {
20800     if( !MTX_Malloc( src, N, N, TRUE ) )
20801     {
20802       MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
20803       return FALSE;
20804     }
20805   }
20806 
20807   for( j = 1; j < src->ncols+1; j++ )
20808   {
20809     for( i = 1; i < src->nrows+1; i++ )
20810     {
20811       src->data[j-1][i-1] = 1.0 / ( i + j - 1.0 );
20812     }
20813   }
20814 
20815   return TRUE;
20816 }
20817 
20818 
20819 BOOL MTX_Swap( MTX* A, MTX *B )
20820 {
20821   MTX C; // used for temporary pointer value storage. MTX_Free( &C ) is not required!
20822   if( A == NULL )
20823   {
20824     MTX_ERROR_MSG( "A is a NULL Matrix" );
20825     return FALSE;
20826   }
20827   if( B == NULL )
20828   {
20829     MTX_ERROR_MSG( "B is a NULL Matrix" );
20830     return FALSE;
20831   }
20832 
20833   // easy since pointer values are just exchanged.
20834 
20835   C.isReal = A->isReal;
20836   C.comment = A->comment;
20837   C.cplx = A->cplx;
20838   C.data = A->data;
20839   C.ncols = A->ncols;
20840   C.nrows = A->nrows;
20841   
20842   A->isReal = B->isReal;
20843   A->comment = B->comment;
20844   A->cplx = B->cplx;
20845   A->data = B->data;
20846   A->ncols = B->ncols;
20847   A->nrows = B->nrows;
20848 
20849   B->isReal = C.isReal;
20850   B->comment = C.comment;
20851   B->cplx = C.cplx;
20852   B->data = C.data;
20853   B->ncols = C.ncols;
20854   B->nrows = C.nrows;
20855 
20856   // C does not need MTX_Free
20857   return TRUE;
20858 }
20859 
20860 
20861 BOOL MTX_LDLt( 
20862   MTX* src,           //!< src = L*D*Lt
20863   MTX *L,             //!< src = L*D*Lt
20864   MTX* d,             //!< src = L*D*Lt, d it the vector diagonal of D.
20865   BOOL checkSymmetric //!< Option to enable/disable checking the src matrix for symmetry.
20866   )
20867 {
20868   int i;
20869   int j;
20870   int k;
20871   int n;
20872   BOOL isSymmetric = TRUE; // assume true
20873   double val;
20874   double maxdif;
20875   double dtmp;
20876 
20877   if( src == NULL || L == NULL || d == NULL )
20878   {
20879     MTX_ERROR_MSG( "An input Matrix is NULL" );
20880     return FALSE;
20881   }
20882 
20883   if( MTX_isNull( src ) )
20884   {
20885     MTX_ERROR_MSG( "NULL Matrix" );
20886     return FALSE;
20887   }
20888 
20889   if( !MTX_isSquare( src ) )
20890   {
20891     MTX_ERROR_MSG( "src Matrix is not square" );
20892     return FALSE;
20893   }
20894 
20895   if( !src->isReal )
20896   {
20897     MTX_ERROR_MSG( "Complex LDLt not supported yet" );
20898     return FALSE;
20899   }
20900 
20901   // get the square dimension
20902   n = src->ncols;
20903 
20904   if( checkSymmetric )
20905   {    
20906     // check symmetric
20907     for( i = 0; i < n; i++ )
20908     {
20909       for( j = i+1; j < n; j++ )
20910       {
20911         val = src->data[j][i];
20912         maxdif = fabs( val )*1e-14;
20913         // Why 1e-14? it works well for most matrices expected.
20914         
20915         dtmp = fabs( val - src->data[i][j] );
20916         if( dtmp > maxdif )
20917         {
20918           isSymmetric = FALSE;
20919           break;
20920         }
20921       }
20922       if( !isSymmetric )
20923         break;
20924     }
20925     if( !isSymmetric )
20926     {
20927       MTX_ERROR_MSG( "src is not symmetric" );
20928       return FALSE;
20929     }
20930   }
20931 
20932   if( !MTX_Copy( src, L ) )
20933   {
20934     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
20935     return FALSE;
20936   }
20937 
20938   if( !MTX_Calloc( d, n, 1, TRUE ) )
20939   {
20940     MTX_ERROR_MSG( "MTX_Calloc returned FALSE." );
20941     return FALSE;
20942   }
20943   
20944   // Perform LDLt decomposition without square roots
20945   // refer http://en.wikipedia.org/wiki/Cholesky_decomposition
20946   // The algorithm below performs everything inplace on a copy of the input matrix.
20947   for( j = 0; j < n; j++ )
20948   {
20949     dtmp = 0;
20950     for( k = 0; k < j; k++ )
20951     {     
20952       val = L->data[k][j];
20953       dtmp += val * val * L->data[k][k];
20954     }
20955     L->data[j][j] -= dtmp; // the diagonal element of D
20956 
20957     for( i = j + 1; i < n; i++ )
20958     {
20959       for( k = 0; k < j; k++ )
20960         L->data[j][i] -= L->data[k][i] * L->data[k][j] * L->data[k][k];
20961 
20962       if( L->data[j][j] == 0.0 )
20963         return FALSE;
20964 
20965       L->data[j][i] /= L->data[j][j];
20966     }
20967   }
20968 
20969   // form the explicit diagonal vector and L matrix
20970   for( i = 0; i < n; i++ )
20971   {
20972     d->data[0][i] = L->data[i][i];
20973     L->data[i][i] = 1.0;
20974 
20975     for( j = i+1; j < n; j++ )
20976     {
20977       L->data[j][i] = 0.0;
20978     }
20979   }
20980 
20981   return TRUE;
20982 }
20983 
20984 
20985 BOOL MTX_UDUt( 
20986   MTX* src,           //!< src = U*D*Ut
20987   MTX *U,             //!< src = U*D*Ut
20988   MTX* d,             //!< src = U*D*Ut, d it the vector diagonal of D.
20989   BOOL checkSymmetric //!< Option to enable/disable checking the src matrix for symmetry.
20990   )
20991 {
20992   int i;
20993   int j;
20994   int k;
20995   int n;
20996   BOOL isSymmetric = TRUE; // assume true
20997   double val;
20998   double maxdif;
20999   double dtmp;
21000   double alpha;
21001   double beta;
21002 
21003   if( src == NULL || U == NULL || d == NULL )
21004   {
21005     MTX_ERROR_MSG( "An input Matrix is NULL" );
21006     return FALSE;
21007   }
21008 
21009   if( MTX_isNull( src ) )
21010   {
21011     MTX_ERROR_MSG( "NULL Matrix" );
21012     return FALSE;
21013   }
21014 
21015   if( !MTX_isSquare( src ) )
21016   {
21017     MTX_ERROR_MSG( "src Matrix is not square" );
21018     return FALSE;
21019   }
21020 
21021   if( !src->isReal )
21022   {
21023     MTX_ERROR_MSG( "Complex LDLt not supported yet" );
21024     return FALSE;
21025   }
21026 
21027   // get the square dimension
21028   n = src->ncols;
21029 
21030   if( checkSymmetric )
21031   {    
21032     // check symmetric
21033     for( i = 0; i < n; i++ )
21034     {
21035       for( j = i+1; j < n; j++ )
21036       {
21037         val = src->data[j][i];
21038         maxdif = fabs( val )*1e-14;
21039         // Why 1e-14? it works well for most matrices expected.
21040         
21041         dtmp = fabs( val - src->data[i][j] );
21042         if( dtmp > maxdif )
21043         {
21044           isSymmetric = FALSE;
21045           break;
21046         }
21047       }
21048       if( !isSymmetric )
21049         break;
21050     }
21051     if( !isSymmetric )
21052     {
21053       MTX_ERROR_MSG( "src is not symmetric" );
21054       return FALSE;
21055     }
21056   }
21057 
21058   if( !MTX_Copy( src, U ) )
21059   {
21060     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
21061     return FALSE;
21062   }
21063   
21064   if( !MTX_Calloc( d, n, 1, TRUE ) )
21065   {
21066     MTX_ERROR_MSG( "MTX_Calloc returned FALSE." );
21067     return FALSE;
21068   }
21069   
21070   // Perform UDUt decomposition without square roots, inplace as U is initialized as a copy.
21071 
21072   for( j = n-1; j >= 1; j-- )
21073   {
21074     dtmp = U->data[j][j];
21075     d->data[0][j] = dtmp;
21076     if( dtmp == 0.0 )
21077       return FALSE;
21078 
21079     alpha = 1.0/dtmp;
21080     for( k = 0; k <= j-1; k++ )
21081     {
21082       beta = U->data[j][k];
21083       U->data[j][k] = alpha*beta;
21084       for( i = 0; i <= k; i++ )
21085       {
21086         U->data[k][i] -= beta*U->data[j][i];        
21087       }
21088     }
21089   }
21090   d->data[0][0] = U->data[0][0];
21091 
21092   // form the explicit U matrix
21093   for( i = 0; i < n; i++ )
21094   {
21095     U->data[i][i] = 1.0;
21096     for( j = 0; j < i; j++ )
21097     {
21098       U->data[j][i] = 0.0;
21099     }
21100   }
21101 
21102   /* The algorithm below is from:
21103   Grewel, M.S (2001), "Kalman Filtering: Theory and Practice using Matlab, Second Edition", 
21104   John Wiley and Sons, ISBN: 0-471-39254-5, pp. 222
21105 
21106   It performs slower than the above algorithm so it is not used.
21107 
21108   for( j = n-1; j >=0; j-- )
21109   {
21110     for( i = j; i >=0; i-- )
21111     {
21112       dtmp = src->data[j][i];
21113       for( k = j+1; k < n; k++ )
21114       {
21115         dtmp -= U->data[k][i] * d->data[0][k] * U->data[k][j];
21116       }
21117       if( i==j )
21118       {
21119         d->data[0][j] = dtmp;
21120         U->data[j][j] = 1.0;        
21121       }
21122       else
21123       {
21124         U->data[j][i] = dtmp/d->data[0][j];        
21125       }
21126     }
21127   }
21128   */
21129   
21130   return TRUE;
21131 }
21132 
21133 
21134 
21135 static BOOL MTX_static_gammp(double a, double x, double* ans);
21136 static BOOL MTX_static_gammq(double a, double x, double* ans);
21137 static BOOL MTX_static_gser(double *gamser, double a, double x, double *gln);
21138 static BOOL MTX_static_gcf(double *gammcf, double a, double x, double *gln);
21139 static double MTX_static_gammln(double xx);
21140 
21141 
21142 BOOL MTX_erf_Inplace( MTX* src )
21143 {
21144   unsigned j = 0;
21145   unsigned i = 0;
21146   double x = 0;  
21147   
21148   if( MTX_isNull( src ) )
21149   {
21150     MTX_ERROR_MSG( "src matrix is NULL" );
21151     return FALSE;
21152   }
21153 
21154   if( !src->isReal )
21155   {
21156     MTX_ERROR_MSG( "complex erf is not yet supported." );
21157     return FALSE;
21158   }
21159 
21160   for( j = 0; j < src->ncols; j++ )
21161   {
21162 
21163     for( i = 0; i < src->nrows; i++ )
21164     {
21165       x = src->data[j][i];
21166 
21167       if( x < 0.0 )
21168       {
21169         if( !MTX_static_gammp( 0.5, x*x, &x ) )
21170         {
21171           MTX_ERROR_MSG( "MTX_static_gammp returned FALSE." );
21172           return FALSE;
21173         }
21174         src->data[j][i] = -x;
21175       }
21176       else
21177       {
21178         if( !MTX_static_gammp( 0.5, x*x, &x ) )
21179         {
21180           MTX_ERROR_MSG( "MTX_static_gammp returned FALSE." );
21181           return FALSE;
21182         }
21183         src->data[j][i] = x;
21184       }
21185     } 
21186   }
21187 
21188   return TRUE;
21189 }
21190 
21191 
21192 
21193 BOOL MTX_erfinv_Inplace( MTX* src )
21194 {
21195   unsigned j = 0;
21196   MTX vec;  
21197   unsigned i = 0;
21198   double u = 0;
21199   double z = 0;
21200   double y = 0;
21201   // Coefficients
21202   const double a[4] = {0.886226899, -1.645349621,  0.914624893, -0.140543331};
21203   const double b[4] = {-2.118377725,  1.442710462, -0.329097515,  0.012229801};
21204   const double c[4] = {-1.970840454, -1.624906493,  3.429567803,  1.641345311};
21205   const double d[2] = {3.543889200,  1.637067800};      
21206   const double y0 = 0.7;
21207   const double two_over_rootpi = 2.0/sqrt(PI);
21208   MTX vecX;
21209   MTX vecErfX;  
21210   MTX_Init(&vecX);    
21211   MTX_Init(&vecErfX);   
21212   MTX_Init(&vec);  
21213   
21214   if( MTX_isNull( src ) )
21215   {
21216     MTX_ERROR_MSG( "src matrix is NULL" );
21217     return FALSE;
21218   }
21219 
21220   if( !src->isReal )
21221   {
21222     MTX_ERROR_MSG( "complex erfinv is not supported." );
21223     return FALSE;
21224   }
21225 
21226   for( j = 0; j < src->ncols; j++ )
21227   {
21228     if( !MTX_CopyColumn( src, j, &vec ) )
21229     {
21230       MTX_Free(&vec);
21231       MTX_ERROR_MSG( "MTX_CopyColumn returned FALSE." );
21232       return FALSE;
21233     }  
21234 
21235     if( !MTX_Resize( &vecX, vec.nrows, 1, TRUE ) )
21236     {
21237       MTX_Free(&vec);
21238       MTX_Free(&vecX);
21239       MTX_Free(&vecErfX);      
21240       MTX_ERROR_MSG( "MTX_Resize returned FALSE." );
21241       return FALSE;
21242     }  
21243     for( i = 0; i < vec.nrows; i++ )
21244     {
21245       y = vec.data[0][i];
21246       if( fabs( y ) < y0 )
21247       {
21248         z = y*y;
21249         vecX.data[0][i] = y * ( ( (a[3]*z+a[2])*z + a[1] )*z + a[0] );
21250         vecX.data[0][i] /= ( ( (b[3]*z+b[2])*z + b[1] )*z + b[0] )*z + 1.0;          
21251       }
21252       else if( y0 < y && y < 1.0 )
21253       {
21254         z = sqrt( -log( (1.0 - y)/2.0 ) );
21255         vecX.data[0][i] = (( c[3]*z + c[2] )*z + c[1])*z + c[0];
21256         vecX.data[0][i] /= (d[1]*z + d[0])*z + 1.0;
21257       }
21258       else if( -y0 > y && y > -1.0 )
21259       {
21260         z = sqrt( -log( (1.0 + y)/2.0 ) );
21261         vecX.data[0][i] = -(((c[3]*z + c[2])*z + c[1])*z + c[0]);
21262         vecX.data[0][i] /= ((d[1]*z+d[0])*z+1.0);
21263       }
21264     }
21265 
21266     if( !MTX_Copy( &vecX, &vecErfX ) )
21267     {
21268       MTX_Free(&vec);
21269       MTX_Free(&vecX);
21270       MTX_Free(&vecErfX);      
21271       MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
21272       return FALSE;
21273     }  
21274 
21275     if( !MTX_erf_Inplace( &vecErfX ) )
21276     {
21277       MTX_Free(&vec);
21278       MTX_Free(&vecX);
21279       MTX_Free(&vecErfX);
21280       MTX_ERROR_MSG( "MTX_erf_Inplace returned FALSE." );
21281       return FALSE;
21282     } 
21283 
21284     for( i = 0; i < vec.nrows; i++ )
21285     {
21286       u = (vecErfX.data[0][i] - vec.data[0][i]) / (two_over_rootpi * exp( -(vecX.data[0][i]*vecX.data[0][i]) ));
21287    
21288       // Halley's step
21289       vecX.data[0][i] -= u / (1.0 + vecX.data[0][i]*u);
21290 
21291       y = vec.data[0][i];
21292       z = vecX.data[0][i];
21293       
21294       if( y == -1 )
21295         z = MTX_NEG_INF;
21296       else if( y == 1 )
21297         z = MTX_POS_INF;
21298       else if( fabs(y) > 1 )
21299         z = MTX_NAN;
21300       else if( y == MTX_NAN )
21301         z = MTX_NAN;
21302 
21303       src->data[j][i] = z;
21304     }
21305   }
21306 
21307   MTX_Free(&vec);
21308   MTX_Free(&vecX);
21309   MTX_Free(&vecErfX);
21310 
21311   return TRUE;
21312 }
21313 
21314 
21315 BOOL MTX_erfc_Inplace( MTX* src )
21316 {
21317   unsigned j = 0;
21318   unsigned i = 0;
21319   double x = 0;    
21320   
21321   if( MTX_isNull( src ) )
21322   {
21323     MTX_ERROR_MSG( "src matrix is NULL" );
21324     return FALSE;
21325   }
21326 
21327   if( !src->isReal )
21328   {
21329     MTX_ERROR_MSG( "complex erfc is not yet supported." );
21330     return FALSE;
21331   }
21332 
21333   for( j = 0; j < src->ncols; j++ )
21334   {
21335 
21336     for( i = 0; i < src->nrows; i++ )
21337     {
21338       x = src->data[j][i];
21339 
21340       if( x < 0.0 )
21341       {
21342         if( !MTX_static_gammp( 0.5, x*x, &x ) )
21343         {
21344           MTX_ERROR_MSG( "MTX_static_gammp returned FALSE." );
21345           return FALSE;
21346         }
21347         src->data[j][i] = 1+x;
21348       }
21349       else
21350       {
21351         if( !MTX_static_gammq( 0.5, x*x, &x ) )
21352         {
21353           MTX_ERROR_MSG( "MTX_static_gammp returned FALSE." );
21354           return FALSE;
21355         }
21356         src->data[j][i] = x;
21357       }
21358     } 
21359   }
21360 
21361   return TRUE;
21362 }
21363 
21364 
21365 BOOL MTX_erfcinv_Inplace( MTX* src )
21366 {
21367   MTX copySrc;
21368   MTX_Init( &copySrc );
21369 
21370   if( !MTX_OneMinus( src, &copySrc ) )
21371   {
21372     MTX_Free( &copySrc );
21373     MTX_ERROR_MSG( "MTX_OneMinus returned FALSE." );
21374     return FALSE;
21375   }
21376   if( !MTX_Copy( &copySrc, src ) )
21377   {
21378     MTX_Free( &copySrc );
21379     MTX_ERROR_MSG( "MTX_Copy returned FALSE." );
21380     return FALSE;
21381   }
21382   if( !MTX_erfinv_Inplace( src ) )
21383   {
21384     MTX_Free( &copySrc );
21385     MTX_ERROR_MSG( "MTX_erfinv_Inplace returned FALSE." );
21386     return FALSE;
21387   }
21388   MTX_Free( &copySrc );
21389   return TRUE;
21390 }
21391 
21392 
21393 
21394 
21395 // Returns the incomplete gamma function P(a,x).
21396 //
21397 // reference
21398 // Press, W.H., S.A. Teukolsky, W.T. Vetterling,  and B.P. Flannery (1997), 
21399 // "Numerical Recipes in C", CAMBRIDGE UNIVERSITY PRESS, ISBN 0 521 43108 5,
21400 // pp. 214.
21401 //
21402 // static
21403 BOOL MTX_static_gammp(double a, double x, double* ans)
21404 {
21405   double gamser=0;
21406   double gammcf=0;
21407   double gln=0;
21408   if( x < 0.0 || a <= 0.0 )
21409   {
21410     MTX_ERROR_MSG( "Invalid arguments a or x.");
21411     return FALSE;
21412   }
21413   if( x < (a+1.0) ) 
21414   { 
21415     // Use the series representation.
21416     if( !MTX_static_gser( &gamser, a, x, &gln) )
21417     {
21418       MTX_ERROR_MSG( "MTX_static_gser returned FALSE." );
21419       return FALSE;
21420     }
21421     *ans = gamser;
21422     return TRUE;
21423   } 
21424   else 
21425   { 
21426     // Use the continued fraction representation
21427     if( !MTX_static_gcf( &gammcf, a, x, &gln ) )
21428     {
21429       MTX_ERROR_MSG( "MTX_static_gcf returned FALSE." );
21430       return FALSE;
21431     }
21432     *ans = 1.0-gammcf; // and take its complement.
21433     return TRUE;
21434   }  
21435 }
21436 
21437 // Returns the incomplete gamma function Q(a,x) == 1 - P(a,x).
21438 //
21439 // reference
21440 // Press, W.H., S.A. Teukolsky, W.T. Vetterling,  and B.P. Flannery (1997), 
21441 // "Numerical Recipes in C", CAMBRIDGE UNIVERSITY PRESS, ISBN 0 521 43108 5,
21442 // pp. 214.
21443 //
21444 // static
21445 BOOL MTX_static_gammq(double a, double x, double* ans)
21446 {
21447   double gamser=0;
21448   double gammcf=0;
21449   double gln=0;
21450   if( x < 0.0 || a <= 0.0 ) 
21451   {
21452     MTX_ERROR_MSG("if( x < 0.0 || a <= 0.0 ) ");
21453     return FALSE;
21454   }
21455   if( x < (a+1.0) ) 
21456   { 
21457     //Use the series representation
21458     if( !MTX_static_gser(&gamser,a,x,&gln) )
21459     {
21460       MTX_ERROR_MSG( "MTX_static_gser returned FALSE." );
21461       return FALSE;
21462     }
21463     *ans = 1.0-gamser; // and take its complement.
21464     return TRUE;
21465   } 
21466   else 
21467   { 
21468     //Use the continued fraction representation.
21469     if( !MTX_static_gcf(&gammcf,a,x,&gln) )
21470     {
21471       MTX_ERROR_MSG( "MTX_static_gcf returned FALSE." );
21472       return FALSE;
21473     }
21474     *ans = gammcf;
21475     return TRUE;
21476   }
21477 }
21478 
21479 
21480 // Returns the incomplete gamma function P(a; x) evaluated by its series representation as gamser.
21481 //
21482 // reference
21483 // Press, W.H., S.A. Teukolsky, W.T. Vetterling,  and B.P. Flannery (1997), 
21484 // "Numerical Recipes in C", CAMBRIDGE UNIVERSITY PRESS, ISBN 0 521 43108 5,
21485 // pp. 214.
21486 //
21487 // static 
21488 BOOL MTX_static_gser(double *gamser, double a, double x, double *gln)
21489 {
21490   int n;
21491   const int itmax = 10000; // Maximum allowed number of iterations.
21492   const double eps = DBL_EPSILON; // Relative accuracy.  
21493   
21494   // in float.h
21495   // #define DBL_EPSILON     2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */  
21496   
21497   double sum;
21498   double del;
21499   double ap;
21500 
21501   // gamser and gln must be valid pointers
21502   // since this is an internal static function they will not be checked.
21503   
21504   *gln = MTX_static_gammln(a);
21505 
21506   if( x <= 0.0 )  
21507   {
21508     if( x < 0.0 )
21509     {
21510       MTX_ERROR_MSG( "x less than 0.");
21511       return FALSE;
21512     }
21513     *gamser=0.0;
21514     return TRUE;
21515   }
21516   else 
21517   {
21518     ap = a;
21519     del = sum = 1.0/a;
21520     for( n = 1; n <= itmax; n++) 
21521     {
21522       ap += 1.0;
21523       del *= x/ap;
21524       sum += del;
21525       if( fabs(del) < fabs(sum)*eps )
21526       {
21527         *gamser = sum * exp( -x+a*log(x)-(*gln) );
21528         return TRUE;
21529       }
21530     }
21531     MTX_ERROR_MSG( "a is too large for the number of iterations in MTX_static_gser." );    
21532     return FALSE;
21533   }
21534 }
21535 
21536 
21537 // Determines the incomplete gamma function Q(a,x) evaluated by 
21538 // its continued fraction representation as gammcf.
21539 // Also returns ln( Gamma(a) ) as gln.
21540 //
21541 // reference
21542 // Press, W.H., S.A. Teukolsky, W.T. Vetterling,  and B.P. Flannery (1997), 
21543 // "Numerical Recipes in C", CAMBRIDGE UNIVERSITY PRESS, ISBN 0 521 43108 5,
21544 // pp. 214.
21545 //
21546 //static 
21547 BOOL MTX_static_gcf(double *gammcf, double a, double x, double *gln)
21548 {
21549   const int itmax = 10000; // Maximum allowed number of iterations.
21550   const double eps = DBL_EPSILON; // Relative accuracy (in float.h).
21551   const double fpmin  = DBL_MIN; // Number near the smallest representable double floating-point number (in float.h).
21552 
21553   // in float.h
21554   // #define DBL_EPSILON     2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */  
21555   // #define DBL_MIN 2.2250738585072014e-308 /* min positive value */
21556   
21557   int i;
21558   double an,b,c,d,del,h;
21559   
21560   *gln = MTX_static_gammln(a);
21561 
21562   b = x+1.0-a; // Set up for evaluating continued fraction by modified Lentz's method with b0 = 0.
21563   c = 1.0/fpmin;
21564   d = 1.0/b;
21565   h = d;
21566   for( i = 1; i <= itmax; i++ ) 
21567   {
21568     // Iterate to convergence.
21569     an = -i*(i-a);
21570     b += 2.0;
21571     d = an*d+b;
21572     if( fabs(d) < fpmin ) 
21573       d = fpmin;
21574     c = b+an/c;
21575     if( fabs(c) < fpmin )
21576       c = fpmin;
21577     d = 1.0/d;
21578     del = d*c;
21579     h *= del;
21580     if( fabs(del-1.0) < eps ) 
21581       break;
21582   }
21583   if( i > itmax )
21584   {
21585     MTX_ERROR_MSG("a too large, too few iterations");
21586     return FALSE;
21587   }
21588   *gammcf = exp(-x+a*log(x)-(*gln))*h; // Put factors in front.
21589   return TRUE;
21590 }
21591 
21592 
21593 // returns the value of ln(Gamma(xx)) for xx > 0  
21594 //
21595 // reference
21596 // Press, W.H., S.A. Teukolsky, W.T. Vetterling,  and B.P. Flannery (1997), 
21597 // "Numerical Recipes in C", CAMBRIDGE UNIVERSITY PRESS, ISBN 0 521 43108 5,
21598 // pp. 214.
21599 //
21600 //static 
21601 double MTX_static_gammln(double xx)
21602 {
21603   double x,y,tmp,ser;
21604   static double cof[6] = {76.18009172947146,-86.50532032941677,24.01409824083091,-1.231739572450155,0.1208650973866179e-2,-0.5395239384953e-5};
21605   int j;
21606   y = x = xx;
21607   tmp = x+5.5;
21608   tmp -= (x+0.5)*log(tmp);
21609   ser = 1.000000000190015;
21610   for( j = 0; j < 6; j++ )
21611   {
21612     y += 1.0;
21613     ser += cof[j]/y;
21614   }
21615   x = -tmp+log(2.5066282746310005*ser/x);
21616   return x;
21617 }
21618 
21619 
21620 
21621 BOOL MTX_find_column_values_equalto( 
21622   const MTX* src,        //!< The source matrix to search.
21623   const unsigned col,    //!< The zero-based index of the column which is searched.
21624   MTX* indexVector,      //!< This is the index vector corresponding to the equal values in the source matrix.  
21625   const double re,       //!< The real part of the equal to value.
21626   const double im,       //!< The imaginary part of the equal to value.
21627   const double tolerance //!< The search tolerance. e.g. 1.0e-12.  
21628   )
21629 {
21630   unsigned i = 0;
21631   unsigned k = 0;
21632   if( MTX_isNull( src ) )
21633   {
21634     MTX_ERROR_MSG( "src is a NULL matrix" );
21635     return FALSE;
21636   }
21637   if( indexVector == NULL )
21638   {
21639     MTX_ERROR_MSG( "indexVector is NULL" );
21640     return FALSE;
21641   }
21642   if( col >= src->ncols )
21643   {
21644     MTX_ERROR_MSG( "Invalid column specified." );
21645     return FALSE;
21646   }
21647   if( tolerance < 0 )
21648   {
21649     MTX_ERROR_MSG( "invalid tolerance (-ve)" );
21650     return FALSE;
21651   }
21652 
21653   if( src->isReal && fabs(im) > tolerance )
21654   {
21655     MTX_Free( indexVector );
21656     // there are no equal values.
21657     return TRUE;
21658   }
21659 
21660   if( !MTX_Malloc( indexVector, src->nrows, 1, TRUE ) )
21661   {
21662     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
21663     return FALSE;
21664   }
21665 
21666   if( fabs(im) < tolerance && src->isReal )
21667   {
21668     // searching real only
21669     for( i = 0; i < src->nrows; i++ )
21670     {
21671       if( fabs( src->data[col][i] - re ) <= tolerance )
21672       {
21673         indexVector->data[0][k] = i;
21674         k++;
21675       }
21676     }
21677   }
21678   else
21679   {
21680     // the src matrix must be complex
21681     if( src->isReal )
21682     {
21683       MTX_ERROR_MSG("Unexpected real matrix");
21684       return FALSE;
21685     }
21686 
21687     for( i = 0; i < src->nrows; i++ )
21688     {
21689       if( fabs( src->cplx[col][i].re - re ) <= tolerance &&
21690         fabs( src->cplx[col][i].im - im ) <= tolerance )
21691       {
21692         indexVector->data[0][k] = i;
21693         k++;
21694       }
21695     }
21696   }
21697 
21698   if( k == 0 )
21699   {
21700     if( !MTX_Free( indexVector ) )
21701     {
21702       MTX_ERROR_MSG("MTX_Free returned FALSE.");
21703       return FALSE;
21704     }
21705   }
21706   else
21707   {
21708     if( !MTX_Redim( indexVector, k, 1 ) )
21709     {
21710       MTX_ERROR_MSG("Unexpected real matrix.");
21711       return FALSE;
21712     }
21713   }
21714 
21715   return TRUE;
21716 }
21717 
21718 BOOL MTX_find_column_values_not_equalto( 
21719   const MTX* src,        //!< The source matrix to search.
21720   const unsigned col,    //!< The zero-based index of the column which is searched.
21721   MTX* indexVector,      //!< This is the index vector corresponding to the values that are not equal in the source matrix.  
21722   const double re,       //!< The real part of the value.
21723   const double im,       //!< The imaginary part of the value.
21724   const double tolerance //!< The search tolerance. e.g. 1.0e-12.  
21725   )
21726 {
21727   unsigned i = 0;
21728   unsigned k = 0;
21729   if( MTX_isNull( src ) )
21730   {
21731     MTX_ERROR_MSG( "src is a NULL matrix" );
21732     return FALSE;
21733   }
21734   if( indexVector == NULL )
21735   {
21736     MTX_ERROR_MSG( "indexVector is NULL" );
21737     return FALSE;
21738   }
21739   if( col >= src->ncols )
21740   {
21741     MTX_ERROR_MSG( "Invalid column specified." );
21742     return FALSE;
21743   }
21744   if( tolerance < 0 )
21745   {
21746     MTX_ERROR_MSG( "invalid tolerance (-ve)" );
21747     return FALSE;
21748   }
21749 
21750   if( src->isReal && fabs(im) > tolerance )
21751   {
21752     // All values are not equal
21753     if( !MTX_Colon( indexVector, 0, 1, src->nrows - 1 ) )
21754     {
21755       MTX_ERROR_MSG( "invalid tolerance (-ve)" );
21756       return FALSE;
21757     }    
21758     return TRUE;
21759   }
21760 
21761   if( !MTX_Malloc( indexVector, src->nrows, 1, TRUE ) )
21762   {
21763     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
21764     return FALSE;
21765   }
21766 
21767   if( fabs(im) <= tolerance && src->isReal )
21768   {
21769     // searching real only
21770     for( i = 0; i < src->nrows; i++ )
21771     {
21772       if( fabs( src->data[col][i] - re ) > tolerance )
21773       {
21774         indexVector->data[0][k] = i;
21775         k++;
21776       }
21777     }
21778   }
21779   else
21780   {
21781     // the src matrix must be complex
21782     if( src->isReal )
21783     {
21784       MTX_ERROR_MSG("Unexpected real matrix");
21785       return FALSE;
21786     }
21787 
21788     for( i = 0; i < src->nrows; i++ )
21789     {
21790       if( fabs( src->cplx[col][i].re - re ) > tolerance ||
21791         fabs( src->cplx[col][i].im - im ) > tolerance )
21792       {
21793         indexVector->data[0][k] = i;
21794         k++;
21795       }
21796     }
21797   }
21798 
21799   if( k == 0 )
21800   {
21801     if( !MTX_Free( indexVector ) )
21802     {
21803       MTX_ERROR_MSG("MTX_Free returned FALSE.");
21804       return FALSE;
21805     }
21806   }
21807   else
21808   {
21809     if( !MTX_Redim( indexVector, k, 1 ) )
21810     {
21811       MTX_ERROR_MSG("Unexpected real matrix.");
21812       return FALSE;
21813     }
21814   }
21815 
21816   return TRUE;
21817 }
21818 
21819 
21820 BOOL MTX_find_column_values_less_than( 
21821   const MTX* src,        //!< The source matrix to search.
21822   const unsigned col,    //!< The zero-based index of the column which is searched.
21823   MTX* indexVector,      //!< This is the index vector of the values desired.  
21824   const double value     //!< The comparison value.   
21825   )
21826 {
21827   unsigned i = 0;
21828   unsigned k = 0;
21829   double re = 0;
21830   double im = 0;
21831   double magv = 0;
21832   if( MTX_isNull( src ) )
21833   {
21834     MTX_ERROR_MSG( "src is a NULL matrix" );
21835     return FALSE;
21836   }
21837   if( indexVector == NULL )
21838   {
21839     MTX_ERROR_MSG( "indexVector is NULL" );
21840     return FALSE;
21841   }
21842   if( col >= src->ncols )
21843   {
21844     MTX_ERROR_MSG( "Invalid column specified." );
21845     return FALSE;
21846   }
21847 
21848   if( !MTX_Malloc( indexVector, src->nrows, 1, TRUE ) )
21849   {
21850     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
21851     return FALSE;
21852   }
21853 
21854 
21855   if( src->isReal )
21856   { 
21857     for( i = 0; i < src->nrows; i++ )
21858     {
21859       if( src->data[col][i] < value )
21860       {
21861         indexVector->data[0][k] = i;
21862         k++;
21863       }
21864     }
21865   }
21866   else
21867   {
21868     for( i = 0; i < src->nrows; i++ )
21869     {
21870       re = src->cplx[col][i].re;
21871       im = src->cplx[col][i].im;
21872       magv = sqrt( re*re + im*im );    
21873       if( magv < value )
21874       {
21875         indexVector->data[0][k] = i;
21876         k++;
21877       }
21878     }
21879   }
21880 
21881   if( k == 0 )
21882   {
21883     if( !MTX_Free( indexVector ) )
21884     {
21885       MTX_ERROR_MSG("MTX_Free returned FALSE.");
21886       return FALSE;
21887     }
21888   }
21889   else
21890   {
21891     if( !MTX_Redim( indexVector, k, 1 ) )
21892     {
21893       MTX_ERROR_MSG("Unexpected real matrix.");
21894       return FALSE;
21895     }
21896   }
21897 
21898   return TRUE;
21899 }
21900 
21901 
21902 BOOL MTX_find_column_values_more_than( 
21903   const MTX* src,        //!< The source matrix to search.
21904   const unsigned col,    //!< The zero-based index of the column which is searched.
21905   MTX* indexVector,      //!< This is the index vector of the values desired.  
21906   const double value     //!< The comparison value.   
21907   )
21908 {
21909   unsigned i = 0;
21910   unsigned k = 0;
21911   double re = 0;
21912   double im = 0;
21913   double magv = 0;
21914   if( MTX_isNull( src ) )
21915   {
21916     MTX_ERROR_MSG( "src is a NULL matrix" );
21917     return FALSE;
21918   }
21919   if( indexVector == NULL )
21920   {
21921     MTX_ERROR_MSG( "indexVector is NULL" );
21922     return FALSE;
21923   }
21924   if( col >= src->ncols )
21925   {
21926     MTX_ERROR_MSG( "Invalid column specified." );
21927     return FALSE;
21928   }
21929 
21930   if( !MTX_Malloc( indexVector, src->nrows, 1, TRUE ) )
21931   {
21932     MTX_ERROR_MSG( "MTX_Malloc returned FALSE." );
21933     return FALSE;
21934   }
21935 
21936 
21937   if( src->isReal )
21938   { 
21939     for( i = 0; i < src->nrows; i++ )
21940     {
21941       if( src->data[col][i] > value )
21942       {
21943         indexVector->data[0][k] = i;
21944         k++;
21945       }
21946     }
21947   }
21948   else
21949   {
21950     for( i = 0; i < src->nrows; i++ )
21951     {
21952       re = src->cplx[col][i].re;
21953       im = src->cplx[col][i].im;
21954       magv = sqrt( re*re + im*im );    
21955       if( magv > value )
21956       {
21957         indexVector->data[0][k] = i;
21958         k++;
21959       }
21960     }
21961   }
21962 
21963   if( k == 0 )
21964   {
21965     if( !MTX_Free( indexVector ) )
21966     {
21967       MTX_ERROR_MSG("MTX_Free returned FALSE.");
21968       return FALSE;
21969     }
21970   }
21971   else
21972   {
21973     if( !MTX_Redim( indexVector, k, 1 ) )
21974     {
21975       MTX_ERROR_MSG("Unexpected real matrix.");
21976       return FALSE;
21977     }
21978   }
21979 
21980   return TRUE;
21981 }
21982 

Generated on Sun Feb 8 15:31:08 2009 for The Zenautics Matrix Project by  doxygen 1.5.4