Jim,
Many thanks for your illuminating comments!
jimmo wrote: ↑Tue Apr 28, 2020 6:21 am
v923z wrote: ↑Tue Apr 28, 2020 5:35 am
I would like to ask, whether it is possible to call a function that was defined in python at the C level.
The simple answer is that yes this is done all over the place via mp_call_function_n_kw (and the wrappers e.g. mp_call_function_0).
Given an mp_obj_t that points to a function (i.e. a "callback" argument or something), you can just invoke it using mp_call_function_*.
But I don't think that's actually what you're asking?
Not exactly. I wanted to save the
mp_obt_t <-> mp_float_t conversion steps, so that I can make the iteration efficient.
v923z wrote: ↑Tue Apr 28, 2020 5:35 am
How could one take this to user-defined functions, like so:
jimmo wrote: ↑Tue Apr 28, 2020 6:21 am
Code: Select all
import ulab
from ulab import vector
def f(x):
return sin(x) + x*x
a = ulab.array([1, 2, 3, 4])
b = f(a)
In this case, if sin() was ulab.sin, and and __mul__ were provided by the array type, wouldn't this already work?
In this particular case, one could do as you suggest, that's true, but you still can't pass a parametrised function to fitting, or you might still want to pass a function object for root finding. That would mean that you have to either "disassemble" the function, or you have to take the compiled version of
f, and then call it for each value that comes up during the Newton iteration.
jimmo wrote: ↑Tue Apr 28, 2020 6:21 am
Did you mean something more like:
and then the map function would invoke f on each element?
Yes, mapping is probably a better term.
jimmo wrote: ↑Tue Apr 28, 2020 6:21 am
I guess the question is -- is the intention that f is called once with "a" and calls vector functions (I thought this would already work).
The crux of the matter is that in
Code: Select all
import ulab
from ulab import vector
def f(x):
return sin(x) + x*x
a = ulab.array([1, 2, 3, 4])
b = f(a)
the constituents of
f are called at the python level, so you don't have access to the values of
f in C. In other words,
f puts together the results of two functions (sin, and *) that both return to python. In a sense, what I need is a way of preventing
f from returning to the console, and supplying its results to another C function. Although, that might not be enough, because
f produces an ndarray (as do sin, and *), so that might be inefficient as far as RAM is concerned.
jimmo wrote: ↑Tue Apr 28, 2020 6:21 am
Or f is called once per item in "a" (somehow MicroPython figures out that calling a single-arg function on an array means we need to vectorise "f").
Barring my last comment, this is what I am aiming for. These two are perhaps two separate, but related issues. It would be great, if both could be solved.
jimmo wrote: ↑Tue Apr 28, 2020 6:21 am
Do you have a numpy example that shows the same thing?
In very general terms
https://docs.scipy.org/doc/numpy/refere ... orize.html is what I am after. But e.g., the newton iteration code is also similar:
https://docs.scipy.org/doc/scipy/refere ... ewton.html, as are any of the fitting routines:
https://docs.scipy.org/doc/scipy/refere ... e_fit.html
"Give me a function defined in python, and I will run efficient computations with it in C."
jimmo wrote: ↑Tue Apr 28, 2020 6:21 am
v923z wrote: ↑Tue Apr 28, 2020 5:35 am
I know that I could do something like this:
...
mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void *)user_function->bytecode);
MICROPY_MAKE_POINTER_CALLABLE makes a pointer to
machine code into a callable function. This will not work as bytecode cannot be natively executed.
Thanks for pointing that out! I would have been barking up the wrong tree.
v923z wrote: ↑Tue Apr 28, 2020 5:35 am
Is there a way to save the round trip to mp_obj_t?
jimmo wrote: ↑Tue Apr 28, 2020 6:21 am
But for many types, the conversion to mp_obj_t is a shift and a single bitwise op.
That's actually good, because then one can save the two function calls. That could already be OK. I have to be careful with the various representation, though, haven't I?