Advertisement
Guest User

Untitled

a guest
Jun 11th, 2017
260
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.56 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2.  
  3. #%% Важные константы.
  4.  
  5. # binary -- все бинарные операции
  6. binary = set("+*/^")
  7. # unary -- все функции
  8. unary = set(["sin", "cos", "tan", "asin", "acos", "atan", "exp", "sqrt", "ln"])
  9. # variables -- все переменные
  10. variables = set("xyz")
  11. # Переменная дифференцирования
  12. diff_with_respect = "x"
  13. # Все переменные за исключением переменной интегрирования.
  14. yz = variables.difference(diff_with_respect)
  15.  
  16. #%% Предобработка
  17.  
  18. def pretreatment(expression):
  19.     """Предобработка выражения. Убирает пробелы и заменяет выражения вида
  20.    (expr1 func -expr2).
  21.    Техническая функция"""
  22.     # убьем пробелы
  23.     expression = expression.replace(" ", "")
  24.     # Чтобы не возиться с минусами (-5+3), заменим:
  25.     # x *- y -> x *-1* y
  26.     expression = expression.replace("*-", "*-1*")
  27.     # x -- y -> x + y
  28.     expression = expression.replace("*--", "+")
  29.     # x / -y -> x /-1/ y
  30.     expression = expression.replace("/-", "/-1/")
  31.     # x +- y -> x - y
  32.     expression = expression.replace("+-", "-")
  33.     # (- x ... -> (-1* x ...
  34.     expression = expression.replace("(-", "(-1*")
  35.     # )- x ... -> )-1* x ...
  36.     expression = expression.replace(")-", ")-1*")
  37.     return expression
  38.  
  39. #%% парсинг.
  40.  
  41. def parsing_expression(expression):
  42.     """Парсит выражение. На выходе дает дерево (словарь словарей), ветви
  43.    которого функции либо операции, листы -- числа либо переменные."""
  44.     # Проверяем, не пришла ли пустая строка.
  45.     if (expression == ""):
  46.         raise ValueError("Invalid expression")
  47.     # Проверяем, что исследуемая часть выражения не запихана в скобки
  48.     # если запихана, извлекаем.
  49.     in_bracket = True # Показывает, нужно ли обрывать крайние скобки.
  50.     while(in_bracket):
  51.         bracket = 1 # счетчик скобок
  52.         if (expression[0] == "(" and expression[-1] == ")"):
  53.             for i in range(1, len(expression)-1):
  54.                 if (expression[i] == "("):
  55.                     bracket += 1
  56.                 elif (expression[i] == ")"):
  57.                     bracket -= 1
  58.                 if (bracket == 0):
  59.                     in_bracket = False
  60.                     break
  61.         else:
  62.             in_bracket = False
  63.         if (in_bracket):
  64.             expression = expression[1:(len(expression)-1)]
  65.     # Проверяем, не является ли наше выражение числом. Если является,
  66.     # вернем это число.
  67.     try:
  68.         return(int(expression))
  69.     except:
  70.         pass
  71.     try:
  72.         return(float(expression))
  73.     except:
  74.         pass
  75.     # Проверяем, не является ли наше выражение переменной. Если является,
  76.     # вернем ее
  77.     if (expression in variables):
  78.         return(expression)
  79.     # Теперь нужно разорвать наше выражение на части по операциям с наименьшим
  80.     #приоритетам, находящимся вне скобок.
  81.     priority = {i : -1 for i in binary} # словарь приоритетов.  
  82.     bracket = 0 # счетчик скобок
  83.     for i in range(len(expression)):
  84.         if (expression[i] == "("):
  85.             bracket += 1
  86.         elif (expression[i] == ")"):
  87.             bracket -= 1
  88.         if (bracket == 0 and
  89.             expression[i] in priority):
  90.             priority[expression[i]] = i
  91.         # просто для ускорения: если найдена операция с наименьшим приоритетом,
  92.         # то дальше можно не считать.
  93.         if (priority["+"] != -1):
  94.             break
  95.     if (priority["+"] != -1):
  96.         return {"+" : [parsing_expression(expression[:priority["+"]]),
  97.                 parsing_expression(expression[priority["+"]+1:])]}
  98.     elif (priority["*"] != -1):
  99.         return {"*" : [parsing_expression(expression[:priority["*"]]),
  100.                 parsing_expression(expression[priority["*"]+1:])]}
  101.     elif (priority["/"] != -1):
  102.         return {"/" : [parsing_expression(expression[:priority["/"]]),
  103.                 parsing_expression(expression[priority["/"]+1:])]}
  104.     elif (priority["^"] != -1):
  105.         return {"^" : [parsing_expression(expression[:priority["^"]]),
  106.                 parsing_expression(expression[priority["^"]+1:])]}
  107.     # Отлично, мы разобрали случаи бинарных операций (у дерева 2 ветвления)
  108.     # Теперь нужно смотреть на унарные.
  109.     # К этому месту у нас остались лишь выражения f(expression)
  110.     if expression[:3] == "sin":
  111.         return {"sin": parsing_expression(expression[3:])}
  112.     elif expression[:3] == "cos":
  113.         return {"cos": parsing_expression(expression[3:])}
  114.     elif expression[:3] == "tan":
  115.         return {"tan": parsing_expression(expression[3:])}
  116.     elif expression[:4] == "asin":
  117.         return {"asin": parsing_expression(expression[4:])}
  118.     elif expression[:4] == "acos":
  119.         return {"acos": parsing_expression(expression[4:])}
  120.     elif expression[:4] == "atan":
  121.         return {"atan": parsing_expression(expression[4:])}
  122.     elif expression[:3] == "exp":
  123.         return {"exp": parsing_expression(expression[3:])}
  124.     elif expression[:4] == "sqrt":
  125.         return {"sqrt": parsing_expression(expression[4:])}
  126.     elif expression[:2] == "ln":
  127.         return {"ln": parsing_expression(expression[2:])}
  128.     else:
  129.         raise ValueError("Invalid expression: " + expression)
  130.  
  131. #%% Поиск производной.
  132.  
  133. # Идея такая. Начинаем протаскивать производную, начиная с корня. На каждом
  134. # шаге у нас либо кусочек дерева {func:[f, g]} (ему соответствует выражение
  135. # f func g), либо {func:f} (соответствующее выражение func(f)). В обоих случаях
  136. # мы можем взять производную в терминах f, g, f', g' и для нее написать дерево.
  137. # Далее запускаем эту функцию для всех f', g'.
  138. def D(tree):
  139.     """По дереву выражения строит дерево производной выражения."""
  140.     # получили функцию на вершине
  141.     func = list(tree.keys())[0]
  142.     # случай бинарной операции
  143.     if func in binary:
  144.         f,g = tree[func]
  145.         # Сначала посчитаем значение производной.
  146.         if (type(f) != dict and (isinstance(f, (int, float)) or (f in yz))):
  147.             Df = 0
  148.         elif (f == "x"):
  149.             Df = 1
  150.         else:
  151.             Df = D(f)
  152.         if (type(g) != dict and
  153.             (isinstance(g, (int, float)) or (g in yz))):
  154.             Dg = 0
  155.         elif (g == "x"):
  156.             Dg = 1
  157.         else:
  158.             Dg = D(g)
  159.         # Теперь пишем дерево для формулы (f func g)'
  160.         if (func == "+"):
  161.             # (f+g)' = f' + g'
  162.             return {"+": [Df, Dg]}
  163.         elif (func == "*"):
  164.             # (fg)' = f'g + fg'
  165.             return {"+":
  166.                         [{"*":[Df, g]},
  167.                          {"*":[f, Dg]}]}
  168.         elif (func == "/"):
  169.             # (f/g)' = f'g^(-1) - fg'g^(-2)
  170.             return {"+":
  171.                         [{"/":
  172.                               [Df, {"^": [g, -1]}]},
  173.                          {"*": [{"*" : [f, Dg]},
  174.                                 {"^" : [g, -2]}]}]}
  175.         elif (func == "^"):
  176.             # (f^g)' = (f^g)g'ln(f) + f'g(f^(g-1)) = Aln(f) + B
  177.             return { "+" :
  178.                            [{"*" : [{"^": [f, g]},
  179.                                     {"*": [Dg, {"ln":f}]}]},
  180.                             {"*" : [{"^" : [f,
  181.                                                 {"+":[g, -1]}]},
  182.                                     {"*" : [g, Df]}]}]}
  183.         else:
  184.             print("Что-то пошло не так")
  185.     # Случай унарной операции
  186.     elif func in ["sin", "cos", "tan", "asin", "acos", "atan", "exp", "sqrt", "ln"]:
  187.         f = tree[func]
  188.         # Считаем значение производной.
  189.         if (type(f) != dict and
  190.             (isinstance(f, (int, float)) or (f in "yz"))):
  191.             Df = 0
  192.         elif (f == "x"):
  193.             Df = 1
  194.         else:
  195.             Df = D(f)
  196.         # (func(f))' = f' * func'(f) = f' * right
  197.         if(func == "sin"):
  198.             right = {"cos" : f}
  199.         elif(func == "cos"):
  200.             right = {"*": [-1, {"sin":f}]}
  201.         elif(func == "tan"):
  202.             right = {"^" : [{"cos":f}, -2]}
  203.         elif(func == "asin"):
  204.             right = {"^": [{"+":[1, {"*":[-1, {"^":[f,2]}]}]},-0.5]}
  205.         elif(func == "acos"):
  206.             right = {"/":[-1, {"sqrt":{"+":[1, {"*":[-1, {"^":[f,2]}]}]}}]}
  207.         elif(func == "atan"):
  208.             right = {"/":[1,{"+":[1, {"^":[f, 2]}]}]}
  209.         elif(func == "exp"):
  210.             right = {"exp": f}
  211.         elif(func == "sqrt"):
  212.             right = {"*":[0.5, {"^":[f, -0.5]}]}
  213.         elif(func == "ln"):
  214.             right = {"/": [1,f]}
  215.         else:
  216.             right = {}
  217.             print("Что-то пошло не так")
  218.         return {"*":[right, Df]}
  219.  
  220. #%% Упрощение
  221. def simplify(tree):
  222.     """Упрощение дерева выражений"""
  223.     # Это условие не должно выполняться!
  224.     if (type(tree) != dict):
  225.         print("Это условие не должно выполняться!")
  226.     func = list(tree.keys())[0]
  227.     # Разбор бинарного случая
  228.     if (func in binary):
  229.         f,g = tree[func]
  230.         # упрощаем
  231.         if (type(f) == dict):
  232.             f = simplify(f)
  233.         if (type(g) == dict):
  234.             g = simplify(g)
  235.         # Считаем, что f и g максимально упрощены. Применяем к ним func
  236.         if(func == "+"):
  237.             if(f == 0):
  238.                 return g
  239.             elif(g == 0):
  240.                 return f
  241.             elif(isinstance(f, (int, float)) and isinstance(g, (int, float))):
  242.                 return (f+g)
  243.         elif(func == "*"):
  244.             if(f == 0 or g == 0):
  245.                 return 0
  246.             elif(f == 1):
  247.                 return g
  248.             elif(g == 1):
  249.                 return f
  250.             elif(isinstance(f, (int, float)) and isinstance(g, (int, float))):
  251.                 return (f*g)
  252.         elif(func == "/"):
  253.             if(f == 0):
  254.                 return 0
  255.             elif(g == 0):
  256.                 return("ERROR")
  257.                 print("Деление на 0")
  258.             elif(g == 1):
  259.                 return f
  260.             elif(isinstance(f, (int, float)) and isinstance(g, (int, float))):
  261.                 return (f/g)
  262.         elif(func == "^"):
  263.             if(f == 0 and g != 0):
  264.                 return 0
  265.             elif(g == 0):
  266.                 return(1)
  267.             elif(f == 1):
  268.                 return(1)
  269.             elif(g == 1):
  270.                 return f
  271.             elif(isinstance(f, (int, float)) and isinstance(g, (int, float))):
  272.                 return (f**g)
  273.         return({func:[f,g]})
  274.     # Разбор унарного случая
  275.     if (func in unary):
  276.         f = tree[func]
  277.         # упрощаем
  278.         if (type(f) == dict):
  279.             f = simplify(f)
  280.         # Считаем, что f максимально упрощена. Применяем к ним func
  281.         if(f == 0):
  282.             if func in ["sin", "tan", "asin", "atan", "sqrt"]:
  283.                 return(0)
  284.             elif func == "exp":
  285.                 return(1)
  286.             elif func == "ln":
  287.                 print("Деление на 0")
  288.                 return("ERROR")
  289.         elif(f == 1):
  290.             if func == "sqrt":
  291.                 return(1)
  292.             elif func == "ln":
  293.                 return(0)
  294.         else:
  295.             return({func : f})
  296.        
  297. #%% Перевод дерева в строку
  298.  
  299. # Для уменьшения числа скобок используются следующие правила:
  300. # 1. Унарная функция обязана быть записанной в скобках.
  301. # 2. Для бинарной функции. пусть есть f, g, func. Если в записи f или g вне
  302. # скобок стоят операции с не меньшим приоритетом,  чем операция func. Тогда
  303. # для соответствующей части (или 2 частей) скобки не нужны.
  304. def to_string(tree, min_priority = 0):
  305.     """Переводит дерево в строковое выражение, пытаясь уменьшить количество
  306.    скобочек.
  307.    
  308.    tree -- дерево, переводящееся в строку
  309.    min_priority -- минимальный приоритет используемой вне скобок операции
  310.    в записи на данный момент. Этот параметр задавать не нужно, он используется
  311.    лишь в рекурсивных вызовах! Словарь приоритетов:
  312.    {"+" : 0, "*" : 1, "/" : 1, "^" : 2}"""
  313.     if (type(tree) != dict):
  314.         # Видимо, этот случай бывает лишь когда на вход подают строку-ответ.
  315.         return(tree, 0)
  316.     func = list(tree.keys())[0]
  317.     # Разбор бинарного случая
  318.     if (func in binary):
  319.         f,g = tree[func]
  320.         min_priority_f = min_priority_g = 999
  321.         # упрощаем
  322.         if (type(f) == dict):
  323.             f, min_priority_f = to_string(f)
  324.         if (type(g) == dict):
  325.             g, min_priority_g = to_string(g)
  326.         # 2. Для бинарной функции. пусть есть f, g, func. Если в записи f или g
  327.         # вне скобок стоят операции с не меньшим приоритетом,  чем операция  
  328.         # func. Тогда для соответствующей части (или 2 частей) скобки не нужны.
  329.         priority = {"+" : 0, "*" : 1, "/" : 1, "^" : 2}
  330.         p1 = (str(f) if(priority[func] <= min_priority_f)
  331.                      else "(" + str(f) + ")")
  332.         p2 = (str(g) if(priority[func] <= min_priority_g)
  333.                      else "(" + str(g) + ")")
  334.         return(p1 + func + p2, priority[func])
  335.     if(func in unary):
  336.         f = tree[func]
  337.         # упрощаем
  338.         if (type(f) == dict):
  339.             f, min_priority_f = to_string(f)
  340.         # 1. Унарная функция обязана быть записанной в скобках.
  341.         return(func + "(" + str(f) + ")", 999)
  342.    
  343.  
  344. #%%
  345. if __name__ == "__main__":
  346.     expression = "x^(x*y)"
  347.     expression = pretreatment(expression)
  348.     tree = parsing_expression(expression)
  349.     D_expression = D(tree)
  350.     simp_D = simplify(D_expression)
  351.     ans = to_string(simp_D)[0]
  352.     print(ans)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement