953 lines
24 KiB
CoffeeScript
953 lines
24 KiB
CoffeeScript
|
|
DEBUG_SIMPLIFY = false
|
|
|
|
Eval_simplify = ->
|
|
push(cadr(p1))
|
|
runUserDefinedSimplifications()
|
|
Eval()
|
|
simplify()
|
|
|
|
runUserDefinedSimplifications = ->
|
|
# -----------------------
|
|
# unfortunately for the time being user
|
|
# specified simplifications are only
|
|
# run in things which don't contain
|
|
# integrals.
|
|
# Doesn't work yet, could be because of
|
|
# some clobbering as "transform" is called
|
|
# recursively?
|
|
if userSimplificationsInListForm.length != 0 and !Find(cadr(p1), symbol(INTEGRAL))
|
|
originalexpanding = expanding
|
|
expanding = false
|
|
if DEBUG_SIMPLIFY then console.log("runUserDefinedSimplifications passed: " + stack[tos-1].toString())
|
|
Eval()
|
|
if DEBUG_SIMPLIFY then console.log("runUserDefinedSimplifications after eval no expanding: " + stack[tos-1].toString())
|
|
expanding = originalexpanding
|
|
|
|
|
|
p1 = stack[tos-1]
|
|
|
|
if DEBUG_SIMPLIFY then console.log "patterns to be checked: "
|
|
for eachSimplification in userSimplificationsInListForm
|
|
if DEBUG_SIMPLIFY then console.log "..." + eachSimplification
|
|
|
|
atLeastOneSuccessInRouldOfRulesApplications = true
|
|
numberOfRulesApplications = 0
|
|
|
|
|
|
while atLeastOneSuccessInRouldOfRulesApplications and numberOfRulesApplications < MAX_CONSECUTIVE_APPLICATIONS_OF_ALL_RULES
|
|
atLeastOneSuccessInRouldOfRulesApplications = false
|
|
numberOfRulesApplications++
|
|
for eachSimplification in userSimplificationsInListForm
|
|
success = true
|
|
eachConsecutiveRuleApplication = 0
|
|
while success and eachConsecutiveRuleApplication < MAX_CONSECUTIVE_APPLICATIONS_OF_SINGLE_RULE
|
|
eachConsecutiveRuleApplication++
|
|
if DEBUG_SIMPLIFY then console.log "simplify - tos: " + tos + " checking pattern: " + eachSimplification + " on: " + p1
|
|
push_symbol(NIL)
|
|
success = transform(eachSimplification, true)
|
|
if success
|
|
atLeastOneSuccessInRouldOfRulesApplications = true
|
|
p1 = stack[tos-1]
|
|
if DEBUG_SIMPLIFY then console.log "p1 at this stage of simplification: " + p1
|
|
if eachConsecutiveRuleApplication == MAX_CONSECUTIVE_APPLICATIONS_OF_SINGLE_RULE
|
|
stop("maximum application of single transformation rule exceeded: " + eachSimplification)
|
|
|
|
if numberOfRulesApplications == MAX_CONSECUTIVE_APPLICATIONS_OF_ALL_RULES
|
|
stop("maximum application of all transformation rules exceeded ")
|
|
|
|
if DEBUG_SIMPLIFY then console.log "METAX = " + get_binding(symbol(METAX))
|
|
if DEBUG_SIMPLIFY then console.log "METAA = " + get_binding(symbol(METAA))
|
|
if DEBUG_SIMPLIFY then console.log "METAB = " + get_binding(symbol(METAB))
|
|
|
|
# ------------------------
|
|
|
|
simplifyForCodeGeneration = ->
|
|
save()
|
|
runUserDefinedSimplifications()
|
|
codeGen = true
|
|
# in "codeGen" mode we completely
|
|
# eval and simplify the function bodies
|
|
# because we really want to resolve all
|
|
# the variables indirections and apply
|
|
# all the simplifications we can.
|
|
simplify_main()
|
|
codeGen = false
|
|
restore()
|
|
|
|
simplify = ->
|
|
save()
|
|
simplify_main()
|
|
restore()
|
|
|
|
simplify_main = ->
|
|
p1 = pop()
|
|
|
|
# when we do code generation, we proceed to
|
|
# fully evaluate and simplify the body of
|
|
# a function, so we resolve all variables
|
|
# indirections and we simplify everything
|
|
# we can given the current assignments.
|
|
if codeGen and car(p1) == symbol(FUNCTION)
|
|
fbody = cadr(p1)
|
|
push fbody
|
|
# let's simplify the body so we give it a
|
|
# compact form
|
|
eval()
|
|
simplify()
|
|
p3 = pop()
|
|
|
|
# replace the evaled body
|
|
args = caddr(p1); # p5 is B
|
|
|
|
push_symbol(FUNCTION)
|
|
push p3
|
|
push args
|
|
list(3)
|
|
p1 = pop()
|
|
|
|
if (istensor(p1))
|
|
simplify_tensor()
|
|
return
|
|
|
|
if (Find(p1, symbol(FACTORIAL)))
|
|
push(p1)
|
|
simfac()
|
|
p2 = pop()
|
|
push(p1)
|
|
rationalize()
|
|
simfac()
|
|
p3 = pop()
|
|
if (count(p2) < count(p3))
|
|
p1 = p2
|
|
else
|
|
p1 = p3
|
|
|
|
f10()
|
|
if DEBUG_SIMPLIFY then console.log "f10: " + p1.toString()
|
|
f1()
|
|
if DEBUG_SIMPLIFY then console.log "f1: " + p1.toString()
|
|
f2()
|
|
if DEBUG_SIMPLIFY then console.log "f2: " + p1.toString()
|
|
f3()
|
|
if DEBUG_SIMPLIFY then console.log "f3: " + p1.toString()
|
|
f4()
|
|
if DEBUG_SIMPLIFY then console.log "f4: " + p1.toString()
|
|
f5()
|
|
if DEBUG_SIMPLIFY then console.log "f5: " + p1.toString()
|
|
f9()
|
|
if DEBUG_SIMPLIFY then console.log "f9: " + p1.toString()
|
|
simplify_polarRect()
|
|
if do_simplify_nested_radicals
|
|
# if there is some de-nesting then
|
|
# re-run a simplification because
|
|
# the shape of the expression might
|
|
# have changed significantly.
|
|
# e.g. simplify(14^(1/2) - (16 - 4*7^(1/2))^(1/2))
|
|
# needs some more semplification after the de-nesting.
|
|
if simplify_nested_radicals()
|
|
if DEBUG_SIMPLIFY then console.log("de-nesting successful into: " + p1.toString())
|
|
push(p1)
|
|
simplify()
|
|
return
|
|
|
|
simplify_rectToClock()
|
|
simplify_rational_expressions()
|
|
|
|
push(p1)
|
|
|
|
simplify_tensor = ->
|
|
i = 0
|
|
p2 = alloc_tensor(p1.tensor.nelem)
|
|
p2.tensor.ndim = p1.tensor.ndim
|
|
for i in [0...p1.tensor.ndim]
|
|
p2.tensor.dim[i] = p1.tensor.dim[i]
|
|
for i in [0...p1.tensor.nelem]
|
|
push(p1.tensor.elem[i])
|
|
simplify()
|
|
p2.tensor.elem[i] = pop()
|
|
|
|
check_tensor_dimensions p2
|
|
|
|
if (isZeroAtomOrTensor(p2))
|
|
p2 = zero; # null tensor becomes scalar zero
|
|
push(p2)
|
|
|
|
|
|
# try rationalizing
|
|
|
|
f1 = ->
|
|
if (car(p1) != symbol(ADD))
|
|
return
|
|
push(p1)
|
|
rationalize()
|
|
p2 = pop()
|
|
if (count(p2) < count(p1))
|
|
p1 = p2
|
|
|
|
# try condensing
|
|
|
|
f2 = ->
|
|
if (car(p1) != symbol(ADD))
|
|
return
|
|
push(p1)
|
|
Condense()
|
|
p2 = pop()
|
|
if (count(p2) <= count(p1))
|
|
p1 = p2
|
|
|
|
# this simplifies forms like (A-B) / (B-A)
|
|
|
|
f3 = ->
|
|
push(p1)
|
|
rationalize()
|
|
negate()
|
|
rationalize()
|
|
negate()
|
|
rationalize()
|
|
p2 = pop()
|
|
if (count(p2) < count(p1))
|
|
p1 = p2
|
|
|
|
|
|
f10 = ->
|
|
|
|
carp1 = car(p1)
|
|
miao = cdr(p1)
|
|
if ( carp1 == symbol(MULTIPLY) || isinnerordot(p1))
|
|
# both operands a transpose?
|
|
|
|
if (car(car(cdr(p1))) == symbol(TRANSPOSE)) and (car(car(cdr(cdr(p1)))) == symbol(TRANSPOSE))
|
|
if DEBUG_SIMPLIFY then console.log "maybe collecting a transpose " + p1
|
|
a = cadr(car(cdr(p1)))
|
|
b = cadr(car(cdr(cdr(p1))))
|
|
if carp1 == symbol(MULTIPLY)
|
|
push(a)
|
|
push(b)
|
|
multiply()
|
|
else if isinnerordot(p1)
|
|
push(b)
|
|
push(a)
|
|
inner()
|
|
push_integer(1)
|
|
push_integer(2)
|
|
originalexpanding = expanding
|
|
expanding = false
|
|
transpose()
|
|
expanding = originalexpanding
|
|
|
|
p2 = pop()
|
|
if (count(p2) < count(p1))
|
|
p1 = p2
|
|
if DEBUG_SIMPLIFY then console.log "collecting a transpose " + p2
|
|
|
|
# try expanding denominators
|
|
|
|
f4 = ->
|
|
if (isZeroAtomOrTensor(p1))
|
|
return
|
|
push(p1)
|
|
rationalize()
|
|
inverse()
|
|
rationalize()
|
|
inverse()
|
|
rationalize()
|
|
p2 = pop()
|
|
if (count(p2) < count(p1))
|
|
p1 = p2
|
|
|
|
# simplifies trig forms
|
|
|
|
simplify_trig = ->
|
|
save()
|
|
p1 = pop()
|
|
f5()
|
|
push(p1)
|
|
restore()
|
|
|
|
f5 = ->
|
|
if (Find(p1, symbol(SIN)) == 0 && Find(p1, symbol(COS)) == 0)
|
|
return
|
|
|
|
p2 = p1
|
|
|
|
trigmode = 1
|
|
push(p2)
|
|
Eval()
|
|
p3 = pop()
|
|
|
|
trigmode = 2
|
|
push(p2)
|
|
Eval()
|
|
p4 = pop()
|
|
|
|
trigmode = 0
|
|
|
|
if (count(p4) < count(p3) || nterms(p4) < nterms(p3))
|
|
p3 = p4
|
|
|
|
if (count(p3) < count(p1) || nterms(p3) < nterms(p1))
|
|
p1 = p3
|
|
|
|
# if it's a sum then try to simplify each term
|
|
|
|
f9 = ->
|
|
if (car(p1) != symbol(ADD))
|
|
return
|
|
push_integer(0)
|
|
p2 = cdr(p1)
|
|
while (iscons(p2))
|
|
push(car(p2))
|
|
simplify()
|
|
add()
|
|
|
|
oldp1 = p1
|
|
oldp2 = p2
|
|
p1 = pop()
|
|
simplify_rational_expressions()
|
|
push(p1)
|
|
p1 = oldp1
|
|
p2 = oldp2
|
|
|
|
p2 = cdr(p2)
|
|
p2 = pop()
|
|
if (count(p2) < count(p1))
|
|
p1 = p2
|
|
|
|
|
|
simplify_rational_expressions = ->
|
|
push p1
|
|
denominator()
|
|
denom = pop()
|
|
|
|
if isone(denom)
|
|
return
|
|
|
|
push p1
|
|
numerator()
|
|
num = pop()
|
|
|
|
if isone(num)
|
|
return
|
|
|
|
if !(polyVar = areunivarpolysfactoredorexpandedform(num, denom))
|
|
return
|
|
|
|
push num
|
|
push denom
|
|
gcd()
|
|
|
|
push(polyVar)
|
|
factor()
|
|
|
|
theGCD = pop()
|
|
|
|
# if there are no common factors then
|
|
# bail
|
|
if isone(theGCD)
|
|
return
|
|
|
|
push num
|
|
push(polyVar)
|
|
factor()
|
|
push theGCD
|
|
#divide()
|
|
inverse()
|
|
multiply_noexpand()
|
|
simplify()
|
|
sasa = stack[tos-1].toString()
|
|
|
|
push denom
|
|
push(polyVar)
|
|
factor()
|
|
push theGCD
|
|
#divide()
|
|
inverse()
|
|
multiply_noexpand()
|
|
simplify()
|
|
sasa = stack[tos-1].toString()
|
|
|
|
divide()
|
|
#simplify()
|
|
Condense()
|
|
sasa = stack[tos-1].toString()
|
|
|
|
p2 = pop()
|
|
if (count(p2) < count(p1))
|
|
p1 = p2
|
|
|
|
|
|
# things like 6*(cos(2/9*pi)+i*sin(2/9*pi))
|
|
# where we have sin and cos, those might start to
|
|
# look better in clock form i.e. 6*(-1)^(2/9)
|
|
simplify_rectToClock = ->
|
|
#debugger
|
|
|
|
if (Find(p1, symbol(SIN)) == 0 && Find(p1, symbol(COS)) == 0)
|
|
return
|
|
|
|
push(p1)
|
|
Eval()
|
|
clockform()
|
|
|
|
p2 = pop(); # put new (hopefully simplified expr) in p2
|
|
if DEBUG_SIMPLIFY then console.log "before simplification clockform: " + p1 + " after: " + p2
|
|
|
|
if (count(p2) < count(p1))
|
|
p1 = p2
|
|
|
|
simplify_polarRect = ->
|
|
push(p1)
|
|
|
|
polarRectAMinusOneBase()
|
|
Eval()
|
|
|
|
p2 = pop(); # put new (hopefully simplified expr) in p2
|
|
|
|
if (count(p2) < count(p1))
|
|
p1 = p2
|
|
|
|
polarRectAMinusOneBase = ->
|
|
save()
|
|
p1 = pop()
|
|
|
|
if isimaginaryunit(p1)
|
|
push(p1)
|
|
restore()
|
|
return
|
|
|
|
if (equal(car(p1), symbol(POWER)) and isminusone(cadr(p1)) )
|
|
|
|
# base we just said is minus 1
|
|
push(one)
|
|
negate()
|
|
|
|
# exponent
|
|
push(caddr(p1))
|
|
polarRectAMinusOneBase()
|
|
|
|
power()
|
|
# try to simplify it using polar and rect
|
|
polar()
|
|
rect()
|
|
|
|
else if (iscons(p1))
|
|
h = tos
|
|
while (iscons(p1))
|
|
#console.log("recursing on: " + car(p1).toString())
|
|
push(car(p1))
|
|
polarRectAMinusOneBase()
|
|
#console.log("...transformed into: " + stack[tos-1].toString())
|
|
p1 = cdr(p1)
|
|
list(tos - h)
|
|
else
|
|
push(p1)
|
|
|
|
restore()
|
|
return
|
|
|
|
nterms = (p) ->
|
|
if (car(p) != symbol(ADD))
|
|
return 1
|
|
else
|
|
return length(p) - 1
|
|
|
|
simplify_nested_radicals = ->
|
|
if recursionLevelNestedRadicalsRemoval > 0
|
|
if DEBUG_SIMPLIFY then console.log("denesting bailing out because of too much recursion")
|
|
return false
|
|
|
|
push(p1)
|
|
somethingSimplified = take_care_of_nested_radicals()
|
|
|
|
|
|
# in this paragraph we check whether we can collect
|
|
# common factors without complicating the expression
|
|
# in particular we want to avoid
|
|
# collecting radicals like in this case where
|
|
# we collect sqrt(2):
|
|
# 2-2^(1/2) into 2^(1/2)*(-1+2^(1/2))
|
|
# but we do like to collect other non-radicals e.g.
|
|
# 17/2+3/2*5^(1/2) into 1/2*(17+3*5^(1/2))
|
|
# so what we do is we count the powers and we check
|
|
# which version has the least number of them.
|
|
simplificationWithoutCondense = stack[tos-1]
|
|
|
|
prev_expanding = expanding
|
|
expanding = 0
|
|
yycondense()
|
|
expanding = prev_expanding
|
|
|
|
simplificationWithCondense = pop()
|
|
#console.log("occurrences of powers in " + simplificationWithoutCondense + " :" + countOccurrencesOfSymbol(symbol(POWER),simplificationWithoutCondense))
|
|
#console.log("occurrences of powers in " + simplificationWithCondense + " :" + countOccurrencesOfSymbol(symbol(POWER),simplificationWithCondense))
|
|
|
|
if (countOccurrencesOfSymbol(symbol(POWER),simplificationWithoutCondense) < countOccurrencesOfSymbol(symbol(POWER),simplificationWithCondense))
|
|
push(simplificationWithoutCondense)
|
|
else
|
|
push(simplificationWithCondense)
|
|
|
|
|
|
# we got out result, wrap up
|
|
p1 = pop()
|
|
return somethingSimplified
|
|
|
|
take_care_of_nested_radicals = ->
|
|
if recursionLevelNestedRadicalsRemoval > 0
|
|
if DEBUG_SIMPLIFY then console.log("denesting bailing out because of too much recursion")
|
|
return false
|
|
|
|
|
|
save()
|
|
p1 = pop()
|
|
#console.log("take_care_of_nested_radicals p1: " + p1.toString())
|
|
|
|
if equal(car(p1), symbol(POWER))
|
|
|
|
#console.log("ok it's a power ")
|
|
base = cadr(p1)
|
|
exponent = caddr(p1)
|
|
#console.log("possible double radical base: " + base)
|
|
#console.log("possible double radical exponent: " + exponent)
|
|
|
|
if !isminusone(exponent) and equal(car(base), symbol(ADD)) and isfraction(exponent) and (equalq(exponent,1,3) or equalq(exponent,1,2))
|
|
|
|
#console.log("ok there is a radix with a term inside")
|
|
firstTerm = cadr(base)
|
|
push(firstTerm)
|
|
take_care_of_nested_radicals()
|
|
pop()
|
|
secondTerm = caddr(base)
|
|
push(secondTerm)
|
|
take_care_of_nested_radicals()
|
|
pop()
|
|
|
|
#console.log("possible double radical term1: " + firstTerm)
|
|
#console.log("possible double radical term2: " + secondTerm)
|
|
|
|
numberOfTerms = 0
|
|
countingTerms = base
|
|
while (cdr(countingTerms) != symbol(NIL))
|
|
numberOfTerms++
|
|
countingTerms = cdr(countingTerms)
|
|
#console.log("number of terms: " + numberOfTerms)
|
|
if numberOfTerms > 2
|
|
#console.log("too many terms under outer radix ")
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
|
|
|
|
# list here all the factors
|
|
commonInnerExponent = null
|
|
commonBases = []
|
|
termsThatAreNotPowers = []
|
|
if (car(secondTerm) == symbol(MULTIPLY))
|
|
# product of factors
|
|
secondTermFactor = cdr(secondTerm)
|
|
if iscons(secondTermFactor)
|
|
while (iscons(secondTermFactor))
|
|
#console.log("second term factor BIS: " + car(secondTermFactor).toString())
|
|
potentialPower = car(secondTermFactor)
|
|
if (car(potentialPower) == symbol(POWER))
|
|
innerbase = cadr(potentialPower)
|
|
innerexponent = caddr(potentialPower)
|
|
if equalq(innerexponent,1,2)
|
|
#console.log("tackling double radical 1: " + p1.toString())
|
|
if !commonInnerExponent?
|
|
commonInnerExponent = innerexponent
|
|
commonBases.push(innerbase)
|
|
else
|
|
if equal(innerexponent, commonInnerExponent)
|
|
#console.log("common base: " + innerbase.toString())
|
|
commonBases.push(innerbase)
|
|
else
|
|
#console.log("no common bases here ")
|
|
#console.log("this one is a power base: " + innerbase + " , exponent: " + innerexponent)
|
|
else
|
|
termsThatAreNotPowers.push(potentialPower)
|
|
secondTermFactor = cdr(secondTermFactor)
|
|
else if (car(secondTerm) == symbol(POWER))
|
|
innerbase = cadr(secondTerm)
|
|
innerexponent = caddr(secondTerm)
|
|
if !commonInnerExponent? and equalq(innerexponent,1,2)
|
|
#console.log("tackling double radical 2: " + p1.toString())
|
|
commonInnerExponent = innerexponent
|
|
commonBases.push(innerbase)
|
|
|
|
|
|
if commonBases.length == 0
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
|
|
A = firstTerm
|
|
#console.log("A: " + A.toString())
|
|
|
|
push_integer(1)
|
|
for i in commonBases
|
|
push(i)
|
|
multiply()
|
|
#console.log("basis with common exponent: " + i.toString())
|
|
C = pop()
|
|
#console.log("C: " + C.toString())
|
|
|
|
push_integer(1)
|
|
for i in termsThatAreNotPowers
|
|
push(i)
|
|
multiply()
|
|
#console.log("terms that are not powers: " + i.toString())
|
|
B = pop()
|
|
#console.log("B: " + B.toString())
|
|
|
|
|
|
if equalq(exponent,1,3)
|
|
push(A)
|
|
negate()
|
|
push(C)
|
|
multiply()
|
|
push(B)
|
|
divide() # 4th coeff
|
|
#console.log("constant coeff " + stack[tos-1].toString())
|
|
checkSize = pop()
|
|
push(checkSize)
|
|
real()
|
|
yyfloat()
|
|
if Math.abs(pop().d) > Math.pow(2, 32)
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
push(checkSize)
|
|
|
|
push_integer(3)
|
|
push(C)
|
|
multiply() # 3rd coeff
|
|
#console.log("next coeff " + stack[tos-1].toString())
|
|
checkSize = pop()
|
|
push(checkSize)
|
|
real()
|
|
yyfloat()
|
|
if Math.abs(pop().d) > Math.pow(2, 32)
|
|
pop()
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
push(checkSize)
|
|
|
|
push(symbol(SECRETX))
|
|
multiply()
|
|
|
|
|
|
push_integer(-3)
|
|
push(A)
|
|
multiply()
|
|
push(B)
|
|
divide() # 2nd coeff
|
|
checkSize = pop()
|
|
push(checkSize)
|
|
real()
|
|
yyfloat()
|
|
if Math.abs(pop().d) > Math.pow(2, 32)
|
|
pop()
|
|
pop()
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
push(checkSize)
|
|
|
|
#console.log("next coeff " + stack[tos-1].toString())
|
|
push(symbol(SECRETX))
|
|
push_integer(2)
|
|
power()
|
|
multiply()
|
|
|
|
push_integer(1) # 1st coeff
|
|
#console.log("next coeff " + stack[tos-1].toString())
|
|
push(symbol(SECRETX))
|
|
push_integer(3)
|
|
power()
|
|
multiply()
|
|
|
|
add()
|
|
add()
|
|
add()
|
|
|
|
else if equalq(exponent,1,2)
|
|
push(C) # 3th coeff
|
|
checkSize = pop()
|
|
push(checkSize)
|
|
real()
|
|
yyfloat()
|
|
if Math.abs(pop().d) > Math.pow(2, 32)
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
push(checkSize)
|
|
#console.log("constant coeff " + stack[tos-1].toString())
|
|
|
|
push_integer(-2)
|
|
push(A)
|
|
multiply()
|
|
push(B)
|
|
divide() # 2nd coeff
|
|
checkSize = pop()
|
|
push(checkSize)
|
|
real()
|
|
yyfloat()
|
|
if Math.abs(pop().d) > Math.pow(2, 32)
|
|
pop()
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
push(checkSize)
|
|
|
|
#console.log("next coeff " + stack[tos-1].toString())
|
|
push(symbol(SECRETX))
|
|
multiply()
|
|
|
|
|
|
push_integer(1) # 1st coeff
|
|
#console.log("next coeff " + stack[tos-1].toString())
|
|
push(symbol(SECRETX))
|
|
push_integer(2)
|
|
power()
|
|
multiply()
|
|
|
|
add()
|
|
add()
|
|
|
|
#console.log("whole polynomial: " + stack[tos-1].toString())
|
|
|
|
push(symbol(SECRETX))
|
|
|
|
|
|
recursionLevelNestedRadicalsRemoval++
|
|
#console.log("invoking roots at recursion level: " + recursionLevelNestedRadicalsRemoval)
|
|
roots()
|
|
recursionLevelNestedRadicalsRemoval--
|
|
if equal(stack[tos-1], symbol(NIL))
|
|
if DEBUG_SIMPLIFY then console.log("roots bailed out because of too much recursion")
|
|
pop()
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
|
|
#console.log("all solutions: " + stack[tos-1].toString())
|
|
|
|
# exclude the solutions with radicals
|
|
possibleSolutions = []
|
|
for eachSolution in stack[tos-1].tensor.elem
|
|
if !Find(eachSolution, symbol(POWER))
|
|
possibleSolutions.push(eachSolution)
|
|
|
|
pop() # popping the tensor with the solutions
|
|
|
|
#console.log("possible solutions: " + possibleSolutions.toString())
|
|
if possibleSolutions.length == 0
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
|
|
possibleRationalSolutions = []
|
|
realOfpossibleRationalSolutions = []
|
|
#console.log("checking the one with maximum real part ")
|
|
for i in possibleSolutions
|
|
push(i)
|
|
real()
|
|
yyfloat()
|
|
possibleRationalSolutions.push(i)
|
|
realOfpossibleRationalSolutions.push(pop().d)
|
|
|
|
whichRationalSolution = realOfpossibleRationalSolutions.indexOf(Math.max.apply(Math, realOfpossibleRationalSolutions))
|
|
SOLUTION = possibleRationalSolutions[whichRationalSolution]
|
|
#console.log("picked solution: " + SOLUTION)
|
|
|
|
|
|
###
|
|
#possibleNewExpressions = []
|
|
#realOfPossibleNewExpressions = []
|
|
# pick the solution which cubic root has no radicals
|
|
lowercase_b = null
|
|
for SOLUTION in possibleSolutions
|
|
console.log("testing solution: " + SOLUTION.toString())
|
|
|
|
debugger
|
|
if equalq(exponent,1,3)
|
|
push(A)
|
|
push(SOLUTION)
|
|
push_integer(3)
|
|
power()
|
|
push_integer(3)
|
|
push(C)
|
|
multiply()
|
|
push(SOLUTION)
|
|
multiply()
|
|
add()
|
|
divide()
|
|
console.log("argument of cubic root: " + stack[tos-1].toString())
|
|
push_rational(1,3)
|
|
power()
|
|
else if equalq(exponent,1,2)
|
|
push(A)
|
|
push(SOLUTION)
|
|
push_integer(2)
|
|
power()
|
|
push(C)
|
|
add()
|
|
divide()
|
|
console.log("argument of cubic root: " + stack[tos-1].toString())
|
|
push_rational(1,2)
|
|
power()
|
|
console.log("b is: " + stack[tos-1].toString())
|
|
|
|
lowercase_b = pop()
|
|
|
|
if !Find(lowercase_b, symbol(POWER))
|
|
break
|
|
###
|
|
|
|
if equalq(exponent,1,3)
|
|
push(A)
|
|
push(SOLUTION)
|
|
push_integer(3)
|
|
power()
|
|
push_integer(3)
|
|
push(C)
|
|
multiply()
|
|
push(SOLUTION)
|
|
multiply()
|
|
add()
|
|
divide()
|
|
#console.log("argument of cubic root: " + stack[tos-1].toString())
|
|
push_rational(1,3)
|
|
power()
|
|
else if equalq(exponent,1,2)
|
|
push(A)
|
|
push(SOLUTION)
|
|
push_integer(2)
|
|
power()
|
|
push(C)
|
|
add()
|
|
divide()
|
|
#console.log("argument of cubic root: " + stack[tos-1].toString())
|
|
push_rational(1,2)
|
|
power()
|
|
#console.log("b is: " + stack[tos-1].toString())
|
|
|
|
lowercase_b = pop()
|
|
|
|
|
|
if !lowercase_b?
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
|
|
push(lowercase_b)
|
|
push(SOLUTION)
|
|
multiply()
|
|
|
|
|
|
if equalq(exponent,1,3)
|
|
#console.log("a is: " + stack[tos-1].toString())
|
|
|
|
lowercase_a = pop()
|
|
|
|
push(lowercase_b)
|
|
push(C)
|
|
push_rational(1,2)
|
|
power()
|
|
multiply()
|
|
|
|
push(lowercase_a)
|
|
add()
|
|
simplify()
|
|
else if equalq(exponent,1,2)
|
|
#console.log("a could be: " + stack[tos-1].toString())
|
|
|
|
lowercase_a = pop()
|
|
|
|
push(lowercase_b)
|
|
push(C)
|
|
push_rational(1,2)
|
|
power()
|
|
multiply()
|
|
|
|
push(lowercase_a)
|
|
add()
|
|
simplify()
|
|
possibleNewExpression = pop()
|
|
#console.log("verifying if " + possibleNewExpression + " is positive")
|
|
push(possibleNewExpression)
|
|
real()
|
|
yyfloat()
|
|
possibleNewExpressionValue = pop()
|
|
if !isnegativenumber(possibleNewExpressionValue)
|
|
#console.log("... it is positive")
|
|
push(possibleNewExpression)
|
|
else
|
|
#console.log("... it is NOT positive")
|
|
push(lowercase_b)
|
|
negate()
|
|
lowercase_b = pop()
|
|
|
|
push(lowercase_a)
|
|
negate()
|
|
lowercase_a = pop()
|
|
|
|
|
|
push(lowercase_b)
|
|
push(C)
|
|
push_rational(1,2)
|
|
power()
|
|
multiply()
|
|
|
|
push(lowercase_a)
|
|
add()
|
|
simplify()
|
|
# possibleNewExpression is now at top of stack
|
|
|
|
|
|
#console.log("potential new expression: " + stack[tos-1].toString())
|
|
p1 = pop()
|
|
#newExpression = pop()
|
|
#debugger
|
|
#push(newExpression)
|
|
#real()
|
|
#yyfloat()
|
|
#possibleNewExpressions.push(newExpression)
|
|
#realOfPossibleNewExpressions.push(pop().d)
|
|
|
|
#whichExpression = realOfPossibleNewExpressions.indexOf(Math.max.apply(Math, realOfPossibleNewExpressions))
|
|
#p1 = possibleNewExpressions[whichExpression]
|
|
#console.log("final new expression: " + p1.toString())
|
|
|
|
push(p1)
|
|
restore()
|
|
return true
|
|
|
|
|
|
|
|
else
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
|
|
else if (iscons(p1))
|
|
h = tos
|
|
anyRadicalSimplificationWorked = false
|
|
while (iscons(p1))
|
|
#console.log("recursing on: " + car(p1).toString())
|
|
push(car(p1))
|
|
anyRadicalSimplificationWorked = anyRadicalSimplificationWorked or take_care_of_nested_radicals()
|
|
#console.log("...transformed into: " + stack[tos-1].toString())
|
|
p1 = cdr(p1)
|
|
list(tos - h)
|
|
restore()
|
|
return anyRadicalSimplificationWorked
|
|
else
|
|
push(p1)
|
|
restore()
|
|
return false
|
|
|
|
throw new Error("control flow should never reach here")
|