diff --git a/Addons/HMat/Src/Blocks/FDenseBlock.hpp b/Addons/HMat/Src/Blocks/FDenseBlock.hpp
index 2afaa94f7bc41370c80f67c2723d59822c1deca9..7bf42da75484f3cc143b5e3697a8318227fb239b 100644
--- a/Addons/HMat/Src/Blocks/FDenseBlock.hpp
+++ b/Addons/HMat/Src/Blocks/FDenseBlock.hpp
@@ -55,6 +55,17 @@ public:
         }
     };
 
+    void resize(const int inNbRow, const int inNbCol){
+        if(inNbRow != nbRows ||
+                 inNbCol != nbCols){
+            clear();
+            nbRows = inNbRow;
+            nbCols = inNbCol;
+            block  = new FReal[nbRows*nbCols];
+        }
+        memset(block, 0, sizeof(FReal)*nbRows*nbCols);
+    }
+
     // dtor
     ~FDenseBlock(){
         // Free memory
@@ -69,6 +80,26 @@ public:
         block = 0;
     }
 
+    int getNbRows() const{
+        return nbRows;
+    }
+
+    int getNbCols() const{
+        return nbCols;
+    }
+
+    FReal getValue(const int idxRow, const int idxCol) const{
+        return block[idxCol*nbRows+idxRow];
+    }
+
+    FReal& getValue(const int idxRow, const int idxCol) {
+        return block[idxCol*nbRows+idxRow];
+    }
+
+    void setValue(const int idxRow, const int idxCol, const FReal& val) {
+        block[idxCol*nbRows+idxRow] = val;
+    }
+
     void gemv(FReal res[], const FReal vec[], const FReal scale = FReal(1.)) const {
         FBlas::gemva(nbRows, nbCols, scale, const_cast<FReal*>(block), const_cast<FReal*>(vec), res);
     }
diff --git a/Addons/HMat/Src/Containers/FBlockPMapping.hpp b/Addons/HMat/Src/Containers/FBlockPMapping.hpp
index cfdc94d3186d639ddae45ee6c7e2d8053d8c28f1..9f99da3bf989fe51b679a98863d963833ff8890e 100644
--- a/Addons/HMat/Src/Containers/FBlockPMapping.hpp
+++ b/Addons/HMat/Src/Containers/FBlockPMapping.hpp
@@ -29,31 +29,31 @@
 #include <memory>
 
 
