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)
Related
I'm trying to write a function that generates the restrictions of a function g at a given point p.
For example, let's say g(x, y, z) = 2x + 3y + z and p = (5, 10, 15). I'm trying to create a function that would return [lambda x : g(x, 10, 15), lambda y: g(5, y, 15), lambda z: g(5, 10, z)]. In other words, I want to take my multivariate function and return a list of univariate functions.
I wrote some Python to describe what I want, but I'm having trouble figuring out how to pass the right inputs from p into the lambda properly.
def restriction_generator(g, p):
restrictions = []
for i in range(len(p)):
restriction = lambda x : g(p[0], p[1], ..., p[i-1], p[x], p[i+1], .... p[-1])
restrictions.append(restriction)
return restrictions
Purpose: I wrote a short function to estimate the derivative of a univariate function, and I'm trying to extend it to compute the gradient of a multivariate function by computing the derivative of each restriction function in the list returned by restriction_generator.
Apologies if this question has been asked before. I couldn't find anything after some searching, but I'm having trouble articulating my problem without all of this extra context. Another title for this question would probably be more appropriate.
Since #bandicoot12 requested some more solutions, I will try to fix up your proposed code. I'm not familiar with the ... notation, but I think this slight change should work:
def restriction_generator(g, p):
restrictions = []
for i in range(len(p)):
restriction = lambda x : g(*p[: i], x, *p[i+1:])
restrictions.append(restriction)
return restrictions
Although I am not familiar with the ... notation, if I had to guess, your original code doesn't work because it probably always inputs p[0]. Maybe it can be fixed by changing it from p[0], p[1], ..., p[i-1] to p[0], ..., p[i-1].
try something like this:
def foo(fun, p, i):
def bar(x):
p[i] = x
return fun(*p)
return bar
and
def restriction_generator(g, p):
restrictions = []
for i in range(len(p)):
restrictions.append(foo(g, p, i))
return restrictions
I am writing a function that is going to take, as one of it's arguments, a dictionary of functions to apply. All of these functions will have at least one argument in common, but some will have others. Without losing the flexibility of letting the user specify arbitrary functions (conditional on having their arguments in scope), how can I introspect a function to see what its arguments are?
Here's a dummy example:
def f1(x, y):
return x+y
def f2(x):
return x**2
fundict = dict(f1 = f1,
f2 = f2)
y = 3 # this will always be defined in the same scope as fundict
for i in list(fundict.keys()):
if <the args to the function have y in them>:
fundict[i](x, y)
else:
fundict[i](x)
Even better would be something that programmatically looks at the definition of the function and feeds the array of arguments to it, conditional on them being in-scope.
I'd also appreciate good general suggestions for different ways to go about solving this problem, that might not involve introspecting a function.
You can use inspect.getfullargspec
import inspect
def f1(x, y):
return x+y
def f2(x):
return x**2
fundict = dict(f1 = f1,
f2 = f2)
y = 3 # this will always be defined in the same scope as fundict
x = 1
for i in list(fundict.keys()):
if 'y' in inspect.getfullargspec(fundict[i]).args:
print(fundict[i](x, y))
else:
print(fundict[i](x))
This gives:
4
1
You can use inspect.getfullargspec.
Example:
>>> for k, fun in fundict.items():
... print(fun.__name__, inspect.getfullargspec(fun)[0])
...
f1 ['x', 'y']
f2 ['x']
I read such a script:
add_numbers = lambda x, y: x+y
add_five = lambda y: add_numbers(5,y)
It derive a new function of one variable, add_five, that adds 5 to its argument:
from this point, introduced functools
In [9]: from functools import partial
In [10]: add_five = partial(add_numbers, 5)
In [11]: add_five(7)
Out[11]: 12
As a novice, I guess it can be easily achieved by
add_five = lambda y: 5+y
add_six = lambda y: 6+y
I am confused what's the benefit if not define add_five in a straighforward method?
The utility of partial is to easily create specialised versions of functions from a general definition.
The case of adding numbers can be illustrating here add_numbers is the general case.
from functools import partial
def add_numbers(x, y):
return x + y
add5 = partial(add_nums, 5)
Here add5 is a specialised case of add_numbers roughly equivalent to
def add5(x):
return add_numbers(x, 5)
Adding numbers is a very trivial example and does not show the utility of partial
The following is a simple example that may better show the utility of partial.
Consider writing a procedure to compute the square root of a number using the Babylonian method.
def square_root(x, tolerance, convergence_test):
y = 1
while not convergence_test(x, y, tolerance):
y = (y + x/y)/2
return y
For most numbers, the convergence test can simply check the difference between y squared and x is 0. Let's call this the absolute error of the estimate
def absolute_error(x, y, tolerance):
return abs(x - y**2) <= tolerance
For very large and small numbers, using absolute error of the estimate can lead to wrong answers for various reasons. In those cases, it is better to use the relative error:
def relative_error(x, y, tolerance):
return abs(x/(y**2) - 1) <= tolerance
With partial, we can easily create specialised functions for using the either absolute and relative error.
sqrt_rel_err = partial(square_root, convergence_test=relative_error)
sqrt_abs_err = partial(square_root, convergence_test=absolute_error)
Now using either is trivial
>>> sqrt_rel_err(2, 0.00001)
1.4142156862745097
>>> sqrt_abs_err(2, 0.00001)
1.4142156862745097
And for small numbers: we see using absolute error gives the wrong answer (especially when the tolerance is greater than the number we are trying to get the square root of)
>>> x = sqrt_abs_err(1e-6, 0.00001)
>>> x**2
4.4981362843183905e-06
Whilst the relative error method yields a more accurate answer.
>>> x = sqrt_rel_err(1e-6, 0.00001)
>>> x**2
1.0000003066033492e-06
I want to apply a function f to a data X, beign X a numpy array. The problem is that f is a sort of "linear combination" of functions, let's say f_i, and each of this functions depends also of another parameter, let's say:
param = 1.0 #same param for every f_i call.
def f(x):
for xi in range(len(x)):
cummulate sum of f_i(x, xi, param)
return the result of the loop, which depends of (x)
Any help with this? I tried sympy but the f_i are not trivial math function, but a combination of them.
You've got a few approaches here.
First and easiest is to pass in params as an argument, which could be an array of extra arguments for each function:
def f(x, params):
for i in len(x):
# Pass in params[i] to f_i
In the case that you need f to only accept one argument, you can do the second approach using a closure:
def f_creator(params):
def closure(x):
for i in len(x):
# Pass in params[i] to f_i
return closure
f = f_creator(... params for f_is go in here...)
# Use f for any special calculations that you need
Finally if these parameters are constant and don't change over the course of your program, you can set them to global constants. This approach isn't recommended because it makes it difficult to test things and makes the code less robust to change.
params = ....
def f(x):
for i in len(x):
# Calculate f_i using global params
I want to have some sort of reference to a function but I do not know if I need to use a def f(x) or a lambda of some kind.
For instance I'd like to print f(3) and have it output 9a, or is this not how python works?
Second question: Assuming I have a working function, how do I return the degree of it?
To create a function, you define it. Functions can do anything, but their primary use pattern is taking parameters and returning values. You have to decide how exactly it transforms parameters into the return value.
For instance, if you want f(x) to return a number, then a should also be a numeric variable defined globally or inside the function:
In [1]: def f(x):
...: a = 2.5
...: return a * x**2
...:
In [2]: f(3)
Out[2]: 22.5
Or maybe you want it to return a string like this:
In [3]: def f(x):
...: return str(x**2) + 'a'
...:
In [4]: f(3)
Out[4]: '9a'
You have to specify your needs if you need more help.
EDIT: As it turns out, you want to work with polynomials or algebraic functions as objects and do some algebraic stuff with them. Python will allow doing that, but not using standard data types. You can define a class for a polynomial and then define any methods or functions to get the highest power or anything else. But Polynomial is not a built-in data type. There may be some good libraries defining such classes, though.
Python (and most other computer languages) don't do algebra, which is what you'll need if you want symbolic output like this. But you could have a function f(a,x) which returns the result for particular (numerical) values of a:
def f(a, x):
return a*x*x
But if you want a program or language which actually does algebra for you, check out sympy or commercial programs like Mathematica.
If you are just working with polynomials, and you just need a data structure which deals well with them, check out numpy and its polynomial class.
I normally use lambda for short and simple functions:
f = lambda a, x: a * x**2
here a and x are parameters of my function. You need to enter a and x
f(2,4)
If you want a as a constant parameter eg. a=2:
f = lambda x: 2 * x**2
f(5)
if you have a list of input values of x, you can combine map with lambda.
it is straighforward and easily readable.
(*map(lambda x: 3 * x**2, [1,2,3,4]),)
or
list(map(lambda x: 3 * x**2, [1,2,3,4])
cheers!
def func():
print "F(x) = 2x + 3"
x = int(raw_input('Enter an integer value for x: '))
Fx = 2 * x + 3
return Fx
print func()
have fun :)
Cheese,
you can use the def function in Python to create a math function, you could type this:
def f(x):
return(2x + (3 + 3) * 11 + 88) # <- you could make your own function.
print(f(3))
Log:
220
Like THAT
or in this:
def f(a, x):
return((a + x) ** (a * x))
then...
print(f(1, 2))
Log...
6