Skip to content

minimal set of changes for returning failure to find non-zero pivot in FFGJ #457

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,12 @@ jobs:
CC: gcc

- BUILD_TYPE: Release
PYTHON_VERSION: '3.8'
PYTHON_VERSION: '3.11'
OS: ubuntu-20.04
WITH_MPC: yes
WITH_MPFR: yes
WITH_FLINT: yes
WITH_FLINT_PY: yes
WITH_SCIPY: yes
WITH_DOCS: yes
INTEGER_CLASS: flint
Expand Down
4 changes: 4 additions & 0 deletions bin/install_travis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ if [[ "${WITH_DOCS}" == "yes" ]]; then
export conda_pkgs="${conda_pkgs} sphinx recommonmark";
fi

if [[ "${WITH_FLINT_PY}" == "yes" ]]; then
export conda_pkgs="${conda_pkgs} python-flint"; # python-flint affects sympy, see e.g. sympy/sympy#26645
fi

if [[ "${WITH_SAGE}" == "yes" ]]; then
# This is split to avoid the 10 minute limit
conda install -q sagelib=8.1
Expand Down
2 changes: 1 addition & 1 deletion cmake/FindCython.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ IF (CYTHON_BIN)
RESULT_VARIABLE CYTHON_RESULT
OUTPUT_VARIABLE CYTHON_OUTPUT
ERROR_VARIABLE CYTHON_ERROR
)
)
if (CYTHON_RESULT EQUAL 0)
# Only if cython exits with the return code 0, we know that all is ok:
SET(Cython_FOUND TRUE)
Expand Down
6 changes: 3 additions & 3 deletions cmake/FindPython.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
set(PYTHON_BIN python CACHE STRING "Python executable name")

execute_process(
COMMAND ${PYTHON_BIN} -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())"
COMMAND ${PYTHON_BIN} -c "import setuptools; from distutils.sysconfig import get_python_inc; print(get_python_inc())"
OUTPUT_VARIABLE PYTHON_SYS_PATH
)
string(STRIP ${PYTHON_SYS_PATH} PYTHON_SYS_PATH)
Expand All @@ -16,7 +16,7 @@ set(PYTHON_INSTALL_HEADER_PATH ${PYTHON_INCLUDE_PATH}/symengine
CACHE BOOL "Python install headers path")

execute_process(
COMMAND ${PYTHON_BIN} -c "from distutils.sysconfig import get_config_var; print(get_config_var('LIBDIR'))"
COMMAND ${PYTHON_BIN} -c "import setuptools; from distutils.sysconfig import get_config_var; print(get_config_var('LIBDIR'))"
OUTPUT_VARIABLE PYTHON_LIB_PATH
)
string(STRIP ${PYTHON_LIB_PATH} PYTHON_LIB_PATH)
Expand Down Expand Up @@ -50,7 +50,7 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
endif()

execute_process(
COMMAND ${PYTHON_BIN} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"
COMMAND ${PYTHON_BIN} -c "import setuptools; from distutils.sysconfig import get_python_lib; print(get_python_lib())"
OUTPUT_VARIABLE PYTHON_INSTALL_PATH_tmp
)
string(STRIP ${PYTHON_INSTALL_PATH_tmp} PYTHON_INSTALL_PATH_tmp)
Expand Down
2 changes: 1 addition & 1 deletion cmake/get_suffix.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from distutils.sysconfig import get_config_var
import setuptools; from distutils.sysconfig import get_config_var
extsuffix = get_config_var('EXT_SUFFIX')
if extsuffix is None:
print("")
Expand Down
9 changes: 5 additions & 4 deletions symengine/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@
from .lib.symengine_wrapper import ComplexMPC

if have_numpy:
from .lib.symengine_wrapper import (Lambdify, LambdifyCSE)

from .lib.symengine_wrapper import Lambdify, LambdifyCSE
def lambdify(args, exprs, **kwargs):
if isinstance(exprs, Basic):
exprs = [exprs]
return Lambdify(args, *exprs, **kwargs)
else:
def __getattr__(name):
if name == 'lambdify':
raise AttributeError("Cannot import numpy, which is required for `lambdify` to work")
if name in ('lambdify', 'Lambdify', 'LambdifyCSE'):
raise AttributeError(f"Cannot import numpy, which is required for `{name}` to work")
raise AttributeError(f"module 'symengine' has no attribute '{name}'")


