sigma-epsilon / sigmaepsilon.math

A mathematical toolkit for tensor algebra and optimization
MIT License
3 stars 0 forks source link

add `evaluation_style` property to the `Function` class #84

Open BALOGHBence opened 1 month ago

BALOGHBence commented 1 month ago

When creating an instance of Function, the user should be able to indicate the evaluation style. The main evaluation styles are the following:

# NUMPY or UNIVERSAL or SEPARATE or MULTIVARIATE
def rosenbrock_1(x, y, a=1, b=100):
    """
    x and y can be scalars or arrays.
    """
    return (a-x)**2 + b*(y-x**2)**2

# SINGLE
def rosenbrock_2(x, a=1, b=100):
    """
    x is a 1d array
    """
    return (a-x[0])**2 + b*(x[1]-x[0]**2)**2

# BATCH or BULK
def rosenbrock_3(x, a=1, b=100):
    """
    x is a 2d array
    """
    return (a-x[:,0])**2 + b*(x[:,1]-x[:,0]**2)**2

An enumeration should be created for these, eg

from enum import Enum

class InputStyle(Enum):
    NUMPY = 1    # For scalar or element-wise array inputs (vectorized, supports NumPy arrays)
    SINGLE = 2   # For fixed-size 1D array (not vectorized, single input like a vector)
    BATCH = 3     # For 2D array inputs used for batch processing (vectorized, multiple inputs)

Mazbe a fourth type could be SYMPY dedicated for symbolic functions generated from SymPy expressions using sympy.lambdify.

BALOGHBence commented 1 month ago

There is another evaluation style that occurs eg. when using the lambdify method from SymPy.

from sympy.parsing.sympy_parser import parse_expr
from sympy import lambdify, symbols
import numpy as np

str_expr = "(x-300)**2 + (y-400)**2"
variables = symbols("x y")
expr = parse_expr(str_expr, evaluate=False).simplify()

f0 = lambdify([variables], expr, "numpy")
f0([300, 400])
x = np.array([[300, 400],[300, 400],[300, 400]])
f0(x.T)

This is similar to BATCH, but with the input transposed.

Also, depending on how the lambdify function is called

f0 = lambdify(variables, expr, "numpy")
f0(300, 400)

x = np.array([[300, 400],[300, 400],[300, 400]])
f0(x[:,0], x[:,1])

This results in the UNIVERSAL style.

When a Function instance is created from a string or a SymPy expression, there should be an option to specify the evaluation style.

BALOGHBence commented 1 month ago

When this is done, the BGA class has to be updated to account for different evaluation styles. Currently it only utilizes BATCH evaluation in the case of symbolic functions.