├── tests ├── integ-1.expect ├── matrix-1.expect ├── nlinfit.expect ├── matrix-1.lua ├── matrix-2.lua ├── integ-1.lua ├── matrix-2.expect ├── test_coulomb.expect ├── matrix-3.expect ├── matrix-3.lua ├── test_dilog.expect ├── nlinfit.lua ├── test_coulomb.lua ├── test-output.py ├── test_dilog.lua ├── randist.expect ├── test_airy.expect ├── test_legendre.expect └── randist.lua ├── .gitignore ├── doc ├── vegas.png ├── sf-bessel-Y.png ├── example-linfit.png ├── example-bessJ-plot.png ├── example-bsplines-plot.png ├── nlinfit-example-plot.png ├── sf-besselJ-functions.png ├── zernicke-contour-3-1.png ├── zernicke-contour-5-1.png ├── zernicke-contour-5-5.png ├── zernicke-contour-8-2.png ├── fft-example-time-signal.png ├── lmfit-enso-dataset-plot.png ├── fft-example-power-spectrum.png ├── examples-airy-functions-plot.png ├── ode-integration-quasi-spiral.png ├── examples-legendre-polynomials.png ├── index.rst ├── intro-example.lua ├── linfit.rst ├── lua-base.rst ├── integ.rst ├── bsplines.rst ├── gsl-ffi.rst ├── linalg.rst ├── examples.rst └── pdf.rst ├── lgsl ├── gsl-check.lua ├── check.lua ├── complex.lua ├── sf.lua ├── rnd.lua ├── templates │ ├── ode-defs.lua.in │ ├── rnd-defs.lua.in │ ├── rk4.lua.in │ ├── rkf45.lua.in │ ├── rkf45vec.lua.in │ └── rk8pd.lua.in ├── ode.lua ├── nlinfit.lua ├── integ.lua ├── csv.lua ├── linfit.lua ├── rng.lua ├── iter.lua ├── bspline.lua ├── template.lua ├── vegas.lua ├── randist.lua └── sort.lua ├── .travis.yml ├── benchmarks └── integration │ ├── qag-bench.lua │ ├── vegas-bench.lua │ ├── qag-bench.c │ └── vegas-bench.c ├── debian ├── build.sh └── control ├── demos ├── integ.lua ├── bspline.lua ├── sf.lua ├── plot.lua ├── linfit.lua ├── vegas.lua ├── anim.lua ├── nlinfit.lua ├── fft.lua ├── demos.lua ├── roots.lua ├── fractals.lua └── ode.lua ├── lgsl.lua ├── Makefile ├── test-output.lua ├── lgsl-0.1-1.rockspec ├── lgsl-scm-3.rockspec └── README.md /tests/integ-1.expect: -------------------------------------------------------------------------------- 1 | 2 2 | 1 3 | 0.1 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*~ 2 | .*.swp 3 | debian_build 4 | tests/log 5 | -------------------------------------------------------------------------------- /doc/vegas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/vegas.png -------------------------------------------------------------------------------- /tests/matrix-1.expect: -------------------------------------------------------------------------------- 1 | dim 3 3 2 | [ 0 0 0 ] 3 | [ 0 0 0 ] 4 | [ 0 0 0 ] 5 | -------------------------------------------------------------------------------- /doc/sf-bessel-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/sf-bessel-Y.png -------------------------------------------------------------------------------- /doc/example-linfit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/example-linfit.png -------------------------------------------------------------------------------- /doc/example-bessJ-plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/example-bessJ-plot.png -------------------------------------------------------------------------------- /doc/example-bsplines-plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/example-bsplines-plot.png -------------------------------------------------------------------------------- /doc/nlinfit-example-plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/nlinfit-example-plot.png -------------------------------------------------------------------------------- /doc/sf-besselJ-functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/sf-besselJ-functions.png -------------------------------------------------------------------------------- /doc/zernicke-contour-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/zernicke-contour-3-1.png -------------------------------------------------------------------------------- /doc/zernicke-contour-5-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/zernicke-contour-5-1.png -------------------------------------------------------------------------------- /doc/zernicke-contour-5-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/zernicke-contour-5-5.png -------------------------------------------------------------------------------- /doc/zernicke-contour-8-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/zernicke-contour-8-2.png -------------------------------------------------------------------------------- /doc/fft-example-time-signal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/fft-example-time-signal.png -------------------------------------------------------------------------------- /doc/lmfit-enso-dataset-plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/lmfit-enso-dataset-plot.png -------------------------------------------------------------------------------- /doc/fft-example-power-spectrum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/fft-example-power-spectrum.png -------------------------------------------------------------------------------- /doc/examples-airy-functions-plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/examples-airy-functions-plot.png -------------------------------------------------------------------------------- /doc/ode-integration-quasi-spiral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/ode-integration-quasi-spiral.png -------------------------------------------------------------------------------- /tests/nlinfit.expect: -------------------------------------------------------------------------------- 1 | GOAL=: 1.55 -1.1 12.5 2 | ITER= 0 : 2.5 -1.5 5.3 7.8370807 3 | ITER= 20 : 1.55 -1.1 12.5 0 4 | -------------------------------------------------------------------------------- /doc/examples-legendre-polynomials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladc/lgsl/HEAD/doc/examples-legendre-polynomials.png -------------------------------------------------------------------------------- /tests/matrix-1.lua: -------------------------------------------------------------------------------- 1 | local matrix = require("lgsl.matrix") 2 | local m = matrix.new(3, 3) 3 | print("dim", m:dim()) 4 | print(m) 5 | 6 | -------------------------------------------------------------------------------- /tests/matrix-2.lua: -------------------------------------------------------------------------------- 1 | local matrix = require("lgsl.matrix") 2 | 3 | local m = matrix.new(8, 8, function(i,j) return i * j end) 4 | print("dim", m:dim()) 5 | print(m) 6 | -------------------------------------------------------------------------------- /tests/integ-1.lua: -------------------------------------------------------------------------------- 1 | local integ = require("lgsl.integ") 2 | local sin, pi = math.sin, math.pi 3 | print(string.format("%.8g", integ.integ(sin, 0, pi))) 4 | print(string.format("%.8g", integ.integ(sin, 0, pi/2))) 5 | print(string.format("%.8g", 0.1 + integ.integ(sin, 0, 2*pi))) 6 | 7 | -------------------------------------------------------------------------------- /lgsl/gsl-check.lua: -------------------------------------------------------------------------------- 1 | 2 | local ffi = require("ffi") 3 | local gsl = require("lgsl.gsl") 4 | 5 | local function gsl_check(status) 6 | if status ~= 0 then 7 | local msg = ffi.string(gsl.gsl_strerror(status)) 8 | error(msg, 2) 9 | end 10 | end 11 | 12 | return gsl_check 13 | -------------------------------------------------------------------------------- /tests/matrix-2.expect: -------------------------------------------------------------------------------- 1 | dim 8 8 2 | [ 1 2 3 4 5 6 7 8 ] 3 | [ 2 4 6 8 10 12 14 16 ] 4 | [ 3 6 9 12 15 18 21 24 ] 5 | [ 4 8 12 16 20 24 28 32 ] 6 | [ 5 10 15 20 25 30 35 40 ] 7 | [ 6 12 18 24 30 36 42 48 ] 8 | [ 7 14 21 28 35 42 49 56 ] 9 | [ 8 16 24 32 40 48 56 64 ] 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # .travis.yml 2 | 3 | language: python 4 | sudo: required 5 | dist: trusty 6 | 7 | env: 8 | - LUA="luajit=2.0" 9 | - LUA="luajit=2.1" 10 | 11 | addons: 12 | apt: 13 | packages: libgsl0ldbl 14 | 15 | before_install: 16 | - pip install hererocks 17 | - hererocks lua_install -r^ --$LUA 18 | - export PATH=$PATH:$PWD/lua_install/bin 19 | - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib 20 | 21 | install: 22 | - luarocks install luacheck 23 | 24 | script: 25 | - luacheck -u --std max+busted lgsl.lua lgsl/*.lua tests/*.lua 26 | - lua test-output.lua 27 | -------------------------------------------------------------------------------- /tests/test_coulomb.expect: -------------------------------------------------------------------------------- 1 | Pass hydrogenicR_1(3.0, 2.0) : 2.575994825614847e-02 2 | Pass hydrogenicR_1(3.0, 10.0) : 9.724727052062820e-13 3 | Pass hydrogenicR(4, 1, 3.0, 0.0) : 0.000000000000000e+00 4 | Pass hydrogenicR(4, 0, 3.0, 2.0) : -3.623182256981820e-02 5 | Pass hydrogenicR(4, 1, 3.0, 2.0) : -2.806504908312958e-02 6 | Pass hydrogenicR(4, 2, 3.0, 2.0) : 1.458302727866843e-01 7 | Pass hydrogenicR(100, 0, 3.0, 2.0): -7.938950980052281e-05 8 | Pass hydrogenicR(100, 10, 3.0, 2.0): 7.112823375353606e-12 9 | Pass hydrogenicR(100, 90, 3.0, 2.0): 5.845231751418131e-245 10 | -------------------------------------------------------------------------------- /tests/matrix-3.expect: -------------------------------------------------------------------------------- 1 | Real scalars only. Single row. 2 | [ 1 2 3 ] 3 | Multi row. 4 | [ 1 2 3 ] 5 | [ 4 5 6 ] 6 | [ 7 8 9 ] 7 | Real and complex scalars. 8 | [ 0+i 2 3 ] 9 | [ 4 0+5i 6 ] 10 | [ 7 8 0+9i ] 11 | Real matrices only. 12 | [ 0 0 1 1 ] 13 | [ 0 0 1 1 ] 14 | [ -1 -1 0 0 ] 15 | [ -1 -1 0 0 ] 16 | Real and complex matrices. 17 | [ 0 0 0+i 0+i ] 18 | [ 0 0 0+i 0+i ] 19 | [ 0-i 0-i 0 0 ] 20 | [ 0-i 0-i 0 0 ] 21 | Real, complex matrices and scalars. 22 | [ 1+i 1+i 1 1 4 ] 23 | [ 1+i 1+i 1 1 4 ] 24 | [ -1 -1 0 0 0+5i ] 25 | [ -1 -1 0 0 0+5i ] 26 | -------------------------------------------------------------------------------- /lgsl/check.lua: -------------------------------------------------------------------------------- 1 | 2 | local check = {} 3 | 4 | local floor = math.floor 5 | local type = type 6 | 7 | local function is_integer(x) 8 | if type(x) == 'number' then 9 | return (floor(x) == x) 10 | else 11 | return false 12 | end 13 | end 14 | 15 | local function is_real(x) 16 | return type(x) == 'number' 17 | end 18 | 19 | function check.integer(x) 20 | if not is_integer(x) then error('integer expected', 2) end 21 | end 22 | 23 | function check.number(x) 24 | if not is_real(x) then error('number expected', 2) end 25 | end 26 | 27 | check.is_integer = is_integer 28 | check.is_real = is_real 29 | 30 | return check 31 | -------------------------------------------------------------------------------- /benchmarks/integration/qag-bench.lua: -------------------------------------------------------------------------------- 1 | local integ = require("lgsl.integ") 2 | local q = integ.prepare({method='qag', limit=1000, order=21}) 3 | 4 | local sin, cos, pi = math.sin, math.cos, math.pi 5 | local epsabs, epsrel = 1e-6, 0.0001 6 | 7 | local function bessel_gen(n) 8 | local xs 9 | local fint = function(t) return cos(n*t - xs*sin(t)) end 10 | return function(x) 11 | xs = x 12 | return q(fint, 0, pi, epsabs, epsrel) 13 | end 14 | end 15 | 16 | local J12 = bessel_gen(12) 17 | 18 | -- p = graph.fxplot(J12, 0, 30*pi) 19 | 20 | local xold, xsmp = -100, 10 21 | for k = 1, 4096*8 do 22 | local x = (k-1) * 30 * math.pi / (4096*8) 23 | local y = J12(x); 24 | if x - xold > xsmp then 25 | io.write(string.format("%.18f %.18f\n",x, y)) 26 | xold = x 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /debian/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | LGT_PACKAGE_NAME=$1 4 | LGT_VERSION=$2 5 | LGT_LUA=$3 6 | LGT_HOMEPAGE=$4 7 | 8 | LGT_ISIZE_A=(`du -s debian_build`) 9 | LGT_ISIZE=${LGT_ISIZE_A[0]} 10 | 11 | LGT_ARCH=all # `dpkg-architecture -qDEB_HOST_ARCH` 12 | LGT_MAINTAINER=$5 13 | if [ -z "$5" ] 14 | then 15 | LGT_MAINTAINER="${USER}@${HOSTNAME}" 16 | fi 17 | 18 | mkdir debian_build/DEBIAN 19 | 20 | cat debian/control | sed "s/LGT_PACKAGE_NAME/$LGT_PACKAGE_NAME/;s/LGT_VERSION/$LGT_VERSION/;s/LGT_INSTALLED_SIZE/$LGT_ISIZE/;s/LGT_ARCH/$LGT_ARCH/;s/LGT_LUA/$LGT_LUA/;s/LGT_MAINTAINER/$LGT_MAINTAINER/;s|LGT_HOMEPAGE|$LGT_HOMEPAGE|" - > debian_build/DEBIAN/control 21 | 22 | chown root.root -R debian_build 23 | chmod a-w -R debian_build 24 | chmod 0755 debian_build/DEBIAN 25 | 26 | dpkg-deb -b debian_build "${LGT_PACKAGE_NAME}_${LGT_VERSION}-1_${LGT_ARCH}.deb" 27 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Package: LGT_PACKAGE_NAME 2 | Maintainer: LGT_MAINTAINER 3 | Version: LGT_VERSION 4 | Architecture: LGT_ARCH 5 | Homepage: LGT_HOMEPAGE 6 | Installed-Size: LGT_INSTALLED_SIZE 7 | Depends: libc6 (>= 2.7-1), libgsl0ldbl (>= 1.14), LGT_LUA 8 | Section: math 9 | Priority: optional 10 | Description: A numerical library for Lua based on GSL 11 | LGSL is a collection of numerical algorithms and functions for Lua, based on the GNU Scientific Library (GSL). It allows matrix/vector manipulation and linear algebra operations. 12 | . 13 | LGSL is not just a wrapper over the C API of GSL but offers a much more simple and expressive way to use GSL. The objective of LGSL is to give the user the power to easily access GSL functions without having to write a complete C application. 14 | . 15 | LGSL is based on the numerical modules of GSL Shell. 16 | -------------------------------------------------------------------------------- /benchmarks/integration/vegas-bench.lua: -------------------------------------------------------------------------------- 1 | local rng = require("lgsl.rng") 2 | local vegas = require("lgsl.vegas") 3 | 4 | local n=9 5 | local lo,hi = 0,2 6 | local exact = n*(n+1)/2 * (hi^3 - lo^3)/3 * (hi-lo)^(n-1) 7 | local a,b={},{} 8 | for i=1,n do 9 | a[i],b[i]=lo,hi 10 | end 11 | local calls = 1e6*n 12 | local r = rng.new('taus2') 13 | r:set(30776) 14 | local function f(x) 15 | return 1*x[1]^2+2*x[2]^2+3*x[3]^2+4*x[4]^2+5*x[5]^2+6*x[6]^2+7*x[7]^2+8*x[8]^2+9*x[9]^2 16 | end 17 | local vegas_result = vegas.integ(f,a,b,calls,{r=r}) 18 | io.write( string.format([[ 19 | vegas final ================== 20 | result = % .10f 21 | sigma = % .10f 22 | exact = % .10f 23 | error = % .10f = %.2g sigma 24 | i = % d 25 | ]] ,vegas_result.result,vegas_result.sigma,exact, vegas_result.result - exact, math.abs(vegas_result.result - exact)/vegas_result.sigma, vegas_result.nruns)) 26 | 27 | -------------------------------------------------------------------------------- /lgsl/complex.lua: -------------------------------------------------------------------------------- 1 | -- complex.lua 2 | -- 3 | -- Support for complex scalar types and arithmetic operators. 4 | -- 5 | -- Copyright (C) 2009-2015 Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | 20 | require("lgsl.matrix") 21 | return package.loaded["lgsl.complex"] 22 | -------------------------------------------------------------------------------- /tests/matrix-3.lua: -------------------------------------------------------------------------------- 1 | local matrix = require("lgsl.matrix") 2 | 3 | print("Real scalars only. Single row.") 4 | local mat0 = matrix.stack({{1,2,3}}) 5 | print(mat0) 6 | 7 | print("Multi row.") 8 | local mat1 = matrix.stack({{1,2,3},{4,5,6},{7,8,9}}) 9 | print(mat1) 10 | 11 | print("Real and complex scalars.") 12 | local mat2 = matrix.stack({{1i,2,3},{4,5i,6},{7,8,9i}}) 13 | print(mat2) 14 | 15 | print("Real matrices only.") 16 | local m1 = matrix.new(2,2) 17 | local mat3 = matrix.stack({{m1,m1+1},{m1-1,m1}}) 18 | print(mat3) 19 | 20 | print("Real and complex matrices.") 21 | local m2 = matrix.cnew(2,2)+1 22 | local mat4 = matrix.stack({{m1,m1+1i},{m1-1i,m1}}) 23 | print(mat4) 24 | 25 | print("Real, complex matrices and scalars.") 26 | local a1 = matrix.cnew(2,2)+1+1i 27 | local a2 = matrix.new(2,2)+1 28 | local a3 = 4 29 | local b1 = matrix.new(2,2)-1 30 | local b2 = matrix.new(2,2) 31 | local b3 = 5i 32 | 33 | local mat5 = matrix.stack({{a1,a2,a3},{b1,b2,b3}}) 34 | print(mat5) 35 | -------------------------------------------------------------------------------- /lgsl/sf.lua: -------------------------------------------------------------------------------- 1 | -- sf.lua 2 | -- 3 | -- Special functions from GSL. 4 | -- 5 | -- Copyright (C) 2009-2015 Benjamin von Ardenne & Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | 21 | local template = require("lgsl.template") 22 | return template.load('lgsl.templates.sf-defs', {}) 23 | -------------------------------------------------------------------------------- /tests/test_dilog.expect: -------------------------------------------------------------------------------- 1 | Pass dilog(-3.0) : -1.939375420766709e+00 2 | Pass dilog(-0.5) : -4.484142069236462e-01 3 | Pass dilog(-0.001) : -9.997501110486512e-04 4 | Pass dilog(0.1) : 1.026177910993911e-01 5 | Pass dilog(0.7) : 8.893776242860387e-01 6 | Pass dilog(1.0) : 1.644934066848226e+00 7 | Pass dilog(1.5) : 2.374395270272480e+00 8 | Pass dilog(2.0) : 2.467401100272339e+00 9 | Pass dilog( 5.0) : 1.783719161266631e+00 10 | Pass dilog( 11.0) : 3.218540439999117e-01 11 | Pass dilog(12.59) : 1.006091816726621e-03 12 | Pass dilog(12.595) : 3.314826006436237e-05 13 | Pass dilog(13.0) : -7.806971248458576e-02 14 | Pass dilog(20.0) : -1.247977086174525e+00 15 | Pass dilog(150.0) : -9.270042702348658e+00 16 | Pass dilog(1100.0) : -2.123250407393175e+01 17 | -------------------------------------------------------------------------------- /lgsl/rnd.lua: -------------------------------------------------------------------------------- 1 | -- rnd.lua 2 | -- 3 | -- Functions for generating random numbers from various distributions. 4 | -- 5 | -- Copyright (C) 2009-2015 Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | 21 | local template = require("lgsl.template") 22 | return template.load('lgsl.templates.rnd-defs', {}) 23 | -------------------------------------------------------------------------------- /demos/integ.lua: -------------------------------------------------------------------------------- 1 | local integ = require("lgsl.integ") 2 | local sf = require("lgsl.sf") 3 | local graph = require("graph") 4 | 5 | local qag = integ.prepare({method='qag', limit=64, order=21}) 6 | local cos, sin, pi = math.cos, math.sin, math.pi 7 | local epsabs, epsrel = 1e-6, 0.01 8 | 9 | local function bessel_gen(n, q) 10 | local xs 11 | local fint = function(t) return cos(n*t - xs*sin(t)) end 12 | return function(x) 13 | xs = x 14 | return q(fint, 0, pi, epsabs, epsrel) / pi 15 | end 16 | end 17 | 18 | local function demo1() 19 | local J4i = bessel_gen(4, qag) 20 | local J4r = function(x) return sf.besselJ(4, x) end 21 | 22 | local p = graph.plot('J4 Bessel function / numerical integration') 23 | p:addline(graph.fxline(J4i, 0, 30*pi), 'red') 24 | p:addline(graph.fxline(J4r, 0, 30*pi), 'blue', {{'dash', 7,3}}) 25 | 26 | p:show() 27 | end 28 | 29 | return {'Numerical Integration', { 30 | { 31 | name = 'numint', 32 | f = demo1, 33 | description = 'Numerical integration of Bessel function' 34 | }, 35 | }} 36 | -------------------------------------------------------------------------------- /benchmarks/integration/qag-bench.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct bessel_param { 6 | double x; 7 | int n; 8 | }; 9 | 10 | double f (double t, void * params) { 11 | struct bessel_param *p = (struct bessel_param *) params; 12 | double x = p->x; 13 | int n = p->n; 14 | return cos(n * t - x * sin(t)); 15 | } 16 | 17 | int 18 | main (void) 19 | { 20 | gsl_integration_workspace * ws = gsl_integration_workspace_alloc (1000); 21 | 22 | struct bessel_param param = {0.0, 12}; 23 | double result, error; 24 | double xold = -100, xsmp = 10; 25 | int k; 26 | 27 | gsl_function F; 28 | F.function = &f; 29 | F.params = ¶m; 30 | 31 | for (k = 0; k < 4096 * 8; k++) 32 | { 33 | param.x = (k * 30 * M_PI) / (4096 * 8); 34 | 35 | gsl_integration_qag (&F, 0, M_PI, 1e-6, 1e-4, 1000, GSL_INTEG_GAUSS21, ws, &result, &error); 36 | 37 | if (param.x - xold > xsmp) 38 | { 39 | xold = param.x; 40 | printf ("%.18f %.18f\n", param.x, result); 41 | } 42 | } 43 | 44 | gsl_integration_workspace_free (ws); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /demos/bspline.lua: -------------------------------------------------------------------------------- 1 | local graph = require("graph") 2 | local matrix = require("lgsl.matrix") 3 | local rng = require("lgsl.rng") 4 | local rnd = require("lgsl.rnd") 5 | local bspline = require("lgsl.bspline") 6 | local linfit = require("lgsl.linfit") 7 | 8 | local cos,exp = math.cos,math.exp 9 | 10 | local function demo1() 11 | local n, br = 200, 10 12 | 13 | local f = function(x) return cos(x) * exp(-0.1 * x) end 14 | local xsmp = function(i) return 15 * (i-1) / (n-1) end 15 | 16 | local x = matrix.new(n, 1, xsmp) 17 | local y = matrix.new(n, 1, function(i) return f(xsmp(i)) end) 18 | local r = rng.new() 19 | local w = matrix.alloc(n, 1) 20 | for i = 1, n do 21 | local yi = y[i] 22 | local sigma = 0.1 * yi 23 | y[i] = yi + rnd.gaussian(r, sigma) 24 | w[i] = 1/sigma^2 25 | end 26 | 27 | local b = bspline(0, 15, br) 28 | local X = b:model(x) 29 | 30 | local c, chisq, cov = linfit(X, y, w) 31 | 32 | local p = graph.plot('B-splines curve approximation') 33 | p:addline(graph.xyline(x, X * c)) 34 | p:addline(graph.xyline(x, y), 'blue', {{'marker', size=5}}) 35 | p.clip = false 36 | p:show() 37 | 38 | return p 39 | end 40 | 41 | return {'B-Splines', { 42 | { 43 | name = 'bspline1', 44 | f = demo1, 45 | description = 'B-Spline approximation of noisy data' 46 | }, 47 | }} 48 | -------------------------------------------------------------------------------- /tests/nlinfit.lua: -------------------------------------------------------------------------------- 1 | local matrix = require("lgsl.matrix") 2 | local nlinfit = require("lgsl.nlinfit") 3 | local pi,sin,cos,exp = math.pi,math.sin, math.cos, math.exp 4 | 5 | local function n2str(x) 6 | return string.format("%.8g", x) 7 | end 8 | 9 | local function vec2str(x) 10 | local t = {} 11 | for i = 1, #x do 12 | t[i] = n2str(x[i]) 13 | end 14 | return table.concat(t, " ") 15 | end 16 | 17 | local function donlfit() 18 | local n = 50 19 | local px = matrix.vec {1.55, -1.1, 12.5} 20 | local p0 = matrix.vec {2.5, -1.5, 5.3} 21 | local xs = function(i) return (i-1)/n end 22 | 23 | local fmodel = function(p, t, J) 24 | local e, s = exp(p[2] * t), sin(p[3] * t) 25 | if J then 26 | J[1] = e * s 27 | J[2] = t * p[1] * e * s 28 | J[3] = t * p[1] * e * cos(p[3] * t) 29 | end 30 | return p[1] * e * s 31 | end 32 | 33 | local y = matrix.new(n, 1, function(i,j) return fmodel(px, xs(i)) end) 34 | local x = matrix.new(n, 1, function(i,j) return xs(i) end) 35 | 36 | local function fdf(p, f, J) 37 | for k=1, n do 38 | local ym = fmodel(p, xs(k), J and J[k]) 39 | if f then f[k] = ym - y[k] end 40 | end 41 | end 42 | 43 | local s = nlinfit {n= n, p= #p0} 44 | 45 | s:set(fdf, p0) 46 | print('GOAL=: ', vec2str(px)) 47 | print('ITER=', 0, ': ', vec2str(s.x), n2str(s.chisq)) 48 | 49 | for i=1, 20 do 50 | s:iterate() 51 | end 52 | print('ITER=', 20, ': ', vec2str(s.x), n2str(s.chisq)) 53 | end 54 | 55 | donlfit() 56 | -------------------------------------------------------------------------------- /demos/sf.lua: -------------------------------------------------------------------------------- 1 | local graph = require("graph") 2 | local sf = require("lgsl.sf") 3 | local pi,sqrt,exp = math.pi,math.sqrt,math.exp 4 | local plot,window,fxline=graph.plot,graph.window,graph.fxline 5 | local fact, laguerre, hyperg1F1 = sf.fact, sf.laguerre, sf.hyperg1F1 6 | local function hermiteLp(n,x) 7 | return 1/sqrt(fact(n) *2^n*sqrt(pi)) * exp(-x*x/2) * (-4)^(n/2) * fact(n/2) * laguerre(n/2, -1/2, x^2) 8 | end 9 | 10 | local function hermiteFp(n,x) 11 | return 1/sqrt(fact(n) *2^n*sqrt(pi)) * exp(-x*x/2) * (-1)^(n/2) * fact(n)/fact(n/2) * hyperg1F1(-n/2, 1/2, x^2) 12 | end 13 | 14 | local function demo_gen(hermiteFF) 15 | local w = window('v...') 16 | 17 | local p = plot('Hermite(2, x)') 18 | p:addline(fxline(function(x) return hermiteFF(2, x) end, -10, 10), 'red') 19 | w:attach(p, '1') 20 | 21 | p = plot('Hermite(4, x)') 22 | p:addline(fxline(function(x) return hermiteFF(4, x) end, -10, 10), 'blue') 23 | w:attach(p, '2') 24 | 25 | p = plot('Hermite(16, x)') 26 | p:addline(fxline(function(x) return hermiteFF(16, x) end, -10, 10, 512), 'green') 27 | w:attach(p, '3') 28 | end 29 | 30 | local demo1 = function() demo_gen(hermiteLp) end 31 | local demo2 = function() demo_gen(hermiteFp) end 32 | 33 | return {'Special Functions', { 34 | { 35 | name = 'sf1', 36 | f = demo1, 37 | description = 'Hermite function using Laguerre polynomials' 38 | }, 39 | { 40 | name = 'sf2', 41 | f = demo2, 42 | description = 'Hermite function using Hypergeometric 1F1 function' 43 | }, 44 | }} 45 | -------------------------------------------------------------------------------- /lgsl.lua: -------------------------------------------------------------------------------- 1 | -- lgsl.lua 2 | -- 3 | -- Load LGSL modules into the lgsl table. 4 | -- 5 | -- Copyright (C) 2009-2015 Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | -- 21 | 22 | local lgsl = { 23 | matrix = require("lgsl.matrix"), 24 | complex = require("lgsl.complex"), 25 | eigen = require("lgsl.eigen"), 26 | iter = require("lgsl.iter"), 27 | rng = require("lgsl.rng"), 28 | rnd = require("lgsl.rnd"), 29 | randist = require("lgsl.randist"), 30 | sf = require("lgsl.sf"), 31 | csv = require("lgsl.csv"), 32 | bspline = require("lgsl.bspline"), 33 | fft = require("lgsl.fft"), 34 | integ = require("lgsl.integ"), 35 | linfit = require("lgsl.linfit"), 36 | nlinfit = require("lgsl.nlinfit"), 37 | ode = require("lgsl.ode"), 38 | vegas = require("lgsl.vegas"), 39 | } 40 | 41 | return lgsl 42 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | ################################## 2 | Welcome to the LGSL documentation 3 | ################################## 4 | 5 | LGSL is a collection of numerical algorithms and functions for `Lua`_, based on 6 | the `GNU Scientific Library (GSL)`_. It allows matrix and vector manipulation, 7 | linear algebra operations, special functions, and much more. LGSL is based on 8 | the numerical modules of `GSL Shell`_, and aims to be an easy-to-include Lua 9 | module with a focus on numerical algorithms. 10 | 11 | LGSL offers an intuitive interface to the GSL functions, giving you easy access 12 | to a well-tested scientific toolbox from your favourite Lua application. The 13 | bindings to GSL were made with the FFI library of `LuaJIT`_. Thanks to LuaJIT, a 14 | Just-In-Time compiler for Lua, scripts which use LGSL can run at speeds 15 | comparable to optimized C code. A selection of functions were reimplemented in 16 | Lua to get the most out of LuaJIT. 17 | 18 | `LGSL on GitHub `_ 19 | 20 | .. _Lua: http://www.lua.org 21 | .. _GNU Scientific Library (GSL): http://www.gnu.org/software/gsl 22 | .. _GSL Shell: http://www.nongnu.org/gsl-shell 23 | .. _LuaJIT: http://luajit.org 24 | 25 | Contents: 26 | 27 | .. toctree:: 28 | :maxdepth: 2 29 | 30 | intro.rst 31 | lua-base.rst 32 | complex.rst 33 | matrices.rst 34 | linalg.rst 35 | eigen.rst 36 | random.rst 37 | randist.rst 38 | pdf.rst 39 | linfit.rst 40 | nlinfit.rst 41 | bsplines.rst 42 | fft.rst 43 | ode.rst 44 | integ.rst 45 | vegas.rst 46 | sf.rst 47 | examples.rst 48 | gsl-ffi.rst 49 | -------------------------------------------------------------------------------- /doc/intro-example.lua: -------------------------------------------------------------------------------- 1 | 2 | local vegas = require("lgsl.vegas") 3 | local sf = require("lgsl.sf") -- for the analytical solution, see below 4 | local iter = require("lgsl.iter") -- for defining the integration boundaries 5 | 6 | local function getunitsphere(n) 7 | return function(x) 8 | local s = 0 9 | for k= 1, n do s = s + x[k]^2 end 10 | return s < 1 and 1 or 0 11 | end 12 | end 13 | 14 | local graph = require("graph") 15 | local ln = graph.path(1, 2) -- 1-sphere = [-1, 1] (length 2) 16 | local max_dim = 14 17 | 18 | --Calculating the volume of d-dimensional sphere 19 | for d=2, max_dim do 20 | --Intializing work varaibles 21 | local a = iter.ilist(function() return 0 end, d) 22 | local b = iter.ilist(function() return 1 end, d) 23 | local calls, n = d*1e4,1 24 | 25 | --Obtaining monte carlo vegas callback 26 | local s = vegas.integ(getunitsphere(d),a,b,calls) 27 | local fmt = "Volume = %.3f +/- %.3f " 28 | print(string.format(fmt,s.result*2^d,s.sigma*2^d)) 29 | 30 | --Increasing the number of calls to reach a satisfying result 31 | while(s.sigma/s.result > 0.005) do 32 | print("Increasing accuracy, doubling number of calls...") 33 | s = s.continue(calls*(2^n)) 34 | print(string.format(fmt,s.result*2^d,s.sigma*2^d)) 35 | n=n+1 36 | end 37 | ln:line_to(d,s.result*2^d) 38 | end 39 | 40 | --plotting a comparison of the numerical result with the analytical solution 41 | local p = graph.plot('Volume of a unit n-sphere') 42 | p.clip, p.pad = false, true 43 | local analytic = function(n) 44 | return math.pi^(n/2) / sf.gamma(1+n/2) 45 | end 46 | p:addline(graph.fxline(analytic, 1, max_dim)) 47 | p:add(ln, "blue", {{'marker', size=8}}) 48 | p.xtitle="n" 49 | p.ytitle="V" 50 | p:show() 51 | -------------------------------------------------------------------------------- /demos/plot.lua: -------------------------------------------------------------------------------- 1 | local graph = require("graph") 2 | local lgsl = require("lgsl") 3 | local rng,rnd,matrix,complex,iter,f = lgsl.rng,lgsl.rnd,lgsl.matrix,lgsl.complex,lgsl.iter,lgsl.fft 4 | local fft, fftinv = f.fft, f.fftinv 5 | local sqrt, pi, exp, floor = math.sqrt, math.pi, math.exp, math.floor 6 | 7 | local function gaussian() 8 | local N = 800 9 | local r = rng.new() 10 | local f = function(x) return 1/sqrt(2*pi) * exp(-x^2/2) end 11 | local p = graph.plot('Simulated Gaussian Distribution') 12 | local b = graph.ibars(iter.sample(function(x) return rnd.poisson(r, floor(f(x)*N)) / N end, -3, 3, 25)) 13 | p:add(b, 'darkgreen') 14 | p:addline(b, graph.rgba(0, 0, 0, 150)) 15 | p:addline(graph.fxline(f, -4, 4), 'red') 16 | p.xtitle, p.ytitle = 'x', 'Frequency' 17 | p:show() 18 | return p 19 | end 20 | 21 | -- FFT example, frequency cut on square pulse and plot of result 22 | local function fftplot() 23 | local n = 256 24 | local ncut = 16 25 | 26 | local v = matrix.new(n, 1, function(i) return i < n/3 and 0 or (i < 2*n/3 and 1 or 0) end) 27 | 28 | local pt, pf = graph.plot('Original / Reconstructed signal'), graph.plot('FFT Spectrum') 29 | 30 | pt:addline(graph.filine(function(i) return v[i] end, n), 'black') 31 | 32 | local ft = fft(v, true) 33 | 34 | pf:add(graph.ibars(iter.isample(function(i) return complex.abs(ft[i]) end, 0, n/2)), 'black') 35 | for k=ncut, n/2 do ft[k] = 0 end 36 | 37 | fftinv(ft, true) 38 | 39 | pt:addline(graph.filine(function(i) return v[i] end, n), 'red') 40 | 41 | pf:show() 42 | pt:show() 43 | 44 | return pt, pf 45 | end 46 | 47 | return {'Plotting', { 48 | { 49 | name= 'gaussian', 50 | f = gaussian, 51 | description = 'Bar Plot example' 52 | }, 53 | { 54 | name= 'fftplot', 55 | f = fftplot, 56 | description = 'FFT Plot example' 57 | }, 58 | }} 59 | -------------------------------------------------------------------------------- /lgsl/templates/ode-defs.lua.in: -------------------------------------------------------------------------------- 1 | 2 | # function VL(var) 3 | # local res = {} 4 | # for i = 0, N-1 do 5 | # res[i+1] = var..'_'..i 6 | # end 7 | # return table.concat(res,',') 8 | # end 9 | 10 | # function AL(var) 11 | # local res = {} 12 | # for i = 0, N-1 do 13 | # res[i+1] = var..'['..i..']' 14 | # end 15 | # return table.concat(res,',') 16 | # end 17 | 18 | # function VLI(var, ord) 19 | # local res = {} 20 | # for i = 0, N-1 do 21 | # res[i+1] = string.format('%s%i_%i', var, ord, i) 22 | # end 23 | # return table.concat(res,',') 24 | # end 25 | 26 | # function KCONV(var, ord, i) 27 | # local sm = {} 28 | # for j = 1, ord do 29 | # local bc = var[j] 30 | # if tonumber(bc) ~= 0 then 31 | # sm[#sm+1] = string.format('(%s)*k%i_%i', bc, j, i) 32 | # end 33 | # end 34 | # return table.concat(sm, ' + ') 35 | # end 36 | 37 | local ffi = require("ffi") 38 | local matrix = require("lgsl.matrix") 39 | 40 | local function ode_new() 41 | local n = $(N) 42 | return {t = 0, h = 1, dim = n, y = matrix.new(n, 1), dydt = matrix.new(n, 1)} 43 | end 44 | 45 | local function ode_init(s, t0, h0, f, $(VL'y')) 46 | $(AL's.y.data') = $(VL'y') 47 | $(AL's.dydt.data') = f(t0, $(VL'y')) 48 | s.t, s.h, s.f = t0, h0, f 49 | end 50 | 51 | local function ode_evolve(s, t1, tsmp) 52 | local step, t0, y = s.step, s.t, s.y 53 | 54 | local function it(s, t) 55 | t = t and t + tsmp or t0 56 | if t <= t1 then 57 | while s.t < t do 58 | step(s, t) 59 | end 60 | return t, $(AL'y.data') 61 | end 62 | end 63 | 64 | return it, s 65 | end 66 | 67 | local function hadjust(rmax, h) 68 | local S = 0.9 69 | if rmax > 1.1 then 70 | local r = S / rmax^(1/$(order)) 71 | r = max(0.2, r) 72 | return r * h, -1 73 | elseif rmax < 0.5 then 74 | local r = S / rmax^(1/($(order)+1)) 75 | r = max(1, min(r, 5)) 76 | return r * h, 1 77 | end 78 | return h, 0 79 | end 80 | -------------------------------------------------------------------------------- /lgsl/ode.lua: -------------------------------------------------------------------------------- 1 | -- ode.lua 2 | -- 3 | -- Functions for solving ordinary differential equation (ODE) initial value 4 | -- problems. 5 | -- 6 | -- Copyright (C) 2009-2015 Francesco Abbate 7 | -- 8 | -- This program is free software; you can redistribute it and/or modify 9 | -- it under the terms of the GNU General Public License as published by 10 | -- the Free Software Foundation; either version 3 of the License, or (at 11 | -- your option) any later version. 12 | -- 13 | -- This program is distributed in the hope that it will be useful, but 14 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 15 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | -- General Public License for more details. 17 | -- 18 | -- You should have received a copy of the GNU General Public License 19 | -- along with this program; if not, write to the Free Software 20 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 | 22 | 23 | local template = require("lgsl.template") 24 | 25 | local function ode(spec) 26 | local required = {N= 'number', eps_abs= 'number'} 27 | local defaults = {eps_rel = 0, a_y = 1, a_dydt = 0} 28 | local is_known = {rkf45= true, rk8pd= true} 29 | 30 | for k, tp in pairs(required) do 31 | if type(spec[k]) ~= tp then 32 | error(string.format('parameter %s should be a %s', k, tp)) 33 | end 34 | end 35 | for k, v in pairs(defaults) do 36 | if not spec[k] then spec[k] = v end 37 | end 38 | 39 | local method = spec.method and spec.method or 'rkf45' 40 | if not is_known[method] then error('unknown ode method: ' .. method) end 41 | spec.method = nil 42 | 43 | local ode_loaded = template.load("lgsl.templates."..method, spec) 44 | 45 | local mt = { 46 | __index = {step = ode_loaded.step, init = ode_loaded.init, evolve = ode_loaded.evolve} 47 | } 48 | 49 | return setmetatable(ode_loaded.new(), mt) 50 | end 51 | 52 | return setmetatable({ode=ode}, {__call= function(t,...) return ode(...) end}) 53 | -------------------------------------------------------------------------------- /benchmarks/integration/vegas-bench.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | double exact = 30720.; 6 | 7 | double 8 | f (double *x, size_t dim, void *params) 9 | { 10 | return 1.*x[0]*x[0]+2.*x[1]*x[1]+3.*x[2]*x[2] 11 | +4.*x[3]*x[3]+5.*x[4]*x[4]+6.*x[5]*x[5] 12 | +7.*x[6]*x[6]+8.*x[7]*x[7]+9.*x[8]*x[8]; 13 | } 14 | void 15 | display_results (char *title, double result, double error, int i) 16 | { 17 | printf ("%s ==================\n", title); 18 | printf ("result = % .10f\n", result); 19 | printf ("sigma = % .10f\n", error); 20 | printf ("exact = % .10f\n", exact); 21 | printf ("error = % .10f = %.2g sigma\n", result - exact, 22 | fabs (result - exact) / error); 23 | printf ("i = % d\n", i); 24 | } 25 | int 26 | main (void) 27 | { 28 | double res, err; 29 | double a= 0.; 30 | double b= 2.; 31 | int dim=9; 32 | double xl[9] = { a,a,a,a,a,a,a,a,a}; 33 | double xu[9] = { b,b,b,b,b,b,b,b,b}; 34 | gsl_monte_function G = { &f, dim, 0 }; 35 | size_t calls =1e6*dim; 36 | 37 | gsl_rng_env_setup (); 38 | gsl_rng *r = gsl_rng_alloc (gsl_rng_taus2); 39 | gsl_rng_set (r, 30776); 40 | 41 | gsl_monte_vegas_state *s = gsl_monte_vegas_alloc (dim); 42 | 43 | gsl_monte_vegas_integrate (&G, xl, xu, dim, 1e4, r, s, 44 | &res, &err); 45 | //display_results ("vegas warm-up", res, err,0); 46 | 47 | //printf ("converging...\n"); 48 | int i=0; 49 | do 50 | { 51 | gsl_monte_vegas_integrate (&G, xl, xu, dim, calls/5, r, s, 52 | &res, &err); 53 | //printf ("result = % .6f sigma = % .6f chisq/dof = %.1f\n", 54 | // res, err, gsl_monte_vegas_chisq (s)); 55 | i=i+1; 56 | } 57 | while (fabs (gsl_monte_vegas_chisq (s) - 1.0) > 0.5); 58 | 59 | display_results ("vegas final", res, err, i); 60 | 61 | gsl_monte_vegas_free (s); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /lgsl/nlinfit.lua: -------------------------------------------------------------------------------- 1 | -- nlinfit.lua 2 | -- 3 | -- Nonlinear least squares fitting function. 4 | -- 5 | -- Copyright (C) 2009-2015 Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | 21 | 22 | local template = require("lgsl.template") 23 | local NLINFIT_METHODS = { 24 | set = function(ss, fdf, x0) return ss.lm.set(fdf, x0) end, 25 | iterate = function(ss) return ss.lm.iterate() end, 26 | test = function(ss, epsabs, epsrel) return ss.lm.test(epsabs, epsrel) end, 27 | } 28 | 29 | local NLINFIT = { 30 | __index = function(t, k) 31 | if k == 'chisq' then 32 | return t.lm.chisq() 33 | else 34 | return NLINFIT_METHODS[k] or t.lm[k] 35 | end 36 | end 37 | } 38 | 39 | local function nlinfit(spec) 40 | if not spec.n then error 'number of points "n" not specified' end 41 | if not spec.p then error 'number of parameters "p" not specified' end 42 | 43 | if spec.n <= 0 or spec.p <= 0 then 44 | error '"n" and "p" shoud be positive integers' 45 | end 46 | 47 | local n, p = spec.n, spec.p 48 | local s = { lm = template.load('lgsl.templates.lmfit', {N= n, P= p}) } 49 | 50 | setmetatable(s, NLINFIT) 51 | 52 | return s 53 | end 54 | 55 | return setmetatable({nlinfit=nlinfit}, {__call= function(t,...) return nlinfit(...) end}) 56 | -------------------------------------------------------------------------------- /tests/test_coulomb.lua: -------------------------------------------------------------------------------- 1 | local gsl = require("lgsl.gsl") 2 | local sf= require("lgsl.sf") 3 | local GSL_DBL_EPSILON, GSL_SQRT_DBL_EPSILON, GSL_LOG_DBL_MAX = 2.2204460492503131e-16, 1.4901161193847656e-08, 7.0978271289338397e+02 4 | local function sprintf(...) io.write(string.format(...)) end 5 | local sqrt, log, exp, M_PI, M_PI_2, DBL_MAX = math.sqrt, math.log, math.exp, math.pi, math.pi/2, 1.7976931348623157E+308 6 | local function compare(val, ref, name, eps) 7 | eps = eps or 1e-9 8 | local inc = 0 9 | if val==0 or ref==0 then inc = 1 end 10 | if gsl.gsl_fcmp(val+inc,ref+inc,eps*100)==0 then 11 | sprintf("Pass %-30s: % .15e\n", name, ref,"\n") 12 | else 13 | sprintf("Fail %-30s: % .15e ~= % .15e\n", name, val, ref) 14 | end 15 | end 16 | local TEST_TOL0 = (2.0*GSL_DBL_EPSILON) 17 | local TEST_TOL1 = (16.0*GSL_DBL_EPSILON) 18 | local TEST_TOL2 = (256.0*GSL_DBL_EPSILON) 19 | local TEST_TOL3 = (2048.0*GSL_DBL_EPSILON) 20 | local TEST_TOL4 = (16384.0*GSL_DBL_EPSILON) 21 | local TEST_TOL5 = (131072.0*GSL_DBL_EPSILON) 22 | local TEST_TOL6 = (1048576.0*GSL_DBL_EPSILON) 23 | compare(sf.hydrogenicR_1(3.0, 2.0) , 0.025759948256148471036, "hydrogenicR_1(3.0, 2.0)", TEST_TOL0) 24 | compare(sf.hydrogenicR_1(3.0, 10.0) , 9.724727052062819704e-13, "hydrogenicR_1(3.0, 10.0)", TEST_TOL1) 25 | compare(sf.hydrogenicR(4, 1, 3.0, 0.0) , 0.0, "hydrogenicR(4, 1, 3.0, 0.0)", TEST_TOL0) 26 | compare(sf.hydrogenicR(4, 0, 3.0, 2.0) , -0.03623182256981820062, "hydrogenicR(4, 0, 3.0, 2.0)", TEST_TOL2) 27 | compare(sf.hydrogenicR(4, 1, 3.0, 2.0) , -0.028065049083129581005, "hydrogenicR(4, 1, 3.0, 2.0)", TEST_TOL2) 28 | compare(sf.hydrogenicR(4, 2, 3.0, 2.0) , 0.14583027278668431009, "hydrogenicR(4, 2, 3.0, 2.0)", TEST_TOL0) 29 | compare(sf.hydrogenicR(100, 0, 3.0, 2.0), -0.00007938950980052281367, "hydrogenicR(100, 0, 3.0, 2.0)", TEST_TOL3) 30 | compare(sf.hydrogenicR(100, 10, 3.0, 2.0), 7.112823375353605977e-12, "hydrogenicR(100, 10, 3.0, 2.0)", TEST_TOL2) 31 | compare(sf.hydrogenicR(100, 90, 3.0, 2.0), 5.845231751418131548e-245, "hydrogenicR(100, 90, 3.0, 2.0)", TEST_TOL2) 32 | -------------------------------------------------------------------------------- /lgsl/integ.lua: -------------------------------------------------------------------------------- 1 | -- integ.lua 2 | -- 3 | -- integ: Function that performs a 1D numeric integration. 4 | -- prepare: Create a function that can perform a 1D numeric integration. 5 | -- 6 | -- Copyright (C) 2009-2015 Francesco Abbate 7 | -- 8 | -- This program is free software; you can redistribute it and/or modify 9 | -- it under the terms of the GNU General Public License as published by 10 | -- the Free Software Foundation; either version 3 of the License, or (at 11 | -- your option) any later version. 12 | -- 13 | -- This program is distributed in the hope that it will be useful, but 14 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 15 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | -- General Public License for more details. 17 | -- 18 | -- You should have received a copy of the GNU General Public License 19 | -- along with this program; if not, write to the Free Software 20 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 | 22 | local template = require("lgsl.template") 23 | local check = require("lgsl.check") 24 | local q_default 25 | 26 | local function integ(f, a, b, epsabs, epsrel) 27 | epsabs = epsabs or 1e-8 28 | epsrel = epsrel or 1e-8 29 | 30 | check.number(a) 31 | check.number(b) 32 | 33 | if not q_default then 34 | q_default = template.load('lgsl.templates.qag', {limit= 64, order= 21}) 35 | end 36 | 37 | local result = q_default (f, a, b, epsabs, epsrel) 38 | 39 | return result 40 | end 41 | 42 | local function quad_prepare(options) 43 | local known_methods = {qng= true, qag= true} 44 | 45 | local method = options.method or 'qag' 46 | local order = options.order or 21 47 | local limit = options.limit or 64 48 | 49 | if not known_methods[method] then 50 | error('the method ' .. method .. ' is unknown') 51 | end 52 | 53 | check.integer(limit) 54 | 55 | if limit < 8 then limit = 8 end 56 | 57 | local q = template.load("lgsl.templates."..method, {limit= limit, order= order}) 58 | 59 | return q 60 | end 61 | 62 | return { 63 | integ = integ, 64 | prepare = quad_prepare 65 | } 66 | -------------------------------------------------------------------------------- /lgsl/csv.lua: -------------------------------------------------------------------------------- 1 | -- csv.lua 2 | -- 3 | -- Comma Separated Values parsing utilities. 4 | -- 5 | -- Copyright (C) 2009-2015 Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | 21 | local csv = {} 22 | 23 | local function add_number(t, n) 24 | local v = tonumber(n) 25 | t[#t+1] = v and v or n 26 | end 27 | 28 | function csv.line (s) 29 | s = s .. ',' -- ending comma 30 | local t = {} -- table to collect fields 31 | local fieldstart = 1 32 | repeat 33 | -- next field is quoted? (start with `"'?) 34 | if string.find(s, '^"', fieldstart) then 35 | local a, c 36 | local i = fieldstart 37 | repeat 38 | -- find closing quote 39 | a, i, c = string.find(s, '"("?)', i+1) 40 | until c ~= '"' -- quote not followed by quote? 41 | if not i then error('unmatched "') end 42 | local f = string.sub(s, fieldstart+1, i-1) 43 | add_number(t, (string.gsub(f, '""', '"'))) 44 | fieldstart = string.find(s, ',', i) + 1 45 | else -- unquoted; find next comma 46 | local nexti = string.find(s, ',', fieldstart) 47 | add_number(t, string.sub(s, fieldstart, nexti-1)) 48 | fieldstart = nexti + 1 49 | end 50 | until fieldstart > string.len(s) 51 | return t 52 | end 53 | 54 | function csv.read(filename) 55 | local t = {} 56 | for line in io.lines(filename) do 57 | if not string.match('^%s*$', line) then 58 | t[#t+1] = csv.line(line) 59 | end 60 | end 61 | return t 62 | end 63 | 64 | return csv 65 | -------------------------------------------------------------------------------- /lgsl/linfit.lua: -------------------------------------------------------------------------------- 1 | -- linfit.lua 2 | -- 3 | -- Linear least squares fitting function. 4 | -- 5 | -- Copyright (C) 2009-2015 Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | 21 | local ffi = require("ffi") 22 | local gsl = require("lgsl.gsl") 23 | local gsl_check = require("lgsl.gsl-check") 24 | local matrix = require("lgsl.matrix") 25 | 26 | local workspace 27 | local workspace_n 28 | local workspace_p 29 | 30 | local function get_workspace(n, p) 31 | local ws 32 | if n == workspace_n and p == workspace_p then 33 | ws = workspace 34 | else 35 | ws = ffi.gc(gsl.gsl_multifit_linear_alloc(n, p), 36 | gsl.gsl_multifit_linear_free) 37 | 38 | workspace_n = n 39 | workspace_p = p 40 | workspace = ws 41 | end 42 | return ws 43 | end 44 | 45 | local function linfit(X, y, w) 46 | local n, p = matrix.dim(X) 47 | local ws = get_workspace(n, p) 48 | local c = matrix.alloc(p, 1) 49 | local cov = matrix.alloc(p, p) 50 | local yv = gsl.gsl_matrix_column (y, 0) 51 | local cv = gsl.gsl_matrix_column (c, 0) 52 | 53 | local chisq = ffi.new('double[1]') 54 | 55 | if w then 56 | local wv = gsl.gsl_matrix_column (w, 0) 57 | gsl_check(gsl.gsl_multifit_wlinear(X, wv, yv, cv, cov, chisq, ws)) 58 | else 59 | gsl_check(gsl.gsl_multifit_linear(X, yv, cv, cov, chisq, ws)) 60 | end 61 | 62 | return c, chisq[0], cov 63 | end 64 | 65 | return setmetatable({linfit=linfit}, {__call=function(t,...) return linfit(...) end}) 66 | -------------------------------------------------------------------------------- /lgsl/rng.lua: -------------------------------------------------------------------------------- 1 | -- rng.lua 2 | -- 3 | -- Pseudorandom number generators. 4 | -- 5 | -- Copyright (C) 2009-2015 Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | 21 | local gsl = require("lgsl.gsl") 22 | local ffi = require("ffi") 23 | 24 | local format, tonumber = string.format, tonumber 25 | 26 | local rng = {} 27 | 28 | local rng_type = ffi.typeof('gsl_rng') 29 | 30 | local function rng_getint(r, seed) 31 | return tonumber(gsl.gsl_rng_uniform_int(r, seed)) 32 | end 33 | 34 | local rng_mt = { 35 | __tostring = function(s) 36 | return format("", s) 37 | end, 38 | 39 | __index = { 40 | getint = rng_getint, 41 | get = gsl.gsl_rng_uniform, 42 | set = gsl.gsl_rng_set, 43 | }, 44 | } 45 | 46 | ffi.metatype(rng_type, rng_mt) 47 | 48 | local function rng_type_lookup(s) 49 | if s then 50 | local ts = gsl.gsl_rng_types_setup() 51 | while ts[0] ~= nil do 52 | local t = ts[0] 53 | if ffi.string(t.name) == s then 54 | return t 55 | end 56 | ts = ts+1 57 | end 58 | error('unknown generator type: ' .. s) 59 | else 60 | return gsl.gsl_rng_default 61 | end 62 | end 63 | 64 | function rng.new(s) 65 | local T = rng_type_lookup(s) 66 | return ffi.gc(gsl.gsl_rng_alloc(T), gsl.gsl_rng_free) 67 | end 68 | 69 | function rng.list() 70 | local t = {} 71 | local ts = gsl.gsl_rng_types_setup() 72 | while ts[0] ~= nil do 73 | t[#t+1] = ffi.string(ts[0].name) 74 | ts = ts+1 75 | end 76 | return t 77 | end 78 | 79 | return rng 80 | -------------------------------------------------------------------------------- /lgsl/iter.lua: -------------------------------------------------------------------------------- 1 | -- iter.lua 2 | -- 3 | -- Collection of functions for some common tasks related to iterators. 4 | -- 5 | -- Copyright (C) 2009-2013 Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | -- 21 | 22 | -- take the function f and return an iterator that gives f(k) 23 | -- for k going from a to b (or if only a is provided, from 1 to a) 24 | local function sequence(f, a, b) 25 | a, b = (b and a or 1), (b or a) 26 | local k = a 27 | return function() 28 | if k <= b then 29 | k = k+1 30 | return f(k-1) 31 | end 32 | end 33 | end 34 | 35 | -- take the function f and return an iterator that gives the couple (x, f(x)) 36 | -- for x going from 'xi' to 'xs' with n sampling points 37 | local function sample(f, xi, xs, n) 38 | local c = (xs-xi)/n 39 | local k = 0 40 | return function() 41 | if k <= n then 42 | local x = xi+k*c 43 | k = k+1 44 | return x, f(x) 45 | end 46 | end 47 | end 48 | 49 | local function ilist(f, a, b) 50 | a, b = (b and a or 1), (b or a) 51 | local ls = {} 52 | for i = a, b do ls[i] = f(i) end 53 | return ls 54 | end 55 | 56 | local function isample(f, a, b) 57 | return sequence(function(i) return i, f(i) end, a, b) 58 | end 59 | 60 | local function isum(f, a, b) 61 | a, b = (b and a or 1), (b or a) 62 | local s = 0 63 | for k = a, b do s = s + f(k) end 64 | return s 65 | end 66 | 67 | local iter = { 68 | sequence = sequence, 69 | sample = sample, 70 | ilist = ilist, 71 | isample = isample, 72 | isum = isum, 73 | } 74 | 75 | return iter 76 | -------------------------------------------------------------------------------- /tests/test-output.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import re 4 | import subprocess 5 | from glob import glob 6 | 7 | test_dir = "tests" 8 | luajit_exec = "luajit" 9 | env = os.environ.copy() 10 | env['LUA_PATH']= "./?.lua;;" 11 | 12 | if not os.path.isdir("tests/log"): 13 | try: 14 | print "Creating directory tests/log..." 15 | os.mkdir("tests/log") 16 | except: 17 | print "Error creating directory tests/log." 18 | sys.exit(1) 19 | 20 | for filename in glob("tests/log/*"): 21 | os.remove(filename) 22 | 23 | try: 24 | subprocess.check_call([luajit_exec, "-e", ""]) 25 | except: 26 | print "Error calling luajit." 27 | print "Please make sure that luajit executable is in the current PATH." 28 | sys.exit(1) 29 | 30 | def get_reference_text(dirpath, testname): 31 | with open(os.path.join(dirpath, testname + ".expect"), "r") as f: 32 | return f.read() 33 | 34 | for dirpath, dirnames, filenames in os.walk(test_dir): 35 | for filename in sorted(filenames): 36 | m = re.match(r'([^.]+)\.lua$', filename) 37 | if m: 38 | fullname = os.path.join(dirpath, filename) 39 | testname = m.group(1) 40 | out_tst = None 41 | run_error = None 42 | try: 43 | process = subprocess.Popen([luajit_exec, fullname], stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) 44 | out_tst, out_errors = process.communicate() 45 | except subprocess.CalledProcessError: 46 | run_error = "fail to run" 47 | try: 48 | out_ref = get_reference_text(dirpath, testname) 49 | except IOError: 50 | run_error = "missing expect file" 51 | led, msg = None, None 52 | if run_error: 53 | led, msg = "*", run_error 54 | elif out_tst == out_ref: 55 | if out_tst in ["", "\n", "\r\n"] or not out_tst: 56 | led, msg = "-", "pass / no output" 57 | else: 58 | led, msg = " ", "pass" 59 | else: 60 | led, msg = "*", "fail" 61 | log = open("tests/log/%s.output.diff" % testname, "w") 62 | log.write("*** reference ***\n%s\n" % out_ref) 63 | log.write("*** test program ***\n%s\n" % out_tst) 64 | log.close() 65 | 66 | print("%s %-24s %s" % (led, testname, msg)) 67 | -------------------------------------------------------------------------------- /lgsl/bspline.lua: -------------------------------------------------------------------------------- 1 | -- bspline.lua 2 | -- 3 | -- B-splines: basis functions to fit smoothing curves to large data sets. 4 | -- 5 | -- Copyright (C) 2009-2015 Francesco Abbate 6 | -- 7 | -- This program is free software; you can redistribute it and/or modify 8 | -- it under the terms of the GNU General Public License as published by 9 | -- the Free Software Foundation; either version 3 of the License, or (at 10 | -- your option) any later version. 11 | -- 12 | -- This program is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | -- General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU General Public License 18 | -- along with this program; if not, write to the Free Software 19 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | 21 | local ffi = require("ffi") 22 | local gsl = require("lgsl.gsl") 23 | local matrix = require("lgsl.matrix") 24 | local gsl_check = require("lgsl.gsl-check") 25 | 26 | local function eval(bs, x) 27 | local dof, ws = bs.dof, bs.ws 28 | local c = matrix.alloc(dof, 1) 29 | local v = gsl.gsl_matrix_column (c, 0) 30 | gsl_check(gsl.gsl_bspline_eval(x, v, ws)) 31 | return c 32 | end 33 | 34 | local function model(bs, x) 35 | local dof, ws = bs.dof, bs.ws 36 | local n = matrix.dim(x) 37 | local m = matrix.alloc(n, dof) 38 | for j = 0, n-1 do 39 | local xj = gsl.gsl_matrix_get(x, j, 0) 40 | local v = gsl.gsl_matrix_row (m, j) 41 | gsl_check(gsl.gsl_bspline_eval(xj, v, ws)) 42 | end 43 | return m 44 | end 45 | 46 | local mt = { 47 | __index = {eval= eval, model= model} 48 | } 49 | 50 | local function bspline(a, b, nbreak) 51 | local breaks 52 | local brk 53 | if type(a) ~= 'number' then 54 | breaks = type(a) == 'table' and matrix.vec(a) or a 55 | brk = gsl.gsl_matrix_column (breaks, 0) 56 | nbreak = #breaks 57 | end 58 | 59 | local k = 4 60 | local dof = nbreak + k - 2 61 | local ws = ffi.gc(gsl.gsl_bspline_alloc (k, nbreak), gsl.gsl_bspline_free) 62 | 63 | if breaks then 64 | gsl_check(gsl.gsl_bspline_knots (brk, ws)) 65 | else 66 | gsl_check(gsl.gsl_bspline_knots_uniform (a, b, ws)) 67 | end 68 | 69 | local bs = {dof= dof, ws= ws} 70 | setmetatable(bs, mt) 71 | 72 | return bs 73 | end 74 | 75 | return setmetatable({bspline=bspline}, {__call=function(t,...) return bspline(...) end}) 76 | -------------------------------------------------------------------------------- /tests/test_dilog.lua: -------------------------------------------------------------------------------- 1 | local gsl = require("lgsl.gsl") 2 | local sf= require("lgsl.sf") 3 | local GSL_DBL_EPSILON, GSL_SQRT_DBL_EPSILON, GSL_LOG_DBL_MAX = 2.2204460492503131e-16, 1.4901161193847656e-08, 7.0978271289338397e+02 4 | local function sprintf(...) io.write(string.format(...)) end 5 | local sqrt, log, exp, M_PI, M_PI_2, DBL_MAX = math.sqrt, math.log, math.exp, math.pi, math.pi/2, 1.7976931348623157E+308 6 | local function compare(val, ref, name, eps) 7 | eps = eps or 1e-9 8 | local inc = 0 9 | if val==0 or ref==0 then inc = 1 end 10 | if gsl.gsl_fcmp(val+inc,ref+inc,eps*100)==0 then 11 | sprintf("Pass %-30s: % .15e\n", name, ref,"\n") 12 | else 13 | sprintf("Fail %-30s: % .15e ~= % .15e\n", name, val, ref) 14 | end 15 | end 16 | local TEST_TOL0 = (2.0*GSL_DBL_EPSILON) 17 | local TEST_TOL1 = (16.0*GSL_DBL_EPSILON) 18 | local TEST_TOL2 = (256.0*GSL_DBL_EPSILON) 19 | local TEST_TOL3 = (2048.0*GSL_DBL_EPSILON) 20 | local TEST_TOL4 = (16384.0*GSL_DBL_EPSILON) 21 | local TEST_TOL5 = (131072.0*GSL_DBL_EPSILON) 22 | local TEST_TOL6 = (1048576.0*GSL_DBL_EPSILON) 23 | compare(sf.dilog(-3.0) , -1.9393754207667089531, "dilog(-3.0)", TEST_TOL0) 24 | compare(sf.dilog(-0.5) , -0.4484142069236462024, "dilog(-0.5)", TEST_TOL0) 25 | compare(sf.dilog(-0.001) , -0.0009997501110486510834, "dilog(-0.001)", TEST_TOL0) 26 | compare(sf.dilog(0.1) , 0.1026177910993911, "dilog(0.1)", TEST_TOL0) 27 | compare(sf.dilog(0.7) , 0.8893776242860387386, "dilog(0.7)", TEST_TOL0) 28 | compare(sf.dilog(1.0) , 1.6449340668482260, "dilog(1.0)", TEST_TOL0) 29 | compare(sf.dilog(1.5) , 2.3743952702724802007, "dilog(1.5)", TEST_TOL0) 30 | compare(sf.dilog(2.0) , 2.4674011002723397, "dilog(2.0)", TEST_TOL0) 31 | compare(sf.dilog( 5.0) , 1.7837191612666306277, "dilog( 5.0)", TEST_TOL0) 32 | compare(sf.dilog( 11.0) , 0.3218540439999117111, "dilog( 11.0)", TEST_TOL1) 33 | compare(sf.dilog(12.59) , 0.0010060918167266208634, "dilog(12.59)", TEST_TOL3) 34 | compare(sf.dilog(12.595) , 0.00003314826006436236810, "dilog(12.595)", TEST_TOL5) 35 | compare(sf.dilog(13.0) , -0.07806971248458575855, "dilog(13.0)", TEST_TOL2) 36 | compare(sf.dilog(20.0) , -1.2479770861745251168, "dilog(20.0)", TEST_TOL2) 37 | compare(sf.dilog(150.0) , -9.270042702348657270, "dilog(150.0)", TEST_TOL0) 38 | compare(sf.dilog(1100.0) , -21.232504073931749553, "dilog(1100.0)", TEST_TOL0) 39 | -------------------------------------------------------------------------------- /demos/linfit.lua: -------------------------------------------------------------------------------- 1 | local graph = require("graph") 2 | local matrix = require("lgsl.matrix") 3 | local rng = require("lgsl.rng") 4 | local rnd = require("lgsl.rnd") 5 | local bspline = require("lgsl.bspline") 6 | local linfit = require("lgsl.linfit") 7 | local sf = require("lgsl.sf") 8 | local iter = require("lgsl.iter") 9 | 10 | local plot = graph.plot 11 | local cos,exp = math.cos,math.exp 12 | 13 | local function demo1() 14 | local x0, x1, n = 0, 12.5, 32 15 | local a, b = 0.55, -2.4 16 | local xsmp = function(i) return (i-1)/(n-1) * x1 end 17 | 18 | local r = rng.new() 19 | local x = matrix.new(n, 1, xsmp) 20 | local y = matrix.new(n, 1, function(i) return a*xsmp(i) + b + rnd.gaussian(r, 0.4) end) 21 | 22 | local X = matrix.new(n, 2, function(i,j) return j==1 and 1 or xsmp(i) end) 23 | local c, chisq, cov = linfit(X, y) 24 | local fit = function(x) return c[1]+c[2]*x end 25 | 26 | local p = graph.fxplot(fit, x0, x1) 27 | p:add(graph.xyline(x, y), 'blue', {{'stroke'}, {'marker', size=5}}) 28 | p.title = 'Linear Fit' 29 | p.clip = false 30 | 31 | return p 32 | 33 | end 34 | 35 | local function demo2() 36 | local order, x0, x1, n = 3, 0.0, 24.0, 96 37 | local bess = function(x) return sf.besselJ(order, x) end 38 | local xsmp = function(i) return x0 + (i-1)/(n-1) * (x1 - x0) end 39 | 40 | local x = matrix.new(n, 1, xsmp) 41 | local y = matrix.new(n, 1, function(i) return sf.besselJ(order, xsmp(i)) end) 42 | 43 | local xnorm = function(x) return (2*x - x0 - x1) / (x1-x0) end 44 | 45 | local model = function(k, x) return sf.legendreP(k, xnorm(x)) end 46 | 47 | local legmodel_order = 18 48 | 49 | local X = matrix.new(n, legmodel_order+1, function(i,j) return model(j-1, xsmp(i)) end) 50 | 51 | local c, chisq = linfit(X, y) 52 | 53 | local pc = graph.fibars(function(i) return c[i] end, 1, #c) 54 | pc.title = 'Legendre polynomials fit coefficients' 55 | pc.pad = true 56 | 57 | local fitleg = function(x) 58 | return iter.isum(function(k) return c[k+1] * model(k, x) end, 0, legmodel_order) 59 | end 60 | 61 | local p = graph.fxplot(fitleg, x0, x1) 62 | p:addline(graph.xyline(x, y), 'blue', {{'marker', size=5}}) 63 | p.title = 'Legendre polynomial fit of Bessel J3(x)' 64 | p.clip = false 65 | 66 | return p 67 | end 68 | -- demo1() 69 | -- demo2() 70 | 71 | return {'Linear Fit', { 72 | { 73 | name= 'linfit1', 74 | f = demo1, 75 | description = 'Simple linear regression example' 76 | }, 77 | { 78 | name= 'linfit2', 79 | f = demo2, 80 | description = 'Complex example of a linear fit based on legendre polynomials' 81 | }, 82 | }} 83 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | PACKAGE_NAME = luajit-lgsl 3 | VERSION = 0.1 4 | LUA = luajit 5 | HOMEPAGE = "http://ladc.github.io/lgsl" 6 | MAINTAINER = "Lesley De Cruz " 7 | 8 | DEB_PACKAGE = $(PACKAGE_NAME)_$(VERSION)-1_$(ARCH).deb 9 | 10 | ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH) 11 | 12 | PREFIX = /usr/local 13 | DOCDIR = doc 14 | DEBIAN = debian_build$(PREFIX) 15 | 16 | LUA_SRC = bspline.lua check.lua complex.lua csv.lua eigen.lua fft.lua \ 17 | gsl-check.lua gsl.lua integ.lua iter.lua linfit.lua \ 18 | matrix.lua nlinfit.lua ode.lua randist.lua rnd.lua \ 19 | rng.lua sf.lua sort.lua template.lua vegas.lua 20 | 21 | DEMO_SRC = anim.lua demos.lua fractals.lua linfit.lua ode.lua roots.lua \ 22 | vegas.lua bspline.lua fft.lua integ.lua nlinfit.lua plot.lua \ 23 | sf.lua wave-particle.lua 24 | DEMO_MAIN_SRC = demos.lua 25 | 26 | LUA_TEMPLATES_SRC = gauss-kronrod-x-wgs.lua.in lmfit.lua.in \ 27 | ode-defs.lua.in qag.lua.in qng.lua.in rk4.lua.in rk8pd.lua.in \ 28 | rkf45.lua.in rkf45vec.lua.in rnd-defs.lua.in sf-defs.lua.in \ 29 | vegas-defs.lua.in 30 | 31 | debian: $(DEB_PACKAGE) 32 | 33 | $(DEB_PACKAGE): 34 | @echo "cleaning build directory" 35 | @rm -fr debian_build 36 | @rm -fr $(DEB_PACKAGE) 37 | @echo "creating debian package $(DEB_PACKAGE)" 38 | @mkdir -p $(DEBIAN)/share/lua/5.1/lgsl 39 | @mkdir -p $(DEBIAN)/share/lua/5.1/lgsl/templates 40 | @mkdir -p $(DEBIAN)/share/lua/5.1/lgsl/demos 41 | @cp $(LUA_SRC:%.lua=lgsl/%.lua) $(DEBIAN)/share/lua/5.1/lgsl 42 | @cp $(DEMO_MAIN_SRC:%.lua=demos/%.lua) $(DEBIAN)/share/lua/5.1/lgsl 43 | @cp $(DEMO_SRC:%.lua=demos/%.lua) $(DEBIAN)/share/lua/5.1/lgsl/demos 44 | @cp lgsl.lua $(DEBIAN)/share/lua/5.1/ 45 | @cp $(LUA_TEMPLATES_SRC:%.lua.in=lgsl/templates/%.lua.in) $(DEBIAN)/share/lua/5.1/lgsl/templates 46 | @fakeroot bash debian/build.sh $(PACKAGE_NAME) $(VERSION) $(LUA) $(HOMEPAGE) $(MAINTAINER) 47 | 48 | install: 49 | @echo "copying files in $(PREFIX)/share/lua/5.1/lgsl" 50 | @mkdir -p $(PREFIX)/share/lua/5.1/lgsl 51 | @mkdir -p $(PREFIX)/share/lua/5.1/lgsl/templates 52 | @mkdir -p $(PREFIX)/share/lua/5.1/lgsl/demos 53 | @cp $(LUA_SRC:%.lua=lgsl/%.lua) $(PREFIX)/share/lua/5.1/lgsl 54 | @cp $(DEMO_MAIN_SRC:%.lua=demos/%.lua) $(PREFIX)/share/lua/5.1/lgsl 55 | @cp $(DEMO_SRC:%.lua=demos/%.lua) $(PREFIX)/share/lua/5.1/lgsl/demos 56 | @cp lgsl.lua $(PREFIX)/share/lua/5.1/ 57 | @cp $(LUA_TEMPLATES_SRC:%.lua.in=lgsl/templates/%.lua.in) $(PREFIX)/share/lua/5.1/lgsl/templates 58 | 59 | clean: 60 | @echo "cleaning" 61 | @rm -fr debian_build 62 | @rm -fr $(DEB_PACKAGE) 63 | 64 | test: 65 | $(LUA) test-output.lua 66 | 67 | doc: doc-html 68 | 69 | doc-html: 70 | cd $(DOCDIR) && $(MAKE) html 71 | 72 | .PHONY: clean debian install test doc 73 | -------------------------------------------------------------------------------- /doc/linfit.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: lua 2 | 3 | Linear Least Squares fit 4 | =========================== 5 | 6 | Overview 7 | -------- 8 | 9 | This chapter describes routines for performing least squares fits to experimental data using linear combinations of functions. The data may be weighted or unweighted, i.e. with known or unknown errors. For weighted data, the functions compute the best fit parameters and their associated covariance matrix. For unweighted data, the covariance matrix is estimated from the scatter of the points, giving a variance-covariance matrix. 10 | 11 | Linear Fit Functions 12 | -------------------- 13 | 14 | .. function:: linfit(X, y[, w]) 15 | 16 | Perform a linear fit for the observations ``y`` using the model matrix ``X``. It returns a vector with the coefficients of the fit, the residual chi square and the covariance matrix. You can optionally provide the weights ``w`` of the observations to obtain a weighted linear fit. The argument ``y`` should be a column matrix of length N while the model ``X`` should be a N x M matrix where M is the number of basis in the linear model. 17 | 18 | *Example* 19 | Let us suppose that we have two column matrices, x and y, and we want to make a linear fit of y versus x. We first build the model matrix and then we use it to perform the linear fit:: 20 | 21 | X = lgsl.matrix.new(n, 2, function(i,j) return j == 1 and 1 or x[i] end) 22 | c, chisq, cov = lgsl.linfit(X, y) 23 | 24 | The function returns the fit coefficients, the residual chi square and the covariance matrix. 25 | 26 | .. module:: linfit 27 | 28 | Complete Example 29 | ---------------- 30 | 31 | We give a complete example where a set of (x, y) observations are simulated and a linear fit is done:: 32 | 33 | lgsl = require("lgsl") 34 | 35 | x0, x1, n = 0, 12.5, 32 36 | a, b = 0.55, -2.4 37 | xsmp = function(i) return (i-1)/(n-1) * x1 end 38 | 39 | r = lgsl.rng.new() 40 | yobs = function(i) return a*xsmp(i) + b + lgsl.rnd.gaussian(r, 0.4) end 41 | 42 | x = lgsl.matrix.new(n, 1, xsmp) 43 | y = lgsl.matrix.new(n, 1, yobs) 44 | 45 | -- model matrix for the linear fit 46 | X = lgsl.matrix.new(n, 2, function(i,j) return j == 1 and 1 or x[i] end) 47 | 48 | print('Linear fit coefficients: ') 49 | c, chisq, cov = lgsl.linfit(X, y) 50 | print(c) 51 | 52 | fit = function(x) return c[1]+c[2]*x end 53 | 54 | graph = require("graph") 55 | p = graph.fxplot(fit, x0, x1) 56 | p:addline(graph.xyline(x, y), 'blue', {{'marker', size=5}}) 57 | p.title = 'Linear Fit' 58 | 59 | .. figure:: example-linfit.png 60 | -------------------------------------------------------------------------------- /lgsl/templates/rnd-defs.lua.in: -------------------------------------------------------------------------------- 1 | 2 | # function ARGS(num_arg) 3 | # local t = {"r"} 4 | # for k = 1, num_arg do t[k+1] = "a"..k end 5 | # return table.concat(t, ",") 6 | # end 7 | 8 | # function RND_DECLARE(short_name, full_name, num_arg) 9 | # local xargs = ARGS(num_arg) 10 | # t = { 11 | # "function rnd."..short_name.."("..xargs..")", 12 | # " if r == nil then error(\"bad argument #1 to rnd."..short_name.." (RNG expected, got nil)\", 2) end", 13 | # " return gsl."..full_name.."("..xargs..")", 14 | # "end" } 15 | # return table.concat(t, "\n") 16 | # end 17 | 18 | local gsl = require("lgsl.gsl") 19 | 20 | local rnd = {} 21 | 22 | $(RND_DECLARE("bernoulli", "gsl_ran_bernoulli", 1)) 23 | $(RND_DECLARE("beta", "gsl_ran_beta", 2)) 24 | $(RND_DECLARE("binomial", "gsl_ran_binomial", 2)) 25 | $(RND_DECLARE("binomial_knuth", "gsl_ran_binomial_knuth", 2)) 26 | $(RND_DECLARE("binomial_tpe", "gsl_ran_binomial_tpe", 1)) 27 | $(RND_DECLARE("exponential", "gsl_ran_exponential", 1)) 28 | $(RND_DECLARE("exppow", "gsl_ran_exppow", 2)) 29 | $(RND_DECLARE("cauchy", "gsl_ran_cauchy", 1)) 30 | $(RND_DECLARE("chisq", "gsl_ran_chisq", 1)) 31 | $(RND_DECLARE("erlang", "gsl_ran_erlang", 2)) 32 | $(RND_DECLARE("fdist", "gsl_ran_fdist", 2)) 33 | $(RND_DECLARE("flat", "gsl_ran_flat", 2)) 34 | $(RND_DECLARE("gamma", "gsl_ran_gamma", 2)) 35 | $(RND_DECLARE("gamma_int", "gsl_ran_gamma_int", 1)) 36 | $(RND_DECLARE("gamma_mt", "gsl_ran_gamma_mt", 2)) 37 | $(RND_DECLARE("gamma_knuth", "gsl_ran_gamma_knuth", 2)) 38 | $(RND_DECLARE("gaussian", "gsl_ran_gaussian", 1)) 39 | $(RND_DECLARE("gaussian_ratio_method", "gsl_ran_gaussian_ratio_method", 1)) 40 | $(RND_DECLARE("gaussian_ziggurat", "gsl_ran_gaussian_ziggurat", 1)) 41 | $(RND_DECLARE("ugaussian", "gsl_ran_ugaussian", 0)) 42 | $(RND_DECLARE("ugaussian_ratio_method", "gsl_ran_ugaussian_ratio_method", 0)) 43 | $(RND_DECLARE("gaussian_tail", "gsl_ran_gaussian_tail", 2)) 44 | $(RND_DECLARE("ugaussian_tail", "gsl_ran_ugaussian_tail", 1)) 45 | $(RND_DECLARE("landau", "gsl_ran_landau", 0)) 46 | $(RND_DECLARE("geometric", "gsl_ran_geometric", 1)) 47 | $(RND_DECLARE("hypergeometric", "gsl_ran_hypergeometric", 3)) 48 | $(RND_DECLARE("gumbel1", "gsl_ran_gumbel1", 2)) 49 | $(RND_DECLARE("gumbel2", "gsl_ran_gumbel2", 2)) 50 | $(RND_DECLARE("logistic", "gsl_ran_logistic", 1)) 51 | $(RND_DECLARE("lognormal", "gsl_ran_lognormal", 2)) 52 | $(RND_DECLARE("logarithmic", "gsl_ran_logarithmic", 1)) 53 | $(RND_DECLARE("pascal", "gsl_ran_pascal", 2)) 54 | $(RND_DECLARE("pareto", "gsl_ran_pareto", 2)) 55 | $(RND_DECLARE("poisson", "gsl_ran_poisson", 1)) 56 | $(RND_DECLARE("rayleigh", "gsl_ran_rayleigh", 1)) 57 | $(RND_DECLARE("rayleigh_tail", "gsl_ran_rayleigh_tail", 2)) 58 | $(RND_DECLARE("tdist", "gsl_ran_tdist", 1)) 59 | $(RND_DECLARE("laplace", "gsl_ran_laplace", 1)) 60 | $(RND_DECLARE("levy", "gsl_ran_levy", 2)) 61 | $(RND_DECLARE("levy_skew", "gsl_ran_levy_skew", 3)) 62 | $(RND_DECLARE("weibull", "gsl_ran_weibull", 2)) 63 | 64 | return rnd 65 | -------------------------------------------------------------------------------- /test-output.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | local lfs = require("lfs") 3 | local test_dir = "tests" 4 | local log_dir = test_dir.."/log" 5 | package.path = "./?.lua;"..package.path 6 | 7 | local function reference_output(dirpath,testname) 8 | local f, err = io.open(dirpath.."/"..testname..".expect") 9 | if err then return nil, err end 10 | local ref = f:read("*a") 11 | f:close() 12 | return ref 13 | end 14 | 15 | local log_attr = lfs.attributes(log_dir) 16 | if not (log_attr and log_attr.mode=="directory") then 17 | local ok, err = lfs.mkdir(log_dir) 18 | if not ok then 19 | print("Error creating directory "..log_dir..": ",err) 20 | os.exit(1) 21 | end 22 | end 23 | 24 | local record 25 | do 26 | local old_print, old_write = print, io.write 27 | local out_buffer 28 | local function rec_print(...) 29 | local args = {...} 30 | for i,v in ipairs(args) do 31 | args[i]=tostring(v) 32 | end 33 | out_buffer = (out_buffer or "")..table.concat(args,"\t").."\n" 34 | end 35 | local function rec_write(...) 36 | out_buffer = (out_buffer or "")..table.concat({...}) 37 | end 38 | record = function(cmd) 39 | if cmd=="stop" then 40 | print, io.write = old_print, old_write 41 | return out_buffer 42 | else 43 | out_buffer = "" 44 | print, io.write = rec_print, rec_write 45 | end 46 | end 47 | end 48 | 49 | local status = 0 50 | for testfile in lfs.dir(test_dir) do 51 | local fullname = test_dir.."/"..testfile 52 | if lfs.attributes(fullname).mode=="file" and testfile:find("%.lua$") then 53 | local err 54 | -- Try to load the test file 55 | local loaded_test, load_err = loadfile(fullname) 56 | if load_err then 57 | err = "failed to load: "..load_err 58 | end 59 | -- Try to read the reference output 60 | local testname = testfile:match("(%S+)%.lua$") 61 | local out_ref, ref_err = reference_output(test_dir,testname) 62 | if ref_err then 63 | err = "missing expect file: "..ref_err 64 | end 65 | -- Try to run the test file 66 | local out_log 67 | if not err then 68 | record() 69 | local run_ok, run_err = pcall(loaded_test) 70 | out_log = record("stop") 71 | if not run_ok then 72 | err = "failed to run: "..run_err 73 | end 74 | end 75 | local led, msg 76 | if not err and out_log == out_ref then 77 | if out_log:find("^\r?\n?$") then 78 | led, msg = "-", "pass / no output" 79 | else 80 | led, msg = " ", "pass" 81 | end 82 | else 83 | led, msg = "*","fail" 84 | status = 1 85 | if not err then 86 | local log = io.open(log_dir.."/"..testname..".output.diff", "w") 87 | if not log then err = "Could not open log file for writing." 88 | else 89 | log:write("*** reference ***\n",out_ref,"\n") 90 | log:write("*** test program ***\n",out_log,"\n") 91 | log:close() 92 | end 93 | end 94 | end 95 | print(string.format("%s %-24s %-6s %s",led, testname, msg, err or "")) 96 | end 97 | end 98 | os.exit(status) 99 | -------------------------------------------------------------------------------- /lgsl/templates/rk4.lua.in: -------------------------------------------------------------------------------- 1 | 2 | # order = 4 3 | 4 | $(include 'lgsl.templates.ode-defs') 5 | 6 | local eps_abs, eps_rel, a_y, a_dydt = 1e-12, 1e-4, 1, 0 7 | 8 | function rk4_step($(VL'y'), dydt, h, t, f) 9 | -- Makes a Runge-Kutta 4th order advance with step size h. 10 | 11 | -- initial values of variables y. 12 | local $(VL'y0') = $(VL'y') 13 | 14 | -- work space 15 | local $(VL'ytmp') 16 | 17 | -- Runge-Kutta coefficients. Contains values of coefficient k1 18 | -- in the beginning 19 | local $(VL'k') = $(AL'dydt') 20 | 21 | -- k1 step 22 | # for i = 0, N-1 do 23 | y_$(i) = y_$(i) + h / 6 * k_$(i) 24 | ytmp_$(i) = y0_$(i) + 0.5 * h * k_$(i) 25 | # end 26 | 27 | -- k2 step 28 | $(VL'k') = f(t + 0.5 + h, $(VL'ytmp')) 29 | 30 | # for i = 0, N-1 do 31 | y_$(i) = y_$(i) + h / 3 * k_$(i) 32 | ytmp_$(i) = y0_$(i) + 0.5 * h * k_$(i) 33 | # end 34 | 35 | -- k3 step 36 | $(VL'k') = f(t + 0.5 + h,$(VL'ytmp')) 37 | 38 | # for i = 0, N-1 do 39 | y_$(i) = y_$(i) + h / 3 * k_$(i) 40 | ytmp_$(i) = y0_$(i) + h * k_$(i) 41 | # end 42 | 43 | -- k4 step 44 | $(VL'k') = f(t + h, $(VL'ytmp')) 45 | 46 | # for i = 0, N-1 do 47 | local res_$(i) = y_$(i) + h / 6 * k_$(i) 48 | # end 49 | 50 | return $(VL'res') 51 | end 52 | 53 | function rk4_evolve(s, f, t1) 54 | local dydt, t, h = s.dydt, s.t, s.h 55 | local h_new 56 | local $(VL'dydt0') = $(AL'dydt') 57 | local $(VL'y') 58 | 59 | if t + h > t1 then h = t1 - t end 60 | 61 | while h > 0 do 62 | $(VL'y') = $(AL's.y') 63 | 64 | -- First traverse h with one step (save to yonestep) 65 | local $(VL'yonestep') = rk4_step ($(VL'y'), dydt, h, t, f) 66 | 67 | -- first step of h/2 68 | $(VL'y') = rk4_step($(VL'y'), dydt, h/2, t, f) 69 | 70 | $(AL'dydt') = f(t + h/2, $(VL'y')) 71 | 72 | -- second step of h/2 73 | $(VL'y') = rk4_step($(VL'y'), dydt, h/2, t + h/2, f) 74 | 75 | -- Derivatives at output 76 | $(AL'dydt') = f(t + h, $(VL'y')) 77 | 78 | -- Error estimation 79 | -- 80 | -- yerr = C * 0.5 * | y(onestep) - y(twosteps) | / (2^order - 1) 81 | -- 82 | -- constant C is approximately 8.0 to ensure 90% of samples lie within 83 | -- the error (assuming a gaussian distribution with prior p(sigma)=1/sigma.) 84 | 85 | # if debug == 'yes' then 86 | local fmt = string.rep('%g, ', $(N)) 87 | print(string.format('Performed step at t: %g with h=%g, results: y=' .. fmt, 88 | t, h, $(VL'y'))) 89 | io.read '*l' 90 | # end 91 | 92 | local yerr, r, d0 93 | local rmax = 0 94 | 95 | # for i = 0, N-1 do 96 | yerr = 4 * (y_$(i) - yonestep_$(i)) / 15 97 | d0 = eps_rel * (a_y * abs(y_$(i)) + a_dydt * abs(h * dydt[$(i)])) + eps_abs 98 | r = abs(yerr) / abs(d0) 99 | rmax = max(r, rmax) 100 | # end 101 | 102 | # if debug == 'yes' then 103 | print('rmax=', rmax) 104 | io.read '*l' 105 | # end 106 | 107 | local inc 108 | h_new, inc = hadjust(rmax, h) 109 | if inc >= 0 then break end 110 | 111 | h = h_new 112 | # if debug == 'yes' then 113 | print('New increment:', h) 114 | # end 115 | 116 | $(AL'dydt') = $(VL'dydt0') 117 | end 118 | 119 | $(AL's.y') = $(VL'y') 120 | s.t = t + h 121 | s.h = h_new 122 | 123 | return h 124 | end 125 | 126 | return {new= ode_new, init= ode_init, evolve= rk4_evolve} 127 | -------------------------------------------------------------------------------- /lgsl/template.lua: -------------------------------------------------------------------------------- 1 | -- template.lua 2 | -- 3 | -- A Lua preprocessor for template code specialization. 4 | -- Adapted by Steve Donovan, based on original code of Rici Lake. 5 | -- 6 | 7 | local M = {} 8 | 9 | ------------------------------------------------------------------------------- 10 | local function preprocess(ch, name, defs) 11 | 12 | local function parseDollarParen(pieces, chunk) 13 | local append, format = table.insert, string.format 14 | local s = 1 15 | for term, executed, e in chunk:gmatch("()$(%b())()") do 16 | append(pieces, 17 | format("%q..(%s or '')..", chunk:sub(s, term - 1), executed)) 18 | s = e 19 | end 20 | append(pieces, format("%q", chunk:sub(s))) 21 | end 22 | 23 | local function parseHashLines(chunk) 24 | local append = table.insert 25 | local pieces, s, args = chunk:find("^\n*#ARGS%s*(%b())[ \t]*\n") 26 | if not args or args:find("^%(%s*%)$") then 27 | pieces, s = {"return function(_put) ", n = 1}, s or 1 28 | else 29 | pieces = {"return function(_put, ", args:sub(2), n = 2} 30 | end 31 | while true do 32 | local ss, e, lua = chunk:find("^#+([^\n]*\n?)", s) 33 | if not e then 34 | ss, e, lua = chunk:find("\n#+([^\n]*\n?)", s) 35 | append(pieces, "_put(") 36 | parseDollarParen(pieces, chunk:sub(s, ss)) 37 | append(pieces, ")") 38 | if not e then break end 39 | end 40 | append(pieces, lua) 41 | s = e + 1 42 | end 43 | append(pieces, " end") 44 | return table.concat(pieces) 45 | end 46 | 47 | local ppenv 48 | 49 | if defs._self then 50 | ppenv = defs._self 51 | else 52 | ppenv = {string= string, table= table, tonumber= tonumber, template= M} 53 | for k, v in pairs(defs) do ppenv[k] = v end 54 | ppenv._self = ppenv 55 | local include = function(filename) 56 | return M.process(filename, ppenv) 57 | end 58 | setfenv(include, ppenv) 59 | ppenv.include = include 60 | end 61 | 62 | local code = parseHashLines(ch) 63 | local fcode = loadstring(code, name) 64 | if fcode then 65 | setfenv(fcode, ppenv) 66 | return fcode() 67 | end 68 | end 69 | 70 | local function read_file(filename) 71 | local f = io.open(filename) 72 | if not f then 73 | error(string.format('error opening template file %s', filename)) 74 | end 75 | local content = f:read('*a') 76 | f:close() 77 | return content 78 | end 79 | 80 | local function process(name, defs) 81 | local path = package.path 82 | local filename, errmsg = package.searchpath(name,(path:gsub("%.lua([;$])",".lua.in%1"))) 83 | if not filename then error(errmsg) end 84 | local template = read_file(filename) 85 | local codegen = preprocess(template, 'template_gen', defs) 86 | local code = {} 87 | local add = function(s) code[#code+1] = s end 88 | codegen(add) 89 | return table.concat(code) 90 | end 91 | 92 | local function template_error(code, filename, err) 93 | local log = io.open('log-out.lua', 'w') 94 | log:write(code) 95 | log:close() 96 | print('output code log in "log-out.lua"') 97 | error('error loading ' .. filename .. ':' .. err) 98 | end 99 | 100 | local function load(filename, defs) 101 | local code = process(filename, defs) 102 | local f, err = loadstring(code, filename) 103 | if not f then template_error(code, filename, err) end 104 | return f() 105 | end 106 | 107 | M.process = process 108 | M.load = load 109 | 110 | return M 111 | 112 | -------------------------------------------------------------------------------- /demos/vegas.lua: -------------------------------------------------------------------------------- 1 | local iter = require("lgsl.iter") 2 | 3 | local vegas = require("lgsl.vegas") 4 | local ilist = iter.ilist 5 | 6 | local graph = require("graph") 7 | local sf = require("lgsl.sf") 8 | 9 | local function testdim(n) 10 | local lo,hi = 0,2 11 | local exact = n*(n+1)/2 * (hi^3 - lo^3)/3 * (hi-lo)^(n-1) 12 | local function integrand(x) 13 | local s = 0 14 | for k= 1, n do s = s + k*x[k]^2 end 15 | return s 16 | end 17 | local a, b = ilist(function() return lo end, n), ilist(function() return hi end, n) 18 | print("Integrating SUM_(k=1,"..n..") k*x[k]^2") 19 | local calls = 1e4*n 20 | local vegas_result = vegas.integ(integrand,a,b,calls) 21 | print( string.format([[ 22 | result = %.6f 23 | sigma = %.6f 24 | exact = %.6f 25 | error = %.6f = %.2g sigma 26 | calls = %.0f 27 | ========================== 28 | ]] ,vegas_result.result,vegas_result.sigma,exact, 29 | vegas_result.result - exact, 30 | math.abs(vegas_result.result - exact)/vegas_result.sigma,vegas_result.nruns*calls)) 31 | return vegas_result.result 32 | end 33 | 34 | local function demo1() 35 | local maxdim = 10 36 | local lo,hi = 0,2 37 | local results = {} 38 | local p = graph.plot('Integral of sum (i*x_i^2) (i=1..n)') 39 | p.clip, p.pad = false, true 40 | local exact = graph.filine(function(n) return n*(n+1)/2 * (hi^3 - lo^3)/3 * (hi-lo)^(n-1) end,maxdim) 41 | local computed = graph.filine(testdim,1,maxdim) 42 | p:addline(exact) 43 | p:add(computed, "blue", {{'marker', size=8}}) 44 | p.xtitle="n" 45 | p:show() 46 | end 47 | 48 | local function getunitsphere(n) 49 | return function(x) 50 | local s = 0 51 | for k= 1, n do s = s + x[k]^2 end 52 | return s < 1 and 1 or 0 53 | end 54 | end 55 | 56 | local function demo2() 57 | local ln = graph.path(1, 2) -- 1-sphere = [-1, 1] (length 2) 58 | local max_dim = 14 59 | for d=2, max_dim do 60 | print("==========================================") 61 | print("Calculating the volume of a unit "..d.."-sphere.") 62 | local a, b = ilist(function() return 0 end, d), ilist(function() return 1 end, d) 63 | local calls, n = d*1e4,1 64 | local vegas_result = vegas.integ(getunitsphere(d),a,b,calls) 65 | local res,sig,num,cont = vegas_result.result, vegas_result.sigma, vegas_result.nruns, vegas_result.continue 66 | local fmt = "Volume = %.3f +/- %.3f " 67 | print(string.format(fmt,res*2^d,sig*2^d)) 68 | while(sig/res > 0.005) do 69 | print("Increasing accuracy, doubling number of calls...") 70 | vegas_result = cont(calls*(2^n)) 71 | res,sig,num = vegas_result.result, vegas_result.sigma, vegas_result.nruns 72 | print(string.format(fmt,res*2^d,sig*2^d)) 73 | n=n+1 74 | end 75 | ln:line_to(d,res*2^d) 76 | end 77 | local p = graph.plot('Volume of a unit n-sphere') 78 | p.clip, p.pad = false, true 79 | p:addline(graph.fxline(function(n) return math.pi^(n/2) / sf.gamma(1+n/2) end, 1, max_dim)) 80 | p:legend('exact value', 'red', 'line') 81 | p:addline(ln, "blue", {{'marker', size=6}}) 82 | p:legend('calculated', 'blue', 'circle', {{'stroke'}}) 83 | p.xtitle="n" 84 | p.ytitle="V" 85 | p:show() 86 | end 87 | 88 | return {'VEGAS Monte Carlo integration', { 89 | { 90 | name= 'vegas', 91 | f = demo1, 92 | description = 'Integrate 9 n-dimensional functions sum(i*(x_i^2))' 93 | }, 94 | { 95 | name= 'sphere', 96 | f = demo2, 97 | description = 'Calculate the volume of a unit n-sphere (n=2..14)' 98 | } 99 | }} 100 | -------------------------------------------------------------------------------- /demos/anim.lua: -------------------------------------------------------------------------------- 1 | local cos, sin = math.cos, math.sin 2 | local graph = require("graph") 3 | local rng = require("lgsl.rng") 4 | local rnd = require("lgsl.rnd") 5 | local pi,tan,exp =math.pi,math.tan,math.exp 6 | 7 | local function star(r) 8 | local a, ae = 54*pi/180, 72*pi/180 9 | local li, hi = r*cos(a), r*sin(a) 10 | local he = li*tan(ae) 11 | local xv, yv = 0, - hi - he 12 | local xb, yb = - li, - hi 13 | local p = graph.path(xv, yv) 14 | p:line_to(xb, yb) 15 | for k=1, 4 do 16 | local th = 2*pi*k/5 17 | p:line_to(xv*cos(th) + yv*sin(th), yv*cos(th) - xv*sin(th)) 18 | p:line_to(xb*cos(th) + yb*sin(th), yb*cos(th) - xb*sin(th)) 19 | end 20 | p:close() 21 | return p 22 | end 23 | 24 | local function demo1() 25 | local plt = graph.canvas 'rotating star' 26 | plt.units = false 27 | plt:show() 28 | local a = 15.0 29 | plt:limits(-a, -a, a, a) 30 | local r = rng.new() 31 | local gray1, gray2 = graph.rgb(230, 230, 230), graph.rgb(155, 155, 155) 32 | for k = 1, 50 do 33 | local x, y = (2*r:get()-1)*a, (2*r:get()-1)*a 34 | local d = rnd.gaussian(r, 0.015*a) + 0.03*a 35 | local s = star(d) 36 | plt:add(s, gray1, {}, {{'translate', x=x, y=y}}) 37 | plt:addline(s, gray2, {}, {{'translate', x=x, y=y}}) 38 | end 39 | plt:pushlayer() 40 | local N, R, nc = 128, 5.0, 8 41 | local yellow, dark = graph.rgba(255, 255, 0, 180), graph.rgb(128, 128, 0) 42 | for k = 0, N * nc do 43 | local r = R * cos(pi*k/N)^2 44 | local th = 2*pi*(k/(N*nc*10)) 45 | local s= star(r) 46 | plt:clear() 47 | plt:add(s, yellow, {}, {{'rotate', angle=th}}) 48 | plt:addline(s, dark, {}, {{'rotate', angle=th}}) 49 | plt:flush() 50 | end 51 | end 52 | 53 | local function demo2() 54 | local f = function(x) return exp(-0.1*x) * cos(x) end 55 | local p = graph.plot 'y = f(x)' 56 | local x0, x1 = 0, 10*pi 57 | local cc = graph.fxline(f, x0, x1) 58 | p.sync = false 59 | p:limits(0, -1, 10*pi, 1) 60 | p:pushlayer() 61 | p:show() 62 | local N = 256 63 | local yellow = graph.rgba(255,255,0,155) 64 | for k= 2, N do 65 | local x = x0 + k * (x1-x0) / N 66 | local ca = graph.fxline(f, x0, x, k) 67 | ca:line_to(x, 0); ca:line_to(0, 0); ca:close() 68 | p:clear() 69 | p:add(ca, yellow) 70 | p:addline(cc) 71 | p:flush() 72 | end 73 | end 74 | 75 | local function demo3() 76 | local p = graph.plot 'box plot' 77 | local r = rng.new() 78 | r:set(os.time()) 79 | p:addline(graph.rect(-10, -10, 10, 10), 'blue', {{'dash', 7, 3}}) 80 | p.sync = false 81 | p:pushlayer() 82 | p:show() 83 | 84 | local L = 100 85 | local get = function() return rnd.gaussian(r, L/2) end 86 | 87 | local N = 256 88 | for k=1, N do 89 | p:clear() 90 | for j=1, 4 do 91 | local x, y, rad = get(), get(), 5 + r:get() * L/2 92 | local rt = graph.circle(x, y, rad) 93 | p:add(rt, graph.rgba(r:getint(255), r:getint(255),r:getint(255), 128)) 94 | p:addline(rt, 'black') 95 | end 96 | p:flush() 97 | end 98 | 99 | return p 100 | end 101 | 102 | -- demo1() 103 | -- demo2() 104 | -- demo3() 105 | 106 | return {'Animations', { 107 | { 108 | name = 'anim1', 109 | f = demo1, 110 | description = 'Rotating Star' 111 | }, 112 | { 113 | name = 'anim2', 114 | f = demo2, 115 | description = 'Function\'s definite integral illustation' 116 | }, 117 | { 118 | name = 'anim3', 119 | f = demo3, 120 | description = 'Animation stress test with automatic plot limits' 121 | }, 122 | }} 123 | -------------------------------------------------------------------------------- /demos/nlinfit.lua: -------------------------------------------------------------------------------- 1 | local graph = require("graph") 2 | local matrix = require("lgsl.matrix") 3 | local nlinfit = require("lgsl.nlinfit") 4 | local rng = require("lgsl.rng") 5 | local rnd = require("lgsl.rnd") 6 | local pi,sqrt,sin,cos,exp = math.pi, math.sqrt,math.sin, math.cos, math.exp 7 | local iter = require("lgsl.iter") 8 | 9 | local function demo1() 10 | local n = 40 11 | 12 | local sigrf = 0.1 13 | local yrf 14 | 15 | local fdf = function(x, f, J) 16 | for i=1, n do 17 | local A, lambda, b = x[1], x[2], x[3] 18 | local t, y, sig = i-1, yrf[i], sigrf 19 | local e = exp(- lambda * t) 20 | if f then f[i] = (A*e+b - y)/sig end 21 | if J then 22 | J:set(i, 1, e / sig) 23 | J:set(i, 2, - t * A * e / sig) 24 | J:set(i, 3, 1 / sig) 25 | end 26 | end 27 | end 28 | 29 | local model = function(x, t) 30 | local A, lambda, b = x[1], x[2], x[3] 31 | return A * exp(- lambda * t) + b 32 | end 33 | 34 | local xref = matrix.vec {5, 0.1, 1} 35 | 36 | local r = rng.new() 37 | r:set(0) 38 | 39 | yrf = matrix.new(n, 1, function(i) return model(xref, i-1) + rnd.gaussian(r, 0.1) end) 40 | 41 | local s = nlinfit {n= n, p= 3} 42 | 43 | s:set(fdf, matrix.vec {1, 0, 0}) 44 | print(s.x, s.chisq) 45 | 46 | for i=1, 10 do 47 | s:iterate() 48 | print('ITER=', i, ': ', s.x, s.chisq) 49 | if s:test(0, 1e-8) then break end 50 | end 51 | 52 | local p = graph.plot('Non-linear fit example') 53 | local pts = graph.ipath(iter.sequence(function(i) return i-1, yrf[i] end, n)) 54 | local fitln = graph.fxline(function(t) return model(s.x, t) end, 0, n-1) 55 | p:addline(pts, 'blue', {{'marker', size=5}}) 56 | p:addline(fitln) 57 | p.clip = false 58 | p.pad = true 59 | p:show() 60 | end 61 | 62 | local function demo2() 63 | local n = 50 64 | local px = matrix.vec {1.55, -1.1, 12.5} 65 | local p0 = matrix.vec {2.5, -1.5, 5.3} 66 | local xs = function(i) return (i-1)/n end 67 | local r = rng.new() 68 | 69 | local fmodel = function(p, t, J) 70 | local e, s = exp(p[2] * t), sin(p[3] * t) 71 | if J then 72 | J[1] = e * s 73 | J[2] = t * p[1] * e * s 74 | J[3] = t * p[1] * e * cos(p[3] * t) 75 | end 76 | return p[1] * e * s 77 | end 78 | 79 | local y = matrix.new(n, 1, function(i,j) return fmodel(px, xs(i)) * (1 + rnd.gaussian(r, 0.1)) end) 80 | local x = matrix.new(n, 1, function(i,j) return xs(i) end) 81 | 82 | local function fdf(p, f, J) 83 | for k=1, n do 84 | local ym = fmodel(p, xs(k), J and J[k]) 85 | if f then f[k] = ym - y[k] end 86 | end 87 | end 88 | 89 | local pl = graph.plot('Non-linear fit / A * exp(a t) sin(w t)') 90 | pl:addline(graph.xyline(x, y), 'blue', {{'marker', size= 5, mark="triangle"}}) 91 | pl:legend('data', 'blue', 'triangle', {{'stroke'}}) 92 | 93 | local s = nlinfit {n= n, p= #p0} 94 | 95 | s:set(fdf, p0) 96 | print(s.x, s.chisq) 97 | 98 | pl:addline(graph.fxline(function(x) return fmodel(s.x, x) end, 0, xs(n)), 'red', {{'dash', 7, 3, 3, 3}}) 99 | pl:legend('seed', 'red', 'line', {{'stroke'},{'dash',7,3}}) 100 | 101 | for i=1, 10 do 102 | s:iterate() 103 | print('ITER=', i, ': ', s.x, s.chisq) 104 | if s:test(0, 1e-8) then break end 105 | end 106 | 107 | pl:addline(graph.fxline(function(x) return fmodel(s.x, x) end, 0, xs(n)), 'red') 108 | pl:legend('best fit', 'red', 'line') 109 | pl.pad = true 110 | pl:show() 111 | 112 | return pl 113 | end 114 | 115 | return {'Non-linear fit', { 116 | { 117 | name = 'nlfit1', 118 | f = demo1, 119 | description = 'Simple non-linear fit' 120 | }, 121 | { 122 | name = 'nlfit2', 123 | f = demo2, 124 | description = 'Non-linear fit of oscillatory function' 125 | }, 126 | }} 127 | -------------------------------------------------------------------------------- /demos/fft.lua: -------------------------------------------------------------------------------- 1 | 2 | -- Fast Fourier Transform Demos / fft.lua 3 | -- 4 | -- Copyright (C) 2009, 2010 Francesco Abbate 5 | -- 6 | -- This program is free software; you can redistribute it and/or modify 7 | -- it under the terms of the GNU General Public License as published by 8 | -- the Free Software Foundation; either version 3 of the License, or (at 9 | -- your option) any later version. 10 | -- 11 | -- This program is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | -- General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU General Public License 17 | -- along with this program; if not, write to the Free Software 18 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | 20 | local graph = require("graph") 21 | local matrix = require("lgsl.matrix") 22 | local complex = require("lgsl.complex") 23 | local sf = require("lgsl.sf") 24 | local f = require("lgsl.fft") 25 | local iter = require("lgsl.iter") 26 | local fft, fftinv = f.fft, f.fftinv 27 | local plot, filine, fibars, ibars = graph.plot, graph.filine, graph.fibars, graph.ibars 28 | 29 | local function demo1() 30 | local n, ncut = 8*3*5, 16 31 | 32 | local sq = matrix.new(n, 1, function(i) return i < n/3 and 0 or (i < 2*n/3 and 1 or 0) end) 33 | 34 | local pt = plot('Original signal / reconstructed') 35 | 36 | pt:addline(filine(function(i) return sq[i] end, n), 'black') 37 | 38 | local ft = fft(sq) 39 | 40 | local pf = fibars(function(k) return complex.abs(ft[k]) end, 0, n/2, 'black') 41 | pf.title = 'FFT Power Spectrum' 42 | 43 | for k=ncut, n - ncut do ft[k] = 0 end 44 | local sqt = fftinv(ft) 45 | 46 | pt:addline(filine(function(i) return sqt[i] end, n), 'red') 47 | pt:show() 48 | 49 | return pt, pf 50 | end 51 | 52 | local function demo2() 53 | local n, ncut = 256, 16 54 | 55 | local sq = matrix.new(n, 1, function(i) return i < n/3 and 0 or (i < 2*n/3 and 1 or 0) end) 56 | 57 | local pt = plot('Original signal / reconstructed') 58 | local pf = plot('FFT Power Spectrum') 59 | 60 | pt:addline(filine(function(i) return sq[i] end, n), 'black') 61 | 62 | local ft = fft(sq, true) 63 | 64 | pf:add(ibars(iter.isample(function(k) return complex.abs(ft[k]) end, 0, n/2)), 'black') 65 | 66 | for k=ncut, n - ncut do ft[k] = 0 end 67 | fftinv(ft, true) 68 | 69 | pt:addline(filine(function(i) return sq[i] end, n), 'red') 70 | 71 | pf:show() 72 | pt:show() 73 | 74 | return pt, pf 75 | end 76 | 77 | local function demo3() 78 | local n, ncut, order = 512, 11, 8 79 | local x1 = sf.besselJ_zero(order, 14) 80 | local xsmp = function(k) return x1*(k-1)/(n-1) end 81 | 82 | local bess = matrix.new(n, 1, function(i) return sf.besselJ(order, xsmp(i)) end) 83 | 84 | local p = plot('Original signal / reconstructed') 85 | p:addline(filine(function(i) return bess[i] end, n), 'black') 86 | 87 | local ft = fft(bess) 88 | 89 | local fftplot = plot('FFT power spectrum') 90 | local bars = ibars(iter.isample(function(k) return complex.abs(ft[k]) end, 0, 60)) 91 | fftplot:add(bars, 'black') 92 | fftplot:show() 93 | 94 | for k=ncut, n/2 do ft[k] = 0 end 95 | local bessr = fftinv(ft) 96 | 97 | p:addline(filine(function(i) return bessr[i] end, n), 'red', {{'dash', 7, 3}}) 98 | p:show() 99 | 100 | return p, fftplot 101 | end 102 | 103 | return {'FFT', { 104 | { 105 | name = 'fft1', 106 | f = demo1, 107 | description = 'GSL example with square function and frequency cutoff' 108 | }, 109 | { 110 | name = 'fft2', 111 | f = demo2, 112 | description = 'The same as before but the FFT transform is done in place' 113 | }, 114 | { 115 | name = 'fft3', 116 | f = demo3, 117 | description = 'frequency cutoff example on bessel function' 118 | }, 119 | }} 120 | -------------------------------------------------------------------------------- /doc/lua-base.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: lua 2 | 3 | .. module:: iter 4 | 5 | .. _lua_base: 6 | 7 | Iterators 8 | ========= 9 | 10 | LGSL provides a number of simple functions to perform some common tasks related to iterators. 11 | These functions allow you to write more simple and compact code and to improve the readability. 12 | The functions described below are available in the module :mod:`iter`. 13 | 14 | .. function:: sequence(f, a, b) 15 | sequence(f, b) 16 | 17 | Return an "iterator" that gives the value (or the values) returned by the evaluation of ``f(i)`` where ``i`` is an integer that goes from ``a`` to ``b``. In the second form, the generated values start from one. 18 | 19 | Generally, an iterator is a function that, each time that it is called, returns one value from a sequence. The sequence is considered to be terminated when the iterator returns ``nil``. An iterator can be used directly in a ``for`` loop with the following syntax:: 20 | 21 | for a, b, ... in f do 22 | -- [ some code here] 23 | end 24 | 25 | where ``f`` is the iterator. If ``f`` returns multiple values they will be all returned by the iterator. 26 | 27 | .. function:: sample(f, xi, xs, n) 28 | 29 | Return an iterator that gives the couple ``x, f(x)`` for ``x`` going from ``xi`` to ``xs`` with ``n`` uniformly spaced intervals. If ``f`` returns multiple values, only the first one is retained. 30 | 31 | Example:: 32 | 33 | iter = require("lgsl.iter") 34 | -- print (x, sin(x)) for x going from 0 to 2*pi with 16 sampling points 35 | for x, y in iter.sample(math.sin, 0, 2*math.pi, 16) do 36 | print(x, y) 37 | end 38 | 39 | .. function:: isample(f, a, b) 40 | isample(f, b) 41 | 42 | Return an iterator that gives the couple ``i, f(i)`` where ``i`` is an integer going from ``a`` to ``b``. In the second form, the sequence will start from one. If ``f`` returns multiple values, only the first one is retained. 43 | 44 | .. function:: ilist(f, a, b) 45 | ilist(f, b) 46 | 47 | Returns a list with the elements ``f(i)`` where ``i`` is an integer going from a to b. 48 | In the second form, the sequence will start from one. 49 | 50 | .. function:: isum(f, a, b) 51 | isum(f, b) 52 | 53 | Returns the sum of ``f(i)`` for all integers ``i`` from a to b. 54 | In the second form, the sequence will start from one. 55 | 56 | 57 | 58 | More complex iterators 59 | ---------------------- 60 | 61 | Actually the more general form of an iterator is the following:: 62 | 63 | for i, a, b, ... in f, s, i0 do 64 | -- [ some code here] 65 | end 66 | 67 | In this latter form, the iterator f is called in the form ``f(s, i)``, where ``s`` is the value provided in the ``for`` loop. The value of ``i`` changes every time, the value taken is the first value returned by the function ``f`` the last times it was called or, for the first time only, ``i0``. 68 | 69 | We give an example to build a stateless row "iterator" over the rows of a matrix.:: 70 | 71 | -- we define the stateless iterator 72 | function my_row_iter(m, i) 73 | local r, c = m:dim() 74 | if i <= r then 75 | return i+1, m:row(i) 76 | end 77 | end 78 | 79 | -- how it can be used 80 | for i, row in my_row_iter, m, 1 do 81 | print('Row number', i, ':', row) 82 | end 83 | 84 | Note that in this case we have to provide the "iterator", its "state" and the initial "index" value ``i0`` explicitly. You may avoid that by using an "iterator builder" like in the following example:: 85 | 86 | function make_row_iter(m) 87 | return my_row_iter, m, 1 88 | end 89 | 90 | -- then we can write 91 | for i, row in make_row_iter(m) do 92 | print('Row number', i, ':', row) 93 | end 94 | 95 | To summarize, this example shows how to create an iterator to iterate over the rows of a matrix. The iterator builder is a function that returns three values, the first is a function (the iterator itself), the second is the state and the third argument is the first value of the index. 96 | 97 | -------------------------------------------------------------------------------- /tests/randist.expect: -------------------------------------------------------------------------------- 1 | Pass gaussian_pdf(x, sigma) : 3.969525474770118e-01 2 | Pass gaussian_P(x, sigma) : 5.398278372770290e-01 3 | Pass gaussian_Q(x, sigma) : 4.601721627229710e-01 4 | Pass gaussian_Pinv(x, sigma) : -1.281551565544601e+00 5 | Pass gaussian_Qinv(x, sigma) : 1.281551565544601e+00 6 | Pass exponential_pdf(x, mu) : 9.048374180359595e-01 7 | Pass exponential_P(x, mu) : 9.516258196404043e-02 8 | Pass exponential_Q(x, mu) : 9.048374180359595e-01 9 | Pass exponential_Pinv(x, mu) : 1.053605156578263e-01 10 | Pass exponential_Qinv(x, mu) : 2.302585092994045e+00 11 | Pass chisq_pdf(x, nu) : 1.142894236600128e-06 12 | Pass chisq_P(x, nu) : 2.563032539662434e-08 13 | Pass chisq_Q(x, nu) : 9.999999743696746e-01 14 | Pass chisq_Pinv(x, nu) : 4.168159008146109e+00 15 | Pass chisq_Qinv(x, nu) : 1.468365657325983e+01 16 | Pass laplace_pdf(x, a) : 1.612026834136676e-01 17 | Pass laplace_P(x, a) : 5.163919497589970e-01 18 | Pass laplace_Q(x, a) : 4.836080502410030e-01 19 | Pass laplace_Pinv(x, a) : -4.828313737302301e+00 20 | Pass laplace_Qinv(x, a) : 4.828313737302301e+00 21 | Pass tdist_pdf(x, nu) : 3.858863266209659e-01 22 | Pass tdist_P(x, nu) : 5.387317760216594e-01 23 | Pass tdist_Q(x, nu) : 4.612682239783406e-01 24 | Pass tdist_Pinv(x, nu) : -1.383028738396633e+00 25 | Pass tdist_Qinv(x, nu) : 1.383028738396633e+00 26 | Pass cauchy_pdf(x, a) : 1.059855336904963e-01 27 | Pass cauchy_P(x, a) : 5.106064024055355e-01 28 | Pass cauchy_Q(x, a) : 4.893935975944646e-01 29 | Pass cauchy_Pinv(x, a) : -9.233050611525762e+00 30 | Pass cauchy_Qinv(x, a) : 9.233050611525762e+00 31 | Pass rayleigh_pdf(x, sigma) : 9.950124791926823e-02 32 | Pass rayleigh_P(x, sigma) : 4.987520807317688e-03 33 | Pass rayleigh_Q(x, sigma) : 9.950124791926823e-01 34 | Pass rayleigh_Pinv(x, sigma) : 4.590436050264208e-01 35 | Pass rayleigh_Qinv(x, sigma) : 2.145966026289347e+00 36 | Pass fdist_pdf(x, nu1, nu2) : 8.638375985314765e-01 37 | Pass fdist_P(x, nu1, nu2) : 9.297052154195022e-02 38 | Pass fdist_Q(x, nu1, nu2) : 9.070294784580498e-01 39 | Pass fdist_Pinv(x, nu1, nu2) : 1.081851067789194e-01 40 | Pass fdist_Qinv(x, nu1, nu2) : 4.324555320336761e+00 41 | Pass gamma_pdf(x, a, b) : 5.945183903129460e-04 42 | Pass gamma_P(x, a, b) : 2.006749362439790e-05 43 | Pass gamma_Q(x, a, b) : 9.999799325063756e-01 44 | Pass gamma_Pinv(x, a, b) : 2.204130656498644e+00 45 | Pass gamma_Qinv(x, a, b) : 1.064464067566841e+01 46 | Pass beta_pdf(x, a, b) : 1.079999999999999e-01 47 | Pass beta_P(x, a, b) : 3.699999999999995e-03 48 | Pass beta_Q(x, a, b) : 9.963000000000000e-01 49 | Pass beta_Pinv(x, a, b) : 3.204605837218185e-01 50 | Pass beta_Qinv(x, a, b) : 8.574406832899693e-01 51 | Pass gaussian_tail_pdf(5, a, sigma): 1.101356902446165e-03 52 | Pass exppow_pdf(x, a, b) : 1.878543514563088e-01 53 | Pass exppow_P(x, a, b) : 5.187993564692450e-01 54 | Pass exppow_Q(x, a, b) : 4.812006435307550e-01 55 | Pass lognormal_pdf(x, zeta, sigma) : 1.707930831120359e-02 56 | Pass lognormal_P(x, zeta, sigma) : 4.789900863651144e-04 57 | Pass lognormal_Q(x, zeta, sigma) : 9.995210099136349e-01 58 | Pass lognormal_Pinv(x, zeta, sigma): 7.546120026931251e-01 59 | Pass lognormal_Qinv(x, zeta, sigma): 9.791861344054885e+00 60 | Pass binomial_pdf(x, p, n) : 1.679615999999999e-02 61 | Pass binomial_P(x, p, n) : 1.679615999999999e-02 62 | Pass binomial_Q(x, p, n) : 9.832038400000001e-01 63 | Pass poisson_pdf(x, mu) : 3.678794411714423e-01 64 | Pass poisson_P(x, mu) : 3.678794411714423e-01 65 | Pass poisson_Q(x, mu) : 6.321205588285578e-01 66 | -------------------------------------------------------------------------------- /lgsl-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "LGSL" 2 | version = "0.1-1" 3 | source = { 4 | url = "https://github.com/ladc/lgsl/archive/0.1.zip", 5 | dir = "lgsl-0.1" 6 | } 7 | description = { 8 | summary = "A numerical library for Lua based on GSL", 9 | detailed = [[ 10 | LGSL is a collection of numerical algorithms and functions for Lua, based on the 11 | GNU Scientific Library (GSL). It allows matrix/vector manipulation and linear 12 | algebra operations. 13 | 14 | LGSL is not just a wrapper over the C API of GSL but offers a much more 15 | simple and expressive way to use GSL. The objective of LGSL is to give 16 | the user the power to easily access GSL functions without having to write 17 | a complete C application. 18 | 19 | LGSL is based on the numerical modules of GSL Shell. 20 | ]], 21 | homepage = "https://github.com/ladc/lgsl", 22 | license = "GPL-3", 23 | maintainer = "Lesley De Cruz " 24 | } 25 | dependencies = { 26 | "lua == 5.1" -- this should be luajit2 27 | } 28 | external_dependencies = { 29 | GSL = { 30 | library = "gsl" 31 | }, 32 | } 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["lgsl.init"] = "lgsl.lua", 37 | -- utilities 38 | ["lgsl.sort"] = "lgsl/sort.lua", 39 | ["lgsl.check"] = "lgsl/check.lua", 40 | ["lgsl.gsl-check"] = "lgsl/gsl-check.lua", 41 | ["lgsl.gsl"] = "lgsl/gsl.lua", 42 | ["lgsl.template"] = "lgsl/template.lua", 43 | -- loaded in lgsl 44 | ["lgsl.matrix"] = "lgsl/matrix.lua", 45 | ["lgsl.complex"] = "lgsl/complex.lua", 46 | ["lgsl.eigen"] = "lgsl/eigen.lua", 47 | ["lgsl.iter"] = "lgsl/iter.lua", 48 | ["lgsl.rng"] = "lgsl/rng.lua", 49 | ["lgsl.rnd"] = "lgsl/rnd.lua", 50 | ["lgsl.randist"] = "lgsl/randist.lua", 51 | ["lgsl.sf"] = "lgsl/sf.lua", 52 | ["lgsl.csv"] = "lgsl/csv.lua", 53 | ["lgsl.bspline"] = "lgsl/bspline.lua", 54 | ["lgsl.fft"] = "lgsl/fft.lua", 55 | ["lgsl.integ"] = "lgsl/integ.lua", 56 | ["lgsl.linfit"] = "lgsl/linfit.lua", 57 | ["lgsl.nlinfit"] = "lgsl/nlinfit.lua", 58 | ["lgsl.ode"] = "lgsl/ode.lua", 59 | ["lgsl.vegas"] = "lgsl/vegas.lua", 60 | ["lgsl.demos"] = "demos/demos.lua", 61 | }, 62 | install = { 63 | lua = { 64 | -- templates 65 | ["lgsl.templates.gauss-kronrod-x-wgs"] = "lgsl/templates/gauss-kronrod-x-wgs.lua.in", 66 | ["lgsl.templates.lmfit"] = "lgsl/templates/lmfit.lua.in", 67 | ["lgsl.templates.ode-defs"] = "lgsl/templates/ode-defs.lua.in", 68 | ["lgsl.templates.qag"] = "lgsl/templates/qag.lua.in", 69 | ["lgsl.templates.qng"] = "lgsl/templates/qng.lua.in", 70 | ["lgsl.templates.rk4"] = "lgsl/templates/rk4.lua.in", 71 | ["lgsl.templates.rk8pd"] = "lgsl/templates/rk8pd.lua.in", 72 | ["lgsl.templates.rkf45"] = "lgsl/templates/rkf45.lua.in", 73 | ["lgsl.templates.rkf45vec"] = "lgsl/templates/rkf45vec.lua.in", 74 | ["lgsl.templates.rnd-defs"] = "lgsl/templates/rnd-defs.lua.in", 75 | ["lgsl.templates.sf-defs"] = "lgsl/templates/sf-defs.lua.in", 76 | ["lgsl.templates.vegas-defs"] = "lgsl/templates/vegas-defs.lua.in", 77 | -- demos 78 | ["lgsl.demos.anim"] = "demos/anim.lua", 79 | ["lgsl.demos.bspline"] = "demos/bspline.lua", 80 | ["lgsl.demos.demos"] = "demos/demos.lua", 81 | ["lgsl.demos.fft"] = "demos/fft.lua", 82 | ["lgsl.demos.fractals"] = "demos/fractals.lua", 83 | ["lgsl.demos.integ"] = "demos/integ.lua", 84 | ["lgsl.demos.linfit"] = "demos/linfit.lua", 85 | ["lgsl.demos.nlinfit"] = "demos/nlinfit.lua", 86 | ["lgsl.demos.ode"] = "demos/ode.lua", 87 | ["lgsl.demos.plot"] = "demos/plot.lua", 88 | ["lgsl.demos.roots"] = "demos/roots.lua", 89 | ["lgsl.demos.sf"] = "demos/sf.lua", 90 | ["lgsl.demos.vegas"] = "demos/vegas.lua", 91 | ["lgsl.demos.wave-particle"] = "demos/wave-particle.lua", 92 | }, 93 | }, 94 | copy_directories = { "tests", "doc" }, 95 | } 96 | -------------------------------------------------------------------------------- /lgsl/templates/rkf45.lua.in: -------------------------------------------------------------------------------- 1 | 2 | # -- rkf45.lua.in 3 | # -- 4 | # -- Copyright (C) 2009-2011 Francesco Abbate 5 | # -- 6 | # -- This program is free software; you can redistribute it and/or modify 7 | # -- it under the terms of the GNU General Public License as published by 8 | # -- the Free Software Foundation; either version 3 of the License, or (at 9 | # -- your option) any later version. 10 | # -- 11 | # -- This program is distributed in the hope that it will be useful, but 12 | # -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # -- General Public License for more details. 15 | # -- 16 | # -- You should have received a copy of the GNU General Public License 17 | # -- along with this program; if not, write to the Free Software 18 | # -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | # -- 20 | 21 | # -- Adapted from the GSL Library, version 1.14 22 | 23 | # -- Runge-Kutta-Fehlberg 4(5) 24 | 25 | # -- Reference eg. Hairer, E., Norsett S.P., Wanner, G. Solving ordinary 26 | # -- differential equations I, Nonstiff Problems, 2nd revised edition, 27 | # -- Springer, 2000. 28 | 29 | local abs, max, min = math.abs, math.max, math.min 30 | 31 | # order = 5 32 | 33 | $(include 'lgsl.templates.ode-defs') 34 | 35 | # AH = { '1/4', '3/8', '12/13', '1', '1/2' } 36 | 37 | # B = { 0 } 38 | # B[2] = { '1/4' } 39 | # B[3] = { '3/32', '9/32' } 40 | # B[4] = { '1932/2197', '-7200/2197', '7296/2197'} 41 | # B[5] = { '8341/4104', '-32832/4104', '29440/4104', '-845/4104'} 42 | # B[6] = { '-6080/20520', '41040/20520', '-28352/20520', '9295/20520', '-5643/20520'} 43 | 44 | # C = {'902880/7618050', 45 | # '0', 46 | # '3953664/7618050', 47 | # '3855735/7618050', 48 | # '-1371249/7618050', 49 | # '277020/7618050' } 50 | 51 | # -- These are the differences of fifth and fourth order coefficients 52 | # -- for error estimation 53 | 54 | # EC = { '1/360', '0', '-128/4275', '-2197/75240', '1/50', '2/55' } 55 | 56 | # y_err_only = (a_dydt == 0) 57 | 58 | local function rkf45_step(s, t1) 59 | local t, h, f = s.t, s.h, s.f 60 | local s_y, s_dydt = s.y, s.dydt 61 | local hadj, inc 62 | 63 | local $(VL'y') 64 | local $(VL'k1') = $(AL's_dydt.data') 65 | 66 | if t < t1 and t + h > t1 then h = t1 - t end 67 | 68 | while h > 0 do 69 | $(VL'y') = $(AL's_y.data') 70 | local rmax = 0 71 | 72 | do 73 | local $(VL'ytmp') 74 | 75 | # for S = 2, 6 do 76 | # for i = 0, N-1 do 77 | ytmp_$(i) = y_$(i) + h * ($(KCONV(B[S], S-1, i))) 78 | # end 79 | local $(VLI('k', S)) = f(t + $(AH[S-1]) * h, $(VL'ytmp')) 80 | # end 81 | 82 | local di 83 | # for i = 0, N-1 do 84 | di = $(KCONV(C, 6, i)) 85 | y_$(i) = y_$(i) + h * di 86 | # end 87 | 88 | # if not y_err_only then 89 | local $(VL'dydt') = f(t + h, $(VL'y')) 90 | # for i = 0, N-1 do 91 | s_dydt.data[$(i)] = dydt_$(i) 92 | # end 93 | # end 94 | 95 | do 96 | local yerr, r, d0 97 | 98 | # for i = 0, N-1 do 99 | yerr = h * ($(KCONV(EC, 6, i))) 100 | # if y_err_only then 101 | d0 = $(eps_rel) * ($(a_y) * abs(y_$(i))) + $(eps_abs) 102 | # else 103 | d0 = $(eps_rel) * ($(a_y) * abs(y_$(i)) + $(a_dydt) * abs(h * dydt_$(i))) + $(eps_abs) 104 | # end 105 | r = abs(yerr) / abs(d0) 106 | rmax = max(r, rmax) 107 | # end 108 | end 109 | end 110 | 111 | hadj, inc = hadjust(rmax, h) 112 | if inc >= 0 then break end 113 | h = hadj 114 | end 115 | 116 | # if y_err_only then 117 | local $(VL'dydt') = f(t + h, $(VL'y')) 118 | # for i = 0, N-1 do 119 | s_dydt.data[$(i)] = dydt_$(i) 120 | # end 121 | # end 122 | 123 | # for i = 0, N-1 do 124 | s_y.data[$(i)] = y_$(i) 125 | # end 126 | s.t = t + h 127 | s.h = hadj 128 | end 129 | 130 | return {new= ode_new, init= ode_init, evolve= ode_evolve, step= rkf45_step} 131 | -------------------------------------------------------------------------------- /lgsl-scm-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "LGSL" 2 | version = "scm-3" 3 | source = { 4 | url = "https://github.com/ladc/lgsl/archive/master.zip", 5 | dir = "lgsl-master" 6 | } 7 | description = { 8 | summary = "A numerical library for Lua based on GSL", 9 | detailed = [[ 10 | LGSL is a collection of numerical algorithms and functions for Lua, based on the 11 | GNU Scientific Library (GSL). It allows matrix/vector manipulation and linear 12 | algebra operations. 13 | 14 | LGSL is not just a wrapper over the C API of GSL but offers a much more 15 | simple and expressive way to use GSL. The objective of LGSL is to give 16 | the user the power to easily access GSL functions without having to write 17 | a complete C application. 18 | 19 | LGSL is based on the numerical modules of GSL Shell. 20 | ]], 21 | homepage = "https://github.com/ladc/lgsl", 22 | license = "GPL-3", 23 | maintainer = "Lesley De Cruz " 24 | } 25 | dependencies = { 26 | "lua == 5.1" -- this should be luajit2 27 | } 28 | external_dependencies = { 29 | GSL = { 30 | library = "gsl" 31 | }, 32 | } 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["lgsl.init"] = "lgsl.lua", 37 | -- utilities 38 | ["lgsl.sort"] = "lgsl/sort.lua", 39 | ["lgsl.check"] = "lgsl/check.lua", 40 | ["lgsl.gsl-check"] = "lgsl/gsl-check.lua", 41 | ["lgsl.gsl"] = "lgsl/gsl.lua", 42 | ["lgsl.template"] = "lgsl/template.lua", 43 | -- loaded in lgsl 44 | ["lgsl.matrix"] = "lgsl/matrix.lua", 45 | ["lgsl.complex"] = "lgsl/complex.lua", 46 | ["lgsl.eigen"] = "lgsl/eigen.lua", 47 | ["lgsl.iter"] = "lgsl/iter.lua", 48 | ["lgsl.rng"] = "lgsl/rng.lua", 49 | ["lgsl.rnd"] = "lgsl/rnd.lua", 50 | ["lgsl.randist"] = "lgsl/randist.lua", 51 | ["lgsl.sf"] = "lgsl/sf.lua", 52 | ["lgsl.csv"] = "lgsl/csv.lua", 53 | ["lgsl.bspline"] = "lgsl/bspline.lua", 54 | ["lgsl.fft"] = "lgsl/fft.lua", 55 | ["lgsl.integ"] = "lgsl/integ.lua", 56 | ["lgsl.linfit"] = "lgsl/linfit.lua", 57 | ["lgsl.nlinfit"] = "lgsl/nlinfit.lua", 58 | ["lgsl.ode"] = "lgsl/ode.lua", 59 | ["lgsl.vegas"] = "lgsl/vegas.lua", 60 | ["lgsl.demos"] = "demos/demos.lua", 61 | }, 62 | install = { 63 | lua = { 64 | -- templates 65 | ["lgsl.templates.gauss-kronrod-x-wgs"] = "lgsl/templates/gauss-kronrod-x-wgs.lua.in", 66 | ["lgsl.templates.lmfit"] = "lgsl/templates/lmfit.lua.in", 67 | ["lgsl.templates.ode-defs"] = "lgsl/templates/ode-defs.lua.in", 68 | ["lgsl.templates.qag"] = "lgsl/templates/qag.lua.in", 69 | ["lgsl.templates.qng"] = "lgsl/templates/qng.lua.in", 70 | ["lgsl.templates.rk4"] = "lgsl/templates/rk4.lua.in", 71 | ["lgsl.templates.rk8pd"] = "lgsl/templates/rk8pd.lua.in", 72 | ["lgsl.templates.rkf45"] = "lgsl/templates/rkf45.lua.in", 73 | ["lgsl.templates.rkf45vec"] = "lgsl/templates/rkf45vec.lua.in", 74 | ["lgsl.templates.rnd-defs"] = "lgsl/templates/rnd-defs.lua.in", 75 | ["lgsl.templates.sf-defs"] = "lgsl/templates/sf-defs.lua.in", 76 | ["lgsl.templates.vegas-defs"] = "lgsl/templates/vegas-defs.lua.in", 77 | -- demos 78 | ["lgsl.demos.anim"] = "demos/anim.lua", 79 | ["lgsl.demos.bspline"] = "demos/bspline.lua", 80 | ["lgsl.demos.demos"] = "demos/demos.lua", 81 | ["lgsl.demos.fft"] = "demos/fft.lua", 82 | ["lgsl.demos.fractals"] = "demos/fractals.lua", 83 | ["lgsl.demos.integ"] = "demos/integ.lua", 84 | ["lgsl.demos.linfit"] = "demos/linfit.lua", 85 | ["lgsl.demos.nlinfit"] = "demos/nlinfit.lua", 86 | ["lgsl.demos.ode"] = "demos/ode.lua", 87 | ["lgsl.demos.plot"] = "demos/plot.lua", 88 | ["lgsl.demos.roots"] = "demos/roots.lua", 89 | ["lgsl.demos.sf"] = "demos/sf.lua", 90 | ["lgsl.demos.vegas"] = "demos/vegas.lua", 91 | ["lgsl.demos.wave-particle"] = "demos/wave-particle.lua", 92 | }, 93 | }, 94 | copy_directories = { "tests", "doc" }, 95 | } 96 | -------------------------------------------------------------------------------- /demos/demos.lua: -------------------------------------------------------------------------------- 1 | local demo_list = {} -- demo list per group. demo_list["groupname"] = {demo1, demo2} 2 | local demo_flatlist = {} -- demo flat list. demo_flatlist[i] = "demoname" 3 | local group_flatlist = {} -- group flat list. group_flatlist[i] = "groupname" 4 | 5 | local noop = function() end 6 | 7 | -- Load a demo file using require(name), and store it in the demo_list. 8 | -- Add the demo and group names to their respective flatlists. 9 | local function load_demo_file(name,verbose) 10 | local write = verbose and io.write or noop 11 | write("Load demo ",name,": ") 12 | local record = require(name) 13 | assert(type(record)=="table","Demo must return table: "..name) 14 | local group, info = record[1], record[2] 15 | local section = demo_list[group] 16 | if not section then 17 | section = {} 18 | demo_list[group] = section 19 | group_flatlist[#group_flatlist+1]=group 20 | end 21 | for k, v in ipairs(info) do 22 | v.fname=name 23 | section[#section+1]=v 24 | write(v.name," ") 25 | demo_flatlist[#demo_flatlist+1]=v.name 26 | end 27 | write("\n") 28 | end 29 | 30 | -- List of files that contain demo functions, and that will be required. 31 | local demo_files = { 32 | 'fft', 'bspline', 'wave-particle', 'plot', 'fractals', 33 | 'ode', 'nlinfit', 'integ', 'anim', 'linfit', 34 | 'sf', 'vegas', 35 | } 36 | 37 | local function demolist_string() 38 | return 'demos = {"'..table.concat(demo_flatlist,'","')..'"}\n' 39 | end 40 | 41 | -- Print overview of demos per group. 42 | local function print_demos_list() 43 | for _,group in ipairs(group_flatlist) do 44 | io.write('*** ', group, '\n') 45 | for k, v in ipairs(demo_list[group]) do 46 | print(v.name .. ' (from '..v.fname..') ' .. v.description) 47 | end 48 | print '' 49 | print("***************************************************") 50 | end 51 | print("Type demos.run(\"name\") to execute demos that match \"name\".") 52 | print("For example type demos.run(\"wave\") for wave particle demo.") 53 | print("Type demos.run{\"name1\", \"name2\"} to run multiple demos.") 54 | print '' 55 | print(demolist_string()) 56 | print '' 57 | end 58 | 59 | -- Check if the list contains anything that item matches. 60 | local function listcontains(list,item) 61 | if type(list)=="string" then 62 | return (item:find(list)) 63 | end 64 | for k,v in ipairs(list) do 65 | if item:find(v) then return true end 66 | end 67 | return false 68 | end 69 | 70 | -- Run all demos that match the list of demo names (e.g. anim will match anim1 71 | -- and anim2); verbosely by default. 72 | local function rundemos(dlist, quiet) 73 | local write,flush = io.write,io.flush 74 | if quiet then write,flush = noop,noop end 75 | if not dlist then write(demolist_string()) end 76 | for i, group in ipairs(group_flatlist) do 77 | local categoryshown=false 78 | for j,v in ipairs(demo_list[group]) do 79 | if not dlist or listcontains(dlist,v.name) then 80 | if not categoryshown then 81 | categoryshown=true 82 | write("Category: ",group,"\n") 83 | end 84 | write(string.format(" %s.%s: %s\n",v.fname,v.name,v.description)) 85 | flush() 86 | v.f() 87 | end 88 | end 89 | end 90 | end 91 | 92 | -- local alldemos = {"fft1", "fft2", "fft3", "bspline1", "wave", "gaussian", "fftplot", "vonkoch", "levyc", "pitags", "pitaga", "nlfit1", "nlfit2", "numint", "anim1", "anim2", "anim3", "linfit1", "linfit2", "sf1", "sf2", "vegas", "sphere"} 93 | 94 | if pcall(debug.getlocal, 4, 1) then -- loaded as library 95 | for i, name in ipairs(demo_files) do 96 | load_demo_file("lgsl.demos."..name, false) -- load quietly 97 | end 98 | return {run = rundemos, show = print_demos_list, load = load_demo_file} 99 | else -- run from command line 100 | for i, name in ipairs(demo_files) do 101 | load_demo_file(name, true) 102 | end 103 | if arg[1] then 104 | rundemos(arg) 105 | else 106 | rundemos() 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /doc/integ.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: lua 2 | 3 | Numerical Integration 4 | ===================== 5 | 6 | This chapter describes routines for performing numerical integration 7 | (quadrature) of a function in one dimension. For the integration of functions in multiple dimensions, please see the section on :ref:`monte-carlo`. 8 | LGSL re-implements the the algorithms used in QUADPACK, a numerical integration package written by Piessens, Doncker-Kapenga, Uberhuber and Kahaner. 9 | FORTRAN code for QUADPACK is available on Netlib. 10 | 11 | Currently only two integration methods are available in LGSL. 12 | Both of them are based on Gauss-Kronrod integration rules. 13 | The first method is non-adaptive and is called QNG while the second one, QAG, is adaptive. 14 | The adaptive method QAG is suitable as a general-purpose integrator, whereas the QNG method should be used only in particular cases where the function has a simple known smooth behavior. 15 | 16 | Introduction 17 | ------------ 18 | 19 | Each algorithm computes an approximation to a definite integral of the form, 20 | 21 | .. math:: 22 | I = \int_a^b f(x) \textrm{d}x 23 | 24 | The user provides absolute and relative error bounds (epsabs, epsrel) 25 | which specify the following accuracy requirement, 26 | 27 | .. math:: 28 | | \textrm{Result} - I | \le \max(\epsilon_{\textrm{abs}}, \epsilon_{\textrm{abs}} |I|) 29 | 30 | where Result is the numerical approximation obtained by the 31 | algorithm. The algorithm attempts to estimate the absolute error 32 | AbsErr = | Result - I | in such a way that the following inequality 33 | holds, 34 | 35 | .. math:: 36 | | \textrm{Result} - I | \le \textrm{AbsErr} \le \max(\epsilon_{\textrm{abs}}, \epsilon_{\textrm{rel}} |I|) 37 | 38 | In short, the routines return the first approximation which has an 39 | absolute error smaller than epsabs or a relative error smaller than 40 | epsrel. 41 | 42 | Note that this is an either-or constraint, not simultaneous. To 43 | compute to a specified absolute error, set epsrel to zero. To compute 44 | to a specified relative error, set epsabs to zero. The routines will 45 | fail to converge if the error bounds are too stringent, but always 46 | return the best approximation obtained up to that stage. 47 | 48 | Functions 49 | --------- 50 | 51 | .. module:: integ 52 | 53 | .. function:: integ(f, a, b, epsabs, epsrel) 54 | 55 | Compute the definite integral of the function ``f`` in the interval specified by ``a`` and ``b`` within the requested precision given by ``epsabs`` and ``epsrel``. 56 | This function always uses the adaptive QAG algorithm internally. 57 | 58 | .. function:: prepare(spec) 59 | 60 | Returns a function that can perform a numeric integration based on the options ``spec``. 61 | The argument ``spec`` is used to choose the quadrature algorithm, the order and the limits for the adaptive search if applicable. 62 | The fields of ``spec`` that you should give are: 63 | 64 | *method* 65 | The quadrature algorithm. Available algorithms are ``qng`` and ``qag``, the default is ``qag``. 66 | 67 | *order* 68 | The order of the integration rule. 69 | The default value is 21. 70 | 71 | *limits* 72 | The maximum number of subdivisions for adaptive algorithms. 73 | The default value is 64. 74 | 75 | Usage Example 76 | ------------- 77 | 78 | Here a simple example that shows how to plot the Bessel function using its integral definition: 79 | 80 | .. math:: 81 | J_n(x) = {1 \over \pi} \int_0^\pi \cos(n \tau - x \sin \tau) \textrm{d}\tau 82 | 83 | The function :func:`integ.prepare` is used to prepare the quadrature function. 84 | The function returned is then called many times to obtain :math:`J_n(x)`:: 85 | 86 | integ = require("lgsl.integ") 87 | 88 | epsabs, epsrel = 1e-6, 0.01 89 | 90 | function bessel_gen(n, q) 91 | local xs 92 | local fint = function(t) return math.cos(n*t - xs*math.sin(t)) end 93 | return function(x) 94 | xs = x 95 | return q(fint, 0, math.pi, epsabs, epsrel) / math.pi 96 | end 97 | end 98 | 99 | -- we get the 'qag' integration rule with default options 100 | q = integ.prepare {method= 'qag'} 101 | 102 | J7 = bessel_gen(7, q) 103 | 104 | -- plot the resulting home-brewn Bessel function (requires the graph-toolkit package) 105 | graph = require("graph") 106 | graph.fxplot(J7, 0, 50) 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LGSL: A numerical library for Lua based on GSL 2 | 3 | [![Build Status](https://travis-ci.org/ladc/lgsl.svg?branch=master)](https://travis-ci.org/ladc/lgsl) 4 | 5 | * Copyright (C) 2009-2016 Francesco Abbate, Lesley De Cruz and Benjamin von Ardenne 6 | * Published under GPL-3 7 | 8 | 9 | ## About 10 | 11 | LGSL is a collection of numerical algorithms and functions for Lua, based on 12 | the GNU Scientific Library (GSL). It allows matrix/vector manipulation and 13 | linear algebra operations. 14 | 15 | LGSL is not just a wrapper over the C API of GSL but offers a much more simple 16 | and expressive way to use GSL. The objective of LGSL is to give the user the 17 | power to easily access GSL functions without having to write a complete C 18 | application. 19 | 20 | LGSL is based on the numerical modules of [GSL 21 | Shell](http://www.nongnu.org/gsl-shell/). 22 | 23 | ## Requirements 24 | 25 | * [LuaJIT 2.0.3](http://luajit.org) or higher. 26 | * [GSL 1.14](http://www.gnu.org/software/gsl/) or higher. 27 | * [graph-toolkit](http://github.com/franko/graph-toolkit) is recommended to 28 | create plots, and required to run the demos. 29 | 30 | ## Usage 31 | 32 | See the [LGSL Documentation](http://lgsl.duckdns.org/). 33 | 34 | To see some demos, fire up LuaJIT and type: 35 | 36 | ``` lua 37 | require("lgsl.demos").run() 38 | ``` 39 | 40 | # Installation Instructions 41 | 42 | LGSL is implemented as a set of Lua files and depends on LuaJIT (version 2.0 or 43 | higher) and on the GSL library (version 1.14 or higher). As the implementation 44 | is in Lua, no compilation is needed. 45 | 46 | The recommended way to install and update LGSL is with LuaRocks. To install the 47 | latest development version, run: 48 | 49 | ``` 50 | luarocks install --server=http://luarocks.org/dev lgsl 51 | ``` 52 | 53 | The standard method to install LGSL without LuaRocks is to type `make install` 54 | from the source directory. The command will install all the required files in 55 | a system-wide directory in the package search path of Lua and requires sudo 56 | privileges. Before installing you may change the `PREFIX` directory in 57 | `Makefile` or with `make install PREFIX=/path/to/install`. 58 | 59 | On Debian-based systems like Ubuntu or Debian itself, the package can be 60 | installed from a Debian package. The .deb package can be downloaded here: 61 | 62 | [luajit-lgsl deb for all architectures](http://lgsl.duckdns.org/deb/luajit-lgsl_0.1-1_all.deb) 63 | 64 | 65 | The command `make debian` or simply `make` will build a Debian package in the 66 | source code directory. Once the package is created, it can be installed with 67 | sudo privileges using the command: 68 | 69 | ``` 70 | sudo dpkg -i name-of-debian-package 71 | ``` 72 | 73 | ## Dependencies 74 | 75 | LGSL currently requires LuaJIT 2.0 or later to run. It is recommended to 76 | install the latest version of LuaJIT. Installation instructions for LuaJIT can 77 | be found on the [LuaJIT website](http://luajit.org/install.html). 78 | 79 | The short version (on POSIX systems): 80 | 81 | ``` 82 | git clone http://luajit.org/git/luajit-2.0.git 83 | cd luajit-2.0 84 | make && sudo make install 85 | ``` 86 | 87 | On most Linux distributions, the GSL library can be installed through your 88 | system package manager. 89 | 90 | On Debian and derived distributions such as Ubuntu: 91 | ``` 92 | sudo apt-get install libgsl0ldbl 93 | ``` 94 | 95 | On Red Hat and family, e.g. CentOS: 96 | ``` 97 | sudo yum install gsl.x86_64 98 | ``` 99 | 100 | On Arch Linux: 101 | ``` 102 | sudo pacman -S gsl 103 | ``` 104 | 105 | Other installation options can be found on the [GSL 106 | website](http://www.gnu.org/software/gsl/). 107 | 108 | ## Recommended Packages 109 | 110 | If you want to create plots or run the demos, you are advised to install the 111 | Lua Graphics Toolkit: 112 | 113 | ``` 114 | luarocks install --server=http://luarocks.org/dev graph-toolkit 115 | ``` 116 | 117 | More information can be found at graph-toolkit's [GitHub 118 | page](https://github.com/franko/graph-toolkit) and the 119 | [documentation](http://franko.github.io/graph-toolkit). 120 | 121 | ## Manual Installation 122 | 123 | To manually install the package, the `lgsl` directory should be copied into a 124 | directory included in the standard Lua search path such as `/usr/share/lua/5.1/`. 125 | The files included in `lgsl/templates` should be included as well by copying them 126 | in a subdirectory named `templates`. 127 | 128 | -------------------------------------------------------------------------------- /doc/bsplines.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: lua 2 | 3 | 4 | Basis Splines 5 | ============= 6 | 7 | Overview 8 | -------- 9 | 10 | B-splines are commonly used as basis functions to fit smoothing curves 11 | to large data sets. To do this, the abscissa axis is broken up into 12 | some number of intervals, where the endpoints of each interval are 13 | called "breakpoints". These breakpoints are then converted to "knots" 14 | by imposing various continuity and smoothness conditions at each 15 | interface. Given a nondecreasing knot vector t = {t\ :sub:`0`, t\ :sub:`1`, ..., 16 | t\ :sub:`n+k-1`}, the n basis splines of order k are defined by 17 | 18 | .. math:: 19 | 20 | \begin{array}{ll} 21 | B_{i,1}(x) = & \left\{ \begin{array}{rl} 22 | 1 & \qquad t_i \le x < t_{i+1} \\ 23 | 0 & \qquad \textrm{else} 24 | \end{array} \right. \\ 25 | B_{i,k}(x) = & \dfrac{x - t_i}{t_{i+k-1} - t_i} B_{i,k-1}(x) 26 | + \dfrac{t_{i+k} - x}{t_{i+k} - t_{i+1}} B_{i+1,k-1}(x) 27 | \end{array} 28 | 29 | for i = 0, ..., n-1. The common case of cubic B-splines is given by k = 30 | 4. The above recurrence relation can be evaluated in a numerically 31 | stable way by the de Boor algorithm. 32 | 33 | If we define appropriate knots on an interval [a,b] then the B-spline basis functions form a complete set on that interval. Therefore we can expand a smoothing function as 34 | 35 | .. math:: 36 | 37 | f(x) = \sum_i c_i B_{i,k}(x) 38 | 39 | given enough :math:`(x_j, f(x_j))` data pairs. The coefficients c\ :sub:`i` can be readily obtained from a least-squares fit. 40 | 41 | B-Splines functions 42 | ------------------- 43 | 44 | .. function:: bspline(a, b, N[, order]) 45 | bspline(knots[, order]) 46 | 47 | Create an object of type :class:`BSpline`. In the first form it will create a basis splines in the interval from ``a`` to ``b`` with ``N`` uniformly spaced breaks. The ``order`` is 4 if unspecified, it corresponds to cubic splines. In the second form you should provide a non-decreasing list ``knots`` with all the points. 48 | 49 | .. class:: BSpline 50 | 51 | This is the class use to calculate the Basis Splines. 52 | 53 | .. method:: eval(x) 54 | 55 | Return a column matrix with ``nbreak + order - 2`` elements that stores the value of all the B-spline basis functions at the position ``x``. 56 | 57 | .. method:: model(x) 58 | 59 | Takes a column matrix of dimension N and returns a matrix of M columns and N rows where M = nbreak + order - 1. The matrix will contain, for each column, the value of the corresponding basis function evaluated in all the N position given by ``x``. 60 | 61 | .. module:: bspline 62 | 63 | B-splines Example 64 | ------------------ 65 | 66 | The following example computes a linear least squares fit to data using cubic B-spline basis functions with uniform breakpoints. The data is generated from the curve :math:`y(x) = \cos(x) \exp(-x/10)` on the interval [0,15] with Gaussian noise added:: 67 | 68 | matrix = require("lgsl.matrix") 69 | bspline = require("lgsl.bspline") 70 | rng = require("lgsl.rng") 71 | rnd = require("lgsl.rnd") 72 | linfit = require("lgsl.linfit") 73 | 74 | -- number of points and breakpoints 75 | n, br = 200, 10 76 | 77 | f = function(x) return math.cos(x) * math.exp(-0.1 * x) end 78 | xsmp = function(i) return 15 * (i-1) / (n-1) end 79 | 80 | -- we calculate the simulated data 81 | x, y = matrix.new(n, 1, xsmp), matrix.new(n, 1, function(i) return f(xsmp(i)) end) 82 | 83 | -- we add a Gaussian noise and calculate weights 84 | r = rng.new() 85 | w = matrix.new(n, 1) 86 | for i=1,n do 87 | local sigma = 0.1 * y[i] 88 | y:set(i,1, y[i] + rnd.gaussian(r, sigma)) 89 | w:set(i,1, 1/sigma^2) 90 | end 91 | 92 | -- we create a bspline object and we calculate the model matrix X 93 | b = bspline(0, 15, br) 94 | X = b:model(x) 95 | 96 | -- linear least-squares fit 97 | c, cov = linfit(X, y, w) 98 | 99 | -- plot; requires graph-toolkit. 100 | graph = require("graph") 101 | 102 | p = graph.plot('B-splines curve approximation') 103 | p:addline(graph.xyline(x, X * c)) 104 | p:addline(graph.xyline(x, y), 'blue', {{'marker', size=5}}) 105 | p:show() 106 | 107 | And the resulting plot is: 108 | 109 | .. figure:: example-bsplines-plot.png 110 | -------------------------------------------------------------------------------- /tests/test_airy.expect: -------------------------------------------------------------------------------- 1 | Pass airyAi(-500.0) : 7.259012010404114e-02 2 | Pass airyAi(-5.0) : 3.507610090241142e-01 3 | Pass airyAi(-0.3000000000000094) : 4.309030952855831e-01 4 | Pass airyAi(0.6999999999999907) : 1.891624003981519e-01 5 | Pass airyAi(1.649999999999991) : 5.831058618720885e-02 6 | Pass airyAi(2.54999999999999) : 1.446149513295428e-02 7 | Pass airyAi(3.499999999999987) : 2.584098786989702e-03 8 | Pass airyAi(5.39999999999998) : 4.272986169411866e-05 9 | Pass airyAi_scaled(-5.0) : 3.507610090241142e-01 10 | Pass airyAi_scaled(0.6999999999999907): 2.795125667681217e-01 11 | Pass airyAi_scaled(1.649999999999991): 2.395493001442741e-01 12 | Pass airyAi_scaled(2.54999999999999): 2.183658595899388e-01 13 | Pass airyAi_scaled(3.499999999999987): 2.032920808163519e-01 14 | Pass airyAi_scaled(5.39999999999998): 1.836050093282229e-01 15 | Pass airyBi(-500.0) : -9.468857013299103e-02 16 | Pass airyBi(-5.0) : -1.383691349016005e-01 17 | Pass airyBi(0.6999999999999907) : 9.733286558781599e-01 18 | Pass airyBi(1.649999999999991) : 2.196407956850028e+00 19 | Pass airyBi(2.54999999999999) : 6.973628612493443e+00 20 | Pass airyBi(3.499999999999987) : 3.305550675461069e+01 21 | Pass airyBi(5.39999999999998) : 1.604476078241272e+03 22 | Pass airyBi_scaled(-5.0) : -1.383691349016005e-01 23 | Pass airyBi_scaled(0.6999999999999907): 6.587080754582302e-01 24 | Pass airyBi_scaled(1.649999999999991): 5.346449995597539e-01 25 | Pass airyBi_scaled(2.54999999999999): 4.618354555422970e-01 26 | Pass airyBi_scaled(3.499999999999987): 4.201771882353061e-01 27 | Pass airyBi_scaled(5.39999999999998): 3.734050675720473e-01 28 | Pass airyAi_deriv(-5.0) : 3.271928185544435e-01 29 | Pass airyAi_deriv(-0.5500000000000094): -1.914604987143629e-01 30 | Pass airyAi_deriv(0.4999999999999906): -2.249105326646850e-01 31 | Pass airyAi_deriv(1.899999999999992): -6.043678178575718e-02 32 | Pass airyAi_deriv(3.249999999999988): -7.792687926790889e-03 33 | Pass airyAi_deriv(5.199999999999981): -1.589434526459543e-04 34 | Pass airyAi_deriv_scaled(-5.0) : 3.271928185544435e-01 35 | Pass airyAi_deriv_scaled(0.5499999999999906): -2.874057279170166e-01 36 | Pass airyAi_deriv_scaled(1.499999999999991): -3.314199796863637e-01 37 | Pass airyAi_deriv_scaled(2.49999999999999): -3.661089384751620e-01 38 | Pass airyAi_deriv_scaled(3.649999999999986): -3.974033831453963e-01 39 | Pass airyAi_deriv_scaled(6.299999999999977): -4.508799189585947e-01 40 | Pass airyBi_deriv(-5.0) : 7.784117730018990e-01 41 | Pass airyBi_deriv(-0.5500000000000094): 5.155785358765014e-01 42 | Pass airyBi_deriv(0.4999999999999906): 5.445725641405883e-01 43 | Pass airyBi_deriv(1.899999999999992): 3.495165862891568e+00 44 | Pass airyBi_deriv(3.249999999999988): 3.655485149250338e+01 45 | Pass airyBi_deriv(5.199999999999981): 2.279748293583233e+03 46 | Pass airyBi_deriv_scaled(-5.0) : 7.784117730018990e-01 47 | Pass airyBi_deriv_scaled(0.5499999999999906): 4.322811281817566e-01 48 | Pass airyBi_deriv_scaled(1.499999999999991): 5.542307563918037e-01 49 | Pass airyBi_deriv_scaled(2.49999999999999): 6.755384441644985e-01 50 | Pass airyBi_deriv_scaled(3.649999999999986): 7.613959373000228e-01 51 | Pass airyBi_deriv_scaled(6.299999999999977): 8.852064139737571e-01 52 | Pass airyAi_zero(2) : -4.087949444130970e+00 53 | Pass airyAi_zero(50) : -3.802100867725525e+01 54 | Pass airyAi_zero(100) : -6.045555727411670e+01 55 | Pass airyAi_zero(110) : -6.443135670991325e+01 56 | Pass airyBi_zero(2) : -3.271093302836353e+00 57 | Pass airyBi_zero(50) : -3.776583438165180e+01 58 | Pass airyBi_zero(100) : -6.025336482580837e+01 59 | Pass airyBi_zero(110) : -6.423551676065615e+01 60 | Pass airyBi_zero(111) : -6.462689948195194e+01 61 | Pass airyBi_zero(200) : -9.588699147356682e+01 62 | Pass airyAi_deriv_zero(2) : -3.248197582179837e+00 63 | Pass airyAi_deriv_zero(50) : -3.776565910053887e+01 64 | Pass airyAi_deriv_zero(100) : -6.025329596442479e+01 65 | Pass airyAi_deriv_zero(110) : -6.423545617243546e+01 66 | Pass airyAi_deriv_zero(1000) : -2.809378080358935e+02 67 | Pass airyBi_deriv_zero(2) : -4.073155089071828e+00 68 | Pass airyBi_deriv_zero(50) : -3.802083574095789e+01 69 | Pass airyBi_deriv_zero(100) : -6.045548887257141e+01 70 | Pass airyBi_deriv_zero(110) : -6.443129648944846e+01 71 | Pass airyBi_deriv_zero(111) : -6.482208737584206e+01 72 | Pass airyBi_deriv_zero(200) : -9.604731050310325e+01 73 | Pass airyBi_deriv_zero(1000) : -2.810315164471119e+02 74 | -------------------------------------------------------------------------------- /doc/gsl-ffi.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: lua 2 | 3 | .. _gsl-ffi-interface: 4 | 5 | GSL FFI interface 6 | ================= 7 | 8 | In this chapter we are going to explain the direct GSL interface to use the C functions provided by the GSL library directly. 9 | 10 | Introduction 11 | ~~~~~~~~~~~~ 12 | 13 | The access to the C GSL functions is possible thanks to the FFI library provided by LuaJIT. 14 | The FFI module allows one to call any C function available from the dynamic libraries currently loaded, directly from Lua code. 15 | 16 | Some of the modules available in LGSL are reimplemented in Lua using the FFI interface and the basic GSL functions for BLAS and linear algebra. 17 | 18 | For example, the module for non-linear fitting has been completely reimplemented in Lua using the FFI interface. 19 | Thanks to the capability of LuaJIT to generate highly optimized code on the fly, the Lua implementation runs at a speed comparable to compiled optimized C code. 20 | For the ODE systems LuaJIT is in general comparable to C in terms of speed. 21 | Another module re-implemented in Lua is the module for numerical integration, where the QAG adaptive routine has been ported with excellent results. 22 | 23 | The non-linear fit module reimplemented in Lua has been checked for correctness using a subset of the `NIST datasets `_. 24 | 25 | You can run the tests yourself by giving the following command. 26 | 27 | .. todo:: 28 | Add NIST tests; add comparison between C and LGSL versions of VEGAS and root finders. 29 | 30 | Then you can compare the results and the plots to the official results published in the NIST website. 31 | 32 | Here is an example of the plot produced for the ENSO dataset: 33 | 34 | .. figure:: lmfit-enso-dataset-plot.png 35 | 36 | GSL FFI interface 37 | ~~~~~~~~~~~~~~~~~ 38 | 39 | .. module:: gsl 40 | 41 | The usage of the GSL FFI interface is done using the :mod:`gsl` module. 42 | This module contains all the GSL functions available and you can call them directly from Lua code. 43 | Because direct usage of the GSL functions is considered "expert mode", the :mod:`gsl` module is not loaded by default when requiring the parent module :mod:`lgsl`. 44 | 45 | Let us see a simple example:: 46 | 47 | -- we load the gsl module 48 | gsl = require("lgsl.gsl") 49 | matrix = require("lgsl.matrix") 50 | 51 | -- we define a new matrix 52 | m = matrix.new(4, 4) 53 | 54 | for i = 0, 3 do 55 | for j = 0, 3 do 56 | gsl.gsl_matrix_set(m, i, j, 1/(i+j+1)) 57 | end 58 | end 59 | 60 | As you can see we are just using the GSL function :func:`gsl_matrix_set` to set the value each of element of the matrix. 61 | 62 | There are a few things that are important to note. 63 | The C function that we have used has the following signature ``void gsl_matrix_set(gsl_matrix *m, int i, int j, double x)``. 64 | When you call it from Lua, the arguments are converted to the appropriate C types using a set of rules specific to the `FFI semantics `_. 65 | The implementation of LGSL ensures that a matrix object can actually be converted to a ``gsl_matrix`` pointer. 66 | As for the other arguments, note that the Lua numbers are converted to integer or double as appropriate to match the C function signature. 67 | If the arguments cannot be converted to the appropriate type, an error is raised. 68 | 69 | Another thing that you may note is that we have ignored the value returned by the GSL function. 70 | In general, the return value can signal an error condition and it could be necessary to check the returned value. 71 | For this purpose, LGSL offers a simple helper function in :mod:`gsl-check`. We illustrate its usage by continuing upon the previous example:: 72 | 73 | gsl_check = require("lgsl.gsl-check") 74 | 75 | gsl_check(gsl.gsl_matrix_add(m,m)) -- this should pass 76 | gsl_check(gsl.gsl_matrix_add(m,matrix.new(2,2))) -- this should raise an error 77 | 78 | The function :func:`gsl_check` above just checks the returned value of the :func:`gsl.gsl_matrix_add` call and raises an error with an appropriate message if needed. In the second call in the example above, it will generate the error: ``"ERROR: matrices must have same dimensions"``. 79 | 80 | Finally note that the indexing convention when calling :func:`gsl.gsl_matrix_set` is the C convention where the first index is 0. 81 | This fact is a direct implication of the fact that we are directly calling the C function defined in the GSL library. 82 | 83 | GSL FFI examples 84 | ~~~~~~~~~~~~~~~~ 85 | 86 | If you want to learn more about the usage of the GSL FFI interface, you may take a look at the implementation file of the :mod:`bspline` module. 87 | 88 | The file is quite small and easy to understand, and it illustrates all the important aspects of the GSL FFI interface. 89 | -------------------------------------------------------------------------------- /demos/roots.lua: -------------------------------------------------------------------------------- 1 | 2 | local rng=require("lgsl.rng") 3 | local abs, max, min = math.abs, math.max, math.min 4 | 5 | local function is_between(x, a, b) 6 | if b < a then a, b = b, a end 7 | return (x > a and x < b) 8 | end 9 | 10 | -- BRENT algorithm 11 | local function brent(f, a, fa, b, fb, eps, del) 12 | 13 | if abs(fa) < abs(fb) then 14 | a, b = b, a 15 | fa, fb = fb, fa 16 | end 17 | 18 | local mflag = true 19 | local c, fc = a, fa 20 | local d 21 | 22 | local s, fs = b, fb 23 | 24 | while abs(fs) >= eps and abs(b-a) > del do 25 | if fa ~= fc and fb ~= fc then 26 | s = a*fb*fc/((fa-fb)*(fa-fc)) + b*fa*fc/((fb-fa)*(fb-fc)) + c*fa*fb/((fc-fa)*(fc-fb)) 27 | else 28 | s = b - fb*(b-a)/(fb-fa) 29 | end 30 | 31 | if not is_between(s, (3*a+b)/4, b) 32 | or ( mflag and abs(s-b) >= abs(b-c)/2) 33 | or (not mflag and abs(s-b) >= abs(c-d)/2) 34 | or ( mflag and abs(b-c) < del) 35 | or (not mflag and abs(c-d) < del) then 36 | s = (a+b)/2 37 | mflag = true 38 | else 39 | mflag = false 40 | end 41 | fs = f(s) 42 | d = c 43 | c, fc = b, fb 44 | if fa * fs < 0 then b, fb = s, fs else a, fa = s, fs end 45 | 46 | if abs(fa) < abs(fb) then 47 | a, b = b, a 48 | fa, fb = fb, fa 49 | end 50 | end 51 | 52 | return s 53 | end 54 | 55 | local function segment_root_brent(f, a, b, eps, del) 56 | local fa, fb = f(a), f(b) 57 | return brent(f, a, fa, b, fb, eps, del) 58 | end 59 | 60 | local function lagrange_quad_est(x0, f0, x1, f1, x2, f2) 61 | local dx01, dx12, dx20 = x0 - x1, x1 - x2, x2 - x0 62 | local a0 = - f0 / (dx01 * dx20) 63 | local a1 = - f1 / (dx01 * dx12) 64 | local a2 = - f2 / (dx20 * dx12) 65 | return a0, a1, a2 66 | end 67 | 68 | local function lagrange_quad_eval(a0, a1, a2, x0, x1, x2, x) 69 | return a0 * (x-x1)*(x-x2) + a1 * (x-x0)*(x-x2) + a2 * (x-x0)*(x-x1) 70 | end 71 | 72 | local function solver_add_root(s, x) 73 | local rs = s.roots 74 | rs[#rs+1] = x 75 | end 76 | 77 | local function solver_get_random(s) 78 | return s.rng:get() 79 | end 80 | 81 | local function root_locate (s, xa, fa, xb, fb) 82 | if fa * fb < 0 then 83 | local f = s.f 84 | local eps, del = s.eps, s.del 85 | if s.scale_f then eps = eps * s.scale_f((xa+xb)/2) end 86 | local x = brent(f, xa, fa, xb, fb, eps, del) 87 | solver_add_root(s, x) 88 | end 89 | end 90 | 91 | local function f_quad_min (a0, a1, a2, x0, x1, x2) 92 | local a = 2*(a0+a1+a2) 93 | if a ~= 0 then 94 | return (a0*(x1+x2) + a1*(x0+x2) + a2*(x0+x1)) / a 95 | end 96 | end 97 | 98 | local function f_approx_test(s, fabsm, a0, a1, a2, x0, xm, x1) 99 | for i=1, 8 do 100 | local r = solver_get_random(s) 101 | local x = x0 + r * (x1 - x0) 102 | local fx = s.f(x) 103 | local fe = lagrange_quad_eval(a0, a1, a2, x0, xm, x1, x) 104 | if abs(fx - fe) > 0.01 * fabsm then return false end 105 | end 106 | return true 107 | end 108 | 109 | local function interval_roots (s, x0, f0, x1, f1) 110 | local f = s.f 111 | local xm = (x0+x1)/2 112 | local fm = f(xm) 113 | local a0, a1, a2 = lagrange_quad_est(x0, f0, xm, fm, x1, f1) 114 | 115 | local fabsm = max(abs(f0), abs(f1), abs(fm)) 116 | 117 | if f_approx_test(s, fabsm, a0, a1, a2, x0, xm, x1) then 118 | local xi, fi 119 | local xmin = f_quad_min (a0, a1, a2, x0, xm, x1) 120 | if xmin and xmin < x1 and xmin > x0 then 121 | xi, fi = xmin, f(xmin) 122 | else 123 | xi, fi = xm, fm 124 | end 125 | 126 | if f0 == 0 then solver_add_root(s, x0) end 127 | if fi == 0 then solver_add_root(s, xi) end 128 | 129 | if f0 ~= 0 and fi ~= 0 then 130 | root_locate(s, x0, f0, xi, fi) 131 | end 132 | 133 | if fi ~= 0 and f1 ~= 0 then 134 | root_locate(s, xi, fi, x1, f1) 135 | end 136 | else 137 | interval_roots (s, x0, f0, xm, fm) 138 | interval_roots (s, xm, fm, x1, f1) 139 | end 140 | end 141 | 142 | local function solver_tolerance(s, eps, del) 143 | s.eps = eps 144 | s.del = del 145 | end 146 | 147 | local function solver_root(s, x0, x1) 148 | local f = s.f 149 | return brent(f, x0, f(x0), x1, f(x1), s.eps, s.del) 150 | end 151 | 152 | local function solver_interval_solve(s, x0, x1, roots) 153 | local f = s.f 154 | s.roots = roots or {} 155 | s.rng = s.rng or rng.new() 156 | interval_roots(s, x0, f(x0), x1, f(x1)) 157 | if f(x1) == 0 then solver_add_root(s, x1) end 158 | return s.roots 159 | end 160 | 161 | local function root_solver_new (f, eps, del, scale_f) 162 | return {f= f, eps= eps, del= del, 163 | scale_f = scale_f, 164 | tolerance = solver_tolerance, 165 | root = solver_root, 166 | solve = solver_interval_solve 167 | } 168 | end 169 | 170 | return {solver = root_solver_new} 171 | -------------------------------------------------------------------------------- /demos/fractals.lua: -------------------------------------------------------------------------------- 1 | local graph = require("graph") 2 | local iter = require("lgsl.iter") 3 | local matrix = require("lgsl.matrix") 4 | local complex = require("lgsl.complex") 5 | local pi,sqrt,sin,cos,atan2 = math.pi, math.sqrt,math.sin, math.cos, math.atan2 6 | local ilist = iter.ilist 7 | local plot, ipath, path, rgb, rgba, rect, color_function = 8 | graph.plot, graph.ipath, graph.path, graph.rgb, graph.rgba, graph.rect, graph.color_function 9 | 10 | local function c_generator(n, n_angle, len_frac, g) 11 | local exp, real, imag = complex.exp, complex.real, complex.imag 12 | local w, r, k = ilist(function() return 0 end, n+1), #g 13 | 14 | local s = len_frac^n 15 | local sz = matrix.cnew(n_angle, 1, function(k) return s * exp(2i*pi*(k-1)/n_angle) end) 16 | 17 | local sh = ilist(function(k) return g[(k-1)%r+1] - g[(k-2)%r+1] end, r) 18 | local a = (g[1]*n) % n_angle 19 | 20 | local z = 0 21 | return function() 22 | if w[n+1] == 0 then 23 | local j 24 | z = z + sz[a+1] 25 | for j=1,n+1 do 26 | w[j] = (w[j] + 1) % r 27 | a = (a + sh[w[j]+1]) % n_angle 28 | if w[j] ~= 0 then 29 | break 30 | end 31 | end 32 | return real(z), imag(z) 33 | end 34 | end 35 | end 36 | 37 | local function levyc(n) 38 | local p = plot('Levy\'s C curve') 39 | local c = ipath(c_generator(n, 4, 1/2, {-1,0,0,1})) 40 | p:addline(c, 'red', {}, {{'rotate', angle= -pi/4}}) 41 | p:addline(c, 'red', {}, {{'translate', x=1/sqrt(2), y=-1/sqrt(2)},{'rotate', angle= pi/4}}) 42 | p.units = false 43 | p:show() 44 | return p 45 | end 46 | 47 | local function von_koch_demo() 48 | local pl = plot() 49 | 50 | local t = path() 51 | t:move_to(0,0) 52 | t:line_to(1,0) 53 | t:line_to(0.5,-sqrt(3)/2) 54 | t:close() 55 | 56 | local v = ipath(c_generator(4, 6, 1/3, {0,1,-1,0})) 57 | local c = rgba(0,0,180,50) 58 | pl:add(v, c) 59 | pl:add(v, c, {}, {{'translate', x=1, y=0}, {'rotate', angle=-2*pi/3}}) 60 | pl:add(v, c, {}, {{'translate', x=0.5, y=-sqrt(3)/2}, 61 | {'rotate', angle=-2*2*pi/3}}) 62 | pl:add(t, c) 63 | 64 | c = rgb(0,0,180) 65 | 66 | pl:addline(v, c) 67 | pl:addline(v, c, {}, {{'translate', x=1, y=0}, {'rotate', angle=-2*pi/3}}) 68 | pl:addline(v, c, {}, {{'translate', x=0.5, y=-sqrt(3)/2}, 69 | {'rotate', angle=-2*2*pi/3}}) 70 | 71 | pl.units = false 72 | pl:show() 73 | end 74 | 75 | local levy_curve_demo = function(n) return levyc(n and n or 6) end 76 | 77 | local function pitag_tree_symm_demo() 78 | local rdsd = sqrt(2)/2 79 | local ubox = rect(0, 0, 1, 1) 80 | local cf 81 | 82 | local function pitag_tree(pl, x, y, th, ll, depth) 83 | local col = cf(depth) 84 | pl:add(ubox, col, {}, {{'translate', x= x, y= y}, 85 | {'rotate', angle= th}, 86 | {'scale', ll}}) 87 | if depth > 0 then 88 | x, y = x - ll*sin(th), y + ll*cos(th) 89 | pitag_tree(pl, x, y, th + pi/4, ll*rdsd, depth-1) 90 | x, y = x + ll*rdsd*cos(th+pi/4), y + ll*rdsd*sin(th+pi/4) 91 | pitag_tree(pl, x, y, th - pi/4, ll*rdsd, depth-1) 92 | end 93 | end 94 | 95 | local depth = 12 96 | local cfgen = color_function('darkgreen', 255) 97 | cf = function(d) return cfgen(1-d/depth) end 98 | local pl = plot() 99 | pl.units = false 100 | pitag_tree(pl, 0, 0, 0, 1, depth) 101 | pl:show() 102 | end 103 | 104 | local function pitag_tree_demo(n) 105 | local ubox = rect(0, 0, 1, 1) 106 | n = n and n or 10 107 | local col, coln 108 | 109 | local function pitag_tree(pl, x, y, th, ll, depth) 110 | if depth == 0 then 111 | local tr = {{'translate', x= x, y= y}, {'rotate', angle= th}, 112 | {'scale', ll}} 113 | pl:add(ubox, col, {}, tr) 114 | pl:add(ubox, coln, {{'stroke', width= 2.5*ll}}, tr) 115 | end 116 | if depth > 0 then 117 | x, y = x - ll*sin(th), y + ll*cos(th) 118 | local a1 = th + atan2(12,16) 119 | pitag_tree(pl, x, y, a1, ll*4/5, depth-1) 120 | x, y = x + ll*4/5*cos(a1), y + ll*4/5*sin(a1) 121 | pitag_tree(pl, x, y, th + atan2(-12,9), ll*3/5, depth-1) 122 | end 123 | end 124 | 125 | local cfgen = color_function('darkgreen', 255) 126 | 127 | local pl = plot() 128 | pl.sync = false 129 | pl.clip = false 130 | pl:show() 131 | 132 | for k=0, n do 133 | col, coln = cfgen(k/n), cfgen((k+1)/n) 134 | pitag_tree(pl, 0, 0, 0, 1, k) 135 | pl:flush() 136 | end 137 | end 138 | 139 | return {'Fractals', { 140 | { 141 | name = 'vonkoch', 142 | f = von_koch_demo, 143 | description = 'Von Koch\'s curve', 144 | }, 145 | { 146 | name = 'levyc', 147 | f = levy_curve_demo, 148 | description = 'Levy\'s C curve', 149 | }, 150 | { 151 | name = 'pitags', 152 | f = pitag_tree_symm_demo, 153 | description = 'Pythagorean Tree (symmetric)', 154 | }, 155 | { 156 | name = 'pitaga', 157 | f = pitag_tree_demo, 158 | description = 'Pythagorean Tree (asymmetric)', 159 | }, 160 | }} 161 | -------------------------------------------------------------------------------- /lgsl/vegas.lua: -------------------------------------------------------------------------------- 1 | -- vegas.lua 2 | -- 3 | -- Create a function that can perform a VEGAS Monte Carlo multidimensional 4 | -- numerical integration. 5 | -- 6 | -- Copyright (C) 2009-2015 Lesley De Cruz & Francesco Abbate 7 | -- 8 | -- This program is free software; you can redistribute it and/or modify 9 | -- it under the terms of the GNU General Public License as published by 10 | -- the Free Software Foundation; either version 3 of the License, or (at 11 | -- your option) any later version. 12 | -- 13 | -- This program is distributed in the hope that it will be useful, but 14 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 15 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | -- General Public License for more details. 17 | -- 18 | -- You should have received a copy of the GNU General Public License 19 | -- along with this program; if not, write to the Free Software 20 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 | 22 | 23 | local ffi = require("ffi") 24 | local template = require("lgsl.template") 25 | 26 | local abs = math.abs 27 | 28 | local default_spec = { 29 | K = 50, -- max bins: even integer, will be divided by two 30 | SIZE_OF_INT = ffi.sizeof('int'), 31 | SIZE_OF_DOUBLE = ffi.sizeof('double'), 32 | MODE_IMPORTANCE = 1, 33 | MODE_IMPORTANCE_ONLY = 2, 34 | MODE_STRATIFIED = 3, 35 | ALPHA = 1.5, 36 | MODE = 1, 37 | ITERATIONS = 5, 38 | } 39 | 40 | local function getintegrator(state,template_spec) 41 | --- perform VEGAS Monte Carlo integration of f 42 | -- @param f function of an N-dimensional vector (/table/ffi-array...) 43 | -- @param a lower bound vector (1-based indexing) 44 | -- @param b upper bound vector (1-based indexing) 45 | -- @param calls number of function calls (will be rounded down to fit grid) 46 | -- @param options table of parameters (optional), of which: 47 | -- r random number generator (default random) 48 | -- chidev deviation tolerance for the integrals' chi^2 value 49 | -- integration will be repeated until chi^2 < chidev 50 | -- warmup number of calls for warmup phase (default 1e4) 51 | return function(f,a,b,calls,options) 52 | local r = options and options.r 53 | local rget = r and (function() return r:get() end) or math.random 54 | local chidev = options and options.chidev or 0.5 55 | local N = template_spec.N 56 | calls = calls or 1e4*N 57 | local a_work = a 58 | if type(a)=="table" then 59 | a_work = ffi.new("double[?]",N+1) 60 | for i=1,N do a_work[i] = a[i] end 61 | end 62 | state.init(a_work, b) -- initialise 63 | state.clear_stage1() -- clear results 64 | state.rebin_stage2(options and options.warmup or 1e4) -- intialise grid 65 | state.integrate(f,a_work,rget) -- warmup 66 | local result_state = {} 67 | -- full integration: 68 | local function cont(c) 69 | calls = c or calls 70 | result_state.nruns = 0 71 | repeat 72 | -- forget previous results, but not the grid 73 | state.clear_stage1() 74 | -- rebin grid for (modified) number of calls 75 | state.rebin_stage2(calls/template_spec.ITERATIONS) 76 | result_state.result,result_state.sigma = state.integrate(f,a_work,rget) 77 | result_state.nruns = result_state.nruns+1 78 | until abs(state.chisq() - 1) < chidev 79 | return result_state 80 | end 81 | result_state.continue = cont 82 | cont(calls) 83 | return result_state 84 | end 85 | end 86 | 87 | --- prepare a VEGAS Monte Carlo integrator 88 | -- @param spec Table with variables that are passed to the template: 89 | -- N number of dimensions of the function 90 | -- e.g. useful if a,b are ffi arrays 91 | -- (Don't change the following variables unless you know what you're doing:) 92 | -- K max. number of bins, even integer (will be divided by two) 93 | -- ALPHA grid flexibility 94 | -- MODE 1: importance, 2: importance only, 3: stratified 95 | -- ITERATIONS number of integrations used for consistency check; 96 | -- each integration uses (calls/iterations) function calls 97 | -- @return vegas_integ integrator 98 | local function vegas_prepare(spec) 99 | -- read template specs 100 | local template_spec = {N = spec.N} 101 | for k,v in pairs(default_spec) do 102 | template_spec[k] = spec[k] or v 103 | end 104 | -- initialise vegas states 105 | local state = template.load('lgsl.templates.vegas-defs', template_spec) 106 | return getintegrator(state,template_spec) 107 | end 108 | 109 | --- perform VEGAS Monte Carlo integration of f with default specs; determine N 110 | -- from bound vector. 111 | -- @param f function of an N-dimensional vector (/table/ffi-array...) 112 | -- @param a lower bound vector (1-based indexing) 113 | -- @param b upper bound vector (1-based indexing) 114 | -- @param calls number of function calls (will be rounded down to fit grid) 115 | -- @param options table of parameters (optional), of which: 116 | -- r random number generator (default random) 117 | -- chidev deviation tolerance for the integrals' chi^2 value 118 | -- integration will be repeated until chi^2 < chidev 119 | -- warmup number of calls for warmup phase (default 1e4) 120 | local function vegas_integ(f,a,b,calls,options) 121 | local integrator = vegas_prepare({N=#a}) 122 | return integrator(f,a,b,calls,options) 123 | end 124 | 125 | return { 126 | prepare = vegas_prepare, 127 | integ = vegas_integ, 128 | } 129 | -------------------------------------------------------------------------------- /lgsl/templates/rkf45vec.lua.in: -------------------------------------------------------------------------------- 1 | 2 | local abs, max, min = math.abs, math.max, math.min 3 | 4 | # order = 5 5 | 6 | # ah = { 1.0/4.0, 3.0/8.0, 12.0/13.0, 1.0, 1.0/2.0 } 7 | # b3 = { 3.0/32.0, 9.0/32.0 } 8 | # b4 = { 1932.0/2197.0, -7200.0/2197.0, 7296.0/2197.0} 9 | # b5 = { 8341.0/4104.0, -32832.0/4104.0, 29440.0/4104.0, -845.0/4104.0} 10 | # b6 = { -6080.0/20520.0, 41040.0/20520.0, -28352.0/20520.0, 9295.0/20520.0, -5643.0/20520.0} 11 | 12 | # c1 = 902880.0/7618050.0 13 | # c3 = 3953664.0/7618050.0 14 | # c4 = 3855735.0/7618050.0 15 | # c5 = -1371249.0/7618050.0 16 | # c6 = 277020.0/7618050.0 17 | 18 | # -- These are the differences of fifth and fourth order coefficients 19 | # -- for error estimation 20 | 21 | # ec = { 0.0, 1.0 / 360.0, 0.0, -128.0 / 4275.0, -2197.0 / 75240.0, 1.0 / 50.0, 2.0 / 55.0 } 22 | 23 | # y_err_only = (a_dydt == 0) 24 | 25 | local ffi = require "ffi" 26 | 27 | local vecsize = $(N) * ffi.sizeof('double') 28 | 29 | local cblas = ffi.load(ffi.os == "Windows" and "libgslcblas-0" or "gslcblas") 30 | 31 | ffi.cdef[[ 32 | typedef struct { 33 | double t; 34 | double h; 35 | double y[$(N)]; 36 | double dydt[$(N)]; 37 | } odevec_state; 38 | 39 | void cblas_daxpy (const int N, const double ALPHA, 40 | const double * X, const int INCX, 41 | double * Y, const int INCY); 42 | ]] 43 | 44 | local function ode_new() 45 | return ffi.new('odevec_state') 46 | end 47 | 48 | local function ode_init(s, t0, h0, f, y) 49 | ffi.copy(s.y, y, vecsize) 50 | f(t0, s.y, s.dydt) 51 | s.t = t0 52 | s.h = h0 53 | end 54 | 55 | local function hadjust(rmax, h) 56 | local S = 0.9 57 | if rmax > 1.1 then 58 | local r = S / rmax^(1/$(order)) 59 | r = max(0.2, r) 60 | return r * h, -1 61 | elseif rmax < 0.5 then 62 | local r = S / rmax^(1/($(order)+1)) 63 | r = max(1, min(r, 5)) 64 | return r * h, 1 65 | end 66 | return h, 0 67 | end 68 | 69 | local ws_y = ffi.new('double[$(N)]') 70 | local ws_k1 = ffi.new('double[$(N)]') 71 | local ws_k2 = ffi.new('double[$(N)]') 72 | local ws_k3 = ffi.new('double[$(N)]') 73 | local ws_k4 = ffi.new('double[$(N)]') 74 | local ws_k5 = ffi.new('double[$(N)]') 75 | local ws_k6 = ffi.new('double[$(N)]') 76 | 77 | local function rkf45_evolve(s, f, t1) 78 | local t, h = s.t, s.h 79 | local hadj, inc 80 | 81 | ffi.copy (ws_k1, s.dydt, vecsize) 82 | 83 | if t + h > t1 then h = t1 - t end 84 | 85 | while h > 0 do 86 | ffi.copy (ws_y, s.y, vecsize) 87 | local rmax = 0 88 | 89 | do 90 | cblas.cblas_daxpy ($(N), h * $(ah[1]), ws_k1, 1, ws_y, 1) 91 | 92 | -- k2 step 93 | f(t + $(ah[1]) * h, ws_y, ws_k2) 94 | 95 | ffi.copy (ws_y, s.y, vecsize) 96 | cblas.cblas_daxpy ($(N), h * $(b3[1]), ws_k1, 1, ws_y, 1) 97 | cblas.cblas_daxpy ($(N), h * $(b3[2]), ws_k2, 1, ws_y, 1) 98 | 99 | -- k3 step 100 | f(t + $(ah[2]) * h, ws_y, ws_k3) 101 | 102 | ffi.copy (ws_y, s.y, vecsize) 103 | cblas.cblas_daxpy ($(N), h * $(b4[1]), ws_k1, 1, ws_y, 1) 104 | cblas.cblas_daxpy ($(N), h * $(b4[2]), ws_k2, 1, ws_y, 1) 105 | cblas.cblas_daxpy ($(N), h * $(b4[3]), ws_k3, 1, ws_y, 1) 106 | 107 | -- k4 step 108 | f(t + $(ah[3]) * h, ws_y, ws_k4) 109 | 110 | ffi.copy (ws_y, s.y, vecsize) 111 | cblas.cblas_daxpy ($(N), h * $(b5[1]), ws_k1, 1, ws_y, 1) 112 | cblas.cblas_daxpy ($(N), h * $(b5[2]), ws_k2, 1, ws_y, 1) 113 | cblas.cblas_daxpy ($(N), h * $(b5[3]), ws_k3, 1, ws_y, 1) 114 | cblas.cblas_daxpy ($(N), h * $(b5[4]), ws_k4, 1, ws_y, 1) 115 | 116 | -- k5 step 117 | f(t + $(ah[4]) * h, ws_y, ws_k5) 118 | 119 | ffi.copy (ws_y, s.y, vecsize) 120 | cblas.cblas_daxpy ($(N), h * $(b6[1]), ws_k1, 1, ws_y, 1) 121 | cblas.cblas_daxpy ($(N), h * $(b6[2]), ws_k2, 1, ws_y, 1) 122 | cblas.cblas_daxpy ($(N), h * $(b6[3]), ws_k3, 1, ws_y, 1) 123 | cblas.cblas_daxpy ($(N), h * $(b6[4]), ws_k4, 1, ws_y, 1) 124 | cblas.cblas_daxpy ($(N), h * $(b6[5]), ws_k5, 1, ws_y, 1) 125 | 126 | -- k6 step and final sum 127 | -- since k2 is no more used we could use k2 to store k6 128 | f(t + $(ah[5]) * h, ws_y, ws_k6) 129 | 130 | ffi.copy (ws_y, s.y, vecsize) 131 | cblas.cblas_daxpy ($(N), h * $(c1), ws_k1, 1, ws_y, 1) 132 | cblas.cblas_daxpy ($(N), h * $(c3), ws_k3, 1, ws_y, 1) 133 | cblas.cblas_daxpy ($(N), h * $(c4), ws_k4, 1, ws_y, 1) 134 | cblas.cblas_daxpy ($(N), h * $(c5), ws_k5, 1, ws_y, 1) 135 | cblas.cblas_daxpy ($(N), h * $(c6), ws_k6, 1, ws_y, 1) 136 | 137 | # if not y_err_only then 138 | -- we use ws_k2 because it is no longer needed here 139 | f(t + h, ws_y, ws_k2) 140 | ffi.copy (s.dydt, ws_k2, vecsize) 141 | # end 142 | 143 | local yerr, r, d0 144 | # for i = 0, N-1 do 145 | yerr = h * ($(ec[2]) * ws_k1[$(i)] + $(ec[4]) * ws_k3[$(i)] + $(ec[5]) * ws_k4[$(i)] + $(ec[6]) * ws_k5[$(i)] + $(ec[7]) * ws_k6[$(i)]) 146 | # if y_err_only then 147 | d0 = $(eps_rel) * ($(a_y) * abs(ws_y[$(i)])) + $(eps_abs) 148 | # else 149 | d0 = $(eps_rel) * ($(a_y) * abs(ws_y[$(i)]) + $(a_dydt) * abs(h * s.dydt[$(i)])) + $(eps_abs) 150 | # end 151 | r = abs(yerr) / abs(d0) 152 | rmax = max(r, rmax) 153 | # end 154 | end 155 | 156 | hadj, inc = hadjust(rmax, h) 157 | if inc >= 0 then break end 158 | 159 | h = hadj 160 | end 161 | 162 | # if y_err_only then 163 | f(t + h, ws_y, ws_k2) 164 | ffi.copy (s.dydt, ws_k2, vecsize) 165 | # end 166 | 167 | ffi.copy (s.y, ws_y, vecsize) 168 | 169 | s.t = t + h 170 | s.h = hadj 171 | 172 | return h 173 | end 174 | 175 | return {new= ode_new, init= ode_init, evolve= rkf45_evolve} 176 | -------------------------------------------------------------------------------- /tests/test_legendre.expect: -------------------------------------------------------------------------------- 1 | Pass legendreP(1, -0.5) : -5.000000000000000e-01 2 | Pass legendreP(1, 1.0e-8) : 1.000000000000000e-08 3 | Pass legendreP(1, 0.5) : 5.000000000000000e-01 4 | Pass legendreP(1, 1.0) : 1.000000000000000e+00 5 | Pass legendreP(10, -0.5) : -1.882286071777345e-01 6 | Pass legendreP(10, 1.0e-8) : -2.460937499999986e-01 7 | Pass legendreP(10, 0.5) : -1.882286071777344e-01 8 | Pass legendreP(10, 1.0) : 1.000000000000000e+00 9 | Pass legendreP(99, -0.5) : 8.300778172138770e-02 10 | Pass legendreP(99, 1.0e-8) : -7.958923738716563e-08 11 | Pass legendreP(99, 0.5) : -8.300778172138770e-02 12 | Pass legendreP(99, 0.999) : -3.317727359254779e-01 13 | Pass legendreP(99, 1.0) : 1.000000000000000e+00 14 | Pass legendreP(1000, -0.5) : -1.916825109165028e-02 15 | Pass legendreP(1000, 1.0e-8) : 2.522501817709829e-02 16 | Pass legendreP(1000, 0.5) : -1.916825109165028e-02 17 | Pass legendreP(1000, 1.0) : 1.000000000000000e+00 18 | Pass legendreP(4000, -0.5) : -9.585404456573080e-03 19 | Pass legendreP(4000, 0.5) : -9.585404456573080e-03 20 | Pass legendreP(4000, 1.0) : 1.000000000000000e+00 21 | Pass legendrePlm(10, 0, -0.5) : -1.882286071777344e-01 22 | Pass legendrePlm(10, 0, 1.0e-08) : -2.460937499999986e-01 23 | Pass legendrePlm(10, 0, 0.5) : -1.882286071777344e-01 24 | Pass legendrePlm(10, 1, -0.5) : -2.006687739436126e+00 25 | Pass legendrePlm(10, 1, 1.0e-08) : -2.707031249999995e-07 26 | Pass legendrePlm(10, 1, 0.5) : 2.006687739436126e+00 27 | Pass legendrePlm(10, 5, -0.5) : -3.008616970611618e+04 28 | Pass legendrePlm(10, 5, 1.0e-08) : -2.533781249999997e-03 29 | Pass legendrePlm(10, 5, 0.5) : 3.008616970611618e+04 30 | Pass legendrePlm(10, 5, 0.999) : -5.036411489013271e-01 31 | Pass legendrePlm(100, 5, -0.5) : -6.617107444248382e+08 32 | Pass legendrePlm(100, 5, 1.0e-08) : 8.178987598063712e+02 33 | Pass legendrePlm(100, 5, 0.5) : 6.617107444248382e+08 34 | Pass legendrePlm(100, 5, 0.999) : -1.983161080380621e+09 35 | Pass legendresphPlm(10, 0, -0.5) : -2.433270236930013e-01 36 | Pass legendresphPlm(10, 0, 0.5) : -2.433270236930013e-01 37 | Pass legendresphPlm(10, 0, 0.999) : 1.222575412279739e+00 38 | Pass legendresphPlm(10, 5, -0.5) : -3.725739049803294e-01 39 | Pass legendresphPlm(10, 5, 1.0e-08): -3.137723358937679e-08 40 | Pass legendresphPlm(10, 5, 0.5) : 3.725739049803294e-01 41 | Pass legendresphPlm(10, 5, 0.999) : -6.236870674727370e-06 42 | Pass legendresphPlm(10, 10, -0.5) : 1.287687118578572e-01 43 | Pass legendresphPlm(10, 10, 0.5) : 1.287687118578572e-01 44 | Pass legendresphPlm(10, 10, 0.999) : 1.732080230758312e-14 45 | Pass legendresphPlm(200, 1, -0.5) : 3.302975570099493e-01 46 | Pass legendresphPlm(200, 1, 0.5) : -3.302975570099493e-01 47 | Pass legendresphPlm(200, 1, 0.999) : -1.406979205554626e+00 48 | Pass legendresphPlm(3, 1, 0.0) : 3.231801841141507e-01 49 | Pass legendresphPlm(200, 1, -0.5) : 3.302975570099493e-01 50 | Pass legendresphPlm(140,135,1) : 0.000000000000000e+00 51 | Pass legendresphPlm(140,135,0.99998689456491752): -6.542652532690932e-305 52 | Pass conicalPsphreg(2, 1.0, -0.5) : 1.640627928700879e+00 53 | Pass conicalPsphreg(10, 1.0, -0.5) : 2.931526672504913e-05 54 | Pass conicalPsphreg(20, 1.0, -0.5) : 7.335769429462035e-15 55 | Pass conicalPsphreg(30, 1.0, -0.5) : 1.323561239426738e-26 56 | Pass conicalPsphreg(10, 1.0, 0.5) : 2.701608719985788e-10 57 | Pass conicalPsphreg(20, 1.0, 0.5) : 1.178256970143593e-24 58 | Pass conicalPsphreg(30, 1.0, 0.5) : 3.636240588303798e-41 59 | Pass conicalPsphreg(10, 1.0, 2.0) : 2.493492962628493e-10 60 | Pass conicalPsphreg(20, 1.0, 2.0) : 1.128476248801262e-24 61 | Pass conicalPsphreg(30, 100.0, 100.0): -1.675777208715953e-64 62 | Pass conicalPcylreg(2, 1.0, -0.5) : 2.204851047237526e+00 63 | Pass conicalPcylreg(10, 1.0, -0.5) : 7.335034531618655e-05 64 | Pass conicalPcylreg(20, 1.0, -0.5) : 2.541986061921216e-14 65 | Pass conicalPcylreg(30, 1.0, -0.5) : 5.579714972260537e-26 66 | Pass conicalPcylreg(10, 1.0, 0.5) : 1.167407881964647e-09 67 | Pass conicalPcylreg(20, 1.0, 0.5) : 7.066408031229072e-24 68 | Pass conicalPcylreg(30, 1.0, 0.5) : 2.654197328686259e-40 69 | Pass conicalPcylreg(10, 1.0, 2.0) : 1.073610975189086e-09 70 | Pass conicalPcylreg(20, 1.0, 2.0) : 6.760965304863387e-24 71 | Pass conicalPcylreg(30, 100.0, 100.0): -4.268753482520651e-63 72 | Pass legendreH3d(5, 1.0e-06, 1.0e-06): 1.154401154401363e-32 73 | Pass legendreH3d(5, 1.0, 1.0e-10) : 2.022491201695877e-52 74 | Pass legendreH3d(5, 1.0, 1.0) : 1.149863503749158e-02 75 | Pass legendreH3d(5, 1.0, 5.0) : 2.069694566254521e-03 76 | Pass legendreH3d(5, 1.0, 7.0) : -1.755530378748899e-03 77 | Pass legendreH3d(5, 1.0, 10.0) : 8.999979724504887e-05 78 | Pass legendreH3d(5, 1.0, 100.0) : -4.185397793298568e-44 79 | Pass legendreH3d(5, 1.0, 500.0) : 1.423511390109196e-217 80 | Pass legendreH3d(5, 100.0, 0.001) : 9.642762597222418e-10 81 | Pass legendreH3d(5, 100.0, 0.002) : 3.082120125430803e-08 82 | Pass legendreH3d(5, 100.0, 0.01) : 9.281069019005840e-05 83 | Pass legendreH3d(5, 100.0, 1.0) : -8.043100696178624e-03 84 | Pass legendreH3d(5, 100.0, 10.0) : -3.927678432813974e-07 85 | Pass legendreH3d(5, 1000.0, 0.001) : 9.256365284253254e-05 86 | Pass legendreH3d(5, 1000.0, 0.01) : -5.553733815473080e-02 87 | Pass legendreH3d(5, 1.0e+08, 1.0e-08): 9.256115861125842e-05 88 | Pass legendreH3d(5, 1.0e+08, 100.0): -6.496143209092861e-52 89 | Pass legendreQ(10, -0.5) : -2.916581396658675e-01 90 | Pass legendreQ(10, 0.5) : 2.916581396658675e-01 91 | Pass legendreQ(10, 1.5) : 1.471423271820748e-05 92 | Pass legendreQ(100, -0.5) : -9.492507395207282e-02 93 | Pass legendreQ(100, 0.5) : 9.492507395207282e-02 94 | Pass legendreQ(100, 1.5) : 1.162816343504412e-43 95 | Pass legendreQ(1000, -0.5) : -3.010507497400530e-02 96 | Pass legendreQ(1000, 0.5) : 3.010507497400530e-02 97 | Pass legendreQ(1000, 1.1) : 1.075725844782536e-194 98 | -------------------------------------------------------------------------------- /doc/linalg.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: lua 2 | 3 | .. currentmodule:: matrix 4 | 5 | Linear Algebra 6 | ============== 7 | 8 | Functions 9 | --------- 10 | 11 | LGSL gives access to linear algebra functions based on GSL itself or on the BLAS routines. 12 | 13 | .. function:: inv(m) 14 | 15 | Returns the inverse of the matrix :math:`m`. 16 | 17 | .. function:: det(m) 18 | 19 | This function computes the determinant of a matrix :math:`m` from its LU decomposition, :math:`L U`. 20 | The determinant is internally computed as the product of the diagonal elements of :math:`U` and the sign of the row permutation signum. 21 | 22 | .. function:: solve(A, b) 23 | 24 | Solve the square system :math: `A x = b` where :math:`A` is a square matrix, :math:`b` 25 | is a column matrix. It returns the solution :math:`x` of the system. 26 | 27 | .. function:: svd(m) 28 | 29 | A general rectangular M-by-N matrix :math:`A` has a singular value 30 | decomposition (SVD) into the product of an M-by-N orthogonal matrix :math:`U`, 31 | an N-by-N diagonal matrix of singular values :math:`S` and the transpose of an 32 | N-by-N orthogonal square matrix :math:`V`, 33 | 34 | .. math:: 35 | A = U S V^T 36 | 37 | The singular values :math:`\sigma_i= S_{ii}` 38 | are all non-negative and are 39 | generally chosen to form a non-increasing sequence 40 | :math:`\sigma_1 \geq \sigma_2 \geq ... \geq \sigma_N \geq 0`. 41 | 42 | The singular value decomposition of a matrix has many practical uses. 43 | The condition number of the matrix is given by the ratio of the largest 44 | singular value to the smallest singular value. The presence of a zero 45 | singular value indicates that the matrix is singular. The number of 46 | non-zero singular values indicates the rank of the matrix. In practice 47 | singular value decomposition of a rank-deficient matrix will not produce 48 | exact zeroes for singular values, due to finite numerical precision. 49 | Small singular values should be edited by choosing a suitable tolerance. 50 | 51 | For a rank-deficient matrix, the null space of :math:`A` is given by the 52 | columns of :math:`V` corresponding to the zero singular values. Similarly, the 53 | range of :math:`A` is given by columns of U corresponding to the non-zero 54 | singular values. 55 | 56 | Note that the routines here compute the "thin" version of the SVD 57 | with :math:`U` as M-by-N orthogonal matrix. This allows in-place computation 58 | and is the most commonly-used form in practice. Mathematically, the 59 | "full" SVD is defined with :math:`U` as an M-by-M orthogonal matrix and :math:`S` as an 60 | M-by-N diagonal matrix (with additional rows of zeros). 61 | 62 | This function returns three values, in the order, :math:`U`, :math:`S`, :math:`V`. So you can 63 | write something like this:: 64 | 65 | U, S, V = matrix.svd(m) 66 | 67 | .. function:: lu(m) 68 | 69 | This function factorizes the square matrix :math:`A` into the LU decomposition :math:`PA = LU`:: 70 | 71 | L, U = matrix.lu(m) 72 | 73 | .. function:: qr(m) 74 | 75 | This function factorizes the M-by-N matrix :math:`A` into the QR decomposition :math:`A = Q R`:: 76 | 77 | Q, R = matrix.qr(m) 78 | 79 | .. function:: cholesky(m) 80 | 81 | A symmetric, positive definite square matrix :math:`A` has a Cholesky decomposition into a product of a 82 | lower triangular matrix :math:`L` and its transpose :math:`L^T`, 83 | 84 | real: :math:`A = L L^T` 85 | 86 | complex: :math:`A = L L^\star` 87 | 88 | This is sometimes referred to as taking the square-root of a matrix. 89 | The Cholesky decomposition can only be carried out when all the eigenvalues of the matrix are positive. 90 | This decomposition can be used to convert the linear system :math:`A x = b` into a pair of triangular systems (:math:`L y = b, L^T x = y`), 91 | which can be solved by forward and back-substitution. 92 | 93 | This function factorizes the symmetric, positive-definite square matrix :math:`A` into the Cholesky decomposition:: 94 | 95 | L, LT = matrix.cholesky(A) 96 | 97 | On input, the values from the diagonal and lower-triangular part of the matrix :math:`A` are used (the upper triangular part is ignored). 98 | If the matrix is not positive-definite then the decomposition will fail. 99 | 100 | 101 | .. function:: td_decomp(m) 102 | 103 | A matrix :math:`A` can be factorized by similarity transformations into the form, 104 | 105 | real: :math:`A = Q T Q^T` 106 | 107 | complex: :math:`A = U T U^T` 108 | 109 | where 110 | 111 | real: :math:`Q` is an orthogonal matrix and :math:`T` is a symmetric tridiagonal matrix. 112 | 113 | complex: :math:`U` is a unitary matrix and :math:`T` is a real symmetric tridiagonal matrix. 114 | 115 | This function calculates this decomposition and returns :math:`Q` or `U`, the diagonal vector and the sub-diagonal vector:: 116 | 117 | Q, Tdiag, Tsdiag = matrix.td_decomp(m) 118 | 119 | .. function:: hessenberg_decomp(m) 120 | 121 | A general real matrix :math:`A` can be decomposed by orthogonal similarity transformations into the form 122 | 123 | :math:`A = U H U^T` 124 | 125 | where :math:`U` is orthogonal and :math:`H` is an upper Hessenberg matrix, meaning that it has zeros below the first subdiagonal. 126 | The Hessenberg reduction is the first step in the Schur decomposition for the nonsymmetric eigenvalue problem, 127 | but has applications in other areas as well. 128 | The function returns ``H`` and ``U``:: 129 | 130 | H, U = matrix.hessenberg_decomp(m) 131 | 132 | .. function:: hesstri_decomp(a,b) 133 | 134 | A general real matrix pair :math:`(A, B)` can be decomposed by orthogonal similarity transformations into the form 135 | 136 | A = U H V^T 137 | B = U R V^T 138 | 139 | where U and V are orthogonal, H is an upper Hessenberg matrix, and R is upper triangular. 140 | The Hessenberg-Triangular reduction is the first step in the generalized Schur decomposition for the generalized eigenvalue problem. 141 | The function returns H, R, U and V:: 142 | 143 | H, R, U, V = matrix.hesstri_decomp(m) 144 | -------------------------------------------------------------------------------- /doc/examples.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: lua 2 | 3 | .. _lgsl-examples: 4 | 5 | LGSL Examples 6 | ================== 7 | 8 | In this chapter we give some usage examples of LGSL. 9 | 10 | Home-made Bessel Functions 11 | -------------------------- 12 | 13 | The Bessel function :math:`J_n` for integer values of n can be defined with the following integral: 14 | 15 | .. math:: 16 | J_n(x) = {1 \over \pi} \int_0^\pi \cos(n \tau - x \sin \tau) \textrm{d}\tau 17 | 18 | We can use this definition to define our home-made Bessel function. 19 | To perform the integral we need to use the :func:`integ.integ` function and provide the function to integrate. 20 | This is easy like eating a piece of cake:: 21 | 22 | integ = require("lgsl.integ").integ 23 | function bessJ(x, n) 24 | local epsabs, epsrel = 1e-8, 1e-4 25 | -- we define the function to integrate 26 | local f = function(t) return math.cos(n*t - x*math.sin(t)) end 27 | return 1/math.pi * integ(f, 0, math.pi, epsabs, epsrel) 28 | end 29 | 30 | The definition of ``bessJ`` takes x and n as arguments and calculates the definite integral between 0 and :math:`\pi`. Using the :mod:`graph` module from the package :ref:`graph-toolkit `, we can plot the results for various values of n:: 31 | 32 | graph = require("graph") 33 | p = graph.plot('Bessel Functions Jn, n=0 ... 5') 34 | for n=0, 5 do 35 | p:addline(graph.fxline(function(x) return bessJ(x,n) end, 0, 20), graph.rainbow(n+1)) 36 | end 37 | p:show() 38 | 39 | to obtain the following result: 40 | 41 | .. figure:: example-bessJ-plot.png 42 | 43 | Then we can also calculate a matrix with the tabulated values. For example, we can use the columns of the matrix to span different values of n. We write:: 44 | 45 | matrix = require("lgsl.matrix") 46 | m = matrix.new(200, 6, function(k,n) bessJ((k-1)/10, n-1) end) 47 | 48 | And we obtain the following matrix:: 49 | 50 | [ 1 0 0 0 0 0 ] 51 | [ 0.997502 0.0499375 0.00124896 2.08203e-05 2.60286e-07 0 ] 52 | [ 0.990025 0.0995008 0.00498335 0.00016625 4.15834e-06 8.31945e-08 ] 53 | [ 0.977626 0.148319 0.0111659 0.000559343 2.0999e-05 6.30443e-07 ] 54 | [ 0.960398 0.196027 0.0197347 0.00132005 6.61351e-05 2.64894e-06 ] 55 | [ 0.93847 0.242268 0.030604 0.00256373 0.000160736 8.05363e-06 ] 56 | [ 0.912005 0.286701 0.0436651 0.00439966 0.00033147 1.99482e-05 ] 57 | [ 0.881201 0.328996 0.0587869 0.00692965 0.000610097 4.28824e-05 ] 58 | [ 0.846287 0.368842 0.0758178 0.0102468 0.00103298 8.30836e-05 ] 59 | [ 0.807524 0.40595 0.0945863 0.014434 0.00164055 0.000148658 ] 60 | [ 0.765198 0.440051 0.114903 0.0195634 0.00247664 0.000249758 ] 61 | [ ... ] 62 | 63 | 64 | Zernike Polynomials 65 | ------------------- 66 | 67 | *Taken from Wikipedia* 68 | 69 | In mathematics, the Zernike polynomials are a sequence of polynomials that are orthogonal on the unit disk. Named after Frits Zernike, they play an important role in beam optics. 70 | 71 | Definitions 72 | ~~~~~~~~~~~ 73 | 74 | There are even and odd Zernike polynomials. The even ones are defined as 75 | 76 | .. math:: 77 | Z_n^m(\rho, \phi) = R_n^m(\rho) \cos(m \phi) 78 | 79 | and the odd ones as 80 | 81 | .. math:: 82 | Z_n^{-m}(\rho, \phi) = R_n^m(\rho) \sin(m \phi) 83 | 84 | where m and n are nonnegative integers with :math:`n \ge m`,:math:`\phi` is the azimuthal angle, and :math:`\rho` is the radial distance. The radial polynomials :math:`R_n^m` are defined as 85 | 86 | .. math:: 87 | R_n^m(\rho) = \sum_{k=0}^{(n-m)/2} \frac{(-1)^k (n-k)!}{k! ((n+m)/2-k)! ((n-m)/2 - k)!} \rho^{n - 2 k} 88 | 89 | for :math:`n - m` even, and are identically 0 for :math:`n - m` odd. 90 | For :math:`m = 0`, the even definition is used which reduces to :math:`R_n^0 (\rho)`. 91 | 92 | Implementation 93 | ~~~~~~~~~~~~~~ 94 | 95 | The above formula can be implemented quite straightforwardly in LGSL with only a subtle point about the factorials in the denominator. The problem is that in some cases you can have the factorial of a negative number and if you feed a negative number to the :func:`fact` function, you will get an error. 96 | 97 | Actually the meaning of the formula is that the factorial of a negative number is :math:`\infty` and so, since it appears in the denominator, its contribution to the sum is null. So, in order to implement this behavior we just define an auxiliary function that returns the inverse of the factorial and zero when the argument is negative. 98 | 99 | So here is the code for the radial part:: 100 | 101 | fact = require("lgsl.sf").fact 102 | 103 | -- inverse factorial function definition 104 | invf = function(n) 105 | return n >= 0 and 1/fact(n) or 0 106 | end 107 | 108 | -- radial part of Zernike's polynomial 109 | function zerR(n, m, p) 110 | local ip, im = (n+m)/2, (n-m)/2 111 | local z = 0 112 | for k=0, im do 113 | local f = fact(n-k) * (invf(k) * invf(ip-k) * invf(im-k)) 114 | if f > 0 then z = z + (-1)^k * f * p^(n-2*k) end 115 | end 116 | return z 117 | end 118 | 119 | Next, we define Zernike's function completed with the angular part:: 120 | 121 | function zernicke(n, m, p, phi, even) 122 | local pf = even and math.cos(m*phi) or math.sin(-m*phi) 123 | return zerR(n, m, p) * pf 124 | end 125 | 126 | Now we are ready to compute our function. The only missing piece is the relation between :math:`\rho`, :math:`\phi` and the Cartesian coordinates but this is trivial: 127 | 128 | .. math:: 129 | \begin{array}{ll} 130 | \rho = & \sqrt{x^2 + y^2} \\ 131 | \phi = & \tan^{-1}(y, x) 132 | \end{array} 133 | 134 | To visualise the functions, we will use the :mod:`contour` module of the graph-toolkit package. 135 | Let us define our sample function in terms of `x` and `y` and use it to call the function :func:`contour.polar_plot`:: 136 | 137 | contour = require("graph.contour") 138 | N, M = 8, -2 139 | f = function(x,y) return zernicke(N, M, math.sqrt(x^2+y^2), math.atan2(y,x)) end 140 | p = contour.polar_plot(f, 0.2, {gridx= 81, gridy= 81, levels= 10}) 141 | p.title = string.format('Zernike polynomial (N=%i, M=%i)', N, M) 142 | 143 | We show a few screenshots of the contour plot for various N and M. 144 | 145 | .. figure:: zernicke-contour-3-1.png 146 | 147 | .. figure:: zernicke-contour-5-1.png 148 | 149 | .. figure:: zernicke-contour-5-5.png 150 | 151 | .. figure:: zernicke-contour-8-2.png 152 | -------------------------------------------------------------------------------- /lgsl/templates/rk8pd.lua.in: -------------------------------------------------------------------------------- 1 | 2 | # -- rk8pd.lua.in 3 | # -- 4 | # -- Copyright (C) 2009-2011 Francesco Abbate 5 | # -- 6 | # -- This program is free software; you can redistribute it and/or modify 7 | # -- it under the terms of the GNU General Public License as published by 8 | # -- the Free Software Foundation; either version 3 of the License, or (at 9 | # -- your option) any later version. 10 | # -- 11 | # -- This program is distributed in the hope that it will be useful, but 12 | # -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # -- General Public License for more details. 15 | # -- 16 | # -- You should have received a copy of the GNU General Public License 17 | # -- along with this program; if not, write to the Free Software 18 | # -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | # -- 20 | 21 | # -- Adapted from the GSL Library, version 1.14 22 | 23 | # -- Runge-Kutta 8(9), Prince-Dormand 24 | # -- 25 | # -- High Order Embedded Runge-Kutta Formulae 26 | # -- P.J. Prince and J.R. Dormand 27 | # -- J. Comp. Appl. Math.,7, pp. 67-75, 1981 28 | 29 | # -- Original author: G. Jungman 30 | # -- Modified for LuaJIT2: Francesco Abbate 31 | 32 | local abs, max, min = math.abs, math.max, math.min 33 | 34 | # order = 8 35 | 36 | $(include 'lgsl.templates.ode-defs') 37 | 38 | # Abar = { '14005451/335480064', 39 | # '0', 40 | # '0', 41 | # '0', 42 | # '0', 43 | # '-59238493/1068277825', 44 | # '181606767/758867731', 45 | # '561292985/797845732', 46 | # '-1041891430/1371343529', 47 | # '760417239/1151165299', 48 | # '118820643/751138087', 49 | # '-528747749/2220607170', 50 | # '1/4' } 51 | 52 | # A = { 53 | # '13451932/455176623', 54 | # '0', 55 | # '0', 56 | # '0', 57 | # '0', 58 | # '-808719846/976000145', 59 | # '1757004468/5645159321', 60 | # '656045339/265891186', 61 | # '-3867574721/1518517206', 62 | # '465885868/322736535', 63 | # '53011238/667516719', 64 | # '2/45' } 65 | 66 | # ah = { 67 | # '1/18', 68 | # '1/12', 69 | # '1/8', 70 | # '5/16', 71 | # '3/8', 72 | # '59/400', 73 | # '93/200', 74 | # '5490023248/9719169821', 75 | # '13/20', 76 | # '1201146811/1299019798', 77 | # '1', 78 | # '1' } 79 | 80 | # B = { 0 } 81 | # B[2] = { '1/18' } 82 | # B[3] = { '1/48', '1/16' } 83 | # B[4] = { '1/32', '0', '3/32' } 84 | # B[5] = { '5/16', '0', '-75/64', '75/64' } 85 | # B[6] = { '3/80', '0', '0', '3/16', '3/20' } 86 | # B[7] = { 87 | # '29443841/614563906', 88 | # '0', 89 | # '0', 90 | # '77736538/692538347', 91 | # '-28693883/1125000000', 92 | # '23124283/1800000000' } 93 | 94 | # B[8] = { 95 | # '16016141/946692911', 96 | # '0', 97 | # '0', 98 | # '61564180/158732637', 99 | # '22789713/633445777', 100 | # '545815736/2771057229', 101 | # '-180193667/1043307555' } 102 | 103 | # B[9] = { 104 | # '39632708/573591083', 105 | # '0', 106 | # '0', 107 | # '-433636366/683701615', 108 | # '-421739975/2616292301', 109 | # '100302831/723423059', 110 | # '790204164/839813087', 111 | # '800635310/3783071287' } 112 | 113 | # B[10] = { 114 | # '246121993/1340847787', 115 | # '0', 116 | # '0', 117 | # '-37695042795/15268766246', 118 | # '-309121744/1061227803', 119 | # '-12992083/490766935', 120 | # '6005943493/2108947869', 121 | # '393006217/1396673457', 122 | # '123872331/1001029789' } 123 | 124 | # B[11] = { 125 | # '-1028468189/846180014', 126 | # '0', 127 | # '0', 128 | # '8478235783/508512852', 129 | # '1311729495/1432422823', 130 | # '-10304129995/1701304382', 131 | # '-48777925059/3047939560', 132 | # '15336726248/1032824649', 133 | # '-45442868181/3398467696', 134 | # '3065993473/597172653' } 135 | 136 | # B[12] = { 137 | # '185892177/718116043', 138 | # '0', 139 | # '0', 140 | # '-3185094517/667107341', 141 | # '-477755414/1098053517', 142 | # '-703635378/230739211', 143 | # '5731566787/1027545527', 144 | # '5232866602/850066563', 145 | # '-4093664535/808688257', 146 | # '3962137247/1805957418', 147 | # '65686358/487910083' } 148 | 149 | # B[13] = { 150 | # '403863854/491063109', 151 | # '0', 152 | # '0', 153 | # '-5068492393/434740067', 154 | # '-411421997/543043805', 155 | # '652783627/914296604', 156 | # '11173962825/925320556', 157 | # '-13158990841/6184727034', 158 | # '3936647629/1978049680', 159 | # '-160528059/685178525', 160 | # '248638103/1413531060', 161 | # '0' } 162 | 163 | # y_err_only = (a_dydt == 0) 164 | 165 | local function rk8pd_step(s, t1) 166 | local t, h, f = s.t, s.h, s.f 167 | local s_y, s_dydt = s.y, s.dydt 168 | local hadj, inc 169 | 170 | local $(VL'y') 171 | local $(VL'k1') = $(AL's_dydt.data') 172 | 173 | if t < t1 and t + h > t1 then h = t1 - t end 174 | 175 | while h > 0 do 176 | $(VL'y') = $(AL's_y.data') 177 | local rmax = 0 178 | 179 | do 180 | local $(VL'ytmp') 181 | 182 | # for S = 2, 13 do 183 | # for i = 0, N-1 do 184 | ytmp_$(i) = y_$(i) + h * ($(KCONV(B[S], S-1, i))) 185 | # end 186 | local $(VLI('k', S)) = f(t + $(ah[S-1]) * h, $(VL'ytmp')) 187 | # end 188 | 189 | local $(VL'ksum8') 190 | # for i = 0, N-1 do 191 | ksum8_$(i) = $(KCONV(Abar, 13, i)) 192 | y_$(i) = y_$(i) + h * ksum8_$(i) 193 | # end 194 | 195 | # if not y_err_only then 196 | local $(VL'dydt') = f(t + h, $(VL'y')) 197 | # for i = 0, N-1 do 198 | s_dydt.data[$(i)] = dydt_$(i) 199 | # end 200 | # end 201 | 202 | do 203 | local yerr, ksum7 204 | 205 | # for i = 0, N-1 do 206 | ksum7 = $(KCONV(A, 12, i)) 207 | yerr = h * (ksum7 - ksum8_$(i)) 208 | # if y_err_only then 209 | d0 = $(eps_rel) * ($(a_y) * abs(y_$(i))) + $(eps_abs) 210 | # else 211 | d0 = $(eps_rel) * ($(a_y) * abs(y_$(i)) + $(a_dydt) * abs(h * dydt_$(i))) + $(eps_abs) 212 | # end 213 | r = abs(yerr) / abs(d0) 214 | rmax = max(r, rmax) 215 | # end 216 | end 217 | end 218 | 219 | hadj, inc = hadjust(rmax, h) 220 | if inc >= 0 then break end 221 | 222 | h = hadj 223 | end 224 | 225 | # if y_err_only then 226 | local $(VL'dydt') = f(t + h, $(VL'y')) 227 | # for i = 0, N-1 do 228 | s_dydt.data[$(i)] = dydt_$(i) 229 | # end 230 | # end 231 | 232 | # for i = 0, N-1 do 233 | s_y.data[$(i)] = y_$(i) 234 | # end 235 | s.t = t + h 236 | s.h = hadj 237 | end 238 | 239 | return {new= ode_new, init= ode_init, evolve= ode_evolve, step= rk8pd_step} 240 | -------------------------------------------------------------------------------- /lgsl/randist.lua: -------------------------------------------------------------------------------- 1 | -- randist.lua 2 | -- 3 | -- Probability density functions, cumulative distribution functions, and 4 | -- inverse cumulative distribution functions from GSL. 5 | -- 6 | -- Copyright (C) 2009-2015 Francesco Abbate 7 | -- 8 | -- This program is free software; you can redistribute it and/or modify 9 | -- it under the terms of the GNU General Public License as published by 10 | -- the Free Software Foundation; either version 3 of the License, or (at 11 | -- your option) any later version. 12 | -- 13 | -- This program is distributed in the hope that it will be useful, but 14 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 15 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | -- General Public License for more details. 17 | -- 18 | -- You should have received a copy of the GNU General Public License 19 | -- along with this program; if not, write to the Free Software 20 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 | 22 | 23 | local gsl = require("lgsl.gsl") 24 | 25 | local randist = { 26 | bernoulli_pdf = gsl.gsl_ran_bernoulli_pdf, 27 | beta_pdf = gsl.gsl_ran_beta_pdf, 28 | binomial_pdf = gsl.gsl_ran_binomial_pdf, 29 | exponential_pdf = gsl.gsl_ran_exponential_pdf, 30 | exppow_pdf = gsl.gsl_ran_exppow_pdf, 31 | cauchy_pdf = gsl.gsl_ran_cauchy_pdf, 32 | chisq_pdf = gsl.gsl_ran_chisq_pdf, 33 | erlang_pdf = gsl.gsl_ran_erlang_pdf, 34 | fdist_pdf = gsl.gsl_ran_fdist_pdf, 35 | flat_pdf = gsl.gsl_ran_flat_pdf, 36 | gamma_pdf = gsl.gsl_ran_gamma_pdf, 37 | gaussian_pdf = gsl.gsl_ran_gaussian_pdf, 38 | ugaussian_pdf = gsl.gsl_ran_ugaussian_pdf, 39 | gaussian_tail_pdf = gsl.gsl_ran_gaussian_tail_pdf, 40 | ugaussian_tail_pdf = gsl.gsl_ran_ugaussian_tail_pdf, 41 | bivariate_gaussian_pdf = gsl.gsl_ran_bivariate_gaussian_pdf, 42 | landau_pdf = gsl.gsl_ran_landau_pdf, 43 | geometric_pdf = gsl.gsl_ran_geometric_pdf, 44 | hypergeometric_pdf = gsl.gsl_ran_hypergeometric_pdf, 45 | gumbel1_pdf = gsl.gsl_ran_gumbel1_pdf, 46 | gumbel2_pdf = gsl.gsl_ran_gumbel2_pdf, 47 | logistic_pdf = gsl.gsl_ran_logistic_pdf, 48 | lognormal_pdf = gsl.gsl_ran_lognormal_pdf, 49 | logarithmic_pdf = gsl.gsl_ran_logarithmic_pdf, 50 | pascal_pdf = gsl.gsl_ran_pascal_pdf, 51 | pareto_pdf = gsl.gsl_ran_pareto_pdf, 52 | poisson_pdf = gsl.gsl_ran_poisson_pdf, 53 | rayleigh_pdf = gsl.gsl_ran_rayleigh_pdf, 54 | rayleigh_tail_pdf = gsl.gsl_ran_rayleigh_tail_pdf, 55 | tdist_pdf = gsl.gsl_ran_tdist_pdf, 56 | laplace_pdf = gsl.gsl_ran_laplace_pdf, 57 | weibull_pdf = gsl.gsl_ran_weibull_pdf, 58 | 59 | ugaussian_P = gsl.gsl_cdf_ugaussian_P, 60 | ugaussian_Q = gsl.gsl_cdf_ugaussian_Q, 61 | 62 | ugaussian_Pinv = gsl.gsl_cdf_ugaussian_Pinv, 63 | ugaussian_Qinv = gsl.gsl_cdf_ugaussian_Qinv, 64 | 65 | gaussian_P = gsl.gsl_cdf_gaussian_P, 66 | gaussian_Q = gsl.gsl_cdf_gaussian_Q, 67 | 68 | gaussian_Pinv = gsl.gsl_cdf_gaussian_Pinv, 69 | gaussian_Qinv = gsl.gsl_cdf_gaussian_Qinv, 70 | 71 | gamma_P = gsl.gsl_cdf_gamma_P, 72 | gamma_Q = gsl.gsl_cdf_gamma_Q, 73 | 74 | gamma_Pinv = gsl.gsl_cdf_gamma_Pinv, 75 | gamma_Qinv = gsl.gsl_cdf_gamma_Qinv, 76 | 77 | cauchy_P = gsl.gsl_cdf_cauchy_P, 78 | cauchy_Q = gsl.gsl_cdf_cauchy_Q, 79 | 80 | cauchy_Pinv = gsl.gsl_cdf_cauchy_Pinv, 81 | cauchy_Qinv = gsl.gsl_cdf_cauchy_Qinv, 82 | 83 | laplace_P = gsl.gsl_cdf_laplace_P, 84 | laplace_Q = gsl.gsl_cdf_laplace_Q, 85 | 86 | laplace_Pinv = gsl.gsl_cdf_laplace_Pinv, 87 | laplace_Qinv = gsl.gsl_cdf_laplace_Qinv, 88 | 89 | rayleigh_P = gsl.gsl_cdf_rayleigh_P, 90 | rayleigh_Q = gsl.gsl_cdf_rayleigh_Q, 91 | 92 | rayleigh_Pinv = gsl.gsl_cdf_rayleigh_Pinv, 93 | rayleigh_Qinv = gsl.gsl_cdf_rayleigh_Qinv, 94 | 95 | chisq_P = gsl.gsl_cdf_chisq_P, 96 | chisq_Q = gsl.gsl_cdf_chisq_Q, 97 | 98 | chisq_Pinv = gsl.gsl_cdf_chisq_Pinv, 99 | chisq_Qinv = gsl.gsl_cdf_chisq_Qinv, 100 | 101 | exponential_P = gsl.gsl_cdf_exponential_P, 102 | exponential_Q = gsl.gsl_cdf_exponential_Q, 103 | 104 | exponential_Pinv = gsl.gsl_cdf_exponential_Pinv, 105 | exponential_Qinv = gsl.gsl_cdf_exponential_Qinv, 106 | 107 | exppow_P = gsl.gsl_cdf_exppow_P, 108 | exppow_Q = gsl.gsl_cdf_exppow_Q, 109 | 110 | tdist_P = gsl.gsl_cdf_tdist_P, 111 | tdist_Q = gsl.gsl_cdf_tdist_Q, 112 | 113 | tdist_Pinv = gsl.gsl_cdf_tdist_Pinv, 114 | tdist_Qinv = gsl.gsl_cdf_tdist_Qinv, 115 | 116 | fdist_P = gsl.gsl_cdf_fdist_P, 117 | fdist_Q = gsl.gsl_cdf_fdist_Q, 118 | 119 | fdist_Pinv = gsl.gsl_cdf_fdist_Pinv, 120 | fdist_Qinv = gsl.gsl_cdf_fdist_Qinv, 121 | 122 | beta_P = gsl.gsl_cdf_beta_P, 123 | beta_Q = gsl.gsl_cdf_beta_Q, 124 | 125 | beta_Pinv = gsl.gsl_cdf_beta_Pinv, 126 | beta_Qinv = gsl.gsl_cdf_beta_Qinv, 127 | 128 | flat_P = gsl.gsl_cdf_flat_P, 129 | flat_Q = gsl.gsl_cdf_flat_Q, 130 | 131 | flat_Pinv = gsl.gsl_cdf_flat_Pinv, 132 | flat_Qinv = gsl.gsl_cdf_flat_Qinv, 133 | 134 | lognormal_P = gsl.gsl_cdf_lognormal_P, 135 | lognormal_Q = gsl.gsl_cdf_lognormal_Q, 136 | 137 | lognormal_Pinv = gsl.gsl_cdf_lognormal_Pinv, 138 | lognormal_Qinv = gsl.gsl_cdf_lognormal_Qinv, 139 | 140 | gumbel1_P = gsl.gsl_cdf_gumbel1_P, 141 | gumbel1_Q = gsl.gsl_cdf_gumbel1_Q, 142 | 143 | gumbel1_Pinv = gsl.gsl_cdf_gumbel1_Pinv, 144 | gumbel1_Qinv = gsl.gsl_cdf_gumbel1_Qinv, 145 | 146 | gumbel2_P = gsl.gsl_cdf_gumbel2_P, 147 | gumbel2_Q = gsl.gsl_cdf_gumbel2_Q, 148 | 149 | gumbel2_Pinv = gsl.gsl_cdf_gumbel2_Pinv, 150 | gumbel2_Qinv = gsl.gsl_cdf_gumbel2_Qinv, 151 | 152 | weibull_P = gsl.gsl_cdf_weibull_P, 153 | weibull_Q = gsl.gsl_cdf_weibull_Q, 154 | 155 | weibull_Pinv = gsl.gsl_cdf_weibull_Pinv, 156 | weibull_Qinv = gsl.gsl_cdf_weibull_Qinv, 157 | 158 | pareto_P = gsl.gsl_cdf_pareto_P, 159 | pareto_Q = gsl.gsl_cdf_pareto_Q, 160 | 161 | pareto_Pinv = gsl.gsl_cdf_pareto_Pinv, 162 | pareto_Qinv = gsl.gsl_cdf_pareto_Qinv, 163 | 164 | logistic_P = gsl.gsl_cdf_logistic_P, 165 | logistic_Q = gsl.gsl_cdf_logistic_Q, 166 | 167 | logistic_Pinv = gsl.gsl_cdf_logistic_Pinv, 168 | logistic_Qinv = gsl.gsl_cdf_logistic_Qinv, 169 | 170 | binomial_P = gsl.gsl_cdf_binomial_P, 171 | binomial_Q = gsl.gsl_cdf_binomial_Q, 172 | 173 | poisson_P = gsl.gsl_cdf_poisson_P, 174 | poisson_Q = gsl.gsl_cdf_poisson_Q, 175 | 176 | geometric_P = gsl.gsl_cdf_geometric_P, 177 | geometric_Q = gsl.gsl_cdf_geometric_Q, 178 | 179 | negative_binomial_P = gsl.gsl_cdf_negative_binomial_P, 180 | negative_binomial_Q = gsl.gsl_cdf_negative_binomial_Q, 181 | 182 | pascal_P = gsl.gsl_cdf_pascal_P, 183 | pascal_Q = gsl.gsl_cdf_pascal_Q, 184 | 185 | hypergeometric_P = gsl.gsl_cdf_hypergeometric_P, 186 | hypergeometric_Q = gsl.gsl_cdf_hypergeometric_Q, 187 | } 188 | 189 | return randist 190 | -------------------------------------------------------------------------------- /lgsl/sort.lua: -------------------------------------------------------------------------------- 1 | -- sort.lua 2 | -- 3 | -- This file provided an implementation of the quicksort algorithm. 4 | -- Based on the libstdc++ std::sort implementation included with GCC. 5 | -- 6 | -- Copyright (C) 2009-2015 Francesco Abbate. 7 | -- 8 | 9 | local bit = require("bit") 10 | 11 | local band, rshift = bit.band, bit.rshift 12 | 13 | local insertion_thresold = 16 14 | 15 | local function less_than(a, b) 16 | return a < b 17 | end 18 | 19 | local function lg2(a) 20 | local c = 0 21 | while a > 0 do 22 | a = rshift(a, 1) 23 | c = c + 1 24 | end 25 | return c - 1 26 | end 27 | 28 | local function div2(a) 29 | return rshift(a, 1) 30 | end 31 | 32 | local function heapsort(array, i0, i1, f) 33 | f = f or less_than 34 | 35 | local function push_heap(first, hole, top, value) 36 | local parent = div2(hole - 1) 37 | while hole > top and f(array[first + parent], value) do 38 | array[first + hole] = array[first + parent] 39 | hole = parent 40 | parent = div2(hole - 1) 41 | end 42 | array[first + hole] = value 43 | end 44 | 45 | local function adjust_heap(first, hole, len, value) 46 | local top = hole 47 | local second = hole 48 | while second < div2(len - 1) do 49 | second = 2 * (second + 1) 50 | if f(array[first + second], array[first + (second - 1)]) then 51 | second = second - 1 52 | end 53 | array[first + hole] = array[first + second] 54 | hole = second 55 | end 56 | if band(len, 1) == 0 and second == div2(len - 2) then 57 | second = 2 * (second + 1) 58 | array[first + hole] = array[first + (second - 1)] 59 | hole = second - 1 60 | end 61 | push_heap(first, hole, top, value) 62 | end 63 | 64 | local function pop_heap(first, last, result) 65 | local value = array[result] 66 | array[result] = array[first] 67 | adjust_heap(first, 0, last - first, value) 68 | end 69 | 70 | local function make_heap(first, last) 71 | if last - first < 2 then return end 72 | local len = last - first 73 | local parent = div2(len - 2) 74 | while true do 75 | local value = array[first + parent] 76 | adjust_heap(first, parent, len, value) 77 | if parent == 0 then 78 | return 79 | end 80 | parent = parent - 1 81 | end 82 | end 83 | 84 | local function heap_select(first, middle, last) 85 | make_heap(first, middle) 86 | for i = middle, last - 1 do 87 | if f(array[i], array[first]) then 88 | pop_heap(first, middle, i) 89 | end 90 | end 91 | end 92 | 93 | local function sort_heap(first, last) 94 | while last - first > 1 do 95 | last = last - 1 96 | pop_heap(first, last, last) 97 | end 98 | end 99 | 100 | heap_select(i0, i1 + 1, i1 + 1) 101 | sort_heap(i0, i1 + 1) 102 | end 103 | 104 | local function insertion_sort(array, compare, istart, iend) 105 | for i = istart + 1, iend do 106 | local current_value = array[i] 107 | local hole_index = i 108 | while hole_index > istart and compare(current_value, array[hole_index - 1]) do 109 | array[hole_index] = array[hole_index - 1] 110 | hole_index = hole_index - 1 111 | end 112 | array[hole_index] = current_value 113 | end 114 | end 115 | 116 | local function quicksort(array, i0, i1, f) 117 | f = f or less_than 118 | 119 | local function move_median_first(a, b, c) 120 | if f(array[a], array[b]) then 121 | if f(array[b], array[c]) then 122 | array[a], array[b] = array[b], array[a] 123 | else 124 | array[a], array[c] = array[c], array[a] 125 | end 126 | elseif f(array[a], array[c]) then 127 | return 128 | elseif f(array[b], array[c]) then 129 | array[a], array[c] = array[c], array[a] 130 | else 131 | array[a], array[b] = array[b], array[a] 132 | end 133 | end 134 | 135 | local function partition(first, last, pivot_value) 136 | while true do 137 | while f(array[first], pivot_value) do 138 | first = first + 1 139 | end 140 | while f(pivot_value, array[last]) do 141 | last = last - 1 142 | end 143 | if first >= last then 144 | return first 145 | end 146 | array[first], array[last] = array[last], array[first] 147 | first = first + 1 148 | last = last - 1 149 | end 150 | end 151 | 152 | local function partition_pivot(first, last) 153 | local mid = div2(first + last) 154 | move_median_first(first, mid, last) 155 | return partition(first + 1, last, array[first]) 156 | end 157 | 158 | local function quicksort_loop(first, last, depth) 159 | while last - first > insertion_thresold do 160 | if depth == 0 then 161 | heapsort(array, first, last, f) 162 | return 163 | end 164 | depth = depth - 1 165 | local cut = partition_pivot(first, last) 166 | quicksort_loop(cut, last, depth) 167 | -- array[first], array[first + 1] = array[first + 1], array[first] 168 | last = cut - 1 169 | end 170 | end 171 | 172 | quicksort_loop(i0, i1, 2 * lg2(i1 - i0 + 1)) 173 | insertion_sort(array, f, i0, i1) 174 | end 175 | 176 | local function array_search(array, i0, i1, val) 177 | for k = i0, i1 do 178 | if array[k] == val then return k end 179 | end 180 | end 181 | 182 | -- sort arrays "array" and "slave" in place for indices from i0 to i1 183 | -- based on values of "array" using the comparison function "f" 184 | local function quicksort_mirror(array, slave, i0, i1, f) 185 | 186 | local function swap(index, a, b) 187 | array[a], array[b] = array[b], array[a] 188 | slave[a], slave[b] = slave[b], slave[a] 189 | index[a], index[b] = index[b], index[a] 190 | end 191 | 192 | local n = i1 - i0 + 1 193 | local id, iv = {}, {} 194 | for k = 1, n do id[k], iv[k] = k, k end 195 | quicksort(id, i0, i1, function(a, b) return f(array[a], array[b]) end) 196 | for k = 1, n do 197 | local val = id[k] 198 | if val > k then 199 | swap(iv, k, val) 200 | elseif val < k then 201 | val = array_search(iv, k, n, val) 202 | swap(iv, k, val) 203 | end 204 | end 205 | end 206 | 207 | return {quicksort = quicksort, quicksort_mirror = quicksort_mirror, 208 | heapsort = heapsort} 209 | -------------------------------------------------------------------------------- /demos/ode.lua: -------------------------------------------------------------------------------- 1 | 2 | -- ODE demo, demos/ode.lua 3 | -- 4 | -- Copyright (C) 2009 Francesco Abbate 5 | -- 6 | -- This program is free software; you can redistribute it and/or modify 7 | -- it under the terms of the GNU General Public License as published by 8 | -- the Free Software Foundation; either version 3 of the License, or (at 9 | -- your option) any later version. 10 | -- 11 | -- This program is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | -- General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU General Public License 17 | -- along with this program; if not, write to the Free Software 18 | -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | -- 20 | 21 | local ode = require("lgsl.ode") 22 | local graph = require("graph") 23 | local cos, exp, pi = math.cos, math.exp, math.pi 24 | 25 | -- T is the period for the Poincare section 26 | local function poincareplot(f, t0, t1, x0, y0, h0, tsmp, T) 27 | local s = ode {N= 2, eps_abs= 1e-8, method='rk8pd'} 28 | s:init(t0, h0, f, x0, y0) 29 | local ln = graph.path(x0, y0) 30 | for t, y1, y2 in s:evolve(t1, tsmp) do 31 | if t % T <= tsmp then ln:line_to(y1, y2) end 32 | end 33 | 34 | local p = graph.plot('Poincare section') 35 | p:add(ln, "black", {{'marker', size=4}}) 36 | p:show() 37 | return p 38 | end 39 | 40 | local function demo1() 41 | local f = function(t, x, y) 42 | return -y-x^2, 2*x - y^3 43 | end 44 | 45 | local x0, y0 = 1, 1 46 | local t0, t1 = 0, 30 47 | 48 | local s = ode {N= 2, eps_abs= 1e-8, method='rk8pd'} 49 | local ln = graph.path(x0, y0) 50 | 51 | s:init(t0, 1e-3, f, x0, y0) 52 | for t, y1, y2 in s:evolve(t1, 0.04) do 53 | ln:line_to(y1, y2) 54 | end 55 | 56 | local p = graph.plot('ODE integration example') 57 | p:addline(ln) 58 | p:show() 59 | return p 60 | end 61 | 62 | local function f_vanderpol_gen(mu) 63 | return function(t, x, y) return y, -x + mu * y * (1-x^2) end 64 | end 65 | 66 | local function demo2() 67 | local f = f_vanderpol_gen(10.0) 68 | 69 | local t0, t1, h = 0, 50, 0.01 70 | local x0, y0 = 1, 0 71 | 72 | local s = ode {N= 2, eps_abs= 1e-8, methdo='rk8pd'} 73 | s:init(t0, h, f, x0, y0) 74 | 75 | local ln1, ln2 = graph.path(t0, x0), graph.path(t0, y0) 76 | 77 | while s.t <= t1 do 78 | s:step(t1) 79 | ln1:line_to(s.t, s.y[1]) 80 | ln2:line_to(s.t, s.y[2]) 81 | end 82 | 83 | local p = graph.plot('ODE integration example') 84 | p:addline(ln1, 'red') 85 | p:addline(ln2, 'blue') 86 | p:show() 87 | return p 88 | end 89 | 90 | local function f_sincos_damp(damp_f) 91 | return function (t, s, c) 92 | return c - damp_f * s, -s - damp_f * c 93 | end 94 | end 95 | 96 | local function demo3() 97 | local damp_f = 0.04 98 | local x, y = 1, 0 99 | local s = ode {N= 2, eps_abs= 1e-8} 100 | local f = f_sincos_damp(damp_f) 101 | local t0, t1, h0, tsmp = 0, 100, 1e-6, 0.5 102 | s:init(t0, h0, f, x, y) 103 | local ln = graph.path(t0, x) 104 | for t, y1 in s:evolve(t1, tsmp) do 105 | ln:line_to(t, y1) 106 | end 107 | local p = graph.plot() 108 | p:addline(ln) 109 | p:addline(graph.fxline(function(t) return cos(t) * exp(- damp_f * t) end, 0, 100), 'blue', {{'dash', 7,3}}) 110 | p:show() 111 | return p 112 | end 113 | 114 | local function demo4() 115 | local a,b,d,g,omega = 1,1,0.2,0.3,1 116 | local odef = function(t, x, y) 117 | return y, a*x-b*x^3-d*y+g*cos(omega*t) 118 | end 119 | 120 | local x, y = 0, 0 121 | 122 | return poincareplot(odef, 0, 5000, x, y, 1e-3, 0.1, 2*pi/omega) 123 | end 124 | 125 | local function demo5() 126 | local g1, g2, e1, e2 = 0.1, 0.3, 0.3, 0.7 127 | 128 | local f = function(t, N1, N2) 129 | return N1*(e1 - g1*N2), -N2*(e2-g2*N1) 130 | end 131 | 132 | local x0, y0 = 10, 5 133 | local t0, t1, h0, tsmp = 0, 30, 1e-3, 0.1 134 | local s = ode {N= 2, eps_abs= 1e-8, method='rk8pd'} 135 | local ln1 = graph.path(t0, x0) 136 | local ln2 = graph.path(t0, y0) 137 | 138 | s:init(t0, h0, f, x0, y0) 139 | for t, y1, y2 in s:evolve(t1, tsmp) do 140 | ln1:line_to(t, y1) 141 | ln2:line_to(t, y2) 142 | end 143 | 144 | local p = graph.plot('Lotka-Volterra ODE integration') 145 | p.clip = false 146 | 147 | p:add(graph.marker(0, x0, 'circle', 8), 'red') 148 | p:add(graph.marker(0, y0, 'circle', 8), 'blue') 149 | 150 | p:add(graph.text(0.5, x0, 'Preys'), 'black') 151 | p:add(graph.text(0.5, y0, 'Predators'), 'black') 152 | 153 | p:addline(ln1) 154 | p:addline(ln2, 'blue') 155 | 156 | p.xtitle, p.ytitle = 'time', 'number' 157 | 158 | p:show() 159 | return p 160 | end 161 | 162 | local function demo6() 163 | -- Lorenz atmospheric model 164 | 165 | -- fluid parameters 166 | local s,r,b = 10,28,8/3 -- sigma (Prandtl), rho (Rayleigh), beta 167 | 168 | local function f(t, x,y,z) 169 | return s*(y-x), x*(r-z)-y, x*y-b*z 170 | end 171 | 172 | local x0, y0, z0 = -1, 3, 4 173 | local t0, t1, h0 = 0, 30, 1e-3 174 | local o = ode {N= 3, eps_abs= 1e-8, method='rk8pd'} 175 | local step = o.step 176 | local lnxy = graph.path(x0, y0) 177 | local lnxz = graph.path(x0, z0) 178 | local lnyz = graph.path(y0, z0) 179 | 180 | o:init(t0, h0, f, x0, y0, z0) 181 | 182 | for t, y1, y2, y3 in o:evolve(t1, 1e-3) do 183 | lnxy:line_to(y1, y2) 184 | lnxz:line_to(y1, y3) 185 | lnyz:line_to(y2, y3) 186 | end 187 | 188 | local w = graph.window("v...") 189 | 190 | local pxy = graph.plot("Lorenz atmospheric model") 191 | pxy.xtitle, pxy.ytitle ="x", "y" 192 | local pxz = graph.plot() 193 | pxz.xtitle, pxz.ytitle ="x", "z" 194 | local pyz = graph.plot() 195 | pyz.xtitle, pyz.ytitle ="y", "z" 196 | 197 | pxy:addline(lnxy) 198 | pxz:addline(lnxz) 199 | pyz:addline(lnyz) 200 | 201 | w:attach(pxy,'3') 202 | w:attach(pxz,'2') 203 | w:attach(pyz,'1') 204 | 205 | return w 206 | end 207 | 208 | return {'ODE', { 209 | { 210 | name = 'ode1', 211 | f = demo1, 212 | description = 'ODE integration example' 213 | }, 214 | { 215 | name = 'ode2', 216 | f = demo2, 217 | description = 'GSL example of Var der Pol oscillator integration' 218 | }, 219 | { 220 | name = 'ode3', 221 | f = demo3, 222 | description = 'Examples of damped harmonic oscillator' 223 | }, 224 | { 225 | name = 'ode4', 226 | f = demo4, 227 | description = 'Example of a Poincare section for the Duffing equation' 228 | }, 229 | { 230 | name = 'ode5', 231 | f = demo5, 232 | description = 'Lotka-Volterra ODE integration' 233 | }, 234 | { 235 | name = 'ode6', 236 | f = demo6, 237 | description = 'Lorenz atmospheric model' 238 | }, 239 | 240 | }} 241 | -------------------------------------------------------------------------------- /tests/randist.lua: -------------------------------------------------------------------------------- 1 | -- This is a (generated) test script for all the methods in the randist module. 2 | 3 | local randist = require("lgsl.randist") 4 | local gsl = require("lgsl.gsl") 5 | local sprintf = function(...) return io.write(string.format(...)) end 6 | local eps = 1e-12 7 | local function compare(val, ref, name) 8 | local inc = 0 9 | if val==0 or ref==0 then inc = 1 end 10 | if gsl.gsl_fcmp(val+inc,ref+inc,eps)==0 then 11 | sprintf("Pass %-30s: % .15e\n", name, ref,"\n") 12 | else 13 | sprintf("Fail %-30s: % .15e ~= % .15e\n", name, val, ref) 14 | end 15 | end 16 | 17 | local x=0.1 18 | local sigma=1 19 | local mu=1 20 | local nu=9 21 | local a=3 22 | local nu1=2 23 | local nu2=4 24 | local b=2 25 | local zeta=1 26 | local p=0.4 27 | local n=8 28 | 29 | compare(randist.gaussian_pdf(x, sigma) , 3.969525474770118e-01, "gaussian_pdf(x, sigma)") 30 | compare(randist.gaussian_P(x, sigma) , 5.398278372770290e-01, "gaussian_P(x, sigma)") 31 | compare(randist.gaussian_Q(x, sigma) , 4.601721627229710e-01, "gaussian_Q(x, sigma)") 32 | compare(randist.gaussian_Pinv(x, sigma) , -1.281551565544601e+00, "gaussian_Pinv(x, sigma)") 33 | compare(randist.gaussian_Qinv(x, sigma) , 1.281551565544601e+00, "gaussian_Qinv(x, sigma)") 34 | compare(randist.exponential_pdf(x, mu) , 9.048374180359595e-01, "exponential_pdf(x, mu)") 35 | compare(randist.exponential_P(x, mu) , 9.516258196404043e-02, "exponential_P(x, mu)") 36 | compare(randist.exponential_Q(x, mu) , 9.048374180359595e-01, "exponential_Q(x, mu)") 37 | compare(randist.exponential_Pinv(x, mu) , 1.053605156578263e-01, "exponential_Pinv(x, mu)") 38 | compare(randist.exponential_Qinv(x, mu) , 2.302585092994045e+00, "exponential_Qinv(x, mu)") 39 | compare(randist.chisq_pdf(x, nu) , 1.142894236600128e-06, "chisq_pdf(x, nu)") 40 | compare(randist.chisq_P(x, nu) , 2.563032539662434e-08, "chisq_P(x, nu)") 41 | compare(randist.chisq_Q(x, nu) , 9.999999743696746e-01, "chisq_Q(x, nu)") 42 | compare(randist.chisq_Pinv(x, nu) , 4.168159008146109e+00, "chisq_Pinv(x, nu)") 43 | compare(randist.chisq_Qinv(x, nu) , 1.468365657325983e+01, "chisq_Qinv(x, nu)") 44 | compare(randist.laplace_pdf(x, a) , 1.612026834136676e-01, "laplace_pdf(x, a)") 45 | compare(randist.laplace_P(x, a) , 5.163919497589970e-01, "laplace_P(x, a)") 46 | compare(randist.laplace_Q(x, a) , 4.836080502410030e-01, "laplace_Q(x, a)") 47 | compare(randist.laplace_Pinv(x, a) , -4.828313737302301e+00, "laplace_Pinv(x, a)") 48 | compare(randist.laplace_Qinv(x, a) , 4.828313737302301e+00, "laplace_Qinv(x, a)") 49 | compare(randist.tdist_pdf(x, nu) , 3.858863266209659e-01, "tdist_pdf(x, nu)") 50 | compare(randist.tdist_P(x, nu) , 5.387317760216594e-01, "tdist_P(x, nu)") 51 | compare(randist.tdist_Q(x, nu) , 4.612682239783406e-01, "tdist_Q(x, nu)") 52 | compare(randist.tdist_Pinv(x, nu) , -1.383028738396633e+00, "tdist_Pinv(x, nu)") 53 | compare(randist.tdist_Qinv(x, nu) , 1.383028738396633e+00, "tdist_Qinv(x, nu)") 54 | compare(randist.cauchy_pdf(x, a) , 1.059855336904963e-01, "cauchy_pdf(x, a)") 55 | compare(randist.cauchy_P(x, a) , 5.106064024055355e-01, "cauchy_P(x, a)") 56 | compare(randist.cauchy_Q(x, a) , 4.893935975944646e-01, "cauchy_Q(x, a)") 57 | compare(randist.cauchy_Pinv(x, a) , -9.233050611525762e+00, "cauchy_Pinv(x, a)") 58 | compare(randist.cauchy_Qinv(x, a) , 9.233050611525762e+00, "cauchy_Qinv(x, a)") 59 | compare(randist.rayleigh_pdf(x, sigma) , 9.950124791926823e-02, "rayleigh_pdf(x, sigma)") 60 | compare(randist.rayleigh_P(x, sigma) , 4.987520807317688e-03, "rayleigh_P(x, sigma)") 61 | compare(randist.rayleigh_Q(x, sigma) , 9.950124791926823e-01, "rayleigh_Q(x, sigma)") 62 | compare(randist.rayleigh_Pinv(x, sigma) , 4.590436050264208e-01, "rayleigh_Pinv(x, sigma)") 63 | compare(randist.rayleigh_Qinv(x, sigma) , 2.145966026289347e+00, "rayleigh_Qinv(x, sigma)") 64 | compare(randist.fdist_pdf(x, nu1, nu2) , 8.638375985314765e-01, "fdist_pdf(x, nu1, nu2)") 65 | compare(randist.fdist_P(x, nu1, nu2) , 9.297052154195022e-02, "fdist_P(x, nu1, nu2)") 66 | compare(randist.fdist_Q(x, nu1, nu2) , 9.070294784580498e-01, "fdist_Q(x, nu1, nu2)") 67 | compare(randist.fdist_Pinv(x, nu1, nu2) , 1.081851067789194e-01, "fdist_Pinv(x, nu1, nu2)") 68 | compare(randist.fdist_Qinv(x, nu1, nu2) , 4.324555320336761e+00, "fdist_Qinv(x, nu1, nu2)") 69 | compare(randist.gamma_pdf(x, a, b) , 5.945183903129460e-04, "gamma_pdf(x, a, b)") 70 | compare(randist.gamma_P(x, a, b) , 2.006749362439790e-05, "gamma_P(x, a, b)") 71 | compare(randist.gamma_Q(x, a, b) , 9.999799325063756e-01, "gamma_Q(x, a, b)") 72 | compare(randist.gamma_Pinv(x, a, b) , 2.204130656498644e+00, "gamma_Pinv(x, a, b)") 73 | compare(randist.gamma_Qinv(x, a, b) , 1.064464067566841e+01, "gamma_Qinv(x, a, b)") 74 | compare(randist.beta_pdf(x, a, b) , 1.079999999999999e-01, "beta_pdf(x, a, b)") 75 | compare(randist.beta_P(x, a, b) , 3.699999999999995e-03, "beta_P(x, a, b)") 76 | compare(randist.beta_Q(x, a, b) , 9.963000000000000e-01, "beta_Q(x, a, b)") 77 | compare(randist.beta_Pinv(x, a, b) , 3.204605837218185e-01, "beta_Pinv(x, a, b)") 78 | compare(randist.beta_Qinv(x, a, b) , 8.574406832899693e-01, "beta_Qinv(x, a, b)") 79 | compare(randist.gaussian_tail_pdf(5, a, sigma), 1.101356902446165e-03, "gaussian_tail_pdf(5, a, sigma)") 80 | compare(randist.exppow_pdf(x, a, b) , 1.878543514563088e-01, "exppow_pdf(x, a, b)") 81 | compare(randist.exppow_P(x, a, b) , 5.187993564692450e-01, "exppow_P(x, a, b)") 82 | compare(randist.exppow_Q(x, a, b) , 4.812006435307550e-01, "exppow_Q(x, a, b)") 83 | compare(randist.lognormal_pdf(x, zeta, sigma) , 1.707930831120359e-02, "lognormal_pdf(x, zeta, sigma)") 84 | compare(randist.lognormal_P(x, zeta, sigma) , 4.789900863651144e-04, "lognormal_P(x, zeta, sigma)") 85 | compare(randist.lognormal_Q(x, zeta, sigma) , 9.995210099136349e-01, "lognormal_Q(x, zeta, sigma)") 86 | compare(randist.lognormal_Pinv(x, zeta, sigma), 7.546120026931251e-01, "lognormal_Pinv(x, zeta, sigma)") 87 | compare(randist.lognormal_Qinv(x, zeta, sigma), 9.791861344054885e+00, "lognormal_Qinv(x, zeta, sigma)") 88 | compare(randist.binomial_pdf(x, p, n) , 1.679615999999999e-02, "binomial_pdf(x, p, n)") 89 | compare(randist.binomial_P(x, p, n) , 1.679615999999999e-02, "binomial_P(x, p, n)") 90 | compare(randist.binomial_Q(x, p, n) , 9.832038400000001e-01, "binomial_Q(x, p, n)") 91 | compare(randist.poisson_pdf(x, mu) , 3.678794411714423e-01, "poisson_pdf(x, mu)") 92 | compare(randist.poisson_P(x, mu) , 3.678794411714423e-01, "poisson_P(x, mu)") 93 | compare(randist.poisson_Q(x, mu) , 6.321205588285578e-01, "poisson_Q(x, mu)") 94 | -------------------------------------------------------------------------------- /doc/pdf.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: lua 2 | 3 | .. module:: randist 4 | 5 | .. _pdf: 6 | 7 | Probability Distribution Functions 8 | ================================== 9 | 10 | Overview 11 | -------- 12 | 13 | The module :mod:`randist` offers a set of functions that mirrors those available from the module :mod:`rnd`. 14 | Generally, for each kind of distribution, a few functions are available to calculate the **probability density function**, the **cumulative distribution function** and the **inverse cumulative distribution function**. 15 | 16 | The cumulative distribution functions and their 17 | inverses are computed separately for the upper and lower tails of the 18 | distribution, allowing full accuracy to be retained for small results. 19 | 20 | *Continuous* random number distributions are defined by a probability density function, :math:`p(x)`, such that the probability of :math:`x` occurring in the infinitesimal range :math:`x` to :math:`x+dx` is :math:`p(x) dx`. 21 | 22 | The cumulative distribution function for the lower tail :math:`P(x)` is defined by the integral, 23 | 24 | .. math:: 25 | P(x) = \int_{-\infty}^{x} dx' p(x') 26 | 27 | and gives the probability of a variate taking a value *less than* :math:`x`. 28 | 29 | The cumulative distribution function for the upper tail :math:`Q(x)` is defined by the integral, 30 | 31 | .. math:: 32 | Q(x) = \int_{x}^{+\infty} dx' p(x') 33 | 34 | and gives the probability of a variate taking a value *greater than* :math:`x`. 35 | 36 | The upper and lower cumulative distribution functions are related by :math:`P(x) + Q(x) = 1` and satisfy :math:`0 \le P(x) \le 1`, :math:`0 \le Q(x) \le 1`. 37 | 38 | The inverse cumulative distribution functions, :math:`x = P^{-1}(p)` and :math:`x = Q^{-1}(q)` give the values of :math:`x` which correspond to a specific value of :math:`p` or :math:`q`. 39 | They can be used to find confidence limits from probability values. 40 | 41 | For *discrete* distributions, the probability of sampling the integer value :math:`k` is given by :math:`p(k)`, where :math:`\sum_k p(k) = 1`. The cumulative distribution function for the lower tail :math:`P(k)` of a discrete distribution is defined as, 42 | 43 | .. math:: P(k) = \sum_{i \le k} p(i) 44 | 45 | where the sum is over the allowed range of the distribution *less than or equal to* :math:`k`. 46 | 47 | The cumulative distribution function for the upper tail of a discrete distribution :math:`Q(k)` is defined as 48 | 49 | .. math:: 50 | Q(k) = \sum_{i > k} p(i) 51 | 52 | giving the sum of probabilities for all values *greater* than :math:`k`. 53 | These two definitions satisfy the identity :math:`P(k) + Q(k) = 1`. 54 | 55 | If the range of the distribution is 1 to :math:`n` inclusive, then :math:`P(n)=1`, 56 | :math:`Q(n)=0` while :math:`P(1) = p(1)`, :math:`Q(1)=1-p(1)`. 57 | 58 | Naming Conventions 59 | ~~~~~~~~~~~~~~~~~~ 60 | 61 | The probability functions are named following an uniform naming convention. 62 | The probability density function end with the suffix ``_pdf``. 63 | The cumulative distribution functions :math:`P(x)` and :math:`Q(x)` end with the suffix ``_P`` and ``_Q``, respectively. 64 | The inverse cumulative distribution functions :math:`P^{-1}(x)` and :math:`Q^{-1}(x)` end with the suffix ``_Pinv`` and ``_Qinv``, respectively. 65 | 66 | Functions Index 67 | ~~~~~~~~~~~~~~~ 68 | 69 | We present here the list of the available probability functions. 70 | 71 | .. note:: 72 | Actually LGSL implements all the functions provided by the GSL library but some of them are not listed here. 73 | Please consult the GSL reference manual if you need a complete list of all the distributions available. 74 | 75 | .. function:: gaussian_pdf(x, sigma) 76 | gaussian_P(x, sigma) 77 | gaussian_Q(x, sigma) 78 | gaussian_Pinv(x, sigma) 79 | gaussian_Qinv(x, sigma) 80 | 81 | See :ref:`Gaussian distribution `. 82 | 83 | .. function:: exponential_pdf(x, mu) 84 | exponential_P(x, mu) 85 | exponential_Q(x, mu) 86 | exponential_Pinv(x, mu) 87 | exponential_Qinv(x, mu) 88 | 89 | See :ref:`Exponential Distribution `. 90 | 91 | .. function:: chisq_pdf(x, nu) 92 | chisq_P(x, nu) 93 | chisq_Q(x, nu) 94 | chisq_Pinv(x, nu) 95 | chisq_Qinv(x, nu) 96 | 97 | See :ref:`Chi square Distribution `. 98 | 99 | .. function:: laplace_pdf(x, a) 100 | laplace_P(x, a) 101 | laplace_Q(x, a) 102 | laplace_Pinv(x, a) 103 | laplace_Qinv(x, a) 104 | 105 | See :ref:`Laplace Distribution `. 106 | 107 | .. function:: tdist_pdf(x, nu) 108 | tdist_P(x, nu) 109 | tdist_Q(x, nu) 110 | tdist_Pinv(x, nu) 111 | tdist_Qinv(x, nu) 112 | 113 | See :ref:`t- Distribution `. 114 | 115 | .. function:: cauchy_pdf(x, a) 116 | cauchy_P(x, a) 117 | cauchy_Q(x, a) 118 | cauchy_Pinv(x, a) 119 | cauchy_Qinv(x, a) 120 | 121 | See :ref:`Cauchy Distribution `. 122 | 123 | .. function:: rayleigh_pdf(x, sigma) 124 | rayleigh_P(x, sigma) 125 | rayleigh_Q(x, sigma) 126 | rayleigh_Pinv(x, sigma) 127 | rayleigh_Qinv(x, sigma) 128 | 129 | See :ref:`Rayleigh Distribution `. 130 | 131 | .. function:: fdist_pdf(x, nu1, nu2) 132 | fdist_P(x, nu1, nu2) 133 | fdist_Q(x, nu1, nu2) 134 | fdist_Pinv(x, nu1, nu2) 135 | fdist_Qinv(x, nu1, nu2) 136 | 137 | See :ref:`F- Distribution `. 138 | 139 | .. function:: gamma_pdf(x, a, b) 140 | gamma_P(x, a, b) 141 | gamma_Q(x, a, b) 142 | gamma_Pinv(x, a, b) 143 | gamma_Qinv(x, a, b) 144 | 145 | See :ref:`Gamma Distribution `. 146 | 147 | .. function:: beta_pdf(x, a, b) 148 | beta_P(x, a, b) 149 | beta_Q(x, a, b) 150 | beta_Pinv(x, a, b) 151 | beta_Qinv(x, a, b) 152 | 153 | See :ref:`Beta Distribution `. 154 | 155 | .. function:: gaussian_tail_pdf(x, a, sigma) 156 | gaussian_tail_P(x, a, sigma) 157 | gaussian_tail_Q(x, a, sigma) 158 | gaussian_tail_Pinv(x, a, sigma) 159 | gaussian_tail_Qinv(x, a, sigma) 160 | 161 | See :ref:`Gaussian tail Distribution `. 162 | 163 | .. function:: exppow_pdf(x, a, b) 164 | exppow_P(x, a, b) 165 | exppow_Q(x, a, b) 166 | exppow_Pinv(x, a, b) 167 | exppow_Qinv(x, a, b) 168 | 169 | See :ref:`Exponential Power Distribution `. 170 | 171 | .. function:: lognormal_pdf(x, zeta, sigma) 172 | lognormal_P(x, zeta, sigma) 173 | lognormal_Q(x, zeta, sigma) 174 | lognormal_Pinv(x, zeta, sigma) 175 | lognormal_Qinv(x, zeta, sigma) 176 | 177 | See :ref:`Lognormal Distribution `. 178 | 179 | .. function:: binomial_pdf(x, p, n) 180 | binomial_P(x, p, n) 181 | binomial_Q(x, p, n) 182 | 183 | See :ref:`Binomial Distribution `. 184 | 185 | .. function:: poisson_pdf(x, mu) 186 | poisson_P(x, mu) 187 | poisson_Q(x, mu) 188 | 189 | See :ref:`Poisson Distribution `. 190 | --------------------------------------------------------------------------------