CMR  1.3.0
smith_normal_form.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "common.hpp"
4 #include "gcd.hpp"
5 #include "linear_algebra.hpp"
6 #include "matrix.hpp"
7 #include "matrix_permuted.hpp"
8 #include "matrix_transposed.hpp"
9 
10 namespace tu
11 {
12  template <typename Matrix>
13  void smith_normal_form_diagonal(Matrix& input_matrix, std::vector <int>& diagonal)
14  {
15  integer_matrix matrix = input_matrix;
16  matrix_permuted <integer_matrix> permuted_matrix(matrix);
17  size_t handled = 0;
18  size_t row = 0;
19  size_t column = 0;
20  diagonal.resize(matrix.size1() < matrix.size2() ? matrix.size1() : matrix.size2(), 0);
21 
22  while (find_smallest_nonzero_matrix_entry(permuted_matrix, handled, permuted_matrix.size1(), handled, permuted_matrix.size2(), row, column))
23  {
24  matrix_permute1(permuted_matrix, handled, row);
25  matrix_permute2(permuted_matrix, handled, column);
26 
28  if (permuted_matrix(handled, handled) < 0)
29  {
30  for (size_t r = 0; r < permuted_matrix.size1(); ++r)
31  permuted_matrix(r, handled) = -permuted_matrix(r, handled);
32  }
33  diagonal[handled] = permuted_matrix(handled, handled);
34 
35  enum tests_t
36  {
37  COLUMN_ZERO = 1, ROW_ZERO = 2, GCD = 4,
38  };
39 
40  int tests = COLUMN_ZERO | ROW_ZERO;
41  while (true)
42  {
44  if ((tests & COLUMN_ZERO) && !matrix_column_zero(permuted_matrix, handled, handled + 1, permuted_matrix.size1()))
45  {
46  bool changed = false;
47  for (size_t r = handled + 1; r < matrix.size1(); ++r)
48  {
49  changed = matrix_row_gcd(permuted_matrix, handled, r, handled) || changed;
50  }
51  if (changed)
52  {
53  tests = ROW_ZERO;
54  continue;
55  }
56  }
58  if ((tests & ROW_ZERO) && !matrix_row_zero(permuted_matrix, handled, handled + 1, permuted_matrix.size2()))
59  {
60  bool changed = false;
61  for (size_t c = handled + 1; c < permuted_matrix.size2(); ++c)
62  {
63  changed = matrix_column_gcd(permuted_matrix, handled, c, handled) || changed;
64  }
65  if (changed)
66  {
67  tests = COLUMN_ZERO;
68  continue;
69  }
70  }
72  bool changed = false;
73  for (size_t r = handled + 1; r < permuted_matrix.size1(); ++r)
74  {
75  for (size_t c = handled + 1; c < permuted_matrix.size2(); ++c)
76  {
77  if (gcd(permuted_matrix(r, c), permuted_matrix(handled, handled)) != permuted_matrix(handled, handled))
78  {
79  for (size_t r = handled; r < permuted_matrix.size1(); ++r)
80  {
81  permuted_matrix(r, handled) += permuted_matrix(r, c);
82  }
83  changed = true;
84  break;
85  }
86  }
87  if (changed)
88  break;
89  }
90  if (changed)
91  tests = COLUMN_ZERO;
92  else
93  break;
94  }
95 
96  handled++;
97  }
98 
99  }
100 
101 } /* namespace tu */
Base class for matrices whose entries have type V.
Definition: matrix.hpp:55
Definition: matrix_permuted.hpp:17
size_type size2() const
Definition: matrix_permuted.hpp:65
size_type size1() const
Definition: matrix_permuted.hpp:56
Definition: algorithm.hpp:14
void matrix_permute1(MatrixType &matrix, size_t index1, size_t index2)
Definition: matrix.hpp:1723
bool find_smallest_nonzero_matrix_entry(const Matrix &matrix, size_t row_first, size_t row_beyond, size_t column_first, size_t column_beyond, size_t &row, size_t &column)
Definition: matrix.hpp:1652
T gcd(T a, T b, T &s, T &t)
Definition: gcd.hpp:29
void smith_normal_form_diagonal(Matrix &input_matrix, std::vector< int > &diagonal)
Definition: smith_normal_form.hpp:13
bool matrix_row_gcd(Matrix &matrix, size_t row1, size_t row2, size_t column)
Definition: linear_algebra.hpp:29
bool matrix_column_gcd(Matrix &matrix, size_t column1, size_t column2, size_t row)
Definition: linear_algebra.hpp:54
boost::numeric::ublas::matrix< long long > integer_matrix
Definition: common.hpp:27
bool matrix_column_zero(const Matrix &matrix, size_t column, size_t row_first, size_t row_beyond)
Definition: matrix.hpp:1689
bool matrix_row_zero(const Matrix &matrix, size_t row, size_t column_first, size_t column_beyond)
Definition: matrix.hpp:1680
void matrix_permute2(MatrixType &matrix, size_t index1, size_t index2)
Definition: matrix.hpp:1740