如何通过尽可能地减少数学公式来简化数学公式

时间:2017-08-09 16:39:00

标签: php math formulas

我会努力在这个问题上保持客观。

我有一个数据库,其中包含由应用程序创建的数百万个数学公式,这些是遵循逻辑的公式:

1)只涉及5个数学运算:加法,减法,乘法,除法和幂(+ - * / ^)

2)每个操作都用括号分隔/分组。

“参数”可以很简单,例如常数或变量。

示例:(x + 15)

在复合案例中,我可能有:

(x *(x + 15))

重要的是要记住,使用括号可以保证正确的操作顺序。

示例:

((x *(x + 15))/ 15)

我的挑战是减少这些公式。

当操作相同且无论因素顺序如何时,它们都没用或重复很多。

示例:

((((x + 4)+ 8) - x)/ 12)

等于1,它不是公式,它是常数,我不得不忽略它。

需要消除像((x + 4)+ 8)和((8 + x)+ 4)这样的重复。

这就是我需要减少的原因。

请注意,所有公式都使用括号和操作之间的空格进行标准化。

我使用正则表达式在PHP中创建了一个例程来进行替换,我设法在一个特定的公式中从8千种可能性减少到不到300种,从而取得了巨大的进步。

然而,由于公式的大小(并非复杂因为它们并不复杂)增加了,我的例程再也不能有效了。

我需要一种算法,而不是常规,来应用我们在学校学到的数学减少。

我认为这是可能的,因为公式是标准化的,并且限于5个基本的数学运算。

我正在使用GitHub中获得的EvalMath类来帮助减少和执行公式。

为了给你一个更好的主意,公式是抽象的,每个“@”由常量和变量实时替换。

(@ + @)
(@ / @)
(@ ** @)
((@ + @) + @)
((@ + @) ** @)
((@ - @) + @)
((@ - @) / @)
((@ - @) ** @)
((@ * @) + @)
((@ * @) / @)
((@ * @) ** @)
((@ / @) / @)

这是一段PHP代码,是我的简化程序的一部分。

在WHILE(TRUE)中,我将规则重复,直到没有替换为止。

最后,我有一个数组,其中包含许多重复数据,通过对公式元素进行一些缩减和重新排序,这是array_unique()解决的问题。

我真的需要帮助,我的大脑正在爆发这个问题。

谢谢。

<?php
    $Math_Formulas = array(
        '(((x + 7) ** 9) - 9)',
        '(((x ^ 3) - 9) - 5)',
        '(((2 + x) + x) * x)',
        '(((x + 3) / 6) / 8)',
        '(((x - 5) + 6) ** 2)',
        '(1024 ^ (x / 5))',
        '((3 - (x + 6)) + 3)',
        '(((x ^ 3) + 9) * 6)',
    );

    while (TRUE)
    {
        $changed = FALSE;

        // Rule 1: (x - x) = 0
        for ($i = 0; $i < count($Math_Formulas); $i++)
        {
            $Formula = trim(preg_replace_callback('/([^-]?)([a-z]+?) [-] ([a-z]+?)/', function($matches) {
                $Expression = $matches[0];
                if ($matches[2] == $matches[3])
                {
                    $Expression = $matches[1] . '0';
                }
                return($Expression);
            }, $Math_Formulas[$i]));
            if ($Formula != $Math_Formulas[$i])
            {
                $changed = TRUE;
                $Math_Formulas[$i] = $Formula;
            }
        }

        // Rule 2: ...

        if (!$changed)
        {
            break;
        }
    }

    $Math_Formulas = array_values(array_unique($Math_Formulas));
?>

更新1:

我认为如果在公式的创建中使用了“反向抛光符号”,一切都会容易得多,但是根据我的公式,我需要重新排列参数(按升序或降序字母顺序)到能够比较它们。

在RPN:

(x + 4)+ 5)变为“x 4 5 +”

(X + 5)+ 4)变为“x 5 4 +”

如何比较两者?那些更大的功能呢?

我认为我犯了一个错误,因为我没有详细说明14“正则表达式”中使用的技术,我正在申请尽可能地简化这些公式。这个过程不仅仅是正则表达式:

原始公式:(((4 - 5)+ x)+ 8)

步骤1:增加(或减法或乘法)两到两个常数并减少表达式,不带括号。

公式:(( - 1 + x)+ 8)

步骤2:删除((n + - n)+ - n)或(n + - (n + - n))的括号。

公式:( - 1 + x + 8)

步骤3:按字母顺序降序重新排序参数。

公式:(x + 8 - 1)

步骤4:在循环中,再次执行步骤1。

最终公式:(x + 7)

还有更多变换,例如(x + x + x)变为(3 * x),( - x + x)变为0。

所有这一切都变得美丽,但当我遇到诸如((x * 9)*(x * 5))/ 9)之类的功能时,这种逻辑失去了效率。我必须至少再创建14个其他嵌套规则。

1 个答案:

答案 0 :(得分:1)

因此,一般方案是首先将表达式转换为表达式树格式。这是树结构,其中每个节点表示数学运算,数字或变量。您可以使用分流码算法进行转换,并且可能会发现可以修改evalmath以生成树而不是简单地对其进行评估。可能还有其他Python库可以做的不仅仅是evalmath。

一旦你有了一个树形结构,它就会变得更容易操作。你可以操纵小的子树来制作更简单的形式,应用你在高中学到的一些数学规则。

例如,您可能希望展开括号。表达式(x + 3)*(x + 5)将表示为树

              *
        +           +
     x     3     x     5 

这棵树可以重写为x ^ 2 + 8 x + 15

              +
        ^                +
     x     2        *        15
                 x     8

一般方案可能会扩展所有括号。然后收集类似的术语并简化。