src/qvmath/qvtensor.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
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         // Check valences for both tensors are equivalent
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         // Check data in both tensors is equal
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    // we have a candidate index.
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         // Move dominant index to end and start of the tensors
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                 // Swap value of the 'pivote'
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         // If both indexes are the same, return the actual tensor
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         // TODO: si el orden es el identidad (1, 2, 3, 4, ......, n), devolver copia de este tensor.
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         // If there are no indexes to move, return the actual tensor
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         // Create ordering for indexes, and list of indexes for result tensor.
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         // If there are no indexes to contract, return the actual tensor
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         // Transpose original tensor, and create result tensor.
00407         const QVTensor Transposed = transpose(order);
00408         QVTensor result(fixedIndexList);
00409 
00410         // Create iterator for variable indexes, and indexator for tensor Transposed
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                 /*std::cout << "leviCivitaAux: indexes " << std::endl;
00449                 for (int n = 0; n < numIndex; n++)
00450                         std::cout << "\t" << indexator.getIndex(n);
00451                 std::cout << std::endl;
00452                 std::cout << "leviCivitaAux: set data " << indexator.getMatrixIndex() << std::endl;*/
00453 
00455                 int accum = 0;
00456                 for (int n = 0; n < numIndex; n++)
00457                         accum = accum*numIndex +  indexator.getIndex(n);
00458 
00459                 //std::cout << "leviCivitaAux: set data " << indexator.getMatrixIndex() << ", " << accum << std::endl;
00460                 //data[indexator.getMatrixIndex()] = parity?1:-1;
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 

Generated on Thu Jul 17 17:23:28 2008 for QVision by  doxygen 1.5.3