Алгебра функций для добавления или умножения нескольких python функций и параметров упаковки в одном векторе - PullRequest
2 голосов
/ 23 марта 2020

Я пытаюсь построить более сложную функцию из суммы и произведения нескольких простых функций. Я хочу создать класс, в который я могу добавить новую простую функцию и ее операцию для создания сложной функции, а затем оценить сложную функцию.

Например, скажем, у меня есть функции:

def f1(a, b, c):
    return 2 * c

def f2(a, b, c, d):
    return c + d

И я хотел бы создать что-то вроде:

f1(0, 0, 1) + f2(0, 0, 1, 0) * f1(0, 0, 2)
#Out:6

Но без ввода всего выражения и с Параметры упакованы в один вектор, поэтому я могу оптимизировать их. Я создал класс, чтобы сделать это, но он действительно довольно неуклюж и не следует BODMAS (математический порядок операций, скобка, деление, умножение, сложение и вычитание):

class FunctionAlgebra:

    def __init__(self):
        self.f = []
        self.op = []
        self.hpid = []
        self.hyperparameters = []
        self.name = '0'

    def compose(self, f, p, op):
        """
        Compose an expression
        """
        self.hpid = np.concatenate([self.hpid, len(self.f) * np.ones(len(p))])
        self.hyperparameters = np.concatenate([self.hyperparameters, p])
        self.f.append(f)
        self.op.append(op)
        self.name += " {} {}".format(op.__name__, f.__name__)
        self.name = self.name.replace('add', "+").replace("multiply", '*')

    def _evalf_(self, a, b, f, args):
        """
        Evaluate a function
        """
        self.cr = f(a, b, *args)

    def multiply(self):
        """
        Multiply function result by total result
        """
        self.result *= self.cr

    def add(self):
        """
        Add function result to the total result.
        """
        self.result += self.cr

    def call(self, a, b, p):
        """
        Call and evaluate the expression
        """
        self.result = 0
        for i in range(len(self.f)):
            args = p[self.hpid == i]
            self._evalf_(a, b, self.f[i], args)
            self.op[i]()
        return self.result

Тестирование в первом примере ответ должен быть 6, но 12 из-за отсутствия БОДМАС:

f = FunctionAlgebra()
f.compose(f1, [1], f.add)
f.compose(f2, [1, 0], f.add)
f.compose(f1, [2], f.multiply)
f.call(0, 0, f.hyperparameters)
#Out:12

Кто-нибудь знает более Pythoni c способ сложения и умножения функций вместе и объединения их параметров в один вектор ?

Спасибо,

Робин

1 Ответ

1 голос
/ 24 марта 2020

Вы не реализовали BODMAS, поэтому все операции выполняются последовательно, слева направо.

Чтобы реализовать приоритет оператора, вы должны:

  • каким-либо образом предоставить выражение (недостаточно беглого использования)
  • проанализировать выражение (например, с помощью antlr4 )
  • и, наконец, выполните операцию в требуемом порядке (например, BODMAS)

Это длинный (но мощный и правильный) путь. Python имеет встроенную функцию eval , поэтому ее можно использовать в своих целях:

class FunctionAlgebra:

    def __init__(self):
        self.parts=[]

    def compose(self, f, p, op):
        self.parts.append({
            'function':f,
            'params':p,
            'operation':op})

    def call(self, *hyperparams):

        #build expression and its input params
        expr = '0'
        inp={}
        i = 0 

        for part in self.parts:
            varname = f'v{i}'
            expr += part['operation']+varname
            inp[varname] = part['function'](*hyperparams, *part['params'])
            i+=1

        print (expr, inp)
        #and eval it
        return eval(expr,inp)


def f1(a, b, c):
    return 2 * c

def f2(a, b, c, d):
    return c + d


f = FunctionAlgebra()
f.compose(f1, [1], '+')
f.compose(f2, [1, 0], '+')
f.compose(f1, [2], '*')

print (f.call(0, 0))

# 0+v0+v1*v2 {'v0': 2, 'v1': 1, 'v2': 4}
# Output 6
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...