eigenmath/rationalize.cpp

230 lines
3.2 KiB
C++

#include "stdafx.h"
#include "defs.h"
#define DEBUG 0
static void __rationalize_tensor(void);
static void multiply_denominators(U *);
static void multiply_denominators_term(U *);
static void multiply_denominators_factor(U *);
static void __lcm(void);
void
eval_rationalize(void)
{
push(cadr(p1));
eval();
rationalize();
}
void
rationalize(void)
{
int x = expanding;
save();
yyrationalize();
restore();
expanding = x;
}
void
yyrationalize(void)
{
p1 = pop();
if (istensor(p1)) {
__rationalize_tensor();
return;
}
expanding = 0;
if (car(p1) != symbol(ADD)) {
push(p1);
return;
}
#if DEBUG
printf("rationalize: this is the input expr:\n");
printline(p1);
#endif
// get common denominator
push(one);
multiply_denominators(p1);
p2 = pop();
#if DEBUG
printf("rationalize: this is the common denominator:\n");
printline(p2);
#endif
// multiply each term by common denominator
push(zero);
p3 = cdr(p1);
while (iscons(p3)) {
push(p2);
push(car(p3));
multiply();
add();
p3 = cdr(p3);
}
#if DEBUG
printf("rationalize: original expr times common denominator:\n");
printline(stack[tos - 1]);
#endif
// collect common factors
Condense();
#if DEBUG
printf("rationalize: after factoring:\n");
printline(stack[tos - 1]);
#endif
// divide by common denominator
push(p2);
divide();
#if DEBUG
printf("rationalize: after dividing by common denom. (and we're done):\n");
printline(stack[tos - 1]);
#endif
}
static void
multiply_denominators(U *p)
{
if (car(p) == symbol(ADD)) {
p = cdr(p);
while (iscons(p)) {
multiply_denominators_term(car(p));
p = cdr(p);
}
} else
multiply_denominators_term(p);
}
static void
multiply_denominators_term(U *p)
{
if (car(p) == symbol(MULTIPLY)) {
p = cdr(p);
while (iscons(p)) {
multiply_denominators_factor(car(p));
p = cdr(p);
}
} else
multiply_denominators_factor(p);
}
static void
multiply_denominators_factor(U *p)
{
if (car(p) != symbol(POWER))
return;
push(p);
p = caddr(p);
// like x^(-2) ?
if (isnegativenumber(p)) {
inverse();
__lcm();
return;
}
// like x^(-a) ?
if (car(p) == symbol(MULTIPLY) && isnegativenumber(cadr(p))) {
inverse();
__lcm();
return;
}
// no match
pop();
}
static void
__rationalize_tensor(void)
{
int i, n;
push(p1);
eval(); // makes a copy
p1 = pop();
if (!istensor(p1)) { // might be zero
push(p1);
return;
}
n = p1->u.tensor->nelem;
for (i = 0; i < n; i++) {
push(p1->u.tensor->elem[i]);
rationalize();
p1->u.tensor->elem[i] = pop();
}
push(p1);
}
#if SELFTEST
static char *s[] = {
"rationalize(a/b+c/d)",
// "1/b*1/d*(a*d+b*c)",
"(a*d+b*c)/(b*d)",
"rationalize(t*y/(t+y)+2*t^2*y*(2*t+y)^(-2))",
// "t*y*1/(t+y)*(2*t+y)^(-2)*((2*t+y)^2+2*t*(t+y))",
// "t*y*((2*t+y)^2+2*t*(t+y))/((t+y)*(2*t+y)^2)",
// "t*y*(2*t*(t+y)+(2*t+y)^2)/((t+y)*(2*t+y)^2)",
"t*y*(6*t^2+y^2+6*t*y)/((t+y)*(2*t+y)^2)",
"rationalize(x^(-2*a)+x^(-4*a))",
// "x^(-4*a)*(1+x^(2*a))",
"(1+x^(2*a))/(x^(4*a))",
"rationalize(x^(1/3)+x^(2/3))",
"x^(1/3)*(1+x^(1/3))",
};
void
test_rationalize(void)
{
test(__FILE__, s, sizeof s / sizeof (char *));
}
#endif
static void
__lcm(void)
{
save();
p1 = pop();
p2 = pop();
push(p1);
push(p2);
multiply();
push(p1);
push(p2);
gcd();
divide();
restore();
}