Постараюсь быть объективным в вопросе.
У меня есть база данных с миллионами математических формул, созданных приложением, это формулы, которые соответствуют логике:
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 тысяч вариантов до менее чем трех сотен.
Однако по мере увеличения размера (а не сложности, потому что они не сложные) формул моя рутина перестает быть эффективной.
Мне нужен алгоритм, а не рутина, чтобы применить математическую редукцию, которую мы выучили в школе.
Я думаю, что это возможно, поскольку формулы стандартизированы и ограничены 5 основными математическими операциями.
Я использую класс EvalMath, полученный в GitHub, чтобы помочь в сокращении и выполнении формул.
Чтобы дать вам лучшее представление, формулы являются абстрактными, и каждый символ «@» заменяется в реальном времени константами и переменными.
(@ + @)
(@ / @)
(@ ** @)
((@ + @) + @)
((@ + @) ** @)
((@ - @) + @)
((@ - @) / @)
((@ - @) ** @)
((@ * @) + @)
((@ * @) / @)
((@ * @) ** @)
((@ / @) / @)
Вот фрагмент кода 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:
Я думаю, что если бы при создании формул использовалась «обратная полировка», все было бы намного проще, но с формулами, которые у меня есть, мне нужно переставить параметры (в возрастающем или убывающем алфавитном порядке), чтобы иметь возможность Сравните их.
В РПН:
(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 вложенных правил.
ratsimp
для упрощения выражений; наверное, в Sympy есть похожая функция. Если вам необходимо написать собственное решение, я советую взглянуть на небольшую систему алгебры, описанную в «Парадигмах программирования ИИ» П. Норвига, и адаптировать концепции к вашей проблеме. - person Robert Dodier   schedule 10.08.2017