symbol.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  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. class Symbol(AtomicExpr, Boolean):
  162. """
  163. Assumptions:
  164. commutative = True
  165. You can override the default assumptions in the constructor.
  166. Examples
  167. ========
  168. >>> from sympy import symbols
  169. >>> A,B = symbols('A,B', commutative = False)
  170. >>> bool(A*B != B*A)
  171. True
  172. >>> bool(A*B*2 == 2*A*B) == True # multiplication by scalars is commutative
  173. True
  174. """
  175. is_comparable = False
  176. __slots__ = ('name', '_assumptions_orig', '_assumptions0')
  177. name: str
  178. is_Symbol = True
  179. is_symbol = True
  180. @property
  181. def kind(self):
  182. if self.is_commutative:
  183. return NumberKind
  184. return UndefinedKind
  185. @property
  186. def _diff_wrt(self):
  187. """Allow derivatives wrt Symbols.
  188. Examples
  189. ========
  190. >>> from sympy import Symbol
  191. >>> x = Symbol('x')
  192. >>> x._diff_wrt
  193. True
  194. """
  195. return True
  196. @staticmethod
  197. def _sanitize(assumptions, obj=None):
  198. """Remove None, convert values to bool, check commutativity *in place*.
  199. """
  200. # be strict about commutativity: cannot be None
  201. is_commutative = fuzzy_bool(assumptions.get('commutative', True))
  202. if is_commutative is None:
  203. whose = '%s ' % obj.__name__ if obj else ''
  204. raise ValueError(
  205. '%scommutativity must be True or False.' % whose)
  206. # sanitize other assumptions so 1 -> True and 0 -> False
  207. for key in list(assumptions.keys()):
  208. v = assumptions[key]
  209. if v is None:
  210. assumptions.pop(key)
  211. continue
  212. assumptions[key] = bool(v)
  213. def _merge(self, assumptions):
  214. base = self.assumptions0
  215. for k in set(assumptions) & set(base):
  216. if assumptions[k] != base[k]:
  217. raise ValueError(filldedent('''
  218. non-matching assumptions for %s: existing value
  219. is %s and new value is %s''' % (
  220. k, base[k], assumptions[k])))
  221. base.update(assumptions)
  222. return base
  223. def __new__(cls, name, **assumptions):
  224. """Symbols are identified by name and assumptions::
  225. >>> from sympy import Symbol
  226. >>> Symbol("x") == Symbol("x")
  227. True
  228. >>> Symbol("x", real=True) == Symbol("x", real=False)
  229. False
  230. """
  231. cls._sanitize(assumptions, cls)
  232. return Symbol.__xnew_cached_(cls, name, **assumptions)
  233. @staticmethod
  234. def __xnew__(cls, name, **assumptions): # never cached (e.g. dummy)
  235. if not isinstance(name, str):
  236. raise TypeError("name should be a string, not %s" % repr(type(name)))
  237. # This is retained purely so that srepr can include commutative=True if
  238. # that was explicitly specified but not if it was not. Ideally srepr
  239. # should not distinguish these cases because the symbols otherwise
  240. # compare equal and are considered equivalent.
  241. #
  242. # See https://github.com/sympy/sympy/issues/8873
  243. #
  244. assumptions_orig = assumptions.copy()
  245. # The only assumption that is assumed by default is comutative=True:
  246. assumptions.setdefault('commutative', True)
  247. assumptions_kb = StdFactKB(assumptions)
  248. assumptions0 = dict(assumptions_kb)
  249. obj = Expr.__new__(cls)
  250. obj.name = name
  251. obj._assumptions = assumptions_kb
  252. obj._assumptions_orig = assumptions_orig
  253. obj._assumptions0 = assumptions0
  254. # The three assumptions dicts are all a little different:
  255. #
  256. # >>> from sympy import Symbol
  257. # >>> x = Symbol('x', finite=True)
  258. # >>> x.is_positive # query an assumption
  259. # >>> x._assumptions
  260. # {'finite': True, 'infinite': False, 'commutative': True, 'positive': None}
  261. # >>> x._assumptions0
  262. # {'finite': True, 'infinite': False, 'commutative': True}
  263. # >>> x._assumptions_orig
  264. # {'finite': True}
  265. #
  266. # Two symbols with the same name are equal if their _assumptions0 are
  267. # the same. Arguably it should be _assumptions_orig that is being
  268. # compared because that is more transparent to the user (it is
  269. # what was passed to the constructor modulo changes made by _sanitize).
  270. return obj
  271. @staticmethod
  272. @cacheit
  273. def __xnew_cached_(cls, name, **assumptions): # symbols are always cached
  274. return Symbol.__xnew__(cls, name, **assumptions)
  275. def __getnewargs_ex__(self):
  276. return ((self.name,), self._assumptions_orig)
  277. # NOTE: __setstate__ is not needed for pickles created by __getnewargs_ex__
  278. # but was used before Symbol was changed to use __getnewargs_ex__ in v1.9.
  279. # Pickles created in previous SymPy versions will still need __setstate__
  280. # so that they can be unpickled in SymPy > v1.9.
  281. def __setstate__(self, state):
  282. for name, value in state.items():
  283. setattr(self, name, value)
  284. def _hashable_content(self):
  285. # Note: user-specified assumptions not hashed, just derived ones
  286. return (self.name,) + tuple(sorted(self.assumptions0.items()))
  287. def _eval_subs(self, old, new):
  288. if old.is_Pow:
  289. from sympy.core.power import Pow
  290. return Pow(self, S.One, evaluate=False)._eval_subs(old, new)
  291. def _eval_refine(self, assumptions):
  292. return self
  293. @property
  294. def assumptions0(self):
  295. return self._assumptions0.copy()
  296. @cacheit
  297. def sort_key(self, order=None):
  298. return self.class_key(), (1, (self.name,)), S.One.sort_key(), S.One
  299. def as_dummy(self):
  300. # only put commutativity in explicitly if it is False
  301. return Dummy(self.name) if self.is_commutative is not False \
  302. else Dummy(self.name, commutative=self.is_commutative)
  303. def as_real_imag(self, deep=True, **hints):
  304. if hints.get('ignore') == self:
  305. return None
  306. else:
  307. from sympy.functions.elementary.complexes import im, re
  308. return (re(self), im(self))
  309. def is_constant(self, *wrt, **flags):
  310. if not wrt:
  311. return False
  312. return self not in wrt
  313. @property
  314. def free_symbols(self):
  315. return {self}
  316. binary_symbols = free_symbols # in this case, not always
  317. def as_set(self):
  318. return S.UniversalSet
  319. class Dummy(Symbol):
  320. """Dummy symbols are each unique, even if they have the same name:
  321. Examples
  322. ========
  323. >>> from sympy import Dummy
  324. >>> Dummy("x") == Dummy("x")
  325. False
  326. If a name is not supplied then a string value of an internal count will be
  327. used. This is useful when a temporary variable is needed and the name
  328. of the variable used in the expression is not important.
  329. >>> Dummy() #doctest: +SKIP
  330. _Dummy_10
  331. """
  332. # In the rare event that a Dummy object needs to be recreated, both the
  333. # `name` and `dummy_index` should be passed. This is used by `srepr` for
  334. # example:
  335. # >>> d1 = Dummy()
  336. # >>> d2 = eval(srepr(d1))
  337. # >>> d2 == d1
  338. # True
  339. #
  340. # If a new session is started between `srepr` and `eval`, there is a very
  341. # small chance that `d2` will be equal to a previously-created Dummy.
  342. _count = 0
  343. _prng = random.Random()
  344. _base_dummy_index = _prng.randint(10**6, 9*10**6)
  345. __slots__ = ('dummy_index',)
  346. is_Dummy = True
  347. def __new__(cls, name=None, dummy_index=None, **assumptions):
  348. if dummy_index is not None:
  349. assert name is not None, "If you specify a dummy_index, you must also provide a name"
  350. if name is None:
  351. name = "Dummy_" + str(Dummy._count)
  352. if dummy_index is None:
  353. dummy_index = Dummy._base_dummy_index + Dummy._count
  354. Dummy._count += 1
  355. cls._sanitize(assumptions, cls)
  356. obj = Symbol.__xnew__(cls, name, **assumptions)
  357. obj.dummy_index = dummy_index
  358. return obj
  359. def __getnewargs_ex__(self):
  360. return ((self.name, self.dummy_index), self._assumptions_orig)
  361. @cacheit
  362. def sort_key(self, order=None):
  363. return self.class_key(), (
  364. 2, (self.name, self.dummy_index)), S.One.sort_key(), S.One
  365. def _hashable_content(self):
  366. return Symbol._hashable_content(self) + (self.dummy_index,)
  367. class Wild(Symbol):
  368. """
  369. A Wild symbol matches anything, or anything
  370. without whatever is explicitly excluded.
  371. Parameters
  372. ==========
  373. name : str
  374. Name of the Wild instance.
  375. exclude : iterable, optional
  376. Instances in ``exclude`` will not be matched.
  377. properties : iterable of functions, optional
  378. Functions, each taking an expressions as input
  379. and returns a ``bool``. All functions in ``properties``
  380. need to return ``True`` in order for the Wild instance
  381. to match the expression.
  382. Examples
  383. ========
  384. >>> from sympy import Wild, WildFunction, cos, pi
  385. >>> from sympy.abc import x, y, z
  386. >>> a = Wild('a')
  387. >>> x.match(a)
  388. {a_: x}
  389. >>> pi.match(a)
  390. {a_: pi}
  391. >>> (3*x**2).match(a*x)
  392. {a_: 3*x}
  393. >>> cos(x).match(a)
  394. {a_: cos(x)}
  395. >>> b = Wild('b', exclude=[x])
  396. >>> (3*x**2).match(b*x)
  397. >>> b.match(a)
  398. {a_: b_}
  399. >>> A = WildFunction('A')
  400. >>> A.match(a)
  401. {a_: A_}
  402. Tips
  403. ====
  404. When using Wild, be sure to use the exclude
  405. keyword to make the pattern more precise.
  406. Without the exclude pattern, you may get matches
  407. that are technically correct, but not what you
  408. wanted. For example, using the above without
  409. exclude:
  410. >>> from sympy import symbols
  411. >>> a, b = symbols('a b', cls=Wild)
  412. >>> (2 + 3*y).match(a*x + b*y)
  413. {a_: 2/x, b_: 3}
  414. This is technically correct, because
  415. (2/x)*x + 3*y == 2 + 3*y, but you probably
  416. wanted it to not match at all. The issue is that
  417. you really did not want a and b to include x and y,
  418. and the exclude parameter lets you specify exactly
  419. this. With the exclude parameter, the pattern will
  420. not match.
  421. >>> a = Wild('a', exclude=[x, y])
  422. >>> b = Wild('b', exclude=[x, y])
  423. >>> (2 + 3*y).match(a*x + b*y)
  424. Exclude also helps remove ambiguity from matches.
  425. >>> E = 2*x**3*y*z
  426. >>> a, b = symbols('a b', cls=Wild)
  427. >>> E.match(a*b)
  428. {a_: 2*y*z, b_: x**3}
  429. >>> a = Wild('a', exclude=[x, y])
  430. >>> E.match(a*b)
  431. {a_: z, b_: 2*x**3*y}
  432. >>> a = Wild('a', exclude=[x, y, z])
  433. >>> E.match(a*b)
  434. {a_: 2, b_: x**3*y*z}
  435. Wild also accepts a ``properties`` parameter:
  436. >>> a = Wild('a', properties=[lambda k: k.is_Integer])
  437. >>> E.match(a*b)
  438. {a_: 2, b_: x**3*y*z}
  439. """
  440. is_Wild = True
  441. __slots__ = ('exclude', 'properties')
  442. def __new__(cls, name, exclude=(), properties=(), **assumptions):
  443. exclude = tuple([sympify(x) for x in exclude])
  444. properties = tuple(properties)
  445. cls._sanitize(assumptions, cls)
  446. return Wild.__xnew__(cls, name, exclude, properties, **assumptions)
  447. def __getnewargs__(self):
  448. return (self.name, self.exclude, self.properties)
  449. @staticmethod
  450. @cacheit
  451. def __xnew__(cls, name, exclude, properties, **assumptions):
  452. obj = Symbol.__xnew__(cls, name, **assumptions)
  453. obj.exclude = exclude
  454. obj.properties = properties
  455. return obj
  456. def _hashable_content(self):
  457. return super()._hashable_content() + (self.exclude, self.properties)
  458. # TODO add check against another Wild
  459. def matches(self, expr, repl_dict=None, old=False):
  460. if any(expr.has(x) for x in self.exclude):
  461. return None
  462. if not all(f(expr) for f in self.properties):
  463. return None
  464. if repl_dict is None:
  465. repl_dict = {}
  466. else:
  467. repl_dict = repl_dict.copy()
  468. repl_dict[self] = expr
  469. return repl_dict
  470. _range = _re.compile('([0-9]*:[0-9]+|[a-zA-Z]?:[a-zA-Z])')
  471. def symbols(names, *, cls=Symbol, **args) -> Any:
  472. r"""
  473. Transform strings into instances of :class:`Symbol` class.
  474. :func:`symbols` function returns a sequence of symbols with names taken
  475. from ``names`` argument, which can be a comma or whitespace delimited
  476. string, or a sequence of strings::
  477. >>> from sympy import symbols, Function
  478. >>> x, y, z = symbols('x,y,z')
  479. >>> a, b, c = symbols('a b c')
  480. The type of output is dependent on the properties of input arguments::
  481. >>> symbols('x')
  482. x
  483. >>> symbols('x,')
  484. (x,)
  485. >>> symbols('x,y')
  486. (x, y)
  487. >>> symbols(('a', 'b', 'c'))
  488. (a, b, c)
  489. >>> symbols(['a', 'b', 'c'])
  490. [a, b, c]
  491. >>> symbols({'a', 'b', 'c'})
  492. {a, b, c}
  493. If an iterable container is needed for a single symbol, set the ``seq``
  494. argument to ``True`` or terminate the symbol name with a comma::
  495. >>> symbols('x', seq=True)
  496. (x,)
  497. To reduce typing, range syntax is supported to create indexed symbols.
  498. Ranges are indicated by a colon and the type of range is determined by
  499. the character to the right of the colon. If the character is a digit
  500. then all contiguous digits to the left are taken as the nonnegative
  501. starting value (or 0 if there is no digit left of the colon) and all
  502. contiguous digits to the right are taken as 1 greater than the ending
  503. value::
  504. >>> symbols('x:10')
  505. (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)
  506. >>> symbols('x5:10')
  507. (x5, x6, x7, x8, x9)
  508. >>> symbols('x5(:2)')
  509. (x50, x51)
  510. >>> symbols('x5:10,y:5')
  511. (x5, x6, x7, x8, x9, y0, y1, y2, y3, y4)
  512. >>> symbols(('x5:10', 'y:5'))
  513. ((x5, x6, x7, x8, x9), (y0, y1, y2, y3, y4))
  514. If the character to the right of the colon is a letter, then the single
  515. letter to the left (or 'a' if there is none) is taken as the start
  516. and all characters in the lexicographic range *through* the letter to
  517. the right are used as the range::
  518. >>> symbols('x:z')
  519. (x, y, z)
  520. >>> symbols('x:c') # null range
  521. ()
  522. >>> symbols('x(:c)')
  523. (xa, xb, xc)
  524. >>> symbols(':c')
  525. (a, b, c)
  526. >>> symbols('a:d, x:z')
  527. (a, b, c, d, x, y, z)
  528. >>> symbols(('a:d', 'x:z'))
  529. ((a, b, c, d), (x, y, z))
  530. Multiple ranges are supported; contiguous numerical ranges should be
  531. separated by parentheses to disambiguate the ending number of one
  532. range from the starting number of the next::
  533. >>> symbols('x:2(1:3)')
  534. (x01, x02, x11, x12)
  535. >>> symbols(':3:2') # parsing is from left to right
  536. (00, 01, 10, 11, 20, 21)
  537. Only one pair of parentheses surrounding ranges are removed, so to
  538. include parentheses around ranges, double them. And to include spaces,
  539. commas, or colons, escape them with a backslash::
  540. >>> symbols('x((a:b))')
  541. (x(a), x(b))
  542. >>> symbols(r'x(:1\,:2)') # or r'x((:1)\,(:2))'
  543. (x(0,0), x(0,1))
  544. All newly created symbols have assumptions set according to ``args``::
  545. >>> a = symbols('a', integer=True)
  546. >>> a.is_integer
  547. True
  548. >>> x, y, z = symbols('x,y,z', real=True)
  549. >>> x.is_real and y.is_real and z.is_real
  550. True
  551. Despite its name, :func:`symbols` can create symbol-like objects like
  552. instances of Function or Wild classes. To achieve this, set ``cls``
  553. keyword argument to the desired type::
  554. >>> symbols('f,g,h', cls=Function)
  555. (f, g, h)
  556. >>> type(_[0])
  557. <class 'sympy.core.function.UndefinedFunction'>
  558. """
  559. result = []
  560. if isinstance(names, str):
  561. marker = 0
  562. splitters = r'\,', r'\:', r'\ '
  563. literals: list[tuple[str, str]] = []
  564. for splitter in splitters:
  565. if splitter in names:
  566. while chr(marker) in names:
  567. marker += 1
  568. lit_char = chr(marker)
  569. marker += 1
  570. names = names.replace(splitter, lit_char)
  571. literals.append((lit_char, splitter[1:]))
  572. def literal(s):
  573. if literals:
  574. for c, l in literals:
  575. s = s.replace(c, l)
  576. return s
  577. names = names.strip()
  578. as_seq = names.endswith(',')
  579. if as_seq:
  580. names = names[:-1].rstrip()
  581. if not names:
  582. raise ValueError('no symbols given')
  583. # split on commas
  584. names = [n.strip() for n in names.split(',')]
  585. if not all(n for n in names):
  586. raise ValueError('missing symbol between commas')
  587. # split on spaces
  588. for i in range(len(names) - 1, -1, -1):
  589. names[i: i + 1] = names[i].split()
  590. seq = args.pop('seq', as_seq)
  591. for name in names:
  592. if not name:
  593. raise ValueError('missing symbol')
  594. if ':' not in name:
  595. symbol = cls(literal(name), **args)
  596. result.append(symbol)
  597. continue
  598. split: list[str] = _range.split(name)
  599. split_list: list[list[str]] = []
  600. # remove 1 layer of bounding parentheses around ranges
  601. for i in range(len(split) - 1):
  602. if i and ':' in split[i] and split[i] != ':' and \
  603. split[i - 1].endswith('(') and \
  604. split[i + 1].startswith(')'):
  605. split[i - 1] = split[i - 1][:-1]
  606. split[i + 1] = split[i + 1][1:]
  607. for s in split:
  608. if ':' in s:
  609. if s.endswith(':'):
  610. raise ValueError('missing end range')
  611. a, b = s.split(':')
  612. if b[-1] in string.digits:
  613. a_i = 0 if not a else int(a)
  614. b_i = int(b)
  615. split_list.append([str(c) for c in range(a_i, b_i)])
  616. else:
  617. a = a or 'a'
  618. split_list.append([string.ascii_letters[c] for c in range(
  619. string.ascii_letters.index(a),
  620. string.ascii_letters.index(b) + 1)]) # inclusive
  621. if not split_list[-1]:
  622. break
  623. else:
  624. split_list.append([s])
  625. else:
  626. seq = True
  627. if len(split_list) == 1:
  628. names = split_list[0]
  629. else:
  630. names = [''.join(s) for s in product(*split_list)]
  631. if literals:
  632. result.extend([cls(literal(s), **args) for s in names])
  633. else:
  634. result.extend([cls(s, **args) for s in names])
  635. if not seq and len(result) <= 1:
  636. if not result:
  637. return ()
  638. return result[0]
  639. return tuple(result)
  640. else:
  641. for name in names:
  642. result.append(symbols(name, cls=cls, **args))
  643. return type(names)(result)
  644. def var(names, **args):
  645. """
  646. Create symbols and inject them into the global namespace.
  647. Explanation
  648. ===========
  649. This calls :func:`symbols` with the same arguments and puts the results
  650. into the *global* namespace. It's recommended not to use :func:`var` in
  651. library code, where :func:`symbols` has to be used::
  652. Examples
  653. ========
  654. >>> from sympy import var
  655. >>> var('x')
  656. x
  657. >>> x # noqa: F821
  658. x
  659. >>> var('a,ab,abc')
  660. (a, ab, abc)
  661. >>> abc # noqa: F821
  662. abc
  663. >>> var('x,y', real=True)
  664. (x, y)
  665. >>> x.is_real and y.is_real # noqa: F821
  666. True
  667. See :func:`symbols` documentation for more details on what kinds of
  668. arguments can be passed to :func:`var`.
  669. """
  670. def traverse(symbols, frame):
  671. """Recursively inject symbols to the global namespace. """
  672. for symbol in symbols:
  673. if isinstance(symbol, Basic):
  674. frame.f_globals[symbol.name] = symbol
  675. elif isinstance(symbol, FunctionClass):
  676. frame.f_globals[symbol.__name__] = symbol
  677. else:
  678. traverse(symbol, frame)
  679. from inspect import currentframe
  680. frame = currentframe().f_back
  681. try:
  682. syms = symbols(names, **args)
  683. if syms is not None:
  684. if isinstance(syms, Basic):
  685. frame.f_globals[syms.name] = syms
  686. elif isinstance(syms, FunctionClass):
  687. frame.f_globals[syms.__name__] = syms
  688. else:
  689. traverse(syms, frame)
  690. finally:
  691. del frame # break cyclic dependencies as stated in inspect docs
  692. return syms
  693. def disambiguate(*iter):
  694. """
  695. Return a Tuple containing the passed expressions with symbols
  696. that appear the same when printed replaced with numerically
  697. subscripted symbols, and all Dummy symbols replaced with Symbols.
  698. Parameters
  699. ==========
  700. iter: list of symbols or expressions.
  701. Examples
  702. ========
  703. >>> from sympy.core.symbol import disambiguate
  704. >>> from sympy import Dummy, Symbol, Tuple
  705. >>> from sympy.abc import y
  706. >>> tup = Symbol('_x'), Dummy('x'), Dummy('x')
  707. >>> disambiguate(*tup)
  708. (x_2, x, x_1)
  709. >>> eqs = Tuple(Symbol('x')/y, Dummy('x')/y)
  710. >>> disambiguate(*eqs)
  711. (x_1/y, x/y)
  712. >>> ix = Symbol('x', integer=True)
  713. >>> vx = Symbol('x')
  714. >>> disambiguate(vx + ix)
  715. (x + x_1,)
  716. To make your own mapping of symbols to use, pass only the free symbols
  717. of the expressions and create a dictionary:
  718. >>> free = eqs.free_symbols
  719. >>> mapping = dict(zip(free, disambiguate(*free)))
  720. >>> eqs.xreplace(mapping)
  721. (x_1/y, x/y)
  722. """
  723. new_iter = Tuple(*iter)
  724. key = lambda x:tuple(sorted(x.assumptions0.items()))
  725. syms = ordered(new_iter.free_symbols, keys=key)
  726. mapping = {}
  727. for s in syms:
  728. mapping.setdefault(str(s).lstrip('_'), []).append(s)
  729. reps = {}
  730. for k in mapping:
  731. # the first or only symbol doesn't get subscripted but make
  732. # sure that it's a Symbol, not a Dummy
  733. mapk0 = Symbol("%s" % (k), **mapping[k][0].assumptions0)
  734. if mapping[k][0] != mapk0:
  735. reps[mapping[k][0]] = mapk0
  736. # the others get subscripts (and are made into Symbols)
  737. skip = 0
  738. for i in range(1, len(mapping[k])):
  739. while True:
  740. name = "%s_%i" % (k, i + skip)
  741. if name not in mapping:
  742. break
  743. skip += 1
  744. ki = mapping[k][i]
  745. reps[ki] = Symbol(name, **ki.assumptions0)
  746. return new_iter.xreplace(reps)