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