Warning, /include/Geant4/tools/array is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_array
0005 #define tools_array
0006
0007 #ifdef TOOLS_MEM
0008 #include "mem"
0009 #endif
0010
0011 #include <vector>
0012 #include <string>
0013
0014 namespace tools {
0015
0016 // array handles an hyperparallelepiped of cells of class T.
0017
0018 template <class T>
0019 class array {
0020 public:
0021 static const std::string& s_class() {
0022 static const std::string s_v("tools::array");
0023 return s_v;
0024 }
0025 public:
0026 typedef typename std::vector< std::pair<unsigned int,unsigned int> > cut_t;
0027 typedef typename std::vector<unsigned int> uints_t;
0028 typedef typename std::vector<T>::iterator vec_it_t;
0029 typedef typename std::vector<T>::const_iterator cons_vec_it_t;
0030 public:
0031 array() {
0032 #ifdef TOOLS_MEM
0033 mem::increment(s_class().c_str());
0034 #endif
0035 }
0036 array(const uints_t& a_orders) {
0037 #ifdef TOOLS_MEM
0038 mem::increment(s_class().c_str());
0039 #endif
0040 configure(a_orders);
0041 }
0042 array(unsigned int a_dimension,unsigned int a_order) {
0043 #ifdef TOOLS_MEM
0044 mem::increment(s_class().c_str());
0045 #endif
0046 // A hypercube of dimension "a_dimension" and size "a_order".
0047 uints_t _orders(a_dimension);
0048 for(unsigned int index=0;index<a_dimension;index++)
0049 _orders[index] = a_order;
0050 configure(_orders);
0051 }
0052 virtual ~array() {
0053 #ifdef TOOLS_MEM
0054 mem::decrement(s_class().c_str());
0055 #endif
0056 }
0057 public:
0058 array(const array& a_from)
0059 :m_orders(a_from.m_orders)
0060 ,m_offsets(a_from.m_offsets)
0061 ,m_vector(a_from.m_vector)
0062 ,m_is(a_from.m_is){
0063 #ifdef TOOLS_MEM
0064 mem::increment(s_class().c_str());
0065 #endif
0066 }
0067 array& operator=(const array& a_from) {
0068 m_orders = a_from.m_orders;
0069 m_offsets = a_from.m_offsets;
0070 m_vector = a_from.m_vector;
0071 m_is = a_from.m_is;
0072 return *this;
0073 }
0074 public: //operators:
0075 array& operator*=(const T& a_T) {multiply(a_T);return *this;}
0076 bool operator==(const array& a_array) const {
0077 return equal(a_array);
0078 }
0079 bool operator!=(const array& a_array) const {
0080 return !operator==(a_array);
0081 }
0082 array operator*(const T& a_T) const {
0083 array a(*this);
0084 a.multiply(a_T);
0085 return a;
0086 }
0087 // the below would need exception to do it properly.
0088 //array operator+(const array& a_array) const {
0089 // array a(*this);
0090 // if(!a.add(a_array)) {} //throw
0091 // return a;
0092 //}
0093 //array& operator+=(const array& a_array) {
0094 // if(!add(a_array)) {} //throw
0095 // return *this;
0096 //}
0097 public:
0098 void copy(const array& a_from) {
0099 m_orders = a_from.m_orders;
0100 m_offsets = a_from.m_offsets;
0101 m_vector = a_from.m_vector;
0102 m_is = a_from.m_is;
0103 }
0104 void clear() {
0105 m_orders.clear();
0106 m_offsets.clear();
0107 m_vector.clear();
0108 m_is.clear();
0109 }
0110 bool configure(const uints_t& a_orders) {
0111 m_orders = a_orders;
0112 size_t dim = m_orders.size();
0113 if(dim==0) {
0114 clear();
0115 return false;
0116 }
0117 unsigned int _size = 1;
0118 for(size_t index=0;index<dim;index++) {
0119 //if(m_orders[index]<0) {
0120 //clear();
0121 //return false;
0122 //}
0123 _size *= m_orders[index];
0124 }
0125 m_vector.resize(_size);
0126 m_vector.assign(_size,zero());
0127 m_offsets.resize(dim,0);
0128 m_offsets[0] = 1;
0129 for(size_t iaxis=1;iaxis<dim;iaxis++)
0130 m_offsets[iaxis] = m_offsets[iaxis-1] * m_orders[iaxis-1];
0131 m_is.resize(dim);
0132 m_is.assign(dim,0);
0133 return true;
0134 }
0135 size_t dimension() const { return m_orders.size();}
0136 const uints_t& orders() const { return m_orders;}
0137 size_t size() const {return m_vector.size();}
0138 bool set_value(const uints_t& a_is,const T& a_value) {
0139 unsigned int off = 0;
0140 if(!offset(a_is,off)) return false;
0141 m_vector[off] = a_value;
0142 return true;
0143 }
0144 bool value(const uints_t& a_is,T& a_value) const {
0145 unsigned int off = 0;
0146 if(!offset(a_is,off)) {
0147 a_value = 0;
0148 return false;
0149 }
0150 a_value = m_vector[off];
0151 return true;
0152 }
0153 T value_no_check(const uints_t& a_is) const { //TOUCHY
0154 unsigned int off = 0;
0155 if(!offset(a_is,off)) {}
0156 return m_vector[off];
0157 }
0158 void reset() {
0159 for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it) *it = 0;
0160 }
0161 const std::vector<T>& vector() const { return m_vector;}
0162 std::vector<T>& vector() { return m_vector;}
0163 bool fill(const std::vector<T>& a_values,cut_t* a_cut = 0) {
0164 size_t dsize = a_values.size();
0165 size_t di = 0;
0166 unsigned int index = 0;
0167 for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it,index++) {
0168 if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
0169 if(di>=dsize) return false; //a_values exhausted too early
0170 *it = a_values[di];
0171 di++;
0172 }
0173 }
0174 return true;
0175 }
0176 bool fill(unsigned int a_sz,const T* a_data,cut_t* a_cut = 0) {
0177 unsigned int di = 0;
0178 unsigned int index = 0;
0179 for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it,index++) {
0180 if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
0181 if(di>=a_sz) return false; //a_values exhausted too early
0182 *it = a_data[di];
0183 di++;
0184 }
0185 }
0186 return true;
0187 }
0188 // Related to other array :
0189 bool equal(const array& a_array) const {
0190 if(m_orders!=a_array.m_orders) return false;
0191 cons_vec_it_t it = m_vector.begin();
0192 cons_vec_it_t ait = a_array.m_vector.begin();
0193 for(;it!=m_vector.end();++it,++ait) {
0194 if((*it)!=(*ait)) return false;
0195 }
0196 return true;
0197 }
0198 bool equal(const array& a_array,T aEpsilon) const {
0199 if(m_orders!=a_array.m_orders) return false;
0200 cons_vec_it_t it = m_vector.begin();
0201 cons_vec_it_t ait = a_array.m_vector.begin();
0202 for(;it!=m_vector.end();++it,++ait) {
0203 T diff = (*it) - (*ait);
0204 if(diff<0) diff *= -1;
0205 if(diff>=aEpsilon) return false;
0206 }
0207 return true;
0208 }
0209 bool is_proportional(const array& a_array,T& a_factor) const {
0210 // If true, then : a_array = a_factor * this.
0211 a_factor = zero();
0212 if(m_orders!=a_array.m_orders) return false;
0213 bool first = true;
0214 cons_vec_it_t it = m_vector.begin();
0215 cons_vec_it_t ait = a_array.m_vector.begin();
0216 for(;it!=m_vector.end();++it,++ait) {
0217 if( ((*it)==zero()) && ((*ait)==zero())) {
0218 continue;
0219 } else if( ((*it)!=zero()) && ((*ait)==zero())) {
0220 return false;
0221 } else if( ((*it)==zero()) && ((*ait)!=zero())) {
0222 return false;
0223 } else {
0224 if(first) {
0225 a_factor = (*ait)/(*it);
0226 first = false;
0227 } else {
0228 if((*ait)!=(*it)*a_factor) return false;
0229 }
0230 }
0231 }
0232 return true;
0233 }
0234 bool add(const array& a_array,cut_t* a_cut = 0) {
0235 if(m_orders!=a_array.m_orders) return false;
0236 vec_it_t it = m_vector.begin();
0237 cons_vec_it_t ait = a_array.m_vector.begin();
0238 unsigned int index = 0;
0239 for(;it!=m_vector.end();++it,++ait,index++) {
0240 if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
0241 (*it) += (*ait);
0242 }
0243 }
0244 return true;
0245 }
0246 bool subtract(const array& a_array) {
0247 if(m_orders!=a_array.m_orders) return false;
0248 vec_it_t it = m_vector.begin();
0249 cons_vec_it_t ait = a_array.m_vector.begin();
0250 for(;it!=m_vector.end();++it,++ait) (*it) -= (*ait);
0251 return true;
0252 }
0253 bool multiply(const array& a_array) {
0254 if(m_orders!=a_array.m_orders) return false;
0255 vec_it_t it = m_vector.begin();
0256 cons_vec_it_t ait = a_array.m_vector.begin();
0257 for(;it!=m_vector.end();++it,++ait) (*it) *= (*ait);
0258 return true;
0259 }
0260 bool divide(const array& a_array) {
0261 if(m_orders!=a_array.m_orders) return false;
0262 bool status = true;
0263 vec_it_t it = m_vector.begin();
0264 cons_vec_it_t ait = a_array.m_vector.begin();
0265 for(;it!=m_vector.end();++it,++ait) {
0266 if((*ait)==zero()) {
0267 (*it) = zero(); //PAW convention.
0268 status = false;
0269 } else {
0270 (*it) /= (*ait);
0271 }
0272 }
0273 return status;
0274 }
0275 bool contract(const array& a_array,T& a_value) const {
0276 a_value = zero();
0277 if(m_orders!=a_array.m_orders) return false;
0278 cons_vec_it_t it = m_vector.begin();
0279 cons_vec_it_t ait = a_array.m_vector.begin();
0280 for(;it!=m_vector.end();++it,++ait) a_value += (*it) * (*ait);
0281 return true;
0282 }
0283 //Else:
0284 void add(const T& a_T,cut_t* a_cut = 0) {
0285 unsigned int index = 0;
0286 for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it,index++) {
0287 if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
0288 (*it) += a_T;
0289 }
0290 }
0291 }
0292 void multiply(const T& a_T) {
0293 for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) *= a_T;
0294 }
0295 bool divide(const T& a_T) {
0296 if(a_T==zero()) return false;
0297 for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) /= a_T;
0298 return true;
0299 }
0300 bool invert() {
0301 bool status = true;
0302 T v_one = one();
0303 for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) {
0304 if((*it)==zero()) {
0305 (*it) = zero(); //PAW convention.
0306 status = false;
0307 } else {
0308 T _value = (*it);
0309 (*it) = v_one/_value;
0310 }
0311 }
0312 return status;
0313 }
0314 bool offset(const uints_t& a_is,unsigned int& a_offset) const {
0315 size_t dim = m_orders.size();
0316 a_offset = 0;
0317 if(a_is.size()!=dim) return false;
0318 if(dim==0) return false;
0319 for(size_t iaxis=0;iaxis<dim;iaxis++) {
0320 unsigned int i = a_is[iaxis];
0321 if(i>=m_orders[iaxis]) {
0322 a_offset = 0;
0323 return false;
0324 }
0325 a_offset += i * m_offsets[iaxis];
0326 }
0327 return true;
0328 }
0329 bool indices(unsigned int a_offset,uints_t& a_is) const {
0330 if(a_offset>=m_vector.size()) return false;
0331 size_t dim = m_orders.size();
0332 unsigned int off = a_offset;
0333 for(int iaxis=int(dim)-1;iaxis>=0;iaxis--) {
0334 a_is[iaxis] = off/m_offsets[iaxis];
0335 off -= a_is[iaxis] * m_offsets[iaxis];
0336 }
0337 return true;
0338 }
0339 bool accept(unsigned int a_index,const cut_t& a_cut) const {
0340 size_t dim = m_orders.size();
0341 if(a_cut.size()!=dim) return false;
0342 if(!indices(a_index,const_cast<uints_t&>(m_is))) return false;
0343 bool good = true;
0344 for(size_t iaxis=0;iaxis<dim;iaxis++) {
0345 if(m_is[iaxis]<a_cut[iaxis].first) {good = false;break;}
0346 if(m_is[iaxis]>a_cut[iaxis].second) {good = false;break;}
0347 }
0348 return good;
0349 }
0350 void set_constant(const T& a_v) {
0351 for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) = a_v;
0352 }
0353 void set_zero(){
0354 set_constant(zero());
0355 }
0356 public:
0357 static T zero() {
0358 //return (T)0;
0359 //return T(0);
0360 return T();
0361 }
0362 static T one() {
0363 //return (T)1;
0364 return T(1);
0365 }
0366 static T minus_one() {
0367 //return (T)-1;
0368 return T(-1);
0369 }
0370 static T two() {
0371 //return (T)2;
0372 return T(2);
0373 }
0374 protected:
0375 uints_t m_orders;
0376 uints_t m_offsets;
0377 std::vector<T> m_vector;
0378 uints_t m_is;
0379 };
0380
0381 }
0382
0383 #include <ostream>
0384
0385 // Helpers array<T> :
0386 namespace tools {
0387
0388 template <class T>
0389 inline bool contract(
0390 const array<T>& aA
0391 ,unsigned int aIA
0392 ,const array<T>& aB
0393 ,unsigned int aIB
0394 ,array<T>& aR
0395 ){
0396 // Contract a tensor (aA) with a vector (aB)
0397 // on indice aIA of aA and aIB of aB.
0398 // aA.dimension must be > 1.
0399 // aB.dimension must be > 1.
0400 if(&aR==&aA) return false;
0401 if(&aR==&aB) return false;
0402
0403 if(aA.dimension()==0) return false;
0404 if(aB.dimension()==0) return false;
0405 if(aIA>=aA.dimension()) return false;
0406 if(aIB>=aB.dimension()) return false;
0407 if(aA.orders()[aIA]!=aB.orders()[aIB]) return false;
0408
0409 unsigned int rdima = aA.dimension()-1;
0410 unsigned int rdimb = aB.dimension()-1;
0411
0412 if((rdima+rdimb)==0) {
0413 std::vector<unsigned int> rorders(1);
0414 rorders[0] = 1;
0415 if(!aR.configure(rorders)) return false;
0416 const std::vector<T>& vA = aA.vector();
0417 const std::vector<T>& vB = aB.vector();
0418 T value = array<T>::zero();
0419 for(unsigned int index=0;index<vA.size();index++) {
0420 value += vA[index]*vB[index];
0421 }
0422 aR.vector()[0] = value;
0423 return true;
0424 }
0425
0426 std::vector<unsigned int> rorders(rdima+rdimb);
0427 unsigned int index;
0428 for(index=0;index<aIA;index++)
0429 rorders[index] = aA.orders()[index];
0430 for(index=aIA;index<rdima;index++)
0431 rorders[index] = aA.orders()[index+1];
0432
0433 for(index=0;index<aIB;index++)
0434 rorders[rdima+index] = aB.orders()[index];
0435 for(index=aIB;index<rdimb;index++)
0436 rorders[rdima+index] = aB.orders()[index+1];
0437
0438 if(!aR.configure(rorders)) return false;
0439
0440 std::vector<unsigned int> ais(aA.dimension());
0441 std::vector<unsigned int> bis(aB.dimension());
0442 std::vector<unsigned int> ris(aR.dimension());
0443
0444 //FIXME : optimize the below.
0445 unsigned int order = aA.orders()[aIA];
0446 unsigned int rsize = aR.size();
0447
0448 std::vector<T>& rvec = aR.vector();
0449
0450 for(unsigned int roffset=0;roffset<rsize;roffset++) {
0451 if(!aR.indices(roffset,ris)) return false;
0452
0453 for(index=0;index<aIA;index++) ais[index] = ris[index];
0454 for(index=aIA;index<rdima;index++) ais[index+1] = ris[index];
0455
0456 for(index=0;index<aIB;index++) bis[index] = ris[rdima+index];
0457 for(index=aIB;index<rdimb;index++) bis[index+1] = ris[rdima+index];
0458
0459 T value = 0;
0460 for(index=0;index<order;index++) {
0461 ais[aIA] = index;
0462 T av;
0463 if(!aA.value(ais,av)) return false;
0464
0465 bis[aIB] = index;
0466 T bv;
0467 if(!aB.value(bis,bv)) return false;
0468
0469 value += av * bv;
0470 }
0471
0472 rvec[roffset] = value;
0473 }
0474
0475 return true;
0476 }
0477
0478 template <class T>
0479 inline bool swap(
0480 const array<T>& aV
0481 ,unsigned int aI1
0482 ,unsigned int aI2
0483 ,array<T>& aR
0484 ){
0485 if(&aR==&aV) return false;
0486
0487 unsigned int dim = aV.dimension();
0488 if(aI1>=dim) return false;
0489 if(aI2>=dim) return false;
0490
0491 if(aI1==aI2) {
0492 aR.copy(aV);
0493 return true;
0494 }
0495
0496 if(!aR.configure(aV.orders())) return false;
0497
0498 std::vector<unsigned int> vis(aV.dimension());
0499 std::vector<unsigned int> ris(aV.dimension());
0500
0501 const std::vector<T>& vvec = aV.vector();
0502
0503 unsigned int size = aV.size();
0504 for(unsigned int offset=0;offset<size;offset++) {
0505 T value = vvec[offset];
0506
0507 if(!aV.indices(offset,vis)) return false;
0508 unsigned int i = vis[aI1];
0509 vis[aI1] = vis[aI2];
0510 vis[aI2] = i;
0511 if(!aR.set_value(vis,value)) return false;
0512 }
0513
0514 return true;
0515 }
0516
0517 //NOTE : print is a Python keyword.
0518 template <class T>
0519 inline void dump(std::ostream& a_out,const tools::array<T>& a_array,const std::string& a_title){
0520 if(a_title.size()) a_out << a_title << std::endl;
0521 const std::vector<T>& vec = a_array.vector();
0522 typedef typename std::vector<T>::const_iterator cons_vec_it_t;
0523 for(cons_vec_it_t it = vec.begin();it!=vec.end();++it) {
0524 a_out << (*it) << std::endl;
0525 }
0526 }
0527
0528 template <class T>
0529 inline void diff(std::ostream& a_out,const array<T>& aA,const array<T>& aB,T a_epsilon){
0530 if(aA.orders()!=aB.orders()) {
0531 a_out << "tools::arrays::diff : not same orders" << std::endl;
0532 return;
0533 }
0534 bool header_done = false;
0535 unsigned int dim = aA.dimension();
0536 std::vector<unsigned int> is(dim);
0537 unsigned int vsize = aA.vector().size();
0538 for(unsigned int index=0;index<vsize;index++) {
0539 T diff = aA.vector()[index]-aB.vector()[index];
0540 if(diff<0) diff *= -1;
0541 if(diff>=a_epsilon) {
0542 aA.indices(index,is);
0543 if(!header_done) {
0544 a_out << "tools::arrays::diff :" << std::endl;
0545 header_done = true;
0546 }
0547 for(unsigned int i=0;i<dim;i++) a_out << is[i] << " ";
0548 a_out << aA.vector()[index] << " " << aB.vector()[index] << std::endl;
0549 }
0550 }
0551 }
0552
0553 //////////////////////////////////////////////////////////////////////////////
0554 /// common array /////////////////////////////////////////////////////////////
0555 //////////////////////////////////////////////////////////////////////////////
0556
0557 template <class T>
0558 class kronecker : public array<T> {
0559 public:
0560 kronecker(unsigned int a_order):array<T>(a_order,a_order){
0561 // epsilon(i1,i2,....in) with n = a_order and i in [0,n[.
0562 // Then an Array of a_order * a_order.
0563 unsigned int index = 0;
0564 typedef typename std::vector<unsigned int> _uints_t;
0565 _uints_t is(a_order);
0566 std::vector<T>& vec = array<T>::vector();
0567 typedef typename std::vector<T>::iterator _vec_it_t;
0568 _vec_it_t it = vec.begin();
0569 for(;it!=vec.end();++it,index++) {
0570 if(!array<T>::indices(index,is)) return; //FIXME throw.
0571 bool good = true;
0572 {for(unsigned int iaxis=0;iaxis<a_order;iaxis++) {
0573 unsigned int ival = is[iaxis];
0574 for(unsigned int iaxis2=iaxis+1;iaxis2<a_order;iaxis2++) {
0575 if(is[iaxis2]==ival) {
0576 good = false;
0577 break;
0578 }
0579 }
0580 if(!good) break;
0581 }}
0582 if(!good) continue;
0583 // All indicies are different.
0584 unsigned int n = 0;
0585 for(unsigned int iaxis=0;iaxis<a_order;) {
0586 unsigned int ival = is[iaxis];
0587 if(ival!=iaxis) {
0588 // Swap and add one permutation :
0589 unsigned int old = is[ival];
0590 is[ival] = ival;
0591 is[iaxis] = old;
0592 n +=1;
0593 } else {
0594 iaxis++;
0595 }
0596 }
0597 {unsigned int n_2 = n/2;
0598 if(2*n_2==n) (*it) = array<T>::one();
0599 else (*it) = array<T>::minus_one();}
0600 }
0601 }
0602 };
0603
0604 template <class T>
0605 inline array<T> operator+(const array<T>& a1,const array<T>& a2) {
0606 array<T> res(a1);
0607 if(!res.add(a2)) {}
0608 return res;
0609 }
0610 template <class T>
0611 inline array<T> operator-(const array<T>& a1,const array<T>& a2) {
0612 array<T> res(a1);
0613 if(!res.subtract(a2)) {}
0614 return res;
0615 }
0616 template <class T>
0617 inline array<T> operator*(const T& a_fac,const array<T>& a_m) {
0618 array<T> res(a_m);
0619 res *= a_fac;
0620 return res;
0621 }
0622
0623 }
0624
0625 #endif