packages feed

hcad-0.1: HCad/Expr.hs

{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PatternSynonyms #-}
module HCad.Expr where


import Algebra.Classes as A
import Prelude hiding (divMod,div,Num(..))
import Prelude (abs)
import qualified Prelude
import qualified Data.Set as Set
import Numeric (showGFloat)
data Expr where
  Con :: Double -> Expr
  Var :: Parameter -> Expr
  Fun :: String -> [Expr] -> Expr
  BinOp :: String -> Expr -> Expr -> Expr
  deriving Eq

pattern (:+:) :: Expr -> Expr -> Expr
pattern x :+: y = BinOp "+" x y

-- pattern (:-:) :: Expr -> Expr -> Expr
-- pattern x :-: y = BinOp "-" x y

pattern (:*:) :: Expr -> Expr -> Expr
pattern x :*: y = BinOp "*" x y

instance Additive Expr where
  zero = Con 0
  Con z + x | abs z < 1e-10 = x
  x + Con z | abs z < 1e-10 = x
  Con x + Con y = Con (x A.+ y)
  (Con x :+: z) + Con y = Con (x A.+ y) A.+ z
  Con y + (Con x :+: z) = Con (x A.+ y) A.+ z
  (Con a :+: x) + (Con b :+: y) = Con (a + b) :+: (x + y)
  (Con x :+: z) + y = Con x :+: (z + y)
  y + (Con x :+: z) = Con x :+: (z + y)
  (a :*: x) + (b :*: y) | x == y = (a + b) * x
  (a :*: x) + y | x == y = (a + 1) * x
  y + (a :*: x)| x == y = (a + 1) * x
  x + Con y = Con y :+: x
  x + y = x :+: y

instance Group Expr where
  -- x - Con z | abs z < 1e-10= x
  -- Con x - Con y = Con (x A.- y)
  -- x - y = BinOp "-" x y
  negate = (Con (-1) *)

instance Division Expr where
  Con x / Con y = Con (x A./ y)
  x / y = BinOp "/" x y


instance Multiplicative Expr where
  Con z * _  | abs z < 1e-10 = zero
  _ * Con z  | abs z < 1e-10 = zero
  Con 1 * x = x
  x * Con 1 = x
  Con x * Con y = Con (x A.* y)
  (x :+: y) * z = x * z + y * z
  z * (x :+: y) = x * z + y * z
  -- z * (x :-: y) = x * z - y * z
  (Con x :*: z) * Con y = Con (x A.* y) A.* z
  Con y * (Con x :*: z) = Con (x A.* y) A.* z
  x * Con y = Con y :*: x
  x * y = BinOp "*" x y
  one = Con 1

instance Show Expr where
  showsPrec d = \case
    BinOp op x y -> showParen True (showsPrec d x . showString op . showsPrec d y)
    Con x -> showGFloat (Just 8) x
    Var v -> showString (paramName v)
    Fun f args -> showString f . showParen True (intercalate' "," $ map (showsPrec d) args)

intercalate' :: Foldable t => String -> t (String -> String) -> String -> String
intercalate' s = foldr1 (\x y -> x . showString s . y)

data Possible = PRange Double Double | PSet [Double]
    deriving (Ord,Eq)
data Parameter
  = Parameter {paramGroup :: String
              ,paramName :: String
              ,paramDefault :: Double
              ,paramComment :: String
              ,paramPossible :: Possible}
    deriving (Ord,Eq)
params :: Expr -> Set.Set Parameter
params = \case
  BinOp _ x y -> foldMap params [x,y]
  Con _ -> Set.empty
  Var p -> Set.singleton p
  Fun _ args -> foldMap params args

confun :: (Double -> Double) -> String -> Expr -> Expr
confun f _g (Con x) = Con (f x)
confun _f g x = Fun g [x]

instance Module Expr Expr where
  (*^) = (A.*)
instance AbelianAdditive Expr where
instance Ring Expr where
instance Field Expr where
instance Floating Expr where
  pi = Con pi
  exp = confun exp "exp"
  log = confun log "log"
  sin = confun sin "sin"
  cos = confun cos "cos"
  asin = confun asin "asin"
  acos = confun acos "acos"
  atan = confun atan "atan"
  sinh = confun sinh "sinh"
  cosh = confun cosh "cosh"
  asinh = confun asinh "asinh"
  acosh = confun acosh "acosh"
  atanh = confun atanh "atanh"

instance Fractional Expr where
  fromRational = A.fromRational
  recip = A.recip

instance Prelude.Num Expr where
  (+) = (A.+)
  (-) = (A.-)
  (*) = (A.*)
  abs = Fun "abs" . return
  signum = Fun "signum" . return
  fromInteger = Con . A.fromInteger