-template <class FReal, class RowBlockClass, class ColBlockClass, class CoreCellClass >
+template <class FReal, class CellClass >
 class FBlockPMapping {
 protected:
-    struct CellNode {
+    struct CellCNode {
         FBlockDescriptor infos;
-        CoreCellClass cell;
+        CellClass cell;
     };
 
-    struct RowNode {
+    struct RowUNode {
         FBlockDescriptor infos;
-        RowBlockClass cell;
+        CellClass cell;
     };
 
-    struct ColNode {
+    struct ColVNode {
         FBlockDescriptor infos;
-        ColBlockClass cell;
+        CellClass cell;
     };
 
     const int dim;
     const int nbPartitions;
     const int nbCells;
 
-    CellNode* cells;
-    RowNode* rowBlocks;
-    ColNode* colBlocks;
+    CellCNode* cBlocks;
+    RowUNode* uRowBlocks;
+    ColVNode* vColBlocks;
 
     FBlockPMapping(const FBlockPMapping&) = delete;
     FBlockPMapping& operator=(const FBlockPMapping&) = delete;
@@ -63,7 +63,7 @@ public:
         : dim(inDim),
           nbPartitions(inNbPartitions),
           nbCells(inNbPartitions*inNbPartitions),
-          cells(nullptr){
+          cBlocks(nullptr){
         FAssertLF(nbPartitions <= inDim);
         FAssertLF(1 <= nbPartitions);
 
@@ -73,41 +73,41 @@ public:
             partitionsOffset[idxPart] = partitionsOffset[idxPart-1] + partitions[idxPart-1];
         }
 
-        cells    = new CellNode[nbCells];
+        cBlocks    = new CellCNode[nbCells];
 
         for(int idxPartCol = 0 ; idxPartCol < nbPartitions ; ++idxPartCol){
             for(int idxPartRow = 0 ; idxPartRow < nbPartitions ; ++idxPartRow){
-                cells[idxPartCol*nbPartitions + idxPartRow].infos.row = partitionsOffset[idxPartRow];
-                cells[idxPartCol*nbPartitions + idxPartRow].infos.col = partitionsOffset[idxPartCol];
-                cells[idxPartCol*nbPartitions + idxPartRow].infos.nbRows = partitions[idxPartRow];
-                cells[idxPartCol*nbPartitions + idxPartRow].infos.nbCols = partitions[idxPartCol];
-                cells[idxPartCol*nbPartitions + idxPartRow].infos.level = 0;
+                cBlocks[idxPartCol*nbPartitions + idxPartRow].infos.row = partitionsOffset[idxPartRow];
+                cBlocks[idxPartCol*nbPartitions + idxPartRow].infos.col = partitionsOffset[idxPartCol];
+                cBlocks[idxPartCol*nbPartitions + idxPartRow].infos.nbRows = partitions[idxPartRow];
+                cBlocks[idxPartCol*nbPartitions + idxPartRow].infos.nbCols = partitions[idxPartCol];
+                cBlocks[idxPartCol*nbPartitions + idxPartRow].infos.level = 0;
             }
         }
 
-        rowBlocks = new RowNode[nbPartitions];
+        uRowBlocks = new RowUNode[nbPartitions];
         for(int idxPartRow = 0 ; idxPartRow < nbPartitions ; ++idxPartRow){
-            rowBlocks[idxPartRow].infos.row = partitionsOffset[idxPartRow];
-            rowBlocks[idxPartRow].infos.col = 0;
-            rowBlocks[idxPartRow].infos.nbRows = partitions[idxPartRow];
-            rowBlocks[idxPartRow].infos.nbCols = dim;
-            rowBlocks[idxPartRow].infos.level = 0;
+            uRowBlocks[idxPartRow].infos.row = partitionsOffset[idxPartRow];
+            uRowBlocks[idxPartRow].infos.col = 0;
+            uRowBlocks[idxPartRow].infos.nbRows = partitions[idxPartRow];
+            uRowBlocks[idxPartRow].infos.nbCols = dim;
+            uRowBlocks[idxPartRow].infos.level = 0;
         }
 
-        colBlocks = new ColNode[nbPartitions];
+        vColBlocks = new ColVNode[nbPartitions];
         for(int idxPartCol = 0 ; idxPartCol < nbPartitions ; ++idxPartCol){
-            colBlocks[idxPartCol].infos.row = 0;
-            colBlocks[idxPartCol].infos.col = partitionsOffset[idxPartCol];
-            colBlocks[idxPartCol].infos.nbRows = dim;
-            colBlocks[idxPartCol].infos.nbCols = partitions[idxPartCol];
-            colBlocks[idxPartCol].infos.level = 0;
+            vColBlocks[idxPartCol].infos.row = 0;
+            vColBlocks[idxPartCol].infos.col = partitionsOffset[idxPartCol];
+            vColBlocks[idxPartCol].infos.nbRows = dim;
+            vColBlocks[idxPartCol].infos.nbCols = partitions[idxPartCol];
+            vColBlocks[idxPartCol].infos.level = 0;
         }
     }
 
     ~FBlockPMapping(){
-        delete[] cells;
-        delete[] rowBlocks;
-        delete[] colBlocks;
+        delete[] cBlocks;
+        delete[] uRowBlocks;
+        delete[] vColBlocks;
     }
 
     int getNbBlocks() const {
@@ -116,74 +116,74 @@ public:
 
     // Iterate blocks
 
-    CoreCellClass& getCell(const int idxRowPart, const int idxColPart){
-        return cells[idxColPart*nbPartitions + idxRowPart].cell;
+    CellClass& getCBlock(const int idxRowPart, const int idxColPart){
+        return cBlocks[idxColPart*nbPartitions + idxRowPart].cell;
     }
 
-    const CoreCellClass& getCell(const int idxRowPart, const int idxColPart) const {
-        return cells[idxColPart*nbPartitions + idxRowPart].cell;
+    const CellClass& getCBlock(const int idxRowPart, const int idxColPart) const {
+        return cBlocks[idxColPart*nbPartitions + idxRowPart].cell;
     }
 
-    const FBlockDescriptor& getCellInfo(const int idxRowPart, const int idxColPart) const {
-        return cells[idxColPart*nbPartitions + idxRowPart].infos;
+    const FBlockDescriptor& getCBlockInfo(const int idxRowPart, const int idxColPart) const {
+        return cBlocks[idxColPart*nbPartitions + idxRowPart].infos;
     }
 
-    void forAllBlocksDescriptor(std::function<void(const FBlockDescriptor&)> callback){
+    void forAllCBlocksDescriptor(std::function<void(const FBlockDescriptor&)> callback){
         for(int idxCell = 0 ; idxCell < nbCells ; ++idxCell){
-            callback(cells[idxCell].infos);
+            callback(cBlocks[idxCell].infos);
         }
     }
 
-    void forAllCellBlocks(std::function<void(const FBlockDescriptor&,
-                          RowBlockClass&, CoreCellClass&, ColBlockClass&)> callback){
+    void forAllBlocks(std::function<void(const FBlockDescriptor&,
+                          CellClass&, CellClass&, CellClass&)> callback){
         for(int idxPartCol = 0 ; idxPartCol < nbPartitions ; ++idxPartCol){
             for(int idxPartRow = 0 ; idxPartRow < nbPartitions ; ++idxPartRow){
-                callback(cells[idxPartCol*nbPartitions + idxPartRow].infos,
-                     cells[idxPartCol*nbPartitions + idxPartRow].cell,
-                     rowBlocks[idxPartRow].cell,
-                     colBlocks[idxPartCol].cell);
+                callback(cBlocks[idxPartCol*nbPartitions + idxPartRow].infos,
+                     cBlocks[idxPartCol*nbPartitions + idxPartRow].cell,
+                     uRowBlocks[idxPartRow].cell,
+                     vColBlocks[idxPartCol].cell);
             }
         }
     }
 
     // Iterate row blocks
 
-    RowBlockClass& getRowCell(const int idxRowPart){
-        return rowBlocks[idxRowPart].cell;
+    CellClass& getUBlock(const int idxRowPart){
+        return uRowBlocks[idxRowPart].cell;
     }
 
-    const RowBlockClass& getRowCell(const int idxRowPart) const {
-        return rowBlocks[idxRowPart].cell;
+    const CellClass& getUBlock(const int idxRowPart) const {
+        return uRowBlocks[idxRowPart].cell;
     }
 
-    const FBlockDescriptor& getRowCellInfo(const int idxRowPart) const {
-        return rowBlocks[idxRowPart].infos;
+    const FBlockDescriptor& getUBlockInfo(const int idxRowPart) const {
+        return uRowBlocks[idxRowPart].infos;
     }
 
 
     // Iterate col blocks
 
-    ColBlockClass& getColCell(const int idxColPart){
-        return colBlocks[idxColPart].cell;
+    CellClass& getVBlock(const int idxColPart){
+        return vColBlocks[idxColPart].cell;
     }
 
-    const ColBlockClass& getColCell(const int idxColPart) const {
-        return colBlocks[idxColPart].cell;
+    const CellClass& getVBlock(const int idxColPart) const {
+        return vColBlocks[idxColPart].cell;
     }
 
-    const FBlockDescriptor& getColCellInfo(const int idxColPart) const {
-        return colBlocks[idxColPart].infos;
+    const FBlockDescriptor& getVBlockInfo(const int idxColPart) const {
+        return vColBlocks[idxColPart].infos;
     }
 
     // Operations
     void gemv(FReal res[], const FReal vec[]) const {
         for(int idxPartCol = 0 ; idxPartCol < nbPartitions ; ++idxPartCol){
             for(int idxPartRow = 0 ; idxPartRow < nbPartitions ; ++idxPartRow){
-//                &res[cells[idxPartCol*nbPartitions + idxPartRow].infos.row],
-//                &vec[cells[idxPartCol*nbPartitions + idxPartRow].infos.col])
-//                cells[idxPartCol*nbPartitions + idxPartRow].cell,
-//                rowBlocks[idxPartRow].cell,
-//                colBlocks[idxPartCol].cell;
+//                &res[cBlocks[idxPartCol*nbPartitions + idxPartRow].infos.row],
+//                &vec[cBlocks[idxPartCol*nbPartitions + idxPartRow].infos.col])
+//                cBlocks[idxPartCol*nbPartitions + idxPartRow].cell,
+//                uRowBlocks[idxPartRow].cell,
+//                vColBlocks[idxPartCol].cell;
             }
         }
     }
@@ -191,11 +191,11 @@ public:
     void gemm(FReal res[], const FReal mat[], const int nbRhs) const {
         for(int idxPartCol = 0 ; idxPartCol < nbPartitions ; ++idxPartCol){
             for(int idxPartRow = 0 ; idxPartRow < nbPartitions ; ++idxPartRow){
-//                &res[cells[idxPartCol*nbPartitions + idxPartRow].infos.row],
-//                &vec[cells[idxPartCol*nbPartitions + idxPartRow].infos.col])
-//                cells[idxPartCol*nbPartitions + idxPartRow].cell,
-//                rowBlocks[idxPartRow].cell,
-//                colBlocks[idxPartCol].cell;
+//                &res[cBlocks[idxPartCol*nbPartitions + idxPartRow].infos.row],
+//                &vec[cBlocks[idxPartCol*nbPartitions + idxPartRow].infos.col])
+//                cBlocks[idxPartCol*nbPartitions + idxPartRow].cell,
+//                uRowBlocks[idxPartRow].cell,
+//                vColBlocks[idxPartCol].cell;
 //                nbRhs, dim
             }
         }
diff --git a/Addons/HMat/Tests/testPartitionsMappingGemvBlock.cpp b/Addons/HMat/Tests/testPartitionsMappingGemvBlock.cpp
index 2b43578eeaba05d5dd366a9869b57a54b193b89b..7ae84e23630303b6fc45251eb8054853990d9b2a 100644
--- a/Addons/HMat/Tests/testPartitionsMappingGemvBlock.cpp
+++ b/Addons/HMat/Tests/testPartitionsMappingGemvBlock.cpp
@@ -81,7 +81,7 @@ int main(int argc, char** argv){
 
     {
         typedef FDenseBlock<FReal> CellClass;
-        typedef FBlockPMapping<FReal, CellClass, CellClass, CellClass> GridClass;
+        typedef FBlockPMapping<FReal, CellClass> GridClass;
 
         std::unique_ptr<int[]> partitions(new int[nbPartitions]);
         {
@@ -96,20 +96,64 @@ int main(int argc, char** argv){
         GridClass grid(dim, partitions.get(), nbPartitions);
 
         // We iterate on the blocks
+        // V blocks cover all the rows, but only some columns (based on the clustering)
         for(int idxColBlock = 0 ; idxColBlock < nbPartitions ; ++idxColBlock){
-            const MatrixClass::BlockDescriptor colBlock = matrix.getBlock(grid.getColCellInfo(idxColBlock));
-
-            // Store the result in grid.getColCell(idxColBlock)
+            const MatrixClass::BlockDescriptor colBlock = matrix.getBlock(grid.getVBlockInfo(idxColBlock));
+            int rj = -1;
+            /// TODO HERE
+            /// Compute rj, and the resulting Vj blocks,
+            /// use the colBlock (some or all of its values)
+
+            /// TODO END
+            // Store the result in grid.getVBlock(idxColBlock)
+            CellClass& Vj = grid.getVBlock(idxColBlock);
+            Vj.resize(rj, colBlock.getNbCols());
+            for(int idxRow = 0 ; idxRow < Vj.getNbRows() ; ++idxRow){
+                for(int idxCol = 0 ; idxCol < Vj.getNbCols() ; ++idxCol){
+                    /// TODO HERE
+                    /// Fill Vj with the result
+                    Vj.setValue(idxRow, idxCol, -1);
+                    /// TODO END
+                }
+            }
         }
+        // U blocks cover all the columns, but only some rows (based on the clustering)
         for(int idxRowBlock = 0 ; idxRowBlock < nbPartitions ; ++idxRowBlock){
-            const MatrixClass::BlockDescriptor rowBlock = matrix.getBlock(grid.getRowCellInfo(idxRowBlock));
-
-            // Store the result in grid.getRowCell(idxRowBlock)
+            const MatrixClass::BlockDescriptor rowBlock = matrix.getBlock(grid.getUBlockInfo(idxRowBlock));
+            int ri = -1;
+            /// TODO HERE
+            /// Compute ri, and the resulting Ui blocks
+            /// use the rowBlock (some or all of its values)
+
+            /// TODO END
+            // Store the result in grid.getUBlock(idxRowBlock)
+            CellClass& Ui = grid.getUBlock(idxRowBlock);
+            Ui.resize(rowBlock.getNbRows(), ri);
+            for(int idxRow = 0 ; idxRow < Ui.getNbRows() ; ++idxRow){
+                for(int idxCol = 0 ; idxCol < Ui.getNbCols() ; ++idxCol){
+                    /// TODO HERE
+                    /// Fill Vj with the result
+                    Ui.setValue(idxRow, idxCol, -1);
+                    /// TODO END
+                }
+            }
         }
         // Build the core part
         for(int idxColBlock = 0 ; idxColBlock < nbPartitions ; ++idxColBlock){
             for(int idxRowBlock = 0 ; idxRowBlock < nbPartitions ; ++idxRowBlock){
-                // Store the result in grid.getCell(idxRowBlock, idxColBlock)
+                const CellClass& Ui = grid.getUBlock(idxRowBlock);
+                const CellClass& Vj = grid.getVBlock(idxColBlock);
+                // Store the result in grid.getCBlock(idxRowBlock, idxColBlock)
+                CellClass& Cij = grid.getCBlock(idxRowBlock, idxColBlock);
+                Cij.resize(Vj.getNbRows(), Ui.getNbCols());
+                for(int idxRow = 0 ; idxRow < Cij.getNbRows() ; ++idxRow){
+                    for(int idxCol = 0 ; idxCol < Cij.getNbCols() ; ++idxCol){
+                        /// TODO HERE
+                        /// Fill Vj with the result
+                        Cij.setValue(idxRow, idxCol, -1);
+                        /// TODO END
+                    }
+                }
             }
         }