00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, Andrew W. Steiner 00005 00006 This file is part of O2scl. 00007 00008 O2scl is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 O2scl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00020 00021 ------------------------------------------------------------------- 00022 */ 00023 #ifndef O2SCL_UMATRIX_CX_TLATE_H 00024 #define O2SCL_UMATRIX_CX_TLATE_H 00025 00026 /** \file umatrix_cx_tlate.h 00027 \brief File for definitions of matrices 00028 */ 00029 00030 #include <iostream> 00031 #include <cstdlib> 00032 #include <string> 00033 #include <fstream> 00034 #include <sstream> 00035 00036 #include <gsl/gsl_matrix.h> 00037 #include <gsl/gsl_ieee_utils.h> 00038 00039 #include <o2scl/err_hnd.h> 00040 #include <o2scl/uvector_tlate.h> 00041 #include <o2scl/uvector_cx_tlate.h> 00042 00043 #ifndef DOXYGENP 00044 namespace o2scl { 00045 #endif 00046 00047 /** 00048 \brief A matrix view of complex numbers 00049 */ 00050 template<class data_t, class complex_t> class umatrix_cx_view_tlate { 00051 00052 #ifndef DOXYGEN_INTERNAL 00053 00054 protected: 00055 00056 /// The data 00057 data_t *data; 00058 /// The number of rows 00059 size_t size1; 00060 /// The number of columns 00061 size_t size2; 00062 /// Zero if memory is owned elsewhere, 1 otherwise 00063 int owner; 00064 00065 #endif 00066 00067 public: 00068 00069 /// \name Copy constructors 00070 //@{ 00071 /// So2scllow copy constructor - create a new view of the same matrix 00072 umatrix_cx_view_tlate(const umatrix_cx_view_tlate &v) { 00073 data=v.data; 00074 size1=v.size1; 00075 size2=v.size2; 00076 owner=0; 00077 } 00078 00079 /// So2scllow copy constructor - create a new view of the same matrix 00080 umatrix_cx_view_tlate& operator=(const umatrix_cx_view_tlate &v) { 00081 data=v.data; 00082 size1=v.size1; 00083 size2=v.size2; 00084 owner=0; 00085 00086 return *this; 00087 } 00088 //@} 00089 00090 ~umatrix_cx_view_tlate() {}; 00091 00092 /// \name Get and set methods 00093 //@{ 00094 /** 00095 \brief Array-like indexing 00096 */ 00097 complex_t *operator[](size_t i) { 00098 #if GSL_RANGE_CHECK 00099 if (i>=size1) { 00100 set_err((((std::string)"Array index ")+itos(i)+" out of bounds" 00101 +" in umatrix_cx_view_tlate::operator[]. Size: "+ 00102 itos(size1)+ 00103 " (index should be less than size).").c_str(),gsl_index); 00104 return (complex_t *)data; 00105 } 00106 #endif 00107 return (complex_t *)(data+2*i*size2); 00108 } 00109 00110 /** 00111 \brief Array-like indexing 00112 */ 00113 const complex_t *operator[](size_t i) const { 00114 #if GSL_RANGE_CHECK 00115 if (i>=size1) { 00116 set_err((((std::string)"Array index ")+itos(i)+" out of bounds" 00117 +" in umatrix_cx_view_tlate::operator[] const. Size: "+ 00118 itos(size1)+ 00119 " (index should be less than size).").c_str(),gsl_index); 00120 return (const complex_t *)data; 00121 } 00122 #endif 00123 return (const complex_t *)(data+2*i*size2); 00124 } 00125 00126 /** 00127 \brief Array-like indexing 00128 */ 00129 complex_t &operator()(size_t i, size_t j) { 00130 #if GSL_RANGE_CHECK 00131 if (i>=size1 || j>=size2) { 00132 set_err((((std::string)"Indices (")+itos(i)+","+itos(j)+ 00133 ") out of bounds" 00134 +" in umatrix_cx_view_tlate::operator(). Sizes: ("+ 00135 itos(size1)+","+itos(size2)+ 00136 ") (index should be less than size).").c_str(),gsl_index); 00137 return *(complex_t *)data; 00138 } 00139 #endif 00140 return *(complex_t *)(data+2*i*size2+j); 00141 } 00142 00143 /** 00144 \brief Array-like indexing 00145 */ 00146 const complex_t &operator()(size_t i, size_t j) const { 00147 #if GSL_RANGE_CHECK 00148 if (i>=size1 || j>=size2) { 00149 set_err((((std::string)"Indices (")+itos(i)+","+itos(j)+ 00150 ") out of bounds" 00151 +" in umatrix_cx_view_tlate::operator() const. Sizes: ("+ 00152 itos(size1)+","+itos(size2)+ 00153 ") (index should be less than size).").c_str(),gsl_index); 00154 return *(const complex_t *)data; 00155 } 00156 #endif 00157 return *(const complex_t *)(data+2*i*size2+j); 00158 } 00159 00160 /** \brief Get (with optional range-checking) */ 00161 complex_t get(size_t i, size_t j) const { 00162 #if GSL_RANGE_CHECK 00163 if (i>=size1 || j>=size2) { 00164 set_err((((std::string)"Indices (")+itos(i)+","+itos(j)+ 00165 ") out of bounds" 00166 +" in umatrix_cx_view_tlate::get(). Sizes: ("+ 00167 itos(size1)+","+itos(size2)+ 00168 ") (index should be less than size).").c_str(),gsl_index); 00169 return *(complex_t *)data; 00170 } 00171 #endif 00172 return *(complex_t *)(data+2*i*size2+j); 00173 } 00174 00175 /** \brief Get pointer (with optional range-checking) */ 00176 complex_t *get_ptr(size_t i, size_t j) { 00177 #if GSL_RANGE_CHECK 00178 if (i>=size1 || j>=size2) { 00179 set_err((((std::string)"Indices (")+itos(i)+","+itos(j)+ 00180 ") out of bounds" 00181 +" in umatrix_cx_view_tlate::get_ptr(). Sizes: ("+ 00182 itos(size1)+","+itos(size2)+ 00183 ") (index should be less than size).").c_str(),gsl_index); 00184 return (complex_t *)data; 00185 } 00186 #endif 00187 return (complex_t *)(data+2*i*size2+j); 00188 } 00189 00190 /** \brief Get pointer (with optional range-checking) */ 00191 const complex_t *get_const_ptr(size_t i, size_t j) const { 00192 #if GSL_RANGE_CHECK 00193 if (i>=size1 || j>=size2) { 00194 set_err((((std::string)"Indices (")+itos(i)+","+itos(j)+ 00195 ") out of bounds" 00196 +" in umatrix_cx_view_tlate::get_const_ptr(). Sizes: ("+ 00197 itos(size1)+","+itos(size2)+ 00198 ") (index should be less than size).").c_str(),gsl_index); 00199 return (const complex_t *)data; 00200 } 00201 #endif 00202 return (const complex_t *)(data+2*i*size2+j); 00203 } 00204 00205 /** \brief Set (with optional range-checking) */ 00206 int set(size_t i, size_t j, complex_t val) { 00207 #if GSL_RANGE_CHECK 00208 if (i>=size1 || j>=size2) { 00209 set_err_ret((((std::string)"Indices (")+itos(i)+","+itos(j)+ 00210 ") out of bounds" 00211 +" in umatrix_cx_view_tlate::set(i,j,val). Sizes: ("+ 00212 itos(size1)+","+itos(size2)+ 00213 ") (index should be less than size).").c_str(),gsl_index); 00214 } 00215 #endif 00216 *(data+2*i*size2+j)=GSL_REAL(val); 00217 *(data+2*i*size2+j+1)=GSL_IMAG(val); 00218 return 0; 00219 } 00220 00221 /** \brief Set (with optional range-checking) */ 00222 int set(size_t i, size_t j, data_t re, data_t im) { 00223 #if GSL_RANGE_CHECK 00224 if (i>=size1 || j>=size2) { 00225 set_err_ret((((std::string)"Indices (")+itos(i)+","+itos(j)+ 00226 ") out of bounds" 00227 +" in umatrix_cx_view_tlate::set(i,j,re,im). Sizes: ("+ 00228 itos(size1)+","+itos(size2)+ 00229 ") (index should be less than size).").c_str(),gsl_index); 00230 } 00231 #endif 00232 *(data+2*i*size2+j)=re; 00233 *(data+2*i*size2+j+1)=im; 00234 return 0; 00235 } 00236 00237 /** \brief Set all of the value to be the value \c val */ 00238 int set_all(complex_t val) { 00239 for(size_t i=0;i<size1;i++) { 00240 for(size_t j=0;j<size2;j++) { 00241 *(data+2*i*size2+j)=GSL_REAL(val); 00242 *(data+2*i*size2+j+1)=GSL_IMAG(val); 00243 } 00244 } 00245 return 0; 00246 } 00247 00248 /** 00249 \brief Method to return number of rows 00250 00251 If no memory has been allocated, this will quietly 00252 return zero. 00253 */ 00254 size_t rows() const { 00255 return size1; 00256 } 00257 00258 /** 00259 \brief Method to return number of columns 00260 00261 If no memory has been allocated, this will quietly 00262 return zero. 00263 */ 00264 size_t cols() const { 00265 return size2; 00266 } 00267 //@} 00268 00269 /// \name Other methods 00270 //@{ 00271 /// Return true if this object owns the data it refers to 00272 bool is_owner() const { 00273 if (owner==1) return true; 00274 return false; 00275 } 00276 //@} 00277 00278 /// \name Arithmetic 00279 //@{ 00280 /** \brief operator+= */ 00281 umatrix_cx_view_tlate<data_t,complex_t> &operator+= 00282 (const umatrix_cx_view_tlate<data_t,complex_t> &x) { 00283 size_t lsize=x.size1; 00284 if (lsize>size1) lsize=size1; 00285 size_t lsize2=x.size2; 00286 if (lsize2>size2) lsize2=size2; 00287 for(size_t i=0;i<lsize;i++) { 00288 for(size_t j=0;j<lsize2;j++) { 00289 (*this)[i][j]+=x[i][j]; 00290 } 00291 } 00292 00293 return *this; 00294 } 00295 00296 /** \brief operator-= */ 00297 umatrix_cx_view_tlate<data_t,complex_t> &operator-= 00298 (const umatrix_cx_view_tlate<data_t,complex_t> &x) { 00299 size_t lsize=x.size1; 00300 if (lsize>size1) lsize=size1; 00301 size_t lsize2=x.size2; 00302 if (lsize2>size2) lsize2=size2; 00303 for(size_t i=0;i<lsize;i++) { 00304 for(size_t j=0;j<lsize2;j++) { 00305 (*this)[i][j]+=x[i][j]; 00306 } 00307 } 00308 00309 return *this; 00310 } 00311 00312 /** \brief operator+= */ 00313 umatrix_cx_view_tlate<data_t,complex_t> &operator+=(const data_t &y) { 00314 for(size_t i=0;i<size1;i++) { 00315 for(size_t j=0;j<size2;j++) { 00316 (*this)[i][j]+=y; 00317 } 00318 } 00319 00320 return *this; 00321 } 00322 00323 /** \brief operator-= */ 00324 umatrix_cx_view_tlate<data_t,complex_t> &operator-=(const data_t &y) { 00325 for(size_t i=0;i<size1;i++) { 00326 for(size_t j=0;j<size2;j++) { 00327 (*this)[i][j]-=y; 00328 } 00329 } 00330 00331 return *this; 00332 } 00333 00334 /** \brief operator*= */ 00335 umatrix_cx_view_tlate<data_t,complex_t> &operator*=(const data_t &y) { 00336 for(size_t i=0;i<size1;i++) { 00337 for(size_t j=0;j<size2;j++) { 00338 (*this)[i][j]*=y; 00339 } 00340 } 00341 00342 return *this; 00343 } 00344 //@} 00345 00346 #ifndef DOXYGEN_INTERNAL 00347 00348 protected: 00349 00350 /** \brief Empty constructor provided for use by 00351 umatrix_cx_tlate(const umatrix_cx_tlate &v) 00352 */ 00353 umatrix_cx_view_tlate() {}; 00354 00355 #endif 00356 00357 }; 00358 00359 /** 00360 \brief A matrix of double-precision numbers 00361 00362 */ 00363 template<class data_t, class complex_t> class umatrix_cx_tlate : 00364 public umatrix_cx_view_tlate<data_t,complex_t> { 00365 public: 00366 00367 /// \name Standard constructor 00368 //@{ 00369 /** \brief Create an umatrix of size \c n with owner as 'true' 00370 */ 00371 umatrix_cx_tlate(size_t r=0, size_t c=0) { 00372 00373 this->data=0; 00374 this->size1=0; 00375 this->size2=0; 00376 00377 // This must be set to 1 even if n=0 so that future 00378 // calls to operator= work properly 00379 this->owner=1; 00380 00381 if (r>0 && c>0) { 00382 this->data=(data_t *)malloc(2*r*c*sizeof(data_t)); 00383 if (this->data) { 00384 this->size1=r; 00385 this->size2=c; 00386 } else { 00387 set_err("No memory for data in umatrix_cx_tlate constructor", 00388 gsl_enomem); 00389 } 00390 } 00391 } 00392 //@} 00393 00394 /// \name Copy constructors 00395 //@{ 00396 /// Deep copy constructor, allocate new space and make a copy 00397 umatrix_cx_tlate(const umatrix_cx_tlate &v) : 00398 umatrix_cx_view_tlate<data_t,complex_t>() { 00399 size_t n=v.size1; 00400 size_t n2=v.size2; 00401 if (n>0 && n2>0) { 00402 this->data=(data_t *)malloc(2*n*n2*sizeof(data_t)); 00403 if (this->data) { 00404 this->size1=n; 00405 this->size2=n2; 00406 this->owner=1; 00407 for(size_t i=0;i<n;i++) { 00408 for(size_t j=0;j<n2;j++) { 00409 *(this->data+i*this->size2+j)=v[i][j]; 00410 } 00411 } 00412 } else { 00413 set_err("No memory for data in umatrix_cx_tlate constructor", 00414 gsl_enomem); 00415 } 00416 } else { 00417 this->size1=0; 00418 this->size2=0; 00419 } 00420 } 00421 00422 /// Deep copy constructor, allocate new space and make a copy 00423 umatrix_cx_tlate 00424 (const umatrix_cx_view_tlate<data_t,complex_t> &v) : 00425 umatrix_cx_view_tlate<data_t,complex_t>() { 00426 size_t r=v.rows(); 00427 size_t c=v.cols(); 00428 if (r>0 && c>0) { 00429 this->data=(data_t *)malloc(2*r*c*sizeof(data_t)); 00430 if (this->data) { 00431 this->size1=v.size1; 00432 this->size2=v.size2; 00433 this->owner=1; 00434 for(size_t i=0;i<r;i++) { 00435 for(size_t j=0;i<c;j++) { 00436 *(this->data+i*this->size2+j)=v[i][j]; 00437 } 00438 } 00439 } else { 00440 set_err("No memory for data in umatrix_cx_tlate constructor", 00441 gsl_enomem); 00442 } 00443 } else { 00444 this->size1=0; 00445 this->size2=0; 00446 } 00447 } 00448 00449 /** \brief Deep copy constructor, if owner is true, allocate space and 00450 make a new copy, otherwise, just copy into the view 00451 */ 00452 umatrix_cx_tlate& operator=(const umatrix_cx_tlate &v) { 00453 size_t sze=v.size1; 00454 size_t sze2=v.size2; 00455 if (this->owner) { 00456 allocate(sze,sze2); 00457 } else { 00458 if (this->size1!=sze || this->size2!=sze2) { 00459 set_err("Sizes don't match in umatrix_cx_tlate::operator=()", 00460 gsl_ebadlen); 00461 return *this; 00462 } 00463 } 00464 for(size_t i=0;i<sze;i++) { 00465 for(size_t j=0;j<sze2;j++) { 00466 *(this->data+i*this->size2+j)=v[i][j]; 00467 } 00468 } 00469 return *this; 00470 } 00471 00472 /** \brief Deep copy constructor, if owner is true, allocate space and 00473 make a new copy, otherwise, just copy into the view 00474 */ 00475 umatrix_cx_tlate& operator= 00476 (const umatrix_cx_view_tlate<data_t,complex_t> &v) { 00477 size_t sze=v.rows(); 00478 size_t sze2=v.cols(); 00479 if (this->owner) { 00480 allocate(sze,sze2); 00481 } else { 00482 if (this->size1!=sze || this->size2!=sze2) { 00483 set_err("Sizes don't match in umatrix_cx_tlate::operator=()", 00484 gsl_ebadlen); 00485 return *this; 00486 } 00487 } 00488 for(size_t i=0;i<sze;i++) { 00489 for(size_t j=0;j<sze2;j++) { 00490 *(this->data+i*this->size2+j)=v[i][j]; 00491 } 00492 } 00493 return *this; 00494 } 00495 00496 /** \brief Deep copy from an array of uvectors 00497 */ 00498 umatrix_cx_tlate(size_t n, 00499 uvector_cx_view_tlate<data_t,complex_t> uva[]) { 00500 if (n>0) { 00501 size_t n2=uva[0]; 00502 if (n2>0) { 00503 allocate(n,n2); 00504 for(size_t i=0;i<n;i++) { 00505 for(size_t j=0;j<n2;j++) { 00506 (*this)[i][j]=uva[i][j]; 00507 } 00508 } 00509 } 00510 } 00511 } 00512 00513 /** \brief Deep copy from a C-style 2-d array 00514 */ 00515 umatrix_cx_tlate(size_t n, size_t n2, data_t **csa) { 00516 if (n>0 && n2>0) { 00517 allocate(n,n2); 00518 for(size_t i=0;i<n;i++) { 00519 for(size_t j=0;j<n2;j++) { 00520 (*this)[i][j]=csa[i][j]; 00521 } 00522 } 00523 } 00524 } 00525 00526 //@} 00527 00528 ~umatrix_cx_tlate() { 00529 if (this->size1>0) { 00530 if (this->owner==1) { 00531 std::free(this->data); 00532 this->size1=0; 00533 this->size2=0; 00534 } 00535 } 00536 } 00537 00538 /// \name Memory allocation 00539 //@{ 00540 /** 00541 \brief Allocate memory after freeing any memory presently in use 00542 */ 00543 int allocate(size_t nrows, size_t ncols) { 00544 if (this->size1>0 || this->size2>0) free(); 00545 00546 if (nrows>0 && ncols>0) { 00547 this->data=(data_t *)malloc(2*nrows*ncols*sizeof(data_t)); 00548 if (this->data) { 00549 this->size1=nrows; 00550 this->size2=ncols; 00551 this->owner=1; 00552 } else { 00553 set_err_ret("No memory for data in umatrix_cx_tlate::allocate()", 00554 gsl_enomem); 00555 } 00556 } else { 00557 set_err_ret("Zero size in umatrix::allocate()",gsl_einval); 00558 } 00559 return 0; 00560 } 00561 00562 /** 00563 \brief Free the memory 00564 00565 This function will safely do nothing if used without first 00566 allocating memory or if called multiple times in succession. 00567 */ 00568 int free() { 00569 if (this->size1>0) { 00570 if (this->owner==1) { 00571 std::free(this->data); 00572 } 00573 this->size1=0; 00574 this->size2=0; 00575 } 00576 return 0; 00577 } 00578 //@} 00579 00580 /// \name Other methods 00581 //@{ 00582 /// \brief Compute the transpose (even if matrix is not square) 00583 umatrix_cx_tlate<data_t,complex_t> transpose() { 00584 umatrix_cx_tlate<data_t,complex_t> result(this->size2,this->size1); 00585 for(size_t i=0;i<this->size1;i++) { 00586 for(size_t j=0;j<this->size2;j++) { 00587 result[j][i]=(*this)[i][j]; 00588 } 00589 } 00590 } 00591 //@} 00592 00593 }; 00594 00595 /** \brief Create a vector from a row of a matrix 00596 */ 00597 template<class data_t, class complex_t> class umatrix_cx_row_tlate : 00598 public uvector_cx_view_tlate<data_t,complex_t> { 00599 public: 00600 /** \brief Create a vector from row \c i of matrix \c m */ 00601 umatrix_cx_row_tlate(umatrix_cx_view_tlate<data_t,complex_t> &m, 00602 size_t i) { 00603 if (i<m.rows()) { 00604 this->sz=m.cols(); 00605 this->data=m[0]+m.cols()*i; 00606 this->owner=0; 00607 } 00608 } 00609 }; 00610 00611 /** \brief Create a const vector from a row of a matrix 00612 */ 00613 template<class data_t, class complex_t> class umatrix_cx_const_row_tlate : 00614 public uvector_cx_view_tlate<data_t,complex_t> { 00615 public: 00616 /** \brief Create a vector from row \c i of matrix \c m */ 00617 umatrix_cx_const_row_tlate 00618 (const umatrix_cx_view_tlate<data_t,complex_t> &m, 00619 size_t i) { 00620 if (i<m.size1) { 00621 this->sz=m.cols(); 00622 this->data=m[0]+m.cols()*i; 00623 this->owner=0; 00624 } 00625 } 00626 }; 00627 00628 /// umatrix_cx typedef 00629 typedef umatrix_cx_tlate<double,gsl_complex> umatrix_cx; 00630 /// umatrix_cx_view typedef 00631 typedef umatrix_cx_view_tlate<double,gsl_complex> umatrix_cx_view; 00632 /// umatrix_cx_row typedef 00633 typedef umatrix_cx_row_tlate<double,gsl_complex> umatrix_cx_row; 00634 /// umatrix_cx_const_row typedef 00635 typedef umatrix_cx_const_row_tlate<double,gsl_complex> 00636 umatrix_cx_const_row; 00637 00638 /** \brief A operator for naive matrix output 00639 00640 This outputs all of the matrix elements. Each row is output with 00641 an endline character at the end of each row. Positive values are 00642 preceeded by an extra space. A 2x2 example: 00643 \verbatim 00644 -3.751935e-05 -6.785864e-04 00645 -6.785864e-04 1.631984e-02 00646 \endverbatim 00647 00648 The function \c gsl_ieee_double_to_rep() is used to determine 00649 the sign of a number, so that "-0.0" as distinct from "+0.0" 00650 is handled correctly. 00651 00652 \todo This assumes that scientific mode is on and showpos 00653 is off. It'd be nice to fix this. 00654 00655 */ 00656 template<class data_t, class complex_t> std::ostream &operator<< 00657 (std::ostream &os, const umatrix_cx_view_tlate<data_t,complex_t> &v) { 00658 size_t i; 00659 gsl_ieee_double_rep r; 00660 for(i=0;i<v.rows()-1;i++) { 00661 for(size_t j=0;j<v.cols();j++) { 00662 gsl_ieee_double_to_rep(&(v[i][j]), &r); 00663 if (r.sign==1) os << v[i][j] << ' '; 00664 else os << ' ' << v[i][j] << ' '; 00665 } 00666 os << '\n'; 00667 } 00668 i=v.rows()-1; 00669 if (i>0) { 00670 for(size_t j=0;j<v.cols();j++) { 00671 gsl_ieee_double_to_rep(&(v[i][j]), &r); 00672 if (r.sign==1) os << v[i][j] << ' '; 00673 else os << ' ' << v[i][j] << ' '; 00674 } 00675 } 00676 return os; 00677 } 00678 00679 /** \brief A simple class to provide an \c allocate() function 00680 for \ref umatrix_cx 00681 00682 00683 */ 00684 class umatrix_cx_alloc { 00685 public: 00686 /// Allocate \c v for \c i elements 00687 void allocate(umatrix_cx &o, int i, int j) { o.allocate(i,j); } 00688 /// Free memory 00689 void free(umatrix_cx &o) { o.free(); } 00690 }; 00691 00692 /** \brief A matrix where the memory allocation is performed in 00693 the constructor 00694 */ 00695 #ifdef DOXYGENP 00696 template<size_t N, size_t M> class ufmatrix_cx : 00697 public umatrix_cx_tlate<data_t,complex_t> 00698 #else 00699 template<size_t N, size_t M> class ufmatrix_cx : 00700 public umatrix_cx_tlate<double,gsl_complex> 00701 #endif 00702 { 00703 public: 00704 ufmatrix_cx() : umatrix_cx_tlate<double,gsl_complex>(N,M) { 00705 } 00706 }; 00707 00708 00709 #ifndef DOXYGENP 00710 } 00711 #endif 00712 00713 #endif 00714 00715 00716
Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.
Project hosting provided by
,
O2scl Sourceforge Project Page