JWS C Library
C language utility library
vector_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 <math.h>
00053 #include <assert.h>
00054 #include <inttypes.h>
00055 
00056 #include "jwsc/base/error.h"
00057 #include "jwsc/math/complex.h"
00058 #include "jwsc/math/blas.h"
00059 #include "jwsc/vector/vector.h"
00060 #include "jwsc/vector/vector_math.h"
00061 
00062 
00078 void add_scalar_to_vector_f(Vector_f** v_out, const Vector_f* v_in, float a)
00079 {
00080     uint32_t   num_elts;
00081     uint32_t   elt;
00082     Vector_f*  v;
00083 
00084     num_elts = v_in->num_elts;
00085 
00086     if (*v_out != v_in)
00087     {
00088         create_vector_f(v_out, num_elts);
00089     }
00090     v = *v_out;
00091 
00092     for (elt = 0; elt < num_elts; elt++)
00093     {
00094         v->elts[ elt ] = a + v_in->elts[ elt ];
00095     }
00096 }
00097 
00106 void add_scalar_to_vector_d(Vector_d** v_out, const Vector_d* v_in, double a)
00107 {
00108     uint32_t   num_elts;
00109     uint32_t   elt;
00110     Vector_d*  v;
00111 
00112     num_elts = v_in->num_elts;
00113 
00114     if (*v_out != v_in)
00115     {
00116         create_vector_d(v_out, num_elts);
00117     }
00118     v = *v_out;
00119 
00120     for (elt = 0; elt < num_elts; elt++)
00121     {
00122         v->elts[ elt ] = a + v_in->elts[ elt ];
00123     }
00124 }
00125 
00134 void add_scalar_to_vector_cf
00135 (
00136     Vector_cf**      v_out, 
00137     const Vector_cf* v_in, 
00138     Complex_f        z
00139 )
00140 {
00141     uint32_t    num_elts;
00142     uint32_t    elt;
00143     Vector_cf*  v;
00144 
00145     num_elts = v_in->num_elts;
00146 
00147     if (*v_out != v_in)
00148     {
00149         create_vector_cf(v_out, num_elts);
00150     }
00151     v = *v_out;
00152 
00153     for (elt = 0; elt < num_elts; elt++)
00154     {
00155         v->elts[ elt ].r = z.r + v_in->elts[ elt ].r;
00156         v->elts[ elt ].i = z.i + v_in->elts[ elt ].i;
00157     }
00158 }
00159 
00168 void add_scalar_to_vector_cd
00169 (
00170     Vector_cd**      v_out, 
00171     const Vector_cd* v_in, 
00172     Complex_d        z
00173 )
00174 {
00175     uint32_t   num_elts;
00176     uint32_t   elt;
00177     Vector_cd*  v;
00178 
00179     num_elts = v_in->num_elts;
00180 
00181     if (*v_out != v_in)
00182     {
00183         create_vector_cd(v_out, num_elts);
00184     }
00185     v = *v_out;
00186 
00187     for (elt = 0; elt < num_elts; elt++)
00188     {
00189         v->elts[ elt ].r = z.r + v_in->elts[ elt ].r;
00190         v->elts[ elt ].i = z.i + v_in->elts[ elt ].i;
00191     }
00192 }
00193 
00214 void multiply_vector_by_scalar_f
00215 (
00216     Vector_f**      v_out, 
00217     const Vector_f* v_in, 
00218     float           a
00219 )
00220 {
00221 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00222     uint32_t  num_elts;
00223     Vector_f* v;
00224 
00225     num_elts = v_in->num_elts;
00226 
00227     if (*v_out != v_in)
00228     {
00229         copy_vector_f(v_out, v_in);
00230     }
00231     v = *v_out;
00232 
00233     blas_sscal(num_elts, a, v->elts, 1);
00234 #else
00235     uint32_t  num_elts;
00236     uint32_t  elt;
00237     Vector_f* v;
00238 
00239     num_elts = v_in->num_elts;
00240 
00241     if (*v_out != v_in)
00242     {
00243         create_vector_f(v_out, num_elts);
00244     }
00245     v = *v_out;
00246 
00247     for (elt = 0; elt < num_elts; elt++)
00248     {
00249         v->elts[ elt ] = a * v_in->elts[ elt ];
00250     }
00251 #endif
00252 }
00253 
00262 void multiply_vector_by_scalar_d
00263 (
00264     Vector_d**      v_out, 
00265     const Vector_d* v_in, 
00266     double          a
00267 )
00268 {
00269 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00270     uint32_t  num_elts;
00271     Vector_d* v;
00272 
00273     num_elts = v_in->num_elts;
00274 
00275     if (*v_out != v_in)
00276     {
00277         copy_vector_d(v_out, v_in);
00278     }
00279     v = *v_out;
00280 
00281     blas_dscal(num_elts, a, v->elts, 1);
00282 #else
00283     uint32_t  num_elts;
00284     uint32_t  elt;
00285     Vector_d* v;
00286 
00287     num_elts = v_in->num_elts;
00288 
00289     if (*v_out != v_in)
00290     {
00291         create_vector_d(v_out, num_elts);
00292     }
00293     v = *v_out;
00294 
00295     for (elt = 0; elt < num_elts; elt++)
00296     {
00297         v->elts[ elt ] = a * v_in->elts[ elt ];
00298     }
00299 #endif
00300 }
00301 
00310 void multiply_vector_by_scalar_cf
00311 (
00312     Vector_cf**      v_out, 
00313     const Vector_cf* v_in, 
00314     Complex_f        z
00315 )
00316 {
00317 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00318     uint32_t   num_elts;
00319     Vector_cf* v;
00320 
00321     num_elts = v_in->num_elts;
00322 
00323     if (*v_out != v_in)
00324     {
00325         copy_vector_cf(v_out, v_in);
00326     }
00327     v = *v_out;
00328 
00329     blas_cscal(num_elts, z, v->elts, 1);
00330 #else
00331     uint32_t   num_elts;
00332     uint32_t   elt;
00333     float      r, i;
00334     Vector_cf* v;
00335 
00336     num_elts = v_in->num_elts;
00337 
00338     if (*v_out != v_in)
00339     {
00340         create_vector_cf(v_out, num_elts);
00341     }
00342     v = *v_out;
00343 
00344     for (elt = 0; elt < num_elts; elt++)
00345     {
00346         r = z.r*v_in->elts[ elt ].r - z.i*v_in->elts[ elt ].i;
00347         i = z.i*v_in->elts[ elt ].r + z.r*v_in->elts[ elt ].i;
00348 
00349         v->elts[ elt ].r = r;
00350         v->elts[ elt ].i = i;
00351     }
00352 #endif
00353 }
00354 
00363 void multiply_vector_by_scalar_cd
00364 (
00365     Vector_cd**      v_out, 
00366     const Vector_cd* v_in, 
00367     Complex_d        z
00368 )
00369 {
00370 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00371     uint32_t   num_elts;
00372     Vector_cd* v;
00373 
00374     num_elts = v_in->num_elts;
00375 
00376     if (*v_out != v_in)
00377     {
00378         copy_vector_cd(v_out, v_in);
00379     }
00380     v = *v_out;
00381 
00382     blas_zscal(num_elts, z, v->elts, 1);
00383 #else
00384     uint32_t   num_elts;
00385     uint32_t   elt;
00386     double     r, i;
00387     Vector_cd* v;
00388 
00389     num_elts = v_in->num_elts;
00390 
00391     if (*v_out != v_in)
00392     {
00393         create_vector_cd(v_out, num_elts);
00394     }
00395     v = *v_out;
00396 
00397     for (elt = 0; elt < num_elts; elt++)
00398     {
00399         r = z.r*v_in->elts[ elt ].r - z.i*v_in->elts[ elt ].i;
00400         i = z.i*v_in->elts[ elt ].r + z.r*v_in->elts[ elt ].i;
00401 
00402         v->elts[ elt ].r = r;
00403         v->elts[ elt ].i = i;
00404     }
00405 #endif
00406 }
00407 
00431 Error* calc_vector_dot_prod_f
00432 (
00433     float*          dp_out,
00434     const Vector_f* v_1, 
00435     const Vector_f* v_2
00436 )
00437 {
00438     uint32_t num_elts;
00439 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00440 #else
00441     uint32_t elt;
00442 #endif
00443 
00444     num_elts = v_1->num_elts;
00445     if (num_elts != v_2->num_elts)
00446     {
00447         return JWSC_EARG("Dot product requires vectors with equal dimensions");
00448     }
00449 
00450 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00451     *dp_out = blas_sdot(num_elts, v_1->elts, 1, v_2->elts, 1);
00452 #else
00453     *dp_out = 0;
00454     for (elt = 0; elt < num_elts; elt++)
00455     {
00456         *dp_out += v_1->elts[ elt ] * v_2->elts[ elt ];
00457     }
00458 #endif
00459 
00460     return NULL;
00461 }
00462 
00474 Error* calc_vector_dot_prod_d
00475 (
00476     double*         dp_out,
00477     const Vector_d* v_1, 
00478     const Vector_d* v_2
00479 )
00480 {
00481     uint32_t num_elts;
00482 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00483 #else
00484     uint32_t elt;
00485 #endif
00486 
00487     num_elts = v_1->num_elts;
00488     if (num_elts != v_2->num_elts)
00489     {
00490         return JWSC_EARG("Dot product requires vectors with equal dimensions");
00491     }
00492 
00493 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00494     *dp_out = blas_ddot(num_elts, v_1->elts, 1, v_2->elts, 1);
00495 #else
00496     *dp_out = 0;
00497     for (elt = 0; elt < num_elts; elt++)
00498     {
00499         *dp_out += v_1->elts[ elt ] * v_2->elts[ elt ];
00500     }
00501 #endif
00502 
00503     return NULL;
00504 }
00505 
00533 Error* calc_3d_vector_cross_prod_f
00534 (
00535     Vector_f**      v_out, 
00536     const Vector_f* v_1, 
00537     const Vector_f* v_2
00538 )
00539 {
00540     float cp_1, cp_2, cp_3;
00541 
00542     if (v_1->num_elts != 3 || v_2->num_elts != 3)
00543     {
00544         if (*v_out != v_1 && *v_out != v_2)
00545         {
00546             free_vector_f(*v_out); *v_out = NULL;
00547         }
00548         return JWSC_EARG("Cross product requires vectors with three-dimensions");
00549     }
00550 
00551     cp_1  = v_1->elts[1] * v_2->elts[2];
00552     cp_1 -= v_1->elts[2] * v_2->elts[1];
00553     cp_2  = v_1->elts[2] * v_2->elts[0];
00554     cp_2 -= v_1->elts[0] * v_2->elts[2];
00555     cp_3  = v_1->elts[0] * v_2->elts[1];
00556     cp_3 -= v_1->elts[1] * v_2->elts[0];
00557 
00558     create_vector_f(v_out, 3);
00559     (*v_out)->elts[0] = cp_1;
00560     (*v_out)->elts[1] = cp_2;
00561     (*v_out)->elts[2] = cp_3;
00562 
00563     return NULL;
00564 }
00565 
00581 Error* calc_3d_vector_cross_prod_d
00582 (
00583     Vector_d**      v_out, 
00584     const Vector_d* v_1, 
00585     const Vector_d* v_2
00586 )
00587 {
00588     double cp_1, cp_2, cp_3;
00589 
00590     if (v_1->num_elts != 3 || v_2->num_elts != 3)
00591     {
00592         if (*v_out != v_1 && *v_out != v_2)
00593         {
00594             free_vector_d(*v_out); *v_out = NULL;
00595         }
00596         return JWSC_EARG("Cross product requires vectors with three-dimensions");
00597     }
00598 
00599     cp_1  = v_1->elts[1] * v_2->elts[2];
00600     cp_1 -= v_1->elts[2] * v_2->elts[1];
00601     cp_2  = v_1->elts[2] * v_2->elts[0];
00602     cp_2 -= v_1->elts[0] * v_2->elts[2];
00603     cp_3  = v_1->elts[0] * v_2->elts[1];
00604     cp_3 -= v_1->elts[1] * v_2->elts[0];
00605 
00606     create_vector_d(v_out, 3);
00607     (*v_out)->elts[0] = cp_1;
00608     (*v_out)->elts[1] = cp_2;
00609     (*v_out)->elts[2] = cp_3;
00610 
00611     return NULL;
00612 }
00613 
00630 void calc_vector_asum_f(float* sum_out, const Vector_f* v)
00631 {
00632 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00633     *sum_out = blas_sasum(v->num_elts, v->elts, 1);
00634 #else
00635     uint32_t num_elts;
00636     uint32_t elt;
00637 
00638     num_elts = v->num_elts;
00639     *sum_out = 0;
00640 
00641     for (elt = 0; elt < num_elts; elt++)
00642     {
00643         (*sum_out) += (float)fabs(v->elts[ elt ]);
00644     }
00645 #endif
00646 }
00647 
00652 void calc_vector_asum_d(double* sum_out, const Vector_d* v)
00653 {
00654 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00655     *sum_out = blas_dasum(v->num_elts, v->elts, 1);
00656 #else
00657     uint32_t num_elts;
00658     uint32_t elt;
00659 
00660     num_elts = v->num_elts;
00661     *sum_out = 0;
00662 
00663     for (elt = 0; elt < num_elts; elt++)
00664     {
00665         (*sum_out) += fabs(v->elts[ elt ]);
00666     }
00667 #endif
00668 }
00669 
00686 void calc_vector_mag_f(float* mag_out, const Vector_f* v)
00687 {
00688 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00689     *mag_out = blas_snrm2(v->num_elts, v->elts, 1);
00690 #else
00691     uint32_t num_elts;
00692     uint32_t elt;
00693 
00694     num_elts = v->num_elts;
00695     *mag_out = 0;
00696 
00697     for (elt = 0; elt < num_elts; elt++)
00698     {
00699         *mag_out += v->elts[ elt ] * v->elts[ elt ];
00700     }
00701 
00702     *mag_out = (float)sqrt(*mag_out);
00703 #endif
00704 }
00705 
00710 void calc_vector_mag_d(double* mag_out, const Vector_d* v)
00711 {
00712 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00713     *mag_out = blas_dnrm2(v->num_elts, v->elts, 1);
00714 #else
00715     uint32_t num_elts;
00716     uint32_t elt;
00717 
00718     num_elts = v->num_elts;
00719     *mag_out = 0;
00720 
00721     for (elt = 0; elt < num_elts; elt++)
00722     {
00723         *mag_out += v->elts[ elt ] * v->elts[ elt ];
00724     }
00725 
00726     *mag_out = sqrt(*mag_out);
00727 #endif
00728 }
00729 
00749 void normalize_vector_sum_f(Vector_f** v_out, const Vector_f* v_in)
00750 {
00751     float sum;
00752 
00753     calc_vector_asum_f(&sum, v_in);
00754 
00755     if (sum > 0)
00756     {
00757         multiply_vector_by_scalar_f(v_out, v_in, 1.0f / sum);
00758     } 
00759     else if (v_in != *v_out)
00760     {
00761         copy_vector_f(v_out, v_in);
00762     }
00763 }
00764 
00772 void normalize_vector_sum_d(Vector_d** v_out, const Vector_d* v_in)
00773 {
00774     double sum;
00775 
00776     calc_vector_asum_d(&sum, v_in);
00777 
00778     if (sum > 0)
00779     {
00780         multiply_vector_by_scalar_d(v_out, v_in, 1.0 / sum);
00781     } 
00782     else if (v_in != *v_out)
00783     {
00784         copy_vector_d(v_out, v_in);
00785     }
00786 }
00787 
00807 void normalize_vector_mag_f(Vector_f** v_out, const Vector_f* v_in)
00808 {
00809     float mag;
00810 
00811     calc_vector_mag_f(&mag, v_in);
00812 
00813     if (mag > 0)
00814     {
00815         multiply_vector_by_scalar_f(v_out, v_in, 1.0f / mag);
00816     }
00817     else if (v_in != *v_out)
00818     {
00819         copy_vector_f(v_out, v_in);
00820     }
00821 }
00822 
00830 void normalize_vector_mag_d(Vector_d** v_out, const Vector_d* v_in)
00831 {
00832     double mag;
00833 
00834     calc_vector_mag_d(&mag, v_in);
00835 
00836     if (mag > 0)
00837     {
00838         multiply_vector_by_scalar_d(v_out, v_in, 1.0 / mag);
00839     }
00840     else if (v_in != *v_out)
00841     {
00842         copy_vector_d(v_out, v_in);
00843     }
00844 }
00845 
00873 Error* add_vectors_f
00874 (
00875     Vector_f**      v_out, 
00876     const Vector_f* v_1, 
00877     const Vector_f* v_2
00878 )
00879 {
00880     uint32_t num_elts;
00881 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00882 #else
00883     uint32_t elt;
00884 #endif
00885 
00886     if (v_1->num_elts != v_2->num_elts)
00887     {
00888         if (*v_out != v_1 && *v_out != v_2)
00889         {
00890             free_vector_f(*v_out); *v_out = NULL;
00891         }
00892         return JWSC_EARG("Adding vectors requires equal dimensions");
00893     }
00894 
00895     num_elts = v_1->num_elts;
00896 
00897 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00898     if (*v_out == v_1)
00899     {
00900         blas_saxpy(num_elts, 1, v_2->elts, 1, v_1->elts, 1);
00901     }
00902     else if (*v_out == v_2)
00903     {
00904         blas_saxpy(num_elts, 1, v_1->elts, 1, v_2->elts, 1);
00905     }
00906     else
00907     {
00908         copy_vector_f(v_out, v_2);
00909         blas_saxpy(num_elts, 1, v_1->elts, 1, (*v_out)->elts, 1);
00910     }
00911 #else
00912     if (*v_out == v_1)
00913     {
00914         for (elt = 0; elt < num_elts; elt++)
00915         {
00916             v_1->elts[ elt ] += v_2->elts[ elt ];
00917         }
00918     }
00919     else if (*v_out == v_2)
00920     {
00921         for (elt = 0; elt < num_elts; elt++)
00922         {
00923             v_2->elts[ elt ] += v_1->elts[ elt ];
00924         }
00925     }
00926     else
00927     {
00928         create_vector_f(v_out, num_elts);
00929         for (elt = 0; elt < num_elts; elt++)
00930         {
00931             (*v_out)->elts[ elt ] = v_1->elts[ elt ] + v_2->elts[ elt ];
00932         }
00933     }
00934 #endif
00935 
00936     return NULL;
00937 }
00938 
00954 Error* add_vectors_d
00955 (
00956     Vector_d**      v_out, 
00957     const Vector_d* v_1, 
00958     const Vector_d* v_2
00959 )
00960 {
00961     uint32_t num_elts;
00962 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00963 #else
00964     uint32_t elt;
00965 #endif
00966 
00967     if (v_1->num_elts != v_2->num_elts)
00968     {
00969         if (*v_out != v_1 && *v_out != v_2)
00970         {
00971             free_vector_d(*v_out); *v_out = NULL;
00972         }
00973         return JWSC_EARG("Adding vectors requires equal dimensions");
00974     }
00975 
00976     num_elts = v_1->num_elts;
00977 
00978 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
00979     if (*v_out == v_1)
00980     {
00981         blas_daxpy(num_elts, 1, v_2->elts, 1, v_1->elts, 1);
00982     }
00983     else if (*v_out == v_2)
00984     {
00985         blas_daxpy(num_elts, 1, v_1->elts, 1, v_2->elts, 1);
00986     }
00987     else
00988     {
00989         copy_vector_d(v_out, v_2);
00990         blas_daxpy(num_elts, 1, v_1->elts, 1, (*v_out)->elts, 1);
00991     }
00992 #else
00993     if (*v_out == v_1)
00994     {
00995         for (elt = 0; elt < num_elts; elt++)
00996         {
00997             v_1->elts[ elt ] += v_2->elts[ elt ];
00998         }
00999     }
01000     else if (*v_out == v_2)
01001     {
01002         for (elt = 0; elt < num_elts; elt++)
01003         {
01004             v_2->elts[ elt ] += v_1->elts[ elt ];
01005         }
01006     }
01007     else
01008     {
01009         create_vector_d(v_out, num_elts);
01010         for (elt = 0; elt < num_elts; elt++)
01011         {
01012             (*v_out)->elts[ elt ] = v_1->elts[ elt ] + v_2->elts[ elt ];
01013         }
01014     }
01015 #endif
01016 
01017     return NULL;
01018 }
01019 
01035 Error* add_vectors_cf
01036 (
01037     Vector_cf**      v_out, 
01038     const Vector_cf* v_1, 
01039     const Vector_cf* v_2
01040 )
01041 {
01042     uint32_t num_elts;
01043 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01044     Complex_f z = {1, 0};
01045 #else
01046     uint32_t elt;
01047 #endif
01048 
01049     if (v_1->num_elts != v_2->num_elts)
01050     {
01051         if (*v_out != v_1 && *v_out != v_2)
01052         {
01053             free_vector_cf(*v_out); *v_out = NULL;
01054         }
01055         return JWSC_EARG("Adding vectors requires equal dimensions");
01056     }
01057 
01058     num_elts = v_1->num_elts;
01059 
01060 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01061     if (*v_out == v_1)
01062     {
01063         blas_caxpy(num_elts, z, v_2->elts, 1, v_1->elts, 1);
01064     }
01065     else if (*v_out == v_2)
01066     {
01067         blas_caxpy(num_elts, z, v_1->elts, 1, v_2->elts, 1);
01068     }
01069     else
01070     {
01071         copy_vector_cf(v_out, v_2);
01072         blas_caxpy(num_elts, z, v_1->elts, 1, (*v_out)->elts, 1);
01073     }
01074 #else
01075     if (*v_out == v_1)
01076     {
01077         for (elt = 0; elt < num_elts; elt++)
01078         {
01079             v_1->elts[ elt ].r = v_1->elts[ elt ].r + v_2->elts[ elt ].r;
01080             v_1->elts[ elt ].i = v_1->elts[ elt ].i + v_2->elts[ elt ].i;
01081         }
01082     }
01083     else if (*v_out == v_2)
01084     {
01085         for (elt = 0; elt < num_elts; elt++)
01086         {
01087             v_2->elts[ elt ].r = v_1->elts[ elt ].r + v_2->elts[ elt ].r;
01088             v_2->elts[ elt ].i = v_1->elts[ elt ].i + v_2->elts[ elt ].i;
01089         }
01090     }
01091     else
01092     {
01093         create_vector_cf(v_out, num_elts);
01094         for (elt = 0; elt < num_elts; elt++)
01095         {
01096             (*v_out)->elts[ elt ].r = v_1->elts[ elt ].r + v_2->elts[ elt ].r;
01097             (*v_out)->elts[ elt ].i = v_1->elts[ elt ].i + v_2->elts[ elt ].i;
01098         }
01099     }
01100 #endif
01101 
01102     return NULL;
01103 }
01104 
01120 Error* add_vectors_cd
01121 (
01122     Vector_cd**      v_out, 
01123     const Vector_cd* v_1, 
01124     const Vector_cd* v_2
01125 )
01126 {
01127     uint32_t num_elts;
01128 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01129     Complex_d z = {1, 0};
01130 #else
01131     uint32_t elt;
01132 #endif
01133 
01134     if (v_1->num_elts != v_2->num_elts)
01135     {
01136         if (*v_out != v_1 && *v_out != v_2)
01137         {
01138             free_vector_cd(*v_out); *v_out = NULL;
01139         }
01140         return JWSC_EARG("Adding vectors requires equal dimensions");
01141     }
01142 
01143     num_elts = v_1->num_elts;
01144 
01145 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01146     if (*v_out == v_1)
01147     {
01148         blas_zaxpy(num_elts, z, v_2->elts, 1, v_1->elts, 1);
01149     }
01150     else if (*v_out == v_2)
01151     {
01152         blas_zaxpy(num_elts, z, v_1->elts, 1, v_2->elts, 1);
01153     }
01154     else
01155     {
01156         copy_vector_cd(v_out, v_2);
01157         blas_zaxpy(num_elts, z, v_1->elts, 1, (*v_out)->elts, 1);
01158     }
01159 #else
01160     if (*v_out == v_1)
01161     {
01162         for (elt = 0; elt < num_elts; elt++)
01163         {
01164             v_1->elts[ elt ].r = v_1->elts[ elt ].r + v_2->elts[ elt ].r;
01165             v_1->elts[ elt ].i = v_1->elts[ elt ].i + v_2->elts[ elt ].i;
01166         }
01167     }
01168     else if (*v_out == v_2)
01169     {
01170         for (elt = 0; elt < num_elts; elt++)
01171         {
01172             v_2->elts[ elt ].r = v_1->elts[ elt ].r + v_2->elts[ elt ].r;
01173             v_2->elts[ elt ].i = v_1->elts[ elt ].i + v_2->elts[ elt ].i;
01174         }
01175     }
01176     else
01177     {
01178         create_vector_cd(v_out, num_elts);
01179         for (elt = 0; elt < num_elts; elt++)
01180         {
01181             (*v_out)->elts[ elt ].r = v_1->elts[ elt ].r + v_2->elts[ elt ].r;
01182             (*v_out)->elts[ elt ].i = v_1->elts[ elt ].i + v_2->elts[ elt ].i;
01183         }
01184     }
01185 #endif
01186 
01187     return NULL;
01188 }
01189 
01217 Error* subtract_vectors_f
01218 (
01219     Vector_f**      v_out, 
01220     const Vector_f* v_1, 
01221     const Vector_f* v_2
01222 )
01223 {
01224     uint32_t num_elts;
01225 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01226     Vector_f* v = NULL;
01227 #else
01228     uint32_t elt;
01229 #endif
01230 
01231     if (v_1->num_elts != v_2->num_elts)
01232     {
01233         if (*v_out != v_1 && *v_out != v_2)
01234         {
01235             free_vector_f(*v_out); *v_out = NULL;
01236         }
01237         return JWSC_EARG("Subtracting vectors requires equal dimensions");
01238     }
01239 
01240     num_elts = v_1->num_elts;
01241 
01242 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01243     if (*v_out == v_1)
01244     {
01245         blas_saxpy(num_elts, -1, v_2->elts, 1, v_1->elts, 1);
01246     }
01247     else if (*v_out == v_2)
01248     {
01249         copy_vector_f(&v, v_1);
01250         blas_saxpy(num_elts, -1, v_2->elts, 1, v->elts, 1);
01251         copy_vector_f(v_out, v);
01252         free_vector_f(v);
01253     }
01254     else
01255     {
01256         copy_vector_f(v_out, v_1);
01257         blas_saxpy(num_elts, -1, v_2->elts, 1, (*v_out)->elts, 1);
01258     }
01259 #else
01260     if (*v_out == v_1)
01261     {
01262         for (elt = 0; elt < num_elts; elt++)
01263         {
01264             v_1->elts[ elt ] = v_1->elts[ elt ] - v_2->elts[ elt ];
01265         }
01266     }
01267     else if (*v_out == v_2)
01268     {
01269         for (elt = 0; elt < num_elts; elt++)
01270         {
01271             v_2->elts[ elt ] = v_1->elts[ elt ] - v_2->elts[ elt ];
01272         }
01273     }
01274     else
01275     {
01276         create_vector_f(v_out, num_elts);
01277         for (elt = 0; elt < num_elts; elt++)
01278         {
01279             (*v_out)->elts[ elt ] = v_1->elts[ elt ] - v_2->elts[ elt ];
01280         }
01281     }
01282 #endif
01283 
01284     return NULL;
01285 }
01286 
01302 Error* subtract_vectors_d
01303 (
01304     Vector_d**      v_out, 
01305     const Vector_d* v_1, 
01306     const Vector_d* v_2
01307 )
01308 {
01309     uint32_t num_elts;
01310 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01311     Vector_d* v = NULL;
01312 #else
01313     uint32_t elt;
01314 #endif
01315 
01316     if (v_1->num_elts != v_2->num_elts)
01317     {
01318         if (*v_out != v_1 && *v_out != v_2)
01319         {
01320             free_vector_d(*v_out); *v_out = NULL;
01321         }
01322         return JWSC_EARG("Subtracting vectors requires equal dimensions");
01323     }
01324 
01325     num_elts = v_1->num_elts;
01326 
01327 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01328     if (*v_out == v_1)
01329     {
01330         blas_daxpy(num_elts, -1, v_2->elts, 1, v_1->elts, 1);
01331     }
01332     else if (*v_out == v_2)
01333     {
01334         copy_vector_d(&v, v_1);
01335         blas_daxpy(num_elts, -1, v_2->elts, 1, v->elts, 1);
01336         copy_vector_d(v_out, v);
01337         free_vector_d(v);
01338     }
01339     else
01340     {
01341         copy_vector_d(v_out, v_1);
01342         blas_daxpy(num_elts, -1, v_2->elts, 1, (*v_out)->elts, 1);
01343     }
01344 #else
01345     if (*v_out == v_1)
01346     {
01347         for (elt = 0; elt < num_elts; elt++)
01348         {
01349             v_1->elts[ elt ] = v_1->elts[ elt ] - v_2->elts[ elt ];
01350         }
01351     }
01352     else if (*v_out == v_2)
01353     {
01354         for (elt = 0; elt < num_elts; elt++)
01355         {
01356             v_2->elts[ elt ] = v_1->elts[ elt ] - v_2->elts[ elt ];
01357         }
01358     }
01359     else
01360     {
01361         create_vector_d(v_out, num_elts);
01362         for (elt = 0; elt < num_elts; elt++)
01363         {
01364             (*v_out)->elts[ elt ] = v_1->elts[ elt ] - v_2->elts[ elt ];
01365         }
01366     }
01367 #endif
01368 
01369     return NULL;
01370 }
01371 
01387 Error* subtract_vectors_cf
01388 (
01389     Vector_cf**      v_out, 
01390     const Vector_cf* v_1, 
01391     const Vector_cf* v_2
01392 )
01393 {
01394     uint32_t num_elts;
01395 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01396     Vector_cf* v = NULL;
01397     Complex_f  z = {-1, 0};
01398 #else
01399     uint32_t elt;
01400 #endif
01401 
01402     if (v_1->num_elts != v_2->num_elts)
01403     {
01404         if (*v_out != v_1 && *v_out != v_2)
01405         {
01406             free_vector_cf(*v_out); *v_out = NULL;
01407         }
01408         return JWSC_EARG("Subtracting vectors requires equal dimensions");
01409     }
01410 
01411     num_elts = v_1->num_elts;
01412 
01413 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01414     if (*v_out == v_1)
01415     {
01416         blas_caxpy(num_elts, z, v_2->elts, 1, v_1->elts, 1);
01417     }
01418     else if (*v_out == v_2)
01419     {
01420         copy_vector_cf(&v, v_1);
01421         blas_caxpy(num_elts, z, v_2->elts, 1, v->elts, 1);
01422         copy_vector_cf(v_out, v);
01423         free_vector_cf(v);
01424     }
01425     else
01426     {
01427         copy_vector_cf(v_out, v_1);
01428         blas_caxpy(num_elts, z, v_2->elts, 1, (*v_out)->elts, 1);
01429     }
01430 #else
01431     if (*v_out == v_1)
01432     {
01433         for (elt = 0; elt < num_elts; elt++)
01434         {
01435             v_1->elts[ elt ].r = v_1->elts[ elt ].r - v_2->elts[ elt ].r;
01436             v_1->elts[ elt ].i = v_1->elts[ elt ].i - v_2->elts[ elt ].i;
01437         }
01438     }
01439     else if (*v_out == v_2)
01440     {
01441         for (elt = 0; elt < num_elts; elt++)
01442         {
01443             v_2->elts[ elt ].r = v_1->elts[ elt ].r - v_2->elts[ elt ].r;
01444             v_2->elts[ elt ].i = v_1->elts[ elt ].i - v_2->elts[ elt ].i;
01445         }
01446     }
01447     else
01448     {
01449         create_vector_cf(v_out, num_elts);
01450         for (elt = 0; elt < num_elts; elt++)
01451         {
01452             (*v_out)->elts[ elt ].r = v_1->elts[ elt ].r - v_2->elts[ elt ].r;
01453             (*v_out)->elts[ elt ].i = v_1->elts[ elt ].i - v_2->elts[ elt ].i;
01454         }
01455     }
01456 #endif
01457 
01458     return NULL;
01459 }
01460 
01476 Error* subtract_vectors_cd
01477 (
01478     Vector_cd**      v_out, 
01479     const Vector_cd* v_1, 
01480     const Vector_cd* v_2
01481 )
01482 {
01483     uint32_t num_elts;
01484 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01485     Vector_cd* v = NULL;
01486     Complex_d  z = {-1, 0};
01487 #else
01488     uint32_t elt;
01489 #endif
01490 
01491     if (v_1->num_elts != v_2->num_elts)
01492     {
01493         if (*v_out != v_1 && *v_out != v_2)
01494         {
01495             free_vector_cd(*v_out); *v_out = NULL;
01496         }
01497         return JWSC_EARG("Subtracting vectors requires equal dimensions");
01498     }
01499 
01500     num_elts = v_1->num_elts;
01501 
01502 #if defined JWSC_HAVE_BLAS || defined JWSC_HAVE_ACCELERATE
01503     if (*v_out == v_1)
01504     {
01505         blas_zaxpy(num_elts, z, v_2->elts, 1, v_1->elts, 1);
01506     }
01507     else if (*v_out == v_2)
01508     {
01509         copy_vector_cd(&v, v_1);
01510         blas_zaxpy(num_elts, z, v_2->elts, 1, v->elts, 1);
01511         copy_vector_cd(v_out, v);
01512         free_vector_cd(v);
01513     }
01514     else
01515     {
01516         copy_vector_cd(v_out, v_1);
01517         blas_zaxpy(num_elts, z, v_2->elts, 1, (*v_out)->elts, 1);
01518     }
01519 #else
01520     if (*v_out == v_1)
01521     {
01522         for (elt = 0; elt < num_elts; elt++)
01523         {
01524             v_1->elts[ elt ].r = v_1->elts[ elt ].r - v_2->elts[ elt ].r;
01525             v_1->elts[ elt ].i = v_1->elts[ elt ].i - v_2->elts[ elt ].i;
01526         }
01527     }
01528     else if (*v_out == v_2)
01529     {
01530         for (elt = 0; elt < num_elts; elt++)
01531         {
01532             v_2->elts[ elt ].r = v_1->elts[ elt ].r - v_2->elts[ elt ].r;
01533             v_2->elts[ elt ].i = v_1->elts[ elt ].i - v_2->elts[ elt ].i;
01534         }
01535     }
01536     else
01537     {
01538         create_vector_cd(v_out, num_elts);
01539         for (elt = 0; elt < num_elts; elt++)
01540         {
01541             (*v_out)->elts[ elt ].r = v_1->elts[ elt ].r - v_2->elts[ elt ].r;
01542             (*v_out)->elts[ elt ].i = v_1->elts[ elt ].i - v_2->elts[ elt ].i;
01543         }
01544     }
01545 #endif
01546 
01547     return NULL;
01548 }
01549