algebrite
Version:
Computer Algebra System in Coffeescript
575 lines (456 loc) • 9.83 kB
text/coffeescript
multiply = ->
if (esc_flag)
stop("escape key stop")
if (isnum(stack[tos - 2]) && isnum(stack[tos - 1]))
multiply_numbers()
else
save()
yymultiply()
restore()
yymultiply = ->
h = 0
i = 0
n = 0
p2 = pop()
p1 = pop()
h = tos
if (iszero(p1) || iszero(p2))
push(zero)
return
if (expanding && isadd(p1))
p1 = cdr(p1)
push(zero)
while (iscons(p1))
push(car(p1))
push(p2)
multiply()
add()
p1 = cdr(p1)
return
if (expanding && isadd(p2))
p2 = cdr(p2)
push(zero)
while (iscons(p2))
push(p1)
push(car(p2))
multiply()
add()
p2 = cdr(p2)
return
if (!istensor(p1) && istensor(p2))
push(p1)
push(p2)
scalar_times_tensor()
return
if (istensor(p1) && !istensor(p2))
push(p1)
push(p2)
tensor_times_scalar()
return
if (car(p1) == symbol(MULTIPLY))
p1 = cdr(p1)
else
push(p1)
list(1)
p1 = pop()
if (car(p2) == symbol(MULTIPLY))
p2 = cdr(p2)
else
push(p2)
list(1)
p2 = pop()
if (isnum(car(p1)) && isnum(car(p2)))
push(car(p1))
push(car(p2))
multiply_numbers()
p1 = cdr(p1)
p2 = cdr(p2)
else if (isnum(car(p1)))
push(car(p1))
p1 = cdr(p1)
else if (isnum(car(p2)))
push(car(p2))
p2 = cdr(p2)
else
push(one)
parse_p1()
parse_p2()
while (iscons(p1) && iscons(p2))
if (caar(p1) == symbol(OPERATOR) && caar(p2) == symbol(OPERATOR))
push_symbol(OPERATOR)
push(cdar(p1))
push(cdar(p2))
append()
cons()
p1 = cdr(p1)
p2 = cdr(p2)
parse_p1()
parse_p2()
continue
switch (cmp_expr(p3, p4))
when -1
push(car(p1))
p1 = cdr(p1)
parse_p1()
when 1
push(car(p2))
p2 = cdr(p2)
parse_p2()
when 0
combine_factors(h)
p1 = cdr(p1)
p2 = cdr(p2)
parse_p1()
parse_p2()
else
stop("internal error 2")
while (iscons(p1))
push(car(p1))
p1 = cdr(p1)
while (iscons(p2))
push(car(p2))
p2 = cdr(p2)
__normalize_radical_factors(h)
if (expanding)
for i in [h...tos]
if (isadd(stack[i]))
multiply_all(tos - h)
return
n = tos - h
if (n == 1)
return
# discard integer 1
if (isrational(stack[h]) && equaln(stack[h], 1))
if (n == 2)
p7 = pop()
pop()
push(p7)
else
stack[h] = symbol(MULTIPLY)
list(n)
return
list(n)
p7 = pop()
push_symbol(MULTIPLY)
push(p7)
cons()
parse_p1 = ->
p3 = car(p1)
p5 = one
if (car(p3) == symbol(POWER))
p5 = caddr(p3)
p3 = cadr(p3)
parse_p2 = ->
p4 = car(p2)
p6 = one
if (car(p4) == symbol(POWER))
p6 = caddr(p4)
p4 = cadr(p4)
combine_factors = (h) ->
push(p4)
push(p5)
push(p6)
add()
power()
p7 = pop()
if (isnum(p7))
push(stack[h])
push(p7)
multiply_numbers()
stack[h] = pop()
else if (car(p7) == symbol(MULTIPLY))
if (isnum(cadr(p7)) && cdddr(p7) == symbol(NIL))
push(stack[h])
push(cadr(p7))
multiply_numbers()
stack[h] = pop()
push(caddr(p7))
else
push(p7)
else
push(p7)
gp = [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]
]
combine_gammas = (h) ->
n = gp[Math.floor(p1.gamma)][Math.floor(p2.gamma)]
if (n < 0)
n = -n
push(stack[h])
negate()
stack[h] = pop()
if (n > 1)
push(_gamma[n])
multiply_noexpand = ->
x = expanding
expanding = 0
multiply()
expanding = x
multiply_all = (n) ->
i = 0
if (n == 1)
return
if (n == 0)
push(one)
return
h = tos - n
push(stack[h])
for i in [1...n]
push(stack[h + i])
multiply()
stack[h] = pop()
tos = h + 1
multiply_all_noexpand = (n) ->
x = expanding
expanding = 0
multiply_all(n)
expanding = x
divide = ->
if (isnum(stack[tos - 2]) && isnum(stack[tos - 1]))
divide_numbers()
else
inverse()
multiply()
inverse = ->
if (isnum(stack[tos - 1]))
invert_number()
else
push_integer(-1)
power()
reciprocate = ->
if (isnum(stack[tos - 1]))
invert_number()
else
push_integer(-1)
power()
negate = ->
if (isnum(stack[tos - 1]))
negate_number()
else
push_integer(-1)
multiply()
negate_expand = ->
x = expanding
expanding = 1
negate()
expanding = x
negate_noexpand = ->
x = expanding
expanding = 0
negate()
expanding = x
__normalize_radical_factors = (h) ->
i = 0
if (isplusone(stack[h]) || isminusone(stack[h]) || isdouble(stack[h]))
return
for i in [(h + 1)...tos]
if (__is_radical_number(stack[i]))
break
if (i == tos)
return
# ok, try to simplify
save()
# numerator
push(stack[h])
mp_numerator()
p1 = pop();
for i in [(h + 1)...tos]
if (isplusone(p1) || isminusone(p1))
break
if (!__is_radical_number(stack[i]))
continue
p3 = cadr(stack[i]);
p4 = caddr(stack[i]);
if (!isnegativenumber(p4))
continue
push(p1);
push(p3);
divide()
p5 = pop();
if (!isinteger(p5))
continue
p1 = p5;
push_symbol(POWER)
push(p3);
push(one)
push(p4);
add()
list(3)
stack[i] = pop()
push(stack[h])
mp_denominator()
p2 = pop();
for i in [(h + 1)...tos]
if (isplusone(p2))
break
if (!__is_radical_number(stack[i]))
continue
p3 = cadr(stack[i]);
p4 = caddr(stack[i]);
if (isnegativenumber(p4))
continue
push(p2);
push(p3);
divide()
p5 = pop();
if (!isinteger(p5))
continue
p2 = p5;
push_symbol(POWER)
push(p3);
push(p4);
push(one)
subtract()
list(3)
stack[i] = pop()
push(p1);
push(p2);
divide()
stack[h] = pop()
restore()
__is_radical_number = (p) ->
if (car(p) == symbol(POWER) && isnum(cadr(p)) && isnum(caddr(p)) && !isminusone(cadr(p)))
return 1
else
return 0