2
/// This file is part of Rheolef.
4
/// Copyright (C) 2000-2009 Pierre Saramito <Pierre.Saramito@imag.fr>
6
/// Rheolef is free software; you can redistribute it and/or modify
7
/// it under the terms of the GNU General Public License as published by
8
/// the Free Software Foundation; either version 2 of the License, or
9
/// (at your option) any later version.
11
/// Rheolef is distributed in the hope that it will be useful,
12
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
/// GNU General Public License for more details.
16
/// You should have received a copy of the GNU General Public License
17
/// along with Rheolef; if not, write to the Free Software
18
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
/// =========================================================================
22
// point : set of coordinates
24
// author: Pierre.Saramito@imag.fr
26
#include "rheolef/tensor.h"
27
#include "rheolef/tensor-eig3.h"
28
#include "rheolef/tensor-svd-algo.h"
29
using namespace rheolef;
37
tensor::put (ostream& out, size_type d) const
41
case 1 : return out << _x[0][0];
42
case 2 : return out << "[" << _x[0][0] << ", " << _x[0][1] << ";\n"
43
<< " " << _x[1][0] << ", " << _x[1][1] << "]";
44
default: return out << "[" << _x[0][0] << ", " << _x[0][1] << ", " << _x[0][2] << ";\n"
45
<< " " << _x[1][0] << ", " << _x[1][1] << ", " << _x[1][2] << ";\n"
46
<< " " << _x[2][0] << ", " << _x[2][1] << ", " << _x[2][2] << "]";
50
tensor::get (istream& in)
52
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
55
if (!in.good()) return in;
57
// no tensor specifier:
61
return in >> _x[0][0];
63
// has a tensor specifier, as:
65
in >> _x[0][0] >> ws >> c;
66
if (c == ']') return in; // 1d case
67
if (c != ',') error_macro ("invalid tensor input: expect `,'");
72
else if (c == ';') d = 2;
73
else error_macro ("invalid tensor input: expect `,' or `;'");
75
in >> _x[0][2] >> ws >> c;
76
if (c != ';') error_macro ("invalid tensor input: expect `;'");
78
in >> _x[1][0] >> ws >> c;
79
if (c != ',') error_macro ("invalid tensor input: expect `,'");
80
in >> _x[1][1] >> ws >> c;
82
if (c != ']') error_macro ("invalid tensor input: expect `]'");
86
if (c != ',') error_macro ("invalid tensor input: expect `,'");
87
in >> _x[1][2] >> ws >> c;
88
if (c != ';') error_macro ("invalid tensor input: expect `;'");
89
in >> _x[2][0] >> ws >> c;
90
if (c != ',') error_macro ("invalid tensor input: expect `,'");
91
in >> _x[2][1] >> ws >> c;
92
if (c != ',') error_macro ("invalid tensor input: expect `,'");
93
in >> _x[2][2] >> ws >> c;
94
if (c != ']') error_macro ("invalid tensor input: expect `]'");
97
bool operator == (const tensor& a, const tensor& b)
99
typedef tensor::size_type size_type;
100
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
101
if (a._x[i][j] != b._x[i][j]) return false;
104
tensor operator - (const tensor& a)
107
typedef tensor::size_type size_type;
108
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
109
b._x[i][j] = - a._x[i][j];
112
tensor operator + (const tensor& a, const tensor& b)
115
typedef tensor::size_type size_type;
116
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
117
c._x[i][j] = a._x[i][j] + b._x[i][j];
120
tensor operator - (const tensor& a, const tensor& b)
123
typedef tensor::size_type size_type;
124
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
125
c._x[i][j] = a._x[i][j] - b._x[i][j];
128
tensor operator * (Float k, const tensor& a)
131
typedef tensor::size_type size_type;
132
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
133
b._x[i][j] = k * a._x[i][j];
136
point operator * (const tensor& a, const point& x)
139
typedef tensor::size_type size_type;
140
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
141
y [i] += a._x[i][j] * x[j];
144
point operator * (const point& x, const tensor& a)
147
typedef tensor::size_type size_type;
148
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
149
y [i] += a._x[j][i] * x[j];
153
trans (const tensor& a, tensor::size_type d) {
155
typedef tensor::size_type size_type;
156
for (size_type i = 0; i < d; i++) for (size_type j = 0; j < d; j++)
157
b._x[i][j] = a._x[j][i];
161
inv (const tensor& a, tensor::size_type d) {
163
typedef tensor::size_type size_type;
171
Float det = a.determinant(2);
174
b(0,1) = - a(0,1)/det;
175
b(1,0) = - a(1,0)/det;
180
Float det = a.determinant(3);
181
b(0,0) = (a(1,1)*a(2,2) - a(1,2)*a(2,1))/det;
182
b(0,1) = (a(0,2)*a(2,1) - a(0,1)*a(2,2))/det;
183
b(0,2) = (a(0,1)*a(1,2) - a(0,2)*a(1,1))/det;
184
b(1,0) = (a(1,2)*a(2,0) - a(1,0)*a(2,2))/det;
185
b(1,1) = (a(0,0)*a(2,2) - a(0,2)*a(2,0))/det;
186
b(1,2) = (a(0,2)*a(1,0) - a(0,0)*a(1,2))/det;
187
b(2,0) = (a(1,0)*a(2,1) - a(1,1)*a(2,0))/det;
188
b(2,1) = (a(0,1)*a(2,0) - a(0,0)*a(2,1))/det;
189
b(2,2) = (a(0,0)*a(1,1) - a(0,1)*a(1,0))/det;
195
tensor operator * (const tensor& a, const tensor& b)
198
typedef tensor::size_type size_type;
199
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
200
for (size_type k = 0; k < 3; k++)
201
c._x[i][j] += a._x[i][k] * b._x[k][j];
204
Float dotdot (const tensor& a, const tensor & b) {
206
typedef tensor::size_type size_type;
207
for (size_type i = 0; i < 3; i++) for (size_type j = 0; j < 3; j++)
208
r += a._x[i][j] * b._x[i][j];
212
tensor::determinant (size_type d) const
215
case 1 : return _x[0][0];
216
case 2 : return _x[0][0]*_x[1][1] - _x[0][1]*_x[1][0];
217
case 3 : return _x[0][0]*(_x[1][1]*_x[2][2] - _x[1][2]*_x[2][1])
218
- _x[0][1]*(_x[1][0]*_x[2][2] - _x[1][2]*_x[2][0])
219
+ _x[0][2]*(_x[1][0]*_x[2][1] - _x[1][1]*_x[2][0]);
221
error_macro ("determinant: unexpected dimension " << d);
227
cumul_otimes (tensor& t, const point& a, const point& b, size_t na, size_t nb)
229
for (size_t i = 0; i < na; i++)
230
for (size_t j = 0; j < nb; j++)
231
t(i,j) += a[i] * b[j];
234
tensor::row(size_type i) const
243
tensor::col(size_type j) const
252
invert_3x3 (const tensor& A, tensor& result) {
253
Float det = determinant(A);
254
if (1+det == 1) return false;
255
Float invdet = 1.0/det;
256
result(0,0) = (A(1,1)*A(2,2)-A(2,1)*A(1,2))*invdet;
257
result(1,0) = -(A(0,1)*A(2,2)-A(0,2)*A(2,1))*invdet;
258
result(2,0) = (A(0,1)*A(1,2)-A(0,2)*A(1,1))*invdet;
259
result(0,1) = -(A(1,0)*A(2,2)-A(1,2)*A(2,0))*invdet;
260
result(1,1) = (A(0,0)*A(2,2)-A(0,2)*A(2,0))*invdet;
261
result(2,1) = -(A(0,0)*A(1,2)-A(1,0)*A(0,2))*invdet;
262
result(0,2) = (A(1,0)*A(2,1)-A(2,0)*A(1,1))*invdet;
263
result(1,2) = -(A(0,0)*A(2,1)-A(2,0)*A(0,1))*invdet;
264
result(2,2) = (A(0,0)*A(1,1)-A(1,0)*A(0,1))*invdet;
267
// ------------------------------------------
268
// eigenvalues: the 3D case
269
// ------------------------------------------
270
static point eig3x3 (const tensor& a, tensor& q)
273
for (size_t i = 0; i < 3; i++)
274
for (size_t j = 0; j < 3; j++)
278
eigen_decomposition(A, Q, D);
280
for (size_t i = 0; i < 3; i++) {
282
for (size_t j = 0; j < 3; j++)
287
// ------------------------------------------
288
// eigenvalues: the 2D case
289
// ------------------------------------------
290
static point eig2x2 (const tensor& a, tensor& q)
292
// TODO: check if a is symetric !
295
// a is already diagonal
296
if (a(0,0) >= a(1,1)) {
301
} else { // swap column 0 & 1:
310
Float discr = sqr(a(1,1) - a(0,0)) + 4*sqr(a(0,1));
311
Float trace = a(0,0) + a(1,1);
312
d[0] = (trace + ::sqrt(discr))/2;
313
d[1] = (trace - ::sqrt(discr))/2;
314
Float lost_precision = 1e-6;
315
if (fabs(d[0]) + lost_precision*fabs(d[1]) == fabs(d[0])) { // d[1] == 0 up to machine precision
318
Float c0 = (d[0]-a(0,0))/a(0,1);
319
Float n0 = ::sqrt(1+sqr(c0));
322
Float c1 = (d[1]-a(0,0))/a(0,1);
323
Float n1 = ::sqrt(1+sqr(c1));
328
// ------------------------------------------
329
// eigenvalues: general case
330
// ------------------------------------------
332
tensor::eig (tensor& q, size_t d) const
337
q(0,0) = 1; d[0] = operator()(0,0); return d;
339
case 2 : return eig2x2 (*this, q);
340
default: return eig3x3 (*this, q);
344
tensor::eig (size_t d) const
349
// ------------------------------------------
351
// ------------------------------------------
353
tensor::svd (tensor& u, tensor& v, size_t dim) const
356
for (size_t i = 0; i < dim; i++)
357
for (size_t j = 0; j < dim; j++)
358
U[i][j] = operator()(i,j);
361
svdcmp (U, S, V, dim, dim, Float(0));
362
// Sort eigenvalues and corresponding vectors.
363
for (size_t i = 0; i < dim-1; i++) {
366
for (size_t j = i+1; j < dim; j++) {
375
for (size_t j = 0; j < dim; j++) {
385
// copy to tensor and point
387
for (size_t i = 0; i < dim; i++) {
389
for (size_t j = 0; j < dim; j++) {
396
}// namespace rheolef