001/* 002 * $Id: AlgebraicNumberRing.java 5997 2020-03-17 15:34:31Z kredel $ 003 */ 004 005package edu.jas.poly; 006 007 008import java.io.Reader; 009import java.util.ArrayList; 010import java.util.Iterator; 011import java.util.List; 012import java.util.Random; 013 014import org.apache.logging.log4j.LogManager; 015import org.apache.logging.log4j.Logger; 016 017import edu.jas.kern.Scripting; 018import edu.jas.structure.RingElem; 019import edu.jas.structure.RingFactory; 020import edu.jas.util.CartesianProduct; 021import edu.jas.util.CartesianProductInfinite; 022 023 024/** 025 * Algebraic number factory. Based on GenPolynomial factory with RingElem 026 * interface. Objects of this class are immutable. 027 * @author Heinz Kredel 028 */ 029 030public class AlgebraicNumberRing<C extends RingElem<C>> 031 implements RingFactory<AlgebraicNumber<C>>, Iterable<AlgebraicNumber<C>> { 032 033 034 /** 035 * Ring part of the factory data structure. 036 */ 037 public final GenPolynomialRing<C> ring; 038 039 040 /** 041 * Module part of the factory data structure. 042 */ 043 public final GenPolynomial<C> modul; 044 045 046 /** 047 * Indicator if this ring is a field 048 */ 049 protected int isField = -1; // initially unknown 050 051 052 private static final Logger logger = LogManager.getLogger(AlgebraicNumberRing.class); 053 054 055 // private static final boolean debug = logger.isDebugEnabled(); 056 057 058 /** 059 * The constructor creates a AlgebraicNumber factory object from a 060 * GenPolynomial objects module. 061 * @param m module GenPolynomial<C>. 062 */ 063 public AlgebraicNumberRing(GenPolynomial<C> m) { 064 ring = m.ring; 065 modul = m; // assert m != 0 066 if (ring.nvar > 1) { 067 throw new IllegalArgumentException("only univariate polynomials allowed"); 068 } 069 } 070 071 072 /** 073 * The constructor creates a AlgebraicNumber factory object from a 074 * GenPolynomial objects module. 075 * @param m module GenPolynomial<C>. 076 * @param isField indicator if m is prime. 077 */ 078 public AlgebraicNumberRing(GenPolynomial<C> m, boolean isField) { 079 ring = m.ring; 080 modul = m; // assert m != 0 081 this.isField = (isField ? 1 : 0); 082 if (ring.nvar > 1) { 083 throw new IllegalArgumentException("only univariate polynomials allowed"); 084 } 085 } 086 087 088 /** 089 * Get the module part. 090 * @return modul. 091 */ 092 public GenPolynomial<C> getModul() { 093 return modul; 094 } 095 096 097 /** 098 * Copy AlgebraicNumber element c. 099 * @param c algebraic number to copy. 100 * @return a copy of c. 101 */ 102 public AlgebraicNumber<C> copy(AlgebraicNumber<C> c) { 103 return new AlgebraicNumber<C>(this, c.val); 104 } 105 106 107 /** 108 * Get the zero element. 109 * @return 0 as AlgebraicNumber. 110 */ 111 public AlgebraicNumber<C> getZERO() { 112 return new AlgebraicNumber<C>(this, ring.getZERO()); 113 } 114 115 116 /** 117 * Get the one element. 118 * @return 1 as AlgebraicNumber. 119 */ 120 public AlgebraicNumber<C> getONE() { 121 return new AlgebraicNumber<C>(this, ring.getONE()); 122 } 123 124 125 /** 126 * Get the generating element. 127 * @return alpha as AlgebraicNumber. 128 */ 129 public AlgebraicNumber<C> getGenerator() { 130 return new AlgebraicNumber<C>(this, ring.univariate(0)); 131 } 132 133 134 /** 135 * Get a list of the generating elements. 136 * @return list of generators for the algebraic structure. 137 * @see edu.jas.structure.ElemFactory#generators() 138 */ 139 public List<AlgebraicNumber<C>> generators() { 140 List<GenPolynomial<C>> gc = ring.generators(); 141 List<AlgebraicNumber<C>> gens = new ArrayList<AlgebraicNumber<C>>(gc.size()); 142 for (GenPolynomial<C> g : gc) { 143 gens.add(new AlgebraicNumber<C>(this, g)); 144 } 145 return gens; 146 } 147 148 149 /** 150 * Is this structure finite or infinite. 151 * @return true if this structure is finite, else false. 152 * @see edu.jas.structure.ElemFactory#isFinite() 153 */ 154 public boolean isFinite() { 155 return ring.coFac.isFinite(); 156 } 157 158 159 /** 160 * Query if this ring is commutative. 161 * @return true if this ring is commutative, else false. 162 */ 163 public boolean isCommutative() { 164 return ring.isCommutative(); 165 } 166 167 168 /** 169 * Query if this ring is associative. 170 * @return true if this ring is associative, else false. 171 */ 172 public boolean isAssociative() { 173 return ring.isAssociative(); 174 } 175 176 177 /** 178 * Query if this ring is a field. 179 * @return true if modul is prime, else false. 180 */ 181 public boolean isField() { 182 if (isField > 0) { 183 return true; 184 } 185 if (isField == 0) { 186 return false; 187 } 188 if (!ring.coFac.isField()) { 189 isField = 0; 190 return false; 191 } 192 return false; 193 } 194 195 196 /** 197 * Set field property of this ring. 198 * @param field true, if this ring is determined to be a field, false, if it 199 * is determined that it is not a field. 200 */ 201 public void setField(boolean field) { 202 if (isField > 0 && field) { 203 return; 204 } 205 if (isField == 0 && !field) { 206 return; 207 } 208 if (field) { 209 isField = 1; 210 } else { 211 isField = 0; 212 } 213 return; 214 } 215 216 217 /** 218 * Get the internal field indicator. 219 * @return internal field indicator. 220 */ 221 public int getField() { 222 return isField; 223 } 224 225 226 /** 227 * Characteristic of this ring. 228 * @return characteristic of this ring. 229 */ 230 public java.math.BigInteger characteristic() { 231 return ring.characteristic(); 232 } 233 234 235 /** 236 * Get a AlgebraicNumber element from a BigInteger value. 237 * @param a BigInteger. 238 * @return a AlgebraicNumber. 239 */ 240 public AlgebraicNumber<C> fillFromInteger(java.math.BigInteger a) { 241 if (characteristic().signum() == 0) { 242 return new AlgebraicNumber<C>(this, ring.fromInteger(a)); 243 } 244 java.math.BigInteger p = characteristic(); 245 java.math.BigInteger b = a; 246 GenPolynomial<C> v = ring.getZERO(); 247 GenPolynomial<C> x = ring.univariate(0, 1L); 248 GenPolynomial<C> t = ring.getONE(); 249 do { 250 java.math.BigInteger[] qr = b.divideAndRemainder(p); 251 java.math.BigInteger q = qr[0]; 252 java.math.BigInteger r = qr[1]; 253 //System.out.println("q = " + q + ", r = " +r); 254 GenPolynomial<C> rp = ring.fromInteger(r); 255 v = v.sum(t.multiply(rp)); 256 t = t.multiply(x); 257 b = q; 258 } while (!b.equals(java.math.BigInteger.ZERO)); 259 AlgebraicNumber<C> an = new AlgebraicNumber<C>(this, v); 260 logger.info("fill(" + a + ") = " + v + ", mod: " + an); 261 //RuntimeException e = new RuntimeException("hihihi"); 262 //e.printStackTrace(); 263 return an; 264 } 265 266 267 /** 268 * Get a AlgebraicNumber element from a long value. 269 * @param a long. 270 * @return a AlgebraicNumber. 271 */ 272 public AlgebraicNumber<C> fillFromInteger(long a) { 273 return fillFromInteger(new java.math.BigInteger("" + a)); 274 } 275 276 277 /** 278 * Get a AlgebraicNumber element from a BigInteger value. 279 * @param a BigInteger. 280 * @return a AlgebraicNumber. 281 */ 282 public AlgebraicNumber<C> fromInteger(java.math.BigInteger a) { 283 return new AlgebraicNumber<C>(this, ring.fromInteger(a)); 284 } 285 286 287 /** 288 * Get a AlgebraicNumber element from a long value. 289 * @param a long. 290 * @return a AlgebraicNumber. 291 */ 292 public AlgebraicNumber<C> fromInteger(long a) { 293 return new AlgebraicNumber<C>(this, ring.fromInteger(a)); 294 // if ( characteristic().signum() == 0 ) { 295 // } 296 // return fromInteger( new java.math.BigInteger(""+a) ); 297 } 298 299 300 /** 301 * Get the String representation as RingFactory. 302 * @see java.lang.Object#toString() 303 */ 304 @Override 305 public String toString() { 306 return "AlgebraicNumberRing[ " + modul.toString() + " | isField=" + isField + " :: " + ring.toString() 307 + " ]"; 308 } 309 310 311 /** 312 * Get a scripting compatible string representation. 313 * @return script compatible representation for this ElemFactory. 314 * @see edu.jas.structure.ElemFactory#toScript() 315 */ 316 @Override 317 public String toScript() { 318 StringBuffer s = new StringBuffer(); 319 s.append("AN("); 320 s.append(modul.toScript()); 321 switch (Scripting.getLang()) { 322 case Ruby: 323 s.append((isField() ? ",true" : ",false")); 324 break; 325 case Python: 326 default: 327 s.append((isField() ? ",True" : ",False")); 328 } 329 s.append(","); 330 s.append(ring.toScript()); 331 s.append(")"); 332 return s.toString(); 333 } 334 335 336 /** 337 * Comparison with any other object. 338 * @see java.lang.Object#equals(java.lang.Object) 339 */ 340 @Override 341 @SuppressWarnings("unchecked") 342 // not jet working 343 public boolean equals(Object b) { 344 if (b == null) { 345 return false; 346 } 347 if (!(b instanceof AlgebraicNumberRing)) { 348 return false; 349 } 350 AlgebraicNumberRing<C> a = (AlgebraicNumberRing<C>) b; 351 return modul.equals(a.modul); 352 } 353 354 355 /** 356 * Hash code for this AlgebraicNumber. 357 * @see java.lang.Object#hashCode() 358 */ 359 @Override 360 public int hashCode() { 361 return 37 * modul.hashCode() + ring.hashCode(); 362 } 363 364 365 /** 366 * AlgebraicNumber random. 367 * @param n such that 0 ≤ v ≤ (2<sup>n</sup>-1). 368 * @return a random integer mod modul. 369 */ 370 public AlgebraicNumber<C> random(int n) { 371 GenPolynomial<C> x = ring.random(n).monic(); 372 return new AlgebraicNumber<C>(this, x); 373 } 374 375 376 /** 377 * AlgebraicNumber random. 378 * @param n such that 0 ≤ v ≤ (2<sup>n</sup>-1). 379 * @param rnd is a source for random bits. 380 * @return a random integer mod modul. 381 */ 382 public AlgebraicNumber<C> random(int n, Random rnd) { 383 GenPolynomial<C> x = ring.random(n, rnd).monic(); 384 return new AlgebraicNumber<C>(this, x); 385 } 386 387 388 /** 389 * Parse AlgebraicNumber from String. 390 * @param s String. 391 * @return AlgebraicNumber from s. 392 */ 393 public AlgebraicNumber<C> parse(String s) { 394 GenPolynomial<C> x = ring.parse(s); 395 return new AlgebraicNumber<C>(this, x); 396 } 397 398 399 /** 400 * Parse AlgebraicNumber from Reader. 401 * @param r Reader. 402 * @return next AlgebraicNumber from r. 403 */ 404 public AlgebraicNumber<C> parse(Reader r) { 405 GenPolynomial<C> x = ring.parse(r); 406 return new AlgebraicNumber<C>(this, x); 407 } 408 409 410 /** 411 * AlgebraicNumber chinese remainder algorithm. Assert deg(c.modul) >= 412 * deg(a.modul) and c.modul * a.modul = this.modul. 413 * @param c AlgebraicNumber. 414 * @param ci inverse of c.modul in ring of a. 415 * @param a other AlgebraicNumber. 416 * @return S, with S mod c.modul == c and S mod a.modul == a. 417 */ 418 public AlgebraicNumber<C> chineseRemainder(AlgebraicNumber<C> c, AlgebraicNumber<C> ci, 419 AlgebraicNumber<C> a) { 420 if (true) { // debug 421 if (c.ring.modul.compareTo(a.ring.modul) < 1) { 422 System.out.println("AlgebraicNumber error " + c + ", " + a); 423 } 424 } 425 AlgebraicNumber<C> b = new AlgebraicNumber<C>(a.ring, c.val); 426 // c mod a.modul 427 // c( tbcf(a.modul) ) if deg(a.modul)==1 428 AlgebraicNumber<C> d = a.subtract(b); // a-c mod a.modul 429 if (d.isZERO()) { 430 return new AlgebraicNumber<C>(this, c.val); 431 } 432 b = d.multiply(ci); // b = (a-c)*ci mod a.modul 433 // (c.modul*b)+c mod this.modul = c mod c.modul = 434 // (c.modul*ci*(a-c)+c) mod a.modul = a mod a.modul 435 GenPolynomial<C> s = c.ring.modul.multiply(b.val); 436 s = s.sum(c.val); 437 return new AlgebraicNumber<C>(this, s); 438 } 439 440 441 /** 442 * AlgebraicNumber interpolation algorithm. Assert deg(c.modul) >= 443 * deg(A.modul) and c.modul * A.modul = this.modul. Special case with 444 * deg(A.modul) == 1. Similar algorithm as chinese remainder algortihm. 445 * @param c AlgebraicNumber. 446 * @param ci inverse of (c.modul)(a) in ring of A. 447 * @param am trailing base coefficient of modul of other AlgebraicNumber A. 448 * @param a value of other AlgebraicNumber A. 449 * @return S, with S(c) == c and S(A) == a. 450 */ 451 public AlgebraicNumber<C> interpolate(AlgebraicNumber<C> c, C ci, C am, C a) { 452 C b = PolyUtil.<C> evaluateMain(ring.coFac /*a*/, c.val, am); 453 // c mod a.modul 454 // c( tbcf(a.modul) ) if deg(a.modul)==1 455 C d = a.subtract(b); // a-c mod a.modul 456 if (d.isZERO()) { 457 return new AlgebraicNumber<C>(this, c.val); 458 } 459 b = d.multiply(ci); // b = (a-c)*ci mod a.modul 460 // (c.modul*b)+c mod this.modul = c mod c.modul = 461 // (c.modul*ci*(a-c)+c) mod a.modul = a mod a.modul 462 GenPolynomial<C> s = c.ring.modul.multiply(b); 463 s = s.sum(c.val); 464 return new AlgebraicNumber<C>(this, s); 465 } 466 467 468 /** 469 * Depth of extension field tower. 470 * @return number of nested algebraic extension fields 471 */ 472 @SuppressWarnings({ "unchecked", "cast" }) 473 public int depth() { 474 AlgebraicNumberRing<C> arr = this; 475 int depth = 1; 476 RingFactory<C> cf = arr.ring.coFac; 477 if (cf instanceof AlgebraicNumberRing) { 478 arr = (AlgebraicNumberRing<C>) (Object) cf; 479 depth += arr.depth(); 480 } 481 return depth; 482 } 483 484 485 /** 486 * Degree of extension field. 487 * @return degree of this algebraic extension field 488 */ 489 public long extensionDegree() { 490 long degree = modul.degree(0); 491 return degree; 492 } 493 494 495 /** 496 * Total degree of nested extension fields. 497 * @return degree of tower of algebraic extension fields 498 */ 499 @SuppressWarnings({ "unchecked", "cast" }) 500 public long totalExtensionDegree() { 501 long degree = modul.degree(0); 502 AlgebraicNumberRing<C> arr = this; 503 RingFactory<C> cf = arr.ring.coFac; 504 if (cf instanceof AlgebraicNumberRing) { 505 arr = (AlgebraicNumberRing<C>) (Object) cf; 506 if (degree == 0L) { 507 degree = arr.totalExtensionDegree(); 508 } else { 509 degree *= arr.totalExtensionDegree(); 510 } 511 } 512 return degree; 513 } 514 515 516 /** 517 * Get a AlgebraicNumber iterator. <b>Note: </b> Only for finite field 518 * coefficients or fields which are iterable. 519 * @return a iterator over all algebraic numbers in this ring. 520 */ 521 public Iterator<AlgebraicNumber<C>> iterator() { 522 return new AlgebraicNumberIterator<C>(this); 523 } 524 525} 526 527 528/** 529 * Algebraic number iterator. 530 * @author Heinz Kredel 531 */ 532class AlgebraicNumberIterator<C extends RingElem<C>> implements Iterator<AlgebraicNumber<C>> { 533 534 535 /** 536 * data structure. 537 */ 538 final Iterator<List<C>> iter; 539 540 541 final List<GenPolynomial<C>> powers; 542 543 544 final AlgebraicNumberRing<C> aring; 545 546 547 private static final Logger logger = LogManager.getLogger(AlgebraicNumberIterator.class); 548 549 550 // private static final boolean debug = logger.isDebugEnabled(); 551 552 553 /** 554 * CartesianProduct iterator constructor. 555 * @param aring AlgebraicNumberRing components of the Cartesian product. 556 */ 557 @SuppressWarnings("unchecked") 558 public AlgebraicNumberIterator(AlgebraicNumberRing<C> aring) { 559 RingFactory<C> cf = aring.ring.coFac; 560 this.aring = aring; 561 long d = aring.modul.degree(0); 562 //System.out.println("d = " + d); 563 powers = new ArrayList<GenPolynomial<C>>((int) d); 564 for (long j = d - 1; j >= 0L; j--) { 565 powers.add(aring.ring.univariate(0, j)); 566 } 567 //System.out.println("powers = " + powers); 568 if (!(cf instanceof Iterable)) { 569 throw new IllegalArgumentException("only for iterable coefficients implemented"); 570 } 571 List<Iterable<C>> comps = new ArrayList<Iterable<C>>((int) d); 572 Iterable<C> cfi = (Iterable<C>) cf; 573 for (long j = 0L; j < d; j++) { 574 comps.add(cfi); 575 } 576 if (cf.isFinite()) { 577 CartesianProduct<C> tuples = new CartesianProduct<C>(comps); 578 iter = tuples.iterator(); 579 } else { 580 CartesianProductInfinite<C> tuples = new CartesianProductInfinite<C>(comps); 581 iter = tuples.iterator(); 582 } 583 if (logger.isInfoEnabled()) { 584 logger.info("iterator for degree " + d + ", finite = " + cf.isFinite()); 585 } 586 } 587 588 589 /** 590 * Test for availability of a next tuple. 591 * @return true if the iteration has more tuples, else false. 592 */ 593 public boolean hasNext() { 594 return iter.hasNext(); 595 } 596 597 598 /** 599 * Get next tuple. 600 * @return next tuple. 601 */ 602 public AlgebraicNumber<C> next() { 603 List<C> coeffs = iter.next(); 604 //System.out.println("coeffs = " + coeffs); 605 GenPolynomial<C> pol = aring.ring.getZERO(); 606 int i = 0; 607 for (GenPolynomial<C> f : powers) { 608 C c = coeffs.get(i++); 609 if (c.isZERO()) { 610 continue; 611 } 612 pol = pol.sum(f.multiply(c)); 613 } 614 return new AlgebraicNumber<C>(aring, pol); 615 } 616 617 618 /** 619 * Remove a tuple if allowed. 620 */ 621 public void remove() { 622 throw new UnsupportedOperationException("cannnot remove tuples"); 623 } 624 625}