#lang racket

;;;;;Funciones;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;de propagación
(define propagacion_lineal_aux
  (lambda (lista-señales lista-pesos);igual length
    (if (null? lista-señales)
        0
        (+
         (* (first lista-señales)
            (first lista-pesos))
         (propagacion_lineal_aux 
          (cdr lista-señales) (cdr lista-pesos)))
        )
    ))
(define propagacion_lineal
  (lambda (lista-señales lista-pesos umbral)
    (- 
     (propagacion_lineal_aux lista-señales lista-pesos)
     umbral)
    ))
;;para usar con sigmoidea_log
(define propagacion_lineal_sigm
  (lambda (lista-señales lista-pesos umbral)
    (- ;<--- ??
     (propagacion_lineal_aux lista-señales lista-pesos)
     umbral)
    ))
(define propagacion_euclidea_aux
  (lambda (lista-señales lista-pesos);igual length
    (if (null? lista-señales)
        0
        (+
         (expt (- (first lista-señales)
                  (first lista-pesos)) 2)
         (propagacion_euclidea_aux
          (cdr lista-señales) (cdr lista-pesos)))
        )
    ))
(define propagacion_euclidea
  (lambda (lista-señales lista-pesos umbral)
    (- 
     (propagacion_euclidea_aux lista-señales lista-pesos)
     umbral)
    ))
;;;de activación
;;considerando o no el estado anterior
(define suma-estado
  (lambda (valor_propagacion . estado)
    (if (null? estado)
        valor_propagacion
        (+ valor_propagacion (car estado)) )
    ))
;;;de salida
;;de escalón, sigmoidea, gaussiana y sinusoidal
(define lineal
  (lambda (valor_activacion)
    valor_activacion ))

(define escalon_1
  (lambda (valor_activacion)
    (if (< valor_activacion 0)
        0
        1)
    ))

(define escalon_2
  (lambda (valor_activacion)
    (if (< valor_activacion 0)
        -1
        1)
    ))

(define escalon_3
  (lambda (valor_activacion)
    (if (< valor_activacion 0)
        -1
        (if (> valor_activacion 1)
            1
            valor_activacion)
        )
    ))

(define escalon_4
  (lambda (valor_activacion)
    (if (< valor_activacion -1)
        -1
        (if (> valor_activacion 1)
            1
            valor_activacion)
        )
    ))

(define sigmoidea_log
  (lambda (valor_activacion)
    (/ 1 (+ 1 (expt 2.71828 (- valor_activacion)))) 
    ))

(define sigmoidea_hiper
  (lambda (valor_activacion)
    (/ (- 
        (expt 2.71828 valor_activacion) 
        (expt 2.71828 (- valor_activacion)))
       (+ 
        (expt 2.71828 valor_activacion) 
        (expt 2.71828 (- valor_activacion))))
    ))


;;;;;LA CLASE NEURONA
(define neurona%
  (class object%
    (init-field
     id
     (umbral 0)
     (func_net 'proc)
     (func_act 'proc)
     (func_sal 'proc)
     )
    (field
     (propagacion 0)
     (activacion 0);estado interno
     (salida 0)
     (errores '())
     )
    ;;añadido
    (define/public get-id
      (lambda ()
        id ))
    (define/public set-umbral
      (lambda (valor)
        (set! umbral valor) ))
    (define/public get-umbral
      (lambda ()
        umbral ))
    ;;backpropagation
    (define/public get-salida
      (lambda ()
        salida))
    (define/public get-error
      (lambda ()
        errores ))
    (define/public add-error
      (lambda (valor)
        (set! errores valor)
        ))
    ;;;
    (define/public proceso!
      (lambda (lista-señales lista-pesos)
        (set! propagacion (func_net lista-señales lista-pesos umbral))
        (set! activacion (func_act propagacion))
        (set! salida (func_sal activacion))
        salida))
    (super-new) 
    ))
;;;;;LA CLASE NEURONA ENTRADA
(define neuron_entrada%
  (class neurona%
    (inherit-field id salida)
    (override proceso!)
    (define proceso!
      (lambda (señal)
        (set! salida señal)
        salida))
    (super-new) 
    ))
;;;;;LA CLASE CAPA
(define capa%
  (class object%
    (init-field
     id
     (lista-neuronas '())
     (lista-pesos-conex_aferentes '(listas))
     )
    ;;añadido
    (define/public get-id
      (lambda ()
        id ))
    (define/public get-neuronas
      (lambda ()
        lista-neuronas ))
    (define/public get-pesos
      (lambda ()
        lista-pesos-conex_aferentes ))
    (define/public set-pesos
      (lambda (lst)
        (set! lista-pesos-conex_aferentes lst) ))
    ;;;
    (define/public proceso!
      (lambda (lista-señales)
        (aux-proceso 
         lista-neuronas 
         lista-señales 
         lista-pesos-conex_aferentes)
        ))
    (define aux-proceso
      (lambda (neuronas señales pesos)
        (if (null? neuronas)
            '()
            (cons
             (send (first neuronas) proceso! señales (first pesos))
             (aux-proceso (rest neuronas) señales (rest pesos)))
            )
        ))
    (super-new)
    ))
;;;;;LA CLASE CAPA
(define capa_entrada%
  (class capa%
    (inherit-field lista-neuronas)
    (override proceso!)
    (define proceso!
      (lambda (lista-señales)
        (aux_proceso 
         lista-neuronas 
         lista-señales)
        ))
    (define aux_proceso
      (lambda (neuronas señales)
        (if (null? neuronas)
            '()
            (cons
             (send (first neuronas) proceso! (first señales))
             (aux_proceso (rest neuronas) (rest señales)))
            )
        ))
    (super-new)
    ))
;;;;;LA CLASE RED
(define red%
  (class object%
    (init-field
     (lista-capas '());orden: entrada, ocultas, salida
     )
    ;;añadido
    (define/public get-capas
      (lambda ()
        lista-capas ))
    ;;;
    (define/public proceso!
      (lambda (señales)
        (aux-proceso lista-capas señales)
        ))
    (define aux-proceso
      (lambda (capas señales)
        (if (null? capas)
            señales
            (aux-proceso (rest capas)
                         (send (first capas) proceso! señales))
            )
        ))
    (super-new)
    ))

(provide red% capa% capa_entrada% neurona% neuron_entrada% 
         propagacion_lineal propagacion_euclidea propagacion_lineal_sigm
         lineal escalon_1 sigmoidea_log)