diff --git a/doc/source/fmpz_mpoly_q.rst b/doc/source/fmpz_mpoly_q.rst
index 727deb5dcc..44211a0077 100644
--- a/doc/source/fmpz_mpoly_q.rst
+++ b/doc/source/fmpz_mpoly_q.rst
@@ -121,11 +121,24 @@ Special values
Input and output
-------------------------------------------------------------------------------
+The variable strings in *x* start with the variable of most significance at index `0`. If *x* is ``NULL``, the variables are named ``x1``, ``x2``, etc.
+
.. function:: void fmpz_mpoly_q_print_pretty(const fmpz_mpoly_q_t f, const char ** x, const fmpz_mpoly_ctx_t ctx)
Prints *res* to standard output. If *x* is not *NULL*, the strings in
*x* are used as the symbols for the variables.
+.. function:: char * fmpz_mpoly_q_get_str_pretty(const fmpz_mpoly_q_t f, const char ** x, const fmpz_mpoly_ctx_t ctx)
+
+ Return a string, which the user is responsible for cleaning up, representing *f*, given an array of variable strings *x*.
+
+.. function:: int fmpz_mpoly_q_set_str_pretty(fmpz_mpoly_q_t res, const char * s, const char ** x, fmpz_mpoly_ctx_t ctx)
+
+ Set *res* to the fraction in the null-terminated string *str* given an array *x* of variable strings.
+ If parsing *str* fails, *res* is set to zero, and `-1` is returned. Otherwise, `0` is returned.
+ The operations ``+``, ``-``, ``*``, and ``/`` are permitted along with integers and the variables in *x*.
+ The character ``^`` must be immediately followed by the (integer) exponent.
+ If division by zero occurs, parsing fails.
Random generation
-------------------------------------------------------------------------------
diff --git a/doc/source/gr_generic.rst b/doc/source/gr_generic.rst
index 41995a3b61..16c414d6b7 100644
--- a/doc/source/gr_generic.rst
+++ b/doc/source/gr_generic.rst
@@ -39,6 +39,30 @@
.. function:: int gr_generic_set_other(gr_ptr res, gr_srcptr x, gr_ctx_t xctx, gr_ctx_t ctx)
int gr_generic_set_fmpq(gr_ptr res, const fmpq_t y, gr_ctx_t ctx)
+Generic string parsing
+-----------------------------------------------------------------------------------------
+
+.. macro :: GR_PARSE_BALANCE_ADDITIONS
+
+.. macro :: GR_PARSE_RING_EXPONENTS
+
+.. function:: int gr_generic_set_str_expr(gr_ptr res, const char * s, int flags, gr_ctx_t ctx)
+ int gr_generic_set_str(gr_ptr res, const char * s, gr_ctx_t ctx)
+ int gr_generic_set_str_balance_additions(gr_ptr res, const char * s, gr_ctx_t ctx)
+ int gr_generic_set_str_ring_exponents(gr_ptr res, const char * s, gr_ctx_t ctx)
+
+ Parses expression string. Generators returned by :func:`gr_gens_recursive` are handled
+ automatically. We have the following flags:
+
+ * ``GR_PARSE_RING_EXPONENTS`` - by default, only (nonnegative) integer literals are allowed
+ for exponents. If this flag is set, exponents are parsed as arbitrary subexpressions
+ within the same ring.
+ * ``GR_PARSE_BALANCE_ADDITIONS`` - attempt to improve performance for huge sums
+ by reording additions (useful for polynomials)
+
+Generic arithmetic
+-----------------------------------------------------------------------------------------
+
.. function:: int gr_generic_add_fmpz(gr_ptr res, gr_srcptr x, const fmpz_t y, gr_ctx_t ctx)
int gr_generic_add_ui(gr_ptr res, gr_srcptr x, ulong y, gr_ctx_t ctx)
int gr_generic_add_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx)
diff --git a/doc/source/nmod_poly.rst b/doc/source/nmod_poly.rst
index 40a108b4cc..d528e90394 100644
--- a/doc/source/nmod_poly.rst
+++ b/doc/source/nmod_poly.rst
@@ -2310,6 +2310,7 @@ Special polynomials
:func:`_nmod_poly_conway` will always succeed.
Here, ``type`` can be the following values:
+
* ``0`` for which there is a bijection between the image of this function
and the database of Conway polynomials,
* ``1`` returns a random prime found in the database and sets ``degree`` to
diff --git a/src/fmpz_mpoly_q.h b/src/fmpz_mpoly_q.h
index a8405ed324..9a701ae43e 100644
--- a/src/fmpz_mpoly_q.h
+++ b/src/fmpz_mpoly_q.h
@@ -112,6 +112,8 @@ fmpz_mpoly_q_gen(fmpz_mpoly_q_t res, slong i, const fmpz_mpoly_ctx_t ctx)
/* Input and output */
void fmpz_mpoly_q_print_pretty(const fmpz_mpoly_q_t f, const char ** x, const fmpz_mpoly_ctx_t ctx);
+char * fmpz_mpoly_q_get_str_pretty(const fmpz_mpoly_q_t f, const char ** vars, const fmpz_mpoly_ctx_t ctx);
+int fmpz_mpoly_q_set_str_pretty(fmpz_mpoly_q_t res, const char * s, const char ** vars, fmpz_mpoly_ctx_t ctx);
/* Random generation */
diff --git a/src/fmpz_mpoly_q/print_pretty.c b/src/fmpz_mpoly_q/print_pretty.c
index 0486b1af0d..d7f439f634 100644
--- a/src/fmpz_mpoly_q/print_pretty.c
+++ b/src/fmpz_mpoly_q/print_pretty.c
@@ -10,6 +10,7 @@
*/
#include "fmpz_mpoly_q.h"
+#include "gr.h"
void
fmpz_mpoly_q_print_pretty(const fmpz_mpoly_q_t f, const char ** x, const fmpz_mpoly_ctx_t ctx)
@@ -34,3 +35,32 @@ fmpz_mpoly_q_print_pretty(const fmpz_mpoly_q_t f, const char ** x, const fmpz_mp
flint_printf(")");
}
}
+
+char * fmpz_mpoly_q_get_str_pretty(const fmpz_mpoly_q_t f, const char ** vars, const fmpz_mpoly_ctx_t ctx)
+{
+ gr_ctx_t grctx;
+ char * s;
+
+ gr_ctx_init_fmpz_mpoly_q(grctx, ctx->minfo->nvars, ctx->minfo->ord);
+ if (vars != NULL)
+ GR_MUST_SUCCEED(gr_ctx_set_gen_names(grctx, vars));
+ GR_MUST_SUCCEED(gr_get_str(&s, f, grctx));
+ gr_ctx_clear(grctx);
+
+ return s;
+}
+
+int
+fmpz_mpoly_q_set_str_pretty(fmpz_mpoly_q_t res, const char * s, const char ** vars, fmpz_mpoly_ctx_t ctx)
+{
+ gr_ctx_t grctx;
+ int ret;
+
+ gr_ctx_init_fmpz_mpoly_q(grctx, ctx->minfo->nvars, ctx->minfo->ord);
+ if (vars != NULL)
+ GR_MUST_SUCCEED(gr_ctx_set_gen_names(grctx, vars));
+ ret = (GR_SUCCESS == gr_set_str(res, s, grctx)) ? 0 : -1;
+
+ gr_ctx_clear(grctx);
+ return ret;
+}
diff --git a/src/fmpz_mpoly_q/test/main.c b/src/fmpz_mpoly_q/test/main.c
index f07bb2afde..651381bfad 100644
--- a/src/fmpz_mpoly_q/test/main.c
+++ b/src/fmpz_mpoly_q/test/main.c
@@ -20,6 +20,7 @@
#include "t-div.c"
#include "t-div_fmpq.c"
#include "t-div_fmpz.c"
+#include "t-get_set_str.c"
#include "t-inv.c"
#include "t-mul.c"
#include "t-mul_fmpq.c"
@@ -39,6 +40,7 @@ test_struct tests[] =
TEST_FUNCTION(fmpz_mpoly_q_div),
TEST_FUNCTION(fmpz_mpoly_q_div_fmpq),
TEST_FUNCTION(fmpz_mpoly_q_div_fmpz),
+ TEST_FUNCTION(fmpz_mpoly_q_get_set_str),
TEST_FUNCTION(fmpz_mpoly_q_inv),
TEST_FUNCTION(fmpz_mpoly_q_mul),
TEST_FUNCTION(fmpz_mpoly_q_mul_fmpq),
diff --git a/src/fmpz_mpoly_q/test/t-get_set_str.c b/src/fmpz_mpoly_q/test/t-get_set_str.c
new file mode 100644
index 0000000000..6585b8d1a4
--- /dev/null
+++ b/src/fmpz_mpoly_q/test/t-get_set_str.c
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2024 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 "test_helpers.h"
+#include "fmpz_mpoly_q.h"
+
+TEST_FUNCTION_START(fmpz_mpoly_q_get_set_str, state)
+{
+ slong iter;
+
+ for (iter = 0; iter < 1000 * 0.1 * flint_test_multiplier(); iter++)
+ {
+ fmpz_mpoly_ctx_t ctx;
+ fmpz_mpoly_q_t A, B;
+ char * s;
+ char * vars[] = { "x", "y", "z", "t", "u" };
+ int use_vars, ok;
+
+ fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX);
+ fmpz_mpoly_q_init(A, ctx);
+ fmpz_mpoly_q_init(B, ctx);
+
+ fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx);
+ fmpz_mpoly_q_randtest(B, state, 10, 2 + n_randint(state, 100), 5, ctx);
+ use_vars = n_randint(state, 2);
+
+ s = fmpz_mpoly_q_get_str_pretty(A, use_vars ? (const char **) vars : NULL, ctx);
+ ok = !fmpz_mpoly_q_set_str_pretty(B, s, use_vars ? (const char **) vars : NULL, ctx);
+ ok = ok && fmpz_mpoly_q_equal(A, B, ctx);
+
+ if (!ok)
+ {
+ flint_printf("FAIL\n");
+ flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n");
+ flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n");
+ flint_abort();
+ }
+
+ flint_free(s);
+ fmpz_mpoly_q_clear(A, ctx);
+ fmpz_mpoly_q_clear(B, ctx);
+ fmpz_mpoly_ctx_clear(ctx);
+ }
+
+ TEST_FUNCTION_END(state);
+}
diff --git a/src/gr.h b/src/gr.h
index 0fe0f3b4b7..c7889d3803 100644
--- a/src/gr.h
+++ b/src/gr.h
@@ -167,6 +167,8 @@ typedef enum
GR_METHOD_WRITE,
GR_METHOD_WRITE_N,
+ _GR_METHOD_LENGTH,
+
GR_METHOD_RANDTEST,
GR_METHOD_RANDTEST_NOT_ZERO,
GR_METHOD_RANDTEST_SMALL,
@@ -851,6 +853,7 @@ typedef int ((*gr_method_poly_binary_op)(gr_ptr, gr_srcptr, slong, gr_srcptr, sl
typedef int ((*gr_method_poly_binary_binary_op)(gr_ptr, gr_ptr, gr_srcptr, slong, gr_srcptr, slong, gr_ctx_ptr));
typedef int ((*gr_method_poly_binary_trunc_op)(gr_ptr, gr_srcptr, slong, gr_srcptr, slong, slong, gr_ctx_ptr));
typedef int ((*gr_method_vec_ctx_op)(gr_vec_t, gr_ctx_ptr));
+typedef slong ((*_gr_method_get_si_op)(gr_srcptr, gr_ctx_ptr));
#ifdef FEXPR_H
typedef int ((*gr_method_get_fexpr_op)(fexpr_t, gr_srcptr, gr_ctx_ptr));
@@ -945,6 +948,7 @@ typedef int ((*gr_method_set_fexpr_op)(gr_ptr, fexpr_vec_t, gr_vec_t, const fexp
#define GR_POLY_BINARY_BINARY_OP(ctx, NAME) (((gr_method_poly_binary_binary_op *) ctx->methods)[GR_METHOD_ ## NAME])
#define GR_POLY_BINARY_TRUNC_OP(ctx, NAME) (((gr_method_poly_binary_trunc_op *) ctx->methods)[GR_METHOD_ ## NAME])
#define GR_VEC_CTX_OP(ctx, NAME) (((gr_method_vec_ctx_op *) ctx->methods)[GR_METHOD_ ## NAME])
+#define _GR_GET_SI_OP(ctx, NAME) (((_gr_method_get_si_op *) ctx->methods)[_GR_METHOD_ ## NAME])
#ifdef FEXPR_H
#define GR_GET_FEXPR_OP(ctx, NAME) (((gr_method_get_fexpr_op *) ctx->methods)[GR_METHOD_ ## NAME])
#define GR_SET_FEXPR_OP(ctx, NAME) (((gr_method_set_fexpr_op *) ctx->methods)[GR_METHOD_ ## NAME])
@@ -993,6 +997,8 @@ GR_INLINE void gr_clear(gr_ptr res, gr_ctx_t ctx) { GR_INIT_CLEAR_OP(ctx, CLEAR)
GR_INLINE void gr_swap(gr_ptr x, gr_ptr y, gr_ctx_t ctx) { GR_SWAP_OP(ctx, SWAP)(x, y, ctx); }
GR_INLINE void gr_set_shallow(gr_ptr res, gr_srcptr x, gr_ctx_t ctx) { GR_VOID_UNARY_OP(ctx, SET_SHALLOW)(res, x, ctx); }
+GR_INLINE void _gr_length(gr_srcptr x, gr_ctx_t ctx) { _GR_GET_SI_OP(ctx, LENGTH)(x, ctx); }
+
GR_INLINE WARN_UNUSED_RESULT int gr_randtest(gr_ptr x, flint_rand_t state, gr_ctx_t ctx) { return GR_RANDTEST(ctx, RANDTEST)(x, state, ctx); }
GR_INLINE WARN_UNUSED_RESULT int gr_randtest_not_zero(gr_ptr x, flint_rand_t state, gr_ctx_t ctx) { return GR_RANDTEST(ctx, RANDTEST_NOT_ZERO)(x, state, ctx); }
GR_INLINE WARN_UNUSED_RESULT int gr_randtest_small(gr_ptr x, flint_rand_t state, gr_ctx_t ctx) { return GR_RANDTEST(ctx, RANDTEST_SMALL)(x, state, ctx); }
diff --git a/src/gr/acb.c b/src/gr/acb.c
index c6eacd575c..b317a6cfce 100644
--- a/src/gr/acb.c
+++ b/src/gr/acb.c
@@ -2026,6 +2026,7 @@ gr_method_tab_input _acb_methods_input[] =
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_acb_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) _gr_acb_set_fmpq},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_acb_set_other},
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_ring_exponents},
{GR_METHOD_SET_D, (gr_funcptr) _gr_acb_set_d},
{GR_METHOD_GET_SI, (gr_funcptr) _gr_acb_get_si},
{GR_METHOD_GET_UI, (gr_funcptr) _gr_acb_get_ui},
diff --git a/src/gr/acf.c b/src/gr/acf.c
index 1425f81cd4..93b95dc4d0 100644
--- a/src/gr/acf.c
+++ b/src/gr/acf.c
@@ -1182,7 +1182,7 @@ gr_method_tab_input _acf_methods_input[] =
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_acf_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) _gr_acf_set_fmpq},
{GR_METHOD_SET_D, (gr_funcptr) _gr_acf_set_d},
-/* {GR_METHOD_SET_STR, (gr_funcptr) _gr_acf_set_str}, */
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_ring_exponents},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_acf_set_other},
{GR_METHOD_GET_FMPZ, (gr_funcptr) _gr_acf_get_fmpz},
diff --git a/src/gr/arb.c b/src/gr/arb.c
index 1cd3e1233c..97c44aea23 100644
--- a/src/gr/arb.c
+++ b/src/gr/arb.c
@@ -151,12 +151,12 @@ _gr_arb_set_fmpq(arb_t res, const fmpq_t v, const gr_ctx_t ctx)
}
int
-_gr_arb_set_str(arb_t res, const char * x, const gr_ctx_t ctx)
+_gr_arb_set_str(arb_t res, const char * x, gr_ctx_t ctx)
{
- if (arb_set_str(res, x, ARB_CTX_PREC(ctx)))
- return GR_DOMAIN;
+ if (!arb_set_str(res, x, ARB_CTX_PREC(ctx)))
+ return GR_SUCCESS;
- return GR_SUCCESS;
+ return gr_generic_set_str_ring_exponents(res, x, ctx);
}
int
diff --git a/src/gr/arf.c b/src/gr/arf.c
index c509dcf131..6a9bde1d8c 100644
--- a/src/gr/arf.c
+++ b/src/gr/arf.c
@@ -16,6 +16,7 @@
#include "gr.h"
#include "gr_vec.h"
#include "gr_poly.h"
+#include "gr_generic.h"
typedef struct
{
@@ -152,14 +153,25 @@ _gr_arf_set(arf_t res, const arf_t x, const gr_ctx_t ctx)
}
int
-_gr_arf_set_str(arf_t res, const char * x, const gr_ctx_t ctx)
+_gr_arf_set_str(arf_t res, const char * x, gr_ctx_t ctx)
{
+ int status;
+
arb_t t;
arb_init(t);
- arb_set_str(t, x, ARF_CTX_PREC(ctx) + 20);
- arf_set_round(res, arb_midref(t), ARF_CTX_PREC(ctx), ARF_CTX_RND(ctx));
+
+ if (!arb_set_str(t, x, ARF_CTX_PREC(ctx) + 20))
+ {
+ arf_set_round(res, arb_midref(t), ARF_CTX_PREC(ctx), ARF_CTX_RND(ctx));
+ status = GR_SUCCESS;
+ }
+ else
+ {
+ status = gr_generic_set_str_ring_exponents(res, x, ctx);
+ }
+
arb_clear(t);
- return GR_SUCCESS;
+ return status;
}
diff --git a/src/gr/ca.c b/src/gr/ca.c
index 3a5a508fa3..10854bf0fa 100644
--- a/src/gr/ca.c
+++ b/src/gr/ca.c
@@ -1689,6 +1689,7 @@ gr_method_tab_input _ca_methods_input[] =
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_ca_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) _gr_ca_set_fmpq},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_ca_set_other},
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_ring_exponents},
{GR_METHOD_GET_SI, (gr_funcptr) _gr_ca_get_si},
{GR_METHOD_GET_UI, (gr_funcptr) _gr_ca_get_ui},
diff --git a/src/gr/fmpq_poly.c b/src/gr/fmpq_poly.c
index c2bf1c6c11..467fd51138 100644
--- a/src/gr/fmpq_poly.c
+++ b/src/gr/fmpq_poly.c
@@ -696,7 +696,7 @@ gr_method_tab_input _fmpq_poly_methods_input[] =
{GR_METHOD_SET_UI, (gr_funcptr) _gr_fmpq_poly_set_ui},
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_fmpq_poly_set_fmpz},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_fmpq_poly_set_other},
-/* {GR_METHOD_SET_STR, (gr_funcptr) _gr_fmpq_poly_set_str}, */
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_balance_additions},
{GR_METHOD_GET_UI, (gr_funcptr) _gr_fmpq_poly_get_ui},
{GR_METHOD_GET_SI, (gr_funcptr) _gr_fmpq_poly_get_si},
{GR_METHOD_GET_FMPZ, (gr_funcptr) _gr_fmpq_poly_get_fmpz},
diff --git a/src/gr/fmpz.c b/src/gr/fmpz.c
index 90079804fa..80ec5dbb1c 100644
--- a/src/gr/fmpz.c
+++ b/src/gr/fmpz.c
@@ -169,12 +169,12 @@ _gr_fmpz_set_other(fmpz_t res, gr_srcptr x, gr_ctx_t x_ctx, gr_ctx_t ctx)
}
int
-_gr_fmpz_set_str(fmpz_t res, const char * x, const gr_ctx_t ctx)
+_gr_fmpz_set_str(fmpz_t res, const char * x, gr_ctx_t ctx)
{
- if (fmpz_set_str(res, x, 10))
- return GR_DOMAIN;
+ if (!fmpz_set_str(res, x, 10))
+ return GR_SUCCESS;
- return GR_SUCCESS;
+ return gr_generic_set_str(res, x, ctx);
}
int
diff --git a/src/gr/fmpz_mpoly.c b/src/gr/fmpz_mpoly.c
index 845f0cbc7a..a0e5285985 100644
--- a/src/gr/fmpz_mpoly.c
+++ b/src/gr/fmpz_mpoly.c
@@ -131,6 +131,12 @@ _gr_fmpz_mpoly_randtest_small(fmpz_mpoly_t res, flint_rand_t state, gr_ctx_t ctx
return GR_SUCCESS;
}
+slong
+_gr_fmpz_mpoly_length(const fmpz_mpoly_t x, gr_ctx_t ctx)
+{
+ return x->length;
+}
+
int
_gr_fmpz_mpoly_write(gr_stream_t out, fmpz_mpoly_t poly, gr_ctx_t ctx)
{
@@ -545,6 +551,7 @@ gr_method_tab_input _gr_fmpz_mpoly_methods_input[] =
{GR_METHOD_SET_SHALLOW, (gr_funcptr) _gr_fmpz_mpoly_set_shallow},
{GR_METHOD_RANDTEST, (gr_funcptr) _gr_fmpz_mpoly_randtest},
{GR_METHOD_RANDTEST_SMALL, (gr_funcptr) _gr_fmpz_mpoly_randtest_small},
+ {_GR_METHOD_LENGTH, (gr_funcptr) _gr_fmpz_mpoly_length},
{GR_METHOD_WRITE, (gr_funcptr) _gr_fmpz_mpoly_write},
{GR_METHOD_ZERO, (gr_funcptr) _gr_fmpz_mpoly_zero},
{GR_METHOD_ONE, (gr_funcptr) _gr_fmpz_mpoly_one},
@@ -558,6 +565,7 @@ gr_method_tab_input _gr_fmpz_mpoly_methods_input[] =
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_fmpz_mpoly_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) _gr_fmpz_mpoly_set_fmpq},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_fmpz_mpoly_set_other},
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_balance_additions},
{GR_METHOD_NEG, (gr_funcptr) _gr_fmpz_mpoly_neg},
{GR_METHOD_ADD, (gr_funcptr) _gr_fmpz_mpoly_add},
{GR_METHOD_ADD_SI, (gr_funcptr) _gr_fmpz_mpoly_add_si},
diff --git a/src/gr/fmpz_mpoly_q.c b/src/gr/fmpz_mpoly_q.c
index c162723b61..63eda04bb2 100644
--- a/src/gr/fmpz_mpoly_q.c
+++ b/src/gr/fmpz_mpoly_q.c
@@ -16,6 +16,7 @@
#include "fmpz_mpoly.h"
#include "fmpz_mpoly_q.h"
#include "fmpz_mpoly_factor.h"
+#include "gr_generic.h"
typedef struct
{
@@ -94,6 +95,12 @@ _gr_fmpz_mpoly_q_randtest_small(fmpz_mpoly_q_t res, flint_rand_t state, gr_ctx_t
return GR_SUCCESS;
}
+slong
+_gr_fmpz_mpoly_q_length(const fmpz_mpoly_q_t x, gr_ctx_t ctx)
+{
+ return fmpz_mpoly_q_numref(x)->length + fmpz_mpoly_q_denref(x)->length;
+}
+
int
_gr_fmpz_mpoly_q_write(gr_stream_t out, fmpz_mpoly_q_t f, gr_ctx_t ctx)
{
@@ -533,6 +540,7 @@ gr_method_tab_input _gr_fmpz_mpoly_q_methods_input[] =
{GR_METHOD_SET_SHALLOW, (gr_funcptr) _gr_fmpz_mpoly_q_set_shallow},
{GR_METHOD_RANDTEST, (gr_funcptr) _gr_fmpz_mpoly_q_randtest},
{GR_METHOD_RANDTEST_SMALL, (gr_funcptr) _gr_fmpz_mpoly_q_randtest_small},
+ {_GR_METHOD_LENGTH, (gr_funcptr) _gr_fmpz_mpoly_q_length},
{GR_METHOD_WRITE, (gr_funcptr) _gr_fmpz_mpoly_q_write},
{GR_METHOD_ZERO, (gr_funcptr) _gr_fmpz_mpoly_q_zero},
{GR_METHOD_ONE, (gr_funcptr) _gr_fmpz_mpoly_q_one},
@@ -545,6 +553,7 @@ gr_method_tab_input _gr_fmpz_mpoly_q_methods_input[] =
{GR_METHOD_SET_SI, (gr_funcptr) _gr_fmpz_mpoly_q_set_si},
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_fmpz_mpoly_q_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) _gr_fmpz_mpoly_q_set_fmpq},
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_balance_additions},
{GR_METHOD_NEG, (gr_funcptr) _gr_fmpz_mpoly_q_neg},
{GR_METHOD_ADD, (gr_funcptr) _gr_fmpz_mpoly_q_add},
{GR_METHOD_ADD_SI, (gr_funcptr) _gr_fmpz_mpoly_q_add_si},
diff --git a/src/gr/fmpz_poly.c b/src/gr/fmpz_poly.c
index 0351ba097f..399850b2b5 100644
--- a/src/gr/fmpz_poly.c
+++ b/src/gr/fmpz_poly.c
@@ -21,6 +21,7 @@
#include "gr_poly.h"
#include "gr_generic.h"
#include "fmpz_poly_factor.h"
+#include "fmpz_mpoly.h"
#define FMPZ_POLY_CTX(ctx) POLYNOMIAL_CTX(ctx)
#define FMPZ_POLY_CTX_VAR(ctx) (FMPZ_POLY_CTX(ctx)->var)
@@ -214,16 +215,30 @@ _gr_fmpz_poly_set_other(fmpz_poly_t res, gr_srcptr x, gr_ctx_t x_ctx, const gr_c
return GR_UNABLE;
}
-/*
int
_gr_fmpz_poly_set_str(fmpz_poly_t res, const char * x, const gr_ctx_t ctx)
{
- if (fmpz_poly_set_str(res, x))
- return GR_DOMAIN;
+ fmpz_mpoly_ctx_t fctx;
+ fmpz_mpoly_t f;
+ int status;
+ const char * vars[] = { "x" };
- return GR_SUCCESS;
+ fmpz_mpoly_ctx_init(fctx, 1, ORD_LEX);
+ fmpz_mpoly_init(f, fctx);
+ if (!fmpz_mpoly_set_str_pretty(f, x, vars, fctx))
+ {
+ fmpz_mpoly_get_fmpz_poly(res, f, 0, fctx);
+ status = GR_SUCCESS;
+ }
+ else
+ {
+ status = GR_UNABLE;
+ }
+ fmpz_mpoly_clear(f, fctx);
+ fmpz_mpoly_ctx_clear(fctx);
+
+ return status;
}
-*/
int
_gr_fmpz_poly_get_ui(ulong * res, const fmpz_poly_t x, const gr_ctx_t ctx)
@@ -799,7 +814,7 @@ gr_method_tab_input _fmpz_poly_methods_input[] =
{GR_METHOD_SET_UI, (gr_funcptr) _gr_fmpz_poly_set_ui},
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_fmpz_poly_set_fmpz},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_fmpz_poly_set_other},
-/* {GR_METHOD_SET_STR, (gr_funcptr) _gr_fmpz_poly_set_str}, */
+ {GR_METHOD_SET_STR, (gr_funcptr) _gr_fmpz_poly_set_str},
{GR_METHOD_GET_UI, (gr_funcptr) _gr_fmpz_poly_get_ui},
{GR_METHOD_GET_SI, (gr_funcptr) _gr_fmpz_poly_get_si},
{GR_METHOD_GET_FMPZ, (gr_funcptr) _gr_fmpz_poly_get_fmpz},
diff --git a/src/gr/fmpzi.c b/src/gr/fmpzi.c
index ed266a8c35..54cde58da2 100644
--- a/src/gr/fmpzi.c
+++ b/src/gr/fmpzi.c
@@ -942,7 +942,6 @@ gr_method_tab_input _fmpzi_methods_input[] =
{GR_METHOD_SET_FMPQ, (gr_funcptr) _gr_fmpzi_set_fmpq},
{GR_METHOD_SET_D, (gr_funcptr) _gr_fmpzi_set_d},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_fmpzi_set_other},
-/* {GR_METHOD_SET_STR, (gr_funcptr) _gr_fmpzi_set_str}, */
{GR_METHOD_GET_FMPZ, (gr_funcptr) _gr_fmpzi_get_fmpz},
{GR_METHOD_GET_FMPQ, (gr_funcptr) _gr_fmpzi_get_fmpq},
{GR_METHOD_GET_UI, (gr_funcptr) _gr_fmpzi_get_ui},
diff --git a/src/gr/mpoly.c b/src/gr/mpoly.c
index 2191359257..758baf15e7 100644
--- a/src/gr/mpoly.c
+++ b/src/gr/mpoly.c
@@ -13,6 +13,7 @@
#include "gr.h"
#include "gr_mpoly.h"
+#include "gr_generic.h"
typedef struct
{
@@ -143,6 +144,12 @@ _gr_gr_mpoly_randtest(gr_mpoly_t res, flint_rand_t state, gr_ctx_t ctx)
return gr_mpoly_randtest_bits(res, state, n_randint(state, 5), 1 + n_randint(state, 3), MPOLYNOMIAL_MCTX(ctx), MPOLYNOMIAL_ELEM_CTX(ctx));
}
+slong
+_gr_gr_mpoly_length(const gr_mpoly_t x, gr_ctx_t ctx)
+{
+ return x->length;
+}
+
int
_gr_gr_mpoly_write(gr_stream_t out, gr_mpoly_t poly, gr_ctx_t ctx)
{
@@ -312,6 +319,7 @@ gr_method_tab_input _gr__gr_gr_mpoly_methods_input[] =
{GR_METHOD_SWAP, (gr_funcptr) _gr_gr_mpoly_swap},
{GR_METHOD_SET_SHALLOW, (gr_funcptr) _gr_gr_mpoly_set_shallow},
{GR_METHOD_RANDTEST, (gr_funcptr) _gr_gr_mpoly_randtest},
+ {_GR_METHOD_LENGTH, (gr_funcptr) _gr_gr_mpoly_length},
{GR_METHOD_WRITE, (gr_funcptr) _gr_gr_mpoly_write},
{GR_METHOD_GENS, (gr_funcptr) _gr_gr_mpoly_gens},
{GR_METHOD_GENS_RECURSIVE, (gr_funcptr) _gr_gr_mpoly_gens_recursive},
@@ -325,6 +333,7 @@ gr_method_tab_input _gr__gr_gr_mpoly_methods_input[] =
{GR_METHOD_SET_SI, (gr_funcptr) _gr_gr_mpoly_set_si},
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_gr_mpoly_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) _gr_gr_mpoly_set_fmpq},
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_balance_additions},
{GR_METHOD_NEG, (gr_funcptr) _gr_gr_mpoly_neg},
{GR_METHOD_ADD, (gr_funcptr) _gr_gr_mpoly_add},
{GR_METHOD_SUB, (gr_funcptr) _gr_gr_mpoly_sub},
diff --git a/src/gr/nf.c b/src/gr/nf.c
index a1e39df332..a1e850c803 100644
--- a/src/gr/nf.c
+++ b/src/gr/nf.c
@@ -554,11 +554,11 @@ gr_method_tab_input _nf_methods_input[] =
{GR_METHOD_SET_UI, (gr_funcptr) _gr_nf_set_ui},
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_nf_set_fmpz},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_nf_set_other},
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_balance_additions},
{GR_METHOD_SET_FEXPR, (gr_funcptr) _gr_nf_set_fexpr},
{GR_METHOD_GET_FEXPR, (gr_funcptr) _gr_nf_get_fexpr},
-
{GR_METHOD_NEG, (gr_funcptr) _gr_nf_neg},
{GR_METHOD_ADD, (gr_funcptr) _gr_nf_add},
diff --git a/src/gr/nmod32.c b/src/gr/nmod32.c
index 169e517ba3..24d48ba9fa 100644
--- a/src/gr/nmod32.c
+++ b/src/gr/nmod32.c
@@ -74,7 +74,7 @@ nmod32_randtest(nmod32_t res, flint_rand_t state, const gr_ctx_t ctx)
int
nmod32_write(gr_stream_t out, const nmod32_t x, const gr_ctx_t ctx)
{
- gr_stream_write_si(out, x[0]);
+ gr_stream_write_ui(out, x[0]);
return GR_SUCCESS;
}
diff --git a/src/gr/nmod8.c b/src/gr/nmod8.c
index e464aceb17..6a2dc2403c 100644
--- a/src/gr/nmod8.c
+++ b/src/gr/nmod8.c
@@ -74,7 +74,7 @@ nmod8_randtest(nmod8_t res, flint_rand_t state, const gr_ctx_t ctx)
int
nmod8_write(gr_stream_t out, const nmod8_t x, const gr_ctx_t ctx)
{
- gr_stream_write_si(out, x[0]);
+ gr_stream_write_ui(out, x[0]);
return GR_SUCCESS;
}
diff --git a/src/gr/polynomial.c b/src/gr/polynomial.c
index 71769eba5c..5f044b8ea3 100644
--- a/src/gr/polynomial.c
+++ b/src/gr/polynomial.c
@@ -442,6 +442,9 @@ gr_method_tab_input _gr_poly_methods_input[] =
{GR_METHOD_SET_FMPZ, (gr_funcptr) polynomial_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) polynomial_set_fmpq},
{GR_METHOD_SET_OTHER, (gr_funcptr) polynomial_set_other},
+ /* todo: we actually want parse using sparse polynomials
+ before converting to the dense representation, to avoid O(n^2) behavior */
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_balance_additions},
{GR_METHOD_NEG, (gr_funcptr) polynomial_neg},
{GR_METHOD_ADD, (gr_funcptr) polynomial_add},
{GR_METHOD_SUB, (gr_funcptr) polynomial_sub},
diff --git a/src/gr/qqbar.c b/src/gr/qqbar.c
index a481811def..b3975a2375 100644
--- a/src/gr/qqbar.c
+++ b/src/gr/qqbar.c
@@ -1167,6 +1167,7 @@ gr_method_tab_input _qqbar_methods_input[] =
{GR_METHOD_SET_FMPQ, (gr_funcptr) _gr_qqbar_set_fmpq},
{GR_METHOD_SET_D, (gr_funcptr) _gr_qqbar_set_d},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_qqbar_set_other},
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_ring_exponents},
{GR_METHOD_GET_SI, (gr_funcptr) _gr_qqbar_get_si},
{GR_METHOD_GET_UI, (gr_funcptr) _gr_qqbar_get_ui},
diff --git a/src/gr/series.c b/src/gr/series.c
index 9189dc3f97..2e908abc96 100644
--- a/src/gr/series.c
+++ b/src/gr/series.c
@@ -1981,6 +1981,7 @@ gr_method_tab_input _gr_series_methods_input[] =
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_gr_series_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) _gr_gr_series_set_fmpq},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_gr_series_set_other},
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_balance_additions},
{GR_METHOD_NEG, (gr_funcptr) _gr_gr_series_neg},
{GR_METHOD_ADD, (gr_funcptr) _gr_gr_series_add},
{GR_METHOD_SUB, (gr_funcptr) _gr_gr_series_sub},
diff --git a/src/gr_generic.h b/src/gr_generic.h
index dc174b4e0d..139c698f91 100644
--- a/src/gr_generic.h
+++ b/src/gr_generic.h
@@ -106,6 +106,14 @@ WARN_UNUSED_RESULT int gr_generic_neg_one(gr_ptr res, gr_ctx_t ctx);
WARN_UNUSED_RESULT int gr_generic_set_other(gr_ptr res, gr_srcptr x, gr_ctx_t xctx, gr_ctx_t ctx);
WARN_UNUSED_RESULT int gr_generic_set_fmpq(gr_ptr res, const fmpq_t y, gr_ctx_t ctx);
+#define GR_PARSE_BALANCE_ADDITIONS 1
+#define GR_PARSE_RING_EXPONENTS 2
+
+WARN_UNUSED_RESULT int gr_generic_set_str_expr(gr_ptr res, const char * s, int flags, gr_ctx_t ctx);
+WARN_UNUSED_RESULT int gr_generic_set_str(gr_ptr res, const char * s, gr_ctx_t ctx);
+WARN_UNUSED_RESULT int gr_generic_set_str_balance_additions(gr_ptr res, const char * s, gr_ctx_t ctx);
+WARN_UNUSED_RESULT int gr_generic_set_str_ring_exponents(gr_ptr res, const char * s, gr_ctx_t ctx);
+
#ifdef FEXPR_H
WARN_UNUSED_RESULT int gr_generic_set_fexpr(gr_ptr res, fexpr_vec_t inputs, gr_vec_t outputs, const fexpr_t expr, gr_ctx_t ctx);
#endif
diff --git a/src/gr_generic/generic.c b/src/gr_generic/generic.c
index b164a1d0fb..89cbdbfcc8 100644
--- a/src/gr_generic/generic.c
+++ b/src/gr_generic/generic.c
@@ -141,6 +141,12 @@ int gr_generic_randtest_small(gr_ptr x, flint_rand_t state, gr_ctx_t ctx)
return status;
}
+slong _gr_generic_length(gr_srcptr x, gr_ctx_t ctx)
+{
+ return 0;
+}
+
+
int gr_generic_gens(gr_vec_t vec, gr_ctx_t ctx)
{
gr_vec_set_length(vec, 0, ctx);
@@ -2493,6 +2499,8 @@ const gr_method_tab_input _gr_generic_methods[] =
{GR_METHOD_SWAP, (gr_funcptr) gr_generic_swap},
{GR_METHOD_SET_SHALLOW, (gr_funcptr) gr_generic_set_shallow},
+ {_GR_METHOD_LENGTH, (gr_funcptr) _gr_generic_length},
+
{GR_METHOD_WRITE, (gr_funcptr) gr_generic_write},
{GR_METHOD_WRITE_N, (gr_funcptr) gr_generic_write_n},
@@ -2521,6 +2529,8 @@ const gr_method_tab_input _gr_generic_methods[] =
{GR_METHOD_SET_OTHER, (gr_funcptr) gr_generic_set_other},
+ {GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str},
+
{GR_METHOD_GET_FEXPR_SERIALIZE, (gr_funcptr) gr_generic_get_fexpr_serialize},
{GR_METHOD_SET_FEXPR, (gr_funcptr) gr_generic_set_fexpr},
diff --git a/src/gr_generic/set_str_expr.c b/src/gr_generic/set_str_expr.c
new file mode 100644
index 0000000000..71ac5cdffd
--- /dev/null
+++ b/src/gr_generic/set_str_expr.c
@@ -0,0 +1,713 @@
+/*
+ Copyright (C) 2020 Daniel Schultz
+ Copyright (C) 2024 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 "mpoly.h"
+#include "gr.h"
+#include "gr_special.h"
+#include "gr_vec.h"
+#include "gr_generic.h"
+
+#define PREC_LOWEST 0
+#define PREC_PLUS 1
+#define PREC_MINUS 1
+#define PREC_TIMES 2
+#define PREC_DIVIDES 2
+#define PREC_UPLUS 3
+#define PREC_UMINUS 3
+#define PREC_POWER 4
+#define PREC_HIGHEST 255
+
+#define OP_TIMES 0
+#define OP_PLUS 1
+#define OP_MINUS 2
+#define OP_DIVIDES 3
+#define OP_LROUND 4
+#define OP_POWER 5
+
+#define FIX_INFIX 0
+#define FIX_PREFIX 1
+#define FIX_POSTFIX 2
+#define FIX_MATCHFIX 3
+
+typedef struct {
+ gr_ctx_struct * R;
+ slong * stack;
+ slong stack_len;
+ slong stack_alloc;
+ char * estore;
+ slong estore_len;
+ slong estore_alloc;
+ void * tmp;
+ string_with_length_struct * terminal_strings;
+ char * terminal_values;
+ slong terminals_alloc;
+ slong terminals_len;
+ int flags;
+ _gr_method_get_si_op size_func;
+} gr_parse_struct;
+
+typedef gr_parse_struct gr_parse_t[1];
+
+void _gr_parse_init(gr_parse_t E);
+void _gr_parse_clear(gr_parse_t E);
+void _gr_parse_add_terminal(gr_parse_t E, const char * s, const void * v);
+int _gr_parse_parse(gr_parse_t E, void * res, const char * s, slong len);
+
+FLINT_FORCE_INLINE int _is_op(slong a)
+{
+ return a >= 0;
+}
+
+FLINT_FORCE_INLINE slong _op_make(slong name, slong fix, slong prec)
+{
+ return (prec << 10) + (fix << 8) + (name << 0);
+}
+
+FLINT_FORCE_INLINE slong _op_prec(slong a)
+{
+ return (ulong)(a) >> 10;
+}
+
+FLINT_FORCE_INLINE slong _op_fix(slong a)
+{
+ return ((ulong)(a) >> 8) & 3;
+}
+
+FLINT_FORCE_INLINE slong _op_name(slong a)
+{
+ return a&255;
+}
+
+/* initialize the R member first */
+void _gr_parse_init(gr_parse_t E)
+{
+ slong i;
+
+ E->flags = 0;
+ E->size_func = (_gr_method_get_si_op) _gr_length;
+
+ E->stack_len = 0;
+ E->stack_alloc = 20;
+ E->stack = FLINT_ARRAY_ALLOC(E->stack_alloc, slong);
+
+ E->estore_len = 0;
+ E->estore_alloc = 10;
+ E->estore = gr_heap_init_vec(E->estore_alloc, E->R);
+
+ E->terminals_len = 0;
+ E->terminals_alloc = 5;
+ E->terminal_values = gr_heap_init_vec(E->terminals_alloc, E->R);
+ E->terminal_strings = FLINT_ARRAY_ALLOC(E->terminals_alloc, string_with_length_struct);
+
+ for (i = 0; i < E->terminals_alloc; i++)
+ {
+ E->terminal_strings[i].str = NULL;
+ E->terminal_strings[i].str_len = 0;
+ }
+
+}
+
+void _gr_parse_clear(gr_parse_t E)
+{
+ slong i;
+
+ flint_free(E->stack);
+
+ gr_heap_clear_vec(E->estore, E->estore_alloc, E->R);
+ gr_heap_clear_vec(E->terminal_values, E->terminals_alloc, E->R);
+
+ for (i = 0; i < E->terminals_alloc; i++)
+ flint_free(E->terminal_strings[i].str);
+
+ flint_free(E->terminal_strings);
+}
+
+void _gr_parse_add_terminal(gr_parse_t E, const char * s, const void * val)
+{
+ slong l, n = E->terminals_len;
+ slong sz = E->R->sizeof_elem;
+
+ if (n + 1 > E->terminals_alloc)
+ {
+ slong i = E->terminals_alloc;
+ slong new_alloc = FLINT_MAX(n + 1, i + i/2);
+
+ E->terminal_strings = (string_with_length_struct *) flint_realloc(
+ E->terminal_strings, new_alloc*
+ sizeof(string_with_length_struct));
+
+ E->terminal_values = (char *) flint_realloc(E->terminal_values, sz * new_alloc);
+ for ( ; i < new_alloc; i++)
+ {
+ E->terminal_strings[i].str = NULL;
+ E->terminal_strings[i].str_len = 0;
+ gr_init(GR_ENTRY(E->terminal_values, i, sz), E->R);
+ }
+
+ E->terminals_alloc = new_alloc;
+ }
+
+ l = strlen(s);
+ E->terminal_strings[n].str_len = l;
+
+ E->terminal_strings[n].str = (char *) flint_realloc(E->terminal_strings[n].str, l + 1);
+ memcpy(E->terminal_strings[n].str, s, l + 1);
+
+ GR_MUST_SUCCEED(gr_set(GR_ENTRY(E->terminal_values, n, sz), val, E->R));
+
+ E->terminals_len = n + 1;
+
+ while (n > 0 && E->terminal_strings[n-1].str_len < E->terminal_strings[n].str_len)
+ {
+ FLINT_SWAP(char *, E->terminal_strings[n-1].str, E->terminal_strings[n].str);
+ FLINT_SWAP(slong, E->terminal_strings[n-1].str_len, E->terminal_strings[n].str_len);
+ gr_swap(GR_ENTRY(E->terminal_values, n - 1, sz), GR_ENTRY(E->terminal_values, n, sz), E->R);
+ n--;
+ }
+}
+
+static int gr_parse_top_is_expr(const gr_parse_t E)
+{
+ return E->stack_len > 0 && !_is_op(E->stack[E->stack_len - 1]);
+}
+
+static void * gr_parse_top_expr(gr_parse_t E)
+{
+ slong sz = E->R->sizeof_elem;
+
+ FLINT_ASSERT(E->stack_len > 0);
+ FLINT_ASSERT(E->stack[E->stack_len - 1] < 0);
+
+ return GR_ENTRY(E->estore, -1 - E->stack[E->stack_len - 1], sz);
+}
+
+static void _gr_parse_push_op(gr_parse_t E, slong op)
+{
+ FLINT_ASSERT(_is_op(op));
+ _slong_array_fit_length(&E->stack, &E->stack_alloc, E->stack_len + 1);
+ E->stack[E->stack_len] = op;
+ E->stack_len++;
+}
+
+/* if the top is not an expr, push the tmp, otherwise fail */
+static int _gr_parse_push_expr(gr_parse_t E)
+{
+ slong sz = E->R->sizeof_elem;
+
+ if (gr_parse_top_is_expr(E))
+ return -1;
+
+ if (E->estore_len + 1 > E->estore_alloc)
+ {
+ slong i = E->estore_alloc;
+ slong new_alloc = FLINT_MAX(E->estore_len + 1, i + i/2);
+ E->estore = flint_realloc(E->estore, new_alloc*sz);
+ for ( ; i < new_alloc; i++)
+ gr_init(GR_ENTRY(E->estore, i, sz), E->R);
+ E->estore_alloc = new_alloc;
+ }
+
+ _slong_array_fit_length(&E->stack, &E->stack_alloc, E->stack_len + 1);
+ E->stack[E->stack_len] = -1 - E->estore_len;
+ E->stack_len++;
+ gr_swap(GR_ENTRY(E->estore, E->estore_len, sz), E->tmp, E->R);
+ E->estore_len++;
+ return 0;
+}
+
+/* if the top is an expr, pop it, otherwise fail */
+static int _gr_parse_pop_expr(gr_parse_t E)
+{
+ slong sz = E->R->sizeof_elem;
+
+ if (!gr_parse_top_is_expr(E))
+ return -1;
+
+ gr_swap(E->tmp, GR_ENTRY(E->estore, -1 - E->stack[E->stack_len - 1], sz), E->R);
+ E->estore_len--;
+ E->stack_len--;
+ return 0;
+}
+
+/* if the top is an operation op, pop it, otherwise fail */
+static int _gr_parse_pop_op(gr_parse_t E, slong op)
+{
+ slong n = E->stack_len - 1;
+
+ if (n < 0 || !_is_op(E->stack[n]) || _op_name(E->stack[n]) != op)
+ return -1;
+
+ E->stack_len = n;
+ return 0;
+}
+
+/* pop ops with precedence > prec */
+static int _gr_parse_pop_prec(gr_parse_t E, slong prec)
+{
+ slong n, n1, n2, n3, p, l1, l3;
+ slong sz = E->R->sizeof_elem;
+
+ if (E->stack_len < 1)
+ return -1;
+
+again:
+
+ n = E->stack_len;
+ if (n < 2)
+ return 0;
+
+ n1 = E->stack[n-1];
+ n2 = E->stack[n-2];
+
+ if (_is_op(n1) || !_is_op(n2))
+ return 0;
+
+ n1 = -1-n1;
+
+ p = _op_prec(n2);
+
+ if (p < prec)
+ return 0;
+
+ if (_op_fix(n2) == FIX_INFIX)
+ {
+ n3 = E->stack[n-3];
+ FLINT_ASSERT(!_is_op(n3));
+ n3 = -1 - n3;
+
+ FLINT_ASSERT(n1 == n3 + 1);
+
+ if (_op_name(n2) == OP_TIMES)
+ {
+ if (GR_SUCCESS != gr_mul(E->tmp, GR_ENTRY(E->estore, n3, sz), GR_ENTRY(E->estore, n1, sz), E->R))
+ {
+ return -1;
+ }
+
+ gr_swap(GR_ENTRY(E->estore, n3, sz), E->tmp, E->R);
+ E->estore_len -= 1;
+ E->stack_len -= 2;
+ }
+ else if (_op_name(n2) == OP_PLUS)
+ {
+ if (E->flags & GR_PARSE_BALANCE_ADDITIONS)
+ {
+ l1 = E->size_func(GR_ENTRY(E->estore, n1, sz), E->R);
+ l3 = E->size_func(GR_ENTRY(E->estore, n3, sz), E->R);
+ }
+ else
+ {
+ l1 = l3 = 0;
+ }
+
+ do_plus:
+
+ if (l1 > l3)
+ {
+ FLINT_SWAP(slong, l3, l1);
+ gr_swap(GR_ENTRY(E->estore, n3, sz), GR_ENTRY(E->estore, n1, sz), E->R);
+ }
+
+ if (p > prec || 2*l1 >= l3)
+ {
+ if (GR_SUCCESS != gr_add(GR_ENTRY(E->estore, n3, sz), GR_ENTRY(E->estore, n3, sz), GR_ENTRY(E->estore, n1, sz), E->R))
+ {
+ return -1;
+ }
+
+ E->estore_len -= 1;
+ E->stack_len -= 2;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else if (_op_name(n2) == OP_MINUS)
+ {
+ if (E->flags & GR_PARSE_BALANCE_ADDITIONS)
+ {
+ l1 = E->size_func(GR_ENTRY(E->estore, n1, sz), E->R);
+ l3 = E->size_func(GR_ENTRY(E->estore, n3, sz), E->R);
+ }
+ else
+ {
+ l1 = l3 = 0;
+ }
+
+ if (4*l1 >= l3 || 4*l3 >= l1)
+ {
+ if (GR_SUCCESS != gr_sub(GR_ENTRY(E->estore, n3, sz), GR_ENTRY(E->estore, n3, sz),
+ GR_ENTRY(E->estore, n1, sz), E->R))
+ {
+ return -1;
+ }
+
+ E->estore_len -= 1;
+ E->stack_len -= 2;
+ }
+ else
+ {
+ if (GR_SUCCESS != gr_neg(GR_ENTRY(E->estore, n1, sz), GR_ENTRY(E->estore, n1, sz), E->R))
+ {
+ return -1;
+ }
+
+ E->stack[n-2] = _op_make(OP_PLUS, FIX_INFIX, PREC_PLUS);
+ goto do_plus;
+ }
+ }
+ else if (_op_name(n2) == OP_DIVIDES)
+ {
+ /*
+ NOTE: if divides and times have the same precedence and the
+ multiplications were to be delayed as the addition are,
+ then there would have to be more shenenigans here.
+ */
+ if (GR_SUCCESS != gr_div(E->tmp, GR_ENTRY(E->estore, n3, sz), GR_ENTRY(E->estore, n1, sz), E->R))
+ {
+ return -1;
+ }
+
+ gr_swap(GR_ENTRY(E->estore, n3, sz), E->tmp, E->R);
+ E->estore_len -= 1;
+ E->stack_len -= 2;
+ }
+ else if (_op_name(n2) == OP_POWER)
+ {
+ if (GR_SUCCESS != gr_pow(E->tmp, GR_ENTRY(E->estore, n3, sz), GR_ENTRY(E->estore, n1, sz), E->R))
+ {
+ return -1;
+ }
+
+ gr_swap(GR_ENTRY(E->estore, n3, sz), E->tmp, E->R);
+ E->estore_len -= 1;
+ E->stack_len -= 2;
+ }
+ else
+ {
+ flint_throw(FLINT_ERROR, "_pop_stack: internal error");
+ }
+
+ goto again;
+ }
+ else if (_op_fix(n2) == FIX_PREFIX)
+ {
+ if (_op_name(n2) == OP_MINUS)
+ GR_MUST_SUCCEED(gr_neg(GR_ENTRY(E->estore, n1, sz), GR_ENTRY(E->estore, n1, sz), E->R));
+
+ E->stack[n-2] = -1-n1;
+ E->stack_len -= 1;
+ goto again;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static const char * _parse_int(fmpz_t c, const char * s, const char * end)
+{
+ char * buffer, * v;
+ const char * send = s + 1;
+ TMP_INIT;
+
+ while (send < end && '0' <= *send && *send <= '9')
+ send++;
+
+ switch (send - s)
+ {
+ case 1:
+ fmpz_set_ui(c, s[0] - '0');
+ s += 1;
+ break;
+ case 2:
+ fmpz_set_ui(c, (s[0] - '0') * 10 + (s[1] - '0'));
+ s += 2;
+ break;
+ case 3:
+ fmpz_set_ui(c, (s[0] - '0') * 100 + (s[1] - '0') * 10 + (s[2] - '0'));
+ s += 3;
+ break;
+ default:
+ TMP_START;
+ v = buffer = (char *) TMP_ALLOC((send - s + 1)*sizeof(char));
+ while (s < send)
+ *v++ = *s++;
+ *v++ = '\0';
+ fmpz_set_str(c, buffer, 10);
+ TMP_END;
+ }
+
+ return s;
+}
+
+int _gr_parse_parse(gr_parse_t E, void * poly, const char * s, slong slen)
+{
+ const char * send = s + slen;
+ fmpz_t c;
+ int ret;
+
+ fmpz_init(c);
+ E->tmp = poly;
+
+ while (s < send)
+ {
+ if ('0' <= *s && *s <= '9')
+ {
+ s = _parse_int(c, s, send);
+
+ GR_MUST_SUCCEED(gr_set_fmpz(E->tmp, c, E->R));
+ if (_gr_parse_push_expr(E))
+ goto failed;
+ }
+ else if (*s == '^')
+ {
+ if (E->flags & GR_PARSE_RING_EXPONENTS)
+ {
+ if (!gr_parse_top_is_expr(E))
+ goto failed;
+
+ if (_gr_parse_pop_prec(E, PREC_POWER))
+ goto failed;
+
+ _gr_parse_push_op(E, _op_make(OP_POWER, FIX_INFIX, PREC_POWER));
+ s++;
+ }
+ else
+ {
+ if (++s >= send || !('0' <= *s && *s <= '9'))
+ goto failed;
+
+ s = _parse_int(c, s, send);
+
+ if (_gr_parse_pop_prec(E, PREC_POWER))
+ goto failed;
+
+ if (!gr_parse_top_is_expr(E))
+ goto failed;
+
+ if (GR_SUCCESS != gr_pow_fmpz(gr_parse_top_expr(E), gr_parse_top_expr(E), c, E->R))
+ goto failed;
+ }
+ }
+ else if (*s == '*')
+ {
+ if (!gr_parse_top_is_expr(E))
+ goto failed;
+
+ if (_gr_parse_pop_prec(E, PREC_TIMES))
+ goto failed;
+
+ _gr_parse_push_op(E, _op_make(OP_TIMES, FIX_INFIX, PREC_TIMES));
+ s++;
+ }
+ else if (*s == '+')
+ {
+ if (!gr_parse_top_is_expr(E))
+ {
+ _gr_parse_push_op(E, _op_make(OP_PLUS, FIX_PREFIX, PREC_UPLUS));
+ }
+ else
+ {
+ if (_gr_parse_pop_prec(E, PREC_PLUS))
+ goto failed;
+
+ _gr_parse_push_op(E, _op_make(OP_PLUS, FIX_INFIX, PREC_PLUS));
+ }
+ s++;
+ }
+ else if (*s == '-')
+ {
+ if (!gr_parse_top_is_expr(E))
+ {
+ _gr_parse_push_op(E, _op_make(OP_MINUS, FIX_PREFIX, PREC_UMINUS));
+ }
+ else
+ {
+ if (_gr_parse_pop_prec(E, PREC_MINUS))
+ goto failed;
+
+ _gr_parse_push_op(E, _op_make(OP_MINUS, FIX_INFIX, PREC_MINUS));
+ }
+ s++;
+ }
+ else if (*s == '/')
+ {
+ if (!gr_parse_top_is_expr(E))
+ goto failed;
+
+ if (_gr_parse_pop_prec(E, PREC_DIVIDES))
+ goto failed;
+
+ _gr_parse_push_op(E, _op_make(OP_DIVIDES, FIX_INFIX, PREC_DIVIDES));
+ s++;
+ }
+ else if (*s == ' ')
+ {
+ s++;
+ }
+ else if (*s == '(')
+ {
+ if (gr_parse_top_is_expr(E))
+ goto failed;
+
+ _gr_parse_push_op(E, _op_make(OP_LROUND, FIX_MATCHFIX, PREC_LOWEST));
+ s++;
+ }
+ else if (*s == ')')
+ {
+ if (_gr_parse_pop_prec(E, PREC_LOWEST))
+ goto failed;
+
+ if (_gr_parse_pop_expr(E))
+ goto failed;
+
+ if (_gr_parse_pop_op(E, OP_LROUND))
+ goto failed;
+
+ if (_gr_parse_push_expr(E))
+ goto failed;
+
+ s++;
+ }
+ else
+ {
+ slong k;
+ for (k = 0; k < E->terminals_len; k++)
+ {
+ slong l = E->terminal_strings[k].str_len;
+ if (0 == strncmp(s, E->terminal_strings[k].str, l))
+ {
+ GR_MUST_SUCCEED(gr_set(E->tmp, GR_ENTRY(E->terminal_values, k, E->R->sizeof_elem), E->R));
+ if (_gr_parse_push_expr(E))
+ goto failed;
+
+ s += l;
+ goto continue_outer;
+ }
+ }
+
+ /* some builtin constants (for R and C) */
+ /* todo: builtin functions */
+
+ if (0 == strncmp(s, "pi", 2) || 0 == strncmp(s, "Pi", 2))
+ {
+ if (GR_SUCCESS != gr_pi(E->tmp, E->R))
+ goto failed;
+ if (_gr_parse_push_expr(E))
+ goto failed;
+ s += 2;
+ goto continue_outer;
+ }
+
+ if (0 == strncmp(s, "i", 1) || 0 == strncmp(s, "I", 1))
+ {
+ if (GR_SUCCESS != gr_i(E->tmp, E->R))
+ goto failed;
+ if (_gr_parse_push_expr(E))
+ goto failed;
+ s += 1;
+ goto continue_outer;
+ }
+
+ goto failed;
+ }
+ continue_outer:;
+ }
+
+ if (_gr_parse_pop_prec(E, PREC_LOWEST))
+ goto failed;
+
+ if (_gr_parse_pop_expr(E))
+ goto failed;
+
+ if (E->stack_len != 0)
+ goto failed;
+
+ ret = 0;
+
+done:
+
+ fmpz_clear(c);
+ return ret;
+
+failed:
+
+ ret = -1;
+ goto done;
+}
+
+int
+gr_generic_set_str_expr(gr_ptr res, const char * s, int flags, gr_ctx_t ctx)
+{
+ gr_parse_t parse;
+ gr_vec_t gens;
+ slong i;
+ char * g;
+ int status;
+
+ /* Quickly see if we simply have an integer literal, e.g. 0 */
+ fmpz_t c;
+ fmpz_init(c);
+ if (!fmpz_set_str(c, s, 10))
+ {
+ status = gr_set_fmpz(res, c, ctx);
+ }
+ else
+ {
+ parse->R = ctx;
+ _gr_parse_init(parse);
+ parse->flags = flags;
+
+ gr_vec_init(gens, 0, ctx);
+ if (gr_gens_recursive(gens, ctx) == GR_SUCCESS)
+ {
+ for (i = 0; i < gens->length; i++)
+ {
+ GR_MUST_SUCCEED(gr_get_str(&g, gr_vec_entry_srcptr(gens, i, ctx), ctx));
+ /* todo: version that consumes s and x */
+ _gr_parse_add_terminal(parse, g, gr_vec_entry_srcptr(gens, i, ctx));
+ flint_free(g);
+ }
+ }
+
+ gr_vec_clear(gens, ctx);
+
+ status = _gr_parse_parse(parse, res, s, strlen(s)) ? GR_UNABLE : GR_SUCCESS;
+
+ _gr_parse_clear(parse);
+ }
+
+ fmpz_clear(c);
+
+ return status;
+}
+
+int
+gr_generic_set_str(gr_ptr res, const char * s, gr_ctx_t ctx)
+{
+ return gr_generic_set_str_expr(res, s, 0, ctx);
+}
+
+int
+gr_generic_set_str_balance_additions(gr_ptr res, const char * s, gr_ctx_t ctx)
+{
+ return gr_generic_set_str_expr(res, s, GR_PARSE_BALANCE_ADDITIONS, ctx);
+}
+
+int
+gr_generic_set_str_ring_exponents(gr_ptr res, const char * s, gr_ctx_t ctx)
+{
+ return gr_generic_set_str_expr(res, s, GR_PARSE_RING_EXPONENTS, ctx);
+}
diff --git a/src/python/flint_ctypes.py b/src/python/flint_ctypes.py
index b643724015..12f86213e9 100644
--- a/src/python/flint_ctypes.py
+++ b/src/python/flint_ctypes.py
@@ -4451,33 +4451,39 @@ def order(self):
class FiniteField_fq(FiniteField_base):
- def __init__(self, p, n):
+ def __init__(self, p, n, var=None):
gr_ctx.__init__(self)
p = ZZ(p)
n = int(n)
assert p.is_prime()
assert n >= 1
- libgr.gr_ctx_init_fq(self._ref, p._ref, n, None)
+ if var is not None:
+ var = ctypes.c_char_p(str(var).encode('ascii'))
+ libgr.gr_ctx_init_fq(self._ref, p._ref, n, var)
self._elem_type = fq
class FiniteField_fq_nmod(FiniteField_base):
- def __init__(self, p, n):
+ def __init__(self, p, n, var=None):
gr_ctx.__init__(self)
- p = ZZ(p)
+ p = self._as_ui(p)
n = int(n)
- assert p.is_prime()
+ assert ZZ(p).is_prime()
assert n >= 1
- libgr.gr_ctx_init_fq_nmod(self._ref, p._ref, n, None)
+ if var is not None:
+ var = ctypes.c_char_p(str(var).encode('ascii'))
+ libgr.gr_ctx_init_fq_nmod(self._ref, p, n, var)
self._elem_type = fq_nmod
class FiniteField_fq_zech(FiniteField_base):
- def __init__(self, p, n):
+ def __init__(self, p, n, var=None):
gr_ctx.__init__(self)
- p = ZZ(p)
+ p = self._as_ui(p)
n = int(n)
- assert p.is_prime()
+ assert ZZ(p).is_prime()
assert n >= 1
- libgr.gr_ctx_init_fq_zech(self._ref, p._ref, n, None)
+ if var is not None:
+ var = ctypes.c_char_p(str(var).encode('ascii'))
+ libgr.gr_ctx_init_fq_zech(self._ref, p, n, var)
self._elem_type = fq_zech
@@ -4512,12 +4518,14 @@ class fq_zech(fq_elem):
class NumberField_nf(gr_ctx):
- def __init__(self, pol):
+ def __init__(self, pol, var=None):
pol = ZZx(pol)
# assert pol.is_irreducible()
gr_ctx.__init__(self)
libgr.gr_ctx_init_nf_fmpz_poly(self._ref, pol._ref)
self._elem_type = nf_elem
+ if var is not None:
+ self._set_gen_name(var)
class nf_elem(gr_elem):
_struct_type = nf_elem_struct
@@ -7521,11 +7529,36 @@ def test_mpoly():
assert str((x+1)*y**2 + (x+2)*y)
assert str((x+1)*y**2 - (x+2)*y) == "(x+1)*y^2 + (-x-2)*y"
+ assert str(FiniteField_fq(3, 2, "c").gen()) == "c"
+ assert str(FiniteField_fq_nmod(3, 2, "d").gen()) == "d"
+ assert str(FiniteField_fq_zech(3, 2, "e").gen()) == "e^1"
def test_mpoly_q():
assert str(FractionField_fmpz_mpoly_q(2).gens()) == '[x1, x2]'
assert str(FractionField_fmpz_mpoly_q(2, ["a", "b"]).gens()) == '[a, b]'
+def test_set_str():
+ assert RR("1/4") == RR(1)/4
+ v = RR("pi ^ (1 / 2)")
+ assert 1.77 < v < 1.78
+ assert CC("1/2 + i/4") == 0.5+0.25j
+ assert CC("(-1)^(1/2)") == 1j
+ assert CF("(-1)^(1/2)") == 1j
+ assert abs(RF("2^(1/2)") ** 2) - 2 < 1e-14
+ assert CC_ca("i*pi/2").exp() == CC_ca.i()
+
+ assert ZZ("1 + 2^10") == 1025
+ x = ZZx.gen(); R = PolynomialRing_gr_mpoly(NumberField(x**3+x+1), 3, ["x", "y", "z"])
+ a, x, y, z = R.gens(recursive=True)
+ assert R("((a-x+1)*y + (a^2+1)*y^2 + z)^2") == ((a-x+1)*y + (a**2+1)*y**2 + z)**2
+ x = ZZx.gen()
+ R = NumberField(x**2+1, "b")
+ assert R("b-1") == R.gen()-1
+
+ R = FractionField_fmpz_mpoly_q(2, ["x", "y"])
+ x, y = R.gens()
+ assert R("(4+4*x-y*(-4))^2 / (1+x+y) / 16") == 1+x+y
+
def test_ca_notebook_examples():
# algebraic number identity
NumberI = fexpr("NumberI")
@@ -7567,6 +7600,8 @@ def test_ca_notebook_examples():
for fname in dir():
if fname.startswith("test_"):
print(fname + "...", end="")
+ import sys
+ sys.stdout.flush()
t1 = time()
globals()[fname]()
t2 = time()