【问题标题】:How to convert a mathematical expression tree to its reduced form?如何将数学表达式树转换为其简化形式?
【发布时间】:2012-04-08 01:06:14
【问题描述】:

我正在做一些数值分析作业,我应该评估、绘制和区分数学表达式。除其他外。我用 Java 实现了表达式树。

到目前为止,我可以构建表达式树,用 Latex 显示它,评估它,绘制它并获得它的导数。树中复合函数实现的接口有以下方法: Function[] child();
void addChild(Function chld);
double evaluate(HashMap subMap);
String toLatex();
int precedence();
Function derivative();

到目前为止我编码的实现是:Constant, Variable, Add, Subtract, Multiply, Divide, Power, Sine, Cosine, Ln.
现在,当我区分一些基本功能时,我会以非简化形式得到它:
d/dx(x^2) ===> x^2 * (1 * 2 / x + 0 * ln(x))
那是因为导数是以最通用的方式实现的。

我想到的解决方案是,在树中每个节点f的构造上,给定f的孩子,我递归地减少孩子,然后做一些朴素的重建。经过这样的重建,孩子们“一起”减少了f
例如,给定表达式 0 * x,树应如下所示:

* / \ 0×

在 * 节点的构造中,如果它的一个子节点是零常数,则 * 节点变成零常数。当然也会扔掉它的孩子。

0

对于所有不同的乘法情况,依此类推。 这需要代表我进行大量分析,并且可能无法涵盖所有​​情况——请记住,乘法并不是唯一需要的函数——。

任务是:给定一个表达式树,我怎样才能对它进行基本的归约?如果您可以向我推荐任何可以解决此问题的链接或论文——最好是在优雅的 OO 方式 - 或者如果您之前解决过它,您的帮助将真的感激。

【问题讨论】:

  • 实际上,您需要实施很多规则,而忘记涵盖所有情况。您需要的是以前做过这件事的人(不是我)的经验,它可以告诉您一种明智的 OOP 设计(结合例如策略、访问者、复合等)。不过,恕我直言,你最好使用函数式语言。
  • 好的,感谢您的快速回复。这就是我要寻找的“以前做过这件事的人”。我不允许使用除 Java 之外的任何东西。 :)
  • 你选择了(或被交给了)一个相当困难的问题。这个issc.uj.ac.za/symbolic/symbolic.html 可能会有所帮助。

标签: java math expression composite


【解决方案1】:

我有完全相同的任务减去乳胶。我相信您没有正确处理导数评估。

这基本上是我作业的复制粘贴,这里的关键是使用某种 epsilon 并使用您已经拥有的其他功能。 关于 derivation difference quotients 的进一步解释可以在维基百科中找到

<!-- language: lang-java -->
/**
* 
This class represents a RealFunction that is the derivative
 of the other real function.

*/

public class DerivativeFunction implements RealFunction{
      private RealFunction toDiff;
    private double _epsilon;
    private static final int TWO = 2;
    /**
    * Constructs a new DerivativeFunction object.
 Numerical computation of the derivative is performed at each point,
 epsilon is used to approximate the
 lim (f(x+t/2) - f(x-t/2))/t.

    * @param f the function whose derivative is to be approximated
    * @param epsilon the value used instead of t-->0
      in the derivative formula.
    */

    public DerivativeFunction(RealFunction f, double epsilon) {
        this.toDiff = f;
        this._epsilon = epsilon;

    }
    /**
    * returns the value of f'(x).

    * @param x the x value given.

    * @return the value f'(x) of this function i.e (f(x+epsilon/2)-f(x - epsilon/2))/epsilon.
*/

    public double valueAt(double x) {
        double reminder = this._epsilon/TWO;
        return (this.toDiff.valueAt(x + reminder) - this.toDiff.valueAt(x - reminder))/this._epsilon;
    }
}

【讨论】:

  • 谢谢,但这不是我想要的。推导只是一个例子,它不是分配的重点。我的意思是,一般来说,在构建任何表达式时,你可能会有一些奇怪的函数或冗余。假设用户输入 [x * x],您必须减少它。或者当你试图将两个函数相乘 [2 * x] * [3 * x^2] 时,你不能这样。作业的主要目的是绘制一些输入函数。
【解决方案2】:

我有非常相似的任务:我需要简化代数表达式,例如(-1)*a + (b - a) + 2*a =&gt; b

经过一番谷歌搜索,发现Computer algebra systems 应该处理此类任务。

这里有一个很好的此类库列表:http://en.wikipedia.org/wiki/Comparison_of_computer_algebra_systems

刚刚尝试过MathEclipse/symja 库 - 它有相当不错的在线评估器(使用这个库实现),它似乎可以满足我的需要,即减少 0*x =&gt; 0a - b + (-1)*a =&gt; -b 等表达式。

您也可以查看其他 Java CAS 库。

希望这会有所帮助...

【讨论】:

  • 有点晚了,但非常感谢! symja 是我一直在寻找的。​​span>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-15
相关资源
最近更新 更多