dvg-ringbuffer


Namedvg-ringbuffer JSON
Version 1.1.0 PyPI version JSON
download
home_pagehttps://github.com/Dennis-van-Gils/python-dvg-ringbuffer
SummaryNumpy ring buffer at a fixed memory address to allow for significantly sped up numpy, sigpy, numba & pyFFTW calculations.
upload_time2024-06-22 09:39:47
maintainerNone
docs_urlNone
authorDennis van Gils
requires_python~=3.0
licenseMIT
keywords ring buffer circular buffer numpy-ringbuffer numpy scipy numba pyfftw deque speed fast
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            .. image:: https://static.pepy.tech/personalized-badge/dvg-ringbuffer?period=month&units=international_system&left_color=gray&right_color=blue&left_text=%E2%86%93%20per%20month
    :target: https://pepy.tech/project/dvg-ringbuffer
.. image:: https://img.shields.io/pypi/v/dvg-ringbuffer
    :target: https://pypi.org/project/dvg-ringbuffer
.. image:: https://img.shields.io/pypi/pyversions/dvg-ringbuffer
    :target: https://pypi.org/project/dvg-ringbuffer
.. image:: https://github.com/Dennis-van-Gils/python-dvg-ringbuffer/actions/workflows/python-package.yml/badge.svg
    :target: https://github.com/Dennis-van-Gils/python-dvg-ringbuffer/actions/workflows/python-package.yml
.. image:: https://coveralls.io/repos/github/Dennis-van-Gils/python-dvg-ringbuffer/badge.svg
    :target: https://coveralls.io/github/Dennis-van-Gils/python-dvg-ringbuffer
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
    :target: https://github.com/psf/black
.. image:: https://img.shields.io/badge/License-MIT-purple.svg
    :target: https://github.com/Dennis-van-Gils/python-dvg-ringbuffer/blob/master/LICENSE.txt

DvG_RingBuffer
==============
*Provides a numpy ring buffer at a fixed memory address to allow for
significantly sped up* ``numpy``, ``sigpy``, ``numba`` *&* ``pyFFTW``
*calculations.*

- Github: https://github.com/Dennis-van-Gils/python-dvg-ringbuffer
- PyPI: https://pypi.org/project/dvg-ringbuffer

Installation::

    pip install dvg-ringbuffer

Based on:

    https://pypi.org/project/numpy_ringbuffer/ by Eric Wieser.

    ``DvG_RingBuffer`` can be used as a drop-in replacement for
    ``numpy_ringbuffer`` and provides several optimizations and extra features,
    but requires Python 3.

If and only if the ring buffer is completely full, will it return its array
data as a contiguous C-style numpy array at a single fixed memory address per
ring buffer instance. It does so by unwrapping the discontiguous ring buffer
array into a second extra *unwrap* buffer that is a private member of the ring
buffer class. This is advantegeous for other accelerated computations by, e.g.,
``numpy``, ``sigpy``, ``numba`` & ``pyFFTW``, that benefit from being fed with
contiguous arrays at the same memory address each time again, such that compiler
optimizations and data planning are made possible.

When the ring buffer is not completely full, it will return its data as a
contiguous C-style numpy array, but at different memory addresses. This is how
the original ``numpy-buffer`` always operates.

Commonly, ``collections.deque()`` is used to act as a ring buffer. The
benefits of a deque is that it is thread safe and fast (enough) for most
situations. However, there is an overhead whenever the deque -- a list-like
container -- needs to be transformed into a numpy array. Because
``DvG_RingBuffer`` already returns numpy arrays it will outperform a
``collections.deque()`` easily, tested to be a factor of ~60.

.. warning::

    * This ring buffer is not thread safe. You'll have to implement your own
      mutex locks when using this ring buffer in multithreaded operations.

    * The data array that is returned by a full ring buffer is a pass by
      reference of the *unwrap* buffer. It is not a copy! Hence, changing
      values in the returned data array is identical to changing values in the
      *unwrap* buffer.

API
===

