;; some tests for statistics package (import (chicken sort) test statistics srfi-1) ;; -- to help the tests (define (to-4-dp f) (/ (round (* f 10000)) 10000)) (define (to-5-dp f) (/ (round (* f 100000)) 100000)) (define (=4 n1 n2) (= (to-4-dp n1) (to-4-dp n2))) (define (=5 n1 n2) (= (to-5-dp n1) (to-5-dp n2))) ;; Helper for approximate equality (define (approx-equal? x y #!optional (tolerance 0.001)) (< (abs (- x y)) tolerance)) ;; Helper for testing lists of pairs (for KDE results) (define (approx-equal-pairs? pairs1 pairs2 #!optional (tolerance 0.001)) (and (= (length pairs1) (length pairs2)) (every (lambda (p1 p2) (and (approx-equal? (car p1) (car p2) tolerance) (approx-equal? (cdr p1) (cdr p2) tolerance))) pairs1 pairs2))) ;; Test data sets (define small-data '(1 2 3 4 5)) (define normal-data '(10 15 20 25 30 35 40 45 50)) (define data-with-outliers '(10 12 14 15 16 18 20 100)) ; 100 is outlier (define iris-sepal-length '(5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1)) (test-group "utilities" (test "cumsum" '(1 3 6 10 15) (cumsum '(1 2 3 4 5))) (test "average-rank" 3 (average-rank 3 '(1 2 3 4 5))) (test "average-rank" 7/2 (average-rank 3 '(1 2 3 3 4 5))) (test-assert "beta-incomplete" (=5 0.28367 (beta-incomplete 0.2 0.1 0.3))) (test "bin-and-count" (vector 5 5) (bin-and-count '(1 2 3 4 5 6 7 8 9 10) 2)) (test "bin-and-count" (vector 2 2 2 2 2) (bin-and-count '(1 2 3 4 5 6 7 8 9 10) 5)) (test "bin-and-count" (vector 5 1) (bin-and-count '(1 2 2 2 3 9) 2)) (test "combinations" 120 (combinations 10 3) ) (test "factorial" 3628800 (factorial 10)) (test-assert "fisher-z-transform" (=5 (fisher-z-transform 0.1) 0.10034)) (test-assert "fisher-z-transform" (=5 (fisher-z-transform 0.5) 0.54931)) (test "gamma-incomplete" (list 0.44217 0.0) (let-values (((a b) (gamma-incomplete 2.0 1.5))) (list (to-5-dp a) b))) (test-assert "gamma-ln" (=5 (gamma-ln 0.5) 0.57236)) (test "permutations" 720 (permutations 10 3)) ) ;(test (random-weighted-sample 3 '(1 2 3 4 5 7 8 9) '(0.15 0.025 0.4 0.1 0.35 0.2 0.15 0.25 0.05 0.01)) ; (=> (lambda (result expected) (= (length result) expected))) 3) (test-group "descriptive statistics" (test "mean" 0 (mean '())) (test "mean" 1 (mean '(1))) (test "mean" 3 (mean '(1 2 3 4 5)) ) (test "median" 1 (median '(1))) (test "median" 3 (median '(1 2 3 4 5))) (test "median" 4 (median '(1 1 2 3 4 5 6 7 8))) (test "mode" '((1) 3) (let-values (((modes counts) (mode '(1 1 1 2 3 4 5)))) (list modes counts))) (test "mode" '((1 4) 3) (let-values (((modes counts) (mode '(1 1 1 2 3 4 4 4 5)))) (list modes counts))) (test "geometric mean" 10.0 (geometric-mean '(1 100))) (test-assert "geometric mean" (=5 2.60517 (geometric-mean '(1 2 3 4 5)))) (test "range" 4 (range '(1 2 3 4 5))) (test "range" 9 (range '(1 1 1 2 3 4 10))) (test "percentile" 7/2 (percentile '(1 2 3 4 5 6) 50)) (test "percentile" 2 (percentile '(1 2 3 4 5 6) 30)) (test "variance" 5/2 (variance '(1 2 3 4 5))) (test-assert "standard deviation" (=5 1.58113883 (standard-deviation '(1 2 3 4 5)))) (test-assert "coefficient of variation" (=5 52.704627 (coefficient-of-variation '(1 2 3 4 5)))) (test-assert (=5 (standard-error-of-the-mean '(1 2 3 4 5)) 0.707106781186548)) (let-values (((mean sd n) (mean-sd-n '(1 2 3 4 5)))) (test-assert "mean sd" (=5 sd 1.58113883008419))) ) (print (binomial-probability 10 0 0.5)) (test-group "distributional functions" (test-assert "binomial-probability" (every (lambda (pair) (=5 (binomial-probability 10 (car pair) 0.5) (cadr pair))) '((0 0.0009765625) (1 0.009765625) (2 0.0439453125) (3 0.1171875) (4 0.205078125) (5 0.24609375) (6 0.205078125) (7 0.1171875) (8 0.0439453125) (9 0.009765625) (10 0.0009765625)))) (test-assert "binomial-cumulative-probability" (every (lambda (pair) (=5 (binomial-cumulative-probability 10 (car pair) 0.5) (cadr pair))) '((0 0.0) (1 0.0009765625) (2 0.0107421875) (3 0.0546875) (4 0.171875) (5 0.376953125) (6 0.623046875) (7 0.828125) (8 0.9453125) (9 0.9892578125) (10 0.9990234375)))) (test-assert "binomial-cumulative-probability" (every (lambda (pair) (=4 (poisson-probability 10 (car pair)) (cadr pair))) '((0 0.0000) (1 0.0005) (2 0.0023) (3 0.0076) (4 0.0189) (5 0.0378) (6 0.0631) (7 0.0901) (8 0.1126) (9 0.1251) (10 0.1251) (11 0.1137) (12 0.0948) (13 0.0729) (14 0.0521) (15 0.0347) (16 0.0217) (17 0.0128) (18 0.0071) (19 0.0037)))) (test-assert "poisson-cumulative-probability" (every (lambda (pair) (=4 (poisson-cumulative-probability 10 (car pair)) (cadr pair))) '((0 0.0000) (1 0.0000) (2 0.0005) (3 0.0028) (4 0.0103) (5 0.0293) (6 0.0671) (7 0.1301) (8 0.2202) (9 0.3328) (10 0.4579) (11 0.5830) (12 0.6968) (13 0.7916) (14 0.8645) (15 0.9165) (16 0.9513) (17 0.9730) (18 0.9857) (19 0.9928)))) (test-assert "normal-pdf" (every (lambda (pair) (=4 (normal-pdf (car pair) 5 4) (cadr pair))) '((0 0.0088) (1 0.0270) (2 0.0648) (3 0.1210) (4 0.1760) (5 0.1995) (6 0.1760) (7 0.1210) (8 0.0648) (9 0.0270)(10 0.0088)))) (test-assert "phi" (every (lambda (pair) (=4 (phi (car pair)) (cadr pair))) '((-2.0 0.0228) (-1.6 0.0548) (-1.2 0.1151) (-0.8 0.2119) (-0.4 0.3446) ( 0.0 0.5000) ( 0.4 0.6554) ( 0.8 0.7881) ( 1.2 0.8849) ( 1.6 0.9452)))) (test-assert "z" (every (lambda (pair) (=5 (z (car pair)) (cadr pair))) '((0.1 -1.2815515713806909) (0.2 -0.8416212245351449)))) (test "convert-to-standard-normal" -1/2 (convert-to-standard-normal 5 6 2)) (test-assert "t-distribution" (=5 3.07763671875 (t-distribution 1 0.9))) (test-assert "t-distribution" (=5 1.3721923828125 (t-distribution 10 0.9))) (test-assert "chi-square" (=5 (chi-square 10 0.4405) 10)) (test-assert "chi-square" (=5 (chi-square 3 0.1718) 5)) (test-assert "chi-square-cdf" (=5 (chi-square-cdf 10 10) 0.559506714934786)) (test-assert "chi-square-cdf" (=5 (chi-square-cdf 5 3) 0.828202855703266)) ) (test-group "tests of confidence intervals" (let-values (((upper-bound lower-bound) (binomial-probability-ci 10 0.8 0.9))) (test-assert "binomial-probability-ci" (=5 upper-bound 0.724273681640625)) (test-assert "binomial-probability-ci" (=5 lower-bound 0.851547241210938)) ) (let-values (((upper-bound lower-bound) (poisson-mu-ci 10 0.9))) (test-assert "poisson-mu-ci" (=5 upper-bound 8.305419921875)) (test-assert "poisson-mu-ci" (=5 lower-bound 10.0635986328125))) (let-values (((upper-bound lower-bound) (normal-mean-ci 0.5 0.1 10 0.8))) (test-assert "normal-mean-ci" (=5 upper-bound 0.491747852700165)) (test-assert "normal-mean-ci" (=5 lower-bound 0.508252147299835))) (let-values (((upper-bound lower-bound) (normal-mean-ci-on-sequence '(1 2 3 4 5) 0.9))) (test-assert "normal-mean-ci-on-sequence" (=5 upper-bound 2.90535368828478)) (test-assert "normal-mean-ci-on-sequence" (=5 lower-bound 3.09464631171522))) ) (test-group "hypothesis testing" (test-assert "z-test" (=5 (z-test 40 1 #:mu 50 #:sigma 10 #:tails ':negative) 0.15865525)) (test-assert "z-test" (=5 (z-test 40 10 #:mu 50 #:sigma 10 #:tails ':negative) 0.000783)) (test-assert "z-test" (=5 (z-test 40 5 #:mu 50 #:sigma 10) 0.025347)) (test-assert "z-test" (=5 (z-test 11/5 5 #:mu 2 #:sigma 1) 0.65472085)) (test-assert "z-test-on-sequence" (=5 (z-test-on-sequence '(1 1 2 3 4) #:mu 2 #:sigma 1) 0.65472085)) (test-assert "t-test-one-sample" (=5 (t-test-one-sample 5 0.8 3 6) 0.162781641721079)) (test-assert "t-test-one-sample-on-sequence" (=5 (t-test-one-sample-on-sequence '(5 6 7) 5.9) 0.878433865229034)) (test-assert "correlation-test-two-sample" (=5 (correlation-test-two-sample 0.9 100 0.85 50) 0.224083300908794)) (test-assert "t-test-paired" (=5 (t-test-paired 7/3 0.57735 3) 0.0198039411803931)) (test-assert "t-test-paired-on-sequences" (=5 (t-test-paired-on-sequences '(4 3 5) '(1 1 3)) 0.0198039411803931)) ) (let-values (((s p) (spearman-rank-correlation '(4 10 3 1 9 2 6 7 8 5) '(5 8 6 2 10 3 9 4 7 1)))) (test-assert "spearman-rank-correlation" (=5 s (/ 113 165))) (test-assert "spearman-rank-correlation" (=5 p 0.0288827975067328))) (test-group "sample size estimates" (test "t-test-one-sample-sse" 163 (t-test-one-sample-sse 5.0 5.2 0.5)) (let-values (((n1 n2) (t-test-two-sample-sse 5.1 0.5 5.2 0.3))) (test "t-test-two-sample-sse" 1040 n1) (test "t-test-two-sample-sse" 1040 n2)) (test "correlation-sse" 11 (correlation-sse 0.80 #:alpha 0.05 #:1-beta 0.9)) ) ;; NOTE: Not same as some on-line sites describe ... (test-group "correlation and regression" (let-values (((a b r r2 p) (linear-regression '(1.0 2.0 3.0) '(0.1 0.3 0.8)))) (test "linear-regression" -0.3 a) (test-assert "linear-regression" (=5 b 0.35)) (test-assert "linear-regression" (=5 r 0.970725343394151)) (test-assert "linear-regression" (=5 r2 0.942307692307692)) (test-assert "linear-regression" (=5 p 0.154420958311267)) ) (test-assert "correlation-coefficient" (=5 0.970725343394151 (correlation-coefficient '(1.0 2.0 3.0) '(0.1 0.3 0.8)))) ) (test-group "significance tests" (test-assert "t-significance" (=5 (t-significance 0.2 5) 0.849360513995829)) (test-assert "t-significance" (=5 (t-significance 0.2 5 #:tails ':both) 0.849360513995829)) (test-assert "t-significance" (=5 (t-significance 0.2 5 #:tails ':positive) 0.424680256997915)) (test-assert "t-significance" (=5 (t-significance 0.2 5 #:tails ':negative) 0.575319743002086)) (test-assert "f-significance" (=5 (f-significance 1.5 8 2) 0.920449812578091)) (test-assert "f-significance" (=5 (f-significance 1.5 8 2 #:one-tailed? #t) 0.460224906289046)) (test-assert "binomial-test-two-sample" (=5 (binomial-test-two-sample 0.2 100 0.3 50) 0.245930683028145)) (test-assert "fisher-exact-test" (=5 (fisher-exact-test 10 20 30 40) 0.5066621427235114)) (test-assert "lambert-W0" (=5 (lambert-W0 1.0) 0.567143290410)) (test-assert "lambert-Wm1" (=5 (lambert-Wm1 -0.1) -3.57715206)) ) (test-group "Interquartile Range (IQR)" (test-assert "IQR of normal data" (approx-equal? (iqr normal-data) 20.0 0.1)) (test-assert "IQR of small data" (approx-equal? (iqr small-data) 2.0 0.1)) (test-error "IQR requires at least 4 elements" (iqr '(1 2 3)))) (test-group "Five-Number Summary" (test-assert "fivenum of normal data" (let ((result (fivenum normal-data))) (and (= (length result) 5) (= (list-ref result 0) 10) ; min (= (list-ref result 4) 50))) ; max ) (test-assert "fivenum median is correct" (let ((result (fivenum normal-data))) (= (list-ref result 2) 30)) ; median ) (test-assert "fivenum Q1 and Q3" (let ((result (fivenum normal-data))) (and (approx-equal? (list-ref result 1) 20.0 0.1) ; Q1 (approx-equal? (list-ref result 3) 40.0 0.1))) ; Q3 ) (test-error "fivenum requires at least 5 elements" (fivenum '(1 2 3 4)))) (test-group "Outlier Detection" (test-assert "outliers identifies extreme values" (let-values (((out clean) (outliers data-with-outliers #:coef 1.5))) (and (member 100 out) (= (length out) 1))) ) (test-assert "outliers returns clean data" (let-values (((out clean) (outliers data-with-outliers #:coef 1.5))) (and (not (member 100 clean)) (= (length clean) 7))) ) (test-assert "no outliers in normal data" (let-values (((out clean) (outliers normal-data #:coef 1.5))) (and (null? out) (= (length clean) (length normal-data)))) ) (test-assert "stricter coef finds fewer outliers" (let-values (((out1 clean1) (outliers data-with-outliers #:coef 1.5)) ((out2 clean2) (outliers data-with-outliers #:coef 3.0))) (>= (length out1) (length out2))) ) (test "outliers requires at least 4 elements" (outliers '(1 2 3)) '())) (test-group "Histogram Breaks" (test-assert "histogram-breaks returns correct number of edges" (let ((breaks (histogram-breaks normal-data 5 #:method 'equal-width))) (= (vector-length breaks) 6)) ; n bins -> n+1 edges ) (test-assert "histogram-breaks covers data range" (let ((breaks (histogram-breaks normal-data 5 #:method 'equal-width))) (and (<= (vector-ref breaks 0) 10) (>= (vector-ref breaks 5) 50))) ) (test-assert "Sturges formula for bin count" (let* ((n 100) (expected-bins (inexact->exact (ceiling (+ 1 (/ (log n) (log 2)))))) (data (iota n)) (breaks (histogram-breaks data n #:method 'sturges))) ;; Should have approximately log2(n)+1 bins (and (> (vector-length breaks) 5) (< (vector-length breaks) 10))) ) (test-assert "Scott's rule produces reasonable bins" (let ((breaks (histogram-breaks normal-data 10 #:method 'scott))) (and (vector? breaks) (> (vector-length breaks) 2))) ) (test-assert "Freedman-Diaconis rule" (let ((breaks (histogram-breaks normal-data 10 #:method 'fd))) (and (vector? breaks) (> (vector-length breaks) 2))) ) (test-error "Unknown histogram method" (histogram-breaks normal-data 5 #:method 'unknown))) (test-group "Histogram Computation" (test-assert "histogram counts all values" (let* ((breaks (histogram-breaks normal-data 5 #:method 'equal-width))) (let-values (((edges counts) (histogram normal-data breaks))) (= (apply + (vector->list counts)) (length normal-data)))) ) (test-assert "histogram returns correct structure" (let* ((breaks (histogram-breaks normal-data 5 #:method 'equal-width))) (let-values (((edges counts) (histogram normal-data breaks))) (and (vector? counts) (= (vector-length counts) (- (vector-length breaks) 1))))) ) (test-assert "histogram with known data" (let* ((data '(1 1 2 2 2 3 3 3 3 4)) (breaks (vector 0.5 1.5 2.5 3.5 4.5))) (let-values (((edges counts) (histogram data breaks))) (and (= (vector-ref counts 0) 2) ; two 1's (= (vector-ref counts 1) 3) ; three 2's (= (vector-ref counts 2) 4) ; four 3's (= (vector-ref counts 3) 1)))) ; one 4 ) (test-assert "histogram handles values at bin edges" (let* ((data '(1.0 2.0 3.0 4.0)) (breaks (vector 1.0 2.0 3.0 4.0))) (let-values (((edges counts) (histogram data breaks))) ;; Last bin should include upper edge (= (vector-ref counts 2) 2))) ; 3.0 and 4.0 )) (test-group "KDE Bandwidth Selectors" (test-assert "NRD bandwidth is positive" (> (kde-bandwidth-nrd normal-data) 0) ) (test-assert "Scott bandwidth is positive" (> (kde-bandwidth-scott normal-data) 0) ) (test-assert "FD bandwidth is positive" (> (kde-bandwidth-fd normal-data) 0) ) (test-assert "NRD bandwidth reasonable magnitude" (let ((bw (kde-bandwidth-nrd iris-sepal-length))) (and (> bw 0.1) (< bw 10.0))) ) (test-assert "Bandwidth scales with sample size" (let ((bw-small (kde-bandwidth-nrd small-data)) (bw-large (kde-bandwidth-nrd iris-sepal-length))) ;; Bandwidth should decrease with larger n (n^(-1/5) rule) (> bw-small bw-large)) )) (test-group "Kernel Density Estimation" (test-assert "KDE returns correct number of points" (let ((result (kde normal-data 5.0 'gaussian 100))) (= (length result) 100)) ) (test-assert "KDE returns pairs" (let ((result (kde normal-data 5.0 'gaussian 10))) (every pair? result)) ) (test-assert "KDE density values are non-negative" (let ((result (kde normal-data 5.0 'gaussian 50))) (every (lambda (p) (>= (cdr p) 0)) result)) ) (test-assert "KDE x-values are sorted" (let ((result (kde normal-data 5.0 'gaussian 50))) (let ((x-vals (map car result))) (equal? x-vals (sort x-vals <)))) ) (test-assert "KDE integrates to approximately 1" (let* ((result (kde normal-data 3.0 'gaussian 500)) (x-vals (map car result)) (y-vals (map cdr result)) (dx (- (cadr x-vals) (car x-vals))) (integral (* dx (apply + y-vals)))) (approx-equal? integral 1.0 0.1)) ) (test-assert "KDE Gaussian kernel" (let ((result (kde small-data 1.0 'gaussian 20))) (and (= (length result) 20) (every pair? result))) ) (test-assert "KDE Epanechnikov kernel" (let ((result (kde small-data 1.0 'epanechnikov 20))) (and (= (length result) 20) (every pair? result))) ) (test-assert "KDE Rectangular kernel" (let ((result (kde small-data 1.0 'rectangular 20))) (and (= (length result) 20) (every pair? result))) ) (test-assert "KDE Triangular kernel" (let ((result (kde small-data 1.0 'triangular 20))) (and (= (length result) 20) (every pair? result))) ) (test-assert "KDE Biweight kernel" (let ((result (kde small-data 1.0 'biweight 20))) (and (= (length result) 20) (every pair? result))) ) (test-assert "KDE with automatic bandwidth" (let* ((bw (kde-bandwidth-nrd normal-data)) (result (kde normal-data bw 'gaussian 100))) (= (length result) 100)) ) (test-error "KDE with unknown kernel" (kde normal-data 1.0 'unknown 10)) (test-error "KDE with empty sequence" (kde '() 1.0 'gaussian 10))) (test-group "Binned Statistics - Means" (test-assert "bin-means returns correct number of bins" (let ((result (bin-means normal-data normal-data 5))) (= (length result) 5)) ) (test-assert "bin-means returns pairs" (let ((result (bin-means normal-data normal-data 5))) (every pair? result)) ) (test-assert "bin-means with simple linear data" (let* ((x-vals '(1 2 3 4 5 6 7 8 9 10)) (y-vals '(10 20 30 40 50 60 70 80 90 100)) (result (bin-means x-vals y-vals 2))) ;; First bin (1-5): mean y = 30 ;; Second bin (6-10): mean y = 80 (and (approx-equal? (cdr (car result)) 30.0 5.0) (approx-equal? (cdr (cadr result)) 80.0 5.0))) ) (test-assert "bin-means handles empty bins" (let* ((x-vals '(1 1 1 10 10 10)) (y-vals '(5 5 5 50 50 50)) (result (bin-means x-vals y-vals 3))) ;; Some bins will be empty (mean = 0) (= (length result) 3)) )) (test-group "Binned Statistics - Standard Deviations" (test-assert "bin-sds returns correct number of bins" (let ((result (bin-sds normal-data normal-data 5))) (= (length result) 5)) ) (test-assert "bin-sds returns pairs" (let ((result (bin-sds normal-data normal-data 5))) (every pair? result)) ) (test-assert "bin-sds values are non-negative" (let ((result (bin-sds normal-data normal-data 5))) (every (lambda (p) (>= (cdr p) 0)) result)) ) (test-assert "bin-sds with constant values" (let* ((x-vals '(1 2 3 4 5 6 7 8 9 10)) (y-vals '(10 10 10 10 10 10 10 10 10 10)) (result (bin-sds x-vals y-vals 2))) ;; SD should be 0 for constant values (every (lambda (p) (approx-equal? (cdr p) 0.0 0.001)) result)) ) (test-assert "bin-sds handles varying data" (let* ((x-vals '(1 2 3 4 5 6 7 8 9 10)) (y-vals '(10 20 30 40 50 60 70 80 90 100)) (result (bin-sds x-vals y-vals 2))) ;; SD should be > 0 for varying values (every (lambda (p) (> (cdr p) 0)) result)) )) (test-group "Integration Tests" (test-assert "Complete histogram pipeline" (let* ((breaks (histogram-breaks iris-sepal-length 10 #:method 'sturges))) (let-values (((edges counts) (histogram iris-sepal-length breaks))) (and (vector? counts) (= (apply + (vector->list counts)) (length iris-sepal-length))))) ) (test-assert "KDE with automatic bandwidth selection" (let* ((bw (kde-bandwidth-nrd iris-sepal-length)) (density (kde iris-sepal-length bw 'gaussian 256))) (and (= (length density) 256) (every (lambda (p) (>= (cdr p) 0)) density))) ) (test-assert "Boxplot statistics computation" (let ((five-num (fivenum iris-sepal-length))) (let-values (((outliers-list clean) (outliers iris-sepal-length #:coef 1.5))) (and (= (length five-num) 5) (>= (length clean) 0)))) ) (test-assert "Binned analysis pipeline" (begin (set-random-seed! 42) (let* ((x (iota 100)) (y (map (lambda (xi) (+ (* 2 xi) (random-uniform))) x)) (means (bin-means x y 10)) (sds (bin-sds x y 10))) (and (= (length means) 10) (= (length sds) 10) (every pair? means) (every pair? sds))) ))) (test-group "Edge Cases and Error Handling" (test-assert "Single-valued data" (let ((data '(5.0 5.0 5.0 5.0 5.0))) (and (approx-equal? (iqr data) 0.0 0.001) (let ((five-num (fivenum data))) (= (list-ref five-num 0) (list-ref five-num 4))))) ) (test-assert "Minimal valid data for fivenum" (let ((result (fivenum '(1 2 3 4 5)))) (= (length result) 5)) ) (test-assert "Histogram with single bin" (let* ((breaks (vector 0.0 10.0))) (let-values (((edges counts) (histogram normal-data breaks))) (= (vector-length counts) 1))) ) (test-assert "KDE with small bandwidth" (let ((result (kde normal-data 0.1 'gaussian 50))) (= (length result) 50)) ) (test-assert "KDE with large bandwidth" (let ((result (kde normal-data 100.0 'gaussian 50))) (and (= (length result) 50) (every (lambda (p) (>= (cdr p) 0)) result))) )) (test-exit)