diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c66ad55 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,154 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2017 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# EditorConfig configuration file (see ). + +# Indicate that this file is a root-level configuration file: +root = true + +# Set properties for all files: +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +# Set properties for JavaScript files: +[*.js] +indent_style = tab + +# Set properties for TypeScript files: +[*.ts] +indent_style = tab + +# Set properties for Python files: +[*.py] +indent_style = space +indent_size = 4 + +# Set properties for Julia files: +[*.jl] +indent_style = tab + +# Set properties for R files: +[*.R] +indent_style = tab + +# Set properties for C files: +[*.c] +indent_style = tab + +# Set properties for C header files: +[*.h] +indent_style = tab + +# Set properties for C++ files: +[*.cpp] +indent_style = tab + +# Set properties for C++ header files: +[*.hpp] +indent_style = tab + +# Set properties for Fortran files: +[*.f] +indent_style = space +indent_size = 2 +insert_final_newline = false + +# Set properties for shell files: +[*.sh] +indent_style = tab + +# Set properties for AWK files: +[*.awk] +indent_style = tab + +# Set properties for HTML files: +[*.html] +indent_style = tab +tab_width = 2 + +# Set properties for CSS files: +[*.css] +indent_style = tab + +# Set properties for Makefiles: +[Makefile] +indent_style = tab + +[*.mk] +indent_style = tab + +# Set properties for Markdown files: +[*.md] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = false + +# Set properties for `usage.txt` files: +[usage.txt] +indent_style = space +indent_size = 2 + +# Set properties for `repl.txt` files: +[repl.txt] +indent_style = space +indent_size = 4 + +# Set properties for `package.json` files: +[package.json] +indent_style = space +indent_size = 2 + +# Set properties for `datapackage.json` files: +[datapackage.json] +indent_style = space +indent_size = 2 + +# Set properties for `tslint.json` files: +[tslint.json] +indent_style = space +indent_size = 2 + +# Set properties for `tsconfig.json` files: +[tsconfig.json] +indent_style = space +indent_size = 2 + +# Set properties for LaTeX files: +[*.tex] +indent_style = tab + +# Set properties for LaTeX Bibliography files: +[*.bib] +indent_style = tab + +# Set properties for YAML files: +[*.yml] +indent_style = space +indent_size = 2 + +# Set properties for GYP files: +[binding.gyp] +indent_style = space +indent_size = 2 + +[*.gypi] +indent_style = space +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7212d81 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,33 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2017 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# Configuration file which assigns attributes to pathnames. +# +# [1]: https://git-scm.com/docs/gitattributes + +# Automatically normalize the line endings of any committed text files: +* text=auto + +# Override what is considered "vendored" by GitHub's linguist: +/deps/** linguist-vendored=false +/lib/node_modules/** linguist-vendored=false linguist-generated=false +test/fixtures/** linguist-vendored=false +tools/** linguist-vendored=false + +# Override what is considered "documentation" by GitHub's linguist: +examples/** linguist-documentation=false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..e7327d4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ + + +We are excited about your pull request, but unfortunately we are not accepting pull requests against this repository, as all development happens on the [main project repository](https://github.com/stdlib-js/stdlib). We kindly request that you submit this pull request against the [respective directory](https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/stats/base/smaxabs) of the main repository where we’ll review and provide feedback. + +If this is your first stdlib contribution, be sure to read the [contributing guide](https://github.com/stdlib-js/stdlib/blob/develop/CONTRIBUTING.md) which provides guidelines and instructions for submitting contributions. You may also consult the [development guide](https://github.com/stdlib-js/stdlib/blob/develop/docs/development.md) for help on developing stdlib. + +We look forward to receiving your contribution! :smiley: \ No newline at end of file diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000..e51e34e --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,19 @@ +name: benchmark + +on: + workflow_dispatch: + +jobs: + benchmark: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 15 + - name: Install production and development dependencies + run: | + npm install + - name: Run benchmarks + run: | + npm run benchmark diff --git a/.github/workflows/close_pull_requests.yml b/.github/workflows/close_pull_requests.yml new file mode 100644 index 0000000..3cd2ea0 --- /dev/null +++ b/.github/workflows/close_pull_requests.yml @@ -0,0 +1,23 @@ +name: Close Pull Requests + +on: + pull_request_target: + types: [opened] + +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: superbrothers/close-pull-request@v3 + with: + comment: | + Thank you for submitting a pull request. :raised_hands: + + We greatly appreciate your willingness to submit a contribution. However, we are not accepting pull requests against this repository, as all development happens on the [main project repository](https://github.com/stdlib-js/stdlib). + + We kindly request that you submit this pull request against the [respective directory](https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/stats/base/smaxabs) of the main repository where we’ll review and provide feedback. If this is your first stdlib contribution, be sure to read the [contributing guide](https://github.com/stdlib-js/stdlib/blob/develop/CONTRIBUTING.md) which provides guidelines and instructions for submitting contributions. + + Thank you again, and we look forward to receiving your contribution! :smiley: + + Best, + The stdlib team \ No newline at end of file diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml new file mode 100644 index 0000000..0c19f10 --- /dev/null +++ b/.github/workflows/examples.yml @@ -0,0 +1,19 @@ +name: examples + +on: + workflow_dispatch: + +jobs: + examples: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 15 + - name: Install production and development dependencies + run: | + npm install + - name: Run examples + run: | + npm run examples diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..ae05f51 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,34 @@ +name: Publish Package + +on: push + +jobs: + publish: + runs-on: ubuntu-latest + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 15 + - name: Increment version + run: | + git config --local user.email "noreply@stdlib.io" + git config --local user.name "stdlib-bot" + npm version patch + - name: Publish package to npm + uses: JS-DevTools/npm-publish@v1 + with: + token: ${{ secrets.NPM_TOKEN }} + access: public + - name: Push changes + run: | + git push origin main + git push --tags + - uses: act10ns/slack@v1 + with: + status: ${{ job.status }} + steps: ${{ toJson(steps) }} + channel: '#npm-ci' + if: failure() diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..3c99108 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,29 @@ +name: build + +on: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 15 + - name: Install production and development dependencies + id: install + run: | + npm install + - name: Run tests + id: tests + run: | + npm test + - uses: act10ns/slack@v1 + with: + status: ${{ job.status }} + steps: ${{ toJson(steps) }} + channel: '#npm-ci' + if: failure() diff --git a/.github/workflows/test_coverage.yml b/.github/workflows/test_coverage.yml new file mode 100644 index 0000000..0e8045d --- /dev/null +++ b/.github/workflows/test_coverage.yml @@ -0,0 +1,24 @@ +name: coverage + +on: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 15 + - name: Install production and development dependencies + run: | + npm install + - name: Calculate test coverage + run: | + npm run test-cov + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + directory: reports/coverage + flags: unittests diff --git a/.github/workflows/test_install.yml b/.github/workflows/test_install.yml new file mode 100644 index 0000000..ee70831 --- /dev/null +++ b/.github/workflows/test_install.yml @@ -0,0 +1,27 @@ +name: Test Installing Dependencies + +on: + workflow_run: + workflows: ["Publish Package"] + types: [completed] + +jobs: + on-success: + runs-on: ubuntu-latest + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + if: ${{ github.event.workflow_run.conclusion == 'success' }} + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: 15 + - name: Install production dependencies via npm + run: | + npm install --only=prod + - uses: act10ns/slack@v1 + with: + status: ${{ job.status }} + steps: ${{ toJson(steps) }} + channel: '#npm-ci' + if: failure() diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1475963 --- /dev/null +++ b/.gitignore @@ -0,0 +1,181 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2017 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# Files # +######### +.postinstall.json + +# Directories # +############### +build/ +downloads/ +reports/ +tmp/ + +# Compiled source # +################### +*.com +*.class +*.dll +*.o +*.so +*.slo +*.lo +*.obj +*.dylib +*.lai +*.la +*.a +*.lib +*.ko +*.elf +*.node + +# Precompiled headers # +####################### +*.gch +*.pch + +# Executables # +############### +*.exe +*.out +*.app + +# Packages # +############ +# It is better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Make an exception for compressed distributable files: +!dist/*.gz + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db +Desktop.ini + +# Temporary files # +################### +*~ + +# Node.js # +########### +/node_modules/ +lib/node_modules/**/node_modules/ +docs/**/node_modules/ +pids +*.pid +*.seed + +# Typescript # +############## +*.tsbuildinfo +lib/node_modules/**/tsconfig.json +lib/node_modules/**/tslint.json + +# Matlab # +########## +*.asv +*.mex* + +# Fortran # +########### +*.mod + +# R # +##### +.Rhistory +.Rapp.history +.Rproj.user/ + +# Python # +########## +__pycache__/ +*.py[cod] +*$py.class +*.egg-info/ + +# TeX # +####### +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.dvi +*-converted-to.* +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.brf +*.run.xml +*.fdb_latexmk +*.synctex +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync +*.alg +*.loa +acs-*.bib +*.thm +*.nav +*.snm +*.vrb +*.acn +*.acr +*.glg +*.glo +*.gls +*-concordance.tex +*.tikz +*-tikzDictionary +*.idx +*.ilg +*.ind +*.ist + +# Visual Studio # +################# +.vscode/ +jsconfig.json diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..401aa76 --- /dev/null +++ b/.npmignore @@ -0,0 +1,225 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2017 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# Files # +######### +CODE_OF_CONDUCT.md +CONTRIBUTING.md +CONTRIBUTORS +TODO.md +ROADMAP.md +.postinstall.json + +# Directories # +############### +.circleci/ +.github/ +**/benchmark/ +**/build/ +**/examples/ +reports/ +support/ +**/tmp/ +workshops/ + +# Ignore test directories, except for testing dependency installation: +**/test/ +!/deps/test/ + +# Only top-level directories: +/etc/ +/docs/ + +# Compiled source # +################### +*.com +*.class +*.dll +*.o +*.so +*.slo +*.lo +*.obj +*.dylib +*.lai +*.la +*.a +*.lib +*.ko +*.elf +*.node + +# Precompiled headers # +####################### +*.gch +*.pch + +# Executables # +############### +*.exe +*.out +*.app + +# Packages # +############ +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Make an exception for compressed distributable files: +!dist/*.gz + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db +Desktop.ini + +# Temporary files # +################### +*~ + +# Node.js # +########### +.npmignore + +# Only top-level node_modules: +/node_modules/ + +# TypeScript # +############## +tsconfig.json +tslint.json +*.tsbuildinfo + +# Matlab # +########## +*.asv +*.mex* + +# Fortran # +########### +*.mod + +# R # +##### +.Rhistory +.Rapp.history +.Rproj.user/ + +# Python # +########## +__pycache__/ +*.py[cod] +*$py.class +*.egg-info/ +.ipynb_checkpoints +setup.cfg +setup.py + +# TeX # +####### +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.dvi +*-converted-to.* +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.brf +*.run.xml +*.fdb_latexmk +*.synctex +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync +*.alg +*.loa +acs-*.bib +*.thm +*.nav +*.snm +*.vrb +*.acn +*.acr +*.glg +*.glo +*.gls +*-concordance.tex +*.tikz +*-tikzDictionary +*.idx +*.ilg +*.ind +*.ist + +# Git # +####### +.git* +.mailmap + +# Visual Studio # +################# +.vscode/ +jsconfig.json + +# Utilities # +############# +.jshintrc +.jshintignore +.eslintrc* +.eslintignore + +.pylintrc +.pycodestyle +.pydocstyle + +.travis.yml +circle.yml +appveyor.yml +azure-pipelines.yml + +.editorconfig +.codeclimate.yml +.codecov.yml + +.rtlintrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..36f5bef --- /dev/null +++ b/.npmrc @@ -0,0 +1,28 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2017 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# Configuration for [npm][1]. +# +# [1]: https://docs.npmjs.com/files/npmrc + +# Disable the creation of a lock file: +package-lock = false +shrinkwrap = false + +# Disable automatically "saving" dependencies on install: +save = false diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..35b70c9 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Code of Conduct + +stdlib expects community participants to adhere to the project Code of Conduct. The [full text](https://github.com/stdlib-js/stdlib/blob/develop/CODE_OF_CONDUCT.md) is available in the main project repository. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5f59443 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contribution Guidelines + +Woot woot! If you are new to stdlib, welcome! And thanks for your interest! Guidelines for how to contribute to the project are [available](https://github.com/stdlib-js/stdlib/blob/develop/CONTRIBUTING.md) in the main project repository. diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..da469e5 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,24 @@ +# This file is generated by tools/scripts/update_contributors. +# +# Contributors listed in alphabetical order. + +Athan Reines +Brendan Graetz +Bruno Fenzl +Christopher Dambamuromo +Dominik Moritz +Frank Kovacs +James +Jithin KS +Joey Reed +Joris Labie +Justin Dennison +Marcus +Matt Cochrane +Milan Raj +Ognjen Jevremović +Philipp Burckhardt +Ricky Reusser +Ryan Seal +Shraddheya Shendre +rei2hu diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fcc9934 --- /dev/null +++ b/LICENSE @@ -0,0 +1,481 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by this +license (the "Software") to use, reproduce, display, distribute, execute, and +transmit the Software, and to prepare derivative works of the Software, and to +permit third-parties to whom the Software is furnished to do so, all subject to +the following: + +The copyright notices in the Software and this entire statement, including the +above license grant, this restriction and the following disclaimer, must be +included in all copies of the Software, in whole or in part, and all derivative +works of the Software, unless such copies or derivative works are solely in the +form of machine-executable object code generated by a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES +OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + + +DEPENDENCIES + +The library links against the following external libraries, which have their own +licenses: + +* OpenBLAS + +Copyright (c) 2011-2014, The OpenBLAS Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. Neither the name of the OpenBLAS project nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* Electron + +Copyright (c) 2013-2017 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* Boost + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + +* Cephes + +Copyright (c) 1984-2000 Stephen L. Moshier + +Some software in this archive may be from the book _Methods and Programs for +Mathematical Functions_ (Prentice-Hall or Simon & Schuster International, 1989) +or from the Cephes Mathematical Library, a commercial product. In either event, +it is copyrighted by the author. What you see here may be used freely but it +comes with no support or guarantee. + +Stephen L. Moshier +moshier@na-net.ornl.gov + + + +ATTRIBUTION + +The library contains implementations from the following external libraries, +which have their own licenses: + +* FreeBSD + +Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunPro, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + + +* FDLIBM + +Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunPro, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + + +* Go + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* SLATEC Common Mathematical Library + +Public domain. + + +* ESLint + +Copyright JS Foundation and other contributors, https://js.foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +* StatsFuns.jl + +Copyright (c) 2015: Dahua Lin. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* SpecialFunctions.jl + +The MIT License (MIT) + +Copyright (c) 2017 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and others: + +https://github.com/JuliaMath/SpecialFunctions.jl/graphs/contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +* MT19937 + +Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1c7d53e --- /dev/null +++ b/Makefile @@ -0,0 +1,534 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2021 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# USER VARIABLES # + +ifndef VERBOSE + QUIET := @ +else + QUIET := +endif + +# Indicate whether to "fast" fail when linting, running tests, etc: +ifndef FAST_FAIL + FAIL_FAST := true +else +ifeq ($(FAST_FAIL), 0) + FAIL_FAST := false +else + FAIL_FAST := true +endif +endif + +# Define the `NODE_PATH` environment variable: +NODE_PATH ?= + +# Define the `NODE_ENV` environment variable: +NODE_ENV ?= + + +# INTERNAL VARIABLES # + +# Instruct make to warn us when we use an undefined variable (e.g., misspellings). +MAKEFLAGS += --warn-undefined-variables + +# Define the default target: +.DEFAULT_GOAL := all + +# Define the `SHELL` variable to avoid issues on systems where the variable may be inherited from the environment. +# +# ## Notes +# +# - We use `bash` so that we can use `pipefail`. +# +# +# [1]: https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html#Makefile-Basics +# [2]: http://clarkgrubb.com/makefile-style-guide +SHELL := bash + +# Define shell flags. +# +# ## Notes +# +# - `.SHELLFLAGS` was introduced in GNU Make 3.82 and has no effect on the version of GNU Make installed on Mac OS X, which is 3.81. +# - The `-e` flag causes `bash` to exit immediately if a `bash` executed command fails. +# - The `-u` flag causes `bash` to exit with an error message if a variable is accessed without being defined. +# - The `pipefail` option specifies that, if any of the commands in a pipeline fail, the entire pipeline fails. Otherwise the return value of a pipeline is the return value of the last command. +# - The `-c` flag is in the default value of `.SHELLFLAGS`, which must be preserved, as this is how `make` passes the script to be executed to `bash`. +# +.SHELLFLAGS := -eu -o pipefail -c + +# Remove targets if its recipe fails. +# +# ## Notes +# +# - Mentioning this target anywhere in a Makefile prevents a user from re-running make and using an incomplete or invalid target. +# - When debugging, it may be necessary to comment this line out so the incomplete or invalid target can be inspected. +# +# [1]: https://www.gnu.org/software/make/manual/html_node/Special-Targets.html +.DELETE_ON_ERROR: + +# Remove all the default suffixes, preferring to define all rules explicitly. +# +# [1]: https://www.gnu.org/software/make/manual/html_node/Suffix-Rules.html#Suffix-Rules +# [2]: https://www.gnu.org/software/make/manual/html_node/Suffix-Rules.html#Suffix-Rules +.SUFFIXES: + +# Determine the OS ([1][1], [2][2]). +# +# [1]: https://en.wikipedia.org/wiki/Uname#Examples +# [2]: http://stackoverflow.com/a/27776822/2225624 +OS ?= $(shell uname) +ifneq (, $(findstring MINGW,$(OS))) + OS := WINNT +else +ifneq (, $(findstring MSYS,$(OS))) + OS := WINNT +else +ifneq (, $(findstring CYGWIN,$(OS))) + OS := WINNT +else +ifneq (, $(findstring Windows_NT,$(OS))) + OS := WINNT +endif +endif +endif +endif + +# Determine the filename: +this_file := $(lastword $(MAKEFILE_LIST)) + +# Determine the absolute path of the Makefile (see http://blog.jgc.org/2007/01/what-makefile-am-i-in.html): +this_dir := $(dir $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))) + +# Remove the trailing slash: +this_dir := $(patsubst %/,%,$(this_dir)) + +# Determine root directory: +ROOT_DIR = $(this_dir) + +# Define the root build directory: +BUILD_DIR ?= $(ROOT_DIR)/build + +# Define the root directory for storing distributable files: +DIST_DIR ?= $(ROOT_DIR)/dist + +# Define the root directory for storing temporary files: +TMP_DIR ?= $(ROOT_DIR)/tmp + +# Define the directories for writing reports, including code coverage: +REPORTS_DIR ?= $(ROOT_DIR)/reports +COVERAGE_DIR ?= $(REPORTS_DIR)/coverage + +# Define the top-level directory containing node module dependencies: +NODE_MODULES ?= $(ROOT_DIR)/node_modules + +# Define the top-level directory containing node module executables: +BIN_DIR ?= $(NODE_MODULES)/.bin + +# Define the path to the root `package.json`: +ROOT_PACKAGE_JSON ?= $(ROOT_DIR)/package.json + +# Define the folder name convention for source files requiring compilation: +SRC_FOLDER ?= src + +# Define the folder name convention for documentation files: +DOCUMENTATION_FOLDER ?= docs + +# Define the folder name convention for configuration files: +CONFIG_FOLDER ?= etc + +# Define the folder name convention for benchmark files: +BENCHMARKS_FOLDER ?= benchmark + +# Define the folder name convention for benchmark fixtures: +BENCHMARKS_FIXTURES_FOLDER ?= $(BENCHMARKS_FOLDER)/fixtures + +# Define the folder name convention for examples files: +EXAMPLES_FOLDER ?= examples + +# Define the folder name convention for examples fixtures: +EXAMPLES_FIXTURES_FOLDER ?= $(EXAMPLES_FOLDER)/fixtures + +# Define the folder name convention for test files: +TESTS_FOLDER ?= test + +# Define the folder name convention for test fixtures: +TESTS_FIXTURES_FOLDER ?= $(TESTS_FOLDER)/fixtures + +# Define a filepath pattern for benchmark files: +BENCHMARKS_FILTER ?= .*/.* + +# Define a filepath pattern for example files: +EXAMPLES_FILTER ?= .*/.* + +# Define a filepath pattern for test files: +TESTS_FILTER ?= .*/.* + +# Define a filename pattern for benchmark files: +BENCHMARKS_PATTERN ?= benchmark*.js + +# Define a filename pattern for example files: +EXAMPLES_PATTERN ?= *.js + +# Define a filename pattern for test files: +TESTS_PATTERN ?= test*.js + +# Define Node environments: +ifdef NODE_ENV + NODE_ENV_BENCHMARK := $(NODE_ENV) + NODE_ENV_EXAMPLES := $(NODE_ENV) + NODE_ENV_TEST := $(NODE_ENV) +else + NODE_ENV ?= + NODE_ENV_BENCHMARK ?= benchmark + NODE_ENV_EXAMPLES ?= examples + NODE_ENV_TEST ?= test +endif + +# Define whether delete operations should be safe (i.e., deleted items are sent to trash, rather than permanently deleted): +SAFE_DELETE ?= false + +# Define the delete command: +ifeq ($(SAFE_DELETE), true) + # FIXME: -rm -rf + DELETE := -rm + DELETE_FLAGS := -rf +else + DELETE ?= -rm + DELETE_FLAGS ?= -rf +endif + +# Determine the `open` command: +ifeq ($(OS), Darwin) + OPEN ?= open +else + OPEN ?= xdg-open +endif +# TODO: add Windows command + +# Define the command for `node`: +NODE ?= node + +# Define the command for `npm`: +NPM ?= npm + +# Define the path to a JavaScript test runner. +# +# ## Notes +# +# - We reference the `bin` file directly in order to support using `istanbul` for code coverage on Windows (https://github.com/gotwarlost/istanbul#usage-on-windows) +JAVASCRIPT_TEST ?= $(NODE_MODULES)/tape/bin/tape + +# Define any command-line options to use when invoking the test runner: +JAVASCRIPT_TEST_FLAGS ?= + +# Define the path to the executable for parsing TAP output: +TAP_REPORTER ?= $(BIN_DIR)/tap-spec + +# Define the path to the Istanbul executable: +ISTANBUL ?= $(BIN_DIR)/istanbul + +# Define which files and directories to exclude from coverage instrumentation: +ISTANBUL_EXCLUDES_FLAGS ?= \ + --no-default-excludes \ + -x 'node_modules/**' \ + -x 'reports/**' \ + -x 'tmp/**' \ + -x 'deps/**' \ + -x 'dist/**' \ + -x "**/$(SRC_FOLDER)/**" \ + -x "**/$(TESTS_FOLDER)/**" \ + -x "**/$(EXAMPLES_FOLDER)/**" \ + -x "**/$(BENCHMARKS_FOLDER)/**" \ + -x "**/$(CONFIG_FOLDER)/**" \ + -x "**/$(DOCUMENTATION_FOLDER)/**" + +# Define the command to generate test coverage: +ISTANBUL_COVER ?= $(ISTANBUL) cover + +# Define the type of report Istanbul should produce: +ISTANBUL_COVER_REPORT_FORMAT ?= lcov + +# Define the command-line options to be used when generating code coverage: +ISTANBUL_COVER_FLAGS ?= \ + $(ISTANBUL_EXCLUDES_FLAGS) \ + --dir $(COVERAGE_DIR) \ + --report $(ISTANBUL_COVER_REPORT_FORMAT) + +# On Mac OSX, in order to use `|` and other regular expression operators, we need to use enhanced regular expression syntax (-E); see https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man7/re_format.7.html#//apple_ref/doc/man/7/re_format. +ifeq ($(OS), Darwin) + find_kernel_prefix := -E +else + find_kernel_prefix := +endif + +# Common exclude flags that most recipes for finding package files should use (Note: order does matter to some degree): +FIND_COMMON_EXCLUDE_FLAGS ?= \ + -not -path "$(ROOT_DIR)/.*" \ + -not -path "$(NODE_MODULES)/*" \ + -not -path "$(BUILD_DIR)/*" \ + -not -path "$(REPORTS_DIR)/*" \ + +# Define exclusion flags to use when searching for benchmark files: +FIND_BENCHMARKS_EXCLUDE_FLAGS ?= \ + $(FIND_COMMON_EXCLUDE_FLAGS) \ + -not -path "$(ROOT_DIR)/**/$(BENCHMARKS_FIXTURES_FOLDER)/*" + +# Define flags for finding benchmark files: +FIND_BENCHMARKS_FLAGS ?= \ + -type f \ + -name "$(BENCHMARKS_PATTERN)" \ + -path "$(ROOT_DIR)/**/$(BENCHMARKS_FOLDER)/**" \ + -regex "$(BENCHMARKS_FILTER)" \ + $(FIND_BENCHMARKS_EXCLUDE_FLAGS) + +ifneq ($(OS), Darwin) + FIND_BENCHMARKS_FLAGS := -regextype posix-extended $(FIND_BENCHMARKS_FLAGS) +endif + +# Define a command to list benchmark files: +FIND_BENCHMARKS_CMD ?= find $(find_kernel_prefix) $(ROOT_DIR) $(FIND_BENCHMARKS_FLAGS) + +# Define exclusion flags to use when searching for examples files: +FIND_EXAMPLES_EXCLUDE_FLAGS ?= \ + $(FIND_COMMON_EXCLUDE_FLAGS) \ + -not -path "$(ROOT_DIR)/**/$(EXAMPLES_FIXTURES_FOLDER)/*" + +# Define flags for finding examples files: +FIND_EXAMPLES_FLAGS ?= \ + -type f \ + -name "$(EXAMPLES_PATTERN)" \ + -path "$(ROOT_DIR)/**/$(EXAMPLES_FOLDER)/**" \ + -regex "$(EXAMPLES_FILTER)" \ + $(FIND_EXAMPLES_EXCLUDE_FLAGS) + +ifneq ($(OS), Darwin) + FIND_EXAMPLES_FLAGS := -regextype posix-extended $(FIND_EXAMPLES_FLAGS) +endif + +# Define a command to list example files: +FIND_EXAMPLES_CMD ?= find $(find_kernel_prefix) $(ROOT_DIR) $(FIND_EXAMPLES_FLAGS) + +# Define exclusion flags to use when searching for test files: +FIND_TESTS_EXCLUDE_FLAGS ?= \ + $(FIND_COMMON_EXCLUDE_FLAGS) \ + -not -path "$(ROOT_DIR)/**/$(TESTS_FIXTURES_FOLDER)/*" + +# Define flags for finding test files: +FIND_TESTS_FLAGS ?= \ + -type f \ + -name "$(TESTS_PATTERN)" \ + -regex "$(TESTS_FILTER)" \ + $(FIND_TESTS_EXCLUDE_FLAGS) + +ifneq ($(OS), Darwin) + FIND_TESTS_FLAGS := -regextype posix-extended $(FIND_TESTS_FLAGS) +endif + +# Define a command to list test files: +FIND_TESTS_CMD ?= find $(find_kernel_prefix) $(ROOT_DIR) $(FIND_TESTS_FLAGS) + + +# RULES # + +#/ +# Default target. +# +# @example +# make +# +# @example +# make all +#/ +all: help + +.PHONY: all + +#/ +# Prints a `Makefile` help message. +# +# @example +# make help +#/ +help: + $(QUIET) echo 'Read the Makefile to see the list of available commands.' + $(QUIET) echo '' + +.PHONY: help + +#/ +# Prints the runtime value of a `Makefile` variable. +# +# ## Notes +# +# - The rule uses the following format: +# +# ```bash +# $ make inspect. +# ``` +# +# @example +# make inspect.ROOT_DIR +# +# @example +# make inspect.CC +#/ +inspect.%: + $(QUIET) echo '$*=$($*)' + +#/ +# Runs the project's install sequence. +# +# @example +# make install +#/ +install: + $(NPM) install + +.PHONY: install + +#/ +# Removes node module dependencies. +# +# @example +# make clean-node +#/ +clean-node: + $(QUIET) $(DELETE) $(DELETE_FLAGS) $(NODE_MODULES) + +#/ +# Runs the project's cleanup sequence. +# +# @example +# make clean +#/ +clean: clean-node clean-cov + $(QUIET) $(DELETE) $(DELETE_FLAGS) $(BUILD_DIR) + $(QUIET) $(DELETE) $(DELETE_FLAGS) $(REPORTS_DIR) + +.PHONY: clean + +#/ +# Runs JavaScript benchmarks consecutively. +# +# ## Notes +# +# - The recipe assumes that benchmark files can be run via Node.js. +# - This rule is useful when wanting to glob for JavaScript benchmark files (e.g., run all JavaScript benchmarks for a particular package). +# +# +# @param {string} [BENCHMARKS_FILTER] - file path pattern (e.g., `.*/utils/group-by/.*`) +# +# @example +# make benchmark +# +# @example +# make benchmark BENCHMARKS_FILTER=".*/utils/group-by/.*" +#/ +benchmark: $(NODE_MODULES) + $(QUIET) $(FIND_BENCHMARKS_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \ + echo ""; \ + echo "Running benchmark: $$file"; \ + NODE_ENV="$(NODE_ENV_BENCHMARK)" \ + NODE_PATH="$(NODE_PATH)" \ + $(NODE) $$file || exit 1; \ + done + +.PHONY: benchmark + +#/ +# Runs JavaScript examples consecutively. +# +# ## Notes +# +# - This rule is useful when wanting to glob for JavaScript examples files (e.g., run all JavaScript examples for a particular package). +# - This rule **assumes** that examples files can be run using Node.js. +# +# +# @param {string} [EXAMPLES_FILTER] - file path pattern (e.g., `.*/math/base/special/abs/.*`) +# +# @example +# make examples +# +# @example +# make examples EXAMPLES_FILTER=".*/strided/common/.*" +#/ +examples: $(NODE_MODULES) + $(QUIET) $(FIND_EXAMPLES_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \ + echo ""; \ + echo "Running example: $$file"; \ + NODE_ENV="$(NODE_ENV_EXAMPLES)" \ + NODE_PATH="$(NODE_PATH)" \ + $(NODE) $$file || exit 1; \ + done + +.PHONY: examples + +#/ +# Runs JavaScript tests consecutively. +# +# ## Notes +# +# - This rule is useful when wanting to glob for JavaScript test files (e.g., run all JavaScript tests for a particular package). +# - This rule **assumes** that test files can be run using Node.js. +# +# +# @param {string} [TEST_FILTER] - file path pattern (e.g., `.*/math/base/special/abs/.*`) +# +# @example +# make test +# +# @example +# make test TESTS_FILTER=".*/strided/common/.*" +#/ +test: $(NODE_MODULES) + $(QUIET) $(FIND_TESTS_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r test; do \ + echo ''; \ + echo "Running test: $$test"; \ + NODE_ENV="$(NODE_ENV_TEST)" \ + NODE_PATH="$(NODE_PATH)" \ + $(JAVASCRIPT_TEST) \ + $(JAVASCRIPT_TEST_FLAGS) \ + $$test \ + | $(TAP_REPORTER) || exit 1; \ + done + +.PHONY: test + +#/ +# Runs unit tests and generate a test coverage report. +# +# @example +# make test-cov +#/ +test-cov: clean-cov + $(QUIET) NODE_ENV="$(NODE_ENV_TEST)" \ + NODE_PATH="$(NODE_PATH)" \ + $(ISTANBUL_COVER) $(ISTANBUL_COVER_FLAGS) $(JAVASCRIPT_TEST) -- $$( $(FIND_TESTS_CMD) ) + +.PHONY: test-cov + +#/ +# Removes a test coverage directory. +# +# @example +# make clean-cov +#/ +clean-cov: + $(QUIET) $(DELETE) $(DELETE_FLAGS) $(COVERAGE_DIR) diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..f5374f6 --- /dev/null +++ b/NOTICE @@ -0,0 +1 @@ +Copyright (c) 2016-2021 The Stdlib Authors. diff --git a/README.md b/README.md new file mode 100644 index 0000000..17eb26b --- /dev/null +++ b/README.md @@ -0,0 +1,229 @@ + + +# smaxabs + +[![NPM version][npm-image]][npm-url] [![Build Status][test-image]][test-url] [![Coverage Status][coverage-image]][coverage-url] [![dependencies][dependencies-image]][dependencies-url] + +> Calculate the maximum absolute value of a single-precision floating-point strided array. + +
+ +
+ + + +
+ +## Installation + +```bash +npm install @stdlib/stats-base-smaxabs +``` + +
+ +
+ +## Usage + +```javascript +var smaxabs = require( '@stdlib/stats-base-smaxabs' ); +``` + +#### smaxabs( N, x, stride ) + +Computes the maximum absolute value of a single-precision floating-point strided array `x`. + +```javascript +var Float32Array = require( '@stdlib/array-float32' ); + +var x = new Float32Array( [ 1.0, -2.0, 2.0 ] ); +var N = x.length; + +var v = smaxabs( N, x, 1 ); +// returns 2.0 +``` + +The function has the following parameters: + +- **N**: number of indexed elements. +- **x**: input [`Float32Array`][@stdlib/array/float32]. +- **stride**: index increment for `x`. + +The `N` and `stride` parameters determine which elements in `x` are accessed at runtime. For example, to compute the maximum absolute value of every other element in `x`, + +```javascript +var Float32Array = require( '@stdlib/array-float32' ); +var floor = require( '@stdlib/math-base-special-floor' ); + +var x = new Float32Array( [ 1.0, 2.0, 2.0, -7.0, -2.0, 3.0, 4.0, 2.0 ] ); +var N = floor( x.length / 2 ); + +var v = smaxabs( N, x, 2 ); +// returns 4.0 +``` + +Note that indexing is relative to the first index. To introduce an offset, use [`typed array`][mdn-typed-array] views. + + + +```javascript +var Float32Array = require( '@stdlib/array-float32' ); +var floor = require( '@stdlib/math-base-special-floor' ); + +var x0 = new Float32Array( [ 2.0, 1.0, 2.0, -2.0, -2.0, 2.0, 3.0, 4.0 ] ); +var x1 = new Float32Array( x0.buffer, x0.BYTES_PER_ELEMENT*1 ); // start at 2nd element + +var N = floor( x0.length / 2 ); + +var v = smaxabs( N, x1, 2 ); +// returns 4.0 +``` + +#### smaxabs.ndarray( N, x, stride, offset ) + +Computes the maximum absolute value of a single-precision floating-point strided array using alternative indexing semantics. + +```javascript +var Float32Array = require( '@stdlib/array-float32' ); + +var x = new Float32Array( [ 1.0, -2.0, 2.0 ] ); +var N = x.length; + +var v = smaxabs.ndarray( N, x, 1, 0 ); +// returns 2.0 +``` + +The function has the following additional parameters: + +- **offset**: starting index for `x`. + +While [`typed array`][mdn-typed-array] views mandate a view offset based on the underlying `buffer`, the `offset` parameter supports indexing semantics based on a starting index. For example, to calculate the maximum absolute value for every other value in `x` starting from the second value + +```javascript +var Float32Array = require( '@stdlib/array-float32' ); +var floor = require( '@stdlib/math-base-special-floor' ); + +var x = new Float32Array( [ 2.0, 1.0, 2.0, -2.0, -2.0, 2.0, 3.0, 4.0 ] ); +var N = floor( x.length / 2 ); + +var v = smaxabs.ndarray( N, x, 2, 1 ); +// returns 4.0 +``` + +
+ + + +
+ +## Notes + +- If `N <= 0`, both functions return `NaN`. + +
+ + + +
+ +## Examples + + + +```javascript +var randu = require( '@stdlib/random-base-randu' ); +var round = require( '@stdlib/math-base-special-round' ); +var Float32Array = require( '@stdlib/array-float32' ); +var smaxabs = require( '@stdlib/stats-base-smaxabs' ); + +var x; +var i; + +x = new Float32Array( 10 ); +for ( i = 0; i < x.length; i++ ) { + x[ i ] = round( (randu()*100.0) - 50.0 ); +} +console.log( x ); + +var v = smaxabs( x.length, x, 1 ); +console.log( v ); +``` + +
+ + + + +
+ +* * * + +## Notice + +This package is part of [stdlib][stdlib], a standard library for JavaScript and Node.js, with an emphasis on numerical and scientific computing. The library provides a collection of robust, high performance libraries for mathematics, statistics, streams, utilities, and more. + +For more information on the project, filing bug reports and feature requests, and guidance on how to develop [stdlib][stdlib], see the main project [repository][stdlib]. + +--- + +## License + +See [LICENSE][stdlib-license]. + + +## Copyright + +Copyright © 2016-2021. The Stdlib [Authors][stdlib-authors]. + +
+ + + + + + + + diff --git a/benchmark/benchmark.js b/benchmark/benchmark.js new file mode 100644 index 0000000..22b27df --- /dev/null +++ b/benchmark/benchmark.js @@ -0,0 +1,96 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var randu = require( '@stdlib/random-base-randu' ); +var isnan = require( '@stdlib/math-base-assert-is-nan' ); +var pow = require( '@stdlib/math-base-special-pow' ); +var Float32Array = require( '@stdlib/array-float32' ); +var pkg = require( './../package.json' ).name; +var smaxabs = require( './../lib/smaxabs.js' ); + + +// FUNCTIONS // + +/** +* Creates a benchmark function. +* +* @private +* @param {PositiveInteger} len - array length +* @returns {Function} benchmark function +*/ +function createBenchmark( len ) { + var x; + var i; + + x = new Float32Array( len ); + for ( i = 0; i < x.length; i++ ) { + x[ i ] = ( randu()*20.0 ) - 10.0; + } + return benchmark; + + function benchmark( b ) { + var v; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + v = smaxabs( x.length, x, 1 ); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); + } +} + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var len; + var min; + var max; + var f; + var i; + + min = 1; // 10^min + max = 6; // 10^max + + for ( i = min; i <= max; i++ ) { + len = pow( 10, i ); + f = createBenchmark( len ); + bench( pkg+':len='+len, f ); + } +} + +main(); diff --git a/benchmark/benchmark.native.js b/benchmark/benchmark.native.js new file mode 100644 index 0000000..25e8796 --- /dev/null +++ b/benchmark/benchmark.native.js @@ -0,0 +1,105 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var bench = require( '@stdlib/bench' ); +var randu = require( '@stdlib/random-base-randu' ); +var isnan = require( '@stdlib/math-base-assert-is-nan' ); +var pow = require( '@stdlib/math-base-special-pow' ); +var Float32Array = require( '@stdlib/array-float32' ); +var tryRequire = require( '@stdlib/utils-try-require' ); +var pkg = require( './../package.json' ).name; + + +// VARIABLES // + +var smaxabs = tryRequire( resolve( __dirname, './../lib/smaxabs.native.js' ) ); +var opts = { + 'skip': ( smaxabs instanceof Error ) +}; + + +// FUNCTIONS // + +/** +* Creates a benchmark function. +* +* @private +* @param {PositiveInteger} len - array length +* @returns {Function} benchmark function +*/ +function createBenchmark( len ) { + var x; + var i; + + x = new Float32Array( len ); + for ( i = 0; i < x.length; i++ ) { + x[ i ] = ( randu()*20.0 ) - 10.0; + } + return benchmark; + + function benchmark( b ) { + var v; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + v = smaxabs( x.length, x, 1 ); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); + } +} + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var len; + var min; + var max; + var f; + var i; + + min = 1; // 10^min + max = 6; // 10^max + + for ( i = min; i <= max; i++ ) { + len = pow( 10, i ); + f = createBenchmark( len ); + bench( pkg+'::native:len='+len, opts, f ); + } +} + +main(); diff --git a/benchmark/benchmark.ndarray.js b/benchmark/benchmark.ndarray.js new file mode 100644 index 0000000..23e6519 --- /dev/null +++ b/benchmark/benchmark.ndarray.js @@ -0,0 +1,96 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var randu = require( '@stdlib/random-base-randu' ); +var isnan = require( '@stdlib/math-base-assert-is-nan' ); +var pow = require( '@stdlib/math-base-special-pow' ); +var Float32Array = require( '@stdlib/array-float32' ); +var pkg = require( './../package.json' ).name; +var smaxabs = require( './../lib/ndarray.js' ); + + +// FUNCTIONS // + +/** +* Creates a benchmark function. +* +* @private +* @param {PositiveInteger} len - array length +* @returns {Function} benchmark function +*/ +function createBenchmark( len ) { + var x; + var i; + + x = new Float32Array( len ); + for ( i = 0; i < x.length; i++ ) { + x[ i ] = ( randu()*20.0 ) - 10.0; + } + return benchmark; + + function benchmark( b ) { + var v; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + v = smaxabs( x.length, x, 1, 0 ); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); + } +} + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var len; + var min; + var max; + var f; + var i; + + min = 1; // 10^min + max = 6; // 10^max + + for ( i = min; i <= max; i++ ) { + len = pow( 10, i ); + f = createBenchmark( len ); + bench( pkg+':ndarray:len='+len, f ); + } +} + +main(); diff --git a/benchmark/benchmark.ndarray.native.js b/benchmark/benchmark.ndarray.native.js new file mode 100644 index 0000000..2c34e73 --- /dev/null +++ b/benchmark/benchmark.ndarray.native.js @@ -0,0 +1,105 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var bench = require( '@stdlib/bench' ); +var randu = require( '@stdlib/random-base-randu' ); +var isnan = require( '@stdlib/math-base-assert-is-nan' ); +var pow = require( '@stdlib/math-base-special-pow' ); +var Float32Array = require( '@stdlib/array-float32' ); +var tryRequire = require( '@stdlib/utils-try-require' ); +var pkg = require( './../package.json' ).name; + + +// VARIABLES // + +var smaxabs = tryRequire( resolve( __dirname, './../lib/ndarray.native.js' ) ); +var opts = { + 'skip': ( smaxabs instanceof Error ) +}; + + +// FUNCTIONS // + +/** +* Creates a benchmark function. +* +* @private +* @param {PositiveInteger} len - array length +* @returns {Function} benchmark function +*/ +function createBenchmark( len ) { + var x; + var i; + + x = new Float32Array( len ); + for ( i = 0; i < x.length; i++ ) { + x[ i ] = ( randu()*20.0 ) - 10.0; + } + return benchmark; + + function benchmark( b ) { + var v; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + v = smaxabs( x.length, x, 1, 0 ); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); + } +} + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var len; + var min; + var max; + var f; + var i; + + min = 1; // 10^min + max = 6; // 10^max + + for ( i = min; i <= max; i++ ) { + len = pow( 10, i ); + f = createBenchmark( len ); + bench( pkg+'::native:ndarray:len='+len, opts, f ); + } +} + +main(); diff --git a/benchmark/c/Makefile b/benchmark/c/Makefile new file mode 100644 index 0000000..7280962 --- /dev/null +++ b/benchmark/c/Makefile @@ -0,0 +1,146 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2020 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# VARIABLES # + +ifndef VERBOSE + QUIET := @ +else + QUIET := +endif + +# Determine the OS ([1][1], [2][2]). +# +# [1]: https://en.wikipedia.org/wiki/Uname#Examples +# [2]: http://stackoverflow.com/a/27776822/2225624 +OS ?= $(shell uname) +ifneq (, $(findstring MINGW,$(OS))) + OS := WINNT +else +ifneq (, $(findstring MSYS,$(OS))) + OS := WINNT +else +ifneq (, $(findstring CYGWIN,$(OS))) + OS := WINNT +else +ifneq (, $(findstring Windows_NT,$(OS))) + OS := WINNT +endif +endif +endif +endif + +# Define the program used for compiling C source files: +ifdef C_COMPILER + CC := $(C_COMPILER) +else + CC := gcc +endif + +# Define the command-line options when compiling C files: +CFLAGS ?= \ + -std=c99 \ + -O3 \ + -Wall \ + -pedantic + +# Determine whether to generate position independent code ([1][1], [2][2]). +# +# [1]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options +# [2]: http://stackoverflow.com/questions/5311515/gcc-fpic-option +ifeq ($(OS), WINNT) + fPIC ?= +else + fPIC ?= -fPIC +endif + +# List of includes (e.g., `-I /foo/bar -I /beep/boop/include`): +INCLUDE ?= + +# List of source files: +SOURCE_FILES ?= + +# List of libraries (e.g., `-lopenblas -lpthread`): +LIBRARIES ?= + +# List of library paths (e.g., `-L /foo/bar -L /beep/boop`): +LIBPATH ?= + +# List of C targets: +c_targets := benchmark.length.out + + +# RULES # + +#/ +# Compiles source files. +# +# @param {string} [C_COMPILER] - C compiler (e.g., `gcc`) +# @param {string} [CFLAGS] - C compiler options +# @param {(string|void)} [fPIC] - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} [INCLUDE] - list of includes (e.g., `-I /foo/bar -I /beep/boop/include`) +# @param {string} [SOURCE_FILES] - list of source files +# @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) +# @param {string} [LIBRARIES] - list of libraries (e.g., `-lopenblas -lpthread`) +# +# @example +# make +# +# @example +# make all +#/ +all: $(c_targets) + +.PHONY: all + +#/ +# Compiles C source files. +# +# @private +# @param {string} CC - C compiler (e.g., `gcc`) +# @param {string} CFLAGS - C compiler options +# @param {(string|void)} fPIC - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} INCLUDE - list of includes (e.g., `-I /foo/bar`) +# @param {string} SOURCE_FILES - list of source files +# @param {string} LIBPATH - list of library paths (e.g., `-L /foo/bar`) +# @param {string} LIBRARIES - list of libraries (e.g., `-lopenblas`) +#/ +$(c_targets): %.out: %.c + $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + +#/ +# Runs compiled benchmarks. +# +# @example +# make run +#/ +run: $(c_targets) + $(QUIET) ./$< + +.PHONY: run + +#/ +# Removes generated files. +# +# @example +# make clean +#/ +clean: + $(QUIET) -rm -f *.o *.out + +.PHONY: clean diff --git a/benchmark/c/benchmark.length.c b/benchmark/c/benchmark.length.c new file mode 100644 index 0000000..6af79e9 --- /dev/null +++ b/benchmark/c/benchmark.length.c @@ -0,0 +1,153 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* Benchmark `smaxabs`. +*/ +#include "stdlib/stats/base/smaxabs.h" +#include +#include +#include +#include +#include + +#define NAME "smaxabs" +#define ITERATIONS 1000000 +#define REPEATS 3 +#define MIN 1 +#define MAX 6 + +/** +* Prints the TAP version. +*/ +void print_version() { + printf( "TAP version 13\n" ); +} + +/** +* Prints the TAP summary. +* +* @param total total number of tests +* @param passing total number of passing tests +*/ +void print_summary( int total, int passing ) { + printf( "#\n" ); + printf( "1..%d\n", total ); // TAP plan + printf( "# total %d\n", total ); + printf( "# pass %d\n", passing ); + printf( "#\n" ); + printf( "# ok\n" ); +} + +/** +* Prints benchmarks results. +* +* @param iterations number of iterations +* @param elapsed elapsed time in seconds +*/ +void print_results( int iterations, double elapsed ) { + double rate = (double)iterations / elapsed; + printf( " ---\n" ); + printf( " iterations: %d\n", iterations ); + printf( " elapsed: %0.9f\n", elapsed ); + printf( " rate: %0.9f\n", rate ); + printf( " ...\n" ); +} + +/** +* Returns a clock time. +* +* @return clock time +*/ +double tic() { + struct timeval now; + gettimeofday( &now, NULL ); + return (double)now.tv_sec + (double)now.tv_usec/1.0e6; +} + +/** +* Generates a random number on the interval [0,1]. +* +* @return random number +*/ +float rand_float() { + int r = rand(); + return (float)r / ( (float)RAND_MAX + 1.0f ); +} + +/* +* Runs a benchmark. +* +* @param iterations number of iterations +* @param len array length +* @return elapsed time in seconds +*/ +double benchmark( int iterations, int len ) { + double elapsed; + float x[ len ]; + float v; + double t; + int i; + + for ( i = 0; i < len; i++ ) { + x[ i ] = ( rand_float()*20000.0f ) - 10000.0f; + } + t = tic(); + for ( i = 0; i < iterations; i++ ) { + v = stdlib_strided_smaxabs( len, x, 1 ); + if ( v != v ) { + printf( "should not return NaN\n" ); + break; + } + } + elapsed = tic() - t; + if ( v != v ) { + printf( "should not return NaN\n" ); + } + return elapsed; +} + +/** +* Main execution sequence. +*/ +int main( void ) { + double elapsed; + int count; + int iter; + int len; + int i; + int j; + + // Use the current time to seed the random number generator: + srand( time( NULL ) ); + + print_version(); + count = 0; + for ( i = MIN; i <= MAX; i++ ) { + len = pow( 10, i ); + iter = ITERATIONS / pow( 10, i-1 ); + for ( j = 0; j < REPEATS; j++ ) { + count += 1; + printf( "# c::%s:len=%d\n", NAME, len ); + elapsed = benchmark( iter, len ); + print_results( iter, elapsed ); + printf( "ok %d benchmark finished\n", count ); + } + } + print_summary( count, count ); +} diff --git a/binding.gyp b/binding.gyp new file mode 100644 index 0000000..7d0005b --- /dev/null +++ b/binding.gyp @@ -0,0 +1,170 @@ +# @license Apache-2.0 +# +# Copyright (c) 2020 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A `.gyp` file for building a Node.js native add-on. +# +# [1]: https://gyp.gsrc.io/docs/InputFormatReference.md +# [2]: https://gyp.gsrc.io/docs/UserDocumentation.md +{ + # List of files to include in this file: + 'includes': [ + './include.gypi', + ], + + # Define variables to be used throughout the configuration for all targets: + 'variables': { + # Target name should match the add-on export name: + 'addon_target_name%': 'addon', + + # Set variables based on the host OS: + 'conditions': [ + [ + 'OS=="win"', + { + # Define the object file suffix: + 'obj': 'obj', + }, + { + # Define the object file suffix: + 'obj': 'o', + } + ], # end condition (OS=="win") + ], # end conditions + }, # end variables + + # Define compile targets: + 'targets': [ + + # Target to generate an add-on: + { + # The target name should match the add-on export name: + 'target_name': '<(addon_target_name)', + + # Define dependencies: + 'dependencies': [], + + # Define directories which contain relevant include headers: + 'include_dirs': [ + # Local include directory: + '<@(include_dirs)', + ], + + # List of source files: + 'sources': [ + '<@(src_files)', + ], + + # Settings which should be applied when a target's object files are used as linker input: + 'link_settings': { + # Define libraries: + 'libraries': [ + '<@(libraries)', + ], + + # Define library directories: + 'library_dirs': [ + '<@(library_dirs)', + ], + }, + + # C/C++ compiler flags: + 'cflags': [ + # Enable commonly used warning options: + '-Wall', + + # Aggressive optimization: + '-O3', + ], + + # C specific compiler flags: + 'cflags_c': [ + # Specify the C standard to which a program is expected to conform: + '-std=c99', + ], + + # C++ specific compiler flags: + 'cflags_cpp': [ + # Specify the C++ standard to which a program is expected to conform: + '-std=c++11', + ], + + # Linker flags: + 'ldflags': [], + + # Apply conditions based on the host OS: + 'conditions': [ + [ + 'OS=="mac"', + { + # Linker flags: + 'ldflags': [ + '-undefined dynamic_lookup', + '-Wl,-no-pie', + '-Wl,-search_paths_first', + ], + }, + ], # end condition (OS=="mac") + [ + 'OS!="win"', + { + # C/C++ flags: + 'cflags': [ + # Generate platform-independent code: + '-fPIC', + ], + }, + ], # end condition (OS!="win") + ], # end conditions + }, # end target <(addon_target_name) + + # Target to copy a generated add-on to a standard location: + { + 'target_name': 'copy_addon', + + # Declare that the output of this target is not linked: + 'type': 'none', + + # Define dependencies: + 'dependencies': [ + # Require that the add-on be generated before building this target: + '<(addon_target_name)', + ], + + # Define a list of actions: + 'actions': [ + { + 'action_name': 'copy_addon', + 'message': 'Copying addon...', + + # Explicitly list the inputs in the command-line invocation below: + 'inputs': [], + + # Declare the expected outputs: + 'outputs': [ + '<(addon_output_dir)/<(addon_target_name).node', + ], + + # Define the command-line invocation: + 'action': [ + 'cp', + '<(PRODUCT_DIR)/<(addon_target_name).node', + '<(addon_output_dir)/<(addon_target_name).node', + ], + }, + ], # end actions + }, # end target copy_addon + ], # end targets +} diff --git a/docs/repl.txt b/docs/repl.txt new file mode 100644 index 0000000..4b4f537 --- /dev/null +++ b/docs/repl.txt @@ -0,0 +1,94 @@ + +{{alias}}( N, x, stride ) + Computes the maximum absolute value of a single-precision floating-point + strided array. + + The `N` and `stride` parameters determine which elements in `x` are accessed + at runtime. + + Indexing is relative to the first index. To introduce an offset, use a typed + array view. + + If `N <= 0`, the function returns `NaN`. + + Parameters + ---------- + N: integer + Number of indexed elements. + + x: Float32Array + Input array. + + stride: integer + Index increment. + + Returns + ------- + out: number + Maximum absolute value. + + Examples + -------- + // Standard Usage: + > var x = new {{alias:@stdlib/array/float32}}( [ 1.0, -2.0, 2.0 ] ); + > {{alias}}( x.length, x, 1 ) + 2.0 + + // Using `N` and `stride` parameters: + > x = new {{alias:@stdlib/array/float32}}( [ -2.0, 1.0, 1.0, -5.0, 2.0, -1.0 ] ); + > var N = {{alias:@stdlib/math/base/special/floor}}( x.length / 2 ); + > var stride = 2; + > {{alias}}( N, x, stride ) + 2.0 + + // Using view offsets: + > var x0 = new {{alias:@stdlib/array/float32}}( [ 1.0, -2.0, 3.0, 2.0, 5.0, -1.0 ] ); + > var x1 = new {{alias:@stdlib/array/float32}}( x0.buffer, x0.BYTES_PER_ELEMENT*1 ); + > N = {{alias:@stdlib/math/base/special/floor}}( x0.length / 2 ); + > stride = 2; + > {{alias}}( N, x1, stride ) + 2.0 + +{{alias}}.ndarray( N, x, stride, offset ) + Computes the maximum absolute value of a single-precision floating-point + strided array using alternative indexing semantics. + + While typed array views mandate a view offset based on the underlying + buffer, the `offset` parameter supports indexing semantics based on a + starting index. + + Parameters + ---------- + N: integer + Number of indexed elements. + + x: Float32Array + Input array. + + stride: integer + Index increment. + + offset: integer + Starting index. + + Returns + ------- + out: number + Maximum absolute value. + + Examples + -------- + // Standard Usage: + > var x = new {{alias:@stdlib/array/float32}}( [ 1.0, -2.0, 2.0 ] ); + > {{alias}}.ndarray( x.length, x, 1, 0 ) + 2.0 + + // Using offset parameter: + > var x = new {{alias:@stdlib/array/float32}}( [ 1.0, -2.0, 3.0, 2.0, 5.0, -1.0 ] ); + > var N = {{alias:@stdlib/math/base/special/floor}}( x.length / 2 ); + > {{alias}}.ndarray( N, x, 2, 1 ) + 2.0 + + See Also + -------- + diff --git a/docs/types/index.d.ts b/docs/types/index.d.ts new file mode 100644 index 0000000..e509bce --- /dev/null +++ b/docs/types/index.d.ts @@ -0,0 +1,92 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +// TypeScript Version: 2.0 + +/** +* Interface describing `smaxabs`. +*/ +interface Routine { + /** + * Computes the maximum absolute value of a single-precision floating-point strided array. + * + * @param N - number of indexed elements + * @param x - input array + * @param stride - stride length + * @returns maximum absolute value + * + * @example + * var Float32Array = require( `@stdlib/array/float32` ); + * + * var x = new Float32Array( [ 1.0, -2.0, 2.0 ] ); + * + * var v = smaxabs( x.length, x, 1 ); + * // returns 2.0 + */ + ( N: number, x: Float32Array, stride: number ): number; + + /** + * Computes the maximum absolute value of a single-precision floating-point strided array using alternative indexing semantics. + * + * @param N - number of indexed elements + * @param x - input array + * @param stride - stride length + * @param offset - starting index + * @returns maximum absolute value + * + * @example + * var Float32Array = require( `@stdlib/array/float32` ); + * + * var x = new Float32Array( [ 1.0, -2.0, 2.0 ] ); + * + * var v = smaxabs.ndarray( x.length, x, 1, 0 ); + * // returns 2.0 + */ + ndarray( N: number, x: Float32Array, stride: number, offset: number ): number; // tslint:disable-line:max-line-length +} + +/** +* Computes the maximum absolute value of a single-precision floating-point strided array. +* +* @param N - number of indexed elements +* @param x - input array +* @param stride - stride length +* @returns maximum absolute value +* +* @example +* var Float32Array = require( `@stdlib/array/float32` ); +* +* var x = new Float32Array( [ 1.0, -2.0, 2.0 ] ); +* +* var v = smaxabs( x.length, x, 1 ); +* // returns 2.0 +* +* @example +* var Float32Array = require( `@stdlib/array/float32` ); +* +* var x = new Float32Array( [ 1.0, -2.0, 2.0 ] ); +* +* var v = smaxabs.ndarray( x.length, x, 1, 0 ); +* // returns 2.0 +*/ +declare var smaxabs: Routine; + + +// EXPORTS // + +export = smaxabs; diff --git a/docs/types/test.ts b/docs/types/test.ts new file mode 100644 index 0000000..30a231b --- /dev/null +++ b/docs/types/test.ts @@ -0,0 +1,157 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import smaxabs = require( './index' ); + + +// TESTS // + +// The function returns a number... +{ + const x = new Float32Array( 10 ); + + smaxabs( x.length, x, 1 ); // $ExpectType number +} + +// The compiler throws an error if the function is provided a first argument which is not a number... +{ + const x = new Float32Array( 10 ); + + smaxabs( '10', x, 1 ); // $ExpectError + smaxabs( true, x, 1 ); // $ExpectError + smaxabs( false, x, 1 ); // $ExpectError + smaxabs( null, x, 1 ); // $ExpectError + smaxabs( undefined, x, 1 ); // $ExpectError + smaxabs( [], x, 1 ); // $ExpectError + smaxabs( {}, x, 1 ); // $ExpectError + smaxabs( ( x: number ): number => x, x, 1 ); // $ExpectError +} + +// The compiler throws an error if the function is provided a second argument which is not a Float32Array... +{ + const x = new Float32Array( 10 ); + + smaxabs( x.length, 10, 1 ); // $ExpectError + smaxabs( x.length, '10', 1 ); // $ExpectError + smaxabs( x.length, true, 1 ); // $ExpectError + smaxabs( x.length, false, 1 ); // $ExpectError + smaxabs( x.length, null, 1 ); // $ExpectError + smaxabs( x.length, undefined, 1 ); // $ExpectError + smaxabs( x.length, [], 1 ); // $ExpectError + smaxabs( x.length, {}, 1 ); // $ExpectError + smaxabs( x.length, ( x: number ): number => x, 1 ); // $ExpectError +} + +// The compiler throws an error if the function is provided a third argument which is not a number... +{ + const x = new Float32Array( 10 ); + + smaxabs( x.length, x, '10' ); // $ExpectError + smaxabs( x.length, x, true ); // $ExpectError + smaxabs( x.length, x, false ); // $ExpectError + smaxabs( x.length, x, null ); // $ExpectError + smaxabs( x.length, x, undefined ); // $ExpectError + smaxabs( x.length, x, [] ); // $ExpectError + smaxabs( x.length, x, {} ); // $ExpectError + smaxabs( x.length, x, ( x: number ): number => x ); // $ExpectError +} + +// The compiler throws an error if the function is provided an unsupported number of arguments... +{ + const x = new Float32Array( 10 ); + + smaxabs(); // $ExpectError + smaxabs( x.length ); // $ExpectError + smaxabs( x.length, x ); // $ExpectError + smaxabs( x.length, x, 1, 10 ); // $ExpectError +} + +// Attached to main export is an `ndarray` method which returns a number... +{ + const x = new Float32Array( 10 ); + + smaxabs.ndarray( x.length, x, 1, 0 ); // $ExpectType number +} + +// The compiler throws an error if the `ndarray` method is provided a first argument which is not a number... +{ + const x = new Float32Array( 10 ); + + smaxabs.ndarray( '10', x, 1, 0 ); // $ExpectError + smaxabs.ndarray( true, x, 1, 0 ); // $ExpectError + smaxabs.ndarray( false, x, 1, 0 ); // $ExpectError + smaxabs.ndarray( null, x, 1, 0 ); // $ExpectError + smaxabs.ndarray( undefined, x, 1, 0 ); // $ExpectError + smaxabs.ndarray( [], x, 1, 0 ); // $ExpectError + smaxabs.ndarray( {}, x, 1, 0 ); // $ExpectError + smaxabs.ndarray( ( x: number ): number => x, x, 1, 0 ); // $ExpectError +} + +// The compiler throws an error if the `ndarray` method is provided a second argument which is not a Float32Array... +{ + const x = new Float32Array( 10 ); + + smaxabs.ndarray( x.length, 10, 1, 0 ); // $ExpectError + smaxabs.ndarray( x.length, '10', 1, 0 ); // $ExpectError + smaxabs.ndarray( x.length, true, 1, 0 ); // $ExpectError + smaxabs.ndarray( x.length, false, 1, 0 ); // $ExpectError + smaxabs.ndarray( x.length, null, 1, 0 ); // $ExpectError + smaxabs.ndarray( x.length, undefined, 1, 0 ); // $ExpectError + smaxabs.ndarray( x.length, [], 1, 0 ); // $ExpectError + smaxabs.ndarray( x.length, {}, 1, 0 ); // $ExpectError + smaxabs.ndarray( x.length, ( x: number ): number => x, 1, 0 ); // $ExpectError +} + +// The compiler throws an error if the `ndarray` method is provided a third argument which is not a number... +{ + const x = new Float32Array( 10 ); + + smaxabs.ndarray( x.length, x, '10', 0 ); // $ExpectError + smaxabs.ndarray( x.length, x, true, 0 ); // $ExpectError + smaxabs.ndarray( x.length, x, false, 0 ); // $ExpectError + smaxabs.ndarray( x.length, x, null, 0 ); // $ExpectError + smaxabs.ndarray( x.length, x, undefined, 0 ); // $ExpectError + smaxabs.ndarray( x.length, x, [], 0 ); // $ExpectError + smaxabs.ndarray( x.length, x, {}, 0 ); // $ExpectError + smaxabs.ndarray( x.length, x, ( x: number ): number => x, 0 ); // $ExpectError +} + +// The compiler throws an error if the `ndarray` method is provided a fourth argument which is not a number... +{ + const x = new Float32Array( 10 ); + + smaxabs.ndarray( x.length, x, 1, '10' ); // $ExpectError + smaxabs.ndarray( x.length, x, 1, true ); // $ExpectError + smaxabs.ndarray( x.length, x, 1, false ); // $ExpectError + smaxabs.ndarray( x.length, x, 1, null ); // $ExpectError + smaxabs.ndarray( x.length, x, 1, undefined ); // $ExpectError + smaxabs.ndarray( x.length, x, 1, [] ); // $ExpectError + smaxabs.ndarray( x.length, x, 1, {} ); // $ExpectError + smaxabs.ndarray( x.length, x, 1, ( x: number ): number => x ); // $ExpectError +} + +// The compiler throws an error if the `ndarray` method is provided an unsupported number of arguments... +{ + const x = new Float32Array( 10 ); + + smaxabs.ndarray(); // $ExpectError + smaxabs.ndarray( x.length ); // $ExpectError + smaxabs.ndarray( x.length, x ); // $ExpectError + smaxabs.ndarray( x.length, x, 1 ); // $ExpectError + smaxabs.ndarray( x.length, x, 1, 0, 10 ); // $ExpectError +} diff --git a/examples/c/Makefile b/examples/c/Makefile new file mode 100644 index 0000000..ff5293d --- /dev/null +++ b/examples/c/Makefile @@ -0,0 +1,146 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2020 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# VARIABLES # + +ifndef VERBOSE + QUIET := @ +else + QUIET := +endif + +# Determine the OS ([1][1], [2][2]). +# +# [1]: https://en.wikipedia.org/wiki/Uname#Examples +# [2]: http://stackoverflow.com/a/27776822/2225624 +OS ?= $(shell uname) +ifneq (, $(findstring MINGW,$(OS))) + OS := WINNT +else +ifneq (, $(findstring MSYS,$(OS))) + OS := WINNT +else +ifneq (, $(findstring CYGWIN,$(OS))) + OS := WINNT +else +ifneq (, $(findstring Windows_NT,$(OS))) + OS := WINNT +endif +endif +endif +endif + +# Define the program used for compiling C source files: +ifdef C_COMPILER + CC := $(C_COMPILER) +else + CC := gcc +endif + +# Define the command-line options when compiling C files: +CFLAGS ?= \ + -std=c99 \ + -O3 \ + -Wall \ + -pedantic + +# Determine whether to generate position independent code ([1][1], [2][2]). +# +# [1]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options +# [2]: http://stackoverflow.com/questions/5311515/gcc-fpic-option +ifeq ($(OS), WINNT) + fPIC ?= +else + fPIC ?= -fPIC +endif + +# List of includes (e.g., `-I /foo/bar -I /beep/boop/include`): +INCLUDE ?= + +# List of source files: +SOURCE_FILES ?= + +# List of libraries (e.g., `-lopenblas -lpthread`): +LIBRARIES ?= + +# List of library paths (e.g., `-L /foo/bar -L /beep/boop`): +LIBPATH ?= + +# List of C targets: +c_targets := example.out + + +# RULES # + +#/ +# Compiles source files. +# +# @param {string} [C_COMPILER] - C compiler (e.g., `gcc`) +# @param {string} [CFLAGS] - C compiler options +# @param {(string|void)} [fPIC] - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} [INCLUDE] - list of includes (e.g., `-I /foo/bar -I /beep/boop/include`) +# @param {string} [SOURCE_FILES] - list of source files +# @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) +# @param {string} [LIBRARIES] - list of libraries (e.g., `-lopenblas -lpthread`) +# +# @example +# make +# +# @example +# make all +#/ +all: $(c_targets) + +.PHONY: all + +#/ +# Compiles C source files. +# +# @private +# @param {string} CC - C compiler (e.g., `gcc`) +# @param {string} CFLAGS - C compiler options +# @param {(string|void)} fPIC - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} INCLUDE - list of includes (e.g., `-I /foo/bar`) +# @param {string} SOURCE_FILES - list of source files +# @param {string} LIBPATH - list of library paths (e.g., `-L /foo/bar`) +# @param {string} LIBRARIES - list of libraries (e.g., `-lopenblas`) +#/ +$(c_targets): %.out: %.c + $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + +#/ +# Runs compiled examples. +# +# @example +# make run +#/ +run: $(c_targets) + $(QUIET) ./$< + +.PHONY: run + +#/ +# Removes generated files. +# +# @example +# make clean +#/ +clean: + $(QUIET) -rm -f *.o *.out + +.PHONY: clean diff --git a/examples/c/example.c b/examples/c/example.c new file mode 100644 index 0000000..d7e830e --- /dev/null +++ b/examples/c/example.c @@ -0,0 +1,39 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stdlib/stats/base/smaxabs.h" +#include +#include + +int main() { + // Create a strided array: + float x[] = { 1.0, -2.0, -3.0, 4.0, -5.0, -6.0, 7.0, 8.0 }; + + // Specify the number of elements: + int64_t N = 4; + + // Specify the stride length: + int64_t stride = 2; + + // Compute the maximum absolute value: + float v = stdlib_strided_smaxabs( N, x, stride ); + + // Print the result: + printf( "maxabs: %f", v ); + printf( "\n" ); +} diff --git a/examples/index.js b/examples/index.js new file mode 100644 index 0000000..9e027b5 --- /dev/null +++ b/examples/index.js @@ -0,0 +1,36 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +var randu = require( '@stdlib/random-base-randu' ); +var round = require( '@stdlib/math-base-special-round' ); +var Float32Array = require( '@stdlib/array-float32' ); +var smaxabs = require( './../lib' ); + +var x; +var i; + +x = new Float32Array( 10 ); +for ( i = 0; i < x.length; i++ ) { + x[ i ] = round( (randu()*100.0) - 50.0 ); +} +console.log( x ); + +var v = smaxabs( x.length, x, 1 ); +console.log( v ); diff --git a/include.gypi b/include.gypi new file mode 100644 index 0000000..2fa318f --- /dev/null +++ b/include.gypi @@ -0,0 +1,53 @@ +# @license Apache-2.0 +# +# Copyright (c) 2020 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A GYP include file for building a Node.js native add-on. +# +# Main documentation: +# +# [1]: https://gyp.gsrc.io/docs/InputFormatReference.md +# [2]: https://gyp.gsrc.io/docs/UserDocumentation.md +{ + # Define variables to be used throughout the configuration for all targets: + 'variables': { + # Source directory: + 'src_dir': './src', + + # Include directories: + 'include_dirs': [ + ' + +/* +* If C++, prevent name mangling so that the compiler emits a binary file having undecorated names, thus mirroring the behavior of a C compiler. +*/ +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Computes the maximum absolute value of a single-precision floating-point strided array. +*/ +float stdlib_strided_smaxabs( const int64_t N, const float *X, const int64_t stride ); + +#ifdef __cplusplus +} +#endif + +#endif // !STDLIB_STATS_BASE_SMAXABS_H diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..f475b01 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,65 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +/** +* Compute the maximum absolute value of a single-precision floating-point strided array. +* +* @module @stdlib/stats/base/smaxabs +* +* @example +* var Float32Array = require( '@stdlib/array-float32' ); +* var smaxabs = require( '@stdlib/stats-base-smaxabs' ); +* +* var x = new Float32Array( [ 1.0, -2.0, 2.0 ] ); +* var N = x.length; +* +* var v = smaxabs( N, x, 1 ); +* // returns 2.0 +* +* @example +* var Float32Array = require( '@stdlib/array-float32' ); +* var floor = require( '@stdlib/math-base-special-floor' ); +* var smaxabs = require( '@stdlib/stats-base-smaxabs' ); +* +* var x = new Float32Array( [ 2.0, 1.0, 2.0, -2.0, -2.0, 2.0, 3.0, 4.0 ] ); +* var N = floor( x.length / 2 ); +* +* var v = smaxabs.ndarray( N, x, 2, 1 ); +* // returns 4.0 +*/ + +// MODULES // + +var join = require( 'path' ).join; +var tryRequire = require( '@stdlib/utils-try-require' ); +var smaxabs = require( './main.js' ); + + +// MAIN // + +var tmp = tryRequire( join( __dirname, './native.js' ) ); +if ( !(tmp instanceof Error) ) { + smaxabs = tmp; +} + + +// EXPORTS // + +module.exports = smaxabs; diff --git a/lib/main.js b/lib/main.js new file mode 100644 index 0000000..f5ef17d --- /dev/null +++ b/lib/main.js @@ -0,0 +1,35 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var setReadOnly = require( '@stdlib/utils-define-nonenumerable-read-only-property' ); +var smaxabs = require( './smaxabs.js' ); +var ndarray = require( './ndarray.js' ); + + +// MAIN // + +setReadOnly( smaxabs, 'ndarray', ndarray ); + + +// EXPORTS // + +module.exports = smaxabs; diff --git a/lib/native.js b/lib/native.js new file mode 100644 index 0000000..93b0213 --- /dev/null +++ b/lib/native.js @@ -0,0 +1,35 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var setReadOnly = require( '@stdlib/utils-define-nonenumerable-read-only-property' ); +var smaxabs = require( './smaxabs.native.js' ); +var ndarray = require( './ndarray.native.js' ); + + +// MAIN // + +setReadOnly( smaxabs, 'ndarray', ndarray ); + + +// EXPORTS // + +module.exports = smaxabs; diff --git a/lib/ndarray.js b/lib/ndarray.js new file mode 100644 index 0000000..ab48c40 --- /dev/null +++ b/lib/ndarray.js @@ -0,0 +1,78 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var isnanf = require( '@stdlib/math-base-assert-is-nanf' ); +var abs = require( '@stdlib/math-base-special-abs' ); + + +// MAIN // + +/** +* Computes the maximum absolute value of a single-precision floating-point strided array. +* +* @param {PositiveInteger} N - number of indexed elements +* @param {Float32Array} x - input array +* @param {integer} stride - stride length +* @param {NonNegativeInteger} offset - starting index +* @returns {number} maximum absolute value +* +* @example +* var Float32Array = require( '@stdlib/array-float32' ); +* var floor = require( '@stdlib/math-base-special-floor' ); +* +* var x = new Float32Array( [ 2.0, 1.0, 2.0, -2.0, -2.0, 2.0, 3.0, 4.0 ] ); +* var N = floor( x.length / 2 ); +* +* var v = smaxabs( N, x, 2, 1 ); +* // returns 4.0 +*/ +function smaxabs( N, x, stride, offset ) { + var max; + var ix; + var v; + var i; + + if ( N <= 0 ) { + return NaN; + } + if ( N === 1 || stride === 0 ) { + return abs( x[ offset ] ); + } + ix = offset; + max = abs( x[ ix ] ); + for ( i = 1; i < N; i++ ) { + ix += stride; + v = abs( x[ ix ] ); + if ( isnanf( v ) ) { + return v; + } + if ( v > max ) { + max = v; + } + } + return max; +} + + +// EXPORTS // + +module.exports = smaxabs; diff --git a/lib/ndarray.native.js b/lib/ndarray.native.js new file mode 100644 index 0000000..f61ad0e --- /dev/null +++ b/lib/ndarray.native.js @@ -0,0 +1,60 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var Float32Array = require( '@stdlib/array-float32' ); +var addon = require( './smaxabs.native.js' ); + + +// MAIN // + +/** +* Computes the maximum absolute value of a double-precision floating-point strided array. +* +* @param {PositiveInteger} N - number of indexed elements +* @param {Float32Array} x - input array +* @param {integer} stride - stride length +* @param {NonNegativeInteger} offset - starting index +* @returns {number} maximum absolute value +* +* @example +* var Float32Array = require( '@stdlib/array-float32' ); +* var floor = require( '@stdlib/math-base-special-floor' ); +* +* var x = new Float32Array( [ 2.0, 1.0, 2.0, -2.0, -2.0, 2.0, 3.0, 4.0 ] ); +* var N = floor( x.length / 2 ); +* +* var v = smaxabs( N, x, 2, 1 ); +* // returns 4.0 +*/ +function smaxabs( N, x, stride, offset ) { + var view; + if ( stride < 0 ) { + offset += (N-1) * stride; + } + view = new Float32Array( x.buffer, x.byteOffset+(x.BYTES_PER_ELEMENT*offset), x.length-offset ); // eslint-disable-line max-len + return addon( N, view, stride ); +} + + +// EXPORTS // + +module.exports = smaxabs; diff --git a/lib/smaxabs.js b/lib/smaxabs.js new file mode 100644 index 0000000..e4fd9fb --- /dev/null +++ b/lib/smaxabs.js @@ -0,0 +1,80 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var isnanf = require( '@stdlib/math-base-assert-is-nanf' ); +var abs = require( '@stdlib/math-base-special-abs' ); + + +// MAIN // + +/** +* Computes the maximum absolute value of a single-precision floating-point strided array. +* +* @param {PositiveInteger} N - number of indexed elements +* @param {Float32Array} x - input array +* @param {integer} stride - stride length +* @returns {number} maximum absolute value +* +* @example +* var Float32Array = require( '@stdlib/array-float32' ); +* +* var x = new Float32Array( [ 1.0, -2.0, 2.0 ] ); +* var N = x.length; +* +* var v = smaxabs( N, x, 1 ); +* // returns 2.0 +*/ +function smaxabs( N, x, stride ) { + var max; + var ix; + var v; + var i; + + if ( N <= 0 ) { + return NaN; + } + if ( N === 1 || stride === 0 ) { + return abs( x[ 0 ] ); + } + if ( stride < 0 ) { + ix = (1-N) * stride; + } else { + ix = 0; + } + max = abs( x[ ix ] ); + for ( i = 1; i < N; i++ ) { + ix += stride; + v = abs( x[ ix ] ); + if ( isnanf( v ) ) { + return v; + } + if ( v > max ) { + max = v; + } + } + return max; +} + + +// EXPORTS // + +module.exports = smaxabs; diff --git a/lib/smaxabs.native.js b/lib/smaxabs.native.js new file mode 100644 index 0000000..29dff95 --- /dev/null +++ b/lib/smaxabs.native.js @@ -0,0 +1,52 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var addon = require( './../src/addon.node' ); + + +// MAIN // + +/** +* Computes the maximum absolute value of a single-precision floating-point strided array. +* +* @param {PositiveInteger} N - number of indexed elements +* @param {Float32Array} x - input array +* @param {integer} stride - stride length +* @returns {number} maximum absolute value +* +* @example +* var Float32Array = require( '@stdlib/array-float32' ); +* +* var x = new Float32Array( [ 1.0, -2.0, 2.0 ] ); +* var N = x.length; +* +* var v = smaxabs( N, x, 1 ); +* // returns 2.0 +*/ +function smaxabs( N, x, stride ) { + return addon( N, x, stride ); +} + + +// EXPORTS // + +module.exports = smaxabs; diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..6763481 --- /dev/null +++ b/manifest.json @@ -0,0 +1,42 @@ +{ + "options": {}, + "fields": [ + { + "field": "src", + "resolve": true, + "relative": true + }, + { + "field": "include", + "resolve": true, + "relative": true + }, + { + "field": "libraries", + "resolve": false, + "relative": false + }, + { + "field": "libpath", + "resolve": true, + "relative": false + } + ], + "confs": [ + { + "src": [ + "./src/smaxabs.c" + ], + "include": [ + "./include" + ], + "libraries": [ + "-lm" + ], + "libpath": [], + "dependencies": [ + "@stdlib/math-base-assert-is-nanf" + ] + } + ] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..4e678f8 --- /dev/null +++ b/package.json @@ -0,0 +1,109 @@ +{ + "name": "@stdlib/stats-base-smaxabs", + "version": "0.0.0", + "description": "Calculate the maximum absolute value of a single-precision floating-point strided array.", + "license": "Apache-2.0", + "author": { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + }, + "contributors": [ + { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + } + ], + "main": "./lib", + "browser": "./lib/main.js", + "gypfile": true, + "directories": { + "benchmark": "./benchmark", + "doc": "./docs", + "example": "./examples", + "include": "./include", + "lib": "./lib", + "test": "./test", + "src": "./src" + }, + "types": "./docs/types", + "scripts": { + "test": "make test", + "test-cov": "make test-cov", + "examples": "make examples", + "benchmark": "make benchmark" + }, + "homepage": "https://github.com/stdlib-js/stdlib", + "repository": { + "type": "git", + "url": "git://github.com/stdlib-js/stats-base-smaxabs.git" + }, + "bugs": { + "url": "https://github.com/stdlib-js/stdlib/issues" + }, + "dependencies": { + "@stdlib/math-base-assert-is-nanf": "^0.0.x", + "@stdlib/math-base-special-abs": "^0.0.x", + "@stdlib/utils-define-nonenumerable-read-only-property": "^0.0.x", + "@stdlib/utils-library-manifest": "^0.0.x", + "@stdlib/utils-try-require": "^0.0.x" + }, + "devDependencies": { + "@stdlib/array-float32": "^0.0.x", + "@stdlib/assert-is-browser": "^0.0.x", + "@stdlib/bench": "^0.0.x", + "@stdlib/math-base-assert-is-nan": "^0.0.x", + "@stdlib/math-base-assert-is-positive-zero": "^0.0.x", + "@stdlib/math-base-special-floor": "^0.0.x", + "@stdlib/math-base-special-pow": "^0.0.x", + "@stdlib/math-base-special-round": "^0.0.x", + "@stdlib/random-base-randu": "^0.0.x", + "proxyquire": "^2.0.0", + "tape": "git+https://github.com/kgryte/tape.git#fix/globby", + "istanbul": "^0.4.1", + "tap-spec": "5.x.x" + }, + "engines": { + "node": ">=0.10.0", + "npm": ">2.7.0" + }, + "os": [ + "aix", + "darwin", + "freebsd", + "linux", + "macos", + "openbsd", + "sunos", + "win32", + "windows" + ], + "keywords": [ + "stdlib", + "stdmath", + "statistics", + "stats", + "mathematics", + "math", + "maximum", + "max", + "absolute", + "abs", + "range", + "extremes", + "domain", + "extent", + "strided", + "strided array", + "typed", + "array", + "float32", + "single", + "float", + "float32array" + ], + "__stdlib__": {}, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/athan" + } +} diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..dd720a3 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,70 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2020 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# VARIABLES # + +ifndef VERBOSE + QUIET := @ +else + QUIET := +endif + +# Determine the OS ([1][1], [2][2]). +# +# [1]: https://en.wikipedia.org/wiki/Uname#Examples +# [2]: http://stackoverflow.com/a/27776822/2225624 +OS ?= $(shell uname) +ifneq (, $(findstring MINGW,$(OS))) + OS := WINNT +else +ifneq (, $(findstring MSYS,$(OS))) + OS := WINNT +else +ifneq (, $(findstring CYGWIN,$(OS))) + OS := WINNT +else +ifneq (, $(findstring Windows_NT,$(OS))) + OS := WINNT +endif +endif +endif +endif + + +# RULES # + +#/ +# Removes generated files for building an add-on. +# +# @example +# make clean-addon +#/ +clean-addon: + $(QUIET) -rm -f *.o *.node + +.PHONY: clean-addon + +#/ +# Removes generated files. +# +# @example +# make clean +#/ +clean: clean-addon + +.PHONY: clean diff --git a/src/addon.cpp b/src/addon.cpp new file mode 100644 index 0000000..3002410 --- /dev/null +++ b/src/addon.cpp @@ -0,0 +1,117 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stdlib/stats/base/smaxabs.h" +#include +#include +#include +#include +#include + +/** +* Add-on namespace. +*/ +namespace stdlib_stats_base_smaxabs { + + /** + * Computes the maximum absolute value of a single-precision floating-point strided array. + * + * ## Notes + * + * - When called from JavaScript, the function expects three arguments: + * + * - `N`: number of indexed elements + * - `X`: input array + * - `stride`: stride length + */ + napi_value node_smaxabs( napi_env env, napi_callback_info info ) { + napi_status status; + + size_t argc = 3; + napi_value argv[ 3 ]; + status = napi_get_cb_info( env, info, &argc, argv, nullptr, nullptr ); + assert( status == napi_ok ); + + if ( argc < 3 ) { + napi_throw_error( env, nullptr, "invalid invocation. Must provide 3 arguments." ); + return nullptr; + } + + napi_valuetype vtype0; + status = napi_typeof( env, argv[ 0 ], &vtype0 ); + assert( status == napi_ok ); + if ( vtype0 != napi_number ) { + napi_throw_type_error( env, nullptr, "invalid argument. First argument must be a number." ); + return nullptr; + } + + bool res; + status = napi_is_typedarray( env, argv[ 1 ], &res ); + assert( status == napi_ok ); + if ( res == false ) { + napi_throw_type_error( env, nullptr, "invalid argument. Second argument must be a Float32Array." ); + return nullptr; + } + + napi_valuetype vtype2; + status = napi_typeof( env, argv[ 2 ], &vtype2 ); + assert( status == napi_ok ); + if ( vtype2 != napi_number ) { + napi_throw_type_error( env, nullptr, "invalid argument. Third argument must be a number." ); + return nullptr; + } + + int64_t N; + status = napi_get_value_int64( env, argv[ 0 ], &N ); + assert( status == napi_ok ); + + int64_t stride; + status = napi_get_value_int64( env, argv[ 2 ], &stride ); + assert( status == napi_ok ); + + napi_typedarray_type vtype1; + size_t xlen; + void *X; + status = napi_get_typedarray_info( env, argv[ 1 ], &vtype1, &xlen, &X, nullptr, nullptr ); + assert( status == napi_ok ); + if ( vtype1 != napi_float32_array ) { + napi_throw_type_error( env, nullptr, "invalid argument. Second argument must be a Float32Array." ); + return nullptr; + } + if ( (N-1)*llabs(stride) >= (int64_t)xlen ) { + napi_throw_range_error( env, nullptr, "invalid argument. Second argument has insufficient elements based on the associated stride and the number of indexed elements." ); + return nullptr; + } + + napi_value v; + status = napi_create_double( env, (double)stdlib_strided_smaxabs( N, (float *)X, stride ), &v ); + assert( status == napi_ok ); + + return v; + } + + napi_value Init( napi_env env, napi_value exports ) { + napi_status status; + napi_value fcn; + status = napi_create_function( env, "exports", NAPI_AUTO_LENGTH, node_smaxabs, NULL, &fcn ); + assert( status == napi_ok ); + return fcn; + } + + NAPI_MODULE( NODE_GYP_MODULE_NAME, Init ) +} // end namespace stdlib_stats_base_smaxabs diff --git a/src/smaxabs.c b/src/smaxabs.c new file mode 100644 index 0000000..d800178 --- /dev/null +++ b/src/smaxabs.c @@ -0,0 +1,61 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stdlib/stats/base/smaxabs.h" +#include "stdlib/math/base/assert/is_nanf.h" +#include +#include + +/** +* Computes the maximum absolute value of a single-precision floating-point strided array. +* +* @param N number of indexed elements +* @param X input array +* @param stride stride length +* @return output value +*/ +float stdlib_strided_smaxabs( const int64_t N, const float *X, const int64_t stride ) { + int64_t ix; + int64_t i; + float max; + float v; + + if ( N <= 0 ) { + return 0.0 / 0.0; // NaN + } + if ( N == 1 || stride == 0 ) { + return fabsf( X[ 0 ] ); + } + if ( stride < 0 ) { + ix = (1-N) * stride; + } else { + ix = 0; + } + max = fabsf( X[ ix ] ); + for ( i = 1; i < N; i++ ) { + ix += stride; + v = fabsf( X[ ix ] ); + if ( stdlib_base_is_nanf( v ) ) { + return v; + } + if ( v > max ) { + max = v; + } + } + return max; +} diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..e33e95b --- /dev/null +++ b/test/test.js @@ -0,0 +1,82 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var proxyquire = require( 'proxyquire' ); +var IS_BROWSER = require( '@stdlib/assert-is-browser' ); +var smaxabs = require( './../lib' ); + + +// VARIABLES // + +var opts = { + 'skip': IS_BROWSER +}; + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof smaxabs, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'attached to the main export is a method providing an ndarray interface', function test( t ) { + t.strictEqual( typeof smaxabs.ndarray, 'function', 'method is a function' ); + t.end(); +}); + +tape( 'if a native implementation is available, the main export is the native implementation', opts, function test( t ) { + var smaxabs = proxyquire( './../lib', { + '@stdlib/utils/try-require': tryRequire + }); + + t.strictEqual( smaxabs, mock, 'returns expected value' ); + t.end(); + + function tryRequire() { + return mock; + } + + function mock() { + // Mock... + } +}); + +tape( 'if a native implementation is not available, the main export is a JavaScript implementation', opts, function test( t ) { + var smaxabs; + var main; + + main = require( './../lib/smaxabs.js' ); + + smaxabs = proxyquire( './../lib', { + '@stdlib/utils/try-require': tryRequire + }); + + t.strictEqual( smaxabs, main, 'returns expected value' ); + t.end(); + + function tryRequire() { + return new Error( 'Cannot find module' ); + } +}); diff --git a/test/test.ndarray.js b/test/test.ndarray.js new file mode 100644 index 0000000..85aa310 --- /dev/null +++ b/test/test.ndarray.js @@ -0,0 +1,177 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var floor = require( '@stdlib/math-base-special-floor' ); +var isnan = require( '@stdlib/math-base-assert-is-nan' ); +var isPositiveZero = require( '@stdlib/math-base-assert-is-positive-zero' ); +var Float32Array = require( '@stdlib/array-float32' ); +var smaxabs = require( './../lib/ndarray.js' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof smaxabs, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function has an arity of 4', function test( t ) { + t.strictEqual( smaxabs.length, 4, 'has expected arity' ); + t.end(); +}); + +tape( 'the function calculates the maximum absolute value of a strided array', function test( t ) { + var x; + var v; + + x = new Float32Array( [ 1.0, -2.0, -4.0, 5.0, 0.0, 3.0 ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( v, 5.0, 'returns expected value' ); + + x = new Float32Array( [ -4.0, -5.0 ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( v, 5.0, 'returns expected value' ); + + x = new Float32Array( [ -0.0, 0.0, -0.0 ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( isPositiveZero( v ), true, 'returns expected value' ); + + x = new Float32Array( [ NaN ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + x = new Float32Array( [ NaN, NaN ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + t.end(); +}); + +tape( 'if provided an `N` parameter less than or equal to `0`, the function returns `NaN`', function test( t ) { + var x; + var v; + + x = new Float32Array( [ 1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( 0, x, 1, 0 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + v = smaxabs( -1, x, 1, 0 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + t.end(); +}); + +tape( 'if provided an `N` parameter equal to `1`, the function returns the first indexed element', function test( t ) { + var x; + var v; + + x = new Float32Array( [ -1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( 1, x, 1, 0 ); + t.strictEqual( v, 1.0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports a `stride` parameter', function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 1.0, // 0 + 2.0, + 2.0, // 1 + -7.0, + -2.0, // 2 + 3.0, + 4.0, // 3 + 2.0 + ]); + + N = floor( x.length / 2 ); + v = smaxabs( N, x, 2, 0 ); + + t.strictEqual( v, 4.0, 'returns expected value' ); + t.end(); +}); + +tape( 'the function supports a negative `stride` parameter', function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 1.0, // 3 + 2.0, + 2.0, // 2 + -7.0, + -2.0, // 1 + 3.0, + 4.0, // 0 + 2.0 + ]); + + N = floor( x.length / 2 ); + v = smaxabs( N, x, -2, 6 ); + + t.strictEqual( v, 4.0, 'returns expected value' ); + t.end(); +}); + +tape( 'if provided a `stride` parameter equal to `0`, the function returns the first indexed element', function test( t ) { + var x; + var v; + + x = new Float32Array( [ -1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( x.length, x, 0, 0 ); + t.strictEqual( v, 1.0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports an `offset` parameter', function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 2.0, + 1.0, // 0 + 2.0, + -2.0, // 1 + -2.0, + 2.0, // 2 + 3.0, + 4.0 // 3 + ]); + N = floor( x.length / 2 ); + + v = smaxabs( N, x, 2, 1 ); + t.strictEqual( v, 4.0, 'returns expected value' ); + + t.end(); +}); diff --git a/test/test.ndarray.native.js b/test/test.ndarray.native.js new file mode 100644 index 0000000..2cf6566 --- /dev/null +++ b/test/test.ndarray.native.js @@ -0,0 +1,186 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var tape = require( 'tape' ); +var floor = require( '@stdlib/math-base-special-floor' ); +var isnan = require( '@stdlib/math-base-assert-is-nan' ); +var isPositiveZero = require( '@stdlib/math-base-assert-is-positive-zero' ); +var Float32Array = require( '@stdlib/array-float32' ); +var tryRequire = require( '@stdlib/utils-try-require' ); + + +// VARIABLES // + +var smaxabs = tryRequire( resolve( __dirname, './../lib/ndarray.native.js' ) ); +var opts = { + 'skip': ( smaxabs instanceof Error ) +}; + + +// TESTS // + +tape( 'main export is a function', opts, function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof smaxabs, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function has an arity of 4', opts, function test( t ) { + t.strictEqual( smaxabs.length, 4, 'has expected arity' ); + t.end(); +}); + +tape( 'the function calculates the maximum absolute value of a strided array', opts, function test( t ) { + var x; + var v; + + x = new Float32Array( [ 1.0, -2.0, -4.0, 5.0, 0.0, 3.0 ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( v, 5.0, 'returns expected value' ); + + x = new Float32Array( [ -4.0, -5.0 ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( v, 5.0, 'returns expected value' ); + + x = new Float32Array( [ -0.0, 0.0, -0.0 ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( isPositiveZero( v ), true, 'returns expected value' ); + + x = new Float32Array( [ NaN ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + x = new Float32Array( [ NaN, NaN ] ); + v = smaxabs( x.length, x, 1, 0 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + t.end(); +}); + +tape( 'if provided an `N` parameter less than or equal to `0`, the function returns `NaN`', opts, function test( t ) { + var x; + var v; + + x = new Float32Array( [ 1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( 0, x, 1, 0 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + v = smaxabs( -1, x, 1, 0 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + t.end(); +}); + +tape( 'if provided an `N` parameter equal to `1`, the function returns the first indexed element', opts, function test( t ) { + var x; + var v; + + x = new Float32Array( [ -1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( 1, x, 1, 0 ); + t.strictEqual( v, 1.0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports a `stride` parameter', opts, function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 1.0, // 0 + 2.0, + 2.0, // 1 + -7.0, + -2.0, // 2 + 3.0, + 4.0, // 3 + 2.0 + ]); + + N = floor( x.length / 2 ); + v = smaxabs( N, x, 2, 0 ); + + t.strictEqual( v, 4.0, 'returns expected value' ); + t.end(); +}); + +tape( 'the function supports a negative `stride` parameter', opts, function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 1.0, // 3 + 2.0, + 2.0, // 2 + -7.0, + -2.0, // 1 + 3.0, + 4.0, // 0 + 2.0 + ]); + + N = floor( x.length / 2 ); + v = smaxabs( N, x, -2, 6 ); + + t.strictEqual( v, 4.0, 'returns expected value' ); + t.end(); +}); + +tape( 'if provided a `stride` parameter equal to `0`, the function returns the first indexed element', opts, function test( t ) { + var x; + var v; + + x = new Float32Array( [ -1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( x.length, x, 0, 0 ); + t.strictEqual( v, 1.0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports an `offset` parameter', opts, function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 2.0, + 1.0, // 0 + 2.0, + -2.0, // 1 + -2.0, + 2.0, // 2 + 3.0, + 4.0 // 3 + ]); + N = floor( x.length / 2 ); + + v = smaxabs( N, x, 2, 1 ); + t.strictEqual( v, 4.0, 'returns expected value' ); + + t.end(); +}); diff --git a/test/test.smaxabs.js b/test/test.smaxabs.js new file mode 100644 index 0000000..7a3c169 --- /dev/null +++ b/test/test.smaxabs.js @@ -0,0 +1,181 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var floor = require( '@stdlib/math-base-special-floor' ); +var isnan = require( '@stdlib/math-base-assert-is-nan' ); +var isPositiveZero = require( '@stdlib/math-base-assert-is-positive-zero' ); +var Float32Array = require( '@stdlib/array-float32' ); +var smaxabs = require( './../lib/smaxabs.js' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof smaxabs, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function has an arity of 3', function test( t ) { + t.strictEqual( smaxabs.length, 3, 'has expected arity' ); + t.end(); +}); + +tape( 'the function calculates the maximum absolute value of a strided array', function test( t ) { + var x; + var v; + + x = new Float32Array( [ 1.0, -2.0, -4.0, 5.0, 0.0, 3.0 ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( v, 5.0, 'returns expected value' ); + + x = new Float32Array( [ -4.0, -5.0 ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( v, 5.0, 'returns expected value' ); + + x = new Float32Array( [ -0.0, 0.0, -0.0 ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( isPositiveZero( v ), true, 'returns expected value' ); + + x = new Float32Array( [ NaN ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + x = new Float32Array( [ NaN, NaN ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + t.end(); +}); + +tape( 'if provided an `N` parameter less than or equal to `0`, the function returns `NaN`', function test( t ) { + var x; + var v; + + x = new Float32Array( [ 1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( 0, x, 1 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + v = smaxabs( -1, x, 1 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + t.end(); +}); + +tape( 'if provided an `N` parameter equal to `1`, the function returns the first element', function test( t ) { + var x; + var v; + + x = new Float32Array( [ -1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( 1, x, 1 ); + t.strictEqual( v, 1.0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports a `stride` parameter', function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 1.0, // 0 + 2.0, + 2.0, // 1 + -7.0, + -2.0, // 2 + 3.0, + 4.0, // 3 + 2.0 + ]); + + N = floor( x.length / 2 ); + v = smaxabs( N, x, 2 ); + + t.strictEqual( v, 4.0, 'returns expected value' ); + t.end(); +}); + +tape( 'the function supports a negative `stride` parameter', function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 1.0, // 3 + 2.0, + 2.0, // 2 + -7.0, + -2.0, // 1 + 3.0, + 4.0, // 0 + 2.0 + ]); + + N = floor( x.length / 2 ); + v = smaxabs( N, x, -2 ); + + t.strictEqual( v, 4.0, 'returns expected value' ); + t.end(); +}); + +tape( 'if provided a `stride` parameter equal to `0`, the function returns the first element', function test( t ) { + var x; + var v; + + x = new Float32Array( [ -1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( x.length, x, 0 ); + t.strictEqual( v, 1.0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports view offsets', function test( t ) { + var x0; + var x1; + var N; + var v; + + x0 = new Float32Array([ + 2.0, + 1.0, // 0 + 2.0, + -2.0, // 1 + -2.0, + 2.0, // 2 + 3.0, + 4.0, // 3 + 6.0 + ]); + + x1 = new Float32Array( x0.buffer, x0.BYTES_PER_ELEMENT*1 ); // start at 2nd element + N = floor(x1.length / 2); + + v = smaxabs( N, x1, 2 ); + t.strictEqual( v, 4.0, 'returns expected value' ); + + t.end(); +}); diff --git a/test/test.smaxabs.native.js b/test/test.smaxabs.native.js new file mode 100644 index 0000000..321f3a3 --- /dev/null +++ b/test/test.smaxabs.native.js @@ -0,0 +1,272 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var tape = require( 'tape' ); +var floor = require( '@stdlib/math-base-special-floor' ); +var isnan = require( '@stdlib/math-base-assert-is-nan' ); +var isPositiveZero = require( '@stdlib/math-base-assert-is-positive-zero' ); +var Float32Array = require( '@stdlib/array-float32' ); +var tryRequire = require( '@stdlib/utils-try-require' ); + + +// VARIABLES // + +var smaxabs = tryRequire( resolve( __dirname, './../lib/smaxabs.native.js' ) ); +var opts = { + 'skip': ( smaxabs instanceof Error ) +}; + + +// TESTS // + +tape( 'main export is a function', opts, function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof smaxabs, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function has an arity of 3', opts, function test( t ) { + t.strictEqual( smaxabs.length, 3, 'has expected arity' ); + t.end(); +}); + +tape( 'the functions throws an error if provided a first argument which is not a number', opts, function test( t ) { + var values; + var i; + + values = [ + '5', + true, + false, + null, + void 0, + [], + {}, + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), TypeError, 'throws an error when provided ' + values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + smaxabs( value, new Float32Array( 10 ), 1 ); + }; + } +}); + +tape( 'the functions throws an error if provided a second argument which is not a Float32Array', opts, function test( t ) { + var values; + var i; + + values = [ + '5', + 5, + true, + false, + null, + void 0, + [], + {}, + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), TypeError, 'throws an error when provided ' + values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + smaxabs( 10, value, 1 ); + }; + } +}); + +tape( 'the functions throws an error if provided a third argument which is not a number', opts, function test( t ) { + var values; + var i; + + values = [ + '5', + true, + false, + null, + void 0, + [], + {}, + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), TypeError, 'throws an error when provided ' + values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + smaxabs( 10, new Float32Array( 10 ), value ); + }; + } +}); + +tape( 'the function calculates the maximum absolute value of a strided array', opts, function test( t ) { + var x; + var v; + + x = new Float32Array( [ 1.0, -2.0, -4.0, 5.0, 0.0, 3.0 ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( v, 5.0, 'returns expected value' ); + + x = new Float32Array( [ -4.0, -5.0 ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( v, 5.0, 'returns expected value' ); + + x = new Float32Array( [ -0.0, 0.0, -0.0 ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( isPositiveZero( v ), true, 'returns expected value' ); + + x = new Float32Array( [ NaN ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + x = new Float32Array( [ NaN, NaN ] ); + v = smaxabs( x.length, x, 1 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + t.end(); +}); + +tape( 'if provided an `N` parameter less than or equal to `0`, the function returns `NaN`', opts, function test( t ) { + var x; + var v; + + x = new Float32Array( [ 1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( 0, x, 1 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + v = smaxabs( -1, x, 1 ); + t.strictEqual( isnan( v ), true, 'returns expected value' ); + + t.end(); +}); + +tape( 'if provided an `N` parameter equal to `1`, the function returns the first element', opts, function test( t ) { + var x; + var v; + + x = new Float32Array( [ -1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( 1, x, 1 ); + t.strictEqual( v, 1.0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports a `stride` parameter', opts, function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 1.0, // 0 + 2.0, + 2.0, // 1 + -7.0, + -2.0, // 2 + 3.0, + 4.0, // 3 + 2.0 + ]); + + N = floor( x.length / 2 ); + v = smaxabs( N, x, 2 ); + + t.strictEqual( v, 4.0, 'returns expected value' ); + t.end(); +}); + +tape( 'the function supports a negative `stride` parameter', opts, function test( t ) { + var N; + var x; + var v; + + x = new Float32Array([ + 1.0, // 3 + 2.0, + 2.0, // 2 + -7.0, + -2.0, // 1 + 3.0, + 4.0, // 0 + 2.0 + ]); + + N = floor( x.length / 2 ); + v = smaxabs( N, x, -2 ); + + t.strictEqual( v, 4.0, 'returns expected value' ); + t.end(); +}); + +tape( 'if provided a `stride` parameter equal to `0`, the function returns the first element', opts, function test( t ) { + var x; + var v; + + x = new Float32Array( [ -1.0, -2.0, -4.0, 5.0, 3.0 ] ); + + v = smaxabs( x.length, x, 0 ); + t.strictEqual( v, 1.0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports view offsets', opts, function test( t ) { + var x0; + var x1; + var N; + var v; + + x0 = new Float32Array([ + 2.0, + 1.0, // 0 + 2.0, + -2.0, // 1 + -2.0, + 2.0, // 2 + 3.0, + 4.0, // 3 + 6.0 + ]); + + x1 = new Float32Array( x0.buffer, x0.BYTES_PER_ELEMENT*1 ); // start at 2nd element + N = floor(x1.length / 2); + + v = smaxabs( N, x1, 2 ); + t.strictEqual( v, 4.0, 'returns expected value' ); + + t.end(); +});