algebrite
Version:
Computer Algebra System in Coffeescript
307 lines (240 loc) • 5.5 kB
text/coffeescript
# Greatest common denominator
# can also be run on polynomials, however
# it works only on the integers and it works
# by factoring the polynomials (not Euclidean algorithm)
Eval_gcd = ->
p1 = cdr(p1)
push(car(p1))
Eval()
p1 = cdr(p1)
while (iscons(p1))
push(car(p1))
Eval()
gcd()
p1 = cdr(p1)
gcd = ->
prev_expanding = expanding
save()
gcd_main()
restore()
expanding = prev_expanding
gcd_main = ->
expanding = 1
p2 = pop()
p1 = pop()
if DEBUG then console.log "gcd_main: p1: " + p1 + " p2: " + p2
if (equal(p1, p2))
push(p1)
return
if (isrational(p1) && isrational(p2))
push(p1)
push(p2)
gcd_numbers()
return
if (polyVar = areunivarpolysfactoredorexpandedform(p1, p2))
gcd_polys(polyVar)
return
if (car(p1) == symbol(ADD) && car(p2) == symbol(ADD))
gcd_sum_sum()
return
if (car(p1) == symbol(ADD))
gcd_sum(p1)
p1 = pop()
if (car(p2) == symbol(ADD))
gcd_sum(p2)
p2 = pop()
if (car(p1) == symbol(MULTIPLY))
gcd_sum_product()
return
if (car(p2) == symbol(MULTIPLY))
gcd_product_sum()
return
if (car(p1) == symbol(MULTIPLY) && car(p2) == symbol(MULTIPLY))
gcd_product_product()
return
gcd_powers_with_same_base()
areunivarpolysfactoredorexpandedform = (p1, p2) ->
if DEBUG then console.log "areunivarpolysfactoredorexpandedform: p1: " + p1 + " p2: " + p2
if polyVar = isunivarpolyfactoredorexpandedform(p1)
if isunivarpolyfactoredorexpandedform(p2,polyVar)
return polyVar
return false
gcd_polys = (polyVar) ->
if DEBUG then console.log "gcd_polys: p1: " + p1 + " polyVar: " + polyVar
# gcd of factors
push(p1)
push polyVar
factorpoly()
p1 = pop()
push(p2)
push polyVar
factorpoly()
p2 = pop()
if DEBUG then console.log "GCD: factored polys:"
if DEBUG then console.log " p1:" + p1.toString()
if DEBUG then console.log " p2:" + p2.toString()
# In case one of two polynomials can be factored,
# (and only in that case), then
# we'll need to run gcd_factors on the two polynomials.
# (In case neither of them can be factored there is no gcd).
# However, gcd_factors expects two _products_ , and
# in case _one_ of the polynomials can't be factored it will look
# like a sum instead of a product.
# So, we'll have to make that sum to look like a factor:
# let's just turn it into a product with 1.
# in case one of the two polys has been factored...
if car(p1) == symbol(MULTIPLY) or car(p2) == symbol(MULTIPLY)
# then make sure that if one of them is a single
# factor, we take the sum and wrap it into a
# multiplication by 1
if car(p1) != symbol(MULTIPLY)
push_symbol(MULTIPLY);
push(p1);
push(one);
list(3);
p1 = pop()
if car(p2) != symbol(MULTIPLY)
push_symbol(MULTIPLY);
push(p2);
push(one);
list(3);
p2 = pop()
if (car(p1) == symbol(MULTIPLY) && car(p2) == symbol(MULTIPLY))
gcd_product_product()
return
gcd_powers_with_same_base()
return true
gcd_product_product = ->
push(one)
p3 = cdr(p1)
while (iscons(p3))
p4 = cdr(p2)
while (iscons(p4))
push(car(p3))
push(car(p4))
gcd()
multiply()
p4 = cdr(p4)
p3 = cdr(p3)
gcd_powers_with_same_base = ->
if (car(p1) == symbol(POWER))
p3 = caddr(p1) # exponent
p1 = cadr(p1) # base
else
p3 = one
if (car(p2) == symbol(POWER))
p4 = caddr(p2) # exponent
p2 = cadr(p2) # base
else
p4 = one
if (!equal(p1, p2))
push(one)
return
# are both exponents numerical?
if (isNumericAtom(p3) && isNumericAtom(p4))
push(p1)
if (lessp(p3, p4))
push(p3)
else
push(p4)
power()
return
# are the exponents multiples of eah other?
push(p3)
push(p4)
divide()
p5 = pop()
if (isNumericAtom(p5))
push(p1)
# choose the smallest exponent
if (car(p3) == symbol(MULTIPLY) && isNumericAtom(cadr(p3)))
p5 = cadr(p3)
else
p5 = one
if (car(p4) == symbol(MULTIPLY) && isNumericAtom(cadr(p4)))
p6 = cadr(p4)
else
p6 = one
if (lessp(p5, p6))
push(p3)
else
push(p4)
power()
return
push(p3)
push(p4)
subtract()
p5 = pop()
if (!isNumericAtom(p5))
push(one)
return
# can't be equal because of test near beginning
push(p1)
if (isnegativenumber(p5))
push(p3)
else
push(p4)
power()
# in this case gcd is used as a composite function, i.e. gcd(gcd(gcd...
gcd_sum_sum = ->
if (length(p1) != length(p2))
push(one)
return
p3 = cdr(p1)
push(car(p3))
p3 = cdr(p3)
while (iscons(p3))
push(car(p3))
gcd()
p3 = cdr(p3)
p3 = pop()
p4 = cdr(p2)
push(car(p4))
p4 = cdr(p4)
while (iscons(p4))
push(car(p4))
gcd()
p4 = cdr(p4)
p4 = pop()
push(p1)
push(p3)
divide()
p5 = pop()
push(p2)
push(p4)
divide()
p6 = pop()
if (equal(p5, p6))
push(p5)
push(p3)
push(p4)
gcd()
multiply()
else
push(one)
gcd_sum = (p) ->
p = cdr(p)
push(car(p))
p = cdr(p)
while (iscons(p))
push(car(p))
gcd()
p = cdr(p)
gcd_sum_product = ->
push(one)
p3 = cdr(p1)
while (iscons(p3))
push(car(p3))
push(p2)
gcd()
multiply()
p3 = cdr(p3)
gcd_product_sum = ->
push(one)
p4 = cdr(p2)
while (iscons(p4))
push(p1)
push(car(p4))
gcd()
multiply()
p4 = cdr(p4)