#lang racket
(provide dno make-net run-normalized ngo initialize-net train-net *learning-rate* *momentum* *step-down*)
(define-syntax make-nodes
(syntax-rules ()
[(_ a b ...) (list (make-vector a 0) (make-vector b 0) ...)]))
(define (make-connections net)
(let rec ((temp-net net)
(connections '()))
(if (eq? (cdr temp-net) '()) (reverse connections)
(rec (cdr temp-net) (cons (connect-row (car temp-net) (cadr temp-net)) connections)))))
(define (connect-row input output)
(let rec ((in input) (connections '()) (count 0) (len (vector-length output)))
(if (eq? len count) (reverse connections)
(rec in (cons (connect-node in) connections) (+ count 1) len))))
(define (connect-node input)
(let rec ((vec (make-vector (vector-length input) 0)) (count 0) (len (vector-length input)))
(if (eq? count len) vec
(begin (vector-set! vec count (random))
(rec vec (+ count 1) len)))))
(define-syntax make-net
(syntax-rules ()
[(_ a b ...)
(let ((x (make-nodes a b ...)))
(vector x (make-connections x)))]))
(define (initialize-net network input)
(let rec ((nodes (cons input (cdr (vector-ref network 0)))) (connections (vector-ref network 1)) (activated-nodes (cons input '())))
(if (eq? (cdr nodes) '()) (vector (reverse activated-nodes) (vector-ref network 1))
(rec (cdr nodes) (cdr connections) (cons (activate-row (car nodes) (cadr nodes) (car connections)) activated-nodes)))))
(define (activate-row input output connections)
(let rec ((in input) (newout output) (connect connections) (count 0))
(if (eq? count (vector-length output)) newout
(begin (vector-set! newout count (activate-node input (car connect)))
(rec in newout (cdr connect) (+ count 1))))))
(define (activate-node input connections)
(let rec ((count 0) (in input) (connect connections) (num 0))
(if (eq? (vector-length input) count) num
(rec (+ count 1) in connect (+ num (* (vector-ref in count) (vector-ref connect count)))))))
(define (output network)
(let rec ((net network))
(if (eq? (cdr net) '()) (car net)
(rec (cdr net)))))
(define (MSE network ideal-output)
(let rec ((out (output network)) (errsum 0) (count 0))
(if (eq? count (vector-length out)) (/ errsum (vector-length out))
(begin (set! errsum (+ errsum (expt (- (vector-ref ideal-output count) (vector-ref out count)) 2)))
(rec out errsum (+ count 1))))))
(define (sigmoid x)
(/ 1.0 (+ 1.0 (exp x))))
(define (sigmoid-prime x)
(* (sigmoid x) (- 1.0 (sigmoid x))))
(define (output-delta weights-sum error)
(* (- error) (sigmoid-prime weights-sum)))
(define (output-deltas connections nodes ideal)
(let rec ((count 0) (connect connections) (n nodes) (deltas (make-vector (vector-length nodes))))
(if (eq? count (vector-length nodes)) deltas
(begin (vector-set! deltas count (output-delta (sum-weights (car connect)) (- (vector-ref ideal count) (vector-ref n count))))
(rec (+ count 1) (cdr connect) n deltas)))))
(define (sum-weights vec)
(let rec ((count 0) (sum 0))
(if (eq? count (vector-length vec)) sum
(rec (+ count 1) (+ sum (vector-ref vec count))))))
(define (calculate-deltas network ideal)
(let rec ((connections (reverse (vector-ref network 1)))(nodes (reverse (vector-ref network 0)))(deltas '()))
(cond ((eq? deltas '()) (begin (set! deltas (cons (output-deltas (car connections) (car nodes) ideal) deltas))
(rec connections (cdr nodes) deltas)))
((eq? (cdr connections) '()) deltas)
(else (begin (set! deltas (cons (interior-delta-row (car connections) (cadr connections) (car nodes) (car deltas)) deltas))
(rec (cdr connections) (cdr nodes) deltas))))))
(define (interior-delta-row connections-out connections-in nodes last-deltas)
(let rec ((count 0) (connect connections-in) (n nodes) (deltas (make-vector (vector-length nodes))))
(if (eq? count (vector-length n)) deltas
(begin (vector-set! deltas count (interior-delta (sum-weights (car connect)) connections-out last-deltas))
(rec (+ count 1) (cdr connect) n deltas)))))
(define (interior-delta sum connections-out last-deltas)
(* (sigmoid-prime sum)
(let rec ((count 0) (del last-deltas) (x 0)(connect connections-out))
(if (eq? count (vector-length del)) x
(begin (set! x (+ x (* (vector-ref del count) (vector-ref (car connect) count))))
(rec (+ count 1) del x (cdr connect)))))))
(define (calculate-gradients activated-network deltas)
(let rec ((temp-net (vector-ref activated-network 0)) (d deltas)
(gradients '()))
(if (eq? (cdr temp-net) '()) (reverse gradients)
(rec (cdr temp-net) (cdr d) (cons (gradient-row (car temp-net) (cadr temp-net) (car d)) gradients)))))
(define (gradient-row input output deltas)
(let rec ((in input) (gradients '()) (count 0) (len (vector-length output)))
(if (eq? len count) (reverse gradients)
(rec in (cons (node-gradients in (vector-ref deltas count)) gradients) (+ count 1) len))))
(define (node-gradients input delta)
(let rec ((in input) (count 0) (len (vector-length input)) (gradients (make-vector (vector-length input))))
(if (eq? count len) gradients
(begin (vector-set! gradients count (* delta (vector-ref input count)))
(rec in (+ count 1) len gradients)))))
(define (adjustments gradients previous-adj)
(let rec ((grad gradients) (p previous-adj) (adj '()))
(if (eq? grad '()) (reverse adj)
(rec (cdr grad) (cdr p) (cons (adjust-row (car grad) (car p)) adj)))))
(define (adjust-row gradients previous-adj)
(let rec ((grad gradients) (p previous-adj) (adj '()))
(if (eq? grad '()) (reverse adj)
(rec (cdr grad) (cdr p) (cons (adjust-one (car grad) (car p)) adj)))))
(define (adjust-one gradients previous-adj)
(let rec ((grad gradients) (p previous-adj) (count 0) (vec (make-vector (vector-length previous-adj))))
(if (eq? count (vector-length gradients)) vec
(begin (vector-set! vec count (+ (* (vector-ref grad count) *learning-rate*) (* (vector-ref p count) *momentum*)))
(rec grad p (+ count 1) vec)))))
(define (train-net net input ideal-out ideal-MSE)
(begin (set! *previous-adj* (padj (vector-ref net 1)))
(let ((test (train net input ideal-out ideal-MSE 30)))
(if test test
net))))
(define (train net input ideal-out ideal-MSE count)
(let* ((i-net (initialize-net net input)) (err (MSE (vector-ref i-net 0) ideal-out)))
(if (eq? count 0) #f
(begin (display err) (newline)
(if (< err ideal-MSE) i-net
(train (iterate i-net ideal-out) input ideal-out ideal-MSE (- count 1)))))))
(define (iterate net ideal)
(let ((adjs (adjustments (calculate-gradients net (calculate-deltas net ideal)) *previous-adj*)))
(begin (vector-set! net 1 (change-weights (vector-ref net 1) adjs))
(set! *previous-adj* adjs)
net)))
(define (change-weights connects adjs)
(let rec ((c connects) (a adjs) (d '()))
(if (eq? c '()) (reverse d)
(rec (cdr c) (cdr a) (cons (ch-weights (car c) (car a)) d)))))
(define (ch-weights conn adj)
(let rec ((c conn) (a adj) (d '()))
(if (eq? c '()) (reverse d)
(rec (cdr c) (cdr a) (cons (ch (car c) (car a)) d)))))
(define (ch co ad)
(let rec ((c co) (a ad) (count 0) (d (make-vector (vector-length co))))
(if (eq? count (vector-length co)) d
(begin (vector-set! d count (- (vector-ref c count) (vector-ref a count)))
(rec c a (+ count 1) d)))))
(define (out net)
(let rec ((net (vector-ref net 0)))
(if (eq? (cdr net) '()) (car net)
(rec (cdr net)))))
(define (padj connections)
(let rec ((c connections) (p '()))
(if (eq? c '()) (reverse p)
(rec (cdr c) (cons (pad (car c)) p)))))
(define (pad con)
(let rec ((c con) (p '()))
(if (eq? c '()) (reverse p)
(rec (cdr c) (cons (make-vector (vector-length (car c)) 0) p)))))
(define (run-net input-list output-list network initial-ideal-MSE)
(let rec ((in input-list) (out output-list) (net network) (ideal-MSE initial-ideal-MSE) (count 0) (count2 0))
(let ((trained (train-net net (car in) (car out) ideal-MSE)))
(cond ((eq? (cdr in) '()) trained)
((and (eq? count2 0) (eq? (vector-ref trained 0) (vector-ref network 0)) (eq? count 10)) (display "Error, current network configuration will not converge"))
((and (eq? count2 0) (eq? (vector-ref trained 0) (vector-ref network 0))) (rec in out (randomize-connects net) ideal-MSE (+ count 1) 0))
(else (rec (cdr in) (cdr out) trained (- ideal-MSE *step-down*) count 1))))))
(define (randomize-connects net)
(let ((nodes (vector-ref net 0)))
(vector nodes (make-connections nodes))))
(define (normalize x datamax datamin rangemax rangemin)
(if (eq? datamax datamin) (/ (- rangemax rangemin) x)
(+ (/ (* (- x datamin) (- rangemax rangemin)) (- datamax datamin)) rangemin)))
(define (denormalize x datamax datamin rangemax rangemin)
(if (eq? datamax datamin) (/ (- rangemax rangemin) x)
(/ (+ (- (* (- datamin datamax) x) (* datamin rangemax)) (* datamax rangemin)) (- rangemin rangemax))))
(define (normalize-vec-list lst)
(let rec ((lst lst) (catcher '()))
(if (eq? lst '()) (reverse catcher)
(rec (cdr lst) (cons (normalize-vec (car lst)) catcher)))))
(define (normalize-vec vec)
(vector-map (lambda (x) (normalize x (apply max (vector->list vec)) (apply min (vector->list vec)) 1 0)) vec))
(define (denormalize-vec-list lst datamax datamin)
(let rec ((lst lst) (catcher '()))
(if (eq? lst '()) (reverse catcher)
(rec (cdr lst) (cons (denormalize-vec (car lst) datamax datamin) catcher)))))
(define (denormalize-vec vec datamax datamin)
(vector-map (lambda (x) (denormalize x datamax datamin 1 0)) vec))
(define (run-normalized input-list output-list network initial-ideal-MSE)
(run-net (normalize-vec-list input-list) (normalize-vec-list output-list) network initial-ideal-MSE))
(define (ngo training-set network ideal-MSE input)
(let ([x (run-normalized (car training-set) (cadr training-set) network ideal-MSE)])
(dno x input)))
(define (dno network input)
(let ([maximum (apply max (vector->list input))]
[minimum (apply min (vector->list input))]
[output (out (initialize-net network (normalize-vec input)))])
(denormalize-vec output maximum minimum)))
(define *learning-rate* 0.5) (define *momentum* 0.7) (define *previous-adj* 0) (define *step-down* 0)