Issues (956)

solutions/problem23.py (19 issues)

1
"""
2
Project Euler Problem 23: Non-Abundant Sums
3
===========================================
4
5
.. module:: solutions.problem23
6
   :synopsis: My solution to problem #23.
7
8
The source code for this problem can be
9
`found here <https://bitbucket.org/nekedome/project-euler/src/master/solutions/problem23.py>`_.
10
11
Problem Statement
12
#################
13
14
A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the
0 ignored issues
show
This line is too long as per the coding-style (118/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
15
sum of the proper divisors of :math:`28` would be :math:`1 + 2 + 4 + 7 + 14 = 28`, which means that :math:`28` is a
0 ignored issues
show
This line is too long as per the coding-style (115/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
16
perfect number.
17
18
A number :math:`n` is called deficient if the sum of its proper divisors is less than :math:`n` and it is called
0 ignored issues
show
This line is too long as per the coding-style (112/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
19
abundant if this sum exceeds :math:`n`.
20
21
As :math:`12` is the smallest abundant number, :math:`1 + 2 + 3 + 4 + 6 = 16`, the smallest number that can be written
0 ignored issues
show
This line is too long as per the coding-style (118/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
22
as the sum of two abundant numbers is :math:`24`. By mathematical analysis, it can be shown that all integers greater
0 ignored issues
show
This line is too long as per the coding-style (117/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
23
than :math:`28123` can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any
0 ignored issues
show
This line is too long as per the coding-style (117/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
24
further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant
0 ignored issues
show
This line is too long as per the coding-style (120/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
25
numbers is less than this limit.
26
27
Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.
0 ignored issues
show
This line is too long as per the coding-style (101/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
28
29
Solution Discussion
30
###################
31
32
The solution can be found with the following algorithm:
33
34
1. Identify all abundant numbers
35
2. Iterate over all integers in :math:`[2, 28123]` and determine if it is a sum of two abundant numbers, accumulate the
0 ignored issues
show
This line is too long as per the coding-style (119/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
36
   sum of all integers that cannot be expressed as such a sum
37
38
Both steps can be optimised with the following approaches.
39
40
First, build a divisor sum sieve which can be enumerated to determine abundant numbers (i.e. :math:`n` s.t.
0 ignored issues
show
This line is too long as per the coding-style (107/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
41
:math:`s(n) \\gt n` where :math:`s(n)` is the sum of the proper divisors of :math:`n`).
42
43
.. note:: the use of a divisor sieve will be much quicker than identifying the divisors of each individual :math:`n`.
0 ignored issues
show
This line is too long as per the coding-style (117/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
44
45
Then, iterate through :math:`[2, 28123]` and check whether there are two abundant numbers that can sum to the current
0 ignored issues
show
This line is too long as per the coding-style (117/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
46
candidate.
47
48
* Let :math:`n` be the current candidate
49
* Let :math:`a_i` be the :math:`i^{th}` abundant number in :math:`[2, 28123]`
50
* For all :math:`a_i`, check whether there exists an :math:`a_j` s.t. :math:`a_i + a_j = n`
51
* If no :math:`a_i, a_j` exist, accumulate :math:`n` into the final answer
52
53
Importantly, by ordering :math:`\\lbrace a_i \\rbrace`, we don't need to check all :math:`a_j` at each step of this
0 ignored issues
show
This line is too long as per the coding-style (115/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
54
algorithm.
55
56
.. math::
57
58
    a_i + a_j &= n \\\\
59
    \\Rightarrow n - a_i &= a_j
60
61
Therefore, we only need to check :math:`a_i \\lt n` (otherwise :math:`n - a_i` would be negative) and since :math:`a_i`
0 ignored issues
show
This line is too long as per the coding-style (119/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
62
is positive, we only need to check :math:`0 \\lt a_j \\lt n`. This means, that we may consider the subset of
0 ignored issues
show
This line is too long as per the coding-style (108/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
63
:math:`\\lbrace a_k \\rbrace` s.t. :math:`a_k \\le n` for each candidate :math:`n`.
64
65
Solution Implementation
66
#######################
67
68
.. literalinclude:: ../../solutions/problem23.py
69
   :language: python
70
   :lines: 73-
71
"""
72
73
from lib.numbertheory import divisors_sieve
74
75
76
def solve():
77
    """ Compute the answer to Project Euler's problem #23 """
78
79
    upper_bound = 28123
80
81
    # Step1: Sieve the sum of proper divisors in [2, upper_bound]
82
    sum_divisors = list(divisors_sieve(upper_bound + 1, proper=True, aggregate="sum"))
83
84
    # Step2: Identify integers not expressible as the sum of two abundant numbers, accumulate their sum
0 ignored issues
show
This line is too long as per the coding-style (103/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
85
    abundant_subspace = set()  # will contain only those a_i that need be considered for each n
86
    answer = 0
87
    for n in range(1, upper_bound + 1):
0 ignored issues
show
Coding Style Naming introduced by
The name n does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
88
        if sum_divisors[n - 1] > n:
89
            abundant_subspace.add(n)
90
        if not any((n - a in abundant_subspace) for a in abundant_subspace):
91
            # The any operator provides lazy evaluation, terminating on the first satisfied condition
0 ignored issues
show
This line is too long as per the coding-style (101/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
92
            answer += n  # accumulate sum
93
94
    return answer
95
96
97
expected_answer = 4179871
0 ignored issues
show
Coding Style Naming introduced by
The name expected_answer does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
98