13

I am new to SymPy, and I can't figure out

from sympy.core import S

What is S actually? And what does S.true mean?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Yathartha Joshi
  • 716
  • 1
  • 14
  • 29
  • 2
    [Singleton](http://docs.sympy.org/0.7.1/modules/core.html#module-sympy.core.singleton). – erip Jan 25 '17 at 19:45
  • 6
    I'm voting to close this question as off-topic because it shows no research effort. – erip Jan 25 '17 at 19:46
  • 3
    @erip I just tried looking for the answer and it actually wasn't obvious to me! I would not close. Also, the docs for `Singleton` are ... less than explicit about what it means or when to use it :) . – cxw Jan 25 '17 at 19:48
  • 1
    In `isympy`, you can use `S?` to get documentation. – Sven Marnach Jan 25 '17 at 19:48
  • 8
    I'm the lead developer of SymPy and I can confirm that it isn't obvious (both existing answers are slightly wrong), and this is a common question. It should not be closed. – asmeurer Jan 26 '17 at 06:19
  • 1
    I was surprised by the downvotes, this looks like an interesting question. – Francesco Bonazzi Jan 26 '17 at 13:21
  • Thanks @asmeurer and Francesco Bonazzi for the positive note. It really gave me boost :) – Yathartha Joshi Jan 26 '17 at 14:34
  • If you are using PyCharm you can Ctr+LeftClick the `S` and it will take you to its source-code. (perhaps it's not adequately documented though; haven't checked) – user Jan 27 '17 at 08:54
  • @erip No research effort has nothing to do with being off-topic. As for the user being able to find it himself, ye i guess that might be true in some cases. – user Jan 27 '17 at 08:55
  • @Fermiparadox [Disagree](http://meta.stackoverflow.com/questions/261592/how-much-research-effort-is-expected-of-stack-overflow-users). SO shouldn't be a first-stop for code questions. – erip Jan 27 '17 at 12:32
  • Clue: `print('The inverse of True is', ~S.true, 'not', ~True)` – mins Oct 11 '22 at 12:28

3 Answers3

23

There's a bit of confusion because S is actually two things.

The first thing it is is the SingletonRegistry. Several classes in SymPy appear so often that they are singletonized, that is, using some metaprogramming they are made so that they can only be instantiated once. For instance, every time you create Integer(0), this will return the same instance, Zero. All singleton instances are attributes of the S object, so Integer(0) can also be accessed as S.Zero.

Singletonization offers two advantages: it saves memory, and it allows fast comparison. It saves memory because no matter how many times the singletonized objects appear in expressions in memory, they all point to the same single instance in memory. The fast comparison comes from the fact that you can use is to compare exact instances in Python (usually, you need to use == to compare things). Hence, you can test a is S.Zero to check if a is the Integer(0) instance.

For the most part, the fact that certain objects are singletonized is an implementation detail that you shouldn't need to worry about. The primary advantage of S for end users is the convenient access to certain instances that are otherwise difficult to type, like S.Half (instead of Rational(1, 2)), or S.true (side note: S.true is the SymPy version of True. Unlike True, it does not subclass from int, so you can write things like ~S.true (not true) and it will give S.false (contrast that with ~True, which gives -2, which isn't false as a boolean).

The second thing it is is a shortcut for sympify. sympify is the function that converts Python objects such as int(1) into SymPy objects such as Integer(1). It also converts the string form of an expression into a SymPy expression like sympify(x**2) -> Symbol("x")**2. S(1) is the same thing as sympify(1) (basically, S.__call__ has been defined to call sympify).

This is for convenience, since S is a single letter. It's mostly useful for defining rational numbers. Consider an expression like x + 1/2. If you enter this directly in Python, it will evaluate the 1/2 and give 0.5 (or just 0 in Python 2, because of integer division), because both arguments are ints. However, in SymPy, you usually want the quotient of two integers to give an exact rational number. The way Python's evaluation works, at least one side of an operator needs to be a SymPy object for the SymPy evaluation to take over. You could write this as x + Rational(1, 2), but this is a lot more typing. A shorter version is x + S(1)/2. Since S(1) returns Integer(1), the division will return a Rational type, since it will call Integer.__div__, which knows how to return a Rational.

