wigners


Namewigners JSON
Version 0.3.0 PyPI version JSON
download
home_pagehttps://github.com/Luthaf/wigners
SummaryCompute Wigner 3j and Clebsch-Gordan coefficients
upload_time2023-03-28 08:45:39
maintainer
docs_urlNone
authorGuillaume Fraux
requires_python
license
keywords clebsch-gordan wigner
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Calculation of Wigner symbols and related constants

This package computes Wigner 3j coefficients and Clebsch-Gordan coefficients in
pure Rust. The calculation is based on the prime factorization of the different
factorials involved in the coefficients, keeping the values in a rational root
form (`sign * \sqrt{s / n}`) for as long as possible. This idea for the
algorithm is described in:

[H. T. Johansson and C. Forssén, SIAM Journal on Scientific Compututing 38 (2016) 376-384](https://doi.org/10.1137/15M1021908)

This implementation takes a lot of inspiration from the
[WignerSymbols](https://github.com/Jutho/WignerSymbols.jl/) Julia implementation
(and even started as a direct translation of it), many thanks to them! This
package is available under the same license as the Julia package.

## Usage

### From python

```
pip install wigners
```

And then call one of the exported function:

```py
import wigners

w3j = wigners.wigner_3j(j1, j2, j3, m1, m2, m3)

cg = wigners.clebsch_gordan(j1, m1, j2, m1, j3, m3)

# full array of Clebsch-Gordan coefficients, computed in parallel
cg_array = wigners.clebsch_gordan_array(ji, j2, j3)

# we have an internal cache for recently computed CG coefficients, if you
# need to clean it up you can use this function
wigners.clear_wigner_3j_cache()
```

### From rust

Add this crate to your `Cargo.toml` dependencies section:

```toml
wigners = "0.3"
```

And then call one of the exported function:

```rust
let w3j = wigners::wigner_3j(j1, j2, j3, m1, m2, m3);

let cg = wigners::clebsch_gordan(j1, m1, j2, m1, j3, m3);

wigners::clear_wigner_3j_cache();
```

## Limitations

Only Wigner 3j symbols for full integers (no half-integers) are implemented,
since that's the only part I need for my own work.

6j and 9j symbols can also be computed with this approach; and support for
half-integers should be feasible as well. I'm open to pull-request implementing
these!

## Benchmarks

This benchmark measure the time to compute all possible Wigner 3j symbols up to
a fixed maximal angular momentum; clearing up any cached values from previous
angular momentum before starting the loop. In pseudo code, the benchmark looks
like this:

```
if cached_wigner_3j:
    clear_wigner_3j_cache()

# only measure the time taken by the loop
start = time.now()
for j1 in range(max_angular):
    for j2 in range(max_angular):
        for j3 in range(max_angular):
            for m1 in range(-j1, j1 + 1):
                for m2 in range(-j2, j2 + 1):
                    for m3 in range(-j3, j3 + 1):
                        w3j = wigner_3j(j1, j2, j3, m1, m2, m3)

elapsed = start - time.now()
```

Here are the results on an Apple M1 Max (10 cores) CPU:

| angular momentum | wigners (this) | wigner-symbols v0.5 | WignerSymbols.jl v2.0 | wigxjpf v1.11 | sympy v1.11 |
|------------------|----------------|---------------------|-----------------------|---------------|-------------|
| 4                | 0.190 ms       | 7.50 ms             | 2.58 ms               | 0.228 ms      | 28.7 ms     |
| 8                | 4.46 ms        | 227 ms              | 47.0 ms               | 7.36 ms       | 1.36 s      |
| 12               | 34.0 ms        | 1.94 s              | 434 ms                | 66.2 ms       | 23.1 s      |
| 16               | 156 ms         | 9.34 s              | 1.98 s                | 333 ms        |    /        |
| 20               | 531 ms         |   /                 | 6.35 s                | 1.21 s        |    /        |


A second set of benchmarks checks computing Wigner symbols for large `j`, with the
corresponding `m` varying from -10 to 10, i.e. in pseudo code:

```
if cached_wigner_3j:
    clear_wigner_3j_cache()

# only measure the time taken by the loop
start = time.now()
for m1 in range(-10, 10 + 1):
    for m2 in range(-10, 10 + 1):
        for m3 in range(-10, 10 + 1):
            w3j = wigner_3j(j1, j2, j3, m1, m2, m3)

elapsed = start - time.now()
```


| (j1, j2, j3)     | wigners (this) | wigner-symbols v0.5 | WignerSymbols.jl v2.0 | wigxjpf v1.11 | sympy v1.11 |
|------------------|----------------|---------------------|-----------------------|---------------|-------------|
| (300, 100, 250)  | 38.7 ms        | 16.5 ms             | 32.9 ms               | 7.60 ms       | 2.31 s      |

To run the benchmarks yourself on your own machine, execute the following commands:

```bash
cd benchmarks
cargo bench # this gives the results for wigners, wigner-symbols and wigxjpf

python sympy-bench.py # this gives the results for sympy

julia wigner-symbol.jl # this gives the results for WignerSymbols.jl
```

## Comparison to `wigner-symbols`

There is another Rust implementation of wigner symbols: the
[wigner-symbols](https://github.com/Rufflewind/wigner-symbols-rs) crate.
`wigner-symbols` also implements 6j and 9j symbols, but it was not usable for my
case since it relies on [rug](https://crates.io/crates/rug) for arbitrary
precision integers and through it on the [GMP](https://gmplib.org/) library. The
GMP library might be problematic for you for one of these reason:
- it is relatively slow (see the benchmarks above)
- it is distributed under LGPL (this crate is distributed under Apache/MIT);
- it is written in C and C++; and as such is hard to cross-compile or compile to WASM;
- it does not support the MSVC compiler on windows, only the GNU compilers

As you can see in the benchmarks above, this usage of GMP becomes an advantage
for large j, where the algorithm used in this crate does not scale as well.

## License

This crate is distributed under both the MIT license and the Apache 2.0 license.



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Luthaf/wigners",
    "name": "wigners",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "clebsch-gordan,wigner",
    "author": "Guillaume Fraux",
    "author_email": "guillaume.fraux@epfl.ch",
    "download_url": "https://files.pythonhosted.org/packages/09/b3/8c067d2440abd9c4aa4f9f91a46a8eaffc1e5a33d97ae8cafbe84756e437/wigners-0.3.0.tar.gz",
    "platform": null,
    "description": "# Calculation of Wigner symbols and related constants\n\nThis package computes Wigner 3j coefficients and Clebsch-Gordan coefficients in\npure Rust. The calculation is based on the prime factorization of the different\nfactorials involved in the coefficients, keeping the values in a rational root\nform (`sign * \\sqrt{s / n}`) for as long as possible. This idea for the\nalgorithm is described in:\n\n[H. T. Johansson and C. Forss\u00e9n, SIAM Journal on Scientific Compututing 38 (2016) 376-384](https://doi.org/10.1137/15M1021908)\n\nThis implementation takes a lot of inspiration from the\n[WignerSymbols](https://github.com/Jutho/WignerSymbols.jl/) Julia implementation\n(and even started as a direct translation of it), many thanks to them! This\npackage is available under the same license as the Julia package.\n\n## Usage\n\n### From python\n\n```\npip install wigners\n```\n\nAnd then call one of the exported function:\n\n```py\nimport wigners\n\nw3j = wigners.wigner_3j(j1, j2, j3, m1, m2, m3)\n\ncg = wigners.clebsch_gordan(j1, m1, j2, m1, j3, m3)\n\n# full array of Clebsch-Gordan coefficients, computed in parallel\ncg_array = wigners.clebsch_gordan_array(ji, j2, j3)\n\n# we have an internal cache for recently computed CG coefficients, if you\n# need to clean it up you can use this function\nwigners.clear_wigner_3j_cache()\n```\n\n### From rust\n\nAdd this crate to your `Cargo.toml` dependencies section:\n\n```toml\nwigners = \"0.3\"\n```\n\nAnd then call one of the exported function:\n\n```rust\nlet w3j = wigners::wigner_3j(j1, j2, j3, m1, m2, m3);\n\nlet cg = wigners::clebsch_gordan(j1, m1, j2, m1, j3, m3);\n\nwigners::clear_wigner_3j_cache();\n```\n\n## Limitations\n\nOnly Wigner 3j symbols for full integers (no half-integers) are implemented,\nsince that's the only part I need for my own work.\n\n6j and 9j symbols can also be computed with this approach; and support for\nhalf-integers should be feasible as well. I'm open to pull-request implementing\nthese!\n\n## Benchmarks\n\nThis benchmark measure the time to compute all possible Wigner 3j symbols up to\na fixed maximal angular momentum; clearing up any cached values from previous\nangular momentum before starting the loop. In pseudo code, the benchmark looks\nlike this:\n\n```\nif cached_wigner_3j:\n    clear_wigner_3j_cache()\n\n# only measure the time taken by the loop\nstart = time.now()\nfor j1 in range(max_angular):\n    for j2 in range(max_angular):\n        for j3 in range(max_angular):\n            for m1 in range(-j1, j1 + 1):\n                for m2 in range(-j2, j2 + 1):\n                    for m3 in range(-j3, j3 + 1):\n                        w3j = wigner_3j(j1, j2, j3, m1, m2, m3)\n\nelapsed = start - time.now()\n```\n\nHere are the results on an Apple M1 Max (10 cores) CPU:\n\n| angular momentum | wigners (this) | wigner-symbols v0.5 | WignerSymbols.jl v2.0 | wigxjpf v1.11 | sympy v1.11 |\n|------------------|----------------|---------------------|-----------------------|---------------|-------------|\n| 4                | 0.190 ms       | 7.50 ms             | 2.58 ms               | 0.228 ms      | 28.7 ms     |\n| 8                | 4.46 ms        | 227 ms              | 47.0 ms               | 7.36 ms       | 1.36 s      |\n| 12               | 34.0 ms        | 1.94 s              | 434 ms                | 66.2 ms       | 23.1 s      |\n| 16               | 156 ms         | 9.34 s              | 1.98 s                | 333 ms        |    /        |\n| 20               | 531 ms         |   /                 | 6.35 s                | 1.21 s        |    /        |\n\n\nA second set of benchmarks checks computing Wigner symbols for large `j`, with the\ncorresponding `m` varying from -10 to 10, i.e. in pseudo code:\n\n```\nif cached_wigner_3j:\n    clear_wigner_3j_cache()\n\n# only measure the time taken by the loop\nstart = time.now()\nfor m1 in range(-10, 10 + 1):\n    for m2 in range(-10, 10 + 1):\n        for m3 in range(-10, 10 + 1):\n            w3j = wigner_3j(j1, j2, j3, m1, m2, m3)\n\nelapsed = start - time.now()\n```\n\n\n| (j1, j2, j3)     | wigners (this) | wigner-symbols v0.5 | WignerSymbols.jl v2.0 | wigxjpf v1.11 | sympy v1.11 |\n|------------------|----------------|---------------------|-----------------------|---------------|-------------|\n| (300, 100, 250)  | 38.7 ms        | 16.5 ms             | 32.9 ms               | 7.60 ms       | 2.31 s      |\n\nTo run the benchmarks yourself on your own machine, execute the following commands:\n\n```bash\ncd benchmarks\ncargo bench # this gives the results for wigners, wigner-symbols and wigxjpf\n\npython sympy-bench.py # this gives the results for sympy\n\njulia wigner-symbol.jl # this gives the results for WignerSymbols.jl\n```\n\n## Comparison to `wigner-symbols`\n\nThere is another Rust implementation of wigner symbols: the\n[wigner-symbols](https://github.com/Rufflewind/wigner-symbols-rs) crate.\n`wigner-symbols` also implements 6j and 9j symbols, but it was not usable for my\ncase since it relies on [rug](https://crates.io/crates/rug) for arbitrary\nprecision integers and through it on the [GMP](https://gmplib.org/) library. The\nGMP library might be problematic for you for one of these reason:\n- it is relatively slow (see the benchmarks above)\n- it is distributed under LGPL (this crate is distributed under Apache/MIT);\n- it is written in C and C++; and as such is hard to cross-compile or compile to WASM;\n- it does not support the MSVC compiler on windows, only the GNU compilers\n\nAs you can see in the benchmarks above, this usage of GMP becomes an advantage\nfor large j, where the algorithm used in this crate does not scale as well.\n\n## License\n\nThis crate is distributed under both the MIT license and the Apache 2.0 license.\n\n\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Compute Wigner 3j and Clebsch-Gordan coefficients",
    "version": "0.3.0",
    "split_keywords": [
        "clebsch-gordan",
        "wigner"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c0a52f1246c48e24bb665c10d4a8c6f725ae918ee1efad093c32983ec86aa635",
                "md5": "cb628f232ba93467cd27e90ee482a130",
                "sha256": "ada27eb7a79ab0c96e73f37656eadfbb20206452cd6007f545383ecb778bc9f0"
            },
            "downloads": -1,
            "filename": "wigners-0.3.0-py3-none-macosx_10_9_x86_64.whl",
            "has_sig": false,
            "md5_digest": "cb628f232ba93467cd27e90ee482a130",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 287641,
            "upload_time": "2023-03-28T08:45:31",
            "upload_time_iso_8601": "2023-03-28T08:45:31.695358Z",
            "url": "https://files.pythonhosted.org/packages/c0/a5/2f1246c48e24bb665c10d4a8c6f725ae918ee1efad093c32983ec86aa635/wigners-0.3.0-py3-none-macosx_10_9_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "bcf80bd16263fe8453bc925e02587f62f0f2c52dc36a1452675c2387f367a7fd",
                "md5": "6d63498a1f0e9e45443a9da4f6cf165b",
                "sha256": "54277157d1048dcef4417302217cfc2234ad77eee288fc1324cbf52dc4190672"
            },
            "downloads": -1,
            "filename": "wigners-0.3.0-py3-none-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "6d63498a1f0e9e45443a9da4f6cf165b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 283985,
            "upload_time": "2023-03-28T08:45:33",
            "upload_time_iso_8601": "2023-03-28T08:45:33.626454Z",
            "url": "https://files.pythonhosted.org/packages/bc/f8/0bd16263fe8453bc925e02587f62f0f2c52dc36a1452675c2387f367a7fd/wigners-0.3.0-py3-none-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "0dab4b44de1b6f5e6a9a6173df9175c062ce193c41c2ab816c225ed6ca0ef76a",
                "md5": "1551d1dfdc9154cda9fc57c85a1371a2",
                "sha256": "f37d9b2a9486f6ccf79c47c86c643273f21ab32124832b62dc3852d513fca202"
            },
            "downloads": -1,
            "filename": "wigners-0.3.0-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
            "has_sig": false,
            "md5_digest": "1551d1dfdc9154cda9fc57c85a1371a2",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 1051658,
            "upload_time": "2023-03-28T08:45:35",
            "upload_time_iso_8601": "2023-03-28T08:45:35.659393Z",
            "url": "https://files.pythonhosted.org/packages/0d/ab/4b44de1b6f5e6a9a6173df9175c062ce193c41c2ab816c225ed6ca0ef76a/wigners-0.3.0-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9b337b9546266a37c64c4638d49c0d77642b3e48639fb52c27463101b096b263",
                "md5": "967ad7a301e5bb9479aac9a3c3873dd0",
                "sha256": "cdfa809d4e7689f9660868bd42721c9f3d5de0a95c447f145c30d196a6a14020"
            },
            "downloads": -1,
            "filename": "wigners-0.3.0-py3-none-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "967ad7a301e5bb9479aac9a3c3873dd0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 169924,
            "upload_time": "2023-03-28T08:45:37",
            "upload_time_iso_8601": "2023-03-28T08:45:37.574961Z",
            "url": "https://files.pythonhosted.org/packages/9b/33/7b9546266a37c64c4638d49c0d77642b3e48639fb52c27463101b096b263/wigners-0.3.0-py3-none-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "09b38c067d2440abd9c4aa4f9f91a46a8eaffc1e5a33d97ae8cafbe84756e437",
                "md5": "d90fdb1a9aa703f5d206a5c60f7f43cb",
                "sha256": "7345d332cad7370283f073879abbe8764d1de1aafb65ec63e8c3a6dbf754caa3"
            },
            "downloads": -1,
            "filename": "wigners-0.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "d90fdb1a9aa703f5d206a5c60f7f43cb",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 23167,
            "upload_time": "2023-03-28T08:45:39",
            "upload_time_iso_8601": "2023-03-28T08:45:39.210302Z",
            "url": "https://files.pythonhosted.org/packages/09/b3/8c067d2440abd9c4aa4f9f91a46a8eaffc1e5a33d97ae8cafbe84756e437/wigners-0.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-03-28 08:45:39",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "Luthaf",
    "github_project": "wigners",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "wigners"
}
        
Elapsed time: 0.05125s