-- |
-- Module: Symtegration.Symbolic.LaTeX
-- Description: Converts a symbolic representation of a mathematical expression into equivalent LaTeX text.
-- Copyright: Copyright 2024 Yoo Chung
-- License: Apache-2.0
-- Maintainer: dev@chungyc.org
--
-- Support for converting symbolic representations of mathematical expressions
-- into equivalent LaTeX text.
module Symtegration.Symbolic.LaTeX (toLaTeX) where

import Data.Text (Text)
import Symtegration.Symbolic
import TextShow (showt)

-- | Converts an 'Expression' into an equivalent LaTeX expression.
--
-- >>> toLaTeX $ exp 5
-- "e^{5}"
--
-- Symbols are included without quotation.
--
-- >>> toLaTeX $ exp "x"
-- "e^{x}"
-- >>> toLaTeX $ "x" + 4 * sin "y"
-- "x + 4 \\sin y"
--
-- Since the text for symbols are included as is, we can also include LaTeX symbols:
--
-- >>> toLaTeX $ exp "\\delta_0"
-- "e^{\\delta_0}"
toLaTeX :: Expression -> Text
toLaTeX :: Expression -> Text
toLaTeX (Number Integer
n) = Integer -> Text
forall a. TextShow a => a -> Text
showt Integer
n
toLaTeX (Symbol Text
"pi") = Text
"\\pi"
toLaTeX (Symbol Text
s) = Text
s
toLaTeX (UnaryApply UnaryFunction
func Expression
x) = UnaryFunction -> Expression -> Text
unary UnaryFunction
func Expression
x
toLaTeX (BinaryApply BinaryFunction
func Expression
x Expression
y) = BinaryFunction -> Expression -> Expression -> Text
binary BinaryFunction
func Expression
x Expression
y

-- | Converts unary functions into LaTeX.
unary :: UnaryFunction -> Expression -> Text
unary :: UnaryFunction -> Expression -> Text
unary UnaryFunction
Negate x :: Expression
x@(Expression
_ :+: Expression
_) = Text
"-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
x
unary UnaryFunction
Negate x :: Expression
x@(Expression
_ :-: Expression
_) = Text
"-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
x
unary UnaryFunction
Negate x :: Expression
x@(Negate' Expression
_) = Text
"-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
x
unary UnaryFunction
Negate Expression
x = Text
"-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
toLaTeX Expression
x
unary UnaryFunction
Abs Expression
x = Text
"\\left\\lvert " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
toLaTeX Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" \\right\\rvert"
unary UnaryFunction
Signum Expression
x = Text
"\\mathrm{signum}" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
par (Expression -> Text
toLaTeX Expression
x)
unary UnaryFunction
Exp Expression
x = Text
"e^" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
brace (Expression -> Text
toLaTeX Expression
x)
unary UnaryFunction
Log Expression
x = Text
"\\log " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Sqrt Expression
x = Text
"\\sqrt" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
brace (Expression -> Text
toLaTeX Expression
x)
unary UnaryFunction
Sin Expression
x = Text
"\\sin " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Cos Expression
x = Text
"\\cos " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Tan Expression
x = Text
"\\tan " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Asin Expression
x = Text
"\\sin^{-1} " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Acos Expression
x = Text
"\\cos^{-1} " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Atan Expression
x = Text
"\\tan^{-1} " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Sinh Expression
x = Text
"\\sinh " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Cosh Expression
x = Text
"\\cosh " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Tanh Expression
x = Text
"\\tanh " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Asinh Expression
x = Text
"\\sinh^{-1} " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Acosh Expression
x = Text
"\\cosh^{-1} " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x
unary UnaryFunction
Atanh Expression
x = Text
"\\tanh^{-1} " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
x

