Skip to content

Implicit derivative #12922

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
miguelmarco opened this issue May 8, 2012 · 38 comments
Closed

Implicit derivative #12922

miguelmarco opened this issue May 8, 2012 · 38 comments

Comments

@miguelmarco
Copy link
Contributor

Added implicit_derivative function. It allows to compute the n'th derivative of the implicit function defined by a symbolic expression.

CC: @kcrisman @sagetrac-sjg10 @burcin

Component: calculus

Keywords: implicit derivative

Author: Miguel Marco

Branch/Commit: 0a76da7

Reviewer: Kannappan Sampath, Ralf Stephan

Issue created by migration from https://trac.sagemath.org/ticket/12922

@miguelmarco
Copy link
Contributor Author

Attachment: 16191.patch.gz

@sagetrac-sjg10
Copy link
Mannequin

sagetrac-sjg10 mannequin commented Jul 11, 2012

comment:3

Reviewed, seems good. Added a check for having no y term in the expression. Was previously an uncaught DivideByZero, while code now gives a more informative error.
Was my first review, would appreciate to know whether I'm actually being any help!

@kcrisman
Copy link
Member

comment:4

Yes, both helpful! A few comments.

  • The reviewer patch should be a separate patch on top of the original patch, so that the original author is kept.
  • In any case, the patch should have a meaningful commit message.
  • I'm a little apprehensive about the many specific variables and functions defined here. Won't that cause some kind of conflict with (say) an already-defined yy? We shouldn't depend on people not needing those variables. Or is everything only in local scope because of the use of SR.symbol?

I'm also wondering - is it possible to have an implicit derivative method for symbolic expressions? Just curious.

@sagetrac-sjg10
Copy link
Mannequin

sagetrac-sjg10 mannequin commented Jul 11, 2012

adds error handler

@miguelmarco
Copy link
Contributor Author

comment:5

Attachment: 16191_review.patch.gz

All the variables defined in the function are local. They do not get mixed with the global variables with the same name. You can even call the function with xx and yy as parameters, and they will not be mixed with the local xx and yy.

sage: var('x,y')
(x, y)
sage: implicit_derivative(y,x,y*x/cos(x+y))
-(x*y*sin(x + y)/cos(x + y)^2 + y/cos(x + y))/(x*y*sin(x + y)/cos(x + y)^2 + x/cos(x + y))
sage: var('xx,yy')
(xx, yy)
sage: implicit_derivative(yy,xx,yy*xx/cos(xx+yy))
-(xx*yy*sin(xx + yy)/cos(xx + yy)^2 + yy/cos(xx + yy))/(xx*yy*sin(xx + yy)/cos(xx + yy)^2 + xx/cos(xx + yy))

About writing this as a method for symbolic expressions... that was my first idea; but i prefeared this aproach, due to the fact that you are actually not diferentiating the symbolic expression, but a function defined implicitely by the symbolic expression. So it seemed more natural to me this kind of syntax.

@sagetrac-sjg10
Copy link
Mannequin

sagetrac-sjg10 mannequin commented Jul 13, 2012

comment:6

Calling var or SR.symbol('somename') even locally does add to the pynac_symbol_registry, yet calling SR.symbol() with no argument will create a temporary variable that will not be added to this registry. Possibly adding to the registry may cause problems if it is being referenced directly for some reason. Maybe worth just using x = SR.symbol() etc?

sage: from sage.symbolic.ring import pynac_symbol_registry
sage: pynac_symbol_registry                               
{'some_variable': some_variable, 'A': A, 'C': C, 'B': B, 'E': E, 'D': D, 'G': G, 'F': F, 'H': H, 'K': K, 'J': J, 'M': M, 'L': L, 'N': N, 'Q': Q, 'P': P, 'S': S, 'R': R, 'U': U, 'T': T, 'W': W, 'V': V, 'Y': Y, 'X': X, 'Z': Z, 'a': a, 'c': c, 'b': b, 'd': d, 'g': g, 'f': f, 'h': h, 'k': k, 'j': j, 'm': m, 'l': l, 'o': o, 'n': n, 'q': q, 'p': p, 's': s, 'r': r, 'u': u, 't': t, 'w': w, 'v': v, 'y': y, 'x': x, 'z': z}
sage: def f(): temp = SR.symbol()                         
....: 
sage: f()
sage: pynac_symbol_registry
{'some_variable': some_variable, 'A': A, 'C': C, 'B': B, 'E': E, 'D': D, 'G': G, 'F': F, 'H': H, 'K': K, 'J': J, 'M': M, 'L': L, 'N': N, 'Q': Q, 'P': P, 'S': S, 'R': R, 'U': U, 'T': T, 'W': W, 'V': V, 'Y': Y, 'X': X, 'Z': Z, 'a': a, 'c': c, 'b': b, 'd': d, 'g': g, 'f': f, 'h': h, 'k': k, 'j': j, 'm': m, 'l': l, 'o': o, 'n': n, 'q': q, 'p': p, 's': s, 'r': r, 'u': u, 't': t, 'w': w, 'v': v, 'y': y, 'x': x, 'z': z}
sage: def f(): temp = SR.symbol('temp')
....: 
sage: f()
sage: pynac_symbol_registry
{'temp': temp, 'some_variable': some_variable, 'A': A, 'C': C, 'B': B, 'E': E, 'D': D, 'G': G, 'F': F, 'H': H, 'K': K, 'J': J, 'M': M, 'L': L, 'N': N, 'Q': Q, 'P': P, 'S': S, 'R': R, 'U': U, 'T': T, 'W': W, 'V': V, 'Y': Y, 'X': X, 'Z': Z, 'a': a, 'c': c, 'b': b, 'd': d, 'g': g, 'f': f, 'h': h, 'k': k, 'j': j, 'm': m, 'l': l, 'o': o, 'n': n, 'q': q, 'p': p, 's': s, 'r': r, 'u': u, 't': t, 'w': w, 'v': v, 'y': y, 'x': x, 'z': z}

