626 lines
17 KiB
Plaintext
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
|