用ocaml简化计算机代数系统的方程

用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

你好!我目前正试图用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
%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”)

  • 从(1)开始,它执行
    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)