From a71fd144f4d7be5d88b4dfe8d4a082587173b270 Mon Sep 17 00:00:00 2001 From: Fredrik Johansson Date: Sat, 1 Feb 2025 11:55:46 +0100 Subject: [PATCH] Support gr objects in flint_printf (#2226) * Support gr objects in flint_printf --- doc/source/flint.rst | 42 ++++++++++++++++----- src/generic_files/io.c | 54 +++++++++++++++++++++++++++ src/gr.h | 10 ++--- src/gr/io.c | 85 +++++++++++++++++++++++++++--------------- src/gr_mat/write.c | 10 ++++- src/test/t-io.c | 79 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 231 insertions(+), 49 deletions(-) diff --git a/doc/source/flint.rst b/doc/source/flint.rst index 028eaf384d..2576357de6 100644 --- a/doc/source/flint.rst +++ b/doc/source/flint.rst @@ -251,16 +251,26 @@ Input/Output We currently support printing vectors of pointers to the following base types: :type:`slong`, :type:`ulong`, :type:`fmpz`, :type:`fmpq`, :type:`mag_struct`, :type:`arf_struct`, :type:`arb_struct` and - :type:`acb_struct`. + :type:`acb_struct`. In this case the nonnegative length of the vector + must be passed as a second parameter following the pointer. + Warning: the length parameter must be passed as a :type:`slong`, + not ``int``. We also support printing matrices of the following types: :type:`nmod_mat_t`, :type:`fmpz_mat_t`, :type:`fmpq_mat_t`, :type:`arb_mat_t` and :type:`acb_mat_t`. - Finally, we currently support printing polynomial of the following types: + We also support printing polynomial of the following types: :type:`nmod_poly_t`, :type:`fmpz_poly_t`, :type:`fmpq_poly_t`, :type:`arb_poly_t` and :type:`acb_poly_t`. + Finally, we support printing generic elements of type :type:`gr_ptr` + as well as :type:`gr_poly_t` and :type:`gr_mat_t`. For + each of these types, the object to be printed must be followed + by the corresponding :type:`gr_ctx_t`. The context object itself + can also printed as a standalone object. + + .. code-block:: c ulong bulong; @@ -275,6 +285,8 @@ Input/Output fmpz_mod_ctx_t bfmpz_mod_ctx; mpz_t bmpz; mpq_t bmpq; + gr_ctx_t bgr_ctx; + gr_ptr bgr; /* Initialize and set variables */ @@ -290,7 +302,9 @@ Input/Output "nmod: %{nmod}\n" "fmpz_mod_ctx: %{fmpz_mod_ctx}\n" "mpz: %{mpz}\n" - "mpq: %{mpq}\n", + "mpq: %{mpq}\n" + "gr: %{gr}\n", + "gr: %{gr_ctx}\n", bulong, bslong, bfmpz, @@ -302,7 +316,9 @@ Input/Output bnmod, bfmpz_mod_ctx, bmpz, - bmpq); + bmpq, + gr, bgr_ctx, + gr_ctx); .. code-block:: c @@ -315,6 +331,7 @@ Input/Output arf_ptr varf; slong varf_len; arb_ptr varb; slong varb_len; acb_ptr vacb; slong vacb_len; + gr_ptr vgr; slong vgr_len; gr_ctx_t vgr_ctx; /* Initialize and set variables */ @@ -327,6 +344,7 @@ Input/Output "arf vector: %{arf*}\n" "arb vector: %{arb*}\n" "acb vector: %{acb*}\n" + "gr vector: %{gr*}\n" vslong, vslong_len, /* They require a vector length specifier */ vnmod, vnmod_len, vfmpz, vfmpz_len, @@ -334,7 +352,8 @@ Input/Output vmag, vmag_len, varf, varf_len, varb, varb_len, - vacb, vacb_len); + vacb, vacb_len, + vgr, vgr_len, vgr_ctx); .. code-block:: c @@ -344,6 +363,7 @@ Input/Output fmpq_mat_t mfmpq; arb_mat_t marb; acb_mat_t macb; + gr_mat_t mgr; gr_ctx_t mgr_ctx; /* Initialize and set variables */ @@ -352,14 +372,16 @@ Input/Output "fmpz matrix: %{fmpz_mat}\n" "fmpz_mod matrix: %{fmpz_mod_mat}\n" "fmpq matrix: %{fmpq_mat}\n" - "arb vector: %{arb_mat}\n" - "acb vector: %{acb_mat}\n" + "arb matrix: %{arb_mat}\n" + "acb matrix: %{acb_mat}\n" + "gr matrix: %{gr_mat}\n" mnmod, mfmpz, mfmpz_mod, mfmpq, marb, - macb); + macb, + mgr, mgr_ctx); .. code-block:: c @@ -369,6 +391,7 @@ Input/Output fmpq_poly_t pfmpq; arb_poly_t parb; acb_poly_t pacb; + gr_poly_t pgr; gr_ctx_t pgr_ctx; /* Initialize and set variables */ @@ -384,7 +407,8 @@ Input/Output pfmpz_mod, pfmpq, parb, - pacb); + pacb, + pgr, pgr_ctx); .. note:: diff --git a/src/generic_files/io.c b/src/generic_files/io.c index 401248cf5a..f680ddc2d6 100644 --- a/src/generic_files/io.c +++ b/src/generic_files/io.c @@ -23,6 +23,12 @@ #include "arf_types.h" #include "arb.h" #include "acb.h" +#include "gr.h" +#include "gr_vec.h" +#include "gr_poly.h" +#include "gr_mat.h" + +int _gr_mat_write(gr_stream_t out, const gr_mat_t mat, int linebreaks, gr_ctx_t ctx); /* Helper functions **********************************************************/ @@ -692,6 +698,54 @@ int flint_vfprintf(FILE * fs, const char * ip, va_list vlist) res += __mpq_fprint(fs, va_arg(vlist, mpq_srcptr)); ip += STRING_LENGTH("mpq}"); } + else if (IS_FLINT_BASE_TYPE(ip, "gr")) + { + gr_stream_t out; + gr_stream_init_file(out, fs); + + if (IS_FLINT_TYPE(ip, "gr")) + { + gr_srcptr elem = va_arg(vlist, gr_srcptr); + gr_ctx_struct * ctx = va_arg(vlist, gr_ctx_struct *); + GR_MUST_SUCCEED(gr_write(out, elem, ctx)); + res += out->len; + ip += STRING_LENGTH("gr}"); + } + else if (IS_FLINT_TYPE(ip, "gr*")) + { + gr_srcptr elem = va_arg(vlist, gr_srcptr); + slong len = va_arg(vlist, slong); + gr_ctx_struct * ctx = va_arg(vlist, gr_ctx_struct *); + GR_MUST_SUCCEED(_gr_vec_write(out, elem, len, ctx)); + res += out->len; + ip += STRING_LENGTH("gr*}"); + } + else if (IS_FLINT_TYPE(ip, "gr_poly")) + { + const gr_poly_struct * elem = va_arg(vlist, const gr_poly_struct *); + gr_ctx_struct * ctx = va_arg(vlist, gr_ctx_struct *); + GR_MUST_SUCCEED(gr_poly_write(out, elem, "x", ctx)); + res += out->len; + ip += STRING_LENGTH("gr_poly}"); + } + else if (IS_FLINT_TYPE(ip, "gr_mat")) + { + const gr_mat_struct * elem = va_arg(vlist, const gr_mat_struct *); + gr_ctx_struct * ctx = va_arg(vlist, gr_ctx_struct *); + GR_MUST_SUCCEED(_gr_mat_write(out, elem, 0, ctx)); + res += out->len; + ip += STRING_LENGTH("gr_mat}"); + } + else if (IS_FLINT_TYPE(ip, "gr_ctx")) + { + gr_ctx_struct * ctx = va_arg(vlist, gr_ctx_struct *); + GR_MUST_SUCCEED(gr_ctx_write(out, ctx)); + res += out->len; + ip += STRING_LENGTH("gr_ctx}"); + } + else + goto printpercentcurlybracket; + } else { printpercentcurlybracket: diff --git a/src/gr.h b/src/gr.h index 22920272e1..cdf57ac9c8 100644 --- a/src/gr.h +++ b/src/gr.h @@ -63,11 +63,11 @@ void gr_stream_init_file(gr_stream_t out, FILE * fp); #endif void gr_stream_init_str(gr_stream_t out); -void gr_stream_write(gr_stream_t out, const char * s); -void gr_stream_write_si(gr_stream_t out, slong x); -void gr_stream_write_ui(gr_stream_t out, ulong x); -void gr_stream_write_free(gr_stream_t out, char * s); -void gr_stream_write_fmpz(gr_stream_t out, const fmpz_t x); +int gr_stream_write(gr_stream_t out, const char * s); +int gr_stream_write_si(gr_stream_t out, slong x); +int gr_stream_write_ui(gr_stream_t out, ulong x); +int gr_stream_write_free(gr_stream_t out, char * s); +int gr_stream_write_fmpz(gr_stream_t out, const fmpz_t x); #define GR_MUST_SUCCEED(expr) do { if ((expr) != GR_SUCCESS) { flint_throw(FLINT_ERROR, "GR_MUST_SUCCEED failure: %s", __FILE__); } } while (0) #define GR_IGNORE(expr) do { int ___unused = (expr); (void) ___unused; } while (0) diff --git a/src/gr/io.c b/src/gr/io.c index 13b62e8640..4990c8f731 100644 --- a/src/gr/io.c +++ b/src/gr/io.c @@ -20,6 +20,8 @@ void gr_stream_init_file(gr_stream_t out, FILE * fp) { out->fp = (FLINT_FILE *) fp; out->s = NULL; + out->len = 0; + out->alloc = 0; } void gr_stream_init_str(gr_stream_t out) @@ -31,16 +33,21 @@ void gr_stream_init_str(gr_stream_t out) out->alloc = 16; } -void gr_stream_write(gr_stream_t out, const char * s) +int gr_stream_write(gr_stream_t out, const char * s) { + slong len, alloc; + if (out->fp != NULL) { - fprintf((FILE *) out->fp, "%s", s); + len = fprintf((FILE *) out->fp, "%s", s); + + if (len < 0) + return GR_UNABLE; + + out->len += len; } else { - slong len, alloc; - len = strlen(s); alloc = out->len + len + 1; @@ -54,49 +61,64 @@ void gr_stream_write(gr_stream_t out, const char * s) memcpy(out->s + out->len, s, len + 1); out->len += len; } + + return GR_SUCCESS; } -void +int gr_stream_write_si(gr_stream_t out, slong x) { if (out->fp != NULL) { - flint_fprintf((FILE *) out->fp, "%wd", x); + slong len = flint_fprintf((FILE *) out->fp, "%wd", x); + + if (len < 0) + return GR_UNABLE; + + out->len += len; + return GR_SUCCESS; } else { char tmp[22]; sprintf(tmp, WORD_FMT "d", x); - gr_stream_write(out, tmp); + return gr_stream_write(out, tmp); } } -void +int gr_stream_write_ui(gr_stream_t out, ulong x) { if (out->fp != NULL) { - flint_fprintf((FILE *) out->fp, "%wu", x); + slong len = flint_fprintf((FILE *) out->fp, "%wu", x); + + if (len < 0) + return GR_UNABLE; + + out->len += len; + return GR_SUCCESS; } else { char tmp[22]; sprintf(tmp, WORD_FMT "u", x); - gr_stream_write(out, tmp); + return gr_stream_write(out, tmp); } } -void +int gr_stream_write_free(gr_stream_t out, char * s) { - gr_stream_write(out, s); + int status = gr_stream_write(out, s); flint_free(s); + return status; } -void +int gr_stream_write_fmpz(gr_stream_t out, const fmpz_t x) { - gr_stream_write_free(out, fmpz_get_str(NULL, 10, x)); + return gr_stream_write_free(out, fmpz_get_str(NULL, 10, x)); } int @@ -104,18 +126,18 @@ gr_ctx_print(gr_ctx_t ctx) { gr_stream_t out; gr_stream_init_file(out, stdout); - gr_ctx_write(out, ctx); - return GR_SUCCESS; + return gr_ctx_write(out, ctx); } int gr_ctx_println(gr_ctx_t ctx) { gr_stream_t out; + int status; gr_stream_init_file(out, stdout); - gr_ctx_write(out, ctx); - gr_stream_write(out, "\n"); - return GR_SUCCESS; + status = gr_ctx_write(out, ctx); + status |= gr_stream_write(out, "\n"); + return status; } int @@ -123,46 +145,49 @@ gr_print(gr_srcptr x, gr_ctx_t ctx) { gr_stream_t out; gr_stream_init_file(out, stdout); - gr_write(out, x, ctx); - return GR_SUCCESS; + return gr_write(out, x, ctx); } int gr_println(gr_srcptr x, gr_ctx_t ctx) { gr_stream_t out; + int status; gr_stream_init_file(out, stdout); - gr_write(out, x, ctx); - gr_stream_write(out, "\n"); - return GR_SUCCESS; + status = gr_write(out, x, ctx); + status |= gr_stream_write(out, "\n"); + return status; } int gr_ctx_get_str(char ** s, gr_ctx_t ctx) { gr_stream_t out; + int status; gr_stream_init_str(out); - gr_ctx_write(out, ctx); + status = gr_ctx_write(out, ctx); *s = out->s; - return GR_SUCCESS; + return status; } int gr_get_str(char ** s, gr_srcptr x, gr_ctx_t ctx) { gr_stream_t out; + int status; gr_stream_init_str(out); - gr_write(out, x, ctx); + status = gr_write(out, x, ctx); *s = out->s; - return GR_SUCCESS; + return status; } int gr_get_str_n(char ** s, gr_srcptr x, slong n, gr_ctx_t ctx) { gr_stream_t out; + int status; gr_stream_init_str(out); - gr_write_n(out, x, n, ctx); + status = gr_write_n(out, x, n, ctx); *s = out->s; - return GR_SUCCESS; + return status; } diff --git a/src/gr_mat/write.c b/src/gr_mat/write.c index 2682e6846a..ca156fd451 100644 --- a/src/gr_mat/write.c +++ b/src/gr_mat/write.c @@ -13,7 +13,7 @@ #include "gr_mat.h" int -gr_mat_write(gr_stream_t out, const gr_mat_t mat, gr_ctx_t ctx) +_gr_mat_write(gr_stream_t out, const gr_mat_t mat, int linebreaks, gr_ctx_t ctx) { int status; slong r, c; @@ -39,10 +39,16 @@ gr_mat_write(gr_stream_t out, const gr_mat_t mat, gr_ctx_t ctx) } if (i < r - 1) - gr_stream_write(out, "],\n"); + gr_stream_write(out, linebreaks ? "],\n" : "], "); else gr_stream_write(out, "]"); } gr_stream_write(out, "]"); return status; } + +int +gr_mat_write(gr_stream_t out, const gr_mat_t mat, gr_ctx_t ctx) +{ + return _gr_mat_write(out, mat, 1, ctx); +} diff --git a/src/test/t-io.c b/src/test/t-io.c index c76ffcdd8d..e0282ad48f 100644 --- a/src/test/t-io.c +++ b/src/test/t-io.c @@ -35,6 +35,10 @@ #include "fmpq_poly.h" #include "arb_poly.h" #include "acb_poly.h" +#include "gr.h" +#include "gr_vec.h" +#include "gr_poly.h" +#include "gr_mat.h" #define STR(x) TEMPLATE_STR(x) @@ -425,6 +429,37 @@ do \ } while (0) #define ACB_POLY_STRING "([-1e+1 +/- 3.11] - i) * x^3 + x^2 - x" +/* Generics */ + +#define MY_GR_CTX_INIT(xgr_ctx) gr_ctx_init_fmpzi(xgr_ctx) +#define MY_GR_INIT(xgr, xgr_ctx) xgr = gr_heap_init(xgr_ctx) +#define MY_GR_VEC_INIT(xgr_vec, xgr_ctx) xgr_vec = gr_heap_init_vec(GR_VEC_LEN, xgr_ctx) +#define MY_GR_POLY_INIT(xgr_poly, xgr_ctx) gr_poly_init(xgr_poly, xgr_ctx) +#define MY_GR_MAT_INIT(xgr_mat, xgr_ctx) gr_mat_init(xgr_mat, 1, 2, xgr_ctx) + +#define MY_GR_SET(xgr, xgr_ctx) GR_IGNORE(gr_set_ui(xgr, 5, xgr_ctx)) +#define MY_GR_VEC_SET(xgr_vec, xgr_ctx) \ + GR_IGNORE(gr_set_ui(GR_ENTRY(xgr_vec, 0, xgr_ctx->sizeof_elem), 1, xgr_ctx)); \ + GR_IGNORE(gr_set_ui(GR_ENTRY(xgr_vec, 1, xgr_ctx->sizeof_elem), 2, xgr_ctx)); \ + GR_IGNORE(gr_set_str(GR_ENTRY(xgr_vec, 2, xgr_ctx->sizeof_elem), "I", xgr_ctx)); +#define MY_GR_POLY_SET(xgr_poly, xgr_ctx) GR_IGNORE(gr_poly_set_coeff_si(xgr_poly, 1, -1, xgr_ctx)) +#define MY_GR_MAT_SET(xgr_mat, xgr_ctx) \ + GR_IGNORE(gr_set_ui(gr_mat_entry_ptr(xgr_mat, 0, 0, xgr_ctx), 4, xgr_ctx)); \ + GR_IGNORE(gr_set_ui(gr_mat_entry_ptr(xgr_mat, 0, 1, xgr_ctx), 3, xgr_ctx)) + +#define MY_GR_CLEAR(xgr, xgr_ctx) gr_heap_clear(xgr, xgr_ctx) +#define MY_GR_VEC_CLEAR(xgr_vec, GR_VEC_LEN, xgr_ctx) gr_heap_clear_vec(xgr_vec, GR_VEC_LEN, xgr_ctx) +#define MY_GR_POLY_CLEAR(xgr_poly, xgr_ctx) gr_poly_clear(xgr_poly, xgr_ctx) +#define MY_GR_MAT_CLEAR(xgr_mat, xgr_ctx) gr_mat_clear(xgr_mat, xgr_ctx) +#define MY_GR_CTX_CLEAR(xgr_ctx) gr_ctx_clear(xgr_ctx) + +#define GR_VEC_LEN WORD(3) +#define GR_STRING "5" +#define GR_VEC_STRING "[1, 2, I]" +#define GR_POLY_STRING "-x" +#define GR_MAT_STRING "[[4, 3]]" +#define GR_CTX_STRING "Gaussian integer ring (fmpzi)" + #define TMP_FILENAME "tmp" TEST_FUNCTION_START(flint_fprintf, state) @@ -474,6 +509,12 @@ TEST_FUNCTION_START(flint_fprintf, state) arb_ptr xarb_vec; acb_ptr xacb_vec; + gr_ctx_t xgr_ctx; + gr_ptr xgr; + gr_ptr xgr_vec; + gr_poly_t xgr_poly; + gr_mat_t xgr_mat; + /* Matrix printing relies on vector printing, so no need to check other * types */ fmpz_mat_t empty_matrix; @@ -539,6 +580,12 @@ TEST_FUNCTION_START(flint_fprintf, state) ARB_POLY_INIT(xarb_poly); ACB_POLY_INIT(xacb_poly); + MY_GR_CTX_INIT(xgr_ctx); + MY_GR_INIT(xgr, xgr_ctx); + MY_GR_VEC_INIT(xgr_vec, xgr_ctx); + MY_GR_POLY_INIT(xgr_poly, xgr_ctx); + MY_GR_MAT_INIT(xgr_mat, xgr_ctx); + /* Set *******************************************************************/ NMOD_SET(xnmod); FMPZ1_SET(xfmpz1); @@ -589,6 +636,11 @@ TEST_FUNCTION_START(flint_fprintf, state) FMPQ_POLY2_SET(xfmpq_poly2); ARB_POLY_SET(xarb_poly); ACB_POLY_SET(xacb_poly); + + MY_GR_SET(xgr, xgr_ctx); + MY_GR_VEC_SET(xgr_vec, xgr_ctx); + MY_GR_POLY_SET(xgr_poly, xgr_ctx); + MY_GR_MAT_SET(xgr_mat, xgr_ctx); /* Print *****************************************************************/ #define STR_SIZE 10000 /* 10 kB should suffice. */ @@ -693,7 +745,12 @@ TEST_FUNCTION_START(flint_fprintf, state) "fmpq_poly (1): " FMPQ_POLY1_STRING "\n" "fmpq_poly (2): " FMPQ_POLY2_STRING "\n" "arb_poly: " ARB_POLY_STRING "\n" - "acb_poly: " ACB_POLY_STRING "\n", + "acb_poly: " ACB_POLY_STRING "\n" + "gr: " GR_STRING "\n" + "gr_vec: " GR_VEC_STRING "\n" + "gr_poly: " GR_POLY_STRING "\n" + "gr_mat: " GR_MAT_STRING "\n" + "gr_ctx: " GR_CTX_STRING "\n", xulong1, xslong, xulong2, @@ -814,7 +871,12 @@ TEST_FUNCTION_START(flint_fprintf, state) "fmpq_poly (1): %{fmpq_poly}\n" "fmpq_poly (2): %{fmpq_poly}\n" "arb_poly: %{arb_poly}\n" - "acb_poly: %{acb_poly}\n", + "acb_poly: %{acb_poly}\n" + "gr: %{gr}\n" + "gr_vec: %{gr*}\n" + "gr_poly: %{gr_poly}\n" + "gr_mat: %{gr_mat}\n" + "gr_ctx: %{gr_ctx}\n", xulong1, xslong, xulong2, @@ -880,7 +942,12 @@ TEST_FUNCTION_START(flint_fprintf, state) xfmpq_poly1, xfmpq_poly2, xarb_poly, - xacb_poly); + xacb_poly, + xgr, xgr_ctx, + xgr_vec, GR_VEC_LEN, xgr_ctx, + xgr_poly, xgr_ctx, + xgr_mat, xgr_ctx, + xgr_ctx); if (res2 > STR_SIZE - 1) TEST_FUNCTION_FAIL( @@ -1037,6 +1104,12 @@ TEST_FUNCTION_START(flint_fprintf, state) FMPQ_POLY2_CLEAR(xfmpq_poly2); ARB_POLY_CLEAR(xarb_poly); ACB_POLY_CLEAR(xacb_poly); + + MY_GR_CLEAR(xgr, xgr_ctx); + MY_GR_VEC_CLEAR(xgr_vec, GR_VEC_LEN, xgr_ctx); + MY_GR_POLY_CLEAR(xgr_poly, xgr_ctx); + MY_GR_MAT_CLEAR(xgr_mat, xgr_ctx); + MY_GR_CTX_CLEAR(xgr_ctx); } fs = freopen(TMP_FILENAME, "w+", fs);