2

I'm trying to get all the Pythagorean quadruples:

a^2 + b^2 + c^2 = d^2 when a, b, c <= 1000,

My code generates all of them (85490) but it takes around 10 minutes.

I am trying to reduce the execution time. How can I improve the execution time?. Any suggestion please.

Here is my code.

   static int isSquare(int n)
   {
      int m = (int) Math.sqrt(n);

      return m * m == n ? m : 0;
   }

   static List<List<Integer>> allQuadraples = new ArrayList<>();

   static int findQuadraples(int range)
   {
      int total = 0;

      for (int a = 1; a <= range; a++)
         for (int b = 1; b <= range; b++)
            for (int c = 1; c <= range; c++)
            {
               int sum = a * a + b * b + c * c;

               int d = isSquare(sum);

               if (d != 0) // a possible Quadruple
               {
                  List<Integer> oneQuadraple = new ArrayList<>(Arrays.asList(a, b, c, d));
                  Collections.sort(oneQuadraple); // sorting before insertion for comparing later
                  if (!allQuadraples.contains(oneQuadraple))
                  {
                     System.out.println(oneQuadraple);
                     allQuadraples.add(oneQuadraple);
                     total++;
                  }
               }
            }

      return total;
   }
User_67128
  • 1,230
  • 8
  • 21
abhimanyue
  • 196
  • 1
  • 12
  • You can check this https://math.stackexchange.com/questions/2088960/solutions-for-a2b2c2-d2 – User_67128 Feb 20 '20 at 16:55
  • 1
    Note that without changing this brute force approach, you can gain time with the following: 1. Restrict the search for `b>=a` and `c>= b` and 2. factorize calculation of `a*a` and `b*b` – Damien Feb 20 '20 at 17:18
  • 1
    1. You do not want to call sqrt each time. You can create map of squares and theirs roots. 2. You should rewrite you loops using the fact that (in addition to mentioned above assumption `ac && a+c>b && b+c>a` – y_ug Feb 20 '20 at 17:22
  • I tested my two proposals in C++ and get the same result as you, in about 1s, with still the same basically brute force approach, but not the need to check for duplicates – Damien Feb 20 '20 at 17:51
  • @Damien, if you do not check for duplicate, how can you find the total unique quadruples? – User_67128 Feb 20 '20 at 17:54
  • 2
    @ManojBanik With the conditions `b>=a` and `c>= b` I avoid all duplicates. and I get the same total as OP: 85490 – Damien Feb 20 '20 at 17:59
  • @y_ug, "a+b>c && a+c>b && b+c>a" is not true at all, check this [1, 6, 18, 19], [2, 3, 6, 7] [2, 4, 4, 6] [2, 5, 14, 15] – User_67128 Feb 20 '20 at 18:03
  • Note: on my linux VM instead of Windows/Cygwin, I got 0.3s, but still in C++ – Damien Feb 20 '20 at 18:05

2 Answers2

2

So, if you still need to store all the quadruples then this is the new function, (Thanks to Damien).

It took only 1.5 sec. for finding and storing all 85490.

   static int findQuadraples(int range)
   {
      int total = 0;

      for (int a = 1; a <= range; a++)
         for (int b = a; b <= range; b++)
            for (int c = b; c <= range; c++)
            {
               int sum = a * a + b * b + c * c;
               int d = isSquare(sum);

               if (d != 0) // a possible Quadruple
               {
                  //System.out.println(Arrays.asList(a, b, c, d));
                  allQuadraples.add(Arrays.asList(a, b, c, d));
                  total++;
               }
            }

      return total;
   }

Without saving into an ArrayList, it takes 1.3 sec.

User_67128
  • 1,230
  • 8
  • 21
  • Note: I also tested to limit the number of multiplications with `int a2=a*a` etc. but in C++ the gain was negligible. Maybe to be tested in java. You may also mention in the post that the main advantage is to avoid the search for duplicates (+1) – Damien Feb 20 '20 at 18:22
  • 1
    You could change `new ArrayList<>(Arrays.asList(Arrays.asList(a, b, c, d))` to just `Arrays.asList(a, b, c, d)`. It's an immutable list but you don't change them anyway ;) – vicpermir Feb 20 '20 at 18:27
  • @vicpermir, yes, it takes less time. Updated my answer. – User_67128 Feb 20 '20 at 18:40
  • Woops, seems I pasted the `Arrays.asList(` twice in my comment, but you got the idea hehe – vicpermir Feb 20 '20 at 18:50
2

Here is a different approach in a slower language. Which is to match up a^2 + b^2 with d^2 - c^2. The operations are slower, but the algorithm is O(n^2) rather than O(n^3).

In Python this took < 1.3 seconds on my laptop.

#! /usr/bin/env python3
limit = 1000

square_differences = {}
for c in range(limit, 0, -1):
    for d in range (c+1, 2*c):
        diff = d*d - c*c
        if 3*limit*limit< diff:
            break
        elif diff not in square_differences:
            square_differences[diff] = []
        square_differences[diff].append((c, d))

quads = []
for a in range(1, limit+1):
    for b in range(a, limit+1):
        s = a*a + b*b
        if s in square_differences:
            for c, d in square_differences[s]:
                if c < b:
                    break
                else:
                    quads.append((a, b, c, d))

print(len(quads))
btilly
  • 43,296
  • 3
  • 59
  • 88
  • Does your code generate all quadruples? because, there are cases when different "d^2 - c^2" produce same answer and you didn't store all of them by "diff not in square_differences" statement. I found it when I was trying to convert your idea with Java. – User_67128 Feb 21 '20 at 15:47
  • @ManojBanik It generates all quadruples. The trick is that I am forcing `a <= b <= c <= d`. So if `d >= 2c` then `a^2 + b^2 + c^2 <= 3c^2 < 4c^2 = (2c)^2 <= d^2`. And that inequality in the middle is why I only need to store `d^2-c^2` when `c < d < 2c`. I also store for any particular output the answers by descending `c`. That lets me stop looking at the rest of the list once `c < b`. – btilly Feb 21 '20 at 19:31
  • 1
    finally I was able to implement your `O(n^2)` idea in `Java`, Yes, it is faster than my previous one, for `1000` it takes `0.7 sec`. compared to `1.3` for `2000` it takes `3.1 sec`. compared to `9.9` for `3000` it takes `10.1 sec`. compared to `33.9`. – User_67128 Feb 22 '20 at 19:06