How to pass parameters to objective function when using minimize_scalar? - python

As explained here, to use scipy.optimize.minimize_scalar we need to define the objective function such as:
def f(x):
return (x - 2) * x * (x + 2)**2
Then, we will optimize it by:
from scipy.optimize import minimize_scalar
res = minimize_scalar(f)
Now, I want to define my function with a variable to optimize and several parameters. For example, some thing like:
def f(x, a, b):
return (x - a) * x * (x + a)**a + b
res = minimize_scalar(f(x, 2, 3))
How can I define the function and use it like that?
Please note that because a and b can be different each time, I cannot define them within the function definition.

Use the args argument:
args : tuple, optional
Extra arguments passed to the objective function.
The correct syntax looks like this:
res = minimize_scalar(f, args=(2, 3))

Related

Python - how do I memoize a partial object?

I have a set of functions that take integers and functions as arguments. I'd like to memoize them.
I know that using this solution, I could use pickle to encode both sets of arguments and memoize the encoded values. In this particular use case, however, the function arguments are large and constant, and I'd rather not take up the lru_cache space with a function argument that, in the course of a program run, never changes.
Is there a way for me to memoize a partial function, where I've fixed the function arguments and have received a partial object that takes only hashable arguments? I can't figure out how to use the functools.lru_cache decorator as a function.
Here's what I've tried on a toy example. It doesn't work; the binomial tree still revisits nodes.
import functools
import logging
logging.basicConfig(level=logging.DEBUG)
def binomial_tree(x, y, fn):
logging.debug(f"binomial_tree({x}, {y})")
"""Note: this does not recombine, and we can't memoize function."""
if x == 10:
return fn(x, y)
else:
return 0.5 * binomial_tree(x + 1, y, fn) + 0.5 * binomial_tree(x + 1, y + 1, fn)
def memoize_fn(fn):
#functools.lru_cache(maxsize=None)
def inner(*args, **kwargs):
return fn(*args, **kwargs)
return inner
memoized_binomial_tree = memoize_fn(functools.partial(binomial_tree, fn=lambda x, y: 10 * x * y))
print(memoized_binomial_tree(0, 0))
Here is a way to memoize your toy example with binomial_tree without encoding and memoizing function arguments:
import functools
import logging
logging.basicConfig(level=logging.DEBUG)
def create_binomial_tree(fn):
#functools.lru_cache(maxsize=None)
def binomial_tree(x, y):
logging.debug(f"binomial_tree({x}, {y})")
if x == 10:
return fn(x, y)
else:
return 0.5 * binomial_tree(x + 1, y) + 0.5 * binomial_tree(x + 1, y + 1)
return binomial_tree
memoized_binomial_tree = create_binomial_tree(fn=lambda x, y: 10 * x * y)
print(memoized_binomial_tree(0, 0))
Maybe it can be applicable in your real use case?

Substitute Function call with sympy

I want to receive input from a user, parse it, then perform some substitutions on the resulting expression. I know that I can use sympy.parsing.sympy_parser.parse_expr to parse arbitrary input from the user. However, I am having trouble substituting in function definitions. Is it possible to make subsitutions in this manner, and if so, how would I do so?
The overall goal is to allow a user to provide a function of x, which is then used to fit data. parse_expr gets me 95% of the way there, but I would like to provide some convenient expansions, such as shown below.
import sympy
from sympy.parsing.sympy_parser import parse_expr
x,height,mean,sigma = sympy.symbols('x height mean sigma')
gaus = height*sympy.exp(-((x-mean)/sigma)**2 / 2)
expr = parse_expr('gaus(100, 5, 0.2) + 5')
print expr.subs('gaus',gaus) # prints 'gaus(100, 5, 0.2) + 5'
print expr.subs(sympy.Symbol('gaus'),gaus) # prints 'gaus(100, 5, 0.2) + 5'
print expr.subs(sympy.Symbol('gaus')(height,mean,sigma),gaus) # prints 'gaus(100, 5, 0.2) + 5'
# Desired output: '100 * exp(-((x-5)/0.2)**2 / 2) + 5'
This is done using python 2.7.9, sympy 0.7.5.
You can use the replace method. For instance
gaus = Function("gaus") # gaus is parsed as a Function
expr.replace(gaus, Lambda((height, mean, sigma), height*sympy.exp(-((x-mean)/sigma)**2 / 2)))
replace also has other options, such as pattern matching.
After some experimentation, while I did not find a built-in solution, it was not difficult to build one that satisfies simple cases. I am not a sympy expert, and so there may be edge cases that I haven't considered.
import sympy
from sympy.core.function import AppliedUndef
def func_sub_single(expr, func_def, func_body):
"""
Given an expression and a function definition,
find/expand an instance of that function.
Ex:
linear, m, x, b = sympy.symbols('linear m x b')
func_sub_single(linear(2, 1), linear(m, b), m*x+b) # returns 2*x+1
"""
# Find the expression to be replaced, return if not there
for unknown_func in expr.atoms(AppliedUndef):
if unknown_func.func == func_def.func:
replacing_func = unknown_func
break
else:
return expr
# Map of argument name to argument passed in
arg_sub = {from_arg:to_arg for from_arg,to_arg in
zip(func_def.args, replacing_func.args)}
# The function body, now with the arguments included
func_body_subst = func_body.subs(arg_sub)
# Finally, replace the function call in the original expression.
return expr.subs(replacing_func, func_body_subst)
def func_sub(expr, func_def, func_body):
"""
Given an expression and a function definition,
find/expand all instances of that function.
Ex:
linear, m, x, b = sympy.symbols('linear m x b')
func_sub(linear(linear(2,1), linear(3,4)),
linear(m, b), m*x+b) # returns x*(2*x+1) + 3*x + 4
"""
if any(func_def.func==body_func.func for body_func in func_body.atoms(AppliedUndef)):
raise ValueError('Function may not be recursively defined')
while True:
prev = expr
expr = func_sub_single(expr, func_def, func_body)
if prev == expr:
return expr

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)

Passing functions in python edited

from math import cos
def diff1(f, x): #approximates first derivative#
h = 10**(-10)
return (f(x+h) - f(x))/h
def newtonFunction(f,x):
return x - f(x)/float(diff1(f,x))
y = cos
x0 = 3
epsilon = .001
print diff1(newtonFunction(y,x0), x0)
This is just a portion of the code, but I want to calculate diff1(f,x) where f is newtonFunction but uses the argument f passed to NewtonMinimum. diff1 already takes f and x as an argument and I get an error saying it expects two arguments for newtonFunction.
I think what you're looking for is functools.partial.
The problem is that f is not newtonFunction, rather it's the value returned by newtonFunction(y,x0). In this example that's a floating point number, hence the 'float' object not callable.
If you want to pass a function as a parameter to another function, you need to use just its name:
diff1(newtonFunction, x0)
Note also that you will then have another problem: in diff1 you're calling f with only one parameter, but newtonFunction takes two parameters.
In diff1, you are missing a * in f(x+h) and f(x) and in newtonFunction. You are also leaving y as a built-in function, so I assumed you wanted the cos of x0. Here is your edited code:
from math import cos
def diff1(f, x): #approximates first derivative#
h = 10**(-10)
return (f*(x+h) - f*(x))/h
def newtonFunction(f,x):
return x - f*(x)/float(diff1(f,x))
y = cos
x0 = 3
epsilon = .001
print diff1(newtonFunction(y(x0),x0), x0)

Python: How to create a function? e.g. f(x) = ax^2

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

Categories