-- |
-- Module: Symtegration.Integration.Sum
-- Description: Integrates the sum of multiple terms in an expression.
-- Copyright: Copyright 2024 Yoo Chung
-- License: Apache-2.0
-- Maintainer: dev@chungyc.org
module Symtegration.Integration.Sum (integrate) where

import Data.Foldable (asum)
import Data.Text (Text)
import Symtegration.Symbolic

-- $setup
-- >>> import Symtegration.Symbolic.Haskell
-- >>> import Symtegration.Symbolic.Simplify

-- | Integrate term by term and returns the sum, using direct methods on each term.
--
-- >>> import Symtegration.Integration.Powers qualified as P
-- >>> import Symtegration.Integration.Trigonometric qualified as T
-- >>> let f = "x" + sin "x"
-- >>> P.integrate "x" f
-- Nothing
-- >>> T.integrate "x" f
-- Nothing
-- >>> let g = integrate [P.integrate, T.integrate] "x" f
-- >>> toHaskell . simplify <$> g
-- Just "(-1) * cos x + 1 / 2 * x ** 2"
integrate ::
  -- | Functions for directly integrating each term.
  [Text -> Expression -> Maybe Expression] ->
  -- | The variable being integrated over.
  Text ->
  -- | The expression being integrated.
  Expression ->
  -- | The integral, if successful.
  Maybe Expression
integrate :: [Text -> Expression -> Maybe Expression]
-> Text -> Expression -> Maybe Expression
integrate [Text -> Expression -> Maybe Expression]
fs Text
v (Negate' Expression
x) =
  UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Negate (Expression -> Expression) -> Maybe Expression -> Maybe Expression
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text -> Expression -> Maybe Expression]
-> Text -> Expression -> Maybe Expression
integrate [Text -> Expression -> Maybe Expression]
fs Text
v Expression
x
integrate [Text -> Expression -> Maybe Expression]
fs Text
v (Expression
x :-: Expression
y) =
  [Text -> Expression -> Maybe Expression]
-> Text -> Expression -> Maybe Expression
integrate [Text -> Expression -> Maybe Expression]
fs Text
v (Expression
x Expression -> Expression -> Expression
:+: Expression -> Expression
Negate' Expression
y)
integrate [Text -> Expression -> Maybe Expression]
fs Text
v (x :: Expression
x@(Expression
_ :+: Expression
_) :+: y :: Expression
y@(Expression
_ :+: Expression
_)) =
  BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Add (Expression -> Expression -> Expression)
-> Maybe Expression -> Maybe (Expression -> Expression)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text -> Expression -> Maybe Expression]
-> Text -> Expression -> Maybe Expression
integrate [Text -> Expression -> Maybe Expression]
fs Text
v Expression
x Maybe (Expression -> Expression)
-> Maybe Expression -> Maybe Expression
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Text -> Expression -> Maybe Expression]
-> Text -> Expression -> Maybe Expression
integrate [Text -> Expression -> Maybe Expression]
fs Text
v Expression
y
integrate [Text -> Expression -> Maybe Expression]
fs Text
v (x :: Expression
x@(Expression
_ :+: Expression
_) :+: Expression
y) =
  BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Add (Expression -> Expression -> Expression)
-> Maybe Expression -> Maybe (Expression -> Expression)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text -> Expression -> Maybe Expression]
-> Text -> Expression -> Maybe Expression
integrate [Text -> Expression -> Maybe Expression]
fs Text
v Expression
x Maybe (Expression -> Expression)
-> Maybe Expression -> Maybe Expression
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Maybe Expression] -> Maybe Expression
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum [Text -> Expression -> Maybe Expression
f Text
v Expression
y | Text -> Expression -> Maybe Expression
f <- [Text -> Expression -> Maybe Expression]
fs]
integrate [Text -> Expression -> Maybe Expression]
fs Text
v (Expression
x :+: y :: Expression
y@(Expression
_ :+: Expression
_)) =
  BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Add (Expression -> Expression -> Expression)
-> Maybe Expression -> Maybe (Expression -> Expression)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Maybe Expression] -> Maybe Expression
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum [Text -> Expression -> Maybe Expression
f Text
v Expression
x | Text -> Expression -> Maybe Expression
f <- [Text -> Expression -> Maybe Expression]
fs] Maybe (Expression -> Expression)
-> Maybe Expression -> Maybe Expression
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Text -> Expression -> Maybe Expression]
-> Text -> Expression -> Maybe Expression
integrate [Text -> Expression -> Maybe Expression]
fs Text
v Expression
y
integrate [Text -> Expression -> Maybe Expression]
fs Text
v (Expression
x :+: Expression
y) =
  BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Add (Expression -> Expression -> Expression)
-> Maybe Expression -> Maybe (Expression -> Expression)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Maybe Expression] -> Maybe Expression
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum [Text -> Expression -> Maybe Expression
f Text
v Expression
x | Text -> Expression -> Maybe Expression
f <- [Text -> Expression -> Maybe Expression]
fs] Maybe (Expression -> Expression)
-> Maybe Expression -> Maybe Expression
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Maybe Expression] -> Maybe Expression
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum [Text -> Expression -> Maybe Expression
f Text
v Expression
y | Text -> Expression -> Maybe Expression
f <- [Text -> Expression -> Maybe Expression]
fs]
integrate [Text -> Expression -> Maybe Expression]
_ Text
_ Expression
_ = Maybe Expression
forall a. Maybe a
Nothing