001/*
002 * $Id$
003 */
004
005package edu.jas.vector;
006
007
008import java.io.Serializable;
009import java.util.ArrayList;
010import java.util.Iterator;
011import java.util.List;
012
013import org.apache.logging.log4j.LogManager;
014import org.apache.logging.log4j.Logger;
015
016import edu.jas.structure.RingElem;
017
018
019/**
020 * Basic linear algebra methods. Implements Basic linear algebra computations
021 * and tests. <b>Note:</b> will eventually use wrong method dispatch in JRE when
022 * used with GenSolvablePolynomial.
023 * @param <C> coefficient type
024 * @author Heinz Kredel
025 */
026public class BasicLinAlg<C extends RingElem<C>> implements Serializable {
027
028
029    private static final Logger logger = LogManager.getLogger(BasicLinAlg.class);
030
031
032    //private static final boolean debug = logger.isDebugEnabled();
033
034
035    /**
036     * Constructor.
037     */
038    public BasicLinAlg() {
039    }
040
041
042    /**
043     * Scalar product of vectors of ring elements.
044     * @param G a ring element list.
045     * @param F a ring element list.
046     * @return the scalar product of G and F.
047     */
048    public C scalarProduct(List<C> G, List<C> F) {
049        C sp = null;
050        Iterator<C> it = G.iterator();
051        Iterator<C> jt = F.iterator();
052        while (it.hasNext() && jt.hasNext()) {
053            C pi = it.next();
054            C pj = jt.next();
055            if (pi == null || pj == null) {
056                continue;
057            }
058            if (sp == null) {
059                sp = pi.multiply(pj);
060            } else {
061                sp = sp.sum(pi.multiply(pj));
062            }
063        }
064        if (it.hasNext() || jt.hasNext()) {
065            logger.error("scalarProduct wrong sizes");
066        }
067        return sp;
068    }
069
070
071    /**
072     * Scalar product of vectors and a matrix of ring elements.
073     * @param G a ring element list.
074     * @param F a list of ring element lists.
075     * @return the scalar product of G and F.
076     */
077    public List<C> leftScalarProduct(List<C> G, List<List<C>> F) {
078        List<C> sp = null; //new ArrayList<C>(G.size());
079        Iterator<C> it = G.iterator();
080        Iterator<List<C>> jt = F.iterator();
081        while (it.hasNext() && jt.hasNext()) {
082            C pi = it.next();
083            List<C> pj = jt.next();
084            if (pi == null || pj == null) {
085                continue;
086            }
087            List<C> s = scalarProduct(pi, pj);
088            if (sp == null) {
089                sp = s;
090            } else {
091                sp = vectorAdd(sp, s);
092            }
093        }
094        if (it.hasNext() || jt.hasNext()) {
095            logger.error("scalarProduct wrong sizes");
096        }
097        return sp;
098    }
099
100
101    /**
102     * Scalar product of vectors and a matrix of ring elements.
103     * @param G a ring element list.
104     * @param F a list of ring element lists.
105     * @return the right scalar product of G and F.
106     */
107    public List<C> rightScalarProduct(List<C> G, List<List<C>> F) {
108        List<C> sp = null; //new ArrayList<C>(G.size());
109        Iterator<C> it = G.iterator();
110        Iterator<List<C>> jt = F.iterator();
111        while (it.hasNext() && jt.hasNext()) {
112            C pi = it.next();
113            List<C> pj = jt.next();
114            if (pi == null || pj == null) {
115                continue;
116            }
117            List<C> s = scalarProduct(pj, pi);
118            if (sp == null) {
119                sp = s;
120            } else {
121                sp = vectorAdd(sp, s);
122            }
123        }
124        if (it.hasNext() || jt.hasNext()) {
125            logger.error("scalarProduct wrong sizes");
126        }
127        return sp;
128    }
129
130
131    /**
132     * Addition of vectors of ring elements.
133     * @param a a ring element list.
134     * @param b a ring element list.
135     * @return a+b, the vector sum of a and b.
136     */
137    public List<C> vectorAdd(List<C> a, List<C> b) {
138        if (a == null) {
139            return b;
140        }
141        if (b == null) {
142            return a;
143        }
144        List<C> V = new ArrayList<C>(a.size());
145        Iterator<C> it = a.iterator();
146        Iterator<C> jt = b.iterator();
147        while (it.hasNext() && jt.hasNext()) {
148            C pi = it.next();
149            C pj = jt.next();
150            C p = pi.sum(pj);
151            V.add(p);
152        }
153        //System.out.println("vectorAdd" + V);
154        if (it.hasNext() || jt.hasNext()) {
155            logger.error("vectorAdd wrong sizes");
156        }
157        return V;
158    }
159
160
161    /**
162     * Negative of vectors of ring elements.
163     * @param a a ring element list.
164     * @return -a, the vector of -a.
165     */
166    public List<C> vectorNegate(List<C> a) {
167        if (a == null) {
168            return a;
169        }
170        List<C> V = new ArrayList<C>(a.size());
171        Iterator<C> it = a.iterator();
172        while (it.hasNext()) {
173            C pi = it.next();
174            if (pi != null) {
175                pi = pi.negate();
176            }
177            V.add(pi);
178        }
179        //System.out.println("vectorNegate" + V);
180        return V;
181    }
182
183
184    /**
185     * Combination of vectors for reduction representation.
186     * @param a a ring element list.
187     * @param b a ring element list.
188     * @return a-b, the vector difference of a and b, with one entry more.
189     */
190    public List<C> vectorCombineRep(List<C> a, List<C> b) {
191        if (a == null || b == null) {
192            throw new IllegalArgumentException("a and b may not be empty");
193        }
194        // if (a.size() != b.size()) {
195        //     throw new IllegalArgumentException("#a != #b");
196        // }
197        List<C> V = new ArrayList<C>(a.size() + 1);
198        Iterator<C> it = a.iterator();
199        Iterator<C> jt = b.iterator();
200        while (it.hasNext() && jt.hasNext()) {
201            C x = it.next();
202            C y = jt.next();
203            if (x == null) {
204                if (y == null) {
205                    //x = y;
206                } else {
207                    x = y.negate();
208                }
209            } else {
210                if (y == null) {
211                    //x = y;
212                } else {
213                    x = x.subtract(y);
214                }
215            }
216            V.add(x);
217        }
218        if (it.hasNext() || jt.hasNext()) {
219            logger.error("vectorCombineRep wrong sizes: it = {}, jt = {}", it, jt);
220            //throw new RuntimeException("it = " + it + ", jt = " + jt);
221        }
222        V.add(null);
223        //System.out.println("vectorCombineRep" + V);
224        return V;
225    }
226
227
228    /**
229     * Combination of vectors for syzygy representation.
230     * @param a a ring element list.
231     * @param b a ring element list.
232     * @return (-a)+b, the vector sum of -a and b, with one entry more.
233     */
234    public List<C> vectorCombineSyz(List<C> a, List<C> b) {
235        if (a == null || b == null) {
236            throw new IllegalArgumentException("a and b may not be empty");
237        }
238        // if (a.size() != b.size()) {
239        //     throw new IllegalArgumentException("#a != #b");
240        // }
241        List<C> V = new ArrayList<C>(a.size() + 1);
242        Iterator<C> it = a.iterator();
243        Iterator<C> jt = b.iterator();
244        while (it.hasNext() && jt.hasNext()) {
245            C x = it.next();
246            C y = jt.next();
247            if (x == null) {
248                if (y == null) {
249                    //x = y;
250                } else {
251                    x = y;
252                }
253            } else {
254                if (y == null) {
255                    //x = y;
256                } else {
257                    x = x.sum(y);
258                }
259            }
260            V.add(x);
261        }
262        if (it.hasNext() || jt.hasNext()) {
263            logger.error("vectorCombineSyz wrong sizes: it = {}, jt = {}", it, jt);
264            //throw new RuntimeException("it = " + it + ", jt = " + jt);
265        }
266        V.add(null);
267        //System.out.println("vectorCombineSyz" + V);
268        return V;
269    }
270
271
272    /**
273     * Combination of vectors for old representation.
274     * @param a a ring element list.
275     * @param b a ring element list.
276     * @return -a-b, the vector difference of -a and b, with one entry more.
277     */
278    public List<C> vectorCombineOld(List<C> a, List<C> b) {
279        if (a == null || b == null) {
280            throw new IllegalArgumentException("a and b may not be empty");
281        }
282        // if (a.size() != b.size()) {
283        //     throw new IllegalArgumentException("#a != #b");
284        // }
285        List<C> V = new ArrayList<C>(a.size() + 1);
286        Iterator<C> it = a.iterator();
287        Iterator<C> jt = b.iterator();
288        while (it.hasNext() && jt.hasNext()) {
289            C x = it.next();
290            C y = jt.next();
291            if (x != null) {
292                //System.out.println("ms = " + m + " " + x);
293                x = x.negate();
294            }
295            if (y != null) {
296                y = y.negate();
297                //System.out.println("mh = " + m + " " + y);
298            }
299            if (x == null) {
300                x = y;
301            } else if (y != null) {
302                x = x.sum(y);
303            }
304            //System.out.println("mx = " + m + " " + x);
305            V.add(x);
306        }
307        if (it.hasNext() || jt.hasNext()) {
308            logger.error("vectorCombineOld wrong sizes: it = {}, jt = {}", it, jt);
309            //throw new RuntimeException("it = " + it + ", jt = " + jt);
310        }
311        V.add(null);
312        //System.out.println("vectorCombineOld" + V);
313        return V;
314    }
315
316
317    /**
318     * Generation of a vector of ring elements.
319     * @param n length of vector.
320     * @param a a ring element to fill vector entries.
321     * @return V, a vector of length n and entries a.
322     */
323    public List<C> genVector(int n, C a) {
324        List<C> V = new ArrayList<C>(n);
325        if (n == 0) {
326            return V;
327        }
328        for (int i = 0; i < n; i++) {
329            V.add(a);
330        }
331        return V;
332    }
333
334
335    /**
336     * Generation of a vector of ring elements.
337     * @param n length of vector.
338     * @param a a ring element to fill vector entries.
339     * @param A vector of starting first entries.
340     * @return V, a vector of length n and entries a, respectively A.
341     */
342    public List<C> genVector(int n, C a, List<C> A) {
343        List<C> V = new ArrayList<C>(n);
344        if (n == 0) {
345            return V;
346        }
347        int i = 0;
348        for (C b : A) {
349            if (i < n) {
350                V.add(b);
351            } else {
352                break;
353            }
354            i++;
355        }
356        for (int j = A.size(); j < n; j++) {
357            V.add(a);
358        }
359        return V;
360    }
361
362
363    /**
364     * Test vector of zero ring elements.
365     * @param a a ring element list.
366     * @return true, if all polynomial in a are zero, else false.
367     */
368    public boolean isZero(List<C> a) {
369        if (a == null) {
370            return true;
371        }
372        for (C pi : a) {
373            if (pi == null) {
374                continue;
375            }
376            if (!pi.isZERO()) {
377                return false;
378            }
379        }
380        return true;
381    }
382
383
384    /**
385     * Scalar product of ring element with vector of ring elements.
386     * @param p a ring element.
387     * @param F a ring element list.
388     * @return the scalar product of p and F.
389     */
390    public List<C> scalarProduct(C p, List<C> F) {
391        List<C> V = new ArrayList<C>(F.size());
392        for (C pi : F) {
393            if (p != null) {
394                pi = p.multiply(pi);
395            } else {
396                pi = null;
397            }
398            V.add(pi);
399        }
400        return V;
401    }
402
403
404    /**
405     * Scalar product of vector of ring element with ring element.
406     * @param F a ring element list.
407     * @param p a ring element.
408     * @return the scalar product of F and p.
409     */
410    public List<C> scalarProduct(List<C> F, C p) {
411        List<C> V = new ArrayList<C>(F.size());
412        for (C pi : F) {
413            if (pi != null) {
414                pi = pi.multiply(p);
415            }
416            V.add(pi);
417        }
418        return V;
419    }
420
421
422    /**
423     * Product of a vector and a matrix of ring elements.
424     * @param G a vectors of ring elements.
425     * @param F a matrix of ring element lists.
426     * @return the left product of G and F.
427     */
428    public GenVector<C> leftProduct(GenVector<C> G, GenMatrix<C> F) {
429        ArrayList<C> sp = new ArrayList<C>(G.val.size());
430        Iterator<ArrayList<C>> jt = F.matrix.iterator();
431        while (jt.hasNext()) {
432            ArrayList<C> pj = jt.next();
433            if (pj == null) {
434                continue;
435            }
436            C s = scalarProduct(G.val, pj);
437            sp.add(s);
438        }
439        return new GenVector<C>(G.modul, sp);
440    }
441
442
443    /**
444     * Product of a vector and a matrix of ring elements.
445     * @param G a vector of element list.
446     * @param F a matrix of ring element lists.
447     * @return the right product of G and F.
448     */
449    public GenVector<C> rightProduct(GenVector<C> G, GenMatrix<C> F) {
450        ArrayList<C> sp = new ArrayList<C>(G.val.size());
451        Iterator<ArrayList<C>> jt = F.matrix.iterator();
452        while (jt.hasNext()) {
453            ArrayList<C> pj = jt.next();
454            if (pj == null) {
455                continue;
456            }
457            C s = scalarProduct(pj, G.val);
458            sp.add(s);
459        }
460        return new GenVector<C>(G.modul, sp);
461    }
462
463}