+/** Compute GCD of multivariate polynomials using the Euclidean PRS algorithm
+ * (not really suited for multivariate GCDs). This function is only provided
+ * for testing purposes.
+ *
+ * @param a first multivariate polynomial
+ * @param b second multivariate polynomial
+ * @param x pointer to symbol (main variable) in which to compute the GCD in
+ * @return the GCD as a new expression
+ * @see gcd */
+
+static ex eu_gcd(const ex &a, const ex &b, const symbol *x)
+{
+//clog << "eu_gcd(" << a << "," << b << ")\n";
+
+ // Sort c and d so that c has higher degree
+ ex c, d;
+ int adeg = a.degree(*x), bdeg = b.degree(*x);
+ if (adeg >= bdeg) {
+ c = a;
+ d = b;
+ } else {
+ c = b;
+ d = a;
+ }
+
+ // Euclidean algorithm
+ ex r;
+ for (;;) {
+//clog << " d = " << d << endl;
+ r = rem(c, d, *x, false);
+ if (r.is_zero())
+ return d.primpart(*x);
+ c = d;
+ d = r;
+ }
+}
+
+
+/** Compute GCD of multivariate polynomials using the Euclidean PRS algorithm
+ * with pseudo-remainders ("World's Worst GCD Algorithm", staying in Z[X]).
+ * This function is only provided for testing purposes.
+ *
+ * @param a first multivariate polynomial
+ * @param b second multivariate polynomial
+ * @param x pointer to symbol (main variable) in which to compute the GCD in
+ * @return the GCD as a new expression
+ * @see gcd */
+
+static ex euprem_gcd(const ex &a, const ex &b, const symbol *x)
+{
+//clog << "euprem_gcd(" << a << "," << b << ")\n";
+
+ // Sort c and d so that c has higher degree
+ ex c, d;
+ int adeg = a.degree(*x), bdeg = b.degree(*x);
+ if (adeg >= bdeg) {
+ c = a;
+ d = b;
+ } else {
+ c = b;
+ d = a;
+ }
+
+ // Euclidean algorithm with pseudo-remainders
+ ex r;
+ for (;;) {
+//clog << " d = " << d << endl;
+ r = prem(c, d, *x, false);
+ if (r.is_zero())
+ return d.primpart(*x);
+ c = d;
+ d = r;
+ }
+}
+
+
+/** Compute GCD of multivariate polynomials using the primitive Euclidean
+ * PRS algorithm (complete content removal at each step). This function is
+ * only provided for testing purposes.
+ *
+ * @param a first multivariate polynomial
+ * @param b second multivariate polynomial
+ * @param x pointer to symbol (main variable) in which to compute the GCD in
+ * @return the GCD as a new expression
+ * @see gcd */
+
+static ex peu_gcd(const ex &a, const ex &b, const symbol *x)
+{
+//clog << "peu_gcd(" << a << "," << b << ")\n";
+
+ // Sort c and d so that c has higher degree
+ ex c, d;
+ int adeg = a.degree(*x), bdeg = b.degree(*x);
+ int ddeg;
+ if (adeg >= bdeg) {
+ c = a;
+ d = b;
+ ddeg = bdeg;
+ } else {
+ c = b;
+ d = a;
+ ddeg = adeg;
+ }
+
+ // Remove content from c and d, to be attached to GCD later
+ ex cont_c = c.content(*x);
+ ex cont_d = d.content(*x);
+ ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
+ if (ddeg == 0)
+ return gamma;
+ c = c.primpart(*x, cont_c);
+ d = d.primpart(*x, cont_d);
+
+ // Euclidean algorithm with content removal
+ ex r;
+ for (;;) {
+//clog << " d = " << d << endl;
+ r = prem(c, d, *x, false);
+ if (r.is_zero())
+ return gamma * d;
+ c = d;
+ d = r.primpart(*x);
+ }
+}
+
+
+/** Compute GCD of multivariate polynomials using the reduced PRS algorithm.
+ * This function is only provided for testing purposes.
+ *
+ * @param a first multivariate polynomial
+ * @param b second multivariate polynomial
+ * @param x pointer to symbol (main variable) in which to compute the GCD in
+ * @return the GCD as a new expression
+ * @see gcd */
+
+static ex red_gcd(const ex &a, const ex &b, const symbol *x)
+{
+//clog << "red_gcd(" << a << "," << b << ")\n";
+
+ // Sort c and d so that c has higher degree
+ ex c, d;
+ int adeg = a.degree(*x), bdeg = b.degree(*x);
+ int cdeg, ddeg;
+ if (adeg >= bdeg) {
+ c = a;
+ d = b;
+ cdeg = adeg;
+ ddeg = bdeg;
+ } else {
+ c = b;
+ d = a;
+ cdeg = bdeg;
+ ddeg = adeg;
+ }
+
+ // Remove content from c and d, to be attached to GCD later
+ ex cont_c = c.content(*x);
+ ex cont_d = d.content(*x);
+ ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
+ if (ddeg == 0)
+ return gamma;
+ c = c.primpart(*x, cont_c);
+ d = d.primpart(*x, cont_d);
+
+ // First element of subresultant sequence
+ ex r, ri = _ex1();
+ int delta = cdeg - ddeg;
+
+ for (;;) {
+ // Calculate polynomial pseudo-remainder
+//clog << " d = " << d << endl;
+ r = prem(c, d, *x, false);
+ if (r.is_zero())
+ return gamma * d.primpart(*x);
+ c = d;
+ cdeg = ddeg;
+
+ if (!divide(r, pow(ri, delta), d, false))
+ throw(std::runtime_error("invalid expression in red_gcd(), division failed"));
+ ddeg = d.degree(*x);
+ if (ddeg == 0) {
+ if (is_ex_exactly_of_type(r, numeric))
+ return gamma;
+ else
+ return gamma * r.primpart(*x);
+ }
+
+ ri = c.expand().lcoeff(*x);
+ delta = cdeg - ddeg;
+ }
+}
+
+