-- | Converts binary functions into LaTeX.
binary :: BinaryFunction -> Expression -> Expression -> Text
binary :: BinaryFunction -> Expression -> Expression -> Text
binary BinaryFunction
Add Expression
x (Negate' Expression
y) = BinaryFunction -> Expression -> Expression -> Text
binary BinaryFunction
Subtract Expression
x Expression
y
binary BinaryFunction
Add Expression
x Expression
y = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" + " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asAddTrailingArg Expression
y
binary BinaryFunction
Multiply x :: Expression
x@(Expression
_ :*: Number Integer
_) y :: Expression
y@(Number Integer
_ :*: Expression
_) = Expression -> Text
toLaTeX Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" \\times " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
toLaTeX Expression
y
binary BinaryFunction
Multiply x :: Expression
x@(Number Integer
_) y :: Expression
y@(Number Integer
_ :*: Expression
_) = Expression -> Text
toLaTeX Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" \\times " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
toLaTeX Expression
y
binary BinaryFunction
Multiply x :: Expression
x@(Expression
_ :*: Number Integer
_) y :: Expression
y@(Number Integer
_) = Expression -> Text
toLaTeX Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" \\times " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
toLaTeX Expression
y
binary BinaryFunction
Multiply Expression
x y :: Expression
y@(Number Integer
_) = Expression -> Text
asMultiplyArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" \\times " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
y
binary BinaryFunction
Multiply x :: Expression
x@(Abs' Expression
_) Expression
y = Expression -> Text
toLaTeX Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asMultiplyArg Expression
y
binary BinaryFunction
Multiply x :: Expression
x@(Signum' Expression
_) Expression
y = Expression -> Text
toLaTeX Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asMultiplyArg Expression
y
binary BinaryFunction
Multiply x :: Expression
x@(Exp' Expression
_) Expression
y = Expression -> Text
toLaTeX Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asMultiplyArg Expression
y
binary BinaryFunction
Multiply x :: Expression
x@(Sqrt' Expression
_) Expression
y = Expression -> Text
toLaTeX Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asMultiplyArg Expression
y
binary BinaryFunction
Multiply x :: Expression
x@(UnaryApply UnaryFunction
_ Expression
_) y :: Expression
y@(Symbol Text
_) = Text -> Text
par (Expression -> Text
toLaTeX Expression
x) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asMultiplyArg Expression
y
binary BinaryFunction
Multiply x :: Expression
x@(LogBase' Expression
_ Expression
_) Expression
y = Text -> Text
par (Expression -> Text
toLaTeX Expression
x) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asMultiplyArg Expression
y
binary BinaryFunction
Multiply Expression
x Expression
y = Expression -> Text
asMultiplyArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asMultiplyArg Expression
y
binary BinaryFunction
Subtract Expression
x y :: Expression
y@(Negate' Expression
_) = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" - " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
y
binary BinaryFunction
Subtract Expression
x y :: Expression
y@(Expression
_ :+: Expression
_) = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" - " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
y
binary BinaryFunction
Subtract Expression
x y :: Expression
y@(Expression
_ :-: Expression
_) = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" - " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
y
binary BinaryFunction
Subtract Expression
x Expression
y = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" - " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asAddTrailingArg Expression
y
binary BinaryFunction
Divide Expression
x Expression
y = Text
"\\frac" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
brace (Expression -> Text
toLaTeX Expression
x) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
brace (Expression -> Text
toLaTeX Expression
y)
binary BinaryFunction
Power Expression
x Expression
y = Expression -> Text
asArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"^" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
brace (Expression -> Text
toLaTeX Expression
y)
binary BinaryFunction
LogBase Expression
x Expression
y = Text
"\\log_" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
brace (Expression -> Text
toLaTeX Expression
x) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asNamedFunctionArg Expression
y

