Full Code of lanl/scico for AI

main 010a7714678a cached
335 files
1.8 MB
529.2k tokens
1832 symbols
1 requests
Download .txt
Showing preview only (1,962K chars total). Download the full file or copy to clipboard to get everything.
Repository: lanl/scico
Branch: main
Commit: 010a7714678a
Files: 335
Total size: 1.8 MB

Directory structure:
gitextract_aiioi9sl/

├── .coveragerc
├── .flake8
├── .github/
│   ├── codecov.yml
│   ├── isbin.sh
│   └── workflows/
│       ├── check_files.yml
│       ├── lint.yml
│       ├── mypy.yml
│       ├── pypi_upload.yml
│       ├── pytest_latest.yml
│       ├── pytest_macos.yml
│       ├── pytest_ubuntu.yml
│       └── test_examples.yml
├── .gitignore
├── .gitmodules
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── CHANGES.rst
├── LICENSE
├── MANIFEST.in
├── README.md
├── conftest.py
├── dev_requirements.txt
├── docs/
│   ├── Makefile
│   ├── docs_requirements.txt
│   ├── rtd_requirements.txt
│   ├── source/
│   │   ├── _static/
│   │   │   └── scico.css
│   │   ├── _templates/
│   │   │   ├── autosummary/
│   │   │   │   └── module.rst
│   │   │   ├── package.rst
│   │   │   └── sidebar/
│   │   │       └── brand.html
│   │   ├── advantages.rst
│   │   ├── api.rst
│   │   ├── classes.rst
│   │   ├── conf/
│   │   │   ├── 10-project.py
│   │   │   ├── 15-theme.py
│   │   │   ├── 20-extensions.py
│   │   │   ├── 25-napoleon.py
│   │   │   ├── 30-autodoc.py
│   │   │   ├── 40-intersphinx.py
│   │   │   ├── 45-mathjax.py
│   │   │   ├── 50-graphviz.py
│   │   │   ├── 55-nbsphinx.py
│   │   │   ├── 60-rtd.py
│   │   │   ├── 70-latex.py
│   │   │   ├── 71-texinfo.py
│   │   │   ├── 72-man_page.py
│   │   │   ├── 80-scico_numpy.py
│   │   │   ├── 81-scico_scipy.py
│   │   │   └── 85-dtype_typehints.py
│   │   ├── conf.py
│   │   ├── contributing.rst
│   │   ├── docsutil.py
│   │   ├── examples.rst
│   │   ├── include/
│   │   │   ├── blockarray.rst
│   │   │   ├── examplenotes.rst
│   │   │   ├── functional.rst
│   │   │   ├── learning.rst
│   │   │   ├── operator.rst
│   │   │   └── optimizer.rst
│   │   ├── index.rst
│   │   ├── install.rst
│   │   ├── inverse.rst
│   │   ├── notes.rst
│   │   ├── overview.rst
│   │   ├── pyfigures/
│   │   │   ├── cylindgrad.py
│   │   │   ├── polargrad.py
│   │   │   ├── spheregrad.py
│   │   │   ├── xray_2d_geom.py
│   │   │   ├── xray_3d_ang.py
│   │   │   ├── xray_3d_vec.py
│   │   │   └── xray_3d_vol.py
│   │   ├── references.bib
│   │   ├── style.rst
│   │   ├── team.rst
│   │   └── zreferences.rst
│   └── tikxfigures/
│       ├── img_align.tex
│       ├── makesvg.sh
│       ├── vol_align_xyz.tex
│       ├── vol_align_xz.tex
│       └── vol_align_yz.tex
├── examples/
│   ├── README.rst
│   ├── examples_requirements.txt
│   ├── jnb.py
│   ├── makeindex.py
│   ├── makenotebooks.py
│   ├── notebooks_requirements.txt
│   ├── removejnberr.py
│   ├── scriptcheck.sh
│   ├── scripts/
│   │   ├── README.rst
│   │   ├── ct_abel_tv_admm.py
│   │   ├── ct_abel_tv_admm_tune.py
│   │   ├── ct_astra_3d_tv_admm.py
│   │   ├── ct_astra_3d_tv_padmm.py
│   │   ├── ct_astra_noreg_pcg.py
│   │   ├── ct_astra_tv_admm.py
│   │   ├── ct_astra_weighted_tv_admm.py
│   │   ├── ct_datagen_foam2.py
│   │   ├── ct_fan_svmbir_ppp_bm3d_admm_prox.py
│   │   ├── ct_modl_train_foam2.py
│   │   ├── ct_multi_tv_admm.py
│   │   ├── ct_odp_train_foam2.py
│   │   ├── ct_projector_comparison_2d.py
│   │   ├── ct_projector_comparison_3d.py
│   │   ├── ct_svmbir_ppp_bm3d_admm_cg.py
│   │   ├── ct_svmbir_ppp_bm3d_admm_prox.py
│   │   ├── ct_svmbir_tv_multi.py
│   │   ├── ct_symcone_tv_padmm.py
│   │   ├── ct_tv_admm.py
│   │   ├── ct_unet_train_foam2.py
│   │   ├── deconv_circ_tv_admm.py
│   │   ├── deconv_datagen_bsds.py
│   │   ├── deconv_datagen_foam1.py
│   │   ├── deconv_microscopy_allchn_tv_admm.py
│   │   ├── deconv_microscopy_tv_admm.py
│   │   ├── deconv_modl_train_foam1.py
│   │   ├── deconv_odp_train_foam1.py
│   │   ├── deconv_ppp_bm3d_admm.py
│   │   ├── deconv_ppp_bm3d_apgm.py
│   │   ├── deconv_ppp_bm4d_admm.py
│   │   ├── deconv_ppp_dncnn_admm.py
│   │   ├── deconv_ppp_dncnn_padmm.py
│   │   ├── deconv_tv_admm.py
│   │   ├── deconv_tv_admm_tune.py
│   │   ├── deconv_tv_padmm.py
│   │   ├── demosaic_ppp_bm3d_admm.py
│   │   ├── denoise_approx_tv_multi.py
│   │   ├── denoise_cplx_tv_nlpadmm.py
│   │   ├── denoise_cplx_tv_pdhg.py
│   │   ├── denoise_datagen_bsds.py
│   │   ├── denoise_dncnn_train_bsds.py
│   │   ├── denoise_dncnn_universal.py
│   │   ├── denoise_l1tv_admm.py
│   │   ├── denoise_ptv_pdhg.py
│   │   ├── denoise_tv_admm.py
│   │   ├── denoise_tv_apgm.py
│   │   ├── denoise_tv_multi.py
│   │   ├── diffusercam_tv_admm.py
│   │   ├── index.rst
│   │   ├── sparsecode_apgm.py
│   │   ├── sparsecode_conv_admm.py
│   │   ├── sparsecode_conv_md_admm.py
│   │   ├── sparsecode_nn_admm.py
│   │   ├── sparsecode_nn_apgm.py
│   │   ├── sparsecode_poisson_apgm.py
│   │   ├── superres_ppp_dncnn_admm.py
│   │   ├── trace_example.py
│   │   └── video_rpca_admm.py
│   ├── updatejnbcode.py
│   └── updatejnbmd.py
├── misc/
│   ├── README.rst
│   ├── conda/
│   │   ├── README.rst
│   │   ├── install_conda.sh
│   │   └── make_conda_env.sh
│   ├── gpu/
│   │   ├── README.rst
│   │   ├── availgpu.py
│   │   └── envinfo.py
│   └── pytest/
│       ├── README.rst
│       ├── pytest_cov.sh
│       ├── pytest_fast.sh
│       └── pytest_time.sh
├── pyproject.toml
├── pytest.ini
├── requirements.txt
├── scico/
│   ├── __init__.py
│   ├── _core.py
│   ├── _version.py
│   ├── data/
│   │   └── __init__.py
│   ├── denoiser.py
│   ├── diagnostics.py
│   ├── examples.py
│   ├── flax/
│   │   ├── __init__.py
│   │   ├── _flax.py
│   │   ├── _models.py
│   │   ├── blocks.py
│   │   ├── examples/
│   │   │   ├── __init__.py
│   │   │   ├── data_generation.py
│   │   │   ├── data_preprocessing.py
│   │   │   ├── examples.py
│   │   │   └── typed_dict.py
│   │   ├── inverse.py
│   │   └── train/
│   │       ├── __init__.py
│   │       ├── apply.py
│   │       ├── checkpoints.py
│   │       ├── clu_utils.py
│   │       ├── diagnostics.py
│   │       ├── input_pipeline.py
│   │       ├── learning_rate.py
│   │       ├── losses.py
│   │       ├── spectral.py
│   │       ├── state.py
│   │       ├── steps.py
│   │       ├── trainer.py
│   │       ├── traversals.py
│   │       └── typed_dict.py
│   ├── function.py
│   ├── functional/
│   │   ├── __init__.py
│   │   ├── _denoiser.py
│   │   ├── _dist.py
│   │   ├── _functional.py
│   │   ├── _indicator.py
│   │   ├── _norm.py
│   │   ├── _proxavg.py
│   │   └── _tvnorm.py
│   ├── linop/
│   │   ├── __init__.py
│   │   ├── _circconv.py
│   │   ├── _convolve.py
│   │   ├── _dft.py
│   │   ├── _diag.py
│   │   ├── _diff.py
│   │   ├── _func.py
│   │   ├── _grad.py
│   │   ├── _linop.py
│   │   ├── _matrix.py
│   │   ├── _stack.py
│   │   ├── _util.py
│   │   ├── optics.py
│   │   └── xray/
│   │       ├── __init__.py
│   │       ├── _axitom/
│   │       │   ├── LICENSE
│   │       │   ├── README.md
│   │       │   ├── backprojection.py
│   │       │   ├── config.py
│   │       │   ├── filtering.py
│   │       │   ├── projection.py
│   │       │   └── utilities.py
│   │       ├── _util.py
│   │       ├── _xray.py
│   │       ├── abel.py
│   │       ├── astra.py
│   │       ├── svmbir.py
│   │       └── symcone.py
│   ├── loss.py
│   ├── metric.py
│   ├── numpy/
│   │   ├── __init__.py
│   │   ├── _blockarray.py
│   │   ├── _wrapped_function_lists.py
│   │   ├── _wrappers.py
│   │   ├── fft.py
│   │   ├── linalg.py
│   │   ├── testing.py
│   │   └── util.py
│   ├── operator/
│   │   ├── __init__.py
│   │   ├── _func.py
│   │   ├── _operator.py
│   │   ├── _stack.py
│   │   └── biconvolve.py
│   ├── optimize/
│   │   ├── __init__.py
│   │   ├── _admm.py
│   │   ├── _admmaux.py
│   │   ├── _common.py
│   │   ├── _ladmm.py
│   │   ├── _padmm.py
│   │   ├── _pgm.py
│   │   ├── _pgmaux.py
│   │   ├── _primaldual.py
│   │   ├── admm.py
│   │   └── pgm.py
│   ├── plot.py
│   ├── random.py
│   ├── ray/
│   │   ├── __init__.py
│   │   └── tune.py
│   ├── scipy/
│   │   ├── __init__.py
│   │   └── special.py
│   ├── solver.py
│   ├── test/
│   │   ├── conftest.py
│   │   ├── flax/
│   │   │   ├── test_apply.py
│   │   │   ├── test_checkpoints.py
│   │   │   ├── test_clu.py
│   │   │   ├── test_examples_flax.py
│   │   │   ├── test_flax.py
│   │   │   ├── test_inv.py
│   │   │   ├── test_spectral.py
│   │   │   ├── test_steps.py
│   │   │   ├── test_train_aux.py
│   │   │   ├── test_trainer.py
│   │   │   └── test_traversal.py
│   │   ├── functional/
│   │   │   ├── prox.py
│   │   │   ├── test_composed.py
│   │   │   ├── test_denoiser_func.py
│   │   │   ├── test_funcional_core.py
│   │   │   ├── test_indicator.py
│   │   │   ├── test_loss.py
│   │   │   ├── test_misc.py
│   │   │   ├── test_norm.py
│   │   │   ├── test_proxavg.py
│   │   │   ├── test_separable.py
│   │   │   └── test_tvnorm.py
│   │   ├── linop/
│   │   │   ├── test_binop.py
│   │   │   ├── test_circconv.py
│   │   │   ├── test_conversions.py
│   │   │   ├── test_convolve.py
│   │   │   ├── test_dft.py
│   │   │   ├── test_diag.py
│   │   │   ├── test_diff.py
│   │   │   ├── test_func.py
│   │   │   ├── test_grad.py
│   │   │   ├── test_linop.py
│   │   │   ├── test_linop_stack.py
│   │   │   ├── test_linop_util.py
│   │   │   ├── test_matrix.py
│   │   │   ├── test_optics.py
│   │   │   └── xray/
│   │   │       ├── test_abel.py
│   │   │       ├── test_astra.py
│   │   │       ├── test_svmbir.py
│   │   │       ├── test_symcone.py
│   │   │       ├── test_xray_2d.py
│   │   │       ├── test_xray_3d.py
│   │   │       └── test_xray_util.py
│   │   ├── numpy/
│   │   │   ├── test_blockarray.py
│   │   │   ├── test_numpy.py
│   │   │   └── test_numpy_util.py
│   │   ├── operator/
│   │   │   ├── test_biconvolve.py
│   │   │   ├── test_op_stack.py
│   │   │   └── test_operator.py
│   │   ├── optimize/
│   │   │   ├── test_admm.py
│   │   │   ├── test_ladmm.py
│   │   │   ├── test_padmm.py
│   │   │   ├── test_pdhg.py
│   │   │   └── test_pgm.py
│   │   ├── osver.py
│   │   ├── test_core.py
│   │   ├── test_data.py
│   │   ├── test_denoiser.py
│   │   ├── test_diagnostics.py
│   │   ├── test_examples.py
│   │   ├── test_function.py
│   │   ├── test_metric.py
│   │   ├── test_random.py
│   │   ├── test_ray_tune.py
│   │   ├── test_scipy_special.py
│   │   ├── test_solver.py
│   │   ├── test_util.py
│   │   └── test_version.py
│   ├── trace.py
│   ├── typing.py
│   └── util.py
└── setup.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .coveragerc
================================================
[run]
source = scico
command_line = -m pytest
omit =
    scico/test/*
    scico/plot.py
    scico/trace.py
    scico/linop/xray/_axitom/*.py

[report]
# Regexes for lines to exclude from consideration
exclude_lines =
    # Have to re-enable the standard pragma
    pragma: no cover
    def __repr__


================================================
FILE: .flake8
================================================
[flake8]
max-line-length = 100
ignore =
#E731: do not assign a lambda expression, use a def
  E731


================================================
FILE: .github/codecov.yml
================================================
coverage:
  precision: 2
  round: nearest
  range: "80...100"

  status:
    project:
      default:
        target: auto
        threshold: 0.05%
    patch: false


================================================
FILE: .github/isbin.sh
================================================
#! /bin/bash

# Determine whether files are acceptable for commit into main scico repo

size_threshold=65536

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
OS=$(uname -a | cut -d ' ' -f 1)

for f in $@; do
    echo $f
    case "$OS" in
        Linux)  size=$(stat --format "%s" $f);;
        Darwin) size=$(stat -f "%z" $f);;
        *)      echo "Error: unsupported operating system $OS" >&2; exit 1;;
    esac
    # Exception on maximum size for pytest-split .test_durations file
    if [ $size -gt $size_threshold ] && [ "$(basename $f)" != ".test_durations" ]; then
        echo "file exceeds maximum allowable size of $size_threshold bytes"
        echo "raw data and ipynb files should go in scico-data"
        exit 2
    fi
    charset=$(file -b --mime $f | sed -e 's/.*charset=//')
    if [ ! -L "$f" ] && [ "$charset" = "binary" ]; then
        echo "binary files cannot be commited to the repository"
        echo "raw data and ipynb files should go in scico-data"
        exit 3
    fi
    basename=$(basename -- "$f")
    ext="${basename##*.}"
    if [ "$ext" = "ipynb" ]; then
        echo "ipynb files cannot be commited to the repository"
        echo "raw data and ipynb files should go in scico-data"
        exit 4
    fi
done

IFS=$SAVEIFS

exit 0


================================================
FILE: .github/workflows/check_files.yml
================================================
# Check file types and sizes

name: check files

on: [push, pull_request]

jobs:
  checkfiles:
    runs-on: ubuntu-latest
    steps:
    - name: checkout
      uses: actions/checkout@v5
    - id: files
      uses: Ana06/get-changed-files@v2.3.0
      continue-on-error: true
    - run: |
       for f in ${{ steps.files.outputs.added }}; do
           ${GITHUB_WORKSPACE}/.github/./isbin.sh $f
       done


================================================
FILE: .github/workflows/lint.yml
================================================
# Run isort and black on pushes to main and any pull requests

name: lint

on:
    push:
        branches:
          - main
    pull_request:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - name: Black code formatter
        uses: psf/black@stable
        with:
          version: ">=24.3.0"
      - name: Isort import sorter
        uses: isort/isort-action@v1
      - name: Pylint code analysis
        run: |
          pip install pylint
          pylint --disable=all --enable=missing-docstring,broad-exception-raised scico


================================================
FILE: .github/workflows/mypy.yml
================================================
# Install and run mypy

name: mypy

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

  workflow_dispatch:

jobs:
  mypy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          submodules: recursive
      - name: Install Python 3
        uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - name: Install dependencies
        run: |
          pip install mypy
      - name: Run mypy
        run: |
          mypy --follow-imports=skip --ignore-missing-imports  --exclude "(numpy|test)" scico/ scico/numpy/util.py


================================================
FILE: .github/workflows/pypi_upload.yml
================================================
# When a tag is pushed, build packages and upload to PyPI

name: pypi upload

# Trigger when tags are pushed
on:
  push:
    tags:
      - '*'

  workflow_dispatch:

jobs:
  build-and-upload:
    name: Upload package to PyPI
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          submodules: recursive
      - name: Install Python 3
        uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          sudo apt-get install -y libopenblas-dev
          pip install -r requirements.txt
          pip install -r dev_requirements.txt
          pip install wheel
          python setup.py sdist bdist_wheel
      - name: Upload package to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          user: __token__
          password: ${{ secrets.PYPI_API_TOKEN }}
          verbose: true


================================================
FILE: .github/workflows/pytest_latest.yml
================================================
# Install scico requirements and run pytest with latest jax version

name: unit tests (latest jax)

# Controls when the workflow will run
on:
  # Run workflow every Sunday at midnight UTC
  schedule:
    - cron: "0 0 * * 0"

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  pytest-latest-jax:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          submodules: recursive
      - name: Install Python 3
        uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - name: Install lastversion
        run: |
          python -m pip install --upgrade pip
          pip install lastversion
      - name: Install dependencies
        run: |
          rjaxlib=$(grep jaxlib requirements.txt | sed -e 's/jaxlib.*<=\([0-9\.]*$\)/\1/')
          rjax=$(grep -E "jax[^lib]" requirements.txt | sed -e 's/jax.*<=\([0-9\.]*$\)/\1/')
          ljaxlib=$(lastversion --at pip jaxlib)
          ljax=$(lastversion --at pip jax)
          echo jaxlib  required: $rjaxlib  latest: $ljaxlib
          echo jax     required: $rjax  latest: $ljax
          if [ "$rjaxlib" = "$ljaxlib" ] && [ "$rjax" = "$ljax" ]; then
            echo Test is redundant: required and latest jaxlib/jax versions match
            echo "TEST=cancel" >> $GITHUB_ENV
          else
            echo "TEST=run" >> $GITHUB_ENV
            sudo apt-get install -y libopenblas-dev
            pip install -r requirements.txt
            pip install -r dev_requirements.txt
            pip install -e .
            pip install --upgrade "jax[cpu]"
          fi
      - name: Run tests with pytest
        run: |
          TEST="${{ env.TEST }}"
          if [ "$TEST" = "run" ]; then
            pytest
          else
            exit 0
          fi


================================================
FILE: .github/workflows/pytest_macos.yml
================================================
# Install scico requirements and run pytest

name: unit tests (macos)

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

  workflow_dispatch:

jobs:

  test:
    runs-on: macos-latest
    strategy:
      fail-fast: false
      matrix:
        group: [1, 2, 3, 4, 5]
    name: pytest split ${{ matrix.group }} (macos)
    defaults:
      run:
        shell: bash -l {0}
    steps:
      # Check-out the repository under $GITHUB_WORKSPACE
      - uses: actions/checkout@v5
        with:
          submodules: recursive
      # Set up conda environment
      - name: Set up miniconda
        uses: conda-incubator/setup-miniconda@v3
        with:
            miniforge-version: latest
            activate-environment: test-env
            python-version: "3.12"
      # Configure conda environment cache
      - name: Set up conda environment cache
        uses: actions/cache@v4
        with:
          path: ${{ env.CONDA }}/envs
          key: conda-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('dev_requirements.txt') }}-${{ env.CACHE_NUMBER }}
        env:
          CACHE_NUMBER: 0  # Increase this value to force cache reset
        id: cache
      # Display environment details
      - name: Display environment details
        run: |
          conda info
          printenv | sort
      # Install dependencies in conda environment
      - name: Install dependencies
        if: steps.cache.outputs.cache-hit != 'true'
        run: |
          conda install -c conda-forge pytest pytest-cov
          python -m pip install --upgrade pip
          pip install pytest-split
          pip install -r requirements.txt
          pip install -r dev_requirements.txt
          pip install "bm3d>=4.0.0"
          pip install "bm4d>=4.0.0"
          pip install "ray[tune]>=2.44"
          pip install hyperopt
          pip install "setuptools<82.0.0"  # workaround for hyperopt 0.2.7
          pip install pydantic
          pip install "orbax-checkpoint>=0.5.0"
          #conda install -c conda-forge "svmbir>=0.4.0"
          conda install -c astra-toolbox astra-toolbox
          conda install -c conda-forge pyyaml
      # Install package to be tested
      - name: Install package to be tested
        run: pip install -e .
      # Run unit tests
      - name: Run main unit tests
        run: |
          DURATIONS_FILE=$(mktemp)
          bzcat data/pytest/durations_macos.bz2 > $DURATIONS_FILE
          pytest -x --level=1 --durations-path=$DURATIONS_FILE --splits=5 --group=${{ matrix.group }} --pyargs scico


================================================
FILE: .github/workflows/pytest_ubuntu.yml
================================================
# Install scico requirements and run pytest

name: unit tests (ubuntu)

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

  workflow_dispatch:
    inputs:
      debug_enabled:
        type: boolean
        description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
        required: false
        default: false
jobs:

  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        group: [1, 2, 3, 4, 5]
    name: pytest split ${{ matrix.group }} (ubuntu)
    defaults:
      run:
        shell: bash -l {0}
    steps:
      # Check-out the repository under $GITHUB_WORKSPACE
      - uses: actions/checkout@v5
        with:
          submodules: recursive
      # Set up conda environment
      - name: Set up miniconda
        uses: conda-incubator/setup-miniconda@v3
        with:
            miniforge-version: latest
            activate-environment: test-env
            python-version: "3.12"
      # Configure conda environment cache
      - name: Set up conda environment cache
        uses: actions/cache@v4
        with:
          path: ${{ env.CONDA }}/envs
          key: conda-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('dev_requirements.txt') }}-${{ env.CACHE_NUMBER }}
        env:
          CACHE_NUMBER: 0  # Increase this value to force cache reset
        id: cache
      # Display environment details
      - name: Display environment details
        run: |
          conda info
          printenv | sort
      # Install required system package
      - name: Install required system package
        run: sudo apt-get install -y libopenblas-dev
      # Install dependencies in conda environment
      - name: Install dependencies
        if: steps.cache.outputs.cache-hit != 'true'
        run: |
          conda install -c conda-forge pytest pytest-cov
          python -m pip install --upgrade pip
          pip install pytest-split
          pip install -r requirements.txt
          pip install -r dev_requirements.txt
          pip install "bm4d>=4.2.2"
          pip install "bm3d>=4.0.0"
          pip install "ray[tune]>=2.44"
          pip install hyperopt
          pip install "setuptools<82.0.0"  # workaround for hyperopt 0.2.7
          pip install pydantic
          pip install "orbax-checkpoint>=0.5.0"
          conda install -c conda-forge "svmbir>=0.4.0"
          conda install -c conda-forge astra-toolbox
          conda install -c conda-forge pyyaml
      # Install package to be tested
      - name: Install package to be tested
        run: pip install -e .
      # Enable tmate debugging of manually-triggered workflows if the input option was provided
      - name: Setup tmate session
        uses: mxschmitt/action-tmate@v3
        if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
      # Run unit tests
      - name: Run main unit tests
        run: |
          DURATIONS_FILE=$(mktemp)
          bzcat data/pytest/durations_ubuntu.bz2 > $DURATIONS_FILE
          pytest -x --cov --level=2 --durations-path=$DURATIONS_FILE --splits=5 --group=${{ matrix.group }} --pyargs scico
      # Upload coverage data
      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          include-hidden-files: true
          name: coverage${{ matrix.group }}
          path: ${{ github.workspace }}/.coverage
      # Run doc tests
      - name: Run doc tests
        if: matrix.group == 1
        run: |
          pytest --ignore-glob="*test_*.py" --ignore=scico/linop/xray --doctest-modules scico
          pytest --doctest-glob="*.rst" docs

  coverage:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Set up Python 3.12
        uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - name: Install deps
        run: |
          python -m pip install --upgrade pip
          pip install coverage
      - name: Download all artifacts
        # Downloads coverage1, coverage2, etc.
        uses: actions/download-artifact@v4
      - name: Run coverage
        run: |
          coverage combine coverage?/.coverage
          coverage report
          coverage xml
      - uses: codecov/codecov-action@v4
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
        with:
          env_vars: OS,PYTHON
          fail_ci_if_error: false
          files: coverage.xml
          flags: unittests
          name: codecov-umbrella
          verbose: true


================================================
FILE: .github/workflows/test_examples.yml
================================================
# Install scico requirements and run short versions of example scripts

name: test examples

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

  # Allow this workflow to be run manually from the Actions tab
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
    name: test examples (ubuntu)
    defaults:
      run:
        shell: bash -l {0}
    steps:
      # Check-out the repository under $GITHUB_WORKSPACE
      - uses: actions/checkout@v5
        with:
          submodules: recursive
      # Set up conda environment
      - name: Set up miniconda
        uses: conda-incubator/setup-miniconda@v3
        with:
            miniforge-version: latest
            activate-environment: test-env
            python-version: "3.12"
      # Configure conda environment cache
      - name: Set up conda environment cache
        uses: actions/cache@v4
        with:
          path: ${{ env.CONDA }}/envs
          key: conda-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('dev_requirements.txt') }}-${{ hashFiles('examples/examples_requirements.txt') }}-${{ env.CACHE_NUMBER }}
        env:
          CACHE_NUMBER: 0  # Increase this value to force cache reset
        id: cache
      # Display environment details
      - name: Display environment details
        run: |
          conda info
          printenv | sort
      # Install required system package
      - name: Install required system package
        run: sudo apt-get install -y libopenblas-dev
      # Install dependencies in conda environment
      - name: Install dependencies
        if: steps.cache.outputs.cache-hit != 'true'
        run: |
          conda install -c conda-forge pytest pytest-cov
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install -r dev_requirements.txt
          conda install -c conda-forge astra-toolbox
          conda install -c conda-forge pyyaml
          pip install --upgrade --force-reinstall scipy>=1.6.0  # Temporary fix for GLIBCXX_3.4.30 not found in conda forge version
          pip install -r examples/examples_requirements.txt
      # Install package to be tested
      - name: Install package to be tested
        run: pip install -e .
      # Run example test
      - name: Run example test
        run: |
          ${GITHUB_WORKSPACE}/examples/scriptcheck.sh -e -d -t -g


================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Editor backups
.*~

# Docs generation
docs/source/_autosummary/
docs/source/examples/

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
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/

# 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
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.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

# VS Code settings
.vscode/

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# macos files
*.DS_Store


================================================
FILE: .gitmodules
================================================
[submodule "data"]
	path = data
	url = https://github.com/lanl/scico-data.git


================================================
FILE: .pre-commit-config.yaml
================================================
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v2.3.0
    hooks:
    -   id: end-of-file-fixer
    -   id: trailing-whitespace
-   repo: local
    hooks:
    - id: check-for-binary
      name: check for binary/ipynb files
      entry: .github/isbin.sh
      language: script
      pass_filenames: true
    - id: autoflake
      name: autoflake
      entry: autoflake
      language: python
      language_version:  python3
      types: [python]
      args: ['-i', '--remove-all-unused-imports',  '--ignore-init-module-imports']
    - id: isort
      name: isort (python)
      entry: isort
      language: python
      language_version:  python3
      types: [python]
    - id: isort
      name: isort (cython)
      entry: isort
      language: python
      language_version:  python3
      types: [cython]
    - id: black
      name: black
      entry: black
      description: 'Black: The uncompromising Python code formatter'
      language: python
      language_version:  python3
      types: [python]
    - id: pylint
      name: pylint
      entry: pylint
      language: python
      language_version: python3
      types: [python]
      exclude: ^(scico/test/|examples|docs)
      args: ['--score=n', '--disable=all', '--enable=missing-docstring,broad-exception-raised']


================================================
FILE: .readthedocs.yaml
================================================
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Get submodules
submodules:
  include: all
  recursive: true

# Set the version of Python and other tools you might need
build:
  os: ubuntu-24.04
  tools:
    python: "3.12"
  jobs:
    pre_build:
      - mkdir -p docs/source/examples
      - |
        for f in data/notebooks/*; do
          b=$(basename $f)
          if [ ! -f "docs/source/examples/$b" ]; then
            ln -s -t docs/source/examples "../../../$f"
          fi
        done
    post_build:  # unclear why this is necessary
      - cp docs/source/_static/scico.css  _readthedocs/html/_static
  apt_packages:
    - graphviz
    - libopenblas-dev

# Build documentation in the docs/ directory with Sphinx
sphinx:
   builder: html
   configuration: docs/source/conf.py
   fail_on_warning: false

# Declare the Python requirements required to build your docs
python:
   install:
   - requirements: docs/docs_requirements.txt
   - requirements: docs/rtd_requirements.txt


================================================
FILE: CHANGES.rst
================================================
===================
SCICO Release Notes
===================

Version 0.0.8   (unreleased)
----------------------------
• Enable certain parameters of array creation functions to trigger
 ``BlockArray`` creation when they receive lists (currently ``device``).
• New functional ``functional.BoxIndicator``.
• Support ``jaxlib`` and ``jax`` versions 0.5.0 to 0.10.0.
• Support ``flax`` versions 0.8.0 to 0.12.7.
• Various bug fixes and minor improvements.



Version 0.0.7   (2025-12-09)
----------------------------

• New module ``scico.trace`` for tracing function/method calls.
• New generic functional ``functional.ComposedFunctional`` representing
  a functional composed with an orthogonal linear operator.
• New optimizer methods ``save_state`` and ``load_state`` supporting
  algorithm state checkpointing.
• New classes for creating a volume from an image by symmetry, and
  for cone beam X-ray transform of a cylindrically symmetric object
  in module ``linop.xray.symcone``.
• New utility functions for CT reconstruction preprocessing added in
  module ``linop.xray``.
• Moved ``linop.abel`` module to ``linop.xray.abel``.
• Make ``orbax-checkpoint`` dependency optional due to absence of recent
  conda-forge packages.
• Support ``jaxlib`` and ``jax`` versions 0.5.0 to 0.8.1.
• Support ``flax`` versions 0.8.0 to 0.12.0.



Version 0.0.6   (2024-10-25)
----------------------------

• Significant changes to ``linop.xray.astra`` API.
• Rename integrated 2D X-ray transform class to
  ``linop.xray.XRayTransform2D`` and add filtered back projection method
  ``fbp``.
• New integrated 3D X-ray transform via ``linop.xray.XRayTransform3D``.
• New functional ``functional.IsotropicTVNorm`` and faster implementation
  of ``functional.AnisotropicTVNorm``.
• New linear operators ``linop.ProjectedGradient``, ``linop.PolarGradient``,
  ``linop.CylindricalGradient``, and ``linop.SphericalGradient``.
• Rename ``scico.numpy.util.parse_axes`` to
  ``scico.numpy.util.normalize_axes``.
• Rename ``scico.flax.save_weights`` and ``scico.flax.load_weights`` to
  ``scico.flax.save_variables`` and ``scico.flax.load_variables``
  respectively.
• Support ``jaxlib`` and ``jax`` versions 0.4.13 to 0.4.35.
• Support ``flax`` versions 0.8.0 to 0.10.0.



Version 0.0.5   (2023-12-18)
----------------------------

• New functionals ``functional.AnisotropicTVNorm`` and
  ``functional.ProximalAverage`` with proximal operator approximations.
• New integrated Radon/X-ray transform ``linop.XRayTransform``.
• New operators ``operator.DiagonalStack`` and ``operator.VerticalStack``.
• Rename modules ``radon_astra`` and ``radon_svmbir`` to ``xray.astra`` and
  ``xray.svmbir`` respectively, and rename ``TomographicProjector`` classes
  to ``XRayTransform``.
• Rename ``AbelProjector`` to ``AbelTransform``.
• Rename ``solver.ATADSolver`` to ``solver.MatrixATADSolver``.
• Rename some ``__init__`` parameters of ``linop.DiagonalStack`` and
  ``linop.VerticalStack``.
• Support ``jaxlib`` and ``jax`` versions 0.4.3 to 0.4.23.
• Support ``flax`` versions up to 0.7.5.
• Use ``orbax`` for checkpointing ``flax`` models.



Version 0.0.4   (2023-08-03)
----------------------------

• Add new ``Function`` class for representing array-to-array mappings with
  more than one input.
• Add new methods and a function for computing Jacobian-vector products for
  ``Operator`` objects.
• Add new proximal ADMM solvers.
• Add new ADMM subproblem solvers for problems involving a sum-of-convolutions
  operator.
• Extend support for other ML models including UNet, ODP and MoDL.
• Add functionality for training Flax-based ML models and for data generation.
• Enable diagnostics for ML training loops.
• Support ``jaxlib`` and ``jax`` versions 0.4.3 to 0.4.14.
• Change required packages and version numbers, including more recent version
  for ``flax``.
• Drop support for Python 3.7.
• Add support for 3D tomographic projection with the ASTRA Toolbox.



Version 0.0.3   (2022-09-21)
----------------------------

• Change required packages and version numbers, including more recent version
  requirements for ``numpy``, ``scipy``, ``svmbir``, and ``ray``.
• Package ``bm4d`` removed from main requirements list due to issue #342.
• Support ``jaxlib`` versions 0.3.0 to 0.3.15 and ``jax`` versions
  0.3.0 to 0.3.17.
• Rename linear operators in ``radon_astra`` and ``radon_svmbir`` modules
  to ``TomographicProjector``.
• Add support for fan beam CT in ``radon_svmbir`` module.
• Add function ``linop.linop_from_function`` for constructing linear
  operators from functions.
• Enable addition operator for functionals.
• Completely new implementation of ``BlockArray`` class.
• Additional solvers in ``scico.solver``.
• New Huber norm (``HuberNorm``) and set distance functionals (``SetDistance``
  and ``SquaredSetDistance``).
• New loss functions ``loss.SquaredL2AbsLoss`` and
  ``loss.SquaredL2SquaredAbsLoss`` for phase retrieval problems.
• Add interface to BM4D denoiser.
• Change interfaces of ``linop.FiniteDifference`` and ``linop.DFT``.
• Change filenames of some example scripts (and corresponding notebooks).
• Add support for Python 3.7.
• New ``DiagonalStack`` linear operator.
• Add support for non-linear operators to ``optimize.PDHG`` optimizer class.
• Various bug fixes.



Version 0.0.2   (2022-02-14)
----------------------------

• Additional optimization algorithms: Linearized ADMM and PDHG.
• Additional Abel transform and array slicing linear operators.
• Additional nuclear norm functional.
• New module ``scico.ray.tune`` providing a simplified interface to Ray Tune.
• Move optimization algorithms into ``optimize`` subpackage.
• Additional iteration stats columns for iterative ADMM subproblem solvers.
• Renamed "Primal Rsdl" to "Prml Rsdl" in displayed iteration stats.
• Move some functions from ``util`` and ``math`` modules to new ``array``
  module.
• Bump pinned ``jaxlib`` and ``jax`` versions to 0.3.0.


Version 0.0.1   (2021-11-24)
----------------------------

• Initial release.


================================================
FILE: LICENSE
================================================
BSD 3-Clause License

Copyright (c) 2021-2025, Los Alamos National Laboratory
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: MANIFEST.in
================================================
include MANIFEST.in
include README.md
include CHANGES.rst
include LICENSE
include setup.py
include conftest.py
include pyproject.toml
include pytest.ini
include requirements.txt
include dev_requirements.txt
include docs/docs_requirements.txt

recursive-include scico *.py
recursive-include scico/data *.png *.mpk *.rst
recursive-include docs Makefile *.py *.ipynb *.rst *.bib *.css *.svg *.png *.ico
recursive-include examples *_requirements.txt *.txt *.rst *.py *.sh
recursive-include misc *.py *.sh *.rst


================================================
FILE: README.md
================================================
[![Python \>= 3.8](https://img.shields.io/badge/python-3.8+-green.svg)](https://www.python.org/)
[![Package License](https://img.shields.io/github/license/lanl/scico.svg)](https://github.com/lanl/scico/blob/main/LICENSE)
[![Code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Documentation Status](https://readthedocs.org/projects/scico/badge/?version=latest)](http://scico.readthedocs.io/en/latest/?badge=latest)
[![JOSS paper](https://joss.theoj.org/papers/10.21105/joss.04722/status.svg)](https://doi.org/10.21105/joss.04722)\
[![Lint status](https://github.com/lanl/scico/actions/workflows/lint.yml/badge.svg)](https://github.com/lanl/scico/actions/workflows/lint.yml)
[![Test status](https://github.com/lanl/scico/actions/workflows/pytest_ubuntu.yml/badge.svg)](https://github.com/lanl/scico/actions/workflows/pytest_ubuntu.yml)
[![Test coverage](https://codecov.io/gh/lanl/scico/branch/main/graph/badge.svg?token=wQimmjnzFf)](https://codecov.io/gh/lanl/scico)
[![CodeFactor](https://www.codefactor.io/repository/github/lanl/scico/badge/main)](https://www.codefactor.io/repository/github/lanl/scico/overview/main)\
[![PyPI package version](https://badge.fury.io/py/scico.svg)](https://badge.fury.io/py/scico)
[![PyPI download statistics](https://static.pepy.tech/personalized-badge/scico?period=total&left_color=grey&right_color=brightgreen&left_text=downloads)](https://pepy.tech/project/scico)
[![Conda Forge Release](https://img.shields.io/conda/vn/conda-forge/scico.svg)](https://anaconda.org/conda-forge/scico)
[![Conda Forge Downloads](https://img.shields.io/conda/dn/conda-forge/scico.svg)](https://anaconda.org/conda-forge/scico)\
[![View notebooks at nbviewer](https://raw.githubusercontent.com/jupyter/design/master/logos/Badges/nbviewer_badge.svg)](https://nbviewer.jupyter.org/github/lanl/scico-data/tree/main/notebooks/index.ipynb)
[![Run notebooks on binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/lanl/scico-data/binder?labpath=notebooks%2Findex.ipynb)
[![Run notebooks on google colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lanl/scico-data/blob/colab/notebooks/index.ipynb)


# Scientific Computational Imaging Code (SCICO)

SCICO is a Python package for solving the inverse problems that arise in
scientific imaging applications. Its primary focus is providing methods
for solving ill-posed inverse problems by using an appropriate prior
model of the reconstruction space. SCICO includes a growing suite of
operators, cost functionals, regularizers, and optimization routines
that may be combined to solve a wide range of problems, and is designed
so that it is easy to add new building blocks. SCICO is built on top of
[JAX](https://github.com/google/jax), which provides features such as
automatic gradient calculation and GPU acceleration.

[Documentation](https://scico.rtfd.io/) is available online. If you use
this software for published work, please cite the corresponding [JOSS
Paper](https://doi.org/10.21105/joss.04722) (see bibtex entry
`balke-2022-scico` in `docs/source/references.bib`).


# Installation

The online documentation includes detailed
[installation instructions](https://scico.rtfd.io/en/latest/install.html).


# Usage Examples

Usage examples are available as Python scripts and Jupyter Notebooks.
Example scripts are located in `examples/scripts`. The corresponding
Jupyter Notebooks are provided in the
[scico-data](https://github.com/lanl/scico-data) submodule and symlinked
to `examples/notebooks`. They are also viewable on
[GitHub](https://github.com/lanl/scico-data/tree/main/notebooks) or
[nbviewer](https://nbviewer.jupyter.org/github/lanl/scico-data/tree/main/notebooks/index.ipynb),
and can be run online on
[binder](https://mybinder.org/v2/gh/lanl/scico-data/binder?labpath=notebooks%2Findex.ipynb)
or
[google colab](https://colab.research.google.com/github/lanl/scico-data/blob/colab/notebooks/index.ipynb).


# License

SCICO is distributed as open-source software under a BSD 3-Clause
License (see the `LICENSE` file for details).

LANL open source approval reference C20091.

\(c\) 2020-2026. Triad National Security, LLC. All rights reserved. This
program was produced under U.S. Government contract 89233218CNA000001
for Los Alamos National Laboratory (LANL), which is operated by Triad
National Security, LLC for the U.S. Department of Energy/National
Nuclear Security Administration. All rights in the program are reserved
by Triad National Security, LLC, and the U.S. Department of
Energy/National Nuclear Security Administration. The Government has
granted for itself and others acting on its behalf a nonexclusive,
paid-up, irrevocable worldwide license in this material to reproduce,
prepare derivative works, distribute copies to the public, perform
publicly and display publicly, and to permit others to do so.


================================================
FILE: conftest.py
================================================
"""
Configure pytest.
"""

import os

import numpy as np

import pytest

os.environ["RAY_ACCEL_ENV_VAR_OVERRIDE_ON_ZERO"] = "0"  # suppress ray warning
try:
    import ray  # noqa: F401
except ImportError:
    have_ray = False
else:
    have_ray = True
    ray.init(num_cpus=1)  # call required to be here: see ray-project/ray#44087

import jax.numpy as jnp

import scico.numpy as snp


def pytest_sessionstart(session):
    """Initialize before start of test session."""
    # placeholder: currently unused


def pytest_sessionfinish(session, exitstatus):
    """Clean up after end of test session."""
    if have_ray:
        ray.shutdown()


@pytest.fixture(autouse=True)
def add_modules(doctest_namespace):
    """Add common modules for use in docstring examples.

    Necessary because `np` is used in doc strings for jax functions
    (e.g. `linear_transpose`) that get pulled into `scico/__init__.py`.
    Also allow `snp` and `jnp` to be used without explicitly importing.
    """
    doctest_namespace["np"] = np
    doctest_namespace["snp"] = snp
    doctest_namespace["jnp"] = jnp


================================================
FILE: dev_requirements.txt
================================================
-r requirements.txt
pylint
pytest>=7.3.0
pytest-split
packaging
pre-commit
black>=24.3.0
isort
autoflake


================================================
FILE: docs/Makefile
================================================
# 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
SOURCEDIR	= source
BUILDDIR	= ../build/sphinx

.PHONY: help clean Makefile


# Put this first so that "make" without argument is like "make help".
help:
	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

clean:
	rm -rf $(BUILDDIR)/*
	rm -f $(SOURCEDIR)/_autosummary/*
	rm -f $(SOURCEDIR)/examples/*

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
	@mkdir -p source/examples; \
	for f in ../data/notebooks/*; do \
	  b=$$(basename $$f) ; \
	  if [ ! -f "source/examples/$$b" ]; then \
	      echo Creating soft link for notebook $$b ; \
	      ln -s -t source/examples "../../$$f" ; \
	  fi \
	done
	$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)


================================================
FILE: docs/docs_requirements.txt
================================================
-r ../requirements.txt
sphinx>=5.0.0
sphinxcontrib-napoleon
sphinxcontrib-bibtex
sphinx-autodoc-typehints
furo>=2024.5.6
jinja2<3.1.0  # temporary fix for jinja2/nbconvert bug
traitlets!=5.2.2  # temporary fix for ipython/traitlets#741
nbsphinx
ipython
ipython_genutils
py2jn
pygraphviz>=1.9
pandoc
docutils>=0.18


================================================
FILE: docs/rtd_requirements.txt
================================================
# nbconvert>=7.5 requires a version of pandoc that is not available
#   in the readthedocs build environment
nbconvert<7.5


================================================
FILE: docs/source/_static/scico.css
================================================
/* furo theme customization */

body[data-theme="dark"] figure img {
  filter: invert(100%);
}

.sidebar-drawer {
  width: fit-content !important;
}

.main > .content {
  min-width: 75%;
  width: fit-content !important;
  max-width: 80em;
}

.highlight {
  background: #e9efff;
}

.sidebar-brand-text {
  font-size: 1.0rem !important;
  text-align: center;
  padding-top: 0.5em;
}


/* Code display section */

div.doctest.highlight-default {
  background-color: #f9f9f4;
}


/* Style for autosummary API docs */

[data-theme=light] dl.field-list.simple {
  background-color: #f5f5f5;
  border-radius: 4px;
}

[data-theme=light] dl.field-list.simple > dt.field-odd {
  background-color: #f2f2f2;
  border-radius: 4px;
}

[data-theme=light] dl.field-list.simple > dt.field-even {
  background-color: #f2f2f2;
  border-radius: 4px;
}

[data-theme=light] dl.py.data {
  background-color: #fdfafa;
  border-radius: 4px;
}

[data-theme=light] dl.py.data > dt {
  border-radius: 4px;
}

[data-theme=light] dl.py.attribute {
  background-color: #fdfafa;
  border-radius: 4px;
}

[data-theme=light] dl.py.attribute > dt {
  border-radius: 4px;
}

[data-theme=light] dl.py.function {
  background-color: #fdfafa;
  border-radius: 4px;
}

[data-theme=light] dl.py.function > dt {
  border-radius: 4px;
}

[data-theme=light] dl.py.function blockquote {
  background-color: #f5f5f5;
  border-left: 0px;
}

[data-theme=light] dl.py.class {
  background-color: #fdfafa;
  border-radius: 4px;
}

[data-theme=light] dl.py.class > dt {
  border-radius: 4px;
}

[data-theme=light] dl.py.method {
  background-color: #f6f6f6;
  border-radius: 4px;
}

[data-theme=light] dl.py.method > dt {
  border-radius: 4px;
}

[data-theme=light] dl.py.property {
  background-color: #f6f6f6;
  border-radius: 4px;
}

[data-theme=light] dl.py.property > dt {
  border-radius: 4px;
}


/* Style for figure captions */

div.figure p.caption span.caption-text,
figcaption span.caption-text {
  font-size: var(--font-size--small);
  margin-left: 5%;
  margin-right: 5%;
  display: inline-block;
  text-align: justify;
}


================================================
FILE: docs/source/_templates/autosummary/module.rst
================================================
{{ fullname | escape | underline}}

.. automodule:: {{ fullname }}

   {% block attributes %}
   {% if attributes %}
   .. rubric:: {{ _('Module Attributes') }}

   .. autosummary::
   {% for item in attributes %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}


   {% block modules %}
   {% if modules %}
   .. rubric:: Modules

   .. autosummary::
      :toctree:
      :recursive:
   {% for item in modules %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}


   {% block functions %}
   {% if functions %}
   .. rubric:: {{ _('Functions') }}

   .. autosummary::
   {% for item in functions %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block classes %}
   {% if classes %}
   .. rubric:: {{ _('Classes') }}

   .. autosummary::
   {% for item in classes %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block exceptions %}
   {% if exceptions %}
   .. rubric:: {{ _('Exceptions') }}

   .. autosummary::
   {% for item in exceptions %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}


================================================
FILE: docs/source/_templates/package.rst
================================================
API Reference
=============

.. automodule:: {{ fullname }}

   {% block modules %}
   {% if modules %}
   .. autosummary::
     :toctree:
     :recursive:
   {% for item in modules %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}


================================================
FILE: docs/source/_templates/sidebar/brand.html
================================================
{#-

Hi there!

You might be interested in https://pradyunsg.me/furo/customisation/sidebar/

Although if you're reading this, chances are that you're either familiar
enough with Sphinx that you know what you're doing, or landed here from that
documentation page.

Hope your day's going well. :)

-#}
<a class="sidebar-brand{% if logo %} centered{% endif %}" href="{{ pathto(master_doc) }}">
  {% block brand_content %}
  {%- if logo_url %}
  <div class="sidebar-logo-container">
    <img class="sidebar-logo" src="{{ logo_url }}" alt="Logo"/>
  </div>
  {%- endif %}
  {%- if theme_light_logo and theme_dark_logo %}
  <div class="sidebar-logo-container">
    <img class="sidebar-logo only-light" src="{{ pathto('_static/' + theme_light_logo, 1) }}" alt="Light Logo"/>
    <img class="sidebar-logo only-dark" src="{{ pathto('_static/' + theme_dark_logo, 1) }}" alt="Dark Logo"/>
  </div>
  {%- endif %}
  {% if not theme_sidebar_hide_name %}
  <span class="sidebar-brand-text">{{ version }}</span>
  {%- endif %}
  {% endblock brand_content %}
</a>


================================================
FILE: docs/source/advantages.rst
================================================
Why SCICO?
==========

Advantages of JAX-based Design
------------------------------

The vast majority of scientific computing packages in Python are based
on `NumPy <https://numpy.org/>`__ and `SciPy <https://scipy.org/>`__.
SCICO, in contrast, is based on `JAX
<https://jax.readthedocs.io/en/latest/>`__, which provides most of the
same features, but with the addition of automatic differentiation, GPU
support, and just-in-time (JIT) compilation. (The availability of
these features in SCICO is subject to some :ref:`caveats
<non_jax_dep>`.) SCICO users and developers are advised to become
familiar with the `differences between JAX and
NumPy. <https://jax.readthedocs.io/en/latest/notebooks/thinking_in_jax.html>`_.

While recent advances in automatic differentiation have primarily been
driven by its important role in deep learning, it is also invaluable in
a functional minimization framework such as SCICO. The most obvious
advantage is allowing the use of gradient-based minimization methods
without the need for tedious mathematical derivation of an expression
for the gradient. Equally valuable, though, is the ability to
automatically compute the adjoint operator of a linear operator, the
manual derivation of which is often time-consuming.

GPU support and JIT compilation both offer the potential for significant
code acceleration, with the speed gains that can be obtained depending
on the algorithm/function to be executed. In many cases, a speed
improvement by an order of magnitude or more can be obtained by running
the same code on a GPU rather than a CPU, and similar speed gains can
sometimes also be obtained via JIT compilation.

The figure below shows timing results obtained on a compute server
with an Intel Xeon Gold 6230 CPU and NVIDIA GeForce RTX 2080 Ti
GPU. It is interesting to note that for :class:`.FiniteDifference` the
GPU provides no acceleration, while JIT provides more than an order of
magnitude of speed improvement on both CPU and GPU. For :class:`.DFT`
and :class:`.Convolve`, significant JIT acceleration is limited to the
GPU, which also provides significant acceleration over the CPU.


.. image:: /figures/jax-timing.png
     :align: center
     :width: 95%
     :alt: Timing results for SCICO operators on CPU and GPU with and without JIT


Related Packages
----------------

Many elements of SCICO are partially available in other packages. We
briefly review them here, highlighting some of the main differences with
SCICO.

`GlobalBioIm <https://biomedical-imaging-group.github.io/GlobalBioIm/>`__
is similar in structure to SCICO (and a major inspiration for SCICO),
providing linear operators and solvers for inverse problems in imaging.
However, it is written in MATLAB and is thus not usable in a completely
free environment. It also lacks the automatic adjoint calculation and
simple GPU support offered by SCICO.

`PyLops <https://pylops.readthedocs.io>`__ provides a linear operator
class and many built-in linear operators. These operators are compatible
with many `SciPy <https://scipy.org/>`__ solvers. GPU support is
provided via `CuPy <https://cupy.dev>`__, which has the disadvantage
that switching for a CPU to GPU requires code changes, unlike SCICO and
`JAX <https://jax.readthedocs.io/en/latest/>`__. SCICO is more focused
on computational imaging that PyLops and has several specialized
operators that PyLops does not.

`Pycsou <https://matthieumeo.github.io/pycsou/html/index>`__, like
SCICO, is a Python project inspired by GlobalBioIm. Since it is based on
PyLops, it shares the disadvantages with respect to SCICO of that
project.

`ODL <https://odlgroup.github.io/odl/>`__ provides a variety of
operators and related infrastructure for prototyping of inverse
problems. It is built on top of
`NumPy <https://numpy.org/>`__/`SciPy <https://scipy.org/>`__, and does
not support any of the advanced features of
`JAX <https://jax.readthedocs.io/en/latest/>`__.

`ProxImaL <http://www.proximal-lang.org/en/latest/>`__ is a Python
package for image optimization problems. Like SCICO and many of the
other projects listed here, problems are specified by combining objects
representing, operators, functionals, and solvers. It does not support
any of the advanced features of
`JAX <https://jax.readthedocs.io/en/latest/>`__.

`ProxMin <https://github.com/pmelchior/proxmin>`__ provides a set of
proximal optimization algorithms for minimizing non-smooth functionals.
It is built on top of
`NumPy <https://numpy.org/>`__/`SciPy <https://scipy.org/>`__, and does
not support any of the advanced features of
`JAX <https://jax.readthedocs.io/en/latest/>`__ (however, an open issue
suggests that `JAX <https://jax.readthedocs.io/en/latest/>`__
compatibility is planned).

`CVXPY <https://www.cvxpy.org>`__ provides a flexible language for
defining optimization problems and a wide selection of solvers, but has
limited support for matrix-free methods.

Other related projects that may be of interest include:

-  `ToMoBAR <https://github.com/dkazanc/ToMoBAR>`__
-  `CCPi-Regularisation Toolkit <https://github.com/vais-ral/CCPi-Regularisation-Toolkit>`__
-  `SPORCO <https://github.com/lanl/sporco>`__
-  `SigPy <https://github.com/mikgroup/sigpy>`__
-  `MIRT <https://github.com/JeffFessler/MIRT.jl>`__
-  `BART <http://mrirecon.github.io/bart/>`__


================================================
FILE: docs/source/api.rst
================================================
:orphan:

API Documentation
=================

.. autosummary::
   :toctree: _autosummary
   :template: package.rst
   :caption: API Reference
   :recursive:

   scico


================================================
FILE: docs/source/classes.rst
================================================
.. _classes:

******************
Main SCICO Classes
******************

.. include:: include/blockarray.rst
.. include:: include/operator.rst
.. include:: include/functional.rst
.. include:: include/optimizer.rst
.. include:: include/learning.rst


================================================
FILE: docs/source/conf/10-project.py
================================================
from scico._version import package_version

# General information about the project.
project = "SCICO"
copyright = "2020-2026, SCICO Developers"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = package_version()
# The full version, including alpha/beta/rc tags.
release = version


================================================
FILE: docs/source/conf/15-theme.py
================================================
# -- Options for HTML output ----------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
# html_theme = "python_docs_theme"
html_theme = "furo"

html_theme_options = {
    "top_of_page_buttons": [],
    # "sidebar_hide_name": True,
}

if html_theme == "python_docs_theme":
    html_sidebars = {
        "**": ["globaltoc.html", "sourcelink.html", "searchbox.html"],
    }

# These folders are copied to the documentation's HTML output
html_static_path = ["_static"]

# These paths are either relative to html_static_path or fully qualified
# paths (eg. https://...)
html_css_files = [
    "scico.css",
    "http://netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css",
]

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = "_static/logo.svg"

# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = "_static/scico.ico"


================================================
FILE: docs/source/conf/20-extensions.py
================================================
# 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.napoleon",
    "sphinx.ext.autodoc",
    "sphinx_autodoc_typehints",
    "sphinx.ext.autosummary",
    "sphinx.ext.doctest",
    "sphinx.ext.intersphinx",
    "sphinx.ext.viewcode",
    "sphinxcontrib.bibtex",
    "sphinx.ext.inheritance_diagram",
    "matplotlib.sphinxext.plot_directive",
    "sphinx.ext.todo",
    "nbsphinx",
]


bibtex_bibfiles = ["references.bib"]


================================================
FILE: docs/source/conf/25-napoleon.py
================================================
from sphinx.ext.napoleon.docstring import GoogleDocstring


## See
##   https://github.com/sphinx-doc/sphinx/issues/2115
##   https://michaelgoerz.net/notes/extending-sphinx-napoleon-docstring-sections.html
##
# first, we define new methods for any new sections and add them to the class
def parse_keys_section(self, section):
    return self._format_fields("Keys", self._consume_fields())


GoogleDocstring._parse_keys_section = parse_keys_section


def parse_attributes_section(self, section):
    return self._format_fields("Attributes", self._consume_fields())


GoogleDocstring._parse_attributes_section = parse_attributes_section


def parse_class_attributes_section(self, section):
    return self._format_fields("Class Attributes", self._consume_fields())


GoogleDocstring._parse_class_attributes_section = parse_class_attributes_section


# we now patch the parse method to guarantee that the the above methods are
# assigned to the _section dict
def patched_parse(self):
    self._sections["keys"] = self._parse_keys_section
    self._sections["class attributes"] = self._parse_class_attributes_section
    self._unpatched_parse()


GoogleDocstring._unpatched_parse = GoogleDocstring._parse
GoogleDocstring._parse = patched_parse


# napoleon_include_init_with_doc = True
napoleon_use_ivar = True
napoleon_use_rtype = False

# See https://github.com/sphinx-doc/sphinx/issues/9119
# napoleon_custom_sections = [("Returns", "params_style")]


================================================
FILE: docs/source/conf/30-autodoc.py
================================================
autodoc_default_options = {
    "member-order": "bysource",
    "inherited-members": False,
    "ignore-module-all": False,
    "show-inheritance": True,
    "members": True,
    "special-members": "__call__",
}
autodoc_docstring_signature = True
autoclass_content = "both"


# See https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_mock_imports
autodoc_mock_imports = ["astra", "svmbir", "ray"]


# See
#  https://stackoverflow.com/questions/2701998#62613202
#  https://github.com/JamesALeedham/Sphinx-Autosummary-Recursion
autosummary_generate = True


# See https://stackoverflow.com/questions/5599254
autoclass_content = "both"


================================================
FILE: docs/source/conf/40-intersphinx.py
================================================
# Intersphinx mapping
intersphinx_mapping = {
    "python": ("https://docs.python.org/3/", None),
    "numpy": ("https://numpy.org/doc/stable/", None),
    "scipy": ("https://docs.scipy.org/doc/scipy/", None),
    "matplotlib": ("https://matplotlib.org/stable/", None),
    "jax": ("https://docs.jax.dev/en/latest/", None),
    "flax": ("https://flax.readthedocs.io/en/latest/", None),
    "ray": ("https://docs.ray.io/en/latest/", None),
    "svmbir": ("https://svmbir.readthedocs.io/en/latest/", None),
}
# Added timeout due to periodic scipy.org down time
# intersphinx_timeout = 30


================================================
FILE: docs/source/conf/45-mathjax.py
================================================
import os

if os.environ.get("NO_MATHJAX"):
    extensions.append("sphinx.ext.imgmath")
    imgmath_image_format = "svg"
else:
    extensions.append("sphinx.ext.mathjax")
    # To use local copy of MathJax for offline use, set MATHJAX_URI to
    #    file:///[path-to-mathjax-repo-root]/es5/tex-mml-chtml.js
    if os.environ.get("MATHJAX_URI"):
        mathjax_path = os.environ.get("MATHJAX_URI")

mathjax3_config = {
    "tex": {
        "macros": {
            "mb": [r"\mathbf{#1}", 1],
            "mbs": [r"\boldsymbol{#1}", 1],
            "mbb": [r"\mathbb{#1}", 1],
            "norm": [r"\lVert #1 \rVert", 1],
            "abs": [r"\left| #1 \right|", 1],
            "argmin": [r"\mathop{\mathrm{argmin}}"],
            "sign": [r"\mathop{\mathrm{sign}}"],
            "prox": [r"\mathrm{prox}"],
            "det": [r"\mathrm{det}"],
            "exp": [r"\mathrm{exp}"],
            "loss": [r"\mathop{\mathrm{loss}}"],
            "kp": [r"k_{\|}"],
            "rp": [r"r_{\|}"],
        }
    }
}


================================================
FILE: docs/source/conf/50-graphviz.py
================================================
graphviz_output_format = "svg"
inheritance_graph_attrs = dict(rankdir="LR", fontsize=9, ratio="compress", bgcolor="transparent")
inheritance_edge_attrs = dict(
    color='"#2962ffff"',
)
inheritance_node_attrs = dict(
    shape="box",
    fontsize=9,
    height=0.4,
    margin='"0.08, 0.03"',
    style='"rounded,filled"',
    color='"#2962ffff"',
    fontcolor='"#2962ffff"',
    fillcolor='"#f0f0f8b0"',
)


================================================
FILE: docs/source/conf/55-nbsphinx.py
================================================
nbsphinx_prolog = """
.. raw:: html

    <style>
    .nbinput .prompt, .nboutput .prompt {
        display: none;
    }
    div.highlight {
        background-color: #f9f9f4;
    }
    p {
        margin-bottom: 0.8em;
        margin-top: 0.8em;
    }
    </style>
"""

nbsphinx_execute = "never"


================================================
FILE: docs/source/conf/60-rtd.py
================================================
import os

on_rtd = os.environ.get("READTHEDOCS") == "True"


if on_rtd:
    print("Building on ReadTheDocs\n")
    print("  current working directory: {}".format(os.path.abspath(os.curdir)))
    print("  rootpath: %s" % rootpath)
    print("  confpath: %s" % confpath)

    html_static_path = []

    # See https://about.readthedocs.com/blog/2024/07/addons-by-default/#how-to-opt-in-to-addons-now
    html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
    if "html_context" not in globals():
        html_context = {}
    html_context["READTHEDOCS"] = True

    import matplotlib

    matplotlib.use("agg")

else:
    # 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"]


================================================
FILE: docs/source/conf/70-latex.py
================================================
# -- Options for LaTeX output ---------------------------------------------

latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #'papersize': 'letterpaper',
    # The font size ('10pt', '11pt' or '12pt').
    #'pointsize': '10pt',
    # Additional stuff for the LaTeX preamble.
    #'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
    ("index", "scico.tex", "SCICO Documentation", "The SCICO Developers", "manual"),
]

latex_engine = "xelatex"

# latex_use_xindy = False


# mathjax3_config must already be defined
latex_macros = []
for k, v in mathjax3_config["tex"]["macros"].items():
    if len(v) == 1:
        latex_macros.append(r"\newcommand{\%s}{%s}" % (k, v[0]))
    else:
        latex_macros.append(r"\newcommand{\%s}[1]{%s}" % (k, v[0]))

imgmath_latex_preamble = "\n".join(latex_macros)

latex_elements = {"preamble": "\n".join(latex_macros)}


================================================
FILE: docs/source/conf/71-texinfo.py
================================================
# -- Options for Texinfo output -------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    (
        "index",
        "SCICO",
        "SCICO Documentation",
        "SCICO Developers",
        "SCICO",
        "Scientific Computational Imaging COde (SCICO)",
        "Miscellaneous",
    ),
]


================================================
FILE: docs/source/conf/72-man_page.py
================================================
# -- Options for manual page output ---------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [("index", "scico", "SCICO Documentation", ["SCICO Developers"], 1)]

# If true, show URL addresses after external links.
# man_show_urls = False


================================================
FILE: docs/source/conf/80-scico_numpy.py
================================================
import re
from inspect import getmembers, isfunction

# Rewrite module names for certain functions imported into scico.numpy so that they are
# included in the docs for that module. While a bit messy to do so here rather than in a
# function run via app.connect, it is necessary (for some yet to be identified reason)
# to do it here to ensure that the relevant API docs include a table of functions.
import scico.numpy

for module in (scico.numpy, scico.numpy.fft, scico.numpy.linalg, scico.numpy.testing):
    for _, f in getmembers(module, isfunction):
        # Rewrite module name so that function is included in docs
        f.__module__ = module.__name__
        f.__doc__ = re.sub(
            r"^:func:`([\w_]+)` wrapped to operate",
            r":obj:`jax.numpy.\1` wrapped to operate",
            str(f.__doc__),
            flags=re.M,
        )
        modname = ".".join(module.__name__.split(".")[1:])
        f.__doc__ = re.sub(
            r"^LAX-backend implementation of :func:`([\w_]+)`.",
            r"LAX-backend implementation of :obj:`%s.\1`." % modname,
            str(f.__doc__),
            flags=re.M,
        )
        # Improve formatting of jax.numpy warning
        f.__doc__ = re.sub(
            r"^\*\*\* This function is not yet implemented by jax.numpy, and will "
            r"raise NotImplementedError \*\*\*",
            "**WARNING**: This function is not yet implemented by jax.numpy, "
            " and will raise :exc:`NotImplementedError`.",
            f.__doc__,
            flags=re.M,
        )
        # Remove cross-references to section NEP35
        f.__doc__ = re.sub(":ref:`NEP 35 <NEP35>`", "NEP 35", f.__doc__, re.M)
        # Remove cross-reference to numpydoc style references section
        f.__doc__ = re.sub(r" \[(\d+)\]_", "", f.__doc__, flags=re.M)
        # Remove entire numpydoc references section
        f.__doc__ = re.sub(r"References\n----------\n.*\n", "", f.__doc__, flags=re.DOTALL)


# Fix various docstring formatting errors
scico.numpy.testing.break_cycles.__doc__ = re.sub(
    "calling gc.collect$",
    "calling gc.collect.\n\n",
    scico.numpy.testing.break_cycles.__doc__,
    flags=re.M,
)
scico.numpy.testing.break_cycles.__doc__ = re.sub(
    r" __del__\) inside", r"__del__\) inside", scico.numpy.testing.break_cycles.__doc__, flags=re.M
)
scico.numpy.testing.assert_raises_regex.__doc__ = re.sub(
    r"\*args,\n.*\*\*kwargs",
    "*args, **kwargs",
    scico.numpy.testing.assert_raises_regex.__doc__,
    flags=re.M,
)
scico.numpy.BlockArray.global_shards.__doc__ = re.sub(
    r"`Shard`s", r"`Shard`\ s", scico.numpy.BlockArray.global_shards.__doc__, flags=re.M
)


================================================
FILE: docs/source/conf/81-scico_scipy.py
================================================
import re
from inspect import getmembers, isfunction

# Similar processing for scico.scipy
import scico.scipy

ssp_func = getmembers(scico.scipy.special, isfunction)
for _, f in ssp_func:
    if f.__module__[0:11] == "scico.scipy" or f.__module__[0:14] == "jax._src.scipy":
        # Rewrite module name so that function is included in docs
        f.__module__ = "scico.scipy.special"
        # Attempt to fix incorrect cross-reference
        f.__doc__ = re.sub(
            r"^:func:`([\w_]+)` wrapped to operate",
            r":obj:`jax.scipy.special.\1` wrapped to operate",
            str(f.__doc__),
            flags=re.M,
        )
        modname = "scipy.special"
        f.__doc__ = re.sub(
            r"^LAX-backend implementation of :func:`([\w_]+)`.",
            r"LAX-backend implementation of :obj:`%s.\1`." % modname,
            str(f.__doc__),
            flags=re.M,
        )
        # Remove cross-reference to numpydoc style references section
        f.__doc__ = re.sub(r"(^|\ )\[(\d+)\]_", "", f.__doc__, flags=re.M)
        # Remove entire numpydoc references section
        f.__doc__ = re.sub(r"References\n----------\n.*\n", "", f.__doc__, flags=re.DOTALL)
        # Remove problematic citation
        f.__doc__ = re.sub(r"See \[dlmf\]_ for details.", "", f.__doc__, re.M)
        f.__doc__ = re.sub(r"\[dlmf\]_", "NIST DLMF", f.__doc__, re.M)

# Fix indentation problems
if hasattr(scico.scipy.special, "sph_harm"):
    scico.scipy.special.sph_harm.__doc__ = re.sub(
        "^Computes the", "  Computes the", scico.scipy.special.sph_harm.__doc__, flags=re.M
    )


================================================
FILE: docs/source/conf/85-dtype_typehints.py
================================================
from typing import Optional, Sequence, Union  # needed for typehints_formatter hack

from scico.typing import (  # needed for typehints_formatter hack
    ArrayIndex,
    AxisIndex,
    DType,
)


# An explanation for this nasty hack, the primary purpose of which is to avoid
# the very long definition of the scico.typing.DType appearing explicitly in the
# docs. This is handled correctly by sphinx.ext.autodoc in some circumstances,
# but only when sphinx_autodoc_typehints is not included in the extension list,
# and the appearance of the type hints (e.g. whether links to definitions are
# included) seems to depend on whether "from __future__ import annotations" was
# used in the module being documented, which is not ideal from a consistency
# perspective. (It's also worth noting that sphinx.ext.autodoc provides some
# configurability for type aliases via the autodoc_type_aliases sphinx
# configuration option.) The alternative is to include sphinx_autodoc_typehints,
# which gives a consistent appearance to the type hints, but the
# autodoc_type_aliases configuration option is ignored, and type aliases are
# always expanded. This hack avoids expansion for the type aliases with the
# longest definitions by definining a custom function for formatting the
# type hints, using an option provided by sphinx_autodoc_typehints. For
# more information, see
#   https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_type_aliases
#   https://github.com/tox-dev/sphinx-autodoc-typehints/issues/284
#   https://github.com/tox-dev/sphinx-autodoc-typehints/blob/main/README.md
def typehints_formatter_function(annotation, config):
    markup = {
        DType: ":obj:`~scico.typing.DType`",
        # Compound types involving DType must be added here to avoid their DType
        # component being expanded in the docs.
        Optional[DType]: r":obj:`~typing.Optional`\ [\ :obj:`~scico.typing.DType`\ ]",
        Union[DType, Sequence[DType]]: (
            r":obj:`~typing.Union`\ [\ :obj:`~scico.typing.DType`\ , "
            r":obj:`~typing.Sequence`\ [\ :obj:`~scico.typing.DType`\ ]]"
        ),
        AxisIndex: ":obj:`~scico.typing.AxisIndex`",
        ArrayIndex: ":obj:`~scico.typing.ArrayIndex`",
    }
    if annotation in markup:
        return markup[annotation]
    else:
        return None


typehints_formatter = typehints_formatter_function


================================================
FILE: docs/source/conf.py
================================================
# -*- coding: utf-8 -*-

import os
import sys

confpath = os.path.dirname(__file__)
sys.path.append(confpath)
rootpath = os.path.realpath(os.path.join(confpath, "..", ".."))
sys.path.append(rootpath)

from docsutil import insert_inheritance_diagram, package_classes, run_conf_files

# Process settings in files in conf directory
_vardict = run_conf_files(vardict={"confpath": confpath, "rootpath": rootpath})
for _k, _v in _vardict.items():
    globals()[_k] = _v
del _vardict, _k, _v


# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = "5.0.0"

# The suffix of source filenames.
source_suffix = ".rst"

# The encoding of source files.
source_encoding = "utf-8"

# The master toctree document.
master_doc = "index"

# Output file base name for HTML help builder.
htmlhelp_basename = "SCICOdoc"

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build", "**tests**", "**README.rst", "include"]

# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"

# Include TODOs
todo_include_todos = True


def class_inherit_diagrams(_):
    # Insert inheritance diagrams for classes that have base classes
    import scico

    custom_parts = {"scico.ray.tune.Tuner": 4}
    clslst = package_classes(scico)
    for cls in clslst:
        insert_inheritance_diagram(cls, parts=custom_parts)


def process_docstring(app, what, name, obj, options, lines):
    # Don't show docs for inherited members in classes in scico.flax.
    # This is primarily useful for silencing warnings due to problems in
    # the current release of flax, but is arguably also useful in avoiding
    # extensive documentation of methods that are likely to be of limited
    # interest to users of the scico.flax classes.
    #
    # Note: this event handler currently has no effect since inclusion of
    #   inherited members is currently globally disabled (see
    #   "inherited-members" in autodoc_default_options), but is left in
    #   place in case a decision is ever made to revert the global setting.
    #
    # See https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html
    # for documentation of the autodoc-process-docstring event used here.
    if what == "class" and "scico.flax." in name:
        options["inherited-members"] = False


def setup(app):
    app.connect("builder-inited", class_inherit_diagrams)
    app.connect("autodoc-process-docstring", process_docstring)


================================================
FILE: docs/source/contributing.rst
================================================
.. _scico_dev_contributing:

Contributing
============

Contributions to SCICO are welcome. Before starting work, please
contact the maintainers, either via email or the GitHub issue system,
to discuss the relevance of your contribution and the most appropriate
location within the existing package structure.


.. _installing_dev:

Installing a Development Version
--------------------------------

1. Fork both the ``scico`` and ``scico-data`` repositories, creating
   copies of these repositories in your own git account.

2. Make sure that you have Python 3.10 or later installed in order to
   create a conda virtual environment.

3. Clone your fork from the source repo.

   ::

      git clone --recurse-submodules git@github.com:<username>/scico.git

4. Create a conda environment using Python 3.10 or later, e.g.:

   ::

      conda create -n scico python=3.12

5. Activate the created conda virtual environment:

   ::

      conda activate scico

6. Change directory to the root of the cloned repository:

   ::

      cd scico

7. Add the ``scico`` repo as an upstream remote to sync your changes:

   ::

      git remote add upstream https://www.github.com/lanl/scico

8. After adding the upstream, the recommended way to install SCICO and
   its dependencies is via pip:

   ::

      pip install -r requirements.txt  # Installs basic requirements
      pip install -r dev_requirements.txt  # Installs developer requirements
      pip install -r docs/docs_requirements.txt # Installs documentation requirements
      pip install -e .  # Installs SCICO from the current directory in editable mode

   For installing dependencies related to the examples please see :ref:`example_notebooks`.
   Installing these are neccessary for the successfull running of the tests.

9. The SCICO project uses the `black
   <https://black.readthedocs.io/en/stable/>`_, `isort
   <https://pypi.org/project/isort/>`_ and `pylint
   <https://pylint.pycqa.org/en/latest/>`_ code formatting
   utilities. It is important to set up a `pre-commit hook
   <https://pre-commit.com>`_ to ensure that any modified code passes
   format check before it is committed to the development repo:

   ::

      pre-commit install  # Sets up git pre-commit hooks

   It is also recommended to `pin the conda package version
   <https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-pkgs.html#preventing-packages-from-updating-pinning>`__
   of `black <https://black.readthedocs.io/en/stable/>`_ to the version
   number specified in ``dev_requirements.txt``.

10. For testing see `Tests`_.



Building Documentation
----------------------

Before building the documentation, one must install the documentation
specific dependencies by running

::

   pip install -r docs/docs_requirements.txt

Then, a local copy of the documentation can be built from the
respository root directory by running

::

  python setup.py build_sphinx


Alternatively, one can also build the documentation by running the
following from the `docs/` directory

::

   make html



Contributing Code
-----------------

- New features / bugs / documentation are *always* developed in separate branches.
- Branches should be named in the form
  `<username>/<brief-description>`, where `<brief-description>`
  provides a highly condensed description of the purpose of the branch
  (e.g. `address_todo`), and may include an issue number if
  appropriate (e.g. `fix_223`).


A feature development workflow might look like this:


1. Follow the instructions in `Installing a Development Version`_.

2. Sync with the upstream repository:

   ::

      git pull --rebase origin main --recurse-submodules

3. Create a branch to develop from:

   ::

      git checkout -b <username>/<brief-description>

4. Make your desired changes.

5. Run the test suite:

   ::

      pytest

   You can limit the test suite to a specific file for example:

   ::

      pytest scico/test/test_blockarray.py

6. When you are finished making changes, create a new commit:

   ::

      git add file1.py git add file2.py
      git commit -m "A good commit message"

   If you have added or modified an example script, see `Usage Examples`_.
   If your contribution involves any significant new features or changes,
   add a corresponding entry to the change summary for the next release
   in the ``CHANGES.rst`` file.

7. Sync with the upstream repository:

   ::

      git fetch upstream
      git rebase upstream/main

8. Push your development upstream:

   ::

      git push --set-upstream origin <username>/<brief-description>

9. Create a new pull request to the ``main`` branch; see `the GitHub instructions <https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request>`_.

10. The SCICO maintainers will review and merge your PR.
    The SCICO project recommends the ``squash and merge`` option for merging PRs.

11. Delete the branch after it has been merged.


Adding Data
-----------

The following steps show how to add new data, ``new_data.npz``, to the
packaged data. We assume the ``scico`` repository has been cloned to
``scico/``. Note that the data is located in the ``scico-data``
submodule, which is attached to the main `scico` repository via the
directory ``scico/data`` (i.e. the ``data/`` subdirectory of the
repository root directory, *not* the ``scico/data`` subdirectory of
the repository root directory). When adding new data, both the
``scico`` and ``scico-data`` repositories must be updated and kept in
sync.


1. Create new branches in the main ``scico`` repository as well as in
   the submodule corresponding to the ``scico-data`` repository (which
   can be achieved by following the usual branch creation procedure
   after changing the current directory to ``scico/data``).

2. Add the ``new_data.npz`` file to the appropriate subdirectory
   (creating a new one if necessary) of the ``scico/data`` directory.

3. Change directory to this directory (taken to be ``scico/data/flax``
   for the purposes of this example) and add/commit the new data file:

   ::

      cd scico/data/flax
      git add new_data.npz
      git commit -m "Add new data file"

4. Return to the ``scico`` repository root directory, add/commit the
   new data, and update submodule:

   ::

      cd ../..  # pwd now `scico` repo root
      git add data
      git commit -m "Add data and update data module"

5. Push both repositories:

   ::

      git submodule foreach --recursive 'git push' && git push



Type Checking
-------------

All code is required to pass ``mypy`` type checking.

Install ``mypy``:

::

   conda install mypy

To run the type checker, execute the following from the scico repository root:

::

   mypy --follow-imports=skip --ignore-missing-imports  --exclude "(numpy|test)" scico/



Tests
-----

All functions and classes should have corresponding ``pytest`` unit tests.


Running Tests
^^^^^^^^^^^^^


To be able to run the tests, install ``pytest`` and, optionally,
``pytest-runner``:

::

    conda install pytest pytest-runner

The tests can be run by

::

    pytest

or (if ``pytest-runner`` is installed)

::

    python setup.py test

from the ``scico`` repository root directory. Tests can be run in an installed
version of ``scico`` by

::

   pytest --pyargs scico

When any significant changes are made to the test suite, the ``pytest-split`` test
time database files in ``data/pytest`` should be updated using

::

   pytest --store-durations --durations-path data/pytest/durations_ubuntu --level 2

(for Ubuntu CI), and

::

   pytest --store-durations --durations-path data/pytest/durations_macos --level 1

(for MacOS CI). These updated files should be bzipped and committed into the
``scico-data`` repository, replacing the current versions.


Test Coverage
^^^^^^^^^^^^^

Test coverage is a measure of the fraction of the package code that is
exercised by the tests. While this should not be the primary criterion
in designing tests, it is a useful tool for finding obvious areas of
omission.

To be able to check test coverage, install ``coverage``:

::

    conda install coverage

A coverage report can be obtained by

::

    coverage run
    coverage report





Usage Examples
--------------

New usage examples should adhere to the same general structure as the
existing examples to ensure that the mechanism for automatically
generating corresponding Jupyter notebooks functions correctly. In
particular:

1. The initial lines of the script should consist of a comment block,
   followed by a blank line, followed by a multiline string with an
   RST heading on the first line, e.g.,

   ::

     #!/usr/bin/env python
     # -*- coding: utf-8 -*-
     # This file is part of the SCICO package. Details of the copyright
     # and user license can be found in the 'LICENSE.txt' file distributed
     # with the package.

     """
     Script Title
     ============

     Script description.
     """

2. The final line of the script is an ``input`` statement intended to
   avoid the script terminating immediately, thereby closing all
   figures:

   ::

     input("\nWaiting for input to close figures and exit")

3. Citations are included using the standard `Sphinx
   <https://www.sphinx-doc.org/en/master/>`__ ``:cite:`cite-key```
   syntax, where ``cite-key`` is the key of an entry in
   ``docs/source/references.bib``.

4. Cross-references to other components of the documentation are
   included using the syntax described in the `nbsphinx documentation
   <https://nbsphinx.readthedocs.io/en/latest/markdown-cells.html#Links-to-*.rst-Files-(and-Other-Sphinx-Source-Files)>`__.

5. External links are included using Markdown syntax ``[link text](url)``.

6. When constructing a synthetic image/volume for use in the example,
   define a global variable `N` that controls the size of the problem,
   and where relevant, define a global variable `maxiter` that
   controls the number of iterations of optimization algorithms such
   as ADMM. Adhering to this convention allows the
   ``examples/scriptcheck.sh`` utility to automatically construct less
   computationally expensive versions of the example scripts for
   testing that they run without any errors.


Adding new examples
^^^^^^^^^^^^^^^^^^^

The following steps show how to add a new example, ``new_example.py``,
to the packaged usage examples. We assume the ``scico`` repository has
been cloned to ``scico/``.

Note that the ``.py`` scripts are included in
``scico/examples/scripts``, while the compiled Jupyter Notebooks are
located in the scico-data submodule, which is symlinked to
``scico/data``. When adding a new usage example, both the ``scico``
and ``scico-data`` repositories must be updated and kept in sync.

.. warning:: Ensure that all binary data (including raw data, images,
   ``.ipynb`` files) are added to ``scico-data``, not the main
   ``scico`` repo.


1. Create new branches in the main `scico` repository as well as in
   the submodule corresponding to the `scico-data` repository (which
   can be achieved by following the usual branch creation procedure
   after changing the current directory to ``scico/data``).

2. Add the ``new_example.py`` script to the ``scico/examples/scripts`` directory.

3. Add the basename of the script (i.e., without the pathname; in this
   case, ``new_example.py``) to the appropriate section of
   ``examples/scripts/index.rst``.

4. Convert your new example to a Jupyter notebook by changing
   directory to the ``scico/examples`` directory and following the
   instructions in ``scico/examples/README.rst``.

5. Change directory to the ``data`` directory and add/commit the new
   Jupyter Notebook:

   ::

      cd scico/data
      git add notebooks/new_example.ipynb
      git commit -m "Add new usage example"

6. Return to the main ``scico`` repository root directory, ensure the
   ``main`` branch is checked out, add/commit the new script and
   updated submodule:

   ::

      cd ..  # pwd now `scico` repo root
      git add data
      git add examples/scripts/new_filename.py
      git commit -m "Add usage example and update data module"

7. Push both repositories:

   ::

      git submodule foreach --recursive 'git push' && git push


================================================
FILE: docs/source/docsutil.py
================================================
# -*- coding: utf-8 -*-
# Copyright (C) 2021-2023 by SCICO Developers
# All rights reserved. BSD 3-clause License.
# This file is part of the SCICO package. Details of the copyright and
# user license can be found in the 'LICENSE' file distributed with the
# package.


"""Utilities for building docs."""

import importlib
import inspect
import os
import pkgutil
import sys
from glob import glob
from runpy import run_path


def run_conf_files(vardict=None, path=None):
    """Execute Python files in conf directory.

    Args:
        vardict: Dictionary into which variable names should be inserted.
            Defaults to empty dict.
        path: Path to conf directory. Defaults to path to this module.

    Returns:
        A dict populated with variables defined during execution of the
        configuration files.
    """
    if vardict is None:
        vardict = {}
    if path is None:
        path = os.path.dirname(__file__)

    files = os.path.join(path, "conf", "*.py")
    for f in sorted(glob(files)):
        conf = run_path(f, init_globals=vardict)
        for k, v in conf.items():
            if len(k) >= 4 and k[0:2] == "__" and k[-2:] == "__":  # ignore __<name>__ variables
                continue
            vardict[k] = v
    return vardict


def package_classes(package):
    """Get a list of classes in a package.

    Return a list of qualified names of classes in the specified
    package. Classes in modules with names beginning with an "_" are
    omitted, as are classes whose internal module name record is not
    the same as the module in which they are found (i.e. indicating
    that they have been imported from elsewhere).

    Args:
        package: Reference to package for which classes are to be listed
          (not package name string).

    Returns:
        A list of qualified names of classes in the specified package.
    """

    classes = []
    # Iterate over modules in package
    for importer, modname, _ in pkgutil.walk_packages(
        path=package.__path__, prefix=(package.__name__ + "."), onerror=lambda x: None
    ):
        # Skip modules whose names begin with a "_"
        if modname.split(".")[-1][0] == "_":
            continue
        importlib.import_module(modname)
        # Iterate over module members
        for name, obj in inspect.getmembers(sys.modules[modname]):
            if inspect.isclass(obj):
                # Get internal module name of class for comparison with working module name
                try:
                    objmodname = getattr(sys.modules[modname], obj.__name__).__module__
                except Exception:
                    objmodname = None
                if objmodname == modname:
                    classes.append(modname + "." + obj.__name__)

    return classes


def get_text_indentation(text, skiplines=0):
    """Compute the leading whitespace indentation in a block of text.

    Args:
        text: A block of text as a string.

    Returns:
        Indentation length.
    """
    min_indent = len(text)
    lines = text.splitlines()
    if len(lines) > skiplines:
        lines = lines[skiplines:]
    else:
        return None
    for line in lines:
        if len(line) > 0:
            indent = len(line) - len(line.lstrip())
            if indent < min_indent:
                min_indent = indent
    return min_indent


def add_text_indentation(text, indent):
    """Insert leading whitespace into a block of text.

    Args:
        text: A block of text as a string.
        indent: Number of leading spaces to insert on each line.

    Returns:
        Text with additional indentation.
    """
    lines = text.splitlines()
    for n, line in enumerate(lines):
        if len(line) > 0:
            lines[n] = (" " * indent) + line
    return "\n".join(lines)


def insert_inheritance_diagram(clsqname, parts=None, default_nparts=2):
    """Insert an inheritance diagram into a class docstring.

    No action is taken for classes without a base clase, and for classes
    without a docstring.

    Args:
        clsqname: Qualified name (i.e. including module name path) of class.
        parts: A dict mapping qualified class names to custom values for
          the ":parts:" directive.
        default_nparts: Default value for the ":parts:" directive.
    """

    # Extract module name and class name from qualified class name
    clspth = clsqname.split(".")
    modname = ".".join(clspth[0:-1])
    clsname = clspth[-1]
    # Get reference to class
    cls = getattr(sys.modules[modname], clsname)
    # Return immediately if class has no base classes
    if getattr(cls, "__bases__") == (object,):
        return
    # Get current docstring
    docstr = getattr(cls, "__doc__")
    # Return immediately if class has no docstring
    if docstr is None:
        return
    # Use class-specific parts or default parts directive value
    if parts and clsqname in parts:
        nparts = parts[clsqname]
    else:
        nparts = default_nparts
    # Split docstring into individual lines
    lines = docstr.splitlines()
    # Return immediately if there are no lines
    if not lines:
        return
    # Cut leading whitespace lines
    n = 0
    for n, line in enumerate(lines):
        if line != "":
            break
    lines = lines[n:]
    # Define inheritance diagram insertion text
    idstr = f"""

    .. inheritance-diagram:: {clsname}
       :parts: {nparts}


    """
    docstr_indent = get_text_indentation(docstr, skiplines=1)
    if docstr_indent is not None and docstr_indent > 4:
        idstr = add_text_indentation(idstr, docstr_indent - 4)
    # Insert inheritance diagram after summary line and whitespace line following it
    lines.insert(2, idstr)
    # Construct new docstring and attach it to the class
    extdocstr = "\n".join(lines)
    setattr(cls, "__doc__", extdocstr)


================================================
FILE: docs/source/examples.rst
================================================
.. _example_notebooks:

Usage Examples
==============

.. toctree::
   :maxdepth: 1

.. include:: include/examplenotes.rst


Organized by Application
------------------------

.. toctree::
   :maxdepth: 1


Computed Tomography
^^^^^^^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/ct_abel_tv_admm
   examples/ct_abel_tv_admm_tune
   examples/ct_symcone_tv_padmm
   examples/ct_astra_noreg_pcg
   examples/ct_astra_3d_tv_admm
   examples/ct_astra_3d_tv_padmm
   examples/ct_tv_admm
   examples/ct_astra_tv_admm
   examples/ct_multi_tv_admm
   examples/ct_astra_weighted_tv_admm
   examples/ct_svmbir_tv_multi
   examples/ct_svmbir_ppp_bm3d_admm_cg
   examples/ct_svmbir_ppp_bm3d_admm_prox
   examples/ct_fan_svmbir_ppp_bm3d_admm_prox
   examples/ct_modl_train_foam2
   examples/ct_odp_train_foam2
   examples/ct_unet_train_foam2
   examples/ct_projector_comparison_2d
   examples/ct_projector_comparison_3d

Deconvolution
^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/deconv_circ_tv_admm
   examples/deconv_tv_admm
   examples/deconv_tv_padmm
   examples/deconv_tv_admm_tune
   examples/deconv_microscopy_tv_admm
   examples/deconv_microscopy_allchn_tv_admm
   examples/deconv_ppp_bm3d_admm
   examples/deconv_ppp_bm3d_apgm
   examples/deconv_ppp_dncnn_admm
   examples/deconv_ppp_dncnn_padmm
   examples/deconv_ppp_bm4d_admm
   examples/deconv_modl_train_foam1
   examples/deconv_odp_train_foam1


Sparse Coding
^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/sparsecode_nn_admm
   examples/sparsecode_nn_apgm
   examples/sparsecode_conv_admm
   examples/sparsecode_conv_md_admm
   examples/sparsecode_apgm
   examples/sparsecode_poisson_apgm


Miscellaneous
^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/demosaic_ppp_bm3d_admm
   examples/superres_ppp_dncnn_admm
   examples/denoise_l1tv_admm
   examples/denoise_ptv_pdhg
   examples/denoise_tv_admm
   examples/denoise_tv_apgm
   examples/denoise_tv_multi
   examples/denoise_approx_tv_multi
   examples/denoise_cplx_tv_nlpadmm
   examples/denoise_cplx_tv_pdhg
   examples/denoise_dncnn_universal
   examples/diffusercam_tv_admm
   examples/video_rpca_admm
   examples/ct_datagen_foam2
   examples/deconv_datagen_bsds
   examples/deconv_datagen_foam1
   examples/denoise_datagen_bsds


Organized by Regularization
---------------------------

.. toctree::
   :maxdepth: 1

Plug and Play Priors
^^^^^^^^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/ct_svmbir_ppp_bm3d_admm_cg
   examples/ct_svmbir_ppp_bm3d_admm_prox
   examples/ct_fan_svmbir_ppp_bm3d_admm_prox
   examples/deconv_ppp_bm3d_admm
   examples/deconv_ppp_bm3d_apgm
   examples/deconv_ppp_dncnn_admm
   examples/deconv_ppp_dncnn_padmm
   examples/deconv_ppp_bm4d_admm
   examples/demosaic_ppp_bm3d_admm
   examples/superres_ppp_dncnn_admm


Total Variation
^^^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/ct_abel_tv_admm
   examples/ct_abel_tv_admm_tune
   examples/ct_symcone_tv_padmm
   examples/ct_tv_admm
   examples/ct_multi_tv_admm
   examples/ct_astra_tv_admm
   examples/ct_astra_3d_tv_admm
   examples/ct_astra_3d_tv_padmm
   examples/ct_astra_weighted_tv_admm
   examples/ct_svmbir_tv_multi
   examples/deconv_circ_tv_admm
   examples/deconv_tv_admm
   examples/deconv_tv_admm_tune
   examples/deconv_tv_padmm
   examples/deconv_microscopy_tv_admm
   examples/deconv_microscopy_allchn_tv_admm
   examples/denoise_l1tv_admm
   examples/denoise_ptv_pdhg
   examples/denoise_tv_admm
   examples/denoise_tv_apgm
   examples/denoise_tv_multi
   examples/denoise_approx_tv_multi
   examples/denoise_cplx_tv_nlpadmm
   examples/denoise_cplx_tv_pdhg
   examples/diffusercam_tv_admm



Sparsity
^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/diffusercam_tv_admm
   examples/sparsecode_nn_admm
   examples/sparsecode_nn_apgm
   examples/sparsecode_conv_admm
   examples/sparsecode_conv_md_admm
   examples/sparsecode_apgm
   examples/sparsecode_poisson_apgm
   examples/video_rpca_admm


Machine Learning
^^^^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/ct_datagen_foam2
   examples/ct_modl_train_foam2
   examples/ct_odp_train_foam2
   examples/ct_unet_train_foam2
   examples/deconv_datagen_bsds
   examples/deconv_datagen_foam1
   examples/deconv_modl_train_foam1
   examples/deconv_odp_train_foam1
   examples/denoise_datagen_bsds
   examples/denoise_dncnn_train_bsds
   examples/denoise_dncnn_universal


Organized by Optimization Algorithm
-----------------------------------

.. toctree::
   :maxdepth: 1

ADMM
^^^^

.. toctree::
   :maxdepth: 1

   examples/ct_abel_tv_admm
   examples/ct_abel_tv_admm_tune
   examples/ct_symcone_tv_padmm
   examples/ct_astra_tv_admm
   examples/ct_tv_admm
   examples/ct_astra_3d_tv_admm
   examples/ct_astra_weighted_tv_admm
   examples/ct_multi_tv_admm
   examples/ct_svmbir_tv_multi
   examples/ct_svmbir_ppp_bm3d_admm_cg
   examples/ct_svmbir_ppp_bm3d_admm_prox
   examples/ct_fan_svmbir_ppp_bm3d_admm_prox
   examples/deconv_circ_tv_admm
   examples/deconv_tv_admm
   examples/deconv_tv_admm_tune
   examples/deconv_microscopy_tv_admm
   examples/deconv_microscopy_allchn_tv_admm
   examples/deconv_ppp_bm3d_admm
   examples/deconv_ppp_dncnn_admm
   examples/deconv_ppp_bm4d_admm
   examples/diffusercam_tv_admm
   examples/sparsecode_nn_admm
   examples/sparsecode_conv_admm
   examples/sparsecode_conv_md_admm
   examples/demosaic_ppp_bm3d_admm
   examples/superres_ppp_dncnn_admm
   examples/denoise_l1tv_admm
   examples/denoise_tv_admm
   examples/denoise_tv_multi
   examples/denoise_approx_tv_multi
   examples/video_rpca_admm


Linearized ADMM
^^^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/ct_svmbir_tv_multi
   examples/denoise_tv_multi


Proximal ADMM
^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/ct_astra_3d_tv_padmm
   examples/deconv_tv_padmm
   examples/denoise_tv_multi
   examples/deconv_ppp_dncnn_padmm


Non-linear Proximal ADMM
^^^^^^^^^^^^^^^^^^^^^^^^

.. toctree::
   :maxdepth: 1

   examples/denoise_cplx_tv_nlpadmm


PDHG
^^^^

.. toctree::
   :maxdepth: 1

   examples/ct_svmbir_tv_multi
   examples/denoise_ptv_pdhg
   examples/denoise_tv_multi
   examples/denoise_cplx_tv_pdhg


PGM
^^^

.. toctree::
   :maxdepth: 1

   examples/deconv_ppp_bm3d_apgm
   examples/sparsecode_apgm
   examples/sparsecode_nn_apgm
   examples/sparsecode_poisson_apgm
   examples/denoise_tv_apgm
   examples/denoise_approx_tv_multi


PCG
^^^

.. toctree::
   :maxdepth: 1

   examples/ct_astra_noreg_pcg


================================================
FILE: docs/source/include/blockarray.rst
================================================
.. _blockarray_class:

BlockArray
==========

.. testsetup::

   >>> import numpy as np
   >>> import scico
   >>> import scico.random
   >>> import scico.linop
   >>> import scico.numpy as snp
   >>> from scico.numpy import BlockArray

The class :class:`.BlockArray` provides a way to combine arrays of
different shapes into a single object for use with other SCICO classes.
A :class:`.BlockArray` consists of a list of :class:`jax.Array` objects,
which we refer to as blocks. A :class:`.BlockArray` differs from a list in
that, whenever possible, :class:`.BlockArray` properties and methods
(including unary and binary operators like +, -, \*, ...) automatically
map along the blocks, returning another :class:`.BlockArray` or tuple as
appropriate. For example,

::

    >>> x = snp.blockarray((
    ...     [[1, 3, 7],
    ...      [2, 2, 1]],
    ...     [2, 4, 8]
    ... ))

    >>> x.shape  # returns tuple
    ((2, 3), (3,))

    >>> x * 2  # returns BlockArray   # doctest: +ELLIPSIS
    BlockArray([...Array([[ 2,  6, 14],
		 [ 4,  4,  2]], dtype=...), ...Array([ 4,  8, 16], dtype=...)])

    >>> y = snp.blockarray((
    ...        [[.2],
    ...         [.3]],
    ...        [.4]
    ... ))

    >>> x + y  # returns BlockArray  # doctest: +ELLIPSIS
    BlockArray([...Array([[1.2, 3.2, 7.2],
		  [2.3, 2.3, 1.3]], dtype=...), ...Array([2.4, 4.4, 8.4], dtype=...)])


.. _numpy_functions_blockarray:

NumPy and SciPy Functions
-------------------------

:mod:`scico.numpy`, :mod:`scico.numpy.testing`, and
:mod:`scico.scipy.special` provide wrappers around :mod:`jax.numpy`,
:mod:`numpy.testing` and :mod:`jax.scipy.special` where many of the
functions have been extended to work with instances of :class:`.BlockArray`.
In particular:

* When a tuple of tuples is passed as the `shape`
  argument to an array creation routine, a :class:`.BlockArray` is created.
* When a :class:`.BlockArray` is passed to a reduction function, the blocks are
  ravelled (i.e., reshaped to be 1D) and concatenated before the reduction
  is applied. This behavior may be prevented by passing the `axis`
  argument, in which case the function is mapped over the blocks.
* When one or more :class:`.BlockArray` instances are passed to a mathematical
  function that is not a reduction, the function is mapped over
  (corresponding) blocks.

For a list of array creation routines, see

::

   >>> scico.numpy.creation_routines  # doctest: +ELLIPSIS
   ('empty', ...)

For a list of  reduction functions, see

::

   >>> scico.numpy.reduction_functions  # doctest: +ELLIPSIS
   ('sum', ...)

For lists of the remaining wrapped functions, see

::

   >>> scico.numpy.mathematical_functions  # doctest: +ELLIPSIS
   ('sin', ...)
   >>> scico.numpy.testing_functions  # doctest: +ELLIPSIS
   ('testing.assert_allclose', ...)
   >>> import scico.scipy
   >>> scico.scipy.special.functions  # doctest: +ELLIPSIS
   ('betainc', ...)

Note that:

* The functional and method versions of the "same" function differ in their
  behavior, with the method version only applying the reduction within each
  block, and the function version applying the reduction across all blocks.
  For example, :func:`scico.numpy.sum` applied to a :class:`.BlockArray` with
  two blocks returns a scalar value, while :meth:`.BlockArray.sum` returns a
  :class:`.BlockArray` two scalar blocks.
* For example, :func:`scico.numpy.ravel` returns a fully flattened, single
  :class:`jax.Array`, while :meth:`.BlockArray.ravel` returns a
  :class:`.BlockArray` with ravelled blocks.


Motivating Example
------------------

The discrete differences of a two-dimensional array, :math:`\mb{x} \in
\mbb{R}^{n \times m}`, in the horizontal and vertical directions can
be represented by the arrays :math:`\mb{x}_h \in \mbb{R}^{n \times
(m-1)}` and :math:`\mb{x}_v \in \mbb{R}^{(n-1) \times m}`
respectively. While it is usually useful to consider the output of a
difference operator as a single entity, we cannot combine these two
arrays into a single array since they have different shapes. We could
vectorize each array and concatenate the resulting vectors, leading to
:math:`\mb{\bar{x}} \in \mbb{R}^{n(m-1) + m(n-1)}`, which can be
stored as a one-dimensional array, but this makes it hard to access
the individual components :math:`\mb{x}_h` and :math:`\mb{x}_v`.

Instead, we can construct a :class:`.BlockArray`, :math:`\mb{x}_B =
[\mb{x}_h, \mb{x}_v]`:


::

  >>> n = 32
  >>> m = 16
  >>> x_h, key = scico.random.randn((n, m-1))
  >>> x_v, _ = scico.random.randn((n-1, m), key=key)

  # Form the blockarray
  >>> x_B = snp.blockarray([x_h, x_v])

  # The blockarray shape is a tuple of tuples
  >>> x_B.shape
  ((32, 15), (31, 16))

  # Each block component can be easily accessed
  >>> x_B[0].shape
  (32, 15)
  >>> x_B[1].shape
  (31, 16)


Constructing a BlockArray
-------------------------

The recommended way to construct a :class:`.BlockArray` is by using the
:func:`~scico.numpy.blockarray` function.

::

   >>> import scico.numpy as snp
   >>> x0, key = scico.random.randn((32, 32))
   >>> x1, _ = scico.random.randn((16,), key=key)
   >>> X = snp.blockarray((x0, x1))
   >>> X.shape
   ((32, 32), (16,))
   >>> X.size
   (1024, 16)
   >>> len(X)
   2

While :func:`~scico.numpy.blockarray` will accept arguments of type
:class:`~numpy.ndarray` or :class:`~jax.Array`, arguments of type :class:`~numpy.ndarray` will be converted to :class:`~jax.Array` type.


Operating on a BlockArray
-------------------------


.. _blockarray_indexing:

Indexing
^^^^^^^^

:class:`.BlockArray` indexing works just like indexing a list.


Multiplication between BlockArray and LinearOperator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The :class:`.Operator` and :class:`.LinearOperator` classes are designed
to work on instances of :class:`.BlockArray` in addition to instances of
:obj:`~jax.Array`. For example

::

    >>> x, key = scico.random.randn((3, 4))
    >>> A_1 = scico.linop.Identity(x.shape)
    >>> A_1.shape  # array -> array
    ((3, 4), (3, 4))

    >>> A_2 = scico.linop.FiniteDifference(x.shape)
    >>> A_2.shape  # array -> BlockArray
    (((2, 4), (3, 3)), (3, 4))

    >>> diag = snp.blockarray([np.array(1.0), np.array(2.0)])
    >>> A_3 = scico.linop.Diagonal(diag, input_shape=(A_2.output_shape))
    >>> A_3.shape  # BlockArray -> BlockArray
    (((2, 4), (3, 3)), ((2, 4), (3, 3)))


================================================
FILE: docs/source/include/examplenotes.rst
================================================
.. _example_depend:

Example Dependencies
--------------------

Some examples use additional dependencies, which are listed in `examples_requirements.txt <https://github.com/lanl/scico/blob/main/examples/examples_requirements.txt>`_.
The additional requirements should be installed via pip, with the exception of ``astra-toolbox``,
which should be installed via conda:

::

   conda install astra-toolbox
   pip install -r examples/examples_requirements.txt  # Installs other example requirements

The dependencies can also be installed individually as required.

Note that ``astra-toolbox`` should be installed on a host with one or more CUDA GPUs to ensure
that the version with GPU support is installed.


Run Time
--------

Most of these examples have been constructed with sufficiently small test problems to
allow them to run to completion within 5 minutes or less on a reasonable workstation.
Note, however, that it was not feasible to construct meaningful examples of the training
of some of the deep learning algorithms that complete within a relatively short time;
the examples "CT Training and Reconstructions with MoDL" and "CT Training and
Reconstructions with ODP" in particular are much slower, and can require multiple hours
to run on a workstation with multiple GPUs.

|


================================================
FILE: docs/source/include/functional.rst
================================================
Functionals
===========

A functional is
a mapping from :math:`\mathbb{R}^n` or :math:`\mathbb{C}^n` to :math:`\mathbb{R}`.
In SCICO, functionals are
primarily used to represent a cost to be minimized
and are represented by instances of the :class:`.Functional` class.
An instance of :class:`.Functional`, ``f``, may provide three core operations.

* Evaluation
   - ``f(x)`` returns the value of the functional
     evaluated at the point ``x``.
   - A functional that can be evaluated
     has the attribute ``f.has_eval == True``.
   - Not all functionals can be evaluated:  see `Plug-and-Play`_.
* Gradient
   - ``f.grad(x)`` returns the gradient of the functional evaluated at ``x``.
   - Gradients are calculated using JAX reverse-mode automatic differentiation,
     exposed through :func:`scico.grad`.
   - *Note:*  The gradient of a functional ``f`` can be evaluated even if that functional is not smooth.
     All that is required is that the functional can be evaluated, ``f.has_eval == True``.
     However, the result may not be a valid gradient (or subgradient) for all inputs.
* Proximal operator
   - ``f.prox(v, lam)`` returns the result of the scaled proximal
     operator of ``f``, i.e., the proximal operator of ``lambda x:
     lam * f(x)``, evaluated at the point ``v``.
   - The proximal operator of a functional :math:`f : \mathbb{R}^n \to
     \mathbb{R}` is the mapping :math:`\mathrm{prox}_f : \mathbb{R}^n
     \to \mathbb{R}^n` defined as

     .. math::
      \mathrm{prox}_f (\mb{v}) =  \argmin_{\mb{x}} f(\mb{x}) +
      \frac{1}{2} \norm{\mb{v} - \mb{x}}_2^2\;.


Plug-and-Play
-------------

For the plug-and-play framework :cite:`sreehari-2016-plug`,
we encapsulate generic denoisers including CNNs
in :class:`.Functional` objects that **cannot be evaluated**.
The denoiser is applied via the the proximal operator.
For examples, see :ref:`example_notebooks`.


Proximal Calculus
-----------------

We support a limited subset of proximal calculus rules:


Scaled Functionals
^^^^^^^^^^^^^^^^^^

Given a scalar ``c`` and a functional ``f`` with a defined proximal method, we can
determine the proximal method of ``c * f`` as

.. math::

   \begin{align}
    \mathrm{prox}_{c f} (v, \lambda) &=  \argmin_x \lambda (c f)(x) + \frac{1}{2} \norm{v - x}_2^2  \\
    &=  \argmin_x (\lambda c) f(x) + \frac{1}{2} \norm{v - x}_2^2 \\
    &= \mathrm{prox}_{f} (v, c \lambda) \;.
    \end{align}

Note that we have made no assumptions regarding homogeneity of ``f``;
rather, only that the proximal method of ``f`` is given
in the parameterized form :math:`\mathrm{prox}_{c f}`.

In SCICO, multiplying a :class:`.Functional` by a scalar
will return a :class:`.ScaledFunctional`.
This :class:`.ScaledFunctional` retains the ``has_eval`` and ``has_prox`` attributes
from the original :class:`.Functional`,
but the proximal method is modified to accomodate the additional scalar.


Separable Functionals
^^^^^^^^^^^^^^^^^^^^^

A separable functional :math:`f : \mathbb{C}^N \to \mathbb{R}` can be written as the sum
of functionals :math:`f_i : \mathbb{C}^{N_i} \to \mathbb{R}` with :math:`\sum_i N_i = N`. In particular,

.. math::
   f(\mb{x}) = f(\mb{x}_1, \dots, \mb{x}_N) = f_1(\mb{x}_1) + \dots + f_N(\mb{x}_N) \;.

The proximal operator of a separable :math:`f` can be written
in terms of the proximal operators of the :math:`f_i`
(see Theorem 6.6 of :cite:`beck-2017-first`):

.. math::
    \mathrm{prox}_f(\mb{x}, \lambda)
    =
    \begin{pmatrix}
      \mathrm{prox}_{f_1}(\mb{x}_1, \lambda) \\
      \vdots \\
      \mathrm{prox}_{f_N}(\mb{x}_N, \lambda) \\
    \end{pmatrix} \;.

Separable Functionals are implemented in the :class:`.SeparableFunctional` class. Separable functionals naturally accept :class:`.BlockArray` inputs and return the prox as a :class:`.BlockArray`.



Adding New Functionals
----------------------

To add a new functional,
create a class which

1. inherits from base :class:`.Functional`;
2. has ``has_eval`` and ``has_prox`` flags;
3. has ``_eval`` and ``prox`` methods, as necessary.

For example,

::

   class MyFunctional(scico.functional.Functional):

       has_eval = True
       has_prox = True

       def _eval(self, x: JaxArray) -> float:
            return snp.sum(x)

       def prox(self, x: JaxArray, lam : float) -> JaxArray:
            return x - lam


Losses
------

In SCICO, a loss is a special type of functional

.. math::
   f(\mb{x}) = \alpha l( \mb{y}, A(\mb{x}) ) \;,

where :math:`\alpha` is a scaling parameter,
:math:`l` is a functional,
:math:`\mb{y}` is a set of measurements,
and :math:`A` is an operator.
SCICO uses the class :class:`.Loss` to represent losses.
Loss functionals commonly arrise in the context of solving
inverse problems in scientific imaging,
where they are used to represent the mismatch
between predicted measurements :math:`A(\mb{x})`
and actual ones :math:`\mb{y}`.


================================================
FILE: docs/source/include/learning.rst
================================================
Learned Models
==============

In SCICO, neural network models are used to represent imaging problems and provide different modes of data-driven regularization.
The models are implemented in `Flax <https://flax.readthedocs.io/>`_, and constitute a representative sample of frequently used networks.


FlaxMap
-------

SCICO interfaces with the implemented models via :class:`.FlaxMap`. This provides a standardized access to all trained models via the model definiton and the learned parameters. Further specialized functionality, such as learned denoisers, are built on top of :class:`.FlaxMap`. The specific models that have been implemented are described below.



DnCNN
-----

The denoiser convolutional neural network model (DnCNN) :cite:`zhang-2017-dncnn`, implemented as :class:`.DnCNNNet`, is used to denoise images that have been corrupted with additive Gaussian noise.



ODP
---

The unrolled optimization with deep priors (ODP) :cite:`diamond-2018-odp`, implemented as :class:`.ODPNet`, is used to solve inverse problems in imaging by adapting classical iterative methods into an end-to-end framework that incorporates deep networks as well as knowledge of the image formation model.

The framework aims to solve the optimization problem

.. math::
   \argmin_{\mb{x}} \; f(A \mb{x}, \mb{y}) + r(\mb{x}) \;,

where :math:`A` represents a linear forward model and :math:`r` a regularization function encoding prior information, by unrolling the iterative solution method into a network where each iteration corresponds to a different stage in the ODP network. Different iterative solutions produce different unrolled optimization algorithms which, in turn, produce different ODP networks. The ones implemented in SCICO are described below.


Proximal Map
^^^^^^^^^^^^

This algorithm corresponds to solving

.. math::
   :label: eq:odp_prox

   \argmin_{\mb{x}} \; \alpha_k \, f(A \mb{x}, \mb{y}) + \frac{1}{2} \| \mb{x} - \mb{x}^k - \mb{x}^{k+1/2} \|_2^2 \;,

with :math:`k` corresponding to the index of the iteration, which translates to an index of the stage of the network, :math:`f(A \mb{x}, \mb{y})` a fidelity term, usually an :math:`\ell_2` norm, and :math:`\mb{x}^{k+1/2}` a regularization representing :math:`\mathrm{prox}_r (\mb{x}^k)` and usually implemented as a convolutional neural network (CNN). This proximal map representation is used when minimization problem :eq:`eq:odp_prox` can be solved in a computationally efficient manner.

:class:`.ODPProxDnBlock` uses this formulation to solve a denoising problem, which, according to :cite:`diamond-2018-odp`, can be solved by

.. math::
   \mb{x}^{k+1} = (\alpha_k \, \mb{y} + \mb{x}^k + \mb{x}^{k+1/2}) \, / \, (\alpha_k + 1) \;,

where :math:`A` corresponds to the identity operator and is therefore omitted, :math:`\mb{y}` is the noisy signal, :math:`\alpha_k > 0` is a learned stage-wise parameter weighting the contribution of the fidelity term and :math:`\mb{x}^k + \mb{x}^{k+1/2}` is the regularization, usually represented by a residual CNN.


:class:`.ODPProxDblrBlock` uses this formulation to solve a deblurring problem, which, according to :cite:`diamond-2018-odp`, can be solved by

.. math::
   \mb{x}^{k+1} = \mathcal{F}^{-1} \mathrm{diag} (\alpha_k | \mathcal{F}(K)|^2 + 1 )^{-1} \mathcal{F} \, (\alpha_k K^T * \mb{y} + \mb{x}^k + \mb{x}^{k+1/2}) \;,

where :math:`A` is the blurring operator, :math:`K` is the blurring kernel, :math:`\mb{y}` is the blurred signal, :math:`\mathcal{F}` is the DFT, :math:`\alpha_k > 0` is a learned  stage-wise parameter weighting the contribution of the fidelity term and :math:`\mb{x}^k + \mb{x}^{k+1/2}` is the regularization represented by a residual CNN.


Gradient Descent
^^^^^^^^^^^^^^^^

When the solution of the optimization problem in :eq:`eq:odp_prox` can not be simply represented by an analytical step, a formulation based on a gradient descent iteration is preferred. This yields

.. math::
   \mb{x}^{k+1} = \mb{x}^k + \mb{x}^{k+1/2} - \alpha_k \, A^T \nabla_x \, f(A \mb{x}^k, \mb{y}) \;,

where :math:`\mb{x}^{k+1/2}` represents :math:`\nabla r(\mb{x}^k)`.

:class:`.ODPGrDescBlock` uses this formulation to solve a generic problem with :math:`\ell_2` fidelity as

.. math::
   \mb{x}^{k+1} = \mb{x}^k + \mb{x}^{k+1/2} - \alpha_k \, A^T (A \mb{x} - \mb{y}) \;,

with :math:`\mb{y}` the measured signal and :math:`\mb{x} + \mb{x}^{k+1/2}` a residual CNN.


MoDL
----

The model-based deep learning (MoDL) :cite:`aggarwal-2019-modl`, implemented as :class:`.MoDLNet`, is used to solve inverse problems in imaging also by adapting classical iterative methods into an end-to-end deep learning framework, but, in contrast to ODP, it solves the optimization problem

.. math::
   \argmin_{\mb{x}} \; \| A \mb{x} - \mb{y}\|_2^2 + \lambda \, \| \mb{x} - \mathrm{D}_w(\mb{x})\|_2^2 \;,

by directly computing the update

.. math::
   \mb{x}^{k+1} = (A^T A + \lambda \, I)^{-1} (A^T \mb{y} + \lambda \, \mb{z}^k) \;,

via conjugate gradient. The regularization :math:`\mb{z}^k = \mathrm{D}_w(\mb{x}^{k})` incorporates prior information, usually in the form of a denoiser model. In this case, the denoiser :math:`\mathrm{D}_w` is shared between all the stages of the network requiring relatively less memory than other unrolling methods. This also allows for deploying a different number of iterations in testing than the ones used in training.


================================================
FILE: docs/source/include/operator.rst
================================================
Operators
=========

An operator is a map from :math:`\mathbb{R}^n` or :math:`\mathbb{C}^n`
to :math:`\mathbb{R}^m` or :math:`\mathbb{C}^m`. In SCICO, operators
are primarily used to represent imaging systems and provide
regularization. SCICO operators are represented by instances of the
:class:`.Operator` class.

SCICO :class:`.Operator` objects extend the notion of "shape" and
"size" from the usual NumPy ``ndarray`` class. Each
:class:`.Operator` object has an ``input_shape`` and ``output_shape``;
these shapes can be either tuples or a tuple of tuples (in the case of
a :class:`.BlockArray`). The ``matrix_shape`` attribute describes the
shape of the :class:`.LinearOperator` if it were to act on vectorized,
or flattened, inputs.

For example, consider a two-dimensional array :math:`\mb{x} \in
\mathbb{R}^{n \times m}`. We compute the discrete differences of
:math:`\mb{x}` in the horizontal and vertical directions, generating
two new arrays: :math:`\mb{x}_h \in \mathbb{R}^{n \times (m-1)}` and
:math:`\mb{x}_v \in \mathbb{R}^{(n-1) \times m}`. We represent this
linear operator by :math:`\mb{A} : \mathbb{R}^{n \times m} \to
\mathbb{R}^{n \times (m-1)} \otimes \mathbb{R}^{(n-1) \times m}`. In
SCICO, this linear operator will return a :class:`.BlockArray` with
the horizontal and vertical differences stored as blocks. Letting
:math:`y = \mb{A} x`, we have ``y.shape = ((n, m-1), (n-1, m))`` and

::

    A.input_shape = (n, m)
    A.output_shape = ((n, m-1), (n-1, m)], (n, m))
    A.shape = ( ((n, m-1), (n-1, m)), (n, m))   # (output_shape, input_shape)
    A.input_size = n*m
    A.output_size = n*(n-1)*m*(m-1)
    A.matrix_shape = (n*(n-1)*m*(m-1), n*m)    # (output_size, input_size)


Operator Calculus
-----------------

SCICO supports a variety of operator calculus rules, allowing new
operators to be defined in terms of old ones. The following table
summarizes the available operations.

+----------------+-----------------+
| Operation      |  Result         |
+----------------+-----------------+
| ``(A+B)(x)``   | ``A(x) + B(x)`` |
+----------------+-----------------+
| ``(A-B)(x)``   | ``A(x) - B(x)`` |
+----------------+-----------------+
| ``(c * A)(x)`` | ``c * A(x)``    |
+----------------+-----------------+
| ``(A/c)(x)``   | ``A(x)/c``      |
+----------------+-----------------+
| ``(-A)(x)``    | ``-A(x)``       |
+----------------+-----------------+
| ``A(B)(x)``    | ``A(B(x))``     |
+----------------+-----------------+
| ``A(B)``       | ``Operator``    |
+----------------+-----------------+


Defining a New Operator
-----------------------

To define a new operator, pass a callable to the :class:`.Operator`
constructor:

::

    A = Operator(input_shape=(32,), eval_fn = lambda x: 2 * x)


Or use subclassing:

::

   >>> from scico.operator import Operator
   >>> class MyOp(Operator):
   ...
   ...     def _eval(self, x):
   ...         return 2 * x

   >>> A = MyOp(input_shape=(32,))

At a minimum, the ``_eval`` function must be overridden.  If either
``output_shape`` or ``output_dtype`` are unspecified, they are
determined by evaluating the operator on an input of appropriate shape
and dtype.


Linear Operators
================

Linear operators are those for which

.. math::

   H(a \mb{x} + b \mb{y}) = a H(\mb{x}) + b H(\mb{y}) \;.

SCICO represents linear operators as instances of the class
:class:`.LinearOperator`.  While finite-dimensional linear operators
can always be associated with a matrix, it is often useful to
represent them in a matrix-free manner.  Most of SCICO's linear
operators are implemented matrix-free.



Using a LinearOperator
----------------------

We implement two ways to evaluate a :class:`.LinearOperator`. The
first is using standard callable syntax: ``A(x)``. The second mimics
the NumPy matrix multiplication syntax: ``A @ x``. Both methods
perform shape and type checks to validate the input before ultimately
either calling `A._eval` or generating a new :class:`.LinearOperator`.

For linear operators that map real-valued inputs to real-valued
outputs, there are two ways to apply the adjoint: ``A.adj(y)`` and
``A.T @ y``.

For complex-valued linear operators, there are three ways to apply the
adjoint ``A.adj(y)``, ``A.H @ y``, and ``A.conj().T @ y``.  Note that
in this case, ``A.T`` returns the non-conjugated transpose of the
:class:`.LinearOperator`.

While the cost of evaluating the linear operator is virtually
identical for ``A(x)`` and ``A @ x``, the ``A.H`` and ``A.conj().T``
methods are somewhat slower; especially the latter. This is because
two intermediate linear operators must be created before the function
is evaluated.  Evaluating ``A.conj().T @ y`` is equivalent to:

::

  def f(y):
    B = A.conj()  # New LinearOperator #1
    C = B.T       # New LinearOperator #2
    return C @ y

**Note**: the speed differences between these methods vanish if
applied inside of a jit-ed function.  For instance:

::

   f = jax.jit(lambda x:  A.conj().T @ x)


+------------------+-----------------+
|  Public Method   |  Private Method |
+------------------+-----------------+
|  ``__call__``    |  ``._eval``     |
+------------------+-----------------+
|  ``adj``         |  ``._adj``      |
+------------------+-----------------+
|  ``gram``        |  ``._gram``     |
+------------------+-----------------+

The public methods perform shape and type checking to validate the
input before either calling the corresponding private method or
returning a composite LinearOperator.


Linear Operator Calculus
------------------------

SCICO supports several linear operator calculus rules.
Given
``A`` and ``B`` of class :class:`.LinearOperator` and of appropriate shape,
``x`` an array of appropriate shape,
``c`` a scalar, and
``O`` an :class:`.Operator`,
we have

+----------------+----------------------------+
| Operation      |  Result                    |
+----------------+----------------------------+
| ``(A+B)(x)``   | ``A(x) + B(x)``            |
+----------------+----------------------------+
| ``(A-B)(x)``   | ``A(x) - B(x)``            |
+----------------+----------------------------+
| ``(c * A)(x)`` | ``c * A(x)``               |
+----------------+----------------------------+
| ``(A/c)(x)``   | ``A(x)/c``                 |
+----------------+----------------------------+
| ``(-A)(x)``    | ``-A(x)``                  |
+----------------+----------------------------+
| ``(A@B)(x)``   | ``A@B@x``                  |
+----------------+----------------------------+
| ``A @ B``      | ``ComposedLinearOperator`` |
+----------------+----------------------------+
| ``A @ O``      | ``Operator``               |
+----------------+----------------------------+
| ``O(A)``       | ``Operator``               |
+----------------+----------------------------+



Defining a New Linear Operator
------------------------------

To define a new linear operator, pass a callable to the
:class:`.LinearOperator` constructor

::

   >>> from scico.linop import LinearOperator
   >>> A = LinearOperator(input_shape=(32,),
   ...       eval_fn = lambda x: 2 * x)

Or, use subclassing:

::

   >>> class MyLinearOperator(LinearOperator):
   ...    def _eval(self, x):
   ...        return 2 * x

   >>> A = MyLinearOperator(input_shape=(32,))

At a minimum, the ``_eval`` method must be overridden.  If the
``_adj`` method is not overriden, the adjoint is determined using
:func:`scico.linear_adjoint`.  If either ``output_shape`` or
``output_dtype`` are unspecified, they are determined by evaluating
the Operator on an input of appropriate shape and dtype.


🔪 Sharp Edges 🔪
------------------

Strict Types in Adjoint
^^^^^^^^^^^^^^^^^^^^^^^

SCICO silently promotes real types to complex types in forward
application, but enforces strict type checking in the adjoint.  This
is due to the strict type-safe nature of jax adjoints.


LinearOperators from External Code
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

External code may be wrapped as a subclass of :class:`.Operator` or
:class:`.LinearOperator` and used in SCICO optimization routines;
however this process can be complicated and error-prone.  As a
starting point, look at the source for
:class:`.radon_svmbir.TomographicProjector` or
:class:`.radon_astra.TomographicProjector` and the JAX documentation
for the `vector-jacobian product
<https://jax.readthedocs.io/en/latest/notebooks/autodiff_cookbook.html#vector-jacobian-products-vjps-aka-reverse-mode-autodiff>`_
and `custom VJP rules
<https://jax.readthedocs.io/en/latest/notebooks/Custom_derivative_rules_for_Python_code.html>`_.


================================================
FILE: docs/source/include/optimizer.rst
================================================
.. _optimizer:

Optimization Algorithms
=======================

ADMM
----

The Alternating Direction Method of Multipliers (ADMM)
:cite:`glowinski-1975-approximation` :cite:`gabay-1976-dual` is an
algorithm for minimizing problems of the form

.. math::
   :label: eq:admm_prob

   \argmin_{\mb{x}, \mb{z}} \; f(\mb{x}) + g(\mb{z}) \; \text{such that}
   \; \acute{A} \mb{x} + \acute{B} \mb{z} = \mb{c} \;,

where :math:`f` and :math:`g` are convex (but not necessarily smooth)
functionals, :math:`\acute{A}` and :math:`\acute{B}` are linear operators,
and :math:`\mb{c}` is a constant vector. (For a thorough introduction and
overview, see :cite:`boyd-2010-distributed`.)

The SCICO ADMM solver, :class:`.ADMM`, solves problems of the form

.. math::
   \argmin_{\mb{x}} \; f(\mb{x}) + \sum_{i=1}^N g_i(C_i \mb{x}) \;,

where :math:`f` and the :math:`g_i` are instances of :class:`.Functional`,
and the :math:`C_i` are :class:`.LinearOperator`, by defining

.. math::
   g(\mb{z}) = \sum_{i=1}^N g_i(\mb{z}_i) \qquad \mb{z}_i = C_i \mb{x}

in :eq:`eq:admm_prob`, corresponding to defining

.. math::
  \acute{A} = \left( \begin{array}{c} C_0 \\ C_1 \\ C_2 \\
              \vdots \end{array} \right)  \quad
  \acute{B} = \left( \begin{array}{cccc}
              -I & 0 & 0 & \ldots \\
              0 & -I & 0 & \ldots \\
              0 &  0  & -I & \ldots \\
              \vdots & \vdots & \vdots & \ddots
              \end{array} \right) \quad
  \mb{z} = \left( \begin{array}{c} \mb{z}_0 \\ \mb{z}_1 \\ \mb{z}_2 \\
              \vdots \end{array} \right)  \quad
  \mb{c} = \left( \begin{array}{c} 0 \\ 0 \\ 0 \\
              \vdots \end{array} \right) \;.

In :class:`.ADMM`, :math:`f` is a :class:`.Functional`, typically a
:class:`.Loss`, corresponding to the forward model of an imaging
problem, and the :math:`g_i` are :class:`.Functional`, typically
corresponding to a regularization term or constraint. Each of the
:math:`g_i` must have a proximal operator defined. It is also possible
to set ``f = None``, which corresponds to defining :math:`f = 0`,
i.e. the zero function.


Subproblem Solvers
^^^^^^^^^^^^^^^^^^

The most computational expensive component of the ADMM iterations is typically
the :math:`\mb{x}`-update,

.. math::
   :label: eq:admm_x_step

   \argmin_{\mb{x}} \; f(\mb{x}) + \sum_i \frac{\rho_i}{2}
   \norm{\mb{z}^{(k)}_i - \mb{u}^{(k)}_i - C_i \mb{x}}_2^2 \;.


The available solvers for this problem are:

* :class:`.admm.GenericSubproblemSolver`

  This is the default subproblem solver as it is applicable in all cases. It
  it is only suitable for relatively small-scale problems as it makes use of
  :func:`.solver.minimize`, which wraps :func:`scipy.optimize.minimize`.

* :class:`.admm.LinearSubproblemSolver`

  This subproblem solver can be used when :math:`f` takes the form
  :math:`\norm{\mb{A} \mb{x} - \mb{y}}^2_W`. It makes use of the conjugate
  gradient method, and is significantly more efficient than
  :class:`.admm.GenericSubproblemSolver` when it can be used.

* :class:`.admm.MatrixSubproblemSolver`

  This subproblem solver can be used when :math:`f` takes the form
  :math:`\norm{\mb{A} \mb{x} - \mb{y}}^2_W`, and :math:`A` and all of the
  :math:`C_i` are diagonal (:class:`.Diagonal`) or matrix operators
  (:class:`MatrixOperator`). It exploits a pre-computed matrix factorization
  for a significantly more efficient solution than conjugate gradient.

* :class:`.admm.CircularConvolveSolver`

  This subproblem solver can be used when :math:`f` takes the form
  :math:`\norm{\mb{A} \mb{x} - \mb{y}}^2_W` and :math:`\mb{A}` and all
  the :math:`C_i` s are circulant (i.e., diagonalized by the DFT).

* :class:`.admm.FBlockCircularConvolveSolver` and :class:`.admm.G0BlockCircularConvolveSolver`

  These subproblem solvers can be used when the primary linear operator
  is block-circulant (i.e. an operator with blocks that are diagonalied
  by the DFT).


For more details of these solvers and how to specify them, see the API
reference page for :mod:`scico.optimize.admm`.


Proximal ADMM
-------------

Proximal ADMM :cite:`deng-2015-global` is an algorithm for solving
problems of the form

.. math::

   \argmin_{\mb{x}} \; f(\mb{x}) + g(\mb{z}) \;
   \text{such that}\; A \mb{x} + B \mb{z} = \mb{c} \;,

where :math:`f` and :math:`g` are are convex (but not necessarily
smooth) functionals and :math:`A` and :math:`B` are linear
operators. Although convergence per iteration is typically somewhat
worse than that of ADMM, the iterations can be much cheaper than that
of ADMM, giving Proximal ADMM competitive time convergence
performance.

The SCICO Proximal ADMM solver, :class:`.ProximalADMM`, requires
:math:`f` and :math:`g` to be instances of :class:`.Functional`, and
to have a proximal operator defined (:meth:`.Functional.prox`), and
:math:`A` and :math:`B` are required to be an instance of
:class:`.LinearOperator`.


Non-Linear Proximal ADMM
------------------------

Non-Linear Proximal ADMM :cite:`benning-2016-preconditioned` is an
algorithm for solving problems of the form

.. math::
   \argmin_{\mb{x}} \; f(\mb{x}) + g(\mb{z}) \;
   \text{such that}\; H(\mb{x}, \mb{z}) = 0 \;,

where :math:`f` and :math:`g` are are convex (but not necessarily
smooth) functionals and :math:`H` is a function of two vector variables.

The SCICO Non-Linear Proximal ADMM solver, :class:`.NonLinearPADMM`, requires
:math:`f` and :math:`g` to be instances of :class:`.Functional`, and
to have a proximal operator defined (:meth:`.Functional.prox`), and
:math:`H` is required to be an instance of :class:`.Function`.



Linearized ADMM
---------------

Linearized ADMM :cite:`yang-2012-linearized`
:cite:`parikh-2014-proximal` (Sec. 4.4.2) is an algorithm for solving
problems of the form

.. math::
   \argmin_{\mb{x}} \; f(\mb{x}) + g(C \mb{x}) \;,

where :math:`f` and :math:`g` are are convex (but not necessarily
smooth) functionals. Although convergence per iteration is typically
significantly worse than that of ADMM, the :math:`\mb{x}`-update, can
be much cheaper than that of ADMM, giving Linearized ADMM competitive
time convergence performance.

The SCICO Linearized ADMM solver, :class:`.LinearizedADMM`,
requires :math:`f` and :math:`g` to be instances of :class:`.Functional`,
and to have a proximal operator defined (:meth:`.Functional.prox`), and
:math:`C` is required to be an instance of :class:`.LinearOperator`.



PDHG
----

The Primal–Dual Hybrid Gradient (PDHG) algorithm
:cite:`esser-2010-general` :cite:`chambolle-2010-firstorder`
:cite:`pock-2011-diagonal` solves problems of the form

.. math::
   \argmin_{\mb{x}} \; f(\mb{x}) + g(C \mb{x}) \;,

where :math:`f` and :math:`g` are are convex (but not necessarily smooth)
functionals. The algorithm has similar advantages over ADMM to those of Linearized ADMM, but typically exhibits better convergence properties.

The SCICO PDHG solver, :class:`.PDHG`,
requires :math:`f` and :math:`g` to be instances of :class:`.Functional`,
and to have a proximal operator defined (:meth:`.Functional.prox`), and
:math:`C` is required to be an instance of :class:`.Operator` or :class:`.LinearOperator`.



PGM
---

The Proximal Gradient Method (PGM) :cite:`daubechies-2004-iterative`
:cite:`beck-2010-gradient` and Accelerated Proximal Gradient Method
(AcceleratedPGM) :cite:`beck-2009-fast` are algorithms for minimizing
problems of the form

.. math::
   \argmin_{\mb{x}} f(\mb{x}) + g(\mb{x}) \;,

where :math:`g` is convex and :math:`f` is smooth and convex. The
corresponding SCICO solvers are :class:`.PGM` and :class:`.AcceleratedPGM`
respectively. In most cases :class:`.AcceleratedPGM` is expected to provide
faster convergence. In both of these classes, :math:`f` and :math:`g` are
both of type :class:`.Functional`, where :math:`f` must be differentiable,
and :math:`g` must have a proximal operator defined.

While ADMM provides significantly more flexibility than PGM, and often
converges faster, the latter is preferred when solving the ADMM
:math:`\mb{x}`-step is very computationally expensive, such as in the case of
:math:`f(\mb{x}) = \norm{\mb{A} \mb{x} - \mb{y}}^2_W` where :math:`A` is
large and does not have any special structure that would allow an efficient
solution of :eq:`eq:admm_x_step`.



Step Size Options
^^^^^^^^^^^^^^^^^

The step size (usually referred to in terms of its reciprocal,
:math:`L`) for the gradient descent in :class:`PGM` can be adapted via
Barzilai-Borwein methods (also called spectral methods) and iterative
line search methods.

The available step size policy classes are:

* :class:`.BBStepSize`

  This implements the step size adaptation based on the Barzilai-Borwein
  method :cite:`barzilai-1988-stepsize`. The step size :math:`\alpha` is
  estimated as

  .. math::
     \mb{\Delta x} = \mb{x}_k - \mb{x}_{k-1} \; \\
     \mb{\Delta g} = \nabla f(\mb{x}_k) - \nabla f (\mb{x}_{k-1}) \; \\
     \alpha = \frac{\mb{\Delta x}^T \mb{\Delta g}}{\mb{\Delta g}^T
     \mb{\Delta g}} \;.

  Since the PGM solver uses the reciprocal of the step size, the value
  :math:`L = 1 / \alpha` is returned.


* :class:`.AdaptiveBBStepSize`

  This implements the adaptive Barzilai-Borwein method as introduced in
  :cite:`zhou-2006-adaptive`. The adaptive step size rule computes

  .. math::
     \mb{\Delta x} = \mb{x}_k - \mb{x}_{k-1} \; \\
     \mb{\Delta g} = \nabla f(\mb{x}_k) - \nabla f (\mb{x}_{k-1}) \; \\
     \alpha^{\mathrm{BB1}} = \frac{\mb{\Delta x}^T \mb{\Delta x}}
     {\mb{\Delta x}^T \mb{\Delta g}} \; \\
     \alpha^{\mathrm{BB2}} = \frac{\mb{\Delta x}^T \mb{\Delta g}}
     {\mb{\Delta g}^T \mb{\Delta g}} \;.

  The determination of the new step size is made via the rule

  .. math::
     \alpha = \left\{ \begin{array}{ll} \alpha^{\mathrm{BB2}}  &
     \mathrm{~if~} \alpha^{\mathrm{BB2}} / \alpha^{\mathrm{BB1}}
     < \kappa \; \\
     \alpha^{\mathrm{BB1}}  & \mathrm{~otherwise} \end{array}
     \right . \;,

  with :math:`\kappa \in (0, 1)`.

  Since the PGM solver uses the reciprocal of the step size, the value
  :math:`L = 1 / \alpha` is returned.


* :class:`.LineSearchStepSize`

  This implements the line search strategy described in :cite:`beck-2009-fast`.
  This strategy estimates :math:`L` such that
  :math:`f(\mb{x}) \leq \hat{f}_{L}(\mb{x})` is satisfied with
  :math:`\hat{f}_{L}` a quadratic approximation to :math:`f` defined as

  .. math::
     \hat{f}_{L}(\mb{x}, \mb{y}) = f(\mb{y}) + \nabla f(\mb{y})^H
     (\mb{x} - \mb{y}) + \frac{L}{2} \left\| \mb{x} - \mb{y}
     \right\|_2^2 \;,

  with :math:`\mb{x}` the potential new update and :math:`\mb{y}` the
  current solution or current extrapolation (if using :class:`.AcceleratedPGM`).


* :class:`.RobustLineSearchStepSize`

  This implements the robust line search strategy described in
  :cite:`florea-2017-robust`. This strategy estimates :math:`L` such that
  :math:`f(\mb{x}) \leq \hat{f}_{L}(\mb{x})` is satisfied with
  :math:`\hat{f}_{L}` a quadratic approximation to :math:`f` defined as

  .. math::
     \hat{f}_{L}(\mb{x}, \mb{y}) = f(\mb{y}) + \nabla f(\mb{y})^H
     (\mb{x} - \mb{y}) + \frac{L}{2} \left\| \mb{x} - \mb{y} \right\|_2^2 \;,

  with :math:`\mb{x}` the potential new update and :math:`\mb{y}` the
  auxiliary extrapolation state. Note that this should only be used
  with :class:`.AcceleratedPGM`.


For more details of these step size managers and how to specify them, see
the API reference page for :mod:`scico.optimize.pgm`.


================================================
FILE: docs/source/index.rst
================================================
SCICO Documentation
===================

.. toctree::
   :maxdepth: 2
   :caption: User Documentation

   overview
   inverse
   advantages
   install
   classes
   notes
   examples
   API Reference <_autosummary/scico.rst>
   zreferences

.. toctree::
   :maxdepth: 2
   :caption: Developer Documentation

   team
   contributing
   style


Indices
=======

* :ref:`genindex`
* :ref:`modindex`


================================================
FILE: docs/source/install.rst
================================================
.. _installing:

Installing SCICO
================

SCICO requires Python version 3.8 or later. (Version 3.12 is
recommended as it is the version under which SCICO is tested in GitHub
continuous integration, and since the most recent versions of JAX require
version 3.10 or later.) SCICO is supported on both Linux and
MacOS, but is not currently supported on Windows due to the limited
support for ``jaxlib`` on Windows. However, Windows users can use
SCICO via the `Windows Subsystem for Linux
<https://docs.microsoft.com/en-us/windows/wsl/about>`_ (WSL). Guides
exist for using WSL with
`CPU only <https://docs.microsoft.com/en-us/windows/wsl/install-win10>`_
and with
`GPU support <https://docs.microsoft.com/en-us/windows/win32/direct3d12/gpu-cuda-in-wsl>`_.

While not required, installation of SCICO and its dependencies within a
`Conda <https://conda.io/projects/conda/en/latest/user-guide/index.html>`_
environment is recommended.
`Scripts <https://github.com/lanl/scico/tree/main/misc/conda>`_
are provided for creating a
`miniconda <https://docs.conda.io/en/latest/miniconda.html>`_
installation and an environment including all primary SCICO dependencies
as well as dependencies for usage example, testing, and building the
documentation.


From PyPI
---------

The simplest way to install the most recent release of SCICO from
`PyPI <https://pypi.python.org/pypi/scico/>`_ is
::

   pip install scico

which will install SCICO and its primary dependencies. If the additional
dependencies for the example scripts are also desired, it can instead be
installed using
::

   pip install scico[examples]

Note, however, that since the ``astra-toolbox`` package available from
PyPI is not straightforward to install (it has numerous build requirements
that are not specified as package dependencies), it is recommended to
first install this package via conda
::

   conda install astra-toolbox



From conda-forge
----------------

SCICO can also be installed from `conda-forge <https://anaconda.org/conda-forge/scico>`_
::

  conda install -c conda-forge "scico>0.0.5"

where the version constraint is required to avoid installation of an old
package with broken dependencies.

Note, however, that installation from conda forge is only possible on a Linux
platform since there is no conda package for the secondary dependency
``tensorstore`` under MacOS. There are also complications on Linux platforms
with Python versions 3.9 or earlier due to the automatic installation of a
version of secondary dependency ``etils`` that does not support Python versions
earlier than 3.10. This can be rectified by
::

  conda install etils=1.5.1

The most recent SCICO conda forge package also includes dependencies for
the example scripts, except for ``bm3d``, ``bm4d``, and
``colour_demosaicing``, for which conda packages are not available. These
can be installed from PyPI
::

  pip install bm3d bm4d colour_demosaicing



From GitHub
-----------

The development version of SCICO can be downloaded from the `GitHub repo
<https://github.com/lanl/scico>`_. Note that, since the SCICO repo has
a submodule, it should be cloned via the command
::

   git clone --recurse-submodules git@github.com:lanl/scico.git

Install using the commands
::

   cd scico
   pip install -r requirements.txt
   pip install -e .


If a clone of the SCICO repository is not needed, it is simpler to
install directly using ``pip``
::

   pip install git+https://github.com/lanl/scico



GPU Support
-----------

The instructions above install a CPU-only version of SCICO. To install
a version with GPU support:

1. Follow the CPU-only instructions, above

2. Install the version of jaxlib with GPU support, as described in the `JAX installation
   instructions  <https://jax.readthedocs.io/en/latest/installation.html>`_.
   In the simplest case, the appropriate command is
   ::

      pip install --upgrade "jax[cuda12]"

   for CUDA 12, but it may be necessary to explicitly specify the
   ``jaxlib`` version if the most recent release is not yet supported
   by SCICO (as specified in the ``requirements.txt`` file).


The script
`misc/gpu/envinfo.py <https://github.com/lanl/scico/blob/main/misc/gpu/envinfo.py>`_
in the source distribution is provided as an aid to debugging GPU support
issues. The script
`misc/gpu/availgpu.py <https://github.com/lanl/scico/blob/main/misc/gpu/availgpu.py>`_
can be used to automatically recommend a setting of the CUDA_VISIBLE_DEVICES
environment variable that excludes GPUs that are already in use.



Additional Dependencies
-----------------------

See :ref:`example_depend` for instructions on installing dependencies
related to the examples.


For Developers
--------------

See :ref:`scico_dev_contributing` for instructions on installing a
version of SCICO suitable for development.


================================================
FILE: docs/source/inverse.rst
================================================
Inverse Problems
================

In traditional imaging, the burden of image formation is placed on
physical components, such as a lens, with the resulting image being
taken from the sensor with minimal processing. In computational
imaging, in contrast, the burden of image formation is shared with or
shifted to computation, with the resulting image typically being very
different from the measured data. Common examples of computational
imaging include demosaicing in consumer cameras, computed tomography
and magnetic resonance imaging in medicine, and synthetic aperture
radar in remote sensing. This is an active and growing area of
research, and many of these problems have common properties that could
be supported by shared implementations of solution components.

The goal of SCICO is to provide a general research tool for
computational imaging, with a particular focus on scientific imaging
applications, which are particularly underrepresented in the existing
range of open-source packages in this area. While a number of other
packages overlap somewhat in functionality with SCICO, only a few
support execution of the same code on both CPU and GPU devices, and we
are not aware of any that support just-in-time compilation and
automatic gradient computation, which is invaluable in computational
imaging. SCICO provides all three of these valuable features (subject
to some :ref:`caveats <non_jax_dep>`) by being built on top of `JAX
<https://jax.readthedocs.io/en/latest/>`__ rather than `NumPy
<https://numpy.org/>`__.


The remainder of this section outlines the steps involved in solving
an inverse problem, and shows how each concept maps to a component of
SCICO. More detail on the main classes involved in setting up and
solving an inverse problem can be found in :ref:`classes`.


Forward Modeling
----------------

In order to solve a computational imaging problem we need to know how
the image we wish to reconstruct, :math:`\mathbf{x}`, is related to the
data that we can measure, :math:`\mathbf{y}`. This is represented via a
model of the measurement process,

.. math:: \mathbf{y} = A(\mathbf{x}) \,.

SCICO provides the :class:`.Operator` and :class:`.LinearOperator`
classes, which may be subclassed by users, in order to implement the
forward operator, :math:`A`. It also has several built-in operators,
most of which are linear, e.g., finite convolutions, discrete Fourier
transforms, optical propagators, Abel transforms, and X-ray transforms
(the same as Radon transforms in 2D). For example,

.. code:: python

       input_shape = (512, 512)
       angles = np.linspace(0, 2 * np.pi, 180, endpoint=False)
       channels = 512
       A = scico.linop.xray.svmbir.XRayTransform(input_shape, angles, channels)

defines a tomographic projection operator.

A significant advantage of SCICO being built on top of `JAX
<https://jax.readthedocs.io/en/latest/>`__ is that the adjoints of
linear operators, which can be quite time consuming to implement even
when the operator itself is straightforward, are computed
automatically by exploiting the automatic differentation features of
`JAX <https://jax.readthedocs.io/en/latest/>`__. If :code:`A` is a
:class:`.LinearOperator`, then its adjoint is simply :code:`A.T` for
real transforms and :code:`A.H` for complex transforms. Likewise,
Jacobian-vector products can be automatically computed for non-linear
operators, allowing for simple linearization and gradient
calculations.

SCICO operators can be composed to construct new operators. (If both
operands are linear, then the result is also linear.) For example, if
:code:`A` and :code:`B` have been defined as distinct linear
operators, then

.. code:: python

       C = B @ A

defines a new linear operator :code:`C` that first applies operator
:code:`A` and then applies operator :code:`B` to the result
(i.e. :math:`C = B A` in math notation). This operator algebra can be
used to build complicated forward operators from simpler building
blocks.

SCICO also handles cases where either the image we want to
reconstruct, :math:`\mb{x}`, or its measurements, :math:`\mb{y}`, do
not fit neatly into a multi-dimensional array. This is achieved via
:class:`.BlockArray` objects, which consist of a :class:`list` of
multi-dimensional array *blocks*. A :class:`.BlockArray` differs from
a :class:`list` in that, whenever possible, :class:`.BlockArray`
properties and methods (including unary and binary operators like
``+``, ``-``, ``*``, …) automatically map along the blocks, returning
another :class:`.BlockArray` or :class:`tuple` as appropriate. For
example, consider a system that measures the column sums and row sums
of an image. If the input image has shape :math:`M \times N`, the
resulting measurement will have shape :math:`M + N`, which is awkward
to represent as a multi-dimensional array. In SCICO, we can represent
this operator by

.. code:: python

       input_shape = (130, 50)
       H0 = scico.linop.Sum(input_shape, axis=0)
       H1 = scico.linop.Sum(input_shape, axis=1)
       H = scico.linop.VerticalStack((H0, H1))

The result of applying ``H`` to an image with shape ``(130, 50)`` is a
:class:`.BlockArray` with shape ``((50,), (130,))``. This result is
compatible with the rest of SCICO and may be used, e.g., as the input
of other operators.


Inverse Problem Formulation
---------------------------

In order to estimate the image from the measured data, we need to solve
an *inverse problem*. In its simplest form, the solution to such an
inverse problem can be expressed as the optimization problem

.. math:: \hat{\mb{x}} = \mathop{\mathrm{arg\,min}}_{\mb{x}} f( \mb{x} ) \,,

where :math:`\mb{x}` is the unknown image and :math:`\hat{\mb{x}}` is
the recovered image. A common choice of :math:`f` is

.. math:: f(\mb{x}) = (1/2) \| A(\mb{x}) - \mb{y} \|_2^2 \,,

where :math:`\mb{y}` is the measured data and :math:`A` is the
forward operator; in this case the minimization problem is a least
squares problem.

In SCICO, the :mod:`.functional` module provides implementations of common
functionals such as :math:`\ell_2` and :math:`\ell_1` norms. The
:mod:`.loss` module is used to implement a special type of functional

.. math:: f(\mb{x}) = \alpha l(A(\mb{x}),\mb{y}) \,,

where :math:`\alpha` is a scaling parameter and :math:`l(\cdot)` is
another functional. The SCICO :mod:`.loss` module contains a variety
of loss functionals that are commonly used in computational
imaging. For example, the squared :math:`\ell_2` loss written above
for a forward operator, :math:`A`, can be defined in SCICO using the
code:

.. code:: python

       f = scico.loss.SquaredL2Loss(y=y, A=A)

The difficulty of the inverse problem depends on the amount of noise in
the measured data and the properties of the forward operator. In
particular, if :math:`A` is a linear operator, then the difficulty of
the inverse problem depends significantly on the condition number of
:math:`A`, since a large condition number implies that large changes in
:math:`\mb{x}` can correspond to small changes in
:math:`\mb{y}`, making it difficult to estimate :math:`\mb{x}`
from :math:`\mb{y}`. When there is a significant amount of
measurement noise or ill-conditioning of :math:`A`, the standard
approach to resolve the limitations in the information available from
the measured data is to introduce a *prior model* of the solution space,
which is typically achieved by adding a *regularization term* to the
data fidelity term, resulting in the optimization problem

.. math:: \hat{\mb{x}} = \mathop{\mathrm{arg\,min}}_{\mb{x}} f(\mb{x}) + g(C (\mb{x})) \,,

where the functional :math:`g(C(\cdot))` is designed to increase the
cost for solutions that are considered less likely or desirable, based
on prior knowledge of the properties of the solution space. A common
choice of :math:`g(C(\cdot))` is the total variation norm

.. math:: g(\mb{x}) = \lambda \| C \mb{x} \|_{2,1} \,,

where :math:`\lambda` is a scalar controlling the regularization
strength, :math:`C` is a linear operator that computes the spatial
gradients of its argument, and :math:`\| \cdot \|_{2,1}` denotes the
:math:`\ell_{2,1}` norm, which promotes group sparsity. Use of this
functional as a regularization term corresponds to the assumption that
the images of interest are piecewise constant. In SCICO, we can
represent this regularization functional using a built-in linear
operator and a member of the :mod:`.functional` module:

.. code:: python

       C = scico.linop.FiniteDifference(A.input_shape, append=0)
       λ = 1.0e-1
       g = λ * scico.functional.L21Norm()

Computing the value of the regularizer then closely matches the math:
:code:`g(C(x))`.

Finally, the overall objective function needs to be optimized. One of
the primary goals of SCICO is to make the solution of such problems
accessible to application domain scientists with limited expertise in
computational imaging, providing infrastructure for solving this type of
problem efficiently, without the need for the user to implement complex
algorithms.


Solvers
-------

Once an inverse problem has been specified using the above components,
the resulting functional must be minimized in order to solve the
problem. SCICO provides a number of optimization algorithms for
addressing a wide range of problems. These optimization algorithms
belong to two distinct categories.


Basic Solvers
~~~~~~~~~~~~~

The :mod:`scico.solver` module provides a number of functions for
solving linear systems and simple optimization problems, some of which
are useful as subproblem solvers within the proximal algorithms
described in the following section. It also provides an interface to
functions in :mod:`scipy.optimize`, supporting their use with
multi-dimensional arrays and scico :class:`.Functional` objects. These
algorithms are useful both as subproblem solvers within the proximal
algorithms described below, as well as for direct solution of
higher-level problems.

For example,

.. code:: python

       f = scico.loss.PoissonLoss(y=y, A=A)
       method = 'BFGS' # or any method available for scipy.optimize.minimize
       x0 = scico.numpy.ones(A.input_shape)
       res = scico.solver.minimize(f, x0=x0, method=method)
       x_hat = res.x

defines a Poisson objective function and minimizes it using the BFGS
:cite:`nocedal-2006-numerical` algorithm.


Proximal Algorithms
~~~~~~~~~~~~~~~~~~~

The :mod:`scico.optimize` sub-package provides a set of *proximal
algorithms* :cite:`parikh-2014-proximal` that have proven to be useful
for solving imaging inverse problems. The common feature of these
algorithms is their exploitation of the *proximal operator*
:cite:`beck-2017-first` (Ch. 6), of the components of the functions
that they minimize.

**ADMM** The most flexible of the proximal algorithms supported by SCICO
is the alternating direction method of multipliers (ADMM)
:cite:`glowinski-1975-approximation` :cite:`gabay-1976-dual`
:cite:`boyd-2010-distributed`, which supports solving problems of the form

.. math:: \mathop{\mathrm{arg\,min}}_{\mb{x}} \; f(\mb{x}) + \sum_{i=1}^N g_i(C_i \mb{x}) \,.

When :math:`f(\cdot)` is an instance of ``scico.loss.SquaredL2Loss``,
i.e.,

.. math:: f(\mb{x}) = (1/2) \| A \mb{x} - \mb{y} \|_2^2 \,,

for linear operator :math:`A` and constant vector :math:`\mb{y}`,
the primary computational cost of the algorithm is typically in solving
a linear system involving a weighted sum of :math:`A^\top A` and the
:math:`C_i^\top C_i`, assuming that the proximal operators of the
functionals :math:`g_i(\cdot)` can be computed efficiently. This linear
system can also be solved efficiently when :math:`A` and all of the
:math:`C_i` are either identity operators or circular convolutions.

**Proximal ADMM** Proximal ADMM :cite:`deng-2015-global` solves problems of
the form

.. math::
    \argmin_{\mb{x}} \; f(\mb{x}) + g(\mb{z}) \;
    \text{such that}\; A \mb{x} + B \mb{z} = \mb{c} \;,

where :math:`A` and :math:`B` are linear operators. There is also a non-linear
PADMM solver :cite:`benning-2016-preconditioned` for problems of the form

.. math::
    \argmin_{\mb{x}} \; f(\mb{x}) + g(\mb{z}) \;
    \text{such that}\; H(\mb{x}, \mb{z}) = 0 \;,

where :math:`H` is a function. For some problems, proximal ADMM converges
substantially faster than ADMM or linearized ADMM.

**Linearized ADMM** Linearized ADMM :cite:`yang-2012-linearized`
:cite:`parikh-2014-proximal` solves a more restricted problem form,

.. math:: \mathop{\mathrm{arg\,min}}_{\mb{x}} \; f(\mb{x}) + g(C \mb{x}) \,.

It is an effective algorithm when the proximal operators of both
:math:`f(\cdot)` and :math:`g(\cdot)` can be computed efficiently, and
has the advantage over "standard" ADMM of avoiding the need for solving
a linear system involving :math:`C^\top C`.

**PDHG** Primal–dual hybrid gradient (PDHG) :cite:`esser-2010-general`
:cite:`chambolle-2010-firstorder` :cite:`pock-2011-diagonal` solves
the same form of problem as linearized ADMM

.. math:: \mathop{\mathrm{arg\,min}}_{\mb{x}} \; f(\mb{x}) + g(C \mb{x}) \,,

but unlike the linearized ADMM implementation, both linear and
non-linear operators :math:`C` are supported. For some problems, PDHG
converges substantially faster than ADMM or linearized ADMM.

**PGM and Accelerated PGM** The proximal gradient method (PGM)
:cite:`daubechies-2004-iterative` and accelerated proximal gradient method
(APGM), which is also known as FISTA :cite:`beck-2017-first`, solve problems
of the form

.. math:: \mathop{\mathrm{arg\,min}}_{\mb{x}} \; f(\mb{x}) + g(\mb{x}) \,,

where :math:`f(\cdot)` is assumed to be differentiable, and
:math:`g(\cdot)` is assumed to have a proximal operator that can be
computed efficiently. These algorithms typically require more iterations
for convergence than ADMM, but can provide faster convergence with time
when the linear solve required by ADMM is slow to compute.


Machine Learning
----------------

While relatively simple regularization terms such as the total
variation norm can be effective when the underlying assumptions are
well matched to the data (e.g., the reconstructed images for certain
materials science applications really are approximately piecewise
constant), it is difficult to design mathematically simple
regularization terms that adequately represent the properties of the
complex data that is often encountered in practice. A widely-used
alternative framework for regularizing the solution of imaging inverse
problems is *plug-and-play priors* (PPP)
:cite:`venkatakrishnan-2013-plugandplay2` :cite:`sreehari-2016-plug`
:cite:`kamilov-2023-plugandplay`, which provides a mechanism for
exploiting image denoisers such as BM3D :cite:`dabov-2008-image` as
implicit priors. With the rise of deep learning methods, PPP provided
one of the first frameworks for applying machine learning methods to
inverse problems via the use of learned denoisers such as DnCNN
:cite:`zhang-2017-dncnn`.

SCICO supports PPP inverse problems solutions with both BM3D and DnCNN
denoisers, and provides usage examples for both choices. BM3D is more
flexible, as it includes a tunable noise level parameter, while SCICO
only includes DnCNN models trained at three different noise levels (as
in the original DnCNN paper), but DnCNN has a significant speed
advantage when GPUs are available. As an example, the following code
outline demonstrates a PPP solution, with a non-negativity constraint
and a 17-layer DnCNN denoiser as a regularizer, of an inverse problem
with measurement, :math:`\mb{y}`, and a generic linear forward
operator, :math:`A`.

.. code:: python

       ρ = 0.3  # ADMM penalty parameter
       maxiter = 10 # number of ADMM iterations

       f = scico.loss.SquaredL2Loss(y=y, A=A)
       g1 = scico.functional.DnCNN("17M")
       g2 = scico.functional.NonNegativeIndicator()
       C = scico.linop.Identity(A.input_shape)

       solver = scico.optimize.admm.ADMM(
         f=f,
         g_list=[g1, g2],
         C_list=[C, C],
         rho_list=[ρ, ρ],
         x0=A.T @ y,
         maxiter=maxiter,
         subproblem_solver=scico.optimize.admm.LinearSubproblemSolver(),
         itstat_options={"display": True, "period": 5},
       )

       x_hat = solver.solve()

Example results for this type of approach applied to image deconvolution
(i.e. with forward operator, :math:`A`, as a convolution) are shown in
the figure below.

.. image:: /figures/deconv_ppp_dncnn.png
     :align: center
     :width: 95%
     :alt: Image deconvolution via PPP with DnCNN denoiser.

|

More recently, a wider variety of frameworks have been developed for
applying deep learning methods to inverse problems, including the
application of the adjoint of the forward operator to map the
measurement to the solution space followed by an artifact removal CNN
:cite:`jin-2017-unet`, and learned networks with structures based on
the unrolling of iterative algorithms such as PPP
:cite:`monga-2021-algorithm`. A number of these methods are currently
being implemented, and will be included in a future SCICO release. It
is worth noting, however, that while some of these methods offer
superior performance to PPP, it is at the cost of having to train the
models with problem-specific data, which may be difficult to obtain,
while PPP is often able to function well with a denoiser trained on
generic image data.


================================================
FILE: docs/source/notes.rst
================================================
*****
Notes
*****


Debugging
=========

If difficulties are encountered in debugging jitted functions, jit can
be globally disabled by setting the environment variable
``JAX_DISABLE_JIT=1`` before running Python, as in

::

   JAX_DISABLE_JIT=1 python test_script.py


Double Precision
================

By default, JAX enforces single-precision numbers. Double precision
can be enabled in one of two ways:

1. Setting the environment variable ``JAX_ENABLE_X64=TRUE`` before
   launching Python.
2. Manually setting the ``jax_enable_x64`` flag **at program
   startup**; that is, **before** importing SCICO.

::

   from jax.config import config
   config.update("jax_enable_x64", True)
   import scico # continue as usual


For more information, see the `JAX notes on double precision <https://jax.readthedocs.io/en/latest/notebooks/Common_Gotchas_in_JAX.html#double-64bit-precision>`_.

Device Control
==============

Use of the CPU device can be forced even when GPUs are present by setting the
environment variable ``JAX_PLATFORM_NAME=cpu`` before running Python. This also
serves to disable the warning that older versions of JAX issued when running
on a platform without a GPU, but this should no longer be necessary for any
JAX versions supported by SCICO.

By default, JAX views a multi-core CPU as a single device. Primarily for testing
purposes, it may be useful to instruct JAX to emulate multiple CPU devices, by
setting the environment variable ``XLA_FLAGS='--xla_force_host_platform_device_count=<n>'``,
where ``<n>`` is an integer number of devices. For more detail see the relevant
`section of the JAX docs <https://jax.readthedocs.io/en/latest/jax-101/06-parallelism.html#aside-hosts-and-devices-in-jax>`__.

By default, JAX will preallocate a large chunk of GPU memory on startup. This
behavior can be controlled using environment variables ``XLA_PYTHON_CLIENT_PREALLOCATE``,
``XLA_PYTHON_CLIENT_MEM_FRACTION``, and ``XLA_PYTHON_CLIENT_ALLOCATOR``, as described in
the relevant `section of the JAX docs <https://jax.readthedocs.io/en/latest/gpu_memory_allocation.html>`__.


Random Number Generation
========================

JAX implements an explicit, non-stateful pseudorandom number generator (PRNG).
The user is responsible for generating a PRNG key and mutating it each time a
new random number is generated. We recommend users read the `JAX documentation
<https://jax.readthedocs.io/en/latest/notebooks/Common_Gotchas_in_JAX.html#random-numbers>`_
for information on the design of JAX random number functionality.


In :mod:`scico.random` we provide convenient wrappers around several `jax.random
<https://jax.readthedocs.io/en/stable/jax.random.html>`_ routines to handle
the generation and splitting of PRNG keys.

::

   # Calls to scico.random functions always return a PRNG key
   # If no key is passed to the function, a new key is generated
   x, key = scico.random.randn((2,))
   print(x)   # [ 0.19307713 -0.52678305]

   # scico.random functions automatically split the PRNGkey and return
   # an updated key
   y, key = scico.random.randn((2,), key=key)
   print(y) # [ 0.00870693 -0.04888531]

The user is responsible for passing the PRNG key to
:mod:`scico.random` functions. If no key is passed, repeated calls to
:mod:`scico.random` functions will return the same random numbers:

::

   x, key = scico.random.randn((2,))
   print(x)   # [ 0.19307713 -0.52678305]

   # No key passed, will return the same random numbers!
   y, key = scico.random.randn((2,))
   print(y)   # [ 0.19307713 -0.52678305]



.. _non_jax_dep:

Compiled Dependency Packages
============================

The code acceleration and automatic differentiation features of JAX
are not available for some components of SCICO that are provided via
interfaces to compiled C code. When these components are used on a
platform with GPUs, the remainder of the code will run on a GPU, but
there is potential for a considerable delay due to host-GPU memory
transfers. This issue primarily affects:


Denoisers
---------

The :func:`.bm3d` and :func:`.bm4d` denoisers (and the corresponding
:class:`.BM3D` and :class:`.BM4D` pseudo-functionals) are implemented
via interfaces to the `bm3d <https://pypi.org/project/bm3d/>`__ and
`bm4d <https://pypi.org/project/bm4d/>`__ packages respectively. The
:class:`~.denoiser.DnCNN` denoiser (and the corresponding
:class:`~.functional.DnCNN` pseudo-functional) denoiser should be used
when the full benefits of JAX-based code are required.


Tomographic Projectors/Radon Transforms
---------------------------------------

Note that the tomographic projections that are frequently referred
to as Radon transforms are referred to as X-ray transforms in SCICO.
While the Radon transform is far more well-known than the X-ray
transform, which is the same as the Radon transform for projections
in two dimensions, these two transform differ in higher numbers of
dimensions, and it is the X-ray transform that is the appropriate
mathematical model for beam attenuation based imaging in three or
more dimensions.

SCICO includes three different implementations of X-ray transforms.
Of these, :class:`.linop.XRayTransform` is an integral component of
SCICO, while the other two depend on external packages.
The :class:`.xray.svmbir.XRayTransform` class is implemented
via an interface to the `svmbir
<https://svmbir.readthedocs.io/en/latest/>`__ package. The
:class:`.xray.astra.XRayTransform2D` and
:class:`.xray.astra.XRayTransform3D` classes are implemented via an
interface to the `ASTRA toolbox
<https://www.astra-toolbox.com/>`__. This toolbox does provide some
GPU acceleration support, but efficiency is expected to be lower than
JAX-based code due to host-GPU memory transfers.


Automatic Differentiation Caveats
=================================


Complex Functions
-----------------

The JAX-defined gradient of a complex-valued function is a
complex-conjugated version of the usual gradient used in mathematical
optimization and computational imaging. Minimizing a function using
the JAX convention involves taking steps in the direction of the
complex conjugated gradient.

The function :func:`scico.grad` returns the expected gradient, that
is, the conjugate of the JAX gradient. For further discussion, see
this `JAX issue <https://github.com/google/jax/issues/4891>`_.

As a concrete example, consider the function :math:`f(x) =
\frac{1}{2}\norm{\mb{A} \mb{x}}_2^2` where :math:`\mb{A}` is a complex
matrix. The gradient of :math:`f` is usually given :math:`(\nabla
f)(\mb{x}) = \mb{A}^H \mb{A} \mb{x}`, where :math:`\mb{A}^H` is the
conjugate transpose of :math:`\mb{A}`. Applying :func:`jax.grad` to
:math:`f` will yield :math:`(\mb{A}^H \mb{A} \mb{x})^*`, where
:math:`\cdot^*` denotes complex conjugation.

The following code demonstrates the use of :func:`jax.grad` and
:func:`scico.grad`:


::

    m, n = (4, 3)
    A, key = randn((m, n), dtype=np.complex64, key=None)
    x, key = randn((n,), dtype=np.complex64, key=key)

    def f(x):
        return 0.5 * snp.linalg.norm(A @ x)**2

    an_grad = A.conj().T @ A @ x  # The expected gradient

    np.testing.assert_allclose(jax.grad(f)(x), an_grad.conj(), rtol=1e-4)
    np.testing.assert_allclose(scico.grad(f)(x), an_grad, rtol=1e-4)


Non-differentiable Functionals
------------------------------

:func:`scico.grad` can be applied to any function, but has undefined
behavior for non-differentiable functions. For non-differerentiable
functions, :func:`scico.grad` may or may not return a valid
subgradient. As an example, ``scico.grad(snp.abs)(0.) = 0``, which is
a valid subgradient. However, ``scico.grad(snp.linalg.norm)([0., 0.])
= [nan, nan]``.

Differentiable functions that are written as the composition of a
differentiable and non-differentiable function should be avoided. As
an example, :math:`f(x) = \norm{x}_2^2` can be implemented in as ``f =
lambda x: snp.linalg.norm(x)**2``. This involves first calculating the
non-squared :math:`\ell_2` norm, then squaring it. The un-squared
:math:`\ell_2` norm is not differentiable at zero. When evaluating
the gradient of ``f`` at 0, :func:`scico.grad` returns :data:`~numpy.NaN`:

::

   >>> import scico
   >>> import scico.numpy as snp
   >>> f = lambda x: snp.linalg.norm(x)**2
   >>> scico.grad(f)(snp.zeros(2, dtype=snp.float32))  # doctest: +SKIP
   Array([nan, nan], dtype=float32)

This can be fixed (assuming real-valued arrays only) by defining the
squared :math:`\ell_2` norm directly as ``g = lambda x: snp.sum(x**2)``.
The gradient will work as expected:

::

   >>> g = lambda x: snp.sum(x**2)
   >>> scico.grad(g)(snp.zeros(2, dtype=snp.float32))  #doctest: +SKIP
   Array([0., 0.], dtype=float32)

If complex-valued arrays also need to be supported, a minor modification is
necessary:

::

   >>> g = lambda x: snp.sum(snp.abs(x)**2)
   >>> scico.grad(g)(snp.zeros(2, dtype=snp.float32))  #doctest: +SKIP
   Array([0., 0.], dtype=float32)
   >>> scico.grad(g)(snp.zeros(2, dtype=snp.complex64))  #doctest: +SKIP
   Array([0.-0.j, 0.-0.j], dtype=complex64)


An alternative is to define a `custom derivative rule
<https://jax.readthedocs.io/en/latest/notebooks/Custom_derivative_rules_for_Python_code.html#enforcing-a-differentiation-convention>`_
to enforce a particular derivative convention at a point.


JAX Arrays
==========

JAX utilizes a new array type :class:`~jax.Array`, which is similar to
NumPy :class:`~numpy.ndarray`, but can be backed by CPU, GPU, or TPU
memory and is immutable.


JAX and NumPy Arrays
--------------------

SCICO and JAX functions can be applied directly to NumPy arrays
without explicit conversion to JAX arrays, but this is not
recommended, as it can result in repeated data transfers from the CPU
to GPU. Consider this toy example on a system with a GPU present:

::

   x = np.random.randn(8)    # Array on host
   A = np.random.randn(8, 8) # Array on host
   y = snp.dot(A, x)         # A, x transfered to GPU
                             # y resides on GPU
   z = y + x                 # x must be transfered to GPU again


The unnecessary transfer can be avoided by first converting ``A`` and ``x`` to
JAX arrays:

::

   x = np.random.randn(8)    # array on host
   A = np.random.randn(8, 8) # array on host
   x = jax.device_put(x)     # transfer to GPU
   A = jax.device_put(A)
   y = snp.dot(A, x)         # no transfer needed
   z = y + x                 # no transfer needed


We recommend that input data be converted to JAX arrays via
:func:`jax.device_put` before calling any SCICO optimizers.

On a multi-GPU system, :func:`jax.device_put` can place data on a specific
GPU. See the `JAX notes on data placement
<https://jax.readthedocs.io/en/latest/faq.html?highlight=data%20placement#controlling-data-and-computation-placement-on-devices>`_.


JAX Arrays are Immutable
------------------------

Unlike standard NumPy arrays, JAX arrays are immutable: once they have
been created, they cannot be changed. This prohibits in-place updating
of JAX arrays. JAX provides special syntax for updating individual
array elements through the `indexed update operators
<https://jax.readthedocs.io/en/latest/jax.ops.html#syntactic-sugar-for-indexed-update-operators>`_.


================================================
FILE: docs/source/overview.rst
================================================
Overview
========

`Scientific Computational Imaging Code (SCICO)
<https://github.com/lanl/scico>`__ is a Python package for solving the
inverse problems that arise in scientific imaging applications. Its
primary focus is providing methods for solving ill-posed inverse
problems by using an appropriate prior model of the reconstruction
space. SCICO includes a growing suite of operators, cost functionals,
regularizers, and optimization algorithms that may be combined to
solve a wide range of problems, and is designed so that it is easy to
add new building blocks. When solving a problem, these components are
combined in a way that makes code for optimization routines look like
the pseudocode in scientific papers. SCICO is built on top of `JAX
<https://jax.readthedocs.io/en/latest/>`__ rather than `NumPy
<https://numpy.org/>`__, enabling GPU/TPU acceleration, just-in-time
compilation, and automatic gradient functionality, which is used to
automatically compute the adjoints of linear operators. An example of
how to solve a multi-channel tomography problem with SCICO is shown in
the figure below.


.. image:: /figures/scico-tomo-overview.png
     :align: center
     :width: 95%
     :alt: Solving a multi-channel tomography problem with SCICO.

|

The SCICO source code is available from `GitHub
<https://github.com/lanl/scico>`__, and pre-built packages are
available from `PyPI <https://github.com/lanl/scico>`__. (Detailed
instructions for installing SCICO are available in :ref:`installing`.)
It has extensive `online documentation <https://scico.rtfd.io/>`__,
including :doc:`API documentation <_autosummary/scico>` and
:ref:`usage examples <example_notebooks>`, which can be run online at
`Google Colab
<https://colab.research.google.com/github/lanl/scico-data/blob/colab/notebooks/index.ipynb>`__
and `binder
<https://mybinder.org/v2/gh/lanl/scico-data/binder?labpath=notebooks%2Findex.ipynb>`__.


If you use this package for published work, please cite
:cite:`balke-2022-scico` (see bibtex entry ``balke-2022-scico`` in
`docs/source/references.bib
<https://github.com/lanl/scico/blob/main/docs/source/references.bib>`_
in the source distribution).



Contributing
------------

Bug reports, feature requests, and general suggestions are welcome,
and should be submitted via the `GitHub issue system
<https://github.com/lanl/scico/issues>`__. More substantial
contributions are also :ref:`welcome <scico_dev_contributing>`.



License
-------

SCICO is distributed as open-source software under a BSD 3-Clause
License (see the `LICENSE
<https://github.com/lanl/scico/blob/master/LICENSE>`__ file for
details). LANL open source approval reference C20091.

© 2020-2025. Triad National Security, LLC. All rights reserved.
This program was produced under U.S. Government contract
89233218CNA000001 for Los Alamos National Laboratory (LANL), which is
operated by Triad National Security, LLC for the U.S. Department of
Energy/National Nuclear Security Administration.  All rights in the
program are reserved by Triad National Security, LLC, and the
U.S. Department of Energy/National Nuclear Security Administration.
The Government has granted for itself and others acting on its behalf
a nonexclusive, paid-up, irrevocable worldwide license in this
material to reproduce, prepare derivative works, distribute copies to
the public, perform publicly and display publicly, and to permit
others to do so.


================================================
FILE: docs/source/pyfigures/cylindgrad.py
================================================
import numpy as np

import scico.linop as scl
from scico import plot

input_shape = (7, 7, 7)
centre = (np.array(input_shape) - 1) / 2
end = np.array(input_shape) - centre
g0, g1, g2 = np.mgrid[-centre[0] : end[0], -centre[1] : end[1], -centre[2] : end[2]]

cg = scl.CylindricalGradient(input_shape=input_shape)

ang = cg.coord[0]
rad = cg.coord[1]
axi = cg.coord[2]

theta = np.arctan2(g0, g1)
clr = theta
# See https://stackoverflow.com/a/49888126
clr = (clr.ravel() - clr.min()) / np.ptp(clr)
clr = np.concatenate((clr, np.repeat(clr, 2)))
clr = plot.plt.cm.plasma(clr)

plot.plt.rcParams["savefig.transparent"] = True

fig = plot.plt.figure(figsize=(20, 6))
ax = fig.add_subplot(1, 3, 1, projection="3d")
ax.quiver(g0, g1, g2, ang[0], ang[1], ang[2], colors=clr, length=0.9)
ax.set_title("Angular local coordinate axis", fontsize=18)
ax.set_xlabel("$x$", fontsize=15)
ax.set_ylabel("$y$", fontsize=15)
ax.set_zlabel("$z$", fontsize=15)
ax.tick_params(labelsize=15)
ax = fig.add_subplot(1, 3, 2, projection="3d")
ax.quiver(g0, g1, g2, rad[0], rad[1], rad[2], colors=clr, length=0.9)
ax.set_title("Radial local coordinate axis", fontsize=18)
ax.set_xlabel("$x$", fontsize=15)
ax.set_ylabel("$y$", fontsize=15)
ax.set_zlabel("$z$", fontsize=15)
ax.tick_params(labelsize=15)
ax = fig.add_subplot(1, 3, 3, projection="3d")
ax.quiver(g0, g1, g2, axi[0], axi[1], axi[2], colors=clr[0], length=0.9)
ax.set_title("Axial local coordinate axis", fontsize=18)
ax.set_xlabel("$x$", fontsize=15)
ax.set_ylabel("$y$", fontsize=15)
ax.set_zlabel("$z$", fontsize=15)
ax.tick_params(labelsize=15)
fig.tight_layout()
fig.show()


================================================
FILE: docs/source/pyfigures/polargrad.py
================================================
import numpy as np

import scico.linop as scl
from scico import plot

input_shape = (21, 21)
centre = (np.array(input_shape) - 1) / 2
end = np.array(input_shape) - centre
g0, g1 = np.mgrid[-centre[0] : end[0], -centre[1] : end[1]]

pg = scl.PolarGradient(input_shape=input_shape)

ang = pg.coord[0]
rad = pg.coord[1]

clr = (np.arctan2(ang[1], ang[0]) + np.pi) / (2 * np.pi)

plot.plt.rcParams["image.cmap"] = "plasma"
plot.plt.rcParams["savefig.transparent"] = True

fig, ax = plot.plt.subplots(nrows=1, ncols=2, figsize=(13, 6))
ax[0].quiver(g0, g1, ang[0], ang[1], clr)
ax[0].set_title("Angular local coordinate axis", fontsize=16)
ax[0].set_xlabel("$x$", fontsize=14)
ax[0].set_ylabel("$y$", fontsize=14)
ax[0].tick_params(labelsize=14)
ax[0].xaxis.set_ticks((-10, -5, 0, 5, 10))
ax[0].yaxis.set_ticks((-10, -5, 0, 5, 10))
ax[1].quiver(g0, g1, rad[0], rad[1], clr)
ax[1].set_title("Radial local coordinate axis", fontsize=16)
ax[1].set_xlabel("$x$", fontsize=14)
ax[1].set_ylabel("$y$", fontsize=14)
ax[1].tick_params(labelsize=14)
ax[1].xaxis.set_ticks((-10, -5, 0, 5, 10))
ax[1].yaxis.set_ticks((-10, -5, 0, 5, 10))
fig.tight_layout()
fig.show()


================================================
FILE: docs/source/pyfigures/spheregrad.py
================================================
import numpy as np

import scico.linop as scl
from scico import plot

input_shape = (7, 7, 7)
centre = (np.array(input_shape) - 1) / 2
end = np.array(input_shape) - centre
g0, g1, g2 = np.mgrid[-centre[0] : end[0], -centre[1] : end[1], -centre[2] : end[2]]

sg = scl.SphericalGradient(input_shape=input_shape)

azi = sg.coord[0]
pol = sg.coord[1]
rad = sg.coord[2]

theta = np.arctan2(g0, g1)
phi = np.arctan2(np.sqrt(g0**2 + g1**2), g2)
clr = theta * phi
# See https://stackoverflow.com/a/49888126
clr = (clr.ravel() - clr.min()) / np.ptp(clr)
clr = np.concatenate((clr, np.repeat(clr, 2)))
clr = plot.plt.cm.plasma(clr)

plot.plt.rcParams["savefig.transparent"] = True

fig = plot.plt.figure(figsize=(20, 6))
ax = fig.add_subplot(1, 3, 1, projection="3d")
ax.quiver(g0, g1, g2, azi[0], azi[1], azi[2], colors=clr, length=0.9)
ax.set_title("Azimuthal local coordinate axis", fontsize=18)
ax.set_xlabel("$x$", fontsize=15)
ax.set_ylabel("$y$", fontsize=15)
ax.set_zlabel("$z$", fontsize=15)
ax.tick_params(labelsize=15)
ax = fig.add_subplot(1, 3, 2, projection="3d")
ax.quiver(g0, g1, g2, pol[0], pol[1], pol[2], colors=clr, length=0.9)
ax.set_title("Polar local coordinate axis", fontsize=18)
ax.set_xlabel("$x$", fontsize=15)
ax.set_ylabel("$y$", fontsize=15)
ax.set_zlabel("$z$", fontsize=15)
ax.tick_params(labelsize=15)
ax = fig.add_subplot(1, 3, 3, projection="3d")
ax.quiver(g0, g1, g2, rad[0], rad[1], rad[2], colors=clr, length=0.9)
ax.set_title("Radial local coordinate axis", fontsize=18)
ax.set_xlabel("$x$", fontsize=15)
ax.set_ylabel("$y$", fontsize=15)
ax.set_zlabel("$z$", fontsize=15)
ax.tick_params(labelsize=15)
fig.tight_layout()
fig.show()


================================================
FILE: docs/source/pyfigures/xray_2d_geom.py
================================================
import numpy as np

import matplotlib as mpl
import matplotlib.patches as patches
import matplotlib.pyplot as plt

mpl.rcParams["savefig.transparent"] = True


c = 1.0 / np.sqrt(2.0)
e = 1e-2
style = "Simple, tail_width=0.5, head_width=4, head_length=8"
fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(21, 7))

# all plots
for n in range(3):
    ax[n].set_aspect(1.0)
    ax[n].set_xlim(-1.1, 1.1)
    ax[n].set_ylim(-1.1, 1.1)
    ax[n].set_xticks(np.linspace(-1.0, 1.0, 5))
    ax[n].set_yticks(np.linspace(-1.0, 1.0, 5))
    ax[n].tick_params(axis="x", labelsize=14)
    ax[n].tick_params(axis="y", labelsize=14)
    ax[n].set_xlabel("axis 1", fontsize=16)
    ax[n].set_ylabel("axis 0", fontsize=16)


# scico
ax[0].set_title("scico", fontsize=18)
plist = [
    patches.FancyArrowPatch((-1.0, 0.0), (-0.5, 0.0), arrowstyle=style, color="r"),
    patches.FancyArrowPatch((-c, -c), (-c / 2.0, -c / 2.0), arrowstyle=style, color="r"),
    patches.FancyArrowPatch(
        (
            0.0,
            -1.0,
        ),
        (0.0, -0.5),
        arrowstyle=style,
        color="r",
    ),
    patches.Arc((0.0, 0.0), 2.0, 2.0, theta1=180, theta2=-45.0, color="b", lw=2, ls="dotted"),
    patches.FancyArrowPatch((c - e, -c - e), (c + e, -c + e), arrowstyle=style, color="b"),
]
for p in plist:
    ax[0].add_patch(p)

ax[0].text(-0.88, 0.02, r"$\theta=0$", color="r", fontsize=16)
ax[0].text(-3 * c / 4 - 0.01, -3 * c / 4 - 0.1, r"$\theta=\frac{\pi}{4}$", color="r", fontsize=16)
ax[0].text(0.03, -0.8, r"$\theta=\frac{\pi}{2}$", color="r", fontsize=16)

ax[0].plot((1.0, 1.0), (-0.375, 0.375), color="orange", lw=2)
ax[0].arrow(
    0.94,
    0.375,
    0.0,
    -0.75,
    color="orange",
    lw=1.0,
    ls="--",
    head_width=0.03,
    length_includes_head=True,
)
ax[0].text(0.7, 0.0, r"$\theta=0$", color="orange", ha="left", fontsize=16)
ax[0].plot((-0.375, 0.375), (1.0, 1.0), color="orange", lw=2)
ax[0].arrow(
    -0.375,
    0.94,
    0.75,
    0.0,
    color="orange",
    lw=1.0,
    ls="--",
    head_width=0.03,
    length_includes_head=True,
)
ax[0].text(0.0, 0.82, r"$\theta=\frac{\pi}{2}$", color="orange", ha="center", fontsize=16)


# astra
ax[1].set_title("astra", fontsize=18)
plist = [
    patches.FancyArrowPatch((0.0, -1.0), (0.0, -0.5), arrowstyle=style, color="r"),
    patches.FancyArrowPatch((c, -c), (c / 2.0, -c / 2.0), arrowstyle=style, color="r"),
    patches.FancyArrowPatch((1.0, 0.0), (0.5, 0.0), arrowstyle=style, color="r"),
    patches.Arc((0.0, 0.0), 2.0, 2.0, theta1=-90, theta2=45.0, color="b", lw=2, ls="dotted"),
    patches.FancyArrowPatch((c + e, c - e), (c - e, c + e), arrowstyle=style, color="b"),
]
for p in plist:
    ax[1].add_patch(p)

ax[1].text(0.02, -0.75, r"$\theta=0$", color="r", fontsize=16)
ax[1].text(3 * c / 4 + 0.01, -3 * c / 4 + 0.01, r"$\theta=\frac{\pi}{4}$", color="r", fontsize=16)
ax[1].text(0.65, 0.05, r"$\theta=\frac{\pi}{2}$", color="r", fontsize=16)

ax[1].plot((-0.375, 0.375), (1.0, 1.0), color="orange", lw=2)
ax[1].arrow(
    -0.375,
    0.94,
    0.75,
    0.0,
    color="orange",
    lw=1.0,
    ls="--",
    head_width=0.03,
    length_includes_head=True,
)
ax[1].text(0.0, 0.82, r"$\theta=0$", color="orange", ha="center", fontsize=16)
ax[1].plot((-1.0, -1.0), (-0.375, 0.375), color="orange", lw=2)
ax[1].arrow(
    -0.94,
    -0.375,
    0.0,
    0.75,
    color="orange",
    lw=1.0,
    ls="--",
    head_width=0.03,
    length_includes_head=True,
)
ax[1].text(-0.9, 0.0, r"$\theta=\frac{\pi}{2}$", color="orange", ha="left", fontsize=16)


# svmbir
ax[2].set_title("svmbir", fontsize=18)
plist = [
    patches.FancyArrowPatch((-1.0, 0.0), (-0.5, 0.0), arrowstyle=style, color="r"),
    patches.FancyArrowPatch((-c, c), (-c / 2.0, c / 2.0), arrowstyle=style, color="r"),
    patches.FancyArrowPatch(
        (
            0.0,
            1.0,
        ),
        (0.0, 0.5),
        arrowstyle=style,
        color="r",
    ),
    patches.Arc((0.0, 0.0), 2.0, 2.0, theta1=45, theta2=180, color="b", lw=2, ls="dotted"),
    patches.FancyArrowPatch((c - e, c + e), (c + e, c - e), arrowstyle=style, color="b"),
]
for p in plist:
    ax[2].add_patch(p)
ax[2].text(-0.88, 0.02, r"$\theta=0$", color="r", fontsize=16)
ax[2].text(-3 * c / 4 + 0.01, 3 * c / 4 + 0.01, r"$\theta=\frac{\pi}{4}$", color="r", fontsize=16)
ax[2].text(0.03, 0.75, r"$\theta=\frac{\pi}{2}$", color="r", fontsize=16)

ax[2].plot((1.0, 1.0), (-0.375, 0.375), color="orange", lw=2)
ax[2].arrow(
    0.94,
    0.375,
    0.0,
    -0.75,
    color="orange",
    lw=1.0,
    ls="--",
    head_width=0.03,
    length_includes_head=True,
)
ax[2].text(0.7, 0.0, r"$\theta=0$", color="orange", ha="left", fontsize=16)

ax[2].plot((-0.375, 0.375), (-1.0, -1.0), color="orange", lw=2)
ax[2].arrow(
    0.375,
    -0.94,
    -0.75,
    0.0,
    color="orange",
    lw=1.0,
    ls="--",
    head_width=0.03,
    length_includes_head=True,
)
ax[2].text(0.0, -0.82, r"$\theta=\frac{\pi}{2}$", color="orange", ha="center", fontsize=16)


fig.tight_layout()
fig.show()


================================================
FILE: docs/source/pyfigures/xray_3d_ang.py
================================================
import numpy as np

import matplotlib as mpl
import matplotlib.patches as patches
import matplotlib.pyplot as plt

mpl.rcParams["savefig.transparent"] = True


c = 1.0 / np.sqrt(2.0)
e = 1e-2
style = "Simple, tail_width=0.5, head_width=4, head_length=8"
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(5, 5))
ax.set_aspect(1.0)
ax.set_xlim(-1.1, 1.1)
ax.set_ylim(-1.1, 1.1)
ax.set_xticks(np.linspace(-1.0, 1.0, 5))
ax.set_yticks(np.linspace(-1.0, 1.0, 5))
ax.tick_params(axis="x", labelsize=12)
ax.tick_params(axis="y", labelsize=12)
ax.set_xlabel("$x$", fontsize=14)
ax.set_ylabel("$y$", fontsize=14)

plist = [
    patches.FancyArrowPatch((0.0, -1.0), (0.0, -0.5), arrowstyle=style, color="r"),
    patches.FancyArrowPatch((c, -c), (c / 2.0, -c / 2.0), arrowstyle=style, color="r"),
    patches.FancyArrowPatch((1.0, 0.0), (0.5, 0.0), arrowstyle=style, color="r"),
    patches.Arc((0.0, 0.0), 2.0, 2.0, theta1=-90, theta2=45.0, color="b", lw=2, ls="dotted"),
    patches.FancyArrowPatch((c + e, c - e), (c - e, c + e), arrowstyle=style, color="b"),
]
for p in plist:
    ax.add_patch(p)
ax.text(0.02, -0.75, r"$\theta=0$", color="r", fontsize=14)
ax.text(
    3 * c / 4 + 0.01,
    -3 * c / 4 + 0.01,
    r"$\theta=\frac{\pi}{4}$",
    color="r",
    fontsize=14,
)
ax.text(0.65, 0.05, r"$\theta=\frac{\pi}{2}$", color="r", fontsize=14)

ax.plot((-0.375, 0.375), (1.0, 1.0), color="orange", lw=2)
ax.arrow(
    -0.375,
    0.94,
    0.75,
    0.0,
    color="orange",
    lw=0.5,
    ls="--",
    head_width=0.03,
    length_includes_head=True,
)
ax.text(0.0, 0.82, r"$\theta=0$", color="orange", ha="center", fontsize=14)

ax.plot((-1.0, -1.0), (-0.375, 0.375), color="orange", lw=2)
ax.arrow(
    -0.94,
    -0.375,
    0.0,
    0.75,
    color="orange",
    lw=0.5,
    ls="--",
    head_width=0.03,
    length_includes_head=True,
)
ax.text(-0.9, 0.0, r"$\theta=\frac{\pi}{2}$", color="orange", ha="left", fontsize=14)

fig.tight_layout()
fig.show()


================================================
FILE: docs/source/pyfigures/xray_3d_vec.py
================================================
import numpy as np

import matplotlib as mpl
from matplotlib import pyplot as plt
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d

mpl.rcParams["savefig.transparent"] = True


# See https://github.com/matplotlib/matplotlib/issues/21688
class Arrow3D(FancyArrowPatch):
    def __init__(self, xs, ys, zs, *args, **kwargs):
        FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs)
        self._verts3d = xs, ys, zs

    def do_3d_projection(self, renderer=None):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
        self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))

        return np.min(zs)


# Define vector components
𝜃 = 10 * np.pi / 180.0  # angle in x-y plane (azimuth angle)
𝛼 = 70 * np.pi / 180.0  # angle with z axis (zenith angle)
𝛥p, 𝛥d = 0.3, 1.0
d = (-𝛥d * np.sin(𝛼) * np.sin(𝜃), 𝛥d * np.sin(𝛼) * np.cos(𝜃), 𝛥d * np.cos(𝛼))
u = (𝛥p * np.cos(𝜃), 𝛥p * np.sin(𝜃), 0.0)
v = (𝛥p * np.cos(𝛼) * np.sin(𝜃), -𝛥p * np.cos(𝛼) * np.cos(𝜃), 𝛥p * np.sin(𝛼))

# Location of text labels
d_txtpos = np.array(d) + np.array([0, 0, -0.12])
u_txtpos = np.array(d) + np.array(u) + np.array([0, 0, -0.1])
v_txtpos = np.array(d) + np.array(v) + np.array([0, 0, 0.03])


arrowstyle = "-|>,head_width=2.5,head_length=9"

fig, ax = plt.subplots(subplot_kw={"projection": "3d"})

# Set view
ax.set_aspect("equal")
ax.elev = 15
ax.azim = -50
ax.set_box_aspect(None, zoom=2)
ax.set_xlim((-1.1, 1.1))
ax.set_ylim((-1.1, 1.1))
ax.set_zlim((-1.1, 1.1))

# Disable shaded 3d axis grids
ax.set_axis_off()

# Draw central x,y,z axes and labels
axis_crds = np.array([[-1, 1], [0, 0], [0, 0]])
axis_lbls = ("$x$", "$y$", "$z$")
for k in range(3):
    crd = np.roll(axis_crds, k, axis=0)
    ax.add_artist(
        Arrow3D(
            *crd.tolist(),
            lw=1.5,
            ls="--",
            arrowstyle=arrowstyle,
            color="black",
        )
    )
    ax.text(*(1.05 * crd[:, 1]).tolist(), axis_lbls[k], fontsize=12)

# Draw d, u, v and labels
ax.quiver(0, 0, 0, *d, arrow_length_ratio=0.08, lw=2, color="blue")
ax.quiver(*d, *u, arrow_length_ratio=0.08 / 𝛥p, lw=2, color="blue")
ax.quiver(*d, *v, arrow_length_ratio=0.08 / 𝛥p, lw=2, color="blue")
ax.text(*d_txtpos, r"$\mathbf{d}$", fontsize=12)
ax.text(*u_txtpos, r"$\mathbf{u}$", fontsize=12)
ax.text(*v_txtpos, r"$\mathbf{v}$", fontsize=12)

fig.tight_layout()
fig.subplots_adjust(-0.1, -0.06, 1, 1)
fig.show()


================================================
FILE: docs/source/pyfigures/xray_3d_vol.py
================================================
import numpy as np

import matplotlib as mpl
from matplotlib import pyplot as plt
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d

mpl.rcParams["savefig.transparent"] = True


# See https://github.com/matplotlib/matplotlib/issues/21688
class Arrow3D(FancyArrowPatch):
    def __init__(self, xs, ys, zs, *args, **kwargs):
        FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs)
        self._verts3d = xs, ys, zs

    def do_3d_projection(self, renderer=None):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
        self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))

        return np.min(zs)


# Define vector components
𝜃 = 10 * np.pi / 180.0  # angle in x-y plane (azimuth angle)
𝛼 = 70 * np.pi / 180.0  # angle with z axis (zenith angle)
𝛥p, 𝛥d = 0.3, 1.0
d = (-𝛥d * np.sin(𝛼) * np.sin(𝜃), 𝛥d * np.sin(𝛼) * np.cos(𝜃), 𝛥d * np.cos(𝛼))
u = (𝛥p * np.cos(𝜃), 𝛥p * np.sin(𝜃), 0.0)
v = (𝛥p * np.cos(𝛼) * np.sin(𝜃), -𝛥p * np.cos(𝛼) * np.cos(𝜃), 𝛥p * np.sin(𝛼))

# Location of text labels
d_txtpos = np.array(d) + np.array([0, 0, -0.12])
u_txtpos = np.array(d) + np.array(u) + np.array([0, 0, -0.1])
v_txtpos = np.array(d) + np.array(v) + np.array([0, 0, 0.03])


arrowstyle = "-|>,head_width=2.5,head_length=9"

fig, ax = plt.subplots(subplot_kw={"projection": "3d"})

# Set view
ax.set_aspect("equal")
ax.elev = 40
ax.azim = -60
ax.set_box_aspect(None, zoom=1.8)
ax.set_xlim((-10.5, 10.5))
ax.set_ylim((-10.5, 10.5))
ax.set_zlim((-10.5, 10.5))

# Disable shaded 3d axis grids
ax.set_axis_off()

# Draw central x,y,z axes and labels
axis_crds = np.array([[-10, 10], [0, 0], [0, 0]])
axis_lbls = ("$x$", "$y$", "$z$")
for k in range(3):
    crd = np.roll(axis_crds, k, axis=0)
    ax.add_artist(
        Arrow3D(
            *crd.tolist(),
            lw=1.5,
            ls="--",
            arrowstyle=arrowstyle,
            color="black",
        )
    )
    ax.text(*(1.05 * crd[:, 1]).tolist(), axis_lbls[k], fontsize=12)

wx = 4
wy = 3
wz = 2
bx = np.array([-wx, wx, wx, wx, -wx, -wx, -wx])
by = np.array([-wy, -wy, wy, wy, wy, -wy, -wy])
bz = np.array([-wz, -wz, -wz, wz, wz, wz, -wz])
ax.plot(bx, by, bz, lw=2, color="blue")
ax.plot(bx[0:3], by[0:3], -bz[0:3], lw=2, color="blue")
bx = np.array([wx, wx])
by = np.array([-wy, -wy])
bz = np.array([-wz, wz])
ax.plot(bx, by, bz, lw=2, color="blue")
bx = np.array([-wx, -wx, wx])
by = np.array([-wy, wy, wy])
bz = np.array([-wz, -wz, -wz])
ax.plot(bx, by, bz, lw=2, ls="--", color="blue")
bx = np.array([-wx, -wx])
by = np.array([wy, wy])
bz = np.array([-wz, wz])
ax.plot(bx, by, bz, lw=2, ls="--", color="blue")

fig.tight_layout()
fig.subplots_adjust(-0.1, -0.1, 1, 1.07)
fig.show()


================================================
FILE: docs/source/references.bib
================================================
@Article {aggarwal-2019-modl,
  author =	 {Aggarwal, Hemant K. and Mani, Merry P. and Jacob,
                  Mathews},
  journal =	 {IEEE Transactions on Medical Imaging},
  title =	 {{MoDL}: Model-Based Deep Learning Architecture for
                  Inverse Problems},
  year =	 2019,
  volume =	 38,
  number =	 2,
  pages =	 {394--405},
  doi =		 {10.1109/TMI.2018.2865356}
}

@Article {alliney-1992-digital,
  author =	 {Alliney, Stefano},
  journal =	 {IEEE Transactions on Signal Processing},
  title =	 {Digital filters as absolute norm regularizers},
  year =	 1992,
  volume =	 40,
  number =	 6,
  pages =	 {1548--1562},
  doi =		 {10.1109/78.139258},
  month =	 Jun
}

@Article {almeida-2013-deconvolving,
  author =	 {Almeida, Mariana S. C. and Figueiredo, M\'ario},
  journal =	 {IEEE Transactions on Image Processing},
  title =	 {Deconvolving Images With Unknown Boundaries Using
                  the Alternating Direction Method of Multipliers},
  year =	 2013,
  month =	 Aug,
  volume =	 22,
  number =	 8,
  pages =	 {3074--3086},
  doi =		 {10.1109/TIP.2013.2258354}
}

@Article {antipa-2018-diffusercam,
  author =	 {Nick Antipa and Grace Kuo and Reinhard Heckel and
                  Ben Mildenhall and Emrah Bostan and Ren Ng and Laura
                  Waller},
  title =	 {{DiffuserCam}: lensless single-exposure 3{D}
                  imaging},
  journal =	 {Optica},
  year =	 2018,
  month =	 Jan,
  volume =	 5,
  number =	 1,
  doi =		 {10.1364/optica.5.000001},
  pages =	 {1--9}
}

@Article {balke-2022-scico,
  author =	 {Thilo Balke and Fernando Davis and Cristina
                  Garcia-Cardona and Soumendu Majee and Michael McCann
                  and Luke Pfister and Brendt Wohlberg},
  title =	 {Scientific Computational Imaging Code ({SCICO})},
  journal =	 {Journal of Open Source Software},
  year =	 2022,
  volume =	 7,
  number =	 78,
  pages =	 4722,
  doi =		 {10.21105/joss.04722}
}

@Article {barzilai-1988-stepsize,
  author =	 {Jonathan Barzilai and Jonathan M. Borwein},
  title =	 {Two-point step size gradient methods},
  journal =	 {{IMA} Journal of Numerical Analysis},
  volume =	 8,
  pages =	 {141--148},
  year =	 1988,
  month =	 Jan,
  doi =		 {10.1093/imanum/8.1.141}
}

@Article {beck-2009-fast,
  title =	 {A Fast Iterative Shrinkage-Thresholding Algorithm
                  for Linear Inverse Problems},
  author =	 {Beck, Amir and Teboulle, Marc},
  journal =	 {SIAM Journal on Imaging Sciences},
  year =	 2009,
  volume =	 2,
  number =	 1,
  pages =	 {183--202},
  doi =		 {10.1137/080716542}
}

@Article {beck-2009-tv,
  title =	 {Fast Gradient-Based Algorithms for Constrained Total
                  Variation Image Denoising and Deblurring Problems},
  author =	 {Beck, Amir and Teboulle, Marc},
  journal =	 {IEEE Transactions on Image Processing},
  year =	 2009,
  month =	 Nov,
  volume =	 18,
  number =	 11,
  pages =	 {2419--2434},
  doi =		 {10.1109/TIP.2009.2028250}
}

@InCollection {beck-2010-gradient,
  author =	 {Amir Beck and Marc Teboulle},
  editor =	 {Daniel P. Palomar and Yonina C. Eldar},
  title =	 {Gradient-based algorithms with applications to
                  signal-recovery problems},
  booktitle =	 {Convex Optimization in Signal Processing and
                  Communications},
  pages =	 {42--88},
  publisher =	 {Cambridge University Press},
  year =	 2010,
  doi =		 {10.1017/CBO9780511804458.003},
  url =          {http://www.math.tau.ac.il/~teboulle/papers/gradient_chapter.pdf}
}

@Software {bradbury-2018-jax,
  author =	 {James Bradbury and Roy Frostig and Peter Hawkins and
                  Matthew James Johnson and Chris Leary and Dougal
                  Maclaurin and George Necula and Adam Paszke and Jake
                  Vander{P}las and Skye Wanderman-{M}ilne and Qiao
                  Zhang},
  title =	 {{JAX}: composable transformations of
                  {P}ython+{N}um{P}y programs},
  url =		 {http://github.com/google/jax},
  version =	 {0.2.5},
  year =	 2018
}

@Book {beck-2017-first,
  title =	 {First-order methods in optimization},
  author =	 {Beck, Amir},
  year =	 2017,
  publisher =	 {Society for Industrial and Applied Mathematics
                  (SIAM)},
  doi =		 {10.1137/1.9781611974997},
  isbn =	 1611974984
}

@InProceedings {benning-2016-preconditioned,
  title =	 {Preconditioned {ADMM} with nonlinear operator
                  constraint},
  author =	 {Benning, Martin and Knoll, Florian and
                  Sch{\"o}nlieb, Carola-Bibiane and Valkonen, Tuomo},
  booktitle =	 {IFIP Conference on System Modeling and Optimization
                  (CSMO) 2015},
  pages =	 {117--126},
  year =	 2016,
  doi =		 {10.1007/978-3-319-55795-3_10}
}

@Article {boyd-2010-distributed,
  title =	 {Distributed optimization and statistical learning
                  via the alternating direction method of multipliers},
  author =	 {Boyd, Stephen and Parikh, Neal and Chu, Eric and
                  Peleato, Borja and Eckstein, Jonathan},
  journal =	 {Foundations and Trends in Machine Learning},
  year =	 2010,
  volume =	 3,
  number =	 1,
  pages =	 {1--122},
  doi =		 {10.1561/2200000016}
}

@Article {buzzard-2018-plug,
  title =	 {Plug-and-play unplugged: Optimization-free
                  reconstruction using consensus equilibrium},
  author =	 {Buzzard, Gregery T. and Chan, Stanley H. and
                  Sreehari, Suhas and Bouman, Charles A.},
  journal =	 {SIAM Journal on Imaging Sciences},
  volume =	 11,
  number =	 3,
  pages =	 {2001--2020},
  year =	 2018,
  doi =		 {10.1137/17M1122451}
}

@Article {cai-2010-singular,
  title =	 {A Singular Value Thresholding Algorithm for Matrix
                  Completion},
  author =	 {Cai, Jian-Feng and Cand{\`e}s, Emmanuel J. and Shen,
                  Zuowei},
  journal =	 {SIAM Journal on Optimization},
  year =	 2010,
  volume =	 20,
  number =	 4,
  pages =	 {1956--1982},
  doi =		 {10.1137/080738970}
}

@Article {chambolle-2010-firstorder,
  author =	 {Antonin Chambolle and Thomas Pock},
  title =	 {A First-Order Primal-Dual Algorithm for Convex
                  Problems with~Applications to Imaging},
  journal =	 {Journal of Mathematical Imaging and Vision},
  doi =		 {10.1007/s10851-010-0251-1},
  year =	 2010,
  month =	 Dec,
  volume =	 40,
  number =	 1,
  pages =	 {120--145}
}

@Misc {chandler-2024-closedform,
  author =	 {Edward P. Chandler and Shirin Shoushtari and Brendt
                  Wohlberg and Ulugbek S. Kamilov},
  title =	 {Closed-Form Approximation of the Total Variation
                  Proximal Operator},
  year =	 2024,
  eprint =	 {2412.07718}
}

@Article {clinthorne-1993-preconditioning,
  author =	 {Clinthorne, Neal H. and Pan, Tin-Su and Chiao,
                  Ping-Chun and Rogers, W. Leslie and Stamos, John A.},
  title =	 {Preconditioning methods for improved convergence
                  rates in iterative reconstructions},
  journal =	 {IEEE Transactions on Medical Imaging},
  year =	 1993,
  volume =	 12,
  number =	 1,
  pages =	 {78--83},
  month =	 Mar,
  doi =		 {10.1109/42.222670}
}

@InProceedings {dabov-2008-image,
  author =	 {Kostadin Dabov and Alessandro Foi and Vladimir
                  Katkovnik and Karen Egiazarian},
  title =	 {Image restoration by sparse {3D} transform-domain
                  collaborative filtering},
  volume =	 6812,
  booktitle =	 {Image Processing: Algorithms and Systems VI},
  editor =	 {Jaakko T. Astola and Karen O. Egiazarian and Edward
                  R. Dougherty},
  organization = {International Society for Optics and Photonics},
  publisher =	 {SPIE},
  pages =	 {62--73},
  year =	 2008,
  month =	 Mar,
  doi =		 {10.1117/12.766355}
}

@Article {daubechies-2004-iterative,
  title =	 {An iterative thresholding algorithm for linear
                  inverse problems with a sparsity constraint},
  author =	 {Daubechies, Ingrid and Defrise, Michel and De Mol,
                  Christine},
  journal =	 {Communications on Pure and Applied Mathematics},
  volume =	 57,
  number =	 11,
  pages =	 {1413--1457},
  year =	 2004,
  doi =		 {10.1002/cpa.20042}
}

@Article {deng-2015-global,
  author =	 {Wei Deng and Wotao Yin},
  title =	 {On the Global and Linear Convergence of the
                  Generalized Alternating Direction Method of
                  Multipliers},
  journal =	 {Journal of Scientific Computing},
  year =	 2015,
  month =	 May,
  volume =	 66,
  number =	 3,
  pages =	 {889--916},
  doi =		 {10.1007/s10915-015-0048-x},
}

@Misc {diamond-2018-odp,
  author =	 {Steven Diamond and Vincent Sitzmann and Felix Heide
                  and Gordon Wetzstein},
  title =	 {Unrolled Optimization with Deep Priors},
  year =	 2018,
  eprint =	 {1705.08041v2}
}

@Article {esser-2010-general,
  author =	 {Ernie Esser and Xiaoqun Zhang and Tony F. Chan},
  title =	 {A General Framework for a Class of First Order
                  Primal-Dual Algorithms for Convex Optimization in
                  Imaging Science},
  journal =	 {SIAM Journal on Imaging Sciences},
  doi =		 {10.1137/09076934x},
  year =	 2010,
  month =	 Jan,
  volume =	 3,
  number =	 4,
  pages =	 {1015--1046}
}

@PhDThesis {esser-2010-primal,
  author =	 {Ernie Esser},
  title =
Download .txt
gitextract_aiioi9sl/

├── .coveragerc
├── .flake8
├── .github/
│   ├── codecov.yml
│   ├── isbin.sh
│   └── workflows/
│       ├── check_files.yml
│       ├── lint.yml
│       ├── mypy.yml
│       ├── pypi_upload.yml
│       ├── pytest_latest.yml
│       ├── pytest_macos.yml
│       ├── pytest_ubuntu.yml
│       └── test_examples.yml
├── .gitignore
├── .gitmodules
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── CHANGES.rst
├── LICENSE
├── MANIFEST.in
├── README.md
├── conftest.py
├── dev_requirements.txt
├── docs/
│   ├── Makefile
│   ├── docs_requirements.txt
│   ├── rtd_requirements.txt
│   ├── source/
│   │   ├── _static/
│   │   │   └── scico.css
│   │   ├── _templates/
│   │   │   ├── autosummary/
│   │   │   │   └── module.rst
│   │   │   ├── package.rst
│   │   │   └── sidebar/
│   │   │       └── brand.html
│   │   ├── advantages.rst
│   │   ├── api.rst
│   │   ├── classes.rst
│   │   ├── conf/
│   │   │   ├── 10-project.py
│   │   │   ├── 15-theme.py
│   │   │   ├── 20-extensions.py
│   │   │   ├── 25-napoleon.py
│   │   │   ├── 30-autodoc.py
│   │   │   ├── 40-intersphinx.py
│   │   │   ├── 45-mathjax.py
│   │   │   ├── 50-graphviz.py
│   │   │   ├── 55-nbsphinx.py
│   │   │   ├── 60-rtd.py
│   │   │   ├── 70-latex.py
│   │   │   ├── 71-texinfo.py
│   │   │   ├── 72-man_page.py
│   │   │   ├── 80-scico_numpy.py
│   │   │   ├── 81-scico_scipy.py
│   │   │   └── 85-dtype_typehints.py
│   │   ├── conf.py
│   │   ├── contributing.rst
│   │   ├── docsutil.py
│   │   ├── examples.rst
│   │   ├── include/
│   │   │   ├── blockarray.rst
│   │   │   ├── examplenotes.rst
│   │   │   ├── functional.rst
│   │   │   ├── learning.rst
│   │   │   ├── operator.rst
│   │   │   └── optimizer.rst
│   │   ├── index.rst
│   │   ├── install.rst
│   │   ├── inverse.rst
│   │   ├── notes.rst
│   │   ├── overview.rst
│   │   ├── pyfigures/
│   │   │   ├── cylindgrad.py
│   │   │   ├── polargrad.py
│   │   │   ├── spheregrad.py
│   │   │   ├── xray_2d_geom.py
│   │   │   ├── xray_3d_ang.py
│   │   │   ├── xray_3d_vec.py
│   │   │   └── xray_3d_vol.py
│   │   ├── references.bib
│   │   ├── style.rst
│   │   ├── team.rst
│   │   └── zreferences.rst
│   └── tikxfigures/
│       ├── img_align.tex
│       ├── makesvg.sh
│       ├── vol_align_xyz.tex
│       ├── vol_align_xz.tex
│       └── vol_align_yz.tex
├── examples/
│   ├── README.rst
│   ├── examples_requirements.txt
│   ├── jnb.py
│   ├── makeindex.py
│   ├── makenotebooks.py
│   ├── notebooks_requirements.txt
│   ├── removejnberr.py
│   ├── scriptcheck.sh
│   ├── scripts/
│   │   ├── README.rst
│   │   ├── ct_abel_tv_admm.py
│   │   ├── ct_abel_tv_admm_tune.py
│   │   ├── ct_astra_3d_tv_admm.py
│   │   ├── ct_astra_3d_tv_padmm.py
│   │   ├── ct_astra_noreg_pcg.py
│   │   ├── ct_astra_tv_admm.py
│   │   ├── ct_astra_weighted_tv_admm.py
│   │   ├── ct_datagen_foam2.py
│   │   ├── ct_fan_svmbir_ppp_bm3d_admm_prox.py
│   │   ├── ct_modl_train_foam2.py
│   │   ├── ct_multi_tv_admm.py
│   │   ├── ct_odp_train_foam2.py
│   │   ├── ct_projector_comparison_2d.py
│   │   ├── ct_projector_comparison_3d.py
│   │   ├── ct_svmbir_ppp_bm3d_admm_cg.py
│   │   ├── ct_svmbir_ppp_bm3d_admm_prox.py
│   │   ├── ct_svmbir_tv_multi.py
│   │   ├── ct_symcone_tv_padmm.py
│   │   ├── ct_tv_admm.py
│   │   ├── ct_unet_train_foam2.py
│   │   ├── deconv_circ_tv_admm.py
│   │   ├── deconv_datagen_bsds.py
│   │   ├── deconv_datagen_foam1.py
│   │   ├── deconv_microscopy_allchn_tv_admm.py
│   │   ├── deconv_microscopy_tv_admm.py
│   │   ├── deconv_modl_train_foam1.py
│   │   ├── deconv_odp_train_foam1.py
│   │   ├── deconv_ppp_bm3d_admm.py
│   │   ├── deconv_ppp_bm3d_apgm.py
│   │   ├── deconv_ppp_bm4d_admm.py
│   │   ├── deconv_ppp_dncnn_admm.py
│   │   ├── deconv_ppp_dncnn_padmm.py
│   │   ├── deconv_tv_admm.py
│   │   ├── deconv_tv_admm_tune.py
│   │   ├── deconv_tv_padmm.py
│   │   ├── demosaic_ppp_bm3d_admm.py
│   │   ├── denoise_approx_tv_multi.py
│   │   ├── denoise_cplx_tv_nlpadmm.py
│   │   ├── denoise_cplx_tv_pdhg.py
│   │   ├── denoise_datagen_bsds.py
│   │   ├── denoise_dncnn_train_bsds.py
│   │   ├── denoise_dncnn_universal.py
│   │   ├── denoise_l1tv_admm.py
│   │   ├── denoise_ptv_pdhg.py
│   │   ├── denoise_tv_admm.py
│   │   ├── denoise_tv_apgm.py
│   │   ├── denoise_tv_multi.py
│   │   ├── diffusercam_tv_admm.py
│   │   ├── index.rst
│   │   ├── sparsecode_apgm.py
│   │   ├── sparsecode_conv_admm.py
│   │   ├── sparsecode_conv_md_admm.py
│   │   ├── sparsecode_nn_admm.py
│   │   ├── sparsecode_nn_apgm.py
│   │   ├── sparsecode_poisson_apgm.py
│   │   ├── superres_ppp_dncnn_admm.py
│   │   ├── trace_example.py
│   │   └── video_rpca_admm.py
│   ├── updatejnbcode.py
│   └── updatejnbmd.py
├── misc/
│   ├── README.rst
│   ├── conda/
│   │   ├── README.rst
│   │   ├── install_conda.sh
│   │   └── make_conda_env.sh
│   ├── gpu/
│   │   ├── README.rst
│   │   ├── availgpu.py
│   │   └── envinfo.py
│   └── pytest/
│       ├── README.rst
│       ├── pytest_cov.sh
│       ├── pytest_fast.sh
│       └── pytest_time.sh
├── pyproject.toml
├── pytest.ini
├── requirements.txt
├── scico/
│   ├── __init__.py
│   ├── _core.py
│   ├── _version.py
│   ├── data/
│   │   └── __init__.py
│   ├── denoiser.py
│   ├── diagnostics.py
│   ├── examples.py
│   ├── flax/
│   │   ├── __init__.py
│   │   ├── _flax.py
│   │   ├── _models.py
│   │   ├── blocks.py
│   │   ├── examples/
│   │   │   ├── __init__.py
│   │   │   ├── data_generation.py
│   │   │   ├── data_preprocessing.py
│   │   │   ├── examples.py
│   │   │   └── typed_dict.py
│   │   ├── inverse.py
│   │   └── train/
│   │       ├── __init__.py
│   │       ├── apply.py
│   │       ├── checkpoints.py
│   │       ├── clu_utils.py
│   │       ├── diagnostics.py
│   │       ├── input_pipeline.py
│   │       ├── learning_rate.py
│   │       ├── losses.py
│   │       ├── spectral.py
│   │       ├── state.py
│   │       ├── steps.py
│   │       ├── trainer.py
│   │       ├── traversals.py
│   │       └── typed_dict.py
│   ├── function.py
│   ├── functional/
│   │   ├── __init__.py
│   │   ├── _denoiser.py
│   │   ├── _dist.py
│   │   ├── _functional.py
│   │   ├── _indicator.py
│   │   ├── _norm.py
│   │   ├── _proxavg.py
│   │   └── _tvnorm.py
│   ├── linop/
│   │   ├── __init__.py
│   │   ├── _circconv.py
│   │   ├── _convolve.py
│   │   ├── _dft.py
│   │   ├── _diag.py
│   │   ├── _diff.py
│   │   ├── _func.py
│   │   ├── _grad.py
│   │   ├── _linop.py
│   │   ├── _matrix.py
│   │   ├── _stack.py
│   │   ├── _util.py
│   │   ├── optics.py
│   │   └── xray/
│   │       ├── __init__.py
│   │       ├── _axitom/
│   │       │   ├── LICENSE
│   │       │   ├── README.md
│   │       │   ├── backprojection.py
│   │       │   ├── config.py
│   │       │   ├── filtering.py
│   │       │   ├── projection.py
│   │       │   └── utilities.py
│   │       ├── _util.py
│   │       ├── _xray.py
│   │       ├── abel.py
│   │       ├── astra.py
│   │       ├── svmbir.py
│   │       └── symcone.py
│   ├── loss.py
│   ├── metric.py
│   ├── numpy/
│   │   ├── __init__.py
│   │   ├── _blockarray.py
│   │   ├── _wrapped_function_lists.py
│   │   ├── _wrappers.py
│   │   ├── fft.py
│   │   ├── linalg.py
│   │   ├── testing.py
│   │   └── util.py
│   ├── operator/
│   │   ├── __init__.py
│   │   ├── _func.py
│   │   ├── _operator.py
│   │   ├── _stack.py
│   │   └── biconvolve.py
│   ├── optimize/
│   │   ├── __init__.py
│   │   ├── _admm.py
│   │   ├── _admmaux.py
│   │   ├── _common.py
│   │   ├── _ladmm.py
│   │   ├── _padmm.py
│   │   ├── _pgm.py
│   │   ├── _pgmaux.py
│   │   ├── _primaldual.py
│   │   ├── admm.py
│   │   └── pgm.py
│   ├── plot.py
│   ├── random.py
│   ├── ray/
│   │   ├── __init__.py
│   │   └── tune.py
│   ├── scipy/
│   │   ├── __init__.py
│   │   └── special.py
│   ├── solver.py
│   ├── test/
│   │   ├── conftest.py
│   │   ├── flax/
│   │   │   ├── test_apply.py
│   │   │   ├── test_checkpoints.py
│   │   │   ├── test_clu.py
│   │   │   ├── test_examples_flax.py
│   │   │   ├── test_flax.py
│   │   │   ├── test_inv.py
│   │   │   ├── test_spectral.py
│   │   │   ├── test_steps.py
│   │   │   ├── test_train_aux.py
│   │   │   ├── test_trainer.py
│   │   │   └── test_traversal.py
│   │   ├── functional/
│   │   │   ├── prox.py
│   │   │   ├── test_composed.py
│   │   │   ├── test_denoiser_func.py
│   │   │   ├── test_funcional_core.py
│   │   │   ├── test_indicator.py
│   │   │   ├── test_loss.py
│   │   │   ├── test_misc.py
│   │   │   ├── test_norm.py
│   │   │   ├── test_proxavg.py
│   │   │   ├── test_separable.py
│   │   │   └── test_tvnorm.py
│   │   ├── linop/
│   │   │   ├── test_binop.py
│   │   │   ├── test_circconv.py
│   │   │   ├── test_conversions.py
│   │   │   ├── test_convolve.py
│   │   │   ├── test_dft.py
│   │   │   ├── test_diag.py
│   │   │   ├── test_diff.py
│   │   │   ├── test_func.py
│   │   │   ├── test_grad.py
│   │   │   ├── test_linop.py
│   │   │   ├── test_linop_stack.py
│   │   │   ├── test_linop_util.py
│   │   │   ├── test_matrix.py
│   │   │   ├── test_optics.py
│   │   │   └── xray/
│   │   │       ├── test_abel.py
│   │   │       ├── test_astra.py
│   │   │       ├── test_svmbir.py
│   │   │       ├── test_symcone.py
│   │   │       ├── test_xray_2d.py
│   │   │       ├── test_xray_3d.py
│   │   │       └── test_xray_util.py
│   │   ├── numpy/
│   │   │   ├── test_blockarray.py
│   │   │   ├── test_numpy.py
│   │   │   └── test_numpy_util.py
│   │   ├── operator/
│   │   │   ├── test_biconvolve.py
│   │   │   ├── test_op_stack.py
│   │   │   └── test_operator.py
│   │   ├── optimize/
│   │   │   ├── test_admm.py
│   │   │   ├── test_ladmm.py
│   │   │   ├── test_padmm.py
│   │   │   ├── test_pdhg.py
│   │   │   └── test_pgm.py
│   │   ├── osver.py
│   │   ├── test_core.py
│   │   ├── test_data.py
│   │   ├── test_denoiser.py
│   │   ├── test_diagnostics.py
│   │   ├── test_examples.py
│   │   ├── test_function.py
│   │   ├── test_metric.py
│   │   ├── test_random.py
│   │   ├── test_ray_tune.py
│   │   ├── test_scipy_special.py
│   │   ├── test_solver.py
│   │   ├── test_util.py
│   │   └── test_version.py
│   ├── trace.py
│   ├── typing.py
│   └── util.py
└── setup.py
Download .txt
SYMBOL INDEX (1832 symbols across 170 files)

FILE: conftest.py
  function pytest_sessionstart (line 25) | def pytest_sessionstart(session):
  function pytest_sessionfinish (line 30) | def pytest_sessionfinish(session, exitstatus):
  function add_modules (line 37) | def add_modules(doctest_namespace):

FILE: docs/source/conf.py
  function class_inherit_diagrams (line 52) | def class_inherit_diagrams(_):
  function process_docstring (line 62) | def process_docstring(app, what, name, obj, options, lines):
  function setup (line 80) | def setup(app):

FILE: docs/source/conf/25-napoleon.py
  function parse_keys_section (line 9) | def parse_keys_section(self, section):
  function parse_attributes_section (line 16) | def parse_attributes_section(self, section):
  function parse_class_attributes_section (line 23) | def parse_class_attributes_section(self, section):
  function patched_parse (line 32) | def patched_parse(self):

FILE: docs/source/conf/85-dtype_typehints.py
  function typehints_formatter_function (line 29) | def typehints_formatter_function(annotation, config):

FILE: docs/source/docsutil.py
  function run_conf_files (line 20) | def run_conf_files(vardict=None, path=None):
  function package_classes (line 47) | def package_classes(package):
  function get_text_indentation (line 87) | def get_text_indentation(text, skiplines=0):
  function add_text_indentation (line 110) | def add_text_indentation(text, indent):
  function insert_inheritance_diagram (line 127) | def insert_inheritance_diagram(clsqname, parts=None, default_nparts=2):

FILE: docs/source/pyfigures/xray_3d_vec.py
  class Arrow3D (line 12) | class Arrow3D(FancyArrowPatch):
    method __init__ (line 13) | def __init__(self, xs, ys, zs, *args, **kwargs):
    method do_3d_projection (line 17) | def do_3d_projection(self, renderer=None):

FILE: docs/source/pyfigures/xray_3d_vol.py
  class Arrow3D (line 12) | class Arrow3D(FancyArrowPatch):
    method __init__ (line 13) | def __init__(self, xs, ys, zs, *args, **kwargs):
    method do_3d_projection (line 17) | def do_3d_projection(self, renderer=None):

FILE: examples/jnb.py
  function py_file_to_string (line 18) | def py_file_to_string(src):
  function script_to_notebook (line 83) | def script_to_notebook(src, dst):
  function read_notebook (line 91) | def read_notebook(fname):
  function execute_notebook (line 101) | def execute_notebook(fname):
  function notebook_executed (line 120) | def notebook_executed(nbfn):
  function same_notebook_code (line 134) | def same_notebook_code(nb1, nb2):
  function same_notebook_markdown (line 166) | def same_notebook_markdown(nb1, nb2):
  function replace_markdown_cells (line 198) | def replace_markdown_cells(src, dst):
  function remove_error_output (line 229) | def remove_error_output(src):

FILE: examples/makenotebooks.py
  function script_uses_ray (line 30) | def script_uses_ray(fname):
  function script_path (line 40) | def script_path(sname):
  function notebook_path (line 46) | def notebook_path(sname):
  function ray_run_nb (line 190) | def ray_run_nb(fname):

FILE: examples/scripts/ct_abel_tv_admm_tune.py
  class Trainable (line 77) | class Trainable(tune.Trainable):
    method setup (line 80) | def setup(self, config, x_gt, x0, y):
    method reset_config (line 96) | def reset_config(self, config):
    method step (line 127) | def step(self):

FILE: examples/scripts/ct_astra_weighted_tv_admm.py
  function postprocess (line 80) | def postprocess(x):
  function plot_recon (line 157) | def plot_recon(x, title, ax):

FILE: examples/scripts/ct_fan_svmbir_ppp_bm3d_admm_prox.py
  function add_poisson_noise (line 93) | def add_poisson_noise(sino, max_intensity):

FILE: examples/scripts/deconv_microscopy_allchn_tv_admm.py
  function deconvolve_channel (line 110) | def deconvolve_channel(channel):

FILE: examples/scripts/deconv_tv_admm_tune.py
  function eval_params (line 76) | def eval_params(config, x_gt, psf, y):

FILE: examples/scripts/demosaic_ppp_bm3d_admm.py
  function Afn (line 50) | def Afn(x):
  function ATfn (line 63) | def ATfn(x):
  function demosaic (line 83) | def demosaic(cfaimg):

FILE: examples/scripts/denoise_tv_apgm.py
  class DualTVLoss (line 81) | class DualTVLoss(loss.Loss):
    method __init__ (line 82) | def __init__(
    method __call__ (line 92) | def __call__(self, x: Union[Array, BlockArray]) -> float:
  class IsoProjector (line 104) | class IsoProjector(functional.Functional):
    method __call__ (line 108) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 111) | def prox(self, v: Array, lam: float, **kwargs) -> Array:
  class AnisoProjector (line 156) | class AnisoProjector(functional.Functional):
    method __call__ (line 160) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 163) | def prox(self, v: Array, lam: float, **kwargs) -> Array:

FILE: examples/scripts/sparsecode_poisson_apgm.py
  class ForwardOperator (line 71) | class ForwardOperator(Operator):
    method __init__ (line 80) | def __init__(self, input_shape: Shape, D0, D1, jit: bool = True):
    method _eval (line 94) | def _eval(self, x: BlockArray) -> BlockArray:
  function plot_results (line 128) | def plot_results(hist, str_ss, L0, xsol, xgt, Aop):

FILE: examples/scripts/superres_ppp_dncnn_admm.py
  function downsample_image (line 31) | def downsample_image(img, rate):

FILE: examples/updatejnbcode.py
  function replace_code_cells (line 15) | def replace_code_cells(src, dst):

FILE: scico/_core.py
  function _append_jax_docs (line 31) | def _append_jax_docs(fn, jaxfn=None):
  function _convert_ba_dts (line 46) | def _convert_ba_dts(arg: Any) -> Any:
  function eval_shape (line 58) | def eval_shape(fun: Callable, *args, **kwargs) -> Any:
  function grad (line 71) | def grad(
  function value_and_grad (line 99) | def value_and_grad(
  function linear_transpose (line 128) | def linear_transpose(fun: Callable, *primals) -> Callable:
  function linear_adjoint (line 140) | def linear_adjoint(fun: Callable, *primals) -> Callable:
  function jacrev (line 156) | def jacrev(
  function cvjp (line 177) | def cvjp(fun: Callable, *primals, jidx: Optional[int] = None) -> Tuple[T...

FILE: scico/_version.py
  function root_init_path (line 17) | def root_init_path() -> str:  # pragma: no cover
  function variable_assign_value (line 26) | def variable_assign_value(path: str, var: str) -> Any:
  function init_variable_assign_value (line 50) | def init_variable_assign_value(var: str) -> Any:  # pragma: no cover
  function current_git_hash (line 66) | def current_git_hash() -> Optional[str]:  # nosec  pragma: no cover
  function package_version (line 79) | def package_version(split: bool = False) -> Union[str, Tuple[str, str]]:...

FILE: scico/data/__init__.py
  function _imread (line 20) | def _imread(filename: str, path: Optional[str] = None, asfloat: bool = F...
  function kodim23 (line 41) | def kodim23(asfloat: bool = False) -> snp.Array:
  function _flax_data_path (line 55) | def _flax_data_path(filename: str) -> str:

FILE: scico/denoiser.py
  function bm3d (line 39) | def bm3d(x: snp.Array, sigma: float, is_rgb: bool = False, profile: Unio...
  function bm4d (line 117) | def bm4d(x: snp.Array, sigma: float, profile: Union[BM4DProfile, str] = ...
  class DnCNN (line 182) | class DnCNN(FlaxMap):
    method __init__ (line 202) | def __init__(self, variant: str = "6M"):
    method __call__ (line 239) | def __call__(self, x: snp.Array, sigma: Optional[float] = None) -> snp...

FILE: scico/diagnostics.py
  class IterationStats (line 18) | class IterationStats:
    method __init__ (line 25) | def __init__(
    method insert (line 156) | def insert(self, values: Union[List, Tuple]):
    method end (line 180) | def end(self):
    method history (line 196) | def history(self, transpose: bool = False) -> Union[List[NamedTuple], ...

FILE: scico/examples.py
  function rgb2gray (line 30) | def rgb2gray(rgb: np.ndarray) -> np.ndarray:
  function volume_read (line 49) | def volume_read(path: str, ext: str = "tif") -> np.ndarray:
  function get_epfl_deconv_data (line 72) | def get_epfl_deconv_data(channel: int, path: str, verbose: bool = False)...
  function epfl_deconv_data (line 128) | def epfl_deconv_data(
  function get_ucb_diffusercam_data (line 168) | def get_ucb_diffusercam_data(path: str, verbose: bool = False):  # pragm...
  function ucb_diffusercam_data (line 221) | def ucb_diffusercam_data(
  function downsample_volume (line 260) | def downsample_volume(vol: np.ndarray, rate: int) -> np.ndarray:
  function tile_volume_slices (line 289) | def tile_volume_slices(x: np.ndarray, sep_width: int = 10) -> np.ndarray:
  function gaussian (line 347) | def gaussian(shape: Shape, sigma: Optional[np.ndarray] = None) -> np.nda...
  function create_cone (line 384) | def create_cone(shape: Shape, center: Optional[List[float]] = None) -> n...
  function create_circular_phantom (line 409) | def create_circular_phantom(
  function create_3d_foam_phantom (line 439) | def create_3d_foam_phantom(
  function create_conv_sparse_phantom (line 488) | def create_conv_sparse_phantom(Nx: int, Nnz: int) -> Tuple[np.ndarray, n...
  function create_tangle_phantom (line 529) | def create_tangle_phantom(nx: int, ny: int, nz: int) -> np.ndarray:
  function create_block_phantom (line 567) | def create_block_phantom(out_shape: Shape) -> np.ndarray:
  function spnoise (line 604) | def spnoise(
  function phase_diff (line 632) | def phase_diff(x: snp.Array, y: snp.Array) -> snp.Array:

FILE: scico/flax/_flax.py
  function load_variables (line 23) | def load_variables(filename: str) -> PyTree:
  function save_variables (line 43) | def save_variables(variables: PyTree, filename: str):
  class FlaxMap (line 57) | class FlaxMap:
    method __init__ (line 60) | def __init__(self, model: Module, variables: PyTree):
    method __call__ (line 71) | def __call__(self, x: Array) -> Array:

FILE: scico/flax/_models.py
  class DnCNNNet (line 41) | class DnCNNNet(Module):
    method __call__ (line 67) | def __call__(
  class ResNet (line 121) | class ResNet(Module):
    method __call__ (line 147) | def __call__(self, x: Array, train: bool = True) -> Array:
  class ConvBNNet (line 196) | class ConvBNNet(Module):
    method __call__ (line 221) | def __call__(self, x: Array, train: bool = True) -> Array:
  class UNet (line 267) | class UNet(Module):
    method __call__ (line 295) | def __call__(self, x: Array, train: bool = True) -> Array:

FILE: scico/flax/blocks.py
  class ConvBNBlock (line 30) | class ConvBNBlock(Module):
    method __call__ (line 55) | def __call__(
  class ConvBlock (line 76) | class ConvBlock(Module):
    method __call__ (line 98) | def __call__(
  class ConvBNPoolBlock (line 118) | class ConvBNPoolBlock(Module):
    method __call__ (line 147) | def __call__(
  class ConvBNUpsampleBlock (line 170) | class ConvBNUpsampleBlock(Module):
    method __call__ (line 196) | def __call__(
  class ConvBNMultiBlock (line 218) | class ConvBNMultiBlock(Module):
    method __call__ (line 247) | def __call__(
  function upscale_nn (line 275) | def upscale_nn(x: Array, scale: int = 2) -> Array:

FILE: scico/flax/examples/data_generation.py
  class UnitCircle (line 25) | class UnitCircle:
  class Foam2 (line 61) | class Foam2(UnitCircle):
    method __init__ (line 67) | def __init__(
  function generate_foam1_images (line 101) | def generate_foam1_images(seed: float, size: int, ndata: int) -> np.ndar...
  function generate_foam2_images (line 126) | def generate_foam2_images(seed: float, size: int, ndata: int) -> np.ndar...
  function vector_f (line 153) | def vector_f(f_: Callable, v: Array) -> Array:
  function batched_f (line 168) | def batched_f(f_: Callable, vr: Array) -> Array:
  function generate_ct_data (line 189) | def generate_ct_data(
  function generate_blur_data (line 276) | def generate_blur_data(
  function distributed_data_generation (line 353) | def distributed_data_generation(

FILE: scico/flax/examples/data_preprocessing.py
  function rotation90 (line 33) | def rotation90(img: Array) -> Array:
  function flip (line 54) | def flip(img: Array) -> Array:
  class CenterCrop (line 74) | class CenterCrop:
    method __init__ (line 81) | def __init__(self, output_size: Union[Shape, int]):
    method __call__ (line 94) | def __call__(self, image: Array) -> Array:
  class PositionalCrop (line 114) | class PositionalCrop:
    method __init__ (line 121) | def __init__(self, output_size: Union[Shape, int]):
    method __call__ (line 134) | def __call__(self, image: Array, top: int, left: int) -> Array:
  class RandomNoise (line 155) | class RandomNoise:
    method __init__ (line 168) | def __init__(self, noise_level: float, range_flag: bool = False):
    method __call__ (line 181) | def __call__(self, image: Array) -> Array:
  function preprocess_images (line 209) | def preprocess_images(
  function build_image_dataset (line 291) | def build_image_dataset(
  function images_read (line 371) | def images_read(path: str, ext: str = "jpg") -> Array:  # pragma: no cover
  function get_bsds_data (line 401) | def get_bsds_data(path: str, verbose: bool = False):  # pragma: no cover
  function build_blur_kernel (line 468) | def build_blur_kernel(
  class PaddedCircularConvolve (line 492) | class PaddedCircularConvolve(LinearOperator):
    method __init__ (line 501) | def __init__(
    method _eval (line 560) | def _eval(self, x: Array) -> Array:

FILE: scico/flax/examples/examples.py
  function get_cache_path (line 24) | def get_cache_path(cache_path: Optional[str] = None) -> Tuple[str, str]:
  function load_ct_data (line 45) | def load_ct_data(
  function load_blur_data (line 177) | def load_blur_data(
  function load_image_data (line 328) | def load_image_data(
  function check_img_data_requirements (line 513) | def check_img_data_requirements(
  function print_input_path (line 576) | def print_input_path(path_display: str):  # pragma: no cover
  function print_output_path (line 585) | def print_output_path(path_display: str):  # pragma: no cover
  function print_data_range (line 594) | def print_data_range(idstring: str, data: Array):  # pragma: no cover
  function print_data_size (line 604) | def print_data_size(idstring: str, size: int):  # pragma: no cover
  function print_info (line 614) | def print_info(
  function print_data_warning (line 637) | def print_data_warning(idstring: str, requested: int, available: int):  ...
  function runtime_error_scalar (line 651) | def runtime_error_scalar(
  function runtime_error_array (line 672) | def runtime_error_array(type: str, idstring: str, maxdiff: float):

FILE: scico/flax/examples/typed_dict.py
  class CTDataSetDict (line 22) | class CTDataSetDict(TypedDict):
  class ConfigImageSetDict (line 30) | class ConfigImageSetDict(TypedDict):

FILE: scico/flax/inverse.py
  class MoDLNet (line 35) | class MoDLNet(Module):
    method __call__ (line 68) | def __call__(self, y: Array, train: bool = True) -> Array:
  function cg_solver (line 113) | def cg_solver(A: Callable, b: Array, x0: Array = None, maxiter: int = 50...
  class ODPProxDnBlock (line 161) | class ODPProxDnBlock(Module):
    method batch_op_adj (line 191) | def batch_op_adj(self, y: Array) -> Array:
    method __call__ (line 196) | def __call__(self, x: Array, y: Array, train: bool = True) -> Array:
  class ODPProxDcnvBlock (line 228) | class ODPProxDcnvBlock(Module):
    method setup (line 258) | def setup(self):
    method batch_op_adj (line 281) | def batch_op_adj(self, y: Array) -> Array:
    method __call__ (line 285) | def __call__(self, x: Array, y: Array, train: bool = True) -> Array:
  class ODPGrDescBlock (line 318) | class ODPGrDescBlock(Module):
    method setup (line 349) | def setup(self):
    method batch_op_adj (line 370) | def batch_op_adj(self, y: Array) -> Array:
    method __call__ (line 374) | def __call__(self, x: Array, y: Array, train: bool = True) -> Array:
  class ODPNet (line 392) | class ODPNet(Module):
    method __call__ (line 428) | def __call__(self, y: Array, train: bool = True) -> Array:
  function power_iteration (line 465) | def power_iteration(A: LinearOperator, maxiter: int = 100):

FILE: scico/flax/train/apply.py
  function apply_fn (line 31) | def apply_fn(model: ModuleDef, variables: ModelVarDict, batch: DataSetDi...
  function only_apply (line 52) | def only_apply(

FILE: scico/flax/train/checkpoints.py
  function checkpoint_restore (line 38) | def checkpoint_restore(
  function checkpoint_save (line 84) | def checkpoint_save(state: TrainState, config: ConfigDict, workdir: Unio...

FILE: scico/flax/train/clu_utils.py
  class ParamRow (line 36) | class ParamRow:
  class ParamRowWithStats (line 45) | class ParamRowWithStats(ParamRow):
  function flatten_dict (line 52) | def flatten_dict(
  function count_parameters (line 75) | def count_parameters(params: PyTree) -> int:
  function get_parameter_rows (line 88) | def get_parameter_rows(
  function _default_table_value_formatter (line 129) | def _default_table_value_formatter(value):
  function make_table (line 141) | def make_table(
  function get_parameter_overview (line 209) | def get_parameter_overview(

FILE: scico/flax/train/diagnostics.py
  function compute_metrics (line 25) | def compute_metrics(output: Array, labels: Array, criterion: Callable = ...
  class ArgumentStruct (line 49) | class ArgumentStruct:
    method __init__ (line 57) | def __init__(self, **entries):
  function stats_obj (line 61) | def stats_obj() -> Tuple[IterationStats, Callable]:

FILE: scico/flax/train/input_pipeline.py
  class IterateData (line 32) | class IterateData:
    method __init__ (line 38) | def __init__(self, dt: DataSetDict, batch_size: int, train: bool = Tru...
    method reset (line 60) | def reset(self):
    method __iter__ (line 72) | def __iter__(self):
    method __next__ (line 75) | def __next__(self):
  function prepare_data (line 90) | def prepare_data(xs: Array) -> Any:
  function create_input_iter (line 102) | def create_input_iter(

FILE: scico/flax/train/learning_rate.py
  function create_cnst_lr_schedule (line 15) | def create_cnst_lr_schedule(config: ConfigDict) -> optax._src.base.Sched...
  function create_exp_lr_schedule (line 30) | def create_exp_lr_schedule(config: ConfigDict) -> optax._src.base.Schedule:
  function create_cosine_lr_schedule (line 48) | def create_cosine_lr_schedule(config: ConfigDict) -> optax._src.base.Sch...

FILE: scico/flax/train/losses.py
  function mse_loss (line 17) | def mse_loss(output: Array, labels: Array) -> float:

FILE: scico/flax/train/spectral.py
  function _l2_normalize (line 35) | def _l2_normalize(x: Array, eps: float = 1e-12) -> Array:
  function estimate_spectral_norm (line 49) | def estimate_spectral_norm(
  class CNN (line 85) | class CNN(Module):
    method __call__ (line 104) | def __call__(self, x):
  function conv (line 126) | def conv(inputs: Array, kernel: Array) -> Array:
  function spectral_normalization_conv (line 151) | def spectral_normalization_conv(
  function exact_spectral_norm (line 177) | def exact_spectral_norm(f, input_shape):

FILE: scico/flax/train/state.py
  class TrainState (line 29) | class TrainState(train_state.TrainState):
  function initialize (line 39) | def initialize(key: KeyArray, model: ModuleDef, ishape: Shape) -> Tuple[...
  function create_basic_train_state (line 63) | def create_basic_train_state(

FILE: scico/flax/train/steps.py
  function train_step (line 26) | def train_step(
  function train_step_post (line 93) | def train_step_post(
  function eval_step (line 139) | def eval_step(

FILE: scico/flax/train/trainer.py
  function sync_batch_stats (line 47) | def sync_batch_stats(state: TrainState) -> TrainState:
  class BasicFlaxTrainer (line 59) | class BasicFlaxTrainer:
    method __init__ (line 62) | def __init__(
    method set_training_parameters (line 111) | def set_training_parameters(
    method configure_steps (line 132) | def configure_steps(
    method configure_reporting (line 183) | def configure_reporting(self, config: ConfigDict):
    method configure_training_functions (line 229) | def configure_training_functions(self, config: ConfigDict):
    method construct_data_iterators (line 296) | def construct_data_iterators(
    method define_parallel_training_functions (line 344) | def define_parallel_training_functions(self):
    method initialize_training_state (line 379) | def initialize_training_state(
    method train (line 414) | def train(self) -> Tuple[Dict[str, Any], Optional[IterationStats]]:
    method update_metrics (line 476) | def update_metrics(self, state: TrainState, step: int, train_metrics: ...
    method checkpoint (line 523) | def checkpoint(self, state: TrainState):  # pragma: no cover
    method log (line 532) | def log(self, logstr: str):

FILE: scico/flax/train/traversals.py
  function construct_traversal (line 19) | def construct_traversal(prmname: str) -> ModelParamTraversal:
  function clip_positive (line 31) | def clip_positive(params: PyTree, traversal: ModelParamTraversal, minval...
  function clip_range (line 45) | def clip_range(

FILE: scico/flax/train/typed_dict.py
  class DataSetDict (line 23) | class DataSetDict(TypedDict):
  class ConfigDict (line 36) | class ConfigDict(TypedDict):
  class ModelVarDict (line 94) | class ModelVarDict(TypedDict):
  class MetricsDict (line 107) | class MetricsDict(TypedDict, total=False):

FILE: scico/function.py
  class Function (line 23) | class Function:
    method __init__ (line 32) | def __init__(
    method __repr__ (line 90) | def __repr__(self):
    method __call__ (line 98) | def __call__(self, *args: Union[Array, BlockArray]) -> Union[Array, Bl...
    method slice (line 109) | def slice(self, index: int, *fix_args: Union[Array, BlockArray]) -> Op...
    method join (line 134) | def join(self) -> Operator:
    method jvp (line 164) | def jvp(
    method vjp (line 191) | def vjp(
    method jacobian (line 217) | def jacobian(

FILE: scico/functional/_denoiser.py
  class BM3D (line 18) | class BM3D(Functional):
    method __init__ (line 31) | def __init__(self, is_rgb: bool = False, profile: Union[denoiser.BM3DP...
    method prox (line 44) | def prox(self, x: Array, lam: float = 1.0, **kwargs) -> Array:  # type...
  class BM4D (line 59) | class BM4D(Functional):
    method __init__ (line 72) | def __init__(self, profile: Union[denoiser.BM4DProfile, str] = "np"):
    method prox (line 81) | def prox(self, x: Array, lam: float = 1.0, **kwargs) -> Array:  # type...
  class DnCNN (line 96) | class DnCNN(Functional):
    method __init__ (line 107) | def __init__(self, variant: str = "6M"):
    method prox (line 126) | def prox(self, x: Array, lam: float = 1.0, **kwargs) -> Array:  # type...

FILE: scico/functional/_dist.py
  class SetDistance (line 18) | class SetDistance(Functional):
    method __init__ (line 41) | def __init__(self, proj: Callable, args=()):
    method __call__ (line 50) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 65) | def prox(
  class SquaredSetDistance (line 88) | class SquaredSetDistance(Functional):
    method __init__ (line 112) | def __init__(self, proj: Callable, args=()):
    method __call__ (line 121) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 136) | def prox(

FILE: scico/functional/_functional.py
  class Functional (line 22) | class Functional:
    method __init__ (line 38) | def __init__(self):
    method __str__ (line 41) | def __str__(self):
    method __repr__ (line 44) | def __repr__(self):
    method __mul__ (line 47) | def __mul__(self, other: Union[float, int]) -> ScaledFunctional:
    method __rmul__ (line 52) | def __rmul__(self, other: Union[float, int]) -> ScaledFunctional:
    method __add__ (line 55) | def __add__(self, other: Functional) -> FunctionalSum:
    method __call__ (line 60) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 72) | def prox(
    method conj_prox (line 102) | def conj_prox(
    method grad (line 130) | def grad(self, x: Union[Array, BlockArray]):
  class ScaledFunctional (line 142) | class ScaledFunctional(Functional):
    method __init__ (line 145) | def __init__(self, functional: Functional, scale: float):
    method __repr__ (line 152) | def __repr__(self):
    method __call__ (line 159) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method __mul__ (line 162) | def __mul__(self, other: Union[float, int]) -> ScaledFunctional:
    method prox (line 167) | def prox(
  class SeparableFunctional (line 201) | class SeparableFunctional(Functional):
    method __init__ (line 216) | def __init__(self, functional_list: List[Functional]):
    method __repr__ (line 228) | def __repr__(self):
    method __call__ (line 236) | def __call__(self, x: BlockArray) -> float:
    method prox (line 244) | def prox(self, v: BlockArray, lam: float = 1.0, **kwargs) -> BlockArray:
  class ComposedFunctional (line 277) | class ComposedFunctional(Functional):
    method __init__ (line 294) | def __init__(self, functional: Functional, linop: LinearOperator):
    method __repr__ (line 309) | def __repr__(self):
    method __call__ (line 315) | def __call__(self, x: BlockArray) -> float:
    method prox (line 318) | def prox(
  class FunctionalSum (line 345) | class FunctionalSum(Functional):
    method __init__ (line 348) | def __init__(self, functional1: Functional, functional2: Functional):
    method __repr__ (line 355) | def __repr__(self):
    method __call__ (line 362) | def __call__(self, x: Union[Array, BlockArray]) -> float:
  class ZeroFunctional (line 366) | class ZeroFunctional(Functional):
    method __call__ (line 372) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 375) | def prox(

FILE: scico/functional/_indicator.py
  class NonNegativeIndicator (line 21) | class NonNegativeIndicator(Functional):
    method __call__ (line 37) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 44) | def prox(
  class L2BallIndicator (line 71) | class L2BallIndicator(Functional):
    method __init__ (line 89) | def __init__(self, radius: float = 1.0):
    method __call__ (line 98) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 102) | def prox(
  class BoxIndicator (line 130) | class BoxIndicator(Functional):
    method __init__ (line 140) | def __init__(self, lb: float = 0.0, ub: float = 1.0):
    method __call__ (line 150) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 156) | def prox(

FILE: scico/functional/_norm.py
  class L0Norm (line 23) | class L0Norm(Functional):
    method __call__ (line 35) | def __call__(x: Union[Array, BlockArray]) -> float:
    method prox (line 40) | def prox(v: Union[Array, BlockArray], lam: float = 1.0, **kwargs) -> U...
  class L1Norm (line 65) | class L1Norm(Functional):
    method __call__ (line 79) | def __call__(x: Union[Array, BlockArray]) -> float:
    method prox (line 84) | def prox(v: Union[Array, BlockArray], lam: float = 1.0, **kwargs) -> A...
  class SquaredL2Norm (line 119) | class SquaredL2Norm(Functional):
    method __call__ (line 133) | def __call__(x: Union[Array, BlockArray]) -> float:
    method prox (line 140) | def prox(v: Union[Array, BlockArray], lam: float = 1.0, **kwargs) -> U...
  class L2Norm (line 161) | class L2Norm(Functional):
    method __call__ (line 173) | def __call__(x: Union[Array, BlockArray]) -> float:
    method prox (line 178) | def prox(v: Union[Array, BlockArray], lam: float = 1.0, **kwargs) -> U...
  class L21Norm (line 208) | class L21Norm(Functional):
    method __init__ (line 229) | def __init__(self, l2_axis: Union[None, int, Tuple] = 0):
    method _l2norm (line 240) | def _l2norm(
    method __call__ (line 246) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method _prox (line 254) | def _prox(
    method prox (line 265) | def prox(
  class L1MinusL2Norm (line 299) | class L1MinusL2Norm(Functional):
    method __init__ (line 311) | def __init__(self, beta: float = 1.0):
    method _l1minusl2norm (line 320) | def _l1minusl2norm(x: Union[Array, BlockArray], beta: float) -> float:
    method __call__ (line 324) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method _prox_vamx_ge_thresh (line 328) | def _prox_vamx_ge_thresh(v, va, vs, alpha, beta):
    method _prox_vamx_le_alpha (line 337) | def _prox_vamx_le_alpha(v, va, vs, vamx, alpha, beta):
    method _prox_vamx_gt_alpha (line 345) | def _prox_vamx_gt_alpha(v, va, vs, alpha, beta):
    method _prox_vamx_gt_0 (line 352) | def _prox_vamx_gt_0(v, va, vs, vamx, alpha, beta):
    method _prox (line 361) | def _prox(v: Union[Array, BlockArray], lam: float, beta: float) -> Uni...
    method prox (line 377) | def prox(
  class HuberNorm (line 400) | class HuberNorm(Functional):
    method __init__ (line 435) | def __init__(self, delta: float = 1.0, separable: bool = True):
    method _call_sep (line 456) | def _call_sep(x: Union[Array, BlockArray], delta: float) -> float:
    method _call_nonsep (line 463) | def _call_nonsep(x: Union[Array, BlockArray], delta: float) -> float:
    method __call__ (line 469) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method _prox_sep (line 474) | def _prox_sep(
    method _prox_nonsep (line 482) | def _prox_nonsep(
    method prox (line 489) | def prox(
  class NuclearNorm (line 523) | class NuclearNorm(Functional):
    method __call__ (line 539) | def __call__(x: Union[Array, BlockArray]) -> float:
    method prox (line 546) | def prox(v: Union[Array, BlockArray], lam: float = 1.0, **kwargs) -> U...

FILE: scico/functional/_proxavg.py
  class ProximalAverage (line 17) | class ProximalAverage(Functional):
    method __init__ (line 36) | def __init__(
    method __repr__ (line 76) | def __repr__(self):
    method __call__ (line 86) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 98) | def prox(

FILE: scico/functional/_tvnorm.py
  class TVNorm (line 33) | class TVNorm(Functional):
    method __init__ (line 44) | def __init__(
    method _call_operator (line 89) | def _call_operator(self, input_shape: Shape, input_dtype: DType) -> Li...
    method __call__ (line 104) | def __call__(self, x: Array) -> float:
    method _prox_operators (line 117) | def _prox_operators(
    method _slice_tuple_to_tuple (line 164) | def _slice_tuple_to_tuple(st: Tuple) -> Tuple:
    method _slice_tuple_from_tuple (line 174) | def _slice_tuple_from_tuple(st: Tuple) -> Tuple:
    method _prox_core (line 185) | def _prox_core(
    method prox (line 208) | def prox(self, v: Array, lam: float = 1.0, **kwargs) -> Array:
  class AnisotropicTVNorm (line 239) | class AnisotropicTVNorm(TVNorm):
    method __init__ (line 270) | def __init__(
  class IsotropicTVNorm (line 297) | class IsotropicTVNorm(TVNorm):
    method __init__ (line 328) | def __init__(
  class SingleAxisFiniteSum (line 355) | class SingleAxisFiniteSum(LinearOperator):
    method __init__ (line 373) | def __init__(
    method _eval (line 414) | def _eval(self, x: snp.Array) -> snp.Array:
  class FiniteSum (line 418) | class FiniteSum(VerticalStack):
    method __init__ (line 426) | def __init__(
  class SingleAxisHaarTransform (line 458) | class SingleAxisHaarTransform(VerticalStack):
    method __init__ (line 468) | def __init__(
  class HaarTransform (line 499) | class HaarTransform(VerticalStack):
    method __init__ (line 508) | def __init__(

FILE: scico/linop/_circconv.py
  class CircularConvolve (line 25) | class CircularConvolve(LinearOperator):
    method __init__ (line 77) | def __init__(
    method _dft_center_shift (line 154) | def _dft_center_shift(self, input_shape) -> np.ndarray:
    method _eval (line 187) | def _eval(self, x: snp.Array) -> snp.Array:
    method _adj (line 198) | def _adj(self, x: snp.Array) -> snp.Array:  # type: ignore
    method __add__ (line 211) | def __add__(self, other):
    method __sub__ (line 224) | def __sub__(self, other):
    method __mul__ (line 237) | def __mul__(self, scalar):
    method __truediv__ (line 247) | def __truediv__(self, scalar):
    method from_operator (line 257) | def from_operator(

FILE: scico/linop/_convolve.py
  class Convolve (line 25) | class Convolve(LinearOperator):
    method __init__ (line 28) | def __init__(
    method _eval (line 78) | def _eval(self, x: snp.Array) -> snp.Array:
    method __add__ (line 82) | def __add__(self, other):
    method __sub__ (line 99) | def __sub__(self, other):
    method __mul__ (line 115) | def __mul__(self, scalar):
    method __truediv__ (line 126) | def __truediv__(self, scalar):
  class ConvolveByX (line 137) | class ConvolveByX(LinearOperator):
    method __init__ (line 144) | def __init__(
    method _eval (line 198) | def _eval(self, h: snp.Array) -> snp.Array:
    method __add__ (line 202) | def __add__(self, other):
    method __sub__ (line 217) | def __sub__(self, other):
    method __mul__ (line 234) | def __mul__(self, scalar):
    method __truediv__ (line 245) | def __truediv__(self, scalar):

FILE: scico/linop/_dft.py
  class DFT (line 24) | class DFT(LinearOperator):
    method __init__ (line 27) | def __init__(
    method _eval (line 88) | def _eval(self, x: snp.Array) -> snp.Array:
    method inv (line 91) | def inv(self, z: snp.Array) -> snp.Array:

FILE: scico/linop/_diag.py
  class Diagonal (line 26) | class Diagonal(LinearOperator):
    method __init__ (line 29) | def __init__(
    method _eval (line 70) | def _eval(self, x: Union[Array, BlockArray]) -> Union[Array, BlockArray]:
    method diagonal (line 74) | def diagonal(self) -> Union[Array, BlockArray]:
    method T (line 79) | def T(self) -> Diagonal:
    method conj (line 83) | def conj(self) -> Diagonal:
    method H (line 88) | def H(self) -> Diagonal:
    method gram_op (line 93) | def gram_op(self) -> Diagonal:
    method __add__ (line 102) | def __add__(self, other):
    method __sub__ (line 108) | def __sub__(self, other):
    method __mul__ (line 114) | def __mul__(self, scalar):
    method __truediv__ (line 118) | def __truediv__(self, scalar):
    method __matmul__ (line 121) | def __matmul__(self, other):
    method norm (line 130) | def norm(self, ord=None):  # pylint: disable=W0622
  class ScaledIdentity (line 155) | class ScaledIdentity(Diagonal):
    method __init__ (line 158) | def __init__(
    method diagonal (line 183) | def diagonal(self) -> Union[Array, BlockArray]:
    method conj (line 186) | def conj(self) -> ScaledIdentity:
    method gram_op (line 193) | def gram_op(self) -> ScaledIdentity:
    method __add__ (line 202) | def __add__(self, other):
    method __sub__ (line 212) | def __sub__(self, other):
    method __mul__ (line 222) | def __mul__(self, scalar):
    method __truediv__ (line 230) | def __truediv__(self, scalar):
    method __matmul__ (line 237) | def __matmul__(self, other):
    method norm (line 253) | def norm(self, ord=None):  # pylint: disable=W0622
  class Identity (line 271) | class Identity(ScaledIdentity):
    method __init__ (line 274) | def __init__(
    method _eval (line 289) | def _eval(self, x: Union[Array, BlockArray]) -> Union[Array, BlockArray]:
    method conj (line 292) | def conj(self) -> Identity:
    method gram_op (line 297) | def gram_op(self) -> Identity:
    method __matmul__ (line 301) | def __matmul__(self, other):
    method __rmatmul__ (line 304) | def __rmatmul__(self, x: Union[Array, BlockArray]) -> Union[Array, Blo...

FILE: scico/linop/_diff.py
  class FiniteDifference (line 25) | class FiniteDifference(VerticalStack):
    method __init__ (line 47) | def __init__(
  class SingleAxisFiniteDifference (line 99) | class SingleAxisFiniteDifference(LinearOperator):
    method __init__ (line 157) | def __init__(
    method _eval (line 236) | def _eval(self, x: snp.Array) -> snp.Array:

FILE: scico/linop/_func.py
  function linop_from_function (line 23) | def linop_from_function(f: Callable, classname: str, f_name: Optional[st...
  class Crop (line 97) | class Crop(LinearOperator):
    method __init__ (line 100) | def __init__(
  class Slice (line 141) | class Slice(LinearOperator):
    method __init__ (line 144) | def __init__(
    method _eval (line 184) | def _eval(self, x: snp.Array) -> snp.Array:

FILE: scico/linop/_grad.py
  function diffstack (line 25) | def diffstack(x: Array, axis: Optional[Union[int, Tuple[int, ...]]] = No...
  class ProjectedGradient (line 51) | class ProjectedGradient(LinearOperator):
    method __init__ (line 80) | def __init__(
    method _eval (line 162) | def _eval(self, x: Array) -> Union[Array, BlockArray]:
  class PolarGradient (line 184) | class PolarGradient(ProjectedGradient):
    method __init__ (line 204) | def __init__(
  class CylindricalGradient (line 281) | class CylindricalGradient(ProjectedGradient):
    method __init__ (line 301) | def __init__(
  class SphericalGradient (line 407) | class SphericalGradient(ProjectedGradient):
    method __init__ (line 427) | def __init__(

FILE: scico/linop/_linop.py
  function _wrap_add_sub (line 30) | def _wrap_add_sub(func: Callable) -> Callable:
  class LinearOperator (line 123) | class LinearOperator(Operator):
    method __init__ (line 126) | def __init__(
    method _set_adjoint (line 187) | def _set_adjoint(self):
    method _set_gram (line 194) | def _set_gram(self):
    method jit (line 198) | def jit(self):
    method __add__ (line 213) | def __add__(self, other):
    method __sub__ (line 224) | def __sub__(self, other):
    method __mul__ (line 235) | def __mul__(self, other):
    method __rmul__ (line 246) | def __rmul__(self, other):
    method __truediv__ (line 250) | def __truediv__(self, other):
    method __matmul__ (line 260) | def __matmul__(self, other):
    method __rmatmul__ (line 264) | def __rmatmul__(self, other):
    method __call__ (line 279) | def __call__(
    method adj (line 296) | def adj(
    method T (line 330) | def T(self) -> LinearOperator:
    method H (line 363) | def H(self) -> LinearOperator:
    method conj (line 387) | def conj(self) -> LinearOperator:
    method gram_op (line 404) | def gram_op(self) -> LinearOperator:
    method gram (line 422) | def gram(
  class ComposedLinearOperator (line 443) | class ComposedLinearOperator(LinearOperator):
    method __init__ (line 450) | def __init__(self, A: LinearOperator, B: LinearOperator, jit: bool = F...

FILE: scico/linop/_matrix.py
  function _wrap_add_sub_matrix (line 29) | def _wrap_add_sub_matrix(func, op):
  class MatrixOperator (line 64) | class MatrixOperator(LinearOperator):
    method __init__ (line 67) | def __init__(self, A: ArrayLike, input_cols: int = 0):
    method __call__ (line 103) | def __call__(self, other):
    method _eval (line 127) | def _eval(self, other):
    method gram (line 130) | def gram(self, other):
    method __add__ (line 134) | def __add__(self, other):
    method __sub__ (line 138) | def __sub__(self, other):
    method __radd__ (line 141) | def __radd__(self, other):
    method __rsub__ (line 145) | def __rsub__(self, other):
    method __neg__ (line 148) | def __neg__(self):
    method __mul__ (line 153) | def __mul__(self, other):
    method __rmul__ (line 172) | def __rmul__(self, other):
    method __truediv__ (line 176) | def __truediv__(self, other):
    method __rtruediv__ (line 195) | def __rtruediv__(self, other):
    method __getitem__ (line 209) | def __getitem__(self, key):
    method T (line 213) | def T(self):
    method H (line 222) | def H(self):
    method conj (line 230) | def conj(self):
    method adj (line 238) | def adj(self, y):
    method to_array (line 241) | def to_array(self):
    method gram_op (line 246) | def gram_op(self):
    method norm (line 253) | def norm(self, ord=None, axis=None, keepdims=False):  # pylint: disabl...

FILE: scico/linop/_stack.py
  class VerticalStack (line 25) | class VerticalStack(VerticalStackOperator, LinearOperator):
    method __init__ (line 50) | def __init__(
    method _adj (line 71) | def _adj(self, y: Union[Array, BlockArray]) -> Array:  # type: ignore
  class DiagonalStack (line 75) | class DiagonalStack(DiagonalStackOperator, LinearOperator):
    method __init__ (line 114) | def __init__(
    method _adj (line 143) | def _adj(self, y: Union[Array, BlockArray]) -> Union[Array, BlockArray...
  class DiagonalReplicated (line 150) | class DiagonalReplicated(DiagonalReplicatedOperator, LinearOperator):
    method __init__ (line 190) | def __init__(
  function linop_over_axes (line 227) | def linop_over_axes(

FILE: scico/linop/_util.py
  function power_iteration (line 23) | def power_iteration(A: LinearOperator, maxiter: int = 100, key: Optional...
  function operator_norm (line 58) | def operator_norm(A: LinearOperator, maxiter: int = 100, key: Optional[P...
  function valid_adjoint (line 91) | def valid_adjoint(
  function jacobian (line 164) | def jacobian(F: Operator, u: snp.Array, include_eval: Optional[bool] = F...

FILE: scico/linop/optics.py
  function _isscalar (line 69) | def _isscalar(element: Any) -> TypeGuard[Union[int, float]]:
  function radial_transverse_frequency (line 74) | def radial_transverse_frequency(
  class Propagator (line 120) | class Propagator(LinearOperator):
    method __init__ (line 123) | def __init__(
    method __repr__ (line 193) | def __repr__(self):
    method _eval (line 202) | def _eval(self, x):
  class AngularSpectrumPropagator (line 206) | class AngularSpectrumPropagator(Propagator):
    method __init__ (line 253) | def __init__(
    method adequate_sampling (line 293) | def adequate_sampling(self):
    method pinv (line 314) | def pinv(self, y):
  class FresnelPropagator (line 320) | class FresnelPropagator(Propagator):
    method __init__ (line 367) | def __init__(
    method adequate_sampling (line 389) | def adequate_sampling(self):
  class FraunhoferPropagator (line 410) | class FraunhoferPropagator(LinearOperator):
    method __init__ (line 464) | def __init__(
    method __repr__ (line 546) | def __repr__(self):
    method _eval (line 557) | def _eval(self, x):
    method adequate_sampling (line 563) | def adequate_sampling(self):

FILE: scico/linop/xray/_axitom/backprojection.py
  function map_object_to_detector_coords (line 22) | def map_object_to_detector_coords(object_xs, object_ys, object_zs, config):
  function _fdk_axisym (line 76) | def _fdk_axisym(projection_filtered, config, angles):
  function fdk (line 133) | def fdk(projection: Array, config: Config, angles: Optional[Array] = Non...

FILE: scico/linop/xray/_axitom/config.py
  class Config (line 14) | class Config:
    method __init__ (line 17) | def __init__(
    method __repr__ (line 86) | def __repr__(self):
    method with_param (line 98) | def with_param(self, **kwargs):

FILE: scico/linop/xray/_axitom/filtering.py
  function _ramp_kernel_real (line 16) | def _ramp_kernel_real(cutoff, length):
  function _add_weights (line 36) | def _add_weights(projection, config):
  function ramp_filter_and_weight (line 62) | def ramp_filter_and_weight(projection, config):

FILE: scico/linop/xray/_axitom/projection.py
  function _partial_forward_project (line 24) | def _partial_forward_project(
  function forward_project (line 82) | def forward_project(

FILE: scico/linop/xray/_axitom/utilities.py
  function _find_center_of_gravity_in_projection (line 16) | def _find_center_of_gravity_in_projection(projection, background_interns...
  function find_center_of_rotation (line 60) | def find_center_of_rotation(projection, background_internsity=0.9, metho...
  function rotate_coordinates (line 94) | def rotate_coordinates(xs_array, ys_array, angle_rad):

FILE: scico/linop/xray/_util.py
  function image_centroid (line 33) | def image_centroid(v: ArrayLike, center_offset: bool = False) -> Tuple[f...
  function center_image (line 61) | def center_image(
  function rotate_volume (line 89) | def rotate_volume(
  function image_alignment_rotation (line 132) | def image_alignment_rotation(
  function volume_alignment_rotation (line 206) | def volume_alignment_rotation(

FILE: scico/linop/xray/_xray.py
  class XRayTransform2D (line 28) | class XRayTransform2D(LinearOperator):
    method __init__ (line 51) | def __init__(
    method project (line 128) | def project(self, im: ArrayLike) -> snp.Array:
    method back_project (line 136) | def back_project(self, y: ArrayLike) -> snp.Array:
    method fbp (line 144) | def fbp(self, y: ArrayLike) -> snp.Array:
    method _ramp_filter (line 186) | def _ramp_filter(x: ArrayLike, tau: float) -> snp.Array:
    method _project (line 211) | def _project(
    method _back_project (line 247) | def _back_project(
    method _calc_weights (line 280) | def _calc_weights(
  class XRayTransform3D (line 323) | class XRayTransform3D(LinearOperator):
    method __init__ (line 352) | def __init__(
    method project (line 376) | def project(self, im: ArrayLike) -> snp.Array:
    method back_project (line 380) | def back_project(self, proj: ArrayLike) -> snp.Array:
    method _project (line 385) | def _project(im: ArrayLike, matrices: ArrayLike, det_shape: Shape) -> ...
    method _project_single (line 411) | def _project_single(
    method _back_project (line 431) | def _back_project(proj: ArrayLike, matrices: ArrayLike, input_shape: S...
    method _back_project_single (line 458) | def _back_project_single(
    method _calc_weights (line 471) | def _calc_weights(
    method matrices_from_euler_angles (line 533) | def matrices_from_euler_angles(

FILE: scico/linop/xray/abel.py
  class AbelTransform (line 30) | class AbelTransform(LinearOperator):
    method __init__ (line 38) | def __init__(self, img_shape: Shape):
    method _eval (line 54) | def _eval(self, x: jax.Array) -> jax.Array:
    method _adj (line 59) | def _adj(self, x: jax.Array) -> jax.Array:  # type: ignore
    method inverse (line 64) | def inverse(self, y: jax.Array) -> jax.Array:
  function _pyabel_transform (line 78) | def _pyabel_transform(
  function _pyabel_daun_get_proj_matrix (line 120) | def _pyabel_daun_get_proj_matrix(img_shape: Shape) -> jax.Array:

FILE: scico/linop/xray/astra.py
  function set_astra_gpu_index (line 66) | def set_astra_gpu_index(idx: Union[int, Sequence[int]]):
  function _project_coords (line 75) | def _project_coords(
  function project_world_coordinates (line 103) | def project_world_coordinates(
  function volume_coords_to_world_coords (line 140) | def volume_coords_to_world_coords(idx: np.ndarray, vol_geom: VolumeGeome...
  function _volume_index_to_astra_world_2d (line 160) | def _volume_index_to_astra_world_2d(idx: np.ndarray, vol_geom: VolumeGeo...
  function _volume_index_to_astra_world_3d (line 180) | def _volume_index_to_astra_world_3d(idx: np.ndarray, vol_geom: VolumeGeo...
  class XRayTransform2D (line 202) | class XRayTransform2D(LinearOperator):
    method __init__ (line 210) | def __init__(
    method _proj (line 304) | def _proj(self, x: jax.Array) -> jax.Array:
    method _bproj (line 315) | def _bproj(self, y: jax.Array) -> jax.Array:
    method fbp (line 325) | def fbp(self, sino: jax.Array, filter_type: str = "Ram-Lak") -> jax.Ar...
  function convert_from_scico_geometry (line 371) | def convert_from_scico_geometry(
  function _astra_to_scico_geometry (line 417) | def _astra_to_scico_geometry(vol_geom: VolumeGeometry, proj_geom: Projec...
  function convert_to_scico_geometry (line 448) | def convert_to_scico_geometry(
  class XRayTransform3D (line 488) | class XRayTransform3D(LinearOperator):  # pragma: no cover
    method __init__ (line 580) | def __init__(
    method create_astra_geometry (line 674) | def create_astra_geometry(
    method _proj (line 720) | def _proj(self, x: jax.Array) -> jax.Array:
    method _bproj (line 731) | def _bproj(self, y: jax.Array) -> jax.Array:
  function angle_to_vector (line 742) | def angle_to_vector(det_spacing: Tuple[float, float], angles: np.ndarray...
  function rotate_vectors (line 763) | def rotate_vectors(vectors: np.ndarray, rot: Rotation) -> np.ndarray:
  function _ensure_writeable (line 781) | def _ensure_writeable(x):

FILE: scico/linop/xray/svmbir.py
  class XRayTransform (line 35) | class XRayTransform(LinearOperator):
    method __init__ (line 66) | def __init__(
    method _proj (line 205) | def _proj(
    method _proj_hcb (line 233) | def _proj_hcb(self, x):
    method _bproj (line 255) | def _bproj(
    method _bproj_hcb (line 285) | def _bproj_hcb(self, y):
  class SVMBIRExtendedLoss (line 308) | class SVMBIRExtendedLoss(Loss):
    method __init__ (line 336) | def __init__(
    method __call__ (line 391) | def __call__(self, x: snp.Array) -> float:
    method prox (line 397) | def prox(self, v: snp.Array, lam: float = 1, **kwargs) -> snp.Array:
  class SVMBIRSquaredL2Loss (line 437) | class SVMBIRSquaredL2Loss(SVMBIRExtendedLoss, SquaredL2Loss):
    method __init__ (line 453) | def __init__(

FILE: scico/linop/xray/symcone.py
  function _volume_by_axial_symmetry (line 34) | def _volume_by_axial_symmetry(
  class AxiallySymmetricVolume (line 83) | class AxiallySymmetricVolume(LinearOperator):
    method __init__ (line 86) | def __init__(
  class SymConeXRayTransform (line 115) | class SymConeXRayTransform(LinearOperator):
    method __init__ (line 125) | def __init__(
    method fdk (line 177) | def fdk(self, y: ArrayLike, num_angles: int = 360):

FILE: scico/loss.py
  function _loss_mul_div_wrapper (line 27) | def _loss_mul_div_wrapper(func):
  class Loss (line 40) | class Loss(functional.Functional):
    method __init__ (line 52) | def __init__(
    method __call__ (line 87) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 102) | def prox(
    method __mul__ (line 133) | def __mul__(self, other):
    method __rmul__ (line 139) | def __rmul__(self, other):
    method __truediv__ (line 143) | def __truediv__(self, other):
    method set_scale (line 149) | def set_scale(self, new_scale: float):
  class SquaredL2Loss (line 154) | class SquaredL2Loss(Loss):
    method __init__ (line 170) | def __init__(
    method __call__ (line 208) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 211) | def prox(
    method hessian (line 246) | def hessian(self) -> linop.LinearOperator:
  class PoissonLoss (line 270) | class PoissonLoss(Loss):
    method __init__ (line 282) | def __init__(
    method __call__ (line 300) | def __call__(self, x: Union[Array, BlockArray]) -> float:
  class SquaredL2AbsLoss (line 305) | class SquaredL2AbsLoss(Loss):
    method __init__ (line 324) | def __init__(
    method __call__ (line 354) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 357) | def prox(
  function _cbrt (line 371) | def _cbrt(x: Union[Array, BlockArray]) -> Union[Array, BlockArray]:
  function _check_root (line 391) | def _check_root(
  function _dep_cubic_root (line 418) | def _dep_cubic_root(
  class SquaredL2SquaredAbsLoss (line 509) | class SquaredL2SquaredAbsLoss(Loss):
    method __init__ (line 528) | def __init__(
    method __call__ (line 558) | def __call__(self, x: Union[Array, BlockArray]) -> float:
    method prox (line 563) | def prox(

FILE: scico/metric.py
  function mae (line 20) | def mae(reference: Union[Array, BlockArray], comparison: Union[Array, Bl...
  function mse (line 34) | def mse(reference: Union[Array, BlockArray], comparison: Union[Array, Bl...
  function snr (line 48) | def snr(reference: Union[Array, BlockArray], comparison: Union[Array, Bl...
  function psnr (line 65) | def psnr(
  function isnr (line 95) | def isnr(
  function bsnr (line 121) | def bsnr(blurry: Union[Array, BlockArray], noisy: Union[Array, BlockArra...
  function rel_res (line 142) | def rel_res(ax: Union[BlockArray, Array], b: Union[BlockArray, Array]) -...

FILE: scico/numpy/__init__.py
  function ravel (line 63) | def ravel(ba: Union[Array | BlockArray]) -> Array:

FILE: scico/numpy/_blockarray.py
  class BlockArray (line 25) | class BlockArray:
    method __init__ (line 52) | def __init__(self, inputs):
    method dtype (line 61) | def dtype(self):
    method __len__ (line 69) | def __len__(self):
    method __getitem__ (line 72) | def __getitem__(self, key):
    method __setitem__ (line 83) | def __setitem__(self, key, value):
    method blockarray (line 87) | def blockarray(iterable):
    method __repr__ (line 91) | def __repr__(self):
    method stack (line 94) | def stack(self, axis=0):
  function _unary_op_wrapper (line 126) | def _unary_op_wrapper(op_name):
  function _binary_op_wrapper (line 141) | def _binary_op_wrapper(op_name):
  function _jax_array_prop_wrapper (line 166) | def _jax_array_prop_wrapper(prop_name):
  function _jax_array_method_wrapper (line 197) | def _jax_array_method_wrapper(method_name):

FILE: scico/numpy/_wrappers.py
  function add_attributes (line 25) | def add_attributes(
  function wrap_recursively (line 56) | def wrap_recursively(
  function map_func_over_args (line 74) | def map_func_over_args(
  function add_full_reduction (line 177) | def add_full_reduction(func: Callable, axis_arg_name: Optional[str] = "a...

FILE: scico/numpy/util.py
  function transpose_ntpl_of_list (line 26) | def transpose_ntpl_of_list(ntpl: NamedTuple) -> List[NamedTuple]:
  function transpose_list_of_ntpl (line 41) | def transpose_list_of_ntpl(ntlist: List[NamedTuple]) -> NamedTuple:
  function namedtuple_to_array (line 56) | def namedtuple_to_array(ntpl: NamedTuple) -> snp.Array:
  function array_to_namedtuple (line 78) | def array_to_namedtuple(array: snp.Array) -> NamedTuple:
  function normalize_axes (line 97) | def normalize_axes(
  function slice_length (line 154) | def slice_length(length: int, idx: AxisIndex) -> Optional[int]:
  function indexed_shape (line 190) | def indexed_shape(shape: Shape, idx: ArrayIndex) -> Tuple[int, ...]:
  function jax_indexed_shape (line 228) | def jax_indexed_shape(shape: Shape, idx: ArrayIndex) -> Tuple[int, ...]:
  function no_nan_divide (line 268) | def no_nan_divide(
  function _readable_size (line 284) | def _readable_size(size: int) -> str:
  function array_info (line 305) | def array_info(x: Union[snp.BlockArray, snp.Array]) -> str:
  function shape_to_size (line 340) | def shape_to_size(shape: Union[Shape, BlockShape]) -> int:
  function is_array (line 360) | def is_array(x: Any) -> bool:
  function is_arraylike (line 375) | def is_arraylike(x: Any) -> bool:
  function is_nested (line 390) | def is_nested(x: Any) -> bool:
  function is_collapsible (line 412) | def is_collapsible(shapes: Sequence[Union[Shape, BlockShape]]) -> bool:
  function is_blockable (line 427) | def is_blockable(shapes: Sequence[Union[Shape, BlockShape]]) -> TypeGuar...
  function shape_dtype_rep (line 442) | def shape_dtype_rep(
  function broadcast_nested_shapes (line 464) | def broadcast_nested_shapes(
  function is_real_dtype (line 500) | def is_real_dtype(dtype: DType) -> bool:
  function is_complex_dtype (line 513) | def is_complex_dtype(dtype: DType) -> bool:
  function real_dtype (line 526) | def real_dtype(dtype: DType) -> DType:
  function complex_dtype (line 544) | def complex_dtype(dtype: DType) -> DType:
  function dtype_name (line 562) | def dtype_name(dtype: DType) -> str:
  function is_scalar_equiv (line 578) | def is_scalar_equiv(s: Any) -> bool:

FILE: scico/operator/_func.py
  function operator_from_function (line 25) | def operator_from_function(f: Callable, classname: str, f_name: Optional...

FILE: scico/operator/_operator.py
  function _wrap_mul_div_scalar (line 29) | def _wrap_mul_div_scalar(func: Callable) -> Callable:
  class Operator (line 63) | class Operator:
    method __init__ (line 69) | def __init__(
    method jit (line 172) | def jit(self):
    method __str__ (line 176) | def __str__(self):
    method __repr__ (line 179) | def __repr__(self):
    method __call__ (line 187) | def __call__(self, x: Union[Operator, Array, BlockArray]) -> Union[Ope...
    method __add__ (line 227) | def __add__(self, other: Operator) -> Operator:
    method __sub__ (line 240) | def __sub__(self, other: Operator) -> Operator:
    method __mul__ (line 254) | def __mul__(self, other):
    method __neg__ (line 263) | def __neg__(self) -> Operator:
    method __rmul__ (line 267) | def __rmul__(self, other):
    method __truediv__ (line 277) | def __truediv__(self, other):
    method jvp (line 286) | def jvp(self, u, v):
    method vjp (line 305) | def vjp(self, u, conjugate=True):
    method freeze (line 342) | def freeze(self, argnum: int, val: Union[Array, BlockArray]) -> Operator:

FILE: scico/operator/_stack.py
  function collapse_shapes (line 26) | def collapse_shapes(
  class VerticalStack (line 46) | class VerticalStack(Operator):
    method __init__ (line 63) | def __init__(
    method check_if_stackable (line 102) | def check_if_stackable(ops: Sequence[Operator]):
    method _eval (line 126) | def _eval(self, x: Array) -> Union[Array, BlockArray]:
    method __repr__ (line 131) | def __repr__(self):
  class DiagonalStack (line 136) | class DiagonalStack(Operator):
    method __init__ (line 167) | def __init__(
    method check_if_stackable (line 208) | def check_if_stackable(ops: Sequence[Operator]):
    method _eval (line 220) | def _eval(self, x: Union[Array, BlockArray]) -> Union[Array, BlockArray]:
    method __repr__ (line 226) | def __repr__(self):
  class DiagonalReplicated (line 231) | class DiagonalReplicated(Operator):
    method __init__ (line 263) | def __init__(
    method __repr__ (line 334) | def __repr__(self):

FILE: scico/operator/biconvolve.py
  class BiConvolve (line 28) | class BiConvolve(Operator):
    method __init__ (line 40) | def __init__(
    method _eval (line 81) | def _eval(self, x: BlockArray) -> Array:
    method freeze (line 84) | def freeze(self, argnum: int, val: Array) -> scico.linop.LinearOperator:

FILE: scico/optimize/_admm.py
  class ADMM (line 33) | class ADMM(Optimizer):
    method __init__ (line 94) | def __init__(
    method _working_vars_finite (line 150) | def _working_vars_finite(self) -> bool:
    method _objective_evaluatable (line 167) | def _objective_evaluatable(self):
    method _itstat_extra_fields (line 171) | def _itstat_extra_fields(self):
    method _state_variable_names (line 200) | def _state_variable_names(self) -> List[str]:
    method minimizer (line 207) | def minimizer(self) -> Union[Array, BlockArray]:
    method objective (line 210) | def objective(
    method norm_primal_residual (line 254) | def norm_primal_residual(self, x: Optional[Union[Array, BlockArray]] =...
    method norm_dual_residual (line 279) | def norm_dual_residual(self) -> float:
    method z_init (line 297) | def z_init(
    method u_init (line 317) | def u_init(self, x0: Union[Array, BlockArray]) -> List[Union[Array, Bl...
    method step (line 334) | def step(self):

FILE: scico/optimize/_admmaux.py
  class SubproblemSolver (line 39) | class SubproblemSolver:
    method internal_init (line 60) | def internal_init(self, admm: soa.ADMM):
  class GenericSubproblemSolver (line 70) | class GenericSubproblemSolver(SubproblemSolver):
    method __init__ (line 82) | def __init__(self, minimize_kwargs: dict = {"options": {"maxiter": 100...
    method solve (line 92) | def solve(self, x0: Union[Array, BlockArray]) -> Union[Array, BlockArr...
  class LinearSubproblemSolver (line 120) | class LinearSubproblemSolver(SubproblemSolver):
    method __init__ (line 162) | def __init__(self, cg_kwargs: Optional[dict[str, Any]] = None, cg_func...
    method internal_init (line 199) | def internal_init(self, admm: soa.ADMM):
    method compute_rhs (line 225) | def compute_rhs(self) -> Union[Array, BlockArray]:
    method solve (line 252) | def solve(self, x0: Union[Array, BlockArray]) -> Union[Array, BlockArr...
  class MatrixSubproblemSolver (line 266) | class MatrixSubproblemSolver(LinearSubproblemSolver):
    method __init__ (line 305) | def __init__(self, check_solve: bool = False, solve_kwargs: Optional[d...
    method internal_init (line 320) | def internal_init(self, admm: soa.ADMM):
    method solve (line 353) | def solve(self, x0: Array) -> Array:
  class CircularConvolveSolver (line 370) | class CircularConvolveSolver(LinearSubproblemSolver):
    method __init__ (line 391) | def __init__(self, ndims: Optional[int] = None):
    method internal_init (line 406) | def internal_init(self, admm: soa.ADMM):
    method solve (line 449) | def solve(self, x0: Union[Array, BlockArray]) -> Union[Array, BlockArr...
  class FBlockCircularConvolveSolver (line 468) | class FBlockCircularConvolveSolver(LinearSubproblemSolver):
    method __init__ (line 568) | def __init__(self, ndims: Optional[int] = None, check_solve: bool = Fa...
    method internal_init (line 579) | def internal_init(self, admm: soa.ADMM):
    method solve (line 608) | def solve(self, x0: Union[Array, BlockArray]) -> Union[Array, BlockArr...
  class G0BlockCircularConvolveSolver (line 627) | class G0BlockCircularConvolveSolver(SubproblemSolver):
    method __init__ (line 739) | def __init__(self, ndims: Optional[int] = None, check_solve: bool = Fa...
    method internal_init (line 750) | def internal_init(self, admm: soa.ADMM):
    method compute_rhs (line 782) | def compute_rhs(self) -> Union[Array, BlockArray]:
    method solve (line 812) | def solve(self, x0: Union[Array, BlockArray]) -> Union[Array, BlockArr...

FILE: scico/optimize/_common.py
  function itstat_func_and_object (line 28) | def itstat_func_and_object(
  class Optimizer (line 77) | class Optimizer:
    method __init__ (line 86) | def __init__(self, **kwargs: Any):
    method _working_vars_finite (line 137) | def _working_vars_finite(self) -> bool:
    method _itstat_default_fields (line 147) | def _itstat_default_fields(self) -> Tuple[Dict[str, str], List[str]]:
    method _objective_evaluatable (line 167) | def _objective_evaluatable(self) -> bool:
    method _itstat_extra_fields (line 175) | def _itstat_extra_fields(self) -> Tuple[Dict[str, str], List[str]]:
    method _state_variable_names (line 186) | def _state_variable_names(self) -> List[str]:
    method _get_state_variables (line 197) | def _get_state_variables(self) -> dict[str, Any]:
    method _set_state_variables (line 207) | def _set_state_variables(self, **kwargs):
    method save_state (line 222) | def save_state(self, path: str):
    method load_state (line 239) | def load_state(self, path: str):
    method history (line 260) | def history(self, transpose: bool = False) -> Union[List[NamedTuple], ...
    method minimizer (line 275) | def minimizer(self) -> Union[Array, BlockArray]:
    method step (line 283) | def step(self):
    method solve (line 287) | def solve(

FILE: scico/optimize/_ladmm.py
  class LinearizedADMM (line 25) | class LinearizedADMM(Optimizer):
    method __init__ (line 84) | def __init__(
    method _working_vars_finite (line 123) | def _working_vars_finite(self) -> bool:
    method _objective_evaluatable (line 135) | def _objective_evaluatable(self):
    method _itstat_extra_fields (line 139) | def _itstat_extra_fields(self):
    method _state_variable_names (line 145) | def _state_variable_names(self) -> List[str]:
    method minimizer (line 148) | def minimizer(self) -> Union[Array, BlockArray]:
    method objective (line 151) | def objective(
    method norm_primal_residual (line 183) | def norm_primal_residual(self, x: Optional[Union[Array, BlockArray]] =...
    method norm_dual_residual (line 204) | def norm_dual_residual(self) -> float:
    method z_init (line 217) | def z_init(
    method u_init (line 236) | def u_init(self, x0: Union[Array, BlockArray]) -> Union[Array, BlockAr...
    method step (line 253) | def step(self):

FILE: scico/optimize/_padmm.py
  class ProximalADMMBase (line 30) | class ProximalADMMBase(Optimizer):
    method __init__ (line 51) | def __init__(
    method _working_vars_finite (line 118) | def _working_vars_finite(self) -> bool:
    method _objective_evaluatable (line 130) | def _objective_evaluatable(self):
    method _itstat_extra_fields (line 134) | def _itstat_extra_fields(self):
    method _state_variable_names (line 140) | def _state_variable_names(self) -> List[str]:
    method minimizer (line 143) | def minimizer(self) -> Union[Array, BlockArray]:
    method objective (line 146) | def objective(
  class ProximalADMM (line 177) | class ProximalADMM(ProximalADMMBase):
    method __init__ (line 222) | def __init__(
    method norm_primal_residual (line 291) | def norm_primal_residual(
    method norm_dual_residual (line 322) | def norm_dual_residual(self) -> float:
    method step (line 346) | def step(self):
    method estimate_parameters (line 362) | def estimate_parameters(
  class NonLinearPADMM (line 407) | class NonLinearPADMM(ProximalADMMBase):
    method __init__ (line 453) | def __init__(
    method norm_primal_residual (line 509) | def norm_primal_residual(
    method norm_dual_residual (line 540) | def norm_dual_residual(self) -> float:
    method step (line 574) | def step(self):
    method estimate_parameters (line 590) | def estimate_parameters(

FILE: scico/optimize/_pgm.py
  class PGM (line 33) | class PGM(Optimizer):
    method __init__ (line 65) | def __init__(
    method x_step (line 109) | def x_step(self, v: Union[Array, BlockArray], L: float) -> Union[Array...
    method _x_step (line 115) | def _x_step(
    method _working_vars_finite (line 121) | def _working_vars_finite(self) -> bool:
    method _objective_evaluatable (line 129) | def _objective_evaluatable(self):
    method _itstat_extra_fields (line 133) | def _itstat_extra_fields(self):
    method _state_variable_names (line 139) | def _state_variable_names(self) -> List[str]:
    method minimizer (line 142) | def minimizer(self) -> Union[Array, BlockArray]:
    method objective (line 145) | def objective(self, x: Optional[Union[Array, BlockArray]] = None) -> f...
    method f_quad_approx (line 151) | def f_quad_approx(
    method norm_residual (line 168) | def norm_residual(self) -> float:
    method step (line 176) | def step(self):
  class AcceleratedPGM (line 185) | class AcceleratedPGM(PGM):
    method __init__ (line 196) | def __init__(
    method step (line 223) | def step(self):
    method _working_vars_finite (line 244) | def _working_vars_finite(self) -> bool:
    method _state_variable_names (line 252) | def _state_variable_names(self) -> List[str]:

FILE: scico/optimize/_pgmaux.py
  class PGMStepSize (line 23) | class PGMStepSize:
    method internal_init (line 40) | def internal_init(self, pgm: sop.PGM):
    method update (line 49) | def update(self, v: Union[Array, BlockArray]) -> float:
  class BBStepSize (line 65) | class BBStepSize(PGMStepSize):
    method __init__ (line 89) | def __init__(self):
    method update (line 94) | def update(self, v: Union[Array, BlockArray]) -> float:
  class AdaptiveBBStepSize (line 128) | class AdaptiveBBStepSize(PGMStepSize):
    method __init__ (line 169) | def __init__(self, kappa: float = 0.5):
    method update (line 181) | def update(self, v: Union[Array, BlockArray]) -> float:
  class LineSearchStepSize (line 232) | class LineSearchStepSize(PGMStepSize):
    method __init__ (line 254) | def __init__(self, gamma_u: float = 1.2, maxiter: int = 50):
    method update (line 269) | def update(self, v: Union[Array, BlockArray]) -> float:
  class RobustLineSearchStepSize (line 295) | class RobustLineSearchStepSize(LineSearchStepSize):
    method __init__ (line 319) | def __init__(self, gamma_d: float = 0.9, gamma_u: float = 2.0, maxiter...
    method update (line 335) | def update(self, v: Union[Array, BlockArray]) -> float:

FILE: scico/optimize/_primaldual.py
  class PDHG (line 27) | class PDHG(Optimizer):
    method __init__ (line 95) | def __init__(
    method _working_vars_finite (line 145) | def _working_vars_finite(self) -> bool:
    method _objective_evaluatable (line 153) | def _objective_evaluatable(self):
    method _itstat_extra_fields (line 157) | def _itstat_extra_fields(self):
    method _state_variable_names (line 163) | def _state_variable_names(self) -> List[str]:
    method minimizer (line 166) | def minimizer(self) -> Union[Array, BlockArray]:
    method objective (line 169) | def objective(
    method norm_primal_residual (line 192) | def norm_primal_residual(self) -> float:
    method norm_dual_residual (line 206) | def norm_dual_residual(self) -> float:
    method step (line 220) | def step(self):
    method estimate_parameters (line 235) | def estimate_parameters(

FILE: scico/plot.py
  function _attach_keypress (line 48) | def _attach_keypress(fig, scaling=1.1):
  function _attach_zoom (line 86) | def _attach_zoom(ax, scaling=2.0):
  function plot (line 180) | def plot(y, x=None, ptyp="plot", xlbl=None, ylbl=None, title=None, lgnd=...
  function surf (line 289) | def surf(
  function contour (line 406) | def contour(
  function imview (line 557) | def imview(
  function close (line 729) | def close(fig=None):
  function _in_ipython (line 746) | def _in_ipython():
  function _in_notebook (line 762) | def _in_notebook():
  function set_ipython_plot_backend (line 778) | def set_ipython_plot_backend(backend="qt"):
  function set_notebook_plot_backend (line 798) | def set_notebook_plot_backend(backend="inline"):
  function config_notebook_plotting (line 818) | def config_notebook_plotting():

FILE: scico/random.py
  function _add_seed (line 65) | def _add_seed(fun):
  function _wrap (line 129) | def _wrap(fun):
  function _is_wrappable (line 135) | def _is_wrappable(fun):
  function randn (line 149) | def randn(

FILE: scico/ray/tune.py
  class _CustomReporter (line 41) | class _CustomReporter(TuneReporterBase):
    method should_report (line 44) | def should_report(self, trials: List[Trial], done: bool = False):
    method report (line 49) | def report(self, trials: List[Trial], done: bool, *sys_info: Dict):
  function run (line 76) | def run(
  class Tuner (line 187) | class Tuner(ray.tune.Tuner):
    method __init__ (line 190) | def __init__(
    method fit (line 310) | def fit(self) -> ResultGrid:

FILE: scico/solver.py
  function _wrap_func (line 74) | def _wrap_func(func: Callable, shape: Union[Shape, BlockShape], dtype: D...
  function _wrap_func_and_grad (line 103) | def _wrap_func_and_grad(func: Callable, shape: Union[Shape, BlockShape],...
  function _split_real_imag (line 135) | def _split_real_imag(x: Union[Array, BlockArray]) -> Union[Array, BlockA...
  function _join_real_imag (line 154) | def _join_real_imag(x: Union[Array, BlockArray]) -> Union[Array, BlockAr...
  function _ravel (line 172) | def _ravel(x: Union[Array, BlockArray]) -> Array:
  function _unravel (line 187) | def _unravel(x: Array, shape: Union[Shape, BlockShape]) -> Union[Array, ...
  function minimize (line 206) | def minimize(
  function minimize_scalar (line 290) | def minimize_scalar(
  function cg (line 326) | def cg(
  function lstsq (line 408) | def lstsq(
  function bisect (line 469) | def bisect(
  function golden (line 543) | def golden(
  class MatrixATADSolver (line 613) | class MatrixATADSolver:
    method __init__ (line 726) | def __init__(
    method solve (line 805) | def solve(self, b: Array, check_finite: Optional[bool] = None) -> Array:
    method accuracy (line 840) | def accuracy(self, x: Array, b: Array) -> float:
  class ConvATADSolver (line 858) | class ConvATADSolver:
    method __init__ (line 940) | def __init__(self, A: ComposedLinearOperator, D: CircularConvolve):
    method solve (line 972) | def solve(self, b: Array) -> Array:
    method accuracy (line 997) | def accuracy(self, x: Array, b: Array) -> float:

FILE: scico/test/conftest.py
  function pytest_addoption (line 8) | def pytest_addoption(parser, pluginmanager):
  function pytest_configure (line 22) | def pytest_configure(config):
  function pytest_collection_modifyitems (line 27) | def pytest_collection_modifyitems(config, items):

FILE: scico/test/flax/test_apply.py
  function testobj (line 21) | def testobj():
  function test_apply_fn (line 25) | def test_apply_fn(testobj):
  function test_except_only_apply (line 48) | def test_except_only_apply(testobj):
  function test_eval (line 62) | def test_eval(testobj, model_cls):
  function test_apply_from_checkpoint (line 87) | def test_apply_from_checkpoint(testobj):

FILE: scico/test/flax/test_checkpoints.py
  function testobj (line 19) | def testobj():
  function test_checkpoint (line 24) | def test_checkpoint(testobj):
  function test_checkpointing_from_trainer (line 66) | def test_checkpointing_from_trainer(testobj, model_cls):
  function test_checkpoint_exception (line 115) | def test_checkpoint_exception(testobj):

FILE: scico/test/flax/test_clu.py
  function test_count_parameters (line 14) | def test_count_parameters():
  function test_count_parameters_empty (line 54) | def test_count_parameters_empty():
  function test_get_parameter_overview_empty (line 91) | def test_get_parameter_overview_empty():
  class CNN (line 95) | class CNN(Module):
    method __call__ (line 97) | def __call__(self, x):
  function test_get_parameter_overview (line 102) | def test_get_parameter_overview():
  function test_printing_bool (line 116) | def test_printing_bool():

FILE: scico/test/flax/test_examples_flax.py
  function test_foam1_gen (line 42) | def test_foam1_gen():
  function test_foam2_gen (line 52) | def test_foam2_gen():
  function test_distdatagen (line 62) | def test_distdatagen():
  function test_ct_data_generation (line 80) | def test_ct_data_generation():
  function test_blur_data_generation (line 97) | def test_blur_data_generation():
  function test_rotation90 (line 113) | def test_rotation90():
  function test_flip (line 124) | def test_flip():
  function test_center_crop (line 136) | def test_center_crop(output_size):
  function test_positional_crop (line 154) | def test_positional_crop(output_size):
  function test_random_noise1 (line 170) | def test_random_noise1(range_flag):
  function test_random_noise2 (line 183) | def test_random_noise2(shape):
  function test_preprocess_images (line 194) | def test_preprocess_images(output_size, gray_flag, num_img_req):
  function test_preprocess_images_multi_flag (line 225) | def test_preprocess_images_multi_flag():
  class SetupTest (line 251) | class SetupTest:
    method __init__ (line 252) | def __init__(self):
  function testobj (line 271) | def testobj():
  function test_build_image_dataset (line 276) | def test_build_image_dataset(testobj, augment):
  function test_padded_circular_convolve (line 298) | def test_padded_circular_convolve():
  function test_runtime_error_scalar (line 311) | def test_runtime_error_scalar():
  function test_runtime_error_array (line 316) | def test_runtime_error_array():
  function test_default_cache_path (line 321) | def test_default_cache_path():
  function test_cache_path (line 331) | def test_cache_path():

FILE: scico/test/flax/test_flax.py
  class TestSet (line 17) | class TestSet:
    method test_convnblock_default (line 18) | def test_convnblock_default(self):
    method test_convnblock_args (line 31) | def test_convnblock_args(self):
    method test_convblock_default (line 49) | def test_convblock_default(self):
    method test_convblock_args (line 60) | def test_convblock_args(self):
    method test_convblock_call (line 76) | def test_convblock_call(self):
    method test_convnpblock_args (line 96) | def test_convnpblock_args(self):
    method test_convnublock_args (line 117) | def test_convnublock_args(self):
    method test_convmnblock_default (line 138) | def test_convmnblock_default(self):
    method test_upscale (line 153) | def test_upscale(self):
    method test_resnet_default (line 161) | def test_resnet_default(self):
    method test_unet_default (line 177) | def test_unet_default(self):
  class DnCNNNetTest (line 194) | class DnCNNNetTest:
    method __init__ (line 195) | def __init__(self):
  function testobj (line 210) | def testobj():
  function test_DnCNN_call (line 214) | def test_DnCNN_call(testobj):
  function test_DnCNN_train (line 220) | def test_DnCNN_train(testobj):
  function test_DnCNN_test (line 240) | def test_DnCNN_test(testobj):
  function test_FlaxMap_call (line 250) | def test_FlaxMap_call(testobj):
  function test_FlaxMap_3D_call (line 261) | def test_FlaxMap_3D_call(testobj):
  function test_FlaxMap_batch_call (line 273) | def test_FlaxMap_batch_call(testobj):
  function test_FlaxMap_blockarray_exception (line 286) | def test_FlaxMap_blockarray_exception(testobj):
  function test_variable_load (line 301) | def test_variable_load(variant):
  function test_variable_load_mismatch (line 323) | def test_variable_load_mismatch():
  function test_variable_save (line 339) | def test_variable_save():

FILE: scico/test/flax/test_inv.py
  class TestSet (line 19) | class TestSet:
    method setup_method (line 20) | def setup_method(self, method):
    method test_odpdn_default (line 27) | def test_odpdn_default(self):
    method test_odpdcnv_default (line 46) | def test_odpdcnv_default(self):
    method test_odpdcnv_padded (line 71) | def test_odpdcnv_padded(self):
    method test_train_odpdcnv_default (line 93) | def test_train_odpdcnv_default(self):
  class TestCT (line 150) | class TestCT:
    method setup_method (line 151) | def setup_method(self, method):
    method test_odpct_default (line 189) | def test_odpct_default(self):
    method test_modlct_default (line 206) | def test_modlct_default(self):
    method test_train_modl (line 222) | def test_train_modl(self):
    method test_train_odpct (line 254) | def test_train_odpct(self):

FILE: scico/test/flax/test_spectral.py
  function test_l2_normalize (line 25) | def test_l2_normalize():
  function test_conv (line 37) | def test_conv(kernel_size):
  class CNN (line 59) | class CNN(Module):
    method __call__ (line 64) | def __call__(self, x):
  function test_conv_layer (line 78) | def test_conv_layer(kernel_size):
  function test_spectral_norm (line 98) | def test_spectral_norm(input_shape):
  function test_spectral_norm_conv (line 112) | def test_spectral_norm_conv(kernel_shape):
  function test_train_spectral_norm (line 127) | def test_train_spectral_norm():

FILE: scico/test/flax/test_steps.py
  function testobj (line 19) | def testobj():
  function test_basic_train_step (line 23) | def test_basic_train_step(testobj):
  function test_post_train_step (line 66) | def test_post_train_step(testobj):
  function test_basic_eval_step (line 114) | def test_basic_eval_step(testobj):

FILE: scico/test/flax/test_train_aux.py
  function testobj (line 23) | def testobj():
  function test_mse_loss (line 27) | def test_mse_loss():
  function test_data_iterator (line 38) | def test_data_iterator(testobj, batch_size):
  function test_dstrain (line 46) | def test_dstrain(testobj, local_batch):
  function test_dstest (line 70) | def test_dstest(testobj, local_batch):
  function test_prepare_data (line 89) | def test_prepare_data(testobj):
  function test_compute_metrics (line 96) | def test_compute_metrics(testobj):
  function test_cnst_learning_rate (line 109) | def test_cnst_learning_rate(testobj):
  function test_cos_learning_rate (line 116) | def test_cos_learning_rate(testobj):
  function test_exp_learning_rate (line 130) | def test_exp_learning_rate(testobj):
  function test_train_initialize_function (line 143) | def test_train_initialize_function(testobj):
  function test_create_basic_train_state_default (line 171) | def test_create_basic_train_state_default(testobj):
  function test_create_basic_train_state (line 208) | def test_create_basic_train_state(testobj):
  function test_sgd_train_state (line 245) | def test_sgd_train_state(testobj):
  function test_sgd_no_momentum_train_state (line 270) | def test_sgd_no_momentum_train_state(testobj):
  function test_argument_struct (line 296) | def test_argument_struct():
  function test_complete_stats_obj (line 309) | def test_complete_stats_obj():
  function test_except_incomplete_stats_obj (line 332) | def test_except_incomplete_stats_obj():
  function test_patch_incomplete_stats_obj (line 356) | def test_patch_incomplete_stats_obj():

FILE: scico/test/flax/test_trainer.py
  class SetupTest (line 21) | class SetupTest:
    method __init__ (line 22) | def __init__(self):
  function testobj (line 66) | def testobj():
  function test_optimizers (line 71) | def test_optimizers(testobj, opt_type):
  function test_optimizers_exception (line 91) | def test_optimizers_exception(testobj):
  function test_sync_batch_stats (line 107) | def test_sync_batch_stats(testobj):
  function test_class_train_default_init (line 134) | def test_class_train_default_init(testobj):
  function test_class_train_default_noseed (line 152) | def test_class_train_default_noseed(testobj):
  function test_class_train_nolog (line 170) | def test_class_train_nolog(testobj):
  function test_class_train_required_steps (line 191) | def test_class_train_required_steps(testobj):
  function test_except_class_train_batch_size (line 218) | def test_except_class_train_batch_size(testobj):
  function test_class_train_set_steps (line 233) | def test_class_train_set_steps(testobj):
  function test_class_train_set_reporting (line 257) | def test_class_train_set_reporting(testobj):
  function test_class_train_set_functions (line 283) | def test_class_train_set_functions(testobj):
  function test_class_train_set_iterators (line 320) | def test_class_train_set_iterators(testobj):
  function test_class_train_set_parallel (line 341) | def test_class_train_set_parallel(testobj, postl):
  function test_class_train_external_init (line 371) | def test_class_train_external_init(testobj, chkflag):
  function test_class_train_train_loop (line 408) | def test_class_train_train_loop(testobj, model_cls):
  function test_class_train_train_post_loop (line 433) | def test_class_train_train_post_loop(testobj):
  function test_class_train_return_state (line 464) | def test_class_train_return_state(testobj):
  function test_class_train_update_metrics (line 487) | def test_class_train_update_metrics(testobj):
  function test_class_train_update_metrics_nolog (line 512) | def test_class_train_update_metrics_nolog(testobj):

FILE: scico/test/flax/test_traversal.py
  function testobj (line 13) | def testobj():
  function test_construct_traversal (line 18) | def test_construct_traversal(testobj, pname):

FILE: scico/test/functional/prox.py
  function prox_func (line 7) | def prox_func(x, v, f, alpha):
  function prox_solve (line 14) | def prox_solve(v, v0, f, alpha):
  function prox_test (line 28) | def prox_test(v, nrm, prx, alpha, x0=None, rtol=1e-6):

FILE: scico/test/functional/test_composed.py
  class TestComposed (line 14) | class TestComposed:
    method setup_method (line 15) | def setup_method(self):
    method test_eval (line 25) | def test_eval(self):
    method test_prox (line 28) | def test_prox(self):

FILE: scico/test/functional/test_denoiser_func.py
  class TestBM3D (line 15) | class TestBM3D:
    method setup_method (line 16) | def setup_method(self):
    method test_gry (line 25) | def test_gry(self):
    method test_rgb (line 30) | def test_rgb(self):
  class TestBM4D (line 40) | class TestBM4D:
    method setup_method (line 41) | def setup_method(self):
    method test (line 48) | def test(self):
  class TestBlindDnCNN (line 54) | class TestBlindDnCNN:
    method setup_method (line 55) | def setup_method(self):
    method test_sngchn (line 62) | def test_sngchn(self):
    method test_mltchn (line 67) | def test_mltchn(self):
  class TestNonBlindDnCNN (line 73) | class TestNonBlindDnCNN:
    method setup_method (line 74) | def setup_method(self):
    method test_sngchn (line 81) | def test_sngchn(self):
    method test_mltchn (line 86) | def test_mltchn(self):

FILE: scico/test/functional/test_funcional_core.py
  function pytest_generate_tests (line 28) | def pytest_generate_tests(metafunc):
  class ProxTestObj (line 44) | class ProxTestObj:
    method __init__ (line 45) | def __init__(self, dtype):
  function test_prox_obj (line 54) | def test_prox_obj(test_dtype):
  class SeparableTestObject (line 58) | class SeparableTestObject:
    method __init__ (line 59) | def __init__(self, dtype):
  function test_separable_obj (line 74) | def test_separable_obj(test_dtype):
  function test_separable_eval (line 78) | def test_separable_eval(test_separable_obj):
  function test_separable_prox (line 85) | def test_separable_prox(test_separable_obj):
  function test_separable_grad (line 94) | def test_separable_grad(test_separable_obj):
  class HuberNormSep (line 103) | class HuberNormSep(functional.HuberNorm):
    method __init__ (line 104) | def __init__(self, delta=1.0):
  class HuberNormNonSep (line 108) | class HuberNormNonSep(functional.HuberNorm):
    method __init__ (line 109) | def __init__(self, delta=1.0):
  class TestNormProx (line 113) | class TestNormProx:
    method test_prox (line 130) | def test_prox(self, norm, alpha, test_prox_obj):
    method test_conj_prox (line 137) | def test_conj_prox(self, norm, alpha, test_prox_obj):
    method test_prox_blockarray (line 146) | def test_prox_blockarray(self, norm, alpha, test_prox_obj):
    method test_prox_zeros (line 159) | def test_prox_zeros(self, norm, test_prox_obj):
    method test_scaled_attrs (line 166) | def test_scaled_attrs(self, norm, test_prox_obj):
    method test_scaled_eval (line 176) | def test_scaled_eval(self, norm, alpha, test_prox_obj):
    method test_scaled_prox (line 185) | def test_scaled_prox(self, norm, alpha, test_prox_obj):
  class TestBlockArrayEval (line 194) | class TestBlockArrayEval:
    method test_eval (line 215) | def test_eval(self, cls, test_prox_obj):
  function test_proj_obj (line 234) | def test_proj_obj(request):
  class TestProj (line 238) | class TestProj:
    method test_prox (line 243) | def test_prox(self, cnstr, test_proj_obj):
    method test_prox_scale_invariance (line 257) | def test_prox_scale_invariance(self, cnstr, test_proj_obj):
    method test_setdistance (line 267) | def test_setdistance(self, sdist, cnstr, alpha, test_proj_obj):

FILE: scico/test/functional/test_indicator.py
  function test_indicator (line 15) | def test_indicator(indicator):

FILE: scico/test/functional/test_loss.py
  class TestLoss (line 18) | class TestLoss:
    method setup_method (line 19) | def setup_method(self):
    method test_generic_squared_l2 (line 36) | def test_generic_squared_l2(self):
    method test_generic_exception (line 46) | def test_generic_exception(self):
    method test_squared_l2 (line 57) | def test_squared_l2(self):
    method test_squared_l2_grad (line 87) | def test_squared_l2_grad(self):
    method test_weighted_squared_l2 (line 97) | def test_weighted_squared_l2(self):
    method test_poisson (line 115) | def test_poisson(self):
  class TestAbsLoss (line 131) | class TestAbsLoss:
    method setup_method (line 137) | def setup_method(self):
    method test_properties (line 152) | def test_properties(self, loss_tuple):
    method test_prox (line 191) | def test_prox(self, loss_tuple):
  function test_cubic_root (line 221) | def test_cubic_root():

FILE: scico/test/functional/test_misc.py
  class TestCheckAttrs (line 11) | class TestCheckAttrs:
    method test_has_eval (line 32) | def test_has_eval(self, cls):
    method test_has_prox (line 36) | def test_has_prox(self, cls):
  class TestJit (line 40) | class TestJit:
    method test_jit (line 62) | def test_jit(self, cls):
  function test_functional_sum (line 81) | def test_functional_sum():
  function test_scalar_vmap (line 91) | def test_scalar_vmap():
  function test_scalar_pmap (line 105) | def test_scalar_pmap():
  function test_scalar_aggregation (line 118) | def test_scalar_aggregation():
  function test_repr_str (line 139) | def test_repr_str(func):

FILE: scico/test/functional/test_norm.py
  function test_l21norm (line 10) | def test_l21norm(axis):
  function test_l2norm_blockarray (line 31) | def test_l2norm_blockarray():

FILE: scico/test/functional/test_proxavg.py
  function test_proxavg_init (line 11) | def test_proxavg_init():
  function test_proxavg (line 31) | def test_proxavg():

FILE: scico/test/functional/test_separable.py
  class SeparableTestObject (line 17) | class SeparableTestObject:
    method __init__ (line 18) | def __init__(self, dtype):
  function test_separable_obj (line 33) | def test_separable_obj(request):
  function test_separable_eval (line 37) | def test_separable_eval(test_separable_obj):
  function test_separable_prox (line 44) | def test_separable_prox(test_separable_obj):
  function test_separable_grad (line 53) | def test_separable_grad(test_separable_obj):

FILE: scico/test/functional/test_tvnorm.py
  function test_single_axis_haar_transform (line 14) | def test_single_axis_haar_transform(axis):
  function test_haar_transform (line 20) | def test_haar_transform():
  function test_aniso_1d (line 27) | def test_aniso_1d(circular):
  class Test2D (line 63) | class Test2D:
    method setup_method (line 64) | def setup_method(self):
    method test_2d (line 79) | def test_2d(self, tvtype, circular):
  class Test3D (line 122) | class Test3D:
    method setup_method (line 123) | def setup_method(self):
    method test_3d (line 139) | def test_3d(self, tvtype, circular):

FILE: scico/test/linop/test_binop.py
  class TestBinaryOp (line 10) | class TestBinaryOp:
    method setup_method (line 11) | def setup_method(self, method):
    method test_case1 (line 16) | def test_case1(self, operator):
    method test_case2 (line 28) | def test_case2(self, operator):
    method test_case3 (line 40) | def test_case3(self, operator):
    method test_case4 (line 52) | def test_case4(self, operator):

FILE: scico/test/linop/test_circconv.py
  class TestCircularConvolve (line 28) | class TestCircularConvolve:
    method setup_method (line 29) | def setup_method(self, method):
    method test_eval (line 35) | def test_eval(self, axes_shape_spec, input_dtype, jit):
    method test_adjoint (line 63) | def test_adjoint(self, axes_shape_spec, input_dtype, jit):
    method test_scalar_left (line 75) | def test_scalar_left(self, axes_shape_spec, operator, jit):
    method test_scalar_right (line 92) | def test_scalar_right(self, axes_shape_spec, operator, jit):
    method test_add_sub (line 107) | def test_add_sub(self, axes_shape_spec, jit):
    method test_matches_convolve (line 123) | def test_matches_convolve(self, input_dtype, jit):
    method test_center (line 151) | def test_center(self, center, jit):
    method test_fractional_center (line 163) | def test_fractional_center(self, jit):
    method test_from_operator (line 182) | def test_from_operator(self, axes_shape_spec, input_dtype, jit_old_op,...
    method test_from_operator_block_array (line 194) | def test_from_operator_block_array(self):

FILE: scico/test/linop/test_conversions.py
  function testCircularConvolve_from_FiniteDifference (line 24) | def testCircularConvolve_from_FiniteDifference(shape_axes, input_dtype, ...

FILE: scico/test/linop/test_convolve.py
  class TestConvolve (line 15) | class TestConvolve:
    method setup_method (line 16) | def setup_method(self, method):
    method test_eval (line 23) | def test_eval(self, input_shape, input_dtype, mode, jit):
    method test_adjoint (line 39) | def test_adjoint(self, input_shape, mode, jit, input_dtype):
  class ConvolveTestObj (line 50) | class ConvolveTestObj:
    method __init__ (line 51) | def __init__(self):
  function testobj (line 75) | def testobj(request):
  function test_init (line 79) | def test_init(testobj):
  function test_scalar_left (line 89) | def test_scalar_left(testobj, operator):
  function test_scalar_right (line 97) | def test_scalar_right(testobj, operator):
  function test_convolve_add_sub (line 107) | def test_convolve_add_sub(testobj, operator):
  function test_add_sub_different_mode (line 125) | def test_add_sub_different_mode(testobj, operator):
  function test_add_sum_generic_linop (line 134) | def test_add_sum_generic_linop(testobj, operator):
  function test_add_sum_conv (line 146) | def test_add_sum_conv(testobj, operator):
  function test_mul_div_generic_linop (line 158) | def test_mul_div_generic_linop(testobj, operator):
  function test_invalid_mode (line 164) | def test_invalid_mode(testobj):
  function test_dimension_mismatch (line 170) | def test_dimension_mismatch(testobj):
  class TestConvolveByX (line 176) | class TestConvolveByX:
    method setup_method (line 177) | def setup_method(self, method):
    method test_eval (line 184) | def test_eval(self, input_shape, input_dtype, mode, jit):
    method test_adjoint (line 201) | def test_adjoint(self, input_shape, mode, jit, input_dtype):
  class ConvolveByXTestObj (line 212) | class ConvolveByXTestObj:
    method __init__ (line 213) | def __init__(self):
  function cbx_testobj (line 237) | def cbx_testobj(request):
  function test_cbx_scalar_left (line 242) | def test_cbx_scalar_left(cbx_testobj, operator):
  function test_cbx_scalar_right (line 250) | def test_cbx_scalar_right(cbx_testobj, operator):
  function test_convolve_add_sub (line 260) | def test_convolve_add_sub(cbx_testobj, operator):
  function test_add_sub_different_mode (line 278) | def test_add_sub_different_mode(cbx_testobj, operator):
  function test_add_sum_generic_linop (line 287) | def test_add_sum_generic_linop(cbx_testobj, operator):
  function test_add_sum_conv (line 299) | def test_add_sum_conv(cbx_testobj, operator):
  function test_mul_div_generic_linop (line 311) | def test_mul_div_generic_linop(cbx_testobj, operator):
  function test_invalid_mode (line 317) | def test_invalid_mode(cbx_testobj):
  function test_dimension_mismatch (line 323) | def test_dimension_mismatch(cbx_testobj):

FILE: scico/test/linop/test_dft.py
  class TestDFT (line 13) | class TestDFT:
    method setup_method (line 14) | def setup_method(self, method):
    method test_dft (line 31) | def test_dft(self, input_shape, axes_and_shape, norm, jit):
    method test_axes_check (line 60) | def test_axes_check(self):

FILE: scico/test/linop/test_diag.py
  class TestDiagonal (line 21) | class TestDiagonal:
    method setup_method (line 22) | def setup_method(self, method):
    method test_eval (line 29) | def test_eval(self, input_shape, diagonal_dtype):
    method test_eval_broadcasting (line 38) | def test_eval_broadcasting(self, diagonal_dtype):
    method test_adjoint (line 67) | def test_adjoint(self, input_shape, diagonal_dtype):
    method test_binary_op (line 77) | def test_binary_op(self, input_shape1, input_shape2, diagonal_dtype, o...
    method test_matmul (line 97) | def test_matmul(self, input_shape1, input_shape2, diagonal_dtype):
    method test_binary_op_mismatch (line 117) | def test_binary_op_mismatch(self, operator):
    method test_scalar_right (line 130) | def test_scalar_right(self, operator):
    method test_scalar_left (line 147) | def test_scalar_left(self, operator):
    method test_gram_op (line 161) | def test_gram_op(self, diagonal_dtype):
    method test_norm (line 173) | def test_norm(self, diagonal_dtype, ord):
    method test_norm_except (line 183) | def test_norm_except(self):
  class TestScaledIdentity (line 192) | class TestScaledIdentity:
    method setup_method (line 193) | def setup_method(self, method):
    method test_eval (line 200) | def test_eval(self, input_shape, input_dtype):
    method test_binary_op (line 210) | def test_binary_op(self, input_shape, operator):
    method test_scale (line 227) | def test_scale(self):
    method test_norm (line 250) | def test_norm(self, input_dtype, ord):
    method test_norm_except (line 264) | def test_norm_except(self):
  class TestIdentity (line 272) | class TestIdentity:
    method setup_method (line 273) | def setup_method(self, method):
    method test_eval (line 280) | def test_eval(self, input_shape, input_dtype):
    method test_binary_op (line 289) | def test_binary_op(self, input_shape, operator):
    method test_scale (line 315) | def test_scale(self):

FILE: scico/test/linop/test_diff.py
  function test_eval (line 11) | def test_eval():
  function test_except (line 38) | def test_except():
  function test_eval_prepend (line 52) | def test_eval_prepend():
  function test_eval_append (line 60) | def test_eval_append():
  function test_adjoint (line 72) | def test_adjoint(input_shape, input_dtype, axes, jit):
  function test_eval_circular (line 92) | def test_eval_circular(shape_axes, input_dtype, jit):

FILE: scico/test/linop/test_func.py
  function test_transpose (line 11) | def test_transpose():
  function test_transpose_ext_init (line 22) | def test_transpose_ext_init():
  function test_reshape (line 32) | def test_reshape():
  function test_pad (line 43) | def test_pad():
  function test_crop (line 59) | def test_crop():
  function test_crop_pad_adjoint (line 70) | def test_crop_pad_adjoint(pad):
  class SliceTestObj (line 77) | class SliceTestObj:
    method __init__ (line 78) | def __init__(self, dtype):
  function slicetestobj (line 83) | def slicetestobj(request):
  function test_slice_eval (line 100) | def test_slice_eval(slicetestobj, idx):
  function test_slice_adj (line 107) | def test_slice_adj(slicetestobj, idx):
  function test_slice_blockarray (line 121) | def test_slice_blockarray(idx):

FILE: scico/test/linop/test_grad.py
  function test_proj_grad (line 20) | def test_proj_grad():
  class TestPolarGradient (line 40) | class TestPolarGradient:
    method setup_method (line 41) | def setup_method(self, method):
    method test_eval (line 59) | def test_eval(self, cdiff, shape_axes, center, outflags, input_dtype, ...
  class TestCylindricalGradient (line 98) | class TestCylindricalGradient:
    method setup_method (line 99) | def setup_method(self, method):
    method test_eval (line 128) | def test_eval(self, shape_axes, center, outflags, input_dtype, jit):
  class TestSphericalGradient (line 169) | class TestSphericalGradient:
    method setup_method (line 170) | def setup_method(self, method):
    method test_eval (line 199) | def test_eval(self, shape_axes, center, outflags, input_dtype, jit):

FILE: scico/test/linop/test_linop.py
  function adjoint_test (line 23) | def adjoint_test(
  class AbsMatOp (line 41) | class AbsMatOp(linop.LinearOperator):
    method __init__ (line 49) | def __init__(self, A, adj_fn=None):
    method _eval (line 55) | def _eval(self, x):
  class LinearOperatorTestObj (line 59) | class LinearOperatorTestObj:
    method __init__ (line 60) | def __init__(self, dtype):
  function testobj (line 80) | def testobj(request):
  function test_binary_op (line 85) | def test_binary_op(testobj, operator):
  function test_scalar_left (line 106) | def test_scalar_left(testobj, operator, scalar):
  function test_scalar_right (line 117) | def test_scalar_right(testobj, operator, scalar):
  function test_negation (line 126) | def test_negation(testobj):
  function test_invalid_add_sub_array (line 134) | def test_invalid_add_sub_array(testobj, operator):
  function test_invalid_add_sub_scalar (line 141) | def test_invalid_add_sub_scalar(testobj, operator):
  function test_matmul_left (line 147) | def test_matmul_left(testobj):
  function test_matmul_right (line 154) | def test_matmul_right(testobj):
  function test_matvec_left (line 161) | def test_matvec_left(testobj):
  function test_matvec_right (line 168) | def test_matvec_right(testobj):
  function test_gram (line 175) | def test_gram(testobj):
  function test_matvec_call (line 188) | def test_matvec_call(testobj):
  function test_adj_composition (line 193) | def test_adj_composition(testobj):
  function test_transpose_matvec (line 209) | def test_transpose_matvec(testobj):
  function test_transpose_matmul (line 224) | def test_transpose_matmul(testobj):
  function test_conj_transpose_matmul (line 234) | def test_conj_transpose_matmul(testobj):
  function test_conj_matvec (line 244) | def test_conj_matvec(testobj):
  function test_adjoint_matvec (line 253) | def test_adjoint_matvec(testobj):
  function test_adjoint_matmul (line 271) | def test_adjoint_matmul(testobj):
  function test_hermitian (line 280) | def test_hermitian(testobj):
  function test_shape (line 287) | def test_shape(testobj):
  function test_adj_lazy (line 305) | def test_adj_lazy():
  function test_jit_adj_lazy (line 318) | def test_jit_adj_lazy():

FILE: scico/test/linop/test_linop_stack.py
  class TestVerticalStack (line 21) | class TestVerticalStack:
    method setup_method (line 22) | def setup_method(self, method):
    method test_construct (line 26) | def test_construct(self, jit):
    method test_adjoint (line 77) | def test_adjoint(self, collapse_output, jit):
    method test_algebra (line 92) | def test_algebra(self, collapse_output, jit):
  class TestBlockDiagonalLinearOperator (line 112) | class TestBlockDiagonalLinearOperator:
    method test_construct (line 113) | def test_construct(self):
    method test_apply (line 119) | def test_apply(self):
    method test_adjoint (line 134) | def test_adjoint(self):
    method test_input_collapse (line 155) | def test_input_collapse(self):
    method test_output_collapse (line 166) | def test_output_collapse(self):
  class TestDiagonalReplicated (line 179) | class TestDiagonalReplicated:
    method setup_method (line 180) | def setup_method(self, method):
    method test_adjoint (line 183) | def test_adjoint(self):

FILE: scico/test/linop/test_linop_util.py
  function test_valid_adjoint (line 19) | def test_valid_adjoint():
  class PowerIterTestObj (line 31) | class PowerIterTestObj:
    method __init__ (line 32) | def __init__(self, dtype):
  function pitestobj (line 50) | def pitestobj(request):
  function test_power_iteration (line 54) | def test_power_iteration(pitestobj):
  function test_operator_norm (line 67) | def test_operator_norm():
  function test_jacobian (line 84) | def test_jacobian(dtype, inc_eval):

FILE: scico/test/linop/test_matrix.py
  class TestMatrix (line 17) | class TestMatrix:
    method setup_method (line 18) | def setup_method(self, method):
    method test_eval (line 24) | def test_eval(self, matrix_shape, input_dtype, input_cols):
    method test_adjoint (line 39) | def test_adjoint(self, matrix_shape, input_dtype, input_cols):
    method test_adjoint_method (line 49) | def test_adjoint_method(self, matrix_shape, input_dtype, input_cols):
    method test_hermetian_method (line 58) | def test_hermetian_method(self, matrix_shape, input_dtype, input_cols):
    method test_gram_method (line 67) | def test_gram_method(self, matrix_shape, input_dtype, input_cols):
    method test_gram_op (line 76) | def test_gram_op(self, matrix_shape, input_dtype, input_cols):
    method test_add_sub (line 84) | def test_add_sub(self, operator):
    method test_scalar_left (line 101) | def test_scalar_left(self, operator):
    method test_scalar_right (line 111) | def test_scalar_right(self, operator):
    method test_elementwise_matops (line 121) | def test_elementwise_matops(self, operator):
    method test_elementwise_array_left (line 131) | def test_elementwise_array_left(self, operator):
    method test_elementwise_array_right (line 139) | def test_elementwise_array_right(self, operator):
    method test_elementwise_matop_shape_mismatch (line 147) | def test_elementwise_matop_shape_mismatch(self, operator):
    method test_elementwise_array_shape_mismatch (line 156) | def test_elementwise_array_shape_mismatch(self, operator):
    method test_elementwise_linop (line 168) | def test_elementwise_linop(self, operator):
    method test_elementwise_linop_mismatch (line 178) | def test_elementwise_linop_mismatch(self, operator):
    method test_elementwise_linop_invalid (line 187) | def test_elementwise_linop_invalid(self, operator):
    method test_matmul (line 198) | def test_matmul(self):
    method test_matmul_cols (line 208) | def test_matmul_cols(self):
    method test_matmul_linop (line 218) | def test_matmul_linop(self):
    method test_matmul_linop_shape_mismatch (line 228) | def test_matmul_linop_shape_mismatch(self):
    method test_matmul_identity (line 236) | def test_matmul_identity(self):
    method test_init_array (line 242) | def test_init_array(self):
    method test_init_wrong_dims (line 255) | def test_init_wrong_dims(self, matrix_shape):
    method test_to_array (line 260) | def test_to_array(self):
    method test_norm (line 275) | def test_norm(self, ord, axis, keepdims, input_dtype):  # pylint: disa...

FILE: scico/test/linop/test_optics.py
  class TestPropagator (line 19) | class TestPropagator:
    method setup_method (line 20) | def setup_method(self, method):
    method test_prop_adjoint (line 30) | def test_prop_adjoint(self, prop, ndim):
    method test_AS_inverse (line 35) | def test_AS_inverse(self, ndim):
    method test_3d_invalid (line 45) | def test_3d_invalid(self, prop):
    method test_shape_dx_mismatch (line 50) | def test_shape_dx_mismatch(self, prop):
    method test_3d_invalid_radial (line 54) | def test_3d_invalid_radial(self):
    method test_shape_dx_mismatch_radial (line 58) | def test_shape_dx_mismatch_radial(self):
  function test_asp_sampling (line 64) | def test_asp_sampling(ndim):
  function test_fresnel_sampling (line 75) | def test_fresnel_sampling(ndim):
  function test_fraunhofer_sampling (line 86) | def test_fraunhofer_sampling(ndim):

FILE: scico/test/linop/xray/test_abel.py
  function make_im (line 15) | def make_im(Nx, Ny):
  function test_inverse (line 24) | def test_inverse(Nx, Ny):
  function test_adjoint (line 35) | def test_adjoint(Nx, Ny):
  function test_ATA (line 42) | def test_ATA(Nx, Ny):
  function test_grad (line 51) | def test_grad(Nx, Ny):
  function test_adjoint_grad (line 61) | def test_adjoint_grad(Nx, Ny):

FILE: scico/test/linop/xray/test_astra.py
  function make_im (line 34) | def make_im(Nx, Ny, is_3d=True):
  function get_tol (line 45) | def get_tol():
  function get_tol_random_input (line 53) | def get_tol_random_input():
  class XRayTransform2DTest (line 61) | class XRayTransform2DTest:
    method __init__ (line 62) | def __init__(self, volume_geometry):
  function testobj (line 81) | def testobj(request):
  function test_init (line 85) | def test_init(testobj):
  function test_ATA_call (line 110) | def test_ATA_call(testobj):
  function test_ATA_matmul (line 117) | def test_ATA_matmul(testobj):
  function test_AAT_call (line 124) | def test_AAT_call(testobj):
  function test_AAT_matmul (line 131) | def test_AAT_matmul(testobj):
  function test_grad (line 138) | def test_grad(testobj):
  function test_adjoint_grad (line 149) | def test_adjoint_grad(testobj):
  function test_adjoint_random (line 157) | def test_adjoint_random(testobj):
  function test_adjoint_typical_input (line 162) | def test_adjoint_typical_input(testobj):
  function test_fbp (line 169) | def test_fbp(testobj):
  function test_jit_in_DiagonalStack (line 176) | def test_jit_in_DiagonalStack():
  function test_3D_on_GPU (line 184) | def test_3D_on_GPU():
  function test_3D_api_equiv (line 196) | def test_3D_api_equiv():
  function test_angle_to_vector (line 209) | def test_angle_to_vector():
  function test_rotate_vectors (line 216) | def test_rotate_vectors():
  function test_geometry (line 226) | def test_geometry():
  function test_projection_convention (line 263) | def test_projection_convention(test_geometry):
  function test_project_coords (line 286) | def test_project_coords(test_geometry):
  function test_convert_to_scico_geometry (line 303) | def test_convert_to_scico_geometry(test_geometry):
  function test_convert_from_scico_geometry (line 313) | def test_convert_from_scico_geometry(test_geometry):
  function test_vol_coord_to_world_coord (line 328) | def test_vol_coord_to_world_coord():
  function test_ensure_writeable (line 335) | def test_ensure_writeable():

FILE: scico/test/linop/xray/test_svmbir.py
  function pytest_generate_tests (line 30) | def pytest_generate_tests(metafunc):
  function make_im (line 62) | def make_im(Nx, Ny, is_3d=True):
  function make_angles (line 73) | def make_angles(num_angles):
  function make_A (line 77) | def make_A(
  function test_grad (line 104) | def test_grad(
  function test_adjoint (line 132) | def test_adjoint(
  function test_prox (line 155) | def test_prox(
  function test_prox_weights (line 186) | def test_prox_weights(
  function test_prox_cg (line 220) | def test_prox_cg(
  function test_approx_prox (line 270) | def test_approx_prox(

FILE: scico/test/linop/xray/test_symcone.py
  class TestAxialSymm (line 15) | class TestAxialSymm:
    method setup_method (line 16) | def setup_method(self, method):
    method test_vbas (line 25) | def test_vbas(self, axis):
  class TestAbelCone (line 44) | class TestAbelCone:
    method setup_method (line 45) | def setup_method(self, method):
    method test_2d (line 54) | def test_2d(self, num_slabs):
    method test_2d_unequal (line 62) | def test_2d_unequal(self, num_slabs):
    method test_3d (line 71) | def test_3d(self, num_slabs):
    method test_3d_unequal (line 78) | def test_3d_unequal(self, num_slabs):
    method test_2d3d_unequal (line 86) | def test_2d3d_unequal(self, num_slabs):
    method test_proj_axis (line 94) | def test_proj_axis(self, axis):
    method test_fdk (line 113) | def test_fdk(self, axis):

FILE: scico/test/linop/xray/test_xray_2d.py
  function test_init (line 15) | def test_init():
  function test_apply (line 33) | def test_apply():
  function test_apply_adjoint (line 52) | def test_apply_adjoint():
  function test_matched_adjoint (line 77) | def test_matched_adjoint():
  function test_fbp (line 90) | def test_fbp(dx, det_count_factor):
  function test_fbp_jit (line 105) | def test_fbp_jit():

FILE: scico/test/linop/xray/test_xray_3d.py
  function test_matched_adjoint (line 9) | def test_matched_adjoint():
  function test_scaling (line 29) | def test_scaling():

FILE: scico/test/linop/xray/test_xray_util.py
  function test_image_centroid (line 29) | def test_image_centroid():
  function test_center_image (line 36) | def test_center_image():
  function test_rotate_volume (line 45) | def test_rotate_volume():
  function align_test_tol (line 52) | def align_test_tol():
  function test_image_alignment (line 61) | def test_image_alignment():
  function test_volume_alignment (line 73) | def test_volume_alignment():

FILE: scico/test/numpy/test_blockarray.py
  function make_arbitrary_jax_array (line 22) | def make_arbitrary_jax_array(shape, dtype):
  function sequence_assert_allclose (line 29) | def sequence_assert_allclose(x, y, *args, **kwargs):
  class OperatorsTestObj (line 37) | class OperatorsTestObj:
    method __init__ (line 40) | def __init__(self, dtype):
  function test_operator_obj (line 72) | def test_operator_obj(request):
  function test_operator_left (line 78) | def test_operator_left(test_operator_obj, operator):
  function test_operator_right (line 87) | def test_operator_right(test_operator_obj, operator):
  function test_ba_ba_operator (line 97) | def test_ba_ba_operator(test_operator_obj, operator):
  function test_ba_ba_matmul (line 107) | def test_ba_ba_matmul(test_operator_obj):
  function test_conj (line 127) | def test_conj(test_operator_obj):
  function test_real (line 135) | def test_real(test_operator_obj):
  function test_imag (line 142) | def test_imag(test_operator_obj):
  function test_ndim (line 149) | def test_ndim(test_operator_obj):
  function test_getitem (line 154) | def test_getitem(test_operator_obj):
  function test_split (line 175) | def test_split(test_operator_obj):
  function test_blockarray_from_one_array (line 181) | def test_blockarray_from_one_array():
  function test_sum_method (line 190) | def test_sum_method(test_operator_obj, axis, keepdims):
  function test_eval_shape_1arg (line 199) | def test_eval_shape_1arg(test_operator_obj):
  function test_eval_shape_2arg (line 210) | def test_eval_shape_2arg(test_operator_obj):
  function test_linear_transpose (line 227) | def test_linear_transpose(test_operator_obj):
  function test_ba_ba_dot (line 236) | def test_ba_ba_dot(test_operator_obj, operator):
  class BlockArrayReductionObj (line 258) | class BlockArrayReductionObj:
    method __init__ (line 259) | def __init__(self, dtype):
  function reduction_obj (line 275) | def reduction_obj(request):
  function test_reduce (line 291) | def test_reduce(reduction_obj, func):
  function test_reduce_axis (line 301) | def test_reduce_axis(reduction_obj, func, axis):
  function test_reduce_singleton (line 316) | def test_reduce_singleton(reduction_obj, func):
  class TestCreators (line 330) | class TestCreators:
    method setup_method (line 331) | def setup_method(self, method):
    method test_zeros (line 339) | def test_zeros(self):
    method test_empty (line 344) | def test_empty(self):
    method test_ones (line 349) | def test_ones(self):
    method test_full (line 354) | def test_full(self):
    method test_full_nodtype (line 361) | def test_full_nodtype(self):
  function test_list_triggering (line 369) | def test_list_triggering():
  function test_test_func (line 378) | def test_test_func(func):
  function x (line 388) | def x():
  function y (line 394) | def y():
  function test_unary (line 400) | def test_unary(op, x):
  function test_elementwise_binary (line 424) | def test_elementwise_binary(op, x, y):
  function test_not_implemented_binary (line 431) | def test_not_implemented_binary(x):
  function test_matmul (line 436) | def test_matmul(x):
  function test_property (line 446) | def test_property():
  function test_method (line 453) | def test_method():
  function test_stack (line 461) | def test_stack():
  function test_ravel (line 470) | def test_ravel():

FILE: scico/test/numpy/test_numpy.py
  function on_cpu (line 11) | def on_cpu():
  function check_results (line 15) | def check_results(jout, sout):
  function test_reshape_array (line 31) | def test_reshape_array():
  function test_ufunc_abs (line 36) | def test_ufunc_abs():
  function test_ufunc_maximum (line 58) | def test_ufunc_maximum():
  function test_ufunc_sign (line 102) | def test_ufunc_sign():
  function test_ufunc_where (line 116) | def test_ufunc_where():
  function test_ufunc_true_divide (line 140) | def test_ufunc_true_divide():
  function test_ufunc_floor_divide (line 167) | def test_ufunc_floor_divide():
  function test_ufunc_real (line 194) | def test_ufunc_real():
  function test_ufunc_imag (line 212) | def test_ufunc_imag():
  function test_ufunc_conj (line 230) | def test_ufunc_conj():
  function test_create_zeros (line 248) | def test_create_zeros():
  function test_create_ones (line 264) | def test_create_ones():
  function test_create_empty (line 272) | def test_create_empty():
  function test_create_full (line 280) | def test_create_full():
  function test_create_zeros_like (line 291) | def test_create_zeros_like():
  function test_create_empty_like (line 307) | def test_create_empty_like():
  function test_create_ones_like (line 321) | def test_create_ones_like():
  function test_create_full_like (line 335) | def test_create_full_like():
  function test_wrap_recursively (line 349) | def test_wrap_recursively():
  function test_add_full_reduction (line 357) | def test_add_full_reduction():

FILE: scico/test/numpy/test_numpy_util.py
  function test_ntpl_list_transpose (line 35) | def test_ntpl_list_transpose():
  function test_namedtuple_to_array (line 44) | def test_namedtuple_to_array():
  function test_no_nan_divide_array (line 52) | def test_no_nan_divide_array():
  function test_no_nan_divide_blockarray (line 64) | def test_no_nan_divide_blockarray():
  function test_array_info (line 76) | def test_array_info():
  function test_normalize_axes (line 88) | def test_normalize_axes():
  function test_slice_length (line 124) | def test_slice_length(length, start, stop, stride):
  function test_slice_length_other (line 132) | def test_slice_length_other(length, slc):
  function test_indexed_shape (line 157) | def test_indexed_shape(shape, slc):
  function test_is_nested (line 163) | def test_is_nested():
  function test_is_collapsible (line 186) | def test_is_collapsible():
  function test_is_blockable (line 193) | def test_is_blockable():
  function test_shape_dtype_rep (line 201) | def test_shape_dtype_rep(shape):
  function test_is_real_dtype (line 206) | def test_is_real_dtype():
  function test_is_complex_dtype (line 211) | def test_is_complex_dtype():
  function test_real_dtype (line 216) | def test_real_dtype():
  function test_complex_dtype (line 220) | def test_complex_dtype():
  function test_dtype_name (line 224) | def test_dtype_name():
  function test_broadcast_nested_shapes (line 229) | def test_broadcast_nested_shapes():
  function test_is_scalar_equiv (line 246) | def test_is_scalar_equiv():

FILE: scico/test/operator/test_biconvolve.py
  class TestBiConvolve (line 14) | class TestBiConvolve:
    method setup_method (line 15) | def setup_method(self, method):
    method test_eval (line 21) | def test_eval(self, input_dtype, mode, jit):
    method test_invalid_shapes (line 43) | def test_invalid_shapes(self):

FILE: scico/test/operator/test_op_stack.py
  class TestVerticalStack (line 26) | class TestVerticalStack:
    method setup_method (line 27) | def setup_method(self, method):
    method test_construct (line 31) | def test_construct(self, jit):
    method test_algebra (line 77) | def test_algebra(self, collapse_output, jit):
  class TestBlockDiagonalOperator (line 97) | class TestBlockDiagonalOperator:
    method test_construct (line 98) | def test_construct(self):
    method test_apply (line 115) | def test_apply(self):
    method test_input_collapse (line 130) | def test_input_collapse(self):
    method test_output_collapse (line 141) | def test_output_collapse(self):
  class TestDiagonalReplicated (line 152) | class TestDiagonalReplicated:
    method setup_method (line 153) | def setup_method(self, method):
    method test_map_auto_vmap (line 158) | def test_map_auto_vmap(self, input_axis, map_type):
    method test_map_auto_pmap (line 168) | def test_map_auto_pmap(self):
    method test_input_axis (line 176) | def test_input_axis(self):
    method test_output_axis (line 188) | def test_output_axis(self):

FILE: scico/test/operator/test_operator.py
  class AbsOperator (line 21) | class AbsOperator(Operator):
    method _eval (line 22) | def _eval(self, x):
  class SquareOperator (line 26) | class SquareOperator(Operator):
    method _eval (line 27) | def _eval(self, x):
  class SumSquareOperator (line 31) | class SumSquareOperator(Operator):
    method _eval (line 32) | def _eval(self, x):
  class OperatorTestObj (line 36) | class OperatorTestObj:
    method __init__ (line 37) | def __init__(self, dtype):
  function testobj (line 53) | def testobj(request):
  function test_binary_op (line 58) | def test_binary_op(testobj, operator):
  function test_binary_op_same (line 74) | def test_binary_op_same(testobj, operator):
  function test_scalar_left (line 89) | def test_scalar_left(testobj, operator, scalar):
  function test_scalar_right (line 99) | def test_scalar_right(testobj, operator, scalar):
  function test_negation (line 109) | def test_negation(testobj):
  function test_invalid_add_sub_array (line 118) | def test_invalid_add_sub_array(testobj, operator):
  function test_invalid_add_sub_scalar (line 125) | def test_invalid_add_sub_scalar(testobj, operator):
  function test_call_operator_operator (line 131) | def test_call_operator_operator(testobj):
  function test_shape_call_vec (line 142) | def test_shape_call_vec(testobj):
  function test_scale_vmap (line 148) | def test_scale_vmap(testobj):
  function test_scale_pmap (line 161) | def test_scale_pmap(testobj):
  function test_freeze_3arg (line 174) | def test_freeze_3arg():
  function test_freeze_2arg (line 200) | def test_freeze_2arg():
  function test_func_op (line 219) | def test_func_op(op_fn, dtype):
  function test_make_func_op (line 228) | def test_make_func_op():
  function test_make_func_op_ext_init (line 236) | def test_make_func_op_ext_init():
  class TestJacobianProdReal (line 246) | class TestJacobianProdReal:
    method setup_method (line 247) | def setup_method(self):
    method test_jvp (line 264) | def test_jvp(self):
    method test_vjp_conj (line 269) | def test_vjp_conj(self):
    method test_vjp_noconj (line 275) | def test_vjp_noconj(self):
  class TestJacobianProdComplex (line 282) | class TestJacobianProdComplex:
    method setup_method (line 283) | def setup_method(self):
    method test_jvp (line 300) | def test_jvp(self):
    method test_vjp_conj (line 305) | def test_vjp_conj(self):
    method test_vjp_noconj (line 311) | def test_vjp_noconj(self):

FILE: scico/test/optimize/test_admm.py
  class TestMisc (line 21) | class TestMisc:
    method setup_method (line 22) | def setup_method(self, method):
    method test_admm (line 26) | def test_admm(self):
    method test_admm_aux (line 80) | def test_admm_aux(self, solver):
  class TestReal (line 109) | class TestReal:
    method setup_method (line 110) | def setup_method(self, method):
    method test_admm_generic (line 130) | def test_admm_generic(self):
    method test_admm_saveload (line 151) | def test_admm_saveload(self):
    method test_admm_quadratic_scico (line 194) | def test_admm_quadratic_scico(self):
    method test_admm_quadratic_jax (line 215) | def test_admm_quadratic_jax(self):
    method test_admm_quadratic_relax (line 236) | def test_admm_quadratic_relax(self):
  class TestRealWeighted (line 259) | class TestRealWeighted:
    method setup_method (line 260) | def setup_method(self, method):
    method test_admm_quadratic_linear (line 283) | def test_admm_quadratic_linear(self):
    method test_admm_quadratic_matrix (line 304) | def test_admm_quadratic_matrix(self):
  class TestComplex (line 326) | class TestComplex:
    method setup_method (line 327) | def setup_method(self, method):
    method test_admm_generic (line 346) | def test_admm_generic(self):
    method test_admm_quadratic_linear (line 367) | def test_admm_quadratic_linear(self):
    method test_admm_quadratic_matrix (line 390) | def test_admm_quadratic_matrix(self):
  class TestCircularConvolveSolve (line 414) | class TestCircularConvolveSolve:
    method setup_and_teardown (line 417) | def setup_and_teardown(self, extra_axis, center):
    method test_admm (line 436) | def test_admm(self):
  class TestSpecialCaseCircularConvolveSolve (line 468) | class TestSpecialCaseCircularConvolveSolve:
    method setup_and_teardown (line 471) | def setup_and_teardown(self, with_cconv):
    method test_admm (line 488) | def test_admm(self):
  class TestBlockCircularConvolveSolve (line 520) | class TestBlockCircularConvolveSolve:
    method setup_method (line 521) | def setup_method(self, method):
    method test_fblock_init (line 540) | def test_fblock_init(self):
    method test_g0block_init (line 569) | def test_g0block_init(self):
    method test_solve (line 598) | def test_solve(self):

FILE: scico/test/optimize/test_ladmm.py
  class TestMisc (line 14) | class TestMisc:
    method setup_method (line 15) | def setup_method(self, method):
    method test_itstat (line 26) | def test_itstat(self):
    method test_callback (line 54) | def test_callback(self):
    method test_finite_check (line 71) | def test_finite_check(self):
  class TestBlockArray (line 81) | class TestBlockArray:
    method setup_method (line 82) | def setup_method(self, method):
    method test_blockarray (line 101) | def test_blockarray(self):
  class TestReal (line 114) | class TestReal:
    method setup_method (line 115) | def setup_method(self, method):
    method test_ladmm (line 132) | def test_ladmm(self):
    method test_ladmm_saveload (line 152) | def test_ladmm_saveload(self):
  class TestComplex (line 191) | class TestComplex:
    method setup_method (line 192) | def setup_method(self, method):
    method test_ladmm (line 209) | def test_ladmm(self):

FILE: scico/test/optimize/test_padmm.py
  class TestMisc (line 14) | class TestMisc:
    method setup_method (line 15) | def setup_method(self, method):
    method test_itstat_padmm (line 34) | def test_itstat_padmm(self):
    method test_itstat_nlpadmm (line 68) | def test_itstat_nlpadmm(self):
    method test_callback (line 101) | def test_callback(self):
    method test_finite_check (line 119) | def test_finite_check(self):
  class TestBlockArray (line 136) | class TestBlockArray:
    method setup_method (line 137) | def setup_method(self, method):
    method test_blockarray_padmm (line 164) | def test_blockarray_padmm(self):
    method test_blockarray_nlpadmm (line 177) | def test_blockarray_nlpadmm(self):
  class TestReal (line 191) | class TestReal:
    method setup_method (line 192) | def setup_method(self, method):
    method test_padmm (line 209) | def test_padmm(self):
    method test_padmm_saveload (line 230) | def test_padmm_saveload(self):
    method test_nlpadmm (line 269) | def test_nlpadmm(self):
  class TestComplex (line 298) | class TestComplex:
    method setup_method (line 299) | def setup_method(self, method):
    method test_nlpadmm (line 316) | def test_nlpadmm(self):
  class TestEstimateParameters (line 345) | class TestEstimateParameters:
    method setup_method (line 346) | def setup_method(self):
    method test_padmm_a (line 364) | def test_padmm_a(self):
    method test_padmm_ab (line 369) | def test_padmm_ab(self):
    method test_real (line 374) | def test_real(self):
    method test_complex (line 379) | def test_complex(self):

FILE: scico/test/optimize/test_pdhg.py
  class TestMisc (line 14) | class TestMisc:
    method setup_method (line 15) | def setup_method(self, method):
    method test_itstat (line 26) | def test_itstat(self):
    method test_callback (line 54) | def test_callback(self):
    method test_finite_check (line 71) | def test_finite_check(self):
  class TestBlockArray (line 87) | class TestBlockArray:
    method setup_method (line 88) | def setup_method(self, method):
    method test_blockarray (line 107) | def test_blockarray(self):
  class TestReal (line 120) | class TestReal:
    method setup_method (line 121) | def setup_method(self, method):
    method test_pdhg (line 138) | def test_pdhg(self):
    method test_pdhg_saveload (line 158) | def test_pdhg_saveload(self):
    method test_nlpdhg (line 196) | def test_nlpdhg(self):
  class TestComplex (line 219) | class TestComplex:
    method setup_method (line 220) | def setup_method(self, method):
    method test_pdhg (line 237) | def test_pdhg(self):
  class TestEstimateParameters (line 258) | class TestEstimateParameters:
    method setup_method (line 259) | def setup_method(self):
    method test_operators_dlft (line 268) | def test_operators_dlft(self):
    method test_operators (line 274) | def test_operators(self):
    method test_ratio (line 281) | def test_ratio(self):

FILE: scico/test/optimize/test_pgm.py
  class TestSet (line 21) | class TestSet:
    method setup_method (line 22) | def setup_method(self, method):
    method test_pgm (line 38) | def test_pgm(self):
    method test_pgm_saveload (line 48) | def test_pgm_saveload(self):
    method test_pgm_isfinite (line 68) | def test_pgm_isfinite(self):
    method test_accelerated_pgm (line 80) | def test_accelerated_pgm(self):
    method test_accelerated_pgm_saveload (line 90) | def test_accelerated_pgm_saveload(self):
    method test_accelerated_pgm_isfinite (line 110) | def test_accelerated_pgm_isfinite(self):
    method test_pgm_BB_step_size (line 122) | def test_pgm_BB_step_size(self):
    method test_pgm_adaptive_BB_step_size (line 139) | def test_pgm_adaptive_BB_step_size(self):
    method test_accelerated_pgm_line_search (line 155) | def test_accelerated_pgm_line_search(self):
    method test_accelerated_pgm_robust_line_search (line 172) | def test_accelerated_pgm_robust_line_search(self):
    method test_pgm_BB_step_size_jit (line 189) | def test_pgm_BB_step_size_jit(self):
    method test_accelerated_pgm_adaptive_BB_step_size_jit (line 211) | def test_accelerated_pgm_adaptive_BB_step_size_jit(self):
  class TestComplex (line 234) | class TestComplex:
    method setup_method (line 235) | def setup_method(self, method):
    method test_pgm (line 251) | def test_pgm(self):
    method test_accelerated_pgm (line 267) | def test_accelerated_pgm(self):
    method test_pgm_BB_step_size (line 277) | def test_pgm_BB_step_size(self):
    method test_pgm_adaptive_BB_step_size (line 294) | def test_pgm_adaptive_BB_step_size(self):
    method test_accelerated_pgm_line_search (line 311) | def test_accelerated_pgm_line_search(self):
    method test_accelerated_pgm_robust_line_search (line 328) | def test_accelerated_pgm_robust_line_search(self):

FILE: scico/test/osver.py
  function osx_ver_geq_than (line 6) | def osx_ver_geq_than(verstr):

FILE: scico/test/test_core.py
  class GradTestObj (line 12) | class GradTestObj:
    method __init__ (line 13) | def __init__(self, dtype):
  function testobj (line 26) | def testobj(request):
  function test_grad (line 30) | def test_grad(testobj):
  function test_grad_aux (line 42) | def test_grad_aux(testobj):
  function test_value_and_grad (line 57) | def test_value_and_grad(testobj):
  function test_value_and_grad_aux (line 72) | def test_value_and_grad_aux(testobj):
  function test_linear_transpose (line 91) | def test_linear_transpose(shape):
  function test_linear_adjoint_shape (line 105) | def test_linear_adjoint_shape(shape):
  function test_linear_adjoint (line 118) | def test_linear_adjoint(testobj):
  function test_linear_adjoint_r_to_c (line 140) | def test_linear_adjoint_r_to_c():
  function test_linear_adjoint_c_to_r (line 151) | def test_linear_adjoint_c_to_r():
  function test_cvjp (line 164) | def test_cvjp(dtype):
  function test_eval_shape_1 (line 195) | def test_eval_shape_1(argskwargs):
  function test_eval_shape_2 (line 227) | def test_eval_shape_2(arrdts):

FILE: scico/test/test_data.py
  class TestSet (line 19) | class TestSet:
    method test_kodim23_uint (line 20) | def test_kodim23_uint(self):
    method test_kodim23_float (line 25) | def test_kodim23_float(self):

FILE: scico/test/test_denoiser.py
  function module_setup_teardown (line 16) | def module_setup_teardown(request):
  class TestBM3D (line 25) | class TestBM3D:
    method setup_method (line 26) | def setup_method(self):
    method test_shape (line 31) | def test_shape(self):
    method test_gry (line 35) | def test_gry(self):
    method test_rgb (line 43) | def test_rgb(self):
    method test_bad_inputs (line 51) | def test_bad_inputs(self):
  class TestBM4D (line 73) | class TestBM4D:
    method setup_method (line 74) | def setup_method(self):
    method test_shape (line 80) | def test_shape(self):
    method test_jit (line 87) | def test_jit(self):
    method test_bad_inputs (line 102) | def test_bad_inputs(self):
  class TestDnCNN (line 120) | class TestDnCNN:
    method setup_method (line 121) | def setup_method(self):
    method test_single_channel (line 127) | def test_single_channel(self):
    method test_multi_channel (line 134) | def test_multi_channel(self):
    method test_init (line 141) | def test_init(self):
    method test_bad_inputs (line 149) | def test_bad_inputs(self):
  class TestNonBLindDnCNN (line 164) | class TestNonBLindDnCNN:
    method setup_method (line 165) | def setup_method(self):
    method test_single_channel (line 172) | def test_single_channel(self):
    method test_multi_channel (line 176) | def test_multi_channel(self):
    method test_bad_inputs (line 180) | def test_bad_inputs(self):

FILE: scico/test/test_diagnostics.py
  class TestSet (line 8) | class TestSet:
    method test_itstat (line 9) | def test_itstat(self):
    method test_display (line 18) | def test_display(self, capsys):
    method test_exception (line 30) | def test_exception(self):
    method test_warning (line 36) | def test_warning(self):

FILE: scico/test/test_examples.py
  function test_rgb2gray (line 30) | def test_rgb2gray():
  function test_volume_read (line 36) | def test_volume_read():
  function test_epfl_deconv_data (line 46) | def test_epfl_deconv_data():
  function test_ucb_diffusercam_data (line 55) | def test_ucb_diffusercam_data():
  function test_downsample_volume (line 64) | def test_downsample_volume():
  function test_tile_volume_slices (line 76) | def test_tile_volume_slices():
  function test_gaussian (line 85) | def test_gaussian():
  function test_create_circular_phantom (line 94) | def test_create_circular_phantom():
  function test_create_cone (line 113) | def test_create_cone(img_shape):
  function test_create_3d_foam_phantom (line 129) | def test_create_3d_foam_phantom(img_shape, N_sphere):
  function test_conv_sparse_phantom (line 134) | def test_conv_sparse_phantom():
  function test_tangle_phantom (line 141) | def test_tangle_phantom():
  function test_spnoise (line 146) | def test_spnoise():
  function test_phase_diff (line 157) | def test_phase_diff():

FILE: scico/test/test_function.py
  class TestFunction (line 11) | class TestFunction:
    method setup_method (line 12) | def setup_method(self):
    method test_init (line 20) | def test_init(self):
    method test_eval (line 26) | def test_eval(self):
    method test_eval_jit (line 36) | def test_eval_jit(self):
    method test_slice (line 47) | def test_slice(self):
    method test_join (line 52) | def test_join(self):
    method test_join_raise (line 57) | def test_join_raise(self):
  function test_jacobian (line 66) | def test_jacobian(dtype):

FILE: scico/test/test_metric.py
  class TestSet (line 7) | class TestSet:
    method setup_method (line 8) | def setup_method(self, method):
    method test_mae_mse (line 11) | def test_mae_mse(self):
    method test_snr_nrm (line 22) | def test_snr_nrm(self):
    method test_snr_signal_range (line 29) | def test_snr_signal_range(self):
    method test_psnr (line 37) | def test_psnr(self):
    method test_isnr (line 43) | def test_isnr(self):
    method test_bsnr (line 49) | def test_bsnr(self):
  function test_rel_res (line 59) | def test_rel_res():

FILE: scico/test/test_random.py
  function test_wrapped_funcs (line 11) | def test_wrapped_funcs(seed):
  function test_add_seed_adapter (line 31) | def test_add_seed_adapter():

FILE: scico/test/test_ray_tune.py
  function test_random_run (line 15) | def test_random_run():
  function test_random_tune (line 40) | def test_random_tune():
  function test_hyperopt_run (line 65) | def test_hyperopt_run():
  function test_hyperopt_tune (line 88) | def test_hyperopt_tune():
  function test_hyperopt_tune_alt_init (line 112) | def test_hyperopt_tune_alt_init():

FILE: scico/test/test_scipy_special.py
  function test_one_arg_funcs (line 29) | def test_one_arg_funcs(func):
  function test_betainc (line 42) | def test_betainc():
  function test_gammainc (line 55) | def test_gammainc(func):
  function test_multigammaln (line 67) | def test_multigammaln():
  function test_logs (line 79) | def test_logs(func):
  function test_zeta (line 90) | def test_zeta():

FILE: scico/test/test_solver.py
  class TestSet (line 11) | class TestSet:
    method setup_method (line 12) | def setup_method(self, method):
    method test_wrap_func_and_grad (line 15) | def test_wrap_func_and_grad(self):
    method test_cg_std (line 28) | def test_cg_std(self):
    method test_cg_op (line 45) | def test_cg_op(self):
    method test_cg_no_info (line 61) | def test_cg_no_info(self):
    method test_cg_complex (line 77) | def test_cg_complex(self):
    method test_preconditioned_cg (line 93) | def test_preconditioned_cg(self):
    method test_lstsq_func (line 116) | def test_lstsq_func(self):
    method test_lstsq_op (line 133) | def test_lstsq_op(self):
  class TestOptimizeScalar (line 149) | class TestOptimizeScalar:
    method setup_method (line 152) | def setup_method(self):
    method fun (line 156) | def fun(self, x, a=1.5):
    method test_minimize_scalar (line 161) | def test_minimize_scalar(self):
  function test_minimize_vector (line 207) | def test_minimize_vector(dtype, method):
  function test_minimize_blockarray (line 230) | def test_minimize_blockarray(dtype, method):
  function test_split_join_array (line 249) | def test_split_join_array():
  function test_split_join_blockarray (line 260) | def test_split_join_blockarray():
  function test_bisect (line 274) | def test_bisect():
  function test_golden (line 289) | def test_golden():
  function test_solve_atai (line 305) | def test_solve_atai(cho_factor, wide, weighted, alpha):
  function test_solve_aati (line 332) | def test_solve_aati(cho_factor, wide, alpha):
  function test_solve_atad (line 351) | def test_solve_atad(cho_factor, wide, vector):

FILE: scico/test/test_util.py
  function test_rattr (line 22) | def test_rattr():
  function test_partial_pos (line 39) | def test_partial_pos():
  function test_partial_kw (line 47) | def test_partial_kw():
  function test_partial_pos_and_kw (line 55) | def test_partial_pos_and_kw():
  function _internet_connected (line 64) | def _internet_connected(host="8.8.8.8", port=53, timeout=3):
  function test_url_get (line 80) | def test_url_get():
  function test_check_for_tracer (line 100) | def test_check_for_tracer():
  function test_timer_basic (line 121) | def test_timer_basic():
  function test_timer_multi (line 133) | def test_timer_multi():
  function test_timer_reset (line 145) | def test_timer_reset():
  function test_ctxttimer_basic (line 154) | def test_ctxttimer_basic():
  function test_ctxttimer_stopstart (line 161) | def test_ctxttimer_stopstart():

FILE: scico/test/test_version.py
  function test_var_val (line 7) | def test_var_val():

FILE: scico/trace.py
  function _get_hash (line 75) | def _get_hash(val: Any) -> Optional[int]:
  function _trace_arg_repr (line 96) | def _trace_arg_repr(val: Any) -> str:
  function register_variable (line 141) | def register_variable(var: Any, name: str):
  function _call_wrapped_function (line 159) | def _call_wrapped_function(func: Callable, *args, **kwargs) -> Any:
  function call_trace (line 193) | def call_trace(func: Callable) -> Callable:
  function _submodule_name (line 279) | def _submodule_name(module, obj):
  function _is_scico_object (line 290) | def _is_scico_object(obj: Any) -> bool:
  function _is_scico_module (line 303) | def _is_scico_module(mod: types.ModuleType) -> bool:
  function _in_module (line 315) | def _in_module(mod: types.ModuleType, obj: Any) -> bool:
  function _is_submodule (line 328) | def _is_submodule(mod: types.ModuleType, submod: types.ModuleType) -> bool:
  function apply_decorator (line 341) | def apply_decorator(
  function trace_scico_calls (line 444) | def trace_scico_calls(verbose: bool = False):

FILE: scico/util.py
  function rgetattr (line 23) | def rgetattr(obj: object, name: str, default: Optional[Any] = None) -> Any:
  function rsetattr (line 46) | def rsetattr(obj: object, name: str, value: Any):
  function partial (line 61) | def partial(func: Callable, indices: Sequence, *fixargs: Any, **fixkwarg...
  function device_info (line 109) | def device_info(devid: int = 0) -> str:  # pragma: no cover
  function check_for_tracer (line 129) | def check_for_tracer(func: Callable) -> Callable:
  function url_get (line 149) | def url_get(
  class Timer (line 188) | class Timer:
    method __init__ (line 195) | def __init__(
    method start (line 227) | def start(self, labels: Optional[Union[str, List[str]]] = None):
    method stop (line 257) | def stop(self, labels: Optional[Union[str, List[str]]] = None):
    method reset (line 294) | def reset(self, labels: Optional[Union[str, List[str]]] = None):
    method elapsed (line 325) | def elapsed(self, label: Optional[str] = None, total: bool = True) -> ...
    method labels (line 365) | def labels(self) -> List[str]:
    method __str__ (line 374) | def __str__(self) -> str:
  class ContextTimer (line 407) | class ContextTimer:
    method __init__ (line 427) | def __init__(
    method __enter__ (line 454) | def __enter__(self):
    method __exit__ (line 463) | def __exit__(self, exc_type, exc_value, traceback):
    method elapsed (line 474) | def elapsed(self, total: bool = True) -> float:
Condensed preview — 335 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,006K chars).
[
  {
    "path": ".coveragerc",
    "chars": 299,
    "preview": "[run]\nsource = scico\ncommand_line = -m pytest\nomit =\n    scico/test/*\n    scico/plot.py\n    scico/trace.py\n    scico/lin"
  },
  {
    "path": ".flake8",
    "chars": 99,
    "preview": "[flake8]\nmax-line-length = 100\nignore =\n#E731: do not assign a lambda expression, use a def\n  E731\n"
  },
  {
    "path": ".github/codecov.yml",
    "chars": 164,
    "preview": "coverage:\n  precision: 2\n  round: nearest\n  range: \"80...100\"\n\n  status:\n    project:\n      default:\n        target: aut"
  },
  {
    "path": ".github/isbin.sh",
    "chars": 1258,
    "preview": "#! /bin/bash\n\n# Determine whether files are acceptable for commit into main scico repo\n\nsize_threshold=65536\n\nSAVEIFS=$I"
  },
  {
    "path": ".github/workflows/check_files.yml",
    "chars": 406,
    "preview": "# Check file types and sizes\n\nname: check files\n\non: [push, pull_request]\n\njobs:\n  checkfiles:\n    runs-on: ubuntu-lates"
  },
  {
    "path": ".github/workflows/lint.yml",
    "chars": 660,
    "preview": "# Run isort and black on pushes to main and any pull requests\n\nname: lint\n\non:\n    push:\n        branches:\n          - m"
  },
  {
    "path": ".github/workflows/mypy.yml",
    "chars": 611,
    "preview": "# Install and run mypy\n\nname: mypy\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\n  workflo"
  },
  {
    "path": ".github/workflows/pypi_upload.yml",
    "chars": 969,
    "preview": "# When a tag is pushed, build packages and upload to PyPI\n\nname: pypi upload\n\n# Trigger when tags are pushed\non:\n  push:"
  },
  {
    "path": ".github/workflows/pytest_latest.yml",
    "chars": 1821,
    "preview": "# Install scico requirements and run pytest with latest jax version\n\nname: unit tests (latest jax)\n\n# Controls when the "
  },
  {
    "path": ".github/workflows/pytest_macos.yml",
    "chars": 2587,
    "preview": "# Install scico requirements and run pytest\n\nname: unit tests (macos)\n\non:\n  push:\n    branches: [ main ]\n  pull_request"
  },
  {
    "path": ".github/workflows/pytest_ubuntu.yml",
    "chars": 4597,
    "preview": "# Install scico requirements and run pytest\n\nname: unit tests (ubuntu)\n\non:\n  push:\n    branches: [ main ]\n  pull_reques"
  },
  {
    "path": ".github/workflows/test_examples.yml",
    "chars": 2454,
    "preview": "# Install scico requirements and run short versions of example scripts\n\nname: test examples\n\non:\n  push:\n    branches: ["
  },
  {
    "path": ".gitignore",
    "chars": 1943,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Editor backups\n.*~\n\n# "
  },
  {
    "path": ".gitmodules",
    "chars": 78,
    "preview": "[submodule \"data\"]\n\tpath = data\n\turl = https://github.com/lanl/scico-data.git\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 1412,
    "preview": "# See https://pre-commit.com for more information\n# See https://pre-commit.com/hooks.html for more hooks\nrepos:\n-   repo"
  },
  {
    "path": ".readthedocs.yaml",
    "chars": 1094,
    "preview": "# .readthedocs.yaml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html f"
  },
  {
    "path": "CHANGES.rst",
    "chars": 6009,
    "preview": "===================\nSCICO Release Notes\n===================\n\nVersion 0.0.8   (unreleased)\n----------------------------\n•"
  },
  {
    "path": "LICENSE",
    "chars": 1543,
    "preview": "BSD 3-Clause License\n\nCopyright (c) 2021-2025, Los Alamos National Laboratory\nAll rights reserved.\n\nRedistribution and u"
  },
  {
    "path": "MANIFEST.in",
    "chars": 507,
    "preview": "include MANIFEST.in\ninclude README.md\ninclude CHANGES.rst\ninclude LICENSE\ninclude setup.py\ninclude conftest.py\ninclude p"
  },
  {
    "path": "README.md",
    "chars": 4930,
    "preview": "[![Python \\>= 3.8](https://img.shields.io/badge/python-3.8+-green.svg)](https://www.python.org/)\n[![Package License](htt"
  },
  {
    "path": "conftest.py",
    "chars": 1092,
    "preview": "\"\"\"\nConfigure pytest.\n\"\"\"\n\nimport os\n\nimport numpy as np\n\nimport pytest\n\nos.environ[\"RAY_ACCEL_ENV_VAR_OVERRIDE_ON_ZERO\""
  },
  {
    "path": "dev_requirements.txt",
    "chars": 105,
    "preview": "-r requirements.txt\npylint\npytest>=7.3.0\npytest-split\npackaging\npre-commit\nblack>=24.3.0\nisort\nautoflake\n"
  },
  {
    "path": "docs/Makefile",
    "chars": 980,
    "preview": "# Makefile for Sphinx documentation\n\n\n# You can set these variables from the command line, and also\n# from the environme"
  },
  {
    "path": "docs/docs_requirements.txt",
    "chars": 314,
    "preview": "-r ../requirements.txt\nsphinx>=5.0.0\nsphinxcontrib-napoleon\nsphinxcontrib-bibtex\nsphinx-autodoc-typehints\nfuro>=2024.5.6"
  },
  {
    "path": "docs/rtd_requirements.txt",
    "chars": 123,
    "preview": "# nbconvert>=7.5 requires a version of pandoc that is not available\n#   in the readthedocs build environment\nnbconvert<7"
  },
  {
    "path": "docs/source/_static/scico.css",
    "chars": 2084,
    "preview": "/* furo theme customization */\n\nbody[data-theme=\"dark\"] figure img {\n  filter: invert(100%);\n}\n\n.sidebar-drawer {\n  widt"
  },
  {
    "path": "docs/source/_templates/autosummary/module.rst",
    "chars": 1106,
    "preview": "{{ fullname | escape | underline}}\n\n.. automodule:: {{ fullname }}\n\n   {% block attributes %}\n   {% if attributes %}\n   "
  },
  {
    "path": "docs/source/_templates/package.rst",
    "chars": 252,
    "preview": "API Reference\n=============\n\n.. automodule:: {{ fullname }}\n\n   {% block modules %}\n   {% if modules %}\n   .. autosummar"
  },
  {
    "path": "docs/source/_templates/sidebar/brand.html",
    "chars": 1048,
    "preview": "{#-\n\nHi there!\n\nYou might be interested in https://pradyunsg.me/furo/customisation/sidebar/\n\nAlthough if you're reading "
  },
  {
    "path": "docs/source/advantages.rst",
    "chars": 5313,
    "preview": "Why SCICO?\n==========\n\nAdvantages of JAX-based Design\n------------------------------\n\nThe vast majority of scientific co"
  },
  {
    "path": "docs/source/api.rst",
    "chars": 168,
    "preview": ":orphan:\n\nAPI Documentation\n=================\n\n.. autosummary::\n   :toctree: _autosummary\n   :template: package.rst\n   :"
  },
  {
    "path": "docs/source/classes.rst",
    "chars": 247,
    "preview": ".. _classes:\n\n******************\nMain SCICO Classes\n******************\n\n.. include:: include/blockarray.rst\n.. include::"
  },
  {
    "path": "docs/source/conf/10-project.py",
    "chars": 443,
    "preview": "from scico._version import package_version\n\n# General information about the project.\nproject = \"SCICO\"\ncopyright = \"2020"
  },
  {
    "path": "docs/source/conf/15-theme.py",
    "chars": 1110,
    "preview": "# -- Options for HTML output ----------------------------------------------\n\n# The theme to use for HTML and HTML Help p"
  },
  {
    "path": "docs/source/conf/20-extensions.py",
    "chars": 550,
    "preview": "# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext"
  },
  {
    "path": "docs/source/conf/25-napoleon.py",
    "chars": 1450,
    "preview": "from sphinx.ext.napoleon.docstring import GoogleDocstring\n\n\n## See\n##   https://github.com/sphinx-doc/sphinx/issues/2115"
  },
  {
    "path": "docs/source/conf/30-autodoc.py",
    "chars": 664,
    "preview": "autodoc_default_options = {\n    \"member-order\": \"bysource\",\n    \"inherited-members\": False,\n    \"ignore-module-all\": Fal"
  },
  {
    "path": "docs/source/conf/40-intersphinx.py",
    "chars": 586,
    "preview": "# Intersphinx mapping\nintersphinx_mapping = {\n    \"python\": (\"https://docs.python.org/3/\", None),\n    \"numpy\": (\"https:/"
  },
  {
    "path": "docs/source/conf/45-mathjax.py",
    "chars": 1015,
    "preview": "import os\n\nif os.environ.get(\"NO_MATHJAX\"):\n    extensions.append(\"sphinx.ext.imgmath\")\n    imgmath_image_format = \"svg\""
  },
  {
    "path": "docs/source/conf/50-graphviz.py",
    "chars": 409,
    "preview": "graphviz_output_format = \"svg\"\ninheritance_graph_attrs = dict(rankdir=\"LR\", fontsize=9, ratio=\"compress\", bgcolor=\"trans"
  },
  {
    "path": "docs/source/conf/55-nbsphinx.py",
    "chars": 297,
    "preview": "nbsphinx_prolog = \"\"\"\n.. raw:: html\n\n    <style>\n    .nbinput .prompt, .nboutput .prompt {\n        display: none;\n    }\n"
  },
  {
    "path": "docs/source/conf/60-rtd.py",
    "chars": 904,
    "preview": "import os\n\non_rtd = os.environ.get(\"READTHEDOCS\") == \"True\"\n\n\nif on_rtd:\n    print(\"Building on ReadTheDocs\\n\")\n    prin"
  },
  {
    "path": "docs/source/conf/70-latex.py",
    "chars": 1031,
    "preview": "# -- Options for LaTeX output ---------------------------------------------\n\nlatex_elements = {\n    # The paper size ('l"
  },
  {
    "path": "docs/source/conf/71-texinfo.py",
    "chars": 462,
    "preview": "# -- Options for Texinfo output -------------------------------------------\n\n# Grouping the document tree into Texinfo f"
  },
  {
    "path": "docs/source/conf/72-man_page.py",
    "chars": 346,
    "preview": "# -- Options for manual page output ---------------------------------------\n\n# One entry per manual page. List of tuples"
  },
  {
    "path": "docs/source/conf/80-scico_numpy.py",
    "chars": 2662,
    "preview": "import re\nfrom inspect import getmembers, isfunction\n\n# Rewrite module names for certain functions imported into scico.n"
  },
  {
    "path": "docs/source/conf/81-scico_scipy.py",
    "chars": 1601,
    "preview": "import re\nfrom inspect import getmembers, isfunction\n\n# Similar processing for scico.scipy\nimport scico.scipy\n\nssp_func "
  },
  {
    "path": "docs/source/conf/85-dtype_typehints.py",
    "chars": 2397,
    "preview": "from typing import Optional, Sequence, Union  # needed for typehints_formatter hack\n\nfrom scico.typing import (  # neede"
  },
  {
    "path": "docs/source/conf.py",
    "chars": 2744,
    "preview": "# -*- coding: utf-8 -*-\n\nimport os\nimport sys\n\nconfpath = os.path.dirname(__file__)\nsys.path.append(confpath)\nrootpath ="
  },
  {
    "path": "docs/source/contributing.rst",
    "chars": 12277,
    "preview": ".. _scico_dev_contributing:\n\nContributing\n============\n\nContributions to SCICO are welcome. Before starting work, please"
  },
  {
    "path": "docs/source/docsutil.py",
    "chars": 5856,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2021-2023 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "docs/source/examples.rst",
    "chars": 6472,
    "preview": ".. _example_notebooks:\n\nUsage Examples\n==============\n\n.. toctree::\n   :maxdepth: 1\n\n.. include:: include/examplenotes.r"
  },
  {
    "path": "docs/source/include/blockarray.rst",
    "chars": 6380,
    "preview": ".. _blockarray_class:\n\nBlockArray\n==========\n\n.. testsetup::\n\n   >>> import numpy as np\n   >>> import scico\n   >>> impor"
  },
  {
    "path": "docs/source/include/examplenotes.rst",
    "chars": 1288,
    "preview": ".. _example_depend:\n\nExample Dependencies\n--------------------\n\nSome examples use additional dependencies, which are lis"
  },
  {
    "path": "docs/source/include/functional.rst",
    "chars": 4885,
    "preview": "Functionals\n===========\n\nA functional is\na mapping from :math:`\\mathbb{R}^n` or :math:`\\mathbb{C}^n` to :math:`\\mathbb{R"
  },
  {
    "path": "docs/source/include/learning.rst",
    "chars": 5378,
    "preview": "Learned Models\n==============\n\nIn SCICO, neural network models are used to represent imaging problems and provide differ"
  },
  {
    "path": "docs/source/include/operator.rst",
    "chars": 8568,
    "preview": "Operators\n=========\n\nAn operator is a map from :math:`\\mathbb{R}^n` or :math:`\\mathbb{C}^n`\nto :math:`\\mathbb{R}^m` or :"
  },
  {
    "path": "docs/source/include/optimizer.rst",
    "chars": 11443,
    "preview": ".. _optimizer:\n\nOptimization Algorithms\n=======================\n\nADMM\n----\n\nThe Alternating Direction Method of Multipli"
  },
  {
    "path": "docs/source/index.rst",
    "chars": 396,
    "preview": "SCICO Documentation\n===================\n\n.. toctree::\n   :maxdepth: 2\n   :caption: User Documentation\n\n   overview\n   in"
  },
  {
    "path": "docs/source/install.rst",
    "chars": 4808,
    "preview": ".. _installing:\n\nInstalling SCICO\n================\n\nSCICO requires Python version 3.8 or later. (Version 3.12 is\nrecomme"
  },
  {
    "path": "docs/source/inverse.rst",
    "chars": 17316,
    "preview": "Inverse Problems\n================\n\nIn traditional imaging, the burden of image formation is placed on\nphysical component"
  },
  {
    "path": "docs/source/notes.rst",
    "chars": 11199,
    "preview": "*****\nNotes\n*****\n\n\nDebugging\n=========\n\nIf difficulties are encountered in debugging jitted functions, jit can\nbe globa"
  },
  {
    "path": "docs/source/overview.rst",
    "chars": 3418,
    "preview": "Overview\n========\n\n`Scientific Computational Imaging Code (SCICO)\n<https://github.com/lanl/scico>`__ is a Python package"
  },
  {
    "path": "docs/source/pyfigures/cylindgrad.py",
    "chars": 1613,
    "preview": "import numpy as np\n\nimport scico.linop as scl\nfrom scico import plot\n\ninput_shape = (7, 7, 7)\ncentre = (np.array(input_s"
  },
  {
    "path": "docs/source/pyfigures/polargrad.py",
    "chars": 1152,
    "preview": "import numpy as np\n\nimport scico.linop as scl\nfrom scico import plot\n\ninput_shape = (21, 21)\ncentre = (np.array(input_sh"
  },
  {
    "path": "docs/source/pyfigures/spheregrad.py",
    "chars": 1661,
    "preview": "import numpy as np\n\nimport scico.linop as scl\nfrom scico import plot\n\ninput_shape = (7, 7, 7)\ncentre = (np.array(input_s"
  },
  {
    "path": "docs/source/pyfigures/xray_2d_geom.py",
    "chars": 5017,
    "preview": "import numpy as np\n\nimport matplotlib as mpl\nimport matplotlib.patches as patches\nimport matplotlib.pyplot as plt\n\nmpl.r"
  },
  {
    "path": "docs/source/pyfigures/xray_3d_ang.py",
    "chars": 1957,
    "preview": "import numpy as np\n\nimport matplotlib as mpl\nimport matplotlib.patches as patches\nimport matplotlib.pyplot as plt\n\nmpl.r"
  },
  {
    "path": "docs/source/pyfigures/xray_3d_vec.py",
    "chars": 2485,
    "preview": "import numpy as np\n\nimport matplotlib as mpl\nfrom matplotlib import pyplot as plt\nfrom matplotlib.patches import FancyAr"
  },
  {
    "path": "docs/source/pyfigures/xray_3d_vol.py",
    "chars": 2759,
    "preview": "import numpy as np\n\nimport matplotlib as mpl\nfrom matplotlib import pyplot as plt\nfrom matplotlib.patches import FancyAr"
  },
  {
    "path": "docs/source/references.bib",
    "chars": 25976,
    "preview": "@Article {aggarwal-2019-modl,\n  author =\t {Aggarwal, Hemant K. and Mani, Merry P. and Jacob,\n                  Mathews},"
  },
  {
    "path": "docs/source/style.rst",
    "chars": 17171,
    "preview": ".. _scico_dev_style:\n\n\nStyle Guide\n===========\n\n\nOverview\n--------\n\nWe adhere to `PEP8 <https://www.python.org/dev/peps/"
  },
  {
    "path": "docs/source/team.rst",
    "chars": 1342,
    "preview": "Developers\n==========\n\nCore Developers\n---------------\n\n- `Cristina Garcia Cardona <https://github.com/crstngc>`_\n- `Mic"
  },
  {
    "path": "docs/source/zreferences.rst",
    "chars": 73,
    "preview": "References\n==========\n\n.. bibliography:: references.bib\n   :style: plain\n"
  },
  {
    "path": "docs/tikxfigures/img_align.tex",
    "chars": 2084,
    "preview": "\\documentclass[tikz]{standalone}\n\\usetikzlibrary{calc,angles,quotes}\n\\begin{document}\n\\begin{tikzpicture}[scale=2]\n  \\fo"
  },
  {
    "path": "docs/tikxfigures/makesvg.sh",
    "chars": 178,
    "preview": "#! /bin/bash\n\npdf2svg vol_align_xyz.pdf vol_align_xyz.svg\npdf2svg vol_align_xz.pdf vol_align_xz.svg\npdf2svg vol_align_yz"
  },
  {
    "path": "docs/tikxfigures/vol_align_xyz.tex",
    "chars": 1212,
    "preview": "\\documentclass{standalone}\n\n\\usepackage{tikz, tikz-3dplot}\n\\begin{document}\n\n\\tdplotsetmaincoords{70}{110}\n\n\\begin{tikzp"
  },
  {
    "path": "docs/tikxfigures/vol_align_xz.tex",
    "chars": 906,
    "preview": "\\documentclass{standalone}\n\n\\usepackage{tikz, tikz-3dplot}\n\\begin{document}\n\n\\tdplotsetmaincoords{90}{0}\n\n\\begin{tikzpic"
  },
  {
    "path": "docs/tikxfigures/vol_align_yz.tex",
    "chars": 908,
    "preview": "\\documentclass{standalone}\n\n\\usepackage{tikz, tikz-3dplot}\n\\begin{document}\n\n\\tdplotsetmaincoords{90}{90}\n\n\\begin{tikzpi"
  },
  {
    "path": "examples/README.rst",
    "chars": 4618,
    "preview": "SCICO Usage Examples\n====================\n\nThis directory contains usage examples for the SCICO package. The primary for"
  },
  {
    "path": "examples/examples_requirements.txt",
    "chars": 233,
    "preview": "-r ../requirements.txt\ncolorama\ncolour_demosaicing\nsvmbir>=0.4.0\nastra-toolbox\nxdesign>=0.5.5\nray[tune,train]>=2.44\nhype"
  },
  {
    "path": "examples/jnb.py",
    "chars": 8338,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2024 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "examples/makeindex.py",
    "chars": 3277,
    "preview": "#!/usr/bin/env python\n\n# Construct an index README file and a docs example index file from\n# source index file \"scripts/"
  },
  {
    "path": "examples/makenotebooks.py",
    "chars": 6259,
    "preview": "#!/usr/bin/env python\n\n# Extract a list of Python scripts from \"scripts/index.rst\" and\n# create/update and execute any J"
  },
  {
    "path": "examples/notebooks_requirements.txt",
    "chars": 166,
    "preview": "-r examples-requirements.txt\nipykernel\nipywidgets\nnbformat\nnbconvert\nnb_conda_kernels<=2.5.1  # 2.5.2 broken: see anacon"
  },
  {
    "path": "examples/removejnberr.py",
    "chars": 465,
    "preview": "#!/usr/bin/env python\n\n# Remove output to stderr in notebooks. NB: use with caution!\n# Run as\n#     python removejnberr."
  },
  {
    "path": "examples/scriptcheck.sh",
    "chars": 3181,
    "preview": "#!/usr/bin/env bash\n\n# Basic test of example script functionality by running them all with\n# optimization algorithms con"
  },
  {
    "path": "examples/scripts/README.rst",
    "chars": 18253,
    "preview": "Usage Examples\n==============\n\n\nOrganized by Application\n------------------------\n\n\nComputed Tomography\n^^^^^^^^^^^^^^^^"
  },
  {
    "path": "examples/scripts/ct_abel_tv_admm.py",
    "chars": 3081,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_abel_tv_admm_tune.py",
    "chars": 7741,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_astra_3d_tv_admm.py",
    "chars": 3468,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_astra_3d_tv_padmm.py",
    "chars": 5044,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_astra_noreg_pcg.py",
    "chars": 4295,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_astra_tv_admm.py",
    "chars": 4150,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_astra_weighted_tv_admm.py",
    "chars": 5555,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_datagen_foam2.py",
    "chars": 2291,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_fan_svmbir_ppp_bm3d_admm_prox.py",
    "chars": 7613,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_modl_train_foam2.py",
    "chars": 11466,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_multi_tv_admm.py",
    "chars": 5180,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_odp_train_foam2.py",
    "chars": 8574,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_projector_comparison_2d.py",
    "chars": 4808,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_projector_comparison_3d.py",
    "chars": 6115,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_svmbir_ppp_bm3d_admm_cg.py",
    "chars": 4112,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_svmbir_ppp_bm3d_admm_prox.py",
    "chars": 6337,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_svmbir_tv_multi.py",
    "chars": 6864,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_symcone_tv_padmm.py",
    "chars": 4771,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_tv_admm.py",
    "chars": 4177,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/ct_unet_train_foam2.py",
    "chars": 6218,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_circ_tv_admm.py",
    "chars": 3118,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_datagen_bsds.py",
    "chars": 2774,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_datagen_foam1.py",
    "chars": 2113,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_microscopy_allchn_tv_admm.py",
    "chars": 6114,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_microscopy_tv_admm.py",
    "chars": 4363,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_modl_train_foam1.py",
    "chars": 11059,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_odp_train_foam1.py",
    "chars": 8372,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_ppp_bm3d_admm.py",
    "chars": 2646,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_ppp_bm3d_apgm.py",
    "chars": 2430,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_ppp_bm4d_admm.py",
    "chars": 3030,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_ppp_dncnn_admm.py",
    "chars": 3085,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_ppp_dncnn_padmm.py",
    "chars": 3128,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_tv_admm.py",
    "chars": 4242,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_tv_admm_tune.py",
    "chars": 6164,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/deconv_tv_padmm.py",
    "chars": 4743,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/demosaic_ppp_bm3d_admm.py",
    "chars": 4353,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_approx_tv_multi.py",
    "chars": 4528,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_cplx_tv_nlpadmm.py",
    "chars": 7183,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_cplx_tv_pdhg.py",
    "chars": 6320,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_datagen_bsds.py",
    "chars": 2330,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_dncnn_train_bsds.py",
    "chars": 5688,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_dncnn_universal.py",
    "chars": 2764,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_l1tv_admm.py",
    "chars": 3232,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_ptv_pdhg.py",
    "chars": 5132,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_tv_admm.py",
    "chars": 4485,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_tv_apgm.py",
    "chars": 7194,
    "preview": "#!/Usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/denoise_tv_multi.py",
    "chars": 6848,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/diffusercam_tv_admm.py",
    "chars": 6435,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/index.rst",
    "chars": 5218,
    "preview": "Usage Examples\n==============\n\n\nOrganized by Application\n------------------------\n\n\nComputed Tomography\n^^^^^^^^^^^^^^^^"
  },
  {
    "path": "examples/scripts/sparsecode_apgm.py",
    "chars": 2405,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/sparsecode_conv_admm.py",
    "chars": 4365,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/sparsecode_conv_md_admm.py",
    "chars": 5534,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/sparsecode_nn_admm.py",
    "chars": 2817,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/sparsecode_nn_apgm.py",
    "chars": 2846,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/sparsecode_poisson_apgm.py",
    "chars": 9244,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/superres_ppp_dncnn_admm.py",
    "chars": 3552,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/trace_example.py",
    "chars": 3215,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/scripts/video_rpca_admm.py",
    "chars": 3701,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# This file is part of the SCICO package. Details of the copyright\n# and u"
  },
  {
    "path": "examples/updatejnbcode.py",
    "chars": 1783,
    "preview": "#!/usr/bin/env python\n\n# Update code cells in notebooks from corresponding scripts without\n# the need to re-execute the "
  },
  {
    "path": "examples/updatejnbmd.py",
    "chars": 1114,
    "preview": "#!/usr/bin/env python\n\n# Update markdown cells in notebooks from corresponding scripts without\n# the need to re-execute "
  },
  {
    "path": "misc/README.rst",
    "chars": 381,
    "preview": "Miscellaneous\n=============\n\nThis directory is a temporary location for content for which there is no\nobviously more app"
  },
  {
    "path": "misc/conda/README.rst",
    "chars": 1631,
    "preview": "Conda Installation Scripts\n==========================\n\nThese scripts are intended to faciliate the installation of `mini"
  },
  {
    "path": "misc/conda/install_conda.sh",
    "chars": 2421,
    "preview": "#!/usr/bin/env bash\n\n# This script installs miniconda3 in the specified path\n#\n# Run with -h flag for usage information\n"
  },
  {
    "path": "misc/conda/make_conda_env.sh",
    "chars": 8437,
    "preview": "#!/usr/bin/env bash\n\n# This script installs a conda environment with all required and\n# optional scico dependencies. The"
  },
  {
    "path": "misc/gpu/README.rst",
    "chars": 317,
    "preview": "GPU Utility Scripts\n===================\n\nThese scripts are intended for debugging and managing JAX use of GPUs:\n\n- ``ava"
  },
  {
    "path": "misc/gpu/availgpu.py",
    "chars": 684,
    "preview": "#!/usr/bin/env python\n\n# Determine which GPUs available for use and recommend CUDA_VISIBLE_DEVICES\n# setting if any are "
  },
  {
    "path": "misc/gpu/envinfo.py",
    "chars": 1691,
    "preview": "#!/usr/bin/env python\n\n# Print host and environment information. Useful for determining whether\n# a Python host has avai"
  },
  {
    "path": "misc/pytest/README.rst",
    "chars": 610,
    "preview": "Specialized Pytest Usage\n========================\n\nThese scripts support specialized ``pytest`` usage:\n\n- ``pytest_cov.s"
  },
  {
    "path": "misc/pytest/pytest_cov.sh",
    "chars": 423,
    "preview": "#!/usr/bin/env bash\n\n# This script runs scico unit tests using the pytest-cov plugin for test\n# coverage analysis. It mu"
  },
  {
    "path": "misc/pytest/pytest_fast.sh",
    "chars": 568,
    "preview": "#!/usr/bin/env bash\n\n# This script runs pytest tests in parallel using the pytest-xdist plugin.\n# Some tests that do not"
  },
  {
    "path": "misc/pytest/pytest_time.sh",
    "chars": 628,
    "preview": "#!/usr/bin/env bash\n\n# This script runs each scico unit test module and lists them all in order\n# of decreasing run time"
  },
  {
    "path": "pyproject.toml",
    "chars": 822,
    "preview": "[build-system]\nrequires = [\"setuptools\"]\nbuild-backend = \"setuptools.build_meta\"\n\n\n[tool.black]\nline-length = 100\ntarget"
  },
  {
    "path": "pytest.ini",
    "chars": 454,
    "preview": "[pytest]\ntestpaths = scico/test docs\naddopts = --doctest-glob=\"*rst\"\ndoctest_optionflags = NORMALIZE_WHITESPACE NUMBER\nf"
  },
  {
    "path": "requirements.txt",
    "chars": 153,
    "preview": "typing_extensions\nnumpy>=2.0\nscipy>=1.13\nimageio>=2.17\ntifffile\nmatplotlib\njaxlib>=0.5.0,<=0.10.0\njax>=0.5.0,<=0.10.0\nfl"
  },
  {
    "path": "scico/__init__.py",
    "chars": 1288,
    "preview": "# Copyright (C) 2021-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# This file is part of the SC"
  },
  {
    "path": "scico/_core.py",
    "chars": 7950,
    "preview": "# Copyright (C) 2020-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# This file is part of the SC"
  },
  {
    "path": "scico/_version.py",
    "chars": 3157,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2020-2024 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/data/__init__.py",
    "chars": 1748,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2021-2024 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/denoiser.py",
    "chars": 10929,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2020-2024 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/diagnostics.py",
    "chars": 8979,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2020-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/examples.py",
    "chars": 20746,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2021-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/__init__.py",
    "chars": 2105,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2021-2024 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/_flax.py",
    "chars": 2840,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2021-2023 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/_models.py",
    "chars": 11668,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2021-2023 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/blocks.py",
    "chars": 8777,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2021-2024 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/examples/__init__.py",
    "chars": 601,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# This fil"
  },
  {
    "path": "scico/flax/examples/data_generation.py",
    "chars": 13157,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/examples/data_preprocessing.py",
    "chars": 19601,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/examples/examples.py",
    "chars": 24914,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/examples/typed_dict.py",
    "chars": 1174,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2023 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/inverse.py",
    "chars": 17085,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2024 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/__init__.py",
    "chars": 306,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# This fil"
  },
  {
    "path": "scico/flax/train/apply.py",
    "chars": 4795,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/checkpoints.py",
    "chars": 4000,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/clu_utils.py",
    "chars": 8207,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/diagnostics.py",
    "chars": 3397,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2023 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/input_pipeline.py",
    "chars": 4364,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/learning_rate.py",
    "chars": 2600,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# This fil"
  },
  {
    "path": "scico/flax/train/losses.py",
    "chars": 732,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2023 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/spectral.py",
    "chars": 5501,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/state.py",
    "chars": 4057,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2023 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/steps.py",
    "chars": 5609,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2023 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/trainer.py",
    "chars": 19705,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/traversals.py",
    "chars": 1844,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2024 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/flax/train/typed_dict.py",
    "chars": 3973,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/function.py",
    "chars": 9422,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2022-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/functional/__init__.py",
    "chars": 1595,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2021-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/functional/_denoiser.py",
    "chars": 4304,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2020-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/functional/_dist.py",
    "chars": 4714,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2020-2025 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/functional/_functional.py",
    "chars": 13963,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2020-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/functional/_indicator.py",
    "chars": 5580,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2020-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  },
  {
    "path": "scico/functional/_norm.py",
    "chars": 17698,
    "preview": "# -*- coding: utf-8 -*-\n# Copyright (C) 2020-2026 by SCICO Developers\n# All rights reserved. BSD 3-clause License.\n# Thi"
  }
]

// ... and 135 more files (download for full content)

About this extraction

This page contains the full source code of the lanl/scico GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 335 files (1.8 MB), approximately 529.2k tokens, and a symbol index with 1832 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!