############################################################################ # # File: polynom.icn # # Subject: Procedures to manipulate multi-variate polynomials # # Author: Ralph E. Griswold # # Date: October 1, 2001 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # The format for strings omits symbols for multiplication and # exponentiation. For example, 3*a^2 is entered as 3a2. # # A polynomial is represented by a table in which each term, such as 3xy, # the xy is # a key and the corresponding value is the coefficient, 3 in # this case. If a variable is raised to a power, such as x^3, the key # is the product of the individual variables, xxx in this case. # ############################################################################ # # Links: strings, tables # ############################################################################ link strings link tables procedure str2poly(str) #: convert string to polynomial local poly, var, vars, term, factor, power poly := table(0) str ? { while term := (move(1) || tab(upto('-+') | 0)) do { # possible sign term ? { factor := 1 # default factor := tab(many(&digits ++ '+.-')) tab(0) ? { vars := "" while var := move(1) do { power := 1 # default power := integer(tab(many(&digits))) vars ||:= repl(var, power) } } poly[csort(vars)] +:= numeric(factor) | fail } } } return poly end procedure polyadd(poly1, poly2) #: add polynomials local poly, keys, k keys := sort(set(keylist(poly1)) ++ set(keylist(poly2))) poly := table(0) every k := !keys do poly[k] := poly1[k] + poly2[k] return poly end procedure polymod(poly, i) #: polynomial modular reduction local poly1, keys, k keys := keylist(poly) poly1 := table(0) every k := !keys do poly1[k] := poly[k] % i return poly1 end procedure polysub(poly1, poly2) #: subtract polynomials local poly, keys, k keys := sort(set(keylist(poly1)) ++ set(keylist(poly2))) poly := table(0) every k := !keys do poly[k] := poly1[k] - poly2[k] return poly end procedure polymul(poly1, poly2) #: multiply polynomials local poly, keys1, keys2, k1, k2 keys1 := keylist(poly1) keys2 := keylist(poly2) poly := table(0) every k1 := !keys1 do every k2 := !keys2 do poly[csort(k1 || k2)] +:= poly1[k1] * poly2[k2] return poly end procedure polyexp(poly1, i) #: exponentiate polynomial local poly poly := copy(poly1) every 1 to i - 1 do poly := polymul(poly, poly1) return poly end procedure poly2str(poly) #: polynomial to string local str, keys, k, count, var keys := keylist(poly) str := "" every k := !keys do { if poly[k] = 0 then next # skip term else if poly[k] > 0 then str ||:= "+" || ((poly[k] ~= 1) | "") else if poly[k] < 0 then str ||:= ((poly[k] ~= 1) | "") k ? { while var := move(1) do { count := 1 count +:= *tab(many(var)) if count = 1 then str ||:= var else str ||:= var || count } } } return str[2:0] | "0" end procedure polydiff(poly, var) #: polynomial differentiation local poly_new, keys, k, nvars, newk poly_new := table() keys := keylist(poly) every k := !keys do { k ? { if newk := tab(upto(var)) then { nvars := *tab(many(var)) newk ||:= repl(var, nvars - 1) || tab(0) poly_new[newk] := nvars * poly[k] } } } return poly_new end procedure polyintg(poly, var) #: polynomial integration local poly_new, keys, k, nvars, newk poly_new := table() keys := keylist(poly) every k := !keys do { k ? { if newk := tab(upto(var)) then { nvars := *tab(many(var)) newk ||:= repl(var, nvars + 1) || tab(0) poly_new[newk] := poly[k] / real(nvars + 1) } } } return poly_new end procedure peval(str) #: string polynomial simplification while str ?:= 2(="(", tab(bal(')')), =")", pos(0)) return poper(str) | str2poly(str) end procedure poper(str) #: find polynomial operation return str ? { pform(tab(bal('-+*^:|%')), move(1), tab(0)) } end procedure pform(str1, op, str2) #: polynomial formation return case op of { "+" : polyadd(peval(str1), peval(str2)) "-" : polysub(peval(str1), peval(str2)) "*" : polymul(peval(str1), peval(str2)) "^" : polyexp(peval(str1), str2) ":" : polydiff(peval(str1), str2) "|" : polyintg(peval(str1), str2) "%" : polymod(peval(str1), str2) } end procedure poly2profile(poly) #: polynomial to profile sequence local str, keys, k, count, vara, i, seg keys := keylist(poly) str := "" every k := !keys do { i := poly[k] if i < 0 then { # if negative, reverse sequence i := abs(i) k := reverse(k) } str ||:= left(repl(k, i + 1), i * *k) } return str end procedure poly2profilelen(poly) #: polynomial to profile sequence local i, keys, k, count, var keys := keylist(poly) i := 0 every k := !keys do i +:= *repl(k, abs(poly[k])) # treat negative as if positive return i end procedure basepolystr(clist, plist) # base polynomial string return "(" || poly2str(basepoly(clist, plist)) || ")" end procedure basepoly(clist, plist) # base polynomial local poly, i, c, p static vlist initial vlist := string(&lcase) poly := table() i := 1 while c := get(clist) & p := get(plist) do { poly[repl(vlist[i], (0 <= p))] := (0 ~= c) i +:= 1 } return poly end