Expand Down
300 changes: 150 additions & 150 deletions symengine/lib/symengine.pxd

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions symengine/lib/symengine_wrapper.in.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

cimport symengine
from symengine cimport RCP, map_basic_basic, rcp_const_basic
from libcpp.memory cimport unique_ptr
from libcpp.vector cimport vector
from libcpp.string cimport string
from libcpp cimport bool as cppbool
Expand Down Expand Up @@ -44,7 +45,7 @@ cdef class _Lambdify(object):
cpdef unsafe_eval(sef, inp, out, unsigned nbroadcast=*)

cdef class LambdaDouble(_Lambdify):
cdef vector[symengine.LambdaRealDoubleVisitor] lambda_double
cdef unique_ptr[symengine.LambdaRealDoubleVisitor] lambda_visitor
cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
cpdef unsafe_real(self, double[::1] inp, double[::1] out, int inp_offset=*, int out_offset=*)
cpdef as_scipy_low_level_callable(self)
Expand All @@ -54,7 +55,7 @@ cdef class LambdaDouble(_Lambdify):
int inp_offset=*, int out_offset=*)

cdef class LambdaComplexDouble(_Lambdify):
cdef vector[symengine.LambdaComplexDoubleVisitor] lambda_double
cdef unique_ptr[symengine.LambdaComplexDoubleVisitor] lambda_visitor
cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
cpdef unsafe_complex(self, double complex[::1] inp, double complex[::1] out, int inp_offset=*, int out_offset=*)

Expand All @@ -63,22 +64,22 @@ IF HAVE_SYMENGINE_LLVM:
cdef int opt_level

cdef class LLVMDouble(_LLVMLambdify):
cdef vector[symengine.LLVMDoubleVisitor] lambda_double
cdef unique_ptr[symengine.LLVMDoubleVisitor] lambda_visitor
cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
cdef _load(self, const string &s)
cpdef unsafe_real(self, double[::1] inp, double[::1] out, int inp_offset=*, int out_offset=*)
cpdef as_scipy_low_level_callable(self)
cpdef as_ctypes(self)

cdef class LLVMFloat(_LLVMLambdify):
cdef vector[symengine.LLVMFloatVisitor] lambda_double
cdef unique_ptr[symengine.LLVMFloatVisitor] lambda_visitor
cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
cdef _load(self, const string &s)
cpdef unsafe_real(self, float[::1] inp, float[::1] out, int inp_offset=*, int out_offset=*)

IF HAVE_SYMENGINE_LLVM_LONG_DOUBLE:
cdef class LLVMLongDouble(_LLVMLambdify):
cdef vector[symengine.LLVMLongDoubleVisitor] lambda_double
cdef unique_ptr[symengine.LLVMLongDoubleVisitor] lambda_visitor
cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
cdef _load(self, const string &s)
cpdef unsafe_real(self, long double[::1] inp, long double[::1] out, int inp_offset=*, int out_offset=*)
83 changes: 46 additions & 37 deletions symengine/lib/symengine_wrapper.in.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1211,7 +1211,7 @@ cdef class Basic(object):
return int(float(self))

def __long__(self):
return long(float(self))
return int(float(self))

def __complex__(self):
f = self.n(real=False)
Expand Down Expand Up @@ -1627,7 +1627,9 @@ class Equality(Relational):
def is_Equality(self):
return True

func = __class__
@property
def func(self):
return self.__class__


Eq = Equality
Expand All @@ -1648,7 +1650,9 @@ class Unequality(Relational):
s = self.args_as_sage()
return sage.ne(*s)

func = __class__
@property
def func(self):
return self.__class__


Ne = Unequality
Expand Down Expand Up @@ -3529,6 +3533,9 @@ cdef class DenseMatrixBase(MatrixBase):
def __neg__(self):
return self.mul_scalar(-1)

def __abs__(self):
return self.applyfunc(abs)

