parameters.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. """Thread-safe global parameters"""
  2. from .cache import clear_cache
  3. from contextlib import contextmanager
  4. from threading import local
  5. class _global_parameters(local):
  6. """
  7. Thread-local global parameters.
  8. Explanation
  9. ===========
  10. This class generates thread-local container for SymPy's global parameters.
  11. Every global parameters must be passed as keyword argument when generating
  12. its instance.
  13. A variable, `global_parameters` is provided as default instance for this class.
  14. WARNING! Although the global parameters are thread-local, SymPy's cache is not
  15. by now.
  16. This may lead to undesired result in multi-threading operations.
  17. Examples
  18. ========
  19. >>> from sympy.abc import x
  20. >>> from sympy.core.cache import clear_cache
  21. >>> from sympy.core.parameters import global_parameters as gp
  22. >>> gp.evaluate
  23. True
  24. >>> x+x
  25. 2*x
  26. >>> log = []
  27. >>> def f():
  28. ... clear_cache()
  29. ... gp.evaluate = False
  30. ... log.append(x+x)
  31. ... clear_cache()
  32. >>> import threading
  33. >>> thread = threading.Thread(target=f)
  34. >>> thread.start()
  35. >>> thread.join()
  36. >>> print(log)
  37. [x + x]
  38. >>> gp.evaluate
  39. True
  40. >>> x+x
  41. 2*x
  42. References
  43. ==========
  44. .. [1] https://docs.python.org/3/library/threading.html
  45. """
  46. def __init__(self, **kwargs):
  47. self.__dict__.update(kwargs)
  48. def __setattr__(self, name, value):
  49. if getattr(self, name) != value:
  50. clear_cache()
  51. return super().__setattr__(name, value)
  52. global_parameters = _global_parameters(evaluate=True, distribute=True, exp_is_pow=False)
  53. class evaluate:
  54. """ Control automatic evaluation
  55. Explanation
  56. ===========
  57. This context manager controls whether or not all SymPy functions evaluate
  58. by default.
  59. Note that much of SymPy expects evaluated expressions. This functionality
  60. is experimental and is unlikely to function as intended on large
  61. expressions.
  62. Examples
  63. ========
  64. >>> from sympy import evaluate
  65. >>> from sympy.abc import x
  66. >>> print(x + x)
  67. 2*x
  68. >>> with evaluate(False):
  69. ... print(x + x)
  70. x + x
  71. """
  72. def __init__(self, x):
  73. self.x = x
  74. self.old = []
  75. def __enter__(self):
  76. self.old.append(global_parameters.evaluate)
  77. global_parameters.evaluate = self.x
  78. def __exit__(self, exc_type, exc_val, exc_tb):
  79. global_parameters.evaluate = self.old.pop()
  80. @contextmanager
  81. def distribute(x):
  82. """ Control automatic distribution of Number over Add
  83. Explanation
  84. ===========
  85. This context manager controls whether or not Mul distribute Number over
  86. Add. Plan is to avoid distributing Number over Add in all of sympy. Once
  87. that is done, this contextmanager will be removed.
  88. Examples
  89. ========
  90. >>> from sympy.abc import x
  91. >>> from sympy.core.parameters import distribute
  92. >>> print(2*(x + 1))
  93. 2*x + 2
  94. >>> with distribute(False):
  95. ... print(2*(x + 1))
  96. 2*(x + 1)
  97. """
  98. old = global_parameters.distribute
  99. try:
  100. global_parameters.distribute = x
  101. yield
  102. finally:
  103. global_parameters.distribute = old
  104. @contextmanager
  105. def _exp_is_pow(x):
  106. """
  107. Control whether `e^x` should be represented as ``exp(x)`` or a ``Pow(E, x)``.
  108. Examples
  109. ========
  110. >>> from sympy import exp
  111. >>> from sympy.abc import x
  112. >>> from sympy.core.parameters import _exp_is_pow
  113. >>> with _exp_is_pow(True): print(type(exp(x)))
  114. <class 'sympy.core.power.Pow'>
  115. >>> with _exp_is_pow(False): print(type(exp(x)))
  116. exp
  117. """
  118. old = global_parameters.exp_is_pow
  119. clear_cache()
  120. try:
  121. global_parameters.exp_is_pow = x
  122. yield
  123. finally:
  124. clear_cache()
  125. global_parameters.exp_is_pow = old