2012-11-08 9 views
8

Iam utilizzando la libreria Eigen per il mio progetto. Sto cercando come rimuovere una determinata riga o colonna dalla matrice data in Eigen. Iam non ha successo.Come rimuovere una determinata riga o colonna durante l'utilizzo di Eigen Library C++

MatrixXd A = X1 X2 X3 X4 
      Y1 Y2 Y3 Y4 
      Z1 Z2 Z3 Z4 
      A1 A2 A3 A4 
MatrixXd Atransform = X1 X2 X4 
         Y1 Y2 Y4 
         Z1 Z2 Z4 
         A1 A2 A4 
enter code here 

diverso dall'iterazione attraverso l'intera matrice o utilizzando le operazioni di blocco sulla matrice A. C'è un metodo per farlo semplicemente.

+1

Non penso che esista un metodo oltre all'utilizzo delle operazioni di blocco. – Jakob

risposta

9

Utilizzando le funzioni di blocco è un po 'più pulito:

void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove) 
{ 
    unsigned int numRows = matrix.rows()-1; 
    unsigned int numCols = matrix.cols(); 

    if(rowToRemove < numRows) 
     matrix.block(rowToRemove,0,numRows-rowToRemove,numCols) = matrix.block(rowToRemove+1,0,numRows-rowToRemove,numCols); 

    matrix.conservativeResize(numRows,numCols); 
} 

void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove) 
{ 
    unsigned int numRows = matrix.rows(); 
    unsigned int numCols = matrix.cols()-1; 

    if(colToRemove < numCols) 
     matrix.block(0,colToRemove,numRows,numCols-colToRemove) = matrix.block(0,colToRemove+1,numRows,numCols-colToRemove); 

    matrix.conservativeResize(numRows,numCols); 
} 
+0

Questo in genere dovrebbe funzionare, ma non è garantito che Eigen copi i blocchi da sinistra a destra (o dall'alto verso il basso), quindi potresti teoricamente ottenere problemi di aliasing. – chtz

+0

@chtz: per evitare questo problema utilizzare la funzione '.eval()'. – davidhigh

1

Sono molto nuovo in C++ ma questo codice funziona in maggio.

Funziona solo per le matrici dinamiche complete ma può adattarlo.

Se qualcuno ha un modo migliore per favore mostrami che voglio davvero imparare.

template<typename ScalarType> 
void MatrixXdRemoveCol(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, int colindex) 
{ 
    Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *auxmat = new Eigen::Matrix<ScalarType,-1,-1,0,-1,-1>; 

    *auxmat = *mat; 

    mat->resize(mat->rows(),mat->cols()-1); 

    int rightColsSize = auxmat->cols()-colindex-1; 

    mat->leftCols(colindex) = auxmat->leftCols(colindex); 
    mat->rightCols(rightColsSize) = auxmat->rightCols(rightColsSize); 
} 

template<typename ScalarType> 
void MatrixXdRemoveCols(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, std::vector<int>* cols) 
{ 
    for(auto iter = cols->rbegin();iter != cols->rend();iter++) 
     MatrixXdRemoveCol<ScalarType>(mat,*iter); 
} 

template<typename ScalarType> 
void MatrixXdRemoveRow(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, int rowindex) 
{ 
    Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *auxmat = new Eigen::Matrix<ScalarType,-1,-1,0,-1,-1>; 

    *auxmat = *mat; 

    mat->resize(mat->rows()-1,mat->cols()); 

    int BottomRowsSize = auxmat->rows()-rowindex-1; 

    mat->topRows(rowindex) = auxmat->topRows(rowindex); 
    mat->bottomRows(BottomRowsSize) = auxmat->bottomRows(BottomRowsSize); 
} 
+2

Non ho familiarità con la libreria di eigen, ma dal punto di vista generale del C++ sembra che ci siano perdite di memoria nelle vostre funzioni: allocate auxmats ma non li eliminate. – cybevnm

+0

In genere, dovresti evitare 'new' quando scrivi C++, a meno che tu non ne abbia davvero bisogno e tu sai cosa stai facendo. Invece basta scrivere 'Eigen :: Matrix auxmat = mat' (e passa' mat' per riferimento e non per puntatore) – chtz

0

Per migliorare la risposta di Andrea, utilizzare bottomRows/rightCols.

void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove) 
{ 
    unsigned int numRows = matrix.rows()-1; 
    unsigned int numCols = matrix.cols(); 

    if(rowToRemove < numRows) 
     matrix.block(rowToRemove,0,numRows-rowToRemove,numCols) = matrix.bottomRows(numRows-rowToRemove); 

    matrix.conservativeResize(numRows,numCols); 
} 

void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove) 
{ 
    unsigned int numRows = matrix.rows(); 
    unsigned int numCols = matrix.cols()-1; 

    if(colToRemove < numCols) 
     matrix.block(0,colToRemove,numRows,numCols-colToRemove) = matrix.rightCols(numCols-colToRemove); 

    matrix.conservativeResize(numRows,numCols); 
} 
0

è possibile trovare la seguente versione statica di meglio per determinati usi (e più in linea con lo spirito di efficienza in fase di compilazione di Eigen). In questo caso, creerai una nuova matrice senza la riga. Una funzione simile può essere costruito per le colonne utilizzando .leftCols() .rightCols()

template<typename T> 
inline constexpr auto removeRow(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& matrix, const int& rowNum) 
{ 
    return (Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>(matrix.rows() - 1, matrix.cols()) 
     << static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(matrix.topRows(rowNum - 1)), 
     static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(matrix.bottomRows(matrix.rows() - rowNum))).finished(); 
} 

Enjoy!

Problemi correlati