Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.11.6 #21

Merged
merged 4 commits into from
Mar 13, 2024
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
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def linkcode_resolve(domain, info):
html_sidebars = {
"sources/getting-started": [],
"sources/creating-continued-fractions": [],
"sources/properties-of-continued-fractions": [],
"sources/exploring-continued-fractions": [],
"sources/mediants": [],
"sources/contributing": [],
"sources/continuedfractions/*": ["sidebar-nav-bs"],
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Prelude

sources/getting-started
sources/creating-continued-fractions
sources/properties-of-continued-fractions
sources/exploring-continued-fractions
sources/mediants
sources/contributing
sources/api-reference
Expand Down
2 changes: 1 addition & 1 deletion docs/sources/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ The CI/CD pipelines are defined in the `CI YML <.github/workflows/ci.yml>`_, and
Versioning and Releases
=======================

The package is currently at version ``0.11.5`` - `semantic versioning <https://semver.org/>`_ is used.
The package is currently at version ``0.11.6`` - `semantic versioning <https://semver.org/>`_ is used.

There is currently no dedicated pipeline for releases - both `GitHub releases <https://github.com/sr-murthy/continuedfractions/releases>`_ and `PyPI packages <https://pypi.org/project/continuedfractions>`_ are published manually, but both have the same version tag.

Expand Down
114 changes: 80 additions & 34 deletions docs/sources/creating-continued-fractions.rst

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
=================================
Properties of Continued Fractions
=================================
=============================
Exploring Continued Fractions
=============================

Python objects of the ``continuedfraction.ContinuedFraction`` class encapsluate a number of basic and interesting properties of continued fractions.
Python objects of the :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` class encapsluate a number of basic and interesting properties of continued fractions that can be easily explored.

.. _properties-of-continued-fractions.elements-and-orders:
.. _exploring-continued-fractions.elements-and-orders:

Elements and Orders
===================

The **elements** (or coefficients) of a (possibly infinite) continued fraction :math:`[a_0;a_1,a_2\cdots]` of a real number :math:`x` include the leading element :math:`a_0 = \lfloor x \rfloor` (the largest integer :math:`a` such that :math:`|a| \leq |x|`), and the whole numbers :math:`a_1,a_2,\cdots` in the denominators of the fractional terms. For ``ContinuedFraction`` objects the ``.elements`` property can be used to look at their elements, e.g. for ``ContinuedFraction(649, 200)`` we have:
The **elements** (or coefficients) of a (possibly infinite) continued fraction :math:`[a_0;a_1,a_2\cdots]` of a real number :math:`x` include the head :math:`a_0 = [x]`, which is the integer part of :math:`x`, and the tail elements :math:`a_1,a_2,\cdots` which occur in the denominators of the fractional terms. The :py:attr:`~continuedfractions.continuedfraction.ContinuedFraction.elements` property can be used to look at their elements, e.g. for ``ContinuedFraction(649, 200)`` we have:

.. code:: python

Expand All @@ -24,15 +24,15 @@ The **order** of a continued fraction is defined to be number of its elements **
>>> cf.order
3

All ``ContinuedFraction`` objects will have a finite sequence of elements and thus a finite order, even if mathematically the numbers they represent may be irrational. The integers represent the special case of zero-order continued fractions.
All :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` objects will have a finite sequence of elements and thus a finite order, even if mathematically the numbers they represent may be irrational. The integers represent the special case of zero-order continued fractions.

.. code:: python

>> ContinuedFraction(3).order
0

The elements and orders of ``ContinuedFraction`` objects are well behaved with respect to all rational operations supported by
``fractions.Fraction``:
The elements and orders of :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` objects are well behaved with respect to all rational operations supported by
:py:class:`fractions.Fraction`:

.. code:: python

Expand All @@ -45,7 +45,7 @@ The elements and orders of ``ContinuedFraction`` objects are well behaved with r
>>> (ContinuedFraction(649, 200) + ContinuedFraction(415, 93)).order
10

.. _properties-of-continued-fractions.convergents-and-rational-approximations:
.. _exploring-continued-fractions.convergents-and-rational-approximations:

Convergents and Rational Approximations
=======================================
Expand All @@ -66,8 +66,8 @@ Each convergent :math:`C_k` represents a **rational approximation** :math:`\frac

This is equivalent to the limit :math:`\lim_{k \to \infty} \epsilon_k = 0`: if :math:`x` is rational the error term will vanish for some :math:`k >= 0` at which point the convergent :math:`C_k = x`. But if :math:`x` is irrational there will be infinitely many convergents, and their sequence may alternate about :math:`x`, but still converge to it.

The ``ContinuedFraction`` class provides a ``.convergents`` property for objects, which returns an immutable map
(`types.MappingProxyType <https://docs.python.org/3/library/types.html#types.MappingProxyType>`_) of all :math:`k`-order convergents, indexed (keyed) by integers :math:`k=0,1,\ldots,n`, where :math:`n` is the order of the continued fraction.
The :py:attr:`~continuedfractions.continuedfraction.ContinuedFraction.convergents` property for objects stores the convergents as an immutable map
(:py:class:`types.MappingProxyType`) of all :math:`k`-order convergents, indexed (keyed) by integers :math:`k=0,1,\ldots,n`, where :math:`n` is the order of the continued fraction.

.. code:: python

Expand All @@ -92,7 +92,7 @@ Using the continued fraction representation :math:`[3; 4, 12, 4]` of :math:`\fra
& C_3 &&= [3; 4, 12, 4] = 3 + \cfrac{1}{4 + \cfrac{1}{12 + \cfrac{1}{4}}} = \frac{649}{200} = 3.245
\end{alignat*}

Obviously, we can only handle finite continued fractions in Python, so the convergents produced by ``ContinuedFraction`` will always be finite in number, regardless of whether the real numbers they approximate are rational or irrational. We can verify the convergents for ``ContinuedFraction(math.pi)`` approach ``math.pi``:
Obviously, we can only handle finite continued fractions in Python, so the convergents produced by :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` will always be finite in number, regardless of whether the real numbers they approximate are rational or irrational. We can verify the convergents for ``ContinuedFraction(math.pi)`` approach ``math.pi``:

.. code:: python

Expand All @@ -102,31 +102,31 @@ Obviously, we can only handle finite continued fractions in Python, so the conve
>>> assert pytest.approx(pi_cf.convergents[27], abs=1e-28) == math.pi
# True

**Note**: As the convergents are constructed during ``ContinuedFraction`` object initialisation, the objects that represent them cannot be of type ``ContinuedFraction``, due to recursion errors. Thus, it was decided to keep them as ``fractions.Fraction`` objects.
**Note**: As the convergents are constructed during :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` object initialisation, the objects that represent them cannot be of type :py:class:`~continuedfractions.continuedfraction.ContinuedFraction`, due to recursion errors. Thus, it was decided to keep them as :py:class:`fractions.Fraction` objects. This is also sufficient for the purposes of approximation. To use convergents as :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` objects use the :py:meth:`~continuedfractions.continuedfraction.ContinuedFraction.segment` method, which is discussed next.

.. _properties-of-continued-fractions.segments-and-remainders:
.. _exploring-continued-fractions.segments-and-remainders:

Segments and Remainders
=======================

Convergents are linked to the concept of **segments**, which are finite subsequences of elements of a given continued fraction. More precisely, we can define the :math:`k`-th segment :math:`S_k` of a continued fraction :math:`[a_0; a_1,\ldots]` as the sequence :math:`(a_0,a_1,\ldots,a_k)` of its first :math:`k + 1` elements, which uniquely determines the :math:`k`-order (simple) convergent :math:`C_k` of the continued fraction, as defined above.

The segments of ``ContinuedFraction`` objects can be obtained via the ``.segment()`` method, which takes a non-negative integer not exceeding the order.
The segments of :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` objects can be obtained via the :py:meth:`~continuedfractions.continuedfraction.ContinuedFraction.segment` method, which takes a non-negative integer not exceeding the order.

.. code:: python

>>> cf.segment(0), cf.segment(1), cf.segment(2), cf.segment(3)
(ContinuedFraction(3, 1), ContinuedFraction(13, 4), ContinuedFraction(159, 49), ContinuedFraction(649, 200))3

**Note**: Unlike the :math:`k`-order convergents the segments are ``ContinuedFraction`` objects.
**Note**: Unlike the :math:`k`-order convergents the segments are :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` objects, and can be used as a proxy for the convergents.

A related concept is that of **remainders** of continued fractions, which are (possibly infinite) subsequences of elements of a given continued fraction, starting from a given element, usually the leading element :math:`a_0`. More precisely, we can define the :math:`k`-th remainder :math:`R_k` of a continued fraction :math:`[a_0; a_1,\ldots]` as the continued fraction :math:`[a_k;a_{k + 1},\ldots]`, obtained by "removing" the elements of the :math:`(k - 1)`-st segment :math:`S_{k - 1} = (a_0,a_1,\ldots,a_{k - 1})` from :math:`[a_0; a_1,\ldots]`.

.. math::

R_k = a_k + \cfrac{1}{a_{k + 1} + \cfrac{1}{a_{k + 2} \ddots }}

The remainders of ``ContinuedFraction`` objects can be obtained via the ``.remainder()`` method, which takes a non-negative integer not exceeding the order.
The remainders of :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` objects can be obtained via the :py:meth:`~continuedfractions.continuedfraction.ContinuedFraction.remainder` method, which takes a non-negative integer not exceeding the order.

.. code:: python

Expand All @@ -145,11 +145,11 @@ Using the continued fraction representation of :math:`\frac{649}{200}` we can ve
& R_3 &&= [4;] = 4 = \frac{4}{1}
\end{alignat*}

Given a (possibly infinite) continued fraction :math:`[a_0; a_1, a_2,\ldots]` the remainders :math:`R_1,R_2,\ldots` satisfy the following relation, for integers :math:`k > 0`:
Given a (possibly infinite) continued fraction :math:`[a_0; a_1, a_2,\ldots]` the remainders :math:`R_1,R_2,\ldots` satisfy the following relation:

.. math::

R_k = \frac{1}{R_{k - 1} - a_{k - 1}}
R_k = \frac{1}{R_{k - 1} - a_{k - 1}}, \hskip{1em} k \geq 1


Khinchin Means & Khinchin's Constant
Expand All @@ -161,15 +161,15 @@ For a (possibly infinite) continued fraction :math:`[a_0; a_1, a_2,\ldots]` and

K_n := \sqrt[n]{a_1a_2 \cdots a_n} = \left( a_1a_2 \cdots a_n \right)^{\frac{1}{n}}, \hskip{1em} n \geq 1

So :math:`K_n` is simply the geometric mean of the sequence :math:`(a_1, a_2,\ldots,a_n)` for :math:`n \geq 1`.
So :math:`K_n` is simply the geometric mean of the integers :math:`a_1, a_2,\ldots,a_n`, for :math:`n \geq 1`.

It has been proved that for irrational numbers, which have infinite continued fraction representations, there are infinitely many for which the quantity :math:`K_n` approaches a constant :math:`K_0 \approx 2.685452\ldots`, called `Khinchin's constant <https://en.wikipedia.org/wiki/Khinchin%27s_constant>`_, independent of the number. So:

.. math::

\lim_{n \to \infty} K_n = \lim_{n \to \infty} \sqrt[n]{a_1a_2 \cdots a_n} = K_0 \approx 2.685452\ldots

The ``ContinuedFraction`` class provides a way of examining the behaviour of :math:`K_n` via the ``.khinchin_mean`` property, as indicated in the examples below.
The :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` class provides a way of examining the behaviour of :math:`K_n` via the :py:attr:`~continuedfractions.continuedfraction.ContinuedFraction.khinchin_mean` property, as indicated in the examples below.

.. code:: python

Expand Down Expand Up @@ -221,7 +221,7 @@ The constant :math:`\gamma`, which has not been proved to be irrational, is defi

where :math:`H_n = \sum_{k=1}^n \frac1{k} = 1 + \frac{1}{2} + \frac{1}{3} + \cdots \frac{1}{n}` is the :math:`n`-th harmonic number.

.. _properties-of-continued-fractions.references:
.. _exploring-continued-fractions.references:

References
==========
Expand All @@ -247,7 +247,3 @@ https://plus.maths.org/content/chaos-numberland-secret-life-continued-fractionsU
[9] Wikipedia. "Euler's constant". https://en.wikipedia.org/wiki/Euler%27s_constant. Accessed 11 March 2024.

[10] Wikipedia. "Khinchin's constant". https://en.wikipedia.org/wiki/Khinchin%27s_constant. Accessed 11 March 2024.

[11] Wikipedia. “Mediant (mathematics)”. https://en.wikipedia.org/wiki/Mediant_(mathematics). Accessed 23 February 2024.

[12] Wikipedia. “Stern-Brocot Tree”. https://en.wikipedia.org/wiki/Stern%E2%80%93Brocot_tree. Accessed 23 February 2024.
16 changes: 8 additions & 8 deletions docs/sources/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ For contributors there are development requirements which are specified in the `

The ``continuedfractions`` package consists of two core libraries.

- `continuedfractions.lib <https://github.com/sr-murthy/continuedfractions/blob/main/src/continuedfractions/lib.py>`_
- `continuedfractions.continuedfraction <https://github.com/sr-murthy/continuedfractions/blob/main/src/continuedfractions/continuedfraction.py>`_
- :py:mod:`continuedfractions.lib`
- :py:mod:`continuedfractions.continuedfraction`

.. _getting-started.package-structure:

Expand All @@ -32,16 +32,16 @@ Package Structure
``continuedfractions.lib``
++++++++++++++++++++++++++

This is a `library <https://github.com/sr-murthy/continuedfractions/blob/main/src/continuedfractions/lib.py>`_ of standalone functions, which are summarised below.
This is a library of standalone functions, which are summarised below.

- ``continued_fraction_rational`` - generates the (ordered) sequence of elements (coefficients) of a finite, simple continued fraction representation of a given rational number, given as a ``fractions.Fraction`` object. The representation will be unique if the given number is a rational number with an exact binary fractional representation, otherwise it will be approximate.
- ``continued_fraction_real`` - generates the sequence of elements of a finite, simple, continued fraction representation of a real number, given as a single ``int``, ``float``, ``fractions.Fraction``, ``decimal.Decimal`` object, or a pair of ``ints`` and/or ``fractions.Fraction`` objects representing the numerator and non-zero denominator, respectively, of the number. The resulting continued fraction representation will be exact for any rational number and which has an exact representation as a binary fraction, otherwise, it will only be approximate. The latter limitation will be addressed in future versions.
- ``convergent`` - returns the ``k``-th convergent (for a positive integer `k`) of a continued fraction representation of a number, from a sequence of its elements; the convergent is returned as a``fractions.Fraction`` object
- ``mediant`` - returns the ``k``-th left or right mediant of two rational numbers, given as ``fractions.Fraction`` objects
- :py:meth:`~continuedfractions.lib.continued_fraction_rational` - generates the (ordered) sequence of elements (coefficients) of a finite, simple continued fraction representation of a given rational number, given as a :py:class:`fractions.Fraction` object. The representation will be unique if the given number is a rational number with an exact binary fractional representation, otherwise it will be approximate.
- :py:meth:`~continuedfractions.lib.continued_fraction_real` - generates the sequence of elements of a finite, simple, continued fraction representation of a real number, given as a single :py:class:`int`, :py:class:`float`, :py:class:`fractions.Fraction`, :py:class:`decimal.Decimal` object, or a pair of integers and/or :py:class:`fractions.Fraction` objects representing the numerator and non-zero denominator, respectively, of the number. The resulting continued fraction representation will be exact for any rational number and which has an exact representation as a binary fraction, otherwise, it will only be approximate. The latter limitation will be addressed in future versions.
- :py:meth:`~continuedfractions.lib.convergent` - returns the ``k``-th convergent (for a positive integer :math:`k`) of a (finite) simple continued fraction representation of a number, from a sequence of its elements; the convergent is returned as a :py:class:`fractions.Fraction` object
- :py:meth:`~continuedfractions.lib.mediant` - returns the ``k``-th left or right mediant of two rational numbers, given as :py:class:`fractions.Fraction` objects

.. _getting-started.package-structure.continuedfractions_continuedfraction:

``continuedfractions.continuedfraction``
++++++++++++++++++++++++++++++++++++++++

This is a `library <https://github.com/sr-murthy/continuedfractions/blob/main/src/continuedfractions/continuedfraction.py>`_ containing a single main class, ``ContinuedFraction``, which subclasses ``fractions.Fraction``, and is designed to represented continued fractions as Python objects which are fully operable as rational numbers.
This is a library containing a single main class, :py:class:`~continuedfractions.continuedfraction.ContinuedFraction`, which is a subclass of :py:class:`fractions.Fraction`, and is designed to represented continued fractions as Python objects which are fully operable as rational numbers.
6 changes: 3 additions & 3 deletions docs/sources/mediants.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Another feature which the package includes is `mediants <https://en.wikipedia.or
Mediants and their Properties
-----------------------------

The (simple) **mediant** of two rational numbers :math:`\frac{a}{b}` and :math:`\frac{c}{d}`, where :math:`b, d \neq 0`, is defined as the rational number:
The (simple) **mediant** of two rational numbers :math:`\frac{a}{b}` and :math:`\frac{c}{d}`, where :math:`b, d, b + d \neq 0`, is defined as the rational number:

.. math::

Expand All @@ -23,7 +23,7 @@ Assuming that :math:`\frac{a}{b} < \frac{c}{d}` and :math:`bd > 0` the mediant a

Mediants can give good rational approximations to real numbers of interest.

The ``ContinuedFraction`` class provides a ``.mediant()`` method which can be used to calculate mediants with other ``ContinuedFraction`` or ``fractions.Fraction`` objects. The result is also a ``ContinuedFraction`` object. A few examples are given below of how to calculate mediants.
The :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` class provides a :py:meth:`~continuedfractions.continuedfraction.ContinuedFraction.mediant` method which can be used to calculate mediants with other :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` or :py:class:`fractions.Fraction` objects. The result is also a :py:class:`~continuedfractions.continuedfraction.ContinuedFraction` object. A few examples are given below of how to calculate mediants.

.. code:: python

Expand Down Expand Up @@ -78,7 +78,7 @@ while the right-mediants form a strictly increasing sequence upper-bounded by :m

\lim_{k \to \infty} \frac{a + kc}{b + kd} = \lim_{k \to \infty} \frac{\frac{a}{k} + c}{\frac{b}{k} + d} = \frac{c}{d}

We can illustrate this using the ``ContinuedFraction.mediant`` method using the ``dir`` option to set the “direction” of the mediant, starting with the right mediants, which don't need to specified with ``dir='right'`` as that is the default value, and using ``k`` to set the mediant order, which defaults to ``k=1``.
We can illustrate this using the :py:meth:`~continuedfractions.continuedfraction.ContinuedFraction.mediant` method using the ``dir`` option to set the “direction” of the mediant, starting with the right mediants, which don't need to specified with ``dir='right'`` as that is the default value, and using ``k`` to set the mediant order, which defaults to ``k=1``.

.. code:: python

Expand Down
Loading
Loading