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