Support expanding some functions
Follows #63
It is good to provide a expand_functions boolean option to control whether some composite functions are expanded or not, e.g.:
-
hypot(x, y)-> $\sqrt{x^2 + y^2}$ -
atan2(y, x)-> $\arctan{\frac{y}{x}}$ -
expit(x)-> $\frac{1}{1+\exp{(-x)}}$
Is it better expit(x) to be $\frac{1}{1+e^{-x}}$ ?
@MAKMED1337 Not sure, but it looks there should be another option to control the behavior around $\exp$ .
I think this can be solved by introducing function-level controls:
- Register replacement rules
Call -> ASTfor each applicable functions. If the expanded AST has other calls, it is kept as-is. - Assin a flag for each rule to control whether the rule is applied or not.
- Add a flag to control the overall behavior (i.e., we perform the replacement if
all_flag && fn_flag[fn_name]is True) - For the replacer routine (it may be NodeTransformer), if it finds a matched name, replace it to AST, and recursively applies the rules to replacements too.
This allows us to control the behavior more precisely. E.g., users can choose the result of expit(x) from either $\frac{1}{1+\exp{(-x)}}$ or $\frac{1}{1+e^{-x}}$
This also involves some caveats:
- It causes infinite replacement if the rule has identity or cyclic rules:
f(x) -> f(x), orf(x) -> g(x) and g(x) -> f(x), which may result in stack overflow. Since it is not easy to detect such behavior in advance, it may be necessary to constrain the maximum recursion of the replacements. - If
with_latextakes every function-level flags, the syntax may become very complicated. I think providing a config function is better, something like:
import latexify
config = latexify.Config.defaults()
config.expand_function("expit")
@latexify.with_latex(config)
def f(x):
return expit(x)
# Will generate: \mathrm{f}(x) \triangleq \frac{1}{1+\exp{(-x)}}
List of methods in math that I think we should allow expansion for:
-
exp(x)-> $e^x$ -
exp2(x)-> $2^x$ -
expm1(x)-> $\exp(x) - 1$ -
log1p(x)-> $\log(1 + x)$ -
pow(x, y)-> $x^y$ -
atan2(x)-> $\arctan(y / x)$ -
erf-> too complicated, also I don't think integrals are supported... yet -
erfc-> see above -
gamma-> maybe for positive integers? I think it's best to leave alone for now -
lgamma-> see above
Let me know what you think @odashi, and I'll get started on these
I think non-elementary functions (erf, erfc, gamma, lgamma) should be avoided from this option. Other candidates look fine to me.
I also think our current implementation (#125) naturally solves https://github.com/google/latexify_py/issues/65#issuecomment-1290288048 , as users can choose whether exp is expanded or not.
This is generally supported in the current implementation. We'd support individual functions in separate issues (if needed).