/usr/share/singular/LIB/modular.lib is in singular-data 4.0.3+ds-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | ////////////////////////////////////////////////////////////////////
version="version modular.lib 4.0.2 May_2015 "; // $Id: 11175274e7170f07c9642eedd11eface43fd4194 $
category="General purpose";
info="
LIBRARY: modular.lib An abstraction layer for modular techniques
AUTHOR: Andreas Steenpass, e-mail: steenpass@mathematik.uni-kl.de
OVERVIEW:
This library is an abstraction layer for modular techniques which are
well-known to speed up many computations and to be easy parallelizable.
@* The basic idea is to execute some computation modulo several primes and then
to lift the result back to characteristic zero via the farey rational map and
chinese remaindering. It is thus possible to overcome the often problematic
coefficient swell and to run the modular computations in parallel.
@* In Singular, modular techniques have been quite successfully employed for
several applications. A first implementation was done for Groebner bases in
Singular's @ref{modstd_lib}, a pioneering work by Stefan Steidel. Since the
algorithm is basically the same for all applications, this library aims at
preventing library authors from writing the same code over and over again by
providing an appropriate abstraction layer. It also offers one-line commands
for ordinary Singular users who want to take advantage of modular techniques
for their own calculations. Thus modular techniques can be regarded as
a parallel skeleton of their own.
@* The terminology (such as 'pTest' and 'finalTest') follows Singular's
@ref{modstd_lib} and [1].
REFERENCES:
[1] Nazeran Idrees, Gerhard Pfister, Stefan Steidel: Parallelization of
Modular Algorithms. Journal of Symbolic Computation 46, 672-684 (2011).
http://arxiv.org/abs/1005.5663
SEE ALSO: link, tasks_lib, parallel_lib, modstd_lib, assprimeszerodim_lib
KEYWORDS: modular_lib; Modular techniques; Parallelization;
Skeletons for parallelization; Distributed computing
PROCEDURES:
modular(...) execute a command modulo several primes and lift the result
back to characteristic zero
";
LIB "resources.lib";
LIB "tasks.lib";
LIB "parallel.lib";
static proc mod_init()
{
string arg_type;
export arg_type;
if (!defined(Resources)) {
LIB "resources.lib";
}
int sem_cores = Resources::sem_cores; // the number of processor cores
exportto(Modular, sem_cores);
}
proc modular(string Command, alias list Arguments, list #)
"USAGE: modular(command, arguments[, primeTest, deleteUnluckyPrimes, pTest,
finalTest, pmax), command string, arguments list, primeTest proc,
deleteUnluckyPrimes proc, pTest proc, finalTest proc, pmax int
RETURN: the result of @code{command} applied to @code{arguments},
computed using modular methods.
NOTE: For the general algorithm and the role of the optional arguments
primeTest, deleteUnluckyPrimes, pTest, and finalTest, see
@ref{modStd} and the reference given in @ref{modular_lib}. The
default for these arguments is that all tests succeed and that all
primes are assumed to be lucky.
@* The type of the result when @code{command} is applied to
@code{arguments} must be either @code{bigint}, @code{ideal},
@code{module}, or @code{matrix}.
@* The optional argument pmax is an upper bound for the prime numbers
to be used for the modular computations. The default is 2147483647
(largest prime which can be represented as an @code{int} in
Singular), or 536870909 (largest prime below 2^29} for baserings with
parameters.
SEE ALSO: modStd
EXAMPLE: example modular; shows an example"
{
/* check for errors */
if (char(basering) != 0) {
ERROR("The characteristic must be zero.");
}
/* auxiliary variables */
int i;
/* set maximal prime number */
int pmax = 2147483647;
if (npars(basering) > 0) {
pmax = 536870909; // prime(2^29)
}
/* read optional parameters */
list defaults = list(primeTest_default, deleteUnluckyPrimes_default,
pTest_default, finalTest_default, pmax);
for (i = 1; i <= size(defaults); i++) {
if (typeof(#[i]) != typeof(defaults[i])) {
# = insert(#, defaults[i], i-1);
}
}
if (size(#) != size(defaults)) {
ERROR("wrong optional parameters");
}
proc primeTest = #[1];
proc deleteUnluckyPrimes = #[2];
proc pTest = #[3];
proc finalTest = #[4];
pmax = #[5];
exportto(Modular, primeTest);
/* export command and arguments */
exportto(Modular, Command);
exportto(Modular, Arguments);
/* modular computations */
def result;
def result_lift;
bigint N = 1;
list modresults;
list primes;
int nAllPrimes;
int nNewPrimes;
int p;
list indices;
int ncores_available;
while (1) {
// compute list of primes
if (nAllPrimes == 0) {
nNewPrimes = NbModProcs();
}
else {
ncores_available = system("semaphore", "get_value", sem_cores)+1;
if (nAllPrimes < ncores_available) {
nNewPrimes = nAllPrimes;
}
else {
nNewPrimes = (nAllPrimes div ncores_available)
*ncores_available;
}
}
primes = primeList(nNewPrimes, pmax);
pmax = primes[size(primes)]-1;
nAllPrimes = nAllPrimes+nNewPrimes;
// do computation modulo several primes
for (i = size(primes); i > 0; i--) {
task t(i) = "Modular::modp", primes[i];
}
startTasks(t(1..size(primes)));
waitAllTasks(t(1..size(primes)));
for (i = size(primes); i > 0; i--) {
modresults[i] = getResult(t(i));
killTask(t(i));
kill t(i);
}
// delete unlucky primes
indices = deleteUnluckyPrimes(modresults);
for (i = size(indices); i > 0; i--) {
modresults = delete(modresults, indices[i]);
primes = delete(primes, indices[i]);
}
// lift result
if (N == 1) {
result_lift = chinrem(modresults, primes);
}
else {
result_lift = chinrem(list(result_lift)+modresults,
list(N)+primes);
}
modresults = list();
for (i = size(primes); i > 0; i--) {
N = N*primes[i];
}
// apply farey
result = farey_parallel(result_lift, N);
// pTest
p = prime(random(pmax div 2, pmax-1));
while (!Modular::primeTest(p, Arguments)) {
if (p <= 2) {
ERROR("no more primes");
}
p = prime(random(p div 2, p-1));
}
if (!pTest(Command, Arguments, result, p)) {
continue;
}
// finalTest
if (finalTest(Command, Arguments, result)) {
break;
}
}
/* kill exported data */
kill Command;
kill Arguments;
kill primeTest;
/* return of result */
return(result);
}
example
{
"EXAMPLE:";
echo = 2;
ring R = 0, (x,y), dp;
ideal I = x9y2+x10, x2y7-y8;
modular("std", list(I));
}
static proc primeList(int n, int pmax)
{
list primes;
int p = pmax;
int i;
for (i = 1; i <= n; i++) {
if (p < 2) {
ERROR("no more primes");
}
p = prime(p);
task t(i) = "Modular::primeList_task", list(p);
p--;
}
startTasks(t(1..n));
waitAllTasks(t(1..n));
int j;
for (i = 1; i <= n; i++) {
if (getResult(t(i))) {
j++;
primes[j] = getArguments(t(i))[1];
}
killTask(t(i));
}
if (j < n) {
primes = primes+primeList(n-j, p);
}
return(primes);
}
static proc primeList_task(int p)
{
return(Modular::primeTest(p, Arguments));
}
static proc modp(int p)
{
def br = basering;
list lbr = ringlist(br);
if (typeof(lbr[1]) == "int") {
lbr[1] = p;
}
else {
lbr[1][1] = p;
}
def rp = ring(lbr);
setring(rp);
list args = fetch(br, Arguments);
execute("def result = "+Command+"("+Tasks::argsToString("args", size(args))
+");");
setring(br);
def result = fetch(rp, result);
return(result);
}
static proc primeTest_default(int p, alias list args)
{
return(1);
}
static proc deleteUnluckyPrimes_default(alias list modresults)
{
return(list());
}
static proc pTest_default(string command, alias list args, def result, int p)
{
return(1);
}
static proc finalTest_default(string command, alias list args, def result)
{
return(1);
}
static proc farey_parallel(def farey_arg, bigint farey_N)
{
arg_type = typeof(farey_arg);
if (arg_type != "bigint" && arg_type != "ideal"
&& arg_type != "module" && arg_type != "matrix") {
ERROR("wrong input type");
}
if (arg_type == "bigint" || arg_type == "matrix") {
return(farey(farey_arg, farey_N));
} // else: farey_arg is an ideal or a module
exportto(Modular, farey_arg);
exportto(Modular, farey_N);
int size_arg = ncols(farey_arg);
int chunks = par_range(size_arg);
intvec range;
int i;
for (i = chunks; i > 0; i--) {
range = par_range(size_arg, i);
task t(i) = "Modular::farey_task", list(range);
}
startTasks(t(1..chunks));
waitAllTasks(t(1..chunks));
def result = getResult(t(chunks));
for (i = chunks-1; i > 0; i--) {
result = getResult(t(i)), result;
killTask(t(i));
}
kill farey_arg;
kill farey_N;
return(result);
}
static proc farey_task(intvec range)
{
execute("def result = farey("+arg_type+"(farey_arg[range[1]..range[2]]),"
+" farey_N);");
return(result);
}
static proc par_range(int N, list #)
{
int nchunks = 2*getcores();
if (nchunks > N) {
nchunks = N;
}
if (size(#)) {
int index = #[1];
intvec range = ((N*(index-1)) div nchunks)+1, (N*index) div nchunks;
return(range);
}
else {
return(nchunks);
}
}
static proc NbModProcs()
{
int available = system("semaphore", "get_value", sem_cores)+1;
int nb;
if (available < 16) {
nb = ((10 div available)+1-(10%available == 0))*available;
}
else { // gives approx. (log_2(available))^2
int tmp = available;
while (tmp > 1) {
tmp = tmp div 2;
nb++;
} // nb = log_2(available)
nb = ((2*nb+1)*available) div (2^nb) + (nb-1)^2 - 2;
}
return(nb);
}
|