Mathematical expression as argument to function? - python

I'm very much a beginner, so please be gentle.
I am tinkering with some Python exercises, and I have code looking like this.
def newton(x0, Tol):
def F(x):
return (x**3)+898
def dF(x):
return 3*x**2
x=[x0]
for n in range(400):
x.append(x[n]-(F(x[n]))/dF(x[n]))
if abs((x[n+1])-(x[n]))<Tol:
conv='Converge'
print n
break
if abs((x[n+1])-(x[n]))>=Tol:
conv='No converge'
return x[n+1], conv
I define a function F(x) and its derivative dF(x) and add values to a list x.
The task is to check if the series converge or not, which I think I have succeeded with.
But the question I have is regarding having the functions (x**3)+898 and 3*x**2 as arguments to the function Newton.
I imagined it would be something like this
def newton(f, df, x0, Tol):
def F(x):
return f
def dF(x):
return df
*calculations*
return x[n+1], conv
And you would call it with
newton((x**3)+898, 3*x**2, x0=something, Tol=something)
So that the functions F(x) and dF(x) are defined in the process.
However, x is not defined so it does not work.
Note that having f and df as parameters of 'newton' is required in the excercise.
How would you go about solving this?
Thanks.

You can use lambdas, which are basically simple functions.
You would call it like this:
newton(lambda x: (x**3)+898, lambda x: 3*x**2, x0=something, Tol=something)
This would be the same as doing something like this:
def f1(x):
return (x**3)+898
def f2(x):
return 3*x**2
newton(f1, f2, x0=something, Tol=something)
The only difference is that you don't "give the lambda a name", ie assign it to a variable. This is handy for functions you only need to use once, especially as key arguments to functions like sorted and max.

Use lambda:
newton(lambda x: (x**3)+898, lambda x: 3*x**2, x0=something, Tol=something)

Related

How can I call a lambda without defining it as a function?

For lambda functions in the following code,
def myfunc(n):
return lambda a : a * n
mydoubler = myfunc(2)
print(mydoubler(11))
I am trying to understand why mydoubler becomes <class 'function'> and how I can call mydoubler(11) without defining it as a function.
A lambda is a function, but with only one expression (line of code).
That expression is executed when the function is called, and the result is returned.
So the equivalent of this lambda:
double = lambda x: x * 2
is this def function:
def double(x):
return x * 2
You can read more here
A lambda is a function, so your code is doing something like
def myfunc(n):
def result(a):
return a * n
return result # returns a function
mydoubler = myfunc(2)
print(f(11))
You're asking how to call mydoubler without defining it as a function, which isn't the clearest question, but you can call it without naming it like so
print( myfunc(2)(11) )
Your myfunc is returning a lambda. Lambda is a small anonymous function. A lambda can take any number of arguments, but can only have one expression.
So after execution of the 3rd line, your mydoubler will become a lambda that's why when you try print(type(mydoubler)) it will return <class 'function'>.
Also in order to call mydoubler with 11, it must be function.
A lambda expression, like a def statement, defines functions. Your code could be equivalently written as
def myfunc(n):
def _(a):
return a * n
return _
mydoubler = myfunc(2)
print(mydoubler(11))
Because the inner function is simple enough to be defined as a single expression, using a lambda expression saves you the trouble of coming up with the otherwise unused name the def statement requires.
The key here is that the inner function closes over the value of n, so that the function returned by myfunc retains a reference to the value of the argument passed to myfunc. That is, mydoubler is hard-coded to multiply its argument by 2, rather than whatever value n may get later. (Indeed, the purpose of the closure is to create a new variable n used by the inner function, one which cannot easily be changed from outside myfunc.)
using decorator you can achive this
from functools import wraps
def decorator_func_with_args(arg1):
def decorator(f):
#wraps(f)
def wrapper(val):
result = f(val)
return result(arg1)
return wrapper
return decorator
#decorator_func_with_args(arg1=2)
def myfunc(n):
return lambda arg:arg*n
result = myfunc(1211)
print(result)
output
2422
Do you mean this?
mydoubler = lambda a : a * 2
mydoubler(11)

How to update pure function?

I'm trying to do the following: I want to write a function translate(f, c) that takes a given function f (say we know f is a function of a single variable x) and a constant c and returns a new function that computes f(x+c).
I know that in Python functions are first-class objects and that I can pass f as an argument, but I can't think of a way to do this without passing x too, which kind of defeats the purpose.
The trick is for translate to return a function instance.
def translate(f, c):
def func(x):
return f(x + c)
return func
Now the variable x is "free", and the names f and c are coming from an enclosing scope.
What about this?
def translate_func(f, c):
return lambda x: f(x + c)
To be used like, e.g.:
import math
g = translate_func(math.sin, 10)
print(g(1) == math.sin(10 + 1))
# True
EDIT
Note that this design pattern of a function taking a function as a parameter and returning another function is quite common in Python and goes by the name of "function decoration", with an associated convenience syntax. See PEP318 for more info on it.
def transalte(f, c):
def _inner(x):
return f(x+c)
return _inner

Python find root for non-zero level

Say I have the following code
def myfunc(x):
return monsterMathExpressionOf(x)
and I would like to find numerically the solution of myfunc(x) == y for diverse values of y. If y == 0 then there are a lot of root finding procedures available, e.g. from scipy. However, if I'd like to find the solution for e.g. y==1 it seems I have to define a new function
def myfunc1(x):
return myfunc(x) - 1
and then find it's root using available procedures. This way does not work for me as I will need to find a lot of solution by running a loop, and I don't want to redefine the function in each step of the loop. Is there a neater solution?
You don't have to redefine a function for every value of y: just define a single function of y that returns a function of x, and use that function inside your loop:
def wrapper(y):
def myfunc(x):
return monsterMathExpressionOf(x) - y
return myfunc
for y in y_values:
f = wrapper(y)
find_root(f, starting_point, ...)
You can also use functools.partial, which may be more to your liking:
def f(x, y):
return monsterMathExpressionOf(x) - y
for y in y_values:
g = partial(f, y=y)
find_root(g, starting_point, ...)
Read the documentation to see how partial is roughly implemented behind the scenes; you'll see it may not be too different compared to the first wrapper implementation.
#Evert's answer shows how you can do this by using either a closure or by using functools.partial, which are both fine solutions.
Another alternative is provided by many numerical solvers. Consider, for example, scipy.optimize.fsolve. That function provides the args argument, which allows you to pass additional fixed arguments to the function to be solved.
For example, suppose myfunc is x**3 + x
def myfunc(x):
return x**3 + x
Define one additional function that includes the parameter y as an argument:
def myfunc2(x, y):
return myfunc(x) - y
To solve, say, myfunc(x) = 3, you can do this:
from scipy.optimize import fsolve
x0 = 1.0 # Initial guess
sol = fsolve(myfunc2, x0, args=(3,))
Instead of defining myfunc2, you could use an anonymous function as the first argument of fsolve:
sol = fsolve(lambda x, y: myfunc(x) - y, x0, args=(3,))
But then you could accomplish the same thing using
sol = fsolve(lambda x: myfunc(x) - 3, x0)

Return function with function

I would like to do something like the following:
def getFunction(params):
f= lambda x:
do stuff with params and x
return f
I get invalid syntax on this. What is the Pythonic/correct way to do it?
This way I can call f(x) without having to call f(x,params) which is a little more messy IMO.
A lambda expression is a very limited way of creating a function, you can't have multiple lines/expressions (per the tutorial, "They are syntactically restricted to a single expression"). However, you can nest standard function definitions:
def getFunction(params):
def to_return(x):
# do stuff with params and x
return to_return
Functions are first-class objects in Python, so once defined you can pass to_return around exactly as you can with a function created using lambda, and either way they get access to the "closure" variables (see e.g. Why aren't python nested functions called closures?).
It looks like what you're actually trying to do is partial function application, for which functools provides a solution. For example, if you have a function multiply():
def multiply(a, b):
return a * b
... then you can create a double() function1 with one of the arguments pre-filled like this:
from functools import partial
double = partial(multiply, 2)
... which works as expected:
>>> double(7)
14
1 Technically a partial object, not a function, but it behaves in the same way.
You can't have a multiline lambda expression in Python, but you can return a lambda or a full function:
def get_function1(x):
f = lambda y: x + y
return f
def get_function2(x):
def f(y):
return x + y
return f

Python: A better way to write n compositions of a function?

I wrote a function "rep" that takes a function f and takes n compositions of f.
So rep(square,3) behaves like this: square(square(square(x))).
And when I pass 3 into it, rep(square,3)(3)=6561.
There is no problem with my code, but I was wondering if there was a way to make it "prettier" (or shorter) without having to call another function or import anything. Thanks!
def compose1(f, g):
"""Return a function h, such that h(x) = f(g(x))."""
def h(x):
return f(g(x))
return h
def rep(f,n):
newfunc = f
count=1
while count < n:
newfunc = compose1(f,newfunc)
count+=1
return newfunc
If you're looking for speed, the for loop is clearly the way to go. But if you're looking for theoretical academic acceptance ;-), stick to terse functional idioms. Like:
def rep(f, n):
return f if n == 1 else lambda x: f(rep(f, n-1)(x))
def rep(f, n):
def repeated(x):
for i in xrange(n):
x = f(x)
return x
return repeated
Using a for loop instead of while is shorter and more readable, and compose1 doesn't really need to be a separate function.
While I agree that repeated composition of the same function is best done with a loop, you could use *args to compose an arbitrary number of functions:
def identity(x):
return x
def compose(*funcs):
if funcs:
rest = compose(*funcs[1:])
return lambda x: funcs[0](rest(x))
else:
return identity
And in this case you would have:
def rep(f,n):
funcs = (f,)*n # tuple with f repeated n times
return compose(*funcs)
And as DSM kindly pointed out in the comments, you could remove the recursion like so:
def compose(*funcs):
if not funcs:
return identity
else:
def composed(x):
for f in reversed(funcs):
x = f(x)
return x
return composed
(also note that you can replace x with *args if you also want to support arbitrary arguments to the functions you're composing, but I left it at one argument since that's how you have it in the original problem)
Maybe someone will find this solution useful
Compose number of functions
from functools import reduce
def compose(*functions):
return reduce(lambda x, y: (lambda arg: x(y(arg))), functions)
Use list comprehensions to generate list of functions
def multi(how_many, func):
return compose(*[func for num in range(how_many)])
Usage
def square(x):
return x * x
multi(3, square)(3) == 6561

Categories