-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstormer.c
130 lines (123 loc) · 3.6 KB
/
stormer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "stormer.h"
GEN
logsofprimes(ulong B, long prec)
{
return glog(primes((long)uprimepi(B)),prec);
}
static inline GEN
createnode(GEN bv, GEN sol, GEN prev)
/* Create node.
* Input: bit vector bv \in {0, 1}^*;
real number sol;
other node prev or NULL.
* Output: [bv, sol, prev].
(bv and sol are copied, prev is stored as a pointer only)
*/
{
if (typ(bv) != t_VECSMALL) pari_err_TYPE("createnode",bv);
if (typ(sol) != t_REAL) pari_err_TYPE("createnode",sol);
if (prev != NULL && typ(prev) != t_VEC) pari_err_TYPE("createnode",prev);
GEN res = cgetg(4,t_VEC);
gel(res,1) = gcopy(bv);
gel(res,2) = gcopy(sol);
gel(res,3) = prev;
return res;
}
static inline int
isleaf (GEN node, GEN lop)
/* is leaf?
* Input: node [bv, sol, prev] as created by createnode or leftchild/rightchild,
lop (as returned by logsofprimes).
* Output: 1 if the node is a leaf, 0 otherwise.
*/
{
if (lg(gel(node,1)) >= lg(lop)) return 1;
return 0;
}
static inline GEN
leftchild(GEN node, GEN prev)
/* Left child.
* Input: node [bv, sol, prev] (as returned by createnode or *child);
node prev.
* Output: Node [vec_append(bv,0), sol, prev].
*/
{
GEN res = cgetg(4,t_VEC);
gel(res,1) = vecsmall_append(gel(node,1),0);
gel(res,2) = gcopy(gel(node,2));
gel(res,3) = prev;
return res;
}
static inline GEN
rightchild(GEN node, GEN lop, GEN prev)
/* Right child.
* Input: node [bv, sol, prev] (as returned by createnode or *child);
lop (as returned by logsofprimes);
node prev.
* Output: Node [vec_append(bv,1), sol+lop(length(lop)-length(bv)), prev];
*/
{
GEN res = cgetg(4,t_VEC);
pari_sp ltop;
if (lg(gel(node,1)) >= lg(lop)) pari_err_COMPONENT("rightchild",">=",gel(node,1),lop);
gel(res,1) = vecsmall_append(gel(node,1),1);
ltop = avma; gel(res,2) = gerepileupto(ltop,addrr(gel(node,2),gel(lop,lg(lop)+1-lg(gel(res,1)))));
gel(res,3) = prev;
return res;
}
GEN
stormer_gen(GEN lop, GEN sol, GEN ub, GEN bv)
{
if (typ(lop) != t_VEC) pari_err_TYPE("stormer_gen", lop);
if (typ(sol) != t_REAL) pari_err_TYPE("stormer_gen",sol);
if (bv != NULL && typ(bv) != t_VECSMALL) pari_err_TYPE("stormer_gen",bv);
GEN rc, node;
pari_sp av = avma;
ulong i;
if (gcmp(sol,ub) > 0) return NULL;
node = gerepileupto(avma,createnode(cgetg(1,t_VECSMALL),sol,NULL));
if (bv == NULL)
{
while (!isleaf(node,lop))
{
av = avma; rc = rightchild(node,lop,node);
if (gcmp(gel(rc,2),ub) > 0) node = gerepileupto(av,leftchild(node,node));
else node = leftchild(node,rc);
}
}
else
{
for (i = 1; i < lg(bv); i++)
{
if ((long)gel(bv,i) == 1) node = rightchild(node,lop,node);
else // code duplication...
{
av = avma; rc = rightchild(node,lop,node);
if (gcmp(gel(rc,2),ub) > 0) node = gerepileupto(av,leftchild(node,node));
else node = leftchild(node,rc);
}
}
}
return node;
}
GEN
stormer_next(GEN node, GEN lop, GEN ub, GEN *old)
{
GEN rc;
pari_sp av;
*old = gel(node,3);
while (lg(gel(node,1)) > lg(gel(*old,1)))
{
node = *old;
*old = gel(node,3);
if (*old == NULL) return NULL;
}
node = *old;
while (!isleaf(node,lop)) // code duplication...
{
av = avma; rc = rightchild(node,lop,node);
if (gcmp(gel(rc,2),ub) > 0) node = gerepileupto(av,leftchild(node,node));
else node = leftchild(node,rc);
}
return node;
}