From UBC Wiki

What is the problem?

Symbolic Integration is the problem of finding a formula for the derivative or indefinite integral for a given function f(x). Unlike numerical integration which gives a numerical value as a result, a computer cannot utilize numerical techniques to aproximate the value. While symbolic derivation can be achieved in logic programming through a series of relatively simple axioms, such as linearity, the chain and product rule, the power rule and the trigonometric definitions. A logical definition for the symbolical derivative can be done as follows:

% deriv(E,X,DE) is true if DE is the derivative of E with respect to X

This means that for symbolic derivation the input form of the function E can be done as any elementary function in multiple forms.

For instance f(x) = x^2 can also be written as something like x*x. The logical query for both will give different symbolic results that are mathematically equivalent.

?- deriv(x^2,x,X).
X = 2*x^(2-1)*1 .

?- deriv(x*x,x,X).
X = x*1+x*1  

This difference in form posses a problem for symbolic integration. The main problem in this approach is that generally speaking, the closed form representation of a function is different from the representation. For instance consider these three axioms for a naive antiderivative logical query:

% antid(DE,X,E) is true if E  is the antiderivative of DE with respect to X
antid(C,X,C*X) :- atomic(C).
antid(F,DX,X) :- deriv(X,DX,DE).
?- antid(2*x,x,X)

This query will get stuck in a loop since the program does not recognize 2*x as being equal to any of the derivative forms of f(x)=x^2. In fact, it won't recognize neither x*1+x*1 or 2*x^(2-1)*1 as correct.

In other words, in order for symbolic integration to work in logical programming, some sort of "reverse simplifier" type clause will be needed if one wishes to use the defintion of the integral as an antiderivative.

Alternatively, one could axiomatically define the properties of integral going through each rule for multiple cases.

For our project we decided to go with the second option.

What is the something extra?

When defining our rules we decided to include the general forms of functions. This means that for instance the rule


will not typically account for the cases in which there is a constant such as ln(bx+a). To account for this we included rules for these cases in multiple functions, for instance in the case of ln(x):

integ(ln(B*X),X,X*ln(B*X)-X) :- atomic(B).
integ(ln(X+A),X,(A+X)*ln(X+A)-X) :- atomic(A).
integ(ln(B*X+A),X,(A/B + X)*ln(B*X + A)-X) :- atomic(A), atomic(B).

Additionally, we looked into the feasability of implementing u-substitution and integration by parts, however this seems out of scope for the current axiom based system since it utilizes derivative in the definition. Consider this naive approach for Integration by Parts:

integ(U*DV,X,U*V- IVDU) :- deriv(V,X,DV), deriv(U,X,DU), integ(V*DU,X,IVDU).

We run into the same issue as utilizing the anti-derivative method since it reiles on the derivative of V and U.

So instead we implemented a definitive integral formula for polynomial functions expanding on David's

What did we learn from doing this?

Initially, we thought that implementing an Integral Calculator which could handle all kinds of different Integrals would be doable, turns out this was a very naive approach from us. Prolog is very good at pattern matching which means that things that have set rules like a Derivative Calculator can be implemented without much hassle. This is also the case for the Integral Calculator but only to a certain extent, and a very minor one in the realm of Integration. While we were able to effectively integrate functions that have defined forms of integration which can be logically defined for Prolog to compute, more complex forms of integration such as, integration by parts or u-substitution are radically harder to implement. Not only are the intricacies we would need to master about Symbolic Integration to fully implement the calculator way out of the scope of any undergraduate analysis class, but this would in essence, as mentioned above, require us to implement a "reverse simplifier" in order to functional operations that Prolog could fully understand. In other words, integration isn't very logical, as opposed to differentiation, it does have set rules which work to a certain extent but more complex forms of integration just have no set logical procedure to follow, it needs a severe amount of interpretations for it to predefined some systematic way to handle every case of an Integral.

Prolog is remarkably good at working with logically defined procedures, that is why it's so good at implementing Expert Systems, it has a very efficient way to match patterns and it is very effective at handling queries and case-by-case methodical problems. Given a set of rules or procedures Prolog will be able to implement and work through all of them flawlessly, and an in theory I am sure a full-fleshed Integral Calculator could be implemented using Prolog, but feasibility-wise it is quite far fetched.

Links to code etc

Project page