Еще один эксперимент с масками Engee Function
Маски и строки в Engee Function
В Engee можно добавить к блоку простой пользовательский интерфейс. Это называется маскированием блока. При помощи масок можно скрыть от пользователя внутреннее устройство блока. Это отличная техника, и давайте добавим маску к блоку Engee Function из прошлого поста.
У функции EF_pdist2, которую мы использовали, есть необязательный параметр - режим расчета (метрика). В ходе проекта дадим пользователю возможность управлять им через маску.
include("PDIST2.jl");
Давайте вспомним как выглядит код модуля:
;cat PDIST2.jl
Как передать строку из маски в Engee Function?
Перед тем как маскировать Engee Function, требуется рассмотреть функциональное ограничение - Engee Function не умеет работать с параметрами типа String
. Но метод расчета задается строкой. Следовательно, нам надо закодировать выбранный метод некоторым числом, передать это число как параметр в Engee Function, а потом декодировать его. То есть в маске понадобится не один параметр, а два. Тогда можно реализовать такую схему:
Декодировать режим расчета будем при помощи словаря, так как тип данных Dict (Словарь) реализует коллекцию пар "ключ-значение". При этом ключом может быть любой базовый тип. Следовательно, возможно сделать даже такой словарь:
mode_dict_t = Dict(1=>"euclidean",2=>"squaredeuclidean",3=>"manhattan",4=>"cosine")
Видно, что ключом здесь выступает целое, а значением - строка. Это позволяет нам сделать следующее:
EF_mode = PDIST2.mode_dict_t[1]
Теперь взглянем на код методов блока Engee Function:
include("/user/start/examples/base_simulation/advanced_block_masking/PDIST2.jl")
mutable struct Block <: AbstractCausalComponent
cache::Matrix{Float64};
modeC::Int64
function Block()
c = zeros(Float64,INPUT_SIGNAL_ATTRIBUTES[1].dimensions);
info("Allocated $(Base.summarysize(c)) bytes for pdist2")
info("Selected $(PDIST2.mode_dict_t[mode])")
new(c,mode)
end
end
function (c::Block)(t::Real, in1, in2)
try
c.cache = PDIST2.EF_pdist2(in1,in2;metric=PDIST2.mode_dict_t[c.modeC]);
catch
error("Matrix Dimensions should be equal!")
stop_simulation()
end
return c.cache
end
modeC - это параметр, который принимает значение числовой переменной из маски (см. ). Тем самым, мы можем передать в нашу функцию PDIST2 метод расчета как
PDIST2.mode_dict_t[c.modeC]
А число мы получим с помощью обратного вызова "реального" параметра из выпадающего списка:
if mask.parameters.mask_mode.value == "euclidean"
mask.parameters.mask_mode_int.value = 1;
elseif mask.parameters.mask_mode.value == "squaredeuclidean"
mask.parameters.mask_mode_int.value = 2;
elseif mask.parameters.mask_mode.value == "manhattan"
mask.parameters.mask_mode_int.value = 3;
elseif mask.parameters.mask_mode.value == "cosine"
mask.parameters.mask_mode_int.value = 4;
end
Таким образом маска будет выглядеть следующим образом:
Обратите внимание, что параметр mask_mode_int должен быть вычисляемым. А скрыт он, так как мы не хотим давать пользователю что-нибудь сломать.
Наконец, откроем и запустим итоговую модель во всех режимах:
demoroot = @__DIR__
mdl = engee.open(joinpath(demoroot,"EF_DF.engee"))
for k in keys(PDIST2.mode_dict_t)
println("Запускаем модель с режимом $(PDIST2.mode_dict_t[k])")
engee.set_param!("EF_DF/PDIST2", "mask_mode"=>PDIST2.mode_dict_t[k])
engee.run(mdl;verbose=true);
end
Выводы
В ходе проекта мы узнали, как пробрасывать строковые параметры в Engee Function, а так же использовали словари штатным, хоть и неочевидным способом.