Passed
Push — master ( 6c9680...9c2115 )
by Bill
02:28
created

solutions.problem32.solve()   A

Complexity

Conditions 4

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 17
nop 0
dl 0
loc 26
rs 9.55
c 0
b 0
f 0
1
"""
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \l was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
2
Project Euler Problem 32: Pandigital Products
3
=============================================
4
5
.. module:: solutions.problem32
6
   :synopsis: My solution to problem #32.
7
8
The source code for this problem can be
9
`found here <https://bitbucket.org/nekedome/project-euler/src/master/solutions/problem32.py>`_.
10
11
Problem Statement
12
#################
13
14
We shall say that an :math:`n`-digit number is pandigital if it makes use of all the digits :math:`1` to :math:`n`
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/100).

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

Loading history...
15
exactly once; for example, the :math:`5`-digit number, :math:`15234`, is :math:`1` through :math:`5` pandigital.
0 ignored issues
show
Coding Style introduced by
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...
16
17
The product :math:`7254` is unusual, as the identity, :math:`39 \\times 186 = 7254`, containing multiplicand,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (109/100).

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

Loading history...
18
multiplier, and product is :math:`1` through :math:`9` pandigital.
19
20
Find the sum of all products whose multiplicand/multiplier/product identity can be written as a :math:`1` through
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (113/100).

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

Loading history...
21
:math:`9` pandigital.
22
23
.. note:: some products can be obtained in more than one way so be sure to only include it once in your sum.
0 ignored issues
show
Coding Style introduced by
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...
24
25
Solution Discussion
26
###################
27
28
The single example given demonstrates that we need not consider prime factorisations but rather the product of two
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/100).

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

Loading history...
29
positive integers; :math:`a \\times b = c`.
30
31
The tuple :math:`(a,b,c)` is defined as :math:`d`-pandigital if the digits :math:`1` through :math:`d` appear precisely
0 ignored issues
show
Coding Style introduced by
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...
32
once in the digits comprising the three integers :math:`a,b,c` when represented in decimal. A pruned search will suffice
0 ignored issues
show
Coding Style introduced by
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...
33
to find all such :math:`d`-pandigital integers.
34
35
First, observe that :math:`c` is completely determined by :math:`a` and :math:`b`, we need only consider :math:`a` and
0 ignored issues
show
Coding Style introduced by
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...
36
:math:`b`. A naive search over all :math:`d`-digit integers :math:`a` and :math:`b` involves a search space of size
0 ignored issues
show
Coding Style introduced by
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...
37
:math:`10^{2 \\times d}`. However, this can be reduced by utilising some additional constraints imposed by the problem.
0 ignored issues
show
Coding Style introduced by
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...
38
39
Since we are searching for :math:`1` through :math:`9` pandigital numbers, we know there are no :math:`0` digits. Thus,
0 ignored issues
show
Coding Style introduced by
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...
40
:math:`a` and :math:`b` are positive integers without leading zeroes and the number of digits in their product is
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (113/100).

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

Loading history...
41
restricted according to:
42
43
.. math::
44
45
    &\\mbox{Let } c = a \\times b \\\\
46
    &\\mbox{Let } |x| \\mbox{ be the number of decimal digits in } x \\\\
47
    &|a| + |b| - 1 \\le |c| \le |a| + |b|
48
49
For :math:`(a,b,c)` to be :math:`d`-pandigital, the total number of digits in all integers must equal :math:`d`:
0 ignored issues
show
Coding Style introduced by
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...
50
51
.. math::
52
53
    |a| + |b| + |c| = d
54
55
Combining these two facts sets up useful constraints on :math:`b`, given :math:`a` and :math:`d`:
56
57
.. math::
58
59
    &|a| + |b| - 1 \\le |c| \\le |a| + |b| \\\\
60
    \\Rightarrow &|a| + |b| + |a| + |b| - 1 \\le |a| + |b| + |c| \\le |a| + |b| + |a| + |b| \\\\
61
    \\Rightarrow &2|a| + 2|b| - 1 \\le d \\le 2|a| + 2|b| \\\\
62
    \\Rightarrow &2|b| - 1 \\le d - 2|a| \\le 2|b| \\\\
63
    \\Rightarrow &d - 2|a| \\le 2|b| \\mbox{ and } 2|b| - 1 \\le d - 2|a| \\\\
64
    \\Rightarrow &\\frac{d}{2} - |a| \\le |b| \\mbox{ and } |b| \\le \\frac{d + 1}{2} - |a| \\\\
65
    \\Rightarrow &\\frac{d}{2} - |a| \\le |b| \\le \\frac{d + 1}{2} - |a|
66
67
Finally, the search over possible integers :math:`a` is bound by two overall constraints. Firstly, that :math:`(a,b,c)`
0 ignored issues
show
Coding Style introduced by
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...
68
must consist of exactly :math:`d` digits and that each integer must be at least one digit. Secondly, that the number of
0 ignored issues
show
Coding Style introduced by
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...
69
digits in :math:`c` will be at least equal to the number of digits in :math:`a`.
70
71
.. math::
72
73
    c = a \\times b \\Rightarrow |c| \\ge |a| \\mbox{ (for positive integers } a,b,c)
74
75
This leads to an upper-bound on the number of digits in :math:`a`:
76
77
.. math::
78
79
    &d = |a| + |b| + |c| \\ge |a| + |b| + |a| = 2|a| + |b| \\\\
80
    \\Rightarrow &d \\ge 2|a| + |b| \\\\
81
    &\\mbox{Since } |b| \\ge 1, 2|a| + |b| \\ge 2|a| + 1 \\\\
82
    \\Rightarrow &d \\ge 2|a| + 1 \\\\
83
    \\Rightarrow &\\frac{d - 1}{2} \\ge |a| \\\\
84
    \\Rightarrow &1 \\le |a| \\le \\frac{d - 1}{2} \\mbox{ (since all } a,b,c \\mbox{ must be at least one digit)}
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/100).

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

Loading history...
85
86
Solution Implementation
87
#######################
88
89
.. literalinclude:: ../../solutions/problem32.py
90
   :language: python
91
   :lines: 94-
92
"""
93
94
from lib.digital import is_pandigital, num_digits
95
96
97
def solve():
98
    """ Compute the answer to Project Euler's problem #32 """
99
100
    # Problem specific parameters
101
    base = 10  # use decimal representation
102
    target = 9  # searching for target-pandigital numbers
103
    a_max = base ** ((target - 1) // 2)  # upper-bound on a
104
105
    # Perform search over a and b looking for target-pandigital numbers
106
    pandigitals = set()
107
    for multiplicand in range(1, a_max):  # search over values of a
108
        a_len = num_digits(multiplicand)
109
        b_lower_digits = (target + 1) // 2 - 1  # minimum number of digits in b
110
        b_upper_digits = target // 2 + 1  # maximum number of digits in b
111
        b_lower = base ** (b_lower_digits - a_len)  # minimum value of b (half-open interval)
112
        b_upper = base ** (b_upper_digits - a_len)  # maximum value of b (half-open interval)
113
114
        for multiplier in range(b_lower, b_upper):  # search over values of b
115
            product = multiplicand * multiplier  # compute c = a * b
116
117
            if is_pandigital([multiplicand, multiplier, product], target, 1, base):
118
                pandigitals.add(product)  # save any unique target-pandigital numbers 'product'
119
120
    # Sum all unique target-pandigital integers
121
    answer = sum(pandigitals)
122
    return answer
123
124
125
expected_answer = 45228
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...
126