m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

918 lines
27 KiB

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