Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement more type conversions #9

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions lib/convert.gi
Original file line number Diff line number Diff line change
@@ -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.
25 changes: 25 additions & 0 deletions lib/libsing.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
26 changes: 26 additions & 0 deletions src/poly.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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("<obj> and <val> 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("<val> must be a polynomial.\n",0L,0L);
}

// TODO: Implement SI_poly(ring, gap object) as generically as possible

#endif
190 changes: 190 additions & 0 deletions src/singobj.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down