1 /*! \file   BisectionTree.hpp
2     \brief  ordeing by graph decomposer, SCOTCH or METIS
3     \author Xavier Juvigny, ONERA
4     \date   Jul.  2nd 2012
5     \date   Nov. 30th 2016
6 */
7 
8 // This file is part of Dissection
9 //
10 // Dissection is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Linking Dissection statically or dynamically with other modules is making
16 // a combined work based on Disssection. Thus, the terms and conditions of
17 // the GNU General Public License cover the whole combination.
18 //
19 // As a special exception, the copyright holders of Dissection give you
20 // permission to combine Dissection program with free software programs or
21 // libraries that are released under the GNU LGPL and with independent modules
22 // that communicate with Dissection solely through the Dissection-fortran
23 // interface. You may copy and distribute such a system following the terms of
24 // the GNU GPL for Dissection and the licenses of the other code concerned,
25 // provided that you include the source code of that other code when and as
26 // the GNU GPL requires distribution of source code and provided that you do
27 // not modify the Dissection-fortran interface.
28 //
29 // Note that people who make modified versions of Dissection are not obligated
30 // to grant this special exception for their modified versions; it is their
31 // choice whether to do so. The GNU General Public License gives permission to
32 // release a modified version without this exception; this exception also makes
33 // it possible to release a modified version which carries forward this
34 // exception. If you modify the Dissection-fortran interface, this exception
35 // does not apply to your modified version of Dissection, and you must remove
36 // this exception when you distribute your modified version.
37 //
38 // This exception is an additional permission under section 7 of the GNU
39 // General Public License, version 3 ("GPLv3")
40 //
41 // Dissection is distributed in the hope that it will be useful,
42 // but WITHOUT ANY WARRANTY; without even the implied warranty of
43 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
44 // GNU General Public License for more details.
45 //
46 // You should have received a copy of the GNU General Public License
47 // along with Dissection.  If not, see <http://www.gnu.org/licenses/>.
48 //
49 
50 // ==============================================================
51 // ==   Bisection tree : stored by components in 1D arrays    ==
52 // ==============================================================
53 #ifndef _DISSECTION_SPLITTERS_BISECTIONTREE_HPP_
54 #define _DISSECTION_SPLITTERS_BISECTIONTREE_HPP_
55 #include <cstdio>
56 #include "Splitters/BitManipulations.hpp"
57 #include "Splitters/BisectionInterConnection.hpp"
58 #include "Splitters/Splitter.hpp"
59 #include "Algebra/CSR_matrix.hpp"
60 
61 namespace Dissection
62 {
63   /** @brief Nested Bisection tree
64 
65       The nested bisection tree is the core of the
66       symbolic factorization.
67       Nodes are numbered from root,starting at 1,
68       to leaves by layer order.
69 
70       By example :      (layer level)
71       -----------  1          0
72                   / \
73                  2   3        1
74                 /\   /\
75                4  5 6  7      2
76 
77       Data are stored components by components, ordered as above :
78                        [D1,D2,D3,D4,D5,D6,D7]
79 
80       Each layer l data begin at 2^l (0 <= l < number of layers)
81 
82       A node n is in layer highest_one_idx(n)
83 
84       The brother of a node n (node sharing same father) is n^1
85       (^ means xor operation as C convention).
86 
87       Ancestors are n>>p where
88       0 < p < number of layers - level of domain
89    */
90   class Tree
91   {
92   public:
93       /**@name Constructors and destructor */
94       //@{
95       /** @brief Build bisection tree
96 
97 	  From the sparse matrix CSR structure,
98 	  build the bisection tree for symbolic factorization
99 	  computing some block permutations to speed-up data
100 	  transfert between blocks.
101 
102 	  @param dim     Dimension of the sparse matrix
103 	  @param ptRows  Indices pointing on the beginning of
104 	                 each row of the sparse matrix.
105 			 The last value ptRows[dim] provides the
106 			 number of non zero coefficients of the
107 			 sparse matrix.
108 	  @param indCols Column indice of each non zero coefficients
109 	                 of the sparse matrix. Values must be stored
110 			 and sorted (increasing) by row
111 	  @param nbMaxLevel Maximal number of iteration for the
112 	                    bisection method.
113 	  @param minSize    Minimal number of nodes per subdomains
114 	                    in the leaves of the tree.
115           @param spltFct The nested bisection library function to use
116 	                 By default, Scotch is used to do nested
117 			 bisection
118           @param checkData  If true, verify some consistencies in the given sparse
119 	                    matrix structure. If false, assume than
120 			    provided sparse matrix structure is
121 			    consistency.
122        */
123     Tree(FILE *fp, bool &berr, unsigned dim,
124 	 const CSR_indirect *csr,
125 	 const bool isSym, //const bool isLower,
126 	 const int *remap_eqn, //const int *remap_indcols,
127 	 unsigned nbMaxLevel=8, unsigned minSize = 120,
128 	 splitter spltFct = NULL,
129 	 bool checkData = false, bool verbose = true);
130 
131       /** @brief Destructor
132        */
133     ~Tree();
134       //@}
135 
136       /** @name Getters and setters */
137       //@{
138       /// Return index of the brother (i.e having same father) node
139       /// of a node nd.
selfIndex(unsigned nd)140     static int selfIndex(unsigned nd) {
141       return (int)(nd - 1);
142     }
Index2Node(unsigned nd)143     static int Index2Node(unsigned nd) {
144       return (int)(nd + 1);
145     }
brotherIndex(unsigned nd)146     static unsigned brotherIndex(unsigned nd) {
147       return (nd ^ 1);
148     }
149     /// Return index of the father node index of a node nd
fatherIndex(unsigned nd)150     static unsigned fatherIndex(unsigned nd) {
151       return (nd / 2);
152     }
153     /// Return index of nth forerunner of domain nd :
nthfatherIndex(unsigned nd,unsigned nth)154     static unsigned nthfatherIndex(unsigned nd, unsigned nth) {
155       return (nd >> nth);
156     }
157     /// Return index of the first child index for node nd :
childIndex(unsigned nd)158     static unsigned childIndex(unsigned nd) {
159       return (nd * 2);
160     }
161       /// Return layer number where lies the domain nd :
nodeLayer(unsigned nd)162     static unsigned nodeLayer(unsigned nd) {
163       return highest_one_idx(nd);
164     }
165     /// Return
NumberOfLevels()166     unsigned NumberOfLevels() {
167       return _nbLevels;
168     }
NumberOfSubdomains()169     unsigned NumberOfSubdomains() {
170       return _nbDoms;
171     }
172     //
NumberOfSubdomains(unsigned level)173     unsigned NumberOfSubdomains(unsigned level) {
174       // (_sbLevels - 1) == (void)
175       if (level < _nbLevels) {
176 	return ((1 << (level + 1)) - 1);  // including own level
177       }
178       else {
179 	return 0U;
180       }
181     }
182 
183       /// Return number of internal nodes of a domain nd (>=1)
sizeOfDomain(unsigned nd) const184     unsigned sizeOfDomain(unsigned nd) const {
185       return _sizeOfDomains[selfIndex(nd)];
186     }
187 
sizeOfFathersStrips(unsigned nd) const188     unsigned sizeOfFathersStrips(unsigned nd) const {
189       return _sizeOfFathersStrips[selfIndex(nd)];
190     }
191 
192     /// Return connection between a domain nd (nd >= 1) and his ancestors
getFathersStrips(unsigned nd)193     const FathersStrips& getFathersStrips(unsigned nd) {
194       return _interco[selfIndex(nd)];
195     }
getDiagCSR(unsigned nd)196     const CSR_indirect& getDiagCSR(unsigned nd) {
197       return _csr_diag[selfIndex(nd)];
198     }
getOffdiagCSR(unsigned nd)199     const CSR_indirect& getOffdiagCSR(unsigned nd) {
200       return _csr_offdiag[selfIndex(nd)];
201     }
getDiagLoc2Glob(unsigned nd)202     int *getDiagLoc2Glob(unsigned nd) {
203       return _loc2glob_diag[selfIndex(nd)];
204     }
getOffdiagLoc2Glob(unsigned nd)205     int *getOffdiagLoc2Glob(unsigned nd) {
206       return _loc2glob_offdiag[selfIndex(nd)];
207     }
208 
209     bool save(FILE* stream) const;
210       /** @brief Load bisection tree contents */
211     bool load(FILE* stream)      ;
212       /** @brief Print information on bisection tree
213 
214 	  A verbose level can be provided. Depending of
215 	  his value, informations printed are :
216 
217 	  >=1 : Some statistics data (number of domains,
218 	        mean number of nodes per domains per layer,
219 		variance of number of nodes per domains,...)
220 	  >=2 : Global indices of nodes contained per domains
221 
222 	  >=3 : Block permutation from a domain and his forerunnings
223 
224 	  @param verboseLevel Choose the level of verbose
225 	                      to print some information for
226 			      dissection tree.
227        */
228     void printInfo(FILE* stream,
229 		   unsigned verboseLevel = 1) const;
230 
231       //@}
232   private:
233     bool _verbose;
234       /* Allocate and fill an array with indices of domain
235 	 containing each local index.
236 	 The caller of this method must free the returned array.
237       */
238     unsigned* compLoc2Dom(unsigned dim) const;
239       /* Remove self references from the skeleton graph of the sparse matrix
240 	 provided to the splitter
241       */
242     void removeLoops(int dim,
243 		     const int* ptRows, const int* indCols,
244 		     int*& ptRows2, int*& indCols2);
245       /* Do symbolic factorization */
246     FathersStrips* symbolicFactorization(SetOfStrips** connections);
247       /* Renumbering interfaces to optimize number of strips */
248     void renumberingInterface(unsigned nperm, unsigned* perm,
249 			      const SetOfStrips& paral,
250 			      const SetOfStrips& parar,
251 			      const SetOfStrips& seq,
252 			      unsigned layer, unsigned iDom) const;
253     void draw_csr(char *filename,
254 		  int dim,
255 		  const int *ptRows,
256 		  const int *indCols,
257 		  const int *ptRow_diag,
258 		  const int *indVals,
259 		  const unsigned *l2d);
260 
261       /// Number of levels done in nested bisection algorithm
262 
263     unsigned _nbDoms;
264     unsigned _nbLevels;
265       /// Number of nodes (internal only for each leaf)
266     int *_sizeOfDomains;
267     int *_sizeOfFathersStrips;
268       /// Indice (starting at 0) of the beginning of each domain
269       /// in local 2 global correspondance.
270     int *_ptOnDomains;
271       /// Local 2 global array for each subdomain (partition)
272     int *_local2global;
273       /// global 2 local array (partition)
274     int *_global2local;
275       ///
276     FathersStrips* _interco;
277       /// For global indices, store the domain containing it :
278     int* _glob2dom;
279     int **_loc2glob_diag;
280     int **_loc2glob_offdiag;
281     bool _isSym;
282     CSR_indirect *_csr_diag;
283     CSR_indirect *_csr_offdiag;
284   };
285 }
286 
287 #endif
288