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