Index: libpolys/polys/ext_fields/transext.cc
===================================================================
--- libpolys/polys/ext_fields/transext.cc	(revision 2d3091c7bb239cd4787574560ab475ac88621da7)
+++ libpolys/polys/ext_fields/transext.cc	(revision 06df101aca2a40770d6d90cccc4cbdedcf52950a)
@@ -7,6 +7,28 @@
 *           transcendental variables t_1, ..., t_s, where s >= 1.
 *           Denoting the implemented coeffs object by cf, then these numbers
-*           are represented as quotients of polynomials in the polynomial
-*           ring K[t_1, .., t_s] represented by cf->extring.
+*           are represented as quotients of polynomials living in the
+*           polynomial ring K[t_1, .., t_s] represented by cf->extring.
+*
+*           An element of K(t_1, .., t_s) may have numerous representations,
+*           due to the possibility of common polynomial factors in the
+*           numerator and denominator. This problem is handled by a
+*           cancellation heuristic: Each number "knows" its complexity
+*           which is 0 if and only if common factors have definitely been
+*           cancelled, and some positive integer otherwise.
+*           Each arithmetic operation of two numbers with complexities c1
+*           and c2 will result in a number of complexity c1 + c2 + some
+*           penalty (specific for each arithmetic operation; see constants
+*           in the *.h file). Whenever the resulting complexity exceeds a
+*           certain threshold (see constant in the *.h file), then the
+*           cancellation heuristic will call 'factory' to compute the gcd
+*           and cancel it out in the given number. (This definite cancel-
+*           lation will also be performed at the beginning of ntWrite,
+*           ensuring that any output is free of common factors.
+*           For the special case of K = Q (i.e., when computing over the
+*           rationals), this definite cancellation procedure will also take
+*           care of nested fractions: If there are fractional coefficients
+*           in the numerator or denominator of a number, then this number
+*           is being replaced by a quotient of two polynomials over Z, or
+*           - if the denominator is a constant - by a polynomial over Q.
 */
 
@@ -71,5 +93,6 @@
 void heuristicGcdCancellation(number a, const coeffs cf);
 void definiteGcdCancellation(number a, const coeffs cf,
-                             BOOLEAN skipSimpleTests);
+                             BOOLEAN simpleTestsHaveAlreadyBeenPerformed);
+void handleNestedFractionsOverQ(fraction f, const coeffs cf);
 
 #ifdef LDEBUG
@@ -529,4 +552,124 @@
 }
 
