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