简单的求导的符号运算算法
来源:互联网 发布:淘宝恶意刷流量软件 编辑:程序博客网 时间:2024/06/01 07:13
简单的求导的符号运算算法
最近准备做一个有意思的事情,想实现基于符号运算法则来实现求导的算法。
现在做出了一个比较简单的雏形,写一篇博客总结一下,顺便介绍一下这个python小项目。
下面的思路和代码片段展现了我的思路,如果有感兴趣的同学应该可以写出实现,如果需要代码可以联系我。因为完整代码里面有很多无聊的提示信息和格式转化,所以我不打算放上来了。
表达式语法树
语法树
语法树是我这个项目里面所有表达式的存在形式,树的一个结点定义如下:
# the class of expression treeclass ExpTree: def __init__(self, op, args): self.op = op self.args = args
前缀表达式转化为语法树
算法比较简单,递归实现表达式解析即可:
# cast a expression string in scheme formation to a expression treedef expr_to_tree(line): # cast a expression element list in scheme formation to a expression tree def expr_list_to_tree(line_list): del line_list[0] op = line_list[0] del line_list[0] args = [] while True: if line_list[0] == ')': del line_list[0] return ExpTree(op, args) if line_list[0] == '(': args.append(expr_list_to_tree(line_list)) else: args.append(line_list[0]) del line_list[0] line = line.replace('(', '( ') line = line.replace(')', ' )') line_list = line.split() return simplify(expr_list_to_tree(line_list))
对语法树求导
这里是算法的核心,这个版本只加入了二元运算的法则,一元函数的法则以后会加入。
算法为递归求导,规则如下:
1.叶子结点:x导数为1,常数导数为0。
2.非叶子结点,左右子树为l,r。那么结点的运算来递归求导:
实现如下:
# get the derivate tree of the derivate of the tree expressiondef derivate(tree): if isinstance(tree, str): if tree == 'x': return '1' else: return '0' op = tree.op args = tree.args if op in ['+', '-']: a0 = args[0] a1 = args[1] return simplify(ExpTree(op, [derivate(a0), derivate(a1)])) elif op == '*': a0 = args[0] a1 = args[1] e1 = ExpTree('*', [derivate(a0), a1]) e2 = ExpTree('*', [a0, derivate(a1)]) return simplify(ExpTree('+', [e1, e2])) elif op == '/': a0 = args[0] a1 = args[1] nom = ExpTree('-', [ExpTree('*', [derivate(a0), a1]), ExpTree('*', [a0, derivate(a1)])]) denom = ExpTree('^', [a1, '2']) return simplify(ExpTree('/', [nom, denom])) elif op in ['**', '^']: a0 = args[0] a1 = args[1] e1 = a1 e2 = ExpTree('^', [a0, ExpTree('-', [a1 ,'1'])]) return simplify(ExpTree('*', [ExpTree('*', [e1, e2]), derivate(a0)]))
表达式化简
因为上述的求导规则经常会产生0或者1项,例如:
所以需要化简,规则为:
1.
2.
3.
4.
5.
6.
实现为:
# simplify a expression treedef simplify(tree): # judge whether ele is a constant def is_constant(ele): if not isinstance(ele, str): return False return ele != 'x' # judge whether ele is a constant equal to v def equ_to_constant(ele, v): eps = 1e-5 if not is_constant(ele): return False return abs(float(ele) - v) < eps if isinstance(tree, str): return tree arg_num = len(tree.args) for i in range(arg_num): tree.args[i] = simplify(tree.args[i]) if tree.op == '+': for i in [0, 1]: if equ_to_constant(tree.args[i], 0): tree = tree.args[1 - i] return tree elif tree.op == '-': if equ_to_constant(tree.args[1], 0): tree = tree.args[0] return tree elif tree.op == '*': for i in [0, 1]: if equ_to_constant(tree.args[i], 0): tree = '0' return tree if equ_to_constant(tree.args[i], 1): tree = tree.args[1 - i] return tree elif tree.op == '/': if equ_to_constant(tree.args[0], 0): tree = '0' return tree if equ_to_constant(tree.args[1], 1): tree = tree.args[0] return tree for i in range(arg_num): if not is_constant(tree.args[i]): return tree tree = str(calculate(tree, None)) return tree
从语法树生成函数
容易实现求值函数calculate(tree, v)
,可以递归计算树在x=v时候的值,那么我们怎么得到树对应的函数呢?
一个lambda表达式足矣: func = lambda x: calculate(tree, x)
注意这个高阶函数的用法。
演示
演示如下:
***zzy@zzy-lenovo-g50-80:~/zzy/SICP$ python3 derivate.py
This is a little interpreter for scheme formation function and its’ derivate:
Scheme formation of f(x) = 2 * x + 1 is (+ 1 (* 2 x)).
f(x) is the function f(x), f(2) is the value f(x)|(x=2).
f, f’, f” or f”’ is (high rank) derivates of f.
Please input f(x) in scheme formation or exit:
(* x (^ (+ x 2) 3))
Please input expression or exit:
f(x)
(* x (^ (+ x 2) 3))
(x * ((x + 2) ^ 3))
Please input expression or exit:
f’(x)
(+ (^ (+ x 2) 3) (* x (* 3 (^ (+ x 2) 2.0))))
(((x + 2) ^ 3) + (x * (3 * ((x + 2) ^ 2.0))))
Please input expression or exit:
f”(x)
(+ (* 3 (^ (+ x 2) 2.0)) (+ (* 3 (^ (+ x 2) 2.0)) (* x (* 3 (* 2.0 (^ (+ x 2) 1.0))))))
((3 * ((x + 2) ^ 2.0)) + ((3 * ((x + 2) ^ 2.0)) + (x * (3 * (2.0 * ((x + 2) ^ 1.0))))))
Please input expression or exit:
f(0)
0.0
Please input expression or exit:
f’(0)
8.0
Please input expression or exit:
exit
Please input f(x) in scheme formation or exit:
exit
Thank you!
下一阶段改进
下一阶段的改进目标是:
1. 增加对一元函数的支持,建立函数和导数表机制。
2. 增加中缀表达式输入转换机制,更符合自然语言。
3*. 使用交换,结合律和分配律,合并同类项,加强化简单功能。(不准备实现)
- 简单的求导的符号运算算法
- 求导的符号运算
- 矩阵的求导运算
- 矩阵的求导运算
- 符号表达式的运算
- Matlab的符号运算
- 常用的符号运算
- python的运算符号
- VB+浮点运算的的简单算法
- perl的运算符号字符
- C语言的运算符号
- java的instanseof运算符号
- 各种运算符号的应用
- MATLAB的符号运算基础
- **MATLAB** MATLAB的符号运算
- 一些运算符号的优先级
- 用链表实现一元多项式的加、减、乘、求导运算
- 大数运算(超长整数运算)算法的简单分析
- 剑指offer-数值的整数次方
- Bootstrap-datetimePicker插件添加秒钟(自定义)选择下拉框
- 正则表达式(验证数值的正则表达式,校验字符的表达式,特殊需求表达式)—干货收集-总会有用的
- xDSL(数字用户线)
- 排序算法 -- (三)简单选择排序
- 简单的求导的符号运算算法
- NSString 和 NSURL的互相转换
- 如何写出你的第一个c语言程序
- Spring的depends-on属性Bean依赖
- MATLAB矩阵分析
- TypeScript 类型兼容性整理
- 多年iOS开发经验总结(一) 其实就是一些常用的代码块
- 4.利用Model Builder迭代器对数据批处理
- Spark计算平台算子介绍与学习