+/* assumes that cf represents the rationals, i.e. Q, and will only
+   be called in that case;
+   assumes furthermore that f != NULL and that the denominator of f != 1;
+   generally speaking, this method removes denominators in the rational
+   coefficients of the numerator and denominator of 'a';
+   more concretely, the following normalizations will be performed,
+   where t^alpha denotes a monomial in the transcendental variables t_k
+   (1) if 'a' is of the form
+          (sum_alpha a_alpha/b_alpha * t^alpha)
+          -------------------------------------
+            (sum_beta c_beta/d_beta * t^beta)
+       with integers a_alpha, b_alpha, c_beta, d_beta, then both the
+       numerator and the denominator will be multiplied by the LCM of
+       the b_alpha's and the d_beta's (if this LCM is != 1),
+   (2) if 'a' is - e.g. after having performed step (1) - of the form
+          (sum_alpha a_alpha * t^alpha)
+          -----------------------------
+            (sum_beta c_beta * t^beta)
+       with integers a_alpha, c_beta, and with a non-constant denominator,
+       then both the numerator and the denominator will be divided by the
+       GCD of the a_alpha's and the c_beta's (if this GCD is != 1),
+   (3) if 'a' is - e.g. after having performed steps (1) and (2) - of the
+       form
+          (sum_alpha a_alpha * t^alpha)
+          -----------------------------
+                        c
+       with integers a_alpha, and c != 1, then 'a' will be replaced by
+       (sum_alpha a_alpha/c * t^alpha);
+   this procedure does not alter COM(f) (this has to be done by the
+   calling procedure);
+   modifies f */
+void handleNestedFractionsOverQ(fraction f, const coeffs cf)
+{
+  assume(nCoeff_is_Q(ntCoeffs));
+  assume(!IS0(f));
+  assume(!DENIS1(f));
+  
+  if (!p_IsConstant(DEN(f), ntRing))
+  { /* step (1); see documentation of this procedure above */
+    number lcmOfDenominators = n_Init(1, ntCoeffs);
+    number c; number tmp;
+    poly p = NUM(f);
+    /* careful when using n_Lcm!!! It computes the lcm of the numerator
+       of the 1st argument and the denominator of the 2nd!!! */
+    while (p != NULL)
+    {
+      c = p_GetCoeff(p, ntRing);
+      tmp = n_Lcm(lcmOfDenominators, c, ntCoeffs);
+      n_Delete(&lcmOfDenominators, ntCoeffs);
+      lcmOfDenominators = tmp;
+      pIter(p);
+    }
+    p = DEN(f);
+    while (p != NULL)
+    {
+      c = p_GetCoeff(p, ntRing);
+      tmp = n_Lcm(lcmOfDenominators, c, ntCoeffs);
+      n_Delete(&lcmOfDenominators, ntCoeffs);
+      lcmOfDenominators = tmp;
+      pIter(p);
+    }
+    if (!n_IsOne(lcmOfDenominators, ntCoeffs))
+    { /* multiply NUM(f) and DEN(f) with lcmOfDenominators */
+      NUM(f) = p_Mult_nn(NUM(f), lcmOfDenominators, ntRing);
+      DEN(f) = p_Mult_nn(DEN(f), lcmOfDenominators, ntRing);
+    }
+    n_Delete(&lcmOfDenominators, ntCoeffs);
+    if (!p_IsConstant(DEN(f), ntRing))
+    { /* step (2); see documentation of this procedure above */
+      p = NUM(f);
+      number gcdOfCoefficients = n_Copy(p_GetCoeff(p, ntRing), ntCoeffs);
+      pIter(p);
+      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
+      {
+        c = p_GetCoeff(p, ntRing);
+        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
+        n_Delete(&gcdOfCoefficients, ntCoeffs);
+        gcdOfCoefficients = tmp;
+        pIter(p);
+      }
+      p = DEN(f);
+      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
+      {
+        c = p_GetCoeff(p, ntRing);
+        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
+        n_Delete(&gcdOfCoefficients, ntCoeffs);
+        gcdOfCoefficients = tmp;
+        pIter(p);
+      }
+      if (!n_IsOne(gcdOfCoefficients, ntCoeffs))
+      { /* divide NUM(f) and DEN(f) by gcdOfCoefficients */
+        number inverseOfGcdOfCoefficients = n_Invers(gcdOfCoefficients,
+                                                     ntCoeffs);
+        NUM(f) = p_Mult_nn(NUM(f), inverseOfGcdOfCoefficients, ntRing);
+        DEN(f) = p_Mult_nn(DEN(f), inverseOfGcdOfCoefficients, ntRing);
+        n_Delete(&inverseOfGcdOfCoefficients, ntCoeffs);
+      }
+      n_Delete(&gcdOfCoefficients, ntCoeffs);
+    }
+  }
+  if (p_IsConstant(DEN(f), ntRing) &&
+      (!n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs)))
+  { /* step (3); see documentation of this procedure above */
+    number inverseOfDen = n_Invers(p_GetCoeff(DEN(f), ntRing), ntCoeffs);
+    NUM(f) = p_Mult_nn(NUM(f), inverseOfDen, ntRing);
+    n_Delete(&inverseOfDen, ntCoeffs);
+    p_Delete(&DEN(f), ntRing);
+    DEN(f) = NULL;
+  }
+  
+  /* Now, due to the above computations, DEN(f) may have become the
+     1-polynomial which needs to be represented by NULL: */
+  if ((DEN(f) != NULL) &&
+      p_IsConstant(DEN(f), ntRing) &&
+      n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
+  {
+    p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
+  }
+}
+
 /* modifies a */
 void heuristicGcdCancellation(number a, const coeffs cf)
@@ -553,5 +696,5 @@
 /* modifies a */
 void definiteGcdCancellation(number a, const coeffs cf,
-                             BOOLEAN skipSimpleTests)
+                             BOOLEAN simpleTestsHaveAlreadyBeenPerformed)
 {
   ntTest(a);
@@ -559,5 +702,5 @@
   fraction f = (fraction)a;
   
-  if (!skipSimpleTests)
+  if (!simpleTestsHaveAlreadyBeenPerformed)
   {
     if (IS0(a)) return;
@@ -574,29 +717,46 @@
   }
   
-#ifdef HAVE_FACTORY
-  /* singclap_gcd destroys its arguments. We hence need copies: */
+#ifdef HAVE_FACTORY  
+  /* singclap_gcd destroys its arguments; we hence need copies: */
   poly pNum = p_Copy(NUM(f), ntRing);
   poly pDen = p_Copy(DEN(f), ntRing);
+  
+  /* Note that, over Q, singclap_gcd will remove the denominators in all
+     rational coefficients of pNum and pDen, before starting to compute
+     the gcd. Thus, we do not need to ensure that the coefficients of
+     pNum and pDen live in Z; they may well be elements of Q\Z. */
   poly pGcd = singclap_gcd(pNum, pDen, cf->extRing);
   if (p_IsConstant(pGcd, ntRing) &&
       n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs))
