application of minimize_scalar - scipy

I am trying to replicate the results posted here (How to use scipy.optimize minimize_scalar when objective function has multiple arguments?) using a different structure. The goal is exactly the same but I just want to code it in a different way. Here is my code:
def mini(g,a,b,args):
object=lambda w1: g(w1, *args)
result=minimize_scalar(object, bounds=(a, b))
minzer, minval=result.x, result.fun
return minzer,minval
def errorr(w0,w1,x,y):
y_pred = w0 + w1*x
mse = ((y-y_pred)**2).mean()
return mse
x = np.array([1,2,3])
y = np.array([52,54,56])
w0=50
mini(errorr, -5, 5, (w0,x,y))
However, the results obtained using my code is quite different from the one in the original posts. I am wondering where did I make the mistake in my code that caused the different results. Thanks!

Since you use lambda w1: g(w1, *args), you are minimizing with respect to the first function argument w0. To minimize with respect to w1, you can write lambda w1: g(args[0], w1, *args[1:]) instead.
However, please avoid python keywords as variable names (e.g. object). In addition, a lambda function is an anonymous function, so assigning it to a variable contradicts its purpose. Consequently, I'd propose either
def mini(g,a,b,args):
def obj_fun(w1): return g(args[0], w1, *args[1:])
result = minimize_scalar(obj_fun, bounds=(a, b))
return result.x, result.fun
or
def mini(g,a,b,args):
result = minimize_scalar(lambda w1: g(args[0], w1, *args[1:]), bounds=(a, b))
return result.x, result.fun

Related

Numba cache and iterative solving

I am trying to use NumbaLSODA, see here, to solve many systems iteratively.
However, it seems that I can't put the function in the numba cache and so I have a big overhead at each iteration.
I was wondering if anybody could help.
This is my code.
First I put all numba related function inside a file
numba_func.py
NOPYTHON = True
CACHE = True
PARALLEL = True
#nb.cfunc(lsoda_sig, nopython=NOPYTHON, cache=CACHE)
def rhs(x, i, di, p):
di[0] = ...
di[1] = ...
di[2] = ...
funcptr = rhs.address
#nb.njit('(float64)(float64, float64, float64, int16)', nopython=NOPYTHON, parallel=PARALLEL, cache=CACHE)
def solve(a, b, c, funcptr):
w0 = np.array([a, b, ...], dtype=np.float64)
p = np.array([c], dtype=np.float64)
x = np.linspace(0, 100, 500)
usol, success = lsoda(funcptr, w0, x, data=p)
return usol[-1][1]
Then I use another file to solve the systems one after the others
from numba_func import solve, funcptr
gs = []
for a, b, c in zip(as, bs, cs):
gs = np.append(gs, solve(a, b, c, funcptr))
I got the following warning:
NumbaWarning: Cannot cache compiled function "solve" as it uses dynamic globals (such as ctypes pointers and large global arrays)
I guess the idea is to pass the variable funcptr correctly so that numba is happy but so far I failed...

Can Julia macros be used to generate code based on specific function implementation?

