Eigenmath/rationalize.cpp

175 lines
2.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;
}
// get common denominator
push(one);
multiply_denominators(p1);
p2 = pop();
// multiply each term by common denominator
push(zero);
p3 = cdr(p1);
while (iscons(p3)) {
push(p2);
push(car(p3));
multiply();
add();
p3 = cdr(p3);
}
// collect common factors
Condense();
// divide by common denominator
push(p2);
divide();
}
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);
}
static void
__lcm(void)
{
save();
p1 = pop();
p2 = pop();
push(p1);
push(p2);
multiply();
push(p1);
push(p2);
gcd();
divide();
restore();
}