예제 #1
0
 /** Constructor. */
 @SuppressWarnings("unchecked")
 public SquarefreeFieldCharP(RingFactory<C> fac) {
   super(GCDFactory.<C>getProxy(fac));
   if (!fac.isField()) {
     // throw new IllegalArgumentException("fac must be a field");
     logger.warn("fac should be a field: " + fac.toScript());
   }
   if (fac.characteristic().signum() == 0) {
     throw new IllegalArgumentException("characterisic(fac) must be non-zero");
   }
   coFac = fac;
   Object oFac = coFac;
   if (oFac instanceof AlgebraicNumberRing) {
     aCoFac = (AlgebraicNumberRing<C>) oFac; // <C> is not correct
     // rengine = (SquarefreeAbstract) SquarefreeFactory.getImplementation(aCoFac.ring);
     qCoFac = null;
   } else {
     aCoFac = null;
     if (oFac instanceof QuotientRing) {
       qCoFac = (QuotientRing<C>) oFac; // <C> is not correct
       // rengine = (SquarefreeAbstract) SquarefreeFactory.getImplementation(qCoFac.ring);
     } else {
       qCoFac = null;
       // rengine = null; //(SquarefreeAbstract) SquarefreeFactory.getImplementation(oFac);
     }
   }
 }
  /** Test matrix conversions. */
  public void testMatrixConversion() {
    RingFactory<BigRational> z = new BigRational(0);
    JLAdapterFactory<BigRational> fac = new JLAdapterFactory<BigRational>(z);

    JLAdapter<BigRational>[][] vec1 = fac.getArray(ll, ll);
    // System.out.println("vec1   =" + matrixToString(vec1));

    RingElem<BigRational>[][] v1 = JLAdapterUtil.<BigRational>fromJLAdapter(vec1);
    // System.out.println("v1     =" + matrixToString(v1));

    JLAdapter<BigRational>[][] vec2 = JLAdapterUtil.<BigRational>toJLAdapterRE(v1);
    // System.out.println("vec2   =" + matrixToString(vec2));

    assertMatrixEquals(vec1, vec2);

    BigRational[][] v2 = new BigRational[ll][];
    for (int i = 0; i < v2.length; i++) {
      v2[i] = new BigRational[ll];
      for (int j = 0; j < v2.length; j++) {
        v2[i][j] = z.random(kl);
      }
    }
    // System.out.println("v2     =" + matrixToString(v2));

    JLAdapter<BigRational>[][] vec3 = JLAdapterUtil.<BigRational>toJLAdapter(v2);
    // System.out.println("vec1   =" + matrixToString(vec3));

    RingElem<BigRational>[][] v3 = JLAdapterUtil.<BigRational>fromJLAdapter(vec3);
    // System.out.println("v3     =" + matrixToString(v3));

    // v3[0][0] = v3[1][1];
    assertMatrixEquals(v2, v3);
  }
예제 #3
0
  /**
   * Invariant interval for algebraic number magnitude.
   *
   * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0.
   * @param f univariate polynomial, non-zero.
   * @param g univariate polynomial, gcd(f,g) == 1.
   * @param eps length limit for interval length.
   * @return v with v a new interval contained in iv such that |g(a) - g(b)| &lt; eps for a, b in v
   *     in iv.
   */
  public Interval<C> invariantMagnitudeInterval(
      Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g, C eps) {
    Interval<C> v = iv;
    if (g == null || g.isZERO()) {
      return v;
    }
    if (g.isConstant()) {
      return v;
    }
    if (f == null || f.isZERO() || f.isConstant()) { // ?
      return v;
    }
    GenPolynomial<C> gp = PolyUtil.<C>baseDeriviative(g);
    // System.out.println("g  = " + g);
    // System.out.println("gp = " + gp);
    C B = magnitudeBound(iv, gp);
    // System.out.println("B = " + B);

    RingFactory<C> cfac = f.ring.coFac;
    C two = cfac.fromInteger(2);

    while (B.multiply(v.length()).compareTo(eps) >= 0) {
      C c = v.left.sum(v.right);
      c = c.divide(two);
      Interval<C> im = new Interval<C>(c, v.right);
      if (signChange(im, f)) {
        v = im;
      } else {
        v = new Interval<C>(v.left, c);
      }
      // System.out.println("v = " + v.toDecimal());
    }
    return v;
  }
