diff --git a/functions.rkt b/functions.rkt index b6485c2..97dcdeb 100644 --- a/functions.rkt +++ b/functions.rkt @@ -1,4 +1,4 @@ -#lang racket +#lang typed/racket ;;; dds/functions @@ -9,93 +9,589 @@ (require "utils.rkt") -(module typed typed/racket - (require "utils.rkt" - syntax/parse/define typed/racket/stream - (only-in typed/racket/unsafe unsafe-provide) - (for-syntax syntax/parse)) +(require "utils.rkt" + syntax/parse/define typed/racket/stream + (only-in typed/racket/unsafe unsafe-provide) + (for-syntax syntax/parse)) - (require/typed racket/stream - [stream-map (All (a b) (-> (-> a b) (Sequenceof a) (Sequenceof b)))]) +(require/typed racket/stream + [stream-map (All (a b) (-> (-> a b) (Sequenceof a) (Sequenceof b)))]) + +(provide + pseudovariadic-lambda pvλ pseudovariadic-define pvdefine + tabulate* tabulate*/strict tabulate*/pv tabulate tabulate/strict tabulate/pv + tabulate*/pv/boolean tabulate/pv/boolean tabulate*/pv/01 tabulate/pv/01 + tabulate*/list tabulate/list + tabulate*/list/boolean tabulate/list/boolean tabulate*/list/01 tabulate/list/01 + table->function/list table->function table->function/pv + enumerate-boolean-tables enumerate-boolean-functions + enumerate-boolean-functions/pv enumerate-boolean-functions/list + random-boolean-table random-boolean-function random-boolean-function/list + + (struct-out tbf) tbf-w tbf-θ boolean->01/vector apply-tbf apply-tbf/boolean + list->tbf lists->tbfs read-org-tbfs tbf-tabulate* tbf-tabulate + tbf-tabulate*/boolean sbf? sbf list->sbf read-org-sbfs) + +(module+ test + (require typed/rackunit)) + +(begin-for-syntax + (require racket (for-syntax syntax/parse)) + + (define (make-pseudovariadic-core args bodies tag-stx) + (define nargs-stx (datum->syntax args (length (syntax->list args)))) + #`(λ xs + (match xs + [(list #,@args) #,@bodies] + [_ (error #,tag-stx "invalid arity, expected ~a argument(s)" #,nargs-stx)]))) + + (define (make-pseudovariadic-lambda stx) + (syntax-parse stx + [(_ (args:id ...) bodies:expr ...) + (make-pseudovariadic-core #'(args ...) + #'(bodies ...) + (datum->syntax stx ''pseudovariadic-lambda))])) + + (define (make-pseudovariadic-define stx) + (syntax-parse stx + [(_ (name:id args:id ...) bodies:expr ...) + #`(define name + #,(make-pseudovariadic-core + #'(args ...) + #'(bodies ...) + (datum->syntax #'name `(quote ,(syntax->datum #'name)))))]))) + +(define-syntax (pseudovariadic-lambda stx) (make-pseudovariadic-lambda stx)) +(define-syntax (pvλ stx) (make-pseudovariadic-lambda stx)) + +(module+ test + (test-case "pseudovariadic-lambda") + (check-false ((pseudovariadic-lambda (x y) (and x y)) #t #f)) + (check-false ((pvλ (x y) (and x y)) #t #f)) + (check-exn exn:fail? (λ () ((pseudovariadic-lambda (x y) (and x y)) #t #f #f))) + (check-exn exn:fail? (λ () ((pvλ (x y) (and x y)) #t #f #f)))) + +(define-syntax (pseudovariadic-define stx) (make-pseudovariadic-define stx)) +(define-syntax (pvdefine stx) (make-pseudovariadic-define stx)) + +(module+ test + (test-case "pseudovariadic-define") + (: f (-> Boolean * Boolean)) + (pseudovariadic-define (f x y) (and x y)) + (check-false (f #t #f)) + (check-exn exn:fail? (λ () (f #t #f #f))) + + (: g (-> Boolean * Boolean)) + (pvdefine (g x y) (and x y)) + (check-false (g #t #f)) + (check-exn exn:fail? (λ () (g #t #f #f)))) + +(define-syntax-parse-rule (make-tabulate* name:id row-op:id apply-op:id) + (define (name funcs doms) + (for/list ([xs (in-list (apply cartesian-product doms))]) + (row-op xs (for/list ([f funcs]) : (Listof b) + (apply-op f xs)))))) + +(: tabulate* (All (b a ... ) (-> (Listof (-> a ... b)) (List (Listof a) ... a) + (Listof (Listof (U Any b)))))) +(make-tabulate* tabulate* append apply) + +(module+ test + (test-case "tabulate*" + (check-equal? (tabulate* + (list (λ (x y) (and x y)) + (λ (x y) (or x y))) + '((#f #t) (#f #t))) + '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))) + (check-equal? (tabulate* empty '((#f #t) (#f #t))) + '((#f #f) (#f #t) (#t #f) (#t #t))))) + +(: tabulate*/strict (All (b a ...) (-> (Listof (-> a ... b)) (List (Listof a) ... a) + (Listof (List (List a ...) (Listof b)))))) +(make-tabulate* tabulate*/strict list apply) + +(module+ test + (test-case "tabulate*/strict" + (check-equal? (tabulate*/strict + (list (λ (x y) (and x y)) + (λ (x y) (or x y))) + '((#f #t) (#f #t))) + '(((#f #f) (#f #f)) ((#f #t) (#f #t)) ((#t #f) (#f #t)) ((#t #t) (#t #t)))))) + + +(: tabulate*/pv (All (a b) (-> (Listof (-> a * b)) (Listof (Listof a)) + (Listof (Listof (U a b)))))) +(make-tabulate* tabulate*/pv append apply) + +(module+ test + (test-case "tabulate*/pv" + (check-equal? (tabulate*/pv (list (pvλ (x y) (and x y)) + (pvλ (x y) (or x y))) + '((#f #t) (#f #t))) + '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))))) + +(define-syntax-parse-rule (simple-apply func:expr arg:expr) + (func arg)) + +(: tabulate*/list (All (a b) (-> (Listof (-> (Listof a) b)) (Listof (Listof a)) + (Listof (Listof (U a b)))))) +(make-tabulate* tabulate*/list append simple-apply) + +(module+ test + (test-case "tabulate*/list" + (check-equal? (tabulate*/list (list (λ ([xs : (Listof Boolean)]) + (and (car xs) (cadr xs))) + (λ ([xs : (Listof Boolean)]) + (or (car xs) (cadr xs)))) + '((#f #t) (#f #t))) + '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))))) + +(: tabulate (All (b a ...) (-> (-> a ... b) (List (Listof a) ... a) + (Listof (Listof (U Any b)))))) +(define (tabulate func doms) + (tabulate* (list func) doms)) + +(module+ test + (test-case "tabulate" + (check-equal? (tabulate (λ (x y) (and x y)) '((#f #t) (#f #t))) + '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) + +(: tabulate/strict (All (b a ...) (-> (-> a ... b) (List (Listof a) ... a) + (Listof (List (List a ...) (Listof b)))))) +(define (tabulate/strict func doms) + (tabulate*/strict (list func) doms)) + +(module+ test + (test-case "tabulate/strict" + (check-equal? (tabulate/strict (λ (x y) (and x y)) '((#f #t) (#f #t))) + '(((#f #f) (#f)) ((#f #t) (#f)) ((#t #f) (#f)) ((#t #t) (#t)))))) + +(: tabulate/pv (All (a b) (-> (-> a * b) (Listof (Listof a)) + (Listof (Listof (U a b)))))) +(define (tabulate/pv func doms) + (tabulate*/pv (list func) doms)) + +(module+ test + (test-case "tabulate/pv" + (check-equal? (tabulate/pv (pvλ (x y) (and x y)) '((#f #t) (#f #t))) + '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) + +(: tabulate/list (All (a b) (-> (-> (Listof a) b) (Listof (Listof a)) + (Listof (Listof (U a b)))))) +(define (tabulate/list func doms) + (tabulate*/list (list func) doms)) + +(module+ test + (test-case "tabulate/list" + (check-equal? (tabulate/list (λ ([xs : (Listof Boolean)]) + (and (car xs) (cadr xs))) + '((#f #t) (#f #t))) + '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) + +(: tabulate/pv/boolean (-> Positive-Integer (-> Boolean * Boolean) (Listof (Listof Boolean)))) +(define (tabulate/pv/boolean arity func) + (tabulate/pv func (make-list arity '(#f #t)))) + +(module+ test + (test-case "tabulate/pv/boolean" + (check-equal? (tabulate/pv/boolean 2 (pvλ (x y) (and x y))) + '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) + +(: tabulate*/pv/boolean (-> Positive-Integer (Listof (-> Boolean * Boolean)) + (Listof (Listof Boolean)))) +(define (tabulate*/pv/boolean arity funcs) + (tabulate*/pv funcs (make-list arity '(#f #t)))) + +(module+ test + (test-case "tabulate*/pv/boolean" + (check-equal? (tabulate*/pv/boolean 2 (list (pvλ (x y) (and x y)) + (pvλ (x y) (or x y)))) + '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))))) + +(: tabulate/pv/01 (-> Positive-Integer (-> (U Zero One) * (U Zero One)) + (Listof (Listof (U Zero One))))) +(define (tabulate/pv/01 arity func) + (tabulate/pv func (make-list arity '(0 1)))) + +(module+ test + (test-case "tabulate/pv/01" + (check-equal? (tabulate/pv/01 2 (pvλ (x y) + (assert-type (modulo (+ x y) 2) (U Zero One)))) + '((0 0 0) (0 1 1) (1 0 1) (1 1 0))))) + +(: tabulate*/pv/01 (-> Positive-Integer (Listof (-> (U Zero One) * (U Zero One))) + (Listof (Listof (U Zero One))))) +(define (tabulate*/pv/01 arity funcs) + (tabulate*/pv funcs (make-list arity '(0 1)))) + +(module+ test + (test-case "tabulate*/pv/01" + (check-equal? (tabulate*/pv/01 2 `(,(pvλ (x y) (assert-type (min x y) (U Zero One))) + ,(pvλ (x y) (assert-type (max x y) (U Zero One))))) + '((0 0 0 0) (0 1 0 1) (1 0 0 1) (1 1 1 1))))) + +(: tabulate/list/boolean (-> Positive-Integer (-> (Listof Boolean) Boolean) + (Listof (Listof Boolean)))) +(define (tabulate/list/boolean arity func) + (tabulate/list func (make-list arity '(#f #t)))) + +(module+ test + (test-case "tabulate/list/boolean" + (check-equal? (tabulate/list/boolean 2 (λ (xs) (and (car xs) (cadr xs)))) + '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) + +(: tabulate*/list/boolean (-> Positive-Integer (Listof (-> (Listof Boolean) Boolean)) + (Listof (Listof Boolean)))) +(define (tabulate*/list/boolean arity funcs) + (tabulate*/list funcs (make-list arity '(#f #t)))) + +(module+ test + (test-case "tabulate*/list/boolean" + (check-equal? + (tabulate*/list/boolean 2 (list (λ (xs) (and (car xs) (cadr xs))) + (λ (xs) (or (car xs) (cadr xs))))) + '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))))) + +(: tabulate/list/01 (-> Positive-Integer (-> (Listof (U Zero One)) (U Zero One)) + (Listof (Listof (U Zero One))))) +(define (tabulate/list/01 arity func) + (tabulate/list func (make-list arity '(0 1)))) + +(module+ test + (test-case "tabulate/list/01" + (check-equal? + (tabulate/list/01 2 (λ (xs) + (assert-type (modulo (+ (car xs) (cadr xs)) 2) (U Zero One)))) + '((0 0 0) (0 1 1) (1 0 1) (1 1 0))))) + +(: tabulate*/list/01 (-> Positive-Integer (Listof (-> (Listof (U Zero One)) (U Zero One))) + (Listof (Listof (U Zero One))))) +(define (tabulate*/list/01 arity funcs) + (tabulate*/list funcs (make-list arity '(0 1)))) + +(module+ test + (test-case "tabulate*/list/01" + (check-equal? (tabulate*/list/01 + 2 + `(,(λ (xs) (assert-type (min (car xs) (cadr xs)) (U Zero One))) + ,(λ (xs) (assert-type (max (car xs) (cadr xs)) (U Zero One))))) + '((0 0 0 0) (0 1 0 1) (1 0 0 1) (1 1 1 1))))) + +(: table->function/list (All (a) (-> (Listof (Listof a)) + (-> (Listof a) a)))) +(define (table->function/list table) + (define ht-tab + (for/hash ([line (in-list table)]) : (HashTable (Listof a) a) + (define-values (x fx) (split-at-right line 1)) + (values x (car fx)))) + (λ (x) (hash-ref ht-tab x))) + +(module+ test + (test-case "table->function/list" + (define negation/list (table->function/list '((#t #f) (#f #t)))) + (check-true (negation/list '(#f))) + (check-false (negation/list '(#t))))) + +(: table->function (All (a) (-> (Listof (Listof a)) (-> a * a)))) +(define (table->function table) + (define func (table->function/list table)) + (λ args (func args))) + +(module+ test + (test-case "table->function" + (define negation (table->function '((#t #f) (#f #t)))) + (check-true (negation #f)) + (check-false (negation #t)))) + +(: table->function/pv (All (a) (-> (Listof (Listof a)) (-> a * a)))) +(define (table->function/pv table) + (define func (table->function/list table)) + (define arity (- (length (car table)) 1)) + (λ xs + (if (= arity (length xs)) + (func xs) + (error 'pseudovariadic-lambda + "invalid arity, expected ~a argument(s)" + arity)))) + +(module+ test + (test-case "table->function/pv" + (define negation (table->function/pv '((#t #f) (#f #t)))) + (check-true (negation #f)) + (check-false (negation #t)) + (check-exn exn:fail? (λ () (negation #f #t))))) + +(: enumerate-boolean-tables (-> Positive-Integer (Sequenceof (Listof (Listof Boolean))))) +(define (enumerate-boolean-tables n) + (define inputs (boolean-power n)) + (define outputs (boolean-power/stream (assert-type (expt 2 n) Integer))) + + (: append-outputs (-> (Listof (Listof Boolean)) (Listof Boolean) + (Listof (Listof Boolean)))) + (define (append-outputs ins outs) + (for/list ([row ins] [o outs]) (append row (list o)))) + + (: yield (-> (Sequenceof (Listof Boolean)) (Sequenceof (Listof (Listof Boolean))))) + (define (yield rest-outputs) + (if (stream-empty? rest-outputs) + (stream) + (stream-cons (append-outputs inputs (stream-first rest-outputs)) + (yield (stream-rest rest-outputs))))) + + (yield outputs)) + +(module+ test + (test-case "enumerate-boolean-tables" + (check-equal? (stream->list (enumerate-boolean-tables 2)) + '(((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #f)) + ((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t)) + ((#f #f #f) (#f #t #f) (#t #f #t) (#t #t #f)) + ((#f #f #f) (#f #t #f) (#t #f #t) (#t #t #t)) + ((#f #f #f) (#f #t #t) (#t #f #f) (#t #t #f)) + ((#f #f #f) (#f #t #t) (#t #f #f) (#t #t #t)) + ((#f #f #f) (#f #t #t) (#t #f #t) (#t #t #f)) + ((#f #f #f) (#f #t #t) (#t #f #t) (#t #t #t)) + ((#f #f #t) (#f #t #f) (#t #f #f) (#t #t #f)) + ((#f #f #t) (#f #t #f) (#t #f #f) (#t #t #t)) + ((#f #f #t) (#f #t #f) (#t #f #t) (#t #t #f)) + ((#f #f #t) (#f #t #f) (#t #f #t) (#t #t #t)) + ((#f #f #t) (#f #t #t) (#t #f #f) (#t #t #f)) + ((#f #f #t) (#f #t #t) (#t #f #f) (#t #t #t)) + ((#f #f #t) (#f #t #t) (#t #f #t) (#t #t #f)) + ((#f #f #t) (#f #t #t) (#t #f #t) (#t #t #t)))))) + +(: enumerate-boolean-functions (-> Positive-Integer (Sequenceof (-> Boolean * Boolean)))) +(define (enumerate-boolean-functions n) + (stream-map (inst table->function Boolean) (enumerate-boolean-tables n))) + +(module+ test + (test-case "enumerate-boolean-functions" + (define bool-f1 (stream-first (enumerate-boolean-functions 1))) + (check-false (bool-f1 #f)) + (check-false (bool-f1 #t)))) + +(: enumerate-boolean-functions/pv (-> Positive-Integer (Sequenceof (-> Boolean * Boolean)))) +(define (enumerate-boolean-functions/pv n) + (stream-map (inst table->function/pv Boolean) (enumerate-boolean-tables n))) + +(module+ test + (test-case "enumerate-boolean-functions/pv" + (define bool-f1/pv (stream-first (enumerate-boolean-functions/pv 1))) + (check-false (bool-f1/pv #f)) + (check-false (bool-f1/pv #t)) + (check-exn exn:fail? (λ () (bool-f1/pv #f #f))))) + +(: enumerate-boolean-functions/list + (-> Positive-Integer (Sequenceof (-> (Listof Boolean) Boolean)))) +(define (enumerate-boolean-functions/list n) + (stream-map (inst table->function/list Boolean) (enumerate-boolean-tables n))) + +(module+ test + (test-case "enumerate-boolean-functions/list" + (define bool-f1/list (stream-first (enumerate-boolean-functions/list 1))) + (check-false (bool-f1/list '(#f))) + (check-false (bool-f1/list '(#t))))) + +(: random-boolean-table (-> Positive-Integer (Listof (Listof Boolean)))) +(define (random-boolean-table n) + (define ins (boolean-power n)) + (define outs (stream-take (in-random 2) (assert-type (expt 2 n) Nonnegative-Integer))) + (for/list ([i ins] [o outs]) + (append i (list (if (= o 1) #t #f))))) + +(module+ test + (test-case "random-boolean-table" + (random-seed 1) + (check-equal? (random-boolean-table 2) + '((#f #f #t) + (#f #t #t) + (#t #f #f) + (#t #t #t))))) + +(: random-boolean-function (-> Positive-Integer (-> Boolean * Boolean))) +(define (random-boolean-function n) + (table->function (random-boolean-table n))) + +(module+ test + (test-case "random-boolean-function" + (random-seed 1) + (define random-bool-f (random-boolean-function 2)) + (check-true (random-bool-f #f #f)) + (check-true (random-bool-f #f #t)) + (check-false (random-bool-f #t #f)) + (check-true (random-bool-f #t #t)))) + +(: random-boolean-function/list (-> Positive-Integer (-> (Listof Boolean) Boolean))) +(define (random-boolean-function/list n) + (table->function/list (random-boolean-table n))) + +(module+ test + (test-case "random-boolean-function/list" + (random-seed 1) + (define random-bool-f/list (random-boolean-function/list 2)) + (check-true (random-bool-f/list '(#f #f))) + (check-true (random-bool-f/list '(#f #t))) + (check-false (random-bool-f/list '(#t #f))) + (check-true (random-bool-f/list '(#t #t))))) + +(struct tbf ([weights : (Vectorof Real)] [threshold : Real]) #:transparent) +(define tbf-w tbf-weights) +(define tbf-θ tbf-threshold) + +(: boolean->01/vector (-> (Vectorof Boolean) (Vectorof (U Zero One)))) +(define (boolean->01/vector bool-v) + (vector-map (λ (x) (any->01 x)) bool-v)) + +(module+ test + (test-case "boolean->01/vector" + (check-equal? (boolean->01/vector #(#t #f #f)) #(1 0 0)))) + +(: apply-tbf (-> tbf (Vectorof (U Zero One)) (U Zero One))) +(define (apply-tbf tbf inputs) + (any->01 + (> + ;; The scalar product between the inputs and the weights. + (for/sum ([x (in-vector inputs)] + [w (in-vector (tbf-w tbf))]) : Real + (* x w)) + (tbf-θ tbf)))) + +(module+ test + (test-case "apply-tbf" + (define f1 (tbf #(2 -2) 1)) + (check-equal? (tabulate/pv/01 2 (pvλ (x y) (apply-tbf f1 (vector x y)))) + '((0 0 0) (0 1 0) (1 0 1) (1 1 0))))) + +(: apply-tbf/boolean (-> tbf (Vectorof Boolean) Boolean)) +(define (apply-tbf/boolean tbf inputs) + (01->boolean (apply-tbf tbf (boolean->01/vector inputs)))) + +(module+ test + (test-case "apply-tbf/boolean" + (define f1 (tbf #(2 -2) 1)) + (check-equal? (tabulate/pv/boolean 2 (pvλ (x y) (apply-tbf/boolean f1 (vector x y)))) + '((#f #f #f) (#f #t #f) (#t #f #t) (#t #t #f))))) + +(: list->tbf (-> (Listof Real) tbf)) +(define (list->tbf lst) + (define-values (w θ) (split-at-right lst 1)) + (tbf (list->vector w) (car θ))) + +(module+ test + (test-case "list->tbf" + (check-equal? (list->tbf '(1 2 3)) (tbf #(1 2) 3)))) + +(: lists->tbfs (-> (Listof (Listof Real)) (Listof tbf))) +(define (lists->tbfs lsts) + (map list->tbf lsts)) + +(module+ test + (test-case "read-tbfs" + (check-equal? (lists->tbfs '((1 2 3) (2 3 4))) + (list (tbf '#(1 2) 3) (tbf '#(2 3) 4))))) + +(: read-org-tbfs (->* (String) (#:headers Boolean) (Listof tbf))) +(define (read-org-tbfs str #:headers [headers #f]) + (define sexp (assert-type (read-org-sexp str) (Listof Any))) + (define sexp-clean (cond [headers (cdr sexp)] [else sexp])) + (lists->tbfs (assert-type sexp-clean (Listof (Listof Real))))) + +(module+ test + (test-case "read-org-tbfs" + (check-equal? (read-org-tbfs "((1 2 1) (1 0 1))") + (list (tbf '#(1 2) 1) (tbf '#(1 0) 1))))) + +(: tbf-tabulate* (-> (Listof tbf) (Listof (Listof (U Zero One))))) +(define (tbf-tabulate* tbfs) + (define funcs (for/list ([tbf tbfs]) + : (Listof (-> (Listof (U Zero One)) (U Zero One))) + (λ ([in : (Listof (U Zero One))]) + (apply-tbf tbf (list->vector in))))) + (define nvars (vector-length (tbf-w (car tbfs)))) + (tabulate*/list funcs (make-list nvars '(0 1)))) + +(module+ test + (test-case "tbf-tabulate*" + (check-equal? (tbf-tabulate* (list (tbf #(2 2) 1) (tbf #(1 1) 1))) + '((0 0 0 0) (0 1 1 0) (1 0 1 0) (1 1 1 1))))) + +(: tbf-tabulate (-> tbf (Listof (Listof (U Zero One))))) +(define (tbf-tabulate t) + (tbf-tabulate* (list t))) + +(module+ test + (test-case "tbf-tabulate" + (check-equal? (tbf-tabulate (tbf #(1 2) 1)) + '((0 0 0) (0 1 1) (1 0 0) (1 1 1))))) + +(: tbf-tabulate*/boolean (-> (Listof tbf) (Listof (Listof Boolean)))) +(define (tbf-tabulate*/boolean tbfs) + (define funcs (for/list ([tbf tbfs]) + : (Listof (-> (Listof Boolean) Boolean)) + (λ ([in : (Listof Boolean)]) + (apply-tbf/boolean tbf (list->vector in))))) + (define nvars (vector-length (tbf-w (car tbfs)))) + (tabulate*/list funcs (make-list nvars '(#f #t)))) + +(module+ test + (test-case "tbf-tabulate*/boolean" + (check-equal? (tbf-tabulate*/boolean (list (tbf #(1 2) 1))) + '((#f #f #f) (#f #t #t) (#t #f #f) (#t #t #t))))) + +(: sbf? (-> tbf Boolean)) +(define (sbf? t) + (= 0 (tbf-θ t))) + +(module+ test + (test-case "sbf?" + (check-false (sbf? (tbf #(1 2) 3))) + (check-true (sbf? (tbf #(1 2) 0))))) + +(: sbf (-> (Vectorof Real) tbf)) +(define (sbf w) + (tbf w 0)) + +(module+ test + (test-case "sbf" + (check-equal? (sbf #(1 -1)) (tbf '#(1 -1) 0)))) + +(: list->sbf (-> (Listof Real) tbf)) +(define (list->sbf lst) (sbf (list->vector lst))) + +(module+ test + (test-case "list->sbf" + (check-equal? (list->sbf '(1 -1)) (tbf '#(1 -1) 0)))) + +(: read-org-sbfs (->* (String) (#:headers Boolean) (Listof tbf))) +(define (read-org-sbfs str #:headers [headers #f]) + (define sexp (assert-type (read-org-sexp str) (Listof Any))) + (define sexp-clean (cond [headers (cdr sexp)] [else sexp])) + (map list->sbf (assert-type sexp-clean (Listof (Listof Real))))) + +(module+ test + (test-case "read-org-sbfs" + (check-equal? (read-org-sbfs "((1 1) (1 -1))") + (list (tbf '#(1 1) 0) (tbf '#(1 -1) 0))))) + +(module untyped racket + (module+ test + (require rackunit)) (provide - pseudovariadic-lambda pvλ pseudovariadic-define pvdefine - tabulate* tabulate*/strict tabulate*/pv tabulate tabulate/strict tabulate/pv - tabulate*/pv/boolean tabulate/pv/boolean tabulate*/pv/01 tabulate/pv/01 - tabulate*/list tabulate/list - tabulate*/list/boolean tabulate/list/boolean tabulate*/list/01 tabulate/list/01 - table->function/list table->function table->function/pv - enumerate-boolean-tables enumerate-boolean-functions - enumerate-boolean-functions/pv enumerate-boolean-functions/list - random-boolean-table random-boolean-function random-boolean-function/list + (contract-out [tabulate* (-> (listof procedure?) (listof (listof any/c)) + (listof (listof any/c)))] + [tabulate (-> procedure? (listof (listof any/c)) + (listof (listof any/c)))] + [tabulate/boolean (-> procedure? (listof (listof boolean?)))] + [tabulate*/boolean (-> (non-empty-listof procedure?) + (listof (listof boolean?)))] + [tabulate/01 (-> procedure? (listof (listof (or/c 0 1))))] + [tabulate*/01 (-> (non-empty-listof procedure?) (listof (listof (or/c 0 1))))])) - (struct-out tbf) tbf-w tbf-θ boolean->01/vector apply-tbf apply-tbf/boolean - list->tbf lists->tbfs read-org-tbfs tbf-tabulate* tbf-tabulate - tbf-tabulate*/boolean sbf? sbf list->sbf read-org-sbfs) - - (module+ test - (require typed/rackunit)) - - (begin-for-syntax - (require racket (for-syntax syntax/parse)) - - (define (make-pseudovariadic-core args bodies tag-stx) - (define nargs-stx (datum->syntax args (length (syntax->list args)))) - #`(λ xs - (match xs - [(list #,@args) #,@bodies] - [_ (error #,tag-stx "invalid arity, expected ~a argument(s)" #,nargs-stx)]))) - - (define (make-pseudovariadic-lambda stx) - (syntax-parse stx - [(_ (args:id ...) bodies:expr ...) - (make-pseudovariadic-core #'(args ...) - #'(bodies ...) - (datum->syntax stx ''pseudovariadic-lambda))])) - - (define (make-pseudovariadic-define stx) - (syntax-parse stx - [(_ (name:id args:id ...) bodies:expr ...) - #`(define name - #,(make-pseudovariadic-core - #'(args ...) - #'(bodies ...) - (datum->syntax #'name `(quote ,(syntax->datum #'name)))))]))) - - (define-syntax (pseudovariadic-lambda stx) (make-pseudovariadic-lambda stx)) - (define-syntax (pvλ stx) (make-pseudovariadic-lambda stx)) - - (module+ test - (test-case "pseudovariadic-lambda") - (check-false ((pseudovariadic-lambda (x y) (and x y)) #t #f)) - (check-false ((pvλ (x y) (and x y)) #t #f)) - (check-exn exn:fail? (λ () ((pseudovariadic-lambda (x y) (and x y)) #t #f #f))) - (check-exn exn:fail? (λ () ((pvλ (x y) (and x y)) #t #f #f)))) - - (define-syntax (pseudovariadic-define stx) (make-pseudovariadic-define stx)) - (define-syntax (pvdefine stx) (make-pseudovariadic-define stx)) - - (module+ test - (test-case "pseudovariadic-define") - (: f (-> Boolean * Boolean)) - (pseudovariadic-define (f x y) (and x y)) - (check-false (f #t #f)) - (check-exn exn:fail? (λ () (f #t #f #f))) - - (: g (-> Boolean * Boolean)) - (pvdefine (g x y) (and x y)) - (check-false (g #t #f)) - (check-exn exn:fail? (λ () (g #t #f #f)))) - - (define-syntax-parse-rule (make-tabulate* name:id row-op:id apply-op:id) - (define (name funcs doms) - (for/list ([xs (in-list (apply cartesian-product doms))]) - (row-op xs (for/list ([f funcs]) : (Listof b) - (apply-op f xs)))))) - - (: tabulate* (All (b a ... ) (-> (Listof (-> a ... b)) (List (Listof a) ... a) - (Listof (Listof (U Any b)))))) - (make-tabulate* tabulate* append apply) + (define (tabulate* funcs doms) + (for/list ([xs (in-list (apply cartesian-product doms))]) + (append xs (for/list ([f funcs]) + (apply f xs))))) (module+ test (test-case "tabulate*" @@ -107,48 +603,6 @@ (check-equal? (tabulate* empty '((#f #t) (#f #t))) '((#f #f) (#f #t) (#t #f) (#t #t))))) - (: tabulate*/strict (All (b a ...) (-> (Listof (-> a ... b)) (List (Listof a) ... a) - (Listof (List (List a ...) (Listof b)))))) - (make-tabulate* tabulate*/strict list apply) - - (module+ test - (test-case "tabulate*/strict" - (check-equal? (tabulate*/strict - (list (λ (x y) (and x y)) - (λ (x y) (or x y))) - '((#f #t) (#f #t))) - '(((#f #f) (#f #f)) ((#f #t) (#f #t)) ((#t #f) (#f #t)) ((#t #t) (#t #t)))))) - - - (: tabulate*/pv (All (a b) (-> (Listof (-> a * b)) (Listof (Listof a)) - (Listof (Listof (U a b)))))) - (make-tabulate* tabulate*/pv append apply) - - (module+ test - (test-case "tabulate*/pv" - (check-equal? (tabulate*/pv (list (pvλ (x y) (and x y)) - (pvλ (x y) (or x y))) - '((#f #t) (#f #t))) - '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))))) - - (define-syntax-parse-rule (simple-apply func:expr arg:expr) - (func arg)) - - (: tabulate*/list (All (a b) (-> (Listof (-> (Listof a) b)) (Listof (Listof a)) - (Listof (Listof (U a b)))))) - (make-tabulate* tabulate*/list append simple-apply) - - (module+ test - (test-case "tabulate*/list" - (check-equal? (tabulate*/list (list (λ ([xs : (Listof Boolean)]) - (and (car xs) (cadr xs))) - (λ ([xs : (Listof Boolean)]) - (or (car xs) (cadr xs)))) - '((#f #t) (#f #t))) - '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))))) - - (: tabulate (All (b a ...) (-> (-> a ... b) (List (Listof a) ... a) - (Listof (Listof (U Any b)))))) (define (tabulate func doms) (tabulate* (list func) doms)) @@ -157,511 +611,37 @@ (check-equal? (tabulate (λ (x y) (and x y)) '((#f #t) (#f #t))) '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) - (: tabulate/strict (All (b a ...) (-> (-> a ... b) (List (Listof a) ... a) - (Listof (List (List a ...) (Listof b)))))) - (define (tabulate/strict func doms) - (tabulate*/strict (list func) doms)) + (define (tabulate/boolean func) + (tabulate func (make-list (procedure-arity func) '(#f #t)))) (module+ test - (test-case "tabulate/strict" - (check-equal? (tabulate/strict (λ (x y) (and x y)) '((#f #t) (#f #t))) - '(((#f #f) (#f)) ((#f #t) (#f)) ((#t #f) (#f)) ((#t #t) (#t)))))) - - (: tabulate/pv (All (a b) (-> (-> a * b) (Listof (Listof a)) - (Listof (Listof (U a b)))))) - (define (tabulate/pv func doms) - (tabulate*/pv (list func) doms)) - - (module+ test - (test-case "tabulate/pv" - (check-equal? (tabulate/pv (pvλ (x y) (and x y)) '((#f #t) (#f #t))) + (test-case "tabulate/boolean" + (check-equal? (tabulate/boolean (lambda (x y) (and x y))) '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) - (: tabulate/list (All (a b) (-> (-> (Listof a) b) (Listof (Listof a)) - (Listof (Listof (U a b)))))) - (define (tabulate/list func doms) - (tabulate*/list (list func) doms)) + (define (tabulate*/boolean funcs) + (define doms (make-list (procedure-arity (car funcs)) '(#f #t))) + (tabulate* funcs doms)) (module+ test - (test-case "tabulate/list" - (check-equal? (tabulate/list (λ ([xs : (Listof Boolean)]) - (and (car xs) (cadr xs))) - '((#f #t) (#f #t))) - '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) - - (: tabulate/pv/boolean (-> Positive-Integer (-> Boolean * Boolean) (Listof (Listof Boolean)))) - (define (tabulate/pv/boolean arity func) - (tabulate/pv func (make-list arity '(#f #t)))) - - (module+ test - (test-case "tabulate/pv/boolean" - (check-equal? (tabulate/pv/boolean 2 (pvλ (x y) (and x y))) - '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) - - (: tabulate*/pv/boolean (-> Positive-Integer (Listof (-> Boolean * Boolean)) - (Listof (Listof Boolean)))) - (define (tabulate*/pv/boolean arity funcs) - (tabulate*/pv funcs (make-list arity '(#f #t)))) - - (module+ test - (test-case "tabulate*/pv/boolean" - (check-equal? (tabulate*/pv/boolean 2 (list (pvλ (x y) (and x y)) - (pvλ (x y) (or x y)))) + (test-case "tabulate*/boolean" + (check-equal? (tabulate*/boolean `(,(λ (x y) (and x y)) + ,(λ (x y) (or x y)))) '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))))) - (: tabulate/pv/01 (-> Positive-Integer (-> (U Zero One) * (U Zero One)) - (Listof (Listof (U Zero One))))) - (define (tabulate/pv/01 arity func) - (tabulate/pv func (make-list arity '(0 1)))) + (define (tabulate/01 func) + (tabulate func (make-list (procedure-arity func) '(0 1)))) (module+ test - (test-case "tabulate/pv/01" - (check-equal? (tabulate/pv/01 2 (pvλ (x y) - (assert-type (modulo (+ x y) 2) (U Zero One)))) + (test-case "tabulate/01" + (check-equal? (tabulate/01 (λ (x y) (modulo (+ x y) 2))) '((0 0 0) (0 1 1) (1 0 1) (1 1 0))))) - (: tabulate*/pv/01 (-> Positive-Integer (Listof (-> (U Zero One) * (U Zero One))) - (Listof (Listof (U Zero One))))) - (define (tabulate*/pv/01 arity funcs) - (tabulate*/pv funcs (make-list arity '(0 1)))) + (define (tabulate*/01 funcs) + (tabulate* funcs (make-list (procedure-arity (car funcs)) '(0 1)))) (module+ test - (test-case "tabulate*/pv/01" - (check-equal? (tabulate*/pv/01 2 `(,(pvλ (x y) (assert-type (min x y) (U Zero One))) - ,(pvλ (x y) (assert-type (max x y) (U Zero One))))) + (test-case "tabulate*/01" + (check-equal? (tabulate*/01 `(,(λ (x y) (min x y)) ,(λ (x y) (max x y)))) '((0 0 0 0) (0 1 0 1) (1 0 0 1) (1 1 1 1))))) - - (: tabulate/list/boolean (-> Positive-Integer (-> (Listof Boolean) Boolean) - (Listof (Listof Boolean)))) - (define (tabulate/list/boolean arity func) - (tabulate/list func (make-list arity '(#f #t)))) - - (module+ test - (test-case "tabulate/list/boolean" - (check-equal? (tabulate/list/boolean 2 (λ (xs) (and (car xs) (cadr xs)))) - '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) - - (: tabulate*/list/boolean (-> Positive-Integer (Listof (-> (Listof Boolean) Boolean)) - (Listof (Listof Boolean)))) - (define (tabulate*/list/boolean arity funcs) - (tabulate*/list funcs (make-list arity '(#f #t)))) - - (module+ test - (test-case "tabulate*/list/boolean" - (check-equal? - (tabulate*/list/boolean 2 (list (λ (xs) (and (car xs) (cadr xs))) - (λ (xs) (or (car xs) (cadr xs))))) - '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))))) - - (: tabulate/list/01 (-> Positive-Integer (-> (Listof (U Zero One)) (U Zero One)) - (Listof (Listof (U Zero One))))) - (define (tabulate/list/01 arity func) - (tabulate/list func (make-list arity '(0 1)))) - - (module+ test - (test-case "tabulate/list/01" - (check-equal? - (tabulate/list/01 2 (λ (xs) - (assert-type (modulo (+ (car xs) (cadr xs)) 2) (U Zero One)))) - '((0 0 0) (0 1 1) (1 0 1) (1 1 0))))) - - (: tabulate*/list/01 (-> Positive-Integer (Listof (-> (Listof (U Zero One)) (U Zero One))) - (Listof (Listof (U Zero One))))) - (define (tabulate*/list/01 arity funcs) - (tabulate*/list funcs (make-list arity '(0 1)))) - - (module+ test - (test-case "tabulate*/list/01" - (check-equal? (tabulate*/list/01 - 2 - `(,(λ (xs) (assert-type (min (car xs) (cadr xs)) (U Zero One))) - ,(λ (xs) (assert-type (max (car xs) (cadr xs)) (U Zero One))))) - '((0 0 0 0) (0 1 0 1) (1 0 0 1) (1 1 1 1))))) - - (: table->function/list (All (a) (-> (Listof (Listof a)) - (-> (Listof a) a)))) - (define (table->function/list table) - (define ht-tab - (for/hash ([line (in-list table)]) : (HashTable (Listof a) a) - (define-values (x fx) (split-at-right line 1)) - (values x (car fx)))) - (λ (x) (hash-ref ht-tab x))) - - (module+ test - (test-case "table->function/list" - (define negation/list (table->function/list '((#t #f) (#f #t)))) - (check-true (negation/list '(#f))) - (check-false (negation/list '(#t))))) - - (: table->function (All (a) (-> (Listof (Listof a)) (-> a * a)))) - (define (table->function table) - (define func (table->function/list table)) - (λ args (func args))) - - (module+ test - (test-case "table->function" - (define negation (table->function '((#t #f) (#f #t)))) - (check-true (negation #f)) - (check-false (negation #t)))) - - (: table->function/pv (All (a) (-> (Listof (Listof a)) (-> a * a)))) - (define (table->function/pv table) - (define func (table->function/list table)) - (define arity (- (length (car table)) 1)) - (λ xs - (if (= arity (length xs)) - (func xs) - (error 'pseudovariadic-lambda - "invalid arity, expected ~a argument(s)" - arity)))) - - (module+ test - (test-case "table->function/pv" - (define negation (table->function/pv '((#t #f) (#f #t)))) - (check-true (negation #f)) - (check-false (negation #t)) - (check-exn exn:fail? (λ () (negation #f #t))))) - - (: enumerate-boolean-tables (-> Positive-Integer (Sequenceof (Listof (Listof Boolean))))) - (define (enumerate-boolean-tables n) - (define inputs (boolean-power n)) - (define outputs (boolean-power/stream (assert-type (expt 2 n) Integer))) - - (: append-outputs (-> (Listof (Listof Boolean)) (Listof Boolean) - (Listof (Listof Boolean)))) - (define (append-outputs ins outs) - (for/list ([row ins] [o outs]) (append row (list o)))) - - (: yield (-> (Sequenceof (Listof Boolean)) (Sequenceof (Listof (Listof Boolean))))) - (define (yield rest-outputs) - (if (stream-empty? rest-outputs) - (stream) - (stream-cons (append-outputs inputs (stream-first rest-outputs)) - (yield (stream-rest rest-outputs))))) - - (yield outputs)) - - (module+ test - (test-case "enumerate-boolean-tables" - (check-equal? (stream->list (enumerate-boolean-tables 2)) - '(((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #f)) - ((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t)) - ((#f #f #f) (#f #t #f) (#t #f #t) (#t #t #f)) - ((#f #f #f) (#f #t #f) (#t #f #t) (#t #t #t)) - ((#f #f #f) (#f #t #t) (#t #f #f) (#t #t #f)) - ((#f #f #f) (#f #t #t) (#t #f #f) (#t #t #t)) - ((#f #f #f) (#f #t #t) (#t #f #t) (#t #t #f)) - ((#f #f #f) (#f #t #t) (#t #f #t) (#t #t #t)) - ((#f #f #t) (#f #t #f) (#t #f #f) (#t #t #f)) - ((#f #f #t) (#f #t #f) (#t #f #f) (#t #t #t)) - ((#f #f #t) (#f #t #f) (#t #f #t) (#t #t #f)) - ((#f #f #t) (#f #t #f) (#t #f #t) (#t #t #t)) - ((#f #f #t) (#f #t #t) (#t #f #f) (#t #t #f)) - ((#f #f #t) (#f #t #t) (#t #f #f) (#t #t #t)) - ((#f #f #t) (#f #t #t) (#t #f #t) (#t #t #f)) - ((#f #f #t) (#f #t #t) (#t #f #t) (#t #t #t)))))) - - (: enumerate-boolean-functions (-> Positive-Integer (Sequenceof (-> Boolean * Boolean)))) - (define (enumerate-boolean-functions n) - (stream-map (inst table->function Boolean) (enumerate-boolean-tables n))) - - (module+ test - (test-case "enumerate-boolean-functions" - (define bool-f1 (stream-first (enumerate-boolean-functions 1))) - (check-false (bool-f1 #f)) - (check-false (bool-f1 #t)))) - - (: enumerate-boolean-functions/pv (-> Positive-Integer (Sequenceof (-> Boolean * Boolean)))) - (define (enumerate-boolean-functions/pv n) - (stream-map (inst table->function/pv Boolean) (enumerate-boolean-tables n))) - - (module+ test - (test-case "enumerate-boolean-functions/pv" - (define bool-f1/pv (stream-first (enumerate-boolean-functions/pv 1))) - (check-false (bool-f1/pv #f)) - (check-false (bool-f1/pv #t)) - (check-exn exn:fail? (λ () (bool-f1/pv #f #f))))) - - (: enumerate-boolean-functions/list - (-> Positive-Integer (Sequenceof (-> (Listof Boolean) Boolean)))) - (define (enumerate-boolean-functions/list n) - (stream-map (inst table->function/list Boolean) (enumerate-boolean-tables n))) - - (module+ test - (test-case "enumerate-boolean-functions/list" - (define bool-f1/list (stream-first (enumerate-boolean-functions/list 1))) - (check-false (bool-f1/list '(#f))) - (check-false (bool-f1/list '(#t))))) - - (: random-boolean-table (-> Positive-Integer (Listof (Listof Boolean)))) - (define (random-boolean-table n) - (define ins (boolean-power n)) - (define outs (stream-take (in-random 2) (assert-type (expt 2 n) Nonnegative-Integer))) - (for/list ([i ins] [o outs]) - (append i (list (if (= o 1) #t #f))))) - - (module+ test - (test-case "random-boolean-table" - (random-seed 1) - (check-equal? (random-boolean-table 2) - '((#f #f #t) - (#f #t #t) - (#t #f #f) - (#t #t #t))))) - - (: random-boolean-function (-> Positive-Integer (-> Boolean * Boolean))) - (define (random-boolean-function n) - (table->function (random-boolean-table n))) - - (module+ test - (test-case "random-boolean-function" - (random-seed 1) - (define random-bool-f (random-boolean-function 2)) - (check-true (random-bool-f #f #f)) - (check-true (random-bool-f #f #t)) - (check-false (random-bool-f #t #f)) - (check-true (random-bool-f #t #t)))) - - (: random-boolean-function/list (-> Positive-Integer (-> (Listof Boolean) Boolean))) - (define (random-boolean-function/list n) - (table->function/list (random-boolean-table n))) - - (module+ test - (test-case "random-boolean-function/list" - (random-seed 1) - (define random-bool-f/list (random-boolean-function/list 2)) - (check-true (random-bool-f/list '(#f #f))) - (check-true (random-bool-f/list '(#f #t))) - (check-false (random-bool-f/list '(#t #f))) - (check-true (random-bool-f/list '(#t #t))))) - - (struct tbf ([weights : (Vectorof Real)] [threshold : Real]) #:transparent) - (define tbf-w tbf-weights) - (define tbf-θ tbf-threshold) - - (: boolean->01/vector (-> (Vectorof Boolean) (Vectorof (U Zero One)))) - (define (boolean->01/vector bool-v) - (vector-map (λ (x) (any->01 x)) bool-v)) - - (module+ test - (test-case "boolean->01/vector" - (check-equal? (boolean->01/vector #(#t #f #f)) #(1 0 0)))) - - (: apply-tbf (-> tbf (Vectorof (U Zero One)) (U Zero One))) - (define (apply-tbf tbf inputs) - (any->01 - (> - ;; The scalar product between the inputs and the weights. - (for/sum ([x (in-vector inputs)] - [w (in-vector (tbf-w tbf))]) : Real - (* x w)) - (tbf-θ tbf)))) - - (module+ test - (test-case "apply-tbf" - (define f1 (tbf #(2 -2) 1)) - (check-equal? (tabulate/pv/01 2 (pvλ (x y) (apply-tbf f1 (vector x y)))) - '((0 0 0) (0 1 0) (1 0 1) (1 1 0))))) - - (: apply-tbf/boolean (-> tbf (Vectorof Boolean) Boolean)) - (define (apply-tbf/boolean tbf inputs) - (01->boolean (apply-tbf tbf (boolean->01/vector inputs)))) - - (module+ test - (test-case "apply-tbf/boolean" - (define f1 (tbf #(2 -2) 1)) - (check-equal? (tabulate/pv/boolean 2 (pvλ (x y) (apply-tbf/boolean f1 (vector x y)))) - '((#f #f #f) (#f #t #f) (#t #f #t) (#t #t #f))))) - - (: list->tbf (-> (Listof Real) tbf)) - (define (list->tbf lst) - (define-values (w θ) (split-at-right lst 1)) - (tbf (list->vector w) (car θ))) - - (module+ test - (test-case "list->tbf" - (check-equal? (list->tbf '(1 2 3)) (tbf #(1 2) 3)))) - - (: lists->tbfs (-> (Listof (Listof Real)) (Listof tbf))) - (define (lists->tbfs lsts) - (map list->tbf lsts)) - - (module+ test - (test-case "read-tbfs" - (check-equal? (lists->tbfs '((1 2 3) (2 3 4))) - (list (tbf '#(1 2) 3) (tbf '#(2 3) 4))))) - - (: read-org-tbfs (->* (String) (#:headers Boolean) (Listof tbf))) - (define (read-org-tbfs str #:headers [headers #f]) - (define sexp (assert-type (read-org-sexp str) (Listof Any))) - (define sexp-clean (cond [headers (cdr sexp)] [else sexp])) - (lists->tbfs (assert-type sexp-clean (Listof (Listof Real))))) - - (module+ test - (test-case "read-org-tbfs" - (check-equal? (read-org-tbfs "((1 2 1) (1 0 1))") - (list (tbf '#(1 2) 1) (tbf '#(1 0) 1))))) - - (: tbf-tabulate* (-> (Listof tbf) (Listof (Listof (U Zero One))))) - (define (tbf-tabulate* tbfs) - (define funcs (for/list ([tbf tbfs]) - : (Listof (-> (Listof (U Zero One)) (U Zero One))) - (λ ([in : (Listof (U Zero One))]) - (apply-tbf tbf (list->vector in))))) - (define nvars (vector-length (tbf-w (car tbfs)))) - (tabulate*/list funcs (make-list nvars '(0 1)))) - - (module+ test - (test-case "tbf-tabulate*" - (check-equal? (tbf-tabulate* (list (tbf #(2 2) 1) (tbf #(1 1) 1))) - '((0 0 0 0) (0 1 1 0) (1 0 1 0) (1 1 1 1))))) - - (: tbf-tabulate (-> tbf (Listof (Listof (U Zero One))))) - (define (tbf-tabulate t) - (tbf-tabulate* (list t))) - - (module+ test - (test-case "tbf-tabulate" - (check-equal? (tbf-tabulate (tbf #(1 2) 1)) - '((0 0 0) (0 1 1) (1 0 0) (1 1 1))))) - - (: tbf-tabulate*/boolean (-> (Listof tbf) (Listof (Listof Boolean)))) - (define (tbf-tabulate*/boolean tbfs) - (define funcs (for/list ([tbf tbfs]) - : (Listof (-> (Listof Boolean) Boolean)) - (λ ([in : (Listof Boolean)]) - (apply-tbf/boolean tbf (list->vector in))))) - (define nvars (vector-length (tbf-w (car tbfs)))) - (tabulate*/list funcs (make-list nvars '(#f #t)))) - - (module+ test - (test-case "tbf-tabulate*/boolean" - (check-equal? (tbf-tabulate*/boolean (list (tbf #(1 2) 1))) - '((#f #f #f) (#f #t #t) (#t #f #f) (#t #t #t))))) - - (: sbf? (-> tbf Boolean)) - (define (sbf? t) - (= 0 (tbf-θ t))) - - (module+ test - (test-case "sbf?" - (check-false (sbf? (tbf #(1 2) 3))) - (check-true (sbf? (tbf #(1 2) 0))))) - - (: sbf (-> (Vectorof Real) tbf)) - (define (sbf w) - (tbf w 0)) - - (module+ test - (test-case "sbf" - (check-equal? (sbf #(1 -1)) (tbf '#(1 -1) 0)))) - - (: list->sbf (-> (Listof Real) tbf)) - (define (list->sbf lst) (sbf (list->vector lst))) - - (module+ test - (test-case "list->sbf" - (check-equal? (list->sbf '(1 -1)) (tbf '#(1 -1) 0)))) - - (: read-org-sbfs (->* (String) (#:headers Boolean) (Listof tbf))) - (define (read-org-sbfs str #:headers [headers #f]) - (define sexp (assert-type (read-org-sexp str) (Listof Any))) - (define sexp-clean (cond [headers (cdr sexp)] [else sexp])) - (map list->sbf (assert-type sexp-clean (Listof (Listof Real))))) - - (module+ test - (test-case "read-org-sbfs" - (check-equal? (read-org-sbfs "((1 1) (1 -1))") - (list (tbf '#(1 1) 0) (tbf '#(1 -1) 0))))) - - (module untyped racket - (module+ test - (require rackunit)) - - (provide - (contract-out [tabulate* (-> (listof procedure?) (listof (listof any/c)) - (listof (listof any/c)))] - [tabulate (-> procedure? (listof (listof any/c)) - (listof (listof any/c)))] - [tabulate/boolean (-> procedure? (listof (listof boolean?)))] - [tabulate*/boolean (-> (non-empty-listof procedure?) - (listof (listof boolean?)))] - [tabulate/01 (-> procedure? (listof (listof (or/c 0 1))))] - [tabulate*/01 (-> (non-empty-listof procedure?) (listof (listof (or/c 0 1))))])) - - (define (tabulate* funcs doms) - (for/list ([xs (in-list (apply cartesian-product doms))]) - (append xs (for/list ([f funcs]) - (apply f xs))))) - - (module+ test - (test-case "tabulate*" - (check-equal? (tabulate* - (list (λ (x y) (and x y)) - (λ (x y) (or x y))) - '((#f #t) (#f #t))) - '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))) - (check-equal? (tabulate* empty '((#f #t) (#f #t))) - '((#f #f) (#f #t) (#t #f) (#t #t))))) - - (define (tabulate func doms) - (tabulate* (list func) doms)) - - (module+ test - (test-case "tabulate" - (check-equal? (tabulate (λ (x y) (and x y)) '((#f #t) (#f #t))) - '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) - - (define (tabulate/boolean func) - (tabulate func (make-list (procedure-arity func) '(#f #t)))) - - (module+ test - (test-case "tabulate/boolean" - (check-equal? (tabulate/boolean (lambda (x y) (and x y))) - '((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t))))) - - (define (tabulate*/boolean funcs) - (define doms (make-list (procedure-arity (car funcs)) '(#f #t))) - (tabulate* funcs doms)) - - (module+ test - (test-case "tabulate*/boolean" - (check-equal? (tabulate*/boolean `(,(λ (x y) (and x y)) - ,(λ (x y) (or x y)))) - '((#f #f #f #f) (#f #t #f #t) (#t #f #f #t) (#t #t #t #t))))) - - (define (tabulate/01 func) - (tabulate func (make-list (procedure-arity func) '(0 1)))) - - (module+ test - (test-case "tabulate/01" - (check-equal? (tabulate/01 (λ (x y) (modulo (+ x y) 2))) - '((0 0 0) (0 1 1) (1 0 1) (1 1 0))))) - - (define (tabulate*/01 funcs) - (tabulate* funcs (make-list (procedure-arity (car funcs)) '(0 1)))) - - (module+ test - (test-case "tabulate*/01" - (check-equal? (tabulate*/01 `(,(λ (x y) (min x y)) ,(λ (x y) (max x y)))) - '((0 0 0 0) (0 1 0 1) (1 0 0 1) (1 1 1 1))))) - ) ) - -(require 'typed) -(provide - pseudovariadic-lambda pvλ pseudovariadic-define pvdefine - tabulate* tabulate*/strict tabulate*/pv - tabulate tabulate/strict tabulate/pv - tabulate*/pv/boolean tabulate/pv/boolean - tabulate*/pv/01 tabulate/pv/01 - tabulate*/list tabulate/list - tabulate*/list/boolean tabulate/list/boolean tabulate*/list/01 tabulate/list/01 - table->function/list table->function table->function/pv - enumerate-boolean-tables enumerate-boolean-functions - enumerate-boolean-functions/pv enumerate-boolean-functions/list - random-boolean-table random-boolean-function random-boolean-function/list - - (struct-out tbf) tbf-w tbf-θ boolean->01/vector apply-tbf apply-tbf/boolean - list->tbf lists->tbfs read-org-tbfs tbf-tabulate* tbf-tabulate - tbf-tabulate*/boolean sbf? sbf list->sbf read-org-sbfs) diff --git a/scribblings/functions.scrbl b/scribblings/functions.scrbl index 892363a..84690aa 100644 --- a/scribblings/functions.scrbl +++ b/scribblings/functions.scrbl @@ -8,7 +8,7 @@ (parameterize ([sandbox-output 'string] [sandbox-error-output 'string] [sandbox-memory-limit 50]) - (make-evaluator 'typed/racket #:requires '((submod "functions.rkt" typed))))) + (make-evaluator 'typed/racket #:requires '("functions.rkt")))) @(define-syntax-rule (ex . args) (examples #:eval functions-evaluator . args)) @@ -610,10 +610,10 @@ See also @racket[read-org-tbfs]. } @section[#:tag "fuctions/untyped"]{Untyped definitions} -@defmodule[(submod dds/functions typed untyped)] +@defmodule[(submod dds/functions untyped)] @(require (for-label (only-in racket/contract/base listof any/c) - (for-label (only-in (submod "../functions.rkt" typed untyped) + (for-label (only-in (submod "../functions.rkt" untyped) tabulate/boolean tabulate*/boolean tabulate/01 tabulate*/01)))) @@ -632,7 +632,7 @@ accompanied by the explicit mention "untyped". (parameterize ([sandbox-output 'string] [sandbox-error-output 'string] [sandbox-memory-limit 50]) - (make-evaluator 'racket #:requires '((submod "functions.rkt" typed untyped))))) + (make-evaluator 'racket #:requires '((submod "functions.rkt" untyped))))) @(define-syntax-rule (ex/untyped . args) (examples #:eval functions-evaluator/untyped . args))