162 lines
3.6 KiB
Python
162 lines
3.6 KiB
Python
"""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)
|
|
|
|
@contextmanager
|
|
def evaluate(x):
|
|
""" 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
|
|
"""
|
|
|
|
old = global_parameters.evaluate
|
|
|
|
try:
|
|
global_parameters.evaluate = x
|
|
yield
|
|
finally:
|
|
global_parameters.evaluate = old
|
|
|
|
|
|
@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
|