用ocaml简化计算机代数系统的方程
你好!我目前正试图用ocaml编写一个程序来绘制一个由用户编写的函数 为此,我解析输入,将输入转换为数据结构。 我目前正在尝试创建一个ocaml函数来最大限度地简化这个输入 例如,x*x-x*x将在0中简化 这是我的解析器:用ocaml简化计算机代数系统的方程,ocaml,symbolic-math,Ocaml,Symbolic Math,你好!我目前正试图用ocaml编写一个程序来绘制一个由用户编写的函数 为此,我解析输入,将输入转换为数据结构。 我目前正在尝试创建一个ocaml函数来最大限度地简化这个输入 例如,x*x-x*x将在0中简化 这是我的解析器: %{ open Function %} %token <float> FLOAT %token <string> VAR %token COS SIN SQRT EXP LN PUIS %token PLUS MINUS TIMES DIV
%{
open Function
%}
%token <float> FLOAT
%token <string> VAR
%token COS SIN SQRT EXP LN PUIS
%token PLUS MINUS TIMES DIV
%token LPAR RPAR
%token EOL
%left LPAR RPAR
%left COS SIN SQRT EXP LN
%left PLUS MINUS
%left TIMES DIV
%left PUIS
%type <Function.formel> main
%start main
%%
main:
expr EOL { $1 }
;
expr:
| FLOAT { flt $1 }
| VAR { var $1 }
| FLOAT VAR { mul (flt $1) (var $2) }
| LPAR expr RPAR { $2 }
| expr TIMES expr { mul $1 $3 }
| expr DIV expr { div $1 $3 }
| expr PLUS expr { add $1 $3 }
| expr MINUS expr { sub $1 $3 }
| expr PUIS expr { puis $1 $3 }
| COS LPAR expr RPAR { cos $3 }
| PLUS expr { pos $2 }
| MINUS expr { neg $2 }
| FLOAT COS LPAR expr RPAR { mul (flt $1) (cos $4) }
| SIN LPAR expr RPAR { sin $3 }
| FLOAT SIN LPAR expr RPAR { mul (flt $1) (sin $4) }
| SQRT LPAR expr RPAR { sqrt $3 }
| LN LPAR expr RPAR { lnp $3 }
| EXP LPAR expr RPAR { expo $3 }
;
我认为我的解析器和lexer都很好
然后,我使用一棵树来存储函数:
type formel =
| Float of float
| Var of string
| Add of formel * formel
| Sub of formel * formel
| Mul of formel * formel
| Div of formel * formel
| Ln of formel
| Cos of formel
| Sin of formel
| Puis of formel * formel
| Sqrt of formel
| Exp of formel
let flt f = Float f
let add e1 e2 = Add (e1, e2)
let sub e1 e2 = Sub (e1, e2)
let mul e1 e2 = Mul (e1, e2)
let div e1 e2 = Div (e1, e2)
let puis e1 e2 = Puis (e1, e2)
let neg e = Mul (Float (-1.), e)
let pos e = Mul (Float 1., e)
let cos e = Cos e
let sin e = Sin e
let var v = Var v
let sqrt e = Sqrt e
let expo e = Exp e
let lnp e = Ln e
这里是我遇到的困难:创建一个函数来简化
let rec simplify f =
let f_simplify = simp f in
if f_simplify = f
then f_simplify
else simplify f_simplify
and simp f =
match f with
| Float f -> Float f
| Var x -> Var x
(* 0 + x -> x *)
| Add (Float 0., f) -> simp f
(* x + 0 -> x *)
| Add (f, Float 0.) -> simp f
(* f1 + f2-> calcul (f1 + f2) *)
| Add (Float f1, Float f2) -> Float (f1 +. f2)
(* x + x -> 2 * x *)
| Add (f, g) when f = g -> simp (Mul (Float 2., simp f))
(* f1 * x + x -> (f1 + 1) * x *)
| Add (Mul (Float f1, f), g) when f = g -> simp (Mul (Float (f1 +. 1.), simp f))
(* x + f1 * x -> (f1 + 1) * x *)
| Add (f, Mul (Float f1, g)) when f = g -> simp (Mul (Float (f1 +. 1.), simp f))
(* x * f1 + x -> (f1 + 1) * x *)
| Add (Mul (f, Float f1), g) when f = g -> simp (Mul (Float (f1 +. 1.), simp f))
(* x + x * f1 -> (f1 + 1) * x *)
| Add (f, Mul (g, Float f1)) when f = g -> simp (Mul (Float (f1 +. 1.), simp f))
(* f1 * x + f2 * x -> (f1 + f2) * x *)
| Add (Mul (Float f1, f), Mul (Float f2, g)) when f = g -> simp (Mul (Float (f1 +. f2), simp f))
(* x * f1 + f2 * x -> (f1 + f2) * x *)
| Add (Mul (f, Float f1), Mul (Float f2, g)) when f = g -> simp (Mul (Float (f1 +. f2), simp f))
(* f1 * x + x * f2 -> (f1 + f2) * x *)
| Add (Mul (Float f1, f), Mul (g, Float f2)) when f = g -> simp (Mul (Float (f1 +. f2), simp f))
(* x * f1 + x * f2 -> (f1 + f2) * x *)
| Add (Mul (f, Float f1), Mul (g, Float f2)) when f = g -> simp (Mul (Float (f1 +. f2), simp f))
| Add (f, g) -> Add (simp f, simp g)
(* 0 - x -> - x *)
| Sub (Float 0., f) -> simp (Mul (Float (-1.), simp f))
(* x - 0 -> x *)
| Sub (f, Float 0.) -> simp f
(* f1 - f2 -> calcul (f1 - f2) *)
| Sub (Float f1, Float f2) -> Float (f1 -. f2)
(* f1 * x + x -> (f1 + 1) * x *)
| Sub (f, g) when f = g -> Float 0.
| Sub (f, g) -> Sub (simp f, simp g)
(* 0 / x -> 0 *)
| Div (Float 0., f) -> Float 0.
(* x / 1 -> x *)
| Div (f, Float 1.) -> simp f
(* f1 / f2 -> calcul (f1 / f2) *)
| Div (Float f1, Float f2) -> Float (f1 /. f2)
(* x / x -> 1 *)
| Div (f, g) when f = g -> Float 1.
| Div (f, g) -> Div (simp f, simp g)
(* 1 * x -> x *)
| Mul (Float 1., f) -> simp f
(* x * 1 -> x *)
| Mul (f, Float 1.) -> simp f
(* 0 * x -> 0 *)
| Mul (Float 0., f) -> Float 0.
(* x * 0 -> 0 *)
| Mul (f, Float 0.) -> Float 0.
(* f1 * f2 -> calcul (f1 * f2) *)
| Mul (Float f1, Float f2) -> Float (f1 *. f2)
(* x * x -> x ^ 2 *)
| Mul (f, g) when f = g -> simp (Puis (simp f, Float 2.))
(* x ^ a * x -> x ^ (a + 1) *)
| Mul (Puis (f, g), h) when f = h -> Puis (simp f, simp (Add (simp g, Float 1.)))
(* (f1 * x) * f2 -> (f1 * f2) * x *)
| Mul (Mul (Float f1, f), Float f2) -> simp (Mul (Float (f1 *. f2), simp f))
(* f1 * (f2 * x) -> (f1 * f2) * x *)
| Mul (Float f1, Mul (Float f2, f)) -> simp (Mul (Float (f1 *. f2), simp f))
(* (x * f1) * f2 -> (f1 * f2) * x *)
| Mul (Mul (f, Float f1), Float f2) -> simp (Mul (Float (f1 *. f2), simp f))
(* f1 * (x * f2) -> (f1 * f2) * x *)
| Mul (Float f1, Mul (f, Float f2)) -> simp (Mul (Float (f1 *. f2), simp f))
| Mul (f, g) -> Mul (simp f, simp g)
(* x ^ 0 -> 1 *)
| Puis (f, Float 0.) -> Float 1.
(* 0 ^ x -> 0 *)
| Puis (Float 0., f) -> Float 0.
(* x ^ 1 -> x *)
| Puis (f, Float 1.) -> simp f
| Puis (f, g) -> Puis (simp f, simp g)
| Ln f -> Ln (simp f)
| Cos f -> Cos (simp f)
| Sin f -> Sin (simp f)
| Sqrt f -> Sqrt (simp f)
| Exp f -> Exp (simp f)
我的问题是:
对于x*x+x*x这样的简单函数,此函数有效。
但是如果我输入函数:2+x*x-x*x,就不会进行简化。结果是:2+x^2-x^2
我不知道如何解决这个问题,我从3天就开始了
我希望一切都清楚,有人可以给我一些提示!
祝你今天愉快 问题有两个方面:
2+x*x+x*x=>2+x^2+x^2==>2+2x^2
)-:formel=
次级(增加(浮动2,多重(变量“x”,变量“x”)),多重(变量“x”,变量“x”))
让我们按照执行顺序进行操作:
Sub(f,g)->Sub(simp f,simp g)
与
f=Add(Float 2.,Mul(Var“x”,Var“x”))
g=Mul(变量“x”,变量“x”)
simpf
,因此匹配Add(f,g)->Add(simpf,simpg)
2.1。它将Float(2.)
与Float f->Float f
2.2。当f=g->simp(Puis(simp f,Float 2.)时,它将Mul(Var(“x”),Var(“x”)
与Mul(f,g)匹配
simp g
,因此在f=g->simp(Puis(simp f,Float 2.)时匹配Mul(f,g)
Sub(添加(浮动2.,Puis(变量“x”,浮动2.)),Puis(变量“x”,浮动2.))
(2+x^2-x^2)
因为左(2+x^2
)和右(x^2
)子树不相等
解决问题(1) 一个想法是添加加法规则的交换属性,并将其转换为相同的先例列表。比如说,
Sub(f,Add(g,h))->[加(f),减(g),减(h)]
这样,您就可以识别相同的子树并消除它们
解决问题(2)
您需要根据运算符的优先级进行简化,例如,x*x
在x+x
简化为2x
之前变成x^2
。这可以通过修改代码多次运行解析来实现。每次更改子树时,都要在上面的树上重新运行简化
另一个想法是通过统一替换技术将其归档。我还没想清楚。但是这很有说服力,这是可行的。如果你的树看起来像
(2+x*x)-x*x
,那么似乎没有轨迹可以应用简化。如果你输入2+(x*x-x*x)
?如果我输入2+(x*x-x*x),结果很好:是2!非常感谢你的帮助!我会考虑的!但我不明白你在留言的最后提出了什么。。。请你把它改一下好吗?或者举个简单的例子?@Mathemataume看看这个。@Mathemataume如果答案对你有帮助,请接受它或投票支持。我想我解决了问题(1)。但仍然存在一些问题:-如何使用自下而上的方式进行简化?我是否应该以特定的方式访问树的每个节点?还是别的什么为了将像x^x/x这样的方程简化为x,我是否应该创建与解决问题(1)相同类型的函数?例如,x^2/x将由[Times(2,Var x),Division(1,Var x]->[Times(1,Var x)]表示。您可以在多次传递中执行此操作。继续运行简化程序,直到子树不再发生变化。或者另一个选项是使用类似于连续传递的技术,尽管如果您不熟悉FP,这非常具有挑战性。
let rec simplify f =
let f_simplify = simp f in
if f_simplify = f
then f_simplify
else simplify f_simplify
and simp f =
match f with
| Float f -> Float f
| Var x -> Var x
(* 0 + x -> x *)
| Add (Float 0., f) -> simp f
(* x + 0 -> x *)
| Add (f, Float 0.) -> simp f
(* f1 + f2-> calcul (f1 + f2) *)
| Add (Float f1, Float f2) -> Float (f1 +. f2)
(* x + x -> 2 * x *)
| Add (f, g) when f = g -> simp (Mul (Float 2., simp f))
(* f1 * x + x -> (f1 + 1) * x *)
| Add (Mul (Float f1, f), g) when f = g -> simp (Mul (Float (f1 +. 1.), simp f))
(* x + f1 * x -> (f1 + 1) * x *)
| Add (f, Mul (Float f1, g)) when f = g -> simp (Mul (Float (f1 +. 1.), simp f))
(* x * f1 + x -> (f1 + 1) * x *)
| Add (Mul (f, Float f1), g) when f = g -> simp (Mul (Float (f1 +. 1.), simp f))
(* x + x * f1 -> (f1 + 1) * x *)
| Add (f, Mul (g, Float f1)) when f = g -> simp (Mul (Float (f1 +. 1.), simp f))
(* f1 * x + f2 * x -> (f1 + f2) * x *)
| Add (Mul (Float f1, f), Mul (Float f2, g)) when f = g -> simp (Mul (Float (f1 +. f2), simp f))
(* x * f1 + f2 * x -> (f1 + f2) * x *)
| Add (Mul (f, Float f1), Mul (Float f2, g)) when f = g -> simp (Mul (Float (f1 +. f2), simp f))
(* f1 * x + x * f2 -> (f1 + f2) * x *)
| Add (Mul (Float f1, f), Mul (g, Float f2)) when f = g -> simp (Mul (Float (f1 +. f2), simp f))
(* x * f1 + x * f2 -> (f1 + f2) * x *)
| Add (Mul (f, Float f1), Mul (g, Float f2)) when f = g -> simp (Mul (Float (f1 +. f2), simp f))
| Add (f, g) -> Add (simp f, simp g)
(* 0 - x -> - x *)
| Sub (Float 0., f) -> simp (Mul (Float (-1.), simp f))
(* x - 0 -> x *)
| Sub (f, Float 0.) -> simp f
(* f1 - f2 -> calcul (f1 - f2) *)
| Sub (Float f1, Float f2) -> Float (f1 -. f2)
(* f1 * x + x -> (f1 + 1) * x *)
| Sub (f, g) when f = g -> Float 0.
| Sub (f, g) -> Sub (simp f, simp g)
(* 0 / x -> 0 *)
| Div (Float 0., f) -> Float 0.
(* x / 1 -> x *)
| Div (f, Float 1.) -> simp f
(* f1 / f2 -> calcul (f1 / f2) *)
| Div (Float f1, Float f2) -> Float (f1 /. f2)
(* x / x -> 1 *)
| Div (f, g) when f = g -> Float 1.
| Div (f, g) -> Div (simp f, simp g)
(* 1 * x -> x *)
| Mul (Float 1., f) -> simp f
(* x * 1 -> x *)
| Mul (f, Float 1.) -> simp f
(* 0 * x -> 0 *)
| Mul (Float 0., f) -> Float 0.
(* x * 0 -> 0 *)
| Mul (f, Float 0.) -> Float 0.
(* f1 * f2 -> calcul (f1 * f2) *)
| Mul (Float f1, Float f2) -> Float (f1 *. f2)
(* x * x -> x ^ 2 *)
| Mul (f, g) when f = g -> simp (Puis (simp f, Float 2.))
(* x ^ a * x -> x ^ (a + 1) *)
| Mul (Puis (f, g), h) when f = h -> Puis (simp f, simp (Add (simp g, Float 1.)))
(* (f1 * x) * f2 -> (f1 * f2) * x *)
| Mul (Mul (Float f1, f), Float f2) -> simp (Mul (Float (f1 *. f2), simp f))
(* f1 * (f2 * x) -> (f1 * f2) * x *)
| Mul (Float f1, Mul (Float f2, f)) -> simp (Mul (Float (f1 *. f2), simp f))
(* (x * f1) * f2 -> (f1 * f2) * x *)
| Mul (Mul (f, Float f1), Float f2) -> simp (Mul (Float (f1 *. f2), simp f))
(* f1 * (x * f2) -> (f1 * f2) * x *)
| Mul (Float f1, Mul (f, Float f2)) -> simp (Mul (Float (f1 *. f2), simp f))
| Mul (f, g) -> Mul (simp f, simp g)
(* x ^ 0 -> 1 *)
| Puis (f, Float 0.) -> Float 1.
(* 0 ^ x -> 0 *)
| Puis (Float 0., f) -> Float 0.
(* x ^ 1 -> x *)
| Puis (f, Float 1.) -> simp f
| Puis (f, g) -> Puis (simp f, simp g)
| Ln f -> Ln (simp f)
| Cos f -> Cos (simp f)
| Sin f -> Sin (simp f)
| Sqrt f -> Sqrt (simp f)
| Exp f -> Exp (simp f)