UNPKG

algebrite

Version:

Computer Algebra System in Coffeescript

335 lines (254 loc) 5.77 kB
### Symbolic addition Terms in a sum are combined if they are identical modulo rational coefficients. For example, A + 2A becomes 3A. However, the sum A + sqrt(2) A is not modified. Combining terms can lead to second-order effects. For example, consider the case of 1/sqrt(2) A + 3/sqrt(2) A + sqrt(2) A The first two terms are combined to yield 2 sqrt(2) A. This result can now be combined with the third term to yield 3 sqrt(2) A ### flag = 0 Eval_add = -> h = tos p1 = cdr(p1) while (iscons(p1)) push(car(p1)) Eval() p2 = pop() push_terms(p2) p1 = cdr(p1) add_terms(tos - h) # Add n terms, returns one expression on the stack. stackAddsCount = 0 add_terms = (n) -> stackAddsCount++ i = 0 h = tos - n s = h # ensure no infinite loop, use "for" if DEBUG then console.log "stack before adding terms #" + stackAddsCount #if stackAddsCount == 137 # debugger if DEBUG for i in [0...tos] console.log print_list stack[i] for i in [0...10] if (n < 2) break flag = 0 #qsort(s, n, sizeof (U *), cmp_terms) subsetOfStack = stack.slice(h,h+n) subsetOfStack.sort(cmp_terms) stack = stack.slice(0,h).concat(subsetOfStack).concat(stack.slice(h+n)) if (flag == 0) break n = combine_terms(h, n) moveTos h + n switch (n) when 0 if evaluatingAsFloats then push_double(0.0) else push(zero) when 1 else list(n) p1 = pop() push_symbol(ADD) push(p1) cons() if DEBUG then console.log "stack after adding terms #" + stackAddsCount #if stackAddsCount == 5 # debugger if DEBUG for i in [0...tos] console.log print_list stack[i] # Compare terms for order, clobbers p1 and p2. cmp_terms_count = 0 cmp_terms = (p1, p2) -> cmp_terms_count++ #if cmp_terms_count == 52 # debugger i = 0 # numbers can be combined if (isnum(p1) && isnum(p2)) flag = 1 #if DEBUG then console.log "cmp_terms #" + cmp_terms_count + " returns 0" return 0 # congruent tensors can be combined if (istensor(p1) && istensor(p2)) if (p1.tensor.ndim < p2.tensor.ndim) #if DEBUG then console.log "cmp_terms #" + cmp_terms_count + " returns -1" return -1 if (p1.tensor.ndim > p2.tensor.ndim) #if DEBUG then console.log "cmp_terms #" + cmp_terms_count + " returns 1" return 1 for i in [0...p1.tensor.ndim] if (p1.tensor.dim[i] < p2.tensor.dim[i]) #if DEBUG then console.log "cmp_terms #" + cmp_terms_count + " returns -1" return -1 if (p1.tensor.dim[i] > p2.tensor.dim[i]) #if DEBUG then console.log "cmp_terms #" + cmp_terms_count + " returns 1" return 1 flag = 1 #if DEBUG then console.log "cmp_terms #" + cmp_terms_count + " returns 0" return 0 if (car(p1) == symbol(MULTIPLY)) p1 = cdr(p1) if (isnum(car(p1))) p1 = cdr(p1) if (cdr(p1) == symbol(NIL)) p1 = car(p1) if (car(p2) == symbol(MULTIPLY)) p2 = cdr(p2) if (isnum(car(p2))) p2 = cdr(p2) if (cdr(p2) == symbol(NIL)) p2 = car(p2) t = cmp_expr(p1, p2) if (t == 0) flag = 1 #if DEBUG then console.log "cmp_terms #" + cmp_terms_count + " returns " + t return t ### Compare adjacent terms in s[] and combine if possible. Returns the number of terms remaining in s[]. n number of terms in s[] initially ### combine_terms = (s, n) -> #debugger # I had to turn the coffeescript for loop into # a more mundane while loop because the i # variable was changed from within the body, # which is something that is not supposed to # happen in the coffeescript 'vector' form. # Also this means I had to add a 'i++' jus before # the end of the body and before the "continue"s i=0 while i < (n-1) check_esc_flag() p3 = stack[s+i] p4 = stack[s+i + 1] if (istensor(p3) && istensor(p4)) push(p3) push(p4) tensor_plus_tensor() p1 = pop() if (p1 != symbol(NIL)) stack[s+i] = p1 for j in [(i + 1)...(n - 1)] stack[s+j] = stack[s+j + 1] n-- i-- i++ continue if (istensor(p3) || istensor(p4)) i++ continue if (isnum(p3) && isnum(p4)) push(p3) push(p4) add_numbers() p1 = pop() if (iszero(p1)) for j in [i...(n - 2)] stack[s+j] = stack[s+j + 2] n -= 2 else stack[s+i] = p1 for j in [(i + 1)...(n - 1)] stack[s+j] = stack[s+j + 1] n-- i-- i++ continue if (isnum(p3) || isnum(p4)) i++ continue if evaluatingAsFloats p1 = one_as_double p2 = one_as_double else p1 = one p2 = one t = 0 if (car(p3) == symbol(MULTIPLY)) p3 = cdr(p3) t = 1; # p3 is now denormal if (isnum(car(p3))) p1 = car(p3) p3 = cdr(p3) if (cdr(p3) == symbol(NIL)) p3 = car(p3) t = 0 if (car(p4) == symbol(MULTIPLY)) p4 = cdr(p4) if (isnum(car(p4))) p2 = car(p4) p4 = cdr(p4) if (cdr(p4) == symbol(NIL)) p4 = car(p4) if (!equal(p3, p4)) i++ continue push(p1) push(p2) add_numbers() p1 = pop() if (iszero(p1)) for j in [i...(n - 2)] stack[s+j] = stack[s+j + 2] n -= 2 i-- i++ continue push(p1) if (t) push(symbol(MULTIPLY)) push(p3) cons() else push(p3) multiply() stack[s+i] = pop() for j in [(i + 1)...(n - 1)] stack[s+j] = stack[s+j + 1] n-- i-- # this i++ is to match the while i++ return n push_terms = (p) -> if (car(p) == symbol(ADD)) p = cdr(p) while (iscons(p)) push(car(p)) p = cdr(p) else if (!iszero(p)) push(p) # add two expressions add = -> save() p2 = pop() p1 = pop() h = tos push_terms(p1) push_terms(p2) add_terms(tos - h) restore() add_all = (k) -> i = 0 save() s = tos - k h = tos for i in [0...k] push_terms(stack[s+i]) add_terms(tos - h) p1 = pop() moveTos tos - k push(p1) restore() subtract = -> negate() add()