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