asmeurer
  • 86,894
  • 26
  • 169
  • 240
  • So, it means that if I write `if f is S.true` (where `f` is an expression) will just check whether f is true, if yes it further checks the condition. – Yathartha Joshi Jan 26 '17 at 14:55
  • Am I interpreting it right @asmeurer *Note: This is in reference with the module `sympy.solvers.solveset` line `837` [link](https://github.com/Yathartha22/sympy/blob/master/sympy/solvers/solveset.py) – Yathartha Joshi Jan 26 '17 at 15:30
  • Thanks for the clear explanation! Would you please also update the [official docs](http://docs.sympy.org/latest/modules/core.html#sympy.core.singleton.S) when you have a chance? ;) – cxw Jan 27 '17 at 13:40
  • @cxw good idea. I've opened a pull request [here](https://github.com/sympy/sympy/pull/12105). – asmeurer Jan 27 '17 at 21:38
2

As many have linked, S is for accessing singletons. Per the source, S is an instance of class SingletonRegistry. S does two things:

  • gives you access to instances such as S.One and S.Zero, which represent fundamental constants
  • lets you create or access singletons representing constants based on their values (e.g., S(1)).

The reason to use a singleton is so that you can compare objects with is rather than ==. is is faster, but only works if you know for sure that your 1 is the same as the 1 you are testing against. The code gives an example:

>>> Basic() is Basic()
False
>>> MySingleton() is MySingleton()
True
 >>> S.MySingleton is MySingleton()
True
cxw
  • 16,685
  • 2
  • 45
  • 81
  • Now, If it is `if f is S.true` where f is an expression(say, `x+1`). What would it mean? – Yathartha Joshi Jan 25 '17 at 20:04
  • @Yathartha it is checking that `f` returned exactly the [`True` singleton](http://docs.sympy.org/latest/modules/logic.html#sympy.logic.boolalg.BooleanTrue). What that means depends on `f`. I don't know enough sympy to know how `x+1` could return a boolean variable, I'm sorry to say. – cxw Jan 25 '17 at 20:10
  • @Yathartha Glad to hear it! If this answer or Sven's (or both) was helpful, would you please hit the up arrow next to the helpful answer(s)? If either answer works particularly well for you, would you please hit the checkmark next to that answer? Those actions will let folks know that you have received help. Thanks! – cxw Jan 25 '17 at 20:47
0

In short

S.true is a singleton used by SymPy to represent true, and there is a difference with Python True:

print(f'The inverse of True is {~S.true}, not {~True}')

prints:

The inverse of True is False, not -2

However, such a difference is usually hidden to the user, and in most cases there isn't any need to use S.true directly as SymPy takes care of that for us, using the function S() internally, a shorthand for sympify().

This function and the associated singletons are part of S, the singleton registry.

Details follow.


S is the registry for singletons

In your context, S is the regular shortcut for singleton registry (sympy.core.singleton.SingletonRegistry). This class is itself created by SymPy based on metaclass Singleton.

A singleton relies on object uniqueness instead of value equality, e.g., the singleton S.Half is used for rational value 1/2, whatever the way it has been obtained, e.g., by dividing 2/4 or as the result of cos(5*pi/3). Using this singleton allows equality checks to be based on the singleton ID/address rather than on a value, operator is is used. Such comparison is easier and quicker. More on singleton pattern.

For practical purposes, SingletonRegistry holds references for constants like 0, 1, False, True, EmptySet, etc. in the form of singletons, and can be accessed using its shortcut S.

S is also the shortcut for simpify

Note S, used as a function, is also the shortcut for function sympify which is used by SymPy to make everything used by the program compatible with SymPy, e.g. it identifies strings associated with symbols and give them the correct type. Part of this sympyfication task is to convert constants into their singleton equivalent, when one exists, and True is automatically converted into S.true when encountered.

S.true is the singleton holding True

Therefore S.true (lowercase t) accesses the singleton used by SymPy to represent a True value. Normally there isn't any need to use the singleton instead of the Boolean value as in SymPy True anyway evaluates to S.true when sympify() is called. However there are exceptions detailed in the documentation about SymPy Boolean functions:

SymPy version of True, a singleton that can be accessed via S.true.

This is the SymPy version of True, for use in the logic module. The primary advantage of using true instead of True is that shorthand Boolean operations like ~ and >> will work as expected on this class, whereas with True they act bitwise on 1. Functions in the logic module will return this class when they evaluate to true.

When to use S.true?

From the same page:

There is liable to be some confusion as to when True should be used and when S.true should be used in various contexts throughout SymPy. An important thing to remember is that sympify(True) returns S.true. This means that for the most part, you can just use True and it will automatically be converted to S.true when necessary, similar to how you can generally use 1 instead of S.One.

The rule of thumb is:

“If the boolean in question can be replaced by an arbitrary symbolic Boolean, like Or(x, y) or x > 1, use S.true. Otherwise, use True

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mins
  • 6,478
  • 12
  • 56
  • 75