algebrite
Version:
Computer Algebra System in Coffeescript
316 lines (265 loc) • 7.94 kB
text/coffeescript
# If the number of args is odd then the last arg is the default result.
# Works like a switch statement. Could also be used for piecewise
# functions? TODO should probably be called "switch"?
Eval_test = ->
orig = p1
p1 = cdr(p1)
while (iscons(p1))
# odd number of parameters means that the
# last argument becomes the default case
# i.e. the one without a test.
if (cdr(p1) == symbol(NIL))
push(car(p1)); # default case
Eval()
return
checkResult = isZeroLikeOrNonZeroLikeOrUndetermined car(p1)
if !checkResult?
# we couldn't determine the result
# of a test. This means we can't conclude
# anything about the result of the
# overall test, so we must bail
# with the unevalled test
push orig
return
else if checkResult
# test succesful, we found out output
push(cadr(p1))
Eval()
return
else
# test unsuccessful, continue to the
# next pair of test,value
p1 = cddr(p1)
# no test matched and there was no
# catch-all case, so we return zero.
push_integer 0
# we test A==B by first subtracting and checking if we symbolically
# get zero. If not, we evaluate to float and check if we get a zero.
# If we get another NUMBER then we know they are different.
# If we get something else, then we don't know and we return the
# unaveluated test, which is the same as saying "maybe".
Eval_testeq = ->
# first try without simplifyng both sides
orig = p1
push(cadr(p1))
Eval()
push(caddr(p1))
Eval()
subtract()
subtractionResult = pop()
# OK so we are doing something tricky here
# we are using isZeroLikeOrNonZeroLikeOrUndetermined to check if the result
# is zero or not zero or unknown.
# isZeroLikeOrNonZeroLikeOrUndetermined has some routines
# to determine the zero-ness/non-zero-ness or
# undeterminate-ness of things so we use
# that here and down below.
checkResult = isZeroLikeOrNonZeroLikeOrUndetermined subtractionResult
if checkResult
push_integer(0)
return
else if checkResult? and !checkResult
push_integer(1)
return
# we didn't get a simple numeric result but
# let's try again after doing
# a simplification on both sides
push(cadr(p1))
Eval()
simplify()
push(caddr(p1))
Eval()
simplify()
subtract()
subtractionResult = pop()
checkResult = isZeroLikeOrNonZeroLikeOrUndetermined subtractionResult
if checkResult
push_integer(0)
return
else if checkResult? and !checkResult
push_integer(1)
return
# if we didn't get to a number then we
# don't know whether the quantities are
# different so do nothing
push orig
# Relational operators expect a numeric result for operand difference.
Eval_testge = ->
orig = p1
comparison = cmp_args()
if !comparison?
push orig
return
if ( comparison >= 0)
push_integer(1)
else
push_integer(0)
Eval_testgt = ->
orig = p1
comparison = cmp_args()
if !comparison?
push orig
return
if ( comparison > 0)
push_integer(1)
else
push_integer(0)
Eval_testle = ->
orig = p1
comparison = cmp_args()
if !comparison?
push orig
return
if ( comparison <= 0)
push_integer(1)
else
push_integer(0)
Eval_testlt = ->
orig = p1
comparison = cmp_args()
if !comparison?
push orig
return
if ( comparison < 0)
push_integer(1)
else
push_integer(0)
# not definition
Eval_not = ->
wholeAndExpression = p1
checkResult = isZeroLikeOrNonZeroLikeOrUndetermined cadr(p1)
if !checkResult?
# inconclusive test on predicate
push wholeAndExpression
else if checkResult
# true -> false
push_integer(0)
else
# false -> true
push_integer(1)
### and =====================================================================
Tags
----
scripting, JS, internal, treenode, general concept
Parameters
----------
a,b,...
General description
-------------------
Logical-and of predicate expressions.
###
# and definition
Eval_and = ->
wholeAndExpression = p1
andPredicates = cdr(wholeAndExpression)
somePredicateUnknown = false
while (iscons(andPredicates))
# eval each predicate
checkResult = isZeroLikeOrNonZeroLikeOrUndetermined car(andPredicates)
if !checkResult?
# here we have stuff that is not reconducible to any
# numeric value (or tensor with numeric values) e.g.
# 'a+b', so it just means that we just don't know the
# truth value of this particular predicate.
# We'll track the fact that we found an unknown
# predicate and we continue with the other predicates.
# (note that in case some subsequent predicate will be false,
# it won't matter that we found some unknowns and
# the whole test will be immediately zero).
somePredicateUnknown = true
andPredicates = cdr(andPredicates)
else if checkResult
# found a true, move on to the next predicate
andPredicates = cdr(andPredicates)
else if !checkResult
# found a false, enough to falsify everything and return
push_integer(0)
return
# We checked all the predicates and none of them
# was false. So they were all either true or unknown.
# Now, if even just one was unknown, we'll have to call this
# test as inconclusive and return the whole test expression.
# If all the predicates were known, then we can conclude
# that the test returns true.
if somePredicateUnknown
push wholeAndExpression
else
push_integer(1)
# or definition
Eval_or = ->
wholeOrExpression = p1
orPredicates = cdr(wholeOrExpression)
somePredicateUnknown = false
while (iscons(orPredicates))
# eval each predicate
checkResult = isZeroLikeOrNonZeroLikeOrUndetermined car(orPredicates)
if !checkResult?
# here we have stuff that is not reconducible to any
# numeric value (or tensor with numeric values) e.g.
# 'a+b', so it just means that we just don't know the
# truth value of this particular predicate.
# We'll track the fact that we found an unknown
# predicate and we continue with the other predicates.
# (note that in case some subsequent predicate will be false,
# it won't matter that we found some unknowns and
# the whole test will be immediately zero).
somePredicateUnknown = true
orPredicates = cdr(orPredicates)
else if checkResult
# found a true, enough to return true
push_integer(1)
return
else if !checkResult
# found a false, move on to the next predicate
orPredicates = cdr(orPredicates)
# We checked all the predicates and none of them
# was true. So they were all either false or unknown.
# Now, if even just one was unknown, we'll have to call this
# test as inconclusive and return the whole test expression.
# If all the predicates were known, then we can conclude
# that the test returns false.
if somePredicateUnknown
push wholeOrExpression
else
push_integer(0)
# use subtract for cases like A < A + 1
# TODO you could be smarter here and
# simplify both sides only in the case
# of "relational operator: cannot determine..."
# a bit like we do in Eval_testeq
cmp_args = ->
t = 0
push(cadr(p1))
Eval()
simplify()
push(caddr(p1))
Eval()
simplify()
subtract()
p1 = pop()
# try floating point if necessary
if (p1.k != NUM && p1.k != DOUBLE)
push(p1)
yyfloat()
Eval()
p1 = pop()
#console.log "comparison: " + p1.toString()
if (isZeroAtomOrTensor(p1))
#console.log "comparison isZero "
return 0
switch (p1.k)
when NUM
if (MSIGN(p1.q.a) == -1)
t = -1
else
t = 1
when DOUBLE
#console.log "comparison p1.d: " + p1.d
if (p1.d < 0.0)
t = -1
else
t = 1
else
#console.log "comparison is null"
t = null
return t