diff --git a/lib/convert.gi b/lib/convert.gi new file mode 100644 index 0000000..64d43ed --- /dev/null +++ b/lib/convert.gi @@ -0,0 +1,126 @@ +# Convert GAP polynomials to Singular polynomials in a given ring +# Args: Singular ring, GAP polynomial[, gensGAP, gensSI] +# +# By default, this guesses how to map the indeterminates based on +# their names. However, the user may also pass a list gensGAP of GAP +# indeterminates plus a list gensSI of Singular "indeterminates"; +# then gensGAP[i] is mapped to gensSI[i]. +# If this fails to specify for all indeterminates occurring in the +# polynomial f how they should be mapped, an error is raised. +# +# TODO: Do we really want the optional lists of generators as parameters, +# or should we leave this to methods of the Value() operation (see below)? +# TODO: Merge converter into SI_poly(?) / SI_FromGAP / SI_ToGAP, or at least +# make use of them there. +# Perhaps a more generic "type conversion" interface is needed... this +# is in fact something that affects more than just libsing. +# TODO: write test cases +# TODO: if gensGAP and gensSI are given, we could allow the user +# to omit the Singular ring, as we only ever need it to +# compute gensSI. +# +SI_polyFromGAP := function(arg) + local s, f, gensGAP, tmp, gensSI, fam, e, g, i, c, t, j, k; + + if not Length(arg) in [2, 4] then + Error("Wrong number of arguments, expected (siRing, gapPoly[, gensGAP, gensSI])"); + fi; + + s := arg[1]; + f := arg[2]; + e := ExtRepPolynomialRatFun(f); + + # TODO: verify that the coefficient rings of s and f match + # TODO: add support for coefficient rings beyond prime fields and integers + + if Length(arg) = 2 then + # User did not tell us how to map indeterminates. + # Make an educated guess based on the names of the indeterminates + + # Compute list of GAP indeterminates occurring in f + gensGAP := []; + for i in [1,3..Length(e)-1] do + UniteSet(gensGAP, e[i]{[1,3..Length(e[i])-1]}); + od; + + + # Map generators by name + tmp := SI_Indeterminates(s); + gensSI := []; + fam := CoefficientsFamily(FamilyObj(f)); + for i in [1..Length(gensGAP)] do + g := Indeterminate(fam, gensGAP[i]); + j := PositionProperty(tmp, x -> String(x) = String(g)); + if j = fail then + Error("Could not determine how to map indeterminates (",g," -> ?)\n"); + fi; + Add(gensSI, tmp[j]); + od; + else + gensGAP := arg[3]; + gensSI := arg[4]; + # TODO: those lists could contain strings (= variable names) + # or numbers (= generator indices), or actual polynomials consisting + # of a single indeterminate. + # Convert each of those to a uniform representation, + # namely ids for gensGAP and polynomials for gensSI. + Error("TODO"); + fi; + + g := Zero(s); + for i in [1,3..Length(e)-1] do + c := e[i+1]; + if IsFFE(c) then c := IntFFE(c); fi; + # TODO: the following code is sub-optimal + # Perhaps use this instead: + # SI_monomial(s,SI_intvec([1,2,3,4,...])); + t := One(s); + for j in [1,3..Length(e[i])-1] do + k := PositionSet(gensGAP, e[i][j]); + t := t * gensSI[k] ^ e[i][j+1]; + od; + g := g + c * t; + od; + + return g; +end; + +# Convert Singular polynomials to GAP polynomials +# Args: Singular polynomial[, gensSI, gensGAP] +# +# Note: No GAP polynomial ring is given, instead we "guess" the right +# coefficient domains. This should be enough, but perhaps not, in which +# case we should allow to optionally pass in a GAP ring as first argument. +# and map generators by name. +SI_polyToGAP := function(arg) + Error("TODO"); +end; + + +# Note: Both of these functions can also be viewed as variation of the +# GAP operation Value(), at least in the case where lists of generators +# are given. Its signatures: +# +# * Value( ratfun, indets, vals[, one] ) +# * Value( upol, value[, one] ) +# +# It can be used for conversion like this already now (at least for +# supported coefficient rings, which means char 0 right now): +# +# f := SOME GAP POLYNOMIAL; +# gensGAP := IndeterminatesOfPolynomialRing(R); +# gensSI := SI_Indeterminates(s); +# Value(f, gensGAP, gensSI); +# +# Conversely, we could install a Value method for Singular polynomials. +# It would of course be useful beyond conversion. + + +# Another approach: provide methods for +# PolynomialByExtRep(NC) / RationalFunctionByExtRep(NC) +# and +# ExtRepPolynomialRatFun / ExtRepNumeratorRatFun / ExtRepDenominatorRatFun +# then let the user convert between polynomials via these ext reps. +# +# Problem: these use families, not rings. +# Also, the result is more cumbersome for the user. diff --git a/lib/libsing.gi b/lib/libsing.gi index 7250488..295ceca 100644 --- a/lib/libsing.gi +++ b/lib/libsing.gi @@ -10,6 +10,31 @@ InstallMethod(SI_number,[IsSingularRing, IsInt],_SI_number); InstallMethod(SI_number,[IsSingularRing, IsFFE],_SI_number); InstallMethod(SI_number,[IsSingularRing, IsRat],_SI_number); +InstallMethod(SI_number,[IsSingularRing, IsZmodnZObj], +function( r, o ) + local c, s, m; + c := SI_char(r); + s := SI_size(r); + m := ModulusOfZmodnZObj(o); + # SI_size(r) # -1 for non-fields for now. + if c <> Characteristic(o) then + Error("Characteristic does not match"); + fi; + if s = -1 then + # Z/mZ + elif s = 0 then + # infinite + Error("TODO"); + elif IsPrimeInt(c) then + # As long as Singular does not implement rings like Z/pZ + Z/pZ, + # we may assume the ring r is a field + fi; + Error("TODO"); +end); + +# DeclareAttribute( "ModulusOfZmodnZObj", IsZmodnZObj ); + + InstallMethod(SI_intvec,[IsSingularObj],SI_intvec_singular); InstallMethod(SI_intvec,[IsList],_SI_intvec); diff --git a/src/poly.cc b/src/poly.cc index 89a5d9d..12df3f2 100644 --- a/src/poly.cc +++ b/src/poly.cc @@ -192,3 +192,29 @@ Obj Func_SI_MULT_POLY_NUMBER(Obj self, Obj a, Obj b) return tmp; } + + +#if 0 + if (IS_INTOBJ(val)) { + TODO + } else if (GAP bigint) { + TODO + } else if (gtype == SINGTYPE_BIGINT || gtype == SINGTYPE_BIGINT_IMM) { + TODO + } else if (gtype == SINGTYPE_NUMBER || gtype == SINGTYPE_NUMBER_IMM) { + TODO + p = p_NSet(_SI_NUMBER_FROM_GAP(r, coeff),r); + + } else if (gtype == SINGTYPE_POLY || gtype == SINGTYPE_POLY_IMM) { + if (r != CXXRING_SINGOBJ(val)) + ErrorQuit(" and must be defined over same ring.\n",0L,0L); + TODO + } else { + // Other GAP types must be explicitly cast via SI_number + // or SI_poly + ErrorQuit(" must be a polynomial.\n",0L,0L); + } + +// TODO: Implement SI_poly(ring, gap object) as generically as possible + +#endif diff --git a/src/singobj.cc b/src/singobj.cc index 9b48199..9a4aa95 100644 --- a/src/singobj.cc +++ b/src/singobj.cc @@ -54,6 +54,22 @@ number _SI_NUMBER_FROM_GAP(ring r, Obj n) return n_Init(i,r); #endif } + + // TODO: possibly use n_InitMPZ for bigints? + +// GF(p^n) with primitive root is stored as follows: +// label the elements a^0, a^1, ..., a^{q-2}, 0 +// as 0, 1, ..., q-2, q-2. +// Then to get the i-th element, just use (number)i + +// If, however, we constructed it using a minimal polynomial, +// then we must enter this as a polynomial over the ground field, +// and can use n_Normalize to normalize it. + +// for transcendental extensions, we describe elements +// as a pair of polynomials; by convention, if denominator +// is 1, then we use the NULL pointer for that. + if (rField_is_Zp(r)) { if (IS_INTOBJ(n)) { @@ -76,6 +92,179 @@ number _SI_NUMBER_FROM_GAP(ring r, Obj n) ErrorQuit("GAP numbers over this field not yet implemented.\n",0L,0L); return NULL; // never executed } + + +#if 0 + +// constructing algebraic or transcendental extensions of Z/pZ or Q or .. + + +TransExtInfo extParam +extParam.r = rDefault(characteristic, num_of_transcend_vars, names); +... free names etc. + +cf = nInitChar(n_transExt, &extParam); +// now construct polynomial ring +rDefault(cf, num_poly_vars, names); // and other variants.... + +// or algebraic: + + AlgExtInfo extParam; + extParam.r = extRing; + R->cf = nInitChar(n_algExt, (void*)&extParam); + // see also naInitChar + + + for other types of rings, see e.g. coeffs.h +#endif + + +/* +> ring r = (5,a); + ? error occurred in or before STDIN line 4: `ring r = (5,a);` + ? expected ring-expression. type 'help ring;' + ? last reserved name was `ring` + error at token `;` +> ring r = (5,a),x,dp; +> r; +// characteristic : 5 +// 1 parameter : a +// minpoly : 0 +// number of vars : 1 +// block 1 : ordering dp +// : names x +// block 2 : ordering C +> minpoly=a2-a+1; +> r; +// characteristic : 5 +// 1 parameter : a +// minpoly : (a2-a+1) +// number of vars : 1 +// block 1 : ordering dp +// : names x +// block 2 : ordering C +> a3; +-1 +> +. +. +. ; +> ring r2 = (integer,25),x,dp; +> r2; +// coeff. ring is : Z/25 +// number of vars : 1 +// block 1 : ordering dp +// : names x +// block 2 : ordering C +> 25x; +0 +> 24x; +24x +> 26x; +x +> +. +. ; +> ring r3 = (25,a),x,dp; +> r3; +// # ground field : 25 +// primitive element : a +// minpoly : 1*a^2+4*a^1+2*a^0 +// number of vars : 1 +// block 1 : ordering dp +// : names x +// block 2 : ordering C +> ring r4 = 25,x,dp; +// ** 25 is invalid as characteristic of the ground field. 32003 is used. +> ring r4 = (integer,5,2),x,dp; +// ** redefining r4 ** +> r4; +// coeff. ring is : Z/5^2 +// number of vars : 1 +// block 1 : ordering dp +// : names x +// block 2 : ordering C +> +. ; +> char(r3); +5 +> char(r2); +25 +> char(r1); + ? `r1` is not defined + ? error occurred in or before STDIN line 31: `char(r1);` +> char(r4); +25 +> char(r); +5 +> size(r); +25 +> size(r2); +-1 +> size(r3); +5 +> size(r4); +-1 +> char(r4); +> ring r5 = (integer,5,1),x,dp; +> r5; +// coeff. ring is : Z/5 +// number of vars : 1 +// block 1 : ordering dp +// : names x +// block 2 : ordering C +> size(r5); +-1 +> +> ring r6 = (0,a),x,dp; +> r6; +// characteristic : 0 +// 1 parameter : a +// minpoly : 0 +// number of vars : 1 +// block 1 : ordering dp +// : names x +// block 2 : ordering C + +*/ + + + + +/* + +#ifdef HAVE_RINGS +... +#else +#define rField_is_Ring(A) (0) +#define rField_is_Ring_2toM(A) (0) +#define rField_is_Ring_ModN(A) (0) +#define rField_is_Ring_PtoM(A) (0) +#define rField_is_Ring_Z(A) (0) +#define rField_is_Domain(A) (1) +#define rField_has_Units(A) (1) +#endif + +static inline BOOLEAN rField_is_Zp(const ring r) +static inline BOOLEAN rField_is_Zp(const ring r, int p) +static inline BOOLEAN rField_is_Q(const ring r) +static inline BOOLEAN rField_is_numeric(const ring r) // R, long R, long C +static inline BOOLEAN rField_is_R(const ring r) +static inline BOOLEAN rField_is_GF(const ring r) +static inline BOOLEAN rField_is_GF(const ring r, int q) +static inline BOOLEAN rField_is_long_R(const ring r) +static inline BOOLEAN rField_is_long_C(const ring r) + + +static inline BOOLEAN rField_has_simple_inverse(const ring r) + +/// Z/p, GF(p,n), R: nCopy, nNew, nDelete are dummies +static inline BOOLEAN rField_has_simple_Alloc(const ring r) + +/ +*/ + + // Here we know that the rationals are the coefficients: if (IS_INTOBJ(n)) { // a GAP immediate integer Int i = INT_INTOBJ(n); @@ -127,6 +316,7 @@ number _SI_BIGINT_FROM_GAP(Obj nr) number n = NULL; if (IS_INTOBJ(nr)) { // a GAP immediate integer Int i = INT_INTOBJ(nr); +// TODO: use NR_SMALL_INT_BITS instead of 28? if (i >= (-1L << 28) && i < (1L << 28)) n = nlInit((int) i,NULL); else