@miguelmarco
Copy link
Contributor Author

comment:7

I have tried to use SR.symbol() instead of SR.symbol('x'), but then the result is a mess.

I can't think of a way to make this work without the said side effect.

@miguelmarco
Copy link
Contributor Author

comment:8

I solved the pynac symbol registry pollution by saving a copy of it at the beginning of the function, and restoring it at the end. I am not sure if this is the best choice, but it is the only solution i found, and seems to work fine.

@burcin
Copy link
Contributor

burcin commented Jun 7, 2013

comment:9

Messing with the symbol registry this way is really not a good idea. That is just supposed to be internal data.

What if there is an exception in that code and the registry is not restored?

What exactly is the problem with using temporary variables? Looking briefly at the patch, it looks like we also need temporary functions.

@miguelmarco
Copy link
Contributor Author

comment:10

The problem with using temporary variables without giving them a name string is this:


sage: from sage.symbolic.function_factory import SymbolicFunction
sage: var('x,y')                                                                                                                                    
(x, y)
sage: def implicit_derivative(Y,X,F,n=1):                                                                                                           
....:         x=SR.symbol()                                                                                                                         
....:         yy=SR.symbol()                                                                                                                        
....:         y=SymbolicFunction('y',1)(x)                                                                                                          
....:         f=SymbolicFunction('f',2)(x,yy)                                                                                                       
....:         Fx=f.diff(x)                                                                                                                          
....:         Fy=f.diff(yy)                                                                                                                         
....:         G=-(Fx/Fy)                                                                                                                            
....:         G=G.subs_expr({yy:y})                                                                                                                 
....:         di={y.diff(x):-F.diff(X)/F.diff(Y)}                                                                                                   
....:         R=G                                                                                                                                   
....:         S=G.diff(x,n-1)                                                                                                                       
....:         for i in range(n+1):                                                                                                                  
....:                 di[y.diff(x,i+1)(x=x)]=R                                                                                                      
....:                 S=S.subs_expr(di)                                                                                                             
....:                 R=G.diff(x,i)                                                                                                                 
....:                 for j in range(n+1-i):                                                                                                        
....:                         di[f.diff(x,i,yy,j)(x=x,yy=y)]=F.diff(X,i,Y,j)                                                                        
....:                         S=S.subs_expr(di)                                                                                                     
....:                 return S                                                                                                                      
....:                                                                                                                                               
sage: implicit_derivative(y,x,x^2+y^2-1)                                                                                                            
-D[0](f)(symbol160, y(symbol160))/D[1](f)(symbol160, y(symbol160))

I don't know why, this problem is not present if we put the strings in the definitions of the variables.

@burcin
Copy link
Contributor

burcin commented Jun 8, 2013

comment:11

Replying to @miguelmarco:

sage: implicit_derivative(y,x,x^2+y^2-1)                                                                                  
-D[0](f)(symbol160, y(symbol160))/D[1](f)(symbol160, y(symbol160))

It looks like the substitution doesn't work at some point.

Looking at the code...

The calls y.diff(x,i+1)(x=x) and f.diff(x,i,yy,j)(x=x,yy=y) rely on the name of the variable. You should use a dictionary argument to .subs().

BTW, the subs_expr() method will go away at some point. Why not just use .subs() everywhere?

@burcin
Copy link
Contributor

burcin commented Jun 8, 2013

comment:12

