Algorithms
==========

This page provides detailed documentation for all the mathematical algorithms
implemented in the Lychrel package.

Fibonacci Sequences
-------------------

Generalized Fibonacci Sequences (Lucas Sequences)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Fibonacci sequence is one of the most famous sequences in mathematics.
The Lychrel package implements a **generalized** version called Lucas sequences.

Mathematical Definition
^^^^^^^^^^^^^^^^^^^^^^^

A generalized Fibonacci sequence is defined by the recurrence relation:

.. math::

   F(n) = p \cdot F(n-1) - q \cdot F(n-2)

where :math:`p` and :math:`q` are integer parameters, with initial conditions:

.. math::

   F(0) = 0, \quad F(1) = 1

Special Cases
^^^^^^^^^^^^^

By choosing different values of :math:`p` and :math:`q`, we get different famous sequences:

* **Standard Fibonacci** (:math:`p=1, q=-1`): :math:`F(n) = F(n-1) + F(n-2)`

  Sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...

* **Lucas Numbers** (:math:`p=1, q=-1`, with :math:`F(0)=2, F(1)=1`):

  Sequence: 2, 1, 3, 4, 7, 11, 18, 29, 47, 76, 123...

* **Pell Numbers** (:math:`p=2, q=-1`): :math:`F(n) = 2F(n-1) + F(n-2)`

  Sequence: 0, 1, 2, 5, 12, 29, 70, 169, 408, 985, 2378...

* **Jacobsthal Numbers** (:math:`p=1, q=-2`): :math:`F(n) = F(n-1) + 2F(n-2)`

  Sequence: 0, 1, 1, 3, 5, 11, 21, 43, 85, 171, 341...

Function Reference
^^^^^^^^^^^^^^^^^^

.. autofunction:: lychrel.fibonacci

Examples
^^^^^^^^

.. code-block:: python

   import lychrel

   # Standard Fibonacci sequence
   print(lychrel.fibonacci(10))  # 55
   print(lychrel.fibonacci(20))  # 6765

   # Pell numbers (p=2, q=-1)
   print(lychrel.fibonacci(10, p=2, q=-1))  # 2378

   # Jacobsthal numbers (p=1, q=-2)
   print(lychrel.fibonacci(10, p=1, q=-2))  # 341

   # Custom parameters
   for i in range(10):
       print(lychrel.fibonacci(i, p=3, q=-2))

Performance Note
^^^^^^^^^^^^^^^^

The implementation uses an iterative algorithm with O(n) time complexity and O(1) space complexity.
Thanks to Rust's ``BigInt`` type, it can handle arbitrarily large Fibonacci numbers:

.. code-block:: python

   # Calculate very large Fibonacci numbers
   print(lychrel.fibonacci(1000))
   # Returns a number with 209 digits!

Kaprekar's Routine
------------------

Kaprekar's Constant
~~~~~~~~~~~~~~~~~~~

Kaprekar's routine is a mathematical algorithm discovered by Indian mathematician D. R. Kaprekar.
For 4-digit numbers in base 10, the routine always converges to **6174**, known as Kaprekar's constant.

The Algorithm
~~~~~~~~~~~~~

1. Take any 4-digit number with at least two different digits (e.g., 3524)
2. Arrange the digits in descending order: 5432
3. Arrange the digits in ascending order: 2345
4. Subtract the smaller from the larger: 5432 - 2345 = 3087
5. Repeat with the result

Example with 3524:

.. code-block:: text

   3524 → 5432 - 2345 = 3087
   3087 → 8730 - 0378 = 8352
   8352 → 8532 - 2358 = 6174
   6174 → 7641 - 1467 = 6174  (fixed point!)

Function Reference
~~~~~~~~~~~~~~~~~~

.. autofunction:: lychrel.kaprekar

Examples
~~~~~~~~

.. code-block:: python

   import lychrel

   # All 4-digit numbers converge to 6174
   print(lychrel.kaprekar(1234))  # 6174
   print(lychrel.kaprekar(9876))  # 6174
   print(lychrel.kaprekar(4680))  # 6174
   print(lychrel.kaprekar(3524))  # 6174

   # Works with different bases
   result = lychrel.kaprekar(1234, base=10)
   print(result)

   # Control maximum iterations
   result = lychrel.kaprekar(1234, max_iterations=100)

Other Kaprekar Constants
~~~~~~~~~~~~~~~~~~~~~~~~~

Different digit lengths have different Kaprekar constants:

* 3 digits: 495
* 4 digits: 6174
* 5 digits: Multiple cycles possible
* 6 digits: Multiple constants (549945, 631764)

Currently, the function works best with 4-digit numbers in base 10.

