racket/collects/math/private/matrix/matrix-operator-norm.rkt
Neil Toronto e5eb9751f0 Initial `math/matrix' documentation, and some changes
* At least stubbed out all (or almost all) `math/matrix' exports; many
  have complete documentation (e.g. types, predicates, accessors,
  constructors, for loops, conversion, much of "Comparing Matrices")

* Moved `matrix-zero?' and fixed to use (matrix-error-norm) as its norm

* Added `matrix-basis-cos-angle' (currently a stub; should return smallest
  singular value of a certain matrix multiplication)
2013-01-01 18:19:43 -07:00

138 lines
5.4 KiB
Racket

#lang typed/racket/base
#|
Two of the functions defined here currently just raise an error: `matrix-op-2norm' and
`matrix-op-angle'. They need to compute, respectively, the maximum and minimum singular values of
their matrix argument.
See "How to Measure Errors" in the LAPACK manual for more details:
http://www.netlib.org/lapack/lug/node75.html
http://www.netlib.org/lapack/lug/node76.html
|#
(require racket/list
racket/fixnum
math/flonum
"matrix-types.rkt"
"matrix-arithmetic.rkt"
"matrix-constructors.rkt"
"matrix-basic.rkt"
"utils.rkt"
"../array/array-struct.rkt"
"../array/array-pointwise.rkt"
"../array/array-fold.rkt"
)
(provide
;; Operator norms
matrix-op-1norm
matrix-op-2norm
matrix-op-inf-norm
matrix-basis-cos-angle
matrix-basis-angle
;; Error measurement
matrix-error-norm
matrix-absolute-error
matrix-relative-error
;; Approximate predicates
matrix-zero?
matrix-identity?
matrix-orthonormal?
)
(: matrix-op-1norm ((Matrix Number) -> Nonnegative-Real))
;; When M is a column matrix, this is equivalent to matrix-1norm
(define (matrix-op-1norm M)
(assert (apply max (map matrix-1norm (matrix-cols M))) nonnegative?))
(: matrix-op-2norm ((Matrix Number) -> Nonnegative-Real))
;; When M is a column matrix, this is equivalent to matrix-2norm
(define (matrix-op-2norm M)
;(matrix-max-singular-value M)
;(sqrt (matrix-max-eigenvalue M))
(error 'unimplemented))
(: matrix-op-inf-norm ((Matrix Number) -> Nonnegative-Real))
;; When M is a column matrix, this is equivalent to matrix-inf-norm
(define (matrix-op-inf-norm M)
(assert (apply max (map matrix-1norm (matrix-rows M))) nonnegative?))
(: matrix-basis-cos-angle (case-> ((Matrix Real) (Matrix Real) -> Real)
((Matrix Number) (Matrix Number) -> Number)))
;; Returns the angle between the two subspaces spanned by the two given sets of column vectors
(define (matrix-basis-cos-angle M R)
;(matrix-min-singular-value (matrix* (matrix-hermitian M) R))
(error 'unimplemented))
(: matrix-basis-angle (case-> ((Matrix Real) (Matrix Real) -> Real)
((Matrix Number) (Matrix Number) -> Number)))
;; Returns the angle between the two subspaces spanned by the two given sets of column vectors
(define (matrix-basis-angle M R)
(acos (matrix-basis-cos-angle M R)))
;; ===================================================================================================
;; Error measurement
(: matrix-error-norm (Parameterof ((Matrix Number) -> Nonnegative-Real)))
(define matrix-error-norm (make-parameter matrix-op-inf-norm))
(: matrix-absolute-error
(case-> ((Matrix Number) (Matrix Number) -> Nonnegative-Real)
((Matrix Number) (Matrix Number) ((Matrix Number) -> Nonnegative-Real)
-> Nonnegative-Real)))
(define (matrix-absolute-error M R [norm (matrix-error-norm)])
(define-values (m n) (matrix-shapes 'matrix-absolute-error M R))
(array-strict! M)
(array-strict! R)
(cond [(array-all-and (inline-array-map eqv? M R)) 0]
[(and (array-all-and (inline-array-map number-rational? M))
(array-all-and (inline-array-map number-rational? R)))
(norm (matrix- (inline-array-map inexact->exact M)
(inline-array-map inexact->exact R)))]
[else +inf.0]))
(: matrix-relative-error
(case-> ((Matrix Number) (Matrix Number) -> Nonnegative-Real)
((Matrix Number) (Matrix Number) ((Matrix Number) -> Nonnegative-Real)
-> Nonnegative-Real)))
(define (matrix-relative-error M R [norm (matrix-error-norm)])
(define-values (m n) (matrix-shapes 'matrix-relative-error M R))
(array-strict! M)
(array-strict! R)
(cond [(array-all-and (inline-array-map eqv? M R)) 0]
[(and (array-all-and (inline-array-map number-rational? M))
(array-all-and (inline-array-map number-rational? R)))
(define num (norm (matrix- M R)))
(define den (norm R))
(cond [(and (zero? num) (zero? den)) 0]
[(zero? den) +inf.0]
[else (assert (/ num den) nonnegative?)])]
[else +inf.0]))
;; ===================================================================================================
;; Approximate predicates
(: matrix-zero? (case-> ((Matrix Number) -> Boolean)
((Matrix Number) Real -> Boolean)))
(define (matrix-zero? M [eps (* 10 epsilon.0)])
(cond [(eps . < . 0) (raise-argument-error 'matrix-identity? "Nonnegative-Real" 1 M eps)]
[else
(define-values (m n) (matrix-shape M))
(<= (matrix-absolute-error M (make-matrix m n 0)) eps)]))
(: matrix-identity? (case-> ((Matrix Number) -> Boolean)
((Matrix Number) Real -> Boolean)))
(define (matrix-identity? M [eps (* 10 epsilon.0)])
(cond [(eps . < . 0) (raise-argument-error 'matrix-identity? "Nonnegative-Real" 1 M eps)]
[else (and (square-matrix? M)
(<= (matrix-relative-error M (identity-matrix (square-matrix-size M))) eps))]))
(: matrix-orthonormal? (case-> ((Matrix Number) -> Boolean)
((Matrix Number) Real -> Boolean)))
(define (matrix-orthonormal? M [eps (* 10 epsilon.0)])
(cond [(eps . < . 0) (raise-argument-error 'matrix-orthonormal? "Nonnegative-Real" 1 M eps)]
[else (and (square-matrix? M)
(matrix-identity? (matrix* M (matrix-hermitian M)) eps))]))