[![CanvasAPI on PyPI](https://img.shields.io/pypi/v/canvasapi.svg)](https://pypi.python.org/pypi/canvasapi)
[![License](https://img.shields.io/pypi/l/canvasapi.svg)](https://pypi.python.org/pypi/canvasapi)
[![Python Versions](https://img.shields.io/pypi/pyversions/canvasapi.svg)](https://pypi.python.org/pypi/canvasapi)
[![Documentation Status](https://readthedocs.org/projects/canvasapi/badge/?version=stable)](http://canvasapi.readthedocs.io/en/stable/?badge=stable)
[![Build Status](https://github.com/ucfopen/canvasapi/actions/workflows/run-tests.yml/badge.svg?branch=develop)](https://github.com/ucfopen/canvasapi/actions)
[![codecov](https://codecov.io/gh/ucfopen/canvasapi/branch/develop/graph/badge.svg?token=CFNpp8f56M)](https://codecov.io/gh/ucfopen/canvasapi)
[![Join UCF Open Slack Discussions](https://badgen.net/badge/icon/ucfopen?icon=slack&label=slack&color=pink)](https://dl.ucf.edu/join-ucfopen)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)

# CanvasAPI

CanvasAPI is a Python library for accessing Instructure’s [Canvas LMS API](https://canvas.instructure.com/doc/api/index.html). The library enables developers to programmatically manage Canvas courses, users, gradebooks, and more.

## Table of Contents

- [CanvasAPI](#canvasapi)
  - [Table of Contents](#table-of-contents)
  - [Installation](#installation)
  - [Documentation](#documentation)
  - [Contributing](#contributing)
  - [Quickstart](#quickstart)
    - [Working with Canvas Objects](#working-with-canvas-objects)
      - [Course objects](#course-objects)
      - [User objects](#user-objects)
      - [Paginated Lists](#paginated-lists)
      - [Keyword arguments](#keyword-arguments)
  - [CanvasAPI Projects](#canvasapi-projects)
  - [Contact Us](#contact-us)

## Installation

You can install CanvasAPI with pip:

`pip install canvasapi`

## Documentation

Full documentation is available at [Read the Docs](http://canvasapi.readthedocs.io/).

## Contributing

Want to help us improve CanvasAPI? Check out our [Contributing Guide](.github/CONTRIBUTING.md) to learn about running CanvasAPI as a developer, picking issues to work on, submitting bug reports, contributing patches, and more.

## Quickstart

Getting started with CanvasAPI is easy.

Like most API clients, CanvasAPI exposes a single class that provides access to the rest of the API: `Canvas`.

The first thing to do is instantiate a new `Canvas` object by providing your Canvas instance’s root API URL and a valid API key:

```python
# Import the Canvas class
from canvasapi import Canvas

# Canvas API URL
API_URL = "https://example.com"
# Canvas API key
API_KEY = "p@$$w0rd"

# Initialize a new Canvas object
canvas = Canvas(API_URL, API_KEY)
```

You can now use `canvas` to begin making API calls.

### Working with Canvas Objects

CanvasAPI converts the JSON responses from the Canvas API into Python objects. These objects provide further access to the Canvas API. You can find a full breakdown of the methods these classes provide in our [class documentation](http://canvasapi.readthedocs.io/en/stable/class-reference.html). Below, you’ll find a few examples of common CanvasAPI use cases.

#### Course objects

Courses can be retrieved from the API:

```python
# Grab course 123456
>>> course = canvas.get_course(123456)

# Access the course's name
>>> course.name
'Test Course'

# Update the course's name
>>> course.update(course={'name': 'New Course Name'})
```

See our documentation on [keyword arguments](#keyword-arguments) for more information about how `course.update()` handles the `name` argument.

#### User objects

Individual users can be pulled from the API as well:

```python
# Grab user 123
>>> user = canvas.get_user(123)

# Access the user's name
>>> user.name
'Test User'

# Retrieve a list of courses the user is enrolled in
>>> courses = user.get_courses()

# Grab a different user by their SIS ID
>>> login_id_user = canvas.get_user('some_user', 'sis_login_id')
```

#### Paginated Lists

Some calls, like the `user.get_courses()` call above, will request multiple objects from Canvas’s API. CanvasAPI collects these objects in a `PaginatedList` object. `PaginatedList` generally acts like a regular Python list. You can grab an element by index, iterate over it, and take a slice of it.

**Warning**: `PaginatedList` lazily loads its elements. Unfortunately, there’s no way to determine the exact number of records Canvas will return without traversing the list fully. This means that `PaginatedList` isn’t aware of its own length and negative indexing is not currently supported.

Let’s look at how we can use the `PaginatedList` returned by our `get_courses()` call:

```python
# Retrieve a list of courses the user is enrolled in
>>> courses = user.get_courses()

>>> print(courses)
<PaginatedList of type Course>

# Access the first element in our list.
#
# You'll notice the first call takes a moment, but the next N-1
# elements (where N = the per_page argument supplied; the default is 10)
# will be instantly accessible.
>>> print(courses[0])
TST101 Test Course (1234567)

# Iterate over our course list
>>> for course in courses:
         print(course)

TST101 Test Course 1 (1234567)
TST102 Test Course 2 (1234568)
TST103 Test Course 3 (1234569)

# Take a slice of our course list
>>> courses[:2]
[TST101 Test Course 1 (1234567), TST102 Test Course 2 (1234568)]
```

#### Keyword arguments

Most of Canvas’s API endpoints accept a variety of arguments. CanvasAPI allows developers to insert keyword arguments when making calls to endpoints that accept arguments.

```python
# Get all of the active courses a user is currently enrolled in
>>> courses = user.get_courses(enrollment_state='active')
```

For a more detailed description of how CanvasAPI handles more complex keyword arguments, check out the [Keyword Argument Documentation](http://canvasapi.readthedocs.io/en/stable/keyword-args.html).

## CanvasAPI Projects

Since its initial release in June 2016, CanvasAPI has amassed over 100 [dependent repositories](https://github.com/ucfopen/canvasapi/network/dependents). Many of these include various tools used to enhance the Canvas experience for both instructors and students. Here are a few popular repositories that use CanvasAPI:

- [Canvas Grab](https://github.com/skyzh/canvas_grab)
  - Canvas Grab is the most popular project using CanvasAPI. This tool, with one click, copies all files from Canvas LMS to local directory. CanvasAPI is used in this project to connect to a course and grab its files.
- [Clanvas](https://github.com/marklalor/clanvas)
  - Clanvas is a command-line client for Canvas. It uses the already available bash commands plus some additional ones to interact with various features of Canvas from the commmand line.
- [CS221Bot](https://github.com/Person314159/cs221bot)
  - CS221Bot is a Discord bot for the CPCS 221 course at University of British Columbia. CanvasAPI is used in this project to connect to and synchronize with a course and get its data, such as announcements, new assignments, and more.

If you have a project that uses CanvasAPI that you'd like to promote, please contact us!

## Contact Us

Need help? Have an idea? Feel free to check out our [Discussions](https://github.com/ucfopen/canvasapi/discussions) board. Just want to say hi or get extended spport? Come join us on the [UCF Open Slack Channel](https://dl.ucf.edu/join-ucfopen) and join the `#canvasapi` channel!


# GSD

The **GSD** file format is the native file format for [HOOMD-blue](https://glotzerlab.engin.umich.edu/hoomd-blue/).
**GSD** files store trajectories of the **HOOMD-blue** system state in a binary file with efficient random access to
frames. **GSD** allows all particle and topology properties to vary from one frame to the next. Use the **GSD** Python
API to specify the initial condition for a **HOOMD-blue** simulation or analyze trajectory output with a script. Read a
**GSD** trajectory with a visualization tool to explore the behavior of the simulation.

## Resources

* [GSD documentation](http://gsd.readthedocs.io): Tutorials, Python API, C API, usage information, and format
  specification.
* [Installation Guide](INSTALLING.rst): Instructions for installing and compiling **GSD**.
* [HOOMD-blue](https://glotzerlab.engin.umich.edu/hoomd-blue/): Simulation engine that reads and writes **GSD** files.
* [GSD discussion board](https://github.com/glotzerlab/gsd/discussions/):
  Ask the **GSD** community for help.
* [freud](https://freud.readthedocs.io): A powerful set of tools for analyzing trajectories.
* [OVITO](https://www.ovito.org/): The Open Visualization Tool works with **GSD** files.
* [gsd-vmd plugin](https://github.com/mphoward/gsd-vmd): VMD plugin to support **GSD** files.

## HOOMD examples

Create a hoomd gsd file.
```python
>>> s = gsd.hoomd.Frame()
>>> s.particles.N = 4
>>> s.particles.types = ['A', 'B']
>>> s.particles.typeid = [0,0,1,1]
>>> s.particles.position = [[0,0,0],[1,1,1], [-1,-1,-1], [1,-1,-1]]
>>> s.configuration.box = [3, 3, 3, 0, 0, 0]
>>> traj = gsd.hoomd.open(name='test.gsd', mode='w')
>>> traj.append(s)
```

Append frames to a gsd file:
```python
>>> def create_frame(i):
...     s = gsd.hoomd.Frame();
...     s.configuration.step = i;
...     s.particles.N = 4+i;
...     s.particles.position = numpy.random.random(size=(4+i,3))
...     return s;
>>> with gsd.hoomd.open('test.gsd', 'a') as t:
...     t.extend( (create_frame(i) for i in range(10)) )
...     print(len(t))
11
```

Randomly index frames:
```python
>>> with gsd.hoomd.open('test.gsd', 'r') as t:
...     frame = t[5]
...     print(frame.configuration.step)
4
...     print(frame.particles.N)
8
...     print(frame.particles.position)
[[ 0.56993282  0.42243481  0.5502916 ]
 [ 0.36892486  0.38167036  0.27310368]
 [ 0.04739023  0.13603486  0.196539  ]
 [ 0.120232    0.91591144  0.99463677]
 [ 0.79806316  0.16991436  0.15228257]
 [ 0.13724308  0.14253527  0.02505   ]
 [ 0.39287439  0.82519054  0.01613089]
 [ 0.23150323  0.95167434  0.7715748 ]]
```

Slice frames:
```python
>>> with gsd.hoomd.open('test.gsd', 'r') as t:
...     for s in t[5:-2]:
...         print(s.configuration.step, end=' ')
4 5 6 7
```

## File layer examples

```python
with gsd.fl.open(name='file.gsd', mode='w') as f:
    f.write_chunk(name='position', data=numpy.array([[1,2,3],[4,5,6]], dtype=numpy.float32));
    f.write_chunk(name='angle', data=numpy.array([0, 1], dtype=numpy.float32));
    f.write_chunk(name='box', data=numpy.array([10, 10, 10], dtype=numpy.float32));
    f.end_frame()
```

```python
with gsd.fl.open(name='file.gsd', mode='r') as f:
    for i in range(1,f.nframes):
        position = f.read_chunk(frame=i, name='position');
        do_something(position);
```


..
    Copyright (C) 2019 CERN.
    Copyright (C) 2019 Northwestern University.

    Invenio-RDM-Records is free software; you can redistribute it and/or
    modify it under the terms of the MIT License; see LICENSE file for more
    details.

====================
 Invenio-RDM-Records
====================

.. image:: https://github.com/inveniosoftware/invenio-rdm-records/workflows/CI/badge.svg
        :target: https://github.com/inveniosoftware/invenio-rdm-records/actions?query=workflow%3ACI+branch%3Amaster

.. image:: https://img.shields.io/github/tag/inveniosoftware/invenio-rdm-records.svg
        :target: https://github.com/inveniosoftware/invenio-rdm-records/releases

.. image:: https://img.shields.io/pypi/dm/invenio-rdm-records.svg
        :target: https://pypi.python.org/pypi/invenio-rdm-records

.. image:: https://img.shields.io/github/license/inveniosoftware/invenio-rdm-records.svg
        :target: https://github.com/inveniosoftware/invenio-rdm-records/blob/master/LICENSE

DataCite-based data model for Invenio.

Further documentation is available on
https://invenio-rdm-records.readthedocs.io/

Development
===========

Install
-------

Choose a version of search and database, then run:

.. code-block:: console

    pipenv run pip install -e .[all]
    pipenv run pip install invenio-search[<opensearch[1]>]
    pipenv run pip install invenio-db[<[mysql|postgresql|]>]

Tests
-----

.. code-block:: console

    pipenv run ./run-tests.sh


========
autopep8
========

.. image:: https://img.shields.io/pypi/v/autopep8.svg
    :target: https://pypi.org/project/autopep8/
    :alt: PyPI Version

.. image:: https://github.com/hhatto/autopep8/workflows/Python%20package/badge.svg
    :target: https://github.com/hhatto/autopep8/actions
    :alt: Build status

.. image:: https://codecov.io/gh/hhatto/autopep8/branch/main/graph/badge.svg
    :target: https://codecov.io/gh/hhatto/autopep8
    :alt: Code Coverage

autopep8 automatically formats Python code to conform to the `PEP 8`_ style
guide. It uses the pycodestyle_ utility to determine what parts of the code
needs to be formatted. autopep8 is capable of fixing most of the formatting
issues_ that can be reported by pycodestyle.

.. _PEP 8: https://www.python.org/dev/peps/pep-0008/
.. _issues: https://pycodestyle.readthedocs.org/en/latest/intro.html#error-codes

.. contents::

Installation
============

From pip::

    $ pip install --upgrade autopep8

Consider using the ``--user`` option_.

.. _option: https://pip.pypa.io/en/latest/user_guide/#user-installs

Requirements
============

autopep8 requires pycodestyle_.

.. _pycodestyle: https://github.com/PyCQA/pycodestyle

Usage
=====

To modify a file in place (with aggressive level 2)::

    $ autopep8 --in-place --aggressive --aggressive <filename>

Before running autopep8.

.. code-block:: python

    import math, sys;

    def example1():
        ####This is a long comment. This should be wrapped to fit within 72 characters.
        some_tuple=(   1,2, 3,'a'  );
        some_variable={'long':'Long code lines should be wrapped within 79 characters.',
        'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'],
        'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1,
        20,300,40000,500000000,60000000000000000]}}
        return (some_tuple, some_variable)
    def example2(): return {'has_key() is deprecated':True}.has_key({'f':2}.has_key(''));
    class Example3(   object ):
        def __init__    ( self, bar ):
         #Comments should have a space after the hash.
         if bar : bar+=1;  bar=bar* bar   ; return bar
         else:
                        some_string = """
    		           Indentation in multiline strings should not be touched.
    Only actual code should be reindented.
    """
                        return (sys.path, some_string)

After running autopep8.

.. code-block:: python

    import math
    import sys

    def example1():
        # This is a long comment. This should be wrapped to fit within 72
        # characters.
        some_tuple = (1, 2, 3, 'a')
        some_variable = {
            'long': 'Long code lines should be wrapped within 79 characters.',
            'other': [
                math.pi,
                100,
                200,
                300,
                9876543210,
                'This is a long string that goes on'],
            'more': {
                'inner': 'This whole logical line should be wrapped.',
                some_tuple: [
                    1,
                    20,
                    300,
                    40000,
                    500000000,
                    60000000000000000]}}
        return (some_tuple, some_variable)

    def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True}

    class Example3(object):
        def __init__(self, bar):
            # Comments should have a space after the hash.
            if bar:
                bar += 1
                bar = bar * bar
                return bar
            else:
                some_string = """
    		           Indentation in multiline strings should not be touched.
    Only actual code should be reindented.
    """
                return (sys.path, some_string)

Options::

    usage: autopep8 [-h] [--version] [-v] [-d] [-i] [--global-config filename]
                    [--ignore-local-config] [-r] [-j n] [-p n] [-a]
                    [--experimental] [--exclude globs] [--list-fixes]
                    [--ignore errors] [--select errors] [--max-line-length n]
                    [--line-range line line] [--hang-closing] [--exit-code]
                    [files [files ...]]

    Automatically formats Python code to conform to the PEP 8 style guide.

    positional arguments:
      files                 files to format or '-' for standard in

    optional arguments:
      -h, --help            show this help message and exit
      --version             show program's version number and exit
      -v, --verbose         print verbose messages; multiple -v result in more
                            verbose messages
      -d, --diff            print the diff for the fixed source
      -i, --in-place        make changes to files in place
      --global-config filename
                            path to a global pep8 config file; if this file does
                            not exist then this is ignored (default:
                            ~/.config/pep8)
      --ignore-local-config
                            don't look for and apply local config files; if not
                            passed, defaults are updated with any config files in
                            the project's root directory
      -r, --recursive       run recursively over directories; must be used with
                            --in-place or --diff
      -j n, --jobs n        number of parallel jobs; match CPU count if value is
                            less than 1
      -p n, --pep8-passes n
                            maximum number of additional pep8 passes (default:
                            infinite)
      -a, --aggressive      enable non-whitespace changes; multiple -a result in
                            more aggressive changes
      --experimental        enable experimental fixes
      --exclude globs       exclude file/directory names that match these comma-
                            separated globs
      --list-fixes          list codes for fixes; used by --ignore and --select
      --ignore errors       do not fix these errors/warnings (default:
                            E226,E24,W50,W690)
      --select errors       fix only these errors/warnings (e.g. E4,W)
      --max-line-length n   set maximum allowed line length (default: 79)
      --line-range line line, --range line line
                            only fix errors found within this inclusive range of
                            line numbers (e.g. 1 99); line numbers are indexed at
                            1
      --hang-closing        hang-closing option passed to pycodestyle
      --exit-code           change to behavior of exit code. default behavior of
                            return value, 0 is no differences, 1 is error exit.
                            return 2 when add this option. 2 is exists
                            differences.

Features
========

autopep8 fixes the following issues_ reported by pycodestyle_::

    E101 - Reindent all lines.
    E11  - Fix indentation.
    E121 - Fix indentation to be a multiple of four.
    E122 - Add absent indentation for hanging indentation.
    E123 - Align closing bracket to match opening bracket.
    E124 - Align closing bracket to match visual indentation.
    E125 - Indent to distinguish line from next logical line.
    E126 - Fix over-indented hanging indentation.
    E127 - Fix visual indentation.
    E128 - Fix visual indentation.
    E129 - Fix visual indentation.
    E131 - Fix hanging indent for unaligned continuation line.
    E133 - Fix missing indentation for closing bracket.
    E20  - Remove extraneous whitespace.
    E211 - Remove extraneous whitespace.
    E22  - Fix extraneous whitespace around keywords.
    E224 - Remove extraneous whitespace around operator.
    E225 - Fix missing whitespace around operator.
    E226 - Fix missing whitespace around arithmetic operator.
    E227 - Fix missing whitespace around bitwise/shift operator.
    E228 - Fix missing whitespace around modulo operator.
    E231 - Add missing whitespace.
    E241 - Fix extraneous whitespace around keywords.
    E242 - Remove extraneous whitespace around operator.
    E251 - Remove whitespace around parameter '=' sign.
    E252 - Missing whitespace around parameter equals.
    E26  - Fix spacing after comment hash for inline comments.
    E265 - Fix spacing after comment hash for block comments.
    E266 - Fix too many leading '#' for block comments.
    E27  - Fix extraneous whitespace around keywords.
    E301 - Add missing blank line.
    E302 - Add missing 2 blank lines.
    E303 - Remove extra blank lines.
    E304 - Remove blank line following function decorator.
    E305 - Expected 2 blank lines after end of function or class.
    E306 - Expected 1 blank line before a nested definition.
    E401 - Put imports on separate lines.
    E402 - Fix module level import not at top of file
    E501 - Try to make lines fit within --max-line-length characters.
    E502 - Remove extraneous escape of newline.
    E701 - Put colon-separated compound statement on separate lines.
    E70  - Put semicolon-separated compound statement on separate lines.
    E711 - Fix comparison with None.
    E712 - Fix comparison with boolean.
    E713 - Use 'not in' for test for membership.
    E714 - Use 'is not' test for object identity.
    E721 - Use "isinstance()" instead of comparing types directly.
    E722 - Fix bare except.
    E731 - Use a def when use do not assign a lambda expression.
    W291 - Remove trailing whitespace.
    W292 - Add a single newline at the end of the file.
    W293 - Remove trailing whitespace on blank line.
    W391 - Remove trailing blank lines.
    W503 - Fix line break before binary operator.
    W504 - Fix line break after binary operator.
    W605 - Fix invalid escape sequence 'x'.

autopep8 also fixes some issues not found by pycodestyle_.

- Normalize files with mixed line endings.
- Put a blank line between a class docstring and its first method
  declaration. (Enabled with ``E301``.)
- Remove blank lines between a function declaration and its docstring. (Enabled
  with ``E303``.)

autopep8 avoids fixing some issues found by pycodestyle_.

- ``E112``/``E113`` for non comments are reports of bad indentation that break
  syntax rules. These should not be modified at all.
- ``E265``, which refers to spacing after comment hash, is ignored if the
  comment looks like code. autopep8 avoids modifying these since they are not
  real comments. If you really want to get rid of the pycodestyle_ warning,
  consider just removing the commented-out code. (This can be automated via
  eradicate_.)

.. _eradicate: https://github.com/myint/eradicate

More advanced usage
===================

By default autopep8 only makes whitespace changes. Thus, by default, it does
not fix ``E711`` and ``E712``. (Changing ``x == None`` to ``x is None`` may
change the meaning of the program if ``x`` has its ``__eq__`` method
overridden.) Nor does it correct deprecated code ``W6``. To enable these
more aggressive fixes, use the ``--aggressive`` option::

    $ autopep8 --aggressive <filename>

Use multiple ``--aggressive`` to increase the aggressiveness level. For
example, ``E712`` requires aggressiveness level 2 (since ``x == True`` could be
changed to either ``x`` or ``x is True``, but autopep8 chooses the former).

``--aggressive`` will also shorten lines more aggressively. It will also remove
trailing whitespace more aggressively. (Usually, we don't touch trailing
whitespace in docstrings and other multiline strings. And to do even more
aggressive changes to docstrings, use docformatter_.)

.. _docformatter: https://github.com/myint/docformatter

To enable only a subset of the fixes, use the ``--select`` option. For example,
to fix various types of indentation issues::

    $ autopep8 --select=E1,W1 <filename>

If the file being fixed is large, you may want to enable verbose progress
messages::

    $ autopep8 -v <filename>

Passing in ``--experimental`` enables the following functionality:

- Shortens code lines by taking its length into account

::

$ autopep8 --experimental <filename>

Disabling line-by-line
----------------------

It is possible to disable autopep8 untill it it turned back on again in the file, using ``autopep8: off`` and then renabling ``autopep8: on``.

.. code-block:: python

    # autopep8: off
        [
            [23, 23, 13, 43],
            [32, 34, 34, 34],
            [56, 34, 34, 11],
            [10, 10, 10, 10],
        ]
    # autopep8: on

``fmt: off`` and ``fmt: on`` are also valid.

Use as a module
===============

The simplest way of using autopep8 as a module is via the ``fix_code()``
function:

    >>> import autopep8
    >>> autopep8.fix_code('x=       123\n')
    'x = 123\n'

Or with options:

    >>> import autopep8
    >>> autopep8.fix_code('print( 123 )\n',
    ...                   options={'ignore': ['E']})
    'print( 123 )\n'

Configuration
=============

By default, if ``$HOME/.config/pycodestyle`` (``~\.pycodestyle`` in Windows
environment) exists, it will be used as global configuration file.
Alternatively, you can specify the global configuration file with the
``--global-config`` option.

Also, if ``setup.cfg``, ``tox.ini``, ``.pep8`` and ``.flake8`` files exist
in the directory where the target file exists, it will be used as the
configuration file.

``pep8``, ``pycodestyle``, and ``flake8`` can be used as a section.

configuration file example::

    [pycodestyle]
    max_line_length = 120
    ignore = E501

pyproject.toml
--------------

autopep8 can also use ``pyproject.toml``.
The section must be ``[tool.autopep8]``, and ``pyproject.toml`` takes precedence
over any other configuration files.

configuration file example::

    [tool.autopep8]
    max_line_length = 120
    ignore = "E501,W6"  # or ["E501", "W6"]
    in-place = true
    recursive = true
    aggressive = 3

Usage with pre-commit
=====================

autopep8 can be used as a hook for pre-commit_.

To add autopep8 as a plugin, add this repo definition to your configuration:

.. code-block:: yaml

    repos:
    -   repo: https://github.com/hhatto/autopep8
        rev: ...  # select the tag or revision you want, or run `pre-commit autoupdate`
        hooks:
        -   id: autopep8

.. _`pre-commit`: https://pre-commit.com

Testing
=======

Test cases are in ``test/test_autopep8.py``. They can be run directly via
``python test/test_autopep8.py`` or via tox_. The latter is useful for
testing against multiple Python interpreters. (We currently test against
CPython versions 3.8, 3.9, 3.10, 3.11 and 3.12. We also test against PyPy.)

.. _`tox`: https://pypi.org/project/tox/

Broad spectrum testing is available via ``test/acid.py``. This script runs
autopep8 against Python code and checks for correctness and completeness of the
code fixes. It can check that the bytecode remains identical.
``test/acid_pypi.py`` makes use of ``acid.py`` to test against the latest
released packages on PyPI.

Troubleshooting
===============

``pkg_resources.DistributionNotFound``
--------------------------------------

If you are using an ancient version of ``setuptools``, you might encounter
``pkg_resources.DistributionNotFound`` when trying to run ``autopep8``. Try
upgrading ``setuptools`` to workaround this ``setuptools`` problem::

    $ pip install --upgrade setuptools

Use ``sudo`` if you are installing to the system.

Links
=====

* PyPI_
* GitHub_
* Codecov_

.. _PyPI: https://pypi.org/project/autopep8/
.. _GitHub: https://github.com/hhatto/autopep8
.. _`Codecov`: https://app.codecov.io/gh/hhatto/autopep8


TuLiP
=====
This is the source repository for TuLiP, the temporal logic planning toolbox.
The project website is http://tulip-control.org

Installation
------------

In most cases, it suffices to::

  pip install .

TuLiP can be installed also `from PyPI <https://pypi.python.org/pypi/tulip>`_::

  pip install tulip

This will install the latest release, together with required dependencies.
To find out what dependencies (including optional ones) are installed, call::

  tulip.interfaces.print_env()

For detailed instructions, including notes about dependencies and troubleshooting,
consult https://tulip-control.sourceforge.io/doc/install.html
The next section describes how to build documentation.
A test suite is provided under ``tests/``.  Consult the section "Testing" below.

Pip can install the latest *development* snapshot too::

  pip install https://github.com/tulip-control/tulip-control/archive/master.zip

Code under development can be unstable so trying `pip install tulip` first
is recommended.

Documentation
-------------

There are two main sources of documentation outside the code.  The "user"
documentation is under ``doc/`` and is built with `Sphinx
<https://www.sphinx-doc.org/>`_, so the usual steps apply, ::

  make html

API documentation is generated using `Epydoc <http://epydoc.sourceforge.net/>`_
and can also be built from the ``doc`` directory, now by ::

  make api

Built copies for the most recent release of TuLiP are available online at:

* https://tulip-control.sourceforge.io/doc/
* https://tulip-control.sourceforge.io/api-doc/

Command summaries are provided by ``make help``.  Besides the above sources, you
may also read API documentation using the standard pydoc tool.  E.g., ::

  pydoc tulip

Testing
-------

Tests are performed using `pytest <https://pytest.org>`_.  From the
root of the source tree (i.e., where ``setup.py`` is located), ::

  ./run_tests.py

to perform basic tests.  To try all available tests, ``./run_tests.py full``.
For alternatives and a summary of usage, ``./run_tests.py -h``

Contact and support
-------------------

* Ask for help on the `tulip-control-users mailing list <https://sourceforge.net/p/tulip-control/mailman/tulip-control-users>`_
* For release announcements, join the `tulip-control-announce mailing list <https://sourceforge.net/p/tulip-control/mailman/tulip-control-announce>`_
* Bug reports and feature requests should be made at https://github.com/tulip-control/tulip-control/issues
  Please check for prior discussion and reports before opening a new issue.

License
-------

This is free software released under the terms of `the BSD 3-Clause License
<https://opensource.org/licenses/BSD-3-Clause>`_.  There is no warranty; not even
for merchantability or fitness for a particular purpose.  Consult LICENSE for
copying conditions.

When code is modified or re-distributed, the LICENSE file should accompany the code or any subset of it, however small.
As an alternative, the LICENSE text can be copied within files, if so desired.

If this software is useful to you, we kindly ask that you cite us::

  I. Filippidis, S. Dathathri, S. C. Livingston, N. Ozay and R. M. Murray,
  "Control design for hybrid systems with TuLiP: The Temporal Logic Planning
  toolbox," 2016 IEEE Conference on Control Applications (CCA), Buenos Aires,
  Argentina, 2016, pp. 1030-1041, doi: 10.1109/CCA.2016.7587949.


# Computational Uncertainty Quantification for Inverse Problems in python

[![pytest](https://github.com/CUQI-DTU/CUQIpy/actions/workflows/tests.yml/badge.svg)](https://github.com/CUQI-DTU/CUQIpy/actions/workflows/tests.yml)
[![docs](https://github.com/CUQI-DTU/CUQIpy/actions/workflows/docs.yml/badge.svg)](https://cuqi-dtu.github.io/CUQIpy/)
[![PyPI](https://github.com/CUQI-DTU/CUQIpy/actions/workflows/publish_pypi.yml/badge.svg)](https://pypi.org/project/CUQIpy/#history)

**CUQIpy** stands for Computational Uncertainty Quantification for Inverse Problems in python. It's a robust Python package designed for modeling and solving inverse problems using Bayesian inference. Here's what it brings to the table:

- A straightforward high-level interface for UQ analysis.
- Complete control over the models and methods.
- An array of predefined distributions, samplers, models, and test problems.
- Easy extendability for your unique needs.

CUQIpy is part of the [CUQI project](https://www.compute.dtu.dk/english/cuqi) supported by the [Villum Foundation.](https://veluxfoundations.dk/en/forskning/teknisk-og-naturvidenskabelig-forskning)

## 📚 Resources

- **Documentation:** [CUQIpy website](https://cuqi-dtu.github.io/CUQIpy/)

- **Papers:** CUQIpy on ArXiv - [Part I](https://arxiv.org/abs/2305.16949) & [Part II](https://arxiv.org/abs/2305.16951)

- **Training:** [Demo & training notebooks](https://github.com/CUQI-DTU/CUQIpy-demos)

## 🚀 Quickstart
Install CUQIpy using pip:
```{r, engine='bash', count_lines}
pip install cuqipy
```
For more detailed instructions, see the [Getting Started](https://cuqi-dtu.github.io/CUQIpy/user/getting_started.html) guide.

## 🧪 Quick Example - UQ in a few lines of code
Experience the simplicity and power of CUQIpy with this Image deconvolution example. Getting started with UQ takes just a few lines of code:
```python
# Imports
import matplotlib.pyplot as plt
from cuqi.testproblem import Deconvolution2D
from cuqi.distribution import Gaussian, LMRF, Gamma
from cuqi.problem import BayesianProblem

# Step 1: Set up forward model and data, y = Ax
A, y_data, info = Deconvolution2D(dim=256, phantom="cookie").get_components()

# Step 2: Define distributions for parameters
d = Gamma(1, 1e-4)
s = Gamma(1, 1e-4)
x = LMRF(0, lambda d: 1/d, geometry=A.domain_geometry)
y = Gaussian(A@x, lambda s: 1/s)

# Step 3: Combine into Bayesian Problem and sample posterior
BP = BayesianProblem(y, x, d, s)
BP.set_data(y=y_data)
samples = BP.sample_posterior(200)

# Step 4: Analyze results
info.exactSolution.plot(); plt.title("Sharp image (exact solution)")
y_data.plot(); plt.title("Blurred and noisy image (data)")
samples["x"].plot_mean(); plt.title("Estimated image (posterior mean)")
samples["x"].plot_std(); plt.title("Uncertainty (posterior standard deviation)")
samples["s"].plot_trace(); plt.suptitle("Noise level (posterior trace)")
samples["d"].plot_trace(); plt.suptitle("Regularization parameter (posterior trace)")
```

## 🔌 Plugins
CUQIpy can be extended with additional functionality by installing optional plugins. We currently offer the following plugins:

- [CUQIpy-CIL](https://github.com/CUQI-DTU/CUQIpy-CIL) A plugin for the Core Imaging Library [(CIL)](https://ccpi.ac.uk/cil/) providing access to forward models for X-ray computed tomography.

- [CUQIpy-FEniCS](https://github.com/CUQI-DTU/CUQIpy-FEniCS): A plugin providing access to the finite element modelling tool [FEniCS](https://fenicsproject.org), which is used for solving PDE-based inverse problems.

- [CUQIpy-PyTorch](https://github.com/CUQI-DTU/CUQIpy-PyTorch): A plugin providing access to the automatic differentiation framework of [PyTorch](https://pytorch.org) within CUQIpy. It allows gradient-based sampling methods without manually providing derivative information of distributions and forward models.

## 💻 Maintainers
- [Nicolai André Brogaard Riis](https://github.com/nabriis)

- [Amal Mohammed A Alghamdi](https://github.com/amal-ghamdi)

- [Chao Zhang](https://github.com/chaozg)

- [Jakob Sauer Jørgensen](https://github.com/jakobsj)

## 🌟 Contributors
A big shoutout to our passionate team! Discover the talented individuals behind CUQIpy
[here](https://github.com/CUQI-DTU/CUQIpy/graphs/contributors).

## 🤝 Contributing
We welcome contributions to CUQIpy. Please see our [contributing guidelines](https://cuqi-dtu.github.io/CUQIpy/dev/index.html) for more information.


Brightway2 input and output
===========================

.. image:: https://img.shields.io/pypi/v/bw2io.svg
   :target: https://pypi.org/project/bw2io/
   :alt: bw2io pypi version

.. image:: https://img.shields.io/conda/vn/conda-forge/bw2io.svg
   :target: https://anaconda.org/conda-forge/bw2io
   :alt: bw2io conda-forge version

.. image:: https://ci.appveyor.com/api/projects/status/7dox9te430eb2f8h?svg=true
   :target: https://ci.appveyor.com/project/cmutel/brightway2-io
   :alt: bw2io appveyor build status

.. image:: https://coveralls.io/repos/bitbucket/cmutel/brightway2-io/badge.svg?branch=master
    :target: https://coveralls.io/bitbucket/cmutel/brightway2-io?branch=default
    :alt: Test coverage report

This package provides tools for the import, export, and management of inventory databases and impact assessment methods. It is part of the `Brightway LCA framework <https://brightway.dev/>`_. `Online documentation <https://2.docs.brightway.dev/>`_ is available, and the source code is hosted on `Github <https://github.com/brightway-lca/brightway2-io>`_.

Bw2io approach
---------------

brightway2-io is an ETL library. First, data is *extracted* into a common format. Next, a series of *strategies* is employed to uniquely identify each dataset and link datasets internally and to the biosphere. Following internal linking, linking to other background datasets can be performed. Finally, database data is written to disk.

This approach offers a number of benefits that help mitigate some of the serious problems in existing inventory data formats: the number of unlinked exchanges can be easily seen, linking strategies can be iteratively applied, and intermediate results can be saved.

Here is a typical usage. Note that we also have shortcuts for popular LCA databases such as ecoinvent:

.. code-block:: ipython

   In [1]: import bw2io as bi

   In [2]: import brightway2 as bw2

   In [3]: bi.__version__
   Out[3]: (0, 8, 7)

   In [4]: bw2.__version__
   Out[4]: (2, 4, 1)

   In [5]: importer = bi.SingleOutputEcospold2Importer('path/to/ecoinvent/datasets/', 'ei_38_cutoff')
   Extracting XML data from 19565 datasets
   Extracted 19565 datasets in 19.21 seconds

   In [6]: importer.apply_strategies()
   Applying strategy: normalize_units
   Applying strategy: update_ecoinvent_locations
   Applying strategy: remove_zero_amount_coproducts
   Applying strategy: remove_zero_amount_inputs_with_no_activity
   Applying strategy: remove_unnamed_parameters
   Applying strategy: es2_assign_only_product_with_amount_as_reference_product
   Applying strategy: assign_single_product_as_activity
   Applying strategy: create_composite_code
   Applying strategy: drop_unspecified_subcategories
   Applying strategy: fix_ecoinvent_flows_pre35
   Applying strategy: drop_temporary_outdated_biosphere_flows
   Applying strategy: link_biosphere_by_flow_uuid
   Applying strategy: link_internal_technosphere_by_composite_code
   Applying strategy: delete_exchanges_missing_activity
   Applying strategy: delete_ghost_exchanges
   Applying strategy: remove_uncertainty_from_negative_loss_exchanges
   Applying strategy: fix_unreasonably_high_lognormal_uncertainties
   Applying strategy: set_lognormal_loc_value
   Applying strategy: convert_activity_parameters_to_list
   Applying strategy: add_cpc_classification_from_single_reference_product
   Applying strategy: delete_none_synonyms
   Applied 21 strategies in 3.62 seconds

   In [7]: importer.statistics()
   19565 datasets
   629959 exchanges
   0 unlinked exchanges

   Out[7]: (19565, 629959, 0)

   In [8]: if importer.statistics()[2] == 0:
   ...:     importer.write_database()
   ...: else:
   ...:     print("There are unlinked exchanges.")
   ...:     importer.write_excel()
   ...:
   19565 datasets
   629959 exchanges
   0 unlinked exchanges

   Writing activities to SQLite3 database:
   0% [##############################] 100% | ETA: 00:00:00
   Total time elapsed: 00:02:29
   Title: Writing activities to SQLite3 database:
   Started: 11/07/2022 11:55:57
   Finished: 11/07/2022 11:58:26
   Total time elapsed: 00:02:29
   CPU %: 32.90
   Memory %: 11.17
   Created database: ei_38_cutoff

Note that brightway2-io can't magically make problems in databases go away.


# City Scrapers

[![CI build status](https://github.com/City-Bureau/city-scrapers/workflows/CI/badge.svg)](https://github.com/City-Bureau/city-scrapers/actions?query=workflow%3ACI)
[![Cron build status](https://github.com/City-Bureau/city-scrapers/workflows/Cron/badge.svg)](https://github.com/City-Bureau/city-scrapers/actions?query=workflow%3ACron)

## Who are the City Bureau Documenters, and why do they want to scrape websites?

Public meetings are important spaces for democracy where any resident can participate and hold public figures accountable. [City Bureau's Documenters program](https://www.documenters.org/) pays community members an hourly wage to inform and engage their communities by attending and documenting public meetings.

How does the Documenters program know when meetings are happening? It isn’t easy! These events are spread across dozens of websites, rarely in useful data formats.

That’s why City Bureau is working together with a team of civic coders to develop and coordinate the City Scrapers, a community open source project to scrape and store these meetings in a central database.

## What are the City Scrapers?

The City Scrapers collect information about public meetings. Every day, the City Scrapers go out and fetch information about new meetings from the Chicago city council's website, the local school council's website, the Chicago police department's website, and many more. This happens automatically so that a person doesn't have to do it. The scrapers store all of the meeting information in a database for journalists at City Bureau to report on them.

Community members are also welcome to use this code to set up their own databases.

## What can I learn from working on the City Scrapers?

A lot about the City of Chicago! What is City Council talking about this week? What are the local school councils, and what community power do they have? What neighborhoods is the police department doing outreach in? Who governs our water?

From building a scraper, you'll gain experience with:

- how the web works (HTTP requests and responses, reading HTML)
- writing functions and tests in Python
- version control and collaborative coding (git and Github)
- a basic data file format (JSON), working with a schema and data validation
- problem-solving, finding patterns, designing robust code

## How can I set up City Scrapers for my area?

This repo is focused on Chicago, but you can set up City Scrapers for your area by following the instructions in the [City-Bureau/city-scrapers-template](https://github.com/city-bureau/city-scrapers-template) repo.

## Community Mission

The City Bureau Labs community welcomes contributions from everyone. We prioritize learning and leadership opportunities for under-represented individuals in tech and journalism.

We hope that working with us will fill experience gaps (like using git/GitHub, working with data, or having your ideas taken seriously), so that more under-represented people will become decision-makers in both our community and Chicago’s tech and media scenes at large.

## Ready to code with us?

1. [Fill out this form](https://airtable.com/shrRv027NLgToRFd6) to join our Slack channel and meet the community.
2. Read about [how we collaborate](https://github.com/City-Bureau/city-scrapers/blob/main/CONTRIBUTING.md) and review our [Code of Conduct](https://github.com/City-Bureau/city-scrapers/blob/main/CODE_OF_CONDUCT.md).
3. Check out our [documentation](https://cityscrapers.org/docs/development/), and get started with [Installation](https://cityscrapers.org/docs/development/#installation) and [Contributing a spider](https://cityscrapers.org/docs/development/#contribute).

We ask all new contributors to start by writing a spider and its documentation or fixing a bug in an existing one in order to gain familiarity with our code and culture. Reach out on Slack for support if you need it.

## Don't want to code?

[Join our Slack channel](https://airtable.com/shrRv027NLgToRFd6) (chatroom) to discuss ideas and meet the community!

A. We have ongoing conversations about what sort of data we should collect and how it should be collected. Help us make these decisions by commenting on [issues with a non-coding label](https://github.com/City-Bureau/city-scrapers/issues?q=is%3Aissue+is%3Aopen+label%3Anon-coding).

B. Research sources for public meetings. Answer questions like: Are we scraping events from the right websites? Are there local agencies that we're missing? Should events be updated manually or by a scraper? [Triage events sources on these issues](https://github.com/City-Bureau/city-scrapers/issues?q=is%3Aissue+is%3Aopen+label%3A%22non-coding%3A+triage+events+source%22).

## Support this work

This project is organized and maintained by [City Bureau](http://www.citybureau.org/).

- [Donate](https://www.citybureau.org/support)
- [Subscribe](https://citybureau.com/newsletter/)
- [Twitter @city_bureau](https://twitter.com/city_bureau/)
- [Facebook](https://www.facebook.com/CityBureau/)


# BayesFlow

[![Actions Status](https://github.com/stefanradev93/bayesflow/workflows/Tests/badge.svg)](https://github.com/stefanradev93/bayesflow/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-red.svg)](https://opensource.org/licenses/MIT)
[![DOI](https://joss.theoj.org/papers/10.21105/joss.05702/status.svg)](https://doi.org/10.21105/joss.05702)
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/esta/issues)

Welcome to our BayesFlow library for efficient simulation-based Bayesian workflows! Our library enables users to create specialized neural networks for *amortized Bayesian inference*, which repay users with rapid statistical inference after a potentially longer simulation-based training phase.

For starters, check out some of our walk-through notebooks:

1. [Quickstart amortized posterior estimation](examples/Intro_Amortized_Posterior_Estimation.ipynb)
2. [Tackling strange bimodal distributions](examples/TwoMoons_Bimodal_Posterior.ipynb)
3. [Detecting model misspecification in posterior inference](examples/Model_Misspecification.ipynb)
4. [Principled Bayesian workflow for cognitive models](examples/LCA_Model_Posterior_Estimation.ipynb)
5. [Posterior estimation for ODEs](examples/Linear_ODE_system.ipynb)
6. [Posterior estimation for SIR-like models](examples/Covid19_Initial_Posterior_Estimation.ipynb)
7. [Model comparison for cognitive models](examples/Model_Comparison_MPT.ipynb)
8. [Hierarchical model comparison for cognitive models](examples/Hierarchical_Model_Comparison_MPT.ipynb)

## Documentation \& Help

The project documentation is available at <https://bayesflow.org>. Please use the [BayesFlow Forums](https://discuss.bayesflow.org/) for any BayesFlow-related questions and discussions, and [GitHub Issues](https://github.com/stefanradev93/BayesFlow/issues) for bug reports and feature requests.

## Installation

See [INSTALL.rst](INSTALL.rst) for installation instructions.

## Conceptual Overview

A cornerstone idea of amortized Bayesian inference is to employ generative
neural networks for parameter estimation, model comparison, and model validation
when working with intractable simulators whose behavior as a whole is too
complex to be described analytically. The figure below presents a higher-level
overview of neurally bootstrapped Bayesian inference.

## Getting Started: Parameter Estimation

The core functionality of BayesFlow is amortized Bayesian posterior estimation, as described in our paper:

Radev, S. T., Mertens, U. K., Voss, A., Ardizzone, L., & Köthe, U. (2020).
BayesFlow: Learning complex stochastic models with invertible neural networks.
IEEE Transactions on Neural Networks and Learning Systems, available
for free at: https://arxiv.org/abs/2003.06281.

However, since then, we have substantially extended the BayesFlow library such that
it is now much more general and cleaner than what we describe in the above paper.

### Minimal Example

```python
import numpy as np
import bayesflow as bf
```

To introduce you to the basic workflow of the library, let's consider
a simple 2D Gaussian model, from which we want to obtain
posterior inference.  We assume a Gaussian simulator (likelihood)
and a Gaussian prior for the means of the two components,
which are our only model parameters in this example:

```python
def simulator(theta, n_obs=50, scale=1.0):
    return np.random.default_rng().normal(loc=theta, scale=scale, size=(n_obs, theta.shape[0]))

def prior(D=2, mu=0., sigma=1.0):
    return np.random.default_rng().normal(loc=mu, scale=sigma, size=D)
```

Then, we connect the `prior` with the `simulator` using a `GenerativeModel` wrapper:

```python
generative_model = bf.simulation.GenerativeModel(prior, simulator, simulator_is_batched=False)
```

Next, we create our BayesFlow setup consisting of a summary and an inference network:

```python
summary_net = bf.networks.SetTransformer(input_dim=2)
inference_net = bf.networks.InvertibleNetwork(num_params=2)
amortized_posterior = bf.amortizers.AmortizedPosterior(inference_net, summary_net)
```

Finally, we connect the networks with the generative model via a `Trainer` instance:

```python
trainer = bf.trainers.Trainer(amortizer=amortized_posterior, generative_model=generative_model)
```

We are now ready to train an amortized posterior approximator. For instance,
to run online training, we simply call:

```python
losses = trainer.train_online(epochs=10, iterations_per_epoch=1000, batch_size=32)
```

Prior to inference, we can use simulation-based calibration (SBC,
https://arxiv.org/abs/1804.06788) to check the computational faithfulness of
the model-amortizer combination on unseen simulations:

```python
# Generate 500 new simulated data sets
new_sims = trainer.configurator(generative_model(500))

# Obtain 100 posterior draws per data set instantly
posterior_draws = amortized_posterior.sample(new_sims, n_samples=100)

# Diagnose calibration
fig = bf.diagnostics.plot_sbc_histograms(posterior_draws, new_sims['parameters'])
```

The histograms are roughly uniform and lie within the expected range for
well-calibrated inference algorithms as indicated by the shaded gray areas.
Accordingly, our neural approximator seems to have converged to the intended target.

As you can see, amortized inference on new (real or simulated) data is easy and fast.
We can obtain further 5000 posterior draws per simulated data set and quickly inspect
how well the model can recover its parameters across the entire *prior predictive distribution*.

```python
posterior_draws = amortized_posterior.sample(new_sims, n_samples=5000)
fig = bf.diagnostics.plot_recovery(posterior_draws, new_sims['parameters'])
```

For any individual data set, we can also compare the parameters' posteriors with
their corresponding priors:

```python
fig = bf.diagnostics.plot_posterior_2d(posterior_draws[0], prior=generative_model.prior)
```

We see clearly how the posterior shrinks relative to the prior for both
model parameters as a result of conditioning on the data.

### References and Further Reading

- Radev, S. T., Mertens, U. K., Voss, A., Ardizzone, L., & Köthe, U. (2020).
BayesFlow: Learning complex stochastic models with invertible neural networks.
IEEE Transactions on Neural Networks and Learning Systems, 33(4), 1452-1466.

- Radev, S. T., Graw, F., Chen, S., Mutters, N. T., Eichel, V. M., Bärnighausen, T., & Köthe, U. (2021).
OutbreakFlow: Model-based Bayesian inference of disease outbreak dynamics with invertible neural networks and its application to the COVID-19 pandemics in Germany. PLoS Computational Biology, 17(10), e1009472.

- Bieringer, S., Butter, A., Heimel, T., Höche, S., Köthe, U., Plehn, T., & Radev, S. T. (2021).
Measuring QCD splittings with invertible networks. SciPost Physics, 10(6), 126.

- von Krause, M., Radev, S. T., & Voss, A. (2022).
Mental speed is high until age 60 as revealed by analysis of over a million participants.
Nature Human Behaviour, 6(5), 700-708.

## Model Misspecification

What if we are dealing with misspecified models? That is, how faithful is our
amortized inference if the generative model is a poor representation of reality?
A modified loss function optimizes the learned summary statistics towards a unit
Gaussian and reliably detects model misspecification during inference time.

In order to use this method, you should only provide the `summary_loss_fun` argument
to the `AmortizedPosterior` instance:

```python
amortized_posterior = bf.amortizers.AmortizedPosterior(inference_net, summary_net, summary_loss_fun='MMD')
```

The amortizer knows how to combine its losses and you can inspect the summary space for outliers during inference.

### References and Further Reading

- Schmitt, M., Bürkner P. C., Köthe U., & Radev S. T. (2022). Detecting Model
Misspecification in Amortized Bayesian Inference with Neural Networks. ArXiv
preprint, available for free at: https://arxiv.org/abs/2112.08866

## Model Comparison

BayesFlow can not only be used for parameter estimation, but also to perform approximate Bayesian model comparison via posterior model probabilities or Bayes factors.
Let's extend the minimal example from before with a second model $M_2$ that we want to compare with our original model $M_1$:

```python
def simulator(theta, n_obs=50, scale=1.0):
    return np.random.default_rng().normal(loc=theta, scale=scale, size=(n_obs, theta.shape[0]))

def prior_m1(D=2, mu=0., sigma=1.0):
    return np.random.default_rng().normal(loc=mu, scale=sigma, size=D)

def prior_m2(D=2, mu=2., sigma=1.0):
    return np.random.default_rng().normal(loc=mu, scale=sigma, size=D)
```

For the purpose of this illustration, the two toy models only differ with respect to their prior specification ($M_1: \mu = 0, M_2: \mu = 2$). We create both models as before and use a `MultiGenerativeModel` wrapper to combine them in a `meta_model`:

```python
model_m1 = bf.simulation.GenerativeModel(prior_m1, simulator, simulator_is_batched=False)
model_m2 = bf.simulation.GenerativeModel(prior_m2, simulator, simulator_is_batched=False)
meta_model = bf.simulation.MultiGenerativeModel([model_m1, model_m2])
```

Next, we construct our neural network with a `PMPNetwork` for approximating posterior model probabilities:

```python
summary_net = bf.networks.SetTransformer(input_dim=2)
probability_net = bf.networks.PMPNetwork(num_models=2)
amortized_bmc = bf.amortizers.AmortizedModelComparison(probability_net, summary_net)
```

We combine all previous steps with a `Trainer` instance and train the neural approximator:

```python
trainer = bf.trainers.Trainer(amortizer=amortized_bmc, generative_model=meta_model)
losses = trainer.train_online(epochs=3, iterations_per_epoch=100, batch_size=32)
```

Let's simulate data sets from our models to check our networks' performance:

```python
sims = trainer.configurator(meta_model(5000))
```

When feeding the data to our trained network, we almost immediately obtain posterior model probabilities for each of the 5000 data sets:

```python
model_probs = amortized_bmc.posterior_probs(sims)
```

How good are these predicted probabilities in the closed world? We can have a look at the calibration:

```python
cal_curves = bf.diagnostics.plot_calibration_curves(sims["model_indices"], model_probs)
```

Our approximator shows excellent calibration, with the calibration curve being closely aligned to the diagonal, an expected calibration error (ECE) near 0 and most predicted probabilities being certain of the model underlying a data set. We can further assess patterns of misclassification with a confusion matrix:

```python
conf_matrix = bf.diagnostics.plot_confusion_matrix(sims["model_indices"], model_probs)
```

For the vast majority of simulated data sets, the "true" data-generating model is correctly identified. With these diagnostic results backing us up, we can proceed and apply our trained network to empirical data.

BayesFlow is also able to conduct model comparison for hierarchical models. See this [tutorial notebook](examples/Hierarchical_Model_Comparison_MPT.ipynb) for an introduction to the associated workflow.

### References and Further Reading

- Radev S. T., D’Alessandro M., Mertens U. K., Voss A., Köthe U., & Bürkner P.
C. (2021). Amortized Bayesian Model Comparison with Evidental Deep Learning.
IEEE Transactions on Neural Networks and Learning Systems.
doi:10.1109/TNNLS.2021.3124052 available for free at: https://arxiv.org/abs/2004.10629

- Schmitt, M., Radev, S. T., & Bürkner, P. C. (2022). Meta-Uncertainty in
Bayesian Model Comparison. In International Conference on Artificial Intelligence
and Statistics, 11-29, PMLR, available for free at: https://arxiv.org/abs/2210.07278

- Elsemüller, L., Schnuerch, M., Bürkner, P. C., & Radev, S. T. (2023). A Deep
Learning Method for Comparing Bayesian Hierarchical Models. ArXiv preprint,
available for free at: https://arxiv.org/abs/2301.11873

## Likelihood Emulation

In order to learn the exchangeable (i.e., permutation invariant) likelihood from the minimal example instead of the posterior, you may use the `AmortizedLikelihood` wrapper:

```python
likelihood_net = bf.networks.InvertibleNetwork(num_params=2)
amortized_likelihood = bf.amortizers.AmortizedLikelihood(likelihood_net)
```

This wrapper can interact with a `Trainer` instance in the same way as the `AmortizedPosterior`. Finally, you can also learn the likelihood and the posterior *simultaneously* by using the `AmortizedPosteriorLikelihood` wrapper and choosing your preferred training scheme:

```python
joint_amortizer = bf.amortizers.AmortizedPosteriorLikelihood(amortized_posterior, amortized_likelihood)
```

Learning both densities enables us to approximate marginal likelihoods or perform approximate leave-one-out cross-validation (LOO-CV) for prior or posterior predictive model comparison, respectively.

### References and Further Reading

Radev, S. T., Schmitt, M., Pratz, V., Picchini, U., Köthe, U., & Bürkner, P.-C. (2023).
JANA: Jointly amortized neural approximation of complex Bayesian models.
*Proceedings of the Thirty-Ninth Conference on Uncertainty in Artificial Intelligence, 216*, 1695-1706.
([arXiv](https://arxiv.org/abs/2302.09125))([PMLR](https://proceedings.mlr.press/v216/radev23a.html))

## Support

This project is currently managed by researchers from Rensselaer Polytechnic Institute, TU Dortmund University, and Heidelberg University. It is partially funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation, Project 528702768). The project is further supported by Germany's Excellence Strategy -- EXC-2075 - 390740016 (Stuttgart Cluster of Excellence SimTech) and EXC-2181 - 390900948 (Heidelberg Cluster of Excellence STRUCTURES), as well as the Informatics for Life initiative funded by the Klaus Tschira Foundation.

## Citing BayesFlow

You can cite BayesFlow along the lines of:

- We approximated the posterior with neural posterior estimation and learned summary statistics (NPE; Radev et al., 2020), as implemented in the BayesFlow software for amortized Bayesian workflows (Radev et al., 2023a).
- We approximated the likelihood with neural likelihood estimation (NLE; Papamakarios et al., 2019) without hand-crafted summary statistics, as implemented in the BayesFlow software for amortized Bayesian workflows (Radev et al., 2023b).
- We performed simultaneous posterior and likelihood estimation with jointly amortized neural approximation (JANA; Radev et al., 2023a), as implemented in the BayesFlow software for amortized Bayesian workflows (Radev et al., 2023b).

1. Radev, S. T., Schmitt, M., Schumacher, L., Elsemüller, L., Pratz, V., Schälte, Y., Köthe, U., & Bürkner, P.-C. (2023a). BayesFlow: Amortized Bayesian workflows with neural networks. *The Journal of Open Source Software, 8(89)*, 5702.([arXiv](https://arxiv.org/abs/2306.16015))([JOSS](https://joss.theoj.org/papers/10.21105/joss.05702))
2. Radev, S. T., Mertens, U. K., Voss, A., Ardizzone, L., Köthe, U. (2020). BayesFlow: Learning complex stochastic models with invertible neural networks. *IEEE Transactions on Neural Networks and Learning Systems, 33(4)*, 1452-1466. ([arXiv](https://arxiv.org/abs/2003.06281))([IEEE TNNLS](https://ieeexplore.ieee.org/document/9298920))
3. Radev, S. T., Schmitt, M., Pratz, V., Picchini, U., Köthe, U., & Bürkner, P.-C. (2023b). JANA: Jointly amortized neural approximation of complex Bayesian models. *Proceedings of the Thirty-Ninth Conference on Uncertainty in Artificial Intelligence, 216*, 1695-1706. ([arXiv](https://arxiv.org/abs/2302.09125))([PMLR](https://proceedings.mlr.press/v216/radev23a.html))

**BibTeX:**

```
@article{bayesflow_2023_software,
  title = {{BayesFlow}: Amortized {B}ayesian workflows with neural networks},
  author = {Radev, Stefan T. and Schmitt, Marvin and Schumacher, Lukas and Elsemüller, Lasse and Pratz, Valentin and Schälte, Yannik and Köthe, Ullrich and Bürkner, Paul-Christian},
  journal = {Journal of Open Source Software},
  volume = {8},
  number = {89},
  pages = {5702},
  year = {2023}
}

@article{bayesflow_2020_original,
  title = {{BayesFlow}: Learning complex stochastic models with invertible neural networks},
  author = {Radev, Stefan T. and Mertens, Ulf K. and Voss, Andreas and Ardizzone, Lynton and K{\"o}the, Ullrich},
  journal = {IEEE transactions on neural networks and learning systems},
  volume = {33},
  number = {4},
  pages = {1452--1466},
  year = {2020}
}

@inproceedings{bayesflow_2023_jana,
  title = {{JANA}: Jointly amortized neural approximation of complex {B}ayesian models},
  author = {Radev, Stefan T. and Schmitt, Marvin and Pratz, Valentin and Picchini, Umberto and K\"othe, Ullrich and B\"urkner, Paul-Christian},
  booktitle = {Proceedings of the Thirty-Ninth Conference on Uncertainty in Artificial Intelligence},
  pages = {1695--1706},
  year = {2023},
  volume = {216},
  series = {Proceedings of Machine Learning Research},
  publisher = {PMLR}
}
```


# Bifrost

| **`CPU/GPU Build`** | **`Coverage`** |
|-----------------|----------------|
|[![GHA](https://github.com/ledatelescope/bifrost/actions/workflows/main.yml/badge.svg)](https://github.com/ledatelescope/bifrost/actions/workflows/main.yml) | [![Coverage Status](https://codecov.io/gh/ledatelescope/bifrost/branch/master/graph/badge.svg?token=f3ge1zWe5P)](https://codecov.io/gh/ledatelescope/bifrost) |

A stream processing framework for high-throughput applications.

### [![Paper](https://img.shields.io/badge/arXiv-1708.00720-blue.svg)](https://arxiv.org/abs/1708.00720)

### [Bifrost Documentation](http://ledatelescope.github.io/bifrost/)

See also the [Bifrost tutorial notebooks](tutorial/), which can be run
on Google Colab or any Jupyter environment where Bifrost is installed
(and a GPU is available).

### [Bifrost Roadmap](ROADMAP.md)

## A Simple Pipeline

Here's a snippet that reads Sigproc filterbank files, applies a
Fast Dispersion Measure Transform (FDMT) on the GPU, and writes
the results to a set of dedispersed time series files:

```python
import bifrost as bf
import sys

filenames = sys.argv[1:]

print "Building pipeline"
data = bf.blocks.read_sigproc(filenames, gulp_nframe=128)
data = bf.blocks.copy(data, 'cuda')
data = bf.blocks.transpose(data, ['pol', 'freq', 'time'])
data = bf.blocks.fdmt(data, max_dm=100.)
data = bf.blocks.copy(data, 'cuda_host')
bf.blocks.write_sigproc(data)

print "Running pipeline"
bf.get_default_pipeline().run()
print "All done"
```

## A More Complex Pipeline

Below is a longer snippet that demonstrates some additional features
of Bifrost pipelines, including the BlockChainer tool, block scopes,
CPU and GPU binding, data views, and dot graph output. This example
generates high-resolution spectra from Guppi Raw data:

```python
import bifrost as bf
import sys

filenames = sys.argv[1:]
f_avg = 4
n_int = 8

print "Building pipeline"
bc = bf.BlockChainer()
bc.blocks.read_guppi_raw(filenames, core=0)
bc.blocks.copy(space='cuda', core=1)
with bf.block_scope(fuse=True, gpu=0):
    bc.blocks.transpose(['time', 'pol', 'freq', 'fine_time'])
    bc.blocks.fft(axes='fine_time', axis_labels='fine_freq', apply_fftshift=True)
    bc.blocks.detect('stokes')
    bc.views.merge_axes('freq', 'fine_freq')
    bc.blocks.reduce('freq', f_avg)
    bc.blocks.accumulate(n_int)
bc.blocks.copy(space='cuda_host', core=2)
bc.blocks.write_sigproc(core=3)

pipeline = bf.get_default_pipeline()
print pipeline.dot_graph()
print "Running pipeline"
pipeline.shutdown_on_signals()
pipeline.run()
print "All done"
```

## Feature Overview

 - Designed for sustained high-throughput stream processing
 - Python API wraps fast C++/CUDA backend
 - Fast and flexible ring buffer specifically designed for processing continuous data streams
 - Native support for both system (CPU) and CUDA (GPU) memory spaces and computation
 - Fast kernels for transposition, dedispersion, correlation, beamforming and more
 - bfMap: JIT-compiled ND array transformations
 - Fast UDP data capture
 - A growing library of ready-to-use pipeline 'blocks'
 - Rich metadata enables seamless interoperability between blocks

## Installation

**For a quick demo which you can run in-browser without installation,
go to the following [link](https://colab.research.google.com/github/ledatelescope/bifrost/blob/master/BifrostDemo.ipynb).**

### C Dependencies

    $ sudo apt-get install exuberant-ctags

### Python Dependencies

 * numpy
 * contextlib2
 * pint
 * ctypesgen

```
$ sudo pip install numpy contextlib2 pint ctypesgen==1.0.2
```

### Bifrost Installation

To configure Bifrost for you your system and build the library, then run:

    $ ./configure
    $ make -j
    $ sudo make install

By default this will install the library and headers into /usr/local/lib and
/usr/local/include respectively.  You can use the --prefix option to configure
to change this.

You can call the following for a local Python installation:

    $ ./configure --with-pyinstall-flags=--user
    $ make -j
    $ sudo make install HAVE_PYTHON=0
    $ make -C python install

### Docker Container

Install dependencies:

 * [Docker Engine](https://docs.docker.com/engine/installation/)
 * [NVIDIA Docker](https://github.com/NVIDIA/nvidia-docker)

Build Docker image:

    $ make docker

Launch container:

    $ nvidia-docker run --rm -it ledatelescope/bifrost

For CPU-only builds:

    $ make docker-cpu
    $ docker run --rm -it ledatelescope/bifrost

### Running Tests

To run all CPU and GPU tests:

    $ make test

## Documentation

### [Online Bifrost Documentation](http://ledatelescope.github.io/bifrost/)

### Building the Docs with Docker

To quickly build the docs using Docker, ensure that you have
built a Bifrost container as `ledatelescope/bifrost`.
Then, inside the `docs` folder, execute `./docker_build_docs.sh`,
which will create a container called `bifrost_docs`, then
run it, and have it complete the docs-building process for you,
outputting the entire html documentation inside `docs/html` on
your machine.

### Building the Docs from Scratch

Install sphinx and breathe using pip, and also install Doxygen.

Doxygen documentation can be generated by running:

    $ make doc

This documentation can then be used in a Sphinx build
by running

    $ make html

inside the /docs directory.

## Telemetry

By default Bifrost installs with basic Python telemetry enabled in
order to help inform how the software is used and to help inform future
development.  The data collected as part of this consist seven things:
 * a timestamp for when the report is generated,
 * a unique installation identifier,
 * the Bifrost version being used,
 * the execution time of the Python process that imports Bifrost,
 * which Bifrost modules are imported,
 * which Bifrost functions are used and their average execution times, and
 * which Bifrost scripts are used.
These data are sent to the Bifrost developers using a HTTP POST request where
they are aggregated.

Users can opt out of telemetry collection using:

```
python -m bifrost.telemetry --disable
```

This command will set a disk-based flag that disables the reporting process.

## Acknowledgement

If you make use of Bifrost as part of your data collection or analysis please
include the following acknowledgement in your publications:

> This research has made use of Bifrost (Cranmer et al. 2017).  Continued
> development of Bifrost is supported by NSF award OAC/2103707.

and cite:

> \bibitem[Cranmer et al.(2017)]{2017JAI.....650007C} Cranmer, M.~D., Barsdell, B.~R., Price, D.~C., et al.\ 2017, Journal of Astronomical Instrumentation, 6, 1750007. doi:10.1142/S2251171717500076

## Contributors

 * Ben Barsdell
 * Daniel Price
 * Miles Cranmer
 * Hugh Garsden
 * Jayce Dowell


SurfaceTopography
=================

*Read and analyze surface topographies with Python.* This code implements basic classes for handling uniform and
nonuniform surface topography data. It contains a rich set of import filters for experimental surface topography data.
Surface topographies can be easily analyzed using standard (rms height, power spectrum, ...) and some special purpose
(autocorrelation function, variable bandwidth analysis, ...) statistical techniques.

If you use this code, please cite:
* [Jacobs, Junge, Pastewka, Surf. Topogr. Metrol. Prop. 1, 013001 (2017)](https://doi.org/10.1088/2051-672X/aa51f8)
* [Röttger el al., Surf. Topogr. Metrol. Prop. 10, 035032 (2022)](https://doi.org/10.1088/2051-672X/ac860a)

Build status
------------

The following badge should say _tests passing_. This means that all automated tests completed successfully for the master branch.

[![Build Status](https://github.com/ContactEngineering/SurfaceTopography/actions/workflows/tests.yml/badge.svg)](https://github.com/ContactEngineering/SurfaceTopography/actions/workflows/tests.yml)

Documentation
-------------

This README file contains a brief introduction into the code. The full documentation can be found at https://contactengineering.github.io/SurfaceTopography/.

Installation
------------

Detailed instruction for the installation are provided in the [documentation](https://contactengineering.github.io/SurfaceTopography/installation.html?highlight=installation). If you want to install from source
you need to run `git submodule update --init` after a fresh checkout.

The most basic configuration of SurfaceTopography installs all requirements autonomously `python3 -m pip install SurfaceTopgography`

Containerized SurfaceTopography
-------------------------------

*ContactEngineering* provides container descriptions at the [ce-container-stack](https://github.com/ContactEngineering/ce-container-stack).

For getting started quickly with [Docker](https://www.docker.com/) and `SurfaceTopography` in a ready-to-run JupyterLab environment, try

    docker run -p 8888:8888 imteksim/jupyterlab-surfacetopography:latest

Navigate to the JupyterLab server in your browser as instructed by the terminal output and launch a notebook with the `SurfaceTopography` kernel.

Funding
-------

Development of this project is funded by the [European Research Council](https://erc.europa.eu) within [Starting Grant 757343](https://cordis.europa.eu/project/id/757343) and by the [Deutsche Forschungsgemeinschaft](https://www.dfg.de/en) within projects [PA 2023/2](https://gepris.dfg.de/gepris/projekt/258153560) and [EXC 2193](https://gepris.dfg.de/gepris/projekt/390951807).


.. image:: https://raw.githubusercontent.com/apriha/snps/master/docs/images/snps_banner.png

|ci| |codecov| |docs| |pypi| |python| |downloads| |ruff|

snps
====
tools for reading, writing, merging, and remapping SNPs 🧬

``snps`` *strives to be an easy-to-use and accessible open-source library for working with
genotype data*

Features
--------
Input / Output
``````````````
- Read raw data (genotype) files from a variety of direct-to-consumer (DTC) DNA testing
  sources with a `SNPs <https://snps.readthedocs.io/en/stable/snps.html#snps.snps.SNPs>`_
  object
- Read and write VCF files (e.g., convert `23andMe <https://www.23andme.com>`_ to VCF)
- Merge raw data files from different DNA tests, identifying discrepant SNPs in the process
- Read data in a variety of formats (e.g., files, bytes, compressed with `gzip` or `zip`)
- Handle several variations of file types, validated via
  `openSNP parsing analysis <https://github.com/apriha/snps/tree/master/analysis/parse-opensnp-files>`_

Build / Assembly Detection and Remapping
````````````````````````````````````````
- Detect the build / assembly of SNPs (supports builds 36, 37, and 38)
- Remap SNPs between builds / assemblies

Data Cleaning
`````````````
- Perform quality control (QC) / filter low quality SNPs based on `chip clusters <https://doi.org/10.1016/j.csbj.2021.06.040>`_
- Fix several common issues when loading SNPs
- Sort SNPs based on chromosome and position
- Deduplicate RSIDs
- Deduplicate alleles in the non-PAR regions of the X and Y chromosomes for males
- Deduplicate alleles on MT
- Assign PAR SNPs to the X or Y chromosome

Analysis
````````
- Derive sex from SNPs
- Detect deduced genotype / chip array and chip version based on `chip clusters <https://doi.org/10.1016/j.csbj.2021.06.040>`_
- Predict ancestry from SNPs (when installed with `ezancestry <https://github.com/arvkevi/ezancestry>`_)

Supported Genotype Files
------------------------
``snps`` supports `VCF <https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3137218/>`_ files and
genotype files from the following DNA testing sources:

- `23andMe <https://www.23andme.com>`_
- `Ancestry <https://www.ancestry.com>`_
- `CircleDNA <https://circledna.com/>`_
- `Código 46 <https://codigo46.com.mx>`_
- `DNA.Land <https://dna.land>`_
- `Family Tree DNA <https://www.familytreedna.com>`_
- `Genes for Good <https://genesforgood.sph.umich.edu>`_
- `LivingDNA <https://livingdna.com>`_
- `Mapmygenome <https://mapmygenome.in>`_
- `MyHeritage <https://www.myheritage.com>`_
- `Sano Genetics <https://sanogenetics.com>`_
- `tellmeGen <https://www.tellmegen.com>`_

Additionally, ``snps`` can read a variety of "generic" CSV and TSV files.

Dependencies
------------
``snps`` requires `Python <https://www.python.org>`_ 3.8+ and the following Python
packages:

- `numpy <http://www.numpy.org>`_
- `pandas <http://pandas.pydata.org>`_
- `atomicwrites <https://github.com/untitaker/python-atomicwrites>`_

Installation
------------
``snps`` is `available <https://pypi.org/project/snps/>`_ on the
`Python Package Index <https://pypi.org>`_. Install ``snps`` (and its required
Python dependencies) via ``pip``::

    $ pip install snps

For `ancestry prediction <https://snps.readthedocs.io/en/stable/snps.html#snps.snps.SNPs.predict_ancestry>`_
capability, ``snps`` can be installed with `ezancestry <https://github.com/arvkevi/ezancestry>`_::

    $ pip install snps[ezancestry]

Examples
--------
Download Example Data
`````````````````````
First, let's setup logging to get some helpful output:

>>> import logging, sys
>>> logger = logging.getLogger()
>>> logger.setLevel(logging.INFO)
>>> logger.addHandler(logging.StreamHandler(sys.stdout))

Now we're ready to download some example data from `openSNP <https://opensnp.org>`_:

>>> from snps.resources import Resources
>>> r = Resources()
>>> paths = r.download_example_datasets()
Downloading resources/662.23andme.340.txt.gz
Downloading resources/662.ftdna-illumina.341.csv.gz

Load Raw Data
`````````````
Load a `23andMe <https://www.23andme.com>`_ raw data file:

>>> from snps import SNPs
>>> s = SNPs("resources/662.23andme.340.txt.gz")
>>> s.source
'23andMe'
>>> s.count
991786

The ``SNPs`` class accepts a path to a file or a bytes object. A ``Reader`` class attempts to
infer the data source and load the SNPs. The loaded SNPs are
`normalized <https://snps.readthedocs.io/en/stable/snps.html#snps.snps.SNPs.snps>`_ and
available via a ``pandas.DataFrame``:

>>> df = s.snps
>>> df.columns.values
array(['chrom', 'pos', 'genotype'], dtype=object)
>>> df.index.name
'rsid'
>>> df.chrom.dtype.name
'object'
>>> df.pos.dtype.name
'uint32'
>>> df.genotype.dtype.name
'object'
>>> len(df)
991786

``snps`` also attempts to detect the build / assembly of the data:

>>> s.build
37
>>> s.build_detected
True
>>> s.assembly
'GRCh37'

Merge Raw Data Files
````````````````````
The dataset consists of raw data files from two different DNA testing sources - let's combine
these files. Specifically, we'll update the ``SNPs`` object with SNPs from a
`Family Tree DNA <https://www.familytreedna.com>`_ file.

>>> merge_results = s.merge([SNPs("resources/662.ftdna-illumina.341.csv.gz")])
Merging SNPs('662.ftdna-illumina.341.csv.gz')
SNPs('662.ftdna-illumina.341.csv.gz') has Build 36; remapping to Build 37
Downloading resources/NCBI36_GRCh37.tar.gz
27 SNP positions were discrepant; keeping original positions
151 SNP genotypes were discrepant; marking those as null
>>> s.source
'23andMe, FTDNA'
>>> s.count
1006960
>>> s.build
37
>>> s.build_detected
True

If the SNPs being merged have a build that differs from the destination build, the SNPs to merge
will be remapped automatically. After this example merge, the build is still detected, since the
build was detected for all ``SNPs`` objects that were merged.

As the data gets added, it's compared to the existing data, and SNP position and genotype
discrepancies are identified. (The discrepancy thresholds can be tuned via parameters.) These
discrepant SNPs are available for inspection after the merge via properties of the ``SNPs`` object.

>>> len(s.discrepant_merge_genotypes)
151

Additionally, any non-called / null genotypes will be updated during the merge, if the file
being merged has a called genotype for the SNP.

Moreover, ``merge`` takes a ``chrom`` parameter - this enables merging of only SNPs associated
with the specified chromosome (e.g., "Y" or "MT").

Finally, ``merge`` returns a list of ``dict``, where each ``dict`` has information corresponding
to the results of each merge (e.g., SNPs in common).

>>> sorted(list(merge_results[0].keys()))
['common_rsids', 'discrepant_genotype_rsids', 'discrepant_position_rsids', 'merged']
>>> merge_results[0]["merged"]
True
>>> len(merge_results[0]["common_rsids"])
692918

Remap SNPs
``````````
Now, let's remap the merged SNPs to change the assembly / build:

>>> s.snps.loc["rs3094315"].pos
752566
>>> chromosomes_remapped, chromosomes_not_remapped = s.remap(38)
Downloading resources/GRCh37_GRCh38.tar.gz
>>> s.build
38
>>> s.assembly
'GRCh38'
>>> s.snps.loc["rs3094315"].pos
817186

SNPs can be remapped between Build 36 (``NCBI36``), Build 37 (``GRCh37``), and Build 38
(``GRCh38``).

Save SNPs
`````````
Ok, so far we've merged the SNPs from two files (ensuring the same build in the process and
identifying discrepancies along the way). Then, we remapped the SNPs to Build 38. Now, let's save
the merged and remapped dataset consisting of 1M+ SNPs to a tab-separated values (TSV) file:

>>> saved_snps = s.to_tsv("out.txt")
Saving output/out.txt
>>> print(saved_snps)
output/out.txt

Moreover, let's get the reference sequences for this assembly and save the SNPs as a VCF file:

>>> saved_snps = s.to_vcf("out.vcf")
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.1.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.2.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.3.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.4.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.5.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.6.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.7.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.8.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.9.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.10.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.11.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.12.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.13.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.14.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.15.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.16.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.17.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.18.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.19.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.20.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.21.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.22.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.X.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.Y.fa.gz
Downloading resources/fasta/GRCh38/Homo_sapiens.GRCh38.dna.chromosome.MT.fa.gz
Saving output/out.vcf
1 SNP positions were found to be discrepant when saving VCF

When saving a VCF, if any SNPs have positions outside of the reference sequence, they are marked
as discrepant and are available via a property of the ``SNPs`` object.

All `output files <https://snps.readthedocs.io/en/stable/output_files.html>`_ are saved to the
output directory.

Documentation
-------------
Documentation is available `here <https://snps.readthedocs.io/>`_.

Acknowledgements
----------------
Thanks to Mike Agostino, Padma Reddy, Kevin Arvai, `openSNP <https://opensnp.org>`_,
`Open Humans <https://www.openhumans.org>`_, and `Sano Genetics <https://sanogenetics.com>`_.

``snps`` incorporates code and concepts generated with the assistance of
`OpenAI's <https://openai.com>`_ `ChatGPT <https://chat.openai.com>`_ (GPT-3.5). ✨

License
-------
``snps`` is licensed under the `BSD 3-Clause License <https://github.com/apriha/snps/blob/master/LICENSE.txt>`_.

.. https://github.com/rtfd/readthedocs.org/blob/master/docs/badges.rst
.. |ci| image:: https://github.com/apriha/snps/actions/workflows/ci.yml/badge.svg?branch=master
   :target: https://github.com/apriha/snps/actions/workflows/ci.yml
.. |codecov| image:: https://codecov.io/gh/apriha/snps/branch/master/graph/badge.svg
   :target: https://codecov.io/gh/apriha/snps
.. |docs| image:: https://readthedocs.org/projects/snps/badge/?version=stable
   :target: https://snps.readthedocs.io/
.. |pypi| image:: https://img.shields.io/pypi/v/snps.svg
   :target: https://pypi.python.org/pypi/snps
.. |python| image:: https://img.shields.io/pypi/pyversions/snps.svg
   :target: https://www.python.org
.. |downloads| image:: https://pepy.tech/badge/snps
   :target: https://pepy.tech/project/snps
.. |ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
   :target: https://github.com/astral-sh/ruff
   :alt: Ruff


***************************************
  Python Electronic Design Automation
***************************************

Hello all,

I have moved on from this project,
and will not spend time on maintenance or bug fixes.
I welcome any discussion in Issues.
I also welcome forks of any kind, for any reason.

--------------------

PyEDA is a Python library for electronic design automation.

`Read the docs! <http://pyeda.rtfd.org>`_

Features
========

* Symbolic Boolean algebra with a selection of function representations:

  * Logic expressions
  * Truth tables, with three output states (0, 1, "don't care")
  * Reduced, ordered binary decision diagrams (ROBDDs)

* SAT solvers:

  * Backtracking
  * `PicoSAT <http://fmv.jku.at/picosat>`_

* `Espresso <http://embedded.eecs.berkeley.edu/pubs/downloads/espresso/index.htm>`_ logic minimization
* Formal equivalence
* Multi-dimensional bit vectors
* DIMACS CNF/SAT parsers
* Logic expression parser

Download
========

Bleeding edge code::

   $ git clone git://github.com/cjdrake/pyeda.git

For release tarballs and zipfiles,
visit PyEDA's page at the
`Cheese Shop <https://pypi.python.org/pypi/pyeda>`_.

Installation
============

Latest release version using
`pip <http://www.pip-installer.org/en/latest>`_::

   $ pip3 install pyeda

Installation from the repository::

   $ python3 setup.py install

Note that you will need to have Python headers and libraries in order to
compile the C extensions.
For MacOS, the standard Python installation should have everything you need.
For Linux, you will probably need to install the Python3 "development" package.

For Debian-based systems (eg Ubuntu, Mint)::

   $ sudo apt-get install python3-dev

For RedHat-based systems (eg RHEL, Centos)::

   $ sudo yum install python3-devel

For Windows, just grab the binaries from Christoph Gohlke's
*excellent* `pythonlibs page <http://www.lfd.uci.edu/~gohlke/pythonlibs/>`_.

Logic Expressions
=================

Invoke your favorite Python terminal,
and invoke an interactive ``pyeda`` session::

   >>> from pyeda.inter import *

Create some Boolean expression variables::

   >>> a, b, c, d = map(exprvar, "abcd")

Construct Boolean functions using overloaded Python operators:
``~`` (NOT), ``|`` (OR), ``^`` (XOR), ``&`` (AND), ``>>`` (IMPLIES)::

   >>> f0 = ~a & b | c & ~d
   >>> f1 = a >> b
   >>> f2 = ~a & b | a & ~b
   >>> f3 = ~a & ~b | a & b
   >>> f4 = ~a & ~b & ~c | a & b & c
   >>> f5 = a & b | ~a & c

Construct Boolean functions using standard function syntax::

   >>> f10 = Or(And(Not(a), b), And(c, Not(d)))
   >>> f11 = Implies(a, b)
   >>> f12 = Xor(a, b)
   >>> f13 = Xnor(a, b)
   >>> f14 = Equal(a, b, c)
   >>> f15 = ITE(a, b, c)
   >>> f16 = Nor(a, b, c)
   >>> f17 = Nand(a, b, c)

Construct Boolean functions using higher order operators::

   >>> OneHot(a, b, c)
   And(Or(~a, ~b), Or(~a, ~c), Or(~b, ~c), Or(a, b, c))
   >>> OneHot0(a, b, c)
   And(Or(~a, ~b), Or(~a, ~c), Or(~b, ~c))
   >>> Majority(a, b, c)
   Or(And(a, b), And(a, c), And(b, c))
   >>> AchillesHeel(a, b, c, d)
   And(Or(a, b), Or(c, d))

Investigate a function's properties::

   >>> f0.support
   frozenset({a, b, c, d})
   >>> f0.inputs
   (a, b, c, d)
   >>> f0.top
   a
   >>> f0.degree
   4
   >>> f0.cardinality
   16
   >>> f0.depth
   2

Convert expressions to negation normal form (NNF),
with only OR/AND and literals::

   >>> f11.to_nnf()
   Or(~a, b)
   >>> f12.to_nnf()
   Or(And(~a, b), And(a, ~b))
   >>> f13.to_nnf()
   Or(And(~a, ~b), And(a, b))
   >>> f14.to_nnf()
   Or(And(~a, ~b, ~c), And(a, b, c))
   >>> f15.to_nnf()
   Or(And(a, b), And(~a, c))
   >>> f16.to_nnf()
   And(~a, ~b, ~c)
   >>> f17.to_nnf()
   Or(~a, ~b, ~c)

Restrict a function's input variables to fixed values,
and perform function composition::

   >>> f0.restrict({a: 0, c: 1})
   Or(b, ~d)
   >>> f0.compose({a: c, b: ~d})
   Or(And(~c, ~d), And(c, ~d))

Test function formal equivalence::

   >>> f2.equivalent(f12)
   True
   >>> f4.equivalent(f14)
   True

Investigate Boolean identities::

   # Double complement
   >>> ~~a
   a

   # Idempotence
   >>> a | a
   a
   >>> And(a, a)
   a

   # Identity
   >>> Or(a, 0)
   a
   >>> And(a, 1)
   a

   # Dominance
   >>> Or(a, 1)
   1
   >>> And(a, 0)
   0

   # Commutativity
   >>> (a | b).equivalent(b | a)
   True
   >>> (a & b).equivalent(b & a)
   True

   # Associativity
   >>> Or(a, Or(b, c))
   Or(a, b, c)
   >>> And(a, And(b, c))
   And(a, b, c)

   # Distributive
   >>> (a | (b & c)).to_cnf()
   And(Or(a, b), Or(a, c))
   >>> (a & (b | c)).to_dnf()
   Or(And(a, b), And(a, c))

   # De Morgan's
   >>> Not(a | b).to_nnf()
   And(~a, ~b)
   >>> Not(a & b).to_nnf()
   Or(~a, ~b)

Perform Shannon expansions::

   >>> a.expand(b)
   Or(And(a, ~b), And(a, b))
   >>> (a & b).expand([c, d])
   Or(And(a, b, ~c, ~d), And(a, b, ~c, d), And(a, b, c, ~d), And(a, b, c, d))

Convert a nested expression to disjunctive normal form::

   >>> f = a & (b | (c & d))
   >>> f.depth
   3
   >>> g = f.to_dnf()
   >>> g
   Or(And(a, b), And(a, c, d))
   >>> g.depth
   2
   >>> f.equivalent(g)
   True

Convert between disjunctive and conjunctive normal forms::

   >>> f = ~a & ~b & c | ~a & b & ~c | a & ~b & ~c | a & b & c
   >>> g = f.to_cnf()
   >>> h = g.to_dnf()
   >>> g
   And(Or(a, b, c), Or(a, ~b, ~c), Or(~a, b, ~c), Or(~a, ~b, c))
   >>> h
   Or(And(~a, ~b, c), And(~a, b, ~c), And(a, ~b, ~c), And(a, b, c))

Multi-Dimensional Bit Vectors
=============================

Create some four-bit vectors, and use slice operators::

   >>> A = exprvars('a', 4)
   >>> B = exprvars('b', 4)
   >>> A
   farray([a[0], a[1], a[2], a[3]])
   >>> A[2:]
   farray([a[2], a[3]])
   >>> A[-3:-1]
   farray([a[1], a[2]])

Perform bitwise operations using Python overloaded operators:
``~`` (NOT), ``|`` (OR), ``&`` (AND), ``^`` (XOR)::

   >>> ~A
   farray([~a[0], ~a[1], ~a[2], ~a[3]])
   >>> A | B
   farray([Or(a[0], b[0]), Or(a[1], b[1]), Or(a[2], b[2]), Or(a[3], b[3])])
   >>> A & B
   farray([And(a[0], b[0]), And(a[1], b[1]), And(a[2], b[2]), And(a[3], b[3])])
   >>> A ^ B
   farray([Xor(a[0], b[0]), Xor(a[1], b[1]), Xor(a[2], b[2]), Xor(a[3], b[3])])

Reduce bit vectors using unary OR, AND, XOR::

   >>> A.uor()
   Or(a[0], a[1], a[2], a[3])
   >>> A.uand()
   And(a[0], a[1], a[2], a[3])
   >>> A.uxor()
   Xor(a[0], a[1], a[2], a[3])

Create and test functions that implement non-trivial logic such as arithmetic::

   >>> from pyeda.logic.addition import *
   >>> S, C = ripple_carry_add(A, B)
   # Note "1110" is LSB first. This says: "7 + 1 = 8".
   >>> S.vrestrict({A: "1110", B: "1000"}).to_uint()
   8

Other Function Representations
==============================

Consult the `documentation <http://pyeda.rtfd.org>`_ for information about
truth tables, and binary decision diagrams.
Each function representation has different trade-offs,
so always use the right one for the job.

PicoSAT SAT Solver C Extension
==============================

PyEDA includes an extension to the industrial-strength
`PicoSAT <http://fmv.jku.at/picosat>`_ SAT solving engine.

Use the ``satisfy_one`` method to finding a single satisfying input point::

   >>> f = OneHot(a, b, c)
   >>> f.satisfy_one()
   {a: 0, b: 0, c: 1}

Use the ``satisfy_all`` method to iterate through all satisfying input points::

   >>> list(f.satisfy_all())
   [{a: 0, b: 0, c: 1}, {a: 0, b: 1, c: 0}, {a: 1, b: 0, c: 0}]

For more interesting examples, see the following documentation chapters:

* `Solving Sudoku <http://pyeda.readthedocs.org/en/latest/sudoku.html>`_
* `All Solutions to the Eight Queens Puzzle <http://pyeda.readthedocs.org/en/latest/queens.html>`_

Espresso Logic Minimization C Extension
=======================================

PyEDA includes an extension to the famous Espresso library for the minimization
of two-level covers of Boolean functions.

Use the ``espresso_exprs`` function to minimize multiple expressions::

   >>> f1 = Or(~a & ~b & ~c, ~a & ~b & c, a & ~b & c, a & b & c, a & b & ~c)
   >>> f2 = Or(~a & ~b & c, a & ~b & c)
   >>> f1m, f2m = espresso_exprs(f1, f2)
   >>> f1m
   Or(And(~a, ~b), And(a, b), And(~b, c))
   >>> f2m
   And(~b, c)

Use the ``espresso_tts`` function to minimize multiple truth tables::

   >>> X = exprvars('x', 4)
   >>> f1 = truthtable(X, "0000011111------")
   >>> f2 = truthtable(X, "0001111100------")
   >>> f1m, f2m = espresso_tts(f1, f2)
   >>> f1m
   Or(x[3], And(x[0], x[2]), And(x[1], x[2]))
   >>> f2m
   Or(x[2], And(x[0], x[1]))

Execute Unit Test Suite
=======================

If you have `PyTest <https://pytest.org>`_ installed,
run the unit test suite with the following command::

   $ make test

If you have `Coverage <https://pypi.python.org/pypi/coverage>`_ installed,
generate a coverage report (including HTML) with the following command::

   $ make cover

Perform Static Lint Checks
==========================

If you have `Pylint <http://www.pylint.org>`_ installed,
perform static lint checks with the following command::

   $ make lint

Build the Documentation
=======================

If you have `Sphinx <http://sphinx-doc.org>`_ installed,
build the HTML documentation with the following command::

   $ make html

Python Versions Supported
=========================

PyEDA is developed using Python 3.3+.
It is **NOT** compatible with Python 2.7, or Python 3.2.

Citations
=========

I recently discovered that people actually use this software in the real world.
Feel free to send me a pull request if you would like your project listed here
as well.

* `A Model-Based Approach for Reliability Assessment in Component-Based Systems <https://www.phmsociety.org/sites/phmsociety.org/files/phm_submission/2014/phmc_14_025.pdf>`_
* `bunsat <http://www.react.uni-saarland.de/tools/bunsat>`_,
  used for the SAT paper `Fast DQBF Refutation <http://www.react.uni-saarland.de/publications/sat14.pdf>`_
* `Solving Logic Riddles with PyEDA <http://nicky.vanforeest.com/misc/pyeda/puzzle.html>`_
* `Input-Aware Implication Selection Scheme Utilizing ATPG for Efficient Concurrent Error Detection <https://www.mdpi.com/2079-9292/7/10/258>`_
* `Generation Methodology for Good-Enough Approximate Modules of ATMR <https://www.dropbox.com/s/dx307ml5qlxn49z/electronicstestingppr.pdf>`_
* `Effect of FPGA Circuit Implementation on Error Detection Using Logic Implication Checking <https://www.dropbox.com/s/brwjnrqdlvkuxxe/08491817.pdf>`_

Presentations
=============

* Video from `SciPy 2015 <https://www.youtube.com/watch?v=cljDuK0ouRs>`_

Contact the Authors
===================

* Chris Drake (cjdrake AT gmail DOT com), http://cjdrake.github.io


Extra Plugins for Nikola
========================

The source repository of <https://plugins.getnikola.com/> — Plugins for the Nikola static site generator.

## How to get your Plugin to the Index

1. Follow the Developer Documentation closely.
2. Fork this repository and put your plugin there.
3. Send a Pull Request.

   **Note:** even if you have commit rights (shared with Nikola or from another plugin you posted), please send a Pull Request for code review.

4. Success!  Your plugin is in the Index.
   Please note that it will appear on the website at midnight UTC, when the site is automatically rebuilt.

## Developer Documentation

Anyone can develop plugins for Nikola.  There are some specific files you need if you want them on the Index, though.

There is also a sample `helloworld` plugin available.

### `README.md`

A [Markdown](http://daringfireball.net/projects/markdown/)-formatted file, describing your plugin, what it does, and how it works.

We aren’t using reST, which is a de-facto standard in the Python and Nikola community, for simplicity and historic reasons.

### `requirements.txt` / `requirements-nonpy.txt` / `requirements-plugins.txt` (all optional)

If your plugin depends on something else, you need to add it to one of those files.

If your dependency is a Python package, put it in the `requirements.txt` file, which is then passed over to `pip` while installing your plugin.  Inserting Nikola’s dependencies you also depend on is not mandatory, but suggested just in case those are not our dependencies anymore.

If you depend on a third-party piece of software that is not a Python package installable via `pip`, you need to provide a `requirements-nonpy.txt` file.  The format is `Human-friendly name::http://download/link`.  It will be shown in the Plugins index, and shown to the user while installing.

If you depend on another Nikola plugin, put it in the `requirements-plugins.txt` file, Nikola will install these when installing your plugin.  The format is just the plugin name(s), each on a separate line.

### `conf.py.sample` (optional)

If there are any config options you need for your plugin, put them here.

### `[plugin name].plugin`

This is a standard ConfigParser-style ini file.  It is parsed by yapsy and the Plugin Index.

```ini
[Core]
Name = plugin-name
Module = plugin-name
Tests = test-suite

[Nikola]
MinVersion = version-number
MaxVersion = version-number
Compiler = compiler-that-uses-extensions
PluginCategory = plugin-category

[Documentation]
Author = authors-name
Version = version-number
Website = https://plugins.getnikola.com/#plugin-name
Description = A short, one-line description
```

#### `[Core]`

In `[Core]`, you need to provide the `Name` of your plugin and the `Module` your plugin resides in.  We recommend to have them identical (just like the directory name and the name of this very config file).

**Additional fields:** If you have tests, put it in the `/tests/` directory of this repository (*not your plugin!*) and put the test module name in a `Tests` field.  Tests in `/tests/` are run in CI (via GitHub Actions).  **Note that the GitHub Actions test runner does not interpret `requirements-nonpy.txt` files!**

#### `[Nikola]`

If you require a specific version of Nikola, set `MinVersion` and `MaxVersion` accordingly.  Those fields are not mandatory.

If the plugin is a compiler extension, you need to set the `Compiler` here.  Otherwise, skip this field.

The `PluginCategory` field is mandatory, and it must contain the plugin category.
Use 'Compiler' for compilers and the base class name for anything else.

#### `[Documentation]`

In which you need to put in the `Author`, `Version`, `Website` (of the plugin; you can just use the link to the Index as shown in the example; replacing `plugin-name` with the obvious thing) and a short `Description`.

### `[plugin name].py`

This is where your plugin resides.  [Follow the *Extending Nikola* tutorial for instructions on how to write a plugin.](https://getnikola.com/extending.html)

Please make sure your plugin has a valid open-source license, and that it has a license comment. For short licenses ([MIT](https://choosealicense.com/licenses/mit/)/[BSD](https://choosealicense.com/licenses/bsd-2-clause/)), include the entire license text; for longer licenses (Apache, GPL/LGPL), use the short declarations ([Apache](https://www.apache.org/licenses/LICENSE-2.0#apply), [GPL](https://www.gnu.org/licenses/gpl-howto.html)). If you don’t know which license to use, we recommend MIT (as seen in Nikola core).