eigenmath/factorpoly.cpp

757 lines
11 KiB
C++
Raw Permalink Normal View History

2006-04-26 00:29:29 +02:00
// Factor a polynomial
2004-03-03 21:24:06 +01:00
2005-08-06 22:57:37 +02:00
#include "stdafx.h"
2004-03-03 21:24:06 +01:00
#include "defs.h"
2006-04-26 00:29:29 +02:00
2004-03-03 21:24:06 +01:00
static void rationalize_coefficients(int);
static int get_factor(void);
static void evalpoly(void);
2005-10-27 19:39:15 +02:00
static void yydivpoly(void);
2006-04-26 00:29:29 +02:00
2004-03-03 21:24:06 +01:00
static int expo;
static U **polycoeff;
2005-08-06 22:57:37 +02:00
#define POLY p1
#define X p2
#define Z p3
#define A p4
#define B p5
#define Q p6
#define RESULT p7
#define FACTOR p8
2004-03-03 21:24:06 +01:00
void
factorpoly(void)
{
save();
p2 = pop();
p1 = pop();
2006-11-22 03:42:38 +01:00
if (p2->k != SYM)
stop("factor: 2nd arg?");
if (find(p1, p2) && !ispoly(p1, p2))
stop("factor: 1st arg?");
2004-03-03 21:24:06 +01:00
push(p1);
2005-08-06 22:57:37 +02:00
push(p2);
2006-11-22 03:42:38 +01:00
yyfactorpoly();
2004-03-03 21:24:06 +01:00
restore();
}
//-----------------------------------------------------------------------------
//
// Input: tos-2 true polynomial
//
// tos-1 free variable
//
// Output: factored polynomial on stack
//
//-----------------------------------------------------------------------------
2006-11-22 03:42:38 +01:00
void
yyfactorpoly(void)
2004-03-03 21:24:06 +01:00
{
int h, i;
save();
X = pop();
POLY = pop();
h = tos;
2007-04-26 06:11:01 +02:00
if (isfloating(POLY))
stop("floating point numbers in polynomial");
2004-03-03 21:24:06 +01:00
polycoeff = stack + tos;
push(POLY);
push(X);
expo = coeff() - 1;
rationalize_coefficients(h);
// for univariate polynomials we could do expo > 1
while (expo > 0) {
2006-04-26 00:29:29 +02:00
if (iszero(polycoeff[0])) {
push_integer(1);
A = pop();
push_integer(0);
B = pop();
2006-04-26 00:51:28 +02:00
} else if (get_factor() == 0) {
2004-03-03 21:24:06 +01:00
if (verbosing)
printf("no factor found\n");
break;
}
push(A);
push(X);
multiply();
push(B);
add();
FACTOR = pop();
if (verbosing) {
printf("success\nFACTOR=");
2004-06-09 04:45:50 +02:00
print(FACTOR);
2004-03-03 21:24:06 +01:00
printf("\n");
}
// factor out negative sign (not req'd because A > 1)
#if 0
if (isnegativeterm(A)) {
push(FACTOR);
negate();
FACTOR = pop();
push(RESULT);
negate_noexpand();
RESULT = pop();
}
#endif
push(RESULT);
push(FACTOR);
multiply_noexpand();
RESULT = pop();
2005-10-27 19:39:15 +02:00
yydivpoly();
2004-03-03 21:24:06 +01:00
while (expo && iszero(polycoeff[expo]))
expo--;
}
// unfactored polynomial
2004-06-25 22:45:15 +02:00
push(zero);
2004-03-03 21:24:06 +01:00
for (i = 0; i <= expo; i++) {
push(polycoeff[i]);
push(X);
push_integer(i);
power();
multiply();
add();
}
POLY = pop();
if (verbosing) {
printf("POLY=");
2004-06-09 04:45:50 +02:00
print(POLY);
2004-03-03 21:24:06 +01:00
printf("\n");
}
// factor out negative sign
if (expo > 0 && isnegativeterm(polycoeff[expo])) {
push(POLY);
negate();
POLY = pop();
push(RESULT);
negate_noexpand();
RESULT = pop();
}
push(RESULT);
push(POLY);
multiply_noexpand();
RESULT = pop();
if (verbosing) {
printf("RESULT=");
2004-06-09 04:45:50 +02:00
print(RESULT);
2004-03-03 21:24:06 +01:00
printf("\n");
}
stack[h] = RESULT;
tos = h + 1;
restore();
}
static void
rationalize_coefficients(int h)
{
int i;
2006-04-26 00:29:29 +02:00
// LCM of all polynomial coefficients
2004-06-25 22:45:15 +02:00
RESULT = one;
2004-03-03 21:24:06 +01:00
for (i = h; i < tos; i++) {
2006-04-26 00:29:29 +02:00
push(stack[i]);
denominator();
push(RESULT);
lcm();
RESULT = pop();
2004-03-03 21:24:06 +01:00
}
2006-04-26 00:29:29 +02:00
// multiply each coefficient by RESULT
2004-03-03 21:24:06 +01:00
for (i = h; i < tos; i++) {
2006-04-26 00:29:29 +02:00
push(RESULT);
push(stack[i]);
multiply();
stack[i] = pop();
2004-03-03 21:24:06 +01:00
}
2006-04-26 00:29:29 +02:00
// reciprocate RESULT
2004-03-03 21:24:06 +01:00
push(RESULT);
2006-04-26 00:29:29 +02:00
reciprocate();
2004-03-03 21:24:06 +01:00
RESULT = pop();
}
static int
get_factor(void)
{
int i, j, h;
int a0, an, na0, nan;
if (verbosing) {
2004-06-25 22:45:15 +02:00
push(zero);
2004-03-03 21:24:06 +01:00
for (i = 0; i <= expo; i++) {
push(polycoeff[i]);
push(X);
push_integer(i);
power();
multiply();
add();
}
POLY = pop();
printf("POLY=");
2004-06-09 04:45:50 +02:00
print(POLY);
2004-03-03 21:24:06 +01:00
printf("\n");
}
h = tos;
an = tos;
push(polycoeff[expo]);
divisors_onstack();
nan = tos - an;
a0 = tos;
push(polycoeff[0]);
divisors_onstack();
na0 = tos - a0;
if (verbosing) {
printf("divisors of base term");
for (i = 0; i < na0; i++) {
printf(", ");
2004-06-09 04:45:50 +02:00
print(stack[a0 + i]);
2004-03-03 21:24:06 +01:00
}
printf("\n");
printf("divisors of leading term");
for (i = 0; i < nan; i++) {
printf(", ");
2004-06-09 04:45:50 +02:00
print(stack[an + i]);
2004-03-03 21:24:06 +01:00
}
printf("\n");
}
// try roots
for (i = 0; i < nan; i++) {
for (j = 0; j < na0; j++) {
A = stack[an + i];
B = stack[a0 + j];
push(B);
push(A);
divide();
negate();
Z = pop();
evalpoly();
if (verbosing) {
printf("try A=");
2004-06-09 04:45:50 +02:00
print(A);
2004-03-03 21:24:06 +01:00
printf(", B=");
2004-06-09 04:45:50 +02:00
print(B);
2004-03-03 21:24:06 +01:00
printf(", root ");
2004-06-09 04:45:50 +02:00
print(X);
2004-03-03 21:24:06 +01:00
printf("=-B/A=");
2004-06-09 04:45:50 +02:00
print(Z);
2004-03-03 21:24:06 +01:00
printf(", POLY(");
2004-06-09 04:45:50 +02:00
print(Z);
2004-03-03 21:24:06 +01:00
printf(")=");
2004-06-09 04:45:50 +02:00
print(Q);
2004-03-03 21:24:06 +01:00
printf("\n");
}
if (iszero(Q)) {
tos = h;
return 1;
}
push(B);
negate();
B = pop();
push(Z);
negate();
Z = pop();
evalpoly();
if (verbosing) {
printf("try A=");
2004-06-09 04:45:50 +02:00
print(A);
2004-03-03 21:24:06 +01:00
printf(", B=");
2004-06-09 04:45:50 +02:00
print(B);
2004-03-03 21:24:06 +01:00
printf(", root ");
2004-06-09 04:45:50 +02:00
print(X);
2004-03-03 21:24:06 +01:00
printf("=-B/A=");
2004-06-09 04:45:50 +02:00
print(Z);
2004-03-03 21:24:06 +01:00
printf(", POLY(");
2004-06-09 04:45:50 +02:00
print(Z);
2004-03-03 21:24:06 +01:00
printf(")=");
2004-06-09 04:45:50 +02:00
print(Q);
2004-03-03 21:24:06 +01:00
printf("\n");
}
if (iszero(Q)) {
tos = h;
return 1;
}
}
}
tos = h;
return 0;
}
//-----------------------------------------------------------------------------
//
// Divide a polynomial by Ax+B
//
// Input: polycoeff Dividend coefficients
//
// expo Degree of dividend
//
// A As above
//
// B As above
//
// Output: polycoeff Contains quotient coefficients
//
//-----------------------------------------------------------------------------
static void
2005-10-27 19:39:15 +02:00
yydivpoly(void)
2004-03-03 21:24:06 +01:00
{
int i;
2004-06-25 22:45:15 +02:00
Q = zero;
2004-03-03 21:24:06 +01:00
for (i = expo; i > 0; i--) {
push(polycoeff[i]);
polycoeff[i] = Q;
push(A);
divide();
Q = pop();
push(polycoeff[i - 1]);
push(Q);
push(B);
multiply();
subtract();
polycoeff[i - 1] = pop();
}
polycoeff[0] = Q;
}
static void
evalpoly(void)
{
int i;
2004-06-25 22:45:15 +02:00
push(zero);
2004-03-03 21:24:06 +01:00
for (i = expo; i >= 0; i--) {
push(Z);
multiply();
push(polycoeff[i]);
add();
}
Q = pop();
}
2007-05-08 16:57:30 +02:00
#if SELFTEST
2004-03-03 21:24:06 +01:00
static char *s[] = {
2006-02-10 18:01:28 +01:00
"bake=0",
"",
2004-03-03 21:24:06 +01:00
"factor((x+1)*(x+2)*(x+3),x)",
"(1+x)*(2+x)*(3+x)",
"factor((x+a)*(x^2+x+1),x)",
"(1+x+x^2)*(a+x)",
"factor(x*(x+1)*(x+2),x)",
"x*(1+x)*(2+x)",
2006-04-26 00:29:29 +02:00
// "factor((x+1)*(x+2)*(y+3)*(y+4),x,y)",
// "(1+x)*(2+x)*(3+y)*(4+y)",
2004-03-03 21:24:06 +01:00
2006-04-26 00:29:29 +02:00
// "factor((x+1)*(x+2)*(y+3)*(y+4),(x,y))",
// "(1+x)*(2+x)*(3+y)*(4+y)",
2004-03-03 21:24:06 +01:00
2006-04-26 00:29:29 +02:00
// "factor((x+1)*(x+2)*(y+3)*(y+4))",
// "(1+x)*(2+x)*(3+y)*(4+y)",
2004-03-03 21:24:06 +01:00
"factor((-2*x+3)*(x+4),x)",
"-(-3+2*x)*(4+x)",
"(-2*x+3)*(x+4)+(-3+2*x)*(4+x)",
"0",
// make sure sign of remaining poly is factored
"factor((x+1)*(-x^2+x+1),x)",
"-(-1-x+x^2)*(1+x)",
// sign handling
//++++++
"factor((x+1/2)*(+x+1/3)*(+x+1/4),x)",
"1/24*(1+2*x)*(1+3*x)*(1+4*x)",
"(x+1/2)*(+x+1/3)*(+x+1/4)-1/24*(1+2*x)*(1+3*x)*(1+4*x)",
"0",
//+++++-
"factor((x+1/2)*(+x+1/3)*(+x-1/4),x)",
"1/24*(-1+4*x)*(1+2*x)*(1+3*x)",
"(x+1/2)*(+x+1/3)*(+x-1/4)-1/24*(-1+4*x)*(1+2*x)*(1+3*x)",
"0",
//++++-+
"factor((x+1/2)*(+x+1/3)*(-x+1/4),x)",
"-1/24*(-1+4*x)*(1+2*x)*(1+3*x)",
"(x+1/2)*(+x+1/3)*(-x+1/4)+1/24*(-1+4*x)*(1+2*x)*(1+3*x)",
"0",
//++++--
"factor((x+1/2)*(+x+1/3)*(-x-1/4),x)",
"-1/24*(1+2*x)*(1+3*x)*(1+4*x)",
"(x+1/2)*(+x+1/3)*(-x-1/4)+1/24*(1+2*x)*(1+3*x)*(1+4*x)",
"0",
//+++-++
"factor((x+1/2)*(+x-1/3)*(+x+1/4),x)",
"1/24*(-1+3*x)*(1+2*x)*(1+4*x)",
"(x+1/2)*(+x-1/3)*(+x+1/4)-1/24*(-1+3*x)*(1+2*x)*(1+4*x)",
"0",
//+++-+-
"factor((x+1/2)*(+x-1/3)*(+x-1/4),x)",
"1/24*(-1+3*x)*(-1+4*x)*(1+2*x)",
"(x+1/2)*(+x-1/3)*(+x-1/4)-1/24*(-1+3*x)*(-1+4*x)*(1+2*x)",
"0",
//+++--+
"factor((x+1/2)*(+x-1/3)*(-x+1/4),x)",
"-1/24*(-1+3*x)*(-1+4*x)*(1+2*x)",
"(x+1/2)*(+x-1/3)*(-x+1/4)+1/24*(-1+3*x)*(-1+4*x)*(1+2*x)",
"0",
//+++---
"factor((x+1/2)*(+x-1/3)*(-x-1/4),x)",
"-1/24*(-1+3*x)*(1+2*x)*(1+4*x)",
"(x+1/2)*(+x-1/3)*(-x-1/4)+1/24*(-1+3*x)*(1+2*x)*(1+4*x)",
"0",
//++-+++
"factor((x+1/2)*(-x+1/3)*(+x+1/4),x)",
"-1/24*(-1+3*x)*(1+2*x)*(1+4*x)",
"(x+1/2)*(-x+1/3)*(+x+1/4)+1/24*(-1+3*x)*(1+2*x)*(1+4*x)",
"0",
//++-++-
"factor((x+1/2)*(-x+1/3)*(+x-1/4),x)",
"-1/24*(-1+3*x)*(-1+4*x)*(1+2*x)",
"(x+1/2)*(-x+1/3)*(+x-1/4)+1/24*(-1+3*x)*(-1+4*x)*(1+2*x)",
"0",
//++-+-+
"factor((x+1/2)*(-x+1/3)*(-x+1/4),x)",
"1/24*(-1+3*x)*(-1+4*x)*(1+2*x)",
"(x+1/2)*(-x+1/3)*(-x+1/4)-1/24*(-1+3*x)*(-1+4*x)*(1+2*x)",
"0",
//++-+--
"factor((x+1/2)*(-x+1/3)*(-x-1/4),x)",
"1/24*(-1+3*x)*(1+2*x)*(1+4*x)",
"(x+1/2)*(-x+1/3)*(-x-1/4)-1/24*(-1+3*x)*(1+2*x)*(1+4*x)",
"0",
//++--++
"factor((x+1/2)*(-x-1/3)*(+x+1/4),x)",
"-1/24*(1+2*x)*(1+3*x)*(1+4*x)",
"(x+1/2)*(-x-1/3)*(+x+1/4)+1/24*(1+2*x)*(1+3*x)*(1+4*x)",
"0",
//++--+-
"factor((x+1/2)*(-x-1/3)*(+x-1/4),x)",
"-1/24*(-1+4*x)*(1+2*x)*(1+3*x)",
"(x+1/2)*(-x-1/3)*(+x-1/4)+1/24*(-1+4*x)*(1+2*x)*(1+3*x)",
"0",
//++---+
"factor((x+1/2)*(-x-1/3)*(-x+1/4),x)",
"1/24*(-1+4*x)*(1+2*x)*(1+3*x)",
"(x+1/2)*(-x-1/3)*(-x+1/4)-1/24*(-1+4*x)*(1+2*x)*(1+3*x)",
"0",
//++----
"factor((x+1/2)*(-x-1/3)*(-x-1/4),x)",
"1/24*(1+2*x)*(1+3*x)*(1+4*x)",
"(x+1/2)*(-x-1/3)*(-x-1/4)-1/24*(1+2*x)*(1+3*x)*(1+4*x)",
"0",
//++++++
"factor((+x+a)*(+x+b)*(+x+c),x)",
"(a+x)*(b+x)*(c+x)",
"(a+x)*(b+x)*(c+x)-(a+x)*(b+x)*(c+x)",
"0",
//+++++-
"factor((+x+a)*(+x+b)*(+x-c),x)",
"(a+x)*(b+x)*(-c+x)",
"(+x+a)*(+x+b)*(+x-c)-(a+x)*(b+x)*(-c+x)",
"0",
//++++-+
"factor((+x+a)*(+x+b)*(-x+c),x)",
"-(a+x)*(b+x)*(-c+x)",
"(+x+a)*(+x+b)*(-x+c)+(a+x)*(b+x)*(-c+x)",
"0",
//++++--
"factor((+x+a)*(+x+b)*(-x-c),x)",
"-(a+x)*(b+x)*(c+x)",
"(+x+a)*(+x+b)*(-x-c)+(a+x)*(b+x)*(c+x)",
"0",
//++++
"factor((+a*x+b)*(+c*x+d),x)",
"(b+a*x)*(d+c*x)",
"(+a*x+b)*(+c*x+d)-(b+a*x)*(d+c*x)",
"0",
//+++-
"factor((+a*x+b)*(+c*x-d),x)",
"(b+a*x)*(-d+c*x)",
"(+a*x+b)*(+c*x-d)-(b+a*x)*(-d+c*x)",
"0",
//++-+
"factor((+a*x+b)*(-c*x+d),x)",
"-(b+a*x)*(-d+c*x)",
"(+a*x+b)*(-c*x+d)+(b+a*x)*(-d+c*x)",
"0",
//++--
"factor((+a*x+b)*(-c*x-d),x)",
"-(b+a*x)*(d+c*x)",
"(+a*x+b)*(-c*x-d)+(b+a*x)*(d+c*x)",
"0",
//+-++
"factor((+a*x-b)*(+c*x+d),x)",
"(d+c*x)*(-b+a*x)",
"(+a*x-b)*(+c*x+d)-(d+c*x)*(-b+a*x)",
"0",
//+-+-
"factor((+a*x-b)*(+c*x-d),x)",
"(-b+a*x)*(-d+c*x)",
"(+a*x-b)*(+c*x-d)-(-b+a*x)*(-d+c*x)",
"0",
//+--+
"factor((+a*x-b)*(-c*x+d),x)",
"-(-b+a*x)*(-d+c*x)",
"(+a*x-b)*(-c*x+d)+(-b+a*x)*(-d+c*x)",
"0",
//+---
"factor((+a*x-b)*(-c*x-d),x)",
"-(d+c*x)*(-b+a*x)",
"(+a*x-b)*(-c*x-d)+(d+c*x)*(-b+a*x)",
"0",
//-+++
"factor((-a*x+b)*(+c*x+d),x)",
"-(d+c*x)*(-b+a*x)",
"(-a*x+b)*(+c*x+d)+(d+c*x)*(-b+a*x)",
"0",
//-++-
"factor((-a*x+b)*(+c*x-d),x)",
"-(-b+a*x)*(-d+c*x)",
"(-a*x+b)*(+c*x-d)+(-b+a*x)*(-d+c*x)",
"0",
//-+-+
"factor((-a*x+b)*(-c*x+d),x)",
"(-b+a*x)*(-d+c*x)",
"(-a*x+b)*(-c*x+d)-(-b+a*x)*(-d+c*x)",
"0",
//-+--
"factor((-a*x+b)*(-c*x-d),x)",
"(d+c*x)*(-b+a*x)",
"(-a*x+b)*(-c*x-d)-(d+c*x)*(-b+a*x)",
"0",
//--++
"factor((-a*x-b)*(+c*x+d),x)",
"-(b+a*x)*(d+c*x)",
"(-a*x-b)*(+c*x+d)+(b+a*x)*(d+c*x)",
"0",
//--+-
"factor((-a*x-b)*(+c*x-d),x)",
"-(b+a*x)*(-d+c*x)",
"(-a*x-b)*(+c*x-d)+(b+a*x)*(-d+c*x)",
"0",
//---+
"factor((-a*x-b)*(-c*x+d),x)",
"(b+a*x)*(-d+c*x)",
"(-a*x-b)*(-c*x+d)-(b+a*x)*(-d+c*x)",
"0",
//----
"factor((-a*x-b)*(-c*x-d),x)",
"(b+a*x)*(d+c*x)",
"(-a*x-b)*(-c*x-d)-(b+a*x)*(d+c*x)",
"0",
// this used to cause divide by zero
// fixed by calling ispoly before calling coeff
2006-04-26 00:29:29 +02:00
// "factor(1/x+1)",
// "(1+x)/x",
2004-03-03 21:24:06 +01:00
// see if poly gets rationalized
2006-04-26 00:29:29 +02:00
// "(x+1)(x+2)(x+3)/x^3",
// "1+6/(x^3)+11/(x^2)+6/x",
2004-03-03 21:24:06 +01:00
2006-04-26 00:29:29 +02:00
// "factor(last)",
// "(1+x)*(2+x)*(3+x)/(x^3)",
2004-03-03 21:24:06 +01:00
// this used to fail
"factor(x,x)",
"x",
"factor(x^2,x)",
"x^2",
"factor(x^3,x)",
"x^3",
2006-02-10 18:01:28 +01:00
"bake=1",
"",
2006-11-22 03:42:38 +01:00
"y=(x+1)(x+2)",
"",
"factor(y,z)",
"x^2+3*x+2",
"factor(y,y)",
"Stop: factor: 2nd arg?",
"y=x^2+exp(x)",
"",
"factor(y)",
"Stop: factor: 1st arg?",
2004-03-03 21:24:06 +01:00
};
void
test_factorpoly(void)
{
test(__FILE__, s, sizeof s / sizeof (char *));
}
2007-05-08 16:57:30 +02:00
#endif