00001 // vector.cc 00002 // SuperMix version 1.0 C++ source file 00003 // 00004 // Copyright (c) 1999 California Institute of Technology. 00005 // All rights reserved. 00006 // 00007 // Redistribution and use in source and binary forms for noncommercial 00008 // purposes are permitted provided that the above copyright notice and 00009 // this paragraph are duplicated in all such forms and that any 00010 // documentation and other materials related to such distribution and 00011 // use acknowledge that the software was developed by California 00012 // Institute of Technology. Redistribution and/or use in source or 00013 // binary forms is not permitted for any commercial purpose. Use of 00014 // this software does not include a permitted use of the Institute's 00015 // name or trademark for any purpose. 00016 // 00017 // DISCLAIMER: 00018 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT 00019 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR 00020 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET 00021 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE 00022 // LICENSED PRODUCT, HOWEVER USED. IN NO EVENT SHALL CALTECH/JPL BE 00023 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO 00024 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC 00025 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF 00026 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN 00027 // FACT SHALL KNOW OF THE POSSIBILITY. THE USER BEARS ALL RISK 00028 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED 00029 // MATERIALS. 00030 // 00031 // Change history: 00032 // 9/8/00: added some STL compatibility functions 00033 // 4/26/00: changed to support copying of empty vectors, make_empty() 00034 // 11/11/98: Changed table access to new syntax 00035 // 10/28/98: removed int_vector stuff 00036 // 7/31/98: added out_separator() static member functions 00037 // 7/30/98: Enhanced show(), added << 00038 // 7/28/98: Added <iostream.h>, since SIScmplx.h doesn't any more 00039 // 7/6/98: Added reindex() 00040 // 1/9/98: Changed shrink to return a reference to the vector, vice int 00041 // 12/18/97: Special version with show() member function 00042 // 12/12/97: "fully" tested with calc 00043 // 12/10/97: tests o.k. with calc. 00044 // 11/24/97: added additional versions of resize(); 00045 // 11/11/97: real_vector and complex_vector test o.k. with vcalc. 00046 // 11/10/97: Fixed maxindex(n) bug. real_vector tests o.k. with vcalc. 00047 // 11/10/97: Many previously void member functions now return an Lvalue. 00048 // 11/8/97: improved reallocate(). 00049 // 11/7/97: fixed a lingering bug in the copy constructor: it didn't set 00050 // data subset control on the target! 00051 // 11/4/97: added checks for v = v and v.copy(v), so these constructs 00052 // behave properly (oops!). 00053 // 11/3/97: New operator =, with an Rvalue RHS. Also made copy() faster. 00054 // Not fully tested yet. 00055 // 10/15/97: added many new member functions and math functions; fixed 00056 // to compile with CC 00057 // 10/6/97: added int_vector definitions; cleaned up some others 00058 // 9/25/97: renamed to vector.cc 00059 // 9/23/97: fully functional and tested real and complex vectors 00060 // 9/17/97: yet more revisions. NOT READY. 00061 // 9/15/97: major changes to functions. Tests o.k. 00062 // 8/15/97: fixed size when copy constructor has insufficient memory; 00063 // now refers to vectors.h vice nonlin2.h 00064 // 8/15/97: added handling of out-of-memory. 00065 // 8/12/97: added complex_vector fcns 00066 // 8/12/97: pulled definitions from nonlin2.h Tests o.k. 00067 00068 #include "vector.h" 00069 #include <iostream.h> 00070 #include <iomanip.h> 00071 00072 // Useful functions: 00073 00074 static inline int min(int a, int b) { return (a < b)? a : b; } 00075 static inline int max(int a, int b) { return (a > b)? a : b; } 00076 static inline int length(int a, int b) 00077 { int n = b - a + 1; return (n < 0)? 0 : n; } 00078 00079 // i/o formatting static variable 00080 00081 static string _out_separator(" "); 00082 00083 00084 // ******************************************************************** 00085 // real_vector definitions: 00086 00087 00088 // vector output: 00089 00090 ostream & operator << (ostream & s, const real_vector & v) 00091 { 00092 ios::streamsize w = s.width(); 00093 if (v.minindex() <= v.maxindex()) s << v[v.minindex()]; // v not empty 00094 for (int i = v.minindex() + 1; i <= v.maxindex(); ++i) 00095 s << _out_separator << setw(w) << v[i]; 00096 return s << setw(0); // just in case no output was generated 00097 } 00098 00099 real_vector & real_vector::show(ostream & s) 00100 { 00101 s << endl << *this << endl; 00102 return *this; 00103 } 00104 00105 real_vector & real_vector::show() 00106 { 00107 return show(cout); 00108 } 00109 00110 const real_vector & real_vector::show(ostream & s) const 00111 { 00112 s << endl << *this << endl; 00113 return *this; 00114 } 00115 00116 const real_vector & real_vector::show() const 00117 { 00118 return show(cout); 00119 } 00120 00121 string real_vector::out_separator() 00122 { return _out_separator; } 00123 00124 string real_vector::out_separator(const string & s) 00125 { string temp = _out_separator; _out_separator = s; return temp; } 00126 00127 string real_vector::out_separator(const char * const s) 00128 { string temp = _out_separator; _out_separator = s; return temp; } 00129 00130 string real_vector::out_separator(const char s) 00131 { string temp = _out_separator; _out_separator = s; return temp; } 00132 00133 //------------------------------------------------------------------------- 00134 // construct() do the real work of vector construction: 00135 00136 void real_vector::construct(const int n, const v_index_mode t) 00137 { 00138 internal_size = (n >= 0) ? n : 0; 00139 internal_mode = t; 00140 switch(t) { 00141 default: 00142 case Index_C: { 00143 if (internal_size) { // != 0: must allocate memory 00144 data = delete_pointer = new double[internal_size]; 00145 if (delete_pointer == 0) internal_size = 0; // out of memory 00146 } 00147 else { // must not allocate memory 00148 data = delete_pointer = 0; 00149 } 00150 minindexvalue = 0; maxindexvalue = internal_size - 1; 00151 break; 00152 } 00153 case Index_1: { 00154 if (internal_size) { // != 0: must allocate memory 00155 data = delete_pointer = new double[internal_size]; 00156 if (delete_pointer == 0) 00157 internal_size = 0; // out of memory 00158 else 00159 --data; // so data[1] is the first element 00160 } 00161 else { // must not allocate memory 00162 data = delete_pointer = 0; 00163 } 00164 minindexvalue = 1; maxindexvalue = internal_size; 00165 break; 00166 } 00167 case Index_S: { 00168 // must always try to allocate memory, even if size == 0: 00169 delete_pointer = new double[2*internal_size + 1]; 00170 if (delete_pointer == 0) { 00171 data = & trash; // out of memory, so send requests here 00172 internal_size = 0; 00173 maxindexvalue = -1; // this is the "out of memory" flag 00174 } 00175 else { // memory allocation succeeded 00176 data = delete_pointer + internal_size; //location of v[0] 00177 maxindexvalue = internal_size; 00178 } 00179 minindexvalue = -maxindexvalue; 00180 break; 00181 } 00182 } // switch 00183 } // construct(const int n, const v_index_mode t = Index_C) 00184 00185 //--------------------------------------------------------------------- 00186 // constfill() fill the vector with a constant: 00187 00188 void real_vector::constfill(const double f) 00189 { for (int i = minindex(); i <= maxindex(); ++i) data[i] = f; } 00190 00191 00192 //--------------------------------------------------------------------- 00193 // copy constructor: 00194 00195 real_vector::real_vector(const real_vector & v1) 00196 : size(internal_size), mode(internal_mode) 00197 { 00198 construct(v1.size, v1.mode); 00199 // the following loop will work even if alloc for v1 failed and 00200 // v1.mode == Index_S. In this case, the contents of trash will be 00201 // copied. 00202 for (int i = minindex(); i <= maxindex(); ++i) 00203 data[i] = v1[i]; 00204 if(v1.is_empty()) 00205 make_empty(); 00206 else 00207 maxindex(v1.maxindex()); 00208 } 00209 00210 //--------------------------------------------------------------------- 00211 // alias constructor: 00212 00213 real_vector::real_vector(double *const ptr, const int n, 00214 const v_index_mode t) 00215 : size(internal_size), mode(internal_mode) 00216 { 00217 data = ptr; 00218 delete_pointer = 0; // don't destroy memory on destruction 00219 internal_mode = t; 00220 if (n >= 0) { 00221 // n is a useful value (could hold 1 element if t = Index_S) 00222 internal_size = n; 00223 maxindexvalue = (mode == Index_C) ? (size - 1) : size; 00224 } 00225 else { 00226 // n isn't useful; no memory available at ptr 00227 internal_size = 0; 00228 maxindexvalue = (mode == Index_1) ? 0 : -1; 00229 } 00230 switch (mode) { // set minindexvalue 00231 case Index_C: { minindexvalue = 0; break; } 00232 case Index_1: { minindexvalue = 1; break; } 00233 case Index_S: { minindexvalue = -maxindexvalue; break; } 00234 } 00235 } 00236 00237 //------------------------------------------------------------------------- 00238 // reindex() change the index modes 00239 00240 real_vector & real_vector::reindex(const v_index_mode M) 00241 { 00242 // first check for do nothings: new mode same as old, or 00243 // vector is an alias 00244 if (M == mode) return *this; 00245 if (delete_pointer == 0 && data != 0 && data != &trash) return *this; 00246 00247 // If here, reindexing necessary 00248 00249 // calculate number of data elements 00250 int n = (mode == Index_S) ? 2*size + 1 : size; 00251 00252 // new Index_S needs an odd number of elements 00253 if (M == Index_S && (n>>1)<<1 == n) { // n even 00254 reallocate(size+1,mode); 00255 n = size; // the new size 00256 } 00257 00258 // now handle the no allocated data case: 00259 if (delete_pointer == 0) { reallocate(0,M); return *this; } 00260 00261 // set up new indexing: 00262 int ptr_offset; // offset into array for data[0] 00263 switch (M) { 00264 default: 00265 { return *this; } // unknown mode, so do nothing 00266 case Index_C: 00267 { ptr_offset = 0; break; } 00268 case Index_1: 00269 { ptr_offset = -1; break; } 00270 case Index_S: 00271 { ptr_offset = (n - 1)/2; break; } 00272 } // switch 00273 internal_size = (M == Index_S) ? ptr_offset : n; 00274 minindexvalue = -ptr_offset; 00275 maxindexvalue = minindexvalue + n - 1; 00276 data = delete_pointer + ptr_offset; 00277 internal_mode = M; 00278 00279 return *this; 00280 } 00281 00282 //--------------------------------------------------------------------- 00283 // change maxindex(), make_empty(): 00284 00285 int real_vector::maxindex(int n) 00286 { 00287 if (size == 0 && mode != Index_S) 00288 // can't change the maxindex if no data elements 00289 return maxindex(); 00290 else { 00291 switch (mode) { 00292 case Index_1: { 00293 if (n < 1) n = 1; 00294 maxindexvalue = (n > size) ? size : n; 00295 break; 00296 } 00297 case Index_S: { 00298 if (n < 0) n = 0; 00299 maxindexvalue = (n > size) ? size : n; 00300 minindexvalue = -maxindexvalue; 00301 break; 00302 } 00303 case Index_C: { 00304 if (n < 0) n = 0; 00305 maxindexvalue = (n >= size) ? (size - 1) : n; 00306 break; 00307 } 00308 default: 00309 ; // do nothing 00310 } //switch 00311 return maxindexvalue; 00312 } //else 00313 } 00314 00315 real_vector & real_vector::make_empty() 00316 { 00317 switch (mode) { 00318 case Index_C: 00319 maxindexvalue = -1; 00320 minindexvalue = 0; 00321 break; 00322 00323 case Index_1: 00324 maxindexvalue = 0; 00325 minindexvalue = 1; 00326 break; 00327 00328 case Index_S: 00329 maxindexvalue = -1; 00330 minindexvalue = 1; 00331 break; 00332 00333 } 00334 00335 return *this; 00336 } 00337 00338 //--------------------------------------------------------------------- 00339 // clean up unused elements: 00340 00341 real_vector & real_vector::clean() 00342 { 00343 int savemax = maxindex(); 00344 int savemin = minindex(); 00345 int i; 00346 maxindex(size); // make all memory visible 00347 for (i = savemax + 1; i <= maxindex(); ++i) data[i] = 0; 00348 for (i = savemin - 1; i >= minindex(); --i) data[i] = 0; 00349 maxindex(savemax); 00350 return *this; 00351 } 00352 00353 //--------------------------------------------------------------------- 00354 // shrink index range to ignore tiny values: 00355 00356 real_vector & real_vector::shrink(double s) 00357 { 00358 int i; // the index 00359 double sum; // accumulator of the sum of the magnitude squared's 00360 s *= s; // magnitude squared for s: our tolerance value 00361 00362 if (mode != Index_S) 00363 // Index_C and Index_1: just compare the sum at the positive indexes 00364 for (i = maxindexvalue, sum = 0; i > 0; --i) { 00365 sum += data[i]*data[i]; 00366 if (sum >= s) break; // found the limit 00367 } 00368 else { 00369 // Index_S must look at sum for negative indexes, too 00370 double nsum; // accumulate negative index sum 00371 for (i = maxindexvalue, nsum = sum = 0; i > 0; --i) { 00372 sum += data[i]*data[i]; 00373 nsum += data[-i]*data[-i]; 00374 if ((sum >= s)||(nsum >= s)) break; 00375 } 00376 } 00377 00378 maxindex(i); // set the new index and return 00379 return *this; 00380 } 00381 00382 //--------------------------------------------------------------------- 00383 // fill all elements, regardless of data subset control: 00384 00385 real_vector & real_vector::fillall(const double s) 00386 { 00387 int savemax = maxindexvalue; 00388 int savemin = minindexvalue; 00389 maximize(); 00390 constfill(s); 00391 maxindexvalue = savemax; minindexvalue = savemin; 00392 return *this; 00393 } 00394 00395 //--------------------------------------------------------------------- 00396 // copy data from another vector: 00397 00398 real_vector & real_vector::copy(const real_vector & v1) 00399 { 00400 // check for self copy: "v.copy(v)", and do something intelligent: 00401 if (data == v1.data) { clean(); return *this; } 00402 00403 // otherwise, not a self copy, so: 00404 maxindex(size); constfill(0); // maximize the index range and clear 00405 // now set data subset on the result: 00406 if(v1.is_empty()) 00407 make_empty(); 00408 else { 00409 maxindex(v1.maxindex()); 00410 // copy over the index range intersection: 00411 int minimum = max(minindexvalue, v1.minindex()); 00412 int maximum = min(maxindexvalue, v1.maxindex()); 00413 for (register int i = minimum; i <= maximum; ++i) 00414 data[i] = v1[i]; 00415 } 00416 return *this; 00417 } 00418 00419 //--------------------------------------------------------------------- 00420 // reallocate memory: 00421 00422 real_vector & real_vector::reallocate(const int n, const v_index_mode t) 00423 { 00424 // just return if reallocation is unnecessary: 00425 if ((size == n)&&(mode == t)) return *this; 00426 00427 // if we're here, we have to reallocate: 00428 real_vector old(data, size, mode); // alias the current vector 00429 double * save_delete_pointer = delete_pointer; 00430 int newmax; // will hold the new maxindexvalue 00431 newmax = (maxindexvalue < old.maxindex()) ? maxindexvalue : n ; 00432 00433 construct(n,t); 00434 copy(old); 00435 maxindex(newmax); 00436 delete [] save_delete_pointer; 00437 return *this; 00438 } 00439 00440 //--------------------------------------------------------------------- 00441 // resize: the ones which couldn't be defined in the header file 00442 00443 real_vector & real_vector::resize(const complex_vector & v) 00444 { 00445 int Size = (v.mode == Index_C) ? v.maxindex()+1: v.maxindex(); 00446 return reallocate(Size, v.mode); 00447 } 00448 00449 //--------------------------------------------------------------------- 00450 // basic assignment operator: 00451 00452 real_vector & real_vector::operator = (const real_vector & v1) 00453 { 00454 // check for self assignment: "v = v", and do something intelligent: 00455 if (data == v1.data) { clean(); return *this; } 00456 00457 // otherwise, not a self assignment, so: 00458 maximize(); 00459 if ((mode != v1.mode)||(maxindexvalue < v1.maxindex())) { 00460 // make the vector compatible with v1's data 00461 delete [] delete_pointer; 00462 int newsize = (v1.mode == Index_C) ? v1.maxindex()+1: v1.maxindex(); 00463 construct(newsize,v1.mode); 00464 } 00465 copy(v1); 00466 return *this; 00467 } 00468 00469 //--------------------------------------------------------------------- 00470 // other assignment operators (no memory reallocation for these): 00471 00472 real_vector & real_vector::operator += (const double s) 00473 { 00474 // make local pointers to the first and last elements: 00475 register double * d = data + minindexvalue; 00476 register double * limit = data + maxindexvalue; 00477 // use the pointer to the first element as the loop variable: 00478 while (d <= limit) *(d++) += s; 00479 return *this; 00480 } 00481 00482 real_vector & real_vector::operator -= (const double s) 00483 { 00484 register double * d = data + minindexvalue; 00485 register double * limit = data + maxindexvalue; 00486 while (d <= limit) *(d++) -= s; 00487 return *this; 00488 } 00489 00490 real_vector & real_vector::operator *= (const double s) 00491 { 00492 register double * d = data + minindexvalue; 00493 register double * limit = data + maxindexvalue; 00494 while (d <= limit) *(d++) *= s; 00495 return *this; 00496 } 00497 00498 real_vector & real_vector::operator /= (const double s) 00499 { 00500 register double * d = data + minindexvalue; 00501 register double * limit = data + maxindexvalue; 00502 while (d <= limit) *(d++) /= s; 00503 return *this; 00504 } 00505 00506 real_vector & real_vector::operator += (const real_vector & v1) 00507 { 00508 clean(); // ensure nonvalid elements are set to 0 00509 // increase the target's valid range if necessary: 00510 if (maxindexvalue < v1.maxindex()) maxindex(v1.maxindex()); 00511 // loop over the intersection of the vectors' valid ranges: 00512 int minimum = max(minindexvalue, v1.minindex()); 00513 int maximum = min(maxindexvalue, v1.maxindex()); 00514 for (register int i = minimum; i <= maximum; ++i) 00515 data[i] += v1[i]; 00516 return *this; 00517 } 00518 00519 real_vector & real_vector::operator -= (const real_vector & v1) 00520 { 00521 clean(); 00522 if (maxindexvalue < v1.maxindex()) maxindex(v1.maxindex()); 00523 int minimum = max(minindexvalue, v1.minindex()); 00524 int maximum = min(maxindexvalue, v1.maxindex()); 00525 for (register int i = minimum; i <= maximum; ++i) 00526 data[i] -= v1[i]; 00527 return *this; 00528 } 00529 00530 //--------------------------------------------------------------------- 00531 // other miscellaneous funtions: 00532 00533 real_vector & real_vector::real(const complex_vector & v) 00534 { 00535 resize(v); 00536 if(v.is_empty()) 00537 make_empty(); 00538 else { 00539 maxindex(v.maxindex()); 00540 int i; 00541 for (i = minindex(); i <= maxindex(); ++i) 00542 data[i] = v[i].real; 00543 } 00544 return *this; 00545 } 00546 00547 real_vector & real_vector::imaginary(const complex_vector & v) 00548 { 00549 resize(v); 00550 if(v.is_empty()) 00551 make_empty(); 00552 else { 00553 maxindex(v.maxindex()); 00554 int i; 00555 for (i = minindex(); i <= maxindex(); ++i) 00556 data[i] = v[i].imaginary; 00557 } 00558 return *this; 00559 } 00560 00561 int real_vector::findmax() const 00562 { 00563 if(maxindexvalue < minindexvalue) return 0; 00564 double norm; // magnitude squared 00565 double max; // max norm so far 00566 int index = minindexvalue; // index to return 00567 00568 norm = data[minindexvalue]; max = norm * norm; // initialize 00569 for (int i = minindexvalue + 1; i <= maxindexvalue; ++i) { 00570 norm = data[i]; norm *= norm; 00571 if ( norm > max ) { 00572 max = norm; index = i; 00573 } 00574 } 00575 return index; 00576 } 00577 00578 real_vector & real_vector::apply(double (*f)(double)) 00579 { 00580 // make local pointers to the first and last elements: 00581 register double * d = data + minindexvalue; 00582 register double * limit = data + maxindexvalue; 00583 // use the pointer to the first element as the loop variable: 00584 for ( ; d <= limit; ++d) *d = f(*d); 00585 return *this; 00586 } 00587 00588 real_vector & real_vector::apply(double (*f)(const double &)) 00589 { 00590 // make local pointers to the first and last elements: 00591 register double * d = data + minindexvalue; 00592 register double * limit = data + maxindexvalue; 00593 // use the pointer to the first element as the loop variable: 00594 for ( ; d <= limit; ++d) *d = f(*d); 00595 return *this; 00596 } 00597 00598 real_vector & real_vector::apply(double (*f)(double, int)) 00599 { 00600 register int i = minindexvalue; 00601 register double * d = data; 00602 register int limit = maxindexvalue; 00603 for ( d += i; i <= limit; ++i, ++d) *d = f(*d, i); 00604 return *this; 00605 } 00606 00607 real_vector & real_vector::apply(double (*f)(const double &, int)) 00608 { 00609 register int i = minindexvalue; 00610 register double * d = data; 00611 register int limit = maxindexvalue; 00612 for ( d += i; i <= limit; ++i, ++d) *d = f(*d, i); 00613 return *this; 00614 } 00615 00616 //--------------------------------------------------------------------- 00617 // STL compatibility: 00618 00619 void real_vector::reserve(int n) 00620 { 00621 if(n <= size) return; 00622 bool e = empty(); int m = maxindexvalue; 00623 reallocate(n); 00624 if (e) 00625 make_empty(); 00626 else 00627 maxindex(m); 00628 } 00629 00630 void real_vector::push_back(double s) 00631 { 00632 // adjust memory allocation, if necessary 00633 int i = maxindex()+1; 00634 if (maxindex(i) != i) { 00635 // then incrementing maxindex didn't work; must reallocate 00636 reallocate(2*(size+1)); // grow size by a factor of 2 00637 maxindex(i); 00638 } 00639 data[i] = s; 00640 } 00641 00642 void real_vector::pop_back() 00643 { 00644 if(empty()) return; 00645 int i = maxindex(maxindex()-1); 00646 if (maxindex() == i) { 00647 // then attempting to decrement maxindex didn't work; 00648 // vector is now empty 00649 make_empty(); 00650 } 00651 } 00652 00653 // end of real_vector definitions 00654 00655 // ******************************************************************** 00656 // complex_vector definitions: 00657 00658 00659 // vector output: 00660 00661 ostream & operator << (ostream & s, const complex_vector & v) 00662 { 00663 ios::streamsize w = s.width(); 00664 if (v.minindex() <= v.maxindex()) s << v[v.minindex()]; // v not empty 00665 for (int i = v.minindex() + 1; i <= v.maxindex(); ++i) 00666 s << _out_separator << setw(w) << v[i]; 00667 return s << setw(0); // just in case no output was generated 00668 } 00669 00670 complex_vector & complex_vector::show(ostream & s) 00671 { 00672 s << endl << *this << endl; 00673 return *this; 00674 } 00675 00676 complex_vector & complex_vector::show() 00677 { 00678 return show(cout); 00679 } 00680 00681 const complex_vector & complex_vector::show(ostream & s) const 00682 { 00683 s << endl << *this << endl; 00684 return *this; 00685 } 00686 00687 const complex_vector & complex_vector::show() const 00688 { 00689 return show(cout); 00690 } 00691 00692 string complex_vector::out_separator() 00693 { return _out_separator; } 00694 00695 string complex_vector::out_separator(const string & s) 00696 { string temp = _out_separator; _out_separator = s; return temp; } 00697 00698 string complex_vector::out_separator(const char * const s) 00699 { string temp = _out_separator; _out_separator = s; return temp; } 00700 00701 string complex_vector::out_separator(const char s) 00702 { string temp = _out_separator; _out_separator = s; return temp; } 00703 00704 //------------------------------------------------------------------------- 00705 // construct() do the real work of vector construction: 00706 00707 void complex_vector::construct(const int n, const v_index_mode t) 00708 { 00709 internal_size = (n >= 0) ? n : 0; 00710 internal_mode = t; 00711 switch(t) { 00712 default: 00713 case Index_C: { 00714 if (internal_size) { // != 0: must allocate memory 00715 data = delete_pointer = new Complex[internal_size]; 00716 if (delete_pointer == 0) internal_size = 0; // out of memory 00717 } 00718 else { // must not allocate memory 00719 data = delete_pointer = 0; 00720 } 00721 minindexvalue = 0; maxindexvalue = internal_size - 1; 00722 break; 00723 } 00724 case Index_1: { 00725 if (internal_size) { // != 0: must allocate memory 00726 data = delete_pointer = new Complex[internal_size]; 00727 if (delete_pointer == 0) 00728 internal_size = 0; // out of memory 00729 else 00730 --data; // so data[1] is the first element 00731 } 00732 else { // must not allocate memory 00733 data = delete_pointer = 0; 00734 } 00735 minindexvalue = 1; maxindexvalue = internal_size; 00736 break; 00737 } 00738 case Index_S: { 00739 // must always try to allocate memory, even if size == 0: 00740 delete_pointer = new Complex[2*internal_size + 1]; 00741 if (delete_pointer == 0) { 00742 data = & trash; // out of memory, so send requests here 00743 internal_size = 0; 00744 maxindexvalue = -1; // this is the "out of memory" flag 00745 } 00746 else { // memory allocation succeeded 00747 data = delete_pointer + internal_size; //location of v[0] 00748 maxindexvalue = internal_size; 00749 } 00750 minindexvalue = -maxindexvalue; 00751 break; 00752 } 00753 } // switch 00754 } // construct(const int n, const v_index_mode t = Index_C) 00755 00756 //--------------------------------------------------------------------- 00757 // constfill() fill the vector with a constant: 00758 00759 void complex_vector::constfill(const Complex f) 00760 { for (int i = minindex(); i <= maxindex(); ++i) data[i] = f; } 00761 00762 //--------------------------------------------------------------------- 00763 // copy constructor: 00764 00765 complex_vector::complex_vector(const complex_vector & v1) 00766 : size(internal_size), mode(internal_mode) 00767 { 00768 construct(v1.size, v1.mode); 00769 // the following loop will work even if alloc for v1 failed and 00770 // v1.mode == Index_S. In this case, the contents of trash will be 00771 // copied. 00772 for (int i = minindex(); i <= maxindex(); ++i) 00773 data[i] = v1[i]; 00774 if(v1.is_empty()) 00775 make_empty(); 00776 else 00777 maxindex(v1.maxindex()); 00778 } 00779 00780 complex_vector::complex_vector(const real_vector & v1) 00781 : size(internal_size), mode(internal_mode) 00782 { 00783 construct(v1.size, v1.mode); 00784 for (int i = minindex(); i <= maxindex(); ++i) 00785 data[i] = v1[i]; 00786 if(v1.is_empty()) 00787 make_empty(); 00788 else 00789 maxindex(v1.maxindex()); 00790 } 00791 00792 //--------------------------------------------------------------------- 00793 // alias constructor: 00794 00795 complex_vector::complex_vector(Complex *const ptr, const int n, 00796 const v_index_mode t) 00797 : size(internal_size), mode(internal_mode) 00798 { 00799 data = ptr; 00800 delete_pointer = 0; // don't destroy memory on destruction 00801 internal_mode = t; 00802 if (n >= 0) { 00803 // n is a useful value (could hold 1 element if t = Index_S) 00804 internal_size = n; 00805 maxindexvalue = (mode == Index_C) ? (size - 1) : size; 00806 } 00807 else { 00808 // n isn't useful; no memory available at ptr 00809 internal_size = 0; 00810 maxindexvalue = (mode == Index_1) ? 0 : -1; 00811 } 00812 switch (mode) { // set minindexvalue 00813 case Index_C: { minindexvalue = 0; break; } 00814 case Index_1: { minindexvalue = 1; break; } 00815 case Index_S: { minindexvalue = -maxindexvalue; break; } 00816 } 00817 } 00818 00819 //------------------------------------------------------------------------- 00820 // reindex() change the index modes 00821 00822 complex_vector & complex_vector::reindex(const v_index_mode M) 00823 { 00824 // first check for do nothings: new mode same as old, or 00825 // vector is an alias 00826 if (M == mode) return *this; 00827 if (delete_pointer == 0 && data != 0 && data != &trash) return *this; 00828 00829 // If here, reindexing necessary 00830 00831 // calculate number of data elements 00832 int n = (mode == Index_S) ? 2*size + 1 : size; 00833 00834 // new Index_S needs an odd number of elements 00835 if (M == Index_S && (n>>1)<<1 == n) { // n even 00836 reallocate(size+1,mode); 00837 n = size; // the new size 00838 } 00839 00840 // now handle the no allocated data case: 00841 if (delete_pointer == 0) { reallocate(0,M); return *this; } 00842 00843 // set up new indexing: 00844 int ptr_offset; // offset into array for data[0] 00845 switch (M) { 00846 default: 00847 { return *this; } // unknown mode, so do nothing 00848 case Index_C: 00849 { ptr_offset = 0; break; } 00850 case Index_1: 00851 { ptr_offset = -1; break; } 00852 case Index_S: 00853 { ptr_offset = (n - 1)/2; break; } 00854 } // switch 00855 internal_size = (M == Index_S) ? ptr_offset : n; 00856 minindexvalue = -ptr_offset; 00857 maxindexvalue = minindexvalue + n - 1; 00858 data = delete_pointer + ptr_offset; 00859 internal_mode = M; 00860 00861 return *this; 00862 } 00863 00864 //--------------------------------------------------------------------- 00865 // change maxindex(), make_empty(): 00866 00867 int complex_vector::maxindex(int n) 00868 { 00869 if (size == 0 && mode != Index_S) 00870 // can't change the maxindex if no data elements 00871 return maxindex(); 00872 else { 00873 switch (mode) { 00874 case Index_1: { 00875 if (n < 1) n = 1; 00876 maxindexvalue = (n > size) ? size : n; 00877 break; 00878 } 00879 case Index_S: { 00880 if (n < 0) n = 0; 00881 maxindexvalue = (n > size) ? size : n; 00882 minindexvalue = -maxindexvalue; 00883 break; 00884 } 00885 case Index_C: { 00886 if (n < 0) n = 0; 00887 maxindexvalue = (n >= size) ? (size - 1) : n; 00888 break; 00889 } 00890 default: 00891 ; // do nothing 00892 } //switch 00893 return maxindexvalue; 00894 } //else 00895 } 00896 00897 complex_vector & complex_vector::make_empty() 00898 { 00899 switch (mode) { 00900 case Index_C: 00901 maxindexvalue = -1; 00902 minindexvalue = 0; 00903 break; 00904 00905 case Index_1: 00906 maxindexvalue = 0; 00907 minindexvalue = 1; 00908 break; 00909 00910 case Index_S: 00911 maxindexvalue = -1; 00912 minindexvalue = 1; 00913 break; 00914 00915 } 00916 00917 return *this; 00918 } 00919 00920 //--------------------------------------------------------------------- 00921 // clean up unused elements: 00922 00923 complex_vector & complex_vector::clean() 00924 { 00925 int savemax = maxindex(); 00926 int savemin = minindex(); 00927 int i; 00928 maxindex(size); // make all memory visible 00929 for (i = savemax + 1; i <= maxindex(); ++i) data[i] = 0; 00930 for (i = savemin - 1; i >= minindex(); --i) data[i] = 0; 00931 maxindex(savemax); 00932 return *this; 00933 } 00934 00935 //--------------------------------------------------------------------- 00936 // shrink index range to ignore tiny values: 00937 00938 complex_vector & complex_vector::shrink(Complex s) 00939 { 00940 int i; // the index 00941 double sum; // accumulator of the sum of the magnitude squared's 00942 double ss = norm(s); // magnitude squared for s: our tolerance value 00943 00944 if (mode != Index_S) 00945 // Index_C and Index_1: just compare the sum at the positive indexes 00946 for (i = maxindexvalue, sum = 0; i > 0; --i) { 00947 sum += norm(data[i]); 00948 if (sum >= ss) break; // found the limit 00949 } 00950 else { 00951 // Index_S must look at sum for negative indexes, too 00952 double nsum; // accumulate negative index sum 00953 for (i = maxindexvalue, nsum = sum = 0; i > 0; --i) { 00954 sum += norm(data[i]); 00955 nsum += norm(data[-i]); 00956 if ((sum >= ss)||(nsum >= ss)) break; 00957 } 00958 } 00959 00960 maxindex(i); // set the new index and return 00961 return *this; 00962 } 00963 00964 //--------------------------------------------------------------------- 00965 // fill all elements, regardless of data subset control: 00966 00967 complex_vector & complex_vector::fillall(const Complex s) 00968 { 00969 int savemax = maxindexvalue; 00970 int savemin = minindexvalue; 00971 maximize(); 00972 constfill(s); 00973 maxindexvalue = savemax; minindexvalue = savemin; 00974 return *this; 00975 } 00976 00977 //--------------------------------------------------------------------- 00978 // copy data from another vector: 00979 00980 complex_vector & complex_vector::copy(const complex_vector & v1) 00981 { 00982 // check for self copy: "v.copy(v)", and do something intelligent: 00983 if (data == v1.data) { clean(); return *this; } 00984 00985 // otherwise, not a self copy, so: 00986 maxindex(size); constfill(0); // maximize the index range and clear 00987 // now set data subset on the result: 00988 if(v1.is_empty()) 00989 make_empty(); 00990 else { 00991 maxindex(v1.maxindex()); 00992 // copy over the index range intersection: 00993 int minimum = max(minindexvalue, v1.minindex()); 00994 int maximum = min(maxindexvalue, v1.maxindex()); 00995 for (register int i = minimum; i <= maximum; ++i) 00996 data[i] = v1[i]; 00997 } 00998 return *this; 00999 } 01000 01001 complex_vector & complex_vector::copy(const real_vector & v1) 01002 { 01003 maxindex(size); constfill(0); // maximize the index range and clear 01004 // now set data subset on the result: 01005 if(v1.is_empty()) 01006 make_empty(); 01007 else { 01008 maxindex(v1.maxindex()); 01009 // copy over the index range intersection: 01010 int minimum = max(minindexvalue, v1.minindex()); 01011 int maximum = min(maxindexvalue, v1.maxindex()); 01012 for (register int i = minimum; i <= maximum; ++i) 01013 data[i] = v1[i]; 01014 } 01015 return *this; 01016 } 01017 01018 //--------------------------------------------------------------------- 01019 // reallocate memory: 01020 01021 complex_vector & complex_vector::reallocate(const int n, const v_index_mode t) 01022 { 01023 // just return if reallocation is unnecessary: 01024 if ((size == n)&&(mode == t)) return *this; 01025 01026 // if we're here, we have to reallocate: 01027 complex_vector old(data, size, mode); // alias the current vector 01028 Complex * save_delete_pointer = delete_pointer; 01029 int newmax; // will hold the new maxindexvalue 01030 newmax = (maxindexvalue < old.maxindex()) ? maxindexvalue : n ; 01031 01032 construct(n,t); 01033 copy(old); 01034 maxindex(newmax); 01035 delete [] save_delete_pointer; 01036 return *this; 01037 } 01038 01039 //--------------------------------------------------------------------- 01040 // assignment operator: 01041 01042 complex_vector & complex_vector::operator = (const complex_vector & v1) 01043 { 01044 // check for self assignment: "v = v", and do something intelligent: 01045 if (data == v1.data) { clean(); return *this; } 01046 01047 // otherwise, not a self assignment, so: 01048 maximize(); 01049 if ((mode != v1.mode)||(maxindexvalue < v1.maxindex())) { 01050 // make the vector compatible with v1's data 01051 delete [] delete_pointer; 01052 int newsize = (v1.mode == Index_C) ? v1.maxindex()+1: v1.maxindex(); 01053 construct(newsize,v1.mode); 01054 } 01055 copy(v1); 01056 return *this; 01057 } 01058 01059 complex_vector & complex_vector::operator = (const real_vector & v1) 01060 { 01061 maximize(); 01062 if ((mode != v1.mode)||(maxindexvalue < v1.maxindex())) { 01063 // make the vector compatible with v1's data 01064 delete [] delete_pointer; 01065 int newsize = (v1.mode == Index_C) ? v1.maxindex()+1: v1.maxindex(); 01066 construct(newsize,v1.mode); 01067 } 01068 copy(v1); 01069 return *this; 01070 } 01071 01072 //--------------------------------------------------------------------- 01073 // other assignment operators (no memory reallocation for these): 01074 01075 complex_vector & complex_vector::operator += (const Complex s) 01076 { 01077 // make local pointers to the first and last elements: 01078 register Complex * d = data + minindexvalue; 01079 register Complex * limit = data + maxindexvalue; 01080 // use the pointer to the first element as the loop variable: 01081 while (d <= limit) *(d++) += s; 01082 return *this; 01083 } 01084 01085 complex_vector & complex_vector::operator -= (const Complex s) 01086 { 01087 register Complex * d = data + minindexvalue; 01088 register Complex * limit = data + maxindexvalue; 01089 while (d <= limit) *(d++) -= s; 01090 return *this; 01091 } 01092 01093 complex_vector & complex_vector::operator *= (const Complex s) 01094 { 01095 register Complex * d = data + minindexvalue; 01096 register Complex * limit = data + maxindexvalue; 01097 while (d <= limit) *(d++) *= s; 01098 return *this; 01099 } 01100 01101 complex_vector & complex_vector::operator /= (const Complex s) 01102 { 01103 register Complex * d = data + minindexvalue; 01104 register Complex * limit = data + maxindexvalue; 01105 while (d <= limit) *(d++) /= s; 01106 return *this; 01107 } 01108 01109 complex_vector & complex_vector::operator += (const complex_vector & v1) 01110 { 01111 clean(); // ensure nonvalid elements are set to 0 01112 // increase the target's valid range if necessary: 01113 if (maxindexvalue < v1.maxindex()) maxindex(v1.maxindex()); 01114 // loop over the intersection of the vectors' valid ranges: 01115 int minimum = max(minindexvalue, v1.minindex()); 01116 int maximum = min(maxindexvalue, v1.maxindex()); 01117 for (register int i = minimum; i <= maximum; ++i) 01118 data[i] += v1[i]; 01119 return *this; 01120 } 01121 01122 complex_vector & complex_vector::operator -= (const complex_vector & v1) 01123 { 01124 clean(); 01125 if (maxindexvalue < v1.maxindex()) maxindex(v1.maxindex()); 01126 int minimum = max(minindexvalue, v1.minindex()); 01127 int maximum = min(maxindexvalue, v1.maxindex()); 01128 for (register int i = minimum; i <= maximum; ++i) 01129 data[i] -= v1[i]; 01130 return *this; 01131 } 01132 01133 complex_vector & complex_vector::operator += (const real_vector & v1) 01134 { 01135 clean(); // ensure nonvalid elements are set to 0 01136 // increase the target's valid range if necessary: 01137 if (maxindexvalue < v1.maxindex()) maxindex(v1.maxindex()); 01138 // loop over the intersection of the vectors' valid ranges: 01139 int minimum = max(minindexvalue, v1.minindex()); 01140 int maximum = min(maxindexvalue, v1.maxindex()); 01141 for (register int i = minimum; i <= maximum; ++i) 01142 data[i].real += v1[i]; 01143 return *this; 01144 } 01145 01146 complex_vector & complex_vector::operator -= (const real_vector & v1) 01147 { 01148 clean(); 01149 if (maxindexvalue < v1.maxindex()) maxindex(v1.maxindex()); 01150 int minimum = max(minindexvalue, v1.minindex()); 01151 int maximum = min(maxindexvalue, v1.maxindex()); 01152 for (register int i = minimum; i <= maximum; ++i) 01153 data[i].real -= v1[i]; 01154 return *this; 01155 } 01156 01157 //--------------------------------------------------------------------- 01158 // other miscellaneous funtions: 01159 01160 complex_vector & complex_vector::real(const complex_vector & v) 01161 { 01162 if (data != v.data) { // only resize if v is not this or an alias 01163 resize(v); 01164 if(v.is_empty()) 01165 make_empty(); 01166 else 01167 maxindex(v.maxindex()); 01168 } 01169 int i; 01170 for (i = minindex(); i <= maxindex(); ++i) 01171 data[i] = v[i].real; 01172 return *this; 01173 } 01174 01175 complex_vector & complex_vector::imaginary(const complex_vector & v) 01176 { 01177 if (data != v.data) { // only resize if v is not this or an alias 01178 resize(v); 01179 if(v.is_empty()) 01180 make_empty(); 01181 else 01182 maxindex(v.maxindex()); 01183 } 01184 int i; 01185 for (i = minindex(); i <= maxindex(); ++i) 01186 data[i] = v[i].imaginary; 01187 return *this; 01188 } 01189 01190 int complex_vector::findmax() const 01191 { 01192 if(maxindexvalue < minindexvalue) return 0; 01193 double mag; // magnitude squared 01194 double max; // max mag so far 01195 int index = minindexvalue; // index to return 01196 01197 max = norm(data[minindexvalue]); // initialize 01198 for (int i = minindexvalue + 1; i <= maxindexvalue; ++i) { 01199 mag = norm(data[i]); 01200 if ( mag > max ) { 01201 max = mag; index = i; 01202 } 01203 } 01204 return index; 01205 } 01206 01207 complex_vector & complex_vector::apply(Complex (*f)(Complex)) 01208 { 01209 // make local pointers to the first and last elements: 01210 register Complex * d = data + minindexvalue; 01211 register Complex * limit = data + maxindexvalue; 01212 // use the pointer to the first element as the loop variable: 01213 for ( ; d <= limit; ++d) *d = f(*d); 01214 return *this; 01215 } 01216 01217 complex_vector & complex_vector::apply(Complex (*f)(const Complex &)) 01218 { 01219 // make local pointers to the first and last elements: 01220 register Complex * d = data + minindexvalue; 01221 register Complex * limit = data + maxindexvalue; 01222 // use the pointer to the first element as the loop variable: 01223 for ( ; d <= limit; ++d) *d = f(*d); 01224 return *this; 01225 } 01226 01227 complex_vector & complex_vector::apply(Complex (*f)(Complex, int)) 01228 { 01229 register int i = minindexvalue; 01230 register Complex * d = data; 01231 register int limit = maxindexvalue; 01232 for ( d += i; i <= limit; ++i, ++d) *d = f(*d, i); 01233 return *this; 01234 } 01235 01236 complex_vector & complex_vector::apply(Complex (*f)(const Complex &, int)) 01237 { 01238 register int i = minindexvalue; 01239 register Complex * d = data; 01240 register int limit = maxindexvalue; 01241 for ( d += i; i <= limit; ++i, ++d) *d = f(*d, i); 01242 return *this; 01243 } 01244 01245 //--------------------------------------------------------------------- 01246 // STL compatibility: 01247 01248 void complex_vector::reserve(int n) 01249 { 01250 if(n <= size) return; 01251 bool e = empty(); int m = maxindexvalue; 01252 reallocate(n); 01253 if (e) 01254 make_empty(); 01255 else 01256 maxindex(m); 01257 } 01258 01259 void complex_vector::push_back(Complex s) 01260 { 01261 // adjust memory allocation, if necessary 01262 int i = maxindex()+1; 01263 if (maxindex(i) != i) { 01264 // then incrementing maxindex didn't work; must reallocate 01265 reallocate(2*(size+1)); // grow size by a factor of 2 01266 maxindex(i); 01267 } 01268 data[i] = s; 01269 } 01270 01271 void complex_vector::pop_back() 01272 { 01273 if(empty()) return; 01274 int i = maxindex(maxindex()-1); 01275 if (maxindex() == i) { 01276 // then attempting to decrement maxindex didn't work; 01277 // vector is now empty 01278 make_empty(); 01279 } 01280 } 01281 01282 // end of complex_vector definitions
Please direct comments and corrections to
supermix@submm.caltech.edu
Go to the supermix home page
Generated by
1.2.7