001/* 002 * $Id$ 003 */ 004 005package edu.jas.structure; 006 007 008import java.util.List; 009 010import org.apache.logging.log4j.LogManager; 011import org.apache.logging.log4j.Logger; 012 013 014/** 015 * Power class to compute powers of RingElem. 016 * @author Heinz Kredel 017 */ 018public class Power<C extends RingElem<C>> { 019 020 021 private static final Logger logger = LogManager.getLogger(Power.class); 022 023 024 private static final boolean debug = logger.isDebugEnabled(); 025 026 027 private final RingFactory<C> fac; 028 029 030 /** 031 * The constructor creates a Power object. 032 */ 033 public Power() { 034 this(null); 035 } 036 037 038 /** 039 * The constructor creates a Power object. 040 * @param fac ring factory 041 */ 042 public Power(RingFactory<C> fac) { 043 this.fac = fac; 044 } 045 046 047 /** 048 * power of a to the n-th, n positive. 049 * @param a element. 050 * @param n integer exponent ≥ 0. 051 * @return a^n. 052 */ 053 public static <C extends RingElem<C>> C positivePower(C a, long n) { 054 if (n <= 0) { 055 throw new IllegalArgumentException("only positive n allowed"); 056 } 057 if (a.isZERO() || a.isONE()) { 058 return a; 059 } 060 C b = a; 061 long i = n - 1; 062 C p = b; 063 do { 064 if (i % 2 == 1) { 065 p = p.multiply(b); 066 } 067 i = i / 2; 068 if (i > 0) { 069 b = b.multiply(b); 070 } 071 } while (i > 0); 072 return p; 073 } 074 075 076 /** 077 * power of a to the n-th, n positive. 078 * @param a element. 079 * @param n java.math.BigInteger exponent ≥ 0. 080 * @return a^n. 081 */ 082 public static <C extends RingElem<C>> C positivePower(C a, java.math.BigInteger n) { 083 if (n.signum() <= 0) { 084 throw new IllegalArgumentException("only positive n allowed"); 085 } 086 if (a.isZERO() || a.isONE()) { 087 return a; 088 } 089 C b = a; 090 if (n.compareTo(java.math.BigInteger.ONE) == 0) { 091 return b; 092 } 093 if (n.bitLength() <= 63) { 094 long l = n.longValue(); 095 return positivePower(a, l); 096 } 097 C p = a; 098 java.math.BigInteger i = n.subtract(java.math.BigInteger.ONE); 099 do { 100 if (i.testBit(0)) { 101 p = p.multiply(b); 102 } 103 i = i.shiftRight(1); 104 if (i.signum() > 0) { 105 b = b.multiply(b); 106 } 107 } while (i.signum() > 0); 108 return p; 109 } 110 111 112 /** 113 * power of a to the n-th, n positive, modulo m. 114 * @param a element. 115 * @param n integer exponent ≥ 0. 116 * @param m modulus. 117 * @return a^n mod m. 118 */ 119 public static <C extends RingElem<C>> C modPositivePower(C a, long n, C m) { 120 if (n <= 0) { 121 throw new IllegalArgumentException("only positive n allowed"); 122 } 123 if (a.isZERO() || a.isONE()) { 124 return a; 125 } 126 127 C b = a.remainder(m); 128 long i = n - 1; 129 C p = b; 130 do { 131 if (i % 2 == 1) { 132 p = p.multiply(b).remainder(m); 133 } 134 i = i / 2; 135 if (i > 0) { 136 b = b.multiply(b).remainder(m); 137 } 138 } while (i > 0); 139 return p; 140 } 141 142 143 /** 144 * power of a to the n-th. 145 * @param a element. 146 * @param n integer exponent. 147 * @param fac ring factory. 148 * @return a^n, with 0^0 = 0 and a^{-n} = {1/a}^n. 149 */ 150 @SuppressWarnings("unchecked") 151 public static <C extends RingElem<C>> C power(RingFactory<C> fac, C a, long n) { 152 if (a == null || a.isZERO()) { 153 return a; 154 } 155 //return a; 156 return (C) Power.<MonoidElem> power((MonoidFactory) fac, a, n); 157 } 158 159 160 /** 161 * power of a to the n-th. 162 * @param a element. 163 * @param n integer exponent. 164 * @param fac monoid factory. 165 * @return a^n, with a^{-n} = {1/a}^n. 166 */ 167 public static <C extends MonoidElem<C>> C power(MonoidFactory<C> fac, C a, long n) { 168 if (n == 0) { 169 if (fac == null) { 170 throw new IllegalArgumentException("fac may not be null for a^0"); 171 } 172 return fac.getONE(); 173 } 174 if (a.isONE()) { 175 return a; 176 } 177 C b = a; 178 if (n < 0) { 179 b = a.inverse(); 180 n = -n; 181 } 182 if (n == 1) { 183 return b; 184 } 185 if (fac == null) { 186 throw new IllegalArgumentException("fac may not be null for n > 1"); 187 } 188 C p = fac.getONE(); 189 long i = n; 190 do { 191 if (i % 2 == 1) { 192 p = p.multiply(b); 193 } 194 i = i / 2; 195 if (i > 0) { 196 b = b.multiply(b); 197 } 198 } while (i > 0); 199 if (n > 11 && debug) { 200 logger.info("n = " + n + ", p = " + p); 201 } 202 return p; 203 } 204 205 206 /** 207 * power of a to the n-th modulo m. 208 * @param a element. 209 * @param n integer exponent. 210 * @param m modulus. 211 * @param fac monoid factory. 212 * @return a^n mod m, with a^{-n} = {1/a}^n. 213 */ 214 public static <C extends MonoidElem<C>> C modPower(MonoidFactory<C> fac, C a, long n, C m) { 215 if (n == 0) { 216 if (fac == null) { 217 throw new IllegalArgumentException("fac may not be null for a^0"); 218 } 219 return fac.getONE(); 220 } 221 if (a.isONE()) { 222 return a; 223 } 224 C b = a.remainder(m); 225 if (n < 0) { 226 b = a.inverse().remainder(m); 227 n = -n; 228 } 229 if (n == 1) { 230 return b; 231 } 232 if (fac == null) { 233 throw new IllegalArgumentException("fac may not be null for n > 1"); 234 } 235 C p = fac.getONE(); 236 long i = n; 237 do { 238 if (i % 2 == 1) { 239 p = p.multiply(b).remainder(m); 240 } 241 i = i / 2; 242 if (i > 0) { 243 b = b.multiply(b).remainder(m); 244 } 245 } while (i > 0); 246 if (n > 11 && debug) { 247 logger.info("n = " + n + ", p = " + p); 248 } 249 return p; 250 } 251 252 253 /** 254 * power of a to the n-th modulo m. 255 * @param a element. 256 * @param n integer exponent. 257 * @param m modulus. 258 * @param fac monoid factory. 259 * @return a^n mod m, with a^{-n} = {1/a}^n. 260 */ 261 public static <C extends MonoidElem<C>> C modPower(MonoidFactory<C> fac, C a, java.math.BigInteger n, 262 C m) { 263 if (n.signum() == 0) { 264 if (fac == null) { 265 throw new IllegalArgumentException("fac may not be null for a^0"); 266 } 267 return fac.getONE(); 268 } 269 if (a.isONE()) { 270 return a; 271 } 272 C b = a.remainder(m); 273 if (n.signum() < 0) { 274 b = a.inverse().remainder(m); 275 n = n.negate(); 276 } 277 if (n.compareTo(java.math.BigInteger.ONE) == 0) { 278 return b; 279 } 280 if (n.bitLength() <= 63) { 281 long l = n.longValue(); 282 return modPower(fac, a, l, m); 283 } 284 if (fac == null) { 285 throw new IllegalArgumentException("fac may not be null for n > 1"); 286 } 287 C p = fac.getONE(); 288 java.math.BigInteger i = n; 289 do { 290 if (i.testBit(0)) { 291 p = p.multiply(b).remainder(m); 292 } 293 i = i.shiftRight(1); 294 if (i.signum() > 0) { 295 b = b.multiply(b).remainder(m); 296 } 297 } while (i.signum() > 0); 298 if (debug) { 299 logger.info("n = " + n + ", p = " + p); 300 } 301 return p; 302 } 303 304 305 /** 306 * power of a to the n-th. 307 * @param a element. 308 * @param n integer exponent. 309 * @return a^n, with 0^0 = 0. 310 */ 311 public C power(C a, long n) { 312 return power(fac, a, n); 313 } 314 315 316 /** 317 * power of a to the n-th. 318 * @param a long. 319 * @param n integer exponent. 320 * @return a^n, with a^0 = 1. 321 */ 322 public static long power(long a, long n) { 323 if (n == 0) { 324 return 1L; 325 } 326 if (a == 1L) { 327 return a; 328 } 329 long b = a; 330 if (n == 1L) { 331 return b; 332 } 333 long p = 1L; 334 long i = n; 335 do { 336 if (i % 2 == 1) { 337 p = p * b; 338 } 339 i = i / 2; 340 if (i > 0) { 341 b = b * b; 342 } 343 } while (i > 0); 344 if (n > 11 && debug) { 345 logger.info("n = " + n + ", p = " + p); 346 } 347 return p; 348 } 349 350 351 /** 352 * power of a to the n-th mod m. 353 * @param a element. 354 * @param n integer exponent. 355 * @param m modulus. 356 * @return a^n mod m, with 0^0 = 0. 357 */ 358 public C modPower(C a, long n, C m) { 359 return modPower(fac, a, n, m); 360 } 361 362 363 /** 364 * power of a to the n-th mod m. 365 * @param a element. 366 * @param n integer exponent. 367 * @param m modulus. 368 * @return a^n mod m, with 0^0 = 0. 369 */ 370 public C modPower(C a, java.math.BigInteger n, C m) { 371 return modPower(fac, a, n, m); 372 } 373 374 375 /** 376 * Logarithm. 377 * @param p logarithm base. 378 * @param a element. 379 * @return k ≥ 1 minimal with p^k ≥ b. 380 */ 381 public static <C extends RingElem<C>> long logarithm(C p, C a) { 382 //if ( p.compareTo(a) < 0 ) { 383 // return 0L; 384 //} 385 long k = 1L; 386 C m = p; 387 while (m.compareTo(a) < 0) { 388 m = m.multiply(p); 389 k++; 390 } 391 return k; 392 } 393 394 395 /** 396 * Multiply elements in list. 397 * @param A list of elements (a_0,...,a_k). 398 * @param fac ring factory. 399 * @return prod(i=0,...k) a_i. 400 */ 401 public static <C extends RingElem<C>> C multiply(RingFactory<C> fac, List<C> A) { 402 return multiply((MonoidFactory<C>) fac, A); 403 } 404 405 406 /** 407 * Multiply elements in list. 408 * @param A list of elements (a_0,...,a_k). 409 * @param fac monoid factory. 410 * @return prod(i=0,...k) a_i. 411 */ 412 public static <C extends MonoidElem<C>> C multiply(MonoidFactory<C> fac, List<C> A) { 413 if (fac == null) { 414 throw new IllegalArgumentException("fac may not be null for empty list"); 415 } 416 C res = fac.getONE(); 417 if (A == null || A.isEmpty()) { 418 return res; 419 } 420 for (C a : A) { 421 res = res.multiply(a); 422 } 423 return res; 424 } 425 426 427 /** 428 * Sum elements in list. 429 * @param A list of elements (a_0,...,a_k). 430 * @param fac ring factory. 431 * @return sum(i=0,...k) a_i. 432 */ 433 public static <C extends RingElem<C>> C sum(RingFactory<C> fac, List<C> A) { 434 return sum((AbelianGroupFactory<C>) fac, A); 435 } 436 437 438 /** 439 * Sum elements in list. 440 * @param A list of elements (a_0,...,a_k). 441 * @param fac monoid factory. 442 * @return sum(i=0,...k) a_i. 443 */ 444 public static <C extends AbelianGroupElem<C>> C sum(AbelianGroupFactory<C> fac, List<C> A) { 445 if (fac == null) { 446 throw new IllegalArgumentException("fac may not be null for empty list"); 447 } 448 C res = fac.getZERO(); 449 if (A == null || A.isEmpty()) { 450 return res; 451 } 452 for (C a : A) { 453 res = res.sum(a); 454 } 455 return res; 456 } 457 458}