asArg :: Expression -> Text
asArg :: Expression -> Text
asArg e :: Expression
e@(Number Integer
n) | Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
0 = Expression -> Text
toLaTeX Expression
e | Bool
otherwise = Text -> Text
par (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Expression -> Text
toLaTeX Expression
e
asArg e :: Expression
e@(Symbol Text
_) = Expression -> Text
toLaTeX Expression
e
asArg e :: Expression
e@(Negate' Expression
_) = Text -> Text
par (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Expression -> Text
toLaTeX Expression
e
asArg e :: Expression
e@(UnaryApply UnaryFunction
_ Expression
_) = Expression -> Text
toLaTeX Expression
e
asArg e :: Expression
e@(Expression
_ :/: Expression
_) = Expression -> Text
toLaTeX Expression
e
asArg e :: Expression
e@(Number Integer
_ :**: Expression
_) = Text -> Text
par (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Expression -> Text
toLaTeX Expression
e
asArg e :: Expression
e@(Expression
_ :**: Expression
_) = Expression -> Text
toLaTeX Expression
e
asArg Expression
e = Text -> Text
par (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Expression -> Text
toLaTeX Expression
e

asAddInitialArg :: Expression -> Text
asAddInitialArg :: Expression -> Text
asAddInitialArg e :: Expression
e@(Number Integer
_) = Expression -> Text
toLaTeX Expression
e
asAddInitialArg e :: Expression
e@(Symbol Text
_) = Expression -> Text
toLaTeX Expression
e
asAddInitialArg e :: Expression
e@(Negate' Expression
_) = Expression -> Text
toLaTeX Expression
e
asAddInitialArg (Expression
x :+: Expression
y) = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" + " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asAddTrailingArg Expression
y
asAddInitialArg (Expression
x :-: y :: Expression
y@(Negate' Expression
_)) = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" - " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
y
asAddInitialArg (Expression
x :-: y :: Expression
y@(Expression
_ :+: Expression
_)) = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" - " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
y
asAddInitialArg (Expression
x :-: y :: Expression
y@(Expression
_ :-: Expression
_)) = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" - " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
asArg Expression
y
asAddInitialArg (Expression
x :-: Expression
y) = Expression -> Text
asAddInitialArg Expression
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" - " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Expression -> Text
toLaTeX Expression
y
asAddInitialArg Expression
e = Expression -> Text
asAddTrailingArg Expression
e

asAddTrailingArg :: Expression -> Text
asAddTrailingArg :: Expression -> Text
asAddTrailingArg e :: Expression
e@(Number Integer
_) = Expression -> Text
asArg Expression
e
asAddTrailingArg e :: Expression
e@(Symbol Text
_) = Expression -> Text
asArg Expression
e
asAddTrailingArg e :: Expression
e@(Negate' Expression
_) = Expression -> Text
asArg Expression
e
asAddTrailingArg Expression
e = Expression -> Text
toLaTeX Expression
e

asMultiplyArg :: Expression -> Text
asMultiplyArg :: Expression -> Text
asMultiplyArg e :: Expression
e@(Number Integer
_) = Expression -> Text
asArg Expression
e
asMultiplyArg e :: Expression
e@(Symbol Text
_) = Expression -> Text
asArg Expression
e
asMultiplyArg e :: Expression
e@(Negate' Expression
_) = Expression -> Text
asArg Expression
e
asMultiplyArg e :: Expression
e@(UnaryApply UnaryFunction
_ Expression
_) = Expression -> Text
toLaTeX Expression
e
asMultiplyArg e :: Expression
e@(Expression
_ :+: Expression
_) = Expression -> Text
asArg Expression
e
asMultiplyArg e :: Expression
e@(Expression
_ :-: Expression
_) = Expression -> Text
asArg Expression
e
asMultiplyArg e :: Expression
e@(BinaryApply BinaryFunction
_ Expression
_ Expression
_) = Expression -> Text
toLaTeX Expression
e

-- For arguments to named functions such as "sin" which do not always delimit their arguments.
-- E.g., it is preferred that "1 + sin x" be "1 + sin x" and not "1 + (sin x)",
-- but we want "cos (sin x)" to be "cos (sin x)" and not "cos sin x".
asNamedFunctionArg :: Expression -> Text
asNamedFunctionArg :: Expression -> Text
asNamedFunctionArg e :: Expression
e@(Exp' Expression
_) = Expression -> Text
asArg Expression
e
asNamedFunctionArg e :: Expression
e@(Abs' Expression
_) = Expression -> Text
asArg Expression
e
asNamedFunctionArg e :: Expression
e@(Sqrt' Expression
_) = Expression -> Text
asArg Expression
e
asNamedFunctionArg e :: Expression
e@(UnaryApply UnaryFunction
_ Expression
_) = Text -> Text
par (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Expression -> Text
toLaTeX Expression
e
asNamedFunctionArg e :: Expression
e@(LogBase' Expression
_ Expression
_) = Text -> Text
par (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Expression -> Text
toLaTeX Expression
e
asNamedFunctionArg Expression
e = Expression -> Text
asArg Expression
e

par :: Text -> Text
par :: Text -> Text
par Text
s = Text
"\\left(" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
s Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\\right)"

brace :: Text -> Text
brace :: Text -> Text
brace Text
s = Text
"{" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
s Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"}"