2013-04-07 5 views
4

У меня есть домашняя система автоматизации, работающая на 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 

Каждый тег - объект, который может быть запрошен для его значения.

Edit: Конкретный вопрос:

Так что теперь мне нужен способ, чтобы прочитать эту группу тегов как уравнение, и возвращает числовой результат. В крайнем случае я мог бы использовать google или wolfram alpha, но это будет медленнее, и я пытаюсь полностью автоматизировать систему автоматизации.

Если вы хотите увидеть весь источник, here it is in github. Обратите внимание, что я не совершил последние несколько изменений, поэтому некоторые из связанных с математикой вещей, которые я привел, не будут работать.

+3

В чем конкретный вопрос здесь? –

+0

Нет конкретного файла, я просто подумал, что добавлю ссылку на тот случай, если кому-то будет интересно. Редактировать: это может быть полезно: https://github.com/Sprakle/HomeAutomation/blob/master/HomeAutomation/src/net/sprakle/homeAutomation/interpretation/tagger/tags/Tag.java –

+0

@OliCharlesworth Я думаю, ему нужен способ превратить теги, назначенные каждой фразе, в выражение, которое Java может понять, чтобы вернуть число. Было бы более полезно, если бы у нас был точный файл (ы), о котором идет речь. – jocopa3

ответ

1

Бен, он прав. Действие синтаксического анализа, которое берет естественный язык, намного сложнее. Что вам нужно сделать, так это добавить математическое преимущество в выражение. То, как вы это делаете, заключается в том, чтобы поместить выражение в какую-то ожидаемую форму, например post/pre/in-fix, и предоставить алгоритм оценки (post-fix заканчивается pop(), pop(), evaluate(), push();. Это требует, чтобы вы проверяли отдельные токены на таблицу, которая исследует пересечение операторов и операндов. Это не то, что вы можете сделать быстро или легко.

+0

Похоже, это задача, но поскольку это предназначено для обучения (для меня), я бы тоже попробовал. Edit: Nevermind, я нашел библиотеку, которая делает то, что я хочу. –

1

Что вам нужно, это метод синтаксического анализа, который будет строить уравнение и возвращать ответ из вашего текста. Я возьму одну строчку и прохожу через такой метод, который вам нужно будет придумать для себя. Обратите внимание, что это всего лишь общая идея и что некоторые языки, отличные от Java, могут быть более подходящими для такого рода операций.

{ВОПРОС/математик} {NUMBER/122} {МАТЕМАТИК/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; 
} 

В основном то, что вам нужно, это хороший способ перехода от инфикса префикса нотации с немного строк для любых преобразований.

Для этого есть более приятные структуры, чем то, что я произвел выше, но что-то вроде этого должно заставить вас идти.

+0

Или вы можете использовать эту библиотеку. –

0

Код я написал полагается, что данный порядок тегов «NUMBER» «МАТЕМАТИКА» «НОМЕР» «МАТЕМАТИКА» «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; 
     } 
    } 
}