source: git/Singular/LIB/modular.lib @ 1ab7bf

spielwiese
Last change on this file since 1ab7bf was 1ab7bf, checked in by Hans Schoenemann <hannes@…>, 10 years ago
fix: references in modular.lib
  • Property mode set to 100644
File size: 9.8 KB
Line 
1////////////////////////////////////////////////////////////////////
2version="version modular.lib 4.0.0.0 May_2014 "; // $Id$
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            if (nAllPrimes < ncores_available) {
129                nNewPrimes = nAllPrimes;
130            }
131            else {
132                nNewPrimes = (nAllPrimes div ncores_available)
133                    *ncores_available;
134            }
135        }
136        primes = primeList(nNewPrimes, pmax);
137        pmax = primes[size(primes)]-1;
138        nAllPrimes = nAllPrimes+nNewPrimes;
139
140        // do computation modulo several primes
141        for (i = size(primes); i > 0; i--) {
142            task t(i) = "Modular::modp", primes[i];
143        }
144        startTasks(t(1..size(primes)));
145        waitAllTasks(t(1..size(primes)));
146        for (i = size(primes); i > 0; i--) {
147            modresults[i] = getResult(t(i));
148            killTask(t(i));
149            kill t(i);
150        }
151
152        // delete unlucky primes
153        indices = deleteUnluckyPrimes(modresults);
154        for (i = size(indices); i > 0; i--) {
155            modresults = delete(modresults, indices[i]);
156            primes = delete(primes, 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        modresults = list();
168        for (i = size(primes); i > 0; i--) {
169            N = N*primes[i];
170        }
171
172        // apply farey
173        result = farey_parallel(result_lift, N);
174
175        // pTest
176        p = prime(random(pmax div 2, pmax-1));
177        while (!Modular::primeTest(p, Arguments)) {
178            if (p <= 2) {
179                ERROR("no more primes");
180            }
181            p = prime(random(p div 2, p-1));
182        }
183        if (!pTest(Command, Arguments, result, p)) {
184            continue;
185        }
186
187        // finalTest
188        if (finalTest(Command, Arguments, result)) {
189            break;
190        }
191    }
192
193    /* kill exported data */
194    kill Command;
195    kill Arguments;
196    kill primeTest;
197
198    /* return of result */
199    return(result);
200}
201example
202{
203    "EXAMPLE:";
204    echo = 2;
205    ring R = 0, (x,y), dp;
206    ideal I = x9y2+x10, x2y7-y8;
207    modular("std", list(I));
208}
209
210static proc primeList(int n, int pmax)
211{
212    list primes;
213    int p = pmax;
214    int i;
215    for (i = 1; i <= n; i++) {
216        if (p < 2) {
217            ERROR("no more primes");
218        }
219        p = prime(p);
220        task t(i) = "Modular::primeList_task", list(p);
221        p--;
222    }
223    startTasks(t(1..n));
224    waitAllTasks(t(1..n));
225    int j;
226    for (i = 1; i <= n; i++) {
227        if (getResult(t(i))) {
228            j++;
229            primes[j] = getArguments(t(i))[1];
230        }
231        killTask(t(i));
232    }
233    if (j < n) {
234        primes = primes+primeList(n-j, p);
235    }
236    return(primes);
237}
238
239static proc primeList_task(int p)
240{
241    return(Modular::primeTest(p, Arguments));
242}
243
244static proc modp(int p)
245{
246    def br = basering;
247    list lbr = ringlist(br);
248    if (typeof(lbr[1]) == "int") {
249        lbr[1] = p;
250    }
251    else {
252        lbr[1][1] = p;
253    }
254    def rp = ring(lbr);
255    setring(rp);
256    list args = fetch(br, Arguments);
257    execute("def result = "+Command+"("+Tasks::argsToString("args", size(args))
258        +");");
259    setring(br);
260    def result = fetch(rp, result);
261    return(result);
262}
263
264static proc primeTest_default(int p, alias list args)
265{
266    return(1);
267}
268
269static proc deleteUnluckyPrimes_default(alias list modresults)
270{
271    return(list());
272}
273
274static proc pTest_default(string command, alias list args, def result, int p)
275{
276    return(1);
277}
278
279static proc finalTest_default(string command, alias list args, def result)
280{
281    return(1);
282}
283
284static proc farey_parallel(ideal farey_arg, bigint farey_N)
285{
286    exportto(Modular, farey_arg);
287    exportto(Modular, farey_N);
288    int size_arg = ncols(farey_arg);
289    int chunks = par_range(size_arg);
290    intvec range;
291    int i;
292    for (i = chunks; i > 0; i--) {
293        range = par_range(size_arg, i);
294        task t(i) = "Modular::farey_task", list(range);
295    }
296    startTasks(t(1..chunks));
297    waitAllTasks(t(1..chunks));
298    ideal result = getResult(t(chunks));
299    for (i = chunks-1; i > 0; i--) {
300        result = getResult(t(i)), result;
301        killTask(t(i));
302    }
303    kill farey_arg;
304    kill farey_N;
305    return(result);
306}
307
308static proc farey_task(intvec range)
309{
310    ideal result = farey(ideal(farey_arg[range[1]..range[2]]), farey_N);
311    return(result);
312}
313
314static proc par_range(int N, list #)
315{
316    int nchunks = 2*getcores();
317    if (nchunks > N) {
318        nchunks = N;
319    }
320    if (size(#)) {
321        int index = #[1];
322        intvec range = ((N*(index-1)) div nchunks)+1, (N*index) div nchunks;
323        return(range);
324    }
325    else {
326        return(nchunks);
327    }
328}
329
330static proc NbModProcs()
331{
332    int available = system("semaphore", "get_value", sem_cores)+1;
333    int nb;
334    if (available < 16) {
335        nb = ((10 div available)+1-(10%available == 0))*available;
336    }
337    else {   // gives approx. (log_2(available))^2
338        int tmp = available;
339        while (tmp > 1) {
340            tmp = tmp div 2;
341            nb++;
342        }   // nb = log_2(available)
343        nb = ((2*nb+1)*available) div (2^nb) + (nb-1)^2 - 2;
344    }
345    return(nb);
346}
347
Note: See TracBrowser for help on using the repository browser.