symtegration-0.4.0: Library for symbolic integration of mathematical expressions.
CopyrightCopyright 2024 Yoo Chung
LicenseApache-2.0
Maintainerdev@chungyc.org
Safe HaskellNone
LanguageGHC2021

Symtegration

Description

Symtegration is a library for symbolic integration of mathematical expressions. For normal use, this is the only module which needs to be loaded. Other modules are used for finer control over what happens, or for supporting the work that yet other modules do.

For example, with \(\int (4x^3 + 1) \, dx = x^4 + x\):

>>> import Symtegration
>>> toHaskell <$> integrate "x" (4 * "x" ** 3 + 1)
Just "x + x ** 4"

For another example, with \(\int (xz+y) \, dz = \frac{xz^2}{2} + yz\):

>>> import Symtegration
>>> toHaskell <$> integrate "z" ("x" * "z" + "y")
Just "y * z + 1 / 2 * x * z ** 2"
Synopsis

Symbolic representation

data Expression Source #

Symbolic representation of a mathematical expression. It is an instance of the Num, Fractional, and Floating type classes, so normal Haskell expressions can be used, although the expressions are limited to using the functions defined by these type classses. The type is also an instance of the IsString type class, so symbols can be expressed as Haskell string with the OverloadedStrings extension. The structure of these values is intended to be visible.

>>> 2 :: Expression
Number 2
>>> "x" :: Expression
Symbol "x"
>>> 2 + sin "x" :: Expression
BinaryApply Add (Number 2) (UnaryApply Sin (Symbol "x"))

A somewhat more concise representation can be obtained using toHaskell:

>>> toHaskell $ 2 * "y" + sin "x"
"2 * y + sin x"

Instances

Instances details
IsString Expression Source # 
Instance details

Defined in Symtegration.Symbolic

Floating Expression Source # 
Instance details

Defined in Symtegration.Symbolic

Generic Expression Source # 
Instance details

Defined in Symtegration.Symbolic

Num Expression Source # 
Instance details

Defined in Symtegration.Symbolic

Read Expression Source # 
Instance details

Defined in Symtegration.Symbolic

Fractional Expression Source # 
Instance details

Defined in Symtegration.Symbolic

Show Expression Source # 
Instance details

Defined in Symtegration.Symbolic

Eq Expression Source #

Structural equality, not semantic equality. E.g., "a" - "a" /= 0.

Instance details

Defined in Symtegration.Symbolic

TextShow Expression Source # 
Instance details

Defined in Symtegration.Symbolic

type Rep Expression Source # 
Instance details

Defined in Symtegration.Symbolic

Integration

integrate Source #

Arguments

:: Text

The symbol representing the variable being integrated over.

-> Expression

The mathematical expression being integrated.

-> Maybe Expression

The indefinite integral, if derived.

Returns the indefinite integral of a mathematical expression given its symbolic representation. It will return Nothing if it is unable to derive an integral. The indefinite integral will be simplified to a certain extent.

For example, with \(\int (4x^3 + 1) \, dx = x^4 + x\) where all the coefficients are numbers:

>>> toHaskell <$> integrate "x" (4 * "x" ** 3 + 1)
Just "x + x ** 4"

It can also return indefinite integrals when the coefficients are symbolic, as with \(\int (xz+y) \, dz = \frac{xz^2}{2} + yz\):

>>> toHaskell <$> integrate "z" ("x" * "z" + "y")
Just "y * z + 1 / 2 * x * z ** 2"

Differentiation

differentiate Source #

Arguments

:: Text

Symbol representing the variable.

-> Expression

Symbolic representation of the mathematical expression to differentiate.

-> Expression

The derivative.

Differentiates a mathematical expression.

>>> toHaskell $ differentiate "x" $ "x" ** 2
"2 * x"
>>> toHaskell $ differentiate "x" $ "a" * sin "x"
"a * cos x"

This uses Numeric.AD.

Computation

evaluate Source #

Arguments

:: Floating a 
=> Expression

Mathematical expression to evaluate.

-> (Text -> Maybe a)

Maps symbols to concrete values.

-> Maybe a

Evaluation result.

Calculates the value for a mathematical expression for a given assignment of values to symbols.

For example, when \(x=5\), then \(2x+1=11\).

>>> evaluate (2 * "x" + 1) (\case "x" -> Just 5)
Just 11.0

All symbols except for "pi" in a mathematical expression must be assigned a value. Otherwise, a value cannot be computed.

>>> evaluate (2 * "x" + 1) (const Nothing)
Nothing

The symbol "pi" is always used to represent \(\pi\), and any assignment to "pi" will be ignored. For example, the following is \(\pi - \pi\), not \(100 - \pi\).

>>> evaluate ("pi" - pi) (\case "x" -> Just 100)
Just 0.0

fractionalEvaluate Source #

Arguments

:: (Eq a, Fractional a) 
=> Expression

Mathematical expression to evaluate.

-> (Text -> Maybe a)

Maps symbols to concrete values.

-> Maybe a

Evaluation result.

Evaluates a mathematical expression with only operations available to Fractional values. In particular, this allows exact evaluations with Rational values. Nothing will be returned if a function not supported by all Fractional values is used by the mathematical expression.

As an exception, the (**) operator is allowed with constant integer exponents, even though (**) is not a function applicable to all Fractional types.

For example,

>>> let p = 1 / (3 * "x"**5 - 2 * "x" + 1) :: Expression
>>> fractionalEvaluate p (\case "x" -> Just (2 / 7 :: Rational))
Just (16807 % 7299)

Compare against evaluate, which cannot even use Rational computations because Rational is not an instance of the Floating type class:

>>> evaluate p (\case "x" -> Just (2 / 7 :: Double))
Just 2.3026441978353196

toFunction Source #

Arguments

:: Floating b 
=> Expression

The expression to be converted into a function.

-> (Text -> a -> b)

Maps how the argument to the function should be mapped to a value for a symbol. E.g., "x" could map the first element in a tuple as the value to use in its place.

-> a

The function generated from the expression.

-> b 

Returns a function based on a given expression. This requires a specification of how a symbol maps the argument to a value to be used in its place.

For example, the symbol "x" could use the argument as is as its value. I.e., "x" can be mapped to a function which maps the argument to itself.

>>> let f = toFunction ("x" ** 2 + 1) (\case "x" -> id) :: Double -> Double
>>> f 3  -- 3 ** 2 + 1
10.0
>>> f 10  -- 10 ** 2 + 1
101.0

For another example, "x" could map the first element from a tuple argument, and "y" could map the second element from the tuple argument. I.e., for a tuple argument to the function, the first element will be used as "x" and the second element will be used as "y".

>>> let m = \case "x" -> (\(x,_) -> x); "y" -> (\(_,y) -> y)
>>> let g = toFunction ("x" + 2 * "y") m :: (Double, Double) -> Double
>>> g (3,4)  -- 3 + 2 * 4
11.0
>>> g (7,1)  -- 7 + 2 * 1
9.0

Conversion

toHaskell :: Expression -> Text Source #

Converts an Expression into an equivalent Haskell expression.

>>> toHaskell $ BinaryApply Add (Number 1) (Number 3)
"1 + 3"
>>> toHaskell $ 1 + 3
"1 + 3"

Symbols are included without quotation.

>>> toHaskell $ ("x" + "y") * 4
"(x + y) * 4"

toLaTeX :: Expression -> Text Source #

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}"

Simplification

When using only this module, explicitly simplifying mathematical expressions should usually not be necessary, since the exported functions automatically simplify results as appropriate. One may want to explicitly simplify mathematical expressions when used with other packages, however, such as when using Numeric.AD directly for differentiation.

simplify :: Expression -> Expression Source #

Simplifies symbolic representations of mathematical expressions.

All addition and multiplication will be associated to the left. The simplification is done with an eye towards making it easier to find common factors.

>>> toHaskell $ simplify $ 4 - "x" + "a" * "x" ** 3 + 2 * "x" - 3
"1 + x + a * x ** 3"

tidy :: Expression -> Expression Source #

Tidies up expressions for nicer output.

Assumes that other simplifications have been applied first. In fact, it may undo changes that made other simplifications easier.

What is tidied up

Expand

This section shows examples of what this function tidies up.

>>> toHaskell $ tidy $ "x" + negate "y"
"x - y"
>>> toHaskell $ tidy $ "x" + Number (-2) * "y"
"x - 2 * y"
>>> toHaskell $ tidy $ Number (-1) / Number 2
"negate (1 / 2)"
>>> toHaskell $ tidy $ Number (-1) * "x"
"negate x"
>>> toHaskell $ tidy $ (-"x") * "y"
"negate (x * y)"
>>> toHaskell $ tidy $ "x" * (-"y")
"negate (x * y)"
>>> toHaskell $ tidy $ (-"x") * (-"y")
"x * y"
>>> toHaskell $ tidy $ "x" + ((-"y") + "z")
"x - y + z"