def __getitem__(self, item):
if isinstance(item, slice):
if (self.ncols() == 0 or self.nrows() == 0):
Expand Down Expand Up @@ -3998,9 +4005,11 @@ cdef class DenseMatrixBase(MatrixBase):
deref(symengine.static_cast_DenseMatrix(b_.thisptr)),
deref(symengine.static_cast_DenseMatrix(x.thisptr)))
elif method.upper() == 'FFGJ':
symengine.FFGJ_solve(deref(symengine.static_cast_DenseMatrix(self.thisptr)),
failure = symengine.FFGJ_solve(deref(symengine.static_cast_DenseMatrix(self.thisptr)),
deref(symengine.static_cast_DenseMatrix(b_.thisptr)),
deref(symengine.static_cast_DenseMatrix(x.thisptr)))
if (failure != 0):
raise Exception("Underdetermined system. Failed to find non-zero pivot in column: %d" % failure)
else:
raise Exception("Unsupported method.")

Expand Down Expand Up @@ -5152,27 +5161,27 @@ cdef class LambdaDouble(_Lambdify):
pass

cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
self.lambda_double.resize(1)
self.lambda_double[0].init(args_, outs_, cse)
self.lambda_visitor.reset(new symengine.LambdaRealDoubleVisitor())
deref(self.lambda_visitor).init(args_, outs_, cse)

cpdef unsafe_real(self, double[::1] inp, double[::1] out, int inp_offset=0, int out_offset=0):
self.lambda_double[0].call(&out[out_offset], &inp[inp_offset])
deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])

cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
cdef double[::1] c_inp, c_out
cdef unsigned idx
c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
c_out = out
for idx in range(nbroadcast):
self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])

cpdef as_scipy_low_level_callable(self):
from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
if self.tot_out_size > 1:
raise RuntimeError("SciPy LowLevelCallable supports only functions with 1 output")
addr1 = cast(<size_t>&_scipy_callback_lambda_real,
CFUNCTYPE(c_double, c_int, POINTER(c_double), c_void_p))
addr2 = cast(<size_t>&self.lambda_double[0], c_void_p)
addr2 = cast(<size_t>self.lambda_visitor.get(), c_void_p)
return create_low_level_callable(self, addr1, addr2)

cpdef as_ctypes(self):
Expand All @@ -5187,7 +5196,7 @@ cdef class LambdaDouble(_Lambdify):
from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
addr1 = cast(<size_t>&_ctypes_callback_lambda_real,
CFUNCTYPE(c_void_p, POINTER(c_double), POINTER(c_double), c_void_p))
addr2 = cast(<size_t>&self.lambda_double[0], c_void_p)
addr2 = cast(<size_t>self.lambda_visitor.get(), c_void_p)
return addr1, addr2


Expand All @@ -5197,19 +5206,19 @@ cdef class LambdaComplexDouble(_Lambdify):
pass

cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
self.lambda_double.resize(1)
self.lambda_double[0].init(args_, outs_, cse)
self.lambda_visitor.reset(new symengine.LambdaComplexDoubleVisitor())
deref(self.lambda_visitor).init(args_, outs_, cse)

cpdef unsafe_complex(self, double complex[::1] inp, double complex[::1] out, int inp_offset=0, int out_offset=0):
self.lambda_double[0].call(&out[out_offset], &inp[inp_offset])
deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])

cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
cdef double complex[::1] c_inp, c_out
cdef unsigned idx
c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
c_out = out
for idx in range(nbroadcast):
self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])


IF HAVE_SYMENGINE_LLVM:
Expand All @@ -5218,31 +5227,31 @@ IF HAVE_SYMENGINE_LLVM:
self.opt_level = opt_level

cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
self.lambda_double.resize(1)
self.lambda_double[0].init(args_, outs_, cse, self.opt_level)
self.lambda_visitor.reset(new symengine.LLVMDoubleVisitor())
deref(self.lambda_visitor).init(args_, outs_, cse, self.opt_level)

cdef _load(self, const string &s):
self.lambda_double.resize(1)
self.lambda_double[0].loads(s)
self.lambda_visitor.reset(new symengine.LLVMDoubleVisitor())
deref(self.lambda_visitor).loads(s)

def __reduce__(self):
"""
Interface for pickle. Note that the resulting object is platform dependent.
"""
cdef bytes s = self.lambda_double[0].dumps()
cdef bytes s = deref(self.lambda_visitor).dumps()
return llvm_loading_func, (self.args_size, self.tot_out_size, self.out_shapes, self.real, \
self.n_exprs, self.order, self.accum_out_sizes, self.numpy_dtype, s)

cpdef unsafe_real(self, double[::1] inp, double[::1] out, int inp_offset=0, int out_offset=0):
self.lambda_double[0].call(&out[out_offset], &inp[inp_offset])
deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])

cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
cdef double[::1] c_inp, c_out
cdef unsigned idx
c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
c_out = out
for idx in range(nbroadcast):
self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])

