This project contains a very simple, and incomplete, symbolic math library in
Scala. It can *differentiate* and *evaluate* simple mathematical expressions.
The library also contains some aspects of an internal DSL: The expressions can
-be entered like regular math with ``Int`` or ``Double``
objects, and there is
+be entered like regular math with ``Int`` or ``Double`` s, and there is
a ML style *"let" expression*. Here is a short example that demonstrates the
- //Create some symbols (unknown variables)
+ //Create some symbols (unknown variables)
val (a, x) = (Sym("a"), Sym("x"))
//Create an expression. `~^` denotes exponentiation (power).
val expr1 = a * x~^4 + 5 * x~^2 + x~^0.5
- //Differentiate the expression with respect to `x`
+ //Differentiate the expression with respect to `x`
val dexpr1 = diff(expr1, x)
//Print the expression in human readable form.
The library is not intended to be used seriously. Instead it should demonstrate
-features of Scala that are interesting for programmers that come form
+features of Scala that are interesting for programmers that come form
traditional object oriented languages; such as: C++, Java, Python, Ruby.
The project should especially demonstrate the usefulness of pattern matching.
Therefore this library is implemented three times with different programming
Package ``symathoo``: Classical object oriented.
+The three libraries are big enough (500 to 700 lines) to give an impression
+how working with a real program would be. But they are small and simple
+enough, to be easily understood. To write the algorithms, and to judge their
+correctness, only high school math is necessary. In principle the algorithms
+can be looked up in Wikipedia
* Add derivation of the ``Log`` node.
* Add new nodes, for example ``sin``, ``cos`` and ``tan``.
* Add function call node. Maybe this makes an inert ``diff`` node superfluous.
* Add ``lambda`` (function body) node.
* Implement an inert ``diff`` node. The "a$x" notation is a hack.
+* Implement a node for a ``for`` loop. Write evaluation and differentiation
+ algorithms for it. (I believe differentiating a ``for`` loop is possible,
+ because older versions of *Maple* could do it.)
* Implement an algorithm to distribute factors over sums, and distribute
powers over products. For example: ``(a + b) * c`` --> ``a*c + b*c``.
This is interesting for ``eval``: more operators with only numeric arguments
can be found, and evaluated.
* Implement an algorithm to collect factors and powers. (The opposite of the
algorithm above.) It makes formulas look good.
* Maybe add a separate ``simplify`` function.
* Implement some of the TODOs in the code.
+Mathematical formulas are internally represented as nested trees of nodes.
+They are implemented as *case classes*, syntactical sugar for simple classes
+that are intended to work with the ``match`` statement.
+* ``Num(num: Double)`` : A number (floating point)
+* ``Sym(name: String)`` : A variable (symbol)
+* ``Add(summands: List[Expr])`` : Addition (n-ary)
+* ``Mul(factors: List[Expr])`` : Multiplication (n-ary)
+* ``Pow(base: Expr, exponent: Expr)``: Exponentiation
+* ``Log(base: Expr, power: Expr)`` : Logarithm
+* ``Let(name: String, value: Expr, exprNext: Expr)``: Bind a value to a
+ variable, and put a single expression into the environment, where the new
+There are no nodes for subtraction and division. Subtraction is represented
+as multiplication with ``-1`` (``-a = -1 * a``), division is expressed as a
+power of ``-1`` (``1/a = a~^(-1)``). Addition and multiplication are also
+*n-ary*, they take an arbitrary number of arguments.
+This idea was taken from the computer algebra program *Maxima*, it is intended
+to reduce the complexity of the algorithms.
+``1 + a`` is expressed as::
+ Add(List(Num(1.0), Sym("a")))
+``1 + a * 2`` is expressed as::
+ Add(List(Num(1.0), Mul(List(Sym("a"), Num(2.0)))))
+Addition and multiplication are n-ary, they can have an arbitrary number of
+arguments. ``1 + a + 2 + 3`` and ``1 * a * 2 * 3`` are respectively
+ Add(List(Num(1.0), Sym("a"), Num(2.0), Num(3.0)))
+ Mul(List(Num(1.0), Sym("a"), Num(2.0), Num(3.0)))
+As there are no subtraction or division operators, ``a-x`` and ``a/x`` are
+respectively expressed as::
+ Add(List(Sym("a"), Mul(List(Num(-1.0), Sym("x")))))
+ Mul(List(Sym("a"), Pow(Sym("x"), Num(-1.0))))
+The ``let`` expression is created by a little abuse of Scala's liberal syntax
+(the DSL). ``let (a:=2) in a * a`` results in::
+ Let("a", Num(2.0), Mul(List(Sym("a"), Sym("a"))))
+Algorithms traverse a tree of nodes in a recursive way, and create a