JWS C Library
C language utility library
matrix_math.c
Go to the documentation of this file.
00001 /*
00002  * This work is licensed under a Creative Commons 
00003  * Attribution-Noncommercial-Share Alike 3.0 United States License.
00004  * 
00005  *    http://creativecommons.org/licenses/by-nc-sa/3.0/us/
00006  * 
00007  * You are free:
00008  * 
00009  *    to Share - to copy, distribute, display, and perform the work
00010  *    to Remix - to make derivative works
00011  * 
00012  * Under the following conditions:
00013  * 
00014  *    Attribution. You must attribute the work in the manner specified by the
00015  *    author or licensor (but not in any way that suggests that they endorse you
00016  *    or your use of the work).
00017  * 
00018  *    Noncommercial. You may not use this work for commercial purposes.
00019  * 
00020  *    Share Alike. If you alter, transform, or build upon this work, you may
00021  *    distribute the resulting work only under the same or similar license to
00022  *    this one.
00023  * 
00024  * For any reuse or distribution, you must make clear to others the license
00025  * terms of this work. The best way to do this is by including this header.
00026  * 
00027  * Any of the above conditions can be waived if you get permission from the
00028  * copyright holder.
00029  * 
00030  * Apart from the remix rights granted under this license, nothing in this
00031  * license impairs or restricts the author's moral rights.
00032  */
00033 
00034 
00049 #include <jwsc/config.h>
00050 
00051 #include <stdlib.h>
00052 #include <assert.h>
00053 #include <math.h>
00054 #include <inttypes.h>
00055 
00056 #include "jwsc/base/error.h"
00057 #include "jwsc/math/complex.h"
00058 #include "jwsc/math/constants.h"
00059 #include "jwsc/math/blas.h"
00060 #include "jwsc/math/lapack.h"
00061 #include "jwsc/vector/vector.h"
00062 #include "jwsc/vector/vector_math.h"
00063 #include "jwsc/matrix/matrix.h"
00064 #include "jwsc/matrix/matrix_math.h"
00065 
00066 #ifdef JWSC_HAVE_DMALLOC
00067 #include <dmalloc.h>
00068 #endif
00069 
00070 
00086 void add_scalar_to_matrix_f
00087 (
00088     Matrix_f**      m_out, 
00089     const Matrix_f* m_in, 
00090     float           a
00091 )
00092 {
00093     uint32_t  num_elts;
00094     uint32_t  elt;
00095     float*    m_in_elts;
00096     float*    m_out_elts;
00097 
00098     num_elts = m_in->num_rows*m_in->num_cols;
00099 
00100     if (*m_out != m_in)
00101     {
00102         create_matrix_f(m_out, m_in->num_rows, m_in->num_cols);
00103     }
00104     m_out_elts = *((*m_out)->elts);
00105     m_in_elts  = *(m_in->elts);
00106 
00107     for (elt = 0; elt < num_elts; elt++)
00108     {
00109         m_out_elts[ elt ] = a + m_in_elts[ elt ];
00110     }
00111 }
00112 
00121 void add_scalar_to_matrix_d
00122 (
00123     Matrix_d**      m_out, 
00124     const Matrix_d* m_in, 
00125     double          a
00126 )
00127 {
00128     uint32_t  num_elts;
00129     uint32_t  elt;
00130     double*   m_in_elts;
00131     double*   m_out_elts;
00132 
00133     num_elts = m_in->num_rows*m_in->num_cols;
00134 
00135     if (*m_out != m_in)
00136     {
00137         create_matrix_d(m_out, m_in->num_rows, m_in->num_cols);
00138     }
00139     m_out_elts = *((*m_out)->elts);
00140     m_in_elts  = *(m_in->elts);
00141 
00142     for (elt = 0; elt < num_elts; elt++)
00143     {
00144         m_out_elts[ elt ] = a + m_in_elts[ elt ];
00145     }
00146 }
00147 
00156 void add_scalar_to_matrix_cf
00157 (
00158     Matrix_cf**      m_out, 
00159     const Matrix_cf* m_in, 
00160     Complex_f        z
00161 )
00162 {
00163     uint32_t   num_elts;
00164     uint32_t   elt;
00165     Complex_f* m_in_elts;
00166     Complex_f* m_out_elts;
00167 
00168     num_elts = m_in->num_rows*m_in->num_cols;
00169 
00170     if (*m_out != m_in)
00171     {
00172         create_matrix_cf(m_out, m_in->num_rows, m_in->num_cols);
00173     }
00174     m_out_elts = *((*m_out)->elts);
00175     m_in_elts  = *(m_in->elts);
00176 
00177     for (elt = 0; elt < num_elts; elt++)
00178     {
00179         m_out_elts[ elt ].r = z.r + m_in_elts[ elt ].r;
00180         m_out_elts[ elt ].i = z.i + m_in_elts[ elt ].i;
00181     }
00182 }
00183 
00192 void add_scalar_to_matrix_cd
00193 (
00194     Matrix_cd**      m_out, 
00195     const Matrix_cd* m_in, 
00196     Complex_d        z
00197 )
00198 {
00199     uint32_t   num_elts;
00200     uint32_t   elt;
00201     Complex_d* m_in_elts;
00202     Complex_d* m_out_elts;
00203 
00204     num_elts = m_in->num_rows*m_in->num_cols;
00205 
00206     if (*m_out != m_in)
00207     {
00208         create_matrix_cd(m_out, m_in->num_rows, m_in->num_cols);
00209     }
00210     m_out_elts = *((*m_out)->elts);
00211     m_in_elts  = *(m_in->elts);
00212 
00213     for (elt = 0; elt < num_elts; elt++)
00214     {
00215         m_out_elts[ elt ].r = z.r + m_in_elts[ elt ].r;
00216         m_out_elts[ elt ].i = z.i + m_in_elts[ elt ].i;
00217     }
00218 }
00219 
00240 void multiply_matrix_by_scalar_f
00241 (
00242     Matrix_f**      m_out, 
00243     const Matrix_f* m_in, 
00244     float           a
00245 )
00246 {
00247     uint32_t num_elts;
00248 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00249 #else
00250     uint32_t elt;
00251     float*   m_out_elts;
00252     float*   m_in_elts;
00253 #endif
00254 
00255     num_elts = m_in->num_rows*m_in->num_cols;
00256 
00257 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00258     if (*m_out != m_in)
00259     {
00260         copy_matrix_f(m_out, m_in);
00261     }
00262 
00263     blas_sscal(num_elts, a, *((*m_out)->elts), 1);
00264 #else
00265     if (*m_out != m_in)
00266     {
00267         create_matrix_f(m_out, m_in->num_rows, m_in->num_cols);
00268     }
00269 
00270     m_out_elts = *((*m_out)->elts);
00271     m_in_elts  = *(m_in->elts);
00272 
00273     for (elt = 0; elt < num_elts; elt++)
00274     {
00275         m_out_elts[ elt ] = a * m_in_elts[ elt ];
00276     }
00277 #endif
00278 }
00279 
00288 void multiply_matrix_by_scalar_d
00289 (
00290     Matrix_d**      m_out, 
00291     const Matrix_d* m_in, 
00292     double          a
00293 )
00294 {
00295     uint32_t num_elts;
00296 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00297 #else
00298     uint32_t elt;
00299     double*  m_out_elts;
00300     double*  m_in_elts;
00301 #endif
00302 
00303     num_elts = m_in->num_rows*m_in->num_cols;
00304 
00305 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00306     if (*m_out != m_in)
00307     {
00308         copy_matrix_d(m_out, m_in);
00309     }
00310 
00311     blas_dscal(num_elts, a, *((*m_out)->elts), 1);
00312 #else
00313     if (*m_out != m_in)
00314     {
00315         create_matrix_d(m_out, m_in->num_rows, m_in->num_cols);
00316     }
00317 
00318     m_out_elts = *((*m_out)->elts);
00319     m_in_elts  = *(m_in->elts);
00320 
00321     for (elt = 0; elt < num_elts; elt++)
00322     {
00323         m_out_elts[ elt ] = a * m_in_elts[ elt ];
00324     }
00325 #endif
00326 }
00327 
00336 void multiply_matrix_by_scalar_cf
00337 (
00338     Matrix_cf**      m_out, 
00339     const Matrix_cf* m_in, 
00340     Complex_f        z
00341 )
00342 {
00343     uint32_t num_elts;
00344 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00345 #else
00346     uint32_t   elt;
00347     float      r, i;
00348     Complex_f* m_out_elts;
00349     Complex_f* m_in_elts;
00350 #endif
00351 
00352     num_elts = m_in->num_rows*m_in->num_cols;
00353 
00354 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00355     if (*m_out != m_in)
00356     {
00357         copy_matrix_cf(m_out, m_in);
00358     }
00359 
00360     blas_cscal(num_elts, z, *((*m_out)->elts), 1);
00361 #else
00362     if (*m_out != m_in)
00363     {
00364         create_matrix_cf(m_out, m_in->num_rows, m_in->num_cols);
00365     }
00366 
00367     m_out_elts = *((*m_out)->elts);
00368     m_in_elts  = *(m_in->elts);
00369 
00370     for (elt = 0; elt < num_elts; elt++)
00371     {
00372         r = z.r*m_in_elts[ elt ].r - z.i*m_in_elts[ elt ].i;
00373         i = z.i*m_in_elts[ elt ].r + z.r*m_in_elts[ elt ].i;
00374 
00375         m_out_elts[ elt ].r = r;
00376         m_out_elts[ elt ].i = i;
00377     }
00378 #endif
00379 }
00380 
00389 void multiply_matrix_by_scalar_cd
00390 (
00391     Matrix_cd**      m_out, 
00392     const Matrix_cd* m_in, 
00393     Complex_d        z
00394 )
00395 {
00396     uint32_t num_elts;
00397 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00398 #else
00399     uint32_t   elt;
00400     float      r, i;
00401     Complex_d* m_out_elts;
00402     Complex_d* m_in_elts;
00403 #endif
00404 
00405     num_elts = m_in->num_rows*m_in->num_cols;
00406 
00407 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00408     if (*m_out != m_in)
00409     {
00410         copy_matrix_cd(m_out, m_in);
00411     }
00412 
00413     blas_zscal(num_elts, z, *((*m_out)->elts), 1);
00414 #else
00415     if (*m_out != m_in)
00416     {
00417         create_matrix_cd(m_out, m_in->num_rows, m_in->num_cols);
00418     }
00419 
00420     m_out_elts = *((*m_out)->elts);
00421     m_in_elts  = *(m_in->elts);
00422 
00423     for (elt = 0; elt < num_elts; elt++)
00424     {
00425         r = z.r*m_in_elts[ elt ].r - z.i*m_in_elts[ elt ].i;
00426         i = z.i*m_in_elts[ elt ].r + z.r*m_in_elts[ elt ].i;
00427 
00428         m_out_elts[ elt ].r = r;
00429         m_out_elts[ elt ].i = i;
00430     }
00431 #endif
00432 }
00433 
00462 Error* multiply_matrices_f
00463 (
00464     Matrix_f**      m_out, 
00465     const Matrix_f* m_1, 
00466     const Matrix_f* m_2
00467 )
00468 {
00469     uint32_t  num_rows, num_cols;
00470     Matrix_f* m;
00471 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00472 #else
00473     uint32_t row, col;
00474     uint32_t elt;
00475     uint32_t length;
00476     float    sum;
00477 #endif
00478 
00479     if (m_1->num_cols != m_2->num_rows)
00480     {
00481         if (*m_out != m_1 && *m_out != m_2)
00482         {
00483             free_matrix_f(*m_out); *m_out = NULL;
00484         }
00485         return JWSC_EARG("Matrices do not have compatible dimensions");
00486     }
00487 
00488     num_rows = m_1->num_rows;
00489     num_cols = m_2->num_cols;
00490 
00491     m = (*m_out == m_1 || *m_out == m_2) ? NULL : *m_out;
00492     create_matrix_f(&m, num_rows, num_cols);
00493 
00494 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00495     blas_sgemm('N', 'N', m_1->num_rows, m_2->num_cols, m_1->num_cols, 1, 
00496             *(m_1->elts), m_1->num_cols, *(m_2->elts), m_2->num_cols, 0, 
00497             *(m->elts), m->num_cols);
00498 #else
00499     length = m_1->num_cols;
00500     for (row = 0; row < num_rows; row++)
00501     {
00502         for (col = 0; col < num_cols; col++)
00503         {
00504             sum = 0;
00505             for (elt = 0; elt < length; elt++)
00506             {
00507                 sum += m_1->elts[ row ][ elt ] * m_2->elts[ elt ][ col ];
00508             }
00509             m->elts[ row ][ col ] = sum;
00510         }
00511     }
00512 #endif
00513 
00514     if (*m_out == m_1 || *m_out == m_2)
00515     {
00516         copy_matrix_f(m_out, m);
00517         free_matrix_f(m);
00518     }
00519     else
00520     {
00521         *m_out = m;
00522     }
00523 
00524     return NULL;
00525 }
00526 
00543 Error* multiply_matrices_d
00544 (
00545     Matrix_d**      m_out, 
00546     const Matrix_d* m_1, 
00547     const Matrix_d* m_2
00548 )
00549 {
00550     uint32_t  num_rows, num_cols;
00551     Matrix_d* m;
00552 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00553 #else
00554     uint32_t row, col;
00555     uint32_t elt;
00556     uint32_t length;
00557     float    sum;
00558 #endif
00559 
00560     if (m_1->num_cols != m_2->num_rows)
00561     {
00562         if (*m_out != m_1 && *m_out != m_2)
00563         {
00564             free_matrix_d(*m_out); *m_out = NULL;
00565         }
00566         return JWSC_EARG("Matrices do not have compatible dimensions");
00567     }
00568 
00569     num_rows = m_1->num_rows;
00570     num_cols = m_2->num_cols;
00571 
00572     m = (*m_out == m_1 || *m_out == m_2) ? NULL : *m_out;
00573     create_matrix_d(&m, num_rows, num_cols);
00574 
00575 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00576     blas_dgemm('N', 'N', m_1->num_rows, m_2->num_cols, m_1->num_cols, 1, 
00577             *(m_1->elts), m_1->num_cols, *(m_2->elts), m_2->num_cols, 0, 
00578             *(m->elts), m->num_cols);
00579 #else
00580     length = m_1->num_cols;
00581     for (row = 0; row < num_rows; row++)
00582     {
00583         for (col = 0; col < num_cols; col++)
00584         {
00585             sum = 0;
00586             for (elt = 0; elt < length; elt++)
00587             {
00588                 sum += m_1->elts[ row ][ elt ] * m_2->elts[ elt ][ col ];
00589             }
00590             m->elts[ row ][ col ] = sum;
00591         }
00592     }
00593 #endif
00594 
00595     if (*m_out == m_1 || *m_out == m_2)
00596     {
00597         copy_matrix_d(m_out, m);
00598         free_matrix_d(m);
00599     }
00600     else
00601     {
00602         *m_out = m;
00603     }
00604 
00605     return NULL;
00606 }
00607 
00624 Error* multiply_matrices_cf
00625 (
00626     Matrix_cf**      m_out, 
00627     const Matrix_cf* m_1, 
00628     const Matrix_cf* m_2
00629 )
00630 {
00631     uint32_t   num_rows, num_cols;
00632     Matrix_cf* m;
00633 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00634     Complex_f alpha;
00635     Complex_f beta;
00636 #else
00637     uint32_t  row, col;
00638     uint32_t  elt;
00639     uint32_t  length;
00640     Complex_f sum;
00641 #endif
00642 
00643     if (m_1->num_cols != m_2->num_rows)
00644     {
00645         if (*m_out != m_1 && *m_out != m_2)
00646         {
00647             free_matrix_cf(*m_out); *m_out = NULL;
00648         }
00649         return JWSC_EARG("Matrices do not have compatible dimensions");
00650     }
00651 
00652     num_rows = m_1->num_rows;
00653     num_cols = m_2->num_cols;
00654 
00655     m = (*m_out == m_1 || *m_out == m_2) ? NULL : *m_out;
00656     create_matrix_cf(&m, num_rows, num_cols);
00657 
00658 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00659     alpha.r = 1; alpha.i = 1;
00660     beta.r  = 0; beta.i  = 0;
00661     blas_cgemm('N', 'N', m_1->num_rows, m_2->num_cols, m_1->num_cols, alpha, 
00662             *(m_1->elts), m_1->num_cols, *(m_2->elts), m_2->num_cols, beta, 
00663             *(m->elts), m->num_cols);
00664 #else
00665     length = m_1->num_cols;
00666     for (row = 0; row < num_rows; row++)
00667     {
00668         for (col = 0; col < num_cols; col++)
00669         {
00670             sum.r = 0; 
00671             sum.i = 0;
00672             for (elt = 0; elt < length; elt++)
00673             {
00674                 sum.r += m_1->elts[ row ][ elt ].r * m_2->elts[ elt ][ col ].r -
00675                          m_1->elts[ row ][ elt ].i * m_2->elts[ elt ][ col ].i;
00676                 sum.i += m_1->elts[ row ][ elt ].i * m_2->elts[ elt ][ col ].r +
00677                          m_1->elts[ row ][ elt ].r * m_2->elts[ elt ][ col ].i;
00678             }
00679             m->elts[ row ][ col ].r = sum.r;
00680             m->elts[ row ][ col ].i = sum.i;
00681         }
00682     }
00683 #endif
00684 
00685     if (*m_out == m_1 || *m_out == m_2)
00686     {
00687         copy_matrix_cf(m_out, m);
00688         free_matrix_cf(m);
00689     }
00690     else
00691     {
00692         *m_out = m;
00693     }
00694 
00695     return NULL;
00696 }
00697 
00714 Error* multiply_matrices_cd
00715 (
00716     Matrix_cd**      m_out, 
00717     const Matrix_cd* m_1, 
00718     const Matrix_cd* m_2
00719 )
00720 {
00721     uint32_t   num_rows, num_cols;
00722     Matrix_cd* m;
00723 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00724     Complex_d alpha;
00725     Complex_d beta;
00726 #else
00727     uint32_t  row, col;
00728     uint32_t  elt;
00729     uint32_t  length;
00730     Complex_d sum;
00731 #endif
00732 
00733     if (m_1->num_cols != m_2->num_rows)
00734     {
00735         if (*m_out != m_1 && *m_out != m_2)
00736         {
00737             free_matrix_cd(*m_out); *m_out = NULL;
00738         }
00739         return JWSC_EARG("Matrices do not have compatible dimensions");
00740     }
00741 
00742     num_rows = m_1->num_rows;
00743     num_cols = m_2->num_cols;
00744 
00745     m = (*m_out == m_1 || *m_out == m_2) ? NULL : *m_out;
00746     create_matrix_cd(&m, num_rows, num_cols);
00747 
00748 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00749     alpha.r = 1; alpha.i = 1;
00750     beta.r  = 0; beta.i  = 0;
00751     blas_zgemm('N', 'N', m_1->num_rows, m_2->num_cols, m_1->num_cols, alpha, 
00752             *(m_1->elts), m_1->num_cols, *(m_2->elts), m_2->num_cols, beta, 
00753             *(m->elts), m->num_cols);
00754 #else
00755     length = m_1->num_cols;
00756     for (row = 0; row < num_rows; row++)
00757     {
00758         for (col = 0; col < num_cols; col++)
00759         {
00760             sum.r = 0; 
00761             sum.i = 0;
00762             for (elt = 0; elt < length; elt++)
00763             {
00764                 sum.r += m_1->elts[ row ][ elt ].r * m_2->elts[ elt ][ col ].r -
00765                          m_1->elts[ row ][ elt ].i * m_2->elts[ elt ][ col ].i;
00766                 sum.i += m_1->elts[ row ][ elt ].i * m_2->elts[ elt ][ col ].r +
00767                          m_1->elts[ row ][ elt ].r * m_2->elts[ elt ][ col ].i;
00768             }
00769             m->elts[ row ][ col ].r = sum.r;
00770             m->elts[ row ][ col ].i = sum.i;
00771         }
00772     }
00773 #endif
00774 
00775     if (*m_out == m_1 || *m_out == m_2)
00776     {
00777         copy_matrix_cd(m_out, m);
00778         free_matrix_cd(m);
00779     }
00780     else
00781     {
00782         *m_out = m;
00783     }
00784 
00785     return NULL;
00786 }
00787 
00815 Error* multiply_matrices_elt_wise_f
00816 (
00817     Matrix_f**      m_out, 
00818     const Matrix_f* m_1, 
00819     const Matrix_f* m_2
00820 )
00821 {
00822     uint32_t  num_rows, num_cols;
00823     uint32_t  num_elts;
00824     uint32_t  elt;
00825     float*    m_out_elts;
00826     float*    m_1_elts;
00827     float*    m_2_elts;
00828 
00829     num_rows = m_1->num_rows;
00830     num_cols = m_1->num_cols;
00831 
00832     if (num_rows != m_2->num_rows ||  num_cols != m_2->num_cols)
00833     {
00834         if (*m_out != m_1 && *m_out != m_2)
00835         {
00836             free_matrix_f(*m_out); *m_out = NULL;
00837         }
00838         return JWSC_EARG("Matrices do not have the same dimensions");
00839     }
00840 
00841     create_matrix_f(m_out, num_rows, num_cols);
00842 
00843     m_out_elts = *((*m_out)->elts);
00844     m_1_elts   = *(m_1->elts);
00845     m_2_elts   = *(m_2->elts);
00846 
00847     num_elts = num_rows*num_cols;
00848     for (elt = 0; elt < num_elts; elt++)
00849     {
00850         m_out_elts[ elt ] = m_1_elts[ elt ]*m_2_elts[ elt ];
00851     }
00852 
00853     return NULL;
00854 }
00855 
00857 Error* multiply_matrices_elt_wise_d
00858 (
00859     Matrix_d**      m_out, 
00860     const Matrix_d* m_1, 
00861     const Matrix_d* m_2
00862 )
00863 {
00864     uint32_t  num_rows, num_cols;
00865     uint32_t  num_elts;
00866     uint32_t  elt;
00867     double*   m_out_elts;
00868     double*   m_1_elts;
00869     double*   m_2_elts;
00870 
00871     num_rows = m_1->num_rows;
00872     num_cols = m_1->num_cols;
00873 
00874     if (num_rows != m_2->num_rows ||  num_cols != m_2->num_cols)
00875     {
00876         if (*m_out != m_1 && *m_out != m_2)
00877         {
00878             free_matrix_d(*m_out); *m_out = NULL;
00879         }
00880         return JWSC_EARG("Matrices do not have the same dimensions");
00881     }
00882 
00883     create_matrix_d(m_out, num_rows, num_cols);
00884 
00885     m_out_elts = *((*m_out)->elts);
00886     m_1_elts   = *(m_1->elts);
00887     m_2_elts   = *(m_2->elts);
00888 
00889     num_elts = num_rows*num_cols;
00890     for (elt = 0; elt < num_elts; elt++)
00891     {
00892         m_out_elts[ elt ] = m_1_elts[ elt ]*m_2_elts[ elt ];
00893     }
00894 
00895     return NULL;
00896 }
00897 
00901 Error* multiply_matrices_elt_wise_cf
00902 (
00903     Matrix_cf**      m_out, 
00904     const Matrix_cf* m_1, 
00905     const Matrix_cf* m_2
00906 )
00907 {
00908     uint32_t   num_rows, num_cols;
00909     uint32_t   num_elts;
00910     uint32_t   elt;
00911     float      r, i;
00912     Complex_f* m_out_elts;
00913     Complex_f* m_1_elts;
00914     Complex_f* m_2_elts;
00915 
00916     num_rows = m_1->num_rows;
00917     num_cols = m_1->num_cols;
00918 
00919     if (num_rows != m_2->num_rows ||  num_cols != m_2->num_cols)
00920     {
00921         if (*m_out != m_1 && *m_out != m_2)
00922         {
00923             free_matrix_cf(*m_out); *m_out = NULL;
00924         }
00925         return JWSC_EARG("Matrices do not have the same dimensions");
00926     }
00927 
00928     create_matrix_cf(m_out, num_rows, num_cols);
00929 
00930     m_out_elts = *((*m_out)->elts);
00931     m_1_elts   = *(m_1->elts);
00932     m_2_elts   = *(m_2->elts);
00933 
00934     num_elts = num_rows*num_cols;
00935     for (elt = 0; elt < num_elts; elt++)
00936     {
00937         r = m_1_elts[ elt ].r * m_2_elts[ elt ].r -
00938             m_1_elts[ elt ].i * m_2_elts[ elt ].i;
00939         i = m_1_elts[ elt ].i * m_2_elts[ elt ].r +
00940             m_1_elts[ elt ].r * m_2_elts[ elt ].i;
00941 
00942         m_out_elts[ elt ].r = r;
00943         m_out_elts[ elt ].i = i;
00944     }
00945 
00946     return NULL;
00947 }
00948 
00952 Error* multiply_matrices_elt_wise_cd
00953 (
00954     Matrix_cd**      m_out, 
00955     const Matrix_cd* m_1, 
00956     const Matrix_cd* m_2
00957 )
00958 {
00959     uint32_t   num_rows, num_cols;
00960     uint32_t   num_elts;
00961     uint32_t   elt;
00962     float      r, i;
00963     Complex_d* m_out_elts;
00964     Complex_d* m_1_elts;
00965     Complex_d* m_2_elts;
00966 
00967     num_rows = m_1->num_rows;
00968     num_cols = m_1->num_cols;
00969 
00970     if (num_rows != m_2->num_rows ||  num_cols != m_2->num_cols)
00971     {
00972         if (*m_out != m_1 && *m_out != m_2)
00973         {
00974             free_matrix_cd(*m_out); *m_out = NULL;
00975         }
00976         return JWSC_EARG("Matrices do not have the same dimensions");
00977     }
00978 
00979     create_matrix_cd(m_out, num_rows, num_cols);
00980 
00981     m_out_elts = *((*m_out)->elts);
00982     m_1_elts   = *(m_1->elts);
00983     m_2_elts   = *(m_2->elts);
00984 
00985     num_elts = num_rows*num_cols;
00986     for (elt = 0; elt < num_elts; elt++)
00987     {
00988         r = m_1_elts[ elt ].r * m_2_elts[ elt ].r -
00989             m_1_elts[ elt ].i * m_2_elts[ elt ].i;
00990         i = m_1_elts[ elt ].i * m_2_elts[ elt ].r +
00991             m_1_elts[ elt ].r * m_2_elts[ elt ].i;
00992 
00993         m_out_elts[ elt ].r = r;
00994         m_out_elts[ elt ].i = i;
00995     }
00996 
00997     return NULL;
00998 }
00999 
01019 void transpose_matrix_f(Matrix_f** m_out, const Matrix_f* m_in)
01020 {
01021     uint32_t  num_rows, num_cols;
01022     uint32_t  row, col;
01023     Matrix_f* m;
01024 
01025     num_rows = m_in->num_cols;
01026     num_cols = m_in->num_rows;
01027 
01028     m = (*m_out == m_in) ? NULL : *m_out;
01029     create_matrix_f(&m, num_rows, num_cols);
01030 
01031     for (row = 0; row < num_rows; row++)
01032     {
01033         for (col = 0; col < num_cols; col++)
01034         {
01035             m->elts[ row ][ col ] = m_in->elts[ col ][ row ];
01036         }
01037     }
01038 
01039     if (*m_out == m_in)
01040     {
01041         copy_matrix_f(m_out, m);
01042         free_matrix_f(m);
01043     }
01044     else
01045     {
01046         *m_out = m;
01047     }
01048 }
01049 
01057 void transpose_matrix_d(Matrix_d** m_out, const Matrix_d* m_in)
01058 {
01059     uint32_t  num_rows, num_cols;
01060     uint32_t  row, col;
01061     Matrix_d* m;
01062 
01063     num_rows = m_in->num_cols;
01064     num_cols = m_in->num_rows;
01065 
01066     m = (*m_out == m_in) ? NULL : *m_out;
01067     create_matrix_d(&m, num_rows, num_cols);
01068 
01069     for (row = 0; row < num_rows; row++)
01070     {
01071         for (col = 0; col < num_cols; col++)
01072         {
01073             m->elts[ row ][ col ] = m_in->elts[ col ][ row ];
01074         }
01075     }
01076 
01077     if (*m_out == m_in)
01078     {
01079         copy_matrix_d(m_out, m);
01080         free_matrix_d(m);
01081     }
01082     else
01083     {
01084         *m_out = m;
01085     }
01086 }
01087 
01095 void transpose_matrix_cf(Matrix_cf** m_out, const Matrix_cf* m_in)
01096 {
01097     uint32_t   num_rows, num_cols;
01098     uint32_t   row, col;
01099     Matrix_cf* m;
01100 
01101     num_rows = m_in->num_cols;
01102     num_cols = m_in->num_rows;
01103 
01104     m = (*m_out == m_in) ? NULL : *m_out;
01105     create_matrix_cf(&m, num_rows, num_cols);
01106 
01107     for (row = 0; row < num_rows; row++)
01108     {
01109         for (col = 0; col < num_cols; col++)
01110         {
01111             m->elts[ row ][ col ] = m_in->elts[ col ][ row ];
01112         }
01113     }
01114 
01115     if (*m_out == m_in)
01116     {
01117         copy_matrix_cf(m_out, m);
01118         free_matrix_cf(m);
01119     }
01120     else
01121     {
01122         *m_out = m;
01123     }
01124 }
01125 
01133 void transpose_matrix_cd(Matrix_cd** m_out, const Matrix_cd* m_in)
01134 {
01135     uint32_t   num_rows, num_cols;
01136     uint32_t   row, col;
01137     Matrix_cd* m;
01138 
01139     num_rows = m_in->num_cols;
01140     num_cols = m_in->num_rows;
01141 
01142     m = (*m_out == m_in) ? NULL : *m_out;
01143     create_matrix_cd(&m, num_rows, num_cols);
01144 
01145     for (row = 0; row < num_rows; row++)
01146     {
01147         for (col = 0; col < num_cols; col++)
01148         {
01149             m->elts[ row ][ col ] = m_in->elts[ col ][ row ];
01150         }
01151     }
01152 
01153     if (*m_out == m_in)
01154     {
01155         copy_matrix_cd(m_out, m);
01156         free_matrix_cd(m);
01157     }
01158     else
01159     {
01160         *m_out = m;
01161     }
01162 }
01163 
01193 Error* multiply_matrix_and_vector_f
01194 (
01195     Vector_f**      v_out, 
01196     const Matrix_f* m_in, 
01197     const Vector_f* v_in
01198 )
01199 {
01200     Vector_f* v;
01201 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01202 #else
01203     uint32_t num_rows, num_cols;
01204     uint32_t row, col;
01205     float    sum;
01206 #endif
01207 
01208     if (m_in->num_cols != v_in->num_elts)
01209     {
01210         if (*v_out != v_in)
01211         {
01212             free_vector_f(*v_out); *v_out = NULL;
01213         }
01214         return JWSC_EARG("Matrix and vector do not have compatible dimensions");
01215     }
01216 
01217     v = (*v_out == v_in) ? NULL : *v_out;
01218     create_vector_f(&v, m_in->num_rows);
01219 
01220 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01221     blas_sgemv('N', m_in->num_rows, m_in->num_cols, 1, *(m_in->elts), 
01222             m_in->num_cols, v_in->elts, 1, 0, v->elts, 1);
01223 #else
01224     num_rows = m_in->num_rows;
01225     num_cols = m_in->num_cols;
01226 
01227     for (row = 0; row < num_rows; row++)
01228     {
01229         sum = 0;
01230         for (col = 0; col < num_cols; col++)
01231         {
01232             sum += m_in->elts[ row ][ col ] * v_in->elts[ col ];
01233         }
01234         v->elts[ row ] = sum;
01235     }
01236 #endif
01237 
01238     if (*v_out == v_in)
01239     {
01240         copy_vector_f(v_out, v);
01241         free_vector_f(v);
01242     }
01243     else
01244     {
01245         *v_out = v;
01246     }
01247 
01248     return NULL;
01249 }
01250 
01268 Error* multiply_matrix_and_vector_d
01269 (
01270     Vector_d**      v_out, 
01271     const Matrix_d* m_in, 
01272     const Vector_d* v_in
01273 )
01274 {
01275     Vector_d* v;
01276 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01277 #else
01278     uint32_t num_rows, num_cols;
01279     uint32_t row, col;
01280     double   sum;
01281 #endif
01282 
01283     if (m_in->num_cols != v_in->num_elts)
01284     {
01285         if (*v_out != v_in)
01286         {
01287             free_vector_d(*v_out); *v_out = NULL;
01288         }
01289         return JWSC_EARG("Matrix and vector do not have compatible dimensions");
01290     }
01291 
01292     v = (*v_out == v_in) ? NULL : *v_out;
01293     create_vector_d(&v, m_in->num_rows);
01294 
01295 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01296     blas_dgemv('N', m_in->num_rows, m_in->num_cols, 1, *(m_in->elts), 
01297             m_in->num_cols, v_in->elts, 1, 0, v->elts, 1);
01298 #else
01299     num_rows = m_in->num_rows;
01300     num_cols = m_in->num_cols;
01301 
01302     for (row = 0; row < num_rows; row++)
01303     {
01304         sum = 0;
01305         for (col = 0; col < num_cols; col++)
01306         {
01307             sum += m_in->elts[ row ][ col ] * v_in->elts[ col ];
01308         }
01309         v->elts[ row ] = sum;
01310     }
01311 #endif
01312 
01313     if (*v_out == v_in)
01314     {
01315         copy_vector_d(v_out, v);
01316         free_vector_d(v);
01317     }
01318     else
01319     {
01320         *v_out = v;
01321     }
01322 
01323     return NULL;
01324 }
01325 
01343 Error* multiply_matrix_and_vector_cf
01344 (
01345     Vector_cf**      v_out, 
01346     const Matrix_cf* m_in, 
01347     const Vector_cf* v_in
01348 )
01349 {
01350     Vector_cf* v;
01351 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01352     Complex_f alpha;
01353     Complex_f beta;
01354 #else
01355     uint32_t  num_rows, num_cols;
01356     uint32_t  row, col;
01357     Complex_f sum;
01358 #endif
01359 
01360     if (m_in->num_cols != v_in->num_elts)
01361     {
01362         if (*v_out != v_in)
01363         {
01364             free_vector_cf(*v_out); *v_out = NULL;
01365         }
01366         return JWSC_EARG("Matrix and vector do not have compatible dimensions");
01367     }
01368 
01369     v = (*v_out == v_in) ? NULL : *v_out;
01370     create_vector_cf(&v, m_in->num_rows);
01371 
01372 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01373     alpha.r = 1; alpha.i = 1;
01374     beta.r  = 0; beta.i  = 0;
01375     blas_cgemv('N', m_in->num_rows, m_in->num_cols, alpha, *(m_in->elts), 
01376             m_in->num_cols, v_in->elts, 1, beta, v->elts, 1);
01377 #else
01378     num_rows = m_in->num_rows;
01379     num_cols = m_in->num_cols;
01380 
01381     for (row = 0; row < num_rows; row++)
01382     {
01383         sum.r = 0;
01384         sum.i = 0;
01385         for (col = 0; col < num_cols; col++)
01386         {
01387             sum.r += m_in->elts[ row ][ col ].r * v_in->elts[ col ].r -
01388                      m_in->elts[ row ][ col ].i * v_in->elts[ col ].i;
01389             sum.i += m_in->elts[ row ][ col ].i * v_in->elts[ col ].r +
01390                      m_in->elts[ row ][ col ].r * v_in->elts[ col ].i;
01391         }
01392         v->elts[ row ].r = sum.r;
01393         v->elts[ row ].i = sum.i;
01394     }
01395 #endif
01396 
01397     if (*v_out == v_in)
01398     {
01399         copy_vector_cf(v_out, v);
01400         free_vector_cf(v);
01401     }
01402     else
01403     {
01404         *v_out = v;
01405     }
01406 
01407     return NULL;
01408 }
01409 
01427 Error* multiply_matrix_and_vector_cd
01428 (
01429     Vector_cd**      v_out, 
01430     const Matrix_cd* m_in, 
01431     const Vector_cd* v_in
01432 )
01433 {
01434     Vector_cd* v;
01435 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01436     Complex_d alpha;
01437     Complex_d beta;
01438 #else
01439     uint32_t  num_rows, num_cols;
01440     uint32_t  row, col;
01441     Complex_d sum;
01442 #endif
01443 
01444     if (m_in->num_cols != v_in->num_elts)
01445     {
01446         if (*v_out != v_in)
01447         {
01448             free_vector_cd(*v_out); *v_out = NULL;
01449         }
01450         return JWSC_EARG("Matrix and vector do not have compatible dimensions");
01451     }
01452 
01453     v = (*v_out == v_in) ? NULL : *v_out;
01454     create_vector_cd(&v, m_in->num_rows);
01455 
01456 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01457     alpha.r = 1; alpha.i = 1;
01458     beta.r  = 0; beta.i  = 0;
01459     blas_zgemv('N', m_in->num_rows, m_in->num_cols, alpha, *(m_in->elts), 
01460             m_in->num_cols, v_in->elts, 1, beta, v->elts, 1);
01461 #else
01462     num_rows = m_in->num_rows;
01463     num_cols = m_in->num_cols;
01464 
01465     for (row = 0; row < num_rows; row++)
01466     {
01467         sum.r = 0;
01468         sum.i = 0;
01469         for (col = 0; col < num_cols; col++)
01470         {
01471             sum.r += m_in->elts[ row ][ col ].r * v_in->elts[ col ].r -
01472                      m_in->elts[ row ][ col ].i * v_in->elts[ col ].i;
01473             sum.i += m_in->elts[ row ][ col ].i * v_in->elts[ col ].r +
01474                      m_in->elts[ row ][ col ].r * v_in->elts[ col ].i;
01475         }
01476         v->elts[ row ].r = sum.r;
01477         v->elts[ row ].i = sum.i;
01478     }
01479 #endif
01480 
01481     if (*v_out == v_in)
01482     {
01483         copy_vector_cd(v_out, v);
01484         free_vector_cd(v);
01485     }
01486     else
01487     {
01488         *v_out = v;
01489     }
01490 
01491     return NULL;
01492 }
01493 
01494 
01495 
01496 
01519 Error* add_matrices_f
01520 (
01521     Matrix_f**      m_out, 
01522     const Matrix_f* m_1, 
01523     const Matrix_f* m_2
01524 )
01525 {
01526     uint32_t num_elts;
01527 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01528 #else
01529     uint32_t elt;
01530     float*   m_1_elts;
01531     float*   m_2_elts;
01532     float*   m_out_elts;
01533 #endif
01534 
01535     if (m_1->num_rows != m_2->num_rows || m_1->num_cols != m_2->num_cols)
01536     {
01537         if (*m_out != m_1 && *m_out != m_2)
01538         {
01539             free_matrix_f(*m_out); *m_out = NULL;
01540         }
01541         return JWSC_EARG("Adding matrices requires equal dimensions");
01542     }
01543 
01544     num_elts = m_1->num_rows*m_1->num_cols;
01545 
01546 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01547     if (*m_out == m_1)
01548     {
01549         blas_saxpy(num_elts, 1, *(m_2->elts), 1, *(m_1->elts), 1);
01550     }
01551     else if (*m_out == m_2)
01552     {
01553         blas_saxpy(num_elts, 1, *(m_1->elts), 1, *(m_2->elts), 1);
01554     }
01555     else
01556     {
01557         copy_matrix_f(m_out, m_2);
01558         blas_saxpy(num_elts, 1, *(m_1->elts), 1, *((*m_out)->elts), 1);
01559     }
01560 #else
01561     m_1_elts   = *(m_1->elts);
01562     m_2_elts   = *(m_2->elts);
01563     m_out_elts = *((*m_out)->elts);
01564 
01565     if (*m_out == m_1)
01566     {
01567         for (elt = 0; elt < num_elts; elt++)
01568         {
01569             m_1_elts[ elt ] += m_2_elts[ elt ];
01570         }
01571     }
01572     else if (*m_out == m_2)
01573     {
01574         for (elt = 0; elt < num_elts; elt++)
01575         {
01576             m_2_elts[ elt ] += m_1_elts[ elt ];
01577         }
01578     }
01579     else
01580     {
01581         create_matrix_f(m_out, m_1->num_rows, m_1->num_cols);
01582         for (elt = 0; elt < num_elts; elt++)
01583         {
01584             m_out_elts[ elt ] = m_1_elts[ elt ] + m_2_elts[ elt ];
01585         }
01586     }
01587 #endif
01588 
01589     return NULL;
01590 }
01591 
01607 Error* add_matrices_d
01608 (
01609     Matrix_d**      m_out, 
01610     const Matrix_d* m_1, 
01611     const Matrix_d* m_2
01612 )
01613 {
01614     uint32_t num_elts;
01615 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01616 #else
01617     uint32_t elt;
01618     double*  m_1_elts;
01619     double*  m_2_elts;
01620     double*  m_out_elts;
01621 #endif
01622 
01623     if (m_1->num_rows != m_2->num_rows || m_1->num_cols != m_2->num_cols)
01624     {
01625         if (*m_out != m_1 && *m_out != m_2)
01626         {
01627             free_matrix_d(*m_out); *m_out = NULL;
01628         }
01629         return JWSC_EARG("Adding matrices requires equal dimensions");
01630     }
01631 
01632     num_elts = m_1->num_rows*m_1->num_cols;
01633 
01634 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01635     if (*m_out == m_1)
01636     {
01637         blas_daxpy(num_elts, 1, *(m_2->elts), 1, *(m_1->elts), 1);
01638     }
01639     else if (*m_out == m_2)
01640     {
01641         blas_daxpy(num_elts, 1, *(m_1->elts), 1, *(m_2->elts), 1);
01642     }
01643     else
01644     {
01645         copy_matrix_d(m_out, m_2);
01646         blas_daxpy(num_elts, 1, *(m_1->elts), 1, *((*m_out)->elts), 1);
01647     }
01648 #else
01649     m_1_elts   = *(m_1->elts);
01650     m_2_elts   = *(m_2->elts);
01651     m_out_elts = *((*m_out)->elts);
01652 
01653     if (*m_out == m_1)
01654     {
01655         for (elt = 0; elt < num_elts; elt++)
01656         {
01657             m_1_elts[ elt ] += m_2_elts[ elt ];
01658         }
01659     }
01660     else if (*m_out == m_2)
01661     {
01662         for (elt = 0; elt < num_elts; elt++)
01663         {
01664             m_2_elts[ elt ] += m_1_elts[ elt ];
01665         }
01666     }
01667     else
01668     {
01669         create_matrix_d(m_out, m_1->num_rows, m_1->num_cols);
01670         for (elt = 0; elt < num_elts; elt++)
01671         {
01672             m_out_elts[ elt ] = m_1_elts[ elt ] + m_2_elts[ elt ];
01673         }
01674     }
01675 #endif
01676 
01677     return NULL;
01678 }
01679 
01695 Error* add_matrices_cf
01696 (
01697     Matrix_cf**      m_out, 
01698     const Matrix_cf* m_1, 
01699     const Matrix_cf* m_2
01700 )
01701 {
01702     uint32_t num_elts;
01703 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01704     Complex_f z = {1, 0};
01705 #else
01706     uint32_t elt;
01707     Complex_f* m_1_elts;
01708     Complex_f* m_2_elts;
01709     Complex_f* m_out_elts;
01710 #endif
01711 
01712     if (m_1->num_rows != m_2->num_rows || m_1->num_cols != m_2->num_cols)
01713     {
01714         if (*m_out != m_1 && *m_out != m_2)
01715         {
01716             free_matrix_cf(*m_out); *m_out = NULL;
01717         }
01718         return JWSC_EARG("Adding matrices requires equal dimensions");
01719     }
01720 
01721     num_elts = m_1->num_rows*m_1->num_cols;
01722 
01723 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01724     if (*m_out == m_1)
01725     {
01726         blas_caxpy(num_elts, z, *(m_2->elts), 1, *(m_1->elts), 1);
01727     }
01728     else if (*m_out == m_2)
01729     {
01730         blas_caxpy(num_elts, z, *(m_1->elts), 1, *(m_2->elts), 1);
01731     }
01732     else
01733     {
01734         copy_matrix_cf(m_out, m_2);
01735         blas_caxpy(num_elts, z, *(m_1->elts), 1, *((*m_out)->elts), 1);
01736     }
01737 #else
01738     m_1_elts   = *(m_1->elts);
01739     m_2_elts   = *(m_2->elts);
01740     m_out_elts = *((*m_out)->elts);
01741 
01742     if (*m_out == m_1)
01743     {
01744         for (elt = 0; elt < num_elts; elt++)
01745         {
01746             m_1_elts[ elt ].r = m_1_elts[ elt ].r + m_2_elts[ elt ].r;
01747             m_1_elts[ elt ].i = m_1_elts[ elt ].i + m_2_elts[ elt ].i;
01748         }
01749     }
01750     else if (*m_out == m_2)
01751     {
01752         for (elt = 0; elt < num_elts; elt++)
01753         {
01754             m_2_elts[ elt ].r = m_1_elts[ elt ].r + m_2_elts[ elt ].r;
01755             m_2_elts[ elt ].i = m_1_elts[ elt ].i + m_2_elts[ elt ].i;
01756         }
01757     }
01758     else
01759     {
01760         create_matrix_cf(m_out, m_1->num_rows, m_1->num_cols);
01761         for (elt = 0; elt < num_elts; elt++)
01762         {
01763             m_out_elts[ elt ].r = m_1_elts[ elt ].r + m_2_elts[ elt ].r;
01764             m_out_elts[ elt ].i = m_1_elts[ elt ].i + m_2_elts[ elt ].i;
01765         }
01766     }
01767 #endif
01768 
01769     return NULL;
01770 }
01771 
01787 Error* add_matrices_cd
01788 (
01789     Matrix_cd**      m_out, 
01790     const Matrix_cd* m_1, 
01791     const Matrix_cd* m_2
01792 )
01793 {
01794     uint32_t num_elts;
01795 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01796     Complex_d z = {1, 0};
01797 #else
01798     uint32_t elt;
01799     Complex_d* m_1_elts;
01800     Complex_d* m_2_elts;
01801     Complex_d* m_out_elts;
01802 #endif
01803 
01804     if (m_1->num_rows != m_2->num_rows || m_1->num_cols != m_2->num_cols)
01805     {
01806         if (*m_out != m_1 && *m_out != m_2)
01807         {
01808             free_matrix_cd(*m_out); *m_out = NULL;
01809         }
01810         return JWSC_EARG("Adding matrices requires equal dimensions");
01811     }
01812 
01813     num_elts = m_1->num_rows*m_1->num_cols;
01814 
01815 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01816     if (*m_out == m_1)
01817     {
01818         blas_zaxpy(num_elts, z, *(m_2->elts), 1, *(m_1->elts), 1);
01819     }
01820     else if (*m_out == m_2)
01821     {
01822         blas_zaxpy(num_elts, z, *(m_1->elts), 1, *(m_2->elts), 1);
01823     }
01824     else
01825     {
01826         copy_matrix_cd(m_out, m_2);
01827         blas_zaxpy(num_elts, z, *(m_1->elts), 1, *((*m_out)->elts), 1);
01828     }
01829 #else
01830     m_1_elts   = *(m_1->elts);
01831     m_2_elts   = *(m_2->elts);
01832     m_out_elts = *((*m_out)->elts);
01833 
01834     if (*m_out == m_1)
01835     {
01836         for (elt = 0; elt < num_elts; elt++)
01837         {
01838             m_1_elts[ elt ].r = m_1_elts[ elt ].r + m_2_elts[ elt ].r;
01839             m_1_elts[ elt ].i = m_1_elts[ elt ].i + m_2_elts[ elt ].i;
01840         }
01841     }
01842     else if (*m_out == m_2)
01843     {
01844         for (elt = 0; elt < num_elts; elt++)
01845         {
01846             m_2_elts[ elt ].r = m_1_elts[ elt ].r + m_2_elts[ elt ].r;
01847             m_2_elts[ elt ].i = m_1_elts[ elt ].i + m_2_elts[ elt ].i;
01848         }
01849     }
01850     else
01851     {
01852         create_matrix_cd(m_out, m_1->num_rows, m_1->num_cols);
01853         for (elt = 0; elt < num_elts; elt++)
01854         {
01855             m_out_elts[ elt ].r = m_1_elts[ elt ].r + m_2_elts[ elt ].r;
01856             m_out_elts[ elt ].i = m_1_elts[ elt ].i + m_2_elts[ elt ].i;
01857         }
01858     }
01859 #endif
01860 
01861     return NULL;
01862 }
01863 
01891 Error* subtract_matrices_f
01892 (
01893     Matrix_f**      m_out, 
01894     const Matrix_f* m_1, 
01895     const Matrix_f* m_2
01896 )
01897 {
01898     uint32_t num_elts;
01899 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01900     Matrix_f* m = NULL;
01901 #else
01902     uint32_t elt;
01903     float*   m_1_elts;
01904     float*   m_2_elts;
01905     float*   m_out_elts;
01906 #endif
01907 
01908     if (m_1->num_rows != m_2->num_rows || m_1->num_cols != m_2->num_cols)
01909     {
01910         if (*m_out != m_1 && *m_out != m_2)
01911         {
01912             free_matrix_f(*m_out); *m_out = NULL;
01913         }
01914         return JWSC_EARG("Subtracting matrices requires equal dimensions");
01915     }
01916 
01917     num_elts = m_1->num_rows*m_1->num_cols;
01918 
01919 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01920     if (*m_out == m_1)
01921     {
01922         blas_saxpy(num_elts, -1, *(m_2->elts), 1, *(m_1->elts), 1);
01923     }
01924     else if (*m_out == m_2)
01925     {
01926         copy_matrix_f(&m, m_1);
01927         blas_saxpy(num_elts, -1, *(m_2->elts), 1, *(m->elts), 1);
01928         copy_matrix_f(m_out, m);
01929         free_matrix_f(m);
01930     }
01931     else
01932     {
01933         copy_matrix_f(m_out, m_1);
01934         blas_saxpy(num_elts, -1, *(m_2->elts), 1, *((*m_out)->elts), 1);
01935     }
01936 #else
01937     m_1_elts   = *(m_1->elts);
01938     m_2_elts   = *(m_2->elts);
01939     m_out_elts = *((*m_out)->elts);
01940 
01941     if (*m_out == m_1)
01942     {
01943         for (elt = 0; elt < num_elts; elt++)
01944         {
01945             m_1_elts[ elt ] = m_1_elts[ elt ] - m_2_elts[ elt ];
01946         }
01947     }
01948     else if (*m_out == m_2)
01949     {
01950         for (elt = 0; elt < num_elts; elt++)
01951         {
01952             m_2_elts[ elt ] = m_1_elts[ elt ] - m_2_elts[ elt ];
01953         }
01954     }
01955     else
01956     {
01957         create_matrix_f(m_out, m_1->num_rows, m_1->num_cols);
01958         for (elt = 0; elt < num_elts; elt++)
01959         {
01960             m_out_elts[ elt ] = m_1_elts[ elt ] - m_2_elts[ elt ];
01961         }
01962     }
01963 #endif
01964 
01965     return NULL;
01966 }
01967 
01983 Error* subtract_matrices_d
01984 (
01985     Matrix_d**      m_out, 
01986     const Matrix_d* m_1, 
01987     const Matrix_d* m_2
01988 )
01989 {
01990     uint32_t num_elts;
01991 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01992     Matrix_d* m = NULL;
01993 #else
01994     uint32_t elt;
01995     double*  m_1_elts;
01996     double*  m_2_elts;
01997     double*  m_out_elts;
01998 #endif
01999 
02000     if (m_1->num_rows != m_2->num_rows || m_1->num_cols != m_2->num_cols)
02001     {
02002         if (*m_out != m_1 && *m_out != m_2)
02003         {
02004             free_matrix_d(*m_out); *m_out = NULL;
02005         }
02006         return JWSC_EARG("Subtracting matrices requires equal dimensions");
02007     }
02008 
02009     num_elts = m_1->num_rows*m_1->num_cols;
02010 
02011 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
02012     if (*m_out == m_1)
02013     {
02014         blas_daxpy(num_elts, -1, *(m_2->elts), 1, *(m_1->elts), 1);
02015     }
02016     else if (*m_out == m_2)
02017     {
02018         copy_matrix_d(&m, m_1);
02019         blas_daxpy(num_elts, -1, *(m_2->elts), 1, *(m->elts), 1);
02020         copy_matrix_d(m_out, m);
02021         free_matrix_d(m);
02022     }
02023     else
02024     {
02025         copy_matrix_d(m_out, m_1);
02026         blas_daxpy(num_elts, -1, *(m_2->elts), 1, *((*m_out)->elts), 1);
02027     }
02028 #else
02029     m_1_elts   = *(m_1->elts);
02030     m_2_elts   = *(m_2->elts);
02031     m_out_elts = *((*m_out)->elts);
02032 
02033     if (*m_out == m_1)
02034     {
02035         for (elt = 0; elt < num_elts; elt++)
02036         {
02037             m_1_elts[ elt ] = m_1_elts[ elt ] - m_2_elts[ elt ];
02038         }
02039     }
02040     else if (*m_out == m_2)
02041     {
02042         for (elt = 0; elt < num_elts; elt++)
02043         {
02044             m_2_elts[ elt ] = m_1_elts[ elt ] - m_2_elts[ elt ];
02045         }
02046     }
02047     else
02048     {
02049         create_matrix_d(m_out, m_1->num_rows, m_1->num_cols);
02050         for (elt = 0; elt < num_elts; elt++)
02051         {
02052             m_out_elts[ elt ] = m_1_elts[ elt ] - m_2_elts[ elt ];
02053         }
02054     }
02055 #endif
02056 
02057     return NULL;
02058 }
02059 
02075 Error* subtract_matrices_cf
02076 (
02077     Matrix_cf**      m_out, 
02078     const Matrix_cf* m_1, 
02079     const Matrix_cf* m_2
02080 )
02081 {
02082     uint32_t num_elts;
02083 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
02084     Matrix_cf* m = NULL;
02085     Complex_f  z = {-1, 0};
02086 #else
02087     uint32_t   elt;
02088     Complex_f* m_1_elts;
02089     Complex_f* m_2_elts;
02090     Complex_f* m_out_elts;
02091 #endif
02092 
02093     if (m_1->num_rows != m_2->num_rows || m_1->num_cols != m_2->num_cols)
02094     {
02095         if (*m_out != m_1 && *m_out != m_2)
02096         {
02097             free_matrix_cf(*m_out); *m_out = NULL;
02098         }
02099         return JWSC_EARG("Subtracting matrices requires equal dimensions");
02100     }
02101 
02102     num_elts = m_1->num_rows*m_1->num_cols;
02103 
02104 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
02105     if (*m_out == m_1)
02106     {
02107         blas_caxpy(num_elts, z, *(m_2->elts), 1, *(m_1->elts), 1);
02108     }
02109     else if (*m_out == m_2)
02110     {
02111         copy_matrix_cf(&m, m_1);
02112         blas_caxpy(num_elts, z, *(m_2->elts), 1, *(m->elts), 1);
02113         copy_matrix_cf(m_out, m);
02114         free_matrix_cf(m);
02115     }
02116     else
02117     {
02118         copy_matrix_cf(m_out, m_1);
02119         blas_caxpy(num_elts, z, *(m_2->elts), 1, *((*m_out)->elts), 1);
02120     }
02121 #else
02122     m_1_elts   = *(m_1->elts);
02123     m_2_elts   = *(m_2->elts);
02124     m_out_elts = *((*m_out)->elts);
02125 
02126     if (*m_out == m_1)
02127     {
02128         for (elt = 0; elt < num_elts; elt++)
02129         {
02130             m_1_elts[ elt ].r = m_1_elts[ elt ].r - m_2_elts[ elt ].r;
02131             m_1_elts[ elt ].i = m_1_elts[ elt ].i - m_2_elts[ elt ].i;
02132         }
02133     }
02134     else if (*m_out == m_2)
02135     {
02136         for (elt = 0; elt < num_elts; elt++)
02137         {
02138             m_2_elts[ elt ].r = m_1_elts[ elt ].r - m_2_elts[ elt ].r;
02139             m_2_elts[ elt ].i = m_1_elts[ elt ].i - m_2_elts[ elt ].i;
02140         }
02141     }
02142     else
02143     {
02144         create_matrix_cf(m_out, m_1->num_rows, m_1->num_cols);
02145         for (elt = 0; elt < num_elts; elt++)
02146         {
02147             m_out_elts[ elt ].r = m_1_elts[ elt ].r - m_2_elts[ elt ].r;
02148             m_out_elts[ elt ].i = m_1_elts[ elt ].i - m_2_elts[ elt ].i;
02149         }
02150     }
02151 #endif
02152 
02153     return NULL;
02154 }
02155 
02171 Error* subtract_matrices_cd
02172 (
02173     Matrix_cd**      m_out, 
02174     const Matrix_cd* m_1, 
02175     const Matrix_cd* m_2
02176 )
02177 {
02178     uint32_t num_elts;
02179 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
02180     Matrix_cd* m = NULL;
02181     Complex_d  z = {-1, 0};
02182 #else
02183     uint32_t   elt;
02184     Complex_d* m_1_elts;
02185     Complex_d* m_2_elts;
02186     Complex_d* m_out_elts;
02187 #endif
02188 
02189     if (m_1->num_rows != m_2->num_rows || m_1->num_cols != m_2->num_cols)
02190     {
02191         if (*m_out != m_1 && *m_out != m_2)
02192         {
02193             free_matrix_cd(*m_out); *m_out = NULL;
02194         }
02195         return JWSC_EARG("Subtracting matrices requires equal dimensions");
02196     }
02197 
02198     num_elts = m_1->num_rows*m_1->num_cols;
02199 
02200 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
02201     if (*m_out == m_1)
02202     {
02203         blas_zaxpy(num_elts, z, *(m_2->elts), 1, *(m_1->elts), 1);
02204     }
02205     else if (*m_out == m_2)
02206     {
02207         copy_matrix_cd(&m, m_1);
02208         blas_zaxpy(num_elts, z, *(m_2->elts), 1, *(m->elts), 1);
02209         copy_matrix_cd(m_out, m);
02210         free_matrix_cd(m);
02211     }
02212     else
02213     {
02214         copy_matrix_cd(m_out, m_1);
02215         blas_zaxpy(num_elts, z, *(m_2->elts), 1, *((*m_out)->elts), 1);
02216     }
02217 #else
02218     m_1_elts   = *(m_1->elts);
02219     m_2_elts   = *(m_2->elts);
02220     m_out_elts = *((*m_out)->elts);
02221 
02222     if (*m_out == m_1)
02223     {
02224         for (elt = 0; elt < num_elts; elt++)
02225         {
02226             m_1_elts[ elt ].r = m_1_elts[ elt ].r - m_2_elts[ elt ].r;
02227             m_1_elts[ elt ].i = m_1_elts[ elt ].i - m_2_elts[ elt ].i;
02228         }
02229     }
02230     else if (*m_out == m_2)
02231     {
02232         for (elt = 0; elt < num_elts; elt++)
02233         {
02234             m_2_elts[ elt ].r = m_1_elts[ elt ].r - m_2_elts[ elt ].r;
02235             m_2_elts[ elt ].i = m_1_elts[ elt ].i - m_2_elts[ elt ].i;
02236         }
02237     }
02238     else
02239     {
02240         create_matrix_cd(m_out, m_1->num_rows, m_1->num_cols);
02241         for (elt = 0; elt < num_elts; elt++)
02242         {
02243             m_out_elts[ elt ].r = m_1_elts[ elt ].r - m_2_elts[ elt ].r;
02244             m_out_elts[ elt ].i = m_1_elts[ elt ].i - m_2_elts[ elt ].i;
02245         }
02246     }
02247 #endif
02248 
02249     return NULL;
02250 }
02251 
02268 void calc_matrix_asum_f(float* sum_out, const Matrix_f* m)
02269 {
02270 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
02271     *sum_out = blas_sasum(m->num_rows*m->num_cols, *(m->elts), 1);
02272 #else
02273     uint32_t num_elts;
02274     uint32_t elt;
02275     float*   m_elts;
02276 
02277     num_elts = m->num_rows*m->num_cols;
02278     m_elts   = *(m->elts);
02279     *sum_out = 0;
02280 
02281     for (elt = 0; elt < num_elts; elt++)
02282     {
02283         (*sum_out) += (float)fabs(m_elts[ elt ]);
02284     }
02285 #endif
02286 }
02287 
02292 void calc_matrix_asum_d(double* sum_out, const Matrix_d* m)
02293 {
02294 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
02295     *sum_out = blas_dasum(m->num_rows*m->num_cols, *(m->elts), 1);
02296 #else
02297     uint32_t num_elts;
02298     uint32_t elt;
02299     double*  m_elts;
02300 
02301     num_elts = m->num_rows*m->num_cols;
02302     m_elts   = *(m->elts);
02303     *sum_out = 0;
02304 
02305     for (elt = 0; elt < num_elts; elt++)
02306     {
02307         (*sum_out) += fabs(m_elts[ elt ]);
02308     }
02309 #endif
02310 }
02311 
02331 void normalize_matrix_sum_f(Matrix_f** m_out, const Matrix_f* m_in)
02332 {
02333     float sum;
02334 
02335     calc_matrix_asum_f(&sum, m_in);
02336 
02337     if (sum > 0)
02338     {
02339         multiply_matrix_by_scalar_f(m_out, m_in, 1.0f / sum);
02340     } 
02341     else 
02342     {
02343         copy_matrix_f(m_out, m_in);
02344     }
02345 }
02346 
02354 void normalize_matrix_sum_d(Matrix_d** m_out, const Matrix_d* m_in)
02355 {
02356     double sum;
02357 
02358     calc_matrix_asum_d(&sum, m_in);
02359 
02360     if (sum > 0)
02361     {
02362         multiply_matrix_by_scalar_d(m_out, m_in, 1.0 / sum);
02363     } 
02364     else 
02365     {
02366         copy_matrix_d(m_out, m_in);
02367     }
02368 }
02369 
02386 void calc_frobenius_norm_f(float* norm_out, const Matrix_f* m)
02387 {
02388     uint32_t row, num_rows;
02389     uint32_t col, num_cols;
02390     float    norm;
02391 
02392     num_rows = m->num_rows;
02393     num_cols = m->num_cols;
02394     norm     = 0;
02395 
02396     for (row = 0; row < num_rows; row++)
02397     {
02398         for (col = 0; col < num_cols; col++)
02399         {
02400             norm += m->elts[ row ][ col ] * m->elts[ row ][ col ];
02401         }
02402     }
02403 
02404     *norm_out = sqrt(norm);
02405 }
02406 
02411 void calc_frobenius_norm_d(double* norm_out, const Matrix_d* m)
02412 {
02413     uint32_t row, num_rows;
02414     uint32_t col, num_cols;
02415     double   norm;
02416 
02417     num_rows = m->num_rows;
02418     num_cols = m->num_cols;
02419     norm     = 0;
02420 
02421     for (row = 0; row < num_rows; row++)
02422     {
02423         for (col = 0; col < num_cols; col++)
02424         {
02425             norm += m->elts[ row ][ col ] * m->elts[ row ][ col ];
02426         }
02427     }
02428 
02429     *norm_out = sqrt(norm);
02430 }
02431 
02450 Error* calc_frobenius_norm_diff_f
02451 (
02452     float*          norm_out, 
02453     const Matrix_f* m_1,
02454     const Matrix_f* m_2
02455 )
02456 {
02457     uint32_t row, num_rows;
02458     uint32_t col, num_cols;
02459     float    norm;
02460     float    d;
02461 
02462     num_rows = m_1->num_rows;
02463     num_cols = m_1->num_cols;
02464 
02465     if (num_rows != m_2->num_rows || num_cols != m_2->num_cols)
02466     {
02467         return JWSC_EARG("Matrix dimensions do not match");
02468     }
02469 
02470     norm = 0;
02471 
02472     for (row = 0; row < num_rows; row++)
02473     {
02474         for (col = 0; col < num_cols; col++)
02475         {
02476             d = m_1->elts[ row ][ col ] - m_2->elts[ row ][ col ];
02477 
02478             norm += d * d;
02479         }
02480     }
02481 
02482     *norm_out = sqrt(norm);
02483 
02484     return NULL;
02485 }
02486 
02492 Error* calc_frobenius_norm_diff_d
02493 (
02494     double*         norm_out, 
02495     const Matrix_d* m_1,
02496     const Matrix_d* m_2
02497 )
02498 {
02499     uint32_t row, num_rows;
02500     uint32_t col, num_cols;
02501     double   norm;
02502     double   d;
02503 
02504     num_rows = m_1->num_rows;
02505     num_cols = m_1->num_cols;
02506 
02507     if (num_rows != m_2->num_rows || num_cols != m_2->num_cols)
02508     {
02509         return JWSC_EARG("Matrix dimensions do not match");
02510     }
02511 
02512     norm = 0;
02513 
02514     for (row = 0; row < num_rows; row++)
02515     {
02516         for (col = 0; col < num_cols; col++)
02517         {
02518             d = m_1->elts[ row ][ col ] - m_2->elts[ row ][ col ];
02519 
02520             norm += d * d;
02521         }
02522     }
02523 
02524     *norm_out = sqrt(norm);
02525 
02526     return NULL;
02527 }
02528 
02547 Error* calc_frobenius_norm_abs_diff_f
02548 (
02549     float*          norm_out, 
02550     const Matrix_f* m_1,
02551     const Matrix_f* m_2
02552 )
02553 {
02554     uint32_t row, num_rows;
02555     uint32_t col, num_cols;
02556     float    norm;
02557     float    d;
02558 
02559     num_rows = m_1->num_rows;
02560     num_cols = m_1->num_cols;
02561 
02562     if (num_rows != m_2->num_rows || num_cols != m_2->num_cols)
02563     {
02564         return JWSC_EARG("Matrix dimensions do not match");
02565     }
02566 
02567     norm = 0;
02568 
02569     for (row = 0; row < num_rows; row++)
02570     {
02571         for (col = 0; col < num_cols; col++)
02572         {
02573             d = fabs(m_1->elts[ row ][ col ]) - fabs(m_2->elts[ row ][ col ]);
02574 
02575             norm += d * d;
02576         }
02577     }
02578 
02579     *norm_out = sqrt(norm);
02580 
02581     return NULL;
02582 }
02583 
02589 Error* calc_frobenius_norm_abs_diff_d
02590 (
02591     double*         norm_out, 
02592     const Matrix_d* m_1,
02593     const Matrix_d* m_2
02594 )
02595 {
02596     uint32_t row, num_rows;
02597     uint32_t col, num_cols;
02598     double   norm;
02599     double   d;
02600 
02601     num_rows = m_1->num_rows;
02602     num_cols = m_1->num_cols;
02603 
02604     if (num_rows != m_2->num_rows || num_cols != m_2->num_cols)
02605     {
02606         return JWSC_EARG("Matrix dimensions do not match");
02607     }
02608 
02609     norm = 0;
02610 
02611     for (row = 0; row < num_rows; row++)
02612     {
02613         for (col = 0; col < num_cols; col++)
02614         {
02615             d = fabs(m_1->elts[ row ][ col ]) - fabs(m_2->elts[ row ][ col ]);
02616 
02617             norm += d * d;
02618         }
02619     }
02620 
02621     *norm_out = sqrt(norm);
02622 
02623     return NULL;
02624 }
02625 
02631 #if defined JWSC_HAVE_LAPACK
02632 
02658 Error* lu_decompose_matrix_f
02659 (
02660     Matrix_f**      m_out, 
02661     Vector_i32**    pivot_out,
02662     const Matrix_f* m_in
02663 )
02664 {
02665     int info;
02666     uint32_t pivot_len;
02667     uint32_t num_rows;
02668     uint32_t num_cols;
02669 
02670     if (*m_out != m_in)
02671     {
02672         copy_matrix_f(m_out, m_in);
02673     }
02674 
02675     num_rows = m_in->num_rows;
02676     num_cols = m_in->num_cols;
02677 
02678     pivot_len = (num_rows < num_cols) ? num_rows : num_cols;
02679     create_vector_i32(pivot_out, pivot_len);
02680 
02681     lapack_sgetrf(num_rows, num_cols, *((*m_out)->elts), num_rows, 
02682             (*pivot_out)->elts, &info);
02683 
02684     assert(info >= 0);
02685     if (info > 0)
02686     {
02687         if (*m_out != m_in)
02688         {
02689             free_matrix_f(*m_out); *m_out = NULL;
02690         }
02691         free_vector_i32(*pivot_out); *pivot_out = NULL;
02692         return JWSC_ECALC("Singular matrix");
02693     }
02694 
02695     return NULL;
02696 }
02697 
02717 Error* lu_decompose_matrix_d
02718 (
02719     Matrix_d**      m_out, 
02720     Vector_i32**    pivot_out,
02721     const Matrix_d* m_in
02722 )
02723 {
02724     int info;
02725     uint32_t pivot_len;
02726     uint32_t num_rows;
02727     uint32_t num_cols;
02728 
02729     if (*m_out != m_in)
02730     {
02731         copy_matrix_d(m_out, m_in);
02732     }
02733 
02734     num_rows = m_in->num_rows;
02735     num_cols = m_in->num_cols;
02736 
02737     pivot_len = (num_rows < num_cols) ? num_rows : num_cols;
02738     create_vector_i32(pivot_out, pivot_len);
02739 
02740     lapack_dgetrf(num_rows, num_cols, *((*m_out)->elts), num_rows, 
02741             (*pivot_out)->elts, &info);
02742 
02743     assert(info >= 0);
02744     if (info > 0)
02745     {
02746         if (*m_out != m_in)
02747         {
02748             free_matrix_d(*m_out); *m_out = NULL;
02749         }
02750         free_vector_i32(*pivot_out); *pivot_out = NULL;
02751         return JWSC_ECALC("Singular matrix");
02752     }
02753 
02754     return NULL;
02755 }
02756 
02758 #endif
02759 
02760 
02761 
02762 
02763 #if defined JWSC_HAVE_LAPACK
02764 
02783 Error* invert_matrix_f(Matrix_f** m_out, const Matrix_f* m_in)
02784 {
02785     Vector_i32* pivot = NULL;
02786     Error* e;
02787 
02788     if ((e = lu_decompose_matrix_f(m_out, &pivot, m_in)) != NULL)
02789     {
02790         return e;
02791     }
02792 
02793     if ((e = invert_lu_matrix_f(m_out, *m_out, pivot)) != NULL)
02794     {
02795         free_vector_i32(pivot);
02796         return e;
02797     }
02798 
02799     free_vector_i32(pivot);
02800 
02801     return NULL;
02802 }
02803 
02816 Error* invert_matrix_d(Matrix_d** m_out, const Matrix_d* m_in)
02817 {
02818     Vector_i32* pivot = NULL;
02819     Error* e;
02820 
02821     if ((e = lu_decompose_matrix_d(m_out, &pivot, m_in)) != NULL)
02822     {
02823         return e;
02824     }
02825 
02826     if ((e = invert_lu_matrix_d(m_out, *m_out, pivot)) != NULL)
02827     {
02828         free_vector_i32(pivot);
02829         return e;
02830     }
02831 
02832     free_vector_i32(pivot);
02833 
02834     return NULL;
02835 }
02836 
02838 #endif
02839 
02840 
02841 
02842 
02843 #if defined JWSC_HAVE_LAPACK
02844 
02869 Error* invert_lu_matrix_f
02870 (
02871     Matrix_f**        m_out, 
02872     const Matrix_f*   m_in, 
02873     const Vector_i32* pivot
02874 )
02875 {
02876     int      info;
02877     uint32_t N;
02878     float*   work;
02879 
02880     if (*m_out != m_in)
02881     {
02882         copy_matrix_f(m_out, m_in);
02883     }
02884 
02885     N = m_in->num_rows;
02886 
02887     if (N != m_in->num_cols)
02888     {
02889         if (*m_out != m_in)
02890         {
02891             free_matrix_f(*m_out); *m_out = NULL;
02892         }
02893         return JWSC_EARG("Matrix not square");
02894     }
02895 
02896     assert(work = malloc(N*sizeof(float)));
02897 
02898     lapack_sgetri(N, *((*m_out)->elts), N, pivot->elts, 
02899             work, N, &info);
02900 
02901     free(work);
02902 
02903     assert(info >= 0);
02904     if (info > 0)
02905     {
02906         if (*m_out != m_in)
02907         {
02908             free_matrix_f(*m_out); *m_out = NULL;
02909         }
02910         return JWSC_ECALC("Singular matrix");
02911     }
02912 
02913     return NULL;
02914 }
02915 
02934 Error* invert_lu_matrix_d
02935 (
02936     Matrix_d**        m_out, 
02937     const Matrix_d*   m_in, 
02938     const Vector_i32* pivot
02939 )
02940 {
02941     int      info;
02942     uint32_t N;
02943     double*  work;
02944 
02945     if (*m_out != m_in)
02946     {
02947         copy_matrix_d(m_out, m_in);
02948     }
02949 
02950     N = m_in->num_rows;
02951 
02952     if (N != m_in->num_cols)
02953     {
02954         if (*m_out != m_in)
02955         {
02956             free_matrix_d(*m_out); *m_out = NULL;
02957         }
02958         return JWSC_EARG("Matrix not square");
02959     }
02960 
02961     assert(work = malloc(N*sizeof(double)));
02962 
02963     lapack_dgetri(N, *((*m_out)->elts), N, pivot->elts, 
02964             work, N, &info);
02965 
02966     free(work);
02967 
02968     assert(info >= 0);
02969     if (info > 0)
02970     {
02971         if (*m_out != m_in)
02972         {
02973             free_matrix_d(*m_out); *m_out = NULL;
02974         }
02975         return JWSC_ECALC("Singular matrix");
02976     }
02977 
02978     return NULL;
02979 }
02980 
02982 #endif
02983 
02984 
02985 
02986 
02987 #if defined JWSC_HAVE_LAPACK
02988 
03005 Error* calc_matrix_determinant_f(float* det_out, const Matrix_f* m)
03006 {
03007     Matrix_f*   lu    = NULL;
03008     Vector_i32* pivot = NULL;
03009     Error*      e;
03010 
03011     if ((e = lu_decompose_matrix_f(&lu, &pivot, m)) != NULL)
03012     {
03013         return e;
03014     }
03015 
03016     if ((e = calc_lu_matrix_determinant_f(det_out, lu, pivot)) != NULL) 
03017     {
03018         free_matrix_f(lu);
03019         free_vector_i32(pivot);
03020         return e;
03021     }
03022 
03023     free_matrix_f(lu);
03024     free_vector_i32(pivot);
03025 
03026     return NULL;
03027 }
03028 
03039 Error* calc_matrix_determinant_d(double* det_out, const Matrix_d* m)
03040 {
03041     Matrix_d*   lu    = NULL;
03042     Vector_i32* pivot = NULL;
03043     Error*      e;
03044 
03045     if ((e = lu_decompose_matrix_d(&lu, &pivot, m)) != NULL)
03046     {
03047         return e;
03048     }
03049 
03050     if ((e = calc_lu_matrix_determinant_d(det_out, lu, pivot)) != NULL) 
03051     {
03052         free_matrix_d(lu);
03053         free_vector_i32(pivot);
03054         return e;
03055     }
03056 
03057     free_matrix_d(lu);
03058     free_vector_i32(pivot);
03059 
03060     return NULL;
03061 }
03062 
03064 #endif
03065 
03066 
03067 
03068 
03085 Error* calc_lu_matrix_determinant_f
03086 (
03087     float*            det_out,
03088     const Matrix_f*   m, 
03089     const Vector_i32* pivot
03090 )
03091 {
03092     uint32_t N;
03093     uint32_t n;
03094 
03095     N = m->num_rows;
03096 
03097     if (N != m->num_cols)
03098     {
03099         return JWSC_EARG("Matrix not square");
03100     }
03101 
03102     *det_out = 1.0f;
03103 
03104     for (n = 0; n < N; n++)
03105     {
03106         *det_out *= m->elts[ n ][ n ];
03107 
03108         if (pivot->elts[ n ] != (n+1))
03109         {
03110             *det_out *= -1.0f;
03111         }
03112     }
03113 
03114     return NULL;
03115 }
03116 
03126 Error* calc_lu_matrix_determinant_d
03127 (
03128     double*           det_out,
03129     const Matrix_d*   m, 
03130     const Vector_i32* pivot
03131 )
03132 {
03133     uint32_t N;
03134     uint32_t n;
03135 
03136     N = m->num_rows;
03137 
03138     if (N != m->num_cols)
03139     {
03140         return JWSC_EARG("Matrix not square");
03141     }
03142 
03143     *det_out = 1.0;
03144 
03145     for (n = 0; n < N; n++)
03146     {
03147         *det_out *= m->elts[ n ][ n ];
03148 
03149         if (pivot->elts[ n ] != (n+1))
03150         {
03151             *det_out *= -1.0;
03152         }
03153     }
03154 
03155     return NULL;
03156 }
03157 
03163 #if defined JWSC_HAVE_LAPACK
03164 
03193 Error* singular_value_decompose_matrix_f
03194 (
03195     Matrix_f**      U_out,
03196     Vector_f**      S_out, 
03197     Matrix_f**      Vt_out,
03198     const Matrix_f* M
03199 )
03200 {
03201     uint32_t num_rows;
03202     uint32_t num_cols;
03203 
03204     float* work;
03205     int    lwork;
03206     int*   iwork;
03207     int    info;
03208     int    max_MN;
03209     int    min_MN;
03210 
03211     Matrix_f* M_copy = NULL;
03212 
03213     copy_matrix_f(&M_copy, M);
03214 
03215     num_rows = M->num_rows;
03216     num_cols = M->num_cols;
03217 
03218     min_MN = num_rows;
03219     max_MN = num_cols;
03220     if (min_MN > max_MN)
03221     {
03222         min_MN = num_cols;
03223         max_MN = num_rows;
03224     }
03225 
03226     create_matrix_f(U_out, num_rows, num_rows);
03227     create_vector_f(S_out, min_MN);
03228     create_matrix_f(Vt_out, num_cols, num_cols);
03229 
03230     if (max_MN >= 4*min_MN*(min_MN+1))
03231         lwork = 3*min_MN*min_MN + max_MN;
03232     else
03233         lwork = 3*min_MN*min_MN + 4*min_MN*(min_MN+1);
03234 
03235     assert(work = malloc(lwork*sizeof(float)));
03236     assert(iwork = malloc(8*min_MN*sizeof(int)));
03237 
03238     lapack_sgesdd('A', num_rows, num_cols, *(M_copy->elts), num_rows, 
03239             (*S_out)->elts, *((*U_out)->elts), num_rows, *((*Vt_out)->elts), 
03240             num_cols, work, lwork, iwork, &info);
03241 
03242     free(work);
03243     free(iwork);
03244 
03245     free_matrix_f(M_copy);
03246 
03247     assert(info >= 0);
03248     if (info > 0)
03249     {
03250         free_matrix_f(*U_out);  *U_out  = NULL;
03251         free_vector_f(*S_out);  *S_out  = NULL;
03252         free_matrix_f(*Vt_out); *Vt_out = NULL;
03253         return JWSC_ECALC("SVD calculation failed");
03254     }
03255 
03256     return NULL;
03257 }
03258 
03281 Error* singular_value_decompose_matrix_d
03282 (
03283     Matrix_d**      U_out,
03284     Vector_d**      S_out, 
03285     Matrix_d**      Vt_out,
03286     const Matrix_d* M
03287 )
03288 {
03289     uint32_t num_rows;
03290     uint32_t num_cols;
03291 
03292     double* work;
03293     int     lwork;
03294     int*    iwork;
03295     int     info;
03296     int     max_MN;
03297     int     min_MN;
03298 
03299     Matrix_d* M_copy = NULL;
03300 
03301     copy_matrix_d(&M_copy, M);
03302 
03303     num_rows = M->num_rows;
03304     num_cols = M->num_cols;
03305 
03306     min_MN = num_rows;
03307     max_MN = num_cols;
03308     if (min_MN > max_MN)
03309     {
03310         min_MN = num_cols;
03311         max_MN = num_rows;
03312     }
03313 
03314     create_matrix_d(U_out, num_rows, num_rows);
03315     create_vector_d(S_out, min_MN);
03316     create_matrix_d(Vt_out, num_cols, num_cols);
03317 
03318     if (max_MN >= 4*min_MN*(min_MN+1))
03319         lwork = 3*min_MN*min_MN + max_MN;
03320     else
03321         lwork = 3*min_MN*min_MN + 4*min_MN*(min_MN+1);
03322 
03323     assert(work = malloc(lwork*sizeof(double)));
03324     assert(iwork = malloc(8*min_MN*sizeof(int)));
03325 
03326     lapack_dgesdd('A', num_rows, num_cols, *(M_copy->elts), num_rows, 
03327             (*S_out)->elts, *((*U_out)->elts), num_rows, *((*Vt_out)->elts), 
03328             num_cols, work, lwork, iwork, &info);
03329 
03330     free(work);
03331     free(iwork);
03332 
03333     free_matrix_d(M_copy);
03334 
03335     assert(info >= 0);
03336     if (info > 0)
03337     {
03338         free_matrix_d(*U_out);  *U_out  = NULL;
03339         free_vector_d(*S_out);  *S_out  = NULL;
03340         free_matrix_d(*Vt_out); *Vt_out = NULL;
03341         return JWSC_ECALC("SVD calculation failed");
03342     }
03343 
03344     return NULL;
03345 }
03346 
03348 #endif
03349 
03350 
03351 
03352 
03353 #if defined JWSC_HAVE_LAPACK
03354 
03388 Error* solve_real_symmetric_matrix_eigenproblem_f
03389 (
03390     Matrix_f**      V_out,
03391     Vector_f**      D_out, 
03392     const Matrix_f* M
03393 )
03394 {
03395     uint32_t num_rows;
03396     uint32_t num_cols;
03397 
03398     float*  work;
03399     int     lwork;
03400     int     info;
03401 
03402     num_rows = M->num_rows;
03403     num_cols = M->num_cols;
03404 
03405     if (num_rows != num_cols)
03406     {
03407         return JWSC_EARG("Matrix not symmetric");
03408     }
03409 
03410     copy_matrix_f(V_out, M);
03411     create_vector_f(D_out, num_rows);
03412 
03413     lwork = 3*num_rows;
03414 
03415     assert(work = malloc(lwork*sizeof(float)));
03416 
03417     lapack_ssyev('V', 'U', num_rows, *((*V_out)->elts), num_rows, 
03418             (*D_out)->elts, work, lwork, &info);
03419 
03420     free(work);
03421 
03422     assert(info >= 0);
03423     if (info > 0)
03424     {
03425         free_matrix_f(*V_out);  *V_out  = NULL;
03426         free_vector_f(*D_out);  *D_out  = NULL;
03427         return JWSC_ECALC("Eigenproblem solver failed");
03428     }
03429 
03430     return NULL;
03431 }
03432 
03460 Error* solve_real_symmetric_matrix_eigenproblem_d
03461 (
03462     Matrix_d**      V_out,
03463     Vector_d**      D_out, 
03464     const Matrix_d* M
03465 )
03466 {
03467     uint32_t num_rows;
03468     uint32_t num_cols;
03469 
03470     double* work;
03471     int     lwork;
03472     int     info;
03473 
03474     num_rows = M->num_rows;
03475     num_cols = M->num_cols;
03476 
03477     if (num_rows != num_cols)
03478     {
03479         return JWSC_EARG("Matrix not symmetric");
03480     }
03481 
03482     copy_matrix_d(V_out, M);
03483     create_vector_d(D_out, num_rows);
03484 
03485     lwork = 3*num_rows;
03486 
03487     assert(work = malloc(lwork*sizeof(double)));
03488 
03489     lapack_dsyev('V', 'U', num_rows, *((*V_out)->elts), num_rows, 
03490             (*D_out)->elts, work, lwork, &info);
03491 
03492     free(work);
03493 
03494     assert(info >= 0);
03495     if (info > 0)
03496     {
03497         free_matrix_d(*V_out);  *V_out  = NULL;
03498         free_vector_d(*D_out);  *D_out  = NULL;
03499         return JWSC_ECALC("Eigenproblem solver failed");
03500     }
03501 
03502     return NULL;
03503 }
03504 
03506 #endif
03507 
03508 
03509 
03510 
03511 #if defined JWSC_HAVE_LAPACK
03512 
03537 Error* pseudoinvert_matrix_no_svd_f
03538 (
03539     Matrix_f**      M_out,
03540     const Matrix_f* M_in
03541 )
03542 {
03543     Matrix_f* Mt = NULL;
03544     Error*    err;
03545 
03546     transpose_matrix_f(&Mt, M_in);
03547 
03548     assert(multiply_matrices_f(M_out, Mt, M_in) == NULL);
03549 
03550     if ((err = invert_matrix_f(M_out, *M_out)) != NULL)
03551     {
03552         if (*M_out != M_in)
03553         {
03554             free_matrix_f(*M_out); *M_out = NULL;
03555         }
03556         free_error(err);
03557         return JWSC_ECALC("Pseudoinverse calculation failed");
03558     }
03559 
03560     assert(multiply_matrices_f(M_out, *M_out, Mt) == NULL);
03561 
03562     free_matrix_f(Mt);
03563 
03564     return NULL;
03565 }
03566 
03585 Error* pseudoinvert_matrix_no_svd_d
03586 (
03587     Matrix_d**      M_out,
03588     const Matrix_d* M_in
03589 )
03590 {
03591     Matrix_d* Mt = NULL;
03592     Error*    err;
03593 
03594     transpose_matrix_d(&Mt, M_in);
03595 
03596     assert(multiply_matrices_d(M_out, Mt, M_in) == NULL);
03597 
03598     if ((err = invert_matrix_d(M_out, *M_out)) != NULL)
03599     {
03600         if (*M_out != M_in)
03601         {
03602             free_matrix_d(*M_out); *M_out = NULL;
03603         }
03604         free_error(err);
03605         return JWSC_ECALC("Pseudoinverse calculation failed");
03606     }
03607 
03608     assert(multiply_matrices_d(M_out, *M_out, Mt) == NULL);
03609 
03610     free_matrix_d(Mt);
03611 
03612     return NULL;
03613 }
03614 
03616 #endif
03617 
03618 
03619 
03620 
03621 #if defined JWSC_HAVE_LAPACK
03622 
03650 Error* pseudoinvert_matrix_f
03651 (
03652     Matrix_f**      M_out,
03653     const Matrix_f* M_in
03654 )
03655 {
03656     uint32_t i ;
03657     Error*   err;
03658 
03659     Matrix_f* U = NULL;
03660     Vector_f* S = NULL;
03661     Matrix_f* T = NULL;
03662     Matrix_f* V = NULL;
03663 
03664     if ((err = singular_value_decompose_matrix_f(&U, &S, &V, M_in)) != NULL)
03665     {
03666         if (*M_out != M_in)
03667         {
03668             free_matrix_f(*M_out); *M_out = NULL;
03669         }
03670         free_error(err);
03671         return JWSC_ECALC("Pseudoinverse calculation with SVD failed");
03672     }
03673 
03674     transpose_matrix_f(&U, U);
03675     transpose_matrix_f(&V, V);
03676     create_zero_matrix_f(&T, M_in->num_cols, M_in->num_rows);
03677 
03678     for (i = 0; i < S->num_elts; i++)
03679     {
03680         if (S->elts[ i ] > 1.0e-16f)
03681         {
03682             T->elts[ i ][ i ] = 1.0f / S->elts[ i ];
03683         }
03684     }
03685 
03686     assert(multiply_matrices_f(M_out, T, U) == NULL);
03687     assert(multiply_matrices_f(M_out, V, *M_out) == NULL);
03688 
03689     free_matrix_f(U);
03690     free_vector_f(S);
03691     free_matrix_f(T);
03692     free_matrix_f(V);
03693 
03694     return NULL;
03695 }
03696 
03718 Error* pseudoinvert_matrix_d
03719 (
03720     Matrix_d**      M_out,
03721     const Matrix_d* M_in
03722 )
03723 {
03724     uint32_t i ;
03725     Error*   err;
03726 
03727     Matrix_d* U = NULL;
03728     Vector_d* S = NULL;
03729     Matrix_d* T = NULL;
03730     Matrix_d* V = NULL;
03731 
03732     if ((err = singular_value_decompose_matrix_d(&U, &S, &V, M_in)) != NULL)
03733     {
03734         if (*M_out != M_in)
03735         {
03736             free_matrix_d(*M_out); *M_out = NULL;
03737         }
03738         free_error(err);
03739         return JWSC_ECALC("Pseudoinverse calculation with SVD failed");
03740     }
03741 
03742     transpose_matrix_d(&U, U);
03743     transpose_matrix_d(&V, V);
03744     create_zero_matrix_d(&T, M_in->num_cols, M_in->num_rows);
03745 
03746     for (i = 0; i < S->num_elts; i++)
03747     {
03748         if (S->elts[ i ] > 1.0e-24)
03749         {
03750             T->elts[ i ][ i ] = 1.0 / S->elts[ i ];
03751         }
03752     }
03753 
03754     assert(multiply_matrices_d(M_out, T, U) == NULL);
03755     assert(multiply_matrices_d(M_out, V, *M_out) == NULL);
03756 
03757     free_matrix_d(U);
03758     free_vector_d(S);
03759     free_matrix_d(T);
03760     free_matrix_d(V);
03761 
03762     return NULL;
03763 }
03764 
03766 #endif
03767 
03768 
03769 
03770 
03787 void create_euler_rotation_matrix_f
03788 (
03789     Matrix_f** m_out,
03790     float      phi,
03791     float      theta,
03792     float      psi
03793 )
03794 {
03795     float cos_phi, sin_phi;
03796     float cos_theta, sin_theta;
03797     float cos_psi, sin_psi;
03798 
03799     cos_phi   = (float)cos(phi);
03800     sin_phi   = (float)sin(phi);
03801     cos_theta = (float)cos(theta);
03802     sin_theta = (float)sin(theta);
03803     cos_psi   = (float)cos(psi);
03804     sin_psi   = (float)sin(psi);
03805 
03806     create_matrix_f(m_out, 3, 3);
03807     (*m_out)->elts[0][0] = cos_psi*cos_phi - cos_theta*sin_phi*sin_psi;
03808     (*m_out)->elts[0][1] = cos_psi*sin_phi + cos_theta*cos_phi*sin_psi;
03809     (*m_out)->elts[0][2] = sin_psi*sin_theta;
03810     (*m_out)->elts[1][0] = -sin_psi*cos_phi - cos_theta*sin_phi*cos_psi;
03811     (*m_out)->elts[1][1] = -sin_psi*sin_phi + cos_theta*cos_phi*cos_psi;
03812     (*m_out)->elts[1][2] = cos_psi*sin_theta;
03813     (*m_out)->elts[2][0] = sin_theta*sin_phi;
03814     (*m_out)->elts[2][1] = -sin_theta*cos_phi;
03815     (*m_out)->elts[2][2] = cos_theta;
03816 }
03817 
03818 
03826 void create_euler_rotation_matrix_d
03827 (
03828     Matrix_d** m_out,
03829     float      phi,
03830     float      theta,
03831     float      psi
03832 )
03833 {
03834     double cos_phi, sin_phi;
03835     double cos_theta, sin_theta;
03836     double cos_psi, sin_psi;
03837 
03838     cos_phi   = cos(phi);
03839     sin_phi   = sin(phi);
03840     cos_theta = cos(theta);
03841     sin_theta = sin(theta);
03842     cos_psi   = cos(psi);
03843     sin_psi   = sin(psi);
03844 
03845     create_matrix_d(m_out, 3, 3);
03846     (*m_out)->elts[0][0] = cos_psi*cos_phi - cos_theta*sin_phi*sin_psi;
03847     (*m_out)->elts[0][1] = cos_psi*sin_phi + cos_theta*cos_phi*sin_psi;
03848     (*m_out)->elts[0][2] = sin_psi*sin_theta;
03849     (*m_out)->elts[1][0] = -sin_psi*cos_phi - cos_theta*sin_phi*cos_psi;
03850     (*m_out)->elts[1][1] = -sin_psi*sin_phi + cos_theta*cos_phi*cos_psi;
03851     (*m_out)->elts[1][2] = cos_psi*sin_theta;
03852     (*m_out)->elts[2][0] = sin_theta*sin_phi;
03853     (*m_out)->elts[2][1] = -sin_theta*cos_phi;
03854     (*m_out)->elts[2][2] = cos_theta;
03855 }
03856 
03884 Error* create_3d_rotation_matrix_1_f
03885 (
03886     Matrix_f**      m_out, 
03887     float           phi,
03888     const Vector_f* v
03889 )
03890 {
03891     if (v->num_elts != 3)
03892     {
03893         free_matrix_f(*m_out); *m_out = NULL;
03894         return JWSC_EARG("Vector for 3D rotation must have three dimensions");
03895     }
03896 
03897     return create_3d_rotation_matrix_2_f(m_out, phi, 
03898             v->elts[0], v->elts[1], v->elts[2]);
03899 }
03900 
03901 
03917 Error* create_3d_rotation_matrix_1_d
03918 (
03919     Matrix_d**      m_out, 
03920     double          phi,
03921     const Vector_d* v
03922 )
03923 {
03924     if (v->num_elts != 3)
03925     {
03926         free_matrix_d(*m_out); *m_out = NULL;
03927         return JWSC_EARG("Vector for 3D rotation must have three dimensions");
03928     }
03929 
03930     return create_3d_rotation_matrix_2_d(m_out, phi, 
03931             v->elts[0], v->elts[1], v->elts[2]);
03932 }
03933 
03934 
03951 Error* create_3d_rotation_matrix_2_f
03952 (
03953     Matrix_f** m_out, 
03954     float      phi,
03955     float      x,
03956     float      y,
03957     float      z
03958 )
03959 {
03960     float cos_phi, cos_theta, cos_psi;
03961     float sin_phi, sin_theta, sin_psi;
03962     float mag_xyz, mag_xy;
03963 
03964     Matrix_f* R_phi   = NULL;
03965     Matrix_f* R_theta = NULL;
03966     Matrix_f* R_psi   = NULL;
03967 
03968     mag_xyz = sqrt(x*x + y*y + z*z);
03969 
03970     if (mag_xyz < 1.0e-8f)
03971     {
03972         free_matrix_f(*m_out); *m_out = NULL;
03973         return JWSC_EARG("Magnitude of rotation vector too small");
03974     }
03975 
03976     /* psi used to rotate around z-axis to put vector on the yz-plane. */
03977     mag_xy = sqrt(x*x + y*y);
03978     if (mag_xy > 1.0e-8f)
03979     {
03980         cos_psi = y / mag_xy;
03981         sin_psi = x / mag_xy;
03982     }
03983     else
03984     {
03985         cos_psi = 0.0f;
03986         sin_psi = 1.0f;
03987     }
03988 
03989     /* theta used to rotate around x-axis to put vector onto the z-axis. */
03990     cos_theta = z / mag_xyz;
03991     sin_theta = mag_xy / mag_xyz;
03992 
03993     /* phi used to rotate around z-axis. This is actually the angle to rotate
03994      * around the vector. */
03995     cos_phi = (float)cos((double)phi);
03996     sin_phi = (float)sin((double)phi);
03997 
03998     create_identity_matrix_f(&R_phi, 3);
03999     R_phi->elts[ 0 ][ 0 ] = cos_phi;
04000     R_phi->elts[ 0 ][ 1 ] = sin_phi;
04001     R_phi->elts[ 1 ][ 0 ] = -sin_phi;
04002     R_phi->elts[ 1 ][ 1 ] = cos_phi;
04003 
04004     create_identity_matrix_f(&R_theta, 3);
04005     R_theta->elts[ 1 ][ 1 ] = cos_theta;
04006     R_theta->elts[ 1 ][ 2 ] = sin_theta;
04007     R_theta->elts[ 2 ][ 1 ] = -sin_theta;
04008     R_theta->elts[ 2 ][ 2 ] = cos_theta;
04009 
04010     create_identity_matrix_f(&R_psi, 3);
04011     R_psi->elts[ 0 ][ 0 ] = cos_psi;
04012     R_psi->elts[ 0 ][ 1 ] = sin_psi;
04013     R_psi->elts[ 1 ][ 0 ] = -sin_psi;
04014     R_psi->elts[ 1 ][ 1 ] = cos_psi;
04015 
04016     /* *m_out = R_psi * R_theta * R_phi * R_theta^T * R_psi^T */
04017     multiply_matrices_f(m_out, R_psi, R_theta);
04018     multiply_matrices_f(m_out, *m_out, R_phi);
04019     transpose_matrix_f(&R_theta, R_theta);
04020     transpose_matrix_f(&R_psi, R_psi);
04021     multiply_matrices_f(m_out, *m_out, R_theta);
04022     multiply_matrices_f(m_out, *m_out, R_psi);
04023 
04024     free_matrix_f(R_phi);
04025     free_matrix_f(R_theta);
04026     free_matrix_f(R_psi);
04027 
04028     return NULL;
04029 }
04030 
04031 
04048 Error* create_3d_rotation_matrix_2_d
04049 (
04050     Matrix_d** m_out, 
04051     double     phi,
04052     double     x,
04053     double     y,
04054     double     z
04055 )
04056 {
04057     double cos_phi, cos_theta, cos_psi;
04058     double sin_phi, sin_theta, sin_psi;
04059     double mag_xyz, mag_xy;
04060 
04061     Matrix_d* R_phi   = NULL;
04062     Matrix_d* R_theta = NULL;
04063     Matrix_d* R_psi   = NULL;
04064 
04065     mag_xyz = sqrt(x*x + y*y + z*z);
04066 
04067     if (mag_xyz < 1.0e-8)
04068     {
04069         free_matrix_d(*m_out); *m_out = NULL;
04070         return JWSC_EARG("Magnitude of rotation vector too small");
04071     }
04072 
04073     /* psi used to rotate around z-axis to put vector on the yz-plane. */
04074     mag_xy = sqrt(x*x + y*y);
04075     if (mag_xy > 1.0e-8)
04076     {
04077         cos_psi = y / mag_xy;
04078         sin_psi = x / mag_xy;
04079     }
04080     else
04081     {
04082         cos_psi = 0.0;
04083         sin_psi = 1.0;
04084     }
04085 
04086     /* theta used to rotate around x-axis to put vector onto the z-axis. */
04087     cos_theta = z / mag_xyz;
04088     sin_theta = mag_xy / mag_xyz;
04089 
04090     /* phi used to rotate around z-axis. This is actually the angle to rotate
04091      * around the vector. */
04092     cos_phi = cos(phi);
04093     sin_phi = sin(phi);
04094 
04095     create_identity_matrix_d(&R_phi, 3);
04096     R_phi->elts[ 0 ][ 0 ] = cos_phi;
04097     R_phi->elts[ 0 ][ 1 ] = sin_phi;
04098     R_phi->elts[ 1 ][ 0 ] = -sin_phi;
04099     R_phi->elts[ 1 ][ 1 ] = cos_phi;
04100 
04101     create_identity_matrix_d(&R_theta, 3);
04102     R_theta->elts[ 1 ][ 1 ] = cos_theta;
04103     R_theta->elts[ 1 ][ 2 ] = sin_theta;
04104     R_theta->elts[ 2 ][ 1 ] = -sin_theta;
04105     R_theta->elts[ 2 ][ 2 ] = cos_theta;
04106 
04107     create_identity_matrix_d(&R_psi, 3);
04108     R_psi->elts[ 0 ][ 0 ] = cos_psi;
04109     R_psi->elts[ 0 ][ 1 ] = sin_psi;
04110     R_psi->elts[ 1 ][ 0 ] = -sin_psi;
04111     R_psi->elts[ 1 ][ 1 ] = cos_psi;
04112 
04113     /* *m_out = R_psi * R_theta * R_phi * R_theta^T * R_psi^T */
04114     multiply_matrices_d(m_out, R_psi, R_theta);
04115     multiply_matrices_d(m_out, *m_out, R_phi);
04116     transpose_matrix_d(&R_theta, R_theta);
04117     transpose_matrix_d(&R_psi, R_psi);
04118     multiply_matrices_d(m_out, *m_out, R_theta);
04119     multiply_matrices_d(m_out, *m_out, R_psi);
04120 
04121     free_matrix_d(R_phi);
04122     free_matrix_d(R_theta);
04123     free_matrix_d(R_psi);
04124 
04125     return NULL;
04126 }
04127 
04156 Error* create_3d_homo_rotation_matrix_1_f
04157 (
04158     Matrix_f**      m_out, 
04159     float           phi,
04160     const Vector_f* v
04161 )
04162 {
04163     if (v->num_elts < 3)
04164     {
04165         free_matrix_f(*m_out); *m_out = NULL;
04166         return JWSC_EARG("Vector for 3D homogeneous rotation is not 3D");
04167     }
04168 
04169     return create_3d_homo_rotation_matrix_2_f(m_out, phi, 
04170             v->elts[0], v->elts[1], v->elts[2]);
04171 }
04172 
04173 
04190 Error* create_3d_homo_rotation_matrix_1_d
04191 (
04192     Matrix_d**      m_out, 
04193     double          phi,
04194     const Vector_d* v
04195 )
04196 {
04197     if (v->num_elts < 3)
04198     {
04199         free_matrix_d(*m_out); *m_out = NULL;
04200         return JWSC_EARG("Vector for 3D homogeneous rotation is not 3D");
04201     }
04202 
04203     return create_3d_homo_rotation_matrix_2_d(m_out, phi, 
04204             v->elts[0], v->elts[1], v->elts[2]);
04205 }
04206 
04207 
04224 Error* create_3d_homo_rotation_matrix_2_f
04225 (
04226     Matrix_f** m_out, 
04227     float      phi,
04228     float      x,
04229     float      y,
04230     float      z
04231 )
04232 {
04233     float cos_phi, cos_theta, cos_psi;
04234     float sin_phi, sin_theta, sin_psi;
04235     float mag_xyz, mag_xy;
04236 
04237     Matrix_f* R_phi   = NULL;
04238     Matrix_f* R_theta = NULL;
04239     Matrix_f* R_psi   = NULL;
04240 
04241     mag_xyz = sqrt(x*x + y*y + z*z);
04242 
04243     if (mag_xyz < 1.0e-8f)
04244     {
04245         free_matrix_f(*m_out); *m_out = NULL;
04246         return JWSC_EARG("Magnitude of rotation vector too small");
04247     }
04248 
04249     /* psi used to rotate around z-axis to put vector on the yz-plane. */
04250     mag_xy = sqrt(x*x + y*y);
04251     if (mag_xy > 1.0e-8f)
04252     {
04253         cos_psi = y / mag_xy;
04254         sin_psi = x / mag_xy;
04255     }
04256     else
04257     {
04258         cos_psi = 0.0f;
04259         sin_psi = 1.0f;
04260     }
04261 
04262     /* theta used to rotate around x-axis to put vector onto the z-axis. */
04263     cos_theta = z / mag_xyz;
04264     sin_theta = mag_xy / mag_xyz;
04265 
04266     /* phi used to rotate around z-axis. This is actually the angle to rotate
04267      * around the vector. */
04268     cos_phi = (float)cos((double)phi);
04269     sin_phi = (float)sin((double)phi);
04270 
04271     create_identity_matrix_f(&R_phi, 4);
04272     R_phi->elts[ 0 ][ 0 ] = cos_phi;
04273     R_phi->elts[ 0 ][ 1 ] = sin_phi;
04274     R_phi->elts[ 1 ][ 0 ] = -sin_phi;
04275     R_phi->elts[ 1 ][ 1 ] = cos_phi;
04276 
04277     create_identity_matrix_f(&R_theta, 4);
04278     R_theta->elts[ 1 ][ 1 ] = cos_theta;
04279     R_theta->elts[ 1 ][ 2 ] = sin_theta;
04280     R_theta->elts[ 2 ][ 1 ] = -sin_theta;
04281     R_theta->elts[ 2 ][ 2 ] = cos_theta;
04282 
04283     create_identity_matrix_f(&R_psi, 4);
04284     R_psi->elts[ 0 ][ 0 ] = cos_psi;
04285     R_psi->elts[ 0 ][ 1 ] = sin_psi;
04286     R_psi->elts[ 1 ][ 0 ] = -sin_psi;
04287     R_psi->elts[ 1 ][ 1 ] = cos_psi;
04288 
04289     /* *m_out = R_psi * R_theta * R_phi * R_theta^T * R_psi^T */
04290     multiply_matrices_f(m_out, R_psi, R_theta);
04291     multiply_matrices_f(m_out, *m_out, R_phi);
04292     transpose_matrix_f(&R_theta, R_theta);
04293     transpose_matrix_f(&R_psi, R_psi);
04294     multiply_matrices_f(m_out, *m_out, R_theta);
04295     multiply_matrices_f(m_out, *m_out, R_psi);
04296 
04297     free_matrix_f(R_phi);
04298     free_matrix_f(R_theta);
04299     free_matrix_f(R_psi);
04300 
04301     return NULL;
04302 }
04303 
04304 
04321 Error* create_3d_homo_rotation_matrix_2_d
04322 (
04323     Matrix_d** m_out, 
04324     double     phi,
04325     double     x,
04326     double     y,
04327     double     z
04328 )
04329 {
04330     double cos_phi, cos_theta, cos_psi;
04331     double sin_phi, sin_theta, sin_psi;
04332     double mag_xyz, mag_xy;
04333 
04334     Matrix_d* R_phi   = NULL;
04335     Matrix_d* R_theta = NULL;
04336     Matrix_d* R_psi   = NULL;
04337 
04338     mag_xyz = sqrt(x*x + y*y + z*z);
04339 
04340     if (mag_xyz < 1.0e-8)
04341     {
04342         free_matrix_d(*m_out); *m_out = NULL;
04343         return JWSC_EARG("Magnitude of rotation vector too small");
04344     }
04345 
04346     /* psi used to rotate around z-axis to put vector on the yz-plane. */
04347     mag_xy = sqrt(x*x + y*y);
04348     if (mag_xy > 1.0e-8)
04349     {
04350         cos_psi = y / mag_xy;
04351         sin_psi = x / mag_xy;
04352     }
04353     else
04354     {
04355         cos_psi = 0.0;
04356         sin_psi = 1.0;
04357     }
04358 
04359     /* theta used to rotate around x-axis to put vector onto the z-axis. */
04360     cos_theta = z / mag_xyz;
04361     sin_theta = mag_xy / mag_xyz;
04362 
04363     /* phi used to rotate around z-axis. This is actually the angle to rotate
04364      * around the vector. */
04365     cos_phi = cos(phi);
04366     sin_phi = sin(phi);
04367 
04368     create_identity_matrix_d(&R_phi, 4);
04369     R_phi->elts[ 0 ][ 0 ] = cos_phi;
04370     R_phi->elts[ 0 ][ 1 ] = sin_phi;
04371     R_phi->elts[ 1 ][ 0 ] = -sin_phi;
04372     R_phi->elts[ 1 ][ 1 ] = cos_phi;
04373 
04374     create_identity_matrix_d(&R_theta, 4);
04375     R_theta->elts[ 1 ][ 1 ] = cos_theta;
04376     R_theta->elts[ 1 ][ 2 ] = sin_theta;
04377     R_theta->elts[ 2 ][ 1 ] = -sin_theta;
04378     R_theta->elts[ 2 ][ 2 ] = cos_theta;
04379 
04380     create_identity_matrix_d(&R_psi, 4);
04381     R_psi->elts[ 0 ][ 0 ] = cos_psi;
04382     R_psi->elts[ 0 ][ 1 ] = sin_psi;
04383     R_psi->elts[ 1 ][ 0 ] = -sin_psi;
04384     R_psi->elts[ 1 ][ 1 ] = cos_psi;
04385 
04386     /* *m_out = R_psi * R_theta * R_phi * R_theta^T * R_psi^T */
04387     multiply_matrices_d(m_out, R_psi, R_theta);
04388     multiply_matrices_d(m_out, *m_out, R_phi);
04389     transpose_matrix_d(&R_theta, R_theta);
04390     transpose_matrix_d(&R_psi, R_psi);
04391     multiply_matrices_d(m_out, *m_out, R_theta);
04392     multiply_matrices_d(m_out, *m_out, R_psi);
04393 
04394     free_matrix_d(R_phi);
04395     free_matrix_d(R_theta);
04396     free_matrix_d(R_psi);
04397 
04398     return NULL;
04399 }
04400 
04426 Error* create_3d_scaling_matrix_1_f
04427 (
04428     Matrix_f**      m_out, 
04429     const Vector_f* v
04430 )
04431 {
04432     if (v->num_elts != 3)
04433     {
04434         free_matrix_f(*m_out); *m_out = NULL;
04435         return JWSC_EARG("Vector for 3D scaling is not 3D");
04436     }
04437 
04438     return create_3d_scaling_matrix_2_f(m_out,
04439             v->elts[0], v->elts[1], v->elts[2]);
04440 }
04441 
04442 
04456 Error* create_3d_scaling_matrix_1_d
04457 (
04458     Matrix_d**      m_out, 
04459     const Vector_d* v
04460 )
04461 {
04462     if (v->num_elts != 3)
04463     {
04464         free_matrix_d(*m_out); *m_out = NULL;
04465         return JWSC_EARG("Vector for 3D scaling is not 3D");
04466     }
04467 
04468     return create_3d_scaling_matrix_2_d(m_out,
04469             v->elts[0], v->elts[1], v->elts[2]);
04470 }
04471 
04472 
04485 Error* create_3d_scaling_matrix_2_f
04486 (
04487     Matrix_f** m_out, 
04488     float      x,
04489     float      y,
04490     float      z
04491 )
04492 {
04493     create_zero_matrix_f(m_out, 3, 3);
04494     (*m_out)->elts[ 0 ][ 0 ] = x;
04495     (*m_out)->elts[ 1 ][ 1 ] = y;
04496     (*m_out)->elts[ 2 ][ 2 ] = z;
04497 
04498     return NULL;
04499 }
04500 
04501 
04514 Error* create_3d_scaling_matrix_2_d
04515 (
04516     Matrix_d** m_out, 
04517     double     x,
04518     double     y,
04519     double     z
04520 )
04521 {
04522     create_zero_matrix_d(m_out, 3, 3);
04523     (*m_out)->elts[ 0 ][ 0 ] = x;
04524     (*m_out)->elts[ 1 ][ 1 ] = y;
04525     (*m_out)->elts[ 2 ][ 2 ] = z;
04526 
04527     return NULL;
04528 }
04529 
04556 Error* create_3d_homo_scaling_matrix_1_f
04557 (
04558     Matrix_f**      m_out, 
04559     const Vector_f* v
04560 )
04561 {
04562     if (v->num_elts < 3)
04563     {
04564         free_matrix_f(*m_out); *m_out = NULL;
04565         return JWSC_EARG("Vector for 3D homogeneous scaling is not 3D");
04566     }
04567 
04568     return create_3d_homo_scaling_matrix_2_f(m_out,
04569             v->elts[0], v->elts[1], v->elts[2]);
04570 }
04571 
04572 
04587 Error* create_3d_homo_scaling_matrix_1_d
04588 (
04589     Matrix_d**      m_out, 
04590     const Vector_d* v
04591 )
04592 {
04593     if (v->num_elts < 3)
04594     {
04595         free_matrix_d(*m_out); *m_out = NULL;
04596         return JWSC_EARG("Vector for 3D homogeneous scaling is not 3D");
04597     }
04598 
04599     return create_3d_homo_scaling_matrix_2_d(m_out,
04600             v->elts[0], v->elts[1], v->elts[2]);
04601 }
04602 
04603 
04616 Error* create_3d_homo_scaling_matrix_2_f
04617 (
04618     Matrix_f** m_out, 
04619     float      x,
04620     float      y,
04621     float      z
04622 )
04623 {
04624     create_identity_matrix_f(m_out, 4);
04625     (*m_out)->elts[ 0 ][ 0 ] = x;
04626     (*m_out)->elts[ 1 ][ 1 ] = y;
04627     (*m_out)->elts[ 2 ][ 2 ] = z;
04628 
04629     return NULL;
04630 }
04631 
04632 
04645 Error* create_3d_homo_scaling_matrix_2_d
04646 (
04647     Matrix_d** m_out, 
04648     double     x,
04649     double     y,
04650     double     z
04651 )
04652 {
04653     create_identity_matrix_d(m_out, 4);
04654     (*m_out)->elts[ 0 ][ 0 ] = x;
04655     (*m_out)->elts[ 1 ][ 1 ] = y;
04656     (*m_out)->elts[ 2 ][ 2 ] = z;
04657 
04658     return NULL;
04659 }
04660 
04687 Error* create_3d_homo_translation_matrix_1_f
04688 (
04689     Matrix_f**      m_out, 
04690     const Vector_f* v
04691 )
04692 {
04693     if (v->num_elts < 3)
04694     {
04695         free_matrix_f(*m_out); *m_out = NULL;
04696         return JWSC_EARG("Vector for 3D homogeneous translation is not 3D");
04697     }
04698 
04699     return create_3d_homo_translation_matrix_2_f(m_out,
04700             v->elts[0], v->elts[1], v->elts[2]);
04701 }
04702 
04703 
04718 Error* create_3d_homo_translation_matrix_1_d
04719 (
04720     Matrix_d**      m_out, 
04721     const Vector_d* v
04722 )
04723 {
04724     if (v->num_elts < 3)
04725     {
04726         free_matrix_d(*m_out); *m_out = NULL;
04727         return JWSC_EARG("Vector for 3D homogeneous translation is not 3D");
04728     }
04729 
04730     return create_3d_homo_translation_matrix_2_d(m_out,
04731             v->elts[0], v->elts[1], v->elts[2]);
04732 }
04733 
04734 
04747 Error* create_3d_homo_translation_matrix_2_f
04748 (
04749     Matrix_f** m_out, 
04750     float      x,
04751     float      y,
04752     float      z
04753 )
04754 {
04755     create_identity_matrix_f(m_out, 4);
04756     (*m_out)->elts[ 0 ][ 3 ] = x;
04757     (*m_out)->elts[ 1 ][ 3 ] = y;
04758     (*m_out)->elts[ 2 ][ 3 ] = z;
04759 
04760     return NULL;
04761 }
04762 
04763 
04776 Error* create_3d_homo_translation_matrix_2_d
04777 (
04778     Matrix_d** m_out, 
04779     double     x,
04780     double     y,
04781     double     z
04782 )
04783 {
04784     create_identity_matrix_d(m_out, 4);
04785     (*m_out)->elts[ 0 ][ 3 ] = x;
04786     (*m_out)->elts[ 1 ][ 3 ] = y;
04787     (*m_out)->elts[ 2 ][ 3 ] = z;
04788 
04789     return NULL;
04790 }
04791