cpdef as_scipy_low_level_callable(self):
from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
Expand All @@ -5252,7 +5261,7 @@ IF HAVE_SYMENGINE_LLVM:
raise RuntimeError("SciPy LowLevelCallable supports only functions with 1 output")
addr1 = cast(<size_t>&_scipy_callback_llvm_real,
CFUNCTYPE(c_double, c_int, POINTER(c_double), c_void_p))
addr2 = cast(<size_t>&self.lambda_double[0], c_void_p)
addr2 = cast(<size_t>self.lambda_visitor.get(), c_void_p)
return create_low_level_callable(self, addr1, addr2)

cpdef as_ctypes(self):
Expand All @@ -5269,71 +5278,71 @@ IF HAVE_SYMENGINE_LLVM:
raise RuntimeError("Lambda function has to be real")
addr1 = cast(<size_t>&_ctypes_callback_llvm_real,
CFUNCTYPE(c_void_p, POINTER(c_double), POINTER(c_double), c_void_p))
addr2 = cast(<size_t>&self.lambda_double[0], c_void_p)
addr2 = cast(<size_t>self.lambda_visitor.get(), c_void_p)
return addr1, addr2

cdef class LLVMFloat(_LLVMLambdify):
def __cinit__(self, args, *exprs, cppbool real=True, order='C', cppbool cse=False, cppbool _load=False, opt_level=3, dtype=None):
self.opt_level = opt_level

cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
self.lambda_double.resize(1)
self.lambda_double[0].init(args_, outs_, cse, self.opt_level)
self.lambda_visitor.reset(new symengine.LLVMFloatVisitor())
deref(self.lambda_visitor).init(args_, outs_, cse, self.opt_level)

cdef _load(self, const string &s):
self.lambda_double.resize(1)
self.lambda_double[0].loads(s)
self.lambda_visitor.reset(new symengine.LLVMFloatVisitor())
deref(self.lambda_visitor).loads(s)

def __reduce__(self):
"""
Interface for pickle. Note that the resulting object is platform dependent.
"""
cdef bytes s = self.lambda_double[0].dumps()
cdef bytes s = deref(self.lambda_visitor).dumps()
return llvm_float_loading_func, (self.args_size, self.tot_out_size, self.out_shapes, self.real, \
self.n_exprs, self.order, self.accum_out_sizes, self.numpy_dtype, s)

cpdef unsafe_real(self, float[::1] inp, float[::1] out, int inp_offset=0, int out_offset=0):
self.lambda_double[0].call(&out[out_offset], &inp[inp_offset])
deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])

cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
cdef float[::1] c_inp, c_out
cdef unsigned idx
c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
c_out = out
for idx in range(nbroadcast):
self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])

IF HAVE_SYMENGINE_LLVM_LONG_DOUBLE:
cdef class LLVMLongDouble(_LLVMLambdify):
def __cinit__(self, args, *exprs, cppbool real=True, order='C', cppbool cse=False, cppbool _load=False, opt_level=3, dtype=None):
self.opt_level = opt_level

cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
self.lambda_double.resize(1)
self.lambda_double[0].init(args_, outs_, cse, self.opt_level)
self.lambda_visitor.reset(new symengine.LLVMLongDoubleVisitor())
deref(self.lambda_visitor).init(args_, outs_, cse, self.opt_level)

cdef _load(self, const string &s):
self.lambda_double.resize(1)
self.lambda_double[0].loads(s)
self.lambda_visitor.reset(new symengine.LLVMLongDoubleVisitor())
deref(self.lambda_visitor).loads(s)

def __reduce__(self):
"""
Interface for pickle. Note that the resulting object is platform dependent.
"""
cdef bytes s = self.lambda_double[0].dumps()
cdef bytes s = deref(self.lambda_visitor).dumps()
return llvm_long_double_loading_func, (self.args_size, self.tot_out_size, self.out_shapes, self.real, \
self.n_exprs, self.order, self.accum_out_sizes, self.numpy_dtype, s)

cpdef unsafe_real(self, long double[::1] inp, long double[::1] out, int inp_offset=0, int out_offset=0):
self.lambda_double[0].call(&out[out_offset], &inp[inp_offset])
deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])

cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
cdef long double[::1] c_inp, c_out
cdef unsigned idx
c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
c_out = out
for idx in range(nbroadcast):
self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])

def llvm_loading_func(*args):
return LLVMDouble(args, _load=True)
Expand Down
Loading