racket/collects/math/private/matrix/matrix-column.rkt
Neil Toronto 8d5a069d41 Moar `math/matrix' review/refactoring
* Split "matrix-constructors.rkt" into three parts:
 * "matrix-constructors.rkt"
 * "matrix-conversion.rkt"
 * "matrix-syntax.rkt"

* Made `matrix-map' automatically inline (it's dirt simple)

* Renamed a few things, changed some type signatures

* Fixed error in `matrix-dot' caught by testing (it was broadcasting)

* Rewrote matrix comprehensions in terms of array comprehensions

* Removed `in-column' and `in-row' (can use `in-array', `matrix-col' and
  `matrix-row')

* Tons of new rackunit tests: only "matrix-2d.rkt" and
  "matrix-operations.rkt" are left (though the latter is large)
2012-12-20 17:32:16 -07:00

127 lines
4.2 KiB
Racket

#lang typed/racket/base
(require math/array
math/base
"matrix-types.rkt"
"matrix-conversion.rkt"
"matrix-arithmetic.rkt"
"../unsafe.rkt")
(provide unit-column
column-height
unsafe-column->vector
column-scale
column+
column-dot
column-norm
column-project
column-project/unit
column-normalize)
(: unit-column : Integer Integer -> (Result-Column Number))
(define (unit-column m i)
(cond
[(and (index? m) (index? i))
(define v (make-vector m 0))
(if (< i m)
(vector-set! v i 1)
(error 'unit-vector "dimension must be largest"))
(vector->matrix m 1 v)]
[else
(error 'unit-vector "expected two indices")]))
(: column-height : (Column Number) -> Index)
(define (column-height v)
(if (vector? v)
(vector-length v)
(matrix-num-rows v)))
(: unsafe-column->vector : (Column Number) -> (Vectorof Number))
(define (unsafe-column->vector v)
(if (vector? v) v
(let ()
(define-values (m n) (matrix-shape v))
(if (= n 1)
(mutable-array-data (array->mutable-array v))
(error 'unsafe-column->vector
"expected a column (vector or mx1 matrix), got ~a" v)))))
(: column-scale : (Column Number) Number -> (Result-Column Number))
(define (column-scale a s)
(if (vector? a)
(let*: ([n (vector-length a)]
[v : (Vectorof Number) (make-vector n 0)])
(for: ([i (in-range 0 n)]
[x : Number (in-vector a)])
(vector-set! v i (* s x)))
(->col-matrix v))
(matrix-scale a s)))
(: column+ : (Column Number) (Column Number) -> (Result-Column Number))
(define (column+ v w)
(cond [(and (vector? v) (vector? w))
(let ([n (vector-length v)]
[m (vector-length w)])
(unless (= m n)
(error 'column+
"expected two column vectors of the same length, got ~a and ~a" v w))
(define: v+w : (Vectorof Number) (make-vector n 0))
(for: ([i (in-range 0 n)]
[x : Number (in-vector v)]
[y : Number (in-vector w)])
(vector-set! v+w i (+ x y)))
(->col-matrix v+w))]
[else
(unless (= (column-height v) (column-height w))
(error 'column+
"expected two column vectors of the same length, got ~a and ~a" v w))
(array+ (->col-matrix v) (->col-matrix w))]))
(: column-dot : (Column Number) (Column Number) -> Number)
(define (column-dot c d)
(define v (unsafe-column->vector c))
(define w (unsafe-column->vector d))
(define m (column-height v))
(define s (column-height w))
(cond
[(not (= m s)) (error 'column-dot
"expected two mx1 matrices with same number of rows, got ~a and ~a"
c d)]
[else
(for/sum: : Number ([i (in-range 0 m)])
(assert i index?)
; Note: If d is a vector of reals,
; then the conjugate is a no-op
(* (unsafe-vector-ref v i)
(conjugate (unsafe-vector-ref w i))))]))
(: column-norm : (Column Number) -> Real)
(define (column-norm v)
(define norm (sqrt (column-dot v v)))
(assert norm real?))
(: column-project : (Column Number) (Column Number) -> (Result-Column Number))
; (column-project v w)
; Return the projection og vector v on vector w.
(define (column-project v w)
(let ([w.w (column-dot w w)])
(if (zero? w.w)
(error 'column-project "projection on the zero vector not defined")
(matrix-scale (->col-matrix w) (/ (column-dot v w) w.w)))))
(: column-project/unit : (Column Number) (Column Number) -> (Result-Column Number))
; (column-project-on-unit v w)
; Return the projection og vector v on a unit vector w.
(define (column-project/unit v w)
(matrix-scale (->col-matrix w) (column-dot v w)))
(: column-normalize : (Column Number) -> (Result-Column Number))
; (column-vector-normalize v)
; Return unit vector with same direction as v.
; If v is the zero vector, the zero vector is returned.
(define (column-normalize w)
(let ([norm (column-norm w)]
[w (->col-matrix w)])
(cond [(zero? norm) w]
[else (matrix-scale w (/ norm))])))