Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 7 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,20 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.13'
cache: 'pip'
- run: pip install -r requirements-dev.txt
- run: mypy --strict calculus
- run: mypy --strict calculus tests examples

pyflakes:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: '3.13'
cache: 'pip'
- run: pip install -r requirements-dev.txt
- run: pyflakes calculus

pycodestyle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- run: pip install -r requirements-dev.txt
- run: pycodestyle calculus

pydocstyle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- run: pip install -r requirements-dev.txt
- run: pydocstyle calculus
- run: ruff check calculus tests examples

pytest:
runs-on: ubuntu-latest
Expand All @@ -53,6 +35,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.13'
cache: 'pip'
- run: pip install -r requirements-dev.txt
- run: pytest

Expand Down Expand Up @@ -81,5 +64,6 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.13'
cache: 'pip'
- run: pip install -r requirements-dev.txt
- run: pymarkdown scan -r . --respect-gitignore
39 changes: 12 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ illustration of the calculus package's sequence ecosystem">

## Vision

The Calculus package aims to provide a collection of reusable abstractions for
discrete and continuous mathematics.
The Calculus package aims to model infinite sequences through lazy evaluation,
providing reusable abstractions for discrete and continuous mathematics.

The current implementation provides a generic `Sequence[T]` abstraction
together with the specialized `NumericSequence`, `Recurrence`,
`NumericRecurrence`, and `Series` subclasses.
together with the specialized `BooleanSequence`, `NumericSequence`,
`Recurrence`, `NumericRecurrence`, and `Series` subclasses.

## Features

Expand All @@ -32,7 +32,7 @@ together with the specialized `NumericSequence`, `Recurrence`,
- Support for zero- and one-indexed sequences.
- Element access and slicing.
- Forward iteration over subsequences.
- `Sequence` transformations (`map`, `combine`, `shift_by`, `shift_to`).
- `Sequence` transformations (`head`, `tail`, `subsequence`, `map`, `combine`).
- Factory methods for constant sequences and sequences built from iterables.
- Fully type-annotated (`mypy --strict`).

Expand Down Expand Up @@ -162,7 +162,7 @@ print((-fib).head(8))
# initial guess of 2.0.
babylonian_sqrt2 = NumericRecurrence(
lambda n, a: 0.5 * (a[-1] + 2.0 / a[-1]),
basis=(2.0,)
basis=(2.0,),
)

