racket/collects/math/private/matrix/matrix-basis.rkt
Neil Toronto 7ac8e1bbce Slightly more `math/matrix'
* Moved to-do list in "matrix-operations.rkt" to the wiki

* Added more mutating vector ops

* Added "matrix-basis.rkt" (unfinished)
2012-12-27 17:30:04 -07:00

113 lines
4.6 KiB
Racket

#lang typed/racket
(require racket/fixnum
math/array
math/matrix
"matrix-column.rkt"
"utils.rkt"
"../unsafe.rkt"
"../vector/vector-mutate.rkt"
)
(: col-matrix-project1 (case-> ((Matrix Real) (Matrix Real) Any -> (U #f (Matrix Real)))
((Matrix Number) (Matrix Number) Any -> (U #f (Matrix Number)))))
(define (col-matrix-project1 v b unit?)
(cond [unit? (matrix-scale b (matrix-dot v b))]
[else (define b.b (matrix-dot b b))
(cond [(and (zero? b.b) (exact? b.b)) #f]
[else (matrix-scale b (/ (matrix-dot v b) b.b))])]))
(: col-matrix-project
(All (A) (case-> ((Matrix Real) (Matrix Real) -> (Matrix Real))
((Matrix Real) (Matrix Real) Any -> (U A (Matrix Real)))
((Matrix Real) (Matrix Real) Any (-> A) -> (U A (Matrix Real)))
((Matrix Number) (Matrix Number) -> (Matrix Number))
((Matrix Number) (Matrix Number) Any -> (U A (Matrix Number)))
((Matrix Number) (Matrix Number) Any (-> A) -> (U A (Matrix Number))))))
(define col-matrix-project
(case-lambda
[(v B) (col-matrix-project v B #f)]
[(v B unit?)
(col-matrix-project
v B unit?
(λ () (error 'col-matrix-project "expected basis with nonzero column vectors; given ~e" B)))]
[(v B unit? fail)
(unless (col-matrix? v) (raise-argument-error 'col-matrix-project "col-matrix?" v))
(define bs (matrix-cols (ensure-matrix 'col-matrix-project B)))
(define p (col-matrix-project1 v (first bs) unit?))
(cond [p (let loop ([bs (rest bs)] [p p])
(cond [(empty? bs) p]
[else (define q (col-matrix-project1 v (first bs) unit?))
(if q (loop (rest bs) (matrix+ p q)) (fail))]))]
[else (fail)])]))
(: find-nonzero-vector (case-> ((Vectorof (Vectorof Real)) -> (U #f Index))
((Vectorof (Vectorof Number)) -> (U #f Index))))
(define (find-nonzero-vector vss)
(define n (vector-length vss))
(cond [(= n 0) #f]
[else (let loop ([#{i : Nonnegative-Fixnum} 0])
(cond [(i . fx< . n)
(define vs (unsafe-vector-ref vss i))
(if (vector-zero? vs) (loop (fx+ i 1)) i)]
[else #f]))]))
(: subtract-projections!
(case-> ((Vectorof (Vectorof Real)) Index Index (Vectorof Real) Any -> Void)
((Vectorof (Vectorof Number)) Index Index (Vectorof Number) Any -> Void)))
(define (subtract-projections! cols n i ci unit?)
(let j-loop ([#{j : Nonnegative-Fixnum} (fx+ i 1)])
(when (j . fx< . n)
(vector-sub-proj! (unsafe-vector-ref cols j) ci unit?)
(j-loop (fx+ j 1)))))
(: matrix-gram-schmidt (All (A) (case-> ((Matrix Real) -> (Array Real))
((Matrix Real) Any -> (Array Real))
((Matrix Number) -> (Array Number))
((Matrix Number) Any -> (Array Number)))))
(define (matrix-gram-schmidt M [unit? #f])
(define rows (matrix->vector* M))
(define n (vector-length rows))
(define i (find-nonzero-vector rows))
(cond [i (define rowi (unsafe-vector-ref rows i))
(subtract-projections! rows n i rowi #f)
(when unit? (vector-normalize! rowi))
(let loop ([#{i : Nonnegative-Fixnum} (fx+ i 1)] [bs (list rowi)])
(cond [(i . fx< . n)
(define rowi (unsafe-vector-ref rows i))
(cond [(vector-zero? rowi) (loop (fx+ i 1) bs)]
[else (subtract-projections! rows n i rowi #f)
(when unit? (vector-normalize! rowi))
(loop (fx+ i 1) (cons rowi bs))])]
[else
(vector*->matrix (list->vector (reverse bs)))]))]
[else
(make-array (vector 0 (matrix-num-cols M)) 0)]))
#|
(define a (col-matrix [1 2 1]))
(define b (col-matrix [1 -2 2]))
(define basis
(gram-schmidt-orthogonal
(matrix-cols
(array #[#[2 1 0] #[2 2 1] #[0 2 0]]))))
(column-project a b)
(col-matrix-project a b)
(projection-on-orthogonal-basis a basis)
(col-matrix-project a (matrix-augment basis))
(projection-on-orthonormal-basis a basis)
(col-matrix-project a (matrix-augment basis) 'orthonormal)
(matrix-gram-schmidt
(matrix [[0 1 2]
[0 2 3]
[0 1 5]]))
(matrix-gram-schmidt
(matrix [[5 1 2]
[2 2 3]
[-3 1 5]]))
|#