예제 #4
0
 /**
  * Get the String representation as RingFactory.
  *
  * @see java.lang.Object#toString()
  */
 @Override
 public String toString() {
   if (nCopies != 0) {
     String cf = ring.toString();
     if (cf.matches("[0-9].*")) {
       cf = ring.getClass().getSimpleName();
     }
     return "ProductRing[ " + cf + "^" + nCopies + " ]";
   } else {
     StringBuffer sb = new StringBuffer("ProductRing[ ");
     int i = 0;
     for (RingFactory<C> f : ringList) {
       if (i != 0) {
         sb.append(", ");
       }
       String cf = f.toString();
       if (cf.matches("[0-9].*")) {
         cf = f.getClass().getSimpleName();
       }
       sb.append(cf);
       i++;
     }
     sb.append(" ]");
     return sb.toString();
   }
 }
예제 #5
0
 /**
  * Product random.
  *
  * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
  * @param q density of nozero entries.
  * @param rnd is a source for random bits.
  * @return a random product element v.
  */
 public Product<C> random(int n, float q, Random rnd) {
   SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
   float d;
   if (nCopies != 0) {
     for (int i = 0; i < nCopies; i++) {
       d = rnd.nextFloat();
       if (d < q) {
         C r = ring.random(n, rnd);
         if (!r.isZERO()) {
           elem.put(i, r);
         }
       }
     }
   } else {
     int i = 0;
     for (RingFactory<C> f : ringList) {
       d = rnd.nextFloat();
       if (d < q) {
         C r = f.random(n, rnd);
         if (!r.isZERO()) {
           elem.put(i, r);
         }
       }
       i++;
     }
   }
   return new Product<C>(this, elem);
 }
예제 #6
0
 /**
  * Comparison with any other object.
  *
  * @see java.lang.Object#equals(java.lang.Object)
  */
 @Override
 @SuppressWarnings("unchecked")
 public boolean equals(Object b) {
   if (!(b instanceof ProductRing)) {
     return false;
   }
   ProductRing<C> a = null;
   try {
     a = (ProductRing<C>) b;
   } catch (ClassCastException e) {
   }
   if (a == null) {
     return false;
   }
   if (nCopies != 0) {
     if (nCopies != a.nCopies || !ring.equals(a.ring)) {
       return false;
     }
   } else {
     if (ringList.size() != a.ringList.size()) {
       return false;
     }
     int i = 0;
     for (RingFactory<C> f : ringList) {
       if (!f.equals(a.ringList.get(i))) {
         return false;
       }
       i++;
     }
   }
   return true;
 }
예제 #7
0
 /**
  * Real root bound. With f(M) * f(-M) != 0.
  *
  * @param f univariate polynomial.
  * @return M such that -M &lt; root(f) &lt; M.
  */
 public C realRootBound(GenPolynomial<C> f) {
   if (f == null) {
     return null;
   }
   RingFactory<C> cfac = f.ring.coFac;
   C M = cfac.getONE();
   if (f.isZERO() || f.isConstant()) {
     return M;
   }
   C a = f.leadingBaseCoefficient().abs();
   for (C c : f.getMap().values()) {
     C d = c.abs().divide(a);
     if (M.compareTo(d) < 0) {
       M = d;
     }
   }
   // works also without this case, only for optimization
   // to use rational number interval end points
   // can fail if real root is in interval [r,r+1]
   // for too low precision or too big r, since r is approximation
   if ((Object) M instanceof RealAlgebraicNumber) {
     RealAlgebraicNumber Mr = (RealAlgebraicNumber) M;
     BigRational r = Mr.magnitude();
     M = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator()));
   }
   M = M.sum(f.ring.coFac.getONE());
   // System.out.println("M = " + M);
   return M;
 }
