Files
geant4/source/analysis/g4tools/include/tools/array
T
2016-12-09 12:35:28 +01:00

626 lines
17 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_array
#define tools_array
#ifdef TOOLS_MEM
#include "mem"
#endif
#include <vector>
#include <string>
namespace tools {
// array handles an hyperparallelepiped of cells of class T.
template <class T>
class array {
public:
static const std::string& s_class() {
static const std::string s_v("tools::array");
return s_v;
}
public:
typedef typename std::vector< std::pair<unsigned int,unsigned int> > cut_t;
typedef typename std::vector<unsigned int> uints_t;
typedef typename std::vector<T>::iterator vec_it_t;
typedef typename std::vector<T>::const_iterator cons_vec_it_t;
public:
array() {
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
array(const uints_t& a_orders) {
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
configure(a_orders);
}
array(unsigned int a_dimension,unsigned int a_order) {
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
// A hypercube of dimension "a_dimension" and size "a_order".
uints_t _orders(a_dimension);
for(unsigned int index=0;index<a_dimension;index++)
_orders[index] = a_order;
configure(_orders);
}
virtual ~array() {
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
public:
array(const array& a_from)
:m_orders(a_from.m_orders)
,m_offsets(a_from.m_offsets)
,m_vector(a_from.m_vector)
,m_is(a_from.m_is){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
array& operator=(const array& a_from) {
m_orders = a_from.m_orders;
m_offsets = a_from.m_offsets;
m_vector = a_from.m_vector;
m_is = a_from.m_is;
return *this;
}
public: //operators:
array& operator*=(const T& a_T) {multiply(a_T);return *this;}
bool operator==(const array& a_array) const {
return equal(a_array);
}
bool operator!=(const array& a_array) const {
return !operator==(a_array);
}
array operator*(const T& a_T) const {
array a(*this);
a.multiply(a_T);
return a;
}
// the below would need exception to do it properly.
//array operator+(const array& a_array) const {
// array a(*this);
// if(!a.add(a_array)) {} //throw
// return a;
//}
//array& operator+=(const array& a_array) {
// if(!add(a_array)) {} //throw
// return *this;
//}
public:
void copy(const array& a_from) {
m_orders = a_from.m_orders;
m_offsets = a_from.m_offsets;
m_vector = a_from.m_vector;
m_is = a_from.m_is;
}
void clear() {
m_orders.clear();
m_offsets.clear();
m_vector.clear();
m_is.clear();
}
bool configure(const uints_t& a_orders) {
m_orders = a_orders;
size_t dim = m_orders.size();
if(dim==0) {
clear();
return false;
}
unsigned int _size = 1;
for(size_t index=0;index<dim;index++) {
//if(m_orders[index]<0) {
//clear();
//return false;
//}
_size *= m_orders[index];
}
m_vector.resize(_size);
m_vector.assign(_size,zero());
m_offsets.resize(dim,0);
m_offsets[0] = 1;
for(size_t iaxis=1;iaxis<dim;iaxis++)
m_offsets[iaxis] = m_offsets[iaxis-1] * m_orders[iaxis-1];
m_is.resize(dim);
m_is.assign(dim,0);
return true;
}
size_t dimension() const { return m_orders.size();}
const uints_t& orders() const { return m_orders;}
size_t size() const {return m_vector.size();}
bool set_value(const uints_t& a_is,const T& a_value) {
unsigned int off = 0;
if(!offset(a_is,off)) return false;
m_vector[off] = a_value;
return true;
}
bool value(const uints_t& a_is,T& a_value) const {
unsigned int off = 0;
if(!offset(a_is,off)) {
a_value = 0;
return false;
}
a_value = m_vector[off];
return true;
}
T value_no_check(const uints_t& a_is) const { //TOUCHY
unsigned int off = 0;
if(!offset(a_is,off)) {}
return m_vector[off];
}
void reset() {
for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it) *it = 0;
}
const std::vector<T>& vector() const { return m_vector;}
std::vector<T>& vector() { return m_vector;}
bool fill(const std::vector<T>& a_values,cut_t* a_cut = 0) {
size_t dsize = a_values.size();
size_t di = 0;
unsigned int index = 0;
for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it,index++) {
if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
if(di>=dsize) return false; //a_values exhausted too early
*it = a_values[di];
di++;
}
}
return true;
}
bool fill(unsigned int a_sz,const T* a_data,cut_t* a_cut = 0) {
unsigned int di = 0;
unsigned int index = 0;
for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it,index++) {
if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
if(di>=a_sz) return false; //a_values exhausted too early
*it = a_data[di];
di++;
}
}
return true;
}
// Related to other array :
bool equal(const array& a_array) const {
if(m_orders!=a_array.m_orders) return false;
cons_vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) {
if((*it)!=(*ait)) return false;
}
return true;
}
bool equal(const array& a_array,T aEpsilon) const {
if(m_orders!=a_array.m_orders) return false;
cons_vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) {
T diff = (*it) - (*ait);
if(diff<0) diff *= -1;
if(diff>=aEpsilon) return false;
}
return true;
}
bool is_proportional(const array& a_array,T& a_factor) const {
// If true, then : a_array = a_factor * this.
a_factor = zero();
if(m_orders!=a_array.m_orders) return false;
bool first = true;
cons_vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) {
if( ((*it)==zero()) && ((*ait)==zero())) {
continue;
} else if( ((*it)!=zero()) && ((*ait)==zero())) {
return false;
} else if( ((*it)==zero()) && ((*ait)!=zero())) {
return false;
} else {
if(first) {
a_factor = (*ait)/(*it);
first = false;
} else {
if((*ait)!=(*it)*a_factor) return false;
}
}
}
return true;
}
bool add(const array& a_array,cut_t* a_cut = 0) {
if(m_orders!=a_array.m_orders) return false;
vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
unsigned int index = 0;
for(;it!=m_vector.end();++it,++ait,index++) {
if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
(*it) += (*ait);
}
}
return true;
}
bool subtract(const array& a_array) {
if(m_orders!=a_array.m_orders) return false;
vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) (*it) -= (*ait);
return true;
}
bool multiply(const array& a_array) {
if(m_orders!=a_array.m_orders) return false;
vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) (*it) *= (*ait);
return true;
}
bool divide(const array& a_array) {
if(m_orders!=a_array.m_orders) return false;
bool status = true;
vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) {
if((*ait)==zero()) {
(*it) = zero(); //PAW convention.
status = false;
} else {
(*it) /= (*ait);
}
}
return status;
}
bool contract(const array& a_array,T& a_value) const {
a_value = zero();
if(m_orders!=a_array.m_orders) return false;
cons_vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) a_value += (*it) * (*ait);
return true;
}
//Else:
void add(const T& a_T,cut_t* a_cut = 0) {
unsigned int index = 0;
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it,index++) {
if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
(*it) += a_T;
}
}
}
void multiply(const T& a_T) {
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) *= a_T;
}
bool divide(const T& a_T) {
if(a_T==zero()) return false;
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) /= a_T;
return true;
}
bool invert() {
bool status = true;
T v_one = one();
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) {
if((*it)==zero()) {
(*it) = zero(); //PAW convention.
status = false;
} else {
T _value = (*it);
(*it) = v_one/_value;
}
}
return status;
}
bool offset(const uints_t& a_is,unsigned int& a_offset) const {
size_t dim = m_orders.size();
a_offset = 0;
if(a_is.size()!=dim) return false;
if(dim==0) return false;
for(size_t iaxis=0;iaxis<dim;iaxis++) {
unsigned int i = a_is[iaxis];
if(i>=m_orders[iaxis]) {
a_offset = 0;
return false;
}
a_offset += i * m_offsets[iaxis];
}
return true;
}
bool indices(unsigned int a_offset,uints_t& a_is) const {
if(a_offset>=m_vector.size()) return false;
size_t dim = m_orders.size();
unsigned int off = a_offset;
for(int iaxis=int(dim)-1;iaxis>=0;iaxis--) {
a_is[iaxis] = off/m_offsets[iaxis];
off -= a_is[iaxis] * m_offsets[iaxis];
}
return true;
}
bool accept(unsigned int a_index,const cut_t& a_cut) const {
size_t dim = m_orders.size();
if(a_cut.size()!=dim) return false;
if(!indices(a_index,const_cast<uints_t&>(m_is))) return false;
bool good = true;
for(size_t iaxis=0;iaxis<dim;iaxis++) {
if(m_is[iaxis]<a_cut[iaxis].first) {good = false;break;}
if(m_is[iaxis]>a_cut[iaxis].second) {good = false;break;}
}
return good;
}
void set_constant(const T& a_v) {
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) = a_v;
}
void set_zero(){
set_constant(zero());
}
public:
static T zero() {
//return (T)0;
//return T(0);
return T();
}
static T one() {
//return (T)1;
return T(1);
}
static T minus_one() {
//return (T)-1;
return T(-1);
}
static T two() {
//return (T)2;
return T(2);
}
protected:
uints_t m_orders;
uints_t m_offsets;
std::vector<T> m_vector;
uints_t m_is;
};
}
#include <ostream>
// Helpers array<T> :
namespace tools {
template <class T>
inline bool contract(
const array<T>& aA
,unsigned int aIA
,const array<T>& aB
,unsigned int aIB
,array<T>& aR
){
// Contract a tensor (aA) with a vector (aB)
// on indice aIA of aA and aIB of aB.
// aA.dimension must be > 1.
// aB.dimension must be > 1.
if(&aR==&aA) return false;
if(&aR==&aB) return false;
if(aA.dimension()==0) return false;
if(aB.dimension()==0) return false;
if(aIA>=aA.dimension()) return false;
if(aIB>=aB.dimension()) return false;
if(aA.orders()[aIA]!=aB.orders()[aIB]) return false;
unsigned int rdima = aA.dimension()-1;
unsigned int rdimb = aB.dimension()-1;
if((rdima+rdimb)==0) {
std::vector<unsigned int> rorders(1);
rorders[0] = 1;
if(!aR.configure(rorders)) return false;
const std::vector<T>& vA = aA.vector();
const std::vector<T>& vB = aB.vector();
T value = array<T>::zero();
for(unsigned int index=0;index<vA.size();index++) {
value += vA[index]*vB[index];
}
aR.vector()[0] = value;
return true;
}
std::vector<unsigned int> rorders(rdima+rdimb);
unsigned int index;
for(index=0;index<aIA;index++)
rorders[index] = aA.orders()[index];
for(index=aIA;index<rdima;index++)
rorders[index] = aA.orders()[index+1];
for(index=0;index<aIB;index++)
rorders[rdima+index] = aB.orders()[index];
for(index=aIB;index<rdimb;index++)
rorders[rdima+index] = aB.orders()[index+1];
if(!aR.configure(rorders)) return false;
std::vector<unsigned int> ais(aA.dimension());
std::vector<unsigned int> bis(aB.dimension());
std::vector<unsigned int> ris(aR.dimension());
//FIXME : optimize the below.
unsigned int order = aA.orders()[aIA];
unsigned int rsize = aR.size();
std::vector<T>& rvec = aR.vector();
for(unsigned int roffset=0;roffset<rsize;roffset++) {
if(!aR.indices(roffset,ris)) return false;
for(index=0;index<aIA;index++) ais[index] = ris[index];
for(index=aIA;index<rdima;index++) ais[index+1] = ris[index];
for(index=0;index<aIB;index++) bis[index] = ris[rdima+index];
for(index=aIB;index<rdimb;index++) bis[index+1] = ris[rdima+index];
T value = 0;
for(index=0;index<order;index++) {
ais[aIA] = index;
T av;
if(!aA.value(ais,av)) return false;
bis[aIB] = index;
T bv;
if(!aB.value(bis,bv)) return false;
value += av * bv;
}
rvec[roffset] = value;
}
return true;
}
template <class T>
inline bool swap(
const array<T>& aV
,unsigned int aI1
,unsigned int aI2
,array<T>& aR
){
if(&aR==&aV) return false;
unsigned int dim = aV.dimension();
if(aI1>=dim) return false;
if(aI2>=dim) return false;
if(aI1==aI2) {
aR.copy(aV);
return true;
}
if(!aR.configure(aV.orders())) return false;
std::vector<unsigned int> vis(aV.dimension());
std::vector<unsigned int> ris(aV.dimension());
const std::vector<T>& vvec = aV.vector();
unsigned int size = aV.size();
for(unsigned int offset=0;offset<size;offset++) {
T value = vvec[offset];
if(!aV.indices(offset,vis)) return false;
unsigned int i = vis[aI1];
vis[aI1] = vis[aI2];
vis[aI2] = i;
if(!aR.set_value(vis,value)) return false;
}
return true;
}
//NOTE : print is a Python keyword.
template <class T>
inline void dump(std::ostream& a_out,const tools::array<T>& a_array,const std::string& a_title){
if(a_title.size()) a_out << a_title << std::endl;
const std::vector<T>& vec = a_array.vector();
typedef typename std::vector<T>::const_iterator cons_vec_it_t;
for(cons_vec_it_t it = vec.begin();it!=vec.end();++it) {
a_out << (*it) << std::endl;
}
}
template <class T>
inline void diff(std::ostream& a_out,const array<T>& aA,const array<T>& aB,T a_epsilon){
if(aA.orders()!=aB.orders()) {
a_out << "tools::arrays::diff : not same orders" << std::endl;
return;
}
bool header_done = false;
unsigned int dim = aA.dimension();
std::vector<unsigned int> is(dim);
unsigned int vsize = aA.vector().size();
for(unsigned int index=0;index<vsize;index++) {
T diff = aA.vector()[index]-aB.vector()[index];
if(diff<0) diff *= -1;
if(diff>=a_epsilon) {
aA.indices(index,is);
if(!header_done) {
a_out << "tools::arrays::diff :" << std::endl;
header_done = true;
}
for(unsigned int i=0;i<dim;i++) a_out << is[i] << " ";
a_out << aA.vector()[index] << " " << aB.vector()[index] << std::endl;
}
}
}
//////////////////////////////////////////////////////////////////////////////
/// common array /////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
template <class T>
class kronecker : public array<T> {
public:
kronecker(unsigned int a_order):array<T>(a_order,a_order){
// epsilon(i1,i2,....in) with n = a_order and i in [0,n[.
// Then an Array of a_order * a_order.
unsigned int index = 0;
typedef typename std::vector<unsigned int> _uints_t;
_uints_t is(a_order);
std::vector<T>& vec = array<T>::vector();
typedef typename std::vector<T>::iterator _vec_it_t;
_vec_it_t it = vec.begin();
for(;it!=vec.end();++it,index++) {
if(!array<T>::indices(index,is)) return; //FIXME throw.
bool good = true;
{for(unsigned int iaxis=0;iaxis<a_order;iaxis++) {
unsigned int ival = is[iaxis];
for(unsigned int iaxis2=iaxis+1;iaxis2<a_order;iaxis2++) {
if(is[iaxis2]==ival) {
good = false;
break;
}
}
if(!good) break;
}}
if(!good) continue;
// All indicies are different.
unsigned int n = 0;
for(unsigned int iaxis=0;iaxis<a_order;) {
unsigned int ival = is[iaxis];
if(ival!=iaxis) {
// Swap and add one permutation :
unsigned int old = is[ival];
is[ival] = ival;
is[iaxis] = old;
n +=1;
} else {
iaxis++;
}
}
{unsigned int n_2 = n/2;
if(2*n_2==n) (*it) = array<T>::one();
else (*it) = array<T>::minus_one();}
}
}
};
template <class T>
inline array<T> operator+(const array<T>& a1,const array<T>& a2) {
array<T> res(a1);
if(!res.add(a2)) {}
return res;
}
template <class T>
inline array<T> operator-(const array<T>& a1,const array<T>& a2) {
array<T> res(a1);
if(!res.subtract(a2)) {}
return res;
}
template <class T>
inline array<T> operator*(const T& a_fac,const array<T>& a_m) {
array<T> res(a_m);
res *= a_fac;
return res;
}
}
#endif