From 94efa1543d4443dad5de0c4161223fdc1993e889 Mon Sep 17 00:00:00 2001 From: Alex Vong Date: Wed, 31 Aug 2022 18:28:15 +0000 Subject: [PATCH] Python header: Add more 2D sym functions. Add more 2D sym functions to abstract over the idea of 2D sym so that we can choose to represent non-Matrix 2D sym to be something other than an Array in the future. For example, we could use TableForm. WIP: This is incomplete. More functions need to use these 2D sym functions. Not sure if this is needed anymore as TableForm was shown to be lacking various features such as indexing and taking transpose. No other candidates are being considered at the moment. * inst/private/{python_header.py,python_ipc_native.m}: Add new 2D sym functions 'is_2d_sym', 'is_matrix', 'is_non_matrix_2d_sym', 'list_from_2d_sym' and 'shape_of_2d_sym'. * inst/@sym/private/mat_rclist_{access,asgn}.m: Use them. * inst/@sym/{transpose.m,vertcat.m}: Use them. --- inst/@sym/private/mat_rclist_access.m | 2 +- inst/@sym/private/mat_rclist_asgn.m | 8 ++++---- inst/@sym/transpose.m | 6 ++---- inst/@sym/vertcat.m | 8 +++----- inst/private/python_header.py | 24 ++++++++++++++++++++++-- inst/private/python_ipc_native.m | 24 ++++++++++++++++++++++-- 6 files changed, 54 insertions(+), 18 deletions(-) diff --git a/inst/@sym/private/mat_rclist_access.m b/inst/@sym/private/mat_rclist_access.m index c46036a3..8662ac57 100644 --- a/inst/@sym/private/mat_rclist_access.m +++ b/inst/@sym/private/mat_rclist_access.m @@ -34,7 +34,7 @@ end cmd = {'(A, rr, cc) = _ins' - 'AA = A.tolist() if isinstance(A, (MatrixBase, NDimArray)) else [[A]]' + 'AA = list_from_2d_sym(A) if is_2d_sym(A) else [[A]]' 'MM = [[AA[i][j]] for i, j in zip(rr, cc)]' 'M = make_2d_sym(MM)' 'return M,'}; diff --git a/inst/@sym/private/mat_rclist_asgn.m b/inst/@sym/private/mat_rclist_asgn.m index bf88254b..91b60762 100644 --- a/inst/@sym/private/mat_rclist_asgn.m +++ b/inst/@sym/private/mat_rclist_asgn.m @@ -65,13 +65,13 @@ 'if A == []:' ' AA = []' ' (nrows_A, ncols_A) = (0, 0)' - 'elif isinstance(A, (MatrixBase, NDimArray)):' - ' AA = A.tolist()' - ' (nrows_A, ncols_A) = A.shape' + 'elif is_2d_sym(A):' + ' AA = list_from_2d_sym(A)' + ' (nrows_A, ncols_A) = shape_of_2d_sym(A)' 'else:' ' AA = [[A]]' ' (nrows_A, ncols_A) = (1, 1)' - 'bb = b.tolist() if isinstance(b, (MatrixBase, NDimArray)) else [[b]]' + 'bb = list_from_2d_sym(b) if is_2d_sym(b) else [[b]]' 'entries = dict(zip(zip(rr, cc), flatten(bb, levels=1)))' 'def entry(i, j):' ' if (i, j) in entries:' diff --git a/inst/@sym/transpose.m b/inst/@sym/transpose.m index 16155480..316c1403 100644 --- a/inst/@sym/transpose.m +++ b/inst/@sym/transpose.m @@ -66,10 +66,8 @@ print_usage (); end - cmd = {'def is_matrix_or_array(x):' - ' return isinstance(x, (MatrixBase, NDimArray))' - 'x, = _ins' - 'return transpose(x) if is_matrix_or_array(x) else x'}; + cmd = {'x, = _ins' + 'return transpose(x) if is_2d_sym(x) else x'}; z = pycall_sympy__ (cmd, x); diff --git a/inst/@sym/vertcat.m b/inst/@sym/vertcat.m index 3a57250a..a9c5d3ce 100644 --- a/inst/@sym/vertcat.m +++ b/inst/@sym/vertcat.m @@ -45,14 +45,12 @@ % special case for 0x0 but other empties should be checked for % compatibilty - cmd = {'def is_matrix_or_array(x):' - ' return isinstance(x, (MatrixBase, NDimArray))' - 'def number_of_columns(x):' - ' return x.shape[1] if is_matrix_or_array(x) else 1' + cmd = {'def number_of_columns(x):' + ' return shape_of_2d_sym(x)[1] if is_2d_sym(x) else 1' 'def all_equal(*ls):' ' return True if ls == [] else all(ls[0] == x for x in ls[1:])' 'def as_list_of_list(x):' - ' return x.tolist() if is_matrix_or_array(x) else [[x]]' + ' return list_from_2d_sym(x) if is_2d_sym(x) else [[x]]' 'args = [x for x in _ins if x != zeros(0, 0)] # remove 0x0 matrices' 'ncols = [number_of_columns(x) for x in args]' 'if not all_equal(*ncols):' diff --git a/inst/private/python_header.py b/inst/private/python_header.py index 08e3be97..87100f04 100644 --- a/inst/private/python_header.py +++ b/inst/private/python_header.py @@ -241,9 +241,10 @@ def octoutput(x, et): try: + # begin: 2D sym funcs + # 2D sym funcs defined in inst/private/python_ipc_native.m + # and inst/private/python_header.py should be kept in sync def make_2d_sym(it_of_it, dbg_matrix_only=False): - # should be kept in sync with the same function - # defined in inst/private/python_ipc_native.m # FIXME: dbg_matrix_only is used for debugging, remove # it once sympy drops non-Expr support in Matrix """ @@ -259,7 +260,26 @@ def make_2d_sym(it_of_it, dbg_matrix_only=False): return Matrix(ls_of_ls) else: dbout(f"make_2d_sym: constructing 2D sym...") + # FIXME: should we use Array or TableForm? return Array(ls_of_ls) + def is_2d_sym(x): + types = (MatrixBase, NDimArray, TableForm) + return isinstance(x, types) + def is_matrix(x): + return isinstance(x, MatrixBase) + def is_non_matrix_2d_sym(x): + return isinstance(x, (NDimArray, TableForm)) + def list_from_2d_sym(X): + if isinstance(X, TableForm): + return [[x for x in tup] for tup in X._lines] + else: + return X.tolist() + def shape_of_2d_sym(X): + if isinstance(X, TableForm): + return (X._h, X._w) + else: + return X.shape + # end: 2D sym funcs except: echo_exception_stdout("in python_header defining fcns block 5") raise diff --git a/inst/private/python_ipc_native.m b/inst/private/python_ipc_native.m index a7a83aba..b1f84329 100644 --- a/inst/private/python_ipc_native.m +++ b/inst/private/python_ipc_native.m @@ -111,9 +111,10 @@ ' # should be kept in sync with the same function' ' # defined in inst/private/python_header.py' ' sys.stderr.write("pydebug: " + str(l) + "\n")' + '# begin: 2D sym funcs' + '# 2D sym funcs defined in inst/private/python_ipc_native.m' + '# and inst/private/python_header.py should be kept in sync' 'def make_2d_sym(it_of_it, dbg_matrix_only=False):' - ' # should be kept in sync with the same function' - ' # defined in inst/private/python_header.py' ' # FIXME: dbg_matrix_only is used for debugging, remove' ' # it once sympy drops non-Expr support in Matrix' ' """' @@ -129,7 +130,26 @@ ' return Matrix(ls_of_ls)' ' else:' ' dbout(f"make_2d_sym: constructing 2D sym...")' + ' # FIXME: should we use Array or TableForm?' ' return Array(ls_of_ls)' + 'def is_2d_sym(x):' + ' types = (MatrixBase, NDimArray, TableForm)' + ' return isinstance(x, types)' + 'def is_matrix(x):' + ' return isinstance(x, MatrixBase)' + 'def is_non_matrix_2d_sym(x):' + ' return isinstance(x, (NDimArray, TableForm))' + 'def list_from_2d_sym(X):' + ' if isinstance(X, TableForm):' + ' return [[x for x in tup] for tup in X._lines]' + ' else:' + ' return X.tolist()' + 'def shape_of_2d_sym(X):' + ' if isinstance(X, TableForm):' + ' return (X._h, X._w)' + ' else:' + ' return X.shape' + '# end: 2D sym funcs' }, newl)) have_headers = true; end