예제 #8
0
 /**
  * Parse interval for a real root from String.
  *
  * @param s String, syntax: [left, right] or [mid].
  * @return Interval from s.
  */
 public static <C extends RingElem<C> & Rational> Interval<C> parseInterval(
     RingFactory<C> fac, String s) {
   int r = s.length();
   int el = s.indexOf("[");
   if (el >= 0) {
     int ri = s.indexOf("]");
     if (ri > 0) {
       r = ri;
     }
   } else {
     el = -1;
   }
   // System.out.println("s  = " + s);
   String iv = s.substring(el + 1, r).trim();
   // System.out.println("iv = " + iv);
   int k = iv.indexOf(",");
   if (k < 0) {
     k = s.indexOf(" ");
   }
   if (k < 0) {
     C mid = fac.parse(iv);
     return new Interval<C>(mid);
   }
   // System.out.println("k  = " + k + ", len = " + iv.length());
   String ls = iv.substring(0, k).trim();
   String rs = iv.substring(k + 1, iv.length()).trim();
   // System.out.println("ls = " + ls + ", rs = " + rs);
   C left = fac.parse(ls);
   C right = fac.parse(rs);
   if (debug) {
     logger.debug("Interval: left = " + left + ", right = " + right);
   }
   return new Interval<C>(left, right);
 }
  /** Test vector conversions. */
  public void testVectorConversion() {
    RingFactory<BigRational> z = new BigRational(0);
    JLAdapterFactory<BigRational> fac = new JLAdapterFactory<BigRational>(z);

    JLAdapter<BigRational>[] vec1 = fac.getArray(ll);
    // System.out.println("vec1 =" + Arrays.toString(vec1));

    RingElem<BigRational>[] v1 = JLAdapterUtil.<BigRational>fromJLAdapter(vec1);
    // System.out.println("v1   =" + Arrays.toString(v1));

    JLAdapter<BigRational>[] vec2 = JLAdapterUtil.<BigRational>toJLAdapterRE(v1);
    // System.out.println("vec2 =" + Arrays.toString(vec2));

    assertTrue("v1[] == v2[] ", Arrays.equals(vec1, vec2));

    BigRational[] v2 = new BigRational[ll];
    for (int i = 0; i < v2.length; i++) {
      v2[i] = z.random(kl);
    }
    // System.out.println("v2   =" + Arrays.toString(v2));

    JLAdapter<BigRational>[] vec3 = JLAdapterUtil.<BigRational>toJLAdapter(v2);
    // System.out.println("vec3 =" + Arrays.toString(vec3));

    RingElem<BigRational>[] v3 = JLAdapterUtil.<BigRational>fromJLAdapter(vec3);
    // System.out.println("v3   =" + Arrays.toString(v3));

    assertTrue("v2[] == v3[] ", Arrays.equals(v2, v3));
  }
예제 #10
0
 /**
  * Refine interval.
  *
  * @param iv root isolating interval with f(left) * f(right) &lt; 0.
  * @param f univariate polynomial, non-zero.
  * @param eps requested interval length.
  * @return a new interval v such that |v| &lt; eps.
  */
 public Interval<C> refineInterval(Interval<C> iv, GenPolynomial<C> f, C eps) {
   if (f == null || f.isZERO() || f.isConstant() || eps == null) {
     return iv;
   }
   if (iv.length().compareTo(eps) < 0) {
     return iv;
   }
   RingFactory<C> cfac = f.ring.coFac;
   C two = cfac.fromInteger(2);
   Interval<C> v = iv;
   while (v.length().compareTo(eps) >= 0) {
     C c = v.left.sum(v.right);
     c = c.divide(two);
     // System.out.println("c = " + c);
     // c = RootUtil.<C>bisectionPoint(v,f);
     if (PolyUtil.<C>evaluateMain(cfac, f, c).isZERO()) {
       v = new Interval<C>(c, c);
       break;
     }
     Interval<C> iv1 = new Interval<C>(v.left, c);
     if (signChange(iv1, f)) {
       v = iv1;
     } else {
       v = new Interval<C>(c, v.right);
     }
   }
   return v;
 }
