00001
00002
00003
00004
00005
00006
00007
00008 #ifndef IMPALGEBRA_MULTI_ARRAY_H
00009 #define IMPALGEBRA_MULTI_ARRAY_H
00010
00011 #include "algebra_config.h"
00012 #include "endian.h"
00013 #include "IMP/base_types.h"
00014 #include "IMP/exception.h"
00015 #include "IMP/random.h"
00016 #include "internal/output_helpers.h"
00017 #include "IMP/algebra/utility.h"
00018 #include "IMP/algebra/endian.h"
00019 #include "IMP/algebra/internal/multi_array_helpers.h"
00020 #include "IMP/algebra/VectorD.h"
00021 #include <ctime>
00022 #include "boost/version.hpp"
00023
00024 IMPALGEBRA_BEGIN_NAMESPACE
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 template<typename T, int D>
00037 class MultiArray
00038 #ifndef SWIG
00039 : public boost::multi_array<T, D>
00040 #endif
00041 {
00042 public:
00043 typedef boost::multi_array_types::index index;
00044 typedef boost::multi_array_types::size_type size_type;
00045
00046
00047 typedef boost::multi_array<T, D> BMA;
00048 typedef MultiArray<T, D> This;
00049
00050 inline bool almost_equal(const double a, const double b,
00051 const double epsilon)
00052 {
00053 return (std::abs(a-b) < epsilon);
00054 }
00055 public:
00056
00057 MultiArray() : BMA() {}
00058
00059
00060
00061 int get_size(const int dim) const {
00062 return this->shape()[dim];
00063 }
00064
00065
00066
00067 int get_start(const int dim) const {
00068 return this->index_bases()[dim];
00069 }
00070
00071
00072
00073 void set_start(const int dim,const int value) {
00074 std::vector<typename boost::multi_array_types::index> idx(D);
00075 for (unsigned int i = 0;i < D;i++) {
00076 idx[i] = this->index_bases()[i];
00077 }
00078 idx[dim] = value;
00079 this->reindex(idx);
00080 }
00081
00082
00083
00084
00085
00086
00087 template<typename T1>
00088 void set_start(const T1& v) {
00089 this->reindex(v);
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 void centered_start() {
00103 std::vector<int> idx(D);
00104 for (unsigned int i = 0;i < D;i++) {
00105 idx[i] =(-1) * (int)this->shape()[i]/2;
00106 }
00107 this->reindex(idx);
00108 }
00109
00110
00111
00112 int get_finish(const int dim) const {
00113 return (this->index_bases()[dim] + this->shape()[dim] - 1);
00114 }
00115
00116
00117 bool is_void() const {
00118 for (index i = 0;i < D;i++) {
00119 if ((index)get_size(i) != 0) {
00120 return false;
00121 }
00122 }
00123 return true;
00124 }
00125
00126
00127 void init_zeros() {
00128 for (unsigned long i=0;i<this->num_elements() ;i++) {
00129 this->data()[i] = 0;
00130 }
00131 }
00132
00133
00134 void fill_with_value(T val=0) {
00135 for (unsigned long i=0;i<this->num_elements() ;i++) {
00136 this->data()[i] = val;
00137 }
00138 }
00139
00140
00141
00142
00143
00144
00145 void copy(This &v) {
00146 for (unsigned long i=0;i<this->num_elements() ;i++) {
00147 this->data()[i] = v.data()[i];
00148 }
00149 }
00150
00151
00152 template<typename U>
00153 void copy_with_casting(MultiArray<U, D> &v) {
00154 for (unsigned long i=0;i<this->num_elements() ;i++) {
00155 this->data()[i] = (T)v.data()[i];
00156 }
00157 }
00158
00159
00160
00161
00162
00163 template<typename T1>
00164 bool is_logical_element(T1 &v) const {
00165 for (unsigned int i = 0;i < D;i++) {
00166 if(v[i]<this->get_start(i) || this->get_finish(i)<v[i]) {
00167 return false;
00168 }
00169 }
00170 return true;
00171 }
00172
00173
00174
00175
00176
00177 template<typename T1>
00178 bool is_physical_element(T1 &v) const {
00179 for (unsigned int i = 0;i < D;i++) {
00180 if(v[i]<0 || (this->get_size(i)-1)<v[i]) {
00181 return false;
00182 }
00183 }
00184 return true;
00185 }
00186
00187
00188 bool first_element() const {
00189 std::vector<index> idx(D);
00190 for (unsigned int i = 0;i < D;i++) {
00191 idx[i] = this->index_bases()[i];
00192 }
00193 return (*this)(idx);
00194 }
00195
00196
00197 #ifndef SWIG
00198
00199
00200 This operator+(const This& v) const {
00201 This result(v);
00202 internal::operate_arrays(*this, v, result, '+');
00203 return result;
00204 }
00205
00206
00207 This operator-(const This& v) const {
00208 This result(v);
00209 internal::operate_arrays(*this, v, result, '-');
00210 return result;
00211 }
00212
00213
00214 This operator*(const This& v) const {
00215 This result(v);
00216 internal::operate_arrays(*this, v, result, '*');
00217 return result;
00218 }
00219
00220
00221 This operator/(const This& v) const {
00222 This result(v);
00223 internal::operate_arrays(*this, v, result, '/');
00224 return result;
00225 }
00226
00227
00228 void operator+=(const This& v) const {
00229 internal::operate_arrays(*this, v, *this, '+');
00230 }
00231
00232
00233 void operator-=(const This& v) const {
00234 internal::operate_arrays(*this, v, *this, '-');
00235 }
00236
00237
00238 void operator*=(const This& v) const {
00239 internal::operate_arrays(*this, v, *this, '*');
00240 }
00241
00242
00243 void operator/=(const This& v) const {
00244 internal::operate_arrays(*this, v, *this, '/');
00245 }
00246
00247
00248 This operator+(const T& v) const {
00249 This result(v);
00250 internal::operate_array_and_scalar(*this, v, result, '+');
00251 return result;
00252 }
00253
00254
00255 This operator-(const T& v) const {
00256 This result(v);
00257 internal::operate_array_and_scalar(*this, v, result, '-');
00258 return result;
00259 }
00260
00261
00262 This operator*(const T& v) const {
00263 This result(v);
00264 internal::operate_array_and_scalar(*this, v, result, '*');
00265 return result;
00266 }
00267
00268
00269
00270 This operator/(const T& v) const {
00271 This result(v);
00272 internal::operate_array_and_scalar(*this, v, result, '/');
00273 return result;
00274 }
00275
00276
00277 void operator+=(const T& v) const {
00278 internal::operate_array_and_scalar(*this, v, *this, '+');
00279 }
00280
00281
00282 void operator-=(const T& v) const {
00283 internal::operate_array_and_scalar(*this, v, *this, '-');
00284 }
00285
00286
00287 void operator*=(const T& v) const {
00288 internal::operate_array_and_scalar(*this, v, *this, '*');
00289 }
00290
00291
00292 void operator/=(const T& v) const {
00293 internal::operate_array_and_scalar(*this, v, *this, '/');
00294 }
00295 #endif
00296
00297
00298
00299
00300
00301
00302
00303 void print_shape(std::ostream& out = std::cout) const {
00304 out << "Dimensions: " << D << std::endl;
00305 out << "Size and range of each of the dimensions: " << std::endl;
00306 for (index i = 0;i < D;i++) {
00307 out << "Size: " << get_size(i) << " range: "
00308 << get_start(i) << " .. " << get_finish(i) << std::endl;
00309 }
00310 }
00311
00312
00313
00314
00315
00316 template <typename T1>
00317 bool same_shape(const MultiArray<T1, D>& b) const {
00318 for (index i = 0;i < D;i++) {
00319 if (get_size(i) != b.get_size(i) || get_start(i) != b.get_start(i)) {
00320 return false;
00321 }
00322 }
00323 return true;
00324 }
00325
00326
00327
00328
00329
00330
00331 template <typename T1>
00332 bool same_size(const MultiArray<T1, D>& b) const {
00333 for (index i = 0;i < D;i++) {
00334 if (get_size(i) != b.get_size(i)) { return false; }
00335 }
00336 return true;
00337 }
00338
00339
00340
00341
00342
00343 template <typename T1>
00344 bool same_start(const MultiArray<T1, D>& b) const {
00345 for (index i = 0;i < D;i++) {
00346 if (get_start(i) != b.get_start(i)) {return false;}
00347 }
00348 return true;
00349 }
00350
00351
00352 T compute_max() const {
00353 T maxval = first_element();
00354 for(unsigned long i = 0; i < this->num_elements();i++) {
00355 if(this->data()[i] > maxval) {
00356 maxval = this->data()[i];
00357 }
00358 }
00359 return maxval;
00360 }
00361
00362
00363
00364
00365
00366 template<typename T1>
00367 T compute_max(T1& max_idx) const {
00368 std::vector<index> idx(D);
00369 T maxval = first_element();
00370 while (internal::roll_inds(idx, this->shape(),this->index_bases())) {
00371 if ((*this)(idx) > maxval) {
00372 maxval = (*this)(idx);
00373 for(int i=0;i<D;i++) {
00374 max_idx[i]=idx[i];
00375 }
00376 }
00377 }
00378 return maxval;
00379 }
00380
00381
00382 T compute_min() const {
00383 T minval = first_element();
00384 for(unsigned long i = 0; i < this->num_elements();i++) {
00385 if(this->data()[i] < minval) { minval = this->data()[i]; }
00386 }
00387 return minval;
00388 }
00389
00390
00391
00392
00393
00394 template<typename T1>
00395 T compute_min(T1& min_idx) const {
00396 std::vector<index> idx(D);
00397 T minval = first_element();
00398 while (internal::roll_inds(idx, this->shape(),this->index_bases())) {
00399 if ((*this)(idx) < minval) {
00400 minval = (*this)(idx);
00401 for(int i=0;i<D;i++) { min_idx[i]=idx[i]; }
00402 }
00403 }
00404 return minval;
00405 }
00406
00407
00408
00409
00410
00411
00412
00413 double compute_avg() const {
00414 if (this->num_elements() == 0) { return 0; }
00415 double avg = 0;
00416 for (unsigned long i=0;i<this->num_elements() ;i++) {
00417 avg += static_cast<double>(this->data()[i]);
00418 }
00419 return avg / (this->num_elements());
00420 }
00421
00422
00423 double compute_stddev() const {
00424 size_type n_elem = this->num_elements();
00425 if (n_elem <= 1) {
00426 return 0;
00427 }
00428 double avg = 0, stddev = 0,val;
00429 for (unsigned long i=0;i<this->num_elements() ;i++) {
00430 val = static_cast<double>(this->data()[i]);
00431 avg += val;
00432 stddev += val*val;
00433 }
00434 avg /= n_elem;
00435 stddev = stddev / n_elem - avg * avg;
00436 stddev *= n_elem / (n_elem - 1);
00437
00438 stddev = sqrt(static_cast<double>(std::abs(stddev)));
00439 return stddev;
00440 }
00441
00442
00443 void compute_stats(double& avg, double& stddev, T& minval, T& maxval) const {
00444 if (is_void()) {
00445 avg = stddev = minval = maxval = 0;
00446 } else {
00447 T val = first_element();
00448 avg = stddev = 0;
00449 maxval = minval = val;
00450 std::vector<index> idx(D);
00451 for (unsigned long i=0;i<this->num_elements() ;i++) {
00452 if (this->data()[i] > maxval) { maxval = val; }
00453 if (this->data()[i] < minval) { minval = val; }
00454 val = static_cast<double>(this->data()[i]);
00455 avg += val;
00456 stddev += val*val;
00457 }
00458
00459 size_type n_elem = this->num_elements();
00460 avg /= n_elem;
00461 if (n_elem > 1) {
00462
00463 stddev = stddev / n_elem - avg * avg;
00464 stddev *= n_elem / (n_elem - 1);
00465
00466 stddev = sqrt(static_cast<double>(std::abs(stddev)));
00467 } else {
00468 stddev = 0;
00469 }
00470 }
00471 }
00472
00473
00474
00475 void normalize() {
00476 double avg,stddev;
00477 T minval,maxval;
00478 compute_stats(avg,stddev,minval,maxval);
00479 for (unsigned long i=0;i<this->num_elements();i++) {
00480 this->data()[i] = (this->data()[i]-avg)/stddev;
00481 }
00482 }
00483
00484
00485
00486 T sum_elements() const {
00487 T sum = 0;
00488 for (unsigned long i=0;i<this->num_elements();i++) {
00489 sum += this->data()[i];
00490 }
00491 return sum;
00492 }
00493
00494
00495
00496 T sum_squared_elements() const {
00497 T sum = 0;
00498 for (unsigned long i=0;i<this->num_elements();i++) {
00499 sum += this->data()[i]*this->data()[i];
00500 }
00501 return sum;
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511 T squared_difference(const This& v) const {
00512 if(!this->same_shape(v)) {
00513 IMP_FAILURE("squared_difference:: operation not supported with arrays "
00514 "of different shape (size and origin).");
00515 } else {
00516 T sum = 0,aux;
00517 for (unsigned long i=0;i<this->num_elements();i++) {
00518 aux = this->data()[i] - v.data()[i];
00519 sum += aux*aux;
00520 }
00521 return sum;
00522 }
00523 }
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548 double cross_correlation_coefficient(const This& v,
00549 bool apply_threshold=false,
00550 double threshold=0.0,
00551 bool divide_by_stddev=true,
00552 bool force_recalc_stats=true,
00553 double avg=0.0,
00554 double stddev=0.0,
00555 double avg_v=0.0,
00556 double stddev_v=0.0) {
00557
00558 IMP_USAGE_CHECK(this->same_size(v),
00559 "MultiArray:: cross correlation coefficient not supported with "
00560 "arrays of different size.");
00561
00562 double t_avg,t_stddev,v_avg,v_stddev;
00563 T t_max,t_min,v_max,v_min;
00564
00565 if(force_recalc_stats) {
00566 this->compute_stats(t_avg,t_stddev,t_min,t_max);
00567 v.compute_stats(v_avg,v_stddev,v_min,v_max);
00568 } else {
00569 t_avg=avg;
00570 t_stddev=stddev;
00571 v_avg=avg_v;
00572 v_stddev=stddev_v;
00573 }
00574
00575 double n_elems = (double)this->num_elements();
00576 double epsilon = 1e-6;
00577
00578 if (divide_by_stddev && ( almost_equal(t_stddev,0.0,epsilon) ||
00579 almost_equal(v_stddev,0.0,epsilon))) {
00580 return 0.0;
00581 }
00582 double ccc = 0.0;
00583 std::vector<index> idx(D);
00584
00585
00586 if(this->same_start(v)) {
00587 for (unsigned long i=0;i<n_elems;++i) {
00588 if(!apply_threshold || (apply_threshold && v.data()[i] > threshold)) {
00589 ccc += this->data()[i]*v.data()[i];
00590 }
00591 }
00592 } else {
00593 while (internal::roll_inds(idx, this->shape(), this->index_bases())) {
00594
00595 if(v.is_logical_element(idx)) {
00596
00597 if(!apply_threshold || (apply_threshold && v(idx) > threshold)) {
00598 ccc += (*this)(idx)*v(idx);
00599 }
00600 }
00601 }
00602 }
00603 if (divide_by_stddev) {
00604 ccc = (ccc-n_elems*t_avg*v_avg)/(n_elems*t_stddev*v_stddev);
00605 }
00606 return ccc;
00607 }
00608
00609
00610
00611
00612
00613 void read(const std::string& filename) {
00614 std::ifstream in;
00615 in.open(filename.c_str(), std::ios::in);
00616 if (!in) {
00617 IMP_FAILURE("MultiArray::read: File " + filename + " not found");
00618 }
00619 in >> *this;
00620 in.close();
00621 }
00622
00623
00624
00625
00626
00627 void read_binary(const std::string& filename,bool reversed=false) {
00628 std::ifstream in;
00629 in.open(filename.c_str(), std::ios::in | std::ios::binary);
00630 if (!in) {
00631 IMP_FAILURE("MultiArray::read_binary: File " + filename + " not found");
00632 }
00633 read_binary(in,reversed);
00634 in.close();
00635 }
00636
00637
00638
00639
00640
00641 void read_binary(std::ifstream& in,bool reversed=false) {
00642 for (unsigned long i=0;i<this->num_elements();i++) {
00643 if (!reversed) {
00644 in.read(reinterpret_cast< char* >(&(this->data()[i])), sizeof(T));
00645 } else {
00646 reversed_read(reinterpret_cast< char* >(&(this->data()[i])),
00647 sizeof(T),1,in,true);
00648 }
00649 }
00650 }
00651
00652
00653 void write(const std::string& filename) const {
00654 std::ofstream out;
00655 out.open(filename.c_str(), std::ios::out);
00656 if (!out) {
00657 IMP_FAILURE("MultiArray::write: "+
00658 filename+" cannot be opened for output");
00659 }
00660 out << *this;
00661 out.close();
00662 }
00663
00664
00665 void write_binary(const std::string& filename,bool reversed=false) {
00666 std::ofstream out;
00667 out.open(filename.c_str(), std::ios::out | std::ios::binary);
00668 if (!out) {
00669 IMP_FAILURE("MultiArray::write: " +
00670 filename +" cannot be opened for output");
00671 }
00672 write_binary(out,reversed);
00673 out.close();
00674 }
00675
00676
00677 void write_binary(std::ofstream& out,bool reversed=false) {
00678 for (unsigned long i=0;i<this->num_elements();i++) {
00679 if (!reversed) {
00680 out.write(reinterpret_cast< char* >(&(this->data()[i])), sizeof(T));
00681 } else {
00682 reversed_write(reinterpret_cast< char* >(&(this->data()[i])),
00683 sizeof(T),1,out,true);
00684 }
00685 }
00686 }
00687
00688 friend std::istream& operator>>(std::istream& in,This& v) {
00689 for (unsigned long i=0;i<v.num_elements();i++) {
00690 in >> v.data()[i];
00691 }
00692 return in;
00693 }
00694
00695 protected:
00696 };
00697
00698 #ifndef IMP_DOXYGEN
00699
00700
00701 template<typename T, int D>
00702 std::ostream& operator<<(std::ostream& ostrm,
00703 const MultiArray<T, D>& v)
00704 {
00705 typedef boost::multi_array_types::index index;
00706 std::vector<index> idx(D);
00707
00708 if (v.is_void()) {
00709 ostrm << "NULL Array" << std::endl;
00710 return ostrm;
00711 } else {
00712 ostrm << std::endl;
00713 }
00714 T absmax = v.first_element();
00715 while (internal::roll_inds(idx, v.shape(), v.index_bases())) {
00716 if (std::abs(v(idx)) > absmax) {
00717 absmax = v(idx);
00718 }
00719 }
00720 int prec = internal::best_precision(absmax, 10);
00721
00722
00723
00724 if (D == 3) {
00725 for (index k = (v).get_start(0);k <= (v).get_finish(0);k++) {
00726 if (v.get_size(0) > 1) ostrm << "Slice No. " << k << std::endl;
00727 for (index j = (v).get_start(1);j <= (v).get_finish(1);j++) {
00728 for (index i = (v).get_start(2);i <= (v).get_finish(2);i++) {
00729 idx[0] = k; idx[1] = j; idx[2] = i;
00730 ostrm << internal::float_to_string((double)v(idx), 10, prec) << ' ';
00731 }
00732 ostrm << std::endl;
00733 }
00734 }
00735 } else if (D == 2) {
00736 for (index j = (v).get_start(0);j <= (v).get_finish(0);j++) {
00737 for (index i = (v).get_start(1);i <= (v).get_finish(1);i++) {
00738 idx[0] = j; idx[1] = i;
00739 ostrm << internal::float_to_string((double)v(idx), 10, prec) << ' ';
00740 }
00741 ostrm << std::endl;
00742 }
00743 } else {
00744 while (internal::roll_inds(idx, v.shape(), v.index_bases())) {
00745 ostrm << internal::float_to_string((double)v(idx), 10, prec) << ' ';
00746 }
00747 ostrm << std::endl;
00748 }
00749 return ostrm;
00750 }
00751 #endif
00752
00753 #ifndef SWIG
00754
00755
00756 template <class T, int D>
00757 MultiArray<T, D> operator+(const T& X,
00758 const MultiArray<T, D>& a1) {
00759 MultiArray<T, D> result(a1->shape());
00760 internal::operate_scalar_and_array(X,a1,result,"+");
00761 return result;
00762 }
00763
00764
00765
00766 template <class T, int D>
00767 MultiArray<T, D> operator-(const T& X,
00768 const MultiArray<T, D>& a1) {
00769 MultiArray<T, D> result(a1->shape());
00770 internal::operate_scalar_and_array(X,a1,result,"-");
00771 }
00772
00773
00774
00775 template <class T, int D>
00776 MultiArray<T, D> operator*(const T& X,
00777 const MultiArray<T, D>& a1) {
00778 MultiArray<T, D> result(a1->shape());
00779 internal::operate_scalar_and_array(X,a1,result,"*");
00780 return result;
00781 }
00782
00783
00784
00785 template <class T, int D>
00786 MultiArray<T, D> operator/(const T& X,
00787 const MultiArray<T, D>& a1) {
00788 MultiArray<T, D> result(a1->shape());
00789 internal::operate_scalar_and_array(X,a1,result,"/");
00790 return result;
00791 }
00792
00793
00794
00795
00796 #endif
00797
00798 IMPALGEBRA_END_NAMESPACE
00799
00800 #endif