Fast algorithm for solving diophantine equation $x^4=a^4+b^4+c^4+d^4$

184 Views Asked by At

This problem was posed to an acquaintance of mine (at their university) and piqued my interest so I tried to solve it. The description goes as follows:

Write a program that finds a solution to the following equation: $x^4=a^4+b^4+c^4+d^4$. One solution is $651^4 = 240^4 + 340^4 + 430^4 + 599^4$ however you are tasked to finding a smaller solution. The program is not allowed to use any type of array/matrix.

The goal is to solve this in a reasonable/fastest amount of time. I have designed a solution that finishes in 10 seconds starting from $x=2$ up to $x=353$ (I know runtimes are arbitrary per machine but I don't want to do an asymptotic analysis at the moment). However I'm not at all versed in this kind of mathematics so I'm looking to see if there's a different approach or some algorithmic optimization I'm not aware of that would make this much faster.

A few things to note:

  • The weird array/matrix restriction essentially blocks dynamic programming. Not sure why they added that but w/e.
  • The smaller solution is $353^4 = 30^4 + 120^4 + 272^4 + 315^4$. This might will help experimentation.
  • The specific problem was to be solved in C language but here I'm looking for an algorithm so pseudo code or any language (no esoteric languages please, not even stuff like APL) is fine.
  • No multithreading/parallelism.
  • A good solution should be able to find the 3rd biggest solution in a reasonable amount of time $2487^4 = 435^4 + 710^4 + 1384^4 + 2420^4$.

EDIT: Was asked to describe my current solution. The basic premise is a brute force one where I run incrementing loops for each value of $x$ followed by $a, b, c$ etc. There are two "tricks".

  1. Each successive variable is always larger than the previous one $d > c > b > a$ and all are smaller than $x-1$.
  2. Since $d$ is the largest and thus would take the longest to iterate through, I don't iterate but simply check whether $\sqrt[4]{x^4 - a^4 - b^4 - c^4} = d$ is an integer.

Here is some fully functional C code:

#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
/**
 * Checks if the provided number n is a perfect square before
 * taking the actual square root (which is a very slow operation).
 */
uint64_t perfectSquareRoot(uint64_t n)
{
  uint64_t h = n & 0xF; // last hexadecimal "digit"
  if (h > 9)
    return 0; // return immediately in 6 cases out of 16.

  // Take advantage of Boolean short-circuit evaluation
  if ( h != 2 && h != 3 && h != 5 && h != 6 && h != 7 && h != 8 )
  {
    uint64_t sqrtN = sqrt(n);
    uint64_t t = (uint64_t) floor(sqrtN + 0.5 );
    if(t*t == n) {
      return sqrtN;
    }
  }
  return 0;
}

int main(int argc, char** argv) {
  int x,a,b,c,d;
  clock_t begin = clock();
  for(x = 2; x < 651; x++) {
    printf("Trying x = %d\n", x);
    uint64_t x4 = pow(x,4);
    for(a=1; a<x-1; a++) {
      uint64_t a4 = pow(a,4);
      uint64_t ab4 = 0; 
      for(b=a; ab4 <= x4; b++) {
      ab4 = a4+pow(b,4);
      uint64_t abc4 = 0; 
        for(c=b; abc4 <= x4; c++) {
          abc4 = ab4+pow(c,4);
          uint64_t d4 = x4 - abc4; // take the difference between x^4 - a^4+b^4+c^4 = d^4
          uint64_t d2 = perfectSquareRoot(d4); // if d4 is a perfect square of a perfect square we found our number
          if(d2) {
            d = perfectSquareRoot(d2);
            if(d) {
              if(x4 == abc4 + pow(d,4)) { // do a final reverse check to handle numerical instability
                printf("x=%d, a=%d, b=%d, c=%d, d=%d\n", x,a,b,c,d);
                goto endlbl;
              }
            }
          }
        }
      }
    }
  }
  endlbl:;
  clock_t end = clock();
  printf("Time Spent: %f", (double) (end - begin / CLOCKS_PER_SEC));
  return 0;
}
1

There are 1 best solutions below

1
On

Part one, brute force: Here is an alternative brute force implementation. The code is julia code, copy+pasted in Appendix 1, my first attempt to implement something in julia, i took this approach after having the "same code" in sage and being unhappy with the waiting time. Since julia should have a quick way to go with loops & CO, i gave it a try.

Some words on the implementation. Consider solutions of the equation: $$ \tag{$*$} x^4 = a^4+b^4+c^4+d^4\ , $$ and try to enumerate them. (This is different from finding a(n infinite) family of solutions of the above diophantine equation, instead we want to list all possible $(x;a,b,c,d)$ below some bound, and check that we have $(*)$. In the process, we can of course eliminate "in time" some values, if there is a good reason to do this.) By symmetry, we can restrict to those variables that satisfy: $$ x > a \ge b\ge c\ge d>0\ . $$ In particular, we have: $$ \begin{aligned} a^4 &<x^4\underbrace{\le}_{\text{but }\ne} a^4+a^4+a^4+a^4=4a^4\ ,&&\text{so} & \frac 1{4^{1/4}}x &<a<x\ , \\ N &:= x^4 -a^4=:n^4\ ,\\ n^4 = N & = b^4 + c^4 + d^4 < b^4+b^4+b^4=3b^4\ ,&&\text{so} & \frac 1{3^{1/4}}n &\le b\le\min(a, n)\ , \\ M &:= x^4 -a^4 -b^4=:m^4\ ,\\ m^4 = M & = c^4 + d^4 < c^4+c^4=2c^4\ ,&&\text{so} & \frac 1{2^{1/4}}m &\le c\le\min(b, m)\ . \end{aligned} $$ With these restrictions the hierarchic loops for x, then a, then b, then c are thiner. The brute force does not spent time at irrelevant places. We get the following results in time: $$ \begin{array}{|r||r|r|r|r|l|} \hline x&a&b&c&d&\text{time in between}\\\hline\hline 353 & 315 & 272 & 120 & 30 & \text{after }2.819s\\\hline 651 & 599 & 430 & 340 & 240 & \text{after further }17.146s\\\hline 2487 & 2420 & 1384 & 710 & 435 & \text{after further }4200.359s\sim1h\; 10'\;1'' \\\hline 2501 & 2365 & 1432 & 1190 & 1130 & \text{after further }90.856s\sim1'\; 30'' \\\hline 2829 & 2745 & 1546 & 1010 & 850 & \text{after further }2837.045s\sim47'\; 17'' \\\hline 3723 & 3152 & 2460 & 2345 & 2270 & \text{after further }15891.990s\sim4h\;24'\; 51'' \\\hline 3973 & 3395 & 3230 & 1652 & 350 & \text{after further }5967.016s\sim1h\;39'\; 27'' \\\hline 4267 & 4094 & 2650 & 1060 & 205 & \text{after further }9992.362s\sim2h\;45'\; 32'' \\\hline \end{array} $$ This was the brute force approach, using it i've got the best results. Minimal brain, maximal success. One can already stop here. (But since the question asks also for ideas to proceed, here is some added information about what i also tried...)


Part two, using the arithmetic of $\Bbb Z[i]$:

I have also tried to restrict the part of the search by means of arithmetics. To illustrate the situation, i will pick some random value for $(x,a,b)$, and show how to search for $(c,d)$ in a different manner, not looping through all possible values. First of all, we take some random case where this may make sense:

sage: x = random.choice(range(10^15));
....: a = random.choice(range(ceil(x/sqrt(2.)), x-1));
....: n = float(x^4 - a^4)^(1/4)
....: b = random.choice(range(ceil(n/3.^(1/4.)), min(a, floor(n))))
sage: x, a, b
(608370828066247, 542212071706557, 364185557122218)

sage: x^4 - a^4 - b^4
32961715639129459861921278445069934729992837454625353749504

(A $c$-loop is now maybe not a too good idea.) The question, the partial programming task is as follows, we have some numbers $x,a,b$. Can we find in this special case some $c,d$ satisfying $(*)$?

This means: $$c^4+d^4= M:=32961715639129459861921278445069934729992837454625353749504\ .$$ Let $C=c^2$, $D=d^2$. Can we find at least $C,D$ first, all possible choices?! Yes, and we can do this algorithmically as follows. If $C^2+D^2=M$, then we have in the gaussian ring $\Bbb Z[i]$ (with unique factorization): $$ M =(C+iD)(C-iD)\ . $$ Here $i=\sqrt{-1}$. Each factorization over $\Bbb Z[i]$ comes from one over $\Bbb Z$, so the first step is to factor $M$:

sage: factor(M)
2^10 * 7 * 13 * 223 * 491 * 3756997069237 * 859886732253410560003268209731690791

And since the factor $7$, a prime congruent to three modulo four, comes to an odd power, we can already eliminate this case from the discussion, there is no chance to factorize. We have a quick verdict after a long/expensive factorization process.

OK, we are generating so long random cases, till we get only even powers for such "bad" (inert) primes.

sage: ok = False
....: while not ok:
....:     ok = True    # optimistic view...
....:     x = random.choice(range(10^15));
....:     a = random.choice(range(ceil(x/sqrt(2.)), x-1));
....:     n = float(x^4 - a^4)^(1/4)
....:     b = random.choice(range(ceil(n/3.^(1/4.)), min(a, floor(n))))
....:     for p, mul in factor(x^4 - a^4 - b^4):
....:         if p % 4 == 3 and mul % 2 == 1:
....:             ok = False
....:             break
....: 
sage: x, a, b
(185166234028427, 178498978831744, 88594416503095)
sage: M = x^4 - a^4 - b^4
sage: factor(M)
2^4 * 5 * 1626851909 * 758983842377232880432972026006638927864216081

We have a big candidate $M$, and try to write it in the form $C^2+D^2$ first. All ways to do this are needed. For this, we write the prime pieces in this factorization as wanted, we factorize them over $\Bbb Z[i]$, in code $i$ is j to not distroy the default $i$ variable in sage:

sage: K.<j> = QuadraticField(-1)
sage: factor(K(5))
(j) * (-j - 2) * (2*j + 1)
sage: factor(K(2))
(-j) * (j + 1)^2
sage: factor(K(1626851909))
(-1) * (10097*j - 39050) * (10097*j + 39050)
sage: factor(K(758983842377232880432972026006638927864216081))
(-1) * (-12375789567144879751684*j - 24613485632209445972735) * 
       (-12375789567144879751684*j + 24613485632209445972735)

(Here, $\pm 1$, $\pm i$ are units, we ignore them for our purpose. Also $1\pm i$ are conjugated, we will place $1+i$ on one side, $1-i$ on the other side, but it doesn't matter, they are conjugated...) And now we separate in conjugated pieces of same norm, each case with each case, and build products. All the needed products are, taking $(1+2i)$ on a fixed side: $$ \small \begin{aligned} &(1+2i)(1+i)^4(39050+10097i)(24613485632209445972735+12375789567144879751684i) &&\text{and}\\ &(1-2i)(1-i)^4(39050-10097i)(24613485632209445972735-12375789567144879751684i)\\ \\[3mm] &(1+2i)(1+i)^4(39050+10097i)(24613485632209445972735-12375789567144879751684i) &&\text{and}\\ &(1-2i)(1-i)^4(39050-10097i)(24613485632209445972735+12375789567144879751684i)\\ \\[3mm] &(1+2i)(1+i)^4(39050-10097i)(24613485632209445972735+12375789567144879751684i) &&\text{and}\\ &(1-2i)(1-i)^4(39050+10097i)(24613485632209445972735-12375789567144879751684i)\\ \\[3mm] &(1+2i)(1+i)^4(39050-10097i)(24613485632209445972735-12375789567144879751684i) &&\text{and}\\ &(1-2i)(1-i)^4(39050+10097i)(24613485632209445972735+12375789567144879751684i)\\ \end{aligned} $$ We multiply, and get for the first case:

sage: (1+2*j)*(1+j)^4*(39050+10097*j)*\
....: (24613485632209445972735+12375789567144879751684*j)
-9616773921528241436220249196*j + 2509582509490142584789530352
sage: C, D = _
sage: C^2 + D^2 == M
True
sage: C
2509582509490142584789530352
sage: D
-9616773921528241436220249196

Now we would adjust signs (for D only) and look if $C=c^2$ and $D=d^2$. At any rate, the factorization was replacing the $c$-loop, which becomes an issue only for "bigger" $M$-values involved.

How does it work with a solution? Consider the triple $x,a,b=2829,2745,1546$. Then $$ M=2829^4-2745^4-1546^4= 2^5 \cdot 5^4 \cdot 73 \cdot 241 \cdot 4441 \\ =(1+i)^5(1-i)^5\cdot(2+i)^4(2-i)^4\cdot(8+3i)(8-3i)\cdot(15+4i)(15-4i) \cdot (60+29i)(60-29i)\ . $$ Now we consider from each pair only one number, all the list is, fixing $(60+29i)$ "on one side": $$ \begin{aligned} (1+i)^5\cdot(2+i)^4(2-i)^0\cdot(8+3i)\cdot(15+4i)\cdot(60+29i) &= 672452i + 1053764 \ ,\\ (1+i)^5\cdot(2+i)^3(2-i)^1\cdot(8+3i)\cdot(15+4i)\cdot(60+29i) &= -439540i + 1170220 \ ,\\ (1+i)^5\cdot(2+i)^2(2-i)^2\cdot(8+3i)\cdot(15+4i)\cdot(60+29i) &=-1199900i + 350500 \ ,\\ (1+i)^5\cdot(2+i)^1(2-i)^3\cdot(8+3i)\cdot(15+4i)\cdot(60+29i) &=-1000340i - 749620 \ ,\\ (1+i)^5\cdot(2+i)^0(2-i)^4\cdot(8+3i)\cdot(15+4i)\cdot(60+29i) &= -508i - 1250044 \ ,\\[3mm] (1+i)^5\cdot(2+i)^4(2-i)^0\cdot(8-3i)\cdot(15+4i)\cdot(60+29i) &=-186244i + 1236092 \ ,\\ (1+i)^5\cdot(2+i)^3(2-i)^1\cdot(8-3i)\cdot(15+4i)\cdot(60+29i) &= -1100620i + 592660 \ ,\\ (1+i)^5\cdot(2+i)^2(2-i)^2\cdot(8-3i)\cdot(15+4i)\cdot(60+29i) &= -1134500i - 524900 \ ,\\ (1+i)^5\cdot(2+i)^1(2-i)^3\cdot(8-3i)\cdot(15+4i)\cdot(60+29i) &= -260780i - 1222540 \ ,\\ (1+i)^5\cdot(2+i)^0(2-i)^4\cdot(8-3i)\cdot(15+4i)\cdot(60+29i) &= 821564i - 942148 \ ,\\[3mm] (1+i)^5\cdot(2+i)^4(2-i)^0\cdot(8+3i)\cdot(15-4i)\cdot(60+29i) &= 58468i + 1248676 \ ,\\ (1+i)^5\cdot(2+i)^3(2-i)^1\cdot(8+3i)\cdot(15-4i)\cdot(60+29i) &= -963860i + 795980 \ ,\\ (1+i)^5\cdot(2+i)^2(2-i)^2\cdot(8+3i)\cdot(15-4i)\cdot(60+29i) &=-1215100i - 293500 \ ,\\ (1+i)^5\cdot(2+i)^1(2-i)^3\cdot(8+3i)\cdot(15-4i)\cdot(60+29i) &=-494260i - 1148180 \ ,\\ (1+i)^5\cdot(2+i)^0(2-i)^4\cdot(8+3i)\cdot(15-4i)\cdot(60+29i) &=621988i - 1084316 \ ,\\[3mm] (1+i)^5\cdot(2+i)^4(2-i)^0\cdot(8-3i)\cdot(15-4i)\cdot(60+29i) &=-776996i + 979228 \ ,\\ (1+i)^5\cdot(2+i)^3(2-i)^1\cdot(8-3i)\cdot(15-4i)\cdot(60+29i) &=-1249580i - 34060 \ ,\\ \color{blue}{ (1+i)^5\cdot(2+i)^2(2-i)^2\cdot(8-3i)\cdot(15-4i)\cdot(60+29i) } & \color{blue}{=-722500i - 1020100} \ ,\\ (1+i)^5\cdot(2+i)^1(2-i)^3\cdot(8-3i)\cdot(15-4i)\cdot(60+29i) &=382580i - 1190060 \ ,\\ (1+i)^5\cdot(2+i)^0(2-i)^4\cdot(8-3i)\cdot(15-4i)\cdot(60+29i) &=1181596i - 407972 \ , \end{aligned} $$ In each of the cases we have to adjust the sign of the real, and of the imaginary part, then check if both are squares of integers. The solution comes from the blue line. If there are any "inert" primes (those which are three modulo four) in the decomposition, they have to be distributed equally on each side.

This explicit procedure may be also used to cover some cases, it may be useful when we search for solutions for "higher" $x$ values in some small range.

Moral: The factorization part is the weak step, so this solution is more qweak then quick.


Appendix 1: Used Julia code in the sequel. Some comments in advance. The package Hecke is imported only to have that is_square functionality. There is no point for me in making this function even more performant. I am happy to wait those seconds or hours when the code runs, my focus is on a (mathematically) structural way to implement the objects. The clock is given by TickTock, when typing tick() it starts ticking, at a tock() it stops, delivering info to the amount of time passed. So below, we first load some libraries, this takes some good seconds, after that the clock ticks, and in some few seconds we have the first solution. We stop the clock, show the solution, check it, then start again the clock from zero, the second solution comes then in less than half a minute after the first one. Again we stop the clock, show the solution, check it, and start hunting the third solution...

#!/usr/bin/julia

using Hecke
using TickTock
println("Using Hecke, TickTock :: The clock starts ticking now...\n")
tick()

SQRTSQRT4 = sqrt(2.)
SQRTSQRT3 = 3.0^(1/4)
SQRTSQRT2 = 2.0^(1/4)

solutions = []
for x = 1:10000
    if x % 100 == 0 println("\tx = $x so far...") end
    for a = Int(ceil(x/SQRTSQRT4)) : (x - 1)
        N = x^4 - a^4
 n = N^0.25
 for b = Int(floor(n/SQRTSQRT3)) : min(a, Int(floor(n)))
     M = N - b^4
            # if prod([p % 4 == 3 && mul % 2 == 1 ? 0 : 1 for (p, mul) in factor(M)]) == 0 continue end
     m = M^0.25
     for c = Int(floor(m/SQRTSQRT2)) : min(b, Int(floor(m)))
      K = M - c^4
  if is_square(K)
      dd = Int(sqrt(K))
      if is_square(dd)
          d = Int(sqrt(dd))
        sol = [a, b, c, d]
         sort!(sol)
         if sol in solutions continue end
                        g = gcd(sol...)
   if g > 1
             println("\t... non primitive solution $sol")
            else
                            tock()
                    println("\nSOLUTION $sol\n\tCHECK:")
                            println("$(x^4) = $x^4 = x^4")
                            println("$(a^4 + b^4 + c^4 + d^4) = $a^4 + $b^4 + $c^4 + $d^4 = a^4 + b^4 + c^4 + d^4\n")
                push!(solutions, sol)
                            println("...restarting the clock, searching for the next solution...")
                            tick()
                        end
                    end
                end
            end
        end
    end
end

                    

Appendix 2: The above code was saved on my hard disk under ~/stackexchange/answers_stackexchange_4625494.jl and after making it executable with chmod +x (linux box, of course) it was started.

Results:

[dan@k9 ~/stackexchange]$ ./answers_stackexchange_4625494.jl 
Using Hecke, TickTock :: The clock starts ticking now...

[ Info:  started timer at: 2023-01-26T16:44:02.099
    x = 100 so far...
    x = 200 so far...
    x = 300 so far...
[ Info:          2.819008529s: 2 seconds, 819 milliseconds

SOLUTION [30, 120, 272, 315]
    CHECK:
15527402881 = 353^4 = x^4
15527402881 = 315^4 + 272^4 + 120^4 + 30^4 = a^4 + b^4 + c^4 + d^4

...restarting the clock, searching for the next solution...
[ Info:  started timer at: 2023-01-26T16:44:05.068
    x = 400 so far...
    x = 500 so far...
    x = 600 so far...
[ Info:         17.146349122s: 17 seconds, 146 milliseconds

SOLUTION [240, 340, 430, 599]
    CHECK:
179607287601 = 651^4 = x^4
179607287601 = 599^4 + 430^4 + 340^4 + 240^4 = a^4 + b^4 + c^4 + d^4

...restarting the clock, searching for the next solution...
[ Info:  started timer at: 2023-01-26T16:44:22.215
    x = 700 so far...
    ... non primitive solution [60, 240, 544, 630]
    x = 800 so far...
    x = 900 so far...
    x = 1000 so far...
    ... non primitive solution [90, 360, 816, 945]
    x = 1100 so far...
    x = 1200 so far...
    x = 1300 so far...
    ... non primitive solution [480, 680, 860, 1198]
    x = 1400 so far...
    ... non primitive solution [120, 480, 1088, 1260]
    x = 1500 so far...
    x = 1600 so far...
    x = 1700 so far...
    ... non primitive solution [150, 600, 1360, 1575]
    x = 1800 so far...
    x = 1900 so far...
    ... non primitive solution [720, 1020, 1290, 1797]
    x = 2000 so far...
    x = 2100 so far...
    ... non primitive solution [180, 720, 1632, 1890]
    x = 2200 so far...
    x = 2300 so far...
    x = 2400 so far...
    ... non primitive solution [210, 840, 1904, 2205]
[ Info:       4200.359438085s: 1 hour, 10 minutes, 359 milliseconds

SOLUTION [435, 710, 1384, 2420]
    CHECK:
38256315558561 = 2487^4 = x^4
38256315558561 = 2420^4 + 1384^4 + 710^4 + 435^4 = a^4 + b^4 + c^4 + d^4

...restarting the clock, searching for the next solution...
[ Info:  started timer at: 2023-01-26T17:54:23.381
    x = 2500 so far...
[ Info:         90.856888575s: 1 minute, 30 seconds, 856 milliseconds

SOLUTION [1130, 1190, 1432, 2365]
    CHECK:
39125037510001 = 2501^4 = x^4
39125037510001 = 2365^4 + 1432^4 + 1190^4 + 1130^4 = a^4 + b^4 + c^4 + d^4

...restarting the clock, searching for the next solution...
[ Info:  started timer at: 2023-01-26T17:55:54.238
    x = 2600 so far...
    ... non primitive solution [960, 1360, 1720, 2396]
    x = 2700 so far...
    x = 2800 so far...
    ... non primitive solution [240, 960, 2176, 2520]
[ Info:       2837.045921869s: 47 minutes, 17 seconds, 45 milliseconds

SOLUTION [850, 1010, 1546, 2745]
    CHECK:
64051866504081 = 2829^4 = x^4
64051866504081 = 2745^4 + 1546^4 + 1010^4 + 850^4 = a^4 + b^4 + c^4 + d^4

...restarting the clock, searching for the next solution...
[ Info:  started timer at: 2023-01-26T18:43:11.284
    x = 2900 so far...
    x = 3000 so far...
    x = 3100 so far...
    ... non primitive solution [270, 1080, 2448, 2835]
    x = 3200 so far...
    ... non primitive solution [1200, 1700, 2150, 2995]
    x = 3300 so far...
    x = 3400 so far...
    x = 3500 so far...
    ... non primitive solution [300, 1200, 2720, 3150]
    x = 3600 so far...

    x = 3700 so far...
[ Info:      15891.990908712s: 4 hours, 24 minutes, 51 seconds, 990 milliseconds

SOLUTION [2270, 2345, 2460, 3152]
    CHECK:
192119808411441 = 3723^4 = x^4
192119808411441 = 3152^4 + 2460^4 + 2345^4 + 2270^4 = a^4 + b^4 + c^4 + d^4

...restarting the clock, searching for the next solution...
[ Info:  started timer at: 2023-01-26T23:52:06.543
    x = 3800 so far...
    ... non primitive solution [330, 1320, 2992, 3465]
    x = 3900 so far...
    ... non primitive solution [1440, 2040, 2580, 3594]
[ Info:       5967.016968883s: 1 hour, 39 minutes, 27 seconds, 16 milliseconds

SOLUTION [350, 1652, 3230, 3395]
    CHECK:
249157669603441 = 3973^4 = x^4
249157669603441 = 3395^4 + 3230^4 + 1652^4 + 350^4 = a^4 + b^4 + c^4 + d^4

...restarting the clock, searching for the next solution...
[ Info:  started timer at: 2023-01-27T01:31:33.561
    x = 4000 so far...
    x = 4100 so far...
    x = 4200 so far...
    ... non primitive solution [360, 1440, 3264, 3780]
[ Info:        9992.36284933s: 2 hours, 46 minutes, 32 seconds, 362 milliseconds

SOLUTION [205, 1060, 2650, 4094]
    CHECK:
331505372729521 = 4267^4 = x^4
331505372729521 = 4094^4 + 2650^4 + 1060^4 + 205^4 = a^4 + b^4 + c^4 + d^4

...restarting the clock, searching for the next solution...
[ Info:  started timer at: 2023-01-27T04:18:05.924
    x = 4300 so far...
          

Appendix 3:

I've implemented also the arithmetical approach, which comes in after a $(x,a,b)$ enumeration in some wanted range. The code was not successful, so it is skipped here.