https://cs.uwaterloo.ca/~smwatt
11email: smwatt@uwaterloo.ca
Efficient Quotients of Non-Commutative Polynomials
Abstract
It is shown how to compute quotients efficiently in non-commutative univariate polynomial rings. This extends earlier work where efficient generic quotients were studied with a primary focus on commutative domains. Fast algorithms are given for left and right quotients of polynomials where the variable commutes with coefficients. These algorithms are based on the concept of the “whole shifted inverse”, which is a specialized quotient where the dividend is a power of the polynomial variable. It is also shown that when the variable does not commute with coefficients, that is for skew polynomials, left and right whole shifted inverses are defined and may be used to compute right and left quotients. In this case their computation is not asymptotically fast, but once obtained, they may be used to compute multiple quotients, each with one multiplication. Examples are shown of polynomials with matrix coefficients, differential operators and difference operators. In addition, a proof-of-concept generic Maple implementations is given.
1 Introduction
In symbolic mathematical computation it is important to have efficient algorithms for the fundamental arithmetic operations of addition, multiplication and division. While linear time algorithms for additive operations are usually straightforward, considerable attention has been devoted to find efficient methods to compute products and quotients of integers, polynomials with integer or finite field coefficients and matrices with elements from a ring. For these, both practically efficient algorithms and theoretically important bounds are well known.
For integer and polynomial division, efficient algorithms based on Newton iteration allow the computation of quotients in time proportional to multiplication. Until recently, these algorithms left the original domain to perform arithmetic in related domains. For integers, this involved computing an approximation to the inverse of the divisor in extended precision approximate arithmetic or in a residue ring, and for polynomials it involved computing the inverse of the reverse of the divisor polynomial in ideal-adic arithmetic.
We have recently shown how these quotients may be computed without leaving the original domain, and we have extended this to a generic domain-preserving algorithm for rings with a suitable whole shift operation [10]. For integers the whole shift multiplies by a power of the representation base and for polynomials it multiplies by a power of the variable, in both cases discarding terms with negative powers. The previous paper developed the concept of the whole shifted inverse and used it to compute quotients efficiently. Non-commutative domains were mentioned only briefly.
The present article expands on how these methods may be used to compute quotients of non-commutative polynomials. In particular, it is shown that
-
the whole shifted inverse is well-defined on non-commutative polynomial rings ,
-
its computation is efficient,
-
they may be used to compute left or right quotients in , each with one multiplication,
-
left and right whole shifted inverses may be defined on skew polynomials , and
-
they may be used to compute the right and left quotients in , each with one multiplication.
The remainder of this article is organized as follows. Section 2 presents some basic background, including notation, the definition of division in a non-commutative context, and the Newton-Schulz iteration. Section 3 considers division of non-commutative polynomials in , showing algorithms for classical division and for pseudodivision. It recalls the notion of the whole shifted inverse, proves it is well-defined on non-commutative and shows that it can be used to compute left and right quotients in this setting. Section 4 recapitulates the generic algorithms from [10] that use a modified Newton iteration to compute the whole shifted inverse. It also explains why it applies when polynomial coefficients are non-commutative. Section 5 gives an example of these algorithms applied to polynomial matrices. Section 6 extends the discussion to skew polynomials , defining left and right whole shifted inverse, and showing how they may be used. Section 7 gives linear ordinary differential and difference operators as examples, before concluding remarks in Section 8.
2 Background
2.1 Notation
We adopt the following notation:
number of base- digits of an integer ,
number of coefficients of a polynomial ,
quotient and remainder (see below)
left and right (pseudo)quotient and remainder,
,
whole shift and whole shifted inverse (see below)
,
skew polynomials (see Section 6)
,
coefficient of skew polynomial with variable powers on the left, right.
,
left and right whole shift and shifted inverse, (see Section 6)
value of at iteration
The “” notation, standing for “precision”, means the number of base- digits or polynomial coefficients. It is similar to that of [4], where it is used to present certain algorithms generically for integers and polynomials.
In particular, if we take integers to be represented in base-, i.e. for any integer there is , such that
(1) |
then integers base- behave similarly to univariate polynomials with coefficients , but with carries complicating matters.
2.2 Division
The notion of integer quotients and remainders can be extended to more general rings. For a Euclidean domain with valuation , such that for any , there exist such that
The value is a quotient of and and is a remainder of dividing by and we write
when these are unique. When both the quotient and remainder are required, we write . When is a non-commutative ring with a valuation , there may exist left and right quotients such that
(2) | ||||||
When these exist and are unique, we write
For certain non-commutative rings with a distance measure , a sequence of approximations to the inverse of may be computed via the Newton-Schulz iteration [7]
(3) |
where denotes the multiplicative identity of the ring. There are several ways to arrange this expression, but the form above emphasizes that as approaches , the product approaches . For matrices, a suitable initial value is , where is the Hermitian transpose.
2.3 Whole Shift and Whole Shifted Inverse
In previous work [10] we studied the problem of efficient domain-preserving computation of quotients and remainders for integers and polynomials, then generalized these results to a generic setting. To this end, we defined the notions of the whole shift and whole shifted inverse with attention to commutative domains. We recapitulate these definitions and two results relevant to the present article.
Definition 1 (Whole -shift in )
Given a polynomial , with a ring and , the whole -shift of with respect to is
(4) |
When is clear by context, we write .
Definition 2 (Whole -shifted inverse in )
Given and , a field, the whole -shifted inverse of with respect to is
(5) |
When is clear by context, we write ,
Theorem 1
Given two polynomials , a field, and ,
(6) |
For classical and Karatsuba multiplication it is more efficient to compute just the top part of the product in (6), omitting the lower terms, instead of shifting:
with computing only terms. For multiplication methods where computing only the top part of the product gives no saving, some improvement is obtained using
Theorem 2
Given , with a field and and suitable starting value , the sequence of iterates
converges to in steps.
A suitable starting value for is given by Shinv0 in Section 4.
3 Division in Non-Commutative
We now lay out how to use and to compute quotients for polynomials with non-commutative coefficients. First we show classical algorithms to compute left and right quotients in . We then prove two theorems, one showing that in this setting, making the whole shifted inverse well defined, and another showing that it may be used to compute left and right quotients.
3.1 Definitions and Classical Algorithms
Let and be two polynomials in with Euclidean norm being the polynomial degree. The left and right quotients and remainders are defined as in (2). Left and right quotients will exist provided that is invertible in and they may be computed by Algorithm 1. In the presentation of the algorithm, denotes a permutation on two elements so is either the identity or a transposition. The notation is a shorthand for so when is the identity and when is a transposition.
There are some circumstances where quotients or related quantities may be computed even if is not invertible. When is an integral domain, quotients may be computed as usual in with being the quotient field of . Alternatively, when is non-commutative but commutes with , it is possible to compute pseudoquotients and pseudoremainders satisfying
as shown in Algorithm 2. In this case, we write
Requiring to commute with is quite restrictive, however, so we focus our attention to situations where the inverse of exists.
Requires . pdiv
3.2 Whole Shift and Whole Shifted Inverse in
We now examine the notions of the whole shift and whole shifted inverse for with non-commutative . First consider the whole shift. Since commutes with all values in , we may without ambiguity take, for and ,
(7) |
That is, the fact that is non-commutative does not lead to left and right variants of the whole shift.
We state two simple theorems with obvious proofs:
Theorem 3
Let . Then, for all ,
Theorem 4
Let with and . Then, for ,
We now come to the main point of this section and show is well-defined when is non-commutative.
Theorem 5 (Whole shifted inverse for non-commutative )
Let , with a non-commutative ring and invertible in . Then, for ,
Thus we may write without ambiguity in the non-commutative case, i.e
(12) |
3.3 Quotients from the Whole Shifted Inverse in
We consider computing the left and right quotients in from the whole shifted inverse. We have the following theorem.
Theorem 6 (Left and right quotients from the whole shifted inverse in )
Let , a ring, with and invertible in . Then for ,
-
Proof.Consider first the right quotient. It is sufficient to show
for some with . It is therefore sufficient to show
(13) We have
(14) (15) Since , Theorem 3 applies and equation (15) gives
with the degree of less than . Therefore
by Theorem 4, and we have shown equation (13) as required. The proof for replaces equation (14) with
and follows the same lines, mutatis mutandis.
As in the commutative case, it may be more efficient to compute only the top part of the product instead of computing the whole thing then shifting away part. Now that we have shown that and are well-defined for non-commutative , we next see that may be computed by our generic algorithm.
4 Generic Algorithm for the Whole Shifted Inverse
Earlier work has shown how to compute efficiently for , both for Euclidean domains , and generically [10]. The generic version shown here in Algorithm 3. We justify below that it applies equally well to polynomials with non-commutative coefficients. The algorithm operates on a ring that is required to have a suitable and certain other operations and properties must be defined. For example, on , a field, these are
hasCarries | |||
The iterative step of Algorithm 3 is given on line 22. Since D.PowDiff computes , this line computes
(16) |
The shift operations are multiplications by powers of , with . The the expressions involving and for shift amounts arise from multiplication by various powers of at different points in order to compute shorter polynomials when possible. Since commutes with all values, it is possible to accumulate these into single pre- and post- shifts. With this in mind, the operations and ultimately compute the polynomial coefficients using the operations of and the order of the multiplicands in (16) is exactly that of the Newton-Schulz iteration (3). The form of Shinv0 above is chosen so that it gives a suitable initial value for non-commutative polynomials.
The computational complexity of the Refine methods of Algorithm 3 may be summarized as follows: The function D.Refine1 computes full-length values at each iteration so has time complexity where is the time complexity of multiplication. The function D.Refine2 reduces the size of the values, computing only the necessary prefixes. The function D.Refine3 reduces the size of some values further and achieves time complexity , which gives time complexity for the purely theoretical , for Schönhage-Strassen and for
5 Non-Commutative Polynomial Example
We give an example of computing left and right quotients via the whole shifted inverse with using the algorithms of Sections 3 and 4. Note that is not a domain—there may be zero divisors, but it is easy enough to check for them. This example, and the one in Section 7, were produced using the Domains package in Maple [5]. The setup to use the Domains package for this example is
with(Domains); F := GaloisField(7); F2x2 := SquareMatrix(2, F); PF2x2 := DenseUnivariatePolynomial(F2x2, x);
We start with
The whole 5-shifted inverse of is then
From this, the left and right quotients and remainders are computed to be
Taking a larger example where has degree 100 and degree 10, D.Refine1 computes with one guard digit in 6 steps with intermediate values of all of 92. Methods D.Refine2 and D.Refine3 compute the same result also in 6 steps but with values of have 4, 8, 16, 32, 64, 92 successively. Method D.Refine3 uses a shorter prefix of on the first iteration (). The Maple code used for this example is given in Figure 1.
6 Division in
We now examine the more general case where the polynomial variable does not commute with coefficients. For quotients and remainders to be defined, a notion of degree is required and we note that this leads immediately to Ore extensions, or skew polynomials. After touching upon classical algorithms, we introduce the notions of left and right whole shifted inverse. We note that the modified Newton-Schulz iteration may be used to compute whole shifted inverses, though in this case there is no benefit over classical division. Finally, we show how left and right whole shifted inverses may be used to compute right and left quotients, each with only one multiplication.
6.1 Definitions and Classical Algorithms
Consider a ring of objects with elements from a ring extended by , with not necessarily commuting with elements of . By distributivity, any finite expression in this extended ring is equal to a sum of monomials, the monomials composed of products of elements of and . To have a well-defined degree compatible with that of usual polynomials, it is required that
(17) |
We call the elements of such a ring skew polynomials. Condition (17) implies that for all there exist such that
(18) |
Therefore, to have well-defined notion of degree, the ring must be an Ore extension, . Ore studied these non-commutative polynomials almost a century ago [6] and overviews of Ore extensions in computer algebra are given in [1, 2]. The subject is viewed from a linear algebra perspective in [3] and the complexity of skew arithmetic is studied in [9]. The ring axioms of imply that be an endomorphism on and be a -derivation, i.e. for all
Different choices of and allow skew polynomials to represent linear differential operators, linear difference operators, -generalizations of these and other algebraic systems.
Condition (18) implies that it is possible to write any skew polynomial as a sum of monomials with all the powers of on the right or all on the left. We will use the notation for coefficients of skew polynomials with all powers of the variable on the right and for coefficients with all powers of the variable on the left, e.g.
Algorithm 4 gives left and right classical division in . As in Section 3, is multiplication with arguments permuted by . When , is a differential ring, usually denoted , and Algorithm 4 specializes to Algorithm 1. The left division algorithm applies only when is bijective. If left division is of primary interest, start from instead of (18) and work in the adjoint ring .
The left division algorithm applies when is bijective. skewdiv
Some care is needed in Algorithm 4 to avoid duplicating computation.
Notice that for rskewdiv the application of qcoeff on line 3 requires -fold application of to and that the computation of on line 4 is .
The latter requires commuting powers of across over the course of the division.
Depending on the cost to compute , it may be useful to create an array of the values for from 0 to .
It is also possible to pre-compute and store the products , with obtained from by one application of (18). Then the may be used in descending order in the for loop without re-computation. Both of these pre-computations are performed in the Maple program for P[RDiv]
shown in Figure 4.
6.2 Whole Shift and Inverse in
It is possible to define left and right analogs of the whole shift and whole shifted inverse for skew polynomials. In general, the left and right operations give different values.
Definition 3 (Left and right whole -shift in )
Given and ,
the left whole -shift of is
the right whole -shift of is
When is clear by context, we write and .
Definition 4 (Left and right whole -shifted inverse in )
Given and ,
the left whole -shifted inverse of with respect to is
the right whole -shifted inverse of with respect to is
When is clear by context, we write and .
Modified Newton-Schulz Iteration
For monic , the whole shifted inverses may be computed using modified Newton-Schulz iterations with guard places as follows:
(19) | ||||
These generalize D.Refine1 in Algorithm 3. For D.Refine2 and D.Refine3, the shifts that reduce the size of intermediate expressions are combined into one pre- and one post-shift in . But on we do not expect these simplifications of shift expressions to be legitimate.
Even though (19) can be used to compute whole shifted inverses, it does not give any benefit over classical division. In the special case of , the multiplication by and then by make it so each iteration creates only one correct term, so iterations are required rather than . In other skew polynomial rings, e.g. linear difference operators, the iteration (19) can still converge, but with multiple iterations required for each degree of the quotient. It is therefore simpler to compute and by classical division.
6.3 Quotients from Whole Shifted Inverses in
It is possible to compute left and right quotients from the right and left whole shifted inverses in . Although computing whole shifted inverses is not asymptotically fast as it is in , once a whole shifted inverse is obtained it can be used to compute multiple quotients and hence remainders, each requiring only one multiplication. This is useful, e.g., when working with differential ideals. In some cases this multiplication of skew polynomials is asymptotically fast [8].
Theorem 7 (Quotients from whole shifted inverses in )
Let , with a ring, , , and invertible in . Then
(20) | ||||
(21) |
-
Proof. We first prove (20). For , we proceed by induction on . Suppose . Since has no term of degree , we have
On the other hand, when , so
and (20) holds. For the inductive step, we assume that (20) holds for . For , let and let , and be given by
With this, has degree at most . The inductive hypothesis gives Therefore,
From this, we have
This completes the inductive step and the proof of (20). Equation (21) is proven as above, mutatis mutandis.
As in the commutative case, it may be more efficient to compute only the required top part of the product in (20) and (21) rather than to compute the whole product and then shift by .
7 Skew Polynomial Examples
7.1 Differential Operators
We take as a first example of using whole shifted inverses to compute quotients of skew polynomials. We use Algorithm 4 to compute the left and right whole shifted inverses, and then Theorem 7 to obtain the quotients. We start with and
The whole shifted inverses and are computed by Algorithm 4.
Then and so
A proof-of-concept Maple implementation for generic skew polynomials is given in Figure 4. The program is to clarify any ambiguities without any serious attention to efficiency. The setup for the above example is
with(Domains): LinearOrdinaryDifferentialOperator := (R, x) -> SkewPolynomial(R, x, r->r, R[Diff], r->r): F := GaloisField(7): R := DenseUnivariatePolynomial(F, ’y’): Lodo := LinearOrdinaryDifferentialOperator(R, ’D[y]’):
7.2 Difference Operators
We use linear ordinary difference operators as a second example, this time with not being the identity. We construct as . As before, we use Algorithm 4 to compute the left and right whole shifted inverses, and then Theorem 7 to obtain the quotients. We take and to be
The whole shifted inverses and are computed by Algorithm 4.
Then and so
The Maple setup for this example is
# Delta(f) acts as subs(y=y+1, f) - f for f in R LinearOrdinaryDifferenceOperator := proc(R, x, C) local E := R[ShiftOperator]; SkewPolynomial(R, x, r->E(r,C[1]), r->R[‘-‘](E(r,C[1]),r), r->E(r,C[‘-‘](C[1]))); end: F := GaloisField(7); R := DenseUnivariatePolynomial(F, ’y’); Lodo := LinearOrdinaryDifferenceOperator(R, ’Delta[y]’, F)
7.3 Difference Operators with Matrix Coefficients
As a final example, we take quotients in to underscore the genericity of this method.
The Maple setup for this example is the same as for the previous example but with F := SquareMatrix(2, GaloisField(7))
.
8 Conclusions
We have extended earlier work on efficient computation of quotients in a generic setting to the case of non-commutative univariate polynomial rings. We have shown that when the polynomial variable commutes with the coefficients, the whole shift and whole shifted inverse are well-defined and they may be used to compute left and right quotients. The whole shifted inverse may be computed by a modified Newton method in exactly the same way as when the coefficients are commutative and the number of iterations is logarithmic in the degree of the result. When the polynomial variable does not commute with the coefficients, left and right whole shifted inverses exist and may be computed by classical division. Once a left or right whole shifted inverse is obtained, several right or left quotients with that divisor may be computed, each with a single multiplication.
References
- [1] Abramov, S.A., Le, H.Q., Li, Z.: Univariate Ore polynomial rings in computer algebra. Journal of Mathematical Sciences 131(5), 5885–5903 (2005)
- [2] Bronstein, M., Petkovšek, M.: An introduction to pseudo-linear algebra. Theoretical Computer Science 157(1), 3–33 (1996)
- [3] Jacobson, N.: Pseudo-linear transformations. Annals of Mathematics, Second Series 38(2), 484–507 (1937)
- [4] Moenck, R.T., Borodin, A.B.: Fast modular transforms via division. In: Proc. 13th Annual Symposium on Switching and Automata Theory (SWAT 1972). pp. 90–96. IEEE, New York (1972)
- [5] Monagan, M.B.: Gauss: a parameterized domain of computation system with support for signature functions. In: Miola, A. (ed.) Design and Implementation of Symbolic Computation Systems. pp. 81–94. Springer Berlin Heidelberg, Berlin, Heidelberg (1993)
- [6] Ore, Ø.: Theory of non-commutative polynomials. Annals of Mathematics, Second Series 34(3), 480–508 (1933)
- [7] Schulz, G.: Iterative Berechnung der reziproken Matrix. Zeitschrift für Angewandte Mathematik und Mechanik 13(1), 57–59 (1933)
- [8] van der Hoeven, J.: FFT-like multiplication of linear differential operators. Journal of Symbolic Computation 33(1), 123–127 (2002)
- [9] van der Hoeven, J.: On the complexity of skew arithmetic. Applicable Algebra in Engineering, Communication and Computing 27, 105–122 (2016)
- [10] Watt, S.M.: Efficient generic quotients using exact arithmetic. In: Proc. International Symposium on Symbolic and Algebraic Computation (ISSAC 2023). ACM, New York (2023)
fshinv := proc (PR, method, h, v, perm) local R, x, k, vk, ivk, vkm1, w, ell, m, s, g, rmul, pmul, pshift, monom, step, refine, refine1, refine2, refine3; R := PR[CoefficientRing]; pmul := (a, b) -> PR[‘*‘](perm(a, b)); rmul := (a, b) -> R [‘*‘](perm(a, b)); monom := (c, x, n) -> PR[‘*‘](PR[Polynom]([c]), PR[‘^‘](x, n)); pshift := (n,v) -> shift(PR, n, v); step := proc(h, v, w, m, ell) PR[‘+‘]( pshift(m,w), pshift(2*m-h,pmul(w,PR[‘-‘]( PR[‘^‘](x,h-m), pmul(v,w) ))) ) end; refine1 := proc (v, h, k, w0, ell0) local m, s, w, ell; w := pshift(h-k-ell0+1, w0); ell := ell0; while ell < h-k+1 do w := step(h, v, w, 0, ell); ell := min(2*ell, h-k+1) od; w end; refine2 := proc (v, h, k, w0, ell0) local m, w, ell; w := w0; ell := ell0; while ell < h-k+1 do m := min(h-k+1-ell, ell); w := step(k+ell+m-1, v, w, m, ell); ell := ell+m od; w end; refine3 := proc (v, h, k, w0, ell0) local m, s, w, ell; w := w0; ell := ell0; while ell < h-k+1 do m := min(h-k+1-ell, ell); s := max(0, k-2*ell+1); w := step(k+ell+m-1-s, pshift(-s, v), w, m, ell); ell := ell+m od; w end; if method = 1 then refine := refine1 elif method = 2 then refine := refine2 elif method = 3 then refine := refine3 else error "Unknown method", method fi; x := PR[Polynom]([R[0],R[1]]); k := PR[Degree](v); vk := PR[Lcoeff](v); ivk := R[‘^‘](vk, -1); if h < k then return 0 elif k = 0 or h = k or v = monom(vk,x,k) then return monom(ivk,x,h-k) fi; vkm1 := PR[Coeff](v, k-1); w := PR[Polynom]([rmul(ivk, rmul(R[‘-‘](vkm1), ivk)), ivk]); ell := 2; g := 1; # Assume all coeff rings need a guard digit pshift(-g, refine(v, h + g, k, w, ell)) end: fdiv := proc (PR, method, u, v, perm) local mul, h, iv, q, r; mul := (a, b) -> PR[‘*‘](perm(a, b)); h := PR[Degree](u); iv := fshinv(PR, method, h, v, perm); q := shift(PR,-(h-k),mul(shift(PR,-k,u),iv)); # Need only top h-k terms r := PR[‘-‘](u, mul(q, v)); (q, r) end: lfdiv := (PR, method, u, v) -> fdiv(PR, method, u, v, (a,b)->(b,a)): rfdiv := (PR, method, u, v) -> fdiv(PR, method, u, v, (a,b)->(a,b)):
SkewPolynomial := proc (R, x, sigma, delta, sigmaInv) local P, deltaStar, mult2, MultVarOnLeft, MultVarOnRight; # Table to contain the operations. P := DenseUnivariatePolynomial(R, x); # If x*r = sigma(r)*x + delta(r), then # r*x = x*sigmaInv(r) - delta(sigmaInv(r)) = x*sigmaInv(r) + deltaStar(r) deltaStar := r -> R[‘-‘](delta(sigmaInv(r))); P[DomainName]:= ’SkewPolynomial’; P[Categories]:= P[Categories] minus {CommutativeRing,IntegralDomain}; P[Properties]:= P[Properties] minus {Commutative(‘*‘)}; P[ThetaOp] := P[Polynom]([R[0], R[1]]); # The variable as skew polynomial. P[Apply] := proc(ell, p) local i, pi, result; # Apply a skew polynomial as an operator. pi := p; # delta^i (p) result := R[‘*‘](P[Coeff](ell, 0), pi); for i to P[Degree](ell) do # For Maple, for loop default from is 1. pi := delta(pi); result := R[‘+‘](result, R[‘*‘](P[Coeff](ell, i), pi)) od; result end: P[‘^‘] := proc(a0, n0) local a, n, p; # Binary powering a := a0; n := n0; p := P[1]; while n > 0 do if irem(n,2) = 1 then p := P[‘*‘](p, a) fi; a := P[‘*‘](a, a); n := iquo(n,2); od; p end: P[‘*‘] := proc() local i, p; # N-ary product p := P[1]; for i to nargs do p := mult2(p, args[i]) od; p end: mult2 := proc(a, b) local s, i, ai, xib; # Binary product xib := b; ai := P[Coeff](a,0); s := P[Map](c->R[‘*‘](ai, c), xib); for i to P[Degree](a) do xib := MultVarOnLeft(xib); ai := P[Coeff](a, i); s := P[‘+‘](s, P[Map](c->R[‘*‘](ai,c), xib)); od; s end: # Compute x*b as polynomial with powers on right. # x*sum(b[i]*x^i, i=0..degb) = sum(sigma(b[i])*x^(i+1) + delta(b[i])*x^i, i=0..degb) MultVarOnLeft := proc(b) local cl, slist, dlist; cl := P[ListCoeffs](b); slist := [ R[0], op(map(sigma, cl)) ]; dlist := [ op(map(delta, cl)), R[0] ]; P[Polynom](zip(R[‘+‘], slist, dlist)); end: # Compute b*x as polynomial with powers on left. # sum(x^i*b[i], i=0..degb)*x = sum(x^(i+1)*sigmaInv(b[i]) + deltaStar(b[i])*x^i, i=0..degb) MultVarOnRight := proc(b) local cl, slist, dlist; cl := P[ListCoeffs](b); slist := [ R[0], op(map(sigmaInv, cl)) ]; dlist := [ op(map(deltaStar, cl)), R[0] ]; P[Polynom](zip(R[‘+‘], slist, dlist)); end: # Continued in Part 2...
# ... continued from Part 1. # For v = sum(vr_i x^i, i = 0..k) = sum(x^i vl_i, i = 0..k) # return polynomial with vl_i, interpreting powers as on left, # abusing the representation of output. P[ConvertToAdjointForm] := proc(v) local v_adj, i, rci, rcip; v_adj := P[0]; for i from P[Degree](v) to 0 by -1 do rci := P[Polynom]([P[Coeff](v,i)]); v_adj := P[‘+‘](v_adj, (MultVarOnRight@@i)(rci)); od; v_adj end: # For v = sum(x^i vl_i, i = 0..k) = sum(x^i vr_i, i = 0..k) # return polynomial with vr_i, interpreting powers as on right, # abusing the representation of input. P[ConvertFromAdjointForm] := proc(v_adj) local v, i, rci; v := P[0]; for i from 0 to P[Degree](v_adj) do rci := P[Polynom]([P[Coeff](v_adj,i)]); v := P[‘+‘](v, (MultVarOnLeft@@i)(rci)) od; v end: # Shift by power on left. P[LShift] := proc(n, v0) local v, shv, i, k; v := P[ConvertToAdjointForm](v0); k := P[Degree](v); if k + n < 0 then shv := P[0] elif n < 0 then shv := P[Polynom]([seq(P[Coeff](v,i), i = -n..k)]) else shv := P[Polynom]([seq(R[0], i=1..n), seq(P[Coeff](v,i), i=0..k)]) fi; P[ConvertFromAdjointForm](shv) end: # Shift by power on right. P[RShift] := proc(n, v) local i, k; k := P[Degree](v); if k + n < 0 then P[0] elif n < 0 then P[Polynom]([seq(P[Coeff](v,i), i = -n..k)]) else P[Polynom]([seq(R[0], i=1..n), seq(P[Coeff](v,i), i=0..k)]) fi end: # Quotient and remainder P[GDiv] := proc(perm, qfun) proc (u, v) local h, k, x, ivk, t, q, r, i, qi; x := P[Polynom]([R[0], R[1]]); ivk := R[Inv](P[Lcoeff](v)); h := P[Degree](u); k := P[Degree](v); q := P[0]; r := u; for i from h - k by -1 to 0 do qi := qfun(P[Coeff](r,i+k), ivk, i, k); t := P[‘*‘](P[Constant](qi), P[‘^‘](x,i)); q := P[‘+‘](q, t); r := P[‘-‘](r, P[‘*‘](perm(t, v))); od; (q, r) end end: P[RDiv0] := P[GDiv](rperm, (u,iv,n,k)->R[‘*‘](u,(sigma@@n)(iv))); P[LDiv] := P[GDiv](lperm, (u,iv,n,k)->(sigmaInv@@k)(R[‘*‘](iv,u))); # Continued in Part 3...
# ... continued from Part 2. # A slightly less repetitive RDiv. P[RDiv] := proc (u, v) local h, k, x, ivk, sigma_ivk_i, x_i_v, q, r, i, qi; x := P[Polynom]([R[0], R[1]]); ivk := R[Inv](P[Lcoeff](v)); h := P[Degree](u); k := P[Degree](v); # Precompute sigma^i(ivk) and x^i*v for required i. sigma_ivk_i[0] := ivk; for i from 1 to h-k do sigma_ivk_i[i] := sigma(sigma_ivk_i[i-1]); od; x_i_v[0] := v; for i from 1 to h-k do x_i_v[i] := P[‘*‘](x, x_i_v[i-1]) od; q := P[0]; r := u; for i from h - k by -1 to 0 do qi := P[Constant](R[‘*‘](P[Coeff](r, i+k), sigma_ivk_i[i])); q := P[‘+‘](q, P[‘*‘](qi, P[‘^‘](x,i))); r := P[‘-‘](r, P[‘*‘](qi, x_i_v[i])); od; (q, r) end: # Needed for some versions of Maple. P[0] := P[Polynom]([R[0]]); P[1] := P[Polynom]([R[1]]); P[‘-‘] := proc() local nb := P[Polynom](map(c-> R[‘-‘](c), P[ListCoeffs](args[nargs]))); if nargs = 1 then nb else P[‘+‘](args[1], nb) fi end: # Return the table P end: