From 56c3e7bb6acb6cd13bf09c02f3b65a6c63f4f890 Mon Sep 17 00:00:00 2001
From: Berenger Bramas <Berenger.Bramas@inria.fr>
Date: Thu, 26 Nov 2015 23:22:10 +0100
Subject: [PATCH] start working on hmat demo

---
 Addons/HMat/CMakeLists.txt               |   2 +-
 Addons/HMat/Src/Containers/FMatGrid.hpp  |  79 +++++++++++++
 Addons/HMat/Src/Core/FDiv2Bissection.hpp | 137 +++++++++++++++++++++++
 Addons/HMat/Src/Utils/FHUtils.hpp        |  14 +++
 Addons/HMat/Src/Utils/FSvgRect.hpp       |  99 ++++++++++++++++
 Addons/HMat/Tests/testDiv2Bissection.cpp |  57 ++++++++++
 6 files changed, 387 insertions(+), 1 deletion(-)
 create mode 100644 Addons/HMat/Src/Containers/FMatGrid.hpp
 create mode 100644 Addons/HMat/Src/Core/FDiv2Bissection.hpp
 create mode 100644 Addons/HMat/Src/Utils/FHUtils.hpp
 create mode 100644 Addons/HMat/Src/Utils/FSvgRect.hpp
 create mode 100644 Addons/HMat/Tests/testDiv2Bissection.cpp

