aboutsummaryrefslogtreecommitdiffhomepage
path: root/Eigen/src/SparseLU/SparseLU_Coletree.h
blob: d57048883104fafaf222a846747be270b498d44f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

/* 
 
 * NOTE: This file is the modified version of sp_coletree.c file in SuperLU 
 
 * -- SuperLU routine (version 3.1) --
 * Univ. of California Berkeley, Xerox Palo Alto Research Center,
 * and Lawrence Berkeley National Lab.
 * August 1, 2008
 *
 * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
 * EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program for any
 * purpose, provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is
 * granted, provided the above notices are retained, and a notice that
 * the code was modified is included with the above copyright notice.
 */
#ifndef SPARSELU_COLETREE_H
#define SPARSELU_COLETREE_H

/** Compute the column elimination tree of a sparse matrix
  * NOTE : The matrix is supposed to be in column-major format. 
  * 
  */
template<typename MatrixType>
int LU_sp_coletree(const MatrixType& mat, VectorXi& parent)
{
  int nc = mat.cols(); // Number of columns 
  int nr = mat.rows(); // Number of rows 
  
  VectorXi root(nc); // root of subtree of etree 
  root.setZero();
  VectorXi pp(nc); // disjoint sets 
  pp.setZero(); // Initialize disjoint sets 
  VectorXi firstcol(nr); // First nonzero column in each row 
  firstcol.setZero(); 
  
  //Compute firstcol[row]
  int row,col; 
  firstcol.setConstant(nc);  //for (row = 0; row < nr; firstcol(row++) = nc); 
  for (col = 0; col < nc; col++)
  {
    for (typename MatrixType::InnerIterator it(mat, col); it; ++it)
    { // Is it necessary to brows the whole matrix, the lower part should do the job ??
      row = it.row();
      firstcol(row) = std::min(firstcol(row), col);
    }
  }
  /* Compute etree by Liu's algorithm for symmetric matrices,
          except use (firstcol[r],c) in place of an edge (r,c) of A.
    Thus each row clique in A'*A is replaced by a star
    centered at its first vertex, which has the same fill. */
  int rset, cset, rroot; 
  for (col = 0; col < nc; col++) 
  {
    pp(col) = cset = col; // Initially, each element is in its own set 
    root(cset) = col; 
    parent(col) = nc; 
    for (typename MatrixType::InnerIterator it(mat, col); it; ++it)
    { //  A sequence of interleaved find and union is performed 
      row = firstcol(it.row());
      if (row >= col) continue; 
      rset = internal::etree_find(row, pp); // Find the name of the set containing row
      rroot = root(rset);
      if (rroot != col) 
      {
        parent(rroot) = col; 
        pp(cset) = cset = rset; // Get the union of cset and rset 
        root(cset) = col; 
      }
    }
  }
  return 0;  
}

/** Find the root of the tree/set containing the vertex i : Use Path halving */ 
int etree_find (int i, VectorXi& pp)
{
  int p = pp(i); // Parent 
  int gp = pp(p); // Grand parent 
  while (gp != p) 
  {
    pp(i) = gp; // Parent pointer on find path is changed to former grand parent
    i = gp; 
    p = pp(i);
    gp = pp(p);
  }
  return p; 
}

/**
  * Post order a tree
  */
VectorXi TreePostorder(int n, VectorXi& parent)
{
  VectorXi first_kid, next_kid; // Linked list of children 
  VectorXi post; // postordered etree
  int postnum; 
  // Allocate storage for working arrays and results 
  first_kid.resize(n+1); 
  next_kid.setZero(n+1);
  post.setZero(n+1);
  
  // Set up structure describing children
  int v, dad; 
  first_kid.setConstant(-1); 
  for (v = n-1, v >= 0; v--) 
  {
    dad = parent(v);
    next_kid(v) = first_kid(dad); 
    first_kid(dad) = v; 
  }
  
  // Depth-first search from dummy root vertex #n
  postnum = 0; 
  internal::nr_etdfs(n, parent, first_kid, next_kid, post, postnum);
  return post; 
}
/** 
  * Depth-first search from vertex n.  No recursion.
  * This routine was contributed by Cédric Doucet, CEDRAT Group, Meylan, France.
*/
void nr_etdfs (int n, int *parent, int* first_kid, int *next_kid, int *post, int postnum)
{
  int current = n, first, next;
  while (postnum != n) 
  {
    // No kid for the current node
    first = first_kid(current);
    
    // no first kid for the current node
    if (first == -1) 
    {
      // Numbering this node because it has no kid 
      post(current) = postnum++;
      
      // looking for the next kid 
      next = next_kid(current); 
      while (next == -1) 
      {
        // No more kids : back to the parent node
        current = parent(current); 
        // numbering the parent node 
        post(current) = postnum++;
        // Get the next kid 
        next = next_kid(current); 
      }
      // stopping criterion 
      if (postnum==n+1) return; 
      
      // Updating current node 
      current = next; 
    }
    else 
    {
      current = first; 
    }
  }
}

#endif