예제 #11
0
 /**
  * Bi-section point.
  *
  * @param iv interval with f(left) * f(right) != 0.
  * @param f univariate polynomial, non-zero.
  * @return a point c in the interval iv such that f(c) != 0.
  */
 public C bisectionPoint(Interval<C> iv, GenPolynomial<C> f) {
   if (f == null) {
     return null;
   }
   RingFactory<C> cfac = f.ring.coFac;
   C two = cfac.fromInteger(2);
   C c = iv.left.sum(iv.right);
   c = c.divide(two);
   if (f.isZERO() || f.isConstant()) {
     return c;
   }
   C m = PolyUtil.<C>evaluateMain(cfac, f, c);
   while (m.isZERO()) {
     C d = iv.left.sum(c);
     d = d.divide(two);
     if (d.equals(c)) {
       d = iv.right.sum(c);
       d = d.divide(two);
       if (d.equals(c)) {
         throw new RuntimeException("should not happen " + iv);
       }
     }
     c = d;
     m = PolyUtil.<C>evaluateMain(cfac, f, c);
     // System.out.println("c = " + c);
   }
   // System.out.println("c = " + c);
   return c;
 }
예제 #12
0
 /**
  * Coefficient squarefree factorization.
  *
  * @param coeff coefficient.
  * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k} p_i^{e_i} and p_i
  *     squarefree.
  */
 @Override
 public SortedMap<C, Long> squarefreeFactors(C coeff) {
   if (coeff == null) {
     return null;
   }
   SortedMap<C, Long> factors = new TreeMap<C, Long>();
   RingFactory<C> cfac = (RingFactory<C>) coeff.factory();
   if (aCoFac != null) {
     AlgebraicNumber<C> an = (AlgebraicNumber<C>) (Object) coeff;
     if (cfac.isFinite()) {
       SquarefreeFiniteFieldCharP<C> reng =
           (SquarefreeFiniteFieldCharP) SquarefreeFactory.getImplementation(cfac);
       SortedMap<C, Long> rfactors = reng.rootCharacteristic(coeff); // ??
       logger.info("rfactors,finite = " + rfactors);
       factors.putAll(rfactors);
       // return factors;
     } else {
       SquarefreeInfiniteAlgebraicFieldCharP<C> reng =
           (SquarefreeInfiniteAlgebraicFieldCharP) SquarefreeFactory.getImplementation(cfac);
       SortedMap<AlgebraicNumber<C>, Long> rfactors = reng.squarefreeFactors(an);
       logger.info("rfactors,infinite,algeb = " + rfactors);
       for (Map.Entry<AlgebraicNumber<C>, Long> me : rfactors.entrySet()) {
         AlgebraicNumber<C> c = me.getKey();
         if (!c.isONE()) {
           C cr = (C) (Object) c;
           Long rk = me.getValue(); // rfactors.get(c);
           factors.put(cr, rk);
         }
       }
     }
   } else if (qCoFac != null) {
     Quotient<C> q = (Quotient<C>) (Object) coeff;
     SquarefreeInfiniteFieldCharP<C> reng =
         (SquarefreeInfiniteFieldCharP) SquarefreeFactory.getImplementation(cfac);
     SortedMap<Quotient<C>, Long> rfactors = reng.squarefreeFactors(q);
     logger.info("rfactors,infinite = " + rfactors);
     for (Map.Entry<Quotient<C>, Long> me : rfactors.entrySet()) {
       Quotient<C> c = me.getKey();
       if (!c.isONE()) {
         C cr = (C) (Object) c;
         Long rk = me.getValue(); // rfactors.get(c);
         factors.put(cr, rk);
       }
     }
   } else if (cfac.isFinite()) {
     SquarefreeFiniteFieldCharP<C> reng =
         (SquarefreeFiniteFieldCharP) SquarefreeFactory.getImplementation(cfac);
     SortedMap<C, Long> rfactors = reng.rootCharacteristic(coeff); // ??
     logger.info("rfactors,finite = " + rfactors);
     factors.putAll(rfactors);
     // return factors;
   } else {
     logger.warn("case " + cfac + " not implemented");
   }
   return factors;
 }
예제 #13
0
 /**
  * Real algebraic number magnitude.
  *
  * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0, with iv such that
  *     |g(a) - g(b)| &lt; eps for a, b in iv.
  * @param f univariate polynomial, non-zero.
  * @param g univariate polynomial, gcd(f,g) == 1.
  * @param eps length limit for interval length.
  * @return g(iv) .
  */
 public C realIntervalMagnitude(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g, C eps) {
   if (g.isZERO() || g.isConstant()) {
     return g.leadingBaseCoefficient();
   }
   RingFactory<C> cfac = g.ring.coFac;
   C c = iv.left.sum(iv.right);
   c = c.divide(cfac.fromInteger(2));
   C ev = PolyUtil.<C>evaluateMain(cfac, g, c);
   // System.out.println("ev = " + ev);
   return ev;
 }
