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].