Skip to content

Instantly share code, notes, and snippets.

@rahulaga
Created November 23, 2015 02:51
Show Gist options
  • Save rahulaga/ac291478d1d78c5f7d15 to your computer and use it in GitHub Desktop.
Save rahulaga/ac291478d1d78c5f7d15 to your computer and use it in GitHub Desktop.
Scheme Gaussian Elimination
;####################
;Gaussian Elimination
;Rahul Agarwal
;###################
;#################################################################
;Test if value is a valid linear equation, helper is part
;of linear-equation? so not testing seperately
;#################################################################
(define (le-helper value)
(cond ((empty? value) #t)
((not (number? (car value))) #f);test if not a number,
also takes care of nested lists
(else (le-helper (cdr value)))
)
)
(define (linear-equation? value)
(cond ((not (list? value)) #f)
((empty? value) #f)
((< (length value) 2) #f);must have atleast 2 or more numbers
(else (le-helper value))
)
)
#fShould be(linear-equation? '())Test...
#fShould be(linear-equation? 3)Test...
#fShould be(linear-equation? '(2))Test...
#tShould be(linear-equation? '(3 2.5 8 3.2))Test...
#tShould be(linear-equation? '(1 -1 +1 0))Test...
#fShould be(linear-equation? '(4 (3 2) 3))Test...
#fShould be(linear-equation? '(2 x 3 3))Test...
#fShould be(linear-equation? '(a b (s)))Test...
#fShould be(linear-equation? '(()))Test...
#tShould be(linear-equation? '(5 10))Test...
#tShould be(linear-equation? '(2/3 1/2 4/2))Test...
;#################################################################
;Test if value is a valid augmented matrix
;The length function gives the length, each row should be a linear
;equation and number atoms in each one more than number rows
;#################################################################
(define (am-helper value len);len is num rows
(cond
((empty? value) #t);reached end without false
((not (and (linear-equation? (car value)) (equal? (+ 1 len)
(length (car value))))) #f); linear eq && NxN+1
(else (am-helper (cdr value) len))
)
)
(define (augmented-matrix? value)
(cond
((not (list? value)) #f)
((empty? value) #f)
(else (am-helper value (length value)))
)
)
#tShould be(augmented-matrix? '((1 1 1 0)(1 -2 2 4)(1 +2 -1 2)))Test...
#fShould be(augmented-matrix? '((1 1 0)(1 -2 2 4)(1 +2 -1 2)))Test...
#fShould be(augmented-matrix? '((1 3 6 1 0)(1 -2 2 4)(1 +2 -1 2)))Test...
#fShould be(augmented-matrix? '((1 1 1 0)(1 -2 x 4)(1 +2 -1 2)))Test...
#fShould be(augmented-matrix? '((1 1 3 0)(1 +2 -1 2)))Test...
#fShould be(augmented-matrix? '((1 1 3 0)(12 1 33 0)(1 8 2 0)(1 +2 -1 2)))Test...
#fShould be(augmented-matrix? '())Test...
#fShould be(augmented-matrix? '((1 1 1 0)(1 -2 2 4)()))Test...
#fShould be(augmented-matrix? '((1 (1 1) 0)(1 (-2) 2 4)(1 +2 -1 (2))))Test...
#fShould be(augmented-matrix? 3)Test...
#fShould be(augmented-matrix? '((2 3 ())(3 2 1)))Test...
#tShould be(augmented-matrix? '((5 10)))Test...
#fShould be(augmented-matrix? '(5 10))Test...
#fShould be(augmented-matrix? '((3 2 1 3) 2 9 2 1 (2 4 2 2)))Test...
;#################################################################
;Find the upper triangualr matrix for the input. It is assumed
;that the value passed
;to this method is a valid augmented matrix so that is not tested and the
;test cases also
;do not target that.
;#################################################################
;Returns the xth value out of a list, returns empty if x is out of bounds
(define (get-x val x)
(cond ((empty? val) empty)
((> x (length val)) empty)
((< x 0) empty)
((= x 0) (car val))
(else (get-x (cdr val) (- x 1)))
)
)
4Should be(get-x '(1 2 4) 2)Test...
emptyShould be(get-x '(1 2 4) -1)Test...
emptyShould be(get-x '(1 2 4) 3)Test...
;returns the colth value of the rowth row
(define (get-rc mat row col)
(get-x (get-x mat row) col)
)
2Should be(get-rc '((0 1 2 3)(4 5 6 7)) 0 2)Test...
emptyShould be(get-rc '((0 1 2 3)(4 5 6 7)) 2 2)Test...
emptyShould be(get-rc '((0 1 2 3)(4 5 6 7)) 0 -2)Test...
;returns the matrix till that row
(define (get-mat-till-row mat row)
(cond ((< row 0) empty)
((> row (length mat)) empty)
(else (cons (car mat)
(get-mat-till-row (cdr mat) (- row 1)))
)
)
)
'((2 3 2 3)(2 3 2 1))Should be(get-mat-till-row '((2 3 2 3)(2 3 2 1)(2 3 2 1)) 1)Test...
'((2 3 2 3))Should be(get-mat-till-row '((2 3 2 3)(2 3 2 1)(2 3 2 1)) 0)Test...
emptyShould be(get-mat-till-row '((2 3 2 3)(2 3 2 1)(2 3 2 1)) -5)Test...
emptyShould be(get-mat-till-row '((2 3 2 3)(2 3 2 1)(2 3 2 1)) 5)Test...
;scalar multi and substraction (sms)
;applies map using lambda function that cross multiples rows using the pivot col
;so that the value at col can then be zero in toList
(define (do-math-sms subList toList col)
(map (lambda
(x y)
(- (* x (get-x subList col))
(* y (get-x toList col)))
)
toList
subList)
)
;NOTE: not tested for boundry cases cos this function can never be called with
;out of bounds values of col
'(0 7 -2)Should be(do-math-sms '(3 5 2) '(4 9 2) 0)Test...
'(-7 0 -8)Should be(do-math-sms '(3 5 2) '(4 9 2) 1)Test...
;makes all the values of the col to zero
;uses the do-math-sms on col in mat
(define (make-zero mat col)
(letrec(
(mz-helper (lambda (row newmat)
(cond ((>= row (length mat)) newmat);prevents make-zero if will
/violate upper triangular
(else
(mz-helper (+ 1 row)
(append newmat
(list (do-math-sms (get-x mat col)
(get-x mat row)
col)))))
)
)
);end lambda
)
(mz-helper (+ 1 col) (get-mat-till-row mat col));letrec body
)
)
;NOTE: not tested for boundry cases cos this function can never be called with
;out of bounds values of col
'((1 3 2)(0 -20 -14))Should be(make-zero '((1 3 2)(8 4 2)) 0)Test...
'((1 3 2 3)(8 2 4 2)(-6 0 -6 -4))Should be(make-zero '((1 3 2 3)(8 2 4 2)(5 2 1 0)) 1)Test...
;counts numbers of zeros before encountering a non-zero value
(define (count-zeros-at-front mat)
(cond ((empty? mat) 0)
((not (zero? (car mat))) 0)
(else (+ 1 (count-zeros-at-front (cdr mat))))
)
)
0Should be(count-zeros-at-front '())Test...
0Should be(count-zeros-at-front '(1 0 0 0))Test...
4Should be(count-zeros-at-front '(0 0 0 0))Test...
2Should be(count-zeros-at-front '(0 0 3 0))Test...
;check top down - the 'row' passed should have 'row' number of zeros
(define (valid-ut-helper mat row totrows)
(cond ((empty? mat) #t)
((not (= row (count-zeros-at-front (car mat)))) #f)
((< row totrows) (valid-ut-helper (cdr mat) (+ 1 row) totrows))
(else #t)
)
)
;checks whether a valid upper-triangular
;last row should hv atleast two non-zero at end, second last three and so on...
(define (valid-ut? mat)
(cond ((empty? mat) #f)
(else (valid-ut-helper mat 0 (length mat)));helper to enable
;looping via recursion
)
)
#fShould be(valid-ut? '())Test...
#tShould be(valid-ut? '((2.5 6.25)))Test...
#tShould be(valid-ut? '((1 1 1 0) (0 -3 1 4) (0 0 5 -10)))Test...
#fShould be(valid-ut? '((1 -1 4) (0 0 -12)))Test...
#fShould be(valid-ut? '((1 1 1 150) (0 1 2 -50) (0 0 0 -50)))Test...
#fShould be(valid-ut? '((0 0 0 0)(0 0 0 0)(0 0 0 0)))Test...
;process by sending each col to zero and creating new matrix
;each col is the pivot value in turn
(define (ut-helper mat col end)
(cond ((empty? (get-rc mat col col)) mat);base
((= col end) mat);base
(else
(ut-helper (make-zero mat col) (+ col 1) end))
)
)
;creates the upper triangle for the given matrix
;actually helper does but writing cos this prototype required
(define (upper-triangular value)
(let ((ut-calculated (ut-helper value 0 (- (length value) 1))));var holding ut found
(cond ((valid-ut? ut-calculated) ut-calculated)
(else 'error)
)
);end let
)
'((5 10))Should be(upper-triangular '((5 10)))Test...
'((1 1 1 0) (0 -3 1 4) (0 0 5 -10))Should be(upper-triangular '((1 1 1 0)
(1 -2 2 4) (1 2 -1 2)))Test...
'((4 8 4 80) (0 -12 -24 -132) (0 0 -624 -1872))Should be(upper-triangular '((4 8 4 80)
(2 1 -4 7) (3 -1 2 22)))Test...
'((2.5 6.25))Should be(upper-triangular '((2.5 6.25)))Test...
'((3/2 5/2 1)(0 34/4 13/4))Should be(upper-triangular '((3/2 5/2 1)(-5/2 3/2 1/2)))Test...
'errorShould be(upper-triangular '((1 -1 4) (2 -2 -4)))Test...
'errorShould be(upper-triangular '((1 1 1 150) (1 2 3 100) (2 3 4 200)))Test...
'errorShould be(upper-triangular '((0 0 0 0)(0 0 0 0)(0 0 0 0)))Test...
;#################################################################
;Backsolver when given a upper-triangular. Again test cases assume
;that since this function is called only after
;upper-triangular is complete the value is a correct augmented matrix
;#################################################################
;my-sum takes the two lists and finds the special sum
;subsitutes values from one list and solves one unknown
(define (my-sum shortList longList ret)
(cond ((empty? shortList) ret)
(else (my-sum (rest shortList)
(rest longList)
(+ ret (* (first shortList)
(first longList)))))
)
)
;helper for backsolver
(define (bs-helper revmat ret col lastcol)
(cond ((empty? revmat) ret)
((zero? (get-x (first revmat) col)) 'error);prevent division by
;zero - catches inconsistent matrix
(else (bs-helper (rest revmat)
(cons (/ (- (get-x (first revmat) lastcol)
(my-sum (reverse ret)
(rest
(reverse (first revmat)))
0))
(get-x (first revmat) col))
ret)
(- col 1)
lastcol))
)
)
;backsolves to get the values
;the reverse is used cos initial values are all zeros and easier
;this way to work at end of list instead of having to write functions to read last
(define (backsolve-upper-triangular value)
(cond ((not (valid-ut? value)) 'error);check if zeros in correct places else error
(else (bs-helper (reverse value)
empty
(- (length value) 1)
(length value)))
)
)
'(2)Should be(backsolve-upper-triangular '((5 10)))Test...
'(4 -2 -2)Should be(backsolve-upper-triangular '((1 1 1 0) (0 -3 1 4) (0 0 -5 10)))Test...
'(7 5 3)Should be(backsolve-upper-triangular '((4 8 4 80) (0 -6 -12 -66) (0 0 156 468)))Test...
'(2.5)Should be(backsolve-upper-triangular '((2.5 6.25)))Test...
'errorShould be(backsolve-upper-triangular '((1 -1 4) (0 0 -12)))Test...
'errorShould be(backsolve-upper-triangular '((1 1 1 150) (0 1 2 -50) (0 0 0 -50)))Test...
'errorShould be(backsolve-upper-triangular '((0 0 0 0)(0 0 0 0)(0 0 0 0)))Test...
'errorShould be(backsolve-upper-triangular '((0 1 2 5)(0 3 1 3)(0 0 6 4)))Test...
;#############################################################
;Combines all functions above, nothing special
;Test cases are same as upper-triangular and backsolve-upper-triangular
;hence very few test cases
;#############################################################
(define (solve value)
(if (augmented-matrix? value)
(let ((ut-calculated (upper-triangular value)))
(if (list? ut-calculated) (backsolve-upper-triangular ut-calculated) 'error)
)
'error
)
)
'(4 -2 -2)Should be(solve '((1 1 1 0) (0 -3 1 4) (0 0 -5 10)))Test...
'errorShould be(solve '((1 -1 4) (0 0 -12)))Test...
'errorShould be(solve '((1 -1 3 4) (0 0 -12)))Test...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment