From 048ab37f571eff915d73b85ffb29ab87fb3af36b Mon Sep 17 00:00:00 2001 From: zhenghan <719470343@qq.com> Date: Fri, 13 Sep 2024 16:04:01 +0800 Subject: [PATCH 1/8] Create tinyexpy.pxd The cython file tinyexpy.pxd is used to bridge the c header file tinyexpr.h --- python/tinyexpy.pxd | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 python/tinyexpy.pxd diff --git a/python/tinyexpy.pxd b/python/tinyexpy.pxd new file mode 100644 index 0000000..9720850 --- /dev/null +++ b/python/tinyexpy.pxd @@ -0,0 +1,37 @@ +ctypedef union te_expr_u: + double value + const double *bound + const void *function + +ctypedef struct te_expr: + int type + te_expr_u u + void *parameters[1] + +ctypedef struct te_variable: + const char *name + const void *address + int type + void *context + +cdef enum: + TE_VARIABLE = 0, + TE_FUNCTION0 = 8, TE_FUNCTION1, TE_FUNCTION2, TE_FUNCTION3, + TE_FUNCTION4, TE_FUNCTION5, TE_FUNCTION6, TE_FUNCTION7, + TE_CLOSURE0 = 16, TE_CLOSURE1, TE_CLOSURE2, TE_CLOSURE3, + TE_CLOSURE4, TE_CLOSURE5, TE_CLOSURE6, TE_CLOSURE7, + TE_FLAG_PURE = 32 + + +cdef extern from "tinyexpr.h" nogil: + + + double te_interp(const char *expression, int *error) + + te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error) + + double te_eval(const te_expr *n) + + void te_print(const te_expr *n) + + void te_free(te_expr *n) From fe65b71ef46b15832a6b378926833819cabc62c4 Mon Sep 17 00:00:00 2001 From: zhenghan <719470343@qq.com> Date: Fri, 13 Sep 2024 16:06:04 +0800 Subject: [PATCH 2/8] Create tinyexpy.pyx The cython file tinyexpy.pyx implements the c extension of python --- python/tinyexpy.pyx | 74 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 python/tinyexpy.pyx diff --git a/python/tinyexpy.pyx b/python/tinyexpy.pyx new file mode 100644 index 0000000..16c2b85 --- /dev/null +++ b/python/tinyexpy.pyx @@ -0,0 +1,74 @@ +cimport tinyexpy +from libc cimport stdlib +from typing import List, Callable, Any + + + + + +cdef class Tinyexpy: + + @staticmethod + cdef double add(double a, double b): + return a + b + + + def py_te_interp(self, expression: str, error: int) -> float: + py_expression = expression.encode("utf8") + cdef int c_error = error + cdef char *c_expression = py_expression + cdef double res = te_interp(c_expression, &c_error) + print(f"Evaluating:\n\t{c_expression.decode('utf8')}\nResult:\n\t{res}\n") + return res + + + def py_te_interp_customize(self, expression: str, py_vars: List[dict]): + cdef char *te_variable_name + cdef char *c_expression + cdef int var_count = len(py_vars) + cdef int c_err + cdef te_expr *n + cdef double[100] x + cdef double r + cdef te_variable c_te_variable + cdef te_variable[100] vars + py_expression = expression.encode("utf8") + c_expression = py_expression + for i, each_py_vars in enumerate(py_vars): + each_value = each_py_vars.get("value") + if isinstance(each_value, float) or isinstance(each_value, int): + each_name = each_py_vars.get("name").encode("utf8") + te_variable_name = each_name + x[i] = float(each_value) + c_te_variable = te_variable(te_variable_name, &x[i]) + vars[i] = c_te_variable + n = te_compile(c_expression, vars, var_count, &c_err) + if n != NULL: + # te_print(n) + r = te_eval(n) + te_free(n) + print(f"Evaluating:\n\t{c_expression.decode('utf8')}\nResult:\n\t{r}\n") + return r + + + + def py_te_interp_my_func(self, func_name: str, expression: str): + cdef te_variable[1] vars + cdef char *c_expression + cdef char *myfunc + cdef int c_err + cdef te_expr *n + cdef double r + py_expression = expression.encode("utf8") + py_func_name = func_name.encode("utf8") + c_expression = py_expression + myfunc = py_func_name + vars[0] = te_variable(name=myfunc, address=self.add, type=TE_FUNCTION2) + n = te_compile(c_expression, vars, 1, &c_err) + if n != NULL: + # te_print(n) + r = te_eval(n) + te_free(n) + print(f"Evaluating:\n\t{c_expression.decode('utf8')}\nResult:\n\t{r}\n") + return r + From a49d9f5ce649176b19038f637c43a0272ea2ac08 Mon Sep 17 00:00:00 2001 From: zhenghan <719470343@qq.com> Date: Fri, 13 Sep 2024 16:07:13 +0800 Subject: [PATCH 3/8] Create requirements.txt python requirements file --- python/requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 python/requirements.txt diff --git a/python/requirements.txt b/python/requirements.txt new file mode 100644 index 0000000..b677f06 --- /dev/null +++ b/python/requirements.txt @@ -0,0 +1 @@ +Cython~=3.0.11 From 9dbbb3ae48adac6c522fc0901bf7299e35378108 Mon Sep 17 00:00:00 2001 From: zhenghan <719470343@qq.com> Date: Fri, 13 Sep 2024 16:08:02 +0800 Subject: [PATCH 4/8] Create setup.py python setup file --- python/setup.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 python/setup.py diff --git a/python/setup.py b/python/setup.py new file mode 100644 index 0000000..d736ded --- /dev/null +++ b/python/setup.py @@ -0,0 +1,11 @@ +from distutils.core import setup, Extension +from Cython.Build import cythonize + + +ext = [Extension("tinyexpy", + sources=["tinyexpy.pyx", "../tinyexpr.c"], + include_dirs=['../'], + depends=["../tinyexpr.h"], + )] + +setup(name="tinyexpy", ext_modules=cythonize(ext, language_level=3)) From 50d72a4bb7efa5c76934d7f5d77aad1252ffd065 Mon Sep 17 00:00:00 2001 From: zhenghan <719470343@qq.com> Date: Fri, 13 Sep 2024 16:08:35 +0800 Subject: [PATCH 5/8] Create test.py test file --- python/test.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 python/test.py diff --git a/python/test.py b/python/test.py new file mode 100644 index 0000000..feaf2f2 --- /dev/null +++ b/python/test.py @@ -0,0 +1,25 @@ +from tinyexpy import Tinyexpy + + +def test_py_te_interp(): + T = Tinyexpy() + return T.py_te_interp(expression="3+3", error=0) + + +def test_py_te_interp_customize(): + T = Tinyexpy() + return T.py_te_interp_customize(expression="x+1+z", + py_vars=[{"name": "x", "value": 2.0}, {"name": "y", "value": 5}, + {"name": "z", "value": 7}]) + + +def test_te_interp_my_func(): + T = Tinyexpy() + return T.py_te_interp_my_func("my_add", "my_add(5, 10)") + + +if __name__ == '__main__': + for i in dir(): + if i.startswith('test'): + globals()[i]() + From d8ee9aa7857e8e7402a9223b055c22464845bf9b Mon Sep 17 00:00:00 2001 From: zhenghan <719470343@qq.com> Date: Fri, 13 Sep 2024 16:12:07 +0800 Subject: [PATCH 6/8] Update tinyexpy.pyx Remove unused references in the typing module --- python/tinyexpy.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tinyexpy.pyx b/python/tinyexpy.pyx index 16c2b85..84bb761 100644 --- a/python/tinyexpy.pyx +++ b/python/tinyexpy.pyx @@ -1,6 +1,6 @@ cimport tinyexpy from libc cimport stdlib -from typing import List, Callable, Any +from typing import List From f637e359cda54269ea462f82d3902afea80a729f Mon Sep 17 00:00:00 2001 From: zhenghan <719470343@qq.com> Date: Fri, 13 Sep 2024 16:14:15 +0800 Subject: [PATCH 7/8] Create setup.sh compile file --- python/setup.sh | 1 + 1 file changed, 1 insertion(+) create mode 100644 python/setup.sh diff --git a/python/setup.sh b/python/setup.sh new file mode 100644 index 0000000..d447b42 --- /dev/null +++ b/python/setup.sh @@ -0,0 +1 @@ +python3 setup.py build_ext --inplace From 0465b002afe29b18e48ffd3a8cec6e61316f810b Mon Sep 17 00:00:00 2001 From: zhenghan <719470343@qq.com> Date: Sat, 14 Sep 2024 10:58:37 +0800 Subject: [PATCH 8/8] Update tinyexpy.pyx Add SIZE_VARS macro definition --- python/tinyexpy.pyx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/python/tinyexpy.pyx b/python/tinyexpy.pyx index 84bb761..56f7d1e 100644 --- a/python/tinyexpy.pyx +++ b/python/tinyexpy.pyx @@ -2,8 +2,7 @@ cimport tinyexpy from libc cimport stdlib from typing import List - - +DEF SIZE_VARS = 100 cdef class Tinyexpy: @@ -28,10 +27,10 @@ cdef class Tinyexpy: cdef int var_count = len(py_vars) cdef int c_err cdef te_expr *n - cdef double[100] x + cdef double[SIZE_VARS] x cdef double r cdef te_variable c_te_variable - cdef te_variable[100] vars + cdef te_variable[SIZE_VARS] vars py_expression = expression.encode("utf8") c_expression = py_expression for i, each_py_vars in enumerate(py_vars): @@ -71,4 +70,13 @@ cdef class Tinyexpy: te_free(n) print(f"Evaluating:\n\t{c_expression.decode('utf8')}\nResult:\n\t{r}\n") return r - + + + + + + + + + +