symbol.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  1. from __future__ import annotations
  2. from .assumptions import StdFactKB, _assume_defined
  3. from .basic import Basic, Atom
  4. from .cache import cacheit
  5. from .containers import Tuple
  6. from .expr import Expr, AtomicExpr
  7. from .function import AppliedUndef, FunctionClass
  8. from .kind import NumberKind, UndefinedKind
  9. from .logic import fuzzy_bool
  10. from .singleton import S
  11. from .sorting import ordered
  12. from .sympify import sympify
  13. from sympy.logic.boolalg import Boolean
  14. from sympy.utilities.iterables import sift, is_sequence
  15. from sympy.utilities.misc import filldedent
  16. import string
  17. import re as _re
  18. import random
  19. from itertools import product
  20. from typing import Any
  21. class Str(Atom):
  22. """
  23. Represents string in SymPy.
  24. Explanation
  25. ===========
  26. Previously, ``Symbol`` was used where string is needed in ``args`` of SymPy
  27. objects, e.g. denoting the name of the instance. However, since ``Symbol``
  28. represents mathematical scalar, this class should be used instead.
  29. """
  30. __slots__ = ('name',)
  31. def __new__(cls, name, **kwargs):
  32. if not isinstance(name, str):
  33. raise TypeError("name should be a string, not %s" % repr(type(name)))
  34. obj = Expr.__new__(cls, **kwargs)
  35. obj.name = name
  36. return obj
  37. def __getnewargs__(self):
  38. return (self.name,)
  39. def _hashable_content(self):
  40. return (self.name,)
  41. def _filter_assumptions(kwargs):
  42. """Split the given dict into assumptions and non-assumptions.
  43. Keys are taken as assumptions if they correspond to an
  44. entry in ``_assume_defined``.
  45. """
  46. assumptions, nonassumptions = map(dict, sift(kwargs.items(),
  47. lambda i: i[0] in _assume_defined,
  48. binary=True))
  49. Symbol._sanitize(assumptions)
  50. return assumptions, nonassumptions
  51. def _symbol(s, matching_symbol=None, **assumptions):
  52. """Return s if s is a Symbol, else if s is a string, return either
  53. the matching_symbol if the names are the same or else a new symbol
  54. with the same assumptions as the matching symbol (or the
  55. assumptions as provided).
  56. Examples
  57. ========
  58. >>> from sympy import Symbol
  59. >>> from sympy.core.symbol import _symbol
  60. >>> _symbol('y')
  61. y
  62. >>> _.is_real is None
  63. True
  64. >>> _symbol('y', real=True).is_real
  65. True
  66. >>> x = Symbol('x')
  67. >>> _symbol(x, real=True)
  68. x
  69. >>> _.is_real is None # ignore attribute if s is a Symbol
  70. True
  71. Below, the variable sym has the name 'foo':
  72. >>> sym = Symbol('foo', real=True)
  73. Since 'x' is not the same as sym's name, a new symbol is created:
  74. >>> _symbol('x', sym).name
  75. 'x'
  76. It will acquire any assumptions give:
  77. >>> _symbol('x', sym, real=False).is_real
  78. False
  79. Since 'foo' is the same as sym's name, sym is returned
  80. >>> _symbol('foo', sym)
  81. foo
  82. Any assumptions given are ignored:
  83. >>> _symbol('foo', sym, real=False).is_real
  84. True
  85. NB: the symbol here may not be the same as a symbol with the same
  86. name defined elsewhere as a result of different assumptions.
  87. See Also
  88. ========
  89. sympy.core.symbol.Symbol
  90. """
  91. if isinstance(s, str):
  92. if matching_symbol and matching_symbol.name == s:
  93. return matching_symbol
  94. return Symbol(s, **assumptions)
  95. elif isinstance(s, Symbol):
  96. return s
  97. else:
  98. raise ValueError('symbol must be string for symbol name or Symbol')
  99. def uniquely_named_symbol(xname, exprs=(), compare=str, modify=None, **assumptions):
  100. """
  101. Return a symbol whose name is derivated from *xname* but is unique
  102. from any other symbols in *exprs*.
  103. *xname* and symbol names in *exprs* are passed to *compare* to be
  104. converted to comparable forms. If ``compare(xname)`` is not unique,
  105. it is recursively passed to *modify* until unique name is acquired.
  106. Parameters
  107. ==========
  108. xname : str or Symbol
  109. Base name for the new symbol.
  110. exprs : Expr or iterable of Expr
  111. Expressions whose symbols are compared to *xname*.
  112. compare : function
  113. Unary function which transforms *xname* and symbol names from
  114. *exprs* to comparable form.
  115. modify : function
  116. Unary function which modifies the string. Default is appending
  117. the number, or increasing the number if exists.
  118. Examples
  119. ========
  120. By default, a number is appended to *xname* to generate unique name.
  121. If the number already exists, it is recursively increased.
  122. >>> from sympy.core.symbol import uniquely_named_symbol, Symbol
  123. >>> uniquely_named_symbol('x', Symbol('x'))
  124. x0
  125. >>> uniquely_named_symbol('x', (Symbol('x'), Symbol('x0')))
  126. x1
  127. >>> uniquely_named_symbol('x0', (Symbol('x1'), Symbol('x0')))
  128. x2
  129. Name generation can be controlled by passing *modify* parameter.
  130. >>> from sympy.abc import x
  131. >>> uniquely_named_symbol('x', x, modify=lambda s: 2*s)
  132. xx
  133. """
  134. def numbered_string_incr(s, start=0):
  135. if not s:
  136. return str(start)
  137. i = len(s) - 1
  138. while i != -1:
  139. if not s[i].isdigit():
  140. break
  141. i -= 1
  142. n = str(int(s[i + 1:] or start - 1) + 1)
  143. return s[:i + 1] + n
  144. default = None
  145. if is_sequence(xname):
  146. xname, default = xname
  147. x = compare(xname)
  148. if not exprs:
  149. return _symbol(x, default, **assumptions)
  150. if not is_sequence(exprs):
  151. exprs = [exprs]
  152. names = set().union(
  153. [i.name for e in exprs for i in e.atoms(Symbol)] +
  154. [i.func.name for e in exprs for i in e.atoms(AppliedUndef)])
  155. if modify is None:
  156. modify = numbered_string_incr
  157. while any(x == compare(s) for s in names):
  158. x = modify(x)
  159. return _symbol(x, default, **assumptions)
  160. _uniquely_named_symbol = uniquely_named_symbol
  161. # XXX: We need type: ignore below because Expr and Boolean are incompatible as
  162. # superclasses. Really Symbol should not be a subclass of Boolean.
  163. class Symbol(AtomicExpr, Boolean): # type: ignore
  164. """
  165. Symbol class is used to create symbolic variables.
  166. Explanation
  167. ===========
  168. Symbolic variables are placeholders for mathematical symbols that can represent numbers, constants, or any other mathematical entities and can be used in mathematical expressions and to perform symbolic computations.
  169. Assumptions:
  170. commutative = True
  171. positive = True
  172. real = True
  173. imaginary = True
  174. complex = True
  175. complete list of more assumptions- :ref:`predicates`
  176. You can override the default assumptions in the constructor.
  177. Examples
  178. ========
  179. >>> from sympy import Symbol
  180. >>> x = Symbol("x", positive=True)
  181. >>> x.is_positive
  182. True
  183. >>> x.is_negative
  184. False
  185. passing in greek letters:
  186. >>> from sympy import Symbol
  187. >>> alpha = Symbol('alpha')
  188. >>> alpha #doctest: +SKIP
  189. α
  190. Trailing digits are automatically treated like subscripts of what precedes them in the name.
  191. General format to add subscript to a symbol :
  192. ``<var_name> = Symbol('<symbol_name>_<subscript>')``
  193. >>> from sympy import Symbol
  194. >>> alpha_i = Symbol('alpha_i')
  195. >>> alpha_i #doctest: +SKIP
  196. αᵢ
  197. Parameters
  198. ==========
  199. AtomicExpr: variable name
  200. Boolean: Assumption with a boolean value(True or False)
  201. """
  202. is_comparable = False
  203. __slots__ = ('name', '_assumptions_orig', '_assumptions0')
  204. name: str
  205. is_Symbol = True
  206. is_symbol = True
  207. @property
  208. def kind(self):
  209. if self.is_commutative:
  210. return NumberKind
  211. return UndefinedKind
  212. @property
  213. def _diff_wrt(self):
  214. """Allow derivatives wrt Symbols.
  215. Examples
  216. ========
  217. >>> from sympy import Symbol
  218. >>> x = Symbol('x')
  219. >>> x._diff_wrt
  220. True
  221. """
  222. return True
  223. @staticmethod
  224. def _sanitize(assumptions, obj=None):
  225. """Remove None, convert values to bool, check commutativity *in place*.
  226. """
  227. # be strict about commutativity: cannot be None
  228. is_commutative = fuzzy_bool(assumptions.get('commutative', True))
  229. if is_commutative is None:
  230. whose = '%s ' % obj.__name__ if obj else ''
  231. raise ValueError(
  232. '%scommutativity must be True or False.' % whose)
  233. # sanitize other assumptions so 1 -> True and 0 -> False
  234. for key in list(assumptions.keys()):
  235. v = assumptions[key]
  236. if v is None:
  237. assumptions.pop(key)
  238. continue
  239. assumptions[key] = bool(v)
  240. def _merge(self, assumptions):
  241. base = self.assumptions0
  242. for k in set(assumptions) & set(base):
  243. if assumptions[k] != base[k]:
  244. raise ValueError(filldedent('''
  245. non-matching assumptions for %s: existing value
  246. is %s and new value is %s''' % (
  247. k, base[k], assumptions[k])))
  248. base.update(assumptions)
  249. return base
  250. def __new__(cls, name, **assumptions):
  251. """Symbols are identified by name and assumptions::
  252. >>> from sympy import Symbol
  253. >>> Symbol("x") == Symbol("x")
  254. True
  255. >>> Symbol("x", real=True) == Symbol("x", real=False)
  256. False
  257. """
  258. cls._sanitize(assumptions, cls)
  259. return Symbol.__xnew_cached_(cls, name, **assumptions)
  260. @staticmethod
  261. @cacheit
  262. def _canonical_assumptions(**assumptions):
  263. # This is retained purely so that srepr can include commutative=True if
  264. # that was explicitly specified but not if it was not. Ideally srepr
  265. # should not distinguish these cases because the symbols otherwise
  266. # compare equal and are considered equivalent.
  267. #
  268. # See https://github.com/sympy/sympy/issues/8873
  269. #
  270. assumptions_orig = assumptions.copy()
  271. # The only assumption that is assumed by default is commutative=True:
  272. assumptions.setdefault('commutative', True)
  273. assumptions_kb = StdFactKB(assumptions)
  274. assumptions0 = dict(assumptions_kb)
  275. return assumptions_kb, assumptions_orig, assumptions0
  276. @staticmethod
  277. def __xnew__(cls, name, **assumptions): # never cached (e.g. dummy)
  278. if not isinstance(name, str):
  279. raise TypeError("name should be a string, not %s" % repr(type(name)))
  280. obj = Expr.__new__(cls)
  281. obj.name = name
  282. assumptions_kb, assumptions_orig, assumptions0 = Symbol._canonical_assumptions(**assumptions)
  283. obj._assumptions = assumptions_kb
  284. obj._assumptions_orig = assumptions_orig
  285. obj._assumptions0 = tuple(sorted(assumptions0.items()))
  286. # The three assumptions dicts are all a little different:
  287. #
  288. # >>> from sympy import Symbol
  289. # >>> x = Symbol('x', finite=True)
  290. # >>> x.is_positive # query an assumption
  291. # >>> x._assumptions
  292. # {'finite': True, 'infinite': False, 'commutative': True, 'positive': None}
  293. # >>> x._assumptions0
  294. # {'finite': True, 'infinite': False, 'commutative': True}
  295. # >>> x._assumptions_orig
  296. # {'finite': True}
  297. #
  298. # Two symbols with the same name are equal if their _assumptions0 are
  299. # the same. Arguably it should be _assumptions_orig that is being
  300. # compared because that is more transparent to the user (it is
  301. # what was passed to the constructor modulo changes made by _sanitize).
  302. return obj
  303. @staticmethod
  304. @cacheit
  305. def __xnew_cached_(cls, name, **assumptions): # symbols are always cached
  306. return Symbol.__xnew__(cls, name, **assumptions)
  307. def __getnewargs_ex__(self):
  308. return ((self.name,), self._assumptions_orig)
  309. # NOTE: __setstate__ is not needed for pickles created by __getnewargs_ex__
  310. # but was used before Symbol was changed to use __getnewargs_ex__ in v1.9.
  311. # Pickles created in previous SymPy versions will still need __setstate__
  312. # so that they can be unpickled in SymPy > v1.9.
  313. def __setstate__(self, state):
  314. for name, value in state.items():
  315. setattr(self, name, value)
  316. def _hashable_content(self):
  317. return (self.name,) + self._assumptions0
  318. def _eval_subs(self, old, new):
  319. if old.is_Pow:
  320. from sympy.core.power import Pow
  321. return Pow(self, S.One, evaluate=False)._eval_subs(old, new)
  322. def _eval_refine(self, assumptions):
  323. return self
  324. @property
  325. def assumptions0(self):
  326. return dict(self._assumptions0)
  327. @cacheit
  328. def sort_key(self, order=None):
  329. return self.class_key(), (1, (self.name,)), S.One.sort_key(), S.One
  330. def as_dummy(self):
  331. # only put commutativity in explicitly if it is False
  332. return Dummy(self.name) if self.is_commutative is not False \
  333. else Dummy(self.name, commutative=self.is_commutative)
  334. def as_real_imag(self, deep=True, **hints):
  335. if hints.get('ignore') == self:
  336. return None
  337. else:
  338. from sympy.functions.elementary.complexes import im, re
  339. return (re(self), im(self))
  340. def is_constant(self, *wrt, **flags):
  341. if not wrt:
  342. return False
  343. return self not in wrt
  344. @property
  345. def free_symbols(self):
  346. return {self}
  347. binary_symbols = free_symbols # in this case, not always
  348. def as_set(self):
  349. return S.UniversalSet
  350. class Dummy(Symbol):
  351. """Dummy symbols are each unique, even if they have the same name:
  352. Examples
  353. ========
  354. >>> from sympy import Dummy
  355. >>> Dummy("x") == Dummy("x")
  356. False
  357. If a name is not supplied then a string value of an internal count will be
  358. used. This is useful when a temporary variable is needed and the name
  359. of the variable used in the expression is not important.
  360. >>> Dummy() #doctest: +SKIP
  361. _Dummy_10
  362. """
  363. # In the rare event that a Dummy object needs to be recreated, both the
  364. # `name` and `dummy_index` should be passed. This is used by `srepr` for
  365. # example:
  366. # >>> d1 = Dummy()
  367. # >>> d2 = eval(srepr(d1))
  368. # >>> d2 == d1
  369. # True
  370. #
  371. # If a new session is started between `srepr` and `eval`, there is a very
  372. # small chance that `d2` will be equal to a previously-created Dummy.
  373. _count = 0
  374. _prng = random.Random()
  375. _base_dummy_index = _prng.randint(10**6, 9*10**6)
  376. __slots__ = ('dummy_index',)
  377. is_Dummy = True
  378. def __new__(cls, name=None, dummy_index=None, **assumptions):
  379. if dummy_index is not None:
  380. assert name is not None, "If you specify a dummy_index, you must also provide a name"
  381. if name is None:
  382. name = "Dummy_" + str(Dummy._count)
  383. if dummy_index is None:
  384. dummy_index = Dummy._base_dummy_index + Dummy._count
  385. Dummy._count += 1
  386. cls._sanitize(assumptions, cls)
  387. obj = Symbol.__xnew__(cls, name, **assumptions)
  388. obj.dummy_index = dummy_index
  389. return obj
  390. def __getnewargs_ex__(self):
  391. return ((self.name, self.dummy_index), self._assumptions_orig)
  392. @cacheit
  393. def sort_key(self, order=None):
  394. return self.class_key(), (
  395. 2, (self.name, self.dummy_index)), S.One.sort_key(), S.One
  396. def _hashable_content(self):
  397. return Symbol._hashable_content(self) + (self.dummy_index,)
  398. class Wild(Symbol):
  399. """
  400. A Wild symbol matches anything, or anything
  401. without whatever is explicitly excluded.
  402. Parameters
  403. ==========
  404. name : str
  405. Name of the Wild instance.
  406. exclude : iterable, optional
  407. Instances in ``exclude`` will not be matched.
  408. properties : iterable of functions, optional
  409. Functions, each taking an expressions as input
  410. and returns a ``bool``. All functions in ``properties``
  411. need to return ``True`` in order for the Wild instance
  412. to match the expression.
  413. Examples
  414. ========
  415. >>> from sympy import Wild, WildFunction, cos, pi
  416. >>> from sympy.abc import x, y, z
  417. >>> a = Wild('a')
  418. >>> x.match(a)
  419. {a_: x}
  420. >>> pi.match(a)
  421. {a_: pi}
  422. >>> (3*x**2).match(a*x)
  423. {a_: 3*x}
  424. >>> cos(x).match(a)
  425. {a_: cos(x)}
  426. >>> b = Wild('b', exclude=[x])
  427. >>> (3*x**2).match(b*x)
  428. >>> b.match(a)
  429. {a_: b_}
  430. >>> A = WildFunction('A')
  431. >>> A.match(a)
  432. {a_: A_}
  433. Tips
  434. ====
  435. When using Wild, be sure to use the exclude
  436. keyword to make the pattern more precise.
  437. Without the exclude pattern, you may get matches
  438. that are technically correct, but not what you
  439. wanted. For example, using the above without
  440. exclude:
  441. >>> from sympy import symbols
  442. >>> a, b = symbols('a b', cls=Wild)
  443. >>> (2 + 3*y).match(a*x + b*y)
  444. {a_: 2/x, b_: 3}
  445. This is technically correct, because
  446. (2/x)*x + 3*y == 2 + 3*y, but you probably
  447. wanted it to not match at all. The issue is that
  448. you really did not want a and b to include x and y,
  449. and the exclude parameter lets you specify exactly
  450. this. With the exclude parameter, the pattern will
  451. not match.
  452. >>> a = Wild('a', exclude=[x, y])
  453. >>> b = Wild('b', exclude=[x, y])
  454. >>> (2 + 3*y).match(a*x + b*y)
  455. Exclude also helps remove ambiguity from matches.
  456. >>> E = 2*x**3*y*z
  457. >>> a, b = symbols('a b', cls=Wild)
  458. >>> E.match(a*b)
  459. {a_: 2*y*z, b_: x**3}
  460. >>> a = Wild('a', exclude=[x, y])
  461. >>> E.match(a*b)
  462. {a_: z, b_: 2*x**3*y}
  463. >>> a = Wild('a', exclude=[x, y, z])
  464. >>> E.match(a*b)
  465. {a_: 2, b_: x**3*y*z}
  466. Wild also accepts a ``properties`` parameter:
  467. >>> a = Wild('a', properties=[lambda k: k.is_Integer])
  468. >>> E.match(a*b)
  469. {a_: 2, b_: x**3*y*z}
  470. """
  471. is_Wild = True
  472. __slots__ = ('exclude', 'properties')
  473. def __new__(cls, name, exclude=(), properties=(), **assumptions):
  474. exclude = tuple([sympify(x) for x in exclude])
  475. properties = tuple(properties)
  476. cls._sanitize(assumptions, cls)
  477. return Wild.__xnew__(cls, name, exclude, properties, **assumptions)
  478. def __getnewargs__(self):
  479. return (self.name, self.exclude, self.properties)
  480. @staticmethod
  481. @cacheit
  482. def __xnew__(cls, name, exclude, properties, **assumptions):
  483. obj = Symbol.__xnew__(cls, name, **assumptions)
  484. obj.exclude = exclude
  485. obj.properties = properties
  486. return obj
  487. def _hashable_content(self):
  488. return super()._hashable_content() + (self.exclude, self.properties)
  489. # TODO add check against another Wild
  490. def matches(self, expr, repl_dict=None, old=False):
  491. if any(expr.has(x) for x in self.exclude):
  492. return None
  493. if not all(f(expr) for f in self.properties):
  494. return None
  495. if repl_dict is None:
  496. repl_dict = {}
  497. else:
  498. repl_dict = repl_dict.copy()
  499. repl_dict[self] = expr
  500. return repl_dict
  501. _range = _re.compile('([0-9]*:[0-9]+|[a-zA-Z]?:[a-zA-Z])')
  502. def symbols(names, *, cls=Symbol, **args) -> Any:
  503. r"""
  504. Transform strings into instances of :class:`Symbol` class.
  505. :func:`symbols` function returns a sequence of symbols with names taken
  506. from ``names`` argument, which can be a comma or whitespace delimited
  507. string, or a sequence of strings::
  508. >>> from sympy import symbols, Function
  509. >>> x, y, z = symbols('x,y,z')
  510. >>> a, b, c = symbols('a b c')
  511. The type of output is dependent on the properties of input arguments::
  512. >>> symbols('x')
  513. x
  514. >>> symbols('x,')
  515. (x,)
  516. >>> symbols('x,y')
  517. (x, y)
  518. >>> symbols(('a', 'b', 'c'))
  519. (a, b, c)
  520. >>> symbols(['a', 'b', 'c'])
  521. [a, b, c]
  522. >>> symbols({'a', 'b', 'c'})
  523. {a, b, c}
  524. If an iterable container is needed for a single symbol, set the ``seq``
  525. argument to ``True`` or terminate the symbol name with a comma::
  526. >>> symbols('x', seq=True)
  527. (x,)
  528. To reduce typing, range syntax is supported to create indexed symbols.
  529. Ranges are indicated by a colon and the type of range is determined by
  530. the character to the right of the colon. If the character is a digit
  531. then all contiguous digits to the left are taken as the nonnegative
  532. starting value (or 0 if there is no digit left of the colon) and all
  533. contiguous digits to the right are taken as 1 greater than the ending
  534. value::
  535. >>> symbols('x:10')
  536. (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)
  537. >>> symbols('x5:10')
  538. (x5, x6, x7, x8, x9)
  539. >>> symbols('x5(:2)')
  540. (x50, x51)
  541. >>> symbols('x5:10,y:5')
  542. (x5, x6, x7, x8, x9, y0, y1, y2, y3, y4)
  543. >>> symbols(('x5:10', 'y:5'))
  544. ((x5, x6, x7, x8, x9), (y0, y1, y2, y3, y4))
  545. If the character to the right of the colon is a letter, then the single
  546. letter to the left (or 'a' if there is none) is taken as the start
  547. and all characters in the lexicographic range *through* the letter to
  548. the right are used as the range::
  549. >>> symbols('x:z')
  550. (x, y, z)
  551. >>> symbols('x:c') # null range
  552. ()
  553. >>> symbols('x(:c)')
  554. (xa, xb, xc)
  555. >>> symbols(':c')
  556. (a, b, c)
  557. >>> symbols('a:d, x:z')
  558. (a, b, c, d, x, y, z)
  559. >>> symbols(('a:d', 'x:z'))
  560. ((a, b, c, d), (x, y, z))
  561. Multiple ranges are supported; contiguous numerical ranges should be
  562. separated by parentheses to disambiguate the ending number of one
  563. range from the starting number of the next::
  564. >>> symbols('x:2(1:3)')
  565. (x01, x02, x11, x12)
  566. >>> symbols(':3:2') # parsing is from left to right
  567. (00, 01, 10, 11, 20, 21)
  568. Only one pair of parentheses surrounding ranges are removed, so to
  569. include parentheses around ranges, double them. And to include spaces,
  570. commas, or colons, escape them with a backslash::
  571. >>> symbols('x((a:b))')
  572. (x(a), x(b))
  573. >>> symbols(r'x(:1\,:2)') # or r'x((:1)\,(:2))'
  574. (x(0,0), x(0,1))
  575. All newly created symbols have assumptions set according to ``args``::
  576. >>> a = symbols('a', integer=True)
  577. >>> a.is_integer
  578. True
  579. >>> x, y, z = symbols('x,y,z', real=True)
  580. >>> x.is_real and y.is_real and z.is_real
  581. True
  582. Despite its name, :func:`symbols` can create symbol-like objects like
  583. instances of Function or Wild classes. To achieve this, set ``cls``
  584. keyword argument to the desired type::
  585. >>> symbols('f,g,h', cls=Function)
  586. (f, g, h)
  587. >>> type(_[0])
  588. <class 'sympy.core.function.UndefinedFunction'>
  589. """
  590. result = []
  591. if isinstance(names, str):
  592. marker = 0
  593. splitters = r'\,', r'\:', r'\ '
  594. literals: list[tuple[str, str]] = []
  595. for splitter in splitters:
  596. if splitter in names:
  597. while chr(marker) in names:
  598. marker += 1
  599. lit_char = chr(marker)
  600. marker += 1
  601. names = names.replace(splitter, lit_char)
  602. literals.append((lit_char, splitter[1:]))
  603. def literal(s):
  604. if literals:
  605. for c, l in literals:
  606. s = s.replace(c, l)
  607. return s
  608. names = names.strip()
  609. as_seq = names.endswith(',')
  610. if as_seq:
  611. names = names[:-1].rstrip()
  612. if not names:
  613. raise ValueError('no symbols given')
  614. # split on commas
  615. names = [n.strip() for n in names.split(',')]
  616. if not all(n for n in names):
  617. raise ValueError('missing symbol between commas')
  618. # split on spaces
  619. for i in range(len(names) - 1, -1, -1):
  620. names[i: i + 1] = names[i].split()
  621. seq = args.pop('seq', as_seq)
  622. for name in names:
  623. if not name:
  624. raise ValueError('missing symbol')
  625. if ':' not in name:
  626. symbol = cls(literal(name), **args)
  627. result.append(symbol)
  628. continue
  629. split: list[str] = _range.split(name)
  630. split_list: list[list[str]] = []
  631. # remove 1 layer of bounding parentheses around ranges
  632. for i in range(len(split) - 1):
  633. if i and ':' in split[i] and split[i] != ':' and \
  634. split[i - 1].endswith('(') and \
  635. split[i + 1].startswith(')'):
  636. split[i - 1] = split[i - 1][:-1]
  637. split[i + 1] = split[i + 1][1:]
  638. for s in split:
  639. if ':' in s:
  640. if s.endswith(':'):
  641. raise ValueError('missing end range')
  642. a, b = s.split(':')
  643. if b[-1] in string.digits:
  644. a_i = 0 if not a else int(a)
  645. b_i = int(b)
  646. split_list.append([str(c) for c in range(a_i, b_i)])
  647. else:
  648. a = a or 'a'
  649. split_list.append([string.ascii_letters[c] for c in range(
  650. string.ascii_letters.index(a),
  651. string.ascii_letters.index(b) + 1)]) # inclusive
  652. if not split_list[-1]:
  653. break
  654. else:
  655. split_list.append([s])
  656. else:
  657. seq = True
  658. if len(split_list) == 1:
  659. names = split_list[0]
  660. else:
  661. names = [''.join(s) for s in product(*split_list)]
  662. if literals:
  663. result.extend([cls(literal(s), **args) for s in names])
  664. else:
  665. result.extend([cls(s, **args) for s in names])
  666. if not seq and len(result) <= 1:
  667. if not result:
  668. return ()
  669. return result[0]
  670. return tuple(result)
  671. else:
  672. for name in names:
  673. result.append(symbols(name, cls=cls, **args))
  674. return type(names)(result)
  675. def var(names, **args):
  676. """
  677. Create symbols and inject them into the global namespace.
  678. Explanation
  679. ===========
  680. This calls :func:`symbols` with the same arguments and puts the results
  681. into the *global* namespace. It's recommended not to use :func:`var` in
  682. library code, where :func:`symbols` has to be used::
  683. Examples
  684. ========
  685. >>> from sympy import var
  686. >>> var('x')
  687. x
  688. >>> x # noqa: F821
  689. x
  690. >>> var('a,ab,abc')
  691. (a, ab, abc)
  692. >>> abc # noqa: F821
  693. abc
  694. >>> var('x,y', real=True)
  695. (x, y)
  696. >>> x.is_real and y.is_real # noqa: F821
  697. True
  698. See :func:`symbols` documentation for more details on what kinds of
  699. arguments can be passed to :func:`var`.
  700. """
  701. def traverse(symbols, frame):
  702. """Recursively inject symbols to the global namespace. """
  703. for symbol in symbols:
  704. if isinstance(symbol, Basic):
  705. frame.f_globals[symbol.name] = symbol
  706. elif isinstance(symbol, FunctionClass):
  707. frame.f_globals[symbol.__name__] = symbol
  708. else:
  709. traverse(symbol, frame)
  710. from inspect import currentframe
  711. frame = currentframe().f_back
  712. try:
  713. syms = symbols(names, **args)
  714. if syms is not None:
  715. if isinstance(syms, Basic):
  716. frame.f_globals[syms.name] = syms
  717. elif isinstance(syms, FunctionClass):
  718. frame.f_globals[syms.__name__] = syms
  719. else:
  720. traverse(syms, frame)
  721. finally:
  722. del frame # break cyclic dependencies as stated in inspect docs
  723. return syms
  724. def disambiguate(*iter):
  725. """
  726. Return a Tuple containing the passed expressions with symbols
  727. that appear the same when printed replaced with numerically
  728. subscripted symbols, and all Dummy symbols replaced with Symbols.
  729. Parameters
  730. ==========
  731. iter: list of symbols or expressions.
  732. Examples
  733. ========
  734. >>> from sympy.core.symbol import disambiguate
  735. >>> from sympy import Dummy, Symbol, Tuple
  736. >>> from sympy.abc import y
  737. >>> tup = Symbol('_x'), Dummy('x'), Dummy('x')
  738. >>> disambiguate(*tup)
  739. (x_2, x, x_1)
  740. >>> eqs = Tuple(Symbol('x')/y, Dummy('x')/y)
  741. >>> disambiguate(*eqs)
  742. (x_1/y, x/y)
  743. >>> ix = Symbol('x', integer=True)
  744. >>> vx = Symbol('x')
  745. >>> disambiguate(vx + ix)
  746. (x + x_1,)
  747. To make your own mapping of symbols to use, pass only the free symbols
  748. of the expressions and create a dictionary:
  749. >>> free = eqs.free_symbols
  750. >>> mapping = dict(zip(free, disambiguate(*free)))
  751. >>> eqs.xreplace(mapping)
  752. (x_1/y, x/y)
  753. """
  754. new_iter = Tuple(*iter)
  755. key = lambda x:tuple(sorted(x.assumptions0.items()))
  756. syms = ordered(new_iter.free_symbols, keys=key)
  757. mapping = {}
  758. for s in syms:
  759. mapping.setdefault(str(s).lstrip('_'), []).append(s)
  760. reps = {}
  761. for k in mapping:
  762. # the first or only symbol doesn't get subscripted but make
  763. # sure that it's a Symbol, not a Dummy
  764. mapk0 = Symbol("%s" % (k), **mapping[k][0].assumptions0)
  765. if mapping[k][0] != mapk0:
  766. reps[mapping[k][0]] = mapk0
  767. # the others get subscripts (and are made into Symbols)
  768. skip = 0
  769. for i in range(1, len(mapping[k])):
  770. while True:
  771. name = "%s_%i" % (k, i + skip)
  772. if name not in mapping:
  773. break
  774. skip += 1
  775. ki = mapping[k][i]
  776. reps[ki] = Symbol(name, **ki.assumptions0)
  777. return new_iter.xreplace(reps)