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

Типы переменных и уравнений

IR Symbolics отражает Julia AST, но поддерживает собственное выполнение математических действий согласно математической семантике. Основой IR является тип Sym, который определяет символьную переменную. Зарегистрированные (математические) функции в Sym (или объектах istree) возвращают выражение, которое istree. Например, op1 = x+y — это один символьный объект, op2 = 2z — другой, а op1*op2 — еще один объект дерева. Затем в верхней части Equation, обычно записываемое как op1 ~ op2, определяет символьное уравнение между двумя операциями.

Типы

Sym, Term и FnType содержатся в SymbolicUtils.jl. Обратите внимание, что в Symbolics мы всегда используем Sym{Real}, Term{Real} и FnType{Tuple{Any}, Real}. Чтобы получить аргументы объекта istree, используйте arguments(t::Term), а чтобы получить операцию, используйте operation(t::Term). Однако обратите внимание, что никогда не следует выполнять диспетчеризацию Term или тестировать isa Term. Вместо этого нужно использовать SymbolicUtils.istree, чтобы проверить, определены ли arguments и operation.

# Symbolics.@variablesMacro

Определяет одну или несколько неизвестных переменных.

@variables t α σ(..) β[1:2]
@variables w(..) x(t) y z(t, α, x)

expr = β[1]* x + y^α + σ(3) * (z - t) - β[2] * w(t - 1)

(..) означает, что значение должно быть оставлено без вызова.

Symbolics поддерживает создание переменных, обозначающих массив некоторого размера.

julia> @variables x[1:3]
1-element Vector{Symbolics.Arr{Num, 1}}:
 x[1:3]

julia> @variables y[1:3, 1:6] # поддержка тензоров
1-element Vector{Symbolics.Arr{Num, 2}}:
 y[1:3,1:6]

julia> @variables t z(t)[1:3] # также работает для зависимых переменных
2-element Vector{Any}:
 t
  (z(t))[1:3]

Символ или выражение, представляющее массив, можно преобразовать в массив символов или выражений с помощью функции scalarize.

julia> Symbolics.scalarize(z)
3-element Vector{Num}:
 (z(t))[1]
 (z(t))[2]
 (z(t))[3]

Обратите внимание, что @variables возвращает вектор всех определенных переменных.

@variables также может принимать значения символов времени выполнения с помощью оператора интерполяции $, и в этом случае @variables не присваивает значение автоматически, а только возвращает вектор символьных переменных. Здесь применяется и весь остальной синтаксис.

julia> a, b, c = :runtime_symbol_value, :value_b, :value_c
(:runtime_symbol_value, :value_b, :value_c)

julia> vars = @variables t $a $b(t) $c(t)[1:3]
4-element Vector{Any}:
      t
 runtime_symbol_value
   value_b(t)
       (value_c(t))[1:3]

julia> (t, a, b, c)
(t, :runtime_symbol_value, :value_b, :value_c)

# Symbolics.EquationType

struct Equation

Отношение равенства между двумя выражениями.

Поля

  • lhs: выражение в левой части уравнения.

  • rhs: выражение в правой части уравнения.

# Base.:~Method

~(lhs, rhs) -> Any

Создает Equation из двух экземпляров Num или Num и Number.

Примеры

julia> using Symbolics

julia> @variables x y;

julia> @variables A[1:3, 1:3] B[1:3, 1:3];

julia> x ~ y
x ~ y

julia> x - y ~ 0
x - y ~ 0

julia> A ~ B
(broadcast(~, A, B))[1:3,1:3]

julia> A .~ 3x
(broadcast(~, A, 3x))[1:3,1:3]

Примечание о функциях, ограниченных Number

Объекты Sym и Term НЕ являются подтипами Number. Symbolics предоставляет простой тип-оболочку Num, который является подтипом Real. Num заключает в оболочку либо Sym, либо Term, либо любой другой объект, определяет тот же набор операций, что и символьные выражения, и направляет их к значениям, которые он заключает. Для распаковки Num можно использовать функцию Symbolics.value.

По умолчанию макросы @variables возвращают объекты, заключенные в Num, чтобы можно было вызывать функции, ограниченные Number или Real.

using Symbolics
@variables t x y z(t);
Symbolics.operation(Symbolics.value(x + y))
+ (generic function with 562 methods)
Symbolics.operation(Symbolics.value(z))
z
Symbolics.arguments(Symbolics.value(x + y))
2-element Vector{Any}:
 x
 y

Обратите внимание, что Julia преобразует иррациональные числа, такие как π и , в Float64 всякий раз, когда они используются в арифметике с другими числами, включая целые. Выражение типа будет немедленно преобразовано в тип float, поэтому выражение типа 2π * x оставит символьный x, умноженный на Float64. Возможно, целесообразно иметь также символьное представление π, которое можно получить с помощью Num(π). В универсальном программировании можно просто переопределить переменную π так, чтобы она имела тот же тип, что и другой аргумент, как показано ниже.

function f(x)
    let π=oftype(x, π)
        1 + (2//3 + 4π/5) * x
    end
end
f(t)
1 + t*((2//3) + (4//5)*π)

Это будет работать для любых входных данных с плавающей запятой, а также для символьных входных данных.

Символьный порядок выполнения

Порядок выполнения может быть выражен в Symbolics.jl следующими способами.

  • IfElse.ifelse(cond,x,y): это диспетчеризируемая версия функции ifelse из IfElse.jl, которая позволяет кодировать условные выражения в символьных ветвях.

Функции проверки

# SymbolicUtils.istreeFunction

istree(x)

Возвращает true, если x — это член. Если имеет значение, operation, arguments также должны быть определены для x.

# SymbolicUtils.operationFunction

operation(x)

Если x является членом, как определено с помощью istree(x), operation(x) возвращает его начало, если x представляет вызов функции, например, начало представляет собой вызываемую функцию.

# SymbolicUtils.argumentsFunction

arguments(x)

Получает аргументы x, которые должны быть определены, если istree(x) имеет значение true.