00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <qtensor/qtensor.h>
00026
00027 QTensor &QTensor::copy(const QTensor &tensor)
00028 {
00029
00030
00031
00032 indexIds = tensor.indexIds;
00033 data = tensor.data;
00034
00035
00036 return *this;
00037 };
00038
00039 bool QTensor::equals(const QTensor &other) const
00040 {
00042 return true;
00043 }
00044
00045 QTensor QTensor::tensorProduct(const QTensor &tensor) const
00046 {
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 const QMap<int, QVector<int> > indexesQTensor1 = getValence().getIndexesPositions(),
00059 indexesQTensor2 = tensor.getValence().getIndexesPositions();
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 int actualIndexSize = 0, actualQTensor1Position = -1, actualQTensor2Position = -1;
00072
00073 QMapIterator< int, QVector<int> > idx(indexesQTensor1);
00074 while (idx.hasNext())
00075 {
00076 idx.next();
00077 const int key = idx.key();
00078 const QVector<int> positionsIndex1 = indexesQTensor1[key], positionsIndex2 = indexesQTensor2[key];
00079
00080 if (positionsIndex1.size() > 1)
00081 std::cerr << "ERROR, índice repetido en primer tensor de producto *." << std::endl;
00082 else if (positionsIndex2.size() > 1)
00083 std::cerr << "ERROR, índice repetido en segundo tensor de producto *." << std::endl;
00084
00085 else if (positionsIndex1.size() == 1 && positionsIndex2.size() == 1)
00086 {
00087 const int position1 = positionsIndex1[0], position2 = positionsIndex2[0];
00088 const int indexSize = dims[position1];
00089
00090 if (indexIds[position1] == tensor.indexIds[position2])
00091 std::cerr << "ERROR, índices iguales en ambos tensores en producto *." << std::endl;
00092 else
00093 if (indexSize > actualIndexSize)
00094 {
00095 actualIndexSize = indexSize;
00096 actualQTensor1Position = position1;
00097 actualQTensor2Position = position2;
00098 }
00099 }
00100 }
00101
00102 if (actualQTensor1Position == -1 && actualQTensor2Position == -1)
00103 return this->outerProduct(tensor).contract();
00104 else if (actualQTensor1Position == -1 || actualQTensor2Position == -1)
00105 std::cerr << "ERROR, posición para el índice dominante no definida en producto *." << std::endl;
00106
00107
00108 QTensorValence indexList1 = this->getValence(), indexList2 = tensor.getValence();
00109
00110
00111
00112
00113
00114
00115
00116 QTensor t1 = this->transpose(actualQTensor1Position, dims.size()-1), t2 = tensor.transpose(actualQTensor2Position, 0);
00117
00118
00119
00120
00121 indexList1.removeAt(actualQTensor1Position);
00122 indexList2.removeAt(actualQTensor2Position);
00123
00124 QTensorValence resultIndexList;
00125 resultIndexList << indexList1 << indexList2;
00126 QTensor result(resultIndexList);
00127
00128 const int k = t2.dims[0], m = t1.getDataSize() / k, n = t2.getDataSize() / k;
00129
00130 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
00131 m, n, k, 1.0,
00132 t1.getReadData(), k,
00133 t2.getReadData(), n, 0.0,
00134 result.getWriteData(), n);
00135
00136 return result;
00137 };
00138
00139 QTensor QTensor::innerProduct(const QTensor &tensor) const
00140 {
00142 return tensor;
00143 }
00144
00145 QTensor QTensor::renameIndexes(const QTensorValence &indexList) const
00146 {
00148 QTensor result = *this;
00149
00150 for (int i = 0; i < indexList.size(); i++)
00151 result.indexIds[i] = indexList.at(i).id;
00152
00153 return result.contract();
00154 }
00155
00157
00158 QTensorValence QTensor::getValence() const
00159 {
00160 QTensorValence result;
00161 for (int i = 0; i < dims.size(); i++)
00162 result.append(QTensorIndex(dims[i], indexIds[i]));
00163 return result;
00164 }
00165
00166 QTensor QTensor::slice(const QTensorIndexValues &indexRangeList) const
00167 {
00168
00169 const int numDims = dims.size();
00170
00171
00172 QTensorIterator tensorIterator(dims, indexIds, indexRangeList);
00173 QTensorValence idxList;
00174
00175 for (int i=0; i< numDims; i++)
00176 if (tensorIterator.numElementsDimension(i) > 1)
00177 idxList.append(QTensorIndex(tensorIterator.numElementsDimension(i), indexIds[i]));
00178
00179 QTensor result(idxList);
00180
00181 double const *srcData = getReadData();
00182 double *destData = result.getWriteData();
00183 int destIndexValue = -tensorIterator.getVectorSize();
00184
00185 do cblas_dcopy(tensorIterator.getVectorSize(), &(srcData[tensorIterator.getVectorIndex()]), 1, &(destData[destIndexValue += tensorIterator.getVectorSize()]),1);
00186 while (tensorIterator.nextVector());
00187
00188 return result;
00189 }
00190
00191 QTensor QTensor::transpose(const QTensorIndex &index1, const QTensorIndex &index2) const
00192 {
00193 int index1Position = -1, index2Position = -1;
00194
00195 if (index1.id == index2.id)
00196 return *this;
00197
00198 for (int n = 0; n< dims.size(); n++)
00199 {
00200 if (indexIds[n] == index1.id)
00201 index1Position = n;
00202 if (indexIds[n] == index2.id)
00203 index2Position = n;
00204 }
00205
00206 if (index1Position == -1 || index2Position == -1)
00207 std::cerr << "ERROR, index not found in transpose." << std::endl;
00208
00209 return transpose(index1Position, index2Position);
00210 }
00211
00212 QTensor QTensor::transpose(const QTensorValence &indexList) const
00213 {
00214 QMap<int, QVector<int> > indexes = indexList.getIndexesPositions();
00215 for (int i = 0; i < indexIds.size(); i++)
00216 if (!indexes.contains(ABS(indexIds[i])))
00217 std::cerr << "ERROR, index " << indexIds[i] << " not found in transpose." << std::endl;
00218
00219 QVector< int > order(indexIds.size());
00220 for (int i = 0; i < order.size(); i++)
00221 order[i] = indexes[ABS(indexIds[i])][0];
00222
00223 return transpose(order);
00224 }
00225
00226 QVector<int> getSorting(const QVector<int> &values)
00227 {
00228 QVector<int> result(values.size()-1), dupe = values;
00229 for (int i = 0; i < values.size() -1; i++)
00230 {
00231 int pivote = i;
00232 for (int j = i+1; j < values.size(); j++)
00233 if (dupe[pivote] > dupe[j])
00234 pivote = j;
00235 result[i] = pivote;
00236
00237
00238 const int temp = dupe[i];
00239 dupe[i] = dupe[pivote];
00240 dupe[pivote] = temp;
00241 }
00242 return result;
00243 }
00244
00245 QTensor QTensor::transpose(const int index1Position, const int index2Position) const
00246 {
00247
00248 if (index1Position == index2Position)
00249 return *this;
00250
00251 QVector <int> order(dims.size());
00252 for (int i = 0; i < order.size(); i++)
00253 order[i] = i;
00254
00255 order[MIN(index1Position, index2Position)] = MAX(index1Position, index2Position);
00256 order[MAX(index1Position, index2Position)] = MIN(index1Position, index2Position);
00257
00258 return transpose(order);
00259 }
00260
00261 QTensor QTensor::transpose(const QVector<int> &order) const
00262 {
00263
00264 QVector<int> sorting = getSorting(order);
00265
00266 QTensorValence idxList = getValence();
00267
00268 bool orderedIndexes = true;
00269 int maxIndexPosition = 0;
00270 for (int i = 0; i < sorting.size(); i++)
00271 if (i != sorting[i])
00272 {
00273 idxList.swap(i, maxIndexPosition = sorting[i]);
00274 orderedIndexes = false;
00275 }
00276
00277
00278 if (orderedIndexes)
00279 return *this;
00280
00281 QTensor result(idxList);
00282
00283 QTensorIndexator ti(result.dims);
00284 const int vectorSize = ti.getStep(maxIndexPosition);
00285 for (int i = sorting.size()-1; i >=0; i--)
00286 if (i != sorting[i])
00287 ti.swapIndexes(i, sorting[i]);
00288
00289 QTensorIterator tensorIterator(ti, maxIndexPosition);
00290
00291 const double *srcData = getReadData();
00292 double *destData = result.getWriteData();
00293 int destIndexValue = -vectorSize;
00294
00295 do cblas_dcopy(vectorSize, &(srcData[destIndexValue += vectorSize]), 1, &(destData[tensorIterator.getVectorIndex()]),1);
00296 while (tensorIterator.nextVector());
00297
00298 return result;
00299 }
00300
00301 QTensor QTensor::contract() const
00302 {
00303 const QMap< int, QVector<int> > map = getValence().getIndexesPositions();
00304
00305
00306 QVector<int> variableIndexesPositions, fixedIndexesPositions;
00307 QVector<int> variableDims;
00308 QTensorValence fixedIndexList;
00309
00310 bool dupedIndexes = false;
00311 QMapIterator< int, QVector<int> > idx(map);
00312 while (idx.hasNext())
00313 {
00314 idx.next();
00315 QVector<int> v = idx.value();
00316
00317 switch(v.size())
00318 {
00319 case 1:
00320 fixedIndexesPositions.append(v[0]);
00321 fixedIndexList.append(QTensorIndex(dims[v[0]],indexIds[v[0]]));
00322 break;
00323 case 2:
00324 if (indexIds[v[0]] != -indexIds[v[1]])
00325 std::cerr << "ERROR: two index apperances are not covariant: "
00326 << indexIds[v[0]] << ", " << indexIds[v[1]] << std::endl;
00327 variableIndexesPositions.append(v[0]);
00328 variableIndexesPositions.append(v[1]);
00329 variableDims.append(dims[v[0]]);
00330 dupedIndexes = true;
00331 break;
00332 default:
00333 std::cerr << "ERROR: more than two index apperances in a tensor" << std::endl;
00334 break;
00335 }
00336 }
00337
00338
00339 if (!dupedIndexes)
00340 return *this;
00341
00342 QVector<int> inverseOrder = variableIndexesPositions + fixedIndexesPositions;
00343 QVector<int> order(inverseOrder.size());
00344 for (int i = 0; i < inverseOrder.size(); i++)
00345 order[inverseOrder[i]] = i;
00346
00347
00348 const QTensor Transposed = transpose(order);
00349 QTensor result(fixedIndexList);
00350
00351
00352 QTensorIterator tensorIterator(variableDims);
00353 QTensorIndexator indexator(Transposed.dims);
00354
00355 const double *srcData = Transposed.getReadData();
00356 double *destData = result.getWriteData();
00357 const int vectorSize = result.getDataSize();
00358
00359 for (int i = 0; i < vectorSize; i++)
00360 destData[i] = 0;
00361
00362 do {
00363 for (int i = 0; i < variableDims.size(); i++)
00364 {
00365 indexator.setIndex(2*i, tensorIterator.getIndex(i));
00366 indexator.setIndex(2*i+1, tensorIterator.getIndex(i));
00367 }
00368
00369 cblas_daxpy(vectorSize, 1, &(srcData[indexator.getMatrixIndex()]), 1, destData, 1);
00370 }
00371 while (tensorIterator.nextVector());
00372
00373 return result;
00374 }
00375
00376 QTensor QTensor::outerProduct(const QTensor &tensor) const
00377 {
00378 QTensorValence indexList;
00379
00380 for (int i = 0; i < getValence().size(); i++)
00381 indexList.append(getValence()[i]);
00382
00383 for (int i = 0; i < tensor.getValence().size(); i++)
00384 indexList.append(tensor.getValence()[i]);
00385
00386 QTensor result(indexList);
00387
00388 const double *src1Data = getReadData();
00389 const double *src2Data = tensor.getReadData();
00390 double *destData = result.getWriteData();
00391 const int vectorSize = tensor.getDataSize();
00392
00393 for (int i = 0, destIndex = 0; i < getDataSize(); i++, destIndex += vectorSize)
00394 {
00395 cblas_dcopy(vectorSize, src2Data, 1, &(destData[destIndex]), 1);
00396 cblas_dscal(vectorSize, src1Data[i], &(destData[destIndex]), 1);
00397 }
00398
00399 return result;
00400 }
00401
00403 #include <QString>
00404 std::ostream& operator << ( std::ostream &os, const QTensor &tensor )
00405 {
00406 const QVector<int> dims = tensor.dims, indexIds = tensor.indexIds;
00407 const int numDims = dims.size();
00408
00409 os << "QTensor <" << ((indexIds[0]<0)?"cov ":"") << ABS(indexIds[0]);
00410
00411 for (int i=1; i<numDims; i++)
00412 os << ", " << ((indexIds[i]<0)?"cov ":"") << ABS(indexIds[i]);
00413
00414 os << "> (" << dims[0];
00415
00416 for (int i=1; i<numDims; i++)
00417 os << " x " << dims[i];
00418
00419 os << ")" << std::endl;
00420
00421 const double *data = tensor.getReadData();
00422 QTensorIterator tensorIterator(dims);
00423
00424 do {
00425 if (tensorIterator.getIndex(numDims-1) == 0)
00426 {
00427 int index = numDims-2;
00428 while(tensorIterator.getIndex(index) == 0)
00429 index--;
00430
00431 for (int i = index; i< numDims-2; i++)
00432 os << qPrintable(QString(4*(i+1), ' ')) << "[" << std::endl;
00433
00434 os << qPrintable(QString(4*(numDims-1), ' ')) << "[ ";
00435 }
00436
00437 os << qPrintable(QString("%1").arg(data[tensorIterator.getVectorIndex()], -8, 'f', 6)) << " ";
00438
00439 if (tensorIterator.getIndex(numDims-1) == dims[numDims-1]-1)
00440 {
00441 os << "]" << std::endl;
00442 int index = numDims-2;
00443 while(tensorIterator.getIndex(index) == dims[index]-1)
00444 index--;
00445 for (int i = numDims-3; i>=index ; i--)
00446 os << qPrintable(QString(4*(i+1), ' ')) << "]" << std::endl;
00447 }
00448 } while (tensorIterator.nextVector());
00449
00450 return os;
00451 }
00452