예제 #14
0
 /**
  * Query if this ring is associative.
  *
  * @return true if this ring is associative, else false.
  */
 public boolean isAssociative() {
   if (nCopies != 0) {
     return ring.isAssociative();
   } else {
     for (RingFactory<C> f : ringList) {
       if (!f.isAssociative()) {
         return false;
       }
     }
     return true;
   }
 }
예제 #15
0
 /**
  * Hash code for this product ring.
  *
  * @see java.lang.Object#hashCode()
  */
 @Override
 public int hashCode() {
   int h = 0;
   if (nCopies != 0) {
     h = ring.hashCode();
     h = 37 * h + nCopies;
   } else {
     for (RingFactory<C> f : ringList) {
       h = 37 * h + f.hashCode();
     }
   }
   return h;
 }
예제 #16
0
 /**
  * Get an atomic element.
  *
  * @param i index.
  * @return e_i as Product.
  */
 public Product<C> getAtomic(int i) {
   if (i < 0 || i >= length()) {
     throw new RuntimeException("index out of bounds " + i);
   }
   SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
   if (nCopies != 0) {
     elem.put(i, ring.getONE());
   } else {
     RingFactory<C> f = ringList.get(i);
     elem.put(i, f.getONE());
   }
   return new Product<C>(this, elem, 1);
 }
예제 #17
0
 /**
  * Get the one element.
  *
  * @return 1 as Product.
  */
 public Product<C> getONE() {
   SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
   if (nCopies != 0) {
     for (int i = 0; i < nCopies; i++) {
       elem.put(i, ring.getONE());
     }
   } else {
     int i = 0;
     for (RingFactory<C> f : ringList) {
       elem.put(i, f.getONE());
       i++;
     }
   }
   return new Product<C>(this, elem, 1);
 }
예제 #18
0
 /**
  * Get a Product element from a BigInteger value.
  *
  * @param a BigInteger.
  * @return a Product.
  */
 public Product<C> fromInteger(java.math.BigInteger a) {
   SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
   if (nCopies != 0) {
     C c = ring.fromInteger(a);
     for (int i = 0; i < nCopies; i++) {
       elem.put(i, c);
     }
   } else {
     int i = 0;
     for (RingFactory<C> f : ringList) {
       elem.put(i, f.fromInteger(a));
       i++;
     }
   }
   return new Product<C>(this, elem);
 }
예제 #19
0
 /**
  * Real algebraic number sign.
  *
  * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0, with iv such that
  *     g(iv) != 0.
  * @param f univariate polynomial, non-zero.
  * @param g univariate polynomial, gcd(f,g) == 1.
  * @return sign(g(iv)) .
  */
 public int realIntervalSign(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) {
   if (g == null || g.isZERO()) {
     return 0;
   }
   if (f == null || f.isZERO() || f.isConstant()) {
     return g.signum();
   }
   if (g.isConstant()) {
     return g.signum();
   }
   RingFactory<C> cfac = f.ring.coFac;
   C c = iv.left.sum(iv.right);
   c = c.divide(cfac.fromInteger(2));
   C ev = PolyUtil.<C>evaluateMain(cfac, g, c);
   // System.out.println("ev = " + ev);
   return ev.signum();
 }
예제 #20
0
 /**
  * Contains a ring factory.
  *
  * @param rf ring factory.
  * @return true, if rf is contained in this, else false.
  */
 public boolean containsFactory(RingFactory<C> rf) {
   if (nCopies != 0) {
     if (ring.equals(rf)) {
       return true;
     }
     return false; // misleading
   } else {
     return ringList.contains(rf);
   }
 }
예제 #21
0
 /**
  * Characteristic of this ring.
  *
  * @return minimal characteristic of ring component.
  */
 public java.math.BigInteger characteristic() {
   if (nCopies != 0) {
     return ring.characteristic();
   } else {
     java.math.BigInteger c = null;
     java.math.BigInteger d;
     for (RingFactory<C> f : ringList) {
       if (c == null) {
         c = f.characteristic();
       } else {
         d = f.characteristic();
         if (c.compareTo(d) > 0) { // c > d
           c = d;
         }
       }
     }
     return c;
   }
 }
