构建计算机代数系统
我正在用 PHP 创建 CAS(计算机代数系统),但现在陷入困境。我正在使用此网站。
现在我写了一个分词器。它将这样的方程转换
1+2x-3*(4-5*(3x))
为:(
NUMBER PLUS_OPERATOR NUMBER VAR[X] MINUS_OPERATOR NUMBER MULTIPLY_OPERATOR GROUP
其中 group 是另一组标记)。我怎样才能简化这个方程?是的,我知道你可以做什么:添加 X 变量,但它们位于子组中。处理这些令牌的最佳方法是什么?
I'm creating a CAS (Computer Algebra System) in PHP, but I'm stuck right now. I am using this website.
Now I wrote a tokenizer. It will convert an equation like this:
1+2x-3*(4-5*(3x))
to this:
NUMBER PLUS_OPERATOR NUMBER VAR[X] MINUS_OPERATOR NUMBER MULTIPLY_OPERATOR GROUP
(where group is another set of tokens). How can I simplify this equation? Yeah, I know what you can do: adding X-vars, but they are in the sub-group. What is the best method I can use for handling those tokens?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
真正有用的下一步是构建一个解析树:
您可以通过编写其中一个中缀解析器。您可以通过编写一个简单的递归下降解析器来做到这一点,或者通过引入大枪和 使用解析器生成器。无论哪种情况,它都有助于构建正式语法:
请注意,此语法不处理
2x
语法,但它应该很容易添加。请注意语法规则中递归的巧妙使用。
primary
仅捕获变量、数字和括号表达式,并在遇到运算符时停止。multiplicative
解析由*
符号分隔的一个或多个primary
表达式,但当遇到+
或 <代码>-符号。additive
解析由+
和-
分隔的一个或多个乘法
表达式,但在遇到时停止>)
。因此,递归方案决定了运算符的优先级。手动实现 预测解析器 并不太困难,因为我已完成以下操作(在 ideone.com 上查看完整示例):
好的,现在您有了这个可爱的解析树,甚至还有一张漂亮的图画。现在怎么办?您的目标(目前)可能是简单地组合术语以获得以下形式的结果:
我将把这部分留给您。拥有解析树应该会让事情变得更加简单。
A really useful next step would be to construct a parse tree:
You'd make one of these by writing an infix parser. You could either do this by writing a simple recursive descent parser, or by bringing in the big guns and using a parser generator. In either case, it helps to construct a formal grammar:
Note that this grammar does not handle the
2x
syntax, but it should be easy to add.Notice the clever use of recursion in the grammar rules.
primary
only captures variables, numbers, and parenthesized expressions, and stops when it runs into an operator.multiplicative
parses one or moreprimary
expressions delimited by*
signs, but stops when it runs into a+
or-
sign.additive
parses one or moremultiplicative
expressions delimited by+
and-
, but stops when it runs into a)
. Hence, the recursion scheme determines operator precedence.It isn't too terribly difficult to implement a predictive parser by hand, as I've done below (see full example at ideone.com):
Okay, so now you have this lovely parse tree, and even a pretty picture to go with it. Now what? Your goal (for now) might be to simply combine terms to get a result of the form:
I'll leave that part to you. Having a parse tree should make things much more straightforward.
PHP 擅长字符串、数字和数组。但对于实现符号公式操作来说,它是一种很糟糕的语言,因为它没有用于处理“符号表达式”的本地机制,而您真正需要的是树。是的,您可以实施所有这些机制。更难的是进行代数运算。如果你想构建一些半复杂的东西,这是相当多的工作。理想情况下,您希望机器能够帮助您直接轻松地编写转换。
例如,您将如何实现任意代数规则?结合性和交换性?术语“远距离匹配”?,例如
您可以查看如何实现一个简单的 CAS 使用我们的DMS程序转换系统。 DMS 具有内置的交换性和结合性等硬数学结构,您可以显式编写代数规则来对符号公式进行运算。
PHP is good at strings, numbers, and arrays. But it is a poor language for implementing symbolic formula manipulation, because it has no native machinery for processing "symbolic expressions", for which you really want trees. Yes, you can implement all that machinery. What is harder is to do the algebraic manipulations. Its quite a lot of work if you want do build something semi-sophisticated. Ideally you want machinery to help you write the transformations directly and easily.
For instance, how will you implement arbitrary algebra rules? Associativity and commutativity? Term "matching at a distance"?, e.g.
You can look at how a simple CAS can be implemented using our DMS program transformation system. DMS has hard mathematical constructs like commutativity and associativity built in, and you can write algebra rules explicitly to operate on symbolic formulas.
这本书
计算机代数和符号计算:Joel S. Cohen 的数学方法
描述了一种自动简化代数表达式的算法。
此算法用于 C# 的 Symbolism 计算机代数库。按照您的示例,以下 C# 程序:
在控制台上显示以下内容:
The book
Computer Algebra and Symbolic Computation: Mathematical Methods by Joel S. Cohen
describes an algorithm for automatic simplification of algebraic expressions.
This algorithm is used in the Symbolism computer algebra library for C#. Going with your example, the following C# program:
displays the following at the console: