diff --git a/CMakeLists.txt b/CMakeLists.txt index 2616d0669f..77bb965ba9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,16 +59,15 @@ endif() # Find sources set(BUILD_DIRS - aprcl ulong_extras long_extras perm fmpz fmpz_vec fmpz_poly - fmpq_poly fmpz_mat fmpz_lll mpfr_vec mpfr_mat mpf_vec mpf_mat nmod_vec nmod_poly - nmod_poly_factor arith mpn_extras nmod_mat fmpq fmpq_vec fmpq_mat padic - fmpz_poly_q fmpz_poly_mat nmod_poly_mat fmpz_mod_poly fmpz_mod_mat + aprcl ulong_extras long_extras perm fmpz fmpz_vec fmpz_sparse_vec fmpz_poly + fmpq_poly fmpz_mat fmpz_sparse_mat fmpz_mod_mat fmpz_lll mpfr_vec mpfr_mat mpf_vec mpf_mat nmod_vec nmod_sparse_vec nmod_poly + nmod_poly_factor arith mpn_extras nmod_mat nmod_sparse_mat fmpq fmpq_vec fmpq_mat padic + fmpz_poly_q fmpz_poly_mat nmod_poly_mat fmpz_mod_poly fmpz_mod_poly_factor fmpz_factor fmpz_poly_factor fft qsieve double_extras d_vec d_mat padic_poly padic_mat qadic - fq fq_vec fq_mat fq_poly fq_poly_factor - fq_nmod fq_nmod_vec fq_nmod_mat fq_nmod_poly fq_nmod_poly_factor - fq_zech fq_zech_vec fq_zech_mat fq_zech_poly fq_zech_poly_factor - fq_default fq_default_mat fq_default_poly fq_default_poly_factor + fq fq_vec fq_sparse_vec fq_mat fq_sparse_mat fq_poly fq_poly_factor + fq_nmod fq_nmod_vec fq_nmod_sparse_vec fq_nmod_mat fq_nmod_sparse_mat fq_nmod_poly fq_nmod_poly_factor + fq_zech fq_zech_vec fq_zech_sparse_vec fq_zech_mat fq_zech_sparse_mat fq_zech_poly fq_zech_poly_factor thread_pool fmpz_mod fmpz_mod_vec n_poly mpoly fmpz_mpoly fmpq_mpoly nmod_mpoly fq_nmod_mpoly fmpz_mod_mpoly fmpz_mpoly_factor fmpq_mpoly_factor nmod_mpoly_factor fmpz_mod_mpoly_factor @@ -77,14 +76,14 @@ set(BUILD_DIRS ) set(TEMPLATE_DIRS - fq_vec_templates fq_mat_templates fq_poly_templates + fq_vec_templates fq_sparse_vec_templates fq_mat_templates fq_sparse_mat_templates fq_poly_templates fq_poly_factor_templates fq_templates ) set(SOURCES printf.c fprintf.c sprintf.c scanf.c fscanf.c sscanf.c clz_tab.c memory_manager.c version.c profiler.c thread_support.c exception.c - hashmap.c inlines.c fmpz/fmpz.c + heap.c hashmap.c inlines.c fmpz/fmpz.c ) if (MSVC) @@ -97,7 +96,7 @@ endif() set(HEADERS NTL-interface.h flint.h longlong.h flint-config.h gmpcompat.h fft_tuning.h - fmpz-conversions.h profiler.h templates.h exception.h hashmap.h + fmpz-conversions.h profiler.h templates.h exception.h heap.h hashmap.h ) foreach (build_dir IN LISTS BUILD_DIRS TEMPLATE_DIRS) diff --git a/Makefile.in b/Makefile.in index e2ad7de956..4de9334a99 100644 --- a/Makefile.in +++ b/Makefile.in @@ -6,15 +6,15 @@ QUIET_AR = @echo ' ' AR ' ' $@; AT=@ -BUILD_DIRS = aprcl ulong_extras long_extras perm fmpz fmpz_vec fmpz_poly \ - fmpq_poly fmpz_mat fmpz_lll mpfr_vec mpfr_mat mpf_vec mpf_mat nmod_vec nmod_poly \ - nmod_poly_factor arith mpn_extras nmod_mat fmpq fmpq_vec fmpq_mat padic \ +BUILD_DIRS = aprcl ulong_extras long_extras perm fmpz fmpz_vec fmpz_sparse_vec fmpz_poly \ + fmpq_poly fmpz_mat fmpz_sparse_mat fmpz_lll mpfr_vec mpfr_mat mpf_vec mpf_mat nmod_vec nmod_sparse_vec nmod_poly \ + nmod_poly_factor arith mpn_extras nmod_mat nmod_sparse_mat fmpq fmpq_vec fmpq_mat padic \ fmpz_poly_q fmpz_poly_mat nmod_poly_mat fmpz_mod_poly \ fmpz_mod_poly_factor fmpz_factor fmpz_poly_factor fft qsieve \ double_extras d_vec d_mat padic_poly padic_mat qadic \ - fq fq_vec fq_mat fq_poly fq_poly_factor fq_embed \ - fq_nmod fq_nmod_vec fq_nmod_mat fq_nmod_poly fq_nmod_poly_factor fq_nmod_embed \ - fq_zech fq_zech_vec fq_zech_mat fq_zech_poly fq_zech_poly_factor fq_zech_embed \ + fq fq_vec fq_sparse_vec fq_mat fq_sparse_mat fq_poly fq_poly_factor fq_embed \ + fq_nmod fq_nmod_vec fq_nmod_sparse_vec fq_nmod_mat fq_nmod_sparse_mat fq_nmod_poly fq_nmod_poly_factor fq_nmod_embed \ + fq_zech fq_zech_vec fq_zech_sparse_vec fq_zech_mat fq_zech_sparse_mat fq_zech_poly fq_zech_poly_factor fq_zech_embed \ fmpz_mod_mat mpoly fmpz_mpoly fmpq_mpoly nmod_mpoly fq_nmod_mpoly \ thread_pool fmpz_mod fmpz_mod_vec fmpz_mod_mpoly fmpz_mod_mpoly_factor \ n_poly fmpz_mpoly_factor fmpq_mpoly_factor nmod_mpoly_factor \ @@ -27,10 +27,10 @@ TEMPLATE_DIRS = fq_vec_templates fq_mat_templates fq_poly_templates \ export -SOURCES = printf.c fprintf.c sprintf.c scanf.c fscanf.c sscanf.c clz_tab.c memory_manager.c version.c profiler.c thread_support.c exception.c hashmap.c inlines.c +SOURCES = printf.c fprintf.c sprintf.c scanf.c fscanf.c sscanf.c clz_tab.c memory_manager.c version.c profiler.c thread_support.c exception.c heap.c hashmap.c inlines.c LIB_SOURCES = $(wildcard $(patsubst %, %/*.c, $(BUILD_DIRS))) $(patsubst %, %/*.c, $(TEMPLATE_DIRS)) -HEADERS = $(patsubst %, %.h, $(BUILD_DIRS)) NTL-interface.h flint.h longlong.h flint-config.h gmpcompat.h fft_tuning.h fmpz-conversions.h profiler.h templates.h exception.h hashmap.h thread_support.h $(patsubst %, %.h, $(TEMPLATE_DIRS)) +HEADERS = $(patsubst %, %.h, $(BUILD_DIRS)) NTL-interface.h flint.h longlong.h flint-config.h gmpcompat.h fft_tuning.h fmpz-conversions.h profiler.h templates.h exception.h heap.h hashmap.h thread_support.h $(patsubst %, %.h, $(TEMPLATE_DIRS)) OBJS = $(patsubst %.c, build/%.o, $(SOURCES)) LIB_OBJS = $(patsubst %, build/%/*.o, $(BUILD_DIRS)) diff --git a/config.h.in b/config.h.in index d6e68ca591..9baa1db0e2 100644 --- a/config.h.in +++ b/config.h.in @@ -8,7 +8,7 @@ #cmakedefine01 FLINT_WANT_ASSERT /* Define if you cpu_set_t in sched.h */ -#cmakedefine01 FLINT_USES_CPUSET +#cmakedefine01 HAVE_CPU_SET_T #cmakedefine01 FLINT_USES_PTHREAD diff --git a/doc/source/fq_nmod_sparse_mat.rst b/doc/source/fq_nmod_sparse_mat.rst new file mode 100644 index 0000000000..ab7f04ac78 --- /dev/null +++ b/doc/source/fq_nmod_sparse_mat.rst @@ -0,0 +1,295 @@ +.. _fq-nmod-sparse-mat: + +**fq_nmod_sparse_mat.h** -- sparse matrixs over finite fields (word-size characteristic) +=============================================================================== + +Description. + +Types, macros and constants +------------------------------------------------------------------------------- + +.. type:: fq_nmod_sparse_mat_t + + Holds an array of (possibly empty) sparse vectors corresponding to rows in + the matrix + +Memory management +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_mat_init(fq_nmod_sparse_mat_t M, slong rows, slong cols, const fq_nmod_ctx_t ctx) + + Initializes an empty sparse matrix ``M`` with given number of rows and columns + +.. function:: void fq_nmod_sparse_mat_clear(fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Clears the entries of the matrix ``M`` and frees the space allocated for it + +.. function:: void fq_nmod_sparse_mat_swap(fq_nmod_sparse_mat_t M1, fq_nmod_sparse_mat_t M2, const fq_nmod_ctx_t ctx) + + Swaps two matrices ``M1`` and ``M2`` (no reallocaton) + + +Instantiation +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_mat_zero(fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Sets matrix ``M`` to zero (the empty sparse matrix) + +.. function:: void fq_nmod_sparse_mat_one(fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Sets matrix ``M`` to identity matrix (based on its number of rows) + +.. function:: void fq_nmod_sparse_mat_set(fq_nmod_sparse_mat_t N, const fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Makes ``N`` a (deep) copy of ``M`` + +.. function:: void fq_nmod_sparse_mat_from_entries(fq_nmod_sparse_mat_t M, slong *rows, slong *inds, fq_nmod_struct *vals, slong nnz, const fq_nmod_ctx_t ctx) + + Constructs matrix ``M`` from a given sequence of ``rows``, ``cols``, and + corresponding ``vals``, all of length ``nnz``, assumes sorted by rows + with no duplicate (row, col) indices + +.. function:: void fq_nmod_sparse_mat_append_col(fq_nmod_sparse_mat_t M, const fq_nmod_struct *v, const fq_nmod_ctx_t ctx) + + Add a dense column to the right of the matrix + +.. function:: void fq_nmod_sparse_mat_append_row(fq_nmod_sparse_mat_t M, const fq_nmod_sparse_vec_t v, const fq_nmod_ctx_t ctx) + + Add a sparse row to the bottom of the matrix + + +Conversion to/from dense matrix +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_mat_from_dense(fq_nmod_sparse_mat_t M, const fq_nmod_mat_t dM, const fq_nmod_ctx_t ctx) + + Converts the dense matrix ``dM`` to a sparse matrix ``M`` + +.. function:: void fq_nmod_sparse_mat_to_dense(fq_nmod_mat_t dM, const fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Converts the sparse matrix ``M`` to a dense matrix ``dM`` + +Windows, concatenation, and splitting +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_mat_window_init(fq_nmod_sparse_mat_t window, const fq_nmod_sparse_mat_t M, slong r1, slong c1, slong r2, slong c2, const fq_nmod_ctx_t ctx) + + Constructs a window on the sparse matrix ``M`` between rows ``r1`` and ``r2`` + and cols ``c1`` and ``c2`` (valid as long as original matrix remains unmodified) + +.. function:: void fq_nmod_sparse_mat_window_clear(fq_nmod_sparse_mat_t window, const fq_nmod_ctx_t ctx) + + Clears a window + +.. function:: void fq_nmod_sparse_mat_concat_horizontal(fq_nmod_sparse_mat_t B, const fq_nmod_sparse_mat_t M1, const fq_nmod_sparse_mat_t M2, const fq_nmod_ctx_t ctx) + + Horizontally concatenates two matrices ``M1`` and ``M2`` into block matrix ``B`` + +.. function:: void fq_nmod_sparse_mat_concat_vertical(fq_nmod_sparse_mat_t B, const fq_nmod_sparse_mat_t M1, const fq_nmod_sparse_mat_t M2, const fq_nmod_ctx_t ctx) + + Vertically concatenates two matrices ``M1`` and ``M2`` into block matrix ``B`` + +.. function:: void fq_nmod_sparse_mat_split_horizontal(fq_nmod_sparse_mat_t M1, fq_nmod_sparse_mat_t M2, const fq_nmod_sparse_mat_t B, slong c, const fq_nmod_ctx_t ctx) + + Splits ``B`` horizontally into two submatrices ``M1`` and ``M2``, dividing at column ``c`` + +.. function:: void fq_nmod_sparse_mat_split_vertical(fq_nmod_sparse_mat_t M1, fq_nmod_sparse_mat_t M2, const fq_nmod_sparse_mat_t B, slong r, const fq_nmod_ctx_t ctx) + + Splits ``B`` vertically into two submatrices ``M1`` and ``M2``, dividing at row ``r`` + + +Permutation +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_mat_permute_cols(fq_nmod_sparse_mat_t M, slong *Q, const fq_nmod_ctx_t ctx) + + Permutes the columns indices of ``M`` according to ``Q``, and re-sorts each row + +.. function:: void fq_nmod_sparse_mat_permute_rows(fq_nmod_sparse_mat_t M, slong *P, const fq_nmod_ctx_t ctx) + + Permutes the rows of ``M`` according to ``P`` + + +Randomization +-------------------------------------------------------------------------------- + + +.. function:: void fq_nmod_sparse_mat_randtest(fq_nmod_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz, const fq_nmod_ctx_t ctx) + + Makes ``M`` a sparse matrix with between ``min_nnz`` and ``max_nnz`` nonzero + entries per row, with individual entries generated by fq_nmod_randtest + + +Output +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_mat_print_pretty(const fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Prints the matrix ``M`` to ``stdout`` in a human-readable format + + +Comparison +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_is_zero(fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Checks if the given matrix ``M`` is trivial (empty), returning `1` if so and `0` + otherwise + +.. function:: void fq_nmod_sparse_mat_equal(const fq_nmod_sparse_mat_t M1, const fq_nmod_sparse_mat_t M2, slong ioff, const fq_nmod_ctx_t ctx) + + Checks if ``M1`` equals ``M2``, returning `1` if so and `0` otherwise + + +Transpose +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_transpose(fq_nmod_sparse_mat_t N, const fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Transposes ``M`` into the matrix ``N`` (must have swapped rows and columns) + + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_mat_neg(fq_nmod_sparse_mat_t N, const fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Sets ``N`` to the negation of ``M`` + +.. function:: void fq_nmod_sparse_mat_scalar_mul_fq_nmod(fq_nmod_sparse_mat_t N, const fq_nmod_sparse_mat_t M, const fq_nmod_t c, const fq_nmod_ctx_t ctx) + + Sets ``N`` to the scalar multiple of ``M`` by ``c`` + +.. function:: void fq_nmod_sparse_mat_add(fq_nmod_sparse_mat_t O, const fq_nmod_sparse_mat_t M, const fq_nmod_sparse_mat_t N, const fq_nmod_ctx_t ctx) + + Sets ``O`` to the sum of ``M`` and ``N`` + +.. function:: void fq_nmod_sparse_mat_sub(fq_nmod_sparse_mat_t O, const fq_nmod_sparse_mat_t M, const fq_nmod_sparse_mat_t N, const fq_nmod_ctx_t ctx) + + Sets ``O`` to the difference of ``M`` and ``N`` + +.. function:: void fq_nmod_sparse_mat_scalar_addmul_fq_nmod(fq_nmod_sparse_mat_t O, const fq_nmod_sparse_mat_t M, const fq_nmod_sparse_mat_t N, const fq_nmod_t c, const fq_nmod_ctx_t ctx) + + Sets ``O`` to the sum of ``M`` and ``c` times ``N`` + +.. function:: void fq_nmod_sparse_mat_scalar_submul_fq_nmod(fq_nmod_sparse_mat_t O, const fq_nmod_sparse_mat_t M, const fq_nmod_sparse_mat_t N, const fq_nmod_t c, const fq_nmod_ctx_t ctx) + + Sets ``O`` to the difference of ``M`` and ``N` times ``v`` + +.. function:: void fq_nmod_sparse_mat_mul_vec(fq_nmod_struct *y, const fq_nmod_sparse_mat_t M, const fq_nmod_struct *x, const fq_nmod_ctx_t ctx) + + Sets ``y`` to the product of ``M`` and ``x`` + +.. function:: void fq_nmod_sparse_mat_mul_mat(fq_nmod_mat_t Y, const fq_nmod_sparse_mat_t M, const fq_nmod_mat_t X, const fq_nmod_ctx_t ctx) + + Sets ``Y`` to the product of ``M`` and ``X`` + +.. function:: slong fq_nmod_sparse_mat_inv(fq_nmod_sparse_mat_t N, const fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Sets ``N`` to the "inverse" of ``M``, i.e., the matrix such that NM is + in reduced row-echelon form + + +Decomposition/reduction +-------------------------------------------------------------------------------- + +.. function:: slong fq_nmod_sparse_mat_lu(slong *P, slong *Q, fq_nmod_sparse_mat_t L, fq_nmod_sparse_mat_t U, const fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Computes the decomposition PMQ = LU for a given sparse matrix ``M``, where + ``P`` is a row permutation, ``Q`` is a column permutation, ``L``is a lower + triangular matrix, and ``U`` is an upper triangular matrix + +.. function:: void fq_nmod_sparse_mat_rref(fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Applies row reduction to put ``M`` in reduced row echelon form (in place) + +Solving +-------------------------------------------------------------------------------- + +.. function:: int fq_nmod_sparse_mat_solve_lu(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, const fq_nmod_struct *b, const fq_nmod_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use LU decomposition to find + a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int fq_nmod_sparse_mat_solve_rref(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, const fq_nmod_struct *b, const fq_nmod_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use the reduced row-echelon + form to find a vector ``x`` such that Mx = b, returns `1` if successful and + `0` if not + +.. function:: int fq_nmod_sparse_mat_solve_lanczos(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, const fq_nmod_struct *b, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use the Lanczos algorithm to + find a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int fq_nmod_sparse_mat_solve_wiedemann(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, const fq_nmod_struct *b, const fq_nmod_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use the Wiedemann algorithm to + find a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int fq_nmod_sparse_mat_solve_block_lanczos(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, const fq_nmod_struct *b, slong block_size, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use Coppersmith's block Lanczos + algorithm (with specified block size) to find a vector ``x`` such that Mx = b, + returns `1` if successful and `0` if not + +.. function:: int fq_nmod_sparse_mat_solve_block_wiedemann(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, const fq_nmod_struct *b, slong block_size, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use Coppersmith's block Wiedemann + algorithm (with specified block size) to find a vector ``x`` such that Mx = b, + returns `1` if successful and `0` if not + +Nullvector and nullspace computation +-------------------------------------------------------------------------------- + +.. function:: int fq_nmod_sparse_mat_nullvector_lanczos(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use the Lanczos algorithm to find a nullvector ``x`` + s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_nmod_sparse_mat_nullvector_wiedemann(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use the Wiedemann algorithm to find a nullvector ``x`` + s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_nmod_sparse_mat_nullvector_block_lanczos(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Lanczos algorithm to find a + nullvector ``x`` s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_nmod_sparse_mat_nullvector_block_wiedemann(fq_nmod_struct *x, const fq_nmod_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Wiedemann algorithm to find a + nullvector ``x`` s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_nmod_sparse_mat_nullspace_rref(fq_nmod_mat_t X, const fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use the reduced row echelon form to construct the + nullspace ``X`` of M (initialized by this function), returns the nullity + +.. function:: int fq_nmod_sparse_mat_nullspace_lu(fq_nmod_mat_t X, const fq_nmod_sparse_mat_t M, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use the LU decomposition to construct the nullspace ``X`` + of M (initialized by this function), returns the nullity + +.. function:: int fq_nmod_sparse_mat_nullspace_lanczos(fq_nmod_mat_t X, const fq_nmod_sparse_mat_t M, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use the Lanczos algorithm to find a nullspace ``X`` + of M (initialized by this function), returns the found nullity + +.. function:: int fq_nmod_sparse_mat_nullspace_wiedemann(fq_nmod_mat_t X, const fq_nmod_sparse_mat_t M, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use the Wiedemann algorithm to find a nullspace ``X`` + of M (initialized by this function), returns the found nullity + +.. function:: int fq_nmod_sparse_mat_nullspace_block_lanczos(fq_nmod_mat_t X, const fq_nmod_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Lanczos algorithm to find a + nullspace ``X`` of M (initialized by this function), returns the found nullity + +.. function:: int fq_nmod_sparse_mat_nullspace_block_wiedemann(fq_nmod_mat_t X, const fq_nmod_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_nmod_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Wiedemann algorithm to find a + nullspace ``X`` of M (initialized by this function), returns the found nullity + diff --git a/doc/source/fq_nmod_sparse_vec.rst b/doc/source/fq_nmod_sparse_vec.rst new file mode 100644 index 0000000000..3a96e1e780 --- /dev/null +++ b/doc/source/fq_nmod_sparse_vec.rst @@ -0,0 +1,176 @@ +.. _fq-nmod-sparse-vec: + +**fq_nmod_sparse_vec.h** -- sparse vectors over finite fields (word-size characteristic) +=============================================================================== + +Description. + +Types, macros and constants +------------------------------------------------------------------------------- + +.. type:: fq_nmod_sparse_entry_t + + Holds a pair (ind, val), where ind (of type slong) is an index into the + vector and val (of type fq_nmod_t) is the value at that index + +.. type:: fq_nmod_sparse_vec_t + + Holds an array of nonzero entries (of type sparse_entry_struct *) of + specified length nnz, sorted by ind + +Memory management +-------------------------------------------------------------------------------- + + +.. function:: void fq_nmod_sparse_vec_init(fq_nmod_sparse_vec_t vec, const fq_nmod_ctx_t ctx) + + Initializes an empty sparse vector (no allocation) + +.. function:: void fq_nmod_sparse_vec_clear(fq_nmod_sparse_vec_t vec, slong len, const fq_nmod_ctx_t ctx) + + Clears the entries of vec and frees the space allocated for it + +.. function:: void fq_nmod_sparse_vec_swap(fq_nmod_sparse_vec_t vec1, fq_nmod_sparse_vec_t vec2, const fq_nmod_ctx_t ctx) + + Swaps two vectors (no reallocaton) + +Instantiation +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_vec_zero(fq_nmod_sparse_vec_t vec, const fq_nmod_ctx_t ctx) + + Sets vec to zero (the empty sparse vector) + +.. function:: void fq_nmod_sparse_vec_one(fq_nmod_sparse_vec_t vec, slong ind, const fq_nmod_ctx_t ctx) + + Sets vec to the ind-th basis vector (single one in position ind) + +.. function:: void fq_nmod_sparse_vec_set(fq_nmod_sparse_vec_t dst, fq_nmod_sparse_vec_t src, const fq_nmod_ctx_t ctx) + + Makes dst a (deep) copy of src + +.. function:: void fq_nmod_sparse_vec_set_entry(fq_nmod_sparse_vec_t vec, slong ind, const fq_nmod_t val, const fq_nmod_ctx_t ctx) + + Sets the value at index ind to val, either replacing an existing value or extending + the array of entries + +.. function:: void _fq_nmod_sparse_vec_from_entries(fq_nmod_sparse_vec_t vec, slong *inds, fq_nmod_struct *vals, slong nnz, const fq_nmod_ctx_t ctx) + + Constructs vec from a given sequence of indices and associated values, both of length nnz. + Assumes no duplicate indices + +Comparison +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_is_zero(fq_nmod_sparse_vec_t vec, const fq_nmod_ctx_t ctx) + + Checks if the given vector is trivial (empty), returning `1` if so and `0` + otherwise + +.. function:: void fq_nmod_sparse_vec_equal(const fq_nmod_sparse_vec_t vec1, const fq_nmod_sparse_vec_t vec2, slong ioff, const fq_nmod_ctx_t ctx) + + Checks if vec1 equals vec2 (with s specified column offset ioff), returning + `1` if so and `0` otherwise + +Indexing +-------------------------------------------------------------------------------- + +.. function:: fq_nmod_t * fq_nmod_sparse_vec_at(fq_nmod_sparse_vec_t vec, slong ind, const fq_nmod_ctx_t ctx) + + Returns a pointer to the value at the index ind (or NULL if index not found) + + +Conversion to/from dense vector +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_vec_from_dense(fq_nmod_sparse_vec_t dst, const fq_nmod_struct *src, slong len, const fq_nmod_ctx_t ctx) + + Converts the dense vector src of length len to a sparse vector + +.. function:: void fq_nmod_sparse_vec_to_dense(fq_nmod_struct *dst, const fq_nmod_sparse_vec_t src, slong len, const fq_nmod_ctx_t ctx) + + Converts the sparse vector src to a dense vector of length len + + +Windows, concatenation, and splitting +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_vec_window_init(fq_nmod_sparse_vec_t window, const fq_nmod_sparse_vec_t vec, slong i1, slong i2, const fq_nmod_ctx_t ctx) + + Constructs a window on a the sparse vector vec between indices i1 and i2 + Note that window is only valid as long as original vector remains unmodified + +.. function:: void fq_nmod_sparse_vec_window_clear(fq_nmod_sparse_vec_t window, const fq_nmod_ctx_t ctx) + + Clears a window (for safety only) + +.. function:: void fq_nmod_sparse_vec_concat(fq_nmod_sparse_vec_t res, const fq_nmod_sparse_vec_t vec1, const fq_nmod_sparse_vec_t vec2, slong len1, const fq_nmod_ctx_t ctx) + + Concatenates two vectors vec1 and vec2 into res, with indices of vec2 + offset by len1 + +.. function:: void fq_nmod_sparse_vec_split(fq_nmod_sparse_vec_t res1, fq_nmod_sparse_vec_t res1, const fq_nmod_sparse_vec_t vec, slong ind, const fq_nmod_ctx_t ctx) + + Splits vec into two vectors res1 and res2, with res1 containing all entries + below index ind and res2 containing the rest + +Permutation +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_vec_permute_inds(fq_nmod_sparse_vec_t vec, slong *P, const fq_nmod_ctx_t ctx) + + Permutes the indices of vec according to P, and resorts + + +Randomization +-------------------------------------------------------------------------------- + + +.. function:: void fq_nmod_sparse_vec_randtest(fq_nmod_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, const fq_nmod_ctx_t ctx) + + Makes vec a sparse vector with nnz nonzero entries uniformly distributed + between 0 and len - 1, with individual entries generated by fq_nmod_randtest + + +Output +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_vec_print_pretty(const fq_nmod_sparse_vec_t vec, slong ioff, slong maxi, const fq_nmod_ctx_t ctx) + + Prints the vector of given length to ``stdout`` in a human-readable format + + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: void fq_nmod_sparse_vec_neg(fq_nmod_sparse_vec_t v, const fq_nmod_sparse_vec_t u, const fq_nmod_ctx_t ctx) + + Sets ``v`` to the negation of ``u`` + +.. function:: void fq_nmod_sparse_vec_scalar_mul_fq_nmod(fq_nmod_sparse_vec_t v, const fq_nmod_sparse_vec_t u, const fq_nmod_t c, const fq_nmod_ctx_t ctx) + + Sets ``v`` to the scalar multiple of ``u`` by ``c`` + +.. function:: void fq_nmod_sparse_vec_add(fq_nmod_sparse_vec_t w, const fq_nmod_sparse_vec_t u, const fq_nmod_sparse_vec_t v, const fq_nmod_ctx_t ctx) + + Sets ``w`` to the sum of ``u`` and ``v`` + +.. function:: void fq_nmod_sparse_vec_sub(fq_nmod_sparse_vec_t w, const fq_nmod_sparse_vec_t u, const fq_nmod_sparse_vec_t v, const fq_nmod_ctx_t ctx) + + Sets ``w`` to the difference of ``u`` and ``v`` + +.. function:: void fq_nmod_sparse_vec_scalar_addmul_fq_nmod(fq_nmod_sparse_vec_t w, const fq_nmod_sparse_vec_t u, const fq_nmod_sparse_vec_t v, const fq_nmod_t c, const fq_nmod_ctx_t ctx) + + Sets ``w`` to the sum of ``u`` and ``c` times ``v`` + +.. function:: void fq_nmod_sparse_vec_scalar_addmul_fq_nmod(fq_nmod_sparse_vec_t w, const fq_nmod_sparse_vec_t u, const fq_nmod_sparse_vec_t v, const fq_nmod_t c, const fq_nmod_ctx_t ctx) + + Sets ``w`` to the difference of ``u`` and ``c` times ``v`` + +.. function:: void fq_nmod_sparse_vec_dot(fq_nmod_t ret, const fq_nmod_sparse_vec_t u, const fq_nmod_sparse_vec_t v, const fq_nmod_ctx_t ctx) + + Sets ``ret`` to the dot product of ``u`` and ``v`` + +.. function:: void fq_nmod_sparse_vec_dot_dense(fq_nmod_t ret, const fq_nmod_sparse_vec_t u, const fq_nmod_struct * v, const fq_nmod_ctx_t ctx) + + Sets ``ret`` to the dot product of (``u``, ``v``) diff --git a/doc/source/fq_sparse_mat.rst b/doc/source/fq_sparse_mat.rst new file mode 100644 index 0000000000..45484a8bc9 --- /dev/null +++ b/doc/source/fq_sparse_mat.rst @@ -0,0 +1,295 @@ +.. _fq-sparse-mat: + +**fq_sparse_mat.h** -- sparse matrixs over finite fields +=============================================================================== + +Description. + +Types, macros and constants +------------------------------------------------------------------------------- + +.. type:: fq_sparse_mat_t + + Holds an array of (possibly empty) sparse vectors corresponding to rows in + the matrix + +Memory management +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_init(fq_sparse_mat_t M, slong rows, slong cols, const fq_ctx_t ctx) + + Initializes an empty sparse matrix ``M`` with given number of rows and columns + +.. function:: void fq_sparse_mat_clear(fq_sparse_mat_t M, const fq_ctx_t ctx) + + Clears the entries of the matrix ``M`` and frees the space allocated for it + +.. function:: void fq_sparse_mat_swap(fq_sparse_mat_t M1, fq_sparse_mat_t M2, const fq_ctx_t ctx) + + Swaps two matrices ``M1`` and ``M2`` (no reallocaton) + + +Instantiation +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_zero(fq_sparse_mat_t M, const fq_ctx_t ctx) + + Sets matrix ``M`` to zero (the empty sparse matrix) + +.. function:: void fq_sparse_mat_one(fq_sparse_mat_t M, const fq_ctx_t ctx) + + Sets matrix ``M`` to identity matrix (based on its number of rows) + +.. function:: void fq_sparse_mat_set(fq_sparse_mat_t N, const fq_sparse_mat_t M, const fq_ctx_t ctx) + + Makes ``N`` a (deep) copy of ``M`` + +.. function:: void fq_sparse_mat_from_entries(fq_sparse_mat_t M, slong *rows, slong *inds, fq_struct *vals, slong nnz, const fq_ctx_t ctx) + + Constructs matrix ``M`` from a given sequence of ``rows``, ``cols``, and + corresponding ``vals``, all of length ``nnz``, assumes sorted by rows + with no duplicate (row, col) indices + +.. function:: void fq_sparse_mat_append_col(fq_sparse_mat_t M, const fq_struct *v, const fq_ctx_t ctx) + + Add a dense column to the right of the matrix + +.. function:: void fq_sparse_mat_append_row(fq_sparse_mat_t M, const fq_sparse_vec_t v, const fq_ctx_t ctx) + + Add a sparse row to the bottom of the matrix + + +Conversion to/from dense matrix +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_from_dense(fq_sparse_mat_t M, const fq_mat_t dM, const fq_ctx_t ctx) + + Converts the dense matrix ``dM`` to a sparse matrix ``M`` + +.. function:: void fq_sparse_mat_to_dense(fq_mat_t dM, const fq_sparse_mat_t M, const fq_ctx_t ctx) + + Converts the sparse matrix ``M`` to a dense matrix ``dM`` + +Windows, concatenation, and splitting +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_window_init(fq_sparse_mat_t window, const fq_sparse_mat_t M, slong r1, slong c1, slong r2, slong c2, const fq_ctx_t ctx) + + Constructs a window on the sparse matrix ``M`` between rows ``r1`` and ``r2`` + and cols ``c1`` and ``c2`` (valid as long as original matrix remains uzechified) + +.. function:: void fq_sparse_mat_window_clear(fq_sparse_mat_t window, const fq_ctx_t ctx) + + Clears a window + +.. function:: void fq_sparse_mat_concat_horizontal(fq_sparse_mat_t B, const fq_sparse_mat_t M1, const fq_sparse_mat_t M2, const fq_ctx_t ctx) + + Horizontally concatenates two matrices ``M1`` and ``M2`` into block matrix ``B`` + +.. function:: void fq_sparse_mat_concat_vertical(fq_sparse_mat_t B, const fq_sparse_mat_t M1, const fq_sparse_mat_t M2, const fq_ctx_t ctx) + + Vertically concatenates two matrices ``M1`` and ``M2`` into block matrix ``B`` + +.. function:: void fq_sparse_mat_split_horizontal(fq_sparse_mat_t M1, fq_sparse_mat_t M2, const fq_sparse_mat_t B, slong c, const fq_ctx_t ctx) + + Splits ``B`` horizontally into two submatrices ``M1`` and ``M2``, dividing at column ``c`` + +.. function:: void fq_sparse_mat_split_vertical(fq_sparse_mat_t M1, fq_sparse_mat_t M2, const fq_sparse_mat_t B, slong r, const fq_ctx_t ctx) + + Splits ``B`` vertically into two submatrices ``M1`` and ``M2``, dividing at row ``r`` + + +Permutation +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_permute_cols(fq_sparse_mat_t M, slong *Q, const fq_ctx_t ctx) + + Permutes the columns indices of ``M`` according to ``Q``, and re-sorts each row + +.. function:: void fq_sparse_mat_permute_rows(fq_sparse_mat_t M, slong *P, const fq_ctx_t ctx) + + Permutes the rows of ``M`` according to ``P`` + + +Randomization +-------------------------------------------------------------------------------- + + +.. function:: void fq_sparse_mat_randtest(fq_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz, const fq_ctx_t ctx) + + Makes ``M`` a sparse matrix with between ``min_nnz`` and ``max_nnz`` nonzero + entries per row, with individual entries generated by fq_randtest + + +Output +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_print_pretty(const fq_sparse_mat_t M, const fq_ctx_t ctx) + + Prints the matrix ``M`` to ``stdout`` in a human-readable format + + +Comparison +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_is_zero(fq_sparse_mat_t M, const fq_ctx_t ctx) + + Checks if the given matrix ``M`` is trivial (empty), returning `1` if so and `0` + otherwise + +.. function:: void fq_sparse_mat_equal(const fq_sparse_mat_t M1, const fq_sparse_mat_t M2, slong ioff, const fq_ctx_t ctx) + + Checks if ``M1`` equals ``M2``, returning `1` if so and `0` otherwise + + +Transpose +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_transpose(fq_sparse_mat_t N, const fq_sparse_mat_t M, const fq_ctx_t ctx) + + Transposes ``M`` into the matrix ``N`` (must have swapped rows and columns) + + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_neg(fq_sparse_mat_t N, const fq_sparse_mat_t M, const fq_ctx_t ctx) + + Sets ``N`` to the negation of ``M`` + +.. function:: void fq_sparse_mat_scalar_mul_fq(fq_sparse_mat_t N, const fq_sparse_mat_t M, const fq_t c, const fq_ctx_t ctx) + + Sets ``N`` to the scalar multiple of ``M`` by ``c`` + +.. function:: void fq_sparse_mat_add(fq_sparse_mat_t O, const fq_sparse_mat_t M, const fq_sparse_mat_t N, const fq_ctx_t ctx) + + Sets ``O`` to the sum of ``M`` and ``N`` + +.. function:: void fq_sparse_mat_sub(fq_sparse_mat_t O, const fq_sparse_mat_t M, const fq_sparse_mat_t N, const fq_ctx_t ctx) + + Sets ``O`` to the difference of ``M`` and ``N`` + +.. function:: void fq_sparse_mat_scalar_addmul_fq(fq_sparse_mat_t O, const fq_sparse_mat_t M, const fq_sparse_mat_t N, const fq_t c, const fq_ctx_t ctx) + + Sets ``O`` to the sum of ``M`` and ``c` times ``N`` + +.. function:: void fq_sparse_mat_scalar_submul_fq(fq_sparse_mat_t O, const fq_sparse_mat_t M, const fq_sparse_mat_t N, const fq_t c, const fq_ctx_t ctx) + + Sets ``O`` to the difference of ``M`` and ``N` times ``v`` + +.. function:: void fq_sparse_mat_mul_vec(fq_struct *y, const fq_sparse_mat_t M, const fq_struct *x, const fq_ctx_t ctx) + + Sets ``y`` to the product of ``M`` and ``x`` + +.. function:: void fq_sparse_mat_mul_mat(fq_mat_t Y, const fq_sparse_mat_t M, const fq_mat_t X, const fq_ctx_t ctx) + + Sets ``Y`` to the product of ``M`` and ``X`` + +.. function:: slong fq_sparse_mat_inv(fq_sparse_mat_t N, const fq_sparse_mat_t M, const fq_ctx_t ctx) + + Sets ``N`` to the "inverse" of ``M``, i.e., the matrix such that NM is + in reduced row-echelon form + + +Decomposition/reduction +-------------------------------------------------------------------------------- + +.. function:: slong fq_sparse_mat_lu(slong *P, slong *Q, fq_sparse_mat_t L, fq_sparse_mat_t U, const fq_sparse_mat_t M, const fq_ctx_t ctx) + + Computes the decomposition PMQ = LU for a given sparse matrix ``M``, where + ``P`` is a row permutation, ``Q`` is a column permutation, ``L``is a lower + triangular matrix, and ``U`` is an upper triangular matrix + +.. function:: void fq_sparse_mat_rref(fq_sparse_mat_t M, const fq_ctx_t ctx) + + Applies row reduction to put ``M`` in reduced row echelon form (in place) + +Solving +-------------------------------------------------------------------------------- + +.. function:: int fq_sparse_mat_solve_lu(fq_struct *x, const fq_sparse_mat_t M, const fq_struct *b, const fq_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use LU decomposition to find + a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int fq_sparse_mat_solve_rref(fq_struct *x, const fq_sparse_mat_t M, const fq_struct *b, const fq_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use the reduced row-echelon + form to find a vector ``x`` such that Mx = b, returns `1` if successful and + `0` if not + +.. function:: int fq_sparse_mat_solve_lanczos(fq_struct *x, const fq_sparse_mat_t M, const fq_struct *b, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use the Lanczos algorithm to + find a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int fq_sparse_mat_solve_wiedemann(fq_struct *x, const fq_sparse_mat_t M, const fq_struct *b, const fq_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use the Wiedemann algorithm to + find a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int fq_sparse_mat_solve_block_lanczos(fq_struct *x, const fq_sparse_mat_t M, const fq_struct *b, slong block_size, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use Coppersmith's block Lanczos + algorithm (with specified block size) to find a vector ``x`` such that Mx = b, + returns `1` if successful and `0` if not + +.. function:: int fq_sparse_mat_solve_block_wiedemann(fq_struct *x, const fq_sparse_mat_t M, const fq_struct *b, slong block_size, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use Coppersmith's block Wiedemann + algorithm (with specified block size) to find a vector ``x`` such that Mx = b, + returns `1` if successful and `0` if not + +Nullvector and nullspace computation +-------------------------------------------------------------------------------- + +.. function:: int fq_sparse_mat_nullvector_lanczos(fq_struct *x, const fq_sparse_mat_t M, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M``, use the Lanczos algorithm to find a nullvector ``x`` + s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_sparse_mat_nullvector_wiedemann(fq_struct *x, const fq_sparse_mat_t M, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M``, use the Wiedemann algorithm to find a nullvector ``x`` + s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_sparse_mat_nullvector_block_lanczos(fq_struct *x, const fq_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Lanczos algorithm to find a + nullvector ``x`` s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_sparse_mat_nullvector_block_wiedemann(fq_struct *x, const fq_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Wiedemann algorithm to find a + nullvector ``x`` s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_sparse_mat_nullspace_rref(fq_mat_t X, const fq_sparse_mat_t M, const fq_ctx_t ctx) + + Given a matrix ``M``, use the reduced row echelon form to construct the + nullspace ``X`` of M (initialized by this function), returns the nullity + +.. function:: int fq_sparse_mat_nullspace_lu(fq_mat_t X, const fq_sparse_mat_t M, const fq_ctx_t ctx) + + Given a matrix ``M``, use the LU decomposition to construct the nullspace ``X`` + of M (initialized by this function), returns the nullity + +.. function:: int fq_sparse_mat_nullspace_lanczos(fq_mat_t X, const fq_sparse_mat_t M, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M``, use the Lanczos algorithm to find a nullspace ``X`` + of M (initialized by this function), returns the found nullity + +.. function:: int fq_sparse_mat_nullspace_wiedemann(fq_mat_t X, const fq_sparse_mat_t M, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M``, use the Wiedemann algorithm to find a nullspace ``X`` + of M (initialized by this function), returns the found nullity + +.. function:: int fq_sparse_mat_nullspace_block_lanczos(fq_mat_t X, const fq_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Lanczos algorithm to find a + nullspace ``X`` of M (initialized by this function), returns the found nullity + +.. function:: int fq_sparse_mat_nullspace_block_wiedemann(fq_mat_t X, const fq_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Wiedemann algorithm to find a + nullspace ``X`` of M (initialized by this function), returns the found nullity + diff --git a/doc/source/fq_sparse_vec.rst b/doc/source/fq_sparse_vec.rst new file mode 100644 index 0000000000..3be0271f33 --- /dev/null +++ b/doc/source/fq_sparse_vec.rst @@ -0,0 +1,176 @@ +.. _fq-sparse-vec: + +**fq_sparse_vec.h** -- sparse vectors over finite fields +=============================================================================== + +Description. + +Types, macros and constants +------------------------------------------------------------------------------- + +.. type:: fq_sparse_entry_t + + Holds a pair (ind, val), where ind (of type slong) is an index into the + vector and val (of type fq_t) is the value at that index + +.. type:: fq_sparse_vec_t + + Holds an array of nonzero entries (of type sparse_entry_struct *) of + specified length nnz, sorted by ind + +Memory management +-------------------------------------------------------------------------------- + + +.. function:: void fq_sparse_vec_init(fq_sparse_vec_t vec, const fq_ctx_t ctx) + + Initializes an empty sparse vector (no allocation) + +.. function:: void fq_sparse_vec_clear(fq_sparse_vec_t vec, slong len, const fq_ctx_t ctx) + + Clears the entries of vec and frees the space allocated for it + +.. function:: void fq_sparse_vec_swap(fq_sparse_vec_t vec1, fq_sparse_vec_t vec2, const fq_ctx_t ctx) + + Swaps two vectors (no reallocaton) + +Instantiation +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_vec_zero(fq_sparse_vec_t vec, const fq_ctx_t ctx) + + Sets vec to zero (the empty sparse vector) + +.. function:: void fq_sparse_vec_one(fq_sparse_vec_t vec, slong ind, const fq_ctx_t ctx) + + Sets vec to the ind-th basis vector (single one in position ind) + +.. function:: void fq_sparse_vec_set(fq_sparse_vec_t dst, fq_sparse_vec_t src, const fq_ctx_t ctx) + + Makes dst a (deep) copy of src + +.. function:: void fq_sparse_vec_set_entry(fq_sparse_vec_t vec, slong ind, const fq_t val, const fq_ctx_t ctx) + + Sets the value at index ind to val, either replacing an existing value or extending + the array of entries + +.. function:: void _fq_sparse_vec_from_entries(fq_sparse_vec_t vec, slong *inds, fq_struct *vals, slong nnz, const fq_ctx_t ctx) + + Constructs vec from a given sequence of indices and associated values, both of length nnz. + Assumes no duplicate indices + +Comparison +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_is_zero(fq_sparse_vec_t vec, const fq_ctx_t ctx) + + Checks if the given vector is trivial (empty), returning `1` if so and `0` + otherwise + +.. function:: void fq_sparse_vec_equal(const fq_sparse_vec_t vec1, const fq_sparse_vec_t vec2, slong ioff, const fq_ctx_t ctx) + + Checks if vec1 equals vec2 (with s specified column offset ioff), returning + `1` if so and `0` otherwise + +Indexing +-------------------------------------------------------------------------------- + +.. function:: fq_t * fq_sparse_vec_at(const fq_sparse_vec_t vec, slong ind, const fq_ctx_t ctx) + + Returns a pointer to the value at the index ind (or NULL if index not found) + + +Conversion to/from dense vector +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_vec_from_dense(fq_sparse_vec_t dst, const fq_struct *src, slong len, const fq_ctx_t ctx) + + Converts the dense vector src of length len to a sparse vector + +.. function:: void fq_sparse_vec_to_dense(fq_struct *dst, const fq_sparse_vec_t src, slong len, const fq_ctx_t ctx) + + Converts the sparse vector src to a dense vector of length len + + +Windows, concatenation, and splitting +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_vec_window_init(fq_sparse_vec_t window, const fq_sparse_vec_t vec, slong i1, slong i2, const fq_ctx_t ctx) + + Constructs a window on a the sparse vector vec between indices i1 and i2 + Note that window is only valid as long as original vector remains unmodified + +.. function:: void fq_sparse_vec_window_clear(fq_sparse_vec_t window, const fq_ctx_t ctx) + + Clears a window (for safety only) + +.. function:: void fq_sparse_vec_concat(fq_sparse_vec_t res, const fq_sparse_vec_t vec1, const fq_sparse_vec_t vec2, slong len1, const fq_ctx_t ctx) + + Concatenates two vectors vec1 and vec2 into res, with indices of vec2 + offset by len1 + +.. function:: void fq_sparse_vec_split(fq_sparse_vec_t res1, fq_sparse_vec_t res1, const fq_sparse_vec_t vec, slong ind, const fq_ctx_t ctx) + + Splits vec into two vectors res1 and res2, with res1 containing all entries + below index ind and res2 containing the rest + +Permutation +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_vec_permute_inds(fq_sparse_vec_t vec, slong *P, const fq_ctx_t ctx) + + Permutes the indices of vec according to P, and resorts + + +Randomization +-------------------------------------------------------------------------------- + + +.. function:: void fq_sparse_vec_randtest(fq_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, const fq_ctx_t ctx) + + Makes vec a sparse vector with nnz nonzero entries uniformly distributed + between 0 and len - 1, with individual entries generated by fq_randtest + + +Output +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_vec_print_pretty(const fq_sparse_vec_t vec, slong ioff, slong maxi, const fq_ctx_t ctx) + + Prints the vector of given length to ``stdout`` in a human-readable format + + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_vec_neg(fq_sparse_vec_t v, const fq_sparse_vec_t u, const fq_ctx_t ctx) + + Sets ``v`` to the negation of ``u`` + +.. function:: void fq_sparse_vec_scalar_mul_fq(fq_sparse_vec_t v, const fq_sparse_vec_t u, const fq_t c, const fq_ctx_t ctx) + + Sets ``v`` to the scalar multiple of ``u`` by ``c`` + +.. function:: void fq_sparse_vec_add(fq_sparse_vec_t w, const fq_sparse_vec_t u, const fq_sparse_vec_t v, const fq_ctx_t ctx) + + Sets ``w`` to the sum of ``u`` and ``v`` + +.. function:: void fq_sparse_vec_sub(fq_sparse_vec_t w, const fq_sparse_vec_t u, const fq_sparse_vec_t v, const fq_ctx_t ctx) + + Sets ``w`` to the difference of ``u`` and ``v`` + +.. function:: void fq_sparse_vec_scalar_addmul_fq(fq_sparse_vec_t w, const fq_sparse_vec_t u, const fq_sparse_vec_t v, const fq_t c, const fq_ctx_t ctx) + + Sets ``w`` to the sum of ``u`` and ``c` times ``v`` + +.. function:: void fq_sparse_vec_scalar_addmul_fq(fq_sparse_vec_t w, const fq_sparse_vec_t u, const fq_sparse_vec_t v, const fq_t c, const fq_ctx_t ctx) + + Sets ``w`` to the difference of ``u`` and ``c` times ``v`` + +.. function:: void fq_sparse_vec_dot(fq_t ret, const fq_sparse_vec_t u, const fq_sparse_vec_t v, const fq_ctx_t ctx) + + Sets ``ret`` to the dot product of ``u`` and ``v`` + +.. function:: void fq_sparse_vec_dot_dense(fq_t ret, const fq_sparse_vec_t u, const fq_struct * v, const fq_ctx_t ctx) + + Sets ``ret`` to the dot product of (``u``, ``v``) diff --git a/doc/source/fq_zech_sparse_mat.rst b/doc/source/fq_zech_sparse_mat.rst new file mode 100644 index 0000000000..f7f5db6f4a --- /dev/null +++ b/doc/source/fq_zech_sparse_mat.rst @@ -0,0 +1,295 @@ +.. _fq-zech-sparse-mat: + +**fq_zech_sparse_mat.h** -- sparse matrixs over finite fields (Zech logarithm representation) +=============================================================================== + +Description. + +Types, macros and constants +------------------------------------------------------------------------------- + +.. type:: fq_zech_sparse_mat_t + + Holds an array of (possibly empty) sparse vectors corresponding to rows in + the matrix + +Memory management +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_mat_init(fq_zech_sparse_mat_t M, slong rows, slong cols, const fq_zech_ctx_t ctx) + + Initializes an empty sparse matrix ``M`` with given number of rows and columns + +.. function:: void fq_zech_sparse_mat_clear(fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Clears the entries of the matrix ``M`` and frees the space allocated for it + +.. function:: void fq_zech_sparse_mat_swap(fq_zech_sparse_mat_t M1, fq_zech_sparse_mat_t M2, const fq_zech_ctx_t ctx) + + Swaps two matrices ``M1`` and ``M2`` (no reallocaton) + + +Instantiation +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_mat_zero(fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Sets matrix ``M`` to zero (the empty sparse matrix) + +.. function:: void fq_zech_sparse_mat_one(fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Sets matrix ``M`` to identity matrix (based on its number of rows) + +.. function:: void fq_zech_sparse_mat_set(fq_zech_sparse_mat_t N, const fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Makes ``N`` a (deep) copy of ``M`` + +.. function:: void fq_zech_sparse_mat_from_entries(fq_zech_sparse_mat_t M, slong *rows, slong *inds, fq_zech_struct *vals, slong nnz, const fq_zech_ctx_t ctx) + + Constructs matrix ``M`` from a given sequence of ``rows``, ``cols``, and + corresponding ``vals``, all of length ``nnz``, assumes sorted by rows + with no duplicate (row, col) indices + +.. function:: void fq_zech_sparse_mat_append_col(fq_zech_sparse_mat_t M, const fq_zech_struct *v, const fq_zech_ctx_t ctx) + + Add a dense column to the right of the matrix + +.. function:: void fq_zech_sparse_mat_append_row(fq_zech_sparse_mat_t M, const fq_zech_sparse_vec_t v, const fq_zech_ctx_t ctx) + + Add a sparse row to the bottom of the matrix + + +Conversion to/from dense matrix +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_mat_from_dense(fq_zech_sparse_mat_t M, const fq_zech_mat_t dM, const fq_zech_ctx_t ctx) + + Converts the dense matrix ``dM`` to a sparse matrix ``M`` + +.. function:: void fq_zech_sparse_mat_to_dense(fq_zech_mat_t dM, const fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Converts the sparse matrix ``M`` to a dense matrix ``dM`` + +Windows, concatenation, and splitting +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_mat_window_init(fq_zech_sparse_mat_t window, const fq_zech_sparse_mat_t M, slong r1, slong c1, slong r2, slong c2, const fq_zech_ctx_t ctx) + + Constructs a window on the sparse matrix ``M`` between rows ``r1`` and ``r2`` + and cols ``c1`` and ``c2`` (valid as long as original matrix remains uzechified) + +.. function:: void fq_zech_sparse_mat_window_clear(fq_zech_sparse_mat_t window, const fq_zech_ctx_t ctx) + + Clears a window + +.. function:: void fq_zech_sparse_mat_concat_horizontal(fq_zech_sparse_mat_t B, const fq_zech_sparse_mat_t M1, const fq_zech_sparse_mat_t M2, const fq_zech_ctx_t ctx) + + Horizontally concatenates two matrices ``M1`` and ``M2`` into block matrix ``B`` + +.. function:: void fq_zech_sparse_mat_concat_vertical(fq_zech_sparse_mat_t B, const fq_zech_sparse_mat_t M1, const fq_zech_sparse_mat_t M2, const fq_zech_ctx_t ctx) + + Vertically concatenates two matrices ``M1`` and ``M2`` into block matrix ``B`` + +.. function:: void fq_zech_sparse_mat_split_horizontal(fq_zech_sparse_mat_t M1, fq_zech_sparse_mat_t M2, const fq_zech_sparse_mat_t B, slong c, const fq_zech_ctx_t ctx) + + Splits ``B`` horizontally into two submatrices ``M1`` and ``M2``, dividing at column ``c`` + +.. function:: void fq_zech_sparse_mat_split_vertical(fq_zech_sparse_mat_t M1, fq_zech_sparse_mat_t M2, const fq_zech_sparse_mat_t B, slong r, const fq_zech_ctx_t ctx) + + Splits ``B`` vertically into two submatrices ``M1`` and ``M2``, dividing at row ``r`` + + +Permutation +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_mat_permute_cols(fq_zech_sparse_mat_t M, slong *Q, const fq_zech_ctx_t ctx) + + Permutes the columns indices of ``M`` according to ``Q``, and re-sorts each row + +.. function:: void fq_zech_sparse_mat_permute_rows(fq_zech_sparse_mat_t M, slong *P, const fq_zech_ctx_t ctx) + + Permutes the rows of ``M`` according to ``P`` + + +Randomization +-------------------------------------------------------------------------------- + + +.. function:: void fq_zech_sparse_mat_randtest(fq_zech_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz, const fq_zech_ctx_t ctx) + + Makes ``M`` a sparse matrix with between ``min_nnz`` and ``max_nnz`` nonzero + entries per row, with individual entries generated by fq_zech_randtest + + +Output +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_mat_print_pretty(const fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Prints the matrix ``M`` to ``stdout`` in a human-readable format + + +Comparison +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_is_zero(fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Checks if the given matrix ``M`` is trivial (empty), returning `1` if so and `0` + otherwise + +.. function:: void fq_zech_sparse_mat_equal(const fq_zech_sparse_mat_t M1, const fq_zech_sparse_mat_t M2, slong ioff, const fq_zech_ctx_t ctx) + + Checks if ``M1`` equals ``M2``, returning `1` if so and `0` otherwise + + +Transpose +-------------------------------------------------------------------------------- + +.. function:: void fq_sparse_mat_transpose(fq_zech_sparse_mat_t N, const fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Transposes ``M`` into the matrix ``N`` (must have swapped rows and columns) + + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_mat_neg(fq_zech_sparse_mat_t N, const fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Sets ``N`` to the negation of ``M`` + +.. function:: void fq_zech_sparse_mat_scalar_mul_fq_zech(fq_zech_sparse_mat_t N, const fq_zech_sparse_mat_t M, const fq_zech_t c, const fq_zech_ctx_t ctx) + + Sets ``N`` to the scalar multiple of ``M`` by ``c`` + +.. function:: void fq_zech_sparse_mat_add(fq_zech_sparse_mat_t O, const fq_zech_sparse_mat_t M, const fq_zech_sparse_mat_t N, const fq_zech_ctx_t ctx) + + Sets ``O`` to the sum of ``M`` and ``N`` + +.. function:: void fq_zech_sparse_mat_sub(fq_zech_sparse_mat_t O, const fq_zech_sparse_mat_t M, const fq_zech_sparse_mat_t N, const fq_zech_ctx_t ctx) + + Sets ``O`` to the difference of ``M`` and ``N`` + +.. function:: void fq_zech_sparse_mat_scalar_addmul_fq_zech(fq_zech_sparse_mat_t O, const fq_zech_sparse_mat_t M, const fq_zech_sparse_mat_t N, const fq_zech_t c, const fq_zech_ctx_t ctx) + + Sets ``O`` to the sum of ``M`` and ``c` times ``N`` + +.. function:: void fq_zech_sparse_mat_scalar_submul_fq_zech(fq_zech_sparse_mat_t O, const fq_zech_sparse_mat_t M, const fq_zech_sparse_mat_t N, const fq_zech_t c, const fq_zech_ctx_t ctx) + + Sets ``O`` to the difference of ``M`` and ``N` times ``v`` + +.. function:: void fq_zech_sparse_mat_mul_vec(fq_zech_struct *y, const fq_zech_sparse_mat_t M, const fq_zech_struct *x, const fq_zech_ctx_t ctx) + + Sets ``y`` to the product of ``M`` and ``x`` + +.. function:: void fq_zech_sparse_mat_mul_mat(fq_zech_mat_t Y, const fq_zech_sparse_mat_t M, const fq_zech_mat_t X, const fq_zech_ctx_t ctx) + + Sets ``Y`` to the product of ``M`` and ``X`` + +.. function:: slong fq_zech_sparse_mat_inv(fq_zech_sparse_mat_t N, const fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Sets ``N`` to the "inverse" of ``M``, i.e., the matrix such that NM is + in reduced row-echelon form + + +Decomposition/reduction +-------------------------------------------------------------------------------- + +.. function:: slong fq_zech_sparse_mat_lu(slong *P, slong *Q, fq_zech_sparse_mat_t L, fq_zech_sparse_mat_t U, const fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Computes the decomposition PMQ = LU for a given sparse matrix ``M``, where + ``P`` is a row permutation, ``Q`` is a column permutation, ``L``is a lower + triangular matrix, and ``U`` is an upper triangular matrix + +.. function:: void fq_zech_sparse_mat_rref(fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Applies row reduction to put ``M`` in reduced row echelon form (in place) + +Solving +-------------------------------------------------------------------------------- + +.. function:: int fq_zech_sparse_mat_solve_lu(fq_zech_struct *x, const fq_zech_sparse_mat_t M, const fq_zech_struct *b, const fq_zech_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use LU decomposition to find + a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int fq_zech_sparse_mat_solve_rref(fq_zech_struct *x, const fq_zech_sparse_mat_t M, const fq_zech_struct *b, const fq_zech_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use the reduced row-echelon + form to find a vector ``x`` such that Mx = b, returns `1` if successful and + `0` if not + +.. function:: int fq_zech_sparse_mat_solve_lanczos(fq_zech_struct *x, const fq_zech_sparse_mat_t M, const fq_zech_struct *b, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use the Lanczos algorithm to + find a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int fq_zech_sparse_mat_solve_wiedemann(fq_zech_struct *x, const fq_zech_sparse_mat_t M, const fq_zech_struct *b, const fq_zech_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use the Wiedemann algorithm to + find a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int fq_zech_sparse_mat_solve_block_lanczos(fq_zech_struct *x, const fq_zech_sparse_mat_t M, const fq_zech_struct *b, slong block_size, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use Coppersmith's block Lanczos + algorithm (with specified block size) to find a vector ``x`` such that Mx = b, + returns `1` if successful and `0` if not + +.. function:: int fq_zech_sparse_mat_solve_block_wiedemann(fq_zech_struct *x, const fq_zech_sparse_mat_t M, const fq_zech_struct *b, slong block_size, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M`` and target vector ``b``, use Coppersmith's block Wiedemann + algorithm (with specified block size) to find a vector ``x`` such that Mx = b, + returns `1` if successful and `0` if not + +Nullvector and nullspace computation +-------------------------------------------------------------------------------- + +.. function:: int fq_zech_sparse_mat_nullvector_lanczos(fq_zech_struct *x, const fq_zech_sparse_mat_t M, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use the Lanczos algorithm to find a nullvector ``x`` + s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_zech_sparse_mat_nullvector_wiedemann(fq_zech_struct *x, const fq_zech_sparse_mat_t M, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use the Wiedemann algorithm to find a nullvector ``x`` + s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_zech_sparse_mat_nullvector_block_lanczos(fq_zech_struct *x, const fq_zech_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Lanczos algorithm to find a + nullvector ``x`` s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_zech_sparse_mat_nullvector_block_wiedemann(fq_zech_struct *x, const fq_zech_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Wiedemann algorithm to find a + nullvector ``x`` s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int fq_zech_sparse_mat_nullspace_rref(fq_zech_mat_t X, const fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use the reduced row echelon form to construct the + nullspace ``X`` of M (initialized by this function), returns the nullity + +.. function:: int fq_zech_sparse_mat_nullspace_lu(fq_zech_mat_t X, const fq_zech_sparse_mat_t M, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use the LU decomposition to construct the nullspace ``X`` + of M (initialized by this function), returns the nullity + +.. function:: int fq_zech_sparse_mat_nullspace_lanczos(fq_zech_mat_t X, const fq_zech_sparse_mat_t M, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use the Lanczos algorithm to find a nullspace ``X`` + of M (initialized by this function), returns the found nullity + +.. function:: int fq_zech_sparse_mat_nullspace_wiedemann(fq_zech_mat_t X, const fq_zech_sparse_mat_t M, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use the Wiedemann algorithm to find a nullspace ``X`` + of M (initialized by this function), returns the found nullity + +.. function:: int fq_zech_sparse_mat_nullspace_block_lanczos(fq_zech_mat_t X, const fq_zech_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Lanczos algorithm to find a + nullspace ``X`` of M (initialized by this function), returns the found nullity + +.. function:: int fq_zech_sparse_mat_nullspace_block_wiedemann(fq_zech_mat_t X, const fq_zech_sparse_mat_t M, slong block_size, flint_rand_t state, const fq_zech_ctx_t ctx) + + Given a matrix ``M``, use Coppersmith's block Wiedemann algorithm to find a + nullspace ``X`` of M (initialized by this function), returns the found nullity + diff --git a/doc/source/fq_zech_sparse_vec.rst b/doc/source/fq_zech_sparse_vec.rst new file mode 100644 index 0000000000..d1b85b94fd --- /dev/null +++ b/doc/source/fq_zech_sparse_vec.rst @@ -0,0 +1,176 @@ +.. _fq-zech-sparse-vec: + +**fq_zech_sparse_vec.h** -- sparse vectors over finite fields (Zech logarithm representation) +=============================================================================== + +Description. + +Types, macros and constants +------------------------------------------------------------------------------- + +.. type:: fq_zech_sparse_entry_t + + Holds a pair (ind, val), where ind (of type slong) is an index into the + vector and val (of type fq_zech_t) is the value at that index + +.. type:: fq_zech_sparse_vec_t + + Holds an array of nonzero entries (of type sparse_entry_struct *) of + specified length nnz, sorted by ind + +Memory management +-------------------------------------------------------------------------------- + + +.. function:: void fq_zech_sparse_vec_init(fq_zech_sparse_vec_t vec, const fq_zech_ctx_t ctx) + + Initializes an empty sparse vector (no allocation) + +.. function:: void fq_zech_sparse_vec_clear(fq_zech_sparse_vec_t vec, slong len, const fq_zech_ctx_t ctx) + + Clears the entries of vec and frees the space allocated for it + +.. function:: void fq_zech_sparse_vec_swap(fq_zech_sparse_vec_t vec1, fq_zech_sparse_vec_t vec2, const fq_zech_ctx_t ctx) + + Swaps two vectors (no reallocaton) + +Instantiation +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_vec_zero(fq_zech_sparse_vec_t vec, const fq_zech_ctx_t ctx) + + Sets vec to zero (the empty sparse vector) + +.. function:: void fq_zech_sparse_vec_one(fq_zech_sparse_vec_t vec, slong ind, const fq_zech_ctx_t ctx) + + Sets vec to the ind-th basis vector (single one in position ind) + +.. function:: void fq_zech_sparse_vec_set(fq_zech_sparse_vec_t dst, fq_zech_sparse_vec_t src, const fq_zech_ctx_t ctx) + + Makes dst a (deep) copy of src + +.. function:: void fq_zech_sparse_vec_set_entry(fq_zech_sparse_vec_t vec, slong ind, const fq_zech_t val, const fq_zech_ctx_t ctx) + + Sets the value at index ind to val, either replacing an existing value or extending + the array of entries + +.. function:: void _fq_zech_sparse_vec_from_entries(fq_zech_sparse_vec_t vec, slong *inds, fq_zech_struct *vals, slong nnz, const fq_zech_ctx_t ctx) + + Constructs vec from a given sequence of indices and associated values, both of length nnz. + Assumes no duplicate indices + +Comparison +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_is_zero(fq_zech_sparse_vec_t vec, const fq_zech_ctx_t ctx) + + Checks if the given vector is trivial (empty), returning `1` if so and `0` + otherwise + +.. function:: void fq_zech_sparse_vec_equal(const fq_zech_sparse_vec_t vec1, const fq_zech_sparse_vec_t vec2, slong ioff, const fq_zech_ctx_t ctx) + + Checks if vec1 equals vec2 (with s specified column offset ioff), returning + `1` if so and `0` otherwise + +Indexing +-------------------------------------------------------------------------------- + +.. function:: fq_zech_t * fq_zech_sparse_vec_at(fq_zech_sparse_vec_t vec, slong ind, const fq_zech_ctx_t ctx) + + Returns a pointer to the value at the index ind (or NULL if index not found) + + +Conversion to/from dense vector +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_vec_from_dense(fq_zech_sparse_vec_t dst, const fq_zech_struct *src, slong len, const fq_zech_ctx_t ctx) + + Converts the dense vector src of length len to a sparse vector + +.. function:: void fq_zech_sparse_vec_to_dense(fq_zech_struct *dst, const fq_zech_sparse_vec_t src, slong len, const fq_zech_ctx_t ctx) + + Converts the sparse vector src to a dense vector of length len + + +Windows, concatenation, and splitting +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_vec_window_init(fq_zech_sparse_vec_t window, const fq_zech_sparse_vec_t vec, slong i1, slong i2, const fq_zech_ctx_t ctx) + + Constructs a window on a the sparse vector vec between indices i1 and i2 + Note that window is only valid as long as original vector remains uzechified + +.. function:: void fq_zech_sparse_vec_window_clear(fq_zech_sparse_vec_t window, const fq_zech_ctx_t ctx) + + Clears a window (for safety only) + +.. function:: void fq_zech_sparse_vec_concat(fq_zech_sparse_vec_t res, const fq_zech_sparse_vec_t vec1, const fq_zech_sparse_vec_t vec2, slong len1, const fq_zech_ctx_t ctx) + + Concatenates two vectors vec1 and vec2 into res, with indices of vec2 + offset by len1 + +.. function:: void fq_zech_sparse_vec_split(fq_zech_sparse_vec_t res1, fq_zech_sparse_vec_t res1, const fq_zech_sparse_vec_t vec, slong ind, const fq_zech_ctx_t ctx) + + Splits vec into two vectors res1 and res2, with res1 containing all entries + below index ind and res2 containing the rest + +Permutation +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_vec_permute_inds(fq_zech_sparse_vec_t vec, slong *P, const fq_zech_ctx_t ctx) + + Permutes the indices of vec according to P, and resorts + + +Randomization +-------------------------------------------------------------------------------- + + +.. function:: void fq_zech_sparse_vec_randtest(fq_zech_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, const fq_zech_ctx_t ctx) + + Makes vec a sparse vector with nnz nonzero entries uniformly distributed + between 0 and len - 1, with individual entries generated by fq_zech_randtest + + +Output +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_vec_print_pretty(const fq_zech_sparse_vec_t vec, slong ioff, slong maxi, const fq_zech_ctx_t ctx) + + Prints the vector of given length to ``stdout`` in a human-readable format + + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: void fq_zech_sparse_vec_neg(fq_zech_sparse_vec_t v, const fq_zech_sparse_vec_t u, const fq_zech_ctx_t ctx) + + Sets ``v`` to the negation of ``u`` + +.. function:: void fq_zech_sparse_vec_scalar_mul_fq_zech(fq_zech_sparse_vec_t v, const fq_zech_sparse_vec_t u, const fq_zech_t c, const fq_zech_ctx_t ctx) + + Sets ``v`` to the scalar multiple of ``u`` by ``c`` + +.. function:: void fq_zech_sparse_vec_add(fq_zech_sparse_vec_t w, const fq_zech_sparse_vec_t u, const fq_zech_sparse_vec_t v, const fq_zech_ctx_t ctx) + + Sets ``w`` to the sum of ``u`` and ``v`` + +.. function:: void fq_zech_sparse_vec_sub(fq_zech_sparse_vec_t w, const fq_zech_sparse_vec_t u, const fq_zech_sparse_vec_t v, const fq_zech_ctx_t ctx) + + Sets ``w`` to the difference of ``u`` and ``v`` + +.. function:: void fq_zech_sparse_vec_scalar_addmul_fq_zech(fq_zech_sparse_vec_t w, const fq_zech_sparse_vec_t u, const fq_zech_sparse_vec_t v, const fq_zech_t c, const fq_zech_ctx_t ctx) + + Sets ``w`` to the sum of ``u`` and ``c` times ``v`` + +.. function:: void fq_zech_sparse_vec_scalar_addmul_fq_zech(fq_zech_sparse_vec_t w, const fq_zech_sparse_vec_t u, const fq_zech_sparse_vec_t v, const fq_zech_t c, const fq_zech_ctx_t ctx) + + Sets ``w`` to the difference of ``u`` and ``c` times ``v`` + +.. function:: void fq_zech_sparse_vec_dot(fq_zech_t ret, const fq_zech_sparse_vec_t u, const fq_zech_sparse_vec_t v, const fq_zech_ctx_t ctx) + + Sets ``ret`` to the dot product of ``u`` and ``v`` + +.. function:: void fq_zech_sparse_vec_dot_dense(fq_zech_t ret, const fq_zech_sparse_vec_t u, const fq_zech_struct * v, const fq_zech_ctx_t ctx) + + Sets ``ret`` to the dot product of (``u``, ``v``) diff --git a/doc/source/nmod_sparse_mat.rst b/doc/source/nmod_sparse_mat.rst new file mode 100644 index 0000000000..52b74b7a18 --- /dev/null +++ b/doc/source/nmod_sparse_mat.rst @@ -0,0 +1,296 @@ +.. _nmod-sparse-mat: + +**nmod_sparse_mat.h** -- sparse matrices over integers mod n +=============================================================================== + +Description. + +Types, macros and constants +------------------------------------------------------------------------------- + +.. type:: nmod_sparse_mat_t + + Holds an array of (possibly empty) sparse vectors corresponding to rows in + the matrix + +Memory management +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_mat_init(nmod_sparse_mat_t M, slong rows, slong cols, nmod_t mod) + + Initializes an empty sparse matrix ``M`` with given number of rows and columns + +.. function:: void nmod_sparse_mat_clear(nmod_sparse_mat_t M) + + Clears the entries of the matrix ``M`` and frees the space allocated for it + +.. function:: void nmod_sparse_mat_swap(nmod_sparse_mat_t M1, nmod_sparse_mat_t M2) + + Swaps two matrices ``M1`` and ``M2`` (no reallocaton) + + +Instantiation +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_mat_zero(nmod_sparse_mat_t M) + + Sets matrix ``M`` to zero (the empty sparse matrix) + +.. function:: void nmod_sparse_mat_one(nmod_sparse_mat_t M) + + Sets matrix ``M`` to identity matrix (based on its number of rows) + +.. function:: void nmod_sparse_mat_set(nmod_sparse_mat_t N, const nmod_sparse_mat_t M) + + Makes ``N`` a (deep) copy of ``M`` + +.. function:: void nmod_sparse_mat_from_entries(nmod_sparse_mat_t M, slong *rows, slong *inds, mp_ptr vals, slong nnz) + + Constructs matrix ``M`` from a given sequence of ``rows``, ``cols``, and + corresponding ``vals``, all of length ``nnz``, assumes sorted by rows + with no duplicate (row, col) indices + +.. function:: void nmod_sparse_mat_append_col(nmod_sparse_mat_t M, mp_srcptr v) + + Add a dense column to the right of the matrix + +.. function:: void nmod_sparse_mat_append_row(nmod_sparse_mat_t M, const nmod_sparse_vec_t v) + + Add a sparse row to the bottom of the matrix + + +Conversion to/from dense matrix +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_mat_from_dense(nmod_sparse_mat_t M, const nmod_mat_t dM) + + Converts the dense matrix ``dM`` to a sparse matrix ``M`` + +.. function:: void nmod_sparse_mat_to_dense(nmod_mat_t dM, const nmod_sparse_mat_t M) + + Converts the sparse matrix ``M`` to a dense matrix ``dM`` + +Windows, concatenation, and splitting +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_mat_window_init(nmod_sparse_mat_t window, const nmod_sparse_mat_t M, slong r1, slong c1, slong r2, slong c2) + + Constructs a window on the sparse matrix ``M`` between rows ``r1`` and ``r2`` + and cols ``c1`` and ``c2`` (valid as long as original matrix remains uzechified) + +.. function:: void nmod_sparse_mat_window_clear(nmod_sparse_mat_t window) + + Clears a window + +.. function:: void nmod_sparse_mat_concat_horizontal(nmod_sparse_mat_t B, const nmod_sparse_mat_t M1, const nmod_sparse_mat_t M2) + + Horizontally concatenates two matrices ``M1`` and ``M2`` into block matrix ``B`` + +.. function:: void nmod_sparse_mat_concat_vertical(nmod_sparse_mat_t B, const nmod_sparse_mat_t M1, const nmod_sparse_mat_t M2) + + Vertically concatenates two matrices ``M1`` and ``M2`` into block matrix ``B`` + +.. function:: void nmod_sparse_mat_split_horizontal(nmod_sparse_mat_t M1, nmod_sparse_mat_t M2, const nmod_sparse_mat_t B, slong c) + + Splits ``B`` horizontally into two submatrices ``M1`` and ``M2``, dividing at column ``c`` + +.. function:: void nmod_sparse_mat_split_vertical(nmod_sparse_mat_t M1, nmod_sparse_mat_t M2, const nmod_sparse_mat_t B, slong r) + + Splits ``B`` vertically into two submatrices ``M1`` and ``M2``, dividing at row ``r`` + + +Permutation +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_mat_permute_cols(nmod_sparse_mat_t M, slong *Q) + + Permutes the columns indices of ``M`` according to ``Q``, and re-sorts each row + +.. function:: void nmod_sparse_mat_permute_rows(nmod_sparse_mat_t M, slong *P) + + Permutes the rows of ``M`` according to ``P`` + + +Randomization +-------------------------------------------------------------------------------- + + +.. function:: void nmod_sparse_mat_randtest(nmod_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz) + + Makes ``M`` a sparse matrix with between ``min_nnz`` and ``max_nnz`` nonzero + entries per row, with individual entries generated by nmod_randtest + + +Output +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_mat_print_pretty(const nmod_sparse_mat_t M) + + Prints the matrix ``M`` to ``stdout`` in a human-readable format + + +Comparison +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_is_zero(nmod_sparse_mat_t M) + + Checks if the given matrix ``M`` is trivial (empty), returning `1` if so and `0` + otherwise + +.. function:: void nmod_sparse_mat_equal(nmod_sparse_mat_t M1, nmod_sparse_mat_t M2, slong ioff) + + Checks if ``M1`` equals ``M2``, returning `1` if so and `0` otherwise + + +Transpose +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_mat_transpose(nmod_sparse_mat_t N, nmod_sparse_mat_t M) + + Transposes ``M`` into the matrix ``N`` (must have swapped rows and columns) + + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_mat_neg(nmod_sparse_mat_t N, const nmod_sparse_mat_t M) + + Sets ``N`` to the negation of ``M`` + +.. function:: void nmod_sparse_mat_scalar_mul_nmod(nmod_sparse_mat_t N, const nmod_sparse_mat_t M, const nmod_t c) + + Sets ``N`` to the scalar multiple of ``M`` by ``c`` + +.. function:: void nmod_sparse_mat_add(nmod_sparse_mat_t O, const nmod_sparse_mat_t M, const nmod_sparse_mat_t N) + + Sets ``O`` to the sum of ``M`` and ``N`` + +.. function:: void nmod_sparse_mat_sub(nmod_sparse_mat_t O, const nmod_sparse_mat_t M, const nmod_sparse_mat_t N) + + Sets ``O`` to the difference of ``M`` and ``N`` + +.. function:: void nmod_sparse_mat_scalar_addmul_nmod(nmod_sparse_mat_t O, const nmod_sparse_mat_t M, const nmod_sparse_mat_t N, const nmod_t c) + + Sets ``O`` to the sum of ``M`` and ``c` times ``N`` + +.. function:: void nmod_sparse_mat_scalar_submul_nmod(nmod_sparse_mat_t O, const nmod_sparse_mat_t M, const nmod_sparse_mat_t N, const nmod_t c) + + Sets ``O`` to the difference of ``M`` and ``N` times ``v`` + +.. function:: void nmod_sparse_mat_mul_vec(mp_ptr y, const nmod_sparse_mat_t M, mp_srcptr x) + + Sets ``y`` to the product of ``M`` and ``x`` + +.. function:: void nmod_sparse_mat_mul_mat(nmod_mat_t Y, const nmod_sparse_mat_t M, const nmod_mat_t X) + + Sets ``Y`` to the product of ``M`` and ``X`` + +.. function:: slong nmod_sparse_mat_inv(nmod_sparse_mat_t N, const nmod_sparse_mat_t M) + + Sets ``N`` to the "inverse" of ``M``, i.e., the matrix such that NM is + in reduced row-echelon form + + +Decomposition/reduction +-------------------------------------------------------------------------------- + +.. function:: slong nmod_sparse_mat_lu(slong *P, slong *Q, nmod_sparse_mat_t L, nmod_sparse_mat_t U, const nmod_sparse_mat_t M) + + Computes the decomposition PMQ = LU for a given sparse matrix ``M``, where + ``P`` is a row permutation, ``Q`` is a column permutation, ``L``is a lower + triangular matrix, and ``U`` is an upper triangular matrix, returns the rank + +.. function:: slong nmod_sparse_mat_rref(nmod_sparse_mat_t M) + + Applies row reduction to put ``M`` in reduced row echelon form (in place) + and returns the rank + +Solving +-------------------------------------------------------------------------------- + +.. function:: int nmod_sparse_mat_solve_lu(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b) + + Given a matrix ``M`` and target vector ``b``, use LU decomposition to find + a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int nmod_sparse_mat_solve_rref(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b) + + Given a matrix ``M`` and target vector ``b``, use the reduced row-echelon + form to find a vector ``x`` such that Mx = b, returns `1` if successful and + `0` if not + +.. function:: int nmod_sparse_mat_solve_lanczos(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b, flint_rand_t state) + + Given a matrix ``M`` and target vector ``b``, use the Lanczos algorithm to + find a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int nmod_sparse_mat_solve_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b) + + Given a matrix ``M`` and target vector ``b``, use the Wiedemann algorithm to + find a vector ``x`` such that Mx = b, returns `1` if successful and `0` if not + +.. function:: int nmod_sparse_mat_solve_block_lanczos(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b, slong block_size, flint_rand_t state) + + Given a matrix ``M`` and target vector ``b``, use Coppersmith's block Lanczos + algorithm (with specified block size) to find a vector ``x`` such that Mx = b, + returns `1` if successful and `0` if not + +.. function:: int nmod_sparse_mat_solve_block_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b, slong block_size, flint_rand_t state) + + Given a matrix ``M`` and target vector ``b``, use Coppersmith's block Wiedemann + algorithm (with specified block size) to find a vector ``x`` such that Mx = b, + returns `1` if successful and `0` if not + +Nullvector and nullspace computation +-------------------------------------------------------------------------------- + +.. function:: int nmod_sparse_mat_nullvector_lanczos(mp_ptr x, const nmod_sparse_mat_t M, flint_rand_t state) + + Given a matrix ``M``, use the Lanczos algorithm to find a nullvector ``x`` + s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int nmod_sparse_mat_nullvector_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, flint_rand_t state) + + Given a matrix ``M``, use the Wiedemann algorithm to find a nullvector ``x`` + s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int nmod_sparse_mat_nullvector_block_lanczos(mp_ptr x, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state) + + Given a matrix ``M``, use Coppersmith's block Lanczos algorithm to find a + nullvector ``x`` s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int nmod_sparse_mat_nullvector_block_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state) + + Given a matrix ``M``, use Coppersmith's block Wiedemann algorithm to find a + nullvector ``x`` s.t. Mx = 0, returns `1` if successful and `0` if not + +.. function:: int nmod_sparse_mat_nullspace_rref(nmod_mat_t X, const nmod_sparse_mat_t M) + + Given a matrix ``M``, use the reduced row echelon form to construct the + nullspace ``X`` of M (initialized by this function), returns the nullity + +.. function:: int nmod_sparse_mat_nullspace_lu(nmod_mat_t X, const nmod_sparse_mat_t M) + + Given a matrix ``M``, use the LU decomposition to construct the nullspace ``X`` + of M (initialized by this function), returns the nullity + +.. function:: int nmod_sparse_mat_nullspace_lanczos(nmod_mat_t X, const nmod_sparse_mat_t M, flint_rand_t state) + + Given a matrix ``M``, use the Lanczos algorithm to find a nullspace ``X`` + of M (initialized by this function), returns the found nullity + +.. function:: int nmod_sparse_mat_nullspace_wiedemann(nmod_mat_t X, const nmod_sparse_mat_t M, flint_rand_t state) + + Given a matrix ``M``, use the Wiedemann algorithm to find a nullspace ``X`` + of M (initialized by this function), returns the found nullity + +.. function:: int nmod_sparse_mat_nullspace_block_lanczos(nmod_mat_t X, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state) + + Given a matrix ``M``, use Coppersmith's block Lanczos algorithm to find a + nullspace ``X`` of M (initialized by this function), returns the found nullity + +.. function:: int nmod_sparse_mat_nullspace_block_wiedemann(nmod_mat_t X, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state) + + Given a matrix ``M``, use Coppersmith's block Wiedemann algorithm to find a + nullspace ``X`` of M (initialized by this function), returns the found nullity + diff --git a/doc/source/nmod_sparse_vec.rst b/doc/source/nmod_sparse_vec.rst new file mode 100644 index 0000000000..bfad8dce7b --- /dev/null +++ b/doc/source/nmod_sparse_vec.rst @@ -0,0 +1,176 @@ +.. _nmod-sparse-vec: + +**nmod_sparse_vec.h** -- sparse vectors over integers mod word-size integers +=============================================================================== + +Description. + +Types, macros and constants +------------------------------------------------------------------------------- + +.. type:: nmod_sparse_entry_t + + Holds a pair (ind, val), where ind (of type slong) is an index into the + vector and val (of type mp_limb_t) is the value at that index + +.. type:: nmod_sparse_vec_t + + Holds an array of nonzero entries (of type nmod_sparse_entry_struct *) of + specified length nnz, sorted by ind + +Memory management +-------------------------------------------------------------------------------- + + +.. function:: void nmod_sparse_vec_init(nmod_sparse_vec_t vec) + + Initializes an empty sparse vector (no allocation) + +.. function:: void nmod_sparse_vec_clear(nmod_sparse_vec_t vec, slong len) + + Clears the entries of vec and frees the space allocated for it + +.. function:: void nmod_sparse_vec_swap(nmod_sparse_vec_t vec1, nmod_sparse_vec_t vec2) + + Swaps two vectors (no reallocaton) + +Instantiation +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_vec_zero(nmod_sparse_vec_t vec) + + Sets vec to zero (the empty sparse vector) + +.. function:: void nmod_sparse_vec_one(nmod_sparse_vec_t vec, slong ind) + + Sets vec to the ind-th basis vector (single one in position ind) + +.. function:: void nmod_sparse_vec_set(nmod_sparse_vec_t dst, nmod_sparse_vec_t src) + + Makes dst a (deep) copy of src + +.. function:: void nmod_sparse_vec_set_entry(nmod_sparse_vec_t vec, slong ind, const mp_limb_t val) + + Sets the value at index ``ind`` to nonzero ``val``, either replacing an existing value or + extending the array of entries + +.. function:: void nmod_sparse_vec_from_entries(nmod_sparse_vec_t vec, slong *inds, mp_ptr vals, slong nnz) + + Constructs vec from a given sequence of indices and associated values, both of length nnz. + Assumes no duplicate indices + +Comparison +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_vec_is_zero(nmod_sparse_vec_t vec) + + Checks if the given vector is trivial (empty), returning `1` if so and `0` + otherwise + +.. function:: void nmod_sparse_vec_equal(const nmod_sparse_vec_t vec1, const nmod_sparse_vec_t vec2, slong ioff) + + Checks if vec1 equals vec2 (with s specified column offset ioff), returning + `1` if so and `0` otherwise + +Indexing +-------------------------------------------------------------------------------- + +.. function:: mp_limb_t * nmod_sparse_vec_at(nmod_sparse_vec_t vec, slong ind) + + Returns a pointer to the value at the index ind (or NULL if index not found) + + +Conversion to/from dense vector +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_vec_from_dense(nmod_sparse_vec_t dst, mp_srcptr src, slong len) + + Converts the dense vector src of length len to a sparse vector + +.. function:: void nmod_sparse_vec_to_dense(mp_ptr dst, const nmod_sparse_vec_t src, slong len) + + Converts the sparse vector src to a dense vector of length len + + +Windows, concatenation, and splitting +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_vec_window_init(nmod_sparse_vec_t window, const nmod_sparse_vec_t vec, slong i1, slong i2) + + Constructs a window on a the sparse vector vec between indices i1 and i2 + Note that window is only valid as long as original vector remains uzechified + +.. function:: void nmod_sparse_vec_window_clear(nmod_sparse_vec_t window) + + Clears a window (for safety only) + +.. function:: void nmod_sparse_vec_concat(nmod_sparse_vec_t res, const nmod_sparse_vec_t vec1, const nmod_sparse_vec_t vec2, slong len1) + + Concatenates two vectors vec1 and vec2 into res, with indices of vec2 + offset by len1 + +.. function:: void nmod_sparse_vec_split(nmod_sparse_vec_t res1, nmod_sparse_vec_t res1, const nmod_sparse_vec_t vec, slong ind) + + Splits vec into two vectors res1 and res2, with res1 containing all entries + below index ind and res2 containing the rest + +Permutation +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_vec_permute_inds(nmod_sparse_vec_t vec, slong *P) + + Permutes the indices of vec according to P, and re-sorts + + +Randomization +-------------------------------------------------------------------------------- + + +.. function:: void nmod_sparse_vec_randtest(nmod_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, nmod_t mod) + + Makes vec a sparse vector with nnz nonzero entries uniformly distributed + between 0 and len - 1, with individual entries generated by nmod_randtest + + +Output +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_vec_print_pretty(const nmod_sparse_vec_t vec, slong ioff, slong maxi, nmod_t mod) + + Prints the vector of given length to ``stdout`` in a human-readable format + + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: void nmod_sparse_vec_neg(nmod_sparse_vec_t v, const nmod_sparse_vec_t u, nmod_t mod) + + Sets ``v`` to the negation of ``u`` + +.. function:: void nmod_sparse_vec_scalar_mul_nmod(nmod_sparse_vec_t v, const nmod_sparse_vec_t u, const mp_limb_t c, nmod_t mod) + + Sets ``v`` to the scalar multiple of ``u`` by ``c`` + +.. function:: void nmod_sparse_vec_add(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, nmod_t mod) + + Sets ``w`` to the sum of ``u`` and ``v`` + +.. function:: void nmod_sparse_vec_sub(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, nmod_t mod) + + Sets ``w`` to the difference of ``u`` and ``v`` + +.. function:: void nmod_sparse_vec_scalar_addmul_nmod(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, const mp_limb_t c, nmod_t mod) + + Sets ``w`` to the sum of ``u`` and ``c` times ``v`` + +.. function:: void nmod_sparse_vec_scalar_submul_nmod(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, const mp_limb_t c, nmod_t mod) + + Sets ``w`` to the difference of ``u`` and ``c` times ``v`` + +.. function:: mp_limb_t nmod_sparse_vec_dot(const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, nmod_t mod) + + Sets ``ret`` to the dot product of ``u`` and ``v`` + +.. function:: mp_limb_t nmod_sparse_vec_dot_dense(const nmod_sparse_vec_t u, mp_srcptr v, nmod_t mod) + + Sets ``ret`` to the dot product of ``u`` and ``v`` diff --git a/fmpz_mat.h b/fmpz_mat.h index faffd10523..56aa923dd3 100644 --- a/fmpz_mat.h +++ b/fmpz_mat.h @@ -244,6 +244,14 @@ FLINT_DLL void fmpz_mat_scalar_mod_fmpz(fmpz_mat_t B, const fmpz_mat_t A, const /* Multiplication */ +FMPZ_MAT_INLINE +void fmpz_mat_mul_vec(fmpz *y, const fmpz_mat_t A, fmpz *x) +{ + slong i; + for (i = 0; i < A->r; ++i) + _fmpz_vec_dot(&y[i], A->rows[i], x, A->c); +} + FLINT_DLL void fmpz_mat_mul(fmpz_mat_t C, const fmpz_mat_t A, const fmpz_mat_t B); FLINT_DLL void fmpz_mat_mul_classical(fmpz_mat_t C, const fmpz_mat_t A, diff --git a/fmpz_mpoly/divides_array.c b/fmpz_mpoly/divides_array.c index 0b233afe73..d218f76f06 100644 --- a/fmpz_mpoly/divides_array.c +++ b/fmpz_mpoly/divides_array.c @@ -14,7 +14,6 @@ #include "flint.h" #include "fmpz.h" #include "fmpz_mpoly.h" -#include "hashmap.h" /* improve locality */ #define BLOCK 128 diff --git a/fmpz_sparse_mat.h b/fmpz_sparse_mat.h new file mode 100644 index 0000000000..965d324bb2 --- /dev/null +++ b/fmpz_sparse_mat.h @@ -0,0 +1,687 @@ +/* + Copyright (C) 2010 William Hart + Copyright (C) 2010,2011 Fredrik Johansson + Copyright (C) 2014 Ashish Kedia + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifndef FMPZ_SPARSE_MAT_H +#define FMPZ_SPARSE_MAT_H + +#ifdef FMPZ_SPARSE_MAT_INLINES_C +#define FMPZ_SPARSE_MAT_INLINE FLINT_DLL +#else +#define FMPZ_SPARSE_MAT_INLINE static __inline__ +#endif + +#undef ulong +#define ulong ulongxx /* interferes with system includes */ +#include +#undef ulong + +#include +#define ulong mp_limb_t +#include "flint.h" +#include "fmpz.h" +#include "fmpz_vec.h" +#include "hashmap.h" +#include "heap.h" +#include "nmod_sparse_mat.h" +#include "fmpz_sparse_vec.h" +#include "fmpz_mat.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* A sparse matrix is a list of sparse row vectors */ +typedef struct +{ + fmpz_sparse_vec_struct *rows; + slong r; + slong c; + slong c_off; +} +fmpz_sparse_mat_struct; + +typedef fmpz_sparse_mat_struct fmpz_sparse_mat_t[1]; + +#define LT(M, r) M->rows[r].entries[0] + +/* Can package matrix with its column support, to enable various operations */ +typedef struct +{ + fmpz_sparse_mat_struct *M; + hashmap_struct *cols; +} +fmpz_sparse_mat_with_transpose_struct; + +typedef fmpz_sparse_mat_with_transpose_struct fmpz_sparse_mat_with_transpose_t[1]; + +/* Memory management */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_init (fmpz_sparse_mat_t M, slong rows, slong cols) +{ + FLINT_ASSERT(rows >= 0 && cols >= 0); + M->rows = flint_calloc(rows, sizeof(*M->rows)); + M->r = rows; + M->c = cols; + M->c_off = 0; +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_clear (fmpz_sparse_mat_t M) +{ + slong i; + for (i = 0; i < M->r; ++i) + { + fmpz_sparse_vec_clear(&M->rows[i]); + } + flint_free(M->rows); + memset(M, 0, sizeof(*M)); +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_resize (fmpz_sparse_mat_t M, slong rows, slong cols) +{ + slong i; + FLINT_ASSERT(rows >= 0 && cols >= 0); + if (M->r != rows) { + if (M->r > rows) + { + for (i = rows; i < M->r; ++i) + { + fmpz_sparse_vec_clear(&M->rows[i]); + } + } + M->rows = flint_realloc(M->rows, rows*sizeof(*M->rows)); + if (M->r < rows) + { + memset(M->rows+M->r, 0, (rows-M->r)*sizeof(*M->rows)); + } + M->r = rows; + } + if (cols < M->c) + { + for (i = 0; i < M->r; ++i) + { + fmpz_sparse_vec_resize(&M->rows[i], cols); + } + } + M->c = cols; +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_swap (fmpz_sparse_mat_t M1, fmpz_sparse_mat_t M2) +{ + fmpz_sparse_mat_t tmp; + *tmp = *M1; *M1 = *M2; *M2 = *tmp; +} + +FLINT_DLL +slong fmpz_sparse_mat_max_bits(const fmpz_sparse_mat_t v); + +/* One-time instantiation */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_zero (fmpz_sparse_mat_t M) +{ + slong i; + for (i = 0; i < M->r; ++i) fmpz_sparse_vec_zero(&M->rows[i]); +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_one (fmpz_sparse_mat_t M) +{ + slong i; + for (i = 0; i < M->r; ++i) fmpz_sparse_vec_one(&M->rows[i], i); +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_set (fmpz_sparse_mat_t N, const fmpz_sparse_mat_t M) +{ + slong i, rmax = FLINT_MIN(M->r, M->r); + if (M==N) return; + for (i = 0; i < rmax; ++i) fmpz_sparse_vec_set(&N->rows[i], &M->rows[i], M->c_off); +} + +FLINT_DLL +void fmpz_sparse_mat_from_entries(fmpz_sparse_mat_t M, slong * rows, slong * cols, fmpz * vals, slong nnz); + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_append_col (fmpz_sparse_mat_t M, const fmpz *v) +{ + slong i; + for (i = 0; i < M->r; ++i) fmpz_sparse_vec_set_entry(&M->rows[i], M->c, &v[i]); + M->c += 1; +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_append_row (fmpz_sparse_mat_t M, const fmpz_sparse_vec_t v) +{ + M->rows = realloc(M->rows, (M->r+1)*sizeof(*M->rows)); + memset(M->rows + M->r, 0, sizeof(*M->rows)); + fmpz_sparse_vec_set(&M->rows[M->r], v, 0); + M->r += 1; +} + +/* Convert from/to dense matrix */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_from_dense (fmpz_sparse_mat_t M, const fmpz_mat_t dM) +{ + slong i, rmax = FLINT_MIN(M->r, dM->r); + if (M->c == 0 || dM->c == 0) {fmpz_sparse_mat_zero(M); return;} + for (i = 0; i < rmax; ++i) fmpz_sparse_vec_from_dense(&M->rows[i], dM->rows[i], dM->c); +} +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_to_dense (fmpz_mat_t dM, const fmpz_sparse_mat_t M) +{ + slong i, rmax = FLINT_MIN(M->r, dM->r); + if (M->c == 0 || dM->c == 0) {fmpz_mat_zero(dM); return;} + for (i = 0; i < rmax; ++i) + fmpz_sparse_vec_to_dense(dM->rows[i], &M->rows[i], dM->c); +} + +/* Convert to/from modular matrix */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_get_nmod_sparse_mat(nmod_sparse_mat_t Amod, const fmpz_sparse_mat_t A) +{ + slong i; + for (i = 0; i < A->r; i++) + fmpz_sparse_vec_get_nmod_sparse_vec(&Amod->rows[i], &A->rows[i], Amod->mod); +} + +void fmpz_sparse_mat_multi_mod_ui_precomp(nmod_sparse_mat_struct * residues, slong nres, const fmpz_sparse_mat_t M, + const fmpz_comb_t comb, fmpz_comb_temp_t temp); + +void fmpz_sparse_mat_multi_mod_ui(nmod_sparse_mat_struct * residues, slong nres, const fmpz_sparse_mat_t M); + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_set_nmod_sparse_mat_unsigned(fmpz_sparse_mat_t A, const nmod_sparse_mat_t Amod) +{ + slong i; + for (i = 0; i < A->r; i++) + fmpz_sparse_vec_set_nmod_sparse_vec_unsigned(&A->rows[i], &Amod->rows[i]); +} + + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_set_nmod_sparse_mat(fmpz_sparse_mat_t A, const nmod_sparse_mat_t Amod) +{ + slong i; + for (i = 0; i < A->r; i++) + fmpz_sparse_vec_set_nmod_sparse_vec(&A->rows[i], &Amod->rows[i], Amod->mod); +} + +FLINT_DLL +void fmpz_sparse_mat_CRT_ui(fmpz_sparse_mat_t res, const fmpz_sparse_mat_t mat1, + const fmpz_t m1, const nmod_sparse_mat_t mat2, int sign); + + +FLINT_DLL +void fmpz_sparse_mat_multi_CRT_ui_precomp(fmpz_sparse_mat_t M, nmod_sparse_mat_struct * residues, slong nres, + const fmpz_comb_t comb, fmpz_comb_temp_t temp, int sign); + +FLINT_DLL +void fmpz_sparse_mat_multi_CRT_ui(fmpz_sparse_mat_t mat, nmod_sparse_mat_struct * residues, slong nres, int sign); + +/* Windows, concatenation, and splitting */ +FLINT_DLL +void fmpz_sparse_mat_window_init (fmpz_sparse_mat_t W, const fmpz_sparse_mat_t M, slong r1, slong c1, slong r2, slong c2); + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_window_clear (fmpz_sparse_mat_t W) +{ + flint_free(W->rows); + memset(W, 0, sizeof(*W)); +} + + +/* Combine M1 and M2 into block matrix B = [M1 M2] */ +/* B->r must equal M1->r and M2->r */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_concat_horizontal(fmpz_sparse_mat_t B, + const fmpz_sparse_mat_t M1, const fmpz_sparse_mat_t M2) +{ + slong i; + B->c = M1->c + M2->c; + for (i = 0; i < B->r; ++i) + fmpz_sparse_vec_concat(&B->rows[i], &M1->rows[i], &M2->rows[i], M1->c); +} +/* Combine M1 and M2 into block matrix B = [M1^t M1^t]^t */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_concat_vertical (fmpz_sparse_mat_t B, const fmpz_sparse_mat_t M1, const fmpz_sparse_mat_t M2) +{ + slong i; + B->c = FLINT_MAX(M1->c, M2->c); + for (i = 0; i < M1->r; ++i) + fmpz_sparse_vec_set(&B->rows[i], &M1->rows[i], M1->c_off); + for (i = M1->r; i < B->r; ++i) + fmpz_sparse_vec_set(&B->rows[i], &M2->rows[i-M1->r], M2->c_off); +} + +/* Split block matrix B = [M1 M2] into submatrices M1 and M2 */ +/* M1->r and M2->r must equal B->r */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_split_horizontal (fmpz_sparse_mat_t M1, fmpz_sparse_mat_t M2, const fmpz_sparse_mat_t B, slong c) +{ + slong i; + for (i = 0; i < B->r; ++i) fmpz_sparse_vec_split(&M1->rows[i], &M2->rows[i], &B->rows[i], c); +} + +/* Split block matix B = [M1^t M1^t]^t into submatrices M1 and M2 */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_split_vertical (fmpz_sparse_mat_t M1, fmpz_sparse_mat_t M2, const fmpz_sparse_mat_t B, slong r) +{ + slong i; + r = FLINT_MIN(r, B->r); + for (i = 0; i < r; ++i) fmpz_sparse_vec_set(&M1->rows[i], &B->rows[i], B->c_off); + for (i = r; i < B->r; ++i) fmpz_sparse_vec_set(&M2->rows[i-r], &B->rows[i], B->c_off); +} + +/* Matrix permutation */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_permute_cols(fmpz_sparse_mat_t M, slong *Q) +{ + slong i; + for (i = 0; i < M->r; ++i) + { + if (!M->rows[i].nnz) continue; + fmpz_sparse_vec_permute_inds(&M->rows[i], Q); + qsort(M->rows[i].entries, M->rows[i].nnz, sizeof(*M->rows[i].entries), fmpz_sparse_entry_cmp); + } +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_permute_rows(fmpz_sparse_mat_t M, slong *P) +{ + slong i; + fmpz_sparse_vec_struct *prows; + prows = flint_calloc(M->r, sizeof(*prows)); + for (i = 0; i < M->r; ++i) prows[P[i]] = M->rows[i]; + memcpy(M->rows, prows, M->r*sizeof(*M->rows)); + flint_free(prows); +} + +/* Random matrix generation */ +FLINT_DLL void fmpz_sparse_mat_randtest (fmpz_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz, flint_bitcnt_t bits); +FLINT_DLL void fmpz_sparse_mat_randtest_unsigned (fmpz_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz, flint_bitcnt_t bits); +/* +FLINT_DLL void fmpz_sparse_mat_randfull (fmpz_sparse_mat_t M, flint_rand_t state, fmpz_ctx_t ctx); +FLINT_DLL int fmpz_sparse_mat_randpermdiag(fmpz_sparse_mat_t M, flint_rand_t state, + const fmpz *diag, slong n); +FLINT_DLL void fmpz_sparse_mat_randrank (fmpz_sparse_mat_t, flint_rand_t state, slong rank, fmpz_ctx_t ctx); +FLINT_DLL void fmpz_sparse_mat_randops (fmpz_sparse_mat_t M, slong count, flint_rand_t state, fmpz_ctx_t ctx); +FLINT_DLL void fmpz_sparse_mat_randtril (fmpz_sparse_mat_t M, flint_rand_t state, int unit, fmpz_ctx_t ctx); +FLINT_DLL void fmpz_sparse_mat_randtriu (fmpz_sparse_mat_t M, flint_rand_t state, int unit, fmpz_ctx_t ctx); + */ + +FLINT_DLL void fmpz_sparse_mat_print_pretty (const fmpz_sparse_mat_t M); + +FMPZ_SPARSE_MAT_INLINE +int fmpz_sparse_mat_equal (const fmpz_sparse_mat_t M1, const fmpz_sparse_mat_t M2) +{ + slong i; + if (M1->r != M2->r) return 0; + for (i = 0; i < M1->r; ++i) + if (!fmpz_sparse_vec_equal(&M1->rows[i], &M2->rows[i], M1->c_off-M2->c_off)) return 0; + return 1; +} + +FMPZ_SPARSE_MAT_INLINE +int fmpz_sparse_mat_is_zero (const fmpz_sparse_mat_t M) +{ + slong i; + for (i = 0; i < M->r; ++i) + if (!fmpz_sparse_vec_is_zero(&M->rows[i])) return 0; + return 1; +} + +/* Must have M->r == N->c and M->c == N->r */ +FLINT_DLL +void fmpz_sparse_mat_transpose (fmpz_sparse_mat_t N, const fmpz_sparse_mat_t M); + +/* Arithmetic */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_neg (fmpz_sparse_mat_t N, const fmpz_sparse_mat_t M) +{ + slong i; + FLINT_ASSERT(M->r == N->r); + for (i = 0; i < N->r; ++i) fmpz_sparse_vec_neg(&N->rows[i], &M->rows[i]); +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_scalar_mul_fmpz(fmpz_sparse_mat_t N, const fmpz_sparse_mat_t M, const fmpz_t c) +{ + slong i; + FLINT_ASSERT(M->r == N->r); + for (i = 0; i < N->r; ++i) fmpz_sparse_vec_scalar_mul_fmpz(&N->rows[i], &M->rows[i], c); +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_mul_diag_fmpz(fmpz_sparse_mat_t N, const fmpz_sparse_mat_t M, fmpz * D) +{ + slong i; + FLINT_ASSERT(M->r == N->r); + for (i = 0; i < N->r; ++i) fmpz_sparse_vec_scalar_mul_fmpz(&N->rows[i], &M->rows[i], &D[i]); +} + + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_scalar_divexact_fmpz(fmpz_sparse_mat_t N, const fmpz_sparse_mat_t M, const fmpz_t c) +{ + slong i; + FLINT_ASSERT(M->r == N->r); + for (i = 0; i < N->r; ++i) fmpz_sparse_vec_scalar_divexact_fmpz(&N->rows[i], &M->rows[i], c); +} + + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_scalar_mod_fmpz(fmpz_sparse_mat_t N, const fmpz_sparse_mat_t M, const fmpz_t mod) +{ + slong i; + FLINT_ASSERT(M->r == N->r); + for (i = 0; i < N->r; ++i) fmpz_sparse_vec_scalar_mod_fmpz(&N->rows[i], &M->rows[i], mod); +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_scalar_mods_fmpz(fmpz_sparse_mat_t N, const fmpz_sparse_mat_t M, const fmpz_t mod) +{ + slong i; + FLINT_ASSERT(M->r == N->r); + for (i = 0; i < N->r; ++i) fmpz_sparse_vec_scalar_mods_fmpz(&N->rows[i], &M->rows[i], mod); +} + + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_add (fmpz_sparse_mat_t O, const fmpz_sparse_mat_t M, const fmpz_sparse_mat_t N) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) fmpz_sparse_vec_add(&O->rows[i], &M->rows[i], &N->rows[i]); +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_sub (fmpz_sparse_mat_t O, const fmpz_sparse_mat_t M, const fmpz_sparse_mat_t N) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) fmpz_sparse_vec_sub(&O->rows[i], &M->rows[i], &N->rows[i]); +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_scalar_addmul_fmpz(fmpz_sparse_mat_t O, const fmpz_sparse_mat_t M, const fmpz_sparse_mat_t N, const fmpz_t c) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) fmpz_sparse_vec_scalar_addmul_fmpz(&O->rows[i], &M->rows[i], &N->rows[i], c); +} + +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_scalar_submul_fmpz(fmpz_sparse_mat_t O, const fmpz_sparse_mat_t M, const fmpz_sparse_mat_t N, const fmpz_t c) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) fmpz_sparse_vec_scalar_submul_fmpz(&O->rows[i], &M->rows[i], &N->rows[i], c); +} + +/* Matrix-vector and matrix-matrix multipliciation */ +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_mul_vec (fmpz *y, const fmpz_sparse_mat_t M, const fmpz *x) +{ + slong i; + if (M->c == 0) _fmpz_vec_zero(y, M->r); + else for (i = 0; i < M->r; ++i) fmpz_sparse_vec_dot_dense(&y[i], &M->rows[i], x); +} +FMPZ_SPARSE_MAT_INLINE +void fmpz_sparse_mat_mul_mat (fmpz_mat_t Y, const fmpz_sparse_mat_t M, const fmpz_mat_t X) +{ + slong i, j; + FLINT_ASSERT(M->r == Y->r && M->c == X->r && X->c == Y->c); + fmpz_mat_zero (Y); + for (i = 0; i < M->r; ++i) + { + for (j = 0; j < M->rows[i].nnz; ++j) + { + fmpz_sparse_entry_struct *e = &M->rows[i].entries[j]; + _fmpz_vec_scalar_addmul_fmpz(Y->rows[i], X->rows[e->ind], X->c, e->val); + } + } +} + +/* Memory management for matrix with transpose */ +FLINT_DLL +void _fmpz_sparse_mat_with_transpose_init(fmpz_sparse_mat_with_transpose_t MT, fmpz_sparse_mat_t M); + +FMPZ_SPARSE_MAT_INLINE +void _fmpz_sparse_mat_with_transpose_clear(fmpz_sparse_mat_with_transpose_t MT) +{ + slong c; + for (c = 0; c < MT->M->c; ++c) + hashmap_clear(&MT->cols[c]); + flint_free(MT->cols); + memset(MT, 0, sizeof(*MT)); +} + +FMPZ_SPARSE_MAT_INLINE +void _fmpz_sparse_mat_with_transpose_print_pretty(fmpz_sparse_mat_with_transpose_t MT) +{ + slong i, j; + fmpz_sparse_mat_print_pretty(MT->M); + flint_printf("Transpose: \nSupport: "); + for (i = 0; i < MT->M->c; ++i) + { + flint_printf("%wd ", MT->cols[i].num); + } + flint_printf("\n"); + for (i = 0; i < MT->M->c; ++i) + { + flint_printf("%wd: [", i); fflush(stdout); + for (j = 0; j < MT->cols[i].num; ++j) + { + if (j > 0) flint_printf(" "); + flint_printf("%wd: ", MT->cols[i].keys[j]); fflush(stdout); + fmpz_print(*((fmpz_t *) (MT->cols[i].vals[j]))); + } + flint_printf("]\n"); + } +} + +FLINT_DLL +void _fmpz_sparse_mat_with_transpose_fix_support(fmpz_sparse_mat_with_transpose_t MT, slong r, slong *osupp, slong onnz); + +#define MT_FIX(MT, r, ...) \ +{\ + slong *supp, nnz; \ + nnz = _fmpz_sparse_vec_support(&supp, &MT->M->rows[r]); \ + __VA_ARGS__; \ + _fmpz_sparse_mat_with_transpose_fix_support(MT, r, supp, nnz);\ + flint_free(supp);\ +} + +FMPZ_SPARSE_MAT_INLINE +int _fmpz_sparse_mat_with_transpose_gauss_elim_col(fmpz_sparse_mat_with_transpose_t MT, slong pr, slong r, slong col) +{ + MT_FIX(MT, r, fmpz_sparse_vec_gauss_elim_col(&MT->M->rows[r], &MT->M->rows[pr], col)); + return fmpz_sparse_vec_at(&MT->M->rows[r], col) == NULL; +} + +FMPZ_SPARSE_MAT_INLINE +int _fmpz_sparse_mat_with_transpose_gauss_elim(fmpz_sparse_mat_with_transpose_t MT, slong pr, slong r) +{ + MT_FIX(MT, r, fmpz_sparse_vec_gauss_elim(&MT->M->rows[r], &MT->M->rows[pr])); + return fmpz_sparse_vec_at(&MT->M->rows[r], MT->M->rows[pr].entries[0].ind) == NULL; +} + +FMPZ_SPARSE_MAT_INLINE +int _fmpz_sparse_mat_with_transpose_gauss_elim_mod(fmpz_sparse_mat_with_transpose_t MT, slong pr, slong r, const fmpz_t mod) +{ + MT_FIX(MT, r, + fmpz_sparse_vec_gauss_elim(&MT->M->rows[r], &MT->M->rows[pr]); + fmpz_sparse_vec_scalar_mod_fmpz(&MT->M->rows[r], &MT->M->rows[r], mod)); + return fmpz_sparse_vec_at(&MT->M->rows[r], MT->M->rows[pr].entries[0].ind) == NULL; +} + +FMPZ_SPARSE_MAT_INLINE +int _fmpz_sparse_mat_with_transpose_gauss_elim_mods(fmpz_sparse_mat_with_transpose_t MT, slong pr, slong r, const fmpz_t mod) +{ + MT_FIX(MT, r, + fmpz_sparse_vec_gauss_elim(&MT->M->rows[r], &MT->M->rows[pr]); + fmpz_sparse_vec_scalar_mods_fmpz(&MT->M->rows[r], &MT->M->rows[r], mod)); + return fmpz_sparse_vec_at(&MT->M->rows[r], MT->M->rows[pr].entries[0].ind) == NULL; +} + +FMPZ_SPARSE_MAT_INLINE +int _fmpz_sparse_mat_with_transpose_gauss_elim_ext(fmpz_sparse_mat_with_transpose_t MT, slong pr, slong r) +{ + /* If leading entries do not match, or leading entry of pr divides that of r, just a normal elimination */ + fmpz_sparse_entry_struct *pe = &MT->M->rows[pr].entries[0], *e = &MT->M->rows[r].entries[0]; + if (pe->ind != e->ind) + return _fmpz_sparse_mat_with_transpose_gauss_elim(MT, pr, r); + + MT_FIX(MT, pr, MT_FIX(MT, r, + fmpz_sparse_vec_gauss_elim_ext(&MT->M->rows[r], &MT->M->rows[pr]) + )); + return 1; +} + +FMPZ_SPARSE_MAT_INLINE +int _fmpz_sparse_mat_with_transpose_gauss_elim_ext_mod(fmpz_sparse_mat_with_transpose_t MT, slong pr, slong r, const fmpz_t mod) +{ + /* If leading entries do not match, or leading entry of pr divides that of r, just a normal elimination */ + fmpz_sparse_entry_struct *pe = &MT->M->rows[pr].entries[0], *e = &MT->M->rows[r].entries[0]; + if (pe->ind != e->ind) + return _fmpz_sparse_mat_with_transpose_gauss_elim_mod(MT, pr, r, mod); + + MT_FIX(MT, pr, MT_FIX(MT, r, + fmpz_sparse_vec_gauss_elim_ext(&MT->M->rows[r], &MT->M->rows[pr]); + fmpz_sparse_vec_scalar_mod_fmpz(&MT->M->rows[pr], &MT->M->rows[pr], mod); + fmpz_sparse_vec_scalar_mod_fmpz(&MT->M->rows[r], &MT->M->rows[r], mod); + )); + return 1; +} + +FMPZ_SPARSE_MAT_INLINE +int _fmpz_sparse_mat_with_transpose_gauss_elim_ext_mods(fmpz_sparse_mat_with_transpose_t MT, slong pr, slong r, const fmpz_t mod) +{ + /* If leading entries do not match, or leading entry of pr divides that of r, just a normal elimination */ + fmpz_sparse_entry_struct *pe = &MT->M->rows[pr].entries[0], *e = &MT->M->rows[r].entries[0]; + if (pe->ind != e->ind) + return _fmpz_sparse_mat_with_transpose_gauss_elim_mods(MT, pr, r, mod); + + MT_FIX(MT, pr, MT_FIX(MT, r, + fmpz_sparse_vec_gauss_elim_ext(&MT->M->rows[r], &MT->M->rows[pr]); + fmpz_sparse_vec_scalar_mods_fmpz(&MT->M->rows[pr], &MT->M->rows[pr], mod); + fmpz_sparse_vec_scalar_mods_fmpz(&MT->M->rows[r], &MT->M->rows[r], mod); + )); + return 1; +} + +/* Utility computations */ +FLINT_DLL +void fmpz_sparse_mat_content(fmpz_t mat_gcd, const fmpz_sparse_mat_t M); + +FLINT_DLL +void fmpz_sparse_mat_gram(fmpz_mat_t B, const fmpz_sparse_mat_t A); + +/* Solving */ +FLINT_DLL +void fmpz_sparse_mat_solve_bound(fmpz_t N, fmpz_t D, const fmpz_sparse_mat_t A, const fmpz_mat_t B); + +FLINT_DLL +int fmpz_sparse_mat_solve_dixon(fmpz_mat_t X, fmpz_t mod, const fmpz_sparse_mat_t A, const fmpz_mat_t B); + +FMPZ_SPARSE_MAT_INLINE +int fmpz_sparse_mat_solve_vec_dixon(fmpz * x, fmpz_t mod, const fmpz_sparse_mat_t A, fmpz *b) +{ + int ret; + slong i; + fmpz_mat_t X, B; + fmpz_mat_init(X, A->c, 1); + fmpz_mat_init(B, A->r, 1); + for (i = 0; i < A->r; ++i) fmpz_set(fmpz_mat_entry(B, i, 0), &b[i]); + ret = fmpz_sparse_mat_solve_dixon(X, mod, A, B); + for (i = 0; i < A->c; ++i) fmpz_set(&x[i], fmpz_mat_entry(X, i, 0)); + fmpz_mat_clear(X); + fmpz_mat_clear(B); + return ret; +} + +FLINT_DLL +int fmpz_sparse_mat_solve_dixon_den(fmpz_mat_t X, fmpz_t den, const fmpz_sparse_mat_t A, const fmpz_mat_t B); + +FMPZ_SPARSE_MAT_INLINE +int fmpz_sparse_mat_solve_vec_dixon_den(fmpz * x, fmpz_t den, const fmpz_sparse_mat_t A, fmpz *b) +{ + int ret; + slong i; + fmpz_mat_t X, B; + fmpz_mat_init(X, A->c, 1); + fmpz_mat_init(B, A->r, 1); + for (i = 0; i < A->r; ++i) fmpz_set(fmpz_mat_entry(B, i, 0), &b[i]); + ret = fmpz_sparse_mat_solve_dixon_den(X, den, A, B); + for (i = 0; i < A->c; ++i) fmpz_set(&x[i], fmpz_mat_entry(X, i, 0)); + fmpz_mat_clear(X); + fmpz_mat_clear(B); + return ret; +} + +/* Determinant computation */ +FLINT_DLL +void fmpz_sparse_mat_det_bound(fmpz_t bound, const fmpz_sparse_mat_t A); +FLINT_DLL +void fmpz_sparse_mat_det_cofactor(fmpz_t det, const fmpz_sparse_mat_t M); +FLINT_DLL +void fmpz_sparse_mat_det_bareiss(fmpz_t det, const fmpz_sparse_mat_t M); +FLINT_DLL +void fmpz_sparse_mat_det_divisor(fmpz_t d, const fmpz_sparse_mat_t M); +FLINT_DLL +void fmpz_sparse_mat_det_modular_accelerated(fmpz_t det, const fmpz_sparse_mat_t A, int proved); +FLINT_DLL +void fmpz_sparse_mat_det_modular_given_divisor(fmpz_t det, const fmpz_sparse_mat_t A, const fmpz_t d, int proved); +FLINT_DLL +void fmpz_sparse_mat_det_modular(fmpz_t det, const fmpz_sparse_mat_t A, int proved); +FLINT_DLL +void fmpz_sparse_mat_det(fmpz_t det, const fmpz_sparse_mat_t A); + +/* Fraction-free LU factorization */ +FLINT_DLL +slong fmpz_sparse_mat_fflu(fmpz *D, slong *P, slong *Q, fmpz_sparse_mat_t L, fmpz_sparse_mat_t U, + const fmpz_sparse_mat_t M); + +/* Hermite normal form */ +FLINT_DLL +int fmpz_sparse_mat_is_in_hnf(const fmpz_sparse_mat_t A); + +FLINT_DLL +slong fmpz_sparse_mat_hnf_classical(fmpz_sparse_mat_t M); + +FLINT_DLL +slong fmpz_sparse_mat_hnf_xgcd(fmpz_sparse_mat_t M); + +FLINT_DLL +slong fmpz_sparse_mat_hnf_minors(fmpz_sparse_mat_t M); + +FLINT_DLL +slong fmpz_sparse_mat_hnf_modular(fmpz_sparse_mat_t M, const fmpz_t det); + +FLINT_DLL +slong fmpz_sparse_mat_hnf_modular_eldiv(fmpz_sparse_mat_t M, const fmpz_t n); + +/* Modular forms */ +slong fmpz_sparse_mat_howell_form_mod(fmpz_sparse_mat_t M, const fmpz_t mod); + +FLINT_DLL +slong fmpz_sparse_mat_strong_echelon_form_mod(fmpz_sparse_mat_t M, const fmpz_t mod); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/fmpz_sparse_mat/CRT_ui.c b/fmpz_sparse_mat/CRT_ui.c new file mode 100644 index 0000000000..577b456dff --- /dev/null +++ b/fmpz_sparse_mat/CRT_ui.c @@ -0,0 +1,31 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "nmod_sparse_mat.h" +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_CRT_ui(fmpz_sparse_mat_t res, const fmpz_sparse_mat_t mat1, + const fmpz_t m1, const nmod_sparse_mat_t mat2, int sign) +{ + slong i; + mp_limb_t m1i_m2 = n_invmod(fmpz_fdiv_ui(m1, mat2->mod.n), mat2->mod.n); + + if (m1i_m2 == 0) + { + flint_printf("Exception (fmpz_mat_CRT_ui). m1 not invertible modulo m2.\n"); + flint_abort(); + } + for (i = 0; i < mat1->r; i++) + fmpz_sparse_vec_CRT_ui(&res->rows[i], &mat1->rows[i], m1, &mat2->rows[i], mat2->mod, m1i_m2, sign); +} + diff --git a/fmpz_sparse_mat/content.c b/fmpz_sparse_mat/content.c new file mode 100644 index 0000000000..f9a7d44b34 --- /dev/null +++ b/fmpz_sparse_mat/content.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2015 Dharak Kharod + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" +#include "fmpz.h" + +void fmpz_sparse_mat_content(fmpz_t mat_gcd, const fmpz_sparse_mat_t M) +{ + slong i, j; + fmpz_set_si(mat_gcd,0); + for (i = 0; i < M->r; i++ ) + { + for (j = 0; j < M->rows[i].nnz; j++) + { + fmpz_gcd(mat_gcd, mat_gcd, M->rows[i].entries[j].val); + if (fmpz_is_one(mat_gcd)) return; + } + } +} + diff --git a/fmpz_sparse_mat/det.c b/fmpz_sparse_mat/det.c new file mode 100644 index 0000000000..1bcad6cab3 --- /dev/null +++ b/fmpz_sparse_mat/det.c @@ -0,0 +1,36 @@ +/* + Copyright (C) 2010,2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_det(fmpz_t det, const fmpz_sparse_mat_t A) +{ + slong dim = A->r; + FLINT_ASSERT(A->r == A->c); + + if (dim < 5) + fmpz_sparse_mat_det_cofactor(det, A); + else if (dim < 25) + fmpz_sparse_mat_det_bareiss(det, A); + else if (dim < 60) + fmpz_sparse_mat_det_modular(det, A, 1); + else + { + slong bits = fmpz_sparse_mat_max_bits(A); + + if (dim < FLINT_ABS(bits)) + fmpz_sparse_mat_det_modular(det, A, 1); + else + fmpz_sparse_mat_det_modular_accelerated(det, A, 1); + } +} diff --git a/fmpz_sparse_mat/det_bareiss.c b/fmpz_sparse_mat/det_bareiss.c new file mode 100644 index 0000000000..3d9ea39291 --- /dev/null +++ b/fmpz_sparse_mat/det_bareiss.c @@ -0,0 +1,48 @@ +/* + Copyright (C) 2010,2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" +#include "perm.h" + +void +fmpz_sparse_mat_det_bareiss(fmpz_t det, const fmpz_sparse_mat_t M) +{ + slong i, rk, *P, *Q; + fmpz *D; + fmpz_sparse_mat_t L, U; + FLINT_ASSERT(M->r == M->c); + fmpz_one(det); + if (M->r == UWORD(0)) return; + + P = flint_malloc(M->r*sizeof(*P)); + Q = flint_malloc(M->c*sizeof(*P)); + D = _fmpz_vec_init(M->r); + fmpz_sparse_mat_init(L, M->r, M->c); + fmpz_sparse_mat_init(U, M->r, M->c); + rk = fmpz_sparse_mat_fflu(D, P, Q, L, U, M); + if (rk != M->r) fmpz_zero(det); + else + { + for (i = 0; i < M->r; ++i) + fmpz_mul(det, det, U->rows[i].entries[0].val); + for (i = 0; i < M->r; ++i) + fmpz_divexact(det, det, &D[i]); + if (_perm_parity(P, M->r) ^ _perm_parity(Q, M->c)) + fmpz_neg(det, det); + } + + flint_free(P); + flint_free(Q); + _fmpz_vec_clear(D, M->r); + fmpz_sparse_mat_clear(L); + fmpz_sparse_mat_clear(U); +} diff --git a/fmpz_sparse_mat/det_bound.c b/fmpz_sparse_mat/det_bound.c new file mode 100644 index 0000000000..b14f1ce389 --- /dev/null +++ b/fmpz_sparse_mat/det_bound.c @@ -0,0 +1,42 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_det_bound(fmpz_t bound, const fmpz_sparse_mat_t A) +{ + fmpz_t s, t; + slong i, j; + FLINT_ASSERT(A->r == A->c); + + fmpz_init(s); + fmpz_init(t); + + /* bound = II_i ceil(||A[i]||_2) */ + fmpz_one(bound); + for (i = 0; i < A->r; i++) + { + fmpz_zero(s); + for (j = 0; j < A->rows[i].nnz; j++) + fmpz_addmul(s, A->rows[i].entries[j].val, A->rows[i].entries[j].val); + fmpz_sqrtrem(s, t, s); + + if (!fmpz_is_zero(t)) + fmpz_add_ui(s, s, UWORD(1)); + + fmpz_mul(bound, bound, s); + } + + fmpz_clear(s); + fmpz_clear(t); +} diff --git a/fmpz_sparse_mat/det_cofactor.c b/fmpz_sparse_mat/det_cofactor.c new file mode 100644 index 0000000000..eccb5bbe3d --- /dev/null +++ b/fmpz_sparse_mat/det_cofactor.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2010,2011,2018 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_det_cofactor(fmpz_t det, const fmpz_sparse_mat_t M) +{ + fmpz_mat_t dM; + FLINT_ASSERT(M->r == M->c); + if (M->r != M->c) {fmpz_zero(det); return;} + if (M->r > 4) + { + flint_printf("Exception (fmpz_sparse_mat_det_cofactor). dim > 4 not implemented."); + flint_abort(); + } + fmpz_mat_init(dM, M->r, M->c); + fmpz_sparse_mat_to_dense(dM, M); + fmpz_mat_det_cofactor(det, dM); + fmpz_mat_clear(dM); +} diff --git a/fmpz_sparse_mat/det_divisor.c b/fmpz_sparse_mat/det_divisor.c new file mode 100644 index 0000000000..bb8d8a64b9 --- /dev/null +++ b/fmpz_sparse_mat/det_divisor.c @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" +#include "fmpq.h" + +void +fmpz_sparse_mat_det_divisor(fmpz_t d, const fmpz_sparse_mat_t M) +{ + int success; + slong i; + fmpz_mat_t X, B; + fmpz_t t, u, v, mod; + FLINT_ASSERT(M->r == M->c); + + fmpz_mat_init(X, M->c, 1); + fmpz_mat_init(B, M->r, 1); + fmpz_init(t); + fmpz_init(u); + fmpz_init(v); + fmpz_init(mod); + + /* Create a "random" vector */ + for (i = 0; i < M->r; i++) + fmpz_set_si(fmpz_mat_entry(B, i, 0), 2*(i % 2) - 1); + + success = fmpz_sparse_mat_solve_dixon(X, mod, M, B); + if (success) + { + fmpz_one(d); + for (i = 0; i < M->r; i++) + { + fmpz_mul(t, d, fmpz_mat_entry(X, i, 0)); + fmpz_fdiv_qr(u, t, t, mod); + if (!_fmpq_reconstruct_fmpz(u, v, t, mod)) + { + flint_printf("Exception (fmpz_mat_det_divisor): " + "Rational reconstruction failed.\n"); + flint_abort(); + } + + fmpz_mul(d, v, d); + } + } + else fmpz_zero(d); + + fmpz_mat_clear(X); + fmpz_mat_clear(B); + fmpz_clear(t); + fmpz_clear(u); + fmpz_clear(v); + fmpz_clear(mod); +} diff --git a/fmpz_sparse_mat/det_modular.c b/fmpz_sparse_mat/det_modular.c new file mode 100644 index 0000000000..a56b1e1e5a --- /dev/null +++ b/fmpz_sparse_mat/det_modular.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_det_modular(fmpz_t det, const fmpz_sparse_mat_t A, int proved) +{ + fmpz_t d; + FLINT_ASSERT(A->r == A->c); + fmpz_init(d); + fmpz_one(d); + fmpz_sparse_mat_det_modular_given_divisor(det, A, d, proved); + fmpz_clear(d); +} diff --git a/fmpz_sparse_mat/det_modular_accelerated.c b/fmpz_sparse_mat/det_modular_accelerated.c new file mode 100644 index 0000000000..ad39bd9b33 --- /dev/null +++ b/fmpz_sparse_mat/det_modular_accelerated.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_det_modular_accelerated(fmpz_t det, const fmpz_sparse_mat_t A, int proved) +{ + fmpz_t d; + FLINT_ASSERT(A->r == A->c); + fmpz_init(d); + fmpz_sparse_mat_det_divisor(d, A); + fmpz_sparse_mat_det_modular_given_divisor(det, A, d, proved); + fmpz_clear(d); +} diff --git a/fmpz_sparse_mat/det_modular_given_divisor.c b/fmpz_sparse_mat/det_modular_given_divisor.c new file mode 100644 index 0000000000..bbb678f93e --- /dev/null +++ b/fmpz_sparse_mat/det_modular_given_divisor.c @@ -0,0 +1,102 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "nmod_sparse_mat.h" +#include "fmpz_sparse_mat.h" + +/* Enable to exercise corner cases */ +#define DEBUG_USE_SMALL_PRIMES 0 + + +static mp_limb_t +next_good_prime(const fmpz_t d, mp_limb_t p) +{ + mp_limb_t r = 0; + + while (r == 0) + { + p = n_nextprime(p, 0); + r = fmpz_fdiv_ui(d, p); + } + + return p; +} + + +void +fmpz_sparse_mat_det_modular_given_divisor(fmpz_t det, const fmpz_sparse_mat_t A, + const fmpz_t d, int proved) +{ + fmpz_t bound, prod, stable_prod, x, xnew; + mp_limb_t p, xmod; + nmod_t mod; + nmod_sparse_mat_t Amod; + slong n = A->r; + FLINT_ASSERT(A->r == A->c); + + if (A->r == 0) {fmpz_one(det); return;} + if (fmpz_is_zero(d)) {fmpz_zero(det); return;} + + fmpz_init(bound); + fmpz_init(prod); + fmpz_init(stable_prod); + fmpz_init(x); + fmpz_init(xnew); + + /* Bound x = det(A) / d */ + fmpz_sparse_mat_det_bound(bound, A); + fmpz_mul_ui(bound, bound, UWORD(2)); /* accomodate sign */ + fmpz_cdiv_q(bound, bound, d); + + nmod_init(&mod, 2); + nmod_sparse_mat_init(Amod, n, n, mod); + fmpz_zero(x); + fmpz_one(prod); + + p = UWORD(1) << NMOD_MAT_OPTIMAL_MODULUS_BITS; + + /* Compute x = det(A) / d */ + while (fmpz_cmp(prod, bound) <= 0) + { + p = next_good_prime(d, p); + nmod_init(&mod, p); + Amod->mod = mod; + fmpz_sparse_mat_get_nmod_sparse_mat(Amod, A); + + /* Compute x = det(A) / d mod p */ + xmod = nmod_sparse_mat_det(Amod); + xmod = n_mulmod2_preinv(xmod, + n_invmod(fmpz_fdiv_ui(d, p), p), Amod->mod.n, Amod->mod.ninv); + + fmpz_CRT_ui(xnew, x, prod, xmod, p, 1); + + if (fmpz_equal(xnew, x)) + { + fmpz_mul_ui(stable_prod, stable_prod, p); + if (!proved && fmpz_bits(stable_prod) > 100) break; + } + else fmpz_set_ui(stable_prod, p); + + fmpz_mul_ui(prod, prod, p); + fmpz_set(x, xnew); + } + + /* det(A) = x * d */ + fmpz_mul(det, x, d); + + nmod_sparse_mat_clear(Amod); + fmpz_clear(bound); + fmpz_clear(prod); + fmpz_clear(stable_prod); + fmpz_clear(x); + fmpz_clear(xnew); +} diff --git a/fmpz_sparse_mat/fflu.c b/fmpz_sparse_mat/fflu.c new file mode 100644 index 0000000000..5038505bb6 --- /dev/null +++ b/fmpz_sparse_mat/fflu.c @@ -0,0 +1,136 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" +#include "hashmap.h" +#include "heap.h" +#include "perm.h" +#include "longlong.h" + +static void update_heap(heap_t h, const fmpz_sparse_mat_with_transpose_t MT, slong r, slong *osupp, slong onnz) +{ + slong i = 0, j = 0, oc, nc, c; + fmpz_sparse_vec_struct *row = &MT->M->rows[r]; + while (1) + { + oc = (i==onnz) ? MT->M->c : osupp[i]; + nc = (j==row->nnz) ? MT->M->c : row->entries[j].ind; + c = FLINT_MIN(oc, nc); + if (c >= MT->M->c) break; + if (oc != nc) heap_adjust(h, c, MT->cols[c].num); + if (c==oc) ++i; + if (c==nc) ++j; + } +} + +slong +fmpz_sparse_mat_fflu(fmpz *D, slong *P, slong *Q, fmpz_sparse_mat_t L, fmpz_sparse_mat_t U, + const fmpz_sparse_mat_t M) +{ + slong i, j, r, c, pr, pc, rank, remr, remc, *supp, nnz; + heap_t h; + fmpz_t pivot, one, tmp; + fmpz_sparse_vec_struct *prow, *row; + hashmap_struct *hcol; + fmpz_t *hval; + fmpz_sparse_mat_with_transpose_t UT; + + for (i = 0; i < M->r; ++i) fmpz_one(&D[i]); + if (M->r == 0 || M->c == 0) + { + fmpz_sparse_mat_zero (L); + fmpz_sparse_mat_zero (U); + for (i = 0; i < M->r; ++i) P[i] = i; + for (i = 0; i < M->c; ++i) Q[i] = i; + return 0; + } + fmpz_init(pivot); + fmpz_init(tmp); + fmpz_init_set_ui(one, UWORD(1)); + fmpz_sparse_mat_zero(L); + fmpz_sparse_mat_set (U, M); + _fmpz_sparse_mat_with_transpose_init(UT, U); + + /* Initialize permutations */ + remr = M->r, remc = M->c; + for (r = 0; r < M->r; ++r) + { + if (!U->rows[r].nnz) P[r] = --remr; + else P[r] = -1; + } + for (c = 0; c < M->c; ++c) + { + if (!UT->cols[c].num) Q[c] = --remc; + else Q[c] = -1; + } + + /* Make heap of nonzero columns by size */ + heap_init(h, M->c); + for (c = 0; c < M->c; ++c) + heap_push(h, UT->cols[c].num); + + /* Run elimination */ + rank = 0; + + while (h->num > 0) + { + /* Get lowest weight column (top of heap) */ + pc = heap_pop(h, NULL); + hcol = &UT->cols[pc]; + + /* Get lowest weight incident row */ + prow = NULL, pr = -1; + for (i = 0; i < hcol->num; ++i) + { + r = hcol->keys[i]; + row = &U->rows[r]; + if (prow == NULL || row->nnz < prow->nnz) + pr = r, prow = row; + } + if (pr == -1) {if (Q[pc] == -1) Q[pc] = --remc; continue;} + P[pr] = Q[pc] = rank++; /* Move pivot row and col to front */ + + /* Get pivot */ + fmpz_set(pivot, *fmpz_sparse_vec_at(prow, pc)); + fmpz_sparse_vec_set_entry(&L->rows[pr], pc, one); + + /* Remove pivot row from transpose */ + for (j = 0; j < prow->nnz; ++j) + hashmap_rem(&UT->cols[prow->entries[j].ind], pr); + + /* Use pivot row to fraction-free Gaussian eliminate other incident rows */ + while (hcol->num > 0) + { + r = hcol->keys[0]; + nnz = _fmpz_sparse_vec_support(&supp, &U->rows[r]); + fmpz_mul(&D[r], &D[r], pivot); + hval = hcol->vals[0], fmpz_set(tmp, *hval); + fmpz_sparse_vec_scalar_mul_fmpz(&U->rows[r], &U->rows[r], pivot); + fmpz_sparse_vec_scalar_mul_fmpz(&L->rows[r], &L->rows[r], pivot); + fmpz_sparse_vec_set_entry(&L->rows[r], pc, tmp); + _fmpz_sparse_mat_with_transpose_gauss_elim_col(UT, pr, r, pc); + update_heap(h, UT, r, supp, nnz); + if (U->rows[r].nnz == 0) P[r] = --remr; + } + } + heap_clear(h); + _fmpz_sparse_mat_with_transpose_clear(UT); + + /* Reorder rows and cols in L and U */ + fmpz_sparse_mat_permute_cols (L, Q); + fmpz_sparse_mat_permute_rows (L, P); + fmpz_sparse_mat_permute_cols (U, Q); + fmpz_sparse_mat_permute_rows (U, P); + fmpz_clear(pivot); + fmpz_clear(tmp); + return rank; +} diff --git a/fmpz_sparse_mat/from_entries.c b/fmpz_sparse_mat/from_entries.c new file mode 100644 index 0000000000..d31194a885 --- /dev/null +++ b/fmpz_sparse_mat/from_entries.c @@ -0,0 +1,26 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +void fmpz_sparse_mat_from_entries(fmpz_sparse_mat_t M, slong * rows, slong * cols, fmpz * vals, slong nnz) +{ + slong r, i, j; + for (r = i = 0; r < M->r; ++r, i = j) + { + for (j = i; j < nnz && rows[j]==r; ++j); + fmpz_sparse_vec_from_entries(&M->rows[r], cols+i, vals+i, j-i); + } +} diff --git a/fmpz_sparse_mat/gram.c b/fmpz_sparse_mat/gram.c new file mode 100644 index 0000000000..2cbb39531a --- /dev/null +++ b/fmpz_sparse_mat/gram.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2014 Abhinav Baid + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +void fmpz_sparse_mat_gram(fmpz_mat_t B, const fmpz_sparse_mat_t M) +{ + slong i, j; + + if (M->r == 0) fmpz_mat_zero(B); + else + for (i = 0; i < M->r; i++) + for (j = 0; j < M->r; j++) + fmpz_sparse_vec_dot(&B->rows[i][j], &M->rows[i], &M->rows[j]); +} diff --git a/fmpz_sparse_mat/hnf_classical.c b/fmpz_sparse_mat/hnf_classical.c new file mode 100644 index 0000000000..d8acb15b07 --- /dev/null +++ b/fmpz_sparse_mat/hnf_classical.c @@ -0,0 +1,99 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "hashmap.h" +#include "fmpz_sparse_mat.h" + +slong +fmpz_sparse_mat_hnf_classical(fmpz_sparse_mat_t M) +{ + slong i, r, pr, pc, rank, remr, next_pr, nnz; + slong *P; /* Row permutation */ + slong *irows; /* Set of row incident on a given column */ + slong nnp, next_nnp; /* Number of such rows which are not previous pivots */ + slong npp; /* Number of such rows which are previous pivots */ + fmpz_sparse_mat_with_transpose_t MT; + hashmap_struct *hcol; + + if (M->r == 0 || M->c == 0) return 0; + + /* Construct virtual transpose */ + _fmpz_sparse_mat_with_transpose_init(MT, M); + + /* Set up permutation */ + P = flint_malloc(M->r*sizeof(*P)); + remr = M->r; + for (r = 0; r < M->r; ++r) + { + if (!M->rows[r].nnz) P[r] = --remr; + else P[r] = -1; + } + irows = flint_malloc(M->r * sizeof(*irows)); + + for (rank = pc = 0; pc < M->c; ++pc) + { + hcol = &MT->cols[pc]; nnz = hcol->num; + if (!nnz) continue; + pr = next_pr = -1, next_nnp = nnz, npp = 0; + + do + { + pr = next_pr, next_pr = -1; + nnp = next_nnp, next_nnp = 0; + for (i = 0; i < nnp; ++i) + { + r = (pr == -1) ? hcol->keys[i] : irows[i]; + if (pr >= 0) /* Reduce row r by row pr */ + { + if (_fmpz_sparse_mat_with_transpose_gauss_elim(MT, pr, r)) + { + if (M->rows[r].nnz == 0) P[r] = --remr; + continue; + } + } + else if (P[r] >= 0) /* Record incident previous pivot rows at end of irows */ + { + irows[hcol->num - (++npp)] = r; + continue; + } + + /* Either add r (back) to irows or make it the next pivot row */ + + if (next_pr >= 0 && fmpz_cmpabs(LT(M, r).val, LT(M, next_pr).val) >= 0) + { + irows[next_nnp++] = r; + continue; + } + if (next_pr >= 0) irows[next_nnp++] = next_pr; + next_pr = r; + } + if (pr != -1) irows[next_nnp++] = pr; + } while (next_pr != -1); /* Stop when no more reduction to be done */ + if (pr == -1) continue; /* No incident rows which are not previous pivots */ + + if (fmpz_sgn(LT(M, pr).val) < 0) + fmpz_sparse_vec_neg(&M->rows[pr], &M->rows[pr]); + + /* Now use row pr to reduce the previous pivot rows */ + for (i = nnz - npp; i < nnz; ++i) + _fmpz_sparse_mat_with_transpose_gauss_elim(MT, pr, irows[i]); + P[pr] = rank++; + } + + /* Apply row permutation */ + fmpz_sparse_mat_permute_rows (M, P); + + flint_free(P); + flint_free(irows); + _fmpz_sparse_mat_with_transpose_clear(MT); + return rank; +} diff --git a/fmpz_sparse_mat/hnf_minors.c b/fmpz_sparse_mat/hnf_minors.c new file mode 100644 index 0000000000..cec18c70a8 --- /dev/null +++ b/fmpz_sparse_mat/hnf_minors.c @@ -0,0 +1,126 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2017 Tommy Hofmann + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +/* + This is the algorithm of Kannan, Bachem, "Polynomial algorithms for computing + the Smith and Hermite normal forms of an integer matrix", Siam J. Comput., + Vol. 8, No. 4, pp. 499-507. +*/ +slong +fmpz_sparse_mat_hnf_minors(fmpz_sparse_mat_t M) +{ + + slong i, r, c, pr, pc, rank, remr, nnz; + slong *P; /* Row permutation */ + slong *Pr; /* Assignment of pivot row to each column */ + fmpz_sparse_mat_with_transpose_t MT; + hashmap_struct *hcol; /* Virtual L^t and one of its rows */ + fmpz_t g, a, b, one; + + if (M->r == 0 || M->c == 0) return 0; + fmpz_init(g); + fmpz_init(a); + fmpz_init(b); + fmpz_init_set_ui(one, UWORD(1)); + + /* Construct virtual transpose */ + _fmpz_sparse_mat_with_transpose_init(MT, M); + + /* Set up permutation and its "inverse" */ + P = flint_malloc(M->r*sizeof(*P)); + Pr = flint_malloc(M->c*sizeof(*Pr)); + remr = M->r; + for (r = 0; r < M->r; ++r) + { + if (!M->rows[r].nnz) P[r] = --remr; + else P[r] = -1; + } + + for (rank = pc = 0; pc < M->c; ++pc) + { + Pr[pc] = -1; + + /* Find first non-empty row which is not a previous pivot and eliminate cols up to pc */ + for (r = 0; r < M->r; ++r) + { + if (P[r] >= 0) continue; + + /* Reduce r by previous pivot rows */ + while ((c = M->rows[r].entries[0].ind) < pc) + { + _fmpz_sparse_mat_with_transpose_gauss_elim_ext(MT, Pr[c], r); + if (M->rows[r].nnz == 0) {P[r] = --remr; break;} + } + if (M->rows[r].nnz > 0 && M->rows[r].entries[0].ind == pc) break; + } + if (r == M->r) continue; /* No viable pivot for column */ + pr = r; + + if (fmpz_sgn(LT(M, r).val) < 0) + fmpz_sparse_vec_neg(&M->rows[r], &M->rows[r]); + + /* Use this row to reduce previous pivot rows */ + hcol = &MT->cols[pc]; nnz = hcol->num; + for (i = 0; i < nnz; ++i) + { + r = hcol->keys[i]; + if (r != pr && P[r] >= 0) + _fmpz_sparse_mat_with_transpose_gauss_elim(MT, pr, r); + } + Pr[pc] = pr; + P[pr] = rank++; + } + + /* Deal with any remaining rows */ + for (r = 0; r < M->r; ++r) + { + if (P[r] >= 0) continue; + + /* Reduce r by previous pivot rows */ + while ((c = M->rows[r].entries[0].ind) < M->c) + { + _fmpz_sparse_mat_with_transpose_gauss_elim_ext(MT, Pr[c], r); + if (M->rows[r].nnz == 0) {P[r] = --remr; break;} + } + } + + /* Since pivot rows were modified, need to re-reduce previous pivot rows */ + for (pc = 0; pc < M->c; ++pc) + { + if (Pr[pc] == -1) continue; /* No pivot for this column */ + pr = Pr[pc]; + hcol = &MT->cols[pc]; nnz = hcol->num; + for (i = 0; i < nnz; ++i) + { + r = hcol->keys[i]; + if (r == pr) continue; + + /* All other incident rows must be previous pivots */ + _fmpz_sparse_mat_with_transpose_gauss_elim(MT, pr, r); + } + } + + /* Apply row permutation */ + fmpz_sparse_mat_permute_rows (M, P); + + flint_free(P); + flint_free(Pr); + _fmpz_sparse_mat_with_transpose_clear(MT); + fmpz_clear(g); + fmpz_clear(a); + fmpz_clear(b); + fmpz_clear(one); + return rank; +} diff --git a/fmpz_sparse_mat/hnf_modular.c b/fmpz_sparse_mat/hnf_modular.c new file mode 100644 index 0000000000..c35acce450 --- /dev/null +++ b/fmpz_sparse_mat/hnf_modular.c @@ -0,0 +1,112 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +slong +fmpz_sparse_mat_hnf_modular(fmpz_sparse_mat_t M, const fmpz_t det) +{ + slong i, r, pr, pc, rank, remr, nnz; + slong *P; /* Row permutation */ + slong *irows; /* Set of rows incident on a given column */ + slong nnp; /* Number of such rows which are not previous pivots */ + slong npp; /* Number of such rows which are previous pivots */ + fmpz_sparse_mat_with_transpose_t MT; + hashmap_struct *hcol; /* Virtual L^t and one of its rows */ + fmpz_t g, a, b, one, rem_det; + + if (M->r == 0 || M->c == 0 || M->r != M->c || fmpz_is_zero(det)) return 0; + fmpz_init(g); + fmpz_init(a); + fmpz_init(b); + fmpz_init_set_ui(one, UWORD(1)); + fmpz_init_set(rem_det, det); + + /* Construct virtual transpose */ + _fmpz_sparse_mat_with_transpose_init(MT, M); + + /* Set up permutation */ + P = flint_malloc(M->r*sizeof(*P)); + remr = M->r; + for (r = 0; r < M->r; ++r) + { + if (!M->rows[r].nnz) P[r] = --remr; + else P[r] = -1; + } + + irows = NULL; + for (rank = pc = 0; pc < M->c; ++pc) + { + hcol = &MT->cols[pc]; nnz = hcol->num; + if (!nnz) continue; + irows = flint_realloc(irows, nnz*sizeof(*irows)); + pr = -1, nnp = 0, npp = 0; + + /* Find incident row pr which is not a previous pivot and has minimal leading term */ + /* Make pi_0 ... pi_{nnp-1} the other incident rows which are not previous pivots */ + /* and pi_{nnz-npp} ... pi_{nnz - 1} the incident rows which are previous pivots */ + for (i = 0; i < nnz; ++i) + { + r = hcol->keys[i]; + if (P[r] >= 0) + irows[hcol->num - (++npp)] = r; + else if (pr >= 0 && fmpz_cmpabs(LT(M, r).val, LT(M, pr).val) >= 0) + irows[nnp++] = r; + else + { + if (pr >= 0) irows[nnp++] = pr; + pr = r; + } + } + if (pr == -1) + { + /* Set pivot col in some non-pivot row to rem_det */ + for (pr = 0; pr < M->r; ++pr) + if (P[pr] == -1) break; + fmpz_sparse_vec_set_entry(&M->rows[pr], pc, rem_det); + fmpz_one(rem_det); + } + else + { + /* Eliminate non-pivot rows */ + for (i = 0; i < nnp; ++i) + _fmpz_sparse_mat_with_transpose_gauss_elim_ext_mods(MT, pr, irows[i], rem_det); + + /* Minimize row modulo rem_det */ + fmpz_xgcd(g, a, b, LT(M, pr).val, rem_det); + + MT_FIX(MT, pr, + fmpz_sparse_vec_scalar_mul_fmpz(&M->rows[pr], &M->rows[pr], a); + fmpz_sparse_vec_scalar_mods_fmpz(&M->rows[pr], &M->rows[pr], rem_det); + if (M->rows[pr].nnz == 0 || LT(M, pr).ind != pc) + fmpz_sparse_vec_set_entry(&M->rows[pr], pc, rem_det); + ); + + fmpz_divexact(rem_det, rem_det, g); + } + /* Reduce previous pivot rows */ + for (i = nnz - npp; i < nnz; ++i) + _fmpz_sparse_mat_with_transpose_gauss_elim(MT, pr, irows[i]); + P[pr] = rank++; + } + /* Apply row permutation */ + fmpz_sparse_mat_permute_rows (M, P); + + flint_free(P); + flint_free(irows); + fmpz_clear(a); + fmpz_clear(b); + fmpz_clear(one); + fmpz_clear(rem_det); + _fmpz_sparse_mat_with_transpose_clear(MT); + return M->r; +} diff --git a/fmpz_sparse_mat/hnf_modular_eldiv.c b/fmpz_sparse_mat/hnf_modular_eldiv.c new file mode 100644 index 0000000000..2a5e334672 --- /dev/null +++ b/fmpz_sparse_mat/hnf_modular_eldiv.c @@ -0,0 +1,41 @@ +/* + Copyright (C) 2015 Tommy Hofmann + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" +#include "nmod_sparse_mat.h" + +slong +fmpz_sparse_mat_hnf_modular_eldiv(fmpz_sparse_mat_t M, const fmpz_t n) +{ + slong i; + + if (fmpz_sparse_mat_is_zero(M)) return 0; + + if (fmpz_abs_fits_ui(n)) + { + /* TODO: have nmod version */ +/* nmod_init(&mod, fmpz_get_ui(n)); + nmod_sparse_mat_init(Mmod, M->r, M->c, mod); + fmpz_sparse_mat_get_nmod_sparse_mat(Mmod, M); + rank = nmod_sparse_mat_strong_echelon_form(Mmod); + fmpz_sparse_mat_set_nmod_sparse_mat_unsigned(M, Mmod); + nmod_sparse_mat_clear(Mmod); + */ } + + fmpz_sparse_mat_strong_echelon_form_mod(M, n); + + for (i = 0; i < M->r; ++i) + if (fmpz_sparse_vec_is_zero(&M->rows[i])) + fmpz_sparse_vec_set_entry(&M->rows[i], i, n); + return M->r; +} + diff --git a/fmpz_sparse_mat/hnf_pernet_stein.c b/fmpz_sparse_mat/hnf_pernet_stein.c new file mode 100644 index 0000000000..836052ac81 --- /dev/null +++ b/fmpz_sparse_mat/hnf_pernet_stein.c @@ -0,0 +1,638 @@ +/* + Copyright (C) 2014, 2015 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_mat.h" +#include "fmpq_mat.h" +#include "perm.h" + +#if 0 + +static void +add_columns(fmpz_mat_t H, const fmpz_mat_t B, const fmpz_mat_t H1, flint_rand_t state) +{ + int neg; + slong i, j, n, bits; + fmpz_t den, tmp, one; + fmpq_t num, alpha; + fmpz_mat_t Bu, B1, cols, k; + fmpq_mat_t H1_q, cols_q, x; + + n = B->r; + + fmpz_mat_init(Bu, n, n); + fmpz_mat_init(B1, n - 1, n); + fmpz_mat_init(cols, n, B->c - n); + fmpz_mat_init(k, n, 1); + fmpq_mat_init(x, n, B->c - n); + fmpq_mat_init(cols_q, n, B->c - n); + fmpq_mat_init(H1_q, n, n); + + for (i = 0; i < n; i++) + for (j = 0; j < cols->c; j++) + fmpz_set(fmpz_mat_entry(cols, i, j), fmpz_mat_entry(B, i, n + j)); + for (i = 0; i < n - 1; i++) + { + for (j = 0; j < n; j++) + { + fmpz_set(fmpz_mat_entry(Bu, i, j), fmpz_mat_entry(B, i, j)); + fmpz_set(fmpz_mat_entry(B1, i, j), fmpz_mat_entry(B, i, j)); + } + } + + /* find kernel basis vector */ + if (fmpz_mat_nullspace(k, B1) != 1) + { + flint_printf("Exception (fmpz_mat_hnf_pernet_stein). " + "Nullspace was not dimension one.\n"); + flint_abort(); + } + + bits = fmpz_mat_max_bits(B1); + if (bits < 0) + bits = -bits; + + fmpz_mat_clear(B1); + + fmpz_init(tmp); + + /* set the last row of Bu to be random, such that Bu is nonsingular */ + while (fmpz_is_zero(tmp)) + { + _fmpz_vec_randtest(Bu->rows[n - 1], state, n, bits); + + fmpz_zero(tmp); + for (j = 0; j < n; j++) + fmpz_addmul(tmp, fmpz_mat_entry(Bu, n - 1, j), + fmpz_mat_entry(k, j, 0)); + } + fmpz_clear(tmp); + + /* solve Bu*x = cols */ + if (!fmpq_mat_solve_fmpz_mat(x, Bu, cols)) + { + flint_printf("Exception (fmpz_mat_hnf_pernet_stein). " + "Singular input matrix for solve."); + flint_abort(); + } + + /* fix final row */ + fmpq_init(num); + fmpz_init(den); + fmpq_init(alpha); + fmpz_init(one); + fmpz_one(one); + + /* compute denominator */ + for (i = 0; i < n; i++) + fmpz_addmul(den, fmpz_mat_entry(B, n - 1, i), fmpz_mat_entry(k, i, 0)); + neg = (fmpz_sgn(den) < 0); + if (neg) + fmpz_neg(den, den); + + for (j = 0; j < B->c - H1->c; j++) + { + fmpq_zero(num); + for (i = 0; i < n; i++) + { + _fmpq_addmul(fmpq_numref(num), fmpq_denref(num), + fmpz_mat_entry(B, n - 1, i), one, + fmpq_mat_entry_num(x, i, j), + fmpq_mat_entry_den(x, i, j)); + } + _fmpq_sub(fmpq_numref(alpha), fmpq_denref(alpha), + fmpz_mat_entry(B, n - 1, n + j), one, + fmpq_numref(num), fmpq_denref(num)); + + _fmpq_mul(fmpq_numref(alpha), fmpq_denref(alpha), + fmpq_numref(alpha), fmpq_denref(alpha), one, den); + if (neg) + fmpq_neg(alpha, alpha); + + /* x_i += alpha*k */ + for (i = 0; i < n; i++) + { + _fmpq_addmul(fmpq_mat_entry_num(x, i, j), + fmpq_mat_entry_den(x, i, j), fmpq_numref(alpha), + fmpq_denref(alpha), fmpz_mat_entry(k, i, 0), one); + } + } + + fmpq_clear(num); + fmpz_clear(den); + fmpz_clear(one); + fmpq_clear(alpha); + + /* set cols = H1*x and place in position in H */ + fmpq_mat_set_fmpz_mat(H1_q, H1); + fmpq_mat_mul(cols_q, H1_q, x); + fmpq_mat_get_fmpz_mat(cols, cols_q); + for (i = 0; i < n; i++) + { + for (j = 0; j < n; j++) + fmpz_set(fmpz_mat_entry(H, i, j), fmpz_mat_entry(H1, i, j)); + for (j = n; j < H->c; j++) + fmpz_set(fmpz_mat_entry(H, i, j), fmpz_mat_entry(cols, i, j - n)); + } + + fmpq_mat_clear(H1_q); + fmpq_mat_clear(x); + fmpq_mat_clear(cols_q); + fmpz_mat_clear(k); + fmpz_mat_clear(cols); + fmpz_mat_clear(Bu); +} + +/* takes input matrix H with rows 0 to start_row - 1 in HNF to a HNF matrix */ +static void +add_rows(fmpz_mat_t H, slong start_row, slong *pivots, slong num_pivots) +{ + slong i, i2, j, j2, new_row, row; + fmpz_t b, d, u, v, r1d, r2d, q; + + fmpz_init(b); + fmpz_init(d); + fmpz_init(u); + fmpz_init(v); + fmpz_init(r1d); + fmpz_init(r2d); + fmpz_init(q); + + for (row = start_row; row < H->r; row++) + { + /* reduce row to be added with existing */ + for (i = j = 0; i < num_pivots; i++) + { + /* check if added row can still be reduced */ + for (; j < pivots[i]; j++) + if (!fmpz_is_zero(fmpz_mat_entry(H, row, j))) + break; + if (j < pivots[i]) + break; + if (fmpz_is_zero(fmpz_mat_entry(H, row, j))) + continue; + fmpz_xgcd(d, u, v, fmpz_mat_entry(H, i, j), + fmpz_mat_entry(H, row, j)); + fmpz_divexact(r1d, fmpz_mat_entry(H, i, j), d); + fmpz_divexact(r2d, fmpz_mat_entry(H, row, j), d); + for (j2 = j; j2 < H->c; j2++) + { + fmpz_mul(b, u, fmpz_mat_entry(H, i, j2)); + fmpz_addmul(b, v, fmpz_mat_entry(H, row, j2)); + fmpz_mul(fmpz_mat_entry(H, row, j2), r1d, + fmpz_mat_entry(H, row, j2)); + fmpz_submul(fmpz_mat_entry(H, row, j2), r2d, + fmpz_mat_entry(H, i, j2)); + fmpz_set(fmpz_mat_entry(H, i, j2), b); + } + } + + /* find first non-zero entry of the added row */ + for (j = 0; j < H->c && fmpz_is_zero(fmpz_mat_entry(H, row, j)); j++) ; + new_row = row; + if (j != H->c) /* last row non-zero, move to correct position */ + { + if (fmpz_sgn(fmpz_mat_entry(H, row, j)) < 0) + { + for (j2 = j; j2 < H->c; j2++) + { + fmpz_neg(fmpz_mat_entry(H, row, j2), + fmpz_mat_entry(H, row, j2)); + } + } + do + { + if (new_row < row) + fmpz_mat_swap_rows(H, NULL, new_row, new_row + 1); + if (new_row == 0) + break; + new_row--; + for (j2 = 0; j2 < H->c && + fmpz_is_zero(fmpz_mat_entry(H, new_row, j2)); j2++) ; + } + while (j2 > j); + } + + /* recompute pivots */ + for (i = new_row, j = 0; i <= row && i < H->c; i++, j++) + { + for (; j < H->c && fmpz_is_zero(fmpz_mat_entry(H, i, j)); j++) ; + if (j == H->c) + break; + pivots[i] = j; + num_pivots = i + 1; + } + + /* reduce above pivot entries */ + for (i = 0; i < num_pivots; i++) + { + for (i2 = 0; i2 < i; i2++) + { + fmpz_fdiv_q(q, fmpz_mat_entry(H, i2, pivots[i]), + fmpz_mat_entry(H, i, pivots[i])); + for (j2 = pivots[i]; j2 < H->c; j2++) + { + fmpz_submul(fmpz_mat_entry(H, i2, j2), q, + fmpz_mat_entry(H, i, j2)); + } + } + } + } + + fmpz_clear(q); + fmpz_clear(r2d); + fmpz_clear(r1d); + fmpz_clear(v); + fmpz_clear(u); + fmpz_clear(d); + fmpz_clear(b); +} + +static void +double_det(fmpz_t d1, fmpz_t d2, const fmpz_mat_t B, const fmpz_mat_t c, + const fmpz_mat_t d) +{ + slong i, j, n; + slong *P; + mp_limb_t p, u1mod, u2mod, v1mod, v2mod; + fmpz_t bound, prod, s1, s2, t, u1, u2, v1, v2; + fmpz_mat_t dt, Bt; + fmpq_t tmpq; + fmpq_mat_t x; + nmod_mat_t Btmod; + + n = B->c; + + fmpz_mat_init(dt, n, 1); + fmpz_mat_init(Bt, n, n); + fmpq_mat_init(x, n, 1); + + for (i = 0; i < n; i++) + { + for (j = 0; j < n - 1; j++) + fmpz_set(fmpz_mat_entry(Bt, i, j), fmpz_mat_entry(B, j, i)); + fmpz_set(fmpz_mat_entry(Bt, i, n - 1), fmpz_mat_entry(c, 0, i)); + } + + /* solve B^Tx = d^T */ + fmpz_mat_transpose(dt, d); + fmpq_mat_solve_fmpz_mat(x, Bt, dt); + + if (!fmpq_is_zero(fmpq_mat_entry(x, n - 1, 0))) + { + fmpz_init(bound); + fmpz_init(prod); + fmpz_init(t); + fmpz_init(s1); + fmpz_init(s2); + fmpz_init(u1); + fmpz_init(u2); + fmpz_init(v1); + fmpz_init(v2); + + /* compute lcm of denominators of vectors x and y */ + fmpq_init(tmpq); + fmpz_one(u1); + fmpz_one(u2); + for (i = 0; i < n - 1; i++) + { + fmpz_lcm(u1, u1, fmpq_mat_entry_den(x, i, 0)); + fmpq_div(tmpq, fmpq_mat_entry(x, i, 0), + fmpq_mat_entry(x, n - 1, 0)); + fmpz_lcm(u2, u2, fmpq_denref(tmpq)); + } + fmpz_lcm(u1, u1, fmpq_mat_entry_den(x, n - 1, 0)); + fmpq_inv(tmpq, fmpq_mat_entry(x, n - 1, 0)); + fmpz_lcm(u2, u2, fmpq_denref(tmpq)); + fmpq_clear(tmpq); + + /* compute Hadamard bounds */ + fmpz_one(bound); + for (j = 0; j < n - 1; j++) + { + fmpz_zero(s1); + for (i = 0; i < n; i++) + fmpz_addmul(s1, fmpz_mat_entry(Bt, i, j), + fmpz_mat_entry(Bt, i, j)); + fmpz_sqrtrem(s1, t, s1); + if (!fmpz_is_zero(t)) + fmpz_add_ui(s1, s1, UWORD(1)); + fmpz_mul(bound, bound, s1); + } + fmpz_zero(s1); + fmpz_zero(s2); + for (j = 0; j < n; j++) + { + fmpz_addmul(s1, fmpz_mat_entry(c, 0, j), fmpz_mat_entry(c, 0, j)); + fmpz_addmul(s2, fmpz_mat_entry(d, 0, j), fmpz_mat_entry(d, 0, j)); + } + fmpz_sqrtrem(s1, t, s1); + if (!fmpz_is_zero(t)) + fmpz_add_ui(s1, s1, UWORD(1)); + fmpz_sqrtrem(s2, t, s2); + if (!fmpz_is_zero(t)) + fmpz_add_ui(s2, s2, UWORD(1)); + fmpz_mul(s1, s1, bound); + fmpz_mul(s2, s2, bound); + fmpz_cdiv_q(s1, s1, u1); + fmpz_cdiv_q(s2, s2, u2); + if (fmpz_cmp(s1, s2) > 0) + fmpz_set(bound, s1); + else + fmpz_set(bound, s2); + fmpz_mul_ui(bound, bound, UWORD(2)); + + fmpz_one(prod); + P = _perm_init(n); + nmod_mat_init(Btmod, n, n, 2); + p = UWORD(1) << NMOD_MAT_OPTIMAL_MODULUS_BITS; + /* compute determinants divided by u1 and u2 */ + while (fmpz_cmp(prod, bound) <= 0) + { + p = n_nextprime(p, 0); + u1mod = fmpz_fdiv_ui(u1, p); + u2mod = fmpz_fdiv_ui(u2, p); + if (!(u1mod || u2mod)) + continue; + _nmod_mat_set_mod(Btmod, p); + for (i = 0; i < n; i++) + { + for (j = 0; j < n - 1; j++) + nmod_mat_entry(Btmod, i, j) = + fmpz_fdiv_ui(fmpz_mat_entry(B, j, i), p); + nmod_mat_entry(Btmod, i, n - 1) = + fmpz_fdiv_ui(fmpz_mat_entry(c, 0, i), p); + } + nmod_mat_lu(P, Btmod, 0); + v1mod = UWORD(1); + for (i = 0; i < n; i++) + v1mod = n_mulmod2_preinv(v1mod, nmod_mat_entry(Btmod, i, i), p, + Btmod->mod.ninv); + if (_perm_parity(P, n) == 1) + v1mod = nmod_neg(v1mod, Btmod->mod); + + for (i = 0; i < n; i++) + { + for (j = 0; j < n - 1; j++) + nmod_mat_entry(Btmod, i, j) = + fmpz_fdiv_ui(fmpz_mat_entry(B, j, i), p); + nmod_mat_entry(Btmod, i, n - 1) = + fmpz_fdiv_ui(fmpz_mat_entry(d, 0, i), p); + } + nmod_mat_lu(P, Btmod, 0); + v2mod = UWORD(1); + for (i = 0; i < n; i++) + v2mod = n_mulmod2_preinv(v2mod, nmod_mat_entry(Btmod, i, i), p, + Btmod->mod.ninv); + if (_perm_parity(P, n) == 1) + v2mod = nmod_neg(v2mod, Btmod->mod); + + v1mod = n_mulmod2_preinv(v1mod, n_invmod(u1mod, p), p, + Btmod->mod.ninv); + v2mod = n_mulmod2_preinv(v2mod, n_invmod(u2mod, p), p, + Btmod->mod.ninv); + fmpz_CRT_ui(v1, v1, prod, v1mod, p, 1); + fmpz_CRT_ui(v2, v2, prod, v2mod, p, 1); + fmpz_mul_ui(prod, prod, p); + } + + fmpz_mul(d1, u1, v1); + fmpz_mul(d2, u2, v2); + + fmpz_clear(bound); + fmpz_clear(prod); + fmpz_clear(s1); + fmpz_clear(s2); + fmpz_clear(u1); + fmpz_clear(u2); + fmpz_clear(v1); + fmpz_clear(v2); + fmpz_clear(t); + _perm_clear(P); + nmod_mat_clear(Btmod); + } + else /* can't use the clever method above so naively compute both dets */ + { + fmpz_mat_det(d1, Bt); + for (j = 0; j < n; j++) + fmpz_set(fmpz_mat_entry(Bt, j, n - 1), fmpz_mat_entry(d, 0, j)); + fmpz_mat_det(d2, Bt); + } + + fmpz_mat_clear(dt); + fmpz_mat_clear(Bt); + fmpq_mat_clear(x); +} + +void +fmpz_mat_hnf_pernet_stein(fmpz_mat_t H, const fmpz_mat_t A, flint_rand_t state) +{ + slong i, j, m, n, p, r, *P, *pivots, finished; + fmpz_t d1, d2, g, s, t; + fmpz_mat_t c, d, B, C, H1, H2, H3; + nmod_mat_t Amod; + + m = fmpz_mat_nrows(A); + n = fmpz_mat_ncols(A); + + if (m == 0 || n == 0) + return; + + /* find permutation so we can ensure first rows of H are nonsingular */ + P = _perm_init(m); + pivots = _perm_init(n); + + finished = 0; + + while (!finished) + { + p = n_randprime(state, NMOD_MAT_OPTIMAL_MODULUS_BITS, 1); + nmod_mat_init(Amod, m, n, p); + + fmpz_mat_get_nmod_mat(Amod, A); + r = _nmod_mat_rref(Amod, pivots, P); + + nmod_mat_clear(Amod); + + /* rank is zero so matrix is possibly zero too */ + if (r == 0) + { + if (fmpz_mat_is_zero(A)) + { + fmpz_mat_zero(H); + _perm_clear(P); + _perm_clear(pivots); + return; + } + continue; + } + + /* if A has full column rank we might wish to use minors based hnf */ + if (r == n && n < 52) + { + slong b = fmpz_mat_max_bits(A), cutoff = 52; + if (b < 0) + b = -b; + + if (b <= 8) + cutoff = 35; + else if (b <= 32) + cutoff = 44; + else if (b <= 256) + cutoff = 48; + + if (n < cutoff) + { + fmpz_mat_hnf_minors(H, A); + _perm_clear(P); + _perm_clear(pivots); + return; + } + } + + fmpz_mat_init(c, 1, r - 1); + fmpz_mat_init(d, 1, r - 1); + fmpz_mat_init(B, r - 2, r - 1); + fmpz_mat_init(C, r - 1, r - 1); + + for (i = 0; i < r - 2; i++) + { + for (j = 0; j < r - 1; j++) + { + fmpz_set(fmpz_mat_entry(B, i, j), + fmpz_mat_entry(A, P[i], pivots[j])); + fmpz_set(fmpz_mat_entry(C, i, j), + fmpz_mat_entry(A, P[i], pivots[j])); + } + fmpz_set(fmpz_mat_entry(C, i, r - 1), + fmpz_mat_entry(A, P[i], pivots[r - 1])); + } + for (j = 0; j < r - 1; j++) + { + fmpz_set(fmpz_mat_entry(c, 0, j), + fmpz_mat_entry(A, P[r - 2], pivots[j])); + fmpz_set(fmpz_mat_entry(d, 0, j), + fmpz_mat_entry(A, P[r - 1], pivots[j])); + } + + fmpz_init(g); + fmpz_init(s); + fmpz_init(t); + + /* if rank is too low leave g = 0 so we don't try to decompose later */ + if (r > 2) + { + fmpz_init(d1); + fmpz_init(d2); + + double_det(d1, d2, B, c, d); + fmpz_xgcd(g, s, t, d1, d2); + + for (j = 0; j < r - 1; j++) + { + fmpz_mul(fmpz_mat_entry(C, r - 2, j), s, + fmpz_mat_entry(A, P[r - 2], pivots[j])); + fmpz_addmul(fmpz_mat_entry(C, r - 2, j), t, + fmpz_mat_entry(A, P[r - 1], pivots[j])); + } + + fmpz_clear(d2); + fmpz_clear(d1); + } + + if (!fmpz_is_zero(g)) /* chosen matrix invertible */ + { + fmpz_mat_init(H1, r - 1, r - 1); + + if (COEFF_IS_MPZ(*g) && C->r > 3) /* if g is too big, recurse */ + fmpz_mat_hnf_pernet_stein(H1, C, state); + else /* use modulo determinant algorithm to compute HNF of C */ + fmpz_mat_hnf_modular(H1, C, g); + + fmpz_mat_clear(B); + fmpz_mat_init(B, r - 1, n); + + for (j = 0; j < n; j++) + { + for (i = 0; i < r - 2; i++) + fmpz_set(fmpz_mat_entry(B, i, j), + fmpz_mat_entry(A, P[i], pivots[j])); + fmpz_mul(fmpz_mat_entry(B, r - 2, j), s, + fmpz_mat_entry(A, P[r - 2], pivots[j])); + fmpz_addmul(fmpz_mat_entry(B, r - 2, j), t, + fmpz_mat_entry(A, P[r - 1], pivots[j])); + } + + fmpz_mat_init(H2, r - 1, n); + fmpz_mat_init(H3, m + 1, n); + + add_columns(H2, B, H1, state); + + for (i = 0; i < r - 1; i++) + for (j = 0; j < n; j++) + fmpz_set(fmpz_mat_entry(H3, i, pivots[j]), + fmpz_mat_entry(H2, i, j)); + + for (i = 1; i <= m - r + 2; i++) + for (j = 0; j < n; j++) + fmpz_set(fmpz_mat_entry(H3, H3->r - i, j), + fmpz_mat_entry(A, P[m - i], j)); + + /* check the pivots of H3 are as expected */ + for (i = 0; i < r - 1; i++) + { + for (j = 0; j < H3->c && fmpz_is_zero(fmpz_mat_entry(H3, i, j)); j++); + if (pivots[i] != j) + break; + } + + /* the pivots were as expected so our choice of prime was ok */ + if (i == r - 1) + { + /* add final rows in */ + add_rows(H3, r - 1, pivots, r - 1); + + /* fill H with HNF */ + for (i = 0; i < m; i++) + for (j = 0; j < n; j++) + fmpz_set(fmpz_mat_entry(H, i, j), fmpz_mat_entry(H3, i, j)); + + finished = 1; + } + /* otherwise we must restart as our random prime gave us incorrect pivots */ + + fmpz_mat_clear(H1); + fmpz_mat_clear(H2); + fmpz_mat_clear(H3); + } + else + { + if (r == n) /* if A has full column rank we can use minors based hnf */ + fmpz_mat_hnf_minors(H, A); + else + fmpz_mat_hnf_classical(H, A); + finished = 1; + } + + fmpz_clear(t); + fmpz_clear(s); + fmpz_clear(g); + fmpz_mat_clear(C); + fmpz_mat_clear(B); + fmpz_mat_clear(c); + fmpz_mat_clear(d); + } + + _perm_clear(P); + _perm_clear(pivots); +} + +#endif \ No newline at end of file diff --git a/fmpz_sparse_mat/hnf_xgcd.c b/fmpz_sparse_mat/hnf_xgcd.c new file mode 100644 index 0000000000..7d765057fb --- /dev/null +++ b/fmpz_sparse_mat/hnf_xgcd.c @@ -0,0 +1,93 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +slong fmpz_sparse_mat_hnf_xgcd(fmpz_sparse_mat_t M) +{ + slong i, r, pr, pc, rank, remr, nnz; + slong *P; /* Row permutation */ + slong *irows; /* Set of rows incident on a given column */ + slong nnp; /* Number of rows which are not pivots */ + slong npp; /* Number of rows which are previous pivots */ + fmpz_sparse_mat_with_transpose_t MT; + hashmap_struct *hcol; /* Virtual L^t and one of its rows */ + fmpz_t g, a, b, one; + + if (M->r == 0 || M->c == 0) return 0; + fmpz_init(g); + fmpz_init(a); + fmpz_init(b); + fmpz_init_set_ui(one, UWORD(1)); + + /* Construct virtual transpose */ + _fmpz_sparse_mat_with_transpose_init(MT, M); + + /* Set up permutation */ + P = flint_malloc(M->r*sizeof(*P)); + remr = M->r; + for (r = 0; r < M->r; ++r) + { + if (!M->rows[r].nnz) P[r] = --remr; + else P[r] = -1; + } + irows = flint_malloc(M->r * sizeof(*irows)); + + for (rank = pc = 0; pc < M->c; ++pc) + { + hcol = &MT->cols[pc]; nnz = hcol->num; + if (!nnz) continue; + pr = -1, nnp = 0, npp = 0; + + for (i = 0; i < nnz; ++i) + { + r = hcol->keys[i]; + if (P[r] >= 0) /* Put previous pivot rows at end of irows */ + irows[hcol->num - (++npp)] = r; + else if (pr >= 0 && fmpz_cmpabs(LT(M, r).val, LT(M, pr).val) >= 0) + irows[nnp++] = r; /* Put non-pivot rows with larger entries at beginning of irows */ + else /* Replace the pivot row with the current row */ + { + if (pr >= 0) irows[nnp++] = pr; + pr = r; + } + } + if (pr == -1) continue; + + /* Eliminate larger, non-pivot rows */ + for (i = 0; i < nnp; ++i) + { + r = irows[i]; + _fmpz_sparse_mat_with_transpose_gauss_elim_ext(MT, pr, r); + if (M->rows[r].nnz == 0) P[r] = --remr; + } + + if (fmpz_sgn(LT(M, pr).val) < 0) + fmpz_sparse_vec_neg(&M->rows[pr], &M->rows[pr]); + + /* Reduce previous pivot rows incident to pivot column */ + for (i = nnz - npp; i < nnz; ++i) + _fmpz_sparse_mat_with_transpose_gauss_elim(MT, pr, irows[i]); + P[pr] = rank++; + } + + /* Apply row permutation */ + fmpz_sparse_mat_permute_rows (M, P); + + flint_free(P); + flint_free(irows); + fmpz_clear(a); + fmpz_clear(b); + fmpz_clear(one); + _fmpz_sparse_mat_with_transpose_clear(MT); + return rank; +} diff --git a/fmpz_sparse_mat/howell_form_mod.c b/fmpz_sparse_mat/howell_form_mod.c new file mode 100644 index 0000000000..e07c84a7ad --- /dev/null +++ b/fmpz_sparse_mat/howell_form_mod.c @@ -0,0 +1,34 @@ +/* + Copyright (C) 2015 Tommy Hofmann + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +slong +fmpz_sparse_mat_howell_form_mod(fmpz_sparse_mat_t M, const fmpz_t mod) +{ + slong i, *P, rank = 0, remr = M->r; + + if (fmpz_sparse_mat_is_zero(M)) return 0; + + fmpz_sparse_mat_strong_echelon_form_mod(M, mod); + P = flint_malloc(M->r*sizeof(*P)); + for (i = 0; i < M->r; ++i) + { + if (M->rows[i].nnz > 0) P[i] = rank++; + else P[i] = --remr; + } + /* Apply row permutation */ + fmpz_sparse_mat_permute_rows (M, P); + flint_free(P); + return rank; +} + diff --git a/fmpz_sparse_mat/is_in_hnf.c b/fmpz_sparse_mat/is_in_hnf.c new file mode 100644 index 0000000000..9caa46df77 --- /dev/null +++ b/fmpz_sparse_mat/is_in_hnf.c @@ -0,0 +1,43 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +int fmpz_sparse_mat_is_in_hnf(const fmpz_sparse_mat_t A) +{ + slong pr, rk, pc, prev_pc, r; + fmpz_t *ptr; + + /* Compute the rank (assuming HNF form) */ + for (rk = A->r; rk != 0; rk--) + { + if (!fmpz_sparse_vec_is_zero(&A->rows[rk - 1]) && LT(A, rk - 1).ind < A->c) break; + } + + /* Check that first rk rows are in HNF */ + prev_pc = -1; + for (pr = 0; pr < rk; pr++) + { + if (fmpz_sparse_vec_is_zero(&A->rows[pr])) return 0; + pc = LT(A, pr).ind; + if (pc >= A->c || pc <= prev_pc || fmpz_sgn(LT(A, pr).val) < 0) return 0; + + for (r = 0; r < pr; r++) + { + ptr = fmpz_sparse_vec_at(&A->rows[r], pc); + if (ptr && ((fmpz_sgn(*ptr) < 0) || (fmpz_cmp(*ptr, LT(A, pr).val) >= 0))) return 0; + } + prev_pc = pc; + } + + return 1; +} diff --git a/fmpz_sparse_mat/max_bits.c b/fmpz_sparse_mat/max_bits.c new file mode 100644 index 0000000000..d5337efa80 --- /dev/null +++ b/fmpz_sparse_mat/max_bits.c @@ -0,0 +1,39 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" +#include "hashmap.h" +#include "longlong.h" + +slong fmpz_sparse_mat_max_bits(const fmpz_sparse_mat_t M) +{ + slong i; + slong bits, row_bits, sign; + + sign = 1; + bits = 0; + + if (M->r == 0 || M->c == 0) + return 0; + + for (i = 0; i < M->r; i++) + { + row_bits = fmpz_sparse_vec_max_bits(&M->rows[i]); + if (row_bits < 0) + { + row_bits = -row_bits; + sign = -1; + } + bits = FLINT_MAX(bits, row_bits); + } + return bits * sign; +} \ No newline at end of file diff --git a/fmpz_sparse_mat/multi_CRT_ui.c b/fmpz_sparse_mat/multi_CRT_ui.c new file mode 100644 index 0000000000..ee8bfdbdcf --- /dev/null +++ b/fmpz_sparse_mat/multi_CRT_ui.c @@ -0,0 +1,55 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_multi_CRT_ui_precomp(fmpz_sparse_mat_t M, + nmod_sparse_mat_struct * residues, slong nres, + const fmpz_comb_t comb, fmpz_comb_temp_t temp, int sign) +{ + slong i, j; + nmod_sparse_vec_struct *vres; + + vres = flint_malloc(nres * sizeof(*vres)); + + for (i = 0; i < M->r; i++) + { + for (j = 0; j < nres; ++j) vres[j] = residues[j].rows[i]; + fmpz_sparse_vec_multi_CRT_ui_precomp(&M->rows[i], vres, nres, comb, temp, sign); + } + flint_free(vres); +} + +void +fmpz_sparse_mat_multi_CRT_ui(fmpz_sparse_mat_t mat, nmod_sparse_mat_struct * residues, slong nres, int sign) +{ + slong i; + mp_limb_t *primes; + fmpz_comb_t comb; + fmpz_comb_temp_t temp; + + for(i = 0; i < nres; ++i) { + FLINT_ASSERT(mat->r == residues[i].r); + } + + primes = flint_malloc(nres * sizeof(*primes)); + for (i = 0; i < nres; i++) primes[i] = residues[i].mod.n; + fmpz_comb_init(comb, primes, nres); + fmpz_comb_temp_init(temp, comb); + + fmpz_sparse_mat_multi_CRT_ui_precomp(mat, residues, nres, comb, temp, sign); + + fmpz_comb_clear(comb); + fmpz_comb_temp_clear(temp); + flint_free(primes); +} diff --git a/fmpz_sparse_mat/multi_mod_ui.c b/fmpz_sparse_mat/multi_mod_ui.c new file mode 100644 index 0000000000..28aa8ec705 --- /dev/null +++ b/fmpz_sparse_mat/multi_mod_ui.c @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +/* for (j = 0; j < fmpz_mat_ncols(mat); j++) + { + fmpz_multi_mod_ui(r, fmpz_mat_entry(mat, i, j), comb, temp); + for (k = 0; k < nres; k++) + nmod_mat_entry(residues[k], i, j) = r[k]; + } + */ +void +fmpz_sparse_mat_multi_mod_ui_precomp(nmod_sparse_mat_struct * residues, slong nres, const fmpz_sparse_mat_t M, + const fmpz_comb_t comb, fmpz_comb_temp_t temp) +{ + slong i, j; + nmod_sparse_vec_struct *vres; + + vres = flint_malloc(nres * sizeof(*vres)); + + for (i = 0; i < M->r; i++) + { + for (j = 0; j < nres; ++j) vres[j] = residues[j].rows[i]; + fmpz_sparse_vec_multi_mod_ui_precomp(vres, nres, &M->rows[i], comb, temp); + for (j = 0; j < nres; ++j) residues[j].rows[i] = vres[j]; + + } + flint_free(vres); +} + +void +fmpz_sparse_mat_multi_mod_ui(nmod_sparse_mat_struct * residues, slong nres, const fmpz_sparse_mat_t M) +{ + slong i; + for(i = 0; i < nres; ++i) { + FLINT_ASSERT(mat->r == residues[i].r); + } + mp_limb_t *primes; + fmpz_comb_t comb; + fmpz_comb_temp_t temp; + + primes = flint_malloc(nres * sizeof(*primes)); + for (i = 0; i < nres; i++) primes[i] = residues[i].mod.n; + fmpz_comb_init(comb, primes, nres); + fmpz_comb_temp_init(temp, comb); + + fmpz_sparse_mat_multi_mod_ui_precomp(residues, nres, M, comb, temp); + + fmpz_comb_clear(comb); + fmpz_comb_temp_clear(temp); + flint_free(primes); +} diff --git a/fmpz_sparse_mat/print_pretty.c b/fmpz_sparse_mat/print_pretty.c new file mode 100644 index 0000000000..a2c4dcfd07 --- /dev/null +++ b/fmpz_sparse_mat/print_pretty.c @@ -0,0 +1,33 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_print_pretty(const fmpz_sparse_mat_t M) +{ + slong i; + char row_fmt[FLINT_BITS + 5]; + flint_sprintf(row_fmt, "%%%dwd: ", n_sizeinbase(M->r, 10)); + + flint_printf("<%wd x %wd sparse integer matrix>\n", + M->r, M->c); + + for (i = 0; i < M->r; i++) + { + flint_printf(row_fmt, i); + fmpz_sparse_vec_print_pretty(&M->rows[i], M->c_off, M->c); + } +} diff --git a/fmpz_sparse_mat/randtest.c b/fmpz_sparse_mat/randtest.c new file mode 100644 index 0000000000..1c7a184925 --- /dev/null +++ b/fmpz_sparse_mat/randtest.c @@ -0,0 +1,30 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_randtest(fmpz_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz, flint_bitcnt_t bits) +{ + slong i, nnz; + + for (i = 0; i < M->r; ++i) + { + nnz = n_randint(state, max_nnz+1); + nnz = FLINT_MAX(nnz, min_nnz); + fmpz_sparse_vec_randtest(&M->rows[i], state, nnz, M->c, bits); + } +} + diff --git a/fmpz_sparse_mat/randtest_unsigned.c b/fmpz_sparse_mat/randtest_unsigned.c new file mode 100644 index 0000000000..06fdb1d90d --- /dev/null +++ b/fmpz_sparse_mat/randtest_unsigned.c @@ -0,0 +1,30 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_randtest_unsigned(fmpz_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz, flint_bitcnt_t bits) +{ + slong i, nnz; + + for (i = 0; i < M->r; ++i) + { + nnz = n_randint(state, max_nnz+1); + nnz = FLINT_MAX(nnz, min_nnz); + fmpz_sparse_vec_randtest_unsigned(&M->rows[i], state, nnz, M->c, bits); + } +} + diff --git a/fmpz_sparse_mat/snf.c b/fmpz_sparse_mat/snf.c new file mode 100644 index 0000000000..f87b4e3d45 --- /dev/null +++ b/fmpz_sparse_mat/snf.c @@ -0,0 +1,51 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_mat.h" + +void +fmpz_sparse_mat_snf(fmpz_mat_t S, const fmpz_mat_t A) +{ + fmpz_t det; + slong m = A->r, n = A->c, b = fmpz_mat_max_bits(A), cutoff = 9; + + if (b <= 2) + cutoff = 15; + else if (b <= 4) + cutoff = 13; + else if (b <= 8) + cutoff = 13; + else if (b <= 16) + cutoff = 11; + else if (b <= 32) + cutoff = 11; + else if (b <= 64) + cutoff = 10; + + if (FLINT_MAX(m, n) < cutoff || m != n) + fmpz_mat_snf_kannan_bachem(S, A); + else + { + fmpz_init(det); + fmpz_mat_det(det, A); + if (!fmpz_is_zero(det)) + { + fmpz_abs(det, det); + fmpz_mat_snf_iliopoulos(S, A, det); + } + else + { + fmpz_mat_snf_kannan_bachem(S, A); + } + fmpz_clear(det); + } +} diff --git a/fmpz_sparse_mat/snf_diagonal.c b/fmpz_sparse_mat/snf_diagonal.c new file mode 100644 index 0000000000..b4e3dc2703 --- /dev/null +++ b/fmpz_sparse_mat/snf_diagonal.c @@ -0,0 +1,43 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_mat.h" + +/* sets a to gcd(a,b) and b to lcm(a,b) using temporary fmpz_t t */ +static void _gcdlcm(fmpz_t t, fmpz_t a, fmpz_t b) +{ + if (fmpz_equal(a, b)) return; + fmpz_gcd(t, a, b); + fmpz_divexact(b, b, t); + fmpz_mul(b, b, a); + fmpz_set(a, t); +} + +void fmpz_sparse_mat_snf_diagonal(fmpz_mat_t S, const fmpz_mat_t A) +{ + fmpz_t t; + slong i, j, n = FLINT_MIN(A->r, A->c); + + fmpz_init(t); + fmpz_mat_set(S, A); + for (i = 0; i < n; i++) + fmpz_abs(fmpz_mat_entry(S, i, i), fmpz_mat_entry(S, i, i)); + for (j = n - 1; j >= 0; j--) + { + for (i = 0; i < j; i++) + { + _gcdlcm(t, fmpz_mat_entry(S, i, i), + fmpz_mat_entry(S, i + 1, i + 1)); + } + } + fmpz_clear(t); +} diff --git a/fmpz_sparse_mat/snf_iliopoulos.c b/fmpz_sparse_mat/snf_iliopoulos.c new file mode 100644 index 0000000000..64abb62250 --- /dev/null +++ b/fmpz_sparse_mat/snf_iliopoulos.c @@ -0,0 +1,238 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_mat.h" + +static void _eliminate_col(fmpz_mat_t S, slong i, const fmpz_t mod) +{ + slong j, k, m, n; + fmpz * t; + fmpz_t b, g, u, v, r1g, r2g; + + m = S->r; + n = S->c; + + if (i == m - 1) + { + fmpz_gcd(fmpz_mat_entry(S, i, i), fmpz_mat_entry(S, i, i), mod); + return; + } + + fmpz_init(g); + fmpz_init(u); + fmpz_init(b); + fmpz_init(r1g); + fmpz_init(r2g); + + if (!fmpz_is_zero(fmpz_mat_entry(S, i, i))) + { + fmpz_init(v); + + fmpz_xgcd(g, u, v, fmpz_mat_entry(S, i + 1, i), + fmpz_mat_entry(S, i, i)); + fmpz_divexact(r1g, fmpz_mat_entry(S, i + 1, i), g); + fmpz_divexact(r2g, fmpz_mat_entry(S, i, i), g); + for (j = i; j < n; j++) + { + fmpz_mul(b, u, fmpz_mat_entry(S, i + 1, j)); + fmpz_addmul(b, v, fmpz_mat_entry(S, i, j)); + fmpz_mul(fmpz_mat_entry(S, i, j), r1g, + fmpz_mat_entry(S, i, j)); + fmpz_submul(fmpz_mat_entry(S, i, j), r2g, + fmpz_mat_entry(S, i + 1, j)); + fmpz_set(fmpz_mat_entry(S, i + 1, j), b); + } + + fmpz_clear(v); + } + + /* compute extended gcd of entries in column i */ + t = _fmpz_vec_init(m - i - 1); + + fmpz_set(g, fmpz_mat_entry(S, i + 1, i)); + fmpz_one(t); + for (j = 2; j < m - i; j++) + { + fmpz_xgcd(g, u, t + j - 1, g, fmpz_mat_entry(S, i + j, i)); + for (k = 0; k < j - 1; k++) + fmpz_mul(t + k, t + k, u); + } + + /* set row i to have gcd in col i */ + for (k = i + 1; k < m; k++) + { + fmpz_mod(t + k - i - 1, t + k - i - 1, mod); + for (j = i; j < n; j++) + fmpz_addmul(fmpz_mat_entry(S, i, j), t + k - i - 1, + fmpz_mat_entry(S, k, j)); + } + + _fmpz_vec_clear(t, m - i - 1); + + /* reduce each row k with row i */ + if (!fmpz_is_zero(g)) /* if g = 0 then don't need to reduce */ + { + for (k = i + 1; k < m; k++) + { + fmpz_divexact(r1g, fmpz_mat_entry(S, k, i), g); + fmpz_neg(r1g, r1g); + for (j = i; j < n; j++) + fmpz_addmul(fmpz_mat_entry(S, k, j), r1g, + fmpz_mat_entry(S, i, j)); + } + for (k = i + 1; k < m; k++) + fmpz_mod(fmpz_mat_entry(S, k, i), fmpz_mat_entry(S, k, i), mod); + } + for (j = i; j < m; j++) + for (k = i + 1; k < n; k++) + fmpz_fdiv_r(fmpz_mat_entry(S, j, k), fmpz_mat_entry(S, j, k), mod); + fmpz_gcd(fmpz_mat_entry(S, i, i), fmpz_mat_entry(S, i, i), mod); + + fmpz_clear(b); + fmpz_clear(g); + fmpz_clear(u); + fmpz_clear(r1g); + fmpz_clear(r2g); +} + +static void _eliminate_row(fmpz_mat_t S, slong i, const fmpz_t mod) +{ + slong j, k, m, n; + fmpz * t; + fmpz_t b, g, u, v, r1g, r2g, halfmod; + + m = S->r; + n = S->c; + + if (i == n - 1) + { + fmpz_gcd(fmpz_mat_entry(S, i, i), fmpz_mat_entry(S, i, i), mod); + return; + } + + fmpz_init(g); + fmpz_init(u); + fmpz_init(b); + fmpz_init(r1g); + fmpz_init(r2g); + fmpz_init(halfmod); + fmpz_fdiv_q_2exp(halfmod, mod, 1); + + if (!fmpz_is_zero(fmpz_mat_entry(S, i, i))) + { + fmpz_init(v); + + fmpz_xgcd(g, u, v, fmpz_mat_entry(S, i, i + 1), + fmpz_mat_entry(S, i, i)); + fmpz_divexact(r1g, fmpz_mat_entry(S, i, i + 1), g); + fmpz_divexact(r2g, fmpz_mat_entry(S, i, i), g); + for (j = i; j < m; j++) + { + fmpz_mul(b, u, fmpz_mat_entry(S, j, i + 1)); + fmpz_addmul(b, v, fmpz_mat_entry(S, j, i)); + fmpz_mul(fmpz_mat_entry(S, j, i), r1g, + fmpz_mat_entry(S, j, i)); + fmpz_submul(fmpz_mat_entry(S, j, i), r2g, + fmpz_mat_entry(S, j, i + 1)); + fmpz_set(fmpz_mat_entry(S, j, i + 1), b); + } + + fmpz_clear(v); + } + + /* compute extended gcd of entries in row i */ + t = _fmpz_vec_init(n - i - 1); + + fmpz_set(g, fmpz_mat_entry(S, i, i + 1)); + fmpz_one(t); + for (j = 2; j < n - i; j++) + { + fmpz_xgcd(g, u, t + j - 1, g, fmpz_mat_entry(S, i, i + j)); + for (k = 0; k < j - 1; k++) + fmpz_mul(t + k, t + k, u); + } + + /* reduce col i to have gcd in row i */ + for (k = i + 1; k < n; k++) + { + fmpz_mod(t + k - i - 1, t + k - i - 1, mod); + for (j = i; j < m; j++) + fmpz_addmul(fmpz_mat_entry(S, j, i), t + k - i - 1, + fmpz_mat_entry(S, j, k)); + } + + _fmpz_vec_clear(t, n - i - 1); + + /* reduce each col k with col i */ + if (!fmpz_is_zero(g)) /* if g = 0 then don't need to reduce */ + { + for (k = i + 1; k < n; k++) + { + fmpz_divexact(r1g, fmpz_mat_entry(S, i, k), g); + fmpz_neg(r1g, r1g); + for (j = i; j < m; j++) + fmpz_addmul(fmpz_mat_entry(S, j, k), r1g, + fmpz_mat_entry(S, j, i)); + } + } + for (j = i + 1; j < m; j++) + for (k = i; k < n; k++) + fmpz_fdiv_r(fmpz_mat_entry(S, j, k), fmpz_mat_entry(S, j, k), mod); + fmpz_gcd(fmpz_mat_entry(S, i, i), fmpz_mat_entry(S, i, i), mod); + + fmpz_clear(b); + fmpz_clear(g); + fmpz_clear(u); + fmpz_clear(r1g); + fmpz_clear(r2g); + fmpz_clear(halfmod); +} + +void fmpz_sparse_mat_snf_iliopoulos(fmpz_mat_t S, const fmpz_mat_t A, const fmpz_t mod) +{ + slong i, k, n; + int done; + + n = FLINT_MIN(A->c, A->r); + + fmpz_mat_set(S, A); + + for (i = 0; i < A->r; i++) + for (k = 0; k < A->c; k++) + fmpz_mod(fmpz_mat_entry(S, i, k), fmpz_mat_entry(S, i, k), mod); + + for (k = 0; k != n; k++) + { + do + { + _eliminate_row(S, k, mod); + _eliminate_col(S, k, mod); + done = 1; + if (fmpz_is_zero(fmpz_mat_entry(S, k, k))) + { + for (i = k + 1; i < A->c && done; i++) + done = fmpz_is_zero(fmpz_mat_entry(S, k, i)); + } + else + { + for (i = k + 1; i < A->c && done; i++) + done = fmpz_divisible(fmpz_mat_entry(S, k, i), + fmpz_mat_entry(S, k, k)); + } + } + while (!done); + for (i = k + 1; i < A->c; i++) + fmpz_zero(fmpz_mat_entry(S, k, i)); + } + + fmpz_mat_snf_diagonal(S, S); +} diff --git a/fmpz_sparse_mat/snf_kannan_bachem.c b/fmpz_sparse_mat/snf_kannan_bachem.c new file mode 100644 index 0000000000..9851416d07 --- /dev/null +++ b/fmpz_sparse_mat/snf_kannan_bachem.c @@ -0,0 +1,138 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_mat.h" + +void fmpz_sparse_mat_snf_kannan_bachem(fmpz_mat_t S, const fmpz_mat_t A) +{ + slong i, j, k, d, m, n; + fmpz_t r1g, r2g, b, u, v, g; + m = A->r; + n = A->c; + d = FLINT_MIN(m, n); + fmpz_init(r1g); + fmpz_init(r2g); + fmpz_init(b); + fmpz_init(u); + fmpz_init(v); + fmpz_init(g); + + fmpz_mat_set(S, A); + + for (k = 0; k != d; k++) + { + int col_done; + do + { + /* clear column */ + for (i = k + 1; i != m; i++) + { + /* reduce row i - 1 with row i */ + if (fmpz_is_zero(fmpz_mat_entry(S, i - 1, k))) + continue; + if (fmpz_cmpabs(fmpz_mat_entry(S, i, k), + fmpz_mat_entry(S, i - 1, k)) == 0) + { + if (fmpz_equal(fmpz_mat_entry(S, i, k), + fmpz_mat_entry(S, i - 1, k))) + { + for (j = k; j != n; j++) + fmpz_sub(fmpz_mat_entry(S, i - 1, j), + fmpz_mat_entry(S, i - 1, j), + fmpz_mat_entry(S, i, j)); + } + else + { + for (j = k; j != n; j++) + fmpz_add(fmpz_mat_entry(S, i - 1, j), + fmpz_mat_entry(S, i - 1, j), + fmpz_mat_entry(S, i, j)); + } + continue; + } + fmpz_xgcd(g, u, v, fmpz_mat_entry(S, i, k), + fmpz_mat_entry(S, i - 1, k)); + fmpz_divexact(r2g, fmpz_mat_entry(S, i - 1, k), g); + fmpz_divexact(r1g, fmpz_mat_entry(S, i, k), g); + for (j = k; j != n; j++) + { + fmpz_mul(b, u, fmpz_mat_entry(S, i, j)); + fmpz_addmul(b, v, fmpz_mat_entry(S, i - 1, j)); + fmpz_mul(fmpz_mat_entry(S, i - 1, j), r1g, + fmpz_mat_entry(S, i - 1, j)); + fmpz_submul(fmpz_mat_entry(S, i - 1, j), r2g, + fmpz_mat_entry(S, i, j)); + fmpz_set(fmpz_mat_entry(S, i, j), b); + } + } + fmpz_mat_swap_rows(S, NULL, m - 1, k); + + /* clear row */ + for (j = k + 1; j != n; j++) + { + /* reduce col j with col k */ + if (fmpz_is_zero(fmpz_mat_entry(S, k, j))) + continue; + if (fmpz_cmpabs(fmpz_mat_entry(S, k, k), + fmpz_mat_entry(S, k, j)) == 0) + { + if (fmpz_equal(fmpz_mat_entry(S, k, k), + fmpz_mat_entry(S, k, j))) + { + for (i = k; i != m; i++) + fmpz_sub(fmpz_mat_entry(S, i, j), + fmpz_mat_entry(S, i, j), + fmpz_mat_entry(S, i, k)); + } + else + { + for (i = k; i != m; i++) + fmpz_add(fmpz_mat_entry(S, i, j), + fmpz_mat_entry(S, i, j), + fmpz_mat_entry(S, i, k)); + } + continue; + } + fmpz_xgcd(g, u, v, fmpz_mat_entry(S, k, k), + fmpz_mat_entry(S, k, j)); + fmpz_divexact(r2g, fmpz_mat_entry(S, k, j), g); + fmpz_divexact(r1g, fmpz_mat_entry(S, k, k), g); + for (i = k; i != m; i++) + { + fmpz_mul(b, u, fmpz_mat_entry(S, i, k)); + fmpz_addmul(b, v, fmpz_mat_entry(S, i, j)); + fmpz_mul(fmpz_mat_entry(S, i, j), r1g, + fmpz_mat_entry(S, i, j)); + fmpz_submul(fmpz_mat_entry(S, i, j), r2g, + fmpz_mat_entry(S, i, k)); + fmpz_set(fmpz_mat_entry(S, i, k), b); + } + } + col_done = 1; + for (i = 0; i != m; i++) + col_done &= (i == k) || fmpz_is_zero(fmpz_mat_entry(S, i, k)); + } + while (!col_done); + + if (fmpz_sgn(fmpz_mat_entry(S, k, k)) < 0) + fmpz_neg(fmpz_mat_entry(S, k, k), fmpz_mat_entry(S, k, k)); + } + + fmpz_clear(r2g); + fmpz_clear(r1g); + fmpz_clear(b); + fmpz_clear(u); + fmpz_clear(v); + fmpz_clear(g); + + fmpz_mat_snf_diagonal(S, S); +} diff --git a/fmpz_sparse_mat/solve_bound.c b/fmpz_sparse_mat/solve_bound.c new file mode 100644 index 0000000000..cec4ae9b34 --- /dev/null +++ b/fmpz_sparse_mat/solve_bound.c @@ -0,0 +1,47 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_solve_bound(fmpz_t N, fmpz_t D, + const fmpz_sparse_mat_t A, const fmpz_mat_t B) +{ + slong i, j; + fmpz_t t, u; + + /* Get product of row norms of A */ + fmpz_sparse_mat_det_bound(D, A); + + fmpz_init(t); + fmpz_init(u); + + fmpz_zero(t); + + /* Get largest column norm of B */ + for (j = 0; j < B->c; j++) + { + fmpz_zero(u); + for (i = 0; i < A->r; i++) + fmpz_addmul(u, fmpz_mat_entry(B, i, j), fmpz_mat_entry(B, i, j)); + if (fmpz_cmp(t, u) < 0) + fmpz_set(t, u); + } + fmpz_sqrtrem(t, u, t); + if (!fmpz_is_zero(u)) + fmpz_add_ui(t, t, UWORD(1)); + + fmpz_mul(N, D, t); + + fmpz_clear(t); + fmpz_clear(u); +} diff --git a/fmpz_sparse_mat/solve_dixon.c b/fmpz_sparse_mat/solve_dixon.c new file mode 100644 index 0000000000..8532d6a54d --- /dev/null +++ b/fmpz_sparse_mat/solve_dixon.c @@ -0,0 +1,236 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpq_mat.h" +#include "fmpz_sparse_mat.h" + +static mp_limb_t find_good_prime_and_invert(nmod_sparse_mat_t Ainv, const fmpz_sparse_mat_t A, const fmpz_t D) +{ + nmod_t nmod; + slong rk = 0; + mp_limb_t p; + fmpz_t prod; + fmpz_init(prod); + + /* Find a prime to use for Hensel lifting, i.e., one modulo which A is invertible */ + p = n_nextprime(UWORD(1) << NMOD_MAT_OPTIMAL_MODULUS_BITS, 0); + for (fmpz_one(prod); fmpz_cmp(prod, D) <= 0; fmpz_mul_ui(prod, prod, p), p = n_nextprime(p, 0)) + { + nmod_init(&nmod, p); + nmod_sparse_mat_init(Ainv, A->r, A->r, nmod); + fmpz_sparse_mat_get_nmod_sparse_mat(Ainv, A); + rk = nmod_sparse_mat_inv(Ainv, Ainv); + if (rk == A->r) break; + nmod_sparse_mat_clear(Ainv); + } + if (rk != A->r) p = 0; /* Failed to invert matrix modulo prime == probably not invertible */ + fmpz_clear(prod); + return p; +} + +static nmod_sparse_mat_struct * get_mod_mats(slong *num_primes, const fmpz_sparse_mat_t A, mp_limb_t p) +{ + slong np; + nmod_t nmod; + fmpz_t prod, bound; + nmod_sparse_mat_struct *A_mod; + fmpz_init(prod); + + /* Get bound on product of primes needed to recover Ay via CRT */ + fmpz_init_set_ui(bound, p); /* size of y */ + fmpz_mul_2exp(bound, bound, FLINT_ABS(fmpz_sparse_mat_max_bits(A))+1); /* Size of A + sign */ + fmpz_mul_ui(bound, bound, A->r); /* Entries in dot product */ + + np = fmpz_bits(bound) / (FLINT_BIT_COUNT(p) - 1) + 2; /* Overestimate */ + A_mod = flint_malloc(np * sizeof(*A_mod)); + np = 0; + for (fmpz_one(prod); fmpz_cmp(prod, bound) < 0; fmpz_mul_ui(prod, prod, p), p = n_nextprime(p, 0)) + { + nmod_init(&nmod, p); + nmod_sparse_mat_init(&A_mod[np], A->r, A->r, nmod); + fmpz_sparse_mat_get_nmod_sparse_mat(&A_mod[np++], A); + } + fmpz_clear(prod); + fmpz_clear(bound); + *num_primes = np; + return flint_realloc(A_mod, np*sizeof(*A_mod)); +} + +int +_fmpq_mat_check_solution_fmpz_sparse_mat(const fmpq_mat_t X, const fmpz_sparse_mat_t A, const fmpz_mat_t B) +{ + slong i, j; + fmpz_mat_t Xclear, AXclear; + fmpz_t t; + fmpz * Xden; + int ok; + + Xden = _fmpz_vec_init(X->c); + fmpz_mat_init(Xclear, X->r, X->c); + fmpz_mat_init(AXclear, X->r, X->c); + fmpz_init(t); + + fmpq_mat_get_fmpz_mat_colwise(Xclear, Xden, X); + fmpz_sparse_mat_mul_mat(AXclear, A, Xclear); + + ok = 1; + for (i = 0; i < B->r && ok; i++) + { + for (j = 0; j < B->c && ok; j++) + { + /* AXclear[i,j] / Xden[j] = B[i,j] */ + fmpz_mul(t, fmpz_mat_entry(B, i, j), Xden + j); + + if (!fmpz_equal(t, fmpz_mat_entry(AXclear, i, j))) + ok = 0; + } + } + + _fmpz_vec_clear(Xden, X->c); + fmpz_mat_clear(Xclear); + fmpz_mat_clear(AXclear); + fmpz_clear(t); + + return ok; +} + +int _fmpz_sparse_mat_solve_dixon(fmpz_mat_t X, fmpz_t mod, const fmpz_sparse_mat_t A, const fmpz_mat_t B, int rat_sol) +{ + slong i, j, jcheck, num_primes; + mp_limb_t p; + fmpz_t N, D, bound, prod; + nmod_sparse_mat_struct *A_mod; + nmod_sparse_mat_t Ainv; + nmod_mat_t d_mod, y_mod, Ay_mod; + fmpz_mat_t d, y, Ay; + fmpq_mat_t Q; + + if (A->r != A->c) + { + flint_printf("Exception (fmpz_sparse_mat_solve_dixon). Non-square system matrix.\n"); + flint_abort(); + } + + if (A->r == 0 || A->c == 0 || B->c == 0) return 1; + if (fmpz_sparse_mat_is_zero(A)) return 0; + + fmpz_init(N); + fmpz_init(D); + fmpz_sparse_mat_solve_bound(N, D, A, B); + p = find_good_prime_and_invert(Ainv, A, D); + if (p == 0) + { + fmpz_clear(N); + fmpz_clear(D); + return 0; + } + + /* Get collection of primes ~ p and construct A mod each */ + A_mod = get_mod_mats(&num_primes, A, p); + + /* Get bound on modulus for Hensel lift */ + fmpz_init(bound); + if (fmpz_cmpabs(N, D) < 0) + fmpz_mul(bound, D, D); + else + fmpz_mul(bound, N, N); + fmpz_mul_ui(bound, bound, UWORD(2)); /* signs */ + + fmpz_mat_init(d, A->r, B->c); + fmpz_mat_init(y, A->r, B->c); + fmpz_mat_init(Ay, A->r, B->c); + nmod_mat_init(d_mod, A->r, B->c, p); + nmod_mat_init(y_mod, A->r, B->c, p); + nmod_mat_init(Ay_mod, A->r, B->c, p); + if (rat_sol) fmpq_mat_init(Q, A->r, B->c); + + /* Initialize X to y = A^-1 b mod p */ + fmpz_init(prod); + fmpz_mat_set(d, B); + fmpz_mat_get_nmod_mat(d_mod, d); + nmod_sparse_mat_mul_mat(y_mod, Ainv, d_mod); + fmpz_mat_set_nmod_mat_unsigned(X, y_mod); + j = jcheck = 1; + for (fmpz_set_ui(mod, p); fmpz_cmp(mod, bound) <= 0; fmpz_mul_ui(mod, mod, p)) + { + if (rat_sol && j == jcheck) + { + if (fmpq_mat_set_fmpz_mat_mod_fmpz(Q, X, mod) && _fmpq_mat_check_solution_fmpz_sparse_mat(Q, A, B)) + break; + jcheck = (slong)(j*1.4) + 1; /* Set when to check next */ + + } + /* Construct Ay via CRT */ + for (i = 0; i < num_primes; i++) + { + _nmod_mat_set_mod(y_mod, A_mod[i].mod.n); + _nmod_mat_set_mod(Ay_mod, A_mod[i].mod.n); + nmod_sparse_mat_mul_mat(Ay_mod, &A_mod[i], y_mod); + if (i == 0) + { + fmpz_mat_set_nmod_mat(Ay, Ay_mod); + fmpz_set_ui(prod, p); + } + else + { + fmpz_mat_CRT_ui(Ay, Ay, prod, Ay_mod, 1); + fmpz_mul_ui(prod, prod, A_mod[i].mod.n); + } + } + /* fmpz_mat_set_nmod_mat_unsigned(y, y_mod); + fmpz_mat_mul(Ay, A, y); */ + + /* Update d = (d - Ay) / p */ + fmpz_mat_sub(d, d, Ay); + fmpz_mat_scalar_divexact_ui(d, d, p); + fmpz_mat_get_nmod_mat(d_mod, d); + + /* Update x = x + (A^(-1) * d mod p) * p^i [= A^(-1) * b mod p^(i+1)] */ + _nmod_mat_set_mod(y_mod, p); + nmod_sparse_mat_mul_mat(y_mod, Ainv, d_mod); + fmpz_mat_scalar_addmul_nmod_mat_fmpz(X, y_mod, mod); + } + if (rat_sol) + { + if (fmpz_cmp(mod, bound) > 0) fmpq_mat_set_fmpz_mat_mod_fmpz(Q, X, mod); + fmpq_mat_get_fmpz_mat_matwise(X, mod, Q); + fmpq_mat_clear(Q); + } + + nmod_mat_clear(d_mod); + nmod_mat_clear(y_mod); + nmod_mat_clear(Ay_mod); + fmpz_mat_clear(d); + fmpz_mat_clear(y); + fmpz_mat_clear(Ay); + + for (i = 0; i < num_primes; i++) nmod_sparse_mat_clear(&A_mod[i]); + flint_free(A_mod); + + fmpz_clear(bound); + fmpz_clear(prod); + + nmod_sparse_mat_clear(Ainv); + fmpz_clear(N); + fmpz_clear(D); + return 1; +} + +int fmpz_sparse_mat_solve_dixon(fmpz_mat_t X, fmpz_t mod, const fmpz_sparse_mat_t A, const fmpz_mat_t B) +{ + return _fmpz_sparse_mat_solve_dixon(X, mod, A, B, 0); +} + +int fmpz_sparse_mat_solve_dixon_den(fmpz_mat_t X, fmpz_t den, const fmpz_sparse_mat_t A, const fmpz_mat_t B) +{ + return _fmpz_sparse_mat_solve_dixon(X, den, A, B, 1); +} diff --git a/fmpz_sparse_mat/strong_echelon_form_mod.c b/fmpz_sparse_mat/strong_echelon_form_mod.c new file mode 100644 index 0000000000..9c8bba8449 --- /dev/null +++ b/fmpz_sparse_mat/strong_echelon_form_mod.c @@ -0,0 +1,191 @@ +/* + Copyright (C) 2015 Tommy Hofmann + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" + + + + +/* Multiply by unit to minimize leading term (to a factor of N) */ +static void scale_row(fmpz_sparse_mat_with_transpose_t MT, slong r, const fmpz_t mod) +{ + fmpz_t g, a, b, n; + if (!fmpz_is_one(LT(MT->M, r).val)) + { + fmpz_init(g); + fmpz_init(a); + fmpz_init(b); + fmpz_xgcd(g, a, b, LT(MT->M, r).val, mod); + if (!fmpz_is_one(g)) /* Need to lift a = (M[pr][pc]/g)^-1 mod N/g to a unit modulo N */ + { + fmpz_divexact(b, mod, g); + fmpz_init_set(n, mod); + while (!fmpz_is_one(g)) + { + fmpz_gcd(g, a, n); + fmpz_divexact(n, n, g); + } + fmpz_addmul(a, n, b); + fmpz_mod(a, a, mod); + fmpz_clear(n); + } + MT_FIX(MT, r, + fmpz_sparse_vec_scalar_mul_fmpz(&MT->M->rows[r], &MT->M->rows[r], a); + fmpz_sparse_vec_scalar_mod_fmpz(&MT->M->rows[r], &MT->M->rows[r], mod); + ); + fmpz_clear(g); + fmpz_clear(a); + fmpz_clear(b); + } +} + +slong +fmpz_sparse_mat_strong_echelon_form_mod(fmpz_sparse_mat_t M, const fmpz_t mod) +{ + slong i, r, c, pr, pc, rank, remr, nzrows; + slong *P; /* Row permutation */ + slong *Pr; /* Map from column to associated pivot row */ + slong *irows; /* Set of rows incident on a given column */ + slong *zrows; /* Set of empty rows */ + slong nnp; /* Number of such rows which are not pivots */ + slong npp; /* Number of such rows which are not pivots */ + fmpz_sparse_mat_with_transpose_t MT; + hashmap_struct *hcol; /* Virtual L^t and one of its rows */ + fmpz_t q, zero; + fmpz_sparse_vec_t zero_vec; + + if (fmpz_sparse_mat_is_zero(M)) return 0; + fmpz_init(zero); + fmpz_init(q); + + /* Final object must have at least as many rows as columns */ + fmpz_sparse_vec_init(zero_vec); + while (M->r < M->c) fmpz_sparse_mat_append_row(M, zero_vec); + + /* Need extra row to deal with final elimination */ + fmpz_sparse_mat_append_row(M, zero_vec); + + /* Initialize data structure to hold copy of incident rows of a given column */ + irows = flint_malloc(M->r*sizeof(*irows)); + zrows = flint_malloc(M->r*sizeof(*zrows)); + + fmpz_sparse_mat_scalar_mod_fmpz(M, M, mod); + + /* Set up permutation */ + P = flint_malloc(M->r*sizeof(*P)); + remr = M->r, nzrows = 0; + for (r = 0; r < M->r; ++r) + { + if (!M->rows[r].nnz) P[r] = --remr, zrows[nzrows++] = r; + else P[r] = -1; + } + + /* Set up pivot row mapping */ + Pr = flint_malloc(M->c*sizeof(*Pr)); + for (c = 0; c < M->c; ++c) + Pr[c] = -1; + + /* Construct virtual transpose */ + _fmpz_sparse_mat_with_transpose_init(MT, M); + + for (pc = 0; pc < M->c; ++pc) + { + hcol = &MT->cols[pc]; + if (!hcol->num) continue; + pr = -1, nnp = 0; + + /* Find incident row pr which is not a previous pivot and has minimal leading term */ + /* Make pi_0 ... pi_{nnp-1} the other incident rows which are not previous pivots */ + for (i = 0; i < hcol->num; ++i) + { + r = hcol->keys[i]; + if (P[r] >= 0) continue; + else if (pr >= 0 && fmpz_cmpabs(LT(M, r).val, LT(M, pr).val) >= 0) + irows[nnp++] = r; + else + { + if (pr >= 0) irows[nnp++] = pr; + pr = r; + } + } + if (pr == -1) continue; /* Cannot perform elimination on this column (yet) */ + scale_row(MT, pr, mod); + Pr[pc] = pr, P[pr] = pc; + + /* Eliminate non-pivot rows */ + for (i = 0; i < nnp; ++i) + { + r = irows[i]; + _fmpz_sparse_mat_with_transpose_gauss_elim_ext_mod(MT, pr, r, mod); + if (M->rows[r].nnz == 0) P[r] = --remr, zrows[nzrows++] = r; + } + } + + /* Reduce upwards, and deal with non-unit leading terms */ + for (pc = 0; pc < M->c; pc++) + { + if (Pr[pc] == -1) {P[zrows[--nzrows]] = pc; continue;} /* No pivot for this column */ + hcol = &MT->cols[pc]; + pr = Pr[pc]; + + /* Reduce previous pivot rows */ + for (i = npp = 0; i < hcol->num; ++i) + if (hcol->keys[i] != pr) + irows[npp++] = hcol->keys[i]; + for (i = 0; i < npp; ++i) + { + _fmpz_sparse_mat_with_transpose_gauss_elim_mod(MT, pr, irows[i], mod); + } + if (fmpz_is_one(LT(M, pr).val)) continue; + + /* Obtain (possibly) new basis element by scalar multiplicition */ + r = zrows[--nzrows]; + fmpz_divexact(q, mod, LT(M, pr).val); + MT_FIX(MT, r, + fmpz_sparse_vec_scalar_mul_fmpz(&M->rows[r], &M->rows[pr], q); + fmpz_sparse_vec_scalar_mod_fmpz(&M->rows[r], &M->rows[r], mod); + ); + + while (!fmpz_sparse_vec_is_zero(&M->rows[r])) + { + c = M->rows[r].entries[0].ind; + /* If no previous pivot row exists, use this row */ + if (Pr[c] == -1) + { + scale_row(MT, r, mod); + Pr[c] = r; P[r] = c; + break; + } + + /* Otherwise, eliminate c using existing pivot */ + _fmpz_sparse_mat_with_transpose_gauss_elim_ext_mod(MT, Pr[c], r, mod); + if (!fmpz_sparse_vec_is_zero(&M->rows[r]) && LT(M, r).ind == c) flint_abort(); + } + /* If row fully eliminated, add back to empty stock */ + + if (fmpz_sparse_vec_is_zero(&M->rows[r])) nzrows++; + + } + fmpz_sparse_mat_permute_rows(M, P); + fmpz_clear(zero); + fmpz_clear(q); + flint_free(irows); + flint_free(zrows); + fmpz_sparse_vec_clear(zero_vec); + M->r -= 1; + M->rows = realloc(M->rows, M->r*sizeof(*M->rows)); + _fmpz_sparse_mat_with_transpose_clear(MT); + flint_free(P); + flint_free(Pr); + return rank; +} + diff --git a/fmpz_sparse_mat/test/t-CRT_ui.c b/fmpz_sparse_mat/test/t-CRT_ui.c new file mode 100644 index 0000000000..daf3662893 --- /dev/null +++ b/fmpz_sparse_mat/test/t-CRT_ui.c @@ -0,0 +1,87 @@ +/* + Copyright (C) 2007 William Hart and David Harvey + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" +#include "nmod_sparse_mat.h" + +int +main(void) +{ + slong rep, r, c, min_nnz, max_nnz, bits, prime_bits, num_primes, j, nreps = 1000; + mp_limb_t primes[1000]; + nmod_t nmod; + fmpz_t mod; + nmod_sparse_mat_t Amod; + fmpz_sparse_mat_t A, B; + FLINT_TEST_INIT(state); + + flint_printf("CRT_ui...."); + fflush(stdout); + + + for (rep = 0; rep < nreps; rep++) + { + bits = n_randint(state, 500) + 2; + r = n_randint(state, 10); + c = n_randint(state, 10); + min_nnz = 0; + max_nnz = c; + prime_bits = 1 + n_randint(state, FLINT_BITS - 1); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + + fmpz_sparse_mat_randtest(A, state, min_nnz, max_nnz, bits); + + fmpz_init_set_ui(mod, UWORD(1)); + for (num_primes = 0; fmpz_bits(mod) <= bits + 1; num_primes++) + { + primes[num_primes] = n_nextprime((num_primes == 0) ? (UWORD(1) << prime_bits) : primes[num_primes - 1], 0); + nmod_init(&nmod, primes[num_primes]); + nmod_sparse_mat_init(Amod, r, c, nmod); + fmpz_sparse_mat_get_nmod_sparse_mat(Amod, A); + if (num_primes == 0) + fmpz_sparse_mat_set_nmod_sparse_mat(B, Amod); + else + fmpz_sparse_mat_CRT_ui(B, B, mod, Amod, 1); + fmpz_mul_ui(mod, mod, primes[num_primes]); + nmod_sparse_mat_clear(Amod); + } + if (!fmpz_sparse_mat_equal(B, A)) + { + flint_printf("FAIL!\n"); + flint_printf("primes: "); + for (j = 0; j < num_primes; j++) + flint_printf("%wu ", primes[j]); + flint_printf("\nA: \n"); + fmpz_sparse_mat_print_pretty(A); + flint_printf("\nB: \n"); + fmpz_sparse_mat_print_pretty(B); + flint_printf("\n"); + abort(); + } + + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_clear(mod); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-CRT_ui_unsigned.c b/fmpz_sparse_mat/test/t-CRT_ui_unsigned.c new file mode 100644 index 0000000000..66339a71b0 --- /dev/null +++ b/fmpz_sparse_mat/test/t-CRT_ui_unsigned.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2007 William Hart and David Harvey + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" +#include "nmod_sparse_mat.h" + +int +main(void) +{ + slong rep, r, c, min_nnz, max_nnz, bits, prime_bits, num_primes, j, nreps = 1000; + mp_limb_t primes[1000]; + nmod_t nmod; + fmpz_t mod; + nmod_sparse_mat_t Amod; + fmpz_sparse_mat_t A, B; + FLINT_TEST_INIT(state); + + flint_printf("CRT_ui_unsigned...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + bits = n_randint(state, 500) + 1; + r = n_randint(state, 10); + c = n_randint(state, 10); + min_nnz = 0; + max_nnz = c; + prime_bits = 1 + n_randint(state, FLINT_BITS - 1); + + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + + fmpz_sparse_mat_randtest_unsigned(A, state, min_nnz, max_nnz, bits); + + fmpz_init_set_ui(mod, UWORD(1)); + for (num_primes = 0; fmpz_bits(mod) <= bits; num_primes++) + { + primes[num_primes] = n_nextprime((num_primes == 0) ? (UWORD(1) << prime_bits) : primes[num_primes - 1], 0); + nmod_init(&nmod, primes[num_primes]); + nmod_sparse_mat_init(Amod, r, c, nmod); + fmpz_sparse_mat_get_nmod_sparse_mat(Amod, A); + if (num_primes == 0) + fmpz_sparse_mat_set_nmod_sparse_mat_unsigned(B, Amod); + else + fmpz_sparse_mat_CRT_ui(B, B, mod, Amod, 0); + fmpz_mul_ui(mod, mod, primes[num_primes]); + nmod_sparse_mat_clear(Amod); + } + + if (!fmpz_sparse_mat_equal(B, A)) + { + flint_printf("FAIL!\n"); + flint_printf("primes: "); + for (j = 0; j < num_primes; j++) + flint_printf("%wu ", primes[j]); + flint_printf("\nA: \n"); + fmpz_sparse_mat_print_pretty(A); + flint_printf("\nB: \n"); + fmpz_sparse_mat_print_pretty(B); + flint_printf("\n"); + abort(); + } + + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_clear(mod); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-add.c b/fmpz_sparse_mat/test/t-add.c new file mode 100644 index 0000000000..4640382989 --- /dev/null +++ b/fmpz_sparse_mat/test/t-add.c @@ -0,0 +1,62 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, bits, r, c; + fmpz_sparse_mat_t A, B, C, D; + FLINT_TEST_INIT(state); + + flint_printf("add/sub...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + r = n_randint(state, 200); + c = n_randint(state, 200); + + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + fmpz_sparse_mat_init(C, r, c); + fmpz_sparse_mat_init(D, r, c); + + fmpz_sparse_mat_randtest(A, state, 0, c, bits); + fmpz_sparse_mat_randtest(B, state, 0, c, bits); + + fmpz_sparse_mat_add(C, A, B); + fmpz_sparse_mat_sub(D, C, B); + + if (!fmpz_sparse_mat_equal(D, A)) + { + flint_printf("FAIL\n"); + abort(); + } + + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_sparse_mat_clear(C); + fmpz_sparse_mat_clear(D); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-concat_horizontal.c b/fmpz_sparse_mat/test/t-concat_horizontal.c new file mode 100644 index 0000000000..e57ad8973d --- /dev/null +++ b/fmpz_sparse_mat/test/t-concat_horizontal.c @@ -0,0 +1,102 @@ +/* + + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int main(void) +{ + slong rep, bits, r, c1, c2, nreps = 100; + fmpz_sparse_mat_t A, B, C; + fmpz_sparse_mat_t window1, window2; + FLINT_TEST_INIT(state); + + flint_printf("concat_horizontal...."); + fflush(stdout); + + + for (rep = 0; rep < nreps; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + r = n_randint(state, 20); + c1 = n_randint(state, 20); + c2 = n_randint(state, 20); + fmpz_sparse_mat_init(A, r, c1); + fmpz_sparse_mat_init(B, r, c2); + fmpz_sparse_mat_init(C, r, c1+c2); + + fmpz_sparse_mat_randtest(A, state, 0, c1, bits); + fmpz_sparse_mat_randtest(B, state, 0, c2, bits); + fmpz_sparse_mat_randtest(C, state, 0, c1+c2, bits); + + fmpz_sparse_mat_concat_horizontal(C, A, B); + + fmpz_sparse_mat_window_init(window1, C, 0, 0, r, c1); + fmpz_sparse_mat_window_init(window2, C, 0, c1, r, c1+c2); + + if (!fmpz_sparse_mat_equal(window1, A) || !fmpz_sparse_mat_equal(window2, B)) + { + flint_printf("A = \n"); + fmpz_sparse_mat_print_pretty(A); + flint_printf("B = \n"); + fmpz_sparse_mat_print_pretty(B); + flint_printf("A | B = \n"); + fmpz_sparse_mat_print_pretty(C); + flint_printf("window1 = \n"); + fmpz_sparse_mat_print_pretty(window1); + flint_printf("window2 = \n"); + fmpz_sparse_mat_print_pretty(window2); + flint_printf("FAIL: window 2 not equal\n"); + abort(); + } + + fmpz_sparse_mat_window_clear(window1); + fmpz_sparse_mat_window_clear(window2); + + fmpz_sparse_mat_init(window1, r, c1); + fmpz_sparse_mat_init(window2, r, c2); + fmpz_sparse_mat_split_horizontal(window1, window2, C, c1); + + if (!(fmpz_sparse_mat_equal(window1, A) && fmpz_sparse_mat_equal(window2, B))) + { + flint_printf("A = \n"); + fmpz_sparse_mat_print_pretty(A); + flint_printf("B = \n"); + fmpz_sparse_mat_print_pretty(B); + flint_printf("A | B = \n"); + fmpz_sparse_mat_print_pretty(C); + flint_printf("window1 = \n"); + fmpz_sparse_mat_print_pretty(window1); + flint_printf("window2 = \n"); + fmpz_sparse_mat_print_pretty(window2); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + fmpz_sparse_mat_clear(window1); + fmpz_sparse_mat_clear(window2); + + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_sparse_mat_clear(C); + } + + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-concat_vertical.c b/fmpz_sparse_mat/test/t-concat_vertical.c new file mode 100644 index 0000000000..0bda166c21 --- /dev/null +++ b/fmpz_sparse_mat/test/t-concat_vertical.c @@ -0,0 +1,94 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int main(void) +{ + slong rep, bits, r1, r2, c, nreps = 100; + fmpz_sparse_mat_t A, B, C; + fmpz_sparse_mat_t window1, window2; + FLINT_TEST_INIT(state); + + + flint_printf("concat_vertical...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + r1 = n_randint(state, 100); + r2 = n_randint(state, 100); + c = n_randint(state, 100); + fmpz_sparse_mat_init(A, r1, c); + fmpz_sparse_mat_init(B, r2, c); + fmpz_sparse_mat_init(C, r1+r2, c); + + fmpz_sparse_mat_randtest(A, state, 0, c, bits); + fmpz_sparse_mat_randtest(B, state, 0, c, bits); + fmpz_sparse_mat_randtest(C, state, 0, c, bits); + + fmpz_sparse_mat_concat_vertical(C, A, B); + + fmpz_sparse_mat_window_init(window1, C, 0, 0, r1, c); + fmpz_sparse_mat_window_init(window2, C, r1, 0, r1+r2, c); + + if (!(fmpz_sparse_mat_equal(window1, A) && fmpz_sparse_mat_equal(window2, B))) + { + flint_printf("A = \n"); + fmpz_sparse_mat_print_pretty(A); + flint_printf("B = \n"); + fmpz_sparse_mat_print_pretty(B); + flint_printf("A concat_vertical B = \n"); + fmpz_sparse_mat_print_pretty(C); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + fmpz_sparse_mat_window_clear(window1); + fmpz_sparse_mat_window_clear(window2); + + fmpz_sparse_mat_init(window1, r1, c); + fmpz_sparse_mat_init(window2, r2, c); + fmpz_sparse_mat_split_vertical(window1, window2, C, r1); + + if (!fmpz_sparse_mat_equal(window1, A) || !fmpz_sparse_mat_equal(window2, B)) + { + flint_printf("A = \n"); + fmpz_sparse_mat_print_pretty(A); + flint_printf("B = \n"); + fmpz_sparse_mat_print_pretty(B); + flint_printf("A concat_vertical B = \n"); + fmpz_sparse_mat_print_pretty(C); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + fmpz_sparse_mat_clear(window1); + fmpz_sparse_mat_clear(window2); + + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_sparse_mat_clear(C); + } + + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-construct.c b/fmpz_sparse_mat/test/t-construct.c new file mode 100644 index 0000000000..ba9014abb9 --- /dev/null +++ b/fmpz_sparse_mat/test/t-construct.c @@ -0,0 +1,94 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, bits, r, c, i, j, k, nnz; + fmpz_sparse_mat_t A, B, C; + slong *rows; + slong *cols; + fmpz *vals; + FLINT_TEST_INIT(state); + + flint_printf("construction from entries...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 100); + while (bits < UWORD(2)); + r = 1; /*n_randint(state, 10);*/ + c = n_randint(state, 10); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + fmpz_sparse_mat_init(C, 0, c); + + fmpz_sparse_mat_randtest(A, state, 0, c, bits); + fmpz_sparse_mat_randtest(B, state, 0, c, bits); + nnz = 0; + for (i = 0; i < r; ++i) nnz += A->rows[i].nnz; + + /* Construct B from entries of A */ + rows = flint_malloc(nnz * sizeof(*rows)); + cols = flint_malloc(nnz * sizeof(*cols)); + vals = _fmpz_vec_init(nnz); + for (i = k = 0; i < r; ++i) + { + for (j = 0; j < A->rows[i].nnz; ++j, ++k) + { + rows[k] = i; + cols[k] = A->rows[i].entries[j].ind; + fmpz_set(&vals[k], A->rows[i].entries[j].val); + } + } + fmpz_sparse_mat_from_entries(B, rows, cols, vals, nnz); + + if (!fmpz_sparse_mat_equal(A, B)) + { + flint_printf("FAIL: A != B\n"); + flint_printf("A = "); + fmpz_sparse_mat_print_pretty(A); + flint_printf("B = "); + fmpz_sparse_mat_print_pretty(B); + abort(); + } + + for (i = 0; i < r; ++i) fmpz_sparse_mat_append_row(C, &A->rows[i]); + if (!fmpz_sparse_mat_equal(A, C)) + { + flint_printf("FAIL: A != C\n"); + flint_printf("A = "); + fmpz_sparse_mat_print_pretty(A); + flint_printf("C = "); + fmpz_sparse_mat_print_pretty(C); + abort(); + } + flint_free(rows); + flint_free(cols); + _fmpz_vec_clear(vals, nnz); + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_sparse_mat_clear(C); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-content.c b/fmpz_sparse_mat/test/t-content.c new file mode 100644 index 0000000000..7f34d90a9c --- /dev/null +++ b/fmpz_sparse_mat/test/t-content.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2015 Dharak Kharod + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" +#include "ulong_extras.h" +#include "long_extras.h" + + +int main() +{ + slong rep, r, c, min_nnz, max_nnz, bits, nreps = 100; + fmpz_sparse_mat_t A,B; + fmpz_t scalar, gcd_mat, temp; + FLINT_TEST_INIT(state); + + flint_printf("fmpz_sparse_mat_content...."); + fflush(stdout); + + for (rep = 0; rep < nreps; ++rep) + { + r = n_randint(state, 50); + c = n_randint(state, 50); + min_nnz = 0; + max_nnz = c; + do bits = n_randint(state, 256); + while (bits <= UWORD(1)); + + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + + fmpz_init(scalar); + fmpz_init(gcd_mat); + fmpz_init(temp); + + fmpz_sparse_mat_randtest(B, state, min_nnz, max_nnz, bits); + + fmpz_sparse_mat_content(gcd_mat, B); + + if (r == 0 || c == 0) + { + if (!fmpz_is_zero(gcd_mat)) + { + flint_printf("FAIL!\n"); + abort(); + } + } else { + fmpz_randtest_not_zero(scalar, state, 50); + + fmpz_sparse_mat_scalar_mul_fmpz(A, B, scalar); + + fmpz_sparse_mat_content(temp, A); + + fmpz_mul(gcd_mat, gcd_mat, scalar); + + if (fmpz_cmpabs(gcd_mat, temp) != 0) + { + flint_printf("FAIL!\n"); + abort(); + } + } + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + + fmpz_clear(scalar); + fmpz_clear(temp); + fmpz_clear(gcd_mat); + } + + + FLINT_TEST_CLEANUP(state); + flint_printf("PASS\n"); + return 0; +} + diff --git a/fmpz_sparse_mat/test/t-dense.c b/fmpz_sparse_mat/test/t-dense.c new file mode 100644 index 0000000000..5a70031e4b --- /dev/null +++ b/fmpz_sparse_mat/test/t-dense.c @@ -0,0 +1,71 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, bits, r, c; + fmpz_sparse_mat_t A, B; + fmpz_mat_t C, D; + FLINT_TEST_INIT(state); + + + flint_printf("conversion to/from dense matrix...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 100); + while (bits < UWORD(2)); + r = n_randint(state, 100); + c = n_randint(state, 100); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + fmpz_mat_init(C, r, c); + fmpz_mat_init(D, r, c); + + fmpz_sparse_mat_randtest(A, state, 0, c, bits); + fmpz_sparse_mat_to_dense(C, A); + fmpz_sparse_mat_from_dense(B, C); + + if (!fmpz_sparse_mat_equal(A, B)) + { + flint_printf("FAIL: A != B\n"); + abort(); + } + + fmpz_mat_randtest(C, state, bits); + fmpz_sparse_mat_from_dense(A, C); + fmpz_sparse_mat_to_dense(D, A); + + if (!fmpz_mat_equal(C, D)) + { + flint_printf("FAIL: C != D\n"); + abort(); + } + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_mat_clear(C); + fmpz_mat_clear(D); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-det.c b/fmpz_sparse_mat/test/t-det.c new file mode 100644 index 0000000000..12f99015b2 --- /dev/null +++ b/fmpz_sparse_mat/test/t-det.c @@ -0,0 +1,86 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_vec.h" +#include "fmpz_sparse_mat.h" +#include "ulong_extras.h" + + +int +main(void) +{ + slong rep, bits, r, nreps = 100, nzero = 0; + fmpz_t det, d; + fmpz_mat_t dA; + fmpz_sparse_mat_t A; + + FLINT_TEST_INIT(state); + + flint_printf("det...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + r = n_randint(state, 75); + bits = 1 + n_randint(state, 100); + + fmpz_sparse_mat_init(A, r, r); + + fmpz_init(det); + fmpz_init(d); + + if (r == 0) + fmpz_one(d); + else + { + fmpz_mat_init(dA, r, r); + if (r > 1 && n_randint(state, 2) == 0) + { + fmpz_zero(d); nzero++; + fmpz_mat_randrank(dA, state, 1+n_randint(state, r - 1), bits); + } + else + { + fmpz_randtest(d, state, 30); + fmpz_mat_randdet(dA, state, d); + } + fmpz_mat_randops(dA, state, n_randint(state, FLINT_MAX(r/4, 1)*r + 1)); + fmpz_sparse_mat_from_dense(A, dA); + fmpz_mat_clear(dA); + } + + fmpz_sparse_mat_det(det, A); + + if (!fmpz_equal(det, d)) + { + flint_printf("FAIL:\n"); + flint_printf("wrong determinant!\n"); + fmpz_sparse_mat_print_pretty(A), flint_printf("\n"); + flint_printf("expected: "), fmpz_print(d), flint_printf("\n"); + flint_printf("ncomputed: "), fmpz_print(det), flint_printf("\n"); + abort(); + } + + fmpz_sparse_mat_clear(A); + fmpz_clear(det); + fmpz_clear(d); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-det_bareiss.c b/fmpz_sparse_mat/test/t-det_bareiss.c new file mode 100644 index 0000000000..7c65540670 --- /dev/null +++ b/fmpz_sparse_mat/test/t-det_bareiss.c @@ -0,0 +1,71 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_vec.h" +#include "fmpz_sparse_mat.h" +#include "ulong_extras.h" + + +int +main(void) +{ + slong rep, bits, r, nreps = 1000; + fmpz_t det, ddet; + fmpz_mat_t dA; + fmpz_sparse_mat_t A; + + FLINT_TEST_INIT(state); + + flint_printf("det_bareiss...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + bits = 1+n_randint(state,200); + r = n_randint(state, 10); + + fmpz_mat_init(dA, r, r); + fmpz_sparse_mat_init(A, r, r); + fmpz_sparse_mat_randtest(A, state, 0, r, bits); + + fmpz_init(det); + fmpz_init(ddet); + + fmpz_sparse_mat_det(det, A); + fmpz_sparse_mat_to_dense(dA, A); + fmpz_mat_det(ddet, dA); + if (!fmpz_equal(det, ddet)) + { + flint_printf("FAIL:\n"); + flint_printf("Incorrect determinant!\n"); + fmpz_sparse_mat_print_pretty(A), flint_printf("\n"); + flint_printf("found det: "), fmpz_print(det), flint_printf("\n"); + flint_printf("right det: "), fmpz_print(ddet), flint_printf("\n"); + abort(); + } + + fmpz_clear(det); + fmpz_clear(ddet); + fmpz_mat_clear(dA); + fmpz_sparse_mat_clear(A); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-det_bound.c b/fmpz_sparse_mat/test/t-det_bound.c new file mode 100644 index 0000000000..b0a6e08c61 --- /dev/null +++ b/fmpz_sparse_mat/test/t-det_bound.c @@ -0,0 +1,68 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_vec.h" +#include "fmpz_sparse_mat.h" +#include "ulong_extras.h" + + +int +main(void) +{ + fmpz_sparse_mat_t A; + slong i, m; + fmpz_t det, bound; + + FLINT_TEST_INIT(state); + + flint_printf("det_bound...."); + fflush(stdout); + + for (i = 0; i < 1000 * flint_test_multiplier(); i++) + { + m = n_randint(state, 10); + + fmpz_sparse_mat_init(A, m, m); + + fmpz_init(det); + fmpz_init(bound); + + fmpz_sparse_mat_randtest(A, state, 0, m, 1+n_randint(state,200)); + + fmpz_sparse_mat_det(det, A); + fmpz_sparse_mat_det_bound(bound, A); + + if (fmpz_cmp(det, bound) > 0) + { + flint_printf("FAIL:\n"); + flint_printf("bound too small!\n"); + fmpz_sparse_mat_print_pretty(A), flint_printf("\n"); + flint_printf("det: "), fmpz_print(det), flint_printf("\n"); + flint_printf("bound: "), fmpz_print(bound), flint_printf("\n"); + abort(); + } + + fmpz_clear(det); + fmpz_clear(bound); + fmpz_sparse_mat_clear(A); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-det_divisor.c b/fmpz_sparse_mat/test/t-det_divisor.c new file mode 100644 index 0000000000..ee4873a7a7 --- /dev/null +++ b/fmpz_sparse_mat/test/t-det_divisor.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_vec.h" +#include "fmpz_sparse_mat.h" +#include "ulong_extras.h" + + +int +main(void) +{ + slong rep, bits, r, nreps = 1000; + fmpz_t det, d; + fmpz_sparse_mat_t A; + + FLINT_TEST_INIT(state); + + flint_printf("det_divisor...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + r = n_randint(state, 15); + bits = 1 + n_randint(state, 100); + + fmpz_init(det); + fmpz_init(d); + fmpz_sparse_mat_init(A, r, r); + + fmpz_sparse_mat_randtest(A, state, 0, r, bits); + + fmpz_sparse_mat_det_divisor(d, A); + fmpz_sparse_mat_det_bareiss(det, A); + + if ((fmpz_is_zero(det) || fmpz_is_zero(d)) && !fmpz_equal(det, d)) + { + flint_printf("FAIL: found divisor of matrix with det 0\n"); + fmpz_sparse_mat_print_pretty(A), flint_printf("\n"); + abort(); + } + else if (!fmpz_divisible(det, d)) + { + flint_printf("FAIL:\n"); + fmpz_sparse_mat_print_pretty(A), flint_printf("\n"); + flint_printf("det: "); fmpz_print(det); flint_printf("\n"); + flint_printf("d: "); fmpz_print(d); flint_printf("\n"); + abort(); + } + + fmpz_sparse_mat_clear(A); + fmpz_clear(det); + fmpz_clear(d); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-det_modular.c b/fmpz_sparse_mat/test/t-det_modular.c new file mode 100644 index 0000000000..de65ef2814 --- /dev/null +++ b/fmpz_sparse_mat/test/t-det_modular.c @@ -0,0 +1,70 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_vec.h" +#include "fmpz_sparse_mat.h" +#include "ulong_extras.h" + + +int +main(void) +{ + slong rep, bits, r, nreps = 1000; + fmpz_t det, d; + fmpz_sparse_mat_t A; + + FLINT_TEST_INIT(state); + + flint_printf("det_modular...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + int proved = n_randlimb(state) % 2; + bits = 1+n_randint(state,200); + r = n_randint(state, 20); + + fmpz_sparse_mat_init(A, r, r); + + fmpz_init(det); + fmpz_init(d); + + fmpz_sparse_mat_randtest(A, state, 0, r, bits); + + fmpz_sparse_mat_det_bareiss(d, A); + fmpz_sparse_mat_det_modular(det, A, proved); + + if (!fmpz_equal(d, det)) + { + flint_printf("FAIL:\n"); + flint_printf("different determinants!\n"); + fmpz_sparse_mat_print_pretty(A), flint_printf("\n"); + flint_printf("det_bareiss: "), fmpz_print(d), flint_printf("\n"); + flint_printf("det_modular: "), fmpz_print(det), flint_printf("\n"); + abort(); + } + + fmpz_clear(d); + fmpz_clear(det); + fmpz_sparse_mat_clear(A); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-det_modular_accelerated.c b/fmpz_sparse_mat/test/t-det_modular_accelerated.c new file mode 100644 index 0000000000..23615aa08c --- /dev/null +++ b/fmpz_sparse_mat/test/t-det_modular_accelerated.c @@ -0,0 +1,70 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_vec.h" +#include "fmpz_sparse_mat.h" +#include "ulong_extras.h" + + +int +main(void) +{ + slong rep, bits, r, nreps = 1000; + fmpz_t det, d; + fmpz_sparse_mat_t A; + + FLINT_TEST_INIT(state); + + flint_printf("det_modular_accelerated...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + int proved = n_randlimb(state) % 2; + bits = 1+n_randint(state,200); + r = n_randint(state, 20); + + fmpz_sparse_mat_init(A, r, r); + + fmpz_init(det); + fmpz_init(d); + + fmpz_sparse_mat_randtest(A, state, 0, r, bits); + + fmpz_sparse_mat_det_bareiss(d, A); + fmpz_sparse_mat_det_modular_accelerated(det, A, proved); + + if (!fmpz_equal(d, det)) + { + flint_printf("FAIL:\n"); + flint_printf("different determinants!\n"); + fmpz_sparse_mat_print_pretty(A), flint_printf("\n"); + flint_printf("det_bareiss: "), fmpz_print(d), flint_printf("\n"); + flint_printf("det_modular: "), fmpz_print(det), flint_printf("\n"); + abort(); + } + + fmpz_clear(d); + fmpz_clear(det); + fmpz_sparse_mat_clear(A); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-fflu.c b/fmpz_sparse_mat/test/t-fflu.c new file mode 100644 index 0000000000..67775f7a9f --- /dev/null +++ b/fmpz_sparse_mat/test/t-fflu.c @@ -0,0 +1,145 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "perm.h" +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, r, c, min_nnz, max_nnz, bits, rk, nreps = 1000, i, j; + slong *P, *Q; + fmpz_t *val; + fmpz *D; + fmpz_mat_t dL, dU, dLU; + fmpz_sparse_mat_t L, U, M, LU; + FLINT_TEST_INIT(state); + + flint_printf("fflu...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + bits = 100; /*2 + n_randint(state, 10);*/ + r = c = n_randint(state, 10); + /*c = n_randint(state, 20);*/ + min_nnz = 0; + max_nnz = c; + + D = _fmpz_vec_init(r); + P = flint_malloc(r*sizeof(*P)); + Q = flint_malloc(c*sizeof(*Q)); + fmpz_sparse_mat_init(M, r, c); + fmpz_sparse_mat_init(L, r, c); + fmpz_sparse_mat_init(U, r, c); + fmpz_sparse_mat_init(LU, r, c); + fmpz_sparse_mat_randtest(M, state, min_nnz, max_nnz, bits); + rk = fmpz_sparse_mat_fflu(D, P, Q, L, U, M); + + /* Check that L is lower triangular (with ones on diagonal up to rank) */ + for (i = 0; i < r; ++i) + { + val = fmpz_sparse_vec_at(&L->rows[i], i); + if (i < rk && (val == NULL || !fmpz_is_one(*val))) + { + flint_printf("FAIL: L does not have unit diagonal up to the rank\n"); + } + for (j = 0; j < L->rows[i].nnz; ++j) + { + if (L->rows[i].entries[j].ind > i) + { + flint_printf("FAIL: L not lower triangular\n"); + abort(); + } + if (L->rows[i].entries[j].ind >= rk) + { + flint_printf("FAIL: L not trivial past the rank\n"); + flint_printf("rank = %wd\n", rk); + flint_printf("L = "); + fmpz_sparse_mat_print_pretty(L); + abort(); + } + } + } + /* Check that U is upper triangular (with nonzero diagonal up to rank) */ + for (i = 0; i < r; ++i) + { + val = fmpz_sparse_vec_at(&U->rows[i], i); + if (i < rk && (val == NULL || fmpz_is_zero(*val))) + { + flint_printf("FAIL: U does not have nonzero diagonal\n"); + abort(); + } + if (i >= rk && U->rows[i].nnz != UWORD(0)) + { + flint_printf("FAIL: U not trivial past the rank\n"); + abort(); + } + for (j = 0; j < U->rows[i].nnz; ++j) + { + if (U->rows[i].entries[j].ind < i) + { + flint_printf("FAIL: U not upper triangular\n"); + abort(); + } + } + } + + + fmpz_mat_init(dL, r, rk); + fmpz_mat_init(dU, rk, c); + fmpz_mat_init(dLU, r, c); + + /* Verify that PDMQ = LU */ + fmpz_sparse_mat_mul_diag_fmpz(M, M, D); + fmpz_sparse_mat_permute_rows(M, P); + fmpz_sparse_mat_permute_cols(M, Q); + fmpz_sparse_mat_to_dense(dL, L); + fmpz_sparse_mat_to_dense(dU, U); + fmpz_mat_mul(dLU, dL, dU); + fmpz_sparse_mat_from_dense(LU, dLU); + if (!fmpz_sparse_mat_equal(M, LU)) + { + flint_printf("FAIL: PDMQ != LU\n"); + flint_printf("PDMQ="); + fmpz_sparse_mat_print_pretty(M); + flint_printf("LU="); + fmpz_sparse_mat_print_pretty(LU); + flint_printf("diff = "); + fmpz_sparse_mat_sub(LU, LU, M); + fmpz_sparse_mat_print_pretty(LU); + abort(); + } + + _fmpz_vec_clear(D, r); + flint_free(P); + flint_free(Q); + fmpz_sparse_mat_clear(M); + fmpz_sparse_mat_clear(U); + fmpz_sparse_mat_clear(L); + fmpz_sparse_mat_clear(LU); + fmpz_mat_clear(dL); + fmpz_mat_clear(dU); + fmpz_mat_clear(dLU); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + diff --git a/fmpz_sparse_mat/test/t-hnf_classical.c b/fmpz_sparse_mat/test/t-hnf_classical.c new file mode 100644 index 0000000000..481fb7d7fa --- /dev/null +++ b/fmpz_sparse_mat/test/t-hnf_classical.c @@ -0,0 +1,75 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, r, c, min_nnz, max_nnz, bits, rk, nreps = 1000; + fmpz_mat_t dA, dH; + fmpz_sparse_mat_t A, H, H2; + FLINT_TEST_INIT(state); + + flint_printf("hnf_classical...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + bits = 2 + n_randint(state, 100); + r = n_randint(state, 10); + c = n_randint(state, 10); + min_nnz = 0; + max_nnz = c; + + fmpz_mat_init(dA, r, c); + fmpz_mat_init(dH, r, c); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(H, r, c); + fmpz_sparse_mat_init(H2, r, c); + fmpz_sparse_mat_randtest(A, state, min_nnz, max_nnz, bits); + fmpz_sparse_mat_set(H, A); + rk = fmpz_sparse_mat_hnf_classical(H); + fmpz_sparse_mat_to_dense(dA, A); + fmpz_mat_hnf_classical(dH, dA); + fmpz_sparse_mat_from_dense(H2, dH); + + if (!fmpz_sparse_mat_equal(H, H2)) + { + flint_printf("FAIL: matrix not in hnf!\n"); + fmpz_sparse_mat_print_pretty(A); flint_printf("\n\n"); + flint_printf("Obtained: \n"); + fmpz_sparse_mat_print_pretty(H); flint_printf("\n\n"); + flint_printf("Should be: \n"); + fmpz_sparse_mat_print_pretty(H2); flint_printf("\n\n"); + flint_printf("Found rank %wd\n", rk); + abort(); + } + + fmpz_sparse_mat_clear(H2); + fmpz_sparse_mat_clear(H); + fmpz_sparse_mat_clear(A); + fmpz_mat_clear(dA); + fmpz_mat_clear(dH); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + diff --git a/fmpz_sparse_mat/test/t-hnf_minors.c b/fmpz_sparse_mat/test/t-hnf_minors.c new file mode 100644 index 0000000000..64d26e8d71 --- /dev/null +++ b/fmpz_sparse_mat/test/t-hnf_minors.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" + + +int +main(void) +{ + slong rep, r, c, min_nnz, max_nnz, bits, rk, nreps = 1000; + fmpz_mat_t dA, dH; + fmpz_sparse_mat_t A, H, H2; + FLINT_TEST_INIT(state); + + flint_printf("hnf_minors...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + bits = 2 + n_randint(state, 100); + r = n_randint(state, 20); + c = n_randint(state, 20); + min_nnz = 0; + max_nnz = c; + + fmpz_mat_init(dA, r, c); + fmpz_mat_init(dH, r, c); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(H, r, c); + fmpz_sparse_mat_init(H2, r, c); + fmpz_sparse_mat_randtest(A, state, min_nnz, max_nnz, bits); + fmpz_sparse_mat_set(H, A); + rk = fmpz_sparse_mat_hnf_minors(H); + fmpz_sparse_mat_to_dense(dA, A); + fmpz_mat_hnf(dH, dA); + fmpz_sparse_mat_from_dense(H2, dH); + if (!fmpz_sparse_mat_equal(H, H2)) + { + flint_printf("FAIL: matrix not in hnf!\n"); + flint_printf("Starting: \n"); + fmpz_sparse_mat_print_pretty(A); flint_printf("\n\n"); + flint_printf("Obtained: \n"); + fmpz_sparse_mat_print_pretty(H); flint_printf("\n\n"); + flint_printf("Found rank %wd\n", rk); + abort(); + } + + fmpz_sparse_mat_clear(H2); + fmpz_sparse_mat_clear(H); + fmpz_sparse_mat_clear(A); + fmpz_mat_clear(dA); + fmpz_mat_clear(dH); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-hnf_modular.c b/fmpz_sparse_mat/test/t-hnf_modular.c new file mode 100644 index 0000000000..0fe0d9a5fe --- /dev/null +++ b/fmpz_sparse_mat/test/t-hnf_modular.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, r, min_nnz, max_nnz, bits, nreps = 1000; + fmpz_t det; + fmpz_sparse_mat_t A, H, H2; + FLINT_TEST_INIT(state); + + flint_printf("hnf_modular...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + bits = 1 + n_randint(state, 200); + r = n_randint(state, 20); + min_nnz = 0; + max_nnz = r; + + fmpz_init(det); + + fmpz_sparse_mat_init(A, r, r); + fmpz_sparse_mat_init(H, r, r); + fmpz_sparse_mat_init(H2, r, r); + + do + { + fmpz_sparse_mat_randtest(A, state, min_nnz, max_nnz, bits); + fmpz_sparse_mat_det(det, A); + } while (fmpz_is_zero(det)); + fmpz_abs(det, det); + fmpz_mul_ui(det, det, 1 + n_randint(state, 10)); + + fmpz_sparse_mat_set(H, A); + fmpz_sparse_mat_hnf_modular(H, det); + + fmpz_sparse_mat_set(H2, A); + fmpz_sparse_mat_hnf_classical(H2); + + if (!fmpz_sparse_mat_is_in_hnf(H)) + { + flint_printf("FAIL:\n"); + flint_printf("matrix not in hnf!\n"); + fmpz_sparse_mat_print_pretty(A); flint_printf("\n\n"); + fmpz_sparse_mat_print_pretty(H); flint_printf("\n\n"); + abort(); + } + + if (!fmpz_sparse_mat_equal(H, H2)) + { + flint_printf("FAIL:\n"); + flint_printf("hnfs produced by different methods should be the same!\n"); + fmpz_sparse_mat_print_pretty(A); flint_printf("\n\n"); + fmpz_sparse_mat_print_pretty(H); flint_printf("\n\n"); + fmpz_sparse_mat_print_pretty(H2); flint_printf("\n\n"); + fmpz_print(det); flint_printf("\n\n"); + abort(); + } + + fmpz_sparse_mat_clear(H2); + fmpz_sparse_mat_clear(H); + fmpz_sparse_mat_clear(A); + fmpz_clear(det); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + diff --git a/fmpz_sparse_mat/test/t-hnf_modular_eldiv.c b/fmpz_sparse_mat/test/t-hnf_modular_eldiv.c new file mode 100644 index 0000000000..ffdc3f9320 --- /dev/null +++ b/fmpz_sparse_mat/test/t-hnf_modular_eldiv.c @@ -0,0 +1,90 @@ +/* + Copyright (C) 2015 Tommy Hofmann + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" + +/* FIX ME */ +int +main(void) +{ + slong rep, r, min_nnz, max_nnz, bits, nreps = 100; + fmpz_t det; + fmpz_sparse_mat_t A, H, H2; + FLINT_TEST_INIT(state); + + flint_printf("hnf_modular_eldiv...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + bits = 1 + n_randint(state, 100); + r = n_randint(state, 20); + min_nnz = 0; + max_nnz = r; + + fmpz_init(det); + + fmpz_sparse_mat_init(A, r, r); + fmpz_sparse_mat_init(H, r, r); + fmpz_sparse_mat_init(H2, r, r); + + do + { + fmpz_sparse_mat_randtest_unsigned(A, state, min_nnz, max_nnz, bits); + fmpz_sparse_mat_det(det, A); + } while (fmpz_is_zero(det)); + fmpz_abs(det, det); + /*fmpz_mul_ui(det, det, 1 + n_randint(state, 10));*/ + + fmpz_sparse_mat_set(H, A); + fmpz_sparse_mat_hnf_modular_eldiv(H, det); + fmpz_sparse_mat_set(H2, A); + fmpz_sparse_mat_hnf_minors(H2); + + if (!fmpz_sparse_mat_is_in_hnf(H)) + { + flint_printf("FAIL:\n"); + flint_printf("matrix not in hnf!\n"); + fmpz_sparse_mat_print_pretty(A); flint_printf("\n\n"); + fmpz_sparse_mat_print_pretty(H); flint_printf("\n\n"); + flint_printf("determinant:"); fmpz_print(det); + flint_printf("\n\n"); + abort(); + } + + if (!fmpz_sparse_mat_equal(H, H2)) + { + flint_printf("FAIL:\n"); + flint_printf("hnfs produced by different methods should be the same!\n"); + fmpz_sparse_mat_print_pretty(A); flint_printf("\n\n"); + fmpz_sparse_mat_print_pretty(H); flint_printf("\n\n"); + fmpz_sparse_mat_print_pretty(H2); flint_printf("\n\n"); + fmpz_print(det); flint_printf("\n\n"); + abort(); + } + + fmpz_sparse_mat_clear(H2); + fmpz_sparse_mat_clear(H); + fmpz_sparse_mat_clear(A); + fmpz_clear(det); + } + + FLINT_TEST_CLEANUP(state); + flint_printf("PASS\n"); + return 0; +} + diff --git a/fmpz_sparse_mat/test/t-hnf_xgcd.c b/fmpz_sparse_mat/test/t-hnf_xgcd.c new file mode 100644 index 0000000000..f518250af9 --- /dev/null +++ b/fmpz_sparse_mat/test/t-hnf_xgcd.c @@ -0,0 +1,75 @@ +/* + Copyright (C) 2014 Alex J. Best + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, r, c, min_nnz, max_nnz, bits, rk, nreps = 1000; + fmpz_mat_t dA, dH; + fmpz_sparse_mat_t A, H, H2; + FLINT_TEST_INIT(state); + + flint_printf("hnf_xgcd...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + bits = 2 + n_randint(state, 100); + r = n_randint(state, 10); + c = n_randint(state, 10); + min_nnz = 0; + max_nnz = c; + + fmpz_mat_init(dA, r, c); + fmpz_mat_init(dH, r, c); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(H, r, c); + fmpz_sparse_mat_init(H2, r, c); + fmpz_sparse_mat_randtest(A, state, min_nnz, max_nnz, bits); + + fmpz_sparse_mat_set(H, A); + rk = fmpz_sparse_mat_hnf_xgcd(H); + fmpz_sparse_mat_to_dense(dA, A); + fmpz_mat_hnf_xgcd(dH, dA); + fmpz_sparse_mat_from_dense(H2, dH); + + if (!fmpz_sparse_mat_equal(H, H2)) + { + flint_printf("FAIL: matrix not in hnf!\n"); + fmpz_sparse_mat_print_pretty(A); flint_printf("\n\n"); + flint_printf("Obtained: \n"); + fmpz_sparse_mat_print_pretty(H); flint_printf("\n\n"); + flint_printf("Should be: \n"); + fmpz_sparse_mat_print_pretty(H2); flint_printf("\n\n"); + flint_printf("Found rank %wd\n", rk); + abort(); + } + + fmpz_sparse_mat_clear(H2); + fmpz_sparse_mat_clear(H); + fmpz_sparse_mat_clear(A); + fmpz_mat_clear(dA); + fmpz_mat_clear(dH); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-howell_form_mod.c b/fmpz_sparse_mat/test/t-howell_form_mod.c new file mode 100644 index 0000000000..d346bfacca --- /dev/null +++ b/fmpz_sparse_mat/test/t-howell_form_mod.c @@ -0,0 +1,79 @@ +/* + Copyright (C) 2015 Tommy Hofmann + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, r, c, min_nnz, max_nnz, bits, rk, rk2, nreps = 10; + fmpz_t mod; + fmpz_mat_t dH; + fmpz_sparse_mat_t A, H, H2; + FLINT_TEST_INIT(state); + + flint_printf("howell_form...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + bits = 64 + n_randint(state, 70); + c = n_randint(state, 10); + r = c + n_randint(state, 10); + min_nnz = 0; + max_nnz = c; + + fmpz_mat_init(dH, r, c); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(H, r, c); + fmpz_sparse_mat_init(H2, r, c); + fmpz_sparse_mat_randtest(A, state, min_nnz, max_nnz, bits); + + fmpz_init(mod); + do fmpz_randtest_not_zero(mod, state, bits); + while (fmpz_fits_si(mod)); + fmpz_sparse_mat_set(H, A); + fmpz_sparse_mat_to_dense(dH, A); + rk = fmpz_sparse_mat_howell_form_mod(H, mod); + rk2 = fmpz_mat_howell_form_mod(dH, mod); + fmpz_sparse_mat_from_dense(H2, dH); + if (!fmpz_sparse_mat_equal(H, H2)) + { + flint_printf("FAIL: Howell form not equal\n"); + fmpz_sparse_mat_print_pretty(H); flint_printf("\n\n"); + fmpz_sparse_mat_print_pretty(H2); flint_printf("\n\n"); + flint_printf("Ranks: %wd, %wd\nModulus: ", rk, rk2); + fmpz_print(mod); + flint_printf("\n\n"); + abort(); + } + + do fmpz_randtest_unsigned(mod, state, 10); + while (fmpz_is_zero(mod)); + + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(H); + fmpz_sparse_mat_clear(H2); + fmpz_mat_clear(dH); + fmpz_clear(mod); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + diff --git a/fmpz_sparse_mat/test/t-init_clear.c b/fmpz_sparse_mat/test/t-init_clear.c new file mode 100644 index 0000000000..e5f3411131 --- /dev/null +++ b/fmpz_sparse_mat/test/t-init_clear.c @@ -0,0 +1,59 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, bits, r, c, i; + fmpz_sparse_mat_t A; + FLINT_TEST_INIT(state); + + + flint_printf("init/clear...."); + fflush(stdout); + + for (rep = 0; rep < 100; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + r = n_randint(state, 200); + c = n_randint(state, 200); + fmpz_sparse_mat_init(A, r, c); + + if (!fmpz_sparse_mat_is_zero(A)) + { + flint_printf("FAIL: A not zero!\n"); + abort(); + } + for (i = 0; i < r; i++) + { + if (!fmpz_sparse_vec_is_zero(&A->rows[i])) + { + flint_printf("FAIL: row %wd not zero!\n", i); + abort(); + } + } + + fmpz_sparse_mat_clear(A); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-mul.c b/fmpz_sparse_mat/test/t-mul.c new file mode 100644 index 0000000000..e9d332695e --- /dev/null +++ b/fmpz_sparse_mat/test/t-mul.c @@ -0,0 +1,84 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, bits, r, c, k; + fmpz_sparse_mat_t A; + fmpz *x, *y, *y2; + fmpz_mat_t B, X, Y, Y2; + FLINT_TEST_INIT(state); + + + flint_printf("multiplication by vec/mat...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 70); + while (bits < UWORD(2)); + r = 1 + n_randint(state, 20); + c = 1 + n_randint(state, 20); + k = 1 + n_randint(state, 20); + fmpz_sparse_mat_init(A, r, c); + fmpz_mat_init(B, r, c); + fmpz_mat_init(X, c, k); + fmpz_mat_init(Y, r, k); + fmpz_mat_init(Y2, r, k); + x = _fmpz_vec_init(c); + y = _fmpz_vec_init(r); + y2 = _fmpz_vec_init(r); + + fmpz_sparse_mat_randtest(A, state, 0, c, bits); + fmpz_sparse_mat_to_dense(B, A); + _fmpz_vec_randtest(x, state, c, bits); + fmpz_sparse_mat_mul_vec(y, A, x); + fmpz_mat_mul_vec(y2, B, x); + + if (!_fmpz_vec_equal(y, y2, A->r)) + { + flint_printf("FAIL: y != y2\n"); + abort(); + } + + fmpz_mat_randtest(X, state, bits); + fmpz_sparse_mat_mul_mat(Y, A, X); + fmpz_mat_mul(Y2, B, X); + + if (!fmpz_mat_equal(Y, Y2)) + { + flint_printf("Fail: Y != Y2\n"); + abort(); + } + + fmpz_sparse_mat_clear(A); + fmpz_mat_clear(B); + _fmpz_vec_clear(x, c); + _fmpz_vec_clear(y, r); + _fmpz_vec_clear(y2, r); + fmpz_mat_clear(X); + fmpz_mat_clear(Y); + fmpz_mat_clear(Y2); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-multi_CRT_ui.c b/fmpz_sparse_mat/test/t-multi_CRT_ui.c new file mode 100644 index 0000000000..b51b8a5114 --- /dev/null +++ b/fmpz_sparse_mat/test/t-multi_CRT_ui.c @@ -0,0 +1,87 @@ +/* + Copyright (C) 2007 William Hart and David Harvey + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" +#include "nmod_sparse_mat.h" + +int +main(void) +{ + slong rep, r, c, min_nnz, max_nnz, bits, prime_bits, num_primes, j, nreps = 1000; + mp_limb_t primes[1000]; + nmod_t nmod; + fmpz_t mod; + nmod_sparse_mat_struct Amod[1000]; + fmpz_sparse_mat_t A, B; + FLINT_TEST_INIT(state); + + flint_printf("multi_CRT_ui...."); + fflush(stdout); + + + for (rep = 0; rep < nreps; rep++) + { + bits = n_randint(state, 500) + 2; + r = n_randint(state, 10); + c = n_randint(state, 10); + min_nnz = 0; + max_nnz = c; + prime_bits = 1 + n_randint(state, FLINT_BITS - 1); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + + fmpz_sparse_mat_randtest(A, state, min_nnz, max_nnz, bits); + + fmpz_init_set_ui(mod, UWORD(1)); + for (num_primes = 0; fmpz_bits(mod) <= bits + 1; num_primes++) + { + primes[num_primes] = n_nextprime((num_primes == 0) ? (UWORD(1) << prime_bits) : primes[num_primes - 1], 0); + nmod_init(&nmod, primes[num_primes]); + nmod_sparse_mat_init(&Amod[num_primes], r, c, nmod); + fmpz_sparse_mat_get_nmod_sparse_mat(&Amod[num_primes], A); + fmpz_mul_ui(mod, mod, primes[num_primes]); + } + fmpz_sparse_mat_multi_mod_ui(Amod, num_primes, A); + fmpz_sparse_mat_multi_CRT_ui(B, Amod, num_primes, 1); + + if (!fmpz_sparse_mat_equal(B, A)) + { + flint_printf("FAIL!\n"); + flint_printf("primes: "); + for (j = 0; j < num_primes; j++) + flint_printf("%wu ", primes[j]); + flint_printf("\nA: \n"); + fmpz_sparse_mat_print_pretty(A); + flint_printf("\nB: \n"); + fmpz_sparse_mat_print_pretty(B); + flint_printf("\n"); + abort(); + } + + for (j = 0; j < num_primes; j++) + nmod_sparse_mat_clear(&Amod[j]); + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_clear(mod); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-multi_CRT_ui_unsigned.c b/fmpz_sparse_mat/test/t-multi_CRT_ui_unsigned.c new file mode 100644 index 0000000000..c83d63418d --- /dev/null +++ b/fmpz_sparse_mat/test/t-multi_CRT_ui_unsigned.c @@ -0,0 +1,87 @@ +/* + Copyright (C) 2007 William Hart and David Harvey + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_sparse_mat.h" +#include "nmod_sparse_mat.h" + +int +main(void) +{ + slong rep, r, c, min_nnz, max_nnz, bits, prime_bits, num_primes, j, nreps = 1000; + mp_limb_t primes[1000]; + nmod_t nmod; + fmpz_t mod; + nmod_sparse_mat_struct Amod[1000]; + fmpz_sparse_mat_t A, B; + FLINT_TEST_INIT(state); + + flint_printf("multi_CRT_ui_unsigned...."); + fflush(stdout); + + + for (rep = 0; rep < nreps; rep++) + { + bits = n_randint(state, 500) + 2; + r = n_randint(state, 10); + c = n_randint(state, 10); + min_nnz = 0; + max_nnz = c; + prime_bits = 1 + n_randint(state, FLINT_BITS - 1); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + + fmpz_sparse_mat_randtest_unsigned(A, state, min_nnz, max_nnz, bits); + + fmpz_init_set_ui(mod, UWORD(1)); + for (num_primes = 0; fmpz_bits(mod) <= bits; num_primes++) + { + primes[num_primes] = n_nextprime((num_primes == 0) ? (UWORD(1) << prime_bits) : primes[num_primes - 1], 0); + nmod_init(&nmod, primes[num_primes]); + nmod_sparse_mat_init(&Amod[num_primes], r, c, nmod); + fmpz_sparse_mat_get_nmod_sparse_mat(&Amod[num_primes], A); + fmpz_mul_ui(mod, mod, primes[num_primes]); + } + fmpz_sparse_mat_multi_mod_ui(Amod, num_primes, A); + fmpz_sparse_mat_multi_CRT_ui(B, Amod, num_primes, 0); + + if (!fmpz_sparse_mat_equal(B, A)) + { + flint_printf("FAIL!\n"); + flint_printf("primes: "); + for (j = 0; j < num_primes; j++) + flint_printf("%wu ", primes[j]); + flint_printf("\nA: \n"); + fmpz_sparse_mat_print_pretty(A); + flint_printf("\nB: \n"); + fmpz_sparse_mat_print_pretty(B); + flint_printf("\n"); + abort(); + } + + for (j = 0; j < num_primes; j++) + nmod_sparse_mat_clear(&Amod[j]); + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_clear(mod); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-neg.c b/fmpz_sparse_mat/test/t-neg.c new file mode 100644 index 0000000000..b4fd5c1873 --- /dev/null +++ b/fmpz_sparse_mat/test/t-neg.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, bits, r, c; + fmpz_sparse_mat_t A, B, C, D; + FLINT_TEST_INIT(state); + + flint_printf("neg...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + r = n_randint(state, 200); + c = n_randint(state, 200); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + fmpz_sparse_mat_init(C, r, c); + fmpz_sparse_mat_init(D, r, c); + + fmpz_sparse_mat_randtest(A, state, 0, c, bits); + fmpz_sparse_mat_randtest(B, state, 0, c, bits); + fmpz_sparse_mat_randtest(C, state, 0, c, bits); + fmpz_sparse_mat_randtest(D, state, 0, c, bits); + + fmpz_sparse_mat_sub(C, A, B); + fmpz_sparse_mat_neg(B, B); + fmpz_sparse_mat_add(D, A, B); + + if (!fmpz_sparse_mat_equal(C, D)) + { + flint_printf("FAIL\n"); + abort(); + } + + fmpz_sparse_mat_neg(C, B); + fmpz_sparse_mat_neg(B, B); + + if (!fmpz_sparse_mat_equal(C, B)) + { + flint_printf("FAIL\n"); + abort(); + } + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_sparse_mat_clear(C); + fmpz_sparse_mat_clear(D); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-scalar_mul.c b/fmpz_sparse_mat/test/t-scalar_mul.c new file mode 100644 index 0000000000..98b5daba12 --- /dev/null +++ b/fmpz_sparse_mat/test/t-scalar_mul.c @@ -0,0 +1,82 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, bits, r, c, nreps = 1000; + fmpz_t a, cc; + fmpz_sparse_mat_t A, B, C, D; + FLINT_TEST_INIT(state); + + flint_printf("scalar_mul...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + r = n_randint(state, 200); + c = n_randint(state, 200); + fmpz_init(a); + fmpz_init(cc); + fmpz_randtest(cc, state, bits); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, r, c); + fmpz_sparse_mat_init(C, r, c); + fmpz_sparse_mat_init(D, r, c); + + fmpz_sparse_mat_randtest(A, state, 0, c, bits); + + fmpz_sparse_mat_scalar_mul_fmpz(B, A, a); + fmpz_one(cc); + fmpz_sub(cc, a, cc); + fmpz_sparse_mat_scalar_mul_fmpz(C, A, cc); + + /* c*A - (c-1)*A == A */ + fmpz_sparse_mat_sub(D, B, C); + + if (!fmpz_sparse_mat_equal(A, D)) + { + flint_printf("FAIL\n"); + abort(); + } + + /* Aliasing */ + fmpz_sparse_mat_scalar_mul_fmpz(C, A, a); + fmpz_sparse_mat_scalar_mul_fmpz(A, A, a); + + if (!fmpz_sparse_mat_equal(A, C)) + { + flint_printf("FAIL\n"); + abort(); + } + + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_sparse_mat_clear(C); + fmpz_sparse_mat_clear(D); + fmpz_clear(a); + fmpz_clear(cc); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-solve_dixon.c b/fmpz_sparse_mat/test/t-solve_dixon.c new file mode 100644 index 0000000000..7143abd9d7 --- /dev/null +++ b/fmpz_sparse_mat/test/t-solve_dixon.c @@ -0,0 +1,100 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_vec.h" +#include "fmpz_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, r, c, nreps = 1000, num_bad_fail = 0; + fmpz_sparse_mat_t A; + fmpz_mat_t X, B, AX, AXm, Bm; + fmpz_t mod, det; + int success; + + FLINT_TEST_INIT(state); + + flint_printf("solve_dixon...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + do bits = n_randint(state, 100); + while (bits < UWORD(2)); + r = n_randint(state, 20); + c = n_randint(state, 20); + + fmpz_sparse_mat_init(A, r, r); + fmpz_mat_init(B, r, c); + fmpz_mat_init(X, r, c); + fmpz_init(mod); + + fmpz_sparse_mat_randtest(A, state, 0, r, bits); + fmpz_mat_randtest(B, state, 1+n_randint(state, 2)*bits); + + success = fmpz_sparse_mat_solve_dixon(X, mod, A, B); + if (!success) + { + fmpz_init(det); + fmpz_sparse_mat_det(det, A); + if (!fmpz_is_zero(det)) + { + num_bad_fail++; + } + fmpz_clear(det); + } + else + { + fmpz_mat_init(AX, r, c); + fmpz_mat_init(AXm, r, c); + fmpz_mat_init(Bm, r, c); + + fmpz_sparse_mat_mul_mat(AX, A, X); + fmpz_mat_scalar_mod_fmpz(AXm, AX, mod); + fmpz_mat_scalar_mod_fmpz(Bm, B, mod); + + if (!fmpz_mat_equal(AXm, Bm) || !success) + { + flint_printf("FAIL:\n"); + flint_printf("AX != B!\n"); + flint_printf("A:\n"), fmpz_sparse_mat_print_pretty(A), flint_printf("\n"); + flint_printf("B:\n"), fmpz_mat_print_pretty(B), flint_printf("\n"); + flint_printf("X:\n"), fmpz_mat_print_pretty(X), flint_printf("\n"); + flint_printf("mod = "), fmpz_print(mod), flint_printf("\n"); + flint_printf("AX:\n"), fmpz_mat_print_pretty(AX), flint_printf("\n"); + abort(); + } + fmpz_mat_clear(Bm); + fmpz_mat_clear(AX); + fmpz_mat_clear(AXm); + } + + + fmpz_sparse_mat_clear(A); + fmpz_mat_clear(B); + fmpz_mat_clear(X); + fmpz_clear(mod); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + if (num_bad_fail != 0) flint_printf("Number of unexpected failures: %wd\n", num_bad_fail); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-solve_dixon_den.c b/fmpz_sparse_mat/test/t-solve_dixon_den.c new file mode 100644 index 0000000000..64c842091a --- /dev/null +++ b/fmpz_sparse_mat/test/t-solve_dixon_den.c @@ -0,0 +1,93 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz.h" +#include "fmpz_vec.h" +#include "fmpz_sparse_mat.h" +#include "ulong_extras.h" + +/* TODO */ +int +main(void) +{ + slong rep, bits, r, c, nreps = 1000, num_bad_fail = 0; + fmpz_sparse_mat_t A; + fmpz_mat_t X, B, AX; + fmpz_t den, det; + int success; + + FLINT_TEST_INIT(state); + + flint_printf("solve_dixon_den...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + do bits = n_randint(state, 100); + while (bits < UWORD(2)); + r = n_randint(state, 20); + c = n_randint(state, 20); + + fmpz_sparse_mat_init(A, r, r); + fmpz_mat_init(B, r, c); + fmpz_mat_init(X, r, c); + fmpz_init(den); + + fmpz_sparse_mat_randtest(A, state, 0, r, bits); + fmpz_mat_randtest(B, state, 1+n_randint(state, 2)*bits); + + success = fmpz_sparse_mat_solve_dixon_den(X, den, A, B); + if (!success) + { + fmpz_init(det); + fmpz_sparse_mat_det(det, A); + if (!fmpz_is_zero(det)) + { + num_bad_fail++; + } + fmpz_clear(det); + } + else + { + fmpz_mat_init(AX, r, c); + fmpz_sparse_mat_mul_mat(AX, A, X); + fmpz_mat_scalar_divexact_fmpz(AX, AX, den); + + if (!fmpz_mat_equal(AX, B)) + { + flint_printf("FAIL:\n"); + flint_printf("AX != B!\n"); + flint_printf("A:\n"), fmpz_sparse_mat_print_pretty(A), flint_printf("\n"); + flint_printf("B:\n"), fmpz_mat_print_pretty(B), flint_printf("\n"); + flint_printf("X:\n"), fmpz_mat_print_pretty(X), flint_printf("\n"); + flint_printf("den = "), fmpz_print(den), flint_printf("\n"); + flint_printf("AX:\n"), fmpz_mat_print_pretty(AX), flint_printf("\n"); + abort(); + } + fmpz_mat_clear(AX); + } + + fmpz_sparse_mat_clear(A); + fmpz_mat_clear(B); + fmpz_mat_clear(X); + fmpz_clear(den); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/test/t-transpose.c b/fmpz_sparse_mat/test/t-transpose.c new file mode 100644 index 0000000000..814f2fbe0c --- /dev/null +++ b/fmpz_sparse_mat/test/t-transpose.c @@ -0,0 +1,63 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +int +main(void) +{ + slong rep, bits, r, c; + fmpz_sparse_mat_t A, B, C; + FLINT_TEST_INIT(state); + + + flint_printf("transpose...."); + fflush(stdout); + + /* Rectangular transpose, same modulus */ + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + r = n_randint(state, 20); + c = n_randint(state, 20); + fmpz_sparse_mat_init(A, r, c); + fmpz_sparse_mat_init(B, c, r); + fmpz_sparse_mat_init(C, r, c); + + fmpz_sparse_mat_randtest(A, state, 0, c, bits); + fmpz_sparse_mat_randtest(B, state, 0, r, bits); + fmpz_sparse_mat_randtest(C, state, 0, c, bits); + + fmpz_sparse_mat_transpose(B, A); + fmpz_sparse_mat_transpose(C, B); + + if (!fmpz_sparse_mat_equal(C, A)) + { + flint_printf("FAIL: C != A\n"); + abort(); + } + + fmpz_sparse_mat_clear(A); + fmpz_sparse_mat_clear(B); + fmpz_sparse_mat_clear(C); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_mat/transpose.c b/fmpz_sparse_mat/transpose.c new file mode 100644 index 0000000000..7800152ae3 --- /dev/null +++ b/fmpz_sparse_mat/transpose.c @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +void +fmpz_sparse_mat_transpose(fmpz_sparse_mat_t B, const fmpz_sparse_mat_t A) +{ + slong r, c, i, j, *nnz; + fmpz_sparse_entry_struct *Ae, *Be; + FLINT_ASSERT(B->r == A->c); + FLINT_ASSERT(A->r == B->c); + nnz = flint_calloc(A->c, sizeof(*nnz)); + /* Get number of nnzs in each column of A (thus each row of B) */ + for (c = 0; c < A->c; ++c) + { + nnz[c] = 0; + } + for (r = 0; r < A->r; ++r) + { + for (i = 0; i < A->rows[r].nnz; ++i) + { + c = A->rows[r].entries[i].ind - A->c_off; + if (c >= A->c) break; + nnz[c]++; + } + } + /* Allocate space for nnz and reset counters */ + for (c = 0; c < A->c; ++c) + { + _fmpz_sparse_vec_resize(&B->rows[c], nnz[c]); + nnz[c] = 0; + } + /* Put entries into transposed matrix */ + for (r = 0; r < A->r; ++r) + { + for (i = 0; i < A->rows[r].nnz; ++i) + { + Ae = &A->rows[r].entries[i]; + c = Ae->ind - A->c_off; + if (c >= A->c) break; + j = nnz[c]++; + Be = &B->rows[c].entries[j]; + Be->ind = r; + fmpz_set(Be->val, Ae->val); + } + } + flint_free(nnz); + B->c_off = 0; +} diff --git a/fmpz_sparse_mat/window_init.c b/fmpz_sparse_mat/window_init.c new file mode 100644 index 0000000000..9d1a50834d --- /dev/null +++ b/fmpz_sparse_mat/window_init.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "flint.h" +#include "fmpz_sparse_mat.h" + +void fmpz_sparse_mat_window_init(fmpz_sparse_mat_t window, const fmpz_sparse_mat_t mat, slong r1, slong c1, slong r2, slong c2) +{ + slong i; + r2 = FLINT_MIN(r2, mat->r), r1 = FLINT_MIN(r1, r2); + c2 = FLINT_MIN(c2, mat->c), c1 = FLINT_MIN(c1, c2); + window->r = r2-r1; + window->c = c2-c1; + window->c_off = c1; + window->rows = flint_malloc(window->r*sizeof(*window->rows)); + for (i = 0; i < window->r; ++i) + fmpz_sparse_vec_window_init(&window->rows[i], &mat->rows[i+r1], c1, c2); +} diff --git a/fmpz_sparse_mat/with_transpose_fix_support.c b/fmpz_sparse_mat/with_transpose_fix_support.c new file mode 100644 index 0000000000..a5933fff2f --- /dev/null +++ b/fmpz_sparse_mat/with_transpose_fix_support.c @@ -0,0 +1,35 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" +#include "hashmap.h" +#include "longlong.h" + +void _fmpz_sparse_mat_with_transpose_fix_support(fmpz_sparse_mat_with_transpose_t MT, slong r, slong *osupp, slong onnz) +{ + slong i = 0, j = 0, oc, nc, c; + fmpz_sparse_vec_struct *row = &MT->M->rows[r]; + + i = 0; + while (1) + { + oc = (i==onnz) ? MT->M->c : osupp[i]; + nc = (j==row->nnz) ? MT->M->c : row->entries[j].ind; + c = FLINT_MIN(oc, nc); + if (c >= MT->M->c) break; + if (oc < nc) hashmap_rem(&MT->cols[c], r); + else hashmap_put(&MT->cols[c], r, &MT->M->rows[r].entries[j].val); + if (oc <= nc) ++i; + if (oc >= nc) ++j; + } +} + diff --git a/fmpz_sparse_mat/with_transpose_init.c b/fmpz_sparse_mat/with_transpose_init.c new file mode 100644 index 0000000000..f45781f7d2 --- /dev/null +++ b/fmpz_sparse_mat/with_transpose_init.c @@ -0,0 +1,34 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_mat.h" +#include "hashmap.h" +#include "longlong.h" + +void _fmpz_sparse_mat_with_transpose_init(fmpz_sparse_mat_with_transpose_t MT, fmpz_sparse_mat_t M) +{ + slong r, c, j; + MT->M = M; + + /* Construct virtual transpose */ + MT->cols = flint_calloc(M->c, sizeof(*MT->cols)); + for (r = 0; r < M->r; ++r) + for (j = 0; j < M->rows[r].nnz; ++j) + if (M->rows[r].entries[j].ind < M->c) + MT->cols[M->rows[r].entries[j].ind].num++; + for (c = 0; c < M->c; ++c) + hashmap_init(&MT->cols[c], MT->cols[c].num); + for (r = 0; r < M->r; ++r) + for (j = 0; j < M->rows[r].nnz; ++j) + if (M->rows[r].entries[j].ind < M->c) + hashmap_put(&MT->cols[M->rows[r].entries[j].ind], r, &M->rows[r].entries[j].val); +} diff --git a/fmpz_sparse_vec.h b/fmpz_sparse_vec.h new file mode 100644 index 0000000000..d25568ff0f --- /dev/null +++ b/fmpz_sparse_vec.h @@ -0,0 +1,446 @@ +/* + Copyright (C) 2010 William Hart + Copyright (C) 2010,2011 Fredrik Johansson + Copyright (C) 2014 Ashish Kedia + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef FMPZ_SPARSE_VEC_H +#define FMPZ_SPARSE_VEC_H + +#ifdef FMPZ_SPARSE_VEC_INLINES_C +#define FMPZ_SPARSE_VEC_INLINE FLINT_DLL +#else +#define FMPZ_SPARSE_VEC_INLINE static __inline__ +#endif + +#undef ulong +#define ulong ulongxx /* interferes with system includes */ +#include +#include +#undef ulong +#include +#define ulong mp_limb_t + +#include "flint.h" +#include "longlong.h" +#include "ulong_extras.h" +#include "nmod_sparse_vec.h" +#include "fmpz_vec.h" +#include "fmpz.h" +#include "thread_support.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct { + slong ind; + fmpz_t val; +} fmpz_sparse_entry_struct; + +typedef fmpz_sparse_entry_struct fmpz_sparse_entry_t[1]; + +typedef struct { + fmpz_sparse_entry_struct *entries; + slong nnz; +} fmpz_sparse_vec_struct; + +typedef fmpz_sparse_vec_struct fmpz_sparse_vec_t[1]; + +FMPZ_SPARSE_VEC_INLINE +int fmpz_sparse_entry_cmp(const void *va, const void *vb) +{ + const fmpz_sparse_entry_struct *a = va; + const fmpz_sparse_entry_struct *b = vb; + if (a->ind < b->ind) return -1; + if (b->ind < a->ind) return 1; + return 0; +} + +/* Memory management */ +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_init(fmpz_sparse_vec_t vec) +{ + memset(vec, 0, sizeof(*vec)); +} + +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_clear(fmpz_sparse_vec_t vec) +{ + slong i; + for (i = 0; i < vec->nnz; ++i) + fmpz_clear(vec->entries[i].val); + flint_free(vec->entries); + memset(vec, 0, sizeof(*vec)); +} + +FMPZ_SPARSE_VEC_INLINE +void _fmpz_sparse_vec_resize(fmpz_sparse_vec_t vec, slong nnz) +{ + slong i; + FLINT_ASSERT(nnz >= 0); + if (nnz == 0) fmpz_sparse_vec_clear(vec); + else if (nnz != vec->nnz) + { + for (i = nnz; i < vec->nnz; ++i) + fmpz_clear (vec->entries[i].val); + vec->entries = flint_realloc(vec->entries, nnz*sizeof(*vec->entries)); + for (i = vec->nnz; i < nnz; ++i) + fmpz_init (vec->entries[i].val); + } + vec->nnz = nnz; +} + +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_resize(fmpz_sparse_vec_t vec, slong cols) +{ + slong i; + FLINT_ASSERT(cols >= 0); + if (vec->nnz == 0) return; + for (i = 0; i < vec->nnz; ++i) { + if (vec->entries[i].ind >= cols) + { + break; + } + } + _fmpz_sparse_vec_resize(vec, i); +} + +FMPZ_SPARSE_VEC_INLINE +slong _fmpz_sparse_vec_support(slong **supp, fmpz_sparse_vec_t vec) +{ + slong i; + *supp = flint_malloc(vec->nnz*sizeof(**supp)); + for (i = 0; i < vec->nnz; ++i) (*supp)[i] = vec->entries[i].ind; + return vec->nnz; +} +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_swap(fmpz_sparse_vec_t vec1, fmpz_sparse_vec_t vec2) +{ + fmpz_sparse_vec_t tmp; + *tmp = *vec1, *vec1 = *vec2, *vec2 = *tmp; +} + +FLINT_DLL +slong fmpz_sparse_vec_max_bits(const fmpz_sparse_vec_t v); + +/* Vector indexing */ +FLINT_DLL +fmpz_t * fmpz_sparse_vec_at(const fmpz_sparse_vec_t vec, slong i); + +/* One-time instantiation */ +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_zero(fmpz_sparse_vec_t vec) +{ + fmpz_sparse_vec_clear(vec); +} + +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_one(fmpz_sparse_vec_t vec, slong ind) +{ + _fmpz_sparse_vec_resize(vec, 1); + vec->entries[0].ind = ind; + fmpz_one(vec->entries[0].val); +} + +FLINT_DLL +void fmpz_sparse_vec_set(fmpz_sparse_vec_t vec, const fmpz_sparse_vec_t src, slong ioff); + +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_set_entry(fmpz_sparse_vec_t v, slong ind, const fmpz_t val) +{ + fmpz_t * oval = fmpz_sparse_vec_at(v, ind); + if (oval == NULL) + { + _fmpz_sparse_vec_resize(v, v->nnz+1); + v->entries[v->nnz-1].ind = ind; + fmpz_set(v->entries[v->nnz-1].val, val); + if (v->nnz >= 2 && v->entries[v->nnz-2].ind > ind) + qsort(v->entries, v->nnz, sizeof(*v->entries), fmpz_sparse_entry_cmp); + } + else fmpz_set(*oval, val); +} + +FLINT_DLL +void fmpz_sparse_vec_from_entries(fmpz_sparse_vec_t vec, slong * inds, fmpz * vals, slong nnz); + +/* Vector comparison */ +FMPZ_SPARSE_VEC_INLINE +int fmpz_sparse_vec_is_zero(const fmpz_sparse_vec_t vec) +{ + return vec->nnz == 0; +} + +FLINT_DLL +int fmpz_sparse_vec_equal(const fmpz_sparse_vec_t vec1, const fmpz_sparse_vec_t vec2, slong ioff); + +/* Convert from/to dense vector */ +FLINT_DLL +void fmpz_sparse_vec_from_dense(fmpz_sparse_vec_t vec, const fmpz *src, slong len); + +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_to_dense(fmpz *vec, const fmpz_sparse_vec_t src, slong len) +{ + slong i; + _fmpz_vec_zero(vec, len); + for (i = 0; i < src->nnz; ++i) + if (src->entries[i].ind < len) + fmpz_set(&vec[src->entries[i].ind], src->entries[i].val); +} + +/* To/from modular vector(s) */ +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_get_nmod_sparse_vec(nmod_sparse_vec_t dst, const fmpz_sparse_vec_t src, const nmod_t mod) +{ + slong i, ind; + if (src->nnz == 0) + nmod_sparse_vec_zero(dst); + else + { + dst->entries = flint_realloc(dst->entries, src->nnz*sizeof(*dst->entries)); + for (i = ind = 0; i < src->nnz; ++i) + { + dst->entries[ind].ind = src->entries[i].ind; + dst->entries[ind].val = fmpz_fdiv_ui(src->entries[i].val, mod.n); + if (dst->entries[ind].val != UWORD(0)) ++ind; + } + if (ind == 0) + { + flint_free(dst->entries); + dst->entries = NULL; + } + else dst->entries = flint_realloc(dst->entries, ind*sizeof(*dst->entries)); + dst->nnz = ind; + } +} + +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_set_nmod_sparse_vec_unsigned(fmpz_sparse_vec_t dst, const nmod_sparse_vec_t src) +{ + slong i; + _fmpz_sparse_vec_resize(dst, src->nnz); + for (i = 0; i < src->nnz; ++i) + { + dst->entries[i].ind = src->entries[i].ind; + fmpz_set_ui(dst->entries[i].val, src->entries[i].val); + } +} + +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_set_nmod_sparse_vec(fmpz_sparse_vec_t dst, const nmod_sparse_vec_t src, const nmod_t mod) +{ + slong i; + _fmpz_sparse_vec_resize(dst, src->nnz); + for (i = 0; i < src->nnz; ++i) + { + dst->entries[i].ind = src->entries[i].ind; + fmpz_set_ui_smod(dst->entries[i].val, src->entries[i].val, mod.n); + } +} + +FLINT_DLL +void fmpz_sparse_vec_multi_mod_ui_precomp(nmod_sparse_vec_struct * residues, slong nres, const fmpz_sparse_vec_t v, + const fmpz_comb_t comb, fmpz_comb_temp_t temp); + +FLINT_DLL +void fmpz_sparse_vec_multi_mod_ui(nmod_sparse_vec_struct * residues, mp_srcptr primes, slong nres, const fmpz_sparse_vec_t v); + +FLINT_DLL +void fmpz_sparse_vec_CRT_ui(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_t m1, + const nmod_sparse_vec_t v, nmod_t m2, mp_limb_t m1i_m2, int sign); + +FLINT_DLL +void fmpz_sparse_vec_multi_CRT_ui_precomp(fmpz_sparse_vec_t v, nmod_sparse_vec_struct const * residues, slong nres, + const fmpz_comb_t comb, fmpz_comb_temp_t temp, int sign); + +FLINT_DLL +void fmpz_sparse_vec_multi_CRT_ui(fmpz_sparse_vec_t v, nmod_sparse_vec_struct * const residues, mp_srcptr primes, slong nres, int sign); + +/* Windows and concatenation */ +FLINT_DLL +void fmpz_sparse_vec_window_init(fmpz_sparse_vec_t window, const fmpz_sparse_vec_t vec, slong i1, slong i2); + + +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_window_clear(fmpz_sparse_vec_t window) +{ + memset(window, 0, sizeof(*window)); +} + +FLINT_DLL +void fmpz_sparse_vec_concat(fmpz_sparse_vec_t res, const fmpz_sparse_vec_t vec1, const fmpz_sparse_vec_t vec2, slong len1); + +FLINT_DLL +void fmpz_sparse_vec_split(fmpz_sparse_vec_t res1, fmpz_sparse_vec_t res2, const fmpz_sparse_vec_t vec, slong ind); + +/* Vector permutation */ +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_permute_inds(fmpz_sparse_vec_t vec, slong *P) +{ + slong i; + for (i = 0; i < vec->nnz; ++i) vec->entries[i].ind = P[vec->entries[i].ind]; +} + +/* Random vector generation */ +FLINT_DLL +void fmpz_sparse_vec_randtest(fmpz_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, flint_bitcnt_t bits); + +FLINT_DLL +void fmpz_sparse_vec_randtest_unsigned(fmpz_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, flint_bitcnt_t bits); + +/* Vector display */ +FLINT_DLL +void fmpz_sparse_vec_print_pretty(const fmpz_sparse_vec_t vec, slong ioff, slong maxi); + +/* Vector operations */ +FMPZ_SPARSE_VEC_INLINE +void fmpz_sparse_vec_neg(fmpz_sparse_vec_t v, const fmpz_sparse_vec_t u) +{ + slong i; + fmpz_sparse_vec_set(v, u, 0); + for (i = 0; i < v->nnz; ++i) fmpz_neg(v->entries[i].val, v->entries[i].val); +} + +FLINT_DLL +void fmpz_sparse_vec_scalar_mul_fmpz(fmpz_sparse_vec_t v, const fmpz_sparse_vec_t u, const fmpz_t c); + +FLINT_DLL +void fmpz_sparse_vec_scalar_divexact_fmpz(fmpz_sparse_vec_t v, const fmpz_sparse_vec_t u, const fmpz_t c); + +FLINT_DLL +void fmpz_sparse_vec_scalar_mod_fmpz(fmpz_sparse_vec_t v, const fmpz_sparse_vec_t u, const fmpz_t mod); + +FLINT_DLL +void fmpz_sparse_vec_scalar_mods_fmpz(fmpz_sparse_vec_t v, const fmpz_sparse_vec_t u, const fmpz_t mod); + +/* Utility macros used by binary vector operations */ +/* Compute total number of indices between two sparse vectors */ +FMPZ_SPARSE_VEC_INLINE +slong _fmpz_sparse_vec_union_nnz(const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v) +{ + slong i, j, nnz = 0; + for (i = j = 0; i < u->nnz && j < v->nnz; ++nnz) + { + if (u->entries[i].ind == v->entries[j].ind) ++i, ++j; + else if (u->entries[i].ind < v->entries[j].ind) ++i; + else if (u->entries[i].ind > v->entries[j].ind) ++j; + } + nnz += u->nnz - i + v->nnz - j; + return nnz; +} + +/* Utility macros used by binary vector operations */ +/* Compute total number of indices between two sparse vectors */ +FMPZ_SPARSE_VEC_INLINE +slong _fmpz_sparse_vec_union_nnz_nmod(const fmpz_sparse_vec_t u, const nmod_sparse_vec_t v) +{ + slong i, j, nnz = 0; + for (i = j = 0; i < u->nnz && j < v->nnz; ++nnz) + { + if (u->entries[i].ind == v->entries[j].ind) ++i, ++j; + else if (u->entries[i].ind < v->entries[j].ind) ++i; + else if (u->entries[i].ind > v->entries[j].ind) ++j; + } + nnz += u->nnz - i + v->nnz - j; + return nnz; +} + +/* Iterate through u and v in descending order, assigning sorted indices to w */ +/* Returns -1 if u and v are both exhausted, + 2 if we->ind = ue->ind == ve->ind + 1 if we->ind = ve->ind > ue->ind (or u exhausted), + 0 if we->ind = ue->ind > ve->ind (or v exhausted). */ +FMPZ_SPARSE_VEC_INLINE +slong _fmpz_sparse_vector_merge_descend(fmpz_sparse_entry_struct **we, + fmpz_sparse_entry_struct **ue, + fmpz_sparse_entry_struct **ve, + const fmpz_sparse_vec_t u, + const fmpz_sparse_vec_t v) +{ + slong uind = (*ue==u->entries) ? -1 : (*ue-1)->ind; + slong vind = (*ve==v->entries) ? -1 : (*ve-1)->ind; + if (uind == -1 && vind == -1) return -1; + if (uind == vind) {--*ue, --*ve, --*we; (*we)->ind = uind; return 2;} + if (uind < vind) {--*ve, --*we; (*we)->ind = vind; return 1;} + --*ue, --*we; (*we)->ind = uind; return 0; +} + +/* Iterate through u and v in descending order, assigning sorted indices to w */ +/* Returns -1 if u and v are both exhausted, + 2 if we->ind = ue->ind == ve->ind + 1 if we->ind = ve->ind > ue->ind (or u exhausted), + 0 if we->ind = ue->ind > ve->ind (or v exhausted). */ +FMPZ_SPARSE_VEC_INLINE +slong _fmpz_sparse_vector_merge_descend_nmod(fmpz_sparse_entry_struct **we, + fmpz_sparse_entry_struct **ue, + nmod_sparse_entry_struct **ve, + const fmpz_sparse_vec_t u, + const nmod_sparse_vec_t v) +{ + slong uind = (*ue==u->entries) ? -1 : (*ue-1)->ind; + slong vind = (*ve==v->entries) ? -1 : (*ve-1)->ind; + if (uind == -1 && vind == -1) return -1; + if (uind == vind) {--*ue, --*ve, --*we; (*we)->ind = uind; return 2;} + if (uind < vind) {--*ve, --*we; (*we)->ind = vind; return 1;} + --*ue, --*we; (*we)->ind = uind; return 0; +} + +/* Like resize, but removes entries from the front of the vector */ +FMPZ_SPARSE_VEC_INLINE +void _fmpz_sparse_vector_shift_left (fmpz_sparse_vec_t v, slong amt) +{ + slong i; + if (amt == v->nnz) fmpz_sparse_vec_clear(v); + else if (amt > 0) + { + for (i = amt; i < v->nnz; ++i) + { + v->entries[i-amt].ind = v->entries[i].ind; + fmpz_set(v->entries[i - amt].val, v->entries[i].val); + } + _fmpz_sparse_vec_resize(v, v->nnz - amt); + } +} + +FLINT_DLL +void fmpz_sparse_vec_add(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v); + +FLINT_DLL +void fmpz_sparse_vec_sub(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v); + +FLINT_DLL +void fmpz_sparse_vec_scalar_addmul_fmpz(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v, const fmpz_t c); + +FLINT_DLL +void fmpz_sparse_vec_scalar_submul_fmpz(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v, const fmpz_t c); + +FLINT_DLL +void fmpz_sparse_vec_dot(fmpz_t ret, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v); + +FLINT_DLL +void fmpz_sparse_vec_dot_dense(fmpz_t ret, const fmpz_sparse_vec_t u, const fmpz *v); + +/* Gaussian elimination operations */ +FLINT_DLL +void fmpz_sparse_vec_gauss_elim_col(fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v, slong col); + +FLINT_DLL +void fmpz_sparse_vec_gauss_elim(fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v); + +FLINT_DLL +void fmpz_sparse_vec_gauss_elim_ext(fmpz_sparse_vec_t u, fmpz_sparse_vec_t v); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/fmpz_sparse_vec/CRT_ui.c b/fmpz_sparse_vec/CRT_ui.c new file mode 100644 index 0000000000..ed34f7616f --- /dev/null +++ b/fmpz_sparse_vec/CRT_ui.c @@ -0,0 +1,39 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "nmod_sparse_vec.h" +#include "fmpz_sparse_vec.h" + +void +fmpz_sparse_vec_CRT_ui(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_t m1, + const nmod_sparse_vec_t v, nmod_t m2, mp_limb_t m1i_m2, int sign) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + fmpz_sparse_entry_struct *ue, *we; + nmod_sparse_entry_struct *ve; + fmpz_t m1m2, zero; + fmpz_init(m1m2); + fmpz_init_set_ui(zero, UWORD(0)); + fmpz_mul_ui(m1m2, m1, m2.n); + + wnnz = _fmpz_sparse_vec_union_nnz_nmod (u, v); + _fmpz_sparse_vec_resize(w, wnnz); + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _fmpz_sparse_vector_merge_descend_nmod (&we, &ue, &ve, u, v)) >= 0) + { + _fmpz_CRT_ui_precomp(we->val, (k==1)?zero:ue->val, m1, (k==0)?UWORD(0):ve->val, + m2.n, m2.ninv, m1m2, m1i_m2, sign); + } + fmpz_clear(zero); + fmpz_clear(m1m2); +} + diff --git a/fmpz_sparse_vec/add.c b/fmpz_sparse_vec/add.c new file mode 100644 index 0000000000..82248c5091 --- /dev/null +++ b/fmpz_sparse_vec/add.c @@ -0,0 +1,43 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_add(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + fmpz_sparse_entry_struct *ue, *ve, *we; + + /* Check for simpler operations first */ + if (vnnz == 0) fmpz_sparse_vec_set(w, u, 0); + else if (unnz == 0) fmpz_sparse_vec_set(w, v, 0); + else + { + wnnz = _fmpz_sparse_vec_union_nnz (u, v); + _fmpz_sparse_vec_resize(w, wnnz); + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _fmpz_sparse_vector_merge_descend (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: fmpz_set(we->val, ue->val); break; + case 1: fmpz_set(we->val, ve->val); break; + default: fmpz_add(we->val, ue->val, ve->val); + if (fmpz_is_zero(we->val)) we++; + } + } + _fmpz_sparse_vector_shift_left (w, we - w->entries); + } +} diff --git a/fmpz_sparse_vec/at.c b/fmpz_sparse_vec/at.c new file mode 100644 index 0000000000..78bc8443fe --- /dev/null +++ b/fmpz_sparse_vec/at.c @@ -0,0 +1,27 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +fmpz_t *fmpz_sparse_vec_at(const fmpz_sparse_vec_t vec, slong i) +{ + /* TODO: binary search */ + slong j; + for (j = 0; j < vec->nnz; ++j) + if (vec->entries[j].ind==i) return &vec->entries[j].val; + return NULL; +} + diff --git a/fmpz_sparse_vec/concat.c b/fmpz_sparse_vec/concat.c new file mode 100644 index 0000000000..2ec111ad27 --- /dev/null +++ b/fmpz_sparse_vec/concat.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_concat(fmpz_sparse_vec_t res, const fmpz_sparse_vec_t vec1, const fmpz_sparse_vec_t vec2, slong len1) +{ + slong i, nnz = vec1->nnz + vec2->nnz; + _fmpz_sparse_vec_resize (res, nnz); + for (i = 0; i < nnz; ++i) + { + fmpz_sparse_entry_struct *e = (i < vec1->nnz) ? &vec1->entries[i] : &vec2->entries[i-vec1->nnz]; + res->entries[i].ind = e->ind + ((i < vec1->nnz) ? 0 : len1); + fmpz_set (res->entries[i].val, e->val); + } +} diff --git a/fmpz_sparse_vec/dot.c b/fmpz_sparse_vec/dot.c new file mode 100644 index 0000000000..63750299c3 --- /dev/null +++ b/fmpz_sparse_vec/dot.c @@ -0,0 +1,33 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_dot(fmpz_t ret, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v) +{ + slong i, j; + fmpz_zero(ret); + for (i = j = 0; i < u->nnz && j < v->nnz; ) + { + if (u->entries[i].ind == v->entries[j].ind) + { + fmpz_addmul(ret, u->entries[i].val, v->entries[j].val); + ++i; ++j; + } + else if (u->entries[i].ind < v->entries[j].ind) ++i; + else if (u->entries[i].ind > v->entries[j].ind) ++j; + } +} diff --git a/fmpz_sparse_vec/dot_dense.c b/fmpz_sparse_vec/dot_dense.c new file mode 100644 index 0000000000..1ac529bd80 --- /dev/null +++ b/fmpz_sparse_vec/dot_dense.c @@ -0,0 +1,25 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_dot_dense(fmpz_t ret, const fmpz_sparse_vec_t u, const fmpz *v) +{ + slong i; + fmpz_zero(ret); + for (i = 0; i < u->nnz; ++i) fmpz_addmul(ret, u->entries[i].val, &v[u->entries[i].ind]); + +} diff --git a/fmpz_sparse_vec/equal.c b/fmpz_sparse_vec/equal.c new file mode 100644 index 0000000000..aec8f682d8 --- /dev/null +++ b/fmpz_sparse_vec/equal.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +int fmpz_sparse_vec_equal(const fmpz_sparse_vec_t vec1, const fmpz_sparse_vec_t vec2, slong ioff) +{ + slong i; + if (vec1->nnz != vec2->nnz) return 0; + for (i = 0; i < vec1->nnz; ++i) + { + if ((vec1->entries[i].ind != vec2->entries[i].ind + ioff) || + (!fmpz_equal(vec1->entries[i].val, vec2->entries[i].val))) return 0; + } + return 1; +} diff --git a/fmpz_sparse_vec/from_dense.c b/fmpz_sparse_vec/from_dense.c new file mode 100644 index 0000000000..1689816c05 --- /dev/null +++ b/fmpz_sparse_vec/from_dense.c @@ -0,0 +1,30 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_from_dense(fmpz_sparse_vec_t dst, const fmpz *src, slong len) +{ + slong i, nnz = 0; + fmpz_sparse_entry_struct *e; + for (i = 0; i < len; ++i) + if (!fmpz_is_zero(&src[i])) ++nnz; + _fmpz_sparse_vec_resize(dst, nnz); + e = dst->entries; + for (i = 0; i < len; ++i) + if (!fmpz_is_zero(&src[i])) + e->ind = i, fmpz_set(e->val, &src[i]), ++e; +} \ No newline at end of file diff --git a/fmpz_sparse_vec/from_entries.c b/fmpz_sparse_vec/from_entries.c new file mode 100644 index 0000000000..4dd16974f3 --- /dev/null +++ b/fmpz_sparse_vec/from_entries.c @@ -0,0 +1,31 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_from_entries(fmpz_sparse_vec_t vec, slong * inds, fmpz * vals, slong nnz) +{ + if (nnz == 0) fmpz_sparse_vec_clear(vec); + else { + slong i; + _fmpz_sparse_vec_resize(vec, nnz); + for (i = 0; i < nnz; ++i) + { + vec->entries[i].ind = inds[i]; + fmpz_set(vec->entries[i].val, &vals[i]); + } + } +} diff --git a/fmpz_sparse_vec/gauss_elim.c b/fmpz_sparse_vec/gauss_elim.c new file mode 100644 index 0000000000..a36dae5755 --- /dev/null +++ b/fmpz_sparse_vec/gauss_elim.c @@ -0,0 +1,122 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +/* Reduce u by v */ +void fmpz_sparse_vec_gauss_elim_col(fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v, slong col) +{ + fmpz_t q; + fmpz_t *uc = fmpz_sparse_vec_at(u, col); + fmpz_t *vc = fmpz_sparse_vec_at(v, col); + if (uc == NULL || vc == NULL) return; + + fmpz_init(q); + fmpz_fdiv_q(q, *uc, *vc); + fmpz_sparse_vec_scalar_submul_fmpz(u, u, v, q); + fmpz_clear(q); +} + +/* Reduce u by v */ +void fmpz_sparse_vec_gauss_elim(fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v) +{ + fmpz_t q, *uc; + fmpz_sparse_entry_struct *lu = u->entries, *lv = v->entries; + if (u->nnz == 0 || v->nnz == 0 || lu->ind > lv->ind) return; + fmpz_init(q); + if (lu->ind == lv->ind) fmpz_fdiv_q(q, lu->val, lv->val); + else if ((uc = fmpz_sparse_vec_at(u, lv->ind))) fmpz_fdiv_q(q, *uc, lv->val); + fmpz_sparse_vec_scalar_submul_fmpz(u, u, v, q); + fmpz_clear(q); +} + +/* Apply unimodular transformation to (u,v) to minimize both vectors lexicographically */ +void fmpz_sparse_vec_gauss_elim_ext(fmpz_sparse_vec_t u, fmpz_sparse_vec_t v) +{ + slong vnnz = v->nnz, unnz = u->nnz, nnz, k; + fmpz_sparse_entry_struct *lu = u->entries; + fmpz_sparse_entry_struct *lv = v->entries; + fmpz_t g, vv, vu, uv, uu, a, b; + fmpz_sparse_entry_struct *ue, *ve, *nue, *nve; + if (u->nnz == 0 || v->nnz == 0) return; + if (lu->ind != lv->ind) {fmpz_sparse_vec_gauss_elim(u, v); return;} + if (fmpz_cmpabs(lu->val, lv->val) < 0) /* Pre-apply transform [[0, -1], [1, 0]] */ + { + fmpz_sparse_vec_swap(u, v); + fmpz_sparse_vec_neg(u, u); + lu = u->entries, lv = v->entries; + vnnz = v->nnz, unnz = u->nnz; + } + if (fmpz_sgn(lv->val) < 0) /* Pre-apply transform [[-1, 0], [0, -1]] */ + { + fmpz_sparse_vec_neg(v, v); + fmpz_sparse_vec_neg(u, u); + } + + /* Check for trivial cases */ + if (fmpz_divisible(lu->val, lv->val)) {fmpz_sparse_vec_gauss_elim(u, v); return;} + + fmpz_init(g); + fmpz_init(vv); + fmpz_init(vu); + fmpz_init(uv); + fmpz_init(uu); + fmpz_init(a); + fmpz_init(b); + + /* Construct transformation */ + fmpz_xgcd(g, vv, vu, lv->val, lu->val); + if (fmpz_sgn(g) < 0) + { + fmpz_neg(vv, vv); + fmpz_neg(vu, vu); + } + fmpz_divexact(uu, lv->val, g); + fmpz_divexact(uv, lu->val, g); + fmpz_neg(uv, uv); /* [[uu uv] [vu vv]] is unimodular */ + + /* Reallocate vectors */ + nnz = _fmpz_sparse_vec_union_nnz (u, v); + _fmpz_sparse_vec_resize(u, nnz); + _fmpz_sparse_vec_resize(v, nnz); + ue = u->entries + unnz, ve = v->entries + vnnz; /* Old locations */ + nue = u->entries + nnz, nve = v->entries + nnz; /* New locations */ + while ((k = _fmpz_sparse_vector_merge_descend (&nue, &ue, &ve, u, v)) >= 0) + { + nve--; + switch(k) + { + case 0: nve->ind = ue->ind; fmpz_mul(nve->val, ue->val, vu); fmpz_mul(nue->val, ue->val, uu); break; + case 1: nve->ind = ve->ind; fmpz_mul(nue->val, ve->val, uv); fmpz_mul(nve->val, ve->val, vv); break; + default: nve->ind = ve->ind; + fmpz_set(a, ve->val); + fmpz_set(b, ue->val); + fmpz_mul(nve->val, a, vv); fmpz_addmul(nve->val, b, vu); + fmpz_mul(nue->val, b, uu); fmpz_addmul(nue->val, a, uv); + } + if (fmpz_is_zero(nue->val)) nue++; + if (fmpz_is_zero(nve->val)) nve++; + } + _fmpz_sparse_vector_shift_left (u, nue - u->entries); + _fmpz_sparse_vector_shift_left (v, nve - v->entries); + fmpz_clear(g); + fmpz_clear(vv); + fmpz_clear(vu); + fmpz_clear(uv); + fmpz_clear(uu); + fmpz_clear(a); + fmpz_clear(b); +} diff --git a/fmpz_sparse_vec/max_bits.c b/fmpz_sparse_vec/max_bits.c new file mode 100644 index 0000000000..e49ba507ea --- /dev/null +++ b/fmpz_sparse_vec/max_bits.c @@ -0,0 +1,79 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + + +slong fmpz_sparse_vec_max_bits(const fmpz_sparse_vec_t v) +{ + slong i, sign, max_limbs; + mp_limb_t max_limb; + mp_size_t limbs; + + sign = 1; + max_limb = 0; + + for (i = 0; i < v->nnz; i++) + { + fmpz c = *(v->entries[i].val); + + if (c >= 0) + { + if (c > COEFF_MAX) + goto bignum; + max_limb |= c; + } + else + { + if (c < COEFF_MIN) + goto bignum; + max_limb |= -c; + sign = -1; + } + } + return sign * FLINT_BIT_COUNT(max_limb); + +bignum: + max_limbs = 1; + + for ( ; i < v->nnz; i++) + { + fmpz c = *(v->entries[i].val); + + if (COEFF_IS_MPZ(c)) + { + __mpz_struct * z = COEFF_TO_PTR(c); + limbs = z->_mp_size; + + if (limbs < 0) + { + sign = -1; + limbs = -limbs; + } + + if (limbs == max_limbs) + max_limb |= z->_mp_d[limbs - 1]; + else if (limbs > max_limbs) + { + max_limb = z->_mp_d[limbs - 1]; + max_limbs = limbs; + } + } + else if (c < 0) + sign = -1; + } + return sign * ((max_limbs - 1) * FLINT_BITS + FLINT_BIT_COUNT(max_limb)); +} \ No newline at end of file diff --git a/fmpz_sparse_vec/multi_CRT_ui.c b/fmpz_sparse_vec/multi_CRT_ui.c new file mode 100644 index 0000000000..2e47171933 --- /dev/null +++ b/fmpz_sparse_vec/multi_CRT_ui.c @@ -0,0 +1,69 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_vec.h" + +void +fmpz_sparse_vec_multi_CRT_ui_precomp(fmpz_sparse_vec_t v, nmod_sparse_vec_struct const * residues, slong nres, + const fmpz_comb_t comb, fmpz_comb_temp_t temp, int sign) +{ + slong j, pos, *rpos, max_nnz, max_ind; + mp_limb_t *r; + fmpz_sparse_entry_struct *e; + + for (j = max_nnz = max_ind = 0; j < nres; ++j) + { + max_nnz = FLINT_MAX(max_nnz, residues[j].nnz); + if (residues[j].nnz != 0) max_ind = FLINT_MAX(max_ind, residues[j].entries[residues[j].nnz - 1].ind); + } + _fmpz_sparse_vec_resize(v, max_nnz); /* May change later */ + if (max_nnz == 0) return; + + rpos = flint_calloc(nres, sizeof(*rpos)); + r = flint_malloc(nres * sizeof (*r)); + for (pos = 0; ; ++pos) + { + if (pos == max_nnz) max_nnz *= 2, _fmpz_sparse_vec_resize(v, max_nnz); + e = &v->entries[pos]; + + /* Get next minimal index */ + e->ind = max_ind + 1; + for (j = 0; j < nres; ++j) + { + e->ind = (rpos[j] != residues[j].nnz && residues[j].entries[rpos[j]].ind < e->ind) ? residues[j].entries[rpos[j]].ind : e->ind; + } + if (e->ind == max_ind + 1) break; + for (j = 0; j < nres; ++j) + { + r[j] = (rpos[j] != residues[j].nnz && residues[j].entries[rpos[j]].ind == e->ind) ? residues[j].entries[rpos[j]++].val : 0; + } + fmpz_multi_CRT_ui(e->val, r, comb, temp, sign); + } + _fmpz_sparse_vec_resize(v, pos); + flint_free(rpos); + flint_free(r); +} + +void +fmpz_sparse_vec_multi_CRT_ui(fmpz_sparse_vec_t v, nmod_sparse_vec_struct * const residues, mp_srcptr primes, slong nres, int sign) +{ + fmpz_comb_t comb; + fmpz_comb_temp_t temp; + + fmpz_comb_init(comb, primes, nres); + fmpz_comb_temp_init(temp, comb); + + fmpz_sparse_vec_multi_CRT_ui_precomp(v, residues, nres, comb, temp, sign); + + fmpz_comb_clear(comb); + fmpz_comb_temp_clear(temp); +} diff --git a/fmpz_sparse_vec/multi_mod_ui.c b/fmpz_sparse_vec/multi_mod_ui.c new file mode 100644 index 0000000000..c52f665f75 --- /dev/null +++ b/fmpz_sparse_vec/multi_mod_ui.c @@ -0,0 +1,63 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fmpz_sparse_vec.h" + +/* for (j = 0; j < fmpz_vec_ncols(vec); j++) + { + + for (k = 0; k < nres; k++) + nmod_vec_entry(residues[k], i, j) = r[k]; + } + */ +void +fmpz_sparse_vec_multi_mod_ui_precomp(nmod_sparse_vec_struct * residues, slong nres, const fmpz_sparse_vec_t v, + const fmpz_comb_t comb, fmpz_comb_temp_t temp) +{ + slong i, j; + nmod_sparse_entry_struct *e; + nmod_sparse_vec_struct *vm; + mp_limb_t *r; + + r = flint_malloc(nres * sizeof(*r)); + + for (j = 0; j < nres; ++j) + vm = &residues[j], vm->entries = realloc(vm->entries, v->nnz * sizeof(*vm->entries)), vm->nnz = 0; + + for (i = 0; i < v->nnz; i++) + { + fmpz_multi_mod_ui(r, v->entries[i].val, comb, temp); + for (j = 0; j < nres; ++j) + if (r[j] != UWORD(0)) + e = &residues[j].entries[residues[j].nnz++], e->ind = v->entries[i].ind, e->val = r[j]; + } + + for (j = 0; j < nres; ++j) + vm = &residues[j], vm->entries = realloc(vm->entries, vm->nnz * sizeof(*vm->entries)); + + flint_free(r); +} + +void +fmpz_sparse_vec_multi_mod_ui(nmod_sparse_vec_struct * residues, mp_srcptr primes, slong nres, const fmpz_sparse_vec_t v) +{ + fmpz_comb_t comb; + fmpz_comb_temp_t temp; + + fmpz_comb_init(comb, primes, nres); + fmpz_comb_temp_init(temp, comb); + + fmpz_sparse_vec_multi_mod_ui_precomp(residues, nres, v, comb, temp); + + fmpz_comb_clear(comb); + fmpz_comb_temp_clear(temp); +} diff --git a/fmpz_sparse_vec/print_pretty.c b/fmpz_sparse_vec/print_pretty.c new file mode 100644 index 0000000000..059237302d --- /dev/null +++ b/fmpz_sparse_vec/print_pretty.c @@ -0,0 +1,37 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +void +fmpz_sparse_vec_print_pretty(const fmpz_sparse_vec_t vec, slong ioff, slong maxi) +{ + slong i; + char ind_fmt[FLINT_BITS + 5]; + + flint_sprintf(ind_fmt, "%%%dwd:", n_sizeinbase(maxi, 10)); + + flint_printf("["); + for (i = 0; i < vec->nnz; i++) + { + flint_printf(ind_fmt, vec->entries[i].ind - ioff); + fmpz_print(vec->entries[i].val); + if (i + 1 < vec->nnz) flint_printf(" "); + } + flint_printf("]\n"); +} + diff --git a/fmpz_sparse_vec/randtest.c b/fmpz_sparse_vec/randtest.c new file mode 100644 index 0000000000..9a46c0a7df --- /dev/null +++ b/fmpz_sparse_vec/randtest.c @@ -0,0 +1,38 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_randtest(fmpz_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, flint_bitcnt_t bits) +{ + slong i, j; + nnz = FLINT_MIN(nnz, len); + _fmpz_sparse_vec_resize(vec, nnz); + for (i = 0; i < nnz; ++i) + { + vec->entries[i].ind = i; + do fmpz_randtest(vec->entries[i].val, state, bits); + while (fmpz_is_zero(vec->entries[i].val)); + } + + /* Use resevoir sampling to get random support */ + for (j = nnz; j < len; ++j) + { + i = n_randint(state, j+1); + if (i < nnz) vec->entries[i].ind = j; + } + qsort(vec->entries, nnz, sizeof(*vec->entries), fmpz_sparse_entry_cmp); +} diff --git a/fmpz_sparse_vec/randtest_unsigned.c b/fmpz_sparse_vec/randtest_unsigned.c new file mode 100644 index 0000000000..457e1486c3 --- /dev/null +++ b/fmpz_sparse_vec/randtest_unsigned.c @@ -0,0 +1,38 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_randtest_unsigned(fmpz_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, flint_bitcnt_t bits) +{ + slong i, j; + nnz = FLINT_MIN(nnz, len); + _fmpz_sparse_vec_resize(vec, nnz); + for (i = 0; i < nnz; ++i) + { + vec->entries[i].ind = i; + do fmpz_randtest_unsigned(vec->entries[i].val, state, bits); + while (fmpz_is_zero(vec->entries[i].val)); + } + + /* Use resevoir sampling to get random support */ + for (j = nnz; j < len; ++j) + { + i = n_randint(state, j+1); + if (i < nnz) vec->entries[i].ind = j; + } + qsort(vec->entries, nnz, sizeof(*vec->entries), fmpz_sparse_entry_cmp); +} diff --git a/fmpz_sparse_vec/scalar_addmul.c b/fmpz_sparse_vec/scalar_addmul.c new file mode 100644 index 0000000000..df39c6aaaf --- /dev/null +++ b/fmpz_sparse_vec/scalar_addmul.c @@ -0,0 +1,50 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_scalar_addmul_fmpz(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v, const fmpz_t c) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + fmpz_t tmp; + fmpz_sparse_entry_struct *ue, *ve, *we; + + /* Check for simpler operations first */ + if (fmpz_is_zero(c) || vnnz == 0) fmpz_sparse_vec_set(w, u, 0); + else if (fmpz_is_one(c)) fmpz_sparse_vec_add(w, u, v); + else if (fmpz_equal_si(c, WORD(-1))) fmpz_sparse_vec_sub(w, u, v); + else if (unnz == 0) fmpz_sparse_vec_scalar_mul_fmpz(w, v, c); + else + { + fmpz_init(tmp); + wnnz = _fmpz_sparse_vec_union_nnz (u, v); + _fmpz_sparse_vec_resize(w, wnnz); + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _fmpz_sparse_vector_merge_descend (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: fmpz_set(we->val, ue->val); break; + case 1: fmpz_mul(we->val, ve->val, c); break; + default: fmpz_mul(tmp, ve->val, c); + fmpz_add(we->val, ue->val, tmp); + if (fmpz_is_zero(we->val)) we++; + } + } + _fmpz_sparse_vector_shift_left (w, we - w->entries); + fmpz_clear(tmp); + } +} diff --git a/fmpz_sparse_vec/scalar_divexact.c b/fmpz_sparse_vec/scalar_divexact.c new file mode 100644 index 0000000000..c584202c97 --- /dev/null +++ b/fmpz_sparse_vec/scalar_divexact.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_scalar_divexact_fmpz(fmpz_sparse_vec_t v, const fmpz_sparse_vec_t u, const fmpz_t c) +{ + if (fmpz_is_one(c)) fmpz_sparse_vec_set(v, u, 0); + else if (fmpz_equal_si(c, WORD(-1))) fmpz_sparse_vec_neg(v, u); + else + { + slong i; + fmpz_sparse_vec_set(v, u, 0); + for (i = 0; i < v->nnz; ++i) fmpz_divexact(v->entries[i].val, v->entries[i].val, c); + } +} \ No newline at end of file diff --git a/fmpz_sparse_vec/scalar_mod.c b/fmpz_sparse_vec/scalar_mod.c new file mode 100644 index 0000000000..5fce2ba885 --- /dev/null +++ b/fmpz_sparse_vec/scalar_mod.c @@ -0,0 +1,34 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_scalar_mod_fmpz(fmpz_sparse_vec_t v, const fmpz_sparse_vec_t u, const fmpz_t mod) +{ + if (fmpz_is_one(mod)) fmpz_sparse_vec_zero(v); + else + { + slong i, ind; + fmpz_sparse_vec_set(v, u, 0); + for (i = ind = 0; i < v->nnz; ++i) + { + v->entries[ind].ind = v->entries[i].ind; + fmpz_mod(v->entries[ind].val, v->entries[i].val, mod); + if (!fmpz_is_zero(v->entries[ind].val)) ++ind; + } + _fmpz_sparse_vec_resize(v, ind); + } +} \ No newline at end of file diff --git a/fmpz_sparse_vec/scalar_mods.c b/fmpz_sparse_vec/scalar_mods.c new file mode 100644 index 0000000000..94c8409069 --- /dev/null +++ b/fmpz_sparse_vec/scalar_mods.c @@ -0,0 +1,34 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_scalar_mods_fmpz(fmpz_sparse_vec_t v, const fmpz_sparse_vec_t u, const fmpz_t mod) +{ + if (fmpz_is_one(mod)) fmpz_sparse_vec_zero(v); + else + { + slong i, ind; + fmpz_sparse_vec_set(v, u, 0); + for (i = ind = 0; i < v->nnz; ++i) + { + v->entries[ind].ind = v->entries[i].ind; + fmpz_smod(v->entries[ind].val, v->entries[i].val, mod); + if (!fmpz_is_zero(v->entries[ind].val)) ++ind; + } + _fmpz_sparse_vec_resize(v, ind); + } +} \ No newline at end of file diff --git a/fmpz_sparse_vec/scalar_mul.c b/fmpz_sparse_vec/scalar_mul.c new file mode 100644 index 0000000000..e51ea0dace --- /dev/null +++ b/fmpz_sparse_vec/scalar_mul.c @@ -0,0 +1,30 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_scalar_mul_fmpz(fmpz_sparse_vec_t v, const fmpz_sparse_vec_t u, const fmpz_t c) +{ + if (fmpz_is_zero(c)) fmpz_sparse_vec_zero(v); + else if (fmpz_is_one(c)) fmpz_sparse_vec_set(v, u, 0); + else if (fmpz_equal_si(c, WORD(-1))) fmpz_sparse_vec_neg(v, u); + else + { + slong i; + fmpz_sparse_vec_set(v, u, 0); + for (i = 0; i < v->nnz; ++i) fmpz_mul(v->entries[i].val, v->entries[i].val, c); + } +} \ No newline at end of file diff --git a/fmpz_sparse_vec/scalar_submul.c b/fmpz_sparse_vec/scalar_submul.c new file mode 100644 index 0000000000..82c9860a8a --- /dev/null +++ b/fmpz_sparse_vec/scalar_submul.c @@ -0,0 +1,74 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_scalar_submul_fmpz(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v, const fmpz_t c) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + fmpz_t tmp, tmp2; + fmpz_sparse_entry_struct *ue, *ve, *we; + +/* flint_printf("c = "), fmpz_print(c); flint_printf("\n"); */ + /* Check for simpler operations first */ + if (fmpz_is_zero(c) || vnnz == 0) fmpz_sparse_vec_set(w, u, 0); + else if (fmpz_is_one(c)) fmpz_sparse_vec_sub(w, u, v); + else if (fmpz_equal_si(c, WORD(-1))) fmpz_sparse_vec_add(w, u, v); + else if (unnz == 0) + { + fmpz_sparse_vec_scalar_mul_fmpz(w, v, c); + fmpz_sparse_vec_neg(w, w); + } + else + { + fmpz_init(tmp); + fmpz_init_set(tmp2, c); + wnnz = _fmpz_sparse_vec_union_nnz (u, v); + _fmpz_sparse_vec_resize(w, wnnz); + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + /* flint_printf("c = "), fmpz_print(c); flint_printf(": %wd\n", c[0]); */ + while ((k = _fmpz_sparse_vector_merge_descend (&we, &ue, &ve, u, v)) >= 0) + { +/* flint_printf("\t\t\tc = "), fmpz_print(c); flint_printf("\n"); + flint_printf("\t\t\ttmp = %wd, tmp2 = %wd\n", tmp[0], tmp2[0]); */ + switch(k) + { + case 0: fmpz_set(we->val, ue->val); break; + case 1: fmpz_mul(we->val, ve->val, tmp2); fmpz_neg(we->val, we->val); break; + default: +/* flint_printf("\t\tSubtracting: "); + fmpz_print(we->val); flint_printf(" <- "); + fmpz_print(ue->val); flint_printf("-"); + fmpz_print(ve->val); flint_printf("*"); fmpz_print(c); flint_printf("\n"); + flint_printf("%wd <- %wd - %wd * %wd\n", we->val[0], ue->val[0], ve->val[0], c[0]); + flint_printf("c1: "); fmpz_print(c); flint_printf("\n"); */ + fmpz_mul(tmp, ve->val, tmp2); +/* flint_printf("%wd = %wd * %wd\n", tmp[0], ve->val[0], c[0]); + flint_printf("c2: "); fmpz_print(c); flint_printf("\n"); */ + fmpz_sub(we->val, ue->val, tmp); +/* flint_printf("%wd = %wd - %wd, %wd\n", we->val[0], ue->val[0], tmp[0], c[0]); + flint_printf("c3: "); fmpz_print(c); flint_printf("\n"); */ + if (fmpz_is_zero(we->val)) we++; +/* flint_printf("c4: "); fmpz_print(c); flint_printf("\n"); */ + } +/* flint_printf("\t\tAfter subtraction: %wd, %wd\n", k, we->ind); + flint_printf("\t\t\tr: "); fmpz_sparse_vec_print_pretty(w, 0, 0); flint_printf("\n"); */ + } + _fmpz_sparse_vector_shift_left (w, we - w->entries); + fmpz_clear(tmp); + fmpz_clear(tmp2); + } +} diff --git a/fmpz_sparse_vec/set.c b/fmpz_sparse_vec/set.c new file mode 100644 index 0000000000..6e84f479db --- /dev/null +++ b/fmpz_sparse_vec/set.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_set(fmpz_sparse_vec_t dst, const fmpz_sparse_vec_t src, slong ioff) +{ + slong i; + if (dst == src) return; + _fmpz_sparse_vec_resize(dst, src->nnz); + for (i = 0; i < dst->nnz; ++i) + { + dst->entries[i].ind = src->entries[i].ind - ioff; + fmpz_set(dst->entries[i].val, src->entries[i].val); + } +} \ No newline at end of file diff --git a/fmpz_sparse_vec/split.c b/fmpz_sparse_vec/split.c new file mode 100644 index 0000000000..6a3582cfc0 --- /dev/null +++ b/fmpz_sparse_vec/split.c @@ -0,0 +1,34 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_split(fmpz_sparse_vec_t res1, fmpz_sparse_vec_t res2, const fmpz_sparse_vec_t vec, slong ind) +{ + slong i, nnz1; + fmpz_sparse_entry_struct *e1, *e2, *e; + for (nnz1 = 0; nnz1 < vec->nnz; ++nnz1) if (vec->entries[nnz1].ind >= ind) break; + + _fmpz_sparse_vec_resize(res1, nnz1); + _fmpz_sparse_vec_resize(res2, vec->nnz - nnz1); + e1 = res1->entries, e2 = res2->entries; + for (i = 0; i < vec->nnz; ++i) + { + e = (i < nnz1) ? e1++ : e2++; + e->ind = vec->entries[i].ind - ((i < nnz1) ? 0 : ind); + fmpz_set(e->val, vec->entries[i].val); + } +} diff --git a/fmpz_sparse_vec/sub.c b/fmpz_sparse_vec/sub.c new file mode 100644 index 0000000000..f0dfe72e06 --- /dev/null +++ b/fmpz_sparse_vec/sub.c @@ -0,0 +1,44 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_sub(fmpz_sparse_vec_t w, const fmpz_sparse_vec_t u, const fmpz_sparse_vec_t v) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + fmpz_sparse_entry_struct *ue, *ve, *we; + + /* Check for simpler operations first */ + if (vnnz == 0) fmpz_sparse_vec_set(w, u, 0); + else if (unnz == 0) fmpz_sparse_vec_neg(w, v); + else + { + wnnz = _fmpz_sparse_vec_union_nnz (u, v); + _fmpz_sparse_vec_resize(w, wnnz); + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _fmpz_sparse_vector_merge_descend (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: fmpz_set(we->val, ue->val); break; + case 1: fmpz_neg(we->val, ve->val); break; + default: fmpz_sub(we->val, ue->val, ve->val); + if (fmpz_is_zero(we->val)) we++; + } + } + _fmpz_sparse_vector_shift_left (w, we - w->entries); + } +} diff --git a/fmpz_sparse_vec/test/t-add.c b/fmpz_sparse_vec/test/t-add.c new file mode 100644 index 0000000000..797afc9aee --- /dev/null +++ b/fmpz_sparse_vec/test/t-add.c @@ -0,0 +1,83 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz; + fmpz_sparse_vec_t u, v, w, x; + + FLINT_TEST_INIT(state); + + flint_printf("add/sub...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 256); + while (bits < UWORD(2)); + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + fmpz_sparse_vec_init(w); + fmpz_sparse_vec_init(x); + + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_randtest(v, state, nnz, len, bits); + + fmpz_sparse_vec_add(w, u, v); + fmpz_sparse_vec_sub(x, w, v); + + if (!fmpz_sparse_vec_equal(u, x, 0)) + { + flint_printf("FAIL: u != u+v-v\n"); + flint_printf("u = "), fmpz_sparse_vec_print_pretty(u, 0, 0); + flint_printf("v = "), fmpz_sparse_vec_print_pretty(v, 0, 0); + flint_printf("w = "), fmpz_sparse_vec_print_pretty(w, 0, 0); + flint_printf("x = "), fmpz_sparse_vec_print_pretty(x, 0, 0); + abort(); + } + + fmpz_sparse_vec_add(u, u, v); + if (!fmpz_sparse_vec_equal(u, w, 0)) + { + flint_printf("FAIL: (u += v) != u + v\n"); + abort(); + } + + fmpz_sparse_vec_sub(u, u, v); + if (!fmpz_sparse_vec_equal(u, x, 0)) + { + flint_printf("FAIL: ((u += v) -= v) != u+v-v\n"); + abort(); + } + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + fmpz_sparse_vec_clear(w); + fmpz_sparse_vec_clear(x); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-concat.c b/fmpz_sparse_vec/test/t-concat.c new file mode 100644 index 0000000000..3a1dbd483e --- /dev/null +++ b/fmpz_sparse_vec/test/t-concat.c @@ -0,0 +1,98 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +int main(void) +{ + slong rep, bits, len, nnz; + fmpz_sparse_vec_t u, v, w; + fmpz_sparse_vec_t window1, window2; + FLINT_TEST_INIT(state); + + flint_printf("concat...."); + fflush(stdout); + + for (rep = 0; rep < 100; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + fmpz_sparse_vec_init(w); + + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_randtest(v, state, nnz, len, bits); + fmpz_sparse_vec_randtest(w, state, nnz, len, bits); + + fmpz_sparse_vec_concat(w, u, v, len); + + fmpz_sparse_vec_window_init(window1, w, 0, len); + fmpz_sparse_vec_window_init(window2, w, len, 2*len); + + if (!(fmpz_sparse_vec_equal(window1, u, 0) && fmpz_sparse_vec_equal(window2, v, len))) + { + flint_printf("u = "); + fmpz_sparse_vec_print_pretty(u, 0, len); + flint_printf("v = \n"); + fmpz_sparse_vec_print_pretty(v, 0, len); + flint_printf("u | v = \n"); + fmpz_sparse_vec_print_pretty(w, 0, len); + flint_printf("window1 = \n"); + fmpz_sparse_vec_print_pretty(window1, 0, len); + flint_printf("window2 = \n"); + fmpz_sparse_vec_print_pretty(window2, len, len); + flint_printf("FAIL: results not equal\n"); + abort(); + } + fmpz_sparse_vec_window_clear(window1); + fmpz_sparse_vec_window_clear(window2); + + fmpz_sparse_vec_init(window1); + fmpz_sparse_vec_init(window2); + fmpz_sparse_vec_split(window1, window2, w, len); + if (!(fmpz_sparse_vec_equal(window1, u, 0) && fmpz_sparse_vec_equal(window2, v, 0))) + { + flint_printf("u = "); + fmpz_sparse_vec_print_pretty(u, 0, len); + flint_printf("v = \n"); + fmpz_sparse_vec_print_pretty(v, 0, len); + flint_printf("u | v = \n"); + fmpz_sparse_vec_print_pretty(w, 0, len); + flint_printf("window1 = \n"); + fmpz_sparse_vec_print_pretty(window1, 0, len); + flint_printf("window2 = \n"); + fmpz_sparse_vec_print_pretty(window2, 0, len); + flint_printf("FAIL: results not equal\n"); + abort(); + } + fmpz_sparse_vec_clear(window1); + fmpz_sparse_vec_clear(window2); + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + fmpz_sparse_vec_clear(w); + } + + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-construct.c b/fmpz_sparse_vec/test/t-construct.c new file mode 100644 index 0000000000..fdc2381532 --- /dev/null +++ b/fmpz_sparse_vec/test/t-construct.c @@ -0,0 +1,76 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz, i; + fmpz_sparse_vec_t u, v; + slong *inds; + fmpz *vals; + FLINT_TEST_INIT(state); + + flint_printf("construction from elements...."); + fflush(stdout); + + for (rep = 0; rep < 1; rep++) + { + do bits = n_randint(state, 100); + while (bits < UWORD(2)); + len = n_randint(state, 10); + nnz = n_randint(state, len+1); + + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_randtest(v, state, nnz, len, bits); + + /* Construct v from entries of u */ + inds = flint_malloc(nnz * sizeof(*inds)); + vals = flint_malloc(nnz * sizeof(*vals)); + for (i = 0; i < nnz; ++i) + { + fmpz_init(&vals[i]); + inds[i] = u->entries[i].ind; + fmpz_set(&vals[i], u->entries[i].val); + } + fmpz_sparse_vec_from_entries(v, inds, vals, nnz); + + if (!fmpz_sparse_vec_equal(u, v, 0)) + { + fmpz_sparse_vec_print_pretty(u, 0, 0); + fmpz_sparse_vec_print_pretty(v, 0, 0); + abort(); + } + flint_free(inds); + for (i = 0; i < nnz; ++i) + { + fmpz_clear(&vals[i]); + } + flint_free(vals); + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-dense.c b/fmpz_sparse_vec/test/t-dense.c new file mode 100644 index 0000000000..ce84cffa53 --- /dev/null +++ b/fmpz_sparse_vec/test/t-dense.c @@ -0,0 +1,84 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz, i; + fmpz_sparse_vec_t u, v; + fmpz *w, *x; + FLINT_TEST_INIT(state); + + flint_printf("conversion to/from dense vector...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + w = _fmpz_vec_init(len); + x = _fmpz_vec_init(len); + + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_randtest(v, state, nnz, len, bits); + + fmpz_sparse_vec_to_dense(w, u, len); + fmpz_sparse_vec_from_dense(v, w, len); + + for (i = 0; i < len; ++i) + { + fmpz_t *val = fmpz_sparse_vec_at(u, i); + if ((fmpz_is_zero(&w[i]) && val != NULL) || (!fmpz_is_zero(&w[i]) && (val == NULL || !fmpz_equal(*val, &w[i])))) + { + flint_printf("FAIL: u[%wd] != v[%wd]\n", i, i); + abort(); + } + } + if (!fmpz_sparse_vec_equal(u, v, 0)) + { + flint_printf("FAIL: u != v\n"); + abort(); + } + + _fmpz_vec_randtest(w, state, len, bits); + fmpz_sparse_vec_from_dense(u, w, len); + fmpz_sparse_vec_to_dense(x, u, len); + + if (!_fmpz_vec_equal(w, x, len)) + { + flint_printf("FAIL: w != x\n"); + abort(); + } + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + _fmpz_vec_clear(w, len); + _fmpz_vec_clear(x, len); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-dot.c b/fmpz_sparse_vec/test/t-dot.c new file mode 100644 index 0000000000..87be4e5b20 --- /dev/null +++ b/fmpz_sparse_vec/test/t-dot.c @@ -0,0 +1,81 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz; + fmpz_t a, b; + fmpz_sparse_vec_t u, v; + fmpz *w, *x; + FLINT_TEST_INIT(state); + + + flint_printf("dot product...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + + fmpz_init(a); + fmpz_init(b); + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + w = _fmpz_vec_init(len); + x = _fmpz_vec_init(len); + + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_randtest(v, state, nnz, len, bits); + fmpz_sparse_vec_to_dense(w, u, len); + fmpz_sparse_vec_to_dense(x, v, len); + + fmpz_sparse_vec_dot(a, u, v); + _fmpz_vec_dot(b, w, x, len); + + if (!fmpz_equal(a, b)) + { + flint_printf("Fail: sparse dot sparse\n"); + abort(); + } + + fmpz_sparse_vec_dot_dense(a, u, x); + + if (!fmpz_equal(a, b)) + { + flint_printf("Fail: sparse dot dense\n"); + abort(); + } + fmpz_clear(a); + fmpz_clear(b); + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + _fmpz_vec_clear(w, len); + _fmpz_vec_clear(x, len); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-gauss_elim.c b/fmpz_sparse_vec/test/t-gauss_elim.c new file mode 100644 index 0000000000..0b60a408c4 --- /dev/null +++ b/fmpz_sparse_vec/test/t-gauss_elim.c @@ -0,0 +1,133 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "fmpz_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz; + fmpz_t a, b, c, d, g; + fmpz_sparse_vec_t u, v, w, x, y; + FLINT_TEST_INIT(state); + + flint_printf("Gaussian elimination...."); + fflush(stdout); + + for (rep = 0; rep < 10; rep++) + { + do bits = n_randint(state, 10); + while (bits < UWORD(2)); + len = n_randint(state, 20); + nnz = n_randint(state, len+1); + + fmpz_init(a); + fmpz_init(b); + fmpz_init(c); + fmpz_init(d); + fmpz_init(g); + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + fmpz_sparse_vec_init(w); + fmpz_sparse_vec_init(x); + fmpz_sparse_vec_init(y); + + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_randtest(v, state, nnz, len, bits); + fmpz_sparse_vec_set(w, u, 0); + fmpz_sparse_vec_set(x, v, 0); + fmpz_sparse_vec_gauss_elim(x, w); + if (!fmpz_sparse_vec_equal(w, u, 0)) + { + flint_printf("FAIL: pivot row modified\n"); + abort(); + } + if (nnz != 0 && fmpz_sparse_vec_at(v, u->entries[0].ind) != NULL) + { + /* Undo elimination and check if matches original */ + fmpz_fdiv_q(c, *fmpz_sparse_vec_at(v, u->entries[0].ind), u->entries[0].val); + fmpz_sparse_vec_scalar_addmul_fmpz(w, x, u, c); + if (!fmpz_sparse_vec_equal(w, v, 0)) + { + flint_printf("FAIL: Incorrect Gaussian elimination\n"); + fmpz_sparse_vec_print_pretty(u, 0, len); + fmpz_sparse_vec_print_pretty(v, 0, len); + fmpz_sparse_vec_print_pretty(x, 0, len); + fmpz_sparse_vec_print_pretty(w, 0, len); + abort(); + } + } + else if (!fmpz_sparse_vec_equal(x, v, 0)) + { + flint_printf("FAIL: Incorrect Gaussian elimination on trivial vectors\n"); + fmpz_sparse_vec_print_pretty(x, 0, len); + abort(); + } + + if (nnz != 0 && u->entries[0].ind == v->entries[0].ind) + { + fmpz_sparse_vec_set(w, u, 0); + fmpz_sparse_vec_set(x, v, 0); + fmpz_sparse_vec_gauss_elim_ext(x, w); + + fmpz_xgcd(g, a, b, u->entries[0].val, v->entries[0].val); + fmpz_divexact(d, u->entries[0].val, g); + fmpz_divexact(c, v->entries[0].val, g); + fmpz_sparse_vec_scalar_mul_fmpz(y, w, d); + fmpz_sparse_vec_scalar_submul_fmpz(y, y, x, b); + if (!fmpz_sparse_vec_equal(y, u, 0)) + { + flint_printf("FAIL: did not recover u when inverting extended Gaussian elimination\n"); + fmpz_sparse_vec_print_pretty(u, 0, len); + fmpz_sparse_vec_print_pretty(v, 0, len); + fmpz_sparse_vec_print_pretty(w, 0, len); + fmpz_sparse_vec_print_pretty(x, 0, len); + fmpz_sparse_vec_print_pretty(y, 0, len); + abort(); + } + fmpz_sparse_vec_scalar_mul_fmpz(y, w, c); + fmpz_sparse_vec_scalar_addmul_fmpz(y, y, x, a); + if (!fmpz_sparse_vec_equal(y, v, 0)) + { + flint_printf("FAIL: did not recover v when inverting extended Gaussian elimination\n"); + fmpz_sparse_vec_print_pretty(u, 0, len); + fmpz_sparse_vec_print_pretty(v, 0, len); + fmpz_sparse_vec_print_pretty(w, 0, len); + fmpz_sparse_vec_print_pretty(x, 0, len); + fmpz_sparse_vec_print_pretty(y, 0, len); + abort(); + } + } + fmpz_clear(a); + fmpz_clear(b); + fmpz_clear(c); + fmpz_clear(d); + fmpz_clear(g); + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + fmpz_sparse_vec_clear(w); + fmpz_sparse_vec_clear(x); + fmpz_sparse_vec_clear(y); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-init_clear.c b/fmpz_sparse_vec/test/t-init_clear.c new file mode 100644 index 0000000000..27deb5c8cd --- /dev/null +++ b/fmpz_sparse_vec/test/t-init_clear.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +static void check_zero(fmpz_sparse_vec_t vec) +{ + if (vec->nnz != UWORD(0)) +{ + flint_printf("FAIL: nnz not zero!\n"); + abort(); + } + if (vec->entries != NULL) +{ + flint_printf("FAIL: entries not null!\n"); + abort(); + } +} + +int +main(void) +{ + slong rep, len, nnz, bits, i; + fmpz_sparse_vec_t vec; + FLINT_TEST_INIT(state); + + flint_printf("init/clear...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + fmpz_sparse_vec_init(vec); + check_zero(vec); + + fmpz_sparse_vec_randtest(vec, state, nnz, len, bits); + + if (nnz == 0) check_zero(vec); + else + { + for (i = 0; i < nnz; ++i) + { + fmpz_sparse_entry_struct *e = &vec->entries[i]; + if (e->ind >= len) + { + flint_printf("FAIL: found index %wd >= %wd!\n", e->ind, len); + abort(); + } + if (fmpz_is_zero(e->val)) + { + flint_printf("FAIL: found zero value\n"); + abort(); + } + if (i > 0 && e->ind <= e[-1].ind) + { + flint_printf("FAIL: found index %wd <= previous index %wd\n", e->ind, e[-1].ind); + abort(); + } + } + } + + fmpz_sparse_vec_clear(vec); + check_zero(vec); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-max_bits.c b/fmpz_sparse_vec/test/t-max_bits.c new file mode 100644 index 0000000000..eceff4a41e --- /dev/null +++ b/fmpz_sparse_vec/test/t-max_bits.c @@ -0,0 +1,68 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, mbits, max_bits, len, nnz, i; + fmpz_sparse_vec_t u; + FLINT_TEST_INIT(state); + + flint_printf("max bits...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + mbits = fmpz_sparse_vec_max_bits(u); + mbits = FLINT_ABS(mbits); + + max_bits = 0; + for (i = 0; i < nnz; ++i) + { + bits = fmpz_bits(u->entries[i].val); + if (bits > mbits) + { + flint_printf("FAIL: entry %wd has bitcnt %wd, max was %wd\n", i, bits, mbits); + fmpz_sparse_vec_print_pretty(u, 0, len); + abort(); + } + if (bits > max_bits) max_bits = bits; + } + if (mbits != max_bits) + { + flint_printf("FAIL: no entry has bitcnt %wd\n", mbits); + fmpz_sparse_vec_print_pretty(u, 0, len); + abort(); + } + fmpz_sparse_vec_clear(u); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-neg.c b/fmpz_sparse_vec/test/t-neg.c new file mode 100644 index 0000000000..18c4bf2f50 --- /dev/null +++ b/fmpz_sparse_vec/test/t-neg.c @@ -0,0 +1,75 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz; + fmpz_sparse_vec_t u, v, w, x; + FLINT_TEST_INIT(state); + + + flint_printf("neg...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + fmpz_sparse_vec_init(w); + fmpz_sparse_vec_init(x); + + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_randtest(v, state, nnz, len, bits); + + fmpz_sparse_vec_sub(w, u, v); + fmpz_sparse_vec_neg(v, v); + fmpz_sparse_vec_add(x, u, v); + + if (!fmpz_sparse_vec_equal(w, x, 0)) + { + flint_printf("FAIL: u - v != u + (-v)\n"); + abort(); + } + + fmpz_sparse_vec_neg(w, u); + fmpz_sparse_vec_neg(u, u); + + if (!fmpz_sparse_vec_equal(w, w, 0)) + { + flint_printf("FAIL\n"); + abort(); + } + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + fmpz_sparse_vec_clear(w); + fmpz_sparse_vec_clear(x); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-nmod.c b/fmpz_sparse_vec/test/t-nmod.c new file mode 100644 index 0000000000..7e19fc03dc --- /dev/null +++ b/fmpz_sparse_vec/test/t-nmod.c @@ -0,0 +1,118 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz, i, j; + slong n, c; + nmod_t mod; + nmod_sparse_vec_t umod; + fmpz_sparse_vec_t u; + FLINT_TEST_INIT(state); + + + flint_printf("nmod...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 256); + while (bits < UWORD(2)); + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + + do n = n_randlimb(state); + while (n < UWORD(2)); + nmod_init(&mod, n); + + nmod_sparse_vec_init(umod); + fmpz_sparse_vec_init(u); + + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_get_nmod_sparse_vec(umod, u, mod); + + for (i = j = 0; i < u->nnz; ++i) + { + c = fmpz_fdiv_ui(u->entries[i].val, n); + if (c == UWORD(0)) continue; + if (u->entries[i].ind != umod->entries[j].ind) + { + flint_printf("Fail: v %% c has extra/missing entry\n"); + abort(); + } + if (c != umod->entries[j].val) + { + flint_printf("Fail: v %% c has incorrect entry\n"); + abort(); + } + ++j; + } + if (j != umod->nnz) + { + flint_printf("Fail: v %% c has incorrect number of nonzeroes\n"); + abort(); + } + + nmod_sparse_vec_randtest(umod, state, nnz, len, mod); + fmpz_sparse_vec_set_nmod_sparse_vec_unsigned(u, umod); + + for (i = 0; i < u->nnz; ++i) + { + if (u->entries[i].ind != umod->entries[i].ind || + fmpz_cmp_ui(u->entries[i].val, umod->entries[i].val)) + { + flint_printf("FAIL: u = umod has bad entry\n"); + abort(); + } + } + if (u->nnz != umod->nnz) + { + flint_printf("Fail: u = umod has bad length\n"); + abort(); + } + + fmpz_sparse_vec_set_nmod_sparse_vec(u, umod, mod); + + for (i = 0; i < u->nnz; ++i) + { + if (u->entries[i].ind != umod->entries[i].ind || + (fmpz_sgn(u->entries[i].val) > 0 && fmpz_cmp_ui(u->entries[i].val, umod->entries[i].val)) || + (fmpz_sgn(u->entries[i].val) < 0 && fmpz_cmp_si(u->entries[i].val, umod->entries[i].val - n))) + { + flint_printf("FAIL: su = umod has bad entry\n"); + abort(); + } + } + if (u->nnz != umod->nnz) + { + flint_printf("Fail: su = umod has bad length\n"); + abort(); + } + + fmpz_sparse_vec_clear(u); + nmod_sparse_vec_clear(umod); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-scalar_divexact.c b/fmpz_sparse_vec/test/t-scalar_divexact.c new file mode 100644 index 0000000000..06cca65702 --- /dev/null +++ b/fmpz_sparse_vec/test/t-scalar_divexact.c @@ -0,0 +1,91 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "fmpz_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz; + fmpz_t c; + fmpz_sparse_vec_t u, v, w; + FLINT_TEST_INIT(state); + + flint_printf("divexact...."); + fflush(stdout); + + for (rep = 0; rep < 1; rep++) + { + do bits = n_randint(state, 100); + while (bits < UWORD(2)); + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + + fmpz_init(c); + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + fmpz_sparse_vec_init(w); + + do fmpz_randtest(c, state, bits); + while (fmpz_is_zero(c)); + + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_randtest(v, state, nnz, len, bits); + + fmpz_sparse_vec_scalar_mul_fmpz(v, u, c); + fmpz_sparse_vec_scalar_divexact_fmpz(w, v, c); + + if (!fmpz_sparse_vec_equal(w, u, 0)) + { + flint_printf("FAIL: out of place c*v/c != v\n"); + flint_printf("rep = %wd, c = ", rep), fmpz_print(c), flint_printf("\n"); + fmpz_sparse_vec_print_pretty(u, 0, 0); + fmpz_sparse_vec_print_pretty(v, 0, 0); + fmpz_sparse_vec_print_pretty(w, 0, 0); + fmpz_clear(c); + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + fmpz_sparse_vec_clear(w); + abort(); + } + fmpz_sparse_vec_scalar_divexact_fmpz(v, v, c); + + if (!fmpz_sparse_vec_equal(v, u, 0)) + { + flint_printf("FAIL: in place c*v/c != v\n"); + flint_printf("c = "), fmpz_print(c), flint_printf("\n"); + fmpz_sparse_vec_print_pretty(u, 0, 0); + fmpz_sparse_vec_print_pretty(v, 0, 0); + fmpz_clear(c); + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + fmpz_sparse_vec_clear(w); + abort(); + } + fmpz_clear(c); + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + fmpz_sparse_vec_clear(w); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-scalar_mod.c b/fmpz_sparse_vec/test/t-scalar_mod.c new file mode 100644 index 0000000000..3f8d026a27 --- /dev/null +++ b/fmpz_sparse_vec/test/t-scalar_mod.c @@ -0,0 +1,161 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz, i, j; + fmpz_t mod, c; + fmpz_sparse_vec_t u, v; + FLINT_TEST_INIT(state); + + + flint_printf("mod...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 10); + while (bits < UWORD(3)); + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + + fmpz_init(mod); + fmpz_init(c); + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + + fmpz_randbits(mod, state, bits-1); + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + + fmpz_sparse_vec_scalar_mod_fmpz(v, u, mod); + + for (i = j = 0; i < u->nnz; ++i) + { + fmpz_mod(c, u->entries[i].val, mod); + if (fmpz_is_zero(c)) continue; + if (u->entries[i].ind != v->entries[j].ind) + { + flint_printf("Fail: v %% c has extra/missing entry\n"); + fmpz_sparse_vec_print_pretty(u, 0, len); + fmpz_print(mod); flint_printf("\n"); + fmpz_sparse_vec_print_pretty(v, 0, len); + abort(); + } + if (fmpz_cmp(c, v->entries[j].val) != 0) + { + flint_printf("Fail: v %% c has incorrect entry\n"); + abort(); + } + ++j; + } + if (j != v->nnz) + { + flint_printf("Fail: v %% c has incorrect number of nonzeroes\n"); + abort(); + } + + fmpz_sparse_vec_scalar_mods_fmpz(v, u, mod); + for (i = j = 0; i < u->nnz; ++i) + { + fmpz_smod(c, u->entries[i].val, mod); + if (fmpz_is_zero(c)) continue; + if (u->entries[i].ind != v->entries[j].ind) + { + flint_printf("Fail: v %%s c has extra/missing entry\n"); + fmpz_sparse_vec_print_pretty(u, 0, len); + fmpz_print(mod); flint_printf("\n"); + fmpz_sparse_vec_print_pretty(v, 0, len); + abort(); + } + if (fmpz_cmp(c, v->entries[j].val) != 0) + { + flint_printf("Fail: v %%s c has incorrect entry\n"); + abort(); + } + ++j; + } + if (j != v->nnz) + { + flint_printf("Fail: v %%s c has incorrect number of nonzeroes\n"); + abort(); + } + + fmpz_sparse_vec_set(v, u, 0); + fmpz_sparse_vec_scalar_mod_fmpz(v, v, mod); + + for (i = j = 0; i < u->nnz; ++i) + { + fmpz_mod(c, u->entries[i].val, mod); + if (fmpz_is_zero(c)) continue; + if (u->entries[i].ind != v->entries[j].ind) + { + flint_printf("Fail: v %%= c has extra/missing entry\n"); + abort(); + } + if (fmpz_cmp(c, v->entries[j].val) != 0) + { + flint_printf("Fail: v %%= c has incorrect entry\n"); + abort(); + } + ++j; + } + if (j != v->nnz) + { + flint_printf("Fail: v %%= c has incorrect number of nonzeroes\n"); + abort(); + } + + fmpz_sparse_vec_set(v, u, 0); + fmpz_sparse_vec_scalar_mods_fmpz(v, v, mod); + + for (i = j = 0; i < u->nnz; ++i) + { + fmpz_smod(c, u->entries[i].val, mod); + if (fmpz_is_zero(c)) continue; + if (u->entries[i].ind != v->entries[j].ind) + { + flint_printf("Fail: v %%s= c has extra/missing entry\n"); + abort(); + } + if (fmpz_cmp(c, v->entries[j].val) != 0) + { + flint_printf("Fail: v %%s= c has incorrect entry\n"); + abort(); + } + ++j; + } + if (j != v->nnz) + { + flint_printf("Fail: v %%s= c has incorrect number of nonzeroes\n"); + abort(); + } + + fmpz_clear(mod); + fmpz_clear(c); + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/test/t-scalar_mul.c b/fmpz_sparse_vec/test/t-scalar_mul.c new file mode 100644 index 0000000000..f4cdc116b0 --- /dev/null +++ b/fmpz_sparse_vec/test/t-scalar_mul.c @@ -0,0 +1,115 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" +#include "fmpz_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, bits, len, nnz; + fmpz_t c; + fmpz_sparse_vec_t u, v, w, x; + FLINT_TEST_INIT(state); + + flint_printf("scalar_mul and muladd...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + do bits = n_randint(state, 200); + while (bits < UWORD(2)); + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + + fmpz_init(c); + fmpz_sparse_vec_init(u); + fmpz_sparse_vec_init(v); + fmpz_sparse_vec_init(w); + fmpz_sparse_vec_init(x); + + fmpz_randtest(c, state, bits); + fmpz_sparse_vec_randtest(u, state, nnz, len, bits); + fmpz_sparse_vec_randtest(v, state, nnz, len, bits); + + fmpz_sparse_vec_scalar_addmul_fmpz(w, u, v, c); + fmpz_sparse_vec_scalar_mul_fmpz(x, v, c); + fmpz_sparse_vec_add(x, x, u); + + if (!fmpz_sparse_vec_equal(w, x, 0)) + { + flint_printf("FAIL: u + c*v != u + (c*v)\n"); + abort(); + } + + fmpz_sparse_vec_scalar_addmul_fmpz(w, u, v, c); + fmpz_sparse_vec_scalar_addmul_fmpz(u, u, v, c); + + if (!fmpz_sparse_vec_equal(u, w, 0)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + fmpz_sparse_vec_scalar_addmul_fmpz(w, u, v, c); + fmpz_sparse_vec_scalar_addmul_fmpz(v, u, v, c); + + if (!fmpz_sparse_vec_equal(v, w, 0)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + fmpz_sparse_vec_scalar_submul_fmpz(w, u, v, c); + fmpz_sparse_vec_scalar_submul_fmpz(u, u, v, c); + + if (!fmpz_sparse_vec_equal(u, w, 0)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + fmpz_sparse_vec_scalar_submul_fmpz(w, u, v, c); + fmpz_sparse_vec_scalar_submul_fmpz(v, u, v, c); + + if (!fmpz_sparse_vec_equal(v, w, 0)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + fmpz_sparse_vec_scalar_mul_fmpz(x, v, c); + fmpz_sparse_vec_scalar_mul_fmpz(v, v, c); + + if (!fmpz_sparse_vec_equal(v, x, 0)) + { + flint_printf("FAIL: c*v != (c *= v)\n"); + abort(); + } + fmpz_clear(c); + fmpz_sparse_vec_clear(u); + fmpz_sparse_vec_clear(v); + fmpz_sparse_vec_clear(w); + fmpz_sparse_vec_clear(x); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/fmpz_sparse_vec/window_init.c b/fmpz_sparse_vec/window_init.c new file mode 100644 index 0000000000..e85950d813 --- /dev/null +++ b/fmpz_sparse_vec/window_init.c @@ -0,0 +1,25 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "fmpz_sparse_vec.h" + +void fmpz_sparse_vec_window_init(fmpz_sparse_vec_t window, const fmpz_sparse_vec_t vec, slong i1, slong i2) +{ + slong start, end; + for (start = 0; start < vec->nnz && vec->entries[start].ind < i1; ++start); + for (end = vec->nnz; end > 0 && vec->entries[end-1].ind >= i2; --end); + window->entries = vec->entries + start; + window->nnz = end - start; +} diff --git a/fq_mat/addmul.c b/fq_mat/addmul.c new file mode 100644 index 0000000000..f2c0cf8b8e --- /dev/null +++ b/fq_mat/addmul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_mat_templates/addmul.c" +#undef CAP_T +#undef T diff --git a/fq_mat/mul_vec.c b/fq_mat/mul_vec.c new file mode 100644 index 0000000000..5927e18dff --- /dev/null +++ b/fq_mat/mul_vec.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_mat_templates/mul_vec.c" +#undef CAP_T +#undef T diff --git a/fq_mat/scalar_addmul.c b/fq_mat/scalar_addmul.c new file mode 100644 index 0000000000..7375dbb9a9 --- /dev/null +++ b/fq_mat/scalar_addmul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_mat_templates/scalar_addmul.c" +#undef CAP_T +#undef T diff --git a/fq_mat/scalar_mul.c b/fq_mat/scalar_mul.c new file mode 100644 index 0000000000..ba7f8885d9 --- /dev/null +++ b/fq_mat/scalar_mul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_mat_templates/scalar_mul.c" +#undef CAP_T +#undef T diff --git a/fq_mat/scalar_submul.c b/fq_mat/scalar_submul.c new file mode 100644 index 0000000000..6aad2e4767 --- /dev/null +++ b/fq_mat/scalar_submul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_mat_templates/scalar_submul.c" +#undef CAP_T +#undef T diff --git a/fq_mat/transpose.c b/fq_mat/transpose.c new file mode 100644 index 0000000000..4c8f61aef0 --- /dev/null +++ b/fq_mat/transpose.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_mat_templates/transpose.c" +#undef CAP_T +#undef T diff --git a/fq_mat_templates.h b/fq_mat_templates.h index 4454e4966f..718f1be7de 100644 --- a/fq_mat_templates.h +++ b/fq_mat_templates.h @@ -274,6 +274,10 @@ FLINT_DLL void TEMPLATE(T, mat_randtriu)(TEMPLATE(T, mat_t) mat, flint_rand_t st /* Transpose */ +FLINT_DLL void TEMPLATE(T, mat_transpose)(TEMPLATE(T, mat_t) B, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, ctx_t) ctx); + /* Addition and subtraction */ FLINT_DLL void TEMPLATE(T, mat_add)(TEMPLATE(T, mat_t) C, @@ -290,6 +294,12 @@ FLINT_DLL void TEMPLATE(T, mat_neg)(TEMPLATE(T, mat_t) B, const TEMPLATE(T, mat_t) A, const TEMPLATE(T, ctx_t) ctx); +FLINT_DLL void TEMPLATE(T, mat_addmul)(TEMPLATE(T, mat_t) D, + const TEMPLATE(T, mat_t) C, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, mat_t) B, + const TEMPLATE(T, ctx_t) ctx); + FLINT_DLL void TEMPLATE(T, mat_submul)(TEMPLATE(T, mat_t) D, const TEMPLATE(T, mat_t) C, const TEMPLATE(T, mat_t) A, @@ -298,6 +308,24 @@ FLINT_DLL void TEMPLATE(T, mat_submul)(TEMPLATE(T, mat_t) D, /* Scalar operations */ +FLINT_DLL void TEMPLATE(T, mat_scalar_mul)(TEMPLATE(T, mat_t) B, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL void TEMPLATE(T, mat_scalar_addmul)(TEMPLATE(T, mat_t) C, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, mat_t) B, + const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL void TEMPLATE(T, mat_scalar_submul)(TEMPLATE(T, mat_t) C, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, mat_t) B, + const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx); + + /* Multiplication */ FLINT_DLL void TEMPLATE(T, mat_mul)(TEMPLATE(T, mat_t) C, @@ -305,6 +333,11 @@ FLINT_DLL void TEMPLATE(T, mat_mul)(TEMPLATE(T, mat_t) C, const TEMPLATE(T, mat_t) B, const TEMPLATE(T, ctx_t) ctx); +FLINT_DLL void TEMPLATE(T, mat_mul_vec)(TEMPLATE(T, struct) *y, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, struct) *x, + const TEMPLATE(T, ctx_t) ctx); + FLINT_DLL void TEMPLATE(T, mat_mul_classical)(TEMPLATE(T, mat_t) C, const TEMPLATE(T, mat_t) A, const TEMPLATE(T, mat_t) B, diff --git a/fq_mat_templates/addmul.c b/fq_mat_templates/addmul.c new file mode 100644 index 0000000000..509a15d34e --- /dev/null +++ b/fq_mat_templates/addmul.c @@ -0,0 +1,32 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +void +TEMPLATE(T, mat_addmul) (TEMPLATE(T, mat_t) D, + const TEMPLATE(T, mat_t) C, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, mat_t) B, + const TEMPLATE(T, ctx_t) ctx) +{ + TEMPLATE(T, mat_t) tmp; + TEMPLATE(T, mat_init) (tmp, A->r, B->c, ctx); + TEMPLATE(T, mat_mul) (tmp, A, B, ctx); + TEMPLATE(T, mat_add) (D, C, tmp, ctx); + TEMPLATE(T, mat_clear) (tmp, ctx); +} + + +#endif diff --git a/fq_mat_templates/mul_vec.c b/fq_mat_templates/mul_vec.c new file mode 100644 index 0000000000..1bc400f9e2 --- /dev/null +++ b/fq_mat_templates/mul_vec.c @@ -0,0 +1,27 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +void +TEMPLATE(T, mat_mul_vec) (TEMPLATE(T, struct) *y, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, struct) *x, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < A->r; ++i) + _TEMPLATE(T, vec_dot) (&y[i], A->rows[i], x, A->c, ctx); +} + + +#endif diff --git a/fq_mat_templates/scalar_addmul.c b/fq_mat_templates/scalar_addmul.c new file mode 100644 index 0000000000..d4b1b03e7b --- /dev/null +++ b/fq_mat_templates/scalar_addmul.c @@ -0,0 +1,33 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +void +TEMPLATE(T, mat_scalar_addmul) (TEMPLATE(T, mat_t) C, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, mat_t) B, + const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < C->r; i++) + { + _TEMPLATE(T, vec_set) (C->rows[i], A->rows[i], A->c, ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (C->rows[i], B->rows[i], A->c, c, ctx); + } +} + + +#endif diff --git a/fq_mat_templates/scalar_mul.c b/fq_mat_templates/scalar_mul.c new file mode 100644 index 0000000000..a82d79899f --- /dev/null +++ b/fq_mat_templates/scalar_mul.c @@ -0,0 +1,31 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +void +TEMPLATE(T, mat_scalar_mul) (TEMPLATE(T, mat_t) B, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < B->r; i++) + { + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (B->rows[i], A->rows[i], A->c, c, ctx); + } +} + + +#endif diff --git a/fq_mat_templates/scalar_submul.c b/fq_mat_templates/scalar_submul.c new file mode 100644 index 0000000000..86765edb3b --- /dev/null +++ b/fq_mat_templates/scalar_submul.c @@ -0,0 +1,33 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +void +TEMPLATE(T, mat_scalar_submul) (TEMPLATE(T, mat_t) C, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, mat_t) B, + const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < C->r; i++) + { + _TEMPLATE(T, vec_set) (C->rows[i], A->rows[i], A->c, ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_submul, T)) (C->rows[i], B->rows[i], A->c, c, ctx); + } +} + + +#endif diff --git a/fq_mat_templates/transpose.c b/fq_mat_templates/transpose.c new file mode 100644 index 0000000000..9949348e23 --- /dev/null +++ b/fq_mat_templates/transpose.c @@ -0,0 +1,53 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +void +TEMPLATE(T, mat_transpose) (TEMPLATE(T, mat_t) B, + const TEMPLATE(T, mat_t) A, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i, j; + TEMPLATE(T, t) tmp; + + if (A == B) + { + TEMPLATE(T, init) (tmp, ctx); + for (i = 0; i < A->r; ++i) + { + for (j = i+1; j < A->c; ++j) + { + TEMPLATE(T, set) (tmp, &A->rows[i][j], ctx); + TEMPLATE(T, set) (&B->rows[i][j], &A->rows[j][i], ctx); + TEMPLATE(T, set) (&B->rows[j][i], tmp, ctx); + } + } + TEMPLATE(T, clear) (tmp, ctx); + } + else + { + for (i = 0; i < A->r; ++i) + { + for (j = 0; j < A->c; ++j) + { + TEMPLATE(T, set) (&B->rows[j][i], &A->rows[i][j], ctx); + } + } + } + +} + + +#endif diff --git a/fq_nmod_mat/addmul.c b/fq_nmod_mat/addmul.c new file mode 100644 index 0000000000..73dccd5e1f --- /dev/null +++ b/fq_nmod_mat/addmul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_mat_templates/addmul.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_mat/mul_vec.c b/fq_nmod_mat/mul_vec.c new file mode 100644 index 0000000000..4ab0ac9c23 --- /dev/null +++ b/fq_nmod_mat/mul_vec.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_mat_templates/mul_vec.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_mat/scalar_addmul.c b/fq_nmod_mat/scalar_addmul.c new file mode 100644 index 0000000000..3f5de0d064 --- /dev/null +++ b/fq_nmod_mat/scalar_addmul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_mat_templates/scalar_addmul.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_mat/scalar_mul.c b/fq_nmod_mat/scalar_mul.c new file mode 100644 index 0000000000..e7c41730a7 --- /dev/null +++ b/fq_nmod_mat/scalar_mul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_mat_templates/scalar_mul.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_mat/scalar_submul.c b/fq_nmod_mat/scalar_submul.c new file mode 100644 index 0000000000..e98442c63e --- /dev/null +++ b/fq_nmod_mat/scalar_submul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_mat_templates/scalar_submul.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_mat/transpose.c b/fq_nmod_mat/transpose.c new file mode 100644 index 0000000000..e50dc6f89a --- /dev/null +++ b/fq_nmod_mat/transpose.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_mat_templates/transpose.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat.h b/fq_nmod_sparse_mat.h new file mode 100644 index 0000000000..c84f117223 --- /dev/null +++ b/fq_nmod_sparse_mat.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2013 Mike Hansen + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef FQ_NMOD_SPARSE_MAT_H +#define FQ_NMOD_SPARSE_MAT_H + +#ifdef FQ_NMOD_SPARSE_MAT_INLINES_C +#define FQ_SPARSE_MAT_TEMPLATES_INLINE FLINT_DLL +#define FQ_NMOD_SPARSE_MAT_INLINE FLINT_DLL +#else +#define FQ_SPARSE_MAT_TEMPLATES_INLINE static __inline__ +#define FQ_NMOD_SPARSE_MAT_INLINE static __inline__ +#endif + + +#include "fq_nmod.h" +#include "fq_nmod_vec.h" +#include "fq_nmod_sparse_vec.h" +#include "fq_nmod_mat.h" + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates.h" +#undef CAP_T +#undef T + +#endif diff --git a/fq_nmod_sparse_mat/from_entries.c b/fq_nmod_sparse_mat/from_entries.c new file mode 100644 index 0000000000..ca0181ed26 --- /dev/null +++ b/fq_nmod_sparse_mat/from_entries.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2011 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/from_entries.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/inv.c b/fq_nmod_sparse_mat/inv.c new file mode 100644 index 0000000000..eb17ddb966 --- /dev/null +++ b/fq_nmod_sparse_mat/inv.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/inv.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/lu.c b/fq_nmod_sparse_mat/lu.c new file mode 100644 index 0000000000..b1dc772bed --- /dev/null +++ b/fq_nmod_sparse_mat/lu.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/lu.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/nullspace_block_lanczos.c b/fq_nmod_sparse_mat/nullspace_block_lanczos.c new file mode 100644 index 0000000000..5b4e5416f7 --- /dev/null +++ b/fq_nmod_sparse_mat/nullspace_block_lanczos.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/nullspace_block_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/nullspace_block_wiedemann.c b/fq_nmod_sparse_mat/nullspace_block_wiedemann.c new file mode 100644 index 0000000000..a1a1e2d597 --- /dev/null +++ b/fq_nmod_sparse_mat/nullspace_block_wiedemann.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/nullspace_block_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/nullspace_lanczos.c b/fq_nmod_sparse_mat/nullspace_lanczos.c new file mode 100644 index 0000000000..2d792bfb05 --- /dev/null +++ b/fq_nmod_sparse_mat/nullspace_lanczos.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/nullspace_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/nullspace_lu.c b/fq_nmod_sparse_mat/nullspace_lu.c new file mode 100644 index 0000000000..e2ebf8770c --- /dev/null +++ b/fq_nmod_sparse_mat/nullspace_lu.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/nullspace_lu.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/nullspace_rref.c b/fq_nmod_sparse_mat/nullspace_rref.c new file mode 100644 index 0000000000..1479456f60 --- /dev/null +++ b/fq_nmod_sparse_mat/nullspace_rref.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/nullspace_rref.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/nullspace_wiedemann.c b/fq_nmod_sparse_mat/nullspace_wiedemann.c new file mode 100644 index 0000000000..eb92c2dd6e --- /dev/null +++ b/fq_nmod_sparse_mat/nullspace_wiedemann.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/nullspace_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/print_pretty.c b/fq_nmod_sparse_mat/print_pretty.c new file mode 100644 index 0000000000..1850340b4f --- /dev/null +++ b/fq_nmod_sparse_mat/print_pretty.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/print_pretty.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/randtest.c b/fq_nmod_sparse_mat/randtest.c new file mode 100644 index 0000000000..4faa708f4f --- /dev/null +++ b/fq_nmod_sparse_mat/randtest.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/randtest.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/rref.c b/fq_nmod_sparse_mat/rref.c new file mode 100644 index 0000000000..d2124c45bd --- /dev/null +++ b/fq_nmod_sparse_mat/rref.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/rref.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/solve_block_lanczos.c b/fq_nmod_sparse_mat/solve_block_lanczos.c new file mode 100644 index 0000000000..57b0424fe9 --- /dev/null +++ b/fq_nmod_sparse_mat/solve_block_lanczos.c @@ -0,0 +1,28 @@ +/* + Copyright (C) 2020 Kartik Venkatram + + Algorithm taken from P. Montgomery, "A Block Lanczos Algorithm for + Finding Dependencies over GF(2)", Advances in Cryptology - EUROCRYPT '95 + + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/solve_block_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/solve_block_wiedemann.c b/fq_nmod_sparse_mat/solve_block_wiedemann.c new file mode 100644 index 0000000000..fdf88b21dc --- /dev/null +++ b/fq_nmod_sparse_mat/solve_block_wiedemann.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/solve_block_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/solve_lanczos.c b/fq_nmod_sparse_mat/solve_lanczos.c new file mode 100644 index 0000000000..5f55f50b77 --- /dev/null +++ b/fq_nmod_sparse_mat/solve_lanczos.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/solve_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/solve_lu.c b/fq_nmod_sparse_mat/solve_lu.c new file mode 100644 index 0000000000..310d98b1c1 --- /dev/null +++ b/fq_nmod_sparse_mat/solve_lu.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/solve_lu.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/solve_rref.c b/fq_nmod_sparse_mat/solve_rref.c new file mode 100644 index 0000000000..fc7f6deb37 --- /dev/null +++ b/fq_nmod_sparse_mat/solve_rref.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/solve_rref.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/solve_wiedemann.c b/fq_nmod_sparse_mat/solve_wiedemann.c new file mode 100644 index 0000000000..3b732c902f --- /dev/null +++ b/fq_nmod_sparse_mat/solve_wiedemann.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/solve_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-add.c b/fq_nmod_sparse_mat/test/t-add.c new file mode 100644 index 0000000000..3e96ab4964 --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-add.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-add.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-concat_horizontal.c b/fq_nmod_sparse_mat/test/t-concat_horizontal.c new file mode 100644 index 0000000000..e4b7afdb3e --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-concat_horizontal.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-concat_horizontal.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-concat_vertical.c b/fq_nmod_sparse_mat/test/t-concat_vertical.c new file mode 100644 index 0000000000..ed52ddd2d1 --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-concat_vertical.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-concat_vertical.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-construct.c b/fq_nmod_sparse_mat/test/t-construct.c new file mode 100644 index 0000000000..b8973155e9 --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-construct.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-construct.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-dense.c b/fq_nmod_sparse_mat/test/t-dense.c new file mode 100644 index 0000000000..da27a9ab68 --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-dense.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-dense.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-init_clear.c b/fq_nmod_sparse_mat/test/t-init_clear.c new file mode 100644 index 0000000000..b40e950776 --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-init_clear.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-init_clear.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-inv.c b/fq_nmod_sparse_mat/test/t-inv.c new file mode 100644 index 0000000000..36d3648729 --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-inv.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-inv.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-lu.c b/fq_nmod_sparse_mat/test/t-lu.c new file mode 100644 index 0000000000..7e4e75a6e8 --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-lu.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-lu.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-mul.c b/fq_nmod_sparse_mat/test/t-mul.c new file mode 100644 index 0000000000..654c1039fa --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-mul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-mul.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-neg.c b/fq_nmod_sparse_mat/test/t-neg.c new file mode 100644 index 0000000000..45b024b361 --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-neg.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-neg.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-nullspace.c b/fq_nmod_sparse_mat/test/t-nullspace.c new file mode 100644 index 0000000000..d561349e5c --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-nullspace.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-nullspace.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-rref.c b/fq_nmod_sparse_mat/test/t-rref.c new file mode 100644 index 0000000000..ba4aa88694 --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-rref.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-rref.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-scalar_mul.c b/fq_nmod_sparse_mat/test/t-scalar_mul.c new file mode 100644 index 0000000000..7c704d8f2e --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-scalar_mul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2011 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-scalar_mul.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-solve.c b/fq_nmod_sparse_mat/test/t-solve.c new file mode 100644 index 0000000000..5e8763aaee --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-solve.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-solve.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/test/t-transpose.c b/fq_nmod_sparse_mat/test/t-transpose.c new file mode 100644 index 0000000000..1392eca38a --- /dev/null +++ b/fq_nmod_sparse_mat/test/t-transpose.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/test/t-transpose.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/transpose.c b/fq_nmod_sparse_mat/transpose.c new file mode 100644 index 0000000000..7db5f5b7c9 --- /dev/null +++ b/fq_nmod_sparse_mat/transpose.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2011 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/transpose.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_mat/window_init.c b/fq_nmod_sparse_mat/window_init.c new file mode 100644 index 0000000000..bd8c3f34e7 --- /dev/null +++ b/fq_nmod_sparse_mat/window_init.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_mat_templates/window_init.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec.h b/fq_nmod_sparse_vec.h new file mode 100644 index 0000000000..a6037b3489 --- /dev/null +++ b/fq_nmod_sparse_vec.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2013 Mike Hansen + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef FQ_NMOD_SPARSE_VEC_H +#define FQ_NMOD_SPARSE_VEC_H + +#ifdef FQ_NMOD_SPARSE_VEC_INLINES_C +#define FQ_SPARSE_VEC_TEMPLATES_INLINE FLINT_DLL +#define FQ_NMOD_SPARSE_VEC_INLINE FLINT_DLL +#else +#define FQ_SPARSE_VEC_TEMPLATES_INLINE static __inline__ +#define FQ_NMOD_SPARSE_VEC_INLINE static __inline__ +#endif + +#include "fq_nmod.h" +#include "fq_nmod_vec.h" + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates.h" +#undef CAP_T +#undef T + +#endif diff --git a/fq_nmod_sparse_vec/add.c b/fq_nmod_sparse_vec/add.c new file mode 100644 index 0000000000..0b2952f536 --- /dev/null +++ b/fq_nmod_sparse_vec/add.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/add.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/print_pretty.c b/fq_nmod_sparse_vec/print_pretty.c new file mode 100644 index 0000000000..770eb351d5 --- /dev/null +++ b/fq_nmod_sparse_vec/print_pretty.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/print_pretty.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/randtest.c b/fq_nmod_sparse_vec/randtest.c new file mode 100644 index 0000000000..17b968995b --- /dev/null +++ b/fq_nmod_sparse_vec/randtest.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/randtest.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/scalar_addmul.c b/fq_nmod_sparse_vec/scalar_addmul.c new file mode 100644 index 0000000000..096833c1a8 --- /dev/null +++ b/fq_nmod_sparse_vec/scalar_addmul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/scalar_addmul.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/scalar_submul.c b/fq_nmod_sparse_vec/scalar_submul.c new file mode 100644 index 0000000000..1a2f5dc482 --- /dev/null +++ b/fq_nmod_sparse_vec/scalar_submul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/scalar_submul.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/sub.c b/fq_nmod_sparse_vec/sub.c new file mode 100644 index 0000000000..1ad014b2be --- /dev/null +++ b/fq_nmod_sparse_vec/sub.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/sub.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/test/t-add.c b/fq_nmod_sparse_vec/test/t-add.c new file mode 100644 index 0000000000..01a6e60300 --- /dev/null +++ b/fq_nmod_sparse_vec/test/t-add.c @@ -0,0 +1,21 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/test/t-add.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/test/t-concat.c b/fq_nmod_sparse_vec/test/t-concat.c new file mode 100644 index 0000000000..8253306aec --- /dev/null +++ b/fq_nmod_sparse_vec/test/t-concat.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/test/t-concat.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/test/t-construct.c b/fq_nmod_sparse_vec/test/t-construct.c new file mode 100644 index 0000000000..40e309f7ef --- /dev/null +++ b/fq_nmod_sparse_vec/test/t-construct.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/test/t-construct.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/test/t-dense.c b/fq_nmod_sparse_vec/test/t-dense.c new file mode 100644 index 0000000000..07fa2b09e5 --- /dev/null +++ b/fq_nmod_sparse_vec/test/t-dense.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/test/t-dense.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/test/t-dot.c b/fq_nmod_sparse_vec/test/t-dot.c new file mode 100644 index 0000000000..45d119f1f3 --- /dev/null +++ b/fq_nmod_sparse_vec/test/t-dot.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/test/t-dot.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/test/t-init_clear.c b/fq_nmod_sparse_vec/test/t-init_clear.c new file mode 100644 index 0000000000..607fa4e215 --- /dev/null +++ b/fq_nmod_sparse_vec/test/t-init_clear.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/test/t-init_clear.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/test/t-neg.c b/fq_nmod_sparse_vec/test/t-neg.c new file mode 100644 index 0000000000..b62369e249 --- /dev/null +++ b/fq_nmod_sparse_vec/test/t-neg.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/test/t-neg.c" +#undef CAP_T +#undef T diff --git a/fq_nmod_sparse_vec/test/t-scalar_mul.c b/fq_nmod_sparse_vec/test/t-scalar_mul.c new file mode 100644 index 0000000000..6a7ea91da8 --- /dev/null +++ b/fq_nmod_sparse_vec/test/t-scalar_mul.c @@ -0,0 +1,23 @@ +/* + wopyright (w) 2011 Fredrik Johansson + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_nmod_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_nmod +#define CAP_T FQ_NMOD +#include "fq_sparse_vec_templates/test/t-scalar_mul.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat.h b/fq_sparse_mat.h new file mode 100644 index 0000000000..d1e2c6411b --- /dev/null +++ b/fq_sparse_mat.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2013 Mike Hansen + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef FQ_SPARSE_MAT_H +#define FQ_SPARSE_MAT_H + +#ifdef FQ_SPARSE_MAT_INLINES_C +#define FQ_SPARSE_MAT_TEMPLATES_INLINE FLINT_DLL +#define FQ_SPARSE_MAT_INLINE FLINT_DLL +#else +#define FQ_SPARSE_MAT_TEMPLATES_INLINE static __inline__ +#define FQ_SPARSE_MAT_INLINE static __inline__ +#endif + + +#include "fq.h" +#include "fq_vec.h" +#include "fq_sparse_vec.h" +#include "fq_mat.h" + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates.h" +#undef CAP_T +#undef T + +#endif diff --git a/fq_sparse_mat/from_entries.c b/fq_sparse_mat/from_entries.c new file mode 100644 index 0000000000..24ea5e68ef --- /dev/null +++ b/fq_sparse_mat/from_entries.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/from_entries.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/inv.c b/fq_sparse_mat/inv.c new file mode 100644 index 0000000000..422d1a27ee --- /dev/null +++ b/fq_sparse_mat/inv.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/inv.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/lu.c b/fq_sparse_mat/lu.c new file mode 100644 index 0000000000..8b4a2fec4a --- /dev/null +++ b/fq_sparse_mat/lu.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/lu.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/nullspace_block_lanczos.c b/fq_sparse_mat/nullspace_block_lanczos.c new file mode 100644 index 0000000000..d806b0a350 --- /dev/null +++ b/fq_sparse_mat/nullspace_block_lanczos.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/nullspace_block_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/nullspace_block_wiedemann.c b/fq_sparse_mat/nullspace_block_wiedemann.c new file mode 100644 index 0000000000..54e56c2912 --- /dev/null +++ b/fq_sparse_mat/nullspace_block_wiedemann.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/nullspace_block_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/nullspace_lanczos.c b/fq_sparse_mat/nullspace_lanczos.c new file mode 100644 index 0000000000..cc2a572ef1 --- /dev/null +++ b/fq_sparse_mat/nullspace_lanczos.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/nullspace_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/nullspace_lu.c b/fq_sparse_mat/nullspace_lu.c new file mode 100644 index 0000000000..81f0dc4b54 --- /dev/null +++ b/fq_sparse_mat/nullspace_lu.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/nullspace_lu.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/nullspace_rref.c b/fq_sparse_mat/nullspace_rref.c new file mode 100644 index 0000000000..f0f1b8d643 --- /dev/null +++ b/fq_sparse_mat/nullspace_rref.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/nullspace_rref.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/nullspace_wiedemann.c b/fq_sparse_mat/nullspace_wiedemann.c new file mode 100644 index 0000000000..32a1393376 --- /dev/null +++ b/fq_sparse_mat/nullspace_wiedemann.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/nullspace_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/print_pretty.c b/fq_sparse_mat/print_pretty.c new file mode 100644 index 0000000000..8090dcc69d --- /dev/null +++ b/fq_sparse_mat/print_pretty.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/print_pretty.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/randtest.c b/fq_sparse_mat/randtest.c new file mode 100644 index 0000000000..5ffb7f0cf4 --- /dev/null +++ b/fq_sparse_mat/randtest.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/randtest.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/rref.c b/fq_sparse_mat/rref.c new file mode 100644 index 0000000000..a5db83126a --- /dev/null +++ b/fq_sparse_mat/rref.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/rref.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/solve_block_lanczos.c b/fq_sparse_mat/solve_block_lanczos.c new file mode 100644 index 0000000000..30206162b3 --- /dev/null +++ b/fq_sparse_mat/solve_block_lanczos.c @@ -0,0 +1,27 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + Algorithm taken from P. Montgomery, "A Block Lanczos Algorithm for + Finding Dependencies over GF(2)", Advances in Cryptology - EUROCRYPT '95 + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/solve_block_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/solve_block_wiedemann.c b/fq_sparse_mat/solve_block_wiedemann.c new file mode 100644 index 0000000000..208a05dd92 --- /dev/null +++ b/fq_sparse_mat/solve_block_wiedemann.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/solve_block_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/solve_lanczos.c b/fq_sparse_mat/solve_lanczos.c new file mode 100644 index 0000000000..e9ffdb4c09 --- /dev/null +++ b/fq_sparse_mat/solve_lanczos.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/solve_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/solve_lu.c b/fq_sparse_mat/solve_lu.c new file mode 100644 index 0000000000..587186cf8f --- /dev/null +++ b/fq_sparse_mat/solve_lu.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/solve_lu.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/solve_rref.c b/fq_sparse_mat/solve_rref.c new file mode 100644 index 0000000000..9a8cd0257b --- /dev/null +++ b/fq_sparse_mat/solve_rref.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/solve_rref.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/solve_wiedemann.c b/fq_sparse_mat/solve_wiedemann.c new file mode 100644 index 0000000000..c40f0f79af --- /dev/null +++ b/fq_sparse_mat/solve_wiedemann.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/solve_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-add.c b/fq_sparse_mat/test/t-add.c new file mode 100644 index 0000000000..c5e5c1590d --- /dev/null +++ b/fq_sparse_mat/test/t-add.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-add.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-concat_horizontal.c b/fq_sparse_mat/test/t-concat_horizontal.c new file mode 100644 index 0000000000..a44d374233 --- /dev/null +++ b/fq_sparse_mat/test/t-concat_horizontal.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-concat_horizontal.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-concat_vertical.c b/fq_sparse_mat/test/t-concat_vertical.c new file mode 100644 index 0000000000..ee3b99ca6f --- /dev/null +++ b/fq_sparse_mat/test/t-concat_vertical.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-concat_vertical.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-construct.c b/fq_sparse_mat/test/t-construct.c new file mode 100644 index 0000000000..b15335ce2c --- /dev/null +++ b/fq_sparse_mat/test/t-construct.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-construct.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-dense.c b/fq_sparse_mat/test/t-dense.c new file mode 100644 index 0000000000..c9207725d2 --- /dev/null +++ b/fq_sparse_mat/test/t-dense.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-dense.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-init_clear.c b/fq_sparse_mat/test/t-init_clear.c new file mode 100644 index 0000000000..ec140aa821 --- /dev/null +++ b/fq_sparse_mat/test/t-init_clear.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-init_clear.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-inv.c b/fq_sparse_mat/test/t-inv.c new file mode 100644 index 0000000000..a4d51256ba --- /dev/null +++ b/fq_sparse_mat/test/t-inv.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-inv.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-lu.c b/fq_sparse_mat/test/t-lu.c new file mode 100644 index 0000000000..f50b51f280 --- /dev/null +++ b/fq_sparse_mat/test/t-lu.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-lu.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-mul.c b/fq_sparse_mat/test/t-mul.c new file mode 100644 index 0000000000..0df33448d9 --- /dev/null +++ b/fq_sparse_mat/test/t-mul.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-mul.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-neg.c b/fq_sparse_mat/test/t-neg.c new file mode 100644 index 0000000000..99cd1b8ad1 --- /dev/null +++ b/fq_sparse_mat/test/t-neg.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-neg.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-nullspace.c b/fq_sparse_mat/test/t-nullspace.c new file mode 100644 index 0000000000..0703f1d579 --- /dev/null +++ b/fq_sparse_mat/test/t-nullspace.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-nullspace.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-rref.c b/fq_sparse_mat/test/t-rref.c new file mode 100644 index 0000000000..00eb87f61c --- /dev/null +++ b/fq_sparse_mat/test/t-rref.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-rref.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-scalar_mul.c b/fq_sparse_mat/test/t-scalar_mul.c new file mode 100644 index 0000000000..0bbd83d529 --- /dev/null +++ b/fq_sparse_mat/test/t-scalar_mul.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-scalar_mul.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-solve.c b/fq_sparse_mat/test/t-solve.c new file mode 100644 index 0000000000..d0c160e64c --- /dev/null +++ b/fq_sparse_mat/test/t-solve.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-solve.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/test/t-transpose.c b/fq_sparse_mat/test/t-transpose.c new file mode 100644 index 0000000000..7adcfd3374 --- /dev/null +++ b/fq_sparse_mat/test/t-transpose.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/test/t-transpose.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/transpose.c b/fq_sparse_mat/transpose.c new file mode 100644 index 0000000000..c64bd3c1ac --- /dev/null +++ b/fq_sparse_mat/transpose.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/transpose.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat/window_init.c b/fq_sparse_mat/window_init.c new file mode 100644 index 0000000000..ec6fa02e2a --- /dev/null +++ b/fq_sparse_mat/window_init.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_mat_templates/window_init.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_mat_templates.h b/fq_sparse_mat_templates.h new file mode 100644 index 0000000000..7d147edbac --- /dev/null +++ b/fq_sparse_mat_templates.h @@ -0,0 +1,415 @@ +/* + Copyright (C) 2010 William Hart + Copyright (C) 2010,2011 Fredrik Johansson + Copyright (C) 2014 Ashish Kedia + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include +#include "flint.h" +#include "longlong.h" +#include "templates.h" +#include "ulong_extras.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* A sparse matrix is a list of sparse vectors */ +typedef struct +{ + TEMPLATE(T, sparse_vec_struct) *rows; + slong r; + slong c; + slong c_off; +} +TEMPLATE(T, sparse_mat_struct); + +typedef TEMPLATE(T, sparse_mat_struct) TEMPLATE(T, sparse_mat_t)[1]; + +/* Memory management */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_init) (TEMPLATE(T, sparse_mat_t) M, slong rows, slong cols, const TEMPLATE(T, ctx_t) ctx) +{ + FLINT_ASSERT(rows >= 0 && cols >= 0); + M->rows = flint_calloc(rows, sizeof(*M->rows)); + M->r = rows; + M->c = cols; + M->c_off = 0; +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_clear) (TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < M->r; ++i) TEMPLATE(T, sparse_vec_clear)(&M->rows[i], ctx); + flint_free(M->rows); + memset(M, 0, sizeof(*M)); +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_resize) (TEMPLATE(T, sparse_mat_t) M, slong rows, slong cols, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + FLINT_ASSERT(rows >= 0 && cols >= 0); + if (M->r != rows) { + if (M->r > rows) + { + for (i = rows; i < M->r; ++i) + { + TEMPLATE(T, sparse_vec_clear)(&M->rows[i], ctx); + } + } + M->rows = flint_realloc(M->rows, rows*sizeof(*M->rows)); + if (M->r < rows) + { + for (i = M->r; i < rows; ++i) + { + TEMPLATE(T, sparse_vec_init)(&M->rows[i], ctx); + } + } + M->r = rows; + } + if (cols < M->c) + { + for (i = 0; i < M->r; ++i) + { + TEMPLATE(T, sparse_vec_resize)(&M->rows[i], cols, ctx); + } + } + M->c = cols; +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_swap) (TEMPLATE(T, sparse_mat_t) M1, TEMPLATE(T, sparse_mat_t) M2, const TEMPLATE(T, ctx_t) ctx) +{ + TEMPLATE(T, sparse_mat_t) tmp; + *tmp = *M1; *M1 = *M2; *M2 = *tmp; +} + +/* One-time instantiation */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_zero) (TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < M->r; ++i) TEMPLATE(T, sparse_vec_zero)(&M->rows[i], ctx); +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_one) (TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < M->r; ++i) TEMPLATE(T, sparse_vec_one)(&M->rows[i], i, ctx); +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_set) (TEMPLATE(T, sparse_mat_t) N, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, rmax = FLINT_MIN(M->r, M->r); + if(M==N) return; + for(i=0; irows[i], &M->rows[i], M->c_off, ctx); +} + +FLINT_DLL +void TEMPLATE(T, sparse_mat_from_entries)(TEMPLATE(T, sparse_mat_t) M, slong * rows, slong * cols, TEMPLATE(T, struct) * vals, slong nnz, const TEMPLATE(T, ctx_t) ctx); + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_append_col) (TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *v, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for(i=0; ir; ++i) TEMPLATE(T, sparse_vec_set_entry)(&M->rows[i], M->c, &v[i], ctx); + M->c += 1; +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_append_row) (TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, sparse_vec_t) v, const TEMPLATE(T, ctx_t) ctx) +{ + M->rows = realloc(M->rows, (M->r+1)*sizeof(*M->rows)); + memset(M->rows + M->r, 0, sizeof(*M->rows)); + TEMPLATE(T, sparse_vec_set)(&M->rows[M->r], v, 0, ctx); + M->r += 1; +} + +/* Convert from/to dense matrix */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_from_dense) (TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, mat_t) dM, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, rmax = FLINT_MIN(M->r, dM->r); + for (i = 0; i < rmax; ++i) TEMPLATE(T, sparse_vec_from_dense)(&M->rows[i], dM->rows[i], dM->c, ctx); +} +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_to_dense) (TEMPLATE(T, mat_t) dM, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, rmax = FLINT_MIN(M->r, dM->r); + for (i = 0; i < rmax; ++i) TEMPLATE(T, sparse_vec_to_dense)(dM->rows[i], &M->rows[i], dM->c, ctx); +} + +/* Windows, concatenation, and splitting */ +FLINT_DLL +void TEMPLATE(T, sparse_mat_window_init) (TEMPLATE(T, sparse_mat_t) W, const TEMPLATE(T, sparse_mat_t) M, slong r1, slong c1, slong r2, slong c2, const TEMPLATE(T, ctx_t) ctx); + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_window_clear) (TEMPLATE(T, sparse_mat_t) W, TEMPLATE(T, ctx_t) ctx) +{ + flint_free(W->rows); + memset(W, 0, sizeof(*W)); +} + + +/* Combine M1 and M2 into block matrix B = [M1 M2] */ +/* B->r must equal M1->r and M2->r */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_concat_horizontal)(TEMPLATE(T, sparse_mat_t) B, + const TEMPLATE(T, sparse_mat_t) M1, const TEMPLATE(T, sparse_mat_t) M2, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + B->c = M1->c + M2->c; + for (i = 0; i < B->r; ++i) + TEMPLATE(T, sparse_vec_concat)(&B->rows[i], &M1->rows[i], &M2->rows[i], M1->c, ctx); +} +/* Combine M1 and M2 into block matrix B = [M1^t M1^t]^t */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_concat_vertical) (TEMPLATE(T, sparse_mat_t) B, const TEMPLATE(T, sparse_mat_t) M1, const TEMPLATE(T, sparse_mat_t) M2, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + B->c = FLINT_MAX(M1->c, M2->c); + for (i = 0; i < M1->r; ++i) + TEMPLATE(T, sparse_vec_set)(&B->rows[i], &M1->rows[i], M1->c_off, ctx); + for (i = M1->r; i < B->r; ++i) + TEMPLATE(T, sparse_vec_set)(&B->rows[i], &M2->rows[i-M1->r], M2->c_off, ctx); +} + +/* Split block matrix B = [M1 M2] into submatrices M1 and M2 */ +/* M1->r and M2->r must equal B->r */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_split_horizontal) (TEMPLATE(T, sparse_mat_t) M1, TEMPLATE(T, sparse_mat_t) M2, const TEMPLATE(T, sparse_mat_t) B, slong c, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for(i=0; ir; ++i) TEMPLATE(T, sparse_vec_split)(&M1->rows[i], &M2->rows[i], &B->rows[i], c, ctx); +} + +/* Split block matix B = [M1^t M1^t]^t into submatrices M1 and M2 */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_split_vertical) (TEMPLATE(T, sparse_mat_t) M1, TEMPLATE(T, sparse_mat_t) M2, const TEMPLATE(T, sparse_mat_t) B, slong r, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + r = FLINT_MIN(r, B->r); + for(i=0; irows[i], &B->rows[i], B->c_off, ctx); + for(i=r; ir; ++i) TEMPLATE(T, sparse_vec_set)(&M2->rows[i-r], &B->rows[i], B->c_off, ctx); +} + +/* Matrix permutation */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_permute_cols)(TEMPLATE(T, sparse_mat_t) M, slong *Q, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < M->r; ++i) { + if(!M->rows[i].nnz) continue; + TEMPLATE(T, sparse_vec_permute_inds)(&M->rows[i], Q, ctx); + qsort(M->rows[i].entries, M->rows[i].nnz, sizeof(*M->rows[i].entries), TEMPLATE(T, sparse_entry_cmp)); + } +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_permute_rows)(TEMPLATE(T, sparse_mat_t) M, slong *P, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + TEMPLATE(T, sparse_vec_struct) *prows; + prows = flint_calloc(M->r, sizeof(*prows)); + for (i = 0; i < M->r; ++i) prows[P[i]] = M->rows[i]; + memcpy(M->rows, prows, M->r*sizeof(*M->rows)); + flint_free(prows); +} + +/* Random matrix generation */ +FLINT_DLL void TEMPLATE(T, sparse_mat_randtest) (TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, slong min_nnz, slong max_nnz, const TEMPLATE(T, ctx_t) ctx); +/* +FLINT_DLL void TEMPLATE(T, sparse_mat_randfull) (TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, TEMPLATE(T, ctx_t) ctx); +FLINT_DLL int TEMPLATE(T, sparse_mat_randpermdiag)(TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, + const TEMPLATE(T, struct) *diag, slong n); +FLINT_DLL void TEMPLATE(T, sparse_mat_randrank) (TEMPLATE(T, sparse_mat_t), flint_rand_t state, slong rank, TEMPLATE(T, ctx_t) ctx); +FLINT_DLL void TEMPLATE(T, sparse_mat_randops) (TEMPLATE(T, sparse_mat_t) M, slong count, flint_rand_t state, TEMPLATE(T, ctx_t) ctx); +FLINT_DLL void TEMPLATE(T, sparse_mat_randtril) (TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, int unit, TEMPLATE(T, ctx_t) ctx); +FLINT_DLL void TEMPLATE(T, sparse_mat_randtriu) (TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, int unit, TEMPLATE(T, ctx_t) ctx); + */ + +FLINT_DLL void TEMPLATE(T, sparse_mat_print_pretty) (const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx); + +FQ_SPARSE_MAT_TEMPLATES_INLINE +int TEMPLATE(T, sparse_mat_equal) (const TEMPLATE(T, sparse_mat_t) M1, const TEMPLATE(T, sparse_mat_t) M2, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + if (M1->r != M2->r) return 0; + for (i = 0; i < M1->r; ++i) + if (!TEMPLATE(T, sparse_vec_equal)(&M1->rows[i], &M2->rows[i], M1->c_off-M2->c_off, ctx)) return 0; + return 1; +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +int TEMPLATE(T, sparse_mat_is_zero) (const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < M->r; ++i) + if (!TEMPLATE(T, sparse_vec_is_zero)(&M->rows[i], ctx)) return 0; + return 1; +} + +/* Must have M->r == N->c and M->c == N->r */ +FLINT_DLL void TEMPLATE(T, sparse_mat_transpose) (TEMPLATE(T, sparse_mat_t) N, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx); + +/* Arithmetic */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_neg) (TEMPLATE(T, sparse_mat_t) N, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + FLINT_ASSERT(M->r == N->r); + for (i = 0; i < N->r; ++i) TEMPLATE(T, sparse_vec_neg)(&N->rows[i], &M->rows[i], ctx); +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, TEMPLATE(sparse_mat_scalar_mul, T)) (TEMPLATE(T, sparse_mat_t) N, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, t) c, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + FLINT_ASSERT(M->r == N->r); + for (i = 0; i < N->r; ++i) TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T))(&N->rows[i], &M->rows[i], c, ctx); +} + + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_add) (TEMPLATE(T, sparse_mat_t) O, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, sparse_mat_t) N, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) TEMPLATE(T, sparse_vec_add)(&O->rows[i], &M->rows[i], &N->rows[i], ctx); +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_sub) (TEMPLATE(T, sparse_mat_t) O, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, sparse_mat_t) N, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) TEMPLATE(T, sparse_vec_sub)(&O->rows[i], &M->rows[i], &N->rows[i], ctx); +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, TEMPLATE(sparse_mat_scalar_addmul, T)) (TEMPLATE(T, sparse_mat_t) O, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, sparse_mat_t) N, const TEMPLATE(T, t) c, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T))(&O->rows[i], &M->rows[i], &N->rows[i], c, ctx); +} + +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, TEMPLATE(sparse_mat_scalar_submul, T)) (TEMPLATE(T, sparse_mat_t) O, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, sparse_mat_t) N, const TEMPLATE(T, t) c, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) TEMPLATE(T, TEMPLATE(sparse_vec_scalar_submul, T))(&O->rows[i], &M->rows[i], &N->rows[i], c, ctx); +} + +/* Matrix-vector and matrix-matrix multipliciation */ +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_mul_vec) (TEMPLATE(T, struct) *y, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *x, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < M->r; ++i) TEMPLATE(T, sparse_vec_dot_dense)(&y[i], &M->rows[i], x, ctx); +} +FQ_SPARSE_MAT_TEMPLATES_INLINE +void TEMPLATE(T, sparse_mat_mul_mat) (TEMPLATE(T, mat_t) Y, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, mat_t) X, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, j; + FLINT_ASSERT(M->r == Y->r && M->c == X->r && X->c == Y->c); + TEMPLATE(T, mat_zero) (Y, ctx); + for (i = 0; i < M->r; ++i) + { + for (j = 0; j < M->rows[i].nnz; ++j) + { + TEMPLATE(T, sparse_entry_struct) *e = &M->rows[i].entries[j]; + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T))(Y->rows[i], X->rows[e->ind], X->c, e->val, ctx); + } + } +} + +FLINT_DLL +slong TEMPLATE(T, sparse_mat_inv) (TEMPLATE(T, sparse_mat_t) Mi, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx); + +/* Decomposition/reduction */ +FLINT_DLL +slong TEMPLATE(T, sparse_mat_lu)(slong *P, slong *Q, TEMPLATE(T, sparse_mat_t) L, TEMPLATE(T, sparse_mat_t) U, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +slong TEMPLATE(T, sparse_mat_rref) (TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx); + +/* Solve Ax=b */ +FLINT_DLL +int TEMPLATE(T, sparse_mat_solve_lanczos) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +int TEMPLATE(T, sparse_mat_solve_wiedemann) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +int TEMPLATE(T, sparse_mat_solve_lu) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +int TEMPLATE(T, sparse_mat_solve_rref) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +int TEMPLATE(T, sparse_mat_solve_block_wiedemann) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, slong block_size, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +int TEMPLATE(T, sparse_mat_solve_block_lanczos) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, slong block_size, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx); + +/* Find single nullvector */ +FLINT_DLL +int TEMPLATE(T, sparse_mat_nullvector_wiedemann) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +int TEMPLATE(T, sparse_mat_nullvector_lanczos) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +int TEMPLATE(T, sparse_mat_nullvector_block_wiedemann) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, slong block_size, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +int TEMPLATE(T, sparse_mat_nullvector_block_lanczos) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, slong block_size, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx); + +/* Note: this should take in uninitialized matrix X */ +FLINT_DLL +slong TEMPLATE(T, sparse_mat_nullspace_rref) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +slong TEMPLATE(T, sparse_mat_nullspace_lu) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +slong TEMPLATE(T, sparse_mat_nullspace_lanczos) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, slong max_iters, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +slong TEMPLATE(T, sparse_mat_nullspace_wiedemann) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, slong max_iters, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +slong TEMPLATE(T, sparse_mat_nullspace_block_lanczos) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, slong block_size, flint_rand_t state, slong max_iters, const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +slong TEMPLATE(T, sparse_mat_nullspace_block_wiedemann) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, slong block_size, flint_rand_t state, slong max_iters, const TEMPLATE(T, ctx_t) ctx); + +/* Nullspace */ +/* NMOD_SPARSE_MAT_INLINE +slong TEMPLATE(T, sparse_mat_nullspace) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, TEMPLATE(T, ctx_t) ctx); + */ +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/fq_sparse_mat_templates/from_entries.c b/fq_sparse_mat_templates/from_entries.c new file mode 100644 index 0000000000..05d2df253a --- /dev/null +++ b/fq_sparse_mat_templates/from_entries.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +void TEMPLATE(T, sparse_mat_from_entries) (TEMPLATE(T, sparse_mat_t) M, slong * rows, slong * cols, TEMPLATE(T, struct) * vals, slong nnz, const TEMPLATE(T, ctx_t) ctx) +{ + slong r, i, j; + for (r = i = 0; r < M->r; ++r, i = j) + { + M->rows[r].nnz = 0; + for (j = i; j < nnz && rows[j]==r; ++j); + TEMPLATE(T, sparse_vec_from_entries) (&M->rows[r], cols+i, vals+i, j-i, ctx); + } +} + +#endif diff --git a/fq_sparse_mat_templates/inv.c b/fq_sparse_mat_templates/inv.c new file mode 100644 index 0000000000..9620a2753b --- /dev/null +++ b/fq_sparse_mat_templates/inv.c @@ -0,0 +1,39 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +slong TEMPLATE(T, sparse_mat_inv) (TEMPLATE(T, sparse_mat_t) Mi, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong rk; + TEMPLATE(T, sparse_mat_t) I, MI; + + /* Create block matrix [M | I] */ + TEMPLATE(T, sparse_mat_init) (I, M->r, M->r, ctx); + TEMPLATE(T, sparse_mat_one) (I, ctx); + TEMPLATE(T, sparse_mat_init) (MI, M->r, M->r + M->c, ctx); + TEMPLATE(T, sparse_mat_concat_horizontal) (MI, M, I, ctx); + + /* Run Gaussian elimination on first half */ + MI->c = M->c; + rk = TEMPLATE(T, sparse_mat_rref) (MI, ctx); + MI->c = M->c+M->r; + TEMPLATE(T, sparse_mat_split_horizontal) (I, Mi, MI, M->c, ctx); + TEMPLATE(T, sparse_mat_clear) (I, ctx); + TEMPLATE(T, sparse_mat_clear) (MI, ctx); + return rk; +} + +#endif diff --git a/fq_sparse_mat_templates/lu.c b/fq_sparse_mat_templates/lu.c new file mode 100644 index 0000000000..091bd775e6 --- /dev/null +++ b/fq_sparse_mat_templates/lu.c @@ -0,0 +1,183 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +static void heap_up(slong *heap, slong *heap_idx, slong *scores, slong pos) +{ + const slong c = heap[pos]; + slong nc, npos; + for (; pos > 0; pos = npos) + { + npos = (pos-1)/2; + nc = heap[npos]; + if (scores[c] >= scores[nc]) break; + + heap[pos] = nc; + heap_idx[nc] = pos; + } + heap[pos] = c; + heap_idx[c] = pos; +} + +static void heap_down(slong *heap, slong *heap_idx, slong *scores, slong size, slong pos) +{ + const slong c = heap[pos]; + slong nc, npos; + for (; pos < (size-1)/2; pos = npos) + { + npos = 2*pos+1; + if (npos+1 < size && scores[heap[npos]] > scores[heap[npos+1]]) ++npos; + nc = heap[npos]; + if (scores[c] <= scores[nc]) break; + + heap[pos] = nc; + heap_idx[nc] = pos; + } + heap[pos] = c; + heap_idx[c] = pos; +} + +/* static void print_heap(slong *heap, slong *scores, slong size) +{ + slong level, i; + for (level = 1; level <= size; level<<=1) + { + for (i = level; i <= size && i < 2*level; ++i) + { + flint_printf("%wd:%wd,%wd\t", i-1, heap[i-1], scores[heap[i-1]]); + } + flint_printf("\n"); + } +} + */ +slong TEMPLATE(T, sparse_mat_lu)(slong *P, slong *Q, + TEMPLATE(T, sparse_mat_t) L, TEMPLATE(T, sparse_mat_t) U, + const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, j, r, c, pr, pc, rank, remr, remc; + slong *heap, *heap_idx, *scores, heap_size; + TEMPLATE(T, t) cinv, cc; + TEMPLATE(T, sparse_mat_t) Lt; + TEMPLATE(T, sparse_vec_struct) *pcol, *prow, *row, *col; + + if (M->r == 0 || M->c == 0) + { + TEMPLATE(T, sparse_mat_zero) (L, ctx); + TEMPLATE(T, sparse_mat_zero) (U, ctx); + for (i = 0; i < M->r; ++i) P[i] = i; + for (i = 0; i < M->c; ++i) Q[i] = i; + return 0; + } + TEMPLATE(T, init) (cinv, ctx); + TEMPLATE(T, init) (cc, ctx); + TEMPLATE(T, sparse_mat_init) (Lt, L->c, L->r, ctx); + TEMPLATE(T, sparse_mat_transpose) (Lt, M, ctx); + TEMPLATE(T, sparse_mat_set) (U, M, ctx); + + /* Set up permutations */ + remr = M->r, remc = M->c; + for (r = 0; r < M->r; ++r) + { + if (!U->rows[r].nnz) P[r] = --remr; + else P[r] = -1; + } + for (c = 0; c < M->c; ++c) + { + if (!Lt->rows[c].nnz) Q[c] = --remc; + else Q[c] = -1; + } + + /* Make heap of nonzero columns by size */ + heap_size = M->c; + heap = flint_malloc(M->c*sizeof(*heap)); + scores = flint_malloc(M->c*sizeof(*scores)); + heap_idx = flint_malloc(M->c*sizeof(*heap_idx)); + for (i = 0; i < M->c; ++i) + { + scores[i] = Lt->rows[i].nnz; /* TODO: randomized tiebreaker */ + heap[i] = i; + heap_up(heap, heap_idx, scores, i); + } + /* Run elimination */ + rank = 0; + for (heap_size = M->c; heap_size > 0; ) + { + /* Get lowest weight column (top of heap) */ + pc = heap[0]; + pcol = &Lt->rows[pc]; + heap[0] = heap[--heap_size]; + heap_down(heap, heap_idx, scores, heap_size, 0); + if (pcol->nnz == 0) continue; /* Empty columns already dealt with */ + Q[pc] = rank; /* Move pivot column to front */ + + /* Get lowest weight incident row */ + pr = pcol->entries[0].ind, prow = &U->rows[pr]; + for (j = 1; j < pcol->nnz; ++j) + { + r = pcol->entries[j].ind, row = &U->rows[r]; + if (row->nnz < prow->nnz) pr = r, prow = row; + } + P[pr] = rank; /* Move pivot row to front */ + + /* Invert pivot */ + TEMPLATE(T, inv) (cinv, *TEMPLATE(T, sparse_vec_at) (prow, pc, ctx), ctx); + + /* Gaussian eliminate rows */ + for (j = 0; j < pcol->nnz; ++j) + { + r = pcol->entries[j].ind, row = &U->rows[r]; + if (P[r] >= 0) continue; /* Skip previous pivot rows */ + TEMPLATE(T, mul) (cc, cinv, *TEMPLATE(T, sparse_vec_at) (row, pc, ctx), ctx); + TEMPLATE(T, neg) (cc, cc, ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T)) (row, row, prow, cc, ctx); + if (row->nnz == 0) P[r] = --remr; + } + /* Gaussian eliminate cols */ + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (pcol, pcol, cinv, ctx); + for (j = 0; j < prow->nnz; ++j) + { + c = prow->entries[j].ind, col = &Lt->rows[c]; + if (Q[c] >= 0) continue; /* Skip previous pivot columns */ + TEMPLATE(T, neg) (cc, *TEMPLATE(T, sparse_vec_at) (col, pr, ctx), ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T)) (col, col, pcol, cc, ctx); + if (col->nnz == 0) Q[c] = --remc; + scores[c] = col->nnz; + heap_up(heap, heap_idx, scores, heap_idx[c]); + heap_down(heap, heap_idx, scores, heap_size, heap_idx[c]); + + } + rank += 1; + } + flint_free(heap); + flint_free(scores); + flint_free(heap_idx); + + TEMPLATE(T, clear) (cinv, ctx); + TEMPLATE(T, clear) (cc, ctx); + + /* Transpose L^t */ + TEMPLATE(T, sparse_mat_transpose) (L, Lt, ctx); + TEMPLATE(T, sparse_mat_clear) (Lt, ctx); + + /* Reorder rows and cols in L and U */ + TEMPLATE(T, sparse_mat_permute_cols) (L, Q, ctx); + TEMPLATE(T, sparse_mat_permute_rows) (L, P, ctx); + TEMPLATE(T, sparse_mat_permute_cols) (U, Q, ctx); + TEMPLATE(T, sparse_mat_permute_rows) (U, P, ctx); + return rank; +} + +#endif diff --git a/fq_sparse_mat_templates/nullspace_block_lanczos.c b/fq_sparse_mat_templates/nullspace_block_lanczos.c new file mode 100644 index 0000000000..3e7ab6b4a1 --- /dev/null +++ b/fq_sparse_mat_templates/nullspace_block_lanczos.c @@ -0,0 +1,80 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +slong TEMPLATE(T, sparse_mat_nullspace_block_lanczos) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, slong block_size, flint_rand_t state, slong max_iters, const TEMPLATE(T, ctx_t) ctx) +{ + /* Generate random solutions to a random system Mx = b and stop when nullspace filled */ + slong i, j, iter, nxs, *xps; + TEMPLATE(T, t) cc; + TEMPLATE(T, struct) *x, **xs; + + TEMPLATE(T, init) (cc, ctx); + x = _TEMPLATE(T, vec_init) (M->c, ctx); + nxs = 0; + xs = NULL; + xps = NULL; + for (iter = 0; iter < max_iters; ) + { + if (TEMPLATE(T, sparse_mat_nullvector_block_lanczos) (x, M, block_size, state, ctx) == 0) {++iter; continue;} + + /* Reduce by existing kernel vectors */ + for (j = nxs-1; j >= 0; --j) + { + TEMPLATE(T, neg) (cc, &x[xps[j]], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (x, xs[j], M->c, cc, ctx); + } + + /* Normalize last nonzero entry to 1 */ + for (i = M->c-1; i >= 0 && TEMPLATE(T, is_zero) (&x[i], ctx); --i); + if (i == -1) {++iter; continue;} /* x in span of xs, nullspace probably complete */ + TEMPLATE(T, inv) (cc, &x[i], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (x, x, M->c, cc, ctx); + + /* Reduce previous vectors by this one */ + for (j = 0; j < nxs; ++j) + { + TEMPLATE(T, neg) (cc, &xs[j][i], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (xs[j], x, M->c, cc, ctx); + } + + /* Insert into list of vectors in nullspace (ordered by pivot) */ + xs = realloc(xs, (nxs+1)*sizeof(*xs)); + xps = realloc(xps, (nxs+1)*sizeof(*xps)); + for (j = 0; j < nxs && i > xps[j]; ++j); + memmove(xs + j + 1, xs + j, (nxs - j)*sizeof(*xs)); + memmove(xps + j + 1, xps + j, (nxs - j)*sizeof(*xps)); + xps[j] = i; + xs[j] = x; + nxs += 1; + x = _TEMPLATE(T, vec_init) (M->c, ctx); /* New vector for next iteration */ + iter = 0; + } + flint_free(xps); + TEMPLATE(T, clear) (cc, ctx); + _TEMPLATE(T, vec_clear) (x, M->c, ctx); + TEMPLATE(T, mat_init) (X, M->c, nxs, ctx); + for (i = 0; i < nxs; ++i) + { + for (j = 0; j < M->c; ++j) + TEMPLATE(T, set) (&X->rows[j][i], &xs[i][j], ctx); + _TEMPLATE(T, vec_clear) (xs[i], M->c, ctx); + } + flint_free(xs); + return X->c; +} + +#endif diff --git a/fq_sparse_mat_templates/nullspace_block_wiedemann.c b/fq_sparse_mat_templates/nullspace_block_wiedemann.c new file mode 100644 index 0000000000..ffe439616e --- /dev/null +++ b/fq_sparse_mat_templates/nullspace_block_wiedemann.c @@ -0,0 +1,81 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +slong TEMPLATE(T, sparse_mat_nullspace_block_wiedemann) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, slong block_size, flint_rand_t state, slong max_iters, const TEMPLATE(T, ctx_t) ctx) +{ + /* Generate random solutions to a random system Mx = b and stop when nullspace filled */ + slong i, j, iter, nxs, *xps; + TEMPLATE(T, t) cc; + TEMPLATE(T, struct) *x, **xs; + + TEMPLATE(T, init) (cc, ctx); + x = _TEMPLATE(T, vec_init) (M->c, ctx); + nxs = 0; + xs = NULL; + xps = NULL; + for (iter = 0; iter < max_iters; ) + { + if (TEMPLATE(T, sparse_mat_nullvector_block_wiedemann) (x, M, block_size, state, ctx) == 0) {++iter; continue;} + + /* Reduce by existing kernel vectors */ + for (j = nxs-1; j >= 0; --j) + { + TEMPLATE(T, neg) (cc, &x[xps[j]], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (x, xs[j], M->c, cc, ctx); + } + + /* Normalize last nonzero entry to 1 */ + for (i = M->c-1; i >= 0 && TEMPLATE(T, is_zero) (&x[i], ctx); --i); + if (i == -1) {++iter; continue;} /* x in span of xs, nullspace probably complete */ + TEMPLATE(T, inv) (cc, &x[i], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (x, x, M->c, cc, ctx); + + /* Reduce previous vectors by this one */ + for (j = 0; j < nxs; ++j) + { + TEMPLATE(T, neg) (cc, &xs[j][i], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (xs[j], x, M->c, cc, ctx); + } + + /* Insert into list of vectors in nullspace (ordered by pivot) */ + xs = realloc(xs, (nxs+1)*sizeof(*xs)); + xps = realloc(xps, (nxs+1)*sizeof(*xps)); + for (j = 0; j < nxs && i > xps[j]; ++j); + memmove(xs + j + 1, xs + j, (nxs - j)*sizeof(*xs)); + memmove(xps + j + 1, xps + j, (nxs - j)*sizeof(*xps)); + xps[j] = i; + xs[j] = x; + nxs += 1; + x = _TEMPLATE(T, vec_init) (M->c, ctx); /* New vector for next iteration */ + iter = 0; + } + flint_free(xps); + TEMPLATE(T, mat_init) (X, M->c, nxs, ctx); + for (i = 0; i < nxs; ++i) + { + for (j = 0; j < M->c; ++j) + TEMPLATE(T, set) (&X->rows[j][i], &xs[i][j], ctx); + _TEMPLATE(T, vec_clear) (xs[i], M->c, ctx); + } + TEMPLATE(T, clear) (cc, ctx); + _TEMPLATE(T, vec_clear) (x, M->c, ctx); + + flint_free(xs); + return X->c; +} + +#endif diff --git a/fq_sparse_mat_templates/nullspace_lanczos.c b/fq_sparse_mat_templates/nullspace_lanczos.c new file mode 100644 index 0000000000..7fbbadd999 --- /dev/null +++ b/fq_sparse_mat_templates/nullspace_lanczos.c @@ -0,0 +1,80 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +slong TEMPLATE(T, sparse_mat_nullspace_lanczos) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, slong max_iters, const TEMPLATE(T, ctx_t) ctx) +{ + /* Generate random solutions to a random system Mx = b and stop when nullspace filled */ + slong i, j, iter, nxs, *xps; + TEMPLATE(T, t) cc; + TEMPLATE(T, struct) *x, **xs; + + TEMPLATE(T, init) (cc, ctx); + x = _TEMPLATE(T, vec_init) (M->c, ctx); + nxs = 0; + xs = NULL; + xps = NULL; + for (iter = 0; iter < max_iters; ) + { + if (TEMPLATE(T, sparse_mat_nullvector_lanczos) (x, M, state, ctx) == 0) {++iter; continue;} + + /* Reduce by existing kernel vectors */ + for (j = nxs-1; j >= 0; --j) + { + TEMPLATE(T, neg) (cc, &x[xps[j]], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (x, xs[j], M->c, cc, ctx); + } + + /* Normalize last nonzero entry to 1 */ + for (i = M->c-1; i >= 0 && TEMPLATE(T, is_zero) (&x[i], ctx); --i); + if (i == -1) {++iter; continue;} /* x in span of xs, nullspace probably complete */ + TEMPLATE(T, inv) (cc, &x[i], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (x, x, M->c, cc, ctx); + + /* Reduce previous vectors by this one */ + for (j = 0; j < nxs; ++j) + { + TEMPLATE(T, neg) (cc, &xs[j][i], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (xs[j], x, M->c, cc, ctx); + } + + /* Insert into list of vectors in nullspace (ordered by pivot) */ + xs = realloc(xs, (nxs+1)*sizeof(*xs)); + xps = realloc(xps, (nxs+1)*sizeof(*xps)); + for (j = 0; j < nxs && i > xps[j]; ++j); + memmove(xs + j + 1, xs + j, (nxs - j)*sizeof(*xs)); + memmove(xps + j + 1, xps + j, (nxs - j)*sizeof(*xps)); + xps[j] = i; + xs[j] = x; + nxs += 1; + x = _TEMPLATE(T, vec_init) (M->c, ctx); /* New vector for next iteration */ + iter = 0; + } + flint_free(xps); + TEMPLATE(T, clear) (cc, ctx); + _TEMPLATE(T, vec_clear) (x, M->c, ctx); + TEMPLATE(T, mat_init) (X, M->c, nxs, ctx); + for (i = 0; i < nxs; ++i) + { + for (j = 0; j < M->c; ++j) + TEMPLATE(T, set) (&X->rows[j][i], &xs[i][j], ctx); + _TEMPLATE(T, vec_clear) (xs[i], M->c, ctx); + } + flint_free(xs); + return X->c; +} + +#endif diff --git a/fq_sparse_mat_templates/nullspace_lu.c b/fq_sparse_mat_templates/nullspace_lu.c new file mode 100644 index 0000000000..26a460374f --- /dev/null +++ b/fq_sparse_mat_templates/nullspace_lu.c @@ -0,0 +1,71 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +slong TEMPLATE(T, sparse_mat_nullspace_lu) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong rk, *P, *Q, *Qi, i, j; + TEMPLATE(T, t) cc; + TEMPLATE(T, sparse_mat_t) L, U; + TEMPLATE(T, sparse_entry_struct) *e; + TEMPLATE(T, sparse_vec_struct) *Urow; + TEMPLATE(T, struct) *Xrow; + + P = flint_malloc(M->r * sizeof(*P)); + Q = flint_malloc(M->c * sizeof(*Q)); + TEMPLATE(T, init) (cc, ctx); + TEMPLATE(T, sparse_mat_init) (L, M->r, M->c, ctx); + TEMPLATE(T, sparse_mat_init) (U, M->r, M->c, ctx); + rk = TEMPLATE(T, sparse_mat_lu) (P, Q, L, U, M, ctx); + flint_free(P); + TEMPLATE(T, sparse_mat_clear) (L, ctx); + for (i = 0; i < rk; ++i) + { + TEMPLATE(T, inv) (cc, U->rows[i].entries[0].val, ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (&U->rows[i], &U->rows[i], cc, ctx); + } + TEMPLATE(T, mat_init) (X, M->c, M->c-rk, ctx); + if (rk != M->c) + { + /* Invert permutation */ + Qi = flint_malloc(M->c * sizeof(*Qi)); + for (i = 0; i < M->c; ++i) Qi[Q[i]] = i; + + /* Mssign unit vectors to non-pivot columns */ + for (i = M->c-1; i >= rk; --i) TEMPLATE(T, one) (&X->rows[Qi[i]][i-rk], ctx); + for (i = rk-1; i >= 0; --i) + { + Urow = &U->rows[i]; + Xrow = X->rows[Qi[i]]; + for (j = 1; j < Urow->nnz; ++j) + { + e = &Urow->entries[j]; + /* Do in-place row elimination */ + TEMPLATE(T, neg) (cc, e->val, ctx); + if (e->ind < rk) _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (Xrow, X->rows[Qi[e->ind]], X->c, cc, ctx); + else TEMPLATE(T, sub) (&Xrow[e->ind-rk], &Xrow[e->ind-rk], e->val, ctx); + } + + } + flint_free(Qi); + } + flint_free(Q); + TEMPLATE(T, clear) (cc, ctx); + TEMPLATE(T, sparse_mat_clear) (U, ctx); + return X->c; +} + +#endif diff --git a/fq_sparse_mat_templates/nullspace_rref.c b/fq_sparse_mat_templates/nullspace_rref.c new file mode 100644 index 0000000000..aec35ecee9 --- /dev/null +++ b/fq_sparse_mat_templates/nullspace_rref.c @@ -0,0 +1,53 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +slong TEMPLATE(T, sparse_mat_nullspace_rref) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, j, rk, numc, *Q; + TEMPLATE(T, struct) *Xrow; + TEMPLATE(T, sparse_mat_t) R; + TEMPLATE(T, sparse_vec_struct) *Rrow; + TEMPLATE(T, sparse_mat_init) (R, M->r, M->c, ctx); + TEMPLATE(T, sparse_mat_set) (R, M, ctx); + rk = TEMPLATE(T, sparse_mat_rref) (R, ctx); + TEMPLATE(T, mat_init) (X, M->c, M->c-rk, ctx); + if (rk != M->c) + { + numc = 0; + /* Mark which cols are pivots and enumerate the nonpivots */ + Q = flint_calloc(M->c, sizeof(*Q)); + for (i = 0; i < rk; ++i) + Q[R->rows[i].entries->ind] = -1; + for (i = 0; i < M->c; ++i) + if (Q[i]==UWORD(0)) Q[i] = numc++, TEMPLATE(T, one) (&X->rows[i][Q[i]], ctx); + + /* For each pivot col, set the corresponding row in X as */ + /* the negative of the associated row in R (reordered by Q) */ + for (i = 0; i < rk; ++i) + { + Rrow = &R->rows[i]; + Xrow = X->rows[Rrow->entries[0].ind]; + for (j = 1; j < Rrow->nnz; ++j) + TEMPLATE(T, neg) (&Xrow[Q[Rrow->entries[j].ind]], Rrow->entries[j].val, ctx); + } + flint_free(Q); + } + TEMPLATE(T, sparse_mat_clear) (R, ctx); + return X->c; +} + +#endif diff --git a/fq_sparse_mat_templates/nullspace_wiedemann.c b/fq_sparse_mat_templates/nullspace_wiedemann.c new file mode 100644 index 0000000000..950b7126b7 --- /dev/null +++ b/fq_sparse_mat_templates/nullspace_wiedemann.c @@ -0,0 +1,81 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +slong TEMPLATE(T, sparse_mat_nullspace_wiedemann) (TEMPLATE(T, mat_t) X, const TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, slong max_iters, const TEMPLATE(T, ctx_t) ctx) +{ + /* Generate random solutions to a random system Mx = b and stop when nullspace filled */ + slong i, j, iter, nxs, *xps; + TEMPLATE(T, t) cc; + TEMPLATE(T, struct) *x, **xs; + + TEMPLATE(T, init) (cc, ctx); + x = _TEMPLATE(T, vec_init) (M->c, ctx); + nxs = 0; + xs = NULL; + xps = NULL; + for (iter = 0; iter < max_iters; ) + { + if (TEMPLATE(T, sparse_mat_nullvector_wiedemann) (x, M, state, ctx) == 0) {++iter; continue;} + + /* Reduce by existing kernel vectors */ + for (j = nxs-1; j >= 0; --j) + { + TEMPLATE(T, neg) (cc, &x[xps[j]], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (x, xs[j], M->c, cc, ctx); + } + + /* Normalize last nonzero entry to 1 */ + for (i = M->c-1; i >= 0 && TEMPLATE(T, is_zero) (&x[i], ctx); --i); + if (i == -1) {++iter; continue;} /* x in span of xs, nullspace probably complete */ + TEMPLATE(T, inv) (cc, &x[i], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (x, x, M->c, cc, ctx); + + /* Reduce previous vectors by this one */ + for (j = 0; j < nxs; ++j) + { + TEMPLATE(T, neg) (cc, &xs[j][i], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (xs[j], x, M->c, cc, ctx); + } + + /* Insert into list of vectors in nullspace (ordered by pivot) */ + xs = realloc(xs, (nxs+1)*sizeof(*xs)); + xps = realloc(xps, (nxs+1)*sizeof(*xps)); + for (j = 0; j < nxs && i > xps[j]; ++j); + memmove(xs + j + 1, xs + j, (nxs - j)*sizeof(*xs)); + memmove(xps + j + 1, xps + j, (nxs - j)*sizeof(*xps)); + xps[j] = i; + xs[j] = x; + nxs += 1; + x = _TEMPLATE(T, vec_init) (M->c, ctx); /* New vector for next iteration */ + iter = 0; + } + flint_free(xps); + TEMPLATE(T, mat_init) (X, M->c, nxs, ctx); + for (i = 0; i < nxs; ++i) + { + for (j = 0; j < M->c; ++j) + TEMPLATE(T, set) (&X->rows[j][i], &xs[i][j], ctx); + _TEMPLATE(T, vec_clear) (xs[i], M->c, ctx); + } + TEMPLATE(T, clear) (cc, ctx); + _TEMPLATE(T, vec_clear) (x, M->c, ctx); + + flint_free(xs); + return X->c; +} + +#endif diff --git a/fq_sparse_mat_templates/print_pretty.c b/fq_sparse_mat_templates/print_pretty.c new file mode 100644 index 0000000000..9189c984cf --- /dev/null +++ b/fq_sparse_mat_templates/print_pretty.c @@ -0,0 +1,36 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +void +TEMPLATE(T, sparse_mat_print_pretty) (const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + char row_fmt[FLINT_BITS + 5]; + flint_sprintf(row_fmt, "%%%dwd: ", n_sizeinbase(M->r, 10)); + + flint_printf("<%wd x %wd sparse integer matrix mod %w>\n", + M->r, M->c, ctx); + + for (i = 0; i < M->r; i++) + { + flint_printf(row_fmt, i); + TEMPLATE(T, sparse_vec_print_pretty) (&M->rows[i], M->c_off, M->c, ctx); + } +} + + +#endif diff --git a/fq_sparse_mat_templates/randtest.c b/fq_sparse_mat_templates/randtest.c new file mode 100644 index 0000000000..b53cde488e --- /dev/null +++ b/fq_sparse_mat_templates/randtest.c @@ -0,0 +1,31 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +void +TEMPLATE(T, sparse_mat_randtest) (TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, slong min_nnz, slong max_nnz, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, nnz; + + for (i = 0; i < M->r; ++i) + { + nnz = n_randint(state, max_nnz+1); + nnz = FLINT_MAX(nnz, min_nnz); + TEMPLATE(T, sparse_vec_randtest) (&M->rows[i], state, nnz, M->c, ctx); + } +} + +#endif diff --git a/fq_sparse_mat_templates/rref.c b/fq_sparse_mat_templates/rref.c new file mode 100644 index 0000000000..9b675457ca --- /dev/null +++ b/fq_sparse_mat_templates/rref.c @@ -0,0 +1,95 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +slong TEMPLATE(T, sparse_mat_rref) (TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, ctx_t) ctx) +{ + slong *P; + slong j, r, c, pr, pc, rank, remr; + TEMPLATE(T, t) cinv, cc; + TEMPLATE(T, sparse_mat_t) Mt; + TEMPLATE(T, sparse_vec_struct) *pcol, *prow, *row, *col; + + if (M->r == 0 || M->c == 0) return 0; + P = flint_malloc(M->r*sizeof(*P)); + TEMPLATE(T, init) (cinv, ctx); + TEMPLATE(T, init) (cc, ctx); + TEMPLATE(T, sparse_mat_init) (Mt, M->c, M->r, ctx); + + /* Make transpose for doing column eliminations */ + TEMPLATE(T, sparse_mat_transpose) (Mt, M, ctx); + + /* Set up permutations */ + remr = M->r; + for (r = 0; r < M->r; ++r) + { + if (!M->rows[r].nnz || M->rows[r].entries[0].ind >= M->c) P[r] = --remr; + else P[r] = -1; + } + + /* Run elimination */ + rank = 0; + for (pc = 0; pc < M->c; ++pc) + { + pcol = &Mt->rows[pc]; + + /* Get lowest weight incident row not used as previous pivot */ + pr = -1, prow = NULL; + for (j = 0; j < pcol->nnz; ++j) + { + r = pcol->entries[j].ind, row = &M->rows[r]; + if (P[r] >= 0) continue; + if (pr==-1 || (row->nnz < prow->nnz)) pr = r, prow = row; + } + if (pr == -1) continue; + P[pr] = rank; + + TEMPLATE(T, inv) (cinv, *TEMPLATE(T, sparse_vec_at) (prow, pc, ctx), ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (prow, prow, cinv, ctx); + + /* Gaussian eliminate rows */ + for (j = 0; j < pcol->nnz; ++j) + { + r = pcol->entries[j].ind, row = &M->rows[r]; + if (r == pr) {TEMPLATE(T, zero) (pcol->entries[j].val, ctx); continue;} + + TEMPLATE(T, neg) (cc, *TEMPLATE(T, sparse_vec_at) (row, pc, ctx), ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T)) (row, row, prow, cc, ctx); + if (row->nnz == 0 || row->entries[0].ind >= M->c) P[r] = --remr; + } + /* Gaussian eliminate cols */ + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (pcol, pcol, cinv, ctx); + for (j = 0; j < prow->nnz; ++j) + { + c = prow->entries[j].ind, col = &Mt->rows[c]; + if (c >= M->c || c == pc) continue; + TEMPLATE(T, neg) (cc, *TEMPLATE(T, sparse_vec_at) (col, pr, ctx), ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T)) (col, col, pcol, cc, ctx); + } + rank += 1; + } + /* Reorder rows */ + TEMPLATE(T, sparse_mat_permute_rows) (M, P, ctx); + + flint_free(P); + TEMPLATE(T, clear) (cinv, ctx); + TEMPLATE(T, clear) (cc, ctx); + TEMPLATE(T, sparse_mat_clear) (Mt, ctx); + + return rank; +} + +#endif diff --git a/fq_sparse_mat_templates/solve_block_lanczos.c b/fq_sparse_mat_templates/solve_block_lanczos.c new file mode 100644 index 0000000000..6f3a4cacce --- /dev/null +++ b/fq_sparse_mat_templates/solve_block_lanczos.c @@ -0,0 +1,260 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + Algorithm taken from P. Montgomery, "A Block Lanczos Algorithm for + Finding Dependencies over GF(2)", Advances in Cryptology - EUROCRYPT '95 + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +/* Run row Gaussian elimination on first b block of [T I], save that, */ +/* if no pivot is found for a given column c, we Gaussian eliminate */ +/* the column c + b and zero out the row c. In addition, we reorder */ +/* columns so that ones corresponding to zero entries in S go first. */ +/* See Figure 1 in the above reference for details. */ +static int compute_nWi_S(TEMPLATE(T, mat_t) nWi, int *S, const TEMPLATE(T, mat_t) Torig, const TEMPLATE(T, ctx_t) ctx) +{ + + const slong b = Torig->r; + slong pc, i, j, rk = 0; + slong *P; + TEMPLATE(T, t) cc; + TEMPLATE(T, mat_t) T; + TEMPLATE(T, mat_struct) *X; + + P = flint_malloc(b * sizeof(*P)); + TEMPLATE(T, init) (cc, ctx); + TEMPLATE(T, mat_init) (T, b, b, ctx); + TEMPLATE(T, mat_set) (T, Torig, ctx); + TEMPLATE(T, mat_one) (nWi, ctx); + + /* Set permutation to have previously dependent vectors at front */ + P = flint_malloc(b*sizeof(*P)); + j = 0; + for (i = 0; i < b; ++i) if (!S[i]) P[j++] = i; + for (i = 0; i < b; ++i) if (S[i]) P[j++] = i; + + for (j = 0; j < b; ++j) + { + pc = P[j]; /* Pivot col */ + + /* Find viable pivot row (from T if possible, then from W) */ + for (X = T, i = j; i < b && TEMPLATE(T, is_zero)(&X->rows[P[i]][pc], ctx); ++i); + if (i == b) + for (X = nWi, i = j; i < b && TEMPLATE(T, is_zero)(&X->rows[P[i]][pc], ctx); ++i); + S[pc] = X == T; /* Viable column in V */ + TEMPLATE(T, mat_swap_rows) (T, NULL, pc, P[i], ctx); + TEMPLATE(T, mat_swap_rows) (nWi, NULL, pc, P[i], ctx); /* Now pivot row = pivot col */ + + /* Make pivot one */ + TEMPLATE(T, inv) (cc, &X->rows[pc][pc], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (T->rows[pc], T->rows[pc], b, cc, ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (nWi->rows[pc], nWi->rows[pc], b, cc, ctx); + + /* Kill all other entries in pivot column */ + for (i = 0; i < b; ++i) + { + TEMPLATE(T, neg) (cc, &X->rows[P[i]][pc], ctx); + if (i == j || TEMPLATE(T, is_zero) (cc, ctx)) continue; + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (T->rows[P[i]], T->rows[pc], T->c, cc, ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (nWi->rows[P[i]], nWi->rows[pc], nWi->c, cc, ctx); + } + if (S[pc]) rk++; /* Count viable columns */ + else + { + /* Kill row of both matrices */ + _TEMPLATE(T, vec_zero) (T->rows[pc], b, ctx); + _TEMPLATE(T, vec_zero) (nWi->rows[pc], b, ctx); + } + } + TEMPLATE(T, mat_neg) (nWi, nWi, ctx); + TEMPLATE(T, mat_clear) (T, ctx); + + return rk; +} + +static void kill_columns(TEMPLATE(T, mat_t) M, int *good, const TEMPLATE(T, ctx_t) ctx) +{ + slong r, c; + for (c = 0; c < M->c; ++c) + if (good[c] == 0) + for (r = 0; r < M->r; ++r) + TEMPLATE(T, zero) (&M->rows[r][c], ctx); +} + +int TEMPLATE(T, sparse_mat_solve_block_lanczos) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, slong block_size, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx) +{ + int ret = 0; + slong i, prev_i, next_i, iter, cur_dim, total_dim = 0; + TEMPLATE(T, sparse_mat_t) Mt; /* Transpose of M, we work with A = MtM */ + TEMPLATE(T, mat_struct) V[3]; /* Keep track of current vector and two previous ones */ + TEMPLATE(T, mat_t) MV; /* Application of M to V */ + TEMPLATE(T, mat_t) AV; /* Application of Mt to MV */ + int *SSt; /* S is the maximal projection s.t. (VS)^tAVS is invertible, so SSt kills the dropped columns */ + TEMPLATE(T, mat_struct) nWi[3]; /* -S((VS)^tAVS)^-1S^t */ + TEMPLATE(T, mat_t) VSSt; /* V with invalid vectors zeroed out */ + TEMPLATE(T, mat_t) T; /* Used to store transposes for inner products */ + TEMPLATE(T, mat_t) VtAV; /* Inner product _A */ + TEMPLATE(T, mat_t) AVtAVSSt_VtAV; /* Sum _A SS^t + _A, shared by two updates */ + TEMPLATE(T, mat_t) DEF; /* Used to store coefficient matrices D, E, and F */ + TEMPLATE(T, mat_t) I, tmp; /* I_{b x b} */ + TEMPLATE(T, struct) *Mtb, *SStVtMtb, *WiSStVtMtb, *VSStWiSStVtMtb; /* Intermediate elements in x update */ + if (_TEMPLATE(T, vec_is_zero) (b, M->r, ctx)) + { + _TEMPLATE(T, vec_zero) (x, M->c, ctx); + return 1; + } + TEMPLATE(T, sparse_mat_init) (Mt, M->c, M->r, ctx); + for (i = 0; i < 3; ++i) TEMPLATE(T, mat_init) (&V[i], M->c, block_size, ctx); + TEMPLATE(T, mat_init) (MV, M->r, block_size, ctx); /* Intermediate product */ + TEMPLATE(T, mat_init) (AV, M->c, block_size, ctx); /* Symmetric product */ + SSt = flint_malloc(block_size*sizeof(*SSt)); + for (i = 0; i < 3; ++i) TEMPLATE(T, mat_init) (&nWi[i], block_size, block_size, ctx); + TEMPLATE(T, mat_init) (VSSt, M->c, block_size, ctx); /* Transpose for computing matrix dot products */ + TEMPLATE(T, mat_init) (T, block_size, M->c, ctx); /* Transpose for computing matrix dot products */ + TEMPLATE(T, mat_init) (VtAV, block_size, block_size, ctx); + TEMPLATE(T, mat_init) (AVtAVSSt_VtAV, block_size, block_size, ctx); /* (AV)^T(AV) + VtAV */ + TEMPLATE(T, mat_init) (DEF, block_size, block_size, ctx); /* Shared by D, E, and F */ + TEMPLATE(T, mat_init) (I, block_size, block_size, ctx); + TEMPLATE(T, mat_init) (tmp, block_size, block_size, ctx); + Mtb = _TEMPLATE(T, vec_init) (M->c, ctx); + SStVtMtb = _TEMPLATE(T, vec_init) (block_size, ctx); + WiSStVtMtb = _TEMPLATE(T, vec_init) (block_size, ctx); + VSStWiSStVtMtb = _TEMPLATE(T, vec_init) (M->c, ctx); + + _TEMPLATE(T, vec_zero) (x, M->c, ctx); + TEMPLATE(T, sparse_mat_transpose) (Mt, M, ctx); + for (i = 0; i < block_size; ++i) SSt[i] = 1; + TEMPLATE(T, mat_one) (I, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (Mtb, Mt, b, ctx); + + /* Initialize V[0] randomly */ + for (i = 0; i < V[0].r*V[0].c; ++i) + TEMPLATE(T, randtest) (&V[0].entries[i], state, ctx); + + for (iter = 0; ; ++iter) + { + i = iter % 3; + next_i = (iter + 1) % 3; + prev_i = (iter + 2) % 3; + if (iter >= 2) + { + /* Compute the F value for this round (minus the final term) */ + TEMPLATE(T, mat_addmul) (DEF, I, VtAV, &nWi[prev_i], ctx); + TEMPLATE(T, mat_mul) (tmp, &nWi[next_i], DEF, ctx); + TEMPLATE(T, mat_mul) (DEF, tmp, AVtAVSSt_VtAV, ctx); + } + + /* Compute AV and V'AV */ + TEMPLATE(T, sparse_mat_mul_mat) (MV, M, &V[i], ctx); + TEMPLATE(T, sparse_mat_mul_mat) (AV, Mt, MV, ctx); + TEMPLATE(T, mat_transpose) (T, &V[i], ctx); + TEMPLATE(T, mat_mul) (VtAV, T, AV, ctx); + if (TEMPLATE(T, mat_is_zero) (VtAV, ctx)) {ret = 1; break;} + + /* Compute W^{-1} and indices of bad vectors */ + cur_dim = compute_nWi_S(&nWi[i], SSt, VtAV, ctx); + total_dim += cur_dim; + if (cur_dim == 0 || total_dim > M->c) break; /* Ran out of vectors */ + + /* Update x_i = x_{i-1} - (VSS^t) W^{-1} (VSS^t)^tb */ + TEMPLATE(T, mat_set) (VSSt, &V[i], ctx); + kill_columns(VSSt, SSt, ctx); + TEMPLATE(T, mat_transpose) (T, VSSt, ctx); + TEMPLATE(T, mat_mul_vec) (SStVtMtb, T, Mtb, ctx); + TEMPLATE(T, mat_mul_vec) (WiSStVtMtb, &nWi[i], SStVtMtb, ctx); + TEMPLATE(T, mat_mul_vec) (VSStWiSStVtMtb, VSSt, WiSStVtMtb, ctx); + _TEMPLATE(T, vec_add) (x, x, VSStWiSStVtMtb, M->c, ctx); + + /** + * Per Equation (19), we compute the next vector + * V_{i+1} = AV_iS_iS_i^t + V_i D + V_{i-1} E + V_{i-2} F + * where + * D = I - W_i^-1((AV_i)^tAV_iS_iS_i^t + V_i^tAV_i) + * E = -W_{i-1}^-1V_i^tAV_iS_iS_i^t + * F = -W_{i-2}^-1(I - V_{i-1}^tAV_{i-1}W_{i-1}^-1) + * ((AV_{i-1})^tAV_{i-1}S_{i-1}S_{i-1}^t + V_{i-1}^tAV_{i-1})S_iS_i^t + **/ + if (iter >= 2) + { + /* V_{i+1} = V_{i-2} F */ + kill_columns(DEF, SSt, ctx); + TEMPLATE(T, mat_mul) (VSSt, &V[next_i], DEF, ctx); + TEMPLATE(T, mat_set) (&V[next_i], VSSt, ctx); + } + if (iter >= 1) + { + /* V_{i+1} += V_{i-1} E */ + TEMPLATE(T, mat_mul) (DEF, &nWi[prev_i], VtAV, ctx); + kill_columns(DEF, SSt, ctx); + TEMPLATE(T, mat_addmul) (&V[next_i], &V[next_i], &V[prev_i], DEF, ctx); + } + /* V_{i+1} += V_i D */ + TEMPLATE(T, mat_transpose) (T, AV, ctx); + TEMPLATE(T, mat_mul) (tmp, T, AV, ctx); + kill_columns(tmp, SSt, ctx); + TEMPLATE(T, mat_add) (AVtAVSSt_VtAV, tmp, VtAV, ctx); + TEMPLATE(T, mat_addmul) (DEF, I, &nWi[i], AVtAVSSt_VtAV, ctx); + TEMPLATE(T, mat_addmul) (&V[next_i], &V[next_i], &V[i], DEF, ctx); + + /* V_{i+1} += AVSS^t */ + kill_columns(AV, SSt, ctx); + TEMPLATE(T, mat_add) (&V[next_i], &V[next_i], AV, ctx); + + if (TEMPLATE(T, mat_is_zero) (&V[i], ctx)) {ret = 1; break;} + } + _TEMPLATE(T, vec_neg) (x, x, M->c, ctx); + TEMPLATE(T, sparse_mat_clear) (Mt, ctx); + for (i = 0; i < 3; ++i) TEMPLATE(T, mat_clear) (&V[i], ctx); + TEMPLATE(T, mat_clear) (MV, ctx); + TEMPLATE(T, mat_clear) (AV, ctx); + flint_free(SSt); + for (i = 0; i < 3; ++i) TEMPLATE(T, mat_clear) (&nWi[i], ctx); + TEMPLATE(T, mat_clear) (T, ctx); + TEMPLATE(T, mat_clear) (VtAV, ctx); + TEMPLATE(T, mat_clear) (VSSt, ctx); + TEMPLATE(T, mat_clear) (AVtAVSSt_VtAV, ctx); + TEMPLATE(T, mat_clear) (DEF, ctx); + TEMPLATE(T, mat_clear) (I, ctx); + TEMPLATE(T, mat_clear) (tmp, ctx); + _TEMPLATE(T, vec_clear) (Mtb, M->c, ctx); + _TEMPLATE(T, vec_clear) (SStVtMtb, block_size, ctx); + _TEMPLATE(T, vec_clear) (WiSStVtMtb, block_size, ctx); + _TEMPLATE(T, vec_clear) (VSStWiSStVtMtb, M->c, ctx); + return ret; +} + +int TEMPLATE(T, sparse_mat_nullvector_block_lanczos) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, slong block_size, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx) +{ + int ret = 1; + TEMPLATE(T, struct) *x2, *b; + x2 = _TEMPLATE(T, vec_init) (M->c, ctx); + b = _TEMPLATE(T, vec_init) (M->r, ctx); + + _TEMPLATE(T, vec_randtest) (x, state, M->c, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (b, M, x, ctx); + if (TEMPLATE(T, sparse_mat_solve_block_lanczos) (x2, M, b, block_size, state, ctx) == 0) ret = 0; /* Lanczos failed */ + if (ret) + { + _TEMPLATE(T, vec_sub) (x, x, x2, M->c, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (b, M, x, ctx); + ret = !_TEMPLATE(T, vec_is_zero) (x, M->c, ctx) && _TEMPLATE(T, vec_is_zero) (b, M->r, ctx); + } + _TEMPLATE(T, vec_clear) (x2, M->c, ctx); + _TEMPLATE(T, vec_clear) (b, M->r, ctx); + return ret; +} + + +#endif diff --git a/fq_sparse_mat_templates/solve_block_wiedemann.c b/fq_sparse_mat_templates/solve_block_wiedemann.c new file mode 100644 index 0000000000..71298aa459 --- /dev/null +++ b/fq_sparse_mat_templates/solve_block_wiedemann.c @@ -0,0 +1,261 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +/* Compute S_i=(M^j Y)_{0...b-1}^T for i = 0,...,ns-1 */ +static void make_block_sequences(TEMPLATE(T, mat_struct) *S, slong ns, const TEMPLATE(T, sparse_mat_t) M, TEMPLATE(T, mat_struct) Y[2], const TEMPLATE(T, ctx_t) ctx) +{ + slong iter, i, b = Y->c; + TEMPLATE(T, mat_struct) W[2]; + for (i = 0; i < 2; ++i) TEMPLATE(T, mat_window_init) (&W[i], &Y[i], 0, 0, b, b, ctx); + for (i = iter = 0; iter < ns; ++iter, i = 1-i) + { + if (iter > 0) TEMPLATE(T, sparse_mat_mul_mat) (&Y[i], M, &Y[1-i], ctx); + TEMPLATE(T, mat_transpose) (&S[iter], &W[i], ctx); + } + for (i = 0; i < 2; ++i) TEMPLATE(T, mat_window_clear) (&W[i], ctx); +} + +/** + * Run Guassian elimination on the first b columns of the augmented + * matrix M = [ D | I], yielding a final matrix + * [ | ] [ Z | ] + * [ D | I ] -> [---| tau ] + * [ | ] [ L | ] + * where the the number of nonzero rows in Z is the ith rank. We choose + * the pivot row for a given column to be the one with minimal degree. +**/ +static void coppersmith_aux_gauss(TEMPLATE(T, mat_t) M, slong *d, const TEMPLATE(T, ctx_t) ctx) +{ + const slong b = M->r/2; + slong pr, pc, r, tmp; + slong *gamma; + TEMPLATE(T, t) cinv, cc; + + TEMPLATE(T, init) (cinv, ctx); + TEMPLATE(T, init) (cc, ctx); + + /* Keep track of viable rows */ + gamma = flint_malloc(b*sizeof(*gamma)); + for (r = 0; r < b; ++r) gamma[r] = 1; + + for (pc = 0; pc < b; ++pc) + { + /* Set the pivot row to be the minimum degree row incident on column pc */ + pr = b + pc; + for (r = 0; r < b; r++) + if (gamma[r] && !TEMPLATE(T, is_zero) (&M->rows[r][pc], ctx) && d[r] < d[pr]) pr = r; + if (TEMPLATE(T, is_zero) (&M->rows[pr][pc], ctx)) continue; + + + /* Try to move pivot row to appropriate position (if not already there) */ + if (pr != b + pc) + { + tmp = d[pr]; d[pr] = d[b+pc]; d[b+pc] = tmp; + + if (!TEMPLATE(T, is_zero) (&M->rows[b + pc][pr], ctx)) + TEMPLATE(T, mat_swap_rows) (M, NULL, pr, b + pc, ctx), pr = b + pc; + else /* Need to make new auxiliary vector and remove r from use */ + _TEMPLATE(T, vec_add) (M->rows[b + pc], M->rows[b + pc], M->rows[pr], 3*b, ctx), gamma[pr] = 0; + } + TEMPLATE(T, inv) (cinv, &M->rows[pr][pc], ctx); + + /* Do Gaussian elimination on first b rows */ + for (r = 0; r < b; ++r) + if (gamma[r] && !TEMPLATE(T, is_zero) (&M->rows[r][pc], ctx)) + { + TEMPLATE(T, mul) (cc, &M->rows[r][pc], cinv, ctx); + TEMPLATE(T, neg) (cc, cc, ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (M->rows[r], M->rows[pr], M->c, cc, ctx); + } + } + TEMPLATE(T, clear) (cc, ctx); + TEMPLATE(T, clear) (cinv, ctx); + flint_free(gamma); +} + +/* Stop with failure if sum(d_0 ... d_{b-1}) < delta */ +/* Stop with success if sum(d_0 ... d_{b-1}) < delta + max(d_0 ... d_{b-1}) - min(d_b ... d_{2b-1}) */ +static int coppersmith_stopping_criterion(slong *d, slong delta, slong b) +{ + slong tmp, r; + + /* Sum degrees of generating polynomials */ + tmp = d[0]; for (r = 1; r < b; ++r) tmp += d[r]; + delta -= tmp; + if (delta < 0) return 0; /* Insufficient degree */ + + /* Add maximum degree of first b polys and subtract minimum degree of last b */ + tmp = d[0]; for (r = 1; r < b; ++r) if (d[r] > tmp) tmp = d[r]; + delta += tmp; + tmp = d[b]; for (r = b + 1; r < 2*b; ++r) if (d[r] < tmp) tmp = d[r]; + delta -= tmp; + return delta < 0 ? 1 : -1; +} + +/** + * Generalization of Berlekamp-Massey due to Coppersmith. + * Iteratively computes a sequence F representing 2b polynomials: + * - the first b are the current (reversed) generating polynomials + * - the last b are certain auxiliary polynomials. +**/ +static int find_block_min_poly(TEMPLATE(T, mat_struct) *S, slong *d, slong n, slong delta, const TEMPLATE(T, ctx_t) ctx) +{ + int ret; + slong t; + slong i, k, r, b = S->r; + slong f_len; + TEMPLATE(T, mat_struct) *F; + TEMPLATE(T, mat_t) M, D, tau, tmp; + + f_len = 1; + F = flint_malloc((n+1)*sizeof(*F)); + TEMPLATE(T, mat_init) (&F[0], 2*b, b, ctx); + TEMPLATE(T, mat_init) (tmp, b, b, ctx); + for (i = 0; i < b; ++i) d[i] = 0, d[b + i] = 1, TEMPLATE(T, one) (&F[0].rows[i][i], ctx); + + /* [ D | I ] -> [ ? | tau ]*/ + TEMPLATE(T, mat_init) (M, 2*b, 3*b, ctx); + + for (t = 0, ret = -1; t < n && ret == -1; ++t) + { + /* Compute discrepancy matrix and tau */ + TEMPLATE(T, mat_window_init) (D, M, 0, 0, 2*b, b, ctx); + TEMPLATE(T, mat_window_init) (tau, M, 0, b, 2*b, 3*b, ctx); + TEMPLATE(T, mat_zero) (D, ctx); + for (k = 0; k <= t; ++k) TEMPLATE(T, mat_addmul) (D, D, &F[k], &S[t-k], ctx); + TEMPLATE(T, mat_one) (tau, ctx); + TEMPLATE(T, mat_window_clear) (D, ctx); + TEMPLATE(T, mat_window_clear) (tau, ctx); + coppersmith_aux_gauss(M, d, ctx); + + /* Multiply F by tau * diag(I xI) */ + TEMPLATE(T, mat_window_init) (tau, M, 0, b, 2*b, 3*b, ctx); /* Needed since gauss reorders rows */ + TEMPLATE(T, mat_init) (&F[f_len++], 2*b, b, ctx); + for (k = f_len-1; k > 0; --k) + TEMPLATE(T, mat_mul) (&F[k], tau, &F[k-1], ctx); /* Every row multiplied by x */ + for (k = 0; k < f_len; ++k) + for (r = 0; r < b; ++r) /* Divide first b rows by x */ + { + if (k < f_len - 1) _TEMPLATE(T, vec_set) (F[k].rows[r], F[k+1].rows[r], b, ctx); + else _TEMPLATE(T, vec_zero) (F[k].rows[r], b, ctx); + } + for (r = b; r < 2*b; ++r) _TEMPLATE(T, vec_zero) (F[0].rows[r], b, ctx), d[r] += 1; + TEMPLATE(T, mat_window_clear) (tau, ctx); + ret = coppersmith_stopping_criterion(d, delta, b); + } + + /* Copy C to S, with each row reversed according to its degree */ + for (r = 0; r < b; ++r) + for (k = 0; k <= d[r]; k++) + _TEMPLATE(T, vec_set) (S[k].rows[r], F[d[r]-k].rows[r], b, ctx); + + for (k = 0; k < f_len; ++k) TEMPLATE(T, mat_clear) (&F[k], ctx); + TEMPLATE(T, mat_clear) (M, ctx); + flint_free(F); + return ret; +} + +static void make_block_sum(TEMPLATE(T, struct) *x, const TEMPLATE(T, mat_struct) *S, const slong *d, const TEMPLATE(T, sparse_mat_t) M, TEMPLATE(T, mat_struct) Z[2], slong l, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, iter, b = S->r; + slong dd; + TEMPLATE(T, struct) *xi; + + /* Compute differences between nominal and real degree */ + dd = 0; + while (_TEMPLATE(T, vec_is_zero) (S[dd].rows[l], b, ctx)) ++dd; + + /* Simulaneously apply all polynomials in row l to iteration of M on Z */ + xi = _TEMPLATE(T, vec_init) (M->c, ctx); + _TEMPLATE(T, vec_zero) (x, M->c, ctx); + for (i = iter = 0; iter <= d[l]; ++iter, i = 1 - i) + { + if (iter > 0) TEMPLATE(T, sparse_mat_mul_mat) (&Z[i], M, &Z[1-i], ctx); + TEMPLATE(T, mat_mul_vec) (xi, &Z[i], S[dd + iter].rows[l], ctx); + _TEMPLATE(T, vec_add) (x, x, xi, M->c, ctx); + } + _TEMPLATE(T, vec_clear) (xi, M->c, ctx); +} + +int TEMPLATE(T, sparse_mat_solve_block_wiedemann) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, slong block_size, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx) +{ + int good = 0, ret; + TEMPLATE (T, struct) *x1; + TEMPLATE(T, sparse_vec_t) z; + TEMPLATE(T, sparse_mat_t) Mb; + if (M->r != M->c) return 0; /* TODO */ + if (_TEMPLATE(T, vec_is_zero) (b, M->c, ctx)) + { + _TEMPLATE(T, vec_zero) (x, M->c, ctx); + return 1; + } + + /* TODO: Precondition M */ + x1 = _TEMPLATE(T, vec_init) (M->c + 1, ctx); + TEMPLATE(T, sparse_vec_init) (z, ctx); + TEMPLATE(T, sparse_mat_init) (Mb, M->r, M->c, ctx); + TEMPLATE(T, sparse_mat_set) (Mb, M, ctx); + TEMPLATE(T, sparse_mat_append_col) (Mb, b, ctx); + TEMPLATE(T, sparse_mat_append_row) (Mb, z, ctx); + + ret = TEMPLATE(T, sparse_mat_nullvector_block_wiedemann) (x1, Mb, block_size, state, ctx); + if (ret && !TEMPLATE(T, is_zero) (&x1[M->c], ctx)) + { + TEMPLATE(T, inv) (&x1[M->c], &x1[M->c], ctx); + TEMPLATE(T, neg) (&x1[M->c], &x1[M->c], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (x, x1, M->c, &x1[M->c], ctx); + good = 1; + } + TEMPLATE(T, sparse_vec_clear) (z, ctx); + TEMPLATE(T, sparse_mat_clear) (Mb, ctx); + _TEMPLATE(T, vec_clear) (x1, M->c + 1, ctx); + return good; +} + +int TEMPLATE(T, sparse_mat_nullvector_block_wiedemann) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, slong block_size, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx) +{ + int ret = 0; + slong l, ns, k; + slong *d; + TEMPLATE(T, struct) *b; + TEMPLATE(T, mat_struct) Y[3], *S; + if (M->r != M->c) return 0; /* TODO */ + + ns = 2*M->r/block_size + 3; /* Maybe 5? */ + S = flint_malloc(ns*sizeof(*S)); + d = flint_calloc(2*block_size, sizeof(*d)); + b = _TEMPLATE(T, vec_init) (M->r, ctx); + for (k = 0; k < ns; ++k) TEMPLATE(T, mat_init) (&S[k], block_size, block_size, ctx); + for (l = 0; l < 3; ++l) TEMPLATE(T, mat_init) (&Y[l], M->c, block_size, ctx); + do TEMPLATE(T, mat_randtest) (&Y[0], state, ctx); + while (TEMPLATE(T, mat_is_zero) (&Y[0], ctx)); + + TEMPLATE(T, sparse_mat_mul_mat) (&Y[1], M, &Y[0], ctx); + make_block_sequences(S, ns, M, &Y[1], ctx); + find_block_min_poly(S, d, ns, M->r, ctx); + + for (l = 0; l < block_size; ++l) + { + TEMPLATE(T, mat_set) (&Y[1], &Y[0], ctx); + make_block_sum(x, S, d, M, Y + 1, l, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (b, M, x, ctx); + if (!_TEMPLATE(T, vec_is_zero) (x, M->c, ctx) && _TEMPLATE(T, vec_is_zero) (b, M->r, ctx)) {ret = 1; break;}; + } + return ret; +} + +#endif diff --git a/fq_sparse_mat_templates/solve_lanczos.c b/fq_sparse_mat_templates/solve_lanczos.c new file mode 100644 index 0000000000..4b1c076a0d --- /dev/null +++ b/fq_sparse_mat_templates/solve_lanczos.c @@ -0,0 +1,127 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +int TEMPLATE(T, sparse_mat_solve_lanczos) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx) +{ + slong j, ret; + + /* We assume that M is not symmetric, and work with A = M^t M */ + TEMPLATE(T, t) cinv, cc, AvtAv, vMtb, alpha, beta; + TEMPLATE(T, struct) *v[2], *Mv, *Av, *Mtb, vtAv[2]; + TEMPLATE(T, sparse_mat_t) Mt; + + if (_TEMPLATE(T, vec_is_zero) (b, M->r, ctx)) + { + _TEMPLATE(T, vec_zero) (x, M->c, ctx); + return 1; + } + + TEMPLATE(T, init) (cinv, ctx); + TEMPLATE(T, init) (cc, ctx); + TEMPLATE(T, init) (AvtAv, ctx); + TEMPLATE(T, init) (vMtb, ctx); + TEMPLATE(T, init) (alpha, ctx); + TEMPLATE(T, init) (beta, ctx); + TEMPLATE(T, init) (&vtAv[0], ctx); + TEMPLATE(T, init) (&vtAv[1], ctx); + v[0] = _TEMPLATE(T, vec_init) (M->c, ctx); + v[1] = _TEMPLATE(T, vec_init) (M->c, ctx); + Mv = _TEMPLATE(T, vec_init) (M->r, ctx); + Av = _TEMPLATE(T, vec_init) (M->c, ctx); + Mtb = _TEMPLATE(T, vec_init) (M->c, ctx); + TEMPLATE(T, sparse_mat_init) (Mt, M->c, M->r, ctx); + + /* Construct transpose */ + TEMPLATE(T, sparse_mat_transpose) (Mt, M, ctx); + + + /* Set starting data */ + _TEMPLATE(T, vec_randtest) (v[0], state, M->c, ctx); + _TEMPLATE(T, vec_zero) (v[1], M->c, ctx); + TEMPLATE(T, one) (&vtAv[1], ctx); + _TEMPLATE(T, vec_zero) (x, M->c, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (Mtb, Mt, b, ctx); + for (j = 0; ; j = 1-j) + { + /* Compute M^T M v_j and check if it is orthogonal to v_j */ + TEMPLATE(T, sparse_mat_mul_vec) (Mv, M, v[j], ctx); + TEMPLATE(T, sparse_mat_mul_vec) (Av, Mt, Mv, ctx); + _TEMPLATE(T, vec_dot) (&vtAv[j], v[j], Av, M->c, ctx); + if (TEMPLATE(T, is_zero) (&vtAv[j], ctx)) break; /* Can't make any more progress */ + + /* Update putative solution by /delta_j * v_j */ + _TEMPLATE(T, vec_dot) (cc, v[j], Mtb, M->c, ctx); + TEMPLATE(T, div) (cc, cc, &vtAv[j], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (x, v[j], M->c, cc, ctx); + + /* v_{j+1} = AtAv - alpha*v_j - beta*v_{j-1}, where */ + /* alpha = /delta_j, and */ + /* beta = delta_j/delta_{j-1} */ + TEMPLATE(T, div) (cc, &vtAv[j], &vtAv[1-j], ctx); + TEMPLATE(T, neg) (cc, cc, ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T))(v[1-j], v[1-j], M->c, cc, ctx); + _TEMPLATE(T, vec_dot) (cc, Av, Av, M->c, ctx); + TEMPLATE(T, div) (cc, cc, &vtAv[j], ctx); + TEMPLATE(T, neg) (cc, cc, ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (v[1-j], v[j], M->c, cc, ctx); + _TEMPLATE(T, vec_add) (v[1-j], v[1-j], Av, M->c, ctx); + } + /* Check result */ + TEMPLATE(T, sparse_mat_mul_vec) (Mv, M, x, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (Av, Mt, Mv, ctx); + ret = _TEMPLATE(T, vec_equal) (Av, Mtb, M->c, ctx); + + /* Clear auxiliary vectors and transpose */ + TEMPLATE(T, clear) (cc, ctx); + TEMPLATE(T, clear) (cinv, ctx); + TEMPLATE(T, clear) (AvtAv, ctx); + TEMPLATE(T, clear) (vMtb, ctx); + TEMPLATE(T, clear) (alpha, ctx); + TEMPLATE(T, clear) (beta, ctx); + TEMPLATE(T, clear) (&vtAv[0], ctx); + TEMPLATE(T, clear) (&vtAv[1], ctx); + _TEMPLATE(T, vec_clear) (v[0], M->c, ctx); + _TEMPLATE(T, vec_clear) (v[1], M->c, ctx); + _TEMPLATE(T, vec_clear) (Mv, M->r, ctx); + _TEMPLATE(T, vec_clear) (Av, M->c, ctx); + _TEMPLATE(T, vec_clear) (Mtb, M->c, ctx); + TEMPLATE(T, sparse_mat_clear) (Mt, ctx); + return ret; +} + +int TEMPLATE(T, sparse_mat_nullvector_lanczos) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx) +{ + int ret = 1; + TEMPLATE(T, struct) *x2, *b; + x2 = _TEMPLATE(T, vec_init) (M->c, ctx); + b = _TEMPLATE(T, vec_init) (M->r, ctx); + + _TEMPLATE(T, vec_randtest) (x, state, M->c, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (b, M, x, ctx); + if (TEMPLATE(T, sparse_mat_solve_lanczos) (x2, M, b, state, ctx) == 0) ret = 0; /* Lanczos failed */ + if (ret) + { + _TEMPLATE(T, vec_sub) (x, x, x2, M->c, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (b, M, x, ctx); + ret = !_TEMPLATE(T, vec_is_zero) (x, M->c, ctx) && _TEMPLATE(T, vec_is_zero) (b, M->r, ctx); + } + _TEMPLATE(T, vec_clear) (x2, M->c, ctx); + _TEMPLATE(T, vec_clear) (b, M->r, ctx); + return ret; +} + +#endif diff --git a/fq_sparse_mat_templates/solve_lu.c b/fq_sparse_mat_templates/solve_lu.c new file mode 100644 index 0000000000..5946414baf --- /dev/null +++ b/fq_sparse_mat_templates/solve_lu.c @@ -0,0 +1,76 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +/* PAQ = LU, Ax = b => set b' = Pb, solve Ly = b', solve Ux' = y, set x = Qx' */ +int TEMPLATE(T, sparse_mat_solve_lu) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, const TEMPLATE(T, ctx_t) ctx) +{ + int good = 1; + slong rk, *P, *Q, i; + TEMPLATE(T, t) cc; + TEMPLATE(T, struct) *bp, *y, *xp; + TEMPLATE(T, sparse_mat_t) L, U; + if (_TEMPLATE(T, vec_is_zero) (b, M->r, ctx)) + { + _TEMPLATE(T, vec_zero) (x, M->c, ctx); + return 1; + } + + P = flint_malloc(M->r * sizeof(*P)); + Q = flint_malloc(M->c * sizeof(*Q)); + TEMPLATE(T, init) (cc, ctx); + bp = _TEMPLATE(T, vec_init) (M->r, ctx); + xp = _TEMPLATE(T, vec_init) (M->c, ctx); + TEMPLATE(T, sparse_mat_init) (L, M->r, M->c, ctx); + TEMPLATE(T, sparse_mat_init) (U, M->r, M->c, ctx); + + rk = TEMPLATE(T, sparse_mat_lu) (P, Q, L, U, M, ctx); + y = _TEMPLATE(T, vec_init) (rk, ctx); + + /* Solve Ly = b' = Pb */ + for (i = 0; i < M->r; ++i) TEMPLATE(T, set) (&bp[P[i]], &b[i], ctx); + + for (i = 0; i < rk; ++i) + { + TEMPLATE(T, sparse_vec_dot_dense) (cc, &L->rows[i], y, ctx); + TEMPLATE(T, sub) (&y[i], &bp[i], cc, ctx); + } + for (i = rk; i < M->r; ++i) + { + TEMPLATE(T, sparse_vec_dot_dense) (cc, &L->rows[i], y, ctx); + if (!TEMPLATE(T, equal) (&bp[i], cc, ctx)) {good = 0; break;} + } + + if (good) + { + /* Find a solution for Ux' = y */ + for (i = rk-1; i >= 0; --i) + { + TEMPLATE(T, sparse_vec_dot_dense) (&xp[i], &U->rows[i], xp, ctx); + TEMPLATE(T, sub) (&xp[i], &y[i], &xp[i], ctx); + TEMPLATE(T, div) (&xp[i], &xp[i], U->rows[i].entries[0].val, ctx); + } + for (i = 0; i < M->c; ++i) TEMPLATE(T, set) (&x[i], &xp[Q[i]], ctx); + } + TEMPLATE(T, sparse_mat_clear) (L, ctx); + TEMPLATE(T, sparse_mat_clear) (U, ctx); + _TEMPLATE(T, vec_clear) (xp, M->c, ctx); + _TEMPLATE(T, vec_clear) (y, rk, ctx); + _TEMPLATE(T, vec_clear) (bp, M->r, ctx); + return good; +} + +#endif diff --git a/fq_sparse_mat_templates/solve_rref.c b/fq_sparse_mat_templates/solve_rref.c new file mode 100644 index 0000000000..022bb21f29 --- /dev/null +++ b/fq_sparse_mat_templates/solve_rref.c @@ -0,0 +1,55 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +int TEMPLATE(T, sparse_mat_solve_rref) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) M, const TEMPLATE(T, struct) *b, const TEMPLATE(T, ctx_t) ctx) +{ + int good = 1; + slong i; + TEMPLATE(T, sparse_mat_t) Mb; + TEMPLATE(T, sparse_vec_struct) *row; + TEMPLATE(T, sparse_entry_struct) *le, *re; + if (_TEMPLATE(T, vec_is_zero) (b, M->r, ctx)) + { + _TEMPLATE(T, vec_zero) (x, M->c, ctx); + return 1; + } + + TEMPLATE(T, sparse_mat_init) (Mb, M->r, M->c, ctx); + + TEMPLATE(T, sparse_mat_set) (Mb, M, ctx); + TEMPLATE(T, sparse_mat_append_col) (Mb, b, ctx); + Mb->c = M->c; + TEMPLATE(T, sparse_mat_rref) (Mb, ctx); + Mb->c = M->c+1; + + _TEMPLATE(T, vec_zero) (x, M->c, ctx); + for (i = 0; i < M->r; ++i) + { + row = &Mb->rows[i]; + if (row->nnz == 0) continue; + le = &row->entries[0]; + re = &row->entries[row->nnz-1]; + /* If any row has leading col M->c, system is not solvable */ + if (le->ind==M->c) {good = 0; break;} + /* Otherwise, x[lc] = lagging value */ + if (re->ind==M->c) TEMPLATE(T, set) (&x[le->ind], re->val, ctx); + } + TEMPLATE(T, sparse_mat_clear) (Mb, ctx); + return good; +} + +#endif diff --git a/fq_sparse_mat_templates/solve_wiedemann.c b/fq_sparse_mat_templates/solve_wiedemann.c new file mode 100644 index 0000000000..b67656b491 --- /dev/null +++ b/fq_sparse_mat_templates/solve_wiedemann.c @@ -0,0 +1,183 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +/* Berlekamp - Massey algorithm */ +static slong find_min_poly(TEMPLATE(T, struct) *s, slong N, const TEMPLATE(T, ctx_t) ctx) +{ + slong L = 0, m, n, i; + slong deg_C = 0, deg_B = 0, deg_T = -1; + TEMPLATE(T, t) cinv, cc, d_C, d_B; + TEMPLATE(T, struct) *B, *C, *T; + + TEMPLATE(T, init) (cinv, ctx); + TEMPLATE(T, init) (cc, ctx); + TEMPLATE(T, init) (d_C, ctx); + TEMPLATE(T, init) (d_B, ctx); + B = _TEMPLATE(T, vec_init) (N, ctx); + C = _TEMPLATE(T, vec_init) (N, ctx); + T = _TEMPLATE(T, vec_init) (N, ctx); + TEMPLATE(T, one) (&B[0], ctx); + TEMPLATE(T, one) (&C[0], ctx); + TEMPLATE(T, one) (d_B, ctx); + + for (n = 0, m = 1; n < N; n++, m++) + { + /* d_C = sum_{i = 0}^L C_i * s_{n-i} */ + TEMPLATE(T, set) (d_C, &s[n], ctx); + for (i = 1; i <= L; i++) + { + TEMPLATE(T, mul) (cc, &C[i], &s[n-i], ctx); + TEMPLATE(T, add) (d_C, d_C, cc, ctx); + } + if (TEMPLATE(T, is_zero)(d_C, ctx)) continue; /* C and L currently valid */ + + /* C(x) = C(x) - (d_C/d_B) x^m B(x); */ + if (L <= 2*n) deg_T = deg_C, _TEMPLATE(T, vec_set) (T, C, deg_C+1, ctx); /* T(X) = C(X) */ + TEMPLATE(T, div) (cinv, d_C, d_B, ctx); + TEMPLATE(T, neg) (cinv, cinv, ctx); + for (i = 0; i <= deg_B; ++i) + { + TEMPLATE(T, mul) (cc, &B[i], cinv, ctx); + TEMPLATE(T, add) (&C[m+i], &C[m+i], cc, ctx); + } + deg_C = FLINT_MAX(deg_C, deg_B + m); + while (TEMPLATE(T, is_zero) (&C[deg_C], ctx)) --deg_C; /* Probably unnecessary */ + + if (2*L <= n) /* Increase number of errors */ + { + L = n + 1 - L, m = 0; + TEMPLATE(T, set) (d_B, d_C, ctx), deg_B = deg_T; + _TEMPLATE(T, vec_set) (B, T, deg_T+1, ctx); + } + } + /* Reverse C into s */ + for (i = 0; i <= L; ++i) TEMPLATE(T, set) (&s[i], &C[L-i], ctx); + + TEMPLATE(T, clear) (cinv, ctx); + TEMPLATE(T, clear) (cc, ctx); + TEMPLATE(T, clear) (d_C, ctx); + TEMPLATE(T, clear) (d_B, ctx); + _TEMPLATE(T, vec_clear) (B, N, ctx); + _TEMPLATE(T, vec_clear) (C, N, ctx); + _TEMPLATE(T, vec_clear) (T, N, ctx); + return L; +} + +/* Compute s_ij=(A^j y)_i for i = 0,...,ns-1, j = 0,...,num-1*/ +static void make_sequences(TEMPLATE(T, struct) **s, slong ns, slong len, const TEMPLATE(T, sparse_mat_t) A, TEMPLATE(T, struct) **y, const TEMPLATE(T, ctx_t) ctx) +{ + slong iter, i, j; + for (i = iter = 0; iter < len; ++iter, i = 1-i) + { + if (iter > 0) TEMPLATE(T, sparse_mat_mul_vec) (y[i], A, y[1-i], ctx); + for (j = 0; j < ns; ++j) TEMPLATE(T, set) (&s[j][iter], &y[i][j], ctx); + } +} + +/* Compute x = \Sigma_{i = 0}^{L-1} s_i * A^i * b = 0 */ +static void make_sum(TEMPLATE(T, struct) *x, TEMPLATE(T, struct) *s, slong L, const TEMPLATE(T, sparse_mat_t) A, TEMPLATE(T, struct) **y, const TEMPLATE(T, ctx_t) ctx) +{ + slong iter, i; + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (x, y[0], A->r, &s[0], ctx); + for (i = iter = 1; iter < L; ++iter, i = 1-i) + { + TEMPLATE(T, sparse_mat_mul_vec) (y[i], A, y[1-i], ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_addmul, T)) (x, y[i], A->r, &s[iter], ctx); + } +} + +int TEMPLATE(T, sparse_mat_solve_wiedemann) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) A, const TEMPLATE(T, struct) *b, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, L, ret = 0, ns = FLINT_MIN(A->r, 2), len = 2*A->r + 1; + TEMPLATE(T, t) cc; + TEMPLATE(T, struct) **s, *y[2]; + if (A->r != A->c) return 0; /* TBD: reduce to square */ + if (_TEMPLATE(T, vec_is_zero) (b, A->r, ctx)) + { + _TEMPLATE(T, vec_zero) (x, A->c, ctx); + return 1; + } + TEMPLATE(T, init) (cc, ctx); + s = flint_malloc(ns * sizeof(*s)); + for (i = 0; i < ns; ++i) s[i] = _TEMPLATE(T, vec_init) (len, ctx); + for (i = 0; i < 2; ++i) y[i] = _TEMPLATE(T, vec_init) (A->r, ctx); + + _TEMPLATE(T, vec_set) (y[0], b, A->r, ctx); + + /* Make some number of sequences to be tried */ + make_sequences(s, ns, len, A, y, ctx); + + /* Try both sequences */ + for (i = 0; i < ns && ret == 0; ++i) + { + /* Get minimal polynomial */ + L = find_min_poly(s[i], len, ctx); + if (TEMPLATE(T, is_zero) (&s[i][0], ctx)) continue; + + /* If \sum_{j = 0}^L s_ijA^jb = 0 => x = -1/s[0]\sum_{j = 0}^{L-1} s_i(j-1) A^jb solves Ax = b */ + _TEMPLATE(T, vec_set) (y[0], b, A->r, ctx); + make_sum(x, s[i]+1, L, A, y, ctx); + TEMPLATE(T, inv) (cc, &s[i][0], ctx); + TEMPLATE(T, neg) (cc, cc, ctx); + _TEMPLATE(T, TEMPLATE(vec_scalar_mul, T)) (x, x, A->r, cc, ctx); + + /* Check if successful */ + TEMPLATE(T, sparse_mat_mul_vec) (y[0], A, x, ctx); + ret = _TEMPLATE(T, vec_equal) (y[0], b, A->r, ctx); + } + + TEMPLATE(T, clear) (cc, ctx); + for (i = 0; i < ns; ++i) _TEMPLATE(T, vec_clear) (s[i], len, ctx); + for (i = 0; i < 2; ++i) _TEMPLATE(T, vec_clear) (y[i], A->r, ctx); + flint_free(s); + return ret; +} + +int TEMPLATE(T, sparse_mat_nullvector_wiedemann) (TEMPLATE(T, struct) *x, const TEMPLATE(T, sparse_mat_t) A, flint_rand_t state, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, L, ret = 0, ns = FLINT_MIN(A->r, 2), len = 2*A->r + 1; + TEMPLATE(T, struct) **s, *y[3]; + + if (A->r != A->c) return 0; /* TBD: reduce to square */ + + s = flint_malloc(ns * sizeof(*s)); + for (i = 0; i < ns; ++i) s[i] = _TEMPLATE(T, vec_init) (len, ctx); + for (i = 0; i < 3; ++i) y[i] = _TEMPLATE(T, vec_init) (A->r, ctx); + + _TEMPLATE(T, vec_randtest) (y[0], state, A->r, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (y[1], A, y[0], ctx); + + make_sequences(s, ns, len, A, &y[1], ctx); + + for (i = 0; i < ns && ret == 0; ++i) + { + /* Get minimal polynomial */ + L = find_min_poly(s[i], len, ctx); + + /* \sum_{j = 0}^L s_ijA^jb = 0 => x = \sum_{j = 0}^L s_ijA^jx solves Ax = 0 */ + _TEMPLATE(T, vec_set) (y[1], y[0], A->r, ctx); + make_sum(x, s[i], L+1, A, &y[1], ctx); + TEMPLATE(T, sparse_mat_mul_vec) (y[1], A, x, ctx); + ret = !_TEMPLATE(T, vec_is_zero) (x, A->c, ctx) && _TEMPLATE(T, vec_is_zero) (y[1], A->r, ctx); + } + for (i = 0; i < ns; ++i) _TEMPLATE(T, vec_clear) (s[i], len, ctx); + for (i = 0; i < 3; ++i) _TEMPLATE(T, vec_clear) (y[i], A->r, ctx); + flint_free(s); + return ret; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-add.c b/fq_sparse_mat_templates/test/t-add.c new file mode 100644 index 0000000000..c7a001930a --- /dev/null +++ b/fq_sparse_mat_templates/test/t-add.c @@ -0,0 +1,67 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, B, C, D; + FLINT_TEST_INIT(state); + + flint_printf("add/sub...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + r = n_randint(state, 200); + c = n_randint(state, 200); + + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (B, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (C, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (D, r, c, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_randtest) (B, state, 0, c, ctx); + + TEMPLATE(T, sparse_mat_add) (C, A, B, ctx); + TEMPLATE(T, sparse_mat_sub) (D, C, B, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (D, A, ctx)) + { + flint_printf("FAIL\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (B, ctx); + TEMPLATE(T, sparse_mat_clear) (C, ctx); + TEMPLATE(T, sparse_mat_clear) (D, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-concat_horizontal.c b/fq_sparse_mat_templates/test/t-concat_horizontal.c new file mode 100644 index 0000000000..0fce63dcb4 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-concat_horizontal.c @@ -0,0 +1,106 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int main(void) +{ + slong rep, r, c1, c2, nreps = 100; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, B, C; + TEMPLATE(T, sparse_mat_t) window1, window2; + FLINT_TEST_INIT(state); + + flint_printf("concat_horizontal...."); + fflush(stdout); + + + for (rep = 0; rep < nreps; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + r = n_randint(state, 20); + c1 = n_randint(state, 20); + c2 = n_randint(state, 20); + TEMPLATE(T, sparse_mat_init) (A, r, c1, ctx); + TEMPLATE(T, sparse_mat_init) (B, r, c2, ctx); + TEMPLATE(T, sparse_mat_init) (C, r, c1+c2, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c1, ctx); + TEMPLATE(T, sparse_mat_randtest) (B, state, 0, c2, ctx); + TEMPLATE(T, sparse_mat_randtest) (C, state, 0, c1+c2, ctx); + + TEMPLATE(T, sparse_mat_concat_horizontal) (C, A, B, ctx); + + TEMPLATE(T, sparse_mat_window_init) (window1, C, 0, 0, r, c1, ctx); + TEMPLATE(T, sparse_mat_window_init) (window2, C, 0, c1, r, c1+c2, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (window1, A, ctx) || !TEMPLATE(T, sparse_mat_equal) (window2, B, ctx)) + { + flint_printf("A = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (A, ctx); + flint_printf("B = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (B, ctx); + flint_printf("A | B = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (C, ctx); + flint_printf("window1 = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (window1, ctx); + flint_printf("window2 = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (window2, ctx); + flint_printf("FAIL: window 2 not equal\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_window_clear) (window1, ctx); + TEMPLATE(T, sparse_mat_window_clear) (window2, ctx); + + TEMPLATE(T, sparse_mat_init) (window1, r, c1, ctx); + TEMPLATE(T, sparse_mat_init) (window2, r, c2, ctx); + TEMPLATE(T, sparse_mat_split_horizontal) (window1, window2, C, c1, ctx); + + if (!(TEMPLATE(T, sparse_mat_equal) (window1, A, ctx) && TEMPLATE(T, sparse_mat_equal) (window2, B, ctx))) + { + flint_printf("A = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (A, ctx); + flint_printf("B = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (B, ctx); + flint_printf("A | B = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (C, ctx); + flint_printf("window1 = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (window1, ctx); + flint_printf("window2 = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (window2, ctx); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_window_clear) (window1, ctx); + TEMPLATE(T, sparse_mat_window_clear) (window2, ctx); + + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (B, ctx); + TEMPLATE(T, sparse_mat_clear) (C, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-concat_vertical.c b/fq_sparse_mat_templates/test/t-concat_vertical.c new file mode 100644 index 0000000000..6af7034d74 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-concat_vertical.c @@ -0,0 +1,99 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int main(void) +{ + slong rep, r1, r2, c, nreps = 100; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, B, C; + TEMPLATE(T, sparse_mat_t) window1, window2; + FLINT_TEST_INIT(state); + + + flint_printf("concat_vertical...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + r1 = n_randint(state, 100); + r2 = n_randint(state, 100); + c = n_randint(state, 100); + TEMPLATE(T, sparse_mat_init) (A, r1, c, ctx); + TEMPLATE(T, sparse_mat_init) (B, r2, c, ctx); + TEMPLATE(T, sparse_mat_init) (C, r1+r2, c, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_randtest) (B, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_randtest) (C, state, 0, c, ctx); + + TEMPLATE(T, sparse_mat_concat_vertical) (C, A, B, ctx); + + TEMPLATE(T, sparse_mat_window_init) (window1, C, 0, 0, r1, c, ctx); + TEMPLATE(T, sparse_mat_window_init) (window2, C, r1, 0, r1+r2, c, ctx); + + if (!(TEMPLATE(T, sparse_mat_equal) (window1, A, ctx) && TEMPLATE(T, sparse_mat_equal) (window2, B, ctx))) + { + flint_printf("A = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (A, ctx); + flint_printf("B = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (B, ctx); + flint_printf("A concat_vertical B = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (C, ctx); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_window_clear) (window1, ctx); + TEMPLATE(T, sparse_mat_window_clear) (window2, ctx); + + TEMPLATE(T, sparse_mat_init) (window1, r1, c, ctx); + TEMPLATE(T, sparse_mat_init) (window2, r2, c, ctx); + TEMPLATE(T, sparse_mat_split_vertical) (window1, window2, C, r1, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (window1, A, ctx) || !TEMPLATE(T, sparse_mat_equal) (window2, B, ctx)) + { + flint_printf("A = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (A, ctx); + flint_printf("B = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (B, ctx); + flint_printf("A concat_vertical B = \n"); + TEMPLATE(T, sparse_mat_print_pretty) (C, ctx); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_window_clear) (window1, ctx); + TEMPLATE(T, sparse_mat_window_clear) (window2, ctx); + + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (B, ctx); + TEMPLATE(T, sparse_mat_clear) (C, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-construct.c b/fq_sparse_mat_templates/test/t-construct.c new file mode 100644 index 0000000000..347daea151 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-construct.c @@ -0,0 +1,99 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c, i, j, k, nnz; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, B, C; + slong *rows; + slong *cols; + TEMPLATE(T, struct) *vals; + FLINT_TEST_INIT(state); + + flint_printf("construction from entries...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + r = n_randint(state, 10); + c = n_randint(state, 10); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (B, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (C, 0, c, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 2, 2, ctx); + TEMPLATE(T, sparse_mat_randtest) (B, state, 2, 2, ctx); + nnz = 0; + for (i = 0; i < r; ++i) nnz += A->rows[i].nnz; + + /* Construct B from entries of A */ + rows = flint_malloc(nnz * sizeof(*rows)); + cols = flint_malloc(nnz * sizeof(*cols)); + vals = _TEMPLATE(T, vec_init) (nnz, ctx); + for (i = k = 0; i < r; ++i) + { + for (j = 0; j < A->rows[i].nnz; ++j, ++k) + { + rows[k] = i; + cols[k] = A->rows[i].entries[j].ind; + TEMPLATE(T, set) (&vals[k], A->rows[i].entries[j].val, ctx); + } + } + TEMPLATE(T, sparse_mat_from_entries) (B, rows, cols, vals, nnz, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (A, B, ctx)) + { + flint_printf("FAIL: A != B\n"); + flint_printf("A = "); + TEMPLATE(T, sparse_mat_print_pretty) (A, ctx); + flint_printf("B = "); + TEMPLATE(T, sparse_mat_print_pretty) (B, ctx); + abort(); + } + + for (i = 0; i < r; ++i) TEMPLATE(T, sparse_mat_append_row) (C, &A->rows[i], ctx); + if (!TEMPLATE(T, sparse_mat_equal) (A, C, ctx)) + { + flint_printf("FAIL: A != C\n"); + flint_printf("A = "); + TEMPLATE(T, sparse_mat_print_pretty) (A, ctx); + flint_printf("C = "); + TEMPLATE(T, sparse_mat_print_pretty) (C, ctx); + abort(); + } + flint_free(rows); + flint_free(cols); + _TEMPLATE(T, vec_clear) (vals, nnz, ctx); + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (B, ctx); + TEMPLATE(T, sparse_mat_clear) (C, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-dense.c b/fq_sparse_mat_templates/test/t-dense.c new file mode 100644 index 0000000000..49819c0205 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-dense.c @@ -0,0 +1,76 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, B; + TEMPLATE(T, mat_t) C, D; + FLINT_TEST_INIT(state); + + + flint_printf("conversion to/from dense matrix...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + r = n_randint(state, 10); + c = n_randint(state, 10); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (B, r, c, ctx); + TEMPLATE(T, mat_init) (C, r, c, ctx); + TEMPLATE(T, mat_init) (D, r, c, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_to_dense) (C, A, ctx); + TEMPLATE(T, sparse_mat_from_dense) (B, C, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (A, B, ctx)) + { + flint_printf("FAIL: A != B\n"); + abort(); + } + + TEMPLATE(T, mat_randtest) (C, state, ctx); + TEMPLATE(T, sparse_mat_from_dense) (A, C, ctx); + TEMPLATE(T, sparse_mat_to_dense) (D, A, ctx); + + if (!TEMPLATE(T, mat_equal) (C, D, ctx)) + { + flint_printf("FAIL: C != D\n"); + abort(); + } + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (B, ctx); + TEMPLATE(T, mat_clear) (C, ctx); + TEMPLATE(T, mat_clear) (D, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-init_clear.c b/fq_sparse_mat_templates/test/t-init_clear.c new file mode 100644 index 0000000000..7f8f1833cb --- /dev/null +++ b/fq_sparse_mat_templates/test/t-init_clear.c @@ -0,0 +1,64 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c, i; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A; + FLINT_TEST_INIT(state); + + + flint_printf("init/clear...."); + fflush(stdout); + + for (rep = 0; rep < 100; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + r = n_randint(state, 200); + c = n_randint(state, 200); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + + if (!TEMPLATE(T, sparse_mat_is_zero) (A, ctx)) + { + flint_printf("FAIL: A not zero!\n"); + abort(); + } + for (i = 0; i < r; i++) + { + if (!TEMPLATE(T, sparse_vec_is_zero) (&A->rows[i], ctx)) + { + flint_printf("FAIL: row %wd not zero!\n", i); + abort(); + } + } + + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-inv.c b/fq_sparse_mat_templates/test/t-inv.c new file mode 100644 index 0000000000..e07bd8e1a6 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-inv.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" +#include + +int +main(void) +{ + slong rep, r, c; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, Ai; + TEMPLATE(T, mat_t) dA, dAiA; + FLINT_TEST_INIT(state); + + flint_printf("inverting A...."); + fflush(stdout); + + for (rep = 0; rep < 200; rep++) + { + if (rep % 5==0) {flint_printf("."); fflush(stdout);} + TEMPLATE(T, ctx_randtest) (ctx, state); + do r = n_randint(state, 100), c = n_randint(state, 100); + while (r==UWORD(0) || c==UWORD(0)); + + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (Ai, r, r, ctx); + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c, ctx); + TEMPLATE(T, mat_init) (dA, r, c, ctx); + TEMPLATE(T, mat_init) (dAiA, r, c, ctx); + TEMPLATE(T, sparse_mat_to_dense) (dA, A, ctx); + + TEMPLATE(T, sparse_mat_inv) (Ai, A, ctx); + TEMPLATE(T, sparse_mat_mul_mat) (dAiA, Ai, dA, ctx); + TEMPLATE(T, mat_rref) (dA, ctx); + if (!TEMPLATE(T, mat_equal) (dAiA, dA, ctx)) + { + flint_printf("FAIL!\n"); + flint_printf("A^-1 x A = "); + TEMPLATE(T, mat_print_pretty) (dAiA, ctx); + flint_printf("rref(A) = "); + TEMPLATE(T, mat_print_pretty) (dA, ctx); + abort(); + } + + TEMPLATE(T, sparse_mat_clear) (Ai, ctx); + TEMPLATE(T, mat_clear) (dA, ctx); + TEMPLATE(T, mat_clear) (dAiA, ctx); + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-lu.c b/fq_sparse_mat_templates/test/t-lu.c new file mode 100644 index 0000000000..a00a78aed5 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-lu.c @@ -0,0 +1,134 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c, i, j, rk, *P, *Q; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, t) *val; + TEMPLATE(T, sparse_mat_t) A, LU, L, U; + TEMPLATE(T, mat_t) dL, dU, dLU; + FLINT_TEST_INIT(state); + + flint_printf("decomposing PAQ = LU...."); + fflush(stdout); + + for (rep = 0; rep < 200; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + if (rep % 20 == 0) {flint_printf("."); fflush(stdout);} + r = n_randint(state, 100); + c = n_randint(state, 100); + + P = flint_malloc(r*sizeof(*P)); + Q = flint_malloc(c*sizeof(*P)); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (LU, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (L, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (U, r, c, ctx); + TEMPLATE(T, sparse_mat_randtest) (A, state, 1, c, ctx); + rk = TEMPLATE(T, sparse_mat_lu) (P, Q, L, U, A, ctx); + TEMPLATE(T, mat_init) (dL, r, rk, ctx); + TEMPLATE(T, mat_init) (dU, rk, c, ctx); + TEMPLATE(T, mat_init) (dLU, r, c, ctx); + + /* Check that L is lower triangular (with ones on diagonal up to rank) */ + for (i = 0; i < r; ++i) + { + val = TEMPLATE(T, sparse_vec_at) (&L->rows[i], i, ctx); + if (i < rk && (val == NULL || !TEMPLATE(T, is_one) (*val, ctx))) + { + flint_printf("FAIL: L does not have unit diagonal up to the rank\n"); + } + for (j = 0; j < L->rows[i].nnz; ++j) + { + TEMPLATE(T, sparse_entry_struct) *e = &L->rows[i].entries[j]; + if (e->ind > i) + { + flint_printf("FAIL: L not lower triangular\n"); + abort(); + } + if (e->ind >= rk) + { + flint_printf("FAIL: L not trivial past the rank\n"); + /*TEMPLATE(T, sparse_mat_print_pretty) (L, ctx);*/ + abort(); + } + } + } + /* Check that U is upper triangular (with nonzero diagonal up to rank) */ + for (i = 0; i < r; ++i) + { + val = TEMPLATE(T, sparse_vec_at) (&U->rows[i], i, ctx); + if (i < rk && (val == NULL || TEMPLATE(T, is_zero) (*val, ctx))) + { + flint_printf("FAIL: U does not have nonzero diagonal\n"); + abort(); + } + if (i >= rk && U->rows[i].nnz != UWORD(0)) + { + flint_printf("FAIL: U not trivial past the rank\n"); + abort(); + } + for (j = 0; j < U->rows[i].nnz; ++j) + { + TEMPLATE(T, sparse_entry_struct) *e = &U->rows[i].entries[j]; + if (e->ind < i) + { + flint_printf("FAIL: U not upper triangular\n"); + abort(); + } + } + } + TEMPLATE(T, sparse_mat_to_dense) (dL, L, ctx); + TEMPLATE(T, sparse_mat_to_dense) (dU, U, ctx); + TEMPLATE(T, mat_mul) (dLU, dL, dU, ctx); + TEMPLATE(T, sparse_mat_from_dense) (LU, dLU, ctx); + TEMPLATE(T, sparse_mat_permute_rows) (A, P, ctx); + TEMPLATE(T, sparse_mat_permute_cols) (A, Q, ctx); + if (!TEMPLATE(T, sparse_mat_equal) (A, LU, ctx)) + { + flint_printf("FAIL: PAQ != LU\n"); + flint_printf("PAQ="); + TEMPLATE(T, sparse_mat_print_pretty) (A, ctx); + flint_printf("LU="); + TEMPLATE(T, sparse_mat_print_pretty) (LU, ctx); + abort(); + } + + flint_free(P); + flint_free(Q); + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (U, ctx); + TEMPLATE(T, sparse_mat_clear) (L, ctx); + TEMPLATE(T, sparse_mat_clear) (LU, ctx); + TEMPLATE(T, mat_clear) (dL, ctx); + TEMPLATE(T, mat_clear) (dU, ctx); + TEMPLATE(T, mat_clear) (dLU, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-mul.c b/fq_sparse_mat_templates/test/t-mul.c new file mode 100644 index 0000000000..46734e6fe2 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-mul.c @@ -0,0 +1,89 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c, k; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A; + TEMPLATE(T, struct) *x, *y, *y2; + TEMPLATE(T, mat_t) B, X, Y, Y2; + FLINT_TEST_INIT(state); + + + flint_printf("multiplication by vec/mat...."); + fflush(stdout); + + for (rep = 0; rep < 10; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + r = n_randint(state, 200); + c = n_randint(state, 200); + k = n_randint(state, 200); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, mat_init) (B, r, c, ctx); + TEMPLATE(T, mat_init) (X, c, k, ctx); + TEMPLATE(T, mat_init) (Y, r, k, ctx); + TEMPLATE(T, mat_init) (Y2, r, k, ctx); + x = _TEMPLATE(T, vec_init) (c, ctx); + y = _TEMPLATE(T, vec_init) (r, ctx); + y2 = _TEMPLATE(T, vec_init) (r, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_to_dense) (B, A, ctx); + _TEMPLATE(T, vec_randtest) (x, state, c, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (y, A, x, ctx); + TEMPLATE(T, mat_mul_vec) (y2, B, x, ctx); + + if (!_TEMPLATE(T, vec_equal) (y, y2, A->r, ctx)) + { + flint_printf("FAIL: y != y2\n"); + abort(); + } + + TEMPLATE(T, mat_randtest) (X, state, ctx); + TEMPLATE(T, sparse_mat_mul_mat) (Y, A, X, ctx); + TEMPLATE(T, mat_mul) (Y2, B, X, ctx); + + if (!TEMPLATE(T, mat_equal) (Y, Y2, ctx)) + { + flint_printf("Fail: Y != Y2\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, mat_clear) (B, ctx); + _TEMPLATE(T, vec_clear) (x, c, ctx); + _TEMPLATE(T, vec_clear) (y, r, ctx); + _TEMPLATE(T, vec_clear) (y2, r, ctx); + TEMPLATE(T, mat_clear) (X, ctx); + TEMPLATE(T, mat_clear) (Y, ctx); + TEMPLATE(T, mat_clear) (Y2, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-neg.c b/fq_sparse_mat_templates/test/t-neg.c new file mode 100644 index 0000000000..30e6e7679b --- /dev/null +++ b/fq_sparse_mat_templates/test/t-neg.c @@ -0,0 +1,78 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, B, C, D; + FLINT_TEST_INIT(state); + + flint_printf("neg...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + r = n_randint(state, 200); + c = n_randint(state, 200); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (B, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (C, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (D, r, c, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_randtest) (B, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_randtest) (C, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_randtest) (D, state, 0, c, ctx); + + TEMPLATE(T, sparse_mat_sub) (C, A, B, ctx); + TEMPLATE(T, sparse_mat_neg) (B, B, ctx); + TEMPLATE(T, sparse_mat_add) (D, A, B, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (C, D, ctx)) + { + flint_printf("FAIL\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_neg) (C, B, ctx); + TEMPLATE(T, sparse_mat_neg) (B, B, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (C, B, ctx)) + { + flint_printf("FAIL\n"); + abort(); + } + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (B, ctx); + TEMPLATE(T, sparse_mat_clear) (C, ctx); + TEMPLATE(T, sparse_mat_clear) (D, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-nullspace.c b/fq_sparse_mat_templates/test/t-nullspace.c new file mode 100644 index 0000000000..f73dbc8eea --- /dev/null +++ b/fq_sparse_mat_templates/test/t-nullspace.c @@ -0,0 +1,96 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +/* #include */ +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, nreps = 50, r, c, i; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A; + TEMPLATE(T, mat_t) X, AX; + slong rk[6]; + slong discrep[6] = {0, 0, 0, 0}; + /* double elapsed[6] = {0, 0, 0, 0}; */ + char *names[6] = {"rref", "lu", "Lanczos", "block Lanczos", "Wiedemann", "block Wiedemann"}; + /* struct timeval start, end; */ + FLINT_TEST_INIT(state); + + flint_printf("finding nullspace of A...."); + fflush(stdout); + + for (rep = 0; rep < nreps; ++rep) + { + if (rep % 5==0) {flint_printf("."); fflush(stdout);} + TEMPLATE(T, ctx_randtest) (ctx, state); + r = c = 50 + n_randint(state, 50); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_randtest) (A, state, c/20, c/10, ctx); + for (i = 0; i < 6; ++i) + { + /* gettimeofday(&start, NULL); */ + switch (i) + { + case 0: rk[0] = TEMPLATE(T, sparse_mat_nullspace_rref) (X, A, ctx); break; + case 1: rk[1] = TEMPLATE(T, sparse_mat_nullspace_lu) (X, A, ctx); break; + case 2: rk[2] = TEMPLATE(T, sparse_mat_nullspace_lanczos) (X, A, state, 5, ctx); break; + case 3: rk[3] = TEMPLATE(T, sparse_mat_nullspace_block_lanczos) (X, A, 8, state, 2, ctx); break; + case 4: rk[4] = TEMPLATE(T, sparse_mat_nullspace_wiedemann) (X, A, state, 5, ctx); break; + case 5: rk[5] = TEMPLATE(T, sparse_mat_nullspace_block_wiedemann) (X, A, 8, state, 2, ctx); break; + } + /*if (i == 0 && rk[0] == UWORD(0) ) { TEMPLATE(T, mat_clear) (X, ctx); break;} else ++rep;*/ + /* gettimeofday(&end, NULL); + elapsed[i] += (end.tv_sec - start.tv_sec) + .000001*(end.tv_usec-start.tv_usec); */ + if (rk[i]!=0) + { + TEMPLATE(T, mat_init) (AX, A->r, X->c, ctx); + TEMPLATE(T, sparse_mat_mul_mat) (AX, A, X, ctx); + if (!TEMPLATE(T, mat_is_zero) (AX, ctx)) + { + flint_printf("FAIL: %d!\n", i); + if (i != 0) + flint_printf("Nullity should be %wd\n", rk[0]); + TEMPLATE(T, sparse_mat_print_pretty) (A, ctx); + TEMPLATE(T, mat_print_pretty) (X, ctx); + abort(); + } + TEMPLATE(T, mat_clear) (AX, ctx); + } + if (rk[i] != rk[0]) discrep[i] += 1; + TEMPLATE(T, mat_clear) (X, ctx); + } + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + for (i = 0; i < 6; ++i) + { + flint_printf("Finding nullspace with %s\n", names[i]); + /* flint_printf("\tAverage time: %lf\n", elapsed[i]/nreps); */ + if (discrep[i] > 0) + flint_printf("\tFailed to find full nullspace in %wd/%wd trials\n", + discrep[i], nreps); + } + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-rref.c b/fq_sparse_mat_templates/test/t-rref.c new file mode 100644 index 0000000000..2debca9ba0 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-rref.c @@ -0,0 +1,65 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, B; + TEMPLATE(T, mat_t) dA; + FLINT_TEST_INIT(state); + + flint_printf("converting A to reduced row echelon form...."); + fflush(stdout); + + for (rep = 0; rep < 200; rep++) + { + if (rep % 20 == 0) {flint_printf("."); fflush(stdout);} + TEMPLATE(T, ctx_randtest) (ctx, state); + r = n_randint(state, 100); + c = n_randint(state, 100); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (B, r, c, ctx); + TEMPLATE(T, mat_init) (dA, r, c, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_to_dense) (dA, A, ctx); + TEMPLATE(T, sparse_mat_rref) (A, ctx); + TEMPLATE(T, mat_rref) (dA, ctx); + TEMPLATE(T, sparse_mat_from_dense) (B, dA, ctx); + if (!TEMPLATE(T, sparse_mat_equal) (A, B, ctx)) + { + flint_printf("FAIL!\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (B, ctx); + TEMPLATE(T, mat_clear) (dA, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-scalar_mul.c b/fq_sparse_mat_templates/test/t-scalar_mul.c new file mode 100644 index 0000000000..8708840ddb --- /dev/null +++ b/fq_sparse_mat_templates/test/t-scalar_mul.c @@ -0,0 +1,87 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + TEMPLATE(T, t) a, cc; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, B, C, D; + FLINT_TEST_INIT(state); + + flint_printf("scalar_mul...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + TEMPLATE(T, init) (a, ctx); + TEMPLATE(T, init) (cc, ctx); + r = n_randint(state, 200); + c = n_randint(state, 200); + TEMPLATE(T, randtest) (cc, state, ctx); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (B, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (C, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (D, r, c, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c, ctx); + + TEMPLATE(T, TEMPLATE(sparse_mat_scalar_mul, T)) (B, A, a, ctx); + TEMPLATE(T, one) (cc, ctx); + TEMPLATE(T, sub) (cc, a, cc, ctx); + TEMPLATE(T, TEMPLATE(sparse_mat_scalar_mul, T)) (C, A, cc, ctx); + + /* c*A - (c-1)*A == A */ + TEMPLATE(T, sparse_mat_sub) (D, B, C, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (A, D, ctx)) + { + flint_printf("FAIL\n"); + abort(); + } + + /* Aliasing */ + TEMPLATE(T, TEMPLATE(sparse_mat_scalar_mul, T)) (C, A, a, ctx); + TEMPLATE(T, TEMPLATE(sparse_mat_scalar_mul, T)) (A, A, a, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (A, C, ctx)) + { + flint_printf("FAIL\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (B, ctx); + TEMPLATE(T, sparse_mat_clear) (C, ctx); + TEMPLATE(T, sparse_mat_clear) (D, ctx); + TEMPLATE(T, clear) (a, ctx); + TEMPLATE(T, clear) (cc, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-solve.c b/fq_sparse_mat_templates/test/t-solve.c new file mode 100644 index 0000000000..92c37dffa3 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-solve.c @@ -0,0 +1,130 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" +/* #include */ + +int +main(void) +{ + int iter, ret; + slong rep, nreps = 100, r, c, i; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, At; + TEMPLATE(T, struct) *x, *x2, *b, *Atb, *Ax, *AtAx; + slong niters[6] = {0, 0, 0, 0, 0, 0}; + slong psol[6] = {0, 0, 0, 0, 0, 0}; + slong nosol[6] = {0, 0, 0, 0, 0, 0}; + /* double elapsed[6] = {0, 0, 0, 0, 0}; */ + char *names[6] = {"rref", "lu", "Lanczos", "block Lanczos", "Wiedemann", "block Wiedemann"}; + /* struct timeval start, end; */ + FLINT_TEST_INIT(state); + + flint_printf("solving Ax = b...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + if (rep % 5==0) {flint_printf("."); fflush(stdout);} + TEMPLATE(T, ctx_randtest) (ctx, state); + + c = r = 50 + n_randint(state, 10); + + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + x = _TEMPLATE(T, vec_init) (c, ctx); + x2 = _TEMPLATE(T, vec_init) (c, ctx); + b = _TEMPLATE(T, vec_init) (r, ctx); + Ax = _TEMPLATE(T, vec_init) (r, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, c/10, c/5, ctx); + _TEMPLATE(T, vec_randtest) (x, state, c, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (b, A, x, ctx); + + for (i = 0; i < 6; ++i) + { + iter = 0; + /* gettimeofday(&start, NULL); */ + switch (i) + { + case 0: ret = TEMPLATE(T, sparse_mat_solve_rref) (x2, A, b, ctx); break; + case 1: ret = TEMPLATE(T, sparse_mat_solve_lu) (x2, A, b, ctx); break; + case 2: do ret = TEMPLATE(T, sparse_mat_solve_lanczos) (x2, A, b, state, ctx); while (ret == 0 && ++iter < 3); break; + case 3: do ret = TEMPLATE(T, sparse_mat_solve_block_lanczos) (x2, A, b, 8, state, ctx); while (ret == 0 && ++iter < 3); break; + case 4: ret = TEMPLATE(T, sparse_mat_solve_wiedemann) (x2, A, b, ctx); break; + case 5: do ret = TEMPLATE(T, sparse_mat_solve_block_wiedemann) (x2, A, b, 8, state, ctx); while (ret == 0 && ++iter < 3); break; + } + /* gettimeofday(&end, NULL); + elapsed[i] += (end.tv_sec - start.tv_sec) + .000001*(end.tv_usec-start.tv_usec); */ + if (ret == 0) nosol[i] += 1; + else + { + niters[i] += iter; + TEMPLATE(T, sparse_mat_mul_vec) (Ax, A, x2, ctx); + if (!_TEMPLATE(T, vec_equal) (b, Ax, A->r, ctx)) + { + if (i == 2 || i == 3) + { + TEMPLATE(T, sparse_mat_init) (At, c, r, ctx); + AtAx = _TEMPLATE(T, vec_init) (c, ctx); + Atb = _TEMPLATE(T, vec_init) (c, ctx); + TEMPLATE(T, sparse_mat_transpose) (At, A, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (AtAx, At, Ax, ctx); + TEMPLATE(T, sparse_mat_mul_vec) (Atb, At, b, ctx); + if (!_TEMPLATE(T, vec_equal) (AtAx, Atb, A->c, ctx)) + { + flint_printf("FAIL on %s: AtAx != Atb\n", names[i]); + abort(); + } + else psol[i] += 1; + _TEMPLATE(T, vec_clear) (AtAx, c, ctx); + _TEMPLATE(T, vec_clear) (Atb, c, ctx); + TEMPLATE(T, sparse_mat_clear) (At, ctx); + } + else + { + flint_printf("FAIL on %s: Ax != b\n", names[i]); + abort(); + } + } + } + } + _TEMPLATE(T, vec_clear) (x, c, ctx); + _TEMPLATE(T, vec_clear) (x2, c, ctx); + _TEMPLATE(T, vec_clear) (b, r, ctx); + _TEMPLATE(T, vec_clear) (Ax, r, ctx); + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + for (i = 0; i < 6; ++i) + { + flint_printf("Solved with %s\n", names[i]); + /* flint_printf("\tAverage time: %lf\n", elapsed[i]/nreps); */ + if (nosol[i]) + flint_printf("\tFound no solution for %wd/%wd examples\n", nosol[i], nreps); + if (psol[i]) + flint_printf("\tFound pseudo-solution for %wd/%wd examples\n", psol[i], nreps); + if (niters[i]) + flint_printf("\tRequired %f extra iters per solution (on average).\n", (double)niters[i]/nreps); + } + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/test/t-transpose.c b/fq_sparse_mat_templates/test/t-transpose.c new file mode 100644 index 0000000000..5531e548c2 --- /dev/null +++ b/fq_sparse_mat_templates/test/t-transpose.c @@ -0,0 +1,68 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c, nreps = 1000; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_mat_t) A, B, C; + FLINT_TEST_INIT(state); + + + flint_printf("transpose...."); + fflush(stdout); + + /* Rectangular transpose, same modulus */ + for (rep = 0; rep < nreps; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + r = n_randint(state, 20); + c = n_randint(state, 20); + TEMPLATE(T, sparse_mat_init) (A, r, c, ctx); + TEMPLATE(T, sparse_mat_init) (B, c, r, ctx); + TEMPLATE(T, sparse_mat_init) (C, r, c, ctx); + + TEMPLATE(T, sparse_mat_randtest) (A, state, 0, c, ctx); + TEMPLATE(T, sparse_mat_randtest) (B, state, 0, r, ctx); + TEMPLATE(T, sparse_mat_randtest) (C, state, 0, c, ctx); + + TEMPLATE(T, sparse_mat_transpose) (B, A, ctx); + TEMPLATE(T, sparse_mat_transpose) (C, B, ctx); + + if (!TEMPLATE(T, sparse_mat_equal) (C, A, ctx)) + { + flint_printf("FAIL: C != A\n"); + abort(); + } + + TEMPLATE(T, sparse_mat_clear) (A, ctx); + TEMPLATE(T, sparse_mat_clear) (B, ctx); + TEMPLATE(T, sparse_mat_clear) (C, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif diff --git a/fq_sparse_mat_templates/transpose.c b/fq_sparse_mat_templates/transpose.c new file mode 100644 index 0000000000..d07ef9a043 --- /dev/null +++ b/fq_sparse_mat_templates/transpose.c @@ -0,0 +1,63 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +void +TEMPLATE(T, sparse_mat_transpose) (TEMPLATE(T, sparse_mat_t) B, const TEMPLATE(T, sparse_mat_t) A, const TEMPLATE(T, ctx_t) ctx) +{ + slong r, c, i, j, *nnz; + TEMPLATE(T, sparse_entry_struct) *Ae, *Be; + FLINT_ASSERT(B->r == A->c && A->r == B->c); + nnz = flint_calloc(A->c, sizeof(*nnz)); + /* Get number of nnzs in each column of A (thus each row of B) */ + for (c = 0; c < A->c; ++c) + { + B->rows[c].nnz = 0; + } + for (r = 0; r < A->r; ++r) + { + for (i = 0; i < A->rows[r].nnz; ++i) + { + c = A->rows[r].entries[i].ind - A->c_off; + if (c >= A->c) break; + nnz[c]++; + } + } + /* Allocate space for nnz and reset counters */ + for (c = 0; c < A->c; ++c) + { + _TEMPLATE(T, sparse_vec_resize) (&B->rows[c], nnz[c], ctx); + nnz[c] = 0; + } + /* Put entries into transposed matrix */ + for (r = 0; r < A->r; ++r) + { + for (i = 0; i < A->rows[r].nnz; ++i) + { + Ae = &A->rows[r].entries[i]; + c = Ae->ind - A->c_off; + if (c >= A->c) break; + j = nnz[c]++; + Be = &B->rows[c].entries[j]; + Be->ind = r; + TEMPLATE(T, set) (Be->val, Ae->val, ctx); + } + } + flint_free(nnz); + B->c_off = 0; +} + +#endif diff --git a/fq_sparse_mat_templates/window_init.c b/fq_sparse_mat_templates/window_init.c new file mode 100644 index 0000000000..38df9f863c --- /dev/null +++ b/fq_sparse_mat_templates/window_init.c @@ -0,0 +1,31 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "templates.h" + +void TEMPLATE(T, sparse_mat_window_init)(TEMPLATE(T, sparse_mat_t) window, const TEMPLATE(T, sparse_mat_t) mat, slong r1, slong c1, slong r2, slong c2, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + r2 = FLINT_MIN(r2, mat->r), r1 = FLINT_MIN(r1, r2); + c2 = FLINT_MIN(c2, mat->c), c1 = FLINT_MIN(c1, c2); + window->r = r2-r1; + window->c = c2-c1; + window->c_off = c1; + window->rows = flint_malloc(window->r*sizeof(*window->rows)); + for (i = 0; i < window->r; ++i) + TEMPLATE(T, sparse_vec_window_init) (&window->rows[i], &mat->rows[i+r1], c1, c2, ctx); +} + +#endif diff --git a/fq_sparse_vec.h b/fq_sparse_vec.h new file mode 100644 index 0000000000..b1dd23f8fe --- /dev/null +++ b/fq_sparse_vec.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2013 Mike Hansen + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef FQ_SPARSE_VEC_H +#define FQ_SPARSE_VEC_H + +#ifdef FQ_SPARSE_VEC_INLINES_C +#define FQ_SPARSE_VEC_TEMPLATES_INLINE FLINT_DLL +#define FQ_SPARSE_VEC_INLINE FLINT_DLL +#else +#define FQ_SPARSE_VEC_TEMPLATES_INLINE static __inline__ +#define FQ_SPARSE_VEC_INLINE static __inline__ +#endif + + +#include "fq.h" +#include "fq_vec.h" + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates.h" +#undef CAP_T +#undef T + +#endif diff --git a/fq_sparse_vec/add.c b/fq_sparse_vec/add.c new file mode 100644 index 0000000000..c847a3d8df --- /dev/null +++ b/fq_sparse_vec/add.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/add.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/print_pretty.c b/fq_sparse_vec/print_pretty.c new file mode 100644 index 0000000000..82c54613ee --- /dev/null +++ b/fq_sparse_vec/print_pretty.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/print_pretty.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/randtest.c b/fq_sparse_vec/randtest.c new file mode 100644 index 0000000000..5175ad52fb --- /dev/null +++ b/fq_sparse_vec/randtest.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/randtest.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/scalar_addmul.c b/fq_sparse_vec/scalar_addmul.c new file mode 100644 index 0000000000..443abc13b4 --- /dev/null +++ b/fq_sparse_vec/scalar_addmul.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/scalar_addmul.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/scalar_submul.c b/fq_sparse_vec/scalar_submul.c new file mode 100644 index 0000000000..18e0dcd76b --- /dev/null +++ b/fq_sparse_vec/scalar_submul.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/scalar_submul.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/sub.c b/fq_sparse_vec/sub.c new file mode 100644 index 0000000000..b29094bbd8 --- /dev/null +++ b/fq_sparse_vec/sub.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/sub.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/test/t-add.c b/fq_sparse_vec/test/t-add.c new file mode 100644 index 0000000000..a88651ab39 --- /dev/null +++ b/fq_sparse_vec/test/t-add.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/test/t-add.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/test/t-concat.c b/fq_sparse_vec/test/t-concat.c new file mode 100644 index 0000000000..92b2860a58 --- /dev/null +++ b/fq_sparse_vec/test/t-concat.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/test/t-concat.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/test/t-construct.c b/fq_sparse_vec/test/t-construct.c new file mode 100644 index 0000000000..6d6b888664 --- /dev/null +++ b/fq_sparse_vec/test/t-construct.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/test/t-construct.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/test/t-dense.c b/fq_sparse_vec/test/t-dense.c new file mode 100644 index 0000000000..9aea544724 --- /dev/null +++ b/fq_sparse_vec/test/t-dense.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/test/t-dense.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/test/t-dot.c b/fq_sparse_vec/test/t-dot.c new file mode 100644 index 0000000000..90b92211fb --- /dev/null +++ b/fq_sparse_vec/test/t-dot.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/test/t-dot.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/test/t-init_clear.c b/fq_sparse_vec/test/t-init_clear.c new file mode 100644 index 0000000000..7b8da28369 --- /dev/null +++ b/fq_sparse_vec/test/t-init_clear.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/test/t-init_clear.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/test/t-neg.c b/fq_sparse_vec/test/t-neg.c new file mode 100644 index 0000000000..8b2c6cfaae --- /dev/null +++ b/fq_sparse_vec/test/t-neg.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/test/t-neg.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec/test/t-scalar_mul.c b/fq_sparse_vec/test/t-scalar_mul.c new file mode 100644 index 0000000000..d62fac011d --- /dev/null +++ b/fq_sparse_vec/test/t-scalar_mul.c @@ -0,0 +1,24 @@ +/* + wopyright (w) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq +#define CAP_T FQ +#include "fq_sparse_vec_templates/test/t-scalar_mul.c" +#undef CAP_T +#undef T diff --git a/fq_sparse_vec_templates.h b/fq_sparse_vec_templates.h new file mode 100644 index 0000000000..5488870712 --- /dev/null +++ b/fq_sparse_vec_templates.h @@ -0,0 +1,437 @@ +/* + Copyright (C) 2010 William Hart + Copyright (C) 2010,2011 Fredrik Johansson + Copyright (C) 2014 Ashish Kedia + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include +#include "flint.h" +#include "longlong.h" +#include "templates.h" +#include "ulong_extras.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct { + slong ind; + TEMPLATE(T, t) val; +} TEMPLATE(T, sparse_entry_struct); + +typedef TEMPLATE(T, sparse_entry_struct) TEMPLATE(T, sparse_entry_t)[1]; + +typedef struct { + TEMPLATE(T, sparse_entry_struct) *entries; + slong nnz; +} TEMPLATE(T, sparse_vec_struct); + +typedef TEMPLATE(T, sparse_vec_struct) TEMPLATE(T, sparse_vec_t)[1]; + +FQ_SPARSE_VEC_TEMPLATES_INLINE +int TEMPLATE(T, sparse_entry_cmp)(const void *va, const void *vb) +{ + const TEMPLATE(T, sparse_entry_struct) *a = va; + const TEMPLATE(T, sparse_entry_struct) *b = vb; + if (a->ind < b->ind) return -1; + if (b->ind < a->ind) return 1; + return 0; +} + +/* Memory management */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_init)(TEMPLATE(T, sparse_vec_t) vec, + const TEMPLATE(T, ctx_t) ctx) +{ + memset(vec, 0, sizeof(*vec)); +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_clear)(TEMPLATE(T, sparse_vec_t) vec, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < vec->nnz; ++i) + TEMPLATE(T, clear) (vec->entries[i].val, ctx); + flint_free(vec->entries); + memset(vec, 0, sizeof(*vec)); +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void _TEMPLATE(T, sparse_vec_resize)(TEMPLATE(T, sparse_vec_t) vec, slong nnz, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + FLINT_ASSERT(nnz >= 0); + if (nnz == 0) TEMPLATE(T, sparse_vec_clear) (vec, ctx); + else if (nnz != vec->nnz) + { + for (i = nnz; i < vec->nnz; ++i) + TEMPLATE(T, clear) (vec->entries[i].val, ctx); + vec->entries = flint_realloc(vec->entries, nnz*sizeof(*vec->entries)); + for (i = vec->nnz; i < nnz; ++i) + TEMPLATE(T, init) (vec->entries[i].val, ctx); + } + vec->nnz = nnz; +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_resize)(TEMPLATE(T, sparse_vec_t) vec, slong cols, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + FLINT_ASSERT(cols >= 0); + if (vec->nnz == 0) return; + for (i = 0; i < vec->nnz; ++i) { + if (vec->entries[i].ind >= cols) + { + break; + } + } + _TEMPLATE(T, sparse_vec_resize)(vec, i, ctx); +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_swap)(TEMPLATE(T, sparse_vec_t) vec1, TEMPLATE(T, sparse_vec_t) vec2, + const TEMPLATE(T, ctx_t) ctx) +{ + TEMPLATE(T, sparse_vec_t) tmp; + *tmp = *vec1, *vec1 = *vec2, *vec2 = *tmp; +} + +/* Vector indexing */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +TEMPLATE(T, t) *TEMPLATE(T, sparse_vec_at)(TEMPLATE(T, sparse_vec_t) vec, slong i, + const TEMPLATE(T, ctx_t) ctx) +{ + slong j; + for (j = 0; j < vec->nnz; ++j) + if (vec->entries[j].ind==i) + return &vec->entries[j].val; + return NULL; +} + +/* One-time instantiation */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_zero)(TEMPLATE(T, sparse_vec_t) vec, + const TEMPLATE(T, ctx_t) ctx) +{ + TEMPLATE(T, sparse_vec_clear)(vec, ctx); +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_one)(TEMPLATE(T, sparse_vec_t) vec, slong ind, + const TEMPLATE(T, ctx_t) ctx) +{ + _TEMPLATE(T, sparse_vec_resize) (vec, 1, ctx); + vec->entries[0].ind = ind; + TEMPLATE(T, one) (vec->entries[0].val, ctx); +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_set)(TEMPLATE(T, sparse_vec_t) dst, const TEMPLATE(T, sparse_vec_t) src, slong ioff, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + if (dst == src) return; + _TEMPLATE(T, sparse_vec_resize) (dst, src->nnz, ctx); + for (i = 0; i < dst->nnz; ++i) + { + dst->entries[i].ind = src->entries[i].ind - ioff; + TEMPLATE(T, set) (dst->entries[i].val, src->entries[i].val, ctx); + } +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_set_entry)(TEMPLATE(T, sparse_vec_t) v, slong ind, const TEMPLATE(T, t) val, + const TEMPLATE(T, ctx_t) ctx) +{ + TEMPLATE(T, t) *oval; + if (TEMPLATE(T, is_zero) (val, ctx)) return; + oval = TEMPLATE(T, sparse_vec_at) (v, ind, ctx); + if (oval == NULL) + { + _TEMPLATE(T, sparse_vec_resize) (v, v->nnz + 1, ctx); + TEMPLATE(T, set) (v->entries[v->nnz-1].val, val, ctx); + v->entries[v->nnz-1].ind = ind; + if (v->nnz >= 2 && ind < v->entries[v->nnz-2].ind) + qsort(v->entries, v->nnz, sizeof(*v->entries), TEMPLATE(T, sparse_entry_cmp)); + } + else TEMPLATE(T, set) (*oval, val, ctx); +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_from_entries)(TEMPLATE(T, sparse_vec_t) vec, slong * inds, TEMPLATE(T, struct) * vals, slong nnz, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + _TEMPLATE(T, sparse_vec_resize) (vec, nnz, ctx); + for (i = 0; i < nnz; ++i) + { + vec->entries[i].ind = inds[i]; + TEMPLATE(T, set) (vec->entries[i].val, &vals[i], ctx); + } +} + +/* Vector comparison */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +int TEMPLATE(T, sparse_vec_is_zero)(const TEMPLATE(T, sparse_vec_t) vec, + const TEMPLATE(T, ctx_t) ctx) +{ + return vec->nnz == 0; +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +int TEMPLATE(T, sparse_vec_equal)(const TEMPLATE(T, sparse_vec_t) vec1, const TEMPLATE(T, sparse_vec_t) vec2, slong ioff, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + if (vec1->nnz != vec2->nnz) return 0; + for (i = 0; i < vec1->nnz; ++i) + { + if ((vec1->entries[i].ind != vec2->entries[i].ind + ioff) || + !TEMPLATE(T, equal)(vec1->entries[i].val, vec2->entries[i].val, ctx)) return 0; + } + return 1; +} + +/* Convert from/to dense vector */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_from_dense)(TEMPLATE(T, sparse_vec_t) dst, TEMPLATE(T, struct) *src, slong len, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i, nnz = 0; + TEMPLATE(T, sparse_entry_struct) *e; + for (i = 0; i < len; ++i) + if (!TEMPLATE(T, is_zero) (&src[i], ctx)) ++nnz; + _TEMPLATE(T, sparse_vec_resize) (dst, nnz, ctx); + e = dst->entries; + for (i = 0; i < len; ++i) + if (!TEMPLATE(T, is_zero) (&src[i], ctx)) + e->ind = i, TEMPLATE(T, set) (e->val, &src[i], ctx), ++e; +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_to_dense)(TEMPLATE(T, struct) *dst, const TEMPLATE(T, sparse_vec_t) src, slong len, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + _TEMPLATE(T, vec_zero)(dst, len, ctx); + for (i = 0; i < src->nnz; ++i) TEMPLATE(T, set)(&dst[src->entries[i].ind], src->entries[i].val, ctx); +} + +/* Windows and concatenation */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_window_init)(TEMPLATE(T, sparse_vec_t) window, const TEMPLATE(T, sparse_vec_t) vec, slong i1, slong i2, + const TEMPLATE(T, ctx_t) ctx) +{ + slong start, end; + for (start = 0; start < vec->nnz && vec->entries[start].ind < i1; ++start); + for (end = vec->nnz; end > 0 && vec->entries[end-1].ind >= i2; --end); + window->entries = vec->entries + start; + window->nnz = end - start; +} + + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_window_clear)(TEMPLATE(T, sparse_vec_t) window, + const TEMPLATE(T, ctx_t) ctx) +{ + memset(window, 0, sizeof(*window)); +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_concat)(TEMPLATE(T, sparse_vec_t) res, const TEMPLATE(T, sparse_vec_t) vec1, const TEMPLATE(T, sparse_vec_t) vec2, slong len1, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i, nnz = vec1->nnz+vec2->nnz; + _TEMPLATE(T, sparse_vec_resize) (res, nnz, ctx); + for (i = 0; i < nnz; ++i) + { + TEMPLATE(T, sparse_entry_struct) *e = (i < vec1->nnz) ? &vec1->entries[i] : &vec2->entries[i-vec1->nnz]; + res->entries[i].ind = e->ind + ((i < vec1->nnz) ? 0 : len1); + TEMPLATE(T, set) (res->entries[i].val, e->val, ctx); + } +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_split)(TEMPLATE(T, sparse_vec_t) res1, TEMPLATE(T, sparse_vec_t) res2, const TEMPLATE(T, sparse_vec_t) vec, slong ind, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i, nnz1; + TEMPLATE(T, sparse_entry_struct) *e1, *e2, *e; + for (nnz1 = 0; nnz1 < vec->nnz; ++nnz1) if (vec->entries[nnz1].ind >= ind) break; + + _TEMPLATE(T, sparse_vec_resize) (res1, nnz1, ctx); + _TEMPLATE(T, sparse_vec_resize) (res2, vec->nnz - nnz1, ctx); + e1 = res1->entries, e2 = res2->entries; + for (i = 0; i < vec->nnz; ++i) + { + e = (i < nnz1) ? e1++ : e2++; + e->ind = vec->entries[i].ind - ((i < nnz1) ? 0 : ind); + TEMPLATE(T, set) (e->val, vec->entries[i].val, ctx); + } +} + +/* Vector permutation */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_permute_inds)(TEMPLATE(T, sparse_vec_t) vec, slong *P, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + for (i = 0; i < vec->nnz; ++i) vec->entries[i].ind = P[vec->entries[i].ind]; + qsort(vec->entries, vec->nnz, sizeof(*vec->entries), TEMPLATE(T, sparse_entry_cmp)); +} + +/* Random vector generation */ +FLINT_DLL +void TEMPLATE(T, sparse_vec_randtest)(TEMPLATE(T, sparse_vec_t) vec, flint_rand_t state, slong nnz, slong len, + const TEMPLATE(T, ctx_t) ctx); + +/* Vector display */ +FLINT_DLL +void TEMPLATE(T, sparse_vec_print_pretty)(const TEMPLATE(T, sparse_vec_t) vec, slong ioff, slong maxi, + const TEMPLATE(T, ctx_t) ctx); + +/* Vector operations */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_neg)(TEMPLATE(T, sparse_vec_t) v, const TEMPLATE(T, sparse_vec_t) u, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + TEMPLATE(T, sparse_vec_set)(v, u, 0, ctx); + for (i = 0; i < v->nnz; ++i) TEMPLATE(T, neg) (v->entries[i].val, v->entries[i].val, ctx); +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T))(TEMPLATE(T, sparse_vec_t) v, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + if (TEMPLATE(T, is_zero) (c, ctx)) {TEMPLATE(T, sparse_vec_zero)(v, ctx); return;} + TEMPLATE(T, sparse_vec_set)(v, u, 0, ctx); + if (!TEMPLATE(T, is_one)(c, ctx)) + for (i = 0; i < v->nnz; ++i) TEMPLATE(T, mul)(v->entries[i].val, v->entries[i].val, c, ctx); +} + +/* Utility macros used by binary vector operations */ +/* Compute total number of indices between two sparse vectors */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +slong _TEMPLATE(T, sparse_vec_union_nnz)(const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i, j, nnz = 0; + for (i = j = 0; i < u->nnz && j < v->nnz; ++nnz) + { + if (u->entries[i].ind == v->entries[j].ind) ++i, ++j; + else if (u->entries[i].ind < v->entries[j].ind) ++i; + else if (u->entries[i].ind > v->entries[j].ind) ++j; + } + nnz += u->nnz - i + v->nnz - j; + return nnz; +} + +/* Iterate through u and v in descending order, assigning sorted indices to w */ +/* Returns -1 if u and v are both exhausted, + 2 if we->ind = ue->ind == ve->ind + 1 if we->ind = ve->ind > ue->ind (or u exhausted), + 0 if we->ind = ue->ind > ve->ind (or v exhausted). */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +slong _TEMPLATE(T, sparse_vector_merge_descend) (TEMPLATE(T, sparse_entry_struct) **we, + TEMPLATE(T, sparse_entry_struct) **ue, + TEMPLATE(T, sparse_entry_struct) **ve, + const TEMPLATE(T, sparse_vec_t) u, + const TEMPLATE(T, sparse_vec_t) v) +{ + slong uind = (*ue==u->entries) ? -1 : (*ue-1)->ind; + slong vind = (*ve==v->entries) ? -1 : (*ve-1)->ind; + if (uind == -1 && vind == -1) return -1; + if (uind == vind) {--*ue, --*ve, --*we; (*we)->ind = uind; return 2;} + if (uind < vind) {--*ve, --*we; (*we)->ind = vind; return 1;} + --*ue, --*we; (*we)->ind = uind; return 0; +} + +/* Like resize, but removes entries from the front of the vector */ +FQ_SPARSE_VEC_TEMPLATES_INLINE +void _TEMPLATE(T, sparse_vector_shift_left) (TEMPLATE(T, sparse_vec_t) v, slong amt, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + if (amt == v->nnz) TEMPLATE(T, sparse_vec_clear) (v, ctx); + else if (amt > 0) + { + v->nnz -= amt; + for (i = 0; i < amt; ++i) TEMPLATE(T, clear) (v->entries[i].val, ctx); + memmove(v->entries, v->entries + amt, v->nnz*sizeof(*v->entries)); + v->entries = flint_realloc(v->entries, v->nnz*sizeof(*v->entries)); + } +} + +FLINT_DLL +void TEMPLATE(T, sparse_vec_add)(TEMPLATE(T, sparse_vec_t) w, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, + const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +void TEMPLATE(T, sparse_vec_sub)(TEMPLATE(T, sparse_vec_t) w, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, + const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +void TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T))(TEMPLATE(T, sparse_vec_t) w, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx); + +FLINT_DLL +void TEMPLATE(T, TEMPLATE(sparse_vec_scalar_submul, T))(TEMPLATE(T, sparse_vec_t) w, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx); + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_dot)(TEMPLATE(T, t) ret, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i, j; + TEMPLATE(T, t) tmp; + TEMPLATE(T, init) (tmp, ctx); + TEMPLATE(T, zero) (ret, ctx); + for (i = j = 0; i < u->nnz && j < v->nnz; ) + { + if (u->entries[i].ind == v->entries[j].ind) + { + TEMPLATE(T, mul) (tmp, u->entries[i].val, v->entries[j].val, ctx); + TEMPLATE(T, add) (ret, ret, tmp, ctx), ++i, ++j; + } + else if (u->entries[i].ind < v->entries[j].ind) ++i; + else if (u->entries[i].ind > v->entries[j].ind) ++j; + } + TEMPLATE(T, clear) (tmp, ctx); +} + +FQ_SPARSE_VEC_TEMPLATES_INLINE +void TEMPLATE(T, sparse_vec_dot_dense)(TEMPLATE(T, t) ret, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, struct) *v, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + TEMPLATE(T, t) tmp; + TEMPLATE(T, init) (tmp, ctx); + TEMPLATE(T, zero) (ret, ctx); + for (i = 0; i < u->nnz; ++i) + { + TEMPLATE(T, mul) (tmp, u->entries[i].val, &v[u->entries[i].ind], ctx); + TEMPLATE(T, add) (ret, ret, tmp, ctx); + } + TEMPLATE(T, clear) (tmp, ctx); +} + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/fq_sparse_vec_templates/add.c b/fq_sparse_vec_templates/add.c new file mode 100644 index 0000000000..9a611bd702 --- /dev/null +++ b/fq_sparse_vec_templates/add.c @@ -0,0 +1,41 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include +#include "templates.h" + +void TEMPLATE(T, sparse_vec_add)(TEMPLATE(T, sparse_vec_t) w, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, + const TEMPLATE(T, ctx_t) ctx) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + TEMPLATE(T, sparse_entry_struct) *ue, *ve, *we; + + if (vnnz == 0) {TEMPLATE(T, sparse_vec_set) (w, u, 0, ctx); return;} + if (unnz == 0) {TEMPLATE(T, sparse_vec_set) (w, v, 0, ctx); return;} + wnnz = _TEMPLATE(T, sparse_vec_union_nnz) (u, v, ctx); + _TEMPLATE(T, sparse_vec_resize) (w, wnnz, ctx); + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _TEMPLATE(T, sparse_vector_merge_descend) (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: TEMPLATE(T, set)(we->val, ue->val, ctx); break; + case 1: TEMPLATE(T, set)(we->val, ve->val, ctx); break; + default: TEMPLATE(T, add)(we->val, ue->val, ve->val, ctx); + if (TEMPLATE(T, is_zero) (we->val, ctx)) we++; + } + } + _TEMPLATE(T, sparse_vector_shift_left) (w, we - w->entries, ctx); +} +#endif + diff --git a/fq_sparse_vec_templates/print_pretty.c b/fq_sparse_vec_templates/print_pretty.c new file mode 100644 index 0000000000..213feff8dd --- /dev/null +++ b/fq_sparse_vec_templates/print_pretty.c @@ -0,0 +1,38 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#ifdef T + +#include "templates.h" + +void +TEMPLATE(T, sparse_vec_print_pretty)(const TEMPLATE(T, sparse_vec_t) vec, slong ioff, slong maxi, const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + char ind_fmt[FLINT_BITS + 5]; + + flint_sprintf(ind_fmt, "%%%dwd:", n_sizeinbase(maxi, 10)); + + flint_printf("["); + for (i = 0; i < vec->nnz; i++) + { + flint_printf(ind_fmt, vec->entries[i].ind - ioff); + TEMPLATE(T, print_pretty) (vec->entries[i].val, ctx); + if (i + 1 < vec->nnz) flint_printf(" "); + } + flint_printf("]\n"); +} + + +#endif + diff --git a/fq_sparse_vec_templates/randtest.c b/fq_sparse_vec_templates/randtest.c new file mode 100644 index 0000000000..368a3c2aa6 --- /dev/null +++ b/fq_sparse_vec_templates/randtest.c @@ -0,0 +1,36 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include "templates.h" + +void TEMPLATE(T, sparse_vec_randtest)(TEMPLATE(T, sparse_vec_t) vec, flint_rand_t state, slong nnz, slong len, const TEMPLATE(T, ctx_t) ctx) +{ + slong i, j; + nnz = FLINT_MIN(nnz, len); + _TEMPLATE(T, sparse_vec_resize) (vec, nnz, ctx); + for (i = 0; i < nnz; ++i) + { + vec->entries[i].ind = i; + do TEMPLATE(T, randtest) (vec->entries[i].val, state, ctx); + while (TEMPLATE(T, is_zero) (vec->entries[i].val, ctx)); + } + + /* Use resevoir sampling to randomize support */ + for (j = nnz; j < len; ++j) + if ((i = n_randint(state, j+1)) < nnz) vec->entries[i].ind = j; + qsort(vec->entries, nnz, sizeof(*vec->entries), TEMPLATE(T, sparse_entry_cmp)); +} + + +#endif + diff --git a/fq_sparse_vec_templates/scalar_addmul.c b/fq_sparse_vec_templates/scalar_addmul.c new file mode 100644 index 0000000000..c05bbb1e3f --- /dev/null +++ b/fq_sparse_vec_templates/scalar_addmul.c @@ -0,0 +1,53 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include +#include "templates.h" + +void TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T))(TEMPLATE(T, sparse_vec_t) w, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + TEMPLATE(T, sparse_entry_struct) *ue, *ve, *we; + TEMPLATE(T, t) tmp; + + /* Check for simpler operations first */ + if (vnnz == 0 || TEMPLATE(T, is_zero) (c, ctx)) {TEMPLATE(T, sparse_vec_set) (w, u, 0, ctx); return;} + if (TEMPLATE(T, is_one) (c, ctx)) {TEMPLATE(T, sparse_vec_add) (w, u, v, ctx); return;} + if (unnz == 0) {TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (w, v, c, ctx); return;} + TEMPLATE(T, init) (tmp, ctx); + TEMPLATE(T, neg) (tmp, c, ctx); + if (TEMPLATE(T, is_one) (tmp, ctx)) TEMPLATE(T, sparse_vec_sub) (w, u, v, ctx); + else /* Now just do standard addmul */ + { + wnnz = _TEMPLATE(T, sparse_vec_union_nnz) (u, v, ctx); + _TEMPLATE(T, sparse_vec_resize) (w, wnnz, ctx); + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _TEMPLATE(T, sparse_vector_merge_descend) (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: TEMPLATE(T, set)(we->val, ue->val, ctx); break; + case 1: TEMPLATE(T, mul)(we->val, ve->val, c, ctx); break; + default: TEMPLATE(T, mul) (tmp, ve->val, c, ctx); + TEMPLATE(T, add) (we->val, ue->val, tmp, ctx); + if (TEMPLATE(T, is_zero) (we->val, ctx)) we++; + } + } + _TEMPLATE(T, sparse_vector_shift_left) (w, we - w->entries, ctx); + } + + TEMPLATE(T, clear) (tmp, ctx); +} +#endif + diff --git a/fq_sparse_vec_templates/scalar_submul.c b/fq_sparse_vec_templates/scalar_submul.c new file mode 100644 index 0000000000..77b4bc89dc --- /dev/null +++ b/fq_sparse_vec_templates/scalar_submul.c @@ -0,0 +1,53 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include +#include "templates.h" + +void TEMPLATE(T, TEMPLATE(sparse_vec_scalar_submul, T))(TEMPLATE(T, sparse_vec_t) w, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, const TEMPLATE(T, t) c, + const TEMPLATE(T, ctx_t) ctx) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + TEMPLATE(T, sparse_entry_struct) *ue, *ve, *we; + TEMPLATE(T, t) tmp; + + /* Check for simpler operations first */ + if (vnnz == 0 || TEMPLATE(T, is_zero) (c, ctx)) {TEMPLATE(T, sparse_vec_set) (w, u, 0, ctx); return;} + if (TEMPLATE(T, is_one) (c, ctx)) {TEMPLATE(T, sparse_vec_sub) (w, u, v, ctx); return;} + TEMPLATE(T, init) (tmp, ctx); + TEMPLATE(T, neg) (tmp, c, ctx); + if (unnz == 0) TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (w, v, tmp, ctx); + else if (TEMPLATE(T, is_one) (tmp, ctx)) TEMPLATE(T, sparse_vec_add) (w, u, v, ctx); + else + { + wnnz = _TEMPLATE(T, sparse_vec_union_nnz) (u, v, ctx); + _TEMPLATE(T, sparse_vec_resize) (w, wnnz, ctx); + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _TEMPLATE(T, sparse_vector_merge_descend) (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: TEMPLATE(T, set)(we->val, ue->val, ctx); break; + case 1: TEMPLATE(T, mul)(we->val, ve->val, c, ctx); + TEMPLATE(T, neg)(we->val, we->val, ctx); break; + default: TEMPLATE(T, mul) (tmp, ve->val, c, ctx); + TEMPLATE(T, sub) (we->val, ue->val, tmp, ctx); + if (TEMPLATE(T, is_zero) (we->val, ctx)) we++; + } + } + _TEMPLATE(T, sparse_vector_shift_left) (w, we - w->entries, ctx); + } + TEMPLATE(T, clear) (tmp, ctx); +} +#endif + diff --git a/fq_sparse_vec_templates/sub.c b/fq_sparse_vec_templates/sub.c new file mode 100644 index 0000000000..1dc625c36b --- /dev/null +++ b/fq_sparse_vec_templates/sub.c @@ -0,0 +1,41 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include +#include "templates.h" + +void TEMPLATE(T, sparse_vec_sub)(TEMPLATE(T, sparse_vec_t) w, const TEMPLATE(T, sparse_vec_t) u, const TEMPLATE(T, sparse_vec_t) v, + const TEMPLATE(T, ctx_t) ctx) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + TEMPLATE(T, sparse_entry_struct) *ue, *ve, *we; + + if (vnnz == 0) {TEMPLATE(T, sparse_vec_set) (w, u, 0, ctx); return;} + if (unnz == 0) {TEMPLATE(T, sparse_vec_neg) (w, v, ctx); return;} + wnnz = _TEMPLATE(T, sparse_vec_union_nnz) (u, v, ctx); + _TEMPLATE(T, sparse_vec_resize) (w, wnnz, ctx); + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _TEMPLATE(T, sparse_vector_merge_descend) (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: TEMPLATE(T, set)(we->val, ue->val, ctx); break; + case 1: TEMPLATE(T, neg)(we->val, ve->val, ctx); break; + default: TEMPLATE(T, sub)(we->val, ue->val, ve->val, ctx); + if (TEMPLATE(T, is_zero) (we->val, ctx)) we++; + } + } + _TEMPLATE(T, sparse_vector_shift_left) (w, we - w->entries, ctx); +} +#endif + diff --git a/fq_sparse_vec_templates/test/t-add.c b/fq_sparse_vec_templates/test/t-add.c new file mode 100644 index 0000000000..dee40647f5 --- /dev/null +++ b/fq_sparse_vec_templates/test/t-add.c @@ -0,0 +1,95 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_vec_t) u, v, w, x; + + FLINT_TEST_INIT(state); + + flint_printf("add/sub...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + len = n_randint(state, 40); + nnz = n_randint(state, len+1); + + TEMPLATE(T, sparse_vec_init)(u, ctx); + TEMPLATE(T, sparse_vec_init)(v, ctx); + TEMPLATE(T, sparse_vec_init)(w, ctx); + TEMPLATE(T, sparse_vec_init)(x, ctx); + + TEMPLATE(T, sparse_vec_randtest)(u, state, nnz, len, ctx); + TEMPLATE(T, sparse_vec_randtest)(v, state, nnz, len, ctx); + + TEMPLATE(T, sparse_vec_add)(w, u, v, ctx); + TEMPLATE(T, sparse_vec_sub)(x, w, v, ctx); + + if (!TEMPLATE(T, sparse_vec_equal)(u, x, 0, ctx)) + { + flint_printf("FAIL: u != u+v-v\n"); + abort(); + } + + TEMPLATE(T, sparse_vec_add)(u, u, v, ctx); + if (!TEMPLATE(T, sparse_vec_equal)(u, w, 0, ctx)) + { + flint_printf("FAIL: (u += v) != u + v\n"); + abort(); + } + + TEMPLATE(T, sparse_vec_sub)(u, u, v, ctx); + if (!TEMPLATE(T, sparse_vec_equal)(u, x, 0, ctx)) + { + flint_printf("FAIL: ((u += v) -= v) != u+v-v\n"); + abort(); + } + TEMPLATE(T, sparse_vec_add)(u, v, u, ctx); + if (!TEMPLATE(T, sparse_vec_equal)(u, w, 0, ctx)) + { + flint_printf("FAIL: (u += v) != u + v\n"); + abort(); + } + + TEMPLATE(T, sparse_vec_sub)(v, w, v, ctx); + if (!TEMPLATE(T, sparse_vec_equal)(v, x, 0, ctx)) + { + flint_printf("FAIL: (v = u+v - v) != u+v-v\n"); + abort(); + } + TEMPLATE(T, sparse_vec_clear)(u, ctx); + TEMPLATE(T, sparse_vec_clear)(v, ctx); + TEMPLATE(T, sparse_vec_clear)(w, ctx); + TEMPLATE(T, sparse_vec_clear)(x, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif \ No newline at end of file diff --git a/fq_sparse_vec_templates/test/t-concat.c b/fq_sparse_vec_templates/test/t-concat.c new file mode 100644 index 0000000000..bd9fee8924 --- /dev/null +++ b/fq_sparse_vec_templates/test/t-concat.c @@ -0,0 +1,103 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include "templates.h" + +#include +#include +#include +#include "ulong_extras.h" + +int main(void) +{ + slong rep, len, nnz; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_vec_t) u, v, w; + TEMPLATE(T, sparse_vec_t) window1, window2; + FLINT_TEST_INIT(state); + + flint_printf("concat...."); + fflush(stdout); + + for (rep = 0; rep < 100; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + + TEMPLATE(T, sparse_vec_init) (u, ctx); + TEMPLATE(T, sparse_vec_init) (v, ctx); + TEMPLATE(T, sparse_vec_init) (w, ctx); + + TEMPLATE(T, sparse_vec_randtest) (u, state, nnz, len, ctx); + TEMPLATE(T, sparse_vec_randtest) (v, state, nnz, len, ctx); + TEMPLATE(T, sparse_vec_randtest) (w, state, nnz, len, ctx); + + TEMPLATE(T, sparse_vec_concat) (w, u, v, len, ctx); + + TEMPLATE(T, sparse_vec_window_init) (window1, w, 0, len, ctx); + TEMPLATE(T, sparse_vec_window_init)(window2, w, len, 2*len, ctx); + + if (!(TEMPLATE(T, sparse_vec_equal) (window1, u, 0, ctx) && TEMPLATE(T, sparse_vec_equal) (window2, v, len, ctx))) + { + flint_printf("u = "); + TEMPLATE(T, sparse_vec_print_pretty) (u, 0, len, ctx); + flint_printf("v = \n"); + TEMPLATE(T, sparse_vec_print_pretty) (v, 0, len, ctx); + flint_printf("u | v = \n"); + TEMPLATE(T, sparse_vec_print_pretty) (w, 0, len, ctx); + flint_printf("window1 = \n"); + TEMPLATE(T, sparse_vec_print_pretty) (window1, 0, len, ctx); + flint_printf("window2 = \n"); + TEMPLATE(T, sparse_vec_print_pretty) (window2, len, len, ctx); + flint_printf("FAIL: results not equal\n"); + abort(); + } + TEMPLATE(T, sparse_vec_window_clear) (window1, ctx); + TEMPLATE(T, sparse_vec_window_clear) (window2, ctx); + + TEMPLATE(T, sparse_vec_init) (window1, ctx); + TEMPLATE(T, sparse_vec_init) (window2, ctx); + TEMPLATE(T, sparse_vec_split) (window1, window2, w, len, ctx); + if (!(TEMPLATE(T, sparse_vec_equal) (window1, u, 0, ctx) && TEMPLATE(T, sparse_vec_equal) (window2, v, 0, ctx))) + { + flint_printf("u = "); + TEMPLATE(T, sparse_vec_print_pretty) (u, 0, len, ctx); + flint_printf("v = \n"); + TEMPLATE(T, sparse_vec_print_pretty) (v, 0, len, ctx); + flint_printf("u | v = \n"); + TEMPLATE(T, sparse_vec_print_pretty) (w, 0, len, ctx); + flint_printf("window1 = \n"); + TEMPLATE(T, sparse_vec_print_pretty) (window1, 0, len, ctx); + flint_printf("window2 = \n"); + TEMPLATE(T, sparse_vec_print_pretty) (window2, 0, len, ctx); + flint_printf("FAIL: results not equal\n"); + abort(); + } + TEMPLATE(T, sparse_vec_window_clear) (window1, ctx); + TEMPLATE(T, sparse_vec_window_clear) (window2, ctx); + TEMPLATE(T, sparse_vec_clear) (u, ctx); + TEMPLATE(T, sparse_vec_clear) (v, ctx); + TEMPLATE(T, sparse_vec_clear) (w, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif \ No newline at end of file diff --git a/fq_sparse_vec_templates/test/t-construct.c b/fq_sparse_vec_templates/test/t-construct.c new file mode 100644 index 0000000000..e1b956805a --- /dev/null +++ b/fq_sparse_vec_templates/test/t-construct.c @@ -0,0 +1,78 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz, i; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_vec_t) u, v; + slong *inds; + TEMPLATE(T, struct) *vals; + FLINT_TEST_INIT(state); + + flint_printf("construction from elements...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + + TEMPLATE(T, sparse_vec_init) (u, ctx); + TEMPLATE(T, sparse_vec_init) (v, ctx); + TEMPLATE(T, sparse_vec_randtest) (u, state, nnz, len, ctx); + TEMPLATE(T, sparse_vec_randtest) (v, state, nnz, len, ctx); + + /* Construct v from entries of u */ + inds = flint_malloc(nnz * sizeof(*inds)); + vals = flint_malloc(nnz * sizeof(*vals)); + for (i = 0; i < nnz; ++i) + { + inds[i] = u->entries[i].ind; + TEMPLATE(T, init) (&vals[i], ctx); + TEMPLATE(T, set) (&vals[i], u->entries[i].val, ctx); + } + TEMPLATE(T, sparse_vec_from_entries) (v, inds, vals, nnz, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (u, v, 0, ctx)) + { + flint_printf("FAIL: u != v\n"); + abort(); + } + flint_free(inds); + for (i = 0; i < nnz; ++i) + { + TEMPLATE(T, clear) (&vals[i], ctx); + } + flint_free(vals); + TEMPLATE(T, sparse_vec_clear) (u, ctx); + TEMPLATE(T, sparse_vec_clear) (v, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif \ No newline at end of file diff --git a/fq_sparse_vec_templates/test/t-dense.c b/fq_sparse_vec_templates/test/t-dense.c new file mode 100644 index 0000000000..9ff08d030d --- /dev/null +++ b/fq_sparse_vec_templates/test/t-dense.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz, i; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, t) *val; + TEMPLATE(T, sparse_vec_t) u, v; + TEMPLATE(T, struct) *w, *x; + FLINT_TEST_INIT(state); + + flint_printf("conversion to/from dense vector...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + + TEMPLATE(T, sparse_vec_init) (u, ctx); + TEMPLATE(T, sparse_vec_init) (v, ctx); + w = _TEMPLATE(T, vec_init) (len, ctx); + x = _TEMPLATE(T, vec_init) (len, ctx); + + TEMPLATE(T, sparse_vec_randtest) (u, state, nnz, len, ctx); + TEMPLATE(T, sparse_vec_randtest) (v, state, nnz, len, ctx); + + TEMPLATE(T, sparse_vec_to_dense) (w, u, len, ctx); + TEMPLATE(T, sparse_vec_from_dense) (v, w, len, ctx); + + for (i = 0; i < len; ++i) + { + val = TEMPLATE(T, sparse_vec_at) (u, i, ctx); + if ((val == NULL && (!TEMPLATE(T, is_zero) (&w[i], ctx))) || (val != NULL && !(TEMPLATE(T, equal) (*val, &w[i], ctx)))) + { + flint_printf("FAIL: u[%wd] != v[%wd]\n", i, i); + abort(); + } + } + if (!TEMPLATE(T, sparse_vec_equal) (u, v, 0, ctx)) + { + flint_printf("FAIL: u != v\n"); + abort(); + } + + _TEMPLATE(T, vec_randtest) (w, state, len, ctx); + TEMPLATE(T, sparse_vec_from_dense) (u, w, len, ctx); + TEMPLATE(T, sparse_vec_to_dense) (x, u, len, ctx); + + if (!_TEMPLATE(T, vec_equal) (w, x, len, ctx)) + { + flint_printf("FAIL: w != x\n"); + abort(); + } + TEMPLATE(T, sparse_vec_clear) (u, ctx); + TEMPLATE(T, sparse_vec_clear) (v, ctx); + _TEMPLATE(T, vec_clear) (w, len, ctx); + _TEMPLATE(T, vec_clear) (x, len, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif \ No newline at end of file diff --git a/fq_sparse_vec_templates/test/t-dot.c b/fq_sparse_vec_templates/test/t-dot.c new file mode 100644 index 0000000000..f7714b43d7 --- /dev/null +++ b/fq_sparse_vec_templates/test/t-dot.c @@ -0,0 +1,85 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, t) a, b; + TEMPLATE(T, sparse_vec_t) u, v; + TEMPLATE(T, struct) *w, *x; + FLINT_TEST_INIT(state); + + flint_printf("dot product...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + TEMPLATE(T, sparse_vec_init) (u, ctx); + TEMPLATE(T, sparse_vec_init) (v, ctx); + TEMPLATE(T, init) (a, ctx); + TEMPLATE(T, init) (b, ctx); + + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + + w = _TEMPLATE(T, vec_init) (len, ctx); + x = _TEMPLATE(T, vec_init) (len, ctx); + + TEMPLATE(T, sparse_vec_randtest) (u, state, nnz, len, ctx); + TEMPLATE(T, sparse_vec_randtest) (v, state, nnz, len, ctx); + TEMPLATE(T, sparse_vec_to_dense) (w, u, len, ctx); + TEMPLATE(T, sparse_vec_to_dense) (x, v, len, ctx); + + TEMPLATE(T, sparse_vec_dot) (a, u, v, ctx); + _TEMPLATE(T, vec_dot) (b, w, x, len, ctx); + + if (!TEMPLATE(T, equal) (a, b, ctx)) + { + flint_printf("Fail: sparse dot sparse\n"); + abort(); + } + + TEMPLATE(T, sparse_vec_dot_dense) (a, u, x, ctx); + + if (!TEMPLATE(T, equal) (a, b, ctx)) + { + flint_printf("Fail: sparse dot dense\n"); + abort(); + } + + TEMPLATE(T, sparse_vec_clear) (u, ctx); + TEMPLATE(T, sparse_vec_clear) (v, ctx); + _TEMPLATE(T, vec_clear) (w, len, ctx); + _TEMPLATE(T, vec_clear) (x, len, ctx); + TEMPLATE(T, clear) (a, ctx); + TEMPLATE(T, clear) (b, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif \ No newline at end of file diff --git a/fq_sparse_vec_templates/test/t-init_clear.c b/fq_sparse_vec_templates/test/t-init_clear.c new file mode 100644 index 0000000000..01145bd904 --- /dev/null +++ b/fq_sparse_vec_templates/test/t-init_clear.c @@ -0,0 +1,94 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +static void check_zero(TEMPLATE(T, sparse_vec_t) vec) +{ + if (vec->nnz != UWORD(0)) +{ + flint_printf("FAIL: nnz not zero!\n"); + abort(); + } + if (vec->entries != NULL) +{ + flint_printf("FAIL: entries not null!\n"); + abort(); + } +} + +int +main(void) +{ + slong rep, len, nnz, i; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_vec_t) vec; + FLINT_TEST_INIT(state); + + flint_printf("init/clear...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + TEMPLATE(T, sparse_vec_init) (vec, ctx); + + check_zero(vec); + + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + + TEMPLATE(T, sparse_vec_randtest) (vec, state, nnz, len, ctx); + + if (nnz == 0) check_zero(vec); + else + { + for (i = 0; i < nnz; ++i) + { + TEMPLATE(T, sparse_entry_struct) *e = &vec->entries[i]; + if (e->ind >= len) + { + flint_printf("FAIL: found index %wd >= %wd!\n", e->ind, len); + abort(); + } + if (TEMPLATE(T, is_zero) (e->val, ctx)) + { + flint_printf("FAIL: found 0 value\n"); + abort(); + } + if (i > 0 && e->ind <= e[-1].ind) + { + flint_printf("FAIL: found index %wd <= previous index %wd\n", e->ind, e[-1].ind); + abort(); + } + } + } + + TEMPLATE(T, sparse_vec_clear) (vec, ctx); + check_zero(vec); + + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif \ No newline at end of file diff --git a/fq_sparse_vec_templates/test/t-neg.c b/fq_sparse_vec_templates/test/t-neg.c new file mode 100644 index 0000000000..0819d6bec3 --- /dev/null +++ b/fq_sparse_vec_templates/test/t-neg.c @@ -0,0 +1,77 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_vec_t) u, v, w, x; + FLINT_TEST_INIT(state); + + + flint_printf("neg...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + + TEMPLATE(T, sparse_vec_init) (u, ctx); + TEMPLATE(T, sparse_vec_init) (v, ctx); + TEMPLATE(T, sparse_vec_init) (w, ctx); + TEMPLATE(T, sparse_vec_init) (x, ctx); + + TEMPLATE(T, sparse_vec_randtest) (u, state, nnz, len, ctx); + TEMPLATE(T, sparse_vec_randtest) (v, state, nnz, len, ctx); + + TEMPLATE(T, sparse_vec_sub) (w, u, v, ctx); + TEMPLATE(T, sparse_vec_neg) (v, v, ctx); + TEMPLATE(T, sparse_vec_add) (x, u, v, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (w, x, 0, ctx)) + { + flint_printf("FAIL: u - v != u + (-v)\n"); + abort(); + } + + TEMPLATE(T, sparse_vec_neg) (w, u, ctx); + TEMPLATE(T, sparse_vec_neg) (u, u, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (w, w, 0, ctx)) + { + flint_printf("FAIL\n"); + abort(); + } + TEMPLATE(T, sparse_vec_clear) (u, ctx); + TEMPLATE(T, sparse_vec_clear) (v, ctx); + TEMPLATE(T, sparse_vec_clear) (w, ctx); + TEMPLATE(T, sparse_vec_clear) (x, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif \ No newline at end of file diff --git a/fq_sparse_vec_templates/test/t-scalar_mul.c b/fq_sparse_vec_templates/test/t-scalar_mul.c new file mode 100644 index 0000000000..35e936f68b --- /dev/null +++ b/fq_sparse_vec_templates/test/t-scalar_mul.c @@ -0,0 +1,128 @@ +/* + Copyright (w) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifdef T + +#include "templates.h" + +#include +#include +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz; + TEMPLATE(T, t) c; + TEMPLATE(T, ctx_t) ctx; + TEMPLATE(T, sparse_vec_t) u, v, w, x; + FLINT_TEST_INIT(state); + + flint_printf("scalar_mul and muladd...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + TEMPLATE(T, ctx_randtest) (ctx, state); + TEMPLATE(T, init) (c, ctx); + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + + TEMPLATE(T, sparse_vec_init) (u, ctx); + TEMPLATE(T, sparse_vec_init) (v, ctx); + TEMPLATE(T, sparse_vec_init) (w, ctx); + TEMPLATE(T, sparse_vec_init) (x, ctx); + + TEMPLATE(T, sparse_vec_randtest) (u, state, nnz, len, ctx); + TEMPLATE(T, sparse_vec_randtest) (v, state, nnz, len, ctx); + TEMPLATE(T, randtest) (c, state, ctx); + + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T)) (w, u, v, c, ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (x, v, c, ctx); + TEMPLATE(T, sparse_vec_add) (x, u, x, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (w, x, 0, ctx)) + { + flint_printf("FAIL: u + c*v != u + (c*v)\n"); + abort(); + } + + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_submul, T)) (w, u, v, c, ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (x, v, c, ctx); + TEMPLATE(T, sparse_vec_sub) (x, u, x, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (w, x, 0, ctx)) + { + flint_printf("FAIL: u + c*v != u + (c*v)\n"); + abort(); + } + + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T)) (w, u, v, c, ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T)) (u, u, v, c, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (u, w, 0, ctx)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T)) (w, u, v, c, ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_addmul, T)) (v, u, v, c, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (v, w, 0, ctx)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_submul, T)) (w, u, v, c, ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_submul, T)) (u, u, v, c, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (u, w, 0, ctx)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_submul, T)) (w, u, v, c, ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_submul, T)) (v, u, v, c, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (v, w, 0, ctx)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (x, v, c, ctx); + TEMPLATE(T, TEMPLATE(sparse_vec_scalar_mul, T)) (v, v, c, ctx); + + if (!TEMPLATE(T, sparse_vec_equal) (v, x, 0, ctx)) + { + flint_printf("FAIL: c*v != (c *= v)\n"); + abort(); + } + + TEMPLATE(T, sparse_vec_clear) (u, ctx); + TEMPLATE(T, sparse_vec_clear) (v, ctx); + TEMPLATE(T, sparse_vec_clear) (w, ctx); + TEMPLATE(T, sparse_vec_clear) (x, ctx); + TEMPLATE(T, clear) (c, ctx); + TEMPLATE(T, ctx_clear) (ctx); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} + +#endif \ No newline at end of file diff --git a/fq_vec_templates.h b/fq_vec_templates.h index 9dbcd0601a..61f9a49dcc 100644 --- a/fq_vec_templates.h +++ b/fq_vec_templates.h @@ -47,6 +47,20 @@ int _TEMPLATE(T, vec_print)(const TEMPLATE(T, struct) * vec, slong len, return _TEMPLATE(T, vec_fprint)(stdout, vec, len, ctx); } +FQ_VEC_TEMPLATES_INLINE +void _TEMPLATE(T, vec_print_pretty)(const TEMPLATE(T, struct) * vec, slong len, + const TEMPLATE(T, ctx_t) ctx) +{ + slong i; + flint_printf("["); + for (i = 0; i < len; ++i) + { + if (i > 0) flint_printf(" "); + TEMPLATE(T, print_pretty) (&vec[i], ctx); + } + flint_printf("]"); +} + /* Conversions *************************************************************/ /* Assignment and basic manipulation ***************************************/ diff --git a/fq_zech_mat/addmul.c b/fq_zech_mat/addmul.c new file mode 100644 index 0000000000..a84b964966 --- /dev/null +++ b/fq_zech_mat/addmul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_mat_templates/addmul.c" +#undef CAP_T +#undef T diff --git a/fq_zech_mat/mul_vec.c b/fq_zech_mat/mul_vec.c new file mode 100644 index 0000000000..1aed5aabe3 --- /dev/null +++ b/fq_zech_mat/mul_vec.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_mat_templates/mul_vec.c" +#undef CAP_T +#undef T diff --git a/fq_zech_mat/scalar_addmul.c b/fq_zech_mat/scalar_addmul.c new file mode 100644 index 0000000000..8ef62b96e2 --- /dev/null +++ b/fq_zech_mat/scalar_addmul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_mat_templates/scalar_addmul.c" +#undef CAP_T +#undef T diff --git a/fq_zech_mat/scalar_mul.c b/fq_zech_mat/scalar_mul.c new file mode 100644 index 0000000000..095427d95b --- /dev/null +++ b/fq_zech_mat/scalar_mul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_mat_templates/scalar_mul.c" +#undef CAP_T +#undef T diff --git a/fq_zech_mat/scalar_submul.c b/fq_zech_mat/scalar_submul.c new file mode 100644 index 0000000000..858564f147 --- /dev/null +++ b/fq_zech_mat/scalar_submul.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_mat_templates/scalar_submul.c" +#undef CAP_T +#undef T diff --git a/fq_zech_mat/transpose.c b/fq_zech_mat/transpose.c new file mode 100644 index 0000000000..8ffa3ea6e8 --- /dev/null +++ b/fq_zech_mat/transpose.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2013 Mike Hansen + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_mat_templates/transpose.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat.h b/fq_zech_sparse_mat.h new file mode 100644 index 0000000000..e6f79c5514 --- /dev/null +++ b/fq_zech_sparse_mat.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2013 Mike Hansen + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef FQ_ZECH_SPARSE_MAT_H +#define FQ_ZECH_SPARSE_MAT_H + +#ifdef FQ_ZECH_SPARSE_MAT_INLINES_C +#define FQ_SPARSE_MAT_TEMPLATES_INLINE FLINT_DLL +#define FQ_ZECH_SPARSE_MAT_INLINE FLINT_DLL +#else +#define FQ_SPARSE_MAT_TEMPLATES_INLINE static __inline__ +#define FQ_ZECH_SPARSE_MAT_INLINE static __inline__ +#endif + + +#include "fq_zech.h" +#include "fq_zech_vec.h" +#include "fq_zech_sparse_vec.h" +#include "fq_zech_mat.h" + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates.h" +#undef CAP_T +#undef T + +#endif diff --git a/fq_zech_sparse_mat/from_entries.c b/fq_zech_sparse_mat/from_entries.c new file mode 100644 index 0000000000..b77e12696e --- /dev/null +++ b/fq_zech_sparse_mat/from_entries.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/from_entries.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/inv.c b/fq_zech_sparse_mat/inv.c new file mode 100644 index 0000000000..a408e8b990 --- /dev/null +++ b/fq_zech_sparse_mat/inv.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/inv.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/lu.c b/fq_zech_sparse_mat/lu.c new file mode 100644 index 0000000000..155df51f22 --- /dev/null +++ b/fq_zech_sparse_mat/lu.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/lu.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/nullspace_block_lanczos.c b/fq_zech_sparse_mat/nullspace_block_lanczos.c new file mode 100644 index 0000000000..432d782b3e --- /dev/null +++ b/fq_zech_sparse_mat/nullspace_block_lanczos.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/nullspace_block_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/nullspace_block_wiedemann.c b/fq_zech_sparse_mat/nullspace_block_wiedemann.c new file mode 100644 index 0000000000..3e90244b4a --- /dev/null +++ b/fq_zech_sparse_mat/nullspace_block_wiedemann.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/nullspace_block_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/nullspace_lanczos.c b/fq_zech_sparse_mat/nullspace_lanczos.c new file mode 100644 index 0000000000..0677b1c8a2 --- /dev/null +++ b/fq_zech_sparse_mat/nullspace_lanczos.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/nullspace_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/nullspace_lu.c b/fq_zech_sparse_mat/nullspace_lu.c new file mode 100644 index 0000000000..371d4b4464 --- /dev/null +++ b/fq_zech_sparse_mat/nullspace_lu.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/nullspace_lu.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/nullspace_rref.c b/fq_zech_sparse_mat/nullspace_rref.c new file mode 100644 index 0000000000..2aa60ad53f --- /dev/null +++ b/fq_zech_sparse_mat/nullspace_rref.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/nullspace_rref.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/nullspace_wiedemann.c b/fq_zech_sparse_mat/nullspace_wiedemann.c new file mode 100644 index 0000000000..8545d09605 --- /dev/null +++ b/fq_zech_sparse_mat/nullspace_wiedemann.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/nullspace_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/print_pretty.c b/fq_zech_sparse_mat/print_pretty.c new file mode 100644 index 0000000000..2a37fce791 --- /dev/null +++ b/fq_zech_sparse_mat/print_pretty.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/print_pretty.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/randtest.c b/fq_zech_sparse_mat/randtest.c new file mode 100644 index 0000000000..5c8144874d --- /dev/null +++ b/fq_zech_sparse_mat/randtest.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/randtest.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/rref.c b/fq_zech_sparse_mat/rref.c new file mode 100644 index 0000000000..42cde0c19b --- /dev/null +++ b/fq_zech_sparse_mat/rref.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/rref.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/solve_block_lanczos.c b/fq_zech_sparse_mat/solve_block_lanczos.c new file mode 100644 index 0000000000..9f08f70926 --- /dev/null +++ b/fq_zech_sparse_mat/solve_block_lanczos.c @@ -0,0 +1,27 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + Algorithm taken from P. Montgomery, "A Block Lanczos Algorithm for + Finding Dependencies over GF(2)", Advances in Cryptology - EUROCRYPT '95 + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/solve_block_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/solve_block_wiedemann.c b/fq_zech_sparse_mat/solve_block_wiedemann.c new file mode 100644 index 0000000000..9004ad97e9 --- /dev/null +++ b/fq_zech_sparse_mat/solve_block_wiedemann.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/solve_block_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/solve_lanczos.c b/fq_zech_sparse_mat/solve_lanczos.c new file mode 100644 index 0000000000..58a88db3c7 --- /dev/null +++ b/fq_zech_sparse_mat/solve_lanczos.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/solve_lanczos.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/solve_lu.c b/fq_zech_sparse_mat/solve_lu.c new file mode 100644 index 0000000000..3569a870e9 --- /dev/null +++ b/fq_zech_sparse_mat/solve_lu.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/solve_lu.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/solve_rref.c b/fq_zech_sparse_mat/solve_rref.c new file mode 100644 index 0000000000..5691dde7af --- /dev/null +++ b/fq_zech_sparse_mat/solve_rref.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/solve_rref.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/solve_wiedemann.c b/fq_zech_sparse_mat/solve_wiedemann.c new file mode 100644 index 0000000000..c47c3741fa --- /dev/null +++ b/fq_zech_sparse_mat/solve_wiedemann.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/solve_wiedemann.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-add.c b/fq_zech_sparse_mat/test/t-add.c new file mode 100644 index 0000000000..783d295204 --- /dev/null +++ b/fq_zech_sparse_mat/test/t-add.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-add.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-concat_horizontal.c b/fq_zech_sparse_mat/test/t-concat_horizontal.c new file mode 100644 index 0000000000..f3ee3eba0e --- /dev/null +++ b/fq_zech_sparse_mat/test/t-concat_horizontal.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-concat_horizontal.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-concat_vertical.c b/fq_zech_sparse_mat/test/t-concat_vertical.c new file mode 100644 index 0000000000..d178c4047e --- /dev/null +++ b/fq_zech_sparse_mat/test/t-concat_vertical.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-concat_vertical.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-construct.c b/fq_zech_sparse_mat/test/t-construct.c new file mode 100644 index 0000000000..d27df5fc1f --- /dev/null +++ b/fq_zech_sparse_mat/test/t-construct.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-construct.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-dense.c b/fq_zech_sparse_mat/test/t-dense.c new file mode 100644 index 0000000000..38269a46f5 --- /dev/null +++ b/fq_zech_sparse_mat/test/t-dense.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-dense.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-init_clear.c b/fq_zech_sparse_mat/test/t-init_clear.c new file mode 100644 index 0000000000..5f9fe8ef63 --- /dev/null +++ b/fq_zech_sparse_mat/test/t-init_clear.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-init_clear.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-inv.c b/fq_zech_sparse_mat/test/t-inv.c new file mode 100644 index 0000000000..7f1d3f10cb --- /dev/null +++ b/fq_zech_sparse_mat/test/t-inv.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-inv.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-lu.c b/fq_zech_sparse_mat/test/t-lu.c new file mode 100644 index 0000000000..5e859d59fa --- /dev/null +++ b/fq_zech_sparse_mat/test/t-lu.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-lu.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-mul.c b/fq_zech_sparse_mat/test/t-mul.c new file mode 100644 index 0000000000..542761741e --- /dev/null +++ b/fq_zech_sparse_mat/test/t-mul.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-mul.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-neg.c b/fq_zech_sparse_mat/test/t-neg.c new file mode 100644 index 0000000000..66520ae447 --- /dev/null +++ b/fq_zech_sparse_mat/test/t-neg.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-neg.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-nullspace.c b/fq_zech_sparse_mat/test/t-nullspace.c new file mode 100644 index 0000000000..58be848415 --- /dev/null +++ b/fq_zech_sparse_mat/test/t-nullspace.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-nullspace.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-rref.c b/fq_zech_sparse_mat/test/t-rref.c new file mode 100644 index 0000000000..b84a2bfa95 --- /dev/null +++ b/fq_zech_sparse_mat/test/t-rref.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-rref.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-scalar_mul.c b/fq_zech_sparse_mat/test/t-scalar_mul.c new file mode 100644 index 0000000000..7166cfecfc --- /dev/null +++ b/fq_zech_sparse_mat/test/t-scalar_mul.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-scalar_mul.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-solve.c b/fq_zech_sparse_mat/test/t-solve.c new file mode 100644 index 0000000000..24f27df969 --- /dev/null +++ b/fq_zech_sparse_mat/test/t-solve.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-solve.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/test/t-transpose.c b/fq_zech_sparse_mat/test/t-transpose.c new file mode 100644 index 0000000000..8d474043aa --- /dev/null +++ b/fq_zech_sparse_mat/test/t-transpose.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/test/t-transpose.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/transpose.c b/fq_zech_sparse_mat/transpose.c new file mode 100644 index 0000000000..c6d2fec1fd --- /dev/null +++ b/fq_zech_sparse_mat/transpose.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/transpose.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_mat/window_init.c b/fq_zech_sparse_mat/window_init.c new file mode 100644 index 0000000000..0df7ccaf51 --- /dev/null +++ b/fq_zech_sparse_mat/window_init.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_mat.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_mat_templates/window_init.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec.h b/fq_zech_sparse_vec.h new file mode 100644 index 0000000000..b538e22721 --- /dev/null +++ b/fq_zech_sparse_vec.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2013 Mike Hansen + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef FQ_ZECH_SPARSE_VEC_H +#define FQ_ZECH_SPARSE_VEC_H + +#ifdef FQ_ZECH_SPARSE_VEC_INLINES_C +#define FQ_SPARSE_VEC_TEMPLATES_INLINE FLINT_DLL +#define FQ_ZECH_SPARSE_VEC_INLINE FLINT_DLL +#else +#define FQ_SPARSE_VEC_TEMPLATES_INLINE static __inline__ +#define FQ_ZECH_SPARSE_VEC_INLINE static __inline__ +#endif + +#include "fq_zech.h" +#include "fq_zech_vec.h" + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates.h" +#undef CAP_T +#undef T + +#endif diff --git a/fq_zech_sparse_vec/add.c b/fq_zech_sparse_vec/add.c new file mode 100644 index 0000000000..a291ea8727 --- /dev/null +++ b/fq_zech_sparse_vec/add.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/add.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/print_pretty.c b/fq_zech_sparse_vec/print_pretty.c new file mode 100644 index 0000000000..34009b3ae5 --- /dev/null +++ b/fq_zech_sparse_vec/print_pretty.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/print_pretty.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/randtest.c b/fq_zech_sparse_vec/randtest.c new file mode 100644 index 0000000000..14f33eb61d --- /dev/null +++ b/fq_zech_sparse_vec/randtest.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/randtest.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/scalar_addmul.c b/fq_zech_sparse_vec/scalar_addmul.c new file mode 100644 index 0000000000..aa00297f87 --- /dev/null +++ b/fq_zech_sparse_vec/scalar_addmul.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/scalar_addmul.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/scalar_submul.c b/fq_zech_sparse_vec/scalar_submul.c new file mode 100644 index 0000000000..28cfc80475 --- /dev/null +++ b/fq_zech_sparse_vec/scalar_submul.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/scalar_submul.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/sub.c b/fq_zech_sparse_vec/sub.c new file mode 100644 index 0000000000..f0d0fc2d3b --- /dev/null +++ b/fq_zech_sparse_vec/sub.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/sub.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/test/t-add.c b/fq_zech_sparse_vec/test/t-add.c new file mode 100644 index 0000000000..96d3f27408 --- /dev/null +++ b/fq_zech_sparse_vec/test/t-add.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/test/t-add.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/test/t-concat.c b/fq_zech_sparse_vec/test/t-concat.c new file mode 100644 index 0000000000..041ac0be20 --- /dev/null +++ b/fq_zech_sparse_vec/test/t-concat.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/test/t-concat.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/test/t-construct.c b/fq_zech_sparse_vec/test/t-construct.c new file mode 100644 index 0000000000..96f77b9a85 --- /dev/null +++ b/fq_zech_sparse_vec/test/t-construct.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/test/t-construct.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/test/t-dense.c b/fq_zech_sparse_vec/test/t-dense.c new file mode 100644 index 0000000000..ebf9a7513c --- /dev/null +++ b/fq_zech_sparse_vec/test/t-dense.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/test/t-dense.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/test/t-dot.c b/fq_zech_sparse_vec/test/t-dot.c new file mode 100644 index 0000000000..e91ac6ba1e --- /dev/null +++ b/fq_zech_sparse_vec/test/t-dot.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/test/t-dot.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/test/t-init_clear.c b/fq_zech_sparse_vec/test/t-init_clear.c new file mode 100644 index 0000000000..02c3ec966a --- /dev/null +++ b/fq_zech_sparse_vec/test/t-init_clear.c @@ -0,0 +1,23 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/test/t-init_clear.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/test/t-neg.c b/fq_zech_sparse_vec/test/t-neg.c new file mode 100644 index 0000000000..6e014f89c3 --- /dev/null +++ b/fq_zech_sparse_vec/test/t-neg.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/test/t-neg.c" +#undef CAP_T +#undef T diff --git a/fq_zech_sparse_vec/test/t-scalar_mul.c b/fq_zech_sparse_vec/test/t-scalar_mul.c new file mode 100644 index 0000000000..35d652fa68 --- /dev/null +++ b/fq_zech_sparse_vec/test/t-scalar_mul.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + + +#include "fq_zech_sparse_vec.h" + +#ifdef T +#undef T +#endif + +#define T fq_zech +#define CAP_T FQ_ZECH +#include "fq_sparse_vec_templates/test/t-scalar_mul.c" +#undef CAP_T +#undef T diff --git a/hashmap.c b/hashmap.c index c4dde1c12f..103b0954c5 100644 --- a/hashmap.c +++ b/hashmap.c @@ -9,141 +9,92 @@ (at your option) any later version. See . */ +#include #include "flint.h" #include "hashmap.h" -void hashmap1_init(hashmap1_t h) +void hashmap_init(hashmap_t h, slong size) { - h->data = (hashmap1_elem_s *) flint_calloc(HASHMAP_START_SIZE, - sizeof(hashmap1_elem_s)); - h->alloc = HASHMAP_START_SIZE; - h->mask = HASHMAP_START_MASK; - h->num_used = 0; + memset(h, 0, sizeof(*h)); + h->size = (UWORD(1)) << MIN_HASHMAP_BITS; + while (h->size < size) h->size <<= UWORD(1); + + h->mask = 2*h->size - 1; + h->num = 0; + h->table = flint_calloc(2*h->size, sizeof(*h->table)); + h->keys = flint_malloc(h->size*sizeof(*h->keys)); + h->vals = flint_malloc(h->size*sizeof(*h->vals)); } -void hashmap1_init2(hashmap1_t h, slong size) +void hashmap_clear(hashmap_t h) { - slong bits = 10; - - if (2*size >= 0) - size *= 2; - - while ((WORD(1) << bits) < size) - bits++; - - h->alloc = (WORD(1) << bits); - h->mask = h->alloc - 1; - h->num_used = 0; - - h->data = (hashmap1_elem_s *) flint_calloc(h->alloc, - sizeof(hashmap1_elem_s)); + flint_free(h->table); + flint_free(h->keys); + flint_free(h->vals); + memset(h, 0, sizeof(*h)); } -void hashmap1_clear(hashmap1_t h) +static void _hashmap_rehash(hashmap_t h) { - flint_free(h->data); + slong i, num = h->num; + h->size <<= 1; + h->mask = 2*h->size - 1; + h->table = realloc(h->table, 2*h->size*sizeof(*h->table)); + h->keys = realloc(h->keys, h->size*sizeof(*h->keys)); + h->vals = realloc(h->vals, h->size*sizeof(*h->vals)); + memset(h->table, 0, 2*h->size*sizeof(*h->table)); + h->num = 0; + for (i = 0; i < num; ++i) + hashmap_put(h, h->keys[i], h->vals[i]); } -/* find location in data to store value with 1 word key */ -slong hashmap1_hash(ulong key, hashmap1_t h) +static slong _hashmap_pos(hashmap_t h, slong key, int skip_deleted) { - slong loc, i; - - if (h->num_used == h->alloc/2) - return -WORD(1); /* hashmap is full */ - - loc = (slong) hashmap1_hash_key(key, h); - - for (i = 0; i < h->alloc; i++) - { - if (h->data[loc].in_use == 0 || h->data[loc].key == key) - return loc; - - loc++; - if (loc == h->alloc) - loc = 0; - } - - return -WORD(1); /* map needs rehashing */ + slong ind, pos = key*UWORD(13282407956253574709) + UWORD(286824421); + for(; (ind = h->table[pos & h->mask]); pos++) + { + if (!skip_deleted && ind == -1) break; + if (ind != -1 && h->keys[ind - 1] == key) break; + } + return pos & h->mask; } -/* rehash a full hashmap to twice current size */ -void hashmap1_rehash(hashmap1_t h) +void * hashmap_get(hashmap_t h, slong key) { - slong i; - hashmap1_elem_s * tmp; - - tmp = h->data; - h->data = (hashmap1_elem_s *) flint_calloc(2*h->alloc, sizeof(hashmap1_elem_s)); - - h->alloc = 2*h->alloc; - h->mask = h->alloc - 1; - h->num_used = 0; - - for (i = 0; i < h->alloc/2; i++) - { - if (tmp[i].in_use == 1) - hashmap1_insert(tmp[i].key, tmp[i].value, h); - } - - flint_free(tmp); + slong pos = _hashmap_pos(h, key, 1), ind = h->table[pos]; + return (ind = h->table[pos]) ? h->vals[ind - 1] : NULL; } -/* insert key, value pair into hashmap */ -void hashmap1_insert(ulong key, void * value, hashmap1_t h) +void hashmap_put(hashmap_t h, slong key, void *val) { - slong loc; - - loc = hashmap1_hash(key, h); - if (loc == -WORD(1)) - { - hashmap1_rehash(h); - loc = hashmap1_hash(key, h); - - if (loc == -WORD(1)) - { - /* should never be reached */ - flint_printf("Rehashing unsuccessful\n"); - flint_abort(); - } - } - - h->data[loc].value = value; - h->data[loc].key = key; - h->data[loc].in_use = 1; - h->num_used += 1; + slong pos = _hashmap_pos(h, key, 1), ind = h->table[pos]; + if(ind > 0) h->vals[ind - 1] = val; + else if(h->num < h->size) + { + pos = _hashmap_pos(h, key, 0); + h->keys[h->num] = key; + h->vals[h->num] = val; + h->table[pos] = ++h->num; + } + else + { + _hashmap_rehash(h); + hashmap_put(h, key, val); + } } -/* - set *ptr to location of value corresponding to key in hashmap - return 1 if found, otherwise return 0 (in which case *ptr = NULL) -*/ -int hashmap1_find(void ** ptr, ulong key, hashmap1_t h) +void hashmap_rem(hashmap_t h, slong key) { - slong i, loc; - - loc = hashmap1_hash_key(key, h); - - for (i = 0; i < h->alloc; i++) - { - if (h->data[loc].in_use == 0) - { - (*ptr) = NULL; - return 0; - } - - if (h->data[loc].key == key) - { - (*ptr) = h->data[loc].value; - return 1; - } - - loc++; - if (loc == h->alloc) - loc = 0; - } - - (*ptr) = NULL; - - return 0; -} + slong pos = _hashmap_pos(h, key, 1), ind = h->table[pos]; + if(ind > 0) + { + h->table[pos] = -1; /* Mark as deleted, new entries can be put here */ + if (ind < h->num) + { + h->keys[ind - 1] = h->keys[h->num - 1]; + h->vals[ind - 1] = h->vals[h->num - 1]; + h->table[_hashmap_pos(h, h->keys[ind - 1], 1)] = ind; + } + h->num--; + } +} \ No newline at end of file diff --git a/hashmap.h b/hashmap.h index 7cda979172..cc131767f0 100644 --- a/hashmap.h +++ b/hashmap.h @@ -14,109 +14,33 @@ #include "flint.h" -#define HASHMAP_START_SIZE 1024 -#define HASHMAP_START_MASK (HASHMAP_START_SIZE - 1) +#define MIN_HASHMAP_BITS 5 -/****************************************************************************** - - Hashmap types with one word key - -******************************************************************************/ - -typedef struct hashmap1_elem_s -{ - ulong key; - void * value; - int in_use; -} hashmap1_elem_s; - -typedef struct hashmap1_s +typedef struct { - slong alloc; - slong num_used; + ulong size; ulong mask; - hashmap1_elem_s * data; -} hashmap1_s; - -typedef hashmap1_s hashmap1_t[1]; - -/****************************************************************************** - - Hash functions - -******************************************************************************/ - -/* from lookup3.c, by Bob Jenkins, May 2006, Public Domain. */ - -#define hash_rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) - -#define hash_mix(a,b,c) \ -{ \ - c ^= b; c -= hash_rot(b, 14); \ - a ^= c; a -= hash_rot(c, 11); \ - b ^= a; b -= hash_rot(a, 25); \ - c ^= b; c -= hash_rot(b, 16); \ - a ^= c; a -= hash_rot(c, 4); \ - b ^= a; b -= hash_rot(a, 14); \ - c ^= b; c -= hash_rot(b, 24); \ -} - -/* End of Public Domain code. */ - -#if FLINT64 - -static __inline__ -ulong hash_word(ulong val) -{ - int * ptr = (int * ) &val; - int a = ptr[0], b = ptr[1], c = 0; - - hash_mix(a, b, c); - - ptr[0] = b; - ptr[1] = c; - - return val; -} - -#else + ulong num; + ulong *table; + slong *keys; + void **vals; +} hashmap_struct; -static __inline__ -ulong hash_word(ulong a) -{ - int b = 0, c = 0; - - hash_mix(a, b, c); - - return c; -} - -#endif +typedef hashmap_struct hashmap_t[1]; -/****************************************************************************** - - Hashmap functions with one word key - -******************************************************************************/ - -FLINT_DLL void hashmap1_init(hashmap1_t h); - -FLINT_DLL void hashmap1_init2(hashmap1_t h, slong size); - -FLINT_DLL void hashmap1_clear(hashmap1_t h); - -static __inline__ -ulong hashmap1_hash_key(ulong key, hashmap1_t h) -{ - return hash_word(key) & h->mask; -} +/* Initialize hash table to accomodate size elements */ +void hashmap_init(hashmap_t h, slong size); -FLINT_DLL slong hashmap1_hash(ulong key, hashmap1_t h); +/* Clear hash table */ +void hashmap_clear(hashmap_t h); -FLINT_DLL void hashmap1_rehash(hashmap1_t h); +/* Get value associated with given key */ +void * hashmap_get(hashmap_t h, slong key); -FLINT_DLL void hashmap1_insert(ulong key, void * value, hashmap1_t h); +/* Assign value to a given key */ +void hashmap_put(hashmap_t h, slong key, void *val); -FLINT_DLL int hashmap1_find(void ** ptr, ulong key, hashmap1_t h); +/* Remove value with a given key */ +void hashmap_rem(hashmap_t h, slong key); #endif diff --git a/heap.c b/heap.c new file mode 100644 index 0000000000..d5417a1fba --- /dev/null +++ b/heap.c @@ -0,0 +1,104 @@ +/* + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include "flint.h" +#include "heap.h" + +static void _heap_up(heap_t h, slong pos) +{ + const slong idx = h->idx[pos]; + slong nidx, npos; + for (; pos > 0; pos = npos) + { + npos = (pos-1)/2; + nidx = h->idx[npos]; + if (h->val[idx] >= h->val[nidx]) break; + + h->idx[pos] = nidx; + h->pos[nidx] = pos; + } + h->idx[pos] = idx; + h->pos[idx] = pos; +} + +void _heap_down(heap_t h, slong pos) +{ + const slong idx = h->idx[pos]; + slong nidx, npos; + for (; (npos = 2*pos+1) < h->num; pos = npos) + { + if (npos+1 < h->num && h->val[h->idx[npos]] > h->val[h->idx[npos+1]]) ++npos; + nidx = h->idx[npos]; + if (h->val[idx] <= h->val[nidx]) break; + + h->idx[pos] = nidx; + h->pos[nidx] = pos; + } + h->idx[pos] = idx; + h->pos[idx] = pos; +} + +void heap_init(heap_t h, slong cap) +{ + h->cap = FLINT_MAX(cap, MIN_HEAP_CAP); + h->idx = flint_malloc(h->cap*sizeof(h->idx)); + h->pos = flint_malloc(h->cap*sizeof(h->pos)); + h->val = flint_malloc(h->cap*sizeof(h->val)); + h->num = h->max = 0; + h->cap = cap; +} + +void heap_clear(heap_t h) +{ + flint_free(h->idx); + flint_free(h->pos); + flint_free(h->val); + memset(h, 0, sizeof(*h)); +} + +slong heap_push(heap_t h, slong val) +{ + if(h->max == h->cap) + { + h->cap *= 2; + h->idx = flint_realloc(h->idx, h->cap*sizeof(h->idx)); + h->pos = flint_realloc(h->pos, h->cap*sizeof(h->pos)); + h->val = flint_realloc(h->val, h->cap*sizeof(h->val)); + } + h->idx[h->max] = h->max; + h->val[h->max] = val; + ++h->num; + _heap_up(h, h->max); + return h->max++; +} + +slong heap_pop(heap_t h, slong *val) +{ + slong idx = h->idx[0]; + if(val) *val = h->val[idx]; + h->pos[idx] = -1; + h->idx[0] = h->idx[--h->num]; + _heap_down(h, 0); + return idx; +} + +slong heap_adjust(heap_t h, slong idx, slong val) +{ + slong oval = h->val[idx], pos = h->pos[idx]; + h->val[idx] = val; + if (pos != -1) + { + if (oval < val) _heap_down(h, pos); + if (oval > val) _heap_up(h, pos); + } + return oval; +} diff --git a/heap.h b/heap.h new file mode 100644 index 0000000000..b98fb5e74d --- /dev/null +++ b/heap.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef HEAP_H +#define HEAP_H + +#include "flint.h" + +#define MIN_HEAP_CAP 32 + +typedef struct +{ + slong *idx; /* Heap of indices */ + slong *pos; /* Inverse of idx (map from index to heap position) */ + slong *val; /* Map from index to values */ + slong num; /* Number of elements in heap */ + slong max; /* Largest index in heap */ + slong cap; /* Capacity of heap */ +} heap_struct; + +typedef heap_struct heap_t[1]; + +/* Initialize heap with initial capacity cap */ +void heap_init(heap_t h, slong cap); + +/* Free heap contents */ +void heap_clear(heap_t h); + +/* Push new score onto heap, returning assigned index */ +/* Note: if want to re-insert a current element with */ +/* new score, use heap_adjust instead */ +slong heap_push(heap_t h, slong val); + +/* Pop element with minimal score from heap */ +slong heap_pop(heap_t h, slong *val); + +/* Modify score of existing element in heap */ +slong heap_adjust(heap_t h, slong idx, slong val); + +#endif \ No newline at end of file diff --git a/mpoly/compose_mat.c b/mpoly/compose_mat.c index a90b9b1c1f..fa335700f9 100644 --- a/mpoly/compose_mat.c +++ b/mpoly/compose_mat.c @@ -11,17 +11,6 @@ #include "mpoly.h" -/* unfortunate function missing from fmpz_mat */ -void fmpz_mat_mul_vec(fmpz * v, const fmpz_mat_t M, fmpz * u) -{ - slong i; - slong r = fmpz_mat_nrows(M); - slong c = fmpz_mat_ncols(M); - - for (i = 0; i < r; i++) - _fmpz_vec_dot(v + i, M->rows[i], u, c); -} - /* Fill the compose matrix for the T_mpoly_compose_T_mpoly_gen functions */ void mpoly_compose_mat_gen(fmpz_mat_t M, const slong * c, const mpoly_ctx_t mctxB, const mpoly_ctx_t mctxAC) diff --git a/nmod_mat.h b/nmod_mat.h index c1190a5c72..9ed0a797fb 100644 --- a/nmod_mat.h +++ b/nmod_mat.h @@ -192,6 +192,13 @@ void nmod_mat_scalar_mul_fmpz(nmod_mat_t res, const nmod_mat_t M, const fmpz_t c /* Matrix multiplication */ +NMOD_MAT_INLINE +void nmod_mat_mul_vec(mp_ptr y, const nmod_mat_t A, mp_srcptr x) { + slong i; + slong limbs = _nmod_vec_dot_bound_limbs(A->c, A->mod); + for(i=0; ir; ++i) + y[i] = _nmod_vec_dot(A->rows[i], x, A->c, A->mod, limbs); +} FLINT_DLL void nmod_mat_mul(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B); FLINT_DLL int nmod_mat_mul_blas(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B); diff --git a/nmod_mat/one.c b/nmod_mat/one.c index 700a54c21f..cb626b06dc 100644 --- a/nmod_mat/one.c +++ b/nmod_mat/one.c @@ -22,6 +22,6 @@ nmod_mat_one(nmod_mat_t mat) slong i,j; for(i = 0; i < mat->r; i++) for(j = 0; j < mat->c; j++) - if(i==j) nmod_mat_entry(mat, i, j) = 1; + if(i == j) nmod_mat_entry(mat, i, j) = 1; else nmod_mat_entry(mat, i, j) = 0; } diff --git a/nmod_sparse_mat.h b/nmod_sparse_mat.h new file mode 100644 index 0000000000..4e1a913cf4 --- /dev/null +++ b/nmod_sparse_mat.h @@ -0,0 +1,464 @@ +/* + Copyright (C) 2010 William Hart + Copyright (C) 2010,2011 Fredrik Johansson + Copyright (C) 2014 Ashish Kedia + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef NMOD_SPARSE_MAT_H +#define NMOD_SPARSE_MAT_H + +#ifdef NMOD_SPARSE_MAT_INLINES_C +#define NMOD_SPARSE_MAT_INLINE FLINT_DLL +#else +#define NMOD_SPARSE_MAT_INLINE static __inline__ +#endif + +#undef ulong +#define ulong ulongxx /* interferes with system includes */ +#include +#undef ulong +#include +#define ulong mp_limb_t + +#include "flint.h" +#include "ulong_extras.h" +#include "nmod_vec.h" +#include "nmod_sparse_vec.h" +#include "nmod_mat.h" +#include "fmpz.h" +#include "thread_support.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* A sparse matrix is a list of sparse vectors */ +typedef struct +{ + nmod_sparse_vec_struct *rows; + slong r; + slong c; + slong c_off; + nmod_t mod; +} +nmod_sparse_mat_struct; + +typedef nmod_sparse_mat_struct nmod_sparse_mat_t[1]; + +/* Memory management */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_init(nmod_sparse_mat_t M, slong rows, slong cols, nmod_t mod) +{ + FLINT_ASSERT(rows >= 0 && cols >= 0); + M->rows = flint_calloc(rows, sizeof(*M->rows)); + M->r = rows; + M->c = cols; + M->c_off = 0; + M->mod = mod; +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_clear(nmod_sparse_mat_t M) +{ + slong i; + for (i = 0; i < M->r; ++i) nmod_sparse_vec_clear(&M->rows[i]); + flint_free(M->rows); + memset(M, 0, sizeof(*M)); +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_resize (nmod_sparse_mat_t M, slong rows, slong cols) +{ + slong i; + FLINT_ASSERT(rows >= 0 && cols >= 0); + if (M->r != rows) { + if (M->r > rows) + { + for (i = rows; i < M->r; ++i) + { + nmod_sparse_vec_clear(&M->rows[i]); + } + } + M->rows = flint_realloc(M->rows, rows*sizeof(*M->rows)); + if (M->r < rows) + { + memset(M->rows+M->r, 0, (rows-M->r)*sizeof(*M->rows)); + } + M->r = rows; + } + if (cols < M->c) + { + for (i = 0; i < M->r; ++i) + { + nmod_sparse_vec_resize(&M->rows[i], cols); + } + } + M->c = cols; +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_swap(nmod_sparse_mat_t M1, nmod_sparse_mat_t M2) +{ + nmod_sparse_mat_t tmp; + *tmp = *M1; *M1 = *M2; *M2 = *tmp; +} + +/* One-time instantiation */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_zero(nmod_sparse_mat_t M) +{ + slong i; + for (i = 0; i < M->r; ++i) nmod_sparse_vec_zero(&M->rows[i]); +} +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_one(nmod_sparse_mat_t M) +{ + slong i; + for (i = 0; i < M->r; ++i) nmod_sparse_vec_one(&M->rows[i], i); +} + +/* One-time instantiation */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_set(nmod_sparse_mat_t M, const nmod_sparse_mat_t src) +{ + slong i, rmax = FLINT_MIN(M->r, src->r); + if (M==src || M->r == 0) return; + for (i = 0; i < rmax; ++i) nmod_sparse_vec_set(&M->rows[i], &src->rows[i], src->c_off); +} + +FLINT_DLL +void nmod_sparse_mat_from_entries(nmod_sparse_mat_t M, slong * rows, slong * cols, mp_limb_t * vals, slong nnz); + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_append_col(nmod_sparse_mat_t M, mp_srcptr v) +{ + slong i; + for (i = 0; i < M->r; ++i) nmod_sparse_vec_set_entry(&M->rows[i], M->c, v[i]); + M->c += 1; +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_append_row(nmod_sparse_mat_t M, const nmod_sparse_vec_t v) +{ + M->rows = realloc(M->rows, (M->r+1)*sizeof(*M->rows)); + memset(M->rows + M->r, 0, sizeof(*M->rows)); + nmod_sparse_vec_set(&M->rows[M->r], v, 0); + M->r += 1; +} + +/* Convert from/to dense matrix */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_from_dense(nmod_sparse_mat_t M, const nmod_mat_t dM) +{ + slong i, rmax = FLINT_MIN(M->r, dM->r); + for (i = 0; i < rmax; ++i) nmod_sparse_vec_from_dense(&M->rows[i], dM->rows[i], dM->c); +} +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_to_dense(nmod_mat_t dM, const nmod_sparse_mat_t M) +{ + slong i, rmax = FLINT_MIN(M->r, dM->r); + for (i = 0; i < rmax; ++i) nmod_sparse_vec_to_dense(dM->rows[i], &M->rows[i], dM->c); +} + +/* Windows, concatenation, and splitting */ +FLINT_DLL +void nmod_sparse_mat_window_init(nmod_sparse_mat_t W, const nmod_sparse_mat_t M, slong r1, slong c1, slong r2, slong c2); + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_window_clear(nmod_sparse_mat_t W) +{ + flint_free(W->rows); + memset(W, 0, sizeof(*W)); +} + + +/* Combine M1 and M2 into block matrix B = [M1 M2] */ +/* B->r must equal M1->r and M2->r */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_concat_horizontal(nmod_sparse_mat_t B, + const nmod_sparse_mat_t M1, const nmod_sparse_mat_t M2) +{ + slong i; + B->c = M1->c + M2->c; + for (i = 0; i < B->r; ++i) + nmod_sparse_vec_concat(&B->rows[i], &M1->rows[i], &M2->rows[i], M1->c); +} +/* Combine M1 and M2 into block matrix B = [M1^t M1^t]^t */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_concat_vertical(nmod_sparse_mat_t B, const nmod_sparse_mat_t M1, const nmod_sparse_mat_t M2) +{ + slong i; + B->c = FLINT_MAX(M1->c, M2->c); + for (i = 0; i < M1->r; ++i) + nmod_sparse_vec_set(&B->rows[i], &M1->rows[i], M1->c_off); + for (i = M1->r; i < B->r; ++i) + nmod_sparse_vec_set(&B->rows[i], &M2->rows[i-M1->r], M2->c_off); +} + +/* Split block matrix B = [M1 M2] into submatrices M1 and M2 */ +/* M1->r and M2->r must equal B->r */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_split_horizontal(nmod_sparse_mat_t M1, nmod_sparse_mat_t M2, const nmod_sparse_mat_t B, slong c) +{ + slong i; + for (i = 0; i < B->r; ++i) nmod_sparse_vec_split(&M1->rows[i], &M2->rows[i], &B->rows[i], c); +} + +/* Split block matix B = [M1^t M1^t]^t into submatrices M1 and M2 */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_split_vertical(nmod_sparse_mat_t M1, nmod_sparse_mat_t M2, const nmod_sparse_mat_t B, slong r) +{ + slong i; + r = FLINT_MIN(r, B->r); + for (i = 0; i < r; ++i) nmod_sparse_vec_set(&M1->rows[i], &B->rows[i], B->c_off); + for (i = r; i < B->r; ++i) nmod_sparse_vec_set(&M2->rows[i-r], &B->rows[i], B->c_off); +} + +/* Matrix permutation */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_permute_cols(nmod_sparse_mat_t M, slong *Q) +{ + slong i; + for (i = 0; i < M->r; ++i) + { + if (!M->rows[i].nnz) continue; + nmod_sparse_vec_permute_inds(&M->rows[i], Q); + qsort(M->rows[i].entries, M->rows[i].nnz, sizeof(*M->rows[i].entries), nmod_sparse_entry_cmp); + } +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_permute_rows(nmod_sparse_mat_t M, slong *P) +{ + slong i; + nmod_sparse_vec_struct *prows; + prows = flint_calloc(M->r, sizeof(*prows)); + for (i = 0; i < M->r; ++i) prows[P[i]] = M->rows[i]; + memcpy(M->rows, prows, M->r*sizeof(*M->rows)); + flint_free(prows); +} + +/* Random matrix generation */ +FLINT_DLL void nmod_sparse_mat_randtest(nmod_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz); +/* +FLINT_DLL void nmod_sparse_mat_randfull(nmod_sparse_mat_t M, flint_rand_t state); +FLINT_DLL int nmod_sparse_mat_randpermdiag(nmod_sparse_mat_t M, flint_rand_t state, + mp_srcptr diag, slong n); +FLINT_DLL void nmod_sparse_mat_randrank(nmod_sparse_mat_t, flint_rand_t state, slong rank); +FLINT_DLL void nmod_sparse_mat_randops(nmod_sparse_mat_t M, slong count, flint_rand_t state); +FLINT_DLL void nmod_sparse_mat_randtril(nmod_sparse_mat_t M, flint_rand_t state, int unit); +FLINT_DLL void nmod_sparse_mat_randtriu(nmod_sparse_mat_t M, flint_rand_t state, int unit); + */ + +FLINT_DLL void nmod_sparse_mat_print_pretty(const nmod_sparse_mat_t M); + +NMOD_SPARSE_MAT_INLINE +int nmod_sparse_mat_equal(const nmod_sparse_mat_t M1, const nmod_sparse_mat_t M2) +{ + slong i; + if (M1->r != M2->r) return 0; + for (i = 0; i < M1->r; ++i) + if (nmod_sparse_vec_equal(&M1->rows[i], &M2->rows[i], M1->c_off-M2->c_off) == 0) return 0; + return 1; +} + +NMOD_SPARSE_MAT_INLINE +int nmod_sparse_mat_is_zero(const nmod_sparse_mat_t M) +{ + slong i; + for (i = 0; i < M->r; ++i) + if (!nmod_sparse_vec_is_zero(&M->rows[i])) return 0; + return 1; +} + +NMOD_SPARSE_MAT_INLINE +int nmod_sparse_mat_is_square(const nmod_sparse_mat_t M) +{ + return (M->r == M->c); +} + +/* Must have M->r == N->c and M->c == N->r */ +FLINT_DLL void nmod_sparse_mat_transpose(nmod_sparse_mat_t N, const nmod_sparse_mat_t M); + +/* Arithmetic */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_neg(nmod_sparse_mat_t N, const nmod_sparse_mat_t M) +{ + slong i; + FLINT_ASSERT(M->r == N->r); + nmod_sparse_mat_set(N, M); + for (i = 0; i < N->r; ++i) nmod_sparse_vec_neg(&N->rows[i], &N->rows[i], N->mod); +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_scalar_mul_nmod(nmod_sparse_mat_t N, const nmod_sparse_mat_t M, mp_limb_t c) +{ + FLINT_ASSERT(M->r == N->r); + if (c == UWORD(0)) nmod_sparse_mat_zero(N); + else { + slong i; + nmod_sparse_mat_set(N, M); + for (i = 0; i < N->r; ++i) nmod_sparse_vec_scalar_mul_nmod(&N->rows[i], &N->rows[i], c, N->mod); + } +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_scalar_mul_fmpz(nmod_sparse_mat_t N, const nmod_sparse_mat_t M, const fmpz_t c) +{ + fmpz_t d; + FLINT_ASSERT(M->r == N->r); + fmpz_init(d); + fmpz_mod_ui(d, c, N->mod.n); + nmod_sparse_mat_scalar_mul_nmod(N, M, fmpz_get_ui(d)); + fmpz_clear(d); +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_add(nmod_sparse_mat_t O, const nmod_sparse_mat_t M, const nmod_sparse_mat_t N) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) nmod_sparse_vec_add(&O->rows[i], &M->rows[i], &N->rows[i], O->mod); +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_sub(nmod_sparse_mat_t O, const nmod_sparse_mat_t M, const nmod_sparse_mat_t N) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) nmod_sparse_vec_sub(&O->rows[i], &M->rows[i], &N->rows[i], O->mod); +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_scalar_addmul_nmod(nmod_sparse_mat_t O, const nmod_sparse_mat_t M, const nmod_sparse_mat_t N, mp_limb_t c) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) nmod_sparse_vec_scalar_addmul_nmod(&O->rows[i], &M->rows[i], &N->rows[i], c, O->mod); +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_scalar_submul_nmod(nmod_sparse_mat_t O, const nmod_sparse_mat_t M, const nmod_sparse_mat_t N, mp_limb_t c) +{ + slong i; + FLINT_ASSERT(O->r == M->r && O->r == N->r); + for (i = 0; i < O->r; ++i) nmod_sparse_vec_scalar_submul_nmod(&O->rows[i], &M->rows[i], &N->rows[i], c, O->mod); +} + +/* Matrix-vector and matrix-matrix multipliciation */ +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_mul_vec(mp_ptr y, const nmod_sparse_mat_t M, mp_srcptr x) +{ + slong i; + for (i = 0; i < M->r; ++i) y[i] = nmod_sparse_vec_dot_dense(&M->rows[i], x, M->mod); +} + +NMOD_SPARSE_MAT_INLINE +void nmod_sparse_mat_mul_mat(nmod_mat_t Y, const nmod_sparse_mat_t M, const nmod_mat_t X) +{ + slong i, j; + FLINT_ASSERT(M->r == Y->r && M->c == X->r && X->c == Y->c); + nmod_mat_zero(Y); + for (i = 0; i < M->r; ++i) + { + for (j = 0; j < M->rows[i].nnz; ++j) + { + nmod_sparse_entry_struct *e = &M->rows[i].entries[j]; + _nmod_vec_scalar_addmul_nmod(Y->rows[i], X->rows[e->ind], X->c, e->val, Y->mod); + } + } +} + +/* Permutations */ +/* FLINT_DLL void nmod_sparse_mat_swap_rows(nmod_sparse_mat_t M, slong * perm, slong r, slong s); +FLINT_DLL void nmod_sparse_mat_invert_rows(nmod_sparse_mat_t M, slong * perm); +FLINT_DLL void nmod_sparse_mat_swap_cols(nmod_sparse_mat_t M, slong * perm, slong r, slong s); +FLINT_DLL void nmod_sparse_mat_invert_cols(nmod_sparse_mat_t M, slong * perm); +FLINT_DLL void nmod_sparse_mat_apply_permutation(nmod_sparse_mat_t M, slong * P, slong n); + */ +FLINT_DLL +slong nmod_sparse_mat_inv(nmod_sparse_mat_t Ai, const nmod_sparse_mat_t M); + +/* Decomposition/reduction */ +FLINT_DLL +slong nmod_sparse_mat_lu(slong *P, slong *Q, nmod_sparse_mat_t L, nmod_sparse_mat_t U, const nmod_sparse_mat_t M); + +FLINT_DLL +slong nmod_sparse_mat_rref(nmod_sparse_mat_t M); + +NMOD_SPARSE_MAT_INLINE +slong nmod_sparse_mat_strong_echelon_form(nmod_sparse_mat_t M) +{ + /* TODO */ + return 0; +} + +/* Solve Ax = b */ +FLINT_DLL +int nmod_sparse_mat_solve_lanczos(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b, flint_rand_t state); + +FLINT_DLL +int nmod_sparse_mat_solve_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b); + +FLINT_DLL +int nmod_sparse_mat_solve_lu(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b); + +FLINT_DLL +int nmod_sparse_mat_solve_rref(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b); + +FLINT_DLL +int nmod_sparse_mat_solve_block_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b, slong block_size, flint_rand_t state); + +FLINT_DLL +int nmod_sparse_mat_solve_block_lanczos(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b, slong block_size, flint_rand_t state); + +/* Find single nullvector */ +FLINT_DLL +int nmod_sparse_mat_nullvector_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, flint_rand_t state); + +FLINT_DLL +int nmod_sparse_mat_nullvector_lanczos(mp_ptr x, const nmod_sparse_mat_t M, flint_rand_t state); + +FLINT_DLL +int nmod_sparse_mat_nullvector_block_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state); + +FLINT_DLL +int nmod_sparse_mat_nullvector_block_lanczos(mp_ptr x, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state); + +/* Note: this should take in uninitialized matrix X */ +FLINT_DLL +slong nmod_sparse_mat_nullspace_lanczos(nmod_mat_t X, const nmod_sparse_mat_t M, flint_rand_t state, slong max_iters); + +FLINT_DLL +slong nmod_sparse_mat_nullspace_block_lanczos(nmod_mat_t X, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state, slong max_iters); + +FLINT_DLL +slong nmod_sparse_mat_nullspace_wiedemann(nmod_mat_t X, const nmod_sparse_mat_t M, flint_rand_t state, slong max_iters); + +FLINT_DLL +slong nmod_sparse_mat_nullspace_block_wiedemann(nmod_mat_t X, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state, slong max_iters); + +FLINT_DLL +slong nmod_sparse_mat_nullspace_rref(nmod_mat_t X, const nmod_sparse_mat_t M); + +FLINT_DLL +slong nmod_sparse_mat_nullspace_lu(nmod_mat_t X, const nmod_sparse_mat_t M); + +/* Determinant */ +FLINT_DLL +mp_limb_t nmod_sparse_mat_det(const nmod_sparse_mat_t M); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nmod_sparse_mat/det.c b/nmod_sparse_mat/det.c new file mode 100644 index 0000000000..1b8b7e7c03 --- /dev/null +++ b/nmod_sparse_mat/det.c @@ -0,0 +1,57 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "flint.h" +#include "ulong_extras.h" +#include "nmod_sparse_mat.h" +#include "perm.h" + +mp_limb_t +nmod_sparse_mat_det(const nmod_sparse_mat_t M) +{ + slong rank, i; + slong *P, *Q; + mp_limb_t det; + nmod_sparse_mat_t L, U; + FLINT_ASSERT(M->r == M->c); + + if (M->r == 0) return UWORD(1); + if (nmod_sparse_mat_is_zero(M)) return UWORD(0); + if (M->r == 1) return M->rows[0].entries[0].val; + + + P = flint_malloc(M->r*sizeof(*P)); + Q = flint_malloc(M->c*sizeof(*P)); + nmod_sparse_mat_init(L, M->r, M->c, M->mod); + nmod_sparse_mat_init(U, M->r, M->c, M->mod); + rank = nmod_sparse_mat_lu(P, Q, L, U, M); + + det = UWORD(0); + + if (rank == M->r) + { + det = UWORD(1); + for (i = 0; i < M->r; i++) + det = n_mulmod2_preinv(det, U->rows[i].entries[0].val, M->mod.n, M->mod.ninv); + if ((_perm_parity(P, M->r) == 1) ^ (_perm_parity(Q, M->c) == 1)) + det = nmod_neg(det, M->mod); + } + + flint_free(P); + flint_free(Q); + nmod_sparse_mat_clear(L); + nmod_sparse_mat_clear(U); + + return det; +} diff --git a/nmod_sparse_mat/from_entries.c b/nmod_sparse_mat/from_entries.c new file mode 100644 index 0000000000..96f1cc5952 --- /dev/null +++ b/nmod_sparse_mat/from_entries.c @@ -0,0 +1,28 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" + +void nmod_sparse_mat_from_entries(nmod_sparse_mat_t M, slong * rows, slong * cols, mp_limb_t * vals, slong nnz) +{ + slong r, i, j; + for (r = i = 0; r < M->r; ++r, i = j) + { + M->rows[r].nnz = 0; + for (j = i; j < nnz && rows[j]==r; ++j); + nmod_sparse_vec_from_entries(&M->rows[r], cols+i, vals+i, j-i); + } +} diff --git a/nmod_sparse_mat/howell_form.c b/nmod_sparse_mat/howell_form.c new file mode 100644 index 0000000000..cba8fc4bce --- /dev/null +++ b/nmod_sparse_mat/howell_form.c @@ -0,0 +1,38 @@ +/* + Copyright (C) 2015 Tommy Hofmann + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +slong +nmod_sparse_mat_howell_form(nmod_sparse_mat_t M) +{ +slong i, *P, rank = 0, remr = M->r; + + if (nmod_sparse_mat_is_zero(M)) return 0; + + nmod_sparse_mat_strong_echelon_form(M); + P = flint_malloc(M->r*sizeof(*P)); + for (i = 0; i < M->r; ++i) + { + if (M->rows[i].nnz > 0) P[i] = rank++; + else P[i] = --remr; + } + /* Apply row permutation */ + nmod_sparse_mat_permute_rows (M, P); + flint_free(P); + return rank; +} + diff --git a/nmod_sparse_mat/inv.c b/nmod_sparse_mat/inv.c new file mode 100644 index 0000000000..b6737d0459 --- /dev/null +++ b/nmod_sparse_mat/inv.c @@ -0,0 +1,38 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" +slong nmod_sparse_mat_inv(nmod_sparse_mat_t Mi, const nmod_sparse_mat_t M) +{ + slong rk; + nmod_sparse_mat_t I, MI; + + /* Create block matrix [M | I] */ + nmod_sparse_mat_init(I, M->r, M->r, M->mod); + nmod_sparse_mat_one(I); + nmod_sparse_mat_init(MI, M->r, M->r + M->c, M->mod); + nmod_sparse_mat_concat_horizontal(MI, M, I); + + /* Run Gaussian elimination on first half */ + MI->c = M->c; + rk = nmod_sparse_mat_rref(MI); + MI->c = M->c+M->r; + nmod_sparse_mat_split_horizontal(I, Mi, MI, M->c); + nmod_sparse_mat_clear(I); + nmod_sparse_mat_clear(MI); + return rk; +} diff --git a/nmod_sparse_mat/lu.c b/nmod_sparse_mat/lu.c new file mode 100644 index 0000000000..125cfcc23b --- /dev/null +++ b/nmod_sparse_mat/lu.c @@ -0,0 +1,173 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +static void heap_up(slong *heap, slong *heap_idx, slong *scores, slong pos) +{ + const slong c = heap[pos]; + slong nc, npos; + for (; pos > 0; pos = npos) + { + npos = (pos-1)/2; + nc = heap[npos]; + if (scores[c] >= scores[nc]) break; + + heap[pos] = nc; + heap_idx[nc] = pos; + } + heap[pos] = c; + heap_idx[c] = pos; +} + +static void heap_down(slong *heap, slong *heap_idx, slong *scores, slong size, slong pos) +{ + const slong c = heap[pos]; + slong nc, npos; + for (; pos < (size-1)/2; pos = npos) + { + npos = 2*pos+1; + if (npos+1 < size && scores[heap[npos]] > scores[heap[npos+1]]) ++npos; + nc = heap[npos]; + if (scores[c] <= scores[nc]) break; + + heap[pos] = nc; + heap_idx[nc] = pos; + } + heap[pos] = c; + heap_idx[c] = pos; +} + +/* static void print_heap(slong *heap, slong *scores, slong size) +{ + slong level, i; + for (level = 1; level <= size; level<<=1) + { + for (i = level; i <= size && i < 2*level; ++i) + { + flint_printf("%wd:%wd,%wd\t", i-1, heap[i-1], scores[heap[i-1]]); + } + flint_printf("\n"); + } +} + */ +slong nmod_sparse_mat_lu(slong *P, slong *Q, + nmod_sparse_mat_t L, nmod_sparse_mat_t U, + const nmod_sparse_mat_t M) +{ + slong i, j, r, c, pr, pc, rank, remr, remc; + slong *heap, *heap_idx, *scores, heap_size; + nmod_sparse_mat_t Lt; + nmod_sparse_vec_struct *pcol, *prow, *row, *col; + mp_limb_t cinv, cc; + + if (M->r == 0 || M->c == 0) + { + nmod_sparse_mat_zero(L); + nmod_sparse_mat_zero(U); + for (i = 0; i < M->r; ++i) P[i] = i; + for (i = 0; i < M->c; ++i) Q[i] = i; + return 0; + } + nmod_sparse_mat_init(Lt, L->c, L->r, M->mod); + nmod_sparse_mat_transpose(Lt, M); + nmod_sparse_mat_set(U, M); + + /* Set up permutations */ + remr = M->r, remc = M->c; + for (r = 0; r < M->r; ++r) + { + if (!U->rows[r].nnz) P[r] = --remr; + else P[r] = -1; + } + for (c = 0; c < M->c; ++c) + { + if (!Lt->rows[c].nnz) Q[c] = --remc; + else Q[c] = -1; + } + + /* Make heap of nonzero columns by size */ + heap_size = M->c; + heap = flint_malloc(M->c*sizeof(*heap)); + scores = flint_malloc(M->c*sizeof(*scores)); + heap_idx = flint_malloc(M->c*sizeof(*heap_idx)); + for (i = 0; i < M->c; ++i) + { + scores[i] = Lt->rows[i].nnz; /* TODO: randomized tiebreaker */ + heap[i] = i; + heap_up(heap, heap_idx, scores, i); + } + /* Run elimination */ + rank = 0; + for (heap_size = M->c; heap_size > 0; ) + { + /* Get lowest weight column (top of heap) */ + pc = heap[0]; + pcol = &Lt->rows[pc]; + heap[0] = heap[--heap_size]; + heap_down(heap, heap_idx, scores, heap_size, 0); + if (pcol->nnz == 0) continue; /* Empty columns already dealt with */ + Q[pc] = rank; /* Move pivot column to front */ + + /* Get lowest weight incident row */ + pr = pcol->entries[0].ind, prow = &U->rows[pr]; + for (j = 1; j < pcol->nnz; ++j) + { + r = pcol->entries[j].ind, row = &U->rows[r]; + if (row->nnz < prow->nnz) pr = r, prow = row; + } + P[pr] = rank; /* Move pivot row to front */ + + /* Invert pivot */ + cinv = nmod_inv(*nmod_sparse_vec_at(prow, pc), M->mod); + + /* Gaussian eliminate rows */ + for (j = 0; j < pcol->nnz; ++j) + { + r = pcol->entries[j].ind, row = &U->rows[r]; + if (P[r] >= 0) continue; /* Skip previous pivot rows */ + cc = nmod_neg(nmod_mul(cinv, *nmod_sparse_vec_at(row, pc), M->mod), M->mod); + nmod_sparse_vec_scalar_addmul_nmod(row, row, prow, cc, M->mod); + if (row->nnz == 0) P[r] = --remr; + } + /* Gaussian eliminate cols */ + nmod_sparse_vec_scalar_mul_nmod(pcol, pcol, cinv, M->mod); + for (j = 0; j < prow->nnz; ++j) + { + c = prow->entries[j].ind, col = &Lt->rows[c]; + if (Q[c] >= 0) continue; /* Skip previous pivot columns */ + cc = nmod_neg(*nmod_sparse_vec_at(col, pr), M->mod); + nmod_sparse_vec_scalar_addmul_nmod(col, col, pcol, cc, M->mod); + if (col->nnz == 0) Q[c] = --remc; + scores[c] = col->nnz; + heap_up(heap, heap_idx, scores, heap_idx[c]); + heap_down(heap, heap_idx, scores, heap_size, heap_idx[c]); + + } + rank += 1; + } + /* Transpose L^t */ + nmod_sparse_mat_transpose(L, Lt); + nmod_sparse_mat_clear(Lt); + + /* Reorder rows and cols in L and U */ + nmod_sparse_mat_permute_cols(L, Q); + nmod_sparse_mat_permute_rows(L, P); + nmod_sparse_mat_permute_cols(U, Q); + nmod_sparse_mat_permute_rows(U, P); + return rank; +} diff --git a/nmod_sparse_mat/nullspace_block_lanczos.c b/nmod_sparse_mat/nullspace_block_lanczos.c new file mode 100644 index 0000000000..8a7f578b9f --- /dev/null +++ b/nmod_sparse_mat/nullspace_block_lanczos.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +slong nmod_sparse_mat_nullspace_block_lanczos(nmod_mat_t X, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state, slong max_iters) +{ + /* Generate random solutions to a random system Mx = b and stop when nullspace filled */ + slong i, j, iter, nxs, *xps; + mp_ptr x, *xs; + x = _nmod_vec_init(M->c); + nxs = 0; + xs = NULL; + xps = NULL; + for (iter = 0; iter < max_iters; ) + { + if (nmod_sparse_mat_nullvector_block_lanczos(x, M, block_size, state) == 0) {++iter; continue;} + + /* Reduce by existing kernel vectors */ + for (j = nxs-1; j >= 0; --j) + { + _nmod_vec_scalar_addmul_nmod(x, xs[j], M->c, nmod_neg(x[xps[j]], M->mod), M->mod); + } + + /* Normalize last nonzero entry to 1 */ + for (i = M->c-1; i >= 0 && x[i] == UWORD(0); --i); + if (i == -1) {++iter; continue;} /* x in span of xs, nullspace probably complete */ + _nmod_vec_scalar_mul_nmod(x, x, M->c, nmod_inv(x[i], M->mod), M->mod); + + /* Reduce previous vectors by this one */ + for (j = 0; j < nxs; ++j) + { + _nmod_vec_scalar_addmul_nmod(xs[j], x, M->c, nmod_neg(xs[j][i], M->mod), M->mod); + } + + /* Insert into list of vectors in nullspace (ordered by pivot) */ + xs = realloc(xs, (nxs+1)*sizeof(*xs)); + xps = realloc(xps, (nxs+1)*sizeof(*xps)); + for (j = 0; j < nxs && i > xps[j]; ++j); + memmove(xs + j + 1, xs + j, (nxs - j)*sizeof(*xs)); + memmove(xps + j + 1, xps + j, (nxs - j)*sizeof(*xps)); + xps[j] = i; + xs[j] = x; + nxs += 1; + x = _nmod_vec_init(M->c); /* New vector for next iteration */ + iter = 0; + } + flint_free(xps); + flint_free(x); + nmod_mat_init(X, M->c, nxs, M->mod.n); + for (i = 0; i < nxs; ++i) + { + for (j = 0; j < M->c; ++j) + X->rows[j][i] = xs[i][j]; + flint_free(xs[i]); + } + flint_free(xs); + return X->c; +} diff --git a/nmod_sparse_mat/nullspace_block_wiedemann.c b/nmod_sparse_mat/nullspace_block_wiedemann.c new file mode 100644 index 0000000000..9ee3d8da43 --- /dev/null +++ b/nmod_sparse_mat/nullspace_block_wiedemann.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +slong nmod_sparse_mat_nullspace_block_wiedemann(nmod_mat_t X, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state, slong max_iters) +{ + /* Generate random solutions to a random system Mx = b and stop when nullspace filled */ + slong i, j, iter, nxs, *xps; + mp_ptr x, *xs; + x = _nmod_vec_init(M->c); + nxs = 0; + xs = NULL; + xps = NULL; + for (iter = 0; iter < max_iters; ) + { + if (nmod_sparse_mat_nullvector_block_wiedemann(x, M, block_size, state) == 0) {++iter; continue;} + + /* Reduce by existing kernel vectors */ + for (j = nxs-1; j >= 0; --j) + { + _nmod_vec_scalar_addmul_nmod(x, xs[j], M->c, nmod_neg(x[xps[j]], M->mod), M->mod); + } + + /* Normalize last nonzero entry to 1 */ + for (i = M->c-1; i >= 0 && x[i] == UWORD(0); --i); + if (i == -1) {++iter; continue;} /* x in span of xs, nullspace probably complete */ + _nmod_vec_scalar_mul_nmod(x, x, M->c, nmod_inv(x[i], M->mod), M->mod); + + /* Reduce previous vectors by this one */ + for (j = 0; j < nxs; ++j) + { + _nmod_vec_scalar_addmul_nmod(xs[j], x, M->c, nmod_neg(xs[j][i], M->mod), M->mod); + } + + /* Insert into list of vectors in nullspace (ordered by pivot) */ + xs = realloc(xs, (nxs+1)*sizeof(*xs)); + xps = realloc(xps, (nxs+1)*sizeof(*xps)); + for (j = 0; j < nxs && i > xps[j]; ++j); + memmove(xs + j + 1, xs + j, (nxs - j)*sizeof(*xs)); + memmove(xps + j + 1, xps + j, (nxs - j)*sizeof(*xps)); + xps[j] = i; + xs[j] = x; + nxs += 1; + x = _nmod_vec_init(M->c); /* New vector for next iteration */ + iter = 0; + } + flint_free(xps); + flint_free(x); + nmod_mat_init(X, M->c, nxs, M->mod.n); + for (i = 0; i < nxs; ++i) + { + for (j = 0; j < M->c; ++j) + X->rows[j][i] = xs[i][j]; + flint_free(xs[i]); + } + flint_free(xs); + return X->c; +} diff --git a/nmod_sparse_mat/nullspace_lanczos.c b/nmod_sparse_mat/nullspace_lanczos.c new file mode 100644 index 0000000000..0a69c496e2 --- /dev/null +++ b/nmod_sparse_mat/nullspace_lanczos.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +slong nmod_sparse_mat_nullspace_lanczos(nmod_mat_t X, const nmod_sparse_mat_t M, flint_rand_t state, slong max_iters) +{ + /* Generate random solutions to a random system Mx = b and stop when nullspace filled */ + slong i, j, iter, nxs, *xps; + mp_ptr x, *xs; + x = _nmod_vec_init(M->c); + nxs = 0; + xs = NULL; + xps = NULL; + for (iter = 0; iter < max_iters; ) + { + if (nmod_sparse_mat_nullvector_lanczos(x, M, state) == 0) {++iter; continue;} + + /* Reduce by existing kernel vectors */ + for (j = nxs-1; j >= 0; --j) + { + _nmod_vec_scalar_addmul_nmod(x, xs[j], M->c, nmod_neg(x[xps[j]], M->mod), M->mod); + } + + /* Normalize last nonzero entry to 1 */ + for (i = M->c-1; i >= 0 && x[i] == UWORD(0); --i); + if (i == -1) {++iter; continue;} /* x in span of xs, nullspace probably complete */ + _nmod_vec_scalar_mul_nmod(x, x, M->c, nmod_inv(x[i], M->mod), M->mod); + + /* Reduce previous vectors by this one */ + for (j = 0; j < nxs; ++j) + { + _nmod_vec_scalar_addmul_nmod(xs[j], x, M->c, nmod_neg(xs[j][i], M->mod), M->mod); + } + + /* Insert into list of vectors in nullspace (ordered by pivot) */ + xs = realloc(xs, (nxs+1)*sizeof(*xs)); + xps = realloc(xps, (nxs+1)*sizeof(*xps)); + for (j = 0; j < nxs && i > xps[j]; ++j); + memmove(xs + j + 1, xs + j, (nxs - j)*sizeof(*xs)); + memmove(xps + j + 1, xps + j, (nxs - j)*sizeof(*xps)); + xps[j] = i; + xs[j] = x; + nxs += 1; + x = _nmod_vec_init(M->c); /* New vector for next iteration */ + iter = 0; + } + flint_free(xps); + flint_free(x); + nmod_mat_init(X, M->c, nxs, M->mod.n); + for (i = 0; i < nxs; ++i) + { + for (j = 0; j < M->c; ++j) + X->rows[j][i] = xs[i][j]; + flint_free(xs[i]); + } + flint_free(xs); + return X->c; +} diff --git a/nmod_sparse_mat/nullspace_lu.c b/nmod_sparse_mat/nullspace_lu.c new file mode 100644 index 0000000000..0f26b407a4 --- /dev/null +++ b/nmod_sparse_mat/nullspace_lu.c @@ -0,0 +1,63 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +slong nmod_sparse_mat_nullspace_lu(nmod_mat_t X, const nmod_sparse_mat_t M) +{ + slong rk, *P, *Q, *Qi, i, j; + nmod_sparse_mat_t L, U; + nmod_sparse_entry_struct *e; + nmod_sparse_vec_struct *Urow; + mp_limb_t *Xrow; + P = flint_malloc(M->r * sizeof(*P)); + Q = flint_malloc(M->c * sizeof(*Q)); + nmod_sparse_mat_init(L, M->r, M->c, M->mod); + nmod_sparse_mat_init(U, M->r, M->c, M->mod); + rk = nmod_sparse_mat_lu(P, Q, L, U, M); + flint_free(P); + nmod_sparse_mat_clear(L); + for (i = 0; i < rk; ++i) + nmod_sparse_vec_scalar_mul_nmod(&U->rows[i], &U->rows[i], nmod_inv(U->rows[i].entries[0].val, M->mod), M->mod); + nmod_mat_init(X, M->c, M->c-rk, M->mod.n); + if (rk != M->c) + { + /* Invert permutation */ + Qi = flint_malloc(M->c * sizeof(*Qi)); + for (i = 0; i < M->c; ++i) Qi[Q[i]] = i; + + /* Mssign unit vectors to non-pivot columns */ + for (i = M->c-1; i >= rk; --i) X->rows[Qi[i]][i-rk] = 1; + for (i = rk-1; i >= 0; --i) + { + Urow = &U->rows[i]; + Xrow = X->rows[Qi[i]]; + for (j = 1; j < Urow->nnz; ++j) + { + e = &Urow->entries[j]; + /* Do in-place row elimination */ + if (e->ind < rk) _nmod_vec_scalar_addmul_nmod(Xrow, X->rows[Qi[e->ind]], X->c, nmod_neg(e->val, M->mod), M->mod); + else Xrow[e->ind-rk] = nmod_sub(Xrow[e->ind-rk], e->val, M->mod); + } + + } + flint_free(Qi); + } + flint_free(Q); + nmod_sparse_mat_clear(U); + return X->c; +} diff --git a/nmod_sparse_mat/nullspace_rref.c b/nmod_sparse_mat/nullspace_rref.c new file mode 100644 index 0000000000..17ea68ab3e --- /dev/null +++ b/nmod_sparse_mat/nullspace_rref.c @@ -0,0 +1,53 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +slong nmod_sparse_mat_nullspace_rref(nmod_mat_t X, const nmod_sparse_mat_t M) +{ + slong i, j, rk, numc, *Q; + nmod_sparse_mat_t R; + nmod_sparse_vec_struct *Rrow; + mp_limb_t *Xrow; + nmod_sparse_mat_init(R, M->r, M->c, M->mod); + nmod_sparse_mat_set(R, M); + rk = nmod_sparse_mat_rref(R); + nmod_mat_init(X, M->c, M->c-rk, M->mod.n); + if (rk != M->c) + { + numc = 0; + /* Mark which cols are pivots and enumerate the nonpivots */ + Q = flint_calloc(M->c, sizeof(*Q)); + for (i = 0; i < rk; ++i) + Q[R->rows[i].entries->ind] = -1; + for (i = 0; i < M->c; ++i) + if (Q[i]==UWORD(0)) Q[i] = numc++, X->rows[i][Q[i]] = 1; + + /* For each pivot col, set the corresponding row in X as */ + /* the negative of the associated row in R (reordered by Q) */ + for (i = 0; i < rk; ++i) + { + Rrow = &R->rows[i]; + Xrow = X->rows[Rrow->entries[0].ind]; + for (j = 1; j < Rrow->nnz; ++j) + Xrow[Q[Rrow->entries[j].ind]] = nmod_neg(Rrow->entries[j].val, M->mod); + } + flint_free(Q); + } + nmod_sparse_mat_clear(R); + return X->c; +} diff --git a/nmod_sparse_mat/nullspace_wiedemann.c b/nmod_sparse_mat/nullspace_wiedemann.c new file mode 100644 index 0000000000..83c65fef3d --- /dev/null +++ b/nmod_sparse_mat/nullspace_wiedemann.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +slong nmod_sparse_mat_nullspace_wiedemann(nmod_mat_t X, const nmod_sparse_mat_t M, flint_rand_t state, slong max_iters) +{ + /* Generate random solutions to a random system Mx = b and stop when nullspace filled */ + slong i, j, iter, nxs, *xps; + mp_ptr x, *xs; + x = _nmod_vec_init(M->c); + nxs = 0; + xs = NULL; + xps = NULL; + for (iter = 0; iter < max_iters; ) + { + if (nmod_sparse_mat_nullvector_wiedemann(x, M, state) == 0) {++iter; continue;} + + /* Reduce by existing kernel vectors */ + for (j = nxs-1; j >= 0; --j) + { + _nmod_vec_scalar_addmul_nmod(x, xs[j], M->c, nmod_neg(x[xps[j]], M->mod), M->mod); + } + + /* Normalize last nonzero entry to 1 */ + for (i = M->c-1; i >= 0 && x[i] == UWORD(0); --i); + if (i == -1) {++iter; continue;} /* x in span of xs, nullspace probably complete */ + _nmod_vec_scalar_mul_nmod(x, x, M->c, nmod_inv(x[i], M->mod), M->mod); + + /* Reduce previous vectors by this one */ + for (j = 0; j < nxs; ++j) + { + _nmod_vec_scalar_addmul_nmod(xs[j], x, M->c, nmod_neg(xs[j][i], M->mod), M->mod); + } + + /* Insert into list of vectors in nullspace (ordered by pivot) */ + xs = realloc(xs, (nxs+1)*sizeof(*xs)); + xps = realloc(xps, (nxs+1)*sizeof(*xps)); + for (j = 0; j < nxs && i > xps[j]; ++j); + memmove(xs + j + 1, xs + j, (nxs - j)*sizeof(*xs)); + memmove(xps + j + 1, xps + j, (nxs - j)*sizeof(*xps)); + xps[j] = i; + xs[j] = x; + nxs += 1; + x = _nmod_vec_init(M->c); /* New vector for next iteration */ + iter = 0; + } + flint_free(xps); + flint_free(x); + nmod_mat_init(X, M->c, nxs, M->mod.n); + for (i = 0; i < nxs; ++i) + { + for (j = 0; j < M->c; ++j) + X->rows[j][i] = xs[i][j]; + flint_free(xs[i]); + } + flint_free(xs); + return X->c; +} diff --git a/nmod_sparse_mat/print_pretty.c b/nmod_sparse_mat/print_pretty.c new file mode 100644 index 0000000000..9f058c764c --- /dev/null +++ b/nmod_sparse_mat/print_pretty.c @@ -0,0 +1,36 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +void +nmod_sparse_mat_print_pretty(const nmod_sparse_mat_t M) +{ + slong i; + char row_fmt[FLINT_BITS + 5]; + flint_sprintf(row_fmt, "%%%dwd: ", n_sizeinbase(M->r, 10)); + + flint_printf("<%wd x %wd sparse integer matrix mod %w>\n", + M->r, M->c, M->mod.n); + + for (i = 0; i < M->r; i++) + { + flint_printf(row_fmt, i); + nmod_sparse_vec_print_pretty(&M->rows[i], M->c_off, M->c, M->mod); + } +} + diff --git a/nmod_sparse_mat/randtest.c b/nmod_sparse_mat/randtest.c new file mode 100644 index 0000000000..3948ecfa7d --- /dev/null +++ b/nmod_sparse_mat/randtest.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" + +void +nmod_sparse_mat_randtest(nmod_sparse_mat_t M, flint_rand_t state, slong min_nnz, slong max_nnz) +{ + slong i, nnz; + + for (i = 0; i < M->r; ++i) + { + nnz = n_randint(state, max_nnz+1); + nnz = FLINT_MAX(nnz, min_nnz); + nmod_sparse_vec_randtest(&M->rows[i], state, nnz, M->c, M->mod); + } +} diff --git a/nmod_sparse_mat/rref.c b/nmod_sparse_mat/rref.c new file mode 100644 index 0000000000..7ddd7bbcde --- /dev/null +++ b/nmod_sparse_mat/rref.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +slong nmod_sparse_mat_rref(nmod_sparse_mat_t M) +{ + slong *P; + slong j, r, c, pr, pc, rank, remr; + nmod_sparse_mat_t Mt; + nmod_sparse_vec_struct *pcol, *prow, *row, *col; + mp_limb_t cinv, cc; + + if (M->r == 0 || M->c == 0) return 0; + nmod_sparse_mat_init(Mt, M->c, M->r, M->mod); + nmod_sparse_mat_transpose(Mt, M); + + /* Set up permutations */ + P = flint_malloc(M->r*sizeof(*P)); + remr = M->r; + for (r = 0; r < M->r; ++r) + { + if (!M->rows[r].nnz || M->rows[r].entries[0].ind >= M->c) P[r] = --remr; + else P[r] = -1; + } + + /* Run elimination */ + rank = 0; + for (pc = 0; pc < M->c; ++pc) + { + pcol = &Mt->rows[pc]; + + /* Get lowest weight incident row not used as previous pivot */ + pr = -1, prow = NULL; + for (j = 0; j < pcol->nnz; ++j) + { + r = pcol->entries[j].ind, row = &M->rows[r]; + if (P[r] >= 0) continue; + if (pr==-1 || (row->nnz < prow->nnz)) pr = r, prow = row; + } + if (pr == -1) continue; + P[pr] = rank; + + cinv = nmod_inv(*nmod_sparse_vec_at(prow, pc), M->mod); + nmod_sparse_vec_scalar_mul_nmod(prow, prow, cinv, M->mod); + + /* Gaussian eliminate rows */ + for (j = 0; j < pcol->nnz; ++j) + { + r = pcol->entries[j].ind, row = &M->rows[r]; + if (r==pr) {pcol->entries[j].val = UWORD(0); continue;} + + cc = nmod_neg(*nmod_sparse_vec_at(row, pc), M->mod); + nmod_sparse_vec_scalar_addmul_nmod(row, row, prow, cc, M->mod); + if (row->nnz == 0 || row->entries[0].ind >= M->c) P[r] = --remr; + } + /* Gaussian eliminate cols */ + nmod_sparse_vec_scalar_mul_nmod(pcol, pcol, cinv, M->mod); + for (j = 0; j < prow->nnz; ++j) + { + c = prow->entries[j].ind, col = &Mt->rows[c]; + if (c >= M->c || c==pc) continue; + cc = nmod_neg(*nmod_sparse_vec_at(col, pr), M->mod); + nmod_sparse_vec_scalar_addmul_nmod(col, col, pcol, cc, M->mod); + } + rank += 1; + } + nmod_sparse_mat_clear(Mt); + + /* Reorder rows */ + nmod_sparse_mat_permute_rows(M, P); + flint_free(P); + return rank; +} diff --git a/nmod_sparse_mat/solve_block_lanczos.c b/nmod_sparse_mat/solve_block_lanczos.c new file mode 100644 index 0000000000..402a8075e9 --- /dev/null +++ b/nmod_sparse_mat/solve_block_lanczos.c @@ -0,0 +1,261 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + Algorithm taken from P. Montgomery, "A Block Lanczos Algorithm for + Finding Dependencies over GF(2)", Advances in Cryptology - EUROCRYPT '95 + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" + +/* Run row Gaussian elimination on first b block of [T I], save that, */ +/* if no pivot is found for a given column c, we Gaussian eliminate */ +/* the column c + b and zero out the row c. In addition, we reorder */ +/* columns so that ones corresponding to zero entries in S go first. */ +/* See Figure 1 in the above reference for details. */ +static int compute_nWi_S(nmod_mat_t nWi, int *S, const nmod_mat_t Torig) +{ + + const slong b = Torig->r; + slong pc, i, j, rk = 0; + nmod_mat_t T; + nmod_mat_struct *X; + slong *P; + mp_limb_t cc; + + P = flint_malloc(b * sizeof(*P)); + nmod_mat_init(T, b, b, Torig->mod.n); + nmod_mat_set(T, Torig); + nmod_mat_one(nWi); + + /* Set permutation to have previously dependent vectors at front */ + P = flint_malloc(b*sizeof(*P)); + j = 0; + for (i = 0; i < b; ++i) if (!S[i]) P[j++] = i; + for (i = 0; i < b; ++i) if (S[i]) P[j++] = i; + + for (j = 0; j < b; ++j) + { + pc = P[j]; /* Pivot col */ + + /* Find viable pivot row (from T if possible, then from W) */ + for (X = T, i = j; i < b && X->rows[P[i]][pc] == 0; ++i); + if (i == b) + for (X = nWi, i = j; i < b && X->rows[P[i]][pc] == 0; ++i); + S[pc] = X == T; /* Viable column in V */ + nmod_mat_swap_rows(T, NULL, pc, P[i]); + nmod_mat_swap_rows(nWi, NULL, pc, P[i]); /* Now pivot row = pivot col */ + + /* Make pivot one */ + cc = nmod_inv(X->rows[pc][pc], T->mod); + _nmod_vec_scalar_mul_nmod(T->rows[pc], T->rows[pc], b, cc, T->mod); + _nmod_vec_scalar_mul_nmod(nWi->rows[pc], nWi->rows[pc], b, cc, T->mod); + + + /* Kill all other entries in pivot column */ + for (i = 0; i < b; ++i) + { + cc = nmod_neg(X->rows[P[i]][pc], T->mod); + if (i == j || cc == 0) continue; + _nmod_vec_scalar_addmul_nmod(T->rows[P[i]], T->rows[pc], T->c, cc, T->mod); + _nmod_vec_scalar_addmul_nmod(nWi->rows[P[i]], nWi->rows[pc], nWi->c, cc, T->mod); + } + if (S[pc]) rk++; /* Count viable columns */ + else + { + /* Kill row of both matrices */ + _nmod_vec_zero(T->rows[pc], b); + _nmod_vec_zero(nWi->rows[pc], b); + } + } + + nmod_mat_neg(nWi, nWi); + nmod_mat_clear(T); + + return rk; +} + +static void kill_columns(nmod_mat_t M, int *good) +{ + slong r, c; + for (c = 0; c < M->c; ++c) + if (good[c] == 0) + for (r = 0; r < M->r; ++r) + M->rows[r][c] = UWORD(0); +} + +int nmod_sparse_mat_solve_block_lanczos(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b, slong block_size, flint_rand_t state) +{ + int ret = 0; + slong i, prev_i, next_i, iter, cur_dim, total_dim = 0; + nmod_sparse_mat_t Mt; /* Transpose of M, we work with A = MtM */ + nmod_mat_struct V[3]; /* Keep track of current vector and two previous ones */ + nmod_mat_t MV; /* Application of M to V */ + nmod_mat_t AV; /* Application of Mt to MV */ + int *SSt; /* S is the maximal projection s.t. (VS)^tAVS is invertible, so SSt kills the dropped columns */ + nmod_mat_struct nWi[3]; /* -S((VS)^tAVS)^-1S^t */ + nmod_mat_t VSSt; /* V with invalid vectors zeroed out */ + nmod_mat_t T; /* Used to store transposes for inner products */ + nmod_mat_t VtAV; /* Inner product _A */ + nmod_mat_t AVtAVSSt_VtAV; /* Sum _A SS^t + _A, shared by two updates */ + nmod_mat_t DEF; /* Used to store coefficient matrices D, E, and F */ + nmod_mat_t I, tmp; /* I_{b x b}, tmp used as scratch */ + mp_ptr Mtb, SStVtMtb, WiSStVtMtb, VSStWiSStVtMtb; /* Intermediate elements in x update */ + + if (_nmod_vec_is_zero(b, M->r)) + { + _nmod_vec_zero(x, M->c); + return 1; + } + + nmod_sparse_mat_init(Mt, M->c, M->r, M->mod); + for (i = 0; i < 3; ++i) nmod_mat_init(&V[i], M->c, block_size, M->mod.n); + nmod_mat_init(MV, M->r, block_size, M->mod.n); /* Intermediate product */ + nmod_mat_init(AV, M->c, block_size, M->mod.n); /* Symmetric product */ + SSt = flint_malloc(block_size*sizeof(*SSt)); + for (i = 0; i < 3; ++i) nmod_mat_init(&nWi[i], block_size, block_size, M->mod.n); + nmod_mat_init(VSSt, M->c, block_size, M->mod.n); + nmod_mat_init(T, block_size, M->c, M->mod.n); /* Transpose for computing matrix dot products */ + nmod_mat_init(VtAV, block_size, block_size, M->mod.n); + nmod_mat_init(AVtAVSSt_VtAV, block_size, block_size, M->mod.n); /* (AV)^T(AV) + VtAV */ + nmod_mat_init(DEF, block_size, block_size, M->mod.n); /* Shared by D, E, and F */ + nmod_mat_init(I, block_size, block_size, M->mod.n); + nmod_mat_init(tmp, block_size, block_size, M->mod.n); + Mtb = _nmod_vec_init(M->c); + SStVtMtb = _nmod_vec_init(block_size); + WiSStVtMtb = _nmod_vec_init(block_size); + VSStWiSStVtMtb = _nmod_vec_init(M->c); + + _nmod_vec_zero(x, M->c); + nmod_sparse_mat_transpose(Mt, M); + for (i = 0; i < block_size; ++i) SSt[i] = 1; + nmod_mat_one(I); + nmod_sparse_mat_mul_vec(Mtb, Mt, b); + + /* Initialize V[0] randomly */ + for (i = 0; i < V[0].r*V[0].c; ++i) + V[0].entries[i] = n_randint(state, V[0].mod.n); + + for (iter = 0; ; ++iter) + { + i = iter % 3; + next_i = (iter + 1) % 3; + prev_i = (iter + 2) % 3; + if (iter >= 2) + { + /* Compute the F value for this round (minus the final term) */ + nmod_mat_addmul(DEF, I, VtAV, &nWi[prev_i]); + nmod_mat_mul(tmp, &nWi[next_i], DEF); + nmod_mat_mul(DEF, tmp, AVtAVSSt_VtAV); + } + + /* Compute AV and V'AV */ + nmod_sparse_mat_mul_mat(MV, M, &V[i]); + nmod_sparse_mat_mul_mat(AV, Mt, MV); + nmod_mat_transpose(T, &V[i]); + nmod_mat_mul(VtAV, T, AV); + if (nmod_mat_is_zero(VtAV)) {ret = 1; break;} + + /* Compute W^{-1} and indices of bad vectors */ + cur_dim = compute_nWi_S(&nWi[i], SSt, VtAV); + total_dim += cur_dim; + if (cur_dim == 0 || total_dim > M->c) break; /* Ran out of vectors */ + + /* Update x_i = x_{i-1} - (VSS^t) W^{-1} (VSS^t)^tb */ + nmod_mat_set(VSSt, &V[i]); + kill_columns(VSSt, SSt); + nmod_mat_transpose(T, VSSt); + nmod_mat_mul_vec(SStVtMtb, T, Mtb); + nmod_mat_mul_vec(WiSStVtMtb, &nWi[i], SStVtMtb); + nmod_mat_mul_vec(VSStWiSStVtMtb, VSSt, WiSStVtMtb); + _nmod_vec_add(x, x, VSStWiSStVtMtb, M->c, M->mod); + + /** + * Per Equation (19), we compute the next vector + * V_{i+1} = AV_iS_iS_i^t + V_i D + V_{i-1} E + V_{i-2} F + * where + * D = I - W_i^-1((AV_i)^tAV_iS_iS_i^t + V_i^tAV_i) + * E = -W_{i-1}^-1V_i^tAV_iS_iS_i^t + * F = -W_{i-2}^-1(I - V_{i-1}^tAV_{i-1}W_{i-1}^-1) + * ((AV_{i-1})^tAV_{i-1}S_{i-1}S_{i-1}^t + V_{i-1}^tAV_{i-1})S_iS_i^t + **/ + if (iter >= 2) + { + /* V_{i+1} = V_{i-2} F */ + kill_columns(DEF, SSt); + nmod_mat_mul(VSSt, &V[next_i], DEF); + nmod_mat_set(&V[next_i], VSSt); + } + if (iter >= 1) + { + /* V_{i+1} += V_{i-1} E */ + nmod_mat_mul(DEF, &nWi[prev_i], VtAV); + kill_columns(DEF, SSt); + nmod_mat_addmul(&V[next_i], &V[next_i], &V[prev_i], DEF); + } + /* V_{i+1} += V_i D */ + nmod_mat_transpose(T, AV); + nmod_mat_mul(tmp, T, AV); + kill_columns(tmp, SSt); + nmod_mat_add(AVtAVSSt_VtAV, tmp, VtAV); + nmod_mat_addmul(DEF, I, &nWi[i], AVtAVSSt_VtAV); + nmod_mat_addmul(&V[next_i], &V[next_i], &V[i], DEF); + + /* V_{i+1} += AVSS^t */ + kill_columns(AV, SSt); + nmod_mat_add(&V[next_i], &V[next_i], AV); + + if (nmod_mat_is_zero(&V[next_i])) {ret = 1; break;} + } + _nmod_vec_neg(x, x, M->c, M->mod); + nmod_sparse_mat_clear(Mt); + for (i = 0; i < 3; ++i) nmod_mat_clear(&V[i]); + nmod_mat_clear(MV); + nmod_mat_clear(AV); + flint_free(SSt); + for (i = 0; i < 3; ++i) nmod_mat_clear(&nWi[i]); + nmod_mat_clear(T); + nmod_mat_clear(VtAV); + nmod_mat_clear(VSSt); + nmod_mat_clear(AVtAVSSt_VtAV); + nmod_mat_clear(DEF); + nmod_mat_clear(I); + nmod_mat_clear(tmp); + _nmod_vec_clear(SStVtMtb); + _nmod_vec_clear(WiSStVtMtb); + _nmod_vec_clear(VSStWiSStVtMtb); + _nmod_vec_clear(Mtb); + return ret; +} + +int nmod_sparse_mat_nullvector_block_lanczos(mp_ptr x, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state) +{ + int ret = 1; + mp_ptr x2, b; + x2 = _nmod_vec_init(M->c); + b = _nmod_vec_init(M->r); + + _nmod_vec_randtest(x, state, M->c, M->mod); + nmod_sparse_mat_mul_vec(b, M, x); + if (nmod_sparse_mat_solve_block_lanczos(x2, M, b, block_size, state) == 0) ret = 0; /* Lanczos failed */ + if (ret) + { + _nmod_vec_sub(x, x, x2, M->c, M->mod); + nmod_sparse_mat_mul_vec(b, M, x); + ret = !_nmod_vec_is_zero(x, M->c) && _nmod_vec_is_zero(b, M->r); + } + _nmod_vec_clear(x2); + _nmod_vec_clear(b); + return ret; +} \ No newline at end of file diff --git a/nmod_sparse_mat/solve_block_wiedemann.c b/nmod_sparse_mat/solve_block_wiedemann.c new file mode 100644 index 0000000000..45422cc18d --- /dev/null +++ b/nmod_sparse_mat/solve_block_wiedemann.c @@ -0,0 +1,252 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" + +/* Compute S_i=(M^j Y)_{0...b-1}^T for i = 0,...,ns-1 */ +static void make_block_sequences(nmod_mat_struct *S, slong ns, const nmod_sparse_mat_t M, nmod_mat_struct Y[2]) +{ + slong iter, i, b = Y->c; + nmod_mat_struct W[2]; + for (i = 0; i < 2; ++i) nmod_mat_window_init(&W[i], &Y[i], 0, 0, b, b); + for (i = iter = 0; iter < ns; ++iter, i = 1-i) + { + if (iter > 0) nmod_sparse_mat_mul_mat(&Y[i], M, &Y[1-i]); + nmod_mat_transpose(&S[iter], &W[i]); + } + for (i = 0; i < 2; ++i) nmod_mat_window_clear(&W[i]); +} + +/** + * Run Guassian elimination on the first b columns of the augmented + * matrix M = [ D | I], yielding a final matrix + * [ | ] [ Z | ] + * [ D | I ] -> [---| tau ] + * [ | ] [ L | ] + * where the the number of nonzero rows in Z is the ith rank. We choose + * the pivot row for a given column to be the one with minimal degree. +**/ +static void coppersmith_aux_gauss(nmod_mat_t M, slong *d) +{ + const slong b = M->r/2; + slong pr, pc, r, tmp; + slong *gamma; + mp_limb_t cinv; + + /* Keep track of viable rows */ + gamma = flint_malloc(b*sizeof(*gamma)); + for (r = 0; r < b; ++r) gamma[r] = 1; + + for (pc = 0; pc < b; ++pc) + { + /* Set the pivot row to be the minimum degree row incident on column pc */ + pr = b + pc; + for (r = 0; r < b; r++) + if (gamma[r] && M->rows[r][pc] && d[r] < d[pr]) pr = r; + if (M->rows[pr][pc] == UWORD(0)) continue; + + + /* Try to move pivot row to appropriate position (if not already there) */ + if (pr != b + pc) + { + tmp = d[pr]; d[pr] = d[b+pc]; d[b+pc] = tmp; + + if (M->rows[b + pc][pr]) + nmod_mat_swap_rows(M, NULL, pr, b + pc), pr = b + pc; + else /* Need to make new auxiliary vector and remove r from use */ + _nmod_vec_add(M->rows[b + pc], M->rows[b + pc], M->rows[pr], 3*b, M->mod), gamma[pr] = 0; + } + cinv = nmod_inv(M->rows[pr][pc], M->mod); + + /* Do Gaussian elimination on first b rows */ + for (r = 0; r < b; ++r) + if (gamma[r] && M->rows[r][pc]) + _nmod_vec_scalar_addmul_nmod(M->rows[r], M->rows[pr], M->c, + nmod_neg(nmod_mul(M->rows[r][pc], cinv, M->mod), M->mod), M->mod); + } + flint_free(gamma); +} + +/* Stop with failure if sum(d_0 ... d_{b-1}) < delta */ +/* Stop with success if sum(d_0 ... d_{b-1}) < delta + max(d_0 ... d_{b-1}) - min(d_b ... d_{2b-1}) */ +static int coppersmith_stopping_criterion(slong *d, slong delta, slong b) +{ + slong tmp, r; + + /* Sum degrees of generating polynomials */ + tmp = d[0]; for (r = 1; r < b; ++r) tmp += d[r]; + delta -= tmp; + if (delta < 0) return 0; /* Insufficient degree */ + + /* Add maximum degree of first b polys and subtract minimum degree of last b */ + tmp = d[0]; for (r = 1; r < b; ++r) if (d[r] > tmp) tmp = d[r]; + delta += tmp; + tmp = d[b]; for (r = b + 1; r < 2*b; ++r) if (d[r] < tmp) tmp = d[r]; + delta -= tmp; + return delta < 0 ? 1 : -1; +} + +/** + * Generalization of Berlekamp-Massey due to Coppersmith. + * Iteratively computes a sequence F representing 2b polynomials: + * - the first b are the current (reversed) generating polynomials + * - the last b are certain auxiliary polynomials. +**/ +static int find_block_min_poly(nmod_mat_struct *S, slong *d, slong n, slong delta) +{ + int ret; + slong t; + slong i, k, r, b = S->r; + slong f_len; + nmod_mat_struct *F; + nmod_mat_t M, D, tau, tmp; + + f_len = 1; + F = flint_malloc((n+1)*sizeof(*F)); + nmod_mat_init(&F[0], 2*b, b, S->mod.n); + nmod_mat_init(tmp, b, b, S->mod.n); + for (i = 0; i < b; ++i) d[i] = 0, d[b + i] = 1, F[0].rows[i][i] = 1; + + /* [ D | I ] -> [ ? | tau ]*/ + nmod_mat_init(M, 2*b, 3*b, S->mod.n); + + for (t = 0, ret = -1; t < n && ret == -1; ++t) + { + /* Compute discrepancy matrix and tau */ + nmod_mat_window_init(D, M, 0, 0, 2*b, b); + nmod_mat_window_init(tau, M, 0, b, 2*b, 3*b); + nmod_mat_zero(D); + for (k = 0; k <= t; ++k) nmod_mat_addmul(D, D, &F[k], &S[t-k]); + nmod_mat_one(tau); + nmod_mat_window_clear(D); + nmod_mat_window_clear(tau); + coppersmith_aux_gauss(M, d); + + /* Multiply F by tau * diag(I xI) */ + nmod_mat_window_init(tau, M, 0, b, 2*b, 3*b); /* Needed since gauss reorders rows */ + nmod_mat_init(&F[f_len++], 2*b, b, S->mod.n); + for (k = f_len-1; k > 0; --k) + nmod_mat_mul(&F[k], tau, &F[k-1]); /* Every row multiplied by x */ + for (k = 0; k < f_len; ++k) + for (r = 0; r < b; ++r) /* Divide first b rows by x */ + { + if (k < f_len - 1) _nmod_vec_set(F[k].rows[r], F[k+1].rows[r], b); + else _nmod_vec_zero(F[k].rows[r], b); + } + for (r = b; r < 2*b; ++r) _nmod_vec_zero(F[0].rows[r], b), d[r] += 1; + nmod_mat_window_clear(tau); + ret = coppersmith_stopping_criterion(d, delta, b); + } + + /* Copy C to S, with each row reversed according to its degree */ + for (r = 0; r < b; ++r) + for (k = 0; k <= d[r]; k++) + _nmod_vec_set(S[k].rows[r], F[d[r]-k].rows[r], b); + + for (k = 0; k < f_len; ++k) nmod_mat_clear(&F[k]); + nmod_mat_clear(M); + flint_free(F); + return ret; +} + +static void make_block_sum(mp_ptr x, const nmod_mat_struct *S, const slong *d, const nmod_sparse_mat_t M, nmod_mat_struct Z[2], slong l) +{ + slong i, iter, b = S->r; + slong dd; + mp_ptr xi; + + /* Compute differences between nominal and real degree */ + dd = 0; + while (_nmod_vec_is_zero(S[dd].rows[l], b)) ++dd; + + /* Simulaneously apply all polynomials in row l to iteration of M on Z */ + xi = _nmod_vec_init(M->c); + _nmod_vec_zero(x, M->c); + for (i = iter = 0; iter <= d[l]; ++iter, i = 1 - i) + { + if (iter > 0) nmod_sparse_mat_mul_mat(&Z[i], M, &Z[1-i]); + nmod_mat_mul_vec(xi, &Z[i], S[dd + iter].rows[l]); + _nmod_vec_add(x, x, xi, M->c, M->mod); + } + _nmod_vec_clear(xi); +} + +int nmod_sparse_mat_solve_block_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b, slong block_size, flint_rand_t state) +{ + int good = 0, ret; + mp_ptr x1; + nmod_sparse_vec_t z; + nmod_sparse_mat_t Mb; + if (M->r != M->c) return 0; /* TODO */ + if (_nmod_vec_is_zero(b, M->c)) + { + _nmod_vec_zero(x, M->c); + return 1; + } + + /* TODO: Precondition M */ + x1 = _nmod_vec_init(M->c + 1); + nmod_sparse_vec_init(z); + nmod_sparse_mat_init(Mb, M->r, M->c, M->mod); + nmod_sparse_mat_set(Mb, M); + nmod_sparse_mat_append_col(Mb, b); + nmod_sparse_mat_append_row(Mb, z); + + ret = nmod_sparse_mat_nullvector_block_wiedemann(x1, Mb, block_size, state); + if (ret && x1[M->c] != UWORD(0)) + { + _nmod_vec_scalar_mul_nmod(x, x1, M->c, nmod_neg(nmod_inv(x1[M->c], M->mod), M->mod), M->mod); + good = 1; + } + nmod_sparse_vec_clear(z); + nmod_sparse_mat_clear(Mb); + _nmod_vec_clear(x1); + return good; +} + +int nmod_sparse_mat_nullvector_block_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, slong block_size, flint_rand_t state) +{ + int ret = 0; + slong l, ns, k; + slong *d; + mp_ptr b; + nmod_mat_struct Y[3], *S; + if (M->r != M->c) return 0; /* TODO */ + + ns = 2*M->r/block_size + 3; /* Maybe 5? */ + S = flint_malloc(ns*sizeof(*S)); + d = flint_calloc(2*block_size, sizeof(*d)); + b = _nmod_vec_init(M->r); + for (k = 0; k < ns; ++k) nmod_mat_init(&S[k], block_size, block_size, M->mod.n); + for (l = 0; l < 3; ++l) nmod_mat_init(&Y[l], M->c, block_size, M->mod.n); + do nmod_mat_randfull(&Y[0], state); + while (nmod_mat_is_zero(&Y[0])); + + nmod_sparse_mat_mul_mat(&Y[1], M, &Y[0]); + make_block_sequences(S, ns, M, &Y[1]); + find_block_min_poly(S, d, ns, M->r); + + for (l = 0; l < block_size; ++l) + { + nmod_mat_set(&Y[1], &Y[0]); + make_block_sum(x, S, d, M, Y + 1, l); + nmod_sparse_mat_mul_vec(b, M, x); + if (!_nmod_vec_is_zero(x, M->c) && _nmod_vec_is_zero(b, M->r)) {ret = 1; break;}; + } + return ret; +} + + diff --git a/nmod_sparse_mat/solve_lanczos.c b/nmod_sparse_mat/solve_lanczos.c new file mode 100644 index 0000000000..961aa808cc --- /dev/null +++ b/nmod_sparse_mat/solve_lanczos.c @@ -0,0 +1,105 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" + + +int nmod_sparse_mat_solve_lanczos(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b, flint_rand_t state) +{ + slong j, ret; + const slong nlimbs = _nmod_vec_dot_bound_limbs(M->c, M->mod); + + /* We assume that M is not symmetric, and work with A = M^t M */ + nmod_sparse_mat_t Mt; + mp_ptr v[2], Mv, Av, Mtb; + mp_limb_t vtAv[2], AvtAv, vMtb; + + _nmod_vec_zero(x, M->c); + if (_nmod_vec_is_zero(b, M->c)) return 1; + + /* Construct transpose */ + nmod_sparse_mat_init(Mt, M->c, M->r, M->mod); + nmod_sparse_mat_transpose(Mt, M); + + /* Construct auxiliary vectors */ + /* Rather than storing the whole sequence of values v_j, we alternate between two vectors */ + v[0] = _nmod_vec_init(M->c); + v[1] = _nmod_vec_init(M->c); + Mv = _nmod_vec_init(M->r); + Av = _nmod_vec_init(M->c); + Mtb = _nmod_vec_init(M->c); + nmod_sparse_mat_mul_vec(Mtb, Mt, b); + + /* Make 0th vector random (and -1st vector trivial) */ + /*_nmod_vec_set(v[0], Mtb, M->c); + for (j = 0; j < M->c; ++j) v[0][j] = n_randint(state, M->mod.n); */ + _nmod_vec_randtest(v[0], state, M->c, M->mod); + _nmod_vec_zero(v[1], M->c); vtAv[1] = 1; + for (j = 0; ; j = 1-j) + { + /* Compute M^T M v_j and check if it is orthogonal to v_j */ + nmod_sparse_mat_mul_vec(Mv, M, v[j]); + nmod_sparse_mat_mul_vec(Av, Mt, Mv); + vtAv[j] = _nmod_vec_dot(v[j], Av, M->c, M->mod, nlimbs); + if (vtAv[j] == UWORD(0)) break; /* Can't make any more progress */ + + /* Update putative solution by /delta_j * v_j */ + vMtb = nmod_div(_nmod_vec_dot(v[j], Mtb, M->c, M->mod, nlimbs), vtAv[j], M->mod); + _nmod_vec_scalar_addmul_nmod(x, v[j], M->c, vMtb, M->mod); + + /* v_{j+1} = MtMv - alpha*v_j - beta*v_{j-1}, where */ + /* alpha = /delta_j, and */ + /* beta = delta_j/delta_{j-1} */ + AvtAv = _nmod_vec_dot(Av, Av, M->c, M->mod, nlimbs); + _nmod_vec_scalar_mul_nmod(v[1-j], v[1-j], M->c, nmod_neg(nmod_div(vtAv[j], vtAv[1-j], M->mod), M->mod), M->mod); + _nmod_vec_scalar_addmul_nmod(v[1-j], v[j], M->c, nmod_neg(nmod_div(AvtAv, vtAv[j], M->mod), M->mod), M->mod); + _nmod_vec_add(v[1-j], v[1-j], Av, M->c, M->mod); + } + /* Check result */ + nmod_sparse_mat_mul_vec(Mv, M, x); + nmod_sparse_mat_mul_vec(Av, Mt, Mv); + ret = _nmod_vec_equal(Av, Mtb, M->c); + + /* Clear auxiliary vectors and transpose */ + _nmod_vec_clear(v[0]); + _nmod_vec_clear(v[1]); + _nmod_vec_clear(Mv); + _nmod_vec_clear(Av); + _nmod_vec_clear(Mtb); + nmod_sparse_mat_clear(Mt); + return ret; +} + +int nmod_sparse_mat_nullvector_lanczos(mp_ptr x, const nmod_sparse_mat_t M, flint_rand_t state) +{ + int ret = 1; + mp_ptr x2, b; + x2 = _nmod_vec_init(M->c); + b = _nmod_vec_init(M->r); + + _nmod_vec_randtest(x, state, M->c, M->mod); + nmod_sparse_mat_mul_vec(b, M, x); + if (nmod_sparse_mat_solve_lanczos(x2, M, b, state) == 0) ret = 0; /* Lanczos failed */ + if (ret) + { + _nmod_vec_sub(x, x, x2, M->c, M->mod); + nmod_sparse_mat_mul_vec(b, M, x); + ret = !_nmod_vec_is_zero(x, M->c) && _nmod_vec_is_zero(b, M->r); + } + _nmod_vec_clear(x2); + _nmod_vec_clear(b); + return ret; +} diff --git a/nmod_sparse_mat/solve_lu.c b/nmod_sparse_mat/solve_lu.c new file mode 100644 index 0000000000..173606852c --- /dev/null +++ b/nmod_sparse_mat/solve_lu.c @@ -0,0 +1,71 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +/* PAQ = LU, Ax = b => set b' = Pb, solve Ly = b', solve Ux' = y, set x = Qx' */ +int nmod_sparse_mat_solve_lu(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b) +{ + int good = 1; + slong rk, *P, *Q, i; + nmod_sparse_mat_t L, U; + mp_ptr bp, y, xp; + if (_nmod_vec_is_zero(b, M->c)) + { + _nmod_vec_zero(x, M->c); + return 1; + } + + P = flint_malloc(M->r * sizeof(*P)); + Q = flint_malloc(M->c * sizeof(*Q)); + nmod_sparse_mat_init(L, M->r, M->c, M->mod); + nmod_sparse_mat_init(U, M->r, M->c, M->mod); + rk = nmod_sparse_mat_lu(P, Q, L, U, M); + L->c = U->r = rk; + + /* Solve Ly = b' = Pb */ + bp = flint_malloc(M->r * sizeof(*bp)); + y = flint_calloc(rk, sizeof(*y)); + for (i = 0; i < M->r; ++i) bp[P[i]] = b[i]; + + flint_free(P); + for (i = 0; i < rk; ++i) + y[i] = nmod_sub(bp[i], nmod_sparse_vec_dot_dense(&L->rows[i], y, M->mod), M->mod); + for (i = rk; i < M->r; ++i) + if (bp[i] != nmod_sparse_vec_dot_dense(&L->rows[i], y, M->mod)) {good = 0; break;} + nmod_sparse_mat_mul_vec(bp, L, y); + + flint_free(bp); + nmod_sparse_mat_clear(L); + + if (good) + { + /* Find a solution for Ux' = y */ + xp = flint_calloc(M->c, sizeof(*xp)); + for (i = rk-1; i >= 0; --i) + xp[i] = nmod_div(nmod_sub(y[i], nmod_sparse_vec_dot_dense(&U->rows[i], xp, M->mod), M->mod), U->rows[i].entries[0].val, M->mod); + nmod_sparse_mat_mul_vec(y, U, xp); + + for (i = 0; i < M->c; ++i) x[i] = xp[Q[i]]; + flint_free(xp); + } + flint_free(Q); + flint_free(y); + U->r = M->r; + nmod_sparse_mat_clear(U); + return good; +} diff --git a/nmod_sparse_mat/solve_rref.c b/nmod_sparse_mat/solve_rref.c new file mode 100644 index 0000000000..1044ac6faf --- /dev/null +++ b/nmod_sparse_mat/solve_rref.c @@ -0,0 +1,53 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" + +int nmod_sparse_mat_solve_rref(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b) +{ + int good = 1; + slong i; + nmod_sparse_mat_t Mb; + nmod_sparse_vec_struct *row; + nmod_sparse_entry_struct *le, *re; + if (_nmod_vec_is_zero(b, M->c)) + { + _nmod_vec_zero(x, M->c); + return 1; + } + nmod_sparse_mat_init(Mb, M->r, M->c, M->mod); + nmod_sparse_mat_set(Mb, M); + nmod_sparse_mat_append_col(Mb, b); + Mb->c = M->c; + nmod_sparse_mat_rref(Mb); + Mb->c = M->c+1; + + memset(x, 0, M->c*sizeof(*x)); + for (i = 0; i < M->r; ++i) + { + row = &Mb->rows[i]; + if (row->nnz == 0) continue; + le = &row->entries[0]; + re = &row->entries[row->nnz-1]; + /* If any row has leading col M->c, system is not solvable */ + if (le->ind==M->c) {good = 0; break;} + /* Otherwise, x[lc] = lagging value */ + if (re->ind==M->c) {x[le->ind] = re->val;} + } + nmod_sparse_mat_clear(Mb); + return good; +} diff --git a/nmod_sparse_mat/solve_wiedemann.c b/nmod_sparse_mat/solve_wiedemann.c new file mode 100644 index 0000000000..2d4329c799 --- /dev/null +++ b/nmod_sparse_mat/solve_wiedemann.c @@ -0,0 +1,171 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" + +/* Berlekamp - Massey algorithm */ +static slong find_min_poly(mp_limb_t *s, slong N, nmod_t mod) +{ + slong L = 0, m, n, i; + mp_limb_t c, d_C, d_B = 1; + + slong deg_C = 0, deg_B = 0, deg_T = -1; + mp_limb_t *B, *C, *T; + B = flint_calloc(N, sizeof(*B)); + C = flint_calloc(N, sizeof(*C)); + T = flint_calloc(N, sizeof(*T)); + B[0] = C[0] = UWORD(1); + + for (n = 0, m = 1; n < N; n++, m++) + { + /* d_C = sum_{i = 0}^L C_i * s_{n-i} */ + d_C = s[n]; + for (i = 1; i <= L; i++) + d_C = nmod_addmul(d_C, C[i], s[n-i], mod); + if (d_C == 0) continue; /* C and L currently valid */ + + /* C(x) = C(x) - (d_C/d_B) x^m B(x); */ + if (L <= 2*n) deg_T = deg_C, memcpy(T, C, (deg_C+1)*sizeof(*T)); /* T(X) = C(X) */ + c = nmod_neg(nmod_div(d_C, d_B, mod), mod); + for (i = 0; i <= deg_B; ++i) + C[m+i] = nmod_addmul(C[m+i], B[i], c, mod); + deg_C = FLINT_MAX(deg_C, deg_B + m); + while (C[deg_C] == UWORD(0)) --deg_C; /* Probably unnecessary */ + + if (2*L <= n) /* Increase number of errors */ + { + L = n + 1 - L, m = 0; + d_B = d_C, deg_B = deg_T; + memcpy(B, T, (deg_T+1)*sizeof(*B)); /* B(x) = C(x) */ + } + } + /* Reverse C into s */ + for (i = 0; i <= L; ++i) s[i] = C[L-i]; + flint_free(B); + flint_free(C); + flint_free(T); + return L; +} + +/* Compute s_ij=(M^j y)_i for i = 0,...,ns-1, j = 0,...,num-1*/ +static void make_sequences(mp_limb_t **s, slong ns, slong len, const nmod_sparse_mat_t M, mp_srcptr b) +{ + slong i, j; + mp_ptr y, My; + y = _nmod_vec_init(M->r); + My = _nmod_vec_init(M->r); + memcpy(y, b, M->r*sizeof(*y)); + for (j = 0; j < len; ++j) + { + if (j > 0) nmod_sparse_mat_mul_vec(My, M, y), memcpy(y, My, M->r*sizeof(*y)); + for (i = 0; i < ns; ++i) s[i][j] = y[i]; + } + _nmod_vec_clear(y); + _nmod_vec_clear(My); +} + +/* Compute x = \Sigma_{i = 0}^{L-1} s_i * M^i * b = 0 */ +static void make_sum(mp_ptr x, mp_limb_t *s, slong L, const nmod_sparse_mat_t M, mp_srcptr b) +{ + slong i; + mp_ptr y, My; + y = _nmod_vec_init(M->r); + My = _nmod_vec_init(M->r); + memcpy(y, b, M->r*sizeof(*y)); + _nmod_vec_scalar_mul_nmod(x, b, M->r, s[0], M->mod); + for (i = 1; i < L; ++i) + { + nmod_sparse_mat_mul_vec(My, M, y), memcpy(y, My, M->r*sizeof(*y)); + _nmod_vec_scalar_addmul_nmod(x, y, M->r, s[i], M->mod); + } + _nmod_vec_clear(y); + _nmod_vec_clear(My); +} + +int nmod_sparse_mat_solve_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, mp_srcptr b) +{ + slong i, L, ret = 0, ns = FLINT_MIN(M->r, 2), len = 2*M->r + 1; + mp_limb_t **s; + mp_ptr Mx; + if (M->r != M->c) return 0; /* TBD: reduce to square */ + if (_nmod_vec_is_zero(b, M->c)) + { + _nmod_vec_zero(x, M->c); + return 1; + } + + Mx = _nmod_vec_init(M->r); + s = flint_malloc(ns * sizeof(*s)); + for (i = 0; i < ns; ++i) s[i] = flint_malloc(len*sizeof(*s[i])); + + make_sequences(s, ns, len, M, b); + + /* Don't have block Berlekamp yet, just try each one */ + for (i = 0; i < ns && ret == 0; ++i) + { + /* Get minimal polynomial */ + L = find_min_poly(s[i], len, M->mod); + if (s[i][0]==0) continue; + + /* If \sum_{j = 0}^L s_ijM^jb = 0 => x = -1/s[0]\sum_{j = 0}^{L-1} s_i(j-1) M^jb solves Mx = b */ + make_sum(x, s[i]+1, L, M, b); + _nmod_vec_scalar_mul_nmod(x, x, M->r, nmod_neg(nmod_inv(s[i][0], M->mod), M->mod), M->mod); + + /* Check if successful */ + nmod_sparse_mat_mul_vec(Mx, M, x); + ret = _nmod_vec_equal(Mx, b, M->r); + } + + _nmod_vec_clear(Mx); + for (i = 0; i < ns; ++i) flint_free(s[i]); + flint_free(s); + return ret; +} + +int nmod_sparse_mat_nullvector_wiedemann(mp_ptr x, const nmod_sparse_mat_t M, flint_rand_t state) +{ + slong i, L, ret = 0, ns = FLINT_MIN(M->r, 2), len = 2*M->r + 1; + mp_limb_t **s; + mp_ptr Mx, b; + Mx = _nmod_vec_init(M->r); + b = _nmod_vec_init(M->r); + + s = flint_malloc(ns * sizeof(*s)); + for (i = 0; i < ns; ++i) s[i] = flint_malloc(len*sizeof(*s[i])); + + _nmod_vec_randtest(x, state, M->r, M->mod); + nmod_sparse_mat_mul_vec(b, M, x); + + if (M->r != M->c) return 0; /* TBD: reduce to square */ + make_sequences(s, ns, len, M, b); + + for (i = 0; i < ns && ret == 0; ++i) + { + /* Get minimal polynomial */ + L = find_min_poly(s[i], len, M->mod); + + /* \sum_{j = 0}^L s_ijM^jb = 0 => x = \sum_{j = 0}^L s_ijM^jx solves Mx = 0 */ + make_sum(x, s[i], L+1, M, x); + nmod_sparse_mat_mul_vec(Mx, M, x); + ret = !_nmod_vec_is_zero(x, M->c) && _nmod_vec_is_zero(Mx, M->r); + } + + _nmod_vec_clear(Mx); + _nmod_vec_clear(b); + for (i = 0; i < ns; ++i) flint_free(s[i]); + flint_free(s); + return ret; +} \ No newline at end of file diff --git a/nmod_sparse_mat/strong_echelon_form.c b/nmod_sparse_mat/strong_echelon_form.c new file mode 100644 index 0000000000..25bed4b5b3 --- /dev/null +++ b/nmod_sparse_mat/strong_echelon_form.c @@ -0,0 +1,186 @@ +/* + Copyright (C) 2015 Tommy Hofmann + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" +#if 0 +static __inline__ int +_nmod_mat_pivot(nmod_mat_t M, slong start_row, slong pc) +{ + slong j; + mp_ptr u; + + if (nmod_mat_entry(M, start_row, pc) != 0) + return 1; + + for (j = start_row + 1; j < M->r; j++) + { + if (M->rows[j][pc] != 0) + { + u = M->rows[j]; + M->rows[j] = M->rows[start_row]; + M->rows[start_row] = u; + + return -1; + } + } + return 0; +} + +static void +_n_ppio(mp_ptr ppi, mp_ptr ppo, mp_limb_t a, mp_limb_t b) +{ + mp_limb_t c, M->r, g; + + c = n_gcd(a, b); + M->r = a/c; + g = n_gcd(c, M->r); + while ( g != 1 ) + { + c = c * g; + M->r = M->r/g; + g = n_gcd(c, M->r); + } + *ppi = c; + *ppo = M->r; +} + +static mp_limb_t +_n_stab(mp_limb_t a, mp_limb_t b, nmod_t N) +{ + mp_limb_t g, a, b; + g = n_gcd(a, b); + b = n_gcd(g, N.M->r); + _n_ppio(&a, &b, N.M->r/b, a/b); + return b; +} + +static mp_limb_t +_n_unit(mp_limb_t a, nmod_t N) +{ + mp_limb_t g, a, l, d; + + g = n_gcdinv(&a, a, N.M->r); + + if (g == 1) + { + return a; + } + else + { + l = N.M->r/g; + d = _n_stab(a, l, N); + return nmod_add(a, nmod_mul(d, l, N), N); + } +} + +/* test wether q*a = b M->mod N has a solution */ +static int +_n_is_divisible(mp_ptr q, mp_limb_t b, mp_limb_t a, nmod_t N) +{ + mp_limb_t e, g; + g = n_gcdinv(&e, a, N.M->r); + + if (( b % g ) == 0) + { + *q = nmod_mul(e, b/g, N); + return 1; + } + + return 0; +} + +void +nmod_sparse_mat_strong_echelon_form(nmod_sparse_mat_t M) +{ + mp_limb_t a, b, u, v, q, t1, t2, g; + slong pr, pc, r, k, l; + mp_limb_t **r; + mp_ptr extra_row; + + if (nmod_mat_is_empty(M)) + return; + + + extra_row = _nmod_vec_init(M->c); + + pr = pc = 0; + + while (pr < M->r && pc < M->c) + { + if (_nmod_mat_pivot(M, pr, pc) == 0) {pc++; continue;} + for (r = pr + 1; r < M->r; r++) + { + if (M->rows[r][pc] == 0) continue; + + if (M->rows[pr][pc] >= M->rows[r][pc]) + g = n_xgcd(&a, &b, M->rows[pr][pc], M->rows[r][pc]); + else + g = n_xgcd(&b, &a, M->rows[r][pc], M->rows[pr][pc]); + + if (b != UWORD(0)) + _nmod_sparse_mat_rowop(M, pr, a, r, nmod_neg(b, M->mod)); + _nmod_sparse_mat_rowop(M, r, UWORD(1), pr, M->rows[r][pc]/g); + nmod_sparse_mat_scalar_div_nmod(M->rows[r], M->rows[r], a); + } + pr++; + pc++; + } + + for (pc = 0; pc < M->c; pc++) + { + if (M->rows[pc][pc] != 0) + { + u = _n_unit(M->rows[pc][pc], M->mod); + _nmod_sparse_vec_scalar_mul_nmod(M->rows[pc], M->rows[pc], u, M->mod); + + for (pr = 0; pr < pc ; pr++) + { + + q = M->rows[pr][pc]/M->rows[pc][pc]; + + for (l = pr; l< M->c; l++) + { + M->rows[pr][l] = nmod_sub(M->rows[pr][l], nmod_mul(q, M->rows[pc][l], M->mod), M->mod); + } + } + + g = n_gcd(M->mod.n, M->rows[pc][pc]); + if (g == 1) continue; + _nmod_vec_scalar_mul_nmod(extra_row, M->rows[pc], M->c, M->mod.n/g, M->mod); + } + else + { + _nmod_vec_set(extra_row, M->rows[pc], M->c); + } + + for (pr = pc + 1; pr < M->c; pr++) + { + if (extra_row[pr] == 0) continue; + + if (M->rows[pr][pr] >= extra_row[pr]) + g = n_xgcd(&a, &b, M->rows[pr][pr], extra_row[pr]); + else + g = n_xgcd(&b, &a, extra_row[pr], M->rows[pr][pr]); + + if (b != UWORD(0)) + _nmod_sparse_mat_rowop(M, pr, a, r, nmod_neg(b, M->mod)); + _nmod_sparse_mat_rowop(M, r, UWORD(1), pr, extra_row[pr]/g); + nmod_sparse_mat_scalar_div_nmod(extra_row, extra_row, a); + } + } + _nmod_vec_clear(extra_row); +} +#endif \ No newline at end of file diff --git a/nmod_sparse_mat/test/t-add.c b/nmod_sparse_mat/test/t-add.c new file mode 100644 index 0000000000..665ba53ec3 --- /dev/null +++ b/nmod_sparse_mat/test/t-add.c @@ -0,0 +1,67 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, B, C, D; + FLINT_TEST_INIT(state); + + flint_printf("add/sub...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + r = n_randint(state, 200); + c = n_randint(state, 200); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_init(B, r, c, mod); + nmod_sparse_mat_init(C, r, c, mod); + nmod_sparse_mat_init(D, r, c, mod); + + nmod_sparse_mat_randtest(A, state, 0, c); + nmod_sparse_mat_randtest(B, state, 0, c); + + nmod_sparse_mat_add(C, A, B); + nmod_sparse_mat_sub(D, C, B); + + if (!nmod_sparse_mat_equal(D, A)) + { + flint_printf("FAIL\n"); + abort(); + } + + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(B); + nmod_sparse_mat_clear(C); + nmod_sparse_mat_clear(D); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-concat_horizontal.c b/nmod_sparse_mat/test/t-concat_horizontal.c new file mode 100644 index 0000000000..4190aa517d --- /dev/null +++ b/nmod_sparse_mat/test/t-concat_horizontal.c @@ -0,0 +1,106 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int main(void) +{ + slong rep, r, c1, c2, nreps = 100; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, B, C; + nmod_sparse_mat_t window1, window2; + FLINT_TEST_INIT(state); + + flint_printf("concat_horizontal...."); + fflush(stdout); + + + for (rep = 0; rep < nreps; rep++) + { + r = n_randint(state, 200); + c1 = n_randint(state, 200); + c2 = n_randint(state, 200); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c1, mod); + nmod_sparse_mat_init(B, r, c2, mod); + nmod_sparse_mat_init(C, r, c1+c2, mod); + + nmod_sparse_mat_randtest(A, state, 0, c1); + nmod_sparse_mat_randtest(B, state, 0, c2); + nmod_sparse_mat_randtest(C, state, 0, c1+c2); + + nmod_sparse_mat_concat_horizontal(C, A, B); + + nmod_sparse_mat_window_init(window1, C, 0, 0, r, c1); + nmod_sparse_mat_window_init(window2, C, 0, c1, r, c1+c2); + + if (!(nmod_sparse_mat_equal(window1, A) && nmod_sparse_mat_equal(window2, B))) + { + flint_printf("A = \n"); + nmod_sparse_mat_print_pretty(A); + flint_printf("B = \n"); + nmod_sparse_mat_print_pretty(B); + flint_printf("A | B = \n"); + nmod_sparse_mat_print_pretty(C); + flint_printf("window1 = \n"); + nmod_sparse_mat_print_pretty(window1); + flint_printf("window2 = \n"); + nmod_sparse_mat_print_pretty(window2); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + nmod_sparse_mat_window_clear(window1); + nmod_sparse_mat_window_clear(window2); + + nmod_sparse_mat_init(window1, r, c1, mod); + nmod_sparse_mat_init(window2, r, c2, mod); + nmod_sparse_mat_split_horizontal(window1, window2, C, c1); + + if (!(nmod_sparse_mat_equal(window1, A) && nmod_sparse_mat_equal(window2, B))) + { + flint_printf("A = \n"); + nmod_sparse_mat_print_pretty(A); + flint_printf("B = \n"); + nmod_sparse_mat_print_pretty(B); + flint_printf("A | B = \n"); + nmod_sparse_mat_print_pretty(C); + flint_printf("window1 = \n"); + nmod_sparse_mat_print_pretty(window1); + flint_printf("window2 = \n"); + nmod_sparse_mat_print_pretty(window2); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + nmod_sparse_mat_window_clear(window1); + nmod_sparse_mat_window_clear(window2); + + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(B); + nmod_sparse_mat_clear(C); + } + + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-concat_vertical.c b/nmod_sparse_mat/test/t-concat_vertical.c new file mode 100644 index 0000000000..e8c7bde02a --- /dev/null +++ b/nmod_sparse_mat/test/t-concat_vertical.c @@ -0,0 +1,99 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_vec.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int main(void) +{ + slong rep, r1, r2, c, nreps = 100; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, B, C; + nmod_sparse_mat_t window1, window2; + FLINT_TEST_INIT(state); + + + flint_printf("concat_vertical...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + r1 = n_randint(state, 100); + r2 = n_randint(state, 100); + c = n_randint(state, 100); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r1, c, mod); + nmod_sparse_mat_init(B, r2, c, mod); + nmod_sparse_mat_init(C, r1+r2, c, mod); + + nmod_sparse_mat_randtest(A, state, 0, c); + nmod_sparse_mat_randtest(B, state, 0, c); + nmod_sparse_mat_randtest(C, state, 0, c); + + nmod_sparse_mat_concat_vertical(C, A, B); + + nmod_sparse_mat_window_init(window1, C, 0, 0, r1, c); + nmod_sparse_mat_window_init(window2, C, r1, 0, r1+r2, c); + + if (!(nmod_sparse_mat_equal(window1, A) && nmod_sparse_mat_equal(window2, B))) + { + flint_printf("A = \n"); + nmod_sparse_mat_print_pretty(A); + flint_printf("B = \n"); + nmod_sparse_mat_print_pretty(B); + flint_printf("A concat_vertical B = \n"); + nmod_sparse_mat_print_pretty(C); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + nmod_sparse_mat_window_clear(window1); + nmod_sparse_mat_window_clear(window2); + + nmod_sparse_mat_init(window1, r1, c, mod); + nmod_sparse_mat_init(window2, r2, c, mod); + nmod_sparse_mat_split_vertical(window1, window2, C, r1); + + if (!(nmod_sparse_mat_equal(window1, A) && nmod_sparse_mat_equal(window2, B))) + { + flint_printf("A = \n"); + nmod_sparse_mat_print_pretty(A); + flint_printf("B = \n"); + nmod_sparse_mat_print_pretty(B); + flint_printf("A concat_vertical B = \n"); + nmod_sparse_mat_print_pretty(C); + flint_printf("FAIL: results not equal\n"); + abort(); + } + + nmod_sparse_mat_window_clear(window1); + nmod_sparse_mat_window_clear(window2); + + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(B); + nmod_sparse_mat_clear(C); + } + + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-construct.c b/nmod_sparse_mat/test/t-construct.c new file mode 100644 index 0000000000..d907484120 --- /dev/null +++ b/nmod_sparse_mat/test/t-construct.c @@ -0,0 +1,98 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c, i, j, k, nnz; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, B, C; + slong *rows; + slong *cols; + mp_limb_t *vals; + FLINT_TEST_INIT(state); + + flint_printf("construction from entries...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + r = n_randint(state, 10); + c = n_randint(state, 10); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_init(B, r, c, mod); + nmod_sparse_mat_init(C, 0, c, mod); + + nmod_sparse_mat_randtest(A, state, 2, 2); + nmod_sparse_mat_randtest(B, state, 2, 2); + nnz = 0; + for (i = 0; i < r; ++i) nnz += A->rows[i].nnz; + + /* Construct B from entries of A */ + rows = flint_malloc(nnz * sizeof(*rows)); + cols = flint_malloc(nnz * sizeof(*cols)); + vals = flint_malloc(nnz * sizeof(*vals)); + for (i = k = 0; i < r; ++i) + { + for (j = 0; j < A->rows[i].nnz; ++j, ++k) + { + rows[k] = i; + cols[k] = A->rows[i].entries[j].ind; + vals[k] = A->rows[i].entries[j].val; + } + } + nmod_sparse_mat_from_entries(B, rows, cols, vals, nnz); + if (!nmod_sparse_mat_equal(A, B)) + { + flint_printf("FAIL: A != B\n"); + flint_printf("A = "); + nmod_sparse_mat_print_pretty(A); + flint_printf("B = "); + nmod_sparse_mat_print_pretty(B); + abort(); + } + + for (i = 0; i < r; ++i) nmod_sparse_mat_append_row(C, &A->rows[i]); + if (!nmod_sparse_mat_equal(A, C)) + { + flint_printf("FAIL: A != C\n"); + flint_printf("A = "); + nmod_sparse_mat_print_pretty(A); + flint_printf("C = "); + nmod_sparse_mat_print_pretty(C); + abort(); + } + flint_free(rows); + flint_free(cols); + flint_free(vals); + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(B); + nmod_sparse_mat_clear(C); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-dense.c b/nmod_sparse_mat/test/t-dense.c new file mode 100644 index 0000000000..a051befba0 --- /dev/null +++ b/nmod_sparse_mat/test/t-dense.c @@ -0,0 +1,76 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, B; + nmod_mat_t C, D; + FLINT_TEST_INIT(state); + + + flint_printf("conversion to/from dense matrix...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + r = n_randint(state, 10); + c = n_randint(state, 10); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_init(B, r, c, mod); + nmod_mat_init(C, r, c, n); + nmod_mat_init(D, r, c, n); + + nmod_sparse_mat_randtest(A, state, 0, c); + nmod_sparse_mat_to_dense(C, A); + nmod_sparse_mat_from_dense(B, C); + + if (!nmod_sparse_mat_equal(A, B)) + { + flint_printf("FAIL: A != B\n"); + abort(); + } + + nmod_mat_randtest(C, state); + nmod_sparse_mat_from_dense(A, C); + nmod_sparse_mat_to_dense(D, A); + + if (!nmod_mat_equal(C, D)) + { + flint_printf("FAIL: C != D\n"); + abort(); + } + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(B); + nmod_mat_clear(C); + nmod_mat_clear(D); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-init_clear.c b/nmod_sparse_mat/test/t-init_clear.c new file mode 100644 index 0000000000..079877e87b --- /dev/null +++ b/nmod_sparse_mat/test/t-init_clear.c @@ -0,0 +1,66 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, r2, c, i; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A; + FLINT_TEST_INIT(state); + + + flint_printf("init/clear...."); + fflush(stdout); + + for (rep = 0; rep < 100; rep++) + { + r = n_randint(state, 200); + r2 = n_randint(state, 200); + c = n_randint(state, 200); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + + if (!nmod_sparse_mat_is_zero(A)) + { + flint_printf("FAIL: A not zero!\n"); + abort(); + } + for (i = 0; i < r; i++) + { + if (!nmod_sparse_vec_is_zero(&A->rows[i])) + { + flint_printf("FAIL: row %wd not zero!\n", i); + abort(); + } + } + + + nmod_sparse_mat_clear(A); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-inv.c b/nmod_sparse_mat/test/t-inv.c new file mode 100644 index 0000000000..2df2d0c7f0 --- /dev/null +++ b/nmod_sparse_mat/test/t-inv.c @@ -0,0 +1,72 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, Ai; + nmod_mat_t dA, dAiA; + FLINT_TEST_INIT(state); + + flint_printf("inverting A...."); + fflush(stdout); + + for (rep = 0; rep < 100; rep++) + { + if (rep % 5==0) {flint_printf("."); fflush(stdout);} + do r = n_randint(state, 200), c = n_randint(state, 200); + while (r==UWORD(0) || c==UWORD(0)); + + do n = n_randtest_not_zero(state); + while (n <= 32 || !n_is_prime(n)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_init(Ai, r, r, mod); + nmod_sparse_mat_randtest(A, state, 0, c); + nmod_mat_init(dA, r, c, n); + nmod_mat_init(dAiA, r, c, n); + nmod_sparse_mat_to_dense(dA, A); + + nmod_sparse_mat_inv(Ai, A); + nmod_sparse_mat_mul_mat(dAiA, Ai, dA); + nmod_mat_rref(dA); + if (!nmod_mat_equal(dAiA, dA)) + { + flint_printf("FAIL!\n"); + flint_printf("A^-1 x A = "); + nmod_mat_print_pretty(dAiA); + flint_printf("rref(A) = "); + nmod_mat_print_pretty(dA); + abort(); + } + + nmod_sparse_mat_clear(Ai); + nmod_mat_clear(dA); + nmod_mat_clear(dAiA); + nmod_sparse_mat_clear(A); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-lu.c b/nmod_sparse_mat/test/t-lu.c new file mode 100644 index 0000000000..03aa3f29b6 --- /dev/null +++ b/nmod_sparse_mat/test/t-lu.c @@ -0,0 +1,132 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + + +int +main(void) +{ + slong rep, r, c, i, j, rk, *P, *Q; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, LU, L, U; + nmod_mat_t dL, dU, dLU; + FLINT_TEST_INIT(state); + + flint_printf("decomposing PAQ = LU...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + if (rep % 50 == 0) {flint_printf("."); fflush(stdout);} + r = n_randint(state, 200); + c = n_randint(state, 200); + + do n = n_randtest_not_zero(state); + while (!n_is_prime(n)); + nmod_init(&mod, n); + P = flint_malloc(r*sizeof(*P)); + Q = flint_malloc(c*sizeof(*P)); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_init(LU, r, c, mod); + nmod_sparse_mat_init(L, r, c, mod); + nmod_sparse_mat_init(U, r, c, mod); + nmod_sparse_mat_randtest(A, state, 1, c); + rk = nmod_sparse_mat_lu(P, Q, L, U, A); + nmod_mat_init(dL, r, rk, n); + nmod_mat_init(dU, rk, c, n); + nmod_mat_init(dLU, r, c, n); + + /* Check that L is lower triangular (with ones on diagonal up to rank) */ + for (i = 0; i < r; ++i) + { + if (i < rk && *nmod_sparse_vec_at(&L->rows[i], i) != UWORD(1)) + { + flint_printf("FAIL: L does not have unit diagonal up to the rank\n"); + } + for (j = 0; j < L->rows[i].nnz; ++j) + { + nmod_sparse_entry_struct *e = &L->rows[i].entries[j]; + if (e->ind > i) + { + flint_printf("FAIL: L not lower triangular\n"); + abort(); + } + if (e->ind >= rk) + { + flint_printf("FAIL: L not trivial past the rank\n"); + nmod_sparse_mat_print_pretty(L); + abort(); + } + } + } + /* Check that U is upper triangular (with nonzero diagonal up to rank) */ + for (i = 0; i < r; ++i) + { + if (i < rk && *nmod_sparse_vec_at(&U->rows[i], i) == UWORD(0)) + { + flint_printf("FAIL: U does not have nonzero diagonal\n"); + abort(); + } + if (i >= rk && U->rows[i].nnz != UWORD(0)) + { + flint_printf("FAIL: U not trivial pas the rank\n"); + abort(); + } + for (j = 0; j < U->rows[i].nnz; ++j) + { + nmod_sparse_entry_struct *e = &U->rows[i].entries[j]; + if (e->ind < i) + { + flint_printf("FAIL: U not upper triangular\n"); + abort(); + } + } + } + nmod_sparse_mat_to_dense(dL, L); + nmod_sparse_mat_to_dense(dU, U); + nmod_mat_mul(dLU, dL, dU); + nmod_sparse_mat_from_dense(LU, dLU); + nmod_sparse_mat_permute_rows(A, P); + nmod_sparse_mat_permute_cols(A, Q); + if (!nmod_sparse_mat_equal(A, LU)) + { + flint_printf("FAIL: PAQ != LU\n"); + flint_printf("PAQ="); + nmod_sparse_mat_print_pretty(A); + flint_printf("LU="); + nmod_sparse_mat_print_pretty(LU); + abort(); + } + + flint_free(P); + flint_free(Q); + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(U); + nmod_sparse_mat_clear(L); + nmod_sparse_mat_clear(LU); + nmod_mat_clear(dL); + nmod_mat_clear(dU); + nmod_mat_clear(dLU); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-mul.c b/nmod_sparse_mat/test/t-mul.c new file mode 100644 index 0000000000..1fca229f3f --- /dev/null +++ b/nmod_sparse_mat/test/t-mul.c @@ -0,0 +1,89 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c, k; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A; + mp_ptr x, y, y2; + nmod_mat_t B, X, Y, Y2; + FLINT_TEST_INIT(state); + + + flint_printf("multiplication by vec/mat...."); + fflush(stdout); + + for (rep = 0; rep < 10; rep++) + { + r = n_randint(state, 200); + c = n_randint(state, 200); + k = n_randint(state, 200); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_randtest(A, state, 0, c); + nmod_mat_init(B, r, c, n); + nmod_sparse_mat_to_dense(B, A); + + x = _nmod_vec_init(c); + y = _nmod_vec_init(r); + y2 = _nmod_vec_init(r); + _nmod_vec_randtest(x, state, c, mod); + nmod_sparse_mat_mul_vec(y, A, x); + nmod_mat_mul_vec(y2, B, x); + + if (!_nmod_vec_equal(y, y2, A->r)) + { + flint_printf("FAIL: y != y2\n"); + abort(); + } + + nmod_mat_init(X, c, k, n); + nmod_mat_init(Y, r, k, n); + nmod_mat_init(Y2, r, k, n); + nmod_mat_randtest(X, state); + nmod_sparse_mat_mul_mat(Y, A, X); + nmod_mat_mul(Y2, B, X); + + if (!nmod_mat_equal(Y, Y2)) + { + flint_printf("Fail: Y != Y2\n"); + abort(); + } + + nmod_sparse_mat_clear(A); + nmod_mat_clear(B); + _nmod_vec_clear(x); + _nmod_vec_clear(y); + _nmod_vec_clear(y2); + nmod_mat_clear(X); + nmod_mat_clear(Y); + nmod_mat_clear(Y2); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-neg.c b/nmod_sparse_mat/test/t-neg.c new file mode 100644 index 0000000000..38b07d63ad --- /dev/null +++ b/nmod_sparse_mat/test/t-neg.c @@ -0,0 +1,78 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, B, C, D; + FLINT_TEST_INIT(state); + + flint_printf("neg...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + r = n_randint(state, 200); + c = n_randint(state, 200); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_init(B, r, c, mod); + nmod_sparse_mat_init(C, r, c, mod); + nmod_sparse_mat_init(D, r, c, mod); + + nmod_sparse_mat_randtest(A, state, 0, c); + nmod_sparse_mat_randtest(B, state, 0, c); + nmod_sparse_mat_randtest(C, state, 0, c); + nmod_sparse_mat_randtest(D, state, 0, c); + + nmod_sparse_mat_sub(C, A, B); + nmod_sparse_mat_neg(B, B); + nmod_sparse_mat_add(D, A, B); + + if (!nmod_sparse_mat_equal(C, D)) + { + flint_printf("FAIL\n"); + abort(); + } + + nmod_sparse_mat_neg(C, B); + nmod_sparse_mat_neg(B, B); + + if (!nmod_sparse_mat_equal(C, B)) + { + flint_printf("FAIL\n"); + abort(); + } + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(B); + nmod_sparse_mat_clear(C); + nmod_sparse_mat_clear(D); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-nullspace.c b/nmod_sparse_mat/test/t-nullspace.c new file mode 100644 index 0000000000..e5191c09cc --- /dev/null +++ b/nmod_sparse_mat/test/t-nullspace.c @@ -0,0 +1,96 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +/* #include */ +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, nreps = 100, r, c, i; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A; + nmod_mat_t X, AX; + slong rk[6]; +/* double elapsed[6] = {0, 0, 0, 0, 0, 0}; */ + slong discrep[6] = {0, 0, 0, 0, 0, 0}; + char *names[6] = {"rref", "lu", "Lanczos", "block Lanczos", "Wiedemann", "block Wiedemann"}; +/* struct timeval start, end; */ + FLINT_TEST_INIT(state); + + flint_printf("finding nullspace of A...."); + fflush(stdout); + + for (rep = 0; rep < nreps; ++rep) + { + if (rep % 5==0) {flint_printf("."); fflush(stdout);} + c = r = 200 + n_randint(state, 100); + do n = n_randtest_not_zero(state); + while (n <= 32 || !n_is_prime(n)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_randtest(A, state, c/20, c/10); + for (i = 0; i < 6; ++i) + { +/* gettimeofday(&start, NULL); */ + switch (i) + { + case 0: rk[0] = nmod_sparse_mat_nullspace_rref(X, A); break; + case 1: rk[1] = nmod_sparse_mat_nullspace_lu(X, A); break; + case 2: rk[2] = nmod_sparse_mat_nullspace_lanczos(X, A, state, 2); break; + case 3: rk[3] = nmod_sparse_mat_nullspace_block_lanczos(X, A, 8, state, 2); break; + case 4: rk[4] = nmod_sparse_mat_nullspace_wiedemann(X, A, state, 2); break; + case 5: rk[5] = nmod_sparse_mat_nullspace_block_wiedemann(X, A, 8, state, 2); break; + } + /* if (i == 0 && rk[0] == UWORD(0) ) { nmod_mat_clear(X); break;} */ +/* gettimeofday(&end, NULL); + elapsed[i] += (end.tv_sec - start.tv_sec) + .000001*(end.tv_usec-start.tv_usec); */ + if (X->c==0) continue; + nmod_mat_init(AX, A->r, X->c, n); + nmod_sparse_mat_mul_mat(AX, A, X); + /*nmod_mat_print_pretty(AX); */ + if (!nmod_mat_is_zero(AX)) + { + flint_printf("FAIL: %s!\n", names[i]); + if (i != 0) + flint_printf("Nullity should be %wd\n", rk[i-1]); + nmod_sparse_mat_print_pretty(A); + nmod_mat_print_pretty(X); + abort(); + } + if (rk[i] != rk[0]) discrep[i] += 1; + + nmod_mat_clear(X); + nmod_mat_clear(AX); + } + nmod_sparse_mat_clear(A); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + for (i = 0; i < 6; ++i) + { + flint_printf("Found nullspace with %s\n", names[i]); +/* flint_printf("\tAverage time %lf:\n", elapsed[i]/nreps); */ + if (discrep[i] > 0) + flint_printf("\tFailed to find full nullspace in %wd/%wd trials\n", + discrep[i], nreps); + } + return 0; +} diff --git a/nmod_sparse_mat/test/t-rref.c b/nmod_sparse_mat/test/t-rref.c new file mode 100644 index 0000000000..be8c071794 --- /dev/null +++ b/nmod_sparse_mat/test/t-rref.c @@ -0,0 +1,65 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, B; + nmod_mat_t dA; + FLINT_TEST_INIT(state); + + flint_printf("converting A to reduced row echelon form...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + r = n_randint(state, 100); + c = n_randint(state, 100); + do n = n_randtest_not_zero(state); + while (n <= 32 || !n_is_prime(n)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_init(B, r, c, mod); + nmod_mat_init(dA, r, c, n); + + nmod_sparse_mat_randtest(A, state, 0, n); + nmod_sparse_mat_to_dense(dA, A); + nmod_sparse_mat_rref(A); + nmod_mat_rref(dA); + nmod_sparse_mat_from_dense(B, dA); + if (!nmod_sparse_mat_equal(A, B)) + { + flint_printf("FAIL!\n"); + abort(); + } + + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(B); + nmod_mat_clear(dA); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-scalar_mul.c b/nmod_sparse_mat/test/t-scalar_mul.c new file mode 100644 index 0000000000..f861934b8b --- /dev/null +++ b/nmod_sparse_mat/test/t-scalar_mul.c @@ -0,0 +1,80 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "nmod_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, B, C, D; + FLINT_TEST_INIT(state); + + flint_printf("scalar_mul...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + r = n_randint(state, 200); + c = n_randint(state, 200); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_init(B, r, c, mod); + nmod_sparse_mat_init(C, r, c, mod); + nmod_sparse_mat_init(D, r, c, mod); + + nmod_sparse_mat_randtest(A, state, 0, c); + + nmod_sparse_mat_scalar_mul_nmod(B, A, c); + nmod_sparse_mat_scalar_mul_nmod(C, A, nmod_sub(c, UWORD(1), A->mod)); + + /* c*A - (c-1)*A == A */ + nmod_sparse_mat_sub(D, B, C); + + if (!nmod_sparse_mat_equal(A, D)) + { + flint_printf("FAIL\n"); + abort(); + } + + /* Aliasing */ + nmod_sparse_mat_scalar_mul_nmod(C, A, c); + nmod_sparse_mat_scalar_mul_nmod(A, A, c); + + if (!nmod_sparse_mat_equal(A, C)) + { + flint_printf("FAIL\n"); + abort(); + } + + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(B); + nmod_sparse_mat_clear(C); + nmod_sparse_mat_clear(D); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/test/t-solve.c b/nmod_sparse_mat/test/t-solve.c new file mode 100644 index 0000000000..7e5a64ae69 --- /dev/null +++ b/nmod_sparse_mat/test/t-solve.c @@ -0,0 +1,142 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +/*#include */ +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + int iter, ret; + slong rep, nreps = 100, r, c, i; + mp_limb_t n; + nmod_t mod; + nmod_mat_t dA; + nmod_sparse_mat_t A, At; + mp_ptr x, x2, b, Atb, Ax, AtAx; + slong niters[6] = {0, 0, 0, 0, 0, 0}; + slong psol[6] = {0, 0, 0, 0, 0, 0}; + slong nosol[6] = {0, 0, 0, 0, 0, 0}; + /*double elapsed[6] = {0, 0, 0, 0, 0};*/ + char *names[6] = {"rref", "lu", "Lanczos", "block Lanczos", "Wiedemann", "block Wiedemann"}; + /*struct timeval start, end;*/ + FLINT_TEST_INIT(state); + + flint_printf("solving Ax = b...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + if (rep % 5==0) {flint_printf("."); fflush(stdout);} + + c = r = 100 + n_randint(state, 50); + do n = n_randtest_not_zero(state); + while (n <= 32 || !n_is_prime(n)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_mat_init(dA, r, c, n); + x = _nmod_vec_init(c); + x2 = _nmod_vec_init(c); + b = _nmod_vec_init(r); + Ax = _nmod_vec_init(r); + + nmod_sparse_mat_randtest(A, state, c/20, c/10); + nmod_sparse_mat_to_dense(dA, A); + _nmod_vec_randtest(x, state, c, mod); + nmod_sparse_mat_mul_vec(b, A, x); + + for (i = 0; i < 6; ++i) + { + iter = 0; + /*gettimeofday(&start, NULL);*/ + switch (i) + { + case 0: ret = nmod_sparse_mat_solve_rref(x2, A, b); break; + case 1: ret = nmod_sparse_mat_solve_lu(x2, A, b); break; + case 2: do ret = nmod_sparse_mat_solve_lanczos(x2, A, b, state); while (ret == 0 && ++iter < 30); break; + case 3: do ret = nmod_sparse_mat_solve_block_lanczos(x2, A, b, 8, state); while (ret == 0 && ++iter < 30); break; + case 4: ret = nmod_sparse_mat_solve_wiedemann(x2, A, b); break; + case 5: do ret = nmod_sparse_mat_solve_block_wiedemann(x2, A, b, 4, state); while (ret == 0 && ++iter < 3); break; + } + /*gettimeofday(&end, NULL); + elapsed[i] += (end.tv_sec - start.tv_sec) + .000001*(end.tv_usec-start.tv_usec);*/ + if (ret == 0) nosol[i] += 1; + else + { + niters[i] += iter; + nmod_sparse_mat_mul_vec(Ax, A, x2); + if (!_nmod_vec_equal(b, Ax, A->r)) + { + if (i == 2 || i == 3) + { + nmod_sparse_mat_init(At, c, r, mod); + AtAx = _nmod_vec_init(c); + Atb = _nmod_vec_init(c); + nmod_sparse_mat_transpose(At, A); + nmod_sparse_mat_mul_vec(AtAx, At, Ax); + nmod_sparse_mat_mul_vec(Atb, At, b); + if (!_nmod_vec_equal(AtAx, Atb, A->c)) + { + flint_printf("FAIL on %s: AtAx != Atb\n", names[i]); + abort(); + } + else psol[i] += 1; + flint_free(AtAx); + flint_free(Atb); + nmod_sparse_mat_clear(At); + } + else + { + flint_printf("FAIL on %s: Ax != b\n", names[i]); + flint_printf("A = "); + nmod_sparse_mat_print_pretty(A); + flint_printf("x = "); + _nmod_vec_print_pretty(x, c, mod); + flint_printf("x2 = "); + _nmod_vec_print_pretty(x2, c, mod); + flint_printf("Ax2 = "); + _nmod_vec_print_pretty(Ax, r, mod); + flint_printf("b = "); + _nmod_vec_print_pretty(b, r, mod); + abort(); + } + } + } + } + flint_free(x); + flint_free(x2); + flint_free(b); + flint_free(Ax); + nmod_sparse_mat_clear(A); + } + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + for (i = 0; i < 6; ++i) + { + flint_printf("Solved with %s\n", names[i]); + /*flint_printf("\tAverage time: %lf\n", elapsed[i]/nreps);*/ + if (nosol[i]) + flint_printf("\tFound no solution for %wd/%wd examples\n", nosol[i], nreps); + if (psol[i]) + flint_printf("\tFound pseudo-solution for %wd/%wd examples\n", psol[i], nreps); + if (niters[i]) + flint_printf("\tRequired %f extra iters per solution (on average).\n", (double)niters[i]/nreps); + } + return 0; +} diff --git a/nmod_sparse_mat/test/t-transpose.c b/nmod_sparse_mat/test/t-transpose.c new file mode 100644 index 0000000000..26b273b517 --- /dev/null +++ b/nmod_sparse_mat/test/t-transpose.c @@ -0,0 +1,68 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, r, c; + mp_limb_t n; + nmod_t mod; + nmod_sparse_mat_t A, B, C; + FLINT_TEST_INIT(state); + + + flint_printf("transpose...."); + fflush(stdout); + + /* Rectangular transpose, same modulus */ + for (rep = 0; rep < 1000; rep++) + { + r = n_randint(state, 200); + c = n_randint(state, 200); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + nmod_sparse_mat_init(A, r, c, mod); + nmod_sparse_mat_init(B, c, r, mod); + nmod_sparse_mat_init(C, r, c, mod); + + nmod_sparse_mat_randtest(A, state, 0, c); + nmod_sparse_mat_randtest(B, state, 0, r); + nmod_sparse_mat_randtest(C, state, 0, c); + + nmod_sparse_mat_transpose(B, A); + nmod_sparse_mat_transpose(C, B); + + if (!nmod_sparse_mat_equal(C, A)) + { + flint_printf("FAIL: C != A\n"); + abort(); + } + + nmod_sparse_mat_clear(A); + nmod_sparse_mat_clear(B); + nmod_sparse_mat_clear(C); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_mat/transpose.c b/nmod_sparse_mat/transpose.c new file mode 100644 index 0000000000..bf1e8d8fe8 --- /dev/null +++ b/nmod_sparse_mat/transpose.c @@ -0,0 +1,64 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" + +void +nmod_sparse_mat_transpose(nmod_sparse_mat_t B, const nmod_sparse_mat_t A) +{ + slong r, c, i, j; + nmod_sparse_entry_struct *Ae, *Be; + nmod_sparse_vec_struct *row; + FLINT_ASSERT(M->r == A->c); + FLINT_ASSERT(A->r == M->c); + + /* Get number of nnzs in each column of A (thus each row of B) */ + for (c = 0; c < A->c; ++c) + { + B->rows[c].nnz = 0; + } + for (r = 0; r < A->r; ++r) + { + for (i = 0; i < A->rows[r].nnz; ++i) + { + c = A->rows[r].entries[i].ind; + if (c >= A->c) break; + B->rows[c].nnz += 1; + } + } + /* Allocate space for nnz and reset counters */ + for (c = 0; c < A->c; ++c) + { + row = &B->rows[c]; + if (row->nnz == 0) nmod_sparse_vec_clear(row); + else row->entries = flint_realloc(row->entries, row->nnz*sizeof(*row->entries)); + row->nnz = 0; + } + /* Put entries into transposed matrix */ + for (r = 0; r < A->r; ++r) + { + for (i = 0; i < A->rows[r].nnz; ++i) + { + Ae = &A->rows[r].entries[i]; + c = Ae->ind; + if (c >= A->c) break; + j = B->rows[c].nnz++; + Be = &B->rows[c].entries[j]; + Be->ind = r, Be->val = Ae->val; + } + } + B->c_off = 0; +} diff --git a/nmod_sparse_mat/window_init.c b/nmod_sparse_mat/window_init.c new file mode 100644 index 0000000000..ee87c93f1f --- /dev/null +++ b/nmod_sparse_mat/window_init.c @@ -0,0 +1,31 @@ +/* + Copyright (C) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_mat.h" + +void nmod_sparse_mat_window_init(nmod_sparse_mat_t window, const nmod_sparse_mat_t mat, slong r1, slong c1, slong r2, slong c2) +{ + slong i; + r2 = FLINT_MIN(r2, mat->r), r1 = FLINT_MIN(r1, r2); + c2 = FLINT_MIN(c2, mat->c), c1 = FLINT_MIN(c1, c2); + window->mod = mat->mod; + window->r = r2-r1; + window->c = c2-c1; + window->c_off = c1; + window->rows = flint_malloc(window->r*sizeof(*window->rows)); + for (i = 0; i < window->r; ++i) + nmod_sparse_vec_window_init(&window->rows[i], &mat->rows[i+r1], c1, c2); +} diff --git a/nmod_sparse_vec.h b/nmod_sparse_vec.h new file mode 100644 index 0000000000..cfc0d0648c --- /dev/null +++ b/nmod_sparse_vec.h @@ -0,0 +1,324 @@ +/* + Copyright (C) 2010 William Hart + Copyright (C) 2010,2011 Fredrik Johansson + Copyright (C) 2014 Ashish Kedia + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#ifndef NMOD_SPARSE_VEC_H +#define NMOD_SPARSE_VEC_H + +#ifdef NMOD_SPARSE_VEC_INLINES_C +#define NMOD_SPARSE_VEC_INLINE FLINT_DLL +#else +#define NMOD_SPARSE_VEC_INLINE static __inline__ +#endif + +#undef ulong +#define ulong ulongxx /* interferes with system includes */ +#include +#include +#undef ulong +#include +#define ulong mp_limb_t + +#include "flint.h" +#include "longlong.h" +#include "ulong_extras.h" +#include "nmod_vec.h" +#include "fmpz.h" +#include "thread_support.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct { + slong ind; + mp_limb_t val; +} nmod_sparse_entry_struct; + +typedef nmod_sparse_entry_struct nmod_sparse_entry_t[1]; + +typedef struct { + nmod_sparse_entry_struct *entries; + slong nnz; +} nmod_sparse_vec_struct; + +typedef nmod_sparse_vec_struct nmod_sparse_vec_t[1]; + +NMOD_SPARSE_VEC_INLINE +int nmod_sparse_entry_cmp(const void *va, const void *vb) +{ + const nmod_sparse_entry_struct *a = va; + const nmod_sparse_entry_struct *b = vb; + if (a->ind < b->ind) return -1; + if (b->ind < a->ind) return 1; + return 0; +} + + +/* Memory management */ +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_init(nmod_sparse_vec_t vec) +{ + memset(vec, 0, sizeof(*vec)); +} +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_clear(nmod_sparse_vec_t vec) +{ + flint_free(vec->entries); + memset(vec, 0, sizeof(*vec)); +} + +NMOD_SPARSE_VEC_INLINE +void _nmod_sparse_vec_resize(nmod_sparse_vec_t vec, slong nnz) +{ + FLINT_ASSERT(nnz >= 0); + if (nnz == 0) nmod_sparse_vec_clear(vec); + else if (nnz != vec->nnz) + { + vec->entries = flint_realloc(vec->entries, nnz*sizeof(*vec->entries)); + } + vec->nnz = nnz; +} + +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_resize(nmod_sparse_vec_t vec, slong cols) +{ + slong i; + FLINT_ASSERT(cols >= 0); + if (vec->nnz == 0) return; + for (i = 0; i < vec->nnz; ++i) { + if (vec->entries[i].ind >= cols) + { + break; + } + } + _nmod_sparse_vec_resize(vec, i); +} + + +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_swap(nmod_sparse_vec_t vec1, nmod_sparse_vec_t vec2) +{ + nmod_sparse_vec_t tmp; + *tmp = *vec1, *vec1 = *vec2, *vec2 = *tmp; +} + +/* Vector indexing */ +FLINT_DLL +mp_limb_t * nmod_sparse_vec_at(nmod_sparse_vec_t vec, slong i); + +/* One-time instantiation */ +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_zero(nmod_sparse_vec_t vec) +{ + nmod_sparse_vec_clear(vec); +} + +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_one(nmod_sparse_vec_t vec, slong ind) +{ + vec->nnz = 1; + vec->entries = realloc(vec->entries, sizeof(*vec->entries)); + vec->entries[0].ind = ind; + vec->entries[0].val = UWORD(1); +} + +FLINT_DLL +void nmod_sparse_vec_set(nmod_sparse_vec_t vec, const nmod_sparse_vec_t src, slong ioff); + +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_set_entry(nmod_sparse_vec_t v, slong ind, mp_limb_t val) +{ + mp_limb_t *oval = nmod_sparse_vec_at(v, ind); + if (oval == NULL) + { + v->entries = flint_realloc(v->entries, (v->nnz+1)*sizeof(*v->entries)); + v->entries[v->nnz].ind = ind; + v->entries[v->nnz].val = val; + v->nnz += 1; + if (v->nnz >= 2 && v->entries[v->nnz-2].ind > ind) + qsort(v->entries, v->nnz, sizeof(*v->entries), nmod_sparse_entry_cmp); + } + else *oval = val; +} + +NMOD_SPARSE_VEC_INLINE +void _nmod_sparse_vec_append_entry(nmod_sparse_vec_t v, slong ind, mp_limb_t val) +{ + mp_limb_t *oval = nmod_sparse_vec_at(v, ind); + if(oval == NULL) + { + v->entries = flint_realloc(v->entries, (v->nnz+1)*sizeof(*v->entries)); + v->entries[v->nnz].ind = ind; + v->entries[v->nnz].val = val; + v->nnz += 1; + if (v->nnz >= 2 && v->entries[v->nnz-2].ind > ind) + qsort(v->entries, v->nnz, sizeof(*v->entries), nmod_sparse_entry_cmp); + } + else *oval = val; +} + +FLINT_DLL +void nmod_sparse_vec_from_entries(nmod_sparse_vec_t vec, slong * inds, mp_limb_t * vals, slong nnz); + +/* Vector comparison */ +NMOD_SPARSE_VEC_INLINE +int nmod_sparse_vec_is_zero(const nmod_sparse_vec_t vec) +{ + return vec->nnz == 0; +} + +FLINT_DLL +int nmod_sparse_vec_equal(const nmod_sparse_vec_t vec1, const nmod_sparse_vec_t vec2, slong ioff); + +/* Convert from/to dense vector */ +FLINT_DLL +void nmod_sparse_vec_from_dense(nmod_sparse_vec_t vec, mp_srcptr src, slong len); + +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_to_dense(mp_ptr vec, const nmod_sparse_vec_t src, slong len) +{ + slong i; + _nmod_vec_zero(vec, len); + for (i = 0; i < src->nnz; ++i) vec[src->entries[i].ind] = src->entries[i].val; +} + +/* Windows and concatenation */ +FLINT_DLL +void nmod_sparse_vec_window_init(nmod_sparse_vec_t window, const nmod_sparse_vec_t vec, slong i1, slong i2); + + +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_window_clear(nmod_sparse_vec_t window) +{ + memset(window, 0, sizeof(*window)); +} + +FLINT_DLL +void nmod_sparse_vec_concat(nmod_sparse_vec_t res, const nmod_sparse_vec_t vec1, const nmod_sparse_vec_t vec2, slong len1); + +FLINT_DLL +void nmod_sparse_vec_split(nmod_sparse_vec_t res1, nmod_sparse_vec_t res2, const nmod_sparse_vec_t vec, slong ind); + +/* Vector permutation */ +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_permute_inds(nmod_sparse_vec_t vec, slong *P) +{ + slong i; + for (i = 0; i < vec->nnz; ++i) vec->entries[i].ind = P[vec->entries[i].ind]; +} + +/* Random vector generation */ +FLINT_DLL +void nmod_sparse_vec_randtest(nmod_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, nmod_t mod); + +/* Vector display */ +FLINT_DLL +void nmod_sparse_vec_print_pretty(const nmod_sparse_vec_t vec, slong ioff, slong maxi, nmod_t mod); + +/* Vector operations */ +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_neg(nmod_sparse_vec_t v, const nmod_sparse_vec_t u, nmod_t mod) +{ + slong i; + nmod_sparse_vec_set(v, u, 0); + for (i = 0; i < v->nnz; ++i) v->entries[i].val = nmod_neg(v->entries[i].val, mod); +} + +FLINT_DLL +void nmod_sparse_vec_scalar_mul_nmod(nmod_sparse_vec_t v, const nmod_sparse_vec_t u, mp_limb_t c, nmod_t mod); + +NMOD_SPARSE_VEC_INLINE +void nmod_sparse_vec_scalar_mul_fmpz(nmod_sparse_vec_t v, const nmod_sparse_vec_t u, const fmpz_t c, nmod_t mod) +{ + fmpz_t d; + fmpz_init(d); + fmpz_mod_ui(d, c, mod.n); + nmod_sparse_vec_scalar_mul_nmod(v, u, fmpz_get_ui(d), mod); + fmpz_clear(d); +} + +/* Utility macros used by binary vector operations */ +/* Compute total number of indices between two sparse vectors */ +NMOD_SPARSE_VEC_INLINE +slong _nmod_sparse_vec_union_nnz(const nmod_sparse_vec_t u, const nmod_sparse_vec_t v) +{ + slong i, j, nnz = 0; + for (i = j = 0; i < u->nnz && j < v->nnz; ++nnz) + { + if (u->entries[i].ind == v->entries[j].ind) ++i, ++j; + else if (u->entries[i].ind < v->entries[j].ind) ++i; + else if (u->entries[i].ind > v->entries[j].ind) ++j; + } + nnz += u->nnz - i + v->nnz - j; + return nnz; +} + +/* Iterate through u and v in descending order, assigning sorted indices to w */ +/* Returns -1 if u and v are both exhausted, + 2 if we->ind = ue->ind == ve->ind + 1 if we->ind = ve->ind > ue->ind (or u exhausted), + 0 if we->ind = ue->ind > ve->ind (or v exhausted). */ +NMOD_SPARSE_VEC_INLINE +slong _nmod_sparse_vector_merge_descend(nmod_sparse_entry_struct **we, + nmod_sparse_entry_struct **ue, + nmod_sparse_entry_struct **ve, + const nmod_sparse_vec_t u, + const nmod_sparse_vec_t v) +{ + slong uind = (*ue==u->entries) ? -1 : (*ue-1)->ind; + slong vind = (*ve==v->entries) ? -1 : (*ve-1)->ind; + if (uind == -1 && vind == -1) return -1; + if (uind == vind) {--*ue, --*ve, --*we; (*we)->ind = uind; return 2;} + if (uind < vind) {--*ve, --*we; (*we)->ind = vind; return 1;} + --*ue, --*we; (*we)->ind = uind; return 0; +} + +/* Like resize, but removes entries from the front of the vector */ +NMOD_SPARSE_VEC_INLINE +void _nmod_sparse_vector_shift_left (nmod_sparse_vec_t v, slong amt) +{ + if (amt == v->nnz) nmod_sparse_vec_clear(v); + else if (amt > 0) + { + v->nnz -= amt; + memmove(v->entries, v->entries + amt, v->nnz*sizeof(*v->entries)); + v->entries = flint_realloc(v->entries, v->nnz*sizeof(*v->entries)); + } +} + +FLINT_DLL +void nmod_sparse_vec_add(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, nmod_t mod); + +FLINT_DLL +void nmod_sparse_vec_sub(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, nmod_t mod); + +FLINT_DLL +void nmod_sparse_vec_scalar_addmul_nmod(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, const mp_limb_t c, nmod_t mod); + +FLINT_DLL +void nmod_sparse_vec_scalar_submul_nmod(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, const mp_limb_t c, nmod_t mod); + + +FLINT_DLL +mp_limb_t nmod_sparse_vec_dot(const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, nmod_t mod); + +FLINT_DLL +mp_limb_t nmod_sparse_vec_dot_dense(const nmod_sparse_vec_t u, mp_srcptr v, nmod_t mod); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nmod_sparse_vec/add.c b/nmod_sparse_vec/add.c new file mode 100644 index 0000000000..173c4b6d6d --- /dev/null +++ b/nmod_sparse_vec/add.c @@ -0,0 +1,45 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_add(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, nmod_t mod) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + nmod_sparse_entry_struct *ue, *ve, *we; + + /* Check for simpler operations first */ + if (vnnz == 0) nmod_sparse_vec_set(w, u, 0); + else if (unnz == 0) nmod_sparse_vec_set(w, v, 0); + else + { + wnnz = _nmod_sparse_vec_union_nnz (u, v); + w->entries = flint_realloc(w->entries, wnnz*sizeof(*w->entries)); + w->nnz = wnnz; + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _nmod_sparse_vector_merge_descend (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: we->val = ue->val; break; + case 1: we->val = ve->val; break; + default: we->val = nmod_add(ue->val, ve->val, mod); + if (we->val == UWORD(0)) we++; + } + } + _nmod_sparse_vector_shift_left (w, we - w->entries); + } +} diff --git a/nmod_sparse_vec/at.c b/nmod_sparse_vec/at.c new file mode 100644 index 0000000000..b7d385c555 --- /dev/null +++ b/nmod_sparse_vec/at.c @@ -0,0 +1,27 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +mp_limb_t *nmod_sparse_vec_at(nmod_sparse_vec_t vec, slong i) +{ + /* TODO: binary search */ + slong j; + for (j = 0; j < vec->nnz; ++j) + if (vec->entries[j].ind==i) return &vec->entries[j].val; + return NULL; +} + diff --git a/nmod_sparse_vec/concat.c b/nmod_sparse_vec/concat.c new file mode 100644 index 0000000000..0257fd6245 --- /dev/null +++ b/nmod_sparse_vec/concat.c @@ -0,0 +1,31 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_concat(nmod_sparse_vec_t res, const nmod_sparse_vec_t vec1, const nmod_sparse_vec_t vec2, slong len1) +{ + res->nnz = vec1->nnz+vec2->nnz; + if (res->nnz == 0) nmod_sparse_vec_clear(res); + else + { + slong i; + res->entries = flint_realloc(res->entries, res->nnz*sizeof(*res->entries)); + memcpy(res->entries, vec1->entries, vec1->nnz*sizeof(*res->entries)); + memcpy(res->entries+vec1->nnz, vec2->entries, vec2->nnz*sizeof(*res->entries)); + for (i = vec1->nnz; i < res->nnz; ++i) res->entries[i].ind += len1; + } +} diff --git a/nmod_sparse_vec/dot.c b/nmod_sparse_vec/dot.c new file mode 100644 index 0000000000..47876c1dc4 --- /dev/null +++ b/nmod_sparse_vec/dot.c @@ -0,0 +1,34 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +mp_limb_t nmod_sparse_vec_dot(const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, nmod_t mod) +{ + slong i, j; + mp_limb_t ret = UWORD(0); + for (i = j = 0; i < u->nnz && j < v->nnz; ) + { + if (u->entries[i].ind == v->entries[j].ind) + { + ret = nmod_addmul(ret, u->entries[i].val, v->entries[j].val, mod); + ++i; ++j; + } + else if (u->entries[i].ind < v->entries[j].ind) ++i; + else if (u->entries[i].ind > v->entries[j].ind) ++j; + } + return ret; +} diff --git a/nmod_sparse_vec/dot_dense.c b/nmod_sparse_vec/dot_dense.c new file mode 100644 index 0000000000..dfa7bce0fa --- /dev/null +++ b/nmod_sparse_vec/dot_dense.c @@ -0,0 +1,25 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +mp_limb_t nmod_sparse_vec_dot_dense(const nmod_sparse_vec_t u, mp_srcptr v, nmod_t mod) +{ + slong i; + mp_limb_t ret = UWORD(0); + for (i = 0; i < u->nnz; ++i) NMOD_ADDMUL(ret, u->entries[i].val, v[u->entries[i].ind], mod); + return ret; +} diff --git a/nmod_sparse_vec/equal.c b/nmod_sparse_vec/equal.c new file mode 100644 index 0000000000..1c1ae4d4b0 --- /dev/null +++ b/nmod_sparse_vec/equal.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +int nmod_sparse_vec_equal(const nmod_sparse_vec_t vec1, const nmod_sparse_vec_t vec2, slong ioff) +{ + slong i; + if (vec1->nnz != vec2->nnz) return 0; + for (i = 0; i < vec1->nnz; ++i) + { + if ((vec1->entries[i].ind != vec2->entries[i].ind + ioff) || + (vec1->entries[i].val != vec2->entries[i].val)) return 0; + } + return 1; +} diff --git a/nmod_sparse_vec/from_dense.c b/nmod_sparse_vec/from_dense.c new file mode 100644 index 0000000000..57eceaf51d --- /dev/null +++ b/nmod_sparse_vec/from_dense.c @@ -0,0 +1,36 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_from_dense(nmod_sparse_vec_t vec, mp_srcptr src, slong len) +{ + slong i; + nmod_sparse_entry_struct *e; + if (len == 0) nmod_sparse_vec_clear(vec); + else { + vec->entries = flint_realloc(vec->entries, len*sizeof(*vec->entries)); + vec->nnz = 0; + for (i = 0; i < len; ++i) + { + if (src[i] == UWORD(0)) continue; + e = &vec->entries[vec->nnz++]; + e->ind = i, e->val = src[i]; + } + if (vec->nnz == 0) nmod_sparse_vec_clear(vec); + else vec->entries = flint_realloc(vec->entries, vec->nnz*sizeof(*vec->entries)); + } +} \ No newline at end of file diff --git a/nmod_sparse_vec/from_entries.c b/nmod_sparse_vec/from_entries.c new file mode 100644 index 0000000000..dbaa73ebe6 --- /dev/null +++ b/nmod_sparse_vec/from_entries.c @@ -0,0 +1,32 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_from_entries(nmod_sparse_vec_t vec, slong * inds, mp_limb_t * vals, slong nnz) +{ + if (nnz == 0) nmod_sparse_vec_clear(vec); + else { + slong i; + vec->nnz = nnz; + vec->entries = flint_realloc(vec->entries, nnz*sizeof(*vec->entries)); + for (i = 0; i < nnz; ++i) + { + vec->entries[i].ind = inds[i]; + vec->entries[i].val = vals[i]; + } + } +} diff --git a/nmod_sparse_vec/print_pretty.c b/nmod_sparse_vec/print_pretty.c new file mode 100644 index 0000000000..46797a3e08 --- /dev/null +++ b/nmod_sparse_vec/print_pretty.c @@ -0,0 +1,39 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "ulong_extras.h" + +void +nmod_sparse_vec_print_pretty(const nmod_sparse_vec_t vec, slong ioff, slong maxi, nmod_t mod) +{ + slong i; + char ind_fmt[FLINT_BITS + 5]; + char val_fmt[FLINT_BITS + 5]; + + flint_sprintf(ind_fmt, "%%%dwd:", n_sizeinbase(maxi, 10)); + flint_sprintf(val_fmt, "%%%dwd", n_sizeinbase(mod.n, 10)); + + flint_printf("["); + for (i = 0; i < vec->nnz; i++) + { + flint_printf(ind_fmt, vec->entries[i].ind - ioff); + flint_printf(val_fmt, vec->entries[i].val); + if (i + 1 < vec->nnz) flint_printf(" "); + } + flint_printf("]\n"); +} + diff --git a/nmod_sparse_vec/randtest.c b/nmod_sparse_vec/randtest.c new file mode 100644 index 0000000000..4004859a1e --- /dev/null +++ b/nmod_sparse_vec/randtest.c @@ -0,0 +1,43 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_randtest(nmod_sparse_vec_t vec, flint_rand_t state, slong nnz, slong len, nmod_t mod) +{ + slong i, j; + mp_limb_t v; + nnz = FLINT_MIN(nnz, len); + vec->nnz = nnz; + if (nnz == 0) {vec->entries = NULL; return;} + + vec->entries = flint_realloc(vec->entries, nnz*sizeof(*vec->entries)); + for (i = 0; i < nnz; ++i) + { + do v = n_randtest(state) % mod.n; + while (v == UWORD(0)); + vec->entries[i].ind = i; + vec->entries[i].val = v; + } + + /* Use resevoir sampling to get random support */ + for (j = nnz; j < len; ++j) + { + i = n_randint(state, j+1); + if (i < nnz) vec->entries[i].ind = j; + } + qsort(vec->entries, nnz, sizeof(*vec->entries), nmod_sparse_entry_cmp); +} diff --git a/nmod_sparse_vec/scalar_addmul.c b/nmod_sparse_vec/scalar_addmul.c new file mode 100644 index 0000000000..fd4c3c0563 --- /dev/null +++ b/nmod_sparse_vec/scalar_addmul.c @@ -0,0 +1,47 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_scalar_addmul_nmod(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, mp_limb_t c, nmod_t mod) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + nmod_sparse_entry_struct *ue, *ve, *we; + + /* Check for simpler operations first */ + if (c == UWORD(0) || vnnz == 0) nmod_sparse_vec_set(w, u, 0); + else if (c == UWORD(1)) nmod_sparse_vec_add(w, u, v, mod); + else if (c + UWORD(1) == mod.n) nmod_sparse_vec_sub(w, u, v, mod); + else if (unnz == 0) nmod_sparse_vec_scalar_mul_nmod(w, v, c, mod); + else + { + wnnz = _nmod_sparse_vec_union_nnz (u, v); + w->entries = flint_realloc(w->entries, wnnz*sizeof(*w->entries)); + w->nnz = wnnz; + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _nmod_sparse_vector_merge_descend (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: we->val = ue->val; break; + case 1: we->val = nmod_mul(ve->val, c, mod); break; + default: we->val = nmod_add (ue->val, nmod_mul(ve->val, c, mod), mod); + if (we->val == UWORD(0)) we++; + } + } + _nmod_sparse_vector_shift_left (w, we - w->entries); + } +} diff --git a/nmod_sparse_vec/scalar_mul.c b/nmod_sparse_vec/scalar_mul.c new file mode 100644 index 0000000000..f5391c9b25 --- /dev/null +++ b/nmod_sparse_vec/scalar_mul.c @@ -0,0 +1,30 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_scalar_mul_nmod(nmod_sparse_vec_t v, const nmod_sparse_vec_t u, mp_limb_t c, nmod_t mod) +{ + if (c == UWORD(0)) nmod_sparse_vec_zero(v); + else if (c == UWORD(1)) nmod_sparse_vec_set(v, u, 0); + else if (c==mod.n-UWORD(1)) nmod_sparse_vec_neg(v, u, mod); + else + { + slong i; + nmod_sparse_vec_set(v, u, 0); + for (i = 0; i < v->nnz; ++i) v->entries[i].val = nmod_mul(v->entries[i].val, c, mod); + } +} \ No newline at end of file diff --git a/nmod_sparse_vec/scalar_submul.c b/nmod_sparse_vec/scalar_submul.c new file mode 100644 index 0000000000..3625d175a5 --- /dev/null +++ b/nmod_sparse_vec/scalar_submul.c @@ -0,0 +1,47 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_scalar_submul_nmod(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, mp_limb_t c, nmod_t mod) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + nmod_sparse_entry_struct *ue, *ve, *we; + + /* Check for simpler operations first */ + if (c == UWORD(0) || vnnz == 0) nmod_sparse_vec_set(w, u, 0); + else if (c == UWORD(1)) nmod_sparse_vec_sub(w, u, v, mod); + else if (c + UWORD(1) == mod.n) nmod_sparse_vec_add(w, u, v, mod); + else if (unnz == 0) nmod_sparse_vec_scalar_mul_nmod(w, v, nmod_neg(c, mod), mod); + else + { + wnnz = _nmod_sparse_vec_union_nnz (u, v); + w->entries = flint_realloc(w->entries, wnnz*sizeof(*w->entries)); + w->nnz = wnnz; + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _nmod_sparse_vector_merge_descend (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: we->val = ue->val; break; + case 1: we->val = nmod_mul(ve->val, nmod_neg(c, mod), mod); break; + default: we->val = nmod_sub(ue->val, nmod_mul(ve->val, c, mod), mod); + if (we->val == UWORD(0)) we++; + } + } + _nmod_sparse_vector_shift_left (w, we - w->entries); + } +} diff --git a/nmod_sparse_vec/set.c b/nmod_sparse_vec/set.c new file mode 100644 index 0000000000..e469a1fbf9 --- /dev/null +++ b/nmod_sparse_vec/set.c @@ -0,0 +1,34 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_set(nmod_sparse_vec_t vec, const nmod_sparse_vec_t src, slong ioff) +{ + slong i; + if (vec==src) return; + if (src->nnz == 0) nmod_sparse_vec_clear(vec); + else + { + vec->entries = flint_realloc(vec->entries, src->nnz*sizeof(*vec->entries)); + memcpy(vec->entries, src->entries, src->nnz*sizeof(*vec->entries)); + vec->nnz = src->nnz; + for (i = 0; i < vec->nnz; ++i) + { + vec->entries[i].ind -= ioff; + } + } +} \ No newline at end of file diff --git a/nmod_sparse_vec/split.c b/nmod_sparse_vec/split.c new file mode 100644 index 0000000000..766f4afc7d --- /dev/null +++ b/nmod_sparse_vec/split.c @@ -0,0 +1,36 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_split(nmod_sparse_vec_t res1, nmod_sparse_vec_t res2, const nmod_sparse_vec_t vec, slong ind) +{ + slong i; + for (i = 0; i < vec->nnz; ++i) if (vec->entries[i].ind >= ind) break; + if (i==0) nmod_sparse_vec_clear(res1); + else { + res1->nnz = i; + res1->entries = flint_realloc(res1->entries, res1->nnz*sizeof(*res1->entries)); + memcpy(res1->entries, vec->entries, res1->nnz*sizeof(*res1->entries)); + } + if (i==vec->nnz) nmod_sparse_vec_clear(res2); + else { + res2->nnz = vec->nnz - i; + res2->entries = flint_realloc(res2->entries, res2->nnz*sizeof(*res2->entries)); + memcpy(res2->entries, vec->entries+i, res2->nnz*sizeof(*res2->entries)); + for (i = 0; i < res2->nnz; ++i) res2->entries[i].ind -= ind; + } +} diff --git a/nmod_sparse_vec/sub.c b/nmod_sparse_vec/sub.c new file mode 100644 index 0000000000..a88ba18299 --- /dev/null +++ b/nmod_sparse_vec/sub.c @@ -0,0 +1,45 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_sub(nmod_sparse_vec_t w, const nmod_sparse_vec_t u, const nmod_sparse_vec_t v, nmod_t mod) +{ + slong unnz = u->nnz, vnnz = v->nnz, wnnz, k; + nmod_sparse_entry_struct *ue, *ve, *we; + + /* Check for simpler operations first */ + if (vnnz == 0) nmod_sparse_vec_set(w, u, 0); + else if (unnz == 0) nmod_sparse_vec_neg(w, v, mod); + else + { + wnnz = _nmod_sparse_vec_union_nnz (u, v); + w->entries = flint_realloc(w->entries, wnnz*sizeof(*w->entries)); + w->nnz = wnnz; + ue = u->entries + unnz, ve = v->entries + vnnz, we = w->entries + wnnz; + while ((k = _nmod_sparse_vector_merge_descend (&we, &ue, &ve, u, v)) >= 0) + { + switch(k) + { + case 0: we->val = ue->val; break; + case 1: we->val = nmod_neg(ve->val, mod); break; + default: we->val = nmod_sub(ue->val, ve->val, mod); + if (we->val == UWORD(0)) we++; + } + } + _nmod_sparse_vector_shift_left (w, we - w->entries); + } +} diff --git a/nmod_sparse_vec/test/t-add.c b/nmod_sparse_vec/test/t-add.c new file mode 100644 index 0000000000..5d819fece4 --- /dev/null +++ b/nmod_sparse_vec/test/t-add.c @@ -0,0 +1,96 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz; + mp_limb_t n; + nmod_t mod; + nmod_sparse_vec_t u, v, w, x; + + FLINT_TEST_INIT(state); + + flint_printf("add/sub...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + len = n_randint(state, 40); + nnz = n_randint(state, len+1); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + + nmod_sparse_vec_init(u); + nmod_sparse_vec_init(v); + nmod_sparse_vec_init(w); + nmod_sparse_vec_init(x); + + nmod_sparse_vec_randtest(u, state, nnz, len, mod); + nmod_sparse_vec_randtest(v, state, nnz, len, mod); + + nmod_sparse_vec_add(w, u, v, mod); + nmod_sparse_vec_sub(x, w, v, mod); + + if (!nmod_sparse_vec_equal(u, x, 0)) + { + flint_printf("FAIL: u != u+v-v\n"); + abort(); + } + + nmod_sparse_vec_add(u, u, v, mod); + if (!nmod_sparse_vec_equal(u, w, 0)) + { + flint_printf("FAIL: (u += v) != u + v\n"); + abort(); + } + + nmod_sparse_vec_sub(u, u, v, mod); + if (!nmod_sparse_vec_equal(u, x, 0)) + { + flint_printf("FAIL: ((u += v) -= v) != u+v-v\n"); + abort(); + } + + nmod_sparse_vec_add(u, v, u, mod); + if (!nmod_sparse_vec_equal(u, w, 0)) + { + flint_printf("FAIL: (u = v + u) != u+v\n"); + abort(); + } + + nmod_sparse_vec_sub(v, u, v, mod); + if (!nmod_sparse_vec_equal(v, x, 0)) + { + flint_printf("FAIL: (u = v + u) != u+v\n"); + abort(); + } + nmod_sparse_vec_clear(u); + nmod_sparse_vec_clear(v); + nmod_sparse_vec_clear(w); + nmod_sparse_vec_clear(x); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_vec/test/t-concat.c b/nmod_sparse_vec/test/t-concat.c new file mode 100644 index 0000000000..f57e103e85 --- /dev/null +++ b/nmod_sparse_vec/test/t-concat.c @@ -0,0 +1,101 @@ +/* + Copyright (C) 2015 Elena Sergeicheva + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "ulong_extras.h" + +int main(void) +{ + slong rep, len, nnz; + mp_limb_t n; + nmod_t mod; + nmod_sparse_vec_t u, v, w; + nmod_sparse_vec_t window1, window2; + FLINT_TEST_INIT(state); + + flint_printf("concat...."); + fflush(stdout); + + for (rep = 0; rep < 100; rep++) + { + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + + nmod_sparse_vec_init(u); + nmod_sparse_vec_init(v); + nmod_sparse_vec_init(w); + + nmod_sparse_vec_randtest(u, state, nnz, len, mod); + nmod_sparse_vec_randtest(v, state, nnz, len, mod); + nmod_sparse_vec_randtest(w, state, nnz, len, mod); + + nmod_sparse_vec_concat(w, u, v, len); + + nmod_sparse_vec_window_init(window1, w, 0, len); + nmod_sparse_vec_window_init(window2, w, len, 2*len); + + if (!(nmod_sparse_vec_equal(window1, u, 0) && nmod_sparse_vec_equal(window2, v, len))) + { + flint_printf("u = "); + nmod_sparse_vec_print_pretty(u, 0, len, mod); + flint_printf("v = \n"); + nmod_sparse_vec_print_pretty(v, 0, len, mod); + flint_printf("u | v = \n"); + nmod_sparse_vec_print_pretty(w, 0, len, mod); + flint_printf("window1 = \n"); + nmod_sparse_vec_print_pretty(window1, 0, len, mod); + flint_printf("window2 = \n"); + nmod_sparse_vec_print_pretty(window2, len, len, mod); + flint_printf("FAIL: results not equal\n"); + abort(); + } + nmod_sparse_vec_window_clear(window1); + nmod_sparse_vec_window_clear(window2); + + nmod_sparse_vec_init(window1); + nmod_sparse_vec_init(window2); + nmod_sparse_vec_split(window1, window2, w, len); + if (!(nmod_sparse_vec_equal(window1, u, 0) && nmod_sparse_vec_equal(window2, v, 0))) + { + flint_printf("u = "); + nmod_sparse_vec_print_pretty(u, 0, len, mod); + flint_printf("v = \n"); + nmod_sparse_vec_print_pretty(v, 0, len, mod); + flint_printf("u | v = \n"); + nmod_sparse_vec_print_pretty(w, 0, len, mod); + flint_printf("window1 = \n"); + nmod_sparse_vec_print_pretty(window1, 0, len, mod); + flint_printf("window2 = \n"); + nmod_sparse_vec_print_pretty(window2, 0, len, mod); + flint_printf("FAIL: results not equal\n"); + abort(); + } + nmod_sparse_vec_window_clear(window1); + nmod_sparse_vec_window_clear(window2); + nmod_sparse_vec_clear(u); + nmod_sparse_vec_clear(v); + nmod_sparse_vec_clear(w); + } + + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_vec/test/t-construct.c b/nmod_sparse_vec/test/t-construct.c new file mode 100644 index 0000000000..a7e4381824 --- /dev/null +++ b/nmod_sparse_vec/test/t-construct.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz, i; + mp_limb_t n; + nmod_t mod; + nmod_sparse_vec_t u, v; + slong *inds; + mp_limb_t *vals; + FLINT_TEST_INIT(state); + + flint_printf("construction from elements...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + + nmod_sparse_vec_init(u); + nmod_sparse_vec_init(v); + nmod_sparse_vec_randtest(u, state, nnz, len, mod); + nmod_sparse_vec_randtest(v, state, nnz, len, mod); + + /* Construct v from entries of u */ + inds = flint_malloc(nnz * sizeof(*inds)); + vals = flint_malloc(nnz * sizeof(*vals)); + for (i = 0; i < nnz; ++i) + { + inds[i] = u->entries[i].ind; + vals[i] = u->entries[i].val; + } + nmod_sparse_vec_from_entries(v, inds, vals, nnz); + + if (!nmod_sparse_vec_equal(u, v, 0)) + { + flint_printf("FAIL: u != v\n"); + abort(); + } + flint_free(inds); + flint_free(vals); + nmod_sparse_vec_clear(u); + nmod_sparse_vec_clear(v); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_vec/test/t-dense.c b/nmod_sparse_vec/test/t-dense.c new file mode 100644 index 0000000000..848b4ac62f --- /dev/null +++ b/nmod_sparse_vec/test/t-dense.c @@ -0,0 +1,87 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz, i; + mp_limb_t n; + nmod_t mod; + nmod_sparse_vec_t u, v; + mp_ptr w, x; + FLINT_TEST_INIT(state); + + flint_printf("conversion to/from dense vector...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + + nmod_sparse_vec_init(u); + nmod_sparse_vec_init(v); + w = _nmod_vec_init(len); + x = _nmod_vec_init(len); + + nmod_sparse_vec_randtest(u, state, nnz, len, mod); + nmod_sparse_vec_randtest(v, state, nnz, len, mod); + + nmod_sparse_vec_to_dense(w, u, len); + nmod_sparse_vec_from_dense(v, w, len); + + for (i = 0; i < len; ++i) + { + mp_limb_t *val = nmod_sparse_vec_at(u, i); + if ((w[i] == 0 && val != NULL) || (w[i] != 0 && (val == NULL || *val != w[i]))) + { + flint_printf("FAIL: u[%wd] != v[%wd]\n", i, i); + abort(); + } + } + if (!nmod_sparse_vec_equal(u, v, 0)) + { + flint_printf("FAIL: u != v\n"); + abort(); + } + + _nmod_vec_randtest(w, state, len, mod); + nmod_sparse_vec_from_dense(u, w, len); + nmod_sparse_vec_to_dense(x, u, len); + + if (!_nmod_vec_equal(w, x, len)) + { + flint_printf("FAIL: w != x\n"); + abort(); + } + nmod_sparse_vec_clear(u); + nmod_sparse_vec_clear(v); + _nmod_vec_clear(w); + _nmod_vec_clear(x); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_vec/test/t-dot.c b/nmod_sparse_vec/test/t-dot.c new file mode 100644 index 0000000000..e8c5f9b86f --- /dev/null +++ b/nmod_sparse_vec/test/t-dot.c @@ -0,0 +1,82 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + int limbs; + slong rep, len, nnz; + mp_limb_t n, a, b; + nmod_t mod; + nmod_sparse_vec_t u, v; + mp_ptr w, x; + FLINT_TEST_INIT(state); + + + flint_printf("dot product...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + + nmod_sparse_vec_init(u); + nmod_sparse_vec_init(v); + w = _nmod_vec_init(len); + x = _nmod_vec_init(len); + + nmod_sparse_vec_randtest(u, state, nnz, len, mod); + nmod_sparse_vec_randtest(v, state, nnz, len, mod); + nmod_sparse_vec_to_dense(w, u, len); + nmod_sparse_vec_to_dense(x, v, len); + + a = nmod_sparse_vec_dot(u, v, mod); + limbs = _nmod_vec_dot_bound_limbs(len, mod); + b = _nmod_vec_dot(w, x, len, mod, limbs); + + if (a != b) + { + flint_printf("Fail: sparse dot sparse\n"); + abort(); + } + + a = nmod_sparse_vec_dot_dense(u, x, mod); + + if (a != b) + { + flint_printf("Fail: sparse dot dense\n"); + abort(); + } + + nmod_sparse_vec_clear(u); + nmod_sparse_vec_clear(v); + _nmod_vec_clear(w); + _nmod_vec_clear(x); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_vec/test/t-init_clear.c b/nmod_sparse_vec/test/t-init_clear.c new file mode 100644 index 0000000000..5e0a24b7ca --- /dev/null +++ b/nmod_sparse_vec/test/t-init_clear.c @@ -0,0 +1,92 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "ulong_extras.h" + +static void check_zero(nmod_sparse_vec_t vec) +{ + if (vec->nnz != UWORD(0)) +{ + flint_printf("FAIL: nnz not zero!\n"); + abort(); + } + if (vec->entries != NULL) +{ + flint_printf("FAIL: entries not null!\n"); + abort(); + } +} + +int +main(void) +{ + slong rep, len, nnz, i; + mp_limb_t n; + nmod_t mod; + nmod_sparse_vec_t vec; + FLINT_TEST_INIT(state); + + flint_printf("init/clear...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + + nmod_sparse_vec_init(vec); + check_zero(vec); + + nmod_sparse_vec_randtest(vec, state, nnz, len, mod); + + if (nnz == 0) check_zero(vec); + else + { + for (i = 0; i < nnz; ++i) + { + nmod_sparse_entry_struct *e = &vec->entries[i]; + if (e->ind >= len) + { + flint_printf("FAIL: found index %wd >= %wd!\n", e->ind, len); + abort(); + } + if (e->val == UWORD(0) || e->val >= n) + { + flint_printf("FAIL: found value %wd (not in (0,%wd))\n", e->val, n); + abort(); + } + if (i > 0 && e->ind <= e[-1].ind) + { + flint_printf("FAIL: found index %wd <= previous index %wd\n", e->ind, e[-1].ind); + abort(); + } + } + } + + nmod_sparse_vec_clear(vec); + check_zero(vec); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_vec/test/t-neg.c b/nmod_sparse_vec/test/t-neg.c new file mode 100644 index 0000000000..bed03d2758 --- /dev/null +++ b/nmod_sparse_vec/test/t-neg.c @@ -0,0 +1,78 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz; + mp_limb_t n; + nmod_t mod; + nmod_sparse_vec_t u, v, w, x; + FLINT_TEST_INIT(state); + + + flint_printf("neg...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + len = n_randint(state, 200); + nnz = n_randint(state, len+1); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + nmod_init(&mod, n); + + nmod_sparse_vec_init(u); + nmod_sparse_vec_init(v); + nmod_sparse_vec_init(w); + nmod_sparse_vec_init(x); + + nmod_sparse_vec_randtest(u, state, nnz, len, mod); + nmod_sparse_vec_randtest(v, state, nnz, len, mod); + + nmod_sparse_vec_sub(w, u, v, mod); + nmod_sparse_vec_neg(v, v, mod); + nmod_sparse_vec_add(x, u, v, mod); + + if (!nmod_sparse_vec_equal(w, x, 0)) + { + flint_printf("FAIL: u - v != u + (-v)\n"); + abort(); + } + + nmod_sparse_vec_neg(w, u, mod); + nmod_sparse_vec_neg(u, u, mod); + + if (!nmod_sparse_vec_equal(w, w, 0)) + { + flint_printf("FAIL\n"); + abort(); + } + nmod_sparse_vec_clear(u); + nmod_sparse_vec_clear(v); + nmod_sparse_vec_clear(w); + nmod_sparse_vec_clear(x); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_vec/test/t-scalar_mul.c b/nmod_sparse_vec/test/t-scalar_mul.c new file mode 100644 index 0000000000..aefd778f9e --- /dev/null +++ b/nmod_sparse_vec/test/t-scalar_mul.c @@ -0,0 +1,126 @@ +/* + wopyright (w) 2011 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" +#include "nmod_vec.h" +#include "ulong_extras.h" + +int +main(void) +{ + slong rep, len, nnz; + mp_limb_t n, c; + nmod_t mod; + nmod_sparse_vec_t u, v, w, x; + FLINT_TEST_INIT(state); + + flint_printf("scalar_mul and muladd...."); + fflush(stdout); + + for (rep = 0; rep < 1000; rep++) + { + len = n_randint(state, 50); + nnz = n_randint(state, len+1); + do n = n_randtest_not_zero(state); + while (n == UWORD(1)); + c = n_randint(state, n); + nmod_init(&mod, n); + + nmod_sparse_vec_init(u); + nmod_sparse_vec_init(v); + nmod_sparse_vec_init(w); + nmod_sparse_vec_init(x); + + nmod_sparse_vec_randtest(u, state, nnz, len, mod); + nmod_sparse_vec_randtest(v, state, nnz, len, mod); + + nmod_sparse_vec_scalar_addmul_nmod(w, u, v, c, mod); + nmod_sparse_vec_scalar_mul_nmod(x, v, c, mod); + nmod_sparse_vec_add(x, x, u, mod); + + if (!nmod_sparse_vec_equal(w, x, 0)) + { + flint_printf("FAIL: u + c*v != u + (c*v)\n"); + abort(); + } + + nmod_sparse_vec_scalar_submul_nmod(w, u, v, c, mod); + nmod_sparse_vec_scalar_mul_nmod(x, v, c, mod); + nmod_sparse_vec_sub(x, u, x, mod); + + if (!nmod_sparse_vec_equal(w, x, 0)) + { + flint_printf("FAIL: u - c*v != u - (c*v)\n"); + abort(); + } + + nmod_sparse_vec_scalar_addmul_nmod(w, u, v, c, mod); + nmod_sparse_vec_scalar_addmul_nmod(u, u, v, c, mod); + + if (!nmod_sparse_vec_equal(u, w, 0)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + nmod_sparse_vec_scalar_addmul_nmod(w, u, v, c, mod); + nmod_sparse_vec_scalar_addmul_nmod(v, u, v, c, mod); + + if (!nmod_sparse_vec_equal(v, w, 0)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + nmod_sparse_vec_scalar_submul_nmod(w, u, v, c, mod); + nmod_sparse_vec_scalar_submul_nmod(u, u, v, c, mod); + + if (!nmod_sparse_vec_equal(u, w, 0)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + nmod_sparse_vec_scalar_submul_nmod(w, u, v, c, mod); + nmod_sparse_vec_scalar_submul_nmod(v, u, v, c, mod); + + if (!nmod_sparse_vec_equal(v, w, 0)) + { + flint_printf("FAIL: u + c*v != (u += c*v)\n"); + abort(); + } + + nmod_sparse_vec_scalar_mul_nmod(x, v, c, mod); + nmod_sparse_vec_scalar_mul_nmod(v, v, c, mod); + + if (!nmod_sparse_vec_equal(v, x, 0)) + { + flint_printf("FAIL: c*v != (c *= v)\n"); + abort(); + } + + nmod_sparse_vec_clear(u); + nmod_sparse_vec_clear(v); + nmod_sparse_vec_clear(w); + nmod_sparse_vec_clear(x); + } + + FLINT_TEST_CLEANUP(state); + + flint_printf("PASS\n"); + return 0; +} diff --git a/nmod_sparse_vec/window_init.c b/nmod_sparse_vec/window_init.c new file mode 100644 index 0000000000..609c6bd6ce --- /dev/null +++ b/nmod_sparse_vec/window_init.c @@ -0,0 +1,26 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2020 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by th e Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "nmod_sparse_vec.h" + +void nmod_sparse_vec_window_init(nmod_sparse_vec_t window, const nmod_sparse_vec_t vec, slong i1, slong i2) +{ + slong start, end; + for (start = 0; start < vec->nnz && vec->entries[start].ind < i1; ++start); + for (end = vec->nnz; end > 0 && vec->entries[end-1].ind >= i2; --end); + window->entries = vec->entries + start; + window->nnz = end - start; +} diff --git a/nmod_vec.h b/nmod_vec.h index c3d910754f..1d40e78790 100644 --- a/nmod_vec.h +++ b/nmod_vec.h @@ -220,6 +220,18 @@ void _nmod_vec_swap(mp_ptr a, mp_ptr b, slong length) } } +NMOD_VEC_INLINE +void _nmod_vec_print_pretty(mp_ptr a, slong length, nmod_t mod) +{ + slong i; + flint_printf("["); + for(i=0; i. +*/ + +#include +#include +#include +#include "flint.h" +#include "hashmap.h" +#include "ulong_extras.h" + +int main(void) +{ + slong rep, num, *keys, *vals, nreps = 1000, i, *ptr; + hashmap_t h; + FLINT_TEST_INIT(state); + + flint_printf("hashmap...."); + fflush(stdout); + for (rep = 0; rep < nreps; rep++) + { + num = n_randint(state, 1000); + keys = flint_malloc(num*sizeof(*keys)); + vals = flint_malloc(num*sizeof(*vals)); + + hashmap_init(h, num); + for (i = 0; i < num; ++i) + { + do keys[i] = n_randtest(state); + while (hashmap_get(h, keys[i]) != NULL); + vals[i] = n_randtest(state); + hashmap_put(h, keys[i], &vals[i]); + } + if (h->num != num) + { + flint_printf("FAIL: Added %wd keys, hashmap only has %wd\n", num, h->num); + abort(); + } + + for (i = 0; i < num; ++i) + { + if (h->keys[i] != keys[i]) + { + flint_printf("FAIL: Mismatch key at %wd:%wd\n", i, keys[i]); + abort(); + } + ptr = hashmap_get(h, keys[i]); + if (ptr != &vals[i]) + { + flint_printf("FAIL: Mismatch value at %wd:%wd\n", i, keys[i]); + abort(); + } + } + for (i = 0; i < num; ++i) + { + hashmap_rem(h, keys[i]); + ptr = hashmap_get(h, keys[i]); + if (ptr != NULL) + { + flint_printf("FAIL: removed key %wd, still exists in hashtable\n"); + abort(); + } + } + flint_free(keys); + flint_free(vals); + hashmap_clear(h); + } + FLINT_TEST_CLEANUP(state); + flint_printf("PASS\n"); + return 0; +} diff --git a/test/t-heap.c b/test/t-heap.c new file mode 100644 index 0000000000..7a6aa86c30 --- /dev/null +++ b/test/t-heap.c @@ -0,0 +1,97 @@ +/* + Copyright (C) 2009 William Hart + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include +#include "flint.h" +#include "heap.h" +#include "ulong_extras.h" + +void check_heap(heap_t h, slong *vals) +{ + slong i, j; + for (i = h->num - 1; i >= 0; --i) + { + if (h->pos[h->idx[i]] != i) + { + flint_printf("Mismatch between idx and pos\n"); + abort(); + } + if (h->val[h->idx[i]] != vals[h->idx[i]]) + { + flint_printf("Mismatch between inside and outside scores\n"); + abort(); + } + if (i==0) break; + j = (i - 1)/2; + if (h->val[h->idx[i]] < h->val[h->idx[j]]) + { + flint_printf("Not a heap: %2wd:%2wd:%2wd < %2wd:%2wd:%2wd\n", + i, h->idx[i], h->val[h->idx[i]], j, h->idx[j], h->val[h->idx[j]]); + abort(); + } + } +} + +int main(void) +{ + slong rep, num, *vals, nreps = 1000, i, val, oval; + heap_t h; + FLINT_TEST_INIT(state); + + flint_printf("heap...."); + fflush(stdout); + for (rep = 0; rep < nreps; rep++) + { + num = n_randint(state, 1000); + vals = flint_malloc(num*sizeof(*vals)); + + heap_init(h, num); + for (i = 0; i < num; ++i) + { + vals[i] = n_randtest(state); + heap_push(h, vals[i]); + } + if (h->num != num) + { + flint_printf("FAIL: Added %wd values, heap only has %wd\n", num, h->num); + abort(); + } + check_heap(h, vals); + + /* Modify each value and check if heap maintained */ + for (i = 0; i < num; ++i) + { + vals[i] = n_randtest(state); + heap_adjust(h, i, vals[i]); + check_heap(h, vals); + } + + /* Pop items from heap and check that in sorted order */ + for (i = 0; i < num; ++i) + { + heap_pop(h, &val); + if (i > 0 && val < oval) + { + flint_printf("FAIL: popping from heap out of order\n"); + abort(); + } + check_heap(h, vals); + oval = val; + } + flint_free(vals); + heap_clear(h); + } + FLINT_TEST_CLEANUP(state); + flint_printf("PASS\n"); + return 0; +}