예제 #22
0
 /**
  * Add a ring factory.
  *
  * @param rf new ring factory.
  */
 public synchronized void addFactory(RingFactory<C> rf) {
   if (nCopies != 0) {
     if (ring.equals(rf)) {
       nCopies++;
     }
     throw new RuntimeException("wrong RingFactory: " + rf);
   } else {
     ringList.add(rf);
   }
 }
예제 #23
0
 /**
  * Query if this ring is a field.
  *
  * @return true or false.
  */
 public boolean isField() {
   if (nCopies != 0) {
     if (nCopies == 1) {
       return ring.isField();
     }
   } else {
     if (ringList.size() == 1) {
       return ringList.get(0).isField();
     }
   }
   return false;
 }
예제 #24
0
  /**
   * Magnitude bound.
   *
   * @param iv interval.
   * @param f univariate polynomial.
   * @return B such that |f(c)| &lt; B for c in iv.
   */
  public C magnitudeBound(Interval<C> iv, GenPolynomial<C> f) {
    if (f == null) {
      return null;
    }
    if (f.isZERO()) {
      return f.ring.coFac.getONE();
    }
    if (f.isConstant()) {
      return f.leadingBaseCoefficient().abs();
    }
    GenPolynomial<C> fa =
        f.map(
            new UnaryFunctor<C, C>() {

              public C eval(C a) {
                return a.abs();
              }
            });
    // System.out.println("fa = " + fa);
    C M = iv.left.abs();
    if (M.compareTo(iv.right.abs()) < 0) {
      M = iv.right.abs();
    }
    // System.out.println("M = " + M);
    RingFactory<C> cfac = f.ring.coFac;
    C B = PolyUtil.<C>evaluateMain(cfac, fa, M);
    // works also without this case, only for optimization
    // to use rational number interval end points
    // can fail if real root is in interval [r,r+1]
    // for too low precision or too big r, since r is approximation
    if ((Object) B instanceof RealAlgebraicNumber) {
      RealAlgebraicNumber Br = (RealAlgebraicNumber) B;
      BigRational r = Br.magnitude();
      B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator()));
    }
    // System.out.println("B = " + B);
    return B;
  }
예제 #25
0
 public Odds(RingFactory<C> fac) {
   this.fac = fac;
   two = fac.fromInteger(2);
   // System.out.println("two = " + two);
 }
