Giter VIP home page Giter VIP logo

gaussjacobiquad's Introduction

GaussJacobiQuad https://zenodo.org/badge/667604312.svg https://github.com/HaoZeke/GaussJacobiQuad/actions/workflows/build_test.yml/badge.svg https://github.com/HaoZeke/GaussJacobiQuad/actions/workflows/build_docs.yml/badge.svg

About

A permissively licensed modern implementation of Gauss-Jacobi quadrature which returns the weights and nodes over the standard interval [-1, 1].

Usage

The most automated approach is to use the conda environment and fpm build:

micromamba create -f environment.yml
micromamba activate gaussjacquad
fpm build

An analytic result can be obtained from the scripts folder.

python scripts/sympy_gauss_jac.py --npts <npoints> --alpha <alpha> --beta <beta> --n_dig <precision>
fpm test

Running the implemented recursion based Gauss-Jacobi can be done via:

fpm run gjp_quad_rec -- <npoints> <alpha> <beta>
fpm run gjp_quad -- <npoints> <alpha> <beta> <method>

Currently the only supported methods are “rec” and “gw” (Golub Welsch).

Meson Support

A meson build backend is also present, which makes it easier to incorporate as subprojects of projects other than those supported by fpm.

meson setup bbdir
meson compile -C bbdir
./bbdir/gjp_quad <npoints> <alpha> <beta> <method>

External Fortran libaries

We support and encourage users to generate single file versions of the algorithms here to include in their code bases. This can be done with the scripts/add_headers.py script:

# Strips comments by default
python scripts/export_single.py --modulename "gjp_algo665"
python scripts/export_single.py --modulename "gjp_gw" --keep-comments

These can be dropped into any code base or compiled as is into a shared library.

gfortran dist/gjp_algo665_single.f90 --shared -fPIC -o libgjp_algo665.so

Interfaces

C/C++ header interface

We provide a header only interface, which bypasses passing strings between Fortran and C. In order to do this, there is some duplication logic in GaussJacobiQuad and GaussJacobiQuadCInterp.

There is also a CLI interface to the C bound interface, c_cli_gjpq. However, this will not be compiled by fpm.

meson setup bbdir
meson compile -C bbdir
./bbdir/c_cli_gjpq <npoints> <alpha> <beta> <method>

The C CLI might be more pleasant in that decimals do not need to be provided explicitly for alpha and beta.

f2py generated interface

The ISO_C_BINDING variant of the code is also used for a python interface generated with f2py. It is easiest to use with the new meson back-end:

cd interfaces/PyInterface
f2py -c --backend meson gjquadpy.pyf \
    --dep lapack \
    ../../src/GaussJacobiQuadCCompat.f90 \
    ../../src/GaussJacobiQuad.f90 \
    ../../src/gjp_constants.f90 \
    ../../src/gjp_types.f90 \
    ../../src/gjp_rec.f90 \
    ../../src/gjp_common.f90 \
    ../../src/gjp_lapack.f90 \
    ../../src/gjp_gw.f90 \
    ../../src/gjp_algo665.f90

Once compiled, the gjpquad_cli.py script can be used to run the code:

python gjquad_cli.py --npts 5 --alpha 2 --beta 3
Root: -6.90457750126761027E-01 Weight: 2.74101780663370022E-02
Root: -3.26519931349000647E-01 Weight: 2.12917860603648035E-01
Root:  8.23378495520349085E-02 Weight: 4.39084379443950568E-01
Root:  4.75178870612831761E-01 Weight: 3.22206565472217876E-01
Root:  7.92794294644228348E-01 Weight: 6.50476830805121059E-02

Notes

  • The rec method fails for high values of beta so the gw method

should be used in such situations.

  • algo665 is an in-place variant of gw and is much faster when many points are needed

Benchmarks

A very preliminary set can be run once all the interfaces have been compiled:

# From $GITROOT
mv interfaces/PyInterface/gjquadpy*.so .
hyperfine --warmup 10 --export-markdown gjp_benchmarks.md \
    'bbdir/gjp_quad 5 2. 3. "gw"' \
    'bbdir/c_cli_gjpq 5 2 3 gw' \
    'PYTHONPATH=$(pwd) python interfaces/PyInterface/gjquad_cli.py --npts 5 --alpha 2 --beta 3' \
    'python scripts/scipy_gauss_jac.py --npts 5 --alpha 2 --beta 3' \
    'python scripts/sympy_gauss_jac.py --npts 5 --alpha 2 --beta 3 --n_dig 15'

Which gives:

