001/*
002 * $Id$
003 */
004
005package edu.jas.vector;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import org.apache.logging.log4j.LogManager;
012import org.apache.logging.log4j.Logger;
013
014import edu.jas.kern.PrettyPrint;
015import edu.jas.structure.AlgebraElem;
016import edu.jas.structure.NotInvertibleException;
017import edu.jas.structure.RingElem;
018
019
020/**
021 * GenMatrix implements a generic matrix algebra over RingElem entries. Matrix
022 * has n columns and m rows over C.
023 * @author Heinz Kredel
024 */
025
026public class GenMatrix<C extends RingElem<C>> implements AlgebraElem<GenMatrix<C>, C> {
027
028
029    private static final Logger logger = LogManager.getLogger(GenMatrix.class);
030
031
032    public final GenMatrixRing<C> ring;
033
034
035    public final ArrayList<ArrayList<C>> matrix;
036
037
038    private int hashValue = 0;
039
040
041    /**
042     * Constructor for zero GenMatrix.
043     * @param r matrix ring
044     */
045    public GenMatrix(GenMatrixRing<C> r) {
046        this(r, r.getZERO().matrix);
047    }
048
049
050    /**
051     * Constructor for GenMatrix.
052     * @param r matrix ring
053     * @param m matrix
054     */
055    public GenMatrix(GenMatrixRing<C> r, List<List<C>> m) {
056        ring = r;
057        matrix = new ArrayList<ArrayList<C>>(r.rows);
058        for (List<C> row : m) {
059            ArrayList<C> nr = new ArrayList<C>(row);
060            matrix.add(nr);
061        }
062        logger.info("{} x {} matrix constructed", ring.rows, ring.cols);
063    }
064
065
066    /**
067     * Constructor for GenMatrix.
068     * @param r matrix ring
069     * @param m matrix
070     */
071    public GenMatrix(GenMatrixRing<C> r, ArrayList<ArrayList<C>> m) {
072        if (r == null || m == null) {
073            throw new IllegalArgumentException("Empty r or m not allowed, r = " + r + ", m = " + m);
074        }
075        ring = r;
076        matrix = new ArrayList<ArrayList<C>>(m);
077        logger.info("{} x {} matrix constructed", ring.rows, ring.cols);
078    }
079
080
081    /**
082     * Constructor for GenMatrix.
083     * @param r matrix ring
084     * @param m matrix
085     */
086    public GenMatrix(GenMatrixRing<C> r, C[][] m) {
087        ring = r;
088        matrix = new ArrayList<ArrayList<C>>(r.rows);
089        for (C[] row : m) {
090            ArrayList<C> nr = new ArrayList<C>(r.cols);
091            for (int i = 0; i < row.length; i++) {
092                nr.add(row[i]);
093            }
094            matrix.add(nr);
095        }
096        logger.info("{} x {} matrix constructed", ring.rows, ring.cols);
097    }
098
099
100    /**
101     * Get element at row i, column j.
102     * @param i row index.
103     * @param j column index.
104     * @return this(i,j).
105     */
106    public C get(int i, int j) {
107        return matrix.get(i).get(j);
108    }
109
110
111    /**
112     * Set element at row i, column j. Mutates this matrix.
113     * @param i row index.
114     * @param j column index.
115     * @param el element to set.
116     */
117    public void setMutate(int i, int j, C el) {
118        ArrayList<C> ri = matrix.get(i);
119        ri.set(j, el);
120        hashValue = 0; // invalidate
121    }
122
123
124    /**
125     * Set element at row i, column j.
126     * @param i row index.
127     * @param j column index.
128     * @param el element to set.
129     * @return new matrix m, with m(i,j) == el.
130     */
131    public GenMatrix<C> set(int i, int j, C el) {
132        GenMatrix<C> mat = this.copy();
133        mat.setMutate(i, j, el);
134        return mat;
135    }
136
137
138    /**
139     * Get column i.
140     * @param i column index.
141     * @return this(*,i) as vector.
142     */
143    public GenVector<C> getColumn(int i) {
144        List<C> cl = new ArrayList<C>(ring.rows);
145        for (int k = 0; k < ring.rows; k++) {
146            cl.add(matrix.get(k).get(i));
147        }
148        GenVectorModul<C> vfac = new GenVectorModul<C>(ring.coFac, ring.rows);
149        GenVector<C> col = new GenVector<C>(vfac, cl);
150        return col;
151    }
152
153
154    /**
155     * Get row i.
156     * @param i row index.
157     * @return this(i,*) as vector.
158     */
159    public GenVector<C> getRow(int i) {
160        List<C> cl = new ArrayList<C>(ring.cols);
161        cl.addAll(matrix.get(i));
162        GenVectorModul<C> vfac = new GenVectorModul<C>(ring.coFac, ring.cols);
163        GenVector<C> row = new GenVector<C>(vfac, cl);
164        return row;
165    }
166
167
168    /**
169     * Get diagonal.
170     * @return diagonal(this) as vector.
171     */
172    public GenVector<C> getDiagonal() {
173        List<C> cl = new ArrayList<C>(ring.rows);
174        for (int i = 0; i < ring.rows; i++) {
175            cl.add(matrix.get(i).get(i));
176        }
177        GenVectorModul<C> vfac = new GenVectorModul<C>(ring.coFac, ring.rows);
178        GenVector<C> dia = new GenVector<C>(vfac, cl);
179        return dia;
180    }
181
182
183    /**
184     * Get upper triangular U matrix.
185     * @return U as matrix with equal length rows.
186     */
187    public GenMatrix<C> getUpper() {
188        final C zero = ring.coFac.getZERO();
189        final C one = ring.coFac.getONE();
190        List<List<C>> cl = new ArrayList<List<C>>(ring.rows);
191        for (int k = 0; k < ring.rows; k++) {
192            List<C> ul = matrix.get(k);
193            List<C> rl = new ArrayList<C>(ring.cols);
194            for (int i = 0; i < ring.cols; i++) {
195                if (i < k) {
196                    rl.add(zero);
197                } else if (i >= k) {
198                    rl.add(ul.get(i));
199                // } else {
200                //     if (ul.get(i).isZERO()) {
201                //         rl.add(zero);
202                //     } else {
203                //         rl.add(one); // mat(k,k).inverse()
204                //     }
205                }
206            }
207            cl.add(rl);
208        }
209        GenMatrix<C> U = new GenMatrix<C>(ring, cl);
210        return U;
211    }
212
213
214    /**
215     * Get upper triangular U matrix with diagonale 1.
216     * @return U as matrix with equal length rows and diagonale 1.
217     */
218    public GenMatrix<C> getUpperScaled() {
219        final C zero = ring.coFac.getZERO();
220        final C one = ring.coFac.getONE();
221        List<List<C>> cl = new ArrayList<List<C>>(ring.rows);
222        for (int k = 0; k < ring.rows; k++) {
223            List<C> ul = matrix.get(k);
224            C kk = ul.get(k);
225            if (kk.isZERO()) {
226                kk = one;
227            } else {
228                kk = kk.inverse();
229            }
230            List<C> rl = new ArrayList<C>(ring.cols);
231            for (int i = 0; i < ring.cols; i++) {
232                if (i < k) {
233                    rl.add(zero);
234                } else { // if (i >= k)
235                    rl.add( ul.get(i).multiply(kk) );
236                }
237            }
238            cl.add(rl);
239        }
240        GenMatrix<C> U = new GenMatrix<C>(ring, cl);
241        return U;
242    }
243
244
245    /**
246     * Get lower triangular L matrix.
247     * @return L as matrix with equal length rows.
248     */
249    public GenMatrix<C> getLower() {
250        final C zero = ring.coFac.getZERO();
251        List<List<C>> cl = new ArrayList<List<C>>(ring.rows);
252        for (int k = 0; k < ring.rows; k++) {
253            List<C> ul = matrix.get(k);
254            List<C> rl = new ArrayList<C>(ring.cols);
255            for (int i = 0; i < ring.cols; i++) {
256                if (i <= k) {
257                    rl.add(ul.get(i)); // can be zero
258                } else if (i > k) {
259                    rl.add(zero);
260                }
261            }
262            cl.add(rl);
263        }
264        GenMatrix<C> L = new GenMatrix<C>(ring, cl);
265        return L;
266    }
267
268
269    /**
270     * Get the String representation as RingElem.
271     * @see java.lang.Object#toString()
272     */
273    @Override
274    public String toString() {
275        StringBuffer s = new StringBuffer();
276        boolean firstRow = true;
277        s.append("[\n");
278        for (List<C> val : matrix) {
279            if (firstRow) {
280                firstRow = false;
281            } else {
282                s.append(",\n");
283            }
284            boolean first = true;
285            s.append("[ ");
286            for (C c : val) {
287                if (first) {
288                    first = false;
289                } else {
290                    s.append(", ");
291                }
292                s.append(c.toString());
293            }
294            s.append(" ]");
295        }
296        s.append(" ] ");
297        if (!PrettyPrint.isTrue()) {
298            s.append(":: " + ring.toString());
299            s.append("\n");
300        }
301        return s.toString();
302    }
303
304
305    /**
306     * Get a scripting compatible string representation.
307     * @return script compatible representation for this Element.
308     * @see edu.jas.structure.Element#toScript()
309     */
310    @Override
311    public String toScript() {
312        // Python case
313        StringBuffer s = new StringBuffer();
314        boolean firstRow = true;
315        s.append("( ");
316        for (List<C> val : matrix) {
317            if (firstRow) {
318                firstRow = false;
319            } else {
320                s.append(", ");
321            }
322            boolean first = true;
323            s.append("( ");
324            for (C c : val) {
325                if (first) {
326                    first = false;
327                } else {
328                    s.append(", ");
329                }
330                s.append(c.toScript());
331            }
332            s.append(" )");
333        }
334        s.append(" ) ");
335        return s.toString();
336    }
337
338
339    /**
340     * Get a scripting compatible string representation of the factory.
341     * @return script compatible representation for this ElemFactory.
342     * @see edu.jas.structure.Element#toScriptFactory()
343     */
344    @Override
345    public String toScriptFactory() {
346        // Python case
347        return factory().toScript();
348    }
349
350
351    /**
352     * Get the corresponding element factory.
353     * @return factory for this Element.
354     * @see edu.jas.structure.Element#factory()
355     */
356    public GenMatrixRing<C> factory() {
357        return ring;
358    }
359
360
361    /**
362     * Copy method.
363     * @see edu.jas.structure.Element#copy()
364     */
365    @Override
366    public GenMatrix<C> copy() {
367        //return ring.copy(this);
368        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
369        ArrayList<C> v;
370        for (ArrayList<C> val : matrix) {
371            v = new ArrayList<C>(val);
372            m.add(v);
373        }
374        return new GenMatrix<C>(ring, m);
375    }
376
377
378    /**
379     * Stack method.
380     * @param st stacked matrix ring.
381     * @param b other matrix.
382     * @return stacked matrix, this on top of other.
383     */
384    public GenMatrix<C> stack(GenMatrixRing<C> st, GenMatrix<C> b) {
385        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(st.rows);
386        ArrayList<C> v;
387        for (ArrayList<C> val : matrix) {
388            v = new ArrayList<C>(val);
389            m.add(v);
390        }
391        for (ArrayList<C> val : b.matrix) {
392            v = new ArrayList<C>(val);
393            m.add(v);
394        }
395        return new GenMatrix<C>(st, m);
396    }
397
398
399    /**
400     * Concat method.
401     * @param cc concated matrix ring.
402     * @param b other matrix.
403     * @return concated matrix, this before of other.
404     */
405    public GenMatrix<C> concat(GenMatrixRing<C> cc, GenMatrix<C> b) {
406        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(cc.rows);
407        ArrayList<ArrayList<C>> bm = b.matrix;
408        ArrayList<C> v, o;
409        int i = 0;
410        for (ArrayList<C> val : matrix) {
411            v = new ArrayList<C>(val);
412            o = bm.get(i++);
413            v.addAll(o);
414            m.add(v);
415        }
416        return new GenMatrix<C>(cc, m);
417    }
418
419
420    /**
421     * Test if this is equal to a zero matrix.
422     */
423    public boolean isZERO() {
424        for (List<C> row : matrix) {
425            for (C elem : row) {
426                if (!elem.isZERO()) {
427                    return false;
428                }
429            }
430        }
431        return true;
432    }
433
434
435    /**
436     * Test if this is one.
437     * @return true if this is 1, else false.
438     */
439    public boolean isONE() {
440        int i = 0;
441        for (List<C> row : matrix) {
442            int j = 0;
443            for (C elem : row) {
444                if (i == j) {
445                    if (!elem.isONE()) {
446                        //System.out.println("elem.isONE = " + elem);
447                        return false;
448                    }
449                } else if (!elem.isZERO()) {
450                    //System.out.println("elem.isZERO = " + elem);
451                    return false;
452                }
453                j++;
454            }
455            i++;
456        }
457        return true;
458    }
459
460
461    /**
462     * Comparison with any other object.
463     * @see java.lang.Object#equals(java.lang.Object)
464     */
465    @Override
466    @SuppressWarnings("unchecked")
467    public boolean equals(Object other) {
468        if (!(other instanceof GenMatrix)) {
469            return false;
470        }
471        GenMatrix om = (GenMatrix) other;
472        if (!ring.equals(om.ring)) {
473            return false;
474        }
475        if (!matrix.equals(om.matrix)) {
476            return false;
477        }
478        return true;
479    }
480
481
482    /**
483     * Hash code for this GenMatrix.
484     * @see java.lang.Object#hashCode()
485     */
486    @Override
487    public int hashCode() {
488        if (hashValue == 0) {
489            hashValue = 37 * matrix.hashCode() + ring.hashCode();
490            if (hashValue == 0) {
491                hashValue = 1;
492            }
493        }
494        return hashValue;
495    }
496
497
498    /**
499     * compareTo, lexicogaphical comparison.
500     * @param b other
501     * @return 1 if (this &lt; b), 0 if (this == b) or -1 if (this &gt; b).
502     */
503    @Override
504    public int compareTo(GenMatrix<C> b) {
505        if (!ring.equals(b.ring)) {
506            return -1;
507        }
508        ArrayList<ArrayList<C>> om = b.matrix;
509        int i = 0;
510        for (ArrayList<C> val : matrix) {
511            ArrayList<C> ov = om.get(i++);
512            int j = 0;
513            for (C c : val) {
514                int s = c.compareTo(ov.get(j++));
515                if (s != 0) {
516                    return s;
517                }
518            }
519        }
520        return 0;
521    }
522
523
524    /**
525     * Test if this is a unit. I.e. there exists x with this.multiply(x).isONE()
526     * == true. Tests if matrix is not singular.
527     * Was previously a test if all diagonal elements are units and all other
528     *  elements are zero.
529     * @return true if this is a unit, else false.
530     */
531    public boolean isUnit() {
532        LinAlg<C> la = new LinAlg<C>();
533        GenMatrix<C> mat = this.copy();
534        List<Integer> P = la.decompositionLU(mat);
535        if (P == null || P.isEmpty()) {
536            return false;
537        }
538        return true;
539    }
540
541
542    /**
543     * sign of matrix.
544     * @return 1 if (this &lt; 0), 0 if (this == 0) or -1 if (this &gt; 0).
545     */
546    public int signum() {
547        return compareTo(ring.getZERO());
548    }
549
550
551    /**
552     * Sum of matrices.
553     * @param b other matrix.
554     * @return this+b
555     */
556    public GenMatrix<C> sum(GenMatrix<C> b) {
557        ArrayList<ArrayList<C>> om = b.matrix;
558        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
559        int i = 0;
560        for (ArrayList<C> val : matrix) {
561            ArrayList<C> ov = om.get(i++);
562            ArrayList<C> v = new ArrayList<C>(ring.cols);
563            int j = 0;
564            for (C c : val) {
565                C e = c.sum(ov.get(j++));
566                v.add(e);
567            }
568            m.add(v);
569        }
570        return new GenMatrix<C>(ring, m);
571    }
572
573
574    /**
575     * Difference of matrices.
576     * @param b other matrix.
577     * @return this-b
578     */
579    public GenMatrix<C> subtract(GenMatrix<C> b) {
580        ArrayList<ArrayList<C>> om = b.matrix;
581        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
582        int i = 0;
583        for (ArrayList<C> val : matrix) {
584            ArrayList<C> ov = om.get(i++);
585            ArrayList<C> v = new ArrayList<C>(ring.cols);
586            int j = 0;
587            for (C c : val) {
588                C e = c.subtract(ov.get(j++));
589                v.add(e);
590            }
591            m.add(v);
592        }
593        return new GenMatrix<C>(ring, m);
594    }
595
596
597    /**
598     * Negative of this matrix.
599     * @return -this
600     */
601    public GenMatrix<C> negate() {
602        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
603        //int i = 0;
604        for (ArrayList<C> val : matrix) {
605            ArrayList<C> v = new ArrayList<C>(ring.cols);
606            for (C c : val) {
607                C e = c.negate();
608                v.add(e);
609            }
610            m.add(v);
611        }
612        return new GenMatrix<C>(ring, m);
613    }
614
615
616    /**
617     * Absolute value of this matrix.
618     * @return abs(this)
619     */
620    public GenMatrix<C> abs() {
621        if (signum() < 0) {
622            return negate();
623        }
624        return this;
625    }
626
627
628    /**
629     * Product of this matrix with scalar.
630     * @param s scalar.
631     * @return this*s
632     */
633    public GenMatrix<C> multiply(C s) {
634        return scalarMultiply(s);
635    }
636
637
638    /**
639     * Product of this matrix with scalar.
640     * @param s scalar
641     * @return this*s
642     */
643    public GenMatrix<C> scalarMultiply(C s) {
644        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
645        //int i = 0;
646        for (ArrayList<C> val : matrix) {
647            ArrayList<C> v = new ArrayList<C>(ring.cols);
648            for (C c : val) {
649                C e = c.multiply(s);
650                v.add(e);
651            }
652            m.add(v);
653        }
654        return new GenMatrix<C>(ring, m);
655    }
656
657
658    /**
659     * Left product of this matrix with scalar.
660     * @param s scalar
661     * @return s*this
662     */
663    public GenMatrix<C> leftScalarMultiply(C s) {
664        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
665        //int i = 0;
666        for (ArrayList<C> val : matrix) {
667            ArrayList<C> v = new ArrayList<C>(ring.cols);
668            for (C c : val) {
669                C e = s.multiply(c);
670                v.add(e);
671            }
672            m.add(v);
673        }
674        return new GenMatrix<C>(ring, m);
675    }
676
677
678    /**
679     * Linear compination of this matrix with scalar multiple of other matrix.
680     * @param s scalar
681     * @param t scalar
682     * @param b other matrix.
683     * @return this*s+b*t
684     */
685    public GenMatrix<C> linearCombination(C s, GenMatrix<C> b, C t) {
686        ArrayList<ArrayList<C>> om = b.matrix;
687        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
688        int i = 0;
689        for (ArrayList<C> val : matrix) {
690            ArrayList<C> ov = om.get(i++);
691            ArrayList<C> v = new ArrayList<C>(ring.cols);
692            int j = 0;
693            for (C c : val) {
694                C c1 = c.multiply(s);
695                C c2 = ov.get(j++).multiply(t);
696                C e = c1.sum(c2);
697                v.add(e);
698            }
699            m.add(v);
700        }
701        return new GenMatrix<C>(ring, m);
702    }
703
704
705    /**
706     * Linear combination of this matrix with scalar multiple of other matrix.
707     * @param t scalar
708     * @param b other matrix.
709     * @return this+b*t
710     */
711    public GenMatrix<C> linearCombination(GenMatrix<C> b, C t) {
712        ArrayList<ArrayList<C>> om = b.matrix;
713        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
714        int i = 0;
715        for (ArrayList<C> val : matrix) {
716            ArrayList<C> ov = om.get(i++);
717            ArrayList<C> v = new ArrayList<C>(ring.cols);
718            int j = 0;
719            for (C c : val) {
720                C c2 = ov.get(j++).multiply(t);
721                C e = c.sum(c2);
722                v.add(e);
723            }
724            m.add(v);
725        }
726        return new GenMatrix<C>(ring, m);
727    }
728
729
730    /**
731     * Left linear combination of this matrix with scalar multiple of other
732     * matrix.
733     * @param t scalar
734     * @param b other matrix.
735     * @return this+t*b
736     */
737    public GenMatrix<C> linearCombination(C t, GenMatrix<C> b) {
738        ArrayList<ArrayList<C>> om = b.matrix;
739        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
740        int i = 0;
741        for (ArrayList<C> val : matrix) {
742            ArrayList<C> ov = om.get(i++);
743            ArrayList<C> v = new ArrayList<C>(ring.cols);
744            int j = 0;
745            for (C c : val) {
746                C c2 = t.multiply(ov.get(j++));
747                C e = c.sum(c2);
748                v.add(e);
749            }
750            m.add(v);
751        }
752        return new GenMatrix<C>(ring, m);
753    }
754
755
756    /**
757     * left linear compination of this matrix with scalar multiple of other
758     * matrix.
759     * @param s scalar
760     * @param t scalar
761     * @param b other matrix.
762     * @return s*this+t*b
763     */
764    public GenMatrix<C> leftLinearCombination(C s, C t, GenMatrix<C> b) {
765        ArrayList<ArrayList<C>> om = b.matrix;
766        ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(ring.rows);
767        int i = 0;
768        for (ArrayList<C> val : matrix) {
769            ArrayList<C> ov = om.get(i++);
770            ArrayList<C> v = new ArrayList<C>(ring.cols);
771            int j = 0;
772            for (C c : val) {
773                C c1 = s.multiply(c);
774                C c2 = t.multiply(ov.get(j++));
775                C e = c1.sum(c2);
776                v.add(e);
777            }
778            m.add(v);
779        }
780        return new GenMatrix<C>(ring, m);
781    }
782
783
784    /**
785     * Transposed matrix.
786     * @param tr transposed matrix ring.
787     * @return transpose(this)
788     */
789    public GenMatrix<C> transpose(GenMatrixRing<C> tr) {
790        GenMatrix<C> t = tr.getZERO().copy();
791        ArrayList<ArrayList<C>> m = t.matrix;
792        int i = 0;
793        for (ArrayList<C> val : matrix) {
794            int j = 0;
795            for (C c : val) {
796                (m.get(j)).set(i, c); //A[j,i] = A[i,j]
797                j++;
798            }
799            i++;
800        }
801        // return new GenMatrix<C>(tr,m);
802        return t;
803    }
804
805
806    /**
807     * Transposed matrix.
808     * @return transpose(this)
809     */
810    public GenMatrix<C> transpose() {
811        GenMatrixRing<C> tr = ring.transpose();
812        return transpose(tr);
813    }
814
815
816    /**
817     * Multiply this with S.
818     * @param S other matrix.
819     * @return this * S.
820     */
821    public GenMatrix<C> multiply(GenMatrix<C> S) {
822        int na = ring.blocksize;
823        int nb = ring.blocksize;
824        //System.out.println("#blocks = " + (matrix.size()/na) + ", na = " + na 
825        //    + " SeqMultBlockTrans");
826        ArrayList<ArrayList<C>> m = matrix;
827        //ArrayList<ArrayList<C>> s = S.matrix;
828
829        GenMatrixRing<C> tr = S.ring.transpose();
830        GenMatrix<C> T = S.transpose(tr);
831        ArrayList<ArrayList<C>> t = T.matrix;
832        //System.out.println("T = " + T); 
833
834        GenMatrixRing<C> pr = ring.product(S.ring);
835        GenMatrix<C> P = pr.getZERO().copy();
836        ArrayList<ArrayList<C>> p = P.matrix;
837        //System.out.println("P = " + P); 
838
839        for (int ii = 0; ii < m.size(); ii += na) {
840            for (int jj = 0; jj < t.size(); jj += nb) {
841
842                for (int i = ii; i < Math.min((ii + na), m.size()); i++) {
843                    ArrayList<C> Ai = m.get(i); //A[i];
844                    for (int j = jj; j < Math.min((jj + nb), t.size()); j++) {
845                        ArrayList<C> Bj = t.get(j); //B[j];
846                        C c = ring.coFac.getZERO();
847                        for (int k = 0; k < Bj.size(); k++) {
848                            c = c.sum(Ai.get(k).multiply(Bj.get(k)));
849                            //  c += Ai[k] * Bj[k];
850                        }
851                        (p.get(i)).set(j, c); // C[i][j] = c;
852                    }
853                }
854
855            }
856        }
857        return new GenMatrix<C>(pr, p);
858    }
859
860
861    /**
862     * Multiply this with S. Simple unblocked algorithm.
863     * @param S other matrix.
864     * @return this * S.
865     */
866    public GenMatrix<C> multiplySimple(GenMatrix<C> S) {
867        ArrayList<ArrayList<C>> m = matrix;
868        ArrayList<ArrayList<C>> B = S.matrix;
869
870        GenMatrixRing<C> pr = ring.product(S.ring);
871        GenMatrix<C> P = pr.getZERO().copy();
872        ArrayList<ArrayList<C>> p = P.matrix;
873
874        for (int i = 0; i < pr.rows; i++) {
875            ArrayList<C> Ai = m.get(i); //A[i];
876            for (int j = 0; j < pr.cols; j++) {
877                C c = ring.coFac.getZERO();
878                for (int k = 0; k < S.ring.rows; k++) {
879                    c = c.sum(Ai.get(k).multiply(B.get(k).get(j)));
880                    //  c += A[i][k] * B[k][j];
881                }
882                (p.get(i)).set(j, c); // C[i][j] = c;
883            }
884        }
885        return new GenMatrix<C>(pr, p);
886    }
887
888
889    /**
890     * Divide this by S.
891     * @param S other matrix.
892     * @return this * S^{-1}.
893     */
894    public GenMatrix<C> divide(GenMatrix<C> S) {
895        //throw new UnsupportedOperationException("divide not yet implemented");
896        return multiply(S.inverse());
897    }
898
899
900    /**
901     * Divide left this by S.
902     * @param S other matrix.
903     * @return S^{-1} * this.
904     */
905    public GenMatrix<C> divideLeft(GenMatrix<C> S) {
906        return S.inverse().multiply(this);
907    }
908
909
910    /**
911     * Remainder after division of this by S.
912     * @param S other matrix.
913     * @return this - (this / S) * S.
914     */
915    public GenMatrix<C> remainder(GenMatrix<C> S) {
916        throw new UnsupportedOperationException("remainder not implemented");
917    }
918
919
920    /**
921     * Quotient and remainder by division of this by S.
922     * @param S a GenMatrix
923     * @return [this/S, this - (this/S)*S].
924     */
925    public GenMatrix<C>[] quotientRemainder(GenMatrix<C> S) {
926        throw new UnsupportedOperationException("quotientRemainder not implemented, input = " + S);
927    }
928
929
930    /**
931     * Inverse of this.
932     * @return x with this * x = 1, if it exists.
933     * @see edu.jas.vector.LinAlg#inverseLU(edu.jas.vector.GenMatrix,java.util.List)
934     */
935    public GenMatrix<C> inverse() {
936        //throw new UnsupportedOperationException("inverse implemented in LinAlg.inverseLU()");
937        LinAlg<C> la = new LinAlg<C>();
938        GenMatrix<C> mat = this.copy();
939        List<Integer> P = la.decompositionLU(mat);
940        if (P == null || P.isEmpty()) {
941            throw new NotInvertibleException("matrix not invertible");
942        }
943        mat = la.inverseLU(mat,P);
944        return mat;
945    }
946
947
948    /**
949     * Greatest common divisor.
950     * @param b other element.
951     * @return gcd(this,b).
952     */
953    public GenMatrix<C> gcd(GenMatrix<C> b) {
954        throw new UnsupportedOperationException("gcd not implemented");
955    }
956
957
958    /**
959     * Extended greatest common divisor.
960     * @param b other element.
961     * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b).
962     */
963    public GenMatrix<C>[] egcd(GenMatrix<C> b) {
964        throw new UnsupportedOperationException("egcd not implemented");
965    }
966
967}