diff --git a/doc/source/gr_poly.rst b/doc/source/gr_poly.rst index 242f73537c..245b0a1bc3 100644 --- a/doc/source/gr_poly.rst +++ b/doc/source/gr_poly.rst @@ -355,6 +355,9 @@ Evaluation .. function:: int _gr_poly_evaluate_rectangular(gr_ptr res, gr_srcptr poly, slong len, gr_srcptr x, gr_ctx_t ctx) int gr_poly_evaluate_rectangular(gr_ptr res, const gr_poly_t poly, gr_srcptr x, gr_ctx_t ctx) +.. function:: int _gr_poly_evaluate_modular(gr_ptr res, gr_srcptr poly, slong len, gr_srcptr x, gr_ctx_t ctx) + int gr_poly_evaluate_modular(gr_ptr res, const gr_poly_t poly, gr_srcptr x, gr_ctx_t ctx) + .. function:: int _gr_poly_evaluate_horner(gr_ptr res, gr_srcptr poly, slong len, gr_srcptr x, gr_ctx_t ctx) int gr_poly_evaluate_horner(gr_ptr res, const gr_poly_t poly, gr_srcptr x, gr_ctx_t ctx) diff --git a/src/gr_poly.h b/src/gr_poly.h index 9426dba735..a56b57f7b0 100644 --- a/src/gr_poly.h +++ b/src/gr_poly.h @@ -269,6 +269,9 @@ WARN_UNUSED_RESULT int gr_poly_rsqrt_series(gr_poly_t res, const gr_poly_t f, sl WARN_UNUSED_RESULT int _gr_poly_evaluate_rectangular(gr_ptr res, gr_srcptr poly, slong len, gr_srcptr x, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_poly_evaluate_rectangular(gr_ptr res, const gr_poly_t poly, gr_srcptr x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int _gr_poly_evaluate_modular(gr_ptr res, gr_srcptr poly, slong len, gr_srcptr x, gr_ctx_t ctx); +WARN_UNUSED_RESULT int gr_poly_evaluate_modular(gr_ptr res, const gr_poly_t poly, gr_srcptr x, gr_ctx_t ctx); + WARN_UNUSED_RESULT int _gr_poly_evaluate_horner(gr_ptr res, gr_srcptr poly, slong len, gr_srcptr x, gr_ctx_t ctx); WARN_UNUSED_RESULT int gr_poly_evaluate_horner(gr_ptr res, const gr_poly_t poly, gr_srcptr x, gr_ctx_t ctx); diff --git a/src/gr_poly/evaluate_modular.c b/src/gr_poly/evaluate_modular.c new file mode 100644 index 0000000000..17110f96c2 --- /dev/null +++ b/src/gr_poly/evaluate_modular.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2023 David Berghaus + + This file is part of FLINT. + + FLINT is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "ulong_extras.h" +#include "gr_vec.h" +#include "gr_poly.h" + +int +_gr_poly_evaluate_modular(gr_ptr y, gr_srcptr poly, + slong len, gr_srcptr x, gr_ctx_t ctx) +{ + slong sz = ctx->sizeof_elem; + int status = GR_SUCCESS; + gr_method_void_unary_op set_shallow = GR_VOID_UNARY_OP(ctx, SET_SHALLOW); + + if (len <= 2) + { + if (len == 0) + return gr_zero(y, ctx); + + if (len == 1) + return gr_set(y, poly, ctx); + + status |= gr_mul(y, x, GR_ENTRY(poly, 1, sz), ctx); + status |= gr_add(y, y, GR_ENTRY(poly, 0, sz), ctx); + } + else + { + slong i, j, k, coeff_index, l, m; + gr_ptr xs, ys, tmp, partial_results; + gr_ptr tmp_gr; + k = n_sqrt(len)+1; + j = (len + k - 1) / k; + + TMP_INIT; + + TMP_START; + tmp = TMP_ALLOC(sz * k); + GR_TMP_INIT(tmp_gr, ctx); + GR_TMP_INIT_VEC(xs, j, ctx); + GR_TMP_INIT_VEC(ys, k, ctx); + GR_TMP_INIT_VEC(partial_results, j, ctx); + + status |= _gr_vec_set_powers(xs, x, j, ctx); + status |= gr_mul(tmp_gr, x, GR_ENTRY(xs, j-1, sz), ctx); /* This is x^j */ + status |= _gr_vec_set_powers(ys, tmp_gr, k, ctx); + + for (l = 0; l < j; l++){ + i = 0; /* Count number of coeffs in this row */ + for (m = 0; m < k; m++) + { + coeff_index = j*m+l; + if (coeff_index < len) + { + set_shallow(GR_ENTRY(tmp, m, sz), GR_ENTRY(poly, coeff_index, sz), ctx); + i++; + } + else + { + break; + } + } + status |= _gr_vec_dot(GR_ENTRY(partial_results, l, sz), NULL, 0, tmp, ys, i, ctx); + } + status |=_gr_vec_dot(y, NULL, 0, partial_results, xs, j, ctx); + GR_TMP_CLEAR(tmp_gr, ctx); + GR_TMP_CLEAR_VEC(xs, j, ctx); + GR_TMP_CLEAR_VEC(ys, k, ctx); + GR_TMP_CLEAR_VEC(partial_results, j, ctx); + TMP_END; + } + return status; +} + + +int +gr_poly_evaluate_modular(gr_ptr res, const gr_poly_t f, gr_srcptr x, gr_ctx_t ctx) +{ + return _gr_poly_evaluate_modular(res, f->coeffs, f->length, x, ctx); +} diff --git a/src/gr_poly/test/t-evaluate_modular.c b/src/gr_poly/test/t-evaluate_modular.c new file mode 100644 index 0000000000..7f51590f92 --- /dev/null +++ b/src/gr_poly/test/t-evaluate_modular.c @@ -0,0 +1,88 @@ +/* + 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 "ulong_extras.h" +#include "gr_poly.h" + +int main() +{ + slong iter; + flint_rand_t state; + + flint_printf("evaluate_modular...."); + fflush(stdout); + + flint_randinit(state); + + for (iter = 0; iter < 1000; iter++) + { + int status; + gr_ctx_t ctx; + gr_poly_t F, G, FG; + gr_ptr x, Fx, Gx, FxGx, FGx; + + /* Test F(x) + G(x) = (F + G)(x) */ + gr_ctx_init_random(ctx, state); + + gr_poly_init(F, ctx); + gr_poly_init(G, ctx); + gr_poly_init(FG, ctx); + + x = gr_heap_init(ctx); + Fx = gr_heap_init(ctx); + Gx = gr_heap_init(ctx); + FxGx = gr_heap_init(ctx); + FGx = gr_heap_init(ctx); + + status = GR_SUCCESS; + + status |= gr_poly_randtest(F, state, 1 + n_randint(state, 10), ctx); + status |= gr_poly_randtest(G, state, 1 + n_randint(state, 10), ctx); + status |= gr_randtest(x, state, ctx); + status |= gr_randtest(Fx, state, ctx); + + status |= gr_poly_add(FG, F, G, ctx); + + status |= gr_poly_evaluate_modular(Fx, F, x, ctx); + status |= gr_set(Gx, x, ctx); /* test aliasing */ + status |= gr_poly_evaluate_modular(Gx, G, Gx, ctx); + status |= gr_add(FxGx, Fx, Gx, ctx); + status |= gr_poly_evaluate_modular(FGx, FG, x, ctx); + + if (status == GR_SUCCESS && gr_equal(FxGx, FGx, ctx) == T_FALSE) + { + flint_printf("FAIL\n\n"); + flint_printf("F = "); gr_poly_print(F, ctx); flint_printf("\n"); + flint_printf("G = "); gr_poly_print(G, ctx); flint_printf("\n"); + flint_printf("x = "); gr_print(x, ctx); flint_printf("\n"); + flint_printf("FxGx = "); gr_print(FxGx, ctx); flint_printf("\n"); + flint_printf("FGx = "); gr_print(FGx, ctx); flint_printf("\n"); + flint_abort(); + } + + gr_poly_clear(F, ctx); + gr_poly_clear(G, ctx); + gr_poly_clear(FG, ctx); + + gr_heap_clear(x, ctx); + gr_heap_clear(Fx, ctx); + gr_heap_clear(Gx, ctx); + gr_heap_clear(FxGx, ctx); + gr_heap_clear(FGx, ctx); + + gr_ctx_clear(ctx); + } + + flint_randclear(state); + flint_cleanup(); + flint_printf("PASS\n"); + return 0; +}