print(babylonian_sqrt2.head(5))
Expand Down Expand Up @@ -210,6 +210,7 @@ print(4 * leibniz[1000])
│ ├── DESIGN.md # Design principles and concepts
│ ├── DEVELOPMENT.md # Development guide
│ ├── NOTES.md # Design decisions and rationale
│ ├── NOTES-legacy.md # Legacy notes
│ ├── STYLE.md # Coding and documentation conventions
│ └── ZOO.md # List of ideas for sequence types
├── examples
Expand All @@ -235,7 +236,8 @@ print(4 * leibniz[1000])
├── LICENSE
├── README.md
├── TODO.md # Planned work
├── pytest.ini # sys.path config for test imports
├── pyproject.toml # Project configuration
├── pytest.ini # Pytest configuration for test imports
└── requirements-dev.txt # Development and CI dependencies
```

Expand All @@ -248,21 +250,7 @@ The project emphasizes:
- comprehensive documentation;
- thorough unit testing.

Before committing, run:

```text
mypy --strict calculus
pyflakes calculus
pycodestyle calculus
pydocstyle calculus
pytest
git diff --cached --check
pymarkdown scan -r . --respect-gitignore
python -m examples.constants_approximation
python -m examples.power_series
python -m examples.rademacher_sequence
python -m examples.integral_approximation
```
Before committing, run `scripts\verify.bat`.

## Dependencies

Expand All @@ -271,9 +259,7 @@ Calculus has no runtime dependencies beyond the Python standard library.
Development requires:

- `mypy` for static type checking
- `pyflakes` for static analysis
- `pycodestyle` for PEP 8 code style checking
- `pydocstyle` for PEP 257 docstring style checking
- `ruff` for static analysis, code style checking, and docstring style checking
- `pytest` for unit testing
- `pymarkdownlnt` for markdown linting

Expand All @@ -285,8 +271,7 @@ pip install -r requirements-dev.txt

## Documentation

- `ARCHITECTURE.md` records the class hierarchy and relationships between its
classes.
- `ARCHITECTURE.md` records the class hierarchy.
- `DESIGN.md` describes the design principles and conceptual model.
- `DEVELOPMENT.md` describes development workflows and conventions.
- `NOTES.md` records design decisions and implementation rationale.
Expand Down
26 changes: 17 additions & 9 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,24 @@

## Features

- Add a `sum()` utility method to NumericSequence, after careful design.
- Add a public `Sequence` method exposing a fresh copy of the evaluation rule
(via `_rule_factory()`), e.g. `rule() -> Rule[T]`.

- Support negative slice bounds (`start`/`stop`) for zero-indexed finite
sequences, mirroring Python's own list-slicing semantics. Currently only
single-element negative indexing (`seq[-1]`) is translated;
`_process_range()` treats slice bounds as literal index values.

- Add a `sum()` utility method to `NumericSequence`, after careful design.

- Add a `round()` utility method to `NumericSequence`, and replace direct
`round()` usage in sources and README examples, removing related mypy
ignores.

- Add an LRU cache to `Series._Rule`, replacing the initial single-slot cache,
to efficiently support out-of-order queries. See NOTES.md ("`Series` rule
caching: single-slot now, cache deferred") for the design choices and open
questions.
to efficiently support out-of-order queries. See NOTES-legacy.md ("`Series`
rule caching: single-slot now, cache deferred") for the design choices and
open questions.

## Improvements

Expand All @@ -19,9 +31,6 @@

## Environment

- Add a gitignored `.llm.md` project context document capturing stable working
conventions for future LLM sessions (see `attic/context/.llm.md`).

- Set up GitHub Issues for tracking bugs and planned work.

- Set up a virtual environment (`venv`) for development, to mirror CI's
Expand All @@ -30,5 +39,4 @@

- Consider converting example Python files into Jupyter notebooks for
narrative-driven docs. Would require new tooling (nbformat/Jupyter) and CI
changes (notebooks aren't covered by mypy/pyflakes/pytest the way .py files
are).
changes.
10 changes: 5 additions & 5 deletions calculus/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
"""The Calculus package."""

from .sequence import Sequence
from .boolean_sequence import BooleanSequence
from .numeric_recurrence import NumericRecurrence
from .numeric_sequence import NumericSequence
from .recurrence import Recurrence
from .numeric_recurrence import NumericRecurrence
from .sequence import Sequence
from .series import Series
from .boolean_sequence import BooleanSequence

__version__ = "0.6.0"

__all__ = [
"Sequence",
"BooleanSequence",
"NumericRecurrence",
"NumericSequence",
"Recurrence",
"NumericRecurrence",
"Sequence",
"Series",
]
25 changes: 15 additions & 10 deletions calculus/boolean_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
__author__ = "Avi Kaplan"

from collections.abc import Callable, Iterable
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Self

from .sequence import INFINITY, Intfinity, Rule, Sequence
from .sequence import INFINITY, Intfinity, Sequence

if TYPE_CHECKING:
from .numeric_sequence import NumericSequence
Expand All @@ -23,7 +23,6 @@
# Boolean Sequence {bₙ}
# ======================================================================


class BooleanSequence(Sequence[bool]):
"""A class representing infinite Boolean sequences.

Expand All @@ -48,14 +47,20 @@ class BooleanSequence(Sequence[bool]):

# -- FACTORY

def _factory(
def _factory(self, size: Intfinity = INFINITY) -> Self:
# Produce a new sequence of the same type and rule.

rule = self._rule_factory()
return type(self)(rule, size=size, first_index=self.first_index)

def _reindex_factory(
self,
rule: Rule[bool],
size: Intfinity,
reindex: bool,
) -> Sequence[bool]:
# Produce a new sequence from rule and size, considering mode.
subrule: Callable[[int], int],
size: Intfinity = INFINITY,
) -> BooleanSequence:
# Produce a new reindexed sequence of the same type.

rule = self._reindex_rule_factory(subrule)
return BooleanSequence(rule, size=size, first_index=self.first_index)

# -- UTILITY
Expand All @@ -74,7 +79,7 @@ def numeric_rule(n: int) -> Real:
return int(boolean_rule(n))

return NumericSequence(
numeric_rule, size=self.size, first_index=self.first_index
numeric_rule, size=self.size, first_index=self.first_index,
)

# -- LOGICAL HELPERS
Expand Down
24 changes: 10 additions & 14 deletions calculus/numeric_recurrence.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@
__all__ = ["NumericRecurrence"]
__author__ = "Avi Kaplan"

from .sequence import Intfinity, Rule
from typing import Self

from .numeric_sequence import NumericSequence, Real
from .recurrence import Recurrence
from .sequence import INFINITY, Intfinity, Rule

# ======================================================================
# Numeric Recurrence {aₙ}
# ======================================================================


class NumericRecurrence(Recurrence[Real], NumericSequence):
class NumericRecurrence(NumericSequence, Recurrence[Real]):
"""A class representing infinite numeric recurrences.

This subclass inherits all functionality from NumericSequence and
Expand Down Expand Up @@ -50,17 +51,12 @@ def _rule_factory(self) -> Rule[Real]:

return Recurrence._rule_factory(self)

def _factory(
self,
rule: Rule[Real],
size: Intfinity,
reindex: bool,
) -> NumericRecurrence | NumericSequence:
# Produce a new sequence from rule and size, considering mode.

if reindex:
return NumericSequence._factory(self, rule, size, reindex)
return NumericRecurrence(self._func, self._basis, size=size)
def _factory(self, size: Intfinity = INFINITY) -> Self:
# Produce a new sequence of the same type and rule.

return type(self)(
self._func, self._basis, size=size, first_index=self._first_index,
)

# -- SPECIAL NUMERIC RECURRENCES

Expand Down
Loading