Before this gets switched to positive review, we should check how it behaves if there already is a symbolic function defined with a custom method for evaluation named y or f.

Why is this not a method of symbolic expressions? Isn't it inconsistent to have the functional notation supported but not a class method?

@miguelmarco
Copy link
Contributor Author

comment:13

Thanks for the comments. I will try to work on it.

As i said, the reason why it is not a method is that it is not clear to me what class should it be in.

Is this a method of the expression F? Well, not exactly, since F is not the function that we are trying to differentiate, but the symbollic expression that deffines it implicitly.

Of X? This is just the variable with which we differentiate on.

Of Y? Riguorilously that should be the function that we are differentiating. But doesn't sound natural at all to add a method like this for symbollic variables.

Or maybe we could define a new class ImplicitelyDefinedSymbolicFunction for this case, bat that sounds way overkill.

@miguelmarco
Copy link
Contributor Author

Attachment: 12922.patch.gz

Newer version, solves the pynac registry pollution without manipulating it

@miguelmarco
Copy link
Contributor Author

comment:14

Ok, your suggestions seemed to work fine. I have uploaded a newer version. Please check it.

@jdemeyer jdemeyer modified the milestones: sage-5.11, sage-5.12 Aug 13, 2013
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.1, sage-6.2 Jan 30, 2014
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin removed this from the sage-6.2 milestone May 6, 2014
@KPanComputes
Copy link

New commits:

39aaf0cAdded implicit_derivative

@KPanComputes
Copy link

comment:25

For starters, I have the following comments:

  1. The one-line docstring for the function is "incorrect": it computes something, yes, but it also returns it. So, please change that to "Return ".
  2. The value error could return the expression F explicitly instead of saying the generic F. While you are it, please use the .format to format the string for the output instead.

Honestly, I have not looked at the math. I will get back about the math and the programming part in a bit.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Aug 24, 2014

Branch pushed to git repo; I updated commit sha1. New commits:

3f3f949Reviewer's suggestions changed, plus some changes for PEP8 compliance.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Aug 24, 2014

Changed commit from 39aaf0c to 3f3f949

@rwst
Copy link
Contributor

rwst commented Sep 1, 2014

comment:27

Replying to @miguelmarco:

As i said, the reason why it is not a method is that it is not clear to me what class should it be in.

Is this a method of the expression F? Well, not exactly, since F is not the function that we are trying to differentiate, but the symbollic expression that deffines it implicitly.

I think Burcin wants this method part of the symbolic expression or function class. If it's not tied to a specific expression then make it a @classmethod (equivalent to a static method in C), and then create the globally accessible name for it.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Sep 2, 2014

Branch pushed to git repo; I updated commit sha1. New commits:

5fe0ffeMoved to a method in the expression class

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Sep 2, 2014

Changed commit from 3f3f949 to 5fe0ffe

@miguelmarco
Copy link
Contributor Author

comment:29

Moved it to a method in the expression class.

@rwst
Copy link
Contributor

rwst commented Feb 2, 2015

Changed branch from u/mmarco/ticket/12922 to u/rws/ticket/12922

@rwst
Copy link
Contributor

rwst commented Feb 2, 2015

comment:31

Just some minor fixes. It looks good. I did no make ptestlong as it's just a new method.


New commits:

7e00610Merge branch 'develop' into t/12922/ticket/12922
954997612922 reviewer's patch: optimize imports and doc cosmetics

@rwst
Copy link
Contributor

rwst commented Feb 2, 2015

Changed reviewer from Kannappan Sampath to Kannappan Sampath, Ralf Stephan

@rwst
Copy link
Contributor

rwst commented Feb 2, 2015

Changed commit from 5fe0ffe to 9549976

@rwst rwst modified the milestones: sage-6.4, sage-6.5 Feb 2, 2015
@miguelmarco
Copy link
Contributor Author

comment:32

Thanks for the review.

@mezzarobba
Copy link
Member

comment:33
**********************************************************************
File "src/sage/misc/sageinspect.py", line 1815, in sage.misc.sageinspect.sage_getsourcelines
Failed example:
    sage_getsourcelines(x)[0][-1]    # last line
Expected:
    '        return self / x\n'
Got:
    '        return S\n'
**********************************************************************

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 8, 2015

Changed commit from 9549976 to 0a76da7

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 8, 2015

Branch pushed to git repo; I updated commit sha1. New commits:

0a76da712922: fix doctest

@rwst
Copy link
Contributor

rwst commented Feb 8, 2015

comment:35

Interesting. That doctest depends on the last line in class Expression to remain unchanged.

@vbraun
Copy link
Member

vbraun commented Feb 17, 2015

Changed branch from u/rws/ticket/12922 to 0a76da7

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

No branches or pull requests

8 participants