File Coverage

congruent_numbers.c
Criterion Covered Total %
statement 334 347 96.2
branch 847 1196 70.8
condition n/a
subroutine n/a
pod n/a
total 1181 1543 76.5


line stmt bran cond sub pod time code
1             #include
2             #include
3              
4             /*
5             * A nice discussion of congruent numbers can be found in:
6             *
7             * https://pub.math.leidenuniv.nl/~stevenhagenp/ANTproc/19yui.pdf
8             *
9             */
10              
11             #include "ptypes.h"
12             #include "congruent_numbers.h"
13             #define FUNC_isqrt 1
14             #define FUNC_is_perfect_square 1
15             #include "util.h"
16             #include "factor.h"
17             #include "rootmod.h"
18              
19             #define SWAP2(x,y) { UV t; t=x; x=y; y=t; }
20              
21             /******************************************************************************/
22              
23             /* We only look at the non-square portion of n. */
24 657           static void remove_square_part(factored_t *nf) /* Turn n*c^2 into n */
25             {
26 657 100         if (nf->n > 3) {
27             uint16_t i, j;
28 2099 100         for (i = 0; i < nf->nfactors; i++)
29 1606 100         if (nf->e[i] > 1)
30 158           break;
31 651 100         if (i < nf->nfactors) {
32 158           UV N = 1;
33 474 100         for (i = 0, j = 0; i < nf->nfactors; i++)
34 316 100         if (nf->e[i] & 1) {
35 187           N *= nf->f[i];
36 187           nf->e[j] = 1;
37 187           nf->f[j++] = nf->f[i];
38             }
39 158           nf->n = N;
40 158           nf->nfactors = j;
41             }
42             }
43             /* factoredp_validate(nf); */
44 657           }
45              
46             /* Cycle through n! permutations of factors (if used). */
47 0           static factored_t permute_odd_factors(const factored_t NF, UV k)
48             {
49             factored_t nf;
50             int permvec[MPU_MAX_DFACTORS];
51 0           bool iseven = NF.f[0] == 2;
52 0           uint32_t noddfac = NF.nfactors - iseven;
53             uint16_t i;
54              
55 0           nf.n = NF.n;
56 0           nf.nfactors = NF.nfactors;
57 0 0         if (iseven) { nf.f[0] = 2; nf.e[0] = NF.e[0]; }
58              
59 0           num_to_perm(k, noddfac, permvec);
60 0 0         for (i = 0; i < noddfac; i++) {
61 0           nf.f[i + iseven] = NF.f[permvec[i] + iseven];
62 0           nf.e[i + iseven] = NF.e[permvec[i] + iseven];
63             }
64 0           return nf;
65             }
66              
67             /******************************************************************************/
68              
69              
70             /* Tunnell's method, counting integer solutions to ternary quadratics.
71             * Assumes the weak BSD conjecture.
72             * Weak BSD holds for n < 42553. (Nemenzo 1998)
73             * Weak BSD holds for n < 71474. (Wado 2005)
74             * Weak BSD holds for n < 300000. (Matsuno 2005]
75             * Weak BSD holds for n < 1000000. (Matsuno 2006 + Elkies 2002)
76             *
77             * The final answer.
78             * Most of the rest of this file is trying to avoid calling this if possible.
79             */
80 161           static bool _is_congruent_number_tunnell(UV n)
81             {
82 161           UV x, y, z, limz, limy, limx, n8z, zsols, sols[2] = {0,0};
83              
84             /* The input MUST be square-free or the result will not be correct. */
85              
86 161 100         if (n&1) {
87 1200 100         for (z = 0, limz = isqrt(n/8); z <= limz; z++) {
88 1093           zsols = 0;
89 1093           n8z = n - 8*z*z;
90 397266 100         for (y = 0, limy = isqrt(n8z/2); y <= limy; y++) {
91 396173           x = n8z - 2*y*y; /* n odd => n8z odd => x odd */
92 396173 100         if (is_perfect_square(x))
93 1209 100         zsols += 1 << (1+(y>0)+(z>0));
94             }
95 1093           sols[z&1] += zsols;
96             }
97             } else {
98 243 100         for (z = 0, limz = isqrt((n/2)/8); z <= limz; z++) {
99 189           zsols = 0;
100 189           n8z = n/2 - 8*z*z;
101 2581 100         for (x = 1, limx = isqrt(n8z); x <= limx; x += 2) {
102 2392           y = n8z - x*x;
103 2392 100         if (y == 0 || is_perfect_square(y))
    100          
104 86 100         zsols += 1 << (1+(y>0)+(z>0));
105             }
106 189           sols[z&1] += zsols;
107             }
108             }
109 161           return (sols[0] == sols[1]);
110             }
111              
112             /******************************************************************************/
113              
114             #define SWAP4(x,y) { UV t; t=x; x=y; y=t; t=x##8; x##8=y##8; y##8=t; }
115             #define KPQ kronecker_uu(p,q)
116             #define KQP kronecker_uu(q,p)
117             /* For 3 factors */
118             #define KPR kronecker_uu(p,r)
119             #define KQR kronecker_uu(q,r)
120             #define KRP kronecker_uu(r,p)
121             #define KRQ kronecker_uu(r,q)
122             /* For 4 factors */
123             #define KPS kronecker_uu(p,s)
124             #define KQS kronecker_uu(q,s)
125             #define KRS kronecker_uu(r,s)
126             #define KSP kronecker_uu(s,p)
127             #define KSQ kronecker_uu(s,q)
128             #define KSR kronecker_uu(s,r)
129              
130             #define LAGRANGE_COND1 (KPQ==KPR || KQR==KQP || KRP==KRQ)
131             #define LAGRANGE_COND2 ((KPQ==1 && KPR==1) || (KQR==1 && KQP==1) || (KRP==1 && KRQ==1))
132             #define LAGRANGE_COND3 ((KPQ==-1 && KPR==-1) || (KQR==-1 && KQP==-1) || (KRP==-1 && KRQ==-1))
133              
134 49           static bool _can_order_kronecker2(UV p, UV q) {
135 49 100         return KPQ==-1 || KQP == -1;
    50          
136             }
137 49           static bool _can_order_kronecker3(UV p, UV q, UV r) {
138 28 100         return (KPR==-1 && KQR==-1 && _can_order_kronecker2(p,q)) ||
    50          
139 89 100         (KPQ==-1 && KRQ==-1 && _can_order_kronecker2(p,r)) ||
    100          
    50          
    50          
140 12 50         (KQP==-1 && KRP==-1 && _can_order_kronecker2(q,r));
    50          
    50          
141             }
142 42           static bool _can_order_kronecker4(UV p, UV q, UV r, UV s) {
143 23 100         return (KPS==-1 && KQS==-1 && KRS==-1 && _can_order_kronecker3(p,q,r)) ||
    50          
    50          
144 25 100         (KPR==-1 && KQR==-1 && KSR==-1 && _can_order_kronecker3(p,q,s)) ||
    50          
    50          
    0          
145 109 100         (KPQ==-1 && KRQ==-1 && KSQ==-1 && _can_order_kronecker3(p,r,s)) ||
    100          
    50          
    0          
    0          
146 25 100         (KQP==-1 && KRP==-1 && KSP==-1 && _can_order_kronecker3(q,r,s));
    50          
    100          
    50          
147             }
148              
149 12           static bool _can_orderk_r(uint32_t nfac, UV fac[]) {
150             uint32_t i,j;
151 12 50         if (nfac <= 1) return TRUE;
152 12 50         if (nfac == 2) return _can_order_kronecker2(fac[0],fac[1]);
153 60 100         for (i = 0; i < nfac; i++) {
154 48           SWAP2(fac[i], fac[nfac-1]); /* Test with this factor at the end */
155 72 50         for (j = 0; j < nfac-1; j++)
156 72 100         if (kronecker_uu(fac[j],fac[nfac-1]) != -1)
157 48           break;
158 48 50         if (j == nfac-1 && _can_orderk_r(nfac-1, fac))
    0          
159 0           break;
160             }
161 12           return i < nfac;
162             }
163             /* Can we order s.t. (p|q) == (p|r) == (q|r) == -1 */
164 12           static bool _can_orderk(uint32_t nfac, const UV fac[]) {
165             UV F[MPU_MAX_DFACTORS];
166 12 50         if (nfac > MPU_MAX_DFACTORS) return FALSE;
167 12           memcpy(F, fac, nfac*sizeof(UV)); /* We can safely permute the ordering */
168 12           return _can_orderk_r(nfac, F);
169             }
170              
171             /* Returns -1 if not known, 0 or 1 indicate definite results. */
172 401           static int _is_congruent_number_filter1(const factored_t nf) {
173 401           const UV n = nf.n;
174 401           const bool isodd = n & 1;
175 401           const bool iseven = !isodd;
176              
177             UV p, q, r, s; /* Four odd factors in mod 8 order */
178             UV p8, q8, r8, s8; /* values mod 8 */
179 401           UV fac[MPU_MAX_DFACTORS] = {0}; /* The odd factors, in mod 8 order */
180 401           uint32_t nfac = 0;
181              
182 401 50         MPUassert(n >= 13, "n too small in icn_filter");
183              
184             /* The ACK conjecture (Alter, Curtz, and Kubota 1972):
185             * n = {5,6,7} mod 8 => n is a congruent number
186             * also follows from the weak BSD conjecture.
187             */
188 401 100         if (n % 8 == 5 || n % 8 == 6 || n % 8 == 7) return 1;
    100          
    100          
189              
190             /* No filter here handles more than 4 odd factors */
191 318 100         if (nf.nfactors-iseven > 4) return -1;
192              
193             { /* Sort odd factors into fac array by mod 8 */
194             uint32_t i;
195 1287 100         for (i=0; i
    100          
196 1287 100         for (i=0; i
    100          
197 1287 100         for (i=0; i
    100          
198 1287 100         for (i=0; i
    100          
199             }
200 296           p = fac[0];
201 296 100         q = (nfac > 1) ? fac[1] : 0;
202 296 100         r = (nfac > 2) ? fac[2] : 0;
203 296 100         s = (nfac > 3) ? fac[3] : 0;
204 296           p8 = p % 8; q8 = q % 8; r8 = r % 8; s8 = s % 8;
205              
206             /* Evink 2021 https://arxiv.org/pdf/2105.01450.pdf
207             * Feng 1996 http://matwbn.icm.edu.pl/ksiazki/aa/aa75/aa7513.pdf
208             * Monsky 1990 https://gdz.sub.uni-goettingen.de/id/PPN266833020_0204
209             * Lagrange 1974 https://www.numdam.org/item/SDPP_1974-1975__16_1_A11_0.pdf
210             */
211              
212 300 100         if (isodd && nfac == 1) { /* n = p */
    100          
213              
214             UV root;
215 43 100         if (p8 == 3) return 0; /* Genocchi 1855 */
216              
217             /* https://arxiv.org/pdf/2105.01450.pdf, Prop 2.1.2 */
218 15 50         if (sqrtmodp(&root, 2, p) && kronecker_uu(1+root, p) == -1)
    100          
219 11           return 0;
220             #if 0
221             { /* Evink 2021 shows these are equivalent to the sqrt test above */
222             UV a,b;
223             if (1 && cornacchia(&a, &b, 1, p)) {
224             if (p != (a*a+b*b)) croak("bad corn for %lu\n",p);
225             if (sqrmod(a+b,16) != 1)
226             { printf("ret\n"); return 0; }
227             }
228             if (1 && cornacchia(&a, &b, 4, p))
229             if (kronecker_uu(a+2*b, p) == -1)
230             { printf("ret 2\n"); return 0; }
231             }
232             #endif
233              
234 264 100         } else if (iseven && nfac == 1) { /* n = 2p */
    100          
235              
236 16 50         if (p8 == 3 || p8 == 7) return 1; /* we already returned 1 earlier */
    50          
237 16 100         if (p8 == 5) return 0; /* Genocchi 1855 */
238 7 100         if (p % 16 == 9) return 0; /* Bastien 1915 */
239              
240 248 100         } else if (isodd && nfac == 2) { /* n = pq */
    100          
241              
242 28 100         if (p8 == 3 && q8 == 3) return 0; /* Genocchi 1855 */
    50          
243             #if 0 /* Monsky, all produce n mod 8 = 5 or 7: we already returned 1 */
244             if (p8 == 3 && q8 == 7) return 1;
245             if (p8 == 3 && q8 == 5) return 1;
246             if (p8 == 1 && q8 == 5 && KPQ == -1) return 1;
247             if (p8 == 1 && q8 == 7 && KPQ == -1) return 1;
248             #endif
249             /* Lagrange 1974 */
250 20 100         if (p8 == 1 && q8 == 3 && KPQ == -1) return 0;
    50          
    50          
251 14 100         if (p8 == 5 && q8 == 7 && KPQ == -1) return 0;
    100          
    100          
252              
253 220 100         } else if (iseven && nfac == 2) { /* n = 2pq */
    100          
254              
255 33 100         if (p8 == 5 && q8 == 5) return 0; /* Genocchi 1855 */
    50          
256             #if 0 /* Monsky, all produce n mod 8 = 6: we already returned 1 */
257             if (p8 == 3 && q8 == 5) return 1;
258             if (p8 == 5 && q8 == 7) return 1;
259             if (p8 == 1 && q8 == 7 && KPQ == -1) return 1;
260             if (p8 == 1 && q8 == 3 && KPQ == -1) return 1;
261             #endif
262             /* Lagrange 1974 */
263 29 100         if (p8 == 3 && q8 == 3) return 0;
    100          
264 23 100         if (p8 == 1 && q8 == 5 && KPQ == -1) return 0;
    100          
    50          
265 19 100         if (p8 == 3 && q8 == 7 && KPQ == -1) return 0;
    50          
    100          
266 13 100         if (p8 == 7 && q8 == 7 && KPQ == 1 && q % 16 == 7) return 0;
    50          
    50          
    50          
267 6 100         if (p8 == 1 && q8 == 1 && KPQ == -1 && (p*q) % 16 == 9) return 0;
    50          
    50          
    50          
268              
269 187 100         } else if (isodd && nfac == 3) { /* n = pqr */
    100          
270              
271             #if 0 /* Serf 1991, all produce n mod 8 = 5 or 7: we already returned 1 */
272             if (p8 == 3 && q8 == 3 && r8 == 5) return 1;
273             if (p8 == 3 && q8 == 3 && r8 == 7) return 1;
274             if (p8 == 7 && q8 == 7 && r8 == 7 && KPQ == -KPR && KPQ == KQR) return 1;
275             #endif
276             /* Lagrange 1974 */
277 38 100         if (p8 == 1 && q8 == 3 && r8 == 3 && KPQ == -KPR) return 0;
    100          
    50          
    50          
278 35 100         if (p8 == 3 && q8 == 5 && r8 == 7 && KQR == -1) return 0;
    100          
    100          
    50          
279 31 100         if (p8 == 3 && q8 == 7 && r8 == 7 && KPQ == -KPR && KPQ == KQR) return 0;
    100          
    50          
    50          
    50          
280 27 100         if (p8 == 1 && q8 == 1 && r8 == 3 && LAGRANGE_COND3) return 0;
    100          
    100          
    100          
    100          
    50          
    100          
    50          
    50          
281 18 100         if (p8 == 1 && q8 == 5 && r8 == 7 && LAGRANGE_COND3) return 0;
    100          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
282 14 100         if (p8 == 3 && q8 == 5 && r8 == 5 && LAGRANGE_COND3) return 0;
    100          
    50          
    100          
    100          
    50          
    100          
    50          
    50          
283 8 100         if (p8 == 3 && q8 == 3 && r8 == 3 && LAGRANGE_COND1) return 0;
    50          
    50          
    100          
    50          
    0          
284 3 50         if (p8 == 1 && q8 == 1 && r8 == 1 && LAGRANGE_COND3) {
    50          
    50          
    50          
    100          
    50          
    50          
    0          
    0          
285             UV c,d;
286 3 50         if (cornacchia(&c, &d, 8, n) && d&1)
    50          
287 3           return 0;
288             }
289              
290 149 100         } else if (iseven && nfac == 3) { /* n = 2pqr */
    100          
291              
292             #if 0 /* Serf 1991, all produce n mod 8 = 6: we already returned 1 */
293             if (p8 == 3 && q8 == 3 && r8 == 7) return 1;
294             if (p8 == 3 && q8 == 5 && r8 == 5) return 1;
295             if (p8 == 5 && q8 == 5 && r8 == 7) return 1;
296             if (p8 == 7 && q8 == 7 && r8 == 7 && KPQ == -KPR && KPQ == KQR) return 1;
297             #endif
298             /* Lagrange 1974 */
299 36 100         if (p8 == 1 && q8 == 3 && r8 == 3 && KPQ == -KPR) return 0;
    100          
    50          
    100          
300 33 100         if (p8 == 1 && q8 == 5 && r8 == 5 && KPQ == -KPR) return 0;
    100          
    50          
    50          
301 30 100         if (p8 == 3 && q8 == 5 && r8 == 7 && KRP == KRQ) return 0;
    100          
    50          
    50          
302 26 100         if (p8 == 1 && q8 == 1 && r8 == 1 && LAGRANGE_COND3 && (p*q*r) % 16 == 9) return 0;
    100          
    100          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
303 22 100         if (p8 == 5 && q8 == 7 && r8 == 7 && KQP == KQR && KQP == -KRP) return 0;
    100          
    50          
    50          
    50          
304 18 100         if (p8 == 1 && q8 == 1 && r8 == 5 && LAGRANGE_COND3) return 0;
    100          
    50          
    50          
    100          
    50          
    50          
    0          
    0          
305             /* Lagrange's 1 3 7 seems to be incorrect.
306             * 13706 = 2*7*11*89 = 2*89*7*11, so p = 1, q = -1, r = 3 mod 8.
307             * cond3 (q|r)= (q|p) = -1.
308             * but 13706 is a congruent number.
309             * Cheng/Guo 2018 show this case with a third congruency.
310             */
311 13 100         if (p8 == 3 && q8 == 3 && r8 == 5 && LAGRANGE_COND1) return 0;
    50          
    50          
    100          
    50          
    0          
312 6 100         if (p8 == 5 && q8 == 5 && r8 == 5 && LAGRANGE_COND2) return 0;
    50          
    50          
    100          
    100          
    50          
    100          
    50          
    50          
313             /* Cheng/Guo 2018, Theorem 1.3.6 */
314 1 50         if (p8 == 1 && q8 == 3 && r8 == 7 && KPQ == -1 && KPR == -1 && KQR == -1) return 0;
    50          
    50          
    0          
    0          
    0          
315              
316 113 100         } else if (isodd && nfac == 4) { /* n = pqrs */
    50          
317              
318             /* Serf 1991 */
319 51 100         if (p8 == 5 && q8 == 5 && r8 == 7 && s8 == 7 &&
    50          
    50          
    50          
320 6 50         ( (KPR == 1 && KQR == -1 && KPS == -1) ||
    0          
    0          
321 6 50         (KPR == -1 && KPS == 1 && KQS == -1) ||
    100          
    50          
322 2 50         (KPR == -1 && KPS == -1 && KQR == -KQS)))
    50          
    50          
323 6           return 0;
324             /* Cheng/Guo 2018, Theorem 1.3.1 */
325 45 100         if (p8 == 3 && q8 == 3 && r8 == 5 && s8 == 7 &&
    50          
    100          
    50          
326 7 100         (KPQ == -1 || KQP == -1) &&
    50          
327 7 50         KPR == -1 && KQR == -1 && KPS == -1 && KQS == -1 && KRS == -1)
    50          
    50          
    50          
    50          
328 7           return 0;
329             /* Cheng/Guo 2018, Theorem 1.2.5 */
330 38 100         if (p8 == 1 && q8 == 3 && r8 == 3 && s8 == 3 &&
    100          
    100          
    50          
331 14 50         KPQ == -1 && KPR == -1 && KPS == -1 &&
    50          
332 7           _can_order_kronecker3(q,r,s))
333 7           return 0;
334             /* Iskra 1996 (also Cheng/Guo 2018, Theorem 1.1.2) */
335 49 100         if (p8 == 3 && q8 == 3 && r8 == 3 && s8 == 3 &&
    50          
    50          
336 18           _can_order_kronecker4(p,q,r,s))
337 12           return 0;
338             /* Das 2020 4 factors */
339 19 100         if (p8 == 1 && q8 == 3 && r8 == 5 && s8 == 7 &&
    100          
    50          
    50          
340 7 100         (KQS == -1 || KSQ == -1) &&
    50          
341 7 50         KPR == 1 && KRP == 1 && KPS == 1 && KRQ == 1 && KPQ == -1 && KRS == -1)
    50          
    50          
    50          
    50          
    50          
342 7           return 0;
343             /* Das 2020 4 factors */
344 12 100         if (p8 == 1 && q8 == 1 && r8 == 3 && s8 == 3 &&
    50          
    50          
    50          
345 6 100         (KRS == -1 || KSR == -1) && KPQ == 1 && KQP == 1 &&
    50          
    50          
    50          
346 6 100         ( (KPR == -1 && KQS == -1 && KPS == 1 && KQR == 1) ||
    50          
    50          
    50          
347 2 50         (KQR == -1 && KPS == -1 && KQS == 1 && KPR == 1) ))
    50          
    50          
    50          
348 6           return 0;
349              
350 62 50         } else if (iseven && nfac == 4) { /* n = 2pqrs */
    50          
351              
352             /* Serf 1991 */
353 62 100         if (p8 == 1 && q8 == 1 && r8 == 3 && s8 == 3 &&
    100          
    50          
    50          
354 6 50         ( (KPQ == 1 && KPR == -KPS && KQR == -KQS) ||
    0          
    0          
355 6 50         (KPQ == -1 && KPR == KPS && KQR == -KQS) ||
    100          
    50          
356 4 50         (KPQ == -1 && KPR == -KPS)))
    50          
357 6           return 0;
358             /* Cheng/Guo 2018, Theorem 1.3.2 */
359 56 100         if (p8 == 3 && q8 == 5 && r8 == 5 && s8 == 7 &&
    100          
    50          
    50          
360 7 50         (KQR == -1 || KRQ == -1) &&
    0          
361 7 50         KPQ == -1 && KPR == -1 && KPS == -1 && KQS == -1 && KRS == -1)
    50          
    50          
    50          
    50          
362 7           return 0;
363             /* Cheng/Guo 2018, Theorem 1.3.8 */
364 49 100         if (p8 == 1 && q8 == 3 && r8 == 3 && s8 == 5 &&
    100          
    50          
    50          
365 7 100         (KQR == -1 || KRQ == -1) &&
    50          
366 7 50         KPQ == -1 && KPR == -1 && KPS == -1 && KQS == -1 && KRS == -1)
    50          
    50          
    50          
    50          
367 7           return 0;
368             /* Cheng/Guo 2018, Theorem 1.2.3 */
369 42 100         if (p8 == 3 && q8 == 3 && r8 == 3 && s8 == 7 &&
    50          
    100          
    100          
370 12 50         KPS == -1 && KQS == -1 && KRS == -1 &&
    50          
371 6           _can_order_kronecker3(p,q,r))
372 6           return 0;
373             /* Cheng/Guo 2018, Theorem 1.2.6 */
374 36 100         if (p8 == 1 && q8 == 5 && r8 == 5 && s8 == 5 &&
    50          
    50          
    50          
375 12 50         KPQ == -1 && KPR == -1 && KPS == -1 &&
    50          
376 6           _can_order_kronecker3(q,r,s))
377 6           return 0;
378             /* Cheng/Guo 2018, Theorem 1.1.1 (even analog of Iskra 1996) */
379 43 100         if (p8 == 3 && q8 == 3 && r8 == 3 && s8 == 3 &&
    50          
    100          
380 13           _can_order_kronecker4(p,q,r,s))
381 7           return 0;
382             /* Cheng/Guo 2018, Theorem 1.1.3 */
383 34 100         if (p8 == 5 && q8 == 5 && r8 == 5 && s8 == 5 &&
    50          
    50          
384 11           _can_order_kronecker4(p,q,r,s))
385 11           return 0;
386             /* Cheng/Guo 2018, Theorem 1.2.1 */
387 12 50         if (p8 == 3 && q8 == 3 && r8 == 5 && s8 == 5 &&
    50          
    100          
    50          
388 6 100         (KPQ == -1 || KQP == -1) && (KRS == -1 || KSR == -1) &&
    50          
    50          
    0          
389 6 50         KPR == -1 && KQR == -1 && KPS == -1 && KQS == -1)
    50          
    50          
    50          
390 6           return 0;
391              
392             }
393              
394 29           return -1;
395             }
396              
397             /******************************************************************************/
398              
399             /* This has more complicated filters that take arbitrary numbers of factors,
400             * and have to handle permutations.
401             */
402              
403             /* Returns -1 if not known, 0 or 1 indicate definite results. */
404 51           static int _is_congruent_number_filter2(const factored_t nf) {
405 51           const bool iseven = nf.f[0] == 2;
406 51           const uint32_t noddfac = nf.nfactors - iseven;
407 51           const UV *oddfac = nf.f + iseven;
408             uint16_t i;
409             bool allmod3;
410              
411 122 100         for (i = 0; i < noddfac; i++)
412 110 100         if (oddfac[i] % 8 != 3)
413 39           break;
414 51           allmod3 = !(i < noddfac);
415              
416             /* Iskra 1996 (odd) ; Cheng/Guo 2019 Theorem 1.1.1 (even) */
417 51 100         if (allmod3 && _can_orderk(noddfac, oddfac)) return 0;
    50          
418              
419 51           return -1;
420             }
421              
422             /******************************************************************************/
423              
424             /* More complicated filters that are factor-permutation dependent, but don't
425             * yet have code to understand that. Ideally that would get done, they would
426             * be moved to _filter2, and this function would go away.
427             *
428             * Currently all inputs with fewer than 4 odd factors are handled earlier.
429             *
430             * For now we either call it once optimistically, or we call it multiple times
431             * with permuted factors.
432             */
433              
434             /* Returns -1 if not known, 0 or 1 indicate definite results. */
435 51           static int _is_congruent_number_filter3(const factored_t nf) {
436 51           const UV *fac = nf.f;
437 51           const UV n = nf.n;
438 51           const int nfactors = nf.nfactors;
439             int i, j;
440              
441             /* Reinholz 2013 https://central.bac-lac.gc.ca/.item?id=TC-BVAU-44941&op=pdf
442             * Cheng 2018 http://maths.nju.edu.cn/~guoxj/articles/IJNT2019.pdf
443             * Cheng 2019 https://www.sciencedirect.com/science/article/pii/S0022314X18302774
444             * Das 2020 https://math.colgate.edu/~integers/u55/u55.pdf
445             */
446              
447             {
448 51 100         const int noddfactors = (n&1) ? nfactors : nfactors-1;
449 51 100         const UV* oddfac = (n&1) ? fac : fac+1;
450 51           int k, l, allmod3 = 1;
451              
452 161 100         for (i = 1; allmod3 && i <= noddfactors; i++)
    100          
453 110 100         if ((oddfac[i-1] % 8) != 3)
454 39           allmod3 = 0;
455              
456             /* Reinholz, Spearman, Yang 2013 */
457 51 100         if (allmod3 && (n&1)) {
    100          
458             int m;
459 12 50         for (m = 2; m <= nfactors; m += 2) {
460 12           int reinholz = 1;
461 36 100         for (i = 1; reinholz && i < nfactors; i++)
    100          
462 66 100         for (j = 0; reinholz && j < i; j++)
    100          
463 42 100         if (j == 0 && i == m-1)
    100          
464 12           reinholz &= kronecker_uu(fac[j],fac[i]) == 1;
465             else
466 30           reinholz &= kronecker_uu(fac[j],fac[i]) == -1;
467 12 100         if (reinholz) return 0;
468             }
469             }
470              
471             /* Cheng/Guo 2019 "Some new families of non-congruent numbers" */
472 45 100         if (allmod3) {
473 18 50         for (k = 2; k <= noddfactors; k++) {
474 36 100         for (l = 1; l < k; l++) {
475 24           int cheng = 1;
476 24 100         if (!((k - l) & 1)) continue;
477 54 100         for (i = 2; cheng && i <= noddfactors; i++)
    100          
478 96 100         for (j = 1; cheng && j < i; j++)
    100          
479 60 100         if (i == k && j == l)
    100          
480 18           cheng &= kronecker_uu(oddfac[j-1],oddfac[i-1]) == -1;
481             else
482 42           cheng &= kronecker_uu(oddfac[j-1],oddfac[i-1]) == 1;
483 18 100         if (cheng) return 0;
484             }
485             }
486             }
487              
488             /* Cheng / Guo 2018 "The non-congruent numbers via Monsky’s formula" */
489             if (1) {
490             bool quad;
491 39           int g[8] = {0}; /* The number in each mod */
492             UV P[MPU_MAX_DFACTORS], Q[MPU_MAX_DFACTORS], R[MPU_MAX_DFACTORS], S[MPU_MAX_DFACTORS];
493 39 100         const int eps = (n&1) ? 1 : 2;
494 182 100         for (i = 0; i < noddfactors; i++) {
495 143           UV m = oddfac[i] % 8;
496 143 100         if (m == 1) P[ g[m]++ ] = oddfac[i];
497 143 100         if (m == 3) Q[ g[m]++ ] = oddfac[i];
498 143 100         if (m == 5) R[ g[m]++ ] = oddfac[i];
499 143 100         if (m == 7) S[ g[m]++ ] = oddfac[i];
500             }
501 39           quad = 1;
502 46 100         for (i = 2; quad && i <= g[1]; i++)
    100          
503 14 100         for (j = 1; j < i; j++)
504 7           quad &= kronecker_uu(P[j-1],P[i-1]) == -1;
505 62 100         for (i = 2; quad && i <= g[3]; i++)
    100          
506 58 100         for (j = 1; j < i; j++)
507 35           quad &= kronecker_uu(Q[j-1],Q[i-1]) == -1;
508 53 100         for (i = 2; quad && i <= g[5]; i++)
    100          
509 29 100         for (j = 1; j < i; j++)
510 15           quad &= kronecker_uu(R[j-1],R[i-1]) == -1;
511 40 100         for (i = 2; quad && i <= g[7]; i++)
    100          
512 2 100         for (j = 1; j < i; j++)
513 1           quad &= kronecker_uu(S[j-1],S[i-1]) == -1;
514 81 100         for (i = 1; quad && i <= g[3]; i++)
    100          
515 67 100         for (j = 1; j <= g[1]; j++)
516 25           quad &= kronecker_uu(P[j-1],Q[i-1]) == -1;
517 69 100         for (i = 1; quad && i <= g[5]; i++)
    100          
518 45 100         for (j = 1; j <= g[1]; j++)
519 15           quad &= kronecker_uu(P[j-1],R[i-1]) == -1;
520 54 100         for (i = 1; quad && i <= g[7]; i++)
    100          
521 24 100         for (j = 1; j <= g[1]; j++)
522 9           quad &= kronecker_uu(P[j-1],S[i-1]) == -1;
523 69 100         for (i = 1; quad && i <= g[5]; i++)
    100          
524 75 100         for (j = 1; j <= g[3]; j++)
525 45           quad &= kronecker_uu(Q[j-1],R[i-1]) == -1;
526 54 100         for (i = 1; quad && i <= g[7]; i++)
    100          
527 36 100         for (j = 1; j <= g[3]; j++)
528 21           quad &= kronecker_uu(Q[j-1],S[i-1]) == -1;
529 52 100         for (i = 1; quad && i <= g[7]; i++)
    100          
530 26 100         for (j = 1; j <= g[5]; j++)
531 13           quad &= kronecker_uu(R[j-1],S[i-1]) == -1;
532 39 100         if (quad) {
533             #if 1 /* Theorem 1.1 */
534 29 100         if ( (g[1] == 0 && g[5] == 0 && g[7] == 0 && eps == 2 && g[3] % 2 == 0)
    100          
    50          
    0          
    0          
535 29 100         || (g[1] == 0 && g[5] == 0 && g[7] == 0 && eps == 1)
    100          
    50          
    0          
536 29 100         || (g[1] == 0 && g[3] == 0 && g[7] == 0 && eps == 2 && g[5] % 2 == 0))
    100          
    100          
    50          
    0          
537 17           return 0;
538             #endif
539             #if 1 /* Theorem 1.2 */
540 29 100         if ( (g[1] == 0 && g[7] == 0 && eps == 1 && (g[3] % 2) == 1 && g[5] >= 1 && g[5] % 2 == 0)
    100          
    100          
    100          
    50          
    50          
541 27 100         || (g[1] == 0 && g[7] == 0 && eps == 2 && g[3] >= 1 && g[5] >= 1 && g[3] % 2 == 0 && g[5] % 2 == 0)
    100          
    100          
    50          
    50          
    50          
    50          
542 27 100         || (g[1] == 0 && g[7] == 0 && eps == 2 && g[3] >= 1 && g[5] == 1 && g[3] % 2 == 0)
    100          
    100          
    50          
    50          
    50          
543 25 100         || (g[1] == 0 && g[5] == 0 && eps == 2 && g[7] == 1 && g[3] % 2 == 1)
    100          
    50          
    0          
    0          
544 25 100         || (g[1] == 0 && g[3] == 0 && eps == 1 && g[5] == 1 && g[7] == 1)
    100          
    50          
    50          
    0          
545 25 100         || (g[5] == 0 && g[7] == 0 && eps == 1 && g[1] > 1 && g[1] % 2 == 0 && g[3] % 2 == 1)
    100          
    100          
    100          
    50          
    50          
546 24 100         || (g[5] == 0 && g[7] == 0 && eps == 1 && g[1] == 1 && g[3] % 2 == 1)
    100          
    100          
    50          
    50          
547 24 100         || (g[3] == 0 && g[7] == 0 && eps == 2 && g[1] == 1 && g[5] % 2 == 1)
    100          
    100          
    50          
    50          
548 24 100         || (g[3] == 0 && g[7] == 0 && eps == 2 && g[5] == 1 && g[1] > 1 && g[1] % 2 == 0) )
    100          
    100          
    50          
    0          
    0          
549 5           return 0;
550             #endif
551             #if 1 /* Theorem 1.3 */
552 24 100         if ( (g[1] == 0 && eps == 1 && g[5] == 1 && g[7] == 1 && g[3] >= 1)
    50          
    100          
    50          
    50          
553 21 100         || (g[1] == 0 && eps == 1 && g[5] >= 2 && g[7] == 1 && g[3] % 2 == 1 && g[5] % 2 == 1)
    50          
    100          
    100          
    50          
    50          
554 20 100         || (g[1] == 0 && eps == 2 && g[5] >= 1 && g[7] == 1 && g[3] % 2 == 1 && g[5] % 2 == 0)
    50          
    0          
    0          
    0          
    0          
555 20 100         || (g[3] == 0 && eps == 1 && g[7] == 1 && g[1] % 2 == 1 && g[5] % 2 == 1)
    100          
    50          
    0          
    0          
556             /* No examples 1.3.4 */
557 20 100         || (g[3] == 0 && eps == 2 && g[5] == 1 && g[7] == 1 && g[1] % 2 == 1)
    100          
    50          
    0          
    0          
558             /* No examples 1.3.5 */
559 20 100         || (g[5] == 0 && eps == 1 && g[1] >= 1 && g[3] >= 1 && g[7] == 1 && g[1] % 2 == 0 && g[3] % 2 == 0)
    100          
    100          
    50          
    0          
    0          
    0          
560 20 100         || (g[5] == 0 && eps == 2 && g[1] >= 1 && g[3] >= 1 && g[7] == 1 && g[1] % 2 == 1 && g[3] % 2 == 1)
    100          
    50          
    50          
    0          
    0          
    0          
561 20 100         || (g[7] == 0 && eps == 1 && g[1] >= 1 && g[5] >= 1 && g[1] % 2 == 0 && g[5] % 2 == 0 && g[3] % 2 == 1)
    100          
    100          
    100          
    50          
    50          
    50          
562 19 100         || (g[7] == 0 && eps == 2 && g[1] == 1 && g[3] >= 1 && g[3] % 2 == 0 && g[5] % 2 == 1)
    100          
    100          
    50          
    0          
    0          
563 19 100         || (g[7] == 0 && eps == 2 && g[1] >= 1 && g[3] >= 1 && g[5] == 1 && g[1] % 2 == 0 && g[3] % 2 == 0) )
    100          
    50          
    100          
    50          
    50          
    50          
564 6           return 0;
565             #endif
566             #if 1 /* Theorem 1.4 */
567 18 100         if ( (eps == 1 && g[1] >= 1 && g[7] == 1 && g[1] % 2 == 0 && g[3] % 2 == 1 && g[5] % 2 == 1)
    100          
    100          
    100          
    50          
    50          
568 15 100         || (eps == 1 && g[3] >= 1 && g[7] == 1 && g[1] % 2 == 1 && g[5] % 2 == 1 && g[3] % 2 == 0) )
    100          
    50          
    50          
    50          
    50          
569 6           return 0;
570             #endif
571             }
572             }
573             }
574              
575             /**************************************************************************/
576              
577             /* Das / Saikia 2020, extending Lagrange 1974 and Serf 1989 */
578 22 100         if ((n&1) && nfactors % 2 == 0 && nfactors >= 4 && nfactors <= 20) {
    100          
    100          
    50          
579 5           int cntmod[8] = {0};
580 35 100         for (i = 0; i < nfactors; i++) {
581 30           int m = fac[i] % 8;
582 30           cntmod[m]++;
583             }
584 5 50         if (cntmod[1] == cntmod[3] && cntmod[5] == cntmod[7]) {
    50          
585             /* We can separate all factors into (1,3) and (5,7) pairs. */
586             UV pf[10], qf[10];
587             int pindexbymod[8], qindexbymod[8];
588 5           const int npairs = nfactors >> 1;
589             bool das;
590              
591 5           pindexbymod[1] = qindexbymod[3] = 0;
592 5           pindexbymod[5] = qindexbymod[7] = cntmod[1];
593 35 100         for (i = 0; i < nfactors; i++) {
594 30           int m = fac[i] % 8;
595 30 100         if (m == 1 || m == 5) pf[pindexbymod[m]++] = fac[i];
    100          
596 15           else qf[qindexbymod[m]++] = fac[i];
597             }
598              
599             /* See if these conditions hold for all pairs */
600 5           das = TRUE;
601 20 100         for (i = 0; i < npairs; i++)
602 15           das &= kronecker_uu(pf[i],qf[i]) == -1;
603 20 50         for (i = 0; das && i < npairs; i++) {
    100          
604 60 100         for (j = 0; j < npairs; j++) {
605 45 100         if (i > j && kronecker_uu(qf[j],qf[i]) != -1) das = FALSE;
    50          
606 45 100         if (i != j && kronecker_uu(pf[i],pf[j]) != 1) das = FALSE;
    50          
607 45 100         if (i != j && kronecker_uu(pf[i],qf[j]) != 1) das = FALSE;
    50          
608             }
609             }
610 5 50         if (das) return 0;
611             }
612             }
613              
614 17           return -1;
615             }
616              
617             /******************************************************************************/
618             /* Allow testing the filters and the counting functions separately */
619              
620 247           int is_congruent_number_filter(UV n) {
621             int res;
622 247           factored_t nf = factorint(n);
623 247           remove_square_part(&nf);
624 247 50         if (nf.n < 13) return (nf.n >= 5 && nf.n <= 7);
    0          
    0          
625              
626 247           res = _is_congruent_number_filter1(nf);
627 247 100         if (res != -1) return res;
628 34           res = _is_congruent_number_filter2(nf);
629 34 50         if (res != -1) return res;
630 34           res = _is_congruent_number_filter3(nf);
631 34 50         if (res != -1) return res;
632              
633             #if 0
634             if (1 && res == -1) {
635             uint32_t noddfac = nf.nfactors - (nf.f[0] == 2);
636             if (noddfac > 3) {
637             UV i, nperms = factorial(noddfac);
638             for (i = 1; res == -1 && i < nperms; i++) {
639             factored_t trynf = permute_odd_factors(nf, i);
640             res = _is_congruent_number_filter3(trynf);
641             }
642             }
643             }
644             /* if (res != -1) printf("%lu\n", nf.n); */
645             #endif
646 0           return res;
647             }
648 200           bool is_congruent_number_tunnell(UV n) {
649 200           factored_t nf = factorint(n);
650 200           remove_square_part(&nf);
651 200 100         if (nf.n < 13) return (nf.n >= 5 && nf.n <= 7);
    100          
    100          
652              
653 144           return _is_congruent_number_tunnell(nf.n);
654             }
655              
656             /******************************************************************************/
657              
658             /* is_congruent_number(n). OEIS A003273. */
659 210           bool is_congruent_number(UV n)
660             {
661             int res;
662 210           factored_t nf = factorint(n);
663 210           remove_square_part(&nf);
664 210 100         if (nf.n < 13) return (nf.n >= 5 && nf.n <= 7);
    100          
    100          
665              
666             /* Relatively simple filters. Order doesn't matter. */
667 154           res = _is_congruent_number_filter1(nf);
668 154 100         if (res != -1) return res;
669             /* More complicated filters. Permutation is handled. */
670 17           res = _is_congruent_number_filter2(nf);
671 17 50         if (res != -1) return res;
672             /* More complicated filters. We haven't implemented permutations. */
673 17           res = _is_congruent_number_filter3(nf);
674 17 50         if (res != -1) return res;
675              
676             if (0) { /* Try filter3 with all odd factor permutations */
677             uint32_t noddfac = nf.nfactors - (nf.f[0] == 2);
678             if (noddfac > 3) {
679             UV i, nperms = factorial(noddfac);
680             for (i = 1; res == -1 && i < nperms; i++) {
681             factored_t trynf = permute_odd_factors(nf, i);
682             res = _is_congruent_number_filter3(trynf);
683             }
684             }
685             if (res != -1) return res;
686             }
687              
688 17           return _is_congruent_number_tunnell(nf.n);
689             }