├── .coveragerc ├── .github └── workflows │ ├── build_test.yml │ ├── codeql-analysis.yml │ └── deploy.yml ├── .gitignore ├── .readthedocs.yaml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── docs ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── _templates │ └── autosummary │ │ ├── base.rst │ │ ├── class.rst │ │ └── module.rst │ ├── acknowledgments.rst │ ├── authors.rst │ ├── conf.py │ ├── index.rst │ ├── quickstart.md │ └── reference │ ├── api │ ├── mtalg.add.rst │ ├── mtalg.div.rst │ ├── mtalg.get_num_threads.rst │ ├── mtalg.mul.rst │ ├── mtalg.pow.rst │ ├── mtalg.random.MultithreadedRNG.beta.rst │ ├── mtalg.random.MultithreadedRNG.binomial.rst │ ├── mtalg.random.MultithreadedRNG.chisquare.rst │ ├── mtalg.random.MultithreadedRNG.exponential.rst │ ├── mtalg.random.MultithreadedRNG.f.rst │ ├── mtalg.random.MultithreadedRNG.gamma.rst │ ├── mtalg.random.MultithreadedRNG.geometric.rst │ ├── mtalg.random.MultithreadedRNG.gumbel.rst │ ├── mtalg.random.MultithreadedRNG.hypergeometric.rst │ ├── mtalg.random.MultithreadedRNG.integers.rst │ ├── mtalg.random.MultithreadedRNG.laplace.rst │ ├── mtalg.random.MultithreadedRNG.logistic.rst │ ├── mtalg.random.MultithreadedRNG.lognormal.rst │ ├── mtalg.random.MultithreadedRNG.logseries.rst │ ├── mtalg.random.MultithreadedRNG.negative_binomial.rst │ ├── mtalg.random.MultithreadedRNG.noncentral_chisquare.rst │ ├── mtalg.random.MultithreadedRNG.noncentral_f.rst │ ├── mtalg.random.MultithreadedRNG.normal.rst │ ├── mtalg.random.MultithreadedRNG.pareto.rst │ ├── mtalg.random.MultithreadedRNG.poisson.rst │ ├── mtalg.random.MultithreadedRNG.power.rst │ ├── mtalg.random.MultithreadedRNG.random.rst │ ├── mtalg.random.MultithreadedRNG.rayleigh.rst │ ├── mtalg.random.MultithreadedRNG.rst │ ├── mtalg.random.MultithreadedRNG.standard_cauchy.rst │ ├── mtalg.random.MultithreadedRNG.standard_exponential.rst │ ├── mtalg.random.MultithreadedRNG.standard_gamma.rst │ ├── mtalg.random.MultithreadedRNG.standard_normal.rst │ ├── mtalg.random.MultithreadedRNG.standard_t.rst │ ├── mtalg.random.MultithreadedRNG.triangular.rst │ ├── mtalg.random.MultithreadedRNG.uniform.rst │ ├── mtalg.random.MultithreadedRNG.vonmises.rst │ ├── mtalg.random.MultithreadedRNG.wald.rst │ ├── mtalg.random.MultithreadedRNG.weibull.rst │ ├── mtalg.random.MultithreadedRNG.zipf.rst │ ├── mtalg.random.beta.rst │ ├── mtalg.random.binomial.rst │ ├── mtalg.random.chisquare.rst │ ├── mtalg.random.exponential.rst │ ├── mtalg.random.f.rst │ ├── mtalg.random.gamma.rst │ ├── mtalg.random.geometric.rst │ ├── mtalg.random.gumbel.rst │ ├── mtalg.random.hypergeometric.rst │ ├── mtalg.random.integers.rst │ ├── mtalg.random.laplace.rst │ ├── mtalg.random.logistic.rst │ ├── mtalg.random.lognormal.rst │ ├── mtalg.random.logseries.rst │ ├── mtalg.random.negative_binomial.rst │ ├── mtalg.random.noncentral_chisquare.rst │ ├── mtalg.random.noncentral_f.rst │ ├── mtalg.random.normal.rst │ ├── mtalg.random.pareto.rst │ ├── mtalg.random.poisson.rst │ ├── mtalg.random.power.rst │ ├── mtalg.random.random.rst │ ├── mtalg.random.rayleigh.rst │ ├── mtalg.random.standard_cauchy.rst │ ├── mtalg.random.standard_exponential.rst │ ├── mtalg.random.standard_gamma.rst │ ├── mtalg.random.standard_normal.rst │ ├── mtalg.random.standard_t.rst │ ├── mtalg.random.triangular.rst │ ├── mtalg.random.uniform.rst │ ├── mtalg.random.vonmises.rst │ ├── mtalg.random.wald.rst │ ├── mtalg.random.weibull.rst │ ├── mtalg.random.zipf.rst │ ├── mtalg.set_num_threads.rst │ └── mtalg.sub.rst │ └── index.rst ├── mtalg ├── __about__.py ├── __init__.py ├── __res │ ├── _MTA.png │ ├── __init__.py │ └── benchmark │ │ ├── benchmark_add.png │ │ ├── benchmark_add.svg │ │ ├── benchmark_add_BARS.png │ │ ├── benchmark_add_BARS.svg │ │ ├── benchmark_rng.png │ │ ├── benchmark_rng.svg │ │ ├── benchmark_rng_BAR.png │ │ └── benchmark_rng_BAR.svg ├── alg │ ├── __init__.py │ └── elementwise_algebra.py ├── core │ ├── __init__.py │ └── threads.py ├── dev-requirements.txt ├── random │ ├── __init__.py │ └── random_number_generators.py ├── requirements.txt ├── testing │ ├── __init__.py │ ├── benchmarks_em_algebra.py │ ├── benchmarks_rng.py │ ├── test_core.py │ ├── test_em_algebra.py │ ├── test_random.py │ └── test_rng.py └── tools │ ├── __get_threads.py │ ├── __init__.py │ └── __set_threads.py ├── setup.py └── sonar-project.properties /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | mtalg/__res/* 4 | mtalg/testing/* 5 | -------------------------------------------------------------------------------- /.github/workflows/build_test.yml: -------------------------------------------------------------------------------- 1 | name: build and test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | build-and-test: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - run: echo "🎉 The job was triggered by a ${{ github.event_name }} event." 16 | - uses: actions/checkout@v2 17 | - name: Set up Python 3.7 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: "3.7" 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install flake8 pytest pytest-cov numba 25 | pip install -r mtalg/requirements.txt 26 | - name: Lint with flake8 27 | run: | 28 | # stop the build if there are Python syntax errors or undefined names 29 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 30 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 31 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 32 | - name: Test with pytest 33 | run: | 34 | pytest mtalg/testing/ --cov-config=.coveragerc --cov=mtalg mtalg/testing/ --cov-report xml:cov.xml --junitxml=unit.xml 35 | - name: Override coverage source path for Sonar 36 | run: sed -i "s/\/home\/runner\/work\/mtalg\/mtalg\/mtalg<\/source>/\/github\/workspace\/mtalg<\/source>/g" /home/runner/work/mtalg/mtalg/cov.xml 37 | - name: Store coverage 38 | uses: actions/upload-artifact@v2 39 | with: 40 | name: pytest_reports 41 | path: | 42 | cov.xml 43 | unit.xml 44 | 45 | test-multiple-os: 46 | name: Test on ${{ matrix.os }} 47 | strategy: 48 | matrix: 49 | os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] 50 | containers: [1] 51 | runs-on: ${{ matrix.os }} 52 | steps: 53 | - name: Checkout 54 | uses: actions/checkout@v1 55 | 56 | - name: Set up Python 3.7 57 | uses: actions/setup-python@v2 58 | with: 59 | python-version: "3.7" 60 | 61 | - name: Install dependencies 62 | run: | 63 | python -m pip install --upgrade pip 64 | pip install flake8 pytest pytest-cov numba 65 | pip install -r mtalg/requirements.txt 66 | 67 | - name: Run tests 68 | run: | 69 | python -c "import sys; print(f'OS: {sys.platform}')" 70 | python -c "import sys; print(f'Python version: {sys.version}')" 71 | pytest mtalg/testing/ 72 | 73 | test-python-versions: 74 | name: Test on Python${{ matrix.vrsns }} 75 | strategy: 76 | matrix: 77 | vrsns: ['3.7', '3.8', '3.9'] 78 | containers: [1] 79 | runs-on: ubuntu-latest 80 | steps: 81 | - name: Checkout 82 | uses: actions/checkout@v1 83 | 84 | - name: Set up Python ${{ matrix.vrsns }} 85 | uses: actions/setup-python@v2 86 | with: 87 | python-version: "${{ matrix.vrsns }}" 88 | 89 | - name: Install dependencies 90 | run: | 91 | python -m pip install --upgrade pip 92 | pip install flake8 pytest pytest-cov numba 93 | pip install -r mtalg/requirements.txt 94 | 95 | - name: Run tests 96 | run: | 97 | python -c "import sys; print(f'OS: {sys.platform}')" 98 | python -c "import sys; print(f'Python version: {sys.version}')" 99 | pytest mtalg/testing/ 100 | 101 | sonarcloud: 102 | name: SonarCloud 103 | needs: [build-and-test, test-multiple-os, test-python-versions] 104 | runs-on: ubuntu-latest 105 | steps: 106 | - uses: actions/checkout@v2 107 | with: 108 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 109 | - name: Get Pytest reports 110 | uses: actions/download-artifact@v2 111 | with: 112 | name: pytest_reports 113 | - name: SonarCloud Scan 114 | uses: SonarSource/sonarcloud-github-action@master 115 | env: 116 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 117 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 118 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '42 17 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'python' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v1 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v1 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v1 71 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: deploy 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | deploy: 7 | environment: Deploy 8 | runs-on: ubuntu-latest 9 | steps: 10 | - run: echo "Starting deployment to PyPi" 11 | - uses: actions/checkout@v2 12 | - name: Set up Python 3.10 13 | uses: actions/setup-python@v2 14 | with: 15 | python-version: "3.10" 16 | - name: Install helpers 17 | run: | 18 | python -m pip install --upgrade pip 19 | pip install twine wheel 20 | - name: Build 21 | run: python3 setup.py sdist bdist_wheel 22 | - name: Deploy to PyPi 23 | env: 24 | TEST_U: ${{ secrets.TEST_U }} 25 | TEST_P: ${{ secrets.TEST_P }} 26 | TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }} 27 | TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} 28 | run: | 29 | twine upload -r testpypi dist/* -u $TEST_U -p $TEST_P 30 | twine upload dist/* 31 | - run: echo "Sucessfully deployed to PyPi" 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | MY_GITLAB_KEY 2 | __RES/ 3 | README_DEVELOPER.md 4 | {{* 5 | *.csv 6 | .* 7 | */__pycache__ 8 | !.circleci 9 | !.gitignore 10 | !.coveragerc 11 | 12 | build 13 | dist 14 | mtalg.egg-info 15 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.12" 12 | # You can also specify other tool versions: 13 | # nodejs: "20" 14 | # rust: "1.70" 15 | # golang: "1.20" 16 | 17 | # Build documentation in the "docs/" directory with Sphinx 18 | sphinx: 19 | configuration: docs/source/conf.py 20 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs 21 | # builder: "dirhtml" 22 | # Fail on all warnings to avoid broken references 23 | # fail_on_warning: true 24 | 25 | # Optionally build your docs in additional formats such as PDF and ePub 26 | # formats: 27 | # - pdf 28 | # - epub 29 | 30 | # Optional but recommended, declare the Python requirements required 31 | # to build your documentation 32 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 33 | python: 34 | install: 35 | - requirements: docs/requirements.txt 36 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## \[Unreleased] - yyyy-mm-dd 8 | 9 | ### Added 10 | 11 | ## \[1.1.2] - 2023-11-23 12 | 13 | ### Added 14 | - Project links 15 | 16 | ## \[1.1.1] - 2023-11-23 17 | 18 | ### Added 19 | - Sphinx docs 20 | 21 | ### Changed 22 | - Removed CDSW threads check 23 | 24 | ## \[1.1.0] - 2022-01-05 25 | 26 | ### Changed 27 | - cpu_count() as default for _global_num_threads 28 | 29 | ### Added 30 | 31 | - Added `get_num_threads` 32 | 33 | ### Fixed 34 | 35 | - Improved documentation 36 | 37 | ## \[1.0.0] - 2021-12-28 38 | 39 | ### Added 40 | - integer and random methods to MRNG 41 | - set_num_threads function 42 | - different generators can be chosen for MRNG 43 | - return of float when size=None for MRNG 44 | - all MRNG methods can be accessed from mtalg.random as well 45 | - More documentation 46 | 47 | ### Changed 48 | - MRNG methods returns instead of haveing to access mrng.values 49 | - MRNG attributes made private 50 | 51 | ### Fixed 52 | - Handling of scalars in alg functions 53 | 54 | ## \[0.1.4] - 2021-12-24 55 | 56 | ### Added 57 | - Almost all distributions 58 | 59 | ## \[0.1.2, 0.1.3] - 2021-12-23 60 | 61 | ### Fixed 62 | - Github pipeline 63 | 64 | ## \[0.1.1] - 2021-12-22 65 | 66 | ### Changed 67 | - simplified num_threads check, changed alg functions to lowercase as per convention 68 | 69 | ## \[0.0.7] - 2021-12-22 70 | 71 | ### Added 72 | - Can call random functions directly from mtalg.random 73 | 74 | ### Fixed 75 | - Bug in mtalg/tools 76 | 77 | ## \[0.0.6] - 2021-12-21 78 | 79 | ### Changed 80 | - Removed numba from dependencies, added as optional dependency 81 | 82 | ## \[0.0.5] - 2021-12-14 83 | 84 | ### Fixed 85 | - np.integer recognized in _check_shape 86 | 87 | ## \[0.0.4] - 2021-11-26 88 | 89 | ### Added 90 | 91 | ### Changed 92 | - Functions given simpler names 93 | 94 | ### Fixed 95 | 96 | ## \[0.0.3] - 2021-11-19 97 | 98 | ### Added 99 | - Multithreaded algebra with scalars 100 | - Support past standard normal distribution 101 | - Different distributions for random sampling 102 | 103 | ### Changed 104 | 105 | ### Fixed 106 | 107 | ## \[0.0.2] - 2021-11-19 108 | 109 | ### Added 110 | 111 | - Generalised multithreaded random number generation 112 | - Benchmarking of multithreaded elementwise algebra 113 | - Benchmarking of multithreaded random number generation 114 | 115 | ## \[0.0.1] - 2021-11-18 116 | 117 | ### Added 118 | - Multithreaded elementwise algebra 119 | - Multithreaded random number generation of 2D matrices 120 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Wouter Wakker, Luca Mingarelli 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | ------------------------------------------------------------------------------- 22 | Note: 23 | The docstrings of the random number generator methods are based on NumPy's 24 | docstrings. 25 | The NumPy license is included in mtalg/random/random_number_generators.py -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![](https://github.com/WWakker/mtalg/raw/master/mtalg/__res/_MTA.png) *mtalg* — Multithreaded Algebra 2 | 3 | [![version](https://img.shields.io/badge/version-1.1.2-success.svg)](https://github.com/WWakker/mtalg) 4 | [![PyPI Latest Release](https://img.shields.io/pypi/v/mtalg.svg)](https://pypi.org/project/mtalg/) 5 | [![build_test](https://github.com/WWakker/mtalg/actions/workflows/build_test.yml/badge.svg)](https://github.com/WWakker/mtalg/actions?query=workflow%3A%22build+and+test%22++) 6 | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=WWakker_mtalg&metric=alert_status)](https://sonarcloud.io/summary/overall?id=WWakker_mtalg) 7 | [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=WWakker_mtalg&metric=coverage)](https://sonarcloud.io/summary/overall?id=WWakker_mtalg) 8 | [![Security](https://snyk-widget.herokuapp.com/badge/pip/mtalg/badge.svg)](https://snyk.io/vuln/pip:mtalg) 9 | [![CodeQL](https://github.com/WWakker/mtalg/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/WWakker/mtalg/actions/workflows/codeql-analysis.yml) 10 | [![License](https://img.shields.io/pypi/l/mtalg.svg)](https://github.com/WWakker/mtalg/blob/master/LICENSE.txt) 11 | [![Downloads](https://pepy.tech/badge/mtalg)](https://pepy.tech/project/mtalg) 12 | [![Run on Repl.it](https://repl.it/badge/github/wwakker/mtalg)](https://replit.com/@lucamingarelli/Try-mtalg#main.py) 13 | 14 | 15 | ## About 16 | 17 | ***mtalg*** is a package for multithreaded algebra and random number generation. 18 | 19 | ## Installation 20 | The library can be install via pip as: 21 | 22 | `pip install mtalg` 23 | 24 | ## Documentation 25 | 26 | - https://mtalg.readthedocs.io 27 | 28 | ## Authors 29 | [Wouter Wakker](https://github.com/WWakker) 30 | and [Luca Mingarelli](https://github.com/LucaMingarelli), 31 | 2021 32 | 33 | [![Python](https://img.shields.io/static/v1?label=made%20with&message=Python&color=blue&style=for-the-badge&logo=Python&logoColor=white)](#) -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | sphinx-rtd-theme 3 | sphobjinv 4 | myst-nb 5 | numpy 6 | -------------------------------------------------------------------------------- /docs/source/_templates/autosummary/base.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. auto{{ objtype }}:: {{ objname }} 6 | -------------------------------------------------------------------------------- /docs/source/_templates/autosummary/class.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autoclass:: {{ objname }} 6 | :no-members: 7 | 8 | {% block methods %} 9 | 10 | {% if methods %} 11 | .. rubric:: {{ _('Methods') }} 12 | 13 | .. autosummary:: 14 | :toctree: 15 | 16 | {% for item in methods %} 17 | {% if item != '__init__' %} 18 | ~{{ name }}.{{ item }} 19 | {% endif %} 20 | {%- endfor %} 21 | {% endif %} 22 | {% endblock %} 23 | 24 | {% block attributes %} 25 | {% if attributes %} 26 | .. rubric:: {{ _('Attributes') }} 27 | 28 | .. autosummary:: 29 | {% for item in attributes %} 30 | ~{{ name }}.{{ item }} 31 | {%- endfor %} 32 | {% endif %} 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /docs/source/_templates/autosummary/module.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. automodule:: {{ fullname }} 4 | 5 | {% block attributes %} 6 | {% if attributes %} 7 | .. rubric:: {{ _('Module Attributes') }} 8 | 9 | .. autosummary:: 10 | {% for item in attributes %} 11 | {{ item }} 12 | {%- endfor %} 13 | {% endif %} 14 | {% endblock %} 15 | 16 | {% block functions %} 17 | {% if functions %} 18 | .. rubric:: {{ _('Functions') }} 19 | 20 | .. autosummary:: 21 | {% for item in functions %} 22 | {{ item }} 23 | {%- endfor %} 24 | {% endif %} 25 | {% endblock %} 26 | 27 | {% block classes %} 28 | {% if classes %} 29 | .. rubric:: {{ _('Classes') }} 30 | 31 | .. autosummary:: 32 | {% for item in classes %} 33 | {{ item }} 34 | {%- endfor %} 35 | {% endif %} 36 | {% endblock %} 37 | 38 | {% block exceptions %} 39 | {% if exceptions %} 40 | .. rubric:: {{ _('Exceptions') }} 41 | 42 | .. autosummary:: 43 | {% for item in exceptions %} 44 | {{ item }} 45 | {%- endfor %} 46 | {% endif %} 47 | {% endblock %} 48 | 49 | {% block modules %} 50 | {% if modules %} 51 | .. rubric:: Modules 52 | 53 | .. autosummary:: 54 | :toctree: 55 | :recursive: 56 | {% for item in modules %} 57 | {{ item }} 58 | {%- endfor %} 59 | {% endif %} 60 | {% endblock %} 61 | -------------------------------------------------------------------------------- /docs/source/acknowledgments.rst: -------------------------------------------------------------------------------- 1 | Acknowledgments 2 | ############### 3 | 4 | The module for multithreaded generation of random numbers is inspired from :std:doc:`numpy:reference/random/multithreading`. 5 | 6 | Logo inspired from the work of `taawon `_. 7 | -------------------------------------------------------------------------------- /docs/source/authors.rst: -------------------------------------------------------------------------------- 1 | Authors 2 | ####### 3 | 4 | `Wouter Wakker `_ and 5 | `Luca Mingarelli `_, 6 | 2021 7 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath('../..')) 5 | import mtalg 6 | 7 | # Configuration file for the Sphinx documentation builder. 8 | # 9 | # For the full list of built-in configuration values, see the documentation: 10 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 11 | 12 | # -- Project information ----------------------------------------------------- 13 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 14 | 15 | project = 'mtalg' 16 | copyright = '2023, Wouter Wakker, Luca Mingarelli' 17 | author = 'Wouter Wakker, Luca Mingarelli' 18 | release = mtalg.__version__ 19 | language = "en" 20 | 21 | # -- General configuration --------------------------------------------------- 22 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 23 | 24 | extensions = ['sphinx.ext.autosummary', 25 | 'sphinx.ext.napoleon', 26 | 'sphinx.ext.intersphinx', 27 | 'sphinx.ext.viewcode', 28 | 'sphinx.ext.autosectionlabel', 29 | 'myst_nb'] 30 | 31 | templates_path = ['_templates'] 32 | exclude_patterns = ["**.ipynb_checkpoints"] 33 | 34 | autodoc_default_options = { 35 | 'members': True, 36 | 'member-order': 'bysource', 37 | 'undoc-members': True, 38 | 'exclude-members': '__init__' 39 | } 40 | 41 | add_module_names = False 42 | autoclass_content = 'class' 43 | autosummary_generate = True 44 | autosummary_imported_members = True 45 | 46 | # -- Options for HTML output ------------------------------------------------- 47 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 48 | 49 | # Intersphinx 50 | intersphinx_mapping = { 51 | "sphinx": ("https://www.sphinx-doc.org/en/master", None), 52 | 'python': ('http://docs.python.org/3', None), 53 | 'numpy': ('https://numpy.org/doc/stable', None), 54 | 'scipy': ('https://docs.scipy.org/doc/scipy', None), 55 | 'matplotlib': ('https://matplotlib.org/stable', None), 56 | 'pandas': ('https://pandas.pydata.org/docs', None) 57 | } 58 | intersphinx_disabled_reftypes = ["*"] 59 | 60 | html_theme = 'sphinx_rtd_theme' 61 | html_static_path = ['_static'] 62 | html_show_sourcelink = False 63 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | mtalg documentation 2 | =================== 3 | 4 | Multithreaded algebra and random number generation. 5 | 6 | .. image:: ../../mtalg/__res/_MTA.png 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | :caption: Contents: 11 | 12 | quickstart 13 | reference/index 14 | acknowledgments 15 | authors 16 | -------------------------------------------------------------------------------- /docs/source/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quick start guide 2 | 3 | ***mtalg*** is a package for multithreaded algebra and random number generation. 4 | 5 | While numpy does support out of the box multithreaded linear algebra 6 | ([numpy.linalg](https://numpy.org/doc/stable/reference/routines.linalg.html)) 7 | for operations such as matrix multiplication, decomposition, spectral analysis, 8 | and related functions, which are building on libraries such as BLAS and LAPACK, 9 | the same does not hold true for simpler algebraic element-wise operations. 10 | Similarly can be said for the generation of random variates. 11 | 12 | ***mtalg*** is the fastest library known to us for large scale element-wise algebraic operations 13 | and non-GPU-based random number generation. For more info on benchmarks you can see the dedicated section below. 14 | 15 | Major benefits become apparent past 10⁷ operations for both the element-wise algebra and the random number generator modules. 16 | 17 | ## Installation 18 | The library can be install via pip as: 19 | 20 | ```shell 21 | pip install mtalg 22 | ``` 23 | 24 | ## How to use 25 | Import mtalg and generate pseudorandom numbers as 26 | 27 | ```python 28 | import mtalg 29 | 30 | a = mtalg.random.standard_normal(size=(10_000, 5_000)) 31 | b = mtalg.random.uniform(size=(10_000, 5_000), low=0, high=10) 32 | # etc. 33 | ``` 34 | 35 | Alternatively, one can also do 36 | ```python 37 | from mtalg.random import MultithreadedRNG 38 | ``` 39 | 40 | and create an instance of the multithreaded random number generator with seed for reproducibility and set the number of threads to be used. 41 | 42 | ```python 43 | mrng = MultithreadedRNG(seed=1, num_threads=4) 44 | ``` 45 | 46 | One can then create random arrays as 47 | 48 | ```python 49 | a = mrng.standard_normal(size=(10_000, 5_000)) 50 | b = mrng.uniform(size=(10_000, 5_000), low=0, high=10) 51 | # etc. 52 | ``` 53 | 54 | Set number of threads to be used by default for algebra functions and subsquent random 55 | number generators (if `num_threads` parameter is not specified). 56 | 57 | ```python 58 | mtalg.set_num_threads(4) 59 | ``` 60 | 61 | Add `b` to `a` (`a` is modified in-place). 62 | 63 | ```python 64 | mtalg.add(a, b) 65 | ``` 66 | 67 | Subtract `a` from `b` (`b` is modified in-place). 68 | 69 | ```python 70 | mtalg.sub(a, b, direction='right') 71 | ``` 72 | 73 | Multiply, divide and raise to power (`a` is modified in-place). 74 | 75 | ```python 76 | mtalg.mul(a, b) 77 | mtalg.div(a, b) 78 | mtalg.pow(a, b) 79 | ``` 80 | 81 | ## Benchmarks 82 | 83 | ### Elementwise algebra 84 | ![](../../mtalg/__res/benchmark/benchmark_add_BARS.svg) 85 | 86 | ![](../../mtalg/__res/benchmark/benchmark_add.svg) 87 | 88 | ### Random number generation 89 | 90 | ![](../../mtalg/__res/benchmark/benchmark_rng_BAR.svg) 91 | 92 | ![](../../mtalg/__res/benchmark/benchmark_rng.svg) 93 | 94 | \* Benchmarks are carrried out using an Intel(R) Xeon(R) Gold 6142M CPU @ 2.60GHz and 24 threads. 95 | -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.add.rst: -------------------------------------------------------------------------------- 1 | mtalg.add 2 | ========= 3 | 4 | .. currentmodule:: mtalg 5 | 6 | .. autofunction:: add -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.div.rst: -------------------------------------------------------------------------------- 1 | mtalg.div 2 | ========= 3 | 4 | .. currentmodule:: mtalg 5 | 6 | .. autofunction:: div -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.get_num_threads.rst: -------------------------------------------------------------------------------- 1 | mtalg.get\_num\_threads 2 | ======================= 3 | 4 | .. currentmodule:: mtalg 5 | 6 | .. autofunction:: get_num_threads -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.mul.rst: -------------------------------------------------------------------------------- 1 | mtalg.mul 2 | ========= 3 | 4 | .. currentmodule:: mtalg 5 | 6 | .. autofunction:: mul -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.pow.rst: -------------------------------------------------------------------------------- 1 | mtalg.pow 2 | ========= 3 | 4 | .. currentmodule:: mtalg 5 | 6 | .. autofunction:: pow -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.beta.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.beta 2 | ================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.beta -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.binomial.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.binomial 2 | ====================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.binomial -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.chisquare.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.chisquare 2 | ======================================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.chisquare -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.exponential.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.exponential 2 | ========================================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.exponential -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.f.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.f 2 | =============================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.f -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.gamma.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.gamma 2 | =================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.gamma -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.geometric.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.geometric 2 | ======================================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.geometric -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.gumbel.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.gumbel 2 | ==================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.gumbel -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.hypergeometric.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.hypergeometric 2 | ============================================ 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.hypergeometric -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.integers.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.integers 2 | ====================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.integers -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.laplace.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.laplace 2 | ===================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.laplace -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.logistic.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.logistic 2 | ====================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.logistic -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.lognormal.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.lognormal 2 | ======================================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.lognormal -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.logseries.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.logseries 2 | ======================================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.logseries -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.negative_binomial.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.negative\_binomial 2 | ================================================ 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.negative_binomial -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.noncentral_chisquare.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.noncentral\_chisquare 2 | =================================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.noncentral_chisquare -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.noncentral_f.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.noncentral\_f 2 | =========================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.noncentral_f -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.normal.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.normal 2 | ==================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.normal -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.pareto.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.pareto 2 | ==================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.pareto -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.poisson.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.poisson 2 | ===================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.poisson -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.power.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.power 2 | =================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.power -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.random.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.random 2 | ==================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.random -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.rayleigh.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.rayleigh 2 | ====================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.rayleigh -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG 2 | ============================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autoclass:: MultithreadedRNG 7 | :no-members: 8 | 9 | 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | :toctree: 16 | 17 | 18 | 19 | 20 | ~MultithreadedRNG.beta 21 | 22 | 23 | ~MultithreadedRNG.binomial 24 | 25 | 26 | ~MultithreadedRNG.chisquare 27 | 28 | 29 | ~MultithreadedRNG.exponential 30 | 31 | 32 | ~MultithreadedRNG.f 33 | 34 | 35 | ~MultithreadedRNG.gamma 36 | 37 | 38 | ~MultithreadedRNG.geometric 39 | 40 | 41 | ~MultithreadedRNG.gumbel 42 | 43 | 44 | ~MultithreadedRNG.hypergeometric 45 | 46 | 47 | ~MultithreadedRNG.integers 48 | 49 | 50 | ~MultithreadedRNG.laplace 51 | 52 | 53 | ~MultithreadedRNG.logistic 54 | 55 | 56 | ~MultithreadedRNG.lognormal 57 | 58 | 59 | ~MultithreadedRNG.logseries 60 | 61 | 62 | ~MultithreadedRNG.negative_binomial 63 | 64 | 65 | ~MultithreadedRNG.noncentral_chisquare 66 | 67 | 68 | ~MultithreadedRNG.noncentral_f 69 | 70 | 71 | ~MultithreadedRNG.normal 72 | 73 | 74 | ~MultithreadedRNG.pareto 75 | 76 | 77 | ~MultithreadedRNG.poisson 78 | 79 | 80 | ~MultithreadedRNG.power 81 | 82 | 83 | ~MultithreadedRNG.random 84 | 85 | 86 | ~MultithreadedRNG.rayleigh 87 | 88 | 89 | ~MultithreadedRNG.standard_cauchy 90 | 91 | 92 | ~MultithreadedRNG.standard_exponential 93 | 94 | 95 | ~MultithreadedRNG.standard_gamma 96 | 97 | 98 | ~MultithreadedRNG.standard_normal 99 | 100 | 101 | ~MultithreadedRNG.standard_t 102 | 103 | 104 | ~MultithreadedRNG.triangular 105 | 106 | 107 | ~MultithreadedRNG.uniform 108 | 109 | 110 | ~MultithreadedRNG.vonmises 111 | 112 | 113 | ~MultithreadedRNG.wald 114 | 115 | 116 | ~MultithreadedRNG.weibull 117 | 118 | 119 | ~MultithreadedRNG.zipf 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.standard_cauchy.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.standard\_cauchy 2 | ============================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.standard_cauchy -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.standard_exponential.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.standard\_exponential 2 | =================================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.standard_exponential -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.standard_gamma.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.standard\_gamma 2 | ============================================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.standard_gamma -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.standard_normal.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.standard\_normal 2 | ============================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.standard_normal -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.standard_t.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.standard\_t 2 | ========================================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.standard_t -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.triangular.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.triangular 2 | ======================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.triangular -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.uniform.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.uniform 2 | ===================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.uniform -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.vonmises.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.vonmises 2 | ====================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.vonmises -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.wald.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.wald 2 | ================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.wald -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.weibull.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.weibull 2 | ===================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.weibull -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.MultithreadedRNG.zipf.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.MultithreadedRNG.zipf 2 | ================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. automethod:: MultithreadedRNG.zipf -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.beta.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.beta 2 | ================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: beta -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.binomial.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.binomial 2 | ===================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: binomial -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.chisquare.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.chisquare 2 | ====================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: chisquare -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.exponential.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.exponential 2 | ======================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: exponential -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.f.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.f 2 | ============== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: f -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.gamma.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.gamma 2 | ================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: gamma -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.geometric.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.geometric 2 | ====================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: geometric -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.gumbel.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.gumbel 2 | =================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: gumbel -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.hypergeometric.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.hypergeometric 2 | =========================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: hypergeometric -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.integers.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.integers 2 | ===================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: integers -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.laplace.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.laplace 2 | ==================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: laplace -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.logistic.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.logistic 2 | ===================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: logistic -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.lognormal.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.lognormal 2 | ====================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: lognormal -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.logseries.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.logseries 2 | ====================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: logseries -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.negative_binomial.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.negative\_binomial 2 | =============================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: negative_binomial -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.noncentral_chisquare.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.noncentral\_chisquare 2 | ================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: noncentral_chisquare -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.noncentral_f.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.noncentral\_f 2 | ========================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: noncentral_f -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.normal.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.normal 2 | =================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: normal -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.pareto.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.pareto 2 | =================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: pareto -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.poisson.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.poisson 2 | ==================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: poisson -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.power.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.power 2 | ================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: power -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.random.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.random 2 | =================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: random -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.rayleigh.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.rayleigh 2 | ===================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: rayleigh -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.standard_cauchy.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.standard\_cauchy 2 | ============================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: standard_cauchy -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.standard_exponential.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.standard\_exponential 2 | ================================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: standard_exponential -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.standard_gamma.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.standard\_gamma 2 | ============================ 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: standard_gamma -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.standard_normal.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.standard\_normal 2 | ============================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: standard_normal -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.standard_t.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.standard\_t 2 | ======================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: standard_t -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.triangular.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.triangular 2 | ======================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: triangular -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.uniform.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.uniform 2 | ==================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: uniform -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.vonmises.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.vonmises 2 | ===================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: vonmises -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.wald.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.wald 2 | ================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: wald -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.weibull.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.weibull 2 | ==================== 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: weibull -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.random.zipf.rst: -------------------------------------------------------------------------------- 1 | mtalg.random.zipf 2 | ================= 3 | 4 | .. currentmodule:: mtalg.random 5 | 6 | .. autofunction:: zipf -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.set_num_threads.rst: -------------------------------------------------------------------------------- 1 | mtalg.set\_num\_threads 2 | ======================= 3 | 4 | .. currentmodule:: mtalg 5 | 6 | .. autofunction:: set_num_threads -------------------------------------------------------------------------------- /docs/source/reference/api/mtalg.sub.rst: -------------------------------------------------------------------------------- 1 | mtalg.sub 2 | ========= 3 | 4 | .. currentmodule:: mtalg 5 | 6 | .. autofunction:: sub -------------------------------------------------------------------------------- /docs/source/reference/index.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | API reference 3 | ============= 4 | 5 | .. currentmodule:: mtalg 6 | 7 | Multithreading settings 8 | ~~~~~~~~~~~~~~~~~~~~~~~ 9 | .. autosummary:: 10 | :toctree: api/ 11 | 12 | get_num_threads 13 | set_num_threads 14 | 15 | Linear algebra 16 | ~~~~~~~~~~~~~~ 17 | .. autosummary:: 18 | :toctree: api/ 19 | 20 | add 21 | div 22 | mul 23 | pow 24 | sub 25 | 26 | Pseudorandom number generation 27 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 28 | 29 | Constructor 30 | ----------- 31 | .. autosummary:: 32 | :toctree: api/ 33 | :template: autosummary/class.rst 34 | 35 | random.MultithreadedRNG 36 | 37 | Functions 38 | ----------- 39 | 40 | The functions below are the same as the methods of the :doc:`MultithreadedRNG ` 41 | defined above, as it comes from an instance of this class, instantiated with default arguments and seed as set by 42 | :std:doc:`numpy:reference/random/generated/numpy.random.seed`. 43 | 44 | .. note:: 45 | For more information on distributions, see 46 | `Random generator distributions `_. 47 | 48 | .. autosummary:: 49 | :toctree: api/ 50 | 51 | random.beta 52 | random.binomial 53 | random.chisquare 54 | random.exponential 55 | random.f 56 | random.gamma 57 | random.geometric 58 | random.gumbel 59 | random.hypergeometric 60 | random.integers 61 | random.laplace 62 | random.logistic 63 | random.lognormal 64 | random.logseries 65 | random.negative_binomial 66 | random.noncentral_chisquare 67 | random.noncentral_f 68 | random.normal 69 | random.pareto 70 | random.poisson 71 | random.power 72 | random.random 73 | random.rayleigh 74 | random.standard_cauchy 75 | random.standard_exponential 76 | random.standard_gamma 77 | random.standard_normal 78 | random.standard_t 79 | random.triangular 80 | random.uniform 81 | random.vonmises 82 | random.wald 83 | random.weibull 84 | random.zipf 85 | -------------------------------------------------------------------------------- /mtalg/__about__.py: -------------------------------------------------------------------------------- 1 | __title__ = "mtalg" 2 | __about__ = "A library for elementwise multithreaded algebra and multithreaded random number generation." 3 | __version__ = '1.1.2' 4 | __authors__ = 'Wouter Wakker and Luca Mingarelli' 5 | __email__ = "lucamingarelli@me.com" 6 | __url__ = "https://github.com/WWakker/mtalg" 7 | -------------------------------------------------------------------------------- /mtalg/__init__.py: -------------------------------------------------------------------------------- 1 | from mtalg.__about__ import (__title__, __version__, 2 | __about__, __email__, 3 | __authors__, __url__) 4 | from mtalg.alg import add, sub, div, mul, pow, std 5 | import mtalg.random 6 | from mtalg.tools.__set_threads import set_num_threads 7 | from mtalg.tools.__get_threads import get_num_threads 8 | import mtalg.core.threads 9 | -------------------------------------------------------------------------------- /mtalg/__res/_MTA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWakker/mtalg/b4345bfb14aa8aef90e19d126525b0ea1e81b9a7/mtalg/__res/_MTA.png -------------------------------------------------------------------------------- /mtalg/__res/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWakker/mtalg/b4345bfb14aa8aef90e19d126525b0ea1e81b9a7/mtalg/__res/__init__.py -------------------------------------------------------------------------------- /mtalg/__res/benchmark/benchmark_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWakker/mtalg/b4345bfb14aa8aef90e19d126525b0ea1e81b9a7/mtalg/__res/benchmark/benchmark_add.png -------------------------------------------------------------------------------- /mtalg/__res/benchmark/benchmark_add_BARS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWakker/mtalg/b4345bfb14aa8aef90e19d126525b0ea1e81b9a7/mtalg/__res/benchmark/benchmark_add_BARS.png -------------------------------------------------------------------------------- /mtalg/__res/benchmark/benchmark_add_BARS.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 35 | 36 | 37 | 38 | 39 | 69 | 89 | 121 | 127 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 175 | 176 | 177 | 178 | 179 | 198 | 219 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 259 | 260 | 261 | 262 | 263 | 287 | 301 | 327 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 360 | 361 | 362 | 363 | 364 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 397 | 398 | 399 | 400 | 401 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 433 | 434 | 435 | 436 | 437 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 461 | 462 | 463 | 464 | 465 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 500 | 501 | 502 | 503 | 504 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 547 | 548 | 549 | 550 | 551 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 591 | 612 | 623 | 644 | 645 | 655 | 686 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 728 | 729 | 730 | 736 | 737 | 738 | 744 | 745 | 746 | 752 | 753 | 754 | 757 | 758 | 759 | 762 | 763 | 764 | 767 | 768 | 769 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | -------------------------------------------------------------------------------- /mtalg/__res/benchmark/benchmark_rng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWakker/mtalg/b4345bfb14aa8aef90e19d126525b0ea1e81b9a7/mtalg/__res/benchmark/benchmark_rng.png -------------------------------------------------------------------------------- /mtalg/__res/benchmark/benchmark_rng_BAR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWakker/mtalg/b4345bfb14aa8aef90e19d126525b0ea1e81b9a7/mtalg/__res/benchmark/benchmark_rng_BAR.png -------------------------------------------------------------------------------- /mtalg/__res/benchmark/benchmark_rng_BAR.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 35 | 36 | 37 | 38 | 39 | 70 | 90 | 122 | 141 | 167 | 183 | 184 | 205 | 235 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 266 | 267 | 268 | 269 | 270 | 286 | 297 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 336 | 337 | 338 | 339 | 340 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 372 | 373 | 374 | 375 | 376 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 411 | 412 | 413 | 414 | 415 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 443 | 444 | 445 | 446 | 447 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 488 | 489 | 490 | 491 | 492 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 542 | 543 | 544 | 545 | 546 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 597 | 611 | 635 | 656 | 677 | 687 | 718 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 760 | 761 | 762 | 768 | 769 | 770 | 776 | 777 | 778 | 784 | 785 | 786 | 792 | 793 | 794 | 800 | 801 | 802 | 805 | 806 | 807 | 810 | 811 | 812 | 815 | 816 | 817 | 820 | 821 | 822 | 823 | 824 | 849 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 906 | 907 | 908 | 914 | 915 | 916 | 917 | 918 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 967 | 968 | 969 | 970 | 971 | 984 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1011 | 1012 | 1013 | 1014 | 1015 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | -------------------------------------------------------------------------------- /mtalg/alg/__init__.py: -------------------------------------------------------------------------------- 1 | from .elementwise_algebra import add, sub, div, mul, pow, std 2 | -------------------------------------------------------------------------------- /mtalg/alg/elementwise_algebra.py: -------------------------------------------------------------------------------- 1 | import concurrent.futures 2 | import numpy as np 3 | import mtalg.core.threads 4 | from typing import Optional, Union 5 | from numbers import Number 6 | 7 | argmax = lambda iterable: max(enumerate(iterable), key=lambda x: x[1])[0] 8 | 9 | 10 | def _add_inplace(x, y): x += y 11 | 12 | 13 | def _sub_inplace(x, y): x -= y 14 | 15 | 16 | def _mul_inplace(x, y): x *= y 17 | 18 | 19 | def _div_inplace(x, y): x /= y 20 | 21 | 22 | def _pow_inplace(x, y): x **= y 23 | 24 | 25 | def add(a: Union[np.ndarray, Number], b: Union[np.ndarray, Number], num_threads: Optional[int] = None, direction: str = 'left'): 26 | """Add multithreaded. 27 | 28 | Modifies a or b in-place depending on the direction. 29 | 30 | Args: 31 | a: Numpy array or scalar. 32 | b: Numpy array or scalar. 33 | num_threads: Number of threads to be used, overrides threads as set by :func:`~mtalg.set_num_threads`. 34 | direction: 'left' or 'right' to decide if a or b is modified. 35 | 36 | Examples: 37 | Add b to a; a is modified in-place. 38 | 39 | >>> a = mtalg.random.standard_normal(size=(10_000, 5_000)) 40 | >>> b = mtalg.random.uniform(size=(10_000, 5_000), low=0, high=10) 41 | >>> mtalg.add(a, b, direction='left') 42 | 43 | Add a to b; b is modified in-place. 44 | 45 | >>> mtalg.add(a, b, direction='right') 46 | 47 | Add a to b using 4 threads. 48 | 49 | >>> mtalg.add(a, b, num_threads=4, direction='right') 50 | """ 51 | __multithreaded_opr_direction(a, b, _add_inplace, num_threads, direction=direction) 52 | 53 | 54 | def sub(a: Union[np.ndarray, Number], b: Union[np.ndarray, Number], num_threads: Optional[int] = None, direction: str = 'left'): 55 | """Subtract multithreaded. 56 | 57 | Modifies a or b in-place depending on the direction. 58 | 59 | Args: 60 | a: Numpy array or scalar. 61 | b: Numpy array or scalar. 62 | num_threads: Number of threads to be used, overrides threads as set by :func:`~mtalg.set_num_threads`. 63 | direction: 'left' or 'right' to decide if a or b is modified. 64 | 65 | Examples: 66 | Subtract b from a; a is modified in-place. 67 | 68 | >>> a = mtalg.random.standard_normal(size=(10_000, 5_000)) 69 | >>> b = mtalg.random.uniform(size=(10_000, 5_000), low=0, high=10) 70 | >>> mtalg.sub(a, b, direction='left') 71 | 72 | Subtract a from b; b is modified in-place. 73 | 74 | >>> mtalg.sub(a, b, direction='right') 75 | 76 | Subtract a from b using 4 threads. 77 | 78 | >>> mtalg.sub(a, b, num_threads=4, direction='right') 79 | """ 80 | __multithreaded_opr_direction(a, b, _sub_inplace, num_threads, direction=direction) 81 | 82 | 83 | def mul(a: Union[np.ndarray, Number], b: Union[np.ndarray, Number], num_threads: Optional[int] = None, direction: str = 'left'): 84 | """Multiply multithreaded. 85 | 86 | Modifies a or b in-place depending on the direction. 87 | 88 | Args: 89 | a: Numpy array or scalar. 90 | b: Numpy array or scalar. 91 | num_threads: Number of threads to be used, overrides threads as set by :func:`~mtalg.set_num_threads`. 92 | direction: 'left' or 'right' to decide if a or b is modified. 93 | 94 | Examples: 95 | Multiply a by b; a is modified in-place. 96 | 97 | >>> a = mtalg.random.standard_normal(size=(10_000, 5_000)) 98 | >>> b = mtalg.random.uniform(size=(10_000, 5_000), low=0, high=10) 99 | >>> mtalg.mul(a, b, direction='left') 100 | 101 | Multiply b by a; b is modified in-place. 102 | 103 | >>> mtalg.mul(a, b, direction='right') 104 | 105 | Multiply b by a using 4 threads. 106 | 107 | >>> mtalg.mul(a, b, num_threads=4, direction='right') 108 | """ 109 | __multithreaded_opr_direction(a, b, _mul_inplace, num_threads, direction=direction) 110 | 111 | 112 | def div(a: Union[np.ndarray, Number], b: Union[np.ndarray, Number], num_threads: Optional[int] = None, direction: str = 'left'): 113 | """Divide multithreaded. 114 | 115 | Modifies a or b in-place depending on the direction. 116 | 117 | Args: 118 | a: Numpy array or scalar. 119 | b: Numpy array or scalar. 120 | num_threads: Number of threads to be used, overrides threads as set by :func:`~mtalg.set_num_threads`. 121 | direction: 'left' or 'right' to decide if a or b is modified. 122 | 123 | Examples: 124 | Divide a by b; a is modified in-place. 125 | 126 | >>> a = mtalg.random.standard_normal(size=(10_000, 5_000)) 127 | >>> b = mtalg.random.uniform(size=(10_000, 5_000), low=0, high=10) 128 | >>> mtalg.div(a, b, direction='left') 129 | 130 | Divide b by a; b is modified in-place. 131 | 132 | >>> mtalg.div(a, b, direction='right') 133 | 134 | Divide b by a using 4 threads. 135 | 136 | >>> mtalg.div(a, b, num_threads=4, direction='right') 137 | """ 138 | __multithreaded_opr_direction(a, b, _div_inplace, num_threads, direction=direction) 139 | 140 | 141 | def pow(a: Union[np.ndarray, Number], b: Union[np.ndarray, Number], num_threads: Optional[int] = None, direction: str = 'left'): 142 | """Raise to power multithreaded. 143 | 144 | Modifies a or b in-place depending on the direction. 145 | 146 | Args: 147 | a: Numpy array or scalar. 148 | b: Numpy array or scalar. 149 | num_threads: Number of threads to be used, overrides threads as set by :func:`~mtalg.set_num_threads`. 150 | direction: 'left' or 'right' to decide if a or b is modified. 151 | 152 | Examples: 153 | Raise a to the bth power; a is modified in-place. 154 | 155 | >>> a = mtalg.random.standard_normal(size=(10_000, 5_000)) 156 | >>> b = mtalg.random.uniform(size=(10_000, 5_000), low=0, high=10) 157 | >>> mtalg.pow(a, b, direction='left') 158 | 159 | Raise b to the ath power; b is modified in-place. 160 | 161 | >>> mtalg.pow(a, b, direction='right') 162 | 163 | Raise b to the ath power b using 4 threads. 164 | 165 | >>> mtalg.pow(a, b, num_threads=4, direction='right') 166 | """ 167 | __multithreaded_opr_direction(a, b, _pow_inplace, num_threads, direction=direction) 168 | 169 | 170 | def __multithreaded_opr_direction(a, b, opr, num_threads, direction='left'): 171 | if direction == 'left': 172 | __multithreaded_opr(a, b, opr, num_threads=num_threads) 173 | elif direction == 'right': 174 | __multithreaded_opr(b, a, opr, num_threads=num_threads) 175 | else: 176 | raise ValueError(f"Invalid direction {direction}. Must take value either 'left' or 'right'. ") 177 | 178 | 179 | def __multithreaded_opr(a, b, opr, num_threads: int = None): 180 | """Modifies a in-place. 181 | 182 | Beats numpy from around 1e7 operations onwards. 183 | 184 | Args: 185 | a (numpy.array): Left array to be summed. Modified in place. 186 | b (numpy.array): Right array to be summed. 187 | num_threads (int or None): Number of threads. 188 | """ 189 | a_scalar = isinstance(a, (int, float, complex, np.integer, np.floating)) 190 | b_scalar = isinstance(b, (int, float, complex, np.integer, np.floating)) 191 | 192 | if not a_scalar and not b_scalar: 193 | scalar = False 194 | assert a.shape == b.shape, 'Shapes of both arrays must be the same' 195 | else: 196 | scalar = True 197 | if a_scalar: 198 | raise ValueError('Cannot modify scalar in-place') 199 | 200 | shape = a.shape 201 | shp_max = argmax(shape) 202 | num_threads = num_threads or mtalg.core.threads._global_num_threads 203 | assert num_threads > 0 and isinstance(num_threads, int), \ 204 | f'Number of threads must be an integer > 0, found: {num_threads}' 205 | steps = [(t * (shape[shp_max] // num_threads), (t + 1) * (shape[shp_max] // num_threads)) 206 | if t < (num_threads - 1) else 207 | (t * (shape[shp_max] // num_threads), shape[shp_max]) 208 | for t in range(num_threads)] 209 | 210 | if scalar: 211 | def _fill(first, last): 212 | opr(a[(slice(None),) * shp_max + (slice(first, last),)], b) 213 | else: 214 | def _fill(first, last): 215 | opr(a[(slice(None),) * shp_max + (slice(first, last),)], 216 | b[(slice(None),) * shp_max + (slice(first, last),)]) 217 | 218 | with concurrent.futures.ThreadPoolExecutor(num_threads) as executor: 219 | futures = [executor.submit(_fill, steps[i][0], steps[i][1]) for i in range(num_threads)] 220 | for fut in concurrent.futures.as_completed(futures): 221 | fut.result() 222 | 223 | 224 | def std(a: np.ndarray) -> Number: 225 | """Numba version of np.std. 226 | 227 | Args: 228 | a: np.ndarray. 229 | 230 | Returns: 231 | standard deviation. 232 | """ 233 | try: 234 | from numba import njit 235 | except ModuleNotFoundError: 236 | raise ModuleNotFoundError("Optional dependency missing: 'numba'.\n" 237 | "Install via pip as `pip install numba` or via conda as `conda install numba`.") 238 | 239 | @njit(parallel=True) 240 | def std_numba(x): 241 | return np.std(x) 242 | 243 | return std_numba(a) 244 | -------------------------------------------------------------------------------- /mtalg/core/__init__.py: -------------------------------------------------------------------------------- 1 | from mtalg.core.threads import * 2 | -------------------------------------------------------------------------------- /mtalg/core/threads.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import cpu_count 2 | _global_num_threads = cpu_count() 3 | -------------------------------------------------------------------------------- /mtalg/dev-requirements.txt: -------------------------------------------------------------------------------- 1 | numpy>=1.17.0 2 | numba 3 | numexpr 4 | mkl_random 5 | tqdm 6 | pytest 7 | pytest-cov 8 | -------------------------------------------------------------------------------- /mtalg/random/__init__.py: -------------------------------------------------------------------------------- 1 | from mtalg.random.random_number_generators import MultithreadedRNG 2 | from inspect import signature 3 | _RNG = MultithreadedRNG() 4 | 5 | 6 | def beta(*args, **kwargs): 7 | return _RNG.beta(*args, **kwargs) 8 | 9 | 10 | def binomial(*args, **kwargs): 11 | return _RNG.binomial(*args, **kwargs) 12 | 13 | 14 | def chisquare(*args, **kwargs): 15 | return _RNG.chisquare(*args, **kwargs) 16 | 17 | 18 | def exponential(*args, **kwargs): 19 | return _RNG.exponential(*args, **kwargs) 20 | 21 | 22 | def f(*args, **kwargs): 23 | return _RNG.f(*args, **kwargs) 24 | 25 | 26 | def gamma(*args, **kwargs): 27 | return _RNG.gamma(*args, **kwargs) 28 | 29 | 30 | def geometric(*args, **kwargs): 31 | return _RNG.geometric(*args, **kwargs) 32 | 33 | 34 | def gumbel(*args, **kwargs): 35 | return _RNG.gumbel(*args, **kwargs) 36 | 37 | 38 | def hypergeometric(*args, **kwargs): 39 | return _RNG.hypergeometric(*args, **kwargs) 40 | 41 | 42 | def integers(*args, **kwargs): 43 | return _RNG.integers(*args, **kwargs) 44 | 45 | 46 | def laplace(*args, **kwargs): 47 | return _RNG.laplace(*args, **kwargs) 48 | 49 | 50 | def logistic(*args, **kwargs): 51 | return _RNG.logistic(*args, **kwargs) 52 | 53 | 54 | def lognormal(*args, **kwargs): 55 | return _RNG.lognormal(*args, **kwargs) 56 | 57 | 58 | def logseries(*args, **kwargs): 59 | return _RNG.logseries(*args, **kwargs) 60 | 61 | 62 | def negative_binomial(*args, **kwargs): 63 | return _RNG.negative_binomial(*args, **kwargs) 64 | 65 | 66 | def noncentral_chisquare(*args, **kwargs): 67 | return _RNG.noncentral_chisquare(*args, **kwargs) 68 | 69 | 70 | def noncentral_f(*args, **kwargs): 71 | return _RNG.noncentral_f(*args, **kwargs) 72 | 73 | 74 | def normal(*args, **kwargs): 75 | return _RNG.normal(*args, **kwargs) 76 | 77 | 78 | def pareto(*args, **kwargs): 79 | return _RNG.pareto(*args, **kwargs) 80 | 81 | 82 | def poisson(*args, **kwargs): 83 | return _RNG.poisson(*args, **kwargs) 84 | 85 | 86 | def power(*args, **kwargs): 87 | return _RNG.power(*args, **kwargs) 88 | 89 | 90 | def random(*args, **kwargs): 91 | return _RNG.random(*args, **kwargs) 92 | 93 | 94 | def rayleigh(*args, **kwargs): 95 | return _RNG.rayleigh(*args, **kwargs) 96 | 97 | 98 | def standard_cauchy(*args, **kwargs): 99 | return _RNG.standard_cauchy(*args, **kwargs) 100 | 101 | 102 | def standard_exponential(*args, **kwargs): 103 | return _RNG.standard_exponential(*args, **kwargs) 104 | 105 | 106 | def standard_gamma(*args, **kwargs): 107 | return _RNG.standard_gamma(*args, **kwargs) 108 | 109 | 110 | def standard_normal(*args, **kwargs): 111 | return _RNG.standard_normal(*args, **kwargs) 112 | 113 | 114 | def standard_t(*args, **kwargs): 115 | return _RNG.standard_t(*args, **kwargs) 116 | 117 | 118 | def triangular(*args, **kwargs): 119 | return _RNG.triangular(*args, **kwargs) 120 | 121 | 122 | def uniform(*args, **kwargs): 123 | return _RNG.uniform(*args, **kwargs) 124 | 125 | 126 | def vonmises(*args, **kwargs): 127 | return _RNG.vonmises(*args, **kwargs) 128 | 129 | 130 | def wald(*args, **kwargs): 131 | return _RNG.wald(*args, **kwargs) 132 | 133 | 134 | def weibull(*args, **kwargs): 135 | return _RNG.weibull(*args, **kwargs) 136 | 137 | 138 | def zipf(*args, **kwargs): 139 | return _RNG.zipf(*args, **kwargs) 140 | 141 | 142 | for func in [beta, binomial, chisquare, exponential, f, gamma, geometric, gumbel, hypergeometric, integers, laplace, 143 | logistic, lognormal, logseries, negative_binomial, noncentral_chisquare, noncentral_f, normal, pareto, 144 | poisson, power, random, rayleigh, standard_cauchy, standard_exponential, standard_gamma, standard_normal, 145 | standard_t, triangular, uniform, vonmises, wald, weibull, zipf]: 146 | func.__doc__ = getattr(_RNG, func.__name__).__doc__ 147 | func.__signature__ = signature(getattr(_RNG, func.__name__)) 148 | -------------------------------------------------------------------------------- /mtalg/random/random_number_generators.py: -------------------------------------------------------------------------------- 1 | """ 2 | The docstrings in this file are based on docstrings of NumPy, which has the following licence: 3 | ---------------------------------------------------------------------------------------------- 4 | 5 | Copyright (c) 2005-2021, NumPy Developers. 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are 10 | met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | 15 | * Redistributions in binary form must reproduce the above 16 | copyright notice, this list of conditions and the following 17 | disclaimer in the documentation and/or other materials provided 18 | with the distribution. 19 | 20 | * Neither the name of the NumPy Developers nor the names of any 21 | contributors may be used to endorse or promote products derived 22 | from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | """ 36 | 37 | from numpy.random import SeedSequence, PCG64, Generator, BitGenerator 38 | import concurrent.futures 39 | import numpy as np 40 | import mtalg.core.threads 41 | from typing import Optional, Union 42 | from numbers import Number 43 | 44 | argmax = lambda iterable: max(enumerate(iterable), key=lambda x: x[1])[0] 45 | 46 | 47 | class MultithreadedRNG: 48 | """Multithreaded random number generator. 49 | 50 | Args: 51 | seed (int): Random seed. 52 | num_threads (int): Number of threads to be used, overrides threads as set by :func:`~mtalg.set_num_threads`. 53 | bit_generator (np.random.BitGenerator): Bit generator, defaults to PCG64. 54 | 55 | Examples: 56 | 57 | Instantiate a multithreaded random number generator which uses 4 threads, setting a seed to derive the 58 | initial BitGenerator state. 59 | 60 | >>> from mtalg.random import MultithreadedRNG 61 | >>> mrng = MultithreadedRNG(seed=1, num_threads=4) 62 | 63 | Create a 10000 x 5000 matrix with numbers, drawing from the standard normal distribution. 64 | 65 | >>> a = mrng.standard_normal(size=(10_000, 5_000)) 66 | 67 | Create a 10000 x 5000 matrix with numbers, drawing from the uniform distribution. 68 | 69 | >>> b = mrng.uniform(size=(10_000, 5_000), low=0, high=10) 70 | 71 | Note: 72 | For more information on distributions, see 73 | `Random generator distributions `_. 74 | """ 75 | 76 | def __init__(self, seed: Optional[int] = None, num_threads: Optional[int] = None, bit_generator: BitGenerator = PCG64): 77 | self._num_threads = num_threads or mtalg.core.threads._global_num_threads 78 | assert self._num_threads > 0 and isinstance(self._num_threads, int), \ 79 | f'Number of threads must be an integer > 0, found: {self._num_threads}' 80 | seq = SeedSequence(seed) 81 | self._random_generators = [Generator(bit_generator=bit_generator(s)) for s in seq.spawn(self._num_threads)] 82 | self._shape = None 83 | self._shp_max = None 84 | self._values = None 85 | self._steps = [] 86 | 87 | def beta(self, a: Number, b: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 88 | """Draw from a beta distribution. 89 | 90 | Args: 91 | a: Alpha, positive (>0). 92 | b: Beta, positive (>0). 93 | size: Output shape. 94 | 95 | Returns 96 | numpy.ndarray or scalar. 97 | """ 98 | self._check_shape(size) 99 | kw_args = {'a': a, 100 | 'b': b} 101 | 102 | if size is None: 103 | return self._random_generators[0].beta(**kw_args) 104 | 105 | def __fill(random_state, out, first, last, **kwargs): 106 | out[(slice(None),) * self._shp_max + 107 | (slice(first, last),)] = random_state.beta(size=self._get_slice_size(first, last), **kwargs) 108 | 109 | return self._fill(__fill, **kw_args) 110 | 111 | def binomial(self, n: Number, p: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 112 | """Draw from a binomial distribution. 113 | 114 | Args: 115 | n: Parameter of the distribution, >= 0. Floats are also accepted, but they will be truncated to integers. 116 | p: Parameter of the distribution, >= 0 and <=1. 117 | size: Output shape. 118 | 119 | Returns: 120 | numpy.ndarray or scalar. 121 | """ 122 | self._check_shape(size) 123 | kw_args = {'n': n, 124 | 'p': p} 125 | 126 | if size is None: 127 | return self._random_generators[0].binomial(**kw_args) 128 | 129 | def __fill(random_state, out, first, last, **kwargs): 130 | out[(slice(None),) * self._shp_max + 131 | (slice(first, last),)] = random_state.binomial(size=self._get_slice_size(first, last), **kwargs) 132 | 133 | return self._fill(__fill, **kw_args) 134 | 135 | def chisquare(self, df: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 136 | """Draw from a chisquare distribution. 137 | 138 | Args: 139 | df: Number of degrees of freedom, must be > 0. 140 | size: Output shape. 141 | 142 | Returns: 143 | numpy.ndarray or scalar. 144 | """ 145 | self._check_shape(size) 146 | kw_args = {'df': df} 147 | 148 | if size is None: 149 | return self._random_generators[0].chisquare(**kw_args) 150 | 151 | def __fill(random_state, out, first, last, **kwargs): 152 | out[(slice(None),) * self._shp_max + 153 | (slice(first, last),)] = random_state.chisquare(size=self._get_slice_size(first, last), **kwargs) 154 | 155 | return self._fill(__fill, **kw_args) 156 | 157 | def exponential(self, scale: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 158 | """Draw from an exponential distribution. 159 | 160 | Args: 161 | scale: The scale parameter, β = 1/λ Must be non-negative. 162 | size: Output shape. 163 | 164 | Returns: 165 | numpy.ndarray or scalar. 166 | """ 167 | self._check_shape(size) 168 | kw_args = {'scale': scale} 169 | 170 | if size is None: 171 | return self._random_generators[0].exponential(**kw_args) 172 | 173 | def __fill(random_state, out, first, last, **kwargs): 174 | out[(slice(None),) * self._shp_max + 175 | (slice(first, last),)] = random_state.exponential(size=self._get_slice_size(first, last), **kwargs) 176 | 177 | return self._fill(__fill, **kw_args) 178 | 179 | def f(self, dfnum: Number, dfden: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 180 | """Draw from an F distribution. 181 | 182 | Args: 183 | dfnum: Degrees of freedom in numerator, must be > 0. 184 | dfden: Degrees of freedom in denominator, must be > 0. 185 | size: Output shape. 186 | 187 | Returns: 188 | ndarray or scalar. 189 | """ 190 | self._check_shape(size) 191 | kw_args = {'dfnum': dfnum, 192 | 'dfden': dfden} 193 | 194 | if size is None: 195 | return self._random_generators[0].f(**kw_args) 196 | 197 | def __fill(random_state, out, first, last, **kwargs): 198 | out[(slice(None),) * self._shp_max + 199 | (slice(first, last),)] = random_state.f(size=self._get_slice_size(first, last), **kwargs) 200 | 201 | return self._fill(__fill, **kw_args) 202 | 203 | def gamma(self, shape: Number, scale: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 204 | """Draw from a gamma distribution. 205 | 206 | Args: 207 | shape: The shape of the gamma distribution. Must be non-negative. 208 | scale: The scale of the gamma distribution. Must be non-negative. Default is equal to 1. 209 | size: Output shape. 210 | 211 | Returns: 212 | numpy.ndarray or scalar. 213 | """ 214 | self._check_shape(size) 215 | kw_args = {'shape': shape, 216 | 'scale': scale} 217 | 218 | if size is None: 219 | return self._random_generators[0].gamma(**kw_args) 220 | 221 | def __fill(random_state, out, first, last, **kwargs): 222 | out[(slice(None),) * self._shp_max + 223 | (slice(first, last),)] = random_state.gamma(size=self._get_slice_size(first, last), **kwargs) 224 | 225 | return self._fill(__fill, **kw_args) 226 | 227 | def geometric(self, p: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 228 | """Draw from a geometric distribution. 229 | 230 | Args: 231 | p: The probability of success of an individual trial. 232 | size: Output shape. 233 | 234 | Returns: 235 | numpy.ndarray or scalar. 236 | """ 237 | self._check_shape(size) 238 | kw_args = {'p': p} 239 | 240 | if size is None: 241 | return self._random_generators[0].geometric(**kw_args) 242 | 243 | def __fill(random_state, out, first, last, **kwargs): 244 | out[(slice(None),) * self._shp_max + 245 | (slice(first, last),)] = random_state.geometric(size=self._get_slice_size(first, last), **kwargs) 246 | 247 | return self._fill(__fill, **kw_args) 248 | 249 | def gumbel(self, loc: Number = 0.0, scale: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 250 | """Draw from a Gumbel distribution. 251 | 252 | Args: 253 | loc: The location of the mode of the distribution. Default is 0. 254 | scale: The scale parameter of the distribution. Default is 1. Must be non-negative. 255 | size: Output shape. 256 | 257 | Returns: 258 | numpy.ndarray or scalar. 259 | """ 260 | self._check_shape(size) 261 | kw_args = {'loc': loc, 262 | 'scale': scale} 263 | 264 | if size is None: 265 | return self._random_generators[0].gumbel(**kw_args) 266 | 267 | def __fill(random_state, out, first, last, **kwargs): 268 | out[(slice(None),) * self._shp_max + 269 | (slice(first, last),)] = random_state.gumbel(size=self._get_slice_size(first, last), **kwargs) 270 | 271 | return self._fill(__fill, **kw_args) 272 | 273 | def hypergeometric(self, ngood: int, nbad: int, nsample: int, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 274 | """Draw from a hypergeometric distribution. 275 | 276 | Args: 277 | ngood: Number of ways to make a good selection. Must be nonnegative and less than 10**9. 278 | nbad: Number of ways to make a bad selection. Must be nonnegative and less than 10**9. 279 | nsample: Number of items sampled. Must be nonnegative and less than ngood + nbad. 280 | size: Output shape. 281 | 282 | Returns: 283 | numpy.ndarray or scalar. 284 | """ 285 | self._check_shape(size) 286 | kw_args = {'ngood': ngood, 287 | 'nbad': nbad, 288 | 'nsample': nsample} 289 | 290 | if size is None: 291 | return self._random_generators[0].hypergeometric(**kw_args) 292 | 293 | def __fill(random_state, out, first, last, **kwargs): 294 | out[(slice(None),) * self._shp_max + 295 | (slice(first, last),)] = random_state.hypergeometric(size=self._get_slice_size(first, last), **kwargs) 296 | 297 | return self._fill(__fill, **kw_args) 298 | 299 | def integers(self, low: int, high: int = None, size: Union[int, tuple, None] = None, dtype=np.int64, endpoint: bool = False) -> Union[np.ndarray, Number]: 300 | """Draw random integers from low (inclusive) to high (exclusive), or if endpoint=True, low (inclusive) to high 301 | (inclusive). 302 | 303 | Args: 304 | low: Lowest (signed) integers to be drawn from the distribution (unless high=None, in which case this 305 | parameter is 0 and this value is used for high). 306 | high: If provided, one above the largest (signed) integer to be drawn from the distribution (see above for 307 | behavior if high=None). 308 | size: Output shape. 309 | dtype: Dtype of output array. 310 | endpoint: If true, sample from the interval [low, high] instead of the default [low, high); 311 | defaults to False. 312 | 313 | Returns: 314 | numpy.ndarray or scalar. 315 | """ 316 | self._check_shape(size) 317 | kw_args = {'low': low, 318 | 'high': high, 319 | 'dtype': dtype, 320 | 'endpoint': endpoint} 321 | 322 | if size is None: 323 | return self._random_generators[0].integers(**kw_args) 324 | 325 | if self._values.dtype != dtype: 326 | self._values = self._values.astype(dtype) 327 | 328 | def __fill(random_state, out, first, last, **kwargs): 329 | out[(slice(None),) * self._shp_max + 330 | (slice(first, last),)] = random_state.integers(size=self._get_slice_size(first, last), **kwargs) 331 | 332 | return self._fill(__fill, **kw_args) 333 | 334 | def laplace(self, loc: Number = 0.0, scale: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 335 | """Draw from a Laplace distribution. 336 | 337 | Args: 338 | loc: The position, μ, of the distribution peak. Default is 0. 339 | scale: λ, the exponential decay. Default is 1. Must be non- negative. 340 | size: Output shape. 341 | 342 | Returns: 343 | numpy.ndarray or scalar. 344 | """ 345 | self._check_shape(size) 346 | kw_args = {'loc': loc, 347 | 'scale': scale} 348 | 349 | if size is None: 350 | return self._random_generators[0].laplace(**kw_args) 351 | 352 | def __fill(random_state, out, first, last, **kwargs): 353 | out[(slice(None),) * self._shp_max + 354 | (slice(first, last),)] = random_state.laplace(size=self._get_slice_size(first, last), 355 | **kwargs) 356 | 357 | return self._fill(__fill, **kw_args) 358 | 359 | def logistic(self, loc: Number = 0.0, scale: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 360 | """Draw from a logistic distribution. 361 | 362 | Args: 363 | loc: Parameter of the distribution. Default is 0. 364 | scale: Parameter of the distribution. Must be non-negative. Default is 1. 365 | size: Output shape. 366 | 367 | Returns: 368 | numpy.ndarray or scalar. 369 | """ 370 | self._check_shape(size) 371 | kw_args = {'loc': loc, 372 | 'scale': scale} 373 | 374 | if size is None: 375 | return self._random_generators[0].logistic(**kw_args) 376 | 377 | def __fill(random_state, out, first, last, **kwargs): 378 | out[(slice(None),) * self._shp_max + 379 | (slice(first, last),)] = random_state.logistic(size=self._get_slice_size(first, last), 380 | **kwargs) 381 | 382 | return self._fill(__fill, **kw_args) 383 | 384 | def lognormal(self, mean: Number = 0.0, sigma: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 385 | """Draw from a lognormal distribution. 386 | 387 | Args: 388 | mean: Mean value of the underlying normal distribution. Default is 0. 389 | sigma: Standard deviation of the underlying normal distribution. Must be non-negative. Default is 1. 390 | size: Output shape. 391 | 392 | Returns: 393 | numpy.ndarray or scalar. 394 | """ 395 | self._check_shape(size) 396 | kw_args = {'mean': mean, 397 | 'sigma': sigma} 398 | 399 | if size is None: 400 | return self._random_generators[0].lognormal(**kw_args) 401 | 402 | def __fill(random_state, out, first, last, **kwargs): 403 | out[(slice(None),) * self._shp_max + 404 | (slice(first, last),)] = random_state.lognormal(size=self._get_slice_size(first, last), 405 | **kwargs) 406 | 407 | return self._fill(__fill, **kw_args) 408 | 409 | def logseries(self, p: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 410 | """Draw from a logarithmic series distribution. 411 | 412 | Args: 413 | p: Shape parameter for the distribution. Must be in the range (0, 1). 414 | size: Output shape. 415 | """ 416 | self._check_shape(size) 417 | kw_args = {'p': p} 418 | 419 | if size is None: 420 | return self._random_generators[0].logseries(**kw_args) 421 | 422 | def __fill(random_state, out, first, last, **kwargs): 423 | out[(slice(None),) * self._shp_max + 424 | (slice(first, last),)] = random_state.logseries(size=self._get_slice_size(first, last), **kwargs) 425 | 426 | return self._fill(__fill, **kw_args) 427 | 428 | def negative_binomial(self, n: Number, p: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 429 | """Draw from a negative binomial distribution. 430 | 431 | Args: 432 | n: Parameter of the distribution, > 0. 433 | p: Parameter of the distribution. Must satisfy 0 < p <= 1. 434 | size: Output shape. 435 | 436 | Returns: 437 | numpy.ndarray or scalar. 438 | """ 439 | self._check_shape(size) 440 | kw_args = {'n': n, 441 | 'p': p} 442 | 443 | if size is None: 444 | return self._random_generators[0].negative_binomial(**kw_args) 445 | 446 | def __fill(random_state, out, first, last, **kwargs): 447 | out[(slice(None),) * self._shp_max + 448 | (slice(first, last),)] = random_state.negative_binomial(size=self._get_slice_size(first, last), 449 | **kwargs) 450 | 451 | return self._fill(__fill, **kw_args) 452 | 453 | def noncentral_chisquare(self, df: Number, nonc: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 454 | """Draw from a noncentral chisquare distribution. 455 | 456 | Args: 457 | df: Number of degrees of freedom, must be > 0. 458 | nonc: Non-centrality, must be non-negative. 459 | size: Output shape. 460 | 461 | Returns: 462 | numpy.ndarray or scalar. 463 | """ 464 | self._check_shape(size) 465 | kw_args = {'df': df, 466 | 'nonc': nonc} 467 | 468 | if size is None: 469 | return self._random_generators[0].noncentral_chisquare(**kw_args) 470 | 471 | def __fill(random_state, out, first, last, **kwargs): 472 | out[(slice(None),) * self._shp_max + 473 | (slice(first, last),)] = random_state.noncentral_chisquare(size=self._get_slice_size(first, last), 474 | **kwargs) 475 | 476 | return self._fill(__fill, **kw_args) 477 | 478 | def noncentral_f(self, dfnum: Number, dfden: Number, nonc: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 479 | """Draw from a noncentral F distribution. 480 | 481 | Args: 482 | dfnum: Degrees of freedom in numerator, must be > 0. 483 | dfden: Degrees of freedom in denominator, must be > 0. 484 | nonc: Non-centrality parameter, the sum of the squares of the numerator means, must be >= 0. 485 | size: Output shape. 486 | 487 | Returns: 488 | numpy.ndarray or scalar. 489 | """ 490 | self._check_shape(size) 491 | kw_args = {'dfnum': dfnum, 492 | 'dfden': dfden, 493 | 'nonc': nonc} 494 | 495 | if size is None: 496 | return self._random_generators[0].noncentral_f(**kw_args) 497 | 498 | def __fill(random_state, out, first, last, **kwargs): 499 | out[(slice(None),) * self._shp_max + 500 | (slice(first, last),)] = random_state.noncentral_f(size=self._get_slice_size(first, last), **kwargs) 501 | 502 | return self._fill(__fill, **kw_args) 503 | 504 | def normal(self, loc: Number = 0.0, scale: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 505 | """Draw from the normal distribution. 506 | 507 | Args: 508 | loc: Mean of the distribution. 509 | scale: Standard deviation of the distribution. 510 | size: Output shape. 511 | 512 | Returns: 513 | numpy.ndarray or scalar. 514 | """ 515 | self._check_shape(size) 516 | kw_args = {'loc': loc, 517 | 'scale': scale} 518 | 519 | if size is None: 520 | return self._random_generators[0].normal(**kw_args) 521 | 522 | def __fill(random_state, out, first, last, **kwargs): 523 | out[(slice(None),) * self._shp_max + 524 | (slice(first, last),)] = random_state.normal(size=self._get_slice_size(first, last), **kwargs) 525 | 526 | return self._fill(__fill, **kw_args) 527 | 528 | def pareto(self, a: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 529 | """Draw from a Pareto II or Lomax distribution. 530 | 531 | Args: 532 | a: Shape of the distribution. Must be positive. 533 | size: Output shape. 534 | 535 | Returns: 536 | numpy.ndarray or scalar. 537 | """ 538 | self._check_shape(size) 539 | kw_args = {'a': a} 540 | 541 | if size is None: 542 | return self._random_generators[0].pareto(**kw_args) 543 | 544 | def __fill(random_state, out, first, last, **kwargs): 545 | out[(slice(None),) * self._shp_max + 546 | (slice(first, last),)] = random_state.pareto(size=self._get_slice_size(first, last), **kwargs) 547 | 548 | return self._fill(__fill, **kw_args) 549 | 550 | def poisson(self, lam: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 551 | """Draw from a poisson distribution. 552 | 553 | Args: 554 | lam: Expected number of events occurring in a fixed-time interval, must be >= 0. 555 | size: Output shape. 556 | 557 | Returns: 558 | numpy.ndarray or scalar. 559 | """ 560 | self._check_shape(size) 561 | kw_args = {'lam': lam} 562 | 563 | if size is None: 564 | return self._random_generators[0].poisson(**kw_args) 565 | 566 | def __fill(random_state, out, first, last, **kwargs): 567 | out[(slice(None),) * self._shp_max + 568 | (slice(first, last),)] = random_state.poisson(size=self._get_slice_size(first, last), **kwargs) 569 | 570 | return self._fill(__fill, **kw_args) 571 | 572 | def power(self, a: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 573 | """Draw from a power distribution. 574 | 575 | Args: 576 | a: Parameter of the distribution. Must be non-negative. 577 | size: Output shape. 578 | 579 | Returns: 580 | numpy.ndarray or scalar. 581 | """ 582 | self._check_shape(size) 583 | kw_args = {'a': a} 584 | 585 | if size is None: 586 | return self._random_generators[0].power(**kw_args) 587 | 588 | def __fill(random_state, out, first, last, **kwargs): 589 | out[(slice(None),) * self._shp_max + 590 | (slice(first, last),)] = random_state.power(size=self._get_slice_size(first, last), **kwargs) 591 | 592 | return self._fill(__fill, **kw_args) 593 | 594 | def random(self, size: Union[int, tuple, None] = None, dtype=np.float64) -> Union[np.ndarray, Number]: 595 | """Return random floats in the half-open interval [0.0, 1.0). 596 | 597 | Args: 598 | size: Output shape. 599 | dtype: Dtype of output array. 600 | 601 | Returns: 602 | numpy.ndarray or scalar. 603 | """ 604 | self._check_shape(size) 605 | kw_args = {'dtype': dtype} 606 | 607 | if size is None: 608 | return self._random_generators[0].random(**kw_args) 609 | 610 | if self._values.dtype != dtype: 611 | self._values = self._values.astype(dtype) 612 | 613 | def __fill(random_state, out, first, last, **kwargs): 614 | if self._shp_max == 0: 615 | random_state.random(out=out[(slice(None),) * self._shp_max + (slice(first, last),)], **kwargs) 616 | else: 617 | out[(slice(None),) * self._shp_max + 618 | (slice(first, last),)] = random_state.random(size=self._get_slice_size(first, last), **kwargs) 619 | 620 | return self._fill(__fill, **kw_args) 621 | 622 | def rayleigh(self, scale: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 623 | """Draw from a Rayleigh distribution. 624 | 625 | Args: 626 | scale: Scale, also equals the mode. Must be non-negative. Default is 1. 627 | size: Output shape. 628 | 629 | Returns: 630 | numpy.ndarray or scalar. 631 | """ 632 | self._check_shape(size) 633 | kw_args = {'scale': scale} 634 | 635 | if size is None: 636 | return self._random_generators[0].rayleigh(**kw_args) 637 | 638 | def __fill(random_state, out, first, last, **kwargs): 639 | out[(slice(None),) * self._shp_max + 640 | (slice(first, last),)] = random_state.rayleigh(size=self._get_slice_size(first, last), **kwargs) 641 | 642 | return self._fill(__fill, **kw_args) 643 | 644 | def standard_cauchy(self, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 645 | """Draw from a standard Cauchy distribution. 646 | 647 | Args: 648 | size (int or tuple): Output shape. 649 | 650 | Returns: 651 | numpy.ndarray or scalar. 652 | """ 653 | self._check_shape(size) 654 | kw_args = {} 655 | 656 | if size is None: 657 | return self._random_generators[0].standard_cauchy(**kw_args) 658 | 659 | def __fill(random_state, out, first, last, **kwargs): 660 | out[(slice(None),) * self._shp_max + 661 | (slice(first, last),)] = random_state.standard_cauchy(size=self._get_slice_size(first, last), 662 | **kwargs) 663 | 664 | return self._fill(__fill, **kw_args) 665 | 666 | def standard_exponential(self, size: Union[int, tuple, None] = None, dtype=np.float64, method: str = 'zig') -> Union[np.ndarray, Number]: 667 | """Draw from a standard exponential distribution. 668 | 669 | Args: 670 | size: Output shape. 671 | dtype: Dtype of output array. 672 | method: Either ‘inv’ or ‘zig’. ‘inv’ uses the inverse CDF method. ‘zig’ uses the much faster Ziggurat 673 | method of Marsaglia and Tsang. 674 | 675 | Returns: 676 | numpy.ndarray or scalar. 677 | """ 678 | self._check_shape(size) 679 | kw_args = {'dtype': dtype, 680 | 'method': method} 681 | 682 | if size is None: 683 | return self._random_generators[0].standard_exponential(**kw_args) 684 | 685 | if self._values.dtype != dtype: 686 | self._values = self._values.astype(dtype) 687 | 688 | def __fill(random_state, out, first, last, **kwargs): 689 | if self._shp_max == 0: 690 | random_state.standard_exponential(out=out[(slice(None),) * self._shp_max + (slice(first, last),)], 691 | **kwargs) 692 | else: 693 | out[(slice(None),) * self._shp_max + 694 | (slice(first, last),)] = random_state.standard_exponential(size=self._get_slice_size(first, last), 695 | **kwargs) 696 | 697 | return self._fill(__fill, **kw_args) 698 | 699 | def standard_gamma(self, shape: Number, size: Union[int, tuple, None] = None, dtype=np.float64) -> Union[np.ndarray, Number]: 700 | """Draw from a standard gamma distribution. 701 | 702 | Args: 703 | shape: Parameter, must be non-negative. 704 | size: Output shape. 705 | dtype: Dtype of output array. 706 | 707 | Returns: 708 | numpy.ndarray or scalar. 709 | """ 710 | self._check_shape(size) 711 | kw_args = {'shape': shape, 712 | 'dtype': dtype} 713 | 714 | if size is None: 715 | return self._random_generators[0].standard_gamma(**kw_args) 716 | 717 | if self._values.dtype != dtype: 718 | self._values = self._values.astype(dtype) 719 | 720 | def __fill(random_state, out, first, last, **kwargs): 721 | if self._shp_max == 0: 722 | random_state.standard_gamma(out=out[(slice(None),) * self._shp_max + (slice(first, last),)], 723 | **kwargs) 724 | else: 725 | out[(slice(None),) * self._shp_max + 726 | (slice(first, last),)] = random_state.standard_gamma(size=self._get_slice_size(first, last), 727 | **kwargs) 728 | 729 | return self._fill(__fill, **kw_args) 730 | 731 | def standard_normal(self, size: Union[int, tuple, None] = None, dtype=np.float64) -> Union[np.ndarray, Number]: 732 | """Draw from a standard normal distribution. 733 | 734 | Args: 735 | size: Output shape. 736 | dtype: Dtype of output array. 737 | 738 | Returns: 739 | numpy.ndarray or scalar. 740 | """ 741 | self._check_shape(size) 742 | kw_args = {'dtype': dtype} 743 | 744 | if size is None: 745 | return self._random_generators[0].standard_normal(**kw_args) 746 | 747 | if self._values.dtype != dtype: 748 | self._values = self._values.astype(dtype) 749 | 750 | def __fill(random_state, out, first, last, **kwargs): 751 | if self._shp_max == 0: 752 | random_state.standard_normal(out=out[(slice(None),) * self._shp_max + (slice(first, last),)], 753 | **kwargs) 754 | else: 755 | out[(slice(None),) * self._shp_max + 756 | (slice(first, last),)] = random_state.standard_normal(size=self._get_slice_size(first, last), 757 | **kwargs) 758 | 759 | return self._fill(__fill, **kw_args) 760 | 761 | def standard_t(self, df: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 762 | """Draw from a standard Student’s t distribution. 763 | 764 | Args: 765 | df: Degrees of freedom, must be > 0. 766 | size: Output shape. 767 | 768 | Returns: 769 | numpy.ndarray or scalar. 770 | """ 771 | self._check_shape(size) 772 | kw_args = {'df': df} 773 | 774 | if size is None: 775 | return self._random_generators[0].standard_t(**kw_args) 776 | 777 | def __fill(random_state, out, first, last, **kwargs): 778 | out[(slice(None),) * self._shp_max + 779 | (slice(first, last),)] = random_state.standard_t(size=self._get_slice_size(first, last), 780 | **kwargs) 781 | 782 | return self._fill(__fill, **kw_args) 783 | 784 | def triangular(self, left: Number, mode: Number, right: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 785 | """Draw from a triangular distribution. 786 | 787 | Args: 788 | left: Lower limit. 789 | mode: The value where the peak of the distribution occurs. The value must fulfill the condition 790 | left <= mode <= right. 791 | right: Upper limit, must be larger than left. 792 | size: Output shape. 793 | 794 | Returns: 795 | numpy.ndarray or scalar. 796 | """ 797 | self._check_shape(size) 798 | kw_args = {'left': left, 799 | 'mode': mode, 800 | 'right': right} 801 | 802 | if size is None: 803 | return self._random_generators[0].triangular(**kw_args) 804 | 805 | def __fill(random_state, out, first, last, **kwargs): 806 | out[(slice(None),) * self._shp_max + 807 | (slice(first, last),)] = random_state.triangular(size=self._get_slice_size(first, last), **kwargs) 808 | 809 | return self._fill(__fill, **kw_args) 810 | 811 | def uniform(self, low: Number = 0.0, high: Number = 1.0, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 812 | """Draw from a uniform distribution. 813 | 814 | Args: 815 | low: Lower bound. 816 | high: Upper bound. 817 | size: Output shape. 818 | 819 | Returns: 820 | numpy.ndarray or scalar. 821 | """ 822 | self._check_shape(size) 823 | kw_args = {'low': low, 824 | 'high': high} 825 | 826 | if size is None: 827 | return self._random_generators[0].uniform(**kw_args) 828 | 829 | def __fill(random_state, out, first, last, **kwargs): 830 | out[(slice(None),) * self._shp_max + 831 | (slice(first, last),)] = random_state.uniform(size=self._get_slice_size(first, last), **kwargs) 832 | 833 | return self._fill(__fill, **kw_args) 834 | 835 | def vonmises(self, mu: Number, kappa: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 836 | """Draw from a von Mises distribution. 837 | 838 | Args: 839 | mu: Mode (“center”) of the distribution. 840 | kappa: Dispersion of the distribution, has to be >=0. 841 | size: Output shape. 842 | 843 | Returns: 844 | numpy.ndarray or scalar. 845 | """ 846 | self._check_shape(size) 847 | kw_args = {'mu': mu, 848 | 'kappa': kappa} 849 | 850 | if size is None: 851 | return self._random_generators[0].vonmises(**kw_args) 852 | 853 | def __fill(random_state, out, first, last, **kwargs): 854 | out[(slice(None),) * self._shp_max + 855 | (slice(first, last),)] = random_state.vonmises(size=self._get_slice_size(first, last), **kwargs) 856 | 857 | return self._fill(__fill, **kw_args) 858 | 859 | def wald(self, mean: Number, scale: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 860 | """Draw from a Wald distribution. 861 | 862 | Args: 863 | mean: Distribution mean, must be > 0. 864 | scale: Scale parameter, must be > 0. 865 | size: Output shape. 866 | 867 | Returns: 868 | numpy.ndarray or scalar. 869 | """ 870 | self._check_shape(size) 871 | kw_args = {'mean': mean, 872 | 'scale': scale} 873 | 874 | if size is None: 875 | return self._random_generators[0].wald(**kw_args) 876 | 877 | def __fill(random_state, out, first, last, **kwargs): 878 | out[(slice(None),) * self._shp_max + 879 | (slice(first, last),)] = random_state.wald(size=self._get_slice_size(first, last), **kwargs) 880 | 881 | return self._fill(__fill, **kw_args) 882 | 883 | def weibull(self, a: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 884 | """Draw from a Weibull distribution. 885 | 886 | Args: 887 | a: Shape parameter of the distribution. Must be nonnegative. 888 | size: Output shape. 889 | 890 | Returns: 891 | numpy.ndarray or scalar. 892 | """ 893 | self._check_shape(size) 894 | kw_args = {'a': a} 895 | 896 | if size is None: 897 | return self._random_generators[0].weibull(**kw_args) 898 | 899 | def __fill(random_state, out, first, last, **kwargs): 900 | out[(slice(None),) * self._shp_max + 901 | (slice(first, last),)] = random_state.weibull(size=self._get_slice_size(first, last), **kwargs) 902 | 903 | return self._fill(__fill, **kw_args) 904 | 905 | def zipf(self, a: Number, size: Union[int, tuple, None] = None) -> Union[np.ndarray, Number]: 906 | """Draw from a Zipf distribution. 907 | 908 | Args: 909 | a: Distribution parameter. Must be greater than 1. 910 | size: Output shape. 911 | 912 | Returns: 913 | numpy.ndarray or scalar. 914 | """ 915 | self._check_shape(size) 916 | kw_args = {'a': a} 917 | 918 | if size is None: 919 | return self._random_generators[0].zipf(**kw_args) 920 | 921 | def __fill(random_state, out, first, last, **kwargs): 922 | out[(slice(None),) * self._shp_max + 923 | (slice(first, last),)] = random_state.zipf(size=self._get_slice_size(first, last), **kwargs) 924 | 925 | return self._fill(__fill, **kw_args) 926 | 927 | def _fill(self, func, **kwargs): 928 | """Send jobs to the threads.""" 929 | with concurrent.futures.ThreadPoolExecutor(self._num_threads) as executor: 930 | futures = [executor.submit(func, 931 | self._random_generators[i], 932 | self._values, 933 | self._steps[i][0], 934 | self._steps[i][1], 935 | **kwargs) 936 | for i in range(self._num_threads)] 937 | for fut in concurrent.futures.as_completed(futures): 938 | fut.result() 939 | 940 | values = self._values 941 | self._values = None 942 | return values 943 | 944 | def _check_shape(self, size): 945 | """Standard size checks to be done before execution of any distribution sampling.""" 946 | if size != self._shape: 947 | if isinstance(size, (int, float, complex, np.integer, np.floating)): 948 | size = size, 949 | self._shape = size 950 | self._shp_max = argmax(self._shape) if size is not None else None 951 | self._steps = [(t * (self._shape[self._shp_max] // self._num_threads), 952 | (t + 1) * (self._shape[self._shp_max] // self._num_threads)) 953 | if t < (self._num_threads - 1) else 954 | (t * (self._shape[self._shp_max] // self._num_threads), self._shape[self._shp_max]) 955 | for t in range(self._num_threads)] if size is not None else [] 956 | self._values = np.empty(self._shape) if size is not None else None 957 | 958 | def _get_slice_size(self, fst, lst): 959 | """Get the shape of the slice to be filled.""" 960 | return tuple(x if i != self._shp_max else lst - fst for i, x in enumerate(self._shape)) 961 | -------------------------------------------------------------------------------- /mtalg/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy>=1.17.0 -------------------------------------------------------------------------------- /mtalg/testing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWakker/mtalg/b4345bfb14aa8aef90e19d126525b0ea1e81b9a7/mtalg/testing/__init__.py -------------------------------------------------------------------------------- /mtalg/testing/benchmarks_em_algebra.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numexpr as ne 3 | import numpy as np 4 | import pandas as pd 5 | import seaborn as sns 6 | import timeit 7 | from numba import njit, prange 8 | from tqdm import tqdm 9 | from mtalg import add 10 | 11 | sns.set() 12 | 13 | rng = np.random.default_rng() 14 | 15 | 16 | def _add(x, y): return x + y 17 | 18 | 19 | def _sub(x, y): return x - y 20 | 21 | 22 | def _mul(x, y): return x * y 23 | 24 | 25 | def _div(x, y): return x / y 26 | 27 | 28 | def _pow(x, y): return x ** y 29 | 30 | 31 | def ne_add(a, b): return ne.evaluate('a + b') 32 | 33 | 34 | def ne_sub(a, b): return ne.evaluate('a - b') 35 | 36 | 37 | def ne_mul(a, b): return ne.evaluate('a * b') 38 | 39 | 40 | def ne_div(a, b): return ne.evaluate('a / b') 41 | 42 | 43 | def ne_pow(a, b): return ne.evaluate('a ** b') 44 | 45 | 46 | @njit(parallel=True) 47 | def numba_add(a, b): 48 | for i in prange(len(a)): 49 | a[i] += b[i] 50 | 51 | 52 | @njit(parallel=True) 53 | def numba_sub(a, b): 54 | for i in prange(len(a)): 55 | a[i] -= b[i] 56 | 57 | 58 | @njit(parallel=True) 59 | def numba_mul(a, b): 60 | for i in prange(len(a)): 61 | a[i] *= b[i] 62 | 63 | 64 | @njit(parallel=True) 65 | def numba_div(a, b): 66 | for i in prange(len(a)): 67 | a[i] /= b[i] 68 | 69 | 70 | @njit(parallel=True) 71 | def numba_pow(a, b): 72 | for i in prange(len(a)): 73 | a[i] **= b[i] 74 | 75 | 76 | if __name__ == '__main__': 77 | 78 | ######## 79 | # Charts 80 | 81 | def get_a_b(shape): 82 | a = rng.standard_normal(shape) 83 | a = a.clip(min=1e-5) 84 | b = a * 3.14 85 | return a, b 86 | 87 | 88 | result = {'x': [], 'mtalg': [], 'numexpr': [], 89 | 'numba': [], 'numpy': []} 90 | 91 | for x in tqdm(np.geomspace(1e3, 1e9, num=200)[::-1].astype(int)): 92 | a, b = get_a_b(shape=x) 93 | n = 50 94 | result['x'].append(x) 95 | result['mtalg'].append(timeit.timeit(lambda: add(a, b, num_threads=24), number=n) / n) 96 | result['numexpr'].append(timeit.timeit(lambda: ne_add(a, b), number=n) / n) 97 | result['numba'].append(timeit.timeit(lambda: numba_add(a, b), number=n) / n) 98 | result['numpy'].append(timeit.timeit(lambda: _add(a, b), number=n) / n) 99 | 100 | df = pd.DataFrame(result).set_index('x').sort_index() 101 | df_plot = df.rolling(10).mean() 102 | 103 | 104 | def plot_line(save=False, path=None): 105 | fig, ax = plt.subplots() 106 | for key, color, lw in zip(['mtalg', 'numba', 'numexpr', 'numpy'], 107 | ['b', 'r', 'g', 'Y'], 108 | [3, 1.2, 1.2, 1.2]): 109 | ax.plot(df_plot.index, 110 | df_plot[key], 111 | label=key, 112 | color=color, 113 | linewidth=lw) 114 | ax.legend() 115 | ax.set_xlabel('Number of operations (size of the array)') 116 | ax.set_ylabel('Execution time [sec]') 117 | plt.loglog() 118 | plt.xlim(1e5, df_plot.index.max()) 119 | 120 | if save: 121 | plt.tight_layout() 122 | fig.savefig(f"{path or 'mtalg/__res/benchmark'}/benchmark_add.png", dpi=400) 123 | fig.savefig(f"{path or 'mtalg/__res/benchmark'}/benchmark_add.svg") 124 | 125 | 126 | plot_line(save=False) 127 | 128 | 129 | def plot_bar(save=False, path=None): 130 | width = .5 131 | bars = ['mtalg', 'numba', 'numexpr', 'numpy'] 132 | 133 | fig, ax = plt.subplots() 134 | ax.bar([0, 1, 2, 3], 135 | [df_plot[bar].values[-1] for bar in bars], 136 | color=['b', 'r', 'g', 'y'], 137 | width=width) 138 | ax.set_xticks([0, 1, 2, 3]) 139 | ax.set_xticklabels(bars) 140 | ax.set_ylabel('Execution time [sec]') 141 | ax.set_title('1bn operations') 142 | 143 | if save: 144 | plt.tight_layout() 145 | fig.savefig(f"{path or 'mtalg/__res/benchmark'}/benchmark_add_BARS.png", dpi=400) 146 | fig.savefig(f"{path or 'mtalg/__res/benchmark'}/benchmark_add_BARS.svg") 147 | 148 | 149 | plot_bar(save=False) 150 | -------------------------------------------------------------------------------- /mtalg/testing/benchmarks_rng.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from numpy.random import default_rng 3 | from timeit import timeit 4 | from mtalg.random import MultithreadedRNG 5 | import seaborn as sns 6 | import matplotlib.pyplot as plt 7 | from tqdm import tqdm 8 | import pandas as pd 9 | import mkl_random 10 | from collections import defaultdict 11 | sns.set() 12 | 13 | mrng = MultithreadedRNG(seed=1, num_threads=24) 14 | rng = default_rng(seed=1) 15 | result = defaultdict(list) 16 | 17 | if __name__ == '__main__': 18 | 19 | for x in tqdm(np.geomspace(1e3, 1e9, num=200)[::-1]): 20 | n = 20 21 | result['x'].append(x) 22 | result['MT_std_norm'].append(timeit(lambda: mrng.standard_normal(size=int(x)), number=n) / n) 23 | result['np_std_norm'].append(timeit(lambda: rng.standard_normal(size=int(x)), number=n) / n) 24 | result['mkl_std_norm'].append(timeit(lambda: mkl_random.standard_normal(size=int(x)), number=n) / n) 25 | result['MT_uniform'].append(timeit(lambda: mrng.uniform(size=int(x)), number=n) / n) 26 | result['np_uniform'].append(timeit(lambda: rng.uniform(size=int(x)), number=n) / n) 27 | result['mkl_uniform'].append(timeit(lambda: mkl_random.uniform(size=int(x)), number=n) / n) 28 | 29 | df = pd.DataFrame(result).set_index('x').sort_index() 30 | df.to_parquet('result.parq') 31 | df_plot = df.rolling(10).mean() 32 | 33 | def plot_line(save=False, path=None): 34 | fig, ax = plt.subplots() 35 | for key, label, color, lstyle, lw in zip( 36 | ['MT_std_norm', 'mkl_std_norm', 'np_std_norm', 'MT_uniform', 'mkl_uniform', 'np_uniform'], 37 | ['mtalg - standard normal', 'mkl_random - standard_normal', 'numpy - standard normal', 38 | 'mtalg - uniform', 'mkl_random - uniform', 'numpy - uniform'], 39 | ['b', 'r', 'Y', 'b', 'r', 'Y'], 40 | ['-', '-', '-', '--', '--', '--'], 41 | [3, 1.2, 1.2, 3, 1.2, 1.2]): 42 | ax.plot(df_plot.index, df_plot[key], label=label, color=color, linestyle=lstyle, linewidth=lw) 43 | ax.legend(loc='upper left', frameon=False) 44 | ax.set_xlabel('Number of operations (size of the array)') 45 | ax.set_ylabel('Execution time [sec]') 46 | plt.loglog() 47 | plt.xlim(1e5, df_plot.index.max()) 48 | plt.ylim(1e-4, 1e2) 49 | 50 | if save: 51 | plt.tight_layout() 52 | fig.savefig(f"{path or 'mtalg/__res/benchmark'}/benchmark_rng.png", dpi=400) 53 | fig.savefig(f"{path or 'mtalg/__res/benchmark'}/benchmark_rng.svg") 54 | 55 | plot_line(save=False) 56 | 57 | 58 | def plot_bar(save=False, path=None): 59 | x = np.array([0, 1]) 60 | width = .25 61 | 62 | fig, ax = plt.subplots() 63 | ax.bar(x - width, [df_plot[x].values[-1] for x in ['MT_std_norm', 'MT_uniform']], color='b', width=width, 64 | label='mtalg') 65 | ax.bar(x, [df_plot[x].values[-1] for x in ['mkl_std_norm', 'mkl_uniform']], color='r', width=width, 66 | label='mkl_random') 67 | ax.bar(x + width, [df_plot[x].values[-1] for x in ['np_std_norm', 'np_uniform']], color='Y', width=width, 68 | label='numpy') 69 | ax.set_xticks(x) 70 | ax.set_xticklabels(['Standard normal', 'Uniform']) 71 | ax.set_ylabel('Execution time [sec]') 72 | ax.set_title('1bn operations') 73 | ax.legend() 74 | 75 | if save: 76 | plt.tight_layout() 77 | fig.savefig(f"{path or 'mtalg/__res/benchmark'}/benchmark_rng_BAR.png", dpi=400) 78 | fig.savefig(f"{path or 'mtalg/__res/benchmark'}/benchmark_rng_BAR.svg") 79 | 80 | plot_bar(save=True) 81 | -------------------------------------------------------------------------------- /mtalg/testing/test_core.py: -------------------------------------------------------------------------------- 1 | import mtalg 2 | import pytest 3 | 4 | import mtalg.core.threads 5 | from multiprocessing import cpu_count 6 | 7 | 8 | class TestCore: 9 | def test1(self): 10 | with pytest.raises(ValueError): 11 | mtalg.set_num_threads(-1) 12 | 13 | def test2(self): 14 | with pytest.raises(ValueError): 15 | mtalg.set_num_threads(1.5) 16 | 17 | def test3(self, n_threads=4): 18 | assert mtalg.core.threads._global_num_threads == cpu_count() 19 | mtalg.set_num_threads(n_threads) 20 | assert mtalg.core.threads._global_num_threads == n_threads 21 | assert mtalg.get_num_threads() == n_threads 22 | -------------------------------------------------------------------------------- /mtalg/testing/test_em_algebra.py: -------------------------------------------------------------------------------- 1 | import pytest, os, numpy as np 2 | from numpy.random import default_rng 3 | from itertools import chain, combinations 4 | 5 | 6 | def _add(x, y): return x + y 7 | def _sub(x, y): return x - y 8 | def _mul(x, y): return x * y 9 | def _div(x, y): return x / y 10 | def _pow(x, y): return x ** y 11 | 12 | 13 | def all_unique_combinations(ll): 14 | return set(chain.from_iterable(combinations(ll, i + 1) for i in range(len(ll)))) 15 | 16 | 17 | SHAPE = (int(4e4), 10, 5) 18 | 19 | 20 | def get_a_b(size, no_negative=False): 21 | import mtalg 22 | 23 | rng = default_rng(1) 24 | aa = rng.standard_normal(size) 25 | bb = rng.standard_normal(size) 26 | bb = bb.clip(min=1e-5) 27 | if no_negative: 28 | aa = aa.clip(min=1e-5) 29 | return aa, bb 30 | 31 | 32 | class TestEmAlgebra: 33 | 34 | def test_missing_numba(self): 35 | os.system("pip uninstall --yes numba") 36 | import mtalg 37 | 38 | a = np.arange(100) 39 | with pytest.raises(ModuleNotFoundError): 40 | mtalg.std(a) 41 | os.system("pip install numba") 42 | 43 | def test_numba_wrapped_functions(self): 44 | import mtalg 45 | os.environ['NUMBA_DISABLE_JIT'] = '1' 46 | a = np.arange(100) 47 | mtalg.std(a) 48 | 49 | def test_all(self): 50 | import mtalg 51 | failed = {} 52 | for op, opMT in zip((_add, _sub, _mul, _div, _pow), 53 | (mtalg.add, mtalg.sub, mtalg.mul, mtalg.div, mtalg.pow)): 54 | for shape in all_unique_combinations(SHAPE): 55 | for scalar in [False, True]: 56 | a, b = get_a_b(shape, no_negative=True) if opMT.__name__ == 'pow' else get_a_b(shape) 57 | if scalar: 58 | b = 2 59 | c = op(a, b) 60 | opMT(a, b, direction='left') 61 | if not (c[c == c] == a[a == a]).all(): 62 | failed[(opMT.__name__, shape, scalar)] = 'failed' 63 | raise Warning(f'Failed with operation {opMT}; shape arrays: {shape}.') 64 | 65 | assert not failed 66 | 67 | def test1(self): 68 | import mtalg 69 | a = np.arange(100) 70 | b = np.arange(100) 71 | mtalg.add(a, b, direction='right') 72 | 73 | def test2(self): 74 | import mtalg 75 | a = np.arange(100) 76 | b = np.arange(100) 77 | with pytest.raises(ValueError): 78 | mtalg.add(a, b, direction='middle') 79 | 80 | def test3(self): 81 | import mtalg 82 | a = np.arange(100) 83 | assert np.isclose(np.std(a), mtalg.std(a)) 84 | 85 | 86 | def test4(self): 87 | import mtalg 88 | a_arr = np.arange(10000).reshape((100, 100)) 89 | a_scal = 2 90 | b_arr = np.arange(10000).reshape((100, 100)) 91 | b_scal = 2 92 | mtalg.add(a_arr, b_arr, direction='left', num_threads=2) 93 | mtalg.add(a_arr, b_arr, direction='right', num_threads=2) 94 | mtalg.add(a_arr, b_scal, direction='left', num_threads=2) 95 | with pytest.raises(ValueError): 96 | mtalg.add(a_arr, b_scal, direction='right', num_threads=2) 97 | with pytest.raises(ValueError): 98 | mtalg.add(a_scal, b_scal, direction='left') 99 | with pytest.raises(ValueError): 100 | mtalg.add(a_scal, b_scal, direction='right') 101 | -------------------------------------------------------------------------------- /mtalg/testing/test_random.py: -------------------------------------------------------------------------------- 1 | import mtalg 2 | import numpy as np 3 | import pytest 4 | 5 | 6 | class TestRandom: 7 | def test1(self): 8 | a = mtalg.random.standard_normal() 9 | assert isinstance(a, float) 10 | 11 | def test2(self): 12 | with pytest.raises(TypeError): 13 | mtalg.random.standard_normal(1, np.float32, 3) 14 | 15 | def test3(self): 16 | with pytest.raises(TypeError): 17 | mtalg.random.standard_normal(size=1, dtype=np.float32, wrong=4) 18 | 19 | def test4(self): 20 | for size in [None, 500, (10, 50), (10, 10, 50), (10, 50, 10)]: 21 | mtalg.random.beta(size=size, a=0.01, b=0.01) 22 | mtalg.random.binomial(size=size, n=10, p=0.5) 23 | mtalg.random.chisquare(size=size, df=100) 24 | mtalg.random.exponential(size=size) 25 | mtalg.random.f(size=size, dfnum=1, dfden=1) 26 | mtalg.random.gamma(size=size, shape=1) 27 | mtalg.random.geometric(size=size, p=.5) 28 | mtalg.random.gumbel(size=size, loc=1, scale=1) 29 | mtalg.random.hypergeometric(size=size, ngood=10, nbad=10, nsample=20) 30 | mtalg.random.integers(size=size, low=0, high=10, endpoint=True) 31 | mtalg.random.integers(size=size, low=0, high=10, endpoint=True, dtype=np.int32) 32 | mtalg.random.laplace(size=size, loc=1, scale=1) 33 | mtalg.random.logistic(size=size, loc=1, scale=1) 34 | mtalg.random.lognormal(size=size) 35 | mtalg.random.logseries(size=size, p=.5) 36 | mtalg.random.negative_binomial(size=size, n=10, p=0.5) 37 | mtalg.random.noncentral_chisquare(size=size, df=10, nonc=1) 38 | mtalg.random.noncentral_f(size=size, dfnum=1, dfden=1, nonc=1) 39 | mtalg.random.normal(size=size, loc=1, scale=2) 40 | mtalg.random.pareto(size=size, a=1) 41 | mtalg.random.poisson(size=size) 42 | mtalg.random.power(size=size, a=2) 43 | mtalg.random.random(size=size) 44 | mtalg.random.random(size=size, dtype=np.float32) 45 | mtalg.random.rayleigh(size=size, scale=1) 46 | mtalg.random.standard_cauchy(size=size) 47 | mtalg.random.standard_exponential(size=size) 48 | mtalg.random.standard_exponential(size=size, dtype=np.float32) 49 | mtalg.random.standard_gamma(size=size, shape=1) 50 | mtalg.random.standard_gamma(size=size, shape=1, dtype=np.float32) 51 | mtalg.random.standard_normal(size=size) 52 | mtalg.random.standard_normal(size=size, dtype=np.float32) 53 | mtalg.random.standard_t(size=size, df=10) 54 | mtalg.random.triangular(size=size, left=0, mode=5, right=10) 55 | mtalg.random.uniform(size=size, low=0, high=10) 56 | mtalg.random.vonmises(size=size, mu=0, kappa=1) 57 | mtalg.random.wald(size=size, mean=1, scale=1) 58 | mtalg.random.weibull(size=size, a=2) 59 | mtalg.random.zipf(size=size, a=2) 60 | 61 | def test5(self): 62 | mtalg.set_num_threads(1) 63 | assert mtalg.random._RNG._num_threads == 1 64 | mtalg.set_num_threads(2) 65 | assert mtalg.random._RNG._num_threads == 2 66 | -------------------------------------------------------------------------------- /mtalg/testing/test_rng.py: -------------------------------------------------------------------------------- 1 | import mtalg 2 | from mtalg.random import MultithreadedRNG 3 | import numpy as np 4 | 5 | 6 | class TestMRNG: 7 | def test1(self): 8 | mrng = MultithreadedRNG(seed=1) 9 | assert mrng._shape is None 10 | 11 | def test2(self): 12 | mrng = MultithreadedRNG(seed=1, num_threads=4) 13 | a = mrng.standard_normal(size=4) 14 | assert a.shape == (4,) 15 | 16 | def test3(self): 17 | mrng = MultithreadedRNG(seed=1, num_threads=4) 18 | a = mrng.standard_normal(4) 19 | b = mrng.standard_normal(4) 20 | assert (a != b).all() 21 | 22 | def test4(self): 23 | mrng = MultithreadedRNG(seed=1, num_threads=4) 24 | a = mrng.standard_normal((2, 2)) 25 | assert a.shape == (2, 2) 26 | 27 | def test5(self): 28 | mrng = MultithreadedRNG(seed=1, num_threads=4) 29 | a = mrng.standard_normal(4) 30 | mrng = MultithreadedRNG(seed=2, num_threads=4) 31 | b = mrng.standard_normal(4) 32 | assert (a != b).all() 33 | 34 | def test6(self): 35 | mrng = MultithreadedRNG(seed=1, num_threads=4) 36 | a = mrng.standard_normal(4) 37 | mrng = MultithreadedRNG(seed=1, num_threads=4) 38 | b = mrng.standard_normal(4) 39 | assert (b == a).all() 40 | 41 | def test7(self): 42 | mrng = MultithreadedRNG(seed=1, num_threads=4) 43 | a = mrng.uniform(size=(10, 10), low=-1000, high=1000) 44 | assert not ((a > 0) & (a < 1)).all() 45 | 46 | def test8(self): 47 | mrng = MultithreadedRNG(seed=1, num_threads=4) 48 | a = mrng.uniform(size=(10, 10), low=0, high=1) 49 | assert ((a > 0) & (a < 1)).all() 50 | 51 | def test9(self): 52 | mrng = MultithreadedRNG(seed=1, num_threads=4) 53 | a = mrng.normal(size=(20, 10, 30, 100, 50), loc=1, scale=2) 54 | assert a.shape == (20, 10, 30, 100, 50) 55 | assert mrng._steps == [(0, 25), (25, 50), (50, 75), (75, 100)] 56 | assert np.isclose(np.std(a), 2, 1e-2) 57 | assert np.isclose(np.mean(a), 1, 1e-2) 58 | 59 | def test10(self): 60 | for gen in [np.random.PCG64, np.random.MT19937, np.random.Philox, np.random.SFC64]: 61 | mrng = MultithreadedRNG(seed=1, num_threads=4, bit_generator=gen) 62 | for size in [500, (10, 50), (10, 10, 50), (10, 50, 10)]: 63 | mrng.beta(size=size, a=0.01, b=0.01) 64 | mrng.binomial(size=size, n=10, p=0.5) 65 | mrng.chisquare(size=size, df=100) 66 | mrng.exponential(size=size) 67 | mrng.f(size=size, dfnum=1, dfden=1) 68 | mrng.gamma(size=size, shape=1) 69 | mrng.geometric(size=size, p=.5) 70 | mrng.gumbel(size=size, loc=1, scale=1) 71 | mrng.hypergeometric(size=size, ngood=10, nbad=10, nsample=20) 72 | mtalg.random.integers(size=size, low=0, high=10, endpoint=True) 73 | mtalg.random.integers(size=size, low=0, high=10, endpoint=True, dtype=np.int32) 74 | mrng.laplace(size=size, loc=1, scale=1) 75 | mrng.logistic(size=size, loc=1, scale=1) 76 | mrng.lognormal(size=size) 77 | mrng.logseries(size=size, p=.5) 78 | mrng.negative_binomial(size=size, n=10, p=0.5) 79 | mrng.noncentral_chisquare(size=size, df=10, nonc=1) 80 | mrng.noncentral_f(size=size, dfnum=1, dfden=1, nonc=1) 81 | mrng.normal(size=size, loc=1, scale=2) 82 | mrng.pareto(size=size, a=1) 83 | mrng.poisson(size=size) 84 | mrng.power(size=size, a=2) 85 | mrng.random(size=size) 86 | mrng.random(size=size, dtype=np.float32) 87 | mrng.rayleigh(size=size, scale=1) 88 | mrng.standard_cauchy(size=size) 89 | mrng.standard_exponential(size=size) 90 | mrng.standard_exponential(size=size, dtype=np.float32) 91 | mrng.standard_gamma(size=size, shape=1) 92 | mrng.standard_gamma(size=size, shape=1, dtype=np.float32) 93 | mrng.standard_normal(size=size) 94 | mrng.standard_normal(size=size, dtype=np.float32) 95 | mrng.standard_t(size=size, df=10) 96 | mrng.triangular(size=size, left=0, mode=5, right=10) 97 | mrng.uniform(size=size, low=0, high=10) 98 | mrng.vonmises(size=size, mu=0, kappa=1) 99 | mrng.wald(size=size, mean=1, scale=1) 100 | mrng.weibull(size=size, a=2) 101 | mrng.zipf(size=size, a=2) 102 | 103 | def test11(self): 104 | mrng = MultithreadedRNG(seed=1, num_threads=4) 105 | mrng.standard_normal(size=(20, 20, 1000)) 106 | 107 | def test12(self): 108 | for gen in [np.random.PCG64, np.random.MT19937, np.random.Philox, np.random.SFC64]: 109 | mrng = MultithreadedRNG(seed=1, num_threads=4, bit_generator=gen) 110 | size = None 111 | a = mrng.beta(size=size, a=0.01, b=0.01) 112 | assert isinstance(a, float) 113 | mrng.binomial(size=size, n=10, p=0.5) 114 | mrng.chisquare(size=size, df=100) 115 | mrng.exponential(size=size) 116 | mrng.f(size=size, dfnum=1, dfden=1) 117 | mrng.gamma(size=size, shape=1) 118 | mrng.geometric(size=size, p=.5) 119 | mrng.gumbel(size=size, loc=1, scale=1) 120 | mrng.hypergeometric(size=size, ngood=10, nbad=10, nsample=20) 121 | mtalg.random.integers(size=size, low=0, high=10, endpoint=True) 122 | mtalg.random.integers(size=size, low=0, high=10, endpoint=True, dtype=np.int32) 123 | mrng.laplace(size=size, loc=1, scale=1) 124 | mrng.logistic(size=size, loc=1, scale=1) 125 | mrng.lognormal(size=size) 126 | mrng.logseries(size=size, p=.5) 127 | mrng.negative_binomial(size=size, n=10, p=0.5) 128 | mrng.noncentral_chisquare(size=size, df=10, nonc=1) 129 | mrng.noncentral_f(size=size, dfnum=1, dfden=1, nonc=1) 130 | mrng.normal(size=size, loc=1, scale=2) 131 | mrng.pareto(size=size, a=1) 132 | mrng.poisson(size=size) 133 | mrng.power(size=size, a=2) 134 | mrng.random(size=size) 135 | mrng.random(size=size, dtype=np.float32) 136 | mrng.rayleigh(size=size, scale=1) 137 | mrng.standard_cauchy(size=size) 138 | mrng.standard_exponential(size=size) 139 | mrng.standard_exponential(size=size, dtype=np.float32) 140 | mrng.standard_gamma(size=size, shape=1) 141 | mrng.standard_normal(size=size) 142 | mrng.standard_normal(size=size, dtype=np.float32) 143 | mrng.standard_t(size=size, df=10) 144 | mrng.triangular(size=size, left=0, mode=5, right=10) 145 | mrng.uniform(size=size, low=0, high=10) 146 | mrng.vonmises(size=size, mu=0, kappa=1) 147 | mrng.wald(size=size, mean=1, scale=1) 148 | mrng.weibull(size=size, a=2) 149 | mrng.zipf(size=size, a=2) 150 | 151 | def test13(self): 152 | mrng = MultithreadedRNG(num_threads=4) 153 | mtalg.set_num_threads(2) 154 | mrng2 = MultithreadedRNG() 155 | mrng3 = MultithreadedRNG(num_threads=3) 156 | assert mrng._num_threads == 4 and mrng2._num_threads == 2 and mrng3._num_threads == 3 157 | -------------------------------------------------------------------------------- /mtalg/tools/__get_threads.py: -------------------------------------------------------------------------------- 1 | import mtalg 2 | 3 | 4 | def get_num_threads() -> int: 5 | """Get number of threads for multithreaded RNGs and algebra functions. 6 | 7 | Returns: 8 | Number of threads. 9 | 10 | Examples: 11 | Check the available number of threads. 12 | 13 | >>> from multiprocessing import cpu_count 14 | >>> cpu_count() 15 | 12 16 | 17 | Check the number of threads used by mtalg. 18 | 19 | >>> mtalg.get_num_threads() 20 | 12 21 | 22 | Change the number of threads used by mtalg. 23 | 24 | >>> mtalg.set_num_threads(6) 25 | >>> mtalg.get_num_threads() 26 | 6 27 | """ 28 | return mtalg.core.threads._global_num_threads 29 | -------------------------------------------------------------------------------- /mtalg/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWakker/mtalg/b4345bfb14aa8aef90e19d126525b0ea1e81b9a7/mtalg/tools/__init__.py -------------------------------------------------------------------------------- /mtalg/tools/__set_threads.py: -------------------------------------------------------------------------------- 1 | import mtalg 2 | 3 | 4 | def set_num_threads(num_threads: int): 5 | """Set number of threads for subsequent multithreaded RNGs and algebra functions. 6 | 7 | Args: 8 | num_threads: Number of threads 9 | 10 | Examples: 11 | Check the available number of threads. 12 | 13 | >>> from multiprocessing import cpu_count 14 | >>> cpu_count() 15 | 12 16 | 17 | Check the number of threads used by mtalg. 18 | 19 | >>> mtalg.get_num_threads() 20 | 12 21 | 22 | Change the number of threads used by mtalg. 23 | 24 | >>> mtalg.set_num_threads(6) 25 | >>> mtalg.get_num_threads() 26 | 6 27 | """ 28 | if not isinstance(num_threads, int): 29 | raise ValueError(f'Number of threads must be an integer, found: {num_threads}') 30 | if not num_threads > 0: 31 | raise ValueError(f'Number of threads must be > 0, found: {num_threads}') 32 | 33 | mtalg.core.threads._global_num_threads = num_threads 34 | mtalg.random._RNG = mtalg.random.MultithreadedRNG(num_threads=num_threads) 35 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as f: 4 | long_description = f.read() 5 | 6 | about = {} 7 | with open("mtalg/__about__.py") as f: 8 | exec(f.read(), about) 9 | 10 | with open("mtalg/requirements.txt") as f: 11 | requirements = f.read().splitlines() 12 | 13 | setuptools.setup( 14 | name="mtalg", 15 | version=about['__version__'], 16 | author=about['__authors__'], 17 | author_email=about['__email__'], 18 | description=about['__about__'], 19 | url=about['__url__'], 20 | license='MIT', 21 | long_description=long_description, 22 | long_description_content_type="text/markdown", 23 | packages=setuptools.find_packages(), 24 | install_requires=requirements, 25 | extras_require={'full': ['numba']}, 26 | classifiers=[ 27 | "Programming Language :: Python :: 3", 28 | "License :: OSI Approved :: MIT License", 29 | "Operating System :: OS Independent", 30 | ], 31 | python_requires='>=3.6', 32 | project_urls={ 33 | 'Documentation': 'https://mtalg.readthedocs.io/', 34 | 'GitHub': 'https://github.com/WWakker/mtalg/', 35 | }, 36 | ) 37 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | # Required metadata 2 | sonar.projectKey=WWakker_mtalg 3 | sonar.organization=mtalg 4 | sonar.projectName=mtalg 5 | sonar.projectDescription=A package for multithreaded elementwise algebra and random number generation 6 | sonar.qualitygate.wait=true 7 | 8 | # Comma-separated paths to directories with sources 9 | sonar.sources=mtalg 10 | sonar.tests=mtalg 11 | sonar.test.inclusions=**/testing/** 12 | sonar.exclusions=**/testing/**, **/__res/** 13 | 14 | # Language 15 | sonar.language=py 16 | sonar.python.version=3 17 | 18 | # Links 19 | sonar.links.homepage=https://github.com/WWakker/mtalg 20 | sonar.links.issue=https://github.com/WWakker/mtalg/issues 21 | sonar.host.url=https://sonarcloud.io 22 | 23 | # Unit tests 24 | sonar.python.xunit.reportPath=unit.xml 25 | sonar.python.coverage.reportPaths=cov.xml 26 | --------------------------------------------------------------------------------