what's the reason for the unexpect behavior of plot() - python

def f(u):
value = 0.0
if u > -1 and u < 1:
value = u * u
return value
Given the above, the following produces the expected plot:
plot(f,(x,-5,5))
But plot(f(x),(x,-5,5)) just draws a horizontal line. Can anyone explain what's going on?

The former passes the function, allowing it to be called inside plot(). The latter calls the function once and passes the returned value, resulting in the same value each time.

Similar to what #Ignacio said, the cause is the function being called once. The problem with this vs other functions like sin is the conditional. The if statement is evaluated when the function is called and not preserved as a symbolic statement. That is, the u > -1 and u < 1[1] is evaluated on the first function call and result is treated accordingly (i.e. left at 0).
As an illustration of what is happening:
sage: x = var('x')
sage: print ":)" if x > 0 else ":("
:(
There is no way to get around this in general[2], because Python has to evaluate the condition in the if statement to work out which code path to take when the function is called.
Best case solution
There is a solution that should work (but doesn't yet). Sage provides Piecewise, so you can define f as:
f = Piecewise([((-5, -1), ConstantFunction(0)),
((-1, 1), x*x),
((1, 5), ConstantFunction(0))],
x)
Unfortunately, the implementation of Piecewise is as yet incomplete, and severely lacking, so the only way to plot this seems to be:
f.plot()
(Limitations: trying to call f with a variable causes errors; it doesn't work with the conventional plot; you can't restrict the domain in Piecewise.plot, it plots the whole thing (hence why I restricted it to &pm;5); it doesn't cope with infinite intervals.)
Working solution
You could also just detect whether the argument to f is a number or variable and do the appropriate action based on that:
def f(u):
try:
float(u) # see it's a number by trying to convert
return u*u if -1 < u < 1 else 0.0
except TypeError: # the conversion failed
if callable(f):
return lambda uu: f(u(uu))
else:
return f
Note the callable call, it checks to see if u is a function (in some sense), if so returns the composition of f with u.
This version allows us to do things like:
sage: f(10)
0.0
sage: f(x)(0.5)
0.25
sage: f(x+3)(-2.2)
0.64
and it also works perfectly fine with plot, in either form. (Although it warns about DeprecationWarnings because of the u(uu) syntax; there are ways to get around this using u.variables but they are fairly awkward.)
Note: This "working" solution is quite fragile, and very suboptimal; the Piecewise version would be the correct solution, if it worked.
[1]: Python actually allows you to write this as -1 < u < 1. Pretty cool.
[2]: Although in some special cases you can, e.g. if you know x > 0, then you can use assume(x > 0) which means the example will print :).

Here is a (possibly) simpler solution for now, using lambdas.
sage: plot(lambda x:f(x), (x,-5,5))

Related

python vs. R scope

I am trying to understand why I get a different output in two different function in R vs the same(?) implementation in python.
python:
def increment(n):
n = n + 1
print(n)
n = 1
increment(n)
print(n)
2
1
def increment2(x):
x[0] = x[0] + 1
print(x)
n = [1]
increment2(n)
print(n)
2
2
R:
increment <- function(n){
n = n + 1
print(n)
}
n = 1
increment(n)
2
print(n)
1
increment2 <- function(n){
n[1] = n[1] + 1
print(n)
}
n = c(1)
increment2(n)
2
print(n)
1
In my head it seems more consistent the R output. everything is inside the function and do not get outside (unless I return and assign the output back to n). Can anyone give me a pythonic interpretation of it?
This can be interpreted in terms of object identity.
A list x in python is like a pointer in that it has an identity independent of its contents so assigning a new value to an element of a list does not change the identity of the list. Changing the contents in the function does not change the list's identity and it seems that a function is free to change the contents.
A vector in R does not have an identity apart from its contents. Changing the contents in the function creates a new vector. The original vector is unchanged. R does have objects which have object identity -- they are called environments.
increment3 <- function(e){
e$n = e$n + 1
print(e$n)
}
e <- new.env()
e$n <- 1
increment3(e)
## [1] 2
print(e$n)
## [1] 2
In R, it is also possible to modify a vector in place using external C or C++ code. For example, see https://gist.github.com/ggrothendieck/53811e2769d0582407ae
I can't speak for how R passes parameters, but it's pretty common for programming languages (including Python) to have mutations on mutable objects be reflected outside of the function that performed the mutation. Java, C#, and other popular languages that support OOP (Object Oriented Programming) act this way too.
Lists like [1] are mutable objects, so you see that mutation outside of the function. This type of behavior makes object oriented programming much more convenient.
If this behavior is undesirable, consider using a functional programming style in python (immutable objects, map, filter, reduce) or passing copies of your mutable objects to your functions.
I don't think there's much going on here that has to do with it being pythonic or not. It's a language mechanism: nothing more.
R is heavily influenced by functional languages, most notably Scheme. In functional languages, a "function" is understood just like in mathematics, it does not (and cannot) change its arguments, and its output depends only on arguments (and nothing else).
# pseudocode
let x be 1
tell_me sin(x) # 0.841
tell_me x # still 1
It is conceivable that sin(x) would commit a sin (from a functional perspective) and assign a new value to x.
R is not a purely functional language, however.
(1) You can (easily, and sometimes with bad consequences) access objects from within a function.
> rm(jumbo) # if you're not running this for the first time
> mumbo <- function() jumbo
> mumbo()
Error in mumbo() : object 'jumbo' not found
> jumbo <- 1
> mumbo()
[1] 1
[edit] There was an objection in a comment that some objects need to be visible from within a function. That is completely true, for example, one cannot possibly define arithmetical operations in every function. So the definition of + must be accessible ... but the difference is, in some languages you have explicit control over what is accessible and what is not. I'm not a python expert but I guess that's what is meant by
from jumbo import *
R has packages, which you can attach in a similar way but the difference is that everything in your workspace is, by default, visible from within a function. This may be useful but is also dangerous as you may inadvertently refer to objects that you forgot to define within a function ... and the thing will work in a wrong way, as in the following example:
X <- 1e+10
addone <- function(x) X + 1 # want to increment the argument by 1
addone(3)
# [1] 1e+10
addone(3)==1e+10+1
# [1] TRUE
This is avoided in packages, so a function in a package cannot accidentally get values from your global workspace. And if you are so inclined, you can change the environment of your own functions as well. This might be a way to prevent such accidental errors (not necessarily a convenient way, though):
environment(mumbo) # .GlobalEnv
environment(mumbo) <- baseenv() # changing the environment
mumbo() # error: object 'jumbo' not found
[/edit]
(2) You can, if you want to, change outside objects from within a function, for example, with <<- (as opposed to <-):
> increment.n <- function(){
+ n <<- n + 1
+ print(n)
+ }
> increment.n()
Error in increment.n() : object 'n' not found
> n <- 1
> increment.n()
[1] 2
> n
[1] 2
>

Returning variables Matlab and Python?

I am trying to translate some code from Matlab to Python. The start of my function (in Matlab) starts like this:
function [varargout]=hysime(varargin);
error(nargchk(3, 4, nargin))
if nargout > 2, error('too many output parameters'); end
verbose = 1; % default value
y = varargin{1}; % 1st parameter is the data set
Later in the program there is something like this:
n = varargin{2}; % the 2nd parameter is the noise
Rn = varargin{3}; % the 3rd parameter is the noise correlation matrix
if nargin == 4, verbose = ~strcmp(lower(varargin{4}),'off');end
and finally there is this:
varargout(1) = {kf};
if nargout == 2, varargout(2) = {Ek};end
return
I am incredibly confused about what this code means. On one hand I understand that the parameters inputed all need to be returned. However, at the end of the program it appears like only 2 variables will be returned (while we input 3?). How can I translate this code so that the necessary parameters are returned? I guess my biggest issue here is that the matlab code is letting the agent input the parameters however they do not all seem required? And it seems like there cannot be more than two outputs? I am just having trouble deciphering what each line of code here means. Can someone please provide an explanation both in what is happening with the matlab code and what I can do to make the same sort of functionality in python?
Thanks!
Short version
The MATLAB code should have been written like this:
function [kf, Ek]=hysime(y, n, Rn, verbose);
error(nargchk(3, 4, nargin))
if nargin < 4
verbose = true;
else
verbose = ~strcmpi(verbose ,'off');
end
If you know MATLAB, this should be clearer. The (mostly) corresponding Python code can be written like this:
def hysime(y, n, Rn, verbose=True):
# rest of the function here
return kf, Ek
Long Version
This function expects 3 or 4 input arguments, with a default value set if the fourth argument is not provided. However, it is done in a way that is much more complicated than it needs to be (although I see this pattern a lot). Ideally in MATLAB you would specify the same thing like this:
function [varargout]=hysime(y, n, Rn, verbose)
error(nargchk(3, 4, nargin))
if nargin < 4
verbose = true;
else
verbose = ~strcmpi(verbose ,'off');
end
So what it is doing is putting the first argument in the variable y, the second in the variable n, the third in Rn, and if the fourth is specified put it in verbose (based on how it compares to the string 'off'), otherwise set verbose to true.
In python, handling of optional arguments is built-in. You can specify default value for arguments right in the function definition by setting name=value, where name is the argument name and value is the default value. Also, for historical reasons MATLAB often uses 'on' and 'off' instead of true and false. This is almost never done in Python, people just use True and False. So you can specify the same thing in Python like so:
def hysime(y, n, Rn, verbose=True):
This makes y, n, and Rn required arguments, but lets verbose be optional.
This doesn't handle the case where verbose is set to the string 'off'. As I said, this is common in MATLAB for historical reasons, but you really shouldn't be doing it in MATLAB anymore when you can avoid it, and you definitely shouldn't be doing it in Python. But if you really, really need to handle that case, you can just do:
def hysime(y, n, Rn, verbose=True):
if isinstance(verbose, str):
verbose = verbose.lower() != 'off'
For the output, what the MATLAB code does is let the function either return one value or two. So someone could do this:
kf = hysime(y, n, Rn);
Or
[kf, Ek] = hysime(y, n, Rn);
However, this is also being done in a way that is more complicated than necessary. If you just return the two values, and only one return value is used, MATLAB will throw away the rest. So rather than messing around with varargout, the function could just return [kf, Ek] and MATLAB will do the same thing. An error will automatically occur if someone tries to call the function with more than 2 outputs as well, so that is also unnecessary.
Dealing with varargout in this way is only necessary if you want the program to change its behavior based on the number of outputs. In this sort of structure, the main reason you would do this is if eK was expensive to calculate, in which case you would do something like this:
varargout(1) = {kf};
if nargout == 2
# calculate eK here
varargout(2) = {Ek};
end
As for the return, that is only needed in MATLAB if you want to cause the function to stop early, before it reaches the end normally. Once it reaches the end normally, it will return automatically. So if the last block of code you specified is the end of the function, then the return is redundant.
So all the code you showed in MATLAB can be reduced to:
function [kf, Ek]=hysime(y, n, Rn, verbose);
error(nargchk(3, 4, nargin))
if nargin < 4
verbose = true;
else
verbose = ~strcmpi(verbose ,'off');
end
As for Python, as I mentioned in my other answer to you, Python requires all returned values be handled. It will never throw away returned values unless you explicitly tell it to. In your case, the simplest solution is just to have return kf, Ek at the end of the function. If someone wants both kf and Ek, they can do:
kf, Ek = hysime(y, n, Rn)
If they only want kf, they can do (where _ is the python convention for a variable you don't care about):
kf, _ = hysime(y, n, Rn)
Or:
kf = hysime(y, n, Rn)[0]
So the python code would be:
def hysime(y, n, Rn, verbose=True):
# rest of the function here
return kf, Ek
If you really want to be able to have one or two returned values, you would need to have another argument to change the behavior. Such as:
def hysime(y, n, Rn, verbose=True, ret_eK=False):
# rest of the function here
return (kf, Ek) if ret_eK else kf
So in this case if the ret_eK argument is specified and set to True, then kf, Ek is returned, otherwise just kf is returned. But in Python you really don't want to do this unless there is some major additional cost to calculating Ek, which doesn't appear to be in this case.

Default Parameters in Function Definition, Syntax problems.

I am having an issue finding a straightforward answer to a question that I have.
I am coding a program that has some default values for certain parameters that do not end up being called by the user. My program is somewhat complicated so I decided to try a simplified problem.
def mult(x = 1, y = 2, z = 3):
ans = x * y * z
print(ans)
mult()
In this quick program, the function call would result in 6. Which makes sense because it goes to the default values I provided. My question is, how can I call this function if, for example, I wanted to define y and not any other variable? What would be the correct syntax in that situation.
My intuition was to call mult(x, 5, z) to indicate default values for x and z but a new value for y. I know that does not work and would like to know what the correct syntax would be.
You can specify the parameter to supply by using = at the call site:
mult(y = 5)
you can call it with keywords
mult(y=7)
mult(z=55)
mult(z=12,y=16,x=5)
mult(x=15)
although as an aside its probably preferable to return ans instead of just printing it ...

Function integration returns “only length-1 arrays can be converted to Python scalars”

I'm trying to integrate a function into a given range that shows the flow of particles in a zero-angle (theta) direction as a function of the energy E of the particles. I've tried several ways and got different errors but there are two that persist at the end. My knowledge of Python is limited, I try to learn new ways of doing stuff as I need them but I've been around this function for days with no success.
My function at the moment looks like this:
from numpy import radians, cos, arange
from scipy.integrate import quad
def integral(self):
theta=0
E = arange(1, 5000, 1)
costh = cos(radians(theta))
a = 18 / (E * costh + 145)
b = (E + 2.7 / costh)**-2.7
c = (E + 5) / (E + 5 / costh)
return a*b*c*1**4
A = quad(integral, 500, 1000)
Applying "quad" to the function like this returns:
TypeError: only length-1 arrays can be converted to Python scalars
If I don't put "self" as argument in the funtion, it returns:
TypeError: integral() takes 0 positional arguments but 1 was given
Has someone an idea on how to bypass this?
integral must have one of the signatures described in the scipy documentation. In your case, a function taking a double as argument and returning a double seems appropriate.
self is only used for member functions of a class. It does not make sense outside a class definition. Replace that with a simple name, say x that will be the input argument of the function to integrate.
The function must return a double. Since E is an array and you seem to make calculations with it, then the computed return value is likely to be an array too. It must be a scalar. Fix that and it will work. When you replace your function with something like:
def integral(x):
return x * x
then it works. This is not what you need, of course, but this is the kind of arguments and return values that are required for quad() to work.
You may want to look here for an example on how quad() is being used.
Some recommendations:
use four spaces for indentation (not 5 as in the example)
parentheses around the result are not required. Remove for more clarity.

How to multiply without the * sign using recursion?

so as homework for a programming class on python we're supposed to multiply to integers (n,m) with each other WITHOUT using the * sign (or another multiplication form). We're supposed to use recursion to solve this problem, so i tried just adding n with itself, m number of times. I think my problem is with using recursion itself. I have searched on the internet for recursion usage, no results. Here is my code. Could someone point me in the right direction?
def mult(n,m):
""" mult outputs the product of two integers n and m
input: any numbers
"""
if m > 0:
return n + n
return m - 1
else:
return 1
I don't want to give you the answer to your homework here so instead hopefully I can provide an example of recursion that may help you along :-).
# Here we define a normal function in python
def count_down(val):
# Next we do some logic, in this case print the value
print(val)
# Now we check for some kind of "exit" condition. In our
# case we want the value to be greater than 1. If our value
# is less than one we do nothing, otherwise we call ourself
# with a new, different value.
if val > 1:
count_down(val-1)
count_down(5)
How can you apply this to what you're currently working on? Maybe, instead of printing something you could have it return something instead...
Thanks guys, i figured it out!!!
i had to return 0 instead of 1, otherwise the answer would always be one higher than what we wanted.
and i understand how you have to call upon the function, which is the main thing i missed.
Here's what i did:
def mult(n,m):
""" mult outputs the product of two integers n and m
input: any numbers
"""
if m == 0:
return 0
else:
return n + mult(n, m - 1)
You have the right mechanics, but you haven't internalized the basics you found in your searches. A recursive function usually breaks down to two cases:
Base Case --
How do you know when you're done? What do you want to do at that point?
Here, you've figured out that your base case is when the multiplier is 0. What do you want to return at this point? Remember, you're doing this as an additive process: I believe you want the additive identity element 0, not the multiplicative 1.
Recursion Case --
Do something trivial to simplify the problem, then recur with this simplified version.
Here, you've figured out that you want to enhance the running sum and reduce the multiplier by 1. However, you haven't called your function again. You haven't properly enhanced any sort of accumulative sum; you've doubled the multiplicand. Also, you're getting confused about recursion: return is to go back to whatever called this function. For recursion, you'll want something like
mult(n, m-1)
Now remember that this is a function: it returns a value. Now, what do you need to do with this value? For instance, if you're trying to compute 4*3, the statement above will give you the value of 4*2, What do you do with that, so that you can return the correct value of 4*3 to whatever called this instance? You'll want something like
result = mult(n, m-1)
return [...] result
... where you have to fill in that [...] spot. If you want, you can combine these into a single line of code; I'm just trying to make it easier for you.

Categories

Resources