From fb45b7ae532984719c87ae6d8877ae15ff240051 Mon Sep 17 00:00:00 2001 From: Gilles Villard Date: Wed, 8 Apr 2026 16:39:38 +0200 Subject: [PATCH 1/5] Cleaning for kernel --- flint-extras/src/nmod_poly_mat_extra/kernel.c | 683 +----------------- .../src/nmod_poly_mat_extra/test/main.c | 2 - .../nmod_poly_mat_extra/test/t-kernel_zls.c | 157 ---- 3 files changed, 1 insertion(+), 841 deletions(-) delete mode 100644 flint-extras/src/nmod_poly_mat_extra/test/t-kernel_zls.c diff --git a/flint-extras/src/nmod_poly_mat_extra/kernel.c b/flint-extras/src/nmod_poly_mat_extra/kernel.c index 774cd250..8fe4db5b 100644 --- a/flint-extras/src/nmod_poly_mat_extra/kernel.c +++ b/flint-extras/src/nmod_poly_mat_extra/kernel.c @@ -472,689 +472,8 @@ slong nmod_poly_mat_kernel_zls_approx(nmod_poly_mat_t ker, } - - - -/** - * - * The content of the file has not yet been tested very extensively - * - */ - -/** - * - * In place, M is m x n, shifted column degrees - * permute the columns in nondecreasing order - * - * Todo/to see: zero is set to degree 0 (not -1), for specific use - * in ZLS algorithm for the kernel - * - * Input: - * M m x n - * ishift[m] - * - * Output: - * M is modified in place - * perm[n],initialized outside, the carried out permutation - * sdeg[n] initialized outside - * - */ - -// Dummy function for qsort - int cmp(const void *a, const void *b) -{ - const slong *x = a; - const slong *y = b; - - if (*x < *y) return -1; - if (*x > *y) return 1; - return 0; -} - -void _nmod_poly_mat_sort_permute_columns_zls(nmod_poly_mat_t M, slong *sdeg, \ - slong *perm, const slong *ishift) -{ - - slong n = M->c; - slong j; - - nmod_poly_mat_column_degree(sdeg, M, ishift); - - for (j=0; j= 2, for the order of the order bases - * kappa * s instead of 3 *s in ZLS - * - * Output: - * returns the dimension w of the kernel, which may be zero - * N, n x w, is initialized here only when w > 0, - * should be freed outside in that case only, - * gives a minimal basis of the right kernel - * degN[n], initialized outside, its first w entries are concerned, - * they are the ishift shift degrees of the kernel basis - * - */ - -int nmod_poly_mat_zls_sorted(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ - const slong *ishift, const double kappa) -{ - - slong i,j,k; - - slong m = A->r; - slong n = A->c; - - - slong min_mn; - slong rho=0; - - // Tuning the order of the subsequent approximant - // ---------------------------------------------- - - long shift[n]; // temporary variable - - - // In order to sort for computing the order of the approximant, for the test m=1 to be ok - for (i=0; i n %ld %ld",m,n); // To see, rectangular case - } - - - slong s; - s = ceil((double) rho/min_mn); - - // Transposed A for the approximant PT on the left - // PT will then be use without transposing - - nmod_poly_mat_t AT; - nmod_poly_mat_init(AT, n, m, A->modulus); - nmod_poly_mat_transpose(AT,A); - - nmod_poly_mat_t PT; - nmod_poly_mat_init(PT, n, n, A->modulus); - - // Approximant PT - // shift is modified in place - // -------------------------- - - for (i=0; imodulus); - nmod_poly_mat_mul(RT,PT,AT); - - slong cdeg[n]; - nmod_poly_mat_row_degree(cdeg, RT, NULL); - - nmod_poly_mat_clear(AT); - - // Zero residue matrix P1 n x n1 - // nonzero residues matrix P2 n x n2 - //----------------------------------- - - slong n1=0; - slong n2; - - for (j=0; j0) { - nmod_poly_mat_init(P1, n, n1, A->modulus); - - k=0; - for (j = 0; j < n; j++) - { - if (cdeg[j]<0) { - - for (i = 0; i < n; i++) - nmod_poly_set(nmod_poly_mat_entry(P1, i, k), nmod_poly_mat_entry(PT, j, i)); - k+=1; - } - } - } - - n2=n-n1; - - // the kernel is found - if (n2==0) { - nmod_poly_mat_init_set(N,P1); - nmod_poly_mat_column_degree(degN, P1, ishift); - - nmod_poly_mat_clear(P1); - return n1; - } - - nmod_poly_mat_t P2; - nmod_poly_mat_init(P2, n, n2, A->modulus); - - k=0; - for (j = 0; j < n; j++) - { - if (cdeg[j]>=0) { - - for (i = 0; i < n; i++) - nmod_poly_set(nmod_poly_mat_entry(P2, i, k), nmod_poly_mat_entry(PT, j, i)); - k+=1; - } - - } - - //nmod_poly_mat_clear(PT); - - // Special case m=1 - // before the divide and conquer on m - // the kernel is found - // ----------------------------------- - - if (m==1){ - - if (n1==0) - return 0; - else { - - nmod_poly_mat_init_set(N,P1); - nmod_poly_mat_column_degree(degN, P1, ishift); - - nmod_poly_mat_clear(P1); - return n1; - } - } - - // Now n2 <> 0 and m > 1 - // one can proceed to the divide and conquer from the rows - // of the nonzero residue P2, and of A.P2 - // -------------------------------------------------------- - - slong * perm = flint_malloc(n2 * sizeof(slong)); - - - slong degP2[n2]; - - // perm will be used also later for G from RT - _nmod_poly_mat_sort_permute_columns_zls(P2,degP2,perm,ishift); - - for (i = 0; i < n2; i++) { - degP2[i]=degP2[i]-ks; // used below for the recursive calls - } - - - //+++++++++ OLD - - // nmod_poly_mat_t G; - // nmod_poly_mat_init(G, m, n2, A->modulus); - - // nmod_poly_mat_mul(G, A, P2); - - // nmod_poly_mat_t TT; - // nmod_poly_mat_init(TT, m, n2, A->modulus); - - - // nmod_poly_mat_shift_right(TT,G,ks); - - - // slong new_m=floor((double) m/2); - - // nmod_poly_mat_t G1; - // nmod_poly_mat_init(G1, new_m, n2, A->modulus); - - // for (i = 0; i < new_m; i++){ - // for (j = 0; j < n2; j++) { - // nmod_poly_set(nmod_poly_mat_entry(G1, i, j), nmod_poly_mat_entry(TT, i, j)); - // } - // } - - // nmod_poly_mat_t G2; - // nmod_poly_mat_init(G2, m-new_m, n2, A->modulus); - - // for (i = 0; i < m-new_m; i++) { - // for (j = 0; j < n2; j++) { - // nmod_poly_set(nmod_poly_mat_entry(G2, i, j), nmod_poly_mat_entry(TT, i+new_m, j)); - // } - // } - - - //++++++++ END OLD - - - //++++++++++ NEW ++++++++++++++ - nmod_poly_mat_t TT; - nmod_poly_mat_init(TT, m, n2, A->modulus); - - // We extract G (temporary TT) from RT as we have been extracting P2 from PT - // and apply above ordering of P2 - k=0; - for (j = 0; j < n; j++) - { - if (cdeg[j]>=0) { - - for (i = 0; i < m; i++) - nmod_poly_set(nmod_poly_mat_entry(TT, i, k), nmod_poly_mat_entry(RT, j, i)); - k+=1; - } - - } - nmod_poly_mat_clear(RT); - - nmod_poly_mat_permute_columns(TT, perm, NULL); - - nmod_poly_mat_t G; - nmod_poly_mat_init(G, m, n2, A->modulus); - - nmod_poly_mat_shift_right(G,TT,ks); - - - // We split G for the recursive call - // --------------------------------- - - slong new_m=floor((double) m/2); - - nmod_poly_mat_t G1; - nmod_poly_mat_init(G1, new_m, n2, A->modulus); - - for (i = 0; i < new_m; i++){ - for (j = 0; j < n2; j++) { - nmod_poly_set(nmod_poly_mat_entry(G1, i, j), nmod_poly_mat_entry(G, i, j)); - } - } - - nmod_poly_mat_t G2; - nmod_poly_mat_init(G2, m-new_m, n2, A->modulus); - - for (i = 0; i < m-new_m; i++) { - for (j = 0; j < n2; j++) { - nmod_poly_set(nmod_poly_mat_entry(G2, i, j), nmod_poly_mat_entry(G, i+new_m, j)); - } - } - - nmod_poly_mat_clear(TT); - nmod_poly_mat_clear(G); - //++++++++++++++ END NEW ++++++++++++++++++ - - // Recursive calls - // --------------- - - nmod_poly_mat_t N1; - nmod_poly_mat_t N2; - - slong c1=0; - slong c2=0; - - - c1=nmod_poly_mat_zls_sorted(N1, degN, G1, degP2, kappa); - - - if (c1 != 0) { - - nmod_poly_mat_t G3; - nmod_poly_mat_init(G3, m-new_m, c1, A->modulus); - - nmod_poly_mat_mul(G3, G2, N1); - - for (i=0; imodulus); - - nmod_poly_mat_mul(Q1, P2, N1); - - nmod_poly_mat_t Q; - nmod_poly_mat_init(Q, n, c2, A->modulus); - - nmod_poly_mat_mul(Q, Q1, N2); - - nmod_poly_mat_clear(N1); - nmod_poly_mat_clear(N2); - nmod_poly_mat_clear(Q1); - nmod_poly_mat_clear(P2); - - if (n1 ==0) { - - nmod_poly_mat_init_set(N,Q); // We should not need to copy - nmod_poly_mat_column_degree(degN, Q, ishift); - - nmod_poly_mat_clear(Q); - return c2; - - } - else { - nmod_poly_mat_init(N, n, n1+c2, A->modulus); - - for (i = 0; i < n; i++) { - for (j = 0; j < n1; j++) { - nmod_poly_set(nmod_poly_mat_entry(N, i, j), nmod_poly_mat_entry(P1,i,j)); - } - } - - for (i = 0; i < n; i++) { - for (j = 0; j < c2; j++) { - nmod_poly_set(nmod_poly_mat_entry(N, i, j+n1), nmod_poly_mat_entry(Q, i, j)); - } - } - - slong odeg[n1+c2]; - - nmod_poly_mat_column_degree(odeg, P1, ishift); - - for (i=0; i= 2, for the order of the order bases - * kappa * s instead of 3 *s in ZLS - * - * Output: - * returns the dimension w of the kernel, which may be zero - * N, is initialized n x n outside - * its first w columns give a minimal basis of the kernel - * degN[n], initialized outside, its first w entries are concerned, - * they are the ishift shifted degrees of the kernel basis - * - */ - -/** - * Calls nmod_poly_mat_zls_sorted after an initial sorting - */ - -int nmod_poly_mat_kernel_zls(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t iA, \ - const slong *ishift, const double kappa) -{ - - slong j,k; - - slong n = iA->c; - - - nmod_poly_mat_t A; - nmod_poly_mat_init_set(A, iA); - - slong * perm = flint_malloc(n * sizeof(slong)); - slong sdeg[n]; - - // No input shift, simply the column degrees, then ordered - // a permutation is carried out in place - // ------------------------------------------------------- - - if (ishift == NULL) { - nmod_poly_mat_column_degree(sdeg, A, NULL); - - for (j=0; j 0 - - return nz; - } - - flint_free(perm); - nmod_poly_mat_clear(A); - - return 0; - -} - - -/** - * Experimental, should not be really considered - * - */ - -int nmod_poly_mat_approximant_kernel(nmod_poly_mat_t N, slong * FLINT_UNUSED(degN), const nmod_poly_mat_t A, \ - const slong *ishift) -{ - - slong i,j,k; - - slong m = A->r; - slong n = A->c; - - slong deg[n]; - - nmod_poly_mat_column_degree(deg, A, NULL); - - slong degmax=deg[0]; - for (i=1; im) - min_nm=m; - - nmod_poly_mat_t AT; - nmod_poly_mat_init(AT, n, m, A->modulus); - nmod_poly_mat_transpose(AT,A); - - nmod_poly_mat_t PT; - nmod_poly_mat_init(PT, n, n, A->modulus); - - - // Approximant PT - // shift is modified in place - // -------------------------- - - slong shift[n]; - for (i=0; imodulus); - nmod_poly_mat_mul(RT,PT,AT); - - slong cdeg[n]; - nmod_poly_mat_row_degree(cdeg, RT, NULL); - - nmod_poly_mat_clear(AT); - nmod_poly_mat_clear(RT); - - - // Zero residue matrix P1 - //----------------------- - - slong n1=0; - - for (j=0; j 0) { - - k=0; - - for (j=0; j. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "nmod_poly_mat_forms.h" -#include "nmod_poly_mat_kernel.h" - -// test one given input -int core_test_kernel_zls(const nmod_poly_mat_t mat, flint_rand_t state) -{ - slong n = mat->c; - - /* pick shift with entries >= cdeg */ - slong * cdeg = FLINT_ARRAY_ALLOC(n, slong); - nmod_poly_mat_column_degree(cdeg, mat, NULL); - slong * shift = FLINT_ARRAY_ALLOC(n, slong); - for (slong j = 0; j < n; j++) - shift[j] = FLINT_MAX(0, cdeg[j]) + n_randint(state, 30); - - nmod_poly_mat_t N; - nmod_poly_mat_init(N, n, n, mat->modulus); - slong degN[n]; - slong nz = nmod_poly_mat_kernel_zls(N, degN, mat, shift, 2.); - - nmod_poly_mat_t Nnz; - nmod_poly_mat_window_init(Nnz, N, 0, 0, n, nz); - int verif = nmod_poly_mat_is_kernel(Nnz, shift, mat, REDUCED, COL_UPPER); - - nmod_poly_mat_clear(N); - nmod_poly_mat_window_clear(Nnz); - flint_free(cdeg); - flint_free(shift); - - return verif; -} - -TEST_FUNCTION_START(nmod_poly_mat_kernel_zls, state) -{ - int i, result; - - for (i = 0; i < 16 * flint_test_multiplier(); i++) - { - ulong nbits = 2 + n_randint(state, 63); - ulong rdim = 1 + n_randint(state, 20); - ulong cdim = rdim + 1 + n_randint(state, 20); - ulong deg = n_randint(state, 100); - - ulong prime = n_randprime(state, nbits, 1); - - nmod_poly_mat_t A; - - if (i < 4) - { - cdim=rdim; - nmod_poly_mat_init(A, rdim, cdim, prime); - nmod_poly_mat_randtest_sparse(A, state, deg+1, 1.0); - } - else if (i < 8) - { - cdim=rdim+1; - nmod_poly_mat_init(A, rdim, cdim, prime); - nmod_poly_mat_randtest_sparse(A, state, deg+1, 0.8); - } - else if (i < 12) - { - nmod_poly_mat_init(A, rdim, cdim, prime); - nmod_poly_mat_randtest_sparse(A, state, deg+1, 0.2); - } - else - { - nmod_poly_mat_init(A, rdim, cdim, prime); - nmod_poly_mat_randtest_sparse(A, state, deg+1, 0.84); - } - - result = core_test_kernel_zls(A, state); - - nmod_poly_mat_clear(A); - - if (!result) - { - TEST_FUNCTION_FAIL("rdim = %wu, cdim = %wu, degree = %wu, p = %wu\n", \ - rdim, cdim, deg, prime); - } - } - - // Degree zero - // ----------- - - for (i = 0; i < 2; i++) - { - ulong rdim = 40 + n_randint(state, 8); - ulong cdim = rdim + n_randint(state, 8); - ulong deg = 0; - - ulong prime = 7; - - nmod_poly_mat_t A; - - nmod_poly_mat_init(A, rdim, cdim, prime); - nmod_poly_mat_randtest_sparse(A, state, deg+1, 0.8); - - result = core_test_kernel_zls(A, state); - - nmod_poly_mat_clear(A); - - if (!result) - { - TEST_FUNCTION_FAIL("rdim = %wu, cdim = %wu, degree = %wu, p = %wu\n", \ - rdim, cdim, deg, prime); - } - } - - // Column dimension smaller that row dimension - // ------------------------------------------- - - for (i = 0; i < 2; i++) - { - ulong rdim = 20 + n_randint(state, 8); - ulong cdim = rdim -8; - ulong deg = 1; - - ulong prime = 2; - - nmod_poly_mat_t A; - - nmod_poly_mat_init(A, rdim, cdim, prime); - nmod_poly_mat_randtest_sparse(A, state, deg+1, 0.2); - - result = core_test_kernel_zls(A, state); - - nmod_poly_mat_clear(A); - - if (!result) - { - TEST_FUNCTION_FAIL("rdim = %wu, cdim = %wu, degree = %wu, p = %wu\n", \ - rdim, cdim, deg, prime); - } - } - - TEST_FUNCTION_END(state); -} From 30a6c0313baf35f8baeec092fa9c76371de771f3 Mon Sep 17 00:00:00 2001 From: Gilles Villard Date: Wed, 8 Apr 2026 16:53:41 +0200 Subject: [PATCH 2/5] cleaning .h --- flint-extras/src/nmod_poly_mat_kernel.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/flint-extras/src/nmod_poly_mat_kernel.h b/flint-extras/src/nmod_poly_mat_kernel.h index 2598dd2e..0cd81c1c 100644 --- a/flint-extras/src/nmod_poly_mat_kernel.h +++ b/flint-extras/src/nmod_poly_mat_kernel.h @@ -180,22 +180,6 @@ int nmod_poly_mat_is_kernel(const nmod_poly_mat_t ker, * */ -/* int nmod_poly_mat_kernel(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ */ -/* const slong *ishift, const double kappa); */ - -int nmod_poly_mat_kernel_zls(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ - const slong *ishift, const double kappa); - - -/** - * Experimental, should not be really considered - * - */ - -int nmod_poly_mat_approximant_kernel(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ - const slong *ishift); - - #ifdef __cplusplus } #endif From 02b1b5f6acdd93729b7bc547ba14d8ae2c726ced Mon Sep 17 00:00:00 2001 From: Gilles Villard Date: Wed, 8 Apr 2026 17:31:14 +0200 Subject: [PATCH 3/5] cleaning --- flint-extras/src/nmod_poly_mat_kernel.h | 32 ------------------------- 1 file changed, 32 deletions(-) diff --git a/flint-extras/src/nmod_poly_mat_kernel.h b/flint-extras/src/nmod_poly_mat_kernel.h index 0cd81c1c..4aa90249 100644 --- a/flint-extras/src/nmod_poly_mat_kernel.h +++ b/flint-extras/src/nmod_poly_mat_kernel.h @@ -148,38 +148,6 @@ int nmod_poly_mat_is_kernel(const nmod_poly_mat_t ker, orientation_t orient); -/** - * - * Right shifted kernel of a polynomial matrix, assuming that the columns has been - * sorted by shifted degree - * - * Algorithm of Wei Zhou, George Labahn, and Arne Storjohann - * "Computing Minimal Nullspace Bases" - * ISSAC 2012, https://dl.acm.org/doi/abs/10.1145/2442829.2442881 - * - * Calls nmod_poly_mat_zls_sorted after an initial sorting - * - * TODO/TO SEE: - * - * Input: - * iA in m x n - * ishift[n], NULL (the degrees are computed) or initialized outside, - * the shift for the kernel - * values should be at least 0 (even for zero columns in A - * "with entries arranged in non-decreasing order and bounding the - * corresponding column degrees of A." - * kappa, a double >= 2, for the order of the order bases - * kappa * s instead of 3 *s in ZLS - * - * Output: - * returns the dimension w of the kernel, which may be zero - * N, is initialized n x n outside - * its first w columns give a minimal basis of the kernel - * degN[n], initialized outside, its first w entries are concerned, - * they are the ishift shifted degrees of the kernel basis - * - */ - #ifdef __cplusplus } #endif From c8117b3f62a78c1c01718dbf8c4c82508d92cad6 Mon Sep 17 00:00:00 2001 From: Gilles Villard Date: Wed, 8 Apr 2026 18:01:30 +0200 Subject: [PATCH 4/5] for check ubuntu that fails --- flint-extras/src/nmod_poly_mat_kernel.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/flint-extras/src/nmod_poly_mat_kernel.h b/flint-extras/src/nmod_poly_mat_kernel.h index 4aa90249..3b46faf0 100644 --- a/flint-extras/src/nmod_poly_mat_kernel.h +++ b/flint-extras/src/nmod_poly_mat_kernel.h @@ -148,6 +148,22 @@ int nmod_poly_mat_is_kernel(const nmod_poly_mat_t ker, orientation_t orient); +/* int nmod_poly_mat_kernel(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ */ +/* const slong *ishift, const double kappa); */ + +int nmod_poly_mat_kernel_zls(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ + const slong *ishift, const double kappa); + + +/** + * Experimental, should not be really considered + * + */ + +int nmod_poly_mat_approximant_kernel(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ + const slong *ishift); + + #ifdef __cplusplus } #endif From 4ec7606dd9cb3a9f2565ab6392bcede5ad22ff33 Mon Sep 17 00:00:00 2001 From: Gilles Villard Date: Wed, 8 Apr 2026 18:24:49 +0200 Subject: [PATCH 5/5] new attempt --- flint-extras/src/nmod_poly_mat_kernel.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/flint-extras/src/nmod_poly_mat_kernel.h b/flint-extras/src/nmod_poly_mat_kernel.h index 3b46faf0..4aa90249 100644 --- a/flint-extras/src/nmod_poly_mat_kernel.h +++ b/flint-extras/src/nmod_poly_mat_kernel.h @@ -148,22 +148,6 @@ int nmod_poly_mat_is_kernel(const nmod_poly_mat_t ker, orientation_t orient); -/* int nmod_poly_mat_kernel(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ */ -/* const slong *ishift, const double kappa); */ - -int nmod_poly_mat_kernel_zls(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ - const slong *ishift, const double kappa); - - -/** - * Experimental, should not be really considered - * - */ - -int nmod_poly_mat_approximant_kernel(nmod_poly_mat_t N, slong *degN, const nmod_poly_mat_t A, \ - const slong *ishift); - - #ifdef __cplusplus } #endif