Документация Engee

Часто задаваемые вопросы

Ограничения символьных вычислений

Не удалось преобразовать функцию в символьное уравнение. Что делать?

Если отображается следующее сообщение об ошибке:

ERROR: TypeError: non-boolean (Num) used in boolean context

скорее всего, причина в алгоритме, который невозможно отследить в чисто символьном алгоритме. Этим характеризуются, например, многие численные решатели. Ошибка появляется, когда вы делаете что-то вроде: если x < tol. Если x — число, то значение верно или неверно. Если x — символ, то это x < tol, поэтому Julia просто не может знать, сколько итераций нужно сделать, и возникает ошибка.

Это проявляется, например, в адаптивных алгоритмах:

function factorial(x)
  out = x
  while x > 1
    x -= 1
    out *= x
  end
  out
end
factorial (generic function with 1 method)

Количество итераций этого алгоритма зависит от значения x, поэтому статического представления алгоритма не существует. Если x равен 5, то это out = x*(x-1)(x-2)(x-3)(x-4), а если x равен 3, то это out = x(x-1)*(x-2). Поэтому не стоит удивляться тому, что:

using Symbolics
@variables x
try
    factorial(x)
catch e
    e
end
TypeError(:if, "", Bool, x > 1)

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

Пространство алгоритмов, которые можно преобразовать в символьные алгоритмы, называют квазистатическим, то есть существует способ представления алгоритма как статического. Разрешены циклы, но количество итераций цикла не должно требовать от вас знание значения символа x. Если алгоритм является квазистатическим, трассировка Symbolics.jl создаст статическую форму кода, развертывая операции и генерируя плоское представление алгоритма.

Что можно сделать?

Если вам нужно представить эту функцию f символически, следует убедиться, что она не трассируется, а напрямую представлена в базовом вычислительном графе. Точно так же как sqrt(x) символически не пытается представить базовый алгоритм, это должно быть сделано и с вашей функцией f. Для этого нужно выполнить @register_symbolic f(x). Если вам нужно определить такие объекты, как производные функции f, см. документацию по регистрации функций.

Тесты на равенство и принадлежность множеству

Сравнение символов с помощью == дает символьное уравнение, а не Bool. Чтобы получить Bool, вызовите isequal.

Чтобы проверить, является ли символ частью коллекции символов, то есть вектора, создайте Set и используйте in, например:

try
    x in [x]
catch e
    e
end
TypeError(:if, "", Bool, x == x)
x in Set([x])
true
any(isequal(x), [x])
true