File Coverage

omega_primes.c
Criterion Covered Total %
statement 87 119 73.1
branch 105 192 54.6
condition n/a
subroutine n/a
pod n/a
total 192 311 61.7


line stmt bran cond sub pod time code
1             /******************************************************************************/
2             /* OMEGA PRIMES */
3             /******************************************************************************/
4              
5             #include
6             #include
7             #include
8             #include
9              
10             #define FUNC_isqrt 1
11             #include "ptypes.h"
12             #include "constants.h"
13             #include "cache.h"
14             #include "sieve.h"
15             #include "util.h"
16             #include "sort.h"
17             #include "prime_counts.h"
18             #include "prime_powers.h"
19             #include "factor.h"
20             #include "inverse_interpolate.h"
21             #include "omega_primes.h"
22              
23 3945           bool is_omega_prime(uint32_t k, UV n) {
24 5920 50         if (k > 0 && !(n& 1)) { k--; do { n >>= 1; } while (!(n& 1)); }
    100          
    100          
25 4553 100         if (k > 0 && !(n% 3)) { k--; do { n /= 3; } while (!(n% 3)); }
    100          
    100          
26 4144 100         if (k > 0 && !(n% 5)) { k--; do { n /= 5; } while (!(n% 5)); }
    100          
    100          
27 4034 100         if (k > 0 && !(n% 7)) { k--; do { n /= 7; } while (!(n% 7)); }
    100          
    100          
28 3983 100         if (k > 0 && !(n%11)) { k--; do { n /= 11; } while (!(n%11)); }
    100          
    100          
29              
30 3945 100         if (n == 1) return (k == 0);
31 3745 100         if (k == 0) return (n == 1);
32 3581 100         if (k == 1) return is_prime_power(n);
33 3367 100         if (n < ipowsafe(13,k)) return 0;
34              
35 181           return ((UV)prime_omega(n) == k);
36             }
37              
38             /* See https://arxiv.org/pdf/2006.16491.pdf page 12 for a brief note */
39              
40             /* For the interpolation */
41 984           static UV opce(UV mid, UV k) { return omega_prime_count(k, mid); }
42              
43              
44             /********************************* Construction *****************************/
45              
46 0           static void _omega_prime_gen_rec(UV** kop, UV* skop, UV* nkop, uint32_t k, UV lo, UV hi, UV m, UV pstart) {
47 0           UV v, *l = *kop, lsize = *skop, n = *nkop;
48              
49 0 0         if (k > 1) {
50 0 0         SIMPLE_FOR_EACH_PRIME(pstart, rootint(hi/m, k)) {
    0          
    0          
51 0 0         if ((m % p) == 0) continue;
52 0 0         if (UV_MAX/m < p) break;
53 0 0         for (v = m*p; UV_MAX/v >= p && v*p <= hi; v *= p)
    0          
54 0           _omega_prime_gen_rec(kop, skop, nkop, k-1, lo, hi, v, p);
55             } END_SIMPLE_FOR_EACH_PRIME
56 0           return;
57             }
58              
59 0 0         START_DO_FOR_EACH_PRIME(pstart, rootint(hi/m, k)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
60 0 0         if ((m % p) == 0) continue;
61 0 0         for (v = m; UV_MAX/v >= p && v*p <= hi; ) {
    0          
62 0           v *= p;
63 0 0         if (v >= lo) { /* Add v to kop list */
64 0 0         if (n >= lsize) {
65 0           lsize = 1 + lsize * 1.2;
66 0 0         Renew(l, lsize, UV);
67             }
68 0           l[n++] = v;
69             }
70             }
71             } END_DO_FOR_EACH_PRIME
72 0           *kop = l; *skop = lsize; *nkop = n;
73             }
74              
75 0           static UV rec_omega_primes(UV** ret, uint32_t k, UV lo, UV hi) {
76             UV nkop, skop;
77              
78 0 0         if (hi < lo) croak("range_omega_prime_sieve error hi %"UVuf" < lo %"UVuf"\n",hi,lo);
79              
80 0           nkop = 0;
81 0           skop = 256;
82 0 0         New(0, *ret, skop, UV);
83 0           _omega_prime_gen_rec(ret, &skop, &nkop, k, lo, hi, 1, 2);
84 0           sort_uv_array(*ret, nkop);
85 0           return nkop;
86             }
87              
88              
89 5           UV range_omega_prime_sieve(UV** ret, uint32_t k, UV lo, UV hi) {
90 5           UV i, min, lmax = 0, n = 0;
91 5           UV* l = 0;
92             unsigned char *nf;
93              
94 5 50         if (hi < lo) croak("range_omega_prime_sieve error hi %"UVuf" < lo %"UVuf"\n",hi,lo);
95              
96 5           min = pn_primorial(k);
97 5 50         if (min == 0 || min > hi) return 0;
    50          
98 5 50         if (lo < min) lo = min;
99              
100 5 100         if (k == 1) return prime_power_sieve(ret, lo, hi);
101              
102             /* TODO: The recursive routine should compute primes like the count does */
103 4 50         if ( ((hi-lo) > 100000000UL) || (k >= 10 && (hi-lo) > 5000000UL) )
    50          
    0          
104 0           return rec_omega_primes(ret, k, lo, hi);
105              
106 4           nf = range_nfactor_sieve(lo, hi, 0);
107 4 50         if (ret != 0) {
108 4           lmax = 1000;
109 4 50         New(0, l, lmax, UV);
110             }
111 10224 100         for (i = 0; i < hi-lo+1; i++) {
112 10220 100         if (nf[i] != k) continue;
113 160 50         if (l != 0) {
114 160 50         if (n >= lmax) { lmax = 1 + lmax * 1.2; Renew(l, lmax, UV); }
    0          
115 160           l[n] = lo+i;
116             }
117 160           n++;
118             }
119 4           Safefree(nf);
120 4 50         if (ret != 0) *ret = l;
121 4           return n;
122             }
123              
124             /* TODO: Should make a single construct routine that calls sieve or recurse */
125              
126              
127             /********************************* Counting *********************************/
128              
129 403           UV max_omega_prime_count(uint32_t k) {
130             #if BITS_PER_WORD == 32
131             static const UV max[10] = {1,203287168,838888926,1389246717,1178725572,540561553,129357524,14327954,567659,4221};
132             if (k >= 10) return 0;
133             #else
134             static const UV max[16] = {1, UVCONST(425656284140516112), /* prime powers */
135             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* TODO: find these */
136             UVCONST(5512134903353),UVCONST(87133769732),UVCONST(446745559),299178
137             };
138 403 50         if (k >= 16) return 0;
139             #endif
140 403 50         if (k >= BITS_PER_WORD) return 0;
141 403 100         if (max[k] == 0) return UV_MAX;
142 81           return max[k];
143             }
144              
145 0           UV max_nth_omega_prime(uint32_t k) {
146             #if BITS_PER_WORD == 32
147             static const UV offset[10] = {0,4,1,8,5,0,34,3,1305,46665};
148             if (k >= 10) return 0;
149             #else
150             static const UV offset[16] = {0,58,7,2,3,5,25,0,48,255,1155,46017,15,
151             UVCONST(125585475),UVCONST(522131625),UVCONST(338362334325)};
152 0 0         if (k >= 16) return 0;
153             #endif
154 0 0         if (k >= BITS_PER_WORD) return 0;
155 0           return UV_MAX - offset[k];
156             }
157              
158              
159             #define RECURSIVE_OMEGA_COUNT(k,n,pr,npr) \
160             _omega_prime_count_rec2(k, n, 1, 2, rootint(n,k), 1, pr, npr)
161              
162             /* Initial call: m = 1, p = 2, s = sqrtn(n), j = 1 */
163 15357           static UV _omega_prime_count_rec2(uint32_t k, UV n, UV m, UV p, UV s, UV j, uint32_t* pr, UV numprimes) {
164 15357           UV t, r, count = 0;
165              
166 15357 100         if (k == 2) {
167             UV r2, w, u, k, rlim;
168 23795 100         for (; p <= s; j++, p = r) {
169 18185 100         r = (j < numprimes) ? pr[j] : next_prime(p);
170 35667 50         for (t = m*p, w = n/t; t <= n && w >= r; t *= p, w = n/t) {
    100          
171             #if 1
172 17482           count += prime_count(w) - j;
173 17482           for (k = j, r2 = r, rlim = isqrt(w);
174 28352 100         r2 <= rlim;
175 10870 100         r2 = (++k < numprimes) ? pr[k] : rlim+1) {
176 10870           u = t * r2;
177 12630 100         do { u *= r2; count++; } while (n/r2 >= u);
178             }
179             #else
180             /* This is the basic method from the definition, before optimizing */
181             UV q;
182             count += prime_power_count(w);
183             rlim = prev_prime(r);
184             for (k = 1, q = 2;
185             q <= rlim;
186             q = (++k < numprimes) ? pr[k-1] : nth_prime(k)) {
187             count -= logint(w, q);
188             }
189             #endif
190 17482 50         if (t > n/p) break;
191             }
192             }
193 5610           return count;
194             }
195              
196 26228 100         for (; p <= s; j++, p = r) {
197 16481 50         r = (j < numprimes) ? pr[j] : next_prime(p);
198 30964 50         for (t = m*p; t <= n; t *= p) {
199 30964           UV S = rootint(n/t, k-1);
200 30964 100         if (r > S) break;
201 14483           count += _omega_prime_count_rec2(k-1, n, t, r, S, j+1, pr, numprimes);
202 14483 50         if (t > n/p) break;
203             }
204             }
205 9747           return count;
206             }
207              
208 1038           UV omega_prime_count(uint32_t k, UV n)
209             {
210             uint32_t* pr;
211             UV maxpr, npr, sum, lo;
212              
213 1038 100         if (k == 0) return (n >= 1);
214 1036 100         if (k == 1) return prime_power_count(n);
215              
216             /* The first k-omega-prime is primorial(p_k) (ignoring zero for k=1) */
217 903           lo = pn_primorial(k);
218 903 100         if (lo == 0 || n < lo) return 0;
    100          
219              
220 874 50         maxpr = rootint(n, (k > 10) ? 4 : (k > 6) ? 3 : 2);
    100          
221 874           npr = range_prime_sieve_32(&pr, maxpr, 0); /* p[0]=2, p[1]=3,... */
222 874           sum = RECURSIVE_OMEGA_COUNT(k, n, pr, npr);
223 874           Safefree(pr);
224 874           return sum;
225             }
226              
227             /* An upper bound for the omega prime count, when n >= 10^12 is shown in
228             * Bayless,Kinlaw,Klyve 2019, page 4
229             * https://www.researchgate.net/profile/Paul-Kinlaw/publication/329788487_Sums_over_primitive_sets_with_a_fixed_number_of_prime_factors/links/5c44103d92851c22a3825286/Sums-over-primitive-sets-with-a-fixed-number-of-prime-factors.pdf
230             * double logn = log(n), loglogn = log(logn);
231             * double lim = (1.0989 * n * pow(loglogn + 1.1174, k-1)) / (factorial(k-1)*logn);
232             */
233              
234              
235             /************************************ nth ***********************************/
236              
237 202           UV nth_omega_prime(uint32_t k, UV n) {
238             UV lo, hi;
239              
240 202 50         if (n == 0) return 0;
241 202 100         if (k == 0) return (n == 1) ? 1 : 0;
242              
243 201 50         if (k > 15 || n > max_omega_prime_count(k)) return 0;
    50          
244              
245 201           lo = pn_primorial(k);
246 201 50         if (lo == 0) return 0;
247 201 100         if (n == 1) return lo;
248              
249 196 100         if (k == 1) {
250 39           hi = nth_prime(n);
251 39 50         if (hi == 0) hi = max_nth_omega_prime(1);
252 39           lo = hi >> 1; /* We could do better */
253             } else {
254 157           hi = 0; /* Let the interpolation routine find it */
255             }
256 196           hi = inverse_interpolate_k(lo, hi, n, k, &opce, 600);
257              
258 3330 100         while (!is_omega_prime(k,hi))
259 3134           hi--;
260             /* if (omega_prime_count(k,hi) != n) croak("bad nth"); */
261 196           return hi;
262             }