diff --git a/Addons/HMat/CMakeLists.txt b/Addons/HMat/CMakeLists.txt
index 2b34dbc5f..c43ec5dd2 100644
--- a/Addons/HMat/CMakeLists.txt
+++ b/Addons/HMat/CMakeLists.txt
@@ -43,7 +43,7 @@ if(SCALFMM_ADDON_HMAT)
         file( GLOB hpp_in_dir Src/*.hpp Src/*.h)
         INSTALL( FILES ${hpp_in_dir} DESTINATION include/ScalFmm/HMat )
 
-        file( GLOB_RECURSE source_tests_files Tests/*.c )
+        file( GLOB_RECURSE source_tests_files Tests/*.cpp )
         INCLUDE_DIRECTORIES( ${CMAKE_BINARY_DIR}/Src )
 
         # Then build test files
diff --git a/Addons/HMat/Src/Containers/FMatGrid.hpp b/Addons/HMat/Src/Containers/FMatGrid.hpp
new file mode 100644
index 000000000..a7d15fa5d
--- /dev/null
+++ b/Addons/HMat/Src/Containers/FMatGrid.hpp
@@ -0,0 +1,79 @@
+#ifndef FMATGRID_HPP
+#define FMATGRID_HPP
+
+// @SCALFMM_PRIVATE
+
+#include "Utils/FGlobal.hpp"
+#include "Utils/FAssert.hpp"
+
+
+template <class FReal>
+class FDenseBlockWrapper{
+protected:
+    const FReal* values;
+    const int nbRows;
+    const int nbCols;
+    const int leadingDim;
+
+public:
+    FDenseBlockWrapper(const FReal* inValues, const int inNbRows, const int inNbCols, const int inLeading)
+        : values(inValues), nbRows(inNbRows), nbCols(inNbCols), leadingDim(inLeading){
+    }
+
+    int getNbRows() const {
+        return nbRows;
+    }
+
+    int getNbCols() const {
+        return nbCols;
+    }
+
+    FReal getValue(const int rowIdx, const int colIdx) const{
+        FAssertLF(rowIdx < nbRows);
+        FAssertLF(colIdx < nbCols);
+        return values[colIdx*leadingDim + rowIdx];
+    }
+
+    constexpr bool existsForReal() const{
+        return true;
+    }
+};
+
+
+template <class FReal>
+class FMatGrid {
+protected:
+    int matDim;
+    FReal* values;
+
+    FMatGrid(const FMatGrid&) = delete;
+    FMatGrid& operator=(const FMatGrid&) = delete;
+
+public:
+    using BlockDescriptor = FDenseBlockWrapper<FReal>;
+
+    FMatGrid(const int inDim, const FReal* inValues)
+        : matDim(inDim), values(nullptr){
+        values = new FReal[matDim*matDim];
+        for(int idxVal = 0 ; idxVal < matDim*matDim ; ++idxVal){
+            values[idxVal] = inValues[idxVal];
+        }
+    }
+
+    ~FMatGrid(){
+        delete[] values;
+    }
+
+    FDenseBlockWrapper<FReal> getBlock(const int rowIdx, const int colIdx, const int nbRows, const int nbCols) const {
+        // static_assert(std::is_move_constructible<BlockClass>::value, "The block class must be movable");
+        // static_assert(std::is_move_assignable<BlockClass>::value, "The block class must be movable");
+        FAssertLF(0 < rowIdx);
+        FAssertLF(0 < colIdx);
+        FAssertLF(rowIdx + nbRows <= matDim);
+        FAssertLF(colIdx + nbRows <= matDim);
+        return FDenseBlockWrapper<FReal>(&values[colIdx*matDim+rowIdx], nbRows, nbCols, matDim);
+    }
+};
+
+#endif // FMATGRID_HPP
+
diff --git a/Addons/HMat/Src/Core/FDiv2Bissection.hpp b/Addons/HMat/Src/Core/FDiv2Bissection.hpp
new file mode 100644
index 000000000..856b22abd
--- /dev/null
+++ b/Addons/HMat/Src/Core/FDiv2Bissection.hpp
@@ -0,0 +1,137 @@
+#ifndef FDIV2BISSECTION_HPP
+#define FDIV2BISSECTION_HPP
+
+// @SCALFMM_PRIVATE
+
+#include "Utils/FGlobal.hpp"
+#include "Utils/FMath.hpp"
+#include "Utils/FAssert.hpp"
+
+#include "../Utils/FHUtils.hpp"
+
+#include <functional>
+
+struct FBlockDescriptor {
+    int x, y, height, width, level;
+};
+
+template <class FReal, class LeafClass, class CellClass >
+class FDiv2Bissection {
+protected:
+    struct LeafNode {
+        FBlockDescriptor infos;
+        LeafClass leaf;
+    };
+
+    struct CellNode {
+        FBlockDescriptor infos;
+        CellClass cell;
+    };
+
+    const int dim;
+    const int height;
+
+    int* nbCells;
+    CellNode** cells;
+
+    int nbLeaves;
+    LeafNode* leaves;
+
+    int totalNbBlocks;
+
+public:
+    explicit FDiv2Bissection(const int inDim, const int inHeight)
+        : dim(inDim), height(inHeight),
+          nbCells(0), cells(nullptr),
+          nbLeaves(0), leaves(nullptr),
+          totalNbBlocks(0){
+        FAssertLF(FMath::pow2(height) <= inDim);
+
+        cells   = new CellNode*[height-1];
+        FSetToZeros(cells, height-1);
+        nbCells = new int[height-1];
+        FSetToZeros(nbCells, height-1);
+
+        int previousWidth = dim;
+        for(int idxLevel = 1 ; idxLevel < height-1 ; ++idxLevel){
+            const int nbCellsAtLevel = FMath::pow2(idxLevel);
+            cells[idxLevel]   = new CellNode[nbCellsAtLevel];
+            nbCells[idxLevel] = nbCellsAtLevel;
+            totalNbBlocks += nbCellsAtLevel;
+
+            const int blockDim = previousWidth/2;
+            for(int idxCell = 0 ; idxCell < nbCellsAtLevel ; ++idxCell){
+                const int xOffset = blockDim * (idxCell&1? idxCell-1 : idxCell+1);
+                const int yOffset = idxCell * blockDim;
+                cells[idxLevel][idxCell].infos.x = xOffset;
+                cells[idxLevel][idxCell].infos.y = yOffset;
+                cells[idxLevel][idxCell].infos.width = blockDim;
+                cells[idxLevel][idxCell].infos.height= blockDim;
+                cells[idxLevel][idxCell].infos.level = idxLevel;
+            }
+
+            previousWidth = blockDim;
+        }
+
+        nbLeaves = FMath::pow2(height);
+        leaves   = new LeafNode[nbLeaves];
+        totalNbBlocks += nbLeaves;
+        {
+            const int blockDim = previousWidth/2;
+            for(int idxLeaf = 0 ; idxLeaf < nbLeaves ; ++idxLeaf){
+                const int corner = (idxLeaf/4)*previousWidth;
+                int xOffset = corner + blockDim * (idxLeaf&1?1:0);
+                int yOffset = corner + blockDim * (idxLeaf&2?1:0);
+                leaves[idxLeaf].infos.x = xOffset;
+                leaves[idxLeaf].infos.y = yOffset;
+                leaves[idxLeaf].infos.width = blockDim;
+                leaves[idxLeaf].infos.height= blockDim;
+                leaves[idxLeaf].infos.level = height-1;
+            }
+        }
+    }
+
+    ~FDiv2Bissection(){
+        for(int idxLevel = 0 ; idxLevel < height-1 ; ++idxLevel){
+            delete[] cells[idxLevel];
+        }
+        delete[] cells;
+        delete[] nbCells;
+        delete[] leaves;
+    }
+
+    int getNbBlocks() const {
+        return totalNbBlocks;
+    }
+
+    void forAllBlocksDescriptor(std::function<void(const FBlockDescriptor&)> callback){
+        for(int idxLevel = 1 ; idxLevel < height-1 ; ++idxLevel){
+            for(int idxCell = 0 ; idxCell < nbCells[idxLevel] ; ++idxCell){
+                callback(cells[idxLevel][idxCell].infos);
+            }
+        }
+        for(int idxLeaf = 0 ; idxLeaf < nbLeaves ; ++idxLeaf){
+            callback(leaves[idxLeaf].infos);
+        }
+    }
+
+    void forAllCellBlocks(std::function<void(const FBlockDescriptor&, CellClass&)> callback){
+        for(int idxLevel = 1 ; idxLevel < height-1 ; ++idxLevel){
+            for(int idxCell = 0 ; idxCell < nbCells[idxLevel] ; ++idxCell){
+                callback(cells[idxLevel][idxCell].infos,
+                         cells[idxLevel][idxCell].cell);
+            }
+        }
+    }
+
+    void forAllLeafBlocks(std::function<void(const FBlockDescriptor&, LeafClass&)> callback){
+        for(int idxLeaf = 0 ; idxLeaf < nbLeaves ; ++idxLeaf){
+            callback(leaves[idxLeaf].infos,
+                     leaves[idxLeaf].leaf);
+        }
+    }
+};
+
+
+#endif // FDIV2BISSECTION_HPP
+
diff --git a/Addons/HMat/Src/Utils/FHUtils.hpp b/Addons/HMat/Src/Utils/FHUtils.hpp
new file mode 100644
index 000000000..2c09afde5
--- /dev/null
+++ b/Addons/HMat/Src/Utils/FHUtils.hpp
@@ -0,0 +1,14 @@
+#ifndef FHUTILS_HPP
+#define FHUTILS_HPP
+
+#include "Utils/FGlobal.hpp"
+
+#include <cstring>
+
+template <class Type>
+void FSetToZeros(Type array[], const int length){
+    memset(array, 0, length*sizeof(Type));
+}
+
+#endif // FHUTILS_HPP
+
diff --git a/Addons/HMat/Src/Utils/FSvgRect.hpp b/Addons/HMat/Src/Utils/FSvgRect.hpp
new file mode 100644
index 000000000..943a02b58
--- /dev/null
+++ b/Addons/HMat/Src/Utils/FSvgRect.hpp
@@ -0,0 +1,99 @@
+#ifndef FSVGRECT_HPP
+#define FSVGRECT_HPP
+
+#include "Utils/FGlobal.hpp"
+#include "Utils/FAssert.hpp"
+
+#include <vector>
+#include <algorithm>
+
+
+class FSvgRect {
+protected:
+    int dim;
+    int svgSize;
+    int margin;
+
+    int rectCounter;
+    double pixelperunknown;
+    int descriptiony;
+
+    FILE* fsvg;
+
+    std::vector<std::tuple<int, int, int>> colors;
+
+public:
+    FSvgRect(const char inFilename[], const int inDim,
+             const int inSvgSize = 2048, const int inMargin = 50)
+        : dim(inDim), svgSize(inSvgSize), margin(inMargin), rectCounter(0),
+          pixelperunknown(0), descriptiony(0), fsvg(NULL){
+        fsvg = fopen(inFilename, "w");
+        FAssertLF(fsvg);
+
+        pixelperunknown = double(svgSize-margin-margin*2)/double(dim);
+
+        fprintf(fsvg, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
+        fprintf(fsvg, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
+                "<svg xmlns=\"http://www.w3.org/2000/svg\"  xmlns:xlink=\"http://www.w3.org/1999/xlink\"  width=\"%d\" height=\"%d\">\n",
+                svgSize, svgSize);
+        fprintf(fsvg, "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" style=\"fill:rgb(%d,%d,%d);stroke-width:1;stroke:rgb(0,0,0)\" />\n",
+                            0, 0,svgSize, svgSize, 255, 255, 255);
+
+        descriptiony = int(svgSize - margin);
+        fprintf(fsvg, "<text x=\"%d\" y=\"%d\" fill=\"red\" id=\"res\" font-size=\"55\">Description: </text>\n", 0, descriptiony);
+
+    }
+
+    ~FSvgRect(){
+        fprintf(fsvg, "</svg>");
+        fclose(fsvg);
+    }
+
+    void addRect(const int inX, const int inY, const int inWidth, const int inHeight, const int inLevel = 0){
+        if(int(colors.size()) <= inLevel){
+            for(int idxColor = int(colors.size()) ; idxColor <= inLevel ; ++idxColor){
+                colors.push_back(std::tuple<int, int, int>(255*drand48(),255*drand48(),255*drand48()));
+            }
+        }
+        fprintf(fsvg, "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" style=\"fill:rgb(%d,%d,%d);stroke-width:1;stroke:rgb(0,0,0)\" />\n",
+                            int(margin + inX*pixelperunknown),
+                            int(margin + inY*pixelperunknown),
+                            int(inWidth*pixelperunknown),
+                            int(inHeight*pixelperunknown),
+                            std::get<0>(colors[inLevel]),std::get<1>(colors[inLevel]),std::get<2>(colors[inLevel]));
+
+        rectCounter += 1;
+    }
+
+    template <class... T>
+    void addRectWithLegend(const int inX, const int inY, const int inWidth, const int inHeight, int inLevel = -1){
+        if(int(colors.size()) <= inLevel){
+            for(int idxColor = int(colors.size()) ; idxColor <= inLevel ; ++idxColor){
+                colors.push_back(std::tuple<int, int, int>(255*drand48(),255*drand48(),255*drand48()));
+            }
+        }
+
+        fprintf(fsvg, "<text x=\"%d\" y=\"%d\" fill=\"red\" id=\"res%d\" font-size=\"55\">Description: X = %d, Y = %d, W = %d, H = %d, L = % d </text>\n",
+                0, descriptiony + svgSize, rectCounter,
+                inX, inY, inWidth, inHeight, inLevel);
+
+        fprintf(fsvg, "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" style=\"fill:rgb(%d,%d,%d);stroke-width:1;stroke:rgb(0,0,0)\" ",
+                int(margin + inX*pixelperunknown),
+                int(margin + inY*pixelperunknown),
+                int(inWidth*pixelperunknown),
+                int(inHeight*pixelperunknown),
+                std::get<0>(colors[inLevel]),std::get<1>(colors[inLevel]),std::get<2>(colors[inLevel]));
+
+        fprintf(fsvg, " onmousedown=\"evt.target.parentNode.getElementById('res%d').setAttribute('y', '%d');\" ",
+                rectCounter,descriptiony);
+        fprintf(fsvg, " onmouseup=\"evt.target.parentNode.getElementById('res%d').setAttribute('y', '%d');\" ",
+                rectCounter,descriptiony + svgSize);
+
+        fprintf(fsvg, "/>\n");
+
+        rectCounter += 1;
+    }
+};
+
+#endif // FSVGRECT_HPP
+
diff --git a/Addons/HMat/Tests/testDiv2Bissection.cpp b/Addons/HMat/Tests/testDiv2Bissection.cpp
new file mode 100644
index 000000000..f1cac6b91
--- /dev/null
+++ b/Addons/HMat/Tests/testDiv2Bissection.cpp
@@ -0,0 +1,57 @@
+
+// @SCALFMM_PRIVATE
+
+#include "../Src/Core/FDiv2Bissection.hpp"
+#include "../Src/Containers/FMatGrid.hpp"
+#include "../Src/Utils/FSvgRect.hpp"
+
+#include "Utils/FParameters.hpp"
+#include "Utils/FParameterNames.hpp"
+
+int main(int argc, char** argv){
+    static const FParameterNames SvgOutParam = {
+        {"-fout", "--out"} ,
+         "Svg output filename."
+    };
+    static const FParameterNames DimParam = {
+        {"-N", "-nb", "-dim"} ,
+         "Dim of the matrix."
+    };
+    static const FParameterNames HeightParam = {
+        {"-h", "-height"} ,
+         "Number of dissection (+1)."
+    };
+
+    FHelpDescribeAndExit(argc, argv,
+            "Test the bisection.",SvgOutParam,
+            DimParam,HeightParam);
+
+    const int dim = FParameters::getValue(argc, argv, DimParam.options, 100);
+    const int height = FParameters::getValue(argc, argv, HeightParam.options, 4);
+    const char* outputfile = FParameters::getStr(argc, argv, SvgOutParam.options, "/tmp/example.svg");
+
+    std::cout << "Config : dim = " << dim << "\n";
+    std::cout << "Config : height = " << height << "\n";
+    std::cout << "Config : outputfile = " << outputfile << "\n";
+
+    FDiv2Bissection<double, int, int> bissection(dim, height);
+
+    {
+        FSvgRect output(outputfile, dim);
+
+        bissection.forAllBlocksDescriptor([&](const FBlockDescriptor& info){
+            output.addRectWithLegend(info.x, info.y, info.width, info.height, info.level);
+        });
+    }
+
+//    const double array[] = {1, 2, 3, 4,
+//                             1, 2, 3, 4,
+//                             1, 2, 3, 4,
+//                             1, 2, 3, 4};
+//    FMatGrid<double> denseMat(4 , array);
+
+//    FMatGrid<double>::BlockDescriptor blockDescriptor = denseMat.getBlock(1,1,1,1);
+
+
+    return 0;
+}
-- 
GitLab