# FIELDS

# Implementation of an algorithm to calculate the transcendence degree of
# N|L and the degree [N=L] if the extension is finite, where N and L lie
# over the base field Q or an algebraic number field.

# Written by Gregor Kemper, 
# email kemper@kalliope.iwr.uni-heidelberg.de

# Aug 30, 1993

# This script defines the fields-package. If you want to install the package 
# right away,  set pathname:=<Directory where invar.m shall be put> 
# (with slash /).

macro(primdivs_in=fields[primdivs_in], extension=fields[extension], 
    normalform=fields[normalform], macaulay=fields[macaulay], 
    primdivs_in=fields[primdivs_in]);



# EXTENSION
# The main routine, calculating properties of extensions N|L lying over
# an algebraic number field K

extension:=proc(generators)
    local i,gens,rels,mipo,indep,spec,nonz,u,a,x,g,equ,vars,random,reorder,G,
        G_T,G_i,agent,trgrN,trgrL,deg,T,split,findarg,reduce;
    
    T:=time();
    
    split:=proc(M,V)
        local x,Y,N;
        Y:=NULL; N:=NULL;
        for x in M do if has(x,V) then Y:=Y,x else N:=N,x fi od;
        [[Y],[N]]
    end;
    
    findarg:=proc(token);
        (a,t)->
            type(a,`=`) and type(lhs(a),string) and substring(lhs(a),1..1)=t;
        select(",[args[2..nargs]],substring(token,1..1));
        if "=[] then 'FAIL' else rhs("[1]) fi
    end;
    
    reduce:=proc(baselist,vars)
        local i,j,n,last,span;
        n:=nops(baselist);
        last:=baselist[n];
        for i to n-1 do
            span:=grobner[gbasis]([baselist[i][],last[]],vars,plex);
            if span=baselist[i] then            # baselist[i] includes last
                RETURN([baselist[1..i-1],baselist[i+1..n]])
            elif span=last then RETURN([baselist[1..n-1]])
            fi
        od;
        baselist
    end;
        
    # Read and pre-process the arguments
    
    if type(generators,{list,set}) then G:=generators else G:=[generators] fi;
    gens:=NULL; i:=1;
    for x in G do
        if type(x,`=`) then gens:=gens,x
        else
            if assigned(g.i) then
                ERROR(``.(evaln(g.i)).` should be an unassigned name!`)
            fi;
            gens:=gens,g.i=x;
            i:=i+1
        fi
    od;
    gens:=[eval(gens)];
    x:=indets(map(rhs,gens)); g:=indets(map(lhs,gens));
    if not type(gens,list(name=ratpoly(rational))) or g intersect x <> {} 
                                                or nops(g)<>nops(gens) then
        ERROR(`Invalid first argument`)
    fi;
    
    rels:=findarg(rels,args);
    if rels<>'FAIL' then
        if not type(rels,{set,list}) then rels:=[rels] fi;
        rels:=[rels[]];
        x:=x union indets(rels);
        if not type(rels,list(polynom(rational))) or g intersect x <> {} 
            then ERROR(`Bad assignment for the relations`)
        fi;
        rels:=map(expand,rels);
    else rels:=[]
    fi;
    
    mipo:=findarg(mipo,args);
    if mipo<>'FAIL' then
        mipo:=expand(mipo);
        a:=indets(mipo)[];
        if nops([a])<>1 or not type(mipo,polynom(rational,a)) then
            ERROR(`Bad assignment for the minimal polynomial`)
        fi;
        x:=x minus {a}
    else mipo:=0
    fi;
    
    indep:=findarg(indep,args);
    if indep<>'FAIL' then
        if indep='all' then indep:=[$1..nops(g)]
        elif type(indep,nonnegint) and indep<=nops(g) then indep:=[$1..indep]
        elif type(indep,{set,list}) and {indep[]} minus {$1..nops(g)} ={} then
            indep:=[indep[]]
        else ERROR(
            `Bad assignment for what generators are supposed independent`)
        fi
    fi;
    
    spec:=findarg(spec,args);
    if spec<>'FAIL' then
        if spec='all' then spec:=[$1..nops(g)]
        elif type(spec,nonnegint) and spec<=nops(g) then spec:=[$1..spec]
        elif type(spec,{set,list}) and {spec[]} minus {$1..nops(g)} ={} then
            spec:=[spec[]]
        else ERROR(`Bad assignment for what generators to specialize`)
        fi
    fi;
    
    nonz:=findarg(nonz,args);
    if nonz<>'FAIL' then
        if not type(nonz,{set,list}) then nonz:=[nonz] fi;
        nonz:=[nonz[]];
        if not type(nonz,list(polynom(rational,[x[],a]))) then
            ERROR(`Bad assignment for non-zeroes`)
        fi;
        nonz:=map(expand,nonz)
    fi;
    
    agent:=findarg(agent,args);
    if agent<>'FAIL' and not member(agent,{'gbasis','Macaulay'}) then
            ERROR(`The "agent" must be 'gbasis' or 'Macaulay'`)
    fi;
    if agent='Macaulay' and not assigned(macaulay) then agent:='FAIL'
    elif agent='gbasis' then agent:=`'gbasis'`
    fi;
    
    if mipo<>0 then
        proc(e,m,a)
            subs(a=RootOf(m),rhs(e));
            evala(Normal("));
            lhs(e)=subs(RootOf(m)=a,")
        end
    else e->lhs(e)=normal(rhs(e))
    fi;
    gens:=map(",gens,mipo,a);
    if mipo<>0 then rels:=map(rem,rels,mipo,a) fi;
    
    `ext/out`(2,`Given Situation:`); `ext/out`(2);
    if mipo<>0 then `ext/out`(2,print,`K=Q(`.a.`) with`); 
    `ext/out`(2,print,mipo=`0,`)
    else `ext/out`(2,print,`K=Q,`)
    fi;
    `ext/out`(2);
    if rels<>[] then
        `ext/out`(2,print,
            cat(`N=K(`,x[1],seq(`,`.(x[i]),i=2..nops(x)),`) with`));
        `ext/out`(2,print,map(r->r=0,rels)[],``)
    else `ext/out`(2,print,cat(`N=K(`,x[1],seq(`,`.(x[i]),i=2..nops(x)),`),`))
    fi;
    `ext/out`(2);
    `ext/out`(2,print,cat(`L=K(`,g[1],seq(`,`.(g[i]),i=2..nops(g)),`) with`));
    `ext/out`(2,print,gens[]);
    `ext/out`(2);
    
    if nonz='FAIL' then
        # Calculate the prime divisors of the denominators of the g_i
        `ext/out`(
        `Calculating the prime divisors of the denominators of the g_i ...`);
        nonz:=primdivs_in(map(e->denom(rhs(e)),gens),mipo);
        `ext/out`(`... done`);
        `ext/out`(2,`They are:`);
        `ext/out`(2,print,nonz)
    else 
        `ext/out`(2,`Assumed non-zero:`);
        `ext/out`(2,print,nonz)
    fi;
    `ext/out`(2);
    
    equ:=[seq(nonz[i]*u[i]-1,i=1..nops(nonz)),rels[],
    seq(numer(rhs(gens[i]))-lhs(gens[i])*denom(rhs(gens[i])),i=1..nops(g))];
    if mipo<>0 then equ:=[equ[],mipo] fi;
    `ext/out`(3,`The equations are:`);
    `ext/out`(3,equ); `ext/out`(3);
    
    if indep<>'FAIL' then
        g:=g minus {seq(lhs(gens[indep[i]]),i=1..nops(indep))}
    fi;
    
    if spec<>'FAIL' then
        random:=rand(-100..100);
        [seq(lhs(gens[spec[i]])=random(),i=1..nops(spec))];
        equ:=subs(",equ);
        g:=g minus {map(lhs,"")[]};
        `ext/out`(`Specialize `.(nops(spec)).` of the generators of L`);
        `ext/out`(2,`Namely:`,"""[]); `ext/out`()
    fi;
    equ:=map(expand,equ);
    
    reorder:=readlib(`grobner/pplex/reorder`);
    x:=reorder(equ,x); if g<>{} then g:=reorder(equ,g) else g:=[] fi;
    if nops(nonz)>0 then reorder(equ,{seq(u[i],i=1..nops(nonz))}) else [] fi;
    vars:=["[],x[],g[]];
    map(convert,vars,string);
    `ext/out`(2,cat(`Take the term order with `,
        "[1],seq(` > `.("[i]), i=2..nops("))));
    `ext/out`(2);
    
    # Doing the Groebner basis calculation ...
    
    if agent<>'FAIL' then ``.agent.` c` else 'C' fi;
    `ext/out`(``.(").`alculating a Groebner basis of I ...`);
    if mipo<>0 then vars:=[vars[],a] fi;
    if agent='FAIL' then
        G:=grobner[gsolve](equ,vars)
    elif agent=`'gbasis'` then
        G:=grobner[gbasis](equ,vars,plex)
    else
        rand(31991); nextprime("());
        `ext/out`(`   (calculating modulo `.(").`)`);
        G:=macaulay(equ,",vars);
        nops(G);
        G:=[seq(G["-i],i=0.."-1)]
    fi;
    `ext/out`(`... done`); `ext/out`();
    
    if agent='FAIL' then
        i:=nops(G);
        if i=0 then G:=[[1]]
        elif i>1 then
            `ext/out`(`'gsolve' yielded `.i.` components!`);
            `ext/out`(3,`This is the result:`);
            `ext/out`(3,G); `ext/out`(3);
            `ext/out`(`Eliminating components that contain others ...`);
            do
                G:=reduce(G,vars);
                if nops(G)=i then break fi;     # No reduction was done
                i:=nops(G)
            od;
            if i=1 then 
                `ext/out`(
                `... Elimination was successful: Only one component left!`);
                `ext/out`()
            else
                `ext/out`(`... There are still multiple components left.`);
                `ext/out`(`Probably the ideal of relations isn't prime.`);
                `ext/out`(`Better rerun with 'agent=gbasis'!`);
                if type(args[nargs],name) then
                    `ext/out`(`Putting the bases into the last argument ...`);
                    assign(args[nargs],G)
                fi;
                RETURN(`MULTIPLE COMPONENTS`)
            fi
        fi;
        G:=G[1]
    fi;
    
    G:=select((p,m)->p<>m,G,mipo);
    `ext/out`(3,`The Groebner basis is`); `ext/out`(3,G); `ext/out`(3);
    
    if spec<>'FAIL' or agent='Macaulay' then `PROBABILISTIC ` else `` fi; 
    `ext/out`(``.(").`Results:`); `ext/out`();
    if G=[1] then
        if spec<>'FAIL' or indep<>'FAIL' or agent='Macaulay' then
            `ext/out`(
    `The supposedly algebraically independent g_i's were in fact dependent OR`)
        fi;
        `ext/out`(
            `Some power of the product of denominators of the g_i's lies`);
        `ext/out`(`    in the ideal spanned by the relations.`);
        RETURN('SINGULAR')
    fi;
    
    # Throw away equations for the u[i]
    G:=split(G,{seq(u[i],i=1..nops(nonz))})[2];
    
    # Calculate the G_i
    trgrN:=0;
    for i in x do
        split(G,i);
        G_i[i]:="[1]; G:=""[2];
        if G_i[i]=[] then trgrN:=trgrN+1; G_i[i]:=0
        else G_i[i]:=collect(G_i[i][nops(G_i[i])],i)
        fi
    od;
    if trgrN=0 then 
        deg:=product('degree(G_i[x[i]],x[i])', 'i'=1..nops(x));
        if deg=1 then `ext/out`(`L=N `)
        else `ext/out`(`N|L is algebraic of degree `.deg)
        fi
    else `ext/out`(`N|L has transcendence degree `.trgrN)
    fi;
    `ext/out`();
    `ext/out`(2,`Minimal polynomials:`); `ext/out`(2);
    for i in x do 
        if G_i[i]<>0 then `ext/out`(2,``.i.`:`); `ext/out`(2,print,G_i[i]) fi 
    od;
    
    G_T:=G;                             # What remains of G is G_T
    # The transcendence degree of L|K is calculated by splitting G_T
    trgrL:=nops(gens)-nops(g);
    for i in g do
        split(G,i);
        G:="[2]; if ""[1]=[] then trgrL:=trgrL+1 fi
    od:
    `ext/out`(`L|K has transcendence degree `.trgrL); `ext/out`();
    if G_T<>[] then
        `ext/out`(2,`Equations:`);
        `ext/out`(2,print,G_T[])
    fi;
    
    if type(args[nargs],name) then
        assign(args[nargs],[[G_T,g],[seq([G_i[x[i]],x[i]],i=1..nops(x))],mipo])
    fi;
    `ext/out`(2);
    if not member(agent,{'FAIL','Maple'}) then 
        ` sec (not counting the `.agent.`-time)`
    else ` sec`
    fi;
    `ext/out`(2,cat(`Time used: `,convert(time()-T,string),"));
    if trgrN=0 then RETURN(deg) else RETURN('TRANSCENDENT') fi
end:


# EXT/OUT
# Output of a piece of protocol

`ext/out`:=proc()
    local lev,narg,pl;
    
    if nargs>0 and type(args[1],integer) then
        lev:=args[1]; narg:=[args[2..nargs]]
    else lev:=1; narg:=[args]
    fi;
    if assigned(protocol_level) then pl:=protocol_level else pl:=1 fi;
    if pl<lev then RETURN() fi;
    if nops(narg)>0 and narg[1]=print then print(narg[2..nops(narg)])
    else lprint(narg[])
    fi;
    RETURN()
end:


# PRIMDIVS_IN
# The (non-constant) prime divisors contained in a set of polynomials

primdivs_in:=proc(polys,minpol)
    local a,p,res;
    
    readlib(factors); res:={};
    if nargs<2 or minpol=0 then
        for p in polys do
            factors(p);
            res:=res union {map(x->x[1],"[2])[]}
        od
    else
        a:=indets(minpol)[];
        for p in polys do
            factors(subs(a=RootOf(minpol),p),RootOf(minpol));
            subs(RootOf(minpol)=a,");
            res:=res union {map(x->x[1],"[2])[]}
        od
    fi;
    [res[]]
end:


# NORMALFORM
# Having calculated the minimal polynomials of a chain of fields leading from
# L to N, calculate the basis representation of an expr relative to these
# minimal polynomials

normalform:=proc(expr,basis)
    local gbas,num,den,ex,x,mipo,a;
    
    if not type(expr,ratpoly(rational)) then 
        ERROR(`Invalid first argument`)
    fi;
    if not type(basis,[[list,list],listlist,polynom]) then 
        ERROR(`Invalid second argument`)
    fi;
    
    gbas:=map(x->x[1],basis[2]);
    x:=map(x->x[2],basis[2]);
    mipo:=basis[3];
    if mipo<>0 then
        a:=indets(mipo)[];
        gbas:=[gbas[],mipo];
        x:=[x[],a]
    fi;
    
    if has(expr,a) then
        evala(Normal(subs(a=RootOf(mipo),expr)));
        ex:=subs(RootOf(mipo)=a,")
    else ex:=normal(expr)
    fi;
    
    num:=numer(ex); den:=denom(ex);
    if has(den,x) then 
        grobner[normalf](den,gbas,x,plex);
        if basis[1][1]<>[] then 
            map(grobner[normalf],
                [numer("),denom(")],basis[1][1],basis[1][2],plex);
            "[1]/"[2]
        fi;
        den:="
    fi;
    if den=0 then RETURN(`The result is 1/0`) fi;
    grobner[normalf](num,gbas,x,plex);
    if basis[1][1]<>[] then
        map(grobner[normalf],[numer("),denom(")],basis[1][1],basis[1][2],plex);
        "[1]/"[2]
    fi;
    "/den;
    if mipo<>0 then
        evala(Normal(subs(a=RootOf(mipo),")));
        subs(RootOf(mipo)=a,")
    fi;
    normal(")
end:


# MACAULAY
# Groebner-basis of 'Ideal' modulo a prime 'P'. This routine provides a partial
# interface to the computer algebra system Macaulay!
# All arguments but 'Ideal' are optional. 'Ideal' must be a set or list of
# polynomials.
# If 'P' is not given or =0, 31991 is taken. 
# The variables are 'Vars', default is Vars=indets(Ideal). If 'Vars' is a set,
# the variables are reordered.
# In this case, the reordered variables are written into 'nord', if present.
# Let indets(Ideal) minus Vars = {p1,...,pn}; the 'macaulay' calculates over
# the field GF(P)(p1,...,pn).
# 'monorder' can be 'plex' or 'tdeg', 'plex' as default.
# If 'change' is given and a name, it is assigned the matrix of change between
# 'Ideal' and the resulting groebner-basis.
# If 'flag'=preserve, the directory 'Transfer_to_Macaulay' is not removed.
#
# CAVEATS: when calling 'macaulay' with `;', for some the result isn't printed!
#   The same for any procedure using 'macaulay'!
#   The Macaulay-program must be accessable by the command `Macaulay'!

macaulay:=proc(Ideal,P,Vars,monorder,nord,change,flag)
    local i,j,n,m,var,lvars,v,lideal,homo,prep,defcon,sub,c,path,hb,vars,ideal,
        pars,reorder,ord,p;
    
    prep:=proc(fname,path)              # change { -> [ and } -> ] in file
        system(`sed s/\\{/\\[/g `.path.fname.` > `.path.
                    `/temp; sed s/\\}/\\]/g `.path.`/temp > `.path.fname.
                                                `; echo \\; >>`.path.fname)
    end;
    
    defcon:=proc(fname,vname)
                # read an expression from a file and write it into vname
        read fname;
        vname:="
    end;
    
    if assigned(x) then ERROR(`x should be an unassigned name!`) fi;
    ideal:=map(expand,Ideal);
    if nargs>=2 and P>0 then p:=P else p:=31991 fi;
    if nargs>=3 then vars:=Vars else vars:=indets(ideal) fi;
    if nargs>=4 then ord:=monorder else ord:=plex fi;
    pars:=indets(ideal) minus {vars[]};
    if "={} then reorder:=readlib(`grobner/iplex/reorder`); pars:=[]
    else reorder:=readlib(`grobner/pplex/reorder`); pars:=reorder(ideal,pars)
    fi;
    if type(vars,list) then vars:=vars
    else
        vars:=reorder(ideal,vars);
        if nargs>=5 then nord:=vars fi
    fi;
    
    var:=[vars[],pars[]];
    map(type,ideal,polynom(rational,var));
    if member(false,") then
        ERROR(
        `Argument 'ideal' must be a set or list of rational polynomials in`,
                                                                        var[])
    fi;
    hb:=false;
    path:=`Transfer_to_Macaulay`;
    if assigned(pathname) then path:=cat(pathname,path) fi;
    if system(`mkdir `.path)<>0 then    # Maybe another maple is doing the same
        for i to 10 do
            if system(`mkdir `.path.i)=0 then path:=``.path.i; break fi
        od;
        if i=11 then ERROR(`Couldn't make the Transfer-directory`) fi
    fi;

    n:=nops(var);
    lvars:=[seq(x[i],i=1..n)];
                            # meet Macaulay's requirements for variable-names
    m:=nops(ideal);
    lideal:=subs([seq(var[i]=lvars[i],i=1..n)],ideal);

    # is 'ideal' homogeneous or not?
    homo:=proc(f,var) 
        expand(2**degree(f,var)*f-subs(map(x->x=2*x,var),f))
    end;
    homo:=evalb(map(homo,{lideal[]},{lvars[]})={0});

    # produce input for Macaulay ...
    writeto(cat(path,`/InputFromMaple`));
    lprint(`ring R`);                                       # define the ring
    lprint(p);                                              # characteristic
    lprint(n);                                              # n indeterminates
    for v in lvars do lprint(v) od;
    lprint();                                               # all weights=1
    if ord=plex then                            # purely lexicographic order!
        if pars=[] then  lprint(1$n)
        else lprint(1$nops(vars),nops(pars))        # pars with total degree!
        fi
    else 
        if pars=[] then lprint()                # lex. order with total degree!
        else lprint(nops(vars),nops(pars))
                            # lex. order with tot. degree, but vars > pars!
        fi
    fi;
    lprint(`ideal I`);                                      # define the ideal
    lprint(m);                                              # m generators
    for i from 1 to m do
        if type(lideal[i],monomial) then lprint(lideal[i])
        else            # split into parts, otherwise lines will be chopped!
            lprint(op(1,lideal[i]),`\\`);
            for j from 2 to nops(lideal[i])-1 do
                    lprint(``+op(j,lideal[i]),`\\`) od;
            lprint(``+op(nops(lideal[i]),lideal[i]))
        fi
    od;
    if homo then
        if nargs>=6 and type(change,name) then
            lprint(`lift-std I b`);     # matrix of changes required, too
            lprint(`putchange b c`);
            lprint(`stdpart b hb !`);
            if pars<>[] then
                lprint(`stdpart b b x[1]..x[`.(nops(vars)).`]`);
                lprint(`prmat hb >`.path.`/OutputForMaple_hb`);
                                            # output in Mathematica-format!
                hb:=true
            else lprint(`putstd b b`)
            fi
        else
            lprint(`std I b`);                          # only grobner-basis
            lprint(`stdpart b b x[1]..x[`.(nops(vars)).`]`)
        fi
    else
        if nargs>=6 and type(change,name) then 
            lprint(`<maple/Macau/inhom I b hb c`);      # "My" modified script
            if pars<>[] then
                lprint(`stdpart b b x[1]..x[`.(nops(vars)).`]`)
            fi;
            lprint(`stdpart hb hb !`);
            lprint(`prmat hb >`.path.`/OutputForMaple_hb`);
            hb:=true
        else
            lprint(`<inhomog_std I b`);     # standard-script or inhom.
            if pars<>[] then
                lprint(`stdpart b b x[1]..x[`.(nops(vars)).`]`)
            fi
        fi
    fi;
    lprint(`prmat b >`.path.`/OutputForMaple_b`);
    if nargs>=6 and type(change,name) then 
            lprint(`prmat c >`.path.`/OutputForMaple_c`) fi;
    lprint('exit');
    writeto(terminal);
    
    # call Macaulay!!
    system(`csh -c 'Macaulay <`.path.`/InputFromMaple > `.path.`/output'`);
                                # "csh", since Bond-shells don't use aliases!
    if "=256 then
        if nargs<7 or flag<>'preserve' then system(`'rm' -r `.path) fi;                 
                                                    # remove Transfer-directory
        ERROR(`I couldn't find the Macaulay-program`)
    fi;
    
    if system(`chmod 666 `.path.`/OutputForMaple_b`)<>0 then # file existent?
        if nargs<7 or flag<>'preserve' then system(`'rm' -r `.path) fi;                 
                                                    # remove Transfer-directory
        ERROR(`Computation by Macaulay wasn't completed!`)
    fi;
    prep(`/OutputForMaple_b`,path);                 # lists, not sets, please!
    if nargs>=6 and type(change,name) then prep(`/OutputForMaple_c`,path) fi;
    if hb then prep(`/OutputForMaple_hb`,path) fi;
    
    defcon(cat(path,`/OutputForMaple_b`),'MacaulayResult_b');
    if nargs>=6 and type(change,name) then
        defcon(cat(path,`/OutputForMaple_c`),'MacaulayResult_c')
    fi;
    if hb then 
        defcon(cat(path,`/OutputForMaple_hb`),'MacaulayResult_hb')
    fi;
    sub:=[seq(lvars[i]=var[i],i=1..n)];
    if nargs>=6 and type(change,name) then
        c:=subs(sub,MacaulayResult_c);                  # Matrix of changes
        c:=[seq([seq(c[j][i],j=1..nops(c))],i=1..nops(c[1]))];  # transpose
        if not hb then change:=c
        else        # pick out lines that actually entered the grobner basis
            v:=NULL;
            for i from 1 to nops(c) do
                if member(MacaulayResult_hb[1][i],{op(op(MacaulayResult_b))})
                                                            then v:=v,c[i] fi
            od;
            change:=[v]
        fi
    fi;
    if nargs<7 or flag<>'preserve' then system(`'rm' -r `.path) fi;
                                            # remove Transfer-directory
    subs(sub,op(MacaulayResult_b))
end:



macro(extension=extension, normalform=normalform, primdivs_in=primdivs_in, 
    macaulay=macaulay);




# ******************************************************************* #
#                                                                     #
#                            The help-files                           #
#                                                                     #
# ******************************************************************* #



`help/text/fields`:=TEXT(
    ``,
    `HELP FOR: The fields package`,
    ``,
    `SYNOPSIS:`,
    `- The fields package is a package of routines for investigating the algebraic `,
    `  or transcendental nature of field extensions N|L lying over a ground field K, `,
    `  which is either the field Q of the rationals or an algebraic number field.`,
    ``,
    `- The functions available are:`,
    ``,
    `               extension, macaulay, normalform, and primdivs_in.`,
    `  `,
    `  The function 'macaulay' only works if the computer algebra system Macaulay is `,
    `  installed on the host machine.`,
    ``,
    `- To get help for particular functions type ?<function> or ?fields,<function>`,
    `  The main routine is 'extension'. See ?extension for what it does.`,
    `  Not all of the routines check the validity of their arguments. 'extension' `,
    `  does thoroughly, though.`,
    ``,
    `- The algorithms used are described (and proved valid) in the paper "An `,
    `  Algorithm to Determine Properties of Field Extensions Lying over a Ground `,
    `  Field" which should come along with the package as a LaTeX- or .dvi-file.`,
    ``,
    `- The fields package was written by Gregor Kemper, e-mail`,
    `  kemper@kalliope.iwr.uni-heidelberg.de`,
    ``,
    `SEE ALSO:  with, extension`
    ):
`help/fields/text/fields`:=`help/text/fields`:
`help/text/extension`:=TEXT(
    ``,
    `FUNCTION: extension - calculations on an extension N|L over a ground field K`,
    `   `,
    `CALLING SEQUENCE:`,
    `   extension(generators,...,'basis');`,
    `   `,
    `PARAMETERS:`,
    `   generators  - A set or list of equations or expressions defining the `,
    `                 generators of L as rational functions in the generators of N.`,
    `   'basis'     - (optional) last argument: a name where the complete result `,
    `                 shall be put (see below).`,
    `   ...         - several optional equations which constitute assignments for `,
    `                 parameters, which can include (in any order):`,
    `   `,
    `   relations=r,  with r a polynomial or a set or list of polynomials in the `,
    `                 generators of N, defining relations in N,`,
    `   minpol=m,     with m a univariate, irreducible polynomial over the rationals `,
    `                 defining an algebraic number field,`,
    `   indep=l,      with l a list of non-negative integers telling the function `,
    `                 which of the generators of L to assume algebraically `,
    `                 independent. See below for further explanation. `,
    `                 If l is just a positive integer, it is expanded to [1,...,l], `,
    `                 and if it is the string 'all', then all generators are `,
    `                 assumed independent.`,
    `   spec=l,       to tell the function which of the generators of L it shall `,
    `                 specialize to random values in order to get quicker `,
    `                 probabilistic results (see below).`,
    `                 The syntax is the same as for 'indep'.`,
    `   nonz=n,       with n a polynomial or a set or list of polynomials in the `,
    `                 generators of N, telling the function to use other non-zero `,
    `                 expressions than the standard ones.`,
    `   agent=sys,    with sys being one of the strings 'gbasis' or 'Macaulay', `,
    `                 telling the function which agent shall do the Groebner basis `,
    `                 calculation. The last option refers to the computer algebra `,
    `                 system Macaulay (see ?macaulay).`,
    `   `,
    `SYNOPSIS:`,
    `- Let K be the field of rationals or an algebraic number field, and let N be a `,
    `  finitely generated field over K with generators x_1,...,x_n. Let `,
    `  (r_1,...,r_s) be the kernel of`,
    `                     K[X_1,...,X_n] -> N, X_i -> x_i.`,
    `  `,
    `  Let L be a field between K and N, generated by a_1,...,a_m with `,
    `  a_i = g_i(x_1,...,x_n). Then 'extension' calculates the transcendence degree `,
    `  of N|L  and of L|K, and the degree [N:L] if the extension is algebraic.`,
    ``,
    `- On its way, 'extension' produces more information than that which can be `,
    `  passed to the user by the last argument 'basis'. Namely, it reorders the x_i `,
    `  in some way, say x_p(1),...,x_p(n) and then for each i calculates minimal `,
    `  polynomial f_i for x_p(i) over`,
    `  `,
    `                     L_(i-1):=L(x_p(1),...,x_p(i-1)),`,
    `  `,
    `  or f_i=0 if L_i|L_(i-1) is transcendent.`,
    `  Secondly, 'extension' produces a lexicographic Groebner basis for the kernel `,
    `  of`,
    `                   K[T_1,...,T_m] -> L, T_i -> a_i.`,
    ``,
    `- For a thorougher description of what 'extension' does and of the algorithm `,
    `  used (with a proof of validity), consider the paper "An Algorithm to `,
    `  Determine Properties of Field Extensions Lying over a Ground Field" which `,
    `  should come along with the fields package as a LaTeX- or .dvi-file.`,
    ``,
    `- The first argument of 'extension' is a set or list of equations relating a `,
    `  name for a generator of L to its value, which is a rational polynomial in the `,
    `  x_i. If the i'th entry is NOT an equation (which the user might choose to `,
    `  do), it is expanded to gi=... The x_i's themselves are taken to be the `,
    `  indeterminates occurring in the generators and in the relations, apart from `,
    `  the (possible) indeterminate which generates K over Q.`,
    ``,
    `- The assignments for relations, minpol, spec and agent are recognized by their `,
    `  first letters, so an argument 'relations=[x1**2+x2**2]' has the same effect `,
    `  as 'rumpelstielzchen=[x1**2+x2**2]'.`,
    ``,
    `- The return value of 'extension' is the degree [N|L] or the string `,
    `  'TRANSCENDENT' (or two more strings marking special events). 'extension' `,
    `  returns its complete result by assigning a list of three entries to the `,
    `  optional last argument 'basis'. The first entry, a list itself, contains a `,
    `  Groebner basis for the relations among the a_i and the ordering of T_i's `,
    `  used, according to Maple's 'plex'-standard. The second entry is a list of the `,
    `  polynomials f_i (in reversed order), together with the x_p(i). (Remember f_i `,
    `  is a minimal polynomial for x_p(i) over L_(i-1).) The third is the minimal `,
    `  polynomial for K|Q, or 0 if K=Q.`,
    ``,
    `- 'extension' prints out some protocol during execution which lets the user `,
    `  follow the steps taken. If you want more protocol, set the global variable `,
    `  protocol_level to a value greater than 1, and if you want none, set it to 0.`,
    ``,
    `- The really hard part of the algorithm is the computation of a Groebner basis `,
    `  for a system that involves the x_i's and T_i's. Experience shows that it `,
    `  usually saves time to treat as many as possible of the T_i's as parameters `,
    `  during this calculation, i.e. they are considered as indeterminates lying in `,
    `  the ground field over which the Groebner basis is calculated. But this `,
    `  requires that the corresponding a_i's be algebraically independent for `,
    `  otherwise the Groebner basis will simply collapse to [1]. Since the user is `,
    `  the only one who can make any reasonable assumptions about algebraic `,
    `  independence of any a_i's, he/she must tell 'extension' explicitly which of `,
    `  the T_i's to treat that way. 'extension' supports this option by the `,
    `  assignment for 'indep'.`,
    ``,
    `- Another idea to decrease the computational cost is to specialize some of the `,
    `  T_i's to random values in order to get good probabilistic results for the `,
    `  transcendence degrees and for [N:L], if finite. This can be done by the `,
    `  assignment for 'spec'. Once again, you should only specialize T_i's for which `,
    `  you believe that the corresponding a_i's are algebraically independent, `,
    `  otherwise the system of equations is bound to collapse.`,
    `  In my experience, I never ever got a wrong result from this specializing `,
    `  business!`,
    ``,
    `- Experience has shown that it is quicker to use the 'gsolve'-routine of Maple `,
    `  for the calculation of the Groebner basis. 'gsolve' might yield a handful of `,
    `  bases G_j, though, and in that case 'extension' tries to eliminate all but `,
    `  one (say G_i) of them by showing that the ideal spanned by G_j includes the `,
    `  ideal spanned by G_i for all j. If that won't work, then probably the ideal `,
    `  spanned by the relations wasn't prime, and the computation is abandoned. On `,
    `  the other hand, if ideal spanned by the relations wasn't prime, there is no `,
    `  warranty that this will be discovered, and while using 'gsolve', 'extension' `,
    `  might finish with a wrong result. The user has the option of making `,
    `  'extension' use the 'gbasis' routine of Maple by assigning 'gbasis' to `,
    `  'agent', though.`,
    ``,
    `- 'extension' can hand over the Groebner calculation to the computer algebra `,
    `  system Macaulay which is very quick but only does calculations modulo some `,
    `  prime, so the result will be probabilistic even without specializing any T_i. `,
    `  Macaulay has to be installed on your host system, of course (see ?macaulay).`,
    ``,
    `- In the course of calculation, 'extension' calculates the prime polynomials `,
    `  d_i which occur as divisors of the denominators of the g_j, and then uses `,
    `  the equations d_i*u_i-1 to rule out solutions for which some denominator of a `,
    `  g_j is zero. As is pointed out in my paper, these d_i can be any polynomials `,
    `  in the x_i such that for their product d there is a natural number n_0 which `,
    `  makes d^n_0 a multiple of all the denominators. Experience has shown that `,
    `  usually the above choice of the d_i maximizes the speed (although there are a `,
    `  lot of additional variables); but if you feel that another choice might be `,
    `  better, you can supply it by assigning a set or list containing your d_i's to `,
    `  'nonz'. Of course these needn't even satisfy the above condition, but then `,
    `  there is absolutely no warranty as for the results!`,
    ``,
    `- extension is part of the fields package.`,
    ``,
    `EXAMPLES:`,
    `> with(fields):`,
    `> protocol_level:=2:`,
    `> extension({x/y,(x^2+y^2)/x^2},'basis');`,
    `Given Situation:`,
    ``,
    `                                      K=Q,`,
    ``,
    ``,
    `                                   N=K(x,y),`,
    ``,
    ``,
    `                                L=K(g1,g2) with`,
    ``,
    `                                             2    2`,
    `                                            x  + y`,
    `                             g1 = x/y, g2 = -------`,
    `                                                2`,
    `                                               x`,
    ``,
    ``,
    `Calculating the prime divisors of the denominators of the g_i ...`,
    `... done`,
    `They are:`,
    `                                     [x, y]`,
    ``,
    ``,
    `Take the term order with u[1] > u[2] > x > y > g1 > g2`,
    ``,
    `Calculating a Groebner basis of I ...`,
    `... done!`,
    ``,
    `Results:`,
    ``,
    `N|L has transcendence degree 1`,
    ``,
    `Minimal polynomials:`,
    ``,
    `x:`,
    `                                    x - g1 y`,
    ``,
    `L|K has transcendence degree 1`,
    ``,
    `Equations:`,
    `                                       2     2`,
    `                               - 1 - g1  + g1  g2`,
    ``,
    ``,
    `Time used: 2.667 sec`,
    `                                  TRANSCENDENT`,
    ``,
    `> basis;`,
    ``,
    `                    2     2`,
    `         [[[- 1 - g1  + g1  g2], [g1, g2]], [[x - g1 y, x], [0, y]], 0]`,
    ``,
    `> `,
    `> # The next example verifies a solution of Noether's problem for A4 ...`,
    `> protocol_level:=1:`,
    `> rel:=d^2-discrim(x^4+s2*x^2-s3*x+s4,x);`,
    ``,
    `rel :=`,
    ``,
    `     2       3   2        4           4         2   2            2            3`,
    `    d  + 4 s2  s3  + 27 s3  - 16 s4 s2  + 128 s4  s2  - 144 s2 s3  s4 - 256 s4`,
    ``,
    `> gens:={T1=s3/s2,T2=s4/s2^2,T3=(d-3*a*s3^2)/s2^3}; mipo:=a^2+3;`,
    ``,
    `                                        2`,
    `                              d - 3 a s3         s3         s4`,
    `                gens := {T3 = -----------, T1 = ----, T2 = ---}`,
    `                                    3            s2          2`,
    `                                  s2                       s2`,
    ``,
    `                                           2`,
    `                                 mipo := a  + 3`,
    ``,
    `> extension(gens,relations=rel,minpol=mipo,indep=all);`,
    `Calculating the prime divisors of the denominators of the g_i ...`,
    `... done`,
    `Calculating a Groebner basis of I ...`,
    `... done!`,
    ``,
    `Results:`,
    ``,
    `N|L is algebraic of degree 1`,
    ``,
    `L|K has transcendence degree 3`,
    ``,
    `                                       1`,
    ``,
    `> # This means that all of N is generated by T1,T2 and T3!`,
    ``,
    `SEE ALSO:  fields`
    ):
`help/fields/text/extension`:=`help/text/extension`:
`help/text/normalform`:=TEXT(
    `FUNCTION: normalform - a normal form of an element of N`,
    `   `,
    `CALLING SEQUENCE:`,
    `   normalform(expr,basis);`,
    `   `,
    `PARAMETERS:`,
    `   expr  - a (multivariate) rational function with rational coefficients`,
    `   basis - a list containing information about N|L as computed by 'extension'`,
    ``,
    `SYNOPSIS:`,
    `- The routine 'extension' produces a tower of fields L_i leading from L to N, `,
    `  and for each extension L_i over L_(i-1) a minimal polynomial f_i if the `,
    `  extension is algebraic. (See ?extension or the paper which should come along `,
    `  with the fields package as a LaTeX- or .dvi-file.) So each element of N has a `,
    `  normal form as a polynomial in the generating element x_p(i) over L_(i-1) of `,
    `  degree less than [L_i : L_(i-1)], or as a rational function in x_p(i) over `,
    `  L_(i-1). Descending along the tower from N to L yields a normal form for an `,
    `  element of N. 'normalform' calculates this normal form for elements of `,
    `  K[x_1,...,x_n]. For fractions, the quotient of the normal form of the `,
    `  numerator over that of the denominator is returned.`,
    ``,
    `- In particular, this provides a membership test for L: If 'expr' lies in L `,
    `  then 'normalform' returns a representation of 'expr' in terms of the `,
    `  a_1,...,a_m. (Again, for notation see ?extension)`,
    ``,
    `- The normal form of an element of N as returned by 'normalform' need not be `,
    `  unique. Zero is always recognized, though.`,
    ``,
    `- Rational functions with coefficients in N are also handled.`,
    ``,
    `- The second argument, 'basis', has exactly the syntax that 'extension' uses `,
    `  when writing its result in the last, optional argument, so you don't have to `,
    `  worry much about it.`,
    `  It is a list of three elements. The first one is a list containing, first, a `,
    `  Groebner basis for the relations among the a_i's and, second, the term order `,
    `  used for this basis, given as a list starting with the highest variable. The `,
    `  second element of 'basis' is the list of minimal polynomials of L_i|L_(i-1), `,
    `  starting with the one for N over L_(n-1). Each minimal polynomial is given as `,
    `  a list of the minimal polynomial itself (or 0 if the extension is `,
    `  transcendental) plus the variable X_p(i) that this polynomial is in. The `,
    `  third element of 'basis' is the minimal polynomial specifying the ground `,
    `  field K as an algebraic number field, or 0 if K=Q.`,
    ``,
    `- normalform is part of the fields package.`,
    ``,
    `EXAMPLES:`,
    `> with(fields):`,
    `> gens:={s=x+y,p=x*y,q=x/y};`,
    ``,
    `                     gens := {s = x + y, p = x y, q = x/y}`,
    ``,
    `> extension(gens,'basis');`,
    `Calculating the prime divisors of the denominators of the g_i ...`,
    `... done`,
    `Calculating a Groebner basis of I ...`,
    `... done`,
    ``,
    `'gsolve' yielded 2 components!`,
    `Eliminating components that contain others ...`,
    `... Elimination was successful: Only one component left!`,
    ``,
    `Results:`,
    ``,
    `L=N `,
    ``,
    `L|K has transcendence degree 2`,
    ``,
    `                                       1`,
    ``,
    `> basis;`,
    ``,
    `                                      2    2`,
    `                  [[[- 2 q p - p + q s  - q  p], [s, p, q]],`,
    ``,
    `                      [[x + y - s, x], [(q + 1) y - s, y]], 0]`,
    ``,
    `> normalform(x,basis);`,
    ``,
    `                                      s q`,
    `                                     -----`,
    `                                     q + 1`,
    ``,
    `> # Check this ...`,
    `> normal(subs(gens,"));`,
    ``,
    `                                       x`,
    ``,
    `SEE ALSO:  fields, extension`
    ):
`help/fields/text/normalform`:=`help/text/normalform`:
`help/text/primdivs_in`:=TEXT(
    `FUNCTION: primdivs_in - The prime divisors contained in a set of polynomials`,
    `   `,
    `CALLING SEQUENCE:`,
    `   primdivs_in(polys,minpol);`,
    `   `,
    `PARAMETERS:`,
    `   polys  - a set or list of (multivariate) polynomials with rational `,
    `                                                            coefficients`,
    `   minpol - (optional) rational polynomial defining the ground field K`,
    ``,
    `SYNOPSIS:`,
    `- 'primdivs_in' returns a list of the (non-constant) prime polynomials `,
    `  occurring as divisors of the polynomials in 'polys'.`,
    ``,
    `- The ground field K is an algebraic number field given by a generating `,
    `  polynomial 'minpol' over Q, or K=Q.`,
    ``,
    `- primdivs_in is part of the fields package.`,
    ``,
    `EXAMPLES:`,
    `> primdivs_in([x^4-y^4,x^3-y^3],a**2+1);`,
    ``,
    `                                2          2`,
    `                [x - y, x + y, x  + x y + y , x - a y, x + a y]`,
    ``,
    `SEE ALSO:  fields`,
    ``
    ):
`help/fields/text/primdivs_in`:=`help/text/primdivs_in`:
`help/text/macaulay`:=TEXT(
    `FUNCTION: macaulay - partial interface to the computer algebra system Macaulay`,
    `   `,
    `CALLING SEQUENCE:`,
    `   macaulay(Ideal,P,Vars,monorder,nord,change,flag);`,
    `   `,
    `PARAMETERS:`,
    `   Ideal    - the ideal, a set or list of multivariate polynomials`,
    `   P        - (optional) prime number giving the modulus (default 31991)`,
    `   Vars     - (optional) variables to calculate with (default  indets(Ideal) )`,
    `   monorder - (optional) term order ('plex' or 'tdeg', with 'plex' as default)`,
    `   nord     - (optional) name where the reordered variables are put`,
    `   change   - (optional) name where the transition matrix between Ideal and the `,
    `                                                          Groebner basis is put `,
    `   flag     - (optional) flag, can be 'preserve' such that the directory `,
    `                                         'Transfer_to_Macaulay' is not removed`,
    ``,
    `SYNOPSIS:`,
    `- 'macaulay' computes a Groebner basis of 'Ideal' modulo 'P' by invoking the `,
    `  computer algebra system Macualay which does the calculation. The data `,
    `  transfer is performed through temporary files.`,
    ``,
    `- The Macaulay program must be installed and accessible by calling  Macaulay.`,
    `  The system can be optained via anonymous ftp from the server`,
    `                             zariski.harvard.edu.`,
    `  It is the fastest system for Groebener basis calculations modulo p that I `,
    `  know.`,
    ``,
    `- CAVEAT: Even when calling macaulay with a ";", for some reason the result `,
    `  isn't displayed.`,
    ``,
    `- macaulay is part of the fields package.`,
    ``,
    `SEE ALSO:  fields`
    ):
`help/fields/text/macaulay`:=`help/text/macaulay`:





# ******************************************************************* #
#                                                                     #
#                               SAVE IT                               #
#                                                                     #
# ******************************************************************* #




#    save fields,
#         `help/text/fields`, `help/fields/text/fields`,
#         `help/text/extension`, `help/fields/text/extension`,
#         `help/text/normalform`, `help/fields/text/normalform`,
#         `help/text/primdivs_in`, `help/fields/text/primdivs_in`,
#         `help/text/macaulay`, `help/fields/text/macaulay`,
#         `ext/out`,
#         `fields.m`:
#quit





# ******************************************************************* #
#                                                                     #
#                               THE END                               #
#                                                                     #
# ******************************************************************* #
