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

时间:2013-04-07 23:36:12

标签: java math nlp

我有一个使用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

每个标记都是一个可以查询其值的对象。

编辑:具体问题:

所以现在我需要一种方法来将该组标签作为方程式读取,并返回数值结果。作为最后的手段,我可​​以使用google或wolfram alpha,但这会更慢,我正在努力保持自动化系统完全自包含。

如果您想查看整个来源,here it is in github. 请注意,我没有提交最后几个更改,所以我给出的一些数学相关的东西不起作用。

4 个答案:

答案 0 :(得分:3)

经过一些更多的googleing(我最初不知道我在做什么的名字)我找到了一个已经做过类似事情的人:

http://www.objecthunter.net/exp4j/

编辑:完成: https://github.com/Sprakle/HomeAutomation/blob/master/HomeAutomation/src/net/sprakle/homeAutomation/interpretation/module/modules/math/Math.java

答案 1 :(得分:1)

本,他是对的。采用自然语言的解析操作要困难得多。您需要做的是为表达式添加数学优先级。你这样做的方法是将表达式放在一些预期的形式,如post / pre / in-fix,并提供一个评估算法(post-fix最终为pop(), pop(), evaluate(), push();。这要求你检查个别令牌一个调查运算符和操作数交集的表。这不是你能快速或轻松地做的事情。

答案 2 :(得分:1)

你需要的是一个解析方法,它将构建一个方程并从你的文本中返回一个答案。我将采取一条线,并通过制作这样一种方法,然后你需要自己解决。请注意,这只是一个普遍的想法,除了Java之外的某些语言可能更适合这种操作。

{QUESTION / math} {NUMBER / 122} {MATH / pwr} {NUMBER / 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;
}

基本上你需要的是一个很好的方法,从中缀到前缀表示法,带一点字符串到任何转换。

这样做的结构可能比我上面制作的更好,但是这样的事情可以让你前进。

答案 3 :(得分: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;
        }
    }
}