File: Filtration.h

package info (click to toggle)
polymake 4.14-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 35,888 kB
  • sloc: cpp: 168,933; perl: 43,407; javascript: 31,575; ansic: 3,007; java: 2,654; python: 632; sh: 268; xml: 117; makefile: 61
file content (274 lines) | stat: -rw-r--r-- 7,551 bytes parent folder | download | duplicates (3)
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#pragma once

#include "polymake/Array.h"
#include "polymake/Matrix.h"
#include "polymake/Set.h"
#include "polymake/SparseVector.h"
#include "polymake/graph/Lattice.h"
#include "polymake/graph/Decoration.h"
#include "polymake/internal/matrix_methods.h"

namespace polymake { namespace topaz {

// dimension and index are needed to find the corresponding boundary via the given matrices.
struct Cell {
  Int deg, dim, idx;

  Cell() : deg(0), dim(0), idx(0) {}

  Cell(Int deg_in, Int dim_in, Int idx_in) : deg(deg_in), dim(dim_in), idx(idx_in) {}

  bool operator!= (const Cell & other) const
  {
    return deg!=other.deg || dim!=other.dim || idx!=other.idx;
  }

  // for testing.
  friend std::ostream& operator<< (std::ostream & os, const Cell& c)
  {
    os << "(" << c.deg << "," << c.dim << "," << c.idx << ")";
    return os;
  }
};

template <typename MatrixType>
class Filtration {
  using Coeff = typename MatrixType::value_type;
  using MatNS = typename MatrixType::persistent_nonsymmetric_type;

public:
  Array<Cell> C; //after object initialization, this array is always sorted as required by the persistent homology algorithm.
  Array<MatrixType> bd_matrix; //boundary matrices by dimension. idx of the cells corresponds to the row in the corresponding matrix
  Array<Array<Int>> ind; //keep track of indices to implement proper bd function

  Filtration() {}

  Filtration(const Array<Cell>& C_in, const Array<MatrixType>& bd_in, bool sorted=false)
    : C(C_in)
    , bd_matrix(bd_in)
    , ind(bd_in.size())
  {
    if (sorted) update_indices();
    else sort();
  }

  Filtration(const graph::Lattice<graph::lattice::BasicDecoration>& HD, const Array<Int>& degs)
    : C(HD.nodes()-2)   // -2 for empty set and dummy
    , bd_matrix(HD.rank())
  {
    Int dim = HD.rank()-1;

    const auto vertex_set = HD.nodes_of_rank(1); // nodes of dim 0
    Int n_bd = vertex_set.size(); // number of vertices
    bd_matrix[0] = ones_matrix<Coeff>(n_bd, 1);
    Map<Int, Int> reindex_map; // map index in hasse diagram to index in boundary matrix.
    Int count_index = 0;
    for (Int i : vertex_set) {
      C[i-1] = Cell(degs[i-1], 0, count_index);
      reindex_map[i] = count_index;
      ++count_index;
    }

    // compute boundary matrices for d>0:
    for (Int d = 1; d < dim; ++d) {
      const auto d_set = HD.nodes_of_rank(d+1);
      Int n = d_set.size();//number of d-simplices
      MatrixType bd(n, n_bd);
      n_bd = n;
      Map<Int, Int> new_reindex_map;

      ///////////////////////
      Int r = 0; //row index
      for (Int f : d_set) { // iterate d-simplices
        auto face = HD.face(f);
        new_reindex_map[f] = r; // fill in index map for next iteration
        C[f-1] = Cell(degs[f-1],d,r);//put indices into cell array

        for (Int sf : HD.in_adjacent_nodes(f)) { // iterate d-1-simplices
          auto subface = HD.face(sf);
          Int i = 0;   // find index of the vertex missing in current subface
          for (auto f_it = entire(face), sf_it = entire(subface);
               (*f_it) == (*sf_it) && !sf_it.at_end(); ++f_it, ++sf_it)
            ++i;

          bd(r, reindex_map[sf]) = i%2 ? Coeff(1) : Coeff(-1);
        }
        ++r;
      }
      ///////////////////////////
      bd_matrix[d] = bd;
      reindex_map = new_reindex_map;
    }

    sort();
  }

  // keeps track of ind matrix for easy access of boundaries
  void update_indices()
  {
    ind.resize(bd_matrix.size());
    for (auto i = entire<indexed>(ind); !i.at_end(); ++i)
      i->resize(bd_matrix[i.index()].rows());
    for (auto c=entire<indexed>(C); !c.at_end(); ++c) {
      ind[c->dim][c->idx] = c.index();
    }
  }

public:
  Int n_cells() const
  {
    return C.size();
  }

