001/*
002 * $Id: SolvableGroebnerBaseSeq.java 4104 2012-08-18 10:00:59Z kredel $
003 */
004
005package edu.jas.gb;
006
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.ListIterator;
011
012import org.apache.log4j.Logger;
013
014import edu.jas.poly.ExpVector;
015import edu.jas.poly.GenPolynomial;
016import edu.jas.poly.GenSolvablePolynomial;
017import edu.jas.poly.GenSolvablePolynomialRing;
018import edu.jas.poly.PolynomialList;
019import edu.jas.structure.RingElem;
020
021
022/**
023 * Solvable Groebner bases sequential algorithms. Implements common left, right
024 * and twosided Groebner bases and left, right and twosided GB tests.
025 * @param <C> coefficient type
026 * @author Heinz Kredel.
027 */
028
029public class SolvableGroebnerBaseSeq<C extends RingElem<C>> extends SolvableGroebnerBaseAbstract<C> {
030
031
032    private static final Logger logger = Logger.getLogger(SolvableGroebnerBaseSeq.class);
033
034
035    private final boolean debug = logger.isDebugEnabled();
036
037
038    /**
039     * Constructor.
040     */
041    public SolvableGroebnerBaseSeq() {
042        super();
043    }
044
045
046    /**
047     * Constructor.
048     * @param sred Solvable reduction engine
049     * @param pl pair selection strategy
050     */
051    public SolvableGroebnerBaseSeq(SolvableReduction<C> sred, PairList<C> pl) {
052        super(sred, pl);
053    }
054
055
056    /**
057     * Left Groebner base using pairlist class.
058     * @param modv number of module variables.
059     * @param F solvable polynomial list.
060     * @return leftGB(F) a left Groebner base of F.
061     */
062    @SuppressWarnings("unchecked")
063    public List<GenSolvablePolynomial<C>> leftGB(int modv, List<GenSolvablePolynomial<C>> F) {
064        List<GenSolvablePolynomial<C>> G = new ArrayList<GenSolvablePolynomial<C>>();
065        PairList<C> pairlist = null;
066        int l = F.size();
067        //  ListIterator it = F.listIterator();
068        for (GenSolvablePolynomial<C> p : F) {
069            //  p = (SolvablePolynomial) it.next();
070            if (p.length() > 0) {
071                p = (GenSolvablePolynomial<C>) p.monic();
072                if (p.isONE()) {
073                    G.clear();
074                    G.add(p);
075                    return G; // since no threads are activated
076                }
077                G.add(p);
078                if (pairlist == null) {
079                    //pairlist = new OrderedPairlist<C>( modv, p.ring );
080                    pairlist = strategy.create(modv, p.ring);
081                }
082                // putOne not required
083                pairlist.put(p);
084            } else {
085                l--;
086            }
087        }
088        if (l <= 1) {
089            return G; // since no threads are activated
090        }
091
092        GenSolvablePolynomial<C> pi, pj, S, H;
093        Pair<C> pair;
094        while (pairlist.hasNext()) {
095            pair = pairlist.removeNext();
096            if (pair == null) {
097                continue;
098            }
099            pi = (GenSolvablePolynomial<C>) pair.pi;
100            pj = (GenSolvablePolynomial<C>) pair.pj;
101            if (debug) {
102                logger.info("pi    = " + pi);
103                logger.info("pj    = " + pj);
104            }
105
106            S = sred.leftSPolynomial(pi, pj);
107            if (S.isZERO()) {
108                pair.setZero();
109                continue;
110            }
111            if (debug) {
112                logger.info("ht(S) = " + S.leadingExpVector());
113            }
114
115            H = sred.leftNormalform(G, S);
116            if (H.isZERO()) {
117                pair.setZero();
118                continue;
119            }
120            if (debug) {
121                logger.info("ht(H) = " + H.leadingExpVector());
122            }
123
124            H = (GenSolvablePolynomial<C>) H.monic();
125            if (H.isONE()) {
126                G.clear();
127                G.add(H);
128                return G; // since no threads are activated
129            }
130            if (debug) {
131                logger.info("H = " + H);
132            }
133            if (H.length() > 0) {
134                l++;
135                G.add(H);
136                pairlist.put(H);
137            }
138        }
139        logger.debug("#sequential list = " + G.size());
140        G = leftMinimalGB(G);
141        logger.info("" + pairlist);
142        return G;
143    }
144
145
146    /**
147     * Solvable Extended Groebner base using critical pair class.
148     * @param modv module variable number.
149     * @param F solvable polynomial list.
150     * @return a container for an extended left Groebner base of F.
151     */
152    @SuppressWarnings("unchecked")
153    public SolvableExtendedGB<C> extLeftGB(int modv, List<GenSolvablePolynomial<C>> F) {
154
155        List<GenSolvablePolynomial<C>> G = new ArrayList<GenSolvablePolynomial<C>>();
156        List<List<GenSolvablePolynomial<C>>> F2G = new ArrayList<List<GenSolvablePolynomial<C>>>();
157        List<List<GenSolvablePolynomial<C>>> G2F = new ArrayList<List<GenSolvablePolynomial<C>>>();
158        PairList<C> pairlist = null;
159        boolean oneInGB = false;
160        int len = F.size();
161
162        List<GenSolvablePolynomial<C>> row = null;
163        List<GenSolvablePolynomial<C>> rows = null;
164        List<GenSolvablePolynomial<C>> rowh = null;
165        GenSolvablePolynomialRing<C> ring = null;
166        GenSolvablePolynomial<C> H;
167        GenSolvablePolynomial<C> p;
168
169        int nzlen = 0;
170        for (GenSolvablePolynomial<C> f : F) {
171            if (f.length() > 0) {
172                nzlen++;
173            }
174            if (ring == null) {
175                ring = f.ring;
176            }
177        }
178        GenSolvablePolynomial<C> mone = ring.getONE(); //.negate();
179        int k = 0;
180        ListIterator<GenSolvablePolynomial<C>> it = F.listIterator();
181        while (it.hasNext()) {
182            p = it.next();
183            if (p.length() > 0) {
184                row = new ArrayList<GenSolvablePolynomial<C>>(nzlen);
185                for (int j = 0; j < nzlen; j++) {
186                    row.add(null);
187                }
188                //C c = p.leadingBaseCoefficient();
189                //c = c.inverse();
190                //p = p.multiply( c );
191                row.set(k, mone); //.multiply(c) );
192                k++;
193                if (p.isUnit()) {
194                    G.clear();
195                    G.add(p);
196                    G2F.clear();
197                    G2F.add(row);
198                    oneInGB = true;
199                    break;
200                }
201                G.add(p);
202                G2F.add(row);
203                if (pairlist == null) {
204                    //pairlist = new CriticalPairList<C>( modv, p.ring );
205                    pairlist = strategy.create(modv, p.ring);
206                }
207                // putOne not required
208                pairlist.put(p);
209            } else {
210                len--;
211            }
212        }
213        SolvableExtendedGB<C> exgb;
214        if (len <= 1 || oneInGB) {
215            // adjust F2G
216            for (GenSolvablePolynomial<C> f : F) {
217                row = new ArrayList<GenSolvablePolynomial<C>>(G.size());
218                for (int j = 0; j < G.size(); j++) {
219                    row.add(null);
220                }
221                H = sred.leftNormalform(row, G, f);
222                if (!H.isZERO()) {
223                    logger.error("nonzero H = " + H);
224                }
225                F2G.add(row);
226            }
227            exgb = new SolvableExtendedGB<C>(F, G, F2G, G2F);
228            //System.out.println("exgb 1 = " + exgb);
229            return exgb;
230        }
231
232        Pair<C> pair;
233        int i, j;
234        GenSolvablePolynomial<C> pi;
235        GenSolvablePolynomial<C> pj;
236        GenSolvablePolynomial<C> S;
237        GenSolvablePolynomial<C> x;
238        GenSolvablePolynomial<C> y;
239        //GenPolynomial<C> z;
240        while (pairlist.hasNext() && !oneInGB) {
241            pair = pairlist.removeNext();
242            if (pair == null) {
243                //pairlist.update(); // ?
244                continue;
245            }
246            i = pair.i;
247            j = pair.j;
248            pi = (GenSolvablePolynomial<C>) pair.pi;
249            pj = (GenSolvablePolynomial<C>) pair.pj;
250            if (debug) {
251                logger.info("i, pi    = " + i + ", " + pi);
252                logger.info("j, pj    = " + j + ", " + pj);
253            }
254
255            rows = new ArrayList<GenSolvablePolynomial<C>>(G.size());
256            for (int m = 0; m < G.size(); m++) {
257                rows.add(null);
258            }
259            S = sred.leftSPolynomial(rows, i, pi, j, pj);
260            if (debug) {
261                logger.debug("is reduction S = " + sred.isLeftReductionNF(rows, G, ring.getZERO(), S));
262            }
263            if (S.isZERO()) {
264                pair.setZero();
265                //pairlist.update( pair, S );
266                // do not add to G2F
267                continue;
268            }
269            if (debug) {
270                logger.debug("ht(S) = " + S.leadingExpVector());
271            }
272
273            rowh = new ArrayList<GenSolvablePolynomial<C>>(G.size());
274            for (int m = 0; m < G.size(); m++) {
275                rowh.add(null);
276            }
277            H = sred.leftNormalform(rowh, G, S);
278            if (debug) {
279                //System.out.println("H = " + H);
280                logger.debug("is reduction H = " + sred.isLeftReductionNF(rowh, G, S, H));
281            }
282            if (H.isZERO()) {
283                pair.setZero();
284                //pairlist.update( pair, H );
285                // do not add to G2F
286                continue;
287            }
288            if (debug) {
289                logger.debug("ht(H) = " + H.leadingExpVector());
290            }
291
292            row = new ArrayList<GenSolvablePolynomial<C>>(G.size() + 1);
293            for (int m = 0; m < G.size(); m++) {
294                x = rows.get(m);
295                if (x != null) {
296                    //System.out.println("ms = " + m + " " + x);
297                    x = (GenSolvablePolynomial<C>) x.negate();
298                }
299                y = rowh.get(m);
300                if (y != null) {
301                    y = (GenSolvablePolynomial<C>) y.negate();
302                    //System.out.println("mh = " + m + " " + y);
303                }
304                if (x == null) {
305                    x = y;
306                } else {
307                    x = (GenSolvablePolynomial<C>) x.sum(y);
308                }
309                //System.out.println("mx = " + m + " " + x);
310                row.add(x);
311            }
312            if (debug) {
313                logger.debug("is reduction 0+sum(row,G) == H : "
314                                + sred.isLeftReductionNF(row, G, H, ring.getZERO()));
315            }
316            row.add(null);
317
318
319            //  H = H.monic();
320            C c = H.leadingBaseCoefficient();
321            c = c.inverse();
322            H = H.multiply(c);
323            // 1*c*row, leads to wrong method dispatch:
324            row = PolynomialList.<C> castToSolvableList(blas.scalarProduct(mone.multiply(c),
325                            PolynomialList.<C> castToList(row)));
326            row.set(G.size(), mone);
327            if (H.isONE()) {
328                // pairlist.record( pair, H );
329                // G.clear(); 
330                G.add(H);
331                G2F.add(row);
332                oneInGB = true;
333                break;
334            }
335            if (debug) {
336                logger.debug("H = " + H);
337            }
338            G.add(H);
339            //pairlist.update( pair, H );
340            pairlist.put(H);
341            G2F.add(row);
342        }
343        if (debug) {
344            exgb = new SolvableExtendedGB<C>(F, G, F2G, G2F);
345            logger.info("exgb unnorm = " + exgb);
346        }
347        G2F = normalizeMatrix(F.size(), G2F);
348        if (debug) {
349            exgb = new SolvableExtendedGB<C>(F, G, F2G, G2F);
350            logger.info("exgb nonmin = " + exgb);
351            boolean t2 = isLeftReductionMatrix(exgb);
352            logger.debug("exgb t2 = " + t2);
353        }
354        exgb = minimalSolvableExtendedGB(F.size(), G, G2F);
355        G = exgb.G;
356        G2F = exgb.G2F;
357        logger.debug("#sequential list = " + G.size());
358        logger.info("" + pairlist);
359        // setup matrices F and F2G
360        for (GenSolvablePolynomial<C> f : F) {
361            row = new ArrayList<GenSolvablePolynomial<C>>(G.size());
362            for (int m = 0; m < G.size(); m++) {
363                row.add(null);
364            }
365            H = sred.leftNormalform(row, G, f);
366            if (!H.isZERO()) {
367                logger.error("nonzero H = " + H);
368            }
369            F2G.add(row);
370        }
371        return new SolvableExtendedGB<C>(F, G, F2G, G2F);
372    }
373
374
375    /**
376     * Twosided Groebner base using pairlist class.
377     * @param modv number of module variables.
378     * @param Fp solvable polynomial list.
379     * @return tsGB(Fp) a twosided Groebner base of Fp.
380     */
381    @SuppressWarnings("unchecked")
382    public List<GenSolvablePolynomial<C>> twosidedGB(int modv, List<GenSolvablePolynomial<C>> Fp) {
383        if (Fp == null || Fp.size() == 0) { // 0 not 1
384            return new ArrayList<GenSolvablePolynomial<C>>();
385        }
386        GenSolvablePolynomialRing<C> fac = Fp.get(0).ring; // assert != null
387        //List<GenSolvablePolynomial<C>> X = generateUnivar( modv, Fp );
388        List<GenSolvablePolynomial<C>> X = fac.univariateList(modv);
389        //System.out.println("X univ = " + X);
390        List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(Fp.size() * (1 + X.size()));
391        F.addAll(Fp);
392        GenSolvablePolynomial<C> p, x, q;
393        for (int i = 0; i < Fp.size(); i++) {
394            p = Fp.get(i);
395            for (int j = 0; j < X.size(); j++) {
396                x = X.get(j);
397                q = p.multiply(x);
398                q = sred.leftNormalform(F, q);
399                if (!q.isZERO()) {
400                    F.add(q);
401                }
402            }
403        }
404        //System.out.println("F generated = " + F);
405        List<GenSolvablePolynomial<C>> G = new ArrayList<GenSolvablePolynomial<C>>();
406        PairList<C> pairlist = null;
407        int l = F.size();
408        ListIterator<GenSolvablePolynomial<C>> it = F.listIterator();
409        while (it.hasNext()) {
410            p = it.next();
411            if (p.length() > 0) {
412                p = (GenSolvablePolynomial<C>) p.monic();
413                if (p.isONE()) {
414                    G.clear();
415                    G.add(p);
416                    return G; // since no threads are activated
417                }
418                G.add(p);
419                if (pairlist == null) {
420                    // pairlist = new OrderedPairlist<C>( modv, p.ring );
421                    pairlist = strategy.create(modv, p.ring);
422                }
423                // putOne not required
424                pairlist.put(p);
425            } else {
426                l--;
427            }
428        }
429        //System.out.println("G to check = " + G);
430        if (l <= 1) { // 1 ok
431            return G; // since no threads are activated
432        }
433
434        Pair<C> pair;
435        GenSolvablePolynomial<C> pi, pj, S, H;
436        while (pairlist.hasNext()) {
437            pair = pairlist.removeNext();
438            if (pair == null) {
439                continue;
440            }
441
442            pi = (GenSolvablePolynomial<C>) pair.pi;
443            pj = (GenSolvablePolynomial<C>) pair.pj;
444            if (debug) {
445                logger.debug("pi    = " + pi);
446                logger.debug("pj    = " + pj);
447            }
448
449            S = sred.leftSPolynomial(pi, pj);
450            if (S.isZERO()) {
451                pair.setZero();
452                continue;
453            }
454            if (debug) {
455                logger.debug("ht(S) = " + S.leadingExpVector());
456            }
457
458            H = sred.leftNormalform(G, S);
459            if (H.isZERO()) {
460                pair.setZero();
461                continue;
462            }
463            if (debug) {
464                logger.debug("ht(H) = " + H.leadingExpVector());
465            }
466
467            H = (GenSolvablePolynomial<C>) H.monic();
468            if (H.isONE()) {
469                G.clear();
470                G.add(H);
471                return G; // since no threads are activated
472            }
473            if (debug) {
474                logger.debug("H = " + H);
475            }
476            if (H.length() > 0) {
477                l++;
478                G.add(H);
479                pairlist.put(H);
480                for (int j = 0; j < X.size(); j++) {
481                    l++;
482                    x = X.get(j);
483                    p = H.multiply(x);
484                    p = sred.leftNormalform(G, p);
485                    if (!p.isZERO()) {
486                        p = (GenSolvablePolynomial<C>) p.monic();
487                        if (p.isONE()) {
488                            G.clear();
489                            G.add(p);
490                            return G; // since no threads are activated
491                        }
492                        G.add(p);
493                        pairlist.put(p);
494                    }
495                }
496            }
497        }
498        logger.debug("#sequential list = " + G.size());
499        G = leftMinimalGB(G);
500        logger.info("" + pairlist);
501        return G;
502    }
503
504
505    /**
506     * Normalize M. Make all rows the same size and make certain column elements
507     * zero.
508     * @param M a reduction matrix.
509     * @return normalized M.
510     */
511    public List<List<GenSolvablePolynomial<C>>> normalizeMatrix(int flen,
512                    List<List<GenSolvablePolynomial<C>>> M) {
513        if (M == null) {
514            return M;
515        }
516        if (M.size() == 0) {
517            return M;
518        }
519        List<List<GenSolvablePolynomial<C>>> N = new ArrayList<List<GenSolvablePolynomial<C>>>();
520        List<List<GenSolvablePolynomial<C>>> K = new ArrayList<List<GenSolvablePolynomial<C>>>();
521        int len = M.get(M.size() - 1).size(); // longest row
522        // pad / extend rows
523        for (List<GenSolvablePolynomial<C>> row : M) {
524            List<GenSolvablePolynomial<C>> nrow = new ArrayList<GenSolvablePolynomial<C>>(row);
525            for (int i = row.size(); i < len; i++) {
526                nrow.add(null);
527            }
528            N.add(nrow);
529        }
530        // System.out.println("norm N fill = " + N);
531        // make zero columns
532        int k = flen;
533        for (int i = 0; i < N.size(); i++) { // 0
534            List<GenSolvablePolynomial<C>> row = N.get(i);
535            if (debug) {
536                logger.info("row = " + row);
537            }
538            K.add(row);
539            if (i < flen) { // skip identity part
540                continue;
541            }
542            List<GenSolvablePolynomial<C>> xrow;
543            GenSolvablePolynomial<C> a;
544            //System.out.println("norm i = " + i);
545            for (int j = i + 1; j < N.size(); j++) {
546                List<GenSolvablePolynomial<C>> nrow = N.get(j);
547                //System.out.println("nrow j = " +j + ", " + nrow);
548                if (k < nrow.size()) { // always true
549                    a = nrow.get(k);
550                    //System.out.println("k, a = " + k + ", " + a);
551                    if (a != null && !a.isZERO()) { // a*row + nrow, leads to wrong method dispatch
552                        List<GenPolynomial<C>> yrow = blas.scalarProduct(a,
553                                        PolynomialList.<C> castToList(row));
554                        yrow = blas.vectorAdd(yrow, PolynomialList.<C> castToList(nrow));
555                        xrow = PolynomialList.<C> castToSolvableList(yrow);
556                        N.set(j, xrow);
557                    }
558                }
559            }
560            k++;
561        }
562        //System.out.println("norm K reduc = " + K);
563        // truncate 
564        N.clear();
565        for (List<GenSolvablePolynomial<C>> row : K) {
566            List<GenSolvablePolynomial<C>> tr = new ArrayList<GenSolvablePolynomial<C>>();
567            for (int i = 0; i < flen; i++) {
568                tr.add(row.get(i));
569            }
570            N.add(tr);
571        }
572        K = N;
573        //System.out.println("norm K trunc = " + K);
574        return K;
575    }
576
577
578    /**
579     * Test if M is a left reduction matrix.
580     * @param exgb an SolvableExtendedGB container.
581     * @return true, if exgb contains a left reduction matrix, else false.
582     */
583    @Override
584    public boolean isLeftReductionMatrix(SolvableExtendedGB<C> exgb) {
585        if (exgb == null) {
586            return true;
587        }
588        return isLeftReductionMatrix(exgb.F, exgb.G, exgb.F2G, exgb.G2F);
589    }
590
591
592    /**
593     * Minimal solvable extended groebner basis.
594     * @param Gp a left Groebner base.
595     * @param M a left reduction matrix, is modified.
596     * @return a (partially) reduced left Groebner base of Gp in a container.
597     */
598    public SolvableExtendedGB<C> minimalSolvableExtendedGB(int flen, List<GenSolvablePolynomial<C>> Gp,
599                    List<List<GenSolvablePolynomial<C>>> M) {
600        if (Gp == null) {
601            return null; //new SolvableExtendedGB<C>(null,Gp,null,M);
602        }
603        if (Gp.size() <= 1) {
604            return new SolvableExtendedGB<C>(null, Gp, null, M);
605        }
606        List<GenSolvablePolynomial<C>> G;
607        List<GenSolvablePolynomial<C>> F;
608        G = new ArrayList<GenSolvablePolynomial<C>>(Gp);
609        F = new ArrayList<GenSolvablePolynomial<C>>(Gp.size());
610
611        List<List<GenSolvablePolynomial<C>>> Mg;
612        List<List<GenSolvablePolynomial<C>>> Mf;
613        Mg = new ArrayList<List<GenSolvablePolynomial<C>>>(M.size());
614        Mf = new ArrayList<List<GenSolvablePolynomial<C>>>(M.size());
615        List<GenSolvablePolynomial<C>> row;
616        for (List<GenSolvablePolynomial<C>> r : M) {
617            // must be copied also
618            row = new ArrayList<GenSolvablePolynomial<C>>(r);
619            Mg.add(row);
620        }
621        row = null;
622
623        GenSolvablePolynomial<C> a;
624        ExpVector e;
625        ExpVector f;
626        GenSolvablePolynomial<C> p;
627        boolean mt;
628        ListIterator<GenSolvablePolynomial<C>> it;
629        ArrayList<Integer> ix = new ArrayList<Integer>();
630        ArrayList<Integer> jx = new ArrayList<Integer>();
631        int k = 0;
632        //System.out.println("flen, Gp, M = " + flen + ", " + Gp.size() + ", " + M.size() );
633        while (G.size() > 0) {
634            a = G.remove(0);
635            e = a.leadingExpVector();
636
637            it = G.listIterator();
638            mt = false;
639            while (it.hasNext() && !mt) {
640                p = it.next();
641                f = p.leadingExpVector();
642                mt = e.multipleOf(f);
643            }
644            it = F.listIterator();
645            while (it.hasNext() && !mt) {
646                p = it.next();
647                f = p.leadingExpVector();
648                mt = e.multipleOf(f);
649            }
650            //System.out.println("k, mt = " + k + ", " + mt);
651            if (!mt) {
652                F.add(a);
653                ix.add(k);
654            } else { // drop polynomial and corresponding row and column
655                // F.add( a.ring.getZERO() );
656                jx.add(k);
657            }
658            k++;
659        }
660        if (debug) {
661            logger.debug("ix, #M, jx = " + ix + ", " + Mg.size() + ", " + jx);
662        }
663        int fix = -1; // copied polys
664        // copy Mg to Mf as indicated by ix
665        for (int i = 0; i < ix.size(); i++) {
666            int u = ix.get(i);
667            if (u >= flen && fix == -1) {
668                fix = Mf.size();
669            }
670            //System.out.println("copy u, fix = " + u + ", " + fix);
671            if (u >= 0) {
672                row = Mg.get(u);
673                Mf.add(row);
674            }
675        }
676        if (F.size() <= 1 || fix == -1) {
677            return new SolvableExtendedGB<C>(null, F, null, Mf);
678        }
679        // must return, since extended normalform has not correct order of polys
680        /*
681        G = F;
682        F = new ArrayList<GenSolvablePolynomial<C>>( G.size() );
683        List<GenSolvablePolynomial<C>> temp;
684        k = 0;
685        final int len = G.size();
686        while ( G.size() > 0 ) {
687            a = G.remove(0);
688            if ( k >= fix ) { // dont touch copied polys
689               row = Mf.get( k );
690               //System.out.println("doing k = " + k + ", " + a);
691               // must keep order, but removed polys missing
692               temp = new ArrayList<GenPolynomial<C>>( len );
693               temp.addAll( F );
694               temp.add( a.ring.getZERO() ); // ??
695               temp.addAll( G );
696               //System.out.println("row before = " + row);
697               a = sred.leftNormalform( row, temp, a );
698               //System.out.println("row after  = " + row);
699            }
700            F.add( a );
701            k++;
702        }
703        // does Mf need renormalization?
704        */
705        return new SolvableExtendedGB<C>(null, F, null, Mf);
706    }
707
708}