将自然语言转换为数学方程

5
我可以帮您进行翻译。以下是需要翻译的内容:

我已经在Java中制作了一个家庭自动化系统,并且我想添加简单的数学功能,例如加法、减法、乘法、除法、根和幂。

在系统目前的状态下,它可以将语句转换为标签,如以下示例所示:

例子:

Phrase: "what is one hundred twenty two to the power of seven"
Tagged: {QUESTION/math} {NUMBER/122} {MATH/pwr} {NUMBER/7}

例子:
Phrase: "twenty seven plus pi 3 squared"
Tagged: {NUMBER/27} {MATH/add} {NUMBER/3.14159} {MATH/multiply} {MATH/pwr} {NUMBER/2}

这个例子同样可以轻松转换成这样:

27 + 3.14159 * 3^2

每个标签都是一个对象,可以查询其值。
编辑:具体问题:
所以现在我需要一种方法将那组标签读取为一个方程,并返回数值结果。作为最后的手段,我可以使用谷歌或Wolfram Alpha,但那会更慢,而我正在尝试使自动化系统完全自包含。
如果您想查看整个源代码,请单击这里在GitHub上。请注意,我还没有提交最近的几个更改,因此我给出的一些与数学有关的示例可能无法正常工作。

3
这里的具体问题是什么? - Oliver Charlesworth
这里没有具体的文件,我只是想添加一个链接以防有人感兴趣。编辑:这个可能很有用:https://github.com/Sprakle/HomeAutomation/blob/master/HomeAutomation/src/net/sprakle/homeAutomation/interpretation/tagger/tags/Tag.java - Ben Cracknell
@OliCharlesworth 我认为他需要一种将分配给每个短语的标签转换为Java可以理解以返回数字的方法。如果我们有相关的确切文件,那将更有帮助。 - jocopa3
1
首先,查看Shunting Yard Algorithm。维基百科主要讨论将其用于转换为RPNAST,但是将其扩展到实际计算结果相当简单。 - Mac
你需要另一个字典来保存你的操作,比如“pow”,“multiply”等。随着你继续读取输入的字符串,然后简单地将你得到的数字与操作匹配,并打印出结果。 - Sterling Duchess
显示剩余3条评论
4个回答

3

1
您需要的是一种解析方法,可以从您的文本中构建一个方程并返回答案。我将采用一行代码,并演示如何制作这样的方法,然后您需要自行解决。请注意,这只是一个概念性的想法,一些语言可能比Java更适合这种操作。

{问题/数学} {数字/122} {算术/pwr} {数字/7}

//let's assume that the preprocessor reduces the input to an array that is something like this:
// [122, pwr, 7] (this is a very common construction in a language like LISP).

public static int math(string[] question){

   while(i < question.length){
      if(question[i] == "pwr"){
           return pow(Integer.parseInt(question[i-1]), Integer.parseInt(question[i+1]);
       }
       i++;
   }
  return 0;
}

基本上,你需要一种从中缀表达式转换为前缀表达式的好方法,并进行一些字符串转换。

可能有比我上面提供的更好的结构来完成这个任务,但是像这样做应该可以让你开始了。


或者你可以使用那个库。 - Peter Geiger

1

Ben,他说得对。接受自然语言的解析操作要困难得多。你需要做的是将数学优先级添加到表达式中。你可以通过将表达式放在某些预期形式中(如后缀/前缀/中缀),并提供一个评估算法(后缀最终变成pop(),pop(),evaluate(),push();)。这要求你将单个标记与调查运算符和操作数的交集的表格进行比较。这不是你可以快速或轻松完成的。


听起来是个相当大的任务,但既然这是一个学习项目(对我来说),那我也可以试试。编辑:算了,我找到了一个可以实现我想要的功能的库。 - Ben Cracknell

0

我写的代码依赖于给定标签的顺序是“NUMBER”、“MATH”、“NUMBER”、“MATH”、“NUMBER”,并且它完全忽略了数学中的运算规则。这只是一个你可以做的大纲,所以你可能需要稍微修改一下才能实现你想要的功能。

由于时间不足,我没有测试过这个文件,所以如果需要,请调试它!

import net.sprakle.homeAutomation.interpretation.tagger.tags.*;
import java.util.List;
import java.util.Arrays;

public class Math {

    private Tag[] tags; //Stores the converted tags as a "MathTag"

    //Requires an array of tags
    public Math(Tag[] inputTags) {
        tags = new MathTag[inputTags.length]; //create a new MathTag array
        System.arraycopy(inputTags, 0, tags, 0, tags.length); //Convert Tag array to MathTag array
    }

    //returns a value based on the tags
    //TODO: ADD MATHEMATICAL ORDER OF OPERATIONS!!!
    public double performMath() {
        double value = 0;//initial value to return

        for (int i = 0; i < tags.length; i++) { //perform initial check of the phrase given
            if (tags[i].getType() = TagType.NUMBER && !tags[i].getWasChecked() && i + 1 < tags.length) {
                value = performOperation(i, value, Double.parseDouble(tags[i].getValue()), tags[i+1].getType());
            } else if (tags[i].getType() = TagType.MATH && !tags[i].getWasChecked() && i + 1 < tags.length) {
                value = performOperation(i, value, Double.parseDouble(tags[i + 1].getValue()), tag.getType()); //I'm not positive if this would not cause issues
            }
        }
    }

    //Perform individual operations given the index of the operation, value1, value2, and the operation type
    //The order of the array "operations" must match the order of the operations in the switch statement.
    public double peformOperation(int i, double value1, double value2, String operation) {
        String[] operations = {"add", "subtract", "multiply", "divide", "pwr", "root"}; //Array of operations
        List list = Arrays.asList(operations); //Not exactly effecient, used to check what operation to perform

        switch (list.indexOf(operation)) { //Perform a task based on the operation
            case 0: //Addition
                tags[i].setChecked(true); //Number
                tags[i + 1].setChecked(true); //Operation
                return value1 + value2;
            case 1: //Subtraction
                tags[i].setChecked(true); //Number
                tags[i + 1].setChecked(true); //Operation
                return value1 - value2;
            case 2: //Multiplication
                tags[i].setChecked(true); //Number
                tags[i + 1].setChecked(true); //Operation
                return value1 * value2;
            case 3: //Division
                tags[i].setChecked(true); //Number
                tags[i + 1].setChecked(true); //Operation
                return value1 / value2;
            case 4: //Power
                tags[i].setChecked(true); //Number
                tags[i + 1].setChecked(true); //Operation
                return value1 * value1;
            case 5: //Square Root
                tags[i].setChecked(true); //Number
                tags[i + 1].setChecked(true); //Operation
                return Math.sqrt(value1);
        }

        return error(); //Non-valid operation found
    }

    //Need some way to detect an error
    public double error() {
        return 0;
    }

    //Need some way to check if a tag was looked at before
    class MathTag extends Tag {

        protected static boolean wasChecked = false;

        public void setChecked(boolean checked) {
            wasChecked = true;
        }

        public boolean getWasChecked() {
            return wasChecked;
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接