``class RingBuffer(capacity, dtype=np.float64, allow_overwrite=True)``
----------------------------------------------------------------------
    Create a new ring buffer with the given capacity and element type.

        Args:
            capacity (``int``):
                The maximum capacity of the ring buffer

            dtype (``data-type``, optional):
                Desired type of buffer elements. Use a type like ``(float, 2)``
                to produce a buffer with shape ``(capacity, 2)``.

                Default: ``np.float64``

            allow_overwrite (``bool``, optional):
                If ``False``, throw an IndexError when trying to append to an
                already full buffer.

                Default: ``True``

Methods
-------
* ``clear()``
* ``append(value)``
    Append a single value to the ring buffer.

    .. code-block:: python

        rb = RingBuffer(3, dtype=np.int)  #  []
        rb.append(1)                      #  [1]
        rb.append(2)                      #  [1, 2]
        rb.append(3)                      #  [1, 2, 3]
        rb.append(4)                      #  [2, 3, 4]

* ``appendleft(value)``
    Append a single value to the ring buffer from the left side.

    .. code-block:: python

        rb = RingBuffer(3, dtype=np.int)  #  []
        rb.appendleft(1)                  #  [1]
        rb.appendleft(2)                  #  [2, 1]
        rb.appendleft(3)                  #  [3, 2, 1]
        rb.appendleft(4)                  #  [4, 3, 2]

* ``extend(values)``
    Extend the ring buffer with a list of values.

    .. code-block:: python

        rb = RingBuffer(3, dtype=np.int)  #  []
        rb.extend([1])                    #  [1]
        rb.extend([2, 3])                 #  [1, 2, 3]
        rb.extend([4, 5, 6, 7])           #  [5, 6, 7]

* ``extendleft(values)``
    Extend the ring buffer with a list of values from the left side.

    .. code-block:: python

        rb = RingBuffer(3, dtype=np.int)  #  []
        rb.extendleft([1])                #  [1]
        rb.extendleft([3, 2])             #  [3, 2, 1]
        rb.extendleft([7, 6, 5, 4])       #  [7, 6, 5]

* ``pop()``
    Remove the right-most item from the ring buffer and return it.

* ``popleft()``
    Remove the left-most item from the ring buffer and return it.

Properties
----------
* ``is_full``
* ``unwrap_address``
* ``current_address``
* ``dtype``
* ``shape``
* ``maxlen``

Indexing & slicing
------------------
* ``[]`` including negative indices and slicing

    .. code-block:: python

        from dvg_ringbuffer import RingBuffer

        rb = RingBuffer(4, dtype=np.int)  # --> rb[:] = array([], dtype=int32)
        rb.extend([1, 2, 3, 4, 5])        # --> rb[:] = array([2, 3, 4, 5])
        x = rb[0]                         # --> x = 2
        x = rb[-1]                        # --> x = 5
        x = rb[:3]                        # --> x = array([2, 3, 4])
        x = rb[np.array([0, 2, -1])]      # --> x = array([2, 4, 5])

        rb = RingBuffer(5, dtype=(np.int, 2))  # --> rb[:] = array([], shape=(0, 2), dtype=int32)
        rb.append([1, 2])                      # --> rb[:] = array([[1, 2]])
        rb.append([3, 4])                      # --> rb[:] = array([[1, 2], [3, 4]])
        rb.append([5, 6])                      # --> rb[:] = array([[1, 2], [3, 4], [5, 6]])
        x = rb[0]                              # --> x = array([1, 2])
        x = rb[0, :]                           # --> x = array([1, 2])
        x = rb[:, 0]                           # --> x = array([1, 3, 5])

Changelog
=========

1.1.0 (2024-06-22)
------------------
* Support for Numpy 2 without any need for changes

1.0.4 (2023-02-27)
------------------
* Deprecated `requires.io` and `travis`

1.0.3 (2021-05-28)
------------------
* Added dev note: Don't use numba's njit decorator on `np.concatenate()`

1.0.2 (2021-05-26)
------------------
* Replaced Numpy types with standard types as requested by Numpy

1.0.1 (2020-07-21)
------------------
* Updated documentation

