File indexing completed on 2024-05-12 15:19:50
0001 /************************************************************************************* 0002 * Copyright (C) 2014 by Percy Camilo T. Aucahuasi <percy.camilo.ta@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or * 0005 * modify it under the terms of the GNU General Public License * 0006 * as published by the Free Software Foundation; either version 2 * 0007 * of the License, or (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program; if not, write to the Free Software * 0016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 0017 *************************************************************************************/ 0018 0019 #include "blockmatrixcommands.h" 0020 0021 #include <QCoreApplication> 0022 0023 #include "analitzautils.h" 0024 #include "expression.h" 0025 #include "value.h" 0026 #include "matrix.h" 0027 0028 using Analitza::Expression; 0029 using Analitza::ExpressionType; 0030 0031 const QString BlockMatrixCommand::id = QStringLiteral("blockmatrix"); 0032 const ExpressionType BlockMatrixCommand::type = ExpressionType(ExpressionType::Lambda) 0033 .addParameter(ExpressionType(ExpressionType::Any, ExpressionType(ExpressionType::Vector, 0034 ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1), -1))) 0035 .addParameter(ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1)); 0036 0037 Expression BlockMatrixCommand::operator()(const QList< Analitza::Expression >& args) 0038 { 0039 Expression ret; 0040 0041 const int nargs = args.size(); 0042 0043 if (nargs == 0) { 0044 ret.addError(QCoreApplication::tr("Invalid parameter count for '%1'").arg(BlockMatrixCommand::id)); 0045 0046 return ret; 0047 } 0048 0049 const Analitza::Object::ObjectType firstArgType = args.first().tree()->type(); 0050 0051 if (firstArgType == Analitza::Object::vector || firstArgType == Analitza::Object::matrixrow) { 0052 const bool isVector = (firstArgType == Analitza::Object::vector); 0053 const Analitza::Vector *firstVector = static_cast<const Analitza::Vector*>(args.first().tree()); 0054 0055 if (firstVector->size() > 0) { // we will check this for all vectors later 0056 const int firstVectorSize = firstVector->size(); 0057 const Analitza::Object::ObjectType firstVectorElementType = firstVector->at(0)->type(); 0058 0059 if (firstVectorElementType == Analitza::Object::matrix) { 0060 const Analitza::Matrix *firstBlock = static_cast<const Analitza::Matrix*>(firstVector->at(0)); 0061 0062 bool isCorrect = true; // this flag tells if is ok to build the block matrix 0063 int nrows = 0; 0064 int ncols = 0; 0065 std::vector<int> blockpattern(firstVectorSize, 0); // if vectors(matrixrow) this tells the row(column) pattern 0066 0067 const int blocklength = isVector? firstBlock->columnCount() : firstBlock->rowCount(); 0068 0069 // we need to know the pattern first, this run only on first arg (first vector) 0070 for (int blockIndex = 0; blockIndex < firstVectorSize && isCorrect; ++blockIndex) { 0071 if (firstVector->at(blockIndex)->type() == Analitza::Object::matrix) { 0072 const Analitza::Matrix* block = static_cast<const Analitza::Matrix*>(firstVector->at(blockIndex)); 0073 0074 if (block->rowCount() > 0 && block->columnCount() > 0) { 0075 const int currentlength = isVector? block->columnCount() : block->rowCount(); 0076 0077 if (currentlength == blocklength) { 0078 blockpattern[blockIndex] = isVector? block->rowCount() : block->columnCount(); 0079 0080 if (isVector) 0081 nrows += blockpattern[blockIndex]; 0082 else 0083 ncols += blockpattern[blockIndex]; 0084 } else { 0085 isCorrect = false; 0086 ret.addError(QCoreApplication::tr("Blocks must have consistent size between each and other")); 0087 } 0088 } else { 0089 isCorrect = false; 0090 ret.addError(QCoreApplication::tr("Do not want empty blocks")); 0091 } 0092 } else { 0093 ret.addError(QCoreApplication::tr("Blocks must be matrices")); 0094 isCorrect = false; 0095 } 0096 } 0097 0098 // check if all args are ok to build a block matrix 0099 for (int argIndex = 0; argIndex < nargs && isCorrect; ++argIndex) { 0100 const Analitza::Object::ObjectType currentArgType = args.at(argIndex).tree()->type(); 0101 const Analitza::Vector *vector = static_cast<const Analitza::Vector*>(args.at(argIndex).tree()); 0102 0103 if (currentArgType == firstArgType) { 0104 if (vector->size() > 0) { 0105 if (vector->size() == firstVectorSize) { 0106 const Analitza::Matrix *currentFirstBlock = static_cast<const Analitza::Matrix*>(vector->at(0)); 0107 const int blocklength = isVector? currentFirstBlock->columnCount() : currentFirstBlock->rowCount(); 0108 0109 for (int blockIndex = 0; blockIndex < firstVectorSize && isCorrect; ++blockIndex) { 0110 if (vector->at(blockIndex)->type() == Analitza::Object::matrix) { 0111 const Analitza::Matrix* block = static_cast<const Analitza::Matrix*>(vector->at(blockIndex)); 0112 0113 if (block->rowCount() > 0 && block->columnCount() > 0) { 0114 const int currentlength = isVector? block->columnCount() : block->rowCount(); 0115 const int currentpattern = isVector? block->rowCount() : block->columnCount(); 0116 0117 if (currentlength != blocklength) { 0118 isCorrect = false; 0119 ret.addError(QCoreApplication::tr("Blocks must have consistent size between each and other")); 0120 } else if (blockpattern[blockIndex] != currentpattern) { 0121 isCorrect = false; 0122 ret.addError(QCoreApplication::tr("Blocks must have consistent size between each and other")); 0123 } 0124 } else { 0125 isCorrect = false; 0126 ret.addError(QCoreApplication::tr("Do not want empty blocks")); 0127 } 0128 } else { 0129 isCorrect = false; 0130 ret.addError(QCoreApplication::tr("Blocks must be matrices")); 0131 } 0132 } 0133 0134 if (isCorrect) { 0135 if (isVector) 0136 ncols += blocklength; 0137 else 0138 nrows += blocklength; 0139 } 0140 } else { 0141 isCorrect = false; 0142 ret.addError(QCoreApplication::tr("Number of blocks must be consistent")); 0143 } 0144 } else { 0145 ret.addError(QCoreApplication::tr("Do not want empty vectors/matrixrow elements")); 0146 isCorrect = false; 0147 } 0148 } else { 0149 isCorrect = false; 0150 ret.addError(QCoreApplication::tr("Matrix constructor needs vectors or matrixrow elements")); 0151 } 0152 } 0153 0154 if (isCorrect) { 0155 Analitza::Matrix *matrix = new Analitza::Matrix(); 0156 0157 QVector< QVector< const Analitza::Object* > > objmatrix(nrows, QVector< const Analitza::Object* >(ncols, nullptr)); 0158 0159 int nrowsoffset = isVector? nrows : 0; 0160 int ncolsoffset = isVector? 0 : ncols; 0161 0162 for (int argIndex = 0; argIndex < nargs && isCorrect; ++argIndex) { 0163 const Analitza::Vector *vector = static_cast<const Analitza::Vector*>(args.at(argIndex).tree()); 0164 0165 int blockpattern = 0; 0166 0167 if (isVector) 0168 nrowsoffset = 0; 0169 else 0170 ncolsoffset = 0; 0171 0172 for (int blockIndex = 0; blockIndex < firstVectorSize && isCorrect; ++blockIndex) { 0173 const Analitza::Matrix* block = static_cast<const Analitza::Matrix*>(vector->at(blockIndex)); 0174 const int m = block->rowCount(); 0175 const int n = block->columnCount(); 0176 0177 blockpattern = isVector? n : m; 0178 0179 for (int i = 0; i < m; ++i) 0180 for (int j = 0; j < n; ++j) 0181 objmatrix[i+nrowsoffset][j+ncolsoffset] = block->at(i,j); 0182 0183 if (isVector) 0184 nrowsoffset += m; 0185 else if (blockIndex == 0) // el patron de cols se define en el primer matrixrow 0186 ncolsoffset += n; 0187 } 0188 0189 if (!isVector) 0190 nrowsoffset += blockpattern; 0191 else if (argIndex == 0) 0192 ncolsoffset += blockpattern; 0193 } 0194 0195 for (int i = 0; i < nrows; ++i) { 0196 Analitza::MatrixRow *row = new Analitza::MatrixRow(ncols); 0197 0198 for (int j = 0; j < ncols; ++j) 0199 row->appendBranch(objmatrix[i][j]->copy()); 0200 0201 matrix->appendBranch(row); 0202 } 0203 0204 ret.setTree(matrix); 0205 0206 return ret; 0207 } 0208 } else 0209 ret.addError(QCoreApplication::tr("Blocks must be matrices")); 0210 } else 0211 ret.addError(QCoreApplication::tr("Do not want empty vectors/matrixrow elements")); 0212 } else 0213 ret.addError(QCoreApplication::tr("Matrix constructor needs vectors or matrixrow elements")); 0214 0215 return ret; 0216 } 0217 0218 0219 const QString BlockDiagonalMatrixCommand::id = QStringLiteral("blockdiag"); 0220 // const ExpressionType BlockDiagonalMatrixCommand::type = variadicFunctionType(VectorAndMatrixAlternatives); 0221 const ExpressionType BlockDiagonalMatrixCommand::type = ExpressionType(ExpressionType::Lambda) 0222 .addParameter(ExpressionType(ExpressionType::Any, 0223 ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1))) 0224 .addParameter(ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1)); 0225 0226 Expression BlockDiagonalMatrixCommand::operator()(const QList< Analitza::Expression >& args) 0227 { 0228 Expression ret; 0229 0230 int nargs = args.size(); 0231 bool byvector = false; 0232 0233 if (nargs == 0) { 0234 ret.addError(QCoreApplication::tr("Invalid parameter count for '%1'").arg(BlockDiagonalMatrixCommand::id)); 0235 return ret; 0236 } 0237 0238 const Analitza::Vector *v = byvector? static_cast<const Analitza::Vector*>(args.first().tree()) : nullptr; 0239 0240 if (byvector) nargs = v->size(); 0241 0242 for (int k = 0; k < nargs; ++k) { 0243 if ((byvector? v->at(k)->type() : args.at(k).tree()->type()) == Analitza::Object::none) { 0244 ret.addError(QCoreApplication::tr("the arg %1 is invalid or is error").arg(k+1)); 0245 return ret; 0246 } 0247 } 0248 0249 if (args.first().tree()->type() == Analitza::Object::matrix) { 0250 bool failbyblockdiag = false; 0251 int nrows = 0; 0252 int ncols = 0; 0253 0254 for (int k = 0; k < nargs && !failbyblockdiag; ++k) 0255 if (args.at(k).tree()->type() == Analitza::Object::matrix) { 0256 const Analitza::Matrix *block = static_cast<const Analitza::Matrix*>(args.at(k).tree()); 0257 const int m = block->rowCount(); 0258 const int n = block->columnCount(); 0259 if (m > 0 && n > 0) { 0260 nrows += m; 0261 ncols += n; 0262 } else { 0263 ret.addError(QCoreApplication::tr("Do not want empty blocks")); 0264 failbyblockdiag = true; 0265 } 0266 } else { 0267 ret.addError(QCoreApplication::tr("Blocks must be matrices")); 0268 failbyblockdiag = true; 0269 } 0270 0271 if (!failbyblockdiag) { 0272 Analitza::Matrix *matrix = new Analitza::Matrix(); 0273 QVector< QVector< const Analitza::Object* > > objmatrix(nrows, QVector< const Analitza::Object* >(ncols, nullptr)); 0274 0275 nrows = 0; 0276 ncols = 0; 0277 0278 for (int k = 0; k < nargs; ++k) { 0279 const Analitza::Matrix *block = static_cast<const Analitza::Matrix*>(args.at(k).tree()); 0280 const int m = block->rowCount(); 0281 const int n = block->columnCount(); 0282 0283 for (int i = 0; i < m; ++i) 0284 for (int j = 0; j < n; ++j) 0285 objmatrix[i+nrows][j+ncols] = block->at(i,j); 0286 0287 nrows += m; 0288 ncols += n; 0289 } 0290 0291 for (int i = 0; i < nrows; ++i) { 0292 Analitza::MatrixRow *row = new Analitza::MatrixRow(ncols); 0293 0294 for (int j = 0; j < ncols; ++j) { 0295 const Analitza::Object *obj = objmatrix[i][j]; 0296 0297 if (obj) 0298 row->appendBranch(obj->copy()); 0299 else 0300 row->appendBranch(new Analitza::Cn(0)); 0301 } 0302 0303 matrix->appendBranch(row); 0304 } 0305 0306 ret.setTree(matrix); 0307 } 0308 0309 return ret; 0310 } 0311 0312 return ret; 0313 }