/edu/jas/structure/Product.java

https://github.com/ancsing/geogebra · Java · 755 lines · 502 code · 86 blank · 167 comment · 141 complexity · 451be489d7f59df827048f2fab213f3e MD5 · raw file

  1. /*
  2. * $Id: Product.java 3211 2010-07-05 12:54:22Z kredel $
  3. */
  4. package edu.jas.structure;
  5. import java.util.Map;
  6. import java.util.Iterator;
  7. import java.util.SortedMap;
  8. import java.util.TreeMap;
  9. import org.apache.log4j.Logger;
  10. import edu.jas.structure.RingElem;
  11. import edu.jas.structure.RingFactory;
  12. import edu.jas.structure.NotInvertibleException;
  13. /**
  14. * Direct product element based on RingElem.
  15. * Objects of this class are (nearly) immutable.
  16. * @author Heinz Kredel
  17. */
  18. public class Product<C extends RingElem<C> >
  19. implements RegularRingElem< Product<C> > {
  20. private static final Logger logger = Logger.getLogger(Product.class);
  21. private boolean debug = logger.isDebugEnabled();
  22. /** Product class factory data structure.
  23. */
  24. public final ProductRing<C> ring;
  25. /** Value part of the element data structure.
  26. */
  27. public final SortedMap<Integer,C> val;
  28. /** Flag to remember if this product element is a unit in each cmponent.
  29. * -1 is unknown, 1 is unit, 0 not a unit.
  30. */
  31. protected int isunit = -1; // initially unknown
  32. /** The constructor creates a Product object
  33. * from a ring factory.
  34. * @param r ring factory.
  35. */
  36. public Product(ProductRing<C> r) {
  37. this( r, new TreeMap<Integer,C>(), 0 );
  38. }
  39. /** The constructor creates a Product object
  40. * from a ring factory and a ring element.
  41. * @param r ring factory.
  42. * @param a ring element.
  43. */
  44. public Product(ProductRing<C> r, SortedMap<Integer,C> a) {
  45. this( r, a, -1 );
  46. }
  47. /** The constructor creates a Product object
  48. * from a ring factory, a ring element and an indicator if a is a unit.
  49. * @param r ring factory.
  50. * @param a ring element.
  51. * @param u isunit indicator, -1, 0, 1.
  52. */
  53. public Product(ProductRing<C> r, SortedMap<Integer,C> a, int u) {
  54. ring = r;
  55. val = a;
  56. isunit = u;
  57. }
  58. /** Get component.
  59. * @param i index of component.
  60. * @return val(i).
  61. */
  62. public C get(int i) {
  63. return val.get(i); // auto-boxing
  64. }
  65. /**
  66. * Get the corresponding element factory.
  67. * @return factory for this Element.
  68. * @see edu.jas.structure.Element#factory()
  69. */
  70. public ProductRing<C> factory() {
  71. return ring;
  72. }
  73. /** Clone this.
  74. * @see java.lang.Object#clone()
  75. */
  76. @Override
  77. public Product<C> clone() {
  78. return new Product<C>( ring, val, isunit );
  79. }
  80. /** Is Product zero.
  81. * @return If this is 0 then true is returned, else false.
  82. * @see edu.jas.structure.RingElem#isZERO()
  83. */
  84. public boolean isZERO() {
  85. return val.size() == 0;
  86. }
  87. /** Is Product one.
  88. * @return If this is 1 then true is returned, else false.
  89. * @see edu.jas.structure.RingElem#isONE()
  90. */
  91. public boolean isONE() {
  92. if ( val.size() != ring.length() ) {
  93. return false;
  94. }
  95. for ( C e : val.values() ) {
  96. if ( ! e.isONE() ) {
  97. return false;
  98. }
  99. }
  100. return true;
  101. }
  102. /** Is Product full.
  103. * @return If every component is non-zero,
  104. * then true is returned, else false.
  105. */
  106. public boolean isFull() {
  107. if ( val.size() != ring.length() ) {
  108. return false;
  109. }
  110. return true;
  111. }
  112. /** Is Product unit.
  113. * @return If this is a unit then true is returned, else false.
  114. * @see edu.jas.structure.RingElem#isUnit()
  115. */
  116. public boolean isUnit() {
  117. if ( isunit > 0 ) {
  118. return true;
  119. }
  120. if ( isunit == 0 ) {
  121. return false;
  122. }
  123. if ( isZERO() ) {
  124. isunit = 0;
  125. return false;
  126. }
  127. for ( C e : val.values() ) {
  128. if ( ! e.isUnit() ) {
  129. isunit = 0;
  130. return false;
  131. }
  132. }
  133. isunit = 1;
  134. return true;
  135. }
  136. /** Is Product idempotent.
  137. * @return If this is a idempotent element then true is returned, else false.
  138. */
  139. public boolean isIdempotent() {
  140. for ( C e : val.values() ) {
  141. if ( ! e.isONE() ) {
  142. return false;
  143. }
  144. }
  145. return true;
  146. }
  147. /** Get the String representation as RingElem.
  148. * @see java.lang.Object#toString()
  149. */
  150. @Override
  151. public String toString() {
  152. return val.toString();
  153. }
  154. /** Get a scripting compatible string representation.
  155. * @return script compatible representation for this Element.
  156. * @see edu.jas.structure.Element#toScript()
  157. */
  158. //JAVA6only: @Override
  159. public String toScript() {
  160. // Python case
  161. StringBuffer s = new StringBuffer("( ");
  162. boolean first = true;
  163. for ( Integer i : val.keySet() ) {
  164. C v = val.get(i);
  165. if ( first ) {
  166. first = false;
  167. } else {
  168. if ( v.signum() < 0 ) {
  169. s.append(" - ");
  170. v = v.negate();
  171. } else {
  172. s.append(" + ");
  173. }
  174. }
  175. if ( !v.isONE() ) {
  176. s.append( v.toScript() + "*" );
  177. }
  178. s.append( "pg"+i );
  179. }
  180. s.append(" )");
  181. return s.toString();
  182. }
  183. /** Get a scripting compatible string representation of the factory.
  184. * @return script compatible representation for this ElemFactory.
  185. * @see edu.jas.structure.Element#toScriptFactory()
  186. */
  187. //JAVA6only: @Override
  188. public String toScriptFactory() {
  189. // Python case
  190. return factory().toScript();
  191. }
  192. /** Product comparison.
  193. * @param b Product.
  194. * @return sign(this-b).
  195. */
  196. //JAVA6only: @Override
  197. public int compareTo(Product<C> b) {
  198. if ( ! ring.equals( b.ring ) ) {
  199. throw new RuntimeException("rings not comparable " + this);
  200. }
  201. SortedMap<Integer,C> v = b.val;
  202. Iterator<Map.Entry<Integer,C>> ti = val.entrySet().iterator();
  203. Iterator<Map.Entry<Integer,C>> bi = v.entrySet().iterator();
  204. int s;
  205. while ( ti.hasNext() && bi.hasNext() ) {
  206. Map.Entry<Integer,C> te = ti.next();
  207. Map.Entry<Integer,C> be = bi.next();
  208. s = te.getKey().compareTo( be.getKey() );
  209. if ( s != 0 ) {
  210. return s;
  211. }
  212. s = te.getValue().compareTo( be.getValue() );
  213. if ( s != 0 ) {
  214. return s;
  215. }
  216. }
  217. if ( ti.hasNext() ) {
  218. return -1;
  219. }
  220. if ( bi.hasNext() ) {
  221. return 1;
  222. }
  223. return 0;
  224. }
  225. /** Comparison with any other object.
  226. * @see java.lang.Object#equals(java.lang.Object)
  227. */
  228. @SuppressWarnings("unchecked")
  229. @Override
  230. public boolean equals(Object b) {
  231. if ( ! ( b instanceof Product ) ) {
  232. return false;
  233. }
  234. Product<C> a = null;
  235. try {
  236. a = (Product<C>) b;
  237. } catch (ClassCastException e) {
  238. }
  239. if ( a == null ) {
  240. return false;
  241. }
  242. return ( 0 == compareTo( a ) );
  243. }
  244. /** Hash code for this local.
  245. * @see java.lang.Object#hashCode()
  246. */
  247. @Override
  248. public int hashCode() {
  249. int h = ring.hashCode();
  250. h = 37 * h + val.hashCode();
  251. return h;
  252. }
  253. /** Product extend.
  254. * Add new component j with value of component i.
  255. * @param i from index.
  256. * @param j to index.
  257. * @return the extended value of this.
  258. */
  259. public Product<C> extend( int i, int j ) {
  260. RingFactory<C> rf = ring.getFactory( j );
  261. SortedMap<Integer,C> elem = new TreeMap<Integer,C>( val );
  262. C v = val.get( i );
  263. C w = rf.copy( v ); // valueOf
  264. if ( ! w.isZERO() ) {
  265. elem.put( j , w );
  266. }
  267. return new Product<C>( ring, elem, isunit );
  268. }
  269. /** Product absolute value.
  270. * @return the absolute value of this.
  271. * @see edu.jas.structure.RingElem#abs()
  272. */
  273. public Product<C> abs() {
  274. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  275. for ( Integer i : val.keySet() ) {
  276. C v = val.get(i).abs();
  277. elem.put( i, v );
  278. }
  279. return new Product<C>( ring, elem, isunit );
  280. }
  281. /** Product summation.
  282. * @param S Product.
  283. * @return this+S.
  284. */
  285. public Product<C> sum(Product<C> S) {
  286. if ( S == null || S.isZERO() ) {
  287. return this;
  288. }
  289. if ( this.isZERO() ) {
  290. return S;
  291. }
  292. SortedMap<Integer,C> elem = new TreeMap<Integer,C>( val ); // clone
  293. SortedMap<Integer,C> sel = S.val;
  294. for ( Integer i : sel.keySet() ) {
  295. C x = elem.get( i );
  296. C y = sel.get( i ); // assert y != null
  297. if ( x != null ) {
  298. x = x.sum(y);
  299. if ( ! x.isZERO() ) {
  300. elem.put( i, x );
  301. } else {
  302. elem.remove( i );
  303. }
  304. } else {
  305. elem.put( i, y );
  306. }
  307. }
  308. return new Product<C>( ring, elem );
  309. }
  310. /** Product negate.
  311. * @return -this.
  312. * @see edu.jas.structure.RingElem#negate()
  313. */
  314. public Product<C> negate() {
  315. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  316. for ( Integer i : val.keySet() ) {
  317. C v = val.get(i).negate();
  318. elem.put( i, v );
  319. }
  320. return new Product<C>( ring, elem, isunit );
  321. }
  322. /** Product signum.
  323. * @see edu.jas.structure.RingElem#signum()
  324. * @return signum of first non-zero component.
  325. */
  326. public int signum() {
  327. if ( val.size() == 0 ) {
  328. return 0;
  329. }
  330. C v = val.get( val.firstKey() );
  331. return v.signum();
  332. }
  333. /** Product subtraction.
  334. * @param S Product.
  335. * @return this-S.
  336. */
  337. public Product<C> subtract(Product<C> S) {
  338. return sum( S.negate() );
  339. }
  340. /** Product quasi-inverse.
  341. * @see edu.jas.structure.RingElem#inverse()
  342. * @return S with S = 1/this if defined.
  343. */
  344. public Product<C> inverse() {
  345. if ( this.isZERO() ) {
  346. return this;
  347. }
  348. int isu = 0;
  349. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  350. for ( Integer i : val.keySet() ) {
  351. C x = val.get( i ); // is non zero
  352. try {
  353. x = x.inverse();
  354. } catch(NotInvertibleException e) {
  355. // could happen for e.g. ModInteger or AlgebraicNumber
  356. x = null; //ring.getFactory(i).getZERO();
  357. }
  358. if ( x != null && ! x.isZERO() ) { // can happen
  359. elem.put( i, x );
  360. isu = 1;
  361. }
  362. }
  363. return new Product<C>( ring, elem, isu );
  364. }
  365. /** Product idempotent.
  366. * @return smallest S with this*S = this.
  367. */
  368. public Product<C> idempotent() {
  369. if ( this.isZERO() ) {
  370. return this;
  371. }
  372. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  373. for ( Integer i : val.keySet() ) {
  374. RingFactory<C> f = ring.getFactory( i );
  375. C x = f.getONE();
  376. elem.put( i, x );
  377. }
  378. return new Product<C>( ring, elem, 1 );
  379. }
  380. /** Product idempotent complement.
  381. * @return 1-this.idempotent().
  382. */
  383. public Product<C> idemComplement() {
  384. if ( this.isZERO() ) {
  385. return ring.getONE();
  386. }
  387. int isu = 0;
  388. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  389. for ( int i = 0; i < ring.length(); i++ ) {
  390. C v = val.get( i );
  391. if ( v == null ) {
  392. RingFactory<C> f = ring.getFactory( i );
  393. C x = f.getONE();
  394. elem.put( i, x );
  395. isu = 1;
  396. }
  397. }
  398. return new Product<C>( ring, elem, isu );
  399. }
  400. /** Product idempotent and.
  401. * @param S Product.
  402. * @return this.idempotent() and S.idempotent().
  403. */
  404. public Product<C> idempotentAnd(Product<C> S) {
  405. if ( this.isZERO() && S.isZERO() ) {
  406. return this;
  407. }
  408. int isu = 0;
  409. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  410. for ( int i = 0; i < ring.length(); i++ ) {
  411. C v = val.get( i );
  412. C w = S.val.get( i );
  413. if ( v != null && w != null ) {
  414. RingFactory<C> f = ring.getFactory( i );
  415. C x = f.getONE();
  416. elem.put( i, x );
  417. isu = 1;
  418. }
  419. }
  420. return new Product<C>( ring, elem, isu );
  421. }
  422. /** Product idempotent or.
  423. * @param S Product.
  424. * @return this.idempotent() or S.idempotent().
  425. */
  426. public Product<C> idempotentOr(Product<C> S) {
  427. if ( this.isZERO() && S.isZERO() ) {
  428. return this;
  429. }
  430. int isu = 0;
  431. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  432. for ( int i = 0; i < ring.length(); i++ ) {
  433. C v = val.get( i );
  434. C w = S.val.get( i );
  435. if ( v != null || w != null ) {
  436. RingFactory<C> f = ring.getFactory( i );
  437. C x = f.getONE();
  438. elem.put( i, x );
  439. isu = 1;
  440. }
  441. }
  442. return new Product<C>( ring, elem, isu );
  443. }
  444. /** Product fill with idempotent.
  445. * @param S Product.
  446. * @return fill this with S.idempotent().
  447. */
  448. public Product<C> fillIdempotent(Product<C> S) {
  449. if ( S.isZERO() ) {
  450. return this;
  451. }
  452. SortedMap<Integer,C> elem = new TreeMap<Integer,C>( val );
  453. for ( int i = 0; i < ring.length(); i++ ) {
  454. C v = elem.get( i );
  455. if ( v != null ) {
  456. continue;
  457. }
  458. C w = S.val.get( i );
  459. if ( w != null ) {
  460. RingFactory<C> f = ring.getFactory( i );
  461. C x = f.getONE();
  462. elem.put( i, x );
  463. }
  464. }
  465. return new Product<C>( ring, elem, isunit );
  466. }
  467. /** Product fill with one.
  468. * @return fill this with one.
  469. */
  470. public Product<C> fillOne() {
  471. if ( this.isFull() ) {
  472. return this;
  473. }
  474. if ( this.isZERO() ) {
  475. return ring.getONE();
  476. }
  477. SortedMap<Integer,C> elem = new TreeMap<Integer,C>( val );
  478. for ( int i = 0; i < ring.length(); i++ ) {
  479. C v = elem.get( i );
  480. if ( v != null ) {
  481. continue;
  482. }
  483. RingFactory<C> f = ring.getFactory( i );
  484. C x = f.getONE();
  485. elem.put( i, x );
  486. }
  487. return new Product<C>( ring, elem, isunit );
  488. }
  489. /** Product quasi-division.
  490. * @param S Product.
  491. * @return this/S.
  492. */
  493. public Product<C> divide(Product<C> S) {
  494. if ( S == null ) {
  495. return ring.getZERO();
  496. }
  497. if ( S.isZERO() ) {
  498. return S;
  499. }
  500. if ( this.isZERO() ) {
  501. return this;
  502. }
  503. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  504. SortedMap<Integer,C> sel = S.val;
  505. for ( Integer i : val.keySet() ) {
  506. C y = sel.get( i );
  507. if ( y != null ) {
  508. C x = val.get( i );
  509. try {
  510. x = x.divide(y);
  511. } catch(NotInvertibleException e) {
  512. // should not happen any more
  513. System.out.println("product divide error: x = " + x + ", y = " + y);
  514. // could happen for e.g. ModInteger or AlgebraicNumber
  515. x = null; //ring.getFactory(i).getZERO();
  516. }
  517. if ( x != null && ! x.isZERO() ) { // can happen
  518. elem.put( i, x );
  519. }
  520. }
  521. }
  522. return new Product<C>( ring, elem );
  523. }
  524. /** Product quasi-remainder.
  525. * @param S Product.
  526. * @return this - (this/S)*S.
  527. */
  528. public Product<C> remainder(Product<C> S) {
  529. if ( S == null ) {
  530. return this; //ring.getZERO();
  531. }
  532. if ( S.isZERO() ) {
  533. return this;
  534. }
  535. if ( this.isZERO() ) {
  536. return this;
  537. }
  538. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  539. SortedMap<Integer,C> sel = S.val;
  540. for ( Integer i : val.keySet() ) {
  541. C y = sel.get( i );
  542. if ( y != null ) {
  543. C x = val.get( i );
  544. x = x.remainder(y);
  545. if ( x != null && ! x.isZERO() ) { // can happen
  546. elem.put( i, x );
  547. }
  548. }
  549. }
  550. return new Product<C>( ring, elem );
  551. }
  552. /** Product multiplication.
  553. * @param S Product.
  554. * @return this*S.
  555. */
  556. public Product<C> multiply(Product<C> S) {
  557. if ( S == null ) {
  558. return ring.getZERO();
  559. }
  560. if ( S.isZERO() ) {
  561. return S;
  562. }
  563. if ( this.isZERO() ) {
  564. return this;
  565. }
  566. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  567. SortedMap<Integer,C> sel = S.val;
  568. for ( Integer i : val.keySet() ) {
  569. C y = sel.get( i );
  570. if ( y != null ) {
  571. C x = val.get( i );
  572. x = x.multiply(y);
  573. if ( x != null && ! x.isZERO() ) {
  574. elem.put( i, x );
  575. }
  576. }
  577. }
  578. return new Product<C>( ring, elem );
  579. }
  580. /** Product multiply by coefficient.
  581. * @param c coefficient.
  582. * @return this*c.
  583. */
  584. public Product<C> multiply(C c) {
  585. SortedMap<Integer,C> elem = new TreeMap<Integer,C>();
  586. for ( Integer i : val.keySet() ) {
  587. C v = val.get(i).multiply(c);
  588. if ( v != null && ! v.isZERO() ) {
  589. elem.put( i, v );
  590. }
  591. }
  592. return new Product<C>( ring, elem );
  593. }
  594. /**
  595. * Greatest common divisor.
  596. * @param S other element.
  597. * @return gcd(this,S).
  598. */
  599. public Product<C> gcd(Product<C> S) {
  600. if ( S == null || S.isZERO() ) {
  601. return this;
  602. }
  603. if ( this.isZERO() ) {
  604. return S;
  605. }
  606. SortedMap<Integer,C> elem = new TreeMap<Integer,C>( val ); // clone
  607. SortedMap<Integer,C> sel = S.val;
  608. for ( Integer i : sel.keySet() ) {
  609. C x = elem.get( i );
  610. C y = sel.get( i ); // assert y != null
  611. if ( x != null ) {
  612. x = x.gcd(y);
  613. if ( x != null && ! x.isZERO() ) {
  614. elem.put( i, x );
  615. } else {
  616. elem.remove( i );
  617. }
  618. } else {
  619. elem.put( i, y );
  620. }
  621. }
  622. return new Product<C>( ring, elem );
  623. }
  624. /**
  625. * Extended greatest common divisor.
  626. * @param S other element.
  627. * @return [ gcd(this,S), c1, c2 ] with c1*this + c2*b = gcd(this,S).
  628. */
  629. @SuppressWarnings("unchecked")
  630. public Product<C>[] egcd(Product<C> S) {
  631. Product<C>[] ret = (Product<C>[]) new Product[3];
  632. ret[0] = null;
  633. ret[1] = null;
  634. ret[2] = null;
  635. if ( S == null || S.isZERO() ) {
  636. ret[0] = this;
  637. return ret;
  638. }
  639. if ( this.isZERO() ) {
  640. ret[0] = S;
  641. return ret;
  642. }
  643. SortedMap<Integer,C> elem = new TreeMap<Integer,C>( val ); // clone
  644. SortedMap<Integer,C> elem1 = this.idempotent().val; // init with 1
  645. SortedMap<Integer,C> elem2 = new TreeMap<Integer,C>(); // zero
  646. SortedMap<Integer,C> sel = S.val;
  647. for ( Integer i : sel.keySet() ) {
  648. C x = elem.get( i );
  649. C y = sel.get( i ); // assert y != null
  650. if ( x != null ) {
  651. C[] g = x.egcd(y);
  652. if ( ! g[0].isZERO() ) {
  653. elem.put( i, g[0] );
  654. elem1.put( i, g[1] );
  655. elem2.put( i, g[2] );
  656. } else {
  657. elem.remove( i );
  658. }
  659. } else {
  660. elem.put( i, y );
  661. elem2.put( i, ring.getFactory(i).getONE() );
  662. }
  663. }
  664. ret[0] = new Product<C>( ring, elem );
  665. ret[1] = new Product<C>( ring, elem1 );
  666. ret[2] = new Product<C>( ring, elem2 );
  667. return ret;
  668. }
  669. }