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