decompogen.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. from sympy.core import (Function, Pow, sympify, Expr)
  2. from sympy.core.relational import Relational
  3. from sympy.core.singleton import S
  4. from sympy.polys import Poly, decompose
  5. from sympy.utilities.misc import func_name
  6. from sympy.functions.elementary.miscellaneous import Min, Max
  7. def decompogen(f, symbol):
  8. """
  9. Computes General functional decomposition of ``f``.
  10. Given an expression ``f``, returns a list ``[f_1, f_2, ..., f_n]``,
  11. where::
  12. f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n))
  13. Note: This is a General decomposition function. It also decomposes
  14. Polynomials. For only Polynomial decomposition see ``decompose`` in polys.
  15. Examples
  16. ========
  17. >>> from sympy.abc import x
  18. >>> from sympy import decompogen, sqrt, sin, cos
  19. >>> decompogen(sin(cos(x)), x)
  20. [sin(x), cos(x)]
  21. >>> decompogen(sin(x)**2 + sin(x) + 1, x)
  22. [x**2 + x + 1, sin(x)]
  23. >>> decompogen(sqrt(6*x**2 - 5), x)
  24. [sqrt(x), 6*x**2 - 5]
  25. >>> decompogen(sin(sqrt(cos(x**2 + 1))), x)
  26. [sin(x), sqrt(x), cos(x), x**2 + 1]
  27. >>> decompogen(x**4 + 2*x**3 - x - 1, x)
  28. [x**2 - x - 1, x**2 + x]
  29. """
  30. f = sympify(f)
  31. if not isinstance(f, Expr) or isinstance(f, Relational):
  32. raise TypeError('expecting Expr but got: `%s`' % func_name(f))
  33. if symbol not in f.free_symbols:
  34. return [f]
  35. # ===== Simple Functions ===== #
  36. if isinstance(f, (Function, Pow)):
  37. if f.is_Pow and f.base == S.Exp1:
  38. arg = f.exp
  39. else:
  40. arg = f.args[0]
  41. if arg == symbol:
  42. return [f]
  43. return [f.subs(arg, symbol)] + decompogen(arg, symbol)
  44. # ===== Min/Max Functions ===== #
  45. if isinstance(f, (Min, Max)):
  46. args = list(f.args)
  47. d0 = None
  48. for i, a in enumerate(args):
  49. if not a.has_free(symbol):
  50. continue
  51. d = decompogen(a, symbol)
  52. if len(d) == 1:
  53. d = [symbol] + d
  54. if d0 is None:
  55. d0 = d[1:]
  56. elif d[1:] != d0:
  57. # decomposition is not the same for each arg:
  58. # mark as having no decomposition
  59. d = [symbol]
  60. break
  61. args[i] = d[0]
  62. if d[0] == symbol:
  63. return [f]
  64. return [f.func(*args)] + d0
  65. # ===== Convert to Polynomial ===== #
  66. fp = Poly(f)
  67. gens = list(filter(lambda x: symbol in x.free_symbols, fp.gens))
  68. if len(gens) == 1 and gens[0] != symbol:
  69. f1 = f.subs(gens[0], symbol)
  70. f2 = gens[0]
  71. return [f1] + decompogen(f2, symbol)
  72. # ===== Polynomial decompose() ====== #
  73. try:
  74. return decompose(f)
  75. except ValueError:
  76. return [f]
  77. def compogen(g_s, symbol):
  78. """
  79. Returns the composition of functions.
  80. Given a list of functions ``g_s``, returns their composition ``f``,
  81. where:
  82. f = g_1 o g_2 o .. o g_n
  83. Note: This is a General composition function. It also composes Polynomials.
  84. For only Polynomial composition see ``compose`` in polys.
  85. Examples
  86. ========
  87. >>> from sympy.solvers.decompogen import compogen
  88. >>> from sympy.abc import x
  89. >>> from sympy import sqrt, sin, cos
  90. >>> compogen([sin(x), cos(x)], x)
  91. sin(cos(x))
  92. >>> compogen([x**2 + x + 1, sin(x)], x)
  93. sin(x)**2 + sin(x) + 1
  94. >>> compogen([sqrt(x), 6*x**2 - 5], x)
  95. sqrt(6*x**2 - 5)
  96. >>> compogen([sin(x), sqrt(x), cos(x), x**2 + 1], x)
  97. sin(sqrt(cos(x**2 + 1)))
  98. >>> compogen([x**2 - x - 1, x**2 + x], x)
  99. -x**2 - x + (x**2 + x)**2 - 1
  100. """
  101. if len(g_s) == 1:
  102. return g_s[0]
  103. foo = g_s[0].subs(symbol, g_s[1])
  104. if len(g_s) == 2:
  105. return foo
  106. return compogen([foo] + g_s[2:], symbol)