/******************************************************************* * * M4RI: Linear Algebra over GF(2) * * Copyright (C) 2010 Martin Albrecht * * Distributed under the terms of the GNU General Public License (GPL) * version 2 or higher. * * This code 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 * General Public License for more details. * * The full text of the GPL is available at: * * http://www.gnu.org/licenses/ * ********************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "echelonform.h" #include "brilliantrussian.h" #include "ple.h" #include "triangular.h" rci_t mzd_echelonize(mzd_t *A, int full) { return _mzd_echelonize_m4ri(A, full, 0, 1, __M4RI_ECHELONFORM_CROSSOVER_DENSITY); } rci_t mzd_echelonize_m4ri(mzd_t *A, int full, int k) { return _mzd_echelonize_m4ri(A, full, k, 0, 1.0); } rci_t mzd_echelonize_pluq(mzd_t *A, int full) { mzp_t *P = mzp_init(A->nrows); mzp_t *Q = mzp_init(A->ncols); rci_t r; if(full) { #if 0 r = mzd_pluq(A, P, Q, 0); mzd_t *U = mzd_init_window(A, 0, 0, r, r); mzd_t *B = mzd_init_window(A, 0, r, r, A->ncols); if(r!=A->ncols) mzd_trsm_upper_left(U, B, 0); if(r) mzd_set_ui(U, 0); for(rci_t i = 0; i < r; ++i) mzd_write_bit(A, i, i, 1); mzd_free_window(U); mzd_free_window(B); if(r) { mzd_t *A0 = mzd_init_window(A, 0, 0, r, A->ncols); mzd_apply_p_right(A0, Q); mzd_free_window(A0); } else { mzd_apply_p_right(A, Q); } #else r = mzd_pluq(A, P, Q, 0); mzd_t *U = mzd_init_window(A, 0, 0, r, r); const rci_t r_radix = m4ri_radix*(r/m4ri_radix); if(r_radix == r && r!=A->ncols) { mzd_t *B = mzd_init_window(A, 0, r, r, A->ncols); if(r!=A->ncols) mzd_trsm_upper_left(U, B, 0); mzd_free_window(B); } else if (r_radix != r && r!=A->ncols) { assert(r_radix < r); if(A->ncols > r_radix+m4ri_radix) { mzd_t *B0 = mzd_submatrix(NULL, A, 0, r_radix, r, r_radix+m4ri_radix); mzd_t *B0w = mzd_init_window( A, 0, r_radix, r, r_radix+m4ri_radix); mzd_t *B1 = mzd_init_window(A, 0, r_radix+m4ri_radix, r, A->ncols); mzd_trsm_upper_left(U, B0, 0); mzd_trsm_upper_left(U, B1, 0); mzd_copy(B0w, B0); mzd_free(B0); mzd_free_window(B0w); mzd_free_window(B1); } else { mzd_t *B = mzd_submatrix(NULL, A, 0, r_radix, r, A->ncols); mzd_t *Bw = mzd_init_window(A, 0, r_radix, r, A->ncols); mzd_trsm_upper_left(U, B, 0); mzd_copy(Bw, B); mzd_free_window(Bw); mzd_free(B); } } mzd_set_ui(U, 1); mzd_free_window(U); if(r) { mzd_t *A0 = mzd_init_window(A, 0, 0, r, A->ncols); mzd_apply_p_right(A0, Q); mzd_free_window(A0); } #endif } else { r = mzd_ple(A, P, Q, 0); for(rci_t i = 0; i < r; ++i) { for(rci_t j = 0; j <= i; j += m4ri_radix) { int const length = MIN(m4ri_radix, i - j + 1); mzd_clear_bits(A, i, j, length); } mzd_write_bit(A, i, Q->values[i], 1); } } if(r != A->nrows) { mzd_t *R = mzd_init_window(A, r, 0, A->nrows, A->ncols); mzd_set_ui(R, 0); mzd_free_window(R); } mzp_free(P); mzp_free(Q); __M4RI_DD_MZD(A); __M4RI_DD_RCI(r); return r; }