#lang scribble/manual @(require (for-label racket "beta.rkt" "yaml.rkt")) @title{SlowThought's Math Library} This library contains functions related to various mathematical topics (currently probability and matrices), which might be of general interest. @section{Beta distributions} @defmodule[beta]{ Beta functions are sort of binomial distributions in reverse - given a set of data, how likely is it that a given binomial distribution produced it? Questions like this are pondered in Bayesian statistics and its many applications. They are handy in many areas where a family of functions with a domain [0,1] is needed. Note that @racket[(make-beta 0 0)] is equivalent in many implementations to @racket[beta[1,1]]. This is because many implementations build the beta function from the gamma function, and then in a typical application have expressions like @racket[beta[x-1,y-1]]. This implementation was built around the Chebyshev integral, and so starting at zero came naturally. Also note that, other than @racket[make-binomial], these functions' arguments are limited to non-negative integers. This allows @racket[chebyshev-integral] to return an analytic solution, as opposed to the typical numerical one.} @defproc[(make-binomial [x real?]) procedure?]{ returns a thunk that returns either #t or #f, with x providing the expectation of #t. It is provided to generate data sets for testing the other functions described in this section.} @defproc[(make-beta [t natural-number/c] [f natural-number/c]) procedure?]{ returns a probability density function of the form @racket[(f x)], which describes the likelihood that a function like those generated by @racket[make-binomial] produced so many #t and #f.} @defproc[(make-cumulative-beta [t natural-number/c] [f natural-number/c]) procedure?]{ returns a function that calculates the integral of @racket[(make-beta t f)].} @defproc[(chebyshev-integral [p natural-number/c] [q natural-number/c]) procedure?]{ returns a function which evaluates the expression @(centered (image/plain "chebyshev.png")) from 0 to x. This is the horsepower behind the other functions. It is provided for those who need to "roll their own" solutions for performance reasons.} @section{YAML -- Yet Another Matrix Library} @defmodule[yaml]{ Two dimensional matrices are implemented as vectors of vectors, and attempt to emulate vectors' syntax and behaviour. The unique part of this implementation is the ability to easily substitute different arithmetic operators in some functions so that you can do operations on, for example, matrices of quaternions or polynomials (coming soon to a planet near you). Also coming soon, a more complete implementation, including, for instance, determinants that can handle quaternions or polynomials. For now, there are Racket-like constructors, accessors, and operators, and some arithmetic operators.} @subsection{Constructors} @defproc*[([(make-matrix [nrows (and/c positive? integer?)] [ncolumns (and/c positive? integer?)]) matrix?] [(make-matrix [nrows (and/c positive? integer?)] [ncolumns (and/c positive? integer?)] [initialize any]) matrix?])]{ returns a matrix. Each value in the matrix is set to @racket[0], or to @racket[initialize], if provided.} @defproc[(build-matrix [nrows (and/c positive? integer?)] [ncolumns (and/c positive? integer?)] [initialize procedure?]) matrix?]{ @scheme[initialize] is a function of the form @scheme[(f irow icolumn)] which is used to fill the returned matrix.} Immutable matrices are just as you'd expect: @schemeblock[(define my-immutable-matrix #(#(1 2 3) #(4 5 6)))] As are mutable matrices: @schemeblock[(define my-mutable-matrix (vector (vector 6 5 4) (vector 3 2 1)))] Some sugar is provided in the name of implementation hiding and readability. The following is equivalent to the last example: @schemeblock[(define my-pretty-matrix (matrix (row 6 5 4) (row 3 2 1)))] @subsection{Accessors} YAML follows Scheme/Racket conventions for vectors. @defproc[(matrix? [m any/c]) boolean?]{ ... is not very robust. A well constructed matrix is a vector of vectors of identical size. If the library's constructors are used, this is garunteed, but @scheme[matrix?] is not yet suspicious of the creative or the evil.} @defproc[(matrix-size [m matrix?])(values exact-positive-integer? exact-positive-integer?)]{ returns the numbers of rows and columns of the matrix @scheme[m] via @scheme[values].} @defproc[(matrix-ref [m matrix?] [row natural-number/c] [column natural-number/c]) any]{ returns the contents of @scheme[m].} @defproc[(matrix-set! [m matrix?] [row natural-number/c] [column natural-number/c] [value any]) any]{ changes the contents of @scheme[m].} @subsection{Operators} Again, YAML tries to follow Scheme/Racket convention. @defproc[(matrix-map [proc procedure?] [m matrix?] ... ) matrix?]{ works in the same fashion as @scheme[vector-map]. Because it is so straight-forward, no seperate implementation is offered for addition, subtraction, or scalar multiplication.} Things start to get complicated when you introduce multiplication. Multipliers have optional arguments for @racket[*] and @racket[+] for the user to provide appropriate operators for his/her special type. @defproc*[([(matrix*vector [m matrix?] [v vector?]) vector?] [(matrix*vector [m matrix?] [v vector?] [multiply *] [add +]) vector?])]{ multiplies a matrix by (the transpose of) a vector to produce another vector.} @defproc*[([(matrix*matrix (m1 matrix?) (m2 matrix?)) matrix?] [(matrix*matrix [m1 matrix?] [m2 matrix?] [multiply *] [add +]) matrix?])]{ multiplies two matrices to produce another one.} @defproc[(transpose (m matrix?)) matrix?]{ returns the transpose of @scheme[m].}