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