2023-05-10 19:55:40 +08:00

139 lines
3.5 KiB
C

/*******************************************************************
*
* M4RI: Linear Algebra over GF(2)
*
* Copyright (C) 2010 Martin Albrecht <M.R.Albrecht@rhul.ac.uk>
*
* 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;
}