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
|
/*******************************************************************
*
* M4RI: Linear Algebra over GF(2)
*
* Copyright (C) 2008 Jean-Guillaume.Dumas@imag.fr
*
* 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 "solve.h"
#include "strassen.h"
#include "ple.h"
#include "triangular.h"
#include "mzp.h"
int mzd_solve_left(mzd_t *A, mzd_t *B, int const cutoff, int const inconsistency_check) {
if(A->ncols > B->nrows)
m4ri_die("mzd_solve_left: A ncols (%d) must be smaller than B nrows (%d).\n", A->ncols, B->nrows);
return _mzd_solve_left(A, B, cutoff, inconsistency_check);
}
int mzd_pluq_solve_left (mzd_t const *A, rci_t rank,
mzp_t const *P, mzp_t const *Q,
mzd_t *B, int const cutoff, int const inconsistency_check) {
if(A->ncols > B->nrows)
m4ri_die("mzd_pluq_solve_left: A ncols (%d) need to be lower than B nrows (%d).\n", A->ncols, B->nrows);
if(P->length != A->nrows)
m4ri_die("mzd_pluq_solve_left: A nrows (%d) need to match P size (%d).\n", A->nrows, P->length);
if(Q->length != A->ncols)
m4ri_die("mzd_pluq_solve_left: A ncols (%d) need to match Q size (%d).\n", A->ncols, P->length);
return _mzd_pluq_solve_left (A, rank, P, Q, B, cutoff, inconsistency_check);
}
int _mzd_pluq_solve_left(mzd_t const *A, rci_t rank,
mzp_t const *P, mzp_t const *Q,
mzd_t *B, int const cutoff, int const inconsistency_check) {
/** A is supposed to store L lower triangular and U upper triangular
* B is modified in place
* (Bi's in the comments are just modified versions of B)
* PLUQ = A
* 1) P B2 = B1
* 2) L B3 = B2
* 3) U B4 = B3
* 4) Q B5 = B4
*/
int retval = 0;
/* P B2 = B1 or B2 = P^T B1 */
mzd_apply_p_left(B, P);
/* L B3 = B2 */
/* view on the upper part of L */
mzd_t const *LU = mzd_init_window_const(A, 0, 0, rank, rank);
mzd_t *Y1 = mzd_init_window(B, 0, 0, rank, B->ncols);
mzd_trsm_lower_left(LU, Y1, cutoff);
if (inconsistency_check) { /* Check for inconsistency */
/** FASTER without this check; update with the lower part of L
*/
mzd_t const *H = mzd_init_window_const(A, rank, 0, A->nrows, rank);
mzd_t *Y2 = mzd_init_window(B, rank, 0, A->nrows, B->ncols);
if(A->nrows < B->nrows) {
mzd_t *Y3 = mzd_init_window(B, A->nrows, 0, B->nrows, B->ncols);
mzd_set_ui(Y3, 0);
mzd_free_window(Y3);
}
mzd_addmul(Y2, H, Y1, cutoff);
/*
* test whether Y2 is the zero matrix
*/
if(!mzd_is_zero(Y2)) {
retval = -1;
}
mzd_free_window((mzd_t*)H);
mzd_free_window(Y2);
}
/* U B4 = B3 */
mzd_trsm_upper_left(LU, Y1, cutoff);
mzd_free_window((mzd_t*)LU);
mzd_free_window(Y1);
if (!inconsistency_check) {
/** Default is to set the undefined bits to zero if inconsistency
* has been checked then Y2 bits are already all zeroes thus this
* clearing is not needed
*/
for(rci_t i = rank; i < B->nrows; ++i) {
for(rci_t j = 0; j < B->ncols; j += m4ri_radix) {
mzd_clear_bits(B, i, j, MIN(m4ri_radix, B->ncols - j));
}
}
}
/* Q B5 = B4 or B5 = Q^T B4 */
mzd_apply_p_left_trans(B, Q);
/* P L U Q B5 = B1 */
__M4RI_DD_MZD(B);
__M4RI_DD_INT(retval);
return retval;
}
int _mzd_solve_left(mzd_t *A, mzd_t *B, int const cutoff, int const inconsistency_check) {
/**
* B is modified in place
* (Bi's in the comments are just modified versions of B)
* 1) PLUQ = A
* 2) P B2 = B1
* 3) L B3 = B2
* 4) U B4 = B3
* 5) Q B5 = B4
*/
mzp_t *P = mzp_init(A->nrows);
mzp_t *Q = mzp_init(A->ncols);
/* PLUQ = A */
rci_t rank = _mzd_pluq(A, P, Q, cutoff);
/* 2, 3, 4, 5 */
int retval = mzd_pluq_solve_left(A, rank, P, Q, B, cutoff, inconsistency_check);
mzp_free(P);
mzp_free(Q);
__M4RI_DD_MZD(A);
__M4RI_DD_MZD(B);
return retval;
}
mzd_t *mzd_kernel_left_pluq(mzd_t *A, int const cutoff) {
mzp_t *P = mzp_init(A->nrows);
mzp_t *Q = mzp_init(A->ncols);
rci_t r = mzd_pluq(A, P, Q, cutoff);
if (r == A->ncols) {
mzp_free(P);
mzp_free(Q);
__M4RI_DD_MZD(A);
return NULL;
}
mzd_t *U = mzd_init_window(A, 0, 0, r, r);
mzd_t *R = mzd_init(A->ncols, A->ncols - r);
mzd_t *RU = mzd_init_window(R, 0, 0, r, R->ncols);
for(rci_t i=0; i< r ; i++) {
for(rci_t j=0; j< RU->ncols; j+=m4ri_radix) {
const int workload = MIN(m4ri_radix, RU->ncols - j);
mzd_xor_bits(RU, i, j, workload, mzd_read_bits(A, i, r + j, workload));
}
}
mzd_trsm_upper_left(U, RU, cutoff);
for(rci_t i = 0; i < R->ncols; ++i) {
mzd_write_bit(R, r + i, i, 1);
}
mzd_apply_p_left_trans(R, Q);
mzp_free(P);
mzp_free(Q);
mzd_free_window(RU);
mzd_free_window(U);
__M4RI_DD_MZD(A);
__M4RI_DD_MZD(R);
return R;
}
|