001/*
002 * $Id$
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.SortedMap;
011import java.util.TreeMap;
012import java.util.Map;
013
014import org.apache.logging.log4j.Logger;
015import org.apache.logging.log4j.LogManager; 
016
017import edu.jas.poly.GenPolynomial;
018import edu.jas.poly.GenPolynomialRing;
019import edu.jas.structure.GcdRingElem;
020import edu.jas.structure.RingElem;
021import edu.jas.structure.RingFactory;
022import edu.jas.structure.QuotPair;
023import edu.jas.structure.QuotPairFactory;
024
025
026/**
027 * Fraction factorization algorithms. This class implements
028 * factorization methods for fractions represended as pairs of
029 * polynomials.
030 * @author Heinz Kredel
031 */
032
033public class FactorFraction<C extends GcdRingElem<C>, 
034                                      D extends GcdRingElem<D> & QuotPair<GenPolynomial<C>> > {
035
036
037    private static final Logger logger = LogManager.getLogger(FactorFraction.class);
038
039
040    /**
041     * Quotient pairs ring factory.
042     * D == QuotPair&lt;GenPolynomial&lt;C&gt;&gt; must hold.
043     */
044    protected final QuotPairFactory<GenPolynomial<C>, D> qfac;
045
046
047    /**
048     * Factorization engine for normal coefficients.
049     */
050    protected final FactorAbstract<C> nengine;
051
052
053    /**
054     * No argument constructor.
055     */
056    protected FactorFraction() {
057        throw new IllegalArgumentException("don't use this constructor");
058    }
059
060
061    /**
062     * Constructor.
063     * @param fac coefficient quotient ring factory.
064     */
065    public FactorFraction(QuotPairFactory<GenPolynomial<C>,D> fac) {
066        this(fac, FactorFactory.<C> getImplementation(((GenPolynomialRing<C>) fac.pairFactory()).coFac));
067    }
068
069
070    /**
071     * Constructor.
072     * @param fac coefficient quotient ring factory.
073     * @param nengine factorization engine for polynomials over base
074     *            coefficients.
075     */
076    public FactorFraction(QuotPairFactory<GenPolynomial<C>,D> fac, FactorAbstract<C> nengine) {
077        this.qfac = fac;
078        this.nengine = nengine;
079        logger.info("qfac.fac: {}", qfac.pairFactory()); //.toScript()
080    }
081
082
083    /**
084     * Get the String representation.
085     * @see java.lang.Object#toString()
086     */
087    @Override
088    public String toString() {
089        return getClass().getName();
090    }
091
092
093    /**
094     * Test if a quotient pair is irreducible.
095     * @param P quotient pair (num,den), with gcd(num,den) == 1.
096     * @return true if P is irreducible, else false.
097     */
098    public boolean isIrreducible(D P) {
099        SortedMap<D, Long> F = factors(P);
100        for (Long e : F.values()) {
101            if (e == null || e != 1L) {
102                return false;
103            }
104        }
105        if (F.size() <= 1) { // x/1
106            return true;
107        } else if (F.size() == 2) { // x/1, 1/y
108            List<D> pp = new ArrayList<D>( F.keySet() );
109            D f = pp.get(0);
110            D g = pp.get(1);
111            if ((f.numerator().isONE() && g.denominator().isONE()) || (g.numerator().isONE() && f.denominator().isONE())) {
112                return true;
113            }
114            return false;
115        } else if (F.size() > 2) {
116            return false;
117        }
118        return false;
119    }
120
121
122    /**
123     * Test if a non trivial factorization exists.
124     * @param P quotient pair (num,den), with gcd(num,den) == 1.
125     * @return true if P is reducible, else false.
126     */
127    public boolean isReducible(D P) {
128        return !isIrreducible(P);
129    }
130
131
132    /**
133     * Quotient pair factorization.
134     * @param P quotient pair (num,den), with gcd(num,den) == 1.
135     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k} p_i**e_i.
136     */
137    public SortedMap<D, Long> factors(D P) {
138        // D == QuotPair<GenPolynomial<C>>
139        SortedMap<D, Long> facs = new TreeMap<D, Long>();
140        if (P == null) {
141            return facs;
142        }
143        GenPolynomial<C> n = P.numerator();
144        GenPolynomial<C> d = P.denominator();
145        if (n.isZERO() || d.isZERO()) {
146            return facs;
147        }
148        if (n.isONE() && d.isONE()) {
149            facs.put(P,1L);
150            return facs;
151        }
152        // assert gcd(n,d) == 1
153        GenPolynomial<C> one = qfac.pairFactory().getONE();
154        if (!n.isONE()) {
155            SortedMap<GenPolynomial<C>, Long> nfacs = nengine.factors(n);
156            for (Map.Entry<GenPolynomial<C>,Long> m : nfacs.entrySet()) {
157                 D q = qfac.create(m.getKey(), one);
158                 facs.put(q, m.getValue());
159            }
160        }
161        if (!d.isONE()) {
162            SortedMap<GenPolynomial<C>, Long> dfacs = nengine.factors(d);
163            for (Map.Entry<GenPolynomial<C>,Long> m : dfacs.entrySet()) {
164                 D q = qfac.create(one, m.getKey());
165                 facs.put(q, m.getValue());
166            }
167        }
168        return facs;
169    }
170
171
172    /**
173     * Test quotient pair factorization.
174     * @param P quotient pair.
175     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
176     * @return true if P = prod_{i=1,...,k} p_i**e_i, else false.
177     */
178    public boolean isFactorization(D P, SortedMap<D, Long> F) {
179        if (P == null || F == null) {
180            throw new IllegalArgumentException("P and F may not be null");
181        }
182        if (P.isZERO() && F.size() == 0) {
183            return true;
184        }
185        D t = null; //P.ring.getONE();
186        for (Map.Entry<D, Long> me : F.entrySet()) {
187            D f = me.getKey();
188            Long E = me.getValue(); 
189            long e = E.longValue();
190            D g = f.power(e); 
191            if (t == null) {
192                t = g;
193            } else {
194                t = t.multiply(g);
195            }
196        }
197        boolean f = P.equals(t) || P.equals(t.negate());
198        if (!f) {
199            System.out.println("\nfactorization(map): " + f);
200            System.out.println("F = " + F);
201            System.out.println("P = " + P);
202            System.out.println("t = " + t);
203            //RuntimeException e = new RuntimeException("fac-map");
204            //e.printStackTrace();
205            //throw e;
206        }
207        return f;
208    }
209
210}