Python generator for “barely obtuse” triangles (Project Euler 224)
$begingroup$
I am trying to solve Project Euler Problem 224:
Let us call an integer sided triangle with sides a ≤ b ≤ c barely obtuse if the sides satisfy a2 + b2 = c2 - 1.
How many barely obtuse triangles are there with perimeter ≤ 75,000,000?
For large v_max
and v_max_n
, the generator below yields very slow when I have 750000000 and 500000000, respectively. Having tried for days, I am still looking for an algorithm that can do this in under a minute.
from itertools import product
import math
n = 15 * 10 ** 8
v_max = math.floor(n / 2 - 1 / (2 * n))
v_max_n = n // 3
(i for i in product(range(2, v_max_n + 1, 2),
range(2, v_max + 1, 2),
range(3, v_max + 1))
if i[0] <= i[1] and i[1] <= i[2] and sum(i) <= n and
i[0] ** 2 + i[1] ** 2 == i[2] ** 2 - 1)
I have tried using it as map(lambda x: x, gen)
, nested for loops, and have generally been racking my brain to no avail.
I tried re-writing b, c as expressions. This tends to be quick but misses some of the triples.
n = 12
v_max = math.floor(n / 2 - 1 / (2 * n))
v_max_n = n // 3
j = 0 # tested this with low n and compared: 12, 150 to see
for a in range(1, v_max_n + 1, 1):
b = (n ** 2 - 2 * n * a - 1) / (2 * (n - a))
c = (a ** 2 + b ** 2 + 1) ** 0.5
if c % 1 == 0 and b % 1 == 0 and a + int(b) + int(c) <= n:
# print(a, int(b), int(c))
j += 1
print(j)
python programming-challenge time-limit-exceeded iterator generator
$endgroup$
|
show 13 more comments
$begingroup$
I am trying to solve Project Euler Problem 224:
Let us call an integer sided triangle with sides a ≤ b ≤ c barely obtuse if the sides satisfy a2 + b2 = c2 - 1.
How many barely obtuse triangles are there with perimeter ≤ 75,000,000?
For large v_max
and v_max_n
, the generator below yields very slow when I have 750000000 and 500000000, respectively. Having tried for days, I am still looking for an algorithm that can do this in under a minute.
from itertools import product
import math
n = 15 * 10 ** 8
v_max = math.floor(n / 2 - 1 / (2 * n))
v_max_n = n // 3
(i for i in product(range(2, v_max_n + 1, 2),
range(2, v_max + 1, 2),
range(3, v_max + 1))
if i[0] <= i[1] and i[1] <= i[2] and sum(i) <= n and
i[0] ** 2 + i[1] ** 2 == i[2] ** 2 - 1)
I have tried using it as map(lambda x: x, gen)
, nested for loops, and have generally been racking my brain to no avail.
I tried re-writing b, c as expressions. This tends to be quick but misses some of the triples.
n = 12
v_max = math.floor(n / 2 - 1 / (2 * n))
v_max_n = n // 3
j = 0 # tested this with low n and compared: 12, 150 to see
for a in range(1, v_max_n + 1, 1):
b = (n ** 2 - 2 * n * a - 1) / (2 * (n - a))
c = (a ** 2 + b ** 2 + 1) ** 0.5
if c % 1 == 0 and b % 1 == 0 and a + int(b) + int(c) <= n:
# print(a, int(b), int(c))
j += 1
print(j)
python programming-challenge time-limit-exceeded iterator generator
$endgroup$
$begingroup$
For me this does not even fit into memory (16 GB). Which is weird, sinceproduct
should not make any intermediate lists and neither shouldrange
...
$endgroup$
– Graipher
Dec 17 '18 at 11:28
$begingroup$
@Graipher you should just get a generator object when you initialize the generator which shouldn't use any memory
$endgroup$
– dustin
Dec 17 '18 at 11:31
1
$begingroup$
@Graipher sum(i) <= n. Added the variable definitions.
$endgroup$
– dustin
Dec 17 '18 at 11:36
1
$begingroup$
It would probably help to tell what problem you are actually trying to achieve.
$endgroup$
– Josay
Dec 17 '18 at 16:24
1
$begingroup$
A running time "under a minute" (or in a few minutes, but somewhere in that ballpark) is certainly possible, but not using a brute-force-search over (10^6)^3 possibilities.
$endgroup$
– tobias_k
Dec 17 '18 at 21:13
|
show 13 more comments
$begingroup$
I am trying to solve Project Euler Problem 224:
Let us call an integer sided triangle with sides a ≤ b ≤ c barely obtuse if the sides satisfy a2 + b2 = c2 - 1.
How many barely obtuse triangles are there with perimeter ≤ 75,000,000?
For large v_max
and v_max_n
, the generator below yields very slow when I have 750000000 and 500000000, respectively. Having tried for days, I am still looking for an algorithm that can do this in under a minute.
from itertools import product
import math
n = 15 * 10 ** 8
v_max = math.floor(n / 2 - 1 / (2 * n))
v_max_n = n // 3
(i for i in product(range(2, v_max_n + 1, 2),
range(2, v_max + 1, 2),
range(3, v_max + 1))
if i[0] <= i[1] and i[1] <= i[2] and sum(i) <= n and
i[0] ** 2 + i[1] ** 2 == i[2] ** 2 - 1)
I have tried using it as map(lambda x: x, gen)
, nested for loops, and have generally been racking my brain to no avail.
I tried re-writing b, c as expressions. This tends to be quick but misses some of the triples.
n = 12
v_max = math.floor(n / 2 - 1 / (2 * n))
v_max_n = n // 3
j = 0 # tested this with low n and compared: 12, 150 to see
for a in range(1, v_max_n + 1, 1):
b = (n ** 2 - 2 * n * a - 1) / (2 * (n - a))
c = (a ** 2 + b ** 2 + 1) ** 0.5
if c % 1 == 0 and b % 1 == 0 and a + int(b) + int(c) <= n:
# print(a, int(b), int(c))
j += 1
print(j)
python programming-challenge time-limit-exceeded iterator generator
$endgroup$
I am trying to solve Project Euler Problem 224:
Let us call an integer sided triangle with sides a ≤ b ≤ c barely obtuse if the sides satisfy a2 + b2 = c2 - 1.
How many barely obtuse triangles are there with perimeter ≤ 75,000,000?
For large v_max
and v_max_n
, the generator below yields very slow when I have 750000000 and 500000000, respectively. Having tried for days, I am still looking for an algorithm that can do this in under a minute.
from itertools import product
import math
n = 15 * 10 ** 8
v_max = math.floor(n / 2 - 1 / (2 * n))
v_max_n = n // 3
(i for i in product(range(2, v_max_n + 1, 2),
range(2, v_max + 1, 2),
range(3, v_max + 1))
if i[0] <= i[1] and i[1] <= i[2] and sum(i) <= n and
i[0] ** 2 + i[1] ** 2 == i[2] ** 2 - 1)
I have tried using it as map(lambda x: x, gen)
, nested for loops, and have generally been racking my brain to no avail.
I tried re-writing b, c as expressions. This tends to be quick but misses some of the triples.
n = 12
v_max = math.floor(n / 2 - 1 / (2 * n))
v_max_n = n // 3
j = 0 # tested this with low n and compared: 12, 150 to see
for a in range(1, v_max_n + 1, 1):
b = (n ** 2 - 2 * n * a - 1) / (2 * (n - a))
c = (a ** 2 + b ** 2 + 1) ** 0.5
if c % 1 == 0 and b % 1 == 0 and a + int(b) + int(c) <= n:
# print(a, int(b), int(c))
j += 1
print(j)
python programming-challenge time-limit-exceeded iterator generator
python programming-challenge time-limit-exceeded iterator generator
edited Dec 18 '18 at 2:18
dustin
asked Dec 17 '18 at 11:20
dustindustin
567
567
$begingroup$
For me this does not even fit into memory (16 GB). Which is weird, sinceproduct
should not make any intermediate lists and neither shouldrange
...
$endgroup$
– Graipher
Dec 17 '18 at 11:28
$begingroup$
@Graipher you should just get a generator object when you initialize the generator which shouldn't use any memory
$endgroup$
– dustin
Dec 17 '18 at 11:31
1
$begingroup$
@Graipher sum(i) <= n. Added the variable definitions.
$endgroup$
– dustin
Dec 17 '18 at 11:36
1
$begingroup$
It would probably help to tell what problem you are actually trying to achieve.
$endgroup$
– Josay
Dec 17 '18 at 16:24
1
$begingroup$
A running time "under a minute" (or in a few minutes, but somewhere in that ballpark) is certainly possible, but not using a brute-force-search over (10^6)^3 possibilities.
$endgroup$
– tobias_k
Dec 17 '18 at 21:13
|
show 13 more comments
$begingroup$
For me this does not even fit into memory (16 GB). Which is weird, sinceproduct
should not make any intermediate lists and neither shouldrange
...
$endgroup$
– Graipher
Dec 17 '18 at 11:28
$begingroup$
@Graipher you should just get a generator object when you initialize the generator which shouldn't use any memory
$endgroup$
– dustin
Dec 17 '18 at 11:31
1
$begingroup$
@Graipher sum(i) <= n. Added the variable definitions.
$endgroup$
– dustin
Dec 17 '18 at 11:36
1
$begingroup$
It would probably help to tell what problem you are actually trying to achieve.
$endgroup$
– Josay
Dec 17 '18 at 16:24
1
$begingroup$
A running time "under a minute" (or in a few minutes, but somewhere in that ballpark) is certainly possible, but not using a brute-force-search over (10^6)^3 possibilities.
$endgroup$
– tobias_k
Dec 17 '18 at 21:13
$begingroup$
For me this does not even fit into memory (16 GB). Which is weird, since
product
should not make any intermediate lists and neither should range
...$endgroup$
– Graipher
Dec 17 '18 at 11:28
$begingroup$
For me this does not even fit into memory (16 GB). Which is weird, since
product
should not make any intermediate lists and neither should range
...$endgroup$
– Graipher
Dec 17 '18 at 11:28
$begingroup$
@Graipher you should just get a generator object when you initialize the generator which shouldn't use any memory
$endgroup$
– dustin
Dec 17 '18 at 11:31
$begingroup$
@Graipher you should just get a generator object when you initialize the generator which shouldn't use any memory
$endgroup$
– dustin
Dec 17 '18 at 11:31
1
1
$begingroup$
@Graipher sum(i) <= n. Added the variable definitions.
$endgroup$
– dustin
Dec 17 '18 at 11:36
$begingroup$
@Graipher sum(i) <= n. Added the variable definitions.
$endgroup$
– dustin
Dec 17 '18 at 11:36
1
1
$begingroup$
It would probably help to tell what problem you are actually trying to achieve.
$endgroup$
– Josay
Dec 17 '18 at 16:24
$begingroup$
It would probably help to tell what problem you are actually trying to achieve.
$endgroup$
– Josay
Dec 17 '18 at 16:24
1
1
$begingroup$
A running time "under a minute" (or in a few minutes, but somewhere in that ballpark) is certainly possible, but not using a brute-force-search over (10^6)^3 possibilities.
$endgroup$
– tobias_k
Dec 17 '18 at 21:13
$begingroup$
A running time "under a minute" (or in a few minutes, but somewhere in that ballpark) is certainly possible, but not using a brute-force-search over (10^6)^3 possibilities.
$endgroup$
– tobias_k
Dec 17 '18 at 21:13
|
show 13 more comments
3 Answers
3
active
oldest
votes
$begingroup$
It seems like you want to find a solution for a²+b²=c²-1
with some added constraints, like a<=b<=c
, a+b+c<=n
, etc. by trying all possible combinations of a
, b
, and c
and testing whether they satisfy all your conditions at once. This is pretty wasteful.
Instead of itertools.product
, you can use a generator expression with three regular for
loops. This has several advantages:
you could move some of the
if
clauses up after the first or second loop, i.e. you don't have to run the other loops if those conditions already fail at this point, e.g.
for x in ... if test(x) for y in ... if test(y) ...
you can use the values of your previous variables in the lower and upper bounds for the later variables (in your case this replaces most of your
if
conditions)- you can basically calculate the value for
c
froma
andb
without testing all possible values
This is how I'd do it:
gen = ((a, b, int(c))
for a in range(2, v_max_n + 1, 2)
for b in range(a, min(v_max + 1, n - a - a), 2) # use a for lower and upper bounds
for c in [(a ** 2 + b ** 2 + 1)**0.5] # just a single candidate for c
if c % 1 == 0) # whole-numbered c found?
Note that the calculation of c
using very_large_number**0.5
might be imprecise with float
; using decimal
might work, though. However, even with those optimizations, testing much fewer values than your original loop (on the order of O(n²) instead of O(n³)), it might not be feasible to find solution for large values of a
, b
and c
.
Also note that I did not thoroughly test this for off-by-one errors, since performance was the main concern.
Another thing that you might try: Invert the loops for a
and for b
, i.e. instead of testing all b
for each a
, no matter how large the difference, test all a
up to b
first. This does not decrease the number of combinations to test, but it seems to yield much more valid combinations in the "smaller" number much faster. Like this (upper bound for b
can probably be reduced):
for b in range(2, v_max + 1, 2)
for a in range(2, b+1, 2)
$endgroup$
$begingroup$
It is feasible to find solutions for large N people have solved it with many languages just not an easy task. projecteuler.net/problem=224
$endgroup$
– dustin
Dec 17 '18 at 14:53
$begingroup$
@dustin Surely it is possible, but certainly not using three nested loops with ~10**18 combinations. I don't know what those folks were using, but probably some high-level fancy math.
$endgroup$
– tobias_k
Dec 17 '18 at 15:03
$begingroup$
I tried all kinds of equation re-written and have like 10 code snippets. This generator one was over 1000x better at lower n but just couldn't hang as n increased.
$endgroup$
– dustin
Dec 17 '18 at 15:05
$begingroup$
I think you need to look at the math more. One thing that will help is that you can put upper bounds on how high to search for one of the numbers based on the gaps between consecutive squares.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:26
1
$begingroup$
yeah I don't disagree. I'm seeing if I can get an answer up that uses this now.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:35
|
show 2 more comments
$begingroup$
v_max_n = n // 3
The name of this variable is a mystery to me, but you seem to be using it as an upper bound on $a$. You can get a notably better upper bound on $a$ very easily: since $a le b$ and $c^2 = a^2 + b^2 + 1$, $a + b + c ge 2a + sqrt{2a^2 + 1} > 2a + sqrt{2a^2} = (2 + sqrt 2)a$. Then your upper bound on $a$ can be reduced by 12.13%.
Given a value of $a$, the constraints on $b$ are $a le b$ and $a + b + sqrt{a^2+b^2+1} le n$. Rearrange and square: $a^2 + b^2 + 1 le n^2 + a^2 + b^2 - 2an +2ab -2bn$ or $b le frac{n^2 - 2an - 1}{2n - 2a}$. I'm not sure why you appear to be using this bound as a forced value in the code you added to the question.
$$sum_{a=1}^{frac{n}{2 + sqrt 2}} left(frac{n^2 - 2an - 1}{2n - 2a} - aright)
= left(sum_{a=1}^{frac{n}{2 + sqrt 2}} frac{n^2 - 2an - 1}{2n - 2a}right) - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(frac{n}{2 + sqrt 2}-n+1right) - psi(1-n)right) + frac{n^2}{2 + sqrt 2} - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(1-frac{1+sqrt2}{2 + sqrt 2}nright) - psi(1-n)right) + frac{(3 + 2sqrt 2)n^2 + (2 + sqrt 2)n}{2(2 + sqrt 2)^2} \
> 0.9n^2
$$
The step from the sum to an expression in terms of the digamma function is courtesy of Wolfram Alpha.
As a rule of thumb, you don't want to be repeating a loop body $10^{12}$ times, so looping over all values of $a$ and all values of $b$ is a non-starter.
Hint: try rearranging $a^2 + b^2 = c^2 - 1$.
$endgroup$
add a comment |
$begingroup$
One improvement over @tobias_k s answer is to add the extra upper bound on b of b<1 + a*a//2
. This is valid because after that, the distance between b^2
and (b+1)^2
will be bigger than a^2
, so c^2
does not exist. This provides a massive speedup at least a first.
$endgroup$
$begingroup$
Did you actually test this? Try 10 ** 3. On my machine, it has poorer performance
$endgroup$
– dustin
Dec 17 '18 at 16:17
$begingroup$
Nice. That's a massive speedup, but it still takes ages untila
gets anywhere close to it's upper bound. (Did not thorougly check whether this actually does not skip any values, though)
$endgroup$
– tobias_k
Dec 17 '18 at 16:23
$begingroup$
@dustin How did you add that "extra check"? I added it to themin
; did you do something else?
$endgroup$
– tobias_k
Dec 17 '18 at 16:26
$begingroup$
@tobias_k I am using timeit for this edit. I added to the min as you say and your solution is still faster without it by 2.3ns and a smaller std. Also, beyond 10 ** 3, it is still going over a minute and I end up stoping the interrupt since it is running very long.
$endgroup$
– dustin
Dec 17 '18 at 16:35
$begingroup$
@dustin "faster by 2.3 ns" is nothing. I did not test it, but maybe the condition is not triggered very often for small n so the additioal check adds a tiny amount of computational overhead without much use. How are you printing your results? Are you getting all the valid results first, or printing them as they come? As I said, waiting for all results still takes ages (after some time,a
barely climbed into the lower 1000s) , but the individual results come in much faster.
$endgroup$
– tobias_k
Dec 17 '18 at 16:39
|
show 3 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209821%2fpython-generator-for-barely-obtuse-triangles-project-euler-224%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
It seems like you want to find a solution for a²+b²=c²-1
with some added constraints, like a<=b<=c
, a+b+c<=n
, etc. by trying all possible combinations of a
, b
, and c
and testing whether they satisfy all your conditions at once. This is pretty wasteful.
Instead of itertools.product
, you can use a generator expression with three regular for
loops. This has several advantages:
you could move some of the
if
clauses up after the first or second loop, i.e. you don't have to run the other loops if those conditions already fail at this point, e.g.
for x in ... if test(x) for y in ... if test(y) ...
you can use the values of your previous variables in the lower and upper bounds for the later variables (in your case this replaces most of your
if
conditions)- you can basically calculate the value for
c
froma
andb
without testing all possible values
This is how I'd do it:
gen = ((a, b, int(c))
for a in range(2, v_max_n + 1, 2)
for b in range(a, min(v_max + 1, n - a - a), 2) # use a for lower and upper bounds
for c in [(a ** 2 + b ** 2 + 1)**0.5] # just a single candidate for c
if c % 1 == 0) # whole-numbered c found?
Note that the calculation of c
using very_large_number**0.5
might be imprecise with float
; using decimal
might work, though. However, even with those optimizations, testing much fewer values than your original loop (on the order of O(n²) instead of O(n³)), it might not be feasible to find solution for large values of a
, b
and c
.
Also note that I did not thoroughly test this for off-by-one errors, since performance was the main concern.
Another thing that you might try: Invert the loops for a
and for b
, i.e. instead of testing all b
for each a
, no matter how large the difference, test all a
up to b
first. This does not decrease the number of combinations to test, but it seems to yield much more valid combinations in the "smaller" number much faster. Like this (upper bound for b
can probably be reduced):
for b in range(2, v_max + 1, 2)
for a in range(2, b+1, 2)
$endgroup$
$begingroup$
It is feasible to find solutions for large N people have solved it with many languages just not an easy task. projecteuler.net/problem=224
$endgroup$
– dustin
Dec 17 '18 at 14:53
$begingroup$
@dustin Surely it is possible, but certainly not using three nested loops with ~10**18 combinations. I don't know what those folks were using, but probably some high-level fancy math.
$endgroup$
– tobias_k
Dec 17 '18 at 15:03
$begingroup$
I tried all kinds of equation re-written and have like 10 code snippets. This generator one was over 1000x better at lower n but just couldn't hang as n increased.
$endgroup$
– dustin
Dec 17 '18 at 15:05
$begingroup$
I think you need to look at the math more. One thing that will help is that you can put upper bounds on how high to search for one of the numbers based on the gaps between consecutive squares.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:26
1
$begingroup$
yeah I don't disagree. I'm seeing if I can get an answer up that uses this now.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:35
|
show 2 more comments
$begingroup$
It seems like you want to find a solution for a²+b²=c²-1
with some added constraints, like a<=b<=c
, a+b+c<=n
, etc. by trying all possible combinations of a
, b
, and c
and testing whether they satisfy all your conditions at once. This is pretty wasteful.
Instead of itertools.product
, you can use a generator expression with three regular for
loops. This has several advantages:
you could move some of the
if
clauses up after the first or second loop, i.e. you don't have to run the other loops if those conditions already fail at this point, e.g.
for x in ... if test(x) for y in ... if test(y) ...
you can use the values of your previous variables in the lower and upper bounds for the later variables (in your case this replaces most of your
if
conditions)- you can basically calculate the value for
c
froma
andb
without testing all possible values
This is how I'd do it:
gen = ((a, b, int(c))
for a in range(2, v_max_n + 1, 2)
for b in range(a, min(v_max + 1, n - a - a), 2) # use a for lower and upper bounds
for c in [(a ** 2 + b ** 2 + 1)**0.5] # just a single candidate for c
if c % 1 == 0) # whole-numbered c found?
Note that the calculation of c
using very_large_number**0.5
might be imprecise with float
; using decimal
might work, though. However, even with those optimizations, testing much fewer values than your original loop (on the order of O(n²) instead of O(n³)), it might not be feasible to find solution for large values of a
, b
and c
.
Also note that I did not thoroughly test this for off-by-one errors, since performance was the main concern.
Another thing that you might try: Invert the loops for a
and for b
, i.e. instead of testing all b
for each a
, no matter how large the difference, test all a
up to b
first. This does not decrease the number of combinations to test, but it seems to yield much more valid combinations in the "smaller" number much faster. Like this (upper bound for b
can probably be reduced):
for b in range(2, v_max + 1, 2)
for a in range(2, b+1, 2)
$endgroup$
$begingroup$
It is feasible to find solutions for large N people have solved it with many languages just not an easy task. projecteuler.net/problem=224
$endgroup$
– dustin
Dec 17 '18 at 14:53
$begingroup$
@dustin Surely it is possible, but certainly not using three nested loops with ~10**18 combinations. I don't know what those folks were using, but probably some high-level fancy math.
$endgroup$
– tobias_k
Dec 17 '18 at 15:03
$begingroup$
I tried all kinds of equation re-written and have like 10 code snippets. This generator one was over 1000x better at lower n but just couldn't hang as n increased.
$endgroup$
– dustin
Dec 17 '18 at 15:05
$begingroup$
I think you need to look at the math more. One thing that will help is that you can put upper bounds on how high to search for one of the numbers based on the gaps between consecutive squares.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:26
1
$begingroup$
yeah I don't disagree. I'm seeing if I can get an answer up that uses this now.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:35
|
show 2 more comments
$begingroup$
It seems like you want to find a solution for a²+b²=c²-1
with some added constraints, like a<=b<=c
, a+b+c<=n
, etc. by trying all possible combinations of a
, b
, and c
and testing whether they satisfy all your conditions at once. This is pretty wasteful.
Instead of itertools.product
, you can use a generator expression with three regular for
loops. This has several advantages:
you could move some of the
if
clauses up after the first or second loop, i.e. you don't have to run the other loops if those conditions already fail at this point, e.g.
for x in ... if test(x) for y in ... if test(y) ...
you can use the values of your previous variables in the lower and upper bounds for the later variables (in your case this replaces most of your
if
conditions)- you can basically calculate the value for
c
froma
andb
without testing all possible values
This is how I'd do it:
gen = ((a, b, int(c))
for a in range(2, v_max_n + 1, 2)
for b in range(a, min(v_max + 1, n - a - a), 2) # use a for lower and upper bounds
for c in [(a ** 2 + b ** 2 + 1)**0.5] # just a single candidate for c
if c % 1 == 0) # whole-numbered c found?
Note that the calculation of c
using very_large_number**0.5
might be imprecise with float
; using decimal
might work, though. However, even with those optimizations, testing much fewer values than your original loop (on the order of O(n²) instead of O(n³)), it might not be feasible to find solution for large values of a
, b
and c
.
Also note that I did not thoroughly test this for off-by-one errors, since performance was the main concern.
Another thing that you might try: Invert the loops for a
and for b
, i.e. instead of testing all b
for each a
, no matter how large the difference, test all a
up to b
first. This does not decrease the number of combinations to test, but it seems to yield much more valid combinations in the "smaller" number much faster. Like this (upper bound for b
can probably be reduced):
for b in range(2, v_max + 1, 2)
for a in range(2, b+1, 2)
$endgroup$
It seems like you want to find a solution for a²+b²=c²-1
with some added constraints, like a<=b<=c
, a+b+c<=n
, etc. by trying all possible combinations of a
, b
, and c
and testing whether they satisfy all your conditions at once. This is pretty wasteful.
Instead of itertools.product
, you can use a generator expression with three regular for
loops. This has several advantages:
you could move some of the
if
clauses up after the first or second loop, i.e. you don't have to run the other loops if those conditions already fail at this point, e.g.
for x in ... if test(x) for y in ... if test(y) ...
you can use the values of your previous variables in the lower and upper bounds for the later variables (in your case this replaces most of your
if
conditions)- you can basically calculate the value for
c
froma
andb
without testing all possible values
This is how I'd do it:
gen = ((a, b, int(c))
for a in range(2, v_max_n + 1, 2)
for b in range(a, min(v_max + 1, n - a - a), 2) # use a for lower and upper bounds
for c in [(a ** 2 + b ** 2 + 1)**0.5] # just a single candidate for c
if c % 1 == 0) # whole-numbered c found?
Note that the calculation of c
using very_large_number**0.5
might be imprecise with float
; using decimal
might work, though. However, even with those optimizations, testing much fewer values than your original loop (on the order of O(n²) instead of O(n³)), it might not be feasible to find solution for large values of a
, b
and c
.
Also note that I did not thoroughly test this for off-by-one errors, since performance was the main concern.
Another thing that you might try: Invert the loops for a
and for b
, i.e. instead of testing all b
for each a
, no matter how large the difference, test all a
up to b
first. This does not decrease the number of combinations to test, but it seems to yield much more valid combinations in the "smaller" number much faster. Like this (upper bound for b
can probably be reduced):
for b in range(2, v_max + 1, 2)
for a in range(2, b+1, 2)
edited Dec 17 '18 at 15:05
answered Dec 17 '18 at 14:51
tobias_ktobias_k
1,529916
1,529916
$begingroup$
It is feasible to find solutions for large N people have solved it with many languages just not an easy task. projecteuler.net/problem=224
$endgroup$
– dustin
Dec 17 '18 at 14:53
$begingroup$
@dustin Surely it is possible, but certainly not using three nested loops with ~10**18 combinations. I don't know what those folks were using, but probably some high-level fancy math.
$endgroup$
– tobias_k
Dec 17 '18 at 15:03
$begingroup$
I tried all kinds of equation re-written and have like 10 code snippets. This generator one was over 1000x better at lower n but just couldn't hang as n increased.
$endgroup$
– dustin
Dec 17 '18 at 15:05
$begingroup$
I think you need to look at the math more. One thing that will help is that you can put upper bounds on how high to search for one of the numbers based on the gaps between consecutive squares.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:26
1
$begingroup$
yeah I don't disagree. I'm seeing if I can get an answer up that uses this now.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:35
|
show 2 more comments
$begingroup$
It is feasible to find solutions for large N people have solved it with many languages just not an easy task. projecteuler.net/problem=224
$endgroup$
– dustin
Dec 17 '18 at 14:53
$begingroup$
@dustin Surely it is possible, but certainly not using three nested loops with ~10**18 combinations. I don't know what those folks were using, but probably some high-level fancy math.
$endgroup$
– tobias_k
Dec 17 '18 at 15:03
$begingroup$
I tried all kinds of equation re-written and have like 10 code snippets. This generator one was over 1000x better at lower n but just couldn't hang as n increased.
$endgroup$
– dustin
Dec 17 '18 at 15:05
$begingroup$
I think you need to look at the math more. One thing that will help is that you can put upper bounds on how high to search for one of the numbers based on the gaps between consecutive squares.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:26
1
$begingroup$
yeah I don't disagree. I'm seeing if I can get an answer up that uses this now.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:35
$begingroup$
It is feasible to find solutions for large N people have solved it with many languages just not an easy task. projecteuler.net/problem=224
$endgroup$
– dustin
Dec 17 '18 at 14:53
$begingroup$
It is feasible to find solutions for large N people have solved it with many languages just not an easy task. projecteuler.net/problem=224
$endgroup$
– dustin
Dec 17 '18 at 14:53
$begingroup$
@dustin Surely it is possible, but certainly not using three nested loops with ~10**18 combinations. I don't know what those folks were using, but probably some high-level fancy math.
$endgroup$
– tobias_k
Dec 17 '18 at 15:03
$begingroup$
@dustin Surely it is possible, but certainly not using three nested loops with ~10**18 combinations. I don't know what those folks were using, but probably some high-level fancy math.
$endgroup$
– tobias_k
Dec 17 '18 at 15:03
$begingroup$
I tried all kinds of equation re-written and have like 10 code snippets. This generator one was over 1000x better at lower n but just couldn't hang as n increased.
$endgroup$
– dustin
Dec 17 '18 at 15:05
$begingroup$
I tried all kinds of equation re-written and have like 10 code snippets. This generator one was over 1000x better at lower n but just couldn't hang as n increased.
$endgroup$
– dustin
Dec 17 '18 at 15:05
$begingroup$
I think you need to look at the math more. One thing that will help is that you can put upper bounds on how high to search for one of the numbers based on the gaps between consecutive squares.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:26
$begingroup$
I think you need to look at the math more. One thing that will help is that you can put upper bounds on how high to search for one of the numbers based on the gaps between consecutive squares.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:26
1
1
$begingroup$
yeah I don't disagree. I'm seeing if I can get an answer up that uses this now.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:35
$begingroup$
yeah I don't disagree. I'm seeing if I can get an answer up that uses this now.
$endgroup$
– Oscar Smith
Dec 17 '18 at 15:35
|
show 2 more comments
$begingroup$
v_max_n = n // 3
The name of this variable is a mystery to me, but you seem to be using it as an upper bound on $a$. You can get a notably better upper bound on $a$ very easily: since $a le b$ and $c^2 = a^2 + b^2 + 1$, $a + b + c ge 2a + sqrt{2a^2 + 1} > 2a + sqrt{2a^2} = (2 + sqrt 2)a$. Then your upper bound on $a$ can be reduced by 12.13%.
Given a value of $a$, the constraints on $b$ are $a le b$ and $a + b + sqrt{a^2+b^2+1} le n$. Rearrange and square: $a^2 + b^2 + 1 le n^2 + a^2 + b^2 - 2an +2ab -2bn$ or $b le frac{n^2 - 2an - 1}{2n - 2a}$. I'm not sure why you appear to be using this bound as a forced value in the code you added to the question.
$$sum_{a=1}^{frac{n}{2 + sqrt 2}} left(frac{n^2 - 2an - 1}{2n - 2a} - aright)
= left(sum_{a=1}^{frac{n}{2 + sqrt 2}} frac{n^2 - 2an - 1}{2n - 2a}right) - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(frac{n}{2 + sqrt 2}-n+1right) - psi(1-n)right) + frac{n^2}{2 + sqrt 2} - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(1-frac{1+sqrt2}{2 + sqrt 2}nright) - psi(1-n)right) + frac{(3 + 2sqrt 2)n^2 + (2 + sqrt 2)n}{2(2 + sqrt 2)^2} \
> 0.9n^2
$$
The step from the sum to an expression in terms of the digamma function is courtesy of Wolfram Alpha.
As a rule of thumb, you don't want to be repeating a loop body $10^{12}$ times, so looping over all values of $a$ and all values of $b$ is a non-starter.
Hint: try rearranging $a^2 + b^2 = c^2 - 1$.
$endgroup$
add a comment |
$begingroup$
v_max_n = n // 3
The name of this variable is a mystery to me, but you seem to be using it as an upper bound on $a$. You can get a notably better upper bound on $a$ very easily: since $a le b$ and $c^2 = a^2 + b^2 + 1$, $a + b + c ge 2a + sqrt{2a^2 + 1} > 2a + sqrt{2a^2} = (2 + sqrt 2)a$. Then your upper bound on $a$ can be reduced by 12.13%.
Given a value of $a$, the constraints on $b$ are $a le b$ and $a + b + sqrt{a^2+b^2+1} le n$. Rearrange and square: $a^2 + b^2 + 1 le n^2 + a^2 + b^2 - 2an +2ab -2bn$ or $b le frac{n^2 - 2an - 1}{2n - 2a}$. I'm not sure why you appear to be using this bound as a forced value in the code you added to the question.
$$sum_{a=1}^{frac{n}{2 + sqrt 2}} left(frac{n^2 - 2an - 1}{2n - 2a} - aright)
= left(sum_{a=1}^{frac{n}{2 + sqrt 2}} frac{n^2 - 2an - 1}{2n - 2a}right) - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(frac{n}{2 + sqrt 2}-n+1right) - psi(1-n)right) + frac{n^2}{2 + sqrt 2} - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(1-frac{1+sqrt2}{2 + sqrt 2}nright) - psi(1-n)right) + frac{(3 + 2sqrt 2)n^2 + (2 + sqrt 2)n}{2(2 + sqrt 2)^2} \
> 0.9n^2
$$
The step from the sum to an expression in terms of the digamma function is courtesy of Wolfram Alpha.
As a rule of thumb, you don't want to be repeating a loop body $10^{12}$ times, so looping over all values of $a$ and all values of $b$ is a non-starter.
Hint: try rearranging $a^2 + b^2 = c^2 - 1$.
$endgroup$
add a comment |
$begingroup$
v_max_n = n // 3
The name of this variable is a mystery to me, but you seem to be using it as an upper bound on $a$. You can get a notably better upper bound on $a$ very easily: since $a le b$ and $c^2 = a^2 + b^2 + 1$, $a + b + c ge 2a + sqrt{2a^2 + 1} > 2a + sqrt{2a^2} = (2 + sqrt 2)a$. Then your upper bound on $a$ can be reduced by 12.13%.
Given a value of $a$, the constraints on $b$ are $a le b$ and $a + b + sqrt{a^2+b^2+1} le n$. Rearrange and square: $a^2 + b^2 + 1 le n^2 + a^2 + b^2 - 2an +2ab -2bn$ or $b le frac{n^2 - 2an - 1}{2n - 2a}$. I'm not sure why you appear to be using this bound as a forced value in the code you added to the question.
$$sum_{a=1}^{frac{n}{2 + sqrt 2}} left(frac{n^2 - 2an - 1}{2n - 2a} - aright)
= left(sum_{a=1}^{frac{n}{2 + sqrt 2}} frac{n^2 - 2an - 1}{2n - 2a}right) - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(frac{n}{2 + sqrt 2}-n+1right) - psi(1-n)right) + frac{n^2}{2 + sqrt 2} - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(1-frac{1+sqrt2}{2 + sqrt 2}nright) - psi(1-n)right) + frac{(3 + 2sqrt 2)n^2 + (2 + sqrt 2)n}{2(2 + sqrt 2)^2} \
> 0.9n^2
$$
The step from the sum to an expression in terms of the digamma function is courtesy of Wolfram Alpha.
As a rule of thumb, you don't want to be repeating a loop body $10^{12}$ times, so looping over all values of $a$ and all values of $b$ is a non-starter.
Hint: try rearranging $a^2 + b^2 = c^2 - 1$.
$endgroup$
v_max_n = n // 3
The name of this variable is a mystery to me, but you seem to be using it as an upper bound on $a$. You can get a notably better upper bound on $a$ very easily: since $a le b$ and $c^2 = a^2 + b^2 + 1$, $a + b + c ge 2a + sqrt{2a^2 + 1} > 2a + sqrt{2a^2} = (2 + sqrt 2)a$. Then your upper bound on $a$ can be reduced by 12.13%.
Given a value of $a$, the constraints on $b$ are $a le b$ and $a + b + sqrt{a^2+b^2+1} le n$. Rearrange and square: $a^2 + b^2 + 1 le n^2 + a^2 + b^2 - 2an +2ab -2bn$ or $b le frac{n^2 - 2an - 1}{2n - 2a}$. I'm not sure why you appear to be using this bound as a forced value in the code you added to the question.
$$sum_{a=1}^{frac{n}{2 + sqrt 2}} left(frac{n^2 - 2an - 1}{2n - 2a} - aright)
= left(sum_{a=1}^{frac{n}{2 + sqrt 2}} frac{n^2 - 2an - 1}{2n - 2a}right) - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(frac{n}{2 + sqrt 2}-n+1right) - psi(1-n)right) + frac{n^2}{2 + sqrt 2} - frac{n(n + 2 + sqrt 2)}{2(2 + sqrt 2)^2} \
= frac{n^2 + 1}2 left(psileft(1-frac{1+sqrt2}{2 + sqrt 2}nright) - psi(1-n)right) + frac{(3 + 2sqrt 2)n^2 + (2 + sqrt 2)n}{2(2 + sqrt 2)^2} \
> 0.9n^2
$$
The step from the sum to an expression in terms of the digamma function is courtesy of Wolfram Alpha.
As a rule of thumb, you don't want to be repeating a loop body $10^{12}$ times, so looping over all values of $a$ and all values of $b$ is a non-starter.
Hint: try rearranging $a^2 + b^2 = c^2 - 1$.
answered Dec 18 '18 at 10:15
Peter TaylorPeter Taylor
17.9k2962
17.9k2962
add a comment |
add a comment |
$begingroup$
One improvement over @tobias_k s answer is to add the extra upper bound on b of b<1 + a*a//2
. This is valid because after that, the distance between b^2
and (b+1)^2
will be bigger than a^2
, so c^2
does not exist. This provides a massive speedup at least a first.
$endgroup$
$begingroup$
Did you actually test this? Try 10 ** 3. On my machine, it has poorer performance
$endgroup$
– dustin
Dec 17 '18 at 16:17
$begingroup$
Nice. That's a massive speedup, but it still takes ages untila
gets anywhere close to it's upper bound. (Did not thorougly check whether this actually does not skip any values, though)
$endgroup$
– tobias_k
Dec 17 '18 at 16:23
$begingroup$
@dustin How did you add that "extra check"? I added it to themin
; did you do something else?
$endgroup$
– tobias_k
Dec 17 '18 at 16:26
$begingroup$
@tobias_k I am using timeit for this edit. I added to the min as you say and your solution is still faster without it by 2.3ns and a smaller std. Also, beyond 10 ** 3, it is still going over a minute and I end up stoping the interrupt since it is running very long.
$endgroup$
– dustin
Dec 17 '18 at 16:35
$begingroup$
@dustin "faster by 2.3 ns" is nothing. I did not test it, but maybe the condition is not triggered very often for small n so the additioal check adds a tiny amount of computational overhead without much use. How are you printing your results? Are you getting all the valid results first, or printing them as they come? As I said, waiting for all results still takes ages (after some time,a
barely climbed into the lower 1000s) , but the individual results come in much faster.
$endgroup$
– tobias_k
Dec 17 '18 at 16:39
|
show 3 more comments
$begingroup$
One improvement over @tobias_k s answer is to add the extra upper bound on b of b<1 + a*a//2
. This is valid because after that, the distance between b^2
and (b+1)^2
will be bigger than a^2
, so c^2
does not exist. This provides a massive speedup at least a first.
$endgroup$
$begingroup$
Did you actually test this? Try 10 ** 3. On my machine, it has poorer performance
$endgroup$
– dustin
Dec 17 '18 at 16:17
$begingroup$
Nice. That's a massive speedup, but it still takes ages untila
gets anywhere close to it's upper bound. (Did not thorougly check whether this actually does not skip any values, though)
$endgroup$
– tobias_k
Dec 17 '18 at 16:23
$begingroup$
@dustin How did you add that "extra check"? I added it to themin
; did you do something else?
$endgroup$
– tobias_k
Dec 17 '18 at 16:26
$begingroup$
@tobias_k I am using timeit for this edit. I added to the min as you say and your solution is still faster without it by 2.3ns and a smaller std. Also, beyond 10 ** 3, it is still going over a minute and I end up stoping the interrupt since it is running very long.
$endgroup$
– dustin
Dec 17 '18 at 16:35
$begingroup$
@dustin "faster by 2.3 ns" is nothing. I did not test it, but maybe the condition is not triggered very often for small n so the additioal check adds a tiny amount of computational overhead without much use. How are you printing your results? Are you getting all the valid results first, or printing them as they come? As I said, waiting for all results still takes ages (after some time,a
barely climbed into the lower 1000s) , but the individual results come in much faster.
$endgroup$
– tobias_k
Dec 17 '18 at 16:39
|
show 3 more comments
$begingroup$
One improvement over @tobias_k s answer is to add the extra upper bound on b of b<1 + a*a//2
. This is valid because after that, the distance between b^2
and (b+1)^2
will be bigger than a^2
, so c^2
does not exist. This provides a massive speedup at least a first.
$endgroup$
One improvement over @tobias_k s answer is to add the extra upper bound on b of b<1 + a*a//2
. This is valid because after that, the distance between b^2
and (b+1)^2
will be bigger than a^2
, so c^2
does not exist. This provides a massive speedup at least a first.
answered Dec 17 '18 at 16:08
Oscar SmithOscar Smith
2,7731022
2,7731022
$begingroup$
Did you actually test this? Try 10 ** 3. On my machine, it has poorer performance
$endgroup$
– dustin
Dec 17 '18 at 16:17
$begingroup$
Nice. That's a massive speedup, but it still takes ages untila
gets anywhere close to it's upper bound. (Did not thorougly check whether this actually does not skip any values, though)
$endgroup$
– tobias_k
Dec 17 '18 at 16:23
$begingroup$
@dustin How did you add that "extra check"? I added it to themin
; did you do something else?
$endgroup$
– tobias_k
Dec 17 '18 at 16:26
$begingroup$
@tobias_k I am using timeit for this edit. I added to the min as you say and your solution is still faster without it by 2.3ns and a smaller std. Also, beyond 10 ** 3, it is still going over a minute and I end up stoping the interrupt since it is running very long.
$endgroup$
– dustin
Dec 17 '18 at 16:35
$begingroup$
@dustin "faster by 2.3 ns" is nothing. I did not test it, but maybe the condition is not triggered very often for small n so the additioal check adds a tiny amount of computational overhead without much use. How are you printing your results? Are you getting all the valid results first, or printing them as they come? As I said, waiting for all results still takes ages (after some time,a
barely climbed into the lower 1000s) , but the individual results come in much faster.
$endgroup$
– tobias_k
Dec 17 '18 at 16:39
|
show 3 more comments
$begingroup$
Did you actually test this? Try 10 ** 3. On my machine, it has poorer performance
$endgroup$
– dustin
Dec 17 '18 at 16:17
$begingroup$
Nice. That's a massive speedup, but it still takes ages untila
gets anywhere close to it's upper bound. (Did not thorougly check whether this actually does not skip any values, though)
$endgroup$
– tobias_k
Dec 17 '18 at 16:23
$begingroup$
@dustin How did you add that "extra check"? I added it to themin
; did you do something else?
$endgroup$
– tobias_k
Dec 17 '18 at 16:26
$begingroup$
@tobias_k I am using timeit for this edit. I added to the min as you say and your solution is still faster without it by 2.3ns and a smaller std. Also, beyond 10 ** 3, it is still going over a minute and I end up stoping the interrupt since it is running very long.
$endgroup$
– dustin
Dec 17 '18 at 16:35
$begingroup$
@dustin "faster by 2.3 ns" is nothing. I did not test it, but maybe the condition is not triggered very often for small n so the additioal check adds a tiny amount of computational overhead without much use. How are you printing your results? Are you getting all the valid results first, or printing them as they come? As I said, waiting for all results still takes ages (after some time,a
barely climbed into the lower 1000s) , but the individual results come in much faster.
$endgroup$
– tobias_k
Dec 17 '18 at 16:39
$begingroup$
Did you actually test this? Try 10 ** 3. On my machine, it has poorer performance
$endgroup$
– dustin
Dec 17 '18 at 16:17
$begingroup$
Did you actually test this? Try 10 ** 3. On my machine, it has poorer performance
$endgroup$
– dustin
Dec 17 '18 at 16:17
$begingroup$
Nice. That's a massive speedup, but it still takes ages until
a
gets anywhere close to it's upper bound. (Did not thorougly check whether this actually does not skip any values, though)$endgroup$
– tobias_k
Dec 17 '18 at 16:23
$begingroup$
Nice. That's a massive speedup, but it still takes ages until
a
gets anywhere close to it's upper bound. (Did not thorougly check whether this actually does not skip any values, though)$endgroup$
– tobias_k
Dec 17 '18 at 16:23
$begingroup$
@dustin How did you add that "extra check"? I added it to the
min
; did you do something else?$endgroup$
– tobias_k
Dec 17 '18 at 16:26
$begingroup$
@dustin How did you add that "extra check"? I added it to the
min
; did you do something else?$endgroup$
– tobias_k
Dec 17 '18 at 16:26
$begingroup$
@tobias_k I am using timeit for this edit. I added to the min as you say and your solution is still faster without it by 2.3ns and a smaller std. Also, beyond 10 ** 3, it is still going over a minute and I end up stoping the interrupt since it is running very long.
$endgroup$
– dustin
Dec 17 '18 at 16:35
$begingroup$
@tobias_k I am using timeit for this edit. I added to the min as you say and your solution is still faster without it by 2.3ns and a smaller std. Also, beyond 10 ** 3, it is still going over a minute and I end up stoping the interrupt since it is running very long.
$endgroup$
– dustin
Dec 17 '18 at 16:35
$begingroup$
@dustin "faster by 2.3 ns" is nothing. I did not test it, but maybe the condition is not triggered very often for small n so the additioal check adds a tiny amount of computational overhead without much use. How are you printing your results? Are you getting all the valid results first, or printing them as they come? As I said, waiting for all results still takes ages (after some time,
a
barely climbed into the lower 1000s) , but the individual results come in much faster.$endgroup$
– tobias_k
Dec 17 '18 at 16:39
$begingroup$
@dustin "faster by 2.3 ns" is nothing. I did not test it, but maybe the condition is not triggered very often for small n so the additioal check adds a tiny amount of computational overhead without much use. How are you printing your results? Are you getting all the valid results first, or printing them as they come? As I said, waiting for all results still takes ages (after some time,
a
barely climbed into the lower 1000s) , but the individual results come in much faster.$endgroup$
– tobias_k
Dec 17 '18 at 16:39
|
show 3 more comments
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209821%2fpython-generator-for-barely-obtuse-triangles-project-euler-224%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
For me this does not even fit into memory (16 GB). Which is weird, since
product
should not make any intermediate lists and neither shouldrange
...$endgroup$
– Graipher
Dec 17 '18 at 11:28
$begingroup$
@Graipher you should just get a generator object when you initialize the generator which shouldn't use any memory
$endgroup$
– dustin
Dec 17 '18 at 11:31
1
$begingroup$
@Graipher sum(i) <= n. Added the variable definitions.
$endgroup$
– dustin
Dec 17 '18 at 11:36
1
$begingroup$
It would probably help to tell what problem you are actually trying to achieve.
$endgroup$
– Josay
Dec 17 '18 at 16:24
1
$begingroup$
A running time "under a minute" (or in a few minutes, but somewhere in that ballpark) is certainly possible, but not using a brute-force-search over (10^6)^3 possibilities.
$endgroup$
– tobias_k
Dec 17 '18 at 21:13