Skip to content

Commit

Permalink
Solve p85 in python (86th solved!); minor docs changes
Browse files Browse the repository at this point in the history
  • Loading branch information
LivInTheLookingGlass committed Oct 21, 2024
1 parent 0e4e2be commit fdf358b
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Olivia's Project Euler Solutions
| | | | |Lu-Cov| |br| |
| | | | |LuaCheck| |
+------------+----------------------------+--------+-------------------+
| Python | CPython 3.6+ |br| | 85 | |Python| |br| |
| Python | CPython 3.6+ |br| | 86 | |Python| |br| |
| | Pypy 3.6+ |br| | | |Py-Cov| |br| |
| | GraalPy 23.1+ |br| | | |CodeQL| |br| |
| | Browser [#]_ | | |PythonLint| |
Expand Down
1 change: 1 addition & 0 deletions _data/answers.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ ID type size answer
77 int 8 71
79 int 32 73162890
81 int 32 427337
85 int 16 2772
87 int 32 1097343
89 int 16 743
92 int 32 8581146
Expand Down
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ Problems Solved
+-----------+-----------+------------+------------+------------+------------+------------+------------+------------+------------+
|:prob:`081`| | | | | | | |:py-d:`0081`| |
+-----------+-----------+------------+------------+------------+------------+------------+------------+------------+------------+
|:prob:`085`| | | | | | | |:py-d:`0085`| |
+-----------+-----------+------------+------------+------------+------------+------------+------------+------------+------------+
|:prob:`087`| | | | | | | |:py-d:`0087`| |
+-----------+-----------+------------+------------+------------+------------+------------+------------+------------+------------+
|:prob:`089`| | | | | | | |:py-d:`0089`| |
Expand Down
23 changes: 23 additions & 0 deletions docs/src/python/p0085.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Python Implementation of Problem 85
===================================

View source code :source:`python/src/p0085.py`

Includes
--------

- :external:py:func:`math.ceil`
- :external:py:func:`math.sqrt`

Problem Solution
----------------

.. automodule:: python.src.p0085
:members:
:undoc-members:

.. literalinclude:: ../../../python/src/p0085.py
:language: python
:linenos:

.. tags:: geometry, packing, combinatorics
1 change: 1 addition & 0 deletions python/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ Problems Solved
- ☒ `77 <./src/p0077.py>`__
- ☒ `79 <./src/p0079.py>`__
- ☒ `81 <./src/p0081.py>`__
- ☒ `85 <./src/p0085.py>`__
- ☒ `87 <./src/p0087.py>`__
- ☒ `89 <./src/p0089.py>`__
- ☒ `92 <./src/p0092.py>`__
Expand Down
14 changes: 11 additions & 3 deletions python/src/lib/primes.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ def modified_eratosthenes() -> Iterator[int]:
def prime_factors(num: int) -> Iterator[int]:
"""Iterates over the prime factors of a number.
.. note::
For the purposes of this function, :math:`-1` is included as a factor for negative numbers, and :math:`0` is
yielded as a special case. In general, prime factors are strictly positive integers greater than 1.
It takes :math:`O(m \\cdot \\log(m)^{1.585} \\cdot \\log(\\log(m)))` time to generate the needed primes, where
:math:`m = \\sqrt{n}`, so :math:`O(\\sqrt{n} \\cdot \\log(\\sqrt{n})^{1.585} \\cdot \\log(\\log(\\sqrt{n})))`,
which simplifies to :math:`O(\\sqrt{n} \\cdot \\log(n)^{1.585} \\cdot \\log(\\log(n)))` operations."""
Expand Down Expand Up @@ -115,7 +120,7 @@ def is_prime(
:math:`O(\\log(n)^{1.585} \\cdot \\log(\\log(n)))`. If count is :math:`c` and ``distinct=False``, it runs in
:math:`O(c \\cdot \\log(n)^{1.585} \\cdot \\log(\\log(n)))`. Otherwise, it runs in
:math:`O(\\sqrt{n} \\cdot \\log(n)^{1.585} \\cdot \\log(\\log(n)))` time."""
if num in (0, 1):
if num < 2:
return False
factors = iter(prime_factors(num))
if count == 1:
Expand Down Expand Up @@ -145,7 +150,7 @@ def primes_and_negatives(*args: int) -> Iterator[int]:


def fast_totient(n: int, factors: Optional[Iterable[int]] = None) -> int:
"""A shortcut method to calculate Euler's totient function which assumes n has *distinct* prime factors.
"""A faster method to calculate Euler's totient function when n has *distinct* prime factors.
It runs exactly 1 multiplication and 1 subtraction per prime factor, giving a worst case of
:math:`O(\\sqrt{n} \\cdot \\log(n)^{3.17} \\cdot \\log(\\log(n)))`."""
Expand All @@ -159,12 +164,15 @@ def _reduce_factors(x: Fraction, y: int) -> Fraction:
def totient(n: int) -> int:
"""Calculates Euler's totient function in the general case.
This function computes the number of integers less than n that are coprime to n. It handles the general case,
including repeated prime factors.
Takes :math:`O(\\log(n))` fraction multiplications, each of which is dominated by two GCDs, which run at
:math:`O(\\log(\\min(a, b))^2)`. Given that the max factor is :math:`\\sqrt{n}`, we can simplify this to a worst
case of :math:`O(\\log(n) \\cdot \\log(\\sqrt{n}))^2 = O(\\log(n) \\cdot \\tfrac{1}{2} \\log(n)^2) = O(\\log(n)^3)`.
Computing the prime factors themselves takes :math:`O(\\sqrt{n} \\cdot \\log(n)^{1.585} \\cdot \\log(\\log(n)))`
when the cache is not initialized, but on all future runs will take :math:`O(\\log(n))` time.
when the global prime cache is not initialized, but on all future runs will take :math:`O(\\log(n))` time.
This combines to give us :math:`O(\\sqrt{n} \\cdot \\log(n)^{4.585} \\cdot \\log(\\log(n)))` time when the cache is
stale, and :math:`O(\\log(n)^4)` time on future runs."""
Expand Down
14 changes: 11 additions & 3 deletions python/src/p0081.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
"""
Project Euler Template
Project Euler Problem 81
In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by only moving to the right and
down, is indicated in bold red and is equal to 2427.
<uncopyable>
.. math::
\\begin{pmatrix}
\\color{red}{131} & 673 & 234 & 103 & 18\\\\
\\color{red}{201} & \\color{red}{96} & \\color{red}{342} & 965 & 150\\\\
630 & 803 & \\color{red}{746} & \\color{red}{422} & 111\\\\
537 & 699 & 497 & \\color{red}{121} & 956\\\\
805 & 732 & 524 & \\color{red}{37} & \\color{red}{331}
\\end{pmatrix}
Find the minimal path sum from the top left to the bottom right by only moving right and down in matrix.txt (right
click and "Save Link/Target As..."), a 31K text file containing an 80 by 80 matrix.
Expand Down Expand Up @@ -36,6 +44,6 @@ def min_path_sum(
def main() -> int:
setup: List[Sequence[int]] = []
for raw_line in get_data_file('p0081_matrix.txt').splitlines():
line = raw_line.rstrip('\n')
line = raw_line.rstrip('\\n')
setup.append(tuple(int(x) for x in line.split(',')))
return min_path_sum(tuple(setup), {})
28 changes: 28 additions & 0 deletions python/src/p0085.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Project Euler Problem 85
Problem:
By counting carefully it can be seen that a rectangular grid measuring 3 by 2 contains eighteen rectangles:
.. image:: https://projecteuler.net/resources/images/0085.png
Although there exists no rectangular grid that contains exactly two million rectangles, find the area of the grid with the nearest solution.
"""
from math import ceil, sqrt


def num_rectangles(x: int, y: int) -> int:
answer = 0
for a in range(1, x + 1):
for b in range(1, y + 1):
answer += (x - a + 1) * (y - b + 1)
return answer


def main(tolerance: int = 2) -> int:
for x in range(1, ceil(sqrt(2000000))):
for y in range(1, x):
if abs(num_rectangles(x, y) - 2000000) <= tolerance:
return x * y
return -1
1 change: 1 addition & 0 deletions python/test_euler.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
*range(76, 78),
79,
81,
85,
87,
89,
92,
Expand Down

0 comments on commit fdf358b

Please sign in to comment.