diff --git a/tests/playground/deriv.hs b/tests/playground/deriv.hs new file mode 100644 index 0000000000..be2a3ca37a --- /dev/null +++ b/tests/playground/deriv.hs @@ -0,0 +1,80 @@ +data Expr = + Val Int + | Var String + | Add Expr Expr + | Mul Expr Expr + | Pow Expr Expr + | Ln Expr + +pown :: Int -> Int -> Int +pown a 0 = 1 +pown a 1 = a +pown a n = + let b = pown a (n `div` 2) in + b * b * (if n `mod` 2 == 0 then 1 else a) + +add :: Expr -> Expr -> Expr +add (Val n) (Val m) = Val (n + m) +add (Val 0) f = f +add f (Val 0) = f +add f (Val n) = add (Val n) f +add (Val n) (Add (Val m) f) = add (Val (n+m)) f +add f (Add (Val n) g) = add (Val n) (add f g) +add (Add f g) h = add f (add g h) +add f g = Add f g + +mul :: Expr -> Expr -> Expr +mul (Val n) (Val m) = Val (n*m) +mul (Val 0) _ = Val 0 +mul _ (Val 0) = Val 0 +mul (Val 1) f = f +mul f (Val 1) = f +mul f (Val n) = mul (Val n) f +mul (Val n) (Mul (Val m) f) = mul (Val (n*m)) f +mul f (Mul (Val n) g) = mul (Val n) (mul f g) +mul (Mul f g) h = mul f (mul g h) +mul f g = Mul f g + +pow :: Expr -> Expr -> Expr +pow (Val m) (Val n) = Val (pown m n) +pow _ (Val 0) = Val 1 +pow f (Val 1) = f +pow (Val 0) _ = Val 0 +pow f g = Pow f g + +ln :: Expr -> Expr +ln (Val 1) = Val 0 +ln f = Ln f + +d :: String -> Expr -> Expr +d x (Val _) = Val 0 +d x (Var y) = if x == y then Val 1 else Val 0 +d x (Add f g) = add (d x f) (d x g) +d x (Mul f g) = add (mul f (d x g)) (mul g (d x f)) +d x (Pow f g) = mul (pow f g) (add (mul (mul g (d x f)) (pow f (Val (-1)))) (mul (ln f) (d x g))) +d x (Ln f) = mul (d x f) (pow f (Val (-1))) + +count :: Expr -> Integer +count (Val _) = 1 +count (Var _) = 1 +count (Add f g) = count f + count g +count (Mul f g) = count f + count g +count (Pow f g) = count f + count g +count (Ln f) = count f + +nest_aux :: Int -> (Int -> Expr -> IO Expr) -> Int -> Expr -> IO Expr +nest_aux s f 0 x = pure x +nest_aux s f m x = f (s - m) x >>= nest_aux s f (m-1) + +nest f n e = nest_aux n f n e + +deriv :: Int -> Expr -> IO Expr +deriv i f = do + let f' = d "x" f + putStrLn (show (i+1) ++ " count: " ++ (show $ count f')) + pure f' + +main = do + let x = Var "x" + let f = pow x x + nest deriv 10 f