fpf.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. ;;;; Flat Polynomial Form, for Commutative Rings
  21. (declare (usual-integrations))
  22. (define fpf:coeff? number?)
  23. (define fpf:coeff-zero? zero?)
  24. (define fpf:coeff-add +)
  25. (define fpf:coeff-sub -)
  26. (define fpf:coeff-mul *)
  27. (define fpf:coeff-div /)
  28. (define fpf:coeff-negate -)
  29. (define fpf:coeff-expt expt)
  30. (define fpf:coeff-divide scheme-number-divide)
  31. ;;; An fpf is a sorted list of terms.
  32. ;;; Each term has exponents and a coefficient.
  33. (define (fpf? x)
  34. (or (fpf:coeff? x) (explicit-fpf? x)))
  35. (define (explicit-fpf? x)
  36. (and (pair? x)
  37. (eq? (car x) '*fpf*)))
  38. (define (fpf:arity fpf)
  39. (if (fpf:coeff? fpf)
  40. 0
  41. (fpf:number-of-vars (fpf:terms fpf))))
  42. (define (fpf:number-of-vars termlist)
  43. (length (fpf:exponents (car termlist))))
  44. (define (fpf:make terms)
  45. (cond ((null? terms) :zero)
  46. ((and (null? (cdr terms))
  47. (fpf:constant-term? (car terms)))
  48. (fpf:coefficient (car terms)))
  49. (else
  50. (cons '*fpf* terms))))
  51. (define (fpf:terms fpf)
  52. (if (and (fpf:coeff? fpf) (fpf:coeff-zero? fpf))
  53. '()
  54. (cdr fpf)))
  55. (define (fpf:make-term exponents coeff)
  56. (cons exponents coeff))
  57. (define (fpf:exponents term)
  58. (car term))
  59. (define (fpf:coefficient term)
  60. (cdr term))
  61. (define (fpf:constant-term? term)
  62. (all-zeros? (fpf:exponents term)))
  63. (define (all-zeros? exponents)
  64. (or (null? exponents)
  65. (and (fix:= 0 (car exponents))
  66. (all-zeros? (cdr exponents)))))
  67. (define (fpf:make-constant c arity)
  68. (list '*fpf*
  69. (fpf:make-term (make-list arity 0)
  70. c)))
  71. (define fpf:zero :zero)
  72. (define fpf:one :one)
  73. (define fpf:-one :-one)
  74. (define fpf:identity
  75. (fpf:make (list (fpf:make-term (list 1) :one))))
  76. (define (fpf:new-variables n)
  77. (make-initialized-list n
  78. (lambda (i)
  79. (fpf:make (list (fpf:make-term
  80. (make-initialized-list n
  81. (lambda (j) (if (fix:= i j) 1 0)))
  82. :one))))))
  83. (define (fpf:same-exponents? fs1 fs2)
  84. (equal? fs1 fs2))
  85. (define (fpf:>exponents? fs1 fs2)
  86. (fpf:graded> fs1 fs2))
  87. (define (fpf:graded> fs1 fs2) ;Graded lexicographical order
  88. (let ((o1 (reduce fix:+ 0 fs1))
  89. (o2 (reduce fix:+ 0 fs2)))
  90. (cond ((fix:> o1 o2) #t)
  91. ((fix:< o1 o2) #f)
  92. (else
  93. (fpf:lexicographical> fs1 fs2)))))
  94. (define (fpf:lexicographical> fs1 fs2) ;Lexicographical order
  95. (let lp ((l1 fs1) (l2 fs2))
  96. (cond ((null? l1) #f)
  97. ((null? l2) #t)
  98. ((fix:> (car l1) (car l2)) #t)
  99. ((fix:< (car l1) (car l2)) #f)
  100. (else (lp (cdr l1) (cdr l2))))))
  101. (define (fpf:map-coefficients proc terms)
  102. (if (null? terms)
  103. '()
  104. (let ((ncoeff (proc (fpf:coefficient (car terms)))))
  105. (if (fpf:coeff-zero? ncoeff)
  106. (fpf:map-coefficients proc (cdr terms))
  107. (cons (fpf:make-term (fpf:exponents (car terms))
  108. ncoeff)
  109. (fpf:map-coefficients proc (cdr terms)))))))
  110. (define (fpf:binary-combine a1 a2 coeff-op terms-op opname)
  111. (define (wta)
  112. (error "Wrong type argument -- FPF" opname a1 a2))
  113. (if (fpf:coeff? a1)
  114. (if (fpf:coeff? a2)
  115. (coeff-op a1 a2)
  116. (if (explicit-fpf? a2)
  117. (fpf:make
  118. (terms-op (fpf:terms (fpf:make-constant a1 (fpf:arity a2)))
  119. (fpf:terms a2)))
  120. (wta)))
  121. (if (fpf:coeff? a2)
  122. (if (explicit-fpf? a1)
  123. (fpf:make
  124. (terms-op (fpf:terms a1)
  125. (fpf:terms (fpf:make-constant a2 (fpf:arity a1)))))
  126. (wta))
  127. (if (and (explicit-fpf? a1)
  128. (explicit-fpf? a2)
  129. (fix:= (fpf:arity a1) (fpf:arity a2)))
  130. (fpf:make (terms-op (fpf:terms a1) (fpf:terms a2)))
  131. (wta)))))
  132. (define (fpf:+ a1 a2)
  133. (fpf:binary-combine a1 a2 fpf:coeff-add fpf:add-terms 'add))
  134. (define (fpf:add-terms xlist ylist)
  135. (fpf:add-terms-general xlist ylist fpf:coeff-add))
  136. (define (fpf:add-terms-general xlist ylist coeff-add)
  137. (let tloop ((xlist xlist) (ylist ylist))
  138. (cond ((null? xlist) ylist)
  139. ((null? ylist) xlist)
  140. (else
  141. (let ((f1 (fpf:exponents (car xlist)))
  142. (f2 (fpf:exponents (car ylist))))
  143. (cond ((fpf:same-exponents? f1 f2)
  144. (let ((ncoeff
  145. (coeff-add (fpf:coefficient (car xlist))
  146. (fpf:coefficient (car ylist)))))
  147. (if (fpf:coeff-zero? ncoeff)
  148. (tloop (cdr xlist) (cdr ylist))
  149. (cons (fpf:make-term f1 ncoeff)
  150. (tloop (cdr xlist) (cdr ylist))))))
  151. ((fpf:>exponents? f1 f2)
  152. (cons (car xlist) (tloop (cdr xlist) ylist)))
  153. (else
  154. (cons (car ylist)
  155. (tloop xlist (cdr ylist))))))))))
  156. (define (fpf:- minuend subtrahend)
  157. (fpf:+ minuend (fpf:negate subtrahend)))
  158. (define (fpf:scale scale-factor p)
  159. (if (fpf:coeff? p)
  160. (fpf:coeff-mul scale-factor p)
  161. (fpf:make (fpf:scale-terms scale-factor (fpf:terms p)))))
  162. (define (fpf:scale-terms scale-factor terms)
  163. (fpf:scale-terms-general scale-factor terms fpf:coeff-mul))
  164. (define (fpf:scale-terms-general scale-factor terms coeff-mul)
  165. (fpf:map-coefficients
  166. (lambda (coefficient)
  167. (coeff-mul scale-factor coefficient))
  168. terms))
  169. (define (fpf:negate p)
  170. (if (fpf:coeff? p)
  171. (fpf:coeff-negate p)
  172. (fpf:make (fpf:negate-terms (fpf:terms p)))))
  173. (define (fpf:negate-terms terms)
  174. (fpf:negate-terms-general terms fpf:coeff-negate))
  175. (define (fpf:negate-terms-general terms neg)
  176. (fpf:map-coefficients neg terms))
  177. (define (fpf:* m1 m2)
  178. (fpf:binary-combine m1 m2 fpf:coeff-mul fpf:mul-terms 'mul))
  179. (define (fpf:mul-terms xlist ylist)
  180. (fpf:mul-terms-general xlist ylist fpf:coeff-add fpf:coeff-mul))
  181. (define (fpf:mul-terms-general xlist ylist add mul)
  182. (let xloop ((xlist xlist))
  183. (if (null? xlist)
  184. '()
  185. (fpf:add-terms-general (fpf:term*terms-general (car xlist) ylist mul)
  186. (xloop (cdr xlist))
  187. add))))
  188. (define (fpf:term*terms-general term terms coeff-mul)
  189. (let ((exponents (fpf:exponents term))
  190. (coeff (fpf:coefficient term)))
  191. (let lp ((terms terms))
  192. (if (null? terms)
  193. '()
  194. (cons (fpf:make-term
  195. (fpf:combine-exponents exponents
  196. (fpf:exponents (car terms)))
  197. (coeff-mul coeff (fpf:coefficient (car terms))))
  198. (lp (cdr terms)))))))
  199. (define (fpf:combine-exponents exponents1 exponents2)
  200. (cond ((null? exponents1) exponents2)
  201. ((null? exponents2) exponents1)
  202. (else
  203. (map fix:+ exponents1 exponents2))))
  204. (define (fpf:square p)
  205. (fpf:* p p))
  206. (define (fpf:expt base exponent)
  207. (define (expt-iter x count answer)
  208. (if (int:zero? count)
  209. answer
  210. (if (even? count)
  211. (expt-iter (fpf:square x) (int:quotient count 2) answer)
  212. (expt-iter x (int:- count 1) (fpf:* x answer)))))
  213. (cond ((fpf:coeff? base) (fpf:coeff-expt base exponent))
  214. ((not (explicit-fpf? base))
  215. (error "Wrong type -- FPF:EXPT:" base exponent))
  216. ((not (exact-integer? exponent))
  217. (error "Can only raise an FPF to an exact integer power" base exponent))
  218. ((negative? exponent)
  219. (error "No inverse -- FPF:EXPT:" base exponent))
  220. (else
  221. (expt-iter base exponent :one))))
  222. (define* (fpf:divide x y #:optional continue)
  223. (let ((cont
  224. (if (default-object? continue)
  225. (lambda (q r) (list (fpf:make q) (fpf:make r)))
  226. (lambda (q r) (continue (fpf:make q) (fpf:make r))))))
  227. (if (and (fpf:coeff? x) (fpf:coeff? y)) ; FBE
  228. (fpf:coeff-divide x y cont)
  229. (cond ((and (fpf:coeff? x) (explicit-fpf? y))
  230. (fpf:divide-terms (fpf:terms (fpf:make-constant x (fpf:arity y)))
  231. (fpf:terms y)
  232. cont))
  233. ((and (fpf:coeff? y) (explicit-fpf? x))
  234. (fpf:divide-terms (fpf:terms x)
  235. (fpf:terms (fpf:make-constant y (fpf:arity x)))
  236. cont))
  237. ((and (explicit-fpf? x)
  238. (explicit-fpf? y)
  239. (fix:= (fpf:arity x) (fpf:arity y)))
  240. (fpf:divide-terms (fpf:terms x) (fpf:terms y) cont))
  241. (else (error "Bad arguments -- FPF:DIVIDE" x y))))))
  242. (define* (fpf:divide-terms termlist1 termlist2 #:optional continue)
  243. (if (default-object? continue) (set! continue list))
  244. (fpf:divide-terms-general termlist1 termlist2
  245. fpf:coeff-add fpf:coeff-mul fpf:coeff-div fpf:coeff-negate continue))
  246. (define (fpf:divide-terms-general numerator-terms denominator-terms add mul div neg cont)
  247. (let ((dexps (fpf:exponents (car denominator-terms)))
  248. (dcoeff (fpf:coefficient (car denominator-terms))))
  249. (define (dloop nterms cont)
  250. (if (null? nterms)
  251. (cont '() '())
  252. (let ((nexps (fpf:exponents (car nterms))))
  253. (cond ((*and (map >= nexps dexps))
  254. (let ((qt
  255. (fpf:make-term (map int:- nexps dexps)
  256. (div (fpf:coefficient (car nterms)) dcoeff))))
  257. (dloop (fpf:add-terms-general nterms
  258. (fpf:negate-terms-general
  259. (fpf:term*terms-general
  260. qt denominator-terms mul)
  261. neg)
  262. add)
  263. (lambda (q r)
  264. (cont (fpf:add-terms-general
  265. (list qt) q add) r)))))
  266. (else
  267. (dloop (cdr nterms)
  268. (lambda (q r)
  269. (cont q
  270. (fpf:add-terms-general
  271. (list (car nterms)) r add)))))))))
  272. (dloop numerator-terms cont)))
  273. (define (fpf:horner-eval poly args)
  274. (if (fpf:coeff? poly) poly (fpf:horner-eval-terms (fpf:terms poly) args)))
  275. (define (fpf:horner-eval-terms terms args)
  276. (fpf:horner-eval-general terms args
  277. fpf:coeff-add fpf:coeff-sub fpf:coeff-mul fpf:coeff-expt))
  278. (define (fpf:horner-eval-general terms args add sub mul expt)
  279. (if (null? terms)
  280. :zero
  281. (let hloop ((terms (cdr terms))
  282. (exponents (fpf:exponents (car terms)))
  283. (sum (fpf:coefficient (car terms))))
  284. (if (null? terms)
  285. (mul sum (a-reduce mul (map expt args exponents)))
  286. (let ((new-exponents (fpf:exponents (car terms))))
  287. (hloop (cdr terms)
  288. new-exponents
  289. (add (fpf:coefficient (car terms))
  290. (mul sum
  291. (a-reduce mul
  292. (map expt
  293. args
  294. (map int:-
  295. exponents
  296. new-exponents)))))))))))
  297. ;;; Converting between flat polynomials and other kinds of expressions
  298. (define (fpf:->expression p vars)
  299. (cond ((fpf:coeff? p) p)
  300. ((explicit-fpf? p)
  301. (a-reduce symb:+
  302. (map (lambda (term)
  303. (symb:* (fpf:coefficient term)
  304. (a-reduce symb:*
  305. (map (lambda (exponent var)
  306. (symb:expt var exponent))
  307. (fpf:exponents term)
  308. vars))))
  309. (fpf:terms p))))
  310. (else
  311. (error "Bad fpf -- ->EXPRESSION" p vars))))
  312. (define* (fpf:expression-> expr cont #:optional less?)
  313. ;; cont = (lambda (poly vars) ... )
  314. (let ((evars
  315. (sort (list-difference (variables-in expr)
  316. fpf:operators-known)
  317. (if (default-object? less?) variable<? less?))))
  318. (cont ((expression-walker
  319. (pair-up evars
  320. (fpf:new-variables (length evars))
  321. fpf:operator-table))
  322. expr)
  323. evars)))
  324. (define +$fpf (accumulation fpf:+ fpf:zero))
  325. (define -$fpf (inverse-accumulation fpf:- fpf:+ fpf:negate fpf:zero))
  326. (define *$fpf (accumulation fpf:* fpf:one))
  327. (define fpf:operator-table
  328. `((+ ,+$fpf)
  329. (- ,-$fpf)
  330. (* ,*$fpf)
  331. (negate ,fpf:negate)
  332. (square ,fpf:square)
  333. (expt ,fpf:expt)))
  334. (define fpf:operators-known (map car fpf:operator-table))