地主家的好儿子 发表于 2023-4-18 14:24:33

CAS 表达式计算实现

本帖最后由 地主家的好儿子 于 2023-4-21 15:29 编辑

准备分几个章节讲解在高级语言上实现代数表达式的功能,matlab中的符号系统运算让我感到很神秘,CAS,最近研究了一个很基本的CAS系统-Swan,它不太完善,但是可以一窥CAS的内核,符号系统是如何运行的,中间涉及到哪些内容 一、展开表达式的情况 1)不带有未知数的表达式 举个例子吧 (3+9)/2*5*pi 2)带有未知数的表达式存储
数学表达式通常由常数、符号、变量名组成 x*y+(2*x-1)*z 其中变量有3个,常量有2个,因为xyz三个都是未知数,所以表达式的值也是未知的, 3)表达式的展开举个例子吧(x-1)*(x+1) 初中数学,按逐项相乘x*x +x*(-1) +x*(1) -1*(1) --运行结果如下
x = sym('x')   --定义一个成为x的变量
y = (x-1)*(x+1)--定义一个表达式y
print(tostring(y))
(x + -1*1)*(x + 1)
print(y:expand())--将表达式展开
-1*1 + -1*x + x*1 + x*x
代码在lua 5.1 环境下测试,在fxlua中环境中也测试通过

4)表达式的按规则合并x*x +x*(-1) +x*(1) -1*(1)对于x的阶数排序x二阶系数为1x一阶系数为0x零阶系数为-1表达式的系数数组为简化后情况 x*x-1,最基本的符号运算,在cas是如何进行的,来看下面的解释
多元变量升幂排序如果定义x,y都是变量,展开后可得(x+y)^3 = (x+y)*(x*x+x*y+x*y+y*y)=x*x*x + 2*x*x*y + x*y*y + x*x*y + 2*x*y*y+ y*y*y这里就涉及到一个升幂排列的问题,这不是最简的形式
我们习惯这样排列x^n*y^0,x^(n-1)*y^1,x^(n-2)*y^2,.....,x^0*y^n 并对相同的幂合并同类项,在代数里面我们称此形式为多项式的升幂形式
对于这样一个需求,我们要求在expand() 函数基础上,扩展出coeff()和幂排序和exp() 和 exp_order()两个功能coeff() 从表达式树结构上取出当前表达式的系数order() 从表达式树结构上取出当前表达式的对定义变量的指数比如 通过2*x*y 的系数是2 幂级因为有两个未知数所以,他的幂集为【1,1】同理         x*x*x + 2*x*x*y + x*y*y + x*x*y + 2*x*y*y+ y*y*y系数   1             2            1             1         2               1幂级                                   幂级相同是可以合并的简化后   x*x*x + 3*x*x*y+3*y*y*x+ y*y*y
当然含有 +x 和 -x 是可以相互抵消的,在运算中,也需要把抵消的情况去除掉,在swan代码中,这步没有实现好,是一个巨大的bug
更多元的情况以此类推

地主家的好儿子 发表于 2023-4-19 11:08:20

思维不能分割,技术可以拆分
分割线后是技术线路图
------------------------------
多项式展开 expand()
多项式基于升幂排序合并和系数提出 exp_order()和coeff()
多项式因子分解 factor()和cancel()
带分母的表达式化简split ()

地主家的好儿子 发表于 2023-4-21 15:38:24

本帖最后由 地主家的好儿子 于 2023-4-21 17:03 编辑

描述升幂化简问题花了这么多篇幅,代码稍显复杂和混乱,已经接近600行了
但至少解决了swan 里面无法正负项消除的bug
----------------------------------
接下来就是多项式求根问题root()和simple()两个函数族
原先的那几个函数又有点绷不住了

1149761294 发表于 2023-4-23 20:03:57

赞一个,难得有人研究这些技术。
顺便,可以参考eigenmath的实现:https://github.com/georgeweigt/eigenmath/blob/main/src/eval_multiply.c
页: [1]
查看完整版本: CAS 表达式计算实现