decompogen.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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. def decompogen(f, symbol):
  7. """
  8. Computes General functional decomposition of ``f``.
  9. Given an expression ``f``, returns a list ``[f_1, f_2, ..., f_n]``,
  10. where::
  11. f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n))
  12. Note: This is a General decomposition function. It also decomposes
  13. Polynomials. For only Polynomial decomposition see ``decompose`` in polys.
  14. Examples
  15. ========
  16. >>> from sympy.abc import x
  17. >>> from sympy import decompogen, sqrt, sin, cos
  18. >>> decompogen(sin(cos(x)), x)
  19. [sin(x), cos(x)]
  20. >>> decompogen(sin(x)**2 + sin(x) + 1, x)
  21. [x**2 + x + 1, sin(x)]
  22. >>> decompogen(sqrt(6*x**2 - 5), x)
  23. [sqrt(x), 6*x**2 - 5]
  24. >>> decompogen(sin(sqrt(cos(x**2 + 1))), x)
  25. [sin(x), sqrt(x), cos(x), x**2 + 1]
  26. >>> decompogen(x**4 + 2*x**3 - x - 1, x)
  27. [x**2 - x - 1, x**2 + x]
  28. """
  29. f = sympify(f)
  30. if not isinstance(f, Expr) or isinstance(f, Relational):
  31. raise TypeError('expecting Expr but got: `%s`' % func_name(f))
  32. if symbol not in f.free_symbols:
  33. return [f]
  34. result = []
  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. result += [f.subs(arg, symbol)] + decompogen(arg, symbol)
  44. return result
  45. # ===== Convert to Polynomial ===== #
  46. fp = Poly(f)
  47. gens = list(filter(lambda x: symbol in x.free_symbols, fp.gens))
  48. if len(gens) == 1 and gens[0] != symbol:
  49. f1 = f.subs(gens[0], symbol)
  50. f2 = gens[0]
  51. result += [f1] + decompogen(f2, symbol)
  52. return result
  53. # ===== Polynomial decompose() ====== #
  54. try:
  55. result += decompose(f)
  56. return result
  57. except ValueError:
  58. return [f]
  59. def compogen(g_s, symbol):
  60. """
  61. Returns the composition of functions.
  62. Given a list of functions ``g_s``, returns their composition ``f``,
  63. where:
  64. f = g_1 o g_2 o .. o g_n
  65. Note: This is a General composition function. It also composes Polynomials.
  66. For only Polynomial composition see ``compose`` in polys.
  67. Examples
  68. ========
  69. >>> from sympy.solvers.decompogen import compogen
  70. >>> from sympy.abc import x
  71. >>> from sympy import sqrt, sin, cos
  72. >>> compogen([sin(x), cos(x)], x)
  73. sin(cos(x))
  74. >>> compogen([x**2 + x + 1, sin(x)], x)
  75. sin(x)**2 + sin(x) + 1
  76. >>> compogen([sqrt(x), 6*x**2 - 5], x)
  77. sqrt(6*x**2 - 5)
  78. >>> compogen([sin(x), sqrt(x), cos(x), x**2 + 1], x)
  79. sin(sqrt(cos(x**2 + 1)))
  80. >>> compogen([x**2 - x - 1, x**2 + x], x)
  81. -x**2 - x + (x**2 + x)**2 - 1
  82. """
  83. if len(g_s) == 1:
  84. return g_s[0]
  85. foo = g_s[0].subs(symbol, g_s[1])
  86. if len(g_s) == 2:
  87. return foo
  88. return compogen([foo] + g_s[2:], symbol)