1.0.0 (2020-07-21)
------------------
* First release on PyPI

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Dennis-van-Gils/python-dvg-ringbuffer",
    "name": "dvg-ringbuffer",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "~=3.0",
    "maintainer_email": null,
    "keywords": "ring buffer, circular buffer, numpy-ringbuffer, numpy, scipy, numba, pyFFTW, deque, speed, fast",
    "author": "Dennis van Gils",
    "author_email": "vangils.dennis@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/ac/70/55aa6c87e675ae9f01d71d8de0e33ea380c6d59831b9b951288817788af9/dvg_ringbuffer-1.1.0.tar.gz",
    "platform": null,
    "description": ".. image:: https://static.pepy.tech/personalized-badge/dvg-ringbuffer?period=month&units=international_system&left_color=gray&right_color=blue&left_text=%E2%86%93%20per%20month\r\n    :target: https://pepy.tech/project/dvg-ringbuffer\r\n.. image:: https://img.shields.io/pypi/v/dvg-ringbuffer\r\n    :target: https://pypi.org/project/dvg-ringbuffer\r\n.. image:: https://img.shields.io/pypi/pyversions/dvg-ringbuffer\r\n    :target: https://pypi.org/project/dvg-ringbuffer\r\n.. image:: https://github.com/Dennis-van-Gils/python-dvg-ringbuffer/actions/workflows/python-package.yml/badge.svg\r\n    :target: https://github.com/Dennis-van-Gils/python-dvg-ringbuffer/actions/workflows/python-package.yml\r\n.. image:: https://coveralls.io/repos/github/Dennis-van-Gils/python-dvg-ringbuffer/badge.svg\r\n    :target: https://coveralls.io/github/Dennis-van-Gils/python-dvg-ringbuffer\r\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\r\n    :target: https://github.com/psf/black\r\n.. image:: https://img.shields.io/badge/License-MIT-purple.svg\r\n    :target: https://github.com/Dennis-van-Gils/python-dvg-ringbuffer/blob/master/LICENSE.txt\r\n\r\nDvG_RingBuffer\r\n==============\r\n*Provides a numpy ring buffer at a fixed memory address to allow for\r\nsignificantly sped up* ``numpy``, ``sigpy``, ``numba`` *&* ``pyFFTW``\r\n*calculations.*\r\n\r\n- Github: https://github.com/Dennis-van-Gils/python-dvg-ringbuffer\r\n- PyPI: https://pypi.org/project/dvg-ringbuffer\r\n\r\nInstallation::\r\n\r\n    pip install dvg-ringbuffer\r\n\r\nBased on:\r\n\r\n    https://pypi.org/project/numpy_ringbuffer/ by Eric Wieser.\r\n\r\n    ``DvG_RingBuffer`` can be used as a drop-in replacement for\r\n    ``numpy_ringbuffer`` and provides several optimizations and extra features,\r\n    but requires Python 3.\r\n\r\nIf and only if the ring buffer is completely full, will it return its array\r\ndata as a contiguous C-style numpy array at a single fixed memory address per\r\nring buffer instance. It does so by unwrapping the discontiguous ring buffer\r\narray into a second extra *unwrap* buffer that is a private member of the ring\r\nbuffer class. This is advantegeous for other accelerated computations by, e.g.,\r\n``numpy``, ``sigpy``, ``numba`` & ``pyFFTW``, that benefit from being fed with\r\ncontiguous arrays at the same memory address each time again, such that compiler\r\noptimizations and data planning are made possible.\r\n\r\nWhen the ring buffer is not completely full, it will return its data as a\r\ncontiguous C-style numpy array, but at different memory addresses. This is how\r\nthe original ``numpy-buffer`` always operates.\r\n\r\nCommonly, ``collections.deque()`` is used to act as a ring buffer. The\r\nbenefits of a deque is that it is thread safe and fast (enough) for most\r\nsituations. However, there is an overhead whenever the deque -- a list-like\r\ncontainer -- needs to be transformed into a numpy array. Because\r\n``DvG_RingBuffer`` already returns numpy arrays it will outperform a\r\n``collections.deque()`` easily, tested to be a factor of ~60.\r\n\r\n.. warning::\r\n\r\n    * This ring buffer is not thread safe. You'll have to implement your own\r\n      mutex locks when using this ring buffer in multithreaded operations.\r\n\r\n    * The data array that is returned by a full ring buffer is a pass by\r\n      reference of the *unwrap* buffer. It is not a copy! Hence, changing\r\n      values in the returned data array is identical to changing values in the\r\n      *unwrap* buffer.\r\n\r\nAPI\r\n===\r\n\r\n``class RingBuffer(capacity, dtype=np.float64, allow_overwrite=True)``\r\n----------------------------------------------------------------------\r\n    Create a new ring buffer with the given capacity and element type.\r\n\r\n        Args:\r\n            capacity (``int``):\r\n                The maximum capacity of the ring buffer\r\n\r\n            dtype (``data-type``, optional):\r\n                Desired type of buffer elements. Use a type like ``(float, 2)``\r\n                to produce a buffer with shape ``(capacity, 2)``.\r\n\r\n                Default: ``np.float64``\r\n\r\n            allow_overwrite (``bool``, optional):\r\n                If ``False``, throw an IndexError when trying to append to an\r\n                already full buffer.\r\n\r\n                Default: ``True``\r\n\r\nMethods\r\n-------\r\n* ``clear()``\r\n* ``append(value)``\r\n    Append a single value to the ring buffer.\r\n\r\n    .. code-block:: python\r\n\r\n        rb = RingBuffer(3, dtype=np.int)  #  []\r\n        rb.append(1)                      #  [1]\r\n        rb.append(2)                      #  [1, 2]\r\n        rb.append(3)                      #  [1, 2, 3]\r\n        rb.append(4)                      #  [2, 3, 4]\r\n\r\n* ``appendleft(value)``\r\n    Append a single value to the ring buffer from the left side.\r\n\r\n    .. code-block:: python\r\n\r\n        rb = RingBuffer(3, dtype=np.int)  #  []\r\n        rb.appendleft(1)                  #  [1]\r\n        rb.appendleft(2)                  #  [2, 1]\r\n        rb.appendleft(3)                  #  [3, 2, 1]\r\n        rb.appendleft(4)                  #  [4, 3, 2]\r\n\r\n* ``extend(values)``\r\n    Extend the ring buffer with a list of values.\r\n\r\n    .. code-block:: python\r\n\r\n        rb = RingBuffer(3, dtype=np.int)  #  []\r\n        rb.extend([1])                    #  [1]\r\n        rb.extend([2, 3])                 #  [1, 2, 3]\r\n        rb.extend([4, 5, 6, 7])           #  [5, 6, 7]\r\n\r\n* ``extendleft(values)``\r\n    Extend the ring buffer with a list of values from the left side.\r\n\r\n    .. code-block:: python\r\n\r\n        rb = RingBuffer(3, dtype=np.int)  #  []\r\n        rb.extendleft([1])                #  [1]\r\n        rb.extendleft([3, 2])             #  [3, 2, 1]\r\n        rb.extendleft([7, 6, 5, 4])       #  [7, 6, 5]\r\n\r\n* ``pop()``\r\n    Remove the right-most item from the ring buffer and return it.\r\n\r\n* ``popleft()``\r\n    Remove the left-most item from the ring buffer and return it.\r\n\r\nProperties\r\n----------\r\n* ``is_full``\r\n* ``unwrap_address``\r\n* ``current_address``\r\n* ``dtype``\r\n* ``shape``\r\n* ``maxlen``\r\n\r\nIndexing & slicing\r\n------------------\r\n* ``[]`` including negative indices and slicing\r\n\r\n    .. code-block:: python\r\n\r\n        from dvg_ringbuffer import RingBuffer\r\n\r\n        rb = RingBuffer(4, dtype=np.int)  # --> rb[:] = array([], dtype=int32)\r\n        rb.extend([1, 2, 3, 4, 5])        # --> rb[:] = array([2, 3, 4, 5])\r\n        x = rb[0]                         # --> x = 2\r\n        x = rb[-1]                        # --> x = 5\r\n        x = rb[:3]                        # --> x = array([2, 3, 4])\r\n        x = rb[np.array([0, 2, -1])]      # --> x = array([2, 4, 5])\r\n\r\n        rb = RingBuffer(5, dtype=(np.int, 2))  # --> rb[:] = array([], shape=(0, 2), dtype=int32)\r\n        rb.append([1, 2])                      # --> rb[:] = array([[1, 2]])\r\n        rb.append([3, 4])                      # --> rb[:] = array([[1, 2], [3, 4]])\r\n        rb.append([5, 6])                      # --> rb[:] = array([[1, 2], [3, 4], [5, 6]])\r\n        x = rb[0]                              # --> x = array([1, 2])\r\n        x = rb[0, :]                           # --> x = array([1, 2])\r\n        x = rb[:, 0]                           # --> x = array([1, 3, 5])\r\n\r\nChangelog\r\n=========\r\n\r\n1.1.0 (2024-06-22)\r\n------------------\r\n* Support for Numpy 2 without any need for changes\r\n\r\n1.0.4 (2023-02-27)\r\n------------------\r\n* Deprecated `requires.io` and `travis`\r\n\r\n1.0.3 (2021-05-28)\r\n------------------\r\n* Added dev note: Don't use numba's njit decorator on `np.concatenate()`\r\n\r\n1.0.2 (2021-05-26)\r\n------------------\r\n* Replaced Numpy types with standard types as requested by Numpy\r\n\r\n1.0.1 (2020-07-21)\r\n------------------\r\n* Updated documentation\r\n\r\n1.0.0 (2020-07-21)\r\n------------------\r\n* First release on PyPI\r\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Numpy ring buffer at a fixed memory address to allow for significantly sped up numpy, sigpy, numba & pyFFTW calculations.",
    "version": "1.1.0",
    "project_urls": {
        "Homepage": "https://github.com/Dennis-van-Gils/python-dvg-ringbuffer",
        "Issue Tracker": "https://github.com/Dennis-van-Gils/python-dvg-ringbuffer/issues"
    },
    "split_keywords": [
        "ring buffer",
        " circular buffer",
        " numpy-ringbuffer",
        " numpy",
        " scipy",
        " numba",
        " pyfftw",
        " deque",
        " speed",
        " fast"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "51311d51171e95e6e10b5c554bedd7b403bb35869e02fd00a8a9d3e8fea4ac0f",
                "md5": "c390d542f1c2ae66f335fb509bd372de",
                "sha256": "1d6798fb21c7ee6443ceddc86d6dedc7ee7b038b0959da31d4550b740aa93088"
            },
            "downloads": -1,
            "filename": "dvg_ringbuffer-1.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c390d542f1c2ae66f335fb509bd372de",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "~=3.0",
            "size": 9545,
            "upload_time": "2024-06-22T09:39:46",
            "upload_time_iso_8601": "2024-06-22T09:39:46.220381Z",
            "url": "https://files.pythonhosted.org/packages/51/31/1d51171e95e6e10b5c554bedd7b403bb35869e02fd00a8a9d3e8fea4ac0f/dvg_ringbuffer-1.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ac7055aa6c87e675ae9f01d71d8de0e33ea380c6d59831b9b951288817788af9",
                "md5": "bcce00cfd53f3ac9d6c05d19679bc633",
                "sha256": "9482a34c88a3ad8a677f8ae1ddeb77e0180043d2a9d58aba9cfd047532fa6b41"
            },
            "downloads": -1,
            "filename": "dvg_ringbuffer-1.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "bcce00cfd53f3ac9d6c05d19679bc633",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "~=3.0",
            "size": 11245,
            "upload_time": "2024-06-22T09:39:47",
            "upload_time_iso_8601": "2024-06-22T09:39:47.949304Z",
            "url": "https://files.pythonhosted.org/packages/ac/70/55aa6c87e675ae9f01d71d8de0e33ea380c6d59831b9b951288817788af9/dvg_ringbuffer-1.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-06-22 09:39:47",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Dennis-van-Gils",
    "github_project": "python-dvg-ringbuffer",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "dvg-ringbuffer"
}
        
Elapsed time: 0.26486s