Archive

Posts Tagged ‘project euler’

Construct Pythagorean triangles with given constraints

August 24, 2020 Leave a comment

This post will present some ideas related to the generation of all Pythagorean triangles satisfying a certain criterion, from an algorithmic point of view. Of course, there are infinitely many such triangles (integer sided with a right angle). Denoting by {b} and {c} the edges adjacent to the right angle and with {a} the hypothenuse, we have the classical relation

\displaystyle b^2+c^2=a^2.

When {a,b,c} are all integers, it is possible to give a more precise result regarding the possible values of {a,b,c}. Indeed, for any such triangle, there exist integers {k,m,n} with {m>n}, {m,n} not both odd and coprime such that

\displaystyle a = k(m^2+n^2), b = k(m^2-n^2), c = 2kmn.

These formulas are attributed to Euclid. The case {k=1} corresponds to {a,b,c} coprime and such a triangle is caled “primitive”. What is important to note is that this formula generates ALL pythagorean triangles exactly once, and this allows us to solve the following two questions:

1. Generate all pythagorean triangles with edges {\leq N}.

2. Generate all pythagorean triangles with {b = N} or {c=N}.

3. Generate all pythagorean triangles with {a = N}.

Now let’s answer these questions one at a time:

1. In order to generate pythagorean triangles with edges {\leq N} we need to loop over all {m,n}, coprime, not both odd with {m>n} such that {m^2+n^2\leq N} and for each primitive triangle, add to the list all its “multiples” by looking at the appropriate {k}. One possible algorithm is

  • set an empty list {L}
  • loop for {m=2} to {\sqrt{N/2}}
    • loop for {n=1} to {m-1}, {\gcd(m,n)=1}, {m,n} not both odd
    • loop for {k=1} to {N/(m^2+n^2)} and add the triangle {[2kmn,k(m^2-n^2),k(m^2+n^2)]} to the list {L}
  • in the end {L} will contain the desired triangles

2. In this question one of the two legs {b} or {c} should be equal to {N}. The only difficulty here is that we need to loop on the divisors of {N}. Indeed, we have two cases:

  • {N=2kmn}: for all divisors {k} of {N}, we should find the possible factorizations {N/(2k) = mn} with {m,n} not both odd and coprime, and then add the corresponding triangle to the list.
  • {N = k (m^2-n^2) = k(m+n)(m-n)}: find all factorizations {N/k = (m+n)(m-n)} and check again that {m,n} obtained are coprime and not both odd.

3. In this case {a = k(m^2+n^2)}. Therefore, one should loop on all divisors {k} of {N} and in each case solve

\displaystyle N/k = m^2+n^2

where {m>n}, {m,n} are coprime, not both odd. This can be done again with a loop.

These tools might come in handy when working on Project Euler problems, since often when dealing with integer sided quantities in a triangle, things can be reduced to pythagorean triangles. When you reach this step, it is enough to loop on these triangles and perform the requested operations.

Integer sided triangle and IA, IB and IC integers

August 3, 2020 Leave a comment

Let {ABC} be a triangle whose side lengths {AB,BC,CA} are positive integers. Denote by {I} the incenter of the triangle {ABC} and suppose also that the segments {IA,IB,IC} have integer lengths. Prove that the inradius of the triangle {ABC} is an integer.

Solution: Denote by {D,E,F} the projections of the incenter on {BC,CA,AB}, respectively. Use the classical notation {a=BC,b=CA,c=AB} for the lengths of the sides of the triangle. Moreover, use the notations {x = AE=AF}, {y=BD=BF}, {z=CD=CE}. Using Pythagora’s theorem in triangles determined by {I,A,B,C,D,E,F} we obtain

\displaystyle x^2+r^2 = IA^2, y^2+r^2 = IB^2, z^2+r^2=IC^2.