Read Out Loud
-------------

The Look-and-Say Sequence
~~~~~~~~~~~~~~~~~~~~~~~~~~

The "Read Out Loud" function implements the famous **Look-and-Say sequence**
(also called the Morris Number Sequence), discovered by mathematician John Conway.

How It Works
~~~~~~~~~~~~

The sequence is generated by "reading" the digits of the previous number,
counting consecutive occurrences of each digit:

.. code-block:: text

   1       →  "one 1"               → 11
   11      →  "two 1s"              → 21
   21      →  "one 2, one 1"        → 1211
   1211    →  "one 1, one 2, two 1s" → 111221
   111221  →  "three 1s, two 2s, one 1" → 312211

Function Reference
~~~~~~~~~~~~~~~~~~

.. autofunction:: lychrel.look_and_say

Examples
~~~~~~~~

.. code-block:: python

   import lychrel

   # Basic examples
   print(lychrel.look_and_say(1))        # 11
   print(lychrel.look_and_say(12))       # 1112
   print(lychrel.look_and_say(3211))     # 131221
   print(lychrel.look_and_say(2333355))  # 124325

   # Generate the Look-and-Say sequence
   n = 1
   for i in range(10):
       print(f"Step {i}: {n}")
       n = lychrel.look_and_say(n)

   # Output:
   # Step 0: 1
   # Step 1: 11
   # Step 2: 21
   # Step 3: 1211
   # Step 4: 111221
   # Step 5: 312211
   # Step 6: 13112221
   # Step 7: 1113213211
   # Step 8: 31131211131221
   # Step 9: 13211311123113112211

Interesting Properties
~~~~~~~~~~~~~~~~~~~~~~

* The sequence never contains digits greater than 3 (when starting from 1)
* The length of each term grows by approximately 30% each step
* The sequence is related to the **cosmological theorem** proved by John Conway
* No term in the sequence contains "333" when starting from 1

Collatz Conjecture
------------------

The 3n+1 Problem
~~~~~~~~~~~~~~~~

The Collatz conjecture is one of the most famous unsolved problems in mathematics.
It's also known as the 3n+1 problem, Ulam conjecture, or Hailstone sequence.

The Conjecture
~~~~~~~~~~~~~~

Starting with any positive integer :math:`n`:

* If :math:`n` is even: divide it by 2 (:math:`n → n/2`)
* If :math:`n` is odd: multiply by 3 and add 1 (:math:`n → 3n+1`)

**The conjecture states**: No matter what number you start with, you will always eventually reach 1.

Despite being tested for extremely large numbers (up to :math:`2^{68}`), no proof exists.

Function Reference
~~~~~~~~~~~~~~~~~~

.. autofunction:: lychrel.collatz

Examples
~~~~~~~~

.. code-block:: python

   import lychrel

   # Simple example
   sequence = lychrel.collatz(5)
   print(sequence)
   # [5, 16, 8, 4, 2, 1]

   # Longer sequence
   sequence = lychrel.collatz(27)
   print(len(sequence))  # 111 steps!
   print(sequence[:10])  # First 10 terms
   # [27, 82, 41, 124, 62, 31, 94, 47, 142, 71]

   # Visualize the sequence
   for i, n in enumerate(lychrel.collatz(10)):
       print(f"Step {i}: {n}")

   # Find stopping time (number of steps to reach 1)
   def stopping_time(n):
       return len(lychrel.collatz(n)) - 1

   # Find which number < 100 has the longest sequence
   max_len = 0
   max_n = 0
   for n in range(1, 100):
       length = stopping_time(n)
       if length > max_len:
           max_len = length
           max_n = n

   print(f"Number with longest sequence: {max_n}")
   print(f"Sequence length: {max_len}")
   # Number with longest sequence: 97
   # Sequence length: 118

Interesting Patterns
~~~~~~~~~~~~~~~~~~~~

* The number 27 takes 111 steps to reach 1
* The highest number reached starting from 27 is 9,232
* Some numbers quickly drop to 1, while others take long, chaotic paths
* The sequences often reach high peaks before eventually descending to 1

.. code-block:: python

   # Find the maximum value reached in the Collatz sequence
   def max_in_sequence(n):
       return max(lychrel.collatz(n))

   print(max_in_sequence(27))   # 9232
   print(max_in_sequence(97))   # 13120
   print(max_in_sequence(871))  # 190996

Current Research
~~~~~~~~~~~~~~~~

* No counterexample has been found despite extensive computational searches
* The problem has been verified for all numbers up to :math:`2^{68} ≈ 2.95 × 10^{20}`
* Many partial results exist, but a complete proof remains elusive
* The problem is easy to state but remarkably difficult to solve
