I started with this code and modified and expanded it in Python. As an exercise/challenge to myself I decided to covert the original to Haskell. I either write imperatively or functionally. This is the first time I have tried converting from one logic to another. I ran into a lot of little issue along the way. I aimed to just get it to work and I want to make it work better now.
import Data.List
import System.Random
import Data.Matrix hiding (transpose, trace)
import Debug.Trace
flipSign::Num a => a -> a
flipSign x = (-1) * x
nonlin:: Bool -> Double -> Double
nonlin True x = x*(1.0-x)
nonlin False x = 1.0 / (1.0 + (exp $ flipSign x))
randomList :: (Random a) => Int -> [a]
randomList seed = randoms (mkStdGen seed)
sample:: [[Double]]
sample = map (map fromIntegral)[ [0,0,1], [0,1,1], [1,0,1], [1,1,1] ]
answers:: [[Double]]
answers = transpose $ map (map fromIntegral) [[0,0,1,1]]
syn0:: [[Double]]
syn0 = [[x] | x<- take 3 (randomList 42 :: [Double])]
dotp:: [[Double]] -> [[Double]] -> [[Double]]
dotp x y = toLists newMatrix
where
mx = fromLists x
my = fromLists y
newMatrix = multStd mx my
nextGeneration::[[Double]] -> [[Double]] -> ([[Double]], [[Double]]) -> ([[Double]],[[Double]])
nextGeneration x labels syn0_l1 = (new_syn0, l1)
where
l0 = x
syn0 = fst syn0_l1
l1 = map (map $ nonlin False) $ dotp l0 syn0
l1_error = zipWith (zipWith (-)) labels l1
l1_delta = zipWith (zipWith (*)) l1_error $ map (map (nonlin True)) l1
new_syn0 = zipWith (zipWith (+)) syn0 $ dotp (transpose l0) l1_delta
generations::([[Double]] -> [[Double]]) -> [[Double]] -> Int -> [[Double]]
generations _ end 0 = end
generations fun weights count = generations fun (fun weights) (count - 1)
main = print $ snd $ iterate (nextGeneration sample answers ) (syn0, [[]] ) !!10000