00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <qvmath.h>
00026 #include <QVTensor>
00027
00028 bool QVTensor::equals(const QVTensor &tensor) const
00029 {
00030 Q_ASSERT(dims.size() == indexIds.size());
00031 Q_ASSERT(tensor.dims.size() == tensor.indexIds.size());
00032
00034
00035
00036 if (dims != tensor.dims)
00037 return false;
00038
00039 for (int i = 0; i < indexIds.size(); i++)
00040 if (indexIds[i] * tensor.indexIds[i] < 0 )
00041 return false;
00042
00043
00044 const double *data1 = getReadData(),
00045 *data2 = tensor.getReadData();
00046
00047 for (int i = 0; i < getDataSize(); i++)
00048 if (data1[i] != data2[i])
00049 return false;
00050
00051 return true;
00052 }
00053
00054 QVTensor QVTensor::tensorProduct(const QVTensor &tensor) const
00055 {
00056 Q_ASSERT(dims.size() == indexIds.size());
00057
00058 QVTensorValence indexList;
00059
00060 for (int i = 0; i < getValence().size(); i++)
00061 indexList.append(getValence()[i]);
00062
00063 for (int i = 0; i < tensor.getValence().size(); i++)
00064 indexList.append(tensor.getValence()[i]);
00065
00066 QVTensor result(indexList);
00067
00068 const double *src1Data = getReadData();
00069 const double *src2Data = tensor.getReadData();
00070 double *destData = result.getWriteData();
00071 const int vectorSize = tensor.getDataSize();
00072
00073 for (int i = 0, destIndex = 0; i < getDataSize(); i++, destIndex += vectorSize)
00074 {
00075 cblas_dcopy(vectorSize, src2Data, 1, &(destData[destIndex]), 1);
00076 cblas_dscal(vectorSize, src1Data[i], &(destData[destIndex]), 1);
00077 }
00078
00079 return result;
00080 }
00081
00082 QVTensor QVTensor::add(const QVTensor &tensor) const
00083 {
00084 Q_ASSERT(dims.size() == indexIds.size());
00086
00087 QVTensor result = *this;
00088
00089 const double *tensorData = tensor.getReadData();
00090 double *resultData = result.getWriteData();
00091
00092
00094
00095 for (int i = 0; i < getDataSize(); i++)
00096 resultData[i] += tensorData[i];
00097
00098 return result;
00099 }
00100
00101 QVTensor QVTensor::substract(const QVTensor &tensor) const
00102 {
00103 Q_ASSERT(dims.size() == indexIds.size());
00106
00107 QVTensor result = *this;
00108
00109 const double *tensorData = tensor.getReadData();
00110 double *resultData = result.getWriteData();
00111
00112
00113 for (int i = 0; i < getDataSize(); i++)
00114 resultData[i] -= tensorData[i];
00115
00116 return result;
00117 }
00118
00119 QVTensor QVTensor::innerProduct(const QVTensor &tensor) const
00120 {
00121 Q_ASSERT(dims.size() == indexIds.size());
00122
00123 const QMap<int, QVector<int> > indexesQVTensor1 = getValence().getIndexesPositions(),
00124 indexesQVTensor2 = tensor.getValence().getIndexesPositions();
00125
00126 int actualIndexSize = 0, actualQVTensor1Position = -1, actualQVTensor2Position = -1;
00127
00128 QMapIterator< int, QVector<int> > idx(indexesQVTensor1);
00129
00130 while (idx.hasNext())
00131 {
00132 idx.next();
00133 const int key = idx.key();
00134 const QVector<int> positionsIndex1 = indexesQVTensor1[key], positionsIndex2 = indexesQVTensor2[key];
00135
00136 if (positionsIndex1.size() > 1)
00137 std::cerr << "ERROR, índice repetido en primer tensor de producto *." << std::endl;
00138 else if (positionsIndex2.size() > 1)
00139 std::cerr << "ERROR, índice repetido en segundo tensor de producto *." << std::endl;
00140
00141 else if (positionsIndex1.size() == 1 && positionsIndex2.size() == 1)
00142 {
00143 const int position1 = positionsIndex1[0], position2 = positionsIndex2[0];
00144 const int indexSize = dims[position1];
00145
00146 if (indexIds[position1] == tensor.indexIds[position2])
00147 std::cerr << "ERROR, índices iguales en ambos tensores en producto *." << std::endl;
00148 else
00149 if (indexSize > actualIndexSize)
00150 {
00151 actualIndexSize = indexSize;
00152 actualQVTensor1Position = position1;
00153 actualQVTensor2Position = position2;
00154 }
00155 }
00156 }
00157
00158 if (actualQVTensor1Position == -1 && actualQVTensor2Position == -1)
00159 return this->tensorProduct(tensor).contract();
00160 else if (actualQVTensor1Position == -1 || actualQVTensor2Position == -1)
00161 std::cerr << "ERROR, posición para el índice dominante no definida en producto *." << std::endl;
00162
00163
00164 QVTensorValence indexList1 = this->getValence(), indexList2 = tensor.getValence();
00165
00166 QVTensor t1 = this->transpose(actualQVTensor1Position, dims.size()-1), t2 = tensor.transpose(actualQVTensor2Position, 0);
00167
00168 indexList1.removeAt(actualQVTensor1Position);
00169 indexList2.removeAt(actualQVTensor2Position);
00170
00171 QVTensorValence resultIndexList;
00172 resultIndexList << indexList1 << indexList2;
00173 QVTensor result(resultIndexList);
00174
00175 const int k = t2.dims[0], m = t1.getDataSize() / k, n = t2.getDataSize() / k;
00176
00177 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
00178 m, n, k, 1.0,
00179 t1.getReadData(), k,
00180 t2.getReadData(), n, 0.0,
00181 result.getWriteData(), n);
00182
00183 return result;
00184 };
00185
00186 QVTensor QVTensor::outerProduct(const QVTensor &) const
00187 {
00189 return *this;
00190 }
00191
00192 QVTensor QVTensor::renameIndexes(const QVTensorValence &indexList) const
00193 {
00194 Q_ASSERT(dims.size() == indexIds.size());
00197 QVTensor result = *this;
00198
00199 for (int i = 0; i < indexList.size(); i++)
00200 result.indexIds[i] = indexList.at(i).id;
00201
00202 return result.contract();
00203 }
00204
00206
00207 QVTensorValence QVTensor::getValence() const
00208 {
00209 Q_ASSERT(dims.size() == indexIds.size());
00210
00211 QVTensorValence result;
00212 for (int i = 0; i < dims.size(); i++)
00213 result.append(QVTensorIndex(dims[i], indexIds[i]));
00214 return result;
00215 }
00216
00217 QVTensor QVTensor::slice(const QVTensorIndexValues &indexRangeList) const
00218 {
00219 Q_ASSERT(dims.size() == indexIds.size());
00220 const int numDims = dims.size();
00221
00222 QVTensorIterator tensorIterator(dims, indexIds, indexRangeList);
00223 QVTensorValence idxList;
00224
00225 for (int i=0; i< numDims; i++)
00226 if (tensorIterator.numElementsDimension(i) > 1)
00227 idxList.append(QVTensorIndex(tensorIterator.numElementsDimension(i), indexIds[i]));
00228
00229 QVTensor result(idxList);
00230
00231 double const *srcData = getReadData();
00232 double *destData = result.getWriteData();
00233 int destIndexValue = -tensorIterator.getVectorSize();
00234
00235 do cblas_dcopy(tensorIterator.getVectorSize(), &(srcData[tensorIterator.getVectorIndex()]), 1, &(destData[destIndexValue += tensorIterator.getVectorSize()]),1);
00236 while (tensorIterator.nextVector());
00237
00238 return result;
00239 }
00240
00241 QVTensor QVTensor::transpose(const QVTensorIndex &index1, const QVTensorIndex &index2) const
00242 {
00243 Q_ASSERT(dims.size() == indexIds.size());
00244
00245 int index1Position = -1, index2Position = -1;
00246
00247 if (index1.id == index2.id)
00248 return *this;
00249
00250 for (int n = 0; n< dims.size(); n++)
00251 {
00252 if (indexIds[n] == index1.id)
00253 index1Position = n;
00254 if (indexIds[n] == index2.id)
00255 index2Position = n;
00256 }
00257
00258 if (index1Position == -1 || index2Position == -1)
00259 std::cerr << "ERROR, index not found in transpose." << std::endl;
00260
00261 return transpose(index1Position, index2Position);
00262 }
00263
00264 QVTensor QVTensor::transpose(const QVTensorValence &indexList) const
00265 {
00266 Q_ASSERT(dims.size() == indexIds.size());
00267
00268 QMap<int, QVector<int> > indexes = indexList.getIndexesPositions();
00269 for (int i = 0; i < indexIds.size(); i++)
00270 if (!indexes.contains(ABS(indexIds[i])))
00271 std::cerr << "ERROR, index " << indexIds[i] << " not found in transpose." << std::endl;
00272
00273 QVector< int > order(indexIds.size());
00274 for (int i = 0; i < order.size(); i++)
00275 order[i] = indexes[ABS(indexIds[i])][0];
00276
00277 return transpose(order);
00278 }
00279
00280 QVector<int> getSorting(const QVector<int> &values)
00281 {
00282 QVector<int> result(values.size()-1), dupe = values;
00283 for (int i = 0; i < values.size() -1; i++)
00284 {
00285 int pivote = i;
00286 for (int j = i+1; j < values.size(); j++)
00287 if (dupe[pivote] > dupe[j])
00288 pivote = j;
00289 result[i] = pivote;
00290
00291
00292 const int temp = dupe[i];
00293 dupe[i] = dupe[pivote];
00294 dupe[pivote] = temp;
00295 }
00296 return result;
00297 }
00298
00299 QVTensor QVTensor::transpose(const int index1Position, const int index2Position) const
00300 {
00301 Q_ASSERT(dims.size() == indexIds.size());
00302
00303
00304 if (index1Position == index2Position)
00305 return *this;
00306
00307 QVector <int> order(dims.size());
00308 for (int i = 0; i < order.size(); i++)
00309 order[i] = i;
00310
00311 order[MIN(index1Position, index2Position)] = MAX(index1Position, index2Position);
00312 order[MAX(index1Position, index2Position)] = MIN(index1Position, index2Position);
00313
00314 return transpose(order);
00315 }
00316
00317 QVTensor QVTensor::transpose(const QVector<int> &order) const
00318 {
00319 Q_ASSERT(dims.size() == indexIds.size());
00320
00321
00322 QVector<int> sorting = getSorting(order);
00323
00324 QVTensorValence idxList = getValence();
00325
00326 bool orderedIndexes = true;
00327 int maxIndexPosition = 0;
00328 for (int i = 0; i < sorting.size(); i++)
00329 if (i != sorting[i])
00330 {
00331 idxList.swap(i, maxIndexPosition = sorting[i]);
00332 orderedIndexes = false;
00333 }
00334
00335
00336 if (orderedIndexes)
00337 return *this;
00338
00339 QVTensor result(idxList);
00340
00341 QVTensorIndexator indexator(result.dims);
00342 const int vectorSize = indexator.getStep(maxIndexPosition);
00343 for (int i = sorting.size()-1; i >=0; i--)
00344 if (i != sorting[i])
00345 indexator.swapIndexes(i, sorting[i]);
00346
00347 QVTensorIterator tensorIterator(indexator, maxIndexPosition);
00348
00349 const double *srcData = getReadData();
00350 double *destData = result.getWriteData();
00351 int destIndexValue = -vectorSize;
00352
00353 do cblas_dcopy(vectorSize, &(srcData[destIndexValue += vectorSize]), 1, &(destData[tensorIterator.getVectorIndex()]),1);
00354 while (tensorIterator.nextVector());
00355
00356 return result;
00357 }
00358
00359 QVTensor QVTensor::contract() const
00360 {
00361 Q_ASSERT(dims.size() == indexIds.size());
00362
00363 const QMap< int, QVector<int> > map = getValence().getIndexesPositions();
00364
00365
00366 QVector<int> variableIndexesPositions, fixedIndexesPositions;
00367 QVector<int> variableDims;
00368 QVTensorValence fixedIndexList;
00369
00370 bool dupedIndexes = false;
00371 QMapIterator< int, QVector<int> > idx(map);
00372 while (idx.hasNext())
00373 {
00374 idx.next();
00375 QVector<int> v = idx.value();
00376
00377 switch(v.size())
00378 {
00379 case 1:
00380 fixedIndexesPositions.append(v[0]);
00381 fixedIndexList.append(QVTensorIndex(dims[v[0]],indexIds[v[0]]));
00382 break;
00383 case 2:
00384 if (indexIds[v[0]] != -indexIds[v[1]])
00385 std::cerr << "ERROR: two index apperances are not covariant: "
00386 << indexIds[v[0]] << ", " << indexIds[v[1]] << std::endl;
00387 variableIndexesPositions.append(v[0]);
00388 variableIndexesPositions.append(v[1]);
00389 variableDims.append(dims[v[0]]);
00390 dupedIndexes = true;
00391 break;
00392 default:
00393 std::cerr << "ERROR: more than two index apperances in a tensor" << std::endl;
00394 break;
00395 }
00396 }
00397
00398
00399 if (!dupedIndexes)
00400 return *this;
00401
00402 QVector<int> inverseOrder = variableIndexesPositions + fixedIndexesPositions;
00403 QVector<int> order(inverseOrder.size());
00404 for (int i = 0; i < inverseOrder.size(); i++)
00405 order[inverseOrder[i]] = i;
00406
00407
00408 const QVTensor Transposed = transpose(order);
00409 QVTensor result(fixedIndexList);
00410
00411
00412 QVTensorIterator tensorIterator(variableDims);
00413 QVTensorIndexator indexator(Transposed.dims);
00414
00415 const double *srcData = Transposed.getReadData();
00416 double *destData = result.getWriteData();
00417 const int vectorSize = result.getDataSize();
00418
00419 for (int i = 0; i < vectorSize; i++)
00420 destData[i] = 0;
00421
00422 do {
00423 for (int i = 0; i < variableDims.size(); i++)
00424 {
00425 indexator.setIndex(2*i, tensorIterator.getIndex(i));
00426 indexator.setIndex(2*i+1, tensorIterator.getIndex(i));
00427 }
00428
00429 cblas_daxpy(vectorSize, 1, &(srcData[indexator.getMatrixIndex()]), 1, destData, 1);
00430 }
00431 while (tensorIterator.nextVector());
00432
00433 return result;
00434 }
00435
00436 double QVTensor::norm2() const
00437 {
00438 return sqrt(cblas_dnrm2(getDataSize(), getReadData(), 1));
00439 };
00440
00442
00443 void leviCivitaAux(double *data, QVTensorIndexator &indexator, int index, bool parity = true)
00444 {
00445 const int numIndex = indexator.getNumberOfDimensions();
00446
00447 if (index+1 == numIndex)
00448 {
00449
00450
00451
00452
00453
00454
00456 int accum = 0;
00457 for (int n = 0; n < numIndex; n++)
00458 accum = accum*numIndex + indexator.getIndex(n);
00459
00460
00461
00462 data[accum] = parity?1:-1;
00463 }
00464 else {
00465 leviCivitaAux(data, indexator, index+1, parity);
00466
00467 for (int i = index+1; i < numIndex; i++)
00468 {
00469 indexator.swapIndexes(index, i);
00470 leviCivitaAux(data, indexator, index+1, !parity);
00471 indexator.swapIndexes(index, i);
00472 }
00473 }
00474 }
00475
00476 QVTensor QVTensor::leviCivita(const int dimension)
00477 {
00478 QVTensorValence valence;
00479
00480 for (int i = 0; i < dimension; i++)
00481 valence = valence * QVTensorIndex(dimension);
00482
00483 QVTensor result(valence);
00484
00485 double *data = result.getWriteData();
00486 const int dataSize = result.getDataSize();
00487 for (int i = 0; i < dataSize; i++)
00488 data[i] = 0;
00489
00490 QVTensorIndexator indexator = result.getIndexator();
00491 for (int i = 0; i < dimension; i++)
00492 indexator.setIndex(i,i);
00493
00494 leviCivitaAux(data, indexator, 0);
00495
00496 return result;
00497 }
00498
00500
00501 #include <QString>
00502 std::ostream& operator << ( std::ostream &os, const QVTensor &tensor )
00503 {
00504 const QVector<int> dims = tensor.dims, indexIds = tensor.indexIds;
00505 const int numDims = dims.size();
00506
00507 Q_ASSERT(dims.size() == indexIds.size());
00508
00509 if (numDims == 0)
00510 {
00511 os << "QVTensor <> () [ " << tensor.getReadData()[0] << " ]";
00512 return os;
00513 }
00514
00515 os << "QVTensor <" << ((indexIds[0]<0)?"cov ":"") << ABS(indexIds[0]);
00516
00517 for (int i=1; i<numDims; i++)
00518 os << ", " << ((indexIds[i]<0)?"cov ":"") << ABS(indexIds[i]);
00519
00520 os << "> (" << dims[0];
00521
00522 for (int i=1; i<numDims; i++)
00523 os << " x " << dims[i];
00524
00525 os << ")" << std::endl;
00526
00527 const double *data = tensor.getReadData();
00528 QVTensorIterator tensorIterator(dims);
00529
00530 do {
00531 if (tensorIterator.getIndex(numDims-1) == 0)
00532 {
00533 int index = numDims-2;
00534 while(index >= 0 && tensorIterator.getIndex(index) == 0)
00535 index--;
00536
00537 for (int i = index; i< numDims-2; i++)
00538 os << qPrintable(QString(4*(i+1), ' ')) << "[" << std::endl;
00539
00540 os << qPrintable(QString(4*(numDims-1), ' ')) << "[ ";
00541 }
00542
00543 os << qPrintable(QString("%1").arg(data[tensorIterator.getVectorIndex()], -8, 'f', 6)) << " ";
00544
00545 if (tensorIterator.getIndex(numDims-1) == dims[numDims-1]-1)
00546 {
00547 os << "]" << std::endl;
00548 int index = numDims-2;
00549 while(index >= 0 && tensorIterator.getIndex(index) == dims[index]-1)
00550 index--;
00551
00552 for (int i = numDims-3; i>=index ; i--)
00553 os << qPrintable(QString(4*(i+1), ' ')) << "]" << std::endl;
00554 }
00555 } while (tensorIterator.nextVector());
00556
00557 return os;
00558 }
00559