From 57912d751c337fef89b8e8b2d8ca8b96b6720566 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Tue, 6 Feb 2024 14:32:41 -0800 Subject: [PATCH 01/59] API for sparse vectors --- src/gr_sparse_vec.h | 257 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 src/gr_sparse_vec.h diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h new file mode 100644 index 0000000000..69f989e0f0 --- /dev/null +++ b/src/gr_sparse_vec.h @@ -0,0 +1,257 @@ +/* + Copyright (C) 2023 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 . +*/ + +#ifndef GR_SPARSE_VEC_H +#define GR_SPARSE_VEC_H + +#ifdef GR_SPARSE_VEC_INLINES_C +#define GR_SPARSE_VEC_INLINE +#else +#define GR_SPARSE_VEC_INLINE static __inline__ +#endif + +#include "gr.h" +#include "gr_vec.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct +{ + ulong *inds; + gr_ptr entries; + ulong nnz; +} +gr_sparse_vec_struct; + +typedef gr_sparse_vec_struct gr_sparse_vec_t[1]; + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_init(gr_sparse_vec_t vec, gr_ctx_t ctx) { + memset(vec, 0, sizeof(gr_sparse_vec_t)); + return GR_SUCCESS; +} + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) { + gr_vec_clear(vec->entries, vec->nnz, ctx); + flint_free(vec->inds); + flint_free(vec->entries); + memset(vec, 0, sizeof(gr_sparse_vec_t)); + return GR_SUCCESS; +} + +#define GR_SPARSE_VEC_ENTRY(vec, i, sz) GR_ENTRY((vec)->entries, i, sz) + +GR_SPARSE_VEC_INLINE ulong * +gr_sparse_vec_ind_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) +{ + return vec->inds + i; +} + +GR_SPARSE_VEC_INLINE ulong * +gr_sparse_vec_ind_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) +{ + return vec->inds + i; +} + +GR_SPARSE_VEC_INLINE gr_ptr +gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) +{ + return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); +} + +GR_SPARSE_VEC_INLINE gr_srcptr +gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) +{ + return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); +} + +GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec, gr_ctx_t ctx) +{ + return vec->nnz; +} + +void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); +void gr_sparse_vec_set_nnz(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_append(gr_sparse_vec_t vec, gr_srcptr src, ulong ind, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_extend(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx); + +int gr_sparse_vec_write(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx); +int gr_sparse_vec_print(const gr_sparse_vec_t vec, gr_ctx_t ctx); + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_CONSTANT_OP(ctx, VEC_ZERO)(vec, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP(ctx, VEC_SET)(res, src, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP(ctx, VEC_NEG)(res, src, len, ctx); } + +WARN_UNUSED_RESULT int gr_sparse_vec_from_entries(gr_sparse_vec_t vec, slong * inds, gr_srcptr vals, slong nnz); + +WARN_UNUSED_RESULT int gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len); + +WARN_UNUSED_RESULT int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, slong len); +WARN_UNUSED_RESULT int gr_sparse_vec_split(gr_sparse_vec_t res1, gr_sparse_vec_t res2, const gr_sparse_vec_t vec, slong ind); + +/* Vector permutation */ +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, slong *P) +{ + slong i; + for (i = 0; i < vec->nnz; ++i) vec->inds[i] = P[vec->inds[i]]; + // TODO: re-sort vector +} + +/* +typedef int ((*gr_method_vec_normalise_op)(slong *, gr_srcptr, slong, gr_ctx_ptr)); +typedef slong ((*gr_method_vec_normalise_weak_op)(gr_srcptr, slong, gr_ctx_ptr)); +#define GR_SPARSE_VEC_NORMALISE_OP(ctx, NAME) (((gr_method_vec_normalise_op *) ctx->methods)[GR_METHOD_ ## NAME]) +#define GR_SPARSE_VEC_NORMALISE_WEAK_OP(ctx, NAME) (((gr_method_vec_normalise_weak_op *) ctx->methods)[GR_METHOD_ ## NAME]) + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_normalise(slong * res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_NORMALISE_OP(ctx, VEC_NORMALISE)(res, vec, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT slong gr_sparse_vec_normalise_weak(const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_NORMALISE_WEAK_OP(ctx, VEC_NORMALISE_WEAK)(vec, len, ctx); } +*/ + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_ADD)(res, src1, src2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_SUB)(res, src1, src2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_MUL)(res, src1, src2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIV)(res, src1, src2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIVEXACT)(res, src1, src2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_POW)(res, src1, src2, len, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_ADD_SCALAR)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_SUB_SCALAR)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_MUL_SCALAR)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_DIV_SCALAR)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_DIVEXACT_SCALAR)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_POW_SCALAR)(vec1, vec2, len, c, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_ADD_SCALAR_SI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_SUB_SCALAR_SI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_MUL_SCALAR_SI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_DIV_SCALAR_SI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_DIVEXACT_SCALAR_SI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_POW_SCALAR_SI)(vec1, vec2, len, c, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_ADD_SCALAR_UI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_SUB_SCALAR_UI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_MUL_SCALAR_UI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_DIV_SCALAR_UI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_DIVEXACT_SCALAR_UI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_POW_SCALAR_UI)(vec1, vec2, len, c, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_ADD_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_SUB_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_MUL_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_DIV_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_DIVEXACT_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_POW_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_ADD_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_SUB_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_MUL_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_DIV_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_DIVEXACT_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_POW_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_add_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_ADD_VEC)(vec1, c, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_sub_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_SUB_VEC)(vec1, c, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_mul_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_MUL_VEC)(vec1, c, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_div_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_DIV_VEC)(vec1, c, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_divexact_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_DIVEXACT_VEC)(vec1, c, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_pow_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_POW_VEC)(vec1, c, vec2, len, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_ADD_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_SUB_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_MUL_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_DIV_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_DIVEXACT_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_POW_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_ADD_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_SUB_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_mul_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_MUL_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_div_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_DIV_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_divexact_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_DIVEXACT_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_pow_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_POW_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_ADD_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_SUB_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_MUL_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_DIV_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_DIVEXACT_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_POW_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_add_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_ADD_VEC)(vec1, c, cctx, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_sub_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_SUB_VEC)(vec1, c, cctx, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_mul_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_MUL_VEC)(vec1, c, cctx, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_div_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_DIV_VEC)(vec1, c, cctx, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_divexact_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_DIVEXACT_VEC)(vec1, c, cctx, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_pow_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_POW_VEC)(vec1, c, cctx, vec2, len, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_MUL_SCALAR_2EXP_SI)(vec1, vec2, len, c, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_ADDMUL_SCALAR)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_SUBMUL_SCALAR)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_ADDMUL_SCALAR_SI)(vec1, vec2, len, c, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_SUBMUL_SCALAR_SI)(vec1, vec2, len, c, ctx); } + +GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_PREDICATE(ctx, VEC_EQUAL)(vec1, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_PREDICATE(ctx, VEC_IS_ZERO)(vec, len, ctx); } + +typedef int ((*gr_method_vec_reduce_op)(gr_sparse_vec_t, gr_srcptr, slong, gr_ctx_ptr)); + +typedef int ((*gr_method_vec_dot_op)(gr_sparse_vec_t, gr_srcptr, int, gr_srcptr, gr_srcptr, slong, gr_ctx_ptr)); +typedef int ((*gr_method_vec_dot_si_op)(gr_sparse_vec_t, gr_srcptr, int, gr_srcptr, const slong *, slong, gr_ctx_ptr)); +typedef int ((*gr_method_vec_dot_ui_op)(gr_sparse_vec_t, gr_srcptr, int, gr_srcptr, const ulong *, slong, gr_ctx_ptr)); +typedef int ((*gr_method_vec_dot_fmpz_op)(gr_sparse_vec_t, gr_srcptr, int, gr_srcptr, const fmpz *, slong, gr_ctx_ptr)); + +#define GR_SPARSE_VEC_REDUCE_OP(ctx, NAME) (((gr_method_vec_reduce_op *) ctx->methods)[GR_METHOD_ ## NAME]) +#define GR_SPARSE_VEC_DOT_OP(ctx, NAME) (((gr_method_vec_dot_op *) ctx->methods)[GR_METHOD_ ## NAME]) +#define GR_SPARSE_VEC_DOT_SI_OP(ctx, NAME) (((gr_method_vec_dot_si_op *) ctx->methods)[GR_METHOD_ ## NAME]) +#define GR_SPARSE_VEC_DOT_UI_OP(ctx, NAME) (((gr_method_vec_dot_ui_op *) ctx->methods)[GR_METHOD_ ## NAME]) +#define GR_SPARSE_VEC_DOT_FMPZ_OP(ctx, NAME) (((gr_method_vec_dot_fmpz_op *) ctx->methods)[GR_METHOD_ ## NAME]) + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sum(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_REDUCE_OP(ctx, VEC_SUM)(res, vec, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_product(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_REDUCE_OP(ctx, VEC_PRODUCT)(res, vec, len, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_OP(ctx, VEC_DOT)(res, initial, subtract, vec1, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_rev(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_OP(ctx, VEC_DOT_REV)(res, initial, subtract, vec1, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_si(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const slong * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_SI_OP(ctx, VEC_DOT_SI)(res, initial, subtract, vec1, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_ui(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const ulong * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_UI_OP(ctx, VEC_DOT_UI)(res, initial, subtract, vec1, vec2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_fmpz(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const fmpz * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_FMPZ_OP(ctx, VEC_DOT_FMPZ)(res, initial, subtract, vec1, vec2, len, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_reciprocals(gr_ptr res, slong len, gr_ctx_t ctx) { return GR_UNARY_OP_SI(ctx, VEC_RECIPROCALS)(res, len, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_set_powers(gr_ptr res, gr_srcptr x, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP(ctx, VEC_SET_POWERS)(res, x, len, ctx); } + +/* todo: could allow overloading this as well */ +/* todo: worth warning about unused result? */ +WARN_UNUSED_RESULT int gr_sparse_vec_randtest(gr_ptr res, flint_rand_t state, slong len, gr_ctx_t ctx); + +/* +WARN_UNUSED_RESULT int gr_sparse_vec_sum_bsplit_parallel(gr_ptr res, const gr_sparse_vec_t vec, slong len, slong basecase_cutoff, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_sum_bsplit(gr_ptr res, const gr_sparse_vec_t vec, slong len, slong basecase_cutoff, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_sum_parallel(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_sum_serial(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_sum_generic(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_vec_product_bsplit_parallel(gr_ptr res, const gr_sparse_vec_t vec, slong len, slong basecase_cutoff, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_product_bsplit(gr_ptr res, const gr_sparse_vec_t vec, slong len, slong basecase_cutoff, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_product_parallel(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_product_serial(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_product_generic(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_vec_step(gr_sparse_vec_t vec, gr_srcptr start, gr_srcptr step, slong len, gr_ctx_t ctx); +*/ + +#ifdef __cplusplus +} +#endif + +#endif From 52d7fbeab4bd853535d106faf00b93a947d919f1 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Tue, 6 Feb 2024 14:42:50 -0800 Subject: [PATCH 02/59] adding gr_sparse_vec dir --- src/gr_sparse_vec/fit_nnz.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/gr_sparse_vec/fit_nnz.c diff --git a/src/gr_sparse_vec/fit_nnz.c b/src/gr_sparse_vec/fit_nnz.c new file mode 100644 index 0000000000..e69de29bb2 From 75d157bc75fb8bdb0a2db1c3a43c236ac0ccc8a5 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Tue, 6 Feb 2024 17:56:03 -0800 Subject: [PATCH 03/59] adding fit, set, update --- src/gr_sparse_vec.h | 12 +++++++----- src/gr_sparse_vec/fit_nnz.c | 17 +++++++++++++++++ src/gr_sparse_vec/set.c | 16 ++++++++++++++++ src/gr_sparse_vec/update.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 src/gr_sparse_vec/set.c create mode 100644 src/gr_sparse_vec/update.c diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 69f989e0f0..f06f528e7b 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -27,9 +27,10 @@ typedef struct { - ulong *inds; + slong alloc; gr_ptr entries; - ulong nnz; + ulong *inds; + slong nnz; } gr_sparse_vec_struct; @@ -41,7 +42,7 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_init(gr_sparse_vec_t v } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) { - gr_vec_clear(vec->entries, vec->nnz, ctx); + _gr_vec_clear(vec->entries, vec->alloc, ctx); flint_free(vec->inds); flint_free(vec->entries); memset(vec, 0, sizeof(gr_sparse_vec_t)); @@ -80,9 +81,10 @@ GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec, gr_ctx_t } void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); -void gr_sparse_vec_set_nnz(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_append(gr_sparse_vec_t vec, gr_srcptr src, ulong ind, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_update_entries(gr_sparse_vec_t vec, gr_srcptr entries, const ulong* inds, slong nnz, gr_ctx_t ctx); +//I think the below might be the same as "add" WARN_UNUSED_RESULT int gr_sparse_vec_extend(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx); int gr_sparse_vec_write(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx); diff --git a/src/gr_sparse_vec/fit_nnz.c b/src/gr_sparse_vec/fit_nnz.c index e69de29bb2..8b5e3c3d9b 100644 --- a/src/gr_sparse_vec/fit_nnz.c +++ b/src/gr_sparse_vec/fit_nnz.c @@ -0,0 +1,17 @@ +#include "gr_sparse_vec.h" + +void +gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) +{ + slong alloc = vec->alloc; + if (len > alloc) + { + slong sz = ctx->sizeof_elem; + if (len < 2 * alloc) + len = 2 * alloc; + vec->inds = flint_realloc(vec->inds, len * sizeof(ulong)); + vec->entries = flint_realloc(vec->entries, len * sz); + _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), len - alloc, ctx); + vec->alloc = len; + } +} \ No newline at end of file diff --git a/src/gr_sparse_vec/set.c b/src/gr_sparse_vec/set.c new file mode 100644 index 0000000000..d4c6dcbf80 --- /dev/null +++ b/src/gr_sparse_vec/set.c @@ -0,0 +1,16 @@ +#include "gr_sparse_vec.h" + +int +gr_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + if (res != src) + { + slong nnz = src->nnz; + gr_sparse_vec_fit_nnz(res, nnz, ctz); + memcpy(res->inds, src->inds, nnz*sizeof(slong)); + res->nnz = nnz; + status = _gr_vec_set(res->entries, src->entries, nnz, ctx); + } + return status; +} \ No newline at end of file diff --git a/src/gr_sparse_vec/update.c b/src/gr_sparse_vec/update.c new file mode 100644 index 0000000000..c6e83305bd --- /dev/null +++ b/src/gr_sparse_vec/update.c @@ -0,0 +1,28 @@ +#include "gr_sparse_vec.h" + +// int +// gr_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +// { +// int status = GR_SUCCESS; +// if (res != src) +// { +// slong nnz = src->nnz; +// gr_sparse_vec_fit_nnz(res, nnz, ctz); +// memcpy(res->inds, src->inds, nnz*sizeof(slong)); +// res->nnz = nnz; +// status = _gr_vec_set(res->entries, src->entries, nnz, ctx); +// } +// return status; +// } + +int +gr_sparse_vec_update(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ + gr_sparse_vec_update_entries(vec, src->entries, src->inds, src->nnz, ctx); +} + +int +gr_sparse_vec_update_entries(gr_sparse_vec_t vec, gr_srcptr entries, const ulong* inds, slong nnz, gr_ctx_t ctx) +{ + +} \ No newline at end of file From 5dd99b0ce848db97026a8da93cdaf7568d32a46b Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Wed, 7 Feb 2024 10:05:50 -0800 Subject: [PATCH 04/59] working on sparse vec --- src/gr_sparse_vec.h | 6 +++-- src/gr_sparse_vec/set_length.c | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/gr_sparse_vec/set_length.c diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index f06f528e7b..f73570bde3 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -30,6 +30,7 @@ typedef struct slong alloc; gr_ptr entries; ulong *inds; + slong len; slong nnz; } gr_sparse_vec_struct; @@ -57,7 +58,7 @@ gr_sparse_vec_ind_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) return vec->inds + i; } -GR_SPARSE_VEC_INLINE ulong * +GR_SPARSE_VEC_INLINE const ulong * gr_sparse_vec_ind_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->inds + i; @@ -80,7 +81,8 @@ GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec, gr_ctx_t return vec->nnz; } -void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); +void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx); +void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_update_entries(gr_sparse_vec_t vec, gr_srcptr entries, const ulong* inds, slong nnz, gr_ctx_t ctx); diff --git a/src/gr_sparse_vec/set_length.c b/src/gr_sparse_vec/set_length.c new file mode 100644 index 0000000000..e73be42404 --- /dev/null +++ b/src/gr_sparse_vec/set_length.c @@ -0,0 +1,45 @@ +#include "gr_sparse_vec.h" + +void +gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) +{ + slong i; + vec->len = len; + for (i=vec->nnz-1; i>=0; i--) + { + + } + + slong alloc = vec->alloc; + if (len > alloc) + { + slong sz = ctx->sizeof_elem; + if (len < 2 * alloc) + len = 2 * alloc; + vec->inds = flint_realloc(vec->inds, len * sizeof(ulong)); + vec->entries = flint_realloc(vec->entries, len * sz); + _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), len - alloc, ctx); + vec->alloc = len; + } +} + + + +#include "gr_vec.h" + +void +gr_vec_set_length(gr_vec_t vec, slong len, gr_ctx_t ctx) +{ + if (vec->length > len) + { + /* potentially free no longer used elements */ + GR_MUST_SUCCEED(_gr_vec_zero(GR_ENTRY(vec->entries, len, ctx->sizeof_elem), vec->length - len, ctx)); + } + else if (vec->length < len) + { + gr_vec_fit_length(vec, len, ctx); + GR_MUST_SUCCEED(_gr_vec_zero(GR_ENTRY(vec->entries, vec->length, ctx->sizeof_elem), len - vec->length, ctx)); + } + + vec->length = len; +} From 45f4d453f6344891b4933904210452ac4bace868 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Wed, 7 Feb 2024 14:25:22 -0800 Subject: [PATCH 05/59] adding macros --- src/gr_sparse_vec.h | 64 +++++++++++++++++++++- src/gr_sparse_vec/count_unique_inds.c | 23 ++++++++ src/gr_sparse_vec/fit_nnz.c | 19 ++++--- src/gr_sparse_vec/set.c | 4 +- src/gr_sparse_vec/set_length.c | 44 +++------------- src/gr_sparse_vec/update.c | 76 +++++++++++++++++++++------ 6 files changed, 168 insertions(+), 62 deletions(-) create mode 100644 src/gr_sparse_vec/count_unique_inds.c diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index f73570bde3..33956be74b 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -30,7 +30,7 @@ typedef struct slong alloc; gr_ptr entries; ulong *inds; - slong len; + slong length; slong nnz; } gr_sparse_vec_struct; @@ -82,10 +82,72 @@ GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec, gr_ctx_t } void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx); +slong gr_sparse_vec_length(const gr_sparse_vec_t vec) { return vec->length; } void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); + +slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulong *inds1, slong nnz1); + +/* This is used for operations like add */ +#define GR_SPARSE_VEC_RIFFLE_TEMPLATE(STATUS, FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_ENTRIES, A_INDS, A_NNZ, B_ENTRIES, B_INDS, B_NNZ, CTX) \ +{ + slong sz = (CTX)->sizeof_elem; + slong new_nnz = _gr_sparse_vec_count_unique_inds((A_INDS), (A_NNZ), (B_INDS), (B_NNZ)) + gr_sparse_vec_fit_nnz(DEST_VEC, new_nnz, (CTX)); + /* We go backward through the destination, because it might be an in-place operation on a source */ + slong a_ptr = (A_NNZ)-1; + slong b_ptr = (B_NNZ)-1; + slong v_ptr = new_nnz-1;; + while (a_ptr >= 0 && b_ptr >= 0 && (STATUS) == GR_SUCCESS) + { + a_ind = (A_INDS)[a_ptr]; + b_ind = (B_INDS)[b_ptr]; + if (a_ind > b_ind) + { + STATUS |= FUNC_A(GR_ENTRY((DEST_VEC)->entries, v_ptr, sz), GR_ENTRY((A_ENTRIES), a_ptr, sz), (CTX)); + (DEST_VEC)->inds[v_ptr] = (A_INDS)[a_ptr]; + a_ptr--; + } + else if (b_ind > a_ind) + { + STATUS |= FUNC_B(GR_ENTRY((DEST_VEC)->entries, v_ptr, sz), GR_ENTRY((B_ENTRIES), b_ptr, sz), (CTX)); + (DEST_VEC)->inds[v_ptr] = (B_INDS)[b_ptr]; + b_ptr--; + } + else + { + STATUS gr_set(GR_ENTRY(vec->entries, dest_ind, sz), GR_ENTRY(entries, si_ind, sz)); + vec->inds[dest_ind] = sorted_inds[si_ind]; + si_ind--; + vec_ind--; + } + v_ptr--; + } + vec->nnz = new_nnz; +} + + +#define GR_SPARSE_VEC_DENSE_VEC_OP(g, res, src, c, ctx) \ +{ \ + int status = GR_SUCCESS; \ + status = gr_vec_set(res, src, ctx); \ + if(status == GR_SUCCESS) { \ + status = g(res->entries, src->entries, len, c, ctx); \ + } \ + return status; \ +} + +int gr_sparse_vec_mul_scalar(gr_vec_t res, gr_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, blah, src, c, ctx) } +int gr_sparse_vec_mul_scalar_si(gr_vec_t res, gr_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } + + + WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_update_entries(gr_sparse_vec_t vec, gr_srcptr entries, const ulong* inds, slong nnz, gr_ctx_t ctx); + + + + //I think the below might be the same as "add" WARN_UNUSED_RESULT int gr_sparse_vec_extend(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx); diff --git a/src/gr_sparse_vec/count_unique_inds.c b/src/gr_sparse_vec/count_unique_inds.c new file mode 100644 index 0000000000..1d8a8e6671 --- /dev/null +++ b/src/gr_sparse_vec/count_unique_inds.c @@ -0,0 +1,23 @@ +#include "gr_sparse_vec.h" + +slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulong *inds1, slong nnz1) +{ + slong ptr0 = 0; + slong ptr1 = 0; + slong count = 0; + while (ptr0 < nnz0 && ptr1 < nnz1) + { + slong ind0 = inds0[ptr0]; + slong ind1 = inds1[ptr1]; + if (ind0 <= ind1) + ptr0++; + if (ind0 >= ind1) + ptr1++; + count++; + } + if (ptr0 < nnz0) + count += (nnz0 - ptr0); + else if (ptr1 < nnz1) + count += (nnz1 - ptr1); + return count; +} \ No newline at end of file diff --git a/src/gr_sparse_vec/fit_nnz.c b/src/gr_sparse_vec/fit_nnz.c index 8b5e3c3d9b..c21b6ee665 100644 --- a/src/gr_sparse_vec/fit_nnz.c +++ b/src/gr_sparse_vec/fit_nnz.c @@ -1,17 +1,22 @@ #include "gr_sparse_vec.h" void -gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) +gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) { slong alloc = vec->alloc; - if (len > alloc) + /* It doesn't make sense to allocate more than the ambient dimension */ + if (nnz > vec->length) + nnz = vec->length; + if (nnz > alloc) { slong sz = ctx->sizeof_elem; - if (len < 2 * alloc) - len = 2 * alloc; - vec->inds = flint_realloc(vec->inds, len * sizeof(ulong)); - vec->entries = flint_realloc(vec->entries, len * sz); - _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), len - alloc, ctx); + if (nnz < 2 * alloc) + nnz = 2 * alloc; + if (nnz > vec->length) + nnz = vec->length; + vec->inds = flint_realloc(vec->inds, nnz * sizeof(ulong)); + vec->entries = flint_realloc(vec->entries, nnz * sz); + _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), nnz - alloc, ctx); vec->alloc = len; } } \ No newline at end of file diff --git a/src/gr_sparse_vec/set.c b/src/gr_sparse_vec/set.c index d4c6dcbf80..ac43e2d3c1 100644 --- a/src/gr_sparse_vec/set.c +++ b/src/gr_sparse_vec/set.c @@ -9,8 +9,10 @@ gr_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) slong nnz = src->nnz; gr_sparse_vec_fit_nnz(res, nnz, ctz); memcpy(res->inds, src->inds, nnz*sizeof(slong)); - res->nnz = nnz; status = _gr_vec_set(res->entries, src->entries, nnz, ctx); + res->nnz = nnz; + res->alloc = nnz; + res->length = src->length; } return status; } \ No newline at end of file diff --git a/src/gr_sparse_vec/set_length.c b/src/gr_sparse_vec/set_length.c index e73be42404..448fb63030 100644 --- a/src/gr_sparse_vec/set_length.c +++ b/src/gr_sparse_vec/set_length.c @@ -3,43 +3,13 @@ void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { - slong i; - vec->len = len; - for (i=vec->nnz-1; i>=0; i--) - { - - } - - slong alloc = vec->alloc; - if (len > alloc) - { - slong sz = ctx->sizeof_elem; - if (len < 2 * alloc) - len = 2 * alloc; - vec->inds = flint_realloc(vec->inds, len * sizeof(ulong)); - vec->entries = flint_realloc(vec->entries, len * sz); - _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), len - alloc, ctx); - vec->alloc = len; - } -} - - - -#include "gr_vec.h" - -void -gr_vec_set_length(gr_vec_t vec, slong len, gr_ctx_t ctx) -{ - if (vec->length > len) - { - /* potentially free no longer used elements */ - GR_MUST_SUCCEED(_gr_vec_zero(GR_ENTRY(vec->entries, len, ctx->sizeof_elem), vec->length - len, ctx)); - } - else if (vec->length < len) + vec->length = len; + /* Scan backward through the nonzeros to discard the ones off the end */ + /* Note that we don't actually free anything; we just mark the nonzeros as unused */ + slong i=vec->nnz-1; + while (i>=0 && vec->inds[i] >= len) { - gr_vec_fit_length(vec, len, ctx); - GR_MUST_SUCCEED(_gr_vec_zero(GR_ENTRY(vec->entries, vec->length, ctx->sizeof_elem), len - vec->length, ctx)); + i--; } - - vec->length = len; + vec->nnz = i+1; } diff --git a/src/gr_sparse_vec/update.c b/src/gr_sparse_vec/update.c index c6e83305bd..6a31b84850 100644 --- a/src/gr_sparse_vec/update.c +++ b/src/gr_sparse_vec/update.c @@ -1,28 +1,72 @@ #include "gr_sparse_vec.h" -// int -// gr_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) -// { -// int status = GR_SUCCESS; -// if (res != src) -// { -// slong nnz = src->nnz; -// gr_sparse_vec_fit_nnz(res, nnz, ctz); -// memcpy(res->inds, src->inds, nnz*sizeof(slong)); -// res->nnz = nnz; -// status = _gr_vec_set(res->entries, src->entries, nnz, ctx); -// } -// return status; -// } + int gr_sparse_vec_update(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx) { - gr_sparse_vec_update_entries(vec, src->entries, src->inds, src->nnz, ctx); + gr_sparse_vec_update_presorted_entries(vec, src->entries, src->inds, src->nnz, ctx); } int gr_sparse_vec_update_entries(gr_sparse_vec_t vec, gr_srcptr entries, const ulong* inds, slong nnz, gr_ctx_t ctx) { -} \ No newline at end of file +} + +int +gr_sparse_vec_update_presorted_entries(gr_sparse_vec_t vec, gr_srcptr entries, const ulong* sorted_inds, slong nnz, gr_ctx_t ctx) +{ + slong vec_nnz = vec->nnz; + slong vec_ind = 0; + slong si_ind = 0; + slong total_new_nnz = 0; + slong sz = ctx->sizeof_elem; + slond dest_ind; + while (vec_ind < vec_nnz && si_ind < nnz) + { + slong vi = vec->inds[vec_ind]; + slong sii = sorted_inds[si_ind]; + if (vi <= sii) + vec_ind += 1; + if (sii <= vi) + si_ind += 1; + total_new_nnz += 1; + } + if (vec_ind < vec_nnz) + total_new_nnz += (vec_nnz - vec_ind); + else if (si_ind < nnz) + total_new_nnz += (nnz - si_ind); + + gr_sparse_vec_fit_nnz(vec, total_new_nnz, ctx); + + vec_ind = vec->nnz-1; + si_ind = nnz-1; + dest_ind = total_new_nnz-1; + while (vec_ind >= 0 && si_ind >= 0) + { + slong vi = vec->inds[vec_ind]; + slong sii = sorted_inds[si_ind]; + if (vi > sii) + { + gr_set(GR_ENTRY(vec->entries, dest_ind, sz), GR_ENTRY(vec->entries, vec_ind, sz)); + vec->inds[dest_ind] = vec->inds[vec_ind]; + vec_ind--; + } + else if (sii > vi) + { + gr_set(GR_ENTRY(vec->entries, dest_ind, sz), GR_ENTRY(entries, si_ind, sz)); + vec->inds[dest_ind] = sorted_inds[si_ind]; + si_ind--; + } + else + { + gr_set(GR_ENTRY(vec->entries, dest_ind, sz), GR_ENTRY(entries, si_ind, sz)); + vec->inds[dest_ind] = sorted_inds[si_ind]; + si_ind--; + vec_ind--; + } + dest_ind--; + } + vec->nnz = total_new_nnz; +} From da2e5d42116c36fbcbbf0b5ba35bdf96565b324e Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Wed, 7 Feb 2024 17:37:47 -0800 Subject: [PATCH 06/59] gr sparse vec template stuff --- src/gr_sparse_vec.h | 104 +++++++++++++------------- src/gr_sparse_vec/count_unique_cols.c | 23 ++++++ src/gr_sparse_vec/count_unique_inds.c | 23 ------ src/gr_sparse_vec/fit_nnz.c | 2 +- src/gr_sparse_vec/set.c | 2 +- src/gr_sparse_vec/set_length.c | 2 +- 6 files changed, 78 insertions(+), 78 deletions(-) create mode 100644 src/gr_sparse_vec/count_unique_cols.c delete mode 100644 src/gr_sparse_vec/count_unique_inds.c diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 33956be74b..48a043bcb3 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -29,7 +29,7 @@ typedef struct { slong alloc; gr_ptr entries; - ulong *inds; + ulong *cols; slong length; slong nnz; } @@ -44,7 +44,7 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_init(gr_sparse_vec_t v GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) { _gr_vec_clear(vec->entries, vec->alloc, ctx); - flint_free(vec->inds); + flint_free(vec->cols); flint_free(vec->entries); memset(vec, 0, sizeof(gr_sparse_vec_t)); return GR_SUCCESS; @@ -53,15 +53,15 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_clear(gr_sparse_vec_t #define GR_SPARSE_VEC_ENTRY(vec, i, sz) GR_ENTRY((vec)->entries, i, sz) GR_SPARSE_VEC_INLINE ulong * -gr_sparse_vec_ind_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) +gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { - return vec->inds + i; + return vec->cols + i; } GR_SPARSE_VEC_INLINE const ulong * -gr_sparse_vec_ind_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) +gr_sparse_vec_col_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { - return vec->inds + i; + return vec->cols + i; } GR_SPARSE_VEC_INLINE gr_ptr @@ -84,48 +84,70 @@ GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec, gr_ctx_t void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx); slong gr_sparse_vec_length(const gr_sparse_vec_t vec) { return vec->length; } void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); + WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); -slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulong *inds1, slong nnz1); +slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulong *cols1, slong nnz1); /* This is used for operations like add */ -#define GR_SPARSE_VEC_RIFFLE_TEMPLATE(STATUS, FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_ENTRIES, A_INDS, A_NNZ, B_ENTRIES, B_INDS, B_NNZ, CTX) \ +#define GR_SPARSE_VEC_RIFFLE_TEMPLATE(LIT_FUNC_A, LIT_FUNC_B, LIT_FUNC_AB, DEST_VEC, A_COLS, A_NNZ, B_COLS, B_NNZ, CTX, CTX2) \ { + int status = GR_SUCCESS; slong sz = (CTX)->sizeof_elem; - slong new_nnz = _gr_sparse_vec_count_unique_inds((A_INDS), (A_NNZ), (B_INDS), (B_NNZ)) + slong sz2 = (CTX2)->sizeof_elem; + slong new_nnz = _gr_sparse_vec_count_unique_cols((A_COLS), (A_NNZ), (B_COLS), (B_NNZ)) gr_sparse_vec_fit_nnz(DEST_VEC, new_nnz, (CTX)); /* We go backward through the destination, because it might be an in-place operation on a source */ - slong a_ptr = (A_NNZ)-1; - slong b_ptr = (B_NNZ)-1; - slong v_ptr = new_nnz-1;; - while (a_ptr >= 0 && b_ptr >= 0 && (STATUS) == GR_SUCCESS) + slong a_ind = (A_NNZ)-1; + slong b_ind = (B_NNZ)-1; + slong dst_ind = new_nnz-1; + while (a_ind >= 0 && b_ind >= 0 && status == GR_SUCCESS) { - a_ind = (A_INDS)[a_ptr]; - b_ind = (B_INDS)[b_ptr]; - if (a_ind > b_ind) + slong a_col = (A_COLS)[a_ind]; + slong b_col = (B_COLS)[b_ind]; + if (a_col > b_col) { - STATUS |= FUNC_A(GR_ENTRY((DEST_VEC)->entries, v_ptr, sz), GR_ENTRY((A_ENTRIES), a_ptr, sz), (CTX)); - (DEST_VEC)->inds[v_ptr] = (A_INDS)[a_ptr]; - a_ptr--; + status |= LIT_FUNC_A; + (DEST_VEC)->cols[dst_ind] = a_col; + a_ind--; } - else if (b_ind > a_ind) + else if (b_col > a_col) { - STATUS |= FUNC_B(GR_ENTRY((DEST_VEC)->entries, v_ptr, sz), GR_ENTRY((B_ENTRIES), b_ptr, sz), (CTX)); - (DEST_VEC)->inds[v_ptr] = (B_INDS)[b_ptr]; - b_ptr--; + status |= LIT_FUNC_B; + (DEST_VEC)->cols[dst_ind] = b_col; + b_ind--; } else { - STATUS gr_set(GR_ENTRY(vec->entries, dest_ind, sz), GR_ENTRY(entries, si_ind, sz)); - vec->inds[dest_ind] = sorted_inds[si_ind]; - si_ind--; - vec_ind--; + status |= LIT_FUNC_AB; + (DEST_VEC)->cols[dest_ind] = a_col; + a_ind--; + b_ind--; } - v_ptr--; + dst_ind--; } - vec->nnz = new_nnz; + (DEST_VEC)->nnz = new_nnz; + return status; } +#define GR_SVEC_RIFFLE_COPY(Y, Y_ind) gr_set(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ptr, sz), ctx) +#define GR_SVEC_RIFFLE_NEG(Y, Y_ind) gr_neg(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ptr, sz), ctx) +#define GR_SVEC_RIFFLE_ADD() gr_add(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src1->entries, a_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx) +#define SUBAB gr_sub(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src1->entries, a_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYRES, COPYSRC, COPYSRC, res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYSRC1, COPYSRC2, ADDAB, vec, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYSRC1, NEGSRC2, SUBAB, vec, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx); } + +#define COPYOTHERSRC2 gr_set_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx2, ctx) +#define ADDOTHERAB gr_add_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src1->entries, a_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx2, ctx) +#define SUBOTHERAB gr_sub_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src1->entries, a_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx2, ctx) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, slong len, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYSRC1, COPYOTHERSRC2, ADDAOTHERB, vec, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx2); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, slong len, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYSRC1, COPYOTHERSRC2, SUBAOTHERB, vec, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx2); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_other_add(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_ADD_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_other_sub(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_SUB_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } + + #define GR_SPARSE_VEC_DENSE_VEC_OP(g, res, src, c, ctx) \ { \ @@ -142,10 +164,6 @@ int gr_sparse_vec_mul_scalar_si(gr_vec_t res, gr_vec_t src, slong c, gr_ctx_t ct -WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_update_entries(gr_sparse_vec_t vec, gr_srcptr entries, const ulong* inds, slong nnz, gr_ctx_t ctx); - - //I think the below might be the same as "add" @@ -155,7 +173,6 @@ int gr_sparse_vec_write(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx int gr_sparse_vec_print(const gr_sparse_vec_t vec, gr_ctx_t ctx); GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_CONSTANT_OP(ctx, VEC_ZERO)(vec, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP(ctx, VEC_SET)(res, src, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP(ctx, VEC_NEG)(res, src, len, ctx); } WARN_UNUSED_RESULT int gr_sparse_vec_from_entries(gr_sparse_vec_t vec, slong * inds, gr_srcptr vals, slong nnz); @@ -183,64 +200,47 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_normalise(slong * res, GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT slong gr_sparse_vec_normalise_weak(const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_NORMALISE_WEAK_OP(ctx, VEC_NORMALISE_WEAK)(vec, len, ctx); } */ -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_ADD)(res, src1, src2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_SUB)(res, src1, src2, len, ctx); } + GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_MUL)(res, src1, src2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIV)(res, src1, src2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIVEXACT)(res, src1, src2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_POW)(res, src1, src2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_ADD_SCALAR)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_SUB_SCALAR)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_MUL_SCALAR)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_DIV_SCALAR)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_DIVEXACT_SCALAR)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_POW_SCALAR)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_ADD_SCALAR_SI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_SUB_SCALAR_SI)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_MUL_SCALAR_SI)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_DIV_SCALAR_SI)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_DIVEXACT_SCALAR_SI)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_POW_SCALAR_SI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_ADD_SCALAR_UI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_SUB_SCALAR_UI)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_MUL_SCALAR_UI)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_DIV_SCALAR_UI)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_DIVEXACT_SCALAR_UI)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_POW_SCALAR_UI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_ADD_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_SUB_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_MUL_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_DIV_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_DIVEXACT_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_POW_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_ADD_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_SUB_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_MUL_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_DIV_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_DIVEXACT_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_POW_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_add_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_ADD_VEC)(vec1, c, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_sub_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_SUB_VEC)(vec1, c, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_mul_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_MUL_VEC)(vec1, c, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_div_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_DIV_VEC)(vec1, c, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_divexact_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_DIVEXACT_VEC)(vec1, c, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_pow_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_POW_VEC)(vec1, c, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_ADD_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_SUB_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_MUL_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_DIV_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_DIVEXACT_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_POW_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_ADD_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_SUB_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_mul_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_MUL_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_div_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_DIV_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_divexact_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_DIVEXACT_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } diff --git a/src/gr_sparse_vec/count_unique_cols.c b/src/gr_sparse_vec/count_unique_cols.c new file mode 100644 index 0000000000..3a5186a8a4 --- /dev/null +++ b/src/gr_sparse_vec/count_unique_cols.c @@ -0,0 +1,23 @@ +#include "gr_sparse_vec.h" + +slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulong *cols1, slong nnz1) +{ + slong ind0 = 0; + slong ind1 = 0; + slong count = 0; + while (ind0 < nnz0 && ind1 < nnz1) + { + slong col0 = cols0[ind0]; + slong col1 = cols1[ind1]; + if (col0 <= col1) + ind0++; + if (col0 >= col1) + ind1++; + count++; + } + if (ind0 < nnz0) + count += (nnz0 - ind0); + else if (ind1 < nnz1) + count += (nnz1 - ind1); + return count; +} \ No newline at end of file diff --git a/src/gr_sparse_vec/count_unique_inds.c b/src/gr_sparse_vec/count_unique_inds.c deleted file mode 100644 index 1d8a8e6671..0000000000 --- a/src/gr_sparse_vec/count_unique_inds.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "gr_sparse_vec.h" - -slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulong *inds1, slong nnz1) -{ - slong ptr0 = 0; - slong ptr1 = 0; - slong count = 0; - while (ptr0 < nnz0 && ptr1 < nnz1) - { - slong ind0 = inds0[ptr0]; - slong ind1 = inds1[ptr1]; - if (ind0 <= ind1) - ptr0++; - if (ind0 >= ind1) - ptr1++; - count++; - } - if (ptr0 < nnz0) - count += (nnz0 - ptr0); - else if (ptr1 < nnz1) - count += (nnz1 - ptr1); - return count; -} \ No newline at end of file diff --git a/src/gr_sparse_vec/fit_nnz.c b/src/gr_sparse_vec/fit_nnz.c index c21b6ee665..3499f60b38 100644 --- a/src/gr_sparse_vec/fit_nnz.c +++ b/src/gr_sparse_vec/fit_nnz.c @@ -14,7 +14,7 @@ gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) nnz = 2 * alloc; if (nnz > vec->length) nnz = vec->length; - vec->inds = flint_realloc(vec->inds, nnz * sizeof(ulong)); + vec->cols = flint_realloc(vec->cols, nnz * sizeof(ulong)); vec->entries = flint_realloc(vec->entries, nnz * sz); _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), nnz - alloc, ctx); vec->alloc = len; diff --git a/src/gr_sparse_vec/set.c b/src/gr_sparse_vec/set.c index ac43e2d3c1..eea6f464f5 100644 --- a/src/gr_sparse_vec/set.c +++ b/src/gr_sparse_vec/set.c @@ -8,7 +8,7 @@ gr_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { slong nnz = src->nnz; gr_sparse_vec_fit_nnz(res, nnz, ctz); - memcpy(res->inds, src->inds, nnz*sizeof(slong)); + memcpy(res->cols, src->cols, nnz*sizeof(slong)); status = _gr_vec_set(res->entries, src->entries, nnz, ctx); res->nnz = nnz; res->alloc = nnz; diff --git a/src/gr_sparse_vec/set_length.c b/src/gr_sparse_vec/set_length.c index 448fb63030..969bb8b832 100644 --- a/src/gr_sparse_vec/set_length.c +++ b/src/gr_sparse_vec/set_length.c @@ -7,7 +7,7 @@ gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) /* Scan backward through the nonzeros to discard the ones off the end */ /* Note that we don't actually free anything; we just mark the nonzeros as unused */ slong i=vec->nnz-1; - while (i>=0 && vec->inds[i] >= len) + while (i>=0 && vec->cols[i] >= len) { i--; } From d92805514b5a198c9980479f6ed38ba161d459e3 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Wed, 7 Feb 2024 20:16:47 -0800 Subject: [PATCH 07/59] working on gr_sparse vec templates --- src/gr_sparse_vec.h | 95 +++++++++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 48a043bcb3..cb7b7c6a3d 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -90,11 +90,11 @@ WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_ve slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulong *cols1, slong nnz1); /* This is used for operations like add */ -#define GR_SPARSE_VEC_RIFFLE_TEMPLATE(LIT_FUNC_A, LIT_FUNC_B, LIT_FUNC_AB, DEST_VEC, A_COLS, A_NNZ, B_COLS, B_NNZ, CTX, CTX2) \ +#define GR_SPVEC_RIFFLE_TEMPLATE(LIT_FUNC_A, LIT_FUNC_B, LIT_FUNC_AB, DEST_VEC, A_COLS, A_NNZ, B_COLS, B_NNZ, CTX, OTHERCTX) \ { int status = GR_SUCCESS; slong sz = (CTX)->sizeof_elem; - slong sz2 = (CTX2)->sizeof_elem; + slong osz = (OTHERCTX)->sizeof_elem; slong new_nnz = _gr_sparse_vec_count_unique_cols((A_COLS), (A_NNZ), (B_COLS), (B_NNZ)) gr_sparse_vec_fit_nnz(DEST_VEC, new_nnz, (CTX)); /* We go backward through the destination, because it might be an in-place operation on a source */ @@ -130,22 +130,77 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo return status; } -#define GR_SVEC_RIFFLE_COPY(Y, Y_ind) gr_set(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ptr, sz), ctx) -#define GR_SVEC_RIFFLE_NEG(Y, Y_ind) gr_neg(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ptr, sz), ctx) -#define GR_SVEC_RIFFLE_ADD() gr_add(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src1->entries, a_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx) -#define SUBAB gr_sub(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src1->entries, a_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYRES, COPYSRC, COPYSRC, res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYSRC1, COPYSRC2, ADDAB, vec, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYSRC1, NEGSRC2, SUBAB, vec, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_neg_other(gr_ptr res, gr_srcptr src, gr_ctx_t src_ctx, gr_ctx_t ctx) { return (gr_set_other(res, src, src_ctx, ctx) | gr_neg(res, res, ctx)); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) { return (gr_mul(res, x, y, ctx) | gr_neg(res, res, ctx)); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx) { return (gr_mul_si(res, x, y, ctx) | gr_neg(res, res, ctx)); } + +#define GR_SPVEC_RIFFLE_UOP(F, Y, Y_ind) F(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) + +#define GR_SPVEC_RIFFLE_COPY(Y, Y_ind) gr_set(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) +#define GR_SPVEC_RIFFLE_NEG(Y, Y_ind) gr_neg(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) +#define GR_SPVEC_RIFFLE_ADD(Y, Y_ind, Z, Z_ind) gr_add(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) +#define GR_SPVEC_RIFFLE_SUB(Y, Y_ind, Z, Z_ind) gr_sub(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(res, a_ind), GP_SPVEC_RIFFLE_COPY(src, b_ind), GP_SPVEC_RIFFLE_COPY(src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); +} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(src1, a_ind), GP_SPVEC_RIFFLE_COPY(src2, b_ind), GP_SPVEC_RIFFLE_ADD(src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx); +} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(src1, a_ind), GP_SPVEC_RIFFLE_NEG(src2, b_ind), GP_SPVEC_RIFFLE_SUB(src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx); +} + +#define GR_SPVEC_RIFFLE_BOPOTHER(Y, Y_ind) gr_set_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, osz), ctx2, ctx) + +juiosdfjiosdjfosdf + +#define GR_SPVEC_RIFFLE_COPYOTHER(Y, Y_ind) gr_set_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, osz), ctx2, ctx) +#define GR_SPVEC_RIFFLE_NEGOTHER(Y, Y_ind) gr_neg_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, osz), ctx2, ctx) +#define GR_SPVEC_RIFFLE_ADDOTHER(Y, Y_ind, Z, Z_ind) gr_add_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, osz), ctx2, ctx) +#define GR_SPVEC_RIFFLE_SUBOTHER(Y, Y_ind, Z, Z_ind) gr_sub_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, osz), ctx2, ctx) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(src1, a_ind), GP_SPVEC_RIFFLE_COPYOTHER(src2, b_ind), GR_SPVEC_RIFFLE_ADDOTHER(src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx2); +} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(src1, a_ind), GP_SPVEC_RIFFLE_NEGOTHER(src1, a_ind), GR_SPVEC_RIFFLE_SUBOTHER(src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx2); +} + +#define GR_SPVEC_RIFFLE_OTHERBOP(F, Y, Y_ind, Z, Z_ind) F(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, osz), ctx1, GR_ENTRY(Z->entries, Z_ind, sz), ctx) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPYOTHER(src1, a_ind), GP_SPVEC_RIFFLE_COPY(src2, b_ind), GR_SPVEC_RIFFLE_OTHERCOP(gr_other_add, src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx1); +} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPYOTHER(src1, a_ind), GP_SPVEC_RIFFLE_NEG(src2, b_ind), GR_SPVEC_RIFFLE_OTHERBOP(gr_other_sub, src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx1); +} + + +#define GR_SPVEC_RIFFLE_UOP_SCALAR(F, Y, Y_ind) F(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), c, ctx) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_UOP(gr_set, res, a_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_mul, src, b_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_addmul, src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); +} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_UOP(gr_set, res, a_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_negmul, src, b_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_submul, src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); +} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_UOP(gr_set, res, a_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_mul_si, src, b_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_addmul_si, src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); +} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ + GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_UOP(gr_set, res, a_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_negmul_si, src, b_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_submul_si, src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); +} + -#define COPYOTHERSRC2 gr_set_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx2, ctx) -#define ADDOTHERAB gr_add_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src1->entries, a_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx2, ctx) -#define SUBOTHERAB gr_sub_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(src1->entries, a_ptr, sz), GR_ENTRY(src2->entries, b_ptr, sz), ctx2, ctx) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, slong len, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYSRC1, COPYOTHERSRC2, ADDAOTHERB, vec, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx2); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, slong len, gr_ctx_t ctx) { GR_SPARSE_VEC_RIFFLE_TEMPLATE(COPYSRC1, COPYOTHERSRC2, SUBAOTHERB, vec, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx2); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_other_add(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_ADD_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_other_sub(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_SUB_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } @@ -246,15 +301,11 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_div_vec(gr_sparse_vec_t vec GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_divexact_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_DIVEXACT_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_pow_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_POW_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_ADD_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_SUB_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_MUL_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_DIV_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_DIVEXACT_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_POW_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_add_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_ADD_VEC)(vec1, c, cctx, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_sub_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_SUB_VEC)(vec1, c, cctx, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_mul_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_MUL_VEC)(vec1, c, cctx, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_div_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_DIV_VEC)(vec1, c, cctx, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_divexact_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_DIVEXACT_VEC)(vec1, c, cctx, vec2, len, ctx); } @@ -262,10 +313,6 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_pow_vec(gr_sparse_ve GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_MUL_SCALAR_2EXP_SI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_ADDMUL_SCALAR)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_SUBMUL_SCALAR)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_ADDMUL_SCALAR_SI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_SUBMUL_SCALAR_SI)(vec1, vec2, len, c, ctx); } GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_PREDICATE(ctx, VEC_EQUAL)(vec1, vec2, len, ctx); } GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_PREDICATE(ctx, VEC_IS_ZERO)(vec, len, ctx); } From c14897c76f481f3d7e9be8682083e8345577ce69 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Thu, 8 Feb 2024 17:54:53 -0800 Subject: [PATCH 08/59] working on several sparse vec functions --- src/gr_sparse_vec.h | 256 +++++++++++--------------- src/gr_sparse_vec/count_unique_cols.c | 3 +- src/gr_sparse_vec/equal.c | 13 ++ src/gr_sparse_vec/fit_nnz.c | 2 +- src/gr_sparse_vec/from_dense.c | 28 +++ src/gr_sparse_vec/permute_cols.c | 49 +++++ src/gr_sparse_vec/set_from_entries.c | 99 ++++++++++ src/gr_sparse_vec/shrink_to_nnz.c | 13 ++ src/gr_sparse_vec/slice.c | 40 ++++ src/gr_sparse_vec/to_dense.c | 25 +++ src/gr_sparse_vec/update.c | 72 -------- src/gr_sparse_vec/write.c | 29 +++ 12 files changed, 411 insertions(+), 218 deletions(-) create mode 100644 src/gr_sparse_vec/equal.c create mode 100644 src/gr_sparse_vec/from_dense.c create mode 100644 src/gr_sparse_vec/permute_cols.c create mode 100644 src/gr_sparse_vec/set_from_entries.c create mode 100644 src/gr_sparse_vec/shrink_to_nnz.c create mode 100644 src/gr_sparse_vec/slice.c create mode 100644 src/gr_sparse_vec/to_dense.c delete mode 100644 src/gr_sparse_vec/update.c create mode 100644 src/gr_sparse_vec/write.c diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index cb7b7c6a3d..337b8d25fa 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -37,8 +37,9 @@ gr_sparse_vec_struct; typedef gr_sparse_vec_struct gr_sparse_vec_t[1]; -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_init(gr_sparse_vec_t vec, gr_ctx_t ctx) { +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_init(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { memset(vec, 0, sizeof(gr_sparse_vec_t)); + vec->length = len; return GR_SUCCESS; } @@ -82,122 +83,129 @@ GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec, gr_ctx_t } void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx); +void gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx); slong gr_sparse_vec_length(const gr_sparse_vec_t vec) { return vec->length; } void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); +slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) { return vec->nnz; } WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entries, slong nnz); +WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, slong * sorted_cols, gr_srcptr entries, slong nnz); +WARN_UNUSED_RESULT int gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); + +int gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx); +int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx); + + + + slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulong *cols1, slong nnz1); -/* This is used for operations like add */ -#define GR_SPVEC_RIFFLE_TEMPLATE(LIT_FUNC_A, LIT_FUNC_B, LIT_FUNC_AB, DEST_VEC, A_COLS, A_NNZ, B_COLS, B_NNZ, CTX, OTHERCTX) \ -{ - int status = GR_SUCCESS; - slong sz = (CTX)->sizeof_elem; - slong osz = (OTHERCTX)->sizeof_elem; - slong new_nnz = _gr_sparse_vec_count_unique_cols((A_COLS), (A_NNZ), (B_COLS), (B_NNZ)) - gr_sparse_vec_fit_nnz(DEST_VEC, new_nnz, (CTX)); - /* We go backward through the destination, because it might be an in-place operation on a source */ - slong a_ind = (A_NNZ)-1; - slong b_ind = (B_NNZ)-1; - slong dst_ind = new_nnz-1; - while (a_ind >= 0 && b_ind >= 0 && status == GR_SUCCESS) - { - slong a_col = (A_COLS)[a_ind]; - slong b_col = (B_COLS)[b_ind]; - if (a_col > b_col) - { - status |= LIT_FUNC_A; - (DEST_VEC)->cols[dst_ind] = a_col; - a_ind--; - } - else if (b_col > a_col) - { - status |= LIT_FUNC_B; - (DEST_VEC)->cols[dst_ind] = b_col; - b_ind--; - } - else - { - status |= LIT_FUNC_AB; - (DEST_VEC)->cols[dest_ind] = a_col; - a_ind--; - b_ind--; - } - dst_ind--; - } - (DEST_VEC)->nnz = new_nnz; - return status; + + +#define GR_SPV_SWAP_INDS(VEC, I, J, CTX) \ +{ \ + slong _temp = (VEC)->cols[I]; \ + (VEC)->cols[I] = (VEC)->cols[J]; \ + (VEC)->cols[J] = _temp; \ + gr_swap(GR_ENTRY((VEC)->entries, (I), ctx), GR_ENTRY((VEC)->entries, (J), ctx), ctx); \ } + +/* This is used for operations like add which have to riffle through the entries of two vectors */ +#define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ + int status; \ + slong sz, new_nnz, a_ind, b_ind, dest_ind, a_nnz, b_nnz, a_col, b_col, i; \ + if ((DEST_VEC)->length != (A_VEC)->length || (A_VEC)->length != (B_VEC)->length) \ + return GR_DOMAIN; \ + status = GR_SUCCESS; \ + sz = (CTX)->sizeof_elem; \ + a_nnz = (A_VEC)->nnz; \ + b_nnz = (B_VEC)->nnz; \ + new_nnz = _gr_sparse_vec_count_unique_cols((A_VEC)->cols, a_nnz, (B_VEC)->cols, b_nnz); \ + gr_sparse_vec_fit_nnz((DEST_VEC), new_nnz, (CTX)); \ + /* We go backward through the destination, because it might be an in-place operation on a source */ \ + a_ind = a_nnz-1; \ + b_ind = b_nnz-1; \ + dest_ind = new_nnz-1; \ + while (a_ind >= 0 && b_ind >= 0 && status == GR_SUCCESS) \ + { \ + a_col = (A_VEC)->cols[a_ind]; \ + b_col = (B_VEC)->cols[b_ind]; \ + if (a_col > b_col) \ + { \ + status |= (FUNC_A); \ + (DEST_VEC)->cols[dest_ind] = a_col; \ + a_ind--; \ + } \ + else if (b_col > a_col) \ + { \ + status |= (FUNC_B); \ + (DEST_VEC)->cols[dest_ind] = b_col; \ + b_ind--; \ + } \ + else \ + { \ + status |= (FUNC_AB); \ + (DEST_VEC)->cols[dest_ind] = a_col; \ + a_ind--; \ + b_ind--; \ + } \ + if (T_FALSE == gr_is_zero(GR_ENTRY((DEST_VEC)->entries, dest_ind, sz))) \ + dest_ind--; \ + } \ + /* Move the result to the beginning of the dest vec */ \ + /* Currently, dest_ind points to one before the start of the legit destination values */ \ + if (dest_ind >= 0 && !status) \ + { \ + new_nnz = (new_nnz-1) - dest_ind; \ + dest_ind++; \ + for (i = 0; i < new_nnz; i++) \ + GR_SPV_SWAP_INDS(DEST_VEC, i, dest_ind + i, CTX); \ + } \ + (DEST_VEC)->nnz = new_nnz; \ + return status; + GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_neg_other(gr_ptr res, gr_srcptr src, gr_ctx_t src_ctx, gr_ctx_t ctx) { return (gr_set_other(res, src, src_ctx, ctx) | gr_neg(res, res, ctx)); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) { return (gr_mul(res, x, y, ctx) | gr_neg(res, res, ctx)); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx) { return (gr_mul_si(res, x, y, ctx) | gr_neg(res, res, ctx)); } -#define GR_SPVEC_RIFFLE_UOP(F, Y, Y_ind) F(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) +#define GR_SPV_RFL_UOP(F, Y, Y_ind) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) +#define GR_SPV_RFL_BOP(F, Y, Y_ind, Z, Z_ind) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) -#define GR_SPVEC_RIFFLE_COPY(Y, Y_ind) gr_set(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) -#define GR_SPVEC_RIFFLE_NEG(Y, Y_ind) gr_neg(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) -#define GR_SPVEC_RIFFLE_ADD(Y, Y_ind, Z, Z_ind) gr_add(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) -#define GR_SPVEC_RIFFLE_SUB(Y, Y_ind, Z, Z_ind) gr_sub(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(res, a_ind), GP_SPVEC_RIFFLE_COPY(src, b_ind), GP_SPVEC_RIFFLE_COPY(src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); -} -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(src1, a_ind), GP_SPVEC_RIFFLE_COPY(src2, b_ind), GP_SPVEC_RIFFLE_ADD(src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx); -} -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(src1, a_ind), GP_SPVEC_RIFFLE_NEG(src2, b_ind), GP_SPVEC_RIFFLE_SUB(src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx); -} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP(gr_set, src, b_ind), GR_SPV_RFL_UOP(gr_set, src, b_ind), res, res, src, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP(gr_set, src2, b_ind), GR_SPV_RFL_BOP(gr_add, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP(gr_neg, src2, b_ind), GR_SPV_RFL_BOP(gr_sub, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } -#define GR_SPVEC_RIFFLE_BOPOTHER(Y, Y_ind) gr_set_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, osz), ctx2, ctx) +#define GR_SPV_RFL_UOP_OTHER(F, Y, Y_ind, CTX2) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), CTX2, ctx) +#define GR_SPV_RFL_BOP_OTHER(F, Y, Y_ind, Z, Z_ind, CTX2) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, CTX2->sizeof_elem), CTX2, ctx) -juiosdfjiosdjfosdf +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_set, src2, b_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_add, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_sub, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } -#define GR_SPVEC_RIFFLE_COPYOTHER(Y, Y_ind) gr_set_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, osz), ctx2, ctx) -#define GR_SPVEC_RIFFLE_NEGOTHER(Y, Y_ind) gr_neg_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, osz), ctx2, ctx) -#define GR_SPVEC_RIFFLE_ADDOTHER(Y, Y_ind, Z, Z_ind) gr_add_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, osz), ctx2, ctx) -#define GR_SPVEC_RIFFLE_SUBOTHER(Y, Y_ind, Z, Z_ind) gr_sub_other(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, osz), ctx2, ctx) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(src1, a_ind), GP_SPVEC_RIFFLE_COPYOTHER(src2, b_ind), GR_SPVEC_RIFFLE_ADDOTHER(src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx2); -} -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPY(src1, a_ind), GP_SPVEC_RIFFLE_NEGOTHER(src1, a_ind), GR_SPVEC_RIFFLE_SUBOTHER(src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx2); -} +#define GR_SPV_RFL_OTHER_BOP(F, Y, Y_ind, CTX2, Z, Z_ind) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), GR_ENTRY(Z->entries, Z_ind, sz), ctx) -#define GR_SPVEC_RIFFLE_OTHERBOP(F, Y, Y_ind, Z, Z_ind) F(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, osz), ctx1, GR_ENTRY(Z->entries, Z_ind, sz), ctx) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPYOTHER(src1, a_ind), GP_SPVEC_RIFFLE_COPY(src2, b_ind), GR_SPVEC_RIFFLE_OTHERCOP(gr_other_add, src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx1); -} -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_COPYOTHER(src1, a_ind), GP_SPVEC_RIFFLE_NEG(src2, b_ind), GR_SPVEC_RIFFLE_OTHERBOP(gr_other_sub, src1, a_ind, src2, b_ind), res, src1->inds, src1->nnz, src2->inds, src2->nnz, ctx, ctx1); -} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), GR_SPV_RFL_UOP(gr_set, src2, b_ind), GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), GR_SPV_RFL_UOP(gr_neg, src2, b_ind), GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } +#define GR_SPV_RFL_UOP_SCALAR(F, Y, Y_ind) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), c, ctx) -#define GR_SPVEC_RIFFLE_UOP_SCALAR(F, Y, Y_ind) F(GR_ENTRY(res->entries, dst_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), c, ctx) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_UOP(gr_set, res, a_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_mul, src, b_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_addmul, src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); -} -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_UOP(gr_set, res, a_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_negmul, src, b_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_submul, src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); -} -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_UOP(gr_set, res, a_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_mul_si, src, b_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_addmul_si, src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); -} -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ - GR_SPVEC_RIFFLE_TEMPLATE(GP_SPVEC_RIFFLE_UOP(gr_set, res, a_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_negmul_si, src, b_ind), GP_SPVEC_RIFFLE_UOP_SCALAR(gr_submul_si, src, b_ind), res, res->inds, res->nnz, src->inds, src->nnz, ctx, ctx); -} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_mul, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_addmul, src, b_ind), res, res, src, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_negmul, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_submul, src, b_ind), res, res, src, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_mul_si, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_addmul_si, src, b_ind), res, res, src, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_negmul_si, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_submul_si, src, b_ind), res, res, src, ctx); } + +truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx); +GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return (vec->nnz == 0); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; return GR_SUCCESS; } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { return (gr_sparse_vec_set(res, src, ctx) | _gr_vec_neg(res->entries, res->entries, res->nnz, ctx)); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sum(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_sum(res, vec->entries, vec->nnz, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_product(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_product(res, vec->entries, vec->nnz, ctx); } @@ -218,33 +226,15 @@ int gr_sparse_vec_mul_scalar(gr_vec_t res, gr_vec_t src, gr_srcptr c, gr_ctx_t c int gr_sparse_vec_mul_scalar_si(gr_vec_t res, gr_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } +/******************************************************************/ +/******************************************************************/ +/******************************************************************/ +/******************************************************************/ +/******************************************************************/ +/******************************************************************/ -//I think the below might be the same as "add" -WARN_UNUSED_RESULT int gr_sparse_vec_extend(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx); - -int gr_sparse_vec_write(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx); -int gr_sparse_vec_print(const gr_sparse_vec_t vec, gr_ctx_t ctx); - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_CONSTANT_OP(ctx, VEC_ZERO)(vec, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP(ctx, VEC_NEG)(res, src, len, ctx); } - -WARN_UNUSED_RESULT int gr_sparse_vec_from_entries(gr_sparse_vec_t vec, slong * inds, gr_srcptr vals, slong nnz); - -WARN_UNUSED_RESULT int gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len); - -WARN_UNUSED_RESULT int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, slong len); -WARN_UNUSED_RESULT int gr_sparse_vec_split(gr_sparse_vec_t res1, gr_sparse_vec_t res2, const gr_sparse_vec_t vec, slong ind); - -/* Vector permutation */ -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, slong *P) -{ - slong i; - for (i = 0; i < vec->nnz; ++i) vec->inds[i] = P[vec->inds[i]]; - // TODO: re-sort vector -} - /* typedef int ((*gr_method_vec_normalise_op)(slong *, gr_srcptr, slong, gr_ctx_ptr)); typedef slong ((*gr_method_vec_normalise_weak_op)(gr_srcptr, slong, gr_ctx_ptr)); @@ -314,8 +304,6 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_pow_vec(gr_sparse_ve GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_MUL_SCALAR_2EXP_SI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_PREDICATE(ctx, VEC_EQUAL)(vec1, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_PREDICATE(ctx, VEC_IS_ZERO)(vec, len, ctx); } typedef int ((*gr_method_vec_reduce_op)(gr_sparse_vec_t, gr_srcptr, slong, gr_ctx_ptr)); @@ -330,38 +318,18 @@ typedef int ((*gr_method_vec_dot_fmpz_op)(gr_sparse_vec_t, gr_srcptr, int, gr_sr #define GR_SPARSE_VEC_DOT_UI_OP(ctx, NAME) (((gr_method_vec_dot_ui_op *) ctx->methods)[GR_METHOD_ ## NAME]) #define GR_SPARSE_VEC_DOT_FMPZ_OP(ctx, NAME) (((gr_method_vec_dot_fmpz_op *) ctx->methods)[GR_METHOD_ ## NAME]) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sum(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_REDUCE_OP(ctx, VEC_SUM)(res, vec, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_product(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_REDUCE_OP(ctx, VEC_PRODUCT)(res, vec, len, ctx); } - GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_OP(ctx, VEC_DOT)(res, initial, subtract, vec1, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_rev(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_OP(ctx, VEC_DOT_REV)(res, initial, subtract, vec1, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_si(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const slong * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_SI_OP(ctx, VEC_DOT_SI)(res, initial, subtract, vec1, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_ui(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const ulong * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_UI_OP(ctx, VEC_DOT_UI)(res, initial, subtract, vec1, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_fmpz(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const fmpz * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_FMPZ_OP(ctx, VEC_DOT_FMPZ)(res, initial, subtract, vec1, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_reciprocals(gr_ptr res, slong len, gr_ctx_t ctx) { return GR_UNARY_OP_SI(ctx, VEC_RECIPROCALS)(res, len, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_set_powers(gr_ptr res, gr_srcptr x, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP(ctx, VEC_SET_POWERS)(res, x, len, ctx); } /* todo: could allow overloading this as well */ /* todo: worth warning about unused result? */ WARN_UNUSED_RESULT int gr_sparse_vec_randtest(gr_ptr res, flint_rand_t state, slong len, gr_ctx_t ctx); -/* -WARN_UNUSED_RESULT int gr_sparse_vec_sum_bsplit_parallel(gr_ptr res, const gr_sparse_vec_t vec, slong len, slong basecase_cutoff, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_sum_bsplit(gr_ptr res, const gr_sparse_vec_t vec, slong len, slong basecase_cutoff, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_sum_parallel(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_sum_serial(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_sum_generic(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int gr_sparse_vec_product_bsplit_parallel(gr_ptr res, const gr_sparse_vec_t vec, slong len, slong basecase_cutoff, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_product_bsplit(gr_ptr res, const gr_sparse_vec_t vec, slong len, slong basecase_cutoff, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_product_parallel(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_product_serial(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_product_generic(gr_ptr res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int gr_sparse_vec_step(gr_sparse_vec_t vec, gr_srcptr start, gr_srcptr step, slong len, gr_ctx_t ctx); -*/ + #ifdef __cplusplus } diff --git a/src/gr_sparse_vec/count_unique_cols.c b/src/gr_sparse_vec/count_unique_cols.c index 3a5186a8a4..aa354112e0 100644 --- a/src/gr_sparse_vec/count_unique_cols.c +++ b/src/gr_sparse_vec/count_unique_cols.c @@ -1,6 +1,7 @@ #include "gr_sparse_vec.h" -slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulong *cols1, slong nnz1) +slong +_gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulong *cols1, slong nnz1) { slong ind0 = 0; slong ind1 = 0; diff --git a/src/gr_sparse_vec/equal.c b/src/gr_sparse_vec/equal.c new file mode 100644 index 0000000000..47b7004c14 --- /dev/null +++ b/src/gr_sparse_vec/equal.c @@ -0,0 +1,13 @@ +truth_t +gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx) +{ + slong nnz, i, sz; + sz = ctx->sizeof_elem; + if (vec1->length != vec2->length || vec->nnz != vec2->nnz) + return T_FALSE; + nnz = vec1->nnz; + for (i = 0; i < nnz; i++) + if (T_TRUE != gr_equal(GR_ENTRY(vec1->entries, i, sz), GR_ENTRY(vec2->entries, i2, sz), ctx)) + return T_FALSE; + return T_TRUE; +} \ No newline at end of file diff --git a/src/gr_sparse_vec/fit_nnz.c b/src/gr_sparse_vec/fit_nnz.c index 3499f60b38..edb48a8ed8 100644 --- a/src/gr_sparse_vec/fit_nnz.c +++ b/src/gr_sparse_vec/fit_nnz.c @@ -19,4 +19,4 @@ gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), nnz - alloc, ctx); vec->alloc = len; } -} \ No newline at end of file +} diff --git a/src/gr_sparse_vec/from_dense.c b/src/gr_sparse_vec/from_dense.c new file mode 100644 index 0000000000..8999619515 --- /dev/null +++ b/src/gr_sparse_vec/from_dense.c @@ -0,0 +1,28 @@ +#include "gr_sparse_vec.h" + +int +gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx) +{ + slong nnz,i,sz,status; + sz = ctx->sizeof_elem; + nnz = 0; + status = GR_SUCCESS; + for (i = 0; i < len; i++) + { + if (T_FALSE == gr_is_zero(GR_ENTRY(src, i, sz), ctx)) + nnz++; + } + gr_sparse_vec_fit_nnz(vec, nnz, ctx); + nnz = 0; + for (i = 0; i < len; i++) + { + if (T_FALSE == gr_is_zero(GR_ENTRY(src, i, sz), ctx)) + { + vec->cols[nnz] = i; + status |= gr_set(GR_ENTRY(vec->entries, nnz, sz), GR_ENTRY(src, i, sz), ctx); + nnz++; + } + } + vec->nnz = nnz; + return status; +} \ No newline at end of file diff --git a/src/gr_sparse_vec/permute_cols.c b/src/gr_sparse_vec/permute_cols.c new file mode 100644 index 0000000000..8573d6090a --- /dev/null +++ b/src/gr_sparse_vec/permute_cols.c @@ -0,0 +1,49 @@ +#include "gr_sparse_vec.h" + +typedef struct +{ + slong col; + slong i; +} +gr_sparse_vec_slong_sorter_t + +static int gr_sparse_vec_slong_sort(const void* a, const void* b) +{ + slong ak = ((gr_sparse_vec_slong_sorter_t*)(a))->col; + slong bk = ((gr_sparse_vec_slong_sorter_t*)(b))->col; + return (ak < bk ? -1 : (ak > bk ? 1 : 0)); +} + +int +gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) +{ + slong i,j,sz,nnz; + int status = GR_SUCCESS; + gr_sparse_vec_slong_sorter_t *si; + if (vec == src) + { + gr_sparse_vec_t temp; + GR_MUST_SUCCEED(gr_sparse_vec_init(temp, src->length, ctx)); + GR_MUST_SUCCEED(gr_sparse_vec_set(temp, src, ctx)); + status |= gr_sparse_vec_permute_cols(temp, src, p, ctx); + status |= gr_sparse_set(vec, temp, ctx); + status |= gr_sparse_vec_clear(temp, ctx); + return status; + } + sz = ctx->sizeof_elem; + nnz = src->nnz; + si = flint_malloc(nnz * sizeof(gr_sparse_vec_slong_sorter_t)); + for (i = 0; i < nnz; i++) + { + si[i].col = p[vec->cols[i]]; + si[i].i = i; + } + qsort(si, nnz, sizeof(gr_sparse_vec_slong_sorter_t), gr_sparse_vec_slong_sort); + for (i = 0; i < nnz; i++) + { + vec->cols[i] = si[i].col; + status |= gr_set(GR_ENTRY(vec->entries, i, sz), GR_ENTRY(src->entries, si[i].i, sz), ctx); + } + flint_free(si); + return status; +} \ No newline at end of file diff --git a/src/gr_sparse_vec/set_from_entries.c b/src/gr_sparse_vec/set_from_entries.c new file mode 100644 index 0000000000..b3628f9694 --- /dev/null +++ b/src/gr_sparse_vec/set_from_entries.c @@ -0,0 +1,99 @@ +#include "gr_sparse_vec.h" + +typedef struct +{ + slong col; + slong i; +} +gr_sparse_vec_slong_sorter_t + +static int gr_sparse_vec_slong_sort(const void* a, const void* b) +{ + slong ak = ((gr_sparse_vec_slong_sorter_t*)(a))->col; + slong bk = ((gr_sparse_vec_slong_sorter_t*)(b))->col; + return (ak < bk ? -1 : (ak > bk ? 1 : 0)); +} + + + +int +gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entries, slong nnz) +{ + slong i,j,sz,new_nnz; + int status; + gr_sparse_vec_slong_sorter_t *si; + si = flint_malloc(nnz * sizeof(gr_sparse_vec_slong_sorter_t)); + for (i = 0; i < nnz; i++) + { + si[i].col = cols[i]; + si[i].i = i; + } + qsort(si, nnz, sizeof(gr_sparse_vec_slong_sorter_t), gr_sparse_vec_slong_sort); + /* Since the columns are sorted, we can just just the last to make sure all the columns fit */ + if (nnz > 0 && si[nnz-1].col >= vec->length) + { + flint_free(si); + return GR_DOMAIN; + } + new_nnz = (nnz == 0 ? 0 : 1); + for (i = 1; i < nnz; i++) + { + if (si[i-1].col != si[i].col) + new_nnz += 1; + } + gr_sparse_vec_fit_nnz(vec, new_nnz, ctz); + sz = ctx->sizeof_elem; + status = GR_SUCCESS; + j = -1; + for (i = 0; i < nnz && status == GR_SUCCESS; i++) + { + /* If it's a new column, do a set; otherwise do an accumulate */ + if (i == 0 || si[i-1].col != si[i].col) + { + if (j == -1 || (T_FALSE == gr_is_zero(vec->entries, j, sz))) /* Only move to the next target if the current one is nonzero */ + { + j++; + if (j >= new_nnz) + { + flint_free(si); + return GR_UNABLE; /* This is consistency check */ + } + } + vec->cols[j] = si[i].col; + status |= gr_set(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, si[i].i, sz), ctx); + } + else + { + if (vec->cols[j] != cols[si[i].i]) /* Consistency check that we're accumulating into the correct column */ + status |= GR_UNABLE; + status |= gr_add(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, si[i].i, sz), ctx); + } + } + vec->nnz = j; + flint_free(si); + return status; +} + +int +gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, slong * sorted_dedup_cols, gr_srcptr entries, slong nnz) +{ + slong i,j,sz; + int status; + gr_sparse_vec_fit_nnz(vec, nnz, ctz); + sz = ctx->sizeof_elem; + j = 0; + status = GR_SUCCESS; + for (i = 0; i < nnz && status == GR_SUCCESS; i++) + { + if (T_FALSE == gr_is_zero(GR_ENTRY(entries, i, sz), ctx)) + { + vec->cols[j] = sorted_deduped_cols[i]; + status |= gr_set(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, i, sz), ctx); + j++; + } + } + vec->nnz = j; + return status; +} + + diff --git a/src/gr_sparse_vec/shrink_to_nnz.c b/src/gr_sparse_vec/shrink_to_nnz.c new file mode 100644 index 0000000000..0800a28580 --- /dev/null +++ b/src/gr_sparse_vec/shrink_to_nnz.c @@ -0,0 +1,13 @@ + +void +gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx); +{ + slong nnz = vec->nnz; + if (vec->alloc > nnz) + { + vec->cols = flint_realloc(vec->cols, nnz * sizeof(ulong)); + _gr_vec_clear(GR_ENTRY(vec->entries, vec->nnz, sz), vec->alloc - nnz, ctx); + vec->entries = flint_realloc(vec->entries, nnz * sz); + vec->alloc = nnz; + } +} \ No newline at end of file diff --git a/src/gr_sparse_vec/slice.c b/src/gr_sparse_vec/slice.c new file mode 100644 index 0000000000..390a619113 --- /dev/null +++ b/src/gr_sparse_vec/slice.c @@ -0,0 +1,40 @@ +#include "gr_sparse_vec.h" + +int +gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx) +{ + slong sz,i,nnz, i_start, i_end, status; + nnz = src->nnz; + sz = ctx->sizeof_elem; + i_start = 0; + status = GR_SUCCESS; + for (i = 0; i < nnz; i++) + { + /* If we find a valid column, start the interval */ + if (src->cols[i] >= col_start) + { + i_start = i; + break; + } + } + for (; i <= nnz; i++) + { + /* Note we will always do this; the first time we see a column outside the interval, or we run off the end, stop it */ + if (i == nnz || src->cols[i] >= col_end) + { + i_end = i; + break; + } + } + /* We are messing with the internals of res; this should be ok even if it is also src */ + new_nnz = i_end - i_start; + res->length = col_end - col_start; + gr_sparse_vec_fit_nnz(res, new_nnz, ctx); + for (i = i_start; i < i_end; i++) + { + res->cols[i-i_start] = res->cols[i] - col_start; + status |= gr_set(GR_ENTRY(res->entries, i-i_start, sz), GR_ENTRY(src->entries, i, sz), ctx); + } + res->nnz = new_nnz; + return status; +} \ No newline at end of file diff --git a/src/gr_sparse_vec/to_dense.c b/src/gr_sparse_vec/to_dense.c new file mode 100644 index 0000000000..e5868c7382 --- /dev/null +++ b/src/gr_sparse_vec/to_dense.c @@ -0,0 +1,25 @@ +#include "gr_sparse_vec.h" + +int +gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); +{ + slong i,j,sz,status,len; + sz = ctx->sizeof_elem; + len = src->length; + nnz = src->nnz; + j = 0; + for (i = 0; i < len; i++) + { + /* if i is the column of the next nonzero in src, copy it is */ + if (j < nnz && i == src->cols[j]) + { + status |= gr_set(GR_ENTRY(vec, i, sz), GR_ENTRY(src->entries, j, sz), ctx); + j++; + } + else + { + status |= gr_zero(GR_ENTRY(vec, i, sz), ctx); + } + } + return status; +} diff --git a/src/gr_sparse_vec/update.c b/src/gr_sparse_vec/update.c deleted file mode 100644 index 6a31b84850..0000000000 --- a/src/gr_sparse_vec/update.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "gr_sparse_vec.h" - - - -int -gr_sparse_vec_update(gr_sparse_vec_t vec, const gr_sparse_vec_t src, gr_ctx_t ctx) -{ - gr_sparse_vec_update_presorted_entries(vec, src->entries, src->inds, src->nnz, ctx); -} - -int -gr_sparse_vec_update_entries(gr_sparse_vec_t vec, gr_srcptr entries, const ulong* inds, slong nnz, gr_ctx_t ctx) -{ - -} - -int -gr_sparse_vec_update_presorted_entries(gr_sparse_vec_t vec, gr_srcptr entries, const ulong* sorted_inds, slong nnz, gr_ctx_t ctx) -{ - slong vec_nnz = vec->nnz; - slong vec_ind = 0; - slong si_ind = 0; - slong total_new_nnz = 0; - slong sz = ctx->sizeof_elem; - slond dest_ind; - while (vec_ind < vec_nnz && si_ind < nnz) - { - slong vi = vec->inds[vec_ind]; - slong sii = sorted_inds[si_ind]; - if (vi <= sii) - vec_ind += 1; - if (sii <= vi) - si_ind += 1; - total_new_nnz += 1; - } - if (vec_ind < vec_nnz) - total_new_nnz += (vec_nnz - vec_ind); - else if (si_ind < nnz) - total_new_nnz += (nnz - si_ind); - - gr_sparse_vec_fit_nnz(vec, total_new_nnz, ctx); - - vec_ind = vec->nnz-1; - si_ind = nnz-1; - dest_ind = total_new_nnz-1; - while (vec_ind >= 0 && si_ind >= 0) - { - slong vi = vec->inds[vec_ind]; - slong sii = sorted_inds[si_ind]; - if (vi > sii) - { - gr_set(GR_ENTRY(vec->entries, dest_ind, sz), GR_ENTRY(vec->entries, vec_ind, sz)); - vec->inds[dest_ind] = vec->inds[vec_ind]; - vec_ind--; - } - else if (sii > vi) - { - gr_set(GR_ENTRY(vec->entries, dest_ind, sz), GR_ENTRY(entries, si_ind, sz)); - vec->inds[dest_ind] = sorted_inds[si_ind]; - si_ind--; - } - else - { - gr_set(GR_ENTRY(vec->entries, dest_ind, sz), GR_ENTRY(entries, si_ind, sz)); - vec->inds[dest_ind] = sorted_inds[si_ind]; - si_ind--; - vec_ind--; - } - dest_ind--; - } - vec->nnz = total_new_nnz; -} diff --git a/src/gr_sparse_vec/write.c b/src/gr_sparse_vec/write.c new file mode 100644 index 0000000000..825ca79b30 --- /dev/null +++ b/src/gr_sparse_vec/write.c @@ -0,0 +1,29 @@ +#include "gr_sparse_vec.h" + +int +gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong i, sz = ctx->sizeof_elem; + slong nnz = vec->nnz; + gr_stream_write(out, "SparseVector{"); + for (i = 0; i < nnz; i++) + { + gr_stream_write(out, "(%ld: ", vec->cols[i]); + status |= gr_write(out, GR_ENTRY(vec->entries, i, sz), ctx); + gr_stream_write(out, ")", vec->cols[i]); + if (i < len - 1) + gr_stream_write(out, ", "); + } + gr_stream_write(out, "}"); + return status; +} + +int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx) +{ + gr_stream_t out; + gr_stream_init_file(out, stdout); + return gr_sparse_vec_write_nz(out, vec, ctx); +} + + From 701127cd8bc595a6b71ad324b22a27fd80a9074e Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Fri, 9 Feb 2024 11:25:30 -0800 Subject: [PATCH 09/59] added some other creation and tests --- src/gr_sparse_vec.h | 57 +++++++++------------------- src/gr_sparse_vec/fit_nnz.c | 2 +- src/gr_sparse_vec/randtest.c | 59 +++++++++++++++++++++++++++++ src/gr_sparse_vec/shrink_to_nnz.c | 2 +- src/gr_sparse_vec/test/main.c | 17 +++++++++ src/gr_sparse_vec/test/t-creation.c | 32 ++++++++++++++++ src/gr_sparse_vec/write.c | 2 +- 7 files changed, 129 insertions(+), 42 deletions(-) create mode 100644 src/gr_sparse_vec/randtest.c create mode 100644 src/gr_sparse_vec/test/main.c create mode 100644 src/gr_sparse_vec/test/t-creation.c diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 337b8d25fa..45c0b8d7aa 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -37,13 +37,17 @@ gr_sparse_vec_struct; typedef gr_sparse_vec_struct gr_sparse_vec_t[1]; -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_init(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_init(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) +{ memset(vec, 0, sizeof(gr_sparse_vec_t)); vec->length = len; return GR_SUCCESS; } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) { +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) +{ _gr_vec_clear(vec->entries, vec->alloc, ctx); flint_free(vec->cols); flint_free(vec->entries); @@ -51,42 +55,20 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_clear(gr_sparse_vec_t return GR_SUCCESS; } -#define GR_SPARSE_VEC_ENTRY(vec, i, sz) GR_ENTRY((vec)->entries, i, sz) -GR_SPARSE_VEC_INLINE ulong * -gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) -{ - return vec->cols + i; -} +#define GR_SPARSE_VEC_ENTRY(vec, i, sz) GR_ENTRY((vec)->entries, i, sz) -GR_SPARSE_VEC_INLINE const ulong * -gr_sparse_vec_col_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) -{ - return vec->cols + i; -} +GR_SPARSE_VEC_INLINE ulong * gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->cols + i; } +GR_SPARSE_VEC_INLINE const ulong * gr_sparse_vec_col_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->cols + i; } +GR_SPARSE_VEC_INLINE gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); } +GR_SPARSE_VEC_INLINE gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); } -GR_SPARSE_VEC_INLINE gr_ptr -gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) -{ - return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); -} - -GR_SPARSE_VEC_INLINE gr_srcptr -gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) -{ - return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); -} - -GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec, gr_ctx_t ctx) -{ - return vec->nnz; -} void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx); void gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx); -slong gr_sparse_vec_length(const gr_sparse_vec_t vec) { return vec->length; } +GR_SPARSE_VEC_INLINE slong gr_sparse_vec_length(const gr_sparse_vec_t vec) { return vec->length; } void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); -slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) { return vec->nnz; } +GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) { return vec->nnz; } WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); @@ -97,9 +79,14 @@ WARN_UNUSED_RESULT int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, g WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); +truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx); +GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return (vec->nnz == 0 ? T_TRUE ? T_FALSE); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; return GR_SUCCESS; } + int gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx); int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx); @@ -199,10 +186,6 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar(gr_spars GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_mul_si, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_addmul_si, src, b_ind), res, res, src, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_negmul_si, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_submul_si, src, b_ind), res, res, src, ctx); } -truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return (vec->nnz == 0); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; return GR_SUCCESS; } - GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { return (gr_sparse_vec_set(res, src, ctx) | _gr_vec_neg(res->entries, res->entries, res->nnz, ctx)); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sum(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_sum(res, vec->entries, vec->nnz, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_product(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_product(res, vec->entries, vec->nnz, ctx); } @@ -325,10 +308,6 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_ui(gr_ptr res, gr_ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_fmpz(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const fmpz * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_FMPZ_OP(ctx, VEC_DOT_FMPZ)(res, initial, subtract, vec1, vec2, len, ctx); } -/* todo: could allow overloading this as well */ -/* todo: worth warning about unused result? */ -WARN_UNUSED_RESULT int gr_sparse_vec_randtest(gr_ptr res, flint_rand_t state, slong len, gr_ctx_t ctx); - #ifdef __cplusplus diff --git a/src/gr_sparse_vec/fit_nnz.c b/src/gr_sparse_vec/fit_nnz.c index edb48a8ed8..d3ae9641f2 100644 --- a/src/gr_sparse_vec/fit_nnz.c +++ b/src/gr_sparse_vec/fit_nnz.c @@ -16,7 +16,7 @@ gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) nnz = vec->length; vec->cols = flint_realloc(vec->cols, nnz * sizeof(ulong)); vec->entries = flint_realloc(vec->entries, nnz * sz); - _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), nnz - alloc, ctx); + _gr_vec_init(GR_ENTRY(vec->entries, alloc, sz), nnz - alloc, ctx); vec->alloc = len; } } diff --git a/src/gr_sparse_vec/randtest.c b/src/gr_sparse_vec/randtest.c new file mode 100644 index 0000000000..2fd32553bb --- /dev/null +++ b/src/gr_sparse_vec/randtest.c @@ -0,0 +1,59 @@ +#include "gr_sparse_vec.h" + +static int +int_sorter(const void * a, const void * b) +{ + return ((slong*)a) - ((slong*)b); +} + + +int +_gr_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong i, j, sz, nnz; + sz = ctx->sizeof_elem; + nnz = (slong)(density * (double)len); + vec->length = len; + /* We choose nnz columns and deupe. For densities above about 1/sqrt(nnz), */ + /* this is not efficient and won't get the density right, but this isn't important for this function */ + if (nnz > vec->alloc) + { + vec->cols = flint_realloc(vec->cols, nnz*sizeof(slong)); + } + for (i = 0; i < nnz; i++) + { + vec->cols[i] = n_randint(state, len); + } + qsort(vec->cols, nnz, sizeof(slong), int_sorter); + /* Contract the col list to remove duplicates */ + j = 0; + for (i = 0; i < nnz; i++) + { + if (i == 0 || vec->cols[j-1] != vec->cols[i]) + { + vec->cols[j] = vec->cols[i]; + j++; + } + } + nnz = j; /* The actual number of distinct nnz */ + /* Make alloc exactly the new nnz to get cols and entries back in sync */ + vec->cols = flint_realloc(vec->cols, nnz*sizeof(slong)); + if (vec->alloc > nnz) + { + _gr_vec_clear(GR_ENTRY(vec->entries, nnz, sz), vec->alloc - nnz, ctx); + vec->entries = flint_realloc(vec->entries, nnz * sz); + } + else if (vec->alloc < nnz) + { + vec->entries = flint_realloc(vec->entries, nnz * sz); + _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), nnz - vec->alloc, ctx); + } + vec->alloc = nnz; + vec->nnz = nnz; + for (i = 0; i < nnz; i++) + { + status |= gr_randtest_not_zero(GR_ENTRY(vec->entries, i, sz), state, ctx); + } + return status; +} diff --git a/src/gr_sparse_vec/shrink_to_nnz.c b/src/gr_sparse_vec/shrink_to_nnz.c index 0800a28580..fe03a9a4b5 100644 --- a/src/gr_sparse_vec/shrink_to_nnz.c +++ b/src/gr_sparse_vec/shrink_to_nnz.c @@ -6,7 +6,7 @@ gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx); if (vec->alloc > nnz) { vec->cols = flint_realloc(vec->cols, nnz * sizeof(ulong)); - _gr_vec_clear(GR_ENTRY(vec->entries, vec->nnz, sz), vec->alloc - nnz, ctx); + _gr_vec_clear(GR_ENTRY(vec->entries, nnz, sz), vec->alloc - nnz, ctx); vec->entries = flint_realloc(vec->entries, nnz * sz); vec->alloc = nnz; } diff --git a/src/gr_sparse_vec/test/main.c b/src/gr_sparse_vec/test/main.c new file mode 100644 index 0000000000..822f38f75d --- /dev/null +++ b/src/gr_sparse_vec/test/main.c @@ -0,0 +1,17 @@ +#include +#include + +/* Include functions *********************************************************/ + +#include "t-creation.c" + +/* Array of test functions ***************************************************/ + +test_struct tests[] = +{ + TEST_FUNCTION(gr_sparse_vec_creation), +}; + +/* main function *************************************************************/ + +TEST_MAIN(tests) \ No newline at end of file diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c new file mode 100644 index 0000000000..dc6d4d178c --- /dev/null +++ b/src/gr_sparse_vec/test/t-creation.c @@ -0,0 +1,32 @@ +#include "test_helpers.h" +#include "gr_sparse_vec.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int +test_init(gr_ctx_t ctx) +{ + gr_sparse_vec_t vec; + int status = GR_SUCCESS; + status |= gr_sparse_vec_init(vec, 5, ctx); + status |= gr_sparse_vec_clear(vec); + return status; +} + +int +test_init_from_entries(gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + return status; +} + + +TEST_FUNCTION_START(gr_sparse_vec_creation, state) +{ + gr_ctx_t ctx; + gr_ctx_init_random(ctx, state); + CHECK_TEST(test_init(ctx), "Init"); + CHECK_TEST(test_init_from_entries(ctx), "Init from entries"); + gr_ctx_clear(ctx); + TEST_FUNCTION_END(state); +} \ No newline at end of file diff --git a/src/gr_sparse_vec/write.c b/src/gr_sparse_vec/write.c index 825ca79b30..d3ce44e034 100644 --- a/src/gr_sparse_vec/write.c +++ b/src/gr_sparse_vec/write.c @@ -6,7 +6,7 @@ gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) int status = GR_SUCCESS; slong i, sz = ctx->sizeof_elem; slong nnz = vec->nnz; - gr_stream_write(out, "SparseVector{"); + gr_stream_write(out, "gr_sparse_vec_t{"); for (i = 0; i < nnz; i++) { gr_stream_write(out, "(%ld: ", vec->cols[i]); From efe5d72a38cdfddd4b9c93ebec0000d390ed38c1 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Fri, 9 Feb 2024 13:00:05 -0800 Subject: [PATCH 10/59] starting to try to compile --- Makefile.in | 2 +- src/gr_sparse_vec.h | 61 +++++++++++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/Makefile.in b/Makefile.in index 9326406050..fa8b2ab4e4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -181,7 +181,7 @@ HEADER_DIRS := \ dirichlet bernoulli hypgeom \ \ gr gr_generic gr_vec gr_mat \ - gr_poly gr_mpoly gr_special \ + gr_poly gr_mpoly gr_sparse_vec gr_special \ \ calcium \ fmpz_mpoly_q \ diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 45c0b8d7aa..728b959bb4 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -192,21 +192,52 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_product(gr_ptr res, +/***** TODO: These plus dense, dense, sparse functions +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_MUL)(res, src1, src2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIV)(res, src1, src2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIVEXACT)(res, src1, src2, len, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_POW)(res, src1, src2, len, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_OP(ctx, VEC_DOT)(res, initial, subtract, vec1, vec2, len, ctx); } + +*/ -#define GR_SPARSE_VEC_DENSE_VEC_OP(g, res, src, c, ctx) \ + +#define GR_SPARSE_VEC_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) \ { \ - int status = GR_SUCCESS; \ - status = gr_vec_set(res, src, ctx); \ - if(status == GR_SUCCESS) { \ - status = g(res->entries, src->entries, len, c, ctx); \ + if(res->length != src->length) \ + { \ + return GR_DOMAIN; \ + } \ + if(res != src) { \ + { \ + gr_sparse_vec_fit_nnz(res, src->nnz, ctx); \ + res->nnz = src->nnz; \ + memcopy(res->cols, src->cols, nnz*sizeof(slong)); \ + } \ - return status; \ + return dense_vec_op(res->entries, src->entries, src->nnz, c, ctx); \ } -int gr_sparse_vec_mul_scalar(gr_vec_t res, gr_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, blah, src, c, ctx) } -int gr_sparse_vec_mul_scalar_si(gr_vec_t res, gr_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } +int gr_sparse_vec_mul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } +int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } +int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } +int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } +int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } +int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } +int gr_sparse_vec_div_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } +int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } +int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } +int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } +int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } +int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } +int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } +int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } +int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } +int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } + /******************************************************************/ @@ -217,17 +248,7 @@ int gr_sparse_vec_mul_scalar_si(gr_vec_t res, gr_vec_t src, slong c, gr_ctx_t ct /******************************************************************/ - /* -typedef int ((*gr_method_vec_normalise_op)(slong *, gr_srcptr, slong, gr_ctx_ptr)); -typedef slong ((*gr_method_vec_normalise_weak_op)(gr_srcptr, slong, gr_ctx_ptr)); -#define GR_SPARSE_VEC_NORMALISE_OP(ctx, NAME) (((gr_method_vec_normalise_op *) ctx->methods)[GR_METHOD_ ## NAME]) -#define GR_SPARSE_VEC_NORMALISE_WEAK_OP(ctx, NAME) (((gr_method_vec_normalise_weak_op *) ctx->methods)[GR_METHOD_ ## NAME]) - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_normalise(slong * res, const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_NORMALISE_OP(ctx, VEC_NORMALISE)(res, vec, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT slong gr_sparse_vec_normalise_weak(const gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_NORMALISE_WEAK_OP(ctx, VEC_NORMALISE_WEAK)(vec, len, ctx); } -*/ - GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_MUL)(res, src1, src2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIV)(res, src1, src2, len, ctx); } @@ -286,8 +307,6 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_pow_vec(gr_sparse_ve GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_MUL_SCALAR_2EXP_SI)(vec1, vec2, len, c, ctx); } - - typedef int ((*gr_method_vec_reduce_op)(gr_sparse_vec_t, gr_srcptr, slong, gr_ctx_ptr)); typedef int ((*gr_method_vec_dot_op)(gr_sparse_vec_t, gr_srcptr, int, gr_srcptr, gr_srcptr, slong, gr_ctx_ptr)); @@ -306,7 +325,7 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_rev(gr_ptr res, gr GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_si(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const slong * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_SI_OP(ctx, VEC_DOT_SI)(res, initial, subtract, vec1, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_ui(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const ulong * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_UI_OP(ctx, VEC_DOT_UI)(res, initial, subtract, vec1, vec2, len, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_fmpz(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const fmpz * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_FMPZ_OP(ctx, VEC_DOT_FMPZ)(res, initial, subtract, vec1, vec2, len, ctx); } - +*/ From 511ab5c8d3c30bcfb4e6547338a1351ef9137a81 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Fri, 9 Feb 2024 14:20:13 -0800 Subject: [PATCH 11/59] compiles --- src/gr_sparse_vec.h | 96 ++++++++++++++-------------- src/gr_sparse_vec/equal.c | 6 +- src/gr_sparse_vec/fit_nnz.c | 23 +++---- src/gr_sparse_vec/permute_cols.c | 7 +- src/gr_sparse_vec/randtest.c | 3 +- src/gr_sparse_vec/set.c | 4 +- src/gr_sparse_vec/set_from_entries.c | 15 +++-- src/gr_sparse_vec/shrink_to_nnz.c | 4 +- src/gr_sparse_vec/slice.c | 3 +- src/gr_sparse_vec/to_dense.c | 5 +- src/gr_sparse_vec/write.c | 9 ++- 11 files changed, 93 insertions(+), 82 deletions(-) diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 728b959bb4..af7e8e718d 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -18,6 +18,7 @@ #define GR_SPARSE_VEC_INLINE static __inline__ #endif +#include #include "gr.h" #include "gr_vec.h" @@ -72,15 +73,15 @@ GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) { return WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entries, slong nnz); -WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, slong * sorted_cols, gr_srcptr entries, slong nnz); +WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, slong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return (vec->nnz == 0 ? T_TRUE ? T_FALSE); } +GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return (vec->nnz == 0 ? T_TRUE : T_FALSE); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; return GR_SUCCESS; } int gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx); @@ -94,12 +95,12 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo -#define GR_SPV_SWAP_INDS(VEC, I, J, CTX) \ -{ \ - slong _temp = (VEC)->cols[I]; \ - (VEC)->cols[I] = (VEC)->cols[J]; \ - (VEC)->cols[J] = _temp; \ - gr_swap(GR_ENTRY((VEC)->entries, (I), ctx), GR_ENTRY((VEC)->entries, (J), ctx), ctx); \ +#define GR_SPV_SWAP_INDS(VEC, I, J, SZ, CTX) \ +{ \ + slong _temp = (VEC)->cols[I]; \ + (VEC)->cols[I] = (VEC)->cols[J]; \ + (VEC)->cols[J] = _temp; \ + gr_swap(GR_ENTRY((VEC)->entries, (I), (SZ)), GR_ENTRY((VEC)->entries, (J), (SZ)), (CTX)); \ } @@ -142,7 +143,7 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo a_ind--; \ b_ind--; \ } \ - if (T_FALSE == gr_is_zero(GR_ENTRY((DEST_VEC)->entries, dest_ind, sz))) \ + if (T_TRUE != gr_is_zero(GR_ENTRY((DEST_VEC)->entries, dest_ind, sz), (CTX))) \ dest_ind--; \ } \ /* Move the result to the beginning of the dest vec */ \ @@ -152,7 +153,7 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo new_nnz = (new_nnz-1) - dest_ind; \ dest_ind++; \ for (i = 0; i < new_nnz; i++) \ - GR_SPV_SWAP_INDS(DEST_VEC, i, dest_ind + i, CTX); \ + GR_SPV_SWAP_INDS(DEST_VEC, i, dest_ind + i, sz, CTX); \ } \ (DEST_VEC)->nnz = new_nnz; \ return status; @@ -161,25 +162,25 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_neg_other(gr_ptr res, gr_srcptr s GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) { return (gr_mul(res, x, y, ctx) | gr_neg(res, res, ctx)); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx) { return (gr_mul_si(res, x, y, ctx) | gr_neg(res, res, ctx)); } -#define GR_SPV_RFL_UOP(F, Y, Y_ind) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) -#define GR_SPV_RFL_BOP(F, Y, Y_ind, Z, Z_ind) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) +#define GR_SPV_RFL_UOP(F, Y, Y_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) +#define GR_SPV_RFL_BOP(F, Y, Y_ind, Z, Z_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP(gr_set, src, b_ind), GR_SPV_RFL_UOP(gr_set, src, b_ind), res, res, src, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP(gr_set, src2, b_ind), GR_SPV_RFL_BOP(gr_add, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP(gr_neg, src2, b_ind), GR_SPV_RFL_BOP(gr_sub, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } -#define GR_SPV_RFL_UOP_OTHER(F, Y, Y_ind, CTX2) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), CTX2, ctx) -#define GR_SPV_RFL_BOP_OTHER(F, Y, Y_ind, Z, Z_ind, CTX2) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, CTX2->sizeof_elem), CTX2, ctx) +#define GR_SPV_RFL_UOP_OTHER(F, Y, Y_ind, CTX2) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), CTX2, ctx) +#define GR_SPV_RFL_BOP_OTHER(F, Y, Y_ind, Z, Z_ind, CTX2) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, CTX2->sizeof_elem), CTX2, ctx) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_set, src2, b_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_add, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_sub, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_set_other, src2, b_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_add_other, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_sub_other, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } -#define GR_SPV_RFL_OTHER_BOP(F, Y, Y_ind, CTX2, Z, Z_ind) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), GR_ENTRY(Z->entries, Z_ind, sz), ctx) +#define GR_SPV_RFL_OTHER_BOP(F, Y, Y_ind, CTX2, Z, Z_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), (CTX2), GR_ENTRY(Z->entries, Z_ind, sz), ctx) GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), GR_SPV_RFL_UOP(gr_set, src2, b_ind), GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), GR_SPV_RFL_UOP(gr_neg, src2, b_ind), GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } -#define GR_SPV_RFL_UOP_SCALAR(F, Y, Y_ind) F(GR_ENTRY(res->entries, dest_ptr, sz), GR_ENTRY(Y->entries, Y_ind, sz), c, ctx) +#define GR_SPV_RFL_UOP_SCALAR(F, Y, Y_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), c, ctx) GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_mul, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_addmul, src, b_ind), res, res, src, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_negmul, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_submul, src, b_ind), res, res, src, ctx); } @@ -205,38 +206,35 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_src -#define GR_SPARSE_VEC_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) \ -{ \ - if(res->length != src->length) \ - { \ - return GR_DOMAIN; \ - } \ - if(res != src) { \ - { \ - gr_sparse_vec_fit_nnz(res, src->nnz, ctx); \ - res->nnz = src->nnz; \ - memcopy(res->cols, src->cols, nnz*sizeof(slong)); \ - - } \ +#define GR_SPARSE_VEC_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) \ + if(res->length != src->length) \ + { \ + return GR_DOMAIN; \ + } \ + if(res != src) \ + { \ + gr_sparse_vec_fit_nnz(res, src->nnz, ctx); \ + res->nnz = src->nnz; \ + memcpy(res->cols, src->cols, src->nnz*sizeof(slong)); \ + } \ return dense_vec_op(res->entries, src->entries, src->nnz, c, ctx); \ -} -int gr_sparse_vec_mul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } -int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } -int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } -int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } -int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } -int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } -int gr_sparse_vec_div_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } -int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } -int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } -int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } -int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } -int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } -int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } -int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } -int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } -int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } diff --git a/src/gr_sparse_vec/equal.c b/src/gr_sparse_vec/equal.c index 47b7004c14..e02d131034 100644 --- a/src/gr_sparse_vec/equal.c +++ b/src/gr_sparse_vec/equal.c @@ -1,13 +1,15 @@ +#include "gr_sparse_vec.h" + truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx) { slong nnz, i, sz; sz = ctx->sizeof_elem; - if (vec1->length != vec2->length || vec->nnz != vec2->nnz) + if (vec1->length != vec2->length || vec1->nnz != vec2->nnz) return T_FALSE; nnz = vec1->nnz; for (i = 0; i < nnz; i++) - if (T_TRUE != gr_equal(GR_ENTRY(vec1->entries, i, sz), GR_ENTRY(vec2->entries, i2, sz), ctx)) + if (T_TRUE != gr_equal(GR_ENTRY(vec1->entries, i, sz), GR_ENTRY(vec2->entries, i, sz), ctx)) return T_FALSE; return T_TRUE; } \ No newline at end of file diff --git a/src/gr_sparse_vec/fit_nnz.c b/src/gr_sparse_vec/fit_nnz.c index d3ae9641f2..5c29167444 100644 --- a/src/gr_sparse_vec/fit_nnz.c +++ b/src/gr_sparse_vec/fit_nnz.c @@ -4,19 +4,20 @@ void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) { slong alloc = vec->alloc; + slong new_alloc = nnz; /* It doesn't make sense to allocate more than the ambient dimension */ - if (nnz > vec->length) - nnz = vec->length; - if (nnz > alloc) + if (new_alloc > vec->length) + new_alloc = vec->length; + if (new_alloc > alloc) { slong sz = ctx->sizeof_elem; - if (nnz < 2 * alloc) - nnz = 2 * alloc; - if (nnz > vec->length) - nnz = vec->length; - vec->cols = flint_realloc(vec->cols, nnz * sizeof(ulong)); - vec->entries = flint_realloc(vec->entries, nnz * sz); - _gr_vec_init(GR_ENTRY(vec->entries, alloc, sz), nnz - alloc, ctx); - vec->alloc = len; + if (new_alloc < 2 * alloc) + new_alloc = 2 * alloc; + if (new_alloc > vec->length) + new_alloc = vec->length; + vec->cols = flint_realloc(vec->cols, new_alloc * sizeof(ulong)); + vec->entries = flint_realloc(vec->entries, new_alloc * sz); + _gr_vec_init(GR_ENTRY(vec->entries, alloc, sz), new_alloc - alloc, ctx); + vec->alloc = new_alloc; } } diff --git a/src/gr_sparse_vec/permute_cols.c b/src/gr_sparse_vec/permute_cols.c index 8573d6090a..40477e27b8 100644 --- a/src/gr_sparse_vec/permute_cols.c +++ b/src/gr_sparse_vec/permute_cols.c @@ -1,3 +1,4 @@ +#include #include "gr_sparse_vec.h" typedef struct @@ -5,7 +6,7 @@ typedef struct slong col; slong i; } -gr_sparse_vec_slong_sorter_t +gr_sparse_vec_slong_sorter_t; static int gr_sparse_vec_slong_sort(const void* a, const void* b) { @@ -17,7 +18,7 @@ static int gr_sparse_vec_slong_sort(const void* a, const void* b) int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) { - slong i,j,sz,nnz; + slong i,sz,nnz; int status = GR_SUCCESS; gr_sparse_vec_slong_sorter_t *si; if (vec == src) @@ -26,7 +27,7 @@ gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong GR_MUST_SUCCEED(gr_sparse_vec_init(temp, src->length, ctx)); GR_MUST_SUCCEED(gr_sparse_vec_set(temp, src, ctx)); status |= gr_sparse_vec_permute_cols(temp, src, p, ctx); - status |= gr_sparse_set(vec, temp, ctx); + status |= gr_sparse_vec_set(vec, temp, ctx); status |= gr_sparse_vec_clear(temp, ctx); return status; } diff --git a/src/gr_sparse_vec/randtest.c b/src/gr_sparse_vec/randtest.c index 2fd32553bb..28a40a0b97 100644 --- a/src/gr_sparse_vec/randtest.c +++ b/src/gr_sparse_vec/randtest.c @@ -1,3 +1,4 @@ +#include #include "gr_sparse_vec.h" static int @@ -8,7 +9,7 @@ int_sorter(const void * a, const void * b) int -_gr_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx) +gr_sparse_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx) { int status = GR_SUCCESS; slong i, j, sz, nnz; diff --git a/src/gr_sparse_vec/set.c b/src/gr_sparse_vec/set.c index eea6f464f5..af33d8db9a 100644 --- a/src/gr_sparse_vec/set.c +++ b/src/gr_sparse_vec/set.c @@ -1,13 +1,13 @@ #include "gr_sparse_vec.h" int -gr_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { int status = GR_SUCCESS; if (res != src) { slong nnz = src->nnz; - gr_sparse_vec_fit_nnz(res, nnz, ctz); + gr_sparse_vec_fit_nnz(res, nnz, ctx); memcpy(res->cols, src->cols, nnz*sizeof(slong)); status = _gr_vec_set(res->entries, src->entries, nnz, ctx); res->nnz = nnz; diff --git a/src/gr_sparse_vec/set_from_entries.c b/src/gr_sparse_vec/set_from_entries.c index b3628f9694..058222fc05 100644 --- a/src/gr_sparse_vec/set_from_entries.c +++ b/src/gr_sparse_vec/set_from_entries.c @@ -1,3 +1,4 @@ +#include #include "gr_sparse_vec.h" typedef struct @@ -5,7 +6,7 @@ typedef struct slong col; slong i; } -gr_sparse_vec_slong_sorter_t +gr_sparse_vec_slong_sorter_t; static int gr_sparse_vec_slong_sort(const void* a, const void* b) { @@ -17,7 +18,7 @@ static int gr_sparse_vec_slong_sort(const void* a, const void* b) int -gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entries, slong nnz) +gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) { slong i,j,sz,new_nnz; int status; @@ -41,7 +42,7 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entr if (si[i-1].col != si[i].col) new_nnz += 1; } - gr_sparse_vec_fit_nnz(vec, new_nnz, ctz); + gr_sparse_vec_fit_nnz(vec, new_nnz, ctx); sz = ctx->sizeof_elem; status = GR_SUCCESS; j = -1; @@ -50,7 +51,7 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entr /* If it's a new column, do a set; otherwise do an accumulate */ if (i == 0 || si[i-1].col != si[i].col) { - if (j == -1 || (T_FALSE == gr_is_zero(vec->entries, j, sz))) /* Only move to the next target if the current one is nonzero */ + if (j == -1 || (T_TRUE != gr_is_zero(GR_ENTRY(vec->entries, j, sz), ctx))) /* Only move to the next target if the current one is nonzero */ { j++; if (j >= new_nnz) @@ -66,7 +67,7 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entr { if (vec->cols[j] != cols[si[i].i]) /* Consistency check that we're accumulating into the correct column */ status |= GR_UNABLE; - status |= gr_add(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, si[i].i, sz), ctx); + status |= gr_add(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, si[i].i, sz), ctx); } } vec->nnz = j; @@ -75,11 +76,11 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entr } int -gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, slong * sorted_dedup_cols, gr_srcptr entries, slong nnz) +gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, slong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) { slong i,j,sz; int status; - gr_sparse_vec_fit_nnz(vec, nnz, ctz); + gr_sparse_vec_fit_nnz(vec, nnz, ctx); sz = ctx->sizeof_elem; j = 0; status = GR_SUCCESS; diff --git a/src/gr_sparse_vec/shrink_to_nnz.c b/src/gr_sparse_vec/shrink_to_nnz.c index fe03a9a4b5..6f8b875aaf 100644 --- a/src/gr_sparse_vec/shrink_to_nnz.c +++ b/src/gr_sparse_vec/shrink_to_nnz.c @@ -1,8 +1,10 @@ +#include "gr_sparse_vec.h" void -gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx); +gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx) { slong nnz = vec->nnz; + slong sz = ctx->sizeof_elem; if (vec->alloc > nnz) { vec->cols = flint_realloc(vec->cols, nnz * sizeof(ulong)); diff --git a/src/gr_sparse_vec/slice.c b/src/gr_sparse_vec/slice.c index 390a619113..c07e19c57c 100644 --- a/src/gr_sparse_vec/slice.c +++ b/src/gr_sparse_vec/slice.c @@ -3,10 +3,11 @@ int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx) { - slong sz,i,nnz, i_start, i_end, status; + slong sz,i,nnz, new_nnz, i_start, i_end, status; nnz = src->nnz; sz = ctx->sizeof_elem; i_start = 0; + i_end = nnz; status = GR_SUCCESS; for (i = 0; i < nnz; i++) { diff --git a/src/gr_sparse_vec/to_dense.c b/src/gr_sparse_vec/to_dense.c index e5868c7382..38e29c7d39 100644 --- a/src/gr_sparse_vec/to_dense.c +++ b/src/gr_sparse_vec/to_dense.c @@ -1,9 +1,10 @@ #include "gr_sparse_vec.h" int -gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); +gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) { - slong i,j,sz,status,len; + slong i,j,sz,nnz,status,len; + status = GR_SUCCESS; sz = ctx->sizeof_elem; len = src->length; nnz = src->nnz; diff --git a/src/gr_sparse_vec/write.c b/src/gr_sparse_vec/write.c index d3ce44e034..66b9cc0162 100644 --- a/src/gr_sparse_vec/write.c +++ b/src/gr_sparse_vec/write.c @@ -1,3 +1,4 @@ +#include #include "gr_sparse_vec.h" int @@ -9,10 +10,12 @@ gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) gr_stream_write(out, "gr_sparse_vec_t{"); for (i = 0; i < nnz; i++) { - gr_stream_write(out, "(%ld: ", vec->cols[i]); + gr_stream_write(out, "("); + gr_stream_write_si(out, vec->cols[i]); + gr_stream_write(out, ": "); status |= gr_write(out, GR_ENTRY(vec->entries, i, sz), ctx); - gr_stream_write(out, ")", vec->cols[i]); - if (i < len - 1) + gr_stream_write(out, ")"); + if (i < nnz - 1) gr_stream_write(out, ", "); } gr_stream_write(out, "}"); From 9cc6a0305ed701496a4c1e379ca523b5640b09c2 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Fri, 9 Feb 2024 15:03:37 -0800 Subject: [PATCH 12/59] added into dense functions --- src/gr_sparse_vec.h | 125 +++++++++++--------------------------------- 1 file changed, 31 insertions(+), 94 deletions(-) diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index af7e8e718d..d344fd9866 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -105,6 +105,8 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo /* This is used for operations like add which have to riffle through the entries of two vectors */ +/* It's an annoying macro that combines with the macros below. This is so we can handle */ +/* Different arguments in different orders, etc */ #define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ int status; \ slong sz, new_nnz, a_ind, b_ind, dest_ind, a_nnz, b_nnz, a_col, b_col, i; \ @@ -158,6 +160,7 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo (DEST_VEC)->nnz = new_nnz; \ return status; +/* We need some convenience functions */ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_neg_other(gr_ptr res, gr_srcptr src, gr_ctx_t src_ctx, gr_ctx_t ctx) { return (gr_set_other(res, src, src_ctx, ctx) | gr_neg(res, res, ctx)); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) { return (gr_mul(res, x, y, ctx) | gr_neg(res, res, ctx)); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx) { return (gr_mul_si(res, x, y, ctx) | gr_neg(res, res, ctx)); } @@ -169,6 +172,10 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP(gr_set, src2, b_ind), GR_SPV_RFL_BOP(gr_add, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP(gr_neg, src2, b_ind), GR_SPV_RFL_BOP(gr_sub, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } +#define GR_SPV_RFL_ZERO gr_zero(GR_ENTRY(res->entries, dest_ind, sz), ctx) + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, GR_SPV_RFL_BOP(gr_mul, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } + #define GR_SPV_RFL_UOP_OTHER(F, Y, Y_ind, CTX2) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), CTX2, ctx) #define GR_SPV_RFL_BOP_OTHER(F, Y, Y_ind, Z, Z_ind, CTX2) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, CTX2->sizeof_elem), CTX2, ctx) @@ -192,12 +199,31 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sum(gr_ptr res, const GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_product(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_product(res, vec->entries, vec->nnz, ctx); } +/* These are versions that incorporate a sparse into a dense */ +#define GR_SPV_INTO_DENSE_TEMPLATE(FUNC, SVEC, CTX) \ + slong i; \ + slong sz = (CTX)->sizeof_elem; \ + int status = GR_SUCCESS; \ + slong nnz = (SVEC)->nnz; \ + for (i = 0; i < nnz; i++) \ + { \ + status |= (FUNC); \ + } \ + return status; + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update_to_dense(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_set(GR_ENTRY(dres, src->cols[i], sz), GR_ENTRY(src->entries, i, sz), ctx), src, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_add(GR_ENTRY(dres, svec2->cols[i], sz), GR_ENTRY(dvec1, svec2->cols[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_sub(GR_ENTRY(dres, svec2->cols[i], sz), GR_ENTRY(dvec1, svec2->cols[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_mul_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_mul(GR_ENTRY(dres, svec2->cols[i], sz), GR_ENTRY(dvec1, svec2->cols[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_div_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_div(GR_ENTRY(dres, svec2->cols[i], sz), GR_ENTRY(dvec1, svec2->cols[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul_si(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul_si(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul_fmpz(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul_fmpz(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -/***** TODO: These plus dense, dense, sparse functions -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_MUL)(res, src1, src2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIV)(res, src1, src2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIVEXACT)(res, src1, src2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_POW)(res, src1, src2, len, ctx); } +/***** TODO: GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_OP(ctx, VEC_DOT)(res, initial, subtract, vec1, vec2, len, ctx); } @@ -238,95 +264,6 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpq(g -/******************************************************************/ -/******************************************************************/ -/******************************************************************/ -/******************************************************************/ -/******************************************************************/ -/******************************************************************/ - - -/* - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_MUL)(res, src1, src2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIV)(res, src1, src2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_DIVEXACT)(res, src1, src2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_VEC_OP(ctx, VEC_POW)(res, src1, src2, len, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_MUL_SCALAR)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_DIV_SCALAR)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_DIVEXACT_SCALAR)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP(ctx, VEC_POW_SCALAR)(vec1, vec2, len, c, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_MUL_SCALAR_SI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_DIV_SCALAR_SI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_DIVEXACT_SCALAR_SI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_POW_SCALAR_SI)(vec1, vec2, len, c, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_MUL_SCALAR_UI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_DIV_SCALAR_UI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_DIVEXACT_SCALAR_UI)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_ui(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, ulong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_UI(ctx, VEC_POW_SCALAR_UI)(vec1, vec2, len, c, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_MUL_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_DIV_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_DIVEXACT_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_fmpz(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpz_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPZ(ctx, VEC_POW_SCALAR_FMPZ)(vec1, vec2, len, c, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_MUL_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_DIV_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_DIVEXACT_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_fmpq(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, const fmpq_t c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_FMPQ(ctx, VEC_POW_SCALAR_FMPQ)(vec1, vec2, len, c, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_mul_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_MUL_VEC)(vec1, c, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_div_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_DIV_VEC)(vec1, c, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_divexact_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_DIVEXACT_VEC)(vec1, c, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_pow_vec(gr_sparse_vec_t vec1, gr_srcptr c, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_VEC_OP(ctx, SCALAR_POW_VEC)(vec1, c, vec2, len, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_MUL_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_DIV_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_DIVEXACT_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, const gr_sparse_vec_t vec3, gr_ctx_t ctx3, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_OTHER(ctx, VEC_POW_OTHER)(vec1, vec2, vec3, ctx3, len, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_mul_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_MUL_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_div_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_DIV_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_divexact_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_DIVEXACT_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_pow_vec(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx2, const gr_sparse_vec_t vec3, slong len, gr_ctx_t ctx) { return GR_OTHER_OP_VEC(ctx, OTHER_POW_VEC)(vec1, vec2, ctx2, vec3, len, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_MUL_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_DIV_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_DIVEXACT_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_pow_scalar_other(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_srcptr c, gr_ctx_t cctx, gr_ctx_t ctx) { return GR_SPARSE_VEC_OP_SCALAR_OTHER(ctx, VEC_POW_SCALAR_OTHER)(vec1, vec2, len, c, cctx, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_mul_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_MUL_VEC)(vec1, c, cctx, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_div_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_DIV_VEC)(vec1, c, cctx, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_divexact_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_DIVEXACT_VEC)(vec1, c, cctx, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_scalar_other_pow_vec(gr_sparse_vec_t vec1, gr_srcptr c, gr_ctx_t cctx, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SCALAR_OTHER_OP_VEC(ctx, SCALAR_OTHER_POW_VEC)(vec1, c, cctx, vec2, len, ctx); } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, slong c, gr_ctx_t ctx) { return GR_SPARSE_VEC_SCALAR_OP_SI(ctx, VEC_MUL_SCALAR_2EXP_SI)(vec1, vec2, len, c, ctx); } - -typedef int ((*gr_method_vec_reduce_op)(gr_sparse_vec_t, gr_srcptr, slong, gr_ctx_ptr)); - -typedef int ((*gr_method_vec_dot_op)(gr_sparse_vec_t, gr_srcptr, int, gr_srcptr, gr_srcptr, slong, gr_ctx_ptr)); -typedef int ((*gr_method_vec_dot_si_op)(gr_sparse_vec_t, gr_srcptr, int, gr_srcptr, const slong *, slong, gr_ctx_ptr)); -typedef int ((*gr_method_vec_dot_ui_op)(gr_sparse_vec_t, gr_srcptr, int, gr_srcptr, const ulong *, slong, gr_ctx_ptr)); -typedef int ((*gr_method_vec_dot_fmpz_op)(gr_sparse_vec_t, gr_srcptr, int, gr_srcptr, const fmpz *, slong, gr_ctx_ptr)); - -#define GR_SPARSE_VEC_REDUCE_OP(ctx, NAME) (((gr_method_vec_reduce_op *) ctx->methods)[GR_METHOD_ ## NAME]) -#define GR_SPARSE_VEC_DOT_OP(ctx, NAME) (((gr_method_vec_dot_op *) ctx->methods)[GR_METHOD_ ## NAME]) -#define GR_SPARSE_VEC_DOT_SI_OP(ctx, NAME) (((gr_method_vec_dot_si_op *) ctx->methods)[GR_METHOD_ ## NAME]) -#define GR_SPARSE_VEC_DOT_UI_OP(ctx, NAME) (((gr_method_vec_dot_ui_op *) ctx->methods)[GR_METHOD_ ## NAME]) -#define GR_SPARSE_VEC_DOT_FMPZ_OP(ctx, NAME) (((gr_method_vec_dot_fmpz_op *) ctx->methods)[GR_METHOD_ ## NAME]) - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_OP(ctx, VEC_DOT)(res, initial, subtract, vec1, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_rev(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_OP(ctx, VEC_DOT_REV)(res, initial, subtract, vec1, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_si(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const slong * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_SI_OP(ctx, VEC_DOT_SI)(res, initial, subtract, vec1, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_ui(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const ulong * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_UI_OP(ctx, VEC_DOT_UI)(res, initial, subtract, vec1, vec2, len, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_fmpz(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const fmpz * vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_FMPZ_OP(ctx, VEC_DOT_FMPZ)(res, initial, subtract, vec1, vec2, len, ctx); } -*/ - - - #ifdef __cplusplus } #endif From 3d6ea814ea9f30cd8299b247ebef2605925c331b Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Fri, 9 Feb 2024 16:59:35 -0800 Subject: [PATCH 13/59] working on documentation --- doc/source/gr_sparse_vec.rst | 217 +++++++++++++++++++++++++++ doc/source/index.rst | 1 + src/gr_sparse_vec.h | 13 +- src/gr_sparse_vec/set_from_entries.c | 6 +- 4 files changed, 227 insertions(+), 10 deletions(-) create mode 100644 doc/source/gr_sparse_vec.rst diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst new file mode 100644 index 0000000000..5425bd0e34 --- /dev/null +++ b/doc/source/gr_sparse_vec.rst @@ -0,0 +1,217 @@ +.. _gr-sparse-vec: + +**gr_sparse_vec.h** -- Sparse vectors over generic rings +=============================================================================== + +A :type:`gr_sparse_vec_t` is a represention of a vector over a generic +ring which is optimized for the situation where there are many entries which +are zero (the vector is sparse). Internally, the vector records only +the positions of the nonzeros and their values. Although technically the +type and all its functions will operate correctly with any density, +a :type:`gr_vec_t` may be more efficient in the number of nonzeros is not small. + +Types and basic access +-------------------------------------------------------------------------------- + +.. type:: gr_sparse_vec_struct + +.. type:: gr_sparse_vec_t + + This struct contains: + + * A pointer to an `slong` array of column indices (``cols``) of nonzeros (we think of the vector as a row) + * A :type:`gr_ptr` array of values of nonzeros (``entries``). + * `slong` values to record the number of nonzeros (``nnz``), the nominal length of the vector (the dimension of the vector space) (``length``), and the space allocated in the ``cols`` and ``entries`` arrays. + + We always require: + + * The ``cols`` are sorted into strictly increasing order + * The ``entries`` are nonzero (meaning, ``gr_is_zero(GR_ENTRY(vec->entries, i, ctx->sizeof_elem), ctx)`` returns ``T_FALSE`` for ``0 <= i < vec->nnz``). + * We have ``nnz <= alloc <= length``. + + A ``gr_sparse_vec_t`` is defined as an array of length one of type + ``gr_sparse_vec_struct``, permitting a ``gr_sparse_vec_t`` to + be passed by reference. + +.. function:: int gr_sparse_vec_init(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) + + Initializes *vec* to a vector of length *len* with no nonzeros. + +.. function:: int gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) + + Clears the vector *vec* + +.. macro:: GR_SPARSE_VEC_COL(vec, i) + + Access the column index of the *i*-th nonzero. + There is no bounds checking. + +.. macro:: GR_SPARSE_VEC_ENTRY(vec, i, sz) + + Access the value of the *i*-th nonzero. + There is no bounds checking. + +.. function:: ulong * gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) + const ulong * gr_sparse_vec_col_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) + gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) + gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) + + Get pointers to the column indices and entries. + +.. function:: void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) + + Ensure that *vec* has enough storage to hold at least *nnz* nonzeros. This does + not change the length of the vector or the number of nonzeros stored. + +.. function:: void gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx) + + Reallocate the storage in *vec* down the current number of nonzeros. + +.. function:: slong gr_sparse_vec_length(const gr_sparse_vec_t vec) + + Return the nominal length of the vector (note: not the number of nonzeros). + +.. function:: void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) + + Set the nominal length of the vector *vec* to *len*. If *len* is smaller than + the current length of *vec*, any entries whose column indices are at least *len* + are truncated. That is, the number of nonzeros can change. + +.. function:: slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) + + Get the number of nonzeros in *vec* + + +Setting and conversion +-------------------------------------------------------------------------------- + +.. function:: int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) + + Copy *src* to a copy of *res* + +.. function:: int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) + + Update *res* with the nonzeros in *src*. That is, any columns in *res* which also appear + in *src* are overwritten with their values in *src*. Any columns in *res* which do + not appear in *src* are left unchanged. + +.. function:: int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) + + Set *vec* to the sparse data given by *cols* and *entries* of length *nnz*. No assumption + is made that the columns are sorted nor that the entries are nonzero. The values associated + with duplicate columns are added together. + +.. function:: int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) + + Set *vec* to the sparse data given by *sorted_deduped_cols* and *entries*. The + *sorted_deduped_cols* must be in strictly increasing order. It is not required + that the values in *entries* are nonzero. + +.. function:: int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) + + Set *vec* to the zero vector. + +.. function:: int gr_sparse_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx) + + Initialize *vec* to a random vector with density (fraction of nonzeros) *density* and length *len*. + The algorithm is suitable when *density* is small. Specifically, column indices + are generated randomly and deduped. So if the density is + larger than ``1/sqrt(len)``, the true density of the returned vector is likely to be + lower than *density*. + +.. function:: int gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx) + + Convert the dense vector *src* of length *len* to the sparse vector *vec*. + +.. function:: int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) + + Convert the sparse vector *src* into a dense vector *vec*, which must have sufficient space. + +.. function:: int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx) + + Set *res* to a copy of the slice of *src* given by any entries whose column indices + lie in the half open interval ``[col_start, col_end)``. Column indices are shifted + by *col_start* (a column index of ``col_start`` would become ``0``). + +.. function:: int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) + + Set *vec* to a copy of *src* with the columns permuted. The column indices are shifted as: ``vec[p[i]] = src[i]``. + + +Comparison +-------------------------------------------------------------------------------- + +.. function:: truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx) + + Returns ``T_TRUE`` if *vec1* and *vec2* represent the same vector and ``T_FALSE`` otherwise. + +.. function:: truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) + + Return ``T_TRUE`` if *vec* represents the zero vector, and ``T_FALSE`` otherwise. + + +Output +-------------------------------------------------------------------------------- + +.. function:: int gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) + + Write the nonzeros of *vec* to the stream *out*. See ``gr_sparse_vec_to_dense`` + if it is desired to print out the entire vector, zeros and all. + +.. function:: int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx) + + Print the nonzeros of *vec* to ``stdout``. See ``gr_sparse_vec_to_dense`` + if it is desired to print out the entire vector, zeros and all. + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) + int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) + int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) + + Componentwise operations. (We do not provide analogous multiplication or division routines due to issues with zero.) + +.. function:: int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) + int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) + + Componentwise operations where the second input is allowed to have a different ring. + +.. function:: int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) + int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) + + Componentwise operations where the first input is allowed to have a different ring. + +.. function:: int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_submul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + + Componentwise add and sub mul, with different options for the scalar. + +.. function:: int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) + + Set *res* to -*src* + + +Sum and product +-------------------------------------------------------------------------------- + +.. function:: int gr_sparse_vec_sum(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) + + Set *res* to the sum of the entries in *vec*. + +.. function:: int gr_sparse_vec_nz_product(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) + + Set *res* to the product of the nonzero entries in *vec*. + + +Dot products +-------------------------------------------------------------------------------- + +Hello + + +.. raw:: latex + + \newpage diff --git a/doc/source/index.rst b/doc/source/index.rst index 44397e77cc..3ef6e6e0c8 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -57,6 +57,7 @@ Generic rings gr_generic.rst gr_special.rst gr_vec.rst + gr_sparse_vec.rst gr_mat.rst gr_poly.rst gr_mpoly.rst diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index d344fd9866..11594f09a8 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -56,7 +56,7 @@ gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) return GR_SUCCESS; } - +#define GR_SPARSE_VEC_COL(vec, i) (vec)->cols[i] #define GR_SPARSE_VEC_ENTRY(vec, i, sz) GR_ENTRY((vec)->entries, i, sz) GR_SPARSE_VEC_INLINE ulong * gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->cols + i; } @@ -64,7 +64,6 @@ GR_SPARSE_VEC_INLINE const ulong * gr_sparse_vec_col_srcptr(const gr_sparse_vec_ GR_SPARSE_VEC_INLINE gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); } GR_SPARSE_VEC_INLINE gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); } - void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx); void gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx); GR_SPARSE_VEC_INLINE slong gr_sparse_vec_length(const gr_sparse_vec_t vec) { return vec->length; } @@ -72,9 +71,9 @@ void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) { return vec->nnz; } WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, slong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; return GR_SUCCESS; } WARN_UNUSED_RESULT int gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx); @@ -82,7 +81,6 @@ WARN_UNUSED_RESULT int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_ truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx); GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return (vec->nnz == 0 ? T_TRUE : T_FALSE); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; return GR_SUCCESS; } int gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx); int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx); @@ -109,7 +107,8 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo /* Different arguments in different orders, etc */ #define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ int status; \ - slong sz, new_nnz, a_ind, b_ind, dest_ind, a_nnz, b_nnz, a_col, b_col, i; \ + slong sz, new_nnz, a_ind, b_ind, dest_ind, a_nnz, b_nnz, i; \ + ulong a_col, b_col; \ if ((DEST_VEC)->length != (A_VEC)->length || (A_VEC)->length != (B_VEC)->length) \ return GR_DOMAIN; \ status = GR_SUCCESS; \ diff --git a/src/gr_sparse_vec/set_from_entries.c b/src/gr_sparse_vec/set_from_entries.c index 058222fc05..acb89f7a0e 100644 --- a/src/gr_sparse_vec/set_from_entries.c +++ b/src/gr_sparse_vec/set_from_entries.c @@ -18,7 +18,7 @@ static int gr_sparse_vec_slong_sort(const void* a, const void* b) int -gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) +gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) { slong i,j,sz,new_nnz; int status; @@ -51,7 +51,7 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entr /* If it's a new column, do a set; otherwise do an accumulate */ if (i == 0 || si[i-1].col != si[i].col) { - if (j == -1 || (T_TRUE != gr_is_zero(GR_ENTRY(vec->entries, j, sz), ctx))) /* Only move to the next target if the current one is nonzero */ + if (j == -1 || (T_FALSE == gr_is_zero(GR_ENTRY(vec->entries, j, sz), ctx))) /* Only move to the next target if the current one is nonzero */ { j++; if (j >= new_nnz) @@ -76,7 +76,7 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, slong * cols, gr_srcptr entr } int -gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, slong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) +gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) { slong i,j,sz; int status; From b6617f7b9ff88272477cfe8611997445ebfbd627 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Sat, 10 Feb 2024 14:51:47 -0800 Subject: [PATCH 14/59] more documentation --- doc/source/gr_sparse_vec.rst | 99 +++++++++++++++++++++++++++++------- src/gr_sparse_vec.h | 4 +- 2 files changed, 85 insertions(+), 18 deletions(-) diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index 5425bd0e34..f1cb33b4c7 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -5,10 +5,11 @@ A :type:`gr_sparse_vec_t` is a represention of a vector over a generic ring which is optimized for the situation where there are many entries which -are zero (the vector is sparse). Internally, the vector records only -the positions of the nonzeros and their values. Although technically the -type and all its functions will operate correctly with any density, -a :type:`gr_vec_t` may be more efficient in the number of nonzeros is not small. +are zero (the vector is *sparse*, or has *low density*). Internally, the +vector records only the positions of the nonzeros and their values. +Although technically the type and all its functions will operate correctly +with any density, a regular :type:`gr_vec_t` may be more efficient in the number +of nonzeros is not small. Types and basic access -------------------------------------------------------------------------------- @@ -113,11 +114,11 @@ Setting and conversion .. function:: int gr_sparse_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx) - Initialize *vec* to a random vector with density (fraction of nonzeros) *density* and length *len*. - The algorithm is suitable when *density* is small. Specifically, column indices - are generated randomly and deduped. So if the density is - larger than ``1/sqrt(len)``, the true density of the returned vector is likely to be - lower than *density*. + Initialize *vec* to a random vector with density (fraction of nonzeros) + *density* and length *len*. The algorithm is suitable when *density* is small. + Specifically, column indices are generated randomly and deduped. So if the + density is larger than ``1/sqrt(len)``, the true density of the returned vector + is likely to be lower than *density*. .. function:: int gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx) @@ -125,17 +126,20 @@ Setting and conversion .. function:: int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) - Convert the sparse vector *src* into a dense vector *vec*, which must have sufficient space. + Convert the sparse vector *src* into a dense vector *vec*, which must have + sufficient space (i.e. ``vec->length``). .. function:: int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx) - Set *res* to a copy of the slice of *src* given by any entries whose column indices - lie in the half open interval ``[col_start, col_end)``. Column indices are shifted - by *col_start* (a column index of ``col_start`` would become ``0``). + Set *res* to a copy of the slice of *src* given by any entries whose + column indices lie in the half open interval ``[col_start, col_end)``. + Column indices are shifted by *col_start* (a column index of ``col_start`` + would become ``0``). .. function:: int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) - Set *vec* to a copy of *src* with the columns permuted. The column indices are shifted as: ``vec[p[i]] = src[i]``. + Set *vec* to a copy of *src* with the columns permuted. The column + indices are shifted as: ``vec[p[i]] = src[i]``. Comparison @@ -147,7 +151,7 @@ Comparison .. function:: truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) - Return ``T_TRUE`` if *vec* represents the zero vector, and ``T_FALSE`` otherwise. + Return ``T_TRUE`` if *vec* represents the zero vector and ``T_FALSE`` otherwise. Output @@ -163,6 +167,7 @@ Output Print the nonzeros of *vec* to ``stdout``. See ``gr_sparse_vec_to_dense`` if it is desired to print out the entire vector, zeros and all. + Arithmetic -------------------------------------------------------------------------------- @@ -170,15 +175,19 @@ Arithmetic int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) - Componentwise operations. (We do not provide analogous multiplication or division routines due to issues with zero.) + Componentwise operations. (We do not provide analogous division or exponentiation + routines due since sparse inputs to these operations would be undefined or + fully dense.) .. function:: int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) + int gr_sparse_vec_mul_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) Componentwise operations where the second input is allowed to have a different ring. .. function:: int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) + int gr_other_mul_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) Componentwise operations where the first input is allowed to have a different ring. @@ -194,6 +203,54 @@ Arithmetic Set *res* to -*src* +Arithmetic into dense vectors +-------------------------------------------------------------------------------- + +.. function:: int gr_sparse_vec_update_to_dense(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) + int gr_sparse_vec_add_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_sparse_vec_sub_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_sparse_vec_nz_mul_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_sparse_vec_nz_div_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_sparse_vec_addmul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_submul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_addmul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) + int gr_sparse_vec_submul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) + int gr_sparse_vec_addmul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) + int gr_sparse_vec_submul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) + + These functions facilitate accumulating a sparse vector into a dense + target. They have one dense input, one sparse input, and a dense output. + For all functions, it is assumed that *dres* and *dvec1* have the same + length as *svec* or *svec2*, as appropriate. The functions + ``gr_sparse_vec_update_to_dense()`` (overwrite the entries in *dres*), + ``gr_sparse_vec_nz_mul_to_dense()``, and ``gr_sparse_vec_nz_div_to_dense()`` + only operate on the locations for which *svec2* is nonzero. + + +Componentwise multiplication and division +-------------------------------------------------------------------------------- + +.. function:: int gr_sparse_vec_mul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) + + Set *res* to be *src* multiplied or divided by *c*. + (Addition and subtraction are not provided because they would create + dense output.) + Sum and product -------------------------------------------------------------------------------- @@ -209,7 +266,15 @@ Sum and product Dot products -------------------------------------------------------------------------------- -Hello +.. function:: int gr_sparse_vec_dot(gr_ptr res, gr_srcptr c, int subtract, const gr_sparse_vec_t x, const gr_sparse_vec_t y, gr_ctx_t ctx) + + Set *res* equal to `c \pm x \cdot y`. + +.. function:: int gr_sparse_vec_dot_rev(gr_ptr res, gr_srcptr c, int subtract, const gr_sparse_vec_t x, const gr_sparse_vec_t y, gr_ctx_t ctx) + + Set *res* equal to `c \pm \sum_{i=0}^{n-1}x_iy_{n-1-i}`. + + .. raw:: latex diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 11594f09a8..f6e9d97283 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -104,7 +104,7 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo /* This is used for operations like add which have to riffle through the entries of two vectors */ /* It's an annoying macro that combines with the macros below. This is so we can handle */ -/* Different arguments in different orders, etc */ +/* different arguments in different orders, etc */ #define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ int status; \ slong sz, new_nnz, a_ind, b_ind, dest_ind, a_nnz, b_nnz, i; \ @@ -180,11 +180,13 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t re GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_set_other, src2, b_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_add_other, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_sub_other, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, GR_SPV_RFL_BOP_OTHER(gr_mul_other, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } #define GR_SPV_RFL_OTHER_BOP(F, Y, Y_ind, CTX2, Z, Z_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), (CTX2), GR_ENTRY(Z->entries, Z_ind, sz), ctx) GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), GR_SPV_RFL_UOP(gr_set, src2, b_ind), GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), GR_SPV_RFL_UOP(gr_neg, src2, b_ind), GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_mul_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, GR_SPV_RFL_OTHER_BOP(gr_other_mul, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } #define GR_SPV_RFL_UOP_SCALAR(F, Y, Y_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), c, ctx) From 3b42d5d5a49101497b3682f42327c32d0f21d054 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Mon, 12 Feb 2024 22:05:52 -0800 Subject: [PATCH 15/59] cmake and compiling --- CMakeLists.txt | 2 +- src/gr_sparse_vec/test/t-creation.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dcae34ba1..c9d89feca2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,7 +139,7 @@ set(_BUILD_DIRS dirichlet bernoulli hypgeom gr gr_generic gr_vec gr_mat - gr_poly gr_mpoly gr_special + gr_poly gr_mpoly gr_special gr_sparse_vec calcium fmpz_mpoly_q diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c index dc6d4d178c..52f62feca6 100644 --- a/src/gr_sparse_vec/test/t-creation.c +++ b/src/gr_sparse_vec/test/t-creation.c @@ -9,7 +9,7 @@ test_init(gr_ctx_t ctx) gr_sparse_vec_t vec; int status = GR_SUCCESS; status |= gr_sparse_vec_init(vec, 5, ctx); - status |= gr_sparse_vec_clear(vec); + status |= gr_sparse_vec_clear(vec, ctx); return status; } @@ -29,4 +29,4 @@ TEST_FUNCTION_START(gr_sparse_vec_creation, state) CHECK_TEST(test_init_from_entries(ctx), "Init from entries"); gr_ctx_clear(ctx); TEST_FUNCTION_END(state); -} \ No newline at end of file +} From c39f222207c1191dd6588668c5bed4e049640825 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Tue, 13 Feb 2024 21:40:10 -0800 Subject: [PATCH 16/59] working on tests and get/set individual entries --- doc/source/gr_sparse_vec.rst | 22 +++++++++++++++++++--- src/gr_sparse_vec.h | 3 +++ src/gr_sparse_vec/find_entry.c | 7 +++++++ src/gr_sparse_vec/set_entry.c | 8 ++++++++ src/gr_sparse_vec/test/t-creation.c | 27 +++++++++++++++++++++++++-- 5 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/gr_sparse_vec/find_entry.c create mode 100644 src/gr_sparse_vec/set_entry.c diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index f1cb33b4c7..6229e34cf3 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -45,12 +45,12 @@ Types and basic access .. macro:: GR_SPARSE_VEC_COL(vec, i) Access the column index of the *i*-th nonzero. - There is no bounds checking. + There is no bounds checking. (See also `gr_sparse_vec_find_entry`) .. macro:: GR_SPARSE_VEC_ENTRY(vec, i, sz) Access the value of the *i*-th nonzero. - There is no bounds checking. + There is no bounds checking. (See also `gr_sparse_vec_find_entry`) .. function:: ulong * gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) const ulong * gr_sparse_vec_col_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) @@ -83,13 +83,29 @@ Types and basic access Get the number of nonzeros in *vec* -Setting and conversion +Getting, setting and conversion -------------------------------------------------------------------------------- .. function:: int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) Copy *src* to a copy of *res* +.. function:: int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_t ctx) + + Set the the value at column *col* to be *entry*. Because of the way sparse + vectors are represented, it is not efficient to call this function + repeatedly (it is linear time in the number of nonzeros in *vec*). + If possible, the entries to update should be batched up and + given using `gr_sparse_vec_update`, `gr_sparse_vec_set_from_entries`, + or `gr_sparse_vec_set_from_entries_sorted_deduped`. + +.. function:: int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx) + + Set *res* to be the entry at column *col*. If *col* is not a column + in which *vec* contains a nonzero, *res* is set to zero. + Because of the way sparse vectors are represented, this is not constant time. + (It is log time in the number of nonzeros in *vec*.) + .. function:: int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) Update *res* with the nonzeros in *src*. That is, any columns in *res* which also appear diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index f6e9d97283..ca3f1dfdd0 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -79,6 +79,9 @@ WARN_UNUSED_RESULT int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, g WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_t ctx); + truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx); GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return (vec->nnz == 0 ? T_TRUE : T_FALSE); } diff --git a/src/gr_sparse_vec/find_entry.c b/src/gr_sparse_vec/find_entry.c new file mode 100644 index 0000000000..b5f94723b6 --- /dev/null +++ b/src/gr_sparse_vec/find_entry.c @@ -0,0 +1,7 @@ +#include +#include "gr_sparse_vec.h" + +int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx) +{ + +} diff --git a/src/gr_sparse_vec/set_entry.c b/src/gr_sparse_vec/set_entry.c new file mode 100644 index 0000000000..3c51329e90 --- /dev/null +++ b/src/gr_sparse_vec/set_entry.c @@ -0,0 +1,8 @@ +#include +#include "gr_sparse_vec.h" + +int +gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_t ctx) +{ + return GR_SUCCESS; +} diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c index 52f62feca6..fc5f14e7d9 100644 --- a/src/gr_sparse_vec/test/t-creation.c +++ b/src/gr_sparse_vec/test/t-creation.c @@ -14,9 +14,32 @@ test_init(gr_ctx_t ctx) } int -test_init_from_entries(gr_ctx_t ctx) +test_init_from_entries(flint_rand_t state, gr_ctx_t ctx) { + slong i; + gr_sparse_vec_t vec; + gr_vec_t dvec; + gr_ptr temp; + GR_TMP_INIT(temp, ctx); int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + slong N = 5; + ulong cols[5] = {0, 2, 4, 6, 8}; + status |= gr_vec_init(dvec, N, ctx); + status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); + status |= gr_sparse_vec_init(vec, 2*N, ctx); + status |= gr_sparse_vec_set_from_entries_sorted_deduped(vec, cols, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); + for (i = 0; i < 2*N; i++) + { + status |= gr_sparse_vec_find_entry(temp, vec, i, ctx); + if ((i & 1) == 1 && (T_TRUE != gr_is_zero(temp, ctx))) /* Odd cols should all be zero */ + return GR_TEST_FAIL; + if ((i & 1) == 0 && (T_TRUE != gr_equal(temp, GR_VEC_ENTRY(dvec, i>>1, ctx)))) + return GR_TEST_FAIL; + } + GR_TMP_CLEAR(temp, ctx); + status |= gr_vec_clear(dvec, ctx); + status |= gr_sparse_vec_clear(vec, ctx); return status; } @@ -26,7 +49,7 @@ TEST_FUNCTION_START(gr_sparse_vec_creation, state) gr_ctx_t ctx; gr_ctx_init_random(ctx, state); CHECK_TEST(test_init(ctx), "Init"); - CHECK_TEST(test_init_from_entries(ctx), "Init from entries"); + CHECK_TEST(test_init_from_entries(state, ctx), "Init from entries"); gr_ctx_clear(ctx); TEST_FUNCTION_END(state); } From e1ce9e5cd9e0533b955541d7ec6da55ebc8a6d3a Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Wed, 14 Feb 2024 20:58:39 -0800 Subject: [PATCH 17/59] find/set entry --- src/gr_sparse_vec/find_entry.c | 24 ++++++++++++-- src/gr_sparse_vec/set_entry.c | 48 +++++++++++++++++++++++++++- src/gr_sparse_vec/set_from_entries.c | 4 +-- src/gr_sparse_vec/test/t-creation.c | 6 ++-- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/src/gr_sparse_vec/find_entry.c b/src/gr_sparse_vec/find_entry.c index b5f94723b6..fa75edc413 100644 --- a/src/gr_sparse_vec/find_entry.c +++ b/src/gr_sparse_vec/find_entry.c @@ -1,7 +1,27 @@ #include #include "gr_sparse_vec.h" -int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx) + +static int gr_sparse_vec_ulong_cmp(const void* a, const void* b) +{ + ulong av = *((ulong*)(a)); + ulong bv = *((ulong*)(b)); + return (av < bv ? -1 : (av > bv ? 1 : 0)); +} + + +int +gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx) { - + slong i; + slong sz = ctx->sizeof_elem; + slong nnz = vec->nnz; + ulong* bs = NULL; + if (col < 0 || col >= vec->length) + return GR_DOMAIN; + bs = bsearch(&col, vec->cols, vec->nnz, sizeof(slong), gr_sparse_vec_ulong_cmp); + if (bs == NULL) + return gr_zero(res, ctx); + i = (bs - vec->cols); + return gr_set(res, GR_ENTRY(vec->entries, i, sz), ctx); } diff --git a/src/gr_sparse_vec/set_entry.c b/src/gr_sparse_vec/set_entry.c index 3c51329e90..2773d52de5 100644 --- a/src/gr_sparse_vec/set_entry.c +++ b/src/gr_sparse_vec/set_entry.c @@ -1,8 +1,54 @@ #include #include "gr_sparse_vec.h" +static int gr_sparse_vec_ulong_cmp(const void* a, const void* b) +{ + ulong av = *((ulong*)(a)); + ulong bv = *((ulong*)(b)); + return (av < bv ? -1 : (av > bv ? 1 : 0)); +} + int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_t ctx) { - return GR_SUCCESS; + slong i,j; + slong sz = ctx->sizeof_elem; + slong nnz = vec->nnz; + ulong* bs = NULL; + if (col < 0 || col >= vec->length) + return GR_DOMAIN; + bs = bsearch(&col, vec->cols, vec->nnz, sizeof(slong), gr_sparse_vec_ulong_cmp); + if (bs != NULL) + { + i = (bs - vec->cols); + return gr_set(GR_ENTRY(vec->entries, i, sz), entry, ctx); + } + else + { + /* In this case, it's going to cost linear time anyway, so just brute force search */ + gr_sparse_vec_fit_nnz(vec, vec->nnz+1, ctx); + for (i = 0; i < nnz; i++) + { + if (vec->cols[i] < col) + break; + } + /* Now if i < nnz, then we should put the entry right *after* it */ + /* If i == nnz, we should put the entry right there */ + if (i < nnz) + i++; + if (i < nnz) + { + /* If necessary, move everything up to make space */ + memmove(vec->cols + i + 1, vec->cols + i, (vec->nnz - i)*sizeof(slong)); + for (j = vec->nnz; j > i; j--) + { + gr_swap(GR_ENTRY(vec->entries, j-1, sz), GR_ENTRY(vec->entries, j, sz), ctx); + } + } + /* Now there's an available spot in index i */ + vec->cols[i] = col; + vec->nnz++; + return gr_set(GR_ENTRY(vec->entries, i, sz), entry, ctx); + } + return GR_UNABLE; /* This shouldn't happen */ } diff --git a/src/gr_sparse_vec/set_from_entries.c b/src/gr_sparse_vec/set_from_entries.c index acb89f7a0e..e2595a91cc 100644 --- a/src/gr_sparse_vec/set_from_entries.c +++ b/src/gr_sparse_vec/set_from_entries.c @@ -8,7 +8,7 @@ typedef struct } gr_sparse_vec_slong_sorter_t; -static int gr_sparse_vec_slong_sort(const void* a, const void* b) +static int gr_sparse_vec_slong_cmp(const void* a, const void* b) { slong ak = ((gr_sparse_vec_slong_sorter_t*)(a))->col; slong bk = ((gr_sparse_vec_slong_sorter_t*)(b))->col; @@ -29,7 +29,7 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entr si[i].col = cols[i]; si[i].i = i; } - qsort(si, nnz, sizeof(gr_sparse_vec_slong_sorter_t), gr_sparse_vec_slong_sort); + qsort(si, nnz, sizeof(gr_sparse_vec_slong_sorter_t), gr_sparse_vec_slong_cmp); /* Since the columns are sorted, we can just just the last to make sure all the columns fit */ if (nnz > 0 && si[nnz-1].col >= vec->length) { diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c index fc5f14e7d9..949b90ccbc 100644 --- a/src/gr_sparse_vec/test/t-creation.c +++ b/src/gr_sparse_vec/test/t-creation.c @@ -25,7 +25,7 @@ test_init_from_entries(flint_rand_t state, gr_ctx_t ctx) slong sz = ctx->sizeof_elem; slong N = 5; ulong cols[5] = {0, 2, 4, 6, 8}; - status |= gr_vec_init(dvec, N, ctx); + gr_vec_init(dvec, N, ctx); status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); status |= gr_sparse_vec_init(vec, 2*N, ctx); status |= gr_sparse_vec_set_from_entries_sorted_deduped(vec, cols, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); @@ -34,11 +34,11 @@ test_init_from_entries(flint_rand_t state, gr_ctx_t ctx) status |= gr_sparse_vec_find_entry(temp, vec, i, ctx); if ((i & 1) == 1 && (T_TRUE != gr_is_zero(temp, ctx))) /* Odd cols should all be zero */ return GR_TEST_FAIL; - if ((i & 1) == 0 && (T_TRUE != gr_equal(temp, GR_VEC_ENTRY(dvec, i>>1, ctx)))) + if ((i & 1) == 0 && (T_TRUE != gr_equal(temp, GR_VEC_ENTRY(dvec, i>>1, sz), ctx))) return GR_TEST_FAIL; } GR_TMP_CLEAR(temp, ctx); - status |= gr_vec_clear(dvec, ctx); + gr_vec_clear(dvec, ctx); status |= gr_sparse_vec_clear(vec, ctx); return status; } From bfc4bca9bdaa0057938328127c4fad64d710e9f0 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Fri, 16 Feb 2024 11:50:14 -0800 Subject: [PATCH 18/59] debugging sparse vec creation test failure --- src/gr_sparse_vec/set_from_entries.c | 2 +- src/gr_sparse_vec/test/t-creation.c | 62 +++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/gr_sparse_vec/set_from_entries.c b/src/gr_sparse_vec/set_from_entries.c index e2595a91cc..c59b717686 100644 --- a/src/gr_sparse_vec/set_from_entries.c +++ b/src/gr_sparse_vec/set_from_entries.c @@ -30,7 +30,7 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entr si[i].i = i; } qsort(si, nnz, sizeof(gr_sparse_vec_slong_sorter_t), gr_sparse_vec_slong_cmp); - /* Since the columns are sorted, we can just just the last to make sure all the columns fit */ + /* Since the columns are sorted, we can just test the last to make sure all the columns fit */ if (nnz > 0 && si[nnz-1].col >= vec->length) { flint_free(si); diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c index 949b90ccbc..3fa723fad3 100644 --- a/src/gr_sparse_vec/test/t-creation.c +++ b/src/gr_sparse_vec/test/t-creation.c @@ -13,8 +13,9 @@ test_init(gr_ctx_t ctx) return status; } + int -test_init_from_entries(flint_rand_t state, gr_ctx_t ctx) +test_init_from_entries_sorted(flint_rand_t state, gr_ctx_t ctx) { slong i; gr_sparse_vec_t vec; @@ -44,12 +45,69 @@ test_init_from_entries(flint_rand_t state, gr_ctx_t ctx) } +int +test_init_from_entries_unsorted(flint_rand_t state, gr_ctx_t ctx) +{ + slong i,j; + gr_sparse_vec_t vec; + gr_vec_t dvec; + gr_ptr temp, temp2; + GR_TMP_INIT2(temp, temp2, ctx); + int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + slong N = 5; + ulong cols[5] = {8, 4, 3, 8, 1}; /* the locations of the duplicate are used later! */ + gr_vec_init(dvec, N, ctx); + status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); + status |= gr_add(temp2, GR_VEC_ENTRY(dvec, 0, sz), GR_VEC_ENTRY(dvec, 3, sz), ctx); + status |= gr_sparse_vec_init(vec, 2*N, ctx); + status |= gr_sparse_vec_set_from_entries(vec, cols, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); + if (status != GR_SUCCESS) + { + flint_printf("Bad status after creating vectors\n"); + return GR_TEST_FAIL; + } + gr_print(temp2, ctx); + gr_vec_print(dvec, ctx); + gr_sparse_vec_print_nz(vec, ctx); + for (i = 0; i < 2*N; i++) + { + status |= gr_sparse_vec_find_entry(temp, vec, i, ctx); + if (i == 8) + { + if (T_TRUE != gr_equal(temp, temp2, ctx)) + return GR_TEST_FAIL; + } + else + { + for (j = 0; j < N; j++) + { + if (cols[j] == i) + { + if (T_TRUE != gr_equal(temp, GR_VEC_ENTRY(dvec, j, sz), ctx)) + return GR_TEST_FAIL; + break; + } + } + } + } + GR_TMP_CLEAR(temp, ctx); + GR_TMP_CLEAR(temp2, ctx); + gr_vec_clear(dvec, ctx); + status |= gr_sparse_vec_clear(vec, ctx); + return status; +} + + + + TEST_FUNCTION_START(gr_sparse_vec_creation, state) { gr_ctx_t ctx; gr_ctx_init_random(ctx, state); CHECK_TEST(test_init(ctx), "Init"); - CHECK_TEST(test_init_from_entries(state, ctx), "Init from entries"); + CHECK_TEST(test_init_from_entries_sorted(state, ctx), "Init from entries sorted"); + CHECK_TEST(test_init_from_entries_unsorted(state, ctx), "Init from entries unsorted"); gr_ctx_clear(ctx); TEST_FUNCTION_END(state); } From edca4ac06eb47a803ae7219706edf16be6564744 Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Tue, 20 Feb 2024 19:24:28 -0800 Subject: [PATCH 19/59] unsorted creation test passing --- src/gr_sparse_vec/set_from_entries.c | 6 ++- src/gr_sparse_vec/test/t-creation.c | 80 +++++++++++++++------------- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/gr_sparse_vec/set_from_entries.c b/src/gr_sparse_vec/set_from_entries.c index c59b717686..b50468ec07 100644 --- a/src/gr_sparse_vec/set_from_entries.c +++ b/src/gr_sparse_vec/set_from_entries.c @@ -45,7 +45,8 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entr gr_sparse_vec_fit_nnz(vec, new_nnz, ctx); sz = ctx->sizeof_elem; status = GR_SUCCESS; - j = -1; + j = -1; /* j tracks the current index we are going to put the nonzero in the sparse vector storage */ + /* i tracks where in the column-sorted list of nonzeros we are pulling from */ for (i = 0; i < nnz && status == GR_SUCCESS; i++) { /* If it's a new column, do a set; otherwise do an accumulate */ @@ -70,7 +71,8 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entr status |= gr_add(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, si[i].i, sz), ctx); } } - vec->nnz = j; + /* Finally, figure out whether the last entry is zero (in which case it doesn't count), and set nnz accordingly */ + vec->nnz = (T_FALSE == gr_is_zero(GR_ENTRY(vec->entries, j, sz), ctx) ? j+1 : j); flint_free(si); return status; } diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c index 3fa723fad3..e437adfb96 100644 --- a/src/gr_sparse_vec/test/t-creation.c +++ b/src/gr_sparse_vec/test/t-creation.c @@ -46,60 +46,68 @@ test_init_from_entries_sorted(flint_rand_t state, gr_ctx_t ctx) int -test_init_from_entries_unsorted(flint_rand_t state, gr_ctx_t ctx) +test_init_from_entries_unsorted_internal(ulong *cols, gr_srcptr entries, slong len, slong n_entries, gr_ctx_t ctx) { - slong i,j; + /* Yes, this is quadratic time just to be careful */ + int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + slong i,j,col; gr_sparse_vec_t vec; - gr_vec_t dvec; gr_ptr temp, temp2; GR_TMP_INIT2(temp, temp2, ctx); - int status = GR_SUCCESS; - slong sz = ctx->sizeof_elem; - slong N = 5; - ulong cols[5] = {8, 4, 3, 8, 1}; /* the locations of the duplicate are used later! */ - gr_vec_init(dvec, N, ctx); - status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); - status |= gr_add(temp2, GR_VEC_ENTRY(dvec, 0, sz), GR_VEC_ENTRY(dvec, 3, sz), ctx); - status |= gr_sparse_vec_init(vec, 2*N, ctx); - status |= gr_sparse_vec_set_from_entries(vec, cols, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); + status |= gr_sparse_vec_init(vec, len, ctx); + status |= gr_sparse_vec_set_from_entries(vec, cols, entries, n_entries, ctx); if (status != GR_SUCCESS) - { - flint_printf("Bad status after creating vectors\n"); return GR_TEST_FAIL; - } - gr_print(temp2, ctx); - gr_vec_print(dvec, ctx); - gr_sparse_vec_print_nz(vec, ctx); - for (i = 0; i < 2*N; i++) + /* Scan through every column in the sparse vector */ + for (i = 0; i < len; i++) { - status |= gr_sparse_vec_find_entry(temp, vec, i, ctx); - if (i == 8) + /* Scan through the entries to figure out what the correct value should be */ + status |= gr_zero(temp, ctx); + for (j = 0; j < n_entries; j++) { - if (T_TRUE != gr_equal(temp, temp2, ctx)) - return GR_TEST_FAIL; - } - else - { - for (j = 0; j < N; j++) - { - if (cols[j] == i) - { - if (T_TRUE != gr_equal(temp, GR_VEC_ENTRY(dvec, j, sz), ctx)) - return GR_TEST_FAIL; - break; - } - } + if (cols[j] == i) + status |= gr_add(temp, temp, GR_ENTRY(entries, j, sz), ctx); } + /* Check it */ + status |= gr_sparse_vec_find_entry(temp2, vec, i, ctx); + if (T_TRUE != gr_equal(temp, temp2, ctx)) + return GR_TEST_FAIL; } GR_TMP_CLEAR(temp, ctx); GR_TMP_CLEAR(temp2, ctx); - gr_vec_clear(dvec, ctx); status |= gr_sparse_vec_clear(vec, ctx); return status; } +int +test_init_from_entries_unsorted(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + slong N = 5; + ulong cols[5] = {8, 4, 3, 8, 1}; + gr_vec_t dvec; + gr_vec_init(dvec, N, ctx); + /* First test against random entries */ + status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); + status |= test_init_from_entries_unsorted_internal(cols, GR_VEC_ENTRY(dvec, 0, sz), 2*N, N, ctx); + + /* Next test against some adversarial entries */ + slong entries_si[5] = {5, 0, 2, -5, 1}; + for (i = 0; i < N; i++) + status |= gr_set_si(GR_VEC_ENTRY(dvec, i, sz), entries_si[i], ctx); + status |= test_init_from_entries_unsorted_internal(cols, GR_VEC_ENTRY(dvec, 0, sz), 2*N, N, ctx); + + gr_vec_clear(dvec, ctx); + return status; +} + + + TEST_FUNCTION_START(gr_sparse_vec_creation, state) { From fd2fad5e6faf779127c6d462ffa4b0c9015ed0df Mon Sep 17 00:00:00 2001 From: Alden Walker Date: Tue, 20 Feb 2024 20:57:57 -0800 Subject: [PATCH 20/59] added conversion test --- src/gr_sparse_vec/from_dense.c | 1 + src/gr_sparse_vec/test/main.c | 2 ++ src/gr_sparse_vec/test/t-conversion.c | 43 +++++++++++++++++++++++++++ src/gr_sparse_vec/to_dense.c | 2 +- 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/gr_sparse_vec/test/t-conversion.c diff --git a/src/gr_sparse_vec/from_dense.c b/src/gr_sparse_vec/from_dense.c index 8999619515..389413e017 100644 --- a/src/gr_sparse_vec/from_dense.c +++ b/src/gr_sparse_vec/from_dense.c @@ -23,6 +23,7 @@ gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t nnz++; } } + vec->length = len; vec->nnz = nnz; return status; } \ No newline at end of file diff --git a/src/gr_sparse_vec/test/main.c b/src/gr_sparse_vec/test/main.c index 822f38f75d..4a505df0db 100644 --- a/src/gr_sparse_vec/test/main.c +++ b/src/gr_sparse_vec/test/main.c @@ -4,12 +4,14 @@ /* Include functions *********************************************************/ #include "t-creation.c" +#include "t-conversion.c" /* Array of test functions ***************************************************/ test_struct tests[] = { TEST_FUNCTION(gr_sparse_vec_creation), + TEST_FUNCTION(gr_sparse_vec_conversion), }; /* main function *************************************************************/ diff --git a/src/gr_sparse_vec/test/t-conversion.c b/src/gr_sparse_vec/test/t-conversion.c new file mode 100644 index 0000000000..bfc7c3fef2 --- /dev/null +++ b/src/gr_sparse_vec/test/t-conversion.c @@ -0,0 +1,43 @@ +#include "test_helpers.h" +#include "gr_sparse_vec.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + + + +int +test_conversion(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + slong N = 100; + slong n_tests = 20; + slong sz = ctx->sizeof_elem; + int status = GR_SUCCESS; + gr_sparse_vec_t vec; + gr_vec_t dvec, dvec2; + gr_vec_init(dvec, N, ctx); + gr_vec_init(dvec2, N, ctx); + status |= gr_sparse_vec_init(vec, N, ctx); + + for (i = 0; i < n_tests; i++) + { + status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); + status |= gr_sparse_vec_from_dense(vec, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); + status |= gr_sparse_vec_to_dense(GR_VEC_ENTRY(dvec2, 0, sz), vec, ctx); + if (T_TRUE != _gr_vec_equal(GR_VEC_ENTRY(dvec, 0, sz), GR_VEC_ENTRY(dvec2, 0, sz), N, ctx)) + return GR_TEST_FAIL; + } + status |= gr_sparse_vec_clear(vec, ctx); + gr_vec_clear(dvec, ctx); + gr_vec_clear(dvec2, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_vec_conversion, state) +{ + gr_ctx_t ctx; + gr_ctx_init_random(ctx, state); + CHECK_TEST(test_conversion(state, ctx), "Conversion from and to dense"); + gr_ctx_clear(ctx); + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_vec/to_dense.c b/src/gr_sparse_vec/to_dense.c index 38e29c7d39..cc97007dbf 100644 --- a/src/gr_sparse_vec/to_dense.c +++ b/src/gr_sparse_vec/to_dense.c @@ -11,7 +11,7 @@ gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) j = 0; for (i = 0; i < len; i++) { - /* if i is the column of the next nonzero in src, copy it is */ + /* if i is the column of the next nonzero in src, copy it in */ if (j < nnz && i == src->cols[j]) { status |= gr_set(GR_ENTRY(vec, i, sz), GR_ENTRY(src->entries, j, sz), ctx); From 94aa615366ad87f2c287ba3aa3afcef5c7ac8003 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 17 Mar 2024 14:44:47 -0700 Subject: [PATCH 21/59] Added shallow transpose macro --- src/gr_mat.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/gr_mat.h b/src/gr_mat.h index 9207f0d750..a67dbc1436 100644 --- a/src/gr_mat.h +++ b/src/gr_mat.h @@ -211,6 +211,21 @@ WARN_UNUSED_RESULT int gr_mat_hilbert(gr_mat_t mat, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_mat_hadamard(gr_mat_t mat, gr_ctx_t ctx); /* todo: dft, dct */ +#define _GR_MAT_INIT_SHALLOW_TRANSPOSE(B, A, sz) { \ + B->r = A->c; \ + B->c = A->r; \ + B->rows = flint_malloc(A->c * sizeof(gr_ptr)); \ + B->entries = TMP_ALLOC(sz * A->c * A->r); \ + for (j = 0; j < A->c; j++) \ + { \ + B->rows[j] = GR_ENTRY(B->entries, j * A->r, sz); \ + for (i = 0; i < A->r; i++) \ + { \ + set_shallow(GR_MAT_ENTRY(B, j, i, sz), GR_MAT_ENTRY(B, i, j, sz), ctx); \ + } + } \ +} + WARN_UNUSED_RESULT int gr_mat_transpose(gr_mat_t B, const gr_mat_t A, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_mat_nonsingular_solve_tril_classical(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx); From 1427ffa464008a0b0b8944f5b86a4f25fa5887d8 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 17 Mar 2024 16:34:41 -0700 Subject: [PATCH 22/59] Some nomenclature changes --- doc/source/gr_sparse_vec.rst | 12 ++++---- src/gr_sparse_vec.h | 19 ++++++++---- ...ount_unique_cols.c => count_unique_inds.c} | 8 ++--- src/gr_sparse_vec/equal.c | 2 +- src/gr_sparse_vec/find_entry.c | 5 ++-- src/gr_sparse_vec/fit_nnz.c | 2 +- src/gr_sparse_vec/from_dense.c | 6 ++-- .../{permute_cols.c => permute_inds.c} | 14 ++++----- src/gr_sparse_vec/randtest.c | 14 ++++----- src/gr_sparse_vec/set.c | 4 +-- src/gr_sparse_vec/set_entry.c | 10 +++---- src/gr_sparse_vec/set_from_entries.c | 12 ++++---- src/gr_sparse_vec/set_length.c | 2 +- src/gr_sparse_vec/shrink_to_nnz.c | 4 +-- src/gr_sparse_vec/slice.c | 8 ++--- src/gr_sparse_vec/test/t-conversion.c | 8 ++--- src/gr_sparse_vec/test/t-creation.c | 30 +++++++++---------- src/gr_sparse_vec/to_dense.c | 4 +-- src/gr_sparse_vec/write.c | 2 +- 19 files changed, 86 insertions(+), 80 deletions(-) rename src/gr_sparse_vec/{count_unique_cols.c => count_unique_inds.c} (69%) rename src/gr_sparse_vec/{permute_cols.c => permute_inds.c} (77%) diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index 6229e34cf3..9df32c050a 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -34,11 +34,11 @@ Types and basic access ``gr_sparse_vec_struct``, permitting a ``gr_sparse_vec_t`` to be passed by reference. -.. function:: int gr_sparse_vec_init(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) +.. function:: void gr_sparse_vec_init(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) Initializes *vec* to a vector of length *len* with no nonzeros. -.. function:: int gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) +.. function:: void gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) Clears the vector *vec* @@ -136,11 +136,11 @@ Getting, setting and conversion density is larger than ``1/sqrt(len)``, the true density of the returned vector is likely to be lower than *density*. -.. function:: int gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx) Convert the dense vector *src* of length *len* to the sparse vector *vec*. -.. function:: int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) +.. function:: int gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) Convert the sparse vector *src* into a dense vector *vec*, which must have sufficient space (i.e. ``vec->length``). @@ -175,12 +175,12 @@ Output .. function:: int gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) - Write the nonzeros of *vec* to the stream *out*. See ``gr_sparse_vec_to_dense`` + Write the nonzeros of *vec* to the stream *out*. See ``gr_vec_set_sparse_vec`` if it is desired to print out the entire vector, zeros and all. .. function:: int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx) - Print the nonzeros of *vec* to ``stdout``. See ``gr_sparse_vec_to_dense`` + Print the nonzeros of *vec* to ``stdout``. See ``gr_vec_set_sparse_vec`` if it is desired to print out the entire vector, zeros and all. diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index ca3f1dfdd0..aded272244 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -38,22 +38,20 @@ gr_sparse_vec_struct; typedef gr_sparse_vec_struct gr_sparse_vec_t[1]; -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +GR_SPARSE_VEC_INLINE void gr_sparse_vec_init(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) { memset(vec, 0, sizeof(gr_sparse_vec_t)); vec->length = len; - return GR_SUCCESS; } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +GR_SPARSE_VEC_INLINE void gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) { _gr_vec_clear(vec->entries, vec->alloc, ctx); flint_free(vec->cols); flint_free(vec->entries); memset(vec, 0, sizeof(gr_sparse_vec_t)); - return GR_SUCCESS; } #define GR_SPARSE_VEC_COL(vec, i) (vec)->cols[i] @@ -73,9 +71,18 @@ GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) { return WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); +GR_SPARSE_VEC_INLINE void gr_sparse_vec_swap(gr_sparse_vec_t res, gr_sparse_vec_t src, gr_ctx_t ctx) +{ + FLINT_SWAP(slong, res->alloc, src->alloc); + FLINT_SWAP(gr_ptr, res->entries, src->entries); + FLINT_SWAP(slong *, res->cols, src->cols); + FLINT_SWAP(slong, res->length, src->length); + FLINT_SWAP(slong, res->nnz, src->nnz); + +} GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; return GR_SUCCESS; } -WARN_UNUSED_RESULT int gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); diff --git a/src/gr_sparse_vec/count_unique_cols.c b/src/gr_sparse_vec/count_unique_inds.c similarity index 69% rename from src/gr_sparse_vec/count_unique_cols.c rename to src/gr_sparse_vec/count_unique_inds.c index aa354112e0..c59d9cfc6f 100644 --- a/src/gr_sparse_vec/count_unique_cols.c +++ b/src/gr_sparse_vec/count_unique_inds.c @@ -1,15 +1,15 @@ #include "gr_sparse_vec.h" slong -_gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulong *cols1, slong nnz1) +_gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulong *inds1, slong nnz1) { slong ind0 = 0; slong ind1 = 0; slong count = 0; while (ind0 < nnz0 && ind1 < nnz1) { - slong col0 = cols0[ind0]; - slong col1 = cols1[ind1]; + slong col0 = inds0[ind0]; + slong col1 = inds1[ind1]; if (col0 <= col1) ind0++; if (col0 >= col1) @@ -21,4 +21,4 @@ _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulong *co else if (ind1 < nnz1) count += (nnz1 - ind1); return count; -} \ No newline at end of file +} diff --git a/src/gr_sparse_vec/equal.c b/src/gr_sparse_vec/equal.c index e02d131034..af4988ddcc 100644 --- a/src/gr_sparse_vec/equal.c +++ b/src/gr_sparse_vec/equal.c @@ -12,4 +12,4 @@ gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_c if (T_TRUE != gr_equal(GR_ENTRY(vec1->entries, i, sz), GR_ENTRY(vec2->entries, i, sz), ctx)) return T_FALSE; return T_TRUE; -} \ No newline at end of file +} diff --git a/src/gr_sparse_vec/find_entry.c b/src/gr_sparse_vec/find_entry.c index fa75edc413..03451147e5 100644 --- a/src/gr_sparse_vec/find_entry.c +++ b/src/gr_sparse_vec/find_entry.c @@ -15,13 +15,12 @@ gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ct { slong i; slong sz = ctx->sizeof_elem; - slong nnz = vec->nnz; ulong* bs = NULL; if (col < 0 || col >= vec->length) return GR_DOMAIN; - bs = bsearch(&col, vec->cols, vec->nnz, sizeof(slong), gr_sparse_vec_ulong_cmp); + bs = bsearch(&col, vec->inds, vec->nnz, sizeof(slong), gr_sparse_vec_ulong_cmp); if (bs == NULL) return gr_zero(res, ctx); - i = (bs - vec->cols); + i = (bs - vec->inds); return gr_set(res, GR_ENTRY(vec->entries, i, sz), ctx); } diff --git a/src/gr_sparse_vec/fit_nnz.c b/src/gr_sparse_vec/fit_nnz.c index 5c29167444..52b8f89728 100644 --- a/src/gr_sparse_vec/fit_nnz.c +++ b/src/gr_sparse_vec/fit_nnz.c @@ -15,7 +15,7 @@ gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) new_alloc = 2 * alloc; if (new_alloc > vec->length) new_alloc = vec->length; - vec->cols = flint_realloc(vec->cols, new_alloc * sizeof(ulong)); + vec->inds = flint_realloc(vec->inds, new_alloc * sizeof(ulong)); vec->entries = flint_realloc(vec->entries, new_alloc * sz); _gr_vec_init(GR_ENTRY(vec->entries, alloc, sz), new_alloc - alloc, ctx); vec->alloc = new_alloc; diff --git a/src/gr_sparse_vec/from_dense.c b/src/gr_sparse_vec/from_dense.c index 389413e017..6947e8a296 100644 --- a/src/gr_sparse_vec/from_dense.c +++ b/src/gr_sparse_vec/from_dense.c @@ -1,7 +1,7 @@ #include "gr_sparse_vec.h" int -gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx) +gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx) { slong nnz,i,sz,status; sz = ctx->sizeof_elem; @@ -18,7 +18,7 @@ gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t { if (T_FALSE == gr_is_zero(GR_ENTRY(src, i, sz), ctx)) { - vec->cols[nnz] = i; + vec->inds[nnz] = i; status |= gr_set(GR_ENTRY(vec->entries, nnz, sz), GR_ENTRY(src, i, sz), ctx); nnz++; } @@ -26,4 +26,4 @@ gr_sparse_vec_from_dense(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t vec->length = len; vec->nnz = nnz; return status; -} \ No newline at end of file +} diff --git a/src/gr_sparse_vec/permute_cols.c b/src/gr_sparse_vec/permute_inds.c similarity index 77% rename from src/gr_sparse_vec/permute_cols.c rename to src/gr_sparse_vec/permute_inds.c index 40477e27b8..6cf9ea7136 100644 --- a/src/gr_sparse_vec/permute_cols.c +++ b/src/gr_sparse_vec/permute_inds.c @@ -16,7 +16,7 @@ static int gr_sparse_vec_slong_sort(const void* a, const void* b) } int -gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) +gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) { slong i,sz,nnz; int status = GR_SUCCESS; @@ -24,11 +24,11 @@ gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong if (vec == src) { gr_sparse_vec_t temp; - GR_MUST_SUCCEED(gr_sparse_vec_init(temp, src->length, ctx)); + gr_sparse_vec_init(temp, src->length, ctx); GR_MUST_SUCCEED(gr_sparse_vec_set(temp, src, ctx)); - status |= gr_sparse_vec_permute_cols(temp, src, p, ctx); + status |= gr_sparse_vec_permute_inds(temp, src, p, ctx); status |= gr_sparse_vec_set(vec, temp, ctx); - status |= gr_sparse_vec_clear(temp, ctx); + gr_sparse_vec_clear(temp, ctx); return status; } sz = ctx->sizeof_elem; @@ -36,15 +36,15 @@ gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong si = flint_malloc(nnz * sizeof(gr_sparse_vec_slong_sorter_t)); for (i = 0; i < nnz; i++) { - si[i].col = p[vec->cols[i]]; + si[i].col = p[vec->inds[i]]; si[i].i = i; } qsort(si, nnz, sizeof(gr_sparse_vec_slong_sorter_t), gr_sparse_vec_slong_sort); for (i = 0; i < nnz; i++) { - vec->cols[i] = si[i].col; + vec->inds[i] = si[i].col; status |= gr_set(GR_ENTRY(vec->entries, i, sz), GR_ENTRY(src->entries, si[i].i, sz), ctx); } flint_free(si); return status; -} \ No newline at end of file +} diff --git a/src/gr_sparse_vec/randtest.c b/src/gr_sparse_vec/randtest.c index 28a40a0b97..c791604012 100644 --- a/src/gr_sparse_vec/randtest.c +++ b/src/gr_sparse_vec/randtest.c @@ -20,26 +20,26 @@ gr_sparse_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_ran /* this is not efficient and won't get the density right, but this isn't important for this function */ if (nnz > vec->alloc) { - vec->cols = flint_realloc(vec->cols, nnz*sizeof(slong)); + vec->inds = flint_realloc(vec->inds, nnz*sizeof(slong)); } for (i = 0; i < nnz; i++) { - vec->cols[i] = n_randint(state, len); + vec->inds[i] = n_randint(state, len); } - qsort(vec->cols, nnz, sizeof(slong), int_sorter); + qsort(vec->inds, nnz, sizeof(slong), int_sorter); /* Contract the col list to remove duplicates */ j = 0; for (i = 0; i < nnz; i++) { - if (i == 0 || vec->cols[j-1] != vec->cols[i]) + if (i == 0 || vec->inds[j-1] != vec->inds[i]) { - vec->cols[j] = vec->cols[i]; + vec->inds[j] = vec->inds[i]; j++; } } nnz = j; /* The actual number of distinct nnz */ - /* Make alloc exactly the new nnz to get cols and entries back in sync */ - vec->cols = flint_realloc(vec->cols, nnz*sizeof(slong)); + /* Make alloc exactly the new nnz to get inds and entries back in sync */ + vec->inds = flint_realloc(vec->inds, nnz*sizeof(slong)); if (vec->alloc > nnz) { _gr_vec_clear(GR_ENTRY(vec->entries, nnz, sz), vec->alloc - nnz, ctx); diff --git a/src/gr_sparse_vec/set.c b/src/gr_sparse_vec/set.c index af33d8db9a..43ffe28f18 100644 --- a/src/gr_sparse_vec/set.c +++ b/src/gr_sparse_vec/set.c @@ -8,11 +8,11 @@ gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { slong nnz = src->nnz; gr_sparse_vec_fit_nnz(res, nnz, ctx); - memcpy(res->cols, src->cols, nnz*sizeof(slong)); + memcpy(res->inds, src->inds, nnz*sizeof(slong)); status = _gr_vec_set(res->entries, src->entries, nnz, ctx); res->nnz = nnz; res->alloc = nnz; res->length = src->length; } return status; -} \ No newline at end of file +} diff --git a/src/gr_sparse_vec/set_entry.c b/src/gr_sparse_vec/set_entry.c index 2773d52de5..039fcb4ebe 100644 --- a/src/gr_sparse_vec/set_entry.c +++ b/src/gr_sparse_vec/set_entry.c @@ -17,10 +17,10 @@ gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_ ulong* bs = NULL; if (col < 0 || col >= vec->length) return GR_DOMAIN; - bs = bsearch(&col, vec->cols, vec->nnz, sizeof(slong), gr_sparse_vec_ulong_cmp); + bs = bsearch(&col, vec->inds, vec->nnz, sizeof(slong), gr_sparse_vec_ulong_cmp); if (bs != NULL) { - i = (bs - vec->cols); + i = (bs - vec->inds); return gr_set(GR_ENTRY(vec->entries, i, sz), entry, ctx); } else @@ -29,7 +29,7 @@ gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_ gr_sparse_vec_fit_nnz(vec, vec->nnz+1, ctx); for (i = 0; i < nnz; i++) { - if (vec->cols[i] < col) + if (vec->inds[i] < col) break; } /* Now if i < nnz, then we should put the entry right *after* it */ @@ -39,14 +39,14 @@ gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_ if (i < nnz) { /* If necessary, move everything up to make space */ - memmove(vec->cols + i + 1, vec->cols + i, (vec->nnz - i)*sizeof(slong)); + memmove(vec->inds + i + 1, vec->inds + i, (vec->nnz - i)*sizeof(slong)); for (j = vec->nnz; j > i; j--) { gr_swap(GR_ENTRY(vec->entries, j-1, sz), GR_ENTRY(vec->entries, j, sz), ctx); } } /* Now there's an available spot in index i */ - vec->cols[i] = col; + vec->inds[i] = col; vec->nnz++; return gr_set(GR_ENTRY(vec->entries, i, sz), entry, ctx); } diff --git a/src/gr_sparse_vec/set_from_entries.c b/src/gr_sparse_vec/set_from_entries.c index b50468ec07..cea072c2c7 100644 --- a/src/gr_sparse_vec/set_from_entries.c +++ b/src/gr_sparse_vec/set_from_entries.c @@ -18,7 +18,7 @@ static int gr_sparse_vec_slong_cmp(const void* a, const void* b) int -gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) +gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) { slong i,j,sz,new_nnz; int status; @@ -26,7 +26,7 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entr si = flint_malloc(nnz * sizeof(gr_sparse_vec_slong_sorter_t)); for (i = 0; i < nnz; i++) { - si[i].col = cols[i]; + si[i].col = inds[i]; si[i].i = i; } qsort(si, nnz, sizeof(gr_sparse_vec_slong_sorter_t), gr_sparse_vec_slong_cmp); @@ -61,12 +61,12 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entr return GR_UNABLE; /* This is consistency check */ } } - vec->cols[j] = si[i].col; + vec->inds[j] = si[i].col; status |= gr_set(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, si[i].i, sz), ctx); } else { - if (vec->cols[j] != cols[si[i].i]) /* Consistency check that we're accumulating into the correct column */ + if (vec->inds[j] != inds[si[i].i]) /* Consistency check that we're accumulating into the correct column */ status |= GR_UNABLE; status |= gr_add(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, si[i].i, sz), ctx); } @@ -78,7 +78,7 @@ gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entr } int -gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) +gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) { slong i,j,sz; int status; @@ -90,7 +90,7 @@ gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorte { if (T_FALSE == gr_is_zero(GR_ENTRY(entries, i, sz), ctx)) { - vec->cols[j] = sorted_deduped_cols[i]; + vec->inds[j] = sorted_deduped_inds[i]; status |= gr_set(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, i, sz), ctx); j++; } diff --git a/src/gr_sparse_vec/set_length.c b/src/gr_sparse_vec/set_length.c index 969bb8b832..448fb63030 100644 --- a/src/gr_sparse_vec/set_length.c +++ b/src/gr_sparse_vec/set_length.c @@ -7,7 +7,7 @@ gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) /* Scan backward through the nonzeros to discard the ones off the end */ /* Note that we don't actually free anything; we just mark the nonzeros as unused */ slong i=vec->nnz-1; - while (i>=0 && vec->cols[i] >= len) + while (i>=0 && vec->inds[i] >= len) { i--; } diff --git a/src/gr_sparse_vec/shrink_to_nnz.c b/src/gr_sparse_vec/shrink_to_nnz.c index 6f8b875aaf..d90955629f 100644 --- a/src/gr_sparse_vec/shrink_to_nnz.c +++ b/src/gr_sparse_vec/shrink_to_nnz.c @@ -7,9 +7,9 @@ gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx) slong sz = ctx->sizeof_elem; if (vec->alloc > nnz) { - vec->cols = flint_realloc(vec->cols, nnz * sizeof(ulong)); + vec->inds = flint_realloc(vec->inds, nnz * sizeof(ulong)); _gr_vec_clear(GR_ENTRY(vec->entries, nnz, sz), vec->alloc - nnz, ctx); vec->entries = flint_realloc(vec->entries, nnz * sz); vec->alloc = nnz; } -} \ No newline at end of file +} diff --git a/src/gr_sparse_vec/slice.c b/src/gr_sparse_vec/slice.c index c07e19c57c..ed885ade3e 100644 --- a/src/gr_sparse_vec/slice.c +++ b/src/gr_sparse_vec/slice.c @@ -12,7 +12,7 @@ gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_st for (i = 0; i < nnz; i++) { /* If we find a valid column, start the interval */ - if (src->cols[i] >= col_start) + if (src->inds[i] >= col_start) { i_start = i; break; @@ -21,7 +21,7 @@ gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_st for (; i <= nnz; i++) { /* Note we will always do this; the first time we see a column outside the interval, or we run off the end, stop it */ - if (i == nnz || src->cols[i] >= col_end) + if (i == nnz || src->inds[i] >= col_end) { i_end = i; break; @@ -33,9 +33,9 @@ gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_st gr_sparse_vec_fit_nnz(res, new_nnz, ctx); for (i = i_start; i < i_end; i++) { - res->cols[i-i_start] = res->cols[i] - col_start; + res->inds[i-i_start] = res->inds[i] - col_start; status |= gr_set(GR_ENTRY(res->entries, i-i_start, sz), GR_ENTRY(src->entries, i, sz), ctx); } res->nnz = new_nnz; return status; -} \ No newline at end of file +} diff --git a/src/gr_sparse_vec/test/t-conversion.c b/src/gr_sparse_vec/test/t-conversion.c index bfc7c3fef2..2ffa8a551c 100644 --- a/src/gr_sparse_vec/test/t-conversion.c +++ b/src/gr_sparse_vec/test/t-conversion.c @@ -17,17 +17,17 @@ test_conversion(flint_rand_t state, gr_ctx_t ctx) gr_vec_t dvec, dvec2; gr_vec_init(dvec, N, ctx); gr_vec_init(dvec2, N, ctx); - status |= gr_sparse_vec_init(vec, N, ctx); + gr_sparse_vec_init(vec, N, ctx); for (i = 0; i < n_tests; i++) { status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); - status |= gr_sparse_vec_from_dense(vec, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); - status |= gr_sparse_vec_to_dense(GR_VEC_ENTRY(dvec2, 0, sz), vec, ctx); + status |= gr_sparse_vec_set_vec(vec, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); + status |= gr_vec_set_sparse_vec(GR_VEC_ENTRY(dvec2, 0, sz), vec, ctx); if (T_TRUE != _gr_vec_equal(GR_VEC_ENTRY(dvec, 0, sz), GR_VEC_ENTRY(dvec2, 0, sz), N, ctx)) return GR_TEST_FAIL; } - status |= gr_sparse_vec_clear(vec, ctx); + gr_sparse_vec_clear(vec, ctx); gr_vec_clear(dvec, ctx); gr_vec_clear(dvec2, ctx); return status; diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c index e437adfb96..2503a232bf 100644 --- a/src/gr_sparse_vec/test/t-creation.c +++ b/src/gr_sparse_vec/test/t-creation.c @@ -8,8 +8,8 @@ test_init(gr_ctx_t ctx) { gr_sparse_vec_t vec; int status = GR_SUCCESS; - status |= gr_sparse_vec_init(vec, 5, ctx); - status |= gr_sparse_vec_clear(vec, ctx); + gr_sparse_vec_init(vec, 5, ctx); + gr_sparse_vec_clear(vec, ctx); return status; } @@ -25,28 +25,28 @@ test_init_from_entries_sorted(flint_rand_t state, gr_ctx_t ctx) int status = GR_SUCCESS; slong sz = ctx->sizeof_elem; slong N = 5; - ulong cols[5] = {0, 2, 4, 6, 8}; + ulong inds[5] = {0, 2, 4, 6, 8}; gr_vec_init(dvec, N, ctx); status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); - status |= gr_sparse_vec_init(vec, 2*N, ctx); - status |= gr_sparse_vec_set_from_entries_sorted_deduped(vec, cols, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); + gr_sparse_vec_init(vec, 2*N, ctx); + status |= gr_sparse_vec_set_from_entries_sorted_deduped(vec, inds, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); for (i = 0; i < 2*N; i++) { status |= gr_sparse_vec_find_entry(temp, vec, i, ctx); - if ((i & 1) == 1 && (T_TRUE != gr_is_zero(temp, ctx))) /* Odd cols should all be zero */ + if ((i & 1) == 1 && (T_TRUE != gr_is_zero(temp, ctx))) /* Odd inds should all be zero */ return GR_TEST_FAIL; if ((i & 1) == 0 && (T_TRUE != gr_equal(temp, GR_VEC_ENTRY(dvec, i>>1, sz), ctx))) return GR_TEST_FAIL; } GR_TMP_CLEAR(temp, ctx); gr_vec_clear(dvec, ctx); - status |= gr_sparse_vec_clear(vec, ctx); + gr_sparse_vec_clear(vec, ctx); return status; } int -test_init_from_entries_unsorted_internal(ulong *cols, gr_srcptr entries, slong len, slong n_entries, gr_ctx_t ctx) +test_init_from_entries_unsorted_internal(ulong *inds, gr_srcptr entries, slong len, slong n_entries, gr_ctx_t ctx) { /* Yes, this is quadratic time just to be careful */ int status = GR_SUCCESS; @@ -55,8 +55,8 @@ test_init_from_entries_unsorted_internal(ulong *cols, gr_srcptr entries, slong l gr_sparse_vec_t vec; gr_ptr temp, temp2; GR_TMP_INIT2(temp, temp2, ctx); - status |= gr_sparse_vec_init(vec, len, ctx); - status |= gr_sparse_vec_set_from_entries(vec, cols, entries, n_entries, ctx); + gr_sparse_vec_init(vec, len, ctx); + status |= gr_sparse_vec_set_from_entries(vec, inds, entries, n_entries, ctx); if (status != GR_SUCCESS) return GR_TEST_FAIL; /* Scan through every column in the sparse vector */ @@ -66,7 +66,7 @@ test_init_from_entries_unsorted_internal(ulong *cols, gr_srcptr entries, slong l status |= gr_zero(temp, ctx); for (j = 0; j < n_entries; j++) { - if (cols[j] == i) + if (inds[j] == i) status |= gr_add(temp, temp, GR_ENTRY(entries, j, sz), ctx); } /* Check it */ @@ -76,7 +76,7 @@ test_init_from_entries_unsorted_internal(ulong *cols, gr_srcptr entries, slong l } GR_TMP_CLEAR(temp, ctx); GR_TMP_CLEAR(temp2, ctx); - status |= gr_sparse_vec_clear(vec, ctx); + gr_sparse_vec_clear(vec, ctx); return status; } @@ -89,18 +89,18 @@ test_init_from_entries_unsorted(flint_rand_t state, gr_ctx_t ctx) int status = GR_SUCCESS; slong sz = ctx->sizeof_elem; slong N = 5; - ulong cols[5] = {8, 4, 3, 8, 1}; + ulong inds[5] = {8, 4, 3, 8, 1}; gr_vec_t dvec; gr_vec_init(dvec, N, ctx); /* First test against random entries */ status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); - status |= test_init_from_entries_unsorted_internal(cols, GR_VEC_ENTRY(dvec, 0, sz), 2*N, N, ctx); + status |= test_init_from_entries_unsorted_internal(inds, GR_VEC_ENTRY(dvec, 0, sz), 2*N, N, ctx); /* Next test against some adversarial entries */ slong entries_si[5] = {5, 0, 2, -5, 1}; for (i = 0; i < N; i++) status |= gr_set_si(GR_VEC_ENTRY(dvec, i, sz), entries_si[i], ctx); - status |= test_init_from_entries_unsorted_internal(cols, GR_VEC_ENTRY(dvec, 0, sz), 2*N, N, ctx); + status |= test_init_from_entries_unsorted_internal(inds, GR_VEC_ENTRY(dvec, 0, sz), 2*N, N, ctx); gr_vec_clear(dvec, ctx); return status; diff --git a/src/gr_sparse_vec/to_dense.c b/src/gr_sparse_vec/to_dense.c index cc97007dbf..233a1d2006 100644 --- a/src/gr_sparse_vec/to_dense.c +++ b/src/gr_sparse_vec/to_dense.c @@ -1,7 +1,7 @@ #include "gr_sparse_vec.h" int -gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) +gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) { slong i,j,sz,nnz,status,len; status = GR_SUCCESS; @@ -12,7 +12,7 @@ gr_sparse_vec_to_dense(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) for (i = 0; i < len; i++) { /* if i is the column of the next nonzero in src, copy it in */ - if (j < nnz && i == src->cols[j]) + if (j < nnz && i == src->inds[j]) { status |= gr_set(GR_ENTRY(vec, i, sz), GR_ENTRY(src->entries, j, sz), ctx); j++; diff --git a/src/gr_sparse_vec/write.c b/src/gr_sparse_vec/write.c index 66b9cc0162..17c484c2e6 100644 --- a/src/gr_sparse_vec/write.c +++ b/src/gr_sparse_vec/write.c @@ -11,7 +11,7 @@ gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) for (i = 0; i < nnz; i++) { gr_stream_write(out, "("); - gr_stream_write_si(out, vec->cols[i]); + gr_stream_write_si(out, vec->inds[i]); gr_stream_write(out, ": "); status |= gr_write(out, GR_ENTRY(vec->entries, i, sz), ctx); gr_stream_write(out, ")"); From 3f53d010a5b7f4cb444e154cdcc57756002fedfc Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 17 Mar 2024 16:36:00 -0700 Subject: [PATCH 23/59] Beginning of gr sparse matrix --- CMakeLists.txt | 2 +- Makefile.in | 3 +- src/gr_sparse_mat.h | 479 ++++++++++++++++++++++++++++++++ src/gr_sparse_mat/fit_nnz.c | 16 ++ src/gr_sparse_mat/invert_rows.c | 24 ++ src/gr_sparse_mat/set.c | 87 ++++++ src/gr_sparse_mat/swap_rows.c | 35 +++ src/gr_sparse_mat/to_dense.c | 51 ++++ 8 files changed, 695 insertions(+), 2 deletions(-) create mode 100644 src/gr_sparse_mat.h create mode 100644 src/gr_sparse_mat/fit_nnz.c create mode 100644 src/gr_sparse_mat/invert_rows.c create mode 100644 src/gr_sparse_mat/set.c create mode 100644 src/gr_sparse_mat/swap_rows.c create mode 100644 src/gr_sparse_mat/to_dense.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c9d89feca2..c2cdcd4734 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,7 +139,7 @@ set(_BUILD_DIRS dirichlet bernoulli hypgeom gr gr_generic gr_vec gr_mat - gr_poly gr_mpoly gr_special gr_sparse_vec + gr_poly gr_mpoly gr_sparse_vec gr_sparse_mat gr_special calcium fmpz_mpoly_q diff --git a/Makefile.in b/Makefile.in index fa8b2ab4e4..7ac77f13f1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -181,7 +181,8 @@ HEADER_DIRS := \ dirichlet bernoulli hypgeom \ \ gr gr_generic gr_vec gr_mat \ - gr_poly gr_mpoly gr_sparse_vec gr_special \ + gr_poly gr_mpoly gr_sparse_vec gr_sparse_mat \ + gr_special \ \ calcium \ fmpz_mpoly_q \ diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h new file mode 100644 index 0000000000..6a5c9073f3 --- /dev/null +++ b/src/gr_sparse_mat.h @@ -0,0 +1,479 @@ +/* + Copyright (C) 2023 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 . +*/ + +#ifndef GR_SPARSE_MAT_H +#define GR_SPARSE_MAT_H + +#ifdef GR_SPARSE_MAT_INLINES_C +#define GR_SPARSE_MAT_INLINE +#else +#define GR_SPARSE_MAT_INLINE static __inline__ +#endif + +#include "gr.h" +#include "gr_mat.h" +#include "gr_sparse_vec.h" +#include "gr_poly.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct +{ + slong r; + slong c; + slong nnz; + slong alloc; + ulong * rows; + ulong * cols; + gr_ptr entries; +} +gr_csr_mat_struct; + +typedef struct +{ + slong r; + slong c; + slong nnz; + gr_sparse_vec_t * rows; +} +gr_lil_mat_struct; + + +typedef gr_csr_mat_struct gr_csr_mat_t[1]; + +typedef gr_lil_mat_struct gr_lil_mat_t[1]; + +#define gr_sparse_mat_nrows(mat, ctx) ((mat)->r) +#define gr_sparse_mat_ncols(mat, ctx) ((mat)->c) +#define gr_sparse_mat_nnz(mat, ctx) ((mat)->nnz) + +#define GR_CSR_MAT_ENTRY(mat,i,j,sz) GR_ENTRY((mat)->entries, (mat)->rows[i] + j, sz) +#define GR_LIL_MAT_ENTRY(mat,i,j,sz) GR_ENTRY((mat)->rows[i]->entries, j, sz) + +GR_SPARSE_MAT_INLINE gr_ptr gr_csr_mat_value_ptr(gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) +{ + return GR_CSR_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); +} + +GR_SPARSE_MAT_INLINE gr_srcptr gr_csr_mat_value_srcptr(const gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) +{ + return GR_CSR_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); +} + +GR_SPARSE_MAT_INLINE gr_ptr gr_lil_mat_value_ptr(gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) +{ + return GR_LIL_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); +} + +GR_SPARSE_MAT_INLINE gr_srcptr gr_lil_mat_value_srcptr(const gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) +{ + return GR_LIL_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); +} + +/* Generics */ +/* +typedef int ((*gr_method_mat_unary_op_get_scalar)(gr_ptr, const gr_sparse_mat_t, gr_ctx_ptr)); +typedef int ((*gr_method_mat_unary_op)(gr_sparse_mat_t, const gr_sparse_mat_t, gr_ctx_ptr)); +typedef int ((*gr_method_mat_binary_op)(gr_sparse_mat_t, const gr_sparse_mat_t, const gr_sparse_mat_t, gr_ctx_ptr)); +typedef int ((*gr_method_mat_pivot_op)(slong *, gr_sparse_mat_t, slong, slong, slong, gr_ctx_ptr)); +typedef int ((*gr_method_mat_diagonalization_op)(gr_vec_t, gr_sparse_mat_t, gr_sparse_mat_t, const gr_sparse_mat_t, int, gr_ctx_ptr)); + +#define GR_SPARSE_MAT_UNARY_OP_GET_SCALAR(ctx, NAME) (((gr_method_mat_unary_op_get_scalar *) ctx->methods)[GR_METHOD_ ## NAME]) +#define GR_SPARSE_MAT_UNARY_OP(ctx, NAME) (((gr_method_mat_unary_op *) ctx->methods)[GR_METHOD_ ## NAME]) +#define GR_SPARSE_MAT_BINARY_OP(ctx, NAME) (((gr_method_mat_binary_op *) ctx->methods)[GR_METHOD_ ## NAME]) +#define GR_SPARSE_MAT_PIVOT_OP(ctx, NAME) (((gr_method_mat_pivot_op *) ctx->methods)[GR_METHOD_ ## NAME]) +#define GR_SPARSE_MAT_DIAGONALIZATION_OP(ctx, NAME) (((gr_method_mat_diagonalization_op *) ctx->methods)[GR_METHOD_ ## NAME]) +*/ + +GR_SPARSE_MAT_INLINE void +gr_csr_mat_init(gr_csr_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) { + memset(mat, 0, sizeof(gr_csr_mat_t)); + mat->r = rows; + mat->c = cols; + mat->nnz = 0; + mat->alloc = 0; + mat->rows = flint_calloc(rows + 1, sizeof(ulong)); +} + +GR_SPARSE_MAT_INLINE void +gr_lil_mat_init(gr_lil_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) { + mat->r = rows; + mat->c = cols; + mat->nnz = 0; + mat->rows = flint_calloc(rows, sizeof(gr_sparse_vec_t)); +} + +void +gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_csr_mat_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_csr_mat_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_mat_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_mat_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx); + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_csr_mat_init_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) { + gr_csr_mat_init(res, mat->r, mat->c, ctx); + return gr_csr_mat_set(res, mat, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_init_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) { + gr_lil_mat_init(res, mat->r, mat->c, ctx); + return gr_lil_mat_set(res, mat, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_csr_mat_init_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +{ + gr_csr_mat_init(res, mat->r, mat->c, ctx); + return gr_csr_mat_set_lil_mat(res, mat, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_init_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + gr_lil_mat_init(res, mat->r, mat->c, ctx); + return gr_lil_mat_set_csr_mat(res, mat, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_mat_init_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + gr_mat_init(res, mat->r, mat->c, ctx); + return gr_mat_set_csr_mat(res, mat, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_mat_init_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +{ + gr_mat_init(res, mat->r, mat->c, ctx); + return gr_mat_set_lil_mat(res, mat, ctx); +} + +GR_SPARSE_MAT_INLINE void +gr_csr_mat_swap(gr_csr_mat_t mat1, gr_csr_mat_t mat2, gr_ctx_t ctx) +{ + FLINT_SWAP(gr_csr_mat_struct, *mat1, *mat2); +} + +GR_SPARSE_MAT_INLINE void +gr_lil_mat_swap(gr_lil_mat_t mat1, gr_lil_mat_t mat2, gr_ctx_t ctx) +{ + FLINT_SWAP(gr_lil_mat_struct, *mat1, *mat2); +} + +GR_SPARSE_MAT_INLINE void +gr_csr_mat_clear(gr_csr_mat_t mat, gr_ctx_t ctx) { + if (mat->alloc != 0) + { + _gr_vec_clear(mat->entries, mat->alloc, ctx); + flint_free(mat->entries); + flint_free(mat->cols); + } + flint_free(mat->rows); + memset(mat, 0, sizeof(gr_csr_mat_t)); +} + +GR_SPARSE_MAT_INLINE void +gr_lil_mat_clear(gr_lil_mat_t mat, gr_ctx_t ctx) { + int row; + + for (row = 0; row < mat->r; ++row) { + gr_sparse_vec_clear(mat->rows[row], ctx); + } + flint_free(mat->rows); + memset(mat, 0, sizeof(gr_lil_mat_t)); +} + + +GR_SPARSE_MAT_INLINE void +_gr_csr_mat_borrow_row(gr_sparse_vec_t res, gr_csr_mat_t mat, slong r, gr_ctx_t ctx) { + ulong offset; + + offset = mat->rows[r]; + res->alloc = 0; + res->nnz = mat->rows[r+1] - offset; + res->cols = mat->cols + offset; + res->entries = GR_ENTRY(mat->entries, offset, ctx->sizeof_elem); +} + +WARN_UNUSED_RESULT int gr_lil_mat_swap_rows(gr_lil_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_invert_rows(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx); + +/* +void gr_sparse_mat_window_init(gr_csr_mat_t window, const gr_csr_mat_t mat, slong r1, slong c1, slong r2, slong c2, gr_ctx_t ctx); + +GR_SPARSE_MAT_INLINE void +gr_sparse_mat_window_clear(gr_csr_mat_t window, gr_ctx_t ctx) +{ + flint_free(window->rows); +} + +WARN_UNUSED_RESULT int gr_lil_mat_concat_horizontal(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_concat_vertical(gr_csr_mat_t res, const gr_csr_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_concat_vertical(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +*/ + +/* +int gr_sparse_mat_write(gr_stream_t out, const gr_csr_mat_t mat, gr_ctx_t ctx); +int gr_sparse_mat_print(const gr_csr_mat_t mat, gr_ctx_t ctx); +*/ + +/* +WARN_UNUSED_RESULT int gr_sparse_mat_randtest(gr_csr_mat_t mat, flint_rand_t state, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_randops(gr_csr_mat_t mat, flint_rand_t state, slong count, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_randpermdiag(int * parity, gr_csr_mat_t mat, flint_rand_t state, gr_ptr diag, slong n, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_randrank(gr_csr_mat_t mat, flint_rand_t state, slong rank, gr_ctx_t ctx); +*/ +/* +#define gr_sparse_mat_is_empty(mat, ctx) (((mat->r == 0) || (mat->c == 0)) ? T_TRUE : T_FALSE) +#define gr_sparse_mat_is_square(mat, ctx) ((mat->r == mat->c) ? T_TRUE : T_FALSE) +#define gr_sparse_mat_is_zero(mat, ctx) ((mat->nnz == 0) ? T_TRUE : T_FALSE); + +truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx); +truth_t gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx); +truth_t gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx); + +truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx); +truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx); +truth_t gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_csr_mat_zero(gr_csr_mat_t res, gr_ctx_t ctx) { + res->nnz = 0; + memset(res->rows, 0, (res->r + 1) * sizeof(ulong)); +} +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_one(gr_csr_mat_t res, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_set_scalar(gr_csr_mat_t res, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_set_ui(gr_csr_mat_t res, ulong v, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_set_si(gr_csr_mat_t res, slong v, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_set_fmpz(gr_csr_mat_t res, const fmpz_t v, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_set_fmpq(gr_csr_mat_t res, const fmpq_t v, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_csr_mat_set_fmpz_csr_mat(gr_csr_mat_t res, const fmpz_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_set_fmpq_csr_mat(gr_csr_mat_t res, const fmpq_csr_mat_t mat, gr_ctx_t ctx); + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_neg(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + int row; + int status; + + if (res->c != mat->c || res->r != mat->r) + { + return GR_DOMAIN; + } + res->nnz = mat->nnz; + for (row = 0; row < res->r; row++) { + status |= gr_sparse_vec_neg(res->rows[i], res->mat[i], ctx); + res->nnz += res->rows[i].nnz; + } + return status; +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_add(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ + int row; + int status; + + if (res->c != mat1->c || res->r != mat1->r || res->c != mat2->c || res->r != mat2->r) + { + return GR_DOMAIN; + } + res->nnz = 0; + for (row = 0; row < res->r; row++) { + status |= gr_sparse_vec_add(res->rows[i], res->mat1[i], res->mat2[i], ctx); + res->nnz += res->rows[i].nnz; + } + return status; +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_sub(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ + int row; + int status; + + if (res->c != mat1->c || res->r != mat1->r || res->c != mat2->c || res->r != mat2->r) + { + return GR_DOMAIN; + } + res->nnz = 0; + for (row = 0; row < res->r; row++) { + status |= gr_sparse_vec_sub(res->rows[i], res->mat1[i], res->mat2[i], ctx); + res->nnz += res->rows[i].nnz; + } + return status; +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_csr_mat_mul_vec(gr_vec_t v, const gr_csr_mat_t A, const gr_vec_t u, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_csr_mat_mul_mat_transpose(gr_mat_t Ct, const gr_csr_mat_t A, const gr_mat_t Bt, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_mat_t A, const gr_mat_t Bt, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ctx_t ctx); + + +WARN_UNUSED_RESULT int gr_sparse_mat_lu(slong * rank, slong * P, gr_csr_mat_t LU, const gr_csr_mat_t A, int rank_check, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_fflu(slong * res_rank, slong * P, gr_csr_mat_t LU, gr_ptr den, const gr_csr_mat_t A, int rank_check, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_fflu(gr_csr_mat_t X, const gr_csr_mat_t A, const gr_csr_mat_t B, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_lu(gr_csr_mat_t X, const gr_csr_mat_t A, const gr_csr_mat_t B, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve(gr_csr_mat_t X, const gr_csr_mat_t A, const gr_csr_mat_t B, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_fflu_precomp(gr_csr_mat_t X, const slong * perm, const gr_csr_mat_t A, const gr_csr_mat_t B, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_lu_precomp(gr_csr_mat_t X, const slong * perm, const gr_csr_mat_t A, const gr_csr_mat_t B, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_den_fflu(gr_csr_mat_t X, gr_ptr den, const gr_csr_mat_t A, const gr_csr_mat_t B, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_den(gr_csr_mat_t X, gr_ptr den, const gr_csr_mat_t A, const gr_csr_mat_t B, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_solve_field(gr_csr_mat_t X, const gr_csr_mat_t A, const gr_csr_mat_t B, gr_ctx_t ctx); +*/ +/* +WARN_UNUSED_RESULT int gr_sparse_mat_det_berkowitz(gr_ptr res, const gr_sparse_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_det_fflu(gr_ptr res, const gr_sparse_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_det_lu(gr_ptr res, const gr_sparse_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_det_cofactor(gr_ptr res, const gr_sparse_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_det_generic_field(gr_ptr res, const gr_sparse_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_det_generic_integral_domain(gr_ptr res, const gr_sparse_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_det_generic(gr_ptr res, const gr_sparse_mat_t A, gr_ctx_t ctx); +*/ +/* +WARN_UNUSED_RESULT int gr_sparse_mat_det(gr_ptr res, const gr_csr_mat_t A, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_inv(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_adjugate_charpoly(gr_csr_mat_t adj, gr_ptr det, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_adjugate_cofactor(gr_csr_mat_t adj, gr_ptr det, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_adjugate(gr_csr_mat_t adj, gr_ptr det, const gr_csr_mat_t A, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_rank_lu(slong * rank, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_rank_fflu(slong * rank, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_rank(slong * rank, const gr_csr_mat_t A, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_rref_lu(slong * res_rank, gr_csr_mat_t R, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_rref_fflu(slong * res_rank, gr_csr_mat_t R, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_rref(slong * res_rank, gr_csr_mat_t R, const gr_csr_mat_t A, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_rref_den_fflu(slong * res_rank, gr_csr_mat_t R, gr_ptr den, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_rref_den(slong * res_rank, gr_csr_mat_t R, gr_ptr den, const gr_csr_mat_t A, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_nullspace(gr_csr_mat_t X, const gr_csr_mat_t A, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_ones(gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_pascal(gr_csr_mat_t mat, int triangular, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_stirling(gr_csr_mat_t mat, int kind, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_hilbert(gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_hadamard(gr_csr_mat_t mat, gr_ctx_t ctx); +*/ +/* todo: dft, dct */ +/* +WARN_UNUSED_RESULT int gr_sparse_mat_transpose(gr_csr_mat_t B, const gr_csr_mat_t A, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_tril_classical(gr_csr_mat_t X, const gr_csr_mat_t L, const gr_csr_mat_t B, int unit, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_tril_recursive(gr_csr_mat_t X, const gr_csr_mat_t L, const gr_csr_mat_t B, int unit, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_tril(gr_csr_mat_t X, const gr_csr_mat_t L, const gr_csr_mat_t B, int unit, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_triu_classical(gr_csr_mat_t X, const gr_csr_mat_t U, const gr_csr_mat_t B, int unit, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_triu_recursive(gr_csr_mat_t X, const gr_csr_mat_t U, const gr_csr_mat_t B, int unit, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_nonsingular_solve_triu(gr_csr_mat_t X, const gr_csr_mat_t U, const gr_csr_mat_t B, int unit, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_trace(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_sparse_mat_charpoly_berkowitz(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_charpoly_berkowitz(gr_poly_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_sparse_mat_charpoly_danilevsky_inplace(gr_ptr res, gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int _gr_sparse_mat_charpoly_danilevsky(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_charpoly_danilevsky(gr_poly_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_sparse_mat_charpoly_faddeev(gr_ptr res, gr_csr_mat_t adj, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_charpoly_faddeev(gr_poly_t res, gr_csr_mat_t adj, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_sparse_mat_charpoly_faddeev_bsgs(gr_ptr res, gr_csr_mat_t adj, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_charpoly_faddeev_bsgs(gr_poly_t res, gr_csr_mat_t adj, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_sparse_mat_charpoly_from_hessenberg(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_charpoly_from_hessenberg(gr_poly_t cp, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_sparse_mat_charpoly_gauss(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_charpoly_gauss(gr_poly_t cp, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_sparse_mat_charpoly_householder(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_charpoly_householder(gr_poly_t cp, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int _gr_sparse_mat_charpoly(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_charpoly(gr_poly_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_hessenberg(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_hessenberg_gauss(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_hessenberg_householder(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); +truth_t gr_sparse_mat_is_hessenberg(const gr_csr_mat_t mat, gr_ctx_t ctx); + +int gr_sparse_mat_reduce_row(slong * column, gr_csr_mat_t A, slong * P, slong * L, slong m, gr_ctx_t ctx); +int gr_sparse_mat_apply_row_similarity(gr_csr_mat_t A, slong r, gr_ptr d, gr_ctx_t ctx); +int gr_sparse_mat_minpoly_field(gr_poly_t p, const gr_csr_mat_t X, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_eigenentries(gr_vec_t lambda, gr_vec_t mult, const gr_csr_mat_t mat, int flags, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_eigenentries_other(gr_vec_t lambda, gr_vec_t mult, const gr_csr_mat_t mat, gr_ctx_t mat_ctx, int flags, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_diagonalization_precomp(gr_vec_t D, gr_csr_mat_t L, gr_csr_mat_t R, const gr_csr_mat_t A, const gr_vec_t eigenentries, const gr_vec_t mult, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_diagonalization_generic(gr_vec_t D, gr_csr_mat_t L, gr_csr_mat_t R, const gr_csr_mat_t A, int flags, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_diagonalization(gr_vec_t D, gr_csr_mat_t L, gr_csr_mat_t R, const gr_csr_mat_t A, int flags, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_set_jordan_blocks(gr_csr_mat_t mat, const gr_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_jordan_blocks(gr_vec_t lambda, slong * num_blocks, slong * block_lambda, slong * block_size, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_jordan_transformation(gr_csr_mat_t mat, const gr_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_jordan_form(gr_csr_mat_t J, gr_csr_mat_t P, const gr_csr_mat_t A, gr_ctx_t ctx); + +truth_t gr_sparse_mat_is_scalar(const gr_csr_mat_t mat, gr_ctx_t ctx); +truth_t gr_sparse_mat_is_diagonal(const gr_csr_mat_t mat, gr_ctx_t ctx); +truth_t gr_sparse_mat_is_lower_triangular(const gr_csr_mat_t mat, gr_ctx_t ctx); +truth_t gr_sparse_mat_is_upper_triangular(const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_mul_diag(gr_csr_mat_t C, const gr_csr_mat_t A, const gr_vec_t D, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_diag_mul(gr_csr_mat_t C, const gr_vec_t D, const gr_csr_mat_t A, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_exp_jordan(gr_csr_mat_t res, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_exp(gr_csr_mat_t res, const gr_csr_mat_t A, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_mat_log_jordan(gr_csr_mat_t res, const gr_csr_mat_t A, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_mat_log(gr_csr_mat_t res, const gr_csr_mat_t A, gr_ctx_t ctx); +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gr_sparse_mat/fit_nnz.c b/src/gr_sparse_mat/fit_nnz.c new file mode 100644 index 0000000000..87d26714e1 --- /dev/null +++ b/src/gr_sparse_mat/fit_nnz.c @@ -0,0 +1,16 @@ +#include "gr_sparse_mat.h" + +void +gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx) +{ + slong alloc = mat->alloc; + slong new_alloc = nnz; + if (new_alloc > alloc) + { + slong sz = ctx->sizeof_elem; + mat->cols = flint_realloc(mat->cols, new_alloc * sizeof(ulong)); + mat->entries = flint_realloc(mat->entries, new_alloc * sz); + _gr_vec_init(GR_ENTRY(mat->entries, alloc, sz), new_alloc - alloc, ctx); + mat->alloc = new_alloc; + } +} diff --git a/src/gr_sparse_mat/invert_rows.c b/src/gr_sparse_mat/invert_rows.c new file mode 100644 index 0000000000..574d1b8585 --- /dev/null +++ b/src/gr_sparse_mat/invert_rows.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2022 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 "gr_sparse_mat.h" + +int gr_lil_mat_invert_rows(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong r = gr_sparse_mat_nrows(mat, ctx); + slong i; + + for (i = 0; i < r / 2; i++) + status |= gr_lil_mat_swap_rows(mat, perm, i, r - i - 1, ctx); + + return status; +} diff --git a/src/gr_sparse_mat/set.c b/src/gr_sparse_mat/set.c new file mode 100644 index 0000000000..51fd63318c --- /dev/null +++ b/src/gr_sparse_mat/set.c @@ -0,0 +1,87 @@ +/* + Copyright (C) 2024 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "gr_sparse_mat.h" + +int gr_csr_mat_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) { + int status; + + if (res->r != mat->r || res->c != mat->c) { + return GR_DOMAIN; + } + res->nnz = mat->nnz; + gr_csr_mat_fit_nnz(res, mat->nnz, ctx); + memcpy(res->rows, mat->rows, mat->r * sizeof(ulong)); + memcpy(res->cols, mat->cols, mat->nnz * sizeof(ulong)); + status = _gr_vec_set(res->entries, mat->entries, mat->nnz, ctx); + return status; +} + +int gr_lil_mat_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) { + ulong row; + int success = GR_SUCCESS; + + if (res->r != mat->r || res->c != mat->c) { + return GR_DOMAIN; + } + res->nnz = mat->nnz; + + for (row = 0; row < mat->r; ++row) { + success |= gr_sparse_vec_set(res->rows[row], mat->rows[row], ctx); + } + return success; +} + +int gr_csr_mat_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +{ + ulong row; + int success = GR_SUCCESS; + gr_sparse_vec_struct *mat_row; + + if (res->r != mat->r || res->c != mat->c) + return GR_DOMAIN; + + gr_csr_mat_fit_nnz(res, mat->nnz, ctx); + + res->nnz = 0; + for(row = 0; row < mat->r; row++) { + mat_row = mat->rows[row]; + res->rows[row] = res->nnz; + memcpy(res->cols + res->nnz, mat_row->cols, mat_row->nnz); + success |= _gr_vec_set(GR_ENTRY(res->entries, res->nnz, ctx->sizeof_elem), mat_row->entries, mat_row->nnz, ctx); + res->nnz += mat_row->nnz; + } + res->rows[res->r] = res->nnz; + + return success; +} + +int gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + ulong row; + int success = GR_SUCCESS; + gr_sparse_vec_t tmp_vec; + + if (res->r != mat->r || res->c != mat->c) + return GR_DOMAIN; + + tmp_vec->alloc = 0; // All memory borrowed + tmp_vec->length = mat->c; + for(row = 0; row < mat->r; row++) { + tmp_vec->cols = mat->cols + mat->rows[row]; + tmp_vec->entries = GR_ENTRY(mat->entries, mat->rows[row], ctx->sizeof_elem); + tmp_vec->nnz = mat->rows[row+1] - mat->rows[row]; + success |= gr_sparse_vec_set(res->rows[row], tmp_vec, ctx); + } + res->nnz = mat->nnz; + + return success; +} diff --git a/src/gr_sparse_mat/swap_rows.c b/src/gr_sparse_mat/swap_rows.c new file mode 100644 index 0000000000..47a6f64118 --- /dev/null +++ b/src/gr_sparse_mat/swap_rows.c @@ -0,0 +1,35 @@ +/* + Copyright (C) 2022 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 "gr_sparse_mat.h" + +int gr_lil_mat_swap_rows(gr_lil_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx) +{ + /* todo: bounds checking */ + if (r < 0 || s < 0 || r >= mat->r || s >= mat->r) + { + return GR_DOMAIN; + } + if (r == s) + { + return GR_DOMAIN; + } + + if (perm != NULL) + FLINT_SWAP(slong, perm[r], perm[s]); + + if (mat->rows[r]->nnz != 0 || mat->rows[s]->nnz != 0) + { + FLINT_SWAP(gr_ptr, mat->rows[r], mat->rows[s]); + } + + return GR_SUCCESS; +} diff --git a/src/gr_sparse_mat/to_dense.c b/src/gr_sparse_mat/to_dense.c new file mode 100644 index 0000000000..7c5ad80865 --- /dev/null +++ b/src/gr_sparse_mat/to_dense.c @@ -0,0 +1,51 @@ +/* + Copyright (C) 2024 Kartik Venkatram + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "gr_sparse_mat.h" + +int gr_mat_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + ulong row, nz; + int success = GR_SUCCESS; + size_t sz = ctx->sizeof_elem; + + if (res->r != mat->r || res->c != mat->c) + return GR_DOMAIN; + + success |= gr_mat_zero(res, ctx); + for (row = 0; row < mat->r; ++row) + { + for (nz = mat->rows[row]; nz < mat->rows[row + 1]; ++nz) + { + success |= gr_set( + GR_MAT_ENTRY(res, row, mat->cols[nz], sz), + GR_ENTRY(mat->entries, nz, sz), + ctx + ); + } + } + return success; +} + +int gr_mat_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +{ + ulong row; + int success = GR_SUCCESS; + + if (res->r != mat->r || res->c != mat->c) + return GR_DOMAIN; + + for (row = 0; row < mat->r; ++row) + { + success |= gr_vec_set_sparse_vec(res->rows[row], mat->rows[row], ctx); + } + return success; +} From 72d3b91adac33bc236e2057c196433dcfc0e5cf4 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 17 Mar 2024 16:36:08 -0700 Subject: [PATCH 24/59] Bug fix --- src/gr_mat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gr_mat.h b/src/gr_mat.h index a67dbc1436..400c4b0abe 100644 --- a/src/gr_mat.h +++ b/src/gr_mat.h @@ -222,7 +222,7 @@ WARN_UNUSED_RESULT int gr_mat_hadamard(gr_mat_t mat, gr_ctx_t ctx); for (i = 0; i < A->r; i++) \ { \ set_shallow(GR_MAT_ENTRY(B, j, i, sz), GR_MAT_ENTRY(B, i, j, sz), ctx); \ - } + } \ } \ } From ae7f8aff88264c31e5977b35cfe90ffa1fc56a04 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 17 Mar 2024 16:37:17 -0700 Subject: [PATCH 25/59] Forgot to save --- src/gr_sparse_vec.h | 62 ++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index aded272244..adf430678f 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -30,7 +30,7 @@ typedef struct { slong alloc; gr_ptr entries; - ulong *cols; + ulong *inds; slong length; slong nnz; } @@ -49,16 +49,16 @@ GR_SPARSE_VEC_INLINE void gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) { _gr_vec_clear(vec->entries, vec->alloc, ctx); - flint_free(vec->cols); + flint_free(vec->inds); flint_free(vec->entries); memset(vec, 0, sizeof(gr_sparse_vec_t)); } -#define GR_SPARSE_VEC_COL(vec, i) (vec)->cols[i] +#define GR_SPARSE_VEC_COL(vec, i) (vec)->inds[i] #define GR_SPARSE_VEC_ENTRY(vec, i, sz) GR_ENTRY((vec)->entries, i, sz) -GR_SPARSE_VEC_INLINE ulong * gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->cols + i; } -GR_SPARSE_VEC_INLINE const ulong * gr_sparse_vec_col_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->cols + i; } +GR_SPARSE_VEC_INLINE ulong * gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->inds + i; } +GR_SPARSE_VEC_INLINE const ulong * gr_sparse_vec_col_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->inds + i; } GR_SPARSE_VEC_INLINE gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); } GR_SPARSE_VEC_INLINE gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); } @@ -69,13 +69,13 @@ void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) { return vec->nnz; } WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx); GR_SPARSE_VEC_INLINE void gr_sparse_vec_swap(gr_sparse_vec_t res, gr_sparse_vec_t src, gr_ctx_t ctx) { FLINT_SWAP(slong, res->alloc, src->alloc); FLINT_SWAP(gr_ptr, res->entries, src->entries); - FLINT_SWAP(slong *, res->cols, src->cols); + FLINT_SWAP(slong *, res->inds, src->inds); FLINT_SWAP(slong, res->length, src->length); FLINT_SWAP(slong, res->nnz, src->nnz); @@ -84,7 +84,7 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t v WARN_UNUSED_RESULT int gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_t ctx); @@ -99,15 +99,15 @@ WARN_UNUSED_RESULT int gr_sparse_vec_randtest(gr_sparse_vec_t vec, double densit -slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulong *cols1, slong nnz1); +slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulong *inds1, slong nnz1); #define GR_SPV_SWAP_INDS(VEC, I, J, SZ, CTX) \ { \ - slong _temp = (VEC)->cols[I]; \ - (VEC)->cols[I] = (VEC)->cols[J]; \ - (VEC)->cols[J] = _temp; \ + slong _temp = (VEC)->inds[I]; \ + (VEC)->inds[I] = (VEC)->inds[J]; \ + (VEC)->inds[J] = _temp; \ gr_swap(GR_ENTRY((VEC)->entries, (I), (SZ)), GR_ENTRY((VEC)->entries, (J), (SZ)), (CTX)); \ } @@ -125,7 +125,7 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo sz = (CTX)->sizeof_elem; \ a_nnz = (A_VEC)->nnz; \ b_nnz = (B_VEC)->nnz; \ - new_nnz = _gr_sparse_vec_count_unique_cols((A_VEC)->cols, a_nnz, (B_VEC)->cols, b_nnz); \ + new_nnz = _gr_sparse_vec_count_unique_inds((A_VEC)->inds, a_nnz, (B_VEC)->inds, b_nnz); \ gr_sparse_vec_fit_nnz((DEST_VEC), new_nnz, (CTX)); \ /* We go backward through the destination, because it might be an in-place operation on a source */ \ a_ind = a_nnz-1; \ @@ -133,24 +133,24 @@ slong _gr_sparse_vec_count_unique_cols(const ulong *cols0, slong nnz0, const ulo dest_ind = new_nnz-1; \ while (a_ind >= 0 && b_ind >= 0 && status == GR_SUCCESS) \ { \ - a_col = (A_VEC)->cols[a_ind]; \ - b_col = (B_VEC)->cols[b_ind]; \ + a_col = (A_VEC)->inds[a_ind]; \ + b_col = (B_VEC)->inds[b_ind]; \ if (a_col > b_col) \ { \ status |= (FUNC_A); \ - (DEST_VEC)->cols[dest_ind] = a_col; \ + (DEST_VEC)->inds[dest_ind] = a_col; \ a_ind--; \ } \ else if (b_col > a_col) \ { \ status |= (FUNC_B); \ - (DEST_VEC)->cols[dest_ind] = b_col; \ + (DEST_VEC)->inds[dest_ind] = b_col; \ b_ind--; \ } \ else \ { \ status |= (FUNC_AB); \ - (DEST_VEC)->cols[dest_ind] = a_col; \ + (DEST_VEC)->inds[dest_ind] = a_col; \ a_ind--; \ b_ind--; \ } \ @@ -222,17 +222,17 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_product(gr_ptr res, } \ return status; -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update_to_dense(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_set(GR_ENTRY(dres, src->cols[i], sz), GR_ENTRY(src->entries, i, sz), ctx), src, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_add(GR_ENTRY(dres, svec2->cols[i], sz), GR_ENTRY(dvec1, svec2->cols[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_sub(GR_ENTRY(dres, svec2->cols[i], sz), GR_ENTRY(dvec1, svec2->cols[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_mul_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_mul(GR_ENTRY(dres, svec2->cols[i], sz), GR_ENTRY(dvec1, svec2->cols[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_div_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_div(GR_ENTRY(dres, svec2->cols[i], sz), GR_ENTRY(dvec1, svec2->cols[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul_si(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul_si(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul_fmpz(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul_fmpz(GR_ENTRY(dres, svec->cols[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update_to_dense(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_set(GR_ENTRY(dres, src->inds[i], sz), GR_ENTRY(src->entries, i, sz), ctx), src, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_add(GR_ENTRY(dres, svec2->inds[i], sz), GR_ENTRY(dvec1, svec2->inds[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_sub(GR_ENTRY(dres, svec2->inds[i], sz), GR_ENTRY(dvec1, svec2->inds[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_mul_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_mul(GR_ENTRY(dres, svec2->inds[i], sz), GR_ENTRY(dvec1, svec2->inds[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_div_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_div(GR_ENTRY(dres, svec2->inds[i], sz), GR_ENTRY(dvec1, svec2->inds[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul_si(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul_si(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul_fmpz(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul_fmpz(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } /***** TODO: @@ -252,7 +252,7 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_src { \ gr_sparse_vec_fit_nnz(res, src->nnz, ctx); \ res->nnz = src->nnz; \ - memcpy(res->cols, src->cols, src->nnz*sizeof(slong)); \ + memcpy(res->inds, src->inds, src->nnz*sizeof(slong)); \ } \ return dense_vec_op(res->entries, src->entries, src->nnz, c, ctx); \ From 9a759548c19cf8cd2d5ce60ec83b3e854096ac80 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 17 Mar 2024 16:53:45 -0700 Subject: [PATCH 26/59] Fixed setting functions --- src/gr_sparse_mat.h | 7 ++++--- src/gr_sparse_mat/set.c | 24 +++++++++--------------- src/gr_sparse_mat/swap_rows.c | 2 +- src/gr_sparse_vec.h | 2 +- src/gr_sparse_vec/set.c | 1 - 5 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 6a5c9073f3..71d835531e 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -211,13 +211,14 @@ gr_lil_mat_clear(gr_lil_mat_t mat, gr_ctx_t ctx) { GR_SPARSE_MAT_INLINE void -_gr_csr_mat_borrow_row(gr_sparse_vec_t res, gr_csr_mat_t mat, slong r, gr_ctx_t ctx) { +_gr_csr_mat_borrow_row(gr_sparse_vec_t res, const gr_csr_mat_t mat, slong r, gr_ctx_t ctx) { ulong offset; offset = mat->rows[r]; - res->alloc = 0; res->nnz = mat->rows[r+1] - offset; - res->cols = mat->cols + offset; + res->alloc = res->nnz; + res->inds = mat->cols + offset; + res->length = mat->c; res->entries = GR_ENTRY(mat->entries, offset, ctx->sizeof_elem); } diff --git a/src/gr_sparse_mat/set.c b/src/gr_sparse_mat/set.c index 51fd63318c..27ab9d83b2 100644 --- a/src/gr_sparse_mat/set.c +++ b/src/gr_sparse_mat/set.c @@ -44,22 +44,20 @@ int gr_csr_mat_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ct { ulong row; int success = GR_SUCCESS; - gr_sparse_vec_struct *mat_row; + gr_sparse_vec_t res_row; if (res->r != mat->r || res->c != mat->c) return GR_DOMAIN; gr_csr_mat_fit_nnz(res, mat->nnz, ctx); - res->nnz = 0; + res->rows[0] = 0; for(row = 0; row < mat->r; row++) { - mat_row = mat->rows[row]; - res->rows[row] = res->nnz; - memcpy(res->cols + res->nnz, mat_row->cols, mat_row->nnz); - success |= _gr_vec_set(GR_ENTRY(res->entries, res->nnz, ctx->sizeof_elem), mat_row->entries, mat_row->nnz, ctx); - res->nnz += mat_row->nnz; + res->rows[row+1] = res->rows[row] + mat->rows[row]->nnz; + _gr_csr_mat_borrow_row(res_row, res, row, ctx); + success |= gr_sparse_vec_set(res_row, mat->rows[row], ctx); } - res->rows[res->r] = res->nnz; + res->nnz = mat->nnz; return success; } @@ -68,18 +66,14 @@ int gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ct { ulong row; int success = GR_SUCCESS; - gr_sparse_vec_t tmp_vec; + gr_sparse_vec_t mat_row; if (res->r != mat->r || res->c != mat->c) return GR_DOMAIN; - tmp_vec->alloc = 0; // All memory borrowed - tmp_vec->length = mat->c; for(row = 0; row < mat->r; row++) { - tmp_vec->cols = mat->cols + mat->rows[row]; - tmp_vec->entries = GR_ENTRY(mat->entries, mat->rows[row], ctx->sizeof_elem); - tmp_vec->nnz = mat->rows[row+1] - mat->rows[row]; - success |= gr_sparse_vec_set(res->rows[row], tmp_vec, ctx); + _gr_csr_mat_borrow_row(mat_row, mat, row, ctx); + success |= gr_sparse_vec_set(res->rows[row], mat_row, ctx); } res->nnz = mat->nnz; diff --git a/src/gr_sparse_mat/swap_rows.c b/src/gr_sparse_mat/swap_rows.c index 47a6f64118..1a92b3d8cf 100644 --- a/src/gr_sparse_mat/swap_rows.c +++ b/src/gr_sparse_mat/swap_rows.c @@ -28,7 +28,7 @@ int gr_lil_mat_swap_rows(gr_lil_mat_t mat, slong * perm, slong r, slong s, gr_ct if (mat->rows[r]->nnz != 0 || mat->rows[s]->nnz != 0) { - FLINT_SWAP(gr_ptr, mat->rows[r], mat->rows[s]); + gr_sparse_vec_swap(mat->rows[r], mat->rows[s], ctx); } return GR_SUCCESS; diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index adf430678f..74045fec9b 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -75,7 +75,7 @@ GR_SPARSE_VEC_INLINE void gr_sparse_vec_swap(gr_sparse_vec_t res, gr_sparse_vec_ { FLINT_SWAP(slong, res->alloc, src->alloc); FLINT_SWAP(gr_ptr, res->entries, src->entries); - FLINT_SWAP(slong *, res->inds, src->inds); + FLINT_SWAP(ulong *, res->inds, src->inds); FLINT_SWAP(slong, res->length, src->length); FLINT_SWAP(slong, res->nnz, src->nnz); diff --git a/src/gr_sparse_vec/set.c b/src/gr_sparse_vec/set.c index 43ffe28f18..2f588a0607 100644 --- a/src/gr_sparse_vec/set.c +++ b/src/gr_sparse_vec/set.c @@ -11,7 +11,6 @@ gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) memcpy(res->inds, src->inds, nnz*sizeof(slong)); status = _gr_vec_set(res->entries, src->entries, nnz, ctx); res->nnz = nnz; - res->alloc = nnz; res->length = src->length; } return status; From a687079fab53483d1b03c150fe0c2f0be129b9c5 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 17 Mar 2024 17:07:43 -0700 Subject: [PATCH 27/59] A few more functions --- src/gr_sparse_mat.h | 17 +++++++- src/gr_sparse_mat/equal.c | 78 ++++++++++++++++++++++++++++++++++ src/gr_sparse_mat/is_neg_one.c | 62 +++++++++++++++++++++++++++ src/gr_sparse_mat/is_one.c | 61 ++++++++++++++++++++++++++ src/gr_sparse_vec.h | 2 +- 5 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 src/gr_sparse_mat/equal.c create mode 100644 src/gr_sparse_mat/is_neg_one.c create mode 100644 src/gr_sparse_mat/is_one.c diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 71d835531e..28ac2b7d7d 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -250,7 +250,7 @@ WARN_UNUSED_RESULT int gr_sparse_mat_randops(gr_csr_mat_t mat, flint_rand_t stat WARN_UNUSED_RESULT int gr_sparse_mat_randpermdiag(int * parity, gr_csr_mat_t mat, flint_rand_t state, gr_ptr diag, slong n, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_mat_randrank(gr_csr_mat_t mat, flint_rand_t state, slong rank, gr_ctx_t ctx); */ -/* + #define gr_sparse_mat_is_empty(mat, ctx) (((mat->r == 0) || (mat->c == 0)) ? T_TRUE : T_FALSE) #define gr_sparse_mat_is_square(mat, ctx) ((mat->r == mat->c) ? T_TRUE : T_FALSE) #define gr_sparse_mat_is_zero(mat, ctx) ((mat->nnz == 0) ? T_TRUE : T_FALSE); @@ -263,11 +263,24 @@ truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx); truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx); truth_t gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +GR_SPARSE_MAT_INLINE void gr_csr_mat_zero(gr_csr_mat_t res, gr_ctx_t ctx) { res->nnz = 0; memset(res->rows, 0, (res->r + 1) * sizeof(ulong)); } + +GR_SPARSE_MAT_INLINE void +gr_lil_mat_zero(gr_lil_mat_t res, gr_ctx_t ctx) { + int row; + + res->nnz = 0; + for(row = 0; row < res->r; ++row) + { + gr_sparse_vec_zero(res->rows[row], ctx); + } +} + +/* GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_one(gr_csr_mat_t res, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_csr_mat_set_scalar(gr_csr_mat_t res, gr_srcptr c, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_csr_mat_set_ui(gr_csr_mat_t res, ulong v, gr_ctx_t ctx); diff --git a/src/gr_sparse_mat/equal.c b/src/gr_sparse_mat/equal.c new file mode 100644 index 0000000000..43faacec29 --- /dev/null +++ b/src/gr_sparse_mat/equal.c @@ -0,0 +1,78 @@ +/* + Copyright (C) 2022 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 "gr_sparse_mat.h" + +truth_t +gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx) +{ + slong i, r, c, nnz; + size_t sz = ctx->sizeof_elem; + + r = gr_sparse_mat_nrows(mat1, ctx); + c = gr_sparse_mat_ncols(mat1, ctx); + nnz = gr_sparse_mat_nnz(mat1, ctx); + + if (r != gr_mat_nrows(mat2, ctx) || + c != gr_mat_ncols(mat2, ctx) || + nnz != gr_sparse_mat_nnz(mat2, ctx)) + { + return T_FALSE; + } + + if (r == 0 || c == 0) + return T_TRUE; + + // TODO: can use memcmp? + for (i = 0; i < nnz; ++i) + { + if (mat1->cols[i] != mat2->cols[i]) + return T_FALSE; + } + + return _gr_vec_equal( + mat1->entries, + mat2->entries, + nnz, + ctx + ); +} + +truth_t +gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ + slong i, r, c, nnz; + truth_t row_is_eq; + size_t sz = ctx->sizeof_elem; + + r = gr_sparse_mat_nrows(mat1, ctx); + c = gr_sparse_mat_ncols(mat1, ctx); + nnz = gr_sparse_mat_nnz(mat1, ctx); + + if (r != gr_mat_nrows(mat2, ctx) || + c != gr_mat_ncols(mat2, ctx) || + nnz != gr_sparse_mat_nnz(mat2, ctx)) + { + return T_FALSE; + } + + if (r == 0 || c == 0) + return T_TRUE; + + for (i = 0; i < r; ++i) + { + row_is_eq = gr_sparse_vec_equal(mat1->rows[i], mat2->rows[i], ctx); + if (row_is_eq != T_TRUE) + break; + } + + return row_is_eq; +} diff --git a/src/gr_sparse_mat/is_neg_one.c b/src/gr_sparse_mat/is_neg_one.c new file mode 100644 index 0000000000..0057f4a82d --- /dev/null +++ b/src/gr_sparse_mat/is_neg_one.c @@ -0,0 +1,62 @@ +/* + Copyright (C) 2022 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 "gr_sparse_mat.h" + +truth_t +gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + int row; + gr_method_unary_predicate is_neg_one = GR_UNARY_PREDICATE(ctx, IS_NEG_ONE); + truth_t this_eq; + slong sz = ctx->sizeof_elem; + + if (mat->r != mat->nnz) + return T_FALSE; + + for (row = 0; row < mat->r; ++row) + { + if (mat->cols[row] != row) + return T_FALSE; + + this_eq = is_neg_one(GR_ENTRY(mat->entries, row, sz), ctx); + + if (this_eq == T_FALSE) + return T_FALSE; + else if (this_eq == T_UNKNOWN) + return T_UNKNOWN; + } + return T_TRUE; +} + +truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx) +{ + int row; + gr_method_unary_predicate is_neg_one = GR_UNARY_PREDICATE(ctx, IS_NEG_ONE); + truth_t this_eq; + + if (mat->r != mat->nnz) + return T_FALSE; + + for (row = 0; row < mat->r; ++row) + { + if (mat->rows[row]->nnz != 1 || mat->rows[row]->inds[0] != row) + return T_FALSE; + + this_eq = is_neg_one(mat->rows[row]->entries, ctx); + + if (this_eq == T_FALSE) + return T_FALSE; + else if (this_eq == T_UNKNOWN) + return T_UNKNOWN; + } + return T_TRUE; +} diff --git a/src/gr_sparse_mat/is_one.c b/src/gr_sparse_mat/is_one.c new file mode 100644 index 0000000000..8e51e1ce66 --- /dev/null +++ b/src/gr_sparse_mat/is_one.c @@ -0,0 +1,61 @@ +/* + Copyright (C) 2022 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 "gr_sparse_mat.h" + +truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + int row; + gr_method_unary_predicate is_one = GR_UNARY_PREDICATE(ctx, IS_ONE); + truth_t this_eq; + slong sz = ctx->sizeof_elem; + + if (mat->r != mat->nnz) + return T_FALSE; + + for (row = 0; row < mat->r; ++row) + { + if (mat->cols[row] != row) + return T_FALSE; + + this_eq = is_one(GR_ENTRY(mat->entries, row, sz), ctx); + + if (this_eq == T_FALSE) + return T_FALSE; + else if (this_eq == T_UNKNOWN) + return T_UNKNOWN; + } + return T_TRUE; +} + +truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx) +{ + int row; + gr_method_unary_predicate is_one = GR_UNARY_PREDICATE(ctx, IS_ONE); + truth_t this_eq; + + if (mat->r != mat->nnz) + return T_FALSE; + + for (row = 0; row < mat->r; ++row) + { + if (mat->rows[row]->nnz != 1 || mat->rows[row]->inds[0] != row) + return T_FALSE; + + this_eq = is_one(mat->rows[row]->entries, ctx); + + if (this_eq == T_FALSE) + return T_FALSE; + else if (this_eq == T_UNKNOWN) + return T_UNKNOWN; + } + return T_TRUE; +} diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 74045fec9b..cfd94de8b9 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -80,7 +80,7 @@ GR_SPARSE_VEC_INLINE void gr_sparse_vec_swap(gr_sparse_vec_t res, gr_sparse_vec_ FLINT_SWAP(slong, res->nnz, src->nnz); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; return GR_SUCCESS; } +GR_SPARSE_VEC_INLINE void gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; } WARN_UNUSED_RESULT int gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx); From 967ee80e90a321406ee2d8a3c405631fc8844b9b Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 17 Mar 2024 17:19:32 -0700 Subject: [PATCH 28/59] Added negation --- src/gr_sparse_mat.h | 25 ++++++++++++++++++++----- src/gr_sparse_mat/equal.c | 2 -- src/gr_sparse_mat/set.c | 37 ++++++++++++++++++++++--------------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 28ac2b7d7d..30c0cc2b78 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -290,11 +290,27 @@ WARN_UNUSED_RESULT int gr_csr_mat_set_fmpq(gr_csr_mat_t res, const fmpq_t v, gr_ WARN_UNUSED_RESULT int gr_csr_mat_set_fmpz_csr_mat(gr_csr_mat_t res, const fmpz_csr_mat_t mat, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_csr_mat_set_fmpq_csr_mat(gr_csr_mat_t res, const fmpq_csr_mat_t mat, gr_ctx_t ctx); +*/ + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_csr_mat_neg(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + + if (res->c != mat->c || res->r != mat->r) + { + return GR_DOMAIN; + } + status |= gr_csr_mat_set(res, mat, ctx); + status |= _gr_vec_neg(res->entries, res->entries, res->nnz, ctx); + return status; +} -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_neg(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_neg(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) { int row; - int status; + int status = GR_SUCCESS; if (res->c != mat->c || res->r != mat->r) { @@ -302,12 +318,11 @@ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_neg(gr_csr_mat_t res, con } res->nnz = mat->nnz; for (row = 0; row < res->r; row++) { - status |= gr_sparse_vec_neg(res->rows[i], res->mat[i], ctx); - res->nnz += res->rows[i].nnz; + status |= gr_sparse_vec_neg(res->rows[row], mat->rows[row], ctx); } return status; } - +/* GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_add(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) { int row; diff --git a/src/gr_sparse_mat/equal.c b/src/gr_sparse_mat/equal.c index 43faacec29..264e57f843 100644 --- a/src/gr_sparse_mat/equal.c +++ b/src/gr_sparse_mat/equal.c @@ -15,7 +15,6 @@ truth_t gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx) { slong i, r, c, nnz; - size_t sz = ctx->sizeof_elem; r = gr_sparse_mat_nrows(mat1, ctx); c = gr_sparse_mat_ncols(mat1, ctx); @@ -51,7 +50,6 @@ gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) { slong i, r, c, nnz; truth_t row_is_eq; - size_t sz = ctx->sizeof_elem; r = gr_sparse_mat_nrows(mat1, ctx); c = gr_sparse_mat_ncols(mat1, ctx); diff --git a/src/gr_sparse_mat/set.c b/src/gr_sparse_mat/set.c index 27ab9d83b2..124bf1ea40 100644 --- a/src/gr_sparse_mat/set.c +++ b/src/gr_sparse_mat/set.c @@ -12,16 +12,20 @@ #include "gr_sparse_mat.h" int gr_csr_mat_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) { - int status; - - if (res->r != mat->r || res->c != mat->c) { - return GR_DOMAIN; + int status = GR_SUCCESS; + + if (res != mat) + { + if (res->r != mat->r || res->c != mat->c) + { + return GR_DOMAIN; + } + res->nnz = mat->nnz; + gr_csr_mat_fit_nnz(res, mat->nnz, ctx); + memcpy(res->rows, mat->rows, mat->r * sizeof(ulong)); + memcpy(res->cols, mat->cols, mat->nnz * sizeof(ulong)); + status = _gr_vec_set(res->entries, mat->entries, mat->nnz, ctx); } - res->nnz = mat->nnz; - gr_csr_mat_fit_nnz(res, mat->nnz, ctx); - memcpy(res->rows, mat->rows, mat->r * sizeof(ulong)); - memcpy(res->cols, mat->cols, mat->nnz * sizeof(ulong)); - status = _gr_vec_set(res->entries, mat->entries, mat->nnz, ctx); return status; } @@ -29,13 +33,16 @@ int gr_lil_mat_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) { ulong row; int success = GR_SUCCESS; - if (res->r != mat->r || res->c != mat->c) { - return GR_DOMAIN; - } - res->nnz = mat->nnz; + if (res != mat) + { + if (res->r != mat->r || res->c != mat->c) { + return GR_DOMAIN; + } + res->nnz = mat->nnz; - for (row = 0; row < mat->r; ++row) { - success |= gr_sparse_vec_set(res->rows[row], mat->rows[row], ctx); + for (row = 0; row < mat->r; ++row) { + success |= gr_sparse_vec_set(res->rows[row], mat->rows[row], ctx); + } } return success; } From 2aa7bb5c13d292216944d2c07c279b33dbae3e45 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 17 Mar 2024 17:42:37 -0700 Subject: [PATCH 29/59] Added scaling ops --- src/gr_sparse_mat.h | 76 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 30c0cc2b78..af24428ec6 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -322,6 +322,76 @@ gr_lil_mat_neg(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) } return status; } + +#define GR_CSR_MAT_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) \ + if(res->r != src->r || res->c != src->c) \ + { \ + return GR_DOMAIN; \ + } \ + if(res != src) \ + { \ + gr_csr_mat_fit_nnz(res, src->nnz, ctx); \ + res->nnz = src->nnz; \ + memcpy(res->rows, src->rows, src->r*sizeof(ulong)); \ + memcpy(res->cols, src->cols, src->nnz*sizeof(ulong)); \ + } \ + return dense_vec_op(res->entries, src->entries, src->nnz, c, ctx); \ + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_2exp_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } + +#define GR_LIL_MAT_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) { \ + int status = GR_SUCCESS; \ + int row; \ + if(res->r != src->r || res->c != src->c) \ + { \ + return GR_DOMAIN; \ + } \ + res->nnz = src->nnz; \ + for (row = 0; row < src->r; ++row) \ + { \ + if(res != src) \ + { \ + gr_sparse_vec_fit_nnz(res->rows[row], src->rows[row]->nnz, ctx); \ + res->rows[row]->nnz = src->rows[row]->nnz; \ + memcpy(res->rows[row]->inds, src->rows[row]->inds, src->rows[row]->nnz*sizeof(ulong)); \ + } \ + status |= dense_vec_op(res->rows[row]->entries, src->rows[row]->entries, src->rows[row]->nnz, c, ctx); \ + } \ + return status; \ +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_2exp_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } + /* GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_add(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) { @@ -357,12 +427,6 @@ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_sub(gr_lil_mat_t res, con return status; } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); - WARN_UNUSED_RESULT int gr_csr_mat_mul_vec(gr_vec_t v, const gr_csr_mat_t A, const gr_vec_t u, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ctx_t ctx); From cb8c911089bbcc8ea15f567a56bd186f636feee0 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Mon, 18 Mar 2024 02:41:53 -0700 Subject: [PATCH 30/59] Sparse vector and matrix multiplication --- doc/source/gr_sparse_vec.rst | 26 +-- src/gr_sparse_mat.h | 5 +- src/gr_sparse_mat/mul.c | 267 ++++++++++++++++++++++ src/gr_sparse_vec.h | 416 +++++++++++++++++++++++++++++------ 4 files changed, 635 insertions(+), 79 deletions(-) create mode 100644 src/gr_sparse_mat/mul.c diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index 9df32c050a..77d6af718f 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -222,24 +222,24 @@ Arithmetic Arithmetic into dense vectors -------------------------------------------------------------------------------- -.. function:: int gr_sparse_vec_update_to_dense(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) - int gr_sparse_vec_add_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) - int gr_sparse_vec_sub_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) - int gr_sparse_vec_nz_mul_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) - int gr_sparse_vec_nz_div_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) - int gr_sparse_vec_addmul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) - int gr_sparse_vec_submul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) - int gr_sparse_vec_addmul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) - int gr_sparse_vec_submul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) - int gr_sparse_vec_addmul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) - int gr_sparse_vec_submul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) +.. function:: int gr_vec_update_sparse_vec_nz(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) + int gr_vec_add_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_vec_sub_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_vec_mul_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_vec_div_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_vec_addmul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) + int gr_vec_submul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) + int gr_vec_addmul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) + int gr_vec_submul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) + int gr_vec_addmul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) + int gr_vec_submul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) These functions facilitate accumulating a sparse vector into a dense target. They have one dense input, one sparse input, and a dense output. For all functions, it is assumed that *dres* and *dvec1* have the same length as *svec* or *svec2*, as appropriate. The functions - ``gr_sparse_vec_update_to_dense()`` (overwrite the entries in *dres*), - ``gr_sparse_vec_nz_mul_to_dense()``, and ``gr_sparse_vec_nz_div_to_dense()`` + ``gr_vec_update_sparse_vec_nz()`` (overwrite the entries in *dres*), + ``gr_vec_mul_sparse_vec_nz()``, and ``gr_vec_div_sparse_vec_nz()`` only operate on the locations for which *svec2* is nonzero. diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index af24428ec6..701e1a59a6 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -253,7 +253,7 @@ WARN_UNUSED_RESULT int gr_sparse_mat_randrank(gr_csr_mat_t mat, flint_rand_t sta #define gr_sparse_mat_is_empty(mat, ctx) (((mat->r == 0) || (mat->c == 0)) ? T_TRUE : T_FALSE) #define gr_sparse_mat_is_square(mat, ctx) ((mat->r == mat->c) ? T_TRUE : T_FALSE) -#define gr_sparse_mat_is_zero(mat, ctx) ((mat->nnz == 0) ? T_TRUE : T_FALSE); +#define gr_sparse_mat_is_zero(mat, ctx) ((mat->nnz == 0) ? T_TRUE : T_FALSE) truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx); truth_t gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx); @@ -426,6 +426,7 @@ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_sub(gr_lil_mat_t res, con } return status; } +*/ WARN_UNUSED_RESULT int gr_csr_mat_mul_vec(gr_vec_t v, const gr_csr_mat_t A, const gr_vec_t u, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ctx_t ctx); @@ -436,7 +437,7 @@ WARN_UNUSED_RESULT int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_ma WARN_UNUSED_RESULT int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ctx_t ctx); - +/* WARN_UNUSED_RESULT int gr_sparse_mat_lu(slong * rank, slong * P, gr_csr_mat_t LU, const gr_csr_mat_t A, int rank_check, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_mat_fflu(slong * res_rank, slong * P, gr_csr_mat_t LU, gr_ptr den, const gr_csr_mat_t A, int rank_check, gr_ctx_t ctx); diff --git a/src/gr_sparse_mat/mul.c b/src/gr_sparse_mat/mul.c new file mode 100644 index 0000000000..27f5a5870f --- /dev/null +++ b/src/gr_sparse_mat/mul.c @@ -0,0 +1,267 @@ +/* + 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 "gr_sparse_mat.h" + +int gr_csr_mat_mul_vec(gr_vec_t v, const gr_csr_mat_t A, const gr_vec_t u, gr_ctx_t ctx) +{ + slong ar, i; + int status; + gr_sparse_vec_t row; + gr_ptr res; + + ar = gr_sparse_mat_nrows(A, ctx); + + if (gr_sparse_mat_ncols(A, ctx) != gr_vec_length(u, ctx) || ar != gr_vec_length(v, ctx)) + return GR_DOMAIN; + + if (gr_sparse_mat_is_zero(A, ctx) == T_TRUE) + { + return _gr_vec_zero(v->entries, v->length, ctx); + } + + status = GR_SUCCESS; + + if (u == v) + { + gr_vec_t w; + gr_vec_init(w, ar, ctx); + status |= gr_csr_mat_mul_vec(w, A, u, ctx); + _gr_vec_swap(v, w, ar, ctx); + gr_vec_clear(w, ctx); + return status; + } + + status |= _gr_vec_zero(v->entries, v->length, ctx); + for (i = 0; i < ar; ++i) { + _gr_csr_mat_borrow_row(row, A, i, ctx); + res = gr_vec_entry_ptr(v, i, ctx); + status |= gr_sparse_vec_dot_vec(res, res, 0, row, u, ctx); + } + + return status; +} + +int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ctx_t ctx) +{ + slong ar, i; + int status; + gr_ptr res; + + ar = gr_sparse_mat_nrows(A, ctx); + + if (gr_sparse_mat_ncols(A, ctx) != gr_vec_length(u, ctx) || ar != gr_vec_length(v, ctx)) + return GR_DOMAIN; + + + if (gr_sparse_mat_is_zero(A, ctx) == T_TRUE) + { + return _gr_vec_zero(v->entries, v->length, ctx); + } + + status = GR_SUCCESS; + + if (u == v) + { + gr_vec_t w; + gr_vec_init(w, ar, ctx); + status |= gr_lil_mat_mul_vec(w, A, u, ctx); + _gr_vec_swap(v, w, ar, ctx); + gr_vec_clear(w, ctx); + return status; + } + + status |= _gr_vec_zero(v->entries, v->length, ctx); + for (i = 0; i < ar; ++i) { + res = gr_vec_entry_ptr(v, i, ctx); + status |= gr_sparse_vec_dot_vec(res, res, 0, A->rows[i], u, ctx); + } + + return status; +} + +#define GR_MAT_OOP_FN(status, M, ctx, fn, ...) \ +{ \ + gr_mat_t T; \ + gr_mat_init(T, M->r, M->c, ctx); \ + status |= fn(T, __VA_ARGS__, ctx); \ + status |= gr_mat_swap_entrywise(T, M, ctx); \ + gr_mat_clear(T, ctx); \ +} + +void _gr_mat_borrow_row(gr_vec_t row, const gr_mat_t mat, slong i, gr_ctx_t ctx) +{ + slong sz = ctx->sizeof_elem; + row->length = mat->c; + row->entries = GR_MAT_ENTRY(mat, i, 0, sz); +} + + +int gr_csr_mat_mul_mat_transpose(gr_mat_t Ct, const gr_csr_mat_t A, const gr_mat_t Bt, gr_ctx_t ctx) +{ + slong ar, btr, i; + int status; + gr_vec_t bt_row, ct_row; + + ar = gr_sparse_mat_nrows(A, ctx); + btr = gr_mat_nrows(Bt, ctx); + + if (gr_sparse_mat_ncols(A, ctx) != gr_mat_ncols(Bt, ctx) || ar != gr_mat_ncols(Ct, ctx) || btr != gr_mat_nrows(Ct, ctx)) + return GR_DOMAIN; + + status = gr_mat_zero(Ct, ctx); + + if (gr_sparse_mat_is_zero(A, ctx)) + { + return status; + } + + if (Bt == Ct) + { + GR_MAT_OOP_FN(status, Ct, ctx, gr_csr_mat_mul_mat_transpose, A, Bt); + return status; + } + + for (i = 0; i < btr; i++) + { + _gr_mat_borrow_row(ct_row, Ct, i, ctx); + _gr_mat_borrow_row(bt_row, Bt, i, ctx); + status |= gr_csr_mat_mul_vec(ct_row, A, bt_row, ctx); + } + return status; +} + + +int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_mat_t A, const gr_mat_t Bt, gr_ctx_t ctx) +{ + slong ar, btr, i; + int status; + gr_vec_t bt_row, ct_row; + + ar = gr_sparse_mat_nrows(A, ctx); + btr = gr_mat_nrows(Bt, ctx); + + if (gr_sparse_mat_ncols(A, ctx) != gr_mat_ncols(Bt, ctx) || ar != gr_mat_ncols(Ct, ctx) || btr != gr_mat_nrows(Ct, ctx)) + return GR_DOMAIN; + + status = gr_mat_zero(Ct, ctx); + + if (gr_sparse_mat_is_zero(A, ctx)) + { + return status; + } + + status = GR_SUCCESS; + + if (Bt == Ct) + { + GR_MAT_OOP_FN(status, Ct, ctx, gr_lil_mat_mul_mat_transpose, A, Bt); + return status; + } + + for (i = 0; i < btr; i++) { + _gr_mat_borrow_row(ct_row, Ct, i, ctx); + _gr_mat_borrow_row(bt_row, Bt, i, ctx); + status |= gr_lil_mat_mul_vec(ct_row, A, bt_row, ctx); + } + return status; +} + +int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ctx_t ctx) +{ + slong ar, bc, i, j, sz; + int status; + + ar = gr_sparse_mat_nrows(A, ctx); + bc = gr_mat_ncols(B, ctx); + + if (gr_sparse_mat_ncols(A, ctx) != gr_mat_nrows(B, ctx) || ar != gr_mat_nrows(C, ctx) || bc != gr_mat_ncols(C, ctx)) + return GR_DOMAIN; + + if (gr_sparse_mat_is_zero(A, ctx)) + { + return gr_mat_zero(C, ctx); + } + + status = GR_SUCCESS; + + if (B == C) + { + GR_MAT_OOP_FN(status, C, ctx, gr_csr_mat_mul_mat, A, B); + return status; + } + + gr_mat_t Bt; + gr_mat_t Ct; + gr_method_void_unary_op set_shallow = GR_VOID_UNARY_OP(ctx, SET_SHALLOW); + + sz = ctx->sizeof_elem; + + TMP_INIT; + TMP_START; + _GR_MAT_INIT_SHALLOW_TRANSPOSE(Bt, B, sz); + _GR_MAT_INIT_SHALLOW_TRANSPOSE(Ct, C, sz); + + status |= gr_csr_mat_mul_mat_transpose(Ct, A, Bt, ctx); + + flint_free(Bt->rows); + flint_free(Ct->rows); + TMP_END; + return status; +} + +int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ctx_t ctx) +{ + slong ar, bc, i, j, sz; + int status; + + ar = gr_sparse_mat_nrows(A, ctx); + bc = gr_mat_ncols(B, ctx); + + if (gr_sparse_mat_ncols(A, ctx) != gr_mat_nrows(B, ctx) || ar != gr_mat_nrows(C, ctx) || bc != gr_mat_ncols(C, ctx)) + return GR_DOMAIN; + + if (gr_sparse_mat_is_zero(A, ctx)) + { + return gr_mat_zero(C, ctx); + } + + status = GR_SUCCESS; + + if (B == C) + { + GR_MAT_OOP_FN(status, C, ctx, gr_lil_mat_mul_mat, A, B); + return status; + } + + gr_mat_t Bt; + gr_mat_t Ct; + gr_method_void_unary_op set_shallow = GR_VOID_UNARY_OP(ctx, SET_SHALLOW); + + sz = ctx->sizeof_elem; + + TMP_INIT; + TMP_START; + _GR_MAT_INIT_SHALLOW_TRANSPOSE(Bt, B, sz); + _GR_MAT_INIT_SHALLOW_TRANSPOSE(Ct, C, sz); + + status |= gr_lil_mat_mul_mat_transpose(Ct, A, Bt, ctx); + + flint_free(Bt->rows); + flint_free(Ct->rows); + TMP_END; + return status; +} diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index cfd94de8b9..f4e1d831c4 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -97,12 +97,9 @@ int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx); - - slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulong *inds1, slong nnz1); - #define GR_SPV_SWAP_INDS(VEC, I, J, SZ, CTX) \ { \ slong _temp = (VEC)->inds[I]; \ @@ -111,10 +108,17 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo gr_swap(GR_ENTRY((VEC)->entries, (I), (SZ)), GR_ENTRY((VEC)->entries, (J), (SZ)), (CTX)); \ } - -/* This is used for operations like add which have to riffle through the entries of two vectors */ -/* It's an annoying macro that combines with the macros below. This is so we can handle */ -/* different arguments in different orders, etc */ +/* + Binary arithmetic operations on sparse vectors have a common pattern of + riffling through the two input vectors A_VEC and B_VEC to produce an + output vector DEST_VEC with indices in sorted order. As the iteration + proceeds, for a given index, we need one function FUNC_A if only A_VEC + has a nonzero element at that index, another function FUNC_B if only + B_VEC has a nonzero element, and a third function FUNC_AB if both are nonzero. + During this process, we maintain a triple of indices a_ind, b_ind, and + dest_ind, which are used when calling this macro to indicate what element(s) + to refer to when calling the appropriate function. +*/ #define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ int status; \ slong sz, new_nnz, a_ind, b_ind, dest_ind, a_nnz, b_nnz, i; \ @@ -169,45 +173,189 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo (DEST_VEC)->nnz = new_nnz; \ return status; -/* We need some convenience functions */ -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_neg_other(gr_ptr res, gr_srcptr src, gr_ctx_t src_ctx, gr_ctx_t ctx) { return (gr_set_other(res, src, src_ctx, ctx) | gr_neg(res, res, ctx)); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) { return (gr_mul(res, x, y, ctx) | gr_neg(res, res, ctx)); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx) { return (gr_mul_si(res, x, y, ctx) | gr_neg(res, res, ctx)); } +/* We need some convenience functions for certain simple operations. */ +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_neg_other(gr_ptr res, gr_srcptr src, gr_ctx_t src_ctx, gr_ctx_t ctx) +{ return (gr_set_other(res, src, src_ctx, ctx) | gr_neg(res, res, ctx)); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_negmul(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) +{ return (gr_mul(res, x, y, ctx) | gr_neg(res, res, ctx)); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_negmul_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx) +{ return (gr_mul_si(res, x, y, ctx) | gr_neg(res, res, ctx)); } -#define GR_SPV_RFL_UOP(F, Y, Y_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) -#define GR_SPV_RFL_BOP(F, Y, Y_ind, Z, Z_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) +// Convenience macros for applying a unary or binary function +#define GR_SPV_RFL_UOP(F, Y, Y_ind) \ + F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) +#define GR_SPV_RFL_BOP(F, Y, Y_ind, Z, Z_ind) \ + F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP(gr_set, src, b_ind), GR_SPV_RFL_UOP(gr_set, src, b_ind), res, res, src, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP(gr_set, src2, b_ind), GR_SPV_RFL_BOP(gr_add, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP(gr_neg, src2, b_ind), GR_SPV_RFL_BOP(gr_sub, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ + // All function are set to src value if possible, otherwise res value + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, res, a_ind), + GR_SPV_RFL_UOP(gr_set, src, b_ind), + GR_SPV_RFL_UOP(gr_set, src, b_ind), + res, res, src, ctx + ); +} +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, src1, a_ind), + GR_SPV_RFL_UOP(gr_set, src2, b_ind), + GR_SPV_RFL_BOP(gr_add, src1, a_ind, src2, b_ind), + res, src1, src2, ctx + ); +} + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, src1, a_ind), + GR_SPV_RFL_UOP(gr_neg, src2, b_ind), + GR_SPV_RFL_BOP(gr_sub, src1, a_ind, src2, b_ind), + res, src1, src2, ctx + ); +} + +// Need a unary function to assign zero #define GR_SPV_RFL_ZERO gr_zero(GR_ENTRY(res->entries, dest_ind, sz), ctx) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, GR_SPV_RFL_BOP(gr_mul, src1, a_ind, src2, b_ind), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_ZERO, + GR_SPV_RFL_ZERO, + GR_SPV_RFL_BOP(gr_mul, src1, a_ind, src2, b_ind), + res, src1, src2, ctx + ); +} + +// Analogous macros for applying a unary or binary function between two contexts +#define GR_SPV_RFL_UOP_OTHER(F, Y, Y_ind, CTX2) \ + F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), CTX2, ctx) +#define GR_SPV_RFL_BOP_OTHER(F, Y, Y_ind, Z, Z_ind, CTX2) \ + F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, CTX2->sizeof_elem), CTX2, ctx) +#define GR_SPV_RFL_OTHER_BOP(F, Y, Y_ind, CTX2, Z, Z_ind) \ + F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), (CTX2), GR_ENTRY(Z->entries, Z_ind, sz), ctx) -#define GR_SPV_RFL_UOP_OTHER(F, Y, Y_ind, CTX2) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), CTX2, ctx) -#define GR_SPV_RFL_BOP_OTHER(F, Y, Y_ind, Z, Z_ind, CTX2) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, CTX2->sizeof_elem), CTX2, ctx) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, src1, a_ind), + GR_SPV_RFL_UOP_OTHER(gr_set_other, src2, b_ind, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_add_other, src1, a_ind, src2, b_ind, ctx2), + res, src1, src2, ctx + ); +} + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, src1, a_ind), + GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_ind, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_sub_other, src1, a_ind, src2, b_ind, ctx2), + res, src1, src2, ctx + ); +} -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_set_other, src2, b_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_add_other, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, src1, a_ind), GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_ind, ctx2), GR_SPV_RFL_BOP_OTHER(gr_sub_other, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, GR_SPV_RFL_BOP_OTHER(gr_mul_other, src1, a_ind, src2, b_ind, ctx2), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_ZERO, + GR_SPV_RFL_ZERO, + GR_SPV_RFL_BOP_OTHER(gr_mul_other, src1, a_ind, src2, b_ind, ctx2), + res, src1, src2, ctx + ); +} + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), + GR_SPV_RFL_UOP(gr_set, src2, b_ind), + GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_ind, ctx1, src2, b_ind), + res, src1, src2, ctx + ); +} -#define GR_SPV_RFL_OTHER_BOP(F, Y, Y_ind, CTX2, Z, Z_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), (CTX2), GR_ENTRY(Z->entries, Z_ind, sz), ctx) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), + GR_SPV_RFL_UOP(gr_neg, src2, b_ind), + GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_ind, ctx1, src2, b_ind), + res, src1, src2, ctx + ); +} + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_other_mul_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_ZERO, + GR_SPV_RFL_ZERO, + GR_SPV_RFL_OTHER_BOP(gr_other_mul, src1, a_ind, ctx1, src2, b_ind), + res, src1, src2, ctx + ); +} + +#define GR_SPV_RFL_UOP_SCALAR(F, Y, Y_ind, C, CTX) \ + F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), C, CTX) + +/* + Subtemplate for doing accumulated operation from one sparse vector into another. + Used to do res += c * src and res -= c * src, for c a scalar. +*/ +#define GR_SPV_ACCUM_TEMPLATE(ELEM_OP, ELEM_ACCUM_OP, RES, SRC, C, CTX) \ + GR_SPV_RFL_TEMPLATE( \ + GR_SPV_RFL_UOP(gr_set, RES, a_ind), \ + GR_SPV_RFL_UOP_SCALAR(ELEM_OP, SRC, b_ind, C, CTX), \ + GR_SPV_RFL_UOP_SCALAR(ELEM_ACCUM_OP, SRC, b_ind, C, CTX), \ + RES, RES, SRC, CTX\ + ) -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), GR_SPV_RFL_UOP(gr_set, src2, b_ind), GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), GR_SPV_RFL_UOP(gr_neg, src2, b_ind), GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_mul_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, GR_SPV_RFL_OTHER_BOP(gr_other_mul, src1, a_ind, ctx1, src2, b_ind), res, src1, src2, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_addmul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_mul, gr_addmul, res, src, c, ctx) } -#define GR_SPV_RFL_UOP_SCALAR(F, Y, Y_ind) F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), c, ctx) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_submul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_negmul, gr_submul, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_mul, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_addmul, src, b_ind), res, res, src, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_negmul, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_submul, src, b_ind), res, res, src, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_mul_si, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_addmul_si, src, b_ind), res, res, src, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE(GR_SPV_RFL_UOP(gr_set, res, a_ind), GR_SPV_RFL_UOP_SCALAR(gr_negmul_si, src, b_ind), GR_SPV_RFL_UOP_SCALAR(gr_submul_si, src, b_ind), res, res, src, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_mul_si, gr_addmul_si, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) { return (gr_sparse_vec_set(res, src, ctx) | _gr_vec_neg(res->entries, res->entries, res->nnz, ctx)); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sum(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_sum(res, vec->entries, vec->nnz, ctx); } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_product(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_product(res, vec->entries, vec->nnz, ctx); } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_negmul_si, gr_submul_si, res, src, c, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ return (gr_sparse_vec_set(res, src, ctx) | _gr_vec_neg(res->entries, res->entries, res->nnz, ctx)); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_sum(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) +{ return _gr_vec_sum(res, vec->entries, vec->nnz, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_nz_product(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) +{ return _gr_vec_product(res, vec->entries, vec->nnz, ctx); } /* These are versions that incorporate a sparse into a dense */ @@ -222,26 +370,119 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_product(gr_ptr res, } \ return status; -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update_to_dense(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_set(GR_ENTRY(dres, src->inds[i], sz), GR_ENTRY(src->entries, i, sz), ctx), src, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_add(GR_ENTRY(dres, svec2->inds[i], sz), GR_ENTRY(dvec1, svec2->inds[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_sub(GR_ENTRY(dres, svec2->inds[i], sz), GR_ENTRY(dvec1, svec2->inds[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_mul_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_mul(GR_ENTRY(dres, svec2->inds[i], sz), GR_ENTRY(dvec1, svec2->inds[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_nz_div_to_dense(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_div(GR_ENTRY(dres, svec2->inds[i], sz), GR_ENTRY(dvec1, svec2->inds[i], sz), GR_ENTRY(svec2->entries, i, sz), ctx), svec2, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul_si(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul_si(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_addmul_fmpz(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_fmpz_to_dense(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) { GR_SPV_INTO_DENSE_TEMPLATE(gr_submul_fmpz(GR_ENTRY(dres, svec->inds[i], sz), GR_ENTRY(svec->entries, i, sz), c, ctx), svec, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_update_sparse_vec_nz(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ GR_SPV_INTO_DENSE_TEMPLATE(gr_set(GR_ENTRY(dres, src->inds[i], sz), GR_ENTRY(src->entries, i, sz), ctx), src, ctx) } -/***** TODO: +/* Sub-macro for applying operation (dense, sparse) -> dense */ -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, slong len, gr_ctx_t ctx) { return GR_SPARSE_VEC_DOT_OP(ctx, VEC_DOT)(res, initial, subtract, vec1, vec2, len, ctx); } +#define GR_SPV_OP_ON_DENSE_TEMPLATE(ELEM_OP, DRES, DVEC, SVEC, CTX) \ + GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(GR_ENTRY((DRES), (SVEC)->inds[i], sz), GR_ENTRY(DVEC, (SVEC)->inds[i], sz), GR_ENTRY((SVEC)->entries, i, sz), CTX), SVEC, CTX) -*/ +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_add_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) +{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_add, dres, dvec1, svec2, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_sub_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) +{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_sub, dres, dvec1, svec2, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_mul_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) +{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_mul, dres, dvec1, svec2, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_div_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) +{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_div, dres, dvec1, svec2, ctx) } + +/* Sub-macro for accumulating operation on dense from sparse */ + +#define GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(ELEM_OP, DRES, SVEC, C, CTX) \ + GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(GR_ENTRY(DRES, (SVEC)->inds[i], sz), GR_ENTRY((SVEC)->entries, i, sz), C, CTX), SVEC, CTX) + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_addmul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul, dres, svec, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_submul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul, dres, svec, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_addmul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul_si, dres, svec, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_submul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul_si, dres, svec, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_addmul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul_fmpz, dres, svec, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_submul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul_fmpz, dres, svec, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx) +{ + int status; + slong idx1, idx2; + slong sz = ctx->sizeof_elem; + + if (vec1->length != vec2->length) + { + return GR_DOMAIN; + } + status = gr_set(res, initial, ctx); + for (idx1 = 0, idx2 = 0; idx1 < vec1->nnz && idx2 < vec2->nnz; ) + { + if (vec1->inds[idx1] < vec2->inds[idx2]) + { + idx1++; + } + else if (vec1->inds[idx1] > vec2->inds[idx2]) + { + idx2++; + } + else if (subtract) + { + status |= gr_submul(res, GR_ENTRY(vec1->entries, idx1, sz), GR_ENTRY(vec2->entries, idx1, sz), ctx); + } + else + { + status |= gr_addmul(res, GR_ENTRY(vec1->entries, idx1, sz), GR_ENTRY(vec2->entries, idx1, sz), ctx); + } + } + return status; +} + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_dot_vec(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_vec_t vec2, gr_ctx_t ctx) +{ + int status; + slong idx; + slong sz = ctx->sizeof_elem; + + if (vec1->length != vec2->length) + { + return GR_DOMAIN; + } + status = gr_set(res, initial, ctx); + for (idx = 0; idx < vec1->nnz; idx++) + { + if (subtract) + { + status |= gr_submul(res, GR_ENTRY(vec1->entries, idx, sz), GR_ENTRY(vec2->entries, vec1->inds[idx], sz), ctx); + } + else + { + status |= gr_addmul(res, GR_ENTRY(vec1->entries, idx, sz), GR_ENTRY(vec2->entries, vec1->inds[idx], sz), ctx); + } + } + return status; +} #define GR_SPARSE_VEC_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) \ if(res->length != src->length) \ @@ -256,22 +497,69 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_src } \ return dense_vec_op(res->entries, src->entries, src->nnz, c, ctx); \ -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) { GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_div_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_div_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } From 26cd947c2191cb07e5a474e5a676c39f410f3ed5 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Mon, 18 Mar 2024 03:26:01 -0700 Subject: [PATCH 31/59] Fixed documentation --- doc/source/gr_sparse_vec.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index 77d6af718f..03d5fff894 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -20,13 +20,13 @@ Types and basic access This struct contains: - * A pointer to an `slong` array of column indices (``cols``) of nonzeros (we think of the vector as a row) + * A pointer to an `slong` array of indices (``inds``) of nonzeros. * A :type:`gr_ptr` array of values of nonzeros (``entries``). - * `slong` values to record the number of nonzeros (``nnz``), the nominal length of the vector (the dimension of the vector space) (``length``), and the space allocated in the ``cols`` and ``entries`` arrays. + * `slong` values to record the number of nonzeros (``nnz``), the nominal length of the vector (the dimension of the vector space) (``length``), and the space allocated in the ``inds`` and ``entries`` arrays. We always require: - * The ``cols`` are sorted into strictly increasing order + * The ``inds`` are sorted into strictly increasing order * The ``entries`` are nonzero (meaning, ``gr_is_zero(GR_ENTRY(vec->entries, i, ctx->sizeof_elem), ctx)`` returns ``T_FALSE`` for ``0 <= i < vec->nnz``). * We have ``nnz <= alloc <= length``. @@ -112,16 +112,16 @@ Getting, setting and conversion in *src* are overwritten with their values in *src*. Any columns in *res* which do not appear in *src* are left unchanged. -.. function:: int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) - Set *vec* to the sparse data given by *cols* and *entries* of length *nnz*. No assumption + Set *vec* to the sparse data given by *inds* and *entries* of length *nnz*. No assumption is made that the columns are sorted nor that the entries are nonzero. The values associated with duplicate columns are added together. -.. function:: int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) - Set *vec* to the sparse data given by *sorted_deduped_cols* and *entries*. The - *sorted_deduped_cols* must be in strictly increasing order. It is not required + Set *vec* to the sparse data given by *sorted_deduped_inds* and *entries*. The + *sorted_deduped_inds* must be in strictly increasing order. It is not required that the values in *entries* are nonzero. .. function:: int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) @@ -152,7 +152,7 @@ Getting, setting and conversion Column indices are shifted by *col_start* (a column index of ``col_start`` would become ``0``). -.. function:: int gr_sparse_vec_permute_cols(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) Set *vec* to a copy of *src* with the columns permuted. The column indices are shifted as: ``vec[p[i]] = src[i]``. From 98ecdf75e4bcef725e40f825953904fffd8024c6 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Mon, 18 Mar 2024 03:34:22 -0700 Subject: [PATCH 32/59] Bug fixes --- src/gr_sparse_vec/test/main.c | 2 +- src/gr_sparse_vec/test/t-creation.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gr_sparse_vec/test/main.c b/src/gr_sparse_vec/test/main.c index 4a505df0db..ef0e9322bb 100644 --- a/src/gr_sparse_vec/test/main.c +++ b/src/gr_sparse_vec/test/main.c @@ -16,4 +16,4 @@ test_struct tests[] = /* main function *************************************************************/ -TEST_MAIN(tests) \ No newline at end of file +TEST_MAIN(tests) diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c index 2503a232bf..a4fc5e963f 100644 --- a/src/gr_sparse_vec/test/t-creation.c +++ b/src/gr_sparse_vec/test/t-creation.c @@ -51,7 +51,7 @@ test_init_from_entries_unsorted_internal(ulong *inds, gr_srcptr entries, slong l /* Yes, this is quadratic time just to be careful */ int status = GR_SUCCESS; slong sz = ctx->sizeof_elem; - slong i,j,col; + slong i,j; gr_sparse_vec_t vec; gr_ptr temp, temp2; GR_TMP_INIT2(temp, temp2, ctx); From 5da944655a7319732c51acc18ce6f9c07cf85076 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Mon, 18 Mar 2024 03:47:24 -0700 Subject: [PATCH 33/59] Changed more col to ind, ind to nzidx --- doc/source/gr_sparse_vec.rst | 38 +++++----- src/gr_sparse_vec.h | 130 +++++++++++++++++------------------ 2 files changed, 84 insertions(+), 84 deletions(-) diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index 03d5fff894..ab6959e99c 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -42,9 +42,9 @@ Types and basic access Clears the vector *vec* -.. macro:: GR_SPARSE_VEC_COL(vec, i) +.. macro:: GR_SPARSE_VEC_IND(vec, i) - Access the column index of the *i*-th nonzero. + Access the index of the *i*-th nonzero. There is no bounds checking. (See also `gr_sparse_vec_find_entry`) .. macro:: GR_SPARSE_VEC_ENTRY(vec, i, sz) @@ -52,12 +52,12 @@ Types and basic access Access the value of the *i*-th nonzero. There is no bounds checking. (See also `gr_sparse_vec_find_entry`) -.. function:: ulong * gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) - const ulong * gr_sparse_vec_col_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) +.. function:: ulong * gr_sparse_vec_ind_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) + const ulong * gr_sparse_vec_ind_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) - Get pointers to the column indices and entries. + Get pointers to the specified indices and entries. .. function:: void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) @@ -75,7 +75,7 @@ Types and basic access .. function:: void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) Set the nominal length of the vector *vec* to *len*. If *len* is smaller than - the current length of *vec*, any entries whose column indices are at least *len* + the current length of *vec*, any entries whose indices are at least *len* are truncated. That is, the number of nonzeros can change. .. function:: slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) @@ -90,33 +90,33 @@ Getting, setting and conversion Copy *src* to a copy of *res* -.. function:: int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong ind, gr_srcptr entry, gr_ctx_t ctx) - Set the the value at column *col* to be *entry*. Because of the way sparse + Set the the value at index *ind* to be *entry*. Because of the way sparse vectors are represented, it is not efficient to call this function repeatedly (it is linear time in the number of nonzeros in *vec*). If possible, the entries to update should be batched up and given using `gr_sparse_vec_update`, `gr_sparse_vec_set_from_entries`, or `gr_sparse_vec_set_from_entries_sorted_deduped`. -.. function:: int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx) - Set *res* to be the entry at column *col*. If *col* is not a column + Set *res* to be the entry at index *ind*. If *ind* is not a index in which *vec* contains a nonzero, *res* is set to zero. Because of the way sparse vectors are represented, this is not constant time. (It is log time in the number of nonzeros in *vec*.) .. function:: int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) - Update *res* with the nonzeros in *src*. That is, any columns in *res* which also appear - in *src* are overwritten with their values in *src*. Any columns in *res* which do + Update *res* with the nonzeros in *src*. That is, any index in *res* which also appear + in *src* are overwritten with their values in *src*. Any indices in *res* which do not appear in *src* are left unchanged. .. function:: int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) Set *vec* to the sparse data given by *inds* and *entries* of length *nnz*. No assumption - is made that the columns are sorted nor that the entries are nonzero. The values associated - with duplicate columns are added together. + is made that the indices are sorted nor that the entries are nonzero. The values associated + with duplicate indices are added together. .. function:: int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) @@ -132,7 +132,7 @@ Getting, setting and conversion Initialize *vec* to a random vector with density (fraction of nonzeros) *density* and length *len*. The algorithm is suitable when *density* is small. - Specifically, column indices are generated randomly and deduped. So if the + Specifically, indices are generated randomly and deduped. So if the density is larger than ``1/sqrt(len)``, the true density of the returned vector is likely to be lower than *density*. @@ -145,16 +145,16 @@ Getting, setting and conversion Convert the sparse vector *src* into a dense vector *vec*, which must have sufficient space (i.e. ``vec->length``). -.. function:: int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong ind_start, slong ind_end, gr_ctx_t ctx) Set *res* to a copy of the slice of *src* given by any entries whose - column indices lie in the half open interval ``[col_start, col_end)``. - Column indices are shifted by *col_start* (a column index of ``col_start`` + indices lie in the half open interval ``[ind_start, ind_end)``. + Column indices are shifted by *ind_start* (a index of ``ind_start`` would become ``0``). .. function:: int gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) - Set *vec* to a copy of *src* with the columns permuted. The column + Set *vec* to a copy of *src* with the indices permuted. The indices are shifted as: ``vec[p[i]] = src[i]``. diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index f4e1d831c4..5a8aa886e5 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -54,13 +54,13 @@ gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) memset(vec, 0, sizeof(gr_sparse_vec_t)); } -#define GR_SPARSE_VEC_COL(vec, i) (vec)->inds[i] -#define GR_SPARSE_VEC_ENTRY(vec, i, sz) GR_ENTRY((vec)->entries, i, sz) +#define GR_SPARSE_VEC_IND(vec, nzidx) (vec)->inds[nzidx] +#define GR_SPARSE_VEC_ENTRY(vec, nzidx, sz) GR_ENTRY((vec)->entries, nzidx, sz) -GR_SPARSE_VEC_INLINE ulong * gr_sparse_vec_col_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->inds + i; } -GR_SPARSE_VEC_INLINE const ulong * gr_sparse_vec_col_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return vec->inds + i; } -GR_SPARSE_VEC_INLINE gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); } -GR_SPARSE_VEC_INLINE gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, i, ctx->sizeof_elem); } +GR_SPARSE_VEC_INLINE ulong * gr_sparse_vec_ind_ptr(gr_sparse_vec_t vec, slong nzidx, gr_ctx_t ctx) { return vec->inds + nzidx; } +GR_SPARSE_VEC_INLINE const ulong * gr_sparse_vec_ind_srcptr(const gr_sparse_vec_t vec, slong nzidx, gr_ctx_t ctx) { return vec->inds + nzidx; } +GR_SPARSE_VEC_INLINE gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong nzidx, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, nzidx, ctx->sizeof_elem); } +GR_SPARSE_VEC_INLINE gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong nzidx, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, nzidx, ctx->sizeof_elem); } void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx); void gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx); @@ -83,11 +83,11 @@ GR_SPARSE_VEC_INLINE void gr_sparse_vec_swap(gr_sparse_vec_t res, gr_sparse_vec_ GR_SPARSE_VEC_INLINE void gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; } WARN_UNUSED_RESULT int gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong ind_start, slong ind_end, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong ind, gr_srcptr entry, gr_ctx_t ctx); truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx); GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return (vec->nnz == 0 ? T_TRUE : T_FALSE); } @@ -115,14 +115,14 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo proceeds, for a given index, we need one function FUNC_A if only A_VEC has a nonzero element at that index, another function FUNC_B if only B_VEC has a nonzero element, and a third function FUNC_AB if both are nonzero. - During this process, we maintain a triple of indices a_ind, b_ind, and + During this process, we maintain a triple of indices a_nzidx, b_nzidx, and dest_ind, which are used when calling this macro to indicate what element(s) to refer to when calling the appropriate function. */ #define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ int status; \ - slong sz, new_nnz, a_ind, b_ind, dest_ind, a_nnz, b_nnz, i; \ - ulong a_col, b_col; \ + slong sz, new_nnz, a_nzidx, b_nzidx, dest_ind, a_nnz, b_nnz, i; \ + ulong a_ind, b_ind; \ if ((DEST_VEC)->length != (A_VEC)->length || (A_VEC)->length != (B_VEC)->length) \ return GR_DOMAIN; \ status = GR_SUCCESS; \ @@ -132,31 +132,31 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo new_nnz = _gr_sparse_vec_count_unique_inds((A_VEC)->inds, a_nnz, (B_VEC)->inds, b_nnz); \ gr_sparse_vec_fit_nnz((DEST_VEC), new_nnz, (CTX)); \ /* We go backward through the destination, because it might be an in-place operation on a source */ \ - a_ind = a_nnz-1; \ - b_ind = b_nnz-1; \ + a_nzidx = a_nnz-1; \ + b_nzidx = b_nnz-1; \ dest_ind = new_nnz-1; \ - while (a_ind >= 0 && b_ind >= 0 && status == GR_SUCCESS) \ + while (a_nzidx >= 0 && b_nzidx >= 0 && status == GR_SUCCESS) \ { \ - a_col = (A_VEC)->inds[a_ind]; \ - b_col = (B_VEC)->inds[b_ind]; \ - if (a_col > b_col) \ + a_ind = (A_VEC)->inds[a_nzidx]; \ + b_ind = (B_VEC)->inds[b_nzidx]; \ + if (a_ind > b_ind) \ { \ status |= (FUNC_A); \ - (DEST_VEC)->inds[dest_ind] = a_col; \ - a_ind--; \ + (DEST_VEC)->inds[dest_ind] = a_ind; \ + a_nzidx--; \ } \ - else if (b_col > a_col) \ + else if (b_ind > a_ind) \ { \ status |= (FUNC_B); \ - (DEST_VEC)->inds[dest_ind] = b_col; \ - b_ind--; \ + (DEST_VEC)->inds[dest_ind] = b_ind; \ + b_nzidx--; \ } \ else \ { \ status |= (FUNC_AB); \ - (DEST_VEC)->inds[dest_ind] = a_col; \ - a_ind--; \ - b_ind--; \ + (DEST_VEC)->inds[dest_ind] = a_ind; \ + a_nzidx--; \ + b_nzidx--; \ } \ if (T_TRUE != gr_is_zero(GR_ENTRY((DEST_VEC)->entries, dest_ind, sz), (CTX))) \ dest_ind--; \ @@ -197,9 +197,9 @@ gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ct { // All function are set to src value if possible, otherwise res value GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, res, a_ind), - GR_SPV_RFL_UOP(gr_set, src, b_ind), - GR_SPV_RFL_UOP(gr_set, src, b_ind), + GR_SPV_RFL_UOP(gr_set, res, a_nzidx), + GR_SPV_RFL_UOP(gr_set, src, b_nzidx), + GR_SPV_RFL_UOP(gr_set, src, b_nzidx), res, res, src, ctx ); } @@ -208,9 +208,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_ind), - GR_SPV_RFL_UOP(gr_set, src2, b_ind), - GR_SPV_RFL_BOP(gr_add, src1, a_ind, src2, b_ind), + GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), + GR_SPV_RFL_UOP(gr_set, src2, b_nzidx), + GR_SPV_RFL_BOP(gr_add, src1, a_nzidx, src2, b_nzidx), res, src1, src2, ctx ); } @@ -219,9 +219,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_ind), - GR_SPV_RFL_UOP(gr_neg, src2, b_ind), - GR_SPV_RFL_BOP(gr_sub, src1, a_ind, src2, b_ind), + GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), + GR_SPV_RFL_UOP(gr_neg, src2, b_nzidx), + GR_SPV_RFL_BOP(gr_sub, src1, a_nzidx, src2, b_nzidx), res, src1, src2, ctx ); } @@ -235,7 +235,7 @@ gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_spar GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, - GR_SPV_RFL_BOP(gr_mul, src1, a_ind, src2, b_ind), + GR_SPV_RFL_BOP(gr_mul, src1, a_nzidx, src2, b_nzidx), res, src1, src2, ctx ); } @@ -252,9 +252,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_ind), - GR_SPV_RFL_UOP_OTHER(gr_set_other, src2, b_ind, ctx2), - GR_SPV_RFL_BOP_OTHER(gr_add_other, src1, a_ind, src2, b_ind, ctx2), + GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), + GR_SPV_RFL_UOP_OTHER(gr_set_other, src2, b_nzidx, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_add_other, src1, a_nzidx, src2, b_nzidx, ctx2), res, src1, src2, ctx ); } @@ -263,9 +263,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_ind), - GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_ind, ctx2), - GR_SPV_RFL_BOP_OTHER(gr_sub_other, src1, a_ind, src2, b_ind, ctx2), + GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), + GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_nzidx, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_sub_other, src1, a_nzidx, src2, b_nzidx, ctx2), res, src1, src2, ctx ); } @@ -276,7 +276,7 @@ gr_sparse_vec_mul_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const g GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, - GR_SPV_RFL_BOP_OTHER(gr_mul_other, src1, a_ind, src2, b_ind, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_mul_other, src1, a_nzidx, src2, b_nzidx, ctx2), res, src1, src2, ctx ); } @@ -285,9 +285,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), - GR_SPV_RFL_UOP(gr_set, src2, b_ind), - GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_ind, ctx1, src2, b_ind), + GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_nzidx, ctx1), + GR_SPV_RFL_UOP(gr_set, src2, b_nzidx), + GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_nzidx, ctx1, src2, b_nzidx), res, src1, src2, ctx ); } @@ -296,9 +296,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_ind, ctx1), - GR_SPV_RFL_UOP(gr_neg, src2, b_ind), - GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_ind, ctx1, src2, b_ind), + GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_nzidx, ctx1), + GR_SPV_RFL_UOP(gr_neg, src2, b_nzidx), + GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_nzidx, ctx1, src2, b_nzidx), res, src1, src2, ctx ); } @@ -309,7 +309,7 @@ gr_other_mul_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_ GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, - GR_SPV_RFL_OTHER_BOP(gr_other_mul, src1, a_ind, ctx1, src2, b_ind), + GR_SPV_RFL_OTHER_BOP(gr_other_mul, src1, a_nzidx, ctx1, src2, b_nzidx), res, src1, src2, ctx ); } @@ -323,9 +323,9 @@ gr_other_mul_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_ */ #define GR_SPV_ACCUM_TEMPLATE(ELEM_OP, ELEM_ACCUM_OP, RES, SRC, C, CTX) \ GR_SPV_RFL_TEMPLATE( \ - GR_SPV_RFL_UOP(gr_set, RES, a_ind), \ - GR_SPV_RFL_UOP_SCALAR(ELEM_OP, SRC, b_ind, C, CTX), \ - GR_SPV_RFL_UOP_SCALAR(ELEM_ACCUM_OP, SRC, b_ind, C, CTX), \ + GR_SPV_RFL_UOP(gr_set, RES, a_nzidx), \ + GR_SPV_RFL_UOP_SCALAR(ELEM_OP, SRC, b_nzidx, C, CTX), \ + GR_SPV_RFL_UOP_SCALAR(ELEM_ACCUM_OP, SRC, b_nzidx, C, CTX), \ RES, RES, SRC, CTX\ ) @@ -428,7 +428,7 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx) { int status; - slong idx1, idx2; + slong nzidx1, nzidx2; slong sz = ctx->sizeof_elem; if (vec1->length != vec2->length) @@ -436,23 +436,23 @@ gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_v return GR_DOMAIN; } status = gr_set(res, initial, ctx); - for (idx1 = 0, idx2 = 0; idx1 < vec1->nnz && idx2 < vec2->nnz; ) + for (nzidx1 = 0, nzidx2 = 0; nzidx1 < vec1->nnz && nzidx2 < vec2->nnz; ) { - if (vec1->inds[idx1] < vec2->inds[idx2]) + if (vec1->inds[nzidx1] < vec2->inds[nzidx2]) { - idx1++; + nzidx1++; } - else if (vec1->inds[idx1] > vec2->inds[idx2]) + else if (vec1->inds[nzidx1] > vec2->inds[nzidx2]) { - idx2++; + nzidx2++; } else if (subtract) { - status |= gr_submul(res, GR_ENTRY(vec1->entries, idx1, sz), GR_ENTRY(vec2->entries, idx1, sz), ctx); + status |= gr_submul(res, GR_ENTRY(vec1->entries, nzidx1, sz), GR_ENTRY(vec2->entries, nzidx1, sz), ctx); } else { - status |= gr_addmul(res, GR_ENTRY(vec1->entries, idx1, sz), GR_ENTRY(vec2->entries, idx1, sz), ctx); + status |= gr_addmul(res, GR_ENTRY(vec1->entries, nzidx1, sz), GR_ENTRY(vec2->entries, nzidx1, sz), ctx); } } return status; @@ -462,7 +462,7 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_dot_vec(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_vec_t vec2, gr_ctx_t ctx) { int status; - slong idx; + slong nzidx; slong sz = ctx->sizeof_elem; if (vec1->length != vec2->length) @@ -470,15 +470,15 @@ gr_sparse_vec_dot_vec(gr_ptr res, gr_srcptr initial, int subtract, const gr_spar return GR_DOMAIN; } status = gr_set(res, initial, ctx); - for (idx = 0; idx < vec1->nnz; idx++) + for (nzidx = 0; nzidx < vec1->nnz; nzidx++) { if (subtract) { - status |= gr_submul(res, GR_ENTRY(vec1->entries, idx, sz), GR_ENTRY(vec2->entries, vec1->inds[idx], sz), ctx); + status |= gr_submul(res, GR_ENTRY(vec1->entries, nzidx, sz), GR_ENTRY(vec2->entries, vec1->inds[nzidx], sz), ctx); } else { - status |= gr_addmul(res, GR_ENTRY(vec1->entries, idx, sz), GR_ENTRY(vec2->entries, vec1->inds[idx], sz), ctx); + status |= gr_addmul(res, GR_ENTRY(vec1->entries, nzidx, sz), GR_ENTRY(vec2->entries, vec1->inds[nzidx], sz), ctx); } } return status; From 4eb5ca1e797698a1fcd5fcc5c884ec34ba0fda7a Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Mon, 18 Mar 2024 03:55:57 -0700 Subject: [PATCH 34/59] Updated sparse vector docs --- doc/source/gr_sparse_vec.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index ab6959e99c..0eedbf56a8 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -80,7 +80,7 @@ Types and basic access .. function:: slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) - Get the number of nonzeros in *vec* + Get the number of nonzeros in *vec*. Getting, setting and conversion @@ -88,7 +88,7 @@ Getting, setting and conversion .. function:: int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) - Copy *src* to a copy of *res* + Set *src* to a copy of *res*. .. function:: int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong ind, gr_srcptr entry, gr_ctx_t ctx) @@ -235,12 +235,13 @@ Arithmetic into dense vectors int gr_vec_submul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) These functions facilitate accumulating a sparse vector into a dense - target. They have one dense input, one sparse input, and a dense output. + target. They have one dense input, one sparse input, and a dense output + (where the dense input and output are the same for the fused operations). For all functions, it is assumed that *dres* and *dvec1* have the same - length as *svec* or *svec2*, as appropriate. The functions - ``gr_vec_update_sparse_vec_nz()`` (overwrite the entries in *dres*), - ``gr_vec_mul_sparse_vec_nz()``, and ``gr_vec_div_sparse_vec_nz()`` - only operate on the locations for which *svec2* is nonzero. + length as *svec* or *svec2*, as appropriate. All functions only modify + the locations in *dres* at which the sparse vector has a nonzero value: + in particular, the functions *gr_vec_mul_sparse_vec_nz* and + *gr_vec_div_sparse_vec_nz* behave very differently from their dense counterparts. Componentwise multiplication and division @@ -286,9 +287,9 @@ Dot products Set *res* equal to `c \pm x \cdot y`. -.. function:: int gr_sparse_vec_dot_rev(gr_ptr res, gr_srcptr c, int subtract, const gr_sparse_vec_t x, const gr_sparse_vec_t y, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_dot_vec(gr_ptr res, gr_srcptr c, int subtract, const gr_sparse_vec_t x, const gr_vec_t y, gr_ctx_t ctx) - Set *res* equal to `c \pm \sum_{i=0}^{n-1}x_iy_{n-1-i}`. + Set *res* equal to `c \pm x \cdot y`. From 34908edfa8581f1ca1a35551ae7f1d0a0a330f11 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Mon, 18 Mar 2024 16:26:26 -0700 Subject: [PATCH 35/59] Finished basic API analogous to sparse vector --- doc/source/gr_mat.rst | 10 +- src/fmpz_mod_mat/det.c | 2 +- src/gr_mat.h | 14 +- src/gr_sparse_mat.h | 438 ++++++++++++++---- src/gr_sparse_mat/equal.c | 84 ++-- src/gr_sparse_mat/fit_nnz.c | 26 ++ src/gr_sparse_mat/invert_rows.c | 48 +- src/gr_sparse_mat/is_neg_one.c | 53 +-- src/gr_sparse_mat/is_one.c | 53 +-- src/gr_sparse_mat/mul.c | 12 +- src/gr_sparse_mat/set.c | 68 ++- src/gr_sparse_vec.h | 12 +- src/gr_sparse_vec/equal.c | 44 +- .../{find_entry.c => get_entry.c} | 2 +- src/gr_sparse_vec/set_entry.c | 49 +- src/gr_sparse_vec/write.c | 6 +- 16 files changed, 666 insertions(+), 255 deletions(-) rename src/gr_sparse_vec/{find_entry.c => get_entry.c} (87%) diff --git a/doc/source/gr_mat.rst b/doc/source/gr_mat.rst index 1a0c75aef5..00ff192a4b 100644 --- a/doc/source/gr_mat.rst +++ b/doc/source/gr_mat.rst @@ -199,20 +199,26 @@ Basic row, column and entry operations ``c`` is the number of columns of ``mat``. If ``perm`` is non-``NULL``, the permutation of the columns will also be applied to ``perm``. -.. function:: truth_t gr_mat_is_empty(const gr_mat_t mat, gr_ctx_t ctx) +.. macro:: gr_mat_is_empty(mat, ctx) Returns whether *mat* is an empty matrix, having either zero rows or zero column. This predicate is always decidable (even if the underlying ring is not computable), returning ``T_TRUE`` or ``T_FALSE``. -.. function:: truth_t gr_mat_is_square(const gr_mat_t mat, gr_ctx_t ctx) +.. macro:: gr_mat_is_square(mat, ctx) Returns whether *mat* is a square matrix, having the same number of rows as columns (not the same thing as being a perfect square!). This predicate is always decidable (even if the underlying ring is not computable), returning ``T_TRUE`` or ``T_FALSE``. +.. macro:: gr_mat_is_compatible(mat1, mat2, ctx) + + Returns whether *mat1* and *mat2* have the same dimensions. + This predicate is always decidable (even if the underlying ring + is not computable), returning ``T_TRUE`` or ``T_FALSE``. + Arithmetic ------------------------------------------------------------------------------- diff --git a/src/fmpz_mod_mat/det.c b/src/fmpz_mod_mat/det.c index d0b9844247..d015cd56b1 100644 --- a/src/fmpz_mod_mat/det.c +++ b/src/fmpz_mod_mat/det.c @@ -39,4 +39,4 @@ void fmpz_mod_mat_det(fmpz_t res, const fmpz_mod_mat_t mat, const fmpz_mod_ctx_t GR_MUST_SUCCEED(gr_mat_det_berkowitz(res, (const gr_mat_struct *) mat, gr_ctx)); } } -} \ No newline at end of file +} diff --git a/src/gr_mat.h b/src/gr_mat.h index 6b660cdccc..fb34988bc3 100644 --- a/src/gr_mat.h +++ b/src/gr_mat.h @@ -99,17 +99,9 @@ WARN_UNUSED_RESULT int gr_mat_randops(gr_mat_t mat, flint_rand_t state, slong co WARN_UNUSED_RESULT int gr_mat_randpermdiag(int * parity, gr_mat_t mat, flint_rand_t state, gr_ptr diag, slong n, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_mat_randrank(gr_mat_t mat, flint_rand_t state, slong rank, gr_ctx_t ctx); -GR_MAT_INLINE truth_t -gr_mat_is_empty(const gr_mat_t mat, gr_ctx_t ctx) -{ - return ((mat->r == 0) || (mat->c == 0)) ? T_TRUE : T_FALSE; -} - -GR_MAT_INLINE truth_t -gr_mat_is_square(const gr_mat_t mat, gr_ctx_t ctx) -{ - return (mat->r == mat->c) ? T_TRUE : T_FALSE; -} +#define gr_mat_is_compatible(mat1, mat2, ctx) (((mat1)->r == (mat2)->r && (mat1)->c == (mat2)->c) ? T_TRUE : T_FALSE) +#define gr_mat_is_empty(mat, ctx) ((((mat)->r == 0) || ((mat)->c == 0)) ? T_TRUE : T_FALSE) +#define gr_mat_is_square(mat, ctx) (((mat)->r == (mat)->c) ? T_TRUE : T_FALSE) truth_t gr_mat_equal(const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx); truth_t gr_mat_is_zero(const gr_mat_t mat, gr_ctx_t ctx); diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 701e1a59a6..7d33b49199 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -15,7 +15,7 @@ #ifdef GR_SPARSE_MAT_INLINES_C #define GR_SPARSE_MAT_INLINE #else -#define GR_SPARSE_MAT_INLINE static __inline__ +#define GR_SPARSE_MAT_INLINE static inline #endif #include "gr.h" @@ -27,6 +27,10 @@ extern "C" { #endif +/** + * Types and basic access +**/ + typedef struct { slong r; @@ -57,25 +61,48 @@ typedef gr_lil_mat_struct gr_lil_mat_t[1]; #define gr_sparse_mat_ncols(mat, ctx) ((mat)->c) #define gr_sparse_mat_nnz(mat, ctx) ((mat)->nnz) +#define GR_CSR_MAT_COL(mat,i,j) ((mat)->cols + (mat)->rows[i] + j) +#define GR_LIL_MAT_COL(mat,i,j) ((mat)->rows[i]->inds + j) + #define GR_CSR_MAT_ENTRY(mat,i,j,sz) GR_ENTRY((mat)->entries, (mat)->rows[i] + j, sz) #define GR_LIL_MAT_ENTRY(mat,i,j,sz) GR_ENTRY((mat)->rows[i]->entries, j, sz) -GR_SPARSE_MAT_INLINE gr_ptr gr_csr_mat_value_ptr(gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE ulong * gr_csr_mat_col_ptr(gr_csr_mat_t mat, slong i, slong j) +{ + return GR_CSR_MAT_COL(mat, i, j); +} + +GR_SPARSE_MAT_INLINE const ulong * gr_csr_mat_col_srcptr(const gr_csr_mat_t mat, slong i, slong j) +{ + return GR_CSR_MAT_COL(mat, i, j); +} + +GR_SPARSE_MAT_INLINE ulong * gr_lil_mat_col_ptr(gr_lil_mat_t mat, slong i, slong j) +{ + return GR_LIL_MAT_COL(mat, i, j); +} + +GR_SPARSE_MAT_INLINE const ulong * gr_lil_mat_col_srcptr(const gr_lil_mat_t mat, slong i, slong j) +{ + return GR_LIL_MAT_COL(mat, i, j); +} + +GR_SPARSE_MAT_INLINE gr_ptr gr_csr_mat_entry_ptr(gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) { return GR_CSR_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); } -GR_SPARSE_MAT_INLINE gr_srcptr gr_csr_mat_value_srcptr(const gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE gr_srcptr gr_csr_mat_entry_srcptr(const gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) { return GR_CSR_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); } -GR_SPARSE_MAT_INLINE gr_ptr gr_lil_mat_value_ptr(gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE gr_ptr gr_lil_mat_entry_ptr(gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) { return GR_LIL_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); } -GR_SPARSE_MAT_INLINE gr_srcptr gr_lil_mat_value_srcptr(const gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE gr_srcptr gr_lil_mat_entry_srcptr(const gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) { return GR_LIL_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); } @@ -113,9 +140,102 @@ gr_lil_mat_init(gr_lil_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) { mat->rows = flint_calloc(rows, sizeof(gr_sparse_vec_t)); } +GR_SPARSE_MAT_INLINE void +gr_csr_mat_clear(gr_csr_mat_t mat, gr_ctx_t ctx) { + if (mat->alloc != 0) + { + _gr_vec_clear(mat->entries, mat->alloc, ctx); + flint_free(mat->entries); + flint_free(mat->cols); + } + flint_free(mat->rows); + memset(mat, 0, sizeof(gr_csr_mat_t)); +} + +GR_SPARSE_MAT_INLINE void +gr_lil_mat_clear(gr_lil_mat_t mat, gr_ctx_t ctx) { + int row; + + for (row = 0; row < mat->r; ++row) { + gr_sparse_vec_clear(mat->rows[row], ctx); + } + flint_free(mat->rows); + memset(mat, 0, sizeof(gr_lil_mat_t)); +} + +GR_SPARSE_MAT_INLINE void +gr_csr_mat_swap(gr_csr_mat_t mat1, gr_csr_mat_t mat2, gr_ctx_t ctx) +{ + FLINT_SWAP(gr_csr_mat_struct, *mat1, *mat2); +} + +GR_SPARSE_MAT_INLINE void +gr_lil_mat_swap(gr_lil_mat_t mat1, gr_lil_mat_t mat2, gr_ctx_t ctx) +{ + FLINT_SWAP(gr_lil_mat_struct, *mat1, *mat2); +} + void gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx); +void +gr_csr_mat_shrink_to_nnz(gr_csr_mat_t mat, gr_ctx_t ctx); + +void +gr_lil_mat_shrink_to_nnz(gr_lil_mat_t mat, gr_ctx_t ctx); + +void +gr_csr_mat_set_cols(gr_csr_mat_t mat, slong cols, gr_ctx_t ctx); + +void +gr_lil_mat_set_cols(gr_lil_mat_t mat, slong cols, gr_ctx_t ctx); + +/** + * Getting, setting, and conversion +**/ + +GR_SPARSE_MAT_INLINE void +_gr_csr_mat_borrow_row(gr_sparse_vec_t res, const gr_csr_mat_t mat, slong r, gr_ctx_t ctx) { + ulong offset; + + offset = mat->rows[r]; + res->nnz = mat->rows[r+1] - offset; + res->alloc = res->nnz; + res->inds = mat->cols + offset; + res->length = mat->c; + res->entries = GR_ENTRY(mat->entries, offset, ctx->sizeof_elem); +} + +WARN_UNUSED_RESULT int +gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t vec, slong row, slong col, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t vec, slong row, slong col, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_csr_mat_set_entry(gr_csr_mat_t vec, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_set_entry(gr_lil_mat_t vec, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); + + +GR_SPARSE_MAT_INLINE void +gr_csr_mat_zero(gr_csr_mat_t res, gr_ctx_t ctx) { + res->nnz = 0; + memset(res->rows, 0, (res->r + 1) * sizeof(ulong)); +} + +GR_SPARSE_MAT_INLINE void +gr_lil_mat_zero(gr_lil_mat_t res, gr_ctx_t ctx) { + int row; + + res->nnz = 0; + for(row = 0; row < res->r; ++row) + { + gr_sparse_vec_zero(res->rows[row], ctx); + } +} + WARN_UNUSED_RESULT int gr_csr_mat_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); @@ -128,6 +248,12 @@ gr_csr_mat_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int +gr_csr_mat_set_mat(gr_csr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_set_mat(gr_lil_mat_t res, const gr_mat_t mat, gr_ctx_t ctx); + WARN_UNUSED_RESULT int gr_mat_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); @@ -160,6 +286,20 @@ gr_lil_mat_init_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t c return gr_lil_mat_set_csr_mat(res, mat, ctx); } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_csr_mat_init_set_mat(gr_csr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) +{ + gr_csr_mat_init(res, mat->r, mat->c, ctx); + return gr_csr_mat_set_mat(res, mat, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_init_set_mat(gr_lil_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) +{ + gr_lil_mat_init(res, mat->r, mat->c, ctx); + return gr_lil_mat_set_mat(res, mat, ctx); +} + GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_mat_init_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) { @@ -174,76 +314,78 @@ gr_mat_init_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) return gr_mat_set_lil_mat(res, mat, ctx); } -GR_SPARSE_MAT_INLINE void -gr_csr_mat_swap(gr_csr_mat_t mat1, gr_csr_mat_t mat2, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_update(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) { - FLINT_SWAP(gr_csr_mat_struct, *mat1, *mat2); + slong row; + int status = GR_SUCCESS; + + if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + return GR_DOMAIN; + + for (row = 0; row < res->r; ++row) + status |= gr_sparse_vec_update(res->rows[row], mat->rows[row], ctx); + return status; } -GR_SPARSE_MAT_INLINE void -gr_lil_mat_swap(gr_lil_mat_t mat1, gr_lil_mat_t mat2, gr_ctx_t ctx) + +WARN_UNUSED_RESULT int +gr_csr_mat_set_from_coo(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); +WARN_UNUSED_RESULT int +gr_lil_mat_set_from_coo(gr_lil_mat_t vec, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_csr_mat_set_from_coo_sorted_deduped(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); +WARN_UNUSED_RESULT int +gr_lil_mat_set_from_coo_sorted_deduped(gr_lil_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_csr_mat_permute_cols(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx) { - FLINT_SWAP(gr_lil_mat_struct, *mat1, *mat2); -} + slong row; + gr_sparse_vec_t tmp; + int status = GR_SUCCESS; -GR_SPARSE_MAT_INLINE void -gr_csr_mat_clear(gr_csr_mat_t mat, gr_ctx_t ctx) { - if (mat->alloc != 0) + for (row = 0; row < mat->r; ++row) { - _gr_vec_clear(mat->entries, mat->alloc, ctx); - flint_free(mat->entries); - flint_free(mat->cols); + _gr_csr_mat_borrow_row(tmp, mat, row, ctx); + status |= gr_sparse_vec_permute_inds(tmp, tmp, perm, ctx); } - flint_free(mat->rows); - memset(mat, 0, sizeof(gr_csr_mat_t)); + return status; } -GR_SPARSE_MAT_INLINE void -gr_lil_mat_clear(gr_lil_mat_t mat, gr_ctx_t ctx) { - int row; +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_permute_cols(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx) +{ + slong row; + int status = GR_SUCCESS; - for (row = 0; row < mat->r; ++row) { - gr_sparse_vec_clear(mat->rows[row], ctx); + for (row = 0; row < mat->r; ++row) + { + status |= gr_sparse_vec_permute_inds(mat->rows[row], mat->rows[row], perm, ctx); } - flint_free(mat->rows); - memset(mat, 0, sizeof(gr_lil_mat_t)); + return status; } +void gr_lil_mat_window_init(gr_lil_mat_t window, const gr_lil_mat_t mat, slong r1, slong c1, slong r2, slong c2, gr_ctx_t ctx); GR_SPARSE_MAT_INLINE void -_gr_csr_mat_borrow_row(gr_sparse_vec_t res, const gr_csr_mat_t mat, slong r, gr_ctx_t ctx) { - ulong offset; - - offset = mat->rows[r]; - res->nnz = mat->rows[r+1] - offset; - res->alloc = res->nnz; - res->inds = mat->cols + offset; - res->length = mat->c; - res->entries = GR_ENTRY(mat->entries, offset, ctx->sizeof_elem); +gr_lil_mat_window_clear(gr_lil_mat_t window, gr_ctx_t ctx) +{ + flint_free(window->rows); } WARN_UNUSED_RESULT int gr_lil_mat_swap_rows(gr_lil_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_permute_rows(gr_lil_mat_t mat, const slong * perm, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_invert_rows(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_invert_rows(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx); /* -void gr_sparse_mat_window_init(gr_csr_mat_t window, const gr_csr_mat_t mat, slong r1, slong c1, slong r2, slong c2, gr_ctx_t ctx); - -GR_SPARSE_MAT_INLINE void -gr_sparse_mat_window_clear(gr_csr_mat_t window, gr_ctx_t ctx) -{ - flint_free(window->rows); -} - WARN_UNUSED_RESULT int gr_lil_mat_concat_horizontal(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_csr_mat_concat_vertical(gr_csr_mat_t res, const gr_csr_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_concat_vertical(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); */ -/* -int gr_sparse_mat_write(gr_stream_t out, const gr_csr_mat_t mat, gr_ctx_t ctx); -int gr_sparse_mat_print(const gr_csr_mat_t mat, gr_ctx_t ctx); -*/ - /* WARN_UNUSED_RESULT int gr_sparse_mat_randtest(gr_csr_mat_t mat, flint_rand_t state, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_mat_randops(gr_csr_mat_t mat, flint_rand_t state, slong count, gr_ctx_t ctx); @@ -251,35 +393,42 @@ WARN_UNUSED_RESULT int gr_sparse_mat_randpermdiag(int * parity, gr_csr_mat_t mat WARN_UNUSED_RESULT int gr_sparse_mat_randrank(gr_csr_mat_t mat, flint_rand_t state, slong rank, gr_ctx_t ctx); */ -#define gr_sparse_mat_is_empty(mat, ctx) (((mat->r == 0) || (mat->c == 0)) ? T_TRUE : T_FALSE) -#define gr_sparse_mat_is_square(mat, ctx) ((mat->r == mat->c) ? T_TRUE : T_FALSE) -#define gr_sparse_mat_is_zero(mat, ctx) ((mat->nnz == 0) ? T_TRUE : T_FALSE) - -truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx); -truth_t gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx); -truth_t gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx); - -truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx); -truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx); -truth_t gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +/** + * Comparison +**/ -GR_SPARSE_MAT_INLINE void -gr_csr_mat_zero(gr_csr_mat_t res, gr_ctx_t ctx) { - res->nnz = 0; - memset(res->rows, 0, (res->r + 1) * sizeof(ulong)); -} +GR_SPARSE_MAT_INLINE truth_t +gr_csr_mat_is_zero(const gr_csr_mat_t mat, gr_ctx_t ctx) +{ return _gr_vec_is_zero(mat->entries, mat->nnz, ctx); } -GR_SPARSE_MAT_INLINE void -gr_lil_mat_zero(gr_lil_mat_t res, gr_ctx_t ctx) { - int row; +GR_SPARSE_MAT_INLINE truth_t +gr_lil_mat_is_zero(const gr_lil_mat_t mat, gr_ctx_t ctx) +{ + slong row; + truth_t row_is_zero; + truth_t ret = T_TRUE; - res->nnz = 0; - for(row = 0; row < res->r; ++row) + for (row = 0; row < mat->r; ++row) { - gr_sparse_vec_zero(res->rows[row], ctx); + row_is_zero = gr_sparse_vec_is_zero(mat->rows[row], ctx); + if (row_is_zero == T_FALSE) + return T_FALSE; + else if (row_is_zero == T_UNKNOWN) + ret = T_UNKNOWN; } + return ret; } +truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx); +truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx); + +truth_t gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx); +truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx); + +truth_t gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx); +truth_t gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +truth_t gr_csr_mat_equal_lil_mat(const gr_csr_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); + /* GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_one(gr_csr_mat_t res, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_csr_mat_set_scalar(gr_csr_mat_t res, gr_srcptr c, gr_ctx_t ctx); @@ -292,12 +441,32 @@ WARN_UNUSED_RESULT int gr_csr_mat_set_fmpz_csr_mat(gr_csr_mat_t res, const fmpz_ WARN_UNUSED_RESULT int gr_csr_mat_set_fmpq_csr_mat(gr_csr_mat_t res, const fmpq_csr_mat_t mat, gr_ctx_t ctx); */ +/** + * Output +**/ + +WARN_UNUSED_RESULT int +gr_csr_mat_write_nz(gr_stream_t out, const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_write_nz(gr_stream_t out, const gr_lil_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_csr_mat_print_nz(const gr_csr_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_print_nz(const gr_lil_mat_t mat, gr_ctx_t ctx); + +/** + * Arithmetic +**/ + GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_neg(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) { int status = GR_SUCCESS; - if (res->c != mat->c || res->r != mat->r) + if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) { return GR_DOMAIN; } @@ -312,7 +481,7 @@ gr_lil_mat_neg(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) int row; int status = GR_SUCCESS; - if (res->c != mat->c || res->r != mat->r) + if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) { return GR_DOMAIN; } @@ -323,6 +492,70 @@ gr_lil_mat_neg(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) return status; } +#define GR_LIL_MAT_BOP(FUNC, RES, MAT1, MAT2, CTX) { \ + int row; \ + int status = GR_SUCCESS; \ + \ + if (gr_mat_is_compatible(RES, MAT1, CTX) == T_FALSE || gr_mat_is_compatible(RES, MAT2, CTX) == T_FALSE) \ + { \ + return GR_DOMAIN; \ + } \ + (RES)->nnz = 0; \ + for (row = 0; row < (RES)->r; row++) { \ + status |= FUNC((RES)->rows[row], (MAT1)->rows[row], (MAT2)->rows[row], CTX); \ + res->nnz += res->rows[row]->nnz; \ + } \ + return status; \ +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_add(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ + GR_LIL_MAT_BOP(gr_sparse_vec_add, res, mat1, mat2, ctx) +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_sub(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ + GR_LIL_MAT_BOP(gr_sparse_vec_sub, res, mat1, mat2, ctx) +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_mul(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ + GR_LIL_MAT_BOP(gr_sparse_vec_mul, res, mat1, mat2, ctx) +} + +#define GR_LIL_MAT_ACCUM_OP(FUNC, RES, MAT, C, CTX) { \ + int row; \ + int status = GR_SUCCESS; \ + \ + if (gr_mat_is_compatible(RES, MAT, CTX) == T_FALSE) \ + { \ + return GR_DOMAIN; \ + } \ + (RES)->nnz = 0; \ + for (row = 0; row < (RES)->r; row++) { \ + status |= FUNC((RES)->rows[row], (MAT)->rows[row], C, CTX); \ + res->nnz += res->rows[row]->nnz; \ + } \ + return status; \ +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_addmul_scalar(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_srcptr c, gr_ctx_t ctx) +{ + GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_addmul_scalar, res, mat, c, ctx) +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_submul_scalar(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_srcptr c, gr_ctx_t ctx) +{ + GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_submul_scalar, res, mat, c, ctx) +} + +/** + * Component-wise multiplication and division +**/ + #define GR_CSR_MAT_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) \ if(res->r != src->r || res->c != src->c) \ { \ @@ -392,41 +625,54 @@ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_ui(gr_lil GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } -/* -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_add(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +/** + * Sum and product +**/ + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_sum(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx) +{ return _gr_vec_sum(res, mat->entries, mat->nnz, ctx); } + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_sum(gr_ptr res, const gr_lil_mat_t mat, gr_ctx_t ctx) { - int row; - int status; + slong row; + int status = GR_SUCCESS; + gr_ptr elem; - if (res->c != mat1->c || res->r != mat1->r || res->c != mat2->c || res->r != mat2->r) + elem = flint_malloc(ctx->sizeof_elem); + gr_init(elem, ctx); + for (row = 0; row < mat->r; ++row) { - return GR_DOMAIN; - } - res->nnz = 0; - for (row = 0; row < res->r; row++) { - status |= gr_sparse_vec_add(res->rows[i], res->mat1[i], res->mat2[i], ctx); - res->nnz += res->rows[i].nnz; + status |= gr_sparse_vec_sum(elem, mat->rows[row], ctx); + status |= gr_add(res, res, elem, ctx); } + gr_clear(elem, ctx); return status; } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_sub(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_nz_product(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx) +{ return _gr_vec_product(res, mat->entries, mat->nnz, ctx); } + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_nz_product(gr_ptr res, const gr_lil_mat_t mat, gr_ctx_t ctx) { - int row; - int status; + slong row; + int status = GR_SUCCESS; + gr_ptr elem; - if (res->c != mat1->c || res->r != mat1->r || res->c != mat2->c || res->r != mat2->r) + elem = flint_malloc(ctx->sizeof_elem); + gr_init(elem, ctx); + status |= gr_one(elem, ctx); + for (row = 0; row < mat->r; ++row) { - return GR_DOMAIN; - } - res->nnz = 0; - for (row = 0; row < res->r; row++) { - status |= gr_sparse_vec_sub(res->rows[i], res->mat1[i], res->mat2[i], ctx); - res->nnz += res->rows[i].nnz; + status |= gr_sparse_vec_nz_product(elem, mat->rows[row], ctx); + status |= gr_mul(res, res, elem, ctx); } - return status; + gr_clear(elem, ctx); + return status; } -*/ + +/** + * Matrix multiplication +**/ WARN_UNUSED_RESULT int gr_csr_mat_mul_vec(gr_vec_t v, const gr_csr_mat_t A, const gr_vec_t u, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ctx_t ctx); diff --git a/src/gr_sparse_mat/equal.c b/src/gr_sparse_mat/equal.c index 264e57f843..0bd59c8565 100644 --- a/src/gr_sparse_mat/equal.c +++ b/src/gr_sparse_mat/equal.c @@ -14,63 +14,71 @@ truth_t gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx) { - slong i, r, c, nnz; - - r = gr_sparse_mat_nrows(mat1, ctx); - c = gr_sparse_mat_ncols(mat1, ctx); - nnz = gr_sparse_mat_nnz(mat1, ctx); + slong row; + gr_sparse_vec_t tmp1, tmp2; + truth_t row_is_eq; + truth_t ret = T_TRUE; - if (r != gr_mat_nrows(mat2, ctx) || - c != gr_mat_ncols(mat2, ctx) || - nnz != gr_sparse_mat_nnz(mat2, ctx)) + if (gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE) { return T_FALSE; } - - if (r == 0 || c == 0) - return T_TRUE; - - // TODO: can use memcmp? - for (i = 0; i < nnz; ++i) + for (row = 0; row < mat1->r; row++) { - if (mat1->cols[i] != mat2->cols[i]) + _gr_csr_mat_borrow_row(tmp1, mat1, row, ctx); + _gr_csr_mat_borrow_row(tmp2, mat2, row, ctx); + row_is_eq = gr_sparse_vec_equal(tmp1, tmp2, ctx); + if (row_is_eq == T_FALSE) return T_FALSE; + else if (row_is_eq == T_UNKNOWN) + ret = T_UNKNOWN; } - - return _gr_vec_equal( - mat1->entries, - mat2->entries, - nnz, - ctx - ); + return ret; } truth_t gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) { - slong i, r, c, nnz; + slong row; truth_t row_is_eq; + truth_t ret = T_TRUE; - r = gr_sparse_mat_nrows(mat1, ctx); - c = gr_sparse_mat_ncols(mat1, ctx); - nnz = gr_sparse_mat_nnz(mat1, ctx); - - if (r != gr_mat_nrows(mat2, ctx) || - c != gr_mat_ncols(mat2, ctx) || - nnz != gr_sparse_mat_nnz(mat2, ctx)) + if (gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE) { return T_FALSE; } + for (row = 0; row < mat1->r; row++) + { + row_is_eq = gr_sparse_vec_equal(mat1->rows[row], mat2->rows[row], ctx); + if (row_is_eq == T_FALSE) + return T_FALSE; + else if (row_is_eq == T_UNKNOWN) + ret = T_UNKNOWN; + } + return ret; +} - if (r == 0 || c == 0) - return T_TRUE; +truth_t +gr_csr_mat_equal_lil_mat(const gr_csr_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ + slong row; + gr_sparse_vec_t tmp; + truth_t row_is_eq; + truth_t ret = T_TRUE; - for (i = 0; i < r; ++i) + if (gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE) { - row_is_eq = gr_sparse_vec_equal(mat1->rows[i], mat2->rows[i], ctx); - if (row_is_eq != T_TRUE) - break; + return T_FALSE; } - - return row_is_eq; + for (row = 0; row < mat1->r; row++) + { + _gr_csr_mat_borrow_row(tmp, mat1, row, ctx); + row_is_eq = gr_sparse_vec_equal(tmp, mat2->rows[row], ctx); + if (row_is_eq == T_FALSE) + return T_FALSE; + else if (row_is_eq == T_UNKNOWN) + ret = T_UNKNOWN; + } + return ret; } + diff --git a/src/gr_sparse_mat/fit_nnz.c b/src/gr_sparse_mat/fit_nnz.c index 87d26714e1..9ba98a973c 100644 --- a/src/gr_sparse_mat/fit_nnz.c +++ b/src/gr_sparse_mat/fit_nnz.c @@ -14,3 +14,29 @@ gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx) mat->alloc = new_alloc; } } + +void +gr_csr_mat_shrink_to_nnz(gr_csr_mat_t mat, gr_ctx_t ctx) +{ + slong nnz = mat->nnz; + slong sz = ctx->sizeof_elem; + if (mat->alloc > nnz) + { + mat->cols = flint_realloc(mat->cols, nnz * sizeof(ulong)); + _gr_vec_clear(GR_ENTRY(mat->entries, nnz, sz), mat->alloc - nnz, ctx); + mat->entries = flint_realloc(mat->entries, nnz * sz); + mat->alloc = nnz; + } +} + +void +gr_lil_mat_shrink_to_nnz(gr_lil_mat_t mat, gr_ctx_t ctx) +{ + slong row; + + for (row = 0; row < mat->r; ++row) + { + gr_sparse_vec_shrink_to_nnz(mat->rows[row], ctx); + } +} + diff --git a/src/gr_sparse_mat/invert_rows.c b/src/gr_sparse_mat/invert_rows.c index 574d1b8585..e038a70471 100644 --- a/src/gr_sparse_mat/invert_rows.c +++ b/src/gr_sparse_mat/invert_rows.c @@ -11,10 +11,56 @@ #include "gr_sparse_mat.h" +int gr_csr_mat_invert_rows(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong r = mat->r; + slong nnz = mat->nnz; + slong i, j, k; + slong sz = ctx->sizeof_elem; + + // Handle permutation if provided + if (perm != NULL) + { + for (i = 0; i < r / 2; i++) + { + FLINT_SWAP(slong, perm[i], perm[r - i - 1]); + } + } + + // Reverse row offsets + for (i = 0; i < r / 2; ++i) + { + FLINT_SWAP(ulong, mat->rows[i + 1], mat->rows[r - i]); + } + + // Reverse all columns and elements + for (j = 0; j < nnz / 2; ++j) + { + k = nnz - j - 1; + FLINT_SWAP(ulong, mat->cols[j], mat->cols[k]); + gr_swap(GR_ENTRY(mat->entries, j, sz), GR_ENTRY(mat->entries, k, sz), ctx); + } + + // Reverse columns and elements in each row + for (i = 0; i < r; ++i) + { + // Fix row offset + mat->rows[i+1] -= (i < r - 1 ? mat->rows[i+2] : 0) - mat->rows[i]; + for (j = mat->rows[i]; j < mat->rows[i+1] / 2; ++j) + { + k = mat->rows[i+1] - j - 1; + FLINT_SWAP(ulong, mat->cols[j], mat->cols[k]); + gr_swap(GR_ENTRY(mat->entries, j, sz), GR_ENTRY(mat->entries, k, sz), ctx); + } + } + return status; +} + int gr_lil_mat_invert_rows(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx) { int status = GR_SUCCESS; - slong r = gr_sparse_mat_nrows(mat, ctx); + slong r = mat->r; slong i; for (i = 0; i < r / 2; i++) diff --git a/src/gr_sparse_mat/is_neg_one.c b/src/gr_sparse_mat/is_neg_one.c index 0057f4a82d..047acc4ab4 100644 --- a/src/gr_sparse_mat/is_neg_one.c +++ b/src/gr_sparse_mat/is_neg_one.c @@ -14,49 +14,46 @@ truth_t gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx) { - int row; + slong row, idx; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); gr_method_unary_predicate is_neg_one = GR_UNARY_PREDICATE(ctx, IS_NEG_ONE); truth_t this_eq; + truth_t ret = T_TRUE; slong sz = ctx->sizeof_elem; - if (mat->r != mat->nnz) - return T_FALSE; - for (row = 0; row < mat->r; ++row) { - if (mat->cols[row] != row) - return T_FALSE; - - this_eq = is_neg_one(GR_ENTRY(mat->entries, row, sz), ctx); - - if (this_eq == T_FALSE) - return T_FALSE; - else if (this_eq == T_UNKNOWN) - return T_UNKNOWN; + for (idx = mat->rows[row]; idx < mat->rows[row+1]; idx++) + { + this_eq = (mat->cols[idx] == row ? is_neg_one : is_zero)(GR_ENTRY(mat->entries, idx, sz), ctx); + if (this_eq == T_FALSE) + return T_FALSE; + else + ret = T_UNKNOWN; + } } - return T_TRUE; + return ret; } truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx) { - int row; + slong row, idx; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); gr_method_unary_predicate is_neg_one = GR_UNARY_PREDICATE(ctx, IS_NEG_ONE); truth_t this_eq; + truth_t ret = T_TRUE; + slong sz = ctx->sizeof_elem; - if (mat->r != mat->nnz) - return T_FALSE; - for (row = 0; row < mat->r; ++row) { - if (mat->rows[row]->nnz != 1 || mat->rows[row]->inds[0] != row) - return T_FALSE; - - this_eq = is_neg_one(mat->rows[row]->entries, ctx); - - if (this_eq == T_FALSE) - return T_FALSE; - else if (this_eq == T_UNKNOWN) - return T_UNKNOWN; + for (idx = 0; idx < mat->rows[row]->nnz; idx++) + { + this_eq = (mat->rows[row]->inds[idx] == row ? is_neg_one : is_zero)(GR_ENTRY(mat->rows[row]->entries, idx, sz), ctx); + if (this_eq == T_FALSE) + return T_FALSE; + else + ret = T_UNKNOWN; + } } - return T_TRUE; + return ret; } diff --git a/src/gr_sparse_mat/is_one.c b/src/gr_sparse_mat/is_one.c index 8e51e1ce66..24be77d61a 100644 --- a/src/gr_sparse_mat/is_one.c +++ b/src/gr_sparse_mat/is_one.c @@ -13,49 +13,46 @@ truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx) { - int row; + slong row, idx; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); gr_method_unary_predicate is_one = GR_UNARY_PREDICATE(ctx, IS_ONE); truth_t this_eq; + truth_t ret = T_TRUE; slong sz = ctx->sizeof_elem; - if (mat->r != mat->nnz) - return T_FALSE; - for (row = 0; row < mat->r; ++row) { - if (mat->cols[row] != row) - return T_FALSE; - - this_eq = is_one(GR_ENTRY(mat->entries, row, sz), ctx); - - if (this_eq == T_FALSE) - return T_FALSE; - else if (this_eq == T_UNKNOWN) - return T_UNKNOWN; + for (idx = mat->rows[row]; idx < mat->rows[row+1]; idx++) + { + this_eq = (mat->cols[idx] == row ? is_one : is_zero)(GR_ENTRY(mat->entries, idx, sz), ctx); + if (this_eq == T_FALSE) + return T_FALSE; + else + ret = T_UNKNOWN; + } } - return T_TRUE; + return ret; } truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx) { - int row; + slong row, idx; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); gr_method_unary_predicate is_one = GR_UNARY_PREDICATE(ctx, IS_ONE); truth_t this_eq; + truth_t ret = T_TRUE; + slong sz = ctx->sizeof_elem; - if (mat->r != mat->nnz) - return T_FALSE; - for (row = 0; row < mat->r; ++row) { - if (mat->rows[row]->nnz != 1 || mat->rows[row]->inds[0] != row) - return T_FALSE; - - this_eq = is_one(mat->rows[row]->entries, ctx); - - if (this_eq == T_FALSE) - return T_FALSE; - else if (this_eq == T_UNKNOWN) - return T_UNKNOWN; + for (idx = 0; idx < mat->rows[row]->nnz; idx++) + { + this_eq = (mat->rows[row]->inds[idx] == row ? is_one : is_zero)(GR_ENTRY(mat->rows[row]->entries, idx, sz), ctx); + if (this_eq == T_FALSE) + return T_FALSE; + else + ret = T_UNKNOWN; + } } - return T_TRUE; + return ret; } diff --git a/src/gr_sparse_mat/mul.c b/src/gr_sparse_mat/mul.c index 27f5a5870f..66fca6d5ea 100644 --- a/src/gr_sparse_mat/mul.c +++ b/src/gr_sparse_mat/mul.c @@ -28,7 +28,7 @@ int gr_csr_mat_mul_vec(gr_vec_t v, const gr_csr_mat_t A, const gr_vec_t u, gr_ct if (gr_sparse_mat_ncols(A, ctx) != gr_vec_length(u, ctx) || ar != gr_vec_length(v, ctx)) return GR_DOMAIN; - if (gr_sparse_mat_is_zero(A, ctx) == T_TRUE) + if (gr_csr_mat_is_zero(A, ctx) == T_TRUE) { return _gr_vec_zero(v->entries, v->length, ctx); } @@ -67,7 +67,7 @@ int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ct return GR_DOMAIN; - if (gr_sparse_mat_is_zero(A, ctx) == T_TRUE) + if (gr_lil_mat_is_zero(A, ctx) == T_TRUE) { return _gr_vec_zero(v->entries, v->length, ctx); } @@ -124,7 +124,7 @@ int gr_csr_mat_mul_mat_transpose(gr_mat_t Ct, const gr_csr_mat_t A, const gr_mat status = gr_mat_zero(Ct, ctx); - if (gr_sparse_mat_is_zero(A, ctx)) + if (gr_csr_mat_is_zero(A, ctx)) { return status; } @@ -159,7 +159,7 @@ int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_mat_t A, const gr_mat status = gr_mat_zero(Ct, ctx); - if (gr_sparse_mat_is_zero(A, ctx)) + if (gr_lil_mat_is_zero(A, ctx)) { return status; } @@ -191,7 +191,7 @@ int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ct if (gr_sparse_mat_ncols(A, ctx) != gr_mat_nrows(B, ctx) || ar != gr_mat_nrows(C, ctx) || bc != gr_mat_ncols(C, ctx)) return GR_DOMAIN; - if (gr_sparse_mat_is_zero(A, ctx)) + if (gr_csr_mat_is_zero(A, ctx)) { return gr_mat_zero(C, ctx); } @@ -234,7 +234,7 @@ int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ct if (gr_sparse_mat_ncols(A, ctx) != gr_mat_nrows(B, ctx) || ar != gr_mat_nrows(C, ctx) || bc != gr_mat_ncols(C, ctx)) return GR_DOMAIN; - if (gr_sparse_mat_is_zero(A, ctx)) + if (gr_lil_mat_is_zero(A, ctx)) { return gr_mat_zero(C, ctx); } diff --git a/src/gr_sparse_mat/set.c b/src/gr_sparse_mat/set.c index 124bf1ea40..c516e37e6c 100644 --- a/src/gr_sparse_mat/set.c +++ b/src/gr_sparse_mat/set.c @@ -16,7 +16,7 @@ int gr_csr_mat_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) { if (res != mat) { - if (res->r != mat->r || res->c != mat->c) + if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) { return GR_DOMAIN; } @@ -35,7 +35,8 @@ int gr_lil_mat_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) { if (res != mat) { - if (res->r != mat->r || res->c != mat->c) { + if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + { return GR_DOMAIN; } res->nnz = mat->nnz; @@ -53,7 +54,7 @@ int gr_csr_mat_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ct int success = GR_SUCCESS; gr_sparse_vec_t res_row; - if (res->r != mat->r || res->c != mat->c) + if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) return GR_DOMAIN; gr_csr_mat_fit_nnz(res, mat->nnz, ctx); @@ -75,7 +76,7 @@ int gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ct int success = GR_SUCCESS; gr_sparse_vec_t mat_row; - if (res->r != mat->r || res->c != mat->c) + if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) return GR_DOMAIN; for(row = 0; row < mat->r; row++) { @@ -86,3 +87,62 @@ int gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ct return success; } + +int gr_csr_mat_set_mat(gr_csr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) +{ + ulong row, col; + slong nnz, sz; + int success = GR_SUCCESS; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); + + if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + return GR_DOMAIN; + + // Get number of nonzero entries + sz = ctx->sizeof_elem; + nnz = 0; + for (row = 0; row < mat->r; ++row) + for (col = 0; col < mat->c; ++col) + if (is_zero(GR_MAT_ENTRY(mat, row, col, sz), ctx) != T_TRUE) + nnz++; + gr_csr_mat_fit_nnz(res, nnz, ctx); + + // Construct sparse matrix from nonzeroes + res->rows[0] = 0; + nnz = 0; + for(row = 0; row < mat->r; row++) + { + for (col = 0; col < mat->c; ++col) + { + if (is_zero(GR_MAT_ENTRY(mat, row, col, sz), ctx) != T_TRUE) + { + res->cols[nnz] = col; + success |= gr_set(GR_ENTRY(res->entries, nnz, sz), GR_MAT_ENTRY(mat, row, col, sz), ctx); + ++nnz; + } + } + res->rows[row + 1] = nnz; + } + res->nnz = nnz; + + return success; +} + +int gr_lil_mat_set_mat(gr_lil_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) +{ + ulong row; + slong sz; + int success = GR_SUCCESS; + + if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + return GR_DOMAIN; + + sz = ctx->sizeof_elem; + res->nnz = 0; + for(row = 0; row < mat->r; row++) { + success |= gr_sparse_vec_set_vec(res->rows[row], GR_MAT_ENTRY(mat, row, 0, sz), mat->c, ctx); + res->nnz += res->rows[row]->nnz; + } + + return success; +} diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 5a8aa886e5..ec8b9ab3a2 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -15,7 +15,7 @@ #ifdef GR_SPARSE_VEC_INLINES_C #define GR_SPARSE_VEC_INLINE #else -#define GR_SPARSE_VEC_INLINE static __inline__ +#define GR_SPARSE_VEC_INLINE static inline #endif #include @@ -86,11 +86,11 @@ WARN_UNUSED_RESULT int gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong ind_start, slong ind_end, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_get_entry(gr_ptr res, gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong ind, gr_srcptr entry, gr_ctx_t ctx); truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return (vec->nnz == 0 ? T_TRUE : T_FALSE); } +GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_is_zero(vec->entries, vec->nnz, ctx); } int gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx); int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx); @@ -205,7 +205,7 @@ gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ct } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) +gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), @@ -216,7 +216,7 @@ gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_spar } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) +gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), @@ -230,7 +230,7 @@ gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_spar #define GR_SPV_RFL_ZERO gr_zero(GR_ENTRY(res->entries, dest_ind, sz), ctx) GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) +gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, diff --git a/src/gr_sparse_vec/equal.c b/src/gr_sparse_vec/equal.c index af4988ddcc..b286337fc4 100644 --- a/src/gr_sparse_vec/equal.c +++ b/src/gr_sparse_vec/equal.c @@ -3,13 +3,41 @@ truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx) { - slong nnz, i, sz; - sz = ctx->sizeof_elem; - if (vec1->length != vec2->length || vec1->nnz != vec2->nnz) + slong i1, i2, sz; + truth_t cur_test; + truth_t ret = T_TRUE; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); + + if (vec1->length != vec2->length) return T_FALSE; - nnz = vec1->nnz; - for (i = 0; i < nnz; i++) - if (T_TRUE != gr_equal(GR_ENTRY(vec1->entries, i, sz), GR_ENTRY(vec2->entries, i, sz), ctx)) - return T_FALSE; - return T_TRUE; + sz = ctx->sizeof_elem; + + for (i1 = 0, i2 = 0; i1 < vec1->nnz && i2 < vec2->nnz; ) + { + if (vec1->inds[i1] < vec2->inds[i2]) + { + // In vector => either known or maybe nonzero + if (is_zero(GR_ENTRY(vec1->entries, i1, sz), ctx) == T_FALSE) + return T_FALSE; + else + ret = T_UNKNOWN; // Have maybe zero vs known zero + } + else if (vec1->inds[i1] > vec2->inds[i2]) + { + if (is_zero(GR_ENTRY(vec2->entries, i2, sz), ctx) == T_FALSE) + return T_FALSE; + else + ret = T_UNKNOWN; // Have maybe zero vs known zero + } + else + { + cur_test = gr_equal(GR_ENTRY(vec1->entries, i1, sz), GR_ENTRY(vec2->entries, i2, sz), ctx); + if (cur_test == T_FALSE) + return T_FALSE; + else if (cur_test == T_UNKNOWN) + ret = T_UNKNOWN; + } + } + + return ret; } diff --git a/src/gr_sparse_vec/find_entry.c b/src/gr_sparse_vec/get_entry.c similarity index 87% rename from src/gr_sparse_vec/find_entry.c rename to src/gr_sparse_vec/get_entry.c index 03451147e5..78f2341032 100644 --- a/src/gr_sparse_vec/find_entry.c +++ b/src/gr_sparse_vec/get_entry.c @@ -11,7 +11,7 @@ static int gr_sparse_vec_ulong_cmp(const void* a, const void* b) int -gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx) +gr_sparse_vec_get_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx) { slong i; slong sz = ctx->sizeof_elem; diff --git a/src/gr_sparse_vec/set_entry.c b/src/gr_sparse_vec/set_entry.c index 039fcb4ebe..fcf1e4f13f 100644 --- a/src/gr_sparse_vec/set_entry.c +++ b/src/gr_sparse_vec/set_entry.c @@ -20,35 +20,42 @@ gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_ bs = bsearch(&col, vec->inds, vec->nnz, sizeof(slong), gr_sparse_vec_ulong_cmp); if (bs != NULL) { - i = (bs - vec->inds); - return gr_set(GR_ENTRY(vec->entries, i, sz), entry, ctx); + i = bs - vec->inds; + if (gr_is_zero(entry, ctx) == T_TRUE) + { + // Shift everything above i down + memmove(vec->inds + i, vec->inds + i + 1, (vec->nnz - i - 1)*sizeof(slong)); + for (j = i; j < vec->nnz; j++) + { + gr_swap(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(vec->entries, j + 1, sz), ctx); + } + --vec->nnz; + return GR_SUCCESS; + } } else { - /* In this case, it's going to cost linear time anyway, so just brute force search */ + if (gr_is_zero(entry, ctx) == T_TRUE) + { + // Already 0 + return GR_SUCCESS; + } + // Make room for new element gr_sparse_vec_fit_nnz(vec, vec->nnz+1, ctx); + + // Find location to put new element for (i = 0; i < nnz; i++) - { - if (vec->inds[i] < col) + if (col < vec->inds[i]) break; - } - /* Now if i < nnz, then we should put the entry right *after* it */ - /* If i == nnz, we should put the entry right there */ - if (i < nnz) - i++; - if (i < nnz) + + // Shift everything above i up + memmove(vec->inds + i + 1, vec->inds + i, (vec->nnz - i)*sizeof(slong)); + for (j = vec->nnz; j > i; j--) { - /* If necessary, move everything up to make space */ - memmove(vec->inds + i + 1, vec->inds + i, (vec->nnz - i)*sizeof(slong)); - for (j = vec->nnz; j > i; j--) - { - gr_swap(GR_ENTRY(vec->entries, j-1, sz), GR_ENTRY(vec->entries, j, sz), ctx); - } + gr_swap(GR_ENTRY(vec->entries, j-1, sz), GR_ENTRY(vec->entries, j, sz), ctx); } - /* Now there's an available spot in index i */ vec->inds[i] = col; - vec->nnz++; - return gr_set(GR_ENTRY(vec->entries, i, sz), entry, ctx); + ++vec->nnz; } - return GR_UNABLE; /* This shouldn't happen */ + return gr_set(GR_ENTRY(vec->entries, i, sz), entry, ctx); } diff --git a/src/gr_sparse_vec/write.c b/src/gr_sparse_vec/write.c index 17c484c2e6..a4155c173b 100644 --- a/src/gr_sparse_vec/write.c +++ b/src/gr_sparse_vec/write.c @@ -7,18 +7,16 @@ gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) int status = GR_SUCCESS; slong i, sz = ctx->sizeof_elem; slong nnz = vec->nnz; - gr_stream_write(out, "gr_sparse_vec_t{"); + gr_stream_write(out, "["); for (i = 0; i < nnz; i++) { - gr_stream_write(out, "("); gr_stream_write_si(out, vec->inds[i]); gr_stream_write(out, ": "); status |= gr_write(out, GR_ENTRY(vec->entries, i, sz), ctx); - gr_stream_write(out, ")"); if (i < nnz - 1) gr_stream_write(out, ", "); } - gr_stream_write(out, "}"); + gr_stream_write(out, "]"); return status; } From 61089536ffc1a1cdba4a9cfdd0eb96bcef95769c Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Mon, 18 Mar 2024 16:36:49 -0700 Subject: [PATCH 36/59] Fixed test --- src/gr_sparse_vec/test/t-creation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c index a4fc5e963f..6a11475658 100644 --- a/src/gr_sparse_vec/test/t-creation.c +++ b/src/gr_sparse_vec/test/t-creation.c @@ -32,7 +32,7 @@ test_init_from_entries_sorted(flint_rand_t state, gr_ctx_t ctx) status |= gr_sparse_vec_set_from_entries_sorted_deduped(vec, inds, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); for (i = 0; i < 2*N; i++) { - status |= gr_sparse_vec_find_entry(temp, vec, i, ctx); + status |= gr_sparse_vec_get_entry(temp, vec, i, ctx); if ((i & 1) == 1 && (T_TRUE != gr_is_zero(temp, ctx))) /* Odd inds should all be zero */ return GR_TEST_FAIL; if ((i & 1) == 0 && (T_TRUE != gr_equal(temp, GR_VEC_ENTRY(dvec, i>>1, sz), ctx))) @@ -70,7 +70,7 @@ test_init_from_entries_unsorted_internal(ulong *inds, gr_srcptr entries, slong l status |= gr_add(temp, temp, GR_ENTRY(entries, j, sz), ctx); } /* Check it */ - status |= gr_sparse_vec_find_entry(temp2, vec, i, ctx); + status |= gr_sparse_vec_get_entry(temp2, vec, i, ctx); if (T_TRUE != gr_equal(temp, temp2, ctx)) return GR_TEST_FAIL; } From d9cebe6b95c75a1dca0d8b6cb0e97bca3b9618b7 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Tue, 19 Mar 2024 15:47:48 -0700 Subject: [PATCH 37/59] Various nomenclature changes, added randtest, testing more rings --- doc/source/gr_sparse_mat.rst | 421 +++++++++++++++++ doc/source/gr_sparse_vec.rst | 176 ++++---- src/gr_sparse_mat.h | 625 +++++++++++++++++++------- src/gr_sparse_mat/canonicalize.c | 110 +++++ src/gr_sparse_mat/equal.c | 4 +- src/gr_sparse_mat/fit_nnz.c | 52 ++- src/gr_sparse_mat/from_entries.c | 30 ++ src/gr_sparse_mat/get_entry.c | 60 +++ src/gr_sparse_mat/invert_rows.c | 4 +- src/gr_sparse_mat/is_neg_one.c | 6 +- src/gr_sparse_mat/is_one.c | 6 +- src/gr_sparse_mat/mul.c | 2 +- src/gr_sparse_mat/set.c | 415 ++++++++++++++--- src/gr_sparse_mat/set_cols.c | 69 +++ src/gr_sparse_mat/set_entry.c | 78 ++++ src/gr_sparse_mat/swap_rows.c | 4 +- src/gr_sparse_mat/to_dense.c | 56 ++- src/gr_sparse_mat/write.c | 83 ++++ src/gr_sparse_vec.h | 594 ++++++++++++++---------- src/gr_sparse_vec/equal.c | 6 +- src/gr_sparse_vec/fit_nnz.c | 4 +- src/gr_sparse_vec/from_dense.c | 2 +- src/gr_sparse_vec/from_entries.c | 91 ++++ src/gr_sparse_vec/get_entry.c | 17 +- src/gr_sparse_vec/permute_inds.c | 2 +- src/gr_sparse_vec/randtest.c | 105 +++-- src/gr_sparse_vec/set.c | 14 +- src/gr_sparse_vec/set_entry.c | 6 +- src/gr_sparse_vec/set_from_entries.c | 102 ----- src/gr_sparse_vec/shrink_to_nnz.c | 4 +- src/gr_sparse_vec/slice.c | 25 +- src/gr_sparse_vec/test/main.c | 6 +- src/gr_sparse_vec/test/t-conversion.c | 17 +- src/gr_sparse_vec/test/t-creation.c | 121 ----- src/gr_sparse_vec/test/t-init.c | 178 ++++++++ src/gr_sparse_vec/test/t-randtest.c | 79 ++++ src/gr_sparse_vec/to_dense.c | 2 +- src/gr_sparse_vec/write.c | 2 +- 38 files changed, 2700 insertions(+), 878 deletions(-) create mode 100644 doc/source/gr_sparse_mat.rst create mode 100644 src/gr_sparse_mat/canonicalize.c create mode 100644 src/gr_sparse_mat/from_entries.c create mode 100644 src/gr_sparse_mat/get_entry.c create mode 100644 src/gr_sparse_mat/set_cols.c create mode 100644 src/gr_sparse_mat/set_entry.c create mode 100644 src/gr_sparse_mat/write.c create mode 100644 src/gr_sparse_vec/from_entries.c delete mode 100644 src/gr_sparse_vec/set_from_entries.c delete mode 100644 src/gr_sparse_vec/test/t-creation.c create mode 100644 src/gr_sparse_vec/test/t-init.c create mode 100644 src/gr_sparse_vec/test/t-randtest.c diff --git a/doc/source/gr_sparse_mat.rst b/doc/source/gr_sparse_mat.rst new file mode 100644 index 0000000000..9b7c141868 --- /dev/null +++ b/doc/source/gr_sparse_mat.rst @@ -0,0 +1,421 @@ +.. _gr-sparse-vec: + +**gr_sparse_mat.h** -- Sparse matrices over generic rings +=============================================================================== + +The types :type:`gr_csr_mat_t` and :type:`gr_lil_mat_t` are representions +of matrices over a generic +ring which are optimized for the situation where there are many entries which +are zero (the matrix is *sparse*, or has *low density*). Internally, the +matrix records only the positions of the nonzeros and their values. +Although technically these types and all its functions will operate correctly +with any density, a regular :type:`gr_mat_t` may be more efficient in the number +of nonzeros is not small. + +Types and basic access +-------------------------------------------------------------------------------- + +.. type:: gr_csr_mat_struct + +.. type:: gr_csr_mat_t + + This struct presents a sparse matrix in "compressed sparse row" form, and contains: + + * An `slong` value ``r``, the number of rows in the matrix. + * An `slong` value ``c``, the number of columns in the matrix. + * An `slong` value ``nnz``, the number of nonzeroes in the matrix. + * An `slong` value ``alloc``, the maximum number of nonzeroes currently allocated. + * A `ulong` array ``rows`` of length ``r+1`` providing row offsets. + * A `ulong` array ``cols`` of length ``nnz`` providing column indices. + * A :type:`gr_ptr` array of of length ``nnz`` providing nonzero values. + + For a given row of index ``row``, its nonzero columns and associated values are given + by the components of ``cols`` and ``entries`` associated to + indices between ``rows[row]`` and ``rows[row+1]``. + We always require: + + * The ``cols`` for each row are sorted into strictly increasing order. + * The ``entries`` are nonzero (meaning, ``gr_is_zero(GR_ENTRY(vec->nzs, i, ctx->sizeof_elem), ctx)`` returns ``T_FALSE`` for ``0 <= i < vec->nnz``). + * We have ``nnz <= alloc <= length``. + + A ``gr_csr_mat_t`` is defined as an array of length one of type + ``gr_csr_mat_struct``, permitting a ``gr_csr_mat_t`` to + be passed by reference. Note that ``gr_csr_mat_t`` is the more efficient + way to represent a sparse matrix, but is less convenient for modification. + +.. type:: gr_lil_mat_struct + +.. type:: gr_lil_mat_t + + This struct presents a sparse matrix in "list of lists" form, and contains: + + * An `slong` value ``r``, the number of rows in the matrix. + * An `slong` value ``c``, the number of columns in the matrix. + * An `slong` value ``nnz``, the number of nonzeroes in the matrix. + * A :type:`gr_sparse_vec_t` array ``rows`` of length ``r``, the (sparse) rows of the matrix. + + A ``gr_lil_mat_t`` is defined as an array of length one of type + ``gr_lil_mat_struct``, permitting a ``gr_lil_mat_t`` to + be passed by reference. Note that ``gr_less_mat_t`` is the less efficient + way to represent a sparse matrix, but is more convenient for modification. + +.. function:: void gr_sparse_mat_nrows(gr_csr_mat_t mat, gr_ctx_t ctx) + void gr_sparse_mat_ncols(gr_csr_mat_t mat, gr_ctx_t ctx) + void gr_sparse_mat_nnz(gr_csr_mat_t mat, gr_ctx_t ctx) + void gr_sparse_mat_nrows(gr_csr_mat_t mat, gr_ctx_t ctx) + void gr_sparse_mat_ncols(gr_csr_mat_t mat, gr_ctx_t ctx) + void gr_sparse_mat_nnz(gr_csr_mat_t mat, gr_ctx_t ctx) + + Get the number of rows/columns/nonzeroes of the given sparse matrix, + in either representation. + +.. macro:: GR_CSR_MAT_COL(mat, i, j) + GR_LIL_MAT_COL(mat, i, j) + + Get a pointer to the column of the *j*-th nonzero in the *i*-th row of *mat*. + There is no bounds checking. + +.. macro:: GR_CSR_MAT_ENTRY(mat, i, j, sz) + GR_LIL_MAT_ENTRY(mat, i, j, sz) + + Get a pointer to the value of the *j*-th nonzero entry in the *i*-th row of *mat*, + given the size of each entry (typically obtained as ``ctx->sizeof_elem``). + There is no bounds checking. + +.. function:: ulong * gr_csr_mat_col_ptr(gr_csr_mat_t mat, slong i, slong j) + const ulong * gr_csr_mat_col_srcptr(const gr_csr_mat_t mat, slong i, slong j) + ulong * gr_lil_mat_col_ptr(gr_lil_mat_t mat, slong i, slong j) + const ulong * gr_lil_mat_col_srcptr(const gr_lil_mat_t mat, slong i, slong j) + + Get a (const) pointer to the column of the *j*-th nonzero in the *i*-th row of *mat*. + There is no bounds checking. + +.. function:: gr_ptr gr_csr_mat_entry_ptr(gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) + gr_srcptr gr_csr_mat_entry_srcptr(gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) + gr_ptr gr_lil_mat_entry_ptr(gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) + gr_srcptr gr_lil_mat_entry_srcptr(gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) + + Get a (const) pointer to the *j*-th nonzero entry in the *i*-th row of *mat*. + There is no bounds checking. + +.. function:: void gr_csr_mat_init(gr_csr_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) + void gr_lil_mat_init(gr_lil_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) + + Initializes *mat* to a *rows* x *cols* matrix with no nonzeros. + +.. function:: void gr_csr_mat_clear(gr_csr_mat_t vec, gr_ctx_t ctx) + void gr_lil_mat_clear(gr_lil_mat_t vec, gr_ctx_t ctx) + + Clears the matrix *mat*. + +.. function:: gr_csr_mat_swap(gr_csr_mat_t mat1, gr_csr_mat_t mat2, gr_ctx_t ctx) + gr_lil_mat_swap(gr_lil_mat_t mat1, gr_lil_mat_t mat2, gr_ctx_t ctx) + + Swap data underlying two sparse matrices (no allocation or copying). + +.. function:: void gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx) + + Ensure that *mat* has enough storage to hold at least *nnz* nonzeros. This does + not change the dimensions of the matrix or the number of nonzeros stored. + + Note that, for matrices in *lil* form, one must perform the analogous operation + on each row. + +.. function:: void gr_csr_mat_shrink_to_nnz(gr_csr_mat_t mat, gr_ctx_t ctx) + + Reallocate the storage in *mat* down the current number of nonzeros. + + Note that, for matrices in *lil* form, the analogous operation is performed + on each row. + +.. function:: void gr_csr_mat_set_cols(gr_csr_mat_t mat, slong cols, gr_ctx_t ctx) + void gr_lil_mat_set_cols(gr_llil_mat_t mat, slong cols, gr_ctx_t ctx) + + Set the nominal number of columns of the matrix *mat* to *cols*. If *cols* is smaller than + the current number of columns of *vec*, any entries whose columns are at least *cols* + are truncated. That is, the number of nonzeros can change. + + + +Getting, setting and conversion +-------------------------------------------------------------------------------- + +.. function:: int gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t vec, slong row, slong col, gr_ctx_t ctx) + int gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t vec, slong row, slong col, gr_ctx_t ctx) + + Set *res* to be the entry at position (*row*, *col*). + + Because of the way sparse matrices are represented, this is logarithmic time in the number of nonzeros + in the specified row. + +.. function:: int gr_csr_mat_set_entry(gr_csr_mat_t vec, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx) + int gr_lil_mat_set_entry(gr_lil_mat_t vec, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx) + + Set the the entry at location (*row*, *col*) to be *entry*. + + Because of the way sparse vectors are represented, it is not efficient to call this function + repeatedly: for the list of lists representation, it is linear time in the number of nonzeros + in the associated row; for the sparse compressed row representation, it is linear time in the + overall number of nonzeroes. If possible, the entries to update should be batched up and + given using `gr_lil_mat_update`, `gr_csr_mat_set_from_coo`, `gr_lil_mat_set_from_coo`, + `gr_csr_mat_set_from_coo_sorted_deduped`, or `gr_lil_mat_set_from_coo_sorted_deduped`. + +.. function:: int gr_csr_mat_zero(gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_zero(gr_lil_mat_t mat, gr_ctx_t ctx) + + Set *mat* to the zero matrix. + +.. function:: int gr_csr_mat_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_csr_mat_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + + Set *res* to a copy of *mat*, possibly changing the type of representation. + +.. function:: int gr_csr_mat_set_mat(gr_csr_mat_t res, gr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_set_mat(gr_lil_mat_t res, gr_mat_t mat, gr_ctx_t ctx) + + Set *res* from the (nominally) dense matrix *mat*. + +.. function:: int gr_mat_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_mat_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + + Set a dense matrix *res* from the sparse matrix *mat*, for either representation. + +.. function:: int gr_csr_mat_init_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_init_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_csr_mat_init_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_init_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_csr_mat_init_set_mat(gr_csr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_init_set_mat(gr_lil_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) + int gr_mat_init_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_mat_init_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + + Simultaneous initialize and setting. + +.. function:: int gr_lil_mat_update(gr_lil_mat_t res, const gr_lil_mat_t_t src, gr_ctx_t ctx) + + Update *res* with the nonzeros in *src*. That is, any (row, col) indices in *res* which also appear + in *src* are overwritten with their values in *src*. Any indices in *res* which do + not appear in *src* are left unchanged. + +.. function:: int gr_csr_mat_set_from_coo(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) + int gr_lil_mat_set_from_coo(gr_lil_mat_t vec, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) + + Set *mat* from the sparse data given by arrays *rows*, *cols*, and *entries*. + + These functions allow one to construct a matrix from nonzero data in coo(rdinate) form, i.e., + a list of triples of (row, col, entry) (provided as parallel arrays *rows*, *cols*, *entries*). + No assumption is made that the indices are sorted nor that the entries are nonzero. The values associated + with duplicate indices are added together. + +.. function:: int gr_csr_mat_set_from_coo_sorted_deduped(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) + int gr_csr_mat_set_from_coo_sorted_deduped(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) + + Set *mat* from the sparse data given by arrays *rows*, *cols*, and *entries*. + + Similar to the set from coo functions, save that the entries are required to be nonzero and the + (row, col) pairs distinct and sorted (by row then col). + +.. function:: int gr_csr_mat_randtest(gr_csr_mat_t mat, double row_density, slong nrows, slong ncols, flint_rand_t state, gr_ctx_t ctx) + int gr_lil_mat_randtest(gr_lil_mat_t mat, double row_density, slong nrows, slong ncols, flint_rand_t state, gr_ctx_t ctx) + + Initialize *mat* to a random *nrows* x *ncols* matrix with row density (fraction of nonzeros) + *density*. The algorithm is suitable when *density* is small. + Specifically, indices are generated randomly and deduped. So if the + density is larger than ``1/sqrt(ncols)``, the true density of the returned vector + is likely to be lower than *density*. + +.. function:: void gr_lil_mat_window_init(gr_lil_mat_t window, const gr_lil_mat_t mat, slong r1, slong c1, slong r2, slong c2, gr_ctx_t ctx) + void gr_lil_mat_window_clear(gr_lil_mat_t window, gr_ctx_t ctx) + + A window is a view on a submatrix with a given interval of rows and columns, and is provided + by using pointer offsets into the given matrix (so no copying is performed). The window + produced is read-only. + +.. function:: int gr_scr_mat_permute_cols(gr_scr_mat_t mat, slong * perm, gr_ctx_t ctx) + int gr_lil_mat_permute_cols(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx) + + Permute the columns in *mat* according to the given permutation, i.e., ``mat[r][perm[i]] = mat[i]``. + +.. function:: int gr_lil_mat_swap_rows(gr_lil_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx) + int gr_lil_mat_permute_rows(gr_lil_mat_t mat, const slong * perm, gr_ctx_t ctx) + int gr_lil_mat_invert_rows(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx) + int gr_scr_mat_invert_rows(gr_scr_mat_t mat, slong * perm, gr_ctx_t ctx) + + Swap two rows in the matrix *mat*, permute the rows according to the given permutation, + or invert all the rows. Note that the permutation *perm* is an input for the rows permutation + function (required to be non-null), while for the other functions it may be optionally provided + to keep track of the permutation(s) performed. + + Because of the nature of the sparse compressed row representation, swapping + and permuting rows is an expensive operation and thus not provided. + +Comparison +-------------------------------------------------------------------------------- + +.. function:: truth_t gr_csr_mat_is_zero(const gr_csr_mat_t mat, gr_ctx_t ctx) + truth_t gr_lil_mat_is_zero(const gr_lil_mat_t mat, gr_ctx_t ctx) + + Return ``T_TRUE`` if *mat* has no nonzeroes, ``T_FALSE`` if has any element + known to be nonzero, and ``T_UNKNOWN`` otherwise. + +.. function:: truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx) + truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx) + truth_t gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx) + truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx) + + Return ``T_TRUE`` if *mat* is square, has one nonzero element in each row (at the + corresponding column), and that element is known to be equal to (negative) one; ``T_FALSE`` if + the matrix is not square, has any off-diagonal element known to be nonzero, or has + any diagonal known to not be (negative) one; and ``T_UNKNOWN`` otherwise. + +.. function:: truth_t gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx) + truth_t gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) + truth_t gr_csr_mat_equal_lil_mat(const gr_csr_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) + + Returns ``T_TRUE`` if *mat1* and *mat2* represent the same matrix and ``T_FALSE`` otherwise. + + +Output +-------------------------------------------------------------------------------- + +.. function:: int gr_csr_mat_write_nz(gr_stream_t out, const gr_csr_mat_t vec, gr_ctx_t ctx) + int gr_lil_mat_write_nz(gr_stream_t out, const gr_lil_mat_t vec, gr_ctx_t ctx) + + Write the nonzeros of *mat* to the stream *out*. See ``gr_mat_set_csr_mat`` and + ``gr_mat_set_lil_mat`` if it is desired to write out the entire matrix, zeros and all. + +.. function:: int gr_csr_mat_print_nz(const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_print_nz(const gr_lil_mat_t mat, gr_ctx_t ctx) + + Print the nonzeros of *mat* to ``stdout``. See ``gr_mat_set_csr_mat`` and + ``gr_mat_set_lil_mat`` if it is desired to print out the entire matrix, zeros and all. + + +Arithmetic +-------------------------------------------------------------------------------- + +.. function:: int gr_csr_mat_neg(gr_csr_mat_t res, const gr_csr_mat_t src, gr_ctx_t ctx) + int gr_lil_mat_neg(gr_lil_mat_t res, const gr_csr_mat_t src, gr_ctx_t ctx) + + Set *res* to -*src*. + +.. function:: int gr_lil_mat_add(gr_lil_mat_t res, const gr_lil_mat_t src1, const gr_lil_mat_t src2, slong len, gr_ctx_t ctx) + int gr_lil_mat_sub(gr_lil_mat_t res, const gr_lil_mat_t src1, const gr_lil_mat_t src2, slong len, gr_ctx_t ctx) + int gr_lil_mat_mul(gr_lil_mat_t res, const gr_lil_mat_t src1, const gr_lil_mat_t src2, slong len, gr_ctx_t ctx) + + Componentwise operations. (We do not provide analogous division or exponentiation + routines due since sparse inputs to these operations would be undefined or + fully dense.) + +.. function:: int gr_lil_mat_addmul_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_lil_mat_submul_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) + + Componentwise add and sub mul, with different options for the scalar. + + +Arithmetic into dense vectors +-------------------------------------------------------------------------------- + +.. function:: int gr_vec_update_sparse_vec_nz(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) + int gr_vec_add_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_vec_sub_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_vec_mul_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_vec_div_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) + int gr_vec_addmul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) + int gr_vec_submul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) + int gr_vec_addmul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) + int gr_vec_submul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) + int gr_vec_addmul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) + int gr_vec_submul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) + + These functions facilitate accumulating a sparse vector into a dense + target. They have one dense input, one sparse input, and a dense output + (where the dense input and output are the same for the fused operations). + For all functions, it is assumed that *dres* and *dvec1* have the same + length as *svec* or *svec2*, as appropriate. All functions only modify + the locations in *dres* at which the sparse vector has a nonzero value: + in particular, the functions *gr_vec_mul_sparse_vec_nz* and + *gr_vec_div_sparse_vec_nz* behave very differently from their dense counterparts. + + +Componentwise multiplication and division +-------------------------------------------------------------------------------- + +.. function:: int gr_csr_mat_mul_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_2exp_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_2exp_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) + + Set *res* to be *src* multiplied or divided by *c*. + (Addition and subtraction are not provided because they would create + dense output.) + +Sum and product +-------------------------------------------------------------------------------- + +.. function:: int gr_csr_mat_sum(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_sum(gr_ptr res, const gr_lil_mat_t mat, gr_ctx_t ctx) + + Set *res* to the sum of the entries in *mat*. + +.. function:: int gr_csr_mat_product(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_product(gr_ptr res, const gr_lil_mat_t mat, gr_ctx_t ctx) + + Set *res* to the product of the nonzero entries in *mat*. + + +Matrix multiplication +-------------------------------------------------------------------------------- + +.. function:: int gr_csr_mat_mul_vec(gr_vec_t v, const gr_csr_mat_t A, const gr_vec_t u, gr_ctx_t ctx) + int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ctx_t ctx) + + Set *v* equal to `A \cdot u`, i.e., right multiplication by *u*. + +.. function:: int gr_csr_mat_mul_mat_transpose(gr_mat_t Ct, const gr_csr_mat_t A, const gr_mat_t Bt, gr_ctx_t ctx) + int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_mat_t A, const gr_mat_t Bt, gr_ctx_t ctx) + + Set *C^T* equal to `A \cdot B^T`, i.e., right multiplication with *B* and *C* considered to + be column matrices. + + This is the standard procedure use by solving, and is maximally cache friendly. + +.. function:: int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ctx_t ctx) + int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ctx_t ctx) + + Set *C* equal to `A \cdot B`, i.e., perform right multiplication by *B*. + + +.. raw:: latex + + \newpage diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index 0eedbf56a8..10e56e995e 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -1,6 +1,6 @@ .. _gr-sparse-vec: -**gr_sparse_vec.h** -- Sparse vectors over generic rings +**gr_sparse_vec.h** -- sparse vectors over generic rings =============================================================================== A :type:`gr_sparse_vec_t` is a represention of a vector over a generic @@ -20,15 +20,17 @@ Types and basic access This struct contains: - * A pointer to an `slong` array of indices (``inds``) of nonzeros. - * A :type:`gr_ptr` array of values of nonzeros (``entries``). - * `slong` values to record the number of nonzeros (``nnz``), the nominal length of the vector (the dimension of the vector space) (``length``), and the space allocated in the ``inds`` and ``entries`` arrays. + * an `slong` value ``length``, the nominal length of the vector, + * an `slong` value ``nnz``, the number of nonzero elements in vector, + * an `slong` value ``alloc``, the maximum number of nonzero element currently storable in the vector, + * a pointer to an `slong` array of indices (``inds``) of nonzeros. + * a :type:`gr_ptr` array of values of nonzeros (``entries``). - We always require: + The methods for sparse vectors maintain the following properties: - * The ``inds`` are sorted into strictly increasing order - * The ``entries`` are nonzero (meaning, ``gr_is_zero(GR_ENTRY(vec->entries, i, ctx->sizeof_elem), ctx)`` returns ``T_FALSE`` for ``0 <= i < vec->nnz``). - * We have ``nnz <= alloc <= length``. + * the indices ``inds`` are unique and sorted into strictly increasing order; + * the ``entries`` are nonzero (``gr_is_zero(entry, ctx)`` does not return ``T_TRUE``). + * ``nnz <= alloc <= length``. A ``gr_sparse_vec_t`` is defined as an array of length one of type ``gr_sparse_vec_struct``, permitting a ``gr_sparse_vec_t`` to @@ -36,28 +38,26 @@ Types and basic access .. function:: void gr_sparse_vec_init(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) - Initializes *vec* to a vector of length *len* with no nonzeros. + Initializes *vec* to an empty vector of length *len* in the ring *ctx*. The + length must be nonnegative. No storage for nonzeroes is allocated. .. function:: void gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) - Clears the vector *vec* + Clears the vector *vec*. -.. macro:: GR_SPARSE_VEC_IND(vec, i) +.. function:: slong gr_sparse_vec_length(const gr_sparse_vec_t vec) - Access the index of the *i*-th nonzero. - There is no bounds checking. (See also `gr_sparse_vec_find_entry`) + Return the nominal length of the vector (note: not the number of nonzeros). -.. macro:: GR_SPARSE_VEC_ENTRY(vec, i, sz) +.. function:: void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) - Access the value of the *i*-th nonzero. - There is no bounds checking. (See also `gr_sparse_vec_find_entry`) + Set the nominal length of the vector *vec* to *len*. If *len* is smaller than + the current length of *vec*, any entries whose indices are at least *len* + are truncated. That is, the number of nonzeros can change. -.. function:: ulong * gr_sparse_vec_ind_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) - const ulong * gr_sparse_vec_ind_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) - gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) - gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) +.. function:: slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) - Get pointers to the specified indices and entries. + Get the number of nonzeros in *vec*. .. function:: void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) @@ -68,96 +68,112 @@ Types and basic access Reallocate the storage in *vec* down the current number of nonzeros. -.. function:: slong gr_sparse_vec_length(const gr_sparse_vec_t vec) +.. function:: int gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx) - Return the nominal length of the vector (note: not the number of nonzeros). + Construct *vec* from the sparse data given by *inds* and *entries* of length *nnz*. + If ``is_canonical`` is true, the indices are assumed to be sorted and unique, and + the entries are assumed to be nonzero. Otherwise, the function will sort and compress + the entries to leave the vector in sorted, unique, nonzero form. -.. function:: void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_randtest(gr_sparse_vec_t vec, slong nnz, int replacement, flint_rand_t state, gr_ctx_t ctx) - Set the nominal length of the vector *vec* to *len*. If *len* is smaller than - the current length of *vec*, any entries whose indices are at least *len* - are truncated. That is, the number of nonzeros can change. + Initialize *vec* to a random vector with ``nnz`` nonzero columns, sampled + either with or without replacement. For small values of ``nnz`` (below + ``1/sqrt(length)``), sampling with replacement is faster and likely to + give the right number of nonzeroes. For larger values of ``nnz``, this + function uses reservoir sampling to get the specified number of nonzeroes + with uniform sampling. The entry at each column so sampled + is generated using ``gr_randtest_nonzero``. -.. function:: slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) +.. function:: int gr_sparse_vec_randtest(gr_sparse_vec_t vec, double prob, int replacement, flint_rand_t state, gr_ctx_t ctx) - Get the number of nonzeros in *vec*. + Initialize *vec* to a random vector, in which each column is independently + sampled with probability ``prob``. The entry at each column so sampled + is generated using ``gr_randtest_nonzero``. Getting, setting and conversion -------------------------------------------------------------------------------- -.. function:: int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +.. macro:: GR_SPARSE_VEC_IND(vec, i) - Set *src* to a copy of *res*. + Macro to access the index of the *i*-th nonzero. + The index must be in bounds (between 0 and ``vec->nnz``). -.. function:: int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong ind, gr_srcptr entry, gr_ctx_t ctx) +.. macro:: GR_SPARSE_VEC_ENTRY(vec, i, sz) - Set the the value at index *ind* to be *entry*. Because of the way sparse - vectors are represented, it is not efficient to call this function - repeatedly (it is linear time in the number of nonzeros in *vec*). - If possible, the entries to update should be batched up and - given using `gr_sparse_vec_update`, `gr_sparse_vec_set_from_entries`, - or `gr_sparse_vec_set_from_entries_sorted_deduped`. + Access the value of the *i*-th nonzero. + The index must be in bounds (between 0 and ``vec->nnz``). + (See also `gr_sparse_vec_get_entry`) -.. function:: int gr_sparse_vec_find_entry(gr_ptr res, gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx) +.. function:: ulong * gr_sparse_vec_ind_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) + const ulong * gr_sparse_vec_ind_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) + gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) + gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong i, gr_ctx_t ctx) - Set *res* to be the entry at index *ind*. If *ind* is not a index - in which *vec* contains a nonzero, *res* is set to zero. - Because of the way sparse vectors are represented, this is not constant time. - (It is log time in the number of nonzeros in *vec*.) + Get pointers to the index or value of the *i*th nonzero. Unlike the above + macros, these perform bounds checking, and return NULL if out of bounds. -.. function:: int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +.. function:: gr_ptr gr_sparse_vec_find_entry(gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx) - Update *res* with the nonzeros in *src*. That is, any index in *res* which also appear - in *src* are overwritten with their values in *src*. Any indices in *res* which do - not appear in *src* are left unchanged. + Return a pointer to the entry at index *ind*. If *ind* is not a index + in which *vec* contains a nonzero (including if it is out of bounds), + the function returns NULL. This is performed via binary search, so + is worst-case logarithmic time. -.. function:: int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_get_entry(gr_ptr res, gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx) - Set *vec* to the sparse data given by *inds* and *entries* of length *nnz*. No assumption - is made that the indices are sorted nor that the entries are nonzero. The values associated - with duplicate indices are added together. + Set *res* to be a copy of the entry at index *ind*. If *ind* is not a index + in which *vec* contains a nonzero, *res* is set to zero. This is performed via binary search, so + is worst-case logarithmic time. -.. function:: int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong ind, gr_srcptr entry, gr_ctx_t ctx) - Set *vec* to the sparse data given by *sorted_deduped_inds* and *entries*. The - *sorted_deduped_inds* must be in strictly increasing order. It is not required - that the values in *entries* are nonzero. + Set the the value at index *ind* to be *entry*. Because of the way sparse + vectors are represented, it is not efficient to call this function + repeatedly (it is worst-case linear time in the number of nonzeros in *vec*). + In such cases, it is preferrable to construct a new sparse vector from the entries + (using `gr_sparse_vec_set_from_entries` or `gr_sparse_vec_set_from_entries_sorted_deduped`) + passed to `gr_sparse_vec_update`. -.. function:: int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) - Set *vec* to the zero vector. + Set *src* to a copy of *res*. -.. function:: int gr_sparse_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong ind_start, slong ind_end, gr_ctx_t ctx) - Initialize *vec* to a random vector with density (fraction of nonzeros) - *density* and length *len*. The algorithm is suitable when *density* is small. - Specifically, indices are generated randomly and deduped. So if the - density is larger than ``1/sqrt(len)``, the true density of the returned vector - is likely to be lower than *density*. + Set *res* to a copy of the slice of *src* given by any entries whose + indices lie in the half open interval ``[ind_start, ind_end)``. + Column indices are shifted by *ind_start* (a index of ``ind_start`` + would become ``0``). .. function:: int gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx) - Convert the dense vector *src* of length *len* to the sparse vector *vec*. + Set *vec* from the (raw) dense vector *src* of length *len*. .. function:: int gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) - Convert the sparse vector *src* into a dense vector *vec*, which must have + Set the raw vector *vec* from sparse vector *src*. *vec* must have sufficient space (i.e. ``vec->length``). -.. function:: int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong ind_start, slong ind_end, gr_ctx_t ctx) +.. function:: void gr_sparse_vec_swap(gr_sparse_vec_t res, gr_sparse_vec_t src, gr_ctx_t ctx) - Set *res* to a copy of the slice of *src* given by any entries whose - indices lie in the half open interval ``[ind_start, ind_end)``. - Column indices are shifted by *ind_start* (a index of ``ind_start`` - would become ``0``). + Swap the sparse vectors *res* and *src*. The entries are swapped as pointers, so + no additional allociation or copying is performed. + +.. function:: int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) + + Set *vec* to the zero vector. + +.. function:: int gr_sparse_vec_one(gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx) + + Set *vec* to the elementary vector with a one at index *ind*. .. function:: int gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx) Set *vec* to a copy of *src* with the indices permuted. The indices are shifted as: ``vec[p[i]] = src[i]``. - Comparison -------------------------------------------------------------------------------- @@ -187,6 +203,16 @@ Output Arithmetic -------------------------------------------------------------------------------- +.. function:: int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) + + Set *res* to -*src* + +.. function:: int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) + + Update *res* with the nonzeros in *src*. That is, any index in *res* which also appear + in *src* are overwritten with their values in *src*. Any indices in *res* which do + not appear in *src* are left unchanged. + .. function:: int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) @@ -214,10 +240,6 @@ Arithmetic Componentwise add and sub mul, with different options for the scalar. -.. function:: int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) - - Set *res* to -*src* - Arithmetic into dense vectors -------------------------------------------------------------------------------- @@ -244,7 +266,7 @@ Arithmetic into dense vectors *gr_vec_div_sparse_vec_nz* behave very differently from their dense counterparts. -Componentwise multiplication and division +Scalar multiplication and division -------------------------------------------------------------------------------- .. function:: int gr_sparse_vec_mul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) @@ -280,7 +302,7 @@ Sum and product Set *res* to the product of the nonzero entries in *vec*. -Dot products +Dot product -------------------------------------------------------------------------------- .. function:: int gr_sparse_vec_dot(gr_ptr res, gr_srcptr c, int subtract, const gr_sparse_vec_t x, const gr_sparse_vec_t y, gr_ctx_t ctx) diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 7d33b49199..30fa6a68ed 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2023 Fredrik Johansson + Copyright (C) 2024 Kartik Venkatram and Alden Walker This file is part of FLINT. @@ -39,72 +39,144 @@ typedef struct slong alloc; ulong * rows; ulong * cols; - gr_ptr entries; + gr_ptr nzs; } gr_csr_mat_struct; +typedef gr_csr_mat_struct gr_csr_mat_t[1]; + typedef struct { slong r; slong c; slong nnz; - gr_sparse_vec_t * rows; + gr_sparse_vec_struct * rows; } gr_lil_mat_struct; +typedef gr_lil_mat_struct gr_lil_mat_t[1]; -typedef gr_csr_mat_struct gr_csr_mat_t[1]; +typedef struct +{ + slong r; + slong c; + slong nnz; + slong alloc; + ulong * rows; + ulong * cols; + gr_ptr nzs; + int is_canonical; +} +gr_coo_mat_struct; -typedef gr_lil_mat_struct gr_lil_mat_t[1]; +typedef gr_coo_mat_struct gr_coo_mat_t[1]; #define gr_sparse_mat_nrows(mat, ctx) ((mat)->r) #define gr_sparse_mat_ncols(mat, ctx) ((mat)->c) #define gr_sparse_mat_nnz(mat, ctx) ((mat)->nnz) -#define GR_CSR_MAT_COL(mat,i,j) ((mat)->cols + (mat)->rows[i] + j) -#define GR_LIL_MAT_COL(mat,i,j) ((mat)->rows[i]->inds + j) +#define GR_CSR_MAT_COL(mat,row,nz_idx) ((mat)->cols + (mat)->rows[row] + nz_idx) +#define GR_CSR_MAT_ENTRY(mat,row,nz_idx,sz) GR_ENTRY((mat)->nzs, (mat)->rows[row] + nz_idx, sz) -#define GR_CSR_MAT_ENTRY(mat,i,j,sz) GR_ENTRY((mat)->entries, (mat)->rows[i] + j, sz) -#define GR_LIL_MAT_ENTRY(mat,i,j,sz) GR_ENTRY((mat)->rows[i]->entries, j, sz) +#define GR_LIL_MAT_COL(mat,row,nz_idx) ((mat)->rows[row].inds + nz_idx) +#define GR_LIL_MAT_ENTRY(mat,row,nz_idx,sz) GR_ENTRY((mat)->rows[row].nzs, nz_idx, sz) -GR_SPARSE_MAT_INLINE ulong * gr_csr_mat_col_ptr(gr_csr_mat_t mat, slong i, slong j) +#define GR_COO_MAT_ROW(mat,nz_idx) ((mat)->rows + nz_idx) +#define GR_COO_MAT_COL(mat,nz_idx) ((mat)->cols + nz_idx) +#define GR_COO_MAT_ENTRY(mat,nz_idx,sz) GR_ENTRY((mat)->nzs, nz_idx, sz) + +GR_SPARSE_MAT_INLINE ulong * +gr_csr_mat_col_ptr(gr_csr_mat_t mat, slong row, slong nz_idx) { - return GR_CSR_MAT_COL(mat, i, j); + return GR_CSR_MAT_COL(mat, row, nz_idx); } -GR_SPARSE_MAT_INLINE const ulong * gr_csr_mat_col_srcptr(const gr_csr_mat_t mat, slong i, slong j) +GR_SPARSE_MAT_INLINE const ulong * +gr_csr_mat_col_srcptr(const gr_csr_mat_t mat, slong row, slong nz_idx) { - return GR_CSR_MAT_COL(mat, i, j); + if (row < 0 || row >= mat->r || nz_idx < 0 || mat->rows[row] + nz_idx >= mat->rows[row+1]) + return NULL; + return GR_CSR_MAT_COL(mat, row, nz_idx); } -GR_SPARSE_MAT_INLINE ulong * gr_lil_mat_col_ptr(gr_lil_mat_t mat, slong i, slong j) +GR_SPARSE_MAT_INLINE gr_ptr +gr_csr_mat_entry_ptr(gr_csr_mat_t mat, slong row, slong nz_idx, gr_ctx_t ctx) { - return GR_LIL_MAT_COL(mat, i, j); + if (row < 0 || row >= mat->r || nz_idx < 0 || mat->rows[row] + nz_idx >= mat->rows[row+1]) + return NULL; + return GR_CSR_MAT_ENTRY(mat, row, nz_idx, ctx->sizeof_elem); } -GR_SPARSE_MAT_INLINE const ulong * gr_lil_mat_col_srcptr(const gr_lil_mat_t mat, slong i, slong j) +GR_SPARSE_MAT_INLINE gr_srcptr +gr_csr_mat_entry_srcptr(const gr_csr_mat_t mat, slong row, slong nz_idx, gr_ctx_t ctx) { - return GR_LIL_MAT_COL(mat, i, j); + if (row < 0 || row >= mat->r || nz_idx < 0 || mat->rows[row] + nz_idx >= mat->rows[row+1]) + return NULL; + return GR_CSR_MAT_ENTRY(mat, row, nz_idx, ctx->sizeof_elem); } -GR_SPARSE_MAT_INLINE gr_ptr gr_csr_mat_entry_ptr(gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE ulong * +gr_lil_mat_col_ptr(gr_lil_mat_t mat, slong row, slong nz_idx) { - return GR_CSR_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); + if (row < 0 || row >= mat->r || nz_idx < 0 || nz_idx >= mat->rows[row].nnz) + return NULL; + return GR_LIL_MAT_COL(mat, row, nz_idx); } -GR_SPARSE_MAT_INLINE gr_srcptr gr_csr_mat_entry_srcptr(const gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE const ulong * +gr_lil_mat_col_srcptr(const gr_lil_mat_t mat, slong row, slong nz_idx) { - return GR_CSR_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); + if (row < 0 || row >= mat->r || nz_idx < 0 || nz_idx >= mat->rows[row].nnz) + return NULL; + return GR_LIL_MAT_COL(mat, row, nz_idx); } -GR_SPARSE_MAT_INLINE gr_ptr gr_lil_mat_entry_ptr(gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE gr_ptr +gr_lil_mat_entry_ptr(gr_lil_mat_t mat, slong row, slong nz_idx, gr_ctx_t ctx) { - return GR_LIL_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); + if (row < 0 || row >= mat->r || nz_idx < 0 || nz_idx >= mat->rows[row].nnz) + return NULL; + return GR_LIL_MAT_ENTRY(mat, row, nz_idx, ctx->sizeof_elem); } -GR_SPARSE_MAT_INLINE gr_srcptr gr_lil_mat_entry_srcptr(const gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE gr_srcptr +gr_lil_mat_entry_srcptr(const gr_lil_mat_t mat, slong row, slong nz_idx, gr_ctx_t ctx) { - return GR_LIL_MAT_ENTRY(mat, i, j, ctx->sizeof_elem); + if (row < 0 || row >= mat->r || nz_idx < 0 || nz_idx >= mat->rows[row].nnz) + return NULL; + return GR_LIL_MAT_ENTRY(mat, row, nz_idx, ctx->sizeof_elem); +} + +GR_SPARSE_MAT_INLINE ulong * +gr_coo_mat_row_ptr(gr_coo_mat_t mat, slong nz_idx) +{ + if (nz_idx < 0 || nz_idx >= mat->nnz) + return NULL; + return GR_COO_MAT_ROW(mat, nz_idx); +} + +GR_SPARSE_MAT_INLINE const ulong * +gr_coo_mat_col_srcptr(const gr_coo_mat_t mat, slong nz_idx) +{ + if (nz_idx < 0 || nz_idx >= mat->nnz) + return NULL; + return GR_COO_MAT_COL(mat, nz_idx); +} + +GR_SPARSE_MAT_INLINE gr_ptr +gr_coo_mat_entry_ptr(gr_coo_mat_t mat, slong nz_idx, gr_ctx_t ctx) +{ + if (nz_idx < 0 || nz_idx >= mat->nnz) + return NULL; + return GR_COO_MAT_ENTRY(mat, nz_idx, ctx->sizeof_elem); +} + +GR_SPARSE_MAT_INLINE gr_srcptr +gr_coo_mat_entry_srcptr(const gr_coo_mat_t mat, slong nz_idx, gr_ctx_t ctx) +{ + if (nz_idx < 0 || nz_idx >= mat->nnz) + return NULL; + return GR_COO_MAT_ENTRY(mat, nz_idx, ctx->sizeof_elem); } /* Generics */ @@ -127,25 +199,35 @@ gr_csr_mat_init(gr_csr_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) { memset(mat, 0, sizeof(gr_csr_mat_t)); mat->r = rows; mat->c = cols; - mat->nnz = 0; - mat->alloc = 0; mat->rows = flint_calloc(rows + 1, sizeof(ulong)); } GR_SPARSE_MAT_INLINE void gr_lil_mat_init(gr_lil_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) { + int row; + + memset(mat, 0, sizeof(gr_lil_mat_t)); + mat->r = rows; + mat->c = cols; + mat->rows = flint_calloc(rows, sizeof(gr_sparse_vec_struct)); + + for(row = 0; row < mat->r; ++row) + gr_sparse_vec_init(&mat->rows[row], cols, ctx); +} + +GR_SPARSE_MAT_INLINE void +gr_coo_mat_init(gr_coo_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) { + memset(mat, 0, sizeof(gr_lil_mat_t)); mat->r = rows; mat->c = cols; - mat->nnz = 0; - mat->rows = flint_calloc(rows, sizeof(gr_sparse_vec_t)); } GR_SPARSE_MAT_INLINE void gr_csr_mat_clear(gr_csr_mat_t mat, gr_ctx_t ctx) { if (mat->alloc != 0) { - _gr_vec_clear(mat->entries, mat->alloc, ctx); - flint_free(mat->entries); + _gr_vec_clear(mat->nzs, mat->alloc, ctx); + flint_free(mat->nzs); flint_free(mat->cols); } flint_free(mat->rows); @@ -156,13 +238,24 @@ GR_SPARSE_MAT_INLINE void gr_lil_mat_clear(gr_lil_mat_t mat, gr_ctx_t ctx) { int row; - for (row = 0; row < mat->r; ++row) { - gr_sparse_vec_clear(mat->rows[row], ctx); - } + for (row = 0; row < mat->r; ++row) + gr_sparse_vec_clear(&mat->rows[row], ctx); flint_free(mat->rows); memset(mat, 0, sizeof(gr_lil_mat_t)); } +GR_SPARSE_MAT_INLINE void +gr_coo_mat_clear(gr_coo_mat_t mat, gr_ctx_t ctx) { + if (mat->alloc != 0) + { + _gr_vec_clear(mat->nzs, mat->alloc, ctx); + flint_free(mat->nzs); + flint_free(mat->rows); + flint_free(mat->cols); + } + memset(mat, 0, sizeof(gr_csr_mat_t)); +} + GR_SPARSE_MAT_INLINE void gr_csr_mat_swap(gr_csr_mat_t mat1, gr_csr_mat_t mat2, gr_ctx_t ctx) { @@ -175,21 +268,50 @@ gr_lil_mat_swap(gr_lil_mat_t mat1, gr_lil_mat_t mat2, gr_ctx_t ctx) FLINT_SWAP(gr_lil_mat_struct, *mat1, *mat2); } +GR_SPARSE_MAT_INLINE void +gr_coo_mat_swap(gr_coo_mat_t mat1, gr_coo_mat_t mat2, gr_ctx_t ctx) +{ + FLINT_SWAP(gr_coo_mat_struct, *mat1, *mat2); +} + void gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx); +void +gr_lil_mat_fit_nnz(gr_coo_mat_t mat, slong *nnz, gr_ctx_t ctx); + +void +gr_coo_mat_fit_nnz(gr_coo_mat_t mat, slong nnz, gr_ctx_t ctx); + + void gr_csr_mat_shrink_to_nnz(gr_csr_mat_t mat, gr_ctx_t ctx); void gr_lil_mat_shrink_to_nnz(gr_lil_mat_t mat, gr_ctx_t ctx); +void +gr_coo_mat_shrink_to_nnz(gr_coo_mat_t mat, gr_ctx_t ctx); + + void gr_csr_mat_set_cols(gr_csr_mat_t mat, slong cols, gr_ctx_t ctx); void gr_lil_mat_set_cols(gr_lil_mat_t mat, slong cols, gr_ctx_t ctx); +void +gr_coo_mat_set_cols(gr_coo_mat_t mat, slong cols, gr_ctx_t ctx); + +int +gr_coo_mat_from_entries(gr_coo_mat_t mat, ulong *rows, ulong *cols, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx); + +int +gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_coo_mat_randtest(gr_coo_mat_t mat, ulong nnz, flint_rand_t state, gr_ctx_t ctx); + /** * Getting, setting, and conversion **/ @@ -199,146 +321,243 @@ _gr_csr_mat_borrow_row(gr_sparse_vec_t res, const gr_csr_mat_t mat, slong r, gr_ ulong offset; offset = mat->rows[r]; + res->length = mat->c; res->nnz = mat->rows[r+1] - offset; res->alloc = res->nnz; res->inds = mat->cols + offset; + res->nzs = GR_ENTRY(mat->nzs, offset, ctx->sizeof_elem); +} + +GR_SPARSE_MAT_INLINE void +_gr_coo_mat_borrow_row(gr_sparse_vec_t res, gr_coo_mat_t mat, slong r, gr_ctx_t ctx) { + ulong offset, nnz; + + if (!mat->is_canonical) + gr_coo_mat_canonicalize(mat, ctx); + + // Binary search to find start and end of row + offset = 0; + nnz = 0; + res->length = mat->c; - res->entries = GR_ENTRY(mat->entries, offset, ctx->sizeof_elem); + res->nnz = nnz; + res->alloc = nnz; + res->inds = mat->cols + offset; + res->nzs = GR_ENTRY(mat->nzs, offset, ctx->sizeof_elem); } +gr_ptr +gr_csr_mat_find_entry(gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx); + +gr_ptr +gr_lil_mat_find_entry(gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx); + +gr_ptr +gr_coo_mat_find_entry(gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx); + WARN_UNUSED_RESULT int -gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t vec, slong row, slong col, gr_ctx_t ctx); +gr_coo_mat_get_entry(gr_ptr res, gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t vec, slong row, slong col, gr_ctx_t ctx); +gr_csr_mat_set_entry(gr_csr_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_csr_mat_set_entry(gr_csr_mat_t vec, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); +gr_lil_mat_set_entry(gr_lil_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_lil_mat_set_entry(gr_lil_mat_t vec, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); +gr_coo_mat_set_entry(gr_coo_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); GR_SPARSE_MAT_INLINE void -gr_csr_mat_zero(gr_csr_mat_t res, gr_ctx_t ctx) { - res->nnz = 0; - memset(res->rows, 0, (res->r + 1) * sizeof(ulong)); +gr_csr_mat_zero(gr_csr_mat_t mat, gr_ctx_t ctx) { + mat->nnz = 0; + memset(mat->rows, 0, (mat->r + 1) * sizeof(ulong)); } GR_SPARSE_MAT_INLINE void -gr_lil_mat_zero(gr_lil_mat_t res, gr_ctx_t ctx) { +gr_lil_mat_zero(gr_lil_mat_t mat, gr_ctx_t ctx) { int row; - res->nnz = 0; - for(row = 0; row < res->r; ++row) + mat->nnz = 0; + for(row = 0; row < mat->r; ++row) { - gr_sparse_vec_zero(res->rows[row], ctx); + gr_sparse_vec_zero(&mat->rows[row], ctx); } } +GR_SPARSE_MAT_INLINE void +gr_coo_mat_zero(gr_coo_mat_t mat, gr_ctx_t ctx) { + mat->nnz = 0; +} + WARN_UNUSED_RESULT int -gr_csr_mat_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); +gr_csr_mat_set(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_set(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_lil_mat_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx); +gr_coo_mat_set(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_csr_mat_set_lil_mat(gr_csr_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_csr_mat_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx); +gr_lil_mat_set_csr_mat(gr_lil_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); +gr_coo_mat_set_csr_mat(gr_coo_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_csr_mat_set_mat(gr_csr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx); +gr_coo_mat_set_lil_mat(gr_coo_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_lil_mat_set_mat(gr_lil_mat_t res, const gr_mat_t mat, gr_ctx_t ctx); +gr_lil_mat_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_mat_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx); +gr_csr_mat_set_coo_mat(gr_csr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_mat_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx); +gr_csr_mat_set_mat(gr_csr_mat_t dst, const gr_mat_t src, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_lil_mat_set_mat(gr_lil_mat_t dst, const gr_mat_t src, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_coo_mat_set_mat(gr_coo_mat_t dst, const gr_mat_t src, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_mat_set_csr_mat(gr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_mat_set_lil_mat(gr_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_mat_set_coo_mat(gr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx); + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_csr_mat_init_set(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) { + gr_csr_mat_init(dst, src->r, src->c, ctx); + return gr_csr_mat_set(dst, src, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_init_set(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) { + gr_lil_mat_init(dst, src->r, src->c, ctx); + return gr_lil_mat_set(dst, src, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_coo_mat_init_set(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) { + gr_coo_mat_init(dst, src->r, src->c, ctx); + return gr_coo_mat_set(dst, src, ctx); +} GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_csr_mat_init_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) { - gr_csr_mat_init(res, mat->r, mat->c, ctx); - return gr_csr_mat_set(res, mat, ctx); +gr_csr_mat_init_set_lil_mat(gr_csr_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) +{ + gr_csr_mat_init(dst, src->r, src->c, ctx); + return gr_csr_mat_set_lil_mat(dst, src, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_init_set_csr_mat(gr_lil_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) +{ + gr_lil_mat_init(dst, src->r, src->c, ctx); + return gr_lil_mat_set_csr_mat(dst, src, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_csr_mat_init_set_coo_mat(gr_csr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) +{ + gr_csr_mat_init(dst, src->r, src->c, ctx); + return gr_csr_mat_set_coo_mat(dst, src, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_lil_mat_init_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) +{ + gr_lil_mat_init(dst, src->r, src->c, ctx); + return gr_lil_mat_set_coo_mat(dst, src, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_coo_mat_init_set_csr_mat(gr_coo_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) +{ + gr_coo_mat_init(dst, src->r, src->c, ctx); + return gr_coo_mat_set_csr_mat(dst, src, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_init_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) { - gr_lil_mat_init(res, mat->r, mat->c, ctx); - return gr_lil_mat_set(res, mat, ctx); +gr_coo_mat_init_set_lil_mat(gr_coo_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) +{ + gr_coo_mat_init(dst, src->r, src->c, ctx); + return gr_coo_mat_set_lil_mat(dst, src, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_csr_mat_init_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +gr_csr_mat_init_set_mat(gr_csr_mat_t dst, const gr_mat_t src, gr_ctx_t ctx) { - gr_csr_mat_init(res, mat->r, mat->c, ctx); - return gr_csr_mat_set_lil_mat(res, mat, ctx); + gr_csr_mat_init(dst, src->r, src->c, ctx); + return gr_csr_mat_set_mat(dst, src, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_init_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +gr_lil_mat_init_set_mat(gr_lil_mat_t dst, const gr_mat_t src, gr_ctx_t ctx) { - gr_lil_mat_init(res, mat->r, mat->c, ctx); - return gr_lil_mat_set_csr_mat(res, mat, ctx); + gr_lil_mat_init(dst, src->r, src->c, ctx); + return gr_lil_mat_set_mat(dst, src, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_csr_mat_init_set_mat(gr_csr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) +gr_coo_mat_init_set_mat(gr_coo_mat_t dst, const gr_mat_t src, gr_ctx_t ctx) { - gr_csr_mat_init(res, mat->r, mat->c, ctx); - return gr_csr_mat_set_mat(res, mat, ctx); + gr_coo_mat_init(dst, src->r, src->c, ctx); + return gr_coo_mat_set_mat(dst, src, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_init_set_mat(gr_lil_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) +gr_mat_init_set_csr_mat(gr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) { - gr_lil_mat_init(res, mat->r, mat->c, ctx); - return gr_lil_mat_set_mat(res, mat, ctx); + gr_mat_init(dst, src->r, src->c, ctx); + return gr_mat_set_csr_mat(dst, src, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_mat_init_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +gr_mat_init_set_lil_mat(gr_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) { - gr_mat_init(res, mat->r, mat->c, ctx); - return gr_mat_set_csr_mat(res, mat, ctx); + gr_mat_init(dst, src->r, src->c, ctx); + return gr_mat_set_lil_mat(dst, src, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_mat_init_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +gr_mat_init_set_coo_mat(gr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) { - gr_mat_init(res, mat->r, mat->c, ctx); - return gr_mat_set_lil_mat(res, mat, ctx); + gr_mat_init(dst, src->r, src->c, ctx); + return gr_mat_set_coo_mat(dst, src, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_update(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +gr_lil_mat_update(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) { slong row; int status = GR_SUCCESS; - if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) return GR_DOMAIN; - for (row = 0; row < res->r; ++row) - status |= gr_sparse_vec_update(res->rows[row], mat->rows[row], ctx); + for (row = 0; row < dst->r; ++row) + status |= gr_sparse_vec_update(&dst->rows[row], &src->rows[row], ctx); return status; } -WARN_UNUSED_RESULT int -gr_csr_mat_set_from_coo(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); -WARN_UNUSED_RESULT int -gr_lil_mat_set_from_coo(gr_lil_mat_t vec, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_csr_mat_set_from_coo_sorted_deduped(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); -WARN_UNUSED_RESULT int -gr_lil_mat_set_from_coo_sorted_deduped(gr_lil_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx); - GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_permute_cols(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx) { @@ -362,7 +581,24 @@ gr_lil_mat_permute_cols(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx) for (row = 0; row < mat->r; ++row) { - status |= gr_sparse_vec_permute_inds(mat->rows[row], mat->rows[row], perm, ctx); + status |= gr_sparse_vec_permute_inds(&mat->rows[row], &mat->rows[row], perm, ctx); + } + return status; +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_coo_mat_permute_cols(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx) +{ + slong nz_idx; + int status = GR_SUCCESS; + + for (nz_idx = 0; nz_idx < mat->nnz; ++nz_idx) + { + mat->cols[nz_idx] = perm[mat->cols[nz_idx]]; + } + if (mat->is_canonical) + { + gr_coo_mat_canonicalize(mat, ctx); } return status; } @@ -376,9 +612,14 @@ gr_lil_mat_window_clear(gr_lil_mat_t window, gr_ctx_t ctx) } WARN_UNUSED_RESULT int gr_lil_mat_swap_rows(gr_lil_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_swap_rows(gr_coo_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx); + WARN_UNUSED_RESULT int gr_lil_mat_permute_rows(gr_lil_mat_t mat, const slong * perm, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_lil_mat_invert_rows(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_permute_rows(gr_coo_mat_t mat, const slong * perm, gr_ctx_t ctx); + WARN_UNUSED_RESULT int gr_csr_mat_invert_rows(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_invert_rows(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_invert_rows(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx); /* WARN_UNUSED_RESULT int gr_lil_mat_concat_horizontal(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); @@ -387,7 +628,6 @@ WARN_UNUSED_RESULT int gr_lil_mat_concat_vertical(gr_lil_mat_t res, const gr_lil */ /* -WARN_UNUSED_RESULT int gr_sparse_mat_randtest(gr_csr_mat_t mat, flint_rand_t state, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_mat_randops(gr_csr_mat_t mat, flint_rand_t state, slong count, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_mat_randpermdiag(int * parity, gr_csr_mat_t mat, flint_rand_t state, gr_ptr diag, slong n, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_mat_randrank(gr_csr_mat_t mat, flint_rand_t state, slong rank, gr_ctx_t ctx); @@ -399,7 +639,7 @@ WARN_UNUSED_RESULT int gr_sparse_mat_randrank(gr_csr_mat_t mat, flint_rand_t sta GR_SPARSE_MAT_INLINE truth_t gr_csr_mat_is_zero(const gr_csr_mat_t mat, gr_ctx_t ctx) -{ return _gr_vec_is_zero(mat->entries, mat->nnz, ctx); } +{ return _gr_vec_is_zero(mat->nzs, mat->nnz, ctx); } GR_SPARSE_MAT_INLINE truth_t gr_lil_mat_is_zero(const gr_lil_mat_t mat, gr_ctx_t ctx) @@ -410,7 +650,7 @@ gr_lil_mat_is_zero(const gr_lil_mat_t mat, gr_ctx_t ctx) for (row = 0; row < mat->r; ++row) { - row_is_zero = gr_sparse_vec_is_zero(mat->rows[row], ctx); + row_is_zero = gr_sparse_vec_is_zero(&mat->rows[row], ctx); if (row_is_zero == T_FALSE) return T_FALSE; else if (row_is_zero == T_UNKNOWN) @@ -419,14 +659,25 @@ gr_lil_mat_is_zero(const gr_lil_mat_t mat, gr_ctx_t ctx) return ret; } +GR_SPARSE_MAT_INLINE truth_t +gr_coo_mat_is_zero(gr_coo_mat_t mat, gr_ctx_t ctx) +{ + if (!mat->is_canonical) + gr_coo_mat_canonicalize(mat, ctx); + return _gr_vec_is_zero(mat->nzs, mat->nnz, ctx); +} + truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx); truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx); +truth_t gr_coo_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx); truth_t gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx); truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx); +truth_t gr_coo_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx); truth_t gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx); truth_t gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +truth_t gr_coo_mat_equal(const gr_coo_mat_t mat1, const gr_coo_mat_t mat2, gr_ctx_t ctx); truth_t gr_csr_mat_equal_lil_mat(const gr_csr_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); /* @@ -451,47 +702,67 @@ gr_csr_mat_write_nz(gr_stream_t out, const gr_csr_mat_t mat, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_write_nz(gr_stream_t out, const gr_lil_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int +gr_coo_mat_write_nz(gr_stream_t out, const gr_coo_mat_t mat, gr_ctx_t ctx); + WARN_UNUSED_RESULT int gr_csr_mat_print_nz(const gr_csr_mat_t mat, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_print_nz(const gr_lil_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int +gr_coo_mat_print_nz(const gr_coo_mat_t mat, gr_ctx_t ctx); + /** * Arithmetic **/ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_csr_mat_neg(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +gr_csr_mat_neg(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) { int status = GR_SUCCESS; - if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) { return GR_DOMAIN; } - status |= gr_csr_mat_set(res, mat, ctx); - status |= _gr_vec_neg(res->entries, res->entries, res->nnz, ctx); + status |= gr_csr_mat_set(dst, src, ctx); + status |= _gr_vec_neg(dst->nzs, dst->nzs, dst->nnz, ctx); return status; } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_neg(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +gr_lil_mat_neg(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) { int row; int status = GR_SUCCESS; - if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) { return GR_DOMAIN; } - res->nnz = mat->nnz; - for (row = 0; row < res->r; row++) { - status |= gr_sparse_vec_neg(res->rows[row], mat->rows[row], ctx); + dst->nnz = src->nnz; + for (row = 0; row < dst->r; row++) { + status |= gr_sparse_vec_neg(&dst->rows[row], &src->rows[row], ctx); } return status; } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int +gr_coo_mat_neg(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + { + return GR_DOMAIN; + } + status |= gr_coo_mat_set(dst, src, ctx); + status |= _gr_vec_neg(dst->nzs, dst->nzs, dst->nnz, ctx); + return status; +} + #define GR_LIL_MAT_BOP(FUNC, RES, MAT1, MAT2, CTX) { \ int row; \ int status = GR_SUCCESS; \ @@ -502,28 +773,28 @@ gr_lil_mat_neg(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) } \ (RES)->nnz = 0; \ for (row = 0; row < (RES)->r; row++) { \ - status |= FUNC((RES)->rows[row], (MAT1)->rows[row], (MAT2)->rows[row], CTX); \ - res->nnz += res->rows[row]->nnz; \ + status |= FUNC(&(RES)->rows[row], &(MAT1)->rows[row], &(MAT2)->rows[row], CTX); \ + dst->nnz += dst->rows[row].nnz; \ } \ return status; \ } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_add(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +gr_lil_mat_add(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) { - GR_LIL_MAT_BOP(gr_sparse_vec_add, res, mat1, mat2, ctx) + GR_LIL_MAT_BOP(gr_sparse_vec_add, dst, mat1, mat2, ctx) } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_sub(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +gr_lil_mat_sub(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) { - GR_LIL_MAT_BOP(gr_sparse_vec_sub, res, mat1, mat2, ctx) + GR_LIL_MAT_BOP(gr_sparse_vec_sub, dst, mat1, mat2, ctx) } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_mul(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +gr_lil_mat_mul(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) { - GR_LIL_MAT_BOP(gr_sparse_vec_mul, res, mat1, mat2, ctx) + GR_LIL_MAT_BOP(gr_sparse_vec_mul, dst, mat1, mat2, ctx) } #define GR_LIL_MAT_ACCUM_OP(FUNC, RES, MAT, C, CTX) { \ @@ -536,101 +807,101 @@ gr_lil_mat_mul(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat } \ (RES)->nnz = 0; \ for (row = 0; row < (RES)->r; row++) { \ - status |= FUNC((RES)->rows[row], (MAT)->rows[row], C, CTX); \ - res->nnz += res->rows[row]->nnz; \ + status |= FUNC(&(RES)->rows[row], &(MAT)->rows[row], C, CTX); \ + (RES)->nnz += (RES)->rows[row].nnz; \ } \ return status; \ } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_addmul_scalar(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_srcptr c, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_addmul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { - GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_addmul_scalar, res, mat, c, ctx) + GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_addmul_scalar, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_submul_scalar(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_srcptr c, gr_ctx_t ctx) +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_submul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { - GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_submul_scalar, res, mat, c, ctx) + GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_submul_scalar, dst, src, c, ctx) } /** * Component-wise multiplication and division **/ -#define GR_CSR_MAT_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) \ - if(res->r != src->r || res->c != src->c) \ +#define GR_CSR_MAT_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) \ + if(dst->r != src->r || dst->c != src->c) \ { \ return GR_DOMAIN; \ } \ - if(res != src) \ + if(dst != src) \ { \ - gr_csr_mat_fit_nnz(res, src->nnz, ctx); \ - res->nnz = src->nnz; \ - memcpy(res->rows, src->rows, src->r*sizeof(ulong)); \ - memcpy(res->cols, src->cols, src->nnz*sizeof(ulong)); \ + gr_csr_mat_fit_nnz(dst, src->nnz, ctx); \ + dst->nnz = src->nnz; \ + memcpy(dst->rows, src->rows, src->r*sizeof(ulong)); \ + memcpy(dst->cols, src->cols, src->nnz*sizeof(ulong)); \ } \ - return dense_vec_op(res->entries, src->entries, src->nnz, c, ctx); \ - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_2exp_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } - -#define GR_LIL_MAT_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) { \ + return dense_vec_op(dst->nzs, src->nzs, src->nnz, c, ctx); \ + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_2exp_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } + +#define GR_LIL_MAT_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) { \ int status = GR_SUCCESS; \ int row; \ - if(res->r != src->r || res->c != src->c) \ + if(dst->r != src->r || dst->c != src->c) \ { \ return GR_DOMAIN; \ } \ - res->nnz = src->nnz; \ + dst->nnz = src->nnz; \ for (row = 0; row < src->r; ++row) \ { \ - if(res != src) \ + if(dst != src) \ { \ - gr_sparse_vec_fit_nnz(res->rows[row], src->rows[row]->nnz, ctx); \ - res->rows[row]->nnz = src->rows[row]->nnz; \ - memcpy(res->rows[row]->inds, src->rows[row]->inds, src->rows[row]->nnz*sizeof(ulong)); \ + gr_sparse_vec_fit_nnz(&dst->rows[row], src->rows[row].nnz, ctx); \ + dst->rows[row].nnz = src->rows[row].nnz; \ + memcpy(dst->rows[row].inds, src->rows[row].inds, src->rows[row].nnz*sizeof(ulong)); \ } \ - status |= dense_vec_op(res->rows[row]->entries, src->rows[row]->entries, src->rows[row]->nnz, c, ctx); \ + status |= dense_vec_op(dst->rows[row].nzs, src->rows[row].nzs, src->rows[row].nnz, c, ctx); \ } \ return status; \ } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_2exp_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_2exp_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } /** * Sum and product **/ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_sum(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx) -{ return _gr_vec_sum(res, mat->entries, mat->nnz, ctx); } +{ return _gr_vec_sum(res, mat->nzs, mat->nnz, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_sum(gr_ptr res, const gr_lil_mat_t mat, gr_ctx_t ctx) { @@ -642,15 +913,18 @@ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_sum(gr_ptr res, const gr_ gr_init(elem, ctx); for (row = 0; row < mat->r; ++row) { - status |= gr_sparse_vec_sum(elem, mat->rows[row], ctx); + status |= gr_sparse_vec_sum(elem, &mat->rows[row], ctx); status |= gr_add(res, res, elem, ctx); } gr_clear(elem, ctx); return status; } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_coo_mat_sum(gr_ptr res, const gr_coo_mat_t mat, gr_ctx_t ctx) +{ return _gr_vec_sum(res, mat->nzs, mat->nnz, ctx); } + GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_nz_product(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx) -{ return _gr_vec_product(res, mat->entries, mat->nnz, ctx); } +{ return _gr_vec_product(res, mat->nzs, mat->nnz, ctx); } GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_nz_product(gr_ptr res, const gr_lil_mat_t mat, gr_ctx_t ctx) { @@ -663,13 +937,16 @@ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_nz_product(gr_ptr res, co status |= gr_one(elem, ctx); for (row = 0; row < mat->r; ++row) { - status |= gr_sparse_vec_nz_product(elem, mat->rows[row], ctx); + status |= gr_sparse_vec_nz_product(elem, &mat->rows[row], ctx); status |= gr_mul(res, res, elem, ctx); } gr_clear(elem, ctx); return status; } +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_coo_mat_nz_product(gr_ptr res, const gr_coo_mat_t mat, gr_ctx_t ctx) +{ return _gr_vec_product(res, mat->nzs, mat->nnz, ctx); } + /** * Matrix multiplication **/ diff --git a/src/gr_sparse_mat/canonicalize.c b/src/gr_sparse_mat/canonicalize.c new file mode 100644 index 0000000000..b62931fcb4 --- /dev/null +++ b/src/gr_sparse_mat/canonicalize.c @@ -0,0 +1,110 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "gr_sparse_mat.h" + +typedef struct +{ + slong i; + slong row; + slong col; +} +sparse_mat_index_t; + +static int sparse_mat_index_cmp(const void* a, const void* b) +{ + slong arow = ((sparse_mat_index_t*)(a))->row; + slong brow = ((sparse_mat_index_t*)(b))->row; + slong acol = ((sparse_mat_index_t*)(a))->col; + slong bcol = ((sparse_mat_index_t*)(b))->col; + return (arow < brow ? -1 : (arow > brow ? 1 : (acol < bcol ? -1 : (acol > bcol ? 1 : 0)))); +} + +static sparse_mat_index_t * _sort_coords(ulong * rows, ulong * cols, slong num) +{ + slong i; + sparse_mat_index_t * si; + + si = flint_malloc(num * sizeof(sparse_mat_index_t)); + for (i = 0; i < num; i++) + { + si[i].i = i; + si[i].row = rows[i]; + si[i].col = cols[i]; + } + + qsort(si, num, sizeof(sparse_mat_index_t), sparse_mat_index_cmp); + return si; +} + +int +gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx) +{ + slong i, j, k, sz, nnz; + int status = GR_SUCCESS; + sparse_mat_index_t *si; + ulong *inv_si; + gr_ptr entry; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); + + if (mat->is_canonical) + return GR_SUCCESS; + + sz = ctx->sizeof_elem; + + // Get sorted order for matrices indices (and inverse mapping) + si = _sort_coords(mat->rows, mat->cols, mat->nnz); + inv_si = flint_malloc(mat->nnz * sizeof(ulong)); + for (i = 0; i < mat->nnz; ++i) + inv_si[si[i].i] = i; + + // Use swaps to apply sort to entries + for (i = 0; i < mat->nnz; ++i) + { + j = si[i].i; + if (i != j) + { + FLINT_SWAP(ulong, mat->rows[i], mat->rows[j]); + FLINT_SWAP(ulong, mat->cols[i], mat->cols[j]); + gr_swap(GR_ENTRY(mat->nzs, i, sz), GR_ENTRY(mat->nzs, j, sz), ctx); + + // Fix mappings to remove i from permutation + k = inv_si[i]; + si[k].i = j; + inv_si[j] = k; + } + } + flint_free(si); + flint_free(inv_si); + + // Compress duplicated entries + nnz = 0; + entry = NULL; + for (i = 0; i < mat->nnz; ++i) + { + if(i > 0 && mat->rows[i-1] == mat->rows[i] && mat->cols[i-1] == mat->cols[i]) + status |= gr_add(entry, entry, GR_ENTRY(mat->nzs, i, sz), ctx); + else + { + // If previous entry does not exist or is not zero, advance to the next one + if (entry == NULL || is_zero(entry, ctx) != T_TRUE) + { + entry = GR_ENTRY(mat->nzs, nnz, sz); + ++nnz; + } + status |= gr_set(entry, GR_ENTRY(mat->nzs, i, sz), ctx); + } + } + return status; +} + + diff --git a/src/gr_sparse_mat/equal.c b/src/gr_sparse_mat/equal.c index 0bd59c8565..222e2006f2 100644 --- a/src/gr_sparse_mat/equal.c +++ b/src/gr_sparse_mat/equal.c @@ -49,7 +49,7 @@ gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) } for (row = 0; row < mat1->r; row++) { - row_is_eq = gr_sparse_vec_equal(mat1->rows[row], mat2->rows[row], ctx); + row_is_eq = gr_sparse_vec_equal(&mat1->rows[row], &mat2->rows[row], ctx); if (row_is_eq == T_FALSE) return T_FALSE; else if (row_is_eq == T_UNKNOWN) @@ -73,7 +73,7 @@ gr_csr_mat_equal_lil_mat(const gr_csr_mat_t mat1, const gr_lil_mat_t mat2, gr_ct for (row = 0; row < mat1->r; row++) { _gr_csr_mat_borrow_row(tmp, mat1, row, ctx); - row_is_eq = gr_sparse_vec_equal(tmp, mat2->rows[row], ctx); + row_is_eq = gr_sparse_vec_equal(tmp, &mat2->rows[row], ctx); if (row_is_eq == T_FALSE) return T_FALSE; else if (row_is_eq == T_UNKNOWN) diff --git a/src/gr_sparse_mat/fit_nnz.c b/src/gr_sparse_mat/fit_nnz.c index 9ba98a973c..e374abc821 100644 --- a/src/gr_sparse_mat/fit_nnz.c +++ b/src/gr_sparse_mat/fit_nnz.c @@ -1,3 +1,14 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "gr_sparse_mat.h" void @@ -9,8 +20,24 @@ gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx) { slong sz = ctx->sizeof_elem; mat->cols = flint_realloc(mat->cols, new_alloc * sizeof(ulong)); - mat->entries = flint_realloc(mat->entries, new_alloc * sz); - _gr_vec_init(GR_ENTRY(mat->entries, alloc, sz), new_alloc - alloc, ctx); + mat->nzs = flint_realloc(mat->nzs, new_alloc * sz); + _gr_vec_init(GR_ENTRY(mat->nzs, alloc, sz), new_alloc - alloc, ctx); + mat->alloc = new_alloc; + } +} + +void +gr_coo_mat_fit_nnz(gr_coo_mat_t mat, slong nnz, gr_ctx_t ctx) +{ + slong alloc = mat->alloc; + slong new_alloc = nnz; + if (new_alloc > alloc) + { + slong sz = ctx->sizeof_elem; + mat->rows = flint_realloc(mat->rows, new_alloc * sizeof(ulong)); + mat->cols = flint_realloc(mat->cols, new_alloc * sizeof(ulong)); + mat->nzs = flint_realloc(mat->nzs, new_alloc * sz); + _gr_vec_init(GR_ENTRY(mat->nzs, alloc, sz), new_alloc - alloc, ctx); mat->alloc = new_alloc; } } @@ -23,8 +50,8 @@ gr_csr_mat_shrink_to_nnz(gr_csr_mat_t mat, gr_ctx_t ctx) if (mat->alloc > nnz) { mat->cols = flint_realloc(mat->cols, nnz * sizeof(ulong)); - _gr_vec_clear(GR_ENTRY(mat->entries, nnz, sz), mat->alloc - nnz, ctx); - mat->entries = flint_realloc(mat->entries, nnz * sz); + _gr_vec_clear(GR_ENTRY(mat->nzs, nnz, sz), mat->alloc - nnz, ctx); + mat->nzs = flint_realloc(mat->nzs, nnz * sz); mat->alloc = nnz; } } @@ -36,7 +63,22 @@ gr_lil_mat_shrink_to_nnz(gr_lil_mat_t mat, gr_ctx_t ctx) for (row = 0; row < mat->r; ++row) { - gr_sparse_vec_shrink_to_nnz(mat->rows[row], ctx); + gr_sparse_vec_shrink_to_nnz(&mat->rows[row], ctx); } } +void +gr_coo_mat_shrink_to_nnz(gr_coo_mat_t mat, gr_ctx_t ctx) +{ + slong nnz = mat->nnz; + slong sz = ctx->sizeof_elem; + if (mat->alloc > nnz) + { + mat->rows = flint_realloc(mat->cols, nnz * sizeof(ulong)); + mat->cols = flint_realloc(mat->cols, nnz * sizeof(ulong)); + _gr_vec_clear(GR_ENTRY(mat->nzs, nnz, sz), mat->alloc - nnz, ctx); + mat->nzs = flint_realloc(mat->nzs, nnz * sz); + mat->alloc = nnz; + } +} + diff --git a/src/gr_sparse_mat/from_entries.c b/src/gr_sparse_mat/from_entries.c new file mode 100644 index 0000000000..06d7f6019c --- /dev/null +++ b/src/gr_sparse_mat/from_entries.c @@ -0,0 +1,30 @@ +#include +#include "gr_sparse_mat.h" + +static int check_coords(ulong * rows, ulong * cols, slong num, slong r, slong c) +{ + slong i; + + for (i = 0; i < num; ++i) + if (rows[i] >= r || cols[i] >= c) + return 0; + return 1; +} + +int +gr_coo_mat_from_entries(gr_coo_mat_t mat, ulong *rows, ulong *cols, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx) +{ + int status; + + if (!check_coords(rows, cols, nnz, mat->r, mat->c)) + return GR_DOMAIN; + + mat->nnz = nnz; + gr_coo_mat_fit_nnz(mat, nnz, ctx); + memcpy(mat->rows, rows, nnz * sizeof(ulong)); + memcpy(mat->cols, cols, nnz * sizeof(ulong)); + status = _gr_vec_set(mat->nzs, entries, nnz, ctx); + mat->is_canonical = is_canonical; + return status; +} + diff --git a/src/gr_sparse_mat/get_entry.c b/src/gr_sparse_mat/get_entry.c new file mode 100644 index 0000000000..dd71a9f914 --- /dev/null +++ b/src/gr_sparse_mat/get_entry.c @@ -0,0 +1,60 @@ +#include +#include "gr_sparse_mat.h" + + +static int ulong_cmp(const void* a, const void* b) +{ + ulong av = *((ulong*)(a)); + ulong bv = *((ulong*)(b)); + return (av < bv ? -1 : (av > bv ? 1 : 0)); +} + +gr_ptr +gr_csr_mat_find_entry(gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx) +{ + slong sz = ctx->sizeof_elem; + ulong* bs = NULL; + + if (row < 0 || row >= mat->r || col < 0 || col >= mat->c) + return NULL; + + bs = bsearch(&col, mat->cols + mat->rows[row], mat->rows[row+1] - mat->rows[row], sizeof(ulong), ulong_cmp); + + if (bs == NULL) + return NULL; + return GR_ENTRY(mat->nzs, bs - mat->cols, sz); +} + +gr_ptr +gr_lil_mat_find_entry(gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx) +{ + if (row < 0 || row >= mat->r) + return NULL; + + return gr_sparse_vec_find_entry(&mat->rows[row], col, ctx); +} + +int +gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx) +{ + slong sz = ctx->sizeof_elem; + ulong* bs = NULL; + + if (row < 0 || row >= mat->r || col < 0 || col >= mat->c) + return GR_DOMAIN; + + bs = bsearch(&col, mat->cols + mat->rows[row], mat->rows[row+1] - mat->rows[row], sizeof(ulong), ulong_cmp); + + if (bs == NULL) + return gr_zero(res, ctx); + return gr_set(res, GR_ENTRY(mat->nzs, bs - mat->cols, sz), ctx); +} + +int +gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx) +{ + if (row < 0 || row >= mat->r) + return GR_DOMAIN; + + return gr_sparse_vec_get_entry(res, &mat->rows[row], col, ctx); +} diff --git a/src/gr_sparse_mat/invert_rows.c b/src/gr_sparse_mat/invert_rows.c index e038a70471..551e82765d 100644 --- a/src/gr_sparse_mat/invert_rows.c +++ b/src/gr_sparse_mat/invert_rows.c @@ -39,7 +39,7 @@ int gr_csr_mat_invert_rows(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx) { k = nnz - j - 1; FLINT_SWAP(ulong, mat->cols[j], mat->cols[k]); - gr_swap(GR_ENTRY(mat->entries, j, sz), GR_ENTRY(mat->entries, k, sz), ctx); + gr_swap(GR_ENTRY(mat->nzs, j, sz), GR_ENTRY(mat->nzs, k, sz), ctx); } // Reverse columns and elements in each row @@ -51,7 +51,7 @@ int gr_csr_mat_invert_rows(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx) { k = mat->rows[i+1] - j - 1; FLINT_SWAP(ulong, mat->cols[j], mat->cols[k]); - gr_swap(GR_ENTRY(mat->entries, j, sz), GR_ENTRY(mat->entries, k, sz), ctx); + gr_swap(GR_ENTRY(mat->nzs, j, sz), GR_ENTRY(mat->nzs, k, sz), ctx); } } return status; diff --git a/src/gr_sparse_mat/is_neg_one.c b/src/gr_sparse_mat/is_neg_one.c index 047acc4ab4..e0d0f9a1ea 100644 --- a/src/gr_sparse_mat/is_neg_one.c +++ b/src/gr_sparse_mat/is_neg_one.c @@ -25,7 +25,7 @@ gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx) { for (idx = mat->rows[row]; idx < mat->rows[row+1]; idx++) { - this_eq = (mat->cols[idx] == row ? is_neg_one : is_zero)(GR_ENTRY(mat->entries, idx, sz), ctx); + this_eq = (mat->cols[idx] == row ? is_neg_one : is_zero)(GR_ENTRY(mat->nzs, idx, sz), ctx); if (this_eq == T_FALSE) return T_FALSE; else @@ -46,9 +46,9 @@ truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx) for (row = 0; row < mat->r; ++row) { - for (idx = 0; idx < mat->rows[row]->nnz; idx++) + for (idx = 0; idx < mat->rows[row].nnz; idx++) { - this_eq = (mat->rows[row]->inds[idx] == row ? is_neg_one : is_zero)(GR_ENTRY(mat->rows[row]->entries, idx, sz), ctx); + this_eq = (mat->rows[row].inds[idx] == row ? is_neg_one : is_zero)(GR_ENTRY(mat->rows[row].nzs, idx, sz), ctx); if (this_eq == T_FALSE) return T_FALSE; else diff --git a/src/gr_sparse_mat/is_one.c b/src/gr_sparse_mat/is_one.c index 24be77d61a..d94ad3a78f 100644 --- a/src/gr_sparse_mat/is_one.c +++ b/src/gr_sparse_mat/is_one.c @@ -24,7 +24,7 @@ truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx) { for (idx = mat->rows[row]; idx < mat->rows[row+1]; idx++) { - this_eq = (mat->cols[idx] == row ? is_one : is_zero)(GR_ENTRY(mat->entries, idx, sz), ctx); + this_eq = (mat->cols[idx] == row ? is_one : is_zero)(GR_ENTRY(mat->nzs, idx, sz), ctx); if (this_eq == T_FALSE) return T_FALSE; else @@ -45,9 +45,9 @@ truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx) for (row = 0; row < mat->r; ++row) { - for (idx = 0; idx < mat->rows[row]->nnz; idx++) + for (idx = 0; idx < mat->rows[row].nnz; idx++) { - this_eq = (mat->rows[row]->inds[idx] == row ? is_one : is_zero)(GR_ENTRY(mat->rows[row]->entries, idx, sz), ctx); + this_eq = (mat->rows[row].inds[idx] == row ? is_one : is_zero)(GR_ENTRY(mat->rows[row].nzs, idx, sz), ctx); if (this_eq == T_FALSE) return T_FALSE; else diff --git a/src/gr_sparse_mat/mul.c b/src/gr_sparse_mat/mul.c index 66fca6d5ea..6cc9af0a3b 100644 --- a/src/gr_sparse_mat/mul.c +++ b/src/gr_sparse_mat/mul.c @@ -87,7 +87,7 @@ int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ct status |= _gr_vec_zero(v->entries, v->length, ctx); for (i = 0; i < ar; ++i) { res = gr_vec_entry_ptr(v, i, ctx); - status |= gr_sparse_vec_dot_vec(res, res, 0, A->rows[i], u, ctx); + status |= gr_sparse_vec_dot_vec(res, res, 0, &A->rows[i], u, ctx); } return status; diff --git a/src/gr_sparse_mat/set.c b/src/gr_sparse_mat/set.c index c516e37e6c..942a935c5e 100644 --- a/src/gr_sparse_mat/set.c +++ b/src/gr_sparse_mat/set.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2024 Kartik Venkatram + Copyright (C) 2024 Kartik Venkatram and Alden Walker This file is part of FLINT. @@ -11,138 +11,431 @@ #include "gr_sparse_mat.h" -int gr_csr_mat_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) { +typedef struct +{ + slong i; + slong row; + slong col; + void * entry; +} +sparse_mat_index_t; + +static int sparse_mat_index_cmp(const void* a, const void* b) +{ + slong arow = ((sparse_mat_index_t*)(a))->row; + slong brow = ((sparse_mat_index_t*)(b))->row; + slong acol = ((sparse_mat_index_t*)(a))->col; + slong bcol = ((sparse_mat_index_t*)(b))->col; + return (arow < brow ? -1 : (arow > brow ? 1 : (acol < bcol ? -1 : (acol > bcol ? 1 : 0)))); +} + +sparse_mat_index_t * _sort_coords(ulong * rows, ulong * cols, const void * entries, slong sz, slong num) +{ + slong i; + sparse_mat_index_t * si; + + si = flint_malloc(num * sizeof(sparse_mat_index_t)); + for (i = 0; i < num; i++) + { + si[i].i = i; + si[i].row = rows[i]; + si[i].col = cols[i]; + si[i].entry = (void *) (((char *) (entries)) + ((i) * (sz))); + } + + qsort(si, num, sizeof(sparse_mat_index_t), sparse_mat_index_cmp); + return si; +} + +int gr_csr_mat_set(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) { int status = GR_SUCCESS; - if (res != mat) + if (dst != src) { - if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) { return GR_DOMAIN; } - res->nnz = mat->nnz; - gr_csr_mat_fit_nnz(res, mat->nnz, ctx); - memcpy(res->rows, mat->rows, mat->r * sizeof(ulong)); - memcpy(res->cols, mat->cols, mat->nnz * sizeof(ulong)); - status = _gr_vec_set(res->entries, mat->entries, mat->nnz, ctx); + dst->nnz = src->nnz; + gr_csr_mat_fit_nnz(dst, src->nnz, ctx); + memcpy(dst->rows, src->rows, src->r * sizeof(ulong)); + memcpy(dst->cols, src->cols, src->nnz * sizeof(ulong)); + status = _gr_vec_set(dst->nzs, src->nzs, src->nnz, ctx); } return status; } -int gr_lil_mat_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) { +int gr_lil_mat_set(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) { ulong row; - int success = GR_SUCCESS; + int status = GR_SUCCESS; - if (res != mat) + if (dst != src) { - if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) { return GR_DOMAIN; } - res->nnz = mat->nnz; + dst->nnz = src->nnz; - for (row = 0; row < mat->r; ++row) { - success |= gr_sparse_vec_set(res->rows[row], mat->rows[row], ctx); + for (row = 0; row < src->r; ++row) { + status |= gr_sparse_vec_set(&dst->rows[row], &src->rows[row], ctx); } } - return success; + return status; } -int gr_csr_mat_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +int gr_coo_mat_set(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) { + int status = GR_SUCCESS; + + if (dst != src) + { + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + { + return GR_DOMAIN; + } + dst->nnz = src->nnz; + gr_coo_mat_fit_nnz(dst, src->nnz, ctx); + memcpy(dst->rows, src->rows, src->nnz * sizeof(ulong)); + memcpy(dst->cols, src->cols, src->nnz * sizeof(ulong)); + status = _gr_vec_set(dst->nzs, src->nzs, src->nnz, ctx); + dst->is_canonical = src->is_canonical; + } + return status; +} + +int gr_csr_mat_set_lil_mat(gr_csr_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) { ulong row; - int success = GR_SUCCESS; - gr_sparse_vec_t res_row; + int status = GR_SUCCESS; + gr_sparse_vec_t dst_row; - if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) return GR_DOMAIN; - gr_csr_mat_fit_nnz(res, mat->nnz, ctx); + gr_csr_mat_fit_nnz(dst, src->nnz, ctx); - res->rows[0] = 0; - for(row = 0; row < mat->r; row++) { - res->rows[row+1] = res->rows[row] + mat->rows[row]->nnz; - _gr_csr_mat_borrow_row(res_row, res, row, ctx); - success |= gr_sparse_vec_set(res_row, mat->rows[row], ctx); + dst->rows[0] = 0; + for(row = 0; row < src->r; row++) { + dst->rows[row+1] = dst->rows[row] + src->rows[row].nnz; + _gr_csr_mat_borrow_row(dst_row, dst, row, ctx); + status |= gr_sparse_vec_set(dst_row, &src->rows[row], ctx); } - res->nnz = mat->nnz; + dst->nnz = src->nnz; - return success; + return status; } -int gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +int gr_lil_mat_set_csr_mat(gr_lil_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) { ulong row; - int success = GR_SUCCESS; + int status = GR_SUCCESS; gr_sparse_vec_t mat_row; - if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + return GR_DOMAIN; + + for(row = 0; row < src->r; row++) { + _gr_csr_mat_borrow_row(mat_row, src, row, ctx); + status |= gr_sparse_vec_set(&dst->rows[row], mat_row, ctx); + } + dst->nnz = src->nnz; + + return status; +} + +int gr_csr_mat_set_coo_mat(gr_csr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) +{ + // Sort entries by row and column + slong i, sz, nnz, row; + int status = GR_SUCCESS; + sparse_mat_index_t * si; + gr_ptr entry; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); + + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + return GR_DOMAIN; + + if (src->nnz == 0) + { + gr_csr_mat_zero(dst, ctx); + return GR_SUCCESS; + } + + sz = ctx->sizeof_elem; + + gr_csr_mat_fit_nnz(dst, src->nnz, ctx); + if (src->is_canonical) + { + // Just copy over the data and set the row offsets + dst->rows[0] = 0; + row = 0; + for (i = 0; i < src->nnz; ++i) + while (row != src->rows[i]) + dst->rows[++row] = i; + + dst->rows[dst->r] = src->nnz; + memcpy(dst->cols, src->cols, src->nnz * sizeof(ulong)); + status |= _gr_vec_set(dst->nzs, src->nzs, src->nnz, ctx); + dst->nnz = src->nnz; + } + else + { + // Sort coordinates + si = _sort_coords(src->rows, src->cols, src->nzs, sz, src->nnz); + + // Accumulate nonzeroes into matrix + row = 0; + nnz = 0; + dst->rows[0] = 0; + entry = NULL; + for (i = 0; i < src->nnz; ++i) + { + // Check if we can just accumulate + if(i > 0 && si[i-1].row == si[i].row && si[i-1].col == si[i].col) + status |= gr_add(entry, entry, si[i].entry, ctx); + else + { + // If previous entry does not exist or is not zero, advance to the next one + if (entry == NULL || is_zero(entry, ctx) != T_TRUE) + { + entry = GR_ENTRY(dst->nzs, nnz, sz); + ++nnz; + } + status |= gr_set(entry, si[i].entry, ctx); + + // Advance row offsets as needed + while (row != si[i].row) + dst->rows[++row] = nnz; + } + } + // Set remaining row offsets and overall number of nonzeroes + while (row < dst->r) + dst->rows[++row] = nnz; + dst->nnz = nnz; + } + return status; +} + +int gr_lil_mat_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) +{ + slong i, prev_i, sz, nnz, row, row_start_idx, row_end_idx; + int status = GR_SUCCESS; + sparse_mat_index_t * si; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); + gr_ptr entry; + + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + return GR_DOMAIN; + + if (src->nnz == 0) + { + gr_lil_mat_zero(dst, ctx); + return GR_SUCCESS; + } + + sz = ctx->sizeof_elem; + if (src->is_canonical) + { + prev_i = i = 0; + for (row = 0; row < dst->r; ++row) + { + while (i < src->nnz && src->rows[i] == row) ++i; + status |= gr_sparse_vec_from_entries( + &dst->rows[row], src->cols + prev_i, GR_ENTRY(src->nnz, prev_i, sz), i - prev_i, 1, ctx + ); + prev_i = i; + } + } + else + { + // Sort entries by row and column + si = _sort_coords(src->rows, src->cols, src->nzs, sz, src->nnz); + + // Construct rows one by one + row_start_idx = 0; + for (row = 0; row < dst->r; ++row) + { + // Get range of indicies in current row and estimate of nonzeroes + for (row_end_idx = row_start_idx; row_end_idx < src->nnz; ++row_end_idx) + if (si[row_end_idx].row != row) + break; + gr_sparse_vec_fit_nnz(&dst->rows[row], row_end_idx - row_start_idx, ctx); + + // Add nonzeroes to row + entry = NULL; + nnz = 0; + for (i = row_start_idx; i < row_end_idx; ++i) + { + // Skip zero entries + if (is_zero(si[i].entry, ctx) == T_TRUE) + continue; + + // Check if we can just accumulate + if(i > row_start_idx && si[i-1].col == si[i].col) + status |= gr_add(entry, entry, si[i].entry, ctx); + else + { + // Check if need to get new entry to store to + if (entry == NULL || is_zero(entry, ctx) != T_TRUE) + { + entry = GR_ENTRY(dst->rows[row].nzs, nnz, sz); + ++nnz; + } + // Store to entry and update current column + status |= gr_set(entry, si[i].entry, ctx); + } + } + dst->rows[row].nnz = nnz; + row_start_idx = row_end_idx; + } + } + + return status; +} + +int gr_coo_mat_set_lil_mat(gr_coo_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) +{ + ulong row, i; + slong sz; + int status = GR_SUCCESS; + + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) return GR_DOMAIN; - for(row = 0; row < mat->r; row++) { - _gr_csr_mat_borrow_row(mat_row, mat, row, ctx); - success |= gr_sparse_vec_set(res->rows[row], mat_row, ctx); + gr_coo_mat_fit_nnz(dst, src->nnz, ctx); + + sz = ctx->sizeof_elem; + + dst->nnz = 0; + for(row = 0; row < src->r; row++) { + for (i = 0; i < src->rows[row].nnz; ++i) + dst->rows[dst->nnz + i] = row; + + memcpy(dst->cols + dst->nnz, src->rows[i].inds, src->rows[i].nnz); + status |= _gr_vec_set(GR_ENTRY(dst->nzs, dst->nnz, sz), src->rows[i].nzs, src->rows[i].nnz, ctx); + dst->nnz += src->rows[i].nnz; } - res->nnz = mat->nnz; + dst->nnz = src->nnz; + dst->is_canonical = 1; + return status; +} + +int gr_coo_mat_set_csr_mat(gr_coo_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) +{ + ulong row; + int status = GR_SUCCESS; + + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + return GR_DOMAIN; + + gr_coo_mat_fit_nnz(dst, src->nnz, ctx); + + dst->nnz = 0; + for(row = 0; row < dst->r; ++row) + while (dst->nnz < src->rows[row + 1]) + src->rows[dst->nnz++] = row; + memcpy(dst->cols, src->cols, src->nnz * sizeof(ulong)); + status |= _gr_vec_set(dst->nzs, src->nzs, src->nnz, ctx); + dst->is_canonical = 1; - return success; + return status; } -int gr_csr_mat_set_mat(gr_csr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) +int gr_csr_mat_set_mat(gr_csr_mat_t dst, const gr_mat_t src, gr_ctx_t ctx) { ulong row, col; slong nnz, sz; - int success = GR_SUCCESS; + int status = GR_SUCCESS; gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); - if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) return GR_DOMAIN; // Get number of nonzero entries sz = ctx->sizeof_elem; nnz = 0; - for (row = 0; row < mat->r; ++row) - for (col = 0; col < mat->c; ++col) - if (is_zero(GR_MAT_ENTRY(mat, row, col, sz), ctx) != T_TRUE) + for (row = 0; row < src->r; ++row) + for (col = 0; col < src->c; ++col) + if (is_zero(GR_MAT_ENTRY(src, row, col, sz), ctx) != T_TRUE) nnz++; - gr_csr_mat_fit_nnz(res, nnz, ctx); + gr_csr_mat_fit_nnz(dst, nnz, ctx); // Construct sparse matrix from nonzeroes - res->rows[0] = 0; + dst->rows[0] = 0; nnz = 0; - for(row = 0; row < mat->r; row++) + for(row = 0; row < src->r; row++) { - for (col = 0; col < mat->c; ++col) + for (col = 0; col < src->c; ++col) { - if (is_zero(GR_MAT_ENTRY(mat, row, col, sz), ctx) != T_TRUE) + if (is_zero(GR_MAT_ENTRY(src, row, col, sz), ctx) != T_TRUE) { - res->cols[nnz] = col; - success |= gr_set(GR_ENTRY(res->entries, nnz, sz), GR_MAT_ENTRY(mat, row, col, sz), ctx); + dst->cols[nnz] = col; + status |= gr_set(GR_ENTRY(dst->nzs, nnz, sz), GR_MAT_ENTRY(src, row, col, sz), ctx); ++nnz; } } - res->rows[row + 1] = nnz; + dst->rows[row + 1] = nnz; } - res->nnz = nnz; + dst->nnz = nnz; - return success; + return status; } -int gr_lil_mat_set_mat(gr_lil_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) +int gr_lil_mat_set_mat(gr_lil_mat_t dst, const gr_mat_t src, gr_ctx_t ctx) { ulong row; slong sz; - int success = GR_SUCCESS; + int status = GR_SUCCESS; - if (gr_mat_is_compatible(res, mat, ctx) == T_FALSE) + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) return GR_DOMAIN; sz = ctx->sizeof_elem; - res->nnz = 0; - for(row = 0; row < mat->r; row++) { - success |= gr_sparse_vec_set_vec(res->rows[row], GR_MAT_ENTRY(mat, row, 0, sz), mat->c, ctx); - res->nnz += res->rows[row]->nnz; + dst->nnz = 0; + for(row = 0; row < src->r; row++) { + status |= gr_sparse_vec_set_vec(&dst->rows[row], GR_MAT_ENTRY(src, row, 0, sz), src->c, ctx); + dst->nnz += dst->rows[row].nnz; } - return success; + return status; +} + +int gr_coo_mat_set_mat(gr_coo_mat_t dst, const gr_mat_t src, gr_ctx_t ctx) +{ + ulong row, col; + slong sz, nnz; + int status = GR_SUCCESS; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); + + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + return GR_DOMAIN; + + sz = ctx->sizeof_elem; + + // Get number of nonzero entries + nnz = 0; + for (row = 0; row < src->r; ++row) + for (col = 0; col < src->c; ++col) + if (is_zero(GR_MAT_ENTRY(src, row, col, sz), ctx) != T_TRUE) + nnz++; + gr_coo_mat_fit_nnz(dst, nnz, ctx); + + // Construct sparse matrix from nonzeroes + nnz = 0; + for(row = 0; row < src->r; row++) + { + for (col = 0; col < src->c; ++col) + { + if (is_zero(GR_MAT_ENTRY(src, row, col, sz), ctx) != T_TRUE) + { + dst->rows[nnz] = row; + dst->cols[nnz] = col; + status |= gr_set(GR_ENTRY(dst->nzs, nnz, sz), GR_MAT_ENTRY(src, row, col, sz), ctx); + ++nnz; + } + } + } + dst->nnz = nnz; + + return status; } diff --git a/src/gr_sparse_mat/set_cols.c b/src/gr_sparse_mat/set_cols.c new file mode 100644 index 0000000000..ace19d9853 --- /dev/null +++ b/src/gr_sparse_mat/set_cols.c @@ -0,0 +1,69 @@ +#include "gr_sparse_mat.h" + +void +gr_csr_mat_set_cols(gr_csr_mat_t mat, slong c, gr_ctx_t ctx) +{ + slong idx, new_idx, row; + slong sz = ctx->sizeof_elem; + + if (c < mat->c) + { + // Keep track of row to update offsets + row = 1; + + // May have some columns to discard + for (idx = new_idx = 0; idx < mat->nnz; ++idx) + { + if (mat->rows[row] == idx) + { + mat->rows[row++] = new_idx; + } + if (mat->cols[idx] < c && idx != new_idx) + { + // Move this entry down in array + mat->cols[new_idx] = mat->cols[idx]; + gr_swap(GR_ENTRY(mat->nzs, new_idx, sz), GR_ENTRY(mat->nzs, idx, sz), ctx); + ++new_idx; + } + } + mat->nnz = new_idx; + } + mat->c = c; + } + +void +gr_lil_mat_set_cols(gr_lil_mat_t mat, slong c, gr_ctx_t ctx) +{ + slong row; + + mat->c = c; + for (row = 0; row < mat->r; ++row) + { + gr_sparse_vec_set_length(&mat->rows[row], c, ctx); + } +} + +void +gr_coo_mat_set_cols(gr_coo_mat_t mat, slong c, gr_ctx_t ctx) +{ + slong idx, new_idx; + slong sz = ctx->sizeof_elem; + + if (c < mat->c) + { + // May have some columns to discard + for (idx = new_idx = 0; idx < mat->nnz; ++idx) + { + if (mat->cols[idx] < c && idx != new_idx) + { + // Move this entry down in array + mat->rows[new_idx] = mat->rows[idx]; + mat->cols[new_idx] = mat->cols[idx]; + gr_swap(GR_ENTRY(mat->nzs, new_idx, sz), GR_ENTRY(mat->nzs, idx, sz), ctx); + ++new_idx; + } + } + mat->nnz = new_idx; + } + mat->c = c; + } diff --git a/src/gr_sparse_mat/set_entry.c b/src/gr_sparse_mat/set_entry.c new file mode 100644 index 0000000000..d4af82c25e --- /dev/null +++ b/src/gr_sparse_mat/set_entry.c @@ -0,0 +1,78 @@ +#include +#include "gr_sparse_mat.h" + +static int ulong_cmp(const void* a, const void* b) +{ + ulong av = *((ulong*)(a)); + ulong bv = *((ulong*)(b)); + return (av < bv ? -1 : (av > bv ? 1 : 0)); +} + +int +gr_csr_mat_set_entry(gr_csr_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx) +{ + slong i, j; + slong sz = ctx->sizeof_elem; + ulong* bs = NULL; + + if (row < 0 || row >= mat->r || col < 0 || col >= mat->c) + return GR_DOMAIN; + + bs = bsearch(&col, mat->cols + mat->rows[row], mat->rows[row+1] - mat->rows[row], sizeof(ulong), ulong_cmp); + + if (bs != NULL) + { + i = bs - mat->cols; + if (gr_is_zero(entry, ctx) == T_TRUE) + { + // Shift everything above i down + for (j = row; j <= mat->r; ++j) + --mat->rows[j]; + memmove(mat->cols + i, mat->cols + i + 1, (mat->nnz - i - 1)*sizeof(slong)); + for (j = i; j < mat->nnz; j++) + { + gr_swap(GR_ENTRY(mat->nzs, j, sz), GR_ENTRY(mat->nzs, j + 1, sz), ctx); + } + --mat->nnz; + + return GR_SUCCESS; + } + } + else + { + if (gr_is_zero(entry, ctx) == T_TRUE) + { + // Already 0 + return GR_SUCCESS; + } + // Make space for one more nonzero + gr_csr_mat_fit_nnz(mat, mat->nnz+1, ctx); + + // Find location + for (i = mat->rows[row]; i < mat->rows[row + 1]; ++i) + if (col < mat->cols[i]) + break; + + // Shift everything above i up + for (j = row; j <= mat->r; ++j) + ++mat->rows[j]; + memmove(mat->cols + i + 1, mat->cols + i, (mat->nnz - i)*sizeof(slong)); + for (j = mat->nnz; j > i; j--) + { + gr_swap(GR_ENTRY(mat->nzs, j-1, sz), GR_ENTRY(mat->nzs, j, sz), ctx); + } + + mat->cols[i] = col; + ++mat->nnz; + } + return gr_set(GR_ENTRY(mat->nzs, i, sz), entry, ctx); +} + +int +gr_lil_mat_set_entry(gr_lil_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx) +{ + if (row < 0 || row >= mat->r) + return GR_DOMAIN; + + return gr_sparse_vec_set_entry(&mat->rows[row], col, entry, ctx); +} diff --git a/src/gr_sparse_mat/swap_rows.c b/src/gr_sparse_mat/swap_rows.c index 1a92b3d8cf..91a7500fbc 100644 --- a/src/gr_sparse_mat/swap_rows.c +++ b/src/gr_sparse_mat/swap_rows.c @@ -26,9 +26,9 @@ int gr_lil_mat_swap_rows(gr_lil_mat_t mat, slong * perm, slong r, slong s, gr_ct if (perm != NULL) FLINT_SWAP(slong, perm[r], perm[s]); - if (mat->rows[r]->nnz != 0 || mat->rows[s]->nnz != 0) + if (mat->rows[r].nnz != 0 || mat->rows[s].nnz != 0) { - gr_sparse_vec_swap(mat->rows[r], mat->rows[s], ctx); + gr_sparse_vec_swap(&mat->rows[r], &mat->rows[s], ctx); } return GR_SUCCESS; diff --git a/src/gr_sparse_mat/to_dense.c b/src/gr_sparse_mat/to_dense.c index 7c5ad80865..3bb4b4665b 100644 --- a/src/gr_sparse_mat/to_dense.c +++ b/src/gr_sparse_mat/to_dense.c @@ -11,41 +11,65 @@ #include "gr_sparse_mat.h" -int gr_mat_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) +int gr_mat_set_csr_mat(gr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) { ulong row, nz; - int success = GR_SUCCESS; + int status = GR_SUCCESS; size_t sz = ctx->sizeof_elem; - if (res->r != mat->r || res->c != mat->c) + if (dst->r != src->r || dst->c != src->c) return GR_DOMAIN; - success |= gr_mat_zero(res, ctx); - for (row = 0; row < mat->r; ++row) + status |= gr_mat_zero(dst, ctx); + for (row = 0; row < src->r; ++row) { - for (nz = mat->rows[row]; nz < mat->rows[row + 1]; ++nz) + for (nz = src->rows[row]; nz < src->rows[row + 1]; ++nz) { - success |= gr_set( - GR_MAT_ENTRY(res, row, mat->cols[nz], sz), - GR_ENTRY(mat->entries, nz, sz), + status |= gr_set( + GR_MAT_ENTRY(dst, row, src->cols[nz], sz), + GR_ENTRY(src->nzs, nz, sz), ctx ); } } - return success; + return status; } -int gr_mat_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) +int gr_mat_set_lil_mat(gr_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) { ulong row; - int success = GR_SUCCESS; + int status = GR_SUCCESS; - if (res->r != mat->r || res->c != mat->c) + if (dst->r != src->r || dst->c != src->c) return GR_DOMAIN; - for (row = 0; row < mat->r; ++row) + for (row = 0; row < src->r; ++row) { - success |= gr_vec_set_sparse_vec(res->rows[row], mat->rows[row], ctx); + status |= gr_vec_set_sparse_vec(dst->rows[row], &src->rows[row], ctx); } - return success; + return status; +} + +int gr_mat_set_coo_mat(gr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) +{ + ulong nz; + int status = GR_SUCCESS; + gr_ptr dst_entry; + gr_srcptr src_entry; + size_t sz = ctx->sizeof_elem; + + if (dst->r != src->r || dst->c != src->c) + return GR_DOMAIN; + + status |= gr_mat_zero(dst, ctx); + for (nz = 0; nz < src->nnz; ++nz) + { + dst_entry = GR_MAT_ENTRY(dst, src->rows[nz], src->cols[nz], sz); + src_entry = GR_ENTRY(src->nzs, nz, sz); + if (src->is_canonical) + status |= gr_set(dst_entry, src_entry, ctx); + else + status |= gr_add(dst_entry, dst_entry, src_entry, ctx); + } + return status; } diff --git a/src/gr_sparse_mat/write.c b/src/gr_sparse_mat/write.c new file mode 100644 index 0000000000..8822ec8394 --- /dev/null +++ b/src/gr_sparse_mat/write.c @@ -0,0 +1,83 @@ +#include +#include "gr_sparse_mat.h" + +int +gr_csr_mat_write_nz(gr_stream_t out, const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong row; + gr_sparse_vec_t tmp; + gr_stream_write(out, "["); + for (row = 0; row < mat->r; row++) + { + _gr_csr_mat_borrow_row(tmp, mat, row, ctx); + status |= gr_sparse_vec_write_nz(out, tmp, ctx); + if (row < mat->r - 1) + gr_stream_write(out, ", "); + } + gr_stream_write(out, "]"); + return status; +} + +int +gr_lil_mat_write_nz(gr_stream_t out, const gr_lil_mat_t mat, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong row; + + gr_stream_write(out, "["); + for (row = 0; row < mat->r; row++) + { + status |= gr_sparse_vec_write_nz(out, &mat->rows[row], ctx); + if (row < mat->r - 1) + gr_stream_write(out, ", "); + } + gr_stream_write(out, "]"); + return status; +} + +int +gr_coo_mat_write_nz(gr_stream_t out, const gr_coo_mat_t mat, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong nz; + slong sz = ctx->sizeof_elem; + + gr_stream_write(out, "["); + for (nz = 0; nz < mat->nnz; nz++) + { + gr_stream_write(out, "("); + gr_stream_write_si(out, mat->rows[nz]); + gr_stream_write(out, ", "); + gr_stream_write_si(out, mat->cols[nz]); + gr_stream_write(out, "): "); + status |= gr_write(out, GR_ENTRY(mat->nzs, nz, sz), ctx); + if (nz < mat->nnz - 1) + gr_stream_write(out, ", "); + } + gr_stream_write(out, "]"); + return status; +} + +int gr_csr_mat_print_nz(const gr_csr_mat_t mat, gr_ctx_t ctx) +{ + gr_stream_t out; + gr_stream_init_file(out, stdout); + return gr_csr_mat_write_nz(out, mat, ctx); +} + +int gr_lil_mat_print_nz(const gr_lil_mat_t mat, gr_ctx_t ctx) +{ + gr_stream_t out; + gr_stream_init_file(out, stdout); + return gr_lil_mat_write_nz(out, mat, ctx); +} + +int gr_coo_mat_print_nz(const gr_coo_mat_t mat, gr_ctx_t ctx) +{ + gr_stream_t out; + gr_stream_init_file(out, stdout); + return gr_coo_mat_write_nz(out, mat, ctx); +} + + diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index ec8b9ab3a2..422378d9e7 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -26,13 +26,16 @@ extern "C" { #endif +/** + * Types and basic access +**/ typedef struct { - slong alloc; - gr_ptr entries; - ulong *inds; slong length; slong nnz; + slong alloc; + ulong *inds; + gr_ptr nzs; } gr_sparse_vec_struct; @@ -48,64 +51,159 @@ gr_sparse_vec_init(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx) GR_SPARSE_VEC_INLINE void gr_sparse_vec_clear(gr_sparse_vec_t vec, gr_ctx_t ctx) { - _gr_vec_clear(vec->entries, vec->alloc, ctx); + _gr_vec_clear(vec->nzs, vec->alloc, ctx); flint_free(vec->inds); - flint_free(vec->entries); + flint_free(vec->nzs); memset(vec, 0, sizeof(gr_sparse_vec_t)); } -#define GR_SPARSE_VEC_IND(vec, nzidx) (vec)->inds[nzidx] -#define GR_SPARSE_VEC_ENTRY(vec, nzidx, sz) GR_ENTRY((vec)->entries, nzidx, sz) +GR_SPARSE_VEC_INLINE slong +gr_sparse_vec_length(const gr_sparse_vec_t vec) +{ return vec->length; } + +void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE ulong * gr_sparse_vec_ind_ptr(gr_sparse_vec_t vec, slong nzidx, gr_ctx_t ctx) { return vec->inds + nzidx; } -GR_SPARSE_VEC_INLINE const ulong * gr_sparse_vec_ind_srcptr(const gr_sparse_vec_t vec, slong nzidx, gr_ctx_t ctx) { return vec->inds + nzidx; } -GR_SPARSE_VEC_INLINE gr_ptr gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong nzidx, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, nzidx, ctx->sizeof_elem); } -GR_SPARSE_VEC_INLINE gr_srcptr gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong nzidx, gr_ctx_t ctx) { return GR_SPARSE_VEC_ENTRY(vec, nzidx, ctx->sizeof_elem); } +GR_SPARSE_VEC_INLINE slong +gr_sparse_vec_nnz(const gr_sparse_vec_t vec) +{ return vec->nnz; } void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx); void gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE slong gr_sparse_vec_length(const gr_sparse_vec_t vec) { return vec->length; } -void gr_sparse_vec_set_length(gr_sparse_vec_t vec, slong len, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE slong gr_sparse_vec_nnz(const gr_sparse_vec_t vec) { return vec->nnz; } -WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE void gr_sparse_vec_swap(gr_sparse_vec_t res, gr_sparse_vec_t src, gr_ctx_t ctx) +WARN_UNUSED_RESULT int +gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_sparse_vec_randtest(gr_sparse_vec_t vec, slong nnz, int replacement, flint_rand_t state, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int +gr_sparse_vec_randtest_prob(gr_sparse_vec_t vec, double prob, flint_rand_t state, gr_ctx_t ctx); + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_is_valid(gr_sparse_vec_t vec, gr_ctx_t ctx) { - FLINT_SWAP(slong, res->alloc, src->alloc); - FLINT_SWAP(gr_ptr, res->entries, src->entries); - FLINT_SWAP(ulong *, res->inds, src->inds); - FLINT_SWAP(slong, res->length, src->length); - FLINT_SWAP(slong, res->nnz, src->nnz); - + slong i, sz = ctx->sizeof_elem; + + // Check that parameters are valid + if (vec->nnz > vec->alloc || vec->alloc > vec->length) + return 0; + + // Check that entries are valid + for (i = 0; i < vec->nnz; ++i) + { + if (vec->inds[i] >= vec->length || (i > 0 && vec->inds[i] <= vec->inds[i-1])) + return 0; + if (gr_is_zero(GR_ENTRY(vec->nzs, i, sz), ctx) == T_TRUE) + return 0; + } + return 1; +} + +/** + * Getting, setting, and conversion +**/ + +#define GR_SPARSE_VEC_IND(vec, nz_idx) (vec)->inds[nz_idx] +#define GR_SPARSE_VEC_ENTRY(vec, nz_idx, sz) GR_ENTRY((vec)->nzs, nz_idx, sz) + +GR_SPARSE_VEC_INLINE ulong * +gr_sparse_vec_ind_ptr(gr_sparse_vec_t vec, slong nz_idx, gr_ctx_t ctx) +{ + if (nz_idx < 0 || nz_idx >= vec->nnz) + return NULL; + return vec->inds + nz_idx; +} + +GR_SPARSE_VEC_INLINE const ulong * +gr_sparse_vec_ind_srcptr(const gr_sparse_vec_t vec, slong nz_idx, gr_ctx_t ctx) +{ + if (nz_idx < 0 || nz_idx >= vec->nnz) + return NULL; + return vec->inds + nz_idx; } -GR_SPARSE_VEC_INLINE void gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; } -WARN_UNUSED_RESULT int gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong ind_start, slong ind_end, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_get_entry(gr_ptr res, gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx); +GR_SPARSE_VEC_INLINE gr_ptr +gr_sparse_vec_entry_ptr(gr_sparse_vec_t vec, slong nz_idx, gr_ctx_t ctx) +{ + if (nz_idx < 0 || nz_idx >= vec->nnz) + return NULL; + return GR_SPARSE_VEC_ENTRY(vec, nz_idx, ctx->sizeof_elem); +} + +GR_SPARSE_VEC_INLINE gr_srcptr +gr_sparse_vec_entry_srcptr(const gr_sparse_vec_t vec, slong nz_idx, gr_ctx_t ctx) +{ + if (nz_idx < 0 || nz_idx >= vec->nnz) + return NULL; + return GR_SPARSE_VEC_ENTRY(vec, nz_idx, ctx->sizeof_elem); +} + +WARN_UNUSED_RESULT gr_ptr gr_sparse_vec_find_entry(gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_vec_get_entry(gr_ptr dst, gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx); + WARN_UNUSED_RESULT int gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong ind, gr_srcptr entry, gr_ctx_t ctx); -truth_t gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_is_zero(vec->entries, vec->nnz, ctx); } +WARN_UNUSED_RESULT int gr_sparse_vec_set(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_slice(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong ind_start, slong ind_end, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_vec_set_vec(gr_sparse_vec_t dst, gr_srcptr src, slong len, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_set_sparse_vec(gr_ptr dst, gr_sparse_vec_t src, gr_ctx_t ctx); + +GR_SPARSE_VEC_INLINE void gr_sparse_vec_swap(gr_sparse_vec_t vec1, gr_sparse_vec_t vec2, gr_ctx_t ctx) +{ + FLINT_SWAP(slong, vec1->alloc, vec2->alloc); + FLINT_SWAP(gr_ptr, vec1->nzs, vec2->nzs); + FLINT_SWAP(ulong *, vec1->inds, vec2->inds); + FLINT_SWAP(slong, vec1->length, vec2->length); + FLINT_SWAP(slong, vec1->nnz, vec2->nnz); + +} +GR_SPARSE_VEC_INLINE +void gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) +{ vec->nnz = 0; } +GR_SPARSE_VEC_INLINE +int gr_sparse_vec_one(gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx) +{ + if (ind < 0) + return GR_DOMAIN; + + gr_sparse_vec_fit_nnz(vec, 1, ctx); + vec->inds[0] = ind; + vec->nnz = 1; + return gr_one(vec->nzs, ctx); +} + +WARN_UNUSED_RESULT int gr_sparse_vec_permute_inds(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong * p, gr_ctx_t ctx); + +/** + * Comparison +**/ + +truth_t gr_sparse_vec_equal(const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx); +GR_SPARSE_VEC_INLINE truth_t gr_sparse_vec_is_zero(const gr_sparse_vec_t vec, gr_ctx_t ctx) { return _gr_vec_is_zero(vec->nzs, vec->nnz, ctx); } + +/** + * Output +**/ int gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx); int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_sparse_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx); +/** + * Arithmetic +**/ +// Internal function to count the union of indicies in inds0 and inds1 slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulong *inds1, slong nnz1); - +// Internal macro to swap two entries with their associated indices #define GR_SPV_SWAP_INDS(VEC, I, J, SZ, CTX) \ { \ slong _temp = (VEC)->inds[I]; \ (VEC)->inds[I] = (VEC)->inds[J]; \ (VEC)->inds[J] = _temp; \ - gr_swap(GR_ENTRY((VEC)->entries, (I), (SZ)), GR_ENTRY((VEC)->entries, (J), (SZ)), (CTX)); \ + gr_swap(GR_ENTRY((VEC)->nzs, (I), (SZ)), GR_ENTRY((VEC)->nzs, (J), (SZ)), (CTX)); \ } /* @@ -115,13 +213,13 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo proceeds, for a given index, we need one function FUNC_A if only A_VEC has a nonzero element at that index, another function FUNC_B if only B_VEC has a nonzero element, and a third function FUNC_AB if both are nonzero. - During this process, we maintain a triple of indices a_nzidx, b_nzidx, and + During this process, we maintain a triple of indices a_nz_idx, b_nz_idx, and dest_ind, which are used when calling this macro to indicate what element(s) to refer to when calling the appropriate function. */ #define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ int status; \ - slong sz, new_nnz, a_nzidx, b_nzidx, dest_ind, a_nnz, b_nnz, i; \ + slong sz, new_nnz, a_nz_idx, b_nz_idx, dest_ind, a_nnz, b_nnz, i; \ ulong a_ind, b_ind; \ if ((DEST_VEC)->length != (A_VEC)->length || (A_VEC)->length != (B_VEC)->length) \ return GR_DOMAIN; \ @@ -132,33 +230,33 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo new_nnz = _gr_sparse_vec_count_unique_inds((A_VEC)->inds, a_nnz, (B_VEC)->inds, b_nnz); \ gr_sparse_vec_fit_nnz((DEST_VEC), new_nnz, (CTX)); \ /* We go backward through the destination, because it might be an in-place operation on a source */ \ - a_nzidx = a_nnz-1; \ - b_nzidx = b_nnz-1; \ + a_nz_idx = a_nnz-1; \ + b_nz_idx = b_nnz-1; \ dest_ind = new_nnz-1; \ - while (a_nzidx >= 0 && b_nzidx >= 0 && status == GR_SUCCESS) \ + while (a_nz_idx >= 0 && b_nz_idx >= 0 && status == GR_SUCCESS) \ { \ - a_ind = (A_VEC)->inds[a_nzidx]; \ - b_ind = (B_VEC)->inds[b_nzidx]; \ + a_ind = (A_VEC)->inds[a_nz_idx]; \ + b_ind = (B_VEC)->inds[b_nz_idx]; \ if (a_ind > b_ind) \ { \ status |= (FUNC_A); \ (DEST_VEC)->inds[dest_ind] = a_ind; \ - a_nzidx--; \ + a_nz_idx--; \ } \ else if (b_ind > a_ind) \ { \ status |= (FUNC_B); \ (DEST_VEC)->inds[dest_ind] = b_ind; \ - b_nzidx--; \ + b_nz_idx--; \ } \ else \ { \ status |= (FUNC_AB); \ (DEST_VEC)->inds[dest_ind] = a_ind; \ - a_nzidx--; \ - b_nzidx--; \ + a_nz_idx--; \ + b_nz_idx--; \ } \ - if (T_TRUE != gr_is_zero(GR_ENTRY((DEST_VEC)->entries, dest_ind, sz), (CTX))) \ + if (T_TRUE != gr_is_zero(GR_ENTRY((DEST_VEC)->nzs, dest_ind, sz), (CTX))) \ dest_ind--; \ } \ /* Move the result to the beginning of the dest vec */ \ @@ -175,190 +273,184 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo /* We need some convenience functions for certain simple operations. */ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_neg_other(gr_ptr res, gr_srcptr src, gr_ctx_t src_ctx, gr_ctx_t ctx) -{ return (gr_set_other(res, src, src_ctx, ctx) | gr_neg(res, res, ctx)); } +gr_neg_other(gr_ptr dst, gr_srcptr src, gr_ctx_t src_ctx, gr_ctx_t ctx) +{ return (gr_set_other(dst, src, src_ctx, ctx) | gr_neg(dst, dst, ctx)); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_negmul(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) -{ return (gr_mul(res, x, y, ctx) | gr_neg(res, res, ctx)); } +gr_negmul(gr_ptr dst, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) +{ return (gr_mul(dst, x, y, ctx) | gr_neg(dst, dst, ctx)); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_negmul_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx) -{ return (gr_mul_si(res, x, y, ctx) | gr_neg(res, res, ctx)); } +gr_negmul_si(gr_ptr dst, gr_srcptr x, slong y, gr_ctx_t ctx) +{ return (gr_mul_si(dst, x, y, ctx) | gr_neg(dst, dst, ctx)); } // Convenience macros for applying a unary or binary function #define GR_SPV_RFL_UOP(F, Y, Y_ind) \ - F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), ctx) + F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, sz), ctx) #define GR_SPV_RFL_BOP(F, Y, Y_ind, Z, Z_ind) \ - F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, sz), ctx) + F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, sz), GR_ENTRY(Z->nzs, Z_ind, sz), ctx) + +// Need a unary function to assign zero +#define GR_SPV_RFL_ZERO gr_zero(GR_ENTRY(dst->nzs, dest_ind, sz), ctx) + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_neg(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ return (gr_sparse_vec_set(dst, src, ctx) | _gr_vec_neg(dst->nzs, dst->nzs, dst->nnz, ctx)); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +gr_sparse_vec_update(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) { - // All function are set to src value if possible, otherwise res value GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, res, a_nzidx), - GR_SPV_RFL_UOP(gr_set, src, b_nzidx), - GR_SPV_RFL_UOP(gr_set, src, b_nzidx), - res, res, src, ctx + GR_SPV_RFL_UOP(gr_set, dst, a_nz_idx), + GR_SPV_RFL_UOP(gr_set, src, b_nz_idx), + GR_SPV_RFL_UOP(gr_set, src, b_nz_idx), + dst, dst, src, ctx ); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +gr_sparse_vec_add(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), - GR_SPV_RFL_UOP(gr_set, src2, b_nzidx), - GR_SPV_RFL_BOP(gr_add, src1, a_nzidx, src2, b_nzidx), - res, src1, src2, ctx + GR_SPV_RFL_UOP(gr_set, src1, a_nz_idx), + GR_SPV_RFL_UOP(gr_set, src2, b_nz_idx), + GR_SPV_RFL_BOP(gr_add, src1, a_nz_idx, src2, b_nz_idx), + dst, src1, src2, ctx ); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +gr_sparse_vec_sub(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), - GR_SPV_RFL_UOP(gr_neg, src2, b_nzidx), - GR_SPV_RFL_BOP(gr_sub, src1, a_nzidx, src2, b_nzidx), - res, src1, src2, ctx + GR_SPV_RFL_UOP(gr_set, src1, a_nz_idx), + GR_SPV_RFL_UOP(gr_neg, src2, b_nz_idx), + GR_SPV_RFL_BOP(gr_sub, src1, a_nz_idx, src2, b_nz_idx), + dst, src1, src2, ctx ); } -// Need a unary function to assign zero -#define GR_SPV_RFL_ZERO gr_zero(GR_ENTRY(res->entries, dest_ind, sz), ctx) - GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +gr_sparse_vec_mul(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, - GR_SPV_RFL_BOP(gr_mul, src1, a_nzidx, src2, b_nzidx), - res, src1, src2, ctx + GR_SPV_RFL_BOP(gr_mul, src1, a_nz_idx, src2, b_nz_idx), + dst, src1, src2, ctx ); } // Analogous macros for applying a unary or binary function between two contexts #define GR_SPV_RFL_UOP_OTHER(F, Y, Y_ind, CTX2) \ - F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), CTX2, ctx) + F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, CTX2->sizeof_elem), CTX2, ctx) #define GR_SPV_RFL_BOP_OTHER(F, Y, Y_ind, Z, Z_ind, CTX2) \ - F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), GR_ENTRY(Z->entries, Z_ind, CTX2->sizeof_elem), CTX2, ctx) + F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, sz), GR_ENTRY(Z->nzs, Z_ind, CTX2->sizeof_elem), CTX2, ctx) #define GR_SPV_RFL_OTHER_BOP(F, Y, Y_ind, CTX2, Z, Z_ind) \ - F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, CTX2->sizeof_elem), (CTX2), GR_ENTRY(Z->entries, Z_ind, sz), ctx) + F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, CTX2->sizeof_elem), (CTX2), GR_ENTRY(Z->nzs, Z_ind, sz), ctx) GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +gr_sparse_vec_add_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), - GR_SPV_RFL_UOP_OTHER(gr_set_other, src2, b_nzidx, ctx2), - GR_SPV_RFL_BOP_OTHER(gr_add_other, src1, a_nzidx, src2, b_nzidx, ctx2), - res, src1, src2, ctx + GR_SPV_RFL_UOP(gr_set, src1, a_nz_idx), + GR_SPV_RFL_UOP_OTHER(gr_set_other, src2, b_nz_idx, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_add_other, src1, a_nz_idx, src2, b_nz_idx, ctx2), + dst, src1, src2, ctx ); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +gr_sparse_vec_sub_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_nzidx), - GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_nzidx, ctx2), - GR_SPV_RFL_BOP_OTHER(gr_sub_other, src1, a_nzidx, src2, b_nzidx, ctx2), - res, src1, src2, ctx + GR_SPV_RFL_UOP(gr_set, src1, a_nz_idx), + GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_nz_idx, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_sub_other, src1, a_nz_idx, src2, b_nz_idx, ctx2), + dst, src1, src2, ctx ); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +gr_sparse_vec_mul_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, - GR_SPV_RFL_BOP_OTHER(gr_mul_other, src1, a_nzidx, src2, b_nzidx, ctx2), - res, src1, src2, ctx + GR_SPV_RFL_BOP_OTHER(gr_mul_other, src1, a_nz_idx, src2, b_nz_idx, ctx2), + dst, src1, src2, ctx ); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +gr_other_add_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_nzidx, ctx1), - GR_SPV_RFL_UOP(gr_set, src2, b_nzidx), - GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_nzidx, ctx1, src2, b_nzidx), - res, src1, src2, ctx + GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_nz_idx, ctx1), + GR_SPV_RFL_UOP(gr_set, src2, b_nz_idx), + GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_nz_idx, ctx1, src2, b_nz_idx), + dst, src1, src2, ctx ); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +gr_other_sub_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_nzidx, ctx1), - GR_SPV_RFL_UOP(gr_neg, src2, b_nzidx), - GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_nzidx, ctx1, src2, b_nzidx), - res, src1, src2, ctx + GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_nz_idx, ctx1), + GR_SPV_RFL_UOP(gr_neg, src2, b_nz_idx), + GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_nz_idx, ctx1, src2, b_nz_idx), + dst, src1, src2, ctx ); } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_other_mul_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +gr_other_mul_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, - GR_SPV_RFL_OTHER_BOP(gr_other_mul, src1, a_nzidx, ctx1, src2, b_nzidx), - res, src1, src2, ctx + GR_SPV_RFL_OTHER_BOP(gr_other_mul, src1, a_nz_idx, ctx1, src2, b_nz_idx), + dst, src1, src2, ctx ); } #define GR_SPV_RFL_UOP_SCALAR(F, Y, Y_ind, C, CTX) \ - F(GR_ENTRY(res->entries, dest_ind, sz), GR_ENTRY(Y->entries, Y_ind, sz), C, CTX) + F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, sz), C, CTX) /* Subtemplate for doing accumulated operation from one sparse vector into another. - Used to do res += c * src and res -= c * src, for c a scalar. + Used to do dst += c * src and dst -= c * src, for c a scalar. */ #define GR_SPV_ACCUM_TEMPLATE(ELEM_OP, ELEM_ACCUM_OP, RES, SRC, C, CTX) \ GR_SPV_RFL_TEMPLATE( \ - GR_SPV_RFL_UOP(gr_set, RES, a_nzidx), \ - GR_SPV_RFL_UOP_SCALAR(ELEM_OP, SRC, b_nzidx, C, CTX), \ - GR_SPV_RFL_UOP_SCALAR(ELEM_ACCUM_OP, SRC, b_nzidx, C, CTX), \ + GR_SPV_RFL_UOP(gr_set, RES, a_nz_idx), \ + GR_SPV_RFL_UOP_SCALAR(ELEM_OP, SRC, b_nz_idx, C, CTX), \ + GR_SPV_RFL_UOP_SCALAR(ELEM_ACCUM_OP, SRC, b_nz_idx, C, CTX), \ RES, RES, SRC, CTX\ ) GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_addmul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_TEMPLATE(gr_mul, gr_addmul, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_submul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_TEMPLATE(gr_negmul, gr_submul, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_TEMPLATE(gr_mul_si, gr_addmul_si, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_TEMPLATE(gr_negmul_si, gr_submul_si, res, src, c, ctx); } +gr_sparse_vec_addmul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_mul, gr_addmul, dst, src, c, ctx) } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) -{ return (gr_sparse_vec_set(res, src, ctx) | _gr_vec_neg(res->entries, res->entries, res->nnz, ctx)); } +gr_sparse_vec_submul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_negmul, gr_submul, dst, src, c, ctx) } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_sum(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) -{ return _gr_vec_sum(res, vec->entries, vec->nnz, ctx); } +gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_mul_si, gr_addmul_si, dst, src, c, ctx) } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_nz_product(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) -{ return _gr_vec_product(res, vec->entries, vec->nnz, ctx); } +gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_negmul_si, gr_submul_si, dst, src, c, ctx); } +/** + * Arithmetic into dense vectors +**/ -/* These are versions that incorporate a sparse into a dense */ +// Internal macro to update a dense vector by iterating over a sparse one #define GR_SPV_INTO_DENSE_TEMPLATE(FUNC, SVEC, CTX) \ slong i; \ slong sz = (CTX)->sizeof_elem; \ @@ -370,14 +462,24 @@ gr_sparse_vec_nz_product(gr_ptr res, const gr_sparse_vec_t vec, gr_ctx_t ctx) } \ return status; -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_update_sparse_vec_nz(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) -{ GR_SPV_INTO_DENSE_TEMPLATE(gr_set(GR_ENTRY(dres, src->inds[i], sz), GR_ENTRY(src->entries, i, sz), ctx), src, ctx) } +// Sub-macro for applying operation (dense, sparse) -> dense +#define GR_SPV_OP_ON_DENSE_TEMPLATE(ELEM_OP, DRES, DVEC, SVEC, CTX) \ + GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(\ + GR_ENTRY((DRES), (SVEC)->inds[i], sz), \ + GR_ENTRY(DVEC, (SVEC)->inds[i], sz), \ + GR_ENTRY((SVEC)->nzs, i, sz), \ + CTX), SVEC, CTX) -/* Sub-macro for applying operation (dense, sparse) -> dense */ +// Sub-macro for accumulating operation on dense from sparse +#define GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(ELEM_OP, DRES, SVEC, C, CTX) \ + GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(\ + GR_ENTRY(DRES, (SVEC)->inds[i], sz), \ + GR_ENTRY((SVEC)->nzs, i, sz),\ + C, CTX), SVEC, CTX) -#define GR_SPV_OP_ON_DENSE_TEMPLATE(ELEM_OP, DRES, DVEC, SVEC, CTX) \ - GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(GR_ENTRY((DRES), (SVEC)->inds[i], sz), GR_ENTRY(DVEC, (SVEC)->inds[i], sz), GR_ENTRY((SVEC)->entries, i, sz), CTX), SVEC, CTX) +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_vec_update_sparse_vec_nz(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ GR_SPV_INTO_DENSE_TEMPLATE(gr_set(GR_ENTRY(dres, src->inds[i], sz), GR_ENTRY(src->nzs, i, sz), ctx), src, ctx) } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_vec_add_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) @@ -395,11 +497,6 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_vec_div_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) { GR_SPV_OP_ON_DENSE_TEMPLATE(gr_div, dres, dvec1, svec2, ctx) } -/* Sub-macro for accumulating operation on dense from sparse */ - -#define GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(ELEM_OP, DRES, SVEC, C, CTX) \ - GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(GR_ENTRY(DRES, (SVEC)->inds[i], sz), GR_ENTRY((SVEC)->entries, i, sz), C, CTX), SVEC, CTX) - GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_vec_addmul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul, dres, svec, c, ctx) } @@ -424,144 +521,163 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_vec_submul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) { GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul_fmpz, dres, svec, c, ctx) } +/** + * Scalar multiplication and division +**/ + +#define GR_SPARSE_VEC_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) \ + if(dst->length != src->length) \ + { \ + return GR_DOMAIN; \ + } \ + if(dst != src) \ + { \ + gr_sparse_vec_fit_nnz(dst, src->nnz, ctx); \ + dst->nnz = src->nnz; \ + memcpy(dst->inds, src->inds, src->nnz*sizeof(slong)); \ + } \ + return dense_vec_op(dst->nzs, src->nzs, src->nnz, c, ctx); \ + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_div_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_div_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } + GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_ctx_t ctx) +gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } + +/** + * Sum and product +**/ + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_sum(gr_ptr dst, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ return _gr_vec_sum(dst, src->nzs, src->nnz, ctx); } + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_nz_product(gr_ptr dst, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ return _gr_vec_product(dst, src->nzs, src->nnz, ctx); } + +/** + * Dot product +**/ + +GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int +gr_sparse_vec_dot(gr_ptr dst, gr_srcptr initial, int subtract, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { int status; - slong nzidx1, nzidx2; + slong nz_idx1, nz_idx2; slong sz = ctx->sizeof_elem; - if (vec1->length != vec2->length) + if (src1->length != src2->length) { return GR_DOMAIN; } - status = gr_set(res, initial, ctx); - for (nzidx1 = 0, nzidx2 = 0; nzidx1 < vec1->nnz && nzidx2 < vec2->nnz; ) + status = gr_set(dst, initial, ctx); + for (nz_idx1 = 0, nz_idx2 = 0; nz_idx1 < src1->nnz && nz_idx2 < src2->nnz; ) { - if (vec1->inds[nzidx1] < vec2->inds[nzidx2]) + if (src1->inds[nz_idx1] < src2->inds[nz_idx2]) { - nzidx1++; + nz_idx1++; } - else if (vec1->inds[nzidx1] > vec2->inds[nzidx2]) + else if (src1->inds[nz_idx1] > src2->inds[nz_idx2]) { - nzidx2++; + nz_idx2++; } else if (subtract) { - status |= gr_submul(res, GR_ENTRY(vec1->entries, nzidx1, sz), GR_ENTRY(vec2->entries, nzidx1, sz), ctx); + status |= gr_submul(dst, GR_ENTRY(src1->nzs, nz_idx1, sz), GR_ENTRY(src2->nzs, nz_idx1, sz), ctx); } else { - status |= gr_addmul(res, GR_ENTRY(vec1->entries, nzidx1, sz), GR_ENTRY(vec2->entries, nzidx1, sz), ctx); + status |= gr_addmul(dst, GR_ENTRY(src1->nzs, nz_idx1, sz), GR_ENTRY(src2->nzs, nz_idx1, sz), ctx); } } return status; } GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_dot_vec(gr_ptr res, gr_srcptr initial, int subtract, const gr_sparse_vec_t vec1, const gr_vec_t vec2, gr_ctx_t ctx) +gr_sparse_vec_dot_vec(gr_ptr dst, gr_srcptr initial, int subtract, const gr_sparse_vec_t src1, const gr_vec_t src2, gr_ctx_t ctx) { int status; - slong nzidx; + slong nz_idx; slong sz = ctx->sizeof_elem; - if (vec1->length != vec2->length) + if (src1->length != src2->length) { return GR_DOMAIN; } - status = gr_set(res, initial, ctx); - for (nzidx = 0; nzidx < vec1->nnz; nzidx++) + status = gr_set(dst, initial, ctx); + for (nz_idx = 0; nz_idx < src1->nnz; nz_idx++) { if (subtract) { - status |= gr_submul(res, GR_ENTRY(vec1->entries, nzidx, sz), GR_ENTRY(vec2->entries, vec1->inds[nzidx], sz), ctx); + status |= gr_submul(dst, GR_ENTRY(src1->nzs, nz_idx, sz), GR_ENTRY(src2->entries, src1->inds[nz_idx], sz), ctx); } else { - status |= gr_addmul(res, GR_ENTRY(vec1->entries, nzidx, sz), GR_ENTRY(vec2->entries, vec1->inds[nzidx], sz), ctx); + status |= gr_addmul(dst, GR_ENTRY(src1->nzs, nz_idx, sz), GR_ENTRY(src2->entries, src1->inds[nz_idx], sz), ctx); } } return status; } -#define GR_SPARSE_VEC_DENSE_VEC_OP(dense_vec_op, res, src, c, ctx) \ - if(res->length != src->length) \ - { \ - return GR_DOMAIN; \ - } \ - if(res != src) \ - { \ - gr_sparse_vec_fit_nnz(res, src->nnz, ctx); \ - res->nnz = src->nnz; \ - memcpy(res->inds, src->inds, src->nnz*sizeof(slong)); \ - } \ - return dense_vec_op(res->entries, src->entries, src->nnz, c, ctx); \ - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_si, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_ui, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, res, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, res, src, c, ctx) } - - #ifdef __cplusplus } diff --git a/src/gr_sparse_vec/equal.c b/src/gr_sparse_vec/equal.c index b286337fc4..2a6def343d 100644 --- a/src/gr_sparse_vec/equal.c +++ b/src/gr_sparse_vec/equal.c @@ -17,21 +17,21 @@ gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_c if (vec1->inds[i1] < vec2->inds[i2]) { // In vector => either known or maybe nonzero - if (is_zero(GR_ENTRY(vec1->entries, i1, sz), ctx) == T_FALSE) + if (is_zero(GR_ENTRY(vec1->nzs, i1, sz), ctx) == T_FALSE) return T_FALSE; else ret = T_UNKNOWN; // Have maybe zero vs known zero } else if (vec1->inds[i1] > vec2->inds[i2]) { - if (is_zero(GR_ENTRY(vec2->entries, i2, sz), ctx) == T_FALSE) + if (is_zero(GR_ENTRY(vec2->nzs, i2, sz), ctx) == T_FALSE) return T_FALSE; else ret = T_UNKNOWN; // Have maybe zero vs known zero } else { - cur_test = gr_equal(GR_ENTRY(vec1->entries, i1, sz), GR_ENTRY(vec2->entries, i2, sz), ctx); + cur_test = gr_equal(GR_ENTRY(vec1->nzs, i1, sz), GR_ENTRY(vec2->nzs, i2, sz), ctx); if (cur_test == T_FALSE) return T_FALSE; else if (cur_test == T_UNKNOWN) diff --git a/src/gr_sparse_vec/fit_nnz.c b/src/gr_sparse_vec/fit_nnz.c index 52b8f89728..5ae7b4c348 100644 --- a/src/gr_sparse_vec/fit_nnz.c +++ b/src/gr_sparse_vec/fit_nnz.c @@ -16,8 +16,8 @@ gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx) if (new_alloc > vec->length) new_alloc = vec->length; vec->inds = flint_realloc(vec->inds, new_alloc * sizeof(ulong)); - vec->entries = flint_realloc(vec->entries, new_alloc * sz); - _gr_vec_init(GR_ENTRY(vec->entries, alloc, sz), new_alloc - alloc, ctx); + vec->nzs = flint_realloc(vec->nzs, new_alloc * sz); + _gr_vec_init(GR_ENTRY(vec->nzs, alloc, sz), new_alloc - alloc, ctx); vec->alloc = new_alloc; } } diff --git a/src/gr_sparse_vec/from_dense.c b/src/gr_sparse_vec/from_dense.c index 6947e8a296..3707cba915 100644 --- a/src/gr_sparse_vec/from_dense.c +++ b/src/gr_sparse_vec/from_dense.c @@ -19,7 +19,7 @@ gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ct if (T_FALSE == gr_is_zero(GR_ENTRY(src, i, sz), ctx)) { vec->inds[nnz] = i; - status |= gr_set(GR_ENTRY(vec->entries, nnz, sz), GR_ENTRY(src, i, sz), ctx); + status |= gr_set(GR_ENTRY(vec->nzs, nnz, sz), GR_ENTRY(src, i, sz), ctx); nnz++; } } diff --git a/src/gr_sparse_vec/from_entries.c b/src/gr_sparse_vec/from_entries.c new file mode 100644 index 0000000000..192b2cfc16 --- /dev/null +++ b/src/gr_sparse_vec/from_entries.c @@ -0,0 +1,91 @@ +#include +#include "gr_sparse_vec.h" + +typedef struct +{ + slong i; + slong ind; +} +sparse_vec_index_t; + +static int sparse_vec_index_cmp(const void* a, const void* b) +{ + slong aind = ((sparse_vec_index_t*)(a))->ind; + slong bind = ((sparse_vec_index_t*)(b))->ind; + return (aind < bind ? -1 : (aind > bind ? 1 : 0)); +} + + +static sparse_vec_index_t * _sort_inds(ulong * inds, slong num) +{ + slong i; + sparse_vec_index_t * si; + + si = flint_malloc(num * sizeof(sparse_vec_index_t)); + for (i = 0; i < num; i++) + { + si[i].i = i; + si[i].ind = inds[i]; + } + + qsort(si, num, sizeof(sparse_vec_index_t), sparse_vec_index_cmp); + return si; +} + +int +gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx) +{ + slong i; + slong sz = ctx->sizeof_elem; + int status = GR_SUCCESS; + sparse_vec_index_t *si; + gr_ptr vec_entry, entry; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); + + for (i = 0; i < nnz; ++i) + if (inds[i] >= vec->length) + return GR_DOMAIN; + + gr_sparse_vec_fit_nnz(vec, nnz, ctx); + if (is_canonical) + { + // Just copy data + memcpy(vec->inds, inds, nnz * sizeof(ulong)); + status |= _gr_vec_set(vec->nzs, entries, nnz, ctx); + vec->nnz = nnz; + } + else + { + si = _sort_inds(inds, nnz); + vec->nnz = 0; + vec_entry = NULL; + for(i = 0; i < nnz; ++i) + { + entry = GR_ENTRY(entries, si[i].i, sz); + + // If index is repeated, accumulate into current vector entry + if (i > 0 && si[i].ind == si[i-1].ind) + status |= gr_add(vec_entry, vec_entry, entry, ctx); + else + { + // If current entry is empty or nonzero, move to next one + if (vec_entry == NULL || is_zero(vec_entry, ctx) != T_TRUE) + { + vec_entry = GR_ENTRY(vec->nzs, vec->nnz, sz); + ++vec->nnz; + } + vec->inds[vec->nnz-1] = si[i].ind; + status |= gr_set(vec_entry, entry, ctx); + } + } + // Check if last entry accumulated to zero + if (vec_entry != NULL && is_zero(vec_entry, ctx) == T_TRUE) + vec->nnz--; + + flint_free(si); + } + return status; +} + + + diff --git a/src/gr_sparse_vec/get_entry.c b/src/gr_sparse_vec/get_entry.c index 78f2341032..953fac1cc4 100644 --- a/src/gr_sparse_vec/get_entry.c +++ b/src/gr_sparse_vec/get_entry.c @@ -10,10 +10,22 @@ static int gr_sparse_vec_ulong_cmp(const void* a, const void* b) } +gr_ptr +gr_sparse_vec_find_entry(gr_sparse_vec_t vec, slong col, gr_ctx_t ctx) +{ + slong sz = ctx->sizeof_elem; + ulong* bs = NULL; + if (col < 0 || col >= vec->length) + return NULL; + bs = bsearch(&col, vec->inds, vec->nnz, sizeof(slong), gr_sparse_vec_ulong_cmp); + if (bs == NULL) + return NULL; + return GR_ENTRY(vec->nzs, bs - vec->inds, sz); +} + int gr_sparse_vec_get_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx) { - slong i; slong sz = ctx->sizeof_elem; ulong* bs = NULL; if (col < 0 || col >= vec->length) @@ -21,6 +33,5 @@ gr_sparse_vec_get_entry(gr_ptr res, gr_sparse_vec_t vec, slong col, gr_ctx_t ctx bs = bsearch(&col, vec->inds, vec->nnz, sizeof(slong), gr_sparse_vec_ulong_cmp); if (bs == NULL) return gr_zero(res, ctx); - i = (bs - vec->inds); - return gr_set(res, GR_ENTRY(vec->entries, i, sz), ctx); + return gr_set(res, GR_ENTRY(vec->nzs, bs - vec->inds, sz), ctx); } diff --git a/src/gr_sparse_vec/permute_inds.c b/src/gr_sparse_vec/permute_inds.c index 6cf9ea7136..5915bf29f1 100644 --- a/src/gr_sparse_vec/permute_inds.c +++ b/src/gr_sparse_vec/permute_inds.c @@ -43,7 +43,7 @@ gr_sparse_vec_permute_inds(gr_sparse_vec_t vec, const gr_sparse_vec_t src, slong for (i = 0; i < nnz; i++) { vec->inds[i] = si[i].col; - status |= gr_set(GR_ENTRY(vec->entries, i, sz), GR_ENTRY(src->entries, si[i].i, sz), ctx); + status |= gr_set(GR_ENTRY(vec->nzs, i, sz), GR_ENTRY(src->nzs, si[i].i, sz), ctx); } flint_free(si); return status; diff --git a/src/gr_sparse_vec/randtest.c b/src/gr_sparse_vec/randtest.c index c791604012..8a61458f7d 100644 --- a/src/gr_sparse_vec/randtest.c +++ b/src/gr_sparse_vec/randtest.c @@ -2,59 +2,96 @@ #include "gr_sparse_vec.h" static int -int_sorter(const void * a, const void * b) +slong_cmp(const void * a, const void * b) { - return ((slong*)a) - ((slong*)b); + slong ax = *((slong *) a); + slong bx = *((slong *) b); + return ax - bx; } int -gr_sparse_vec_randtest(gr_sparse_vec_t vec, double density, slong len, flint_rand_t state, gr_ctx_t ctx) +gr_sparse_vec_randtest(gr_sparse_vec_t vec, slong nnz, int replacement, flint_rand_t state, gr_ctx_t ctx) { int status = GR_SUCCESS; - slong i, j, sz, nnz; + slong i, j, sz; sz = ctx->sizeof_elem; - nnz = (slong)(density * (double)len); - vec->length = len; - /* We choose nnz columns and deupe. For densities above about 1/sqrt(nnz), */ - /* this is not efficient and won't get the density right, but this isn't important for this function */ - if (nnz > vec->alloc) - { - vec->inds = flint_realloc(vec->inds, nnz*sizeof(slong)); - } - for (i = 0; i < nnz; i++) + + if (nnz < 0 || nnz > vec->length) + return GR_DOMAIN; + + // Make space + gr_sparse_vec_fit_nnz(vec, nnz, ctx); + + if (replacement) { - vec->inds[i] = n_randint(state, len); + // Randomly sample nnz columns with replacement, and then sort and prune duplicates + for (i = 0; i < nnz; ++i) + vec->inds[i] = n_randint(state, vec->length); + qsort(vec->inds, nnz, sizeof(slong), slong_cmp); + + j = 0; + for (i = 0; i < nnz; ++i) + if (i == 0 || vec->inds[i] != vec->inds[i-1]) + vec->inds[j++] = vec->inds[i]; + vec->nnz = j; } - qsort(vec->inds, nnz, sizeof(slong), int_sorter); - /* Contract the col list to remove duplicates */ - j = 0; - for (i = 0; i < nnz; i++) + else { - if (i == 0 || vec->inds[j-1] != vec->inds[i]) + // Randomly sample nnz columns without replacement, then sort + for (i = 0; i < vec->length; ++i) { - vec->inds[j] = vec->inds[i]; - j++; + j = i < nnz ? i : n_randint(state, i+1); + if (j < nnz) vec->inds[j] = i; } + if (nnz < vec->length) + qsort(vec->inds, nnz, sizeof(slong), slong_cmp); + vec->nnz = nnz; } - nnz = j; /* The actual number of distinct nnz */ - /* Make alloc exactly the new nnz to get inds and entries back in sync */ - vec->inds = flint_realloc(vec->inds, nnz*sizeof(slong)); - if (vec->alloc > nnz) + + for (i = 0; i < vec->nnz; ++i) + status |= gr_randtest_not_zero(GR_ENTRY(vec->nzs, i, sz), state, ctx); + + return status; +} + +int +gr_sparse_vec_randtest_prob(gr_sparse_vec_t vec, double prob, flint_rand_t state, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong i, sz; + sz = ctx->sizeof_elem; + + if (prob < 0 || prob > 1) + return GR_DOMAIN; + + // Handle corner cases + if (prob == 0) { - _gr_vec_clear(GR_ENTRY(vec->entries, nnz, sz), vec->alloc - nnz, ctx); - vec->entries = flint_realloc(vec->entries, nnz * sz); + gr_sparse_vec_zero(vec, ctx); + return GR_SUCCESS; } - else if (vec->alloc < nnz) + if (prob == 1) { - vec->entries = flint_realloc(vec->entries, nnz * sz); - _gr_vec_init(GR_ENTRY(vec->entries, vec->alloc, sz), nnz - vec->alloc, ctx); + status |= gr_sparse_vec_randtest(vec, vec->length, 0, state, ctx); + return status; } - vec->alloc = nnz; - vec->nnz = nnz; - for (i = 0; i < nnz; i++) + + // Allocate space for expected number of nonzeroes, and expand as needed + gr_sparse_vec_fit_nnz(vec, prob * vec->length, ctx); + + // TODO: for low probability, should be able to do this faster + vec->nnz = 0; + for (i = 0; i < vec->length; ++i) { - status |= gr_randtest_not_zero(GR_ENTRY(vec->entries, i, sz), state, ctx); + if (n_randint(state, 0) < 2 * prob * WORD_MAX) + { + if (vec->nnz == vec->alloc) + gr_sparse_vec_fit_nnz(vec, vec->alloc * 2, ctx); + status |= gr_randtest_not_zero(GR_ENTRY(vec->nzs, vec->nnz, sz), state, ctx); + vec->inds[vec->nnz++] = i; + } } + return status; } diff --git a/src/gr_sparse_vec/set.c b/src/gr_sparse_vec/set.c index 2f588a0607..0a36abdf52 100644 --- a/src/gr_sparse_vec/set.c +++ b/src/gr_sparse_vec/set.c @@ -1,17 +1,17 @@ #include "gr_sparse_vec.h" int -gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +gr_sparse_vec_set(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) { int status = GR_SUCCESS; - if (res != src) + if (dst != src) { slong nnz = src->nnz; - gr_sparse_vec_fit_nnz(res, nnz, ctx); - memcpy(res->inds, src->inds, nnz*sizeof(slong)); - status = _gr_vec_set(res->entries, src->entries, nnz, ctx); - res->nnz = nnz; - res->length = src->length; + gr_sparse_vec_fit_nnz(dst, nnz, ctx); + memcpy(dst->inds, src->inds, nnz*sizeof(slong)); + status = _gr_vec_set(dst->nzs, src->nzs, nnz, ctx); + dst->nnz = nnz; + dst->length = src->length; } return status; } diff --git a/src/gr_sparse_vec/set_entry.c b/src/gr_sparse_vec/set_entry.c index fcf1e4f13f..b8e141e8c7 100644 --- a/src/gr_sparse_vec/set_entry.c +++ b/src/gr_sparse_vec/set_entry.c @@ -27,7 +27,7 @@ gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_ memmove(vec->inds + i, vec->inds + i + 1, (vec->nnz - i - 1)*sizeof(slong)); for (j = i; j < vec->nnz; j++) { - gr_swap(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(vec->entries, j + 1, sz), ctx); + gr_swap(GR_ENTRY(vec->nzs, j, sz), GR_ENTRY(vec->nzs, j + 1, sz), ctx); } --vec->nnz; return GR_SUCCESS; @@ -52,10 +52,10 @@ gr_sparse_vec_set_entry(gr_sparse_vec_t vec, slong col, gr_srcptr entry, gr_ctx_ memmove(vec->inds + i + 1, vec->inds + i, (vec->nnz - i)*sizeof(slong)); for (j = vec->nnz; j > i; j--) { - gr_swap(GR_ENTRY(vec->entries, j-1, sz), GR_ENTRY(vec->entries, j, sz), ctx); + gr_swap(GR_ENTRY(vec->nzs, j-1, sz), GR_ENTRY(vec->nzs, j, sz), ctx); } vec->inds[i] = col; ++vec->nnz; } - return gr_set(GR_ENTRY(vec->entries, i, sz), entry, ctx); + return gr_set(GR_ENTRY(vec->nzs, i, sz), entry, ctx); } diff --git a/src/gr_sparse_vec/set_from_entries.c b/src/gr_sparse_vec/set_from_entries.c deleted file mode 100644 index cea072c2c7..0000000000 --- a/src/gr_sparse_vec/set_from_entries.c +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include "gr_sparse_vec.h" - -typedef struct -{ - slong col; - slong i; -} -gr_sparse_vec_slong_sorter_t; - -static int gr_sparse_vec_slong_cmp(const void* a, const void* b) -{ - slong ak = ((gr_sparse_vec_slong_sorter_t*)(a))->col; - slong bk = ((gr_sparse_vec_slong_sorter_t*)(b))->col; - return (ak < bk ? -1 : (ak > bk ? 1 : 0)); -} - - - -int -gr_sparse_vec_set_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) -{ - slong i,j,sz,new_nnz; - int status; - gr_sparse_vec_slong_sorter_t *si; - si = flint_malloc(nnz * sizeof(gr_sparse_vec_slong_sorter_t)); - for (i = 0; i < nnz; i++) - { - si[i].col = inds[i]; - si[i].i = i; - } - qsort(si, nnz, sizeof(gr_sparse_vec_slong_sorter_t), gr_sparse_vec_slong_cmp); - /* Since the columns are sorted, we can just test the last to make sure all the columns fit */ - if (nnz > 0 && si[nnz-1].col >= vec->length) - { - flint_free(si); - return GR_DOMAIN; - } - new_nnz = (nnz == 0 ? 0 : 1); - for (i = 1; i < nnz; i++) - { - if (si[i-1].col != si[i].col) - new_nnz += 1; - } - gr_sparse_vec_fit_nnz(vec, new_nnz, ctx); - sz = ctx->sizeof_elem; - status = GR_SUCCESS; - j = -1; /* j tracks the current index we are going to put the nonzero in the sparse vector storage */ - /* i tracks where in the column-sorted list of nonzeros we are pulling from */ - for (i = 0; i < nnz && status == GR_SUCCESS; i++) - { - /* If it's a new column, do a set; otherwise do an accumulate */ - if (i == 0 || si[i-1].col != si[i].col) - { - if (j == -1 || (T_FALSE == gr_is_zero(GR_ENTRY(vec->entries, j, sz), ctx))) /* Only move to the next target if the current one is nonzero */ - { - j++; - if (j >= new_nnz) - { - flint_free(si); - return GR_UNABLE; /* This is consistency check */ - } - } - vec->inds[j] = si[i].col; - status |= gr_set(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, si[i].i, sz), ctx); - } - else - { - if (vec->inds[j] != inds[si[i].i]) /* Consistency check that we're accumulating into the correct column */ - status |= GR_UNABLE; - status |= gr_add(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, si[i].i, sz), ctx); - } - } - /* Finally, figure out whether the last entry is zero (in which case it doesn't count), and set nnz accordingly */ - vec->nnz = (T_FALSE == gr_is_zero(GR_ENTRY(vec->entries, j, sz), ctx) ? j+1 : j); - flint_free(si); - return status; -} - -int -gr_sparse_vec_set_from_entries_sorted_deduped(gr_sparse_vec_t vec, ulong * sorted_deduped_inds, gr_srcptr entries, slong nnz, gr_ctx_t ctx) -{ - slong i,j,sz; - int status; - gr_sparse_vec_fit_nnz(vec, nnz, ctx); - sz = ctx->sizeof_elem; - j = 0; - status = GR_SUCCESS; - for (i = 0; i < nnz && status == GR_SUCCESS; i++) - { - if (T_FALSE == gr_is_zero(GR_ENTRY(entries, i, sz), ctx)) - { - vec->inds[j] = sorted_deduped_inds[i]; - status |= gr_set(GR_ENTRY(vec->entries, j, sz), GR_ENTRY(entries, i, sz), ctx); - j++; - } - } - vec->nnz = j; - return status; -} - - diff --git a/src/gr_sparse_vec/shrink_to_nnz.c b/src/gr_sparse_vec/shrink_to_nnz.c index d90955629f..10a6de3213 100644 --- a/src/gr_sparse_vec/shrink_to_nnz.c +++ b/src/gr_sparse_vec/shrink_to_nnz.c @@ -8,8 +8,8 @@ gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx) if (vec->alloc > nnz) { vec->inds = flint_realloc(vec->inds, nnz * sizeof(ulong)); - _gr_vec_clear(GR_ENTRY(vec->entries, nnz, sz), vec->alloc - nnz, ctx); - vec->entries = flint_realloc(vec->entries, nnz * sz); + _gr_vec_clear(GR_ENTRY(vec->nzs, nnz, sz), vec->alloc - nnz, ctx); + vec->nzs = flint_realloc(vec->nzs, nnz * sz); vec->alloc = nnz; } } diff --git a/src/gr_sparse_vec/slice.c b/src/gr_sparse_vec/slice.c index ed885ade3e..6b9dcfe6ec 100644 --- a/src/gr_sparse_vec/slice.c +++ b/src/gr_sparse_vec/slice.c @@ -1,7 +1,18 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "gr_sparse_vec.h" int -gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx) +gr_sparse_vec_slice(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong col_start, slong col_end, gr_ctx_t ctx) { slong sz,i,nnz, new_nnz, i_start, i_end, status; nnz = src->nnz; @@ -27,15 +38,15 @@ gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong col_st break; } } - /* We are messing with the internals of res; this should be ok even if it is also src */ + /* We are messing with the internals of dst; this should be ok even if it is also src */ new_nnz = i_end - i_start; - res->length = col_end - col_start; - gr_sparse_vec_fit_nnz(res, new_nnz, ctx); + dst->length = col_end - col_start; + gr_sparse_vec_fit_nnz(dst, new_nnz, ctx); for (i = i_start; i < i_end; i++) { - res->inds[i-i_start] = res->inds[i] - col_start; - status |= gr_set(GR_ENTRY(res->entries, i-i_start, sz), GR_ENTRY(src->entries, i, sz), ctx); + dst->inds[i-i_start] = dst->inds[i] - col_start; + status |= gr_set(GR_ENTRY(dst->nzs, i-i_start, sz), GR_ENTRY(src->nzs, i, sz), ctx); } - res->nnz = new_nnz; + dst->nnz = new_nnz; return status; } diff --git a/src/gr_sparse_vec/test/main.c b/src/gr_sparse_vec/test/main.c index ef0e9322bb..7e6302ee24 100644 --- a/src/gr_sparse_vec/test/main.c +++ b/src/gr_sparse_vec/test/main.c @@ -3,15 +3,17 @@ /* Include functions *********************************************************/ -#include "t-creation.c" +#include "t-init.c" #include "t-conversion.c" +#include "t-randtest.c" /* Array of test functions ***************************************************/ test_struct tests[] = { - TEST_FUNCTION(gr_sparse_vec_creation), + TEST_FUNCTION(gr_sparse_vec_init), TEST_FUNCTION(gr_sparse_vec_conversion), + TEST_FUNCTION(gr_sparse_vec_randtest), }; /* main function *************************************************************/ diff --git a/src/gr_sparse_vec/test/t-conversion.c b/src/gr_sparse_vec/test/t-conversion.c index 2ffa8a551c..9b4c498289 100644 --- a/src/gr_sparse_vec/test/t-conversion.c +++ b/src/gr_sparse_vec/test/t-conversion.c @@ -1,10 +1,19 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" #include "gr_sparse_vec.h" #define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } - - int test_conversion(flint_rand_t state, gr_ctx_t ctx) { @@ -13,11 +22,13 @@ test_conversion(flint_rand_t state, gr_ctx_t ctx) slong n_tests = 20; slong sz = ctx->sizeof_elem; int status = GR_SUCCESS; - gr_sparse_vec_t vec; + gr_sparse_vec_t vec, vec2; gr_vec_t dvec, dvec2; + gr_vec_init(dvec, N, ctx); gr_vec_init(dvec2, N, ctx); gr_sparse_vec_init(vec, N, ctx); + gr_sparse_vec_init(vec2, N, ctx); for (i = 0; i < n_tests; i++) { diff --git a/src/gr_sparse_vec/test/t-creation.c b/src/gr_sparse_vec/test/t-creation.c deleted file mode 100644 index 6a11475658..0000000000 --- a/src/gr_sparse_vec/test/t-creation.c +++ /dev/null @@ -1,121 +0,0 @@ -#include "test_helpers.h" -#include "gr_sparse_vec.h" - -#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } - -int -test_init(gr_ctx_t ctx) -{ - gr_sparse_vec_t vec; - int status = GR_SUCCESS; - gr_sparse_vec_init(vec, 5, ctx); - gr_sparse_vec_clear(vec, ctx); - return status; -} - - -int -test_init_from_entries_sorted(flint_rand_t state, gr_ctx_t ctx) -{ - slong i; - gr_sparse_vec_t vec; - gr_vec_t dvec; - gr_ptr temp; - GR_TMP_INIT(temp, ctx); - int status = GR_SUCCESS; - slong sz = ctx->sizeof_elem; - slong N = 5; - ulong inds[5] = {0, 2, 4, 6, 8}; - gr_vec_init(dvec, N, ctx); - status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); - gr_sparse_vec_init(vec, 2*N, ctx); - status |= gr_sparse_vec_set_from_entries_sorted_deduped(vec, inds, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); - for (i = 0; i < 2*N; i++) - { - status |= gr_sparse_vec_get_entry(temp, vec, i, ctx); - if ((i & 1) == 1 && (T_TRUE != gr_is_zero(temp, ctx))) /* Odd inds should all be zero */ - return GR_TEST_FAIL; - if ((i & 1) == 0 && (T_TRUE != gr_equal(temp, GR_VEC_ENTRY(dvec, i>>1, sz), ctx))) - return GR_TEST_FAIL; - } - GR_TMP_CLEAR(temp, ctx); - gr_vec_clear(dvec, ctx); - gr_sparse_vec_clear(vec, ctx); - return status; -} - - -int -test_init_from_entries_unsorted_internal(ulong *inds, gr_srcptr entries, slong len, slong n_entries, gr_ctx_t ctx) -{ - /* Yes, this is quadratic time just to be careful */ - int status = GR_SUCCESS; - slong sz = ctx->sizeof_elem; - slong i,j; - gr_sparse_vec_t vec; - gr_ptr temp, temp2; - GR_TMP_INIT2(temp, temp2, ctx); - gr_sparse_vec_init(vec, len, ctx); - status |= gr_sparse_vec_set_from_entries(vec, inds, entries, n_entries, ctx); - if (status != GR_SUCCESS) - return GR_TEST_FAIL; - /* Scan through every column in the sparse vector */ - for (i = 0; i < len; i++) - { - /* Scan through the entries to figure out what the correct value should be */ - status |= gr_zero(temp, ctx); - for (j = 0; j < n_entries; j++) - { - if (inds[j] == i) - status |= gr_add(temp, temp, GR_ENTRY(entries, j, sz), ctx); - } - /* Check it */ - status |= gr_sparse_vec_get_entry(temp2, vec, i, ctx); - if (T_TRUE != gr_equal(temp, temp2, ctx)) - return GR_TEST_FAIL; - } - GR_TMP_CLEAR(temp, ctx); - GR_TMP_CLEAR(temp2, ctx); - gr_sparse_vec_clear(vec, ctx); - return status; -} - - - -int -test_init_from_entries_unsorted(flint_rand_t state, gr_ctx_t ctx) -{ - slong i; - int status = GR_SUCCESS; - slong sz = ctx->sizeof_elem; - slong N = 5; - ulong inds[5] = {8, 4, 3, 8, 1}; - gr_vec_t dvec; - gr_vec_init(dvec, N, ctx); - /* First test against random entries */ - status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); - status |= test_init_from_entries_unsorted_internal(inds, GR_VEC_ENTRY(dvec, 0, sz), 2*N, N, ctx); - - /* Next test against some adversarial entries */ - slong entries_si[5] = {5, 0, 2, -5, 1}; - for (i = 0; i < N; i++) - status |= gr_set_si(GR_VEC_ENTRY(dvec, i, sz), entries_si[i], ctx); - status |= test_init_from_entries_unsorted_internal(inds, GR_VEC_ENTRY(dvec, 0, sz), 2*N, N, ctx); - - gr_vec_clear(dvec, ctx); - return status; -} - - - - -TEST_FUNCTION_START(gr_sparse_vec_creation, state) -{ - gr_ctx_t ctx; - gr_ctx_init_random(ctx, state); - CHECK_TEST(test_init(ctx), "Init"); - CHECK_TEST(test_init_from_entries_sorted(state, ctx), "Init from entries sorted"); - CHECK_TEST(test_init_from_entries_unsorted(state, ctx), "Init from entries unsorted"); - gr_ctx_clear(ctx); - TEST_FUNCTION_END(state); -} diff --git a/src/gr_sparse_vec/test/t-init.c b/src/gr_sparse_vec/test/t-init.c new file mode 100644 index 0000000000..634e0edd11 --- /dev/null +++ b/src/gr_sparse_vec/test/t-init.c @@ -0,0 +1,178 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_vec.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int +test_init(gr_ctx_t ctx) +{ + gr_sparse_vec_t vec; + gr_sparse_vec_init(vec, 5, ctx); + if (vec->length != 5 || vec->alloc != 0 || vec->nnz != 0 || vec->inds != NULL || vec->nzs != NULL) + return GR_TEST_FAIL; + gr_sparse_vec_clear(vec, ctx); + return GR_SUCCESS; +} + +int +test_init_from_entries_canonical(flint_rand_t state, gr_ctx_t ctx) +{ + // TODO: randomize length and nonzero cols + slong i; + gr_sparse_vec_t vec; + gr_ptr entries; + gr_ptr temp; + int status = GR_SUCCESS; + truth_t eq; + slong sz = ctx->sizeof_elem; + slong N = 5; + slong len = 10; + ulong inds[5] = {0, 2, 3, 6, 9}; + + //flint_printf("Running init test\n"); + GR_TMP_INIT(temp, ctx); + entries = flint_malloc(N * sz); + _gr_vec_init(entries, N, ctx); + for (i = 0; i < N; ++i) + status |= gr_randtest_not_zero(GR_ENTRY(entries, i, sz), state, ctx); + if (status != GR_SUCCESS) + { + flint_printf("Failed to make random numbers!\n"); + return GR_TEST_FAIL; // Not my fault! + } + + gr_sparse_vec_init(vec, len, ctx); + status |= gr_sparse_vec_from_entries(vec, inds, entries, N, 1, ctx); + + // Check parameters + if (status != GR_SUCCESS || vec->length != len || vec->alloc != 5 || vec->nnz != 5) + { + flint_printf("Bad params! %ld %ld %ld\n", vec->length, vec->alloc, vec->nnz); + return GR_TEST_FAIL; + } + + // Check indices and entries + for (i = 0; i < N; ++i) + { + if (*gr_sparse_vec_ind_ptr(vec, i, ctx) != inds[i]) + { + flint_printf("Bad indices!\n"); + return GR_TEST_FAIL; + } + eq = gr_equal(gr_sparse_vec_entry_ptr(vec, i, ctx), GR_ENTRY(entries, i, sz), ctx); + if (eq == T_FALSE) + { + flint_printf("Bad elements!\n"); + return GR_TEST_FAIL; + } + } + gr_sparse_vec_clear(vec, ctx); + _gr_vec_clear(entries, N, ctx); + flint_free(entries); + return status; +} + +int +test_init_from_entries_internal(ulong *inds, gr_srcptr entries, slong len, slong num, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + slong i,j; + gr_sparse_vec_t vec; + gr_ptr temp, temp2, temp3; + + GR_TMP_INIT2(temp, temp2, ctx); + gr_sparse_vec_init(vec, len, ctx); + status |= gr_sparse_vec_from_entries(vec, inds, entries, num, 0, ctx); + if (status != GR_SUCCESS) + return GR_TEST_FAIL; + + // Check every entry (including the zeroes) + for (i = 0; i < len; i++) + { + // Compute the expected value of the entry + status |= gr_zero(temp, ctx); + for (j = 0; j < num; j++) + if (inds[j] == i) + status |= gr_add(temp, temp, GR_ENTRY(entries, j, sz), ctx); + + status |= gr_sparse_vec_get_entry(temp2, vec, i, ctx); + temp3 = gr_sparse_vec_find_entry(vec, i, ctx); + if ( + gr_equal(temp, temp2, ctx) == T_FALSE || + (temp3 == NULL && gr_is_zero(temp, ctx) == T_FALSE) || + (temp3 != NULL && gr_is_zero(temp3, ctx) == T_TRUE) || + (temp3 != NULL && gr_equal(temp, temp3, ctx) == T_FALSE) + ) + { + flint_printf("Failed on %d!\n", i); + gr_println(temp, ctx); + gr_println(temp2, ctx); + return GR_TEST_FAIL; + } + } + GR_TMP_CLEAR(temp, ctx); + GR_TMP_CLEAR(temp2, ctx); + gr_sparse_vec_clear(vec, ctx); + return status; +} + +int +test_init_from_entries(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + slong N = 5; + ulong inds[5] = {8, 4, 3, 8, 1}; + gr_ptr entries = flint_malloc(N * sz); + + _gr_vec_init(entries, N, ctx); + + status |= _gr_vec_randtest(entries, state, N, ctx); + status |= test_init_from_entries_internal(inds, entries, 2*N, N, ctx); + + /* Next test against some adversarial entries */ + slong entries_si[5] = {5, 0, 2, -5, 1}; + for (i = 0; i < N; i++) + status |= gr_set_si(GR_ENTRY(entries, i, sz), entries_si[i], ctx); + status |= test_init_from_entries_internal(inds, entries, 2*N, N, ctx); + + _gr_vec_clear(entries, N, ctx); + flint_free(entries); + return status; +} + +TEST_FUNCTION_START(gr_sparse_vec_init, state) +{ + int i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while(1) + { + gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_print(ctx); flint_printf("\n"); + CHECK_TEST(test_init(ctx), "Init"); + CHECK_TEST(test_init_from_entries_canonical(state, ctx), "Init from entries in canonical form"); + CHECK_TEST(test_init_from_entries(state, ctx), "Init from entries in noncanonical form"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_vec/test/t-randtest.c b/src/gr_sparse_vec/test/t-randtest.c new file mode 100644 index 0000000000..5e829a14c7 --- /dev/null +++ b/src/gr_sparse_vec/test/t-randtest.c @@ -0,0 +1,79 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_vec.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int +test_randtest(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + slong N = 1024; + slong n_tests = 10; + int status = GR_SUCCESS; + gr_sparse_vec_t vec; + gr_sparse_vec_init(vec, N, ctx); + + //flint_printf("Testing w/o replacement\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_sparse_vec_randtest(vec, 128, 0, state, ctx); + if (!gr_sparse_vec_is_valid(vec, ctx) || vec->nnz != 128) + return GR_TEST_FAIL; + } + + //flint_printf("Testing w/ replacement\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_sparse_vec_randtest(vec, 32, 1, state, ctx); + if (!gr_sparse_vec_is_valid(vec, ctx) || vec->nnz > 32 || vec->nnz < 24) + return GR_TEST_FAIL; + } + + //flint_printf("Testing w/ prob\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_sparse_vec_randtest_prob(vec, 0.125, state, ctx); + if (!gr_sparse_vec_is_valid(vec, ctx) || vec->nnz > 192 || vec->nnz < 64) + { + gr_sparse_vec_print_nz(vec, ctx); flint_printf("%ld\n", vec->nnz); + return GR_TEST_FAIL; + } + + } + gr_sparse_vec_clear(vec, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_vec_randtest, state) +{ + int i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while(1) + { + //gr_ctx_init_nmod(ctx, 2147483647); + gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_print(ctx); flint_printf("\n"); + + CHECK_TEST(test_randtest(state, ctx), "Test random sparse vector generation"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_vec/to_dense.c b/src/gr_sparse_vec/to_dense.c index 233a1d2006..6a6367b870 100644 --- a/src/gr_sparse_vec/to_dense.c +++ b/src/gr_sparse_vec/to_dense.c @@ -14,7 +14,7 @@ gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) /* if i is the column of the next nonzero in src, copy it in */ if (j < nnz && i == src->inds[j]) { - status |= gr_set(GR_ENTRY(vec, i, sz), GR_ENTRY(src->entries, j, sz), ctx); + status |= gr_set(GR_ENTRY(vec, i, sz), GR_ENTRY(src->nzs, j, sz), ctx); j++; } else diff --git a/src/gr_sparse_vec/write.c b/src/gr_sparse_vec/write.c index a4155c173b..09ef401ef1 100644 --- a/src/gr_sparse_vec/write.c +++ b/src/gr_sparse_vec/write.c @@ -12,7 +12,7 @@ gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) { gr_stream_write_si(out, vec->inds[i]); gr_stream_write(out, ": "); - status |= gr_write(out, GR_ENTRY(vec->entries, i, sz), ctx); + status |= gr_write(out, GR_ENTRY(vec->nzs, i, sz), ctx); if (i < nnz - 1) gr_stream_write(out, ", "); } From e931f8d9841b1ea3d057bb815eff12a64184b371 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Tue, 19 Mar 2024 15:51:41 -0700 Subject: [PATCH 38/59] More doc fixes --- doc/source/gr_sparse_vec.rst | 98 ++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index 10e56e995e..6d75bb7cb3 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -24,12 +24,12 @@ Types and basic access * an `slong` value ``nnz``, the number of nonzero elements in vector, * an `slong` value ``alloc``, the maximum number of nonzero element currently storable in the vector, * a pointer to an `slong` array of indices (``inds``) of nonzeros. - * a :type:`gr_ptr` array of values of nonzeros (``entries``). + * a :type:`gr_ptr` array of values of nonzeros (``nzs``). The methods for sparse vectors maintain the following properties: * the indices ``inds`` are unique and sorted into strictly increasing order; - * the ``entries`` are nonzero (``gr_is_zero(entry, ctx)`` does not return ``T_TRUE``). + * the ``nzs`` are nonzero (``gr_is_zero(entry, ctx)`` does not return ``T_TRUE``). * ``nnz <= alloc <= length``. A ``gr_sparse_vec_t`` is defined as an array of length one of type @@ -136,29 +136,29 @@ Getting, setting and conversion (using `gr_sparse_vec_set_from_entries` or `gr_sparse_vec_set_from_entries_sorted_deduped`) passed to `gr_sparse_vec_update`. -.. function:: int gr_sparse_vec_set(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_set(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) - Set *src* to a copy of *res*. + Set *dst* to a copy of *src*. -.. function:: int gr_sparse_vec_slice(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong ind_start, slong ind_end, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_slice(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong ind_start, slong ind_end, gr_ctx_t ctx) - Set *res* to a copy of the slice of *src* given by any entries whose + Set *dst* to a copy of the slice of *src* given by any entries whose indices lie in the half open interval ``[ind_start, ind_end)``. Column indices are shifted by *ind_start* (a index of ``ind_start`` would become ``0``). -.. function:: int gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_set_vec(gr_sparse_vec_t dst, gr_srcptr src, slong len, gr_ctx_t ctx) - Set *vec* from the (raw) dense vector *src* of length *len*. + Set *dst* from the (raw) dense vector *src* of length *len*. -.. function:: int gr_vec_set_sparse_vec(gr_ptr vec, gr_sparse_vec_t src, gr_ctx_t ctx) +.. function:: int gr_vec_set_sparse_vec(gr_ptr dst, gr_sparse_vec_t src, gr_ctx_t ctx) - Set the raw vector *vec* from sparse vector *src*. *vec* must have - sufficient space (i.e. ``vec->length``). + Set the raw vector *dst* from sparse vector *src*. *dst* must have + sufficient space (i.e., ``vec->length``). -.. function:: void gr_sparse_vec_swap(gr_sparse_vec_t res, gr_sparse_vec_t src, gr_ctx_t ctx) +.. function:: void gr_sparse_vec_swap(gr_sparse_vec_t vec1, gr_sparse_vec_t vec2, gr_ctx_t ctx) - Swap the sparse vectors *res* and *src*. The entries are swapped as pointers, so + Swap the sparse vectors *vec1* and *vec2*. The entries are swapped as pointers, so no additional allociation or copying is performed. .. function:: int gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) @@ -203,40 +203,40 @@ Output Arithmetic -------------------------------------------------------------------------------- -.. function:: int gr_sparse_vec_neg(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_neg(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) - Set *res* to -*src* + Set *dst* to -*src* -.. function:: int gr_sparse_vec_update(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_update(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) - Update *res* with the nonzeros in *src*. That is, any index in *res* which also appear - in *src* are overwritten with their values in *src*. Any indices in *res* which do + Update *dst* with the nonzeros in *src*. That is, any index in *dst* which also appear + in *src* are overwritten with their values in *src*. Any indices in *dst* which do not appear in *src* are left unchanged. -.. function:: int gr_sparse_vec_add(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) - int gr_sparse_vec_sub(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) - int gr_sparse_vec_mul(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_add(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) + int gr_sparse_vec_sub(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) + int gr_sparse_vec_mul(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, slong len, gr_ctx_t ctx) Componentwise operations. (We do not provide analogous division or exponentiation routines due since sparse inputs to these operations would be undefined or fully dense.) -.. function:: int gr_sparse_vec_add_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) - int gr_sparse_vec_sub_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) - int gr_sparse_vec_mul_other(gr_sparse_vec_t res, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_add_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) + int gr_sparse_vec_sub_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) + int gr_sparse_vec_mul_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) Componentwise operations where the second input is allowed to have a different ring. -.. function:: int gr_other_add_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) - int gr_other_sub_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) - int gr_other_mul_sparse_vec(gr_sparse_vec_t res, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +.. function:: int gr_other_add_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) + int gr_other_sub_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) + int gr_other_mul_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) Componentwise operations where the first input is allowed to have a different ring. -.. function:: int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_sparse_vec_submul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) - int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_submul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) Componentwise add and sub mul, with different options for the scalar. @@ -269,24 +269,24 @@ Arithmetic into dense vectors Scalar multiplication and division -------------------------------------------------------------------------------- -.. function:: int gr_sparse_vec_mul_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) - int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) - int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) - int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) - int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) - int gr_sparse_vec_div_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) - int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) - int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) - int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) - int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t res, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t res, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) - int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t res, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) - int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) - int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t res, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) - - Set *res* to be *src* multiplied or divided by *c*. +.. function:: int gr_sparse_vec_mul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) + + Set *dst* to be *src* multiplied or divided by *c*. (Addition and subtraction are not provided because they would create dense output.) From 6b3ed70fe0ffbda6ab018066cbd6ad7d898bf419 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Tue, 19 Mar 2024 15:55:13 -0700 Subject: [PATCH 39/59] More doc fixes --- src/gr_sparse_vec/test/t-conversion.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/gr_sparse_vec/test/t-conversion.c b/src/gr_sparse_vec/test/t-conversion.c index 9b4c498289..084af35792 100644 --- a/src/gr_sparse_vec/test/t-conversion.c +++ b/src/gr_sparse_vec/test/t-conversion.c @@ -38,6 +38,15 @@ test_conversion(flint_rand_t state, gr_ctx_t ctx) if (T_TRUE != _gr_vec_equal(GR_VEC_ENTRY(dvec, 0, sz), GR_VEC_ENTRY(dvec2, 0, sz), N, ctx)) return GR_TEST_FAIL; } + + for (i = 0; i < n_tests; i++) + { + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + status |= gr_vec_set_sparse_vec(GR_VEC_ENTRY(dvec, 0, sz), vec, ctx); + status |= gr_sparse_vec_set_vec(vec2, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); + if (T_TRUE != gr_sparse_vec_equal(vec, vec2, ctx)) + return GR_TEST_FAIL; + } gr_sparse_vec_clear(vec, ctx); gr_vec_clear(dvec, ctx); gr_vec_clear(dvec2, ctx); @@ -46,9 +55,13 @@ test_conversion(flint_rand_t state, gr_ctx_t ctx) TEST_FUNCTION_START(gr_sparse_vec_conversion, state) { + slong i; gr_ctx_t ctx; - gr_ctx_init_random(ctx, state); - CHECK_TEST(test_conversion(state, ctx), "Conversion from and to dense"); - gr_ctx_clear(ctx); + for (i = 0; i < 16; ++i) + { + gr_ctx_init_random(ctx, state); + CHECK_TEST(test_conversion(state, ctx), "Conversion from and to dense"); + gr_ctx_clear(ctx); + } TEST_FUNCTION_END(state); } From 9436272ff94d3988e52a2e0e9abb43cf1d694ecb Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Tue, 19 Mar 2024 17:15:29 -0700 Subject: [PATCH 40/59] Fixed equality and tested scaling --- src/gr_sparse_vec/equal.c | 3 + src/gr_sparse_vec/test/main.c | 2 + src/gr_sparse_vec/test/t-conversion.c | 38 ++++++- src/gr_sparse_vec/test/t-mul_scalar.c | 138 ++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 src/gr_sparse_vec/test/t-mul_scalar.c diff --git a/src/gr_sparse_vec/equal.c b/src/gr_sparse_vec/equal.c index 2a6def343d..77d9d89aec 100644 --- a/src/gr_sparse_vec/equal.c +++ b/src/gr_sparse_vec/equal.c @@ -21,6 +21,7 @@ gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_c return T_FALSE; else ret = T_UNKNOWN; // Have maybe zero vs known zero + i1++; } else if (vec1->inds[i1] > vec2->inds[i2]) { @@ -28,6 +29,7 @@ gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_c return T_FALSE; else ret = T_UNKNOWN; // Have maybe zero vs known zero + i2++; } else { @@ -36,6 +38,7 @@ gr_sparse_vec_equal(const gr_sparse_vec_t vec1, const gr_sparse_vec_t vec2, gr_c return T_FALSE; else if (cur_test == T_UNKNOWN) ret = T_UNKNOWN; + i1++; i2++; } } diff --git a/src/gr_sparse_vec/test/main.c b/src/gr_sparse_vec/test/main.c index 7e6302ee24..941e0d735a 100644 --- a/src/gr_sparse_vec/test/main.c +++ b/src/gr_sparse_vec/test/main.c @@ -6,6 +6,7 @@ #include "t-init.c" #include "t-conversion.c" #include "t-randtest.c" +#include "t-mul_scalar.c" /* Array of test functions ***************************************************/ @@ -14,6 +15,7 @@ test_struct tests[] = TEST_FUNCTION(gr_sparse_vec_init), TEST_FUNCTION(gr_sparse_vec_conversion), TEST_FUNCTION(gr_sparse_vec_randtest), + TEST_FUNCTION(gr_sparse_vec_mul_div_scalar), }; /* main function *************************************************************/ diff --git a/src/gr_sparse_vec/test/t-conversion.c b/src/gr_sparse_vec/test/t-conversion.c index 084af35792..3f69ff2661 100644 --- a/src/gr_sparse_vec/test/t-conversion.c +++ b/src/gr_sparse_vec/test/t-conversion.c @@ -30,24 +30,48 @@ test_conversion(flint_rand_t state, gr_ctx_t ctx) gr_sparse_vec_init(vec, N, ctx); gr_sparse_vec_init(vec2, N, ctx); + //flint_printf("Testing copy\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + status |= gr_sparse_vec_set(vec2, vec, ctx); + if (T_FALSE == gr_sparse_vec_equal(vec, vec2, ctx)) + { + gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + //flint_printf("Testing from/to dense vec\n"); for (i = 0; i < n_tests; i++) { status |= _gr_vec_randtest(GR_VEC_ENTRY(dvec, 0, sz), state, N, ctx); status |= gr_sparse_vec_set_vec(vec, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); status |= gr_vec_set_sparse_vec(GR_VEC_ENTRY(dvec2, 0, sz), vec, ctx); - if (T_TRUE != _gr_vec_equal(GR_VEC_ENTRY(dvec, 0, sz), GR_VEC_ENTRY(dvec2, 0, sz), N, ctx)) + if (T_FALSE == _gr_vec_equal(GR_VEC_ENTRY(dvec, 0, sz), GR_VEC_ENTRY(dvec2, 0, sz), N, ctx)) + { + gr_vec_print(dvec, ctx); flint_printf("\n"); + gr_vec_print(dvec2, ctx); flint_printf("\n"); return GR_TEST_FAIL; + } } + //flint_printf("Testing from/to sparse vec\n"); for (i = 0; i < n_tests; i++) { status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); status |= gr_vec_set_sparse_vec(GR_VEC_ENTRY(dvec, 0, sz), vec, ctx); status |= gr_sparse_vec_set_vec(vec2, GR_VEC_ENTRY(dvec, 0, sz), N, ctx); - if (T_TRUE != gr_sparse_vec_equal(vec, vec2, ctx)) + if (T_FALSE == gr_sparse_vec_equal(vec, vec2, ctx)) + { + gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); return GR_TEST_FAIL; + } } gr_sparse_vec_clear(vec, ctx); + gr_sparse_vec_clear(vec2, ctx); gr_vec_clear(dvec, ctx); gr_vec_clear(dvec2, ctx); return status; @@ -59,7 +83,15 @@ TEST_FUNCTION_START(gr_sparse_vec_conversion, state) gr_ctx_t ctx; for (i = 0; i < 16; ++i) { - gr_ctx_init_random(ctx, state); + while (1) + { + gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_println(ctx); CHECK_TEST(test_conversion(state, ctx), "Conversion from and to dense"); gr_ctx_clear(ctx); } diff --git a/src/gr_sparse_vec/test/t-mul_scalar.c b/src/gr_sparse_vec/test/t-mul_scalar.c new file mode 100644 index 0000000000..ce9d3467f8 --- /dev/null +++ b/src/gr_sparse_vec/test/t-mul_scalar.c @@ -0,0 +1,138 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_vec.h" +#include "fmpz.h" +#include "fmpq.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + + +int +test_mul_scalar(flint_rand_t state, gr_ctx_t ctx) +{ + slong i, c; + ulong uc; + slong N = 100; + slong n_tests = 20; + int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + gr_sparse_vec_t vec, vec2; + gr_ptr dvec, dvec2; + gr_ptr temp; + fmpz_t zc; + fmpq_t qc; + + GR_TMP_INIT(temp, ctx); + fmpz_init(zc); + fmpq_init(qc); + dvec = flint_malloc(N * sz); + dvec2 = flint_malloc(N * sz); + _gr_vec_init(dvec, N, ctx); + _gr_vec_init(dvec2, N, ctx); + gr_sparse_vec_init(vec, N, ctx); + gr_sparse_vec_init(vec2, N, ctx); + + for (i = 0; i < 6 * n_tests; i++) + { + if (i % 6 == 4 && gr_ctx_is_field(ctx) != T_TRUE) + continue; + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + status |= gr_vec_set_sparse_vec(dvec, vec, ctx); + + switch(i % 6) + { + case 0: + //flint_printf("Testing scalar\n"); + status |= gr_randtest_not_zero(temp, state, ctx); + status |= gr_sparse_vec_mul_scalar(vec2, vec, temp, ctx); + status |= _gr_vec_mul_scalar(dvec2, dvec, N, temp, ctx); + break; + case 1: + //flint_printf("Testing scalar_si\n"); + c = n_randint(state, 0); + status |= gr_sparse_vec_mul_scalar_si(vec2, vec, c, ctx); + status |= _gr_vec_mul_scalar_si(dvec2, dvec, N, c, ctx); + break; + case 2: + //flint_printf("Testing scalar_ui\n"); + uc = n_randint(state, 0); + status |= gr_sparse_vec_mul_scalar_ui(vec2, vec, uc, ctx); + status |= _gr_vec_mul_scalar_ui(dvec2, dvec, N, uc, ctx); + break; + case 3: + //flint_printf("Testing scalar_fmpz\n"); + fmpz_randtest_not_zero(zc, state, 32); + status |= gr_sparse_vec_mul_scalar_fmpz(vec2, vec, zc, ctx); + status |= _gr_vec_mul_scalar_fmpz(dvec2, dvec, N, zc, ctx); + break; + case 4: + //flint_printf("Testing scalar_fmpq\n"); + fmpq_randtest_not_zero(qc, state, 32); + //fmpq_print(qc); flint_printf("\n"); + status |= gr_sparse_vec_mul_scalar_fmpq(vec2, vec, qc, ctx); + //_gr_vec_print(dvec, N, ctx); flint_printf("\n"); + status |= _gr_vec_mul_scalar_fmpq(dvec2, dvec, N, qc, ctx); + //_gr_vec_print(dvec2, N, ctx); flint_printf("\n\n\n"); + break; + case 5: + //flint_printf("Testing scalar_2exp_si\n"); + c = n_randint(state, 32) + 1; + status |= gr_sparse_vec_mul_scalar_2exp_si(vec2, vec, c, ctx); + status |= _gr_vec_mul_scalar_2exp_si(dvec2, dvec, N, c, ctx); + break; + } + //gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + //gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); + + status |= gr_vec_set_sparse_vec(dvec, vec2, ctx); + if (T_FALSE == _gr_vec_equal(dvec, dvec2, N, ctx)) + { + _gr_vec_print(dvec, N, ctx); flint_printf("\n"); + _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); + status |= gr_sparse_vec_set_vec(vec, dvec2, N, ctx); + gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + gr_sparse_vec_clear(vec, ctx); + gr_sparse_vec_clear(vec2, ctx); + _gr_vec_clear(dvec, N, ctx); + _gr_vec_clear(dvec2, N, ctx); + flint_free(dvec); + flint_free(dvec2); + GR_TMP_CLEAR(temp, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_vec_mul_div_scalar, state) +{ + slong i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while (1) + { + gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_println(ctx); + CHECK_TEST(test_mul_scalar(state, ctx), "Scalar multiplication and division"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} From 1565c9bcd5ce29db4e0c782749d8496559461b6e Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Wed, 20 Mar 2024 02:39:37 -0700 Subject: [PATCH 41/59] Fixed bug in riffling --- src/gr_sparse_vec.h | 140 ++++++++--------- src/gr_sparse_vec/test/t-mul_scalar.c | 218 +++++++++++++++++++++++--- src/gr_sparse_vec/write.c | 5 +- 3 files changed, 266 insertions(+), 97 deletions(-) diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 422378d9e7..3572672fd7 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -214,12 +214,12 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo has a nonzero element at that index, another function FUNC_B if only B_VEC has a nonzero element, and a third function FUNC_AB if both are nonzero. During this process, we maintain a triple of indices a_nz_idx, b_nz_idx, and - dest_ind, which are used when calling this macro to indicate what element(s) + dest_nz_idx, which are used when calling this macro to indicate what element(s) to refer to when calling the appropriate function. */ #define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ int status; \ - slong sz, new_nnz, a_nz_idx, b_nz_idx, dest_ind, a_nnz, b_nnz, i; \ + slong sz, new_nnz, a_nz_idx, b_nz_idx, dest_nz_idx, a_nnz, b_nnz, i; \ ulong a_ind, b_ind; \ if ((DEST_VEC)->length != (A_VEC)->length || (A_VEC)->length != (B_VEC)->length) \ return GR_DOMAIN; \ @@ -232,41 +232,42 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo /* We go backward through the destination, because it might be an in-place operation on a source */ \ a_nz_idx = a_nnz-1; \ b_nz_idx = b_nnz-1; \ - dest_ind = new_nnz-1; \ - while (a_nz_idx >= 0 && b_nz_idx >= 0 && status == GR_SUCCESS) \ - { \ + dest_nz_idx = new_nnz-1; \ + while (a_nz_idx >= -1 && b_nz_idx >= -1 && status == GR_SUCCESS) \ + { \ + if (a_nz_idx == -1 && b_nz_idx == -1) break; \ a_ind = (A_VEC)->inds[a_nz_idx]; \ b_ind = (B_VEC)->inds[b_nz_idx]; \ - if (a_ind > b_ind) \ + if (b_nz_idx == -1 || (a_nz_idx >= 0 && a_ind > b_ind)) \ { \ status |= (FUNC_A); \ - (DEST_VEC)->inds[dest_ind] = a_ind; \ + (DEST_VEC)->inds[dest_nz_idx] = a_ind; \ a_nz_idx--; \ } \ - else if (b_ind > a_ind) \ + else if (a_nz_idx == -1 || b_ind > a_ind) \ { \ status |= (FUNC_B); \ - (DEST_VEC)->inds[dest_ind] = b_ind; \ + (DEST_VEC)->inds[dest_nz_idx] = b_ind; \ b_nz_idx--; \ } \ else \ { \ status |= (FUNC_AB); \ - (DEST_VEC)->inds[dest_ind] = a_ind; \ + (DEST_VEC)->inds[dest_nz_idx] = a_ind; \ a_nz_idx--; \ b_nz_idx--; \ } \ - if (T_TRUE != gr_is_zero(GR_ENTRY((DEST_VEC)->nzs, dest_ind, sz), (CTX))) \ - dest_ind--; \ + if (T_TRUE != gr_is_zero(GR_ENTRY((DEST_VEC)->nzs, dest_nz_idx, sz), (CTX))) \ + dest_nz_idx--; \ } \ /* Move the result to the beginning of the dest vec */ \ - /* Currently, dest_ind points to one before the start of the legit destination values */ \ - if (dest_ind >= 0 && !status) \ + /* Currently, dest_nz_idx points to one before the start of the legit destination values */ \ + if (dest_nz_idx >= 0 && !status) \ { \ - new_nnz = (new_nnz-1) - dest_ind; \ - dest_ind++; \ + new_nnz = (new_nnz-1) - dest_nz_idx; \ + dest_nz_idx++; \ for (i = 0; i < new_nnz; i++) \ - GR_SPV_SWAP_INDS(DEST_VEC, i, dest_ind + i, sz, CTX); \ + GR_SPV_SWAP_INDS(DEST_VEC, i, dest_nz_idx + i, sz, CTX); \ } \ (DEST_VEC)->nnz = new_nnz; \ return status; @@ -284,14 +285,36 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_negmul_si(gr_ptr dst, gr_srcptr x, slong y, gr_ctx_t ctx) { return (gr_mul_si(dst, x, y, ctx) | gr_neg(dst, dst, ctx)); } +// Need a zero-ary function to assign zero +#define GR_SPV_RFL_ZERO gr_zero(GR_ENTRY(dst->nzs, dest_nz_idx, sz), ctx) + // Convenience macros for applying a unary or binary function -#define GR_SPV_RFL_UOP(F, Y, Y_ind) \ - F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, sz), ctx) -#define GR_SPV_RFL_BOP(F, Y, Y_ind, Z, Z_ind) \ - F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, sz), GR_ENTRY(Z->nzs, Z_ind, sz), ctx) +#define GR_SPV_RFL_UOP(F, DST, DST_IND, SRC, SRC_IND) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC)->nzs, SRC_IND, sz), ctx) +#define GR_SPV_RFL_BOP(F, DST, DST_IND, SRC1, SRC1_IND, SRC2, SRC2_IND) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC1)->nzs, SRC1_IND, sz), GR_ENTRY((SRC2)->nzs, SRC2_IND, sz), ctx) +#define GR_SPV_RFL_BOP_SCALAR(F, DST, DST_IND, SRC, SRC_IND, C, CTX) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC)->nzs, SRC_IND, sz), C, CTX) -// Need a unary function to assign zero -#define GR_SPV_RFL_ZERO gr_zero(GR_ENTRY(dst->nzs, dest_ind, sz), ctx) +// Analogous macros for applying a unary or binary function between two contexts +#define GR_SPV_RFL_UOP_OTHER(F, DST, DST_IND, SRC, SRC_IND, CTX2) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC)->nzs, SRC_IND, (CTX2)->sizeof_elem), CTX2, ctx) +#define GR_SPV_RFL_BOP_OTHER(F, DST, DST_IND, SRC1, SRC1_IND, SRC2, SRC2_IND, CTX2) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC1)->nzs, SRC1_IND, sz), GR_ENTRY((SRC2)->nzs, SRC2_IND, (CTX2)->sizeof_elem), CTX2, ctx) +#define GR_SPV_RFL_OTHER_BOP(F, DST, DST_IND, SRC1, SRC1_IND, CTX2, SRC2, SRC2_IND) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC1)->nzs, SRC1_IND, CTX2->sizeof_elem), (CTX2), GR_ENTRY((SRC2)->nzs, SRC2_IND, sz), ctx) + +/* + Subtemplate for doing accumulated operation from one sparse vector into another. + Used to do dst += c * src and dst -= c * src, for c a scalar. +*/ +#define GR_SPV_ACCUM_TEMPLATE(ELEM_OP, ELEM_ACCUM_OP, DST, SRC, C, CTX) \ + GR_SPV_RFL_TEMPLATE( \ + GR_SPV_RFL_UOP(gr_set, DST, dest_nz_idx, DST, a_nz_idx), \ + GR_SPV_RFL_BOP_SCALAR(ELEM_OP, DST, dest_nz_idx, SRC, b_nz_idx, C, CTX), \ + GR_SPV_RFL_UOP(gr_set, DST, dest_nz_idx, DST, a_nz_idx) | GR_SPV_RFL_BOP_SCALAR(ELEM_ACCUM_OP, DST, dest_nz_idx, SRC, b_nz_idx, C, CTX), \ + DST, DST, SRC, CTX\ + ) GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_neg(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) @@ -301,9 +324,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, dst, a_nz_idx), - GR_SPV_RFL_UOP(gr_set, src, b_nz_idx), - GR_SPV_RFL_UOP(gr_set, src, b_nz_idx), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, dst, a_nz_idx), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src, b_nz_idx), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src, b_nz_idx), dst, dst, src, ctx ); } @@ -312,9 +335,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_nz_idx), - GR_SPV_RFL_UOP(gr_set, src2, b_nz_idx), - GR_SPV_RFL_BOP(gr_add, src1, a_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_BOP(gr_add, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx), dst, src1, src2, ctx ); } @@ -323,9 +346,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_nz_idx), - GR_SPV_RFL_UOP(gr_neg, src2, b_nz_idx), - GR_SPV_RFL_BOP(gr_sub, src1, a_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), + GR_SPV_RFL_UOP(gr_neg, dst, dest_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_BOP(gr_sub, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx), dst, src1, src2, ctx ); } @@ -336,26 +359,18 @@ gr_sparse_vec_mul(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_spar GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, - GR_SPV_RFL_BOP(gr_mul, src1, a_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_BOP(gr_mul, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx), dst, src1, src2, ctx ); } -// Analogous macros for applying a unary or binary function between two contexts -#define GR_SPV_RFL_UOP_OTHER(F, Y, Y_ind, CTX2) \ - F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, CTX2->sizeof_elem), CTX2, ctx) -#define GR_SPV_RFL_BOP_OTHER(F, Y, Y_ind, Z, Z_ind, CTX2) \ - F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, sz), GR_ENTRY(Z->nzs, Z_ind, CTX2->sizeof_elem), CTX2, ctx) -#define GR_SPV_RFL_OTHER_BOP(F, Y, Y_ind, CTX2, Z, Z_ind) \ - F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, CTX2->sizeof_elem), (CTX2), GR_ENTRY(Z->nzs, Z_ind, sz), ctx) - GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_nz_idx), - GR_SPV_RFL_UOP_OTHER(gr_set_other, src2, b_nz_idx, ctx2), - GR_SPV_RFL_BOP_OTHER(gr_add_other, src1, a_nz_idx, src2, b_nz_idx, ctx2), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), + GR_SPV_RFL_UOP_OTHER(gr_set_other, dst, dest_nz_idx, src2, b_nz_idx, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_add_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), dst, src1, src2, ctx ); } @@ -364,9 +379,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, src1, a_nz_idx), - GR_SPV_RFL_UOP_OTHER(gr_neg_other, src2, a_nz_idx, ctx2), - GR_SPV_RFL_BOP_OTHER(gr_sub_other, src1, a_nz_idx, src2, b_nz_idx, ctx2), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), + GR_SPV_RFL_UOP_OTHER(gr_neg_other, dst, dest_nz_idx, src2, a_nz_idx, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_sub_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), dst, src1, src2, ctx ); } @@ -377,7 +392,7 @@ gr_sparse_vec_mul_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const g GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, - GR_SPV_RFL_BOP_OTHER(gr_mul_other, src1, a_nz_idx, src2, b_nz_idx, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_mul_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), dst, src1, src2, ctx ); } @@ -386,9 +401,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_add_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_nz_idx, ctx1), - GR_SPV_RFL_UOP(gr_set, src2, b_nz_idx), - GR_SPV_RFL_OTHER_BOP(gr_other_add, src1, a_nz_idx, ctx1, src2, b_nz_idx), + GR_SPV_RFL_UOP_OTHER(gr_set_other, dst, dest_nz_idx, src1, a_nz_idx, ctx1), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_OTHER_BOP(gr_other_add, dst, dest_nz_idx, src1, a_nz_idx, ctx1, src2, b_nz_idx), dst, src1, src2, ctx ); } @@ -397,9 +412,9 @@ GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_other_sub_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) { GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP_OTHER(gr_set_other, src1, a_nz_idx, ctx1), - GR_SPV_RFL_UOP(gr_neg, src2, b_nz_idx), - GR_SPV_RFL_OTHER_BOP(gr_other_sub, src1, a_nz_idx, ctx1, src2, b_nz_idx), + GR_SPV_RFL_UOP_OTHER(gr_set_other, dst, dest_nz_idx, src1, a_nz_idx, ctx1), + GR_SPV_RFL_UOP(gr_neg, dst, dest_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_OTHER_BOP(gr_other_sub, dst, dest_nz_idx, src1, a_nz_idx, ctx1, src2, b_nz_idx), dst, src1, src2, ctx ); } @@ -410,26 +425,11 @@ gr_other_mul_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_ GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_ZERO, GR_SPV_RFL_ZERO, - GR_SPV_RFL_OTHER_BOP(gr_other_mul, src1, a_nz_idx, ctx1, src2, b_nz_idx), + GR_SPV_RFL_OTHER_BOP(gr_other_mul, dst, dest_nz_idx, src1, a_nz_idx, ctx1, src2, b_nz_idx), dst, src1, src2, ctx ); } -#define GR_SPV_RFL_UOP_SCALAR(F, Y, Y_ind, C, CTX) \ - F(GR_ENTRY(dst->nzs, dest_ind, sz), GR_ENTRY(Y->nzs, Y_ind, sz), C, CTX) - -/* - Subtemplate for doing accumulated operation from one sparse vector into another. - Used to do dst += c * src and dst -= c * src, for c a scalar. -*/ -#define GR_SPV_ACCUM_TEMPLATE(ELEM_OP, ELEM_ACCUM_OP, RES, SRC, C, CTX) \ - GR_SPV_RFL_TEMPLATE( \ - GR_SPV_RFL_UOP(gr_set, RES, a_nz_idx), \ - GR_SPV_RFL_UOP_SCALAR(ELEM_OP, SRC, b_nz_idx, C, CTX), \ - GR_SPV_RFL_UOP_SCALAR(ELEM_ACCUM_OP, SRC, b_nz_idx, C, CTX), \ - RES, RES, SRC, CTX\ - ) - GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) { GR_SPV_ACCUM_TEMPLATE(gr_mul, gr_addmul, dst, src, c, ctx) } diff --git a/src/gr_sparse_vec/test/t-mul_scalar.c b/src/gr_sparse_vec/test/t-mul_scalar.c index ce9d3467f8..422c4b59a0 100644 --- a/src/gr_sparse_vec/test/t-mul_scalar.c +++ b/src/gr_sparse_vec/test/t-mul_scalar.c @@ -15,12 +15,156 @@ #include "fmpq.h" #define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } +int + +#define TEST_ACCUM_MUL_SCALAR(STATUS, K, L, TYPE, VEC, VEC2, DVEC, DVEC2, DVEC3, C, CTX) { \ + if (K == 0) \ + { \ + if (L == 0) \ + { \ + STATUS |= gr_sparse_vec_addmul_##TYPE(VEC, VEC2, C, CTX); \ + STATUS |= _gr_vec_addmul_##TYPE(DVEC, DVEC2, N, C, CTX); \ + } \ + else \ + { \ + STATUS |= gr_sparse_vec_submul_##TYPE(VEC, VEC2, C, CTX); \ + STATUS |= _gr_vec_submul_##TYPE(DVEC, DVEC2, N, C, CTX); \ + } \ + } \ + else \ + { \ + if (L == 0) \ + { \ + status |= gr_vec_addmul_sparse_vec_##TYPE(DVEC, VEC, C, CTX); \ + status |= _gr_vec_addmul_##TYPE(DVEC2, DVEC3, N, C, CTX); \ + } \ + else \ + { \ + status |= gr_vec_submul_sparse_vec_##TYPE(DVEC, VEC, C, CTX); \ + status |= _gr_vec_submul_##TYPE(DVEC2, DVEC3, N, C, CTX); \ + } \ + } \ +} + +test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) +{ + slong i, j, k, l, c; + slong N = 20; + slong n_tests = 20; + int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + gr_sparse_vec_t vec, vec2; + gr_ptr dvec, dvec2, dvec3; + gr_ptr temp; + truth_t eq; + + GR_TMP_INIT(temp, ctx); + dvec = flint_malloc(N * sz); + dvec2 = flint_malloc(N * sz); + dvec3 = flint_malloc(N * sz); + _gr_vec_init(dvec, N, ctx); + _gr_vec_init(dvec2, N, ctx); + _gr_vec_init(dvec3, N, ctx); + gr_sparse_vec_init(vec, N, ctx); + gr_sparse_vec_init(vec2, N, ctx); + + for (i = 0; i < 8 * n_tests; i++) + { + j = i % 2; // Which type of scalar + k = (i / 2) % 2; // Into sparse or dense + l = (i / 4) % 2; // Add or subtract + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + + if (k == 0) + { + status |= gr_vec_set_sparse_vec(dvec, vec, ctx); + status |= gr_sparse_vec_randtest(vec2, 10, 0, state, ctx); + status |= gr_vec_set_sparse_vec(dvec2, vec2, ctx); + } + else + { + status |= _gr_vec_randtest(dvec, state, N, ctx); + status |= _gr_vec_set(dvec2, dvec, N, ctx); + status |= gr_vec_set_sparse_vec(dvec3, vec, ctx); + } + //flint_printf("\nBefore:\n"); + //flint_printf("\nvec = "); gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + //flint_printf("\nvec2 = "); gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); + //flint_printf("\ndvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); + //flint_printf("\ndvec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); + + switch(j) + { + case 0: + status |= gr_randtest_not_zero(temp, state, ctx); + //flint_printf("\nc = "); gr_println(temp, ctx); flint_printf("\n"); + TEST_ACCUM_MUL_SCALAR(status, k, l, scalar, vec, vec2, dvec, dvec2, dvec3, temp, ctx) + break; + case 1: + //flint_printf("Testing scalar_si\n"); + c = n_randint(state, 0); + TEST_ACCUM_MUL_SCALAR(status, k, l, scalar_si, vec, vec2, dvec, dvec2, dvec3, c, ctx) + break; + } + //flint_printf("\nAfter:\n"); + //flint_printf("\nvec = "); gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + gr_sparse_vec_set_vec(vec2, dvec, N, ctx); + //flint_printf("\nvec2 = "); gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); + //flint_printf("\ndvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); + //flint_printf("\ndvec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); + + if (k == 0) + status |= gr_vec_set_sparse_vec(dvec2, vec, ctx); + eq = _gr_vec_equal(dvec, dvec2, N, ctx); + if (eq == T_FALSE || status != GR_SUCCESS) + { + flint_printf( + "\ni = %d, j = %d, k = %d, l = %d, equal = %d, status = %d\n", + i, j, k, l, eq, status + ); + gr_ctx_println(ctx); + flint_printf("dvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); + flint_printf("dvec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + gr_sparse_vec_clear(vec, ctx); + gr_sparse_vec_clear(vec2, ctx); + _gr_vec_clear(dvec, N, ctx); + _gr_vec_clear(dvec2, N, ctx); + _gr_vec_clear(dvec3, N, ctx); + flint_free(dvec); + flint_free(dvec2); + flint_free(dvec3); + GR_TMP_CLEAR(temp, ctx); + return status; +} + + +#define TEST_MUL_SCALAR(STATUS, K, TYPE, VEC, VEC2, DVEC, DVEC2, C, CTX) { \ + if (K == 1) \ + { \ + STATUS |= gr_sparse_vec_div_##TYPE(VEC2, VEC, C, CTX); \ + STATUS |= _gr_vec_div_##TYPE(DVEC2, DVEC, N, C, CTX); \ + } \ + else \ + { \ + STATUS |= gr_sparse_vec_mul_##TYPE(VEC2, VEC, C, CTX); \ + STATUS |= _gr_vec_mul_##TYPE(DVEC2, DVEC, N, C, CTX); \ + if (K == 2) \ + { \ + STATUS |= gr_sparse_vec_divexact_##TYPE(VEC2, VEC, C, CTX); \ + STATUS |= _gr_vec_divexact_##TYPE(DVEC2, DVEC, N, C, CTX); \ + } \ + } \ +} int -test_mul_scalar(flint_rand_t state, gr_ctx_t ctx) +test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) { - slong i, c; + slong i, j, k, c; ulong uc; slong N = 100; slong n_tests = 20; @@ -31,6 +175,7 @@ test_mul_scalar(flint_rand_t state, gr_ctx_t ctx) gr_ptr temp; fmpz_t zc; fmpq_t qc; + truth_t eq; GR_TMP_INIT(temp, ctx); fmpz_init(zc); @@ -42,61 +187,76 @@ test_mul_scalar(flint_rand_t state, gr_ctx_t ctx) gr_sparse_vec_init(vec, N, ctx); gr_sparse_vec_init(vec2, N, ctx); - for (i = 0; i < 6 * n_tests; i++) + for (i = 0; i < 18 * n_tests; i++) { - if (i % 6 == 4 && gr_ctx_is_field(ctx) != T_TRUE) + j = i % 6; // Which type of scalar + k = (i / 6) % 3; // Mul, div, or mul + divexact + if ((j == 4 || k == 1) && gr_ctx_is_field(ctx) != T_TRUE) + continue; + if (k == 2 && gr_ctx_is_integral_domain(ctx) != T_TRUE) continue; status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); status |= gr_vec_set_sparse_vec(dvec, vec, ctx); - switch(i % 6) + switch(j) { case 0: //flint_printf("Testing scalar\n"); status |= gr_randtest_not_zero(temp, state, ctx); - status |= gr_sparse_vec_mul_scalar(vec2, vec, temp, ctx); - status |= _gr_vec_mul_scalar(dvec2, dvec, N, temp, ctx); + TEST_MUL_SCALAR(status, k, scalar, vec, vec2, dvec, dvec2, temp, ctx) break; case 1: //flint_printf("Testing scalar_si\n"); c = n_randint(state, 0); - status |= gr_sparse_vec_mul_scalar_si(vec2, vec, c, ctx); - status |= _gr_vec_mul_scalar_si(dvec2, dvec, N, c, ctx); + TEST_MUL_SCALAR(status, k, scalar_si, vec, vec2, dvec, dvec2, c, ctx) break; case 2: //flint_printf("Testing scalar_ui\n"); uc = n_randint(state, 0); - status |= gr_sparse_vec_mul_scalar_ui(vec2, vec, uc, ctx); - status |= _gr_vec_mul_scalar_ui(dvec2, dvec, N, uc, ctx); + TEST_MUL_SCALAR(status, k, scalar_ui, vec, vec2, dvec, dvec2, uc, ctx) break; case 3: //flint_printf("Testing scalar_fmpz\n"); fmpz_randtest_not_zero(zc, state, 32); - status |= gr_sparse_vec_mul_scalar_fmpz(vec2, vec, zc, ctx); - status |= _gr_vec_mul_scalar_fmpz(dvec2, dvec, N, zc, ctx); + TEST_MUL_SCALAR(status, k, scalar_fmpz, vec, vec2, dvec, dvec2, zc, ctx) break; case 4: //flint_printf("Testing scalar_fmpq\n"); fmpq_randtest_not_zero(qc, state, 32); - //fmpq_print(qc); flint_printf("\n"); - status |= gr_sparse_vec_mul_scalar_fmpq(vec2, vec, qc, ctx); - //_gr_vec_print(dvec, N, ctx); flint_printf("\n"); - status |= _gr_vec_mul_scalar_fmpq(dvec2, dvec, N, qc, ctx); - //_gr_vec_print(dvec2, N, ctx); flint_printf("\n\n\n"); - break; + TEST_MUL_SCALAR(status, k, scalar_fmpq, vec, vec2, dvec, dvec2, qc, ctx) + break; case 5: //flint_printf("Testing scalar_2exp_si\n"); c = n_randint(state, 32) + 1; - status |= gr_sparse_vec_mul_scalar_2exp_si(vec2, vec, c, ctx); - status |= _gr_vec_mul_scalar_2exp_si(dvec2, dvec, N, c, ctx); + if (k == 1) + { + status |= gr_sparse_vec_mul_scalar_2exp_si(vec2, vec, -c, ctx); + status |= _gr_vec_mul_scalar_2exp_si(dvec2, dvec, N, -c, ctx); + } + else + { + status |= gr_sparse_vec_mul_scalar_2exp_si(vec2, vec, c, ctx); + status |= _gr_vec_mul_scalar_2exp_si(dvec2, dvec, N, c, ctx); + if (k == 2) + { + status |= gr_sparse_vec_mul_scalar_2exp_si(vec2, vec2, -c, ctx); + status |= _gr_vec_mul_scalar_2exp_si(dvec2, dvec2, N, -c, ctx); + } + } break; } //gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); //gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); status |= gr_vec_set_sparse_vec(dvec, vec2, ctx); - if (T_FALSE == _gr_vec_equal(dvec, dvec2, N, ctx)) + eq = _gr_vec_equal(dvec, dvec2, N, ctx); + if (eq == T_FALSE || status != GR_SUCCESS) { + flint_printf( + "j = %d, k = %d, equal = %d, status = %d\n", + j, k, eq, status + ); + gr_ctx_println(ctx); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); status |= gr_sparse_vec_set_vec(vec, dvec2, N, ctx); @@ -112,6 +272,8 @@ test_mul_scalar(flint_rand_t state, gr_ctx_t ctx) _gr_vec_clear(dvec2, N, ctx); flint_free(dvec); flint_free(dvec2); + fmpz_clear(zc); + fmpq_clear(qc); GR_TMP_CLEAR(temp, ctx); return status; } @@ -124,15 +286,23 @@ TEST_FUNCTION_START(gr_sparse_vec_mul_div_scalar, state) { while (1) { + //gr_ctx_init_fmpz(ctx); gr_ctx_init_random(ctx, state); if (gr_ctx_is_zero_ring(ctx) == T_TRUE) gr_ctx_clear(ctx); else break; } - //gr_ctx_println(ctx); - CHECK_TEST(test_mul_scalar(state, ctx), "Scalar multiplication and division"); + CHECK_TEST(test_accum_mul_scalar(state, ctx), "Scalar accumulation into sparse and dense"); + CHECK_TEST(test_mul_div_scalar(state, ctx), "Scalar multiplication and division"); gr_ctx_clear(ctx); } TEST_FUNCTION_END(state); } + +// vec = [ +// 8: [0.0729740542394905489231860002370251 +/- 4.22e-35], +// 8: [-1.565059542762220528273371476451385e+59 +/- 5.02e+25], +// 84: [2.138150592348574067073082771877590e-50 +/- 4.83e-84], +// 84: [0.4375000000000000000000000000000000 +/- 2.41e-35], +// ] diff --git a/src/gr_sparse_vec/write.c b/src/gr_sparse_vec/write.c index 09ef401ef1..0e98faa673 100644 --- a/src/gr_sparse_vec/write.c +++ b/src/gr_sparse_vec/write.c @@ -10,13 +10,14 @@ gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) gr_stream_write(out, "["); for (i = 0; i < nnz; i++) { + gr_stream_write(out, "\n\t"); gr_stream_write_si(out, vec->inds[i]); gr_stream_write(out, ": "); status |= gr_write(out, GR_ENTRY(vec->nzs, i, sz), ctx); if (i < nnz - 1) gr_stream_write(out, ", "); } - gr_stream_write(out, "]"); + gr_stream_write(out, "\n]"); return status; } @@ -26,5 +27,3 @@ int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx) gr_stream_init_file(out, stdout); return gr_sparse_vec_write_nz(out, vec, ctx); } - - From 6eb88f738fb9d3ae563757a8a941184d6291bd67 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Wed, 20 Mar 2024 04:32:22 -0700 Subject: [PATCH 42/59] Fixed other testing --- src/gr_sparse_vec.h | 6 +- src/gr_sparse_vec/test/t-mul_scalar.c | 133 ++++++++++++++++++++++---- 2 files changed, 119 insertions(+), 20 deletions(-) diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 3572672fd7..bca1c298bb 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -233,8 +233,8 @@ slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulo a_nz_idx = a_nnz-1; \ b_nz_idx = b_nnz-1; \ dest_nz_idx = new_nnz-1; \ - while (a_nz_idx >= -1 && b_nz_idx >= -1 && status == GR_SUCCESS) \ - { \ + while (a_nz_idx >= -1 && b_nz_idx >= -1 && status == GR_SUCCESS) \ + { \ if (a_nz_idx == -1 && b_nz_idx == -1) break; \ a_ind = (A_VEC)->inds[a_nz_idx]; \ b_ind = (B_VEC)->inds[b_nz_idx]; \ @@ -380,7 +380,7 @@ gr_sparse_vec_sub_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const g { GR_SPV_RFL_TEMPLATE( GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), - GR_SPV_RFL_UOP_OTHER(gr_neg_other, dst, dest_nz_idx, src2, a_nz_idx, ctx2), + GR_SPV_RFL_UOP_OTHER(gr_neg_other, dst, dest_nz_idx, src2, b_nz_idx, ctx2), GR_SPV_RFL_BOP_OTHER(gr_sub_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), dst, src1, src2, ctx ); diff --git a/src/gr_sparse_vec/test/t-mul_scalar.c b/src/gr_sparse_vec/test/t-mul_scalar.c index 422c4b59a0..9ad139d55d 100644 --- a/src/gr_sparse_vec/test/t-mul_scalar.c +++ b/src/gr_sparse_vec/test/t-mul_scalar.c @@ -48,43 +48,70 @@ int test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) { - slong i, j, k, l, c; + slong i, j, k, l, m, c; slong N = 20; slong n_tests = 20; - int status = GR_SUCCESS; + int status; slong sz = ctx->sizeof_elem; - gr_sparse_vec_t vec, vec2; - gr_ptr dvec, dvec2, dvec3; + gr_sparse_vec_t vec, vec2, vec3; + gr_ptr dvec, dvec2, dvec3, dvec4; gr_ptr temp; + gr_ctx_t ctx2; truth_t eq; + gr_ctx_init_fmpz(ctx2); GR_TMP_INIT(temp, ctx); dvec = flint_malloc(N * sz); dvec2 = flint_malloc(N * sz); dvec3 = flint_malloc(N * sz); + dvec4 = flint_malloc(N * ctx2->sizeof_elem); _gr_vec_init(dvec, N, ctx); _gr_vec_init(dvec2, N, ctx); _gr_vec_init(dvec3, N, ctx); + _gr_vec_init(dvec4, N, ctx2); gr_sparse_vec_init(vec, N, ctx); gr_sparse_vec_init(vec2, N, ctx); + gr_sparse_vec_init(vec3, N, ctx2); - for (i = 0; i < 8 * n_tests; i++) + for (i = 0; i < 36 * n_tests; i++) { - j = i % 2; // Which type of scalar - k = (i / 2) % 2; // Into sparse or dense - l = (i / 4) % 2; // Add or subtract - status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + status = GR_SUCCESS; + //flint_printf("%d\n", i); + j = i % 3; // Which type of scalar + k = (i / 3) % 2; // Into sparse or dense + l = (i / 6) % 2; // Add or subtract + m = (i / 12) % 3; // For plain add/subtract, also check other ctx usage + if ((j > 0 || k > 0) && m > 0) continue; + //flint_printf("Setting up vectors\n"); + //flint_printf("\tRandomizing vec\n"); + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); if (k == 0) { + //flint_printf("\tCopying vec into dvec\n"); status |= gr_vec_set_sparse_vec(dvec, vec, ctx); - status |= gr_sparse_vec_randtest(vec2, 10, 0, state, ctx); - status |= gr_vec_set_sparse_vec(dvec2, vec2, ctx); + if (m > 0) + { + //flint_printf("\tRandomizing vec3\n"); + status |= gr_sparse_vec_randtest(vec3, 10, 0, state, ctx2); + //flint_printf("\tCopying vec3 into dvec4\n"); + status |= gr_vec_set_sparse_vec(dvec4, vec3, ctx2); + } + else + { + //flint_printf("\tRandomizing vec2\n"); + status |= gr_sparse_vec_randtest(vec2, 10, 0, state, ctx); + //flint_printf("\tCopying vec2 into dvec2\n"); + status |= gr_vec_set_sparse_vec(dvec2, vec2, ctx); + } } else { + //flint_printf("\tRandomizing dvec\n"); status |= _gr_vec_randtest(dvec, state, N, ctx); + //flint_printf("\tCopying dvec into dvec2\n"); status |= _gr_vec_set(dvec2, dvec, N, ctx); + //flint_printf("\tCopying vec into dvec3\n"); status |= gr_vec_set_sparse_vec(dvec3, vec, ctx); } //flint_printf("\nBefore:\n"); @@ -93,26 +120,88 @@ test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) //flint_printf("\ndvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); //flint_printf("\ndvec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); + //flint_printf("Doing op\n"); switch(j) { case 0: + // Scalar = 1 => add or sub + if (k == 0) + { + if (m == 0) + { + if (l == 0) + { + status |= gr_sparse_vec_add(vec, vec, vec2, ctx); + status |= _gr_vec_add(dvec, dvec, dvec2, N, ctx); + } + else + { + status |= gr_sparse_vec_sub(vec, vec, vec2, ctx); + status |= _gr_vec_sub(dvec, dvec, dvec2, N, ctx); + } + } + else if (m == 1) + { + if (l == 0) + { + status |= gr_sparse_vec_add_other(vec, vec, vec3, ctx2, ctx); + status |= _gr_vec_add_other(dvec, dvec, dvec4, ctx2, N, ctx); + } + else + { + status |= gr_sparse_vec_sub_other(vec, vec, vec3, ctx2, ctx); + status |= _gr_vec_sub_other(dvec, dvec, dvec4, ctx2, N, ctx); + } + } + else + { + if (l == 0) + { + status |= gr_other_add_sparse_vec(vec, vec3, ctx2, vec, ctx); + status |= _gr_other_add_vec(dvec, dvec4, ctx2, dvec, N, ctx); + } + else + { + status |= gr_other_sub_sparse_vec(vec, vec3, ctx2, vec, ctx); + status |= _gr_other_sub_vec(dvec, dvec4, ctx2, dvec, N, ctx); + } + } + } + else + { + if (l == 0) + { + status |= gr_vec_add_sparse_vec(dvec, dvec, vec, ctx); + status |= _gr_vec_add(dvec2, dvec2, dvec3, N, ctx); + } + else + { + status |= gr_vec_sub_sparse_vec(dvec, dvec, vec, ctx); + status |= _gr_vec_sub(dvec2, dvec2, dvec3, N, ctx); + } + } + break; + case 1: status |= gr_randtest_not_zero(temp, state, ctx); //flint_printf("\nc = "); gr_println(temp, ctx); flint_printf("\n"); TEST_ACCUM_MUL_SCALAR(status, k, l, scalar, vec, vec2, dvec, dvec2, dvec3, temp, ctx) break; - case 1: + case 2: //flint_printf("Testing scalar_si\n"); c = n_randint(state, 0); TEST_ACCUM_MUL_SCALAR(status, k, l, scalar_si, vec, vec2, dvec, dvec2, dvec3, c, ctx) break; } + //flint_printf("Checking\n"); //flint_printf("\nAfter:\n"); //flint_printf("\nvec = "); gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); - gr_sparse_vec_set_vec(vec2, dvec, N, ctx); + //status |= gr_sparse_vec_set_vec(vec2, dvec, N, ctx); //flint_printf("\nvec2 = "); gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); //flint_printf("\ndvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); //flint_printf("\ndvec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); - + if (status == GR_UNABLE) + continue; + if (k == 0) status |= gr_vec_set_sparse_vec(dvec2, vec, ctx); @@ -120,8 +209,8 @@ test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) if (eq == T_FALSE || status != GR_SUCCESS) { flint_printf( - "\ni = %d, j = %d, k = %d, l = %d, equal = %d, status = %d\n", - i, j, k, l, eq, status + "\ni = %d, j = %d, k = %d, l = %d, m = %d, equal = %d, status = %d\n", + i, j, k, l, m, eq, status ); gr_ctx_println(ctx); flint_printf("dvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); @@ -132,13 +221,17 @@ test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) gr_sparse_vec_clear(vec, ctx); gr_sparse_vec_clear(vec2, ctx); + gr_sparse_vec_clear(vec3, ctx2); _gr_vec_clear(dvec, N, ctx); _gr_vec_clear(dvec2, N, ctx); _gr_vec_clear(dvec3, N, ctx); + _gr_vec_clear(dvec4, N, ctx2); flint_free(dvec); flint_free(dvec2); flint_free(dvec3); + flint_free(dvec4); GR_TMP_CLEAR(temp, ctx); + gr_ctx_clear(ctx2); return status; } @@ -168,7 +261,7 @@ test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) ulong uc; slong N = 100; slong n_tests = 20; - int status = GR_SUCCESS; + int status; slong sz = ctx->sizeof_elem; gr_sparse_vec_t vec, vec2; gr_ptr dvec, dvec2; @@ -245,6 +338,12 @@ test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) } break; } + // If any operation not allowed, just skip test + if (status == GR_UNABLE) + { + status = GR_SUCCESS; + continue; + } //gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); //gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); From 1a49b2d7982f701a8e3e89e9b2df3a2c6797b4cd Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Wed, 20 Mar 2024 07:19:13 -0700 Subject: [PATCH 43/59] Weakened test because of ring compatibility issues, decent coverage now --- src/gr_sparse_vec.h | 496 ++---------------- src/gr_sparse_vec/arith.c | 397 ++++++++++++++ src/gr_sparse_vec/test/main.c | 10 +- .../test/{t-mul_scalar.c => t-arith.c} | 342 ++++++------ 4 files changed, 640 insertions(+), 605 deletions(-) create mode 100644 src/gr_sparse_vec/arith.c rename src/gr_sparse_vec/test/{t-mul_scalar.c => t-arith.c} (61%) diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index bca1c298bb..168fa62f24 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -157,11 +157,12 @@ GR_SPARSE_VEC_INLINE void gr_sparse_vec_swap(gr_sparse_vec_t vec1, gr_sparse_vec FLINT_SWAP(ulong *, vec1->inds, vec2->inds); FLINT_SWAP(slong, vec1->length, vec2->length); FLINT_SWAP(slong, vec1->nnz, vec2->nnz); - } + GR_SPARSE_VEC_INLINE void gr_sparse_vec_zero(gr_sparse_vec_t vec, gr_ctx_t ctx) { vec->nnz = 0; } + GR_SPARSE_VEC_INLINE int gr_sparse_vec_one(gr_sparse_vec_t vec, slong ind, gr_ctx_t ctx) { @@ -197,410 +198,66 @@ int gr_sparse_vec_print_nz(const gr_sparse_vec_t vec, gr_ctx_t ctx); // Internal function to count the union of indicies in inds0 and inds1 slong _gr_sparse_vec_count_unique_inds(const ulong *inds0, slong nnz0, const ulong *inds1, slong nnz1); -// Internal macro to swap two entries with their associated indices -#define GR_SPV_SWAP_INDS(VEC, I, J, SZ, CTX) \ -{ \ - slong _temp = (VEC)->inds[I]; \ - (VEC)->inds[I] = (VEC)->inds[J]; \ - (VEC)->inds[J] = _temp; \ - gr_swap(GR_ENTRY((VEC)->nzs, (I), (SZ)), GR_ENTRY((VEC)->nzs, (J), (SZ)), (CTX)); \ -} - -/* - Binary arithmetic operations on sparse vectors have a common pattern of - riffling through the two input vectors A_VEC and B_VEC to produce an - output vector DEST_VEC with indices in sorted order. As the iteration - proceeds, for a given index, we need one function FUNC_A if only A_VEC - has a nonzero element at that index, another function FUNC_B if only - B_VEC has a nonzero element, and a third function FUNC_AB if both are nonzero. - During this process, we maintain a triple of indices a_nz_idx, b_nz_idx, and - dest_nz_idx, which are used when calling this macro to indicate what element(s) - to refer to when calling the appropriate function. -*/ -#define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ - int status; \ - slong sz, new_nnz, a_nz_idx, b_nz_idx, dest_nz_idx, a_nnz, b_nnz, i; \ - ulong a_ind, b_ind; \ - if ((DEST_VEC)->length != (A_VEC)->length || (A_VEC)->length != (B_VEC)->length) \ - return GR_DOMAIN; \ - status = GR_SUCCESS; \ - sz = (CTX)->sizeof_elem; \ - a_nnz = (A_VEC)->nnz; \ - b_nnz = (B_VEC)->nnz; \ - new_nnz = _gr_sparse_vec_count_unique_inds((A_VEC)->inds, a_nnz, (B_VEC)->inds, b_nnz); \ - gr_sparse_vec_fit_nnz((DEST_VEC), new_nnz, (CTX)); \ - /* We go backward through the destination, because it might be an in-place operation on a source */ \ - a_nz_idx = a_nnz-1; \ - b_nz_idx = b_nnz-1; \ - dest_nz_idx = new_nnz-1; \ - while (a_nz_idx >= -1 && b_nz_idx >= -1 && status == GR_SUCCESS) \ - { \ - if (a_nz_idx == -1 && b_nz_idx == -1) break; \ - a_ind = (A_VEC)->inds[a_nz_idx]; \ - b_ind = (B_VEC)->inds[b_nz_idx]; \ - if (b_nz_idx == -1 || (a_nz_idx >= 0 && a_ind > b_ind)) \ - { \ - status |= (FUNC_A); \ - (DEST_VEC)->inds[dest_nz_idx] = a_ind; \ - a_nz_idx--; \ - } \ - else if (a_nz_idx == -1 || b_ind > a_ind) \ - { \ - status |= (FUNC_B); \ - (DEST_VEC)->inds[dest_nz_idx] = b_ind; \ - b_nz_idx--; \ - } \ - else \ - { \ - status |= (FUNC_AB); \ - (DEST_VEC)->inds[dest_nz_idx] = a_ind; \ - a_nz_idx--; \ - b_nz_idx--; \ - } \ - if (T_TRUE != gr_is_zero(GR_ENTRY((DEST_VEC)->nzs, dest_nz_idx, sz), (CTX))) \ - dest_nz_idx--; \ - } \ - /* Move the result to the beginning of the dest vec */ \ - /* Currently, dest_nz_idx points to one before the start of the legit destination values */ \ - if (dest_nz_idx >= 0 && !status) \ - { \ - new_nnz = (new_nnz-1) - dest_nz_idx; \ - dest_nz_idx++; \ - for (i = 0; i < new_nnz; i++) \ - GR_SPV_SWAP_INDS(DEST_VEC, i, dest_nz_idx + i, sz, CTX); \ - } \ - (DEST_VEC)->nnz = new_nnz; \ - return status; - -/* We need some convenience functions for certain simple operations. */ -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_neg_other(gr_ptr dst, gr_srcptr src, gr_ctx_t src_ctx, gr_ctx_t ctx) -{ return (gr_set_other(dst, src, src_ctx, ctx) | gr_neg(dst, dst, ctx)); } +WARN_UNUSED_RESULT int gr_sparse_vec_neg(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_negmul(gr_ptr dst, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) -{ return (gr_mul(dst, x, y, ctx) | gr_neg(dst, dst, ctx)); } +WARN_UNUSED_RESULT int gr_sparse_vec_update(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_negmul_si(gr_ptr dst, gr_srcptr x, slong y, gr_ctx_t ctx) -{ return (gr_mul_si(dst, x, y, ctx) | gr_neg(dst, dst, ctx)); } - -// Need a zero-ary function to assign zero -#define GR_SPV_RFL_ZERO gr_zero(GR_ENTRY(dst->nzs, dest_nz_idx, sz), ctx) - -// Convenience macros for applying a unary or binary function -#define GR_SPV_RFL_UOP(F, DST, DST_IND, SRC, SRC_IND) \ - F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC)->nzs, SRC_IND, sz), ctx) -#define GR_SPV_RFL_BOP(F, DST, DST_IND, SRC1, SRC1_IND, SRC2, SRC2_IND) \ - F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC1)->nzs, SRC1_IND, sz), GR_ENTRY((SRC2)->nzs, SRC2_IND, sz), ctx) -#define GR_SPV_RFL_BOP_SCALAR(F, DST, DST_IND, SRC, SRC_IND, C, CTX) \ - F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC)->nzs, SRC_IND, sz), C, CTX) - -// Analogous macros for applying a unary or binary function between two contexts -#define GR_SPV_RFL_UOP_OTHER(F, DST, DST_IND, SRC, SRC_IND, CTX2) \ - F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC)->nzs, SRC_IND, (CTX2)->sizeof_elem), CTX2, ctx) -#define GR_SPV_RFL_BOP_OTHER(F, DST, DST_IND, SRC1, SRC1_IND, SRC2, SRC2_IND, CTX2) \ - F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC1)->nzs, SRC1_IND, sz), GR_ENTRY((SRC2)->nzs, SRC2_IND, (CTX2)->sizeof_elem), CTX2, ctx) -#define GR_SPV_RFL_OTHER_BOP(F, DST, DST_IND, SRC1, SRC1_IND, CTX2, SRC2, SRC2_IND) \ - F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC1)->nzs, SRC1_IND, CTX2->sizeof_elem), (CTX2), GR_ENTRY((SRC2)->nzs, SRC2_IND, sz), ctx) +WARN_UNUSED_RESULT int gr_sparse_vec_add(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_sub(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) ; +WARN_UNUSED_RESULT int gr_sparse_vec_mul(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx); -/* - Subtemplate for doing accumulated operation from one sparse vector into another. - Used to do dst += c * src and dst -= c * src, for c a scalar. -*/ -#define GR_SPV_ACCUM_TEMPLATE(ELEM_OP, ELEM_ACCUM_OP, DST, SRC, C, CTX) \ - GR_SPV_RFL_TEMPLATE( \ - GR_SPV_RFL_UOP(gr_set, DST, dest_nz_idx, DST, a_nz_idx), \ - GR_SPV_RFL_BOP_SCALAR(ELEM_OP, DST, dest_nz_idx, SRC, b_nz_idx, C, CTX), \ - GR_SPV_RFL_UOP(gr_set, DST, dest_nz_idx, DST, a_nz_idx) | GR_SPV_RFL_BOP_SCALAR(ELEM_ACCUM_OP, DST, dest_nz_idx, SRC, b_nz_idx, C, CTX), \ - DST, DST, SRC, CTX\ - ) +WARN_UNUSED_RESULT int gr_sparse_vec_add_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_sub_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_mul_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_neg(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) -{ return (gr_sparse_vec_set(dst, src, ctx) | _gr_vec_neg(dst->nzs, dst->nzs, dst->nnz, ctx)); } +WARN_UNUSED_RESULT int gr_other_add_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_other_sub_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_other_mul_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_update(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, dst, a_nz_idx), - GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src, b_nz_idx), - GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src, b_nz_idx), - dst, dst, src, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_add(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), - GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src2, b_nz_idx), - GR_SPV_RFL_BOP(gr_add, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx), - dst, src1, src2, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_sub(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), - GR_SPV_RFL_UOP(gr_neg, dst, dest_nz_idx, src2, b_nz_idx), - GR_SPV_RFL_BOP(gr_sub, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx), - dst, src1, src2, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_ZERO, - GR_SPV_RFL_ZERO, - GR_SPV_RFL_BOP(gr_mul, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx), - dst, src1, src2, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_add_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), - GR_SPV_RFL_UOP_OTHER(gr_set_other, dst, dest_nz_idx, src2, b_nz_idx, ctx2), - GR_SPV_RFL_BOP_OTHER(gr_add_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), - dst, src1, src2, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_sub_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), - GR_SPV_RFL_UOP_OTHER(gr_neg_other, dst, dest_nz_idx, src2, b_nz_idx, ctx2), - GR_SPV_RFL_BOP_OTHER(gr_sub_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), - dst, src1, src2, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_ZERO, - GR_SPV_RFL_ZERO, - GR_SPV_RFL_BOP_OTHER(gr_mul_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), - dst, src1, src2, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_other_add_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP_OTHER(gr_set_other, dst, dest_nz_idx, src1, a_nz_idx, ctx1), - GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src2, b_nz_idx), - GR_SPV_RFL_OTHER_BOP(gr_other_add, dst, dest_nz_idx, src1, a_nz_idx, ctx1, src2, b_nz_idx), - dst, src1, src2, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_other_sub_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_UOP_OTHER(gr_set_other, dst, dest_nz_idx, src1, a_nz_idx, ctx1), - GR_SPV_RFL_UOP(gr_neg, dst, dest_nz_idx, src2, b_nz_idx), - GR_SPV_RFL_OTHER_BOP(gr_other_sub, dst, dest_nz_idx, src1, a_nz_idx, ctx1, src2, b_nz_idx), - dst, src1, src2, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_other_mul_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) -{ - GR_SPV_RFL_TEMPLATE( - GR_SPV_RFL_ZERO, - GR_SPV_RFL_ZERO, - GR_SPV_RFL_OTHER_BOP(gr_other_mul, dst, dest_nz_idx, src1, a_nz_idx, ctx1, src2, b_nz_idx), - dst, src1, src2, ctx - ); -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_addmul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_TEMPLATE(gr_mul, gr_addmul, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_submul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_TEMPLATE(gr_negmul, gr_submul, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_TEMPLATE(gr_mul_si, gr_addmul_si, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_TEMPLATE(gr_negmul_si, gr_submul_si, dst, src, c, ctx); } +WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx); /** * Arithmetic into dense vectors **/ -// Internal macro to update a dense vector by iterating over a sparse one -#define GR_SPV_INTO_DENSE_TEMPLATE(FUNC, SVEC, CTX) \ - slong i; \ - slong sz = (CTX)->sizeof_elem; \ - int status = GR_SUCCESS; \ - slong nnz = (SVEC)->nnz; \ - for (i = 0; i < nnz; i++) \ - { \ - status |= (FUNC); \ - } \ - return status; - -// Sub-macro for applying operation (dense, sparse) -> dense -#define GR_SPV_OP_ON_DENSE_TEMPLATE(ELEM_OP, DRES, DVEC, SVEC, CTX) \ - GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(\ - GR_ENTRY((DRES), (SVEC)->inds[i], sz), \ - GR_ENTRY(DVEC, (SVEC)->inds[i], sz), \ - GR_ENTRY((SVEC)->nzs, i, sz), \ - CTX), SVEC, CTX) - -// Sub-macro for accumulating operation on dense from sparse -#define GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(ELEM_OP, DRES, SVEC, C, CTX) \ - GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(\ - GR_ENTRY(DRES, (SVEC)->inds[i], sz), \ - GR_ENTRY((SVEC)->nzs, i, sz),\ - C, CTX), SVEC, CTX) - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_update_sparse_vec_nz(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) -{ GR_SPV_INTO_DENSE_TEMPLATE(gr_set(GR_ENTRY(dres, src->inds[i], sz), GR_ENTRY(src->nzs, i, sz), ctx), src, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_add_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) -{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_add, dres, dvec1, svec2, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_sub_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) -{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_sub, dres, dvec1, svec2, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_mul_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) -{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_mul, dres, dvec1, svec2, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_div_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) -{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_div, dres, dvec1, svec2, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_addmul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul, dres, svec, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_submul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul, dres, svec, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_addmul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul_si, dres, svec, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_submul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul_si, dres, svec, c, ctx) } +WARN_UNUSED_RESULT int gr_vec_update_sparse_vec_nz(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_add_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_sub_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_mul_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_div_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx); -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_addmul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul_fmpz, dres, svec, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_vec_submul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) -{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul_fmpz, dres, svec, c, ctx) } +WARN_UNUSED_RESULT int gr_vec_addmul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_submul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_addmul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_submul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_addmul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_vec_submul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx); /** * Scalar multiplication and division **/ -#define GR_SPARSE_VEC_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) \ - if(dst->length != src->length) \ - { \ - return GR_DOMAIN; \ - } \ - if(dst != src) \ - { \ - gr_sparse_vec_fit_nnz(dst, src->nnz, ctx); \ - dst->nnz = src->nnz; \ - memcpy(dst->inds, src->inds, src->nnz*sizeof(slong)); \ - } \ - return dense_vec_op(dst->nzs, src->nzs, src->nnz, c, ctx); \ - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) -{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } +WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx); /** * Sum and product @@ -618,65 +275,8 @@ gr_sparse_vec_nz_product(gr_ptr dst, const gr_sparse_vec_t src, gr_ctx_t ctx) * Dot product **/ -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_dot(gr_ptr dst, gr_srcptr initial, int subtract, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) -{ - int status; - slong nz_idx1, nz_idx2; - slong sz = ctx->sizeof_elem; - - if (src1->length != src2->length) - { - return GR_DOMAIN; - } - status = gr_set(dst, initial, ctx); - for (nz_idx1 = 0, nz_idx2 = 0; nz_idx1 < src1->nnz && nz_idx2 < src2->nnz; ) - { - if (src1->inds[nz_idx1] < src2->inds[nz_idx2]) - { - nz_idx1++; - } - else if (src1->inds[nz_idx1] > src2->inds[nz_idx2]) - { - nz_idx2++; - } - else if (subtract) - { - status |= gr_submul(dst, GR_ENTRY(src1->nzs, nz_idx1, sz), GR_ENTRY(src2->nzs, nz_idx1, sz), ctx); - } - else - { - status |= gr_addmul(dst, GR_ENTRY(src1->nzs, nz_idx1, sz), GR_ENTRY(src2->nzs, nz_idx1, sz), ctx); - } - } - return status; -} - -GR_SPARSE_VEC_INLINE WARN_UNUSED_RESULT int -gr_sparse_vec_dot_vec(gr_ptr dst, gr_srcptr initial, int subtract, const gr_sparse_vec_t src1, const gr_vec_t src2, gr_ctx_t ctx) -{ - int status; - slong nz_idx; - slong sz = ctx->sizeof_elem; - - if (src1->length != src2->length) - { - return GR_DOMAIN; - } - status = gr_set(dst, initial, ctx); - for (nz_idx = 0; nz_idx < src1->nnz; nz_idx++) - { - if (subtract) - { - status |= gr_submul(dst, GR_ENTRY(src1->nzs, nz_idx, sz), GR_ENTRY(src2->entries, src1->inds[nz_idx], sz), ctx); - } - else - { - status |= gr_addmul(dst, GR_ENTRY(src1->nzs, nz_idx, sz), GR_ENTRY(src2->entries, src1->inds[nz_idx], sz), ctx); - } - } - return status; -} +WARN_UNUSED_RESULT int gr_sparse_vec_dot(gr_ptr dst, gr_srcptr initial, int subtract, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_sparse_vec_dot_vec(gr_ptr dst, gr_srcptr initial, int subtract, const gr_sparse_vec_t src1, gr_srcptr src2, gr_ctx_t ctx); #ifdef __cplusplus diff --git a/src/gr_sparse_vec/arith.c b/src/gr_sparse_vec/arith.c new file mode 100644 index 0000000000..815fda59a1 --- /dev/null +++ b/src/gr_sparse_vec/arith.c @@ -0,0 +1,397 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + Copyright (C) 2023 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 +#include "gr_sparse_vec.h" + +/* + Binary arithmetic operations on sparse vectors have a common pattern of + riffling through the two input vectors A_VEC and B_VEC to produce an + output vector DEST_VEC with indices in sorted order. As the iteration + proceeds, for a given index, we need one function FUNC_A if only A_VEC + has a nonzero element at that index, another function FUNC_B if only + B_VEC has a nonzero element, and a third function FUNC_AB if both are nonzero. + During this process, we maintain a triple of indices a_nz_idx, b_nz_idx, and + dest_nz_idx, which are used when calling this macro to indicate what element(s) + to refer to when calling the appropriate function. +*/ + +// Sub macro to swap two entries with their associated indices +#define GR_SPV_SWAP_INDS(VEC, I, J, SZ, CTX) \ +{ \ + slong _temp = (VEC)->inds[I]; \ + (VEC)->inds[I] = (VEC)->inds[J]; \ + (VEC)->inds[J] = _temp; \ + gr_swap(GR_ENTRY((VEC)->nzs, (I), (SZ)), GR_ENTRY((VEC)->nzs, (J), (SZ)), (CTX)); \ +} + +#define GR_SPV_RFL_TEMPLATE(FUNC_A, FUNC_B, FUNC_AB, DEST_VEC, A_VEC, B_VEC, CTX) \ + int status; \ + slong sz, new_nnz, a_nz_idx, b_nz_idx, dest_nz_idx, a_nnz, b_nnz, i; \ + ulong a_ind, b_ind; \ + if ((DEST_VEC)->length != (A_VEC)->length || (A_VEC)->length != (B_VEC)->length) \ + return GR_DOMAIN; \ + status = GR_SUCCESS; \ + sz = (CTX)->sizeof_elem; \ + a_nnz = (A_VEC)->nnz; \ + b_nnz = (B_VEC)->nnz; \ + new_nnz = _gr_sparse_vec_count_unique_inds((A_VEC)->inds, a_nnz, (B_VEC)->inds, b_nnz); \ + gr_sparse_vec_fit_nnz((DEST_VEC), new_nnz, (CTX)); \ + /* We go backward through the destination, because it might be an in-place operation on a source */ \ + a_nz_idx = a_nnz-1; \ + b_nz_idx = b_nnz-1; \ + dest_nz_idx = new_nnz-1; \ + while (a_nz_idx >= -1 && b_nz_idx >= -1 && status == GR_SUCCESS) \ + { \ + if (a_nz_idx == -1 && b_nz_idx == -1) break; \ + a_ind = (A_VEC)->inds[a_nz_idx]; \ + b_ind = (B_VEC)->inds[b_nz_idx]; \ + if (b_nz_idx == -1 || (a_nz_idx >= 0 && a_ind > b_ind)) \ + { \ + status |= (FUNC_A); \ + (DEST_VEC)->inds[dest_nz_idx] = a_ind; \ + a_nz_idx--; \ + } \ + else if (a_nz_idx == -1 || b_ind > a_ind) \ + { \ + status |= (FUNC_B); \ + (DEST_VEC)->inds[dest_nz_idx] = b_ind; \ + b_nz_idx--; \ + } \ + else \ + { \ + status |= (FUNC_AB); \ + (DEST_VEC)->inds[dest_nz_idx] = a_ind; \ + a_nz_idx--; \ + b_nz_idx--; \ + } \ + if (T_TRUE != gr_is_zero(GR_ENTRY((DEST_VEC)->nzs, dest_nz_idx, sz), (CTX))) \ + dest_nz_idx--; \ + } \ + /* Move the result to the beginning of the dest vec */ \ + /* Currently, dest_nz_idx points to one before the start of the legit destination values */ \ + if (dest_nz_idx >= 0 && !status) \ + { \ + new_nnz = (new_nnz-1) - dest_nz_idx; \ + dest_nz_idx++; \ + for (i = 0; i < new_nnz; i++) \ + GR_SPV_SWAP_INDS(DEST_VEC, i, dest_nz_idx + i, sz, CTX); \ + } \ + (DEST_VEC)->nnz = new_nnz; \ + return status; + +/* We need some convenience functions for certain simple operations. */ +int gr_neg_other(gr_ptr dst, gr_srcptr src, gr_ctx_t src_ctx, gr_ctx_t ctx) +{ return (gr_set_other(dst, src, src_ctx, ctx) | gr_neg(dst, dst, ctx)); } + +int gr_negmul(gr_ptr dst, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) +{ return (gr_mul(dst, x, y, ctx) | gr_neg(dst, dst, ctx)); } + +int gr_negmul_si(gr_ptr dst, gr_srcptr x, slong y, gr_ctx_t ctx) +{ return (gr_mul_si(dst, x, y, ctx) | gr_neg(dst, dst, ctx)); } + +// Need a zero-ary function to assign zero +#define GR_SPV_RFL_ZERO gr_zero(GR_ENTRY(dst->nzs, dest_nz_idx, sz), ctx) + +// Convenience macros for applying a unary or binary function +#define GR_SPV_RFL_UOP(F, DST, DST_IND, SRC, SRC_IND) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC)->nzs, SRC_IND, sz), ctx) +#define GR_SPV_RFL_BOP(F, DST, DST_IND, SRC1, SRC1_IND, SRC2, SRC2_IND) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC1)->nzs, SRC1_IND, sz), GR_ENTRY((SRC2)->nzs, SRC2_IND, sz), ctx) +#define GR_SPV_RFL_BOP_SCALAR(F, DST, DST_IND, SRC, SRC_IND, C, CTX) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC)->nzs, SRC_IND, sz), C, CTX) + +// Analogous macros for applying a unary or binary function between two contexts +#define GR_SPV_RFL_UOP_OTHER(F, DST, DST_IND, SRC, SRC_IND, CTX2) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC)->nzs, SRC_IND, (CTX2)->sizeof_elem), CTX2, ctx) +#define GR_SPV_RFL_BOP_OTHER(F, DST, DST_IND, SRC1, SRC1_IND, SRC2, SRC2_IND, CTX2) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC1)->nzs, SRC1_IND, sz), GR_ENTRY((SRC2)->nzs, SRC2_IND, (CTX2)->sizeof_elem), CTX2, ctx) +#define GR_SPV_RFL_OTHER_BOP(F, DST, DST_IND, SRC1, SRC1_IND, CTX2, SRC2, SRC2_IND) \ + F(GR_ENTRY((DST)->nzs, DST_IND, sz), GR_ENTRY((SRC1)->nzs, SRC1_IND, CTX2->sizeof_elem), (CTX2), GR_ENTRY((SRC2)->nzs, SRC2_IND, sz), ctx) + +/* + Subtemplate for doing accumulated operation from one sparse vector into another. + Used to do dst += c * src and dst -= c * src, for c a scalar. +*/ +#define GR_SPV_ACCUM_TEMPLATE(ELEM_OP, ELEM_ACCUM_OP, DST, SRC, C, CTX) \ + GR_SPV_RFL_TEMPLATE( \ + GR_SPV_RFL_UOP(gr_set, DST, dest_nz_idx, DST, a_nz_idx), \ + GR_SPV_RFL_BOP_SCALAR(ELEM_OP, DST, dest_nz_idx, SRC, b_nz_idx, C, CTX), \ + GR_SPV_RFL_UOP(gr_set, DST, dest_nz_idx, DST, a_nz_idx) | GR_SPV_RFL_BOP_SCALAR(ELEM_ACCUM_OP, DST, dest_nz_idx, SRC, b_nz_idx, C, CTX), \ + DST, DST, SRC, CTX\ + ) + +int gr_sparse_vec_neg(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ return (gr_sparse_vec_set(dst, src, ctx) | _gr_vec_neg(dst->nzs, dst->nzs, dst->nnz, ctx)); } + +int +gr_sparse_vec_update(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, dst, a_nz_idx), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src, b_nz_idx), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src, b_nz_idx), + dst, dst, src, ctx + ); +} + +int +gr_sparse_vec_add(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_BOP(gr_add, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx), + dst, src1, src2, ctx + ); +} + +int +gr_sparse_vec_sub(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), + GR_SPV_RFL_UOP(gr_neg, dst, dest_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_BOP(gr_sub, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx), + dst, src1, src2, ctx + ); +} + +int gr_sparse_vec_mul(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_ZERO, + GR_SPV_RFL_ZERO, + GR_SPV_RFL_BOP(gr_mul, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx), + dst, src1, src2, ctx + ); +} + +int +gr_sparse_vec_add_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), + GR_SPV_RFL_UOP_OTHER(gr_set_other, dst, dest_nz_idx, src2, b_nz_idx, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_add_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), + dst, src1, src2, ctx + ); +} + +int +gr_sparse_vec_sub_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src1, a_nz_idx), + GR_SPV_RFL_UOP_OTHER(gr_neg_other, dst, dest_nz_idx, src2, b_nz_idx, ctx2), + GR_SPV_RFL_BOP_OTHER(gr_sub_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), + dst, src1, src2, ctx + ); +} + +int +gr_sparse_vec_mul_other(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_ZERO, + GR_SPV_RFL_ZERO, + GR_SPV_RFL_BOP_OTHER(gr_mul_other, dst, dest_nz_idx, src1, a_nz_idx, src2, b_nz_idx, ctx2), + dst, src1, src2, ctx + ); +} + +int gr_other_add_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP_OTHER(gr_set_other, dst, dest_nz_idx, src1, a_nz_idx, ctx1), + GR_SPV_RFL_UOP(gr_set, dst, dest_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_OTHER_BOP(gr_other_add, dst, dest_nz_idx, src1, a_nz_idx, ctx1, src2, b_nz_idx), + dst, src1, src2, ctx + ); +} + +int gr_other_sub_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_UOP_OTHER(gr_set_other, dst, dest_nz_idx, src1, a_nz_idx, ctx1), + GR_SPV_RFL_UOP(gr_neg, dst, dest_nz_idx, src2, b_nz_idx), + GR_SPV_RFL_OTHER_BOP(gr_other_sub, dst, dest_nz_idx, src1, a_nz_idx, ctx1, src2, b_nz_idx), + dst, src1, src2, ctx + ); +} + +int gr_other_mul_sparse_vec(gr_sparse_vec_t dst, const gr_sparse_vec_t src1, gr_ctx_t ctx1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + GR_SPV_RFL_TEMPLATE( + GR_SPV_RFL_ZERO, + GR_SPV_RFL_ZERO, + GR_SPV_RFL_OTHER_BOP(gr_other_mul, dst, dest_nz_idx, src1, a_nz_idx, ctx1, src2, b_nz_idx), + dst, src1, src2, ctx + ); +} + +int gr_sparse_vec_addmul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_mul, gr_addmul, dst, src, c, ctx) } + +int gr_sparse_vec_submul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_negmul, gr_submul, dst, src, c, ctx) } + +int gr_sparse_vec_addmul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_mul_si, gr_addmul_si, dst, src, c, ctx) } + +int gr_sparse_vec_submul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_TEMPLATE(gr_negmul_si, gr_submul_si, dst, src, c, ctx); } + +/** + * Arithmetic into dense vectors +**/ + +// Internal macro to update a dense vector by iterating over a sparse one +#define GR_SPV_INTO_DENSE_TEMPLATE(FUNC, SVEC, CTX) \ + slong i; \ + slong sz = (CTX)->sizeof_elem; \ + int status = GR_SUCCESS; \ + slong nnz = (SVEC)->nnz; \ + for (i = 0; i < nnz; i++) \ + { \ + status |= (FUNC); \ + } \ + return status; + +// Sub-macro for applying operation (dense, sparse) -> dense +#define GR_SPV_OP_ON_DENSE_TEMPLATE(ELEM_OP, DRES, DVEC, SVEC, CTX) \ + GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(\ + GR_ENTRY((DRES), (SVEC)->inds[i], sz), \ + GR_ENTRY(DVEC, (SVEC)->inds[i], sz), \ + GR_ENTRY((SVEC)->nzs, i, sz), \ + CTX), SVEC, CTX) + +// Sub-macro for accumulating operation on dense from sparse +#define GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(ELEM_OP, DRES, SVEC, C, CTX) \ + GR_SPV_INTO_DENSE_TEMPLATE(ELEM_OP(\ + GR_ENTRY(DRES, (SVEC)->inds[i], sz), \ + GR_ENTRY((SVEC)->nzs, i, sz),\ + C, CTX), SVEC, CTX) + +int gr_vec_update_sparse_vec_nz(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) +{ GR_SPV_INTO_DENSE_TEMPLATE(gr_set(GR_ENTRY(dres, src->inds[i], sz), GR_ENTRY(src->nzs, i, sz), ctx), src, ctx) } + +int gr_vec_add_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) +{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_add, dres, dvec1, svec2, ctx) } + +int gr_vec_sub_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) +{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_sub, dres, dvec1, svec2, ctx) } + +int gr_vec_mul_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) +{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_mul, dres, dvec1, svec2, ctx) } + +int gr_vec_div_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) +{ GR_SPV_OP_ON_DENSE_TEMPLATE(gr_div, dres, dvec1, svec2, ctx) } + +int gr_vec_addmul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul, dres, svec, c, ctx) } + +int gr_vec_submul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul, dres, svec, c, ctx) } + +int gr_vec_addmul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul_si, dres, svec, c, ctx) } + +int gr_vec_submul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul_si, dres, svec, c, ctx) } + +int gr_vec_addmul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_addmul_fmpz, dres, svec, c, ctx) } + +int gr_vec_submul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPV_ACCUM_INTO_DENSE_TEMPLATE(gr_submul_fmpz, dres, svec, c, ctx) } + +/** + * Scalar multiplication and division +**/ + +#define GR_SPARSE_VEC_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) \ + if(dst->length != src->length) \ + { \ + return GR_DOMAIN; \ + } \ + if(dst != src) \ + { \ + gr_sparse_vec_fit_nnz(dst, src->nnz, ctx); \ + dst->nnz = src->nnz; \ + memcpy(dst->inds, src->inds, src->nnz*sizeof(slong)); \ + } \ + return dense_vec_op(dst->nzs, src->nzs, src->nnz, c, ctx); \ + +int +gr_sparse_vec_mul_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } + +int +gr_sparse_vec_mul_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } + +int +gr_sparse_vec_mul_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } + +int +gr_sparse_vec_mul_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } + +int +gr_sparse_vec_mul_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } + +int +gr_sparse_vec_mul_scalar_2exp_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } + +int +gr_sparse_vec_div_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } + +int +gr_sparse_vec_div_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } + +int +gr_sparse_vec_div_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } + +int +gr_sparse_vec_div_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } + +int +gr_sparse_vec_div_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } + +int +gr_sparse_vec_divexact_scalar(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } + +int +gr_sparse_vec_divexact_scalar_si(gr_sparse_vec_t dst, const gr_sparse_vec_t src, slong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } + +int +gr_sparse_vec_divexact_scalar_ui(gr_sparse_vec_t dst, const gr_sparse_vec_t src, ulong c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } + +int +gr_sparse_vec_divexact_scalar_fmpz(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } + +int +gr_sparse_vec_divexact_scalar_fmpq(gr_sparse_vec_t dst, const gr_sparse_vec_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_SPARSE_VEC_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } diff --git a/src/gr_sparse_vec/test/main.c b/src/gr_sparse_vec/test/main.c index 941e0d735a..1f5722d5d9 100644 --- a/src/gr_sparse_vec/test/main.c +++ b/src/gr_sparse_vec/test/main.c @@ -3,10 +3,12 @@ /* Include functions *********************************************************/ -#include "t-init.c" +#include "t-arith.c" #include "t-conversion.c" +#include "t-dot.c" +#include "t-init.c" #include "t-randtest.c" -#include "t-mul_scalar.c" +#include "t-sum-prod.c" /* Array of test functions ***************************************************/ @@ -15,7 +17,9 @@ test_struct tests[] = TEST_FUNCTION(gr_sparse_vec_init), TEST_FUNCTION(gr_sparse_vec_conversion), TEST_FUNCTION(gr_sparse_vec_randtest), - TEST_FUNCTION(gr_sparse_vec_mul_div_scalar), + TEST_FUNCTION(gr_sparse_vec_arith), + TEST_FUNCTION(gr_sparse_vec_dot), + TEST_FUNCTION(gr_sparse_vec_sum_prod), }; /* main function *************************************************************/ diff --git a/src/gr_sparse_vec/test/t-mul_scalar.c b/src/gr_sparse_vec/test/t-arith.c similarity index 61% rename from src/gr_sparse_vec/test/t-mul_scalar.c rename to src/gr_sparse_vec/test/t-arith.c index 9ad139d55d..1a623c40b7 100644 --- a/src/gr_sparse_vec/test/t-mul_scalar.c +++ b/src/gr_sparse_vec/test/t-arith.c @@ -17,6 +17,157 @@ #define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } int + +test_add_sub_mul(flint_rand_t state, gr_ctx_t ctx) +{ + slong i, k, l, m; + slong N = 20; + slong n_tests = 20; + int status; + gr_sparse_vec_t vec, vec2, vec_other; + gr_ptr dvec, dvec2, dvec3, dvec_other; + gr_ptr temp; + gr_ctx_t ctx_other; + truth_t eq; + + gr_ctx_init_fmpz(ctx_other); + GR_TMP_INIT(temp, ctx); + GR_TMP_INIT_VEC(dvec, N, ctx); + GR_TMP_INIT_VEC(dvec2, N, ctx); + GR_TMP_INIT_VEC(dvec3, N, ctx); + GR_TMP_INIT_VEC(dvec_other, N, ctx_other); + gr_sparse_vec_init(vec, N, ctx); + gr_sparse_vec_init(vec2, N, ctx); + gr_sparse_vec_init(vec_other, N, ctx_other); + + for (i = 0; i < 18 * n_tests; i++) + { + status = GR_SUCCESS; + //flint_printf("%d\n", i); + k = i % 2; // Into sparse or dense + l = (i / 2) % 3; // Add, subtract, or mul + m = (i / 6) % 3; // For into sparse, also check other ctx usage + if (k > 0 && m > 0) continue; + + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + if (k == 0) + { + status |= gr_vec_set_sparse_vec(dvec, vec, ctx); + if (m == 0) + { + status |= gr_sparse_vec_randtest(vec2, 10, 0, state, ctx); + status |= gr_vec_set_sparse_vec(dvec2, vec2, ctx); + if (l == 0) + { + status |= gr_sparse_vec_add(vec, vec, vec2, ctx); + status |= _gr_vec_add(dvec, dvec, dvec2, N, ctx); + } + else if (l == 1) + { + status |= gr_sparse_vec_sub(vec, vec, vec2, ctx); + status |= _gr_vec_sub(dvec, dvec, dvec2, N, ctx); + } + else + { + status |= gr_sparse_vec_mul(vec, vec, vec2, ctx); + status |= _gr_vec_mul(dvec, dvec, dvec2, N, ctx); + } + } + else + { + status |= gr_sparse_vec_randtest(vec_other, 10, 0, state, ctx_other); + status |= gr_vec_set_sparse_vec(dvec_other, vec_other, ctx_other); + if (m == 1) + { + if (l == 0) + { + status |= gr_sparse_vec_add_other(vec, vec, vec_other, ctx_other, ctx); + status |= _gr_vec_add_other(dvec, dvec, dvec_other, ctx_other, N, ctx); + } + else if (l == 1) + { + status |= gr_sparse_vec_sub_other(vec, vec, vec_other, ctx_other, ctx); + status |= _gr_vec_sub_other(dvec, dvec, dvec_other, ctx_other, N, ctx); + } + else + { + status |= gr_sparse_vec_mul_other(vec, vec, vec_other, ctx_other, ctx); + status |= _gr_vec_mul_other(dvec, dvec, dvec_other, ctx_other, N, ctx); + } + } + else + { + if (l == 0) + { + status |= gr_other_add_sparse_vec(vec, vec_other, ctx_other, vec, ctx); + status |= _gr_other_add_vec(dvec, dvec_other, ctx_other, dvec, N, ctx); + } + else if (l == 1) + { + status |= gr_other_sub_sparse_vec(vec, vec_other, ctx_other, vec, ctx); + status |= _gr_other_sub_vec(dvec, dvec_other, ctx_other, dvec, N, ctx); + } + else + { + status |= gr_other_mul_sparse_vec(vec, vec_other, ctx_other, vec, ctx); + status |= _gr_other_mul_vec(dvec, dvec_other, ctx_other, dvec, N, ctx); + } + } + } + } + else + { + status |= _gr_vec_randtest(dvec, state, N, ctx); + status |= _gr_vec_set(dvec2, dvec, N, ctx); + status |= gr_vec_set_sparse_vec(dvec3, vec, ctx); + + if (l == 0) + { + status |= gr_vec_add_sparse_vec(dvec, dvec, vec, ctx); + status |= _gr_vec_add(dvec2, dvec2, dvec3, N, ctx); + } + else if (l == 1) + { + status |= gr_vec_sub_sparse_vec(dvec, dvec, vec, ctx); + status |= _gr_vec_sub(dvec2, dvec2, dvec3, N, ctx); + } + else + { + continue; // TODO + } + } + + if (status == GR_UNABLE) + continue; + + if (k == 0) + status |= gr_vec_set_sparse_vec(dvec2, vec, ctx); + eq = _gr_vec_equal(dvec, dvec2, N, ctx); + if (eq == T_FALSE || status != GR_SUCCESS) + { + flint_printf( + "\ni = %d, k = %d, l = %d, m = %d, equal = %d, status = %d\n", + i, k, l, m, eq, status + ); + gr_ctx_println(ctx); + flint_printf("dvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); + flint_printf("dvec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + gr_sparse_vec_clear(vec, ctx); + gr_sparse_vec_clear(vec2, ctx); + gr_sparse_vec_clear(vec_other, ctx_other); + GR_TMP_CLEAR_VEC(dvec, N, ctx); + GR_TMP_CLEAR_VEC(dvec2, N, ctx); + GR_TMP_CLEAR_VEC(dvec3, N, ctx); + GR_TMP_CLEAR_VEC(dvec_other, N, ctx_other); + GR_TMP_CLEAR(temp, ctx); + gr_ctx_clear(ctx_other); + return status; +} + #define TEST_ACCUM_MUL_SCALAR(STATUS, K, L, TYPE, VEC, VEC2, DVEC, DVEC2, DVEC3, C, CTX) { \ if (K == 0) \ { \ @@ -46,171 +197,71 @@ int } \ } -test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) +int test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) { - slong i, j, k, l, m, c; + slong i, j, k, l, c; slong N = 20; slong n_tests = 20; int status; - slong sz = ctx->sizeof_elem; - gr_sparse_vec_t vec, vec2, vec3; - gr_ptr dvec, dvec2, dvec3, dvec4; + gr_sparse_vec_t vec, vec2, vec_other; + gr_ptr dvec, dvec2, dvec3; gr_ptr temp; - gr_ctx_t ctx2; + gr_ctx_t ctx_other; truth_t eq; - gr_ctx_init_fmpz(ctx2); + gr_ctx_init_fmpz(ctx_other); GR_TMP_INIT(temp, ctx); - dvec = flint_malloc(N * sz); - dvec2 = flint_malloc(N * sz); - dvec3 = flint_malloc(N * sz); - dvec4 = flint_malloc(N * ctx2->sizeof_elem); - _gr_vec_init(dvec, N, ctx); - _gr_vec_init(dvec2, N, ctx); - _gr_vec_init(dvec3, N, ctx); - _gr_vec_init(dvec4, N, ctx2); + GR_TMP_INIT_VEC(dvec, N, ctx); + GR_TMP_INIT_VEC(dvec2, N, ctx); + GR_TMP_INIT_VEC(dvec3, N, ctx); gr_sparse_vec_init(vec, N, ctx); gr_sparse_vec_init(vec2, N, ctx); - gr_sparse_vec_init(vec3, N, ctx2); + gr_sparse_vec_init(vec_other, N, ctx_other); - for (i = 0; i < 36 * n_tests; i++) + for (i = 0; i < 8 * n_tests; i++) { status = GR_SUCCESS; //flint_printf("%d\n", i); - j = i % 3; // Which type of scalar - k = (i / 3) % 2; // Into sparse or dense - l = (i / 6) % 2; // Add or subtract - m = (i / 12) % 3; // For plain add/subtract, also check other ctx usage - if ((j > 0 || k > 0) && m > 0) continue; + j = i % 2; // Scaler = ctx or si + k = (i / 2) % 2; // Into sparse or dense + l = (i / 4) % 2; // Add or subtract - //flint_printf("Setting up vectors\n"); - //flint_printf("\tRandomizing vec\n"); status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); if (k == 0) { - //flint_printf("\tCopying vec into dvec\n"); status |= gr_vec_set_sparse_vec(dvec, vec, ctx); - if (m > 0) - { - //flint_printf("\tRandomizing vec3\n"); - status |= gr_sparse_vec_randtest(vec3, 10, 0, state, ctx2); - //flint_printf("\tCopying vec3 into dvec4\n"); - status |= gr_vec_set_sparse_vec(dvec4, vec3, ctx2); - } - else - { - //flint_printf("\tRandomizing vec2\n"); - status |= gr_sparse_vec_randtest(vec2, 10, 0, state, ctx); - //flint_printf("\tCopying vec2 into dvec2\n"); - status |= gr_vec_set_sparse_vec(dvec2, vec2, ctx); - } + status |= gr_sparse_vec_randtest(vec2, 10, 0, state, ctx); + status |= gr_vec_set_sparse_vec(dvec2, vec2, ctx); } else { - //flint_printf("\tRandomizing dvec\n"); status |= _gr_vec_randtest(dvec, state, N, ctx); - //flint_printf("\tCopying dvec into dvec2\n"); status |= _gr_vec_set(dvec2, dvec, N, ctx); - //flint_printf("\tCopying vec into dvec3\n"); status |= gr_vec_set_sparse_vec(dvec3, vec, ctx); } - //flint_printf("\nBefore:\n"); - //flint_printf("\nvec = "); gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); - //flint_printf("\nvec2 = "); gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); - //flint_printf("\ndvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); - //flint_printf("\ndvec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); - - //flint_printf("Doing op\n"); - switch(j) + if (j == 0) { - case 0: - // Scalar = 1 => add or sub - if (k == 0) - { - if (m == 0) - { - if (l == 0) - { - status |= gr_sparse_vec_add(vec, vec, vec2, ctx); - status |= _gr_vec_add(dvec, dvec, dvec2, N, ctx); - } - else - { - status |= gr_sparse_vec_sub(vec, vec, vec2, ctx); - status |= _gr_vec_sub(dvec, dvec, dvec2, N, ctx); - } - } - else if (m == 1) - { - if (l == 0) - { - status |= gr_sparse_vec_add_other(vec, vec, vec3, ctx2, ctx); - status |= _gr_vec_add_other(dvec, dvec, dvec4, ctx2, N, ctx); - } - else - { - status |= gr_sparse_vec_sub_other(vec, vec, vec3, ctx2, ctx); - status |= _gr_vec_sub_other(dvec, dvec, dvec4, ctx2, N, ctx); - } - } - else - { - if (l == 0) - { - status |= gr_other_add_sparse_vec(vec, vec3, ctx2, vec, ctx); - status |= _gr_other_add_vec(dvec, dvec4, ctx2, dvec, N, ctx); - } - else - { - status |= gr_other_sub_sparse_vec(vec, vec3, ctx2, vec, ctx); - status |= _gr_other_sub_vec(dvec, dvec4, ctx2, dvec, N, ctx); - } - } - } - else - { - if (l == 0) - { - status |= gr_vec_add_sparse_vec(dvec, dvec, vec, ctx); - status |= _gr_vec_add(dvec2, dvec2, dvec3, N, ctx); - } - else - { - status |= gr_vec_sub_sparse_vec(dvec, dvec, vec, ctx); - status |= _gr_vec_sub(dvec2, dvec2, dvec3, N, ctx); - } - } - break; - case 1: status |= gr_randtest_not_zero(temp, state, ctx); - //flint_printf("\nc = "); gr_println(temp, ctx); flint_printf("\n"); TEST_ACCUM_MUL_SCALAR(status, k, l, scalar, vec, vec2, dvec, dvec2, dvec3, temp, ctx) break; - case 2: - //flint_printf("Testing scalar_si\n"); + } + else + { c = n_randint(state, 0); TEST_ACCUM_MUL_SCALAR(status, k, l, scalar_si, vec, vec2, dvec, dvec2, dvec3, c, ctx) break; } - //flint_printf("Checking\n"); - //flint_printf("\nAfter:\n"); - //flint_printf("\nvec = "); gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); - //status |= gr_sparse_vec_set_vec(vec2, dvec, N, ctx); - //flint_printf("\nvec2 = "); gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); - //flint_printf("\ndvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); - //flint_printf("\ndvec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); if (status == GR_UNABLE) continue; - if (k == 0) status |= gr_vec_set_sparse_vec(dvec2, vec, ctx); eq = _gr_vec_equal(dvec, dvec2, N, ctx); if (eq == T_FALSE || status != GR_SUCCESS) { flint_printf( - "\ni = %d, j = %d, k = %d, l = %d, m = %d, equal = %d, status = %d\n", - i, j, k, l, m, eq, status + "\ni = %d, j = %d, k = %d, l = %d, equal = %d, status = %d\n", + i, j, k, l, eq, status ); gr_ctx_println(ctx); flint_printf("dvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); @@ -221,17 +272,12 @@ test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) gr_sparse_vec_clear(vec, ctx); gr_sparse_vec_clear(vec2, ctx); - gr_sparse_vec_clear(vec3, ctx2); - _gr_vec_clear(dvec, N, ctx); - _gr_vec_clear(dvec2, N, ctx); - _gr_vec_clear(dvec3, N, ctx); - _gr_vec_clear(dvec4, N, ctx2); - flint_free(dvec); - flint_free(dvec2); - flint_free(dvec3); - flint_free(dvec4); + gr_sparse_vec_clear(vec_other, ctx_other); + GR_TMP_CLEAR_VEC(dvec, N, ctx); + GR_TMP_CLEAR_VEC(dvec2, N, ctx); + GR_TMP_CLEAR_VEC(dvec3, N, ctx); GR_TMP_CLEAR(temp, ctx); - gr_ctx_clear(ctx2); + gr_ctx_clear(ctx_other); return status; } @@ -254,15 +300,13 @@ test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) } \ } -int -test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) +int test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) { slong i, j, k, c; ulong uc; slong N = 100; slong n_tests = 20; int status; - slong sz = ctx->sizeof_elem; gr_sparse_vec_t vec, vec2; gr_ptr dvec, dvec2; gr_ptr temp; @@ -271,12 +315,10 @@ test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) truth_t eq; GR_TMP_INIT(temp, ctx); + GR_TMP_INIT_VEC(dvec, N, ctx); + GR_TMP_INIT_VEC(dvec2, N, ctx); fmpz_init(zc); fmpq_init(qc); - dvec = flint_malloc(N * sz); - dvec2 = flint_malloc(N * sz); - _gr_vec_init(dvec, N, ctx); - _gr_vec_init(dvec2, N, ctx); gr_sparse_vec_init(vec, N, ctx); gr_sparse_vec_init(vec2, N, ctx); @@ -286,7 +328,7 @@ test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) k = (i / 6) % 3; // Mul, div, or mul + divexact if ((j == 4 || k == 1) && gr_ctx_is_field(ctx) != T_TRUE) continue; - if (k == 2 && gr_ctx_is_integral_domain(ctx) != T_TRUE) + if (k == 2 && (gr_ctx_is_exact(ctx) != T_TRUE || gr_ctx_is_integral_domain(ctx) != T_TRUE)) continue; status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); status |= gr_vec_set_sparse_vec(dvec, vec, ctx); @@ -339,7 +381,7 @@ test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) break; } // If any operation not allowed, just skip test - if (status == GR_UNABLE) + if (status == GR_UNABLE || status == GR_DOMAIN) // TODO: FIXME { status = GR_SUCCESS; continue; @@ -367,17 +409,15 @@ test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) gr_sparse_vec_clear(vec, ctx); gr_sparse_vec_clear(vec2, ctx); - _gr_vec_clear(dvec, N, ctx); - _gr_vec_clear(dvec2, N, ctx); - flint_free(dvec); - flint_free(dvec2); + GR_TMP_CLEAR_VEC(dvec, N, ctx); + GR_TMP_CLEAR_VEC(dvec2, N, ctx); fmpz_clear(zc); fmpq_clear(qc); GR_TMP_CLEAR(temp, ctx); return status; } -TEST_FUNCTION_START(gr_sparse_vec_mul_div_scalar, state) +TEST_FUNCTION_START(gr_sparse_vec_arith, state) { slong i; gr_ctx_t ctx; @@ -392,16 +432,10 @@ TEST_FUNCTION_START(gr_sparse_vec_mul_div_scalar, state) else break; } - CHECK_TEST(test_accum_mul_scalar(state, ctx), "Scalar accumulation into sparse and dense"); + CHECK_TEST(test_add_sub_mul(state, ctx), "Addition, subtraction, and multiplication into sparse and dense"); + CHECK_TEST(test_accum_mul_scalar(state, ctx), "Scalar addmul and submul into sparse and dense"); CHECK_TEST(test_mul_div_scalar(state, ctx), "Scalar multiplication and division"); gr_ctx_clear(ctx); } TEST_FUNCTION_END(state); } - -// vec = [ -// 8: [0.0729740542394905489231860002370251 +/- 4.22e-35], -// 8: [-1.565059542762220528273371476451385e+59 +/- 5.02e+25], -// 84: [2.138150592348574067073082771877590e-50 +/- 4.83e-84], -// 84: [0.4375000000000000000000000000000000 +/- 2.41e-35], -// ] From 9bce9eecd989fd2f3c8ef1f414ebc87e07433de3 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Wed, 20 Mar 2024 07:19:49 -0700 Subject: [PATCH 44/59] Added missed tests --- src/gr_sparse_vec/dot.c | 60 ++++++++++++++ src/gr_sparse_vec/test/t-dot.c | 117 ++++++++++++++++++++++++++++ src/gr_sparse_vec/test/t-sum-prod.c | 97 +++++++++++++++++++++++ 3 files changed, 274 insertions(+) create mode 100644 src/gr_sparse_vec/dot.c create mode 100644 src/gr_sparse_vec/test/t-dot.c create mode 100644 src/gr_sparse_vec/test/t-sum-prod.c diff --git a/src/gr_sparse_vec/dot.c b/src/gr_sparse_vec/dot.c new file mode 100644 index 0000000000..f0ef1b91e5 --- /dev/null +++ b/src/gr_sparse_vec/dot.c @@ -0,0 +1,60 @@ +/* + Copyright (C) 2023 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 +#include "gr_sparse_vec.h" + +int gr_sparse_vec_dot(gr_ptr dst, gr_srcptr initial, int subtract, const gr_sparse_vec_t src1, const gr_sparse_vec_t src2, gr_ctx_t ctx) +{ + int status; + slong nz_idx1, nz_idx2; + slong sz = ctx->sizeof_elem; + + if (src1->length != src2->length) + { + return GR_DOMAIN; + } + status = gr_set(dst, initial, ctx); + for (nz_idx1 = 0, nz_idx2 = 0; nz_idx1 < src1->nnz && nz_idx2 < src2->nnz; ) + { + if (src1->inds[nz_idx1] < src2->inds[nz_idx2]) + nz_idx1++; + else if (src1->inds[nz_idx1] > src2->inds[nz_idx2]) + nz_idx2++; + else { + if (subtract) + status |= gr_submul(dst, GR_ENTRY(src1->nzs, nz_idx1, sz), GR_ENTRY(src2->nzs, nz_idx2, sz), ctx); + else + status |= gr_addmul(dst, GR_ENTRY(src1->nzs, nz_idx1, sz), GR_ENTRY(src2->nzs, nz_idx2, sz), ctx); + nz_idx1++, nz_idx2++; + } + } + return status; +} + +int gr_sparse_vec_dot_vec(gr_ptr dst, gr_srcptr initial, int subtract, const gr_sparse_vec_t src1, gr_srcptr src2, gr_ctx_t ctx) +{ + int status; + slong nz_idx; + slong sz = ctx->sizeof_elem; + + status = gr_set(dst, initial, ctx); + //flint_printf("dst = "); status |= gr_println(dst, ctx); + for (nz_idx = 0; nz_idx < src1->nnz; nz_idx++) + { + if (subtract) + status |= gr_submul(dst, GR_ENTRY(src1->nzs, nz_idx, sz), GR_ENTRY(src2, src1->inds[nz_idx], sz), ctx); + else + status |= gr_addmul(dst, GR_ENTRY(src1->nzs, nz_idx, sz), GR_ENTRY(src2, src1->inds[nz_idx], sz), ctx); + //flint_printf("dst = "); status |= gr_println(dst, ctx); + } + return status; +} diff --git a/src/gr_sparse_vec/test/t-dot.c b/src/gr_sparse_vec/test/t-dot.c new file mode 100644 index 0000000000..de6cb6783f --- /dev/null +++ b/src/gr_sparse_vec/test/t-dot.c @@ -0,0 +1,117 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_vec.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int test_dot(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + slong N = 30; + slong n_tests = 20; + int status = GR_SUCCESS; + gr_sparse_vec_t vec, vec2; + gr_ptr dvec, dvec2; + gr_ptr dot, dot2; + GR_TMP_INIT2(dot, dot2, ctx); + + GR_TMP_INIT_VEC(dvec, N, ctx); + GR_TMP_INIT_VEC(dvec2, N, ctx); + gr_sparse_vec_init(vec, N, ctx); + gr_sparse_vec_init(vec2, N, ctx); + + //flint_printf("Testing copy\n"); + for (i = 0; i < 2*n_tests; i++) + { + // Give a random initial value to dot + status |= gr_randtest(dot, state, ctx); + status |= gr_set(dot2, dot, ctx); + + // Get two random sparse vectors + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + status |= gr_sparse_vec_randtest(vec2, 10, 0, state, ctx); + status |= gr_vec_set_sparse_vec(dvec, vec, ctx); + status |= gr_vec_set_sparse_vec(dvec2, vec2, ctx); + + // Compute sparse dot product and check against dense one + status |= gr_sparse_vec_dot(dot, dot, i % 2, vec, vec2, ctx); + status |= _gr_vec_dot(dot2, dot2, i % 2, dvec, dvec2, N, ctx); + if (gr_equal(dot, dot2, ctx) == T_FALSE) + { + gr_ctx_println(ctx); + flint_printf("vec = "); gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + flint_printf("vec2 = "); gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); + flint_printf("dvec = "); _gr_vec_print(dvec, N, ctx); flint_printf("\n"); + flint_printf("dvec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); + flint_printf("dot = "); gr_println(dot, ctx); + flint_printf("dot2 = "); gr_println(dot2, ctx); + return GR_TEST_FAIL; + } + } + + //flint_printf("Testing from/to dense vec\n"); + for (i = 0; i < 2*n_tests; i++) + { + // Give a random initial value to dot + status |= gr_randtest(dot, state, ctx); + status |= gr_set(dot2, dot, ctx); + + // Get random sparse and dense vectors + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + status |= _gr_vec_randtest(dvec2, state, N, ctx); + status |= gr_vec_set_sparse_vec(dvec, vec, ctx); + + // Compute sparse-dense dot product and check against dense-dense one + status |= gr_sparse_vec_dot_vec(dot, dot, i % 2, vec, dvec2, ctx); + status |= _gr_vec_dot(dot2, dot2, i % 2, dvec, dvec2, N, ctx); + + if (gr_equal(dot, dot2, ctx) == T_FALSE) + { + gr_ctx_println(ctx); + flint_printf("vec = "); gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + flint_printf("vec2 = "); _gr_vec_print(dvec2, N, ctx); flint_printf("\n"); + flint_printf("dot = "); gr_println(dot, ctx); + flint_printf("dot2 = "); gr_println(dot2, ctx); + return GR_TEST_FAIL; + } + } + + gr_sparse_vec_clear(vec, ctx); + gr_sparse_vec_clear(vec2, ctx); + GR_TMP_CLEAR_VEC(dvec, N, ctx); + GR_TMP_CLEAR_VEC(dvec2, N, ctx); + GR_TMP_CLEAR2(dot, dot2, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_vec_dot, state) +{ + slong i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while (1) + { + gr_ctx_init_fmpz(ctx); + //gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_println(ctx); + CHECK_TEST(test_dot(state, ctx), "Dot product"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_vec/test/t-sum-prod.c b/src/gr_sparse_vec/test/t-sum-prod.c new file mode 100644 index 0000000000..703cb118c7 --- /dev/null +++ b/src/gr_sparse_vec/test/t-sum-prod.c @@ -0,0 +1,97 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_vec.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int test_sum_prod(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + slong N = 30; + slong n_tests = 20; + int status = GR_SUCCESS; + gr_sparse_vec_t vec; + gr_ptr dvec; + gr_ptr res, res2; + GR_TMP_INIT2(res, res2, ctx); + + GR_TMP_INIT_VEC(dvec, N, ctx); + gr_sparse_vec_init(vec, N, ctx); + + //flint_printf("Testing sum\n"); + for (i = 0; i < 2*n_tests; i++) + { + // Get random sparse vector + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + status |= gr_vec_set_sparse_vec(dvec, vec, ctx); + + // Compute sparse sum and check against dense one + status |= gr_sparse_vec_sum(res, vec, ctx); + status |= _gr_vec_sum(res2, dvec, N, ctx); + if (gr_equal(res, res2, ctx) == T_FALSE) + { + gr_ctx_println(ctx); + flint_printf("vec = "); gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + flint_printf("res = "); gr_println(res, ctx); + flint_printf("res2 = "); gr_println(res2, ctx); + return GR_TEST_FAIL; + } + } + + //flint_printf("Testing prod\n"); + for (i = 0; i < 2*n_tests; i++) + { + // Get random sparse vector + status |= gr_sparse_vec_randtest(vec, 10, 0, state, ctx); + status |= gr_vec_set_sparse_vec(dvec, vec, ctx); + + // Compute sparse sum and check against dense one + status |= gr_sparse_vec_nz_product(res, vec, ctx); + status |= _gr_vec_product(res2, vec->nzs, vec->nnz, ctx); + if (gr_equal(res, res2, ctx) == T_FALSE) + { + gr_ctx_println(ctx); + flint_printf("vec = "); gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + flint_printf("res = "); gr_println(res, ctx); + flint_printf("res2 = "); gr_println(res2, ctx); + return GR_TEST_FAIL; + } + } + + gr_sparse_vec_clear(vec, ctx); + GR_TMP_CLEAR_VEC(dvec, N, ctx); + GR_TMP_CLEAR2(res, res2, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_vec_sum_prod, state) +{ + slong i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while (1) + { + gr_ctx_init_fmpz(ctx); + //gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_println(ctx); + CHECK_TEST(test_sum_prod(state, ctx), "Sum and (nonzero) product"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} From 0b4ac8bbb67c5f15e06b73e63c16bfe5b490a358 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Wed, 20 Mar 2024 07:31:49 -0700 Subject: [PATCH 45/59] Moved inline arithmetic functions to files --- src/gr_sparse_mat.h | 211 +++++++------------------------------ src/gr_sparse_mat/arith.c | 69 ++++++++++++ src/gr_sparse_mat/neg.c | 57 ++++++++++ src/gr_sparse_mat/scalar.c | 115 ++++++++++++++++++++ 4 files changed, 282 insertions(+), 170 deletions(-) create mode 100644 src/gr_sparse_mat/arith.c create mode 100644 src/gr_sparse_mat/neg.c create mode 100644 src/gr_sparse_mat/scalar.c diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 30fa6a68ed..c08dcfe8dc 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -718,183 +718,54 @@ gr_coo_mat_print_nz(const gr_coo_mat_t mat, gr_ctx_t ctx); * Arithmetic **/ -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_csr_mat_neg(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) -{ - int status = GR_SUCCESS; - - if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) - { - return GR_DOMAIN; - } - status |= gr_csr_mat_set(dst, src, ctx); - status |= _gr_vec_neg(dst->nzs, dst->nzs, dst->nnz, ctx); - return status; -} - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_neg(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) -{ - int row; - int status = GR_SUCCESS; - - if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) - { - return GR_DOMAIN; - } - dst->nnz = src->nnz; - for (row = 0; row < dst->r; row++) { - status |= gr_sparse_vec_neg(&dst->rows[row], &src->rows[row], ctx); - } - return status; -} - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_coo_mat_neg(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) -{ - int status = GR_SUCCESS; - - if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) - { - return GR_DOMAIN; - } - status |= gr_coo_mat_set(dst, src, ctx); - status |= _gr_vec_neg(dst->nzs, dst->nzs, dst->nnz, ctx); - return status; -} - -#define GR_LIL_MAT_BOP(FUNC, RES, MAT1, MAT2, CTX) { \ - int row; \ - int status = GR_SUCCESS; \ - \ - if (gr_mat_is_compatible(RES, MAT1, CTX) == T_FALSE || gr_mat_is_compatible(RES, MAT2, CTX) == T_FALSE) \ - { \ - return GR_DOMAIN; \ - } \ - (RES)->nnz = 0; \ - for (row = 0; row < (RES)->r; row++) { \ - status |= FUNC(&(RES)->rows[row], &(MAT1)->rows[row], &(MAT2)->rows[row], CTX); \ - dst->nnz += dst->rows[row].nnz; \ - } \ - return status; \ -} - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_add(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) -{ - GR_LIL_MAT_BOP(gr_sparse_vec_add, dst, mat1, mat2, ctx) -} - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_sub(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) -{ - GR_LIL_MAT_BOP(gr_sparse_vec_sub, dst, mat1, mat2, ctx) -} - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_mul(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) -{ - GR_LIL_MAT_BOP(gr_sparse_vec_mul, dst, mat1, mat2, ctx) -} - -#define GR_LIL_MAT_ACCUM_OP(FUNC, RES, MAT, C, CTX) { \ - int row; \ - int status = GR_SUCCESS; \ - \ - if (gr_mat_is_compatible(RES, MAT, CTX) == T_FALSE) \ - { \ - return GR_DOMAIN; \ - } \ - (RES)->nnz = 0; \ - for (row = 0; row < (RES)->r; row++) { \ - status |= FUNC(&(RES)->rows[row], &(MAT)->rows[row], C, CTX); \ - (RES)->nnz += (RES)->rows[row].nnz; \ - } \ - return status; \ -} +WARN_UNUSED_RESULT int gr_csr_mat_neg(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_neg(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_neg(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx); -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_addmul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) -{ - GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_addmul_scalar, dst, src, c, ctx) -} +WARN_UNUSED_RESULT int gr_lil_mat_add(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_sub(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_submul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) -{ - GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_submul_scalar, dst, src, c, ctx) -} +WARN_UNUSED_RESULT int gr_lil_mat_addmul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_submul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); /** * Component-wise multiplication and division **/ -#define GR_CSR_MAT_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) \ - if(dst->r != src->r || dst->c != src->c) \ - { \ - return GR_DOMAIN; \ - } \ - if(dst != src) \ - { \ - gr_csr_mat_fit_nnz(dst, src->nnz, ctx); \ - dst->nnz = src->nnz; \ - memcpy(dst->rows, src->rows, src->r*sizeof(ulong)); \ - memcpy(dst->cols, src->cols, src->nnz*sizeof(ulong)); \ - } \ - return dense_vec_op(dst->nzs, src->nzs, src->nnz, c, ctx); \ - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_2exp_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } - -#define GR_LIL_MAT_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) { \ - int status = GR_SUCCESS; \ - int row; \ - if(dst->r != src->r || dst->c != src->c) \ - { \ - return GR_DOMAIN; \ - } \ - dst->nnz = src->nnz; \ - for (row = 0; row < src->r; ++row) \ - { \ - if(dst != src) \ - { \ - gr_sparse_vec_fit_nnz(&dst->rows[row], src->rows[row].nnz, ctx); \ - dst->rows[row].nnz = src->rows[row].nnz; \ - memcpy(dst->rows[row].inds, src->rows[row].inds, src->rows[row].nnz*sizeof(ulong)); \ - } \ - status |= dense_vec_op(dst->rows[row].nzs, src->rows[row].nzs, src->rows[row].nnz, c, ctx); \ - } \ - return status; \ -} - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_2exp_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } +WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_mul_scalar_2exp_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_div_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_div_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_divexact_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul_scalar_2exp_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_div_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_div_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx); /** * Sum and product diff --git a/src/gr_sparse_mat/arith.c b/src/gr_sparse_mat/arith.c new file mode 100644 index 0000000000..8dae66a5be --- /dev/null +++ b/src/gr_sparse_mat/arith.c @@ -0,0 +1,69 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + Copyright (C) 2023 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 +#include "gr_sparse_mat.h" + +#define GR_LIL_MAT_BOP(FUNC, RES, MAT1, MAT2, CTX) \ +{ \ + int row; \ + int status = GR_SUCCESS; \ + \ + if (gr_mat_is_compatible(RES, MAT1, CTX) == T_FALSE || gr_mat_is_compatible(RES, MAT2, CTX) == T_FALSE) \ + { \ + return GR_DOMAIN; \ + } \ + (RES)->nnz = 0; \ + for (row = 0; row < (RES)->r; row++) \ +{ \ + status |= FUNC(&(RES)->rows[row], &(MAT1)->rows[row], &(MAT2)->rows[row], CTX); \ + dst->nnz += dst->rows[row].nnz; \ + } \ + return status; \ +} + +int gr_lil_mat_add(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ GR_LIL_MAT_BOP(gr_sparse_vec_add, dst, mat1, mat2, ctx) } + +int gr_lil_mat_sub(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ GR_LIL_MAT_BOP(gr_sparse_vec_sub, dst, mat1, mat2, ctx) } + +int gr_lil_mat_mul(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +{ GR_LIL_MAT_BOP(gr_sparse_vec_mul, dst, mat1, mat2, ctx) } + +#define GR_LIL_MAT_ACCUM_OP(FUNC, RES, MAT, C, CTX) \ +{ \ + int row; \ + int status = GR_SUCCESS; \ + \ + if (gr_mat_is_compatible(RES, MAT, CTX) == T_FALSE) \ + { \ + return GR_DOMAIN; \ + } \ + (RES)->nnz = 0; \ + for (row = 0; row < (RES)->r; row++) \ + { \ + status |= FUNC(&(RES)->rows[row], &(MAT)->rows[row], C, CTX); \ + (RES)->nnz += (RES)->rows[row].nnz; \ + } \ + return status; \ +} + +int gr_lil_mat_addmul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ + GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_addmul_scalar, dst, src, c, ctx) +} + +int gr_lil_mat_submul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ + GR_LIL_MAT_ACCUM_OP(gr_sparse_vec_submul_scalar, dst, src, c, ctx) +} diff --git a/src/gr_sparse_mat/neg.c b/src/gr_sparse_mat/neg.c new file mode 100644 index 0000000000..b4193aebc6 --- /dev/null +++ b/src/gr_sparse_mat/neg.c @@ -0,0 +1,57 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + Copyright (C) 2023 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 +#include "gr_sparse_mat.h" + +int gr_csr_mat_neg(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + { + return GR_DOMAIN; + } + status |= gr_csr_mat_set(dst, src, ctx); + status |= _gr_vec_neg(dst->nzs, dst->nzs, dst->nnz, ctx); + return status; +} + +int gr_lil_mat_neg(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) +{ + int row; + int status = GR_SUCCESS; + + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + { + return GR_DOMAIN; + } + dst->nnz = src->nnz; + for (row = 0; row < dst->r; row++) +{ + status |= gr_sparse_vec_neg(&dst->rows[row], &src->rows[row], ctx); + } + return status; +} + +int gr_coo_mat_neg(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + + if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) + { + return GR_DOMAIN; + } + status |= gr_coo_mat_set(dst, src, ctx); + status |= _gr_vec_neg(dst->nzs, dst->nzs, dst->nnz, ctx); + return status; +} diff --git a/src/gr_sparse_mat/scalar.c b/src/gr_sparse_mat/scalar.c new file mode 100644 index 0000000000..d68deef628 --- /dev/null +++ b/src/gr_sparse_mat/scalar.c @@ -0,0 +1,115 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + Copyright (C) 2023 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 +#include "gr_sparse_mat.h" + +#define GR_CSR_MAT_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) \ + if(dst->r != src->r || dst->c != src->c) \ + { \ + return GR_DOMAIN; \ + } \ + if(dst != src) \ + { \ + gr_csr_mat_fit_nnz(dst, src->nnz, ctx); \ + dst->nnz = src->nnz; \ + memcpy(dst->rows, src->rows, src->r*sizeof(ulong)); \ + memcpy(dst->cols, src->cols, src->nnz*sizeof(ulong)); \ + } \ + return dense_vec_op(dst->nzs, src->nzs, src->nnz, c, ctx); \ + +int gr_csr_mat_mul_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } +int gr_csr_mat_mul_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } +int gr_csr_mat_mul_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } +int gr_csr_mat_mul_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } +int gr_csr_mat_mul_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } +int gr_csr_mat_mul_scalar_2exp_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } +int gr_csr_mat_div_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } +int gr_csr_mat_div_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } +int gr_csr_mat_div_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } +int gr_csr_mat_div_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } +int gr_csr_mat_div_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } +int gr_csr_mat_divexact_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } +int gr_csr_mat_divexact_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } +int gr_csr_mat_divexact_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } +int gr_csr_mat_divexact_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } +int gr_csr_mat_divexact_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_CSR_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } + +#define GR_LIL_MAT_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) { \ + int status = GR_SUCCESS; \ + int row; \ + if(dst->r != src->r || dst->c != src->c) \ + { \ + return GR_DOMAIN; \ + } \ + dst->nnz = src->nnz; \ + for (row = 0; row < src->r; ++row) \ + { \ + if(dst != src) \ + { \ + gr_sparse_vec_fit_nnz(&dst->rows[row], src->rows[row].nnz, ctx); \ + dst->rows[row].nnz = src->rows[row].nnz; \ + memcpy(dst->rows[row].inds, src->rows[row].inds, src->rows[row].nnz*sizeof(ulong)); \ + } \ + status |= dense_vec_op(dst->rows[row].nzs, src->rows[row].nzs, src->rows[row].nnz, c, ctx); \ + } \ + return status; \ +} + +int gr_lil_mat_mul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } +int gr_lil_mat_mul_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } +int gr_lil_mat_mul_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } +int gr_lil_mat_mul_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } +int gr_lil_mat_mul_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } +int gr_lil_mat_mul_scalar_2exp_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } +int gr_lil_mat_div_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } +int gr_lil_mat_div_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } +int gr_lil_mat_div_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } +int gr_lil_mat_div_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } +int gr_lil_mat_div_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } +int gr_lil_mat_divexact_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } +int gr_lil_mat_divexact_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } +int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } +int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } +int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } From a3be3d5f0d2315e27120d571f884f8b4d138785b Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Wed, 20 Mar 2024 07:36:33 -0700 Subject: [PATCH 46/59] Moved column permutations to file --- src/gr_sparse_mat.h | 71 ++++---------------------------- src/gr_sparse_mat/permute_cols.c | 56 +++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 62 deletions(-) create mode 100644 src/gr_sparse_mat/permute_cols.c diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index c08dcfe8dc..464546b835 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -557,51 +557,9 @@ gr_lil_mat_update(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) return status; } - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_csr_mat_permute_cols(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx) -{ - slong row; - gr_sparse_vec_t tmp; - int status = GR_SUCCESS; - - for (row = 0; row < mat->r; ++row) - { - _gr_csr_mat_borrow_row(tmp, mat, row, ctx); - status |= gr_sparse_vec_permute_inds(tmp, tmp, perm, ctx); - } - return status; -} - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_lil_mat_permute_cols(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx) -{ - slong row; - int status = GR_SUCCESS; - - for (row = 0; row < mat->r; ++row) - { - status |= gr_sparse_vec_permute_inds(&mat->rows[row], &mat->rows[row], perm, ctx); - } - return status; -} - -GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int -gr_coo_mat_permute_cols(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx) -{ - slong nz_idx; - int status = GR_SUCCESS; - - for (nz_idx = 0; nz_idx < mat->nnz; ++nz_idx) - { - mat->cols[nz_idx] = perm[mat->cols[nz_idx]]; - } - if (mat->is_canonical) - { - gr_coo_mat_canonicalize(mat, ctx); - } - return status; -} +WARN_UNUSED_RESULT int gr_csr_mat_permute_cols(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_permute_cols(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_permute_cols(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx); void gr_lil_mat_window_init(gr_lil_mat_t window, const gr_lil_mat_t mat, slong r1, slong c1, slong r2, slong c2, gr_ctx_t ctx); @@ -696,23 +654,12 @@ WARN_UNUSED_RESULT int gr_csr_mat_set_fmpq_csr_mat(gr_csr_mat_t res, const fmpq_ * Output **/ -WARN_UNUSED_RESULT int -gr_csr_mat_write_nz(gr_stream_t out, const gr_csr_mat_t mat, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_lil_mat_write_nz(gr_stream_t out, const gr_lil_mat_t mat, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_coo_mat_write_nz(gr_stream_t out, const gr_coo_mat_t mat, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_csr_mat_print_nz(const gr_csr_mat_t mat, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_lil_mat_print_nz(const gr_lil_mat_t mat, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_coo_mat_print_nz(const gr_coo_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_write_nz(gr_stream_t out, const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_write_nz(gr_stream_t out, const gr_lil_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_write_nz(gr_stream_t out, const gr_coo_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_print_nz(const gr_csr_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_print_nz(const gr_lil_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_print_nz(const gr_coo_mat_t mat, gr_ctx_t ctx); /** * Arithmetic diff --git a/src/gr_sparse_mat/permute_cols.c b/src/gr_sparse_mat/permute_cols.c new file mode 100644 index 0000000000..a0be3f03f8 --- /dev/null +++ b/src/gr_sparse_mat/permute_cols.c @@ -0,0 +1,56 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + Copyright (C) 2023 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 +#include "gr_sparse_mat.h" + +int gr_csr_mat_permute_cols(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx) +{ + slong row; + gr_sparse_vec_t tmp; + int status = GR_SUCCESS; + + for (row = 0; row < mat->r; ++row) + { + _gr_csr_mat_borrow_row(tmp, mat, row, ctx); + status |= gr_sparse_vec_permute_inds(tmp, tmp, perm, ctx); + } + return status; +} + +int gr_lil_mat_permute_cols(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx) +{ + slong row; + int status = GR_SUCCESS; + + for (row = 0; row < mat->r; ++row) + { + status |= gr_sparse_vec_permute_inds(&mat->rows[row], &mat->rows[row], perm, ctx); + } + return status; +} + +int gr_coo_mat_permute_cols(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx) +{ + slong nz_idx; + int status = GR_SUCCESS; + + for (nz_idx = 0; nz_idx < mat->nnz; ++nz_idx) + { + mat->cols[nz_idx] = perm[mat->cols[nz_idx]]; + } + if (mat->is_canonical) + { + gr_coo_mat_canonicalize(mat, ctx); + } + return status; +} \ No newline at end of file From ca8e38e50c4cc5502ad0c43a4b33405caad9ce0a Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Wed, 20 Mar 2024 07:36:48 -0700 Subject: [PATCH 47/59] Added newline --- src/gr_sparse_mat/permute_cols.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gr_sparse_mat/permute_cols.c b/src/gr_sparse_mat/permute_cols.c index a0be3f03f8..92ce520c36 100644 --- a/src/gr_sparse_mat/permute_cols.c +++ b/src/gr_sparse_mat/permute_cols.c @@ -53,4 +53,4 @@ int gr_coo_mat_permute_cols(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx) gr_coo_mat_canonicalize(mat, ctx); } return status; -} \ No newline at end of file +} From ecf1f65c60af67defc0bb44f8d34eaf1d8f6799a Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Wed, 20 Mar 2024 16:55:38 -0700 Subject: [PATCH 48/59] Fixed a few bugs, test for generation and conversion --- doc/source/gr_sparse_vec.rst | 4 +- src/gr_sparse_mat.h | 100 +++++------ src/gr_sparse_mat/canonicalize.c | 34 +++- src/gr_sparse_mat/equal.c | 51 ++++-- src/gr_sparse_mat/from_entries.c | 5 +- src/gr_sparse_mat/get_entry.c | 63 +++++-- src/gr_sparse_mat/permute_cols.c | 2 +- src/gr_sparse_mat/randtest.c | 119 +++++++++++++ src/gr_sparse_mat/set.c | 38 ++-- src/gr_sparse_mat/test/main.c | 21 +++ src/gr_sparse_mat/test/t-conversion.c | 152 ++++++++++++++++ src/gr_sparse_mat/test/t-init.c | 247 ++++++++++++++++++++++++++ src/gr_sparse_mat/test/t-randtest.c | 79 ++++++++ src/gr_sparse_mat/to_dense.c | 2 +- src/gr_sparse_mat/write.c | 9 +- src/gr_sparse_vec.h | 2 +- src/gr_sparse_vec/from_entries.c | 4 +- src/gr_sparse_vec/set.c | 3 + src/gr_sparse_vec/test/t-randtest.c | 3 +- 19 files changed, 818 insertions(+), 120 deletions(-) create mode 100644 src/gr_sparse_mat/randtest.c create mode 100644 src/gr_sparse_mat/test/main.c create mode 100644 src/gr_sparse_mat/test/t-conversion.c create mode 100644 src/gr_sparse_mat/test/t-init.c create mode 100644 src/gr_sparse_mat/test/t-randtest.c diff --git a/doc/source/gr_sparse_vec.rst b/doc/source/gr_sparse_vec.rst index 6d75bb7cb3..788254b861 100644 --- a/doc/source/gr_sparse_vec.rst +++ b/doc/source/gr_sparse_vec.rst @@ -68,10 +68,10 @@ Types and basic access Reallocate the storage in *vec* down the current number of nonzeros. -.. function:: int gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx) +.. function:: int gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, truth_t is_canonical, gr_ctx_t ctx) Construct *vec* from the sparse data given by *inds* and *entries* of length *nnz*. - If ``is_canonical`` is true, the indices are assumed to be sorted and unique, and + If ``is_canonical`` is `T_TRUE`, the indices are assumed to be sorted and unique, and the entries are assumed to be nonzero. Otherwise, the function will sort and compress the entries to leave the vector in sorted, unique, nonzero form. diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 464546b835..38a622151b 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -65,7 +65,7 @@ typedef struct ulong * rows; ulong * cols; gr_ptr nzs; - int is_canonical; + truth_t is_canonical; } gr_coo_mat_struct; @@ -155,6 +155,22 @@ gr_coo_mat_row_ptr(gr_coo_mat_t mat, slong nz_idx) return GR_COO_MAT_ROW(mat, nz_idx); } +GR_SPARSE_MAT_INLINE const ulong * +gr_coo_mat_row_srcptr(const gr_coo_mat_t mat, slong nz_idx) +{ + if (nz_idx < 0 || nz_idx >= mat->nnz) + return NULL; + return GR_COO_MAT_ROW(mat, nz_idx); +} + +GR_SPARSE_MAT_INLINE const ulong * +gr_coo_mat_col_ptr(gr_coo_mat_t mat, slong nz_idx) +{ + if (nz_idx < 0 || nz_idx >= mat->nnz) + return NULL; + return GR_COO_MAT_COL(mat, nz_idx); +} + GR_SPARSE_MAT_INLINE const ulong * gr_coo_mat_col_srcptr(const gr_coo_mat_t mat, slong nz_idx) { @@ -217,9 +233,10 @@ gr_lil_mat_init(gr_lil_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) { GR_SPARSE_MAT_INLINE void gr_coo_mat_init(gr_coo_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) { - memset(mat, 0, sizeof(gr_lil_mat_t)); + memset(mat, 0, sizeof(gr_coo_mat_t)); mat->r = rows; mat->c = cols; + mat->is_canonical = T_TRUE; } GR_SPARSE_MAT_INLINE void @@ -274,43 +291,31 @@ gr_coo_mat_swap(gr_coo_mat_t mat1, gr_coo_mat_t mat2, gr_ctx_t ctx) FLINT_SWAP(gr_coo_mat_struct, *mat1, *mat2); } -void -gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx); - -void -gr_lil_mat_fit_nnz(gr_coo_mat_t mat, slong *nnz, gr_ctx_t ctx); +void gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx); +void gr_lil_mat_fit_nnz(gr_coo_mat_t mat, slong *nnz, gr_ctx_t ctx); +void gr_coo_mat_fit_nnz(gr_coo_mat_t mat, slong nnz, gr_ctx_t ctx); -void -gr_coo_mat_fit_nnz(gr_coo_mat_t mat, slong nnz, gr_ctx_t ctx); +void gr_csr_mat_shrink_to_nnz(gr_csr_mat_t mat, gr_ctx_t ctx); +void gr_lil_mat_shrink_to_nnz(gr_lil_mat_t mat, gr_ctx_t ctx); +void gr_coo_mat_shrink_to_nnz(gr_coo_mat_t mat, gr_ctx_t ctx); -void -gr_csr_mat_shrink_to_nnz(gr_csr_mat_t mat, gr_ctx_t ctx); -void -gr_lil_mat_shrink_to_nnz(gr_lil_mat_t mat, gr_ctx_t ctx); +void gr_csr_mat_set_cols(gr_csr_mat_t mat, slong cols, gr_ctx_t ctx); +void gr_lil_mat_set_cols(gr_lil_mat_t mat, slong cols, gr_ctx_t ctx); +void gr_coo_mat_set_cols(gr_coo_mat_t mat, slong cols, gr_ctx_t ctx); -void -gr_coo_mat_shrink_to_nnz(gr_coo_mat_t mat, gr_ctx_t ctx); +int gr_coo_mat_from_entries(gr_coo_mat_t mat, ulong *rows, ulong *cols, gr_srcptr entries, slong nnz, truth_t is_canonical, gr_ctx_t ctx); +truth_t gr_coo_mat_is_canonical(gr_coo_mat_t mat, gr_ctx_t ctx); -void -gr_csr_mat_set_cols(gr_csr_mat_t mat, slong cols, gr_ctx_t ctx); +int gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx); -void -gr_lil_mat_set_cols(gr_lil_mat_t mat, slong cols, gr_ctx_t ctx); - -void -gr_coo_mat_set_cols(gr_coo_mat_t mat, slong cols, gr_ctx_t ctx); - -int -gr_coo_mat_from_entries(gr_coo_mat_t mat, ulong *rows, ulong *cols, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx); - -int -gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx); +WARN_UNUSED_RESULT int +gr_coo_mat_randtest(gr_coo_mat_t mat, slong nnz, int replacement, truth_t is_canonical, flint_rand_t state, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_coo_mat_randtest(gr_coo_mat_t mat, ulong nnz, flint_rand_t state, gr_ctx_t ctx); +gr_coo_mat_randtest_prob(gr_coo_mat_t mat, double prob, flint_rand_t state, gr_ctx_t ctx); /** * Getting, setting, and conversion @@ -332,7 +337,7 @@ GR_SPARSE_MAT_INLINE void _gr_coo_mat_borrow_row(gr_sparse_vec_t res, gr_coo_mat_t mat, slong r, gr_ctx_t ctx) { ulong offset, nnz; - if (!mat->is_canonical) + if (mat->is_canonical == T_FALSE) gr_coo_mat_canonicalize(mat, ctx); // Binary search to find start and end of row @@ -346,32 +351,17 @@ _gr_coo_mat_borrow_row(gr_sparse_vec_t res, gr_coo_mat_t mat, slong r, gr_ctx_t res->nzs = GR_ENTRY(mat->nzs, offset, ctx->sizeof_elem); } -gr_ptr -gr_csr_mat_find_entry(gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx); - -gr_ptr -gr_lil_mat_find_entry(gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx); - -gr_ptr -gr_coo_mat_find_entry(gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_coo_mat_get_entry(gr_ptr res, gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx); - -WARN_UNUSED_RESULT int -gr_csr_mat_set_entry(gr_csr_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); +gr_ptr gr_csr_mat_find_entry(gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx); +gr_ptr gr_lil_mat_find_entry(gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx); +gr_ptr gr_coo_mat_find_entry(gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx); -WARN_UNUSED_RESULT int -gr_lil_mat_set_entry(gr_lil_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_get_entry(gr_ptr res, gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx); -WARN_UNUSED_RESULT int -gr_coo_mat_set_entry(gr_coo_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_set_entry(gr_csr_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_set_entry(gr_lil_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_set_entry(gr_coo_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx); GR_SPARSE_MAT_INLINE void @@ -620,7 +610,7 @@ gr_lil_mat_is_zero(const gr_lil_mat_t mat, gr_ctx_t ctx) GR_SPARSE_MAT_INLINE truth_t gr_coo_mat_is_zero(gr_coo_mat_t mat, gr_ctx_t ctx) { - if (!mat->is_canonical) + if (mat->is_canonical == T_FALSE) gr_coo_mat_canonicalize(mat, ctx); return _gr_vec_is_zero(mat->nzs, mat->nnz, ctx); } diff --git a/src/gr_sparse_mat/canonicalize.c b/src/gr_sparse_mat/canonicalize.c index b62931fcb4..e4c3801059 100644 --- a/src/gr_sparse_mat/canonicalize.c +++ b/src/gr_sparse_mat/canonicalize.c @@ -46,8 +46,26 @@ static sparse_mat_index_t * _sort_coords(ulong * rows, ulong * cols, slong num) return si; } -int -gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx) +truth_t gr_coo_mat_is_canonical(gr_coo_mat_t mat, gr_ctx_t ctx) +{ + slong i, sz; + gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); + sz = ctx->sizeof_elem; + + for (i = 0; i < mat->nnz; ++i) + { + // Check that indices are unique and in order + if (i > 0 && (mat->rows[i] < mat->rows[i-1] || (mat->rows[i] == mat->rows[i-1] && mat->cols[i] <= mat->cols[i-1]))) + return T_FALSE; + + // Check that entries are not known to be zero + if (is_zero(GR_ENTRY(mat->nzs, i, sz), ctx) == T_TRUE) + return T_FALSE; + } + return T_TRUE; +} + +int gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx) { slong i, j, k, sz, nnz; int status = GR_SUCCESS; @@ -56,11 +74,13 @@ gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx) gr_ptr entry; gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); - if (mat->is_canonical) + if (mat->is_canonical == T_TRUE) return GR_SUCCESS; sz = ctx->sizeof_elem; + //gr_coo_mat_print_nz(mat, ctx); + // Get sorted order for matrices indices (and inverse mapping) si = _sort_coords(mat->rows, mat->cols, mat->nnz); inv_si = flint_malloc(mat->nnz * sizeof(ulong)); @@ -85,6 +105,7 @@ gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx) } flint_free(si); flint_free(inv_si); + //gr_coo_mat_print_nz(mat, ctx); // Compress duplicated entries nnz = 0; @@ -101,9 +122,16 @@ gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx) entry = GR_ENTRY(mat->nzs, nnz, sz); ++nnz; } + mat->rows[nnz-1] = mat->rows[i]; + mat->cols[nnz-1] = mat->cols[i]; status |= gr_set(entry, GR_ENTRY(mat->nzs, i, sz), ctx); } } + if (entry != NULL && is_zero(entry, ctx) == T_TRUE) + --nnz; + mat->nnz = nnz; + //gr_coo_mat_print_nz(mat, ctx); + mat->is_canonical = gr_coo_mat_is_canonical(mat, ctx); return status; } diff --git a/src/gr_sparse_mat/equal.c b/src/gr_sparse_mat/equal.c index 222e2006f2..2f939f5b0d 100644 --- a/src/gr_sparse_mat/equal.c +++ b/src/gr_sparse_mat/equal.c @@ -13,21 +13,34 @@ truth_t gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx) +{ + if + ( + gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE || + mat1->nnz != mat2->nnz || + memcmp(mat1->rows, mat2->rows, mat1->r * sizeof(ulong)) || + memcmp(mat1->cols, mat2->cols, mat1->nnz * sizeof(ulong)) + ) + { + return T_FALSE; + } + return _gr_vec_equal(mat1->nzs, mat2->nzs, mat1->nnz, ctx); +} + +truth_t +gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) { slong row; - gr_sparse_vec_t tmp1, tmp2; truth_t row_is_eq; truth_t ret = T_TRUE; - if (gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE) + if (gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE || mat1->nnz != mat2->nnz) { return T_FALSE; } for (row = 0; row < mat1->r; row++) { - _gr_csr_mat_borrow_row(tmp1, mat1, row, ctx); - _gr_csr_mat_borrow_row(tmp2, mat2, row, ctx); - row_is_eq = gr_sparse_vec_equal(tmp1, tmp2, ctx); + row_is_eq = gr_sparse_vec_equal(&mat1->rows[row], &mat2->rows[row], ctx); if (row_is_eq == T_FALSE) return T_FALSE; else if (row_is_eq == T_UNKNOWN) @@ -36,26 +49,28 @@ gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx) return ret; } -truth_t -gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) +truth_t gr_coo_mat_equal(const gr_coo_mat_t mat1, const gr_coo_mat_t mat2, gr_ctx_t ctx) { - slong row; - truth_t row_is_eq; - truth_t ret = T_TRUE; + slong i; if (gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE) { return T_FALSE; } - for (row = 0; row < mat1->r; row++) + if (mat1->is_canonical == T_FALSE || mat2->is_canonical == T_FALSE) { - row_is_eq = gr_sparse_vec_equal(&mat1->rows[row], &mat2->rows[row], ctx); - if (row_is_eq == T_FALSE) - return T_FALSE; - else if (row_is_eq == T_UNKNOWN) - ret = T_UNKNOWN; + return T_UNKNOWN; } - return ret; + if + ( + mat1->nnz != mat2->nnz || + memcmp(mat1->rows, mat2->rows, mat1->nnz * sizeof(ulong)) || + memcmp(mat1->cols, mat2->cols, mat1->nnz * sizeof(ulong)) + ) + { + return T_FALSE; + } + return _gr_vec_equal(mat1->nzs, mat2->nzs, mat1->nnz, ctx); } truth_t @@ -66,7 +81,7 @@ gr_csr_mat_equal_lil_mat(const gr_csr_mat_t mat1, const gr_lil_mat_t mat2, gr_ct truth_t row_is_eq; truth_t ret = T_TRUE; - if (gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE) + if (gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE || mat1->nnz != mat2->nnz) { return T_FALSE; } diff --git a/src/gr_sparse_mat/from_entries.c b/src/gr_sparse_mat/from_entries.c index 06d7f6019c..3a8f4d6bcc 100644 --- a/src/gr_sparse_mat/from_entries.c +++ b/src/gr_sparse_mat/from_entries.c @@ -11,19 +11,18 @@ static int check_coords(ulong * rows, ulong * cols, slong num, slong r, slong c) return 1; } -int -gr_coo_mat_from_entries(gr_coo_mat_t mat, ulong *rows, ulong *cols, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx) +int gr_coo_mat_from_entries(gr_coo_mat_t mat, ulong *rows, ulong *cols, gr_srcptr entries, slong nnz, truth_t is_canonical, gr_ctx_t ctx) { int status; if (!check_coords(rows, cols, nnz, mat->r, mat->c)) return GR_DOMAIN; - mat->nnz = nnz; gr_coo_mat_fit_nnz(mat, nnz, ctx); memcpy(mat->rows, rows, nnz * sizeof(ulong)); memcpy(mat->cols, cols, nnz * sizeof(ulong)); status = _gr_vec_set(mat->nzs, entries, nnz, ctx); + mat->nnz = nnz; mat->is_canonical = is_canonical; return status; } diff --git a/src/gr_sparse_mat/get_entry.c b/src/gr_sparse_mat/get_entry.c index dd71a9f914..06aa605083 100644 --- a/src/gr_sparse_mat/get_entry.c +++ b/src/gr_sparse_mat/get_entry.c @@ -9,8 +9,7 @@ static int ulong_cmp(const void* a, const void* b) return (av < bv ? -1 : (av > bv ? 1 : 0)); } -gr_ptr -gr_csr_mat_find_entry(gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx) +gr_ptr gr_csr_mat_find_entry(gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx) { slong sz = ctx->sizeof_elem; ulong* bs = NULL; @@ -34,27 +33,63 @@ gr_lil_mat_find_entry(gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx) return gr_sparse_vec_find_entry(&mat->rows[row], col, ctx); } -int -gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx) +gr_ptr gr_coo_mat_find_entry(gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx) { + slong i, lower, upper; slong sz = ctx->sizeof_elem; - ulong* bs = NULL; if (row < 0 || row >= mat->r || col < 0 || col >= mat->c) - return GR_DOMAIN; + return NULL; - bs = bsearch(&col, mat->cols + mat->rows[row], mat->rows[row+1] - mat->rows[row], sizeof(ulong), ulong_cmp); + if (mat->is_canonical) + { + // Find using (manual) binary search + lower = 0; + upper = mat->nnz; + while (lower <= upper) + { + i = (lower + upper)/2; + if (mat->rows[i] < row || (mat->rows[i] == row && mat->cols[i] < col)) + lower = i + 1; + else if (mat->rows[i] > row || (mat->rows[i] == row && mat->cols[i] > col)) + upper = i - 1; + else + return GR_ENTRY(mat->nzs, i, sz); + } + } + else + { + // Exhaust to find first instance + for (i = 0; i < mat->nnz; ++i) + if (mat->rows[i] == row && mat->cols[i] == col) + return GR_ENTRY(mat->nzs, i, sz); + } + return NULL; +} - if (bs == NULL) +int gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx) +{ + gr_ptr ptr = gr_csr_mat_find_entry(mat, row, col, ctx); + + if (ptr == NULL) return gr_zero(res, ctx); - return gr_set(res, GR_ENTRY(mat->nzs, bs - mat->cols, sz), ctx); + return gr_set(res, ptr, ctx); } -int -gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx) +int gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx) { - if (row < 0 || row >= mat->r) - return GR_DOMAIN; + gr_ptr ptr = gr_lil_mat_find_entry(mat, row, col, ctx); + + if (ptr == NULL) + return gr_zero(res, ctx); + return gr_set(res, ptr, ctx); +} - return gr_sparse_vec_get_entry(res, &mat->rows[row], col, ctx); +int gr_coo_mat_get_entry(gr_ptr res, gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx) +{ + gr_ptr ptr = gr_coo_mat_find_entry(mat, row, col, ctx); + + if (ptr == NULL) + return gr_zero(res, ctx); + return gr_set(res, ptr, ctx); } diff --git a/src/gr_sparse_mat/permute_cols.c b/src/gr_sparse_mat/permute_cols.c index 92ce520c36..7b921618dd 100644 --- a/src/gr_sparse_mat/permute_cols.c +++ b/src/gr_sparse_mat/permute_cols.c @@ -48,7 +48,7 @@ int gr_coo_mat_permute_cols(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx) { mat->cols[nz_idx] = perm[mat->cols[nz_idx]]; } - if (mat->is_canonical) + if (mat->is_canonical == T_TRUE) { gr_coo_mat_canonicalize(mat, ctx); } diff --git a/src/gr_sparse_mat/randtest.c b/src/gr_sparse_mat/randtest.c new file mode 100644 index 0000000000..c69b6151c0 --- /dev/null +++ b/src/gr_sparse_mat/randtest.c @@ -0,0 +1,119 @@ +#include +#include "gr_sparse_mat.h" + +static int +slong_cmp(const void * a, const void * b) +{ + slong ax = *((slong *) a); + slong bx = *((slong *) b); + return ax - bx; +} + + +int gr_coo_mat_randtest(gr_coo_mat_t mat, slong nnz, int replacement, truth_t is_canonical, flint_rand_t state, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong i, j, sz, len; + sz = ctx->sizeof_elem; + len = mat->r * mat->c; + + if (nnz < 0 || nnz > mat->r * mat->c) + return GR_DOMAIN; + + // Make space + gr_coo_mat_fit_nnz(mat, nnz, ctx); + + if (replacement) + { + // Randomly sample nnz locations with replacement + for (i = 0; i < nnz; ++i) + mat->cols[i] = n_randint(state, len); + + // If canonical, sort and compress + if (is_canonical == T_TRUE) + { + qsort(mat->cols, nnz, sizeof(slong), slong_cmp); + + j = 0; + for (i = 0; i < nnz; ++i) + if (i == 0 || mat->cols[i] != mat->cols[i-1]) + mat->cols[j++] = mat->cols[i]; + mat->nnz = j; + } + else + mat->nnz = nnz; + } + else + { + // Randomly sample nnz columns without replacement + for (i = 0; i < len; ++i) + { + j = i < nnz ? i : n_randint(state, i+1); + if (j < nnz) mat->cols[j] = i; + } + if (is_canonical == T_TRUE && nnz < len) + qsort(mat->cols, nnz, sizeof(slong), slong_cmp); + mat->nnz = nnz; + } + + for (i = 0; i < nnz; ++i) + { + mat->rows[i] = mat->cols[i] / mat->c; + mat->cols[i] %= mat->c; + } + mat->is_canonical = is_canonical; + + for (i = 0; i < mat->nnz; ++i) + { + if (is_canonical == T_TRUE) + status |= gr_randtest_not_zero(GR_ENTRY(mat->nzs, i, sz), state, ctx); + else + status |= gr_randtest(GR_ENTRY(mat->nzs, i, sz), state, ctx); + } + return status; +} + +int +gr_coo_mat_randtest_prob(gr_coo_mat_t mat, double prob, flint_rand_t state, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong i, j, sz; + sz = ctx->sizeof_elem; + + if (prob < 0 || prob > 1) + return GR_DOMAIN; + + // Handle corner cases + if (prob == 0) + { + gr_coo_mat_zero(mat, ctx); + return GR_SUCCESS; + } + if (prob == 1) + { + status |= gr_coo_mat_randtest(mat, mat->r * mat->c, 0, T_TRUE, state, ctx); + return status; + } + + // Allocate space for expected number of nonzeroes, and expand as needed + gr_coo_mat_fit_nnz(mat, prob * mat->r * mat->c, ctx); + + // TODO: for low probability, should be able to do this faster + mat->nnz = 0; + for (i = 0; i < mat->r; ++i) + { + for (j = 0; j < mat->c; ++j) + { + if (n_randint(state, 0) < 2 * prob * WORD_MAX) + { + if (mat->nnz == mat->alloc) + gr_coo_mat_fit_nnz(mat, mat->alloc * 2, ctx); + status |= gr_randtest_not_zero(GR_ENTRY(mat->nzs, mat->nnz, sz), state, ctx); + mat->rows[mat->nnz] = i; + mat->cols[mat->nnz++] = j; + } + } + } + mat->is_canonical = T_TRUE; + return status; +} diff --git a/src/gr_sparse_mat/set.c b/src/gr_sparse_mat/set.c index 942a935c5e..8d97ad6d8b 100644 --- a/src/gr_sparse_mat/set.c +++ b/src/gr_sparse_mat/set.c @@ -164,7 +164,7 @@ int gr_csr_mat_set_coo_mat(gr_csr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct sz = ctx->sizeof_elem; gr_csr_mat_fit_nnz(dst, src->nnz, ctx); - if (src->is_canonical) + if (src->is_canonical == T_TRUE) { // Just copy over the data and set the row offsets dst->rows[0] = 0; @@ -172,10 +172,12 @@ int gr_csr_mat_set_coo_mat(gr_csr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct for (i = 0; i < src->nnz; ++i) while (row != src->rows[i]) dst->rows[++row] = i; + while (row < dst->r) + dst->rows[++row] = i; - dst->rows[dst->r] = src->nnz; memcpy(dst->cols, src->cols, src->nnz * sizeof(ulong)); status |= _gr_vec_set(dst->nzs, src->nzs, src->nnz, ctx); + //_gr_vec_print(dst->nzs, src->nnz, ctx); dst->nnz = src->nnz; } else @@ -218,7 +220,7 @@ int gr_csr_mat_set_coo_mat(gr_csr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct int gr_lil_mat_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) { - slong i, prev_i, sz, nnz, row, row_start_idx, row_end_idx; + slong i, sz, nnz, row, row_start_idx, row_end_idx; int status = GR_SUCCESS; sparse_mat_index_t * si; gr_method_unary_predicate is_zero = GR_UNARY_PREDICATE(ctx, IS_ZERO); @@ -234,17 +236,18 @@ int gr_lil_mat_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct } sz = ctx->sizeof_elem; - if (src->is_canonical) + if (src->is_canonical == T_TRUE) { - prev_i = i = 0; + row_start_idx = row_end_idx = 0; for (row = 0; row < dst->r; ++row) { - while (i < src->nnz && src->rows[i] == row) ++i; + while (row_end_idx < src->nnz && src->rows[row_end_idx] == row) ++row_end_idx; status |= gr_sparse_vec_from_entries( - &dst->rows[row], src->cols + prev_i, GR_ENTRY(src->nnz, prev_i, sz), i - prev_i, 1, ctx + &dst->rows[row], src->cols + row_start_idx, GR_ENTRY(src->nzs, row_start_idx, sz), row_end_idx - row_start_idx, T_TRUE, ctx ); - prev_i = i; + row_start_idx = row_end_idx; } + dst->nnz = src->nnz; } else { @@ -253,6 +256,7 @@ int gr_lil_mat_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct // Construct rows one by one row_start_idx = 0; + dst->nnz = 0; for (row = 0; row < dst->r; ++row) { // Get range of indicies in current row and estimate of nonzeroes @@ -282,10 +286,12 @@ int gr_lil_mat_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct ++nnz; } // Store to entry and update current column + dst->rows[row].inds[nnz - 1] = si[i].col; status |= gr_set(entry, si[i].entry, ctx); } } dst->rows[row].nnz = nnz; + dst->nnz += nnz; row_start_idx = row_end_idx; } } @@ -298,6 +304,7 @@ int gr_coo_mat_set_lil_mat(gr_coo_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ct ulong row, i; slong sz; int status = GR_SUCCESS; + gr_sparse_vec_struct *vec; if (gr_mat_is_compatible(dst, src, ctx) == T_FALSE) return GR_DOMAIN; @@ -308,15 +315,16 @@ int gr_coo_mat_set_lil_mat(gr_coo_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ct dst->nnz = 0; for(row = 0; row < src->r; row++) { - for (i = 0; i < src->rows[row].nnz; ++i) + vec = &src->rows[row]; + for (i = 0; i < vec->nnz; ++i) dst->rows[dst->nnz + i] = row; - memcpy(dst->cols + dst->nnz, src->rows[i].inds, src->rows[i].nnz); - status |= _gr_vec_set(GR_ENTRY(dst->nzs, dst->nnz, sz), src->rows[i].nzs, src->rows[i].nnz, ctx); - dst->nnz += src->rows[i].nnz; + memcpy(dst->cols + dst->nnz, vec->inds, vec->nnz * sizeof(ulong)); + status |= _gr_vec_set(GR_ENTRY(dst->nzs, dst->nnz, sz), vec->nzs, vec->nnz, ctx); + dst->nnz += vec->nnz; } dst->nnz = src->nnz; - dst->is_canonical = 1; + dst->is_canonical = T_TRUE; return status; } @@ -333,10 +341,10 @@ int gr_coo_mat_set_csr_mat(gr_coo_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ct dst->nnz = 0; for(row = 0; row < dst->r; ++row) while (dst->nnz < src->rows[row + 1]) - src->rows[dst->nnz++] = row; + dst->rows[dst->nnz++] = row; memcpy(dst->cols, src->cols, src->nnz * sizeof(ulong)); status |= _gr_vec_set(dst->nzs, src->nzs, src->nnz, ctx); - dst->is_canonical = 1; + dst->is_canonical = T_TRUE; return status; } diff --git a/src/gr_sparse_mat/test/main.c b/src/gr_sparse_mat/test/main.c new file mode 100644 index 0000000000..20cf241726 --- /dev/null +++ b/src/gr_sparse_mat/test/main.c @@ -0,0 +1,21 @@ +#include +#include + +/* Include functions *********************************************************/ + +#include "t-init.c" +#include "t-conversion.c" +#include "t-randtest.c" + +/* Array of test functions ***************************************************/ + +test_struct tests[] = +{ + TEST_FUNCTION(gr_sparse_mat_init), + TEST_FUNCTION(gr_sparse_mat_conversion), + TEST_FUNCTION(gr_sparse_mat_randtest), +}; + +/* main function *************************************************************/ + +TEST_MAIN(tests) diff --git a/src/gr_sparse_mat/test/t-conversion.c b/src/gr_sparse_mat/test/t-conversion.c new file mode 100644 index 0000000000..8932d392db --- /dev/null +++ b/src/gr_sparse_mat/test/t-conversion.c @@ -0,0 +1,152 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_mat.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int test_conversion(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + slong M = 20; + slong N = 20; + slong n_tests = 20; + int status = GR_SUCCESS; + gr_coo_mat_t mat, mat2; + gr_csr_mat_t csr_mat, csr_mat2; + gr_lil_mat_t lil_mat, lil_mat2; + gr_mat_t dmat, dmat2; + + gr_mat_init(dmat, M, N, ctx); + gr_mat_init(dmat2, M, N, ctx); + gr_coo_mat_init(mat, M, N, ctx); + gr_coo_mat_init(mat2, M, N, ctx); + gr_csr_mat_init(csr_mat, M, N, ctx); + gr_csr_mat_init(csr_mat2, M, N, ctx); + gr_lil_mat_init(lil_mat, M, N, ctx); + gr_lil_mat_init(lil_mat2, M, N, ctx); + + //flint_printf("Testing copy\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_coo_mat_randtest(mat, 40, 0, T_TRUE, state, ctx); + status |= gr_coo_mat_set(mat2, mat, ctx); + if (gr_coo_mat_equal(mat, mat2, ctx) == T_FALSE) + { + status |= gr_coo_mat_print_nz(mat, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(mat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + //flint_printf("Testing from/to dense mat\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_mat_randtest(dmat, state, ctx); + status |= gr_coo_mat_set_mat(mat, dmat, ctx); + status |= gr_mat_set_coo_mat(dmat2, mat, ctx); + if (T_FALSE == gr_mat_equal(dmat, dmat2, ctx)) + { + status |= gr_mat_print(dmat, ctx); flint_printf("\n"); + status |= gr_mat_print(dmat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + //flint_printf("Testing from/to sparse mat\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_coo_mat_randtest(mat, 10, 0, T_TRUE, state, ctx); + status |= gr_mat_set_coo_mat(dmat, mat, ctx); + status |= gr_coo_mat_set_mat(mat2, dmat, ctx); + if (T_FALSE == gr_coo_mat_equal(mat, mat2, ctx)) + { + status |= gr_coo_mat_print_nz(mat, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(mat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + //flint_printf("Testing coo -> csr -> lil -> coo\n"); + for (i = 0; i < 2 * n_tests; i++) + { + status |= gr_coo_mat_randtest(mat, 10, 0, (i % 2) ? T_FALSE : T_TRUE, state, ctx); + //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat, ctx); + status |= gr_csr_mat_set_coo_mat(csr_mat, mat, ctx); + //flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); + status |= gr_lil_mat_set_csr_mat(lil_mat, csr_mat, ctx); + //flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); + status |= gr_coo_mat_set_lil_mat(mat2, lil_mat, ctx); + //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat2, ctx); + status |= gr_csr_mat_set_coo_mat(csr_mat2, mat2, ctx); + //flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat2, ctx); + if (T_FALSE == gr_csr_mat_equal(csr_mat, csr_mat2, ctx)) + { + status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\n"); + status |= gr_csr_mat_print_nz(csr_mat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + //flint_printf("Testing coo -> lil -> csr -> coo\n"); + for (i = 0; i < 2 * n_tests; i++) + { + status |= gr_coo_mat_randtest(mat, 10, 0, (i % 2) ? T_FALSE : T_TRUE, state, ctx); + //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat, ctx); flint_printf("\nnnz = %d\n", mat->nnz); + status |= gr_lil_mat_set_coo_mat(lil_mat, mat, ctx); + //flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\nnnz = %d\n", lil_mat->nnz); + status |= gr_csr_mat_set_lil_mat(csr_mat, lil_mat, ctx); + //flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\nnnz = %d\n", csr_mat->nnz); + status |= gr_coo_mat_set_csr_mat(mat2, csr_mat, ctx); + //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat2, ctx); flint_printf("\nnnz = %d\n", mat2->nnz); + status |= gr_lil_mat_set_coo_mat(lil_mat2, mat2, ctx); + //flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat2, ctx); flint_printf("\nnnz = %d\n", lil_mat2->nnz); + if (T_FALSE == gr_lil_mat_equal(lil_mat, lil_mat2, ctx)) + { + status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\n"); + status |= gr_lil_mat_print_nz(lil_mat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + gr_csr_mat_clear(csr_mat, ctx); + gr_csr_mat_clear(csr_mat2, ctx); + gr_lil_mat_clear(lil_mat, ctx); + gr_lil_mat_clear(lil_mat2, ctx); + gr_coo_mat_clear(mat, ctx); + gr_coo_mat_clear(mat2, ctx); + gr_mat_clear(dmat, ctx); + gr_mat_clear(dmat2, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_mat_conversion, state) +{ + slong i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while (1) + { + //gr_ctx_init_fmpz(ctx); + gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_println(ctx); + CHECK_TEST(test_conversion(state, ctx), "Conversion between various sparse representations (and dense)"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_mat/test/t-init.c b/src/gr_sparse_mat/test/t-init.c new file mode 100644 index 0000000000..2fcadf33fa --- /dev/null +++ b/src/gr_sparse_mat/test/t-init.c @@ -0,0 +1,247 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_mat.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int test_init_csr(gr_ctx_t ctx) +{ + gr_csr_mat_t mat; + gr_csr_mat_init(mat, 5, 6, ctx); + if (mat->r != 5 || mat->c != 6 || mat->alloc != 0 || mat->nnz != 0 || mat->rows == NULL || mat->cols != NULL || mat->nzs != NULL) + { + flint_printf("Failed init CSR test\n"); + return GR_TEST_FAIL; + } + gr_csr_mat_clear(mat, ctx); + return GR_SUCCESS; +} + +int test_init_lil(gr_ctx_t ctx) +{ + gr_lil_mat_t mat; + gr_lil_mat_init(mat, 5, 6, ctx); + if (mat->r != 5 || mat->c != 6 || mat->nnz != 0 || mat->rows == NULL) + { + flint_printf("Failed init LIL test\n"); + return GR_TEST_FAIL; + } + gr_lil_mat_clear(mat, ctx); + return GR_SUCCESS; +} + +int test_init_coo(gr_ctx_t ctx) +{ + gr_coo_mat_t mat; + gr_coo_mat_init(mat, 5, 6, ctx); + if (mat->r != 5 || mat->c != 6 || mat->alloc != 0 || mat->nnz != 0 || mat->rows != NULL || mat->cols != NULL || mat->nzs != NULL || mat->is_canonical != T_TRUE) + { + flint_printf("Failed init COO test\n"); + return GR_TEST_FAIL; + } + gr_coo_mat_clear(mat, ctx); + return GR_SUCCESS; +} + +int test_init_from_entries_canonical(flint_rand_t state, gr_ctx_t ctx) +{ + // TODO: randomize length and nonzero cols + slong i; + gr_coo_mat_t mat; + gr_ptr entries; + gr_ptr temp; + int status = GR_SUCCESS; + truth_t eq; + slong sz = ctx->sizeof_elem; + slong r = 5; + slong c = 10; + slong N = 15; + ulong rows[25] = {0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4}; + ulong cols[25] = {0, 2, 3, 1, 4, 6, 8, 9, 5, 7, 0, 1, 3, 5, 6, 8, 2, 4, 7, 9}; + + //flint_printf("Running init test\n"); + GR_TMP_INIT(temp, ctx); + GR_TMP_INIT_VEC(entries, N, ctx); + for (i = 0; i < N; ++i) + status |= gr_randtest_not_zero(GR_ENTRY(entries, i, sz), state, ctx); + if (status != GR_SUCCESS) + { + flint_printf("Failed to make random numbers!\n"); + return GR_SUCCESS; // Not my fault! + } + + gr_coo_mat_init(mat, r, c, ctx); + status |= gr_coo_mat_from_entries(mat, rows, cols, entries, N, T_TRUE, ctx); + + // Check parameters + if (status != GR_SUCCESS || mat->r != r || mat->c != c || mat->alloc != 15 || mat->nnz != 15) + { + flint_printf("Bad params! %ld %ld %ld %ld\n", mat->r, mat->c, mat->alloc, mat->nnz); + return GR_TEST_FAIL; + } + + // Check indices and entries + for (i = 0; i < N; ++i) + { + if (*gr_coo_mat_row_ptr(mat, i) != rows[i]) + { + flint_printf("Bad row index!\n"); + return GR_TEST_FAIL; + } + if (*gr_coo_mat_col_ptr(mat, i) != cols[i]) + { + flint_printf("Bad column index!\n"); + return GR_TEST_FAIL; + } + eq = gr_equal(gr_coo_mat_entry_ptr(mat, i, ctx), GR_ENTRY(entries, i, sz), ctx); + if (eq == T_FALSE) + { + flint_printf("Bad elements!\n"); + return GR_TEST_FAIL; + } + } + gr_coo_mat_clear(mat, ctx); + GR_TMP_CLEAR_VEC(entries, N, ctx); + return status; +} + +int test_init_from_entries_internal(ulong *rows, ulong *cols, gr_srcptr entries, slong r, slong c, slong num, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + slong i, j, k; + gr_coo_mat_t mat; + gr_ptr temp, temp2, temp3; + + ///flint_printf("\n\n\nRunning internal test\n"); + GR_TMP_INIT2(temp, temp2, ctx); + gr_coo_mat_init(mat, r, c, ctx); + status |= gr_coo_mat_from_entries(mat, rows, cols, entries, num, T_FALSE, ctx); + if (status != GR_SUCCESS) + return GR_TEST_FAIL; + + gr_coo_mat_canonicalize(mat, ctx); + if (mat->is_canonical == T_FALSE) + return GR_TEST_FAIL; + + // Check every entry (including the zeroes) + for (i = 0; i < r; i++) + { + for (j = 0; j < c; j++) + { + // Compute the expected value of the entry + status |= gr_zero(temp, ctx); + for (k = 0; k < num; k++) + if (rows[k] == i && cols[k] == j) + status |= gr_add(temp, temp, GR_ENTRY(entries, k, sz), ctx); + + status |= gr_coo_mat_get_entry(temp2, mat, i, j, ctx); + temp3 = gr_coo_mat_find_entry(mat, i, j, ctx); + if ( + gr_equal(temp, temp2, ctx) == T_FALSE || + (temp3 == NULL && gr_is_zero(temp, ctx) == T_FALSE) || + (temp3 != NULL && gr_is_zero(temp3, ctx) == T_TRUE) || + (temp3 != NULL && gr_equal(temp, temp3, ctx) == T_FALSE) + ) + { + flint_printf("Failed on %d!\n", i); + gr_println(temp, ctx); + gr_println(temp2, ctx); + flint_printf("%p\n", temp3); + if (temp3 != NULL) + gr_println(temp3, ctx); + return GR_TEST_FAIL; + } + } + } + GR_TMP_CLEAR2(temp, temp2, ctx); + gr_coo_mat_clear(mat, ctx); + return status; +} + +int test_init_from_entries(flint_rand_t state, gr_ctx_t ctx) +{ + slong i, j; + int status = GR_SUCCESS; + slong r = 5; + slong c = 10; + slong N = 20; + ulong rows[20] = {0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4}; + ulong cols[20] = {0, 2, 3, 1, 4, 6, 8, 9, 5, 7, 0, 1, 3, 5, 6, 8, 2, 4, 7, 9}; + gr_ptr entries; + GR_TMP_INIT_VEC(entries, N, ctx); + status |= _gr_vec_randtest(entries, state, N, ctx); + + // Randomly permute the rows and columns + for (i = 0; i < N; ++i) + { + j = n_randint(state, N); + FLINT_SWAP(ulong, rows[i], rows[j]); + j = n_randint(state, N); + FLINT_SWAP(ulong, cols[i], cols[j]); + } + status |= test_init_from_entries_internal(rows, cols, entries, r, c, N, ctx); + + GR_TMP_CLEAR_VEC(entries, N, ctx); + return status; +} + +int test_init_from_entries_adversarial(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + int status = GR_SUCCESS; + slong sz = ctx->sizeof_elem; + slong r = 5; + slong c = 10; + slong N = 20; + ulong rows[20] = {1, 0, 3, 4, 2, 1, 4, 1, 3, 2, 3, 3, 4, 0, 0, 1, 2, 4, 3, 0}; + ulong cols[20] = {0, 2, 3, 1, 4, 8, 8, 0, 5, 7, 0, 3, 3, 5, 6, 8, 4, 2, 5, 9}; + slong ents[20] = {-1, 3, 1, 2, 0, 6, 4, 1, 3, 1, -4, -1, 2, 9, 1, -6, 4, 0, -2, 4}; + + gr_ptr entries; + GR_TMP_INIT_VEC(entries, N, ctx); + + for (i = 0; i < N; i++) + status |= gr_set_si(GR_ENTRY(entries, i, sz), ents[i], ctx); + status |= test_init_from_entries_internal(rows, cols, entries, r, c, N, ctx); + + GR_TMP_CLEAR_VEC(entries, N, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_mat_init, state) +{ + int i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while(1) + { + //gr_ctx_init_fmpz(ctx); + gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_println(ctx); + CHECK_TEST(test_init_csr(ctx), "Init CSR matrix") + CHECK_TEST(test_init_lil(ctx), "Init LIL matrix") + CHECK_TEST(test_init_coo(ctx), "Init COO matrix") + CHECK_TEST(test_init_from_entries_canonical(state, ctx), "Init from entries in canonical form"); + CHECK_TEST(test_init_from_entries(state, ctx), "Init from entries in noncanonical order"); + CHECK_TEST(test_init_from_entries_adversarial(state, ctx), "Init from entries in adversarial order"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_mat/test/t-randtest.c b/src/gr_sparse_mat/test/t-randtest.c new file mode 100644 index 0000000000..026fdf78af --- /dev/null +++ b/src/gr_sparse_mat/test/t-randtest.c @@ -0,0 +1,79 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_mat.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int test_randtest(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + slong M = 16; + slong N = 64; + slong n_tests = 10; + int status = GR_SUCCESS; + gr_coo_mat_t mat; + gr_coo_mat_init(mat, M, N, ctx); + + //flint_printf("Testing w/o replacement\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_coo_mat_randtest(mat, 128, 0, T_TRUE, state, ctx); + if (gr_coo_mat_is_canonical(mat, ctx) == T_FALSE || mat->nnz != 128) + return GR_TEST_FAIL; + } + + //flint_printf("Testing w/ replacement\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_coo_mat_randtest(mat, 32, 1, T_TRUE, state, ctx); + if (gr_coo_mat_is_canonical(mat, ctx) == T_FALSE || mat->nnz > 32 || mat->nnz < 24) + return GR_TEST_FAIL; + } + + //flint_printf("Testing w/ prob\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_coo_mat_randtest_prob(mat, 0.125, state, ctx); + if (gr_coo_mat_is_canonical(mat, ctx) == T_FALSE || mat->nnz > 192 || mat->nnz < 64) + { + status |= gr_coo_mat_print_nz(mat, ctx); flint_printf("%ld\n", mat->nnz); + return GR_TEST_FAIL; + } + + } + gr_coo_mat_clear(mat, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_mat_randtest, state) +{ + int i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while(1) + { + //gr_ctx_init_nmod(ctx, 2147483647); + gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_print(ctx); flint_printf("\n"); + + CHECK_TEST(test_randtest(state, ctx), "Test random sparse matrix generation"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_mat/to_dense.c b/src/gr_sparse_mat/to_dense.c index 3bb4b4665b..b202c88038 100644 --- a/src/gr_sparse_mat/to_dense.c +++ b/src/gr_sparse_mat/to_dense.c @@ -66,7 +66,7 @@ int gr_mat_set_coo_mat(gr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ctx) { dst_entry = GR_MAT_ENTRY(dst, src->rows[nz], src->cols[nz], sz); src_entry = GR_ENTRY(src->nzs, nz, sz); - if (src->is_canonical) + if (src->is_canonical == T_TRUE) status |= gr_set(dst_entry, src_entry, ctx); else status |= gr_add(dst_entry, dst_entry, src_entry, ctx); diff --git a/src/gr_sparse_mat/write.c b/src/gr_sparse_mat/write.c index 8822ec8394..ace2499600 100644 --- a/src/gr_sparse_mat/write.c +++ b/src/gr_sparse_mat/write.c @@ -10,12 +10,13 @@ gr_csr_mat_write_nz(gr_stream_t out, const gr_csr_mat_t mat, gr_ctx_t ctx) gr_stream_write(out, "["); for (row = 0; row < mat->r; row++) { + gr_stream_write(out, "\n\t"); _gr_csr_mat_borrow_row(tmp, mat, row, ctx); status |= gr_sparse_vec_write_nz(out, tmp, ctx); if (row < mat->r - 1) gr_stream_write(out, ", "); } - gr_stream_write(out, "]"); + gr_stream_write(out, "\n]"); return status; } @@ -28,11 +29,12 @@ gr_lil_mat_write_nz(gr_stream_t out, const gr_lil_mat_t mat, gr_ctx_t ctx) gr_stream_write(out, "["); for (row = 0; row < mat->r; row++) { + gr_stream_write(out, "\n\t"); status |= gr_sparse_vec_write_nz(out, &mat->rows[row], ctx); if (row < mat->r - 1) gr_stream_write(out, ", "); } - gr_stream_write(out, "]"); + gr_stream_write(out, "\n]"); return status; } @@ -46,6 +48,7 @@ gr_coo_mat_write_nz(gr_stream_t out, const gr_coo_mat_t mat, gr_ctx_t ctx) gr_stream_write(out, "["); for (nz = 0; nz < mat->nnz; nz++) { + gr_stream_write(out, "\n\t"); gr_stream_write(out, "("); gr_stream_write_si(out, mat->rows[nz]); gr_stream_write(out, ", "); @@ -55,7 +58,7 @@ gr_coo_mat_write_nz(gr_stream_t out, const gr_coo_mat_t mat, gr_ctx_t ctx) if (nz < mat->nnz - 1) gr_stream_write(out, ", "); } - gr_stream_write(out, "]"); + gr_stream_write(out, "\n]"); return status; } diff --git a/src/gr_sparse_vec.h b/src/gr_sparse_vec.h index 168fa62f24..273779f011 100644 --- a/src/gr_sparse_vec.h +++ b/src/gr_sparse_vec.h @@ -71,7 +71,7 @@ void gr_sparse_vec_fit_nnz(gr_sparse_vec_t vec, slong nnz, gr_ctx_t ctx); void gr_sparse_vec_shrink_to_nnz(gr_sparse_vec_t vec, gr_ctx_t ctx); WARN_UNUSED_RESULT int -gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx); +gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, truth_t is_canonical, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_sparse_vec_randtest(gr_sparse_vec_t vec, slong nnz, int replacement, flint_rand_t state, gr_ctx_t ctx); diff --git a/src/gr_sparse_vec/from_entries.c b/src/gr_sparse_vec/from_entries.c index 192b2cfc16..c38ff76346 100644 --- a/src/gr_sparse_vec/from_entries.c +++ b/src/gr_sparse_vec/from_entries.c @@ -33,7 +33,7 @@ static sparse_vec_index_t * _sort_inds(ulong * inds, slong num) } int -gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, int is_canonical, gr_ctx_t ctx) +gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, slong nnz, truth_t is_canonical, gr_ctx_t ctx) { slong i; slong sz = ctx->sizeof_elem; @@ -47,7 +47,7 @@ gr_sparse_vec_from_entries(gr_sparse_vec_t vec, ulong * inds, gr_srcptr entries, return GR_DOMAIN; gr_sparse_vec_fit_nnz(vec, nnz, ctx); - if (is_canonical) + if (is_canonical == T_TRUE) { // Just copy data memcpy(vec->inds, inds, nnz * sizeof(ulong)); diff --git a/src/gr_sparse_vec/set.c b/src/gr_sparse_vec/set.c index 0a36abdf52..c27de46aeb 100644 --- a/src/gr_sparse_vec/set.c +++ b/src/gr_sparse_vec/set.c @@ -4,6 +4,9 @@ int gr_sparse_vec_set(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) { int status = GR_SUCCESS; + if (dst->length != src->length) + return GR_DOMAIN; + if (dst != src) { slong nnz = src->nnz; diff --git a/src/gr_sparse_vec/test/t-randtest.c b/src/gr_sparse_vec/test/t-randtest.c index 5e829a14c7..57feb5380b 100644 --- a/src/gr_sparse_vec/test/t-randtest.c +++ b/src/gr_sparse_vec/test/t-randtest.c @@ -14,8 +14,7 @@ #define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } -int -test_randtest(flint_rand_t state, gr_ctx_t ctx) +int test_randtest(flint_rand_t state, gr_ctx_t ctx) { slong i; slong N = 1024; From 1152d1593b2b885514ade5ccb9afaf222989ac77 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Wed, 20 Mar 2024 17:35:40 -0700 Subject: [PATCH 49/59] More conversion tests --- src/gr_sparse_mat/set.c | 18 ++++++++++---- src/gr_sparse_mat/test/t-conversion.c | 34 +++++++++++++-------------- src/gr_sparse_vec/from_dense.c | 4 ++-- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/gr_sparse_mat/set.c b/src/gr_sparse_mat/set.c index 8d97ad6d8b..6616bbdcc8 100644 --- a/src/gr_sparse_mat/set.c +++ b/src/gr_sparse_mat/set.c @@ -192,24 +192,30 @@ int gr_csr_mat_set_coo_mat(gr_csr_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct entry = NULL; for (i = 0; i < src->nnz; ++i) { + //flint_printf("(%d, %d)\n", si[i].row, si[i].col); + // Check if we can just accumulate if(i > 0 && si[i-1].row == si[i].row && si[i-1].col == si[i].col) status |= gr_add(entry, entry, si[i].entry, ctx); else { + // Advance row offsets as needed + // If previous entry does not exist or is not zero, advance to the next one if (entry == NULL || is_zero(entry, ctx) != T_TRUE) { entry = GR_ENTRY(dst->nzs, nnz, sz); ++nnz; } - status |= gr_set(entry, si[i].entry, ctx); - - // Advance row offsets as needed while (row != si[i].row) - dst->rows[++row] = nnz; + dst->rows[++row] = nnz - 1; + dst->cols[nnz - 1] = si[i].col; + status |= gr_set(entry, si[i].entry, ctx); } } + if (entry != NULL && is_zero(entry, ctx) == T_TRUE) + --nnz; + // Set remaining row offsets and overall number of nonzeroes while (row < dst->r) dst->rows[++row] = nnz; @@ -263,6 +269,7 @@ int gr_lil_mat_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct for (row_end_idx = row_start_idx; row_end_idx < src->nnz; ++row_end_idx) if (si[row_end_idx].row != row) break; + //flint_printf("(%d, %d)\n", row_start_idx, row_end_idx); gr_sparse_vec_fit_nnz(&dst->rows[row], row_end_idx - row_start_idx, ctx); // Add nonzeroes to row @@ -270,6 +277,7 @@ int gr_lil_mat_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct nnz = 0; for (i = row_start_idx; i < row_end_idx; ++i) { + //flint_printf("\t(%d, %d)\n", si[i].row, si[i].col); // Skip zero entries if (is_zero(si[i].entry, ctx) == T_TRUE) continue; @@ -290,6 +298,8 @@ int gr_lil_mat_set_coo_mat(gr_lil_mat_t dst, const gr_coo_mat_t src, gr_ctx_t ct status |= gr_set(entry, si[i].entry, ctx); } } + if (entry != NULL && is_zero(entry, ctx) == T_TRUE) + --nnz; dst->rows[row].nnz = nnz; dst->nnz += nnz; row_start_idx = row_end_idx; diff --git a/src/gr_sparse_mat/test/t-conversion.c b/src/gr_sparse_mat/test/t-conversion.c index 8932d392db..756bfb14aa 100644 --- a/src/gr_sparse_mat/test/t-conversion.c +++ b/src/gr_sparse_mat/test/t-conversion.c @@ -62,7 +62,7 @@ int test_conversion(flint_rand_t state, gr_ctx_t ctx) } } - //flint_printf("Testing from/to sparse mat\n"); + // flint_printf("Testing from/to sparse mat\n"); for (i = 0; i < n_tests; i++) { status |= gr_coo_mat_randtest(mat, 10, 0, T_TRUE, state, ctx); @@ -76,19 +76,19 @@ int test_conversion(flint_rand_t state, gr_ctx_t ctx) } } - //flint_printf("Testing coo -> csr -> lil -> coo\n"); + // flint_printf("Testing coo -> csr -> lil -> mat -> csr\n"); for (i = 0; i < 2 * n_tests; i++) { status |= gr_coo_mat_randtest(mat, 10, 0, (i % 2) ? T_FALSE : T_TRUE, state, ctx); - //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat, ctx); + // flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat, ctx); status |= gr_csr_mat_set_coo_mat(csr_mat, mat, ctx); - //flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); + // flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); status |= gr_lil_mat_set_csr_mat(lil_mat, csr_mat, ctx); - //flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); - status |= gr_coo_mat_set_lil_mat(mat2, lil_mat, ctx); - //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat2, ctx); - status |= gr_csr_mat_set_coo_mat(csr_mat2, mat2, ctx); - //flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat2, ctx); + // flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); + status |= gr_mat_set_lil_mat(dmat, lil_mat, ctx); + // flint_printf("\n\nmat = "); status |= gr_mat_print(dmat, ctx); + status |= gr_csr_mat_set_mat(csr_mat2, dmat, ctx); + // flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat2, ctx); if (T_FALSE == gr_csr_mat_equal(csr_mat, csr_mat2, ctx)) { status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\n"); @@ -97,19 +97,19 @@ int test_conversion(flint_rand_t state, gr_ctx_t ctx) } } - //flint_printf("Testing coo -> lil -> csr -> coo\n"); + // flint_printf("Testing coo -> lil -> csr -> mat -> lil\n"); for (i = 0; i < 2 * n_tests; i++) { status |= gr_coo_mat_randtest(mat, 10, 0, (i % 2) ? T_FALSE : T_TRUE, state, ctx); - //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat, ctx); flint_printf("\nnnz = %d\n", mat->nnz); + // flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat, ctx); flint_printf("\nnnz = %d\n", mat->nnz); status |= gr_lil_mat_set_coo_mat(lil_mat, mat, ctx); - //flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\nnnz = %d\n", lil_mat->nnz); + // flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\nnnz = %d\n", lil_mat->nnz); status |= gr_csr_mat_set_lil_mat(csr_mat, lil_mat, ctx); - //flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\nnnz = %d\n", csr_mat->nnz); - status |= gr_coo_mat_set_csr_mat(mat2, csr_mat, ctx); - //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat2, ctx); flint_printf("\nnnz = %d\n", mat2->nnz); - status |= gr_lil_mat_set_coo_mat(lil_mat2, mat2, ctx); - //flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat2, ctx); flint_printf("\nnnz = %d\n", lil_mat2->nnz); + // flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\nnnz = %d\n", csr_mat->nnz); + status |= gr_mat_set_csr_mat(dmat, csr_mat, ctx); + // flint_printf("\n\nmat = "); status |= gr_mat_print(dmat, ctx); + status |= gr_lil_mat_set_mat(lil_mat2, dmat, ctx); + // flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat2, ctx); flint_printf("\nnnz = %d\n", lil_mat2->nnz); if (T_FALSE == gr_lil_mat_equal(lil_mat, lil_mat2, ctx)) { status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\n"); diff --git a/src/gr_sparse_vec/from_dense.c b/src/gr_sparse_vec/from_dense.c index 3707cba915..bdaefbef3e 100644 --- a/src/gr_sparse_vec/from_dense.c +++ b/src/gr_sparse_vec/from_dense.c @@ -9,14 +9,14 @@ gr_sparse_vec_set_vec(gr_sparse_vec_t vec, gr_srcptr src, slong len, gr_ctx_t ct status = GR_SUCCESS; for (i = 0; i < len; i++) { - if (T_FALSE == gr_is_zero(GR_ENTRY(src, i, sz), ctx)) + if (T_TRUE != gr_is_zero(GR_ENTRY(src, i, sz), ctx)) nnz++; } gr_sparse_vec_fit_nnz(vec, nnz, ctx); nnz = 0; for (i = 0; i < len; i++) { - if (T_FALSE == gr_is_zero(GR_ENTRY(src, i, sz), ctx)) + if (T_TRUE != gr_is_zero(GR_ENTRY(src, i, sz), ctx)) { vec->inds[nnz] = i; status |= gr_set(GR_ENTRY(vec->nzs, nnz, sz), GR_ENTRY(src, i, sz), ctx); From 971f11ae14b3360892a82a86facb1d00bb930761 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Thu, 21 Mar 2024 02:16:56 -0700 Subject: [PATCH 50/59] A little more coverage --- src/gr_sparse_mat/set.c | 2 +- src/gr_sparse_mat/test/t-conversion.c | 88 ++++++++++++++++----------- 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/src/gr_sparse_mat/set.c b/src/gr_sparse_mat/set.c index 6616bbdcc8..8b308a81ab 100644 --- a/src/gr_sparse_mat/set.c +++ b/src/gr_sparse_mat/set.c @@ -58,7 +58,7 @@ int gr_csr_mat_set(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_ctx_t ctx) { } dst->nnz = src->nnz; gr_csr_mat_fit_nnz(dst, src->nnz, ctx); - memcpy(dst->rows, src->rows, src->r * sizeof(ulong)); + memcpy(dst->rows, src->rows, (src->r+1) * sizeof(ulong)); memcpy(dst->cols, src->cols, src->nnz * sizeof(ulong)); status = _gr_vec_set(dst->nzs, src->nzs, src->nnz, ctx); } diff --git a/src/gr_sparse_mat/test/t-conversion.c b/src/gr_sparse_mat/test/t-conversion.c index 756bfb14aa..3e3fb772fe 100644 --- a/src/gr_sparse_mat/test/t-conversion.c +++ b/src/gr_sparse_mat/test/t-conversion.c @@ -21,15 +21,15 @@ int test_conversion(flint_rand_t state, gr_ctx_t ctx) slong N = 20; slong n_tests = 20; int status = GR_SUCCESS; - gr_coo_mat_t mat, mat2; + gr_coo_mat_t coo_mat, coo_mat2; gr_csr_mat_t csr_mat, csr_mat2; gr_lil_mat_t lil_mat, lil_mat2; gr_mat_t dmat, dmat2; gr_mat_init(dmat, M, N, ctx); gr_mat_init(dmat2, M, N, ctx); - gr_coo_mat_init(mat, M, N, ctx); - gr_coo_mat_init(mat2, M, N, ctx); + gr_coo_mat_init(coo_mat, M, N, ctx); + gr_coo_mat_init(coo_mat2, M, N, ctx); gr_csr_mat_init(csr_mat, M, N, ctx); gr_csr_mat_init(csr_mat2, M, N, ctx); gr_lil_mat_init(lil_mat, M, N, ctx); @@ -38,12 +38,12 @@ int test_conversion(flint_rand_t state, gr_ctx_t ctx) //flint_printf("Testing copy\n"); for (i = 0; i < n_tests; i++) { - status |= gr_coo_mat_randtest(mat, 40, 0, T_TRUE, state, ctx); - status |= gr_coo_mat_set(mat2, mat, ctx); - if (gr_coo_mat_equal(mat, mat2, ctx) == T_FALSE) + status |= gr_coo_mat_randtest(coo_mat, 40, 0, T_TRUE, state, ctx); + status |= gr_coo_mat_set(coo_mat2, coo_mat, ctx); + if (gr_coo_mat_equal(coo_mat, coo_mat2, ctx) == T_FALSE) { - status |= gr_coo_mat_print_nz(mat, ctx); flint_printf("\n"); - status |= gr_coo_mat_print_nz(mat2, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(coo_mat, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(coo_mat2, ctx); flint_printf("\n"); return GR_TEST_FAIL; } } @@ -52,8 +52,8 @@ int test_conversion(flint_rand_t state, gr_ctx_t ctx) for (i = 0; i < n_tests; i++) { status |= gr_mat_randtest(dmat, state, ctx); - status |= gr_coo_mat_set_mat(mat, dmat, ctx); - status |= gr_mat_set_coo_mat(dmat2, mat, ctx); + status |= gr_coo_mat_set_mat(coo_mat, dmat, ctx); + status |= gr_mat_set_coo_mat(dmat2, coo_mat, ctx); if (T_FALSE == gr_mat_equal(dmat, dmat2, ctx)) { status |= gr_mat_print(dmat, ctx); flint_printf("\n"); @@ -65,54 +65,70 @@ int test_conversion(flint_rand_t state, gr_ctx_t ctx) // flint_printf("Testing from/to sparse mat\n"); for (i = 0; i < n_tests; i++) { - status |= gr_coo_mat_randtest(mat, 10, 0, T_TRUE, state, ctx); - status |= gr_mat_set_coo_mat(dmat, mat, ctx); - status |= gr_coo_mat_set_mat(mat2, dmat, ctx); - if (T_FALSE == gr_coo_mat_equal(mat, mat2, ctx)) + status |= gr_coo_mat_randtest(coo_mat, 10, 0, T_TRUE, state, ctx); + status |= gr_mat_set_coo_mat(dmat, coo_mat, ctx); + status |= gr_coo_mat_set_mat(coo_mat2, dmat, ctx); + if (T_FALSE == gr_coo_mat_equal(coo_mat, coo_mat2, ctx)) { - status |= gr_coo_mat_print_nz(mat, ctx); flint_printf("\n"); - status |= gr_coo_mat_print_nz(mat2, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(coo_mat, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(coo_mat2, ctx); flint_printf("\n"); return GR_TEST_FAIL; } } - // flint_printf("Testing coo -> csr -> lil -> mat -> csr\n"); + // flint_printf("Testing coo -> csr -> csr -> lil -> mat -> csr -> coo \n"); for (i = 0; i < 2 * n_tests; i++) { - status |= gr_coo_mat_randtest(mat, 10, 0, (i % 2) ? T_FALSE : T_TRUE, state, ctx); - // flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat, ctx); - status |= gr_csr_mat_set_coo_mat(csr_mat, mat, ctx); - // flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); - status |= gr_lil_mat_set_csr_mat(lil_mat, csr_mat, ctx); - // flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); + status |= gr_coo_mat_randtest(coo_mat, 10, 0, (i % 2) ? T_FALSE : T_TRUE, state, ctx); + //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(coo_mat, ctx); + status |= gr_csr_mat_set_coo_mat(csr_mat, coo_mat, ctx); + //flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\nnnz = %d\n", csr_mat->nnz); + status |= gr_csr_mat_set(csr_mat2, csr_mat, ctx); + //flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat2, ctx); flint_printf("\nnnz = %d\n", csr_mat2->nnz); + status |= gr_lil_mat_set_csr_mat(lil_mat, csr_mat2, ctx); + //flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); status |= gr_mat_set_lil_mat(dmat, lil_mat, ctx); - // flint_printf("\n\nmat = "); status |= gr_mat_print(dmat, ctx); + //flint_printf("\n\nmat = "); status |= gr_mat_print(dmat, ctx); status |= gr_csr_mat_set_mat(csr_mat2, dmat, ctx); - // flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat2, ctx); - if (T_FALSE == gr_csr_mat_equal(csr_mat, csr_mat2, ctx)) + //flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat2, ctx); + status |= gr_coo_mat_set_csr_mat(coo_mat2, csr_mat2, ctx); + //flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(coo_mat2, ctx); flint_printf("\nnnz = %d\n", coo_mat2->nnz); + if + ( + T_FALSE == gr_csr_mat_equal(csr_mat, csr_mat2, ctx) || + T_FALSE == gr_coo_mat_equal(coo_mat, coo_mat2, ctx) + ) { - status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(coo_mat, ctx); flint_printf("\n"); status |= gr_csr_mat_print_nz(csr_mat2, ctx); flint_printf("\n"); return GR_TEST_FAIL; } } - // flint_printf("Testing coo -> lil -> csr -> mat -> lil\n"); + // flint_printf("Testing coo -> lil -> lil -> csr -> mat -> lil -> coo\n"); for (i = 0; i < 2 * n_tests; i++) { - status |= gr_coo_mat_randtest(mat, 10, 0, (i % 2) ? T_FALSE : T_TRUE, state, ctx); - // flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(mat, ctx); flint_printf("\nnnz = %d\n", mat->nnz); - status |= gr_lil_mat_set_coo_mat(lil_mat, mat, ctx); + status |= gr_coo_mat_randtest(coo_mat, 10, 0, (i % 2) ? T_FALSE : T_TRUE, state, ctx); + // flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(coo_mat, ctx); flint_printf("\nnnz = %d\n", coo_mat->nnz); + status |= gr_lil_mat_set_coo_mat(lil_mat, coo_mat, ctx); // flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\nnnz = %d\n", lil_mat->nnz); - status |= gr_csr_mat_set_lil_mat(csr_mat, lil_mat, ctx); + status |= gr_lil_mat_set(lil_mat2, lil_mat, ctx); + // flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat2, ctx); flint_printf("\nnnz = %d\n", lil_mat2->nnz); + status |= gr_csr_mat_set_lil_mat(csr_mat, lil_mat2, ctx); // flint_printf("\n\ncsr_mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\nnnz = %d\n", csr_mat->nnz); status |= gr_mat_set_csr_mat(dmat, csr_mat, ctx); // flint_printf("\n\nmat = "); status |= gr_mat_print(dmat, ctx); status |= gr_lil_mat_set_mat(lil_mat2, dmat, ctx); // flint_printf("\n\nlil_mat = "); status |= gr_lil_mat_print_nz(lil_mat2, ctx); flint_printf("\nnnz = %d\n", lil_mat2->nnz); - if (T_FALSE == gr_lil_mat_equal(lil_mat, lil_mat2, ctx)) + status |= gr_coo_mat_set_lil_mat(coo_mat2, lil_mat2, ctx); + // flint_printf("\n\ncoo_mat = "); status |= gr_coo_mat_print_nz(coo_mat2, ctx); flint_printf("\nnnz = %d\n", coo_mat2->nnz); + if + ( + T_FALSE == gr_lil_mat_equal(lil_mat, lil_mat2, ctx) || + T_FALSE == gr_coo_mat_equal(coo_mat, coo_mat2, ctx) + ) { - status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(coo_mat, ctx); flint_printf("\n"); status |= gr_lil_mat_print_nz(lil_mat2, ctx); flint_printf("\n"); return GR_TEST_FAIL; } @@ -122,8 +138,8 @@ int test_conversion(flint_rand_t state, gr_ctx_t ctx) gr_csr_mat_clear(csr_mat2, ctx); gr_lil_mat_clear(lil_mat, ctx); gr_lil_mat_clear(lil_mat2, ctx); - gr_coo_mat_clear(mat, ctx); - gr_coo_mat_clear(mat2, ctx); + gr_coo_mat_clear(coo_mat, ctx); + gr_coo_mat_clear(coo_mat2, ctx); gr_mat_clear(dmat, ctx); gr_mat_clear(dmat2, ctx); return status; From 0b5eee668dc2d132631805c5e866d8fac491c4a4 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Thu, 21 Mar 2024 08:57:42 -0700 Subject: [PATCH 51/59] Basic stuff mostly tested, have most of the functionality for solving --- src/gr_mat.h | 59 +++- src/gr_mat/add_scalar.c | 85 +++--- src/gr_mat/div_scalar.c | 44 ++- src/gr_mat/divexact_scalar.c | 45 +++ src/gr_mat/mul_scalar.c | 42 ++- src/gr_mat/mul_vec.c | 39 +++ src/gr_mat/sub_scalar.c | 86 +++--- src/gr_sparse_mat.h | 23 +- src/gr_sparse_mat/equal.c | 4 +- src/gr_sparse_mat/mul.c | 104 +++---- src/gr_sparse_mat/randtest.c | 11 +- src/gr_sparse_mat/scalar.c | 51 +++- src/gr_sparse_mat/set.c | 1 + src/gr_sparse_mat/test/main.c | 6 +- src/gr_sparse_mat/test/t-arith.c | 467 +++++++++++++++++++++++++++++++ src/gr_sparse_mat/test/t-mul.c | 194 +++++++++++++ src/gr_sparse_vec/test/t-arith.c | 4 +- src/gr_vec.h | 8 + 18 files changed, 1090 insertions(+), 183 deletions(-) create mode 100644 src/gr_mat/divexact_scalar.c create mode 100644 src/gr_mat/mul_vec.c create mode 100644 src/gr_sparse_mat/test/t-arith.c create mode 100644 src/gr_sparse_mat/test/t-mul.c diff --git a/src/gr_mat.h b/src/gr_mat.h index fb34988bc3..6cbd37560e 100644 --- a/src/gr_mat.h +++ b/src/gr_mat.h @@ -100,8 +100,12 @@ WARN_UNUSED_RESULT int gr_mat_randpermdiag(int * parity, gr_mat_t mat, flint_ran WARN_UNUSED_RESULT int gr_mat_randrank(gr_mat_t mat, flint_rand_t state, slong rank, gr_ctx_t ctx); #define gr_mat_is_compatible(mat1, mat2, ctx) (((mat1)->r == (mat2)->r && (mat1)->c == (mat2)->c) ? T_TRUE : T_FALSE) -#define gr_mat_is_empty(mat, ctx) ((((mat)->r == 0) || ((mat)->c == 0)) ? T_TRUE : T_FALSE) -#define gr_mat_is_square(mat, ctx) (((mat)->r == (mat)->c) ? T_TRUE : T_FALSE) + +GR_MAT_INLINE truth_t gr_mat_is_empty(const gr_mat_t mat, gr_ctx_t ctx) +{ return (((mat)->r == 0) || ((mat)->c == 0)) ? T_TRUE : T_FALSE; } + +GR_MAT_INLINE truth_t gr_mat_is_square(const gr_mat_t mat, gr_ctx_t ctx) +{ return ((mat)->r == (mat)->c) ? T_TRUE : T_FALSE; } truth_t gr_mat_equal(const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx); truth_t gr_mat_is_zero(const gr_mat_t mat, gr_ctx_t ctx); @@ -127,11 +131,40 @@ WARN_UNUSED_RESULT int gr_mat_sub(gr_mat_t res, const gr_mat_t mat1, const gr_ma /* todo: test, wrap; div; more conversions */ WARN_UNUSED_RESULT int gr_mat_add_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_add_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_add_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_add_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_add_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx); + WARN_UNUSED_RESULT int gr_mat_sub_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_sub_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_sub_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_sub_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_sub_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx); + WARN_UNUSED_RESULT int gr_mat_mul_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_mul_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_mul_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_mul_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_mul_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_mul_scalar_2exp_si(gr_mat_t res, const gr_mat_t mat, slong e, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_mat_div_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_div_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_div_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_div_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_div_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_mat_divexact_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_divexact_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_divexact_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_divexact_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_divexact_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx); + WARN_UNUSED_RESULT int gr_mat_addmul_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_mat_submul_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_mat_div_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_mat_mul_vec(gr_ptr v, const gr_mat_t A, gr_srcptr u, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_mat_mul_classical(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_mat_mul_strassen(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); @@ -206,21 +239,27 @@ WARN_UNUSED_RESULT int gr_mat_hilbert(gr_mat_t mat, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_mat_hadamard(gr_mat_t mat, gr_ctx_t ctx); /* todo: dft, dct */ -#define _GR_MAT_INIT_SHALLOW_TRANSPOSE(B, A, sz) { \ - B->r = A->c; \ - B->c = A->r; \ - B->rows = flint_malloc(A->c * sizeof(gr_ptr)); \ - B->entries = TMP_ALLOC(sz * A->c * A->r); \ +#define _GR_MAT_SHALLOW_TRANSPOSE(AT, A, sz) { \ for (j = 0; j < A->c; j++) \ { \ - B->rows[j] = GR_ENTRY(B->entries, j * A->r, sz); \ for (i = 0; i < A->r; i++) \ { \ - set_shallow(GR_MAT_ENTRY(B, j, i, sz), GR_MAT_ENTRY(B, i, j, sz), ctx); \ + set_shallow(GR_MAT_ENTRY(AT, j, i, sz), GR_MAT_ENTRY(A, i, j, sz), ctx); \ } \ } \ } +#define _GR_MAT_INIT_SHALLOW_TRANSPOSE(AT, A, sz) { \ + AT->r = A->c; \ + AT->c = A->r; \ + AT->rows = flint_malloc(AT->r * sizeof(gr_ptr)); \ + AT->entries = TMP_ALLOC(sz * A->c * A->r); \ + for (j = 0; j < A->c; j++) \ + AT->rows[j] = GR_ENTRY(AT->entries, j * A->r, sz); \ + _GR_MAT_SHALLOW_TRANSPOSE(AT, A, sz) \ +} + + WARN_UNUSED_RESULT int gr_mat_transpose(gr_mat_t B, const gr_mat_t A, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_mat_nonsingular_solve_tril_classical(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx); diff --git a/src/gr_mat/add_scalar.c b/src/gr_mat/add_scalar.c index caef02d18e..17800bdff1 100644 --- a/src/gr_mat/add_scalar.c +++ b/src/gr_mat/add_scalar.c @@ -11,35 +11,56 @@ #include "gr_mat.h" -int -gr_mat_add_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx) -{ - slong i, j, r, c; - slong sz = ctx->sizeof_elem; - int status = GR_SUCCESS; - - r = gr_mat_nrows(res, ctx); - c = gr_mat_ncols(res, ctx); - - if (res == mat) - { - for (i = 0; i < FLINT_MIN(r, c); i++) - status |= gr_add(GR_MAT_ENTRY(res, i, i, sz), GR_MAT_ENTRY(res, i, i, sz), x, ctx); - } - else - { - for (i = 0; i < r; i++) - { - for (j = 0; j < c; j++) - { - /* todo: vectorize */ - if (i == j) - status |= gr_add(GR_MAT_ENTRY(res, i, j, sz), GR_MAT_ENTRY(mat, i, j, sz), x, ctx); - else - status |= gr_set(GR_MAT_ENTRY(res, i, j, sz), GR_MAT_ENTRY(mat, i, j, sz), ctx); - } - } - } - - return status; -} +#define GR_MAT_ADD_SCALAR(FUNC, res, mat, x, ctx) \ + slong i, j, r, c, sz = (ctx)->sizeof_elem; \ + int status = GR_SUCCESS; \ + r = gr_mat_nrows(res, ctx); \ + c = gr_mat_ncols(res, ctx); \ + if (res == mat) \ + { \ + for (i = 0; i < FLINT_MIN(r, c); i++) \ + status |= (FUNC)( \ + GR_MAT_ENTRY(res, i, i, sz), \ + GR_MAT_ENTRY(res, i, i, sz), \ + x, ctx \ + ); \ + } \ + else \ + { \ + for (i = 0; i < r; i++) \ + { \ + for (j = 0; j < c; j++) \ + { \ + /* todo: vectorize */ \ + if (i == j) \ + status |= (FUNC)( \ + GR_MAT_ENTRY(res, i, j, sz), \ + GR_MAT_ENTRY(mat, i, j, sz), \ + x, ctx \ + ); \ + else \ + status |= gr_set( \ + GR_MAT_ENTRY(res, i, j, sz), \ + GR_MAT_ENTRY(mat, i, j, sz), \ + ctx \ + ); \ + } \ + } \ + } \ + return status; \ + + +int gr_mat_add_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx) +{ GR_MAT_ADD_SCALAR(gr_add, res, mat, x, ctx) } + +int gr_mat_add_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx) +{ GR_MAT_ADD_SCALAR(gr_add_si, res, mat, x, ctx) } + +int gr_mat_add_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx) +{ GR_MAT_ADD_SCALAR(gr_add_ui, res, mat, x, ctx) } + +int gr_mat_add_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx) +{ GR_MAT_ADD_SCALAR(gr_add_fmpz, res, mat, x, ctx) } + +int gr_mat_add_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx) +{ GR_MAT_ADD_SCALAR(gr_add_fmpq, res, mat, x, ctx) } diff --git a/src/gr_mat/div_scalar.c b/src/gr_mat/div_scalar.c index 4567e562f2..42d2911428 100644 --- a/src/gr_mat/div_scalar.c +++ b/src/gr_mat/div_scalar.c @@ -10,22 +10,36 @@ */ #include "gr_mat.h" +#include "gr_vec.h" -/* todo: use a vector function; preinvert when appropriate */ -int -gr_mat_div_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx) -{ - slong i, j, r, c; - int status = GR_SUCCESS; - slong sz = ctx->sizeof_elem; +/* preinvert when appropriate */ - r = gr_mat_nrows(res, ctx); - c = gr_mat_ncols(res, ctx); +#define GR_MAT_DIV_SCALAR(SCALAR_TYPE, res, mat, x, ctx) \ + slong i, r, c; \ + int status = GR_SUCCESS; \ + r = gr_mat_nrows(res, ctx); \ + c = gr_mat_ncols(res, ctx); \ + if (c != 0) \ + for (i = 0; i < r; i++) \ + status |= _gr_vec_div_##SCALAR_TYPE( \ + res->rows[i], \ + mat->rows[i], \ + c, x, ctx \ + ); \ + return status; \ - if (c != 0) - for (i = 0; i < r; i++) - for (j = 0; j < c; j++) - status |= gr_div(GR_MAT_ENTRY(res, i, j, sz), GR_MAT_ENTRY(mat, i, j, sz), x, ctx); - return status; -} +int gr_mat_div_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx) +{ GR_MAT_DIV_SCALAR(scalar, res, mat, x, ctx); } + +int gr_mat_div_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx) +{ GR_MAT_DIV_SCALAR(scalar_si, res, mat, x, ctx); } + +int gr_mat_div_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx) +{ GR_MAT_DIV_SCALAR(scalar_ui, res, mat, x, ctx); } + +int gr_mat_div_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx) +{ GR_MAT_DIV_SCALAR(scalar_fmpz, res, mat, x, ctx); } + +int gr_mat_div_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx) +{ GR_MAT_DIV_SCALAR(scalar_fmpq, res, mat, x, ctx); } diff --git a/src/gr_mat/divexact_scalar.c b/src/gr_mat/divexact_scalar.c new file mode 100644 index 0000000000..6526f13647 --- /dev/null +++ b/src/gr_mat/divexact_scalar.c @@ -0,0 +1,45 @@ +/* + Copyright (C) 2022 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 3 of the License, or + (at your option) any later version. See . +*/ + +#include "gr_mat.h" +#include "gr_vec.h" + +/* preinvert when appropriate */ + +#define GR_MAT_DIVEXACT_SCALAR(SCALAR_TYPE, res, mat, x, ctx) \ + slong i, r, c; \ + int status = GR_SUCCESS; \ + r = gr_mat_nrows(res, ctx); \ + c = gr_mat_ncols(res, ctx); \ + if (c != 0) \ + for (i = 0; i < r; i++) \ + status |= _gr_vec_divexact_##SCALAR_TYPE( \ + res->rows[i], \ + mat->rows[i], \ + c, x, ctx \ + ); \ + return status; \ + + +int gr_mat_divexact_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx) +{ GR_MAT_DIVEXACT_SCALAR(scalar, res, mat, x, ctx); } + +int gr_mat_divexact_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx) +{ GR_MAT_DIVEXACT_SCALAR(scalar_si, res, mat, x, ctx); } + +int gr_mat_divexact_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx) +{ GR_MAT_DIVEXACT_SCALAR(scalar_ui, res, mat, x, ctx); } + +int gr_mat_divexact_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx) +{ GR_MAT_DIVEXACT_SCALAR(scalar_fmpz, res, mat, x, ctx); } + +int gr_mat_divexact_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx) +{ GR_MAT_DIVEXACT_SCALAR(scalar_fmpq, res, mat, x, ctx); } diff --git a/src/gr_mat/mul_scalar.c b/src/gr_mat/mul_scalar.c index 74e39ab6a9..422fa7e1a6 100644 --- a/src/gr_mat/mul_scalar.c +++ b/src/gr_mat/mul_scalar.c @@ -12,18 +12,36 @@ #include "gr_vec.h" #include "gr_mat.h" -int -gr_mat_mul_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx) -{ - slong i, r, c; - int status = GR_SUCCESS; - r = gr_mat_nrows(res, ctx); - c = gr_mat_ncols(res, ctx); +#define GR_MAT_MUL_SCALAR(SCALAR_TYPE, res, mat, x, ctx) \ + slong i, r, c; \ + int status = GR_SUCCESS; \ + r = gr_mat_nrows(res, ctx); \ + c = gr_mat_ncols(res, ctx); \ + if (c != 0) \ + for (i = 0; i < r; i++) \ + status |= _gr_vec_mul_##SCALAR_TYPE( \ + res->rows[i], \ + mat->rows[i], \ + c, x, ctx \ + ); \ + return status; \ - if (c != 0) - for (i = 0; i < r; i++) - status |= _gr_vec_mul_scalar(res->rows[i], mat->rows[i], c, x, ctx); - return status; -} +int gr_mat_mul_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx) +{ GR_MAT_MUL_SCALAR(scalar, res, mat, x, ctx); } + +int gr_mat_mul_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx) +{ GR_MAT_MUL_SCALAR(scalar_si, res, mat, x, ctx); } + +int gr_mat_mul_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx) +{ GR_MAT_MUL_SCALAR(scalar_ui, res, mat, x, ctx); } + +int gr_mat_mul_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx) +{ GR_MAT_MUL_SCALAR(scalar_fmpz, res, mat, x, ctx); } + +int gr_mat_mul_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx) +{ GR_MAT_MUL_SCALAR(scalar_fmpq, res, mat, x, ctx); } + +int gr_mat_mul_scalar_2exp_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx) +{ GR_MAT_MUL_SCALAR(scalar_2exp_si, res, mat, x, ctx); } diff --git a/src/gr_mat/mul_vec.c b/src/gr_mat/mul_vec.c new file mode 100644 index 0000000000..1ec06394eb --- /dev/null +++ b/src/gr_mat/mul_vec.c @@ -0,0 +1,39 @@ + +/* + Copyright (C) 2022 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 3 of the License, or + (at your option) any later version. See . +*/ + +#include "gr_mat.h" +#include "gr_vec.h" + +int gr_mat_mul_vec(gr_ptr v, const gr_mat_t A, gr_srcptr u, gr_ctx_t ctx) +{ + slong r, c, row, sz; + gr_ptr w; + int status; + + sz = ctx->sizeof_elem; + r = gr_mat_nrows(A, ctx); + c = gr_mat_ncols(A, ctx); + + if (u == v) + { + GR_TMP_INIT_VEC(w, r, ctx); + _gr_vec_init(w, r, ctx); + status = gr_mat_mul_vec(w, A, u, ctx); + _gr_vec_swap(v, w, r, ctx); + GR_TMP_CLEAR_VEC(w, r, ctx); + return status; + } + status = _gr_vec_zero(v, r, ctx); + for (row = 0; row < r; ++row) + status |= _gr_vec_dot(GR_ENTRY(v, row, sz), GR_ENTRY(v, row, sz), 0, A->rows[row], u, c, ctx); + return status; +} diff --git a/src/gr_mat/sub_scalar.c b/src/gr_mat/sub_scalar.c index 597cc3f249..179a60d356 100644 --- a/src/gr_mat/sub_scalar.c +++ b/src/gr_mat/sub_scalar.c @@ -11,35 +11,57 @@ #include "gr_mat.h" -int -gr_mat_sub_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx) -{ - slong i, j, r, c; - slong sz = ctx->sizeof_elem; - int status = GR_SUCCESS; - - r = gr_mat_nrows(res, ctx); - c = gr_mat_ncols(res, ctx); - - if (res == mat) - { - for (i = 0; i < FLINT_MIN(r, c); i++) - status |= gr_sub(GR_MAT_ENTRY(res, i, i, sz), GR_MAT_ENTRY(res, i, i, sz), x, ctx); - } - else - { - for (i = 0; i < r; i++) - { - for (j = 0; j < c; j++) - { - /* todo: vectorize */ - if (i == j) - status |= gr_sub(GR_MAT_ENTRY(res, i, j, sz), GR_MAT_ENTRY(mat, i, j, sz), x, ctx); - else - status |= gr_set(GR_MAT_ENTRY(res, i, j, sz), GR_MAT_ENTRY(mat, i, j, sz), ctx); - } - } - } - - return status; -} + +#define GR_MAT_SUB_SCALAR(FUNC, res, mat, x, ctx) \ + slong i, j, r, c, sz = (ctx)->sizeof_elem; \ + int status = GR_SUCCESS; \ + r = gr_mat_nrows(res, ctx); \ + c = gr_mat_ncols(res, ctx); \ + if (res == mat) \ + { \ + for (i = 0; i < FLINT_MIN(r, c); i++) \ + status |= (FUNC)( \ + GR_MAT_ENTRY(res, i, i, sz), \ + GR_MAT_ENTRY(res, i, i, sz), \ + x, ctx \ + ); \ + } \ + else \ + { \ + for (i = 0; i < r; i++) \ + { \ + for (j = 0; j < c; j++) \ + { \ + /* todo: vectorize */ \ + if (i == j) \ + status |= (FUNC)( \ + GR_MAT_ENTRY(res, i, j, sz), \ + GR_MAT_ENTRY(mat, i, j, sz), \ + x, ctx \ + ); \ + else \ + status |= gr_set( \ + GR_MAT_ENTRY(res, i, j, sz), \ + GR_MAT_ENTRY(mat, i, j, sz), \ + ctx \ + ); \ + } \ + } \ + } \ + return status; \ + + +int gr_mat_sub_scalar(gr_mat_t res, const gr_mat_t mat, gr_srcptr x, gr_ctx_t ctx) +{ GR_MAT_SUB_SCALAR(gr_sub, res, mat, x, ctx) } + +int gr_mat_sub_scalar_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx) +{ GR_MAT_SUB_SCALAR(gr_sub_si, res, mat, x, ctx) } + +int gr_mat_sub_scalar_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx) +{ GR_MAT_SUB_SCALAR(gr_sub_ui, res, mat, x, ctx) } + +int gr_mat_sub_scalar_fmpz(gr_mat_t res, const gr_mat_t mat, fmpz_t x, gr_ctx_t ctx) +{ GR_MAT_SUB_SCALAR(gr_sub_fmpz, res, mat, x, ctx) } + +int gr_mat_sub_scalar_fmpq(gr_mat_t res, const gr_mat_t mat, fmpq_t x, gr_ctx_t ctx) +{ GR_MAT_SUB_SCALAR(gr_sub_fmpq, res, mat, x, ctx) } diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 38a622151b..cb736bed61 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -661,7 +661,7 @@ WARN_UNUSED_RESULT int gr_coo_mat_neg(gr_coo_mat_t dst, const gr_coo_mat_t src, WARN_UNUSED_RESULT int gr_lil_mat_add(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_sub(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_lil_mat_mul(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +//WARN_UNUSED_RESULT int gr_lil_mat_mul(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_addmul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_submul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); @@ -704,6 +704,23 @@ WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t dst, const gr_ WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_mul_scalar(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_mul_scalar_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_mul_scalar_ui(gr_coo_mat_t dst, const gr_coo_mat_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_mul_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_mul_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_mul_scalar_2exp_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_div_scalar(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_div_scalar_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_div_scalar_ui(gr_coo_mat_t dst, const gr_coo_mat_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_div_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_div_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_divexact_scalar(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_divexact_scalar_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_divexact_scalar_ui(gr_coo_mat_t dst, const gr_coo_mat_t src, ulong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_divexact_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_coo_mat_divexact_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx); + /** * Sum and product **/ @@ -759,8 +776,8 @@ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_coo_mat_nz_product(gr_ptr res, co * Matrix multiplication **/ -WARN_UNUSED_RESULT int gr_csr_mat_mul_vec(gr_vec_t v, const gr_csr_mat_t A, const gr_vec_t u, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_csr_mat_mul_vec(gr_ptr v, const gr_csr_mat_t A, gr_srcptr u, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul_vec(gr_ptr v, const gr_lil_mat_t A, gr_srcptr u, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_csr_mat_mul_mat_transpose(gr_mat_t Ct, const gr_csr_mat_t A, const gr_mat_t Bt, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_mat_t A, const gr_mat_t Bt, gr_ctx_t ctx); diff --git a/src/gr_sparse_mat/equal.c b/src/gr_sparse_mat/equal.c index 2f939f5b0d..500e4802a8 100644 --- a/src/gr_sparse_mat/equal.c +++ b/src/gr_sparse_mat/equal.c @@ -18,7 +18,7 @@ gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx) ( gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE || mat1->nnz != mat2->nnz || - memcmp(mat1->rows, mat2->rows, mat1->r * sizeof(ulong)) || + memcmp(mat1->rows, mat2->rows, (mat1->r + 1) * sizeof(ulong)) || memcmp(mat1->cols, mat2->cols, mat1->nnz * sizeof(ulong)) ) { @@ -51,8 +51,6 @@ gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) truth_t gr_coo_mat_equal(const gr_coo_mat_t mat1, const gr_coo_mat_t mat2, gr_ctx_t ctx) { - slong i; - if (gr_mat_is_compatible(mat1, mat2, ctx) == T_FALSE) { return T_FALSE; diff --git a/src/gr_sparse_mat/mul.c b/src/gr_sparse_mat/mul.c index 6cc9af0a3b..f05aadd89d 100644 --- a/src/gr_sparse_mat/mul.c +++ b/src/gr_sparse_mat/mul.c @@ -16,78 +16,67 @@ #include "flint.h" #include "gr_sparse_mat.h" -int gr_csr_mat_mul_vec(gr_vec_t v, const gr_csr_mat_t A, const gr_vec_t u, gr_ctx_t ctx) +int gr_csr_mat_mul_vec(gr_ptr v, const gr_csr_mat_t A, gr_srcptr u, gr_ctx_t ctx) { - slong ar, i; + slong ar, i, sz; int status; gr_sparse_vec_t row; - gr_ptr res; + sz = ctx->sizeof_elem; ar = gr_sparse_mat_nrows(A, ctx); - if (gr_sparse_mat_ncols(A, ctx) != gr_vec_length(u, ctx) || ar != gr_vec_length(v, ctx)) - return GR_DOMAIN; - if (gr_csr_mat_is_zero(A, ctx) == T_TRUE) { - return _gr_vec_zero(v->entries, v->length, ctx); + return _gr_vec_zero(v, ar, ctx); } - status = GR_SUCCESS; - if (u == v) { - gr_vec_t w; - gr_vec_init(w, ar, ctx); - status |= gr_csr_mat_mul_vec(w, A, u, ctx); + gr_ptr w; + GR_TMP_INIT_VEC(w, ar, ctx); + status = gr_csr_mat_mul_vec(w, A, u, ctx); _gr_vec_swap(v, w, ar, ctx); - gr_vec_clear(w, ctx); + GR_TMP_CLEAR_VEC(w, ar, ctx); return status; } - status |= _gr_vec_zero(v->entries, v->length, ctx); + status = _gr_vec_zero(v, ar, ctx); for (i = 0; i < ar; ++i) { _gr_csr_mat_borrow_row(row, A, i, ctx); - res = gr_vec_entry_ptr(v, i, ctx); - status |= gr_sparse_vec_dot_vec(res, res, 0, row, u, ctx); + status |= gr_sparse_vec_dot_vec(GR_ENTRY(v, i, sz), GR_ENTRY(v, i, sz), 0, row, u, ctx); } return status; } -int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ctx_t ctx) +int gr_lil_mat_mul_vec(gr_ptr v, const gr_lil_mat_t A, gr_srcptr u, gr_ctx_t ctx) { - slong ar, i; + slong ar, i, sz; int status; - gr_ptr res; + sz = ctx->sizeof_elem; ar = gr_sparse_mat_nrows(A, ctx); - if (gr_sparse_mat_ncols(A, ctx) != gr_vec_length(u, ctx) || ar != gr_vec_length(v, ctx)) - return GR_DOMAIN; - - if (gr_lil_mat_is_zero(A, ctx) == T_TRUE) { - return _gr_vec_zero(v->entries, v->length, ctx); + return _gr_vec_zero(v, ar, ctx); } status = GR_SUCCESS; if (u == v) { - gr_vec_t w; - gr_vec_init(w, ar, ctx); + gr_ptr w; + GR_TMP_INIT_VEC(w, ar, ctx); status |= gr_lil_mat_mul_vec(w, A, u, ctx); _gr_vec_swap(v, w, ar, ctx); - gr_vec_clear(w, ctx); + GR_TMP_CLEAR_VEC(w, ar, ctx); return status; } - status |= _gr_vec_zero(v->entries, v->length, ctx); - for (i = 0; i < ar; ++i) { - res = gr_vec_entry_ptr(v, i, ctx); - status |= gr_sparse_vec_dot_vec(res, res, 0, &A->rows[i], u, ctx); + status |= _gr_vec_zero(v, ar, ctx); + for (i = 0; i < ar; ++i) {\ + status |= gr_sparse_vec_dot_vec(GR_ENTRY(v, i, sz), GR_ENTRY(v, i, sz), 0, &A->rows[i], u, ctx); } return status; @@ -102,19 +91,10 @@ int gr_lil_mat_mul_vec(gr_vec_t v, const gr_lil_mat_t A, const gr_vec_t u, gr_ct gr_mat_clear(T, ctx); \ } -void _gr_mat_borrow_row(gr_vec_t row, const gr_mat_t mat, slong i, gr_ctx_t ctx) -{ - slong sz = ctx->sizeof_elem; - row->length = mat->c; - row->entries = GR_MAT_ENTRY(mat, i, 0, sz); -} - - int gr_csr_mat_mul_mat_transpose(gr_mat_t Ct, const gr_csr_mat_t A, const gr_mat_t Bt, gr_ctx_t ctx) { slong ar, btr, i; int status; - gr_vec_t bt_row, ct_row; ar = gr_sparse_mat_nrows(A, ctx); btr = gr_mat_nrows(Bt, ctx); @@ -122,24 +102,20 @@ int gr_csr_mat_mul_mat_transpose(gr_mat_t Ct, const gr_csr_mat_t A, const gr_mat if (gr_sparse_mat_ncols(A, ctx) != gr_mat_ncols(Bt, ctx) || ar != gr_mat_ncols(Ct, ctx) || btr != gr_mat_nrows(Ct, ctx)) return GR_DOMAIN; - status = gr_mat_zero(Ct, ctx); - - if (gr_csr_mat_is_zero(A, ctx)) - { - return status; - } + if (gr_csr_mat_is_zero(A, ctx) == T_TRUE) + return gr_mat_zero(Ct, ctx); if (Bt == Ct) { + status = GR_SUCCESS; GR_MAT_OOP_FN(status, Ct, ctx, gr_csr_mat_mul_mat_transpose, A, Bt); return status; } + status = gr_mat_zero(Ct, ctx); for (i = 0; i < btr; i++) { - _gr_mat_borrow_row(ct_row, Ct, i, ctx); - _gr_mat_borrow_row(bt_row, Bt, i, ctx); - status |= gr_csr_mat_mul_vec(ct_row, A, bt_row, ctx); + status |= gr_csr_mat_mul_vec(Ct->rows[i], A, Bt->rows[i], ctx); } return status; } @@ -149,7 +125,6 @@ int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_mat_t A, const gr_mat { slong ar, btr, i; int status; - gr_vec_t bt_row, ct_row; ar = gr_sparse_mat_nrows(A, ctx); btr = gr_mat_nrows(Bt, ctx); @@ -157,25 +132,19 @@ int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_mat_t A, const gr_mat if (gr_sparse_mat_ncols(A, ctx) != gr_mat_ncols(Bt, ctx) || ar != gr_mat_ncols(Ct, ctx) || btr != gr_mat_nrows(Ct, ctx)) return GR_DOMAIN; - status = gr_mat_zero(Ct, ctx); - - if (gr_lil_mat_is_zero(A, ctx)) - { - return status; - } - - status = GR_SUCCESS; + if (gr_lil_mat_is_zero(A, ctx) == T_TRUE) + return gr_mat_zero(Ct, ctx); if (Bt == Ct) { + status = GR_SUCCESS; GR_MAT_OOP_FN(status, Ct, ctx, gr_lil_mat_mul_mat_transpose, A, Bt); return status; } + status = gr_mat_zero(Ct, ctx); for (i = 0; i < btr; i++) { - _gr_mat_borrow_row(ct_row, Ct, i, ctx); - _gr_mat_borrow_row(bt_row, Bt, i, ctx); - status |= gr_lil_mat_mul_vec(ct_row, A, bt_row, ctx); + status |= gr_lil_mat_mul_vec(Ct->rows[i], A, Bt->rows[i], ctx); } return status; } @@ -191,10 +160,8 @@ int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ct if (gr_sparse_mat_ncols(A, ctx) != gr_mat_nrows(B, ctx) || ar != gr_mat_nrows(C, ctx) || bc != gr_mat_ncols(C, ctx)) return GR_DOMAIN; - if (gr_csr_mat_is_zero(A, ctx)) - { + if (gr_csr_mat_is_zero(A, ctx) == T_TRUE) return gr_mat_zero(C, ctx); - } status = GR_SUCCESS; @@ -217,9 +184,12 @@ int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ct status |= gr_csr_mat_mul_mat_transpose(Ct, A, Bt, ctx); + _GR_MAT_SHALLOW_TRANSPOSE(C, Ct, sz); + flint_free(Bt->rows); flint_free(Ct->rows); TMP_END; + return status; } @@ -234,10 +204,8 @@ int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ct if (gr_sparse_mat_ncols(A, ctx) != gr_mat_nrows(B, ctx) || ar != gr_mat_nrows(C, ctx) || bc != gr_mat_ncols(C, ctx)) return GR_DOMAIN; - if (gr_lil_mat_is_zero(A, ctx)) - { + if (gr_lil_mat_is_zero(A, ctx) == T_TRUE) return gr_mat_zero(C, ctx); - } status = GR_SUCCESS; @@ -260,6 +228,8 @@ int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ct status |= gr_lil_mat_mul_mat_transpose(Ct, A, Bt, ctx); + _GR_MAT_SHALLOW_TRANSPOSE(C, Ct, sz); + flint_free(Bt->rows); flint_free(Ct->rows); TMP_END; diff --git a/src/gr_sparse_mat/randtest.c b/src/gr_sparse_mat/randtest.c index c69b6151c0..ece681d88b 100644 --- a/src/gr_sparse_mat/randtest.c +++ b/src/gr_sparse_mat/randtest.c @@ -15,9 +15,9 @@ int gr_coo_mat_randtest(gr_coo_mat_t mat, slong nnz, int replacement, truth_t is int status = GR_SUCCESS; slong i, j, sz, len; sz = ctx->sizeof_elem; - len = mat->r * mat->c; + len = flint_mul_sizes(mat->r, mat->c); - if (nnz < 0 || nnz > mat->r * mat->c) + if (nnz < 0 || nnz > len) return GR_DOMAIN; // Make space @@ -77,8 +77,9 @@ int gr_coo_mat_randtest_prob(gr_coo_mat_t mat, double prob, flint_rand_t state, gr_ctx_t ctx) { int status = GR_SUCCESS; - slong i, j, sz; + slong i, j, sz, len; sz = ctx->sizeof_elem; + len = flint_mul_sizes(mat->r, mat->c); if (prob < 0 || prob > 1) return GR_DOMAIN; @@ -91,12 +92,12 @@ gr_coo_mat_randtest_prob(gr_coo_mat_t mat, double prob, flint_rand_t state, gr_c } if (prob == 1) { - status |= gr_coo_mat_randtest(mat, mat->r * mat->c, 0, T_TRUE, state, ctx); + status |= gr_coo_mat_randtest(mat, len, 0, T_TRUE, state, ctx); return status; } // Allocate space for expected number of nonzeroes, and expand as needed - gr_coo_mat_fit_nnz(mat, prob * mat->r * mat->c, ctx); + gr_coo_mat_fit_nnz(mat, prob * len, ctx); // TODO: for low probability, should be able to do this faster mat->nnz = 0; diff --git a/src/gr_sparse_mat/scalar.c b/src/gr_sparse_mat/scalar.c index d68deef628..c14493a4cf 100644 --- a/src/gr_sparse_mat/scalar.c +++ b/src/gr_sparse_mat/scalar.c @@ -22,7 +22,7 @@ { \ gr_csr_mat_fit_nnz(dst, src->nnz, ctx); \ dst->nnz = src->nnz; \ - memcpy(dst->rows, src->rows, src->r*sizeof(ulong)); \ + memcpy(dst->rows, src->rows, (src->r+1)*sizeof(ulong)); \ memcpy(dst->cols, src->cols, src->nnz*sizeof(ulong)); \ } \ return dense_vec_op(dst->nzs, src->nzs, src->nnz, c, ctx); \ @@ -113,3 +113,52 @@ int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, co { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) { GR_LIL_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } + + +#define GR_COO_MAT_DENSE_VEC_OP(dense_vec_op, dst, src, c, ctx) \ + if(dst->r != src->r || dst->c != src->c) \ + { \ + return GR_DOMAIN; \ + } \ + if(dst != src) \ + { \ + gr_coo_mat_fit_nnz(dst, src->nnz, ctx); \ + dst->nnz = src->nnz; \ + memcpy(dst->rows, src->rows, src->nnz*sizeof(ulong)); \ + memcpy(dst->cols, src->cols, src->nnz*sizeof(ulong)); \ + dst->is_canonical = src->is_canonical; \ + } \ + return dense_vec_op(dst->nzs, src->nzs, src->nnz, c, ctx); \ + +int gr_coo_mat_mul_scalar(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar, dst, src, c, ctx) } +int gr_coo_mat_mul_scalar_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_si, dst, src, c, ctx) } +int gr_coo_mat_mul_scalar_ui(gr_coo_mat_t dst, const gr_coo_mat_t src, ulong c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_ui, dst, src, c, ctx) } +int gr_coo_mat_mul_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpz, dst, src, c, ctx) } +int gr_coo_mat_mul_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_fmpq, dst, src, c, ctx) } +int gr_coo_mat_mul_scalar_2exp_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_mul_scalar_2exp_si, dst, src, c, ctx) } +int gr_coo_mat_div_scalar(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_div_scalar, dst, src, c, ctx) } +int gr_coo_mat_div_scalar_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_si, dst, src, c, ctx) } +int gr_coo_mat_div_scalar_ui(gr_coo_mat_t dst, const gr_coo_mat_t src, ulong c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_ui, dst, src, c, ctx) } +int gr_coo_mat_div_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpz, dst, src, c, ctx) } +int gr_coo_mat_div_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_div_scalar_fmpq, dst, src, c, ctx) } +int gr_coo_mat_divexact_scalar(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar, dst, src, c, ctx) } +int gr_coo_mat_divexact_scalar_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_si, dst, src, c, ctx) } +int gr_coo_mat_divexact_scalar_ui(gr_coo_mat_t dst, const gr_coo_mat_t src, ulong c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_ui, dst, src, c, ctx) } +int gr_coo_mat_divexact_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpz, dst, src, c, ctx) } +int gr_coo_mat_divexact_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx) +{ GR_COO_MAT_DENSE_VEC_OP(_gr_vec_divexact_scalar_fmpq, dst, src, c, ctx) } diff --git a/src/gr_sparse_mat/set.c b/src/gr_sparse_mat/set.c index 8b308a81ab..54678bf522 100644 --- a/src/gr_sparse_mat/set.c +++ b/src/gr_sparse_mat/set.c @@ -9,6 +9,7 @@ (at your option) any later version. See . */ +#include "stdlib.h" #include "gr_sparse_mat.h" typedef struct diff --git a/src/gr_sparse_mat/test/main.c b/src/gr_sparse_mat/test/main.c index 20cf241726..e48c09c65a 100644 --- a/src/gr_sparse_mat/test/main.c +++ b/src/gr_sparse_mat/test/main.c @@ -3,8 +3,10 @@ /* Include functions *********************************************************/ -#include "t-init.c" +#include "t-arith.c" #include "t-conversion.c" +#include "t-init.c" +#include "t-mul.c" #include "t-randtest.c" /* Array of test functions ***************************************************/ @@ -14,6 +16,8 @@ test_struct tests[] = TEST_FUNCTION(gr_sparse_mat_init), TEST_FUNCTION(gr_sparse_mat_conversion), TEST_FUNCTION(gr_sparse_mat_randtest), + TEST_FUNCTION(gr_sparse_mat_arith), + TEST_FUNCTION(gr_sparse_mat_mul), }; /* main function *************************************************************/ diff --git a/src/gr_sparse_mat/test/t-arith.c b/src/gr_sparse_mat/test/t-arith.c new file mode 100644 index 0000000000..156039bf1a --- /dev/null +++ b/src/gr_sparse_mat/test/t-arith.c @@ -0,0 +1,467 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_mat.h" +#include "fmpz.h" +#include "fmpq.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int test_neg(flint_rand_t state, gr_ctx_t ctx) +{ + slong i; + slong M = 20; + slong N = 20; + slong n_tests = 20; + int status = GR_SUCCESS; + gr_csr_mat_t csr_mat, csr_mat2; + gr_lil_mat_t lil_mat, lil_mat2; + gr_coo_mat_t coo_mat, coo_mat2; + gr_mat_t dmat, dmat2; + + gr_mat_init(dmat, M, N, ctx); + gr_mat_init(dmat2, M, N, ctx); + gr_coo_mat_init(coo_mat, M, N, ctx); + gr_coo_mat_init(coo_mat2, M, N, ctx); + gr_csr_mat_init(csr_mat, M, N, ctx); + gr_csr_mat_init(csr_mat2, M, N, ctx); + gr_lil_mat_init(lil_mat, M, N, ctx); + gr_lil_mat_init(lil_mat2, M, N, ctx); + + //flint_printf("Testing neg coo\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_coo_mat_randtest(coo_mat, 80, 0, T_TRUE, state, ctx); + status |= gr_coo_mat_neg(coo_mat2, coo_mat, ctx); + status |= gr_mat_set_coo_mat(dmat2, coo_mat, ctx); + status |= gr_mat_neg(dmat, dmat2, ctx); + status |= gr_mat_set_coo_mat(dmat2, coo_mat2, ctx); + if (gr_mat_equal(dmat, dmat2, ctx) == T_FALSE) + { + status |= gr_coo_mat_print_nz(coo_mat, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(coo_mat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + //flint_printf("Testing neg csr\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_coo_mat_randtest(coo_mat, 80, 0, T_TRUE, state, ctx); + status |= gr_csr_mat_set_coo_mat(csr_mat, coo_mat, ctx); + status |= gr_csr_mat_neg(csr_mat2, csr_mat, ctx); + status |= gr_mat_set_csr_mat(dmat2, csr_mat, ctx); + status |= gr_mat_neg(dmat, dmat2, ctx); + status |= gr_mat_set_csr_mat(dmat2, csr_mat2, ctx); + if (gr_mat_equal(dmat, dmat2, ctx) == T_FALSE) + { + status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\n"); + status |= gr_csr_mat_print_nz(csr_mat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + //flint_printf("Testing neg lil\n"); + for (i = 0; i < n_tests; i++) + { + status |= gr_coo_mat_randtest(coo_mat, 80, 0, T_TRUE, state, ctx); + status |= gr_lil_mat_set_coo_mat(lil_mat, coo_mat, ctx); + status |= gr_lil_mat_neg(lil_mat2, lil_mat, ctx); + status |= gr_mat_set_lil_mat(dmat2, lil_mat, ctx); + status |= gr_mat_neg(dmat, dmat2, ctx); + status |= gr_mat_set_lil_mat(dmat2, lil_mat2, ctx); + if (gr_mat_equal(dmat, dmat2, ctx) == T_FALSE) + { + status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\n"); + status |= gr_lil_mat_print_nz(lil_mat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + gr_csr_mat_clear(csr_mat, ctx); + gr_csr_mat_clear(csr_mat2, ctx); + gr_lil_mat_clear(lil_mat, ctx); + gr_lil_mat_clear(lil_mat2, ctx); + gr_coo_mat_clear(coo_mat, ctx); + gr_coo_mat_clear(coo_mat2, ctx); + gr_mat_clear(dmat, ctx); + gr_mat_clear(dmat2, ctx); + return status; +} + +int test_add_sub(flint_rand_t state, gr_ctx_t ctx) +{ + slong i, j; + slong M = 20; + slong N = 20; + slong n_tests = 20; + int status = GR_SUCCESS; + truth_t eq; + gr_csr_mat_t csr_mat, csr_mat2; + gr_lil_mat_t lil_mat, lil_mat2; + gr_coo_mat_t coo_mat, coo_mat2; + gr_mat_t dmat, dmat2; + + gr_mat_init(dmat, M, N, ctx); + gr_mat_init(dmat2, M, N, ctx); + gr_coo_mat_init(coo_mat, M, N, ctx); + gr_coo_mat_init(coo_mat2, M, N, ctx); + gr_csr_mat_init(csr_mat, M, N, ctx); + gr_csr_mat_init(csr_mat2, M, N, ctx); + gr_lil_mat_init(lil_mat, M, N, ctx); + gr_lil_mat_init(lil_mat2, M, N, ctx); + + for (i = 0; i < 2 * n_tests; i++) + { + status = GR_SUCCESS; + //flint_printf("%d\n", i); + j = i % 2; // Add or subtract + + status |= gr_coo_mat_randtest(coo_mat, 80, 0, T_TRUE, state, ctx); + status |= gr_coo_mat_randtest(coo_mat2, 80, 0, T_TRUE, state, ctx); + status |= gr_lil_mat_set_coo_mat(lil_mat, coo_mat, ctx); + status |= gr_lil_mat_set_coo_mat(lil_mat2, coo_mat2, ctx); + status |= gr_mat_set_lil_mat(dmat, lil_mat, ctx); + status |= gr_mat_set_lil_mat(dmat2, lil_mat2, ctx); + if (j == 0) + { + status |= gr_lil_mat_add(lil_mat, lil_mat, lil_mat2, ctx); + status |= gr_mat_add(dmat, dmat, dmat2, ctx); + } + else + { + status |= gr_lil_mat_sub(lil_mat, lil_mat, lil_mat2, ctx); + status |= gr_mat_sub(dmat, dmat, dmat2, ctx); + } + + if (status == GR_UNABLE) + continue; + + status |= gr_mat_set_lil_mat(dmat2, lil_mat, ctx); + eq = gr_mat_equal(dmat, dmat2, ctx); + if (eq == T_FALSE || status != GR_SUCCESS) + { + flint_printf( + "\ni = %d, j = %d, equal = %d, status = %d\n", + i, j, eq, status + ); + gr_ctx_println(ctx); + flint_printf("mat = "); gr_mat_print(dmat, ctx); flint_printf("\n"); + flint_printf("mat2 = "); gr_mat_print(dmat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + gr_csr_mat_clear(csr_mat, ctx); + gr_csr_mat_clear(csr_mat2, ctx); + gr_lil_mat_clear(lil_mat, ctx); + gr_lil_mat_clear(lil_mat2, ctx); + gr_coo_mat_clear(coo_mat, ctx); + gr_coo_mat_clear(coo_mat2, ctx); + gr_mat_clear(dmat, ctx); + gr_mat_clear(dmat2, ctx); + return status; +} + +int test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) +{ + slong i, j; + slong M = 20; + slong N = 20; + slong n_tests = 20; + int status = GR_SUCCESS; + truth_t eq; + gr_lil_mat_t lil_mat, lil_mat2; + gr_coo_mat_t coo_mat, coo_mat2; + gr_mat_t dmat, dmat2; + gr_ptr gr_c; + + GR_TMP_INIT(gr_c, ctx); + gr_mat_init(dmat, M, N, ctx); + gr_mat_init(dmat2, M, N, ctx); + gr_coo_mat_init(coo_mat, M, N, ctx); + gr_coo_mat_init(coo_mat2, M, N, ctx); + gr_lil_mat_init(lil_mat, M, N, ctx); + gr_lil_mat_init(lil_mat2, M, N, ctx); + + for (i = 0; i < 2 * n_tests; i++) + { + status = GR_SUCCESS; + //flint_printf("%d\n", i); + j = i % 2; // Add or subtract + + status |= gr_coo_mat_randtest(coo_mat, 80, 0, T_TRUE, state, ctx); + status |= gr_coo_mat_randtest(coo_mat2, 80, 0, T_TRUE, state, ctx); + status |= gr_lil_mat_set_coo_mat(lil_mat, coo_mat, ctx); + status |= gr_lil_mat_set_coo_mat(lil_mat2, coo_mat2, ctx); + status |= gr_mat_set_lil_mat(dmat, lil_mat, ctx); + status |= gr_mat_set_lil_mat(dmat2, lil_mat2, ctx); + + status |= gr_randtest_not_zero(gr_c, state, ctx); + if (j == 0) + { + status |= gr_lil_mat_addmul_scalar(lil_mat, lil_mat2, gr_c, ctx); + status |= gr_mat_addmul_scalar(dmat, dmat2, gr_c, ctx); + } + else + { + status |= gr_lil_mat_submul_scalar(lil_mat, lil_mat2, gr_c, ctx); + status |= gr_mat_submul_scalar(dmat, dmat2, gr_c, ctx); + } + status |= gr_mat_set_lil_mat(dmat2, lil_mat, ctx); + eq = gr_mat_equal(dmat, dmat2, ctx); + if (eq == T_FALSE || status != GR_SUCCESS) + { + flint_printf( + "\ni = %d, j = %d, equal = %d, status = %d\n", + i, j, eq, status + ); + gr_ctx_println(ctx); + flint_printf("dmat = "); gr_mat_print(dmat, ctx); flint_printf("\n"); + flint_printf("dmat2 = "); gr_mat_print(dmat2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + gr_lil_mat_clear(lil_mat, ctx); + gr_lil_mat_clear(lil_mat2, ctx); + gr_coo_mat_clear(coo_mat, ctx); + gr_coo_mat_clear(coo_mat2, ctx); + gr_mat_clear(dmat, ctx); + gr_mat_clear(dmat2, ctx); + GR_TMP_CLEAR(gr_c, ctx); + return status; +} + +#define TEST_OP_SCALAR(STATUS, MAT_TYPE, OP, SCALAR_TYPE, MAT, MAT2, DMAT, DMAT2, C, CTX) \ + STATUS |= gr_##MAT_TYPE##_mat_##OP##_##SCALAR_TYPE(MAT2, MAT, C, CTX); \ + STATUS |= gr_mat_##OP##_##SCALAR_TYPE(DMAT2, DMAT, C, CTX); \ + + +#define TEST_MUL_SCALAR(STATUS, K, MAT_TYPE, SCALAR_TYPE, MAT, MAT2, DMAT, DMAT2, C, CTX) { \ + if (K == 1) \ + { TEST_OP_SCALAR(STATUS, MAT_TYPE, div, SCALAR_TYPE, MAT, MAT2, DMAT, DMAT2, C, CTX) } \ + else \ + { \ + TEST_OP_SCALAR(STATUS, MAT_TYPE, mul, SCALAR_TYPE, MAT, MAT2, DMAT, DMAT2, C, CTX) \ + if (K == 2) \ + { TEST_OP_SCALAR(STATUS, MAT_TYPE, divexact, SCALAR_TYPE, MAT2, MAT2, DMAT2, DMAT2, C, CTX) } \ + } \ +} + +int test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) +{ + slong i, j, k, l; + slong M = 20; + slong N = 20; + slong n_tests = 20; + int status = GR_SUCCESS; + gr_csr_mat_t csr_mat, csr_mat2; + gr_lil_mat_t lil_mat, lil_mat2; + gr_coo_mat_t coo_mat, coo_mat2; + gr_mat_t dmat, dmat2; + slong c; + ulong uc; + gr_ptr gr_c; + fmpz_t fmpz_c; + fmpq_t fmpq_c; + truth_t eq; + + GR_TMP_INIT(gr_c, ctx); + gr_mat_init(dmat, M, N, ctx); + gr_mat_init(dmat2, M, N, ctx); + gr_coo_mat_init(coo_mat, M, N, ctx); + gr_coo_mat_init(coo_mat2, M, N, ctx); + gr_csr_mat_init(csr_mat, M, N, ctx); + gr_csr_mat_init(csr_mat2, M, N, ctx); + gr_lil_mat_init(lil_mat, M, N, ctx); + gr_lil_mat_init(lil_mat2, M, N, ctx); + + for (i = 0; i < 54 * n_tests; i++) + { + j = i % 6; // Which type of scalar + k = (i / 6) % 3; // Mul, div, or mul + divexact + l = (i / 18) % 3; // CSR, LIL, or COO mat + //flint_printf("\nTesting (%d, %d, %d)\n", l, k, j); + if ((j == 4 || k == 1) && gr_ctx_is_field(ctx) != T_TRUE) + continue; + if (k == 2 && (gr_ctx_is_exact(ctx) != T_TRUE || gr_ctx_is_integral_domain(ctx) != T_TRUE)) + continue; + status |= gr_coo_mat_randtest(coo_mat, 80, 0, T_TRUE, state, ctx); + status |= gr_mat_set_coo_mat(dmat, coo_mat, ctx); + if (l == 0) + status |= gr_csr_mat_set_coo_mat(csr_mat, coo_mat, ctx); + else if (l == 1) + status |= gr_lil_mat_set_coo_mat(lil_mat, coo_mat, ctx); + + //flint_printf("\nmat = "); status |= gr_coo_mat_print_nz(coo_mat, ctx); flint_printf("\n"); + //flint_printf("\nmat = "); status |= gr_mat_print(dmat, ctx); flint_printf("\n"); + switch(j) + { + case 0: + //flint_printf("Testing scalar\n"); + status |= gr_randtest_not_zero(gr_c, state, ctx); + if (l == 0) + TEST_MUL_SCALAR(status, k, csr, scalar, csr_mat, csr_mat2, dmat, dmat2, gr_c, ctx) + else if (l == 1) + TEST_MUL_SCALAR(status, k, lil, scalar, lil_mat, lil_mat2, dmat, dmat2, gr_c, ctx) + else + TEST_MUL_SCALAR(status, k, coo, scalar, coo_mat, coo_mat2, dmat, dmat2, gr_c, ctx) + break; + case 1: + c = n_randint(state, 0); + //flint_printf("Testing scalar_si = %ld\n", c); + if (l == 0) + TEST_MUL_SCALAR(status, k, csr, scalar_si, csr_mat, csr_mat2, dmat, dmat2, c, ctx) + else if (l == 1) + TEST_MUL_SCALAR(status, k, lil, scalar_si, lil_mat, lil_mat2, dmat, dmat2, c, ctx) + else + TEST_MUL_SCALAR(status, k, coo, scalar_si, coo_mat, coo_mat2, dmat, dmat2, c, ctx) + break; + case 2: + //flint_printf("Testing scalar_ui\n"); + uc = n_randint(state, 0); + if (l == 0) + TEST_MUL_SCALAR(status, k, csr, scalar_ui, csr_mat, csr_mat2, dmat, dmat2, uc, ctx) + else if (l == 1) + TEST_MUL_SCALAR(status, k, lil, scalar_ui, lil_mat, lil_mat2, dmat, dmat2, uc, ctx) + else + TEST_MUL_SCALAR(status, k, coo, scalar_ui, coo_mat, coo_mat2, dmat, dmat2, uc, ctx) + break; + case 3: + //flint_printf("Testing scalar_fmpz\n"); + fmpz_randtest_not_zero(fmpz_c, state, 32); + if (l == 0) + TEST_MUL_SCALAR(status, k, csr, scalar_fmpz, csr_mat, csr_mat2, dmat, dmat2, fmpz_c, ctx) + else if (l == 1) + TEST_MUL_SCALAR(status, k, lil, scalar_fmpz, lil_mat, lil_mat2, dmat, dmat2, fmpz_c, ctx) + else + TEST_MUL_SCALAR(status, k, coo, scalar_fmpz, coo_mat, coo_mat2, dmat, dmat2, fmpz_c, ctx) + break; + case 4: + //flint_printf("Testing scalar_fmpq\n"); + fmpq_randtest_not_zero(fmpq_c, state, 32); + if (l == 0) + TEST_MUL_SCALAR(status, k, csr, scalar_fmpq, csr_mat, csr_mat2, dmat, dmat2, fmpq_c, ctx) + else if (l == 1) + TEST_MUL_SCALAR(status, k, lil, scalar_fmpq, lil_mat, lil_mat2, dmat, dmat2, fmpq_c, ctx) + else + TEST_MUL_SCALAR(status, k, coo, scalar_fmpq, coo_mat, coo_mat2, dmat, dmat2, fmpq_c, ctx) + break; + case 5: + //flint_printf("Testing scalar_2exp_si\n"); + // Scaling by 2^c always done with multiply, even if it is a divide + c = n_randint(state, 32) + 1; + if (k == 0 || k == 2) + { + if (l == 0) + { TEST_OP_SCALAR(status, csr, mul, scalar_2exp_si, csr_mat, csr_mat2, dmat, dmat2, c, ctx) } + else if (l == 1) + { TEST_OP_SCALAR(status, lil, mul, scalar_2exp_si, lil_mat, lil_mat2, dmat, dmat2, c, ctx) } + else + { TEST_OP_SCALAR(status, coo, mul, scalar_2exp_si, coo_mat, coo_mat2, dmat, dmat2, c, ctx) } + } + if (k == 1 || k == 2) + { + if (l == 0) + { TEST_OP_SCALAR(status, csr, mul, scalar_2exp_si, csr_mat, csr_mat2, dmat, dmat2, -c, ctx) } + else if (l == 1) + { TEST_OP_SCALAR(status, lil, mul, scalar_2exp_si, lil_mat, lil_mat2, dmat, dmat2, -c, ctx) } + else + { TEST_OP_SCALAR(status, coo, mul, scalar_2exp_si, coo_mat, coo_mat2, dmat, dmat2, -c, ctx) } + } + break; + } + + // If any operation not allowed, just skip test + if (status == GR_UNABLE || status == GR_DOMAIN) // TODO: FIXME + { + status = GR_SUCCESS; + continue; + } + //gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); + //gr_sparse_vec_print_nz(vec2, ctx); flint_printf("\n"); + + if (l == 0) + status |= gr_mat_set_csr_mat(dmat, csr_mat2, ctx); + else if (l == 1) + status |= gr_mat_set_lil_mat(dmat, lil_mat2, ctx); + else + status |= gr_mat_set_coo_mat(dmat, coo_mat2, ctx); + eq = gr_mat_equal(dmat, dmat2, ctx); + if (eq == T_FALSE || status != GR_SUCCESS) + { + flint_printf( + "j = %d, k = %d, equal = %d, status = %d\n", + j, k, eq, status + ); + gr_ctx_println(ctx); + flint_printf("\n\ndmat: "); status |= gr_mat_print(dmat, ctx); flint_printf("\n"); + flint_printf("\n\ndmat2: "); status |= gr_mat_print(dmat2, ctx); flint_printf("\n"); + if (l == 0) + { + status |= gr_csr_mat_set_mat(csr_mat, dmat2, ctx); + status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\n"); + status |= gr_csr_mat_print_nz(csr_mat2, ctx); flint_printf("\n"); + } + else if (l == 1) + { + status |= gr_lil_mat_set_mat(lil_mat, dmat2, ctx); + status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\n"); + status |= gr_lil_mat_print_nz(lil_mat2, ctx); flint_printf("\n"); + } + else + { + status |= gr_coo_mat_set_mat(coo_mat, dmat2, ctx); + status |= gr_coo_mat_print_nz(coo_mat, ctx); flint_printf("\n"); + status |= gr_coo_mat_print_nz(coo_mat2, ctx); flint_printf("\n"); + } + return GR_TEST_FAIL; + } + } + + fmpz_clear(fmpz_c); + fmpq_clear(fmpq_c); + gr_csr_mat_clear(csr_mat, ctx); + gr_csr_mat_clear(csr_mat2, ctx); + gr_lil_mat_clear(lil_mat, ctx); + gr_lil_mat_clear(lil_mat2, ctx); + gr_coo_mat_clear(coo_mat, ctx); + gr_coo_mat_clear(coo_mat2, ctx); + gr_mat_clear(dmat, ctx); + gr_mat_clear(dmat2, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_mat_arith, state) +{ + slong i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while (1) + { + //gr_ctx_init_fmpz(ctx); + gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + CHECK_TEST(test_neg(state, ctx), "Sparse matrix negation"); + CHECK_TEST(test_add_sub(state, ctx), "Sparse matrix addition, subtraction, and multiplication"); + CHECK_TEST(test_accum_mul_scalar(state, ctx), "Sparse matrix scalar addmul and submul"); + CHECK_TEST(test_mul_div_scalar(state, ctx), "Sparse matrix scalar multiplication and division"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_mat/test/t-mul.c b/src/gr_sparse_mat/test/t-mul.c new file mode 100644 index 0000000000..d41577f3d7 --- /dev/null +++ b/src/gr_sparse_mat/test/t-mul.c @@ -0,0 +1,194 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public 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 "test_helpers.h" +#include "gr_sparse_mat.h" + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int test_mul(flint_rand_t state, gr_ctx_t ctx) +{ + slong i, j; + slong M = 5; + slong N = 15; + slong O = 2; + slong n_tests = 20; + int status = GR_SUCCESS; + truth_t eq; + gr_csr_mat_t csr_mat; + gr_lil_mat_t lil_mat; + gr_coo_mat_t coo_mat; + gr_ptr u, v, v2; + gr_mat_t dmat, U, V, V2; + gr_mat_t UT, VT, VT2; + + gr_coo_mat_init(coo_mat, M, N, ctx); + gr_csr_mat_init(csr_mat, M, N, ctx); + gr_lil_mat_init(lil_mat, M, N, ctx); + gr_mat_init(dmat, M, N, ctx); + + GR_TMP_INIT_VEC(u, N, ctx); + gr_mat_init(UT, O, N, ctx); + gr_mat_init(U, N, O, ctx); + + GR_TMP_INIT_VEC(v, M, ctx); + gr_mat_init(VT, O, M, ctx); + gr_mat_init(V, M, O, ctx); + + GR_TMP_INIT_VEC(v2, M, ctx); + gr_mat_init(VT2, O, M, ctx); + gr_mat_init(V2, M, O, ctx); + + //flint_printf("Testing sparse matrix-vector multiplication\n"); + for (i = 0; i < 2*n_tests; i++) + { + j = i % 2; // CSR or LIL mat + + // Get random sparse matrix + status |= gr_coo_mat_randtest(coo_mat, 20, 0, T_TRUE, state, ctx); + status |= gr_mat_set_coo_mat(dmat, coo_mat, ctx); + if (j == 0) + status |= gr_csr_mat_set_coo_mat(csr_mat, coo_mat, ctx); + else + status |= gr_lil_mat_set_coo_mat(lil_mat, coo_mat, ctx); + + // Get a random dense vector + status |= _gr_vec_randtest(u, state, N, ctx); + + // Compute matrix multiply using sparse and dense reprs + if (j == 0) + status |= gr_csr_mat_mul_vec(v, csr_mat, u, ctx); + else + status |= gr_lil_mat_mul_vec(v, lil_mat, u, ctx); + status |= gr_mat_mul_vec(v2, dmat, u, ctx); + + eq = _gr_vec_equal(v, v2, M, ctx); + if (eq == T_FALSE || status != GR_SUCCESS) + { + gr_ctx_println(ctx); + if (j == 0) + { + status |= flint_printf("mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\n"); + } + else + { + status |= flint_printf("mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\n"); + } + flint_printf("u = "); status |= _gr_vec_print(u, N, ctx); flint_printf("\n"); + flint_printf("v = "); status |= _gr_vec_print(v, M, ctx); flint_printf("\n"); + flint_printf("v2 = "); status |= _gr_vec_print(v2, M, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + + // Get a random dense column matrix + status |= gr_mat_randtest(UT, state, ctx); + + // Compute matrix multiply using sparse and dense reprs + if (j == 0) + status |= gr_csr_mat_mul_mat_transpose(VT, csr_mat, UT, ctx); + else + status |= gr_lil_mat_mul_mat_transpose(VT, lil_mat, UT, ctx); + status |= gr_mat_transpose(U, UT, ctx); + status |= gr_mat_mul(V2, dmat, U, ctx); + status |= gr_mat_transpose(VT2, V2, ctx); + + eq = gr_mat_equal(VT, VT2, ctx); + if (eq == T_FALSE || status != GR_SUCCESS) + { + gr_ctx_println(ctx); + flint_printf("j = %d, eq = %d, status = %d\n", j, eq, status); + if (j == 0) + { + status |= flint_printf("mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\n"); + } + else + { + status |= flint_printf("mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\n"); + } + flint_printf("UT = "); status |= gr_mat_print(UT, ctx); flint_printf("\n"); + flint_printf("VT = "); status |= gr_mat_print(VT, ctx); flint_printf("\n"); + flint_printf("VT2 = "); status |= gr_mat_print(VT2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + + // Get a random dense row matrix + status |= gr_mat_randtest(U, state, ctx); + + // Compute matrix multiply using sparse and dense reprs + if (j == 0) + status |= gr_csr_mat_mul_mat(V, csr_mat, U, ctx); + else + status |= gr_lil_mat_mul_mat(V, lil_mat, U, ctx); + + //flint_printf("\nBefore matmul U = "); gr_mat_print(U, ctx); flint_printf("\n"); + status |= gr_mat_mul(V2, dmat, U, ctx); + //flint_printf("\nAfter matmul U = "); gr_mat_print(U, ctx); flint_printf("\n"); + + eq = gr_mat_equal(V, V2, ctx); + if (eq == T_FALSE || status != GR_SUCCESS) + { + gr_ctx_println(ctx); + flint_printf("j = %d, eq = %d, status = %d\n", j, eq, status); + if (j == 0) + { + status |= flint_printf("mat = "); status |= gr_csr_mat_print_nz(csr_mat, ctx); flint_printf("\n"); + } + else + { + status |= flint_printf("mat = "); status |= gr_lil_mat_print_nz(lil_mat, ctx); flint_printf("\n"); + } + flint_printf("U = "); status |= gr_mat_print(U, ctx); flint_printf("\n"); + flint_printf("V = "); status |= gr_mat_print(V, ctx); flint_printf("\n"); + flint_printf("V2 = "); status |= gr_mat_print(V2, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + + gr_mat_clear(U, ctx); + gr_mat_clear(UT, ctx); + GR_TMP_CLEAR_VEC(u, N, ctx); + + gr_mat_clear(V, ctx); + gr_mat_clear(VT, ctx); + GR_TMP_CLEAR_VEC(v, M, ctx); + + gr_mat_clear(VT2, ctx); + gr_mat_clear(V2, ctx); + GR_TMP_CLEAR_VEC(v2, M, ctx); + + gr_mat_clear(dmat, ctx); + gr_csr_mat_clear(csr_mat, ctx); + gr_lil_mat_clear(lil_mat, ctx); + gr_coo_mat_clear(coo_mat, ctx); + return status; +} + +TEST_FUNCTION_START(gr_sparse_mat_mul, state) +{ + slong i; + gr_ctx_t ctx; + for (i = 0; i < 16; ++i) + { + while (1) + { + //gr_ctx_init_fmpz(ctx); + gr_ctx_init_random(ctx, state); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + //gr_ctx_println(ctx); + CHECK_TEST(test_mul(state, ctx), "Sparse matrix-vector and sparse matrix-matrix products"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_vec/test/t-arith.c b/src/gr_sparse_vec/test/t-arith.c index 1a623c40b7..6e9c062887 100644 --- a/src/gr_sparse_vec/test/t-arith.c +++ b/src/gr_sparse_vec/test/t-arith.c @@ -294,8 +294,8 @@ int test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) STATUS |= _gr_vec_mul_##TYPE(DVEC2, DVEC, N, C, CTX); \ if (K == 2) \ { \ - STATUS |= gr_sparse_vec_divexact_##TYPE(VEC2, VEC, C, CTX); \ - STATUS |= _gr_vec_divexact_##TYPE(DVEC2, DVEC, N, C, CTX); \ + STATUS |= gr_sparse_vec_divexact_##TYPE(VEC2, VEC2, C, CTX); \ + STATUS |= _gr_vec_divexact_##TYPE(DVEC2, DVEC2, N, C, CTX); \ } \ } \ } diff --git a/src/gr_vec.h b/src/gr_vec.h index 363c65c7f0..3489dd359b 100644 --- a/src/gr_vec.h +++ b/src/gr_vec.h @@ -58,6 +58,14 @@ int _gr_vec_print(gr_srcptr vec, slong len, gr_ctx_t ctx); int gr_vec_print(const gr_vec_t vec, gr_ctx_t ctx); GR_VEC_INLINE WARN_UNUSED_RESULT int _gr_vec_zero(gr_ptr vec, slong len, gr_ctx_t ctx) { return GR_VEC_CONSTANT_OP(ctx, VEC_ZERO)(vec, len, ctx); } +GR_VEC_INLINE WARN_UNUSED_RESULT int _gr_vec_one(gr_ptr vec, slong pos, slong len, gr_ctx_t ctx) +{ + int status; + if (pos < 0 || len < 0 || pos >= len) + return GR_DOMAIN; + status = GR_VEC_CONSTANT_OP(ctx, VEC_ZERO)(vec, len, ctx); + return status | gr_one(GR_ENTRY(vec, pos, ctx->sizeof_elem), ctx); +} GR_VEC_INLINE WARN_UNUSED_RESULT int _gr_vec_set(gr_ptr res, gr_srcptr src, slong len, gr_ctx_t ctx) { return GR_VEC_OP(ctx, VEC_SET)(res, src, len, ctx); } GR_VEC_INLINE WARN_UNUSED_RESULT int _gr_vec_neg(gr_ptr res, gr_srcptr src, slong len, gr_ctx_t ctx) { return GR_VEC_OP(ctx, VEC_NEG)(res, src, len, ctx); } From 71eb7d2ccd6b0577ca3944ab7de8382a74256b4e Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Fri, 22 Mar 2024 03:29:41 -0700 Subject: [PATCH 52/59] Added solvers, compiles but will not work yet --- src/gr_mat.h | 4 + src/gr_mat/addmul.c | 24 ++ src/gr_mat/addmul_classical.c | 117 +++++++++ src/gr_sparse_mat.h | 42 ++++ src/gr_sparse_mat/nullspace.c | 109 ++++++++ src/gr_sparse_mat/solve_block_lanczos.c | 289 ++++++++++++++++++++++ src/gr_sparse_mat/solve_block_wiedemann.c | 288 +++++++++++++++++++++ src/gr_sparse_mat/solve_lanczos.c | 125 ++++++++++ src/gr_sparse_mat/solve_wiedemann.c | 259 +++++++++++++++++++ src/gr_sparse_mat/transpose.c | 63 +++++ src/gr_sparse_vec/set.c | 2 +- 11 files changed, 1321 insertions(+), 1 deletion(-) create mode 100644 src/gr_mat/addmul.c create mode 100644 src/gr_mat/addmul_classical.c create mode 100644 src/gr_sparse_mat/nullspace.c create mode 100644 src/gr_sparse_mat/solve_block_lanczos.c create mode 100644 src/gr_sparse_mat/solve_block_wiedemann.c create mode 100644 src/gr_sparse_mat/solve_lanczos.c create mode 100644 src/gr_sparse_mat/solve_wiedemann.c create mode 100644 src/gr_sparse_mat/transpose.c diff --git a/src/gr_mat.h b/src/gr_mat.h index 6cbd37560e..e41e7456a2 100644 --- a/src/gr_mat.h +++ b/src/gr_mat.h @@ -171,6 +171,10 @@ WARN_UNUSED_RESULT int gr_mat_mul_strassen(gr_mat_t C, const gr_mat_t A, const g WARN_UNUSED_RESULT int gr_mat_mul_generic(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_mat_mul(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_addmul_classical(gr_mat_t D, const gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_addmul_generic(gr_mat_t D, const gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_addmul(gr_mat_t D, const gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); + /* todo */ GR_MAT_INLINE WARN_UNUSED_RESULT int gr_mat_sqr(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) diff --git a/src/gr_mat/addmul.c b/src/gr_mat/addmul.c new file mode 100644 index 0000000000..7dc4a06182 --- /dev/null +++ b/src/gr_mat/addmul.c @@ -0,0 +1,24 @@ +/* + Copyright (C) 2022 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 3 of the License, or + (at your option) any later version. See . +*/ + +#include "gr_mat.h" + +int +gr_mat_addmul_generic(gr_mat_t D, const gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx) +{ + return gr_mat_mul_classical(C, A, B, ctx); +} + +int +gr_mat_addmul(gr_mat_t D, const gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx) +{ + return gr_mat_addmul_generic(D, C, A, B, ctx); +} diff --git a/src/gr_mat/addmul_classical.c b/src/gr_mat/addmul_classical.c new file mode 100644 index 0000000000..dc97d4ec49 --- /dev/null +++ b/src/gr_mat/addmul_classical.c @@ -0,0 +1,117 @@ +/* + Copyright (C) 2022 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 3 of the License, or + (at your option) any later version. See . +*/ + +#include +#include "gr_vec.h" +#include "gr_mat.h" + +int +gr_mat_addmul_classical(gr_mat_t D, const gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx) +{ + slong ar, ac, br, bc, i, j, sz; + int status; + + ar = gr_mat_nrows(A, ctx); + ac = gr_mat_ncols(A, ctx); + br = gr_mat_nrows(B, ctx); + bc = gr_mat_ncols(B, ctx); + + if (gr_mat_is_compatible(C, D, ctx) == T_FALSE || ac != br || ar != gr_mat_nrows(C, ctx) || bc != gr_mat_ncols(C, ctx)) + return GR_DOMAIN; + + if (br == 0) + { + return GR_SUCCESS; + } + + status = GR_SUCCESS; + + if (A == D || B == D) + { + gr_mat_t T; + gr_mat_init(T, ar, bc, ctx); + status |= gr_mat_addmul_classical(T, C, A, B, ctx); + status |= gr_mat_swap_entrywise(T, D, ctx); + gr_mat_clear(T, ctx); + return status; + } + + sz = ctx->sizeof_elem; + + if (br == 1) + { + for (i = 0; i < ar; i++) + { + for (j = 0; j < bc; j++) + { + if (C != D) + status |= gr_set(GR_MAT_ENTRY(D, i, j, sz), GR_MAT_ENTRY(C, i, j, sz), ctx); + status |= gr_addmul(GR_MAT_ENTRY(D, i, j, sz), + GR_MAT_ENTRY(A, i, 0, sz), + GR_MAT_ENTRY(B, 0, j, sz), ctx); + } + } + } + else + { + gr_ptr tmp; + gr_method_void_unary_op set_shallow = GR_VOID_UNARY_OP(ctx, SET_SHALLOW); + TMP_INIT; + + TMP_START; + tmp = TMP_ALLOC(sz * br * bc); + + /* Make a shallow transpose so that we can use dot products. + Inline common sizes. (Caution: are we sure about the alignment? + Some asserts would be nice here.) + Todo: we may want inlining in nonsingular_solve etc. as well. */ + for (i = 0; i < br; i++) + { + for (j = 0; j < bc; j++) + { + switch (sz) + { +#if 0 + case 1: + ((int8_t *) GR_ENTRY(tmp, j * br + i, 1))[0] = ((int8_t *) GR_MAT_ENTRY(B, i, j, 1))[0]; + break; + case 2: + ((int16_t *) GR_ENTRY(tmp, j * br + i, 2))[0] = ((int16_t *) GR_MAT_ENTRY(B, i, j, 2))[0]; + break; + case 4: + ((int32_t *) GR_ENTRY(tmp, j * br + i, 4))[0] = ((int32_t *) GR_MAT_ENTRY(B, i, j, 4))[0]; + break; +#if FLINT_BITS == 64 + case 8: + ((int64_t *) GR_ENTRY(tmp, j * br + i, 8))[0] = ((int64_t *) GR_MAT_ENTRY(B, i, j, 8))[0]; + break; +#endif +#endif + default: + set_shallow(GR_ENTRY(tmp, j * br + i, sz), GR_MAT_ENTRY(B, i, j, sz), ctx); + } + } + } + + for (i = 0; i < ar; i++) + { + for (j = 0; j < bc; j++) + { + status |= _gr_vec_dot(GR_MAT_ENTRY(D, i, j, sz), GR_MAT_ENTRY(C, i, j, sz), 0, + GR_MAT_ENTRY(A, i, 0, sz), GR_ENTRY(tmp, j * br, sz), br, ctx); + } + } + + TMP_END; + } + + return status; +} diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index cb736bed61..0d3c28b030 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -772,6 +772,11 @@ GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_nz_product(gr_ptr res, co GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_coo_mat_nz_product(gr_ptr res, const gr_coo_mat_t mat, gr_ctx_t ctx) { return _gr_vec_product(res, mat->nzs, mat->nnz, ctx); } +/** + * Transpose +*/ +int gr_lil_mat_transpose(gr_lil_mat_t B, const gr_lil_mat_t A, gr_ctx_t ctx); + /** * Matrix multiplication **/ @@ -785,6 +790,43 @@ WARN_UNUSED_RESULT int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_ma WARN_UNUSED_RESULT int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ctx_t ctx); +/** + * Solving, nullvector, and nullspace computation +**/ + +WARN_UNUSED_RESULT int gr_lil_mat_solve_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, flint_rand_t state, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_solve_block_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, slong block_size, flint_rand_t state, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_solve_wiedemann(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_solve_block_wiedemann(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, slong block_size, flint_rand_t state, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_lil_mat_nullvector_lanczos(gr_ptr x, const gr_lil_mat_t M, flint_rand_t state, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_nullvector_block_lanczos(gr_ptr x, const gr_lil_mat_t M, slong block_size, flint_rand_t state, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_nullvector_wiedemann(gr_ptr x, const gr_lil_mat_t M, flint_rand_t state, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_nullvector_block_wiedemann(gr_ptr x, const gr_lil_mat_t M, slong block_size, flint_rand_t state, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_lil_mat_nullspace(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, const char *algorithm, slong block_size, gr_ctx_t ctx); + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_nullspace_lanczos(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, gr_ctx_t ctx) +{ + return gr_lil_mat_nullspace(X, M, state, max_iters, "lanczos", 1, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_nullspace_wiedemann(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, gr_ctx_t ctx) +{ + return gr_lil_mat_nullspace(X, M, state, max_iters, "wiedemann", 1, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_nullspace_block_lanczos(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, slong block_size, gr_ctx_t ctx) +{ + return gr_lil_mat_nullspace(X, M, state, max_iters, "block lanczos", block_size, ctx); +} + +GR_SPARSE_MAT_INLINE WARN_UNUSED_RESULT int gr_lil_mat_nullspace_block_wiedemann(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, slong block_size, gr_ctx_t ctx) +{ + return gr_lil_mat_nullspace(X, M, state, max_iters, "block wiedemann", block_size, ctx); +} + + /* WARN_UNUSED_RESULT int gr_sparse_mat_lu(slong * rank, slong * P, gr_csr_mat_t LU, const gr_csr_mat_t A, int rank_check, gr_ctx_t ctx); diff --git a/src/gr_sparse_mat/nullspace.c b/src/gr_sparse_mat/nullspace.c new file mode 100644 index 0000000000..70daaaa37b --- /dev/null +++ b/src/gr_sparse_mat/nullspace.c @@ -0,0 +1,109 @@ +/* + Copyright (C) 2010 Fredrik Johansson + Copyright (C) 2024 Kartik Venkatram + + This file is part of FLINT. + + FLINT is 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 "stdlib.h" +#include "gr_sparse_mat.h" + +int gr_lil_mat_nullspace(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, const char *algorithm, slong block_size, gr_ctx_t ctx) +{ + /* Generate random solutions to a random system Mx = b and stop when nullspace filled */ + slong i, j, c, iter, nullity, *x_pivots, sz; + gr_ptr x, coeff, *xs; + int status = GR_SUCCESS, cur_status; + + sz = ctx->sizeof_elem; + c = gr_sparse_mat_ncols(M, ctx); + + GR_TMP_INIT(coeff, ctx); + GR_TMP_INIT_VEC(x, c, ctx); + nullity = 0; + xs = NULL; + x_pivots = NULL; + for (iter = 0; iter < max_iters; ) + { + if (strcmp(algorithm, "lanczos") == 0) + cur_status = gr_lil_mat_nullvector_lanczos(x, M, state, ctx); + else if (strcmp(algorithm, "wiedemann") == 0) + cur_status = gr_lil_mat_nullvector_wiedemann(x, M, state, ctx); + else if (strcmp(algorithm, "block lanczos") == 0) + cur_status = gr_lil_mat_nullvector_block_lanczos(x, M, block_size, state, ctx); + else if (strcmp(algorithm, "block wiedemann") == 0) + cur_status = gr_lil_mat_nullvector_block_wiedemann(x, M, block_size, state, ctx); + else + { + status = GR_DOMAIN; + break; + } + if (cur_status == GR_TEST_FAIL) + { + ++iter; + continue; + } + + /* Reduce by existing kernel vectors */ + for (j = nullity-1; j >= 0; --j) + { + status |= gr_neg(coeff, GR_ENTRY(x, x_pivots[j], sz), ctx); + status |= _gr_vec_addmul_scalar(x, xs[j], c, coeff, ctx); + } + + /* Normalize last nonzero entry to 1 */ + for (i = c-1; i >= 0; --i) + if (gr_is_zero(GR_ENTRY(x, i, sz), ctx) != T_TRUE) + break; + if (i == -1) { + /* x in span of xs, nullspace probably complete */ + ++iter; + continue; + } + status |= gr_inv(coeff, GR_ENTRY(x, i, sz), ctx); + status |= _gr_vec_mul_scalar(x, x, c, coeff, ctx); + + /* Reduce previous vectors by this one */ + for (j = 0; j < nullity; ++j) + { + status |= gr_neg(coeff, GR_ENTRY(xs[j], i, sz), ctx); + status |= _gr_vec_addmul_scalar(xs[j], x, c, coeff, ctx); + } + + /* Insert into list of vectors in nullspace (ordered by pivot) */ + xs = flint_realloc(xs, (nullity+1)*sizeof(gr_ptr)); + x_pivots = flint_realloc(x_pivots, (nullity+1)*sizeof(slong *)); + for (j = 0; j < nullity; ++j) + if (i > x_pivots[j]) + break; + memmove(xs + j + 1, xs + j, (nullity - j) * sizeof(gr_ptr)); + memmove(x_pivots + j + 1, x_pivots + j, (nullity - j) * sizeof(slong *)); + x_pivots[j] = i; + xs[j] = x; // Steal allocation + x = NULL; + GR_TMP_INIT_VEC(x, c, ctx); + + // Advance nullity and restart iteration + nullity += 1; + iter = 0; + } + // Set X to have xs as column vectors + // TODO: can use shallow to reuse memory? + gr_mat_init(X, c, nullity, ctx); + for (i = 0; i < nullity; ++i) + for (j = 0; j < c; ++j) + status |= gr_set(gr_mat_entry_ptr(X, j, i, ctx), GR_ENTRY(xs[i], j, sz), ctx); + + flint_free(x_pivots); + GR_TMP_CLEAR_VEC(x, c, ctx); + for (i = 0; i < nullity; ++i) + GR_TMP_CLEAR_VEC(xs[i], c, ctx); + flint_free(xs); + return status; +} + diff --git a/src/gr_sparse_mat/solve_block_lanczos.c b/src/gr_sparse_mat/solve_block_lanczos.c new file mode 100644 index 0000000000..42e8673dc5 --- /dev/null +++ b/src/gr_sparse_mat/solve_block_lanczos.c @@ -0,0 +1,289 @@ +/* + 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 "gr_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(slong *rk, gr_mat_t nWi, int *S, const gr_mat_t Torig, gr_ctx_t ctx) +{ + const slong b = Torig->r; + slong pc, i, j; + gr_mat_t T; + gr_mat_struct *X; + slong *P; + gr_ptr cc; + int status = GR_SUCCESS; + + GR_TMP_INIT(cc, ctx); + P = flint_malloc(b * sizeof(*P)); + gr_mat_init(T, b, b, ctx); + status |= gr_mat_set(T, Torig, ctx); + status |= gr_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; + + *rk = 0; + 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; ++i) + if (gr_is_zero(gr_mat_entry_srcptr(X, P[i], pc, ctx), ctx) == T_FALSE) + break; + if (i == b) + for (X = nWi, i = j; i < b; ++i) + if (gr_is_zero(gr_mat_entry_srcptr(X, P[i], pc, ctx), ctx) == T_FALSE) + break; + S[pc] = X == T; /* Viable column in V */ + status |= gr_mat_swap_rows(T, NULL, pc, P[i], ctx); + status |= gr_mat_swap_rows(nWi, NULL, pc, P[i], ctx); /* Now pivot row = pivot col */ + + /* Make pivot one */ + status |= gr_inv(cc, gr_mat_entry_ptr(X, pc, pc, ctx), ctx); + status |= _gr_vec_mul_scalar(T->rows[pc], T->rows[pc], b, cc, ctx); + status |= _gr_vec_mul_scalar(nWi->rows[pc], nWi->rows[pc], b, cc, ctx); + + + /* Kill all other entries in pivot column */ + for (i = 0; i < b; ++i) + { + status |= gr_neg(cc, gr_mat_entry_ptr(X, P[i], pc, ctx), ctx); + if (i == j || cc == 0) continue; + status |= _gr_vec_addmul_scalar(T->rows[P[i]], T->rows[pc], T->c, cc, ctx); + status |= _gr_vec_addmul_scalar(nWi->rows[P[i]], nWi->rows[pc], nWi->c, cc, ctx); + } + if (S[pc]) (*rk)++; /* Count viable columns */ + else + { + /* Kill row of both matrices */ + status |= _gr_vec_zero(T->rows[pc], b, ctx); + status |= _gr_vec_zero(nWi->rows[pc], b, ctx); + } + } + + status |= gr_mat_neg(nWi, nWi, ctx); + gr_mat_clear(T, ctx); + GR_TMP_CLEAR(cc, ctx); + + return status; +} + +static int kill_columns(gr_mat_t M, int *good, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + slong i, j; + for (j = 0; j < M->c; ++j) + if (good[j] == 0) + for (i = 0; i < M->r; ++i) + status |= gr_zero(gr_mat_entry_ptr(M, i, j, ctx), ctx); + return status; +} + +int gr_lil_mat_solve_block_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, slong block_size, flint_rand_t state, gr_ctx_t ctx) +{ + slong r, c, i, j, prev_i, next_i, iter, cur_dim, total_dim = 0; + gr_lil_mat_t Mt; /* Transpose of M, we work with A = MtM */ + gr_mat_struct V[3]; /* Keep track of current vector and two previous ones */ + gr_mat_t MV; /* Application of M to V */ + gr_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 */ + gr_mat_struct nWi[3]; /* -S((VS)^tAVS)^-1S^t */ + gr_mat_t VSSt; /* V with invalid vectors zeroed out */ + gr_mat_t T; /* Used to store transposes for inner products */ + gr_mat_t VtAV; /* Inner product _A */ + gr_mat_t AVtAVSSt_VtAV; /* Sum _A SS^t + _A, shared by two updates */ + gr_mat_t DEF; /* Used to store coefficient matrices D, E, and F */ + gr_mat_t I, tmp; /* I_{b x b}, tmp used as scratch */ + gr_ptr Mtb, SStVtMtb, WiSStVtMtb, VSStWiSStVtMtb; /* Intermediate elements in x update */ + int status = GR_SUCCESS; + + // TODO: handle this + if (x == b) + return GR_DOMAIN; + + r = gr_sparse_mat_nrows(M, ctx); + c = gr_sparse_mat_ncols(M, ctx); + + if (_gr_vec_is_zero(b, r, ctx)) + { + status |= _gr_vec_zero(x, c, ctx); + return GR_SUCCESS; + } + + gr_lil_mat_init(Mt, c, r, ctx); + for (i = 0; i < 3; ++i) + gr_mat_init(&V[i], c, block_size, ctx); + gr_mat_init(MV, r, block_size, ctx); /* Intermediate product */ + gr_mat_init(AV, c, block_size, ctx); /* Symmetric product */ + SSt = flint_malloc(block_size*sizeof(*SSt)); + for (i = 0; i < 3; ++i) + gr_mat_init(&nWi[i], block_size, block_size, ctx); + gr_mat_init(VSSt, c, block_size, ctx); + gr_mat_init(T, block_size, c, ctx); /* Transpose for computing matrix dot products */ + gr_mat_init(VtAV, block_size, block_size, ctx); + gr_mat_init(AVtAVSSt_VtAV, block_size, block_size, ctx); /* (AV)^T(AV) + VtAV */ + gr_mat_init(DEF, block_size, block_size, ctx); /* Shared by D, E, and F */ + gr_mat_init(I, block_size, block_size, ctx); + gr_mat_init(tmp, block_size, block_size, ctx); + GR_TMP_INIT_VEC(Mtb, c, ctx); + GR_TMP_INIT_VEC(SStVtMtb, block_size, ctx); + GR_TMP_INIT_VEC(WiSStVtMtb, block_size, ctx); + GR_TMP_INIT_VEC(VSStWiSStVtMtb, c, ctx); + + status |= _gr_vec_zero(x, c, ctx); + status |= gr_lil_mat_transpose(Mt, M, ctx); + for (i = 0; i < block_size; ++i) SSt[i] = 1; + status |= gr_mat_one(I, ctx); + status |= gr_lil_mat_mul_vec(Mtb, Mt, b, ctx); + + /* Initialize V[0] randomly */ + for (i = 0; i < c; ++i) + for (j = 0; j < block_size; ++j) + status |= gr_randtest(gr_mat_entry_ptr(&V[0], i, j, ctx), 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) */ + status |= gr_mat_addmul(DEF, I, VtAV, &nWi[prev_i], ctx); + status |= gr_mat_mul(tmp, &nWi[next_i], DEF, ctx); + status |= gr_mat_mul(DEF, tmp, AVtAVSSt_VtAV, ctx); + } + + /* Compute AV and V'AV */ + status |= gr_lil_mat_mul_mat(MV, M, &V[i], ctx); + status |= gr_lil_mat_mul_mat(AV, Mt, MV, ctx); + status |= gr_mat_transpose(T, &V[i], ctx); + status |= gr_mat_mul(VtAV, T, AV, ctx); + if (gr_mat_is_zero(VtAV, ctx) == T_TRUE) {status = GR_SUCCESS; break;} + + /* Compute W^{-1} and indices of bad vectors */ + status |= compute_nWi_S(&cur_dim, &nWi[i], SSt, VtAV, ctx); + total_dim += cur_dim; + if (cur_dim == 0 || total_dim > c) break; /* Ran out of vectors */ + + /* Update x_i = x_{i-1} - (VSS^t) W^{-1} (VSS^t)^tb */ + status |= gr_mat_set(VSSt, &V[i], ctx); + status |= kill_columns(VSSt, SSt, ctx); + status |= gr_mat_transpose(T, VSSt, ctx); + status |= gr_mat_mul_vec(SStVtMtb, T, Mtb, ctx); + status |= gr_mat_mul_vec(WiSStVtMtb, &nWi[i], SStVtMtb, ctx); + status |= gr_mat_mul_vec(VSStWiSStVtMtb, VSSt, WiSStVtMtb, ctx); + status |= _gr_vec_add(x, x, VSStWiSStVtMtb, 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 */ + status |= kill_columns(DEF, SSt, ctx); + status |= gr_mat_mul(VSSt, &V[next_i], DEF, ctx); + status |= gr_mat_set(&V[next_i], VSSt, ctx); + } + if (iter >= 1) + { + /* V_{i+1} += V_{i-1} E */ + status |= gr_mat_mul(DEF, &nWi[prev_i], VtAV, ctx); + status |= kill_columns(DEF, SSt, ctx); + status |= gr_mat_addmul(&V[next_i], &V[next_i], &V[prev_i], DEF, ctx); + } + /* V_{i+1} += V_i D */ + status |= gr_mat_transpose(T, AV, ctx); + status |= gr_mat_mul(tmp, T, AV, ctx); + status |= kill_columns(tmp, SSt, ctx); + status |= gr_mat_add(AVtAVSSt_VtAV, tmp, VtAV, ctx); + status |= gr_mat_addmul(DEF, I, &nWi[i], AVtAVSSt_VtAV, ctx); + status |= gr_mat_addmul(&V[next_i], &V[next_i], &V[i], DEF, ctx); + + /* V_{i+1} += AVSS^t */ + status |= kill_columns(AV, SSt, ctx); + status |= gr_mat_add(&V[next_i], &V[next_i], AV, ctx); + + if (gr_mat_is_zero(&V[next_i], ctx) == T_TRUE) {status = GR_SUCCESS; break;} + } + status |= _gr_vec_neg(x, x, c, ctx); + gr_lil_mat_clear(Mt, ctx); + for (i = 0; i < 3; ++i) + gr_mat_clear(&V[i], ctx); + gr_mat_clear(MV, ctx); + gr_mat_clear(AV, ctx); + flint_free(SSt); + for (i = 0; i < 3; ++i) + gr_mat_clear(&nWi[i], ctx); + gr_mat_clear(T, ctx); + gr_mat_clear(VtAV, ctx); + gr_mat_clear(VSSt, ctx); + gr_mat_clear(AVtAVSSt_VtAV, ctx); + gr_mat_clear(DEF, ctx); + gr_mat_clear(I, ctx); + gr_mat_clear(tmp, ctx); + GR_TMP_CLEAR_VEC(Mtb, c, ctx); + GR_TMP_CLEAR_VEC(SStVtMtb, block_size, ctx); + GR_TMP_CLEAR_VEC(WiSStVtMtb, block_size, ctx); + GR_TMP_CLEAR_VEC(VSStWiSStVtMtb, c, ctx); + return status; +} + +int gr_lil_mat_nullvector_block_lanczos(gr_ptr x, const gr_lil_mat_t M, slong block_size, flint_rand_t state, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + gr_ptr x2, b; + GR_TMP_INIT_VEC(x2, M->c, ctx); + GR_TMP_INIT_VEC(b, M->r, ctx); + + status |= _gr_vec_randtest(x, state, M->c, ctx); + status |= gr_lil_mat_mul_vec(b, M, x, ctx); + status |= gr_lil_mat_solve_block_lanczos(x2, M, b, block_size, state, ctx); + + if (status == GR_SUCCESS) + { + status |= _gr_vec_sub(x, x, x2, M->c, ctx); + if (_gr_vec_is_zero(x, M->c, ctx) == T_TRUE) + status = GR_TEST_FAIL; + else + { + status |= gr_lil_mat_mul_vec(b, M, x, ctx); + if (_gr_vec_is_zero(b, M->r, ctx) == T_FALSE) + status = GR_DOMAIN; + } + } + GR_TMP_CLEAR_VEC(x2, M->c, ctx); + GR_TMP_CLEAR_VEC(b, M->r, ctx); + return status; +} diff --git a/src/gr_sparse_mat/solve_block_wiedemann.c b/src/gr_sparse_mat/solve_block_wiedemann.c new file mode 100644 index 0000000000..16137fb670 --- /dev/null +++ b/src/gr_sparse_mat/solve_block_wiedemann.c @@ -0,0 +1,288 @@ +/* + 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 "gr_sparse_mat.h" + +/* Compute S_i=(M^j Y)_{0...b-1}^T for i = 0,...,ns-1 */ +static int make_block_sequences(gr_mat_struct *S, slong ns, const gr_lil_mat_t M, gr_mat_struct Y[2], gr_ctx_t ctx) +{ + slong iter, i, b = Y->c; + gr_mat_struct W[2]; + int status = GR_SUCCESS; + + for (i = 0; i < 2; ++i) gr_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) status |= gr_lil_mat_mul_mat(&Y[i], M, &Y[1-i], ctx); + status |= gr_mat_transpose(&S[iter], &W[i], ctx); + } + for (i = 0; i < 2; ++i) gr_mat_window_clear(&W[i], ctx); + return status; +} + +/** + * 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 int coppersmith_aux_gauss(gr_mat_t M, slong *d, gr_ctx_t ctx) +{ + const slong b = M->r/2; + slong pr, pc, r, tmp; + slong *gamma; + gr_ptr cinv, coeff; + int status = GR_SUCCESS; + + /* Keep track of viable rows */ + gamma = flint_malloc(b * sizeof(slong)); + for (r = 0; r < b; ++r) gamma[r] = 1; + + GR_TMP_INIT2(cinv, coeff, ctx); + 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] && gr_mat_entry_ptr(M, r, pc, ctx) && d[r] < d[pr]) pr = r; + if (gr_is_zero(gr_mat_entry_ptr(M, pr, pc, ctx), ctx) == T_TRUE) 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 (gr_mat_entry_ptr(M, b + pc, pr, ctx)) + status |= gr_mat_swap_rows(M, NULL, pr, b + pc, ctx), pr = b + pc; + else /* Need to make new auxiliary vector and remove r from use */ + status |= _gr_vec_add(M->rows[b + pc], M->rows[b + pc], M->rows[pr], 3*b, ctx), gamma[pr] = 0; + } + status |= gr_inv(cinv, gr_mat_entry_ptr(M, pr, pc, ctx), ctx); + + /* Do Gaussian elimination on first b rows */ + for (r = 0; r < b; ++r) + if (gamma[r] && gr_is_zero(gr_mat_entry_ptr(M, r, pc, ctx), ctx) == T_FALSE) + { + status |= gr_mul(coeff, gr_mat_entry_ptr(M, r, pc, ctx), cinv, ctx); + status |= gr_neg(coeff, coeff, ctx); + status |= _gr_vec_addmul_scalar( + M->rows[r], M->rows[pr], M->c, + coeff, ctx + ); + + } + } + flint_free(gamma); + GR_TMP_CLEAR2(cinv, coeff, ctx); + return status; +} + +/* 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(gr_mat_struct *S, slong *d, slong n, slong delta, gr_ctx_t ctx) +{ + int ret; + slong t; + slong i, k, r, b = S->r; + slong f_len; + gr_mat_struct *F; + gr_mat_t M, D, tau, tmp; + int status = GR_SUCCESS; + + f_len = 1; + F = flint_malloc((n + 1) * sizeof(gr_mat_struct)); + gr_mat_init(&F[0], 2*b, b, ctx); + gr_mat_init(tmp, b, b, ctx); + for (i = 0; i < b; ++i) + { + d[i] = 0; + d[b + i] = 1; + status |= gr_one(gr_mat_entry_ptr(&F[0], i, i, ctx), ctx); + } + + /* [ D | I ] -> [ ? | tau ]*/ + gr_mat_init(M, 2*b, 3*b, ctx); + + for (t = 0, ret = -1; t < n && ret == -1; ++t) + { + /* Compute discrepancy matrix and tau */ + gr_mat_window_init(D, M, 0, 0, 2*b, b, ctx); + gr_mat_window_init(tau, M, 0, b, 2*b, 3*b, ctx); + status |= gr_mat_zero(D, ctx); + for (k = 0; k <= t; ++k) status |= gr_mat_addmul(D, D, &F[k], &S[t-k], ctx); + status |= gr_mat_one(tau, ctx); + gr_mat_window_clear(D, ctx); + gr_mat_window_clear(tau, ctx); + status |= coppersmith_aux_gauss(M, d, ctx); + + /* Multiply F by tau * diag(I xI) */ + gr_mat_window_init(tau, M, 0, b, 2*b, 3*b, ctx); /* Needed since gauss reorders rows */ + gr_mat_init(&F[f_len++], 2*b, b, ctx); + for (k = f_len-1; k > 0; --k) + status |= gr_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) + status |= _gr_vec_set(F[k].rows[r], F[k+1].rows[r], b, ctx); + else + status |= _gr_vec_zero(F[k].rows[r], b, ctx); + } + for (r = b; r < 2*b; ++r) + status |= _gr_vec_zero(F[0].rows[r], b, ctx), d[r] += 1; + gr_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++) + status |= _gr_vec_set(S[k].rows[r], F[d[r]-k].rows[r], b, ctx); + + for (k = 0; k < f_len; ++k) + gr_mat_clear(&F[k], ctx); + gr_mat_clear(M, ctx); + flint_free(F); + return status; +} + +static int make_block_sum(gr_ptr x, const gr_mat_struct *S, const slong *d, const gr_lil_mat_t M, gr_mat_struct Z[2], slong l, gr_ctx_t ctx) +{ + slong i, iter, b = S->r; + slong dd; + gr_ptr xi; + int status = GR_SUCCESS; + + /* Compute differences between nominal and real degree */ + dd = 0; + while (_gr_vec_is_zero(S[dd].rows[l], b, ctx) == T_TRUE) ++dd; + + /* Simulaneously apply all polynomials in row l to iteration of M on Z */ + GR_TMP_INIT_VEC(xi, M->c, ctx); + status |= _gr_vec_zero(x, M->c, ctx); + for (i = iter = 0; iter <= d[l]; ++iter, i = 1 - i) + { + if (iter > 0) status |= gr_lil_mat_mul_mat(&Z[i], M, &Z[1-i], ctx); + status |= gr_mat_mul_vec(xi, &Z[i], S[dd + iter].rows[l], ctx); + status |= _gr_vec_add(x, x, xi, M->c, ctx); + } + GR_TMP_CLEAR_VEC(xi, M->c, ctx); + return status; +} + +int gr_lil_mat_solve_block_wiedemann(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, slong block_size, flint_rand_t state, gr_ctx_t ctx) +{ + int i; + slong sz = ctx->sizeof_elem; + gr_ptr x1, coeff; + gr_lil_mat_t Mb; + int status = GR_SUCCESS; + + if (M->r != M->c) return 0; /* TODO */ + if (_gr_vec_is_zero(b, M->c, ctx) == T_TRUE) + { + return _gr_vec_zero(x, M->c, ctx); + } + + /* TODO: Precondition M */ + GR_TMP_INIT(coeff, ctx); + GR_TMP_INIT_VEC(x1, M->c + 1, ctx); + gr_lil_mat_init(Mb, M->r + 1, M->c + 1, ctx); + for (i = 0; i < M->r; ++i) + { + gr_sparse_vec_fit_nnz(&Mb->rows[i], M->rows[i].nnz + 1, ctx); + status |= gr_sparse_vec_set(&Mb->rows[i], &M->rows[i], ctx); + status |= gr_sparse_vec_set_entry(&Mb->rows[i], M->c, GR_ENTRY(b, i, sz), ctx); + } + status |= gr_lil_mat_set(Mb, M, ctx); + + status |= gr_lil_mat_nullvector_block_wiedemann(x1, Mb, block_size, state, ctx); + if (status == GR_SUCCESS && gr_is_zero(GR_ENTRY(x1, M->c, sz), ctx) == T_FALSE) + { + status |= gr_inv(coeff, GR_ENTRY(x1, M->c, sz), ctx); + status |= gr_neg(coeff, coeff, ctx); + status |= _gr_vec_mul_scalar(x, x1, M->c, coeff, ctx); + } + gr_lil_mat_clear(Mb, ctx); + GR_TMP_CLEAR_VEC(x1, M->c + 1, ctx); + GR_TMP_CLEAR(coeff, ctx); + return status; +} + +int gr_lil_mat_nullvector_block_wiedemann(gr_ptr x, const gr_lil_mat_t M, slong block_size, flint_rand_t state, gr_ctx_t ctx) +{ + slong l, ns, k; + slong *d; + gr_ptr b; + gr_mat_struct Y[3], *S; + int status = GR_SUCCESS; + 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)); + GR_TMP_INIT_VEC(b, M->r, ctx); + for (k = 0; k < ns; ++k) + gr_mat_init(&S[k], block_size, block_size, ctx); + for (l = 0; l < 3; ++l) + gr_mat_init(&Y[l], M->c, block_size, ctx); + do + status |= gr_mat_randtest(&Y[0], state, ctx); + while (gr_mat_is_zero(&Y[0], ctx) == T_TRUE); + + status |= gr_lil_mat_mul_mat(&Y[1], M, &Y[0], ctx); + status |= make_block_sequences(S, ns, M, &Y[1], ctx); + status |= find_block_min_poly(S, d, ns, M->r, ctx); + + for (l = 0; l < block_size; ++l) + { + status |= gr_mat_set(&Y[1], &Y[0], ctx); + status |= make_block_sum(x, S, d, M, Y + 1, l, ctx); + status |= gr_lil_mat_mul_vec(b, M, x, ctx); + if (!_gr_vec_is_zero(x, M->c, ctx) && _gr_vec_is_zero(b, M->r, ctx)) {status = GR_DOMAIN; break;}; + } + GR_TMP_CLEAR_VEC(b, M->r, ctx); + return status; +} + + diff --git a/src/gr_sparse_mat/solve_lanczos.c b/src/gr_sparse_mat/solve_lanczos.c new file mode 100644 index 0000000000..179779a229 --- /dev/null +++ b/src/gr_sparse_mat/solve_lanczos.c @@ -0,0 +1,125 @@ +/* + 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 "gr_sparse_mat.h" + +int gr_lil_mat_solve_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, flint_rand_t state, gr_ctx_t ctx) +{ + slong j, r, c; + gr_lil_mat_t Mt; + gr_ptr v[2], Mv, Av, Mtb; + gr_ptr vtAv[2], AvtAv, vMtb, tmp; + int status = GR_SUCCESS; + + // TODO: handle this + if (x == b) + return GR_DOMAIN; + + r = gr_sparse_mat_nrows(M, ctx); + c = gr_sparse_mat_ncols(M, ctx); + + status |= _gr_vec_zero(x, c, ctx); + if (_gr_vec_is_zero(b, c, ctx) == T_TRUE) + return GR_SUCCESS; // Trivial solution works + + /* We assume that M is not symmetric, and work with A = M^t M */ + gr_lil_mat_init(Mt, c, r, ctx); + status |= gr_lil_mat_transpose(Mt, M, ctx); + + /* Construct auxiliary values and vectors */ + /* Rather than storing the whole sequence of values v_j, we alternate between two vectors */ + GR_TMP_INIT5(vtAv[0], vtAv[1], AvtAv, vMtb, tmp, ctx); + GR_TMP_INIT_VEC(v[0], c, ctx); + GR_TMP_INIT_VEC(v[1], c, ctx); + GR_TMP_INIT_VEC(Mv, r, ctx); + GR_TMP_INIT_VEC(Av, c, ctx); + GR_TMP_INIT_VEC(Mtb, c, ctx); + + /* Make 0th vector random (and -1st vector trivial) */ + /*_gr_vec_set(v[0], Mtb, M->c); + for (j = 0; j < M->c; ++j) v[0][j] = n_randint(state, M->mod.n); */ + status |= gr_lil_mat_mul_vec(Mtb, Mt, b, ctx); + status |= _gr_vec_randtest(v[0], state, c, ctx); + status |= _gr_vec_zero(v[1], c, ctx); + status |= gr_one(vtAv[1], ctx); + for (j = 0; ; j = 1-j) + { + /* Compute M^T M v_j and check if it is orthogonal to v_j */ + status |= gr_lil_mat_mul_vec(Mv, M, v[j], ctx); + status |= gr_lil_mat_mul_vec(Av, Mt, Mv, ctx); + status |= gr_zero(vtAv[j], ctx); + status |= _gr_vec_dot(vtAv[j], vtAv[j], 0, v[j], Av, c, ctx); + if (gr_is_zero(vtAv[j], ctx) == T_TRUE) break; /* Can't make any more progress */ + + /* Update putative solution by /delta_j * v_j */ + status |= gr_zero(tmp, ctx); + status |= _gr_vec_dot(tmp, tmp, 0, v[j], Mtb, c, ctx); + status |= gr_div(vMtb, tmp, vtAv[j], ctx); + status |= _gr_vec_addmul_scalar(x, v[j], c, vMtb, ctx); + + /* v_{j+1} = MtMv - alpha*v_j - beta*v_{j-1}, where */ + /* alpha = /delta_j, and */ + /* beta = delta_j/delta_{j-1} */ + status |= gr_zero(AvtAv, ctx); + status |= _gr_vec_dot(AvtAv, AvtAv, 0, Av, Av, c, ctx); + status |= gr_div(tmp, vtAv[j], vtAv[1-j], ctx); + status |= gr_neg(tmp, tmp, ctx); + status |= _gr_vec_mul_scalar(v[1-j], v[1-j], M->c, tmp, ctx); + status |= gr_div(tmp, AvtAv, vtAv[j], ctx); + status |= gr_neg(tmp, tmp, ctx); + status |= _gr_vec_addmul_scalar(v[1-j], v[j], M->c, tmp, ctx); + status |= _gr_vec_add(v[1-j], v[1-j], Av, M->c, ctx); + } + /* Check result */ + status |= gr_lil_mat_mul_vec(Mv, M, x, ctx); + status |= gr_lil_mat_mul_vec(Av, Mt, Mv, ctx); + if (_gr_vec_equal(Av, Mtb, c, ctx) == T_FALSE) + status = GR_DOMAIN; + + /* Clear auxiliary vectors and transpose */ + gr_lil_mat_clear(Mt, ctx); + GR_TMP_CLEAR5(vtAv[0], vtAv[1], AvtAv, vMtb, tmp, ctx); + GR_TMP_CLEAR_VEC(v[0], c, ctx); + GR_TMP_CLEAR_VEC(v[1], c, ctx); + GR_TMP_CLEAR_VEC(Mv, r, ctx); + GR_TMP_CLEAR_VEC(Av, c, ctx); + GR_TMP_CLEAR_VEC(Mtb, c, ctx); + return status; +} + +int gr_lil_mat_nullvector_lanczos(gr_ptr x, const gr_lil_mat_t M, flint_rand_t state, gr_ctx_t ctx) +{ + int status = GR_SUCCESS; + gr_ptr x2, b; + GR_TMP_INIT_VEC(x2, M->c, ctx); + GR_TMP_INIT_VEC(b, M->r, ctx); + + status |= _gr_vec_randtest(x, state, M->c, ctx); + status |= gr_lil_mat_mul_vec(b, M, x, ctx); + status |= gr_lil_mat_solve_lanczos(x2, M, b, state, ctx); + + if (status == GR_SUCCESS) + { + status |= _gr_vec_sub(x, x, x2, M->c, ctx); + if (_gr_vec_is_zero(x, M->c, ctx) == T_TRUE) + status = GR_TEST_FAIL; + else + { + status |= gr_lil_mat_mul_vec(b, M, x, ctx); + if (_gr_vec_is_zero(b, M->r, ctx) == T_FALSE) + status = GR_DOMAIN; + } + } + GR_TMP_CLEAR_VEC(x2, M->c, ctx); + GR_TMP_CLEAR_VEC(b, M->r, ctx); + return status; +} diff --git a/src/gr_sparse_mat/solve_wiedemann.c b/src/gr_sparse_mat/solve_wiedemann.c new file mode 100644 index 0000000000..0a53727e65 --- /dev/null +++ b/src/gr_sparse_mat/solve_wiedemann.c @@ -0,0 +1,259 @@ +/* + 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 "gr_sparse_mat.h" + +/* Berlekamp - Massey algorithm */ +static int find_min_poly(slong *L, gr_ptr s, slong N, gr_ctx_t ctx) +{ + slong m, n, i, sz; + slong deg_C, deg_B, deg_T; + gr_ptr B, C, T; + gr_ptr c, d_C, d_B; + int status = GR_SUCCESS; + + sz = ctx->sizeof_elem; + GR_TMP_INIT3(c, d_C, d_B, ctx); + GR_TMP_INIT_VEC(B, N, ctx); + GR_TMP_INIT_VEC(C, N, ctx); + GR_TMP_INIT_VEC(T, N, ctx); + + deg_C = 0, deg_B = 0, deg_T = -1; + status |= gr_one(d_B, ctx); + status |= gr_one(B, ctx); + status |= gr_one(C, ctx); + + *L = 0; + for (n = 0, m = 1; n < N; n++, m++) + { + /* d_C = sum_{i = 0}^L C_i * s_{n-i} */ + status |= gr_set(d_C, GR_ENTRY(s, n, sz), ctx); + for (i = 1; i <= *L; i++) + status |= gr_addmul(d_C, GR_ENTRY(C, i, sz), GR_ENTRY(s, n-i, sz), ctx); + if (gr_is_zero(d_C, ctx) == T_TRUE) 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; + status |= _gr_vec_set(T, C, deg_C+1, ctx); + } + status |= gr_div(c, d_C, d_B, ctx); + status |= gr_neg(c, c, ctx); + for (i = 0; i <= deg_B; ++i) + status |= gr_addmul(GR_ENTRY(C, m+i, sz), GR_ENTRY(B, i, sz), c, ctx); + + deg_C = FLINT_MAX(deg_C, deg_B + m); + while (gr_is_zero(GR_ENTRY(C, deg_C, sz), ctx) == T_TRUE) + --deg_C; /* Probably unnecessary */ + + if (2 * *L <= n) /* Increase number of errors */ + { + *L = n + 1 - *L, m = 0; + status |= gr_set(d_B, d_C, ctx); + deg_B = deg_T; + status |= _gr_vec_set(B, T, deg_T+1, ctx); + } + } + /* Reverse C into s */ + for (i = 0; i <= *L; ++i) + status |= gr_set(GR_ENTRY(s, i, sz), GR_ENTRY(C, *L-i, sz), ctx); + + GR_TMP_CLEAR_VEC(B, N, ctx); + GR_TMP_CLEAR_VEC(C, N, ctx); + GR_TMP_CLEAR_VEC(T, N, ctx); + GR_TMP_CLEAR3(c, d_C, d_B, ctx); + return status; +} + +/* Compute s_ij=(M^j y)_i for i = 0,...,ns-1, j = 0,...,num-1*/ +static int make_sequences(gr_ptr *s, slong ns, slong len, const gr_lil_mat_t M, gr_srcptr b, gr_ctx_t ctx) +{ + slong i, j, r, sz; + gr_ptr y, My; + int status = GR_SUCCESS; + + sz = ctx->sizeof_elem; + r = gr_sparse_mat_nrows(M, ctx); + + GR_TMP_INIT_VEC(y, r, ctx); + GR_TMP_INIT_VEC(My, r, ctx); + status |= _gr_vec_set(y, b, r, ctx); + + for (j = 0; j < len; ++j) + { + if (j > 0) + { + status |= gr_lil_mat_mul_vec(My, M, y, ctx); + status |= _gr_vec_set(y, My, r, ctx); + } + for (i = 0; i < ns; ++i) + status |= gr_set(GR_ENTRY(s[i], j, sz), GR_ENTRY(y, i, sz), ctx); + } + GR_TMP_CLEAR_VEC(y, r, ctx); + GR_TMP_CLEAR_VEC(My, r, ctx); + return status; +} + +/* Compute x = \Sigma_{i = 0}^{L-1} s_i * M^i * b = 0 */ +static int make_sum(gr_ptr x, gr_ptr *s, slong L, const gr_lil_mat_t M, gr_srcptr b, gr_ctx_t ctx) +{ + slong i, r; + gr_ptr y, My; + int status; + + r = gr_sparse_mat_nrows(M, ctx); + + GR_TMP_INIT_VEC(y, r, ctx); + GR_TMP_INIT_VEC(My, r, ctx); + status = _gr_vec_set(y, b, r, ctx); + + status = _gr_vec_mul_scalar(x, b, r, s[0], ctx); + for (i = 1; i < L; ++i) + { + status |= gr_lil_mat_mul_vec(My, M, y, ctx); + status |= _gr_vec_set(y, My, r, ctx); + status |= _gr_vec_addmul_scalar(x, y, r, s[i], ctx); + } + GR_TMP_CLEAR_VEC(y, r, ctx); + GR_TMP_CLEAR_VEC(My, r, ctx); + return status; +} + +int gr_lil_mat_solve_wiedemann(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, gr_ctx_t ctx) +{ + slong i, r, c, L, ns, len, sz; + gr_ptr *s; + gr_ptr Mx, coeff; + int status = GR_SUCCESS; + + // TODO: handle this + if (x == b) + return GR_DOMAIN; + /* TBD: reduce to square */ + if (M->r != M->c) + return GR_DOMAIN; + + sz = ctx->sizeof_elem; + r = gr_sparse_mat_nrows(M, ctx); + c = gr_sparse_mat_ncols(M, ctx); + + if (_gr_vec_is_zero(b, c, ctx)) + { + return _gr_vec_zero(x, c, ctx); + } + + GR_TMP_INIT_VEC(Mx, r, ctx); + GR_TMP_INIT(coeff, ctx); + + // Get dimension of sequence to solve + ns = FLINT_MIN(r, 2); + len = 2 * r + 1; + s = flint_malloc(ns * sizeof(gr_ptr)); + for (i = 0; i < ns; ++i) + GR_TMP_INIT_VEC(s[i], len, ctx); + + status |= make_sequences(s, ns, len, M, b, ctx); + + /* Don't have block Berlekamp yet, just try each one */ + for (i = 0; i < ns; ++i) + { + /* Get minimal polynomial */ + status |= find_min_poly(&L, s[i], len, ctx); + if (gr_is_zero(s[i], ctx) == T_TRUE) continue; + + /* \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 */ + status |= make_sum(x, GR_ENTRY(s[i], 1, sz), L, M, b, ctx); + status |= gr_inv(coeff, s[i], ctx); + status |= gr_neg(coeff, coeff, ctx); + status |= _gr_vec_mul_scalar(x, x, r, coeff, ctx); + + /* Check if successful */ + status |= gr_lil_mat_mul_vec(Mx, M, x, ctx); + if (_gr_vec_equal(Mx, b, r, ctx) != T_FALSE) + break; + } + if (i == ns) + status |= GR_UNABLE; + + GR_TMP_CLEAR_VEC(Mx, r, ctx); + GR_TMP_CLEAR(coeff, ctx); + + for (i = 0; i < ns; ++i) + GR_TMP_CLEAR_VEC(s[i], len, ctx); + flint_free(s); + return status; +} + +int gr_lil_mat_nullvector_wiedemann(gr_ptr x, const gr_lil_mat_t M, flint_rand_t state, gr_ctx_t ctx) +{ + slong i, L, r, c, sz, ns, len; + gr_ptr *s; + gr_ptr Mx, b; + int status = GR_SUCCESS; + + // TODO: handle this + if (x == b) + return GR_DOMAIN; + /* TBD: reduce to square */ + if (M->r != M->c) + return GR_DOMAIN; + + r = gr_sparse_mat_nrows(M, ctx); + c = gr_sparse_mat_ncols(M, ctx); + + GR_TMP_INIT_VEC(Mx, r, ctx); + GR_TMP_INIT_VEC(b, r, ctx); + + // Get dimension of sequence to solve + ns = FLINT_MIN(r, 2); + len = 2 * r + 1; + s = flint_malloc(ns * sizeof(gr_ptr)); + for (i = 0; i < ns; ++i) + GR_TMP_INIT_VEC(s[i], len, ctx); + + status |= _gr_vec_randtest(x, state, r, ctx); + status |= gr_lil_mat_mul_vec(b, M, x, ctx); + + status |= make_sequences(s, ns, len, M, b, ctx); + + for (i = 0; i < ns; ++i) + { + /* Get minimal polynomial */ + status |= find_min_poly(&L, s[i], len, ctx); + + /* \sum_{j = 0}^L s_ijM^jb = 0 */ + /* => x = \sum_{j = 0}^L s_ijM^jx solves Mx = 0 */ + status |= make_sum(x, s[i], L+1, M, x, ctx); + status |= gr_lil_mat_mul_vec(Mx, M, x, ctx); + if + ( + _gr_vec_is_zero(x, c, ctx) != T_TRUE || + _gr_vec_is_zero(Mx, r, ctx) != T_FALSE + ) + break; + } + if (i == ns) + status |= GR_UNABLE; + + GR_TMP_CLEAR_VEC(Mx, r, ctx); + GR_TMP_CLEAR_VEC(b, r, ctx); + for (i = 0; i < ns; ++i) + GR_TMP_CLEAR_VEC(s[i], len, ctx); + flint_free(s); + return status; +} diff --git a/src/gr_sparse_mat/transpose.c b/src/gr_sparse_mat/transpose.c new file mode 100644 index 0000000000..7d6486afcd --- /dev/null +++ b/src/gr_sparse_mat/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 . +*/ + +#include +#include +#include +#include "flint.h" +#include "gr_sparse_mat.h" + +int gr_lil_mat_transpose(gr_lil_mat_t B, const gr_lil_mat_t A, gr_ctx_t ctx) +{ + slong r, c, i, j, nz_idx, sz; + gr_sparse_vec_struct *Arow, *Brow; + int status = GR_SUCCESS; + + sz = ctx->sizeof_elem; + r = gr_sparse_mat_nrows(A, ctx); + c = gr_sparse_mat_ncols(A, ctx); + + + /* Get number of nnzs in each column of A (thus each row of B) */ + for (j = 0; j < c; ++j) + { + B->rows[c].nnz = 0; + } + for (i = 0; i < A->r; ++r) + { + Arow = &A->rows[r]; + for (nz_idx = 0; nz_idx < A->rows[r].nnz; ++nz_idx) + { + B->rows[Arow->inds[nz_idx]].nnz += 1; + } + } + /* Allocate space for nnz and reset counters */ + for (j = 0; j < c; ++j) + { + Brow = &B->rows[c]; + gr_sparse_vec_fit_nnz(Brow, Brow->nnz, ctx); + Brow->nnz = 0; + } + /* Put entries into transposed matrix */ + for (i = 0; i < r; ++i) + { + Arow = &A->rows[r]; + for (nz_idx = 0; nz_idx < Arow->nnz; ++nz_idx) + { + Brow = &B->rows[Arow->inds[i]]; + Brow->inds[Brow->nnz] = r; + status |= gr_set(GR_ENTRY(Brow->nzs, Brow->nnz, sz), GR_ENTRY(Arow->nzs, nz_idx, sz), ctx); + Brow->nnz++; + } + } + return status; +} diff --git a/src/gr_sparse_vec/set.c b/src/gr_sparse_vec/set.c index c27de46aeb..9761492ef2 100644 --- a/src/gr_sparse_vec/set.c +++ b/src/gr_sparse_vec/set.c @@ -4,7 +4,7 @@ int gr_sparse_vec_set(gr_sparse_vec_t dst, const gr_sparse_vec_t src, gr_ctx_t ctx) { int status = GR_SUCCESS; - if (dst->length != src->length) + if (dst->length < src->length) return GR_DOMAIN; if (dst != src) From a3cdc8255a8229fbb931ee5b7d697bf7ddf172b6 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Fri, 22 Mar 2024 03:42:25 -0700 Subject: [PATCH 53/59] Fixed tests --- src/gr_sparse_mat/solve_lanczos.c | 9 +++------ src/gr_sparse_vec/test/t-arith.c | 6 +++--- src/gr_sparse_vec/test/t-init.c | 23 ++++++++++++----------- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/gr_sparse_mat/solve_lanczos.c b/src/gr_sparse_mat/solve_lanczos.c index 179779a229..56c36eef46 100644 --- a/src/gr_sparse_mat/solve_lanczos.c +++ b/src/gr_sparse_mat/solve_lanczos.c @@ -56,21 +56,18 @@ int gr_lil_mat_solve_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, flint_ /* Compute M^T M v_j and check if it is orthogonal to v_j */ status |= gr_lil_mat_mul_vec(Mv, M, v[j], ctx); status |= gr_lil_mat_mul_vec(Av, Mt, Mv, ctx); - status |= gr_zero(vtAv[j], ctx); - status |= _gr_vec_dot(vtAv[j], vtAv[j], 0, v[j], Av, c, ctx); + status |= _gr_vec_dot(vtAv[j], NULL, 0, v[j], Av, c, ctx); if (gr_is_zero(vtAv[j], ctx) == T_TRUE) break; /* Can't make any more progress */ /* Update putative solution by /delta_j * v_j */ - status |= gr_zero(tmp, ctx); - status |= _gr_vec_dot(tmp, tmp, 0, v[j], Mtb, c, ctx); + status |= _gr_vec_dot(tmp, NULL, 0, v[j], Mtb, c, ctx); status |= gr_div(vMtb, tmp, vtAv[j], ctx); status |= _gr_vec_addmul_scalar(x, v[j], c, vMtb, ctx); /* v_{j+1} = MtMv - alpha*v_j - beta*v_{j-1}, where */ /* alpha = /delta_j, and */ /* beta = delta_j/delta_{j-1} */ - status |= gr_zero(AvtAv, ctx); - status |= _gr_vec_dot(AvtAv, AvtAv, 0, Av, Av, c, ctx); + status |= _gr_vec_dot(AvtAv, NULL, 0, Av, Av, c, ctx); status |= gr_div(tmp, vtAv[j], vtAv[1-j], ctx); status |= gr_neg(tmp, tmp, ctx); status |= _gr_vec_mul_scalar(v[1-j], v[1-j], M->c, tmp, ctx); diff --git a/src/gr_sparse_vec/test/t-arith.c b/src/gr_sparse_vec/test/t-arith.c index 6e9c062887..51e9cef9b4 100644 --- a/src/gr_sparse_vec/test/t-arith.c +++ b/src/gr_sparse_vec/test/t-arith.c @@ -23,7 +23,7 @@ test_add_sub_mul(flint_rand_t state, gr_ctx_t ctx) slong i, k, l, m; slong N = 20; slong n_tests = 20; - int status; + int status = GR_SUCCESS; gr_sparse_vec_t vec, vec2, vec_other; gr_ptr dvec, dvec2, dvec3, dvec_other; gr_ptr temp; @@ -202,7 +202,7 @@ int test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) slong i, j, k, l, c; slong N = 20; slong n_tests = 20; - int status; + int status = GR_SUCCESS; gr_sparse_vec_t vec, vec2, vec_other; gr_ptr dvec, dvec2, dvec3; gr_ptr temp; @@ -306,7 +306,7 @@ int test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) ulong uc; slong N = 100; slong n_tests = 20; - int status; + int status = GR_SUCCESS; gr_sparse_vec_t vec, vec2; gr_ptr dvec, dvec2; gr_ptr temp; diff --git a/src/gr_sparse_vec/test/t-init.c b/src/gr_sparse_vec/test/t-init.c index 634e0edd11..a9dd16b98c 100644 --- a/src/gr_sparse_vec/test/t-init.c +++ b/src/gr_sparse_vec/test/t-init.c @@ -14,8 +14,7 @@ #define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } -int -test_init(gr_ctx_t ctx) +int test_init(gr_ctx_t ctx) { gr_sparse_vec_t vec; gr_sparse_vec_init(vec, 5, ctx); @@ -42,8 +41,7 @@ test_init_from_entries_canonical(flint_rand_t state, gr_ctx_t ctx) //flint_printf("Running init test\n"); GR_TMP_INIT(temp, ctx); - entries = flint_malloc(N * sz); - _gr_vec_init(entries, N, ctx); + GR_TMP_INIT_VEC(entries, N, ctx); for (i = 0; i < N; ++i) status |= gr_randtest_not_zero(GR_ENTRY(entries, i, sz), state, ctx); if (status != GR_SUCCESS) @@ -78,8 +76,7 @@ test_init_from_entries_canonical(flint_rand_t state, gr_ctx_t ctx) } } gr_sparse_vec_clear(vec, ctx); - _gr_vec_clear(entries, N, ctx); - flint_free(entries); + GR_TMP_CLEAR_VEC(entries, N, ctx); return status; } @@ -94,7 +91,9 @@ test_init_from_entries_internal(ulong *inds, gr_srcptr entries, slong len, slong GR_TMP_INIT2(temp, temp2, ctx); gr_sparse_vec_init(vec, len, ctx); - status |= gr_sparse_vec_from_entries(vec, inds, entries, num, 0, ctx); + //flint_printf("entries: "); status |= _gr_vec_print(entries, num, ctx); flint_printf("\n"); + status |= gr_sparse_vec_from_entries(vec, inds, entries, num, T_FALSE, ctx); + //flint_printf("vec: "); status |= gr_sparse_vec_print_nz(vec, ctx); flint_printf("\n"); if (status != GR_SUCCESS) return GR_TEST_FAIL; @@ -117,8 +116,11 @@ test_init_from_entries_internal(ulong *inds, gr_srcptr entries, slong len, slong ) { flint_printf("Failed on %d!\n", i); + gr_ctx_println(ctx); gr_println(temp, ctx); gr_println(temp2, ctx); + if (temp3 != NULL) + gr_println(temp3, ctx); return GR_TEST_FAIL; } } @@ -136,9 +138,9 @@ test_init_from_entries(flint_rand_t state, gr_ctx_t ctx) slong sz = ctx->sizeof_elem; slong N = 5; ulong inds[5] = {8, 4, 3, 8, 1}; - gr_ptr entries = flint_malloc(N * sz); + gr_ptr entries; - _gr_vec_init(entries, N, ctx); + GR_TMP_INIT_VEC(entries, N, ctx); status |= _gr_vec_randtest(entries, state, N, ctx); status |= test_init_from_entries_internal(inds, entries, 2*N, N, ctx); @@ -149,8 +151,7 @@ test_init_from_entries(flint_rand_t state, gr_ctx_t ctx) status |= gr_set_si(GR_ENTRY(entries, i, sz), entries_si[i], ctx); status |= test_init_from_entries_internal(inds, entries, 2*N, N, ctx); - _gr_vec_clear(entries, N, ctx); - flint_free(entries); + GR_TMP_CLEAR_VEC(entries, N, ctx); return status; } From fe248bdb4fed3d9ce41b307caf0722f2ae9946d8 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Fri, 22 Mar 2024 07:44:52 -0700 Subject: [PATCH 54/59] Everything but block lanczos works --- src/gr_sparse_mat/solve_block_lanczos.c | 6 ++-- src/gr_sparse_mat/solve_lanczos.c | 37 ++++++++++++++++++++----- src/gr_sparse_mat/solve_wiedemann.c | 24 ++++++++++------ src/gr_sparse_mat/test/main.c | 2 ++ src/gr_sparse_mat/test/t-arith.c | 6 ++++ src/gr_sparse_mat/transpose.c | 26 +++++++++-------- 6 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/gr_sparse_mat/solve_block_lanczos.c b/src/gr_sparse_mat/solve_block_lanczos.c index 42e8673dc5..e0d3ed2871 100644 --- a/src/gr_sparse_mat/solve_block_lanczos.c +++ b/src/gr_sparse_mat/solve_block_lanczos.c @@ -73,7 +73,7 @@ static int compute_nWi_S(slong *rk, gr_mat_t nWi, int *S, const gr_mat_t Torig, for (i = 0; i < b; ++i) { status |= gr_neg(cc, gr_mat_entry_ptr(X, P[i], pc, ctx), ctx); - if (i == j || cc == 0) continue; + if (i == j || gr_is_zero(cc, ctx) == T_TRUE) continue; status |= _gr_vec_addmul_scalar(T->rows[P[i]], T->rows[pc], T->c, cc, ctx); status |= _gr_vec_addmul_scalar(nWi->rows[P[i]], nWi->rows[pc], nWi->c, cc, ctx); } @@ -120,7 +120,7 @@ int gr_lil_mat_solve_block_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, gr_mat_t DEF; /* Used to store coefficient matrices D, E, and F */ gr_mat_t I, tmp; /* I_{b x b}, tmp used as scratch */ gr_ptr Mtb, SStVtMtb, WiSStVtMtb, VSStWiSStVtMtb; /* Intermediate elements in x update */ - int status = GR_SUCCESS; + int status = GR_UNABLE; // TODO: handle this if (x == b) @@ -129,7 +129,7 @@ int gr_lil_mat_solve_block_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, r = gr_sparse_mat_nrows(M, ctx); c = gr_sparse_mat_ncols(M, ctx); - if (_gr_vec_is_zero(b, r, ctx)) + if (_gr_vec_is_zero(b, r, ctx) == T_TRUE) { status |= _gr_vec_zero(x, c, ctx); return GR_SUCCESS; diff --git a/src/gr_sparse_mat/solve_lanczos.c b/src/gr_sparse_mat/solve_lanczos.c index 56c36eef46..aab6a2031f 100644 --- a/src/gr_sparse_mat/solve_lanczos.c +++ b/src/gr_sparse_mat/solve_lanczos.c @@ -14,7 +14,7 @@ int gr_lil_mat_solve_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, flint_rand_t state, gr_ctx_t ctx) { - slong j, r, c; + slong j, r, c, iter; gr_lil_mat_t Mt; gr_ptr v[2], Mv, Av, Mtb; gr_ptr vtAv[2], AvtAv, vMtb, tmp; @@ -27,6 +27,7 @@ int gr_lil_mat_solve_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, flint_ r = gr_sparse_mat_nrows(M, ctx); c = gr_sparse_mat_ncols(M, ctx); + // flint_printf("M = "); gr_lil_mat_print_nz(M, ctx); flint_printf("\n"); status |= _gr_vec_zero(x, c, ctx); if (_gr_vec_is_zero(b, c, ctx) == T_TRUE) return GR_SUCCESS; // Trivial solution works @@ -34,6 +35,7 @@ int gr_lil_mat_solve_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, flint_ /* We assume that M is not symmetric, and work with A = M^t M */ gr_lil_mat_init(Mt, c, r, ctx); status |= gr_lil_mat_transpose(Mt, M, ctx); + //flint_printf("M^T = "); gr_lil_mat_print_nz(Mt, ctx); flint_printf("\n"); /* Construct auxiliary values and vectors */ /* Rather than storing the whole sequence of values v_j, we alternate between two vectors */ @@ -48,39 +50,60 @@ int gr_lil_mat_solve_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, flint_ /*_gr_vec_set(v[0], Mtb, M->c); for (j = 0; j < M->c; ++j) v[0][j] = n_randint(state, M->mod.n); */ status |= gr_lil_mat_mul_vec(Mtb, Mt, b, ctx); + // flint_printf("\tM^Tb = "); _gr_vec_print(Mtb, c, ctx); flint_printf("\n"); status |= _gr_vec_randtest(v[0], state, c, ctx); status |= _gr_vec_zero(v[1], c, ctx); status |= gr_one(vtAv[1], ctx); - for (j = 0; ; j = 1-j) + for (iter = j = 0; ; j = 1-j, ++iter) { - /* Compute M^T M v_j and check if it is orthogonal to v_j */ + // flint_printf("\n\niter = %d\n", iter); + /* Compute A v_j and check if it is orthogonal to v_j */ + // flint_printf("\n\tv[%d] = ", j); _gr_vec_print(v[j], c, ctx); flint_printf("\n"); status |= gr_lil_mat_mul_vec(Mv, M, v[j], ctx); + // flint_printf("\tMv[%d] = ", j); _gr_vec_print(Mv, r, ctx); flint_printf("\n"); status |= gr_lil_mat_mul_vec(Av, Mt, Mv, ctx); + // flint_printf("\tAv[%d] = ", j); _gr_vec_print(Av, c, ctx); flint_printf("\n"); status |= _gr_vec_dot(vtAv[j], NULL, 0, v[j], Av, c, ctx); + // flint_printf("\tv[%d]^TAv[%d] = ", j, j); gr_println(vtAv[j], ctx); if (gr_is_zero(vtAv[j], ctx) == T_TRUE) break; /* Can't make any more progress */ - /* Update putative solution by /delta_j * v_j */ - status |= _gr_vec_dot(tmp, NULL, 0, v[j], Mtb, c, ctx); - status |= gr_div(vMtb, tmp, vtAv[j], ctx); + /* Update putative solution by (/) * v_j */ + status |= _gr_vec_dot(vMtb, NULL, 0, v[j], Mtb, c, ctx); + // flint_printf("\n\tv[%d]M^Tb = ", j); gr_println(vMtb, ctx); + status |= gr_div(vMtb, vMtb, vtAv[j], ctx); + // flint_printf("\tv[%d]M^Tb/(v[%d]^TAv[%d]) = ", j, j, j); gr_println(vMtb, ctx); status |= _gr_vec_addmul_scalar(x, v[j], c, vMtb, ctx); + // flint_printf("\tx = x + ([%d]M^Tb/(v[%d]^TAv[%d])) v[%d] = ", j, j, j); _gr_vec_print(x, c, ctx); flint_printf("\n"); /* v_{j+1} = MtMv - alpha*v_j - beta*v_{j-1}, where */ /* alpha = /delta_j, and */ /* beta = delta_j/delta_{j-1} */ status |= _gr_vec_dot(AvtAv, NULL, 0, Av, Av, c, ctx); + // flint_printf("\t(Av[%d])^TAv[%d] = ", j, j); gr_println(AvtAv, ctx); status |= gr_div(tmp, vtAv[j], vtAv[1-j], ctx); + // flint_printf("\t((Av[%d])^TAv[%d])/((Av[%d])^TAv[%d]) = ", j, j, 1-j, 1-j); gr_println(tmp, ctx); status |= gr_neg(tmp, tmp, ctx); + // flint_printf("\t-((Av[%d])^TAv[%d])/((Av[%d])^TAv[%d]) = ", j, j, 1-j, 1-j); gr_println(tmp, ctx); status |= _gr_vec_mul_scalar(v[1-j], v[1-j], M->c, tmp, ctx); + // flint_printf("\tv[%d] = -((Av[%d])^TAv[%d])/((Av[%d])^TAv[%d]) v[%d] = ", 1-j, j, j, 1-j, 1-j, 1-j); _gr_vec_print(v[1-j], c, ctx); flint_printf("\n"); + status |= gr_div(tmp, AvtAv, vtAv[j], ctx); + // flint_printf("\n\t((Av[%d])^TAv[%d])/(v[%d]^TAv[%d]) = ", j, j, j, j); gr_println(tmp, ctx); status |= gr_neg(tmp, tmp, ctx); + // flint_printf("\t-((Av[%d])^TAv[%d])/(v[%d]^TAv[%d]) = ", j, j, j, j); gr_println(tmp, ctx); status |= _gr_vec_addmul_scalar(v[1-j], v[j], M->c, tmp, ctx); + // flint_printf("\tv[%d] = v[%d] - ((Av[%d])^TAv[%d])/(v[%d]^TAv[%d]) v[%d] = ", 1-j, 1-j, j, j, j, j, j); _gr_vec_print(v[1-j], c, ctx); flint_printf("\n"); status |= _gr_vec_add(v[1-j], v[1-j], Av, M->c, ctx); + // flint_printf("\tv[%d] = v[%d] + Av[%d] = ", 1-j, 1-j, j); _gr_vec_print(v[1-j], c, ctx); flint_printf("\n"); } /* Check result */ + // flint_printf("x = ", j); _gr_vec_print(x, c, ctx); flint_printf("\n"); status |= gr_lil_mat_mul_vec(Mv, M, x, ctx); + // flint_printf("Mx = ", j); _gr_vec_print(Mv, r, ctx); flint_printf("\n"); status |= gr_lil_mat_mul_vec(Av, Mt, Mv, ctx); + // flint_printf("Ax = ", j); _gr_vec_print(Av, r, ctx); flint_printf("\n"); if (_gr_vec_equal(Av, Mtb, c, ctx) == T_FALSE) - status = GR_DOMAIN; + status = GR_UNABLE; /* Clear auxiliary vectors and transpose */ gr_lil_mat_clear(Mt, ctx); diff --git a/src/gr_sparse_mat/solve_wiedemann.c b/src/gr_sparse_mat/solve_wiedemann.c index 0a53727e65..b69c90f524 100644 --- a/src/gr_sparse_mat/solve_wiedemann.c +++ b/src/gr_sparse_mat/solve_wiedemann.c @@ -109,24 +109,27 @@ static int make_sequences(gr_ptr *s, slong ns, slong len, const gr_lil_mat_t M, } /* Compute x = \Sigma_{i = 0}^{L-1} s_i * M^i * b = 0 */ -static int make_sum(gr_ptr x, gr_ptr *s, slong L, const gr_lil_mat_t M, gr_srcptr b, gr_ctx_t ctx) +static int make_sum(gr_ptr x, gr_ptr s, slong L, const gr_lil_mat_t M, gr_srcptr b, gr_ctx_t ctx) { - slong i, r; + slong i, r, sz; gr_ptr y, My; int status; + sz = ctx->sizeof_elem; r = gr_sparse_mat_nrows(M, ctx); GR_TMP_INIT_VEC(y, r, ctx); GR_TMP_INIT_VEC(My, r, ctx); status = _gr_vec_set(y, b, r, ctx); - status = _gr_vec_mul_scalar(x, b, r, s[0], ctx); + //flint_printf("\t\tScaling\n"); + status = _gr_vec_mul_scalar(x, b, r, s, ctx); for (i = 1; i < L; ++i) { + //flint_printf("\t\tIterating %d\n", i); status |= gr_lil_mat_mul_vec(My, M, y, ctx); status |= _gr_vec_set(y, My, r, ctx); - status |= _gr_vec_addmul_scalar(x, y, r, s[i], ctx); + status |= _gr_vec_addmul_scalar(x, y, r, GR_ENTRY(s, i, sz), ctx); } GR_TMP_CLEAR_VEC(y, r, ctx); GR_TMP_CLEAR_VEC(My, r, ctx); @@ -151,7 +154,7 @@ int gr_lil_mat_solve_wiedemann(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, gr_c r = gr_sparse_mat_nrows(M, ctx); c = gr_sparse_mat_ncols(M, ctx); - if (_gr_vec_is_zero(b, c, ctx)) + if (_gr_vec_is_zero(b, c, ctx) == T_TRUE) { return _gr_vec_zero(x, c, ctx); } @@ -166,23 +169,29 @@ int gr_lil_mat_solve_wiedemann(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, gr_c for (i = 0; i < ns; ++i) GR_TMP_INIT_VEC(s[i], len, ctx); + //flint_printf("Make sequences\n"); status |= make_sequences(s, ns, len, M, b, ctx); /* Don't have block Berlekamp yet, just try each one */ for (i = 0; i < ns; ++i) { /* Get minimal polynomial */ + //flint_printf("Finding minimal polynomial for index %d\n", i); status |= find_min_poly(&L, s[i], len, ctx); if (gr_is_zero(s[i], ctx) == T_TRUE) continue; /* \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 */ + //flint_printf("\tMaking sum\n"); status |= make_sum(x, GR_ENTRY(s[i], 1, sz), L, M, b, ctx); + //flint_printf("\tInverting\n"); status |= gr_inv(coeff, s[i], ctx); status |= gr_neg(coeff, coeff, ctx); + //flint_printf("\tScaling\n"); status |= _gr_vec_mul_scalar(x, x, r, coeff, ctx); /* Check if successful */ + //flint_printf("\tChecking result\n"); status |= gr_lil_mat_mul_vec(Mx, M, x, ctx); if (_gr_vec_equal(Mx, b, r, ctx) != T_FALSE) break; @@ -201,15 +210,12 @@ int gr_lil_mat_solve_wiedemann(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, gr_c int gr_lil_mat_nullvector_wiedemann(gr_ptr x, const gr_lil_mat_t M, flint_rand_t state, gr_ctx_t ctx) { - slong i, L, r, c, sz, ns, len; + slong i, L, r, c, ns, len; gr_ptr *s; gr_ptr Mx, b; int status = GR_SUCCESS; // TODO: handle this - if (x == b) - return GR_DOMAIN; - /* TBD: reduce to square */ if (M->r != M->c) return GR_DOMAIN; diff --git a/src/gr_sparse_mat/test/main.c b/src/gr_sparse_mat/test/main.c index e48c09c65a..9150ab95bb 100644 --- a/src/gr_sparse_mat/test/main.c +++ b/src/gr_sparse_mat/test/main.c @@ -8,6 +8,7 @@ #include "t-init.c" #include "t-mul.c" #include "t-randtest.c" +#include "t-solve.c" /* Array of test functions ***************************************************/ @@ -18,6 +19,7 @@ test_struct tests[] = TEST_FUNCTION(gr_sparse_mat_randtest), TEST_FUNCTION(gr_sparse_mat_arith), TEST_FUNCTION(gr_sparse_mat_mul), + TEST_FUNCTION(gr_sparse_mat_solve), }; /* main function *************************************************************/ diff --git a/src/gr_sparse_mat/test/t-arith.c b/src/gr_sparse_mat/test/t-arith.c index 156039bf1a..2c5baec10b 100644 --- a/src/gr_sparse_mat/test/t-arith.c +++ b/src/gr_sparse_mat/test/t-arith.c @@ -120,6 +120,7 @@ int test_add_sub(flint_rand_t state, gr_ctx_t ctx) gr_lil_mat_init(lil_mat, M, N, ctx); gr_lil_mat_init(lil_mat2, M, N, ctx); + //flint_printf("Testing add sub\n"); for (i = 0; i < 2 * n_tests; i++) { status = GR_SUCCESS; @@ -193,6 +194,7 @@ int test_accum_mul_scalar(flint_rand_t state, gr_ctx_t ctx) gr_lil_mat_init(lil_mat, M, N, ctx); gr_lil_mat_init(lil_mat2, M, N, ctx); + //flint_printf("Testing addmul submul\n"); for (i = 0; i < 2 * n_tests; i++) { status = GR_SUCCESS; @@ -276,6 +278,9 @@ int test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) fmpq_t fmpq_c; truth_t eq; + fmpz_init(fmpz_c); + fmpq_init(fmpq_c); + GR_TMP_INIT(gr_c, ctx); gr_mat_init(dmat, M, N, ctx); gr_mat_init(dmat2, M, N, ctx); @@ -286,6 +291,7 @@ int test_mul_div_scalar(flint_rand_t state, gr_ctx_t ctx) gr_lil_mat_init(lil_mat, M, N, ctx); gr_lil_mat_init(lil_mat2, M, N, ctx); + //flint_printf("Testing mul div scalar\n"); for (i = 0; i < 54 * n_tests; i++) { j = i % 6; // Which type of scalar diff --git a/src/gr_sparse_mat/transpose.c b/src/gr_sparse_mat/transpose.c index 7d6486afcd..2b92ead8f2 100644 --- a/src/gr_sparse_mat/transpose.c +++ b/src/gr_sparse_mat/transpose.c @@ -12,8 +12,6 @@ #include #include -#include -#include "flint.h" #include "gr_sparse_mat.h" int gr_lil_mat_transpose(gr_lil_mat_t B, const gr_lil_mat_t A, gr_ctx_t ctx) @@ -26,16 +24,22 @@ int gr_lil_mat_transpose(gr_lil_mat_t B, const gr_lil_mat_t A, gr_ctx_t ctx) r = gr_sparse_mat_nrows(A, ctx); c = gr_sparse_mat_ncols(A, ctx); + if (r != gr_sparse_mat_ncols(B, ctx) || c != gr_sparse_mat_nrows(B, ctx)) + return GR_DOMAIN; + // TODO: handle + if (A == B) + return GR_DOMAIN; + /* Get number of nnzs in each column of A (thus each row of B) */ for (j = 0; j < c; ++j) { - B->rows[c].nnz = 0; + B->rows[j].nnz = 0; } - for (i = 0; i < A->r; ++r) + for (i = 0; i < A->r; ++i) { - Arow = &A->rows[r]; - for (nz_idx = 0; nz_idx < A->rows[r].nnz; ++nz_idx) + Arow = &A->rows[i]; + for (nz_idx = 0; nz_idx < A->rows[i].nnz; ++nz_idx) { B->rows[Arow->inds[nz_idx]].nnz += 1; } @@ -43,20 +47,20 @@ int gr_lil_mat_transpose(gr_lil_mat_t B, const gr_lil_mat_t A, gr_ctx_t ctx) /* Allocate space for nnz and reset counters */ for (j = 0; j < c; ++j) { - Brow = &B->rows[c]; + Brow = &B->rows[j]; gr_sparse_vec_fit_nnz(Brow, Brow->nnz, ctx); Brow->nnz = 0; } /* Put entries into transposed matrix */ for (i = 0; i < r; ++i) { - Arow = &A->rows[r]; + Arow = &A->rows[i]; for (nz_idx = 0; nz_idx < Arow->nnz; ++nz_idx) { - Brow = &B->rows[Arow->inds[i]]; - Brow->inds[Brow->nnz] = r; + Brow = &B->rows[Arow->inds[nz_idx]]; + Brow->inds[Brow->nnz] = i; status |= gr_set(GR_ENTRY(Brow->nzs, Brow->nnz, sz), GR_ENTRY(Arow->nzs, nz_idx, sz), ctx); - Brow->nnz++; + (Brow->nnz)++; } } return status; From f9f9e5187f9f7b9066bf315dbd4486d931d940b5 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Fri, 22 Mar 2024 07:56:35 -0700 Subject: [PATCH 55/59] Forgot a file --- src/gr_sparse_mat/test/t-solve.c | 163 +++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 src/gr_sparse_mat/test/t-solve.c diff --git a/src/gr_sparse_mat/test/t-solve.c b/src/gr_sparse_mat/test/t-solve.c new file mode 100644 index 0000000000..ef2384cda1 --- /dev/null +++ b/src/gr_sparse_mat/test/t-solve.c @@ -0,0 +1,163 @@ +/* + 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 "test_helpers.h" +#include "gr_sparse_mat.h" +/* #include */ + +int test_solve(flint_rand_t state, gr_ctx_t ctx) +{ + int iter, ret; + slong rep, nreps = 100, r, c, i; + gr_coo_mat_t Aorig; + gr_lil_mat_t A, At; + gr_ptr x, x2, b, Atb, Ax, AtAx; + gr_mat_t dmat; + 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}; + slong sol[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"}; + int status = GR_SUCCESS; + /* struct timeval start, end; */ + + flint_printf("solving Ax = b...."); + fflush(stdout); + + for (rep = 0; rep < nreps; rep++) + { + if (rep % 5==0) {flint_printf("."); fflush(stdout);} + + c = r = 50 + n_randint(state, 5); + + gr_coo_mat_init(Aorig, r, c, ctx); + gr_lil_mat_init(A, r, c, ctx); + gr_mat_init(dmat, r, c, ctx); + GR_TMP_INIT_VEC(x, c, ctx); + GR_TMP_INIT_VEC(x2, c, ctx); + GR_TMP_INIT_VEC(b, r, ctx); + GR_TMP_INIT_VEC(Ax, r, ctx); + + // Set up a solvable problem + status |= gr_coo_mat_randtest_prob(Aorig, .2, state, ctx); + status |= gr_lil_mat_set_coo_mat(A, Aorig, ctx); + status |= _gr_vec_randtest(x, state, c, ctx); + status |= gr_lil_mat_mul_vec(b, A, x, ctx); + status |= gr_mat_set_lil_mat(dmat, A, ctx); + // flint_printf("A = "); gr_mat_print(dmat, ctx); flint_printf("\n"); + // flint_printf("x = "); _gr_vec_print(x, c, ctx); flint_printf("\n"); + // flint_printf("b = "); _gr_vec_print(b, r, ctx); flint_printf("\n"); + + for (i = 0; i < 6; ++i) + { + iter = 0; + /* gettimeofday(&start, NULL); */ + // TODO: rref and lu solving + if (i == 0 || i == 1) + continue; + switch (i) + { + //case 0: ret = gr_lil_mat_solve_rref(x2, A, b, ctx); break; + //case 1: ret = gr_lil_mat_solve_lu(x2, A, b, ctx); break; + case 2: do ret = gr_lil_mat_solve_lanczos(x2, A, b, state, ctx); while (ret == GR_UNABLE && ++iter < 3); break; + case 3: do ret = gr_lil_mat_solve_block_lanczos(x2, A, b, 8, state, ctx); while (ret == GR_UNABLE && ++iter < 3); break; + case 4: ret = gr_lil_mat_solve_wiedemann(x2, A, b, ctx); break; + case 5: do ret = gr_lil_mat_solve_block_wiedemann(x2, A, b, 8, state, ctx); while (ret == GR_TEST_FAIL && ++iter < 3); break; + } + // /* gettimeofday(&end, NULL); + // elapsed[i] += (end.tv_sec - start.tv_sec) + .000001*(end.tv_usec-start.tv_usec); */ + if (ret == GR_UNABLE) nosol[i] += 1; + else + { + niters[i] += iter; + status |= gr_lil_mat_mul_vec(Ax, A, x2, ctx); + if (_gr_vec_equal(b, Ax, A->r, ctx) == T_FALSE) + { + if (i == 2 || i == 3) + { + gr_lil_mat_init(At, c, r, ctx); + GR_TMP_INIT_VEC(AtAx, c, ctx); + GR_TMP_INIT_VEC(Atb, c, ctx); + status |= gr_lil_mat_transpose(At, A, ctx); + status |= gr_lil_mat_mul_vec(AtAx, At, Ax, ctx); + status |= gr_lil_mat_mul_vec(Atb, At, b, ctx); + if (_gr_vec_equal(AtAx, Atb, A->c, ctx) != T_TRUE) + { + flint_printf("FAIL on %s: AtAx != Atb\n", names[i]); + abort(); + } + else psol[i] += 1; + GR_TMP_CLEAR_VEC(AtAx, c, ctx); + GR_TMP_CLEAR_VEC(Atb, c, ctx); + gr_lil_mat_clear(At, ctx); + } + else + { + flint_printf("FAIL on %s: Ax != b\n", names[i]); + return GR_TEST_FAIL; + } + } + else + { + sol[i] += 1; + } + } + } + + GR_TMP_CLEAR_VEC(x, c, ctx); + GR_TMP_CLEAR_VEC(x2, c, ctx); + GR_TMP_CLEAR_VEC(b, r, ctx); + GR_TMP_CLEAR_VEC(Ax, r, ctx); + gr_lil_mat_clear(A, ctx); + gr_mat_clear(dmat, ctx); + } + + flint_printf("PASS\n"); + for (i = 0; i < 6; ++i) + { + flint_printf("Solved %d with %s\n", sol[i], 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 status; +} + + +TEST_FUNCTION_START(gr_sparse_mat_solve, state) +{ + slong i; + gr_ctx_t ctx; + for (i = 0; i < 1; ++i) + { + while (1) + { + //gr_ctx_init_fmpz(ctx); + gr_ctx_init_random(ctx, state); + gr_ctx_init_fq_nmod(ctx, 65521, 1, "a"); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE || gr_ctx_is_exact(ctx) != T_TRUE || gr_ctx_is_field(ctx) != T_TRUE || gr_ctx_is_finite(ctx) != T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + CHECK_TEST(test_solve(state, ctx), "Sparse matrix solving"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} + From ad3dfe55f1dbcbe7170d678308874dc7b7e10408 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Fri, 22 Mar 2024 09:15:42 -0700 Subject: [PATCH 56/59] Updated documentation, added functions to update a dense matrix with a sparse one --- doc/source/gr_sparse_mat.rst | 379 +++++++++++++++++++++----------- src/gr_sparse_mat.h | 28 ++- src/gr_sparse_mat/arith_dense.c | 134 +++++++++++ src/gr_sparse_mat/fit_nnz.c | 9 + 4 files changed, 419 insertions(+), 131 deletions(-) create mode 100644 src/gr_sparse_mat/arith_dense.c diff --git a/doc/source/gr_sparse_mat.rst b/doc/source/gr_sparse_mat.rst index 9b7c141868..b5c95e80d2 100644 --- a/doc/source/gr_sparse_mat.rst +++ b/doc/source/gr_sparse_mat.rst @@ -27,7 +27,7 @@ Types and basic access * An `slong` value ``alloc``, the maximum number of nonzeroes currently allocated. * A `ulong` array ``rows`` of length ``r+1`` providing row offsets. * A `ulong` array ``cols`` of length ``nnz`` providing column indices. - * A :type:`gr_ptr` array of of length ``nnz`` providing nonzero values. + * A :type:`gr_ptr` array ``nzs`` of length ``nnz`` providing nonzero values. For a given row of index ``row``, its nonzero columns and associated values are given by the components of ``cols`` and ``entries`` associated to @@ -56,9 +56,30 @@ Types and basic access A ``gr_lil_mat_t`` is defined as an array of length one of type ``gr_lil_mat_struct``, permitting a ``gr_lil_mat_t`` to - be passed by reference. Note that ``gr_less_mat_t`` is the less efficient + be passed by reference. Note that ``gr_lil_mat_t`` is a less efficient way to represent a sparse matrix, but is more convenient for modification. +.. type:: gr_coo_mat_struct + +.. type:: gr_coo_mat_t + + This struct presents a sparse matrix in (coo)rdinate form, and contains: + + * An `slong` value ``r``, the number of rows in the matrix. + * An `slong` value ``c``, the number of columns in the matrix. + * An `slong` value ``nnz``, the number of nonzeroes in the matrix. + * An `slong` value ``alloc``, the maximum number of nonzeroes currently allocated. + * A :type:`gr_sparse_vec_t` array ``rows`` of length ``nnz``, the list of rows for each entry. + * A :type:`gr_sparse_vec_t` array ``cols`` of length ``nnz``, the list of columns for each entry. + * A :type:`gr_sparse_vec_t` array ``nzs`` of length ``nnz``, the list of columns for each entry. + * A `truth_t` value `is_canonical`, with is `T_TRUE` if the matrix is in "canonical" form (sorted by rows and columns, with unique non-zero entries). + + A ``gr_coo_mat_t`` is defined as an array of length one of type + ``gr_coo_mat_struct``, permitting a ``gr_coo_mat_t`` to + be passed by reference. Note that ``gr_coo_mat_t`` is the least efficient + way to represent a sparse matrix (and has minimal functionality), but + is convenient for constructing from arbitrary lists of entries. + .. function:: void gr_sparse_mat_nrows(gr_csr_mat_t mat, gr_ctx_t ctx) void gr_sparse_mat_ncols(gr_csr_mat_t mat, gr_ctx_t ctx) void gr_sparse_mat_nnz(gr_csr_mat_t mat, gr_ctx_t ctx) @@ -67,7 +88,7 @@ Types and basic access void gr_sparse_mat_nnz(gr_csr_mat_t mat, gr_ctx_t ctx) Get the number of rows/columns/nonzeroes of the given sparse matrix, - in either representation. + in any representation. .. macro:: GR_CSR_MAT_COL(mat, i, j) GR_LIL_MAT_COL(mat, i, j) @@ -82,13 +103,20 @@ Types and basic access given the size of each entry (typically obtained as ``ctx->sizeof_elem``). There is no bounds checking. +.. macro:: GR_COO_MAT_ROW(mat, i) + GR_LIL_MAT_COL(mat, i) + GR_LIL_MAT_ENTRY(mat, i) + + Get a pointer to the row, column, and value of the *i*-th nonzero in the matrix, repectively. + There is no bounds checking. + .. function:: ulong * gr_csr_mat_col_ptr(gr_csr_mat_t mat, slong i, slong j) const ulong * gr_csr_mat_col_srcptr(const gr_csr_mat_t mat, slong i, slong j) ulong * gr_lil_mat_col_ptr(gr_lil_mat_t mat, slong i, slong j) const ulong * gr_lil_mat_col_srcptr(const gr_lil_mat_t mat, slong i, slong j) Get a (const) pointer to the column of the *j*-th nonzero in the *i*-th row of *mat*. - There is no bounds checking. + If the location is out of bounds, the function returns NULL. .. function:: gr_ptr gr_csr_mat_entry_ptr(gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) gr_srcptr gr_csr_mat_entry_srcptr(gr_csr_mat_t mat, slong i, slong j, gr_ctx_t ctx) @@ -96,60 +124,112 @@ Types and basic access gr_srcptr gr_lil_mat_entry_srcptr(gr_lil_mat_t mat, slong i, slong j, gr_ctx_t ctx) Get a (const) pointer to the *j*-th nonzero entry in the *i*-th row of *mat*. - There is no bounds checking. + If the location is out of bounds, the function returns NULL. + +.. function:: ulong * gr_coo_mat_row_ptr(gr_coo_mat_t mat, slong i) + const ulong * gr_coo_mat_row_srcptr(const gr_coo_mat_t mat, slong i) + ulong * gr_coo_mat_col_ptr(gr_coo_mat_t mat, slong i) + const ulong * gr_coo_mat_col_srcptr(const gr_coo_mat_t mat, slong i) + gr_ptr gr_coo_mat_entry_ptr(gr_coo_mat_t mat, slong i) + gr_srcptr gr_coo_mat_entry_ptr(const gr_coo_mat_t mat, slong i) .. function:: void gr_csr_mat_init(gr_csr_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) void gr_lil_mat_init(gr_lil_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) + void gr_coo_mat_init(gr_coo_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) Initializes *mat* to a *rows* x *cols* matrix with no nonzeros. -.. function:: void gr_csr_mat_clear(gr_csr_mat_t vec, gr_ctx_t ctx) - void gr_lil_mat_clear(gr_lil_mat_t vec, gr_ctx_t ctx) +.. function:: void gr_csr_mat_clear(gr_csr_mat_t mat, gr_ctx_t ctx) + void gr_lil_mat_clear(gr_lil_mat_t mat, gr_ctx_t ctx) + void gr_coo_mat_clear(gr_coo_mat_t mat, gr_ctx_t ctx) Clears the matrix *mat*. .. function:: gr_csr_mat_swap(gr_csr_mat_t mat1, gr_csr_mat_t mat2, gr_ctx_t ctx) gr_lil_mat_swap(gr_lil_mat_t mat1, gr_lil_mat_t mat2, gr_ctx_t ctx) + gr_coo_mat_swap(gr_coo_mat_t mat1, gr_coo_mat_t mat2, gr_ctx_t ctx) Swap data underlying two sparse matrices (no allocation or copying). .. function:: void gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx) + void gr_lil_mat_fit_nnz(gr_lil_mat_t mat, slong *nnz, gr_ctx_t ctx) + void gr_coo_mat_fit_nnz(gr_coo_mat_t mat, slong nnz, gr_ctx_t ctx) Ensure that *mat* has enough storage to hold at least *nnz* nonzeros. This does not change the dimensions of the matrix or the number of nonzeros stored. - - Note that, for matrices in *lil* form, one must perform the analogous operation - on each row. + Note that, for matrices in *lil* form, *nnz* is a vector of sizes, one for each row. .. function:: void gr_csr_mat_shrink_to_nnz(gr_csr_mat_t mat, gr_ctx_t ctx) + void gr_lil_mat_shrink_to_nnz(gr_lil_mat_t mat, gr_ctx_t ctx) + void gr_coo_mat_shrink_to_nnz(gr_coo_mat_t mat, gr_ctx_t ctx) Reallocate the storage in *mat* down the current number of nonzeros. - Note that, for matrices in *lil* form, the analogous operation is performed + Note that, for matrices in *lil* form, the operation is performed on each row. .. function:: void gr_csr_mat_set_cols(gr_csr_mat_t mat, slong cols, gr_ctx_t ctx) - void gr_lil_mat_set_cols(gr_llil_mat_t mat, slong cols, gr_ctx_t ctx) + void gr_lil_mat_set_cols(gr_lil_mat_t mat, slong cols, gr_ctx_t ctx) + void gr_coo_mat_set_cols(gr_coo_mat_t mat, slong cols, gr_ctx_t ctx) Set the nominal number of columns of the matrix *mat* to *cols*. If *cols* is smaller than - the current number of columns of *vec*, any entries whose columns are at least *cols* - are truncated. That is, the number of nonzeros can change. + the current number of columns of *mat*, any entries whose columns are at least *cols* + are truncated. That is, the number of nonzeros can change (but the allocation does not). + +.. function:: int gr_coo_mat_from_entries(gr_coo_mat_t mat, ulong *rows, ulong *cols, gr_srcptr entries, slong nnz, truth_t is_canonical, gr_ctx_t ctx) + + Construct a sparse matrix in coordinate form from three list of corresponding + rows, columns, and (presumably nonzero) values. If *is_canonical* is set to *T_TRUE*, + the rows and columns are assumed to sorted in row-column order and unique, and the + values are assumed to be non-zero. Otherwise, they may be in any order with zeroes, + and duplicate elements are assumed to add. + +.. function:: truth_t gr_coo_mat_is_canonical(gr_coo_mat_t mat, gr_ctx_t ctx) + + Check if a matrix in coordinate form is in canonical form, with sorted and unique + (row, column) pairs and no (known) zero entries. + +.. function:: int gr_coo_mat_canonicalize(gr_coo_mat_t mat, gr_ctx_t ctx) + + Put a coordinate-form sparse matrix in canonical form. +.. function:: int gr_coo_mat_randtest(gr_coo_mat_t mat, slong nnz, int replacement, truth_t is_canonical, flint_rand_t state, gr_ctx_t ctx) + Construct a random coordinate-form sparse matrix *mat* with (approximately) *nnz* nonzeroes, + in coordinate form iff *is_canonical* is set to *T_TRUE*. If replacement is set, the + (row, column) indices are chosen randomly with replacement, so the actual number of nonzeroes + may be slightly less. Otherwise, the matrix is guaranteed to have *nnz* identically distributed + nonzeroes, using reservoir sampling. The latter is better for sampling high density matrices, + the former for low density ones. In both cases, the nonzero values are chosen using ``gr_randtest_nonzero``. + +.. function:: int gr_coo_mat_randtest_prob(gr_coo_mat_t mat, double prob, flint_rand_t state, gr_ctx_t ctx) + + Construct a random coordinate-form sparse matrix *mat*, with each entry set to a random nonzero + value with probability *prob*. Getting, setting and conversion -------------------------------------------------------------------------------- -.. function:: int gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t vec, slong row, slong col, gr_ctx_t ctx) - int gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t vec, slong row, slong col, gr_ctx_t ctx) - - Set *res* to be the entry at position (*row*, *col*). +.. function:: gr_ptr gr_csr_mat_find_entry(gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx) + gr_ptr gr_lil_mat_find_entry(gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx) + gr_ptr gr_coo_mat_find_entry(gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx) + int gr_csr_mat_get_entry(gr_ptr res, gr_csr_mat_t mat, slong row, slong col, gr_ctx_t ctx) + int gr_lil_mat_get_entry(gr_ptr res, gr_lil_mat_t mat, slong row, slong col, gr_ctx_t ctx) + int gr_coo_mat_get_entry(gr_ptr res, gr_coo_mat_t mat, slong row, slong col, gr_ctx_t ctx) + + The *find* functions look for an entry at position (*row*, *col*), returning it if found and NULL + otherwise; the corresponding *get* functions instead copy any value found into *res*, and set + *res* to zero if that position is not found. In the case of non-canonical form COO + sparse matrices, the value is taken to be the first nonzero found at that positiion. - Because of the way sparse matrices are represented, this is logarithmic time in the number of nonzeros - in the specified row. + Because of the way sparse matrices are represented, this is + * logarithmic time in the number of nonzeros in the specified row, for CSR and LIL matrices, + * logarithmic time in the number of nonzeros in the matrix, for canonical form COO matrices, and + * linear time in the number of nonzeroes in the matrix, for non-canonical form COO matrices. -.. function:: int gr_csr_mat_set_entry(gr_csr_mat_t vec, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx) - int gr_lil_mat_set_entry(gr_lil_mat_t vec, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx) +.. function:: int gr_csr_mat_set_entry(gr_csr_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx) + int gr_lil_mat_set_entry(gr_lil_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx) + int gr_coo_mat_set_entry(gr_coo_mat_t mat, slong row, slong col, gr_srcptr entry, gr_ctx_t ctx) Set the the entry at location (*row*, *col*) to be *entry*. @@ -157,39 +237,52 @@ Getting, setting and conversion repeatedly: for the list of lists representation, it is linear time in the number of nonzeros in the associated row; for the sparse compressed row representation, it is linear time in the overall number of nonzeroes. If possible, the entries to update should be batched up and - given using `gr_lil_mat_update`, `gr_csr_mat_set_from_coo`, `gr_lil_mat_set_from_coo`, - `gr_csr_mat_set_from_coo_sorted_deduped`, or `gr_lil_mat_set_from_coo_sorted_deduped`. + given using `gr_coo_mat_from_entries`. .. function:: int gr_csr_mat_zero(gr_csr_mat_t mat, gr_ctx_t ctx) int gr_lil_mat_zero(gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_zero(gr_coo_mat_t mat, gr_ctx_t ctx) - Set *mat* to the zero matrix. + Set *mat* to the zero matrix (by setting *nnz* to 0; no actual element values are changed). .. function:: int gr_csr_mat_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) int gr_lil_mat_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_set(gr_coo_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) int gr_csr_mat_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) int gr_lil_mat_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_set_lil_mat(gr_coo_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_set_csr_mat(gr_coo_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_csr_mat_set_coo_mat(gr_csr_mat_t res, const gr_coo_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_set_coo_mat(gr_lil_mat_t res, const gr_coo_mat_t mat, gr_ctx_t ctx) Set *res* to a copy of *mat*, possibly changing the type of representation. .. function:: int gr_csr_mat_set_mat(gr_csr_mat_t res, gr_mat_t mat, gr_ctx_t ctx) int gr_lil_mat_set_mat(gr_lil_mat_t res, gr_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_set_mat(gr_coo_mat_t res, gr_mat_t mat, gr_ctx_t ctx) Set *res* from the (nominally) dense matrix *mat*. .. function:: int gr_mat_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) int gr_mat_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_mat_set_coo_mat(gr_mat_t res, const gr_coo_mat_t mat, gr_ctx_t ctx) - Set a dense matrix *res* from the sparse matrix *mat*, for either representation. + Set a dense matrix *res* from the sparse matrix *mat*, for some representation. .. function:: int gr_csr_mat_init_set(gr_csr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) int gr_lil_mat_init_set(gr_lil_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) int gr_csr_mat_init_set_lil_mat(gr_csr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) int gr_lil_mat_init_set_csr_mat(gr_lil_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_init_set_lil_mat(gr_coo_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_init_set_csr_mat(gr_coo_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_csr_mat_init_set_coo_mat(gr_csr_mat_t res, const gr_coo_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_init_set_coo_mat(gr_lil_mat_t res, const gr_coo_mat_t mat, gr_ctx_t ctx) int gr_csr_mat_init_set_mat(gr_csr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) int gr_lil_mat_init_set_mat(gr_lil_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_init_set_mat(gr_coo_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) int gr_mat_init_set_csr_mat(gr_mat_t res, const gr_csr_mat_t mat, gr_ctx_t ctx) int gr_mat_init_set_lil_mat(gr_mat_t res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_mat_init_set_coo_mat(gr_mat_t res, const gr_coo_mat_t mat, gr_ctx_t ctx) Simultaneous initialize and setting. @@ -199,42 +292,16 @@ Getting, setting and conversion in *src* are overwritten with their values in *src*. Any indices in *res* which do not appear in *src* are left unchanged. -.. function:: int gr_csr_mat_set_from_coo(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) - int gr_lil_mat_set_from_coo(gr_lil_mat_t vec, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) - - Set *mat* from the sparse data given by arrays *rows*, *cols*, and *entries*. - - These functions allow one to construct a matrix from nonzero data in coo(rdinate) form, i.e., - a list of triples of (row, col, entry) (provided as parallel arrays *rows*, *cols*, *entries*). - No assumption is made that the indices are sorted nor that the entries are nonzero. The values associated - with duplicate indices are added together. - -.. function:: int gr_csr_mat_set_from_coo_sorted_deduped(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) - int gr_csr_mat_set_from_coo_sorted_deduped(gr_csr_mat_t mat, ulong * rows, ulong * cols, gr_srcptr entries, slong nnz, gr_ctx_t ctx) - - Set *mat* from the sparse data given by arrays *rows*, *cols*, and *entries*. - - Similar to the set from coo functions, save that the entries are required to be nonzero and the - (row, col) pairs distinct and sorted (by row then col). - -.. function:: int gr_csr_mat_randtest(gr_csr_mat_t mat, double row_density, slong nrows, slong ncols, flint_rand_t state, gr_ctx_t ctx) - int gr_lil_mat_randtest(gr_lil_mat_t mat, double row_density, slong nrows, slong ncols, flint_rand_t state, gr_ctx_t ctx) - - Initialize *mat* to a random *nrows* x *ncols* matrix with row density (fraction of nonzeros) - *density*. The algorithm is suitable when *density* is small. - Specifically, indices are generated randomly and deduped. So if the - density is larger than ``1/sqrt(ncols)``, the true density of the returned vector - is likely to be lower than *density*. - .. function:: void gr_lil_mat_window_init(gr_lil_mat_t window, const gr_lil_mat_t mat, slong r1, slong c1, slong r2, slong c2, gr_ctx_t ctx) void gr_lil_mat_window_clear(gr_lil_mat_t window, gr_ctx_t ctx) A window is a view on a submatrix with a given interval of rows and columns, and is provided by using pointer offsets into the given matrix (so no copying is performed). The window - produced is read-only. + produced is read-only. TO BE IMPLEMENTD .. function:: int gr_scr_mat_permute_cols(gr_scr_mat_t mat, slong * perm, gr_ctx_t ctx) int gr_lil_mat_permute_cols(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx) + int gr_coo_mat_permute_cols(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx) Permute the columns in *mat* according to the given permutation, i.e., ``mat[r][perm[i]] = mat[i]``. @@ -248,6 +315,8 @@ Getting, setting and conversion function (required to be non-null), while for the other functions it may be optionally provided to keep track of the permutation(s) performed. + Permuting the rows is TO BE IMPLEMENTED. + Because of the nature of the sparse compressed row representation, swapping and permuting rows is an expensive operation and thus not provided. @@ -256,22 +325,29 @@ Comparison .. function:: truth_t gr_csr_mat_is_zero(const gr_csr_mat_t mat, gr_ctx_t ctx) truth_t gr_lil_mat_is_zero(const gr_lil_mat_t mat, gr_ctx_t ctx) + truth_t gr_coo_mat_is_zero(gr_coo_mat_t mat, gr_ctx_t ctx) Return ``T_TRUE`` if *mat* has no nonzeroes, ``T_FALSE`` if has any element - known to be nonzero, and ``T_UNKNOWN`` otherwise. + known to be nonzero, and ``T_UNKNOWN`` otherwise. For a coordinate-form matrix, + if it is not in canonical form, it is canonicalized before returning. .. function:: truth_t gr_csr_mat_is_one(const gr_csr_mat_t mat, gr_ctx_t ctx) truth_t gr_lil_mat_is_one(const gr_lil_mat_t mat, gr_ctx_t ctx) + truth_t gr_coo_mat_is_one(const gr_coo_mat_t mat, gr_ctx_t ctx) truth_t gr_csr_mat_is_neg_one(const gr_csr_mat_t mat, gr_ctx_t ctx) truth_t gr_lil_mat_is_neg_one(const gr_lil_mat_t mat, gr_ctx_t ctx) + truth_t gr_coo_mat_is_neg_one(const gr_coo_mat_t mat, gr_ctx_t ctx) Return ``T_TRUE`` if *mat* is square, has one nonzero element in each row (at the corresponding column), and that element is known to be equal to (negative) one; ``T_FALSE`` if the matrix is not square, has any off-diagonal element known to be nonzero, or has any diagonal known to not be (negative) one; and ``T_UNKNOWN`` otherwise. + Functions for coordinate-form matrices are TO BE IMPLEMENTED. + .. function:: truth_t gr_csr_mat_equal(const gr_csr_mat_t mat1, const gr_csr_mat_t mat2, gr_ctx_t ctx) truth_t gr_lil_mat_equal(const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) + truth_t gr_coo_mat_equal(const gr_coo_mat_t mat1, const gr_coo_mat_t mat2, gr_ctx_t ctx) truth_t gr_csr_mat_equal_lil_mat(const gr_csr_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx) Returns ``T_TRUE`` if *mat1* and *mat2* represent the same matrix and ``T_FALSE`` otherwise. @@ -280,24 +356,29 @@ Comparison Output -------------------------------------------------------------------------------- -.. function:: int gr_csr_mat_write_nz(gr_stream_t out, const gr_csr_mat_t vec, gr_ctx_t ctx) - int gr_lil_mat_write_nz(gr_stream_t out, const gr_lil_mat_t vec, gr_ctx_t ctx) +.. function:: int gr_csr_mat_write_nz(gr_stream_t out, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_write_nz(gr_stream_t out, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_write_nz(gr_stream_t out, const gr_coo_mat_t mat, gr_ctx_t ctx) - Write the nonzeros of *mat* to the stream *out*. See ``gr_mat_set_csr_mat`` and - ``gr_mat_set_lil_mat`` if it is desired to write out the entire matrix, zeros and all. + Write the nonzeros of *mat* to the stream *out*. Using ``gr_mat_write`` together with + ``gr_mat_set_csr_mat``, ``gr_mat_set_lil_mat``, or ``gr_mat_set_lil_mat``, + if it is desired to write out the entire matrix, zeros and all. .. function:: int gr_csr_mat_print_nz(const gr_csr_mat_t mat, gr_ctx_t ctx) int gr_lil_mat_print_nz(const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_print_nz(const gr_coo_mat_t mat, gr_ctx_t ctx) - Print the nonzeros of *mat* to ``stdout``. See ``gr_mat_set_csr_mat`` and - ``gr_mat_set_lil_mat`` if it is desired to print out the entire matrix, zeros and all. + Write the nonzeros of *mat* to *stdout*. Using ``gr_mat_write`` together with + ``gr_mat_set_csr_mat``, ``gr_mat_set_lil_mat``, or ``gr_mat_set_lil_mat``, + if it is desired to write out the entire matrix, zeros and all. Arithmetic -------------------------------------------------------------------------------- .. function:: int gr_csr_mat_neg(gr_csr_mat_t res, const gr_csr_mat_t src, gr_ctx_t ctx) - int gr_lil_mat_neg(gr_lil_mat_t res, const gr_csr_mat_t src, gr_ctx_t ctx) + int gr_lil_mat_neg(gr_lil_mat_t res, const gr_lil_mat_t src, gr_ctx_t ctx) + int gr_coo_mat_neg(gr_coo_mat_t res, const gr_coo_mat_t src, gr_ctx_t ctx) Set *res* to -*src*. @@ -315,81 +396,101 @@ Arithmetic Componentwise add and sub mul, with different options for the scalar. -Arithmetic into dense vectors --------------------------------------------------------------------------------- - -.. function:: int gr_vec_update_sparse_vec_nz(gr_ptr dres, const gr_sparse_vec_t src, gr_ctx_t ctx) - int gr_vec_add_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) - int gr_vec_sub_sparse_vec(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) - int gr_vec_mul_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) - int gr_vec_div_sparse_vec_nz(gr_ptr dres, gr_srcptr dvec1, const gr_sparse_vec_t svec2, gr_ctx_t ctx) - int gr_vec_addmul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) - int gr_vec_submul_sparse_vec_scalar(gr_ptr dres, const gr_sparse_vec_t svec, gr_srcptr c, gr_ctx_t ctx) - int gr_vec_addmul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) - int gr_vec_submul_sparse_vec_scalar_si(gr_ptr dres, const gr_sparse_vec_t svec, slong c, gr_ctx_t ctx) - int gr_vec_addmul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) - int gr_vec_submul_sparse_vec_scalar_fmpz(gr_ptr dres, const gr_sparse_vec_t svec, const fmpz_t c, gr_ctx_t ctx) - - These functions facilitate accumulating a sparse vector into a dense - target. They have one dense input, one sparse input, and a dense output - (where the dense input and output are the same for the fused operations). - For all functions, it is assumed that *dres* and *dvec1* have the same - length as *svec* or *svec2*, as appropriate. All functions only modify - the locations in *dres* at which the sparse vector has a nonzero value: - in particular, the functions *gr_vec_mul_sparse_vec_nz* and - *gr_vec_div_sparse_vec_nz* behave very differently from their dense counterparts. - Componentwise multiplication and division -------------------------------------------------------------------------------- -.. function:: int gr_csr_mat_mul_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_csr_mat_mul_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) - int gr_csr_mat_mul_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) - int gr_csr_mat_mul_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) - int gr_csr_mat_mul_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) - int gr_csr_mat_mul_scalar_2exp_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) - int gr_csr_mat_div_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_csr_mat_div_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) - int gr_csr_mat_div_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) - int gr_csr_mat_div_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) - int gr_csr_mat_div_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) - int gr_csr_mat_divexact_scalar(gr_csr_mat_t res, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_csr_mat_divexact_scalar_si(gr_csr_mat_t res, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) - int gr_csr_mat_divexact_scalar_ui(gr_csr_mat_t res, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) - int gr_csr_mat_divexact_scalar_fmpz(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) - int gr_csr_mat_divexact_scalar_fmpq(gr_csr_mat_t res, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) - int gr_lil_mat_mul_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_lil_mat_mul_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) - int gr_lil_mat_mul_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) - int gr_lil_mat_mul_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) - int gr_lil_mat_mul_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) - int gr_lil_mat_mul_scalar_2exp_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) - int gr_lil_mat_div_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_lil_mat_div_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) - int gr_lil_mat_div_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) - int gr_lil_mat_div_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) - int gr_lil_mat_div_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) - int gr_lil_mat_divexact_scalar(gr_lil_mat_t res, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) - int gr_lil_mat_divexact_scalar_si(gr_lil_mat_t res, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) - int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t res, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) - int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) - int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t res, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) - - Set *res* to be *src* multiplied or divided by *c*. +.. function:: int gr_csr_mat_mul_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_csr_mat_mul_scalar_2exp_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_csr_mat_div_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar(gr_csr_mat_t dst, const gr_csr_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar_si(gr_csr_mat_t dst, const gr_csr_mat_t src, slong c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar_ui(gr_csr_mat_t dst, const gr_csr_mat_t src, ulong c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar_fmpz(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_csr_mat_divexact_scalar_fmpq(gr_csr_mat_t dst, const gr_csr_mat_t src, const fmpq_t c, gr_ctx_t ctx) + + int gr_lil_mat_mul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_lil_mat_mul_scalar_2exp_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_lil_mat_div_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar_si(gr_lil_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar_ui(gr_lil_mat_t dst, const gr_lil_mat_t src, ulong c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar_fmpz(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_lil_mat_divexact_scalar_fmpq(gr_lil_mat_t dst, const gr_lil_mat_t src, const fmpq_t c, gr_ctx_t ctx) + + int gr_coo_mat_mul_scalar(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_coo_mat_mul_scalar_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx) + int gr_coo_mat_mul_scalar_ui(gr_coo_mat_t dst, const gr_coo_mat_t src, ulong c, gr_ctx_t ctx) + int gr_coo_mat_mul_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_coo_mat_mul_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_coo_mat_mul_scalar_2exp_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx) + int gr_coo_mat_div_scalar(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_coo_mat_div_scalar_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx) + int gr_coo_mat_div_scalar_ui(gr_coo_mat_t dst, const gr_coo_mat_t src, ulong c, gr_ctx_t ctx) + int gr_coo_mat_div_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_coo_mat_div_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx) + int gr_coo_mat_divexact_scalar(gr_coo_mat_t dst, const gr_coo_mat_t src, gr_srcptr c, gr_ctx_t ctx) + int gr_coo_mat_divexact_scalar_si(gr_coo_mat_t dst, const gr_coo_mat_t src, slong c, gr_ctx_t ctx) + int gr_coo_mat_divexact_scalar_ui(gr_coo_mat_t dst, const gr_coo_mat_t src, ulong c, gr_ctx_t ctx) + int gr_coo_mat_divexact_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx) + int gr_coo_mat_divexact_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx) + + Set *dst* to be *src* multiplied or divided by *c*. (Addition and subtraction are not provided because they would create dense output.) +Arithmetic into dense matrices +-------------------------------------------------------------------------------- + +.. function:: int gr_mat_update_lil_mat_nz(gr_ptr dres, const gr_lil_mat_t src, gr_ctx_t ctx) + int gr_mat_add_lil_mat(gr_ptr dres, gr_srcptr dvec1, const gr_lil_mat_t svec2, gr_ctx_t ctx) + int gr_mat_sub_lil_mat(gr_ptr dres, gr_srcptr dvec1, const gr_lil_mat_t svec2, gr_ctx_t ctx) + int gr_mat_mul_lil_mat_nz(gr_ptr dres, gr_srcptr dvec1, const gr_lil_mat_t svec2, gr_ctx_t ctx) + int gr_mat_div_lil_mat_nz(gr_ptr dres, gr_srcptr dvec1, const gr_lil_mat_t svec2, gr_ctx_t ctx) + int gr_mat_addmul_lil_mat_scalar(gr_ptr dres, const gr_lil_mat_t svec, gr_srcptr c, gr_ctx_t ctx) + int gr_mat_submul_lil_mat_scalar(gr_ptr dres, const gr_lil_mat_t svec, gr_srcptr c, gr_ctx_t ctx) + int gr_mat_addmul_lil_mat_scalar_si(gr_ptr dres, const gr_lil_mat_t svec, slong c, gr_ctx_t ctx) + int gr_mat_submul_lil_mat_scalar_si(gr_ptr dres, const gr_lil_mat_t svec, slong c, gr_ctx_t ctx) + int gr_mat_addmul_lil_mat_scalar_fmpz(gr_ptr dres, const gr_lil_mat_t svec, const fmpz_t c, gr_ctx_t ctx) + int gr_mat_submul_lil_mat_scalar_fmpz(gr_ptr dres, const gr_lil_mat_t svec, const fmpz_t c, gr_ctx_t ctx) + + These functions facilitate accumulating a sparse matrix into a dense + target. They have one dense input, one sparse input, and a dense output + (where the dense input and output are the same for the fused operations). + For all functions, it is assumed that *dres* and *dvec1* have the same + shape as *svec* or *svec2*, as appropriate. All functions only modify + the locations in *dres* at which the sparse matrix has a nonzero value: + in particular, the functions *gr_mat_mul_lil_mat_nz* and + *gr_mat_div_lil_mat_nz* behave very differently from their dense counterparts. + Sum and product -------------------------------------------------------------------------------- .. function:: int gr_csr_mat_sum(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx) int gr_lil_mat_sum(gr_ptr res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_sum(gr_ptr res, const gr_coo_mat_t mat, gr_ctx_t ctx) Set *res* to the sum of the entries in *mat*. -.. function:: int gr_csr_mat_product(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx) - int gr_lil_mat_product(gr_ptr res, const gr_lil_mat_t mat, gr_ctx_t ctx) +.. function:: int gr_csr_mat_nz_product(gr_ptr res, const gr_csr_mat_t mat, gr_ctx_t ctx) + int gr_lil_mat_nz_product(gr_ptr res, const gr_lil_mat_t mat, gr_ctx_t ctx) + int gr_coo_mat_nz_product(gr_ptr res, const gr_coo_mat_t mat, gr_ctx_t ctx) Set *res* to the product of the nonzero entries in *mat*. @@ -408,14 +509,42 @@ Matrix multiplication Set *C^T* equal to `A \cdot B^T`, i.e., right multiplication with *B* and *C* considered to be column matrices. - This is the standard procedure use by solving, and is maximally cache friendly. - .. function:: int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ctx_t ctx) int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ctx_t ctx) Set *C* equal to `A \cdot B`, i.e., perform right multiplication by *B*. -.. raw:: latex +Solving, nullvector, and nullspace computation +-------------------------------------------------------------------------------- + +.. function:: int gr_lil_mat_solve_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, flint_rand_t state, gr_ctx_t ctx) + int gr_lil_mat_solve_block_lanczos(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, slong block_size, flint_rand_t state, gr_ctx_t ctx) + int gr_lil_mat_solve_wiedemann(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, gr_ctx_t ctx) + int gr_lil_mat_solve_block_wiedemann(gr_ptr x, const gr_lil_mat_t M, gr_srcptr b, slong block_size, flint_rand_t state, gr_ctx_t ctx) + + Solve `Mx = b` for a sparse matrix `M` and *M->c* long column vector `b`, using either Lanczos' or Wiedemann's algorithm. + Both are randomized algorithms which use a given random state machine, and thus may fail without provably no solution + (returning `GR_UNABLE`). Both have block variants which are better for large matrices, and take an extra parameter of + `block_size`. The (block) Wiedemann algorithm requires the given matrix to be square, but not symmetric: the Lanczos + algorithm requires both, but assumes the given matrix may be neither, so instead solves `M^TMx = M^Tb`. Thus, it may + return a *pseudo-solution*, which solves the latter but not the former. + +.. function:: int gr_lil_mat_nullvector_lanczos(gr_ptr x, const gr_lil_mat_t M, flint_rand_t state, gr_ctx_t ctx) + int gr_lil_mat_nullvector_block_lanczos(gr_ptr x, const gr_lil_mat_t M, slong block_size, flint_rand_t state, gr_ctx_t ctx) + int gr_lil_mat_nullvector_wiedemann(gr_ptr x, const gr_lil_mat_t M, flint_rand_t state, gr_ctx_t ctx) + int gr_lil_mat_nullvector_block_wiedemann(gr_ptr x, const gr_lil_mat_t M, slong block_size, flint_rand_t state, gr_ctx_t ctx) + + Find a nullvector for the sparse matrix `M`, using (block) Lanczos or Wiedemann. + +.. function:: int gr_lil_mat_nullspace(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, const char *algorithm, slong block_size, gr_ctx_t ctx) + int gr_lil_mat_nullspace_lanczos(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, gr_ctx_t ctx) + int gr_lil_mat_nullspace_wiedemann(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, gr_ctx_t ctx) + gr_lil_mat_nullspace_block_lanczos(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, slong block_size, gr_ctx_t ctx) + int gr_lil_mat_nullspace_block_wiedemann(gr_mat_t X, const gr_lil_mat_t M, flint_rand_t state, slong max_iters, slong block_size, gr_ctx_t ctx) + + Find the nullspace for the sparse matrix `M`, using (block) Lanczos or Wiedemann. + +.. raw:: latexint \newpage diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index 0d3c28b030..e4fe4e9ae7 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -292,7 +292,7 @@ gr_coo_mat_swap(gr_coo_mat_t mat1, gr_coo_mat_t mat2, gr_ctx_t ctx) } void gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx); -void gr_lil_mat_fit_nnz(gr_coo_mat_t mat, slong *nnz, gr_ctx_t ctx); +void gr_lil_mat_fit_nnz(gr_lil_mat_t mat, slong *nnz, gr_ctx_t ctx); void gr_coo_mat_fit_nnz(gr_coo_mat_t mat, slong nnz, gr_ctx_t ctx); @@ -560,14 +560,14 @@ gr_lil_mat_window_clear(gr_lil_mat_t window, gr_ctx_t ctx) } WARN_UNUSED_RESULT int gr_lil_mat_swap_rows(gr_lil_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_coo_mat_swap_rows(gr_coo_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx); +//WARN_UNUSED_RESULT int gr_coo_mat_swap_rows(gr_coo_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_lil_mat_permute_rows(gr_lil_mat_t mat, const slong * perm, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_coo_mat_permute_rows(gr_coo_mat_t mat, const slong * perm, gr_ctx_t ctx); +//WARN_UNUSED_RESULT int gr_lil_mat_permute_rows(gr_lil_mat_t mat, const slong * perm, gr_ctx_t ctx); +//WARN_UNUSED_RESULT int gr_coo_mat_permute_rows(gr_coo_mat_t mat, const slong * perm, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_csr_mat_invert_rows(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_invert_rows(gr_lil_mat_t mat, slong * perm, gr_ctx_t ctx); -WARN_UNUSED_RESULT int gr_coo_mat_invert_rows(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx); +//WARN_UNUSED_RESULT int gr_coo_mat_invert_rows(gr_coo_mat_t mat, slong * perm, gr_ctx_t ctx); /* WARN_UNUSED_RESULT int gr_lil_mat_concat_horizontal(gr_lil_mat_t res, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); @@ -661,7 +661,7 @@ WARN_UNUSED_RESULT int gr_coo_mat_neg(gr_coo_mat_t dst, const gr_coo_mat_t src, WARN_UNUSED_RESULT int gr_lil_mat_add(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_sub(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); -//WARN_UNUSED_RESULT int gr_lil_mat_mul(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_mul(gr_lil_mat_t dst, const gr_lil_mat_t mat1, const gr_lil_mat_t mat2, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_addmul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_submul_scalar(gr_lil_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); @@ -721,6 +721,22 @@ WARN_UNUSED_RESULT int gr_coo_mat_divexact_scalar_ui(gr_coo_mat_t dst, const gr_ WARN_UNUSED_RESULT int gr_coo_mat_divexact_scalar_fmpz(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpz_t c, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_coo_mat_divexact_scalar_fmpq(gr_coo_mat_t dst, const gr_coo_mat_t src, const fmpq_t c, gr_ctx_t ctx); +/** + * Arithmetic into dense matrices +*/ + +WARN_UNUSED_RESULT int gr_mat_update_lil_mat_nz(gr_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_add_lil_mat(gr_mat_t dst, const gr_mat_t src1, const gr_lil_mat_t src2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_sub_lil_mat(gr_mat_t dst, const gr_mat_t src1, const gr_lil_mat_t src2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_mul_lil_mat_nz(gr_mat_t dst, const gr_mat_t src1, const gr_lil_mat_t src2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_div_lil_mat_nz(gr_mat_t dst, const gr_mat_t src1, const gr_lil_mat_t src2, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_addmul_lil_mat_scalar(gr_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_submul_lil_mat_scalar(gr_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_addmul_lil_mat_scalar_si(gr_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_submul_lil_mat_scalar_si(gr_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_addmul_lil_mat_scalar_fmpz(gr_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_mat_submul_lil_mat_scalar_fmpz(gr_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx); + /** * Sum and product **/ diff --git a/src/gr_sparse_mat/arith_dense.c b/src/gr_sparse_mat/arith_dense.c new file mode 100644 index 0000000000..6947ce5eb0 --- /dev/null +++ b/src/gr_sparse_mat/arith_dense.c @@ -0,0 +1,134 @@ +/* + Copyright (C) 2024 Kartik Venkatram and Alden Walker + Copyright (C) 2023 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 +#include "gr_sparse_mat.h" + + +WARN_UNUSED_RESULT int gr_mat_update_lil_mat_nz(gr_mat_t dst, const gr_lil_mat_t src, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src->r; ++row) + success |= gr_vec_update_sparse_vec_nz(dst->rows[row], &src->rows[row], ctx); + return success; +} + +WARN_UNUSED_RESULT int gr_mat_add_lil_mat(gr_mat_t dst, const gr_mat_t src1, const gr_lil_mat_t src2, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src1, ctx) != T_TRUE || gr_mat_is_compatible(dst, src2, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src1->r; ++row) + success |= gr_vec_add_sparse_vec(dst->rows[row], src1->rows[row], &src2->rows[row], ctx); + return success; +} + +WARN_UNUSED_RESULT int gr_mat_sub_lil_mat(gr_mat_t dst, const gr_mat_t src1, const gr_lil_mat_t src2, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src1, ctx) != T_TRUE || gr_mat_is_compatible(dst, src2, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src1->r; ++row) + success |= gr_vec_sub_sparse_vec(dst->rows[row], src1->rows[row], &src2->rows[row], ctx); + return success; +} +WARN_UNUSED_RESULT int gr_mat_mul_lil_mat_nz(gr_mat_t dst, const gr_mat_t src1, const gr_lil_mat_t src2, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src1, ctx) != T_TRUE || gr_mat_is_compatible(dst, src2, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src1->r; ++row) + success |= gr_vec_mul_sparse_vec_nz(dst->rows[row], src1->rows[row], &src2->rows[row], ctx); + return success; +} +WARN_UNUSED_RESULT int gr_mat_div_lil_mat_nz(gr_mat_t dst, const gr_mat_t src1, const gr_lil_mat_t src2, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src1, ctx) != T_TRUE || gr_mat_is_compatible(dst, src2, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src1->r; ++row) + success |= gr_vec_div_sparse_vec_nz(dst->rows[row], src1->rows[row], &src2->rows[row], ctx); + return success; +} + +WARN_UNUSED_RESULT int gr_mat_addmul_lil_mat_scalar(gr_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src->r; ++row) + success |= gr_vec_addmul_sparse_vec_scalar(dst->rows[row], &src->rows[row], c, ctx); + return success; +} + +WARN_UNUSED_RESULT int gr_mat_submul_lil_mat_scalar(gr_mat_t dst, const gr_lil_mat_t src, gr_srcptr c, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src->r; ++row) + success |= gr_vec_submul_sparse_vec_scalar(dst->rows[row], &src->rows[row], c, ctx); + return success; +} + +WARN_UNUSED_RESULT int gr_mat_addmul_lil_mat_scalar_si(gr_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src->r; ++row) + success |= gr_vec_addmul_sparse_vec_scalar_si(dst->rows[row], &src->rows[row], c, ctx); + return success; +} + +WARN_UNUSED_RESULT int gr_mat_submul_lil_mat_scalar_si(gr_mat_t dst, const gr_lil_mat_t src, slong c, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src->r; ++row) + success |= gr_vec_submul_sparse_vec_scalar_si(dst->rows[row], &src->rows[row], c, ctx); + return success; +} + +WARN_UNUSED_RESULT int gr_mat_addmul_lil_mat_scalar_fmpz(gr_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src->r; ++row) + success |= gr_vec_addmul_sparse_vec_scalar_fmpz(dst->rows[row], &src->rows[row], c, ctx); + return success; +} + +WARN_UNUSED_RESULT int gr_mat_submul_lil_mat_scalar_fmpz(gr_mat_t dst, const gr_lil_mat_t src, const fmpz_t c, gr_ctx_t ctx) +{ + slong row; + int success = GR_SUCCESS; + if (gr_mat_is_compatible(dst, src, ctx) != T_TRUE) + return GR_DOMAIN; + for (row = 0; row < src->r; ++row) + success |= gr_vec_submul_sparse_vec_scalar_fmpz(dst->rows[row], &src->rows[row], c, ctx); + return success; +} diff --git a/src/gr_sparse_mat/fit_nnz.c b/src/gr_sparse_mat/fit_nnz.c index e374abc821..45fc747371 100644 --- a/src/gr_sparse_mat/fit_nnz.c +++ b/src/gr_sparse_mat/fit_nnz.c @@ -26,6 +26,15 @@ gr_csr_mat_fit_nnz(gr_csr_mat_t mat, slong nnz, gr_ctx_t ctx) } } +void +gr_lil_mat_fit_nnz(gr_lil_mat_t mat, slong *nnz, gr_ctx_t ctx) +{ + int row; + + for (row = 0; row < mat->r; ++row) + gr_sparse_vec_fit_nnz(&mat->rows[row], nnz[row], ctx); +} + void gr_coo_mat_fit_nnz(gr_coo_mat_t mat, slong nnz, gr_ctx_t ctx) { From 7b5ec2bac8b07a672e1958908acaab970b375a1f Mon Sep 17 00:00:00 2001 From: Fredrik Johansson Date: Sat, 27 Apr 2024 14:31:16 +0200 Subject: [PATCH 57/59] fix sparse_vec arithmetic for length zero --- src/gr_sparse_vec/arith.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gr_sparse_vec/arith.c b/src/gr_sparse_vec/arith.c index 815fda59a1..4ebd048e55 100644 --- a/src/gr_sparse_vec/arith.c +++ b/src/gr_sparse_vec/arith.c @@ -53,8 +53,8 @@ while (a_nz_idx >= -1 && b_nz_idx >= -1 && status == GR_SUCCESS) \ { \ if (a_nz_idx == -1 && b_nz_idx == -1) break; \ - a_ind = (A_VEC)->inds[a_nz_idx]; \ - b_ind = (B_VEC)->inds[b_nz_idx]; \ + a_ind = (a_nz_idx >= 0) ? (A_VEC)->inds[a_nz_idx] : -1; \ + b_ind = (b_nz_idx >= 0) ? (B_VEC)->inds[b_nz_idx] : -1; \ if (b_nz_idx == -1 || (a_nz_idx >= 0 && a_ind > b_ind)) \ { \ status |= (FUNC_A); \ From 4ec61b02407d4eda1125cb3ba737d42c058594d0 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 28 Apr 2024 17:37:32 -0700 Subject: [PATCH 58/59] Added LU and rref --- src/gr_sparse_mat.h | 10 +++++++++- src/gr_sparse_mat/randtest.c | 6 ++++++ src/gr_sparse_mat/test/main.c | 10 +++++++--- src/gr_sparse_mat/test/t-solve.c | 2 ++ src/gr_sparse_vec/write.c | 5 +++-- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/gr_sparse_mat.h b/src/gr_sparse_mat.h index e4fe4e9ae7..5772f91398 100644 --- a/src/gr_sparse_mat.h +++ b/src/gr_sparse_mat.h @@ -562,7 +562,7 @@ gr_lil_mat_window_clear(gr_lil_mat_t window, gr_ctx_t ctx) WARN_UNUSED_RESULT int gr_lil_mat_swap_rows(gr_lil_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx); //WARN_UNUSED_RESULT int gr_coo_mat_swap_rows(gr_coo_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx); -//WARN_UNUSED_RESULT int gr_lil_mat_permute_rows(gr_lil_mat_t mat, const slong * perm, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_lil_mat_permute_rows(gr_lil_mat_t mat, const slong * perm, gr_ctx_t ctx); //WARN_UNUSED_RESULT int gr_coo_mat_permute_rows(gr_coo_mat_t mat, const slong * perm, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_csr_mat_invert_rows(gr_csr_mat_t mat, slong * perm, gr_ctx_t ctx); @@ -806,6 +806,14 @@ WARN_UNUSED_RESULT int gr_lil_mat_mul_mat_transpose(gr_mat_t Ct, const gr_lil_ma WARN_UNUSED_RESULT int gr_csr_mat_mul_mat(gr_mat_t C, const gr_csr_mat_t A, const gr_mat_t B, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_lil_mat_mul_mat(gr_mat_t C, const gr_lil_mat_t A, const gr_mat_t B, gr_ctx_t ctx); +/** + * LU and reduce echelon form representation +**/ + +WARN_UNUSED_RESULT int gr_lil_mat_lu(slong *rank, slong *P, slong *Q, gr_lil_mat_t L, gr_lil_mat_t U, const gr_lil_mat_t M, gr_ctx_t ctx); + +WARN_UNUSED_RESULT int gr_lil_mat_rref(slong *res_rank, gr_lil_mat_t R, gr_lil_mat_t A, gr_ctx_t ctx); + /** * Solving, nullvector, and nullspace computation **/ diff --git a/src/gr_sparse_mat/randtest.c b/src/gr_sparse_mat/randtest.c index ece681d88b..cbe5e54d03 100644 --- a/src/gr_sparse_mat/randtest.c +++ b/src/gr_sparse_mat/randtest.c @@ -20,6 +20,12 @@ int gr_coo_mat_randtest(gr_coo_mat_t mat, slong nnz, int replacement, truth_t is if (nnz < 0 || nnz > len) return GR_DOMAIN; + if (nnz == 0) + { + gr_coo_mat_zero(mat, ctx); + return GR_SUCCESS; + } + // Make space gr_coo_mat_fit_nnz(mat, nnz, ctx); diff --git a/src/gr_sparse_mat/test/main.c b/src/gr_sparse_mat/test/main.c index 9150ab95bb..71bde04c9c 100644 --- a/src/gr_sparse_mat/test/main.c +++ b/src/gr_sparse_mat/test/main.c @@ -3,11 +3,13 @@ /* Include functions *********************************************************/ -#include "t-arith.c" -#include "t-conversion.c" #include "t-init.c" -#include "t-mul.c" #include "t-randtest.c" +#include "t-conversion.c" +#include "t-arith.c" +#include "t-mul.c" +#include "t-lu.c" +#include "t-rref.c" #include "t-solve.c" /* Array of test functions ***************************************************/ @@ -19,6 +21,8 @@ test_struct tests[] = TEST_FUNCTION(gr_sparse_mat_randtest), TEST_FUNCTION(gr_sparse_mat_arith), TEST_FUNCTION(gr_sparse_mat_mul), + TEST_FUNCTION(gr_sparse_mat_rref), + TEST_FUNCTION(gr_sparse_mat_lu), TEST_FUNCTION(gr_sparse_mat_solve), }; diff --git a/src/gr_sparse_mat/test/t-solve.c b/src/gr_sparse_mat/test/t-solve.c index ef2384cda1..88adcd6304 100644 --- a/src/gr_sparse_mat/test/t-solve.c +++ b/src/gr_sparse_mat/test/t-solve.c @@ -15,6 +15,8 @@ #include "gr_sparse_mat.h" /* #include */ +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + int test_solve(flint_rand_t state, gr_ctx_t ctx) { int iter, ret; diff --git a/src/gr_sparse_vec/write.c b/src/gr_sparse_vec/write.c index 0e98faa673..6c1ae1a5dc 100644 --- a/src/gr_sparse_vec/write.c +++ b/src/gr_sparse_vec/write.c @@ -10,14 +10,15 @@ gr_sparse_vec_write_nz(gr_stream_t out, const gr_sparse_vec_t vec, gr_ctx_t ctx) gr_stream_write(out, "["); for (i = 0; i < nnz; i++) { - gr_stream_write(out, "\n\t"); + //gr_stream_write(out, "\n\t"); gr_stream_write_si(out, vec->inds[i]); gr_stream_write(out, ": "); status |= gr_write(out, GR_ENTRY(vec->nzs, i, sz), ctx); if (i < nnz - 1) gr_stream_write(out, ", "); } - gr_stream_write(out, "\n]"); + gr_stream_write(out, "]"); + //gr_stream_write(out, "\n]"); return status; } From 83ebaaaae1075bcbe41cfb5445bb43214525d0e6 Mon Sep 17 00:00:00 2001 From: Kartik Venkatram Date: Sun, 28 Apr 2024 17:40:25 -0700 Subject: [PATCH 59/59] Forgot to add files --- src/gr_sparse_mat/lu.c | 214 +++++++++++++++++++++++++++++++ src/gr_sparse_mat/permute_rows.c | 45 +++++++ src/gr_sparse_mat/rref.c | 119 +++++++++++++++++ src/gr_sparse_mat/test/t-lu.c | 164 +++++++++++++++++++++++ src/gr_sparse_mat/test/t-rref.c | 100 +++++++++++++++ 5 files changed, 642 insertions(+) create mode 100644 src/gr_sparse_mat/lu.c create mode 100644 src/gr_sparse_mat/permute_rows.c create mode 100644 src/gr_sparse_mat/rref.c create mode 100644 src/gr_sparse_mat/test/t-lu.c create mode 100644 src/gr_sparse_mat/test/t-rref.c diff --git a/src/gr_sparse_mat/lu.c b/src/gr_sparse_mat/lu.c new file mode 100644 index 0000000000..52f2609614 --- /dev/null +++ b/src/gr_sparse_mat/lu.c @@ -0,0 +1,214 @@ +/* + 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 "gr_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"); + } +} + */ +int gr_lil_mat_lu( + slong *res_rank, slong *P, slong *Q, + gr_lil_mat_t L, gr_lil_mat_t U, + const gr_lil_mat_t A, gr_ctx_t ctx +) +{ + slong i, j, r, c, rank, pr, pc, remr, remc; + slong *heap, *heap_idx, *scores, heap_size; + gr_lil_mat_t Lt; + gr_sparse_vec_struct *pcol, *prow, *row, *col; + gr_ptr cinv, cc; + int status = GR_SUCCESS; + + if (A->r == 0 || A->c == 0 || A->nnz == 0) + { + *res_rank = 0; + gr_lil_mat_zero(L, ctx); + gr_lil_mat_zero(U, ctx); + for (i = 0; i < A->r; ++i) P[i] = i; + for (j = 0; j < A->c; ++j) Q[j] = j; + return GR_SUCCESS; + } + GR_TMP_INIT2(cinv, cc, ctx); + gr_lil_mat_init(Lt, L->c, L->r, ctx); + status |= gr_lil_mat_transpose(Lt, A, ctx); + status |= gr_lil_mat_set(U, A, ctx); + + /* Set up permutations */ + remr = A->r, remc = A->c; + for (r = 0; r < A->r; ++r) + { + if (!U->rows[r].nnz) P[r] = --remr; + else P[r] = -1; + } + if (Q != NULL) + { + for (j = 0; j < A->c; ++j) + { + if (!Lt->rows[j].nnz) Q[j] = --remc; + else Q[j] = -1; + } + /* Make heap of nonzero columns by size */ + heap_size = A->c; + heap = flint_malloc(A->c*sizeof(*heap)); + scores = flint_malloc(A->c*sizeof(*scores)); + heap_idx = flint_malloc(A->c*sizeof(*heap_idx)); + for (j = 0; j < A->c; ++j) + { + scores[j] = Lt->rows[j].nnz; /* TODO: randomized tiebreaker */ + heap[j] = j; + heap_up(heap, heap_idx, scores, j); + } + } + + /* Run elimination */ + rank = 0; + for (heap_size = A->c; heap_size > 0; ) + { + + /* Get pivot column */ + if (Q != NULL) + { + /* 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 */ + } + else + { + pc = A->c - heap_size--; + pcol = &Lt->rows[pc]; + if (pcol->nnz == 0) continue; /* Nothing to do */ + } + + /* Get lowest weight incident row */ + pr = pcol->inds[0], prow = &U->rows[pr]; + for (j = 1; j < pcol->nnz; ++j) + { + r = pcol->inds[j], row = &U->rows[r]; + if (row->nnz < prow->nnz) pr = r, prow = row; + } + P[pr] = rank; /* Move pivot row to front */ + + /* Invert pivot */ + status |= gr_inv(cinv, gr_sparse_vec_find_entry(prow, pc, ctx), ctx); + + /* Lower triangular matrix will have ones on the diagonal */ + status |= gr_sparse_vec_mul_scalar(pcol, pcol, cinv, ctx); + + /* Gaussian eliminate lower rows in U incident on pivot column */ + for (j = 0; j < pcol->nnz; ++j) + { + r = pcol->inds[j], row = &U->rows[r]; + if (P[r] >= 0) continue; /* Skip previous pivot rows */ + + status |= gr_mul(cc, cinv, gr_sparse_vec_find_entry(row, pc, ctx), ctx); + status |= gr_neg(cc, cc, ctx); + status |= gr_sparse_vec_addmul_scalar(row, prow, cc, ctx); + if (row->nnz == 0) P[r] = --remr; + } + /* Gaussian eliminate lower cols in L incident on pivot row */ + for (j = 0; j < prow->nnz; ++j) + { + c = prow->inds[j], col = &Lt->rows[c]; + if ((Q == NULL && (c >= A->c || c<=pc)) || (Q != NULL && Q[c] >= 0)) + continue; /* Skip previous pivot columns */ + status |= gr_neg(cc, gr_sparse_vec_find_entry(col, pr, ctx), ctx); + status |= gr_sparse_vec_addmul_scalar(col, pcol, cc, ctx); + + if (Q != NULL) + { + 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; + } + /* Fix nnz */ + Lt->nnz = 0; + for (j = 0; j < A->c; ++j) + { + Lt->nnz += Lt->rows[j].nnz; + } + U->nnz = 0; + for (j = 0; j < A->r; ++j) + { + U->nnz += U->rows[j].nnz; + } + + /* Transpose L^t */ + status |= gr_lil_mat_transpose(L, Lt, ctx); + + /* Reorder rows and cols in L and U */ + status |= gr_lil_mat_permute_rows(L, P, ctx); + status |= gr_lil_mat_permute_rows(U, P, ctx); + if (Q != NULL) + { + status |= gr_lil_mat_permute_cols(L, Q, ctx); + status |= gr_lil_mat_permute_cols(U, Q, ctx); + } + *res_rank = rank; + + gr_lil_mat_clear(Lt, ctx); + GR_TMP_INIT2(cinv, cc, ctx); + return status; +} diff --git a/src/gr_sparse_mat/permute_rows.c b/src/gr_sparse_mat/permute_rows.c new file mode 100644 index 0000000000..473c01b3f0 --- /dev/null +++ b/src/gr_sparse_mat/permute_rows.c @@ -0,0 +1,45 @@ +/* + Copyright (C) 2022 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 "gr_sparse_mat.h" + +int gr_lil_mat_permute_rows(gr_lil_mat_t mat, const slong * perm, gr_ctx_t ctx) +{ + slong i, j; + slong *iperm; + + /* todo: bounds checking */ + if (perm == NULL) + { + return GR_DOMAIN; + } + + // Get inverse permutation, i.e., iperm[i] = row to go in ith place + iperm = flint_malloc(mat->r * sizeof(slong)); + for (i = 0; i < mat->r; ++i) + { + iperm[perm[i]] = i; + } + + // Will do at most rows - 1 swaps + for (i = 0; i < mat->r - 1; ++i) + { + // Get element to permute with current location + for (j = iperm[i]; j < i; j = iperm[j]); + if (i != j) + { + gr_sparse_vec_swap(&mat->rows[i], &mat->rows[j], ctx); + } + } + + flint_free(iperm); + return GR_SUCCESS; +} diff --git a/src/gr_sparse_mat/rref.c b/src/gr_sparse_mat/rref.c new file mode 100644 index 0000000000..c2c8a1f6e7 --- /dev/null +++ b/src/gr_sparse_mat/rref.c @@ -0,0 +1,119 @@ +/* + 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 "gr_sparse_vec.h" +#include "gr_sparse_mat.h" + +int gr_lil_mat_rref(slong *res_rank, gr_lil_mat_t R, gr_lil_mat_t A, gr_ctx_t ctx) +{ + slong *P; + slong j, r, c, pr, pc, rank, remr, sz; + slong nr = A->r; + slong nc = A->c; + gr_lil_mat_t Rt; + gr_sparse_vec_struct *pcol, *prow, *row, *col; + gr_ptr cinv, cc; + int status = GR_SUCCESS; + + if (gr_mat_is_compatible(A, R, ctx) != T_TRUE) + { + return GR_DOMAIN; + } + if (nr == 0 || nc == 0) + { + *res_rank = 0; + return GR_SUCCESS; + } + if (A->nnz == 0) + { + gr_lil_mat_zero(R, ctx); + return GR_SUCCESS; + } + // Get transpose and copy of A + gr_lil_mat_init(Rt, nc, nr, ctx); + status |= gr_lil_mat_transpose(Rt, A, ctx); + status |= gr_lil_mat_set(R, A, ctx); + + GR_TMP_INIT2(cinv, cc, ctx); + + sz = ctx->sizeof_elem; + + /* Set up permutations */ + P = flint_malloc(nr*sizeof(*P)); + remr = nr; + for (r = 0; r < nr; ++r) + { + if (!A->rows[r].nnz || A->rows[r].inds[0] >= nc) P[r] = --remr; + else P[r] = -1; + } + + /* Run elimination */ + rank = 0; + for (pc = 0; pc < nc; ++pc) + { + pcol = &Rt->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->inds[j], row = &R->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; + + status |= gr_inv(cinv, gr_sparse_vec_find_entry(prow, pc, ctx), ctx); + status |= gr_sparse_vec_mul_scalar(prow, prow, cinv, ctx); + + /* Gaussian eliminate rows */ + for (j = 0; j < pcol->nnz; ++j) + { + r = pcol->inds[j], row = &R->rows[r]; + if (r==pr) {status |= gr_zero(GR_ENTRY(pcol->nzs, j, sz), ctx); continue;} + + status |= gr_neg(cc, gr_sparse_vec_find_entry(row, pc, ctx), ctx); + status |= gr_sparse_vec_addmul_scalar(row, prow, cc, ctx); + if (row->nnz == 0 || row->inds[0] >= nc) P[r] = --remr; + } + /* Gaussian eliminate cols */ + status |= gr_sparse_vec_mul_scalar(pcol, pcol, cinv, ctx); + for (j = 0; j < prow->nnz; ++j) + { + c = prow->inds[j], col = &Rt->rows[c]; + if (c >= nc || c==pc) continue; + status |= gr_neg(cc, gr_sparse_vec_find_entry(col, pr, ctx), ctx); + status |= gr_sparse_vec_addmul_scalar(col, pcol, cc, ctx); + } + rank += 1; + } + gr_lil_mat_clear(Rt, ctx); + + /* Fix nnz */ + R->nnz = 0; + for (j = 0; j < nr; ++j) + { + R->nnz += R->rows[j].nnz; + } + + /* Reorder rows */ + status |= gr_lil_mat_permute_rows(R, P, ctx); + flint_free(P); + GR_TMP_CLEAR2(cinv, cc, ctx); + *res_rank = rank; + return status; +} diff --git a/src/gr_sparse_mat/test/t-lu.c b/src/gr_sparse_mat/test/t-lu.c new file mode 100644 index 0000000000..1aff24855d --- /dev/null +++ b/src/gr_sparse_mat/test/t-lu.c @@ -0,0 +1,164 @@ +/* + 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 "test_helpers.h" +#include "gr_sparse_mat.h" +/* #include */ + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int test_lu(flint_rand_t state, gr_ctx_t ctx) +{ + slong rep, r, c, i, j, rk, *P, *Q; + gr_ptr val; + gr_coo_mat_t Aorig; + gr_lil_mat_t A, LU, L, U; + gr_mat_t dL, dU, dLU; + int status = GR_SUCCESS; + + flint_printf("decomposing PAQ = LU...."); + fflush(stdout); + + for (rep = 0; rep < 200; rep++) + { + if (rep % 20 == 0) {flint_printf("."); fflush(stdout);} + + r = n_randint(state, 20); + c = n_randint(state, 20); + + P = flint_malloc(r*sizeof(*P)); + Q = flint_malloc(c*sizeof(*P)); + + gr_coo_mat_init(Aorig, r, c, ctx); + gr_lil_mat_init(A, r, c, ctx); + gr_lil_mat_init(LU, r, c, ctx); + gr_lil_mat_init(L, r, c, ctx); + gr_lil_mat_init(U, r, c, ctx); + + status |= gr_coo_mat_randtest(Aorig, FLINT_MIN(r * 3, c * 3), 0, T_TRUE, state, ctx); + status |= gr_lil_mat_set_coo_mat(A, Aorig, ctx); + status |= gr_lil_mat_lu(&rk, P, Q, L, U, A, ctx); + + /* Check that L is lower triangular (with ones on diagonal up to rank) */ + for (i = 0; i < r; ++i) + { + val = gr_sparse_vec_find_entry(&L->rows[i], i, ctx); + if (i < rk && (val == NULL || gr_is_one(val, ctx) == T_FALSE)) + { + flint_printf("FAIL: L does not have unit diagonal up to the rank\n"); + status |= gr_lil_mat_print_nz(L, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + for (j = 0; j < L->rows[i].nnz; ++j) + { + if (L->rows[i].inds[j] > i) + { + flint_printf("FAIL: L not lower triangular\n"); + status |= gr_lil_mat_print_nz(L, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + if (L->rows[i].inds[j] >= rk) + { + flint_printf("FAIL: L not trivial past the rank\n"); + status |= gr_lil_mat_print_nz(L, ctx); flint_printf("\n"); + /*gr_lil_mat_print_pretty(L, ctx);*/ + return GR_TEST_FAIL; + } + } + } + /* Check that U is upper triangular (with nonzero diagonal up to rank) */ + for (i = 0; i < r; ++i) + { + val = gr_sparse_vec_find_entry(&U->rows[i], i, ctx); + if (i < rk && (val == NULL || gr_is_zero(val, ctx) == T_TRUE)) + { + flint_printf("FAIL: U does not have nonzero diagonal\n"); + status |= gr_lil_mat_print_nz(U, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + if (i >= rk && U->rows[i].nnz != 0) + { + flint_printf("FAIL: U not trivial past the rank\n"); + status |= gr_lil_mat_print_nz(U, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + for (j = 0; j < U->rows[i].nnz; ++j) + { + if (U->rows[i].inds[j] < i) + { + flint_printf("FAIL: U not upper triangular\n"); + status |= gr_lil_mat_print_nz(U, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + } + } + + //flint_printf("L = "); status |= gr_lil_mat_print_nz(L, ctx); flint_printf("\n"); + //flint_printf("U = "); status |= gr_lil_mat_print_nz(U, ctx); flint_printf("\n"); + + // Check that PAQ = LU + gr_mat_init(dL, r, c, ctx); + gr_mat_init(dU, r, c, ctx); + gr_mat_init(dLU, r, c, ctx); + status |= gr_mat_set_lil_mat(dL, L, ctx); + status |= gr_mat_set_lil_mat(dU, U, ctx); + status |= gr_mat_mul(dLU, dL, dU, ctx); + status |= gr_lil_mat_set_mat(LU, dLU, ctx); + status |= gr_lil_mat_permute_rows(A, P, ctx); + status |= gr_lil_mat_permute_cols(A, Q, ctx); + if (status != GR_SUCCESS || gr_lil_mat_equal(A, LU, ctx) == T_FALSE) + { + flint_printf("FAIL: PAQ != LU\n"); + flint_printf("PAQ = "); status |= gr_lil_mat_print_nz(A, ctx); flint_printf("\n"); + flint_printf("LU = "); status |= gr_lil_mat_print_nz(LU, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + + flint_free(P); + flint_free(Q); + gr_coo_mat_clear(Aorig, ctx); + gr_lil_mat_clear(A, ctx); + gr_lil_mat_clear(U, ctx); + gr_lil_mat_clear(L, ctx); + gr_lil_mat_clear(LU, ctx); + gr_mat_clear(dL, ctx); + gr_mat_clear(dU, ctx); + gr_mat_clear(dLU, ctx); + } + + flint_printf("PASS\n"); + return status; +} + + +TEST_FUNCTION_START(gr_sparse_mat_lu, state) +{ + slong i; + gr_ctx_t ctx; + for (i = 0; i < 1; ++i) + { + while (1) + { + //gr_ctx_init_fmpz(ctx); + //gr_ctx_init_random(ctx, state); + gr_ctx_init_fq_nmod(ctx, 65521, 1, "a"); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE || gr_ctx_is_exact(ctx) != T_TRUE || gr_ctx_is_field(ctx) != T_TRUE || gr_ctx_is_finite(ctx) != T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + CHECK_TEST(test_lu(state, ctx), "Sparse matrix LU decomposition"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} diff --git a/src/gr_sparse_mat/test/t-rref.c b/src/gr_sparse_mat/test/t-rref.c new file mode 100644 index 0000000000..9cecebb887 --- /dev/null +++ b/src/gr_sparse_mat/test/t-rref.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 "test_helpers.h" +#include "gr_sparse_mat.h" +/* #include */ + +#define CHECK_TEST(x, name) { if (GR_SUCCESS != (x)) { flint_printf("FAIL %s\n", (name)); flint_abort(); } } + +int test_rref(flint_rand_t state, gr_ctx_t ctx) +{ + slong rep, r, c, sparse_rank, dense_rank; + gr_coo_mat_t Aorig; + gr_lil_mat_t A, B, R; + gr_mat_t dA, dR; + int status = GR_SUCCESS; + + 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);} + + r = n_randint(state, 20); + c = n_randint(state, 20); + gr_coo_mat_init(Aorig, r, c, ctx); + gr_lil_mat_init(A, r, c, ctx); + gr_lil_mat_init(B, r, c, ctx); + gr_lil_mat_init(R, r, c, ctx); + gr_mat_init(dA, r, c, ctx); + gr_mat_init(dR, r, c, ctx); + + status |= gr_coo_mat_randtest(Aorig, FLINT_MIN(r * 3, c * 3), 0, T_TRUE, state, ctx); + if (status != GR_SUCCESS) + { + flint_printf("Some failure!\n"); + return GR_TEST_FAIL; + } + status |= gr_lil_mat_set_coo_mat(A, Aorig, ctx); + status |= gr_mat_set_lil_mat(dA, A, ctx); + + status |= gr_lil_mat_rref(&sparse_rank, R, A, ctx); + status |= gr_mat_rref(&dense_rank, dR, dA, ctx); + status |= gr_lil_mat_set_mat(B, dR, ctx); + + if (status != GR_SUCCESS || gr_lil_mat_equal(R, B, ctx) == T_FALSE) + { + flint_printf("FAIL!\n"); + flint_printf("A = "); status |= gr_lil_mat_print_nz(A, ctx); flint_printf("\n"); + flint_printf("R = "); status |= gr_lil_mat_print_nz(R, ctx); flint_printf("\n"); + flint_printf("dR = "); status |= gr_lil_mat_print_nz(B, ctx); flint_printf("\n"); + return GR_TEST_FAIL; + } + + gr_coo_mat_clear(Aorig, ctx); + gr_lil_mat_clear(A, ctx); + gr_lil_mat_clear(B, ctx); + gr_lil_mat_clear(R, ctx); + gr_mat_clear(dA, ctx); + gr_mat_clear(dR, ctx); + } + + flint_printf("PASS\n"); + return status; +} + + +TEST_FUNCTION_START(gr_sparse_mat_rref, state) +{ + slong i; + gr_ctx_t ctx; + for (i = 0; i < 1; ++i) + { + while (1) + { + //gr_ctx_init_fmpz(ctx); + //gr_ctx_init_random(ctx, state); + gr_ctx_init_fq_nmod(ctx, 65521, 1, "a"); + if (gr_ctx_is_zero_ring(ctx) == T_TRUE || gr_ctx_is_exact(ctx) != T_TRUE || gr_ctx_is_field(ctx) != T_TRUE || gr_ctx_is_finite(ctx) != T_TRUE) + gr_ctx_clear(ctx); + else + break; + } + CHECK_TEST(test_rref(state, ctx), "Sparse matrix reduced row echelon form"); + gr_ctx_clear(ctx); + } + TEST_FUNCTION_END(state); +} +