001    /*
002     * $Id: GenMatrixRing.java 3571 2011-03-18 22:02:51Z kredel $
003     */
004    
005    package edu.jas.vector;
006    
007    
008    // import java.io.IOException;
009    import java.io.Reader;
010    import java.math.BigInteger;
011    import java.util.ArrayList;
012    import java.util.List;
013    import java.util.Random;
014    
015    import org.apache.log4j.Logger;
016    
017    import edu.jas.kern.StringUtil;
018    import edu.jas.structure.AlgebraFactory;
019    import edu.jas.structure.RingElem;
020    import edu.jas.structure.RingFactory;
021    
022    
023    /**
024     * GenMatrixRing implements a generic matrix algebra factory with RingFactory.
025     * Matrices of n rows and m columns over C.
026     * @author Heinz Kredel
027     */
028    
029    public class GenMatrixRing<C extends RingElem<C>> implements AlgebraFactory<GenMatrix<C>, C> {
030    
031    
032        private static final Logger logger = Logger.getLogger(GenMatrixRing.class);
033    
034    
035        public final RingFactory<C> coFac;
036    
037    
038        public final int rows;
039    
040    
041        public final int cols;
042    
043    
044        public final int blocksize;
045    
046    
047        public final static int DEFAULT_BSIZE = 10;
048    
049    
050        public final GenMatrix<C> ZERO;
051    
052    
053        public final GenMatrix<C> ONE;
054    
055    
056        private final static Random random = new Random();
057    
058    
059        public final static float DEFAULT_DENSITY = 0.5f;
060    
061    
062        private final float density = DEFAULT_DENSITY;
063    
064    
065        /**
066         * Constructors for GenMatrixRing.
067         * @param b coefficient factory.
068         * @param r number of rows.
069         * @param c number of colums.
070         */
071        public GenMatrixRing(RingFactory<C> b, int r, int c) {
072            this(b, r, c, DEFAULT_BSIZE);
073        }
074    
075    
076        /**
077         * Constructors for GenMatrixRing.
078         * @param b coefficient factory.
079         * @param r number of rows.
080         * @param c number of colums.
081         * @param s block size for blocked operations.
082         */
083        @SuppressWarnings("unchecked")
084        public GenMatrixRing(RingFactory<C> b, int r, int c, int s) {
085            if (b == null) {
086                throw new IllegalArgumentException("RingFactory is null");
087            }
088            if (r < 1) {
089                throw new IllegalArgumentException("rows < 1 " + r);
090            }
091            if (c < 1) {
092                throw new IllegalArgumentException("cols < 1 " + c);
093            }
094            coFac = b;
095            rows = r;
096            cols = c;
097            blocksize = s;
098            ArrayList<C> z = new ArrayList<C>(cols);
099            for (int i = 0; i < cols; i++) {
100                z.add(coFac.getZERO());
101            }
102            ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows);
103            for (int i = 0; i < rows; i++) {
104                m.add((ArrayList<C>) z.clone());
105            }
106            ZERO = new GenMatrix<C>(this, m);
107            m = new ArrayList<ArrayList<C>>(rows);
108            C one = coFac.getONE();
109            ArrayList<C> v;
110            for (int i = 0; i < rows; i++) {
111                if (i < cols) {
112                    v = (ArrayList<C>) z.clone();
113                    v.set(i, one);
114                    m.add(v);
115                }
116            }
117            ONE = new GenMatrix<C>(this, m);
118        }
119    
120    
121        /**
122         * Get the String representation as RingElem.
123         * @see java.lang.Object#toString()
124         */
125        @Override
126        public String toString() {
127            StringBuffer s = new StringBuffer();
128            s.append(coFac.getClass().getSimpleName());
129            s.append("[" + rows + "," + cols + "]");
130            return s.toString();
131        }
132    
133    
134        /**
135         * Get a scripting compatible string representation.
136         * @return script compatible representation for this ElemFactory.
137         * @see edu.jas.structure.ElemFactory#toScript()
138         */
139        //JAVA6only: @Override
140        public String toScript() {
141            // Python case
142            StringBuffer s = new StringBuffer("Mat(");
143            String f = null;
144            try {
145                f = ((RingElem<C>) coFac).toScriptFactory(); // sic
146            } catch (Exception e) {
147                f = coFac.toScript();
148            }
149            s.append(f + "," + rows + "," + cols + ")");
150            return s.toString();
151        }
152    
153    
154        /**
155         * Get the constant one for the GenMatrix.
156         * @return ZERO.
157         */
158        public GenMatrix<C> getZERO() {
159            return ZERO;
160        }
161    
162    
163        /**
164         * Get the constant one for the GenMatrix.
165         * @return 1.
166         */
167        public GenMatrix<C> getONE() {
168            return ONE;
169        }
170    
171    
172        /**
173         * Get a list of the generating elements.
174         * @return list of generators for the algebraic structure.
175         * @see edu.jas.structure.ElemFactory#generators()
176         */
177        public List<GenMatrix<C>> generators() {
178            List<C> rgens = coFac.generators();
179            List<GenMatrix<C>> gens = new ArrayList<GenMatrix<C>>(rows * cols * rgens.size());
180            for (int i = 0; i < rows; i++) {
181                for (int j = 0; j < cols; j++) {
182                    for (C el : rgens) {
183                        GenMatrix<C> g = ZERO.set(i, j, el); // uses clone()
184                        gens.add(g);
185                    }
186                }
187            }
188            return gens;
189        }
190    
191    
192        /**
193         * Is this structure finite or infinite.
194         * @return true if this structure is finite, else false.
195         * @see edu.jas.structure.ElemFactory#isFinite()
196         */
197        public boolean isFinite() {
198            return coFac.isFinite();
199        }
200    
201    
202        /**
203         * Comparison with any other object.
204         * @see java.lang.Object#equals(java.lang.Object)
205         */
206        @Override
207        public boolean equals(Object other) {
208            if (!(other instanceof GenMatrixRing)) {
209                return false;
210            }
211            GenMatrixRing omod = (GenMatrixRing) other;
212            if (rows != omod.rows) {
213                return false;
214            }
215            if (cols != omod.cols) {
216                return false;
217            }
218            if (!coFac.equals(omod.coFac)) {
219                return false;
220            }
221            return true;
222        }
223    
224    
225        /**
226         * Hash code for this matrix ring.
227         * @see java.lang.Object#hashCode()
228         */
229        @Override
230        public int hashCode() {
231            int h;
232            h = rows * 17 + cols;
233            h = 37 * h + coFac.hashCode();
234            return h;
235        }
236    
237    
238        /**
239         * Query if this ring is a field. May return false if it is to hard to
240         * determine if this ring is a field.
241         * @return true if it is known that this ring is a field, else false.
242         */
243        public boolean isField() {
244            return false;
245        }
246    
247    
248        /**
249         * Query if this monoid is commutative.
250         * @return true if this monoid is commutative, else false.
251         */
252        public boolean isCommutative() {
253            return false;
254        }
255    
256    
257        /**
258         * Query if this ring is associative.
259         * @return true if this monoid is associative, else false.
260         */
261        public boolean isAssociative() {
262            return (rows == cols);
263        }
264    
265    
266        /**
267         * Characteristic of this ring.
268         * @return characteristic of this ring.
269         */
270        public java.math.BigInteger characteristic() {
271            return coFac.characteristic();
272        }
273    
274    
275        /**
276         * Transposed matrix ring.
277         * @return transposed ring factory.
278         */
279        public GenMatrixRing<C> transpose() {
280            if (rows == cols) {
281                return this;
282            }
283            return new GenMatrixRing<C>(coFac, cols, rows, blocksize);
284        }
285    
286    
287        /**
288         * Product matrix ring for multiplication.
289         * @param other matrix ring factory.
290         * @return product ring factory.
291         */
292        public GenMatrixRing<C> product(GenMatrixRing<C> other) {
293            if (cols != other.rows) {
294                throw new IllegalArgumentException("invalid dimensions in product");
295            }
296            if (!coFac.equals(other.coFac)) {
297                throw new IllegalArgumentException("invalid coefficients in product");
298            }
299            if (rows == other.rows && cols == other.cols) {
300                return this;
301            }
302            return new GenMatrixRing<C>(coFac, rows, other.cols, blocksize);
303        }
304    
305    
306        /**
307         * Get the matrix for a.
308         * @param a long
309         * @return matrix corresponding to a.
310         */
311        public GenMatrix<C> fromInteger(long a) {
312            C c = coFac.fromInteger(a);
313            return ONE.scalarMultiply(c);
314        }
315    
316    
317        /**
318         * Get the matrix for a.
319         * @param a long
320         * @return matrix corresponding to a.
321         */
322        public GenMatrix<C> fromInteger(BigInteger a) {
323            C c = coFac.fromInteger(a);
324            return ONE.scalarMultiply(c);
325        }
326    
327    
328        /**
329         * From List of coefficients.
330         * @param om list of list of coefficients.
331         */
332        public GenMatrix<C> fromList(List<List<C>> om) {
333            if (om == null) {
334                return ZERO;
335            }
336            if (om.size() > rows) {
337                throw new IllegalArgumentException("size v > rows " + om + " > " + rows);
338            }
339            ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows);
340            for (int i = 0; i < rows; i++) {
341                List<C> ov = om.get(i);
342                ArrayList<C> v;
343                if (ov == null) {
344                    v = ZERO.matrix.get(0);
345                } else {
346                    if (ov.size() > cols) {
347                        throw new IllegalArgumentException("size v > cols " + ov + " > " + cols);
348                    }
349                    v = new ArrayList<C>(cols);
350                    v.addAll(ov);
351                    // pad with zeros if required:
352                    for (int j = v.size(); j < cols; j++) {
353                        v.add(coFac.getZERO());
354                    }
355                }
356                m.add(v);
357            }
358            return new GenMatrix<C>(this, m);
359        }
360    
361    
362        /**
363         * Random matrix.
364         * @param k size of random coefficients.
365         */
366        public GenMatrix<C> random(int k) {
367            return random(k, density, random);
368        }
369    
370    
371        /**
372         * Random matrix.
373         * @param k size of random coefficients.
374         * @param q density of nozero coefficients.
375         */
376        public GenMatrix<C> random(int k, float q) {
377            return random(k, q, random);
378        }
379    
380    
381        /**
382         * Random matrix.
383         * @param k size of random coefficients.
384         * @param random is a source for random bits.
385         * @return a random element.
386         */
387        public GenMatrix<C> random(int k, Random random) {
388            return random(k, density, random);
389        }
390    
391    
392        /**
393         * Random matrix.
394         * @param k size of random coefficients.
395         * @param q density of nozero coefficients.
396         * @param random is a source for random bits.
397         * @return a random element.
398         */
399        public GenMatrix<C> random(int k, float q, Random random) {
400            ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows);
401            for (int i = 0; i < rows; i++) {
402                ArrayList<C> v = new ArrayList<C>(cols);
403                for (int j = 0; j < cols; j++) {
404                    C e;
405                    if (random.nextFloat() < q) {
406                        e = coFac.random(k);
407                    } else {
408                        e = coFac.getZERO();
409                    }
410                    v.add(e);
411                }
412                m.add(v);
413            }
414            return new GenMatrix<C>(this, m);
415        }
416    
417    
418        /**
419         * Random upper triangular matrix.
420         * @param k size of random coefficients.
421         * @param q density of nozero coefficients.
422         */
423        public GenMatrix<C> randomUpper(int k, float q) {
424            return randomUpper(k, q, random);
425        }
426    
427    
428        /**
429         * Random upper triangular matrix.
430         * @param k size of random coefficients.
431         * @param q density of nozero coefficients.
432         * @param random is a source for random bits.
433         * @return a random element.
434         */
435        public GenMatrix<C> randomUpper(int k, float q, Random random) {
436            ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows);
437            for (int i = 0; i < rows; i++) {
438                ArrayList<C> v = new ArrayList<C>(cols);
439                for (int j = 0; j < cols; j++) {
440                    C e = coFac.getZERO();
441                    if (j >= i) {
442                        if (random.nextFloat() < q) {
443                            e = coFac.random(k);
444                        }
445                    }
446                    v.add(e);
447                }
448                m.add(v);
449            }
450            return new GenMatrix<C>(this, m);
451        }
452    
453    
454        /**
455         * Random lower triangular matrix.
456         * @param k size of random coefficients.
457         * @param q density of nozero coefficients.
458         */
459        public GenMatrix<C> randomLower(int k, float q) {
460            return randomLower(k, q, random);
461        }
462    
463    
464        /**
465         * Random lower triangular matrix.
466         * @param k size of random coefficients.
467         * @param q density of nozero coefficients.
468         * @param random is a source for random bits.
469         * @return a random element.
470         */
471        public GenMatrix<C> randomLower(int k, float q, Random random) {
472            ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows);
473            for (int i = 0; i < rows; i++) {
474                ArrayList<C> v = new ArrayList<C>(cols);
475                for (int j = 0; j < cols; j++) {
476                    C e = coFac.getZERO();
477                    if (j <= i) {
478                        if (random.nextFloat() < q) {
479                            e = coFac.random(k);
480                        }
481                    }
482                    v.add(e);
483                }
484                m.add(v);
485            }
486            return new GenMatrix<C>(this, m);
487        }
488    
489    
490        /**
491         * copy matrix.
492         */
493        public GenMatrix<C> copy(GenMatrix<C> c) {
494            if (c == null) {
495                return c;
496            }
497            return c.clone();
498        }
499    
500    
501        /**
502         * parse a matrix from a String. Syntax: [ [ c, ..., c ], ..., [ c, ..., c ]
503         * ]
504         */
505        public GenMatrix<C> parse(String s) {
506            int i = s.indexOf("[");
507            if (i >= 0) {
508                s = s.substring(i + 1);
509            }
510            ArrayList<ArrayList<C>> mat = new ArrayList<ArrayList<C>>(rows);
511            ArrayList<C> v;
512            GenVector<C> vec;
513            GenVectorModul<C> vmod = new GenVectorModul<C>(coFac, cols);
514            String e;
515            int j;
516            do {
517                i = s.indexOf("]"); // delimit vector
518                j = s.lastIndexOf("]"); // delimit matrix
519                if (i != j) {
520                    if (i >= 0) {
521                        e = s.substring(0, i);
522                        s = s.substring(i);
523                        vec = vmod.parse(e);
524                        v = (ArrayList<C>) vec.val;
525                        mat.add(v);
526                        i = s.indexOf(",");
527                        if (i >= 0) {
528                            s = s.substring(i + 1);
529                        }
530                    }
531                } else { // matrix delimiter
532                    if (i >= 0) {
533                        e = s.substring(0, i);
534                        if (e.trim().length() > 0) {
535                            throw new RuntimeException("Error e not empty " + e);
536                        }
537                        s = s.substring(i + 1);
538                    }
539                    break;
540                }
541            } while (i >= 0);
542            return new GenMatrix<C>(this, mat);
543        }
544    
545    
546        /**
547         * parse a matrix from a Reader.
548         */
549        public GenMatrix<C> parse(Reader r) {
550            String s = StringUtil.nextPairedString(r, '[', ']');
551            return parse(s);
552        }
553    
554    }