/* for documentation see tensor.h Author: Raimundo Sierra www.rsierra.com Copyright: Copyright (c) 2000 Raimundo Sierra. All rights reserved. LICENSE: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "tensor.h" #ifdef debug int tensorcounter=0; // counts calls to constructors int tensordestructorcounter=0; // counst calls to destructors #endif //constructors /* matrix is linearised (efficiency!) / t1, t2, t3 \ | t4, t5, t6 | \ t7, t8, t9 / corresponds to /_t[0], _t[1], _t[2] \ |_t[3], _t[4], _t[5] | \_t[6], _t[7], _t[8] / which formerly was /_t[0][0], _t[0][1], _t[0][2] \ |_t[1][0], _t[1][1], _t[1][2] | \_t[2][0], _t[2][1], _t[2][2] / */ tensor::tensor() { _t[0]= 0; _t[1]= 0; _t[2]= 0; _t[3]= 0; _t[4]= 0; _t[5]= 0; _t[6]= 0; _t[7]= 0; _t[8] = 0.0; #ifdef debug tensorcounter++; if(tensorcounter%10000 == 0){ //cout << "tensorcounter in tensor() is: "<=b && b>=c){ i[0]=0; i[1]=1; i[2]=2; } else if(a>=c && c>=b){ i[0]=0; i[1]=2; i[2]=1; } else if(b>=a && a>=c){ i[0]=1; i[1]=0; i[2]=2; } else if(b>=c && c>=a){ i[0]=1; i[1]=2; i[2]=0; } else if(c>=a && a>=b){ i[0]=2; i[1]=0; i[2]=1; } else if(c>=b && b>=a){ i[0]=2; i[1]=1; i[2]=0; } else { cout << "\n\nError in tensor.h eigsort()\n" "Values are: a: "<isZero()){ cout << "Eigenvalue 1 is zero, eigenvalue 2 and/or 3 not\n"; return -3; } #endif vector1[0] = float(A[w[0]*3]); vector1[1] = float(A[w[0]*3+1]); vector1[2] = float(A[w[0]*3+2]); vector2[0] = float(A[w[1]*3]); vector2[1] = float(A[w[1]*3+1]); vector2[2] = float(A[w[1]*3+2]); vector3[0] = float(A[w[2]*3]); vector3[1] = float(A[w[2]*3+1]); vector3[2] = float(A[w[2]*3+2]); } else { eig1 = W[0]; eig2 = W[1]; eig3 = W[2]; vector1[0] = A[0]; vector1[1] = A[1]; vector1[2] = A[2]; vector2[0] = A[3]; vector2[1] = A[4]; vector2[2] = A[5]; vector3[0] = A[6]; vector3[1] = A[7]; vector3[2] = A[8]; } delete[] A; delete[] B; delete[] w; delete[] W; delete[] WORK; return 1; } int tensor::svd( float &r1, float &r2, float &r3, tensor &s, tensor &q) //tensor::svd( float &r1, float &r2, float &r3, tensor &q, tensor &s) { if(isZero()){ r1 = 0; r2 = 0; r3 = 0; q.setZero(); s.setZero(); return 1; } // the following variables are used to call the function dsygv_ from the CLAPACK library integer l, ans, lwork; char jobu = 'A'; char jobvt = 'A'; //char n = 'V'; //k = 2; l = 3; lwork = 20; // tells how much memory to use in clapack, can probably be optimized float * S = new float[3]; float * A = new float[9]; // input: tensormatrix, output: eigenvectors float * U = new float[9]; // float * VT = new float[9]; // //float * W = new float[3]; // resultvector containing eigenvalues float * WORK = new float[lwork]; A[0] = float(_t[0]) ; // convert tensor to single row array in CLAPACK format A[1] = float(_t[1]) ; // A[1] A[2] = float(_t[2]) ; // A[2] A[3] = float(_t[3]) ; /* A[3] / 0 1 2 \ */ A[4] = float(_t[4]) ; /* A[4] | 3 4 5 | */ A[5] = float(_t[5]) ; /* A[5] \ 6 7 8 / */ A[6] = float(_t[6]) ; // A[6] A[7] = float(_t[7]) ; // A[7] A[8] = float(_t[8]) ; // A[8] ans = sgesvd_(&jobu, &jobvt, &l, &l, A, &l, S, U, &l, VT, &l, WORK, &lwork, &ans); //#ifdef debug if (ans != 0){ cout << "An error ocurred when calling lapack function sgesvd_() in function svd() in tensor.h\n"; return -2; } //#endif r1 = S[0]; r2 = S[1]; r3 = S[2]; q.set(U[0], U[1], U[2], U[3], U[4], U[5], U[6], U[7], U[8]); s.set(VT[0], VT[1], VT[2], VT[3], VT[4], VT[5], VT[6], VT[7], VT[8]); delete[] A; delete[] S; delete[] U; delete[] VT; delete[] WORK; return 1; } float* tensor::eigvec1(float *eigvec1) const { if(this->isZero()){ eigvec1[0] = eigvec1[1] = eigvec1[2] = 0.0; return eigvec1; } float eigvec2[3], eigvec3[3]; float eigval1, eigval2, eigval3; eig( eigval1, eigval2, eigval3, eigvec1, eigvec2, eigvec3, 1); return eigvec1; } float* tensor::eigvec2(float *eigvec2) const { if(this->isZero()){ eigvec2[0] = eigvec2[1] = eigvec2[2] = 0.0; return eigvec2; } float eigvec1[3], eigvec3[3]; float eigval1, eigval2, eigval3; eig( eigval1, eigval2, eigval3, eigvec1, eigvec2, eigvec3, 1); return eigvec2; } float* tensor::eigvec3(float *eigvec3) const { if(this->isZero()){ eigvec3[0] = eigvec3[1] = eigvec3[2] = 0.0; return eigvec3; } float eigvec1[3], eigvec2[3]; float eigval1, eigval2, eigval3; eig( eigval1, eigval2, eigval3, eigvec1, eigvec2, eigvec3, 1); return eigvec3; } float tensor::eigval1() const { if(this->isZero()) return 0; float eigvec1[3], eigvec2[3], eigvec3[3]; float eigval1, eigval2, eigval3; eig( eigval1, eigval2, eigval3, eigvec1, eigvec2, eigvec3, 1); return eigval1; } float tensor::eigval2() const { if(this->isZero()) return 0; float eigvec1[3], eigvec2[3], eigvec3[3]; float eigval1, eigval2, eigval3; eig( eigval1, eigval2, eigval3, eigvec1, eigvec2, eigvec3, 1); return eigval2; } float tensor::eigval3() const { if(this->isZero()) return 0; float eigvec1[3], eigvec2[3], eigvec3[3]; float eigval1, eigval2, eigval3; eig( eigval1, eigval2, eigval3, eigvec1, eigvec2, eigvec3, 1); return eigval3; } float tensor::anisotropy() const { if(this->isZero()) return 1; float eigvec1[3], eigvec2[3], eigvec3[3]; float eigval1, eigval2, eigval3; eig( eigval1, eigval2, eigval3, eigvec1, eigvec2, eigvec3, 1); return (1 - eigval3/eigval1); } bool tensor::operator== (const tensor &t) const { for(int i=0; i<9; i++){ if (_t[i] != t._t[i]) return false; } return true; } bool tensor::operator!= (const tensor &t) const { int tmp=0; for(int i=0; i<9; i++){ if (_t[i] != t._t[i]) tmp=1; } if(tmp==1) return true; return false; } bool tensor::operator< (const tensor &t) const { //cout << "DEBUG: operator < this->euclid "<euclid()<< "and t.euclid() "<measure() < t.measure()) return true; return false; } bool tensor::operator> (const tensor &t) const { if(this->measure() > t.measure()) return true; return false; } bool tensor::operator<= (const tensor &t) const { if(this->measure() > t.measure()) return false; return true; } bool tensor::operator>= (const tensor &t) const { if(this->measure() < t.measure()) return false; return true; } //functions void tensor::scale(const float factor) { for(int i=0; i<9; i++){ _t[i] = float(double(factor)*double(_t[i])); } } float tensor::det() const { return float(double(_t[0])*double(_t[4])*double(_t[8]) + double(_t[3])*double(_t[7])*double(_t[2]) + double(_t[6])*double(_t[1])*double(_t[5]) - double(_t[0])*double(_t[5])*double(_t[7]) - double(_t[1])*double(_t[3])*double(_t[8]) - double(_t[2])*double(_t[4])*double(_t[6])); } float tensor::trace() const { return _t[0] + _t[4] + _t[8]; } tensor tensor::inv(tensor &result) const { result._t[0] = _t[8]*_t[4] - _t[5]*_t[7]; result._t[1] = _t[2]*_t[7] - _t[8]*_t[1]; result._t[2] = _t[1]*_t[5] - _t[2]*_t[4]; result._t[3] = _t[5]*_t[6] - _t[8]*_t[3]; result._t[4] = _t[8]*_t[0] - _t[2]*_t[6]; result._t[5] = _t[2]*_t[3] - _t[0]*_t[5]; result._t[6] = _t[3]*_t[7] - _t[4]*_t[6]; result._t[7] = _t[1]*_t[6] - _t[0]*_t[7]; result._t[8] = _t[0]*_t[4] - _t[1]*_t[3]; float tmp = det(); if(tmp==0) { cerr <<"WARNING: Dividing by zero in tensor.h inv() "; #ifdef debug cout << endl; this->print(); cout << endl; #endif cout <<"Setting tensor to zero\n"; result.setZero(); return result; } result = result/tmp; return result; } tensor tensor::trans(tensor &result) const { result._t[0] = _t[0]; result._t[1] = _t[3]; result._t[2] = _t[6]; result._t[3] = _t[1]; result._t[4] = _t[4]; result._t[5] = _t[7]; result._t[6] = _t[2]; result._t[7] = _t[5]; result._t[8] = _t[8]; return result; } float tensor::euclid() const { float tmp = 0; for(int i=0; i<9; i++){ tmp = tmp + _t[i]*_t[i]; } return sqrt(tmp); } float tensor::Max() const { float tmp = -INF; for(int i=0; i<9; i++){ if(_t[i] > tmp) tmp = _t[i]; } return tmp; } float tensor::Min() const { float tmp = INF; for(int i=0; i<9; i++){ if(_t[i] < tmp) tmp = _t[i]; } return tmp; } void tensor::print() const { cout << "Tensor values:\n"; cout << "\t[ " << _t[0] << "\t" << _t[1] << "\t" << _t[2] << " ;\n"; cout << "\t " << _t[3] << "\t" << _t[4] << "\t" << _t[5] << " ;\n"; cout << "\t " << _t[6] << "\t" << _t[7] << "\t" << _t[8] << " ]\n"; } void tensor::set(float t1, float t2, float t3, float t4, float t5, float t6) { _t[0] = t1; _t[1] = t4; _t[2] = t5; _t[3] = t4; _t[4] = t2; _t[5] = t6; _t[6] = t5; _t[7] = t6; _t[8] = t3; } void tensor::set(float t1, float t2, float t3, float t4, float t5, float t6, float t7, float t8, float t9) { #ifdef debug if(t4!=t2 || t7!=t3 || t8!=t6){ cout << "WARNING: setting non-symmetric tensor!\n"; } #endif _t[0] = t1; _t[1] = t2; _t[2] = t3; _t[3] = t4; _t[4] = t5; _t[5] = t6; _t[6] = t7; _t[7] = t8; _t[8] = t9; } void tensor::setZero() { _t[0] = 0.0; _t[1] = 0.0; _t[2] = 0.0; _t[3] = 0.0; _t[4] = 0.0; _t[5] = 0.0; _t[6] = 0.0; _t[7] = 0.0; _t[8] = 0.0; } /* void tensor::makeSymmetric() { _t[1] = (_t[1] + _t[3])/2; _t[2] = (_t[2] + _t[6])/2; _t[5] = (_t[5] + _t[7])/2; _t[3] = _t[1]; _t[6] = _t[2]; _t[7] = _t[5]; } */ float tensor::get(const int i, const int j) const { if ( i<0 || i>2 || j<0 || j>2){ cout <<"Not a valid tensor range: 0