;;;; math-utils-vector-test.scm -*- Scheme -*- ;;;; Kon Lovett, Jul '23 (import test) (import (only (chicken format) format) (test-utils gloss)) ;;; (test-begin "Math Utils Vector") (import (math-utils vector)) ;;; (import (chicken string)) (import (chicken fixnum)) (import (chicken random)) (import (only vector-lib vector-unfold)) ;NOTE must have precision set (define-syntax test-vector (syntax-rules () ((test-vector ?r ?e) (test #f 0.0 (exact->inexact (vector-compare ?r ?e))) ) ((test-vector ?lb ?r ?e) (test ?lb 0.0 (exact->inexact (vector-compare ?r ?e))) ) ) ) ;; ;https://en.wikipedia.org/wiki/Cosine_similarity (define (cosine-similarity/reference a b) (/ (dot-product a b) (* (absolute-magnitude a) (absolute-magnitude b))) ) #; (repeat-random (100) (let*-random ((len 1000) (a (vector-of real len)) (b (vector-of real len)) ) (test "\"fast\" cosine-similarity eqv cosine-similarity reference" (cosine-similarity/reference a b) (cosine-similarity a b)) ) ) (define (make-random-real-vector len #!optional (zeros? #f) (rnd pseudo-random-real)) (vector-unfold (lambda _ #;(i . seeds) (let loop ((trys 10)) (let ((n (rnd))) (if (or (not (zero? n)) zeros?) n (if (fx< trys 0) 1 (loop (fx- trys 1)))) ) ) ) len) ) ;; (test-group "cosine-similarity \"fast\" = reference w/ random length & real values" (let loop ((cnt (pseudo-random-integer 25))) (unless (fx= 0 cnt) (let* ((len (pseudo-random-integer 10000)) (a (make-random-real-vector len)) (b (make-random-real-vector len)) ) (test (conc "Length " len) (exact->inexact (cosine-similarity/reference a b)) (exact->inexact (cosine-similarity a b))) (loop (fx- cnt 1)) ) ) ) ) (test-group "operations" (test 10 (dot-product #(1 2 3) #(3 2 1))) (test-group "any X empty is 0" (test 0 (cross-product #() #())) (test 0 (cross-product #() #(3))) (test 0 (cross-product #(1) #())) ) (test 3 (cross-product #(1) #(3))) (test -4 (cross-product #(1 2) #(3 2))) (test #(-4 8 -4) (cross-product #(1 2 3) #(3 2 1))) ) (test-group "vector apply" (define (vector-mul . vs) (apply vector-apply * vs)) (define (vector-add . vs) (apply vector-apply + vs)) (define (vector-dif . vs) (apply vector-apply - vs)) (test #(4 4 4) (vector-add #(1 2 3) #(3 2 1))) (test #(3 4 3) (vector-mul #(1 2 3) #(3 2 1))) (test "cmp" #(-2 0 2) (vector-dif #(1 2 3) #(3 2 1))) ) (test-group "vector reduce" ;use of inf.0 as `seed' w/ max/min causes inexact result! ;(define (vector/max v) (vector-reduce max -inf.0 v)) ;(define (vector/min v) (vector-reduce min +inf.0 v)) (define (vector/max v) (vector-reduce max (vector-ref v 0) v 1)) (define (vector/min v) (vector-reduce min (vector-ref v 0) v 1)) (test 3 (vector/max #(1 2 3))) (test 1 (vector/min #(1 2 3))) ) (test-group "compare" (test-assert "diff len" (positive? (vector-compare #(1 2 3 4) #(3 2 1)))) (test-assert "<" (negative? (vector-compare #(1 2 3) #(3 2 1)))) (test-assert "=" (zero? (vector-compare #(3 2 1) #(3 2 1)))) (test-assert ">" (positive? (vector-compare #(3 2 1) #(1 2 3)))) (test-assert "multi <" (negative? (vector-compare #(-2 0 2) #(3 2 1) #(1 2 3)))) (test-assert "multi =" (zero? (vector-compare #(1 2 3) #(1 2 3) #(1 2 3)))) (test-assert "multi >" (positive? (vector-compare #(3 2 1) #(1 2 3) #(-2 0 2)))) ) (test-group "softmax" (parameterize ((current-test-epsilon 0.001)) ;2 places precision of input (test-vector "low spike" #(0.01 0.00 0.03 0.09 0.61 0.00 0.25) (softmax #(-0.8 -5.0 +0.5 +1.5 +3.4 -2.3 +2.5))) (test "low spike p" 1.0 (vector-reduce + 0 (softmax #(-0.8 -5.0 +0.5 +1.5 +3.4 -2.3 +2.5)))) (test-vector "high spike" #(0.00 0.00 0.00 0.00 0.99 0.01 0.00) (softmax #(-0.8 -5.0 +0.5 +1.5 +8.5 -2.3 +2.5))) (test "high spike p" 1.0 (vector-reduce + 0 (softmax #(-0.8 -5.0 +0.5 +1.5 +8.5 -2.3 +2.5)))) ) ;wikipedia example ;#(0.000908800555363033 0.00247037603533682 0.9966208234093) ;#(0.001 0.002 0.997) ;(softmax #(1 2 8)) ) (test-group "softmax w/ temp" (parameterize ((current-test-epsilon 0.001)) ;2 places precision of input (test-vector "same when temp = 1" #(0.01 0.00 0.03 0.09 0.61 0.00 0.25) (softmax* #(-0.8 -5.0 +0.5 +1.5 +3.4 -2.3 +2.5))) ;default 1 (test "same when temp = 1 p" 1.0 (vector-reduce + 0 (softmax* #(-0.8 -5.0 +0.5 +1.5 +3.4 -2.3 +2.5)))) (test-vector "temp > 1" #(0.19 0.04 0.14 0.10 0.34 0.05 0.14) (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) 6.57)) (test "temp > 1 p" 1.0 (vector-reduce + 0 (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) 6.57))) (test-vector "temp < 1" #(0.0 0.0 0.0 0.0 0.99957 0.0 0.0) (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) 0.5)) (test "temp < 1 p" 1.0 (vector-reduce + 0 (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) 0.5))) (test-vector "temp = 0" #(0.00 0.00 0.00 0.00 1.00 0.00 0.00) (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) 0)) (test "temp = 0 p" 1.0 (vector-reduce + 0 (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) 0))) ;(vector-apply (cut @prec 4 <> round) ^) (test-vector "temp < -1" #(0.0661 0.3528 0.0897 0.1312 0.0365 0.2339 0.0897) (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) -6.57)) (test "temp < -1 p" 1.0 (vector-reduce + 0 (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) -6.57))) (test-vector "temp < 0" #(0.0 0.0 0.0 0.0 0.99957 0.0 0.0) (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) -0.5)) (test "temp < 0 p" 1.0 (vector-reduce + 0 (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) -0.5))) ;(vector-apply (cut @prec 4 <> round) ^) (test-vector "temp >> 1" #(0.1436 0.1412 0.1432 0.1426 0.1444 0.1418 0.1432) (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) 666)) (test "temp >> 1 p" 1.0 (vector-reduce + 0 (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) 666))) ;(gloss (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) 666)) ;(vector-apply (cut @prec 4 <> round) ^) (test-vector "temp >>> 1" #(0.1429 0.1429 0.1429 0.1429 0.1429 0.1429 0.1429) (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) most-positive-fixnum)) (test "temp >>> 1 p" 1.0 (vector-reduce + 0 (softmax* #(+6.0 -5.0 +4.0 +1.5 +9.9 -2.3 +4.0) most-positive-fixnum))) ) ) ;;; (test-end "Math Utils Vector") (test-exit)