0

I am new using function generators. I am working with the following function:

def math_model(n: float):
    def crrcn(x, t0: float, amp: float, tau: float, offset: float, dt: float, k: float):
        crrcn = np.zeros(np.shape(x))
        for i, a in enumerate(x):
            if a < (t0 + dt):
                crrcn[i] = offset
            else: 
                crrcn[i] = offset + k * amp * (math.exp(n) / (n ** n)) * ((a - (t0 + dt)) / tau) ** n * math.exp( - (a - (t0 + dt)) / tau) 
        return crrcn
    return crrcn

which defines a mathematical model I will use later to fit some data with scipy curve_fit. I wanted to use this same model to build a more complicated one with the following line.

model = partial(math_model(N), dt = 0, k = 1) + math_model(N)

which gives me:

TypeError: unsupported operand type(s) for +: 'functools.partial' and 'function'

From which I understand that I cannot build a function from two functions using this operator and as far as I know there are no function operands in python. How can one build a function from other functions without explicitly evaluating them?

smarie
  • 4,568
  • 24
  • 39
xikhari
  • 99
  • 3
  • 14

2 Answers2

2

PREVIOUS ANSWER:

This seems like a misunderstanding of partial.

partial(...) returns a new function. It does not execute it, it just creates it.

So your line model = partial(math_model(N), dt = 0, k = 1) + math_model(N) is invalid, because you are basically doing a a + b operation, where a is ... a function :)

What you may wish to do is simply applying the model. That can be done using math_model(N)(dt = 0, k = 1).

So

model = math_model(N)(dt = 0, k = 1) + math_model(N)

may do the trick

NEW EDIT: It seems that I misunderstood you. You actually wish to create a function by combining two functions. This is therefore some kind of symbolic reasoning. There are a few libraries out there for this, the most advanced that I know is SymPy. Or if your functions have only one argument, you can use my mini_lambda

For example with mini-lambda:

from mini_lambda import x

f1 = x ** 2
f2 = 5 * x
f3 = f1 + f2

print(f3.to_string())
print(f3.evaluate(1))

yields

x ** 2 + 5 * x
6
smarie
  • 4,568
  • 24
  • 39
  • Thanks for the clarifying. Currying does a nice job. The thing is that I actually need model to be a function object. As long as I use '+' python won't be happy considering that '+' does not supports function types. – xikhari Oct 22 '19 at 15:38
  • Thanks will give sympy a look. – xikhari Oct 22 '19 at 15:49
1

Given that the function depends on multiple variables mini_lambda was not an option.But with sympy it was nice and easy.

def math_model():
    a, o, t, t0, tau, dt, k = sympy.symbols('a, o, t, t0, tau, dt, k')
    semi = a * sympy.exp(-(t - t0)/ tau)
    reflex = k * a * sympy.exp(-(t -(t0 + dt))/ tau)
    double = sympy.Piecewise((o, t < t0),(o + semi, (t0 <= t) & (t < t0 + dt)), (o + semi + reflex, t0 + dt <= t))
    return sympy.lambdify([t, t0, dt, k, o, a, tau], double, 'scipy')

Thanks for suggesting Sympy. After using lambdify the result is a python function which in this case relies on scipy definitions of mathematical functions.

xikhari
  • 99
  • 3
  • 14