  Int n_frames() const
  {
    return C[n_cells()-1].deg; //TODO this only works with sorted array...
  }

  Int dim() const
  {
    return bd_matrix.size()-1;
  }

  using Chain = SparseVector<Coeff>;
  Chain bd(Int i) const
  {
    Cell cell = C[i];
    Int d = cell.dim;
    Chain c(C.size());
    if (d==0) return c; //points have empty boundary
    Chain b = bd_matrix[d].row(cell.idx);
    for (auto e = entire(b); !e.at_end(); ++e) {
      c[ind[d-1][e.index()]] = *e;
    }
    return c;
  }

  // sort cells by degree first and dimension second, as required by persistent homology algo.
private:
  struct cellComparator {
    bool operator()(const Cell& c1, const Cell& c2) const
    {
      if (c1.deg < c2.deg) return true;
      if (c1.deg == c2.deg) {
        if (c1.dim < c2.dim) return true;
        if (c1.dim == c2.dim) return c1.idx < c2.idx; // idx gets sorted lex to allow equality checking
      }
      return false;
    }
  };

  void sort()
  {
    std::sort(C.begin(), C.end(), cellComparator());
    update_indices(); //TODO do this while sorting?
  }

public:
  const Cell& operator[](Int i) const
  {
    return C[i];
  }

  const MatrixType& boundary_matrix(Int d) const
  {
    return bd_matrix[d];
  }

  const Array<Cell> cells() const
  {
    return C;
  }

  /// returns d-bd matrix of t-th frame TODO accept non-sorted filtrations?
  /// @param[out] frame indices of d-simplices present in this frame
  /// @param[out] frame_bd indices of d-1-simplices present
  MatrixType boundary_matrix_with_frame_sets(Int d, Int t, Set<Int>& frame, Set<Int>& frame_bd) const
  {
    if (t>n_frames()) throw std::runtime_error("Filtration: input exceeds number of frames");
    if (d>dim()) throw std::runtime_error("Filtration: input exceeds filtration dimension");
    const MatrixType& B = bd_matrix[d];

    for (auto i = entire<indexed>(ind[d]); !i.at_end(); ++i) {
      if (C[*i].deg <= t) frame += i.index();
    }
    if (d>0) {
      for (auto i = entire<indexed>(ind[d-1]); !i.at_end(); ++i) {
        if (C[*i].deg <= t) frame_bd += i.index();
      }
    } else {
      frame_bd = sequence(0, B.cols());
    }

    return B.minor(frame, frame_bd);
  }

  MatrixType boundary_matrix(Int d, Int t) const
  {
    Set<Int> frame, frame_bd;
    return boundary_matrix_with_frame_sets(d, t, frame, frame_bd);
  }

  auto get_iter() const
  {
    return entire<indexed>(C);
  }

  // for testing.
  friend std::ostream & operator<< (std::ostream& os, const Filtration& c)
  {
    for (Int i = 0; i < c.n_cells(); ++i) os << c[i] << ",";
    return os;
  }

  template <typename MatrixType2>
  bool operator== (const Filtration<MatrixType2>& other) const
  {
    return bd_matrix == other.bd_matrix && C == other.C;
  }

  template <typename> friend struct pm::spec_object_traits;
};

} }

namespace pm{

template <>
struct spec_object_traits< Serialized< polymake::topaz::Cell > >
  : spec_object_traits<is_composite> {

  using masquerade_for = polymake::topaz::Cell;

  typedef cons<Int, cons<Int, Int>> elements;

  template <typename Me, typename Visitor>
  static void visit_elements(Me& me, Visitor& v)
  {
    v << me.deg << me.dim << me.idx;
  }
};

template <typename MatrixType>
struct spec_object_traits< Serialized< polymake::topaz::Filtration<MatrixType> > >
  : spec_object_traits<is_composite> {

  using masquerade_for = polymake::topaz::Filtration<MatrixType>;

  typedef cons<Array<polymake::topaz::Cell>, Array<MatrixType> > elements;

  template <typename Me, typename Visitor>
  static void visit_elements(Me& me, Visitor& v) //for data_load
  {
    v << me.C << me.bd_matrix;
    me.update_indices();
  }

  template <typename Visitor>
  static void visit_elements(const pm::Serialized<masquerade_for>& me, Visitor& v) //for data_save
  {
    v << me.C << me.bd_matrix;
  }
};

}