예제 #26
0
  /**
   * GenPolynomial absolute factorization of a irreducible polynomial.
   *
   * @param P irreducible! GenPolynomial.
   * @return factors container: [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i in K(alpha)[x] for
   *     suitable alpha and p_i irreducible over L[x], where K \subset K(alpha) \subset L is an
   *     algebraically closed field over K. <b>Note:</b> K(alpha) not yet minimal.
   */
  public Factors<C> factorsAbsoluteIrreducible(GenPolynomial<C> P) {
    if (P == null) {
      throw new RuntimeException(this.getClass().getName() + " P == null");
    }
    if (P.isZERO()) {
      return new Factors<C>(P);
    }
    GenPolynomialRing<C> pfac = P.ring; // K[x]
    if (pfac.nvar <= 1) {
      return baseFactorsAbsoluteIrreducible(P);
    }
    if (!pfac.coFac.isField()) {
      throw new RuntimeException("only for field coefficients");
    }
    List<GenPolynomial<C>> factors = new ArrayList<GenPolynomial<C>>();
    if (P.degree() <= 1) {
      return new Factors<C>(P);
    }
    // find field extension K(alpha)
    GenPolynomial<C> up = P;
    RingFactory<C> cf = pfac.coFac;
    long cr = cf.characteristic().longValue(); // char might be larger
    if (cr == 0L) {
      cr = Long.MAX_VALUE;
    }
    long rp = 0L;
    for (int i = 0; i < (pfac.nvar - 1); i++) {
      rp = 0L;
      GenPolynomialRing<C> nfac = pfac.contract(1);
      String[] vn = new String[] {pfac.getVars()[pfac.nvar - 1]};
      GenPolynomialRing<GenPolynomial<C>> rfac =
          new GenPolynomialRing<GenPolynomial<C>>(nfac, 1, pfac.tord, vn);
      GenPolynomial<GenPolynomial<C>> upr = PolyUtil.<C>recursive(rfac, up);
      // System.out.println("upr = " + upr);
      GenPolynomial<C> ep;
      do {
        if (rp >= cr) {
          throw new RuntimeException("elements of prime field exhausted: " + cr);
        }
        C r = cf.fromInteger(rp); // cf.random(rp);
        // System.out.println("r   = " + r);
        ep = PolyUtil.<C>evaluateMain(nfac, upr, r);
        // System.out.println("ep  = " + ep);
        rp++;
      } while (!isSquarefree(ep) /*todo: || ep.degree() <= 1*/); // max deg
      up = ep;
      pfac = nfac;
    }
    up = up.monic();
    if (debug) {
      logger.info("P(" + rp + ") = " + up);
      // System.out.println("up  = " + up);
    }
    if (debug && !isSquarefree(up)) {
      throw new RuntimeException("not irreducible up = " + up);
    }
    if (up.degree(0) <= 1) {
      return new Factors<C>(P);
    }
    // find irreducible factor of up
    List<GenPolynomial<C>> UF = baseFactorsSquarefree(up);
    // System.out.println("UF  = " + UF);
    FactorsList<C> aUF = baseFactorsAbsoluteSquarefree(up);
    // System.out.println("aUF  = " + aUF);
    AlgebraicNumberRing<C> arfac = aUF.findExtensionField();
    // System.out.println("arfac  = " + arfac);

    long e = up.degree(0);
    // search factor polynomial with smallest degree
    for (int i = 0; i < UF.size(); i++) {
      GenPolynomial<C> upi = UF.get(i);
      long d = upi.degree(0);
      if (1 <= d && d <= e) {
        up = upi;
        e = up.degree(0);
      }
    }
    if (up.degree(0) <= 1) {
      return new Factors<C>(P);
    }
    if (debug) {
      logger.info("field extension by " + up);
    }

    List<GenPolynomial<AlgebraicNumber<C>>> afactors =
        new ArrayList<GenPolynomial<AlgebraicNumber<C>>>();

    // setup field extension K(alpha)
    // String[] vars = new String[] { "z_" + Math.abs(up.hashCode() % 1000) };
    String[] vars = pfac.newVars("z_");
    pfac = pfac.clone();
    String[] ovars = pfac.setVars(vars); // side effects!
    GenPolynomial<C> aup = pfac.copy(up); // hack to exchange the variables

    // AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(aup,true); // since irreducible
    AlgebraicNumberRing<C> afac = arfac;
    int depth = afac.depth();
    // System.out.println("afac = " + afac);
    GenPolynomialRing<AlgebraicNumber<C>> pafac =
        new GenPolynomialRing<AlgebraicNumber<C>>(afac, P.ring.nvar, P.ring.tord, P.ring.getVars());
    // System.out.println("pafac = " + pafac);
    // convert to K(alpha)
    GenPolynomial<AlgebraicNumber<C>> Pa =
        PolyUtil.<C>convertToRecAlgebraicCoefficients(depth, pafac, P);
    // System.out.println("Pa = " + Pa);
    // factor over K(alpha)
    FactorAbstract<AlgebraicNumber<C>> engine = FactorFactory.<C>getImplementation(afac);
    afactors = engine.factorsSquarefree(Pa);
    if (debug) {
      logger.info("K(alpha) factors multi = " + afactors);
      // System.out.println("K(alpha) factors = " + afactors);
    }
    if (afactors.size() <= 1) {
      return new Factors<C>(P);
    }
    // normalize first factor to monic
    GenPolynomial<AlgebraicNumber<C>> p1 = afactors.get(0);
    AlgebraicNumber<C> p1c = p1.leadingBaseCoefficient();
    if (!p1c.isONE()) {
      GenPolynomial<AlgebraicNumber<C>> p2 = afactors.get(1);
      afactors.remove(p1);
      afactors.remove(p2);
      p1 = p1.divide(p1c);
      p2 = p2.multiply(p1c);
      afactors.add(p1);
      afactors.add(p2);
    }
    // recursion for splitting field
    // find minimal field extension K(beta) \subset K(alpha)
    return new Factors<C>(P, afac, Pa, afactors);
  }