source: git/Singular/LIB/modular.lib @ 91c7251

spielwiese
Last change on this file since 91c7251 was 6dd9bf, checked in by Andreas Steenpass <steenpass@…>, 10 years ago
add: modular.lib (cherry picked from commit 4033c6b71b5bdc43798b4183c90512f5d4871308) Signed-off-by: Andreas Steenpass <steenpass@mathematik.uni-kl.de> Conflicts: Singular/singular-libs
  • Property mode set to 100644
File size: 9.8 KB
Line 
1////////////////////////////////////////////////////////////////////
2version="version modular.lib 3-1-7-0 Dec_2013 ";
3category="General purpose";
4info="
5LIBRARY:   modular.lib  An abstraction layer for modular techniques
6AUTHOR:    Andreas Steenpass, e-mail: steenpass@mathematik.uni-kl.de
7
8OVERVIEW:
9This library is an abstraction layer for modular techniques which are
10well-known to speed up many computations and to be easy parallelizable.
11@* The basic idea is to execute some computation modulo several primes and then
12to lift the result back to characteristic zero via the farey rational map and
13chinese remaindering. It is thus possible to overcome the often problematic
14coefficient swell and to run the modular computations in parallel.
15@* In Singular, modular techniques have been quite successfully employed for
16several applications. A first implementation was done for Groebner bases in
17Singular's @ref{modstd.lib}, a pioneering work by Stefan Steidel. Since the
18algorithm is basically the same for all applications, this library aims at
19preventing library authors from writing the same code over and over again by
20providing an appropriate abstraction layer. It also offers one-line commands
21for ordinary Singular users who want to take advantage of modular techniques
22for their own calculations. Thus modular techniques can be regarded as
23a parallel skeleton of their own.
24@* The terminology (such as 'pTest' and 'finalTest') follows Singular's
25@ref{modstd.lib} and [1].
26
27REFERENCES:
28[1] Nazeran Idrees, Gerhard Pfister, Stefan Steidel: Parallelization of
29    Modular Algorithms. Journal of Symbolic Computation 46, 672-684 (2011).
30    http://arxiv.org/abs/1005.5663
31
32SEE ALSO:  link, tasks_lib, parallel_lib, modstd_lib, assprimeszerodim_lib
33
34KEYWORDS:  modular.lib; Modular techniques; Parallelization;
35           Skeletons for parallelization; Distributed computing
36
37PROCEDURES:
38  modular(...)  execute a command modulo several primes and lift the result
39                back to characteristic zero
40";
41
42LIB "resources.lib";
43LIB "tasks.lib";
44LIB "parallel.lib";
45
46static proc mod_init()
47{
48    if (!defined(Resources)) {
49        LIB "resources.lib";
50    }
51    int sem_cores = Resources::sem_cores;   // the number of processor cores
52    exportto(Modular, sem_cores);
53}
54
55proc modular(string Command, alias list Arguments, list #)
56"USAGE:   modular(command, arguments[, primeTest, deleteUnluckyPrimes, pTest,
57          finalTest, pmax), command string, arguments list, primeTest proc,
58          deleteUnluckyPrimes proc, pTest proc, finalTest proc, pmax int
59RETURN:   the result of @code{command} applied to @code{arguments},
60          computed using modular methods.
61NOTE:     For the general algorithm and the role of the optional arguments
62          primeTest, deleteUnluckyPrimes, pTest, and finalTest, see
63          @ref{modStd} and the reference given in @ref{modular.lib}. The
64          default for these arguments is that all tests succeed and that all
65          primes are assumed to be lucky.
66       @* The optional argument pmax is an upper bound for the prime numbers
67          to be used for the modular computations. The default is 2147483647
68          (largest prime which can be represented as an @code{int} in
69          Singular), or 536870909 (largest prime below 2^29} for baserings with
70          parameters.
71SEE ALSO: modStd
72EXAMPLE:  example modular; shows an example"
73{
74    /* check for errors */
75    if (char(basering) != 0) {
76        ERROR("The characteristic must be zero.");
77    }
78
79    /* auxiliary variables */
80    int i;
81
82    /* set maximal prime number */
83    int pmax = 2147483647;
84    if (npars(basering) > 0) {
85        pmax = 536870909;   // prime(2^29)
86    }
87
88    /* read optional parameters */
89    list defaults = list(primeTest_default, deleteUnluckyPrimes_default,
90        pTest_default, finalTest_default, pmax);
91    for (i = 1; i <= size(defaults); i++) {
92        if (typeof(#[i]) != typeof(defaults[i])) {
93            # = insert(#, defaults[i], i-1);
94        }
95    }
96    if (size(#) != size(defaults)) {
97        ERROR("wrong optional parameters");
98    }
99    proc primeTest = #[1];
100    proc deleteUnluckyPrimes = #[2];
101    proc pTest = #[3];
102    proc finalTest = #[4];
103    pmax = #[5];
104    exportto(Modular, primeTest);
105
106    /* export command and arguments */
107    exportto(Modular, Command);
108    exportto(Modular, Arguments);
109
110    /* modular computations */
111    def result;
112    def result_lift;
113    bigint N = 1;
114    list modresults;
115    list primes;
116    int nAllPrimes;
117    int nNewPrimes;
118    int p;
119    list indices;
120    int ncores_available;
121    while (1) {
122        // compute list of primes
123        if (nAllPrimes == 0) {
124            nNewPrimes = NbModProcs();
125        }
126        else {
127            ncores_available = system("semaphore", "get_value", sem_cores)+1;
128            nNewPrimes = nAllPrimes div ncores_available;
129            if (nAllPrimes < ncores_available) {
130                nNewPrimes = nAllPrimes;
131            }
132            else {
133                nNewPrimes = (nAllPrimes div ncores_available)
134                    *ncores_available;
135            }
136        }
137        primes = primeList(nNewPrimes, pmax);
138        pmax = primes[size(primes)]-1;
139        nAllPrimes = nAllPrimes+nNewPrimes;
140
141        // do computation modulo several primes
142        for (i = size(primes); i > 0; i--) {
143            task t(i) = "Modular::modp", primes[i];
144        }
145        startTasks(t(1..size(primes)));
146        waitAllTasks(t(1..size(primes)));
147        for (i = size(primes); i > 0; i--) {
148            modresults[i] = getResult(t(i));
149            killTask(t(i));
150            kill t(i);
151        }
152
153        // delete unlucky primes
154        indices = deleteUnluckyPrimes(modresults);
155        for (i = size(indices); i > 0; i--) {
156            modresults = delete(modresults, indices[i]);
157        }
158
159        // lift result
160        if (N == 1) {
161            result_lift = chinrem(modresults, primes);
162        }
163        else {
164            result_lift = chinrem(list(result_lift)+modresults,
165                list(N)+primes);
166        }
167        for (i = size(primes); i > 0; i--) {
168            N = N*primes[i];
169        }
170
171        // apply farey
172        result = farey_parallel(result_lift, N);
173
174        // pTest
175        p = prime(random(pmax div 2, pmax-1));
176        while (!Modular::primeTest(p, Arguments)) {
177            if (p <= 2) {
178                ERROR("no more primes");
179            }
180            p = prime(random(p div 2, p-1));
181        }
182        if (!pTest(Command, Arguments, result, p)) {
183            continue;
184        }
185
186        // finalTest
187        if (finalTest(Command, Arguments, result)) {
188            break;
189        }
190    }
191
192    /* kill exported data */
193    kill Command;
194    kill Arguments;
195    kill primeTest;
196
197    /* return of result */
198    return(result);
199}
200example
201{
202    "EXAMPLE:";
203    echo = 2;
204    ring R = 0, (x,y), dp;
205    ideal I = x9y2+x10, x2y7-y8;
206    modular("std", list(I));
207}
208
209static proc primeList(int n, int pmax)
210{
211    list primes;
212    int p = pmax;
213    int i;
214    for (i = 1; i <= n; i++) {
215        if (p < 2) {
216            ERROR("no more primes");
217        }
218        p = prime(p);
219        task t(i) = "Modular::primeList_task", list(p);
220        p--;
221    }
222    startTasks(t(1..n));
223    waitAllTasks(t(1..n));
224    int j;
225    for (i = 1; i <= n; i++) {
226        if (getResult(t(i))) {
227            j++;
228            primes[j] = getArguments(t(i))[1];
229        }
230        killTask(t(i));
231    }
232    if (j < n) {
233        primes = primes+primeList(n-j, p);
234    }
235    return(primes);
236}
237
238static proc primeList_task(int p)
239{
240    return(Modular::primeTest(p, Arguments));
241}
242
243static proc modp(int p)
244{
245    def br = basering;
246    list lbr = ringlist(br);
247    if (typeof(lbr[1]) == "int") {
248        lbr[1] = p;
249    }
250    else {
251        lbr[1][1] = p;
252    }
253    def rp = ring(lbr);
254    setring(rp);
255    list args = fetch(br, Arguments);
256    execute("def result = "+Command+"("+Tasks::argsToString("args", size(args))
257        +");");
258    setring(br);
259    def result = fetch(rp, result);
260    return(result);
261}
262
263static proc primeTest_default(int p, alias list args)
264{
265    return(1);
266}
267
268static proc deleteUnluckyPrimes_default(alias list modresults)
269{
270    return(list());
271}
272
273static proc pTest_default(string command, alias list args, def result, int p)
274{
275    return(1);
276}
277
278static proc finalTest_default(string command, alias list args, def result)
279{
280    return(1);
281}
282
283static proc farey_parallel(ideal farey_arg, bigint farey_N)
284{
285    exportto(Modular, farey_arg);
286    exportto(Modular, farey_N);
287    int size_arg = ncols(farey_arg);
288    int chunks = par_range(size_arg);
289    intvec range;
290    int i;
291    for (i = chunks; i > 0; i--) {
292        range = par_range(size_arg, i);
293        task t(i) = "Modular::farey_task", list(range);
294    }
295    startTasks(t(1..chunks));
296    waitAllTasks(t(1..chunks));
297    ideal result = getResult(t(chunks));
298    for (i = chunks-1; i > 0; i--) {
299        result = getResult(t(i)), result;
300        killTask(t(i));
301    }
302    kill farey_arg;
303    kill farey_N;
304    return(result);
305}
306
307static proc farey_task(intvec range)
308{
309    ideal result = farey(ideal(farey_arg[range[1]..range[2]]), farey_N);
310    return(result);
311}
312
313static proc par_range(int N, list #)
314{
315    int nchunks = 2*getcores();
316    if (nchunks > N) {
317        nchunks = N;
318    }
319    if (size(#)) {
320        int index = #[1];
321        intvec range = ((N*(index-1)) div nchunks)+1, (N*index) div nchunks;
322        return(range);
323    }
324    else {
325        return(nchunks);
326    }
327}
328
329static proc NbModProcs()
330{
331    int available = system("semaphore", "get_value", sem_cores)+1;
332    int nb;
333    if (available < 16) {
334        nb = ((10 div available)+1-(10%available == 0))*available;
335    }
336    else {   // gives approx. (log_2(available))^2
337        int tmp = available;
338        while (tmp > 1) {
339            tmp = tmp div 2;
340            nb++;
341        }   // nb = log_2(available)
342        nb = ((2*nb+1)*available) div (2^nb) + (nb-1)^2 - 2;
343    }
344    return(nb);
345}
346
Note: See TracBrowser for help on using the repository browser.