691 lines
21 KiB
Racket
691 lines
21 KiB
Racket
#lang racket
|
|
|
|
(module common racket/base
|
|
(provide curly?)
|
|
(define (curly? stx)
|
|
; Was the form in stx written with curly parentheses?
|
|
(let ([p (syntax-property stx 'paren-shape)])
|
|
(and p
|
|
(or (eqv? p #\{)
|
|
(and (pair? p)
|
|
(or (eqv? (car p) #\{)
|
|
(eqv? (cdr p) #\{))))))))
|
|
|
|
(module splay racket
|
|
; Convenient syntax for working with splay-trees
|
|
; {s i} = (splay-tree-ref s i 0)
|
|
; {s i 0} = (splay-tree-remove! s i)
|
|
; {s i v} = (splay-tree-set! s i v)
|
|
; {count s} = (splay-tree-count s)
|
|
; {remove! s i} = (splay-tree-remove! s i)
|
|
; {for-each s f} = (splay-tree-for-each s f) ; where f : exponent coef -> coef
|
|
; note: f is called with exponents going from smallest to greatest
|
|
; ...
|
|
(provide (rename-out [app #%app]))
|
|
(require (for-syntax (submod ".." common))
|
|
data/splay-tree racket/dict)
|
|
|
|
(define-syntax (app stx)
|
|
(syntax-case stx
|
|
(count remove! for-each map
|
|
greatest-pos least-pos value-at key-at ->list next)
|
|
[{_}
|
|
(curly? stx)
|
|
(syntax/loc stx (make-adjustable-splay-tree))]
|
|
[{_ next s}
|
|
(curly? stx)
|
|
(syntax/loc stx (splay-tree-iterate-next s))]
|
|
[{_ count s}
|
|
(curly? stx)
|
|
(syntax/loc stx (splay-tree-count s))]
|
|
[{_ key-at s key}
|
|
(curly? stx)
|
|
(syntax/loc stx (splay-tree-iterate-key s key))]
|
|
[{_ value-at s pos}
|
|
(curly? stx)
|
|
(syntax/loc stx (splay-tree-iterate-value s pos))]
|
|
[{_ greatest-pos s}
|
|
(curly? stx)
|
|
(syntax/loc stx (splay-tree-iterate-greatest s))]
|
|
|
|
[{_ least-pos s}
|
|
(curly? stx)
|
|
(syntax/loc stx (splay-tree-iterate-least s))]
|
|
[{_ for-each s f}
|
|
(curly? stx)
|
|
(syntax/loc stx (dict-for-each s f))]
|
|
[{_ map s f}
|
|
(curly? stx)
|
|
(syntax/loc stx (dict-map s f))]
|
|
[{_ remove! s v}
|
|
(curly? stx)
|
|
(syntax/loc stx (splay-tree-remove! s v))]
|
|
[{_ ->list s}
|
|
(curly? stx)
|
|
(syntax/loc stx (splay-tree->list s))]
|
|
;; Add new keywords above this line!
|
|
[{_ s i}
|
|
(curly? stx)
|
|
(syntax/loc stx (splay-tree-ref s i 0))]
|
|
[{_ s i v}
|
|
(curly? stx)
|
|
(syntax/loc stx
|
|
(let ([v1 v])
|
|
(if (zero? v1)
|
|
(splay-tree-remove! s i)
|
|
(splay-tree-set! s i v1))))]
|
|
[(_ . more)
|
|
(syntax/loc stx (#%app . more))])))
|
|
|
|
|
|
(module poly-base racket
|
|
; Polynomals in one variable.
|
|
|
|
; Polynomials are represented as splay-trees of terms.
|
|
; Let t be the splay-tree representing the terms of p, then
|
|
; ci*x^i is a term of p <=> {t i} = ci
|
|
; All ci stored in t are non-zero, thus
|
|
; the zero polynomial is represented by the empty splay-tree.
|
|
|
|
; In this module {}-syntax works on splay trees.
|
|
|
|
; These function can use the internal representation of polynomials.
|
|
(provide (struct-out poly)
|
|
in-terms in-reverse-terms
|
|
current-poly-display default-poly-display infix-poly-display
|
|
make-zero
|
|
degree
|
|
mono
|
|
copy-poly
|
|
k+poly k+poly! poly+k*poly!
|
|
poly+poly poly-poly poly*poly
|
|
k*poly k*poly!
|
|
poly^n slow-poly^n
|
|
deriv
|
|
terms
|
|
leading-term leading-coef leading-exponent
|
|
trailing-term trailing-coef trailing-exponent
|
|
poly-eval ; horner
|
|
poly/x-r ; horner
|
|
|
|
poly-zero?)
|
|
|
|
(require data/splay-tree racket/dict
|
|
(submod ".." splay))
|
|
|
|
(define-struct poly (terms)
|
|
#:property prop:custom-write
|
|
(λ (s out write?) ((current-poly-display) s out write?))
|
|
#:property prop:sequence (lambda (p)
|
|
(let ([t (terms p)])
|
|
(make-do-sequence
|
|
(λ ()
|
|
(values
|
|
(λ (pos) (mono {key-at t pos} {value-at t pos}))
|
|
(λ (pos) (splay-tree-iterate-next t pos))
|
|
{least-pos t}
|
|
(λ (pos) pos)
|
|
#f
|
|
#f)))))
|
|
#:methods gen:dict
|
|
[(define (dict-ref p pos [default (λ () (mono 0 0))])
|
|
(let ([t (poly-terms p)]) (mono pos {t pos})))]
|
|
#:transparent)
|
|
(define terms poly-terms)
|
|
|
|
(define (in-terms p)
|
|
(in-dict (terms p)))
|
|
|
|
(define default-poly-display
|
|
(λ (s out write?)
|
|
(define (display-poly p)
|
|
((if write? write display)
|
|
(list 'poly
|
|
(for/list ([(i ci) (in-reverse-terms p)])
|
|
(list i ci))) out))
|
|
(define write-poly display-poly)
|
|
(if write? (write-poly s) (display-poly s))))
|
|
|
|
(define infix-poly-display
|
|
(λ (s out write?)
|
|
(define (display-poly p)
|
|
((if write? write display)
|
|
(poly->string p "x") out))
|
|
(define write-poly display-poly)
|
|
(if write? (write-poly s) (display-poly s))))
|
|
|
|
(define (poly->string p [var "x"])
|
|
(define (sign r) (if (>= r 0) "+" "-"))
|
|
(define (exponent->string var n)
|
|
(cond [(= n 0) ""]
|
|
[(= n 1) var]
|
|
[else (string-append var "^" (number->string n))]))
|
|
(let* ([sign-coef-exps
|
|
(for/list ([(i ci) (in-reverse-terms p)])
|
|
(let ([es (exponent->string var i)]
|
|
[signs (sign ci)]
|
|
[cis (number->string (abs ci))])
|
|
(cond
|
|
[(= i 0) (list signs cis "")]
|
|
[(= ci 1) (list "+" "" es)]
|
|
[(= ci -1) (list "-" "" es)]
|
|
[else (list signs cis es)])))])
|
|
(define (space x)
|
|
(if (equal? x "") "" (string-append " " x)))
|
|
(match sign-coef-exps
|
|
[(list) "0"]
|
|
[(list (list sign coef exps) more ...)
|
|
(string-append
|
|
(if (equal? sign "+") "" sign)
|
|
(if (equal? sign "+") coef (space coef))
|
|
exps
|
|
(apply string-append
|
|
(map (match-lambda
|
|
[(list sign coef exps)
|
|
(string-append (space sign) (space coef) exps)])
|
|
more)))])))
|
|
|
|
(define current-poly-display
|
|
(make-parameter default-poly-display))
|
|
|
|
|
|
(require (only-in unstable/sequence
|
|
sequence-lift))
|
|
|
|
(define (in-reverse-terms p)
|
|
(sequence-lift (λ (c) (values (car c) (cdr c)))
|
|
(in-list (reverse {->list (terms p)}))))
|
|
|
|
(define (make-zero) (poly {}))
|
|
|
|
(define (poly-zero? p)
|
|
(zero? {count (terms p)}))
|
|
|
|
(define (copy-poly p)
|
|
(let ([q {}])
|
|
(for ([(i ci) (in-dict (terms p))])
|
|
{q i ci})
|
|
(poly q)))
|
|
|
|
(define (mono i ci)
|
|
(let ([t {}])
|
|
(unless (zero? ci)
|
|
{t i ci})
|
|
(poly t)))
|
|
|
|
(define (k+poly! k p)
|
|
(let ([t (terms p)])
|
|
{t 0 (+ k {t 0})})
|
|
p)
|
|
|
|
(define (k+poly k p)
|
|
(k+poly! k (copy-poly p)))
|
|
|
|
(define (k*poly! k p)
|
|
(let ([t (terms p)])
|
|
(if (zero? k)
|
|
{for-each t (λ (i ci) {remove! t i})}
|
|
{for-each t (λ (i ci) {t i (* k ci)})}))
|
|
p)
|
|
|
|
(define (k*poly k p)
|
|
(k*poly! k (copy-poly p)))
|
|
|
|
(define (degree p)
|
|
(let* ([t (terms p)]
|
|
[pos {greatest-pos t}])
|
|
(if pos {key-at t pos} -inf.0)))
|
|
|
|
(define (coef p i)
|
|
{(terms p) i})
|
|
|
|
(define (leading-term p)
|
|
(let* ([t (terms p)]
|
|
[pos {greatest-pos t}])
|
|
(if pos
|
|
(mono {key-at t pos} {value-at t pos})
|
|
(mono 0 0)))) ; or #f ?
|
|
|
|
(define (leading-coef p)
|
|
(let* ([t (terms p)]
|
|
[pos {greatest-pos t}])
|
|
(if pos
|
|
{value-at t pos}
|
|
0))) ; ?
|
|
|
|
(define (leading-exponent p)
|
|
(let* ([t (terms p)]
|
|
[pos {greatest-pos t}])
|
|
(if pos
|
|
{key-at t pos}
|
|
-inf.0)))
|
|
|
|
|
|
(define (trailing-term p)
|
|
(let* ([t (terms p)]
|
|
[pos {least-pos t}])
|
|
(if pos
|
|
(mono {key-at t pos} {value-at t pos})
|
|
(mono 0 0)))) ; or #f ?
|
|
|
|
(define (trailing-coef p)
|
|
(let* ([t (terms p)]
|
|
[pos {least-pos t}])
|
|
(if pos
|
|
{value-at t pos}
|
|
0))) ; ?
|
|
|
|
(define (trailing-exponent p)
|
|
(let* ([t (terms p)]
|
|
[pos {least-pos t}])
|
|
(if pos
|
|
{key-at t pos}
|
|
-inf.0)))
|
|
|
|
(define (poly+poly p q)
|
|
(if (> (degree p) (degree q))
|
|
(poly+poly q p)
|
|
; degree q largest
|
|
(let* ([r (copy-poly q)]
|
|
[t (terms r)]
|
|
[s (terms p)])
|
|
{for-each s (λ (i ci) {t i (+ {t i} {s i})})}
|
|
r)))
|
|
|
|
(define (poly-poly p q)
|
|
(let* ([r (copy-poly p)]
|
|
[t (terms r)]
|
|
[s (terms q)])
|
|
{for-each s (λ (i ci) {t i (- {t i} {s i})})}
|
|
r))
|
|
|
|
(define (poly*poly p q)
|
|
(let ([t {}]
|
|
[r (terms p)]
|
|
[s (terms q)])
|
|
(for* ([(i ci) (in-dict r)]
|
|
[(j cj) (in-dict s)])
|
|
(let ([k (+ i j)])
|
|
{t k (+ (* ci cj) {t k})}))
|
|
(poly t)))
|
|
|
|
(define (slow-poly^n p n)
|
|
; strictly for testing
|
|
(if (zero? n)
|
|
(mono 0 1)
|
|
(poly*poly p (slow-poly^n p (- n 1)))))
|
|
|
|
(define (poly^n p n)
|
|
(cond
|
|
[(= n 0) (mono 0 1)]
|
|
[(= n 1) p]
|
|
[else
|
|
(let ([c {count (terms p)}])
|
|
(cond
|
|
[(= c 0) p]
|
|
[(= c 1) (slow-poly^n p n)]
|
|
[else
|
|
(let* ([a (leading-term p)]
|
|
[b (poly-poly (copy-poly p) a)]
|
|
[a^n (make-hash)]
|
|
[b^n (make-hash)])
|
|
(hash-set! a^n 0 (mono 0 1))
|
|
(hash-set! b^n 0 (mono 0 1))
|
|
(for ([i (in-range 1 (+ n 1))])
|
|
(hash-set! a^n i (poly*poly a (hash-ref a^n (- i 1))))
|
|
(hash-set! b^n i (poly*poly b (hash-ref b^n (- i 1)))))
|
|
(let ([c 1] ; c = (choose n i)
|
|
[r (mono 0 0)])
|
|
(for ([i (in-range 0 (+ n 1))])
|
|
(poly+k*poly! r c (poly*poly (hash-ref a^n i)
|
|
(hash-ref b^n (- n i))))
|
|
; (choose n i+1) / (chose n i) = (n-i)/(i+1)
|
|
(set! c (/ (* c (- n i))
|
|
(+ i 1))))
|
|
r))]))]))
|
|
|
|
(define (poly+k*poly! p k q)
|
|
(let ([t (terms p)] [s (terms q)])
|
|
{for-each s (λ (i ci) {t i (+ {t i} (* k ci))})}
|
|
p))
|
|
|
|
(define (deriv p)
|
|
(let ([d {}]
|
|
[t (terms p)])
|
|
{for-each t (λ (i ci) (unless (zero? i) {d (- i 1) (* ci i)}))}
|
|
(poly d)))
|
|
|
|
(define (poly->list p)
|
|
(for/list ([(i ci) (in-dict (terms p))])
|
|
(cons i ci)))
|
|
|
|
(define (poly-eval p r)
|
|
; Horners method
|
|
; 3*x^3 + 1*x = x*( 3*x^2 + 1) = x*( x^2*(3) + 1)
|
|
(if (poly-zero? p)
|
|
0
|
|
(let ([v 0] [k (degree p)])
|
|
(for ([(i ci) (in-reverse-terms p)])
|
|
(set! v (+ ci (* v (expt r (- k i)))))
|
|
(set! k i))
|
|
(* v (expt r (trailing-exponent p))))))
|
|
|
|
(define (poly/x-r p r)
|
|
; BUG TODO: test case where p is non-consecutive exponents
|
|
; Examples from Wikipedia
|
|
; > (poly/x-r {+ {^ x 3} {* -6 {^ x 2}} {* 11 x} -6} 2)
|
|
; '(1 -4 3 0)
|
|
; > (poly/x-r {+ {* 2 {^ x 3}} {* -6 {^ x 2}} {* 2 x} -1} 3)
|
|
; '(2 0 2 5)
|
|
; the last number is the remainder
|
|
(let ([j 1] [v 0] [k (degree p)])
|
|
(for/list ([c (in-list (reverse (poly->list p)))])
|
|
(let ([i (car c)] [ci (cdr c)])
|
|
(display (- k i)) (newline)
|
|
(set! v (+ ci (* v (expt r (- k i)))))
|
|
(set! k i)
|
|
v))))
|
|
|
|
)
|
|
|
|
(module poly-base-syntax racket
|
|
(require (submod ".." poly-base)
|
|
(for-syntax (submod ".." common)))
|
|
(provide (all-from-out (submod ".." poly-base))
|
|
(rename-out [app #%app])
|
|
for/poly for/poly*)
|
|
|
|
(define-for-syntax (curlify stx)
|
|
(syntax-property stx 'paren-shape #\{))
|
|
|
|
|
|
(define-syntax (for/poly stx)
|
|
(syntax-case stx ()
|
|
[(_ clauses . defs+exprs)
|
|
(with-syntax ([original stx])
|
|
#'(for/fold/derived original ([sum (make-zero)]) clauses
|
|
(define d (let () . defs+exprs))
|
|
(values (poly+poly sum d))))]))
|
|
|
|
(define-syntax (for/poly* stx)
|
|
(syntax-case stx ()
|
|
[(_ clauses . defs+exprs)
|
|
(with-syntax ([original stx])
|
|
#'(for/fold/derived original ([sum (mono 0 1)]) clauses
|
|
(define d (let () . defs+exprs))
|
|
(values (poly*poly sum d))))]))
|
|
|
|
(define-syntax (app stx)
|
|
(syntax-case stx (* + - ^ quot+rem quot rem zero? eval constant)
|
|
[{_ k}
|
|
(and (curly? stx) (number? (syntax-e #'k)))
|
|
(syntax/loc stx (mono 0 k))]
|
|
[{_ e}
|
|
(curly? stx)
|
|
(syntax/loc stx
|
|
(let ([v e]) (if (number? v) (mono 0 v) (v))))]
|
|
[{_ * k p}
|
|
(and (curly? stx) (number? (syntax-e #'k)))
|
|
(syntax/loc stx (k*poly k p))]
|
|
[{_ * p k}
|
|
(and (curly? stx) (number? (syntax-e #'k)))
|
|
(syntax/loc stx (k*poly k p))]
|
|
[{_ * p q}
|
|
(curly? stx)
|
|
(syntax/loc stx (poly*poly p q))]
|
|
[{_ * p q r ...}
|
|
(curly? stx)
|
|
(syntax/loc stx {app * {app * p q} r ...})]
|
|
[{_ + k1 k2}
|
|
(and (curly? stx) (number? (syntax-e #'k1)) (number? (syntax-e #'k2)))
|
|
(syntax/loc stx (mono 0 (+ k1 k2)))]
|
|
[{_ + k p}
|
|
(and (curly? stx) (number? (syntax-e #'k)))
|
|
(syntax/loc stx (k+poly k p))]
|
|
[{_ + p k}
|
|
(and (curly? stx) (number? (syntax-e #'k)))
|
|
(syntax/loc stx (k+poly k p))]
|
|
[{_ + p q}
|
|
(curly? stx)
|
|
(syntax/loc stx (poly+poly p q))]
|
|
[{_ + p q r ...}
|
|
(curly? stx)
|
|
(syntax/loc stx {app + {app + p q} r ...})]
|
|
[{_ - p}
|
|
(curly? stx)
|
|
(syntax/loc stx (k*poly -1 p))]
|
|
[{_ - k1 k2}
|
|
(and (curly? stx) (number? (syntax-e #'k1)) (number? (syntax-e #'k2)))
|
|
(syntax/loc stx (mono 0 (- k1 k2)))]
|
|
[{_ - k p}
|
|
(and (curly? stx) (number? (syntax-e #'k)))
|
|
(syntax/loc stx (k+poly (- k) p))]
|
|
[{_ - p k}
|
|
(and (curly? stx) (number? (syntax-e #'k)))
|
|
(syntax/loc stx (k+poly (- k) p))]
|
|
[{_ - p q}
|
|
(curly? stx)
|
|
(syntax/loc stx (poly-poly p q))]
|
|
[{_ ^ k1 k2}
|
|
(and (curly? stx) (number? (syntax-e #'k1)) (number? (syntax-e #'k2)))
|
|
(syntax/loc stx (mono 0 (expt k1 k2)))]
|
|
[{_ ^ p n}
|
|
(curly? stx)
|
|
(syntax/loc stx (poly^n p n))]
|
|
[{_ zero? p}
|
|
(curly? stx)
|
|
(syntax/loc stx (poly-zero? p))]
|
|
[{_ eval p x0}
|
|
(curly? stx)
|
|
(syntax/loc stx (poly-eval p x0))]
|
|
[{_ constant e}
|
|
(curly? stx)
|
|
(syntax/loc stx (mono 0 e))]
|
|
[(_ . more)
|
|
(syntax/loc stx (#%app . more))])))
|
|
|
|
(module poly racket
|
|
(require (submod ".." poly-base-syntax)
|
|
(for-syntax (submod ".." common)))
|
|
(provide (except-out (all-from-out (submod ".." poly-base-syntax)) #%app)
|
|
(rename-out [app #%app])
|
|
poly-quot+rem poly-quot poly-rem poly-gcd
|
|
poly-compose)
|
|
|
|
#;(define (poly-quot+rem p1 p2)
|
|
(define lc leading-coef)
|
|
(let ([m (degree p1)]
|
|
[n (degree p2)])
|
|
(cond
|
|
[(< m n) (values (make-zero) p1)]
|
|
[(= m n) (let ([q (/ (lc p1) (lc p2))])
|
|
(values (mono 0 q) (poly-poly p1 (k*poly q p2))))]
|
|
[else (let* ([q (/ (lc p1) (lc p2))]
|
|
[p1* (poly-poly p1 (poly*poly (mono (- m n) q) p2))])
|
|
(let-values ([(q1 r) (poly-quot+rem p1* p2)])
|
|
(values (poly+poly q1 (mono (- m n) q)) r)))])))
|
|
|
|
(define (poly-quot+rem p1 p2)
|
|
(define lc leading-coef)
|
|
(let ([m (degree p1)]
|
|
[n (degree p2)])
|
|
(cond
|
|
[(< m n) (values {0} p1)]
|
|
[(= m n) (let ([q (/ (lc p1) (lc p2))])
|
|
(values {q} {- p1 {* {constant q} p2}}))]
|
|
[else (let* ([q (/ (lc p1) (lc p2))]
|
|
[p1* {- p1 {* (mono (- m n) q) p2}}])
|
|
(let-values ([(q1 r) (poly-quot+rem p1* p2)])
|
|
(values {+ q1 (mono (- m n) q)} r)))])))
|
|
|
|
(define (poly-quot p1 p2)
|
|
(let-values ([(q r) (poly-quot+rem p1 p2)])
|
|
q))
|
|
|
|
(define (poly-rem p1 p2)
|
|
(let-values ([(q r) (poly-quot+rem p1 p2)])
|
|
r))
|
|
|
|
(define (poly-gcd p1 p2)
|
|
(if (< (degree p1) (degree p2))
|
|
(poly-gcd p2 p1)
|
|
(let loop ([r0 p1] [r1 p2])
|
|
(if {zero? r1}
|
|
r0
|
|
(loop r1 (poly-rem r0 r1))))))
|
|
|
|
(define (poly-compose p q)
|
|
;; computes p(q(x))
|
|
(for/poly ([(i ci) (in-terms p)])
|
|
{* {constant ci} {^ q i}}))
|
|
|
|
(define-syntax (app stx)
|
|
(syntax-case stx (quot+rem quot rem gcd)
|
|
[{_ rem p1 p2}
|
|
(syntax/loc stx (poly-rem p1 p2))]
|
|
[{_ gcd p1 p2}
|
|
(syntax/loc stx (poly-gcd p1 p2))]
|
|
[{_ quot p1 p2}
|
|
(syntax/loc stx (poly-quot p1 p2))]
|
|
[{_ quot+rem p1 p2}
|
|
(syntax/loc stx (poly-quot+rem p1 p2))]
|
|
[(_ . more)
|
|
(syntax/loc stx (#%app . more))]))
|
|
|
|
)
|
|
|
|
(module summation racket
|
|
(require (submod ".." poly))
|
|
(provide symbolic-sum
|
|
poly-delta poly-shift
|
|
poly-falling-factorial poly-rising-factorial
|
|
binomial stirling-2)
|
|
|
|
; binomial : natural natural -> natural
|
|
; compute the binomial coeffecient n choose k
|
|
(define (binomial n k)
|
|
; ; <http://www.swox.com/gmp/manual/Binomial-Coefficients-Algorithm.html>
|
|
; TODO: Check range of n and k
|
|
(cond
|
|
[(= k 0) 1]
|
|
[(= k 1) n]
|
|
[(= k 2) (/ (* n (- n 1)) 2)]
|
|
[(> k (/ n 2)) (binomial n (- n k))]
|
|
[else (* (+ n (- k) 1)
|
|
(for/product ([i (in-range 2 (+ k 1))])
|
|
(/ (+ n (- k) i)
|
|
i)))]))
|
|
|
|
(define (poly-shift p [k 1])
|
|
;; computes p(x+k)
|
|
(poly-compose p {+ (mono 1 1) {constant k}}))
|
|
|
|
(define (poly-delta p)
|
|
;; computes p(x+1) - p(x)
|
|
{- (poly-shift p) p})
|
|
|
|
(define (poly-falling-factorial p m)
|
|
;; computes p(x) * p(x-1) * ... * p(x-m+1)
|
|
;; there are m factors in the product
|
|
(for/poly* ([i (in-range m)])
|
|
(poly-shift p (- i))))
|
|
|
|
(define (poly-rising-factorial p m)
|
|
;; computes p(x) * p(x+1) * ... * p(x+m-1)
|
|
;; there are m factors in the product
|
|
(for/poly* ([i (in-range m)])
|
|
(poly-shift p i)))
|
|
|
|
(define (stirling-2 m i)
|
|
; TODO: *very* naïve implementation
|
|
(cond
|
|
[(and (= i 0) (= m 0)) 1]
|
|
[(= i 0) 0]
|
|
[(> i m) 0]
|
|
[else (+ (stirling-2 (- m 1) (- i 1))
|
|
(* i (stirling-2 (- m 1) i)))]))
|
|
|
|
;;; (symbolic-sum p) = Sigma p(k)
|
|
;;; 0<=k<x
|
|
(define (symbolic-sum p)
|
|
(define x (mono 1 1))
|
|
(if {zero? p}
|
|
(make-zero)
|
|
(for/poly ([(i ci) (in-terms p)])
|
|
(for/poly ([j (in-range (+ i 1))])
|
|
{* {constant (* ci (/ (stirling-2 i j) (+ j 1)))}
|
|
(poly-falling-factorial x (+ j 1))}))))
|
|
|
|
|
|
; Sum of the first million cubes.
|
|
; > (my-poly-eval (symbolic-sum x^3) 1000001)
|
|
; 250000500000250000000000
|
|
|
|
|
|
)
|
|
|
|
(module sturm racket
|
|
(require (submod ".." poly))
|
|
(provide sturm-sequence
|
|
count-sign-changes
|
|
count-real-roots-in-interval)
|
|
|
|
(define (sturm-sequence p)
|
|
(define (next p_n p_n+1)
|
|
{- {rem p_n p_n+1}})
|
|
(define p0 p)
|
|
(define p1 {deriv p})
|
|
(define p*
|
|
(let loop ([p_n p0]
|
|
[p_n+1 p1])
|
|
(if {zero? p_n+1}
|
|
(list p_n)
|
|
(cons p_n (loop p_n+1 (next p_n p_n+1))))))
|
|
p*)
|
|
|
|
(define (count-sign-changes xs)
|
|
(define (same-sign? r s)
|
|
(or (and (positive? r)
|
|
(positive? s))
|
|
(and (negative? r)
|
|
(negative? s))))
|
|
(match xs
|
|
[(list) 0]
|
|
[(list x1) 0]
|
|
[(list x1 x2 x3 ...)
|
|
(+ (if (same-sign? x1 x2) 0 1)
|
|
(count-sign-changes (cons x2 x3)))]))
|
|
|
|
(define (count-real-roots-in-interval p a b)
|
|
; http://audition.ens.fr/brette/calculscientifique/lecture8.pdf
|
|
; http://www.di.ens.fr/~ponce/scicomp/notes.pdf
|
|
; should p be square-free?
|
|
(define x (mono 1 1))
|
|
(define (poly-eval p x0)
|
|
{leading-coef {rem p {- x {x0}}}}) ; TODO: Use fix horner
|
|
(define (count x0)
|
|
(count-sign-changes
|
|
(map (λ (p) (poly-eval p x0))
|
|
(sturm-sequence p))))
|
|
(- (count a) (count b)))
|
|
|
|
)
|
|
|
|
(require 'poly)
|
|
(require 'sturm)
|
|
(require 'summation)
|
|
|
|
(define x (mono 1 1))
|
|
(define x^2 (mono 2 1))
|
|
(define x^3 (mono 3 1))
|
|
|
|
(current-poly-display infix-poly-display)
|
|
(poly-quot+rem {+ {^ x 3} {^ x 2}} {^ x 3})
|
|
|
|
(define (my-poly-eval p x0)
|
|
(define x (mono 1 1))
|
|
; TODO
|
|
{leading-coef {rem p {- x {x0}}}})
|
|
|
|
|