#
# TableDistributedMultivariatePolynomial(R,X)
#
# A sparse distributed multivariate polynomial domain R[X] where
# R is a ring and E is an exponent vector.
#
# The representation is a Maple list of elements from R and X, i.e.
# The representation is a Maple table of elements from R and the
# indices are elements from X.
#
#    T[e[1]] := c[1]
#    T[e[2]] := c[2]
#    ...
#    T[e[n]] := c[n]
#
# Where the c[i] are from R and the e[i] are from X
# R must be a ring and X is an ordered abelian monoid hence defining an
# ordering on the terms: e[i] > e[j] for i > j
#
# Author DG: 1992
#
TableDistributedMultivariatePolynomial := proc()
local P,R,S,env; option remember;

    R := args[1];
    S := args[2];

    P := DistributedMultivariatePolynomial(R,S);
    P[DomainName] := TableDistributedMultivariatePolynomial;

    env := ['C' = R, 'D' = P, 'E' = S];
    # Rep [table('sparse', [ e[1] = c[1], ..., e[n] = c[n] ] )] 
    #    where c[k] in R and e[k] in S

    P[0] := TSDMP( table('sparse') );
    P[1] := TSDMP( table('sparse', [S[0]=R[1]]) );

    P[`+`] := subs(env, proc(a) `TSDMP/Add`(D,args) end);
    P[`*`] := subs(env, proc(a) `TSDMP/Mul`(D,args) end);

    P[`=`] := proc(a,b) evalb(op(2,eval(op(a)))=op(2,eval(op(b)))) end;

    P[Type] := proc(a) type(a, TSDMP( table ) ) end:

    P[Lcoeff] := subs(env, proc(a, t) local e;
        e := map(op, [indices(op(a))]);
        if e = [] then 
            if nargs=2 then t := E[0] fi; C[0] 
        else e := E[Max](op(e)); 
            if nargs=2 then t := e fi; op(a)[ e ] 
        fi
    end);
    P[Lterm] := subs(env, proc(a) local e,t;
        e := map(op, [indices(op(a))]);
        if e = [] then 
            t := D[0]
        else
            e := E[Max](op(e));
            t := table('sparse', [ e = op(a)[e] ] );
        fi;
        TSDMP( t )
    end);
    
    P[Coeff] := subs(env, proc(a,e) local c;
        c := op(a)[e]; if c = 0 then C[0] else c fi
    end);
    P[Degree] := subs(env, proc(a,n) local d,i,e,m;
        if not member(n,D[Variables],i) then ERROR(`bad variable`,n) fi;
        m := 0;
        for e in map(op, [indices(op(a))]) do
            d := E[Degree](e,i);
            if d > m then m := d fi;
        od;
        m
    end);
    P[List2Poly] := subs(env, proc(x) local i,a,c;
        a := table('sparse');
        for i to nops(x) do 
            if a[x[i][2]]=0 then c := x[i][1]
		else c := C[`+`](a[x[i][2]],x[i][1]) fi;
            if C[`=`](c,C[0]) then 
                a[x[i][2]] := evaln(a[x[i][2]])
            else 
                a[x[i][2]] := c 
            fi
        od;
        TSDMP(a)
    end);
    P[Poly2List] := proc(a) local e;
        [seq( [op(a)[e],e], e=map(op, [indices(op(a))]) ) ]
    end;

    if hasCategory(R,IntegralDomain) then
        # implementations of PseudoRem, Res
        # implementation of Unit, Div
    fi;

    if hasCategory(R,GcdDomain) then
        # implementation of Gcd
    fi;

    op(P)
end:

`TSDMP/Add` := proc(D,A,B) local plus, equal, zero, S, a,b,c, ae, be, ce, e;

    if nargs = 2 then RETURN(A) fi;
    if nargs > 3 then RETURN( procname(D,procname(D,A,B),args[4..nargs]) ) fi;

    plus := D[CoefficientRing][`+`];
    equal := D[CoefficientRing][`=`];
    zero := D[CoefficientRing][0];

    a := op(A): b := op(B):
    S := {op(map(op, [indices(a)])), op(map(op, [indices(b)]))};
    c := table('sparse'):
    for e in S do ae := a[e]; be := b[e];
        if ae = 0 or be = 0 then 
            c[e] := ae+be 
        else 
            ce := plus(ae,be);
            if not equal(ce, zero) then c[e] := ce fi
        fi
    od;
    TSDMP(c);
end:

`TSDMP/Mul` := proc(D,A,B)
local plus, mult, equal, zero, expplus, a, b, c, ea, eb, ec, cc;

    if nargs = 2 then RETURN(A) fi;
    if nargs > 3 then RETURN(procname(D,procname(D,A,B),args[4..nargs])) fi;
    if type(A,integer) then RETURN(procname(D,D[Coerce](A),args[3..nargs])) fi;

    plus := D[CoefficientRing][`+`];
    mult := D[CoefficientRing][`*`];
    equal := D[CoefficientRing][`=`];
    zero := D[CoefficientRing][0];
    expplus := D[ExponentVector][`+`];
    
    a := op(A): b := op(B): c := table('sparse');
    for ea in map(op, [indices(a)]) do
        for eb in map(op, [indices(b)]) do
            cc := mult(a[ea],b[eb]);
            if not equal(cc, zero) then
                ec := expplus(ea,eb);
                if c[ec]=0 then c[ec] := cc
                else cc := plus(c[ec], cc);
                    if equal(cc,zero) then c[ec] := evaln(c[ec]);
                    else c[ec] := cc
                    fi
                fi
            fi
        od
    od;
    TSDMP(c)
end:

save `TDMP.m`;
quit
