|
"""Thread-safe global parameters""" |
|
|
|
from .cache import clear_cache |
|
from contextlib import contextmanager |
|
from threading import local |
|
|
|
class _global_parameters(local): |
|
""" |
|
Thread-local global parameters. |
|
|
|
Explanation |
|
=========== |
|
|
|
This class generates thread-local container for SymPy's global parameters. |
|
Every global parameters must be passed as keyword argument when generating |
|
its instance. |
|
A variable, `global_parameters` is provided as default instance for this class. |
|
|
|
WARNING! Although the global parameters are thread-local, SymPy's cache is not |
|
by now. |
|
This may lead to undesired result in multi-threading operations. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.abc import x |
|
>>> from sympy.core.cache import clear_cache |
|
>>> from sympy.core.parameters import global_parameters as gp |
|
|
|
>>> gp.evaluate |
|
True |
|
>>> x+x |
|
2*x |
|
|
|
>>> log = [] |
|
>>> def f(): |
|
... clear_cache() |
|
... gp.evaluate = False |
|
... log.append(x+x) |
|
... clear_cache() |
|
>>> import threading |
|
>>> thread = threading.Thread(target=f) |
|
>>> thread.start() |
|
>>> thread.join() |
|
|
|
>>> print(log) |
|
[x + x] |
|
|
|
>>> gp.evaluate |
|
True |
|
>>> x+x |
|
2*x |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://docs.python.org/3/library/threading.html |
|
|
|
""" |
|
def __init__(self, **kwargs): |
|
self.__dict__.update(kwargs) |
|
|
|
def __setattr__(self, name, value): |
|
if getattr(self, name) != value: |
|
clear_cache() |
|
return super().__setattr__(name, value) |
|
|
|
global_parameters = _global_parameters(evaluate=True, distribute=True, exp_is_pow=False) |
|
|
|
class evaluate: |
|
""" Control automatic evaluation |
|
|
|
Explanation |
|
=========== |
|
|
|
This context manager controls whether or not all SymPy functions evaluate |
|
by default. |
|
|
|
Note that much of SymPy expects evaluated expressions. This functionality |
|
is experimental and is unlikely to function as intended on large |
|
expressions. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import evaluate |
|
>>> from sympy.abc import x |
|
>>> print(x + x) |
|
2*x |
|
>>> with evaluate(False): |
|
... print(x + x) |
|
x + x |
|
""" |
|
def __init__(self, x): |
|
self.x = x |
|
self.old = [] |
|
|
|
def __enter__(self): |
|
self.old.append(global_parameters.evaluate) |
|
global_parameters.evaluate = self.x |
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb): |
|
global_parameters.evaluate = self.old.pop() |
|
|
|
@contextmanager |
|
def distribute(x): |
|
""" Control automatic distribution of Number over Add |
|
|
|
Explanation |
|
=========== |
|
|
|
This context manager controls whether or not Mul distribute Number over |
|
Add. Plan is to avoid distributing Number over Add in all of sympy. Once |
|
that is done, this contextmanager will be removed. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.abc import x |
|
>>> from sympy.core.parameters import distribute |
|
>>> print(2*(x + 1)) |
|
2*x + 2 |
|
>>> with distribute(False): |
|
... print(2*(x + 1)) |
|
2*(x + 1) |
|
""" |
|
|
|
old = global_parameters.distribute |
|
|
|
try: |
|
global_parameters.distribute = x |
|
yield |
|
finally: |
|
global_parameters.distribute = old |
|
|
|
|
|
@contextmanager |
|
def _exp_is_pow(x): |
|
""" |
|
Control whether `e^x` should be represented as ``exp(x)`` or a ``Pow(E, x)``. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import exp |
|
>>> from sympy.abc import x |
|
>>> from sympy.core.parameters import _exp_is_pow |
|
>>> with _exp_is_pow(True): print(type(exp(x))) |
|
<class 'sympy.core.power.Pow'> |
|
>>> with _exp_is_pow(False): print(type(exp(x))) |
|
exp |
|
""" |
|
old = global_parameters.exp_is_pow |
|
|
|
clear_cache() |
|
try: |
|
global_parameters.exp_is_pow = x |
|
yield |
|
finally: |
|
clear_cache() |
|
global_parameters.exp_is_pow = old |
|
|