I am fairly new to Julia and I am learning about metaprogramming.
I would like to write a macro that receive in input a function and returns another function based on the implementation details of its input.
For example given:
function f(x)
x + 100
end
function g(x)
f(x)*x
end
function h(x)
g(x)-0.5*f(x)
end
I would like to write a macro that returns something like that:
function h_traced(x)
f = x + 100
println("loc 1 x: ", x)
g = f * x
println("loc 2 x: ", x)
res = g - 0.5 * f
println("loc 3 x: ", x)
Now both code_lowered and code_typed seems to give me back the AST in the form of CodeInfo, however when I try to use it programmatically in my macro I get empty object.
macro myExpand(f)
body = code_lowered(f)
println("myExpand Body lenght: ",length(body))
end
called like this
#myExpand :(h)
however the same call outside the macro works ok.
code_lowered(h)
At last even the following return an empty CodeInfo.
macro myExpand(f)
body = code_lowered(Symbol("h"))
println("myExpand Body lenght: ",length(body))
end
This might be incredible trivial but I could not work out myseld why the h symbol does not resolve to the function defined. Am I missing something about the scope of symbols?
I find it useful to think about macros as a way to transform an input syntax into an output syntax.
So you could very well define a macro #my_macro such that
#my_macro function h(x)
g(x)-0.5*f(x)
end
would expand to something like
function h_traced(x)
println("entering function: x=", x)
g(x)-0.5*f(x)
end
But to such a macro, h is merely a name, an identifier (technically, a Symbol) that can be transformed into h_traced. h is not the function that is bound to this name (in the same way as x = 2 involves binding a name x, to an integer value 2, but x is not 2; x is merely a name that can be used to refer to 2). In contrast to this, when you call code_lowered(h), h gets evaluated first, and code_lowered is passed its value (which is a function) as argument.
Back to our macro: expanding to an expression that involves the definition of g and f goes way further than mere syntax transformations: we're leaving the purely syntactic domain, since such a transformation would need to "understand" that these are functions, look up their definitions and so on.
You are right to think about code_lowered and friends: this is IMO the adequate level of abstraction for what you're trying to achieve. You should probably look into tools like Cassette.jl or IRTools.jl. That being said, if you're still relatively new to Julia, you might want to get a bit more used to the language before delving too deeply into such topics.
You don't need a macro, you need a generated function. They can not only return code (Expr), but also IR (lowered code). Usually, for this kind of thing, people use Base.uncompressed_ast, not code_lowered. Both Cassette and IRTools simplify the implementation for you, in different ways.
The basic idea is:
Have a generated function that takes a function and its arguments
In that function, get the IR of that function, and modify it to your purposes
Return the new IR from the generated function. This will then be compiled and called on the original arguments.
A short demonstration with IRTools:
julia> IRTools.#dynamo function traced(args...)
ir = IRTools.IR(args...)
p = IRTools.Pipe(ir)
for (v, stmt) in p
IRTools.insertafter!(p, v, IRTools.xcall(println, "loc $v"))
end
return IRTools.finish(p)
end
julia> function h(x)
sin(x)-0.5*cos(x)
end
h (generic function with 1 method)
julia> #code_ir traced(h, 1)
1: (%1, %2)
%3 = Base.getfield(%2, 1)
%4 = Base.getfield(%2, 2)
%5 = Main.sin(%4)
%6 = (println)("loc %3")
%7 = Main.cos(%4)
%8 = (println)("loc %4")
%9 = 0.5 * %7
%10 = (println)("loc %5")
%11 = %5 - %9
%12 = (println)("loc %6")
return %11
julia> traced(h, 1)
loc %3
loc %4
loc %5
loc %6
0.5713198318738266
The rest is left as an exercise. The numbers of the variables are off, because they are, of course, shifted during the transformation. You'd have to add some bookkeeping for that, or use the substitute function on Pipe in some way (but I never quite understood it). If you need the name of the variables, you can get the IR with slots preserved by using a different method of the IR constructor.
(And now the advertisement: I have written something like this. It's currently quite inefficient, but you might get some ideas from it.)

sympy derivative with boolean

I am trying to take the derivative of a function including a boolean variable with sympy.
My expected result:
Two different derivatives, depending on the boolean being either True or False (i.e. 1 or 0).
Example:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
bo = sy.Function("bo")
fct1 = sy.Function("fct1")
fct2 = sy.Function("fct2")
FOC2 = sy.Function("FOC2")
y = 5
a = 2
b = 4
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
# the following gives the smaller positive intercept with the x-axis)
# this intercept is the threshold value for the boolean function, bo
min(sy.solve(fct1(x)-y, x))
def bo(x):
if fct1(x) <= y:
return 1
else:
return 0
def fct2(c, x):
return a + b*c + bo(x)*c
def FOC2(c, x):
return sy.diff(fct2(c, x), c)
print(FOC2(c, x))
The min-function after the comments shows me the threshold of x for bo being True or False would be 4.29..., thus positive and real.
Output:
TypeError: cannot determine truth value of Relation
I understand that the truth value depends on x, which is a symbol. Thus, without knowing x one cannot determine bo.
But how would I get my expected result, where bo is symbolic?
First off, I would advise you to carefully consider what is going on in your code the way it is pasted above. You first define a few sympy functions, e.g.
fct1 = sy.Function("fct1")
So after this, fct1 is an undefined sympy.Function - undefined in the sense that it is neither specified what its arguments are, nor what the function looks like.
However, then you define same-named functions explicitly, as in
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
Note however, that at this point, fct1 ceases to be a sympy.Function, or any sympy object for that matter: you overwrite the old definition, and it is now just a regular python function!
This is also the reason that you get the error: when you call bo(x), python tries to evaluate
-0.004*x**2 + 0.25*x + 4 <= 5
and return a value according to your definition of bo(). But python does not know whether the above is true (or how to make that comparison), so it complains.
I would suggest 2 changes:
Instead of python functions, as in the code, you could simply use sympy expressions, e.g.
fct1 = -0.004*x**2 + 0.25*x + 4
To get the truth value of your condition, I would suggest to use the Heaviside function (wiki), which evaluates to 0 for a negative argument, and to 1 for positive. Its implementation in sympy is sympy.Heaviside.
Your code could then look as follows:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
y = 5
a = 2
b = 4
fct1 = -0.004*x**2 + 0.25*x + 4
bo = sy.Heaviside(y - fct1)
fct2 = a + b*c + bo * c
FOC2 = sy.diff(fct2, c)
print(FOC2)
Two comments on the line
bo = sy.Heaviside(y - fct1)
(1) The current implementation does not evaluate sympy.Heaviside(0)by default; this is beacause there's differing definitions around (some define it to be 1, others 1/2). You'd want it to be 1, to be in accordance with the (weak) inequality in the OP. In sympy 1.1, this can be achieved by passing an additional argument to Heaviside, namely whatever you want Heaviside(0) to evaluate to:
bo = sy.Heaviside(y - fct1, 1)
This is not supported in older versions of sympy.
(2) You will get your FOC2, again involving a Heaviside term. What I like about this, is that you could keep working with this expression, say if you wanted to take a second derivative and so on. If, for the sake of readability, you would prefer a piecewise expression - no problem. Just replace the according line with
bo = sy.Heaviside(y - fct1)._eval_rewrite_as_Piecewise(y-fct1)
Which will translate to a piecewise function automatically. (note that under older versions, this automatically implicitly uses Heaviside(0) = 0.5 - best to use (1) and (2) together:
bo = sy.Heaviside(y - fct1, 1)._eval_rewrite_as_Piecewise(y-fct1)
Unfortunately, I don't have a working sympy 1.1 at my hands right now and can only test the old code.
One more noteconcerning sympy's piecewise functions: they are much more readable if using sympy's latex printing, by inserting
sy.init_printing()
early in the code.
(Disclaimer: I am by no means an expert in sympy, and there might be other, preferable solutions out there. Just trying to make a suggestion!)

How does rowfun know to reference variables inside a table

From the documentation, we see the following example:
g = gallery('integerdata',3,[15,1],1);
x = gallery('uniformdata',[15,1],9);
y = gallery('uniformdata',[15,1],2);
A = table(g,x,y)
func = #(x, y) (x - y);
B = rowfun(func,A,...
'GroupingVariable','g',...
'OutputVariableName','MeanDiff')
When the function func is applied to A in rowfun how does it know that there are variables in A called x and y?
EDIT: I feel that my last statement must not be true, as you do not get the same result if you did A = table(g, y, x).
I am still very confused by how rowfun can use a function that does not actually use any variables defined within the calling environment.
Unless you specify the rows (and their order) with the Name/Value argument InputVariables, Matlab will simply take column 1 as first input, column 2 as second input etc, ignoring eventual grouping columns.
Consequently, for better readability and maintainability of your code, I consider it good practice to always specify InputVariables explicitly.

scipy.optimize.leastsq : How to specify non-parameters?

I want to know how to use leastsq from scipy for chi-square fitting. I know the structure is basically -
parameters = leastsq(chi(exp_data, exp_err, param), initial_guess, arg = (?,?,?))
where exp_data, exp_err are arrays
def fitted_data(param):
fitted_data = a*param[0] + b*param[1]**2 + c*np.sin(param[3])
return fitted_data
def chi(exp_data, exp_err, param):
chi = (exp_data - fitted_data(param))/exp_err
return(chi)
What I don't understand is how to specify only param as the parameters to explore for chi square fitting. I don't understand how to use arg = (?,?,?), as I have multiple inputs for the function chi, not just parameters.
Thank you very much.
leastsq takes a function to be minimized. This function has to be dependent on the parameters of your fit, and may additionally be dependent on other parameters, that are considered constant for the minimization. These are provided via the args-argument as a tuple. The parameters are to be provided as the first argument, and all additional arguments may follow after.
Your function to be minimized therefor needs to look like this:
def residuals(params, args)
I adjusted your code to fit these requirements:
def fitted_data(params) :
fitted_data = a*params[0] + b*params[1]**2 + c*np.sin(params[3])
return fitted_data
def chi(params, exp_data, exp_err) :
chi = (exp_data - fitted_data(params)/exp_err
return chi
result = scipy.optimize.leastsq(chi, x0=(1, 1, 1), args=(exp_data, exp_err))