73 throw std::runtime_error(
74 "Determinants of Hermite normal form matrices must be greater than 0");
86 namespace HermiteCounter_impl {
91 assert(attempt <= diag(position));
92 assert(position < diag.size() - 1);
93 assert(diag(position + 1) == 1);
94 assert(diag(position) > 1);
100 while (diag(position) % attempt != 0) {
104 diag(position) = diag(position) / attempt;
105 diag(position + 1) = attempt;
118 if (position == diag.size() - 1) {
121 }
while (position >= 0 && diag(position) == 1);
131 attempt = diag(diag.size() - 1) + 1;
132 diag(position) = diag(position) * diag(diag.size() - 1);
133 diag(diag.size() - 1) = 1;
140 assert(init_dim > 0);
144 for (
int i = 0; i < init_dim; i++) {
156 Eigen::VectorXi begincount(Eigen::VectorXi::Zero(uppersize));
159 Eigen::VectorXi stepcount(Eigen::VectorXi::Ones(uppersize));
162 Eigen::VectorXi endcount(Eigen::VectorXi::Zero(uppersize));
167 endcount(slot) = current_diag(i) - 1;
176 const Eigen::VectorXi ¤t_upper_tri) {
177 assert(current_upper_tri.size() ==
upper_size(current_diag.size()));
179 Eigen::MatrixXi hmat(current_diag.asDiagonal());
182 for (
Index i = 0; i < current_diag.size() - 1; i++) {
183 for (
Index j = i + 1; j < current_diag.size(); j++) {
184 hmat(i, j) = current_upper_tri(slot);
216 const Eigen::VectorXi &active_dims) {
217 assert(hermit_mat.rows() == active_dims.sum() &&
218 hermit_mat.cols() == active_dims.sum());
219 assert(active_dims.maxCoeff() == 1 && active_dims.minCoeff() == 0);
221 Eigen::MatrixXi expanded(
228 for (i = 0; i < expanded.rows(); i++) {
229 if (active_dims(i) == 0) {
237 for (j = 0; j < expanded.cols(); j++) {
238 if (active_dims(j) == 0) {
246 expanded(i, j) = hermit_mat(si, sj);
301 const Eigen::MatrixXi &G) {
302 assert(H.rows() == H.cols());
303 assert(G.rows() == G.cols());
304 assert(G.rows() >= H.rows());
311 Eigen::MatrixXi B(m, m);
313 Eigen::MatrixXi Z_block(Eigen::MatrixXi::Zero(n, m - n));
314 B << H, Z_block, Z_block.transpose(), I_block;
338 assert(hermit_mat.rows() == hermit_mat.cols());
340 int dims = hermit_mat.rows();
343 for (
int i = dims; i > 0; i--) {
347 Eigen::VectorXi unrolled_herm(unrolldim);
352 enum STEP { DOWN, UP, LEFT };
353 STEP curr_step = DOWN;
355 Index unroll_ind = 0;
357 for (
Index i = 0; i < dims; i++) {
358 for (
Index j = 0; j < dims - i; j++) {
372 unrolled_herm(unroll_ind) = hermit_mat(lasti, lastj);
389 return unrolled_herm;
416 assert(unrolled_H0.size() == unrolled_H1.size());
418 for (
Index i = 0; i < unrolled_H0.size(); i++) {
419 if (unrolled_H0(i) > unrolled_H1(i)) {
423 else if (unrolled_H0(i) < unrolled_H1(i)) {
const Container & current() const
A Counter allows looping over many incrementing variables in one loop.
Index m_pos
Keeps track of the current diagonal element that needs to be factored.
Index _increment_diagonal()
Go to the next values of diagonal elements that keep the same determinant.
HermiteCounter(int init_determinant, int init_dim)
constructor to satisfy iterator requirements. Do not recommend.
HermiteCounter & operator++()
Jump to the next available HNF matrix.
void next_determinant()
Skip the remaining iterations and start at the next determinant value.
void jump_to_determinant(value_type new_det)
Reset the diagonal to the specified determinant and set the other elements to zero.
Eigen::MatrixXi operator()() const
Get the current matrix the counter is on.
EigenVectorXiCounter m_upper_tri
unrolled vector of the upper triangle (does not include diagonal elements)
Eigen::VectorXi::Scalar value_type
Index dim() const
Get the dimensions of *this.
Eigen::VectorXi m_diagonal
Vector holding diagonal element values.
Eigen::VectorXi diagonal() const
value_type determinant() const
Get the current determinant.
Eigen::MatrixXi current() const
Get the current matrix the counter is on.
void reset_current()
reset the counter to the first iteration of the current determinant
EigenCounter< Eigen::VectorXi > EigenVectorXiCounter
Counter for Eigen::VectorXi.
IdentitySymRepBuilder Identity()
EigenVectorXiCounter _upper_tri_counter(const Eigen::VectorXi ¤t_diag)
Create a counter for the elements above the diagonal based on the current diagonal value.
Eigen::MatrixXi _expand_dims(const Eigen::MatrixXi &H, const Eigen::MatrixXi &G)
Expand a n x n Hermite normal matrix (H) into a m x m one through a m x m generating matrix (G) (e....
HermiteCounter::Index next_spill_position(Eigen::VectorXi &diag, HermiteCounter::Index position)
Spill the next factor of the specified element with its neighbor, and return new position.
bool _canonical_compare(const Eigen::MatrixXi &H0, const Eigen::MatrixXi &H1)
Compare two integer matrices and see which one is lexicographically greatest. Returns true if H0<H1.
Eigen::MatrixXi _zip_matrix(const Eigen::VectorXi ¤t_diag, const Eigen::VectorXi ¤t_upper_tri)
Assemble a matrix diagonal and unrolled upper triangle values into a matrix.
HermiteCounter::Index _spill_factor(Eigen::VectorXi &diag, HermiteCounter::Index position, HermiteCounter::value_type attempt)
Find the next factor of the specified position and share with next element. Use attempt as starting p...
Eigen::MatrixXi _expand_dims_old(const Eigen::MatrixXi &hermit_mat, const Eigen::VectorXi &active_dims)
Expand a n x n Hermite normal matrix into a m x m one (e.g. for 2D supercells)
Eigen::VectorXi _canonical_unroll(const Eigen::MatrixXi &hermit_mat)
Unroll a Hermit normal form square matrix into a vector such that it's canonical form is easy to comp...
HermiteCounter::Index upper_size(HermiteCounter::Index init_dim)
Determine the number of elements in the upper triangular matrix (excluding diagonal)
INDEX_TYPE Index
For long integer indexing: