Writing a symbolic calculator

Mar 9, 2012 at 8:12am
Hi all,
I have been cooking up this symbolic calculator for quite a while
and it can already do useful things, although very slowly;
I will probably speed it up as need arises (and it will :).


The bad news about the calculator's implementation is
that it is 2.3 k lines of code, is very slow and completely untested/experimental.
However, my goal at the moment is to design its syntax and
the inner workings (and this is where your advice comes in:).

The good news is that the calculator can be used directly online here:

http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator

(using Apache server) and that it supports LaTeX (using the great jsmath script).
The (c++) source code is in a link there too.

There is more bad news: the calculator cannot divide
nor does support large integers. However, there is more good news too:
it is fully symbolic and you can mess heavily with the syntax.

This is how you can teach it to compute derivatives:
1
2
3
4
\partial {} ({{a}}{{b}}) := \partial {}a b+ a\partial {} b;
\partial{}({{a}}+{{b}}):=\partial {}a+\partial{}b;
\partial{}({{a}}):if (IsInteger{} a):=0;
\partial{}(\partial{} (\partial{}(a b)))


http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator?in1=%5Cpartial+%7B%7D+%28%7B%7Ba%7D%7D%7B%7Bb%7D%7D%29+%3A%3D+%5Cpartial+%7B%7Da+b%2B+a%5Cpartial+%7B%7D+b%3B%0D%0A%5Cpartial%7B%7D%28%7B%7Ba%7D%7D%2B%7B%7Bb%7D%7D%29%3A%3D%5Cpartial+%7B%7Da%2B%5Cpartial%7B%7Db%3B%0D%0A%5Cpartial%7B%7D%28%7B%7Ba%7D%7D%29%3Aif+%28IsInteger%7B%7D+a%29%3A%3D0%3B%0D%0A%5Cpartial%7B%7D%28%5Cpartial%7B%7D+%28%5Cpartial%7B%7D%28a+b%29%29%29

and this is how you can teach it to compute (small) Fibonacci numbers:

1
2
3
4
Fibonacci{}({{a}}):if(a==1):=1;
Fibonacci{}({{a}}):if(a==0):=1;
Fibonacci{}({{a}}):if(IsInteger{}(a)):=Fibonacci{}(a-1)+Fibonacci{}(a-2);
Fibonacci{}(9)


http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator?in1=Fibonacci%7B%7D%28%7B%7Ba%7D%7D%29%3Aif%28a%3D%3D1%29%3A%3D1%3B%0D%0AFibonacci%7B%7D%28%7B%7Ba%7D%7D%29%3Aif%28a%3D%3D0%29%3A%3D1%3B%0D%0AFibonacci%7B%7D%28%7B%7Ba%7D%7D%29%3Aif%28IsInteger%7B%7D%28a%29%29%3A%3DFibonacci%7B%7D%28a-1%29%2BFibonacci%7B%7D%28a-2%29%3B%0D%0AFibonacci%7B%7D%289%29

How would you design a calculator syntax?

The calculator approach I have is heavily influenced by both Mathematica and the desire for it to be LaTeX-compatible.

Cheers!
tition
Last edited on Mar 9, 2012 at 8:30am
Mar 9, 2012 at 3:53pm
When you say "teach it to compute" do you mean it actually learns?
Mar 9, 2012 at 4:49pm
Well, I mean you tell it a substitution rule, just like in Mathematica.
 
f{}({{x}}):=x+1


tells it to substitute f{}(x) by x+1, where x is anything because its first occurrence is enclosed in {{ }} brackets. This of course is a bad substitution because substituting anything by anything +1 will go infinitely.

This is how you tell the program to use the Leibnitz rule:
d {} ({{a}}{{b}}):= d{}(a) *b + a* d{}(b);

Again, {{a}} means that a is anything (this is equivalent to Mathematica's a_ syntax).

As d is not enclosed in {{ }} brackets, it means d is a fixed global variable.

d{} (a)
means the variable d, interpreted as function, applied to a.
d(a)
means simply d*a which is also written as d a.

 
e^{x+y}:=e^x e^y

This means "whenever you encounter e^{x+y}, where e, x and y are global variables, substitute e^{x+y} by e^x e^y".

On the other hand,
 
e^{{{x}}+{{y}}}:=e^x e^y

will carry out this rule for arbitrary values of x and y, and

 
{{e}}^{{{x}}+{{y}}}:=e^x e^y

will in addition make e arbitrary (however you shouldn't denote an arbitrary variable with e, that is just confusing notation).

(d{}a) {} b
Means the variable d, interpreted as a function, applied to a, and the entire result, interpretted as a function, applied to b.


This is how you can teach the calculator to do the chain rule for differentiation:

1
2
d {} ({{f}}{}{{g}}):= (d{}g){}x (d{}f){}(g{}x); 
d{}(f{}(g{}(h{}x)))


Oops.. just found out the result is correct but the displayed computation is unreadable. The calculator needs more work :)

[Edit:] However, here is how you can fix it using the calculator's own manipulation >:)

1
2
3
4
5
d {} ({{f}}{}{{g}}):= (d{}g){}x (d{}f){}(g{}x); 
(d{}x){} x:=1;
z:=d{}(f{}(g{}(h{}x)));
{{a}}{} x:=a;
z


http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator?in1=d+%7B%7D+%28%7B%7Bf%7D%7D%7B%7D%7B%7Bg%7D%7D%29%3A%3D+%28d%7B%7Dg%29%7B%7Dx+%28d%7B%7Df%29%7B%7D%28g%7B%7Dx%29%3B+%0D%0A%28d%7B%7Dx%29%7B%7D+x%3A%3D1%3B%0D%0Az%3A%3Dd%7B%7D%28f%7B%7D%28g%7B%7D%28h%7B%7Dx%29%29%29%3B%0D%0A%7B%7Ba%7D%7D%7B%7D+x%3A%3Da%3B%0D%0Az%0D%0A
Last edited on Mar 9, 2012 at 8:05pm
Mar 9, 2012 at 8:25pm
I just feel the syntax is not obtuse enough. Think you can weird it up a notch?

Have you considered doing it in Haskell? A while ago I wrote a simple symbolic differentiator in about 100 lines, and most of it was the pattern matching rules.
Mar 9, 2012 at 8:45pm
What does the word obtuse mean - does it mean that the syntax is not weird enough?

Well, I mean, in a way it is a functional calculator.
I have never written even a hello world in Haskell
(I tried to read a program in Haskell from this forum, to no avail).

As far as pattern matching rules go: well, that is the whole point of the exercise,
and I wouldn't substitute here C++ for anything.

Here are complex numbers:

1
2
i*i:=-1;
(5i+6)*(12i+13)


http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator?in1=i*i%3A%3D-1%3B%0D%0A%285i%2B6%29*%2812i%2B13%29

Here is factorial:
factorial{}0:=1;
factorial{}{{n}} :if(IsInteger{} n):=n factorial{} (n-1);
factorial{} 5

http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator?in1=factorial%7B%7D0%3A%3D1%3B+%0D%0Afactorial%7B%7D%7B%7Bn%7D%7D+%3Aif%28IsInteger%7B%7D+n%29%3A%3Dn+factorial%7B%7D+%28n-1%29%3B+%0D%0Afactorial%7B%7D+5


Here are quaternions:
1
2
3
4
5
i*j:=k; j*i:=-k;
j*k:=i; k*j:=-j*k;
k*i:=j; i*k:=-j;
i*i:=-1; j*j:=-1; k*k:=-1;
(1+2 i+ 3 j+ 4 k)* (1+2 i+ 3 j+ 4 k)


http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator?in1=i*j%3A%3Dk%3B+j*i%3A%3D-k%3B%0D%0Aj*k%3A%3Di%3B+k*j%3A%3D-j*k%3B%0D%0Ak*i%3A%3Dj%3B+i*k%3A%3D-j%3B%0D%0Ai*i%3A%3D-1%3B+j*j%3A%3D-1%3B+k*k%3A%3D-1%3B%0D%0A%281%2B2+i%2B+3+j%2B+4+k%29*+%281%2B2+i%2B+3+j%2B+4+k%29


I guess the principle is clear (Mathematica does it, you did too,...),
the deal is to make it so that it is very quick and comfortable to use.

Part of the design goal was also to be able to copy+paste
formulas from actual math articles (which are written in LaTeX)
be able to simplify them directly, and paste back into the math article.
Last edited on Mar 9, 2012 at 8:55pm
Mar 9, 2012 at 9:16pm
I think he was being sarcastic about it not being obtuse enough - LaTeX syntax is kind of obtuse already, but you've made it into a calculator! I think he was commenting on the peculiarity of LaTeX as the syntax of a calculator, it just seems weird (although it's similar to an idea I had - a LaTeX parser that would also calculate the answers to your expressions on-the-fly; I didn't think I was skilled enough to do it).

As for "hello, world" in Haskell, it looks a bit like this:
1
2
main :: IO ()
main = do putStrLn "hello, world"
Mar 9, 2012 at 9:54pm
LaTeX syntax is kind of obtuse already.


I disagree. I have been using it professionally for the last 5 years. It is the most efficient (and currently, the only*) way of writing serious mathematical papers. .doc is taboo on the floor of the building I work.

*Most mathematical journals accept LaTeX manuscripts only. A few exceptions accept pdf/dvi/eps as well. No serious journal accepts human-readable format other than LaTeX.

The calculator is only partially LaTeX-compatible: it does not use the symbol \, which is the command-symbol for LaTeX.

I have made a promise to myself to make the calculator output LaTeX-compatible. However, the calculator input does not have to be LaTeX-compatible.
Last edited on Mar 9, 2012 at 9:58pm
Mar 9, 2012 at 10:13pm
I agree that it's the best, but it's still kind of obtuse.

MS Word's equation feature is quite good but LaTeX is much better, mostly because you can type commands rather than clicking buttons all over the place.

What is the format of a LaTeX output file?
Mar 10, 2012 at 12:05am
Was it totally necessary to label functions differently from variables? A symbol is a symbol, after all.
And your love for braces can only be compared to Lisp's love for parentheses.
Mar 10, 2012 at 12:17am
helios wrote:
Was it totally necessary to label functions differently from variables? A symbol is a symbol, after all.

There's a point - you could use something similar to type inference to figure out whether it's a function or a variable, or, even better, make them the same thing.
Mar 10, 2012 at 1:04am
Was it totally necessary to label functions differently from variables?


helios, they are not labeled differently. You can even use constants as functions, for example

1{}x:=x;
[Edit:] Just implemented left distributivity for functions (it actually shortened the code hehe):
Here it is:
 
(f g+h){}x;

http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator?in1=%28f+g%2Bh%29%7B%7Dx



{{x}} will display in LaTeX in the same way as x, which was my intention.

The Mathematica solution: x_ is a no-no - it does not compile correctly in LaTeX. Whatever the choice for bounded variable operation is, it must be invisible in LaTeX. I chose {{x}} (I tried a few other options, but this one was best so far).

Do you have a better idea?

As far as function arguments go:
f{} x in the calculator is equivalent to
f[x] in Mathematica. The Mathematica solution is no good to me: most mathematicians denote function arguments with usual () brackets.

Furthermore,
[a,b] is reserved for a Lie bracket operation
[a,b]:=a b-b a
At the moment the calculator supports neither the comma nor the [] operations but it will soon.

Again, taking on better suggestions.
Last edited on Mar 10, 2012 at 2:02am
Mar 10, 2012 at 2:53am
helios, they are not labeled differently.
What's that "{}" thing then?

Whatever the choice for bounded variable operation is, it must be invisible in LaTeX.
But you said the input didn't need to be compatible with LaTeX.

The main problem IMO is that you're using the braces for everything, and it just makes it too hard to follow.
How about using unbracketed notation for function application (f x y z) if you must have implicit multiplication? Or maybe multiplication of a function with anything else the same as function application.
Also, I don't get the difference between {{x}} and x. Could you explain the semantics in a little more detail?
Mar 10, 2012 at 3:25am
A function f evaluated at x internally is represented as {} (f, x);
A function application is a new operation. It has a little different properties compared to * and +, for example it is true that
(f+g){} x:= f{}x+g{}x
but it is not true that
f{}(x+y):=f{}x+f{}y
(if this were true, f would be called an additive function).

But you said the input didn't need to be compatible with LaTeX


Oops, you are right. It is not necessary that it be compatible with LaTeX. But I want it nonetheless :)
[Edit:]
However, the output of the calculator must also be a valid input of the calculator (this is just common sense). I can make a relaxed input, and then add all the "stricter" syntax in the output. This I guess is in the right spirit of relaxed syntax. For example, the calculator accepts
3*-4
[Edit:]and so does c++!

if you must have implicit multiplication


This is entirely a matter of taste. I prefer implicit multiplication and explicit function application to explicit multiplication and implicit function application (I guess what you are suggesting). It is easily doable however. Most math texts do not write * for multiplication as opposed to computer science texts.

Also, I don't get the difference between {{x}} and x

This is an idea I learned from Mathematica, perhaps the most brilliant idea of that program.{{x}} translates one to one to the Mathematica x_.

The{{}} operation is used to denote substitution (pattern) rules. {{x}} is a local variable, valid only for the duration of the current command it resides in. The first letter enclosed in {{}} becomes "dummy" variable. Any further encounter of that letter in the same command, even if not enclosed in {{}}, is automatically considered to be enclosed in {{}}. For example,
 
{{x}}{{y}}:=x+y

is the same as
 
{{x}}{{y}}:={{x}}+{{y}}

A dummy variable should not be used outside of the left side of (something := something ) expression. A dummy variable denotes the "-any expression matches me-" pattern. That is, if you say
 
{{x}}:=x+1
,
you are saying "(AnyExpression) should be substituted by (AnyExpression +1)". Of course, this will set the calculator on an "infinite cycle". Here is that exact example:
http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator?in1=%7B%7Ba%7D%7D%3A%3Da%2B1%3B%0D%0Ax

For example, the pattern {{x}}^({{a}}+{{x}}) would match b^{c+b} (with {{x}}=b and {{a}}=c), would match b^{b+b} (with {{x}}=b and {{a}}=b), but would not match b^{c+d}.
Last edited on Mar 10, 2012 at 4:22am
Mar 10, 2012 at 6:13am
A function f evaluated at x internally is represented as {} (f, x);
Oh, I get it, now. It's $.

I prefer implicit multiplication and explicit function application to explicit multiplication and implicit function application
They aren't mutually exclusive. For example, if someone does
x + y := x y
f x := 2
/*1*/ 1+1
/*2*/ f+0
#1 would evaluate to 1, since 1 is not a function, but #2 would evaluate to 2, since f is. Basically, the first statement is transformed internally into
x + y := x (if x is a function then {} else *) y

Wouldn't it make more sense to make {{}} do the opposite? It seems much more likely to want to refer to some arbitrary expression than to a specific global constant, doesn't it?
Mar 10, 2012 at 4:52pm
I can use both $ and {} for function argument (again, they are not mutually exclusive) ([Edit:] implemented!).

One way to implement what you are suggesting is the following substitution rule

f *{{x}}:= f$x;

For example,
1
2
3
f {{x}}:= f$x;
f(a*b);
f*a*b

http://cartan.math.umb.edu/vpf/cgi-bin/symbolicCalculator?in1=f+%7B%7Bx%7D%7D%3A%3D+f%24x%3B%0D%0Af%28a*b%29%3B%0D%0Af+*+a*b

which is already working without modifying anything.

Wouldn't it make more sense to make {{}} do the opposite? It seems much more likely to want to refer to some arbitrary expression than to a specific global constant, doesn't it?


I can't make up my mind. Most function names better have global names, and most function arguments better be dummy variables. I really don't know which is best (but, Mathematica did chose the special syntax for dummy variable, and regular syntax for global variable).
Last edited on Mar 10, 2012 at 5:14pm
Topic archived. No new replies allowed.