ummary
  bbdir/c_cli_gjpq 5 2 3 gw ran
    1.03 ± 0.45 times faster than bbdir/gjp_quad 5 2. 3. "gw"
   39.08 ± 11.48 times faster than PYTHONPATH=$(pwd) python interfaces/PyInterface/gjquad_cli.py --npts 5 --alpha 2 --beta 3
   55.71 ± 16.51 times faster than python scripts/scipy_gauss_jac.py --npts 5 --alpha 2 --beta 3
   86.73 ± 24.86 times faster than python scripts/sympy_gauss_jac.py --npts 5 --alpha 2 --beta 3 --n_dig 15
hyperfine --warmup 10 --export-markdown gjp_benchmarks.md       32.65s user 61.31s system 469% cpu 20.004 total

Or in other words:

CommandMean [ms]Min [ms]Max [ms]Relative
~gjp_quad 5 2. 3. “gw”~2.6 ± 0.81.87.81.03 ± 0.45
c_cli_gjpq 5 2 3 gw2.5 ± 0.71.88.41.00
gjquad_cli.py --npts 5 --alpha 2 --beta 397.5 ± 6.395.4130.839.08 ± 11.48
scipy_gauss_jac.py --npts 5 --alpha 2 --beta 3139.0 ± 10.6132.4173.455.71 ± 16.51
sympy_gauss_jac.py --npts 5 --alpha 2 --beta 3 --n_dig 15216.4 ± 1.7214.7219.786.73 ± 24.86

Which suggests what one might suspect, that there is a large overhead in calling python , and that the C and Fortran variants are almost exactly as fast as each other. However, the f2py variant is still way faster than the existing python implementations.

hyperfine --warmup 10 --export-markdown gjp_benchmarks.md \
    'PYTHONPATH=$(pwd) python interfaces/PyInterface/gjquad_cli.py --npts 5 --alpha 2 --beta 3' \
    'python scripts/scipy_gauss_jac.py --npts 5 --alpha 2 --beta 3'
Summary
  PYTHONPATH=$(pwd) python interfaces/PyInterface/gjquad_cli.py --npts 5 --alpha 2 --beta 3 ran
    1.38 ± 0.11 times faster than python scripts/scipy_gauss_jac.py --npts 5 --alpha 2 --beta 3

Development

Developing locally

A pre-commit job is setup on CI to enforce consistent styles, so it is best to set it up locally as well (using pipx for isolation):

# Run before commiting
pipx run pre-commit run --all-files
# Or install the git hook to enforce this
pipx run pre-commit install

Updating licenses

When the headers in the sources need to be updated modify add_headers.py and run:

python scripts/add_headers.py --dirs src/ interfaces/ --ftypes "f90,f77" --cchar '!'
python scripts/add_headers.py --dirs interfaces --ftypes "c,h" --cchar '//'
python scripts/add_headers.py --dirs interfaces scripts --ftypes "py" --cchar '#'

Remember to do this before exporting the code into other projects (e.g. featom).

License

MIT.

Citation

If you use this library (including the interfaces) please remember to cite it as:

Rohit Goswami. (2023). HaoZeke/GaussJacobiQuad: GaussJacobiQuad I (v0.1.0). Zenodo. https://doi.org/10.5281/ZENODO.8285112

Or use the bibtex entry:

@software{rgGaussQuad23,
  author       = {Rohit Goswami},
  title        = {HaoZeke/GaussJacobiQuad: GaussJacobiQuad I},
  month        = aug,
  year         = 2023,
  publisher    = {Zenodo},
  version      = {v0.1.0},
  doi          = {10.5281/zenodo.8285112},
  url          = {https://doi.org/10.5281/zenodo.8285112}
}

An ArXiv –> JOSS paper is in the works.

gaussjacobiquad's People

Contributors

haozeke avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

gaussjacobiquad's Issues

Plot the points and weights as a function of beta

Set alpha=0 and plot all points and weights as a function of beta. Then let's choose 0 <= beta <= 12 and fit the curve to machine accuracy using minimax polynomial and generate Fortran code that stores these coefficients for each point and weight for a select Nq (the number of points). We'll start with Nq=64, and we can choose, maybe we can just do Nq = 1, 2, 4, 8, 16, 32, 64, or something like that.

ENH: Add scaling logic

Currently these solvers implement the quadrature over the interval [-1, 1] but these can be scaled to arbitrary bounds.

ENH: Add the Golub Welsch

This is probably the most textbook approach, perhaps more known to the Fortran community via Algorithm 665, but the basic principle can be implemented with any diagonalization routine (e.g. from LAPACK).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.