Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I combine two functions that take the same arguments?

Tags:

python

I have a given function

def unnorm(x, alpha, beta):
    return (1 + alpha * x + beta * x ** 2)

Which I then integrate to find a normalization constant for in a range, and turn it to a lambda function that takes the same parameters as unnorm. Now, to create a fit-able object, I combine the functions like this:

def normalized(x, alpha, beta):
    return unnorm(x, alpha, beta) * norm(x, alpha, beta)

Which is nice and all, but there's still repetition and pulling names from the global namespace.

How can I combine the two functions in a cleaner fashion, without having to re-write parameters? E.g

def normalized(func, normalizer):
    return func * normalizer

Full code:

import sympy
import numpy as np
import inspect

def normalize_function(f, xmin, xmax):
    """
    Normalizes function to PDF in the given range
    """
    # Get function arguments
    fx_args = inspect.getfullargspec(f).args
    # Convert to symbolic notation
    symbolic_args = sympy.symbols(fx_args)
    # Find definite integral
    fx_definite_integral = sympy.integrate(f(*symbolic_args), (symbolic_args[0], xmin, xmax))
    # Convert to a normalization multiplication term, as a real function
    N = sympy.lambdify(expr = 1 / fx_definite_integral, args = symbolic_args)
    return N

def unnorm(x, alpha, beta):
    return (1 + alpha * x + beta * x ** 2)

norm = normalize_function(unnorm, -1, 1)

# How do I condense this to a generic expression?
def normalized(x, alpha, beta):
    return unnorm(x, alpha, beta) * norm(x, alpha, beta)

x = np.random.random(100)

print(normalized(x, alpha = 0.5, beta = 0.5))
like image 587
komodovaran_ Avatar asked Jan 28 '23 14:01

komodovaran_


1 Answers

I don't see anything wrong with what you are doing now. But for aesthetic purposes, here are a couple of alternatives with some minimal functions.

def doubler(x, y, z):
    return 2*(x + y + z)

def halver(x, y, z):
    return 0.5*(x + y + z)

def doubler_halver_sumprod(*args):
    return doubler(*args) * halver(*args)

dhs = lambda *args: doubler(*args) * halver(*args)

doubler_halver_sumprod(1, 2, 3)  # 36
dhs(1, 2, 3)                     # 36

If you want a truly extendible, functional approach, extracting arguments once, this could work:

from operator import mul, methodcaller
from functools import reduce

def prod(iterable):
    return reduce(mul, iterable, 1)

def doubler(x, y, z):
    return 2*(x + y + z)

def halver(x, y, z):
    return 0.5*(x + y + z)

def dhs2(*args):
    return prod(map(methodcaller('__call__', *args), (doubler, halver)))

def dhs3(*args):
    return prod(f(*args) for f in (doubler, halver))

dhs2(1, 2, 3)  # 36
dhs3(1, 2, 3)  # 36
like image 152
jpp Avatar answered Feb 19 '23 05:02

jpp