Step Derivation implemented #2933

wants to merge 5 commits into


None yet
4 participants

rajat974 commented Feb 19, 2014

Derivation steps has been implemented, in which one can see the steps involving derivations.
For now, it only includes the derivations of the expressions including addition, multiplication, and power of all the functions.


rajat974 commented Feb 24, 2014

@mrocklin Can you please provide me some feedback with this !


mrocklin commented Feb 24, 2014

Hi @rajat974 , thanks for pinging me. I am not alerted when new pull requests come up and don't always check the mailing list.

After looking at your code briefly (I'm at work right now) here are some thoughts

  1. The results you get look really cool
  2. Your code is clear and simple
  3. I think that to apply this approach to all of SymPy will take a lot of work. I think we would have to duplicate all _eval_foo methods to _step_foo methods. This is probably too much. The step-by-step feature is really cool but shouldn't make the code too much bigger. I wonder if there is a way to collect the steps that occur without rewriting all of the _eval_foo methods. How can we do what you have done here without changing SymPy too much? I wonder if there is some fancier way.

rajat974 commented Feb 25, 2014

@mrocklin Despite of being busy thanks for reviewing it. I have gone through the different parts of the sympy code, its true that we would have to implement a lot of new functions, but same can be reduced in some parts, like integration( where we already have manual integration steps etc.). Similarly, in some other parts _step_foo can be added to their base classes. We can think of these kind of optimizations as of now. I am thinking of some better idea also.


rajat974 commented Mar 3, 2014

I was working on the other parts of the sympy code, to understand the much part of it so that i can have ideas for this project that how we can reduce new step_eval functions to implement step-by-step expressions. I have come up with new ideas and different kind of implementations.

  1. In sympy we have different kind of implementations for different kind of functions. In integration we already have the list of the steps. For example: If i evaluate

integrate(asin(x) *log(x), x), we get the integral_steps
PartsRule(u=log(x), dv=asin(x), v_step=PartsRule(u=asin(x), dv=1, v_step=ConstantRule(constant=1, context=1, symbol=x), second_step= URule(u_var=_u, u_func=-x**2 + 1,constant=1/2, substep= ConstantTimesRule(constant=1/2, other=-1/sqrt(_u), substep =ConstantTimesRule(constant=-1, other=1/sqrt(_u), substep= PowerRule(base=_u, exp=-1/2, context=1/sqrt(_u), symbol=_u), context=-1/sqrt(_u), symbol=_u), context=-1/sqrt(_u), symbol=x), context=x/sqrt(-x**2 + 1), symbol=x), context=asin(x), symbol=x), second_step=RewriteRule(rewritten=asin(x) + sqrt(-x**2 + 1)/x, substep=AddRule(substeps=[PartsRule(u=asin(x), dv=1, v_step= ConstantRule(constant=1, context=1, symbol=x), second_step= URule(u_var=_u, u_func=-x**2 + 1, constant=1/2, substep= ConstantTimesRule(constant=1/2, other=-1/sqrt(_u), substep =ConstantTimesRule(constant=-1, other=1/sqrt(_u), substep= PowerRule(base=_u, exp=-1/2, context=1/sqrt(_u), symbol=_u), context=-1/sqrt(_u), symbol=_u), context=-1/sqrt(_u), symbol=x), context=x/sqrt(-x**2 + 1), symbol=x), context=asin(x), symbol=x), DontKnowRule(context=sqrt(-x**2 + 1)/x, symbol=x)], context=asin(x) + sqrt(-x**2 + 1)/x, symbol=x), context=(x*asin(x) + sqrt(-x**2 + 1))/x, symbol=x), context=log(x)*asin(x), symbol=x)

For such a big parts like integral, we can just parse this output and change this into a tree to get the whole hierarchy and then we can print the steps which are taken to do this integral.
In Integrations, different algorithms have been used, we can use these steps and it can be used to explain the algorithms to the users. Say if a user want to know about risch algorithm , we can use these steps to explain the algorithm by taking one example of any function.

  1. For derivations, I had already implemented tree structures for having step by step expressions, as you can see in the commits.
    For the optimizations and addition of less functions, we can traceback for some functions and get the inputs and outputs of the called function and put that in a tree like
def goto_child(self, infunc):
           if len(infunc.args) == 0:
              return infunc
          temp = infunc
          infunc =  list(infunc.args)
          for i in range(len(infunc)):
              if isinstance(infunc[i], Derivative):
                  infunc[i] = diff(infunc[i].expr, infunc[i].args[-1], evaluate=True, step=True)
                  infunc[i] = self.goto_child(infunc[i])
          at = tuple(infunc)
          return temp.func(*at)
def tracefunc(frame, event, arg, indent=[0]):
      if event == "call":
          if frame.f_code.co_name == "_eval_derivative":
                 # make a parent with 'arg' and the send the child to the next call
      elif event == "return":
                # store the resturn result and then go to next level of tree
      return tracefunc  

This implementation will be same for many functions which have the standard call for doit() or for _eval_derivative(). Same can be done for the basic classes.

According to me, if we use traceback, there is a need of step_derivation function at the end of for some parent classes, because sympy code is very vast and if in future some change happens, then we may have to change this parser for traceback functions .

Conclusive thought which i have is, We can use traceback to form string of steps for every called functions (similar to shown in integration ) and then we make parser for the main function( like Integrate() ) and since for every function we can get the input argument and output argument, we can make a tree and then we output the results.
Benifits: Very Less addition of new functions, parser will be able to parse for every function including both simple and complex. Easy Implementation.

Eagerly waiting for your feedback.


rajat974 commented Mar 6, 2014

@mrocklin Can you please give me some feedback ??


mrocklin commented Mar 8, 2014

Sorry for the delay @rajat974

I agree with you that tracing looks like a good strategy. Presumably we could replace your check

if frame.f_code.co_name == "_eval_derivative"

with something much more general like

if '_eval_' in frame.f_code.co_name:

and capture much more information. I haven't thought much about this approach. Do you see any problems that will need to be solved to make it work?


rajat974 commented Mar 10, 2014

@mrocklin There is not any limitation with this approach. But what i was saying that we can use these techniques to form a steps string as we already have in integration parts. I discussed that in last comment. Can you please look over it , so that i can start with the proposal.


rajat974 commented Mar 11, 2014

@mrocklin I have submitted the proposal. Please have a look over the proposal and suggest me the changes.


rajat974 commented Mar 19, 2014

@mrocklin I had submitted the proposal. Please review it and give me suggestions to improve it , as deadline is very near.


mrocklin commented Mar 20, 2014

Hi @rajat974, sorry that I can't provide feedback right now. I'm very busy at work. I hope to have time to look at applications this weekend. You'll still have an opportunity to discuss the application in comments during the evaluation time. You could also reach out to the other core developers beforehand.


akshayah3 commented Apr 27, 2014

@mrocklin @rajat974 What is the status of this PR?


mrocklin commented Apr 27, 2014

This PR was a proof of concept attached to a GSoC submission. While it shows good progress I think that it is not sufficiently general to serve as the final solution. Probably it should be closed.

hargup closed this May 20, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment