Skip to content

Commit 66aa3c0

Browse files
author
Release Manager
committed
Trac #24171: Formal set membership function
To express solution sets from solvers an expression-is-element-of-set relation is needed. For ease of implementation this can be made a formal function `element_of`. It depends on sets being made coercible into SR. The present ticket plays safe and only does this for finite sets and a few standard infinite sets: `NN`, `ZZ`, `QQ`, `AA`; and `RealSet`s. `element_of` converts to !SymPy's `Contains`. This is useful in combination with #31931, which adds !SymPy conversions to some of the above sets. URL: https://trac.sagemath.org/24171 Reported by: rws Ticket author(s): Ralf Stephan, Matthias Koeppe Reviewer(s): Travis Scrimshaw, Matthias Koeppe
2 parents dae5f2c + a8c94ca commit 66aa3c0

File tree

4 files changed

+96
-4
lines changed

4 files changed

+96
-4
lines changed

src/sage/functions/other.py

+72
Original file line numberDiff line numberDiff line change
@@ -2285,3 +2285,75 @@ def _evalf_(self, poly, index, parent=None, algorithm=None):
22852285

22862286
complex_root_of = Function_crootof()
22872287

2288+
2289+
class Function_elementof(BuiltinFunction):
2290+
"""
2291+
Formal set membership function that is only accessible internally.
2292+
2293+
This function is called to express a set membership statement,
2294+
usually as part of a solution set returned by ``solve()``.
2295+
See :class:`sage.sets.set.Set` and :class:`sage.sets.real_set.RealSet`
2296+
for possible set arguments.
2297+
2298+
EXAMPLES::
2299+
2300+
sage: from sage.functions.other import element_of
2301+
sage: element_of(x, SR(ZZ))
2302+
element_of(x, Integer Ring)
2303+
sage: element_of(sin(x), SR(QQ))
2304+
element_of(sin(x), Rational Field)
2305+
sage: element_of(x, SR(RealSet.open_closed(0,1)))
2306+
element_of(x, (0, 1])
2307+
sage: element_of(x, SR(Set([4,6,8])))
2308+
element_of(x, {8, 4, 6})
2309+
"""
2310+
def __init__(self):
2311+
"""
2312+
EXAMPLES::
2313+
2314+
sage: from sage.functions.other import element_of
2315+
sage: loads(dumps(element_of))
2316+
element_of
2317+
"""
2318+
BuiltinFunction.__init__(self, "element_of", nargs=2,
2319+
conversions=dict(sympy='Contains'))
2320+
2321+
def _eval_(self, x, s):
2322+
"""
2323+
EXAMPLES::
2324+
2325+
sage: from sage.functions.other import element_of
2326+
sage: element_of(x, SR(RealSet(-oo, oo)))
2327+
element_of(x, (-oo, +oo))
2328+
sage: element_of(x, 0)
2329+
Traceback (most recent call last):
2330+
...
2331+
ValueError: not a set: 0
2332+
"""
2333+
from sage.categories.sets_cat import Sets
2334+
if not s in Sets():
2335+
raise ValueError("not a set: {}".format(s))
2336+
2337+
def _latex_(self):
2338+
r"""
2339+
EXAMPLES::
2340+
2341+
sage: from sage.functions.other import element_of
2342+
sage: latex(element_of)
2343+
\in
2344+
"""
2345+
return r'\in'
2346+
2347+
def _print_latex_(self, ex, s):
2348+
r"""
2349+
EXAMPLES::
2350+
2351+
sage: from sage.functions.other import element_of
2352+
sage: latex(element_of(x, SR(ZZ)))
2353+
x \in \Bold{Z}
2354+
sage: latex(element_of(x, SR(Set([4,6,8]))))
2355+
x \in \left\{8, 4, 6\right\}
2356+
"""
2357+
return r"{} \in {}".format(latex(ex), latex(s))
2358+
2359+
element_of = Function_elementof()

src/sage/libs/pynac/pynac.pyx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1190,7 +1190,7 @@ cdef bint py_is_real(a):
11901190
return False
11911191
except NotImplementedError:
11921192
return False
1193-
except AttributeError:
1193+
except (TypeError, AttributeError):
11941194
pass
11951195
return py_imag(a) == 0
11961196

src/sage/symbolic/random_tests.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from sage.symbolic.constants import (pi, e, golden_ratio, log2, euler_gamma,
2121
catalan, khinchin, twinprime, mertens)
2222
from sage.functions.hypergeometric import hypergeometric
23-
from sage.functions.other import cases
23+
from sage.functions.other import (cases, element_of)
2424
from sage.symbolic.comparison import mixed_order
2525

2626
###################################################################
@@ -48,13 +48,13 @@ def _mk_full_functions():
4848
Note that this doctest will produce different output whenever a
4949
symbolic function is added or removed.
5050
"""
51+
excluded = [hypergeometric, cases, element_of]
5152
items = sorted(symbol_table['functions'].items())
5253
return [(1.0, f, f.number_of_arguments())
5354
for (name, f) in items
5455
if hasattr(f, 'number_of_arguments') and
5556
f.number_of_arguments() > 0 and
56-
f != hypergeometric and
57-
f != cases]
57+
f not in excluded]
5858

5959
# For creating simple expressions
6060

src/sage/symbolic/ring.pyx

+20
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,17 @@ cdef class SymbolicRing(CommutativeRing):
254254
sage: SR(complex(2,-3))
255255
(2-3j)
256256
257+
Any proper subset of the complex numbers::
258+
259+
sage: SR(NN)
260+
Non negative integer semiring
261+
sage: SR(ZZ)
262+
Integer Ring
263+
sage: SR(Set([1/2, 2/3, 3/4]))
264+
{3/4, 2/3, 1/2}
265+
sage: SR(RealSet(0, 1))
266+
(0, 1)
267+
257268
TESTS::
258269
259270
sage: SR._coerce_(int(5))
@@ -364,6 +375,7 @@ cdef class SymbolicRing(CommutativeRing):
364375
from sage.rings.infinity import (infinity, minus_infinity,
365376
unsigned_infinity)
366377
from sage.structure.factorization import Factorization
378+
from sage.categories.sets_cat import Sets
367379

368380
if isinstance(x, RealNumber):
369381
if x.is_NaN():
@@ -392,6 +404,14 @@ cdef class SymbolicRing(CommutativeRing):
392404
elif isinstance(x, Factorization):
393405
from sage.misc.all import prod
394406
return prod([SR(p)**e for p,e in x], SR(x.unit()))
407+
elif x in Sets():
408+
from sage.rings.all import NN, ZZ, QQ, AA
409+
from sage.sets.real_set import RealSet
410+
if (x.is_finite() or x in (NN, ZZ, QQ, AA)
411+
or isinstance(x, RealSet)):
412+
exp = x
413+
else:
414+
raise TypeError(f"unable to convert {x!r} to a symbolic expression")
395415
else:
396416
raise TypeError(f"unable to convert {x!r} to a symbolic expression")
397417

0 commit comments

Comments
 (0)