-  {
-      /* gcd = 1; nothing to cancel */
+  { /* gcd = 1; nothing to cancel;
+       Suppose the given rational function field is over Q. Although the
+       gcd is 1, we may have produced fractional coefficients in NUM(f),
+       DEN(f), or both, due to previous arithmetics. The next call will
+       remove those nested fractions, in case there are any. */
+    if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
   }
   else
-  {
-      poly newNum = singclap_pdivide(NUM(f), pGcd, ntRing);
-      p_Delete(&NUM(f), ntRing);
-      NUM(f) = newNum;
-      poly newDen = singclap_pdivide(DEN(f), pGcd, ntRing);
+  { /* We divide both NUM(f) and DEN(f) by the gcd which is known
+       to be != 1. */
+    poly newNum = singclap_pdivide(NUM(f), pGcd, ntRing);
+    p_Delete(&NUM(f), ntRing);
+    NUM(f) = newNum;
+    poly newDen = singclap_pdivide(DEN(f), pGcd, ntRing);
+    p_Delete(&DEN(f), ntRing);
+    DEN(f) = newDen;
+    if (p_IsConstant(DEN(f), ntRing) &&
+        n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
+    {
+      /* DEN(f) = 1 needs to be represented by NULL! */
       p_Delete(&DEN(f), ntRing);
-      if (p_IsConstant(newDen, ntRing) &&
-          n_IsOne(p_GetCoeff(newDen, ntRing), ntCoeffs))
-      {
-        /* newDen = 1 needs to be represented by NULL */
-        p_Delete(&newDen, ntRing);
-        newDen = NULL;
-      }
-      DEN(f) = newDen;
+      newDen = NULL;
+    }
+    else
+    { /* Note that over Q, by cancelling the gcd, we may have produced
+         fractional coefficients in NUM(f), DEN(f), or both. The next
+         call will remove those nested fractions, in case there are
+         any. */
+      if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
+    }
   }
   COM(f) = 0;
Index: libpolys/polys/ext_fields/transext.h
===================================================================
--- libpolys/polys/ext_fields/transext.h	(revision 2d3091c7bb239cd4787574560ab475ac88621da7)
+++ libpolys/polys/ext_fields/transext.h	(revision 06df101aca2a40770d6d90cccc4cbdedcf52950a)
@@ -9,6 +9,28 @@
 *           transcendental variables t_1, ..., t_s, where s >= 1.
 *           Denoting the implemented coeffs object by cf, then these numbers
-*           are represented as quotients of polynomials in the polynomial
-*           ring K[t_1, .., t_s] represented by cf->extring.
+*           are represented as quotients of polynomials living in the
+*           polynomial ring K[t_1, .., t_s] represented by cf->extring.
+*
+*           An element of K(t_1, .., t_s) may have numerous representations,
+*           due to the possibility of common polynomial factors in the
+*           numerator and denominator. This problem is handled by a
+*           cancellation heuristic: Each number "knows" its complexity
+*           which is 0 if and only if common factors have definitely been
+*           cancelled, and some positive integer otherwise.
+*           Each arithmetic operation of two numbers with complexities c1
+*           and c2 will result in a number of complexity c1 + c2 + some
+*           penalty (specific for each arithmetic operation; see constants
+*           in the *.h file). Whenever the resulting complexity exceeds a
+*           certain threshold (see constant in the *.h file), then the
+*           cancellation heuristic will call 'factory' to compute the gcd
+*           and cancel it out in the given number. (This definite cancel-
+*           lation will also be performed at the beginning of ntWrite,
+*           ensuring that any output is free of common factors.
+*           For the special case of K = Q (i.e., when computing over the
+*           rationals), this definite cancellation procedure will also take
+*           care of nested fractions: If there are fractional coefficients
+*           in the numerator or denominator of a number, then this number
+*           is being replaced by a quotient of two polynomials over Z, or
+*           - if the denominator is a constant - by a polynomial over Q.
 */
 
Index: libpolys/tests/coeffs_test.h
===================================================================
--- libpolys/tests/coeffs_test.h	(revision 2d3091c7bb239cd4787574560ab475ac88621da7)
+++ libpolys/tests/coeffs_test.h	(revision 06df101aca2a40770d6d90cccc4cbdedcf52950a)
@@ -481,9 +481,35 @@
      setGMPFloatDigits( 10, 5 ); // Init global variables in mpr_complex.cc for gmp_float's... // Note that this seems also to be required for Z_2^m (and Zn?)!????
      simple(n_long_C);
-   }  
-
-   
-   // polynomial rings needed for extentions: n_algExt, n_transExt !
-   
+   }
+   
+   void test_Q_special()
+   {
+     const coeffs cf = nInitChar(n_Q, NULLp);
+
+     if (cf == NULLp)
+       clog << ( "Test: could not get this coeff. domain" );
+
+     TS_ASSERT_DIFFERS(cf->cfCoeffWrite, NULLp);
+
+     if (cf->cfCoeffWrite != NULL )
+     {
+       clog << "Coeff-domain: "  << endl; 
+       n_CoeffWrite(cf); PrintLn();
+     }
+     
+     number q1 = n_Init(21, cf);
+     number q2 = n_Init(2, cf);
+     number q3 = n_Div(q1, q2, cf);
+     number q4 = n_Init(30, cf);
+     number q5 = n_Mult(q3, q4, cf);
+     TS_ASSERT(n_Test(q5, cf));
+     Print("21/2 * 30 = %d\n", n_Int(q5, cf));
+     TS_ASSERT(n_Test(q5, cf));
+     n_Delete(&q1, cf);
+     n_Delete(&q2, cf);
+     n_Delete(&q3, cf);
+     n_Delete(&q4, cf);
+     n_Delete(&q5, cf);
+   }
 };
 
Index: libpolys/tests/polys_test.h
===================================================================
--- libpolys/tests/polys_test.h	(revision 2d3091c7bb239cd4787574560ab475ac88621da7)
+++ libpolys/tests/polys_test.h	(revision 06df101aca2a40770d6d90cccc4cbdedcf52950a)
@@ -220,4 +220,16 @@
   {
     poly t = p_ISet(c, r);
+    if (exp > 0) { p_SetExp(t, i, exp, r); p_Setm(t, r); }
+    p = p_Add_q(p, t, r);
+  }
+  /* assumes that r is over Q;
+     replaces p by p + c1 / c2 * var(i)^exp (in-place);
+     expects exp >= 0, and c2 != 0 */
+  void plusTermOverQ(poly &p, int c1, int c2, int i, int exp, const ring r)
+  {
+    number c1AsN = n_Init(c1, r->cf);
+    number c2AsN = n_Init(c2, r->cf);
+    number c =  n_Div(c1AsN, c2AsN, r->cf);
+    poly t = p_ISet(1, r); p_SetCoeff(t, c, r);
     if (exp > 0) { p_SetExp(t, i, exp, r); p_Setm(t, r); }
     p = p_Add_q(p, t, r);
@@ -2493,5 +2505,5 @@
     poly theProduct = p_Mult_q(entry, factor, s);
     p_Write(theProduct, s);
-    clog << "ending multiplication..." << endl;
+    clog << "...ending multiplication" << endl;
     n_Delete(&qfactorAsN, cf); p_Delete(&theProduct, s);
     
@@ -2508,9 +2520,109 @@
     /* The following multiplication + output of the product is very slow
        in the svn/trunk SINGULAR version; see trac ticket #308.
-       Here, in the Spielwiese, the result is instantaneous! */
+       Here, in the Spielwiese, the result is instantaneous. */
     theProduct = p_Mult_q(entry, factor, s);
     p_Write(theProduct, s);
-    clog << "ending very special multiplication..." << endl;
+    clog << "...ending very special multiplication" << endl;
     n_Delete(&qfactorAsN, cf); p_Delete(&theProduct, s);
+        
+    rDelete(s); // kills 'cf' and 'r' as well
+  }
+  void test_Q_Ext_s_t_NestedFractions()
+  {
+    clog << "Start by creating Q[s, t]..." << endl;
+
+    char* n[] = {"s", "t"};
+    ring r = rDefault( 0, 2, n);   // Q[s, t]
+    TS_ASSERT_DIFFERS( r, NULLp );
+
+    PrintRing(r);
+
+    TS_ASSERT( rField_is_Domain(r) );
+    TS_ASSERT( rField_is_Q(r) );
+
+    TS_ASSERT( !rField_is_Zp(r) );
+    TS_ASSERT( !rField_is_Zp(r, 17) );
+
+    TS_ASSERT_EQUALS( rVar(r), 2);
+
+    n_coeffType type = nRegister(n_transExt, ntInitChar);
+    TS_ASSERT(type == n_transExt);
+
+    TransExtInfo extParam;
+    extParam.r = r;
+
+    clog << "Next create the rational function field Q(s, t)..." << endl;
+
+    const coeffs cf = nInitChar(type, &extParam);   // Q(s, t)
+
+    if( cf == NULL )
+      TS_FAIL("Could not get needed coeff. domain");
+
+    TS_ASSERT_DIFFERS( cf->cfCoeffWrite, NULLp );
+
+    if( cf->cfCoeffWrite != NULL )
+    {
+      clog << "Coeff-domain: "  << endl;
+      n_CoeffWrite(cf); PrintLn();
+    }
+
+    TS_ASSERT( !nCoeff_is_algExt(cf) );
+    TS_ASSERT( nCoeff_is_transExt(cf) );
+
+    clog << "Finally create the polynomial ring Q(s, t)[x, y, z]..."
+         << endl;
+
+    char* m[] = {"x", "y", "z"};
+    ring s = rDefault(cf, 3, m);   // Q(s, t)[x, y, z]
+    TS_ASSERT_DIFFERS(s, NULLp);
+
+    PrintRing(s);
+
+    TS_ASSERT( rField_is_Domain(s) );
+    TS_ASSERT( !rField_is_Q(s) );
+    TS_ASSERT( !rField_is_Zp(s) );
+    TS_ASSERT( !rField_is_Zp(s, 11) );
+    TS_ASSERT( !rField_is_Zp(s, 17) );
+    TS_ASSERT( !rField_is_GF(s) );
+    TS_ASSERT( rField_is_Extension(s) );
+    TS_ASSERT( !rField_is_GF(s, 25) );
+    TS_ASSERT_EQUALS(rVar(s), 3);
+    
+    /* test 1 for nested fractions, i.e. fractional coefficients: */
+    poly v1 = NULL;
+    plusTermOverQ(v1, 21, 2, 1, 1, cf->extRing);       // 21/2*s
+    plusTermOverQ(v1, 14, 3, 1, 0, cf->extRing);       // 21/2*s + 14/3
+    number v1_n = toFractionNumber(v1, cf);
+    PrintSized(v1_n, cf);
+    poly v2 = NULL;
+    plusTermOverQ(v2, 7, 5, 1, 1, cf->extRing);       // 7/5*s
+    plusTermOverQ(v2, -49, 6, 2, 1, cf->extRing);     // 7/5*s - 49/6*t
+    number v2_n = toFractionNumber(v2, cf);
+    PrintSized(v2_n, cf);
+    number v3_n = n_Div(v1_n, v2_n, cf);   // (45*s + 20) / (6s - 35*t)
+    PrintSized(v3_n, cf);
+    n_Delete(&v1_n, cf); n_Delete(&v2_n, cf); n_Delete(&v3_n, cf);
+    
+    /* test 2 for nested fractions, i.e. fractional coefficients: */
+    v1 = NULL;
+    plusTermOverQ(v1, 1, 2, 1, 1, cf->extRing);       // 1/2*s
+    plusTermOverQ(v1, 1, 1, 1, 0, cf->extRing);       // 1/2*s + 1
+    v2 = NULL;
+    plusTermOverQ(v2, 1, 1, 1, 1, cf->extRing);       // s
+    plusTermOverQ(v2, 2, 3, 2, 1, cf->extRing);       // s + 2/3*t
+    poly v3 = p_Mult_q(v1, v2, cf->extRing);   // (1/2*s + 1) * (s + 2/3*t)
+    number v_n = toFractionNumber(v3, cf);
+    PrintSized(v_n, cf);
+    poly w1 = NULL;
+    plusTermOverQ(w1, 1, 2, 1, 1, cf->extRing);       // 1/2*s
+    plusTermOverQ(w1, 1, 1, 1, 0, cf->extRing);       // 1/2*s + 1
+    poly w2 = NULL;
+    plusTermOverQ(w2, -7, 5, 1, 0, cf->extRing);      // -7/5
+    poly w3 = p_Mult_q(w1, w2, cf->extRing);   // (1/2*s + 1) * (-7/5)
+    number w_n = toFractionNumber(w3, cf);
+    PrintSized(w_n, cf);
+    number z_n = n_Div(v_n, w_n, cf);          // -5/7*s - 10/21*t
+    PrintSized(z_n, cf);
+    n_Delete(&v_n, cf); n_Delete(&w_n, cf); n_Delete(&z_n, cf);
     
     rDelete(s); // kills 'cf' and 'r' as well
