图片解析应用
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.

368 lines
12 KiB

  1. from sympy.core.function import Derivative
  2. from sympy.core.function import UndefinedFunction, AppliedUndef
  3. from sympy.core.symbol import Symbol
  4. from sympy.interactive.printing import init_printing
  5. from sympy.printing.latex import LatexPrinter
  6. from sympy.printing.pretty.pretty import PrettyPrinter
  7. from sympy.printing.pretty.pretty_symbology import center_accent
  8. from sympy.printing.str import StrPrinter
  9. from sympy.printing.precedence import PRECEDENCE
  10. __all__ = ['vprint', 'vsstrrepr', 'vsprint', 'vpprint', 'vlatex',
  11. 'init_vprinting']
  12. class VectorStrPrinter(StrPrinter):
  13. """String Printer for vector expressions. """
  14. def _print_Derivative(self, e):
  15. from sympy.physics.vector.functions import dynamicsymbols
  16. t = dynamicsymbols._t
  17. if (bool(sum([i == t for i in e.variables])) &
  18. isinstance(type(e.args[0]), UndefinedFunction)):
  19. ol = str(e.args[0].func)
  20. for i, v in enumerate(e.variables):
  21. ol += dynamicsymbols._str
  22. return ol
  23. else:
  24. return StrPrinter().doprint(e)
  25. def _print_Function(self, e):
  26. from sympy.physics.vector.functions import dynamicsymbols
  27. t = dynamicsymbols._t
  28. if isinstance(type(e), UndefinedFunction):
  29. return StrPrinter().doprint(e).replace("(%s)" % t, '')
  30. return e.func.__name__ + "(%s)" % self.stringify(e.args, ", ")
  31. class VectorStrReprPrinter(VectorStrPrinter):
  32. """String repr printer for vector expressions."""
  33. def _print_str(self, s):
  34. return repr(s)
  35. class VectorLatexPrinter(LatexPrinter):
  36. """Latex Printer for vector expressions. """
  37. def _print_Function(self, expr, exp=None):
  38. from sympy.physics.vector.functions import dynamicsymbols
  39. func = expr.func.__name__
  40. t = dynamicsymbols._t
  41. if hasattr(self, '_print_' + func) and \
  42. not isinstance(type(expr), UndefinedFunction):
  43. return getattr(self, '_print_' + func)(expr, exp)
  44. elif isinstance(type(expr), UndefinedFunction) and (expr.args == (t,)):
  45. # treat this function like a symbol
  46. expr = Symbol(func)
  47. if exp is not None:
  48. # copied from LatexPrinter._helper_print_standard_power, which
  49. # we can't call because we only have exp as a string.
  50. base = self.parenthesize(expr, PRECEDENCE['Pow'])
  51. base = self.parenthesize_super(base)
  52. return r"%s^{%s}" % (base, exp)
  53. else:
  54. return super()._print(expr)
  55. else:
  56. return super()._print_Function(expr, exp)
  57. def _print_Derivative(self, der_expr):
  58. from sympy.physics.vector.functions import dynamicsymbols
  59. # make sure it is in the right form
  60. der_expr = der_expr.doit()
  61. if not isinstance(der_expr, Derivative):
  62. return r"\left(%s\right)" % self.doprint(der_expr)
  63. # check if expr is a dynamicsymbol
  64. t = dynamicsymbols._t
  65. expr = der_expr.expr
  66. red = expr.atoms(AppliedUndef)
  67. syms = der_expr.variables
  68. test1 = not all(True for i in red if i.free_symbols == {t})
  69. test2 = not all(t == i for i in syms)
  70. if test1 or test2:
  71. return super()._print_Derivative(der_expr)
  72. # done checking
  73. dots = len(syms)
  74. base = self._print_Function(expr)
  75. base_split = base.split('_', 1)
  76. base = base_split[0]
  77. if dots == 1:
  78. base = r"\dot{%s}" % base
  79. elif dots == 2:
  80. base = r"\ddot{%s}" % base
  81. elif dots == 3:
  82. base = r"\dddot{%s}" % base
  83. elif dots == 4:
  84. base = r"\ddddot{%s}" % base
  85. else: # Fallback to standard printing
  86. return super()._print_Derivative(der_expr)
  87. if len(base_split) != 1:
  88. base += '_' + base_split[1]
  89. return base
  90. class VectorPrettyPrinter(PrettyPrinter):
  91. """Pretty Printer for vectorialexpressions. """
  92. def _print_Derivative(self, deriv):
  93. from sympy.physics.vector.functions import dynamicsymbols
  94. # XXX use U('PARTIAL DIFFERENTIAL') here ?
  95. t = dynamicsymbols._t
  96. dot_i = 0
  97. syms = list(reversed(deriv.variables))
  98. while len(syms) > 0:
  99. if syms[-1] == t:
  100. syms.pop()
  101. dot_i += 1
  102. else:
  103. return super()._print_Derivative(deriv)
  104. if not (isinstance(type(deriv.expr), UndefinedFunction)
  105. and (deriv.expr.args == (t,))):
  106. return super()._print_Derivative(deriv)
  107. else:
  108. pform = self._print_Function(deriv.expr)
  109. # the following condition would happen with some sort of non-standard
  110. # dynamic symbol I guess, so we'll just print the SymPy way
  111. if len(pform.picture) > 1:
  112. return super()._print_Derivative(deriv)
  113. # There are only special symbols up to fourth-order derivatives
  114. if dot_i >= 5:
  115. return super()._print_Derivative(deriv)
  116. # Deal with special symbols
  117. dots = {0 : "",
  118. 1 : "\N{COMBINING DOT ABOVE}",
  119. 2 : "\N{COMBINING DIAERESIS}",
  120. 3 : "\N{COMBINING THREE DOTS ABOVE}",
  121. 4 : "\N{COMBINING FOUR DOTS ABOVE}"}
  122. d = pform.__dict__
  123. #if unicode is false then calculate number of apostrophes needed and add to output
  124. if not self._use_unicode:
  125. apostrophes = ""
  126. for i in range(0, dot_i):
  127. apostrophes += "'"
  128. d['picture'][0] += apostrophes + "(t)"
  129. else:
  130. d['picture'] = [center_accent(d['picture'][0], dots[dot_i])]
  131. return pform
  132. def _print_Function(self, e):
  133. from sympy.physics.vector.functions import dynamicsymbols
  134. t = dynamicsymbols._t
  135. # XXX works only for applied functions
  136. func = e.func
  137. args = e.args
  138. func_name = func.__name__
  139. pform = self._print_Symbol(Symbol(func_name))
  140. # If this function is an Undefined function of t, it is probably a
  141. # dynamic symbol, so we'll skip the (t). The rest of the code is
  142. # identical to the normal PrettyPrinter code
  143. if not (isinstance(func, UndefinedFunction) and (args == (t,))):
  144. return super()._print_Function(e)
  145. return pform
  146. def vprint(expr, **settings):
  147. r"""Function for printing of expressions generated in the
  148. sympy.physics vector package.
  149. Extends SymPy's StrPrinter, takes the same setting accepted by SymPy's
  150. :func:`~.sstr`, and is equivalent to ``print(sstr(foo))``.
  151. Parameters
  152. ==========
  153. expr : valid SymPy object
  154. SymPy expression to print.
  155. settings : args
  156. Same as the settings accepted by SymPy's sstr().
  157. Examples
  158. ========
  159. >>> from sympy.physics.vector import vprint, dynamicsymbols
  160. >>> u1 = dynamicsymbols('u1')
  161. >>> print(u1)
  162. u1(t)
  163. >>> vprint(u1)
  164. u1
  165. """
  166. outstr = vsprint(expr, **settings)
  167. import builtins
  168. if (outstr != 'None'):
  169. builtins._ = outstr
  170. print(outstr)
  171. def vsstrrepr(expr, **settings):
  172. """Function for displaying expression representation's with vector
  173. printing enabled.
  174. Parameters
  175. ==========
  176. expr : valid SymPy object
  177. SymPy expression to print.
  178. settings : args
  179. Same as the settings accepted by SymPy's sstrrepr().
  180. """
  181. p = VectorStrReprPrinter(settings)
  182. return p.doprint(expr)
  183. def vsprint(expr, **settings):
  184. r"""Function for displaying expressions generated in the
  185. sympy.physics vector package.
  186. Returns the output of vprint() as a string.
  187. Parameters
  188. ==========
  189. expr : valid SymPy object
  190. SymPy expression to print
  191. settings : args
  192. Same as the settings accepted by SymPy's sstr().
  193. Examples
  194. ========
  195. >>> from sympy.physics.vector import vsprint, dynamicsymbols
  196. >>> u1, u2 = dynamicsymbols('u1 u2')
  197. >>> u2d = dynamicsymbols('u2', level=1)
  198. >>> print("%s = %s" % (u1, u2 + u2d))
  199. u1(t) = u2(t) + Derivative(u2(t), t)
  200. >>> print("%s = %s" % (vsprint(u1), vsprint(u2 + u2d)))
  201. u1 = u2 + u2'
  202. """
  203. string_printer = VectorStrPrinter(settings)
  204. return string_printer.doprint(expr)
  205. def vpprint(expr, **settings):
  206. r"""Function for pretty printing of expressions generated in the
  207. sympy.physics vector package.
  208. Mainly used for expressions not inside a vector; the output of running
  209. scripts and generating equations of motion. Takes the same options as
  210. SymPy's :func:`~.pretty_print`; see that function for more information.
  211. Parameters
  212. ==========
  213. expr : valid SymPy object
  214. SymPy expression to pretty print
  215. settings : args
  216. Same as those accepted by SymPy's pretty_print.
  217. """
  218. pp = VectorPrettyPrinter(settings)
  219. # Note that this is copied from sympy.printing.pretty.pretty_print:
  220. # XXX: this is an ugly hack, but at least it works
  221. use_unicode = pp._settings['use_unicode']
  222. from sympy.printing.pretty.pretty_symbology import pretty_use_unicode
  223. uflag = pretty_use_unicode(use_unicode)
  224. try:
  225. return pp.doprint(expr)
  226. finally:
  227. pretty_use_unicode(uflag)
  228. def vlatex(expr, **settings):
  229. r"""Function for printing latex representation of sympy.physics.vector
  230. objects.
  231. For latex representation of Vectors, Dyadics, and dynamicsymbols. Takes the
  232. same options as SymPy's :func:`~.latex`; see that function for more information;
  233. Parameters
  234. ==========
  235. expr : valid SymPy object
  236. SymPy expression to represent in LaTeX form
  237. settings : args
  238. Same as latex()
  239. Examples
  240. ========
  241. >>> from sympy.physics.vector import vlatex, ReferenceFrame, dynamicsymbols
  242. >>> N = ReferenceFrame('N')
  243. >>> q1, q2 = dynamicsymbols('q1 q2')
  244. >>> q1d, q2d = dynamicsymbols('q1 q2', 1)
  245. >>> q1dd, q2dd = dynamicsymbols('q1 q2', 2)
  246. >>> vlatex(N.x + N.y)
  247. '\\mathbf{\\hat{n}_x} + \\mathbf{\\hat{n}_y}'
  248. >>> vlatex(q1 + q2)
  249. 'q_{1} + q_{2}'
  250. >>> vlatex(q1d)
  251. '\\dot{q}_{1}'
  252. >>> vlatex(q1 * q2d)
  253. 'q_{1} \\dot{q}_{2}'
  254. >>> vlatex(q1dd * q1 / q1d)
  255. '\\frac{q_{1} \\ddot{q}_{1}}{\\dot{q}_{1}}'
  256. """
  257. latex_printer = VectorLatexPrinter(settings)
  258. return latex_printer.doprint(expr)
  259. def init_vprinting(**kwargs):
  260. """Initializes time derivative printing for all SymPy objects, i.e. any
  261. functions of time will be displayed in a more compact notation. The main
  262. benefit of this is for printing of time derivatives; instead of
  263. displaying as ``Derivative(f(t),t)``, it will display ``f'``. This is
  264. only actually needed for when derivatives are present and are not in a
  265. physics.vector.Vector or physics.vector.Dyadic object. This function is a
  266. light wrapper to :func:`~.init_printing`. Any keyword
  267. arguments for it are valid here.
  268. {0}
  269. Examples
  270. ========
  271. >>> from sympy import Function, symbols
  272. >>> t, x = symbols('t, x')
  273. >>> omega = Function('omega')
  274. >>> omega(x).diff()
  275. Derivative(omega(x), x)
  276. >>> omega(t).diff()
  277. Derivative(omega(t), t)
  278. Now use the string printer:
  279. >>> from sympy.physics.vector import init_vprinting
  280. >>> init_vprinting(pretty_print=False)
  281. >>> omega(x).diff()
  282. Derivative(omega(x), x)
  283. >>> omega(t).diff()
  284. omega'
  285. """
  286. kwargs['str_printer'] = vsstrrepr
  287. kwargs['pretty_printer'] = vpprint
  288. kwargs['latex_printer'] = vlatex
  289. init_printing(**kwargs)
  290. params = init_printing.__doc__.split('Examples\n ========')[0] # type: ignore
  291. init_vprinting.__doc__ = init_vprinting.__doc__.format(params) # type: ignore