Moreover, it can be proved that if {s = (a+b+c)/2} then {x = p-a, y = p-b, z=p-c}. Using the hypothesis, it follows that {2x,2y,2z} are integers. Using this and the Pythagora’s relations above we find that {4r^2} should be an integer. However, this is not enough to conclude that {r} would also be an integer.

Looking at the triangle {IAB}, denoting {\alpha/2 = \angle IAB} and {\beta/2 = \angle IBA}, {\gamma/2 = \angle ICA} and applying the sine rule we get

\displaystyle \frac{AI}{\sin(\beta/2)} = \frac{c}{\sin((\alpha+\beta)/2)} = \frac{c}{\cos \gamma/2}.

Now note that {\sin \beta/2 = r/IB} and {\cos \gamma/2 = (s-c)/IC}, which gives

\displaystyle \frac{AI}{r/IB} = \frac{c}{(s-c)/IC}.

This complicated relation allows us to deduce that {r} is rational. This means that {r = p/q} with {p} and {q} coprime integers. Moreover, we saw that {4r^2 = 4 p^2/q^2} is an integer, which means that {q^2 |4} or {q|2}. In the end we find that {2r} should always be an integer.

Now, is it possible that {r} is only a half integer, i.e. {2r} is odd? The Pythagora’s relations above imply that

\displaystyle 4x^2+4r^2=4IA^2.

If {2r} is an odd integer then {4r^2} is also odd and of the form {4k+1}. Moreover, {2x} is also an integer, which by the above relation should also be odd, which means that {4x^2} is an integer of the form {4k'+1}. In the end we arrive at

\displaystyle 4k'+1+4k+1 = 4IA^2,

which is a contradiction. Therefore {r} must be an integer!

Sum of floors of multiples of the Golden Ratio

July 25, 2020 1 comment

Propose an algorithm for computing

\displaystyle S_n = \sum_{i=1}^n \lfloor i\varphi \rfloor

for {n=10^{16}}, where {\varphi= \frac{\sqrt{5}+1}{2}} is the golden ratio. The sum {S_n} is the sum of the first {n} terms in the so called lower Wythoff sequence.

Solution: Computing a floor function and a multiplication is not complicated, therefore proposing a {O(n)} algorithm for computing {S_n} is trivial. However, such an algorithm is not viable for {n = 10^{16}}.

The path to a much more efficient algorithm goes through the notion of Beatty sequence. For a positive irrational number {r>1} the associated Beatty sequence is {(\lfloor nr\rfloor)_{n\geq 1}}. This notion becomes interesting when noting the following fact. If {s>1} is defined by {1/r+1/s=1} then the Beatty sequences {(\lfloor nr\rfloor)_{n\geq 1}} and {(\lfloor ns\rfloor)_{n\geq 1}} cover all the positive integers. The latter sequence is called the associated complementary Beatty sequence. Two proofs of this fact can be found in the Wikipedia link above.

It is obvious now that {S_n} is just the partial sum of the Beatty sequence associated to {\varphi}. Now let’s see what is the complementary sequence. A brief computation shows that the associated {s} is given by {s=\varphi+1}, which shows that the terms which are not of the form {\lfloor i\varphi\rfloor} are not far from it. In order to see how this can give an efficient algorithm, let’s follow the instructions below:

  • denote by {N = \lfloor n\varphi \rfloor}, the largest term in {S_n}.
  • looking at all the integers up to {N}, in view of the result regarding the Beatty sequences, they are either of the form {\lfloor i\varphi \rfloor} or of the form {\lfloor j(\varphi+1) \rfloor} (in the associated complementary sequence).
  • denote by {J} the largest integer such that {\lfloor j(\varphi+1) \rfloor< N}, which is given by {J = \lfloor (N+1)/(\varphi+1)\rfloor}. Then, it is not difficult to see that {S_n} is the difference between the sum of all positive integers up to {N} and {S_J+1+...+J}.
  • In the end we obtain

    \displaystyle S_n = N(N+1)/2 - S_J-J(J+1)/2.

  • by convention, state that {S_0=0} or {S_1=1}.

The last item above shows that a recursive algorithm can be implemented in order to compute {S_n}. Moreover, since the computation of {S_n} is reduced to the computation of {S_J} where {J = \lfloor (\lfloor n\varphi\rfloor+1)/(\varphi+1)\rfloor\leq n \frac{\varphi}{\varphi+1}+\frac{1}{\varphi+1}}, the algorithm will converge very fast, since the sequence of upper bounds for {J} converges exponentially to zero. Therefore, the algorithm obtained will have complexity {O(\log n)} and will work for extremely large values of {n}, provided the language you are using can handle the expected precision.

The algorithm for computing {S_n} shown above can be used, for example, in computing sums related to elements in the Wythoff table, which can be expressed using Fibonacci numbers and terms in {S_n}.

Other values of {r}, like for example {r=\sqrt{2}} (with {s=2+\sqrt{2}}) lead to other types of sums for which the same type of algorithm can be applied. It is likely that even cases where {s} is not explicitly related to {r} through an integer may be handled through a similar procedure (to be confirmed).

Sum of the Euler Totient function

May 10, 2018 10 comments

Given a positive integer {n}, the Euler totient function {\varphi(n)} is defined as the number of positive integers less than {n} which are co-prime with {n} (i.e. they have no common factors with {n}). There are formulas for computing {\varphi(n)} starting from the factorization of {n}. One such formula is

\displaystyle \varphi(n) = n \prod_{p|n} \left(1-\frac{1}{p}\right),

where the product is made over all primes dividing {n}.

If you have to compute {\varphi(n)} for all numbers less than a threshold then another property could be useful: {\varphi} is arithmetic, that is, {\varphi(mn) = \varphi(m)\varphi(n)} whenever {\gcd(m,n)=1}. Therefore you could store all values computed until {k} and for computing the value {\varphi(k+1)} there are two possibilities: {k+1=p^\alpha} is a prime power and then {\varphi(k+1) = p^{\alpha}-p^{\alpha-1}} or {k+1} is composite and {k+1 = mn} with {m,n\leq k,\ \gcd(m,n)=1}. Then use the stored values to compute {\varphi(k+1)=\varphi(m)\varphi(n)}.

I now come to the main point of this post: computing the sum of all values of the totient function up to a certain {N}:

\displaystyle \text{Compute } S(N) = \sum_{i=1}^N \varphi(i).

One approach is to compute each {\varphi(i)} and sum them. I will call this the brute-force approach. For all numerical purposes I will use Pari-GP in this post. On my computer it takes less than a second to compute {S(10^6)} and about {12} seconds to compute {S(10^7)}. This is super linear in time, since the algorithm computes the factorization for each {n} and then sums the values. Using the sieve approach could improve the timing a bit, but the algorithm is still super linear.

In some Project Euler problems it is not uncommon to have to compute something like {S(10^{11})} or even larger. Therefore, there must be more efficient ways to compute {S(N)} out there, so let’s study some of the properties of {S(N)}. In another post I dealt with the acceleration of the computation of the sum of the divisor function.

We have {S(N) = \sum_{i=1}^N \varphi(i)} which is the number of pairs {(a,b)} with {1\leq a\leq b \leq N} such that {\gcd(a,b) =1}. It is not difficult to see that the total number of such pairs is {n(n+1)/2}. Moreover, the possible values of {\gcd(a,b)} are {1,2,...,N}. Now, if for {m \leq N} we search instead for pairs satisfying {\gcd(a,b)=m} then we have {a = ma',\ b = mb'} with {\gcd(a',b')=1} and we get

\displaystyle 1 \leq a' \leq b' \leq N/m,\ \gcd(a',b')=1.

There fore the number of pairs with gcd equal to {m} is {S(\lfloor N/m\rfloor )}. Now we arrive at an interesting recursive formula:

\displaystyle S(N) = \frac{n(n+1)}{2} - \sum_{m=2}^N S(\lfloor N/m \rfloor ).

At a first sight this looks more complicated, but there is a trick to keep in mind whenever you see a summation over {m} of terms of the form {\lfloor N/m \rfloor}: these quantities are constant on large intervals. Indeed,

\displaystyle \lfloor N/m \rfloor = d \Leftrightarrow md \leq N < m(d+1)\Leftrightarrow N/(d+1)<m \leq N/d.

Therefore we can change the index of summation from {m} to {d=\lfloor N/m \rfloor}. The range of {d} for which the interval {I_d = [N/(d+1),N/d]} contains more than one integer is of order {\sqrt(N)}. Indeed, {N/d-N/(d+1) = N/(d(d+1))}. Therefore for {d\leq \sqrt(N)} we should have at least one integer in the interval {I_d}. The part where {d} is larger than {\sqrt{N}} corresponds to {m} smaller than {\sqrt{N}}. Therefore, we can split {S(N)} into two sums, each of order {\sqrt{N}}. and get that

\displaystyle S(N) = \frac{N(N+1)}{2}- \sum_{m=2}^{\sqrt{N}} S(\lfloor N/m \rfloor)-\sum_{d=1}^{\sqrt{N}}\left(\lfloor N/d \rfloor-\lfloor N/(d+1)\rfloor\right)S(d),

where in the last sum we must make sure that {d \neq \lfloor N/d \rfloor} in order to avoid duplicating terms in the sum.

Therefore we replaced a sum until {N} to two sums with upper bound {\sqrt{N}}. The complexity is not {\sqrt{N}}, but something like {N^{2/3}} since we have a recursive computation. Nevertheless, with this new formula and using memoization, to keep track of the values of {S} already computed, we can compute {S(N)} very fast:

{S(10^6) = 303963552392} is computed instantly (vs {1} second with brute force)

{S(10^7) = 30396356427242} takes {1} second (vs {12} seconds with brute force)

{S(10^8)} takes {5} seconds (vs over {3} minutes with brute force)

{S(10^9)} takes {30} seconds

{S(10^{11})} takes about {12} minutes

etc. Recall that these computations are done in Pari GP, which is not too fast. If you use C++ you can compute {S(10^8)} in {0.2} seconds, {S(10^9)} in {1} second and {S(10^{10})} in {6} seconds and {S(10^{11})} in under a minute, if you manage to get past overflow errors.

A hint for Project Euler Pb 613

November 18, 2017 Leave a comment

The text for Problem 613 can be found here. The hint is the following picture 🙂

PE613

Project Euler – Problem 264

July 28, 2017 Leave a comment

Today I managed to solve problem 264 from Project Euler. This is my highest rating problem until now: 85%. You can click the link for the full text of the problem. The main idea is to find all triangles ABC with vertices having integer coordinates such that

  • the circumcenter O of each of the triangles is the origin
  • the orthocenter H (the intersection of the heights) is the point of coordinates (0,5)
  • the perimeter is lower than a certain bound

I will not give detailed advice or codes. You can already find a program online for this problem (I won’t tell you where) and it can serve to verify the final code, before going for the final result. Anyway, following the hints below may help you get to a solution.

The initial idea has to do with a geometric relation linking the points A, B, C, O and H. Anyone who did some problems with vectors and triangles should have come across the needed relation at some time. If not, just search for important lines in triangles, especially the line passing through O and H (and another important point).

Once you find this vectorial relation, it is possible to translate it in coordinates. The fact that points A, B, C are on a circle centered in O shows that their coordinates satisfy an equation of the form x^2+y^2=n, where n is a positive integer, not necessarily a square… It is possible to enumerate all solutions to the following equation for fixed n, simply by looping over x and y. This helps you find all lattice points on the circle of radius \sqrt{n}.

Once these lattice points are found one needs to check the orthocenter condition. The relations are pretty simple and in the end we have two conditions to check for the sum of the x and y coordinates. The testing procedure is a triple loop. We initially have a list of points on a circle, from the previous step. We loop over them such that we dont count triangles twice: i from 1 to m, j from i+1 to m, k from j+1 to m, etc. Once a suitable solution is found, we compute the perimeter using the classical distance formula between two points given in coordinates. Once the perimeter is computed we add it to the total.

Since the triple loop has cubic complexity, one could turn it in a double loop. Loop over pairs and construct the third point using the orthocenter condition. Then just check if the point is also on the circle. I didn’t manage to make this double loop without overcounting things, so I use it as a test: use double loops to check every family of points on a given circle. If you find something then use a triple loop to count it properly. It turns out that cases where the triple loop is needed are quite rare.

So now you have the ingredients to check if on a circle of given radius there are triangles with the desired properties. Now we just iterate over the square of the radius. The problem is to find the proper upper bound for this radius in order to get all the triangles with perimeter below the bound. It turns out that a simple observation can get you close to a near optimal bound. Since in the end the radii get really large and the size of the triangles gets really large, the segment OH becomes small, being of fixed length 5. When OH is very small, the triangle is almost equilateral. Just use the upper bound for the radius for an equilateral triangle of perimeter equal to the upper bound of 100000 given in the problem.

Using these ideas you can build a bruteforce algorithm. Plotting the values of the radii which give valid triangles will help you find that you only need to loop over a small part of the radii values. Factoring these values will help you reduce even more the search space. I managed to  solve the problem in about 5 hours in Pari GP. This means things could be improved. However, having an algorithm which can give the result in “reasonable” time is fine by me.

I hope this will help you get towards the result.

Project Euler 607

June 11, 2017 9 comments

If you like solving Project Euler problems you should try Problem number 607. It’s not very hard, as it can be reduced to a small optimization problem. The idea is to find a path which minimizes time, knowing that certain regions correspond to different speeds. A precise statement of the result can be found on the official page. Here’s an image of the path which realizes the shortest time:

euler607

 

Project Euler tips

March 28, 2017 2 comments

A few years back I started working on Project Euler problems mainly because it was fun from a mathematical point of view, but also to improve my programming skills. After solving about 120 problems I seem to have hit a wall, because the numbers involved in some of the problems were just too big for my simple brute-force algorithms.

Recently, I decided to try and see if I can do some more of these problems. I cannot say that I’ve acquired some new techniques between 2012-2016 concerning the mathematics involved in these problems. My research topics are usually quite different and my day to day programming routines are more about constructing new stuff which works fast enough than optimizing actual code. Nevertheless, I have some experience coding in Matlab, and I realized that nested loops are to be avoided. Vectorizing the code can speed up things 100 fold.

So the point of Project Euler tasks is making things go well for large numbers. Normally all problems are tested and should run within a minute on a regular machine. This brings us to choosing the right algorithms, the right simplifications and finding the complexity of the algorithms involved.

Read more…

Project Euler Problem 285

March 25, 2017 Leave a comment

Another quite nice problem from Project Euler is number 285. The result of the problem depends on the computation of a certain probability, which in turn is related to the computation of a certain area. Below is an illustration of the computation for k equal to 10.

pb285_10

To save you some time, here’s a picture of the case k=1 which I ignored and spent quite a lot of time debugging… Plus, it only affects the last three digits or so after the decimal point…

pb285_1

Here’s a Matlab code which can construct the pictures above and can compute the result for low cases. To solve the problem, you should compute explicitly all these areas.


function problem285(k)

N = 100000;

a = rand(1,N);
b = rand(1,N);

ind = find(abs(sqrt((k*a+1).^2+(k*b+1).^2)-k)<0.5);

plot(a(ind),b(ind),'.');
axis equal

M = k;
pl = 1;

for k=1:M
if mod(k,100)==0
k
end
r1 = (k+0.5)/k;
r2 = (k-0.5)/k;

f1 = @(x) (x<=(-1/k+r1)).*(x>=(-1/k-r1)).*(sqrt(r1^2-(x+1/k).^2)-1/k).*(x>=0).*(x<=1); f1 = @(x) f1(x).*(f1(x)>=0);
f2 = @(x) (x<=(-1/k+r2)).*(x>=(-1/k-r2)).*(sqrt(r2^2-(x+1/k).^2)-1/k).*(x>=0).*(x<=1); f2 = @(x) f2(x).*(f2(x)>=0);

if k == pl
thetas = linspace(0,pi/2,200);
hold on
plot(-1/k+r1*cos(thetas),-1/k+r1*sin(thetas),'r','LineWidth',2);
plot(-1/k+r2*cos(thetas),-1/k+r2*sin(thetas),'r','LineWidth',2);
plot([0 1 1 0 0],[0 0 1 1 0],'k','LineWidth',3);
hold off
axis off
end

A(k) = integral(@(x) f1(x)-f2(x),0,1);

end

xs = xlim;
ys = ylim;

w = 0.01;
axis([xs(1)-w xs(2)+w ys(1)-w ys(2)+w]);

sum((1:k).*A)

Fireworks – Project Euler 317

March 19, 2017 Leave a comment

You can read the text of the problem here. The idea is that we have an explosion at a given height in a uniform gravitational field (no friction/wind). Supposing that all particles go outwards from the explosion point with a constant initial speed, what is the shape of the body formed by these particles? A hint is given in the picture below with a nice Matlab simulation.

euler317

Now what happens if we add a little bit of wind? Here’s the perturbation obtained when adding a 10m/s uniform wind speed vs the initial configuration. Something like this would be a lot more challenging 🙂

pb317_wind

Project Euler Problem 144 – Laser light escaping an ellipse

February 5, 2017 Leave a comment

ellipse

Project Euler – problem 144 – visualization of the solution in Matlab

Linear programming #1 – Project Euler 185

January 28, 2017 11 comments

I was recently faced with a very nice challenge from Project Euler – Problem 185. The idea is to find a number with a fixed number of digits by making guesses. Each time you are told how many digits you got right. By got right, I mean guessing the right digit on the right position. If you find a digit which is in the number, but on a different position, you don’t know…

There is a test case with 5 digits:

90342 ;2 correct
70794 ;0 correct
39458 ;2 correct
34109 ;1 correct
51545 ;2 correct
12531 ;1 correct

with unique solution 39542 and the difficult case with 16 digits

5616185650518293 ;2 correct
3847439647293047 ;1 correct
5855462940810587 ;3 correct
9742855507068353 ;3 correct
4296849643607543 ;3 correct
3174248439465858 ;1 correct
4513559094146117 ;2 correct
7890971548908067 ;3 correct
8157356344118483 ;1 correct
2615250744386899 ;2 correct
8690095851526254 ;3 correct
6375711915077050 ;1 correct
6913859173121360 ;1 correct
6442889055042768 ;2 correct
2321386104303845 ;0 correct
2326509471271448 ;2 correct
5251583379644322 ;2 correct
1748270476758276 ;3 correct
4895722652190306 ;1 correct
3041631117224635 ;3 correct
1841236454324589 ;3 correct
2659862637316867 ;2 correct

While the small case could be tackled using a pure brute force approach (only 10^5) cases to check, the second case becomes intractable. Looping through all 10^{16} cases would take ages. One could try genetic algorithms or other algorithms based on randomness. Recursive approaches are also possible.

There is however a way to express this problem which makes it solvable right away using a linear programming solver: that is an algorithm which finds valid solutions given some constraints. How do we find these constraints? There are essentially two types of constraints in our case:

  • each of the positions of the result contains one digit from 0 to 9
  • in each of the guesses given above we have a fixed number of correct digits

Read more…