У меня есть следующий союз как мой AST для символического выражения математики:Упрощая вложенные умножения в математическом выражении
type Expr =
| Const of float
| X of float * float
| Sum of Expr * Expr
| Mul of Expr * Expr
| Pow of Expr * Expr
| Sin of Expr
| Cos of Expr
static member (+) (e1,e2) = Sum(e1,e2)
static member (*) (e1,e2) = Mul(e1,e2)
static member (/) (e1,e2) = Mul(e1, Pow(e2,Const -1.0))
let (!) e = Mul(Const -1.0,e)
let (^) e n = Pow(e ,n)
Проблема:
Я пытаюсь упростить выражения, как Mul(Mul(expr1,expr2),expr3)
или Mul(e,Mul(e1,e2))
или вообще при наличии n-вложенных умножений в выражении.
Я написал эту функцию simp
, которая принимает Expr
и рекурсивно упрощает вещи вниз. (Только некоторая алгебра), два правила этой функции (читать комментарии в коде) вызывает бесконечную рекурсию, когда функция simp
вызывается из fullSimp
let rec simp expr =
match expr with
| Mul(Sum(e1,e2),e) -> simp (e1*e) + simp (e2*e)
| Mul(e,Sum(e1,e2)) -> simp (e1*e) + simp (e2*e)
| Mul(e1,e2) when e1 = e2 -> simp e1^Const 2.0
| Mul(Mul(e1,e2),e) -> Mul(simp (e1*e),simp e2) // adding this rule makes the function 'fullSimp' recurse infinitely
| Mul(e,Mul(e1,e2)) -> Mul(simp (e2*e), simp e1) // same as above
| Mul(e1,e2) -> simp e1 * simp e2
| Cos e -> Cos(simp e)
| Sin e -> Sin(simp e)
| _ -> expr
, а затем есть функция fullSimp
, которая вызывает simp
до simp
не возвращает никаких изменений в упрощенной версии выражения
let rec fullSimp e =
let simplified = simp e
if simplified <> e then fullSimp simplified
else simplified
Попытка оценить следующее выражение дает бесконечную рекурсию !!!
fullSimp (Mul (Mul (Const 2.0,Cos (X (1.0,1.0))),Sin (X (1.0,1.0))))
// notice the nested multiplications here
// also notice that this does not simplify any furthur so the function
// should return the same input.
Удаление двух правил из simp
решает бесконечную рекурсию, но не проблема упрощения вложенных умножений.
Редактировать: Чтобы думать о проблеме по-другому, я пытаюсь собрать (умножить) константы и varibales, которые находятся в вложенных узлах mulitplication. Например, я пытаюсь принять такое выражение
Mul(Const 5.0,Mul(Mul (Const 2.0,Sin (X (4.0,2.0))),Mul (Cos (X (4.0,2.0)),X (8.0,1.0))))
и превратить его в Mul (Mul (X (80.0,1.0),Sin (X (4.0,2.0))),Cos (X (4.0,2.0)))
, который не может упрощенный любую Furthur
Примечания: Согласно обратной связи в комментариях я редактировал это пару раз. Теперь, надеюсь, ясно, в чем проблема. Извинения за несоответствия.
Можете ли вы опубликовать полную минимальную часть кода, который воспроизводит ошибку? – Gustavo
@Gustavo Я не получаю сообщение об ошибке, добавляя правило 'Mul (Mul (e1, e2), e) -> Mul (simp (e1 * e), simp e2)' будет заставлять программу застревать, например, когда полностью упрощая производную tan (x), которая анализируется как sin (x) * cos (x)^- 1. –
Я знаю, это будет воспроизведение проблемы. Но код, который вы опубликовали, является неполным, он не компилируется. – Gustavo