Юлия-Ланг сравнение выражения и коммутативности
ОК, мой заголовок не велик, но это легко объяснить на примере.
julia>a = :(1 + 2)
julia>b = :(2 + 1)
julia>a == b
false
У меня есть два выражения а и б. Я хотел бы знать, если они дадут мне такие же результаты без оценки.
Я думал, что коммутативные операторы, такие как + или *, могут сделать вывод, что результаты будут одинаковыми.
РЕДАКТИРОВАТЬ: Другой способ понять это - сравнить очень специфическое подмножество выражений, которые могут определить коммутативность функции: Expr(:call, +, a, b) <=> Expr(:call, +, b, a)
2 ответа
Мы можем написать довольно простую функцию, чтобы проверить, имеют ли два массива одинаковые элементы, по порядку упорядочения:
function eq_modulo_ordering!(xs, ys) # note !, mutates xs and ys
while !isempty(xs)
i = findfirst(isequal(pop!(xs)), ys)
i === nothing && return false
deleteat!(ys, i)
end
isempty(ys)
end
eq_modulo_ordering(xs, ys) = eq_modulo_ordering!(copy(xs), copy(ys))
Затем мы можем использовать эту функцию, чтобы проверить, эквивалентны ли два выражения верхнего уровня.
function expr_equiv(a::Expr, b::Expr, comm)
a.head === b.head || return false
a.head === :call || return a == b
a.args[1] ∈ comm || return a == b
eq_modulo_ordering(a.args, b.args)
end
expr_equiv(a, b, comm) = a == b
expr_equiv(a, b) = expr_equiv(a, b, [:+])
В случае, если мы хотим проверить, что два выражения полностью эквивалентны за пределами верхнего уровня, мы могли бы изменить наши функции, чтобы использовать взаимную рекурсию, чтобы проверить, являются ли подвыражения expr_equiv
, скорее, чем isequal
,
function eq_modulo_ordering!(xs, ys, comm) # note !, mutates xs and ys
while !isempty(xs)
x = pop!(xs)
i = findfirst(b -> expr_equiv(x, b, comm), ys)
i === nothing && return false
deleteat!(ys, i)
end
isempty(ys)
end
eq_modulo_ordering(xs, ys, comm) = eq_modulo_ordering!(copy(xs), copy(ys), comm)
function expr_equiv(a::Expr, b::Expr, comm)
a.head === b.head || return false
a.head === :call || return a == b
a.args[1] ∈ comm || return all(expr_equiv.(a.args, b.args, Ref(comm)))
eq_modulo_ordering(a.args, b.args, comm)
end
expr_equiv(a, b, comm) = a == b
expr_equiv(a, b) = expr_equiv(a, b, [:+])
Теперь мы можем использовать expr_equiv
как и ожидалось, опционально предоставляя список функций, которые являются коммутативными.
julia> expr_equiv(:((a + b + b) * c), :((b + a + b) * c))
true
julia> expr_equiv(:((a + a + b) * c), :((b + a + b) * c))
false
julia> expr_equiv(:(c * (a + b + b)), :((b + a + b) * c), [:+, :*])
true
Это невозможно. Выяснение того, имеют ли две программы один и тот же результат без их оценки, называется функциональной проблемой и доказуемо эквивалентно решению проблемы остановки.
Невозможно вычислить, будут ли фрагменты кода иметь одинаковый результат.