Artifact f709c1813495dbc426ac7a10692ac462014d0bae92766357a8b15ee5d94cbe4d:
- Executable file
r37/packages/poly/polydiv.red
— part of check-in
[f2fda60abd]
at
2011-09-02 18:13:33
on branch master
— Some historical releases purely for archival purposes
git-svn-id: https://svn.code.sf.net/p/reduce-algebra/code/trunk/historical@1375 2bfe0521-f11c-4a00-b80e-6202646ff360 (user: arthurcnorman@users.sourceforge.net, size: 6488) [annotate] [blame] [check-ins using] [more...]
- Executable file
r38/packages/poly/polydiv.red
— part of check-in
[f2fda60abd]
at
2011-09-02 18:13:33
on branch master
— Some historical releases purely for archival purposes
git-svn-id: https://svn.code.sf.net/p/reduce-algebra/code/trunk/historical@1375 2bfe0521-f11c-4a00-b80e-6202646ff360 (user: arthurcnorman@users.sourceforge.net, size: 6488) [annotate] [blame] [check-ins using]
module polydiv; % Enhanced polynomial division. % F.J.Wright@Maths.QMW.ac.uk, 6 Nov 1995. % Defines (or redefines) the following polynomial division operators: % divide, div and remainder (mod), % pseudo_divide, pseudo_quotient (pseudo_div) and pseudo_remainder. % However, for now, div has been commented out, since it conflicts with % other packages (avector and fide). % =================================================================== % Enhanced algebraic-mode operators for performing polynomial division % over the current coefficient domain, based on the operator REMAINDER % currently defined in poly.red by put('remainder,'polyfn,'remf); % divide(p,q) or p divide q returns an algebraic list {quotient, % remainder} of p divided by q as polynomials over the current domain. % div(p,q) or p div q returns only the quotient. % remainder(p,q) or p mod q returns only the remainder. % div and mod are the operator names used in Pascal for Euclidean % (integer) division. % An optional third argument (for the prefix forms) specifies the % variable to treat as the leading variable for the (effectively % univariate) polynomial division. % Interface code % ============== % Regular division: % ---------------- put('divide, 'psopfn, 'poly!-divide); symbolic procedure poly!-divide u; poly!-divide!*(u, nil, nil); remprop('remainder, 'polyfn); put('remainder, 'psopfn, 'poly!-remainder); put('mod, 'psopfn, 'poly!-remainder); % name from Pascal symbolic procedure poly!-remainder u; poly!-divide!*(u, 'remainder, nil); % put('div, 'psopfn, 'poly!-quotient); % name from Pascal symbolic procedure poly!-quotient u; poly!-divide!*(u, 'quotient, nil); infix divide, mod; % infix div; % Set a relatively low precedence: precedence divide, freeof; % higher than freeof, lower than + % precedence div, divide; % precedence mod, div; % Pseudo-division: % --------------- put('pseudo_divide, 'psopfn, 'pseudo!-divide); symbolic procedure pseudo!-divide u; poly!-divide!*(u, nil, t); put('pseudo_remainder, 'psopfn, 'pseudo!-remainder); symbolic procedure pseudo!-remainder u; poly!-divide!*(u, 'remainder, t); put('pseudo_div, 'psopfn, 'pseudo!-quotient); put('pseudo_quotient, 'psopfn, 'pseudo!-quotient); symbolic procedure pseudo!-quotient u; poly!-divide!*(u, 'quotient, t); fluid '(kord!*); symbolic procedure poly!-divide!*(u, fn, pseudo); % u = (p, q, x) % Returns the quotient and remainder of p (pseudo-)divided by q. % If specified, x is made the leading variable before dividing, % otherwise the first variable found is used. begin scalar p, q, x, new_kord; if null cdr u then RedErr "Divisor required"; if length u > 3 then RedErr "Division operators take 2 or 3 arguments."; if null (q := !*a2f cadr u) then RedErr "Zero divisor"; p := !*a2f car u; if cddr u and (x := !*a2k caddr u) and not(kord!* and x eq car kord!*) then << new_kord := t; updkorder x; p := reorder p; q := reorder q >> where kord!* = kord!*; % preserve environment u := if pseudo then pseudo!-qremf(p, q, x) else qremf(p, q); p := car u; q := cdr u; if new_kord then << if not(fn eq 'remainder) then p := reorder p; if not(fn eq 'quotient) then q := reorder q >>; return if fn eq 'remainder then mk!*sq (q ./ 1) else if fn eq 'quotient then mk!*sq (p ./ 1) else {'list, mk!*sq (p ./ 1), mk!*sq (q ./ 1)} end; % Pseudo-division code % ==================== symbolic procedure pseudo!-qremf(u, v, var); % Returns quotient and remainder of u pseudo-divided by v wrt var. % u and v are standard forms, var is a kernel or nil. % If var = nil then var := first kernel found. % Internally, polynomials are represented as coeff lists wrt var, % i.e. as lists of forms. % (Knuth 1981, Seminumerical Algorithms, Algorithm R, page 407.) begin scalar no_var, m, n, k, q0, q, car_v, car_u, vv; no_var := null var; m := if domainp u or (var and not(mvar u eq var)) then 0 else << if not var then var := mvar u; ldeg u >>; n := if domainp v or (var and not(mvar v eq var)) then 0 else << if not var then var := mvar v; ldeg v >>; %% The following special-case code for n = 0 and m < n is not %% necessary, but could be a cheap efficiency measure. %% if zerop n then return multf(exptf(v,m), u) . nil; %% if minusp(k := m - n) then return nil . u; u := if zerop m then {u} else coeffs u; v := if zerop n then {v} else coeffs v; if no_var and not(domainp_list v and domainp_list u) then msgpri("Main division variable selected is", var, nil, nil, nil); k := m - n; car_v := car v; while k >= 0 do << %% Compute the quotient q EFFICIENTLY. %% q0 = (q_0 ... q_k) without powers of v_n q0 := (car_u := car u) . q0; vv := cdr v; u := for each c in cdr u collect << c := multf(c, car_v); if vv then << c := subtrf(c, multf(car_u, car vv)); vv := cdr vv >>; c >>; k := k - 1 >>; if q0 then << %% Reverse q0 and multiply in powers of v_n: q := car q0 . nil; vv := 1; % v_n^0 while (q0 := cdr q0) do q := multf(car q0, (vv := multf(vv, car_v))) . q >>; return coeffs!-to!-form(q, var) . coeffs!-to!-form(u, var) end; symbolic procedure coeffs!-to!-form(coeff_list, var); % Convert a coefficient list in DESCENDING power order to a % standard form wrt the specified variable var: coeff_list and coeffs!-to!-form1(coeff_list, var, length coeff_list - 1); symbolic procedure coeffs!-to!-form1(coeff_list, var, d); if d > 0 then ( if car coeff_list then ((var .^ d) .* (car coeff_list)) .+ reductum else reductum ) where reductum = coeffs!-to!-form1(cdr coeff_list, var, d - 1) else car coeff_list; symbolic procedure domainp_list coeff_list; % Returns true if argument is a list of domain elements: null coeff_list or (domainp car coeff_list and domainp_list cdr coeff_list); endmodule; end;