From ab6aec252aa9d49bcfd6352e890bb867e52c3508 Mon Sep 17 00:00:00 2001 From: Chaoming Wang Date: Fri, 7 Jun 2024 10:08:55 +0800 Subject: [PATCH] init commit --- .github/ISSUE_TEMPLATE/bug_report.md | 16 + .github/ISSUE_TEMPLATE/feature_request.md | 10 + .github/PULL_REQUEST_TEMPLATE.md | 37 + .github/dependabot.yml | 26 + .github/workflows/CI.yml | 113 + .github/workflows/Publish.yml | 17 + .gitignore | 228 + .pre-commit-config.yaml | 27 + .readthedocs.yml | 20 + CODE_OF_CONDUCT.md | 132 + CONTRIBUTING.md | 4 + LICENSE | 202 + README.md | 48 + SECURITY.md | 23 + brainunit/__init__.py | 27 + brainunit/_base.py | 3066 ++++++++ brainunit/_misc.py | 38 + brainunit/_unit_common.py | 8182 +++++++++++++++++++++ brainunit/_unit_constants.py | 92 + brainunit/_unit_shortcuts.py | 121 + brainunit/_unit_test.py | 1655 +++++ changelog.md | 4 + docs/Makefile | 21 + docs/_templates/classtemplate.rst | 9 + docs/api.rst | 12 + docs/apis/functional.rst | 76 + docs/apis/init.rst | 43 + docs/apis/metric.rst | 121 + docs/apis/optim.rst | 50 + docs/auto_generater.py | 369 + docs/conf.py | 131 + docs/index.rst | 61 + docs/make.bat | 35 + pyproject.toml | 66 + requirements-dev.txt | 6 + requirements-doc.txt | 15 + requirements.txt | 4 + setup.py | 94 + 38 files changed, 15201 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/CI.yml create mode 100644 .github/workflows/Publish.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .readthedocs.yml create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 brainunit/__init__.py create mode 100644 brainunit/_base.py create mode 100644 brainunit/_misc.py create mode 100644 brainunit/_unit_common.py create mode 100644 brainunit/_unit_constants.py create mode 100644 brainunit/_unit_shortcuts.py create mode 100644 brainunit/_unit_test.py create mode 100644 changelog.md create mode 100644 docs/Makefile create mode 100644 docs/_templates/classtemplate.rst create mode 100644 docs/api.rst create mode 100644 docs/apis/functional.rst create mode 100644 docs/apis/init.rst create mode 100644 docs/apis/metric.rst create mode 100644 docs/apis/optim.rst create mode 100644 docs/auto_generater.py create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 pyproject.toml create mode 100644 requirements-dev.txt create mode 100644 requirements-doc.txt create mode 100644 requirements.txt create mode 100644 setup.py diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..45bfacb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,16 @@ +--- +name: 'Bug Report' +about: 'Report a bug or unexpected behavior to help us improve the package' +labels: 'bug' +--- + +Please: + +- [ ] Check for duplicate issues. +- [ ] Provide a complete example of how to reproduce the bug, wrapped in triple backticks like this: + +```python +import brainunit as bu +``` + +- [ ] If applicable, include full error messages/tracebacks. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..ceb49b1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,10 @@ +--- +name: 'Feature Request' +about: 'Suggest a new idea or improvement for ``brainunit``' +labels: 'enhancement' +--- + +Please: + +- [ ] Check for duplicate requests. +- [ ] Describe your goal, and if possible provide a code snippet with a motivating example. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ae3d2c8 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,37 @@ + + + +## Description + + + + + + +## How Has This Been Tested + + + + + +## Types of changes + + +- Bug fix (non-breaking change which fixes an issue) +- New feature (non-breaking change which adds functionality) +- Documentation (non-breaking change which updates documentation) +- Breaking change (fix or feature that would cause existing functionality to change) +- Code style (formatting, renaming) +- Refactoring (no functional changes, no api changes) +- Other (please describe here): + +## Checklist + + +- [ ] Code follows the code style of this project. +- [ ] Changes follow the **CONTRIBUTING** guidelines. +- [ ] Update necessary documentation accordingly. +- [ ] Lint and tests pass locally with the changes. +- [ ] Check issues and pull requests first. You don't want to duplicate effort. + +## Other information \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..09e0cf6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,26 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + allow: + - dependency-type: "all" + commit-message: + prefix: ":arrow_up:" + open-pull-requests-limit: 50 + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + allow: + - dependency-type: "all" + commit-message: + prefix: ":arrow_up:" + open-pull-requests-limit: 50 diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..64e140c --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,113 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Continuous Integration + +on: + push: + branches: + - '**' # matches every branch + pull_request: + branches: + - '**' # matches every branch + + +permissions: + contents: read # to fetch code + actions: write # to cancel previous workflows + +# This is what will cancel the workflow +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + + +jobs: + test_linux: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [ "3.9", "3.10", "3.11", "3.12" ] + + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.12.1 + with: + access_token: ${{ github.token }} + - uses: actions/checkout@v4 + - name: Print concurrency group + run: echo '${{ github.workflow }}-${{ github.ref }}' + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip cache purge + python -m pip install --upgrade pip setuptools --no-cache-dir + python -m pip install -r requirements-dev.txt --no-cache-dir + pip install . --no-cache-dir + - name: Test with pytest + run: | + pytest brainunit/ + + + test_macos: + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + python-version: [ "3.9", "3.10", "3.11", "3.12" ] + + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.12.1 + with: + access_token: ${{ github.token }} + - uses: actions/checkout@v4 + - name: Print concurrency group + run: echo '${{ github.workflow }}-${{ github.ref }}' + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip cache purge + python -m pip install --upgrade pip setuptools --no-cache-dir + python -m pip install -r requirements-dev.txt --no-cache-dir + pip install . + - name: Test with pytest + run: | + pytest brainunit/ + + + test_windows: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + python-version: [ "3.9", "3.10", "3.11", "3.12" ] + + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.12.1 + with: + access_token: ${{ github.token }} + - uses: actions/checkout@v4 + - name: Print concurrency group + run: echo '${{ github.workflow }}-${{ github.ref }}' + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip cache purge + python -m pip install --upgrade pip setuptools --no-cache-dir + python -m pip install -r requirements-dev.txt --no-cache-dir + pip install . --no-cache-dir + - name: Test with pytest + run: | + pytest brainunit/ -p no:faulthandler diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml new file mode 100644 index 0000000..f81070d --- /dev/null +++ b/.github/workflows/Publish.yml @@ -0,0 +1,17 @@ +name: Publish to PyPI.org +on: + release: + types: [published] +jobs: + pypi: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - run: python setup.py bdist_wheel --python-tag=py3 + - name: Publish package + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2942400 --- /dev/null +++ b/.gitignore @@ -0,0 +1,228 @@ +publishment.md +#experimental/ +.vscode +io_test_tmp* + +brainpy/math/brainpy_object/tests/io_test_tmp* + +lib/ + +development + +brainpy/dyn/tests/data +examples/dynamics_simulation/data +examples/dynamics_simulation/results +examples/training_ann_models/data +examples/dynamics_analysis/data +extensions/.idea +extensions/wheelhouse +extensions/dist +extensions/win_dll +extensions/fixed_wheels +extensions/build +extensions/cmake-build-debug +BrainPyExamples/ +BrainModels/ +book/ +docs/examples +docs/apis/jaxsetting.rst +docs/quickstart/data +examples/recurrent_neural_network/neurogym +develop/iconip_paper +develop/benchmark/COBA/results +develop/test +develop/outputdir +docs/tutorial_math/data +docs/tutorial_simulation/data + +docs/images/numpybrain_arch.pptx +docs/images/synapses_index.pdf +docs/images/synapses_index.xlsx +docs/images/neuron_structure.xlsx +docs/images/neuron_structure.pdf +docs/images/connection_methods.pptx + +*/_autosummary +*/generated + +docs/apis/auto +docs/quickstart/.ipynb_checkpoints + +docs/apis/_autosummary +docs/apis/generated +docs/apis/math/generated +docs/apis/integrators/generated + +develop/benchmark/COBA/brian2* +develop/benchmark/COBA/annarchy* +develop/benchmark/COBAHH/brian2* +develop/benchmark/COBAHH/annarchy* +develop/benchmark/CUBA/annarchy* +develop/benchmark/CUBA/brian2* + + +*~ +\#*\# +*.pyc +.DS_Store +docs/_autosummary +docs/generated +docs/_build +dist/ +build/ +*.egg-info +.idea +docs/images/logo1.tif +docs/images/logo2.tif +docs/images/logo3.tif +docs/images/logo4.tif + +*/__pycache__ +docs/c4_examples/ + + +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +/docs/apis/simulation/generated/ +!/brainpy/dyn/tests/data/ +/examples/dynamics_simulation/data/ +/examples/training_snn_models/logs/T100_b64_lr0.001/ +/examples/training_snn_models/logs/ +/examples/training_snn_models/data/ +/docs/tutorial_advanced/data/ +/my_tests/ +/examples/dynamics_simulation/Joglekar_2018_data/ +/docs/apis/deprecated/generated/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..52b5a74 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,27 @@ +# Install the pre-commit hooks below with +# 'pre-commit install' + +# Auto-update the version of the hooks with +# 'pre-commit autoupdate' + +# Run the hooks on all files with +# 'pre-commit run --all' + +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: end-of-file-fixer + # only include python files + files: \.py$ + - id: debug-statements + # only include python files + files: \.py$ + - id: trailing-whitespace + # only include python files + files: \.py$ + +- repo: https://github.com/pycqa/flake8 + rev: '6.1.0' + hooks: + - id: flake8 diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..82cdd08 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,20 @@ +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +build: + os: "ubuntu-20.04" + tools: + python: "3.10" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Optionally set the version of Python and requirements required to build your docs +python: + install: + - requirements: requirements-doc.txt \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..0890db8 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at brainpy@foxmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4c276f0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +# Contributing to BrainPy + +For information on how to contribute to BrainPy, see +[Contributing to BrainPy](https://brainpy.readthedocs.io/en/latest/tutorial_advanced/contributing.html). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6450791 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2024] [BrainPy Ecosystem] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b6c3466 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ + + +# Unit-aware System for Brain Dynamics Programming + +

+ Header image of brainunit. +

+ + + +

+ Supported Python Version + LICENSE + + Documentation Status + + PyPI version + Continuous Integration +

+ + +[``brainunit``](https://github.com/brainpy/brainunit) provides common toolboxes for brain dynamics programming (BDP). + + +## Installation + +You can install ``brainunit`` via pip: + +```bash +pip install brainunit --upgrade +``` + +## Documentation + +The official documentation is hosted on Read the Docs: [https://brainunit.readthedocs.io](https://brainunit.readthedocs.io) + + + +## See also the BDP ecosystem + +- [``brainpy``](https://github.com/brainpy/BrainPy): The solution for the general-purpose brain dynamics programming. + +- [``braincore``](https://github.com/brainpy/braincore): The core system for the next generation of BrainPy framework. + +- [``brainunit``](https://github.com/brainpy/brainunit): The tools for the brain dynamics simulation and analysis. + +- [``brainscale``](https://github.com/brainpy/brainscale): The scalable online learning for biological spiking neural networks. + diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..fa4b396 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +# Security Policy + +## Reporting a bug in BrainCore + +Report security bugs in BrainPy via [Github Issue](https://github.com/brainpy/braincore/issues). + +Normally your report will be acknowledged within 5 days, and you'll receive a more detailed response +to your report within 10 days indicating the next steps in handling your submission. These timelines +may extend when our triage volunteers are away on holiday, particularly at the end of the year. + +After the initial reply to your report, the security team will endeavor to keep you informed of the +progress being made towards a fix and full announcement, and may ask for additional information or +guidance surrounding the reported issue. + +## Reporting a bug in a third party module + +Security bugs in third party modules should be reported to their respective maintainers. + +## Reporting a Vulnerability + +If you discover a security vulnerability in this project, please report it to us as soon as possible. +We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your +contributions. diff --git a/brainunit/__init__.py b/brainunit/__init__.py new file mode 100644 index 0000000..dbd9a17 --- /dev/null +++ b/brainunit/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2024 BDP Ecosystem Limited. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + + +from ._base import * +from ._base import __all__ as _base_all +from ._unit_common import * +from ._unit_common import __all__ as _common_all +from ._unit_constants import * +from ._unit_constants import __all__ as _constants_all +from ._unit_shortcuts import * +from ._unit_shortcuts import __all__ as _std_units_all + +__all__ = _common_all + _std_units_all + _constants_all + _base_all +del _common_all, _std_units_all, _constants_all, _base_all diff --git a/brainunit/_base.py b/brainunit/_base.py new file mode 100644 index 0000000..ed28a84 --- /dev/null +++ b/brainunit/_base.py @@ -0,0 +1,3066 @@ +# Copyright 2024 BDP Ecosystem Limited. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +from __future__ import annotations + +import collections +import itertools +import numbers +import operator +from contextlib import contextmanager +from typing import Union, Optional, Sequence, Callable, Tuple, Any, List + +import brainstate as bst +import jax +import jax.numpy as jnp +import numpy as np +from jax.tree_util import register_pytree_node_class + +from ._misc import get_dtype + +__all__ = [ + 'Quantity', + 'Unit', + 'UnitRegistry', + 'DimensionMismatchError', + 'get_or_create_dimension', + 'get_unit', + 'get_basic_unit', + 'is_unitless', + 'have_same_unit', + 'in_unit', + 'in_best_unit', + 'register_new_unit', + 'check_units', + 'is_scalar_type', + 'fail_for_dimension_mismatch', +] + +_all_slice = slice(None, None, None) + +random = None +_unit_checking = True +_automatically_register_units = True +_allow_python_scalar_value = False + + +@contextmanager +def turn_off_unit_register(): + try: + global _automatically_register_units + _automatically_register_units = False + yield + finally: + _automatically_register_units = True + + +@contextmanager +def allow_python_scalar(): + try: + global _allow_python_scalar_value + _allow_python_scalar_value = True + yield + finally: + _allow_python_scalar_value = False + + +@contextmanager +def turn_off_unit_checking(): + try: + global _unit_checking + _unit_checking = False + yield + finally: + _unit_checking = True + + +def _get_random_module(): + global random + if random is None: + from brainstate import random + return random + + +def _to_quantity(array): + if isinstance(array, Quantity): + return array + elif isinstance(array, (numbers.Number, jax.Array, np.number, np.ndarray, list, tuple)): + return Quantity(value=array) + else: + raise TypeError('Input array should be an instance of Array.') + + +def _assert_not_quantity(array): + if isinstance(array, Quantity): + raise ValueError('Input array should not be an instance of Array.') + return array + + +def _short_str(arr): + """ + Return a short string representation of an array, suitable for use in + error messages. + """ + arr = np.asanyarray(arr) + old_printoptions = jnp.get_printoptions() + jnp.set_printoptions(edgeitems=2, threshold=5) + arr_string = str(arr) + jnp.set_printoptions(**old_printoptions) + return arr_string + + +def get_unit_for_display(d): + """ + Return a string representation of an appropriate unscaled unit or ``'1'`` + for a dimensionless array. + + Parameters + ---------- + d : Dimension or int + The dimension to find a unit for. + + Returns + ------- + s : str + A string representation of the respective unit or the string ``'1'``. + """ + if (isinstance(d, int) and d == 1) or d is DIMENSIONLESS: + return "1" + else: + return str(get_unit(d)) + + +# SI dimensions (see table at the top of the file) and various descriptions, +# each description maps to an index i, and the power of each dimension +# is stored in the variable dims[i] +_di = { + "Length": 0, + "length": 0, + "metre": 0, + "metres": 0, + "meter": 0, + "meters": 0, + "m": 0, + "Mass": 1, + "mass": 1, + "kilogram": 1, + "kilograms": 1, + "kg": 1, + "Time": 2, + "time": 2, + "second": 2, + "seconds": 2, + "s": 2, + "Electric Current": 3, + "electric current": 3, + "Current": 3, + "current": 3, + "ampere": 3, + "amperes": 3, + "A": 3, + "Temperature": 4, + "temperature": 4, + "kelvin": 4, + "kelvins": 4, + "K": 4, + "Quantity of Substance": 5, + "Quantity of substance": 5, + "quantity of substance": 5, + "Substance": 5, + "substance": 5, + "mole": 5, + "moles": 5, + "mol": 5, + "Luminosity": 6, + "luminosity": 6, + "candle": 6, + "candles": 6, + "cd": 6, +} + +_ilabel = ["m", "kg", "s", "A", "K", "mol", "cd"] + +# The same labels with the names used for constructing them in Python code +_iclass_label = ["metre", "kilogram", "second", "amp", "kelvin", "mole", "candle"] + +# SI unit _prefixes as integer exponents of 10, see table at end of file. +_siprefixes = { + "y": -24, + "z": -21, + "a": -18, + "f": -15, + "p": -12, + "n": -9, + "u": -6, + "m": -3, + "c": -2, + "d": -1, + "": 0, + "da": 1, + "h": 2, + "k": 3, + "M": 6, + "G": 9, + "T": 12, + "P": 15, + "E": 18, + "Z": 21, + "Y": 24, +} + + +class Dimension: + """ + Stores the indices of the 7 basic SI unit dimension (length, mass, etc.). + + Provides a subset of arithmetic operations appropriate to dimensions: + multiplication, division and powers, and equality testing. + + Parameters + ---------- + dims : sequence of `float` + The dimension indices of the 7 basic SI unit dimensions. + + Notes + ----- + Users shouldn't use this class directly, it is used internally in Array + and Unit. Even internally, never use ``Dimension(...)`` to create a new + instance, use `get_or_create_dimension` instead. This function makes + sure that only one Dimension instance exists for every combination of + indices, allowing for a very fast dimensionality check with ``is``. + """ + + __slots__ = ["_dims"] + __array_priority__ = 1000 + + # ---- INITIALISATION ---- # + + def __init__(self, dims): + self._dims = dims + + # ---- METHODS ---- # + def get_dimension(self, d): + """ + Return a specific dimension. + + Parameters + ---------- + d : `str` + A string identifying the SI basic unit dimension. Can be either a + description like "length" or a basic unit like "m" or "metre". + + Returns + ------- + dim : `float` + The dimensionality of the dimension `d`. + """ + return self._dims[_di[d]] + + @property + def is_unitless(self): + """ + Whether this Dimension is dimensionless. + + Notes + ----- + Normally, instead one should check dimension for being identical to + `DIMENSIONLESS`. + """ + return all([x == 0 for x in self._dims]) + + @property + def dim(self): + """ + Returns the `Dimension` object itself. This can be useful, because it + allows to check for the dimension of an object by checking its ``dim`` + attribute -- this will return a `Dimension` object for `Array`, + `Unit` and `Dimension`. + """ + return self + + @property + def unit(self): + return self + + # ---- REPRESENTATION ---- # + def _str_representation(self, python_code=False): + """ + String representation in basic SI units, or ``"1"`` for dimensionless. + Use ``python_code=False`` for display purposes and ``True`` for valid + Python code. + """ + + if python_code: + power_operator = " ** " + else: + power_operator = "^" + + parts = [] + for i in range(len(self._dims)): + if self._dims[i]: + if python_code: + s = _iclass_label[i] + else: + s = _ilabel[i] + if self._dims[i] != 1: + s += power_operator + str(self._dims[i]) + parts.append(s) + if python_code: + s = " * ".join(parts) + if not len(s): + return f"{self.__class__.__name__}()" + else: + s = " ".join(parts) + if not len(s): + return "1" + return s.strip() + + def __repr__(self): + return self._str_representation(python_code=True) + + def __str__(self): + return self._str_representation(python_code=False) + + # ---- ARITHMETIC ---- # + # Note that none of the dimension arithmetic objects do sanity checking + # on their inputs, although most will throw an exception if you pass the + # wrong sort of input + def __mul__(self, value): + return get_or_create_dimension([x + y for x, y in zip(self._dims, value._dims)]) + + def __div__(self, value): + return get_or_create_dimension([x - y for x, y in zip(self._dims, value._dims)]) + + def __truediv__(self, value): + return self.__div__(value) + + def __pow__(self, value: numbers.Number | jax.Array): + if value is DIMENSIONLESS: + return self + value = np.array(value) + if value.size > 1: + raise TypeError("Too many exponents") + return get_or_create_dimension([x * value for x in self._dims]) + + def __imul__(self, value): + raise TypeError("Dimension object is immutable") + + def __idiv__(self, value): + raise TypeError("Dimension object is immutable") + + def __itruediv__(self, value): + raise TypeError("Dimension object is immutable") + + def __ipow__(self, value): + raise TypeError("Dimension object is immutable") + + # ---- COMPARISON ---- # + def __eq__(self, value): + try: + return np.allclose(self._dims, value._dims) + except AttributeError: + # Only compare equal to another Dimensions object + return False + + def __ne__(self, value): + return not self.__eq__(value) + + def __hash__(self): + return hash(self._dims) + + # MAKE DIMENSION PICKABLE # + def __getstate__(self): + return self._dims + + def __setstate__(self, state): + self._dims = state + + def __reduce__(self): + # Make sure that unpickling Dimension objects does not bypass the singleton system + return get_or_create_dimension, (self._dims,) + + # --- Dimension objects are singletons and deepcopy is therefore not necessary + def __deepcopy__(self, memodict): + return self + + +def get_or_create_dimension(*args, **kwds): + """ + Create a new Dimension object or get a reference to an existing one. + This function takes care of only creating new objects if they were not + created before and otherwise returning a reference to an existing object. + This allows to compare dimensions very efficiently using ``is``. + + Parameters + ---------- + args : sequence of `float` + A sequence with the indices of the 7 elements of an SI dimension. + kwds : keyword arguments + a sequence of ``keyword=value`` pairs where the keywords are the names of + the SI dimensions, or the standard unit. + + Examples + -------- + The following are all definitions of the dimensions of force + + >>> from brainunit import * + >>> get_or_create_dimension(length=1, mass=1, time=-2) + metre * kilogram * second ** -2 + >>> get_or_create_dimension(m=1, kg=1, s=-2) + metre * kilogram * second ** -2 + >>> get_or_create_dimension([1, 1, -2, 0, 0, 0, 0]) + metre * kilogram * second ** -2 + + Notes + ----- + The 7 units are (in order): + + Length, Mass, Time, Electric Current, Temperature, + Quantity of Substance, Luminosity + + and can be referred to either by these names or their SI unit names, + e.g. length, metre, and m all refer to the same thing here. + """ + if len(args): + # initialisation by list + dims = args[0] + try: + if len(dims) != 7: + raise TypeError() + except TypeError: + raise TypeError("Need a sequence of exactly 7 items") + else: + # initialisation by keywords + dims = [0, 0, 0, 0, 0, 0, 0] + for k in kwds: + # _di stores the index of the dimension with name 'k' + dims[_di[k]] = kwds[k] + + dims = tuple(dims) + + # check whether this Dimension object has already been created + if dims in _dimensions: + return _dimensions[dims] + else: + new_dim = Dimension(dims) + _dimensions[dims] = new_dim + return new_dim + + +DIMENSIONLESS = Dimension((0, 0, 0, 0, 0, 0, 0)) +_dimensions = {(0, 0, 0, 0, 0, 0, 0): DIMENSIONLESS} + + +class DimensionMismatchError(Exception): + """ + Exception class for attempted operations with inconsistent dimensions. + + For example, ``3*mvolt + 2*amp`` raises this exception. The purpose of this + class is to help catch errors based on incorrect units. The exception will + print a representation of the dimensions of the two inconsistent objects + that were operated on. + + Parameters + ---------- + description : ``str`` + A description of the type of operation being performed, e.g. Addition, + Multiplication, etc. + dims : Dimension + The physical dimensions of the objects involved in the operation, any + number of them is possible + """ + __module__ = "brainunit" + + def __init__(self, description, *dims): + # Call the base class constructor to make Exception pickable, see: + # http://bugs.python.org/issue1692335 + super().__init__(description, *dims) + self.dims: Tuple = dims + self.desc = description + + def __repr__(self): + dims_repr = [repr(dim) for dim in self.dims] + return f"{self.__class__.__name__}({self.desc!r}, {', '.join(dims_repr)})" + + def __str__(self): + s = self.desc + if len(self.dims) == 0: + pass + elif len(self.dims) == 1: + s += f" (unit is {get_unit_for_display(self.dims[0])}" + elif len(self.dims) == 2: + d1, d2 = self.dims + s += ( + f" (units are {get_unit_for_display(d1)} and {get_unit_for_display(d2)}" + ) + else: + s += ( + " (units are" + f" {' '.join([f'({get_unit_for_display(d)})' for d in self.dims])}" + ) + if len(self.dims): + s += ")." + return s + + +def get_unit(obj) -> Dimension: + """ + Return the unit of any object that has them. + + Slightly more general than `Array.dimensions` because it will + return `DIMENSIONLESS` if the object is of number type but not a `Array` + (e.g. a `float` or `int`). + + Parameters + ---------- + obj : `object` + The object to check. + + Returns + ------- + dim : Dimension + The physical dimensions of the `obj`. + """ + try: + return obj.unit + except AttributeError: + # The following is not very pretty, but it will avoid the costly + # isinstance check for the common types + if isinstance(obj, (numbers.Number, jax.Array, np.number, np.ndarray)): + return DIMENSIONLESS + try: + return Quantity(obj).unit + except TypeError: + raise TypeError(f"Object of type {type(obj)} does not have dimensions") + + +def have_same_unit(obj1, obj2) -> bool: + """Test if two values have the same dimensions. + + Parameters + ---------- + obj1, obj2 : {`Array`, array-like, number} + The values of which to compare the dimensions. + + Returns + ------- + same : `bool` + ``True`` if `obj1` and `obj2` have the same dimensions. + """ + + if not _unit_checking: + return True # ignore units when unit checking is disabled + + # If dimensions are consistently created using get_or_create_dimensions, + # the fast "is" comparison should always return the correct result. + # To be safe, we also do an equals comparison in case it fails. This + # should only add a small amount of unnecessary computation for cases in + # which this function returns False which very likely leads to a + # DimensionMismatchError anyway. + dim1 = get_unit(obj1) + dim2 = get_unit(obj2) + return (dim1 is dim2) or (dim1 == dim2) or dim1 is None or dim2 is None + + +def fail_for_dimension_mismatch( + obj1, obj2=None, error_message=None, **error_arrays +): + """ + Compare the dimensions of two objects. + + Parameters + ---------- + obj1, obj2 : {array-like, `Array`} + The object to compare. If `obj2` is ``None``, assume it to be + dimensionless + error_message : str, optional + An error message that is used in the DimensionMismatchError + error_arrays : dict mapping str to `Array`, optional + Arrays in this dictionary will be converted using the `_short_str` + helper method and inserted into the ``error_message`` (which should + have placeholders with the corresponding names). The reason for doing + this in a somewhat complicated way instead of directly including all the + details in ``error_messsage`` is that converting large arrays + to strings can be rather costly and we don't want to do it if no error + occured. + + Returns + ------- + dim1, dim2 : Dimension, `Dimension` + The physical dimensions of the two arguments (so that later code does + not need to get the dimensions again). + + Raises + ------ + DimensionMismatchError + If the dimensions of `obj1` and `obj2` do not match (or, if `obj2` is + ``None``, in case `obj1` is not dimensionsless). + + Notes + ----- + Implements special checking for ``0``, treating it as having "any + dimensions". + """ + if not _unit_checking: + return None, None + + dim1 = get_unit(obj1) + if obj2 is None: + dim2 = DIMENSIONLESS + else: + dim2 = get_unit(obj2) + + if dim1 is not dim2 and not (dim1 is None or dim2 is None): + # Special treatment for "0": + # if it is not a Array, it has "any dimension". + # This allows expressions like 3*mV + 0 to pass (useful in cases where + # zero is treated as the neutral element, e.g. in the Python sum + # builtin) or comparisons like 3 * mV == 0 to return False instead of + # failing # with a DimensionMismatchError. Note that 3*mV == 0*second + # is not allowed, though. + + if (dim1 is DIMENSIONLESS and jnp.all(obj1 == 0)) or ( + dim2 is DIMENSIONLESS and jnp.all(obj2 == 0) + ): + return dim1, dim2 + + # We do another check here, this should allow Brian1 units to pass as + # having the same dimensions as a Brian2 unit + if dim1 == dim2: + return dim1, dim2 + + if error_message is None: + error_message = "Dimension mismatch" + else: + error_arrays = { + name: _short_str(q) for name, q in error_arrays.items() + } + error_message = error_message.format(**error_arrays) + # If we are comparing an object to a specific unit, we don't want to + # restate this unit (it is probably mentioned in the text already) + if obj2 is None or isinstance(obj2, (Dimension, Unit)): + raise DimensionMismatchError(error_message, dim1) + else: + raise DimensionMismatchError(error_message, dim1, dim2) + else: + return dim1, dim2 + + +def in_unit(x, u, precision=None) -> str: + """ + Display a value in a certain unit with a given precision. + + Parameters + ---------- + x : {`Array`, array-like, number} + The value to display + u : {`Array`, `Unit`} + The unit to display the value `x` in. + precision : `int`, optional + The number of digits of precision (in the given unit, see Examples). + If no value is given, numpy's `get_printoptions` value is used. + + Returns + ------- + s : `str` + A string representation of `x` in units of `u`. + + Examples + -------- + >>> from brainunit import * + >>> in_unit(3 * volt, mvolt) + '3000. mV' + >>> in_unit(123123 * msecond, second, 2) + '123.12 s' + >>> in_unit(10 * uA/cm**2, nA/um**2) + '1.00000000e-04 nA/(um^2)' + >>> in_unit(10 * mV, ohm * amp) + '0.01 ohm A' + >>> in_unit(10 * nS, ohm) # doctest: +NORMALIZE_WHITESPACE + ... # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + DimensionMismatchError: Non-matching unit for method "in_unit", + dimensions were (m^-2 kg^-1 s^3 A^2) (m^2 kg s^-3 A^-2) + + See Also + -------- + Array.in_unit + """ + if is_unitless(x): + fail_for_dimension_mismatch(x, u, 'Non-matching unit for function "in_unit"') + return str(jnp.array(x / u)) + else: + return x.repr_in_unit(u, precision=precision) + + +def in_best_unit(x, precision=None): + """ + Represent the value in the "best" unit. + + Parameters + ---------- + x : {`Array`, array-like, number} + The value to display + precision : `int`, optional + The number of digits of precision (in the best unit, see Examples). + If no value is given, numpy's `get_printoptions` value is used. + + Returns + ------- + representation : `str` + A string representation of this `Array`. + + Examples + -------- + >>> from brainunit import * + >>> in_best_unit(0.00123456 * volt) + '1.23456 mV' + >>> in_best_unit(0.00123456 * volt, 2) + '1.23 mV' + >>> in_best_unit(0.123456) + '0.123456' + >>> in_best_unit(0.123456, 2) + '0.12' + + See Also + -------- + Array.in_best_unit + """ + if is_unitless(x): + if precision is None: + precision = jnp.get_printoptions()["precision"] + return str(jnp.round(x, precision)) + + u = x.get_best_unit() + return x.repr_in_unit(u, precision=precision) + + +def array_with_units( + floatval, + units: Dimension, + dtype: bst.typing.DTypeLike = None +) -> 'Quantity': + """ + Create a new `Array` with the given dimensions. Calls + `get_or_create_dimension` with the dimension tuple of the `dims` + argument to make sure that unpickling (which calls this function) does not + accidentally create new Dimension objects which should instead refer to + existing ones. + + Parameters + ---------- + floatval : `float` + The floating point value of the array. + units: Dimension + The unit dimensions of the array. + dtype: `dtype`, optional + The data type of the array. + + Returns + ------- + array : `Quantity` + The new `Array` object. + + Examples + -------- + >>> from brainunit import * + >>> array_with_units(0.001, volt.unit) + 1. * mvolt + """ + return Quantity(floatval, unit=get_or_create_dimension(units._dims), dtype=dtype) + + +def is_unitless(obj) -> bool: + """ + Test if a value is dimensionless or not. + + Parameters + ---------- + obj : `object` + The object to check. + + Returns + ------- + dimensionless : `bool` + ``True`` if `obj` is dimensionless. + """ + return get_unit(obj) is DIMENSIONLESS + + +def is_scalar_type(obj) -> bool: + """ + Tells you if the object is a 1d number type. + + Parameters + ---------- + obj : `object` + The object to check. + + Returns + ------- + scalar : `bool` + ``True`` if `obj` is a scalar that can be interpreted as a + dimensionless `Array`. + """ + try: + return obj.ndim == 0 and is_unitless(obj) + except AttributeError: + return jnp.isscalar(obj) and not isinstance(obj, str) + + +def wrap_function_keep_dimensions(func): + """ + Returns a new function that wraps the given function `func` so that it + keeps the dimensions of its input. Arrays are transformed to + unitless jax numpy arrays before calling `func`, the output is a array + with the original dimensions re-attached. + + These transformations apply only to the very first argument, all + other arguments are ignored/untouched, allowing to work functions like + ``sum`` to work as expected with additional ``axis`` etc. arguments. + """ + + def f(x, *args, **kwds): # pylint: disable=C0111 + return Quantity(func(x.value, *args, **kwds), unit=x.unit) + + f._arg_units = [None] + f._return_unit = lambda u: u + f.__name__ = func.__name__ + f.__doc__ = func.__doc__ + f._do_not_run_doctests = True + return f + + +def wrap_function_change_dimensions(func, change_dim_func): + """ + Returns a new function that wraps the given function `func` so that it + changes the dimensions of its input. Arrays are transformed to + unitless jax numpy arrays before calling `func`, the output is a array + with the original dimensions passed through the function + `change_dim_func`. A typical use would be a ``sqrt`` function that uses + ``lambda d: d ** 0.5`` as ``change_dim_func``. + + These transformations apply only to the very first argument, all + other arguments are ignored/untouched. + """ + + def f(x, *args, **kwds): # pylint: disable=C0111 + assert isinstance(x, Quantity), "Only Quantity objects can be passed to this function" + return _return_check_unitless(Quantity(func(x.value, *args, **kwds), unit=change_dim_func(x.value, x.unit))) + + f._arg_units = [None] + f._return_unit = change_dim_func + f.__name__ = func.__name__ + f.__doc__ = func.__doc__ + f._do_not_run_doctests = True + return f + + +def wrap_function_remove_dimensions(func): + """ + Returns a new function that wraps the given function `func` so that it + removes any dimensions from its input. Useful for functions that are + returning integers (indices) or booleans, irrespective of the datatype + contained in the array. + + These transformations apply only to the very first argument, all + other arguments are ignored/untouched. + """ + + def f(x, *args, **kwds): # pylint: disable=C0111 + assert isinstance(x, Quantity), "Only Quantity objects can be passed to this function" + return func(x.value, *args, **kwds) + + f._arg_units = [None] + f._return_unit = 1 + f.__name__ = func.__name__ + f.__doc__ = func.__doc__ + f._do_not_run_doctests = True + return f + + +def _return_check_unitless(q): + if q.is_unitless: + return q.value + else: + return q + + +def process_list_with_units(value): + def check_units_and_collect_values(lst): + all_units = [] + values = [] + + for item in lst: + if isinstance(item, list): + val, unit = check_units_and_collect_values(item) + values.append(val) + if unit is not None: + all_units.append(unit) + elif isinstance(item, Quantity): + values.append(item.value) + all_units.append(item.unit) + else: + values.append(item) + all_units.append(DIMENSIONLESS) + + if all_units: + first_unit = all_units[0] + if not all(unit == first_unit for unit in all_units): + raise TypeError("All elements must have the same unit") + return values, first_unit + else: + return values, DIMENSIONLESS + + values, unit = check_units_and_collect_values(value) + return values, unit + + +@register_pytree_node_class +class Quantity(object): + """ + The `Quantity` class represents a physical quantity with a value and a + unit. It is used to represent all physical quantities in ``BrainCore``. + + """ + __slots__ = ('_value', '_unit') + _value: Union[jax.Array, numbers.Number] + _unit: Dimension + __array_priority__ = 1000 + + def __init__( + self, + value: Any, + dtype: bst.typing.DTypeLike = None, + unit: Dimension = DIMENSIONLESS, + ): + if isinstance(value, numbers.Number) and _allow_python_scalar_value: + self._unit = unit + self._value = value + return + + if isinstance(value, (list, tuple)): + value, new_unit = process_list_with_units(value) + if unit == DIMENSIONLESS: + unit = new_unit + elif new_unit != DIMENSIONLESS: + if unit != new_unit: + raise TypeError(f"All elements must have the same unit. But got {unit} != {new_unit}") + try: + # Transform to jnp array + value = jnp.array(value, dtype=dtype) + except ValueError: + raise TypeError("All elements must be convertible to a jax array") + dtype = dtype or get_dtype(value) + + # array value + if isinstance(value, Quantity): + self._unit = value.unit + self._value = jnp.array(value.value, dtype=dtype) + return + + elif isinstance(value, (np.ndarray, jax.Array)): + value = jnp.array(value, dtype=dtype) + + elif isinstance(value, (jnp.number, numbers.Number)): + value = jnp.array(value, dtype=dtype) + + else: + raise TypeError(f"Invalid type for value: {type(value)}") + + # value + self._value = value + + # unit + self._unit = unit + + @property + def value(self) -> jax.Array | numbers.Number: + # return the value + return self._value + + @value.setter + def value(self, value): + # Do not support setting the value directly + raise NotImplementedError("Cannot set the value of a Quantity object directly," + "Please create a new Quantity object with the value you want.") + + def update_value(self, value): + """ + Set the value of the array. + + Examples:: + + >>> a = jax.numpy.array([1, 2, 3]) * mV + >>> a[:] = jax.numpy.array([4, 5, 6]) * mV + >>> a.value = jax.numpy.array([7, 8, 9]) + + Args: + value: The new value of the array. + """ + self_value = self._check_tracer() + if isinstance(value, Quantity): + raise ValueError("Cannot set the value of an Array object to another Array object.") + if isinstance(value, np.ndarray): + value = jnp.asarray(value, dtype=self.dtype) + elif isinstance(value, jax.Array): + pass + else: + value = jnp.asarray(value, dtype=self.dtype) + # check + if value.shape != self_value.shape: + raise ValueError(f"The shape of the original data is {self_value.shape}, " + f"while we got {value.shape}.") + if value.dtype != self_value.dtype: + raise ValueError(f"The dtype of the original data is {self_value.dtype}, " + f"while we got {value.dtype}.") + self._value = value + + @property + def unit(self) -> Dimension: + """ + The physical unit dimensions of this Array + """ + return self._unit + + @unit.setter + def unit(self, unit): + # Do not support setting the unit directly + raise NotImplementedError("Cannot set the unit of a Quantity object directly," + "Please create a new Quantity object with the value you want.") + + @staticmethod + def with_units(value, *args, **keywords): + """ + Create a `Array` object with the given units. + + Parameters + ---------- + value : {array_like, number} + The value of the dimension + args : {`Dimension`, sequence of float} + Either a single argument (a `Dimension`) or a sequence of 7 values. + keywords + Keywords defining the dim, see `Dimension` for details. + + Returns + ------- + q : `Quantity` + A `Array` object with the given dim + + Examples + -------- + All of these define an equivalent `Array` object: + + >>> from brainunit import * + >>> Quantity.with_units(2, get_or_create_dimension(length=1)) + 2. * metre + >>> Quantity.with_units(2, length=1) + 2. * metre + >>> 2 * metre + 2. * metre + """ + if len(args) and isinstance(args[0], Dimension): + dimensions = args[0] + else: + dimensions = get_or_create_dimension(*args, **keywords) + return Quantity(value, unit=dimensions) + + @property + def is_unitless(self) -> bool: + """ + Whether the array does not have unit. + + Returns: + bool: True if the array does not have unit. + """ + return self.unit.is_unitless + + def has_same_unit(self, other): + """ + Whether this Array has the same unit dimensions as another Array + + Parameters + ---------- + other : Quantity + The other Array to compare with + + Returns + ------- + bool + Whether the two Arrays have the same unit dimensions + """ + if not _unit_checking: + return True + other_unit = get_unit(other.unit) + return (get_unit(self.unit) is other_unit) or (get_unit(self.unit) == other_unit) + + def get_best_unit(self, *regs) -> 'Quantity': + """ + Return the best unit for this `Array`. + + Parameters + ---------- + regs : any number of `UnitRegistry objects + The registries that are searched for units. If none are provided, it + will check the standard, user and additional unit registers in turn. + + Returns + ------- + u : `Quantity` or `Unit` + The best unit for this `Array`. + """ + if self.is_unitless: + return Unit(1) + if len(regs): + for r in regs: + try: + return r[self] + except KeyError: + pass + return Quantity(1, unit=self.unit) + else: + return self.get_best_unit(standard_unit_register, user_unit_register, additional_unit_register) + + def repr_in_unit( + self, + u: 'Unit', + precision: int | None = None, + python_code: bool = False + ) -> str: + """ + Represent the Array in a given unit. + + Parameters + ---------- + u : `Unit` + The unit in which to show the ar. + precision : `int`, optional + The number of digits of precision (in the given unit) + If no value is given, numpy's `get_printoptions` is used. + python_code : `bool`, optional + Whether to return a string that can be used as python code. + If True, the string will be formatted as a python expression. + If False, the string will be formatted as a human-readable string. + + Returns + ------- + s : `str` + The string representation of the Array in the given unit. + + Examples + -------- + >>> from brainunit import * + >>> x = 25.123456 * mV + >>> x.repr_in_unit(volt) + '0.02512346 V' + >>> x.repr_in_unit(volt, 3) + '0.025 V' + >>> x.repr_in_unit(mV, 3) + '25.123 mV' + """ + fail_for_dimension_mismatch(self, u, 'Non-matching unit for method "in_unit"') + value = jnp.asarray(self.value / u.value) + if value.shape == (): + s = jnp.array_str(jnp.array([value]), precision=precision) + s = s.replace("[", "").replace("]", "").strip() + else: + if value.size > 100: + if python_code: + s = jnp.array_repr(value, precision=precision)[:100] + s += "..." + else: + s = jnp.array_str(value, precision=precision)[:100] + s += "..." + else: + if python_code: + s = jnp.array_repr(value, precision=precision) + else: + s = jnp.array_str(value, precision=precision) + + if not u.is_unitless: + if isinstance(u, Unit): + if python_code: + s += f" * {repr(u)}" + else: + s += f" {str(u)}" + else: + if python_code: + s += f" * {repr(u.unit)}" + else: + s += f" {str(u.unit)}" + elif python_code: # Make a array without unit recognisable + return f"{self.__class__.__name__}({s.strip()})" + return s.strip() + + def repr_in_best_unit(self, precision: int = None, python_code: bool = False, *regs): + """ + Represent the array in the "best" unit. + + Parameters + ---------- + precision : `int`, optional + The number of digits of precision (in the best unit, see + Examples). If no value is given, numpy's + `get_printoptions` value is used. + python_code : `bool`, optional + Whether to return a string that can be used as python code. + If True, the string will be formatted as a python expression. + If False, the string will be formatted as a human-readable string. + regs : `UnitRegistry` objects + The registries where to search for units. If none are given, the + standard, user-defined and additional registries are searched in + that order. + + Returns + ------- + representation : `str` + A string representation of this `Array`. + + Examples + -------- + >>> from brainunit import * + >>> x = 0.00123456 * volt + >>> x.repr_in_best_unit() + '1.23456 mV' + >>> x.repr_in_best_unit(3) + '1.23 mV' + """ + u = self.get_best_unit(*regs) + return self.repr_in_unit(u, precision, python_code) + + def _check_tracer(self): + self_value = self.value + # if hasattr(self_value, '_trace') and hasattr(self_value._trace.main, 'jaxpr_stack'): + # if len(self_value._trace.main.jaxpr_stack) == 0: + # raise RuntimeError('This Array is modified during the transformation. ' + # 'BrainPy only supports transformations for Variable. ' + # 'Please declare it as a Variable.') from jax.core.escaped_tracer_error(self_value, None) + return self_value + + @property + def dtype(self): + """Variable dtype.""" + return get_dtype(self._value) + + @property + def shape(self) -> Tuple[int, ...]: + """Variable shape.""" + return jnp.shape(self._value) + + @property + def ndim(self) -> int: + return jnp.ndim(self.value) + + @property + def imag(self) -> 'Quantity': + return Quantity(jnp.imag(self.value), unit=self.unit) + + @property + def real(self) -> 'Quantity': + return Quantity(jnp.real(self.value), unit=self.unit) + + @property + def size(self) -> int: + return jnp.size(self.value) + + @property + def T(self) -> 'Quantity': + return Quantity(self.value.T, unit=self.unit) + + @property + def isreal(self) -> jax.Array: + return jnp.isreal(self.value) + + @property + def isscalar(self) -> bool: + return is_scalar_type(self) + + @property + def isfinite(self) -> jax.Array: + return jnp.isfinite(self.value) + + @property + def isinfnite(self) -> jax.Array: + return jnp.isinf(self.value) + + @property + def isinf(self) -> jax.Array: + return jnp.isinf(self.value) + + @property + def isnan(self) -> jax.Array: + return jnp.isnan(self.value) + + # ----------------------- # + # Python inherent methods # + # ----------------------- # + + def __repr__(self) -> str: + return self.repr_in_best_unit(python_code=True) + + def __str__(self) -> str: + return self.repr_in_best_unit() + + def __format__(self, format_spec: str) -> str: + # Avoid that formatted strings like f"{q}" use floating point formatting for the + # array, i.e. discard the unit + if format_spec == "": + return str(self) + else: + return self.value.__format__(format_spec) + + def __iter__(self): + """Solve the issue of DeviceArray.__iter__. + + Details please see JAX issues: + + - https://github.com/google/jax/issues/7713 + - https://github.com/google/jax/pull/3821 + """ + if self.ndim == 0: + yield self + else: + for i in range(self.shape[0]): + yield Quantity(self.value[i], unit=self.unit) + + def __getitem__(self, index) -> 'Quantity': + if isinstance(index, slice) and (index == _all_slice): + return Quantity(self.value, unit=self.unit) + elif isinstance(index, tuple): + for x in index: + assert not isinstance(x, Quantity), "Array indices must be integers or slices, not Array" + elif isinstance(index, Quantity): + raise TypeError("Array indices must be integers or slices, not Array") + return Quantity(self.value[index], unit=self.unit) + + def __setitem__(self, index, value: 'Quantity'): + if not isinstance(value, Quantity): + raise DimensionMismatchError("Only Array can be assigned to Array.") + fail_for_dimension_mismatch(self, value, "Inconsistent units in assignment") + value = value.value + + # index is a tuple + _assert_not_quantity(index) + if isinstance(index, (tuple, list)): + index = tuple(_assert_not_quantity(x) for x in index) + # index is numpy.ndarray + elif isinstance(index, np.ndarray): + index = jnp.asarray(index) + + # update + self_value = self._check_tracer() + self.update_value(self_value.at[index].set(value)) + + # ---------- # + # operations # + # ---------- # + + def __len__(self) -> int: + return len(self.value) + + def __neg__(self) -> 'Quantity': + return Quantity(self.value.__neg__(), unit=self.unit) + + def __pos__(self) -> 'Quantity': + return Quantity(self.value.__pos__(), unit=self.unit) + + def __abs__(self) -> 'Quantity': + return Quantity(self.value.__abs__(), unit=self.unit) + + def __invert__(self) -> 'Quantity': + return Quantity(self.value.__invert__(), unit=self.unit) + + def _comparison(self, other: Any, operator_str: str, operation: Callable): + is_scalar = is_scalar_type(other) + if not is_scalar and not isinstance(other, (jax.Array, Quantity, np.ndarray)): + return NotImplemented + if not is_scalar or not jnp.isinf(other): + other = _to_quantity(other) + message = "Cannot perform comparison {value1} %s {value2}, units do not match" % operator_str + fail_for_dimension_mismatch(self, other, message, value1=self, value2=other) + other = _to_quantity(other) + return operation(self.value, other.value) + + def __eq__(self, oc): + return self._comparison(oc, "==", operator.eq) + + def __ne__(self, oc): + return self._comparison(oc, "!=", operator.ne) + + def __lt__(self, oc): + return self._comparison(oc, "<", operator.lt) + + def __le__(self, oc): + return self._comparison(oc, "<=", operator.le) + + def __gt__(self, oc): + return self._comparison(oc, ">", operator.gt) + + def __ge__(self, oc): + return self._comparison(oc, ">=", operator.ge) + + def _binary_operation( + self, + other, + value_operation: Callable, + unit_operation: Callable = lambda a, b: a, + fail_for_mismatch: bool = False, + operator_str: str = None, + inplace: bool = False, + ): + """ + General implementation for binary operations. + + Parameters + ---------- + other : {`Array`, `ndarray`, scalar} + The object with which the operation should be performed. + value_operation : function of two variables + The function with which the two objects are combined. For example, + `operator.mul` for a multiplication. + unit_operation : function of two variables, optional + The function with which the dimension of the resulting object is + calculated (as a function of the dimensions of the two involved + objects). For example, `operator.mul` for a multiplication. If not + specified, the dimensions of `self` are used for the resulting + object. + fail_for_mismatch : bool, optional + Whether to fail for a dimension mismatch between `self` and `other` + (defaults to ``False``) + operator_str : str, optional + The string to use for the operator in an error message. + inplace: bool, optional + Whether to do the operation in-place (defaults to ``False``). + """ + other = _to_quantity(other) + other_unit = None + + if fail_for_mismatch: + if inplace: + message = "Cannot calculate ... %s {value}, units do not match" % operator_str + _, other_unit = fail_for_dimension_mismatch(self, other, message, value=other) + else: + message = "Cannot calculate {value1} %s {value2}, units do not match" % operator_str + _, other_unit = fail_for_dimension_mismatch(self, other, message, value1=self, value2=other) + + if other_unit is None: + other_unit = get_unit(other) + + new_unit = unit_operation(self.unit, other_unit) + result = value_operation(self.value, other.value) + r = Quantity(result, unit=new_unit) + if inplace: + self.update_value(r.value) + return self + return r + + def __add__(self, oc): + return self._binary_operation(oc, operator.add, fail_for_mismatch=True, operator_str="+") + + def __radd__(self, oc): + return self.__add__(oc) + + def __iadd__(self, oc): + # a += b + r = self._binary_operation(oc, operator.add, fail_for_mismatch=True, operator_str="+=", inplace=True) + self.update_value(r.value) + return self + + def __sub__(self, oc): + return self._binary_operation(oc, operator.sub, fail_for_mismatch=True, operator_str="-") + + def __rsub__(self, oc): + return Quantity(oc).__sub__(self) + + def __isub__(self, oc): + # a -= b + r = self._binary_operation(oc, operator.sub, fail_for_mismatch=True, operator_str="-=", inplace=True) + self.update_value(r.value) + return self + + def __mul__(self, oc): + r = self._binary_operation(oc, operator.mul, operator.mul) + return _return_check_unitless(r) + + def __rmul__(self, oc): + return self.__mul__(oc) + + def __imul__(self, oc): + # a *= b + raise NotImplementedError("In-place multiplication is not supported") + + def __div__(self, oc): + # self / oc + r = self._binary_operation(oc, operator.truediv, operator.truediv) + return _return_check_unitless(r) + + def __idiv__(self, oc): + raise NotImplementedError("In-place division is not supported") + + def __truediv__(self, oc): + # self / oc + return self.__div__(oc) + + def __rdiv__(self, oc): + # oc / self + # division with swapped arguments + rdiv = lambda a, b: operator.truediv(b, a) + r = self._binary_operation(oc, rdiv, rdiv) + return _return_check_unitless(r) + + def __rtruediv__(self, oc): + # oc / self + return self.__rdiv__(oc) + + def __itruediv__(self, oc): + # a /= b + raise NotImplementedError("In-place true division is not supported") + + def __floordiv__(self, oc): + # self // oc + r = self._binary_operation(oc, operator.floordiv, operator.truediv) + return _return_check_unitless(r) + + def __rfloordiv__(self, oc): + # oc // self + rdiv = lambda a, b: operator.truediv(b, a) + rfloordiv = lambda a, b: operator.truediv(b, a) + r = self._binary_operation(oc, rfloordiv, rdiv) + return _return_check_unitless(r) + + def __ifloordiv__(self, oc): + # a //= b + raise NotImplementedError("In-place floor division is not supported") + + def __mod__(self, oc): + # self % oc + r = self._binary_operation(oc, operator.mod, operator_str=r"%") + return _return_check_unitless(r) + + def __rmod__(self, oc): + # oc % self + oc = _to_quantity(oc) + r = oc._binary_operation(self, operator.mod, operator_str=r"%") + return _return_check_unitless(r) + + def __imod__(self, oc): + raise NotImplementedError("In-place mod is not supported") + + def __divmod__(self, oc): + return self.__floordiv__(oc), self.__mod__(oc) + + def __rdivmod__(self, oc): + return self.__rfloordiv__(oc), self.__rmod__(oc) + + def __matmul__(self, oc): + r = self._binary_operation(oc, operator.matmul, operator.mul) + return _return_check_unitless(r) + + def __rmatmul__(self, oc): + oc = _to_quantity(oc) + r = oc._binary_operation(self, operator.matmul, operator.mul) + return _return_check_unitless(r) + + def __imatmul__(self, oc): + # a @= b + raise NotImplementedError("In-place matrix multiplication is not supported") + + # -------------------- # + + def __pow__(self, oc): + # self ** oc + if isinstance(oc, (jax.Array, np.ndarray, numbers.Number, Quantity)) or is_scalar_type(oc): + fail_for_dimension_mismatch( + oc, + error_message=( + "Cannot calculate " + "{base} ** {exponent}, " + "the exponent has to be " + "dimensionless" + ), + base=self, + exponent=oc, + ) + if isinstance(oc, Quantity): + oc = oc.value + r = Quantity(jnp.array(self.value) ** oc, unit=self.unit ** oc) + return _return_check_unitless(r) + else: + return TypeError('Cannot calculate {base} ** {exponent}, the ' + 'exponent has to be dimensionless'.format(base=self, exponent=oc)) + + def __rpow__(self, oc): + # oc ** self + if self.is_unitless: + if isinstance(oc, (jax.Array, np.ndarray, numbers.Number)): + return oc ** self.value + else: + return oc.__pow__(self.value) + else: + raise DimensionMismatchError(f"Cannot calculate {_short_str(oc)} ** {_short_str(self)}, " + f"the base has to be dimensionless", + self.unit) + + def __ipow__(self, oc): + # a **= b + raise NotImplementedError("In-place power is not supported") + + def __and__(self, oc): + # Remove the unit from the result + raise NotImplementedError("Bitwise operations are not supported") + + def __rand__(self, oc): + # Remove the unit from the result + raise NotImplementedError("Bitwise operations are not supported") + + def __iand__(self, oc): + # Remove the unit from the result + raise NotImplementedError("Bitwise operations are not supported") + + def __or__(self, oc): + # Remove the unit from the result + raise NotImplementedError("Bitwise operations are not supported") + + def __ror__(self, oc): + # Remove the unit from the result + raise NotImplementedError("Bitwise operations are not supported") + + def __ior__(self, oc): + # Remove the unit from the result + # a |= b + raise NotImplementedError("Bitwise operations are not supported") + + def __xor__(self, oc): + # Remove the unit from the result + raise NotImplementedError("Bitwise operations are not supported") + + def __rxor__(self, oc): + # Remove the unit from the result + raise NotImplementedError("Bitwise operations are not supported") + + def __ixor__(self, oc) -> 'Quantity': + # Remove the unit from the result + # a ^= b + raise NotImplementedError("Bitwise operations are not supported") + + def __lshift__(self, oc) -> 'Quantity': + # self << oc + if is_scalar_type(oc) and isinstance(oc, Quantity): + oc = oc.value + r = Quantity(self.value << oc, unit=self.unit) + return _return_check_unitless(r) + + def __rlshift__(self, oc) -> 'Quantity': + # oc << self + if isinstance(oc, (jax.Array, np.ndarray, numbers.Number)): + oc = Quantity(oc, unit=DIMENSIONLESS) + r = oc.__lshift__(self.value) + return _return_check_unitless(r) + + def __ilshift__(self, oc) -> 'Quantity': + # a <<= b + r = self.__lshift__(oc) + self.update_value(r.value) + return self + + def __rshift__(self, oc) -> 'Quantity': + # self >> oc + if isinstance(oc, Quantity): + oc = oc.value + r = Quantity(self.value >> oc, unit=self.unit) + return _return_check_unitless(r) + + def __rrshift__(self, oc) -> 'Quantity': + # oc >> self + if isinstance(oc, (jax.Array, np.ndarray, numbers.Number)): + oc = Quantity(oc, unit=DIMENSIONLESS) + r = oc.__rshift__(self.value) + return _return_check_unitless(r) + + def __irshift__(self, oc) -> 'Quantity': + # a >>= b + r = self.__rshift__(oc) + self.update_value(r.value) + return self + + def __round__(self, ndigits: int = None) -> 'Quantity': + return Quantity(self.value.__round__(ndigits), unit=self.unit) + + def __reduce__(self): + return array_with_units, (self.value, self.unit, self.value.dtype) + + # ----------------------- # + # NumPy methods # + # ----------------------- # + + all = wrap_function_remove_dimensions(jnp.all) + any = wrap_function_remove_dimensions(jnp.any) + nonzero = wrap_function_remove_dimensions(jnp.nonzero) + argmax = wrap_function_remove_dimensions(jnp.argmax) + argmin = wrap_function_remove_dimensions(jnp.argmin) + argsort = wrap_function_remove_dimensions(jnp.argsort) + + var = wrap_function_change_dimensions(jnp.var, lambda v, d: d ** 2) + + round = wrap_function_keep_dimensions(jnp.round) + std = wrap_function_keep_dimensions(jnp.std) + sum = wrap_function_keep_dimensions(jnp.sum) + trace = wrap_function_keep_dimensions(jnp.trace) + cumsum = wrap_function_keep_dimensions(jnp.cumsum) + diagonal = wrap_function_keep_dimensions(jnp.diagonal) + max = wrap_function_keep_dimensions(jnp.max) + mean = wrap_function_keep_dimensions(jnp.mean) + min = wrap_function_keep_dimensions(jnp.min) + ptp = wrap_function_keep_dimensions(jnp.ptp) + ravel = wrap_function_keep_dimensions(jnp.ravel) + + def astype(self, dtype) -> 'Quantity': + """Copy of the array, cast to a specified type. + + Parameters + ---------- + dtype: str, dtype + Typecode or data-type to which the array is cast. + """ + if dtype is None: + return Quantity(self.value, unit=self.unit) + else: + return Quantity(self.value.astype(dtype), unit=self.unit) + + def clip(self, min: Quantity = None, max: Quantity = None, *args, **kwds) -> 'Quantity': + """Return an array whose values are limited to [min, max]. One of max or min must be given.""" + + fail_for_dimension_mismatch(self, min, "clip") + fail_for_dimension_mismatch(self, max, "clip") + return Quantity( + jnp.clip( + jnp.array(self.value), + jnp.array(min.value), + jnp.array(max.value), + *args, + **kwds, + ), + unit=self.unit, + ) + + def conj(self) -> 'Quantity': + """Complex-conjugate all elements.""" + return Quantity(jnp.conj(self.value), unit=self.unit) + + def conjugate(self) -> 'Quantity': + """Return the complex conjugate, element-wise.""" + return Quantity(jnp.conjugate(self.value), unit=self.unit) + + def copy(self) -> 'Quantity': + """Return a copy of the array.""" + return Quantity(jnp.copy(self.value), unit=self.unit) + + def dot(self, b) -> 'Quantity': + """Dot product of two arrays.""" + r = self._binary_operation(b, jnp.dot, operator.mul) + return _return_check_unitless(r) + + def fill(self, value: Quantity) -> 'Quantity': + """Fill the array with a scalar value.""" + fail_for_dimension_mismatch(self, value, "fill") + self.update_value((jnp.ones_like(self.value) * value).value) + return self + + def flatten(self) -> 'Quantity': + return Quantity(jnp.reshape(self.value, -1), unit=self.unit) + + def item(self, *args) -> 'Quantity': + """Copy an element of an array to a standard Python scalar and return it.""" + with allow_python_scalar(): + if isinstance(self.value, jax.Array): + return Quantity(self.value.item(*args), unit=self.unit) + else: + return Quantity(self.value, unit=self.unit) + + def prod(self, *args, **kwds) -> 'Quantity': + """Return the product of the array elements over the given axis.""" + prod_res = jnp.prod(self.value, *args, **kwds) + # Calculating the correct dimensions is not completly trivial (e.g. + # like doing self.dim**self.size) because prod can be called on + # multidimensional arrays along a certain axis. + # Our solution: Use a "dummy matrix" containing a 1 (without units) at + # each entry and sum it, using the same keyword arguments as provided. + # The result gives the exponent for the dimensions. + # This relies on sum and prod having the same arguments, which is true + # now and probably remains like this in the future + dim_exponent = jnp.ones_like(self.value).sum(*args, **kwds) + # The result is possibly multidimensional but all entries should be + # identical + if dim_exponent.size > 1: + dim_exponent = dim_exponent[-1] + r = Quantity(jnp.array(prod_res), unit=self.unit ** dim_exponent) + return _return_check_unitless(r) + + def nanprod(self, *args, **kwds) -> 'Quantity': + """Return the product of array elements over a given axis treating Not a Numbers (NaNs) as ones.""" + prod_res = jnp.nanprod(self.value, *args, **kwds) + nan_mask = jnp.isnan(self.value) + dim_exponent = jnp.cumsum(jnp.where(nan_mask, 0, 1), *args) + if dim_exponent.size > 1: + dim_exponent = dim_exponent[-1] + r = Quantity(jnp.array(prod_res), unit=self.unit ** dim_exponent) + return _return_check_unitless(r) + + def cumprod(self, *args, **kwds): # pylint: disable=C0111 + prod_res = jnp.cumprod(self.value, *args, **kwds) + dim_exponent = jnp.ones_like(self.value).cumsum(*args, **kwds) + if dim_exponent.size > 1: + dim_exponent = dim_exponent[-1] + r = Quantity(jnp.array(prod_res), unit=self.unit ** dim_exponent) + return _return_check_unitless(r) + + def nancumprod(self, *args, **kwds): # pylint: disable=C0111 + prod_res = jnp.nancumprod(self.value, *args, **kwds) + nan_mask = jnp.isnan(self.value) + dim_exponent = jnp.cumsum(jnp.where(nan_mask, 0, 1), *args) + if dim_exponent.size > 1: + dim_exponent = dim_exponent[-1] + r = Quantity(jnp.array(prod_res), unit=self.unit ** dim_exponent) + return _return_check_unitless(r) + + def put(self, indices, values) -> 'Quantity': + """Replaces specified elements of an array with given values. + + Parameters + ---------- + indices: array_like + Target indices, interpreted as integers. + values: array_like + Values to place in the array at target indices. + """ + fail_for_dimension_mismatch(self, values, "put") + self.__setitem__(indices, values) + return self + + def repeat(self, repeats, axis=None) -> 'Quantity': + """Repeat elements of an array.""" + r = jnp.repeat(self.value, repeats=repeats, axis=axis) + return Quantity(r, unit=self.unit) + + def reshape(self, *shape, order='C') -> 'Quantity': + """Returns an array containing the same data with a new shape.""" + return Quantity(jnp.reshape(self.value, shape, order=order), unit=self.unit) + + def resize(self, new_shape) -> 'Quantity': + """Change shape and size of array in-place.""" + self.update_value(jnp.resize(self.value, new_shape)) + return self + + def sort(self, axis=-1, stable=True, order=None) -> 'Quantity': + """Sort an array in-place. + + Parameters + ---------- + axis : int, optional + Axis along which to sort. Default is -1, which means sort along the + last axis. + stable : bool, optional + Whether to use a stable sorting algorithm. The default is True. + order : str or list of str, optional + When `a` is an array with fields defined, this argument specifies + which fields to compare first, second, etc. A single field can + be specified as a string, and not all fields need be specified, + but unspecified fields will still be used, in the order in which + they come up in the dtype, to break ties. + """ + self.update_value(jnp.sort(self.value, axis=axis, stable=stable, order=order)) + return self + + def squeeze(self, axis=None) -> 'Quantity': + """Remove axes of length one from ``a``.""" + return Quantity(jnp.squeeze(self.value, axis=axis), unit=self.unit) + + def swapaxes(self, axis1, axis2) -> 'Quantity': + """Return a view of the array with `axis1` and `axis2` interchanged.""" + return Quantity(jnp.swapaxes(self.value, axis1, axis2), unit=self.unit) + + def split(self, indices_or_sections, axis=0) -> List['Quantity']: + """Split an array into multiple sub-arrays as views into ``ary``. + + Parameters + ---------- + indices_or_sections : int, 1-D array + If `indices_or_sections` is an integer, N, the array will be divided + into N equal arrays along `axis`. If such a split is not possible, + an error is raised. + + If `indices_or_sections` is a 1-D array of sorted integers, the entries + indicate where along `axis` the array is split. For example, + ``[2, 3]`` would, for ``axis=0``, result in + + - ary[:2] + - ary[2:3] + - ary[3:] + + If an index exceeds the dimension of the array along `axis`, + an empty sub-array is returned correspondingly. + axis : int, optional + The axis along which to split, default is 0. + + Returns + ------- + sub-arrays : list of ndarrays + A list of sub-arrays as views into `ary`. + """ + return [Quantity(a, unit=self.unit) for a in jnp.split(self.value, indices_or_sections, axis=axis)] + + def take(self, indices, axis=None, mode=None) -> 'Quantity': + """Return an array formed from the elements of a at the given indices.""" + return Quantity(jnp.take(self.value, indices=indices, axis=axis, mode=mode), unit=self.unit) + + def tolist(self): + """Return the array as an ``a.ndim``-levels deep nested list of Python scalars. + + Return a copy of the array data as a (nested) Python list. + Data items are converted to the nearest compatible builtin Python type, via + the `~numpy.ndarray.item` function. + + If ``a.ndim`` is 0, then since the depth of the nested list is 0, it will + not be a list at all, but a simple Python scalar. + """ + + def replace_with_array(seq, unit): + """ + Replace all the elements in the list with an equivalent `Array` + with the given `unit`. + """ + # No recursion needed for single values + if not isinstance(seq, list): + return Quantity(seq, unit=unit) + + def top_replace(s): + """ + Recursively descend into the list. + """ + for i in s: + if not isinstance(i, list): + yield Quantity(i, unit=unit) + else: + yield type(i)(top_replace(i)) + + return type(seq)(top_replace(seq)) + + if isinstance(self.value, jax.Array): + return replace_with_array(self.value.tolist(), self.unit) + else: + with allow_python_scalar(): + return Quantity(self.value, unit=self.unit) + + def transpose(self, *axes) -> 'Quantity': + """Returns a view of the array with axes transposed. + + For a 1-D array this has no effect, as a transposed vector is simply the + same vector. To convert a 1-D array into a 2D column vector, an additional + dimension must be added. `jnp.atleast2d(a).T` achieves this, as does + `a[:, jnp.newaxis]`. + For a 2-D array, this is a standard matrix transpose. + For an n-D array, if axes are given, their order indicates how the + axes are permuted (see Examples). If axes are not provided and + ``a.shape = (i[0], i[1], ... i[n-2], i[n-1])``, then + ``a.transpose().shape = (i[n-1], i[n-2], ... i[1], i[0])``. + + Parameters + ---------- + axes : None, tuple of ints, or `n` ints + + * None or no argument: reverses the order of the axes. + + * tuple of ints: `i` in the `j`-th place in the tuple means `a`'s + `i`-th axis becomes `a.transpose()`'s `j`-th axis. + + * `n` ints: same as an n-tuple of the same ints (this form is + intended simply as a "convenience" alternative to the tuple form) + + Returns + ------- + out : ndarray + View of `a`, with axes suitably permuted. + """ + return Quantity(jnp.transpose(self.value, *axes), unit=self.unit) + + def tile(self, reps) -> 'Quantity': + """Construct an array by repeating A the number of times given by reps. + + If `reps` has length ``d``, the result will have dimension of + ``max(d, A.ndim)``. + + If ``A.ndim < d``, `A` is promoted to be d-dimensional by prepending new + axes. So a shape (3,) array is promoted to (1, 3) for 2-D replication, + or shape (1, 1, 3) for 3-D replication. If this is not the desired + behavior, promote `A` to d-dimensions manually before calling this + function. + + If ``A.ndim > d``, `reps` is promoted to `A`.ndim by pre-pending 1's to it. + Thus for an `A` of shape (2, 3, 4, 5), a `reps` of (2, 2) is treated as + (1, 1, 2, 2). + + Note : Although tile may be used for broadcasting, it is strongly + recommended to use numpy's broadcasting operations and functions. + + Parameters + ---------- + reps : array_like + The number of repetitions of `A` along each axis. + + Returns + ------- + c : ndarray + The tiled output array. + """ + return Quantity(jnp.tile(self.value, reps), unit=self.unit) + + def view(self, *args, dtype=None) -> 'Quantity': + r"""New view of array with the same data. + + This function is compatible with pytorch syntax. + + Returns a new tensor with the same data as the :attr:`self` tensor but of a + different :attr:`shape`. + + The returned tensor shares the same data and must have the same number + of elements, but may have a different size. For a tensor to be viewed, the new + view size must be compatible with its original size and stride, i.e., each new + view dimension must either be a subspace of an original dimension, or only span + across original dimensions :math:`d, d+1, \dots, d+k` that satisfy the following + contiguity-like condition that :math:`\forall i = d, \dots, d+k-1`, + + .. math:: + + \text{stride}[i] = \text{stride}[i+1] \times \text{size}[i+1] + + Otherwise, it will not be possible to view :attr:`self` tensor as :attr:`shape` + without copying it (e.g., via :meth:`contiguous`). When it is unclear whether a + :meth:`view` can be performed, it is advisable to use :meth:`reshape`, which + returns a view if the shapes are compatible, and copies (equivalent to calling + :meth:`contiguous`) otherwise. + + Args: + shape (int...): the desired size + + Example:: + + >>> import brainstate + >>> x = brainstate.random.randn(4, 4) + >>> x.size + [4, 4] + >>> y = x.view(16) + >>> y.size + [16] + >>> z = x.view(-1, 8) # the size -1 is inferred from other dimensions + >>> z.size + [2, 8] + + >>> a = brainstate.random.randn(1, 2, 3, 4) + >>> a.size + [1, 2, 3, 4] + >>> b = a.transpose(1, 2) # Swaps 2nd and 3rd dimension + >>> b.size + [1, 3, 2, 4] + >>> c = a.view(1, 3, 2, 4) # Does not change tensor layout in memory + >>> c.size + [1, 3, 2, 4] + >>> brainstate.math.equal(b, c) + False + + + .. method:: view(dtype) -> Tensor + :noindex: + + Returns a new tensor with the same data as the :attr:`self` tensor but of a + different :attr:`dtype`. + + If the element size of :attr:`dtype` is different than that of ``self.dtype``, + then the size of the last dimension of the output will be scaled + proportionally. For instance, if :attr:`dtype` element size is twice that of + ``self.dtype``, then each pair of elements in the last dimension of + :attr:`self` will be combined, and the size of the last dimension of the output + will be half that of :attr:`self`. If :attr:`dtype` element size is half that + of ``self.dtype``, then each element in the last dimension of :attr:`self` will + be split in two, and the size of the last dimension of the output will be + double that of :attr:`self`. For this to be possible, the following conditions + must be true: + + * ``self.dim()`` must be greater than 0. + * ``self.stride(-1)`` must be 1. + + Additionally, if the element size of :attr:`dtype` is greater than that of + ``self.dtype``, the following conditions must be true as well: + + * ``self.size(-1)`` must be divisible by the ratio between the element + sizes of the dtypes. + * ``self.storage_offset()`` must be divisible by the ratio between the + element sizes of the dtypes. + * The strides of all dimensions, except the last dimension, must be + divisible by the ratio between the element sizes of the dtypes. + + If any of the above conditions are not met, an error is thrown. + + + Args: + dtype (:class:`dtype`): the desired dtype + + Example:: + + >>> x = brainstate.random.randn(4, 4) + >>> x + Array([[ 0.9482, -0.0310, 1.4999, -0.5316], + [-0.1520, 0.7472, 0.5617, -0.8649], + [-2.4724, -0.0334, -0.2976, -0.8499], + [-0.2109, 1.9913, -0.9607, -0.6123]]) + >>> x.dtype + brainstate.math.float32 + + >>> y = x.view(numpy.int32) + >>> y + tensor([[ 1064483442, -1124191867, 1069546515, -1089989247], + [-1105482831, 1061112040, 1057999968, -1084397505], + [-1071760287, -1123489973, -1097310419, -1084649136], + [-1101533110, 1073668768, -1082790149, -1088634448]], + dtype=numpy.int32) + >>> y[0, 0] = 1000000000 + >>> x + tensor([[ 0.0047, -0.0310, 1.4999, -0.5316], + [-0.1520, 0.7472, 0.5617, -0.8649], + [-2.4724, -0.0334, -0.2976, -0.8499], + [-0.2109, 1.9913, -0.9607, -0.6123]]) + + >>> x.view(numpy.complex64) + tensor([[ 0.0047-0.0310j, 1.4999-0.5316j], + [-0.1520+0.7472j, 0.5617-0.8649j], + [-2.4724-0.0334j, -0.2976-0.8499j], + [-0.2109+1.9913j, -0.9607-0.6123j]]) + >>> x.view(numpy.complex64).size + [4, 2] + + >>> x.view(numpy.uint8) + tensor([[ 0, 202, 154, 59, 182, 243, 253, 188, 185, 252, 191, 63, 240, 22, + 8, 191], + [227, 165, 27, 190, 128, 72, 63, 63, 146, 203, 15, 63, 22, 106, + 93, 191], + [205, 59, 30, 192, 112, 206, 8, 189, 7, 95, 152, 190, 12, 147, + 89, 191], + [ 43, 246, 87, 190, 235, 226, 254, 63, 111, 240, 117, 191, 177, 191, + 28, 191]], dtype=uint8) + >>> x.view(numpy.uint8).size + [4, 16] + + """ + if isinstance(self.value, jax.Array): + if len(args) == 0: + if dtype is None: + raise ValueError('Provide dtype or shape.') + else: + return Quantity(self.value.view(dtype), unit=self.unit) + else: + if isinstance(args[0], int): # shape + if dtype is not None: + raise ValueError('Provide one of dtype or shape. Not both.') + return Quantity(self.value.reshape(*args), unit=self.unit) + else: # dtype + assert not isinstance(args[0], int) + assert dtype is None + return Quantity(self.value.view(args[0]), unit=self.unit) + else: + return Quantity(jnp.asarray(self.value, dtype=dtype), unit=self.unit) + + # ------------------ + # NumPy support + # ------------------ + + def to_numpy(self, dtype=None) -> np.ndarray: + """Convert to numpy.ndarray.""" + return np.asarray(self.value, dtype=dtype) + + def to_jax(self, dtype=None) -> jax.Array: + """Convert to jax.numpy.ndarray.""" + if dtype is None: + return self.value + else: + return jnp.asarray(self.value, dtype=dtype) + + def __array__(self, dtype=None) -> np.ndarray: + """Support ``numpy.array()`` and ``numpy.asarray()`` functions.""" + return np.asarray(self.value, dtype=dtype) + + def __float__(self): + return self.value.__float__() + + def __index__(self): + return operator.index(self.value) + + # ---------------------- + # PyTorch compatibility + # ---------------------- + + def unsqueeze(self, dim: int) -> 'Quantity': + """ + Array.unsqueeze(dim) -> Array, or so called Tensor + equals + Array.expand_dims(dim) + + See :func:`brainstate.math.unsqueeze` + """ + return Quantity(jnp.expand_dims(self.value, dim), unit=self.unit) + + def expand_dims(self, axis: Union[int, Sequence[int]]) -> 'Quantity': + """ + self.expand_dims(axis: int|Sequence[int]) + + 1. 如果axis类型为int: + 返回一个在self基础上的第axis维度前插入一个维度Array, + axis<0表示倒数第|axis|维度, + 令n=len(self._value.shape),则axis的范围为[-(n+1),n] + + 2. 如果axis类型为Sequence[int]: + 则返回依次扩展axis[i]的结果, + 即self.expand_dims(axis)==self.expand_dims(axis[0]).expand_dims(axis[1])...expand_dims(axis[len(axis)-1]) + + + 1. If the type of axis is int: + + Returns an Array of dimensions inserted before the axis dimension based on self, + + The first | axis < 0 indicates the bottom axis | dimensions, + + Set n=len(self._value.shape), then axis has the range [-(n+1),n] + + + 2. If the type of axis is Sequence[int] : + + Returns the result of extending axis[i] in sequence, + + self.expand_dims(axis)==self.expand_dims(axis[0]).expand_dims(axis[1])... expand_dims(axis[len(axis)-1]) + + """ + return Quantity(jnp.expand_dims(self.value, axis), unit=self.unit) + + def expand_as(self, array: Union['Quantity', jax.Array, np.ndarray]) -> 'Quantity': + """ + Expand an array to a shape of another array. + + Parameters + ---------- + array : Quantity + + Returns + ------- + expanded : Quantity + A readonly view on the original array with the given shape of array. It is + typically not contiguous. Furthermore, more than one element of a + expanded array may refer to a single memory location. + """ + if isinstance(array, Quantity): + array = array.value + return Quantity(jnp.broadcast_to(self.value, array), unit=self.unit) + + def pow(self, oc) -> 'Quantity': + return self.__pow__(oc) + + def clamp( + self, + min_value: Optional['Quantity'] = None, + max_value: Optional['Quantity'] = None, + ) -> 'Quantity': + """ + return the value between min_value and max_value, + if min_value is None, then no lower bound, + if max_value is None, then no upper bound. + """ + return self.clip(min_value, max_value) + + def clone(self) -> 'Quantity': + if isinstance(self.value, jax.Array): + return self.copy() + with allow_python_scalar(): + return type(self)(self.value, unit=self.unit) + + def tree_flatten(self) -> Tuple[jax.Array | numbers.Number, Any]: + """ + Tree flattens the data. + + Returns: + The data and the unit. + """ + return self.value, self.unit + + @classmethod + def tree_unflatten(cls, unit, value) -> 'Quantity': + """ + Tree unflattens the data. + + Args: + unit: The unit. + value: The data. + + Returns: + The Quantity object. + """ + return cls(value, unit=unit) + + def cuda(self, deice=None) -> 'Quantity': + deice = jax.devices('cuda')[0] if deice is None else deice + self.update_value(jax.device_put(self.value, deice)) + return self + + def cpu(self, device=None) -> 'Quantity': + device = jax.devices('cpu')[0] if device is None else device + self.update_value(jax.device_put(self.value, device)) + return self + + # dtype exchanging # + # ---------------- # + + def int(self) -> 'Quantity': + return Quantity(jnp.asarray(self.value, dtype=jnp.int32), unit=self.unit) + + def long(self) -> 'Quantity': + return Quantity(jnp.asarray(self.value, dtype=jnp.int64), unit=self.unit) + + def half(self) -> 'Quantity': + return Quantity(jnp.asarray(self.value, dtype=jnp.float16), unit=self.unit) + + def float(self) -> 'Quantity': + return Quantity(jnp.asarray(self.value, dtype=jnp.float32), unit=self.unit) + + def double(self) -> 'Quantity': + return Quantity(jnp.asarray(self.value, dtype=jnp.float64), unit=self.unit) + + +class Unit(Quantity): + r""" + A physical unit. + + Normally, you do not need to worry about the implementation of + units. They are derived from the `Array` object with + some additional information (name and string representation). + + Basically, a unit is just a number with given dimensions, e.g. + mvolt = 0.001 with the dimensions of voltage. The units module + defines a large number of standard units, and you can also define + your own (see below). + + The unit class also keeps track of various things that were used + to define it so as to generate a nice string representation of it. + See below. + + When creating scaled units, you can use the following prefixes: + + ====== ====== ============== + Factor Name Prefix + ====== ====== ============== + 10^24 yotta Y + 10^21 zetta Z + 10^18 exa E + 10^15 peta P + 10^12 tera T + 10^9 giga G + 10^6 mega M + 10^3 kilo k + 10^2 hecto h + 10^1 deka da + 1 + 10^-1 deci d + 10^-2 centi c + 10^-3 milli m + 10^-6 micro u (\mu in SI) + 10^-9 nano n + 10^-12 pico p + 10^-15 femto f + 10^-18 atto a + 10^-21 zepto z + 10^-24 yocto y + ====== ====== ============== + + **Defining your own** + + It can be useful to define your own units for printing + purposes. So for example, to define the newton metre, you + write + + >>> import brainunit as U + >>> Nm = U.newton * U.metre + + You can then do + + >>> (1*Nm).in_unit(Nm) + '1. N m' + + New "compound units", i.e. units that are composed of other units will be + automatically registered and from then on used for display. For example, + imagine you define total conductance for a membrane, and the total area of + that membrane: + + >>> conductance = 10.*U.nS + >>> area = 20000*U.um**2 + + If you now ask for the conductance density, you will get an "ugly" display + in basic SI dimensions, as Brian does not know of a corresponding unit: + + >>> conductance/area + 0.5 * metre ** -4 * kilogram ** -1 * second ** 3 * amp ** 2 + + By using an appropriate unit once, it will be registered and from then on + used for display when appropriate: + + >>> U.usiemens/U.cm**2 + usiemens / (cmetre ** 2) + >>> conductance/area # same as before, but now Brian knows about uS/cm^2 + 50. * usiemens / (cmetre ** 2) + + Note that user-defined units cannot override the standard units (`volt`, + `second`, etc.) that are predefined by Brian. For example, the unit + ``Nm`` has the dimensions "length²·mass/time²", and therefore the same + dimensions as the standard unit `joule`. The latter will be used for display + purposes: + + >>> 3*U.joule + 3. * joule + >>> 3*Nm + 3. * joule + + """ + __slots__ = ["_value", "_unit", "scale", "_dispname", "_name", "iscompound"] + + __array_priority__ = 1000 + + def __init__( + self, + value, + unit: Dimension = None, + scale: int = 0, + name: str = None, + dispname: str = None, + iscompound: bool = None, + dtype: bst.typing.DTypeLike = None, + ): + if unit is None: + unit = DIMENSIONLESS + if value != 10.0 ** scale: + raise AssertionError(f"Unit value has to be 10**scale (scale={scale}, value={value})") + + # The scale for this unit (as the integer exponent of 10), i.e. + # a scale of 3 means 10^3, for a "k" prefix. + self.scale = scale + if name is None: + if unit is DIMENSIONLESS: + name = "Unit(1)" + else: + name = repr(unit) + # The full name of this unit + self._name = name + # The display name of this unit + if dispname is None: + dispname = name + self._dispname = dispname + # Whether this unit is a combination of other units + self.iscompound = iscompound + + super().__init__(value, dtype=dtype, unit=unit) + + if _automatically_register_units: + register_new_unit(self) + + @staticmethod + def create(unit: Dimension, name: str, dispname: str, scale: int = 0): + """ + Create a new named unit. + + Parameters + ---------- + unit : Dimension + The dimensions of the unit. + name : `str` + The full name of the unit, e.g. ``'volt'`` + dispname : `str` + The display name, e.g. ``'V'`` + scale : int, optional + The scale of this unit as an exponent of 10, e.g. -3 for a unit that + is 1/1000 of the base scale. Defaults to 0 (i.e. a base unit). + + Returns + ------- + u : `Unit` + The new unit. + """ + name = str(name) + dispname = str(dispname) + + u = Unit( + 10.0 ** scale, + unit=unit, + scale=scale, + name=name, + dispname=dispname, + ) + + return u + + @staticmethod + def create_scaled_unit(baseunit, scalefactor): + """ + Create a scaled unit from a base unit. + + Parameters + ---------- + baseunit : `Unit` + The unit of which to create a scaled version, e.g. ``volt``, + ``amp``. + scalefactor : `str` + The scaling factor, e.g. ``"m"`` for mvolt, mamp + + Returns + ------- + u : `Unit` + The new unit. + """ + name = scalefactor + baseunit.name + dispname = scalefactor + baseunit.dispname + scale = _siprefixes[scalefactor] + baseunit.scale + + u = Unit( + 10.0 ** scale, + unit=baseunit.unit, + name=name, + dispname=dispname, + scale=scale, + ) + + return u + + name = property(fget=lambda self: self._name, doc="The name of the unit") + + dispname = property(fget=lambda self: self._dispname, doc="The display name of the unit") + + def __repr__(self): + return self.name + + def __str__(self): + return self.dispname + + def __mul__(self, other): + if isinstance(other, Unit): + name = f"{self.name} * {other.name}" + dispname = f"{self.dispname} * {other.dispname}" + scale = self.scale + other.scale + u = Unit( + 10.0 ** scale, + unit=self.unit * other.unit, + name=name, + dispname=dispname, + iscompound=True, + scale=scale, + ) + return u + else: + return super().__mul__(other) + + def __div__(self, other): + if isinstance(other, Unit): + if self.iscompound: + dispname = f"({self.dispname})" + name = f"({self.name})" + else: + dispname = self.dispname + name = self.name + dispname += "/" + name += " / " + if other.iscompound: + dispname += f"({other.dispname})" + name += f"({other.name})" + else: + dispname += other.dispname + name += other.name + + scale = self.scale - other.scale + u = Unit( + 10.0 ** scale, + unit=self.unit / other.unit, + name=name, + dispname=dispname, + scale=scale, + iscompound=True, + ) + return u + else: + return super().__div__(other) + + def __rdiv__(self, other): + if is_scalar_type(other) and other == 1: + dispname = self.dispname + name = self.name + if self.iscompound: + dispname = f"({self.dispname})" + name = f"({self.name})" + u = Unit( + self.value, + unit=self.unit ** -1, + name=f"1 / {name}", + dispname=f"1 / {dispname}", + scale=-self.scale, + iscompound=True, + ) + return u + else: + return super().__rdiv__(other) + + def __pow__(self, other): + if is_scalar_type(other): + if self.iscompound: + dispname = f"({self.dispname})" + name = f"({self.name})" + else: + dispname = self.dispname + name = self.name + dispname += f"^{str(other)}" + name += f" ** {repr(other)}" + scale = self.scale * other + u = Unit( + 10.0 ** scale, + unit=self.unit ** other, + name=name, + dispname=dispname, + scale=scale, + iscompound=True, + ) # To avoid issues with units like (second ** -1) ** -1 + return u + else: + return super().__pow__(other) + + def __iadd__(self, other): + raise TypeError("Units cannot be modified in-place") + + def __isub__(self, other): + raise TypeError("Units cannot be modified in-place") + + def __imul__(self, other): + raise TypeError("Units cannot be modified in-place") + + def __idiv__(self, other): + raise TypeError("Units cannot be modified in-place") + + def __itruediv__(self, other): + raise TypeError("Units cannot be modified in-place") + + def __ifloordiv__(self, other): + raise TypeError("Units cannot be modified in-place") + + def __imod__(self, other): + raise TypeError("Units cannot be modified in-place") + + def __ipow__(self, other, modulo=None): + raise TypeError("Units cannot be modified in-place") + + def __eq__(self, other): + if isinstance(other, Unit): + return other.unit is self.unit and other.scale == self.scale + else: + return Quantity.__eq__(self, other) + + def __neq__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash((self.unit, self.scale)) + + +class UnitRegistry: + """ + Stores known units for printing in best units. + + All a user needs to do is to use the `register_new_unit` + function. + + Default registries: + + The units module defines three registries, the standard units, + user units, and additional units. Finding best units is done + by first checking standard, then user, then additional. New + user units are added by using the `register_new_unit` function. + + Standard units includes all the basic non-compound unit names + built in to the module, including volt, amp, etc. Additional + units defines some compound units like newton metre (Nm) etc. + + Methods + ------- + add + __getitem__ + """ + + def __init__(self): + self.units = collections.OrderedDict() + self.units_for_dimensions = collections.defaultdict(dict) + + def add(self, u): + """Add a unit to the registry""" + self.units[repr(u)] = u + self.units_for_dimensions[u.unit][float(u)] = u + + def __getitem__(self, x): + """Returns the best unit for array x + + The algorithm is to consider the value: + + m=abs(x/u) + + for all matching units u. We select the unit where this ratio is the + closest to 10 (if it is an array with several values, we select the + unit where the deviations from that are the smallest. More precisely, + the unit that minimizes the sum of (log10(m)-1)**2 over all entries). + """ + matching = self.units_for_dimensions.get(x.unit, {}) + if len(matching) == 0: + raise KeyError("Unit not found in registry.") + + matching_values = jnp.array(list(matching.keys())) + print_opts = jnp.get_printoptions() + edgeitems, threshold = print_opts["edgeitems"], print_opts["threshold"] + if x.size > threshold: + # Only care about optimizing the units for the values that will + # actually be shown later + # The code looks a bit complex, but should return the same numbers + # that are shown by numpy's string conversion + slices = [] + for shape in x.shape: + if shape > 2 * edgeitems: + slices.append((slice(0, edgeitems), slice(-edgeitems, None))) + else: + slices.append((slice(None),)) + x_flat = jnp.hstack( + [jnp.array(x[use_slices].flatten().value) for use_slices in itertools.product(*slices)] + ) + else: + x_flat = jnp.array(x.value).flatten() + floatreps = jnp.tile(jnp.abs(x_flat), (len(matching), 1)).T / matching_values + # ignore zeros, they are well represented in any unit + floatreps = floatreps.at[floatreps == 0].set(jnp.nan) + # floatreps[floatreps == 0] = jnp.nan + if jnp.all(jnp.isnan(floatreps)): + return matching[1.0] # all zeros, use the base unit + + deviations = jnp.nansum((jnp.log10(floatreps) - 1) ** 2, axis=0) + return list(matching.values())[deviations.argmin()] + + +def register_new_unit(u): + """Register a new unit for automatic displaying of arrays + + Parameters + ---------- + u : `Unit` + The unit that should be registered. + + Examples + -------- + >>> from brainunit import * + >>> 2.0*farad/metre**2 + 2. * metre ** -4 * kilogram ** -1 * second ** 4 * amp ** 2 + >>> register_new_unit(pfarad / mmetre**2) + >>> 2.0*farad/metre**2 + 2000000. * pfarad / (mmetre ** 2) + """ + user_unit_register.add(u) + + +#: `UnitRegistry` containing all the standard units (metre, kilogram, um2...) +standard_unit_register = UnitRegistry() + +#: `UnitRegistry` containing additional units (newton*metre, farad / metre, ...) +additional_unit_register = UnitRegistry() + +#: `UnitRegistry` containing all units defined by the user +user_unit_register = UnitRegistry() + + +def get_basic_unit(d): + """ + Find an unscaled unit (e.g. `volt` but not `mvolt`) for a `Dimension`. + + Parameters + ---------- + d : Dimension + The dimension to find a unit for. + + Returns + ------- + u : `Unit` + A registered unscaled `Unit` for the dimensions ``d``, or a new `Unit` + if no unit was found. + """ + for unit_register in [ + standard_unit_register, + user_unit_register, + additional_unit_register, + ]: + if 1.0 in unit_register.units_for_dimensions[d]: + return unit_register.units_for_dimensions[d][1.0] + return Unit(1.0, unit=d) + + +def check_units(**au): + """Decorator to check units of arguments passed to a function + + Examples + -------- + >>> from brainunit import * + >>> @check_units(I=amp, R=ohm, wibble=metre, result=volt) + ... def getvoltage(I, R, **k): + ... return I*R + + You don't have to check the units of every variable in the function, and + you can define what the units should be for variables that aren't + explicitly named in the definition of the function. For example, the code + above checks that the variable wibble should be a length, so writing + + >>> getvoltage(1*amp, 1*ohm, wibble=1) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + DimensionMismatchError: Function "getvoltage" variable "wibble" has wrong dimensions, dimensions were (1) (m) + + fails, but + + >>> getvoltage(1*amp, 1*ohm, wibble=1*metre) + 1. * volt + + passes. String arguments or ``None`` are not checked + + >>> getvoltage(1*amp, 1*ohm, wibble='hello') + 1. * volt + + By using the special name ``result``, you can check the return value of the + function. + + You can also use ``1`` or ``bool`` as a special value to check for a + unitless number or a boolean value, respectively: + + >>> @check_units(value=1, absolute=bool, result=bool) + ... def is_high(value, absolute=False): + ... if absolute: + ... return abs(value) >= 5 + ... else: + ... return value >= 5 + + This will then again raise an error if the argument if not of the expected + type: + + >>> is_high(7) + True + >>> is_high(-7, True) + True + >>> is_high(3, 4) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + TypeError: Function "is_high" expected a boolean value for argument "absolute" but got 4. + + If the return unit depends on the unit of an argument, you can also pass + a function that takes the units of all the arguments as its inputs (in the + order specified in the function header): + + >>> @check_units(result=lambda d: d**2) + ... def square(value): + ... return value**2 + + If several arguments take arbitrary units but they have to be + consistent among each other, you can state the name of another argument as + a string to state that it uses the same unit as that argument. + + >>> @check_units(summand_1=None, summand_2='summand_1') + ... def multiply_sum(multiplicand, summand_1, summand_2): + ... "Calculates multiplicand*(summand_1 + summand_2)" + ... return multiplicand*(summand_1 + summand_2) + >>> multiply_sum(3, 4*mV, 5*mV) + 27. * mvolt + >>> multiply_sum(3*nA, 4*mV, 5*mV) + 27. * pwatt + >>> multiply_sum(3*nA, 4*mV, 5*nA) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + DimensionMismatchError: Function 'multiply_sum' expected the same arguments for arguments 'summand_1', 'summand_2', but argument 'summand_1' has unit V, while argument 'summand_2' has unit A. + + Raises + ------ + + DimensionMismatchError + In case the input arguments or the return value do not have the + expected dimensions. + TypeError + If an input argument or return value was expected to be a boolean but + is not. + + Notes + ----- + This decorator will destroy the signature of the original function, and + replace it with the signature ``(*args, **kwds)``. Other decorators will + do the same thing, and this decorator critically needs to know the signature + of the function it is acting on, so it is important that it is the first + decorator to act on a function. It cannot be used in combination with + another decorator that also needs to know the signature of the function. + + Note that the ``bool`` type is "strict", i.e. it expects a proper + boolean value and does not accept 0 or 1. This is not the case the other + way round, declaring an argument or return value as "1" *does* allow for a + ``True`` or ``False`` value. + """ + + def do_check_units(f): + def new_f(*args, **kwds): + newkeyset = kwds.copy() + arg_names = f.__code__.co_varnames[0: f.__code__.co_argcount] + for n, v in zip(arg_names, args[0: f.__code__.co_argcount]): + if ( + not isinstance(v, (Quantity, str, bool)) + and v is not None + and n in au + ): + try: + # allow e.g. to pass a Python list of values + v = Quantity(v) + except TypeError: + if have_same_unit(au[n], 1): + raise TypeError( + f"Argument {n} is not a unitless value/array." + ) + else: + raise TypeError( + f"Argument '{n}' is not a array, " + "expected a array with dimensions " + f"{au[n]}" + ) + newkeyset[n] = v + + for k in newkeyset: + # string variables are allowed to pass, the presumption is they + # name another variable. None is also allowed, useful for + # default parameters + if ( + k in au + and not isinstance(newkeyset[k], str) + and not newkeyset[k] is None + and not au[k] is None + ): + if au[k] == bool: + if not isinstance(newkeyset[k], bool): + value = newkeyset[k] + error_message = ( + f"Function '{f.__name__}' " + "expected a boolean value " + f"for argument '{k}' but got " + f"'{value}'" + ) + raise TypeError(error_message) + elif isinstance(au[k], str): + if not au[k] in newkeyset: + error_message = ( + f"Function '{f.__name__}' " + "expected its argument to have the " + f"same units as argument '{k}', but " + "there is no argument of that name" + ) + raise TypeError(error_message) + if not have_same_unit(newkeyset[k], newkeyset[au[k]]): + d1 = get_unit(newkeyset[k]) + d2 = get_unit(newkeyset[au[k]]) + error_message = ( + f"Function '{f.__name__}' expected " + f"the argument '{k}' to have the same " + f"units as argument '{au[k]}', but " + f"argument '{k}' has " + f"unit {get_unit_for_display(d1)}, " + f"while argument '{au[k]}' " + f"has unit {get_unit_for_display(d2)}." + ) + raise DimensionMismatchError(error_message) + elif not have_same_unit(newkeyset[k], au[k]): + unit = repr(au[k]) + value = newkeyset[k] + error_message = ( + f"Function '{f.__name__}' " + "expected a array with unit " + f"{unit} for argument '{k}' but got " + f"'{value}'" + ) + raise DimensionMismatchError( + error_message, get_unit(newkeyset[k]) + ) + + result = f(*args, **kwds) + if "result" in au: + if isinstance(au["result"], Callable) and au["result"] != bool: + expected_result = au["result"](*[get_unit(a) for a in args]) + else: + expected_result = au["result"] + if au["result"] == bool: + if not isinstance(result, bool): + error_message = ( + "The return value of function " + f"'{f.__name__}' was expected to be " + "a boolean value, but was of type " + f"{type(result)}" + ) + raise TypeError(error_message) + elif not have_same_unit(result, expected_result): + unit = get_unit_for_display(expected_result) + error_message = ( + "The return value of function " + f"'{f.__name__}' was expected to have " + f"unit {unit} but was " + f"'{result}'" + ) + raise DimensionMismatchError(error_message, get_unit(result)) + return result + + new_f._orig_func = f + new_f.__doc__ = f.__doc__ + new_f.__name__ = f.__name__ + # store the information in the function, necessary when using the + # function in expressions or equations + if hasattr(f, "_orig_arg_names"): + arg_names = f._orig_arg_names + else: + arg_names = f.__code__.co_varnames[: f.__code__.co_argcount] + new_f._arg_names = arg_names + new_f._arg_units = [au.get(name, None) for name in arg_names] + return_unit = au.get("result", None) + if return_unit is None: + new_f._return_unit = None + else: + new_f._return_unit = return_unit + if return_unit == bool: + new_f._returns_bool = True + else: + new_f._returns_bool = False + new_f._orig_arg_names = arg_names + + # copy any annotation attributes + if hasattr(f, "_annotation_attributes"): + for attrname in f._annotation_attributes: + setattr(new_f, attrname, getattr(f, attrname)) + new_f._annotation_attributes = getattr(f, "_annotation_attributes", []) + [ + "_arg_units", + "_arg_names", + "_return_unit", + "_orig_func", + "_returns_bool", + ] + return new_f + + return do_check_units diff --git a/brainunit/_misc.py b/brainunit/_misc.py new file mode 100644 index 0000000..f5b18da --- /dev/null +++ b/brainunit/_misc.py @@ -0,0 +1,38 @@ +# Copyright 2024 BDP Ecosystem Limited. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + + +import brainstate as bst + + +def get_dtype(a): + """ + Get the dtype of a. + """ + if hasattr(a, 'dtype'): + return a.dtype + else: + if isinstance(a, bool): + return bool + elif isinstance(a, int): + return bst.environ.ditype() + elif isinstance(a, float): + return bst.environ.dftype() + elif isinstance(a, complex): + return bst.environ.dctype() + else: + raise TypeError(f'Can not get dtype of {a}.') + + diff --git a/brainunit/_unit_common.py b/brainunit/_unit_common.py new file mode 100644 index 0000000..b7a9476 --- /dev/null +++ b/brainunit/_unit_common.py @@ -0,0 +1,8182 @@ +# Copyright 2024 BDP Ecosystem Limited. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +import itertools + +from ._base import ( + Unit, + additional_unit_register, + get_or_create_dimension, + standard_unit_register, + turn_off_unit_register, + allow_python_scalar +) + +__all__ = [ + "metre", + "meter", + "kilogram", + "second", + "amp", + "ampere", + "kelvin", + "mole", + "mol", + "candle", + "kilogramme", + "gram", + "gramme", + "molar", + "radian", + "steradian", + "hertz", + "newton", + "pascal", + "joule", + "watt", + "coulomb", + "volt", + "farad", + "ohm", + "siemens", + "weber", + "tesla", + "henry", + "lumen", + "lux", + "becquerel", + "gray", + "sievert", + "katal", + "ametre", + "cmetre", + "Zmetre", + "Pmetre", + "dmetre", + "Gmetre", + "fmetre", + "hmetre", + "dametre", + "mmetre", + "nmetre", + "pmetre", + "umetre", + "Tmetre", + "ymetre", + "Emetre", + "zmetre", + "Mmetre", + "kmetre", + "Ymetre", + "ameter", + "cmeter", + "Zmeter", + "Pmeter", + "dmeter", + "Gmeter", + "fmeter", + "hmeter", + "dameter", + "mmeter", + "nmeter", + "pmeter", + "umeter", + "Tmeter", + "ymeter", + "Emeter", + "zmeter", + "Mmeter", + "kmeter", + "Ymeter", + "asecond", + "csecond", + "Zsecond", + "Psecond", + "dsecond", + "Gsecond", + "fsecond", + "hsecond", + "dasecond", + "msecond", + "nsecond", + "psecond", + "usecond", + "Tsecond", + "ysecond", + "Esecond", + "zsecond", + "Msecond", + "ksecond", + "Ysecond", + "aamp", + "camp", + "Zamp", + "Pamp", + "damp", + "Gamp", + "famp", + "hamp", + "daamp", + "mamp", + "namp", + "pamp", + "uamp", + "Tamp", + "yamp", + "Eamp", + "zamp", + "Mamp", + "kamp", + "Yamp", + "aampere", + "campere", + "Zampere", + "Pampere", + "dampere", + "Gampere", + "fampere", + "hampere", + "daampere", + "mampere", + "nampere", + "pampere", + "uampere", + "Tampere", + "yampere", + "Eampere", + "zampere", + "Mampere", + "kampere", + "Yampere", + "amole", + "cmole", + "Zmole", + "Pmole", + "dmole", + "Gmole", + "fmole", + "hmole", + "damole", + "mmole", + "nmole", + "pmole", + "umole", + "Tmole", + "ymole", + "Emole", + "zmole", + "Mmole", + "kmole", + "Ymole", + "amol", + "cmol", + "Zmol", + "Pmol", + "dmol", + "Gmol", + "fmol", + "hmol", + "damol", + "mmol", + "nmol", + "pmol", + "umol", + "Tmol", + "ymol", + "Emol", + "zmol", + "Mmol", + "kmol", + "Ymol", + "acandle", + "ccandle", + "Zcandle", + "Pcandle", + "dcandle", + "Gcandle", + "fcandle", + "hcandle", + "dacandle", + "mcandle", + "ncandle", + "pcandle", + "ucandle", + "Tcandle", + "ycandle", + "Ecandle", + "zcandle", + "Mcandle", + "kcandle", + "Ycandle", + "agram", + "cgram", + "Zgram", + "Pgram", + "dgram", + "Ggram", + "fgram", + "hgram", + "dagram", + "mgram", + "ngram", + "pgram", + "ugram", + "Tgram", + "ygram", + "Egram", + "zgram", + "Mgram", + "kgram", + "Ygram", + "agramme", + "cgramme", + "Zgramme", + "Pgramme", + "dgramme", + "Ggramme", + "fgramme", + "hgramme", + "dagramme", + "mgramme", + "ngramme", + "pgramme", + "ugramme", + "Tgramme", + "ygramme", + "Egramme", + "zgramme", + "Mgramme", + "kgramme", + "Ygramme", + "amolar", + "cmolar", + "Zmolar", + "Pmolar", + "dmolar", + "Gmolar", + "fmolar", + "hmolar", + "damolar", + "mmolar", + "nmolar", + "pmolar", + "umolar", + "Tmolar", + "ymolar", + "Emolar", + "zmolar", + "Mmolar", + "kmolar", + "Ymolar", + "aradian", + "cradian", + "Zradian", + "Pradian", + "dradian", + "Gradian", + "fradian", + "hradian", + "daradian", + "mradian", + "nradian", + "pradian", + "uradian", + "Tradian", + "yradian", + "Eradian", + "zradian", + "Mradian", + "kradian", + "Yradian", + "asteradian", + "csteradian", + "Zsteradian", + "Psteradian", + "dsteradian", + "Gsteradian", + "fsteradian", + "hsteradian", + "dasteradian", + "msteradian", + "nsteradian", + "psteradian", + "usteradian", + "Tsteradian", + "ysteradian", + "Esteradian", + "zsteradian", + "Msteradian", + "ksteradian", + "Ysteradian", + "ahertz", + "chertz", + "Zhertz", + "Phertz", + "dhertz", + "Ghertz", + "fhertz", + "hhertz", + "dahertz", + "mhertz", + "nhertz", + "phertz", + "uhertz", + "Thertz", + "yhertz", + "Ehertz", + "zhertz", + "Mhertz", + "khertz", + "Yhertz", + "anewton", + "cnewton", + "Znewton", + "Pnewton", + "dnewton", + "Gnewton", + "fnewton", + "hnewton", + "danewton", + "mnewton", + "nnewton", + "pnewton", + "unewton", + "Tnewton", + "ynewton", + "Enewton", + "znewton", + "Mnewton", + "knewton", + "Ynewton", + "apascal", + "cpascal", + "Zpascal", + "Ppascal", + "dpascal", + "Gpascal", + "fpascal", + "hpascal", + "dapascal", + "mpascal", + "npascal", + "ppascal", + "upascal", + "Tpascal", + "ypascal", + "Epascal", + "zpascal", + "Mpascal", + "kpascal", + "Ypascal", + "ajoule", + "cjoule", + "Zjoule", + "Pjoule", + "djoule", + "Gjoule", + "fjoule", + "hjoule", + "dajoule", + "mjoule", + "njoule", + "pjoule", + "ujoule", + "Tjoule", + "yjoule", + "Ejoule", + "zjoule", + "Mjoule", + "kjoule", + "Yjoule", + "awatt", + "cwatt", + "Zwatt", + "Pwatt", + "dwatt", + "Gwatt", + "fwatt", + "hwatt", + "dawatt", + "mwatt", + "nwatt", + "pwatt", + "uwatt", + "Twatt", + "ywatt", + "Ewatt", + "zwatt", + "Mwatt", + "kwatt", + "Ywatt", + "acoulomb", + "ccoulomb", + "Zcoulomb", + "Pcoulomb", + "dcoulomb", + "Gcoulomb", + "fcoulomb", + "hcoulomb", + "dacoulomb", + "mcoulomb", + "ncoulomb", + "pcoulomb", + "ucoulomb", + "Tcoulomb", + "ycoulomb", + "Ecoulomb", + "zcoulomb", + "Mcoulomb", + "kcoulomb", + "Ycoulomb", + "avolt", + "cvolt", + "Zvolt", + "Pvolt", + "dvolt", + "Gvolt", + "fvolt", + "hvolt", + "davolt", + "mvolt", + "nvolt", + "pvolt", + "uvolt", + "Tvolt", + "yvolt", + "Evolt", + "zvolt", + "Mvolt", + "kvolt", + "Yvolt", + "afarad", + "cfarad", + "Zfarad", + "Pfarad", + "dfarad", + "Gfarad", + "ffarad", + "hfarad", + "dafarad", + "mfarad", + "nfarad", + "pfarad", + "ufarad", + "Tfarad", + "yfarad", + "Efarad", + "zfarad", + "Mfarad", + "kfarad", + "Yfarad", + "aohm", + "cohm", + "Zohm", + "Pohm", + "dohm", + "Gohm", + "fohm", + "hohm", + "daohm", + "mohm", + "nohm", + "pohm", + "uohm", + "Tohm", + "yohm", + "Eohm", + "zohm", + "Mohm", + "kohm", + "Yohm", + "asiemens", + "csiemens", + "Zsiemens", + "Psiemens", + "dsiemens", + "Gsiemens", + "fsiemens", + "hsiemens", + "dasiemens", + "msiemens", + "nsiemens", + "psiemens", + "usiemens", + "Tsiemens", + "ysiemens", + "Esiemens", + "zsiemens", + "Msiemens", + "ksiemens", + "Ysiemens", + "aweber", + "cweber", + "Zweber", + "Pweber", + "dweber", + "Gweber", + "fweber", + "hweber", + "daweber", + "mweber", + "nweber", + "pweber", + "uweber", + "Tweber", + "yweber", + "Eweber", + "zweber", + "Mweber", + "kweber", + "Yweber", + "atesla", + "ctesla", + "Ztesla", + "Ptesla", + "dtesla", + "Gtesla", + "ftesla", + "htesla", + "datesla", + "mtesla", + "ntesla", + "ptesla", + "utesla", + "Ttesla", + "ytesla", + "Etesla", + "ztesla", + "Mtesla", + "ktesla", + "Ytesla", + "ahenry", + "chenry", + "Zhenry", + "Phenry", + "dhenry", + "Ghenry", + "fhenry", + "hhenry", + "dahenry", + "mhenry", + "nhenry", + "phenry", + "uhenry", + "Thenry", + "yhenry", + "Ehenry", + "zhenry", + "Mhenry", + "khenry", + "Yhenry", + "alumen", + "clumen", + "Zlumen", + "Plumen", + "dlumen", + "Glumen", + "flumen", + "hlumen", + "dalumen", + "mlumen", + "nlumen", + "plumen", + "ulumen", + "Tlumen", + "ylumen", + "Elumen", + "zlumen", + "Mlumen", + "klumen", + "Ylumen", + "alux", + "clux", + "Zlux", + "Plux", + "dlux", + "Glux", + "flux", + "hlux", + "dalux", + "mlux", + "nlux", + "plux", + "ulux", + "Tlux", + "ylux", + "Elux", + "zlux", + "Mlux", + "klux", + "Ylux", + "abecquerel", + "cbecquerel", + "Zbecquerel", + "Pbecquerel", + "dbecquerel", + "Gbecquerel", + "fbecquerel", + "hbecquerel", + "dabecquerel", + "mbecquerel", + "nbecquerel", + "pbecquerel", + "ubecquerel", + "Tbecquerel", + "ybecquerel", + "Ebecquerel", + "zbecquerel", + "Mbecquerel", + "kbecquerel", + "Ybecquerel", + "agray", + "cgray", + "Zgray", + "Pgray", + "dgray", + "Ggray", + "fgray", + "hgray", + "dagray", + "mgray", + "ngray", + "pgray", + "ugray", + "Tgray", + "ygray", + "Egray", + "zgray", + "Mgray", + "kgray", + "Ygray", + "asievert", + "csievert", + "Zsievert", + "Psievert", + "dsievert", + "Gsievert", + "fsievert", + "hsievert", + "dasievert", + "msievert", + "nsievert", + "psievert", + "usievert", + "Tsievert", + "ysievert", + "Esievert", + "zsievert", + "Msievert", + "ksievert", + "Ysievert", + "akatal", + "ckatal", + "Zkatal", + "Pkatal", + "dkatal", + "Gkatal", + "fkatal", + "hkatal", + "dakatal", + "mkatal", + "nkatal", + "pkatal", + "ukatal", + "Tkatal", + "ykatal", + "Ekatal", + "zkatal", + "Mkatal", + "kkatal", + "Ykatal", + "metre2", + "metre3", + "meter2", + "meter3", + "kilogram2", + "kilogram3", + "second2", + "second3", + "amp2", + "amp3", + "ampere2", + "ampere3", + "kelvin2", + "kelvin3", + "mole2", + "mole3", + "mol2", + "mol3", + "candle2", + "candle3", + "kilogramme2", + "kilogramme3", + "gram2", + "gram3", + "gramme2", + "gramme3", + "molar2", + "molar3", + "radian2", + "radian3", + "steradian2", + "steradian3", + "hertz2", + "hertz3", + "newton2", + "newton3", + "pascal2", + "pascal3", + "joule2", + "joule3", + "watt2", + "watt3", + "coulomb2", + "coulomb3", + "volt2", + "volt3", + "farad2", + "farad3", + "ohm2", + "ohm3", + "siemens2", + "siemens3", + "weber2", + "weber3", + "tesla2", + "tesla3", + "henry2", + "henry3", + "lumen2", + "lumen3", + "lux2", + "lux3", + "becquerel2", + "becquerel3", + "gray2", + "gray3", + "sievert2", + "sievert3", + "katal2", + "katal3", + "ametre2", + "ametre3", + "cmetre2", + "cmetre3", + "Zmetre2", + "Zmetre3", + "Pmetre2", + "Pmetre3", + "dmetre2", + "dmetre3", + "Gmetre2", + "Gmetre3", + "fmetre2", + "fmetre3", + "hmetre2", + "hmetre3", + "dametre2", + "dametre3", + "mmetre2", + "mmetre3", + "nmetre2", + "nmetre3", + "pmetre2", + "pmetre3", + "umetre2", + "umetre3", + "Tmetre2", + "Tmetre3", + "ymetre2", + "ymetre3", + "Emetre2", + "Emetre3", + "zmetre2", + "zmetre3", + "Mmetre2", + "Mmetre3", + "kmetre2", + "kmetre3", + "Ymetre2", + "Ymetre3", + "ameter2", + "ameter3", + "cmeter2", + "cmeter3", + "Zmeter2", + "Zmeter3", + "Pmeter2", + "Pmeter3", + "dmeter2", + "dmeter3", + "Gmeter2", + "Gmeter3", + "fmeter2", + "fmeter3", + "hmeter2", + "hmeter3", + "dameter2", + "dameter3", + "mmeter2", + "mmeter3", + "nmeter2", + "nmeter3", + "pmeter2", + "pmeter3", + "umeter2", + "umeter3", + "Tmeter2", + "Tmeter3", + "ymeter2", + "ymeter3", + "Emeter2", + "Emeter3", + "zmeter2", + "zmeter3", + "Mmeter2", + "Mmeter3", + "kmeter2", + "kmeter3", + "Ymeter2", + "Ymeter3", + "asecond2", + "asecond3", + "csecond2", + "csecond3", + "Zsecond2", + "Zsecond3", + "Psecond2", + "Psecond3", + "dsecond2", + "dsecond3", + "Gsecond2", + "Gsecond3", + "fsecond2", + "fsecond3", + "hsecond2", + "hsecond3", + "dasecond2", + "dasecond3", + "msecond2", + "msecond3", + "nsecond2", + "nsecond3", + "psecond2", + "psecond3", + "usecond2", + "usecond3", + "Tsecond2", + "Tsecond3", + "ysecond2", + "ysecond3", + "Esecond2", + "Esecond3", + "zsecond2", + "zsecond3", + "Msecond2", + "Msecond3", + "ksecond2", + "ksecond3", + "Ysecond2", + "Ysecond3", + "aamp2", + "aamp3", + "camp2", + "camp3", + "Zamp2", + "Zamp3", + "Pamp2", + "Pamp3", + "damp2", + "damp3", + "Gamp2", + "Gamp3", + "famp2", + "famp3", + "hamp2", + "hamp3", + "daamp2", + "daamp3", + "mamp2", + "mamp3", + "namp2", + "namp3", + "pamp2", + "pamp3", + "uamp2", + "uamp3", + "Tamp2", + "Tamp3", + "yamp2", + "yamp3", + "Eamp2", + "Eamp3", + "zamp2", + "zamp3", + "Mamp2", + "Mamp3", + "kamp2", + "kamp3", + "Yamp2", + "Yamp3", + "aampere2", + "aampere3", + "campere2", + "campere3", + "Zampere2", + "Zampere3", + "Pampere2", + "Pampere3", + "dampere2", + "dampere3", + "Gampere2", + "Gampere3", + "fampere2", + "fampere3", + "hampere2", + "hampere3", + "daampere2", + "daampere3", + "mampere2", + "mampere3", + "nampere2", + "nampere3", + "pampere2", + "pampere3", + "uampere2", + "uampere3", + "Tampere2", + "Tampere3", + "yampere2", + "yampere3", + "Eampere2", + "Eampere3", + "zampere2", + "zampere3", + "Mampere2", + "Mampere3", + "kampere2", + "kampere3", + "Yampere2", + "Yampere3", + "amole2", + "amole3", + "cmole2", + "cmole3", + "Zmole2", + "Zmole3", + "Pmole2", + "Pmole3", + "dmole2", + "dmole3", + "Gmole2", + "Gmole3", + "fmole2", + "fmole3", + "hmole2", + "hmole3", + "damole2", + "damole3", + "mmole2", + "mmole3", + "nmole2", + "nmole3", + "pmole2", + "pmole3", + "umole2", + "umole3", + "Tmole2", + "Tmole3", + "ymole2", + "ymole3", + "Emole2", + "Emole3", + "zmole2", + "zmole3", + "Mmole2", + "Mmole3", + "kmole2", + "kmole3", + "Ymole2", + "Ymole3", + "amol2", + "amol3", + "cmol2", + "cmol3", + "Zmol2", + "Zmol3", + "Pmol2", + "Pmol3", + "dmol2", + "dmol3", + "Gmol2", + "Gmol3", + "fmol2", + "fmol3", + "hmol2", + "hmol3", + "damol2", + "damol3", + "mmol2", + "mmol3", + "nmol2", + "nmol3", + "pmol2", + "pmol3", + "umol2", + "umol3", + "Tmol2", + "Tmol3", + "ymol2", + "ymol3", + "Emol2", + "Emol3", + "zmol2", + "zmol3", + "Mmol2", + "Mmol3", + "kmol2", + "kmol3", + "Ymol2", + "Ymol3", + "acandle2", + "acandle3", + "ccandle2", + "ccandle3", + "Zcandle2", + "Zcandle3", + "Pcandle2", + "Pcandle3", + "dcandle2", + "dcandle3", + "Gcandle2", + "Gcandle3", + "fcandle2", + "fcandle3", + "hcandle2", + "hcandle3", + "dacandle2", + "dacandle3", + "mcandle2", + "mcandle3", + "ncandle2", + "ncandle3", + "pcandle2", + "pcandle3", + "ucandle2", + "ucandle3", + "Tcandle2", + "Tcandle3", + "ycandle2", + "ycandle3", + "Ecandle2", + "Ecandle3", + "zcandle2", + "zcandle3", + "Mcandle2", + "Mcandle3", + "kcandle2", + "kcandle3", + "Ycandle2", + "Ycandle3", + "agram2", + "agram3", + "cgram2", + "cgram3", + "Zgram2", + "Zgram3", + "Pgram2", + "Pgram3", + "dgram2", + "dgram3", + "Ggram2", + "Ggram3", + "fgram2", + "fgram3", + "hgram2", + "hgram3", + "dagram2", + "dagram3", + "mgram2", + "mgram3", + "ngram2", + "ngram3", + "pgram2", + "pgram3", + "ugram2", + "ugram3", + "Tgram2", + "Tgram3", + "ygram2", + "ygram3", + "Egram2", + "Egram3", + "zgram2", + "zgram3", + "Mgram2", + "Mgram3", + "kgram2", + "kgram3", + "Ygram2", + "Ygram3", + "agramme2", + "agramme3", + "cgramme2", + "cgramme3", + "Zgramme2", + "Zgramme3", + "Pgramme2", + "Pgramme3", + "dgramme2", + "dgramme3", + "Ggramme2", + "Ggramme3", + "fgramme2", + "fgramme3", + "hgramme2", + "hgramme3", + "dagramme2", + "dagramme3", + "mgramme2", + "mgramme3", + "ngramme2", + "ngramme3", + "pgramme2", + "pgramme3", + "ugramme2", + "ugramme3", + "Tgramme2", + "Tgramme3", + "ygramme2", + "ygramme3", + "Egramme2", + "Egramme3", + "zgramme2", + "zgramme3", + "Mgramme2", + "Mgramme3", + "kgramme2", + "kgramme3", + "Ygramme2", + "Ygramme3", + "amolar2", + "amolar3", + "cmolar2", + "cmolar3", + "Zmolar2", + "Zmolar3", + "Pmolar2", + "Pmolar3", + "dmolar2", + "dmolar3", + "Gmolar2", + "Gmolar3", + "fmolar2", + "fmolar3", + "hmolar2", + "hmolar3", + "damolar2", + "damolar3", + "mmolar2", + "mmolar3", + "nmolar2", + "nmolar3", + "pmolar2", + "pmolar3", + "umolar2", + "umolar3", + "Tmolar2", + "Tmolar3", + "ymolar2", + "ymolar3", + "Emolar2", + "Emolar3", + "zmolar2", + "zmolar3", + "Mmolar2", + "Mmolar3", + "kmolar2", + "kmolar3", + "Ymolar2", + "Ymolar3", + "aradian2", + "aradian3", + "cradian2", + "cradian3", + "Zradian2", + "Zradian3", + "Pradian2", + "Pradian3", + "dradian2", + "dradian3", + "Gradian2", + "Gradian3", + "fradian2", + "fradian3", + "hradian2", + "hradian3", + "daradian2", + "daradian3", + "mradian2", + "mradian3", + "nradian2", + "nradian3", + "pradian2", + "pradian3", + "uradian2", + "uradian3", + "Tradian2", + "Tradian3", + "yradian2", + "yradian3", + "Eradian2", + "Eradian3", + "zradian2", + "zradian3", + "Mradian2", + "Mradian3", + "kradian2", + "kradian3", + "Yradian2", + "Yradian3", + "asteradian2", + "asteradian3", + "csteradian2", + "csteradian3", + "Zsteradian2", + "Zsteradian3", + "Psteradian2", + "Psteradian3", + "dsteradian2", + "dsteradian3", + "Gsteradian2", + "Gsteradian3", + "fsteradian2", + "fsteradian3", + "hsteradian2", + "hsteradian3", + "dasteradian2", + "dasteradian3", + "msteradian2", + "msteradian3", + "nsteradian2", + "nsteradian3", + "psteradian2", + "psteradian3", + "usteradian2", + "usteradian3", + "Tsteradian2", + "Tsteradian3", + "ysteradian2", + "ysteradian3", + "Esteradian2", + "Esteradian3", + "zsteradian2", + "zsteradian3", + "Msteradian2", + "Msteradian3", + "ksteradian2", + "ksteradian3", + "Ysteradian2", + "Ysteradian3", + "ahertz2", + "ahertz3", + "chertz2", + "chertz3", + "Zhertz2", + "Zhertz3", + "Phertz2", + "Phertz3", + "dhertz2", + "dhertz3", + "Ghertz2", + "Ghertz3", + "fhertz2", + "fhertz3", + "hhertz2", + "hhertz3", + "dahertz2", + "dahertz3", + "mhertz2", + "mhertz3", + "nhertz2", + "nhertz3", + "phertz2", + "phertz3", + "uhertz2", + "uhertz3", + "Thertz2", + "Thertz3", + "yhertz2", + "yhertz3", + "Ehertz2", + "Ehertz3", + "zhertz2", + "zhertz3", + "Mhertz2", + "Mhertz3", + "khertz2", + "khertz3", + "Yhertz2", + "Yhertz3", + "anewton2", + "anewton3", + "cnewton2", + "cnewton3", + "Znewton2", + "Znewton3", + "Pnewton2", + "Pnewton3", + "dnewton2", + "dnewton3", + "Gnewton2", + "Gnewton3", + "fnewton2", + "fnewton3", + "hnewton2", + "hnewton3", + "danewton2", + "danewton3", + "mnewton2", + "mnewton3", + "nnewton2", + "nnewton3", + "pnewton2", + "pnewton3", + "unewton2", + "unewton3", + "Tnewton2", + "Tnewton3", + "ynewton2", + "ynewton3", + "Enewton2", + "Enewton3", + "znewton2", + "znewton3", + "Mnewton2", + "Mnewton3", + "knewton2", + "knewton3", + "Ynewton2", + "Ynewton3", + "apascal2", + "apascal3", + "cpascal2", + "cpascal3", + "Zpascal2", + "Zpascal3", + "Ppascal2", + "Ppascal3", + "dpascal2", + "dpascal3", + "Gpascal2", + "Gpascal3", + "fpascal2", + "fpascal3", + "hpascal2", + "hpascal3", + "dapascal2", + "dapascal3", + "mpascal2", + "mpascal3", + "npascal2", + "npascal3", + "ppascal2", + "ppascal3", + "upascal2", + "upascal3", + "Tpascal2", + "Tpascal3", + "ypascal2", + "ypascal3", + "Epascal2", + "Epascal3", + "zpascal2", + "zpascal3", + "Mpascal2", + "Mpascal3", + "kpascal2", + "kpascal3", + "Ypascal2", + "Ypascal3", + "ajoule2", + "ajoule3", + "cjoule2", + "cjoule3", + "Zjoule2", + "Zjoule3", + "Pjoule2", + "Pjoule3", + "djoule2", + "djoule3", + "Gjoule2", + "Gjoule3", + "fjoule2", + "fjoule3", + "hjoule2", + "hjoule3", + "dajoule2", + "dajoule3", + "mjoule2", + "mjoule3", + "njoule2", + "njoule3", + "pjoule2", + "pjoule3", + "ujoule2", + "ujoule3", + "Tjoule2", + "Tjoule3", + "yjoule2", + "yjoule3", + "Ejoule2", + "Ejoule3", + "zjoule2", + "zjoule3", + "Mjoule2", + "Mjoule3", + "kjoule2", + "kjoule3", + "Yjoule2", + "Yjoule3", + "awatt2", + "awatt3", + "cwatt2", + "cwatt3", + "Zwatt2", + "Zwatt3", + "Pwatt2", + "Pwatt3", + "dwatt2", + "dwatt3", + "Gwatt2", + "Gwatt3", + "fwatt2", + "fwatt3", + "hwatt2", + "hwatt3", + "dawatt2", + "dawatt3", + "mwatt2", + "mwatt3", + "nwatt2", + "nwatt3", + "pwatt2", + "pwatt3", + "uwatt2", + "uwatt3", + "Twatt2", + "Twatt3", + "ywatt2", + "ywatt3", + "Ewatt2", + "Ewatt3", + "zwatt2", + "zwatt3", + "Mwatt2", + "Mwatt3", + "kwatt2", + "kwatt3", + "Ywatt2", + "Ywatt3", + "acoulomb2", + "acoulomb3", + "ccoulomb2", + "ccoulomb3", + "Zcoulomb2", + "Zcoulomb3", + "Pcoulomb2", + "Pcoulomb3", + "dcoulomb2", + "dcoulomb3", + "Gcoulomb2", + "Gcoulomb3", + "fcoulomb2", + "fcoulomb3", + "hcoulomb2", + "hcoulomb3", + "dacoulomb2", + "dacoulomb3", + "mcoulomb2", + "mcoulomb3", + "ncoulomb2", + "ncoulomb3", + "pcoulomb2", + "pcoulomb3", + "ucoulomb2", + "ucoulomb3", + "Tcoulomb2", + "Tcoulomb3", + "ycoulomb2", + "ycoulomb3", + "Ecoulomb2", + "Ecoulomb3", + "zcoulomb2", + "zcoulomb3", + "Mcoulomb2", + "Mcoulomb3", + "kcoulomb2", + "kcoulomb3", + "Ycoulomb2", + "Ycoulomb3", + "avolt2", + "avolt3", + "cvolt2", + "cvolt3", + "Zvolt2", + "Zvolt3", + "Pvolt2", + "Pvolt3", + "dvolt2", + "dvolt3", + "Gvolt2", + "Gvolt3", + "fvolt2", + "fvolt3", + "hvolt2", + "hvolt3", + "davolt2", + "davolt3", + "mvolt2", + "mvolt3", + "nvolt2", + "nvolt3", + "pvolt2", + "pvolt3", + "uvolt2", + "uvolt3", + "Tvolt2", + "Tvolt3", + "yvolt2", + "yvolt3", + "Evolt2", + "Evolt3", + "zvolt2", + "zvolt3", + "Mvolt2", + "Mvolt3", + "kvolt2", + "kvolt3", + "Yvolt2", + "Yvolt3", + "afarad2", + "afarad3", + "cfarad2", + "cfarad3", + "Zfarad2", + "Zfarad3", + "Pfarad2", + "Pfarad3", + "dfarad2", + "dfarad3", + "Gfarad2", + "Gfarad3", + "ffarad2", + "ffarad3", + "hfarad2", + "hfarad3", + "dafarad2", + "dafarad3", + "mfarad2", + "mfarad3", + "nfarad2", + "nfarad3", + "pfarad2", + "pfarad3", + "ufarad2", + "ufarad3", + "Tfarad2", + "Tfarad3", + "yfarad2", + "yfarad3", + "Efarad2", + "Efarad3", + "zfarad2", + "zfarad3", + "Mfarad2", + "Mfarad3", + "kfarad2", + "kfarad3", + "Yfarad2", + "Yfarad3", + "aohm2", + "aohm3", + "cohm2", + "cohm3", + "Zohm2", + "Zohm3", + "Pohm2", + "Pohm3", + "dohm2", + "dohm3", + "Gohm2", + "Gohm3", + "fohm2", + "fohm3", + "hohm2", + "hohm3", + "daohm2", + "daohm3", + "mohm2", + "mohm3", + "nohm2", + "nohm3", + "pohm2", + "pohm3", + "uohm2", + "uohm3", + "Tohm2", + "Tohm3", + "yohm2", + "yohm3", + "Eohm2", + "Eohm3", + "zohm2", + "zohm3", + "Mohm2", + "Mohm3", + "kohm2", + "kohm3", + "Yohm2", + "Yohm3", + "asiemens2", + "asiemens3", + "csiemens2", + "csiemens3", + "Zsiemens2", + "Zsiemens3", + "Psiemens2", + "Psiemens3", + "dsiemens2", + "dsiemens3", + "Gsiemens2", + "Gsiemens3", + "fsiemens2", + "fsiemens3", + "hsiemens2", + "hsiemens3", + "dasiemens2", + "dasiemens3", + "msiemens2", + "msiemens3", + "nsiemens2", + "nsiemens3", + "psiemens2", + "psiemens3", + "usiemens2", + "usiemens3", + "Tsiemens2", + "Tsiemens3", + "ysiemens2", + "ysiemens3", + "Esiemens2", + "Esiemens3", + "zsiemens2", + "zsiemens3", + "Msiemens2", + "Msiemens3", + "ksiemens2", + "ksiemens3", + "Ysiemens2", + "Ysiemens3", + "aweber2", + "aweber3", + "cweber2", + "cweber3", + "Zweber2", + "Zweber3", + "Pweber2", + "Pweber3", + "dweber2", + "dweber3", + "Gweber2", + "Gweber3", + "fweber2", + "fweber3", + "hweber2", + "hweber3", + "daweber2", + "daweber3", + "mweber2", + "mweber3", + "nweber2", + "nweber3", + "pweber2", + "pweber3", + "uweber2", + "uweber3", + "Tweber2", + "Tweber3", + "yweber2", + "yweber3", + "Eweber2", + "Eweber3", + "zweber2", + "zweber3", + "Mweber2", + "Mweber3", + "kweber2", + "kweber3", + "Yweber2", + "Yweber3", + "atesla2", + "atesla3", + "ctesla2", + "ctesla3", + "Ztesla2", + "Ztesla3", + "Ptesla2", + "Ptesla3", + "dtesla2", + "dtesla3", + "Gtesla2", + "Gtesla3", + "ftesla2", + "ftesla3", + "htesla2", + "htesla3", + "datesla2", + "datesla3", + "mtesla2", + "mtesla3", + "ntesla2", + "ntesla3", + "ptesla2", + "ptesla3", + "utesla2", + "utesla3", + "Ttesla2", + "Ttesla3", + "ytesla2", + "ytesla3", + "Etesla2", + "Etesla3", + "ztesla2", + "ztesla3", + "Mtesla2", + "Mtesla3", + "ktesla2", + "ktesla3", + "Ytesla2", + "Ytesla3", + "ahenry2", + "ahenry3", + "chenry2", + "chenry3", + "Zhenry2", + "Zhenry3", + "Phenry2", + "Phenry3", + "dhenry2", + "dhenry3", + "Ghenry2", + "Ghenry3", + "fhenry2", + "fhenry3", + "hhenry2", + "hhenry3", + "dahenry2", + "dahenry3", + "mhenry2", + "mhenry3", + "nhenry2", + "nhenry3", + "phenry2", + "phenry3", + "uhenry2", + "uhenry3", + "Thenry2", + "Thenry3", + "yhenry2", + "yhenry3", + "Ehenry2", + "Ehenry3", + "zhenry2", + "zhenry3", + "Mhenry2", + "Mhenry3", + "khenry2", + "khenry3", + "Yhenry2", + "Yhenry3", + "alumen2", + "alumen3", + "clumen2", + "clumen3", + "Zlumen2", + "Zlumen3", + "Plumen2", + "Plumen3", + "dlumen2", + "dlumen3", + "Glumen2", + "Glumen3", + "flumen2", + "flumen3", + "hlumen2", + "hlumen3", + "dalumen2", + "dalumen3", + "mlumen2", + "mlumen3", + "nlumen2", + "nlumen3", + "plumen2", + "plumen3", + "ulumen2", + "ulumen3", + "Tlumen2", + "Tlumen3", + "ylumen2", + "ylumen3", + "Elumen2", + "Elumen3", + "zlumen2", + "zlumen3", + "Mlumen2", + "Mlumen3", + "klumen2", + "klumen3", + "Ylumen2", + "Ylumen3", + "alux2", + "alux3", + "clux2", + "clux3", + "Zlux2", + "Zlux3", + "Plux2", + "Plux3", + "dlux2", + "dlux3", + "Glux2", + "Glux3", + "flux2", + "flux3", + "hlux2", + "hlux3", + "dalux2", + "dalux3", + "mlux2", + "mlux3", + "nlux2", + "nlux3", + "plux2", + "plux3", + "ulux2", + "ulux3", + "Tlux2", + "Tlux3", + "ylux2", + "ylux3", + "Elux2", + "Elux3", + "zlux2", + "zlux3", + "Mlux2", + "Mlux3", + "klux2", + "klux3", + "Ylux2", + "Ylux3", + "abecquerel2", + "abecquerel3", + "cbecquerel2", + "cbecquerel3", + "Zbecquerel2", + "Zbecquerel3", + "Pbecquerel2", + "Pbecquerel3", + "dbecquerel2", + "dbecquerel3", + "Gbecquerel2", + "Gbecquerel3", + "fbecquerel2", + "fbecquerel3", + "hbecquerel2", + "hbecquerel3", + "dabecquerel2", + "dabecquerel3", + "mbecquerel2", + "mbecquerel3", + "nbecquerel2", + "nbecquerel3", + "pbecquerel2", + "pbecquerel3", + "ubecquerel2", + "ubecquerel3", + "Tbecquerel2", + "Tbecquerel3", + "ybecquerel2", + "ybecquerel3", + "Ebecquerel2", + "Ebecquerel3", + "zbecquerel2", + "zbecquerel3", + "Mbecquerel2", + "Mbecquerel3", + "kbecquerel2", + "kbecquerel3", + "Ybecquerel2", + "Ybecquerel3", + "agray2", + "agray3", + "cgray2", + "cgray3", + "Zgray2", + "Zgray3", + "Pgray2", + "Pgray3", + "dgray2", + "dgray3", + "Ggray2", + "Ggray3", + "fgray2", + "fgray3", + "hgray2", + "hgray3", + "dagray2", + "dagray3", + "mgray2", + "mgray3", + "ngray2", + "ngray3", + "pgray2", + "pgray3", + "ugray2", + "ugray3", + "Tgray2", + "Tgray3", + "ygray2", + "ygray3", + "Egray2", + "Egray3", + "zgray2", + "zgray3", + "Mgray2", + "Mgray3", + "kgray2", + "kgray3", + "Ygray2", + "Ygray3", + "asievert2", + "asievert3", + "csievert2", + "csievert3", + "Zsievert2", + "Zsievert3", + "Psievert2", + "Psievert3", + "dsievert2", + "dsievert3", + "Gsievert2", + "Gsievert3", + "fsievert2", + "fsievert3", + "hsievert2", + "hsievert3", + "dasievert2", + "dasievert3", + "msievert2", + "msievert3", + "nsievert2", + "nsievert3", + "psievert2", + "psievert3", + "usievert2", + "usievert3", + "Tsievert2", + "Tsievert3", + "ysievert2", + "ysievert3", + "Esievert2", + "Esievert3", + "zsievert2", + "zsievert3", + "Msievert2", + "Msievert3", + "ksievert2", + "ksievert3", + "Ysievert2", + "Ysievert3", + "akatal2", + "akatal3", + "ckatal2", + "ckatal3", + "Zkatal2", + "Zkatal3", + "Pkatal2", + "Pkatal3", + "dkatal2", + "dkatal3", + "Gkatal2", + "Gkatal3", + "fkatal2", + "fkatal3", + "hkatal2", + "hkatal3", + "dakatal2", + "dakatal3", + "mkatal2", + "mkatal3", + "nkatal2", + "nkatal3", + "pkatal2", + "pkatal3", + "ukatal2", + "ukatal3", + "Tkatal2", + "Tkatal3", + "ykatal2", + "ykatal3", + "Ekatal2", + "Ekatal3", + "zkatal2", + "zkatal3", + "Mkatal2", + "Mkatal3", + "kkatal2", + "kkatal3", + "Ykatal2", + "Ykatal3", + "liter", + "aliter", + "liter", + "cliter", + "Zliter", + "Pliter", + "dliter", + "Gliter", + "fliter", + "hliter", + "daliter", + "mliter", + "nliter", + "pliter", + "uliter", + "Tliter", + "yliter", + "Eliter", + "zliter", + "Mliter", + "kliter", + "Yliter", + "litre", + "alitre", + "litre", + "clitre", + "Zlitre", + "Plitre", + "dlitre", + "Glitre", + "flitre", + "hlitre", + "dalitre", + "mlitre", + "nlitre", + "plitre", + "ulitre", + "Tlitre", + "ylitre", + "Elitre", + "zlitre", + "Mlitre", + "klitre", + "Ylitre", + "celsius" # Dummy object raising an error +] + +with turn_off_unit_register(), allow_python_scalar(): + #### FUNDAMENTAL UNITS + metre = Unit.create(get_or_create_dimension(m=1), "metre", "m") + meter = Unit.create(get_or_create_dimension(m=1), "meter", "m") + # Liter has a scale of 10^-3, since 1 l = 1 dm^3 = 10^-3 m^3 + liter = Unit.create(unit=(meter ** 3).unit, name="liter", dispname="l", scale=-3) + litre = Unit.create(unit=(meter ** 3).unit, name="litre", dispname="l", scale=-3) + kilogram = Unit.create(get_or_create_dimension(kg=1), "kilogram", "kg") + kilogramme = Unit.create(get_or_create_dimension(kg=1), "kilogramme", "kg") + gram = Unit.create(unit=kilogram.unit, name="gram", dispname="g", scale=-3) + gramme = Unit.create(unit=kilogram.unit, name="gramme", dispname="g", scale=-3) + second = Unit.create(get_or_create_dimension(s=1), "second", "s") + amp = Unit.create(get_or_create_dimension(A=1), "amp", "A") + ampere = Unit.create(get_or_create_dimension(A=1), "ampere", "A") + kelvin = Unit.create(get_or_create_dimension(K=1), "kelvin", "K") + mole = Unit.create(get_or_create_dimension(mol=1), "mole", "mol") + mol = Unit.create(get_or_create_dimension(mol=1), "mol", "mol") + # Molar has a scale of 10^3, since 1 M = 1 mol/l = 1000 mol/m^3 + molar = Unit.create((mole / liter).unit, name="molar", dispname="M", scale=3) + candle = Unit.create(get_or_create_dimension(candle=1), "candle", "cd") + fundamental_units = [metre, meter, gram, second, amp, kelvin, mole, candle] + + radian = Unit.create(get_or_create_dimension(), "radian", "rad") + steradian = Unit.create(get_or_create_dimension(), "steradian", "sr") + hertz = Unit.create(get_or_create_dimension(s=-1), "hertz", "Hz") + newton = Unit.create(get_or_create_dimension(m=1, kg=1, s=-2), "newton", "N") + pascal = Unit.create(get_or_create_dimension(m=-1, kg=1, s=-2), "pascal", "Pa") + joule = Unit.create(get_or_create_dimension(m=2, kg=1, s=-2), "joule", "J") + watt = Unit.create(get_or_create_dimension(m=2, kg=1, s=-3), "watt", "W") + coulomb = Unit.create(get_or_create_dimension(s=1, A=1), "coulomb", "C") + volt = Unit.create(get_or_create_dimension(m=2, kg=1, s=-3, A=-1), "volt", "V") + farad = Unit.create(get_or_create_dimension(m=-2, kg=-1, s=4, A=2), "farad", "F") + ohm = Unit.create(get_or_create_dimension(m=2, kg=1, s=-3, A=-2), "ohm", "ohm") + siemens = Unit.create(get_or_create_dimension(m=-2, kg=-1, s=3, A=2), "siemens", "S") + weber = Unit.create(get_or_create_dimension(m=2, kg=1, s=-2, A=-1), "weber", "Wb") + tesla = Unit.create(get_or_create_dimension(kg=1, s=-2, A=-1), "tesla", "T") + henry = Unit.create(get_or_create_dimension(m=2, kg=1, s=-2, A=-2), "henry", "H") + lumen = Unit.create(get_or_create_dimension(cd=1), "lumen", "lm") + lux = Unit.create(get_or_create_dimension(m=-2, cd=1), "lux", "lx") + becquerel = Unit.create(get_or_create_dimension(s=-1), "becquerel", "Bq") + gray = Unit.create(get_or_create_dimension(m=2, s=-2), "gray", "Gy") + sievert = Unit.create(get_or_create_dimension(m=2, s=-2), "sievert", "Sv") + katal = Unit.create(get_or_create_dimension(s=-1, mol=1), "katal", "kat") + + ######### SCALED BASE UNITS ########### + ametre = Unit.create_scaled_unit(metre, "a") + cmetre = Unit.create_scaled_unit(metre, "c") + Zmetre = Unit.create_scaled_unit(metre, "Z") + Pmetre = Unit.create_scaled_unit(metre, "P") + dmetre = Unit.create_scaled_unit(metre, "d") + Gmetre = Unit.create_scaled_unit(metre, "G") + fmetre = Unit.create_scaled_unit(metre, "f") + hmetre = Unit.create_scaled_unit(metre, "h") + dametre = Unit.create_scaled_unit(metre, "da") + mmetre = Unit.create_scaled_unit(metre, "m") + nmetre = Unit.create_scaled_unit(metre, "n") + pmetre = Unit.create_scaled_unit(metre, "p") + umetre = Unit.create_scaled_unit(metre, "u") + Tmetre = Unit.create_scaled_unit(metre, "T") + ymetre = Unit.create_scaled_unit(metre, "y") + Emetre = Unit.create_scaled_unit(metre, "E") + zmetre = Unit.create_scaled_unit(metre, "z") + Mmetre = Unit.create_scaled_unit(metre, "M") + kmetre = Unit.create_scaled_unit(metre, "k") + Ymetre = Unit.create_scaled_unit(metre, "Y") + ameter = Unit.create_scaled_unit(meter, "a") + cmeter = Unit.create_scaled_unit(meter, "c") + Zmeter = Unit.create_scaled_unit(meter, "Z") + Pmeter = Unit.create_scaled_unit(meter, "P") + dmeter = Unit.create_scaled_unit(meter, "d") + Gmeter = Unit.create_scaled_unit(meter, "G") + fmeter = Unit.create_scaled_unit(meter, "f") + hmeter = Unit.create_scaled_unit(meter, "h") + dameter = Unit.create_scaled_unit(meter, "da") + mmeter = Unit.create_scaled_unit(meter, "m") + nmeter = Unit.create_scaled_unit(meter, "n") + pmeter = Unit.create_scaled_unit(meter, "p") + umeter = Unit.create_scaled_unit(meter, "u") + Tmeter = Unit.create_scaled_unit(meter, "T") + ymeter = Unit.create_scaled_unit(meter, "y") + Emeter = Unit.create_scaled_unit(meter, "E") + zmeter = Unit.create_scaled_unit(meter, "z") + Mmeter = Unit.create_scaled_unit(meter, "M") + kmeter = Unit.create_scaled_unit(meter, "k") + Ymeter = Unit.create_scaled_unit(meter, "Y") + asecond = Unit.create_scaled_unit(second, "a") + csecond = Unit.create_scaled_unit(second, "c") + Zsecond = Unit.create_scaled_unit(second, "Z") + Psecond = Unit.create_scaled_unit(second, "P") + dsecond = Unit.create_scaled_unit(second, "d") + Gsecond = Unit.create_scaled_unit(second, "G") + fsecond = Unit.create_scaled_unit(second, "f") + hsecond = Unit.create_scaled_unit(second, "h") + dasecond = Unit.create_scaled_unit(second, "da") + msecond = Unit.create_scaled_unit(second, "m") + nsecond = Unit.create_scaled_unit(second, "n") + psecond = Unit.create_scaled_unit(second, "p") + usecond = Unit.create_scaled_unit(second, "u") + Tsecond = Unit.create_scaled_unit(second, "T") + ysecond = Unit.create_scaled_unit(second, "y") + Esecond = Unit.create_scaled_unit(second, "E") + zsecond = Unit.create_scaled_unit(second, "z") + Msecond = Unit.create_scaled_unit(second, "M") + ksecond = Unit.create_scaled_unit(second, "k") + Ysecond = Unit.create_scaled_unit(second, "Y") + aamp = Unit.create_scaled_unit(amp, "a") + camp = Unit.create_scaled_unit(amp, "c") + Zamp = Unit.create_scaled_unit(amp, "Z") + Pamp = Unit.create_scaled_unit(amp, "P") + damp = Unit.create_scaled_unit(amp, "d") + Gamp = Unit.create_scaled_unit(amp, "G") + famp = Unit.create_scaled_unit(amp, "f") + hamp = Unit.create_scaled_unit(amp, "h") + daamp = Unit.create_scaled_unit(amp, "da") + mamp = Unit.create_scaled_unit(amp, "m") + namp = Unit.create_scaled_unit(amp, "n") + pamp = Unit.create_scaled_unit(amp, "p") + uamp = Unit.create_scaled_unit(amp, "u") + Tamp = Unit.create_scaled_unit(amp, "T") + yamp = Unit.create_scaled_unit(amp, "y") + Eamp = Unit.create_scaled_unit(amp, "E") + zamp = Unit.create_scaled_unit(amp, "z") + Mamp = Unit.create_scaled_unit(amp, "M") + kamp = Unit.create_scaled_unit(amp, "k") + Yamp = Unit.create_scaled_unit(amp, "Y") + aampere = Unit.create_scaled_unit(ampere, "a") + campere = Unit.create_scaled_unit(ampere, "c") + Zampere = Unit.create_scaled_unit(ampere, "Z") + Pampere = Unit.create_scaled_unit(ampere, "P") + dampere = Unit.create_scaled_unit(ampere, "d") + Gampere = Unit.create_scaled_unit(ampere, "G") + fampere = Unit.create_scaled_unit(ampere, "f") + hampere = Unit.create_scaled_unit(ampere, "h") + daampere = Unit.create_scaled_unit(ampere, "da") + mampere = Unit.create_scaled_unit(ampere, "m") + nampere = Unit.create_scaled_unit(ampere, "n") + pampere = Unit.create_scaled_unit(ampere, "p") + uampere = Unit.create_scaled_unit(ampere, "u") + Tampere = Unit.create_scaled_unit(ampere, "T") + yampere = Unit.create_scaled_unit(ampere, "y") + Eampere = Unit.create_scaled_unit(ampere, "E") + zampere = Unit.create_scaled_unit(ampere, "z") + Mampere = Unit.create_scaled_unit(ampere, "M") + kampere = Unit.create_scaled_unit(ampere, "k") + Yampere = Unit.create_scaled_unit(ampere, "Y") + amole = Unit.create_scaled_unit(mole, "a") + cmole = Unit.create_scaled_unit(mole, "c") + Zmole = Unit.create_scaled_unit(mole, "Z") + Pmole = Unit.create_scaled_unit(mole, "P") + dmole = Unit.create_scaled_unit(mole, "d") + Gmole = Unit.create_scaled_unit(mole, "G") + fmole = Unit.create_scaled_unit(mole, "f") + hmole = Unit.create_scaled_unit(mole, "h") + damole = Unit.create_scaled_unit(mole, "da") + mmole = Unit.create_scaled_unit(mole, "m") + nmole = Unit.create_scaled_unit(mole, "n") + pmole = Unit.create_scaled_unit(mole, "p") + umole = Unit.create_scaled_unit(mole, "u") + Tmole = Unit.create_scaled_unit(mole, "T") + ymole = Unit.create_scaled_unit(mole, "y") + Emole = Unit.create_scaled_unit(mole, "E") + zmole = Unit.create_scaled_unit(mole, "z") + Mmole = Unit.create_scaled_unit(mole, "M") + kmole = Unit.create_scaled_unit(mole, "k") + Ymole = Unit.create_scaled_unit(mole, "Y") + amol = Unit.create_scaled_unit(mol, "a") + cmol = Unit.create_scaled_unit(mol, "c") + Zmol = Unit.create_scaled_unit(mol, "Z") + Pmol = Unit.create_scaled_unit(mol, "P") + dmol = Unit.create_scaled_unit(mol, "d") + Gmol = Unit.create_scaled_unit(mol, "G") + fmol = Unit.create_scaled_unit(mol, "f") + hmol = Unit.create_scaled_unit(mol, "h") + damol = Unit.create_scaled_unit(mol, "da") + mmol = Unit.create_scaled_unit(mol, "m") + nmol = Unit.create_scaled_unit(mol, "n") + pmol = Unit.create_scaled_unit(mol, "p") + umol = Unit.create_scaled_unit(mol, "u") + Tmol = Unit.create_scaled_unit(mol, "T") + ymol = Unit.create_scaled_unit(mol, "y") + Emol = Unit.create_scaled_unit(mol, "E") + zmol = Unit.create_scaled_unit(mol, "z") + Mmol = Unit.create_scaled_unit(mol, "M") + kmol = Unit.create_scaled_unit(mol, "k") + Ymol = Unit.create_scaled_unit(mol, "Y") + acandle = Unit.create_scaled_unit(candle, "a") + ccandle = Unit.create_scaled_unit(candle, "c") + Zcandle = Unit.create_scaled_unit(candle, "Z") + Pcandle = Unit.create_scaled_unit(candle, "P") + dcandle = Unit.create_scaled_unit(candle, "d") + Gcandle = Unit.create_scaled_unit(candle, "G") + fcandle = Unit.create_scaled_unit(candle, "f") + hcandle = Unit.create_scaled_unit(candle, "h") + dacandle = Unit.create_scaled_unit(candle, "da") + mcandle = Unit.create_scaled_unit(candle, "m") + ncandle = Unit.create_scaled_unit(candle, "n") + pcandle = Unit.create_scaled_unit(candle, "p") + ucandle = Unit.create_scaled_unit(candle, "u") + Tcandle = Unit.create_scaled_unit(candle, "T") + ycandle = Unit.create_scaled_unit(candle, "y") + Ecandle = Unit.create_scaled_unit(candle, "E") + zcandle = Unit.create_scaled_unit(candle, "z") + Mcandle = Unit.create_scaled_unit(candle, "M") + kcandle = Unit.create_scaled_unit(candle, "k") + Ycandle = Unit.create_scaled_unit(candle, "Y") + agram = Unit.create_scaled_unit(gram, "a") + cgram = Unit.create_scaled_unit(gram, "c") + Zgram = Unit.create_scaled_unit(gram, "Z") + Pgram = Unit.create_scaled_unit(gram, "P") + dgram = Unit.create_scaled_unit(gram, "d") + Ggram = Unit.create_scaled_unit(gram, "G") + fgram = Unit.create_scaled_unit(gram, "f") + hgram = Unit.create_scaled_unit(gram, "h") + dagram = Unit.create_scaled_unit(gram, "da") + mgram = Unit.create_scaled_unit(gram, "m") + ngram = Unit.create_scaled_unit(gram, "n") + pgram = Unit.create_scaled_unit(gram, "p") + ugram = Unit.create_scaled_unit(gram, "u") + Tgram = Unit.create_scaled_unit(gram, "T") + ygram = Unit.create_scaled_unit(gram, "y") + Egram = Unit.create_scaled_unit(gram, "E") + zgram = Unit.create_scaled_unit(gram, "z") + Mgram = Unit.create_scaled_unit(gram, "M") + kgram = Unit.create_scaled_unit(gram, "k") + Ygram = Unit.create_scaled_unit(gram, "Y") + agramme = Unit.create_scaled_unit(gramme, "a") + cgramme = Unit.create_scaled_unit(gramme, "c") + Zgramme = Unit.create_scaled_unit(gramme, "Z") + Pgramme = Unit.create_scaled_unit(gramme, "P") + dgramme = Unit.create_scaled_unit(gramme, "d") + Ggramme = Unit.create_scaled_unit(gramme, "G") + fgramme = Unit.create_scaled_unit(gramme, "f") + hgramme = Unit.create_scaled_unit(gramme, "h") + dagramme = Unit.create_scaled_unit(gramme, "da") + mgramme = Unit.create_scaled_unit(gramme, "m") + ngramme = Unit.create_scaled_unit(gramme, "n") + pgramme = Unit.create_scaled_unit(gramme, "p") + ugramme = Unit.create_scaled_unit(gramme, "u") + Tgramme = Unit.create_scaled_unit(gramme, "T") + ygramme = Unit.create_scaled_unit(gramme, "y") + Egramme = Unit.create_scaled_unit(gramme, "E") + zgramme = Unit.create_scaled_unit(gramme, "z") + Mgramme = Unit.create_scaled_unit(gramme, "M") + kgramme = Unit.create_scaled_unit(gramme, "k") + Ygramme = Unit.create_scaled_unit(gramme, "Y") + amolar = Unit.create_scaled_unit(molar, "a") + cmolar = Unit.create_scaled_unit(molar, "c") + Zmolar = Unit.create_scaled_unit(molar, "Z") + Pmolar = Unit.create_scaled_unit(molar, "P") + dmolar = Unit.create_scaled_unit(molar, "d") + Gmolar = Unit.create_scaled_unit(molar, "G") + fmolar = Unit.create_scaled_unit(molar, "f") + hmolar = Unit.create_scaled_unit(molar, "h") + damolar = Unit.create_scaled_unit(molar, "da") + mmolar = Unit.create_scaled_unit(molar, "m") + nmolar = Unit.create_scaled_unit(molar, "n") + pmolar = Unit.create_scaled_unit(molar, "p") + umolar = Unit.create_scaled_unit(molar, "u") + Tmolar = Unit.create_scaled_unit(molar, "T") + ymolar = Unit.create_scaled_unit(molar, "y") + Emolar = Unit.create_scaled_unit(molar, "E") + zmolar = Unit.create_scaled_unit(molar, "z") + Mmolar = Unit.create_scaled_unit(molar, "M") + kmolar = Unit.create_scaled_unit(molar, "k") + Ymolar = Unit.create_scaled_unit(molar, "Y") + aradian = Unit.create_scaled_unit(radian, "a") + cradian = Unit.create_scaled_unit(radian, "c") + Zradian = Unit.create_scaled_unit(radian, "Z") + Pradian = Unit.create_scaled_unit(radian, "P") + dradian = Unit.create_scaled_unit(radian, "d") + Gradian = Unit.create_scaled_unit(radian, "G") + fradian = Unit.create_scaled_unit(radian, "f") + hradian = Unit.create_scaled_unit(radian, "h") + daradian = Unit.create_scaled_unit(radian, "da") + mradian = Unit.create_scaled_unit(radian, "m") + nradian = Unit.create_scaled_unit(radian, "n") + pradian = Unit.create_scaled_unit(radian, "p") + uradian = Unit.create_scaled_unit(radian, "u") + Tradian = Unit.create_scaled_unit(radian, "T") + yradian = Unit.create_scaled_unit(radian, "y") + Eradian = Unit.create_scaled_unit(radian, "E") + zradian = Unit.create_scaled_unit(radian, "z") + Mradian = Unit.create_scaled_unit(radian, "M") + kradian = Unit.create_scaled_unit(radian, "k") + Yradian = Unit.create_scaled_unit(radian, "Y") + asteradian = Unit.create_scaled_unit(steradian, "a") + csteradian = Unit.create_scaled_unit(steradian, "c") + Zsteradian = Unit.create_scaled_unit(steradian, "Z") + Psteradian = Unit.create_scaled_unit(steradian, "P") + dsteradian = Unit.create_scaled_unit(steradian, "d") + Gsteradian = Unit.create_scaled_unit(steradian, "G") + fsteradian = Unit.create_scaled_unit(steradian, "f") + hsteradian = Unit.create_scaled_unit(steradian, "h") + dasteradian = Unit.create_scaled_unit(steradian, "da") + msteradian = Unit.create_scaled_unit(steradian, "m") + nsteradian = Unit.create_scaled_unit(steradian, "n") + psteradian = Unit.create_scaled_unit(steradian, "p") + usteradian = Unit.create_scaled_unit(steradian, "u") + Tsteradian = Unit.create_scaled_unit(steradian, "T") + ysteradian = Unit.create_scaled_unit(steradian, "y") + Esteradian = Unit.create_scaled_unit(steradian, "E") + zsteradian = Unit.create_scaled_unit(steradian, "z") + Msteradian = Unit.create_scaled_unit(steradian, "M") + ksteradian = Unit.create_scaled_unit(steradian, "k") + Ysteradian = Unit.create_scaled_unit(steradian, "Y") + ahertz = Unit.create_scaled_unit(hertz, "a") + chertz = Unit.create_scaled_unit(hertz, "c") + Zhertz = Unit.create_scaled_unit(hertz, "Z") + Phertz = Unit.create_scaled_unit(hertz, "P") + dhertz = Unit.create_scaled_unit(hertz, "d") + Ghertz = Unit.create_scaled_unit(hertz, "G") + fhertz = Unit.create_scaled_unit(hertz, "f") + hhertz = Unit.create_scaled_unit(hertz, "h") + dahertz = Unit.create_scaled_unit(hertz, "da") + mhertz = Unit.create_scaled_unit(hertz, "m") + nhertz = Unit.create_scaled_unit(hertz, "n") + phertz = Unit.create_scaled_unit(hertz, "p") + uhertz = Unit.create_scaled_unit(hertz, "u") + Thertz = Unit.create_scaled_unit(hertz, "T") + yhertz = Unit.create_scaled_unit(hertz, "y") + Ehertz = Unit.create_scaled_unit(hertz, "E") + zhertz = Unit.create_scaled_unit(hertz, "z") + Mhertz = Unit.create_scaled_unit(hertz, "M") + khertz = Unit.create_scaled_unit(hertz, "k") + Yhertz = Unit.create_scaled_unit(hertz, "Y") + anewton = Unit.create_scaled_unit(newton, "a") + cnewton = Unit.create_scaled_unit(newton, "c") + Znewton = Unit.create_scaled_unit(newton, "Z") + Pnewton = Unit.create_scaled_unit(newton, "P") + dnewton = Unit.create_scaled_unit(newton, "d") + Gnewton = Unit.create_scaled_unit(newton, "G") + fnewton = Unit.create_scaled_unit(newton, "f") + hnewton = Unit.create_scaled_unit(newton, "h") + danewton = Unit.create_scaled_unit(newton, "da") + mnewton = Unit.create_scaled_unit(newton, "m") + nnewton = Unit.create_scaled_unit(newton, "n") + pnewton = Unit.create_scaled_unit(newton, "p") + unewton = Unit.create_scaled_unit(newton, "u") + Tnewton = Unit.create_scaled_unit(newton, "T") + ynewton = Unit.create_scaled_unit(newton, "y") + Enewton = Unit.create_scaled_unit(newton, "E") + znewton = Unit.create_scaled_unit(newton, "z") + Mnewton = Unit.create_scaled_unit(newton, "M") + knewton = Unit.create_scaled_unit(newton, "k") + Ynewton = Unit.create_scaled_unit(newton, "Y") + apascal = Unit.create_scaled_unit(pascal, "a") + cpascal = Unit.create_scaled_unit(pascal, "c") + Zpascal = Unit.create_scaled_unit(pascal, "Z") + Ppascal = Unit.create_scaled_unit(pascal, "P") + dpascal = Unit.create_scaled_unit(pascal, "d") + Gpascal = Unit.create_scaled_unit(pascal, "G") + fpascal = Unit.create_scaled_unit(pascal, "f") + hpascal = Unit.create_scaled_unit(pascal, "h") + dapascal = Unit.create_scaled_unit(pascal, "da") + mpascal = Unit.create_scaled_unit(pascal, "m") + npascal = Unit.create_scaled_unit(pascal, "n") + ppascal = Unit.create_scaled_unit(pascal, "p") + upascal = Unit.create_scaled_unit(pascal, "u") + Tpascal = Unit.create_scaled_unit(pascal, "T") + ypascal = Unit.create_scaled_unit(pascal, "y") + Epascal = Unit.create_scaled_unit(pascal, "E") + zpascal = Unit.create_scaled_unit(pascal, "z") + Mpascal = Unit.create_scaled_unit(pascal, "M") + kpascal = Unit.create_scaled_unit(pascal, "k") + Ypascal = Unit.create_scaled_unit(pascal, "Y") + ajoule = Unit.create_scaled_unit(joule, "a") + cjoule = Unit.create_scaled_unit(joule, "c") + Zjoule = Unit.create_scaled_unit(joule, "Z") + Pjoule = Unit.create_scaled_unit(joule, "P") + djoule = Unit.create_scaled_unit(joule, "d") + Gjoule = Unit.create_scaled_unit(joule, "G") + fjoule = Unit.create_scaled_unit(joule, "f") + hjoule = Unit.create_scaled_unit(joule, "h") + dajoule = Unit.create_scaled_unit(joule, "da") + mjoule = Unit.create_scaled_unit(joule, "m") + njoule = Unit.create_scaled_unit(joule, "n") + pjoule = Unit.create_scaled_unit(joule, "p") + ujoule = Unit.create_scaled_unit(joule, "u") + Tjoule = Unit.create_scaled_unit(joule, "T") + yjoule = Unit.create_scaled_unit(joule, "y") + Ejoule = Unit.create_scaled_unit(joule, "E") + zjoule = Unit.create_scaled_unit(joule, "z") + Mjoule = Unit.create_scaled_unit(joule, "M") + kjoule = Unit.create_scaled_unit(joule, "k") + Yjoule = Unit.create_scaled_unit(joule, "Y") + awatt = Unit.create_scaled_unit(watt, "a") + cwatt = Unit.create_scaled_unit(watt, "c") + Zwatt = Unit.create_scaled_unit(watt, "Z") + Pwatt = Unit.create_scaled_unit(watt, "P") + dwatt = Unit.create_scaled_unit(watt, "d") + Gwatt = Unit.create_scaled_unit(watt, "G") + fwatt = Unit.create_scaled_unit(watt, "f") + hwatt = Unit.create_scaled_unit(watt, "h") + dawatt = Unit.create_scaled_unit(watt, "da") + mwatt = Unit.create_scaled_unit(watt, "m") + nwatt = Unit.create_scaled_unit(watt, "n") + pwatt = Unit.create_scaled_unit(watt, "p") + uwatt = Unit.create_scaled_unit(watt, "u") + Twatt = Unit.create_scaled_unit(watt, "T") + ywatt = Unit.create_scaled_unit(watt, "y") + Ewatt = Unit.create_scaled_unit(watt, "E") + zwatt = Unit.create_scaled_unit(watt, "z") + Mwatt = Unit.create_scaled_unit(watt, "M") + kwatt = Unit.create_scaled_unit(watt, "k") + Ywatt = Unit.create_scaled_unit(watt, "Y") + acoulomb = Unit.create_scaled_unit(coulomb, "a") + ccoulomb = Unit.create_scaled_unit(coulomb, "c") + Zcoulomb = Unit.create_scaled_unit(coulomb, "Z") + Pcoulomb = Unit.create_scaled_unit(coulomb, "P") + dcoulomb = Unit.create_scaled_unit(coulomb, "d") + Gcoulomb = Unit.create_scaled_unit(coulomb, "G") + fcoulomb = Unit.create_scaled_unit(coulomb, "f") + hcoulomb = Unit.create_scaled_unit(coulomb, "h") + dacoulomb = Unit.create_scaled_unit(coulomb, "da") + mcoulomb = Unit.create_scaled_unit(coulomb, "m") + ncoulomb = Unit.create_scaled_unit(coulomb, "n") + pcoulomb = Unit.create_scaled_unit(coulomb, "p") + ucoulomb = Unit.create_scaled_unit(coulomb, "u") + Tcoulomb = Unit.create_scaled_unit(coulomb, "T") + ycoulomb = Unit.create_scaled_unit(coulomb, "y") + Ecoulomb = Unit.create_scaled_unit(coulomb, "E") + zcoulomb = Unit.create_scaled_unit(coulomb, "z") + Mcoulomb = Unit.create_scaled_unit(coulomb, "M") + kcoulomb = Unit.create_scaled_unit(coulomb, "k") + Ycoulomb = Unit.create_scaled_unit(coulomb, "Y") + avolt = Unit.create_scaled_unit(volt, "a") + cvolt = Unit.create_scaled_unit(volt, "c") + Zvolt = Unit.create_scaled_unit(volt, "Z") + Pvolt = Unit.create_scaled_unit(volt, "P") + dvolt = Unit.create_scaled_unit(volt, "d") + Gvolt = Unit.create_scaled_unit(volt, "G") + fvolt = Unit.create_scaled_unit(volt, "f") + hvolt = Unit.create_scaled_unit(volt, "h") + davolt = Unit.create_scaled_unit(volt, "da") + mvolt = Unit.create_scaled_unit(volt, "m") + nvolt = Unit.create_scaled_unit(volt, "n") + pvolt = Unit.create_scaled_unit(volt, "p") + uvolt = Unit.create_scaled_unit(volt, "u") + Tvolt = Unit.create_scaled_unit(volt, "T") + yvolt = Unit.create_scaled_unit(volt, "y") + Evolt = Unit.create_scaled_unit(volt, "E") + zvolt = Unit.create_scaled_unit(volt, "z") + Mvolt = Unit.create_scaled_unit(volt, "M") + kvolt = Unit.create_scaled_unit(volt, "k") + Yvolt = Unit.create_scaled_unit(volt, "Y") + afarad = Unit.create_scaled_unit(farad, "a") + cfarad = Unit.create_scaled_unit(farad, "c") + Zfarad = Unit.create_scaled_unit(farad, "Z") + Pfarad = Unit.create_scaled_unit(farad, "P") + dfarad = Unit.create_scaled_unit(farad, "d") + Gfarad = Unit.create_scaled_unit(farad, "G") + ffarad = Unit.create_scaled_unit(farad, "f") + hfarad = Unit.create_scaled_unit(farad, "h") + dafarad = Unit.create_scaled_unit(farad, "da") + mfarad = Unit.create_scaled_unit(farad, "m") + nfarad = Unit.create_scaled_unit(farad, "n") + pfarad = Unit.create_scaled_unit(farad, "p") + ufarad = Unit.create_scaled_unit(farad, "u") + Tfarad = Unit.create_scaled_unit(farad, "T") + yfarad = Unit.create_scaled_unit(farad, "y") + Efarad = Unit.create_scaled_unit(farad, "E") + zfarad = Unit.create_scaled_unit(farad, "z") + Mfarad = Unit.create_scaled_unit(farad, "M") + kfarad = Unit.create_scaled_unit(farad, "k") + Yfarad = Unit.create_scaled_unit(farad, "Y") + aohm = Unit.create_scaled_unit(ohm, "a") + cohm = Unit.create_scaled_unit(ohm, "c") + Zohm = Unit.create_scaled_unit(ohm, "Z") + Pohm = Unit.create_scaled_unit(ohm, "P") + dohm = Unit.create_scaled_unit(ohm, "d") + Gohm = Unit.create_scaled_unit(ohm, "G") + fohm = Unit.create_scaled_unit(ohm, "f") + hohm = Unit.create_scaled_unit(ohm, "h") + daohm = Unit.create_scaled_unit(ohm, "da") + mohm = Unit.create_scaled_unit(ohm, "m") + nohm = Unit.create_scaled_unit(ohm, "n") + pohm = Unit.create_scaled_unit(ohm, "p") + uohm = Unit.create_scaled_unit(ohm, "u") + Tohm = Unit.create_scaled_unit(ohm, "T") + yohm = Unit.create_scaled_unit(ohm, "y") + Eohm = Unit.create_scaled_unit(ohm, "E") + zohm = Unit.create_scaled_unit(ohm, "z") + Mohm = Unit.create_scaled_unit(ohm, "M") + kohm = Unit.create_scaled_unit(ohm, "k") + Yohm = Unit.create_scaled_unit(ohm, "Y") + asiemens = Unit.create_scaled_unit(siemens, "a") + csiemens = Unit.create_scaled_unit(siemens, "c") + Zsiemens = Unit.create_scaled_unit(siemens, "Z") + Psiemens = Unit.create_scaled_unit(siemens, "P") + dsiemens = Unit.create_scaled_unit(siemens, "d") + Gsiemens = Unit.create_scaled_unit(siemens, "G") + fsiemens = Unit.create_scaled_unit(siemens, "f") + hsiemens = Unit.create_scaled_unit(siemens, "h") + dasiemens = Unit.create_scaled_unit(siemens, "da") + msiemens = Unit.create_scaled_unit(siemens, "m") + nsiemens = Unit.create_scaled_unit(siemens, "n") + psiemens = Unit.create_scaled_unit(siemens, "p") + usiemens = Unit.create_scaled_unit(siemens, "u") + Tsiemens = Unit.create_scaled_unit(siemens, "T") + ysiemens = Unit.create_scaled_unit(siemens, "y") + Esiemens = Unit.create_scaled_unit(siemens, "E") + zsiemens = Unit.create_scaled_unit(siemens, "z") + Msiemens = Unit.create_scaled_unit(siemens, "M") + ksiemens = Unit.create_scaled_unit(siemens, "k") + Ysiemens = Unit.create_scaled_unit(siemens, "Y") + aweber = Unit.create_scaled_unit(weber, "a") + cweber = Unit.create_scaled_unit(weber, "c") + Zweber = Unit.create_scaled_unit(weber, "Z") + Pweber = Unit.create_scaled_unit(weber, "P") + dweber = Unit.create_scaled_unit(weber, "d") + Gweber = Unit.create_scaled_unit(weber, "G") + fweber = Unit.create_scaled_unit(weber, "f") + hweber = Unit.create_scaled_unit(weber, "h") + daweber = Unit.create_scaled_unit(weber, "da") + mweber = Unit.create_scaled_unit(weber, "m") + nweber = Unit.create_scaled_unit(weber, "n") + pweber = Unit.create_scaled_unit(weber, "p") + uweber = Unit.create_scaled_unit(weber, "u") + Tweber = Unit.create_scaled_unit(weber, "T") + yweber = Unit.create_scaled_unit(weber, "y") + Eweber = Unit.create_scaled_unit(weber, "E") + zweber = Unit.create_scaled_unit(weber, "z") + Mweber = Unit.create_scaled_unit(weber, "M") + kweber = Unit.create_scaled_unit(weber, "k") + Yweber = Unit.create_scaled_unit(weber, "Y") + atesla = Unit.create_scaled_unit(tesla, "a") + ctesla = Unit.create_scaled_unit(tesla, "c") + Ztesla = Unit.create_scaled_unit(tesla, "Z") + Ptesla = Unit.create_scaled_unit(tesla, "P") + dtesla = Unit.create_scaled_unit(tesla, "d") + Gtesla = Unit.create_scaled_unit(tesla, "G") + ftesla = Unit.create_scaled_unit(tesla, "f") + htesla = Unit.create_scaled_unit(tesla, "h") + datesla = Unit.create_scaled_unit(tesla, "da") + mtesla = Unit.create_scaled_unit(tesla, "m") + ntesla = Unit.create_scaled_unit(tesla, "n") + ptesla = Unit.create_scaled_unit(tesla, "p") + utesla = Unit.create_scaled_unit(tesla, "u") + Ttesla = Unit.create_scaled_unit(tesla, "T") + ytesla = Unit.create_scaled_unit(tesla, "y") + Etesla = Unit.create_scaled_unit(tesla, "E") + ztesla = Unit.create_scaled_unit(tesla, "z") + Mtesla = Unit.create_scaled_unit(tesla, "M") + ktesla = Unit.create_scaled_unit(tesla, "k") + Ytesla = Unit.create_scaled_unit(tesla, "Y") + ahenry = Unit.create_scaled_unit(henry, "a") + chenry = Unit.create_scaled_unit(henry, "c") + Zhenry = Unit.create_scaled_unit(henry, "Z") + Phenry = Unit.create_scaled_unit(henry, "P") + dhenry = Unit.create_scaled_unit(henry, "d") + Ghenry = Unit.create_scaled_unit(henry, "G") + fhenry = Unit.create_scaled_unit(henry, "f") + hhenry = Unit.create_scaled_unit(henry, "h") + dahenry = Unit.create_scaled_unit(henry, "da") + mhenry = Unit.create_scaled_unit(henry, "m") + nhenry = Unit.create_scaled_unit(henry, "n") + phenry = Unit.create_scaled_unit(henry, "p") + uhenry = Unit.create_scaled_unit(henry, "u") + Thenry = Unit.create_scaled_unit(henry, "T") + yhenry = Unit.create_scaled_unit(henry, "y") + Ehenry = Unit.create_scaled_unit(henry, "E") + zhenry = Unit.create_scaled_unit(henry, "z") + Mhenry = Unit.create_scaled_unit(henry, "M") + khenry = Unit.create_scaled_unit(henry, "k") + Yhenry = Unit.create_scaled_unit(henry, "Y") + alumen = Unit.create_scaled_unit(lumen, "a") + clumen = Unit.create_scaled_unit(lumen, "c") + Zlumen = Unit.create_scaled_unit(lumen, "Z") + Plumen = Unit.create_scaled_unit(lumen, "P") + dlumen = Unit.create_scaled_unit(lumen, "d") + Glumen = Unit.create_scaled_unit(lumen, "G") + flumen = Unit.create_scaled_unit(lumen, "f") + hlumen = Unit.create_scaled_unit(lumen, "h") + dalumen = Unit.create_scaled_unit(lumen, "da") + mlumen = Unit.create_scaled_unit(lumen, "m") + nlumen = Unit.create_scaled_unit(lumen, "n") + plumen = Unit.create_scaled_unit(lumen, "p") + ulumen = Unit.create_scaled_unit(lumen, "u") + Tlumen = Unit.create_scaled_unit(lumen, "T") + ylumen = Unit.create_scaled_unit(lumen, "y") + Elumen = Unit.create_scaled_unit(lumen, "E") + zlumen = Unit.create_scaled_unit(lumen, "z") + Mlumen = Unit.create_scaled_unit(lumen, "M") + klumen = Unit.create_scaled_unit(lumen, "k") + Ylumen = Unit.create_scaled_unit(lumen, "Y") + alux = Unit.create_scaled_unit(lux, "a") + clux = Unit.create_scaled_unit(lux, "c") + Zlux = Unit.create_scaled_unit(lux, "Z") + Plux = Unit.create_scaled_unit(lux, "P") + dlux = Unit.create_scaled_unit(lux, "d") + Glux = Unit.create_scaled_unit(lux, "G") + flux = Unit.create_scaled_unit(lux, "f") + hlux = Unit.create_scaled_unit(lux, "h") + dalux = Unit.create_scaled_unit(lux, "da") + mlux = Unit.create_scaled_unit(lux, "m") + nlux = Unit.create_scaled_unit(lux, "n") + plux = Unit.create_scaled_unit(lux, "p") + ulux = Unit.create_scaled_unit(lux, "u") + Tlux = Unit.create_scaled_unit(lux, "T") + ylux = Unit.create_scaled_unit(lux, "y") + Elux = Unit.create_scaled_unit(lux, "E") + zlux = Unit.create_scaled_unit(lux, "z") + Mlux = Unit.create_scaled_unit(lux, "M") + klux = Unit.create_scaled_unit(lux, "k") + Ylux = Unit.create_scaled_unit(lux, "Y") + abecquerel = Unit.create_scaled_unit(becquerel, "a") + cbecquerel = Unit.create_scaled_unit(becquerel, "c") + Zbecquerel = Unit.create_scaled_unit(becquerel, "Z") + Pbecquerel = Unit.create_scaled_unit(becquerel, "P") + dbecquerel = Unit.create_scaled_unit(becquerel, "d") + Gbecquerel = Unit.create_scaled_unit(becquerel, "G") + fbecquerel = Unit.create_scaled_unit(becquerel, "f") + hbecquerel = Unit.create_scaled_unit(becquerel, "h") + dabecquerel = Unit.create_scaled_unit(becquerel, "da") + mbecquerel = Unit.create_scaled_unit(becquerel, "m") + nbecquerel = Unit.create_scaled_unit(becquerel, "n") + pbecquerel = Unit.create_scaled_unit(becquerel, "p") + ubecquerel = Unit.create_scaled_unit(becquerel, "u") + Tbecquerel = Unit.create_scaled_unit(becquerel, "T") + ybecquerel = Unit.create_scaled_unit(becquerel, "y") + Ebecquerel = Unit.create_scaled_unit(becquerel, "E") + zbecquerel = Unit.create_scaled_unit(becquerel, "z") + Mbecquerel = Unit.create_scaled_unit(becquerel, "M") + kbecquerel = Unit.create_scaled_unit(becquerel, "k") + Ybecquerel = Unit.create_scaled_unit(becquerel, "Y") + agray = Unit.create_scaled_unit(gray, "a") + cgray = Unit.create_scaled_unit(gray, "c") + Zgray = Unit.create_scaled_unit(gray, "Z") + Pgray = Unit.create_scaled_unit(gray, "P") + dgray = Unit.create_scaled_unit(gray, "d") + Ggray = Unit.create_scaled_unit(gray, "G") + fgray = Unit.create_scaled_unit(gray, "f") + hgray = Unit.create_scaled_unit(gray, "h") + dagray = Unit.create_scaled_unit(gray, "da") + mgray = Unit.create_scaled_unit(gray, "m") + ngray = Unit.create_scaled_unit(gray, "n") + pgray = Unit.create_scaled_unit(gray, "p") + ugray = Unit.create_scaled_unit(gray, "u") + Tgray = Unit.create_scaled_unit(gray, "T") + ygray = Unit.create_scaled_unit(gray, "y") + Egray = Unit.create_scaled_unit(gray, "E") + zgray = Unit.create_scaled_unit(gray, "z") + Mgray = Unit.create_scaled_unit(gray, "M") + kgray = Unit.create_scaled_unit(gray, "k") + Ygray = Unit.create_scaled_unit(gray, "Y") + asievert = Unit.create_scaled_unit(sievert, "a") + csievert = Unit.create_scaled_unit(sievert, "c") + Zsievert = Unit.create_scaled_unit(sievert, "Z") + Psievert = Unit.create_scaled_unit(sievert, "P") + dsievert = Unit.create_scaled_unit(sievert, "d") + Gsievert = Unit.create_scaled_unit(sievert, "G") + fsievert = Unit.create_scaled_unit(sievert, "f") + hsievert = Unit.create_scaled_unit(sievert, "h") + dasievert = Unit.create_scaled_unit(sievert, "da") + msievert = Unit.create_scaled_unit(sievert, "m") + nsievert = Unit.create_scaled_unit(sievert, "n") + psievert = Unit.create_scaled_unit(sievert, "p") + usievert = Unit.create_scaled_unit(sievert, "u") + Tsievert = Unit.create_scaled_unit(sievert, "T") + ysievert = Unit.create_scaled_unit(sievert, "y") + Esievert = Unit.create_scaled_unit(sievert, "E") + zsievert = Unit.create_scaled_unit(sievert, "z") + Msievert = Unit.create_scaled_unit(sievert, "M") + ksievert = Unit.create_scaled_unit(sievert, "k") + Ysievert = Unit.create_scaled_unit(sievert, "Y") + akatal = Unit.create_scaled_unit(katal, "a") + ckatal = Unit.create_scaled_unit(katal, "c") + Zkatal = Unit.create_scaled_unit(katal, "Z") + Pkatal = Unit.create_scaled_unit(katal, "P") + dkatal = Unit.create_scaled_unit(katal, "d") + Gkatal = Unit.create_scaled_unit(katal, "G") + fkatal = Unit.create_scaled_unit(katal, "f") + hkatal = Unit.create_scaled_unit(katal, "h") + dakatal = Unit.create_scaled_unit(katal, "da") + mkatal = Unit.create_scaled_unit(katal, "m") + nkatal = Unit.create_scaled_unit(katal, "n") + pkatal = Unit.create_scaled_unit(katal, "p") + ukatal = Unit.create_scaled_unit(katal, "u") + Tkatal = Unit.create_scaled_unit(katal, "T") + ykatal = Unit.create_scaled_unit(katal, "y") + Ekatal = Unit.create_scaled_unit(katal, "E") + zkatal = Unit.create_scaled_unit(katal, "z") + Mkatal = Unit.create_scaled_unit(katal, "M") + kkatal = Unit.create_scaled_unit(katal, "k") + Ykatal = Unit.create_scaled_unit(katal, "Y") + ######### SCALED BASE UNITS TO POWERS ########### + metre2 = Unit.create((metre ** 2).unit, name="metre2", dispname=f"{str(metre)}^2", scale=metre.scale * 2) + metre3 = Unit.create((metre ** 3).unit, name="metre3", dispname=f"{str(metre)}^3", scale=metre.scale * 3) + meter2 = Unit.create((meter ** 2).unit, name="meter2", dispname=f"{str(meter)}^2", scale=meter.scale * 2) + meter3 = Unit.create((meter ** 3).unit, name="meter3", dispname=f"{str(meter)}^3", scale=meter.scale * 3) + kilogram2 = Unit.create((kilogram ** 2).unit, name="kilogram2", dispname=f"{str(kilogram)}^2", + scale=kilogram.scale * 2) + kilogram3 = Unit.create((kilogram ** 3).unit, name="kilogram3", dispname=f"{str(kilogram)}^3", + scale=kilogram.scale * 3) + second2 = Unit.create((second ** 2).unit, name="second2", dispname=f"{str(second)}^2", scale=second.scale * 2) + second3 = Unit.create((second ** 3).unit, name="second3", dispname=f"{str(second)}^3", scale=second.scale * 3) + amp2 = Unit.create((amp ** 2).unit, name="amp2", dispname=f"{str(amp)}^2", scale=amp.scale * 2) + amp3 = Unit.create((amp ** 3).unit, name="amp3", dispname=f"{str(amp)}^3", scale=amp.scale * 3) + ampere2 = Unit.create((ampere ** 2).unit, name="ampere2", dispname=f"{str(ampere)}^2", scale=ampere.scale * 2) + ampere3 = Unit.create((ampere ** 3).unit, name="ampere3", dispname=f"{str(ampere)}^3", scale=ampere.scale * 3) + kelvin2 = Unit.create((kelvin ** 2).unit, name="kelvin2", dispname=f"{str(kelvin)}^2", scale=kelvin.scale * 2) + kelvin3 = Unit.create((kelvin ** 3).unit, name="kelvin3", dispname=f"{str(kelvin)}^3", scale=kelvin.scale * 3) + mole2 = Unit.create((mole ** 2).unit, name="mole2", dispname=f"{str(mole)}^2", scale=mole.scale * 2) + mole3 = Unit.create((mole ** 3).unit, name="mole3", dispname=f"{str(mole)}^3", scale=mole.scale * 3) + mol2 = Unit.create((mol ** 2).unit, name="mol2", dispname=f"{str(mol)}^2", scale=mol.scale * 2) + mol3 = Unit.create((mol ** 3).unit, name="mol3", dispname=f"{str(mol)}^3", scale=mol.scale * 3) + candle2 = Unit.create((candle ** 2).unit, name="candle2", dispname=f"{str(candle)}^2", scale=candle.scale * 2) + candle3 = Unit.create((candle ** 3).unit, name="candle3", dispname=f"{str(candle)}^3", scale=candle.scale * 3) + kilogramme2 = Unit.create((kilogramme ** 2).unit, name="kilogramme2", dispname=f"{str(kilogramme)}^2", + scale=kilogramme.scale * 2) + kilogramme3 = Unit.create((kilogramme ** 3).unit, name="kilogramme3", dispname=f"{str(kilogramme)}^3", + scale=kilogramme.scale * 3) + gram2 = Unit.create((gram ** 2).unit, name="gram2", dispname=f"{str(gram)}^2", scale=gram.scale * 2) + gram3 = Unit.create((gram ** 3).unit, name="gram3", dispname=f"{str(gram)}^3", scale=gram.scale * 3) + gramme2 = Unit.create((gramme ** 2).unit, name="gramme2", dispname=f"{str(gramme)}^2", scale=gramme.scale * 2) + gramme3 = Unit.create((gramme ** 3).unit, name="gramme3", dispname=f"{str(gramme)}^3", scale=gramme.scale * 3) + molar2 = Unit.create((molar ** 2).unit, name="molar2", dispname=f"{str(molar)}^2", scale=molar.scale * 2) + molar3 = Unit.create((molar ** 3).unit, name="molar3", dispname=f"{str(molar)}^3", scale=molar.scale * 3) + radian2 = Unit.create((radian ** 2).unit, name="radian2", dispname=f"{str(radian)}^2", scale=radian.scale * 2) + radian3 = Unit.create((radian ** 3).unit, name="radian3", dispname=f"{str(radian)}^3", scale=radian.scale * 3) + steradian2 = Unit.create((steradian ** 2).unit, name="steradian2", dispname=f"{str(steradian)}^2", + scale=steradian.scale * 2) + steradian3 = Unit.create((steradian ** 3).unit, name="steradian3", dispname=f"{str(steradian)}^3", + scale=steradian.scale * 3) + hertz2 = Unit.create((hertz ** 2).unit, name="hertz2", dispname=f"{str(hertz)}^2", scale=hertz.scale * 2) + hertz3 = Unit.create((hertz ** 3).unit, name="hertz3", dispname=f"{str(hertz)}^3", scale=hertz.scale * 3) + newton2 = Unit.create((newton ** 2).unit, name="newton2", dispname=f"{str(newton)}^2", scale=newton.scale * 2) + newton3 = Unit.create((newton ** 3).unit, name="newton3", dispname=f"{str(newton)}^3", scale=newton.scale * 3) + pascal2 = Unit.create((pascal ** 2).unit, name="pascal2", dispname=f"{str(pascal)}^2", scale=pascal.scale * 2) + pascal3 = Unit.create((pascal ** 3).unit, name="pascal3", dispname=f"{str(pascal)}^3", scale=pascal.scale * 3) + joule2 = Unit.create((joule ** 2).unit, name="joule2", dispname=f"{str(joule)}^2", scale=joule.scale * 2) + joule3 = Unit.create((joule ** 3).unit, name="joule3", dispname=f"{str(joule)}^3", scale=joule.scale * 3) + watt2 = Unit.create((watt ** 2).unit, name="watt2", dispname=f"{str(watt)}^2", scale=watt.scale * 2) + watt3 = Unit.create((watt ** 3).unit, name="watt3", dispname=f"{str(watt)}^3", scale=watt.scale * 3) + coulomb2 = Unit.create((coulomb ** 2).unit, name="coulomb2", dispname=f"{str(coulomb)}^2", scale=coulomb.scale * 2) + coulomb3 = Unit.create((coulomb ** 3).unit, name="coulomb3", dispname=f"{str(coulomb)}^3", scale=coulomb.scale * 3) + volt2 = Unit.create((volt ** 2).unit, name="volt2", dispname=f"{str(volt)}^2", scale=volt.scale * 2) + volt3 = Unit.create((volt ** 3).unit, name="volt3", dispname=f"{str(volt)}^3", scale=volt.scale * 3) + farad2 = Unit.create((farad ** 2).unit, name="farad2", dispname=f"{str(farad)}^2", scale=farad.scale * 2) + farad3 = Unit.create((farad ** 3).unit, name="farad3", dispname=f"{str(farad)}^3", scale=farad.scale * 3) + ohm2 = Unit.create((ohm ** 2).unit, name="ohm2", dispname=f"{str(ohm)}^2", scale=ohm.scale * 2) + ohm3 = Unit.create((ohm ** 3).unit, name="ohm3", dispname=f"{str(ohm)}^3", scale=ohm.scale * 3) + siemens2 = Unit.create((siemens ** 2).unit, name="siemens2", dispname=f"{str(siemens)}^2", scale=siemens.scale * 2) + siemens3 = Unit.create((siemens ** 3).unit, name="siemens3", dispname=f"{str(siemens)}^3", scale=siemens.scale * 3) + weber2 = Unit.create((weber ** 2).unit, name="weber2", dispname=f"{str(weber)}^2", scale=weber.scale * 2) + weber3 = Unit.create((weber ** 3).unit, name="weber3", dispname=f"{str(weber)}^3", scale=weber.scale * 3) + tesla2 = Unit.create((tesla ** 2).unit, name="tesla2", dispname=f"{str(tesla)}^2", scale=tesla.scale * 2) + tesla3 = Unit.create((tesla ** 3).unit, name="tesla3", dispname=f"{str(tesla)}^3", scale=tesla.scale * 3) + henry2 = Unit.create((henry ** 2).unit, name="henry2", dispname=f"{str(henry)}^2", scale=henry.scale * 2) + henry3 = Unit.create((henry ** 3).unit, name="henry3", dispname=f"{str(henry)}^3", scale=henry.scale * 3) + lumen2 = Unit.create((lumen ** 2).unit, name="lumen2", dispname=f"{str(lumen)}^2", scale=lumen.scale * 2) + lumen3 = Unit.create((lumen ** 3).unit, name="lumen3", dispname=f"{str(lumen)}^3", scale=lumen.scale * 3) + lux2 = Unit.create((lux ** 2).unit, name="lux2", dispname=f"{str(lux)}^2", scale=lux.scale * 2) + lux3 = Unit.create((lux ** 3).unit, name="lux3", dispname=f"{str(lux)}^3", scale=lux.scale * 3) + becquerel2 = Unit.create((becquerel ** 2).unit, name="becquerel2", dispname=f"{str(becquerel)}^2", + scale=becquerel.scale * 2) + becquerel3 = Unit.create((becquerel ** 3).unit, name="becquerel3", dispname=f"{str(becquerel)}^3", + scale=becquerel.scale * 3) + gray2 = Unit.create((gray ** 2).unit, name="gray2", dispname=f"{str(gray)}^2", scale=gray.scale * 2) + gray3 = Unit.create((gray ** 3).unit, name="gray3", dispname=f"{str(gray)}^3", scale=gray.scale * 3) + sievert2 = Unit.create((sievert ** 2).unit, name="sievert2", dispname=f"{str(sievert)}^2", scale=sievert.scale * 2) + sievert3 = Unit.create((sievert ** 3).unit, name="sievert3", dispname=f"{str(sievert)}^3", scale=sievert.scale * 3) + katal2 = Unit.create((katal ** 2).unit, name="katal2", dispname=f"{str(katal)}^2", scale=katal.scale * 2) + katal3 = Unit.create((katal ** 3).unit, name="katal3", dispname=f"{str(katal)}^3", scale=katal.scale * 3) + ametre2 = Unit.create((ametre ** 2).unit, name="ametre2", dispname=f"{str(ametre)}^2", scale=ametre.scale * 2) + ametre3 = Unit.create((ametre ** 3).unit, name="ametre3", dispname=f"{str(ametre)}^3", scale=ametre.scale * 3) + cmetre2 = Unit.create((cmetre ** 2).unit, name="cmetre2", dispname=f"{str(cmetre)}^2", scale=cmetre.scale * 2) + cmetre3 = Unit.create((cmetre ** 3).unit, name="cmetre3", dispname=f"{str(cmetre)}^3", scale=cmetre.scale * 3) + Zmetre2 = Unit.create((Zmetre ** 2).unit, name="Zmetre2", dispname=f"{str(Zmetre)}^2", scale=Zmetre.scale * 2) + Zmetre3 = Unit.create((Zmetre ** 3).unit, name="Zmetre3", dispname=f"{str(Zmetre)}^3", scale=Zmetre.scale * 3) + Pmetre2 = Unit.create((Pmetre ** 2).unit, name="Pmetre2", dispname=f"{str(Pmetre)}^2", scale=Pmetre.scale * 2) + Pmetre3 = Unit.create((Pmetre ** 3).unit, name="Pmetre3", dispname=f"{str(Pmetre)}^3", scale=Pmetre.scale * 3) + dmetre2 = Unit.create((dmetre ** 2).unit, name="dmetre2", dispname=f"{str(dmetre)}^2", scale=dmetre.scale * 2) + dmetre3 = Unit.create((dmetre ** 3).unit, name="dmetre3", dispname=f"{str(dmetre)}^3", scale=dmetre.scale * 3) + Gmetre2 = Unit.create((Gmetre ** 2).unit, name="Gmetre2", dispname=f"{str(Gmetre)}^2", scale=Gmetre.scale * 2) + Gmetre3 = Unit.create((Gmetre ** 3).unit, name="Gmetre3", dispname=f"{str(Gmetre)}^3", scale=Gmetre.scale * 3) + fmetre2 = Unit.create((fmetre ** 2).unit, name="fmetre2", dispname=f"{str(fmetre)}^2", scale=fmetre.scale * 2) + fmetre3 = Unit.create((fmetre ** 3).unit, name="fmetre3", dispname=f"{str(fmetre)}^3", scale=fmetre.scale * 3) + hmetre2 = Unit.create((hmetre ** 2).unit, name="hmetre2", dispname=f"{str(hmetre)}^2", scale=hmetre.scale * 2) + hmetre3 = Unit.create((hmetre ** 3).unit, name="hmetre3", dispname=f"{str(hmetre)}^3", scale=hmetre.scale * 3) + dametre2 = Unit.create((dametre ** 2).unit, name="dametre2", dispname=f"{str(dametre)}^2", scale=dametre.scale * 2) + dametre3 = Unit.create((dametre ** 3).unit, name="dametre3", dispname=f"{str(dametre)}^3", scale=dametre.scale * 3) + mmetre2 = Unit.create((mmetre ** 2).unit, name="mmetre2", dispname=f"{str(mmetre)}^2", scale=mmetre.scale * 2) + mmetre3 = Unit.create((mmetre ** 3).unit, name="mmetre3", dispname=f"{str(mmetre)}^3", scale=mmetre.scale * 3) + nmetre2 = Unit.create((nmetre ** 2).unit, name="nmetre2", dispname=f"{str(nmetre)}^2", scale=nmetre.scale * 2) + nmetre3 = Unit.create((nmetre ** 3).unit, name="nmetre3", dispname=f"{str(nmetre)}^3", scale=nmetre.scale * 3) + pmetre2 = Unit.create((pmetre ** 2).unit, name="pmetre2", dispname=f"{str(pmetre)}^2", scale=pmetre.scale * 2) + pmetre3 = Unit.create((pmetre ** 3).unit, name="pmetre3", dispname=f"{str(pmetre)}^3", scale=pmetre.scale * 3) + umetre2 = Unit.create((umetre ** 2).unit, name="umetre2", dispname=f"{str(umetre)}^2", scale=umetre.scale * 2) + umetre3 = Unit.create((umetre ** 3).unit, name="umetre3", dispname=f"{str(umetre)}^3", scale=umetre.scale * 3) + Tmetre2 = Unit.create((Tmetre ** 2).unit, name="Tmetre2", dispname=f"{str(Tmetre)}^2", scale=Tmetre.scale * 2) + Tmetre3 = Unit.create((Tmetre ** 3).unit, name="Tmetre3", dispname=f"{str(Tmetre)}^3", scale=Tmetre.scale * 3) + ymetre2 = Unit.create((ymetre ** 2).unit, name="ymetre2", dispname=f"{str(ymetre)}^2", scale=ymetre.scale * 2) + ymetre3 = Unit.create((ymetre ** 3).unit, name="ymetre3", dispname=f"{str(ymetre)}^3", scale=ymetre.scale * 3) + Emetre2 = Unit.create((Emetre ** 2).unit, name="Emetre2", dispname=f"{str(Emetre)}^2", scale=Emetre.scale * 2) + Emetre3 = Unit.create((Emetre ** 3).unit, name="Emetre3", dispname=f"{str(Emetre)}^3", scale=Emetre.scale * 3) + zmetre2 = Unit.create((zmetre ** 2).unit, name="zmetre2", dispname=f"{str(zmetre)}^2", scale=zmetre.scale * 2) + zmetre3 = Unit.create((zmetre ** 3).unit, name="zmetre3", dispname=f"{str(zmetre)}^3", scale=zmetre.scale * 3) + Mmetre2 = Unit.create((Mmetre ** 2).unit, name="Mmetre2", dispname=f"{str(Mmetre)}^2", scale=Mmetre.scale * 2) + Mmetre3 = Unit.create((Mmetre ** 3).unit, name="Mmetre3", dispname=f"{str(Mmetre)}^3", scale=Mmetre.scale * 3) + kmetre2 = Unit.create((kmetre ** 2).unit, name="kmetre2", dispname=f"{str(kmetre)}^2", scale=kmetre.scale * 2) + kmetre3 = Unit.create((kmetre ** 3).unit, name="kmetre3", dispname=f"{str(kmetre)}^3", scale=kmetre.scale * 3) + Ymetre2 = Unit.create((Ymetre ** 2).unit, name="Ymetre2", dispname=f"{str(Ymetre)}^2", scale=Ymetre.scale * 2) + Ymetre3 = Unit.create((Ymetre ** 3).unit, name="Ymetre3", dispname=f"{str(Ymetre)}^3", scale=Ymetre.scale * 3) + ameter2 = Unit.create((ameter ** 2).unit, name="ameter2", dispname=f"{str(ameter)}^2", scale=ameter.scale * 2) + ameter3 = Unit.create((ameter ** 3).unit, name="ameter3", dispname=f"{str(ameter)}^3", scale=ameter.scale * 3) + cmeter2 = Unit.create((cmeter ** 2).unit, name="cmeter2", dispname=f"{str(cmeter)}^2", scale=cmeter.scale * 2) + cmeter3 = Unit.create((cmeter ** 3).unit, name="cmeter3", dispname=f"{str(cmeter)}^3", scale=cmeter.scale * 3) + Zmeter2 = Unit.create((Zmeter ** 2).unit, name="Zmeter2", dispname=f"{str(Zmeter)}^2", scale=Zmeter.scale * 2) + Zmeter3 = Unit.create((Zmeter ** 3).unit, name="Zmeter3", dispname=f"{str(Zmeter)}^3", scale=Zmeter.scale * 3) + Pmeter2 = Unit.create((Pmeter ** 2).unit, name="Pmeter2", dispname=f"{str(Pmeter)}^2", scale=Pmeter.scale * 2) + Pmeter3 = Unit.create((Pmeter ** 3).unit, name="Pmeter3", dispname=f"{str(Pmeter)}^3", scale=Pmeter.scale * 3) + dmeter2 = Unit.create((dmeter ** 2).unit, name="dmeter2", dispname=f"{str(dmeter)}^2", scale=dmeter.scale * 2) + dmeter3 = Unit.create((dmeter ** 3).unit, name="dmeter3", dispname=f"{str(dmeter)}^3", scale=dmeter.scale * 3) + Gmeter2 = Unit.create((Gmeter ** 2).unit, name="Gmeter2", dispname=f"{str(Gmeter)}^2", scale=Gmeter.scale * 2) + Gmeter3 = Unit.create((Gmeter ** 3).unit, name="Gmeter3", dispname=f"{str(Gmeter)}^3", scale=Gmeter.scale * 3) + fmeter2 = Unit.create((fmeter ** 2).unit, name="fmeter2", dispname=f"{str(fmeter)}^2", scale=fmeter.scale * 2) + fmeter3 = Unit.create((fmeter ** 3).unit, name="fmeter3", dispname=f"{str(fmeter)}^3", scale=fmeter.scale * 3) + hmeter2 = Unit.create((hmeter ** 2).unit, name="hmeter2", dispname=f"{str(hmeter)}^2", scale=hmeter.scale * 2) + hmeter3 = Unit.create((hmeter ** 3).unit, name="hmeter3", dispname=f"{str(hmeter)}^3", scale=hmeter.scale * 3) + dameter2 = Unit.create((dameter ** 2).unit, name="dameter2", dispname=f"{str(dameter)}^2", scale=dameter.scale * 2) + dameter3 = Unit.create((dameter ** 3).unit, name="dameter3", dispname=f"{str(dameter)}^3", scale=dameter.scale * 3) + mmeter2 = Unit.create((mmeter ** 2).unit, name="mmeter2", dispname=f"{str(mmeter)}^2", scale=mmeter.scale * 2) + mmeter3 = Unit.create((mmeter ** 3).unit, name="mmeter3", dispname=f"{str(mmeter)}^3", scale=mmeter.scale * 3) + nmeter2 = Unit.create((nmeter ** 2).unit, name="nmeter2", dispname=f"{str(nmeter)}^2", scale=nmeter.scale * 2) + nmeter3 = Unit.create((nmeter ** 3).unit, name="nmeter3", dispname=f"{str(nmeter)}^3", scale=nmeter.scale * 3) + pmeter2 = Unit.create((pmeter ** 2).unit, name="pmeter2", dispname=f"{str(pmeter)}^2", scale=pmeter.scale * 2) + pmeter3 = Unit.create((pmeter ** 3).unit, name="pmeter3", dispname=f"{str(pmeter)}^3", scale=pmeter.scale * 3) + umeter2 = Unit.create((umeter ** 2).unit, name="umeter2", dispname=f"{str(umeter)}^2", scale=umeter.scale * 2) + umeter3 = Unit.create((umeter ** 3).unit, name="umeter3", dispname=f"{str(umeter)}^3", scale=umeter.scale * 3) + Tmeter2 = Unit.create((Tmeter ** 2).unit, name="Tmeter2", dispname=f"{str(Tmeter)}^2", scale=Tmeter.scale * 2) + Tmeter3 = Unit.create((Tmeter ** 3).unit, name="Tmeter3", dispname=f"{str(Tmeter)}^3", scale=Tmeter.scale * 3) + ymeter2 = Unit.create((ymeter ** 2).unit, name="ymeter2", dispname=f"{str(ymeter)}^2", scale=ymeter.scale * 2) + ymeter3 = Unit.create((ymeter ** 3).unit, name="ymeter3", dispname=f"{str(ymeter)}^3", scale=ymeter.scale * 3) + Emeter2 = Unit.create((Emeter ** 2).unit, name="Emeter2", dispname=f"{str(Emeter)}^2", scale=Emeter.scale * 2) + Emeter3 = Unit.create((Emeter ** 3).unit, name="Emeter3", dispname=f"{str(Emeter)}^3", scale=Emeter.scale * 3) + zmeter2 = Unit.create((zmeter ** 2).unit, name="zmeter2", dispname=f"{str(zmeter)}^2", scale=zmeter.scale * 2) + zmeter3 = Unit.create((zmeter ** 3).unit, name="zmeter3", dispname=f"{str(zmeter)}^3", scale=zmeter.scale * 3) + Mmeter2 = Unit.create((Mmeter ** 2).unit, name="Mmeter2", dispname=f"{str(Mmeter)}^2", scale=Mmeter.scale * 2) + Mmeter3 = Unit.create((Mmeter ** 3).unit, name="Mmeter3", dispname=f"{str(Mmeter)}^3", scale=Mmeter.scale * 3) + kmeter2 = Unit.create((kmeter ** 2).unit, name="kmeter2", dispname=f"{str(kmeter)}^2", scale=kmeter.scale * 2) + kmeter3 = Unit.create((kmeter ** 3).unit, name="kmeter3", dispname=f"{str(kmeter)}^3", scale=kmeter.scale * 3) + Ymeter2 = Unit.create((Ymeter ** 2).unit, name="Ymeter2", dispname=f"{str(Ymeter)}^2", scale=Ymeter.scale * 2) + Ymeter3 = Unit.create((Ymeter ** 3).unit, name="Ymeter3", dispname=f"{str(Ymeter)}^3", scale=Ymeter.scale * 3) + asecond2 = Unit.create((asecond ** 2).unit, name="asecond2", dispname=f"{str(asecond)}^2", scale=asecond.scale * 2) + asecond3 = Unit.create((asecond ** 3).unit, name="asecond3", dispname=f"{str(asecond)}^3", scale=asecond.scale * 3) + csecond2 = Unit.create((csecond ** 2).unit, name="csecond2", dispname=f"{str(csecond)}^2", scale=csecond.scale * 2) + csecond3 = Unit.create((csecond ** 3).unit, name="csecond3", dispname=f"{str(csecond)}^3", scale=csecond.scale * 3) + Zsecond2 = Unit.create((Zsecond ** 2).unit, name="Zsecond2", dispname=f"{str(Zsecond)}^2", scale=Zsecond.scale * 2) + Zsecond3 = Unit.create((Zsecond ** 3).unit, name="Zsecond3", dispname=f"{str(Zsecond)}^3", scale=Zsecond.scale * 3) + Psecond2 = Unit.create((Psecond ** 2).unit, name="Psecond2", dispname=f"{str(Psecond)}^2", scale=Psecond.scale * 2) + Psecond3 = Unit.create((Psecond ** 3).unit, name="Psecond3", dispname=f"{str(Psecond)}^3", scale=Psecond.scale * 3) + dsecond2 = Unit.create((dsecond ** 2).unit, name="dsecond2", dispname=f"{str(dsecond)}^2", scale=dsecond.scale * 2) + dsecond3 = Unit.create((dsecond ** 3).unit, name="dsecond3", dispname=f"{str(dsecond)}^3", scale=dsecond.scale * 3) + Gsecond2 = Unit.create((Gsecond ** 2).unit, name="Gsecond2", dispname=f"{str(Gsecond)}^2", scale=Gsecond.scale * 2) + Gsecond3 = Unit.create((Gsecond ** 3).unit, name="Gsecond3", dispname=f"{str(Gsecond)}^3", scale=Gsecond.scale * 3) + fsecond2 = Unit.create((fsecond ** 2).unit, name="fsecond2", dispname=f"{str(fsecond)}^2", scale=fsecond.scale * 2) + fsecond3 = Unit.create((fsecond ** 3).unit, name="fsecond3", dispname=f"{str(fsecond)}^3", scale=fsecond.scale * 3) + hsecond2 = Unit.create((hsecond ** 2).unit, name="hsecond2", dispname=f"{str(hsecond)}^2", scale=hsecond.scale * 2) + hsecond3 = Unit.create((hsecond ** 3).unit, name="hsecond3", dispname=f"{str(hsecond)}^3", scale=hsecond.scale * 3) + dasecond2 = Unit.create((dasecond ** 2).unit, name="dasecond2", dispname=f"{str(dasecond)}^2", + scale=dasecond.scale * 2) + dasecond3 = Unit.create((dasecond ** 3).unit, name="dasecond3", dispname=f"{str(dasecond)}^3", + scale=dasecond.scale * 3) + msecond2 = Unit.create((msecond ** 2).unit, name="msecond2", dispname=f"{str(msecond)}^2", scale=msecond.scale * 2) + msecond3 = Unit.create((msecond ** 3).unit, name="msecond3", dispname=f"{str(msecond)}^3", scale=msecond.scale * 3) + nsecond2 = Unit.create((nsecond ** 2).unit, name="nsecond2", dispname=f"{str(nsecond)}^2", scale=nsecond.scale * 2) + nsecond3 = Unit.create((nsecond ** 3).unit, name="nsecond3", dispname=f"{str(nsecond)}^3", scale=nsecond.scale * 3) + psecond2 = Unit.create((psecond ** 2).unit, name="psecond2", dispname=f"{str(psecond)}^2", scale=psecond.scale * 2) + psecond3 = Unit.create((psecond ** 3).unit, name="psecond3", dispname=f"{str(psecond)}^3", scale=psecond.scale * 3) + usecond2 = Unit.create((usecond ** 2).unit, name="usecond2", dispname=f"{str(usecond)}^2", scale=usecond.scale * 2) + usecond3 = Unit.create((usecond ** 3).unit, name="usecond3", dispname=f"{str(usecond)}^3", scale=usecond.scale * 3) + Tsecond2 = Unit.create((Tsecond ** 2).unit, name="Tsecond2", dispname=f"{str(Tsecond)}^2", scale=Tsecond.scale * 2) + Tsecond3 = Unit.create((Tsecond ** 3).unit, name="Tsecond3", dispname=f"{str(Tsecond)}^3", scale=Tsecond.scale * 3) + ysecond2 = Unit.create((ysecond ** 2).unit, name="ysecond2", dispname=f"{str(ysecond)}^2", scale=ysecond.scale * 2) + ysecond3 = Unit.create((ysecond ** 3).unit, name="ysecond3", dispname=f"{str(ysecond)}^3", scale=ysecond.scale * 3) + Esecond2 = Unit.create((Esecond ** 2).unit, name="Esecond2", dispname=f"{str(Esecond)}^2", scale=Esecond.scale * 2) + Esecond3 = Unit.create((Esecond ** 3).unit, name="Esecond3", dispname=f"{str(Esecond)}^3", scale=Esecond.scale * 3) + zsecond2 = Unit.create((zsecond ** 2).unit, name="zsecond2", dispname=f"{str(zsecond)}^2", scale=zsecond.scale * 2) + zsecond3 = Unit.create((zsecond ** 3).unit, name="zsecond3", dispname=f"{str(zsecond)}^3", scale=zsecond.scale * 3) + Msecond2 = Unit.create((Msecond ** 2).unit, name="Msecond2", dispname=f"{str(Msecond)}^2", scale=Msecond.scale * 2) + Msecond3 = Unit.create((Msecond ** 3).unit, name="Msecond3", dispname=f"{str(Msecond)}^3", scale=Msecond.scale * 3) + ksecond2 = Unit.create((ksecond ** 2).unit, name="ksecond2", dispname=f"{str(ksecond)}^2", scale=ksecond.scale * 2) + ksecond3 = Unit.create((ksecond ** 3).unit, name="ksecond3", dispname=f"{str(ksecond)}^3", scale=ksecond.scale * 3) + Ysecond2 = Unit.create((Ysecond ** 2).unit, name="Ysecond2", dispname=f"{str(Ysecond)}^2", scale=Ysecond.scale * 2) + Ysecond3 = Unit.create((Ysecond ** 3).unit, name="Ysecond3", dispname=f"{str(Ysecond)}^3", scale=Ysecond.scale * 3) + aamp2 = Unit.create((aamp ** 2).unit, name="aamp2", dispname=f"{str(aamp)}^2", scale=aamp.scale * 2) + aamp3 = Unit.create((aamp ** 3).unit, name="aamp3", dispname=f"{str(aamp)}^3", scale=aamp.scale * 3) + camp2 = Unit.create((camp ** 2).unit, name="camp2", dispname=f"{str(camp)}^2", scale=camp.scale * 2) + camp3 = Unit.create((camp ** 3).unit, name="camp3", dispname=f"{str(camp)}^3", scale=camp.scale * 3) + Zamp2 = Unit.create((Zamp ** 2).unit, name="Zamp2", dispname=f"{str(Zamp)}^2", scale=Zamp.scale * 2) + Zamp3 = Unit.create((Zamp ** 3).unit, name="Zamp3", dispname=f"{str(Zamp)}^3", scale=Zamp.scale * 3) + Pamp2 = Unit.create((Pamp ** 2).unit, name="Pamp2", dispname=f"{str(Pamp)}^2", scale=Pamp.scale * 2) + Pamp3 = Unit.create((Pamp ** 3).unit, name="Pamp3", dispname=f"{str(Pamp)}^3", scale=Pamp.scale * 3) + damp2 = Unit.create((damp ** 2).unit, name="damp2", dispname=f"{str(damp)}^2", scale=damp.scale * 2) + damp3 = Unit.create((damp ** 3).unit, name="damp3", dispname=f"{str(damp)}^3", scale=damp.scale * 3) + Gamp2 = Unit.create((Gamp ** 2).unit, name="Gamp2", dispname=f"{str(Gamp)}^2", scale=Gamp.scale * 2) + Gamp3 = Unit.create((Gamp ** 3).unit, name="Gamp3", dispname=f"{str(Gamp)}^3", scale=Gamp.scale * 3) + famp2 = Unit.create((famp ** 2).unit, name="famp2", dispname=f"{str(famp)}^2", scale=famp.scale * 2) + famp3 = Unit.create((famp ** 3).unit, name="famp3", dispname=f"{str(famp)}^3", scale=famp.scale * 3) + hamp2 = Unit.create((hamp ** 2).unit, name="hamp2", dispname=f"{str(hamp)}^2", scale=hamp.scale * 2) + hamp3 = Unit.create((hamp ** 3).unit, name="hamp3", dispname=f"{str(hamp)}^3", scale=hamp.scale * 3) + daamp2 = Unit.create((daamp ** 2).unit, name="daamp2", dispname=f"{str(daamp)}^2", scale=daamp.scale * 2) + daamp3 = Unit.create((daamp ** 3).unit, name="daamp3", dispname=f"{str(daamp)}^3", scale=daamp.scale * 3) + mamp2 = Unit.create((mamp ** 2).unit, name="mamp2", dispname=f"{str(mamp)}^2", scale=mamp.scale * 2) + mamp3 = Unit.create((mamp ** 3).unit, name="mamp3", dispname=f"{str(mamp)}^3", scale=mamp.scale * 3) + namp2 = Unit.create((namp ** 2).unit, name="namp2", dispname=f"{str(namp)}^2", scale=namp.scale * 2) + namp3 = Unit.create((namp ** 3).unit, name="namp3", dispname=f"{str(namp)}^3", scale=namp.scale * 3) + pamp2 = Unit.create((pamp ** 2).unit, name="pamp2", dispname=f"{str(pamp)}^2", scale=pamp.scale * 2) + pamp3 = Unit.create((pamp ** 3).unit, name="pamp3", dispname=f"{str(pamp)}^3", scale=pamp.scale * 3) + uamp2 = Unit.create((uamp ** 2).unit, name="uamp2", dispname=f"{str(uamp)}^2", scale=uamp.scale * 2) + uamp3 = Unit.create((uamp ** 3).unit, name="uamp3", dispname=f"{str(uamp)}^3", scale=uamp.scale * 3) + Tamp2 = Unit.create((Tamp ** 2).unit, name="Tamp2", dispname=f"{str(Tamp)}^2", scale=Tamp.scale * 2) + Tamp3 = Unit.create((Tamp ** 3).unit, name="Tamp3", dispname=f"{str(Tamp)}^3", scale=Tamp.scale * 3) + yamp2 = Unit.create((yamp ** 2).unit, name="yamp2", dispname=f"{str(yamp)}^2", scale=yamp.scale * 2) + yamp3 = Unit.create((yamp ** 3).unit, name="yamp3", dispname=f"{str(yamp)}^3", scale=yamp.scale * 3) + Eamp2 = Unit.create((Eamp ** 2).unit, name="Eamp2", dispname=f"{str(Eamp)}^2", scale=Eamp.scale * 2) + Eamp3 = Unit.create((Eamp ** 3).unit, name="Eamp3", dispname=f"{str(Eamp)}^3", scale=Eamp.scale * 3) + zamp2 = Unit.create((zamp ** 2).unit, name="zamp2", dispname=f"{str(zamp)}^2", scale=zamp.scale * 2) + zamp3 = Unit.create((zamp ** 3).unit, name="zamp3", dispname=f"{str(zamp)}^3", scale=zamp.scale * 3) + Mamp2 = Unit.create((Mamp ** 2).unit, name="Mamp2", dispname=f"{str(Mamp)}^2", scale=Mamp.scale * 2) + Mamp3 = Unit.create((Mamp ** 3).unit, name="Mamp3", dispname=f"{str(Mamp)}^3", scale=Mamp.scale * 3) + kamp2 = Unit.create((kamp ** 2).unit, name="kamp2", dispname=f"{str(kamp)}^2", scale=kamp.scale * 2) + kamp3 = Unit.create((kamp ** 3).unit, name="kamp3", dispname=f"{str(kamp)}^3", scale=kamp.scale * 3) + Yamp2 = Unit.create((Yamp ** 2).unit, name="Yamp2", dispname=f"{str(Yamp)}^2", scale=Yamp.scale * 2) + Yamp3 = Unit.create((Yamp ** 3).unit, name="Yamp3", dispname=f"{str(Yamp)}^3", scale=Yamp.scale * 3) + aampere2 = Unit.create((aampere ** 2).unit, name="aampere2", dispname=f"{str(aampere)}^2", scale=aampere.scale * 2) + aampere3 = Unit.create((aampere ** 3).unit, name="aampere3", dispname=f"{str(aampere)}^3", scale=aampere.scale * 3) + campere2 = Unit.create((campere ** 2).unit, name="campere2", dispname=f"{str(campere)}^2", scale=campere.scale * 2) + campere3 = Unit.create((campere ** 3).unit, name="campere3", dispname=f"{str(campere)}^3", scale=campere.scale * 3) + Zampere2 = Unit.create((Zampere ** 2).unit, name="Zampere2", dispname=f"{str(Zampere)}^2", scale=Zampere.scale * 2) + Zampere3 = Unit.create((Zampere ** 3).unit, name="Zampere3", dispname=f"{str(Zampere)}^3", scale=Zampere.scale * 3) + Pampere2 = Unit.create((Pampere ** 2).unit, name="Pampere2", dispname=f"{str(Pampere)}^2", scale=Pampere.scale * 2) + Pampere3 = Unit.create((Pampere ** 3).unit, name="Pampere3", dispname=f"{str(Pampere)}^3", scale=Pampere.scale * 3) + dampere2 = Unit.create((dampere ** 2).unit, name="dampere2", dispname=f"{str(dampere)}^2", scale=dampere.scale * 2) + dampere3 = Unit.create((dampere ** 3).unit, name="dampere3", dispname=f"{str(dampere)}^3", scale=dampere.scale * 3) + Gampere2 = Unit.create((Gampere ** 2).unit, name="Gampere2", dispname=f"{str(Gampere)}^2", scale=Gampere.scale * 2) + Gampere3 = Unit.create((Gampere ** 3).unit, name="Gampere3", dispname=f"{str(Gampere)}^3", scale=Gampere.scale * 3) + fampere2 = Unit.create((fampere ** 2).unit, name="fampere2", dispname=f"{str(fampere)}^2", scale=fampere.scale * 2) + fampere3 = Unit.create((fampere ** 3).unit, name="fampere3", dispname=f"{str(fampere)}^3", scale=fampere.scale * 3) + hampere2 = Unit.create((hampere ** 2).unit, name="hampere2", dispname=f"{str(hampere)}^2", scale=hampere.scale * 2) + hampere3 = Unit.create((hampere ** 3).unit, name="hampere3", dispname=f"{str(hampere)}^3", scale=hampere.scale * 3) + daampere2 = Unit.create((daampere ** 2).unit, name="daampere2", dispname=f"{str(daampere)}^2", + scale=daampere.scale * 2) + daampere3 = Unit.create((daampere ** 3).unit, name="daampere3", dispname=f"{str(daampere)}^3", + scale=daampere.scale * 3) + mampere2 = Unit.create((mampere ** 2).unit, name="mampere2", dispname=f"{str(mampere)}^2", scale=mampere.scale * 2) + mampere3 = Unit.create((mampere ** 3).unit, name="mampere3", dispname=f"{str(mampere)}^3", scale=mampere.scale * 3) + nampere2 = Unit.create((nampere ** 2).unit, name="nampere2", dispname=f"{str(nampere)}^2", scale=nampere.scale * 2) + nampere3 = Unit.create((nampere ** 3).unit, name="nampere3", dispname=f"{str(nampere)}^3", scale=nampere.scale * 3) + pampere2 = Unit.create((pampere ** 2).unit, name="pampere2", dispname=f"{str(pampere)}^2", scale=pampere.scale * 2) + pampere3 = Unit.create((pampere ** 3).unit, name="pampere3", dispname=f"{str(pampere)}^3", scale=pampere.scale * 3) + uampere2 = Unit.create((uampere ** 2).unit, name="uampere2", dispname=f"{str(uampere)}^2", scale=uampere.scale * 2) + uampere3 = Unit.create((uampere ** 3).unit, name="uampere3", dispname=f"{str(uampere)}^3", scale=uampere.scale * 3) + Tampere2 = Unit.create((Tampere ** 2).unit, name="Tampere2", dispname=f"{str(Tampere)}^2", scale=Tampere.scale * 2) + Tampere3 = Unit.create((Tampere ** 3).unit, name="Tampere3", dispname=f"{str(Tampere)}^3", scale=Tampere.scale * 3) + yampere2 = Unit.create((yampere ** 2).unit, name="yampere2", dispname=f"{str(yampere)}^2", scale=yampere.scale * 2) + yampere3 = Unit.create((yampere ** 3).unit, name="yampere3", dispname=f"{str(yampere)}^3", scale=yampere.scale * 3) + Eampere2 = Unit.create((Eampere ** 2).unit, name="Eampere2", dispname=f"{str(Eampere)}^2", scale=Eampere.scale * 2) + Eampere3 = Unit.create((Eampere ** 3).unit, name="Eampere3", dispname=f"{str(Eampere)}^3", scale=Eampere.scale * 3) + zampere2 = Unit.create((zampere ** 2).unit, name="zampere2", dispname=f"{str(zampere)}^2", scale=zampere.scale * 2) + zampere3 = Unit.create((zampere ** 3).unit, name="zampere3", dispname=f"{str(zampere)}^3", scale=zampere.scale * 3) + Mampere2 = Unit.create((Mampere ** 2).unit, name="Mampere2", dispname=f"{str(Mampere)}^2", scale=Mampere.scale * 2) + Mampere3 = Unit.create((Mampere ** 3).unit, name="Mampere3", dispname=f"{str(Mampere)}^3", scale=Mampere.scale * 3) + kampere2 = Unit.create((kampere ** 2).unit, name="kampere2", dispname=f"{str(kampere)}^2", scale=kampere.scale * 2) + kampere3 = Unit.create((kampere ** 3).unit, name="kampere3", dispname=f"{str(kampere)}^3", scale=kampere.scale * 3) + Yampere2 = Unit.create((Yampere ** 2).unit, name="Yampere2", dispname=f"{str(Yampere)}^2", scale=Yampere.scale * 2) + Yampere3 = Unit.create((Yampere ** 3).unit, name="Yampere3", dispname=f"{str(Yampere)}^3", scale=Yampere.scale * 3) + amole2 = Unit.create((amole ** 2).unit, name="amole2", dispname=f"{str(amole)}^2", scale=amole.scale * 2) + amole3 = Unit.create((amole ** 3).unit, name="amole3", dispname=f"{str(amole)}^3", scale=amole.scale * 3) + cmole2 = Unit.create((cmole ** 2).unit, name="cmole2", dispname=f"{str(cmole)}^2", scale=cmole.scale * 2) + cmole3 = Unit.create((cmole ** 3).unit, name="cmole3", dispname=f"{str(cmole)}^3", scale=cmole.scale * 3) + Zmole2 = Unit.create((Zmole ** 2).unit, name="Zmole2", dispname=f"{str(Zmole)}^2", scale=Zmole.scale * 2) + Zmole3 = Unit.create((Zmole ** 3).unit, name="Zmole3", dispname=f"{str(Zmole)}^3", scale=Zmole.scale * 3) + Pmole2 = Unit.create((Pmole ** 2).unit, name="Pmole2", dispname=f"{str(Pmole)}^2", scale=Pmole.scale * 2) + Pmole3 = Unit.create((Pmole ** 3).unit, name="Pmole3", dispname=f"{str(Pmole)}^3", scale=Pmole.scale * 3) + dmole2 = Unit.create((dmole ** 2).unit, name="dmole2", dispname=f"{str(dmole)}^2", scale=dmole.scale * 2) + dmole3 = Unit.create((dmole ** 3).unit, name="dmole3", dispname=f"{str(dmole)}^3", scale=dmole.scale * 3) + Gmole2 = Unit.create((Gmole ** 2).unit, name="Gmole2", dispname=f"{str(Gmole)}^2", scale=Gmole.scale * 2) + Gmole3 = Unit.create((Gmole ** 3).unit, name="Gmole3", dispname=f"{str(Gmole)}^3", scale=Gmole.scale * 3) + fmole2 = Unit.create((fmole ** 2).unit, name="fmole2", dispname=f"{str(fmole)}^2", scale=fmole.scale * 2) + fmole3 = Unit.create((fmole ** 3).unit, name="fmole3", dispname=f"{str(fmole)}^3", scale=fmole.scale * 3) + hmole2 = Unit.create((hmole ** 2).unit, name="hmole2", dispname=f"{str(hmole)}^2", scale=hmole.scale * 2) + hmole3 = Unit.create((hmole ** 3).unit, name="hmole3", dispname=f"{str(hmole)}^3", scale=hmole.scale * 3) + damole2 = Unit.create((damole ** 2).unit, name="damole2", dispname=f"{str(damole)}^2", scale=damole.scale * 2) + damole3 = Unit.create((damole ** 3).unit, name="damole3", dispname=f"{str(damole)}^3", scale=damole.scale * 3) + mmole2 = Unit.create((mmole ** 2).unit, name="mmole2", dispname=f"{str(mmole)}^2", scale=mmole.scale * 2) + mmole3 = Unit.create((mmole ** 3).unit, name="mmole3", dispname=f"{str(mmole)}^3", scale=mmole.scale * 3) + nmole2 = Unit.create((nmole ** 2).unit, name="nmole2", dispname=f"{str(nmole)}^2", scale=nmole.scale * 2) + nmole3 = Unit.create((nmole ** 3).unit, name="nmole3", dispname=f"{str(nmole)}^3", scale=nmole.scale * 3) + pmole2 = Unit.create((pmole ** 2).unit, name="pmole2", dispname=f"{str(pmole)}^2", scale=pmole.scale * 2) + pmole3 = Unit.create((pmole ** 3).unit, name="pmole3", dispname=f"{str(pmole)}^3", scale=pmole.scale * 3) + umole2 = Unit.create((umole ** 2).unit, name="umole2", dispname=f"{str(umole)}^2", scale=umole.scale * 2) + umole3 = Unit.create((umole ** 3).unit, name="umole3", dispname=f"{str(umole)}^3", scale=umole.scale * 3) + Tmole2 = Unit.create((Tmole ** 2).unit, name="Tmole2", dispname=f"{str(Tmole)}^2", scale=Tmole.scale * 2) + Tmole3 = Unit.create((Tmole ** 3).unit, name="Tmole3", dispname=f"{str(Tmole)}^3", scale=Tmole.scale * 3) + ymole2 = Unit.create((ymole ** 2).unit, name="ymole2", dispname=f"{str(ymole)}^2", scale=ymole.scale * 2) + ymole3 = Unit.create((ymole ** 3).unit, name="ymole3", dispname=f"{str(ymole)}^3", scale=ymole.scale * 3) + Emole2 = Unit.create((Emole ** 2).unit, name="Emole2", dispname=f"{str(Emole)}^2", scale=Emole.scale * 2) + Emole3 = Unit.create((Emole ** 3).unit, name="Emole3", dispname=f"{str(Emole)}^3", scale=Emole.scale * 3) + zmole2 = Unit.create((zmole ** 2).unit, name="zmole2", dispname=f"{str(zmole)}^2", scale=zmole.scale * 2) + zmole3 = Unit.create((zmole ** 3).unit, name="zmole3", dispname=f"{str(zmole)}^3", scale=zmole.scale * 3) + Mmole2 = Unit.create((Mmole ** 2).unit, name="Mmole2", dispname=f"{str(Mmole)}^2", scale=Mmole.scale * 2) + Mmole3 = Unit.create((Mmole ** 3).unit, name="Mmole3", dispname=f"{str(Mmole)}^3", scale=Mmole.scale * 3) + kmole2 = Unit.create((kmole ** 2).unit, name="kmole2", dispname=f"{str(kmole)}^2", scale=kmole.scale * 2) + kmole3 = Unit.create((kmole ** 3).unit, name="kmole3", dispname=f"{str(kmole)}^3", scale=kmole.scale * 3) + Ymole2 = Unit.create((Ymole ** 2).unit, name="Ymole2", dispname=f"{str(Ymole)}^2", scale=Ymole.scale * 2) + Ymole3 = Unit.create((Ymole ** 3).unit, name="Ymole3", dispname=f"{str(Ymole)}^3", scale=Ymole.scale * 3) + amol2 = Unit.create((amol ** 2).unit, name="amol2", dispname=f"{str(amol)}^2", scale=amol.scale * 2) + amol3 = Unit.create((amol ** 3).unit, name="amol3", dispname=f"{str(amol)}^3", scale=amol.scale * 3) + cmol2 = Unit.create((cmol ** 2).unit, name="cmol2", dispname=f"{str(cmol)}^2", scale=cmol.scale * 2) + cmol3 = Unit.create((cmol ** 3).unit, name="cmol3", dispname=f"{str(cmol)}^3", scale=cmol.scale * 3) + Zmol2 = Unit.create((Zmol ** 2).unit, name="Zmol2", dispname=f"{str(Zmol)}^2", scale=Zmol.scale * 2) + Zmol3 = Unit.create((Zmol ** 3).unit, name="Zmol3", dispname=f"{str(Zmol)}^3", scale=Zmol.scale * 3) + Pmol2 = Unit.create((Pmol ** 2).unit, name="Pmol2", dispname=f"{str(Pmol)}^2", scale=Pmol.scale * 2) + Pmol3 = Unit.create((Pmol ** 3).unit, name="Pmol3", dispname=f"{str(Pmol)}^3", scale=Pmol.scale * 3) + dmol2 = Unit.create((dmol ** 2).unit, name="dmol2", dispname=f"{str(dmol)}^2", scale=dmol.scale * 2) + dmol3 = Unit.create((dmol ** 3).unit, name="dmol3", dispname=f"{str(dmol)}^3", scale=dmol.scale * 3) + Gmol2 = Unit.create((Gmol ** 2).unit, name="Gmol2", dispname=f"{str(Gmol)}^2", scale=Gmol.scale * 2) + Gmol3 = Unit.create((Gmol ** 3).unit, name="Gmol3", dispname=f"{str(Gmol)}^3", scale=Gmol.scale * 3) + fmol2 = Unit.create((fmol ** 2).unit, name="fmol2", dispname=f"{str(fmol)}^2", scale=fmol.scale * 2) + fmol3 = Unit.create((fmol ** 3).unit, name="fmol3", dispname=f"{str(fmol)}^3", scale=fmol.scale * 3) + hmol2 = Unit.create((hmol ** 2).unit, name="hmol2", dispname=f"{str(hmol)}^2", scale=hmol.scale * 2) + hmol3 = Unit.create((hmol ** 3).unit, name="hmol3", dispname=f"{str(hmol)}^3", scale=hmol.scale * 3) + damol2 = Unit.create((damol ** 2).unit, name="damol2", dispname=f"{str(damol)}^2", scale=damol.scale * 2) + damol3 = Unit.create((damol ** 3).unit, name="damol3", dispname=f"{str(damol)}^3", scale=damol.scale * 3) + mmol2 = Unit.create((mmol ** 2).unit, name="mmol2", dispname=f"{str(mmol)}^2", scale=mmol.scale * 2) + mmol3 = Unit.create((mmol ** 3).unit, name="mmol3", dispname=f"{str(mmol)}^3", scale=mmol.scale * 3) + nmol2 = Unit.create((nmol ** 2).unit, name="nmol2", dispname=f"{str(nmol)}^2", scale=nmol.scale * 2) + nmol3 = Unit.create((nmol ** 3).unit, name="nmol3", dispname=f"{str(nmol)}^3", scale=nmol.scale * 3) + pmol2 = Unit.create((pmol ** 2).unit, name="pmol2", dispname=f"{str(pmol)}^2", scale=pmol.scale * 2) + pmol3 = Unit.create((pmol ** 3).unit, name="pmol3", dispname=f"{str(pmol)}^3", scale=pmol.scale * 3) + umol2 = Unit.create((umol ** 2).unit, name="umol2", dispname=f"{str(umol)}^2", scale=umol.scale * 2) + umol3 = Unit.create((umol ** 3).unit, name="umol3", dispname=f"{str(umol)}^3", scale=umol.scale * 3) + Tmol2 = Unit.create((Tmol ** 2).unit, name="Tmol2", dispname=f"{str(Tmol)}^2", scale=Tmol.scale * 2) + Tmol3 = Unit.create((Tmol ** 3).unit, name="Tmol3", dispname=f"{str(Tmol)}^3", scale=Tmol.scale * 3) + ymol2 = Unit.create((ymol ** 2).unit, name="ymol2", dispname=f"{str(ymol)}^2", scale=ymol.scale * 2) + ymol3 = Unit.create((ymol ** 3).unit, name="ymol3", dispname=f"{str(ymol)}^3", scale=ymol.scale * 3) + Emol2 = Unit.create((Emol ** 2).unit, name="Emol2", dispname=f"{str(Emol)}^2", scale=Emol.scale * 2) + Emol3 = Unit.create((Emol ** 3).unit, name="Emol3", dispname=f"{str(Emol)}^3", scale=Emol.scale * 3) + zmol2 = Unit.create((zmol ** 2).unit, name="zmol2", dispname=f"{str(zmol)}^2", scale=zmol.scale * 2) + zmol3 = Unit.create((zmol ** 3).unit, name="zmol3", dispname=f"{str(zmol)}^3", scale=zmol.scale * 3) + Mmol2 = Unit.create((Mmol ** 2).unit, name="Mmol2", dispname=f"{str(Mmol)}^2", scale=Mmol.scale * 2) + Mmol3 = Unit.create((Mmol ** 3).unit, name="Mmol3", dispname=f"{str(Mmol)}^3", scale=Mmol.scale * 3) + kmol2 = Unit.create((kmol ** 2).unit, name="kmol2", dispname=f"{str(kmol)}^2", scale=kmol.scale * 2) + kmol3 = Unit.create((kmol ** 3).unit, name="kmol3", dispname=f"{str(kmol)}^3", scale=kmol.scale * 3) + Ymol2 = Unit.create((Ymol ** 2).unit, name="Ymol2", dispname=f"{str(Ymol)}^2", scale=Ymol.scale * 2) + Ymol3 = Unit.create((Ymol ** 3).unit, name="Ymol3", dispname=f"{str(Ymol)}^3", scale=Ymol.scale * 3) + acandle2 = Unit.create((acandle ** 2).unit, name="acandle2", dispname=f"{str(acandle)}^2", scale=acandle.scale * 2) + acandle3 = Unit.create((acandle ** 3).unit, name="acandle3", dispname=f"{str(acandle)}^3", scale=acandle.scale * 3) + ccandle2 = Unit.create((ccandle ** 2).unit, name="ccandle2", dispname=f"{str(ccandle)}^2", scale=ccandle.scale * 2) + ccandle3 = Unit.create((ccandle ** 3).unit, name="ccandle3", dispname=f"{str(ccandle)}^3", scale=ccandle.scale * 3) + Zcandle2 = Unit.create((Zcandle ** 2).unit, name="Zcandle2", dispname=f"{str(Zcandle)}^2", scale=Zcandle.scale * 2) + Zcandle3 = Unit.create((Zcandle ** 3).unit, name="Zcandle3", dispname=f"{str(Zcandle)}^3", scale=Zcandle.scale * 3) + Pcandle2 = Unit.create((Pcandle ** 2).unit, name="Pcandle2", dispname=f"{str(Pcandle)}^2", scale=Pcandle.scale * 2) + Pcandle3 = Unit.create((Pcandle ** 3).unit, name="Pcandle3", dispname=f"{str(Pcandle)}^3", scale=Pcandle.scale * 3) + dcandle2 = Unit.create((dcandle ** 2).unit, name="dcandle2", dispname=f"{str(dcandle)}^2", scale=dcandle.scale * 2) + dcandle3 = Unit.create((dcandle ** 3).unit, name="dcandle3", dispname=f"{str(dcandle)}^3", scale=dcandle.scale * 3) + Gcandle2 = Unit.create((Gcandle ** 2).unit, name="Gcandle2", dispname=f"{str(Gcandle)}^2", scale=Gcandle.scale * 2) + Gcandle3 = Unit.create((Gcandle ** 3).unit, name="Gcandle3", dispname=f"{str(Gcandle)}^3", scale=Gcandle.scale * 3) + fcandle2 = Unit.create((fcandle ** 2).unit, name="fcandle2", dispname=f"{str(fcandle)}^2", scale=fcandle.scale * 2) + fcandle3 = Unit.create((fcandle ** 3).unit, name="fcandle3", dispname=f"{str(fcandle)}^3", scale=fcandle.scale * 3) + hcandle2 = Unit.create((hcandle ** 2).unit, name="hcandle2", dispname=f"{str(hcandle)}^2", scale=hcandle.scale * 2) + hcandle3 = Unit.create((hcandle ** 3).unit, name="hcandle3", dispname=f"{str(hcandle)}^3", scale=hcandle.scale * 3) + dacandle2 = Unit.create((dacandle ** 2).unit, name="dacandle2", dispname=f"{str(dacandle)}^2", + scale=dacandle.scale * 2) + dacandle3 = Unit.create((dacandle ** 3).unit, name="dacandle3", dispname=f"{str(dacandle)}^3", + scale=dacandle.scale * 3) + mcandle2 = Unit.create((mcandle ** 2).unit, name="mcandle2", dispname=f"{str(mcandle)}^2", scale=mcandle.scale * 2) + mcandle3 = Unit.create((mcandle ** 3).unit, name="mcandle3", dispname=f"{str(mcandle)}^3", scale=mcandle.scale * 3) + ncandle2 = Unit.create((ncandle ** 2).unit, name="ncandle2", dispname=f"{str(ncandle)}^2", scale=ncandle.scale * 2) + ncandle3 = Unit.create((ncandle ** 3).unit, name="ncandle3", dispname=f"{str(ncandle)}^3", scale=ncandle.scale * 3) + pcandle2 = Unit.create((pcandle ** 2).unit, name="pcandle2", dispname=f"{str(pcandle)}^2", scale=pcandle.scale * 2) + pcandle3 = Unit.create((pcandle ** 3).unit, name="pcandle3", dispname=f"{str(pcandle)}^3", scale=pcandle.scale * 3) + ucandle2 = Unit.create((ucandle ** 2).unit, name="ucandle2", dispname=f"{str(ucandle)}^2", scale=ucandle.scale * 2) + ucandle3 = Unit.create((ucandle ** 3).unit, name="ucandle3", dispname=f"{str(ucandle)}^3", scale=ucandle.scale * 3) + Tcandle2 = Unit.create((Tcandle ** 2).unit, name="Tcandle2", dispname=f"{str(Tcandle)}^2", scale=Tcandle.scale * 2) + Tcandle3 = Unit.create((Tcandle ** 3).unit, name="Tcandle3", dispname=f"{str(Tcandle)}^3", scale=Tcandle.scale * 3) + ycandle2 = Unit.create((ycandle ** 2).unit, name="ycandle2", dispname=f"{str(ycandle)}^2", scale=ycandle.scale * 2) + ycandle3 = Unit.create((ycandle ** 3).unit, name="ycandle3", dispname=f"{str(ycandle)}^3", scale=ycandle.scale * 3) + Ecandle2 = Unit.create((Ecandle ** 2).unit, name="Ecandle2", dispname=f"{str(Ecandle)}^2", scale=Ecandle.scale * 2) + Ecandle3 = Unit.create((Ecandle ** 3).unit, name="Ecandle3", dispname=f"{str(Ecandle)}^3", scale=Ecandle.scale * 3) + zcandle2 = Unit.create((zcandle ** 2).unit, name="zcandle2", dispname=f"{str(zcandle)}^2", scale=zcandle.scale * 2) + zcandle3 = Unit.create((zcandle ** 3).unit, name="zcandle3", dispname=f"{str(zcandle)}^3", scale=zcandle.scale * 3) + Mcandle2 = Unit.create((Mcandle ** 2).unit, name="Mcandle2", dispname=f"{str(Mcandle)}^2", scale=Mcandle.scale * 2) + Mcandle3 = Unit.create((Mcandle ** 3).unit, name="Mcandle3", dispname=f"{str(Mcandle)}^3", scale=Mcandle.scale * 3) + kcandle2 = Unit.create((kcandle ** 2).unit, name="kcandle2", dispname=f"{str(kcandle)}^2", scale=kcandle.scale * 2) + kcandle3 = Unit.create((kcandle ** 3).unit, name="kcandle3", dispname=f"{str(kcandle)}^3", scale=kcandle.scale * 3) + Ycandle2 = Unit.create((Ycandle ** 2).unit, name="Ycandle2", dispname=f"{str(Ycandle)}^2", scale=Ycandle.scale * 2) + Ycandle3 = Unit.create((Ycandle ** 3).unit, name="Ycandle3", dispname=f"{str(Ycandle)}^3", scale=Ycandle.scale * 3) + agram2 = Unit.create((agram ** 2).unit, name="agram2", dispname=f"{str(agram)}^2", scale=agram.scale * 2) + agram3 = Unit.create((agram ** 3).unit, name="agram3", dispname=f"{str(agram)}^3", scale=agram.scale * 3) + cgram2 = Unit.create((cgram ** 2).unit, name="cgram2", dispname=f"{str(cgram)}^2", scale=cgram.scale * 2) + cgram3 = Unit.create((cgram ** 3).unit, name="cgram3", dispname=f"{str(cgram)}^3", scale=cgram.scale * 3) + Zgram2 = Unit.create((Zgram ** 2).unit, name="Zgram2", dispname=f"{str(Zgram)}^2", scale=Zgram.scale * 2) + Zgram3 = Unit.create((Zgram ** 3).unit, name="Zgram3", dispname=f"{str(Zgram)}^3", scale=Zgram.scale * 3) + Pgram2 = Unit.create((Pgram ** 2).unit, name="Pgram2", dispname=f"{str(Pgram)}^2", scale=Pgram.scale * 2) + Pgram3 = Unit.create((Pgram ** 3).unit, name="Pgram3", dispname=f"{str(Pgram)}^3", scale=Pgram.scale * 3) + dgram2 = Unit.create((dgram ** 2).unit, name="dgram2", dispname=f"{str(dgram)}^2", scale=dgram.scale * 2) + dgram3 = Unit.create((dgram ** 3).unit, name="dgram3", dispname=f"{str(dgram)}^3", scale=dgram.scale * 3) + Ggram2 = Unit.create((Ggram ** 2).unit, name="Ggram2", dispname=f"{str(Ggram)}^2", scale=Ggram.scale * 2) + Ggram3 = Unit.create((Ggram ** 3).unit, name="Ggram3", dispname=f"{str(Ggram)}^3", scale=Ggram.scale * 3) + fgram2 = Unit.create((fgram ** 2).unit, name="fgram2", dispname=f"{str(fgram)}^2", scale=fgram.scale * 2) + fgram3 = Unit.create((fgram ** 3).unit, name="fgram3", dispname=f"{str(fgram)}^3", scale=fgram.scale * 3) + hgram2 = Unit.create((hgram ** 2).unit, name="hgram2", dispname=f"{str(hgram)}^2", scale=hgram.scale * 2) + hgram3 = Unit.create((hgram ** 3).unit, name="hgram3", dispname=f"{str(hgram)}^3", scale=hgram.scale * 3) + dagram2 = Unit.create((dagram ** 2).unit, name="dagram2", dispname=f"{str(dagram)}^2", scale=dagram.scale * 2) + dagram3 = Unit.create((dagram ** 3).unit, name="dagram3", dispname=f"{str(dagram)}^3", scale=dagram.scale * 3) + mgram2 = Unit.create((mgram ** 2).unit, name="mgram2", dispname=f"{str(mgram)}^2", scale=mgram.scale * 2) + mgram3 = Unit.create((mgram ** 3).unit, name="mgram3", dispname=f"{str(mgram)}^3", scale=mgram.scale * 3) + ngram2 = Unit.create((ngram ** 2).unit, name="ngram2", dispname=f"{str(ngram)}^2", scale=ngram.scale * 2) + ngram3 = Unit.create((ngram ** 3).unit, name="ngram3", dispname=f"{str(ngram)}^3", scale=ngram.scale * 3) + pgram2 = Unit.create((pgram ** 2).unit, name="pgram2", dispname=f"{str(pgram)}^2", scale=pgram.scale * 2) + pgram3 = Unit.create((pgram ** 3).unit, name="pgram3", dispname=f"{str(pgram)}^3", scale=pgram.scale * 3) + ugram2 = Unit.create((ugram ** 2).unit, name="ugram2", dispname=f"{str(ugram)}^2", scale=ugram.scale * 2) + ugram3 = Unit.create((ugram ** 3).unit, name="ugram3", dispname=f"{str(ugram)}^3", scale=ugram.scale * 3) + Tgram2 = Unit.create((Tgram ** 2).unit, name="Tgram2", dispname=f"{str(Tgram)}^2", scale=Tgram.scale * 2) + Tgram3 = Unit.create((Tgram ** 3).unit, name="Tgram3", dispname=f"{str(Tgram)}^3", scale=Tgram.scale * 3) + ygram2 = Unit.create((ygram ** 2).unit, name="ygram2", dispname=f"{str(ygram)}^2", scale=ygram.scale * 2) + ygram3 = Unit.create((ygram ** 3).unit, name="ygram3", dispname=f"{str(ygram)}^3", scale=ygram.scale * 3) + Egram2 = Unit.create((Egram ** 2).unit, name="Egram2", dispname=f"{str(Egram)}^2", scale=Egram.scale * 2) + Egram3 = Unit.create((Egram ** 3).unit, name="Egram3", dispname=f"{str(Egram)}^3", scale=Egram.scale * 3) + zgram2 = Unit.create((zgram ** 2).unit, name="zgram2", dispname=f"{str(zgram)}^2", scale=zgram.scale * 2) + zgram3 = Unit.create((zgram ** 3).unit, name="zgram3", dispname=f"{str(zgram)}^3", scale=zgram.scale * 3) + Mgram2 = Unit.create((Mgram ** 2).unit, name="Mgram2", dispname=f"{str(Mgram)}^2", scale=Mgram.scale * 2) + Mgram3 = Unit.create((Mgram ** 3).unit, name="Mgram3", dispname=f"{str(Mgram)}^3", scale=Mgram.scale * 3) + kgram2 = Unit.create((kgram ** 2).unit, name="kgram2", dispname=f"{str(kgram)}^2", scale=kgram.scale * 2) + kgram3 = Unit.create((kgram ** 3).unit, name="kgram3", dispname=f"{str(kgram)}^3", scale=kgram.scale * 3) + Ygram2 = Unit.create((Ygram ** 2).unit, name="Ygram2", dispname=f"{str(Ygram)}^2", scale=Ygram.scale * 2) + Ygram3 = Unit.create((Ygram ** 3).unit, name="Ygram3", dispname=f"{str(Ygram)}^3", scale=Ygram.scale * 3) + agramme2 = Unit.create((agramme ** 2).unit, name="agramme2", dispname=f"{str(agramme)}^2", scale=agramme.scale * 2) + agramme3 = Unit.create((agramme ** 3).unit, name="agramme3", dispname=f"{str(agramme)}^3", scale=agramme.scale * 3) + cgramme2 = Unit.create((cgramme ** 2).unit, name="cgramme2", dispname=f"{str(cgramme)}^2", scale=cgramme.scale * 2) + cgramme3 = Unit.create((cgramme ** 3).unit, name="cgramme3", dispname=f"{str(cgramme)}^3", scale=cgramme.scale * 3) + Zgramme2 = Unit.create((Zgramme ** 2).unit, name="Zgramme2", dispname=f"{str(Zgramme)}^2", scale=Zgramme.scale * 2) + Zgramme3 = Unit.create((Zgramme ** 3).unit, name="Zgramme3", dispname=f"{str(Zgramme)}^3", scale=Zgramme.scale * 3) + Pgramme2 = Unit.create((Pgramme ** 2).unit, name="Pgramme2", dispname=f"{str(Pgramme)}^2", scale=Pgramme.scale * 2) + Pgramme3 = Unit.create((Pgramme ** 3).unit, name="Pgramme3", dispname=f"{str(Pgramme)}^3", scale=Pgramme.scale * 3) + dgramme2 = Unit.create((dgramme ** 2).unit, name="dgramme2", dispname=f"{str(dgramme)}^2", scale=dgramme.scale * 2) + dgramme3 = Unit.create((dgramme ** 3).unit, name="dgramme3", dispname=f"{str(dgramme)}^3", scale=dgramme.scale * 3) + Ggramme2 = Unit.create((Ggramme ** 2).unit, name="Ggramme2", dispname=f"{str(Ggramme)}^2", scale=Ggramme.scale * 2) + Ggramme3 = Unit.create((Ggramme ** 3).unit, name="Ggramme3", dispname=f"{str(Ggramme)}^3", scale=Ggramme.scale * 3) + fgramme2 = Unit.create((fgramme ** 2).unit, name="fgramme2", dispname=f"{str(fgramme)}^2", scale=fgramme.scale * 2) + fgramme3 = Unit.create((fgramme ** 3).unit, name="fgramme3", dispname=f"{str(fgramme)}^3", scale=fgramme.scale * 3) + hgramme2 = Unit.create((hgramme ** 2).unit, name="hgramme2", dispname=f"{str(hgramme)}^2", scale=hgramme.scale * 2) + hgramme3 = Unit.create((hgramme ** 3).unit, name="hgramme3", dispname=f"{str(hgramme)}^3", scale=hgramme.scale * 3) + dagramme2 = Unit.create((dagramme ** 2).unit, name="dagramme2", dispname=f"{str(dagramme)}^2", + scale=dagramme.scale * 2) + dagramme3 = Unit.create((dagramme ** 3).unit, name="dagramme3", dispname=f"{str(dagramme)}^3", + scale=dagramme.scale * 3) + mgramme2 = Unit.create((mgramme ** 2).unit, name="mgramme2", dispname=f"{str(mgramme)}^2", scale=mgramme.scale * 2) + mgramme3 = Unit.create((mgramme ** 3).unit, name="mgramme3", dispname=f"{str(mgramme)}^3", scale=mgramme.scale * 3) + ngramme2 = Unit.create((ngramme ** 2).unit, name="ngramme2", dispname=f"{str(ngramme)}^2", scale=ngramme.scale * 2) + ngramme3 = Unit.create((ngramme ** 3).unit, name="ngramme3", dispname=f"{str(ngramme)}^3", scale=ngramme.scale * 3) + pgramme2 = Unit.create((pgramme ** 2).unit, name="pgramme2", dispname=f"{str(pgramme)}^2", scale=pgramme.scale * 2) + pgramme3 = Unit.create((pgramme ** 3).unit, name="pgramme3", dispname=f"{str(pgramme)}^3", scale=pgramme.scale * 3) + ugramme2 = Unit.create((ugramme ** 2).unit, name="ugramme2", dispname=f"{str(ugramme)}^2", scale=ugramme.scale * 2) + ugramme3 = Unit.create((ugramme ** 3).unit, name="ugramme3", dispname=f"{str(ugramme)}^3", scale=ugramme.scale * 3) + Tgramme2 = Unit.create((Tgramme ** 2).unit, name="Tgramme2", dispname=f"{str(Tgramme)}^2", scale=Tgramme.scale * 2) + Tgramme3 = Unit.create((Tgramme ** 3).unit, name="Tgramme3", dispname=f"{str(Tgramme)}^3", scale=Tgramme.scale * 3) + ygramme2 = Unit.create((ygramme ** 2).unit, name="ygramme2", dispname=f"{str(ygramme)}^2", scale=ygramme.scale * 2) + ygramme3 = Unit.create((ygramme ** 3).unit, name="ygramme3", dispname=f"{str(ygramme)}^3", scale=ygramme.scale * 3) + Egramme2 = Unit.create((Egramme ** 2).unit, name="Egramme2", dispname=f"{str(Egramme)}^2", scale=Egramme.scale * 2) + Egramme3 = Unit.create((Egramme ** 3).unit, name="Egramme3", dispname=f"{str(Egramme)}^3", scale=Egramme.scale * 3) + zgramme2 = Unit.create((zgramme ** 2).unit, name="zgramme2", dispname=f"{str(zgramme)}^2", scale=zgramme.scale * 2) + zgramme3 = Unit.create((zgramme ** 3).unit, name="zgramme3", dispname=f"{str(zgramme)}^3", scale=zgramme.scale * 3) + Mgramme2 = Unit.create((Mgramme ** 2).unit, name="Mgramme2", dispname=f"{str(Mgramme)}^2", scale=Mgramme.scale * 2) + Mgramme3 = Unit.create((Mgramme ** 3).unit, name="Mgramme3", dispname=f"{str(Mgramme)}^3", scale=Mgramme.scale * 3) + kgramme2 = Unit.create((kgramme ** 2).unit, name="kgramme2", dispname=f"{str(kgramme)}^2", scale=kgramme.scale * 2) + kgramme3 = Unit.create((kgramme ** 3).unit, name="kgramme3", dispname=f"{str(kgramme)}^3", scale=kgramme.scale * 3) + Ygramme2 = Unit.create((Ygramme ** 2).unit, name="Ygramme2", dispname=f"{str(Ygramme)}^2", scale=Ygramme.scale * 2) + Ygramme3 = Unit.create((Ygramme ** 3).unit, name="Ygramme3", dispname=f"{str(Ygramme)}^3", scale=Ygramme.scale * 3) + amolar2 = Unit.create((amolar ** 2).unit, name="amolar2", dispname=f"{str(amolar)}^2", scale=amolar.scale * 2) + amolar3 = Unit.create((amolar ** 3).unit, name="amolar3", dispname=f"{str(amolar)}^3", scale=amolar.scale * 3) + cmolar2 = Unit.create((cmolar ** 2).unit, name="cmolar2", dispname=f"{str(cmolar)}^2", scale=cmolar.scale * 2) + cmolar3 = Unit.create((cmolar ** 3).unit, name="cmolar3", dispname=f"{str(cmolar)}^3", scale=cmolar.scale * 3) + Zmolar2 = Unit.create((Zmolar ** 2).unit, name="Zmolar2", dispname=f"{str(Zmolar)}^2", scale=Zmolar.scale * 2) + Zmolar3 = Unit.create((Zmolar ** 3).unit, name="Zmolar3", dispname=f"{str(Zmolar)}^3", scale=Zmolar.scale * 3) + Pmolar2 = Unit.create((Pmolar ** 2).unit, name="Pmolar2", dispname=f"{str(Pmolar)}^2", scale=Pmolar.scale * 2) + Pmolar3 = Unit.create((Pmolar ** 3).unit, name="Pmolar3", dispname=f"{str(Pmolar)}^3", scale=Pmolar.scale * 3) + dmolar2 = Unit.create((dmolar ** 2).unit, name="dmolar2", dispname=f"{str(dmolar)}^2", scale=dmolar.scale * 2) + dmolar3 = Unit.create((dmolar ** 3).unit, name="dmolar3", dispname=f"{str(dmolar)}^3", scale=dmolar.scale * 3) + Gmolar2 = Unit.create((Gmolar ** 2).unit, name="Gmolar2", dispname=f"{str(Gmolar)}^2", scale=Gmolar.scale * 2) + Gmolar3 = Unit.create((Gmolar ** 3).unit, name="Gmolar3", dispname=f"{str(Gmolar)}^3", scale=Gmolar.scale * 3) + fmolar2 = Unit.create((fmolar ** 2).unit, name="fmolar2", dispname=f"{str(fmolar)}^2", scale=fmolar.scale * 2) + fmolar3 = Unit.create((fmolar ** 3).unit, name="fmolar3", dispname=f"{str(fmolar)}^3", scale=fmolar.scale * 3) + hmolar2 = Unit.create((hmolar ** 2).unit, name="hmolar2", dispname=f"{str(hmolar)}^2", scale=hmolar.scale * 2) + hmolar3 = Unit.create((hmolar ** 3).unit, name="hmolar3", dispname=f"{str(hmolar)}^3", scale=hmolar.scale * 3) + damolar2 = Unit.create((damolar ** 2).unit, name="damolar2", dispname=f"{str(damolar)}^2", scale=damolar.scale * 2) + damolar3 = Unit.create((damolar ** 3).unit, name="damolar3", dispname=f"{str(damolar)}^3", scale=damolar.scale * 3) + mmolar2 = Unit.create((mmolar ** 2).unit, name="mmolar2", dispname=f"{str(mmolar)}^2", scale=mmolar.scale * 2) + mmolar3 = Unit.create((mmolar ** 3).unit, name="mmolar3", dispname=f"{str(mmolar)}^3", scale=mmolar.scale * 3) + nmolar2 = Unit.create((nmolar ** 2).unit, name="nmolar2", dispname=f"{str(nmolar)}^2", scale=nmolar.scale * 2) + nmolar3 = Unit.create((nmolar ** 3).unit, name="nmolar3", dispname=f"{str(nmolar)}^3", scale=nmolar.scale * 3) + pmolar2 = Unit.create((pmolar ** 2).unit, name="pmolar2", dispname=f"{str(pmolar)}^2", scale=pmolar.scale * 2) + pmolar3 = Unit.create((pmolar ** 3).unit, name="pmolar3", dispname=f"{str(pmolar)}^3", scale=pmolar.scale * 3) + umolar2 = Unit.create((umolar ** 2).unit, name="umolar2", dispname=f"{str(umolar)}^2", scale=umolar.scale * 2) + umolar3 = Unit.create((umolar ** 3).unit, name="umolar3", dispname=f"{str(umolar)}^3", scale=umolar.scale * 3) + Tmolar2 = Unit.create((Tmolar ** 2).unit, name="Tmolar2", dispname=f"{str(Tmolar)}^2", scale=Tmolar.scale * 2) + Tmolar3 = Unit.create((Tmolar ** 3).unit, name="Tmolar3", dispname=f"{str(Tmolar)}^3", scale=Tmolar.scale * 3) + ymolar2 = Unit.create((ymolar ** 2).unit, name="ymolar2", dispname=f"{str(ymolar)}^2", scale=ymolar.scale * 2) + ymolar3 = Unit.create((ymolar ** 3).unit, name="ymolar3", dispname=f"{str(ymolar)}^3", scale=ymolar.scale * 3) + Emolar2 = Unit.create((Emolar ** 2).unit, name="Emolar2", dispname=f"{str(Emolar)}^2", scale=Emolar.scale * 2) + Emolar3 = Unit.create((Emolar ** 3).unit, name="Emolar3", dispname=f"{str(Emolar)}^3", scale=Emolar.scale * 3) + zmolar2 = Unit.create((zmolar ** 2).unit, name="zmolar2", dispname=f"{str(zmolar)}^2", scale=zmolar.scale * 2) + zmolar3 = Unit.create((zmolar ** 3).unit, name="zmolar3", dispname=f"{str(zmolar)}^3", scale=zmolar.scale * 3) + Mmolar2 = Unit.create((Mmolar ** 2).unit, name="Mmolar2", dispname=f"{str(Mmolar)}^2", scale=Mmolar.scale * 2) + Mmolar3 = Unit.create((Mmolar ** 3).unit, name="Mmolar3", dispname=f"{str(Mmolar)}^3", scale=Mmolar.scale * 3) + kmolar2 = Unit.create((kmolar ** 2).unit, name="kmolar2", dispname=f"{str(kmolar)}^2", scale=kmolar.scale * 2) + kmolar3 = Unit.create((kmolar ** 3).unit, name="kmolar3", dispname=f"{str(kmolar)}^3", scale=kmolar.scale * 3) + Ymolar2 = Unit.create((Ymolar ** 2).unit, name="Ymolar2", dispname=f"{str(Ymolar)}^2", scale=Ymolar.scale * 2) + Ymolar3 = Unit.create((Ymolar ** 3).unit, name="Ymolar3", dispname=f"{str(Ymolar)}^3", scale=Ymolar.scale * 3) + aradian2 = Unit.create((aradian ** 2).unit, name="aradian2", dispname=f"{str(aradian)}^2", scale=aradian.scale * 2) + aradian3 = Unit.create((aradian ** 3).unit, name="aradian3", dispname=f"{str(aradian)}^3", scale=aradian.scale * 3) + cradian2 = Unit.create((cradian ** 2).unit, name="cradian2", dispname=f"{str(cradian)}^2", scale=cradian.scale * 2) + cradian3 = Unit.create((cradian ** 3).unit, name="cradian3", dispname=f"{str(cradian)}^3", scale=cradian.scale * 3) + Zradian2 = Unit.create((Zradian ** 2).unit, name="Zradian2", dispname=f"{str(Zradian)}^2", scale=Zradian.scale * 2) + Zradian3 = Unit.create((Zradian ** 3).unit, name="Zradian3", dispname=f"{str(Zradian)}^3", scale=Zradian.scale * 3) + Pradian2 = Unit.create((Pradian ** 2).unit, name="Pradian2", dispname=f"{str(Pradian)}^2", scale=Pradian.scale * 2) + Pradian3 = Unit.create((Pradian ** 3).unit, name="Pradian3", dispname=f"{str(Pradian)}^3", scale=Pradian.scale * 3) + dradian2 = Unit.create((dradian ** 2).unit, name="dradian2", dispname=f"{str(dradian)}^2", scale=dradian.scale * 2) + dradian3 = Unit.create((dradian ** 3).unit, name="dradian3", dispname=f"{str(dradian)}^3", scale=dradian.scale * 3) + Gradian2 = Unit.create((Gradian ** 2).unit, name="Gradian2", dispname=f"{str(Gradian)}^2", scale=Gradian.scale * 2) + Gradian3 = Unit.create((Gradian ** 3).unit, name="Gradian3", dispname=f"{str(Gradian)}^3", scale=Gradian.scale * 3) + fradian2 = Unit.create((fradian ** 2).unit, name="fradian2", dispname=f"{str(fradian)}^2", scale=fradian.scale * 2) + fradian3 = Unit.create((fradian ** 3).unit, name="fradian3", dispname=f"{str(fradian)}^3", scale=fradian.scale * 3) + hradian2 = Unit.create((hradian ** 2).unit, name="hradian2", dispname=f"{str(hradian)}^2", scale=hradian.scale * 2) + hradian3 = Unit.create((hradian ** 3).unit, name="hradian3", dispname=f"{str(hradian)}^3", scale=hradian.scale * 3) + daradian2 = Unit.create((daradian ** 2).unit, name="daradian2", dispname=f"{str(daradian)}^2", + scale=daradian.scale * 2) + daradian3 = Unit.create((daradian ** 3).unit, name="daradian3", dispname=f"{str(daradian)}^3", + scale=daradian.scale * 3) + mradian2 = Unit.create((mradian ** 2).unit, name="mradian2", dispname=f"{str(mradian)}^2", scale=mradian.scale * 2) + mradian3 = Unit.create((mradian ** 3).unit, name="mradian3", dispname=f"{str(mradian)}^3", scale=mradian.scale * 3) + nradian2 = Unit.create((nradian ** 2).unit, name="nradian2", dispname=f"{str(nradian)}^2", scale=nradian.scale * 2) + nradian3 = Unit.create((nradian ** 3).unit, name="nradian3", dispname=f"{str(nradian)}^3", scale=nradian.scale * 3) + pradian2 = Unit.create((pradian ** 2).unit, name="pradian2", dispname=f"{str(pradian)}^2", scale=pradian.scale * 2) + pradian3 = Unit.create((pradian ** 3).unit, name="pradian3", dispname=f"{str(pradian)}^3", scale=pradian.scale * 3) + uradian2 = Unit.create((uradian ** 2).unit, name="uradian2", dispname=f"{str(uradian)}^2", scale=uradian.scale * 2) + uradian3 = Unit.create((uradian ** 3).unit, name="uradian3", dispname=f"{str(uradian)}^3", scale=uradian.scale * 3) + Tradian2 = Unit.create((Tradian ** 2).unit, name="Tradian2", dispname=f"{str(Tradian)}^2", scale=Tradian.scale * 2) + Tradian3 = Unit.create((Tradian ** 3).unit, name="Tradian3", dispname=f"{str(Tradian)}^3", scale=Tradian.scale * 3) + yradian2 = Unit.create((yradian ** 2).unit, name="yradian2", dispname=f"{str(yradian)}^2", scale=yradian.scale * 2) + yradian3 = Unit.create((yradian ** 3).unit, name="yradian3", dispname=f"{str(yradian)}^3", scale=yradian.scale * 3) + Eradian2 = Unit.create((Eradian ** 2).unit, name="Eradian2", dispname=f"{str(Eradian)}^2", scale=Eradian.scale * 2) + Eradian3 = Unit.create((Eradian ** 3).unit, name="Eradian3", dispname=f"{str(Eradian)}^3", scale=Eradian.scale * 3) + zradian2 = Unit.create((zradian ** 2).unit, name="zradian2", dispname=f"{str(zradian)}^2", scale=zradian.scale * 2) + zradian3 = Unit.create((zradian ** 3).unit, name="zradian3", dispname=f"{str(zradian)}^3", scale=zradian.scale * 3) + Mradian2 = Unit.create((Mradian ** 2).unit, name="Mradian2", dispname=f"{str(Mradian)}^2", scale=Mradian.scale * 2) + Mradian3 = Unit.create((Mradian ** 3).unit, name="Mradian3", dispname=f"{str(Mradian)}^3", scale=Mradian.scale * 3) + kradian2 = Unit.create((kradian ** 2).unit, name="kradian2", dispname=f"{str(kradian)}^2", scale=kradian.scale * 2) + kradian3 = Unit.create((kradian ** 3).unit, name="kradian3", dispname=f"{str(kradian)}^3", scale=kradian.scale * 3) + Yradian2 = Unit.create((Yradian ** 2).unit, name="Yradian2", dispname=f"{str(Yradian)}^2", scale=Yradian.scale * 2) + Yradian3 = Unit.create((Yradian ** 3).unit, name="Yradian3", dispname=f"{str(Yradian)}^3", scale=Yradian.scale * 3) + asteradian2 = Unit.create((asteradian ** 2).unit, name="asteradian2", dispname=f"{str(asteradian)}^2", + scale=asteradian.scale * 2) + asteradian3 = Unit.create((asteradian ** 3).unit, name="asteradian3", dispname=f"{str(asteradian)}^3", + scale=asteradian.scale * 3) + csteradian2 = Unit.create((csteradian ** 2).unit, name="csteradian2", dispname=f"{str(csteradian)}^2", + scale=csteradian.scale * 2) + csteradian3 = Unit.create((csteradian ** 3).unit, name="csteradian3", dispname=f"{str(csteradian)}^3", + scale=csteradian.scale * 3) + Zsteradian2 = Unit.create((Zsteradian ** 2).unit, name="Zsteradian2", dispname=f"{str(Zsteradian)}^2", + scale=Zsteradian.scale * 2) + Zsteradian3 = Unit.create((Zsteradian ** 3).unit, name="Zsteradian3", dispname=f"{str(Zsteradian)}^3", + scale=Zsteradian.scale * 3) + Psteradian2 = Unit.create((Psteradian ** 2).unit, name="Psteradian2", dispname=f"{str(Psteradian)}^2", + scale=Psteradian.scale * 2) + Psteradian3 = Unit.create((Psteradian ** 3).unit, name="Psteradian3", dispname=f"{str(Psteradian)}^3", + scale=Psteradian.scale * 3) + dsteradian2 = Unit.create((dsteradian ** 2).unit, name="dsteradian2", dispname=f"{str(dsteradian)}^2", + scale=dsteradian.scale * 2) + dsteradian3 = Unit.create((dsteradian ** 3).unit, name="dsteradian3", dispname=f"{str(dsteradian)}^3", + scale=dsteradian.scale * 3) + Gsteradian2 = Unit.create((Gsteradian ** 2).unit, name="Gsteradian2", dispname=f"{str(Gsteradian)}^2", + scale=Gsteradian.scale * 2) + Gsteradian3 = Unit.create((Gsteradian ** 3).unit, name="Gsteradian3", dispname=f"{str(Gsteradian)}^3", + scale=Gsteradian.scale * 3) + fsteradian2 = Unit.create((fsteradian ** 2).unit, name="fsteradian2", dispname=f"{str(fsteradian)}^2", + scale=fsteradian.scale * 2) + fsteradian3 = Unit.create((fsteradian ** 3).unit, name="fsteradian3", dispname=f"{str(fsteradian)}^3", + scale=fsteradian.scale * 3) + hsteradian2 = Unit.create((hsteradian ** 2).unit, name="hsteradian2", dispname=f"{str(hsteradian)}^2", + scale=hsteradian.scale * 2) + hsteradian3 = Unit.create((hsteradian ** 3).unit, name="hsteradian3", dispname=f"{str(hsteradian)}^3", + scale=hsteradian.scale * 3) + dasteradian2 = Unit.create((dasteradian ** 2).unit, name="dasteradian2", dispname=f"{str(dasteradian)}^2", + scale=dasteradian.scale * 2) + dasteradian3 = Unit.create((dasteradian ** 3).unit, name="dasteradian3", dispname=f"{str(dasteradian)}^3", + scale=dasteradian.scale * 3) + msteradian2 = Unit.create((msteradian ** 2).unit, name="msteradian2", dispname=f"{str(msteradian)}^2", + scale=msteradian.scale * 2) + msteradian3 = Unit.create((msteradian ** 3).unit, name="msteradian3", dispname=f"{str(msteradian)}^3", + scale=msteradian.scale * 3) + nsteradian2 = Unit.create((nsteradian ** 2).unit, name="nsteradian2", dispname=f"{str(nsteradian)}^2", + scale=nsteradian.scale * 2) + nsteradian3 = Unit.create((nsteradian ** 3).unit, name="nsteradian3", dispname=f"{str(nsteradian)}^3", + scale=nsteradian.scale * 3) + psteradian2 = Unit.create((psteradian ** 2).unit, name="psteradian2", dispname=f"{str(psteradian)}^2", + scale=psteradian.scale * 2) + psteradian3 = Unit.create((psteradian ** 3).unit, name="psteradian3", dispname=f"{str(psteradian)}^3", + scale=psteradian.scale * 3) + usteradian2 = Unit.create((usteradian ** 2).unit, name="usteradian2", dispname=f"{str(usteradian)}^2", + scale=usteradian.scale * 2) + usteradian3 = Unit.create((usteradian ** 3).unit, name="usteradian3", dispname=f"{str(usteradian)}^3", + scale=usteradian.scale * 3) + Tsteradian2 = Unit.create((Tsteradian ** 2).unit, name="Tsteradian2", dispname=f"{str(Tsteradian)}^2", + scale=Tsteradian.scale * 2) + Tsteradian3 = Unit.create((Tsteradian ** 3).unit, name="Tsteradian3", dispname=f"{str(Tsteradian)}^3", + scale=Tsteradian.scale * 3) + ysteradian2 = Unit.create((ysteradian ** 2).unit, name="ysteradian2", dispname=f"{str(ysteradian)}^2", + scale=ysteradian.scale * 2) + ysteradian3 = Unit.create((ysteradian ** 3).unit, name="ysteradian3", dispname=f"{str(ysteradian)}^3", + scale=ysteradian.scale * 3) + Esteradian2 = Unit.create((Esteradian ** 2).unit, name="Esteradian2", dispname=f"{str(Esteradian)}^2", + scale=Esteradian.scale * 2) + Esteradian3 = Unit.create((Esteradian ** 3).unit, name="Esteradian3", dispname=f"{str(Esteradian)}^3", + scale=Esteradian.scale * 3) + zsteradian2 = Unit.create((zsteradian ** 2).unit, name="zsteradian2", dispname=f"{str(zsteradian)}^2", + scale=zsteradian.scale * 2) + zsteradian3 = Unit.create((zsteradian ** 3).unit, name="zsteradian3", dispname=f"{str(zsteradian)}^3", + scale=zsteradian.scale * 3) + Msteradian2 = Unit.create((Msteradian ** 2).unit, name="Msteradian2", dispname=f"{str(Msteradian)}^2", + scale=Msteradian.scale * 2) + Msteradian3 = Unit.create((Msteradian ** 3).unit, name="Msteradian3", dispname=f"{str(Msteradian)}^3", + scale=Msteradian.scale * 3) + ksteradian2 = Unit.create((ksteradian ** 2).unit, name="ksteradian2", dispname=f"{str(ksteradian)}^2", + scale=ksteradian.scale * 2) + ksteradian3 = Unit.create((ksteradian ** 3).unit, name="ksteradian3", dispname=f"{str(ksteradian)}^3", + scale=ksteradian.scale * 3) + Ysteradian2 = Unit.create((Ysteradian ** 2).unit, name="Ysteradian2", dispname=f"{str(Ysteradian)}^2", + scale=Ysteradian.scale * 2) + Ysteradian3 = Unit.create((Ysteradian ** 3).unit, name="Ysteradian3", dispname=f"{str(Ysteradian)}^3", + scale=Ysteradian.scale * 3) + ahertz2 = Unit.create((ahertz ** 2).unit, name="ahertz2", dispname=f"{str(ahertz)}^2", scale=ahertz.scale * 2) + ahertz3 = Unit.create((ahertz ** 3).unit, name="ahertz3", dispname=f"{str(ahertz)}^3", scale=ahertz.scale * 3) + chertz2 = Unit.create((chertz ** 2).unit, name="chertz2", dispname=f"{str(chertz)}^2", scale=chertz.scale * 2) + chertz3 = Unit.create((chertz ** 3).unit, name="chertz3", dispname=f"{str(chertz)}^3", scale=chertz.scale * 3) + Zhertz2 = Unit.create((Zhertz ** 2).unit, name="Zhertz2", dispname=f"{str(Zhertz)}^2", scale=Zhertz.scale * 2) + Zhertz3 = Unit.create((Zhertz ** 3).unit, name="Zhertz3", dispname=f"{str(Zhertz)}^3", scale=Zhertz.scale * 3) + Phertz2 = Unit.create((Phertz ** 2).unit, name="Phertz2", dispname=f"{str(Phertz)}^2", scale=Phertz.scale * 2) + Phertz3 = Unit.create((Phertz ** 3).unit, name="Phertz3", dispname=f"{str(Phertz)}^3", scale=Phertz.scale * 3) + dhertz2 = Unit.create((dhertz ** 2).unit, name="dhertz2", dispname=f"{str(dhertz)}^2", scale=dhertz.scale * 2) + dhertz3 = Unit.create((dhertz ** 3).unit, name="dhertz3", dispname=f"{str(dhertz)}^3", scale=dhertz.scale * 3) + Ghertz2 = Unit.create((Ghertz ** 2).unit, name="Ghertz2", dispname=f"{str(Ghertz)}^2", scale=Ghertz.scale * 2) + Ghertz3 = Unit.create((Ghertz ** 3).unit, name="Ghertz3", dispname=f"{str(Ghertz)}^3", scale=Ghertz.scale * 3) + fhertz2 = Unit.create((fhertz ** 2).unit, name="fhertz2", dispname=f"{str(fhertz)}^2", scale=fhertz.scale * 2) + fhertz3 = Unit.create((fhertz ** 3).unit, name="fhertz3", dispname=f"{str(fhertz)}^3", scale=fhertz.scale * 3) + hhertz2 = Unit.create((hhertz ** 2).unit, name="hhertz2", dispname=f"{str(hhertz)}^2", scale=hhertz.scale * 2) + hhertz3 = Unit.create((hhertz ** 3).unit, name="hhertz3", dispname=f"{str(hhertz)}^3", scale=hhertz.scale * 3) + dahertz2 = Unit.create((dahertz ** 2).unit, name="dahertz2", dispname=f"{str(dahertz)}^2", scale=dahertz.scale * 2) + dahertz3 = Unit.create((dahertz ** 3).unit, name="dahertz3", dispname=f"{str(dahertz)}^3", scale=dahertz.scale * 3) + mhertz2 = Unit.create((mhertz ** 2).unit, name="mhertz2", dispname=f"{str(mhertz)}^2", scale=mhertz.scale * 2) + mhertz3 = Unit.create((mhertz ** 3).unit, name="mhertz3", dispname=f"{str(mhertz)}^3", scale=mhertz.scale * 3) + nhertz2 = Unit.create((nhertz ** 2).unit, name="nhertz2", dispname=f"{str(nhertz)}^2", scale=nhertz.scale * 2) + nhertz3 = Unit.create((nhertz ** 3).unit, name="nhertz3", dispname=f"{str(nhertz)}^3", scale=nhertz.scale * 3) + phertz2 = Unit.create((phertz ** 2).unit, name="phertz2", dispname=f"{str(phertz)}^2", scale=phertz.scale * 2) + phertz3 = Unit.create((phertz ** 3).unit, name="phertz3", dispname=f"{str(phertz)}^3", scale=phertz.scale * 3) + uhertz2 = Unit.create((uhertz ** 2).unit, name="uhertz2", dispname=f"{str(uhertz)}^2", scale=uhertz.scale * 2) + uhertz3 = Unit.create((uhertz ** 3).unit, name="uhertz3", dispname=f"{str(uhertz)}^3", scale=uhertz.scale * 3) + Thertz2 = Unit.create((Thertz ** 2).unit, name="Thertz2", dispname=f"{str(Thertz)}^2", scale=Thertz.scale * 2) + Thertz3 = Unit.create((Thertz ** 3).unit, name="Thertz3", dispname=f"{str(Thertz)}^3", scale=Thertz.scale * 3) + yhertz2 = Unit.create((yhertz ** 2).unit, name="yhertz2", dispname=f"{str(yhertz)}^2", scale=yhertz.scale * 2) + yhertz3 = Unit.create((yhertz ** 3).unit, name="yhertz3", dispname=f"{str(yhertz)}^3", scale=yhertz.scale * 3) + Ehertz2 = Unit.create((Ehertz ** 2).unit, name="Ehertz2", dispname=f"{str(Ehertz)}^2", scale=Ehertz.scale * 2) + Ehertz3 = Unit.create((Ehertz ** 3).unit, name="Ehertz3", dispname=f"{str(Ehertz)}^3", scale=Ehertz.scale * 3) + zhertz2 = Unit.create((zhertz ** 2).unit, name="zhertz2", dispname=f"{str(zhertz)}^2", scale=zhertz.scale * 2) + zhertz3 = Unit.create((zhertz ** 3).unit, name="zhertz3", dispname=f"{str(zhertz)}^3", scale=zhertz.scale * 3) + Mhertz2 = Unit.create((Mhertz ** 2).unit, name="Mhertz2", dispname=f"{str(Mhertz)}^2", scale=Mhertz.scale * 2) + Mhertz3 = Unit.create((Mhertz ** 3).unit, name="Mhertz3", dispname=f"{str(Mhertz)}^3", scale=Mhertz.scale * 3) + khertz2 = Unit.create((khertz ** 2).unit, name="khertz2", dispname=f"{str(khertz)}^2", scale=khertz.scale * 2) + khertz3 = Unit.create((khertz ** 3).unit, name="khertz3", dispname=f"{str(khertz)}^3", scale=khertz.scale * 3) + Yhertz2 = Unit.create((Yhertz ** 2).unit, name="Yhertz2", dispname=f"{str(Yhertz)}^2", scale=Yhertz.scale * 2) + Yhertz3 = Unit.create((Yhertz ** 3).unit, name="Yhertz3", dispname=f"{str(Yhertz)}^3", scale=Yhertz.scale * 3) + anewton2 = Unit.create((anewton ** 2).unit, name="anewton2", dispname=f"{str(anewton)}^2", scale=anewton.scale * 2) + anewton3 = Unit.create((anewton ** 3).unit, name="anewton3", dispname=f"{str(anewton)}^3", scale=anewton.scale * 3) + cnewton2 = Unit.create((cnewton ** 2).unit, name="cnewton2", dispname=f"{str(cnewton)}^2", scale=cnewton.scale * 2) + cnewton3 = Unit.create((cnewton ** 3).unit, name="cnewton3", dispname=f"{str(cnewton)}^3", scale=cnewton.scale * 3) + Znewton2 = Unit.create((Znewton ** 2).unit, name="Znewton2", dispname=f"{str(Znewton)}^2", scale=Znewton.scale * 2) + Znewton3 = Unit.create((Znewton ** 3).unit, name="Znewton3", dispname=f"{str(Znewton)}^3", scale=Znewton.scale * 3) + Pnewton2 = Unit.create((Pnewton ** 2).unit, name="Pnewton2", dispname=f"{str(Pnewton)}^2", scale=Pnewton.scale * 2) + Pnewton3 = Unit.create((Pnewton ** 3).unit, name="Pnewton3", dispname=f"{str(Pnewton)}^3", scale=Pnewton.scale * 3) + dnewton2 = Unit.create((dnewton ** 2).unit, name="dnewton2", dispname=f"{str(dnewton)}^2", scale=dnewton.scale * 2) + dnewton3 = Unit.create((dnewton ** 3).unit, name="dnewton3", dispname=f"{str(dnewton)}^3", scale=dnewton.scale * 3) + Gnewton2 = Unit.create((Gnewton ** 2).unit, name="Gnewton2", dispname=f"{str(Gnewton)}^2", scale=Gnewton.scale * 2) + Gnewton3 = Unit.create((Gnewton ** 3).unit, name="Gnewton3", dispname=f"{str(Gnewton)}^3", scale=Gnewton.scale * 3) + fnewton2 = Unit.create((fnewton ** 2).unit, name="fnewton2", dispname=f"{str(fnewton)}^2", scale=fnewton.scale * 2) + fnewton3 = Unit.create((fnewton ** 3).unit, name="fnewton3", dispname=f"{str(fnewton)}^3", scale=fnewton.scale * 3) + hnewton2 = Unit.create((hnewton ** 2).unit, name="hnewton2", dispname=f"{str(hnewton)}^2", scale=hnewton.scale * 2) + hnewton3 = Unit.create((hnewton ** 3).unit, name="hnewton3", dispname=f"{str(hnewton)}^3", scale=hnewton.scale * 3) + danewton2 = Unit.create((danewton ** 2).unit, name="danewton2", dispname=f"{str(danewton)}^2", + scale=danewton.scale * 2) + danewton3 = Unit.create((danewton ** 3).unit, name="danewton3", dispname=f"{str(danewton)}^3", + scale=danewton.scale * 3) + mnewton2 = Unit.create((mnewton ** 2).unit, name="mnewton2", dispname=f"{str(mnewton)}^2", scale=mnewton.scale * 2) + mnewton3 = Unit.create((mnewton ** 3).unit, name="mnewton3", dispname=f"{str(mnewton)}^3", scale=mnewton.scale * 3) + nnewton2 = Unit.create((nnewton ** 2).unit, name="nnewton2", dispname=f"{str(nnewton)}^2", scale=nnewton.scale * 2) + nnewton3 = Unit.create((nnewton ** 3).unit, name="nnewton3", dispname=f"{str(nnewton)}^3", scale=nnewton.scale * 3) + pnewton2 = Unit.create((pnewton ** 2).unit, name="pnewton2", dispname=f"{str(pnewton)}^2", scale=pnewton.scale * 2) + pnewton3 = Unit.create((pnewton ** 3).unit, name="pnewton3", dispname=f"{str(pnewton)}^3", scale=pnewton.scale * 3) + unewton2 = Unit.create((unewton ** 2).unit, name="unewton2", dispname=f"{str(unewton)}^2", scale=unewton.scale * 2) + unewton3 = Unit.create((unewton ** 3).unit, name="unewton3", dispname=f"{str(unewton)}^3", scale=unewton.scale * 3) + Tnewton2 = Unit.create((Tnewton ** 2).unit, name="Tnewton2", dispname=f"{str(Tnewton)}^2", scale=Tnewton.scale * 2) + Tnewton3 = Unit.create((Tnewton ** 3).unit, name="Tnewton3", dispname=f"{str(Tnewton)}^3", scale=Tnewton.scale * 3) + ynewton2 = Unit.create((ynewton ** 2).unit, name="ynewton2", dispname=f"{str(ynewton)}^2", scale=ynewton.scale * 2) + ynewton3 = Unit.create((ynewton ** 3).unit, name="ynewton3", dispname=f"{str(ynewton)}^3", scale=ynewton.scale * 3) + Enewton2 = Unit.create((Enewton ** 2).unit, name="Enewton2", dispname=f"{str(Enewton)}^2", scale=Enewton.scale * 2) + Enewton3 = Unit.create((Enewton ** 3).unit, name="Enewton3", dispname=f"{str(Enewton)}^3", scale=Enewton.scale * 3) + znewton2 = Unit.create((znewton ** 2).unit, name="znewton2", dispname=f"{str(znewton)}^2", scale=znewton.scale * 2) + znewton3 = Unit.create((znewton ** 3).unit, name="znewton3", dispname=f"{str(znewton)}^3", scale=znewton.scale * 3) + Mnewton2 = Unit.create((Mnewton ** 2).unit, name="Mnewton2", dispname=f"{str(Mnewton)}^2", scale=Mnewton.scale * 2) + Mnewton3 = Unit.create((Mnewton ** 3).unit, name="Mnewton3", dispname=f"{str(Mnewton)}^3", scale=Mnewton.scale * 3) + knewton2 = Unit.create((knewton ** 2).unit, name="knewton2", dispname=f"{str(knewton)}^2", scale=knewton.scale * 2) + knewton3 = Unit.create((knewton ** 3).unit, name="knewton3", dispname=f"{str(knewton)}^3", scale=knewton.scale * 3) + Ynewton2 = Unit.create((Ynewton ** 2).unit, name="Ynewton2", dispname=f"{str(Ynewton)}^2", scale=Ynewton.scale * 2) + Ynewton3 = Unit.create((Ynewton ** 3).unit, name="Ynewton3", dispname=f"{str(Ynewton)}^3", scale=Ynewton.scale * 3) + apascal2 = Unit.create((apascal ** 2).unit, name="apascal2", dispname=f"{str(apascal)}^2", scale=apascal.scale * 2) + apascal3 = Unit.create((apascal ** 3).unit, name="apascal3", dispname=f"{str(apascal)}^3", scale=apascal.scale * 3) + cpascal2 = Unit.create((cpascal ** 2).unit, name="cpascal2", dispname=f"{str(cpascal)}^2", scale=cpascal.scale * 2) + cpascal3 = Unit.create((cpascal ** 3).unit, name="cpascal3", dispname=f"{str(cpascal)}^3", scale=cpascal.scale * 3) + Zpascal2 = Unit.create((Zpascal ** 2).unit, name="Zpascal2", dispname=f"{str(Zpascal)}^2", scale=Zpascal.scale * 2) + Zpascal3 = Unit.create((Zpascal ** 3).unit, name="Zpascal3", dispname=f"{str(Zpascal)}^3", scale=Zpascal.scale * 3) + Ppascal2 = Unit.create((Ppascal ** 2).unit, name="Ppascal2", dispname=f"{str(Ppascal)}^2", scale=Ppascal.scale * 2) + Ppascal3 = Unit.create((Ppascal ** 3).unit, name="Ppascal3", dispname=f"{str(Ppascal)}^3", scale=Ppascal.scale * 3) + dpascal2 = Unit.create((dpascal ** 2).unit, name="dpascal2", dispname=f"{str(dpascal)}^2", scale=dpascal.scale * 2) + dpascal3 = Unit.create((dpascal ** 3).unit, name="dpascal3", dispname=f"{str(dpascal)}^3", scale=dpascal.scale * 3) + Gpascal2 = Unit.create((Gpascal ** 2).unit, name="Gpascal2", dispname=f"{str(Gpascal)}^2", scale=Gpascal.scale * 2) + Gpascal3 = Unit.create((Gpascal ** 3).unit, name="Gpascal3", dispname=f"{str(Gpascal)}^3", scale=Gpascal.scale * 3) + fpascal2 = Unit.create((fpascal ** 2).unit, name="fpascal2", dispname=f"{str(fpascal)}^2", scale=fpascal.scale * 2) + fpascal3 = Unit.create((fpascal ** 3).unit, name="fpascal3", dispname=f"{str(fpascal)}^3", scale=fpascal.scale * 3) + hpascal2 = Unit.create((hpascal ** 2).unit, name="hpascal2", dispname=f"{str(hpascal)}^2", scale=hpascal.scale * 2) + hpascal3 = Unit.create((hpascal ** 3).unit, name="hpascal3", dispname=f"{str(hpascal)}^3", scale=hpascal.scale * 3) + dapascal2 = Unit.create((dapascal ** 2).unit, name="dapascal2", dispname=f"{str(dapascal)}^2", + scale=dapascal.scale * 2) + dapascal3 = Unit.create((dapascal ** 3).unit, name="dapascal3", dispname=f"{str(dapascal)}^3", + scale=dapascal.scale * 3) + mpascal2 = Unit.create((mpascal ** 2).unit, name="mpascal2", dispname=f"{str(mpascal)}^2", scale=mpascal.scale * 2) + mpascal3 = Unit.create((mpascal ** 3).unit, name="mpascal3", dispname=f"{str(mpascal)}^3", scale=mpascal.scale * 3) + npascal2 = Unit.create((npascal ** 2).unit, name="npascal2", dispname=f"{str(npascal)}^2", scale=npascal.scale * 2) + npascal3 = Unit.create((npascal ** 3).unit, name="npascal3", dispname=f"{str(npascal)}^3", scale=npascal.scale * 3) + ppascal2 = Unit.create((ppascal ** 2).unit, name="ppascal2", dispname=f"{str(ppascal)}^2", scale=ppascal.scale * 2) + ppascal3 = Unit.create((ppascal ** 3).unit, name="ppascal3", dispname=f"{str(ppascal)}^3", scale=ppascal.scale * 3) + upascal2 = Unit.create((upascal ** 2).unit, name="upascal2", dispname=f"{str(upascal)}^2", scale=upascal.scale * 2) + upascal3 = Unit.create((upascal ** 3).unit, name="upascal3", dispname=f"{str(upascal)}^3", scale=upascal.scale * 3) + Tpascal2 = Unit.create((Tpascal ** 2).unit, name="Tpascal2", dispname=f"{str(Tpascal)}^2", scale=Tpascal.scale * 2) + Tpascal3 = Unit.create((Tpascal ** 3).unit, name="Tpascal3", dispname=f"{str(Tpascal)}^3", scale=Tpascal.scale * 3) + ypascal2 = Unit.create((ypascal ** 2).unit, name="ypascal2", dispname=f"{str(ypascal)}^2", scale=ypascal.scale * 2) + ypascal3 = Unit.create((ypascal ** 3).unit, name="ypascal3", dispname=f"{str(ypascal)}^3", scale=ypascal.scale * 3) + Epascal2 = Unit.create((Epascal ** 2).unit, name="Epascal2", dispname=f"{str(Epascal)}^2", scale=Epascal.scale * 2) + Epascal3 = Unit.create((Epascal ** 3).unit, name="Epascal3", dispname=f"{str(Epascal)}^3", scale=Epascal.scale * 3) + zpascal2 = Unit.create((zpascal ** 2).unit, name="zpascal2", dispname=f"{str(zpascal)}^2", scale=zpascal.scale * 2) + zpascal3 = Unit.create((zpascal ** 3).unit, name="zpascal3", dispname=f"{str(zpascal)}^3", scale=zpascal.scale * 3) + Mpascal2 = Unit.create((Mpascal ** 2).unit, name="Mpascal2", dispname=f"{str(Mpascal)}^2", scale=Mpascal.scale * 2) + Mpascal3 = Unit.create((Mpascal ** 3).unit, name="Mpascal3", dispname=f"{str(Mpascal)}^3", scale=Mpascal.scale * 3) + kpascal2 = Unit.create((kpascal ** 2).unit, name="kpascal2", dispname=f"{str(kpascal)}^2", scale=kpascal.scale * 2) + kpascal3 = Unit.create((kpascal ** 3).unit, name="kpascal3", dispname=f"{str(kpascal)}^3", scale=kpascal.scale * 3) + Ypascal2 = Unit.create((Ypascal ** 2).unit, name="Ypascal2", dispname=f"{str(Ypascal)}^2", scale=Ypascal.scale * 2) + Ypascal3 = Unit.create((Ypascal ** 3).unit, name="Ypascal3", dispname=f"{str(Ypascal)}^3", scale=Ypascal.scale * 3) + ajoule2 = Unit.create((ajoule ** 2).unit, name="ajoule2", dispname=f"{str(ajoule)}^2", scale=ajoule.scale * 2) + ajoule3 = Unit.create((ajoule ** 3).unit, name="ajoule3", dispname=f"{str(ajoule)}^3", scale=ajoule.scale * 3) + cjoule2 = Unit.create((cjoule ** 2).unit, name="cjoule2", dispname=f"{str(cjoule)}^2", scale=cjoule.scale * 2) + cjoule3 = Unit.create((cjoule ** 3).unit, name="cjoule3", dispname=f"{str(cjoule)}^3", scale=cjoule.scale * 3) + Zjoule2 = Unit.create((Zjoule ** 2).unit, name="Zjoule2", dispname=f"{str(Zjoule)}^2", scale=Zjoule.scale * 2) + Zjoule3 = Unit.create((Zjoule ** 3).unit, name="Zjoule3", dispname=f"{str(Zjoule)}^3", scale=Zjoule.scale * 3) + Pjoule2 = Unit.create((Pjoule ** 2).unit, name="Pjoule2", dispname=f"{str(Pjoule)}^2", scale=Pjoule.scale * 2) + Pjoule3 = Unit.create((Pjoule ** 3).unit, name="Pjoule3", dispname=f"{str(Pjoule)}^3", scale=Pjoule.scale * 3) + djoule2 = Unit.create((djoule ** 2).unit, name="djoule2", dispname=f"{str(djoule)}^2", scale=djoule.scale * 2) + djoule3 = Unit.create((djoule ** 3).unit, name="djoule3", dispname=f"{str(djoule)}^3", scale=djoule.scale * 3) + Gjoule2 = Unit.create((Gjoule ** 2).unit, name="Gjoule2", dispname=f"{str(Gjoule)}^2", scale=Gjoule.scale * 2) + Gjoule3 = Unit.create((Gjoule ** 3).unit, name="Gjoule3", dispname=f"{str(Gjoule)}^3", scale=Gjoule.scale * 3) + fjoule2 = Unit.create((fjoule ** 2).unit, name="fjoule2", dispname=f"{str(fjoule)}^2", scale=fjoule.scale * 2) + fjoule3 = Unit.create((fjoule ** 3).unit, name="fjoule3", dispname=f"{str(fjoule)}^3", scale=fjoule.scale * 3) + hjoule2 = Unit.create((hjoule ** 2).unit, name="hjoule2", dispname=f"{str(hjoule)}^2", scale=hjoule.scale * 2) + hjoule3 = Unit.create((hjoule ** 3).unit, name="hjoule3", dispname=f"{str(hjoule)}^3", scale=hjoule.scale * 3) + dajoule2 = Unit.create((dajoule ** 2).unit, name="dajoule2", dispname=f"{str(dajoule)}^2", scale=dajoule.scale * 2) + dajoule3 = Unit.create((dajoule ** 3).unit, name="dajoule3", dispname=f"{str(dajoule)}^3", scale=dajoule.scale * 3) + mjoule2 = Unit.create((mjoule ** 2).unit, name="mjoule2", dispname=f"{str(mjoule)}^2", scale=mjoule.scale * 2) + mjoule3 = Unit.create((mjoule ** 3).unit, name="mjoule3", dispname=f"{str(mjoule)}^3", scale=mjoule.scale * 3) + njoule2 = Unit.create((njoule ** 2).unit, name="njoule2", dispname=f"{str(njoule)}^2", scale=njoule.scale * 2) + njoule3 = Unit.create((njoule ** 3).unit, name="njoule3", dispname=f"{str(njoule)}^3", scale=njoule.scale * 3) + pjoule2 = Unit.create((pjoule ** 2).unit, name="pjoule2", dispname=f"{str(pjoule)}^2", scale=pjoule.scale * 2) + pjoule3 = Unit.create((pjoule ** 3).unit, name="pjoule3", dispname=f"{str(pjoule)}^3", scale=pjoule.scale * 3) + ujoule2 = Unit.create((ujoule ** 2).unit, name="ujoule2", dispname=f"{str(ujoule)}^2", scale=ujoule.scale * 2) + ujoule3 = Unit.create((ujoule ** 3).unit, name="ujoule3", dispname=f"{str(ujoule)}^3", scale=ujoule.scale * 3) + Tjoule2 = Unit.create((Tjoule ** 2).unit, name="Tjoule2", dispname=f"{str(Tjoule)}^2", scale=Tjoule.scale * 2) + Tjoule3 = Unit.create((Tjoule ** 3).unit, name="Tjoule3", dispname=f"{str(Tjoule)}^3", scale=Tjoule.scale * 3) + yjoule2 = Unit.create((yjoule ** 2).unit, name="yjoule2", dispname=f"{str(yjoule)}^2", scale=yjoule.scale * 2) + yjoule3 = Unit.create((yjoule ** 3).unit, name="yjoule3", dispname=f"{str(yjoule)}^3", scale=yjoule.scale * 3) + Ejoule2 = Unit.create((Ejoule ** 2).unit, name="Ejoule2", dispname=f"{str(Ejoule)}^2", scale=Ejoule.scale * 2) + Ejoule3 = Unit.create((Ejoule ** 3).unit, name="Ejoule3", dispname=f"{str(Ejoule)}^3", scale=Ejoule.scale * 3) + zjoule2 = Unit.create((zjoule ** 2).unit, name="zjoule2", dispname=f"{str(zjoule)}^2", scale=zjoule.scale * 2) + zjoule3 = Unit.create((zjoule ** 3).unit, name="zjoule3", dispname=f"{str(zjoule)}^3", scale=zjoule.scale * 3) + Mjoule2 = Unit.create((Mjoule ** 2).unit, name="Mjoule2", dispname=f"{str(Mjoule)}^2", scale=Mjoule.scale * 2) + Mjoule3 = Unit.create((Mjoule ** 3).unit, name="Mjoule3", dispname=f"{str(Mjoule)}^3", scale=Mjoule.scale * 3) + kjoule2 = Unit.create((kjoule ** 2).unit, name="kjoule2", dispname=f"{str(kjoule)}^2", scale=kjoule.scale * 2) + kjoule3 = Unit.create((kjoule ** 3).unit, name="kjoule3", dispname=f"{str(kjoule)}^3", scale=kjoule.scale * 3) + Yjoule2 = Unit.create((Yjoule ** 2).unit, name="Yjoule2", dispname=f"{str(Yjoule)}^2", scale=Yjoule.scale * 2) + Yjoule3 = Unit.create((Yjoule ** 3).unit, name="Yjoule3", dispname=f"{str(Yjoule)}^3", scale=Yjoule.scale * 3) + awatt2 = Unit.create((awatt ** 2).unit, name="awatt2", dispname=f"{str(awatt)}^2", scale=awatt.scale * 2) + awatt3 = Unit.create((awatt ** 3).unit, name="awatt3", dispname=f"{str(awatt)}^3", scale=awatt.scale * 3) + cwatt2 = Unit.create((cwatt ** 2).unit, name="cwatt2", dispname=f"{str(cwatt)}^2", scale=cwatt.scale * 2) + cwatt3 = Unit.create((cwatt ** 3).unit, name="cwatt3", dispname=f"{str(cwatt)}^3", scale=cwatt.scale * 3) + Zwatt2 = Unit.create((Zwatt ** 2).unit, name="Zwatt2", dispname=f"{str(Zwatt)}^2", scale=Zwatt.scale * 2) + Zwatt3 = Unit.create((Zwatt ** 3).unit, name="Zwatt3", dispname=f"{str(Zwatt)}^3", scale=Zwatt.scale * 3) + Pwatt2 = Unit.create((Pwatt ** 2).unit, name="Pwatt2", dispname=f"{str(Pwatt)}^2", scale=Pwatt.scale * 2) + Pwatt3 = Unit.create((Pwatt ** 3).unit, name="Pwatt3", dispname=f"{str(Pwatt)}^3", scale=Pwatt.scale * 3) + dwatt2 = Unit.create((dwatt ** 2).unit, name="dwatt2", dispname=f"{str(dwatt)}^2", scale=dwatt.scale * 2) + dwatt3 = Unit.create((dwatt ** 3).unit, name="dwatt3", dispname=f"{str(dwatt)}^3", scale=dwatt.scale * 3) + Gwatt2 = Unit.create((Gwatt ** 2).unit, name="Gwatt2", dispname=f"{str(Gwatt)}^2", scale=Gwatt.scale * 2) + Gwatt3 = Unit.create((Gwatt ** 3).unit, name="Gwatt3", dispname=f"{str(Gwatt)}^3", scale=Gwatt.scale * 3) + fwatt2 = Unit.create((fwatt ** 2).unit, name="fwatt2", dispname=f"{str(fwatt)}^2", scale=fwatt.scale * 2) + fwatt3 = Unit.create((fwatt ** 3).unit, name="fwatt3", dispname=f"{str(fwatt)}^3", scale=fwatt.scale * 3) + hwatt2 = Unit.create((hwatt ** 2).unit, name="hwatt2", dispname=f"{str(hwatt)}^2", scale=hwatt.scale * 2) + hwatt3 = Unit.create((hwatt ** 3).unit, name="hwatt3", dispname=f"{str(hwatt)}^3", scale=hwatt.scale * 3) + dawatt2 = Unit.create((dawatt ** 2).unit, name="dawatt2", dispname=f"{str(dawatt)}^2", scale=dawatt.scale * 2) + dawatt3 = Unit.create((dawatt ** 3).unit, name="dawatt3", dispname=f"{str(dawatt)}^3", scale=dawatt.scale * 3) + mwatt2 = Unit.create((mwatt ** 2).unit, name="mwatt2", dispname=f"{str(mwatt)}^2", scale=mwatt.scale * 2) + mwatt3 = Unit.create((mwatt ** 3).unit, name="mwatt3", dispname=f"{str(mwatt)}^3", scale=mwatt.scale * 3) + nwatt2 = Unit.create((nwatt ** 2).unit, name="nwatt2", dispname=f"{str(nwatt)}^2", scale=nwatt.scale * 2) + nwatt3 = Unit.create((nwatt ** 3).unit, name="nwatt3", dispname=f"{str(nwatt)}^3", scale=nwatt.scale * 3) + pwatt2 = Unit.create((pwatt ** 2).unit, name="pwatt2", dispname=f"{str(pwatt)}^2", scale=pwatt.scale * 2) + pwatt3 = Unit.create((pwatt ** 3).unit, name="pwatt3", dispname=f"{str(pwatt)}^3", scale=pwatt.scale * 3) + uwatt2 = Unit.create((uwatt ** 2).unit, name="uwatt2", dispname=f"{str(uwatt)}^2", scale=uwatt.scale * 2) + uwatt3 = Unit.create((uwatt ** 3).unit, name="uwatt3", dispname=f"{str(uwatt)}^3", scale=uwatt.scale * 3) + Twatt2 = Unit.create((Twatt ** 2).unit, name="Twatt2", dispname=f"{str(Twatt)}^2", scale=Twatt.scale * 2) + Twatt3 = Unit.create((Twatt ** 3).unit, name="Twatt3", dispname=f"{str(Twatt)}^3", scale=Twatt.scale * 3) + ywatt2 = Unit.create((ywatt ** 2).unit, name="ywatt2", dispname=f"{str(ywatt)}^2", scale=ywatt.scale * 2) + ywatt3 = Unit.create((ywatt ** 3).unit, name="ywatt3", dispname=f"{str(ywatt)}^3", scale=ywatt.scale * 3) + Ewatt2 = Unit.create((Ewatt ** 2).unit, name="Ewatt2", dispname=f"{str(Ewatt)}^2", scale=Ewatt.scale * 2) + Ewatt3 = Unit.create((Ewatt ** 3).unit, name="Ewatt3", dispname=f"{str(Ewatt)}^3", scale=Ewatt.scale * 3) + zwatt2 = Unit.create((zwatt ** 2).unit, name="zwatt2", dispname=f"{str(zwatt)}^2", scale=zwatt.scale * 2) + zwatt3 = Unit.create((zwatt ** 3).unit, name="zwatt3", dispname=f"{str(zwatt)}^3", scale=zwatt.scale * 3) + Mwatt2 = Unit.create((Mwatt ** 2).unit, name="Mwatt2", dispname=f"{str(Mwatt)}^2", scale=Mwatt.scale * 2) + Mwatt3 = Unit.create((Mwatt ** 3).unit, name="Mwatt3", dispname=f"{str(Mwatt)}^3", scale=Mwatt.scale * 3) + kwatt2 = Unit.create((kwatt ** 2).unit, name="kwatt2", dispname=f"{str(kwatt)}^2", scale=kwatt.scale * 2) + kwatt3 = Unit.create((kwatt ** 3).unit, name="kwatt3", dispname=f"{str(kwatt)}^3", scale=kwatt.scale * 3) + Ywatt2 = Unit.create((Ywatt ** 2).unit, name="Ywatt2", dispname=f"{str(Ywatt)}^2", scale=Ywatt.scale * 2) + Ywatt3 = Unit.create((Ywatt ** 3).unit, name="Ywatt3", dispname=f"{str(Ywatt)}^3", scale=Ywatt.scale * 3) + acoulomb2 = Unit.create((acoulomb ** 2).unit, name="acoulomb2", dispname=f"{str(acoulomb)}^2", + scale=acoulomb.scale * 2) + acoulomb3 = Unit.create((acoulomb ** 3).unit, name="acoulomb3", dispname=f"{str(acoulomb)}^3", + scale=acoulomb.scale * 3) + ccoulomb2 = Unit.create((ccoulomb ** 2).unit, name="ccoulomb2", dispname=f"{str(ccoulomb)}^2", + scale=ccoulomb.scale * 2) + ccoulomb3 = Unit.create((ccoulomb ** 3).unit, name="ccoulomb3", dispname=f"{str(ccoulomb)}^3", + scale=ccoulomb.scale * 3) + Zcoulomb2 = Unit.create((Zcoulomb ** 2).unit, name="Zcoulomb2", dispname=f"{str(Zcoulomb)}^2", + scale=Zcoulomb.scale * 2) + Zcoulomb3 = Unit.create((Zcoulomb ** 3).unit, name="Zcoulomb3", dispname=f"{str(Zcoulomb)}^3", + scale=Zcoulomb.scale * 3) + Pcoulomb2 = Unit.create((Pcoulomb ** 2).unit, name="Pcoulomb2", dispname=f"{str(Pcoulomb)}^2", + scale=Pcoulomb.scale * 2) + Pcoulomb3 = Unit.create((Pcoulomb ** 3).unit, name="Pcoulomb3", dispname=f"{str(Pcoulomb)}^3", + scale=Pcoulomb.scale * 3) + dcoulomb2 = Unit.create((dcoulomb ** 2).unit, name="dcoulomb2", dispname=f"{str(dcoulomb)}^2", + scale=dcoulomb.scale * 2) + dcoulomb3 = Unit.create((dcoulomb ** 3).unit, name="dcoulomb3", dispname=f"{str(dcoulomb)}^3", + scale=dcoulomb.scale * 3) + Gcoulomb2 = Unit.create((Gcoulomb ** 2).unit, name="Gcoulomb2", dispname=f"{str(Gcoulomb)}^2", + scale=Gcoulomb.scale * 2) + Gcoulomb3 = Unit.create((Gcoulomb ** 3).unit, name="Gcoulomb3", dispname=f"{str(Gcoulomb)}^3", + scale=Gcoulomb.scale * 3) + fcoulomb2 = Unit.create((fcoulomb ** 2).unit, name="fcoulomb2", dispname=f"{str(fcoulomb)}^2", + scale=fcoulomb.scale * 2) + fcoulomb3 = Unit.create((fcoulomb ** 3).unit, name="fcoulomb3", dispname=f"{str(fcoulomb)}^3", + scale=fcoulomb.scale * 3) + hcoulomb2 = Unit.create((hcoulomb ** 2).unit, name="hcoulomb2", dispname=f"{str(hcoulomb)}^2", + scale=hcoulomb.scale * 2) + hcoulomb3 = Unit.create((hcoulomb ** 3).unit, name="hcoulomb3", dispname=f"{str(hcoulomb)}^3", + scale=hcoulomb.scale * 3) + dacoulomb2 = Unit.create((dacoulomb ** 2).unit, name="dacoulomb2", dispname=f"{str(dacoulomb)}^2", + scale=dacoulomb.scale * 2) + dacoulomb3 = Unit.create((dacoulomb ** 3).unit, name="dacoulomb3", dispname=f"{str(dacoulomb)}^3", + scale=dacoulomb.scale * 3) + mcoulomb2 = Unit.create((mcoulomb ** 2).unit, name="mcoulomb2", dispname=f"{str(mcoulomb)}^2", + scale=mcoulomb.scale * 2) + mcoulomb3 = Unit.create((mcoulomb ** 3).unit, name="mcoulomb3", dispname=f"{str(mcoulomb)}^3", + scale=mcoulomb.scale * 3) + ncoulomb2 = Unit.create((ncoulomb ** 2).unit, name="ncoulomb2", dispname=f"{str(ncoulomb)}^2", + scale=ncoulomb.scale * 2) + ncoulomb3 = Unit.create((ncoulomb ** 3).unit, name="ncoulomb3", dispname=f"{str(ncoulomb)}^3", + scale=ncoulomb.scale * 3) + pcoulomb2 = Unit.create((pcoulomb ** 2).unit, name="pcoulomb2", dispname=f"{str(pcoulomb)}^2", + scale=pcoulomb.scale * 2) + pcoulomb3 = Unit.create((pcoulomb ** 3).unit, name="pcoulomb3", dispname=f"{str(pcoulomb)}^3", + scale=pcoulomb.scale * 3) + ucoulomb2 = Unit.create((ucoulomb ** 2).unit, name="ucoulomb2", dispname=f"{str(ucoulomb)}^2", + scale=ucoulomb.scale * 2) + ucoulomb3 = Unit.create((ucoulomb ** 3).unit, name="ucoulomb3", dispname=f"{str(ucoulomb)}^3", + scale=ucoulomb.scale * 3) + Tcoulomb2 = Unit.create((Tcoulomb ** 2).unit, name="Tcoulomb2", dispname=f"{str(Tcoulomb)}^2", + scale=Tcoulomb.scale * 2) + Tcoulomb3 = Unit.create((Tcoulomb ** 3).unit, name="Tcoulomb3", dispname=f"{str(Tcoulomb)}^3", + scale=Tcoulomb.scale * 3) + ycoulomb2 = Unit.create((ycoulomb ** 2).unit, name="ycoulomb2", dispname=f"{str(ycoulomb)}^2", + scale=ycoulomb.scale * 2) + ycoulomb3 = Unit.create((ycoulomb ** 3).unit, name="ycoulomb3", dispname=f"{str(ycoulomb)}^3", + scale=ycoulomb.scale * 3) + Ecoulomb2 = Unit.create((Ecoulomb ** 2).unit, name="Ecoulomb2", dispname=f"{str(Ecoulomb)}^2", + scale=Ecoulomb.scale * 2) + Ecoulomb3 = Unit.create((Ecoulomb ** 3).unit, name="Ecoulomb3", dispname=f"{str(Ecoulomb)}^3", + scale=Ecoulomb.scale * 3) + zcoulomb2 = Unit.create((zcoulomb ** 2).unit, name="zcoulomb2", dispname=f"{str(zcoulomb)}^2", + scale=zcoulomb.scale * 2) + zcoulomb3 = Unit.create((zcoulomb ** 3).unit, name="zcoulomb3", dispname=f"{str(zcoulomb)}^3", + scale=zcoulomb.scale * 3) + Mcoulomb2 = Unit.create((Mcoulomb ** 2).unit, name="Mcoulomb2", dispname=f"{str(Mcoulomb)}^2", + scale=Mcoulomb.scale * 2) + Mcoulomb3 = Unit.create((Mcoulomb ** 3).unit, name="Mcoulomb3", dispname=f"{str(Mcoulomb)}^3", + scale=Mcoulomb.scale * 3) + kcoulomb2 = Unit.create((kcoulomb ** 2).unit, name="kcoulomb2", dispname=f"{str(kcoulomb)}^2", + scale=kcoulomb.scale * 2) + kcoulomb3 = Unit.create((kcoulomb ** 3).unit, name="kcoulomb3", dispname=f"{str(kcoulomb)}^3", + scale=kcoulomb.scale * 3) + Ycoulomb2 = Unit.create((Ycoulomb ** 2).unit, name="Ycoulomb2", dispname=f"{str(Ycoulomb)}^2", + scale=Ycoulomb.scale * 2) + Ycoulomb3 = Unit.create((Ycoulomb ** 3).unit, name="Ycoulomb3", dispname=f"{str(Ycoulomb)}^3", + scale=Ycoulomb.scale * 3) + avolt2 = Unit.create((avolt ** 2).unit, name="avolt2", dispname=f"{str(avolt)}^2", scale=avolt.scale * 2) + avolt3 = Unit.create((avolt ** 3).unit, name="avolt3", dispname=f"{str(avolt)}^3", scale=avolt.scale * 3) + cvolt2 = Unit.create((cvolt ** 2).unit, name="cvolt2", dispname=f"{str(cvolt)}^2", scale=cvolt.scale * 2) + cvolt3 = Unit.create((cvolt ** 3).unit, name="cvolt3", dispname=f"{str(cvolt)}^3", scale=cvolt.scale * 3) + Zvolt2 = Unit.create((Zvolt ** 2).unit, name="Zvolt2", dispname=f"{str(Zvolt)}^2", scale=Zvolt.scale * 2) + Zvolt3 = Unit.create((Zvolt ** 3).unit, name="Zvolt3", dispname=f"{str(Zvolt)}^3", scale=Zvolt.scale * 3) + Pvolt2 = Unit.create((Pvolt ** 2).unit, name="Pvolt2", dispname=f"{str(Pvolt)}^2", scale=Pvolt.scale * 2) + Pvolt3 = Unit.create((Pvolt ** 3).unit, name="Pvolt3", dispname=f"{str(Pvolt)}^3", scale=Pvolt.scale * 3) + dvolt2 = Unit.create((dvolt ** 2).unit, name="dvolt2", dispname=f"{str(dvolt)}^2", scale=dvolt.scale * 2) + dvolt3 = Unit.create((dvolt ** 3).unit, name="dvolt3", dispname=f"{str(dvolt)}^3", scale=dvolt.scale * 3) + Gvolt2 = Unit.create((Gvolt ** 2).unit, name="Gvolt2", dispname=f"{str(Gvolt)}^2", scale=Gvolt.scale * 2) + Gvolt3 = Unit.create((Gvolt ** 3).unit, name="Gvolt3", dispname=f"{str(Gvolt)}^3", scale=Gvolt.scale * 3) + fvolt2 = Unit.create((fvolt ** 2).unit, name="fvolt2", dispname=f"{str(fvolt)}^2", scale=fvolt.scale * 2) + fvolt3 = Unit.create((fvolt ** 3).unit, name="fvolt3", dispname=f"{str(fvolt)}^3", scale=fvolt.scale * 3) + hvolt2 = Unit.create((hvolt ** 2).unit, name="hvolt2", dispname=f"{str(hvolt)}^2", scale=hvolt.scale * 2) + hvolt3 = Unit.create((hvolt ** 3).unit, name="hvolt3", dispname=f"{str(hvolt)}^3", scale=hvolt.scale * 3) + davolt2 = Unit.create((davolt ** 2).unit, name="davolt2", dispname=f"{str(davolt)}^2", scale=davolt.scale * 2) + davolt3 = Unit.create((davolt ** 3).unit, name="davolt3", dispname=f"{str(davolt)}^3", scale=davolt.scale * 3) + mvolt2 = Unit.create((mvolt ** 2).unit, name="mvolt2", dispname=f"{str(mvolt)}^2", scale=mvolt.scale * 2) + mvolt3 = Unit.create((mvolt ** 3).unit, name="mvolt3", dispname=f"{str(mvolt)}^3", scale=mvolt.scale * 3) + nvolt2 = Unit.create((nvolt ** 2).unit, name="nvolt2", dispname=f"{str(nvolt)}^2", scale=nvolt.scale * 2) + nvolt3 = Unit.create((nvolt ** 3).unit, name="nvolt3", dispname=f"{str(nvolt)}^3", scale=nvolt.scale * 3) + pvolt2 = Unit.create((pvolt ** 2).unit, name="pvolt2", dispname=f"{str(pvolt)}^2", scale=pvolt.scale * 2) + pvolt3 = Unit.create((pvolt ** 3).unit, name="pvolt3", dispname=f"{str(pvolt)}^3", scale=pvolt.scale * 3) + uvolt2 = Unit.create((uvolt ** 2).unit, name="uvolt2", dispname=f"{str(uvolt)}^2", scale=uvolt.scale * 2) + uvolt3 = Unit.create((uvolt ** 3).unit, name="uvolt3", dispname=f"{str(uvolt)}^3", scale=uvolt.scale * 3) + Tvolt2 = Unit.create((Tvolt ** 2).unit, name="Tvolt2", dispname=f"{str(Tvolt)}^2", scale=Tvolt.scale * 2) + Tvolt3 = Unit.create((Tvolt ** 3).unit, name="Tvolt3", dispname=f"{str(Tvolt)}^3", scale=Tvolt.scale * 3) + yvolt2 = Unit.create((yvolt ** 2).unit, name="yvolt2", dispname=f"{str(yvolt)}^2", scale=yvolt.scale * 2) + yvolt3 = Unit.create((yvolt ** 3).unit, name="yvolt3", dispname=f"{str(yvolt)}^3", scale=yvolt.scale * 3) + Evolt2 = Unit.create((Evolt ** 2).unit, name="Evolt2", dispname=f"{str(Evolt)}^2", scale=Evolt.scale * 2) + Evolt3 = Unit.create((Evolt ** 3).unit, name="Evolt3", dispname=f"{str(Evolt)}^3", scale=Evolt.scale * 3) + zvolt2 = Unit.create((zvolt ** 2).unit, name="zvolt2", dispname=f"{str(zvolt)}^2", scale=zvolt.scale * 2) + zvolt3 = Unit.create((zvolt ** 3).unit, name="zvolt3", dispname=f"{str(zvolt)}^3", scale=zvolt.scale * 3) + Mvolt2 = Unit.create((Mvolt ** 2).unit, name="Mvolt2", dispname=f"{str(Mvolt)}^2", scale=Mvolt.scale * 2) + Mvolt3 = Unit.create((Mvolt ** 3).unit, name="Mvolt3", dispname=f"{str(Mvolt)}^3", scale=Mvolt.scale * 3) + kvolt2 = Unit.create((kvolt ** 2).unit, name="kvolt2", dispname=f"{str(kvolt)}^2", scale=kvolt.scale * 2) + kvolt3 = Unit.create((kvolt ** 3).unit, name="kvolt3", dispname=f"{str(kvolt)}^3", scale=kvolt.scale * 3) + Yvolt2 = Unit.create((Yvolt ** 2).unit, name="Yvolt2", dispname=f"{str(Yvolt)}^2", scale=Yvolt.scale * 2) + Yvolt3 = Unit.create((Yvolt ** 3).unit, name="Yvolt3", dispname=f"{str(Yvolt)}^3", scale=Yvolt.scale * 3) + afarad2 = Unit.create((afarad ** 2).unit, name="afarad2", dispname=f"{str(afarad)}^2", scale=afarad.scale * 2) + afarad3 = Unit.create((afarad ** 3).unit, name="afarad3", dispname=f"{str(afarad)}^3", scale=afarad.scale * 3) + cfarad2 = Unit.create((cfarad ** 2).unit, name="cfarad2", dispname=f"{str(cfarad)}^2", scale=cfarad.scale * 2) + cfarad3 = Unit.create((cfarad ** 3).unit, name="cfarad3", dispname=f"{str(cfarad)}^3", scale=cfarad.scale * 3) + Zfarad2 = Unit.create((Zfarad ** 2).unit, name="Zfarad2", dispname=f"{str(Zfarad)}^2", scale=Zfarad.scale * 2) + Zfarad3 = Unit.create((Zfarad ** 3).unit, name="Zfarad3", dispname=f"{str(Zfarad)}^3", scale=Zfarad.scale * 3) + Pfarad2 = Unit.create((Pfarad ** 2).unit, name="Pfarad2", dispname=f"{str(Pfarad)}^2", scale=Pfarad.scale * 2) + Pfarad3 = Unit.create((Pfarad ** 3).unit, name="Pfarad3", dispname=f"{str(Pfarad)}^3", scale=Pfarad.scale * 3) + dfarad2 = Unit.create((dfarad ** 2).unit, name="dfarad2", dispname=f"{str(dfarad)}^2", scale=dfarad.scale * 2) + dfarad3 = Unit.create((dfarad ** 3).unit, name="dfarad3", dispname=f"{str(dfarad)}^3", scale=dfarad.scale * 3) + Gfarad2 = Unit.create((Gfarad ** 2).unit, name="Gfarad2", dispname=f"{str(Gfarad)}^2", scale=Gfarad.scale * 2) + Gfarad3 = Unit.create((Gfarad ** 3).unit, name="Gfarad3", dispname=f"{str(Gfarad)}^3", scale=Gfarad.scale * 3) + ffarad2 = Unit.create((ffarad ** 2).unit, name="ffarad2", dispname=f"{str(ffarad)}^2", scale=ffarad.scale * 2) + ffarad3 = Unit.create((ffarad ** 3).unit, name="ffarad3", dispname=f"{str(ffarad)}^3", scale=ffarad.scale * 3) + hfarad2 = Unit.create((hfarad ** 2).unit, name="hfarad2", dispname=f"{str(hfarad)}^2", scale=hfarad.scale * 2) + hfarad3 = Unit.create((hfarad ** 3).unit, name="hfarad3", dispname=f"{str(hfarad)}^3", scale=hfarad.scale * 3) + dafarad2 = Unit.create((dafarad ** 2).unit, name="dafarad2", dispname=f"{str(dafarad)}^2", scale=dafarad.scale * 2) + dafarad3 = Unit.create((dafarad ** 3).unit, name="dafarad3", dispname=f"{str(dafarad)}^3", scale=dafarad.scale * 3) + mfarad2 = Unit.create((mfarad ** 2).unit, name="mfarad2", dispname=f"{str(mfarad)}^2", scale=mfarad.scale * 2) + mfarad3 = Unit.create((mfarad ** 3).unit, name="mfarad3", dispname=f"{str(mfarad)}^3", scale=mfarad.scale * 3) + nfarad2 = Unit.create((nfarad ** 2).unit, name="nfarad2", dispname=f"{str(nfarad)}^2", scale=nfarad.scale * 2) + nfarad3 = Unit.create((nfarad ** 3).unit, name="nfarad3", dispname=f"{str(nfarad)}^3", scale=nfarad.scale * 3) + pfarad2 = Unit.create((pfarad ** 2).unit, name="pfarad2", dispname=f"{str(pfarad)}^2", scale=pfarad.scale * 2) + pfarad3 = Unit.create((pfarad ** 3).unit, name="pfarad3", dispname=f"{str(pfarad)}^3", scale=pfarad.scale * 3) + ufarad2 = Unit.create((ufarad ** 2).unit, name="ufarad2", dispname=f"{str(ufarad)}^2", scale=ufarad.scale * 2) + ufarad3 = Unit.create((ufarad ** 3).unit, name="ufarad3", dispname=f"{str(ufarad)}^3", scale=ufarad.scale * 3) + Tfarad2 = Unit.create((Tfarad ** 2).unit, name="Tfarad2", dispname=f"{str(Tfarad)}^2", scale=Tfarad.scale * 2) + Tfarad3 = Unit.create((Tfarad ** 3).unit, name="Tfarad3", dispname=f"{str(Tfarad)}^3", scale=Tfarad.scale * 3) + yfarad2 = Unit.create((yfarad ** 2).unit, name="yfarad2", dispname=f"{str(yfarad)}^2", scale=yfarad.scale * 2) + yfarad3 = Unit.create((yfarad ** 3).unit, name="yfarad3", dispname=f"{str(yfarad)}^3", scale=yfarad.scale * 3) + Efarad2 = Unit.create((Efarad ** 2).unit, name="Efarad2", dispname=f"{str(Efarad)}^2", scale=Efarad.scale * 2) + Efarad3 = Unit.create((Efarad ** 3).unit, name="Efarad3", dispname=f"{str(Efarad)}^3", scale=Efarad.scale * 3) + zfarad2 = Unit.create((zfarad ** 2).unit, name="zfarad2", dispname=f"{str(zfarad)}^2", scale=zfarad.scale * 2) + zfarad3 = Unit.create((zfarad ** 3).unit, name="zfarad3", dispname=f"{str(zfarad)}^3", scale=zfarad.scale * 3) + Mfarad2 = Unit.create((Mfarad ** 2).unit, name="Mfarad2", dispname=f"{str(Mfarad)}^2", scale=Mfarad.scale * 2) + Mfarad3 = Unit.create((Mfarad ** 3).unit, name="Mfarad3", dispname=f"{str(Mfarad)}^3", scale=Mfarad.scale * 3) + kfarad2 = Unit.create((kfarad ** 2).unit, name="kfarad2", dispname=f"{str(kfarad)}^2", scale=kfarad.scale * 2) + kfarad3 = Unit.create((kfarad ** 3).unit, name="kfarad3", dispname=f"{str(kfarad)}^3", scale=kfarad.scale * 3) + Yfarad2 = Unit.create((Yfarad ** 2).unit, name="Yfarad2", dispname=f"{str(Yfarad)}^2", scale=Yfarad.scale * 2) + Yfarad3 = Unit.create((Yfarad ** 3).unit, name="Yfarad3", dispname=f"{str(Yfarad)}^3", scale=Yfarad.scale * 3) + aohm2 = Unit.create((aohm ** 2).unit, name="aohm2", dispname=f"{str(aohm)}^2", scale=aohm.scale * 2) + aohm3 = Unit.create((aohm ** 3).unit, name="aohm3", dispname=f"{str(aohm)}^3", scale=aohm.scale * 3) + cohm2 = Unit.create((cohm ** 2).unit, name="cohm2", dispname=f"{str(cohm)}^2", scale=cohm.scale * 2) + cohm3 = Unit.create((cohm ** 3).unit, name="cohm3", dispname=f"{str(cohm)}^3", scale=cohm.scale * 3) + Zohm2 = Unit.create((Zohm ** 2).unit, name="Zohm2", dispname=f"{str(Zohm)}^2", scale=Zohm.scale * 2) + Zohm3 = Unit.create((Zohm ** 3).unit, name="Zohm3", dispname=f"{str(Zohm)}^3", scale=Zohm.scale * 3) + Pohm2 = Unit.create((Pohm ** 2).unit, name="Pohm2", dispname=f"{str(Pohm)}^2", scale=Pohm.scale * 2) + Pohm3 = Unit.create((Pohm ** 3).unit, name="Pohm3", dispname=f"{str(Pohm)}^3", scale=Pohm.scale * 3) + dohm2 = Unit.create((dohm ** 2).unit, name="dohm2", dispname=f"{str(dohm)}^2", scale=dohm.scale * 2) + dohm3 = Unit.create((dohm ** 3).unit, name="dohm3", dispname=f"{str(dohm)}^3", scale=dohm.scale * 3) + Gohm2 = Unit.create((Gohm ** 2).unit, name="Gohm2", dispname=f"{str(Gohm)}^2", scale=Gohm.scale * 2) + Gohm3 = Unit.create((Gohm ** 3).unit, name="Gohm3", dispname=f"{str(Gohm)}^3", scale=Gohm.scale * 3) + fohm2 = Unit.create((fohm ** 2).unit, name="fohm2", dispname=f"{str(fohm)}^2", scale=fohm.scale * 2) + fohm3 = Unit.create((fohm ** 3).unit, name="fohm3", dispname=f"{str(fohm)}^3", scale=fohm.scale * 3) + hohm2 = Unit.create((hohm ** 2).unit, name="hohm2", dispname=f"{str(hohm)}^2", scale=hohm.scale * 2) + hohm3 = Unit.create((hohm ** 3).unit, name="hohm3", dispname=f"{str(hohm)}^3", scale=hohm.scale * 3) + daohm2 = Unit.create((daohm ** 2).unit, name="daohm2", dispname=f"{str(daohm)}^2", scale=daohm.scale * 2) + daohm3 = Unit.create((daohm ** 3).unit, name="daohm3", dispname=f"{str(daohm)}^3", scale=daohm.scale * 3) + mohm2 = Unit.create((mohm ** 2).unit, name="mohm2", dispname=f"{str(mohm)}^2", scale=mohm.scale * 2) + mohm3 = Unit.create((mohm ** 3).unit, name="mohm3", dispname=f"{str(mohm)}^3", scale=mohm.scale * 3) + nohm2 = Unit.create((nohm ** 2).unit, name="nohm2", dispname=f"{str(nohm)}^2", scale=nohm.scale * 2) + nohm3 = Unit.create((nohm ** 3).unit, name="nohm3", dispname=f"{str(nohm)}^3", scale=nohm.scale * 3) + pohm2 = Unit.create((pohm ** 2).unit, name="pohm2", dispname=f"{str(pohm)}^2", scale=pohm.scale * 2) + pohm3 = Unit.create((pohm ** 3).unit, name="pohm3", dispname=f"{str(pohm)}^3", scale=pohm.scale * 3) + uohm2 = Unit.create((uohm ** 2).unit, name="uohm2", dispname=f"{str(uohm)}^2", scale=uohm.scale * 2) + uohm3 = Unit.create((uohm ** 3).unit, name="uohm3", dispname=f"{str(uohm)}^3", scale=uohm.scale * 3) + Tohm2 = Unit.create((Tohm ** 2).unit, name="Tohm2", dispname=f"{str(Tohm)}^2", scale=Tohm.scale * 2) + Tohm3 = Unit.create((Tohm ** 3).unit, name="Tohm3", dispname=f"{str(Tohm)}^3", scale=Tohm.scale * 3) + yohm2 = Unit.create((yohm ** 2).unit, name="yohm2", dispname=f"{str(yohm)}^2", scale=yohm.scale * 2) + yohm3 = Unit.create((yohm ** 3).unit, name="yohm3", dispname=f"{str(yohm)}^3", scale=yohm.scale * 3) + Eohm2 = Unit.create((Eohm ** 2).unit, name="Eohm2", dispname=f"{str(Eohm)}^2", scale=Eohm.scale * 2) + Eohm3 = Unit.create((Eohm ** 3).unit, name="Eohm3", dispname=f"{str(Eohm)}^3", scale=Eohm.scale * 3) + zohm2 = Unit.create((zohm ** 2).unit, name="zohm2", dispname=f"{str(zohm)}^2", scale=zohm.scale * 2) + zohm3 = Unit.create((zohm ** 3).unit, name="zohm3", dispname=f"{str(zohm)}^3", scale=zohm.scale * 3) + Mohm2 = Unit.create((Mohm ** 2).unit, name="Mohm2", dispname=f"{str(Mohm)}^2", scale=Mohm.scale * 2) + Mohm3 = Unit.create((Mohm ** 3).unit, name="Mohm3", dispname=f"{str(Mohm)}^3", scale=Mohm.scale * 3) + kohm2 = Unit.create((kohm ** 2).unit, name="kohm2", dispname=f"{str(kohm)}^2", scale=kohm.scale * 2) + kohm3 = Unit.create((kohm ** 3).unit, name="kohm3", dispname=f"{str(kohm)}^3", scale=kohm.scale * 3) + Yohm2 = Unit.create((Yohm ** 2).unit, name="Yohm2", dispname=f"{str(Yohm)}^2", scale=Yohm.scale * 2) + Yohm3 = Unit.create((Yohm ** 3).unit, name="Yohm3", dispname=f"{str(Yohm)}^3", scale=Yohm.scale * 3) + asiemens2 = Unit.create((asiemens ** 2).unit, name="asiemens2", dispname=f"{str(asiemens)}^2", + scale=asiemens.scale * 2) + asiemens3 = Unit.create((asiemens ** 3).unit, name="asiemens3", dispname=f"{str(asiemens)}^3", + scale=asiemens.scale * 3) + csiemens2 = Unit.create((csiemens ** 2).unit, name="csiemens2", dispname=f"{str(csiemens)}^2", + scale=csiemens.scale * 2) + csiemens3 = Unit.create((csiemens ** 3).unit, name="csiemens3", dispname=f"{str(csiemens)}^3", + scale=csiemens.scale * 3) + Zsiemens2 = Unit.create((Zsiemens ** 2).unit, name="Zsiemens2", dispname=f"{str(Zsiemens)}^2", + scale=Zsiemens.scale * 2) + Zsiemens3 = Unit.create((Zsiemens ** 3).unit, name="Zsiemens3", dispname=f"{str(Zsiemens)}^3", + scale=Zsiemens.scale * 3) + Psiemens2 = Unit.create((Psiemens ** 2).unit, name="Psiemens2", dispname=f"{str(Psiemens)}^2", + scale=Psiemens.scale * 2) + Psiemens3 = Unit.create((Psiemens ** 3).unit, name="Psiemens3", dispname=f"{str(Psiemens)}^3", + scale=Psiemens.scale * 3) + dsiemens2 = Unit.create((dsiemens ** 2).unit, name="dsiemens2", dispname=f"{str(dsiemens)}^2", + scale=dsiemens.scale * 2) + dsiemens3 = Unit.create((dsiemens ** 3).unit, name="dsiemens3", dispname=f"{str(dsiemens)}^3", + scale=dsiemens.scale * 3) + Gsiemens2 = Unit.create((Gsiemens ** 2).unit, name="Gsiemens2", dispname=f"{str(Gsiemens)}^2", + scale=Gsiemens.scale * 2) + Gsiemens3 = Unit.create((Gsiemens ** 3).unit, name="Gsiemens3", dispname=f"{str(Gsiemens)}^3", + scale=Gsiemens.scale * 3) + fsiemens2 = Unit.create((fsiemens ** 2).unit, name="fsiemens2", dispname=f"{str(fsiemens)}^2", + scale=fsiemens.scale * 2) + fsiemens3 = Unit.create((fsiemens ** 3).unit, name="fsiemens3", dispname=f"{str(fsiemens)}^3", + scale=fsiemens.scale * 3) + hsiemens2 = Unit.create((hsiemens ** 2).unit, name="hsiemens2", dispname=f"{str(hsiemens)}^2", + scale=hsiemens.scale * 2) + hsiemens3 = Unit.create((hsiemens ** 3).unit, name="hsiemens3", dispname=f"{str(hsiemens)}^3", + scale=hsiemens.scale * 3) + dasiemens2 = Unit.create((dasiemens ** 2).unit, name="dasiemens2", dispname=f"{str(dasiemens)}^2", + scale=dasiemens.scale * 2) + dasiemens3 = Unit.create((dasiemens ** 3).unit, name="dasiemens3", dispname=f"{str(dasiemens)}^3", + scale=dasiemens.scale * 3) + msiemens2 = Unit.create((msiemens ** 2).unit, name="msiemens2", dispname=f"{str(msiemens)}^2", + scale=msiemens.scale * 2) + msiemens3 = Unit.create((msiemens ** 3).unit, name="msiemens3", dispname=f"{str(msiemens)}^3", + scale=msiemens.scale * 3) + nsiemens2 = Unit.create((nsiemens ** 2).unit, name="nsiemens2", dispname=f"{str(nsiemens)}^2", + scale=nsiemens.scale * 2) + nsiemens3 = Unit.create((nsiemens ** 3).unit, name="nsiemens3", dispname=f"{str(nsiemens)}^3", + scale=nsiemens.scale * 3) + psiemens2 = Unit.create((psiemens ** 2).unit, name="psiemens2", dispname=f"{str(psiemens)}^2", + scale=psiemens.scale * 2) + psiemens3 = Unit.create((psiemens ** 3).unit, name="psiemens3", dispname=f"{str(psiemens)}^3", + scale=psiemens.scale * 3) + usiemens2 = Unit.create((usiemens ** 2).unit, name="usiemens2", dispname=f"{str(usiemens)}^2", + scale=usiemens.scale * 2) + usiemens3 = Unit.create((usiemens ** 3).unit, name="usiemens3", dispname=f"{str(usiemens)}^3", + scale=usiemens.scale * 3) + Tsiemens2 = Unit.create((Tsiemens ** 2).unit, name="Tsiemens2", dispname=f"{str(Tsiemens)}^2", + scale=Tsiemens.scale * 2) + Tsiemens3 = Unit.create((Tsiemens ** 3).unit, name="Tsiemens3", dispname=f"{str(Tsiemens)}^3", + scale=Tsiemens.scale * 3) + ysiemens2 = Unit.create((ysiemens ** 2).unit, name="ysiemens2", dispname=f"{str(ysiemens)}^2", + scale=ysiemens.scale * 2) + ysiemens3 = Unit.create((ysiemens ** 3).unit, name="ysiemens3", dispname=f"{str(ysiemens)}^3", + scale=ysiemens.scale * 3) + Esiemens2 = Unit.create((Esiemens ** 2).unit, name="Esiemens2", dispname=f"{str(Esiemens)}^2", + scale=Esiemens.scale * 2) + Esiemens3 = Unit.create((Esiemens ** 3).unit, name="Esiemens3", dispname=f"{str(Esiemens)}^3", + scale=Esiemens.scale * 3) + zsiemens2 = Unit.create((zsiemens ** 2).unit, name="zsiemens2", dispname=f"{str(zsiemens)}^2", + scale=zsiemens.scale * 2) + zsiemens3 = Unit.create((zsiemens ** 3).unit, name="zsiemens3", dispname=f"{str(zsiemens)}^3", + scale=zsiemens.scale * 3) + Msiemens2 = Unit.create((Msiemens ** 2).unit, name="Msiemens2", dispname=f"{str(Msiemens)}^2", + scale=Msiemens.scale * 2) + Msiemens3 = Unit.create((Msiemens ** 3).unit, name="Msiemens3", dispname=f"{str(Msiemens)}^3", + scale=Msiemens.scale * 3) + ksiemens2 = Unit.create((ksiemens ** 2).unit, name="ksiemens2", dispname=f"{str(ksiemens)}^2", + scale=ksiemens.scale * 2) + ksiemens3 = Unit.create((ksiemens ** 3).unit, name="ksiemens3", dispname=f"{str(ksiemens)}^3", + scale=ksiemens.scale * 3) + Ysiemens2 = Unit.create((Ysiemens ** 2).unit, name="Ysiemens2", dispname=f"{str(Ysiemens)}^2", + scale=Ysiemens.scale * 2) + Ysiemens3 = Unit.create((Ysiemens ** 3).unit, name="Ysiemens3", dispname=f"{str(Ysiemens)}^3", + scale=Ysiemens.scale * 3) + aweber2 = Unit.create((aweber ** 2).unit, name="aweber2", dispname=f"{str(aweber)}^2", scale=aweber.scale * 2) + aweber3 = Unit.create((aweber ** 3).unit, name="aweber3", dispname=f"{str(aweber)}^3", scale=aweber.scale * 3) + cweber2 = Unit.create((cweber ** 2).unit, name="cweber2", dispname=f"{str(cweber)}^2", scale=cweber.scale * 2) + cweber3 = Unit.create((cweber ** 3).unit, name="cweber3", dispname=f"{str(cweber)}^3", scale=cweber.scale * 3) + Zweber2 = Unit.create((Zweber ** 2).unit, name="Zweber2", dispname=f"{str(Zweber)}^2", scale=Zweber.scale * 2) + Zweber3 = Unit.create((Zweber ** 3).unit, name="Zweber3", dispname=f"{str(Zweber)}^3", scale=Zweber.scale * 3) + Pweber2 = Unit.create((Pweber ** 2).unit, name="Pweber2", dispname=f"{str(Pweber)}^2", scale=Pweber.scale * 2) + Pweber3 = Unit.create((Pweber ** 3).unit, name="Pweber3", dispname=f"{str(Pweber)}^3", scale=Pweber.scale * 3) + dweber2 = Unit.create((dweber ** 2).unit, name="dweber2", dispname=f"{str(dweber)}^2", scale=dweber.scale * 2) + dweber3 = Unit.create((dweber ** 3).unit, name="dweber3", dispname=f"{str(dweber)}^3", scale=dweber.scale * 3) + Gweber2 = Unit.create((Gweber ** 2).unit, name="Gweber2", dispname=f"{str(Gweber)}^2", scale=Gweber.scale * 2) + Gweber3 = Unit.create((Gweber ** 3).unit, name="Gweber3", dispname=f"{str(Gweber)}^3", scale=Gweber.scale * 3) + fweber2 = Unit.create((fweber ** 2).unit, name="fweber2", dispname=f"{str(fweber)}^2", scale=fweber.scale * 2) + fweber3 = Unit.create((fweber ** 3).unit, name="fweber3", dispname=f"{str(fweber)}^3", scale=fweber.scale * 3) + hweber2 = Unit.create((hweber ** 2).unit, name="hweber2", dispname=f"{str(hweber)}^2", scale=hweber.scale * 2) + hweber3 = Unit.create((hweber ** 3).unit, name="hweber3", dispname=f"{str(hweber)}^3", scale=hweber.scale * 3) + daweber2 = Unit.create((daweber ** 2).unit, name="daweber2", dispname=f"{str(daweber)}^2", scale=daweber.scale * 2) + daweber3 = Unit.create((daweber ** 3).unit, name="daweber3", dispname=f"{str(daweber)}^3", scale=daweber.scale * 3) + mweber2 = Unit.create((mweber ** 2).unit, name="mweber2", dispname=f"{str(mweber)}^2", scale=mweber.scale * 2) + mweber3 = Unit.create((mweber ** 3).unit, name="mweber3", dispname=f"{str(mweber)}^3", scale=mweber.scale * 3) + nweber2 = Unit.create((nweber ** 2).unit, name="nweber2", dispname=f"{str(nweber)}^2", scale=nweber.scale * 2) + nweber3 = Unit.create((nweber ** 3).unit, name="nweber3", dispname=f"{str(nweber)}^3", scale=nweber.scale * 3) + pweber2 = Unit.create((pweber ** 2).unit, name="pweber2", dispname=f"{str(pweber)}^2", scale=pweber.scale * 2) + pweber3 = Unit.create((pweber ** 3).unit, name="pweber3", dispname=f"{str(pweber)}^3", scale=pweber.scale * 3) + uweber2 = Unit.create((uweber ** 2).unit, name="uweber2", dispname=f"{str(uweber)}^2", scale=uweber.scale * 2) + uweber3 = Unit.create((uweber ** 3).unit, name="uweber3", dispname=f"{str(uweber)}^3", scale=uweber.scale * 3) + Tweber2 = Unit.create((Tweber ** 2).unit, name="Tweber2", dispname=f"{str(Tweber)}^2", scale=Tweber.scale * 2) + Tweber3 = Unit.create((Tweber ** 3).unit, name="Tweber3", dispname=f"{str(Tweber)}^3", scale=Tweber.scale * 3) + yweber2 = Unit.create((yweber ** 2).unit, name="yweber2", dispname=f"{str(yweber)}^2", scale=yweber.scale * 2) + yweber3 = Unit.create((yweber ** 3).unit, name="yweber3", dispname=f"{str(yweber)}^3", scale=yweber.scale * 3) + Eweber2 = Unit.create((Eweber ** 2).unit, name="Eweber2", dispname=f"{str(Eweber)}^2", scale=Eweber.scale * 2) + Eweber3 = Unit.create((Eweber ** 3).unit, name="Eweber3", dispname=f"{str(Eweber)}^3", scale=Eweber.scale * 3) + zweber2 = Unit.create((zweber ** 2).unit, name="zweber2", dispname=f"{str(zweber)}^2", scale=zweber.scale * 2) + zweber3 = Unit.create((zweber ** 3).unit, name="zweber3", dispname=f"{str(zweber)}^3", scale=zweber.scale * 3) + Mweber2 = Unit.create((Mweber ** 2).unit, name="Mweber2", dispname=f"{str(Mweber)}^2", scale=Mweber.scale * 2) + Mweber3 = Unit.create((Mweber ** 3).unit, name="Mweber3", dispname=f"{str(Mweber)}^3", scale=Mweber.scale * 3) + kweber2 = Unit.create((kweber ** 2).unit, name="kweber2", dispname=f"{str(kweber)}^2", scale=kweber.scale * 2) + kweber3 = Unit.create((kweber ** 3).unit, name="kweber3", dispname=f"{str(kweber)}^3", scale=kweber.scale * 3) + Yweber2 = Unit.create((Yweber ** 2).unit, name="Yweber2", dispname=f"{str(Yweber)}^2", scale=Yweber.scale * 2) + Yweber3 = Unit.create((Yweber ** 3).unit, name="Yweber3", dispname=f"{str(Yweber)}^3", scale=Yweber.scale * 3) + atesla2 = Unit.create((atesla ** 2).unit, name="atesla2", dispname=f"{str(atesla)}^2", scale=atesla.scale * 2) + atesla3 = Unit.create((atesla ** 3).unit, name="atesla3", dispname=f"{str(atesla)}^3", scale=atesla.scale * 3) + ctesla2 = Unit.create((ctesla ** 2).unit, name="ctesla2", dispname=f"{str(ctesla)}^2", scale=ctesla.scale * 2) + ctesla3 = Unit.create((ctesla ** 3).unit, name="ctesla3", dispname=f"{str(ctesla)}^3", scale=ctesla.scale * 3) + Ztesla2 = Unit.create((Ztesla ** 2).unit, name="Ztesla2", dispname=f"{str(Ztesla)}^2", scale=Ztesla.scale * 2) + Ztesla3 = Unit.create((Ztesla ** 3).unit, name="Ztesla3", dispname=f"{str(Ztesla)}^3", scale=Ztesla.scale * 3) + Ptesla2 = Unit.create((Ptesla ** 2).unit, name="Ptesla2", dispname=f"{str(Ptesla)}^2", scale=Ptesla.scale * 2) + Ptesla3 = Unit.create((Ptesla ** 3).unit, name="Ptesla3", dispname=f"{str(Ptesla)}^3", scale=Ptesla.scale * 3) + dtesla2 = Unit.create((dtesla ** 2).unit, name="dtesla2", dispname=f"{str(dtesla)}^2", scale=dtesla.scale * 2) + dtesla3 = Unit.create((dtesla ** 3).unit, name="dtesla3", dispname=f"{str(dtesla)}^3", scale=dtesla.scale * 3) + Gtesla2 = Unit.create((Gtesla ** 2).unit, name="Gtesla2", dispname=f"{str(Gtesla)}^2", scale=Gtesla.scale * 2) + Gtesla3 = Unit.create((Gtesla ** 3).unit, name="Gtesla3", dispname=f"{str(Gtesla)}^3", scale=Gtesla.scale * 3) + ftesla2 = Unit.create((ftesla ** 2).unit, name="ftesla2", dispname=f"{str(ftesla)}^2", scale=ftesla.scale * 2) + ftesla3 = Unit.create((ftesla ** 3).unit, name="ftesla3", dispname=f"{str(ftesla)}^3", scale=ftesla.scale * 3) + htesla2 = Unit.create((htesla ** 2).unit, name="htesla2", dispname=f"{str(htesla)}^2", scale=htesla.scale * 2) + htesla3 = Unit.create((htesla ** 3).unit, name="htesla3", dispname=f"{str(htesla)}^3", scale=htesla.scale * 3) + datesla2 = Unit.create((datesla ** 2).unit, name="datesla2", dispname=f"{str(datesla)}^2", scale=datesla.scale * 2) + datesla3 = Unit.create((datesla ** 3).unit, name="datesla3", dispname=f"{str(datesla)}^3", scale=datesla.scale * 3) + mtesla2 = Unit.create((mtesla ** 2).unit, name="mtesla2", dispname=f"{str(mtesla)}^2", scale=mtesla.scale * 2) + mtesla3 = Unit.create((mtesla ** 3).unit, name="mtesla3", dispname=f"{str(mtesla)}^3", scale=mtesla.scale * 3) + ntesla2 = Unit.create((ntesla ** 2).unit, name="ntesla2", dispname=f"{str(ntesla)}^2", scale=ntesla.scale * 2) + ntesla3 = Unit.create((ntesla ** 3).unit, name="ntesla3", dispname=f"{str(ntesla)}^3", scale=ntesla.scale * 3) + ptesla2 = Unit.create((ptesla ** 2).unit, name="ptesla2", dispname=f"{str(ptesla)}^2", scale=ptesla.scale * 2) + ptesla3 = Unit.create((ptesla ** 3).unit, name="ptesla3", dispname=f"{str(ptesla)}^3", scale=ptesla.scale * 3) + utesla2 = Unit.create((utesla ** 2).unit, name="utesla2", dispname=f"{str(utesla)}^2", scale=utesla.scale * 2) + utesla3 = Unit.create((utesla ** 3).unit, name="utesla3", dispname=f"{str(utesla)}^3", scale=utesla.scale * 3) + Ttesla2 = Unit.create((Ttesla ** 2).unit, name="Ttesla2", dispname=f"{str(Ttesla)}^2", scale=Ttesla.scale * 2) + Ttesla3 = Unit.create((Ttesla ** 3).unit, name="Ttesla3", dispname=f"{str(Ttesla)}^3", scale=Ttesla.scale * 3) + ytesla2 = Unit.create((ytesla ** 2).unit, name="ytesla2", dispname=f"{str(ytesla)}^2", scale=ytesla.scale * 2) + ytesla3 = Unit.create((ytesla ** 3).unit, name="ytesla3", dispname=f"{str(ytesla)}^3", scale=ytesla.scale * 3) + Etesla2 = Unit.create((Etesla ** 2).unit, name="Etesla2", dispname=f"{str(Etesla)}^2", scale=Etesla.scale * 2) + Etesla3 = Unit.create((Etesla ** 3).unit, name="Etesla3", dispname=f"{str(Etesla)}^3", scale=Etesla.scale * 3) + ztesla2 = Unit.create((ztesla ** 2).unit, name="ztesla2", dispname=f"{str(ztesla)}^2", scale=ztesla.scale * 2) + ztesla3 = Unit.create((ztesla ** 3).unit, name="ztesla3", dispname=f"{str(ztesla)}^3", scale=ztesla.scale * 3) + Mtesla2 = Unit.create((Mtesla ** 2).unit, name="Mtesla2", dispname=f"{str(Mtesla)}^2", scale=Mtesla.scale * 2) + Mtesla3 = Unit.create((Mtesla ** 3).unit, name="Mtesla3", dispname=f"{str(Mtesla)}^3", scale=Mtesla.scale * 3) + ktesla2 = Unit.create((ktesla ** 2).unit, name="ktesla2", dispname=f"{str(ktesla)}^2", scale=ktesla.scale * 2) + ktesla3 = Unit.create((ktesla ** 3).unit, name="ktesla3", dispname=f"{str(ktesla)}^3", scale=ktesla.scale * 3) + Ytesla2 = Unit.create((Ytesla ** 2).unit, name="Ytesla2", dispname=f"{str(Ytesla)}^2", scale=Ytesla.scale * 2) + Ytesla3 = Unit.create((Ytesla ** 3).unit, name="Ytesla3", dispname=f"{str(Ytesla)}^3", scale=Ytesla.scale * 3) + ahenry2 = Unit.create((ahenry ** 2).unit, name="ahenry2", dispname=f"{str(ahenry)}^2", scale=ahenry.scale * 2) + ahenry3 = Unit.create((ahenry ** 3).unit, name="ahenry3", dispname=f"{str(ahenry)}^3", scale=ahenry.scale * 3) + chenry2 = Unit.create((chenry ** 2).unit, name="chenry2", dispname=f"{str(chenry)}^2", scale=chenry.scale * 2) + chenry3 = Unit.create((chenry ** 3).unit, name="chenry3", dispname=f"{str(chenry)}^3", scale=chenry.scale * 3) + Zhenry2 = Unit.create((Zhenry ** 2).unit, name="Zhenry2", dispname=f"{str(Zhenry)}^2", scale=Zhenry.scale * 2) + Zhenry3 = Unit.create((Zhenry ** 3).unit, name="Zhenry3", dispname=f"{str(Zhenry)}^3", scale=Zhenry.scale * 3) + Phenry2 = Unit.create((Phenry ** 2).unit, name="Phenry2", dispname=f"{str(Phenry)}^2", scale=Phenry.scale * 2) + Phenry3 = Unit.create((Phenry ** 3).unit, name="Phenry3", dispname=f"{str(Phenry)}^3", scale=Phenry.scale * 3) + dhenry2 = Unit.create((dhenry ** 2).unit, name="dhenry2", dispname=f"{str(dhenry)}^2", scale=dhenry.scale * 2) + dhenry3 = Unit.create((dhenry ** 3).unit, name="dhenry3", dispname=f"{str(dhenry)}^3", scale=dhenry.scale * 3) + Ghenry2 = Unit.create((Ghenry ** 2).unit, name="Ghenry2", dispname=f"{str(Ghenry)}^2", scale=Ghenry.scale * 2) + Ghenry3 = Unit.create((Ghenry ** 3).unit, name="Ghenry3", dispname=f"{str(Ghenry)}^3", scale=Ghenry.scale * 3) + fhenry2 = Unit.create((fhenry ** 2).unit, name="fhenry2", dispname=f"{str(fhenry)}^2", scale=fhenry.scale * 2) + fhenry3 = Unit.create((fhenry ** 3).unit, name="fhenry3", dispname=f"{str(fhenry)}^3", scale=fhenry.scale * 3) + hhenry2 = Unit.create((hhenry ** 2).unit, name="hhenry2", dispname=f"{str(hhenry)}^2", scale=hhenry.scale * 2) + hhenry3 = Unit.create((hhenry ** 3).unit, name="hhenry3", dispname=f"{str(hhenry)}^3", scale=hhenry.scale * 3) + dahenry2 = Unit.create((dahenry ** 2).unit, name="dahenry2", dispname=f"{str(dahenry)}^2", scale=dahenry.scale * 2) + dahenry3 = Unit.create((dahenry ** 3).unit, name="dahenry3", dispname=f"{str(dahenry)}^3", scale=dahenry.scale * 3) + mhenry2 = Unit.create((mhenry ** 2).unit, name="mhenry2", dispname=f"{str(mhenry)}^2", scale=mhenry.scale * 2) + mhenry3 = Unit.create((mhenry ** 3).unit, name="mhenry3", dispname=f"{str(mhenry)}^3", scale=mhenry.scale * 3) + nhenry2 = Unit.create((nhenry ** 2).unit, name="nhenry2", dispname=f"{str(nhenry)}^2", scale=nhenry.scale * 2) + nhenry3 = Unit.create((nhenry ** 3).unit, name="nhenry3", dispname=f"{str(nhenry)}^3", scale=nhenry.scale * 3) + phenry2 = Unit.create((phenry ** 2).unit, name="phenry2", dispname=f"{str(phenry)}^2", scale=phenry.scale * 2) + phenry3 = Unit.create((phenry ** 3).unit, name="phenry3", dispname=f"{str(phenry)}^3", scale=phenry.scale * 3) + uhenry2 = Unit.create((uhenry ** 2).unit, name="uhenry2", dispname=f"{str(uhenry)}^2", scale=uhenry.scale * 2) + uhenry3 = Unit.create((uhenry ** 3).unit, name="uhenry3", dispname=f"{str(uhenry)}^3", scale=uhenry.scale * 3) + Thenry2 = Unit.create((Thenry ** 2).unit, name="Thenry2", dispname=f"{str(Thenry)}^2", scale=Thenry.scale * 2) + Thenry3 = Unit.create((Thenry ** 3).unit, name="Thenry3", dispname=f"{str(Thenry)}^3", scale=Thenry.scale * 3) + yhenry2 = Unit.create((yhenry ** 2).unit, name="yhenry2", dispname=f"{str(yhenry)}^2", scale=yhenry.scale * 2) + yhenry3 = Unit.create((yhenry ** 3).unit, name="yhenry3", dispname=f"{str(yhenry)}^3", scale=yhenry.scale * 3) + Ehenry2 = Unit.create((Ehenry ** 2).unit, name="Ehenry2", dispname=f"{str(Ehenry)}^2", scale=Ehenry.scale * 2) + Ehenry3 = Unit.create((Ehenry ** 3).unit, name="Ehenry3", dispname=f"{str(Ehenry)}^3", scale=Ehenry.scale * 3) + zhenry2 = Unit.create((zhenry ** 2).unit, name="zhenry2", dispname=f"{str(zhenry)}^2", scale=zhenry.scale * 2) + zhenry3 = Unit.create((zhenry ** 3).unit, name="zhenry3", dispname=f"{str(zhenry)}^3", scale=zhenry.scale * 3) + Mhenry2 = Unit.create((Mhenry ** 2).unit, name="Mhenry2", dispname=f"{str(Mhenry)}^2", scale=Mhenry.scale * 2) + Mhenry3 = Unit.create((Mhenry ** 3).unit, name="Mhenry3", dispname=f"{str(Mhenry)}^3", scale=Mhenry.scale * 3) + khenry2 = Unit.create((khenry ** 2).unit, name="khenry2", dispname=f"{str(khenry)}^2", scale=khenry.scale * 2) + khenry3 = Unit.create((khenry ** 3).unit, name="khenry3", dispname=f"{str(khenry)}^3", scale=khenry.scale * 3) + Yhenry2 = Unit.create((Yhenry ** 2).unit, name="Yhenry2", dispname=f"{str(Yhenry)}^2", scale=Yhenry.scale * 2) + Yhenry3 = Unit.create((Yhenry ** 3).unit, name="Yhenry3", dispname=f"{str(Yhenry)}^3", scale=Yhenry.scale * 3) + alumen2 = Unit.create((alumen ** 2).unit, name="alumen2", dispname=f"{str(alumen)}^2", scale=alumen.scale * 2) + alumen3 = Unit.create((alumen ** 3).unit, name="alumen3", dispname=f"{str(alumen)}^3", scale=alumen.scale * 3) + clumen2 = Unit.create((clumen ** 2).unit, name="clumen2", dispname=f"{str(clumen)}^2", scale=clumen.scale * 2) + clumen3 = Unit.create((clumen ** 3).unit, name="clumen3", dispname=f"{str(clumen)}^3", scale=clumen.scale * 3) + Zlumen2 = Unit.create((Zlumen ** 2).unit, name="Zlumen2", dispname=f"{str(Zlumen)}^2", scale=Zlumen.scale * 2) + Zlumen3 = Unit.create((Zlumen ** 3).unit, name="Zlumen3", dispname=f"{str(Zlumen)}^3", scale=Zlumen.scale * 3) + Plumen2 = Unit.create((Plumen ** 2).unit, name="Plumen2", dispname=f"{str(Plumen)}^2", scale=Plumen.scale * 2) + Plumen3 = Unit.create((Plumen ** 3).unit, name="Plumen3", dispname=f"{str(Plumen)}^3", scale=Plumen.scale * 3) + dlumen2 = Unit.create((dlumen ** 2).unit, name="dlumen2", dispname=f"{str(dlumen)}^2", scale=dlumen.scale * 2) + dlumen3 = Unit.create((dlumen ** 3).unit, name="dlumen3", dispname=f"{str(dlumen)}^3", scale=dlumen.scale * 3) + Glumen2 = Unit.create((Glumen ** 2).unit, name="Glumen2", dispname=f"{str(Glumen)}^2", scale=Glumen.scale * 2) + Glumen3 = Unit.create((Glumen ** 3).unit, name="Glumen3", dispname=f"{str(Glumen)}^3", scale=Glumen.scale * 3) + flumen2 = Unit.create((flumen ** 2).unit, name="flumen2", dispname=f"{str(flumen)}^2", scale=flumen.scale * 2) + flumen3 = Unit.create((flumen ** 3).unit, name="flumen3", dispname=f"{str(flumen)}^3", scale=flumen.scale * 3) + hlumen2 = Unit.create((hlumen ** 2).unit, name="hlumen2", dispname=f"{str(hlumen)}^2", scale=hlumen.scale * 2) + hlumen3 = Unit.create((hlumen ** 3).unit, name="hlumen3", dispname=f"{str(hlumen)}^3", scale=hlumen.scale * 3) + dalumen2 = Unit.create((dalumen ** 2).unit, name="dalumen2", dispname=f"{str(dalumen)}^2", scale=dalumen.scale * 2) + dalumen3 = Unit.create((dalumen ** 3).unit, name="dalumen3", dispname=f"{str(dalumen)}^3", scale=dalumen.scale * 3) + mlumen2 = Unit.create((mlumen ** 2).unit, name="mlumen2", dispname=f"{str(mlumen)}^2", scale=mlumen.scale * 2) + mlumen3 = Unit.create((mlumen ** 3).unit, name="mlumen3", dispname=f"{str(mlumen)}^3", scale=mlumen.scale * 3) + nlumen2 = Unit.create((nlumen ** 2).unit, name="nlumen2", dispname=f"{str(nlumen)}^2", scale=nlumen.scale * 2) + nlumen3 = Unit.create((nlumen ** 3).unit, name="nlumen3", dispname=f"{str(nlumen)}^3", scale=nlumen.scale * 3) + plumen2 = Unit.create((plumen ** 2).unit, name="plumen2", dispname=f"{str(plumen)}^2", scale=plumen.scale * 2) + plumen3 = Unit.create((plumen ** 3).unit, name="plumen3", dispname=f"{str(plumen)}^3", scale=plumen.scale * 3) + ulumen2 = Unit.create((ulumen ** 2).unit, name="ulumen2", dispname=f"{str(ulumen)}^2", scale=ulumen.scale * 2) + ulumen3 = Unit.create((ulumen ** 3).unit, name="ulumen3", dispname=f"{str(ulumen)}^3", scale=ulumen.scale * 3) + Tlumen2 = Unit.create((Tlumen ** 2).unit, name="Tlumen2", dispname=f"{str(Tlumen)}^2", scale=Tlumen.scale * 2) + Tlumen3 = Unit.create((Tlumen ** 3).unit, name="Tlumen3", dispname=f"{str(Tlumen)}^3", scale=Tlumen.scale * 3) + ylumen2 = Unit.create((ylumen ** 2).unit, name="ylumen2", dispname=f"{str(ylumen)}^2", scale=ylumen.scale * 2) + ylumen3 = Unit.create((ylumen ** 3).unit, name="ylumen3", dispname=f"{str(ylumen)}^3", scale=ylumen.scale * 3) + Elumen2 = Unit.create((Elumen ** 2).unit, name="Elumen2", dispname=f"{str(Elumen)}^2", scale=Elumen.scale * 2) + Elumen3 = Unit.create((Elumen ** 3).unit, name="Elumen3", dispname=f"{str(Elumen)}^3", scale=Elumen.scale * 3) + zlumen2 = Unit.create((zlumen ** 2).unit, name="zlumen2", dispname=f"{str(zlumen)}^2", scale=zlumen.scale * 2) + zlumen3 = Unit.create((zlumen ** 3).unit, name="zlumen3", dispname=f"{str(zlumen)}^3", scale=zlumen.scale * 3) + Mlumen2 = Unit.create((Mlumen ** 2).unit, name="Mlumen2", dispname=f"{str(Mlumen)}^2", scale=Mlumen.scale * 2) + Mlumen3 = Unit.create((Mlumen ** 3).unit, name="Mlumen3", dispname=f"{str(Mlumen)}^3", scale=Mlumen.scale * 3) + klumen2 = Unit.create((klumen ** 2).unit, name="klumen2", dispname=f"{str(klumen)}^2", scale=klumen.scale * 2) + klumen3 = Unit.create((klumen ** 3).unit, name="klumen3", dispname=f"{str(klumen)}^3", scale=klumen.scale * 3) + Ylumen2 = Unit.create((Ylumen ** 2).unit, name="Ylumen2", dispname=f"{str(Ylumen)}^2", scale=Ylumen.scale * 2) + Ylumen3 = Unit.create((Ylumen ** 3).unit, name="Ylumen3", dispname=f"{str(Ylumen)}^3", scale=Ylumen.scale * 3) + alux2 = Unit.create((alux ** 2).unit, name="alux2", dispname=f"{str(alux)}^2", scale=alux.scale * 2) + alux3 = Unit.create((alux ** 3).unit, name="alux3", dispname=f"{str(alux)}^3", scale=alux.scale * 3) + clux2 = Unit.create((clux ** 2).unit, name="clux2", dispname=f"{str(clux)}^2", scale=clux.scale * 2) + clux3 = Unit.create((clux ** 3).unit, name="clux3", dispname=f"{str(clux)}^3", scale=clux.scale * 3) + Zlux2 = Unit.create((Zlux ** 2).unit, name="Zlux2", dispname=f"{str(Zlux)}^2", scale=Zlux.scale * 2) + Zlux3 = Unit.create((Zlux ** 3).unit, name="Zlux3", dispname=f"{str(Zlux)}^3", scale=Zlux.scale * 3) + Plux2 = Unit.create((Plux ** 2).unit, name="Plux2", dispname=f"{str(Plux)}^2", scale=Plux.scale * 2) + Plux3 = Unit.create((Plux ** 3).unit, name="Plux3", dispname=f"{str(Plux)}^3", scale=Plux.scale * 3) + dlux2 = Unit.create((dlux ** 2).unit, name="dlux2", dispname=f"{str(dlux)}^2", scale=dlux.scale * 2) + dlux3 = Unit.create((dlux ** 3).unit, name="dlux3", dispname=f"{str(dlux)}^3", scale=dlux.scale * 3) + Glux2 = Unit.create((Glux ** 2).unit, name="Glux2", dispname=f"{str(Glux)}^2", scale=Glux.scale * 2) + Glux3 = Unit.create((Glux ** 3).unit, name="Glux3", dispname=f"{str(Glux)}^3", scale=Glux.scale * 3) + flux2 = Unit.create((flux ** 2).unit, name="flux2", dispname=f"{str(flux)}^2", scale=flux.scale * 2) + flux3 = Unit.create((flux ** 3).unit, name="flux3", dispname=f"{str(flux)}^3", scale=flux.scale * 3) + hlux2 = Unit.create((hlux ** 2).unit, name="hlux2", dispname=f"{str(hlux)}^2", scale=hlux.scale * 2) + hlux3 = Unit.create((hlux ** 3).unit, name="hlux3", dispname=f"{str(hlux)}^3", scale=hlux.scale * 3) + dalux2 = Unit.create((dalux ** 2).unit, name="dalux2", dispname=f"{str(dalux)}^2", scale=dalux.scale * 2) + dalux3 = Unit.create((dalux ** 3).unit, name="dalux3", dispname=f"{str(dalux)}^3", scale=dalux.scale * 3) + mlux2 = Unit.create((mlux ** 2).unit, name="mlux2", dispname=f"{str(mlux)}^2", scale=mlux.scale * 2) + mlux3 = Unit.create((mlux ** 3).unit, name="mlux3", dispname=f"{str(mlux)}^3", scale=mlux.scale * 3) + nlux2 = Unit.create((nlux ** 2).unit, name="nlux2", dispname=f"{str(nlux)}^2", scale=nlux.scale * 2) + nlux3 = Unit.create((nlux ** 3).unit, name="nlux3", dispname=f"{str(nlux)}^3", scale=nlux.scale * 3) + plux2 = Unit.create((plux ** 2).unit, name="plux2", dispname=f"{str(plux)}^2", scale=plux.scale * 2) + plux3 = Unit.create((plux ** 3).unit, name="plux3", dispname=f"{str(plux)}^3", scale=plux.scale * 3) + ulux2 = Unit.create((ulux ** 2).unit, name="ulux2", dispname=f"{str(ulux)}^2", scale=ulux.scale * 2) + ulux3 = Unit.create((ulux ** 3).unit, name="ulux3", dispname=f"{str(ulux)}^3", scale=ulux.scale * 3) + Tlux2 = Unit.create((Tlux ** 2).unit, name="Tlux2", dispname=f"{str(Tlux)}^2", scale=Tlux.scale * 2) + Tlux3 = Unit.create((Tlux ** 3).unit, name="Tlux3", dispname=f"{str(Tlux)}^3", scale=Tlux.scale * 3) + ylux2 = Unit.create((ylux ** 2).unit, name="ylux2", dispname=f"{str(ylux)}^2", scale=ylux.scale * 2) + ylux3 = Unit.create((ylux ** 3).unit, name="ylux3", dispname=f"{str(ylux)}^3", scale=ylux.scale * 3) + Elux2 = Unit.create((Elux ** 2).unit, name="Elux2", dispname=f"{str(Elux)}^2", scale=Elux.scale * 2) + Elux3 = Unit.create((Elux ** 3).unit, name="Elux3", dispname=f"{str(Elux)}^3", scale=Elux.scale * 3) + zlux2 = Unit.create((zlux ** 2).unit, name="zlux2", dispname=f"{str(zlux)}^2", scale=zlux.scale * 2) + zlux3 = Unit.create((zlux ** 3).unit, name="zlux3", dispname=f"{str(zlux)}^3", scale=zlux.scale * 3) + Mlux2 = Unit.create((Mlux ** 2).unit, name="Mlux2", dispname=f"{str(Mlux)}^2", scale=Mlux.scale * 2) + Mlux3 = Unit.create((Mlux ** 3).unit, name="Mlux3", dispname=f"{str(Mlux)}^3", scale=Mlux.scale * 3) + klux2 = Unit.create((klux ** 2).unit, name="klux2", dispname=f"{str(klux)}^2", scale=klux.scale * 2) + klux3 = Unit.create((klux ** 3).unit, name="klux3", dispname=f"{str(klux)}^3", scale=klux.scale * 3) + Ylux2 = Unit.create((Ylux ** 2).unit, name="Ylux2", dispname=f"{str(Ylux)}^2", scale=Ylux.scale * 2) + Ylux3 = Unit.create((Ylux ** 3).unit, name="Ylux3", dispname=f"{str(Ylux)}^3", scale=Ylux.scale * 3) + abecquerel2 = Unit.create((abecquerel ** 2).unit, name="abecquerel2", dispname=f"{str(abecquerel)}^2", + scale=abecquerel.scale * 2) + abecquerel3 = Unit.create((abecquerel ** 3).unit, name="abecquerel3", dispname=f"{str(abecquerel)}^3", + scale=abecquerel.scale * 3) + cbecquerel2 = Unit.create((cbecquerel ** 2).unit, name="cbecquerel2", dispname=f"{str(cbecquerel)}^2", + scale=cbecquerel.scale * 2) + cbecquerel3 = Unit.create((cbecquerel ** 3).unit, name="cbecquerel3", dispname=f"{str(cbecquerel)}^3", + scale=cbecquerel.scale * 3) + Zbecquerel2 = Unit.create((Zbecquerel ** 2).unit, name="Zbecquerel2", dispname=f"{str(Zbecquerel)}^2", + scale=Zbecquerel.scale * 2) + Zbecquerel3 = Unit.create((Zbecquerel ** 3).unit, name="Zbecquerel3", dispname=f"{str(Zbecquerel)}^3", + scale=Zbecquerel.scale * 3) + Pbecquerel2 = Unit.create((Pbecquerel ** 2).unit, name="Pbecquerel2", dispname=f"{str(Pbecquerel)}^2", + scale=Pbecquerel.scale * 2) + Pbecquerel3 = Unit.create((Pbecquerel ** 3).unit, name="Pbecquerel3", dispname=f"{str(Pbecquerel)}^3", + scale=Pbecquerel.scale * 3) + dbecquerel2 = Unit.create((dbecquerel ** 2).unit, name="dbecquerel2", dispname=f"{str(dbecquerel)}^2", + scale=dbecquerel.scale * 2) + dbecquerel3 = Unit.create((dbecquerel ** 3).unit, name="dbecquerel3", dispname=f"{str(dbecquerel)}^3", + scale=dbecquerel.scale * 3) + Gbecquerel2 = Unit.create((Gbecquerel ** 2).unit, name="Gbecquerel2", dispname=f"{str(Gbecquerel)}^2", + scale=Gbecquerel.scale * 2) + Gbecquerel3 = Unit.create((Gbecquerel ** 3).unit, name="Gbecquerel3", dispname=f"{str(Gbecquerel)}^3", + scale=Gbecquerel.scale * 3) + fbecquerel2 = Unit.create((fbecquerel ** 2).unit, name="fbecquerel2", dispname=f"{str(fbecquerel)}^2", + scale=fbecquerel.scale * 2) + fbecquerel3 = Unit.create((fbecquerel ** 3).unit, name="fbecquerel3", dispname=f"{str(fbecquerel)}^3", + scale=fbecquerel.scale * 3) + hbecquerel2 = Unit.create((hbecquerel ** 2).unit, name="hbecquerel2", dispname=f"{str(hbecquerel)}^2", + scale=hbecquerel.scale * 2) + hbecquerel3 = Unit.create((hbecquerel ** 3).unit, name="hbecquerel3", dispname=f"{str(hbecquerel)}^3", + scale=hbecquerel.scale * 3) + dabecquerel2 = Unit.create((dabecquerel ** 2).unit, name="dabecquerel2", dispname=f"{str(dabecquerel)}^2", + scale=dabecquerel.scale * 2) + dabecquerel3 = Unit.create((dabecquerel ** 3).unit, name="dabecquerel3", dispname=f"{str(dabecquerel)}^3", + scale=dabecquerel.scale * 3) + mbecquerel2 = Unit.create((mbecquerel ** 2).unit, name="mbecquerel2", dispname=f"{str(mbecquerel)}^2", + scale=mbecquerel.scale * 2) + mbecquerel3 = Unit.create((mbecquerel ** 3).unit, name="mbecquerel3", dispname=f"{str(mbecquerel)}^3", + scale=mbecquerel.scale * 3) + nbecquerel2 = Unit.create((nbecquerel ** 2).unit, name="nbecquerel2", dispname=f"{str(nbecquerel)}^2", + scale=nbecquerel.scale * 2) + nbecquerel3 = Unit.create((nbecquerel ** 3).unit, name="nbecquerel3", dispname=f"{str(nbecquerel)}^3", + scale=nbecquerel.scale * 3) + pbecquerel2 = Unit.create((pbecquerel ** 2).unit, name="pbecquerel2", dispname=f"{str(pbecquerel)}^2", + scale=pbecquerel.scale * 2) + pbecquerel3 = Unit.create((pbecquerel ** 3).unit, name="pbecquerel3", dispname=f"{str(pbecquerel)}^3", + scale=pbecquerel.scale * 3) + ubecquerel2 = Unit.create((ubecquerel ** 2).unit, name="ubecquerel2", dispname=f"{str(ubecquerel)}^2", + scale=ubecquerel.scale * 2) + ubecquerel3 = Unit.create((ubecquerel ** 3).unit, name="ubecquerel3", dispname=f"{str(ubecquerel)}^3", + scale=ubecquerel.scale * 3) + Tbecquerel2 = Unit.create((Tbecquerel ** 2).unit, name="Tbecquerel2", dispname=f"{str(Tbecquerel)}^2", + scale=Tbecquerel.scale * 2) + Tbecquerel3 = Unit.create((Tbecquerel ** 3).unit, name="Tbecquerel3", dispname=f"{str(Tbecquerel)}^3", + scale=Tbecquerel.scale * 3) + ybecquerel2 = Unit.create((ybecquerel ** 2).unit, name="ybecquerel2", dispname=f"{str(ybecquerel)}^2", + scale=ybecquerel.scale * 2) + ybecquerel3 = Unit.create((ybecquerel ** 3).unit, name="ybecquerel3", dispname=f"{str(ybecquerel)}^3", + scale=ybecquerel.scale * 3) + Ebecquerel2 = Unit.create((Ebecquerel ** 2).unit, name="Ebecquerel2", dispname=f"{str(Ebecquerel)}^2", + scale=Ebecquerel.scale * 2) + Ebecquerel3 = Unit.create((Ebecquerel ** 3).unit, name="Ebecquerel3", dispname=f"{str(Ebecquerel)}^3", + scale=Ebecquerel.scale * 3) + zbecquerel2 = Unit.create((zbecquerel ** 2).unit, name="zbecquerel2", dispname=f"{str(zbecquerel)}^2", + scale=zbecquerel.scale * 2) + zbecquerel3 = Unit.create((zbecquerel ** 3).unit, name="zbecquerel3", dispname=f"{str(zbecquerel)}^3", + scale=zbecquerel.scale * 3) + Mbecquerel2 = Unit.create((Mbecquerel ** 2).unit, name="Mbecquerel2", dispname=f"{str(Mbecquerel)}^2", + scale=Mbecquerel.scale * 2) + Mbecquerel3 = Unit.create((Mbecquerel ** 3).unit, name="Mbecquerel3", dispname=f"{str(Mbecquerel)}^3", + scale=Mbecquerel.scale * 3) + kbecquerel2 = Unit.create((kbecquerel ** 2).unit, name="kbecquerel2", dispname=f"{str(kbecquerel)}^2", + scale=kbecquerel.scale * 2) + kbecquerel3 = Unit.create((kbecquerel ** 3).unit, name="kbecquerel3", dispname=f"{str(kbecquerel)}^3", + scale=kbecquerel.scale * 3) + Ybecquerel2 = Unit.create((Ybecquerel ** 2).unit, name="Ybecquerel2", dispname=f"{str(Ybecquerel)}^2", + scale=Ybecquerel.scale * 2) + Ybecquerel3 = Unit.create((Ybecquerel ** 3).unit, name="Ybecquerel3", dispname=f"{str(Ybecquerel)}^3", + scale=Ybecquerel.scale * 3) + agray2 = Unit.create((agray ** 2).unit, name="agray2", dispname=f"{str(agray)}^2", scale=agray.scale * 2) + agray3 = Unit.create((agray ** 3).unit, name="agray3", dispname=f"{str(agray)}^3", scale=agray.scale * 3) + cgray2 = Unit.create((cgray ** 2).unit, name="cgray2", dispname=f"{str(cgray)}^2", scale=cgray.scale * 2) + cgray3 = Unit.create((cgray ** 3).unit, name="cgray3", dispname=f"{str(cgray)}^3", scale=cgray.scale * 3) + Zgray2 = Unit.create((Zgray ** 2).unit, name="Zgray2", dispname=f"{str(Zgray)}^2", scale=Zgray.scale * 2) + Zgray3 = Unit.create((Zgray ** 3).unit, name="Zgray3", dispname=f"{str(Zgray)}^3", scale=Zgray.scale * 3) + Pgray2 = Unit.create((Pgray ** 2).unit, name="Pgray2", dispname=f"{str(Pgray)}^2", scale=Pgray.scale * 2) + Pgray3 = Unit.create((Pgray ** 3).unit, name="Pgray3", dispname=f"{str(Pgray)}^3", scale=Pgray.scale * 3) + dgray2 = Unit.create((dgray ** 2).unit, name="dgray2", dispname=f"{str(dgray)}^2", scale=dgray.scale * 2) + dgray3 = Unit.create((dgray ** 3).unit, name="dgray3", dispname=f"{str(dgray)}^3", scale=dgray.scale * 3) + Ggray2 = Unit.create((Ggray ** 2).unit, name="Ggray2", dispname=f"{str(Ggray)}^2", scale=Ggray.scale * 2) + Ggray3 = Unit.create((Ggray ** 3).unit, name="Ggray3", dispname=f"{str(Ggray)}^3", scale=Ggray.scale * 3) + fgray2 = Unit.create((fgray ** 2).unit, name="fgray2", dispname=f"{str(fgray)}^2", scale=fgray.scale * 2) + fgray3 = Unit.create((fgray ** 3).unit, name="fgray3", dispname=f"{str(fgray)}^3", scale=fgray.scale * 3) + hgray2 = Unit.create((hgray ** 2).unit, name="hgray2", dispname=f"{str(hgray)}^2", scale=hgray.scale * 2) + hgray3 = Unit.create((hgray ** 3).unit, name="hgray3", dispname=f"{str(hgray)}^3", scale=hgray.scale * 3) + dagray2 = Unit.create((dagray ** 2).unit, name="dagray2", dispname=f"{str(dagray)}^2", scale=dagray.scale * 2) + dagray3 = Unit.create((dagray ** 3).unit, name="dagray3", dispname=f"{str(dagray)}^3", scale=dagray.scale * 3) + mgray2 = Unit.create((mgray ** 2).unit, name="mgray2", dispname=f"{str(mgray)}^2", scale=mgray.scale * 2) + mgray3 = Unit.create((mgray ** 3).unit, name="mgray3", dispname=f"{str(mgray)}^3", scale=mgray.scale * 3) + ngray2 = Unit.create((ngray ** 2).unit, name="ngray2", dispname=f"{str(ngray)}^2", scale=ngray.scale * 2) + ngray3 = Unit.create((ngray ** 3).unit, name="ngray3", dispname=f"{str(ngray)}^3", scale=ngray.scale * 3) + pgray2 = Unit.create((pgray ** 2).unit, name="pgray2", dispname=f"{str(pgray)}^2", scale=pgray.scale * 2) + pgray3 = Unit.create((pgray ** 3).unit, name="pgray3", dispname=f"{str(pgray)}^3", scale=pgray.scale * 3) + ugray2 = Unit.create((ugray ** 2).unit, name="ugray2", dispname=f"{str(ugray)}^2", scale=ugray.scale * 2) + ugray3 = Unit.create((ugray ** 3).unit, name="ugray3", dispname=f"{str(ugray)}^3", scale=ugray.scale * 3) + Tgray2 = Unit.create((Tgray ** 2).unit, name="Tgray2", dispname=f"{str(Tgray)}^2", scale=Tgray.scale * 2) + Tgray3 = Unit.create((Tgray ** 3).unit, name="Tgray3", dispname=f"{str(Tgray)}^3", scale=Tgray.scale * 3) + ygray2 = Unit.create((ygray ** 2).unit, name="ygray2", dispname=f"{str(ygray)}^2", scale=ygray.scale * 2) + ygray3 = Unit.create((ygray ** 3).unit, name="ygray3", dispname=f"{str(ygray)}^3", scale=ygray.scale * 3) + Egray2 = Unit.create((Egray ** 2).unit, name="Egray2", dispname=f"{str(Egray)}^2", scale=Egray.scale * 2) + Egray3 = Unit.create((Egray ** 3).unit, name="Egray3", dispname=f"{str(Egray)}^3", scale=Egray.scale * 3) + zgray2 = Unit.create((zgray ** 2).unit, name="zgray2", dispname=f"{str(zgray)}^2", scale=zgray.scale * 2) + zgray3 = Unit.create((zgray ** 3).unit, name="zgray3", dispname=f"{str(zgray)}^3", scale=zgray.scale * 3) + Mgray2 = Unit.create((Mgray ** 2).unit, name="Mgray2", dispname=f"{str(Mgray)}^2", scale=Mgray.scale * 2) + Mgray3 = Unit.create((Mgray ** 3).unit, name="Mgray3", dispname=f"{str(Mgray)}^3", scale=Mgray.scale * 3) + kgray2 = Unit.create((kgray ** 2).unit, name="kgray2", dispname=f"{str(kgray)}^2", scale=kgray.scale * 2) + kgray3 = Unit.create((kgray ** 3).unit, name="kgray3", dispname=f"{str(kgray)}^3", scale=kgray.scale * 3) + Ygray2 = Unit.create((Ygray ** 2).unit, name="Ygray2", dispname=f"{str(Ygray)}^2", scale=Ygray.scale * 2) + Ygray3 = Unit.create((Ygray ** 3).unit, name="Ygray3", dispname=f"{str(Ygray)}^3", scale=Ygray.scale * 3) + asievert2 = Unit.create((asievert ** 2).unit, name="asievert2", dispname=f"{str(asievert)}^2", + scale=asievert.scale * 2) + asievert3 = Unit.create((asievert ** 3).unit, name="asievert3", dispname=f"{str(asievert)}^3", + scale=asievert.scale * 3) + csievert2 = Unit.create((csievert ** 2).unit, name="csievert2", dispname=f"{str(csievert)}^2", + scale=csievert.scale * 2) + csievert3 = Unit.create((csievert ** 3).unit, name="csievert3", dispname=f"{str(csievert)}^3", + scale=csievert.scale * 3) + Zsievert2 = Unit.create((Zsievert ** 2).unit, name="Zsievert2", dispname=f"{str(Zsievert)}^2", + scale=Zsievert.scale * 2) + Zsievert3 = Unit.create((Zsievert ** 3).unit, name="Zsievert3", dispname=f"{str(Zsievert)}^3", + scale=Zsievert.scale * 3) + Psievert2 = Unit.create((Psievert ** 2).unit, name="Psievert2", dispname=f"{str(Psievert)}^2", + scale=Psievert.scale * 2) + Psievert3 = Unit.create((Psievert ** 3).unit, name="Psievert3", dispname=f"{str(Psievert)}^3", + scale=Psievert.scale * 3) + dsievert2 = Unit.create((dsievert ** 2).unit, name="dsievert2", dispname=f"{str(dsievert)}^2", + scale=dsievert.scale * 2) + dsievert3 = Unit.create((dsievert ** 3).unit, name="dsievert3", dispname=f"{str(dsievert)}^3", + scale=dsievert.scale * 3) + Gsievert2 = Unit.create((Gsievert ** 2).unit, name="Gsievert2", dispname=f"{str(Gsievert)}^2", + scale=Gsievert.scale * 2) + Gsievert3 = Unit.create((Gsievert ** 3).unit, name="Gsievert3", dispname=f"{str(Gsievert)}^3", + scale=Gsievert.scale * 3) + fsievert2 = Unit.create((fsievert ** 2).unit, name="fsievert2", dispname=f"{str(fsievert)}^2", + scale=fsievert.scale * 2) + fsievert3 = Unit.create((fsievert ** 3).unit, name="fsievert3", dispname=f"{str(fsievert)}^3", + scale=fsievert.scale * 3) + hsievert2 = Unit.create((hsievert ** 2).unit, name="hsievert2", dispname=f"{str(hsievert)}^2", + scale=hsievert.scale * 2) + hsievert3 = Unit.create((hsievert ** 3).unit, name="hsievert3", dispname=f"{str(hsievert)}^3", + scale=hsievert.scale * 3) + dasievert2 = Unit.create((dasievert ** 2).unit, name="dasievert2", dispname=f"{str(dasievert)}^2", + scale=dasievert.scale * 2) + dasievert3 = Unit.create((dasievert ** 3).unit, name="dasievert3", dispname=f"{str(dasievert)}^3", + scale=dasievert.scale * 3) + msievert2 = Unit.create((msievert ** 2).unit, name="msievert2", dispname=f"{str(msievert)}^2", + scale=msievert.scale * 2) + msievert3 = Unit.create((msievert ** 3).unit, name="msievert3", dispname=f"{str(msievert)}^3", + scale=msievert.scale * 3) + nsievert2 = Unit.create((nsievert ** 2).unit, name="nsievert2", dispname=f"{str(nsievert)}^2", + scale=nsievert.scale * 2) + nsievert3 = Unit.create((nsievert ** 3).unit, name="nsievert3", dispname=f"{str(nsievert)}^3", + scale=nsievert.scale * 3) + psievert2 = Unit.create((psievert ** 2).unit, name="psievert2", dispname=f"{str(psievert)}^2", + scale=psievert.scale * 2) + psievert3 = Unit.create((psievert ** 3).unit, name="psievert3", dispname=f"{str(psievert)}^3", + scale=psievert.scale * 3) + usievert2 = Unit.create((usievert ** 2).unit, name="usievert2", dispname=f"{str(usievert)}^2", + scale=usievert.scale * 2) + usievert3 = Unit.create((usievert ** 3).unit, name="usievert3", dispname=f"{str(usievert)}^3", + scale=usievert.scale * 3) + Tsievert2 = Unit.create((Tsievert ** 2).unit, name="Tsievert2", dispname=f"{str(Tsievert)}^2", + scale=Tsievert.scale * 2) + Tsievert3 = Unit.create((Tsievert ** 3).unit, name="Tsievert3", dispname=f"{str(Tsievert)}^3", + scale=Tsievert.scale * 3) + ysievert2 = Unit.create((ysievert ** 2).unit, name="ysievert2", dispname=f"{str(ysievert)}^2", + scale=ysievert.scale * 2) + ysievert3 = Unit.create((ysievert ** 3).unit, name="ysievert3", dispname=f"{str(ysievert)}^3", + scale=ysievert.scale * 3) + Esievert2 = Unit.create((Esievert ** 2).unit, name="Esievert2", dispname=f"{str(Esievert)}^2", + scale=Esievert.scale * 2) + Esievert3 = Unit.create((Esievert ** 3).unit, name="Esievert3", dispname=f"{str(Esievert)}^3", + scale=Esievert.scale * 3) + zsievert2 = Unit.create((zsievert ** 2).unit, name="zsievert2", dispname=f"{str(zsievert)}^2", + scale=zsievert.scale * 2) + zsievert3 = Unit.create((zsievert ** 3).unit, name="zsievert3", dispname=f"{str(zsievert)}^3", + scale=zsievert.scale * 3) + Msievert2 = Unit.create((Msievert ** 2).unit, name="Msievert2", dispname=f"{str(Msievert)}^2", + scale=Msievert.scale * 2) + Msievert3 = Unit.create((Msievert ** 3).unit, name="Msievert3", dispname=f"{str(Msievert)}^3", + scale=Msievert.scale * 3) + ksievert2 = Unit.create((ksievert ** 2).unit, name="ksievert2", dispname=f"{str(ksievert)}^2", + scale=ksievert.scale * 2) + ksievert3 = Unit.create((ksievert ** 3).unit, name="ksievert3", dispname=f"{str(ksievert)}^3", + scale=ksievert.scale * 3) + Ysievert2 = Unit.create((Ysievert ** 2).unit, name="Ysievert2", dispname=f"{str(Ysievert)}^2", + scale=Ysievert.scale * 2) + Ysievert3 = Unit.create((Ysievert ** 3).unit, name="Ysievert3", dispname=f"{str(Ysievert)}^3", + scale=Ysievert.scale * 3) + akatal2 = Unit.create((akatal ** 2).unit, name="akatal2", dispname=f"{str(akatal)}^2", scale=akatal.scale * 2) + akatal3 = Unit.create((akatal ** 3).unit, name="akatal3", dispname=f"{str(akatal)}^3", scale=akatal.scale * 3) + ckatal2 = Unit.create((ckatal ** 2).unit, name="ckatal2", dispname=f"{str(ckatal)}^2", scale=ckatal.scale * 2) + ckatal3 = Unit.create((ckatal ** 3).unit, name="ckatal3", dispname=f"{str(ckatal)}^3", scale=ckatal.scale * 3) + Zkatal2 = Unit.create((Zkatal ** 2).unit, name="Zkatal2", dispname=f"{str(Zkatal)}^2", scale=Zkatal.scale * 2) + Zkatal3 = Unit.create((Zkatal ** 3).unit, name="Zkatal3", dispname=f"{str(Zkatal)}^3", scale=Zkatal.scale * 3) + Pkatal2 = Unit.create((Pkatal ** 2).unit, name="Pkatal2", dispname=f"{str(Pkatal)}^2", scale=Pkatal.scale * 2) + Pkatal3 = Unit.create((Pkatal ** 3).unit, name="Pkatal3", dispname=f"{str(Pkatal)}^3", scale=Pkatal.scale * 3) + dkatal2 = Unit.create((dkatal ** 2).unit, name="dkatal2", dispname=f"{str(dkatal)}^2", scale=dkatal.scale * 2) + dkatal3 = Unit.create((dkatal ** 3).unit, name="dkatal3", dispname=f"{str(dkatal)}^3", scale=dkatal.scale * 3) + Gkatal2 = Unit.create((Gkatal ** 2).unit, name="Gkatal2", dispname=f"{str(Gkatal)}^2", scale=Gkatal.scale * 2) + Gkatal3 = Unit.create((Gkatal ** 3).unit, name="Gkatal3", dispname=f"{str(Gkatal)}^3", scale=Gkatal.scale * 3) + fkatal2 = Unit.create((fkatal ** 2).unit, name="fkatal2", dispname=f"{str(fkatal)}^2", scale=fkatal.scale * 2) + fkatal3 = Unit.create((fkatal ** 3).unit, name="fkatal3", dispname=f"{str(fkatal)}^3", scale=fkatal.scale * 3) + hkatal2 = Unit.create((hkatal ** 2).unit, name="hkatal2", dispname=f"{str(hkatal)}^2", scale=hkatal.scale * 2) + hkatal3 = Unit.create((hkatal ** 3).unit, name="hkatal3", dispname=f"{str(hkatal)}^3", scale=hkatal.scale * 3) + dakatal2 = Unit.create((dakatal ** 2).unit, name="dakatal2", dispname=f"{str(dakatal)}^2", scale=dakatal.scale * 2) + dakatal3 = Unit.create((dakatal ** 3).unit, name="dakatal3", dispname=f"{str(dakatal)}^3", scale=dakatal.scale * 3) + mkatal2 = Unit.create((mkatal ** 2).unit, name="mkatal2", dispname=f"{str(mkatal)}^2", scale=mkatal.scale * 2) + mkatal3 = Unit.create((mkatal ** 3).unit, name="mkatal3", dispname=f"{str(mkatal)}^3", scale=mkatal.scale * 3) + nkatal2 = Unit.create((nkatal ** 2).unit, name="nkatal2", dispname=f"{str(nkatal)}^2", scale=nkatal.scale * 2) + nkatal3 = Unit.create((nkatal ** 3).unit, name="nkatal3", dispname=f"{str(nkatal)}^3", scale=nkatal.scale * 3) + pkatal2 = Unit.create((pkatal ** 2).unit, name="pkatal2", dispname=f"{str(pkatal)}^2", scale=pkatal.scale * 2) + pkatal3 = Unit.create((pkatal ** 3).unit, name="pkatal3", dispname=f"{str(pkatal)}^3", scale=pkatal.scale * 3) + ukatal2 = Unit.create((ukatal ** 2).unit, name="ukatal2", dispname=f"{str(ukatal)}^2", scale=ukatal.scale * 2) + ukatal3 = Unit.create((ukatal ** 3).unit, name="ukatal3", dispname=f"{str(ukatal)}^3", scale=ukatal.scale * 3) + Tkatal2 = Unit.create((Tkatal ** 2).unit, name="Tkatal2", dispname=f"{str(Tkatal)}^2", scale=Tkatal.scale * 2) + Tkatal3 = Unit.create((Tkatal ** 3).unit, name="Tkatal3", dispname=f"{str(Tkatal)}^3", scale=Tkatal.scale * 3) + ykatal2 = Unit.create((ykatal ** 2).unit, name="ykatal2", dispname=f"{str(ykatal)}^2", scale=ykatal.scale * 2) + ykatal3 = Unit.create((ykatal ** 3).unit, name="ykatal3", dispname=f"{str(ykatal)}^3", scale=ykatal.scale * 3) + Ekatal2 = Unit.create((Ekatal ** 2).unit, name="Ekatal2", dispname=f"{str(Ekatal)}^2", scale=Ekatal.scale * 2) + Ekatal3 = Unit.create((Ekatal ** 3).unit, name="Ekatal3", dispname=f"{str(Ekatal)}^3", scale=Ekatal.scale * 3) + zkatal2 = Unit.create((zkatal ** 2).unit, name="zkatal2", dispname=f"{str(zkatal)}^2", scale=zkatal.scale * 2) + zkatal3 = Unit.create((zkatal ** 3).unit, name="zkatal3", dispname=f"{str(zkatal)}^3", scale=zkatal.scale * 3) + Mkatal2 = Unit.create((Mkatal ** 2).unit, name="Mkatal2", dispname=f"{str(Mkatal)}^2", scale=Mkatal.scale * 2) + Mkatal3 = Unit.create((Mkatal ** 3).unit, name="Mkatal3", dispname=f"{str(Mkatal)}^3", scale=Mkatal.scale * 3) + kkatal2 = Unit.create((kkatal ** 2).unit, name="kkatal2", dispname=f"{str(kkatal)}^2", scale=kkatal.scale * 2) + kkatal3 = Unit.create((kkatal ** 3).unit, name="kkatal3", dispname=f"{str(kkatal)}^3", scale=kkatal.scale * 3) + Ykatal2 = Unit.create((Ykatal ** 2).unit, name="Ykatal2", dispname=f"{str(Ykatal)}^2", scale=Ykatal.scale * 2) + Ykatal3 = Unit.create((Ykatal ** 3).unit, name="Ykatal3", dispname=f"{str(Ykatal)}^3", scale=Ykatal.scale * 3) + aliter = Unit.create_scaled_unit(liter, "a") + liter = Unit.create_scaled_unit(liter, "") + cliter = Unit.create_scaled_unit(liter, "c") + Zliter = Unit.create_scaled_unit(liter, "Z") + Pliter = Unit.create_scaled_unit(liter, "P") + dliter = Unit.create_scaled_unit(liter, "d") + Gliter = Unit.create_scaled_unit(liter, "G") + fliter = Unit.create_scaled_unit(liter, "f") + hliter = Unit.create_scaled_unit(liter, "h") + daliter = Unit.create_scaled_unit(liter, "da") + mliter = Unit.create_scaled_unit(liter, "m") + nliter = Unit.create_scaled_unit(liter, "n") + pliter = Unit.create_scaled_unit(liter, "p") + uliter = Unit.create_scaled_unit(liter, "u") + Tliter = Unit.create_scaled_unit(liter, "T") + yliter = Unit.create_scaled_unit(liter, "y") + Eliter = Unit.create_scaled_unit(liter, "E") + zliter = Unit.create_scaled_unit(liter, "z") + Mliter = Unit.create_scaled_unit(liter, "M") + kliter = Unit.create_scaled_unit(liter, "k") + Yliter = Unit.create_scaled_unit(liter, "Y") + alitre = Unit.create_scaled_unit(litre, "a") + litre = Unit.create_scaled_unit(litre, "") + clitre = Unit.create_scaled_unit(litre, "c") + Zlitre = Unit.create_scaled_unit(litre, "Z") + Plitre = Unit.create_scaled_unit(litre, "P") + dlitre = Unit.create_scaled_unit(litre, "d") + Glitre = Unit.create_scaled_unit(litre, "G") + flitre = Unit.create_scaled_unit(litre, "f") + hlitre = Unit.create_scaled_unit(litre, "h") + dalitre = Unit.create_scaled_unit(litre, "da") + mlitre = Unit.create_scaled_unit(litre, "m") + nlitre = Unit.create_scaled_unit(litre, "n") + plitre = Unit.create_scaled_unit(litre, "p") + ulitre = Unit.create_scaled_unit(litre, "u") + Tlitre = Unit.create_scaled_unit(litre, "T") + ylitre = Unit.create_scaled_unit(litre, "y") + Elitre = Unit.create_scaled_unit(litre, "E") + zlitre = Unit.create_scaled_unit(litre, "z") + Mlitre = Unit.create_scaled_unit(litre, "M") + klitre = Unit.create_scaled_unit(litre, "k") + Ylitre = Unit.create_scaled_unit(litre, "Y") + + +class _Celsius: + """ + A dummy object to raise errors when ``celsius`` is used. The use of + `celsius` can lead to ambiguities when mixed with temperatures in `kelvin`, + so its use is no longer supported. See github issue #817 for details. + """ + error_text = ( + "The unit 'celsius' is no longer supported to avoid" + "ambiguities when mixed with absolute temperatures defined" + "in Kelvin. Directly use 'kelvin' when you are only" + "interested in temperature differences, and add the" + "'zero_celsius' constant from the brainpy._src.math.units.constants" + "module if you want to convert a temperature from Celsius to" + "Kelvin." + ) + + def __mul__(self, other): + raise TypeError(_Celsius.error_text) + + def __rmul__(self, other): + raise TypeError(_Celsius.error_text) + + def __div__(self, other): + raise TypeError(_Celsius.error_text) + + def __rdiv__(self, other): + raise TypeError(_Celsius.error_text) + + def __pow__(self, other): + raise TypeError(_Celsius.error_text) + + def __eq__(self, other): + raise TypeError(_Celsius.error_text) + + def __neq__(self, other): + raise TypeError(_Celsius.error_text) + + +celsius = _Celsius() + +base_units = [ + katal, + sievert, + gray, + becquerel, + lux, + lumen, + henry, + tesla, + weber, + siemens, + ohm, + farad, + volt, + coulomb, + watt, + joule, + pascal, + newton, + hertz, + steradian, + radian, + molar, + gramme, + gram, + kilogramme, + candle, + mol, + mole, + kelvin, + ampere, + amp, + second, + kilogram, + meter, + metre, +] + +scaled_units = [ + Ykatal, + kkatal, + Mkatal, + zkatal, + Ekatal, + ykatal, + Tkatal, + ukatal, + pkatal, + nkatal, + mkatal, + fkatal, + Gkatal, + Pkatal, + Zkatal, + akatal, + Ysievert, + ksievert, + Msievert, + zsievert, + Esievert, + ysievert, + Tsievert, + usievert, + psievert, + nsievert, + msievert, + fsievert, + Gsievert, + Psievert, + Zsievert, + asievert, + Ygray, + kgray, + Mgray, + zgray, + Egray, + ygray, + Tgray, + ugray, + pgray, + ngray, + mgray, + fgray, + Ggray, + Pgray, + Zgray, + agray, + Ybecquerel, + kbecquerel, + Mbecquerel, + zbecquerel, + Ebecquerel, + ybecquerel, + Tbecquerel, + ubecquerel, + pbecquerel, + nbecquerel, + mbecquerel, + fbecquerel, + Gbecquerel, + Pbecquerel, + Zbecquerel, + abecquerel, + Ylux, + klux, + Mlux, + zlux, + Elux, + ylux, + Tlux, + ulux, + plux, + nlux, + mlux, + flux, + Glux, + Plux, + Zlux, + alux, + Ylumen, + klumen, + Mlumen, + zlumen, + Elumen, + ylumen, + Tlumen, + ulumen, + plumen, + nlumen, + mlumen, + flumen, + Glumen, + Plumen, + Zlumen, + alumen, + Yhenry, + khenry, + Mhenry, + zhenry, + Ehenry, + yhenry, + Thenry, + uhenry, + phenry, + nhenry, + mhenry, + fhenry, + Ghenry, + Phenry, + Zhenry, + ahenry, + Ytesla, + ktesla, + Mtesla, + ztesla, + Etesla, + ytesla, + Ttesla, + utesla, + ptesla, + ntesla, + mtesla, + ftesla, + Gtesla, + Ptesla, + Ztesla, + atesla, + Yweber, + kweber, + Mweber, + zweber, + Eweber, + yweber, + Tweber, + uweber, + pweber, + nweber, + mweber, + fweber, + Gweber, + Pweber, + Zweber, + aweber, + Ysiemens, + ksiemens, + Msiemens, + zsiemens, + Esiemens, + ysiemens, + Tsiemens, + usiemens, + psiemens, + nsiemens, + msiemens, + fsiemens, + Gsiemens, + Psiemens, + Zsiemens, + asiemens, + Yohm, + kohm, + Mohm, + zohm, + Eohm, + yohm, + Tohm, + uohm, + pohm, + nohm, + mohm, + fohm, + Gohm, + Pohm, + Zohm, + aohm, + Yfarad, + kfarad, + Mfarad, + zfarad, + Efarad, + yfarad, + Tfarad, + ufarad, + pfarad, + nfarad, + mfarad, + ffarad, + Gfarad, + Pfarad, + Zfarad, + afarad, + Yvolt, + kvolt, + Mvolt, + zvolt, + Evolt, + yvolt, + Tvolt, + uvolt, + pvolt, + nvolt, + mvolt, + fvolt, + Gvolt, + Pvolt, + Zvolt, + avolt, + Ycoulomb, + kcoulomb, + Mcoulomb, + zcoulomb, + Ecoulomb, + ycoulomb, + Tcoulomb, + ucoulomb, + pcoulomb, + ncoulomb, + mcoulomb, + fcoulomb, + Gcoulomb, + Pcoulomb, + Zcoulomb, + acoulomb, + Ywatt, + kwatt, + Mwatt, + zwatt, + Ewatt, + ywatt, + Twatt, + uwatt, + pwatt, + nwatt, + mwatt, + fwatt, + Gwatt, + Pwatt, + Zwatt, + awatt, + Yjoule, + kjoule, + Mjoule, + zjoule, + Ejoule, + yjoule, + Tjoule, + ujoule, + pjoule, + njoule, + mjoule, + fjoule, + Gjoule, + Pjoule, + Zjoule, + ajoule, + Ypascal, + kpascal, + Mpascal, + zpascal, + Epascal, + ypascal, + Tpascal, + upascal, + ppascal, + npascal, + mpascal, + fpascal, + Gpascal, + Ppascal, + Zpascal, + apascal, + Ynewton, + knewton, + Mnewton, + znewton, + Enewton, + ynewton, + Tnewton, + unewton, + pnewton, + nnewton, + mnewton, + fnewton, + Gnewton, + Pnewton, + Znewton, + anewton, + Yhertz, + khertz, + Mhertz, + zhertz, + Ehertz, + yhertz, + Thertz, + uhertz, + phertz, + nhertz, + mhertz, + fhertz, + Ghertz, + Phertz, + Zhertz, + ahertz, + Ysteradian, + ksteradian, + Msteradian, + zsteradian, + Esteradian, + ysteradian, + Tsteradian, + usteradian, + psteradian, + nsteradian, + msteradian, + fsteradian, + Gsteradian, + Psteradian, + Zsteradian, + asteradian, + Yradian, + kradian, + Mradian, + zradian, + Eradian, + yradian, + Tradian, + uradian, + pradian, + nradian, + mradian, + fradian, + Gradian, + Pradian, + Zradian, + aradian, + Ymolar, + kmolar, + Mmolar, + zmolar, + Emolar, + ymolar, + Tmolar, + umolar, + pmolar, + nmolar, + mmolar, + fmolar, + Gmolar, + Pmolar, + Zmolar, + amolar, + Ygramme, + kgramme, + Mgramme, + zgramme, + Egramme, + ygramme, + Tgramme, + ugramme, + pgramme, + ngramme, + mgramme, + fgramme, + Ggramme, + Pgramme, + Zgramme, + agramme, + Ygram, + kgram, + Mgram, + zgram, + Egram, + ygram, + Tgram, + ugram, + pgram, + ngram, + mgram, + fgram, + Ggram, + Pgram, + Zgram, + agram, + Ycandle, + kcandle, + Mcandle, + zcandle, + Ecandle, + ycandle, + Tcandle, + ucandle, + pcandle, + ncandle, + mcandle, + fcandle, + Gcandle, + Pcandle, + Zcandle, + acandle, + Ymol, + kmol, + Mmol, + zmol, + Emol, + ymol, + Tmol, + umol, + pmol, + nmol, + mmol, + fmol, + Gmol, + Pmol, + Zmol, + amol, + Ymole, + kmole, + Mmole, + zmole, + Emole, + ymole, + Tmole, + umole, + pmole, + nmole, + mmole, + fmole, + Gmole, + Pmole, + Zmole, + amole, + Yampere, + kampere, + Mampere, + zampere, + Eampere, + yampere, + Tampere, + uampere, + pampere, + nampere, + mampere, + fampere, + Gampere, + Pampere, + Zampere, + aampere, + Yamp, + kamp, + Mamp, + zamp, + Eamp, + yamp, + Tamp, + uamp, + pamp, + namp, + mamp, + famp, + Gamp, + Pamp, + Zamp, + aamp, + Ysecond, + ksecond, + Msecond, + zsecond, + Esecond, + ysecond, + Tsecond, + usecond, + psecond, + nsecond, + msecond, + fsecond, + Gsecond, + Psecond, + Zsecond, + asecond, + Ymeter, + kmeter, + Mmeter, + zmeter, + Emeter, + ymeter, + Tmeter, + umeter, + pmeter, + nmeter, + mmeter, + fmeter, + Gmeter, + Pmeter, + Zmeter, + ameter, + Ymetre, + kmetre, + Mmetre, + zmetre, + Emetre, + ymetre, + Tmetre, + umetre, + pmetre, + nmetre, + mmetre, + fmetre, + Gmetre, + Pmetre, + Zmetre, + ametre, +] + +powered_units = [ + Ykatal3, + Ykatal2, + kkatal3, + kkatal2, + Mkatal3, + Mkatal2, + zkatal3, + zkatal2, + Ekatal3, + Ekatal2, + ykatal3, + ykatal2, + Tkatal3, + Tkatal2, + ukatal3, + ukatal2, + pkatal3, + pkatal2, + nkatal3, + nkatal2, + mkatal3, + mkatal2, + fkatal3, + fkatal2, + Gkatal3, + Gkatal2, + Pkatal3, + Pkatal2, + Zkatal3, + Zkatal2, + akatal3, + akatal2, + Ysievert3, + Ysievert2, + ksievert3, + ksievert2, + Msievert3, + Msievert2, + zsievert3, + zsievert2, + Esievert3, + Esievert2, + ysievert3, + ysievert2, + Tsievert3, + Tsievert2, + usievert3, + usievert2, + psievert3, + psievert2, + nsievert3, + nsievert2, + msievert3, + msievert2, + fsievert3, + fsievert2, + Gsievert3, + Gsievert2, + Psievert3, + Psievert2, + Zsievert3, + Zsievert2, + asievert3, + asievert2, + Ygray3, + Ygray2, + kgray3, + kgray2, + Mgray3, + Mgray2, + zgray3, + zgray2, + Egray3, + Egray2, + ygray3, + ygray2, + Tgray3, + Tgray2, + ugray3, + ugray2, + pgray3, + pgray2, + ngray3, + ngray2, + mgray3, + mgray2, + fgray3, + fgray2, + Ggray3, + Ggray2, + Pgray3, + Pgray2, + Zgray3, + Zgray2, + agray3, + agray2, + Ybecquerel3, + Ybecquerel2, + kbecquerel3, + kbecquerel2, + Mbecquerel3, + Mbecquerel2, + zbecquerel3, + zbecquerel2, + Ebecquerel3, + Ebecquerel2, + ybecquerel3, + ybecquerel2, + Tbecquerel3, + Tbecquerel2, + ubecquerel3, + ubecquerel2, + pbecquerel3, + pbecquerel2, + nbecquerel3, + nbecquerel2, + mbecquerel3, + mbecquerel2, + fbecquerel3, + fbecquerel2, + Gbecquerel3, + Gbecquerel2, + Pbecquerel3, + Pbecquerel2, + Zbecquerel3, + Zbecquerel2, + abecquerel3, + abecquerel2, + Ylux3, + Ylux2, + klux3, + klux2, + Mlux3, + Mlux2, + zlux3, + zlux2, + Elux3, + Elux2, + ylux3, + ylux2, + Tlux3, + Tlux2, + ulux3, + ulux2, + plux3, + plux2, + nlux3, + nlux2, + mlux3, + mlux2, + flux3, + flux2, + Glux3, + Glux2, + Plux3, + Plux2, + Zlux3, + Zlux2, + alux3, + alux2, + Ylumen3, + Ylumen2, + klumen3, + klumen2, + Mlumen3, + Mlumen2, + zlumen3, + zlumen2, + Elumen3, + Elumen2, + ylumen3, + ylumen2, + Tlumen3, + Tlumen2, + ulumen3, + ulumen2, + plumen3, + plumen2, + nlumen3, + nlumen2, + mlumen3, + mlumen2, + flumen3, + flumen2, + Glumen3, + Glumen2, + Plumen3, + Plumen2, + Zlumen3, + Zlumen2, + alumen3, + alumen2, + Yhenry3, + Yhenry2, + khenry3, + khenry2, + Mhenry3, + Mhenry2, + zhenry3, + zhenry2, + Ehenry3, + Ehenry2, + yhenry3, + yhenry2, + Thenry3, + Thenry2, + uhenry3, + uhenry2, + phenry3, + phenry2, + nhenry3, + nhenry2, + mhenry3, + mhenry2, + fhenry3, + fhenry2, + Ghenry3, + Ghenry2, + Phenry3, + Phenry2, + Zhenry3, + Zhenry2, + ahenry3, + ahenry2, + Ytesla3, + Ytesla2, + ktesla3, + ktesla2, + Mtesla3, + Mtesla2, + ztesla3, + ztesla2, + Etesla3, + Etesla2, + ytesla3, + ytesla2, + Ttesla3, + Ttesla2, + utesla3, + utesla2, + ptesla3, + ptesla2, + ntesla3, + ntesla2, + mtesla3, + mtesla2, + ftesla3, + ftesla2, + Gtesla3, + Gtesla2, + Ptesla3, + Ptesla2, + Ztesla3, + Ztesla2, + atesla3, + atesla2, + Yweber3, + Yweber2, + kweber3, + kweber2, + Mweber3, + Mweber2, + zweber3, + zweber2, + Eweber3, + Eweber2, + yweber3, + yweber2, + Tweber3, + Tweber2, + uweber3, + uweber2, + pweber3, + pweber2, + nweber3, + nweber2, + mweber3, + mweber2, + fweber3, + fweber2, + Gweber3, + Gweber2, + Pweber3, + Pweber2, + Zweber3, + Zweber2, + aweber3, + aweber2, + Ysiemens3, + Ysiemens2, + ksiemens3, + ksiemens2, + Msiemens3, + Msiemens2, + zsiemens3, + zsiemens2, + Esiemens3, + Esiemens2, + ysiemens3, + ysiemens2, + Tsiemens3, + Tsiemens2, + usiemens3, + usiemens2, + psiemens3, + psiemens2, + nsiemens3, + nsiemens2, + msiemens3, + msiemens2, + fsiemens3, + fsiemens2, + Gsiemens3, + Gsiemens2, + Psiemens3, + Psiemens2, + Zsiemens3, + Zsiemens2, + asiemens3, + asiemens2, + Yohm3, + Yohm2, + kohm3, + kohm2, + Mohm3, + Mohm2, + zohm3, + zohm2, + Eohm3, + Eohm2, + yohm3, + yohm2, + Tohm3, + Tohm2, + uohm3, + uohm2, + pohm3, + pohm2, + nohm3, + nohm2, + mohm3, + mohm2, + fohm3, + fohm2, + Gohm3, + Gohm2, + Pohm3, + Pohm2, + Zohm3, + Zohm2, + aohm3, + aohm2, + Yfarad3, + Yfarad2, + kfarad3, + kfarad2, + Mfarad3, + Mfarad2, + zfarad3, + zfarad2, + Efarad3, + Efarad2, + yfarad3, + yfarad2, + Tfarad3, + Tfarad2, + ufarad3, + ufarad2, + pfarad3, + pfarad2, + nfarad3, + nfarad2, + mfarad3, + mfarad2, + ffarad3, + ffarad2, + Gfarad3, + Gfarad2, + Pfarad3, + Pfarad2, + Zfarad3, + Zfarad2, + afarad3, + afarad2, + Yvolt3, + Yvolt2, + kvolt3, + kvolt2, + Mvolt3, + Mvolt2, + zvolt3, + zvolt2, + Evolt3, + Evolt2, + yvolt3, + yvolt2, + Tvolt3, + Tvolt2, + uvolt3, + uvolt2, + pvolt3, + pvolt2, + nvolt3, + nvolt2, + mvolt3, + mvolt2, + fvolt3, + fvolt2, + Gvolt3, + Gvolt2, + Pvolt3, + Pvolt2, + Zvolt3, + Zvolt2, + avolt3, + avolt2, + Ycoulomb3, + Ycoulomb2, + kcoulomb3, + kcoulomb2, + Mcoulomb3, + Mcoulomb2, + zcoulomb3, + zcoulomb2, + Ecoulomb3, + Ecoulomb2, + ycoulomb3, + ycoulomb2, + Tcoulomb3, + Tcoulomb2, + ucoulomb3, + ucoulomb2, + pcoulomb3, + pcoulomb2, + ncoulomb3, + ncoulomb2, + mcoulomb3, + mcoulomb2, + fcoulomb3, + fcoulomb2, + Gcoulomb3, + Gcoulomb2, + Pcoulomb3, + Pcoulomb2, + Zcoulomb3, + Zcoulomb2, + acoulomb3, + acoulomb2, + Ywatt3, + Ywatt2, + kwatt3, + kwatt2, + Mwatt3, + Mwatt2, + zwatt3, + zwatt2, + Ewatt3, + Ewatt2, + ywatt3, + ywatt2, + Twatt3, + Twatt2, + uwatt3, + uwatt2, + pwatt3, + pwatt2, + nwatt3, + nwatt2, + mwatt3, + mwatt2, + fwatt3, + fwatt2, + Gwatt3, + Gwatt2, + Pwatt3, + Pwatt2, + Zwatt3, + Zwatt2, + awatt3, + awatt2, + Yjoule3, + Yjoule2, + kjoule3, + kjoule2, + Mjoule3, + Mjoule2, + zjoule3, + zjoule2, + Ejoule3, + Ejoule2, + yjoule3, + yjoule2, + Tjoule3, + Tjoule2, + ujoule3, + ujoule2, + pjoule3, + pjoule2, + njoule3, + njoule2, + mjoule3, + mjoule2, + fjoule3, + fjoule2, + Gjoule3, + Gjoule2, + Pjoule3, + Pjoule2, + Zjoule3, + Zjoule2, + ajoule3, + ajoule2, + Ypascal3, + Ypascal2, + kpascal3, + kpascal2, + Mpascal3, + Mpascal2, + zpascal3, + zpascal2, + Epascal3, + Epascal2, + ypascal3, + ypascal2, + Tpascal3, + Tpascal2, + upascal3, + upascal2, + ppascal3, + ppascal2, + npascal3, + npascal2, + mpascal3, + mpascal2, + fpascal3, + fpascal2, + Gpascal3, + Gpascal2, + Ppascal3, + Ppascal2, + Zpascal3, + Zpascal2, + apascal3, + apascal2, + Ynewton3, + Ynewton2, + knewton3, + knewton2, + Mnewton3, + Mnewton2, + znewton3, + znewton2, + Enewton3, + Enewton2, + ynewton3, + ynewton2, + Tnewton3, + Tnewton2, + unewton3, + unewton2, + pnewton3, + pnewton2, + nnewton3, + nnewton2, + mnewton3, + mnewton2, + fnewton3, + fnewton2, + Gnewton3, + Gnewton2, + Pnewton3, + Pnewton2, + Znewton3, + Znewton2, + anewton3, + anewton2, + Yhertz3, + Yhertz2, + khertz3, + khertz2, + Mhertz3, + Mhertz2, + zhertz3, + zhertz2, + Ehertz3, + Ehertz2, + yhertz3, + yhertz2, + Thertz3, + Thertz2, + uhertz3, + uhertz2, + phertz3, + phertz2, + nhertz3, + nhertz2, + mhertz3, + mhertz2, + fhertz3, + fhertz2, + Ghertz3, + Ghertz2, + Phertz3, + Phertz2, + Zhertz3, + Zhertz2, + ahertz3, + ahertz2, + Ysteradian3, + Ysteradian2, + ksteradian3, + ksteradian2, + Msteradian3, + Msteradian2, + zsteradian3, + zsteradian2, + Esteradian3, + Esteradian2, + ysteradian3, + ysteradian2, + Tsteradian3, + Tsteradian2, + usteradian3, + usteradian2, + psteradian3, + psteradian2, + nsteradian3, + nsteradian2, + msteradian3, + msteradian2, + fsteradian3, + fsteradian2, + Gsteradian3, + Gsteradian2, + Psteradian3, + Psteradian2, + Zsteradian3, + Zsteradian2, + asteradian3, + asteradian2, + Yradian3, + Yradian2, + kradian3, + kradian2, + Mradian3, + Mradian2, + zradian3, + zradian2, + Eradian3, + Eradian2, + yradian3, + yradian2, + Tradian3, + Tradian2, + uradian3, + uradian2, + pradian3, + pradian2, + nradian3, + nradian2, + mradian3, + mradian2, + fradian3, + fradian2, + Gradian3, + Gradian2, + Pradian3, + Pradian2, + Zradian3, + Zradian2, + aradian3, + aradian2, + Ymolar3, + Ymolar2, + kmolar3, + kmolar2, + Mmolar3, + Mmolar2, + zmolar3, + zmolar2, + Emolar3, + Emolar2, + ymolar3, + ymolar2, + Tmolar3, + Tmolar2, + umolar3, + umolar2, + pmolar3, + pmolar2, + nmolar3, + nmolar2, + mmolar3, + mmolar2, + fmolar3, + fmolar2, + Gmolar3, + Gmolar2, + Pmolar3, + Pmolar2, + Zmolar3, + Zmolar2, + amolar3, + amolar2, + Ygramme3, + Ygramme2, + kgramme3, + kgramme2, + Mgramme3, + Mgramme2, + zgramme3, + zgramme2, + Egramme3, + Egramme2, + ygramme3, + ygramme2, + Tgramme3, + Tgramme2, + ugramme3, + ugramme2, + pgramme3, + pgramme2, + ngramme3, + ngramme2, + mgramme3, + mgramme2, + fgramme3, + fgramme2, + Ggramme3, + Ggramme2, + Pgramme3, + Pgramme2, + Zgramme3, + Zgramme2, + agramme3, + agramme2, + Ygram3, + Ygram2, + kgram3, + kgram2, + Mgram3, + Mgram2, + zgram3, + zgram2, + Egram3, + Egram2, + ygram3, + ygram2, + Tgram3, + Tgram2, + ugram3, + ugram2, + pgram3, + pgram2, + ngram3, + ngram2, + mgram3, + mgram2, + fgram3, + fgram2, + Ggram3, + Ggram2, + Pgram3, + Pgram2, + Zgram3, + Zgram2, + agram3, + agram2, + Ycandle3, + Ycandle2, + kcandle3, + kcandle2, + Mcandle3, + Mcandle2, + zcandle3, + zcandle2, + Ecandle3, + Ecandle2, + ycandle3, + ycandle2, + Tcandle3, + Tcandle2, + ucandle3, + ucandle2, + pcandle3, + pcandle2, + ncandle3, + ncandle2, + mcandle3, + mcandle2, + fcandle3, + fcandle2, + Gcandle3, + Gcandle2, + Pcandle3, + Pcandle2, + Zcandle3, + Zcandle2, + acandle3, + acandle2, + Ymol3, + Ymol2, + kmol3, + kmol2, + Mmol3, + Mmol2, + zmol3, + zmol2, + Emol3, + Emol2, + ymol3, + ymol2, + Tmol3, + Tmol2, + umol3, + umol2, + pmol3, + pmol2, + nmol3, + nmol2, + mmol3, + mmol2, + fmol3, + fmol2, + Gmol3, + Gmol2, + Pmol3, + Pmol2, + Zmol3, + Zmol2, + amol3, + amol2, + Ymole3, + Ymole2, + kmole3, + kmole2, + Mmole3, + Mmole2, + zmole3, + zmole2, + Emole3, + Emole2, + ymole3, + ymole2, + Tmole3, + Tmole2, + umole3, + umole2, + pmole3, + pmole2, + nmole3, + nmole2, + mmole3, + mmole2, + fmole3, + fmole2, + Gmole3, + Gmole2, + Pmole3, + Pmole2, + Zmole3, + Zmole2, + amole3, + amole2, + Yampere3, + Yampere2, + kampere3, + kampere2, + Mampere3, + Mampere2, + zampere3, + zampere2, + Eampere3, + Eampere2, + yampere3, + yampere2, + Tampere3, + Tampere2, + uampere3, + uampere2, + pampere3, + pampere2, + nampere3, + nampere2, + mampere3, + mampere2, + fampere3, + fampere2, + Gampere3, + Gampere2, + Pampere3, + Pampere2, + Zampere3, + Zampere2, + aampere3, + aampere2, + Yamp3, + Yamp2, + kamp3, + kamp2, + Mamp3, + Mamp2, + zamp3, + zamp2, + Eamp3, + Eamp2, + yamp3, + yamp2, + Tamp3, + Tamp2, + uamp3, + uamp2, + pamp3, + pamp2, + namp3, + namp2, + mamp3, + mamp2, + famp3, + famp2, + Gamp3, + Gamp2, + Pamp3, + Pamp2, + Zamp3, + Zamp2, + aamp3, + aamp2, + Ysecond3, + Ysecond2, + ksecond3, + ksecond2, + Msecond3, + Msecond2, + zsecond3, + zsecond2, + Esecond3, + Esecond2, + ysecond3, + ysecond2, + Tsecond3, + Tsecond2, + usecond3, + usecond2, + psecond3, + psecond2, + nsecond3, + nsecond2, + msecond3, + msecond2, + fsecond3, + fsecond2, + Gsecond3, + Gsecond2, + Psecond3, + Psecond2, + Zsecond3, + Zsecond2, + asecond3, + asecond2, + Ymeter3, + Ymeter2, + kmeter3, + kmeter2, + Mmeter3, + Mmeter2, + zmeter3, + zmeter2, + Emeter3, + Emeter2, + ymeter3, + ymeter2, + Tmeter3, + Tmeter2, + umeter3, + umeter2, + pmeter3, + pmeter2, + nmeter3, + nmeter2, + mmeter3, + mmeter2, + fmeter3, + fmeter2, + Gmeter3, + Gmeter2, + Pmeter3, + Pmeter2, + Zmeter3, + Zmeter2, + ameter3, + ameter2, + Ymetre3, + Ymetre2, + kmetre3, + kmetre2, + Mmetre3, + Mmetre2, + zmetre3, + zmetre2, + Emetre3, + Emetre2, + ymetre3, + ymetre2, + Tmetre3, + Tmetre2, + umetre3, + umetre2, + pmetre3, + pmetre2, + nmetre3, + nmetre2, + mmetre3, + mmetre2, + fmetre3, + fmetre2, + Gmetre3, + Gmetre2, + Pmetre3, + Pmetre2, + Zmetre3, + Zmetre2, + ametre3, + ametre2, + katal3, + katal2, + sievert3, + sievert2, + gray3, + gray2, + becquerel3, + becquerel2, + lux3, + lux2, + lumen3, + lumen2, + henry3, + henry2, + tesla3, + tesla2, + weber3, + weber2, + siemens3, + siemens2, + ohm3, + ohm2, + farad3, + farad2, + volt3, + volt2, + coulomb3, + coulomb2, + watt3, + watt2, + joule3, + joule2, + pascal3, + pascal2, + newton3, + newton2, + hertz3, + hertz2, + steradian3, + steradian2, + radian3, + radian2, + molar3, + molar2, + gramme3, + gramme2, + gram3, + gram2, + kilogramme3, + kilogramme2, + candle3, + candle2, + mol3, + mol2, + mole3, + mole2, + kelvin3, + kelvin2, + ampere3, + ampere2, + amp3, + amp2, + second3, + second2, + kilogram3, + kilogram2, + meter3, + meter2, + metre3, + metre2, +] + +# Current list from http://physics.nist.gov/cuu/Units/units.html, far from complete +additional_units = [ + pascal * second, newton * metre, watt / metre ** 2, joule / kelvin, + joule / (kilogram * kelvin), joule / kilogram, watt / (metre * kelvin), + joule / metre ** 3, volt / metre ** 3, coulomb / metre ** 3, coulomb / metre ** 2, + farad / metre, henry / metre, joule / mole, joule / (mole * kelvin), + coulomb / kilogram, gray / second, katal / metre ** 3, + # We don't want liter/litre to be used as a standard unit for display, so we + # put it here instead of in the standard units + aliter, liter, cliter, Zliter, Pliter, dliter, Gliter, fliter, hliter, daliter, mliter, nliter, pliter, uliter, + Tliter, yliter, Eliter, zliter, Mliter, kliter, Yliter, alitre, litre, clitre, Zlitre, Plitre, dlitre, Glitre, flitre, + hlitre, dalitre, mlitre, nlitre, plitre, ulitre, Tlitre, ylitre, Elitre, zlitre, Mlitre, klitre, Ylitre, ] + +all_units = [ + Ylitre, + klitre, + Mlitre, + zlitre, + Elitre, + ylitre, + Tlitre, + ulitre, + plitre, + nlitre, + mlitre, + dalitre, + hlitre, + flitre, + Glitre, + dlitre, + Plitre, + Zlitre, + clitre, + litre, + alitre, + litre, + Yliter, + kliter, + Mliter, + zliter, + Eliter, + yliter, + Tliter, + uliter, + pliter, + nliter, + mliter, + daliter, + hliter, + fliter, + Gliter, + dliter, + Pliter, + Zliter, + cliter, + liter, + aliter, + liter, + Ykatal3, + Ykatal2, + kkatal3, + kkatal2, + Mkatal3, + Mkatal2, + zkatal3, + zkatal2, + Ekatal3, + Ekatal2, + ykatal3, + ykatal2, + Tkatal3, + Tkatal2, + ukatal3, + ukatal2, + pkatal3, + pkatal2, + nkatal3, + nkatal2, + mkatal3, + mkatal2, + dakatal3, + dakatal2, + hkatal3, + hkatal2, + fkatal3, + fkatal2, + Gkatal3, + Gkatal2, + dkatal3, + dkatal2, + Pkatal3, + Pkatal2, + Zkatal3, + Zkatal2, + ckatal3, + ckatal2, + akatal3, + akatal2, + Ysievert3, + Ysievert2, + ksievert3, + ksievert2, + Msievert3, + Msievert2, + zsievert3, + zsievert2, + Esievert3, + Esievert2, + ysievert3, + ysievert2, + Tsievert3, + Tsievert2, + usievert3, + usievert2, + psievert3, + psievert2, + nsievert3, + nsievert2, + msievert3, + msievert2, + dasievert3, + dasievert2, + hsievert3, + hsievert2, + fsievert3, + fsievert2, + Gsievert3, + Gsievert2, + dsievert3, + dsievert2, + Psievert3, + Psievert2, + Zsievert3, + Zsievert2, + csievert3, + csievert2, + asievert3, + asievert2, + Ygray3, + Ygray2, + kgray3, + kgray2, + Mgray3, + Mgray2, + zgray3, + zgray2, + Egray3, + Egray2, + ygray3, + ygray2, + Tgray3, + Tgray2, + ugray3, + ugray2, + pgray3, + pgray2, + ngray3, + ngray2, + mgray3, + mgray2, + dagray3, + dagray2, + hgray3, + hgray2, + fgray3, + fgray2, + Ggray3, + Ggray2, + dgray3, + dgray2, + Pgray3, + Pgray2, + Zgray3, + Zgray2, + cgray3, + cgray2, + agray3, + agray2, + Ybecquerel3, + Ybecquerel2, + kbecquerel3, + kbecquerel2, + Mbecquerel3, + Mbecquerel2, + zbecquerel3, + zbecquerel2, + Ebecquerel3, + Ebecquerel2, + ybecquerel3, + ybecquerel2, + Tbecquerel3, + Tbecquerel2, + ubecquerel3, + ubecquerel2, + pbecquerel3, + pbecquerel2, + nbecquerel3, + nbecquerel2, + mbecquerel3, + mbecquerel2, + dabecquerel3, + dabecquerel2, + hbecquerel3, + hbecquerel2, + fbecquerel3, + fbecquerel2, + Gbecquerel3, + Gbecquerel2, + dbecquerel3, + dbecquerel2, + Pbecquerel3, + Pbecquerel2, + Zbecquerel3, + Zbecquerel2, + cbecquerel3, + cbecquerel2, + abecquerel3, + abecquerel2, + Ylux3, + Ylux2, + klux3, + klux2, + Mlux3, + Mlux2, + zlux3, + zlux2, + Elux3, + Elux2, + ylux3, + ylux2, + Tlux3, + Tlux2, + ulux3, + ulux2, + plux3, + plux2, + nlux3, + nlux2, + mlux3, + mlux2, + dalux3, + dalux2, + hlux3, + hlux2, + flux3, + flux2, + Glux3, + Glux2, + dlux3, + dlux2, + Plux3, + Plux2, + Zlux3, + Zlux2, + clux3, + clux2, + alux3, + alux2, + Ylumen3, + Ylumen2, + klumen3, + klumen2, + Mlumen3, + Mlumen2, + zlumen3, + zlumen2, + Elumen3, + Elumen2, + ylumen3, + ylumen2, + Tlumen3, + Tlumen2, + ulumen3, + ulumen2, + plumen3, + plumen2, + nlumen3, + nlumen2, + mlumen3, + mlumen2, + dalumen3, + dalumen2, + hlumen3, + hlumen2, + flumen3, + flumen2, + Glumen3, + Glumen2, + dlumen3, + dlumen2, + Plumen3, + Plumen2, + Zlumen3, + Zlumen2, + clumen3, + clumen2, + alumen3, + alumen2, + Yhenry3, + Yhenry2, + khenry3, + khenry2, + Mhenry3, + Mhenry2, + zhenry3, + zhenry2, + Ehenry3, + Ehenry2, + yhenry3, + yhenry2, + Thenry3, + Thenry2, + uhenry3, + uhenry2, + phenry3, + phenry2, + nhenry3, + nhenry2, + mhenry3, + mhenry2, + dahenry3, + dahenry2, + hhenry3, + hhenry2, + fhenry3, + fhenry2, + Ghenry3, + Ghenry2, + dhenry3, + dhenry2, + Phenry3, + Phenry2, + Zhenry3, + Zhenry2, + chenry3, + chenry2, + ahenry3, + ahenry2, + Ytesla3, + Ytesla2, + ktesla3, + ktesla2, + Mtesla3, + Mtesla2, + ztesla3, + ztesla2, + Etesla3, + Etesla2, + ytesla3, + ytesla2, + Ttesla3, + Ttesla2, + utesla3, + utesla2, + ptesla3, + ptesla2, + ntesla3, + ntesla2, + mtesla3, + mtesla2, + datesla3, + datesla2, + htesla3, + htesla2, + ftesla3, + ftesla2, + Gtesla3, + Gtesla2, + dtesla3, + dtesla2, + Ptesla3, + Ptesla2, + Ztesla3, + Ztesla2, + ctesla3, + ctesla2, + atesla3, + atesla2, + Yweber3, + Yweber2, + kweber3, + kweber2, + Mweber3, + Mweber2, + zweber3, + zweber2, + Eweber3, + Eweber2, + yweber3, + yweber2, + Tweber3, + Tweber2, + uweber3, + uweber2, + pweber3, + pweber2, + nweber3, + nweber2, + mweber3, + mweber2, + daweber3, + daweber2, + hweber3, + hweber2, + fweber3, + fweber2, + Gweber3, + Gweber2, + dweber3, + dweber2, + Pweber3, + Pweber2, + Zweber3, + Zweber2, + cweber3, + cweber2, + aweber3, + aweber2, + Ysiemens3, + Ysiemens2, + ksiemens3, + ksiemens2, + Msiemens3, + Msiemens2, + zsiemens3, + zsiemens2, + Esiemens3, + Esiemens2, + ysiemens3, + ysiemens2, + Tsiemens3, + Tsiemens2, + usiemens3, + usiemens2, + psiemens3, + psiemens2, + nsiemens3, + nsiemens2, + msiemens3, + msiemens2, + dasiemens3, + dasiemens2, + hsiemens3, + hsiemens2, + fsiemens3, + fsiemens2, + Gsiemens3, + Gsiemens2, + dsiemens3, + dsiemens2, + Psiemens3, + Psiemens2, + Zsiemens3, + Zsiemens2, + csiemens3, + csiemens2, + asiemens3, + asiemens2, + Yohm3, + Yohm2, + kohm3, + kohm2, + Mohm3, + Mohm2, + zohm3, + zohm2, + Eohm3, + Eohm2, + yohm3, + yohm2, + Tohm3, + Tohm2, + uohm3, + uohm2, + pohm3, + pohm2, + nohm3, + nohm2, + mohm3, + mohm2, + daohm3, + daohm2, + hohm3, + hohm2, + fohm3, + fohm2, + Gohm3, + Gohm2, + dohm3, + dohm2, + Pohm3, + Pohm2, + Zohm3, + Zohm2, + cohm3, + cohm2, + aohm3, + aohm2, + Yfarad3, + Yfarad2, + kfarad3, + kfarad2, + Mfarad3, + Mfarad2, + zfarad3, + zfarad2, + Efarad3, + Efarad2, + yfarad3, + yfarad2, + Tfarad3, + Tfarad2, + ufarad3, + ufarad2, + pfarad3, + pfarad2, + nfarad3, + nfarad2, + mfarad3, + mfarad2, + dafarad3, + dafarad2, + hfarad3, + hfarad2, + ffarad3, + ffarad2, + Gfarad3, + Gfarad2, + dfarad3, + dfarad2, + Pfarad3, + Pfarad2, + Zfarad3, + Zfarad2, + cfarad3, + cfarad2, + afarad3, + afarad2, + Yvolt3, + Yvolt2, + kvolt3, + kvolt2, + Mvolt3, + Mvolt2, + zvolt3, + zvolt2, + Evolt3, + Evolt2, + yvolt3, + yvolt2, + Tvolt3, + Tvolt2, + uvolt3, + uvolt2, + pvolt3, + pvolt2, + nvolt3, + nvolt2, + mvolt3, + mvolt2, + davolt3, + davolt2, + hvolt3, + hvolt2, + fvolt3, + fvolt2, + Gvolt3, + Gvolt2, + dvolt3, + dvolt2, + Pvolt3, + Pvolt2, + Zvolt3, + Zvolt2, + cvolt3, + cvolt2, + avolt3, + avolt2, + Ycoulomb3, + Ycoulomb2, + kcoulomb3, + kcoulomb2, + Mcoulomb3, + Mcoulomb2, + zcoulomb3, + zcoulomb2, + Ecoulomb3, + Ecoulomb2, + ycoulomb3, + ycoulomb2, + Tcoulomb3, + Tcoulomb2, + ucoulomb3, + ucoulomb2, + pcoulomb3, + pcoulomb2, + ncoulomb3, + ncoulomb2, + mcoulomb3, + mcoulomb2, + dacoulomb3, + dacoulomb2, + hcoulomb3, + hcoulomb2, + fcoulomb3, + fcoulomb2, + Gcoulomb3, + Gcoulomb2, + dcoulomb3, + dcoulomb2, + Pcoulomb3, + Pcoulomb2, + Zcoulomb3, + Zcoulomb2, + ccoulomb3, + ccoulomb2, + acoulomb3, + acoulomb2, + Ywatt3, + Ywatt2, + kwatt3, + kwatt2, + Mwatt3, + Mwatt2, + zwatt3, + zwatt2, + Ewatt3, + Ewatt2, + ywatt3, + ywatt2, + Twatt3, + Twatt2, + uwatt3, + uwatt2, + pwatt3, + pwatt2, + nwatt3, + nwatt2, + mwatt3, + mwatt2, + dawatt3, + dawatt2, + hwatt3, + hwatt2, + fwatt3, + fwatt2, + Gwatt3, + Gwatt2, + dwatt3, + dwatt2, + Pwatt3, + Pwatt2, + Zwatt3, + Zwatt2, + cwatt3, + cwatt2, + awatt3, + awatt2, + Yjoule3, + Yjoule2, + kjoule3, + kjoule2, + Mjoule3, + Mjoule2, + zjoule3, + zjoule2, + Ejoule3, + Ejoule2, + yjoule3, + yjoule2, + Tjoule3, + Tjoule2, + ujoule3, + ujoule2, + pjoule3, + pjoule2, + njoule3, + njoule2, + mjoule3, + mjoule2, + dajoule3, + dajoule2, + hjoule3, + hjoule2, + fjoule3, + fjoule2, + Gjoule3, + Gjoule2, + djoule3, + djoule2, + Pjoule3, + Pjoule2, + Zjoule3, + Zjoule2, + cjoule3, + cjoule2, + ajoule3, + ajoule2, + Ypascal3, + Ypascal2, + kpascal3, + kpascal2, + Mpascal3, + Mpascal2, + zpascal3, + zpascal2, + Epascal3, + Epascal2, + ypascal3, + ypascal2, + Tpascal3, + Tpascal2, + upascal3, + upascal2, + ppascal3, + ppascal2, + npascal3, + npascal2, + mpascal3, + mpascal2, + dapascal3, + dapascal2, + hpascal3, + hpascal2, + fpascal3, + fpascal2, + Gpascal3, + Gpascal2, + dpascal3, + dpascal2, + Ppascal3, + Ppascal2, + Zpascal3, + Zpascal2, + cpascal3, + cpascal2, + apascal3, + apascal2, + Ynewton3, + Ynewton2, + knewton3, + knewton2, + Mnewton3, + Mnewton2, + znewton3, + znewton2, + Enewton3, + Enewton2, + ynewton3, + ynewton2, + Tnewton3, + Tnewton2, + unewton3, + unewton2, + pnewton3, + pnewton2, + nnewton3, + nnewton2, + mnewton3, + mnewton2, + danewton3, + danewton2, + hnewton3, + hnewton2, + fnewton3, + fnewton2, + Gnewton3, + Gnewton2, + dnewton3, + dnewton2, + Pnewton3, + Pnewton2, + Znewton3, + Znewton2, + cnewton3, + cnewton2, + anewton3, + anewton2, + Yhertz3, + Yhertz2, + khertz3, + khertz2, + Mhertz3, + Mhertz2, + zhertz3, + zhertz2, + Ehertz3, + Ehertz2, + yhertz3, + yhertz2, + Thertz3, + Thertz2, + uhertz3, + uhertz2, + phertz3, + phertz2, + nhertz3, + nhertz2, + mhertz3, + mhertz2, + dahertz3, + dahertz2, + hhertz3, + hhertz2, + fhertz3, + fhertz2, + Ghertz3, + Ghertz2, + dhertz3, + dhertz2, + Phertz3, + Phertz2, + Zhertz3, + Zhertz2, + chertz3, + chertz2, + ahertz3, + ahertz2, + Ysteradian3, + Ysteradian2, + ksteradian3, + ksteradian2, + Msteradian3, + Msteradian2, + zsteradian3, + zsteradian2, + Esteradian3, + Esteradian2, + ysteradian3, + ysteradian2, + Tsteradian3, + Tsteradian2, + usteradian3, + usteradian2, + psteradian3, + psteradian2, + nsteradian3, + nsteradian2, + msteradian3, + msteradian2, + dasteradian3, + dasteradian2, + hsteradian3, + hsteradian2, + fsteradian3, + fsteradian2, + Gsteradian3, + Gsteradian2, + dsteradian3, + dsteradian2, + Psteradian3, + Psteradian2, + Zsteradian3, + Zsteradian2, + csteradian3, + csteradian2, + asteradian3, + asteradian2, + Yradian3, + Yradian2, + kradian3, + kradian2, + Mradian3, + Mradian2, + zradian3, + zradian2, + Eradian3, + Eradian2, + yradian3, + yradian2, + Tradian3, + Tradian2, + uradian3, + uradian2, + pradian3, + pradian2, + nradian3, + nradian2, + mradian3, + mradian2, + daradian3, + daradian2, + hradian3, + hradian2, + fradian3, + fradian2, + Gradian3, + Gradian2, + dradian3, + dradian2, + Pradian3, + Pradian2, + Zradian3, + Zradian2, + cradian3, + cradian2, + aradian3, + aradian2, + Ymolar3, + Ymolar2, + kmolar3, + kmolar2, + Mmolar3, + Mmolar2, + zmolar3, + zmolar2, + Emolar3, + Emolar2, + ymolar3, + ymolar2, + Tmolar3, + Tmolar2, + umolar3, + umolar2, + pmolar3, + pmolar2, + nmolar3, + nmolar2, + mmolar3, + mmolar2, + damolar3, + damolar2, + hmolar3, + hmolar2, + fmolar3, + fmolar2, + Gmolar3, + Gmolar2, + dmolar3, + dmolar2, + Pmolar3, + Pmolar2, + Zmolar3, + Zmolar2, + cmolar3, + cmolar2, + amolar3, + amolar2, + Ygramme3, + Ygramme2, + kgramme3, + kgramme2, + Mgramme3, + Mgramme2, + zgramme3, + zgramme2, + Egramme3, + Egramme2, + ygramme3, + ygramme2, + Tgramme3, + Tgramme2, + ugramme3, + ugramme2, + pgramme3, + pgramme2, + ngramme3, + ngramme2, + mgramme3, + mgramme2, + dagramme3, + dagramme2, + hgramme3, + hgramme2, + fgramme3, + fgramme2, + Ggramme3, + Ggramme2, + dgramme3, + dgramme2, + Pgramme3, + Pgramme2, + Zgramme3, + Zgramme2, + cgramme3, + cgramme2, + agramme3, + agramme2, + Ygram3, + Ygram2, + kgram3, + kgram2, + Mgram3, + Mgram2, + zgram3, + zgram2, + Egram3, + Egram2, + ygram3, + ygram2, + Tgram3, + Tgram2, + ugram3, + ugram2, + pgram3, + pgram2, + ngram3, + ngram2, + mgram3, + mgram2, + dagram3, + dagram2, + hgram3, + hgram2, + fgram3, + fgram2, + Ggram3, + Ggram2, + dgram3, + dgram2, + Pgram3, + Pgram2, + Zgram3, + Zgram2, + cgram3, + cgram2, + agram3, + agram2, + Ycandle3, + Ycandle2, + kcandle3, + kcandle2, + Mcandle3, + Mcandle2, + zcandle3, + zcandle2, + Ecandle3, + Ecandle2, + ycandle3, + ycandle2, + Tcandle3, + Tcandle2, + ucandle3, + ucandle2, + pcandle3, + pcandle2, + ncandle3, + ncandle2, + mcandle3, + mcandle2, + dacandle3, + dacandle2, + hcandle3, + hcandle2, + fcandle3, + fcandle2, + Gcandle3, + Gcandle2, + dcandle3, + dcandle2, + Pcandle3, + Pcandle2, + Zcandle3, + Zcandle2, + ccandle3, + ccandle2, + acandle3, + acandle2, + Ymol3, + Ymol2, + kmol3, + kmol2, + Mmol3, + Mmol2, + zmol3, + zmol2, + Emol3, + Emol2, + ymol3, + ymol2, + Tmol3, + Tmol2, + umol3, + umol2, + pmol3, + pmol2, + nmol3, + nmol2, + mmol3, + mmol2, + damol3, + damol2, + hmol3, + hmol2, + fmol3, + fmol2, + Gmol3, + Gmol2, + dmol3, + dmol2, + Pmol3, + Pmol2, + Zmol3, + Zmol2, + cmol3, + cmol2, + amol3, + amol2, + Ymole3, + Ymole2, + kmole3, + kmole2, + Mmole3, + Mmole2, + zmole3, + zmole2, + Emole3, + Emole2, + ymole3, + ymole2, + Tmole3, + Tmole2, + umole3, + umole2, + pmole3, + pmole2, + nmole3, + nmole2, + mmole3, + mmole2, + damole3, + damole2, + hmole3, + hmole2, + fmole3, + fmole2, + Gmole3, + Gmole2, + dmole3, + dmole2, + Pmole3, + Pmole2, + Zmole3, + Zmole2, + cmole3, + cmole2, + amole3, + amole2, + Yampere3, + Yampere2, + kampere3, + kampere2, + Mampere3, + Mampere2, + zampere3, + zampere2, + Eampere3, + Eampere2, + yampere3, + yampere2, + Tampere3, + Tampere2, + uampere3, + uampere2, + pampere3, + pampere2, + nampere3, + nampere2, + mampere3, + mampere2, + daampere3, + daampere2, + hampere3, + hampere2, + fampere3, + fampere2, + Gampere3, + Gampere2, + dampere3, + dampere2, + Pampere3, + Pampere2, + Zampere3, + Zampere2, + campere3, + campere2, + aampere3, + aampere2, + Yamp3, + Yamp2, + kamp3, + kamp2, + Mamp3, + Mamp2, + zamp3, + zamp2, + Eamp3, + Eamp2, + yamp3, + yamp2, + Tamp3, + Tamp2, + uamp3, + uamp2, + pamp3, + pamp2, + namp3, + namp2, + mamp3, + mamp2, + daamp3, + daamp2, + hamp3, + hamp2, + famp3, + famp2, + Gamp3, + Gamp2, + damp3, + damp2, + Pamp3, + Pamp2, + Zamp3, + Zamp2, + camp3, + camp2, + aamp3, + aamp2, + Ysecond3, + Ysecond2, + ksecond3, + ksecond2, + Msecond3, + Msecond2, + zsecond3, + zsecond2, + Esecond3, + Esecond2, + ysecond3, + ysecond2, + Tsecond3, + Tsecond2, + usecond3, + usecond2, + psecond3, + psecond2, + nsecond3, + nsecond2, + msecond3, + msecond2, + dasecond3, + dasecond2, + hsecond3, + hsecond2, + fsecond3, + fsecond2, + Gsecond3, + Gsecond2, + dsecond3, + dsecond2, + Psecond3, + Psecond2, + Zsecond3, + Zsecond2, + csecond3, + csecond2, + asecond3, + asecond2, + Ymeter3, + Ymeter2, + kmeter3, + kmeter2, + Mmeter3, + Mmeter2, + zmeter3, + zmeter2, + Emeter3, + Emeter2, + ymeter3, + ymeter2, + Tmeter3, + Tmeter2, + umeter3, + umeter2, + pmeter3, + pmeter2, + nmeter3, + nmeter2, + mmeter3, + mmeter2, + dameter3, + dameter2, + hmeter3, + hmeter2, + fmeter3, + fmeter2, + Gmeter3, + Gmeter2, + dmeter3, + dmeter2, + Pmeter3, + Pmeter2, + Zmeter3, + Zmeter2, + cmeter3, + cmeter2, + ameter3, + ameter2, + Ymetre3, + Ymetre2, + kmetre3, + kmetre2, + Mmetre3, + Mmetre2, + zmetre3, + zmetre2, + Emetre3, + Emetre2, + ymetre3, + ymetre2, + Tmetre3, + Tmetre2, + umetre3, + umetre2, + pmetre3, + pmetre2, + nmetre3, + nmetre2, + mmetre3, + mmetre2, + dametre3, + dametre2, + hmetre3, + hmetre2, + fmetre3, + fmetre2, + Gmetre3, + Gmetre2, + dmetre3, + dmetre2, + Pmetre3, + Pmetre2, + Zmetre3, + Zmetre2, + cmetre3, + cmetre2, + ametre3, + ametre2, + katal3, + katal2, + sievert3, + sievert2, + gray3, + gray2, + becquerel3, + becquerel2, + lux3, + lux2, + lumen3, + lumen2, + henry3, + henry2, + tesla3, + tesla2, + weber3, + weber2, + siemens3, + siemens2, + ohm3, + ohm2, + farad3, + farad2, + volt3, + volt2, + coulomb3, + coulomb2, + watt3, + watt2, + joule3, + joule2, + pascal3, + pascal2, + newton3, + newton2, + hertz3, + hertz2, + steradian3, + steradian2, + radian3, + radian2, + molar3, + molar2, + gramme3, + gramme2, + gram3, + gram2, + kilogramme3, + kilogramme2, + candle3, + candle2, + mol3, + mol2, + mole3, + mole2, + kelvin3, + kelvin2, + ampere3, + ampere2, + amp3, + amp2, + second3, + second2, + kilogram3, + kilogram2, + meter3, + meter2, + metre3, + metre2, + Ykatal, + kkatal, + Mkatal, + zkatal, + Ekatal, + ykatal, + Tkatal, + ukatal, + pkatal, + nkatal, + mkatal, + dakatal, + hkatal, + fkatal, + Gkatal, + dkatal, + Pkatal, + Zkatal, + ckatal, + akatal, + Ysievert, + ksievert, + Msievert, + zsievert, + Esievert, + ysievert, + Tsievert, + usievert, + psievert, + nsievert, + msievert, + dasievert, + hsievert, + fsievert, + Gsievert, + dsievert, + Psievert, + Zsievert, + csievert, + asievert, + Ygray, + kgray, + Mgray, + zgray, + Egray, + ygray, + Tgray, + ugray, + pgray, + ngray, + mgray, + dagray, + hgray, + fgray, + Ggray, + dgray, + Pgray, + Zgray, + cgray, + agray, + Ybecquerel, + kbecquerel, + Mbecquerel, + zbecquerel, + Ebecquerel, + ybecquerel, + Tbecquerel, + ubecquerel, + pbecquerel, + nbecquerel, + mbecquerel, + dabecquerel, + hbecquerel, + fbecquerel, + Gbecquerel, + dbecquerel, + Pbecquerel, + Zbecquerel, + cbecquerel, + abecquerel, + Ylux, + klux, + Mlux, + zlux, + Elux, + ylux, + Tlux, + ulux, + plux, + nlux, + mlux, + dalux, + hlux, + flux, + Glux, + dlux, + Plux, + Zlux, + clux, + alux, + Ylumen, + klumen, + Mlumen, + zlumen, + Elumen, + ylumen, + Tlumen, + ulumen, + plumen, + nlumen, + mlumen, + dalumen, + hlumen, + flumen, + Glumen, + dlumen, + Plumen, + Zlumen, + clumen, + alumen, + Yhenry, + khenry, + Mhenry, + zhenry, + Ehenry, + yhenry, + Thenry, + uhenry, + phenry, + nhenry, + mhenry, + dahenry, + hhenry, + fhenry, + Ghenry, + dhenry, + Phenry, + Zhenry, + chenry, + ahenry, + Ytesla, + ktesla, + Mtesla, + ztesla, + Etesla, + ytesla, + Ttesla, + utesla, + ptesla, + ntesla, + mtesla, + datesla, + htesla, + ftesla, + Gtesla, + dtesla, + Ptesla, + Ztesla, + ctesla, + atesla, + Yweber, + kweber, + Mweber, + zweber, + Eweber, + yweber, + Tweber, + uweber, + pweber, + nweber, + mweber, + daweber, + hweber, + fweber, + Gweber, + dweber, + Pweber, + Zweber, + cweber, + aweber, + Ysiemens, + ksiemens, + Msiemens, + zsiemens, + Esiemens, + ysiemens, + Tsiemens, + usiemens, + psiemens, + nsiemens, + msiemens, + dasiemens, + hsiemens, + fsiemens, + Gsiemens, + dsiemens, + Psiemens, + Zsiemens, + csiemens, + asiemens, + Yohm, + kohm, + Mohm, + zohm, + Eohm, + yohm, + Tohm, + uohm, + pohm, + nohm, + mohm, + daohm, + hohm, + fohm, + Gohm, + dohm, + Pohm, + Zohm, + cohm, + aohm, + Yfarad, + kfarad, + Mfarad, + zfarad, + Efarad, + yfarad, + Tfarad, + ufarad, + pfarad, + nfarad, + mfarad, + dafarad, + hfarad, + ffarad, + Gfarad, + dfarad, + Pfarad, + Zfarad, + cfarad, + afarad, + Yvolt, + kvolt, + Mvolt, + zvolt, + Evolt, + yvolt, + Tvolt, + uvolt, + pvolt, + nvolt, + mvolt, + davolt, + hvolt, + fvolt, + Gvolt, + dvolt, + Pvolt, + Zvolt, + cvolt, + avolt, + Ycoulomb, + kcoulomb, + Mcoulomb, + zcoulomb, + Ecoulomb, + ycoulomb, + Tcoulomb, + ucoulomb, + pcoulomb, + ncoulomb, + mcoulomb, + dacoulomb, + hcoulomb, + fcoulomb, + Gcoulomb, + dcoulomb, + Pcoulomb, + Zcoulomb, + ccoulomb, + acoulomb, + Ywatt, + kwatt, + Mwatt, + zwatt, + Ewatt, + ywatt, + Twatt, + uwatt, + pwatt, + nwatt, + mwatt, + dawatt, + hwatt, + fwatt, + Gwatt, + dwatt, + Pwatt, + Zwatt, + cwatt, + awatt, + Yjoule, + kjoule, + Mjoule, + zjoule, + Ejoule, + yjoule, + Tjoule, + ujoule, + pjoule, + njoule, + mjoule, + dajoule, + hjoule, + fjoule, + Gjoule, + djoule, + Pjoule, + Zjoule, + cjoule, + ajoule, + Ypascal, + kpascal, + Mpascal, + zpascal, + Epascal, + ypascal, + Tpascal, + upascal, + ppascal, + npascal, + mpascal, + dapascal, + hpascal, + fpascal, + Gpascal, + dpascal, + Ppascal, + Zpascal, + cpascal, + apascal, + Ynewton, + knewton, + Mnewton, + znewton, + Enewton, + ynewton, + Tnewton, + unewton, + pnewton, + nnewton, + mnewton, + danewton, + hnewton, + fnewton, + Gnewton, + dnewton, + Pnewton, + Znewton, + cnewton, + anewton, + Yhertz, + khertz, + Mhertz, + zhertz, + Ehertz, + yhertz, + Thertz, + uhertz, + phertz, + nhertz, + mhertz, + dahertz, + hhertz, + fhertz, + Ghertz, + dhertz, + Phertz, + Zhertz, + chertz, + ahertz, + Ysteradian, + ksteradian, + Msteradian, + zsteradian, + Esteradian, + ysteradian, + Tsteradian, + usteradian, + psteradian, + nsteradian, + msteradian, + dasteradian, + hsteradian, + fsteradian, + Gsteradian, + dsteradian, + Psteradian, + Zsteradian, + csteradian, + asteradian, + Yradian, + kradian, + Mradian, + zradian, + Eradian, + yradian, + Tradian, + uradian, + pradian, + nradian, + mradian, + daradian, + hradian, + fradian, + Gradian, + dradian, + Pradian, + Zradian, + cradian, + aradian, + Ymolar, + kmolar, + Mmolar, + zmolar, + Emolar, + ymolar, + Tmolar, + umolar, + pmolar, + nmolar, + mmolar, + damolar, + hmolar, + fmolar, + Gmolar, + dmolar, + Pmolar, + Zmolar, + cmolar, + amolar, + Ygramme, + kgramme, + Mgramme, + zgramme, + Egramme, + ygramme, + Tgramme, + ugramme, + pgramme, + ngramme, + mgramme, + dagramme, + hgramme, + fgramme, + Ggramme, + dgramme, + Pgramme, + Zgramme, + cgramme, + agramme, + Ygram, + kgram, + Mgram, + zgram, + Egram, + ygram, + Tgram, + ugram, + pgram, + ngram, + mgram, + dagram, + hgram, + fgram, + Ggram, + dgram, + Pgram, + Zgram, + cgram, + agram, + Ycandle, + kcandle, + Mcandle, + zcandle, + Ecandle, + ycandle, + Tcandle, + ucandle, + pcandle, + ncandle, + mcandle, + dacandle, + hcandle, + fcandle, + Gcandle, + dcandle, + Pcandle, + Zcandle, + ccandle, + acandle, + Ymol, + kmol, + Mmol, + zmol, + Emol, + ymol, + Tmol, + umol, + pmol, + nmol, + mmol, + damol, + hmol, + fmol, + Gmol, + dmol, + Pmol, + Zmol, + cmol, + amol, + Ymole, + kmole, + Mmole, + zmole, + Emole, + ymole, + Tmole, + umole, + pmole, + nmole, + mmole, + damole, + hmole, + fmole, + Gmole, + dmole, + Pmole, + Zmole, + cmole, + amole, + Yampere, + kampere, + Mampere, + zampere, + Eampere, + yampere, + Tampere, + uampere, + pampere, + nampere, + mampere, + daampere, + hampere, + fampere, + Gampere, + dampere, + Pampere, + Zampere, + campere, + aampere, + Yamp, + kamp, + Mamp, + zamp, + Eamp, + yamp, + Tamp, + uamp, + pamp, + namp, + mamp, + daamp, + hamp, + famp, + Gamp, + damp, + Pamp, + Zamp, + camp, + aamp, + Ysecond, + ksecond, + Msecond, + zsecond, + Esecond, + ysecond, + Tsecond, + usecond, + psecond, + nsecond, + msecond, + dasecond, + hsecond, + fsecond, + Gsecond, + dsecond, + Psecond, + Zsecond, + csecond, + asecond, + Ymeter, + kmeter, + Mmeter, + zmeter, + Emeter, + ymeter, + Tmeter, + umeter, + pmeter, + nmeter, + mmeter, + dameter, + hmeter, + fmeter, + Gmeter, + dmeter, + Pmeter, + Zmeter, + cmeter, + ameter, + Ymetre, + kmetre, + Mmetre, + zmetre, + Emetre, + ymetre, + Tmetre, + umetre, + pmetre, + nmetre, + mmetre, + dametre, + hmetre, + fmetre, + Gmetre, + dmetre, + Pmetre, + Zmetre, + cmetre, + ametre, + katal, + sievert, + gray, + becquerel, + lux, + lumen, + henry, + tesla, + weber, + siemens, + ohm, + farad, + volt, + coulomb, + watt, + joule, + pascal, + newton, + hertz, + steradian, + radian, + molar, + gramme, + gram, + kilogramme, + candle, + mol, + mole, + kelvin, + ampere, + amp, + second, + kilogram, + meter, + metre, +] + +for unit in itertools.chain(powered_units, scaled_units, base_units): + standard_unit_register.add(unit) +for unit in additional_units: + additional_unit_register.add(unit) + +del base_units, scaled_units, powered_units, additional_units, additional_unit_register, standard_unit_register diff --git a/brainunit/_unit_constants.py b/brainunit/_unit_constants.py new file mode 100644 index 0000000..914c33d --- /dev/null +++ b/brainunit/_unit_constants.py @@ -0,0 +1,92 @@ +# Copyright 2024 BDP Ecosystem Limited. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +r""" +A module providing some physical units as `Quantity` objects. Note that these +units are not imported by wildcard imports (e.g. `from brian2 import *`), they +have to be imported explicitly. You can use ``import ... as ...`` to import them +with shorter names, e.g.:: + + from brainpy.math.units import faraday_constant as F + +The available constants are: + +==================== ================== ======================= ================================================================== +Constant Symbol(s) Brian name Value +==================== ================== ======================= ================================================================== +Avogadro constant :math:`N_A, L` ``avogadro_constant`` :math:`6.022140857\times 10^{23}\,\mathrm{mol}^{-1}` +Boltzmann constant :math:`k` ``boltzmann_constant`` :math:`1.38064852\times 10^{-23}\,\mathrm{J}\,\mathrm{K}^{-1}` +Electric constant :math:`\epsilon_0` ``electric_constant`` :math:`8.854187817\times 10^{-12}\,\mathrm{F}\,\mathrm{m}^{-1}` +Electron mass :math:`m_e` ``electron_mass`` :math:`9.10938356\times 10^{-31}\,\mathrm{kg}` +Elementary charge :math:`e` ``elementary_charge`` :math:`1.6021766208\times 10^{-19}\,\mathrm{C}` +Faraday constant :math:`F` ``faraday_constant`` :math:`96485.33289\,\mathrm{C}\,\mathrm{mol}^{-1}` +Gas constant :math:`R` ``gas_constant`` :math:`8.3144598\,\mathrm{J}\,\mathrm{mol}^{-1}\,\mathrm{K}^{-1}` +Magnetic constant :math:`\mu_0` ``magnetic_constant`` :math:`12.566370614\times 10^{-7}\,\mathrm{N}\,\mathrm{A}^{-2}` +Molar mass constant :math:`M_u` ``molar_mass_constant`` :math:`1\times 10^{-3}\,\mathrm{kg}\,\mathrm{mol}^{-1}` +0°C ``zero_celsius`` :math:`273.15\,\mathrm{K}` +==================== ================== ======================= ================================================================== +""" + +import numpy as np + +from ._base import (turn_off_unit_register, + allow_python_scalar) +from ._unit_common import ( + amp, + coulomb, + farad, + gram, + joule, + kelvin, + kilogram, + meter, + mole, + newton, +) + +__all__ = [ + 'avogadro_constant', + 'boltzmann_constant', + 'electric_constant', + 'electron_mass', + 'elementary_charge', + 'faraday_constant', + 'gas_constant', + 'magnetic_constant', + 'molar_mass_constant', + 'zero_celsius', +] + +with turn_off_unit_register(), allow_python_scalar(): + #: Avogadro constant (http://physics.nist.gov/cgi-bin/cuu/Value?na) + avogadro_constant = 6.022140857e23 / mole + #: Boltzmann constant (physics.nist.gov/cgi-bin/cuu/Value?k) + boltzmann_constant = 1.38064852e-23 * joule / kelvin + #: electric constant (http://physics.nist.gov/cgi-bin/cuu/Value?ep0) + electric_constant = 8.854187817e-12 * farad / meter + #: Electron rest mass (physics.nist.gov/cgi-bin/cuu/Value?me) + electron_mass = 9.10938356e-31 * kilogram + #: Elementary charge (physics.nist.gov/cgi-bin/cuu/Value?e) + elementary_charge = 1.6021766208e-19 * coulomb + #: Faraday constant (http://physics.nist.gov/cgi-bin/cuu/Value?f) + faraday_constant = 96485.33289 * coulomb / mole + #: gas constant (http://physics.nist.gov/cgi-bin/cuu/Value?r) + gas_constant = 8.3144598 * joule / mole / kelvin + #: Magnetic constant (http://physics.nist.gov/cgi-bin/cuu/Value?mu0) + magnetic_constant = 4 * np.pi * 1e-7 * newton / amp ** 2 + #: Molar mass constant (http://physics.nist.gov/cgi-bin/cuu/Value?mu) + molar_mass_constant = 1 * gram / mole + #: zero degree Celsius + zero_celsius = 273.15 * kelvin diff --git a/brainunit/_unit_shortcuts.py b/brainunit/_unit_shortcuts.py new file mode 100644 index 0000000..90aa52d --- /dev/null +++ b/brainunit/_unit_shortcuts.py @@ -0,0 +1,121 @@ +# Copyright 2024 BDP Ecosystem Limited. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +""" +Optional short unit names + +This module defines the following short unit names: + +mV, mA, uA (micro_amp), nA, pA, mF, uF, nF, nS, mS, uS, ms, +Hz, kHz, MHz, cm, cm2, cm3, mm, mm2, mm3, um, um2, um3 +""" + +from ._unit_common import ( + mvolt, + mamp, + uamp, + namp, + pamp, + pfarad, + ufarad, + nfarad, + nsiemens, + usiemens, + msiemens, + msecond, + usecond, + hertz, + khertz, + Mhertz, + cmetre, + cmetre2, + cmetre3, + mmetre, + mmetre2, + mmetre3, + umetre, + umetre2, + umetre3, + mmolar, + umolar, + nmolar, +) + +__all__ = [ + "mV", + "mA", + "uA", + "nA", + "pA", + "pF", + "uF", + "nF", + "nS", + "uS", + "mS", + "ms", + "us", + "Hz", + "kHz", + "MHz", + "cm", + "cm2", + "cm3", + "mm", + "mm2", + "mm3", + "um", + "um2", + "um3", + "mM", + "uM", + "nM", +] + +mV = mvolt + +mA = mamp +uA = uamp +nA = namp +pA = pamp + +pF = pfarad +uF = ufarad +nF = nfarad + +nS = nsiemens +uS = usiemens +mS = msiemens + +ms = msecond +us = usecond + +Hz = hertz +kHz = khertz +MHz = Mhertz + +cm = cmetre +cm2 = cmetre2 +cm3 = cmetre3 +mm = mmetre +mm2 = mmetre2 +mm3 = mmetre3 +um = umetre +um2 = umetre2 +um3 = umetre3 + +mM = mmolar +uM = umolar +nM = nmolar diff --git a/brainunit/_unit_test.py b/brainunit/_unit_test.py new file mode 100644 index 0000000..11be699 --- /dev/null +++ b/brainunit/_unit_test.py @@ -0,0 +1,1655 @@ +# Copyright 2024 BDP Ecosystem Limited. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +import itertools +import warnings + +import jax.numpy as jnp +import numpy as np +import pytest +from numpy.testing import assert_equal + +import brainstate as bst + +array = np.array +bst.environ.set(precision=64) + +from brainunit._unit_common import * +from brainunit._base import ( + DIMENSIONLESS, + DimensionMismatchError, + Quantity, + Unit, + check_units, + fail_for_dimension_mismatch, + get_or_create_dimension, + get_unit, + get_basic_unit, + have_same_unit, + in_unit, + is_scalar_type, +) +# from braincore.math import ufuncs_integers +from brainunit._unit_shortcuts import Hz, cm, kHz, ms, mV, nS + + +def assert_allclose(actual, desired, rtol=4.5e8, atol=0, **kwds): + """ + Thin wrapper around numpy's `~numpy.testing.utils.assert_allclose` function. The tolerance depends on the floating + point precision as defined by the `core.default_float_dtype` preference. + + Parameters + ---------- + actual : `numpy.ndarray` + The results to check. + desired : `numpy.ndarray` + The expected results. + rtol : float, optional + The relative tolerance which will be multiplied with the machine epsilon of the type set as + `core.default_float_type`. + atol : float, optional + The absolute tolerance + """ + assert have_same_unit(actual, desired) + eps = jnp.finfo(np.float32).eps + rtol = eps * rtol + jnp.allclose( + jnp.asarray(actual), jnp.asarray(desired), rtol=rtol, atol=atol, **kwds + ) + + +def assert_quantity(q, values, unit): + values = jnp.asarray(values) + if isinstance(q, Quantity): + assert have_same_unit(q.unit, unit), f"Dimension mismatch: ({get_unit(q)}) ({get_unit(unit)})" + if not jnp.allclose(q.value, values): + raise AssertionError(f"Values do not match: {q.value} != {values}") + elif isinstance(q, jnp.ndarray): + if jnp.allclose(q, values): + return True + else: + raise AssertionError(f"Values do not match: {q} != {values}") + else: + assert jnp.allclose(q, values), f"Values do not match: {q} != {values}" + + # try: + # if jnp.allclose(q, values): + # return True + # except: + # pass + # assert isinstance(q, Quantity) or ( + # have_same_unit(unit, 1) + # and (values.shape == () or isinstance(q, jnp.ndarray)) + # ), q + # assert_allclose(jnp.asarray(q), values) + # assert have_same_unit(q.unit, unit), f"Dimension mismatch: ({get_unit(q)}) ({get_unit(unit)})" + + +def test_construction(): + """Test the construction of Array objects""" + q = 500 * ms + assert_quantity(q, 0.5, second) + q = np.float64(500) * ms + assert_quantity(q, 0.5, second) + q = np.array(500) * ms + assert_quantity(q, 0.5, second) + q = np.array([500, 1000]) * ms + assert_quantity(q, np.array([0.5, 1]), second) + q = Quantity(500) + assert_quantity(q, 500, 1) + q = Quantity(500, unit=second.unit) + assert_quantity(q, 500, second) + q = Quantity([0.5, 1], unit=second.unit) + assert_quantity(q, np.array([0.5, 1]), second) + q = Quantity(np.array([0.5, 1]), unit=second.unit) + assert_quantity(q, np.array([0.5, 1]), second) + q = Quantity([500 * ms, 1 * second]) + assert_quantity(q, np.array([0.5, 1]), second) + q = Quantity.with_units(np.array([0.5, 1]), second=1) + assert_quantity(q, np.array([0.5, 1]), second) + q = [0.5, 1] * second + assert_quantity(q, np.array([0.5, 1]), second) + + # dimensionless quantities + q = Quantity([1, 2, 3]) + assert_quantity(q, np.array([1, 2, 3]), Unit(1)) + q = Quantity(np.array([1, 2, 3])) + assert_quantity(q, np.array([1, 2, 3]), Unit(1)) + q = Quantity([]) + assert_quantity(q, np.array([]), Unit(1)) + + # Illegal constructor calls + with pytest.raises(TypeError): + Quantity([500 * ms, 1]) + with pytest.raises(TypeError): + Quantity(["some", "nonsense"]) + with pytest.raises(TypeError): + Quantity([500 * ms, 1 * volt]) + + +def test_get_dimensions(): + """ + Test various ways of getting/comparing the dimensions of a Array. + """ + q = 500 * ms + assert get_unit(q) is get_or_create_dimension(q.unit._dims) + assert get_unit(q) is q.unit + assert q.has_same_unit(3 * second) + dims = q.unit + assert_equal(dims.get_dimension("time"), 1.0) + assert_equal(dims.get_dimension("length"), 0) + + assert get_unit(5) is DIMENSIONLESS + assert get_unit(5.0) is DIMENSIONLESS + assert get_unit(np.array(5, dtype=np.int32)) is DIMENSIONLESS + assert get_unit(np.array(5.0)) is DIMENSIONLESS + assert get_unit(np.float32(5.0)) is DIMENSIONLESS + assert get_unit(np.float64(5.0)) is DIMENSIONLESS + assert is_scalar_type(5) + assert is_scalar_type(5.0) + assert is_scalar_type(np.array(5, dtype=np.int32)) + assert is_scalar_type(np.array(5.0)) + assert is_scalar_type(np.float32(5.0)) + assert is_scalar_type(np.float64(5.0)) + with pytest.raises(TypeError): + get_unit("a string") + # wrong number of indices + with pytest.raises(TypeError): + get_or_create_dimension([1, 2, 3, 4, 5, 6]) + # not a sequence + with pytest.raises(TypeError): + get_or_create_dimension(42) + + +def test_display(): + """ + Test displaying a Array in different units + """ + + assert_equal(in_unit(3. * volt, mvolt), "3000. mV") + assert_equal(in_unit(10. * mV, ohm * amp), "0.01 ohm * A") + with pytest.raises(DimensionMismatchError): + in_unit(10 * nS, ohm) + # with bst.environ.context(precision=32): + # assert_equal(in_unit(3. * volt, mvolt), "3000. mV") + # assert_equal(in_unit(10. * mV, ohm * amp), "0.01 ohm * A") + # with pytest.raises(DimensionMismatchError): + # in_unit(10 * nS, ohm) + + # A bit artificial... + assert_equal(in_unit(10.0, Unit(10.0, scale=1)), "1.0") + + +def test_unary_operations(): + q = Quantity(5, unit=mV) + assert_quantity(-q, -5, mV) + assert_quantity(+q, 5, mV) + assert_quantity(abs(Quantity(-5, unit=mV)), 5, mV) + assert_quantity(~Quantity(0b101, unit=DIMENSIONLESS), -0b110, DIMENSIONLESS) + + +def test_operations(): + q1 = Quantity(5, unit=mV) + q2 = Quantity(10, unit=mV) + assert_quantity(q1 + q2, 15, mV) + assert_quantity(q1 - q2, -5, mV) + assert_quantity(q1 * q2, 50, mV * mV) + assert_quantity(q2 / q1, 2, DIMENSIONLESS) + assert_quantity(q2 // q1, 2, DIMENSIONLESS) + assert_quantity(q2 % q1, 0, mV) + assert_quantity(divmod(q2, q1)[0], 2, DIMENSIONLESS) + assert_quantity(divmod(q2, q1)[1], 0, mV) + assert_quantity(q1 ** 2, 25, mV ** 2) + assert_quantity(q1 << 1, 10, mV) + assert_quantity(q1 >> 1, 2, mV) + assert_quantity(round(q1, 0), 5, mV) + # matmul + q1 = Quantity([1, 2], unit=mV) + q2 = Quantity([3, 4], unit=mV) + assert_quantity(q1 @ q2, 11, mV ** 2) + + +def test_numpy_methods(): + q = Quantity([[1, 2], [3, 4]], unit=mV) + assert q.all() + assert q.any() + assert q.nonzero()[0].tolist() == [0, 0, 1, 1] + assert q.argmax() == 3 + assert q.argmin() == 0 + assert q.argsort(axis=None).tolist() == [0, 1, 2, 3] + assert_quantity(q.var(), 1.25, mV ** 2) + assert_quantity(q.round(), [[1, 2], [3, 4]], mV) + assert_quantity(q.std(), 1.11803398875, mV) + assert_quantity(q.sum(), 10, mV) + assert_quantity(q.trace(), 5, mV) + assert_quantity(q.cumsum(), [1, 3, 6, 10], mV) + assert_quantity(q.cumprod(), [1, 2, 6, 24], mV ** 4) + assert_quantity(q.diagonal(), [1, 4], mV) + assert_quantity(q.max(), 4, mV) + assert_quantity(q.mean(), 2.5, mV) + assert_quantity(q.min(), 1, mV) + assert_quantity(q.ptp(), 3, mV) + assert_quantity(q.ravel(), [1, 2, 3, 4], mV) + + +def test_shape_manipulation(): + q = [[1, 2], [3, 4]] * volt + + # Test flatten + assert_quantity(q.flatten(), [1, 2, 3, 4], volt) + + # Test swapaxes + assert_quantity(q.swapaxes(0, 1), [[1, 3], [2, 4]], volt) + + # Test take + assert_quantity(q.take(jnp.array([0, 2])), [1, 3], volt) + + # Test transpose + assert_quantity(q.transpose(), [[1, 3], [2, 4]], volt) + + # Test tile + assert_quantity(q.tile(2), [[1, 2, 1, 2], [3, 4, 3, 4]], volt) + + # Test unsqueeze + assert_quantity(q.unsqueeze(0), [[[1, 2], [3, 4]]], volt) + + # Test expand_dims + assert_quantity(q.expand_dims(0), [[[1, 2], [3, 4]]], volt) + + # Test expand_as + expand_as_shape = (1, 2, 2) + assert_quantity(q.expand_as(jnp.zeros(expand_as_shape).shape), [[[1, 2], [3, 4]]], volt) + + # Test put + q_put = [[1, 2], [3, 4]] * volt + q_put.put([[1, 0], [0, 1]], [10, 30] * volt) + assert_quantity(q_put, [[1, 30], [10, 4]], volt) + + # Test squeeze (no axes to squeeze in this case, so the array remains the same) + q_squeeze = [[1, 2], [3, 4]] * volt + assert_quantity(q_squeeze.squeeze(), [[1, 2], [3, 4]], volt) + + # Test array_split + q_spilt = [[10, 2], [30, 4]] * volt + assert_quantity(np.array_split(q_spilt, 2)[0], [[10, 2]], volt) + + +def test_misc_methods(): + q = [5, 10, 15] * volt + + # Test astype + assert_quantity(q.astype(np.float32), [5, 10, 15], volt) + + # Test clip + min_val = [6, 6, 6] * volt + max_val = [14, 14, 14] * volt + assert_quantity(q.clip(min_val, max_val), [6, 10, 14], volt) + + # Test conj + assert_quantity(q.conj(), [5, 10, 15], volt) + + # Test conjugate + assert_quantity(q.conjugate(), [5, 10, 15], volt) + + # Test copy + assert_quantity(q.copy(), [5, 10, 15], volt) + + # Test dot + assert_quantity(q.dot(Quantity([2, 2, 2], unit=DIMENSIONLESS)), 60, volt) + + # Test fill + q_filled = [5, 10, 15] * volt + q_filled.fill(2 * volt) + assert_quantity(q_filled, [2, 2, 2], volt) + + # Test item + assert_quantity(q.item(0), 5, volt) + + # Test prod + assert_quantity(q.prod(), 750, volt ** 3) + + # Test repeat + assert_quantity(q.repeat(2), [5, 5, 10, 10, 15, 15], volt) + + # Test clamp (same as clip, but using min and max values directly) + assert_quantity(q.clamp(6 * volt, 14 * volt), [6, 10, 14], volt) + + # Test sort + q = [15, 5, 10] * volt + assert_quantity(q.sort(), [5, 10, 15], volt) + + +# def test_str_repr(): +# """ +# Test that str representations do not raise any errors and that repr +# fullfills eval(repr(x)) == x. Also test generating LaTeX representations via sympy. +# """ +# import sympy +# +# units_which_should_exist = [ +# metre, +# meter, +# kilogram, +# kilogramme, +# second, +# amp, +# kelvin, +# mole, +# candle, +# radian, +# steradian, +# hertz, +# newton, +# pascal, +# joule, +# watt, +# coulomb, +# volt, +# farad, +# ohm, +# siemens, +# weber, +# tesla, +# henry, +# lumen, +# lux, +# becquerel, +# gray, +# sievert, +# katal, +# gram, +# gramme, +# molar, +# liter, +# litre, +# ] +# +# # scaled versions of all these units should exist (we just check farad as an example) +# some_scaled_units = [ +# Yfarad, +# Zfarad, +# Efarad, +# Pfarad, +# Tfarad, +# Gfarad, +# Mfarad, +# kfarad, +# hfarad, +# dafarad, +# dfarad, +# cfarad, +# mfarad, +# ufarad, +# nfarad, +# pfarad, +# ffarad, +# afarad, +# zfarad, +# yfarad, +# ] +# +# # some powered units +# powered_units = [cmetre2, Yfarad3] +# +# # Combined units +# complex_units = [ +# (kgram * metre2) / (amp * second3), +# 5 * (kgram * metre2) / (amp * second3), +# metre * second ** -1, +# 10 * metre * second ** -1, +# np.array([1, 2, 3]) * kmetre / second, +# np.ones(3) * nS / cm ** 2, +# # Made-up unit: +# Unit( +# 1, +# unit=get_or_create_dimension(length=5, time=2), +# dispname="O", +# ), +# 8000 * umetre ** 3, +# [0.0001, 10000] * umetre ** 3, +# 1 / metre, +# 1 / (coulomb * metre ** 2), +# Unit(1) / second, +# 3.0 * mM, +# 5 * mole / liter, +# 7 * liter / meter3, +# 1 / second ** 2, +# volt ** -2, +# (volt ** 2) ** -1, +# (1 / second) / meter, +# 1 / (1 / second), +# ] +# +# unitless = [second / second, 5 * second / second, Unit(1)] +# +# for u in itertools.chain( +# units_which_should_exist, +# some_scaled_units, +# powered_units, +# complex_units, +# unitless, +# ): +# assert len(str(u)) > 0 +# if not is_unitless(u): +# assert len(sympy.latex(u)) +# v1 = repr(u) +# v2 = eval(v1) +# assert get_unit(eval(repr(u))) == get_unit(u) +# assert_allclose(eval(repr(u)).value, u.value) +# +# for ar in [np.arange(10000) * mV, np.arange(100).reshape(10, 10) * mV]: +# latex_str = sympy.latex(ar) +# assert 0 < len(latex_str) < 2000 # arbitrary threshold, but see #1425 +# +# # test the `DIMENSIONLESS` object +# assert str(DIMENSIONLESS) == "1" +# assert repr(DIMENSIONLESS) == "Dimension()" +# +# # test DimensionMismatchError (only that it works without raising an error +# for error in [ +# DimensionMismatchError("A description"), +# DimensionMismatchError("A description", DIMENSIONLESS), +# DimensionMismatchError("A description", DIMENSIONLESS, second.unit), +# ]: +# assert len(str(error)) +# assert len(repr(error)) + + +def test_format_quantity(): + # Avoid that the default f-string (or .format call) discards units when used without + # a format spec + with bst.environ.context(precision=64): + q = 0.5 * ms + assert f"{q}" == f"{q!s}" == str(q) + assert f"{q:g}" == f"{float(q)}" + + +def test_slicing(): + # Slicing and indexing, setting items + Array = np.reshape(np.arange(6), (2, 3)) * mV + assert_allclose(Array[:].value, Array.value) + assert_allclose(Array[0].value, (np.asarray(Array)[0] * volt).value) + assert_allclose(Array[0:1].value, (np.asarray(Array)[0:1] * volt).value) + assert_allclose(Array[0, 1].value, (np.asarray(Array)[0, 1] * volt).value) + assert_allclose(Array[0:1, 1:].value, (np.asarray(Array)[0:1, 1:] * volt).value) + bool_matrix = np.array([[True, False, False], [False, False, True]]) + assert_allclose(Array[bool_matrix].value, (np.asarray(Array)[bool_matrix] * volt).value) + + +def test_setting(): + quantity = np.reshape(np.arange(6), (2, 3)) * mV + quantity[0, 1] = 10 * mV + assert quantity[0, 1] == 10 * mV + quantity[:, 1] = 20 * mV + assert np.all(quantity[:, 1] == 20 * mV) + # TODO: jax.numpy ndarray doesn't support this + # quantity[1, :] = np.ones((1, 3)) * volt + # assert np.all(quantity[1, :] == 1 * volt) + + quantity[1, 2] = 0 * mV + assert quantity[1, 2] == 0 * mV + + def set_to_value(key, value): + quantity[key] = value + + with pytest.raises(DimensionMismatchError): + set_to_value(0, 1) + with pytest.raises(DimensionMismatchError): + set_to_value(0, 1 * second) + with pytest.raises(DimensionMismatchError): + set_to_value((slice(2), slice(3)), np.ones((2, 3))) + + +def test_multiplication_division(): + quantities = [3 * mV, np.array([1, 2]) * mV, np.ones((3, 3)) * mV] + q2 = 5 * second + + for q in quantities: + # Scalars and array scalars + assert_quantity(q / 3, np.asarray(q) / 3, volt) + assert_quantity(3 / q, 3 / np.asarray(q), 1 / volt) + assert_quantity(q * 3, np.asarray(q) * 3, volt) + assert_quantity(3 * q, 3 * np.asarray(q), volt) + assert_quantity(q / np.float64(3), np.asarray(q) / 3, volt) + assert_quantity(np.float64(3) / q, 3 / np.asarray(q), 1 / volt) + assert_quantity(q * np.float64(3), np.asarray(q) * 3, volt) + assert_quantity(np.float64(3) * q, 3 * np.asarray(q), volt) + assert_quantity(q / jnp.array(3), np.asarray(q) / 3, volt) + assert_quantity(np.array(3) / q, 3 / np.asarray(q), 1 / volt) + assert_quantity(q * jnp.array(3), np.asarray(q) * 3, volt) + assert_quantity(np.array(3) * q, 3 * np.asarray(q), volt) + + # (unitless) arrays + assert_quantity(q / np.array([3]), np.asarray(q) / 3, volt) + assert_quantity(np.array([3]) / q, 3 / np.asarray(q), 1 / volt) + assert_quantity(q * np.array([3]), np.asarray(q) * 3, volt) + assert_quantity(np.array([3]) * q, 3 * np.asarray(q), volt) + + # arrays with units + assert_quantity(q / q, np.asarray(q) / np.asarray(q), 1) + assert_quantity(q * q, np.asarray(q) ** 2, volt ** 2) + assert_quantity(q / q2, np.asarray(q) / np.asarray(q2), volt / second) + assert_quantity(q2 / q, np.asarray(q2) / np.asarray(q), second / volt) + assert_quantity(q * q2, np.asarray(q) * np.asarray(q2), volt * second) + + # using unsupported objects should fail + with pytest.raises(TypeError): + q / "string" + with pytest.raises(TypeError): + "string" / q + with pytest.raises(TypeError): + "string" * q + with pytest.raises(TypeError): + q * "string" + + +def test_addition_subtraction(): + quantities = [3 * mV, np.array([1, 2]) * mV, np.ones((3, 3)) * mV] + q2 = 5 * volt + + for q in quantities: + # arrays with units + assert_quantity(q + q, np.asarray(q) + np.asarray(q), volt) + assert_quantity(q - q, 0, volt) + assert_quantity(q + q2, np.asarray(q) + np.asarray(q2), volt) + assert_quantity(q2 + q, np.asarray(q2) + np.asarray(q), volt) + assert_quantity(q - q2, np.asarray(q) - np.asarray(q2), volt) + assert_quantity(q2 - q, np.asarray(q2) - np.asarray(q), volt) + + # mismatching units + with pytest.raises(DimensionMismatchError): + q + 5 * second + with pytest.raises(DimensionMismatchError): + 5 * second + q + with pytest.raises(DimensionMismatchError): + q - 5 * second + with pytest.raises(DimensionMismatchError): + 5 * second - q + + # scalar + with pytest.raises(DimensionMismatchError): + q + 5 + with pytest.raises(DimensionMismatchError): + 5 + q + with pytest.raises(DimensionMismatchError): + q + np.float64(5) + with pytest.raises(DimensionMismatchError): + np.float64(5) + q + with pytest.raises(DimensionMismatchError): + q - 5 + with pytest.raises(DimensionMismatchError): + 5 - q + with pytest.raises(DimensionMismatchError): + q - np.float64(5) + with pytest.raises(DimensionMismatchError): + np.float64(5) - q + + # unitless array + with pytest.raises(DimensionMismatchError): + q + np.array([5]) + with pytest.raises(DimensionMismatchError): + np.array([5]) + q + with pytest.raises(DimensionMismatchError): + q + np.array([5], dtype=np.float64) + with pytest.raises(DimensionMismatchError): + np.array([5], dtype=np.float64) + q + with pytest.raises(DimensionMismatchError): + q - np.array([5]) + with pytest.raises(DimensionMismatchError): + np.array([5]) - q + with pytest.raises(DimensionMismatchError): + q - np.array([5], dtype=np.float64) + with pytest.raises(DimensionMismatchError): + np.array([5], dtype=np.float64) - q + + # Check that operations with 0 work + assert_quantity(q + 0, np.asarray(q), volt) + assert_quantity(0 + q, np.asarray(q), volt) + assert_quantity(q - 0, np.asarray(q), volt) + # Doesn't support 0 - Quantity + # assert_quantity(0 - q, -np.asarray(q), volt) + assert_quantity(q + np.float64(0), np.asarray(q), volt) + assert_quantity(np.float64(0) + q, np.asarray(q), volt) + assert_quantity(q - np.float64(0), np.asarray(q), volt) + # assert_quantity(np.float64(0) - q, -np.asarray(q), volt) + + # using unsupported objects should fail + with pytest.raises(TypeError): + "string" + q + with pytest.raises(TypeError): + q + "string" + with pytest.raises(TypeError): + q - "string" + with pytest.raises(TypeError): + "string" - q + + +# def test_unary_operations(): +# from operator import neg, pos +# +# for op in [neg, pos]: +# for x in [2, np.array([2]), np.array([1, 2])]: +# assert_quantity(op(x * kilogram), op(x), kilogram) + + +def test_binary_operations(): + """Test whether binary operations work when they should and raise + DimensionMismatchErrors when they should. + Does not test for the actual result. + """ + from operator import add, eq, ge, gt, le, lt, ne, sub + + def assert_operations_work(a, b): + try: + # Test python builtins + tryops = [add, sub, lt, le, gt, ge, eq, ne] + for op in tryops: + op(a, b) + op(b, a) + + # Test equivalent numpy functions + numpy_funcs = [ + np.add, + np.subtract, + np.less, + np.less_equal, + np.greater, + np.greater_equal, + np.equal, + np.not_equal, + np.maximum, + np.minimum, + ] + for numpy_func in numpy_funcs: + numpy_func(a, b) + numpy_func(b, a) + except DimensionMismatchError as ex: + raise AssertionError(f"Operation raised unexpected exception: {ex}") + + def assert_operations_do_not_work(a, b): + # Test python builtins + tryops = [add, sub, lt, le, gt, ge, eq, ne] + for op in tryops: + with pytest.raises(DimensionMismatchError): + op(a, b) + with pytest.raises(DimensionMismatchError): + op(b, a) + + # Do not support equivalent numpy functions + # numpy_funcs = [ + # np.add, + # np.subtract, + # np.less, + # np.less_equal, + # np.greater, + # np.greater_equal, + # np.equal, + # np.not_equal, + # np.maximum, + # np.minimum, + # ] + # for numpy_func in numpy_funcs: + # with pytest.raises(DimensionMismatchError): + # numpy_func(a, b) + # with pytest.raises(DimensionMismatchError): + # numpy_func(b, a) + + # + # Check that consistent units work + # + + # unit arrays + a = 1 * kilogram + for b in [2 * kilogram, np.array([2]) * kilogram, np.array([1, 2]) * kilogram]: + assert_operations_work(a, b) + + # dimensionless units and scalars + a = 1 + for b in [ + 2 * kilogram / kilogram, + np.array([2]) * kilogram / kilogram, + np.array([1, 2]) * kilogram / kilogram, + ]: + assert_operations_work(a, b) + + # dimensionless units and unitless arrays + a = np.array([1]) + for b in [ + 2 * kilogram / kilogram, + np.array([2]) * kilogram / kilogram, + np.array([1, 2]) * kilogram / kilogram, + ]: + assert_operations_work(a, b) + + # + # Check that inconsistent units do not work + # + + # unit arrays + a = np.array([1]) * second + for b in [2 * kilogram, np.array([2]) * kilogram, np.array([1, 2]) * kilogram]: + assert_operations_do_not_work(a, b) + + # unitless array + a = np.array([1]) + for b in [2 * kilogram, np.array([2]) * kilogram, np.array([1, 2]) * kilogram]: + assert_operations_do_not_work(a, b) + + # scalar + a = 1 + for b in [2 * kilogram, np.array([2]) * kilogram, np.array([1, 2]) * kilogram]: + assert_operations_do_not_work(a, b) + + # Check that comparisons with inf/-inf always work + values = [ + 2 * kilogram / kilogram, + 2 * kilogram, + np.array([2]) * kilogram, + np.array([1, 2]) * kilogram, + ] + for value in values: + assert np.all(value < np.inf) + assert np.all(np.inf > value) + assert np.all(value <= np.inf) + assert np.all(np.inf >= value) + assert np.all(value != np.inf) + assert np.all(np.inf != value) + assert np.all(value >= -np.inf) + assert np.all(-np.inf <= value) + assert np.all(value > -np.inf) + assert np.all(-np.inf < value) + + +def test_power(): + """ + Test raising quantities to a power. + """ + values = [2 * kilogram, np.array([2]) * kilogram, np.array([1, 2]) * kilogram] + for value in values: + assert_quantity(value ** 3, np.asarray(value) ** 3, kilogram ** 3) + # Test raising to a dimensionless Array + assert_quantity( + value ** (3 * volt / volt), np.asarray(value) ** 3, kilogram ** 3 + ) + with pytest.raises(DimensionMismatchError): + value ** (2 * volt) + with pytest.raises(TypeError): + value ** np.array([2, 3]) + + +def test_inplace_operations(): + q = np.arange(10) * volt + q_orig = q.copy() + q_id = id(q) + + # Doesn't support in-place operations which change unit + # q *= 2 + # assert np.all(q == 2 * q_orig) and id(q) == q_id + # q /= 2 + # assert np.all(q == q_orig) and id(q) == q_id + q += 1 * volt + assert np.all(q == q_orig + 1 * volt) and id(q) == q_id + q -= 1 * volt + assert np.all(q == q_orig) and id(q) == q_id + + # q **= 2 + # assert np.all(q == q_orig ** 2) and id(q) == q_id + # q **= 0.5 + # assert np.all(q == q_orig) and id(q) == q_id + + def illegal_add(q2): + q = np.arange(10) * volt + q += q2 + + with pytest.raises(DimensionMismatchError): + illegal_add(1 * second) + with pytest.raises(DimensionMismatchError): + illegal_add(1) + + def illegal_sub(q2): + q = np.arange(10) * volt + q -= q2 + + with pytest.raises(DimensionMismatchError): + illegal_add(1 * second) + with pytest.raises(DimensionMismatchError): + illegal_add(1) + + def illegal_pow(q2): + q = np.arange(10) * volt + q **= q2 + + # with pytest.raises(DimensionMismatchError): + # illegal_pow(1 * volt) + # with pytest.raises(TypeError): + # illegal_pow(np.arange(10)) + + # inplace operations with unsupported objects should fail + for inplace_op in [ + q.__iadd__, + q.__isub__, + # q.__imul__, + # q.__idiv__, + # q.__itruediv__, + # q.__ifloordiv__, + # q.__imod__, + # q.__ipow__, + ]: + try: + result = inplace_op("string") + # if it doesn't fail with an error, it should return NotImplemented + assert result == NotImplemented + except TypeError: + pass # raised on numpy >= 0.10 + + # make sure that inplace operations do not work on units/dimensions at all + for inplace_op in [ + volt.__iadd__, + volt.__isub__, + # volt.__imul__, + # volt.__idiv__, + # volt.__itruediv__, + # volt.__ifloordiv__, + # volt.__imod__, + # volt.__ipow__, + ]: + with pytest.raises(TypeError): + inplace_op(volt) + # for inplace_op in [ + # volt.unit.__imul__, + # volt.unit.__idiv__, + # volt.unit.__itruediv__, + # volt.unit.__ipow__, + # ]: + # with pytest.raises(TypeError): + # inplace_op(volt.unit) + + +def test_unit_discarding_functions(): + """ + Test functions that discard units. + """ + from brainunit import ones_like, zeros_like + + values = [3 * mV, np.array([1, 2]) * mV, np.arange(12).reshape(3, 4) * mV] + for value in values: + assert_equal(np.sign(value.value), np.sign(np.asarray(value.value))) + assert_equal(zeros_like(value), np.zeros_like(np.asarray(value.value))) + assert_equal(ones_like(value), np.ones_like(np.asarray(value.value))) + # Calling non-zero on a 0d array is deprecated, don't test it: + if value.ndim > 0: + assert_equal(np.nonzero(value.value), np.nonzero(np.asarray(value.value))) + + +def test_unitsafe_functions(): + """ + Test the unitsafe functions wrapping their numpy counterparts. + """ + from braincore.math import ( + arccos, + arccosh, + arcsin, + arcsinh, + arctan, + arctanh, + cos, + cosh, + exp, + log, + sin, + sinh, + tan, + tanh, + ) + + # All functions with their numpy counterparts + funcs = [ + (sin, np.sin), + (sinh, np.sinh), + (arcsin, np.arcsin), + (arcsinh, np.arcsinh), + (cos, np.cos), + (cosh, np.cosh), + (arccos, np.arccos), + (arccosh, np.arccosh), + (tan, np.tan), + (tanh, np.tanh), + (arctan, np.arctan), + (arctanh, np.arctanh), + (log, np.log), + (exp, np.exp), + ] + + unitless_values = [ + 3 * mV / mV, + np.array([1, 2]) * mV / mV, + np.ones((3, 3)) * mV / mV, + ] + numpy_values = [3, np.array([1, 2]), np.ones((3, 3))] + unit_values = [3 * mV, np.array([1, 2]) * mV, np.ones((3, 3)) * mV] + + for func, np_func in funcs: + # make sure these functions raise errors when run on values with dimensions + for val in unit_values: + with pytest.raises(DimensionMismatchError): + func(val) + + # make sure the functions are equivalent to their numpy counterparts + # when run on unitless values while ignoring warnings about invalid + # values or divisions by zero + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + + for val in unitless_values: + if hasattr(val, "value"): + assert_allclose(func(val.value), np_func(val.value)) + else: + assert_allclose(func(val), np_func(val)) + + for val in numpy_values: + assert_allclose(func(val), np_func(val)) + + +def test_special_case_numpy_functions(): + """ + Test a couple of functions/methods that need special treatment. + """ + from braincore.math import diagonal, dot, ravel, trace, where + + quadratic_matrix = np.reshape(np.arange(9), (3, 3)) * mV + + # Temporarily suppress warnings related to the matplotlib 1.3 bug + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + # Check that function and method do the same + assert_allclose(ravel(quadratic_matrix).value, quadratic_matrix.ravel().value) + # Check that function gives the same result as on unitless arrays + assert_allclose( + np.asarray(ravel(quadratic_matrix).value), ravel(np.asarray(quadratic_matrix)) + ) + # Check that the function gives the same results as the original numpy + # function + assert_allclose( + np.ravel(np.asarray(quadratic_matrix.value)), ravel(np.asarray(quadratic_matrix.value)) + ) + + # Do the same checks for diagonal, trace and dot + assert_allclose(diagonal(quadratic_matrix).value, quadratic_matrix.diagonal().value) + assert_allclose( + np.asarray(diagonal(quadratic_matrix).value), diagonal(np.asarray(quadratic_matrix.value)) + ) + assert_allclose( + np.diagonal(np.asarray(quadratic_matrix.value)), + diagonal(np.asarray(quadratic_matrix.value)), + ) + + assert_allclose(trace(quadratic_matrix).value, quadratic_matrix.trace().value) + assert_allclose( + np.asarray(trace(quadratic_matrix).value), trace(np.asarray(quadratic_matrix.value)) + ) + assert_allclose( + np.trace(np.asarray(quadratic_matrix.value)), trace(np.asarray(quadratic_matrix.value)) + ) + + assert_allclose( + dot(quadratic_matrix, quadratic_matrix).value, quadratic_matrix.dot(quadratic_matrix).value + ) + assert_allclose( + np.asarray(dot(quadratic_matrix, quadratic_matrix).value), + dot(np.asarray(quadratic_matrix.value), np.asarray(quadratic_matrix.value)), + ) + assert_allclose( + np.dot(np.asarray(quadratic_matrix.value), np.asarray(quadratic_matrix.value)), + dot(np.asarray(quadratic_matrix.value), np.asarray(quadratic_matrix.value)), + ) + assert_allclose( + np.asarray(quadratic_matrix.prod().value), np.asarray(quadratic_matrix.value).prod() + ) + assert_allclose( + np.asarray(quadratic_matrix.prod(axis=0).value), + np.asarray(quadratic_matrix.value).prod(axis=0), + ) + + # Check for correct units + assert have_same_unit(quadratic_matrix, ravel(quadratic_matrix)) + assert have_same_unit(quadratic_matrix, trace(quadratic_matrix)) + assert have_same_unit(quadratic_matrix, diagonal(quadratic_matrix)) + assert have_same_unit( + quadratic_matrix[0] ** 2, dot(quadratic_matrix, quadratic_matrix) + ) + assert have_same_unit( + quadratic_matrix.prod(axis=0), quadratic_matrix[0] ** quadratic_matrix.shape[0] + ) + + # check the where function + # pure numpy array + cond = [True, False, False] + ar1 = np.array([1, 2, 3]) + ar2 = np.array([4, 5, 6]) + assert_equal(np.where(cond), where(cond)) + assert_equal(np.where(cond, ar1, ar2), where(cond, ar1, ar2)) + + # dimensionless Array + assert_allclose( + np.where(cond, ar1, ar2), np.asarray(where(cond, ar1 * mV / mV, ar2 * mV / mV)) + ) + + # Array with dimensions + ar1 = ar1 * mV + ar2 = ar2 * mV + assert_allclose( + np.where(cond, np.asarray(ar1), np.asarray(ar2)), + np.asarray(where(cond, ar1, ar2)), + ) + + # Check some error cases + with pytest.raises(ValueError): + where(cond, ar1) + with pytest.raises(TypeError): + where(cond, ar1, ar1, ar2) + with pytest.raises(DimensionMismatchError): + where(cond, ar1, ar1 / ms) + + # Check setasflat (for numpy < 1.7) + if hasattr(Quantity, "setasflat"): + a = np.arange(10) * mV + b = np.ones(10).reshape(5, 2) * volt + c = np.ones(10).reshape(5, 2) * second + with pytest.raises(DimensionMismatchError): + a.setasflat(c) + a.setasflat(b) + assert_equal(a.flatten(), b.flatten()) + + # Check cumprod + a = np.arange(1, 10) * mV / mV + assert_allclose(a.cumprod(), np.asarray(a).cumprod()) + # with pytest.raises(TypeError): + # (np.arange(1, 5) * mV).cumprod() + + +# Functions that should not change units + +def test_numpy_functions_same_dimensions(): + values = [np.array([1, 2]), np.ones((3, 3))] + units = [volt, second, siemens, mV, kHz] + + # Do not suopport numpy functions + # keep_dim_funcs = [ + # np.abs, + # np.cumsum, + # np.max, + # np.mean, + # np.min, + # np.negative, + # ptp, + # np.round, + # np.squeeze, + # np.std, + # np.sum, + # np.transpose, + # ] + # + # for value, unit in itertools.product(values, units): + # q_ar = value * unit + # for func in keep_dim_funcs: + # test_ar = func(q_ar) + # if not get_unit(test_ar) is q_ar.unit: + # raise AssertionError( + # f"'{func.__name__}' failed on {q_ar!r} -- unit was " + # f"{q_ar.unit}, is now {get_unit(test_ar)}." + # ) + # + # # Python builtins should work on one-dimensional arrays + # value = np.arange(5) + # builtins = [abs, max, min, sum] + # for unit in units: + # q_ar = value * unit + # for func in builtins: + # test_ar = func(q_ar) + # if not get_unit(test_ar) is q_ar.unit: + # raise AssertionError( + # f"'{func.__name__}' failed on {q_ar!r} -- unit " + # f"was {q_ar.unit}, is now " + # f"{get_unit(test_ar)}" + # ) + + +def test_numpy_functions_indices(): + """ + Check numpy functions that return indices. + """ + values = [np.array([-4, 3, -2, 1, 0]), np.ones((3, 3)), np.array([17])] + units = [volt, second, siemens, mV, kHz] + + # numpy functions + keep_dim_funcs = [np.argmin, np.argmax, np.argsort, np.nonzero] + + for value, unit in itertools.product(values, units): + q_ar = value * unit + for func in keep_dim_funcs: + test_ar = func(q_ar) + # Compare it to the result on the same value without units + comparison_ar = func(value) + test_ar = np.asarray(test_ar) + comparison_ar = np.asarray(comparison_ar) + assert_equal( + test_ar, + comparison_ar, + ( + "function %s returned an incorrect result when used on quantities " + % func.__name__ + ), + ) + + +# Do not support numpy functions +# def test_numpy_functions_dimensionless(): +# """ +# Test that numpy functions that should work on dimensionless quantities only +# work dimensionless arrays and return the correct result. +# """ +# unitless_values = [3, np.array([-4, 3, -1, 2]), np.ones((3, 3))] +# unit_values = [3 * mV, np.array([-4, 3, -1, 2]) * mV, np.ones((3, 3)) * mV] +# with warnings.catch_warnings(): +# # ignore division by 0 warnings +# warnings.simplefilter("ignore", RuntimeWarning) +# for value in unitless_values: +# for ufunc in ufuncs_dimensionless: +# result_unitless = eval(f"np.{ufunc}(value)") +# result_array = eval(f"np.{ufunc}(np.array(value))") +# assert isinstance( +# result_unitless, (np.ndarray, np.number) +# ) and not isinstance(result_unitless, Quantity) +# assert_equal(result_unitless, result_array) +# for ufunc in ufuncs_dimensionless_twoargs: +# result_unitless = eval(f"np.{ufunc}(value, value)") +# result_array = eval(f"np.{ufunc}(np.array(value), np.array(value))") +# assert isinstance( +# result_unitless, (np.ndarray, np.number) +# ) and not isinstance(result_unitless, Quantity) +# assert_equal(result_unitless, result_array) +# +# for value, unitless_value in zip(unit_values, unitless_values): +# for ufunc in ufuncs_dimensionless: +# with pytest.raises(DimensionMismatchError): +# eval(f"np.{ufunc}(value)", globals(), {"value": value}) +# for ufunc in ufuncs_dimensionless_twoargs: +# with pytest.raises(DimensionMismatchError): +# eval( +# f"np.{ufunc}(value1, value2)", +# globals(), +# {"value1": value, "value2": unitless_value}, +# ) +# with pytest.raises(DimensionMismatchError): +# eval( +# f"np.{ufunc}(value2, value1)", +# globals(), +# {"value1": value, "value2": unitless_value}, +# ) +# with pytest.raises(DimensionMismatchError): +# eval(f"np.{ufunc}(value, value)", globals(), {"value": value}) + + +# Do not support numpy functions +# def test_numpy_functions_change_dimensions(): +# """ +# Test some numpy functions that change the dimensions of the Array. +# """ +# unit_values = [np.array([1, 2]) * mV, np.ones((3, 3)) * 2 * mV] +# for value in unit_values: +# assert_quantity(np.var(value), np.var(np.array(value)), volt ** 2) +# assert_quantity(np.square(value), np.square(np.array(value)), volt ** 2) +# assert_quantity(np.sqrt(value), np.sqrt(np.array(value)), volt ** 0.5) +# assert_quantity( +# np.reciprocal(value), np.reciprocal(np.array(value)), 1.0 / volt +# ) + + +# Do not support numpy functions +# def test_numpy_functions_matmul(): +# """ +# Check support for matmul and the ``@`` operator. +# """ +# no_units_eye = np.eye(3) +# with_units_eye = no_units_eye * Mohm +# matrix_no_units = np.arange(9).reshape((3, 3)) +# matrix_units = matrix_no_units * nA +# +# # First operand with units +# assert_allclose((no_units_eye @ matrix_units).value, matrix_units.value) +# assert have_same_unit(no_units_eye @ matrix_units, matrix_units) +# assert_allclose(np.matmul(no_units_eye, matrix_units.value), matrix_units.value) +# assert have_same_unit(np.matmul(no_units_eye, matrix_units.value), matrix_units.value) +# +# # Second operand with units +# assert_allclose((with_units_eye @ matrix_no_units).value, (matrix_no_units * Mohm).value) +# assert have_same_unit( +# with_units_eye @ matrix_no_units, matrix_no_units * Mohm +# ) +# assert_allclose(np.matmul(with_units_eye.value, matrix_no_units), (matrix_no_units * Mohm).value) +# assert have_same_unit( +# np.matmul(with_units_eye, matrix_no_units), matrix_no_units * Mohm +# ) +# +# # Both operands with units +# assert_allclose( +# (with_units_eye @ matrix_units).value, (no_units_eye @ matrix_no_units * nA * Mohm).value +# ) +# assert have_same_unit(with_units_eye @ matrix_units, nA * Mohm) +# assert_allclose( +# np.matmul(with_units_eye.value, matrix_units.value), +# (np.matmul(no_units_eye, matrix_no_units) * nA * Mohm).value, +# ) +# assert have_same_unit(np.matmul(with_units_eye, matrix_units), nA * Mohm) + + +# def test_numpy_functions_typeerror(): +# """ +# Assures that certain numpy functions raise a TypeError when called on +# quantities. +# """ +# unitless_values = [ +# 3 * mV / mV, +# np.array([1, 2]) * mV / mV, +# np.ones((3, 3)) * mV / mV, +# ] +# unit_values = [3 * mV, np.array([1, 2]) * mV, np.ones((3, 3)) * mV] +# for value in unitless_values + unit_values: +# for ufunc in ufuncs_integers: +# if ufunc == "invert": +# # only takes one argument +# with pytest.raises(TypeError): +# eval(f"np.{ufunc}(value)", globals(), {"value": value}) +# else: +# with pytest.raises(TypeError): +# eval(f"np.{ufunc}(value, value)", globals(), {"value": value}) + + +# Doesn't support logical functions +# +# def test_numpy_functions_logical(): +# """ +# Assure that logical numpy functions work on all quantities and return +# unitless boolean arrays. +# """ +# unit_values1 = [3 * mV, np.array([1, 2]) * mV, np.ones((3, 3)) * mV] +# unit_values2 = [3 * second, np.array([1, 2]) * second, np.ones((3, 3)) * second] +# for ufunc in ufuncs_logical: +# for value1, value2 in zip(unit_values1, unit_values2): +# try: +# # one argument +# result_units = eval(f"np.{ufunc}(value1)") +# result_array = eval(f"np.{ufunc}(np.array(value1))") +# except (ValueError, TypeError): +# # two arguments +# result_units = eval(f"np.{ufunc}(value1, value2)") +# result_array = eval(f"np.{ufunc}(np.array(value1), np.array(value2))") +# # assert that comparing to a string results in "NotImplemented" or an error +# try: +# result = eval(f'np.{ufunc}(value1, "a string")') +# assert result == NotImplemented +# except (ValueError, TypeError): +# pass # raised on numpy >= 0.10 +# try: +# result = eval(f'np.{ufunc}("a string", value1)') +# assert result == NotImplemented +# except (ValueError, TypeError): +# pass # raised on numpy >= 0.10 +# assert not isinstance(result_units, Quantity) +# assert_equal(result_units, result_array) + + +# +# def test_arange_linspace(): +# # For dimensionless values, the unit-safe functions should give the same results +# assert_equal(brian2.arange(5), np.arange(5)) +# assert_equal(brian2.arange(1, 5), np.arange(1, 5)) +# assert_equal(brian2.arange(10, step=2), np.arange(10, step=2)) +# assert_equal(brian2.arange(0, 5, 0.5), np.arange(0, 5, 0.5)) +# assert_equal(brian2.linspace(0, 1), np.linspace(0, 1)) +# assert_equal(brian2.linspace(0, 1, 10), np.linspace(0, 1, 10)) +# +# # Make sure units are checked +# with pytest.raises(DimensionMismatchError): +# brian2.arange(1 * mV, 5) +# with pytest.raises(DimensionMismatchError): +# brian2.arange(1 * mV, 5 * mV) +# with pytest.raises(DimensionMismatchError): +# brian2.arange(1, 5 * mV) +# with pytest.raises(DimensionMismatchError): +# brian2.arange(1 * mV, 5 * ms) +# with pytest.raises(DimensionMismatchError): +# brian2.arange(1 * mV, 5 * mV, step=1 * ms) +# with pytest.raises(DimensionMismatchError): +# brian2.arange(1 * ms, 5 * mV) +# +# # Check correct functioning with units +# assert_quantity( +# brian2.arange(5 * mV, step=1 * mV), float(mV) * np.arange(5, step=1), mV +# ) +# assert_quantity( +# brian2.arange(1 * mV, 5 * mV, 1 * mV), float(mV) * np.arange(1, 5, 1), mV +# ) +# assert_quantity(brian2.linspace(1 * mV, 2 * mV), float(mV) * np.linspace(1, 2), mV) +# +# # Check errors for arange with incorrect numbers of arguments/duplicate arguments +# with pytest.raises(TypeError): +# brian2.arange() +# with pytest.raises(TypeError): +# brian2.arange(0, 5, 1, 0) +# with pytest.raises(TypeError): +# brian2.arange(0, stop=1) +# with pytest.raises(TypeError): +# brian2.arange(0, 5, stop=1) +# with pytest.raises(TypeError): +# brian2.arange(0, 5, start=1) +# with pytest.raises(TypeError): +# brian2.arange(0, 5, 1, start=1) +# with pytest.raises(TypeError): +# brian2.arange(0, 5, 1, stop=2) +# with pytest.raises(TypeError): +# brian2.arange(0, 5, 1, step=2) + + +def test_list(): + """ + Test converting to and from a list. + """ + values = [3 * mV, np.array([1, 2]) * mV, np.arange(12).reshape(4, 3) * mV] + for value in values: + l = value.tolist() + from_list = Quantity(l) + assert have_same_unit(from_list, value) + assert_allclose(from_list.value, value.value) + + +def test_check_units(): + """ + Test the check_units decorator + """ + + @check_units(v=volt) + def a_function(v, x): + """ + v has to have units of volt, x can have any (or no) unit. + """ + pass + + # Try correct units + a_function(3 * mV, 5 * second) + a_function(5 * volt, "something") + a_function([1, 2, 3] * volt, None) + # lists that can be converted should also work + a_function([1 * volt, 2 * volt, 3 * volt], None) + # Strings and None are also allowed to pass + a_function("a string", None) + a_function(None, None) + + # Try incorrect units + with pytest.raises(DimensionMismatchError): + a_function(5 * second, None) + with pytest.raises(DimensionMismatchError): + a_function(5, None) + with pytest.raises(TypeError): + a_function(object(), None) + with pytest.raises(TypeError): + a_function([1, 2 * volt, 3], None) + + @check_units(result=second) + def b_function(return_second): + """ + Return a value in seconds if return_second is True, otherwise return + a value in volt. + """ + if return_second: + return 5 * second + else: + return 3 * volt + + # Should work (returns second) + b_function(True) + # Should fail (returns volt) + with pytest.raises(DimensionMismatchError): + b_function(False) + + @check_units(a=bool, b=1, result=bool) + def c_function(a, b): + if a: + return b > 0 + else: + return b + + assert c_function(True, 1) + assert not c_function(True, -1) + with pytest.raises(TypeError): + c_function(1, 1) + with pytest.raises(TypeError): + c_function(1 * mV, 1) + with pytest.raises(TypeError): + c_function(False, 1) + + +def test_get_basic_unit(): + """ + Test get_unit + """ + values = [ + (volt.unit, volt), + (mV.unit, volt), + ((amp / metre ** 2).unit, amp / metre ** 2), + ] + for unit, expected_unit in values: + unit = get_basic_unit(unit) + assert isinstance(unit, Unit) + assert unit == expected_unit + assert float(unit) == 1.0 + + +def test_get_best_unit(): + # get_best_unit should not check all values for long arrays, since it is + # a function used for display purposes only. Instead, only the first and + # last few values should matter (see github issue #966) + long_ar = np.ones(10000) * siemens + long_ar[:10] = 1 * nS + long_ar[-10:] = 2 * nS + values = [ + # (np.arange(10) * mV, mV), + # ([0.001, 0.002, 0.003] * second, ms), + (long_ar, nS), + ] + for ar, expected_unit in values: + assert ar.get_best_unit() is expected_unit + assert str(expected_unit) in ar.repr_in_best_unit() + + +def test_switching_off_unit_checks(): + """ + Check switching off unit checks (used for external functions). + """ + from brainunit._base import turn_off_unit_checking + + x = 3 * second + y = 5 * volt + with pytest.raises(DimensionMismatchError): + x + y + + with turn_off_unit_checking(): + # Now it should work + assert np.asarray(x + y) == np.array(8) + assert have_same_unit(x, y) + assert x.has_same_unit(y) + + +def test_fail_for_dimension_mismatch(): + """ + Test the fail_for_dimension_mismatch function. + """ + # examples that should not raise an error + dim1, dim2 = fail_for_dimension_mismatch(3) + assert dim1 is DIMENSIONLESS + assert dim2 is DIMENSIONLESS + dim1, dim2 = fail_for_dimension_mismatch(3 * volt / volt) + assert dim1 is DIMENSIONLESS + assert dim2 is DIMENSIONLESS + dim1, dim2 = fail_for_dimension_mismatch(3 * volt / volt, 7) + assert dim1 is DIMENSIONLESS + assert dim2 is DIMENSIONLESS + dim1, dim2 = fail_for_dimension_mismatch(3 * volt, 5 * volt) + assert dim1 is volt.unit + assert dim2 is volt.unit + + # examples that should raise an error + with pytest.raises(DimensionMismatchError): + fail_for_dimension_mismatch(6 * volt) + with pytest.raises(DimensionMismatchError): + fail_for_dimension_mismatch(6 * volt, 5 * second) + + +def test_deepcopy(): + d = {"x": 1 * second} + from copy import deepcopy + + d_copy = deepcopy(d) + assert d_copy["x"] == 1 * second + d_copy["x"] += 1 * second + assert d_copy["x"] == 2 * second + assert d["x"] == 1 * second + + +# Doesn't support copy +# +# def test_inplace_on_scalars(): +# # We want "copy semantics" for in-place operations on scalar quantities +# # in the same way as for Python scalars +# for scalar in [3 * mV, 3 * mV / mV]: +# scalar_reference = scalar +# scalar_copy = Quantity(scalar, copy=True) +# scalar += scalar_copy +# assert_equal(scalar_copy, scalar_reference) +# scalar *= 1.5 +# assert_equal(scalar_copy, scalar_reference) +# scalar /= 2 +# assert_equal(scalar_copy, scalar_reference) +# +# # also check that it worked correctly for the scalar itself +# assert_allclose(scalar, (scalar_copy + scalar_copy) * 1.5 / 2) +# +# # For arrays, it should use reference semantics +# for vector in [[3] * mV, [3] * mV / mV]: +# vector_reference = vector +# vector_copy = Quantity(vector, copy=True) +# vector += vector_copy +# assert_equal(vector, vector_reference) +# vector *= 1.5 +# assert_equal(vector, vector_reference) +# vector /= 2 +# assert_equal(vector, vector_reference) +# +# # also check that it worked correctly for the vector itself +# assert_allclose(vector, (vector_copy + vector_copy) * 1.5 / 2) + + +def test_units_vs_quantities(): + # Unit objects should stay Unit objects under certain operations + # (important e.g. in the unit definition of Equations, where only units but + # not quantities are allowed) + assert isinstance(meter ** 2, Unit) + assert isinstance(meter ** -1, Unit) + assert isinstance(meter ** 0.5, Unit) + assert isinstance(meter / second, Unit) + assert isinstance(amp / meter ** 2, Unit) + assert isinstance(1 / meter, Unit) + assert isinstance(1.0 / meter, Unit) + + # Using the unconventional type(x) == y since we want to test that + # e.g. meter**2 stays a Unit and does not become a Array however Unit + # inherits from Array and therefore both would pass the isinstance test + assert type(2 / meter) == Quantity + assert type(2 * meter) == Quantity + assert type(meter + meter) == Quantity + assert type(meter - meter) == Quantity + + +def test_all_units_list(): + from brainunit._unit_common import all_units + + assert meter in all_units + assert volt in all_units + assert cm in all_units + assert Hz in all_units + assert all(isinstance(u, Unit) for u in all_units) + + +def test_constants(): + import brainunit._unit_constants as constants + + # Check that the expected names exist and have the correct dimensions + assert constants.avogadro_constant.unit == (1 / mole).unit + assert constants.boltzmann_constant.unit == (joule / kelvin).unit + assert constants.electric_constant.unit == (farad / meter).unit + assert constants.electron_mass.unit == kilogram.unit + assert constants.elementary_charge.unit == coulomb.unit + assert constants.faraday_constant.unit == (coulomb / mole).unit + assert constants.gas_constant.unit == (joule / mole / kelvin).unit + assert constants.magnetic_constant.unit == (newton / amp2).unit + assert constants.molar_mass_constant.unit == (kilogram / mole).unit + assert constants.zero_celsius.unit == kelvin.unit + + # Check the consistency between a few constants + assert_allclose( + constants.gas_constant.value, + (constants.avogadro_constant * constants.boltzmann_constant).value, + ) + assert_allclose( + constants.faraday_constant.value, + (constants.avogadro_constant * constants.elementary_charge).value, + ) + +# if __name__ == "__main__": +# test_construction() +# test_get_dimensions() +# test_display() +# test_scale() +# test_power() +# test_pickling() +# test_str_repr() +# test_slicing() +# test_setting() +# test_multiplication_division() +# test_addition_subtraction() +# test_unary_operations() +# test_binary_operations() +# test_inplace_operations() +# test_unit_discarding_functions() +# test_unitsafe_functions() +# test_special_case_numpy_functions() +# test_numpy_functions_same_dimensions() +# test_numpy_functions_indices() +# test_numpy_functions_dimensionless() +# test_numpy_functions_change_dimensions() +# test_numpy_functions_typeerror() +# test_numpy_functions_logical() +# # test_arange_linspace() +# test_list() +# test_check_units() +# test_get_unit() +# test_get_best_unit() +# test_switching_off_unit_checks() +# test_fail_for_dimension_mismatch() +# test_deepcopy() +# test_inplace_on_scalars() +# test_units_vs_quantities() +# test_all_units_list() +# test_constants() diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..efb2823 --- /dev/null +++ b/changelog.md @@ -0,0 +1,4 @@ +# Release Notes + + + diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..2de4207 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,21 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SPHINXPROJ = brainpy +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_templates/classtemplate.rst b/docs/_templates/classtemplate.rst new file mode 100644 index 0000000..eeb823a --- /dev/null +++ b/docs/_templates/classtemplate.rst @@ -0,0 +1,9 @@ +.. role:: hidden + :class: hidden-section +.. currentmodule:: {{ module }} + + +{{ name | underline}} + +.. autoclass:: {{ name }} + :members: diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..b7bbc7c --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,12 @@ +API Documentation +================= + +.. toctree:: + :maxdepth: 1 + + apis/changelog.md + apis/functional.rst + apis/init.rst + apis/metric.rst + apis/optim.rst + diff --git a/docs/apis/functional.rst b/docs/apis/functional.rst new file mode 100644 index 0000000..705a08d --- /dev/null +++ b/docs/apis/functional.rst @@ -0,0 +1,76 @@ +``braintools.functional`` module +================================ + +.. currentmodule:: braintools.functional +.. automodule:: braintools.functional + +Activation Functions +-------------------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + tanh + relu + squareplus + softplus + soft_sign + sigmoid + silu + swish + log_sigmoid + elu + leaky_relu + hard_tanh + celu + selu + gelu + glu + logsumexp + log_softmax + softmax + standardize + one_hot + relu6 + hard_sigmoid + hard_silu + hard_swish + hard_shrink + rrelu + mish + soft_shrink + prelu + tanh_shrink + softmin + + +Normalization +------------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + weight_standardization + + +Spike Operations +---------------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + spike_bitwise_or + spike_bitwise_and + spike_bitwise_iand + spike_bitwise_not + spike_bitwise_xor + spike_bitwise_ixor + spike_bitwise + + diff --git a/docs/apis/init.rst b/docs/apis/init.rst new file mode 100644 index 0000000..5c52c1e --- /dev/null +++ b/docs/apis/init.rst @@ -0,0 +1,43 @@ +``braintools.init`` module +========================== + +.. currentmodule:: braintools.init +.. automodule:: braintools.init + + +Initializers +------------ + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + Initializer + ZeroInit + Constant + Identity + Normal + TruncatedNormal + Uniform + VarianceScaling + KaimingUniform + KaimingNormal + XavierUniform + XavierNormal + LecunUniform + LecunNormal + Orthogonal + DeltaOrthogonal + + +Initialization Helpers +---------------------- + +.. autosummary:: + :toctree: generated/ + + parameter + state + noise + to_size \ No newline at end of file diff --git a/docs/apis/metric.rst b/docs/apis/metric.rst new file mode 100644 index 0000000..33cfc52 --- /dev/null +++ b/docs/apis/metric.rst @@ -0,0 +1,121 @@ +``braintools.metric`` module +============================ + +.. currentmodule:: braintools.metric +.. automodule:: braintools.metric + +Classification Losses +--------------------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + sigmoid_binary_cross_entropy + hinge_loss + perceptron_loss + softmax_cross_entropy + softmax_cross_entropy_with_integer_labels + multiclass_hinge_loss + multiclass_perceptron_loss + poly_loss_cross_entropy + kl_divergence + kl_divergence_with_log_targets + convex_kl_divergence + ctc_loss + ctc_loss_with_forward_probs + sigmoid_focal_loss + + +Correlation +----------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + cross_correlation + voltage_fluctuation + matrix_correlation + weighted_correlation + functional_connectivity + functional_connectivity_dynamics + + +Fenchel-Young Loss +------------------ + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + make_fenchel_young_loss + + +Spike Firing +------------ + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + raster_plot + firing_rate + + +Local Field Potential +--------------------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + unitary_LFP + + +Ranking Losses +-------------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + ranking_softmax_loss + + +Regression Losses +----------------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + squared_error + absolute_error + l1_loss + l2_loss + l2_norm + huber_loss + log_cosh + cosine_similarity + cosine_distance + + +Smoothing Losses +---------------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + smooth_labels + + diff --git a/docs/apis/optim.rst b/docs/apis/optim.rst new file mode 100644 index 0000000..c73cab8 --- /dev/null +++ b/docs/apis/optim.rst @@ -0,0 +1,50 @@ +``braintools.optim`` module +=========================== + +.. currentmodule:: braintools.optim +.. automodule:: braintools.optim + +SGD Optimizers +-------------- + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + to_same_dict_tree + OptimState + Optimizer + SGD + Momentum + MomentumNesterov + Adagrad + Adadelta + RMSProp + Adam + LARS + Adan + AdamW + + +Learning Rate Schedulers +------------------------ + +.. autosummary:: + :toctree: generated/ + :nosignatures: + :template: classtemplate.rst + + LearningRateScheduler + ConstantLR + StepLR + MultiStepLR + CosineAnnealingLR + CosineAnnealingWarmRestarts + ExponentialLR + ExponentialDecayLR + InverseTimeDecayLR + PolynomialDecayLR + PiecewiseConstantLR + + diff --git a/docs/auto_generater.py b/docs/auto_generater.py new file mode 100644 index 0000000..79b515e --- /dev/null +++ b/docs/auto_generater.py @@ -0,0 +1,369 @@ +# -*- coding: utf-8 -*- + +import importlib +import inspect +import os + +block_list = ['test', 'register_pytree_node', 'call', 'namedtuple', 'jit', 'wraps', 'index', 'function'] + + +def get_class_funcs(module): + classes, functions, others = [], [], [] + # Solution from: https://stackoverflow.com/questions/43059267/how-to-do-from-module-import-using-importlib + if "__all__" in module.__dict__: + names = module.__dict__["__all__"] + else: + names = [x for x in module.__dict__ if not x.startswith("_")] + for k in names: + data = getattr(module, k) + if not inspect.ismodule(data) and not k.startswith("_"): + if inspect.isfunction(data): + functions.append(k) + elif isinstance(data, type): + classes.append(k) + else: + others.append(k) + + return classes, functions, others + + +def _write_module(module_name, filename, header=None, template=False): + module = importlib.import_module(module_name) + classes, functions, others = get_class_funcs(module) + + fout = open(filename, 'w') + # write header + if header is None: + header = f'``{module_name}`` module' + fout.write(header + '\n') + fout.write('=' * len(header) + '\n\n') + fout.write(f'.. currentmodule:: {module_name} \n') + fout.write(f'.. automodule:: {module_name} \n\n') + + # write autosummary + fout.write('.. autosummary::\n') + if template: + fout.write(' :template: classtemplate.rst\n') + fout.write(' :toctree: generated/\n\n') + for m in functions: + fout.write(f' {m}\n') + for m in classes: + fout.write(f' {m}\n') + for m in others: + fout.write(f' {m}\n') + + fout.close() + + +def _write_submodules(module_name, filename, header=None, submodule_names=(), section_names=()): + fout = open(filename, 'w') + # write header + if header is None: + header = f'``{module_name}`` module' + else: + header = header + fout.write(header + '\n') + fout.write('=' * len(header) + '\n\n') + fout.write(f'.. currentmodule:: {module_name} \n') + fout.write(f'.. automodule:: {module_name} \n\n') + + # whole module + for i, name in enumerate(submodule_names): + module = importlib.import_module(module_name + '.' + name) + classes, functions, others = get_class_funcs(module) + + fout.write(section_names[i] + '\n') + fout.write('-' * len(section_names[i]) + '\n\n') + + # write autosummary + fout.write('.. autosummary::\n') + fout.write(' :toctree: generated/\n') + fout.write(' :nosignatures:\n') + fout.write(' :template: classtemplate.rst\n\n') + for m in functions: + fout.write(f' {m}\n') + for m in classes: + fout.write(f' {m}\n') + for m in others: + fout.write(f' {m}\n') + + fout.write(f'\n\n') + + fout.close() + + +def _write_subsections(module_name, + filename, + subsections: dict, + header: str = None): + fout = open(filename, 'w') + header = f'``{module_name}`` module' if header is None else header + fout.write(header + '\n') + fout.write('=' * len(header) + '\n\n') + fout.write(f'.. currentmodule:: {module_name} \n') + fout.write(f'.. automodule:: {module_name} \n\n') + + fout.write('.. contents::' + '\n') + fout.write(' :local:' + '\n') + fout.write(' :depth: 1' + '\n\n') + + for name, values in subsections.items(): + fout.write(name + '\n') + fout.write('-' * len(name) + '\n\n') + fout.write('.. autosummary::\n') + fout.write(' :toctree: generated/\n') + fout.write(' :nosignatures:\n') + fout.write(' :template: classtemplate.rst\n\n') + for m in values: + fout.write(f' {m}\n') + fout.write(f'\n\n') + + fout.close() + + +def _write_subsections_v2(module_path, + out_path, + filename, + subsections: dict, + header: str = None): + fout = open(filename, 'w') + header = f'``{out_path}`` module' if header is None else header + fout.write(header + '\n') + fout.write('=' * len(header) + '\n\n') + fout.write(f'.. currentmodule:: {out_path} \n') + fout.write(f'.. automodule:: {out_path} \n\n') + + fout.write('.. contents::' + '\n') + fout.write(' :local:' + '\n') + fout.write(' :depth: 1' + '\n\n') + + for name, subheader in subsections.items(): + module = importlib.import_module(f'{module_path}.{name}') + classes, functions, others = get_class_funcs(module) + + fout.write(subheader + '\n') + fout.write('-' * len(subheader) + '\n\n') + fout.write('.. autosummary::\n') + fout.write(' :toctree: generated/\n') + fout.write(' :nosignatures:\n') + fout.write(' :template: classtemplate.rst\n\n') + for m in functions: + fout.write(f' {m}\n') + for m in classes: + fout.write(f' {m}\n') + for m in others: + fout.write(f' {m}\n') + fout.write(f'\n\n') + + fout.close() + + +def _write_subsections_v3(module_path, + out_path, + filename, + subsections: dict, + header: str = None): + fout = open(filename, 'w') + header = f'``{out_path}`` module' if header is None else header + fout.write(header + '\n') + fout.write('=' * len(header) + '\n\n') + fout.write(f'.. currentmodule:: {out_path} \n') + fout.write(f'.. automodule:: {out_path} \n\n') + + fout.write('.. contents::' + '\n') + fout.write(' :local:' + '\n') + fout.write(' :depth: 2' + '\n\n') + + for section in subsections: + fout.write(subsections[section]['header'] + '\n') + fout.write('-' * len(subsections[section]['header']) + '\n\n') + + fout.write(f'.. currentmodule:: {out_path}.{section} \n') + fout.write(f'.. automodule:: {out_path}.{section} \n\n') + + for name, subheader in subsections[section]['content'].items(): + module = importlib.import_module(f'{module_path}.{section}.{name}') + classes, functions, others = get_class_funcs(module) + + fout.write(subheader + '\n') + fout.write('~' * len(subheader) + '\n\n') + fout.write('.. autosummary::\n') + fout.write(' :toctree: generated/\n') + fout.write(' :nosignatures:\n') + fout.write(' :template: classtemplate.rst\n\n') + for m in functions: + fout.write(f' {m}\n') + for m in classes: + fout.write(f' {m}\n') + for m in others: + fout.write(f' {m}\n') + fout.write(f'\n\n') + + fout.close() + + +def _write_subsections_v4(module_path, + filename, + subsections: dict, + header: str = None): + fout = open(filename, 'w') + header = f'``{module_path}`` module' if header is None else header + fout.write(header + '\n') + fout.write('=' * len(header) + '\n\n') + + fout.write('.. contents::' + '\n') + fout.write(' :local:' + '\n') + fout.write(' :depth: 1' + '\n\n') + + for name, (subheader, out_path) in subsections.items(): + + module = importlib.import_module(f'{module_path}.{name}') + classes, functions, others = get_class_funcs(module) + + fout.write(subheader + '\n') + fout.write('-' * len(subheader) + '\n\n') + + fout.write(f'.. currentmodule:: {out_path} \n') + fout.write(f'.. automodule:: {out_path} \n\n') + + + fout.write('.. autosummary::\n') + fout.write(' :toctree: generated/\n') + fout.write(' :nosignatures:\n') + fout.write(' :template: classtemplate.rst\n\n') + for m in functions: + fout.write(f' {m}\n') + for m in classes: + fout.write(f' {m}\n') + for m in others: + fout.write(f' {m}\n') + fout.write(f'\n\n') + + fout.close() + + +def _get_functions(obj): + return set([n for n in dir(obj) + if (n not in block_list # not in blacklist + and callable(getattr(obj, n)) # callable + and not isinstance(getattr(obj, n), type) # not class + and n[0].islower() # starts with lower char + and not n.startswith('__') # not special methods + ) + ]) + + +def _import(mod, klass=None, is_jax=False): + obj = importlib.import_module(mod) + if klass: + obj = getattr(obj, klass) + return obj, ':meth:`{}.{}.{{}}`'.format(mod, klass) + else: + if not is_jax: + return obj, ':obj:`{}.{{}}`'.format(mod) + else: + from docs import implemented_jax_funcs + return implemented_jax_funcs, ':obj:`{}.{{}}`'.format(mod) + + +def _generate_comparison_rst(numpy_mod, brainpy_mod, jax_mod, klass=None, header=', , ', is_jax=False): + np_obj, np_fmt = _import(numpy_mod, klass) + np_funcs = _get_functions(np_obj) + + bm_obj, bm_fmt = _import(brainpy_mod, klass) + bm_funcs = _get_functions(bm_obj) + + jax_obj, jax_fmt = _import(jax_mod, klass, is_jax=is_jax) + jax_funcs = _get_functions(jax_obj) + + buf = [] + buf += [ + '.. csv-table::', + ' :header: {}'.format(header), + '', + ] + for f in sorted(np_funcs): + np_cell = np_fmt.format(f) + bm_cell = bm_fmt.format(f) if f in bm_funcs else r'\-' + jax_cell = jax_fmt.format(f) if f in jax_funcs else r'\-' + line = ' {}, {}, {}'.format(np_cell, bm_cell, jax_cell) + buf.append(line) + + unique_names = bm_funcs - np_funcs + for f in sorted(unique_names): + np_cell = r'\-' + bm_cell = bm_fmt.format(f) if f in bm_funcs else r'\-' + jax_cell = jax_fmt.format(f) if f in jax_funcs else r'\-' + line = ' {}, {}, {}'.format(np_cell, bm_cell, jax_cell) + buf.append(line) + + buf += [ + '', + '**Summary**\n', + '- Number of NumPy functions: {}\n'.format(len(np_funcs)), + '- Number of functions covered by ``brainpy.math``: {}\n'.format(len(bm_funcs & np_funcs)), + '- Number of functions unique in ``brainpy.math``: {}\n'.format(len(bm_funcs - np_funcs)), + '- Number of functions covered by ``jax.numpy``: {}\n'.format(len(jax_funcs & np_funcs)), + ] + return buf + + +def _section(header, numpy_mod, brainpy_mod, jax_mod, klass=None, is_jax=False): + buf = [header, '-' * len(header), '', ] + header2 = 'NumPy, brainpy.math, jax.numpy' + buf += _generate_comparison_rst(numpy_mod, brainpy_mod, jax_mod, klass=klass, header=header2, is_jax=is_jax) + buf += [''] + return buf + + +def main(): + os.makedirs('apis/auto/', exist_ok=True) + + _write_module(module_name='braintools.init', + filename='apis/init.rst', + header='``braintools.init`` module') + + module_and_name = [ + ('_classification', 'Classification Losses'), + ('_correlation', 'Correlation'), + ('_fenchel_young', 'Fenchel-Young Loss'), + ('_firings', 'Spike Firing'), + ('_lfp', 'Local Field Potential'), + ('_ranking', 'Ranking Losses'), + ('_regression', 'Regression Losses'), + ('_smoothing', 'Smoothing Losses'), + ] + _write_submodules(module_name='braintools.metric', + filename='apis/metric.rst', + header='``braintools.metric`` module', + submodule_names=[k[0] for k in module_and_name], + section_names=[k[1] for k in module_and_name]) + + module_and_name = [ + ('_activations', 'Activation Functions'), + ('_normalization', 'Normalization'), + ('_spikes', 'Spike Operations'), + ] + _write_submodules(module_name='braintools.functional', + filename='apis/functional.rst', + header='``braintools.functional`` module', + submodule_names=[k[0] for k in module_and_name], + section_names=[k[1] for k in module_and_name]) + + module_and_name = [ + ('_sgd_optimizer', 'SGD Optimizers'), + ('_lr_scheduler', 'Learning Rate Schedulers'), + ] + _write_submodules(module_name='braintools.optim', + filename='apis/optim.rst', + header='``braintools.optim`` module', + submodule_names=[k[0] for k in module_and_name], + section_names=[k[1] for k in module_and_name]) + + +if __name__ == '__main__': + main() + + + + diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..dc0d609 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,131 @@ +# Copyright 2024 BDP Ecosystem Limited. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# a_list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# + +import os +import sys + +sys.path.insert(0, os.path.abspath('../')) + +import brainunit + + +# -- Project information ----------------------------------------------------- + +project = 'brainunit' +copyright = '2024, brainunit' +author = 'BDP Ecosystem' + +# The full version, including alpha/beta/rc tags +release = brainunit.__version__ + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.intersphinx', + 'sphinx.ext.mathjax', + 'sphinx.ext.napoleon', + 'sphinx.ext.viewcode', + 'sphinx_autodoc_typehints', + 'myst_nb', + 'matplotlib.sphinxext.plot_directive', + 'sphinx_thebe', + 'sphinx_design' +] +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] +source_suffix = ['.rst', '.ipynb', '.md'] + + +# source_suffix = '.rst' +autosummary_generate = True + +# The master toctree document. +master_doc = 'index' + +intersphinx_mapping = { + "python": ("https://docs.python.org/3.8", None), + "sphinx": ("https://www.sphinx-doc.org/en/master", None), +} +nitpick_ignore = [ + ("py:class", "docutils.nodes.document"), + ("py:class", "docutils.parsers.rst.directives.body.Sidebar"), +] + +suppress_warnings = ["myst.domains", "ref.ref"] + +numfig = True + +myst_enable_extensions = [ + "dollarmath", + "amsmath", + "deflist", + "colon_fence", +] +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +html_theme = "sphinx_book_theme" +html_logo = "_static/brainunit.jpg" +html_title = "brainunit" +html_copy_source = True +html_sourcelink_suffix = "" +html_favicon = "_static/brainunit.jpg" +html_last_updated_fmt = "" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] +jupyter_execute_notebooks = "off" +thebe_config = { + "repository_url": "https://github.com/binder-examples/jupyter-stacks-datascience", + "repository_branch": "master", +} + + +html_theme_options = { + 'show_toc_level': 2, +} + +# -- Options for myst ---------------------------------------------- +# Notebook cell execution timeout; defaults to 30. +execution_timeout = 200 + +autodoc_default_options = { + 'exclude-members': '....,default_rng', +} diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..4e4b932 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,61 @@ +``brainunit`` documentation +=========================== + +`brainunit `_ implements the common toolboxes for brain dynamics programming (BDP). + +---- + + +Installation +^^^^^^^^^^^^ + +.. tab-set:: + + .. tab-item:: CPU + + .. code-block:: bash + + pip install -U brainunit[cpu] + + .. tab-item:: GPU (CUDA 11.0) + + .. code-block:: bash + + pip install -U brainunit[cuda11] + + .. tab-item:: GPU (CUDA 12.0) + + .. code-block:: bash + + pip install -U brainunit[cuda12] + + .. tab-item:: TPU + + .. code-block:: bash + + pip install -U brainunit[tpu] + + +---- + + +See also the BDP ecosystem +^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +- `brainpy `_: The solution for the general-purpose brain dynamics programming. + +- `braincore `_: The core system for the next generation of BrainPy framework. + +- `brainunit `_: The tools for the brain dynamics simulation and analysis. + +- `brainscale `_: The scalable online learning for biological spiking neural networks. + + + +.. toctree:: + :hidden: + :maxdepth: 2 + + api.rst + diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..922152e --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0577db5 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,66 @@ +[build-system] +requires = ["setuptools", "numpy", 'jax', 'jaxlib', 'braincore'] +build-backend = "setuptools.build_meta" + + +[tool.setuptools.packages.find] +exclude = [ + "docs*", "tests*", "examples*", "build*", "dist*", + "braintools.egg-info*", "braintools/__pycache__*", + "braintools/__init__.py" +] + + +[tool.distutils.bdist_wheel] +universal = true + + +[project] +name = "braintools" +description = "The Toolbox for Brain Dynamics Programming." +readme = 'README.md' +license = { text = 'Apache-2.0 license' } +requires-python = '>=3.9' +authors = [{ name = 'BrainPy Team', email = 'chao.brain@qq.com' }] +classifiers = [ + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python', + 'Topic :: Scientific/Engineering :: Bio-Informatics', + 'Topic :: Scientific/Engineering :: Mathematics', + 'Topic :: Scientific/Engineering :: Artificial Intelligence', + 'Topic :: Software Development :: Libraries', +] + + +keywords = ["BrainPy", "brain simulation", "brain-inspired computing"] + +dependencies = [ + 'jax', + 'jaxlib', + 'numpy', + 'braincore', +] + +dynamic = ['version'] + +[tool.flit.module] +name = "braintools" + +[project.urls] +homepage = 'http://github.com/brainpy/braintools' +repository = 'http://github.com/brainpy/braintools' + +[project.optional-dependencies] +testing = [ + 'pytest', +] diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..85a3f7a --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,6 @@ +-r requirements.txt +brainpy + +# test requirements +pytest +absl-py diff --git a/requirements-doc.txt b/requirements-doc.txt new file mode 100644 index 0000000..0eab13b --- /dev/null +++ b/requirements-doc.txt @@ -0,0 +1,15 @@ +-r requirements.txt +matplotlib + +# document requirements +pandoc +Jinja2 +sphinx>=5 +myst-nb +sphinx_thebe +sphinx-autodoc-typehints +sphinx-book-theme>=1.0.1 +sphinx-copybutton>=0.5.0 +sphinx-remove-toctrees +jupyter-sphinx>=0.3.2 +sphinx-design diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c82c553 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +numpy +jax +jaxlib +brainstate diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ab4d550 --- /dev/null +++ b/setup.py @@ -0,0 +1,94 @@ +# Copyright 2024- BrainPy Ecosystem Limited. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +# -*- coding: utf-8 -*- + +import io +import os +import re +import sys +import time + +from setuptools import find_packages +from setuptools import setup + +# version +here = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(here, 'brainunit/', '__init__.py'), 'r') as f: + init_py = f.read() +version = re.search('__version__ = "(.*)"', init_py).groups()[0] +if len(sys.argv) > 2 and sys.argv[2] == '--python-tag=py3': + version = version +else: + version += '.post{}'.format(time.strftime("%Y%m%d", time.localtime())) + +# obtain long description from README +with io.open(os.path.join(here, 'README.md'), 'r', encoding='utf-8') as f: + README = f.read() + +# installation packages +packages = find_packages( + exclude=["docs*", "tests*", "examples*", "build*", + "dist*", "brainunit.egg-info*", "brainunit/__pycache__*"] +) + +# setup +setup( + name='brainunit', + version=version, + description='A Unit-aware System for Brain Dynamics Programming', + long_description=README, + long_description_content_type="text/markdown", + author='BrainPy Team', + author_email='chao.brain@qq.com', + packages=packages, + python_requires='>=3.9', + install_requires=['numpy>=1.15', 'jax', 'brainstate'], + url='https://github.com/brainpy/brainunit', + project_urls={ + "Bug Tracker": "https://github.com/brainpy/brainunit/issues", + "Documentation": "https://brainunit.readthedocs.io/", + "Source Code": "https://github.com/brainpy/brainunit", + }, + extras_require={ + 'cpu': ['jaxlib', ], + 'cuda11': ['jaxlib[cuda11_pip]', ], + 'cuda12': ['jaxlib[cuda12_pip]', ], + 'tpu': ['jaxlib[tpu]'], + 'cpu_mini': ['jaxlib'], + 'cuda11_mini': ['jaxlib[cuda11_pip]'], + 'cuda12_mini': ['jaxlib[cuda12_pip]'], + }, + keywords=('computational neuroscience, ' + 'brain-inspired computation, ' + 'brain dynamics programming'), + classifiers=[ + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: Apache Software License', + 'Topic :: Scientific/Engineering :: Bio-Informatics', + 'Topic :: Scientific/Engineering :: Mathematics', + 'Topic :: Scientific/Engineering :: Artificial Intelligence', + 'Topic :: Software Development :: Libraries', + ], + license='Apache-2.0 license', +)