001/* 002 * $Id: Power.java 5872 2018-07-20 16:01:46Z kredel $ 003 */ 004 005package edu.jas.structure; 006 007 008import java.util.List; 009 010import org.apache.logging.log4j.Logger; 011import org.apache.logging.log4j.LogManager; 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 C p = fac.getONE(); 186 long i = n; 187 do { 188 if (i % 2 == 1) { 189 p = p.multiply(b); 190 } 191 i = i / 2; 192 if (i > 0) { 193 b = b.multiply(b); 194 } 195 } while (i > 0); 196 if (n > 11 && debug) { 197 logger.info("n = " + n + ", p = " + p); 198 } 199 return p; 200 } 201 202 203 /** 204 * power of a to the n-th modulo m. 205 * @param a element. 206 * @param n integer exponent. 207 * @param m modulus. 208 * @param fac monoid factory. 209 * @return a^n mod m, with a^{-n} = {1/a}^n. 210 */ 211 public static <C extends MonoidElem<C>> C modPower(MonoidFactory<C> fac, C a, long n, C m) { 212 if (n == 0) { 213 if (fac == null) { 214 throw new IllegalArgumentException("fac may not be null for a^0"); 215 } 216 return fac.getONE(); 217 } 218 if (a.isONE()) { 219 return a; 220 } 221 C b = a.remainder(m); 222 if (n < 0) { 223 b = a.inverse().remainder(m); 224 n = -n; 225 } 226 if (n == 1) { 227 return b; 228 } 229 C p = fac.getONE(); 230 long i = n; 231 do { 232 if (i % 2 == 1) { 233 p = p.multiply(b).remainder(m); 234 } 235 i = i / 2; 236 if (i > 0) { 237 b = b.multiply(b).remainder(m); 238 } 239 } while (i > 0); 240 if (n > 11 && debug) { 241 logger.info("n = " + n + ", p = " + p); 242 } 243 return p; 244 } 245 246 247 /** 248 * power of a to the n-th modulo m. 249 * @param a element. 250 * @param n integer exponent. 251 * @param m modulus. 252 * @param fac monoid factory. 253 * @return a^n mod m, with a^{-n} = {1/a}^n. 254 */ 255 public static <C extends MonoidElem<C>> C modPower(MonoidFactory<C> fac, C a, java.math.BigInteger n, C m) { 256 if (n.signum() == 0) { 257 if (fac == null) { 258 throw new IllegalArgumentException("fac may not be null for a^0"); 259 } 260 return fac.getONE(); 261 } 262 if (a.isONE()) { 263 return a; 264 } 265 C b = a.remainder(m); 266 if (n.signum() < 0) { 267 b = a.inverse().remainder(m); 268 n = n.negate(); 269 } 270 if (n.compareTo(java.math.BigInteger.ONE) == 0) { 271 return b; 272 } 273 if (n.bitLength() <= 63) { 274 long l = n.longValue(); 275 return modPower(fac, a, l, m); 276 } 277 C p = fac.getONE(); 278 java.math.BigInteger i = n; 279 do { 280 if (i.testBit(0)) { 281 p = p.multiply(b).remainder(m); 282 } 283 i = i.shiftRight(1); 284 if (i.signum() > 0) { 285 b = b.multiply(b).remainder(m); 286 } 287 } while (i.signum() > 0); 288 if (debug) { 289 logger.info("n = " + n + ", p = " + p); 290 } 291 return p; 292 } 293 294 295 /** 296 * power of a to the n-th. 297 * @param a element. 298 * @param n integer exponent. 299 * @return a^n, with 0^0 = 0. 300 */ 301 public C power(C a, long n) { 302 return power(fac, a, n); 303 } 304 305 306 /** 307 * power of a to the n-th. 308 * @param a long. 309 * @param n integer exponent. 310 * @return a^n, with a^0 = 1. 311 */ 312 public static long power(long a, long n) { 313 if (n == 0) { 314 return 1L; 315 } 316 if (a == 1L) { 317 return a; 318 } 319 long b = a; 320 if (n == 1L) { 321 return b; 322 } 323 long p = 1L; 324 long i = n; 325 do { 326 if (i % 2 == 1) { 327 p = p * b; 328 } 329 i = i / 2; 330 if (i > 0) { 331 b = b * b; 332 } 333 } while (i > 0); 334 if (n > 11 && debug) { 335 logger.info("n = " + n + ", p = " + p); 336 } 337 return p; 338 } 339 340 341 /** 342 * power of a to the n-th mod m. 343 * @param a element. 344 * @param n integer exponent. 345 * @param m modulus. 346 * @return a^n mod m, with 0^0 = 0. 347 */ 348 public C modPower(C a, long n, C m) { 349 return modPower(fac, a, n, m); 350 } 351 352 353 /** 354 * power of a to the n-th mod m. 355 * @param a element. 356 * @param n integer exponent. 357 * @param m modulus. 358 * @return a^n mod m, with 0^0 = 0. 359 */ 360 public C modPower(C a, java.math.BigInteger n, C m) { 361 return modPower(fac, a, n, m); 362 } 363 364 365 /** 366 * Logarithm. 367 * @param p logarithm base. 368 * @param a element. 369 * @return k ≥ 1 minimal with p^k ≥ b. 370 */ 371 public static <C extends RingElem<C>> long logarithm(C p, C a) { 372 //if ( p.compareTo(a) < 0 ) { 373 // return 0L; 374 //} 375 long k = 1L; 376 C m = p; 377 while (m.compareTo(a) < 0) { 378 m = m.multiply(p); 379 k++; 380 } 381 return k; 382 } 383 384 385 /** 386 * Multiply elements in list. 387 * @param A list of elements (a_0,...,a_k). 388 * @param fac ring factory. 389 * @return prod(i=0,...k) a_i. 390 */ 391 public static <C extends RingElem<C>> C multiply(RingFactory<C> fac, List<C> A) { 392 return multiply((MonoidFactory<C>) fac, A); 393 } 394 395 396 /** 397 * Multiply elements in list. 398 * @param A list of elements (a_0,...,a_k). 399 * @param fac monoid factory. 400 * @return prod(i=0,...k) a_i. 401 */ 402 public static <C extends MonoidElem<C>> C multiply(MonoidFactory<C> fac, List<C> A) { 403 if (fac == null) { 404 throw new IllegalArgumentException("fac may not be null for empty list"); 405 } 406 C res = fac.getONE(); 407 if (A == null || A.isEmpty()) { 408 return res; 409 } 410 for (C a : A) { 411 res = res.multiply(a); 412 } 413 return res; 414 } 415 416 417 /** 418 * Sum elements in list. 419 * @param A list of elements (a_0,...,a_k). 420 * @param fac ring factory. 421 * @return sum(i=0,...k) a_i. 422 */ 423 public static <C extends RingElem<C>> C sum(RingFactory<C> fac, List<C> A) { 424 return sum((AbelianGroupFactory<C>) fac, A); 425 } 426 427 428 /** 429 * Sum elements in list. 430 * @param A list of elements (a_0,...,a_k). 431 * @param fac monoid factory. 432 * @return sum(i=0,...k) a_i. 433 */ 434 public static <C extends AbelianGroupElem<C>> C sum(AbelianGroupFactory<C> fac, List<C> A) { 435 if (fac == null) { 436 throw new IllegalArgumentException("fac may not be null for empty list"); 437 } 438 C res = fac.getZERO(); 439 if (A == null || A.isEmpty()) { 440 return res; 441 } 442 for (C a : A) { 443 res = res.sum(a); 444 } 445 return res; 446 } 447 448}