Confused about build_function

I wanted to do a very basic application of build_function to test out modelingtoolkit.jl, but ran into issues.

using ModelingToolkit

@parameters a b
@variables x

y = x^2
z = x + a

f_y = build_function(y, x) # This works like I'd expect
# eval(f_y)(3)
# 9

f_y = build_function(y, x, a) # This works like I'd expect
# eval(f_y)(3, 5)
# 8

However, in general, there is a single (large) vector or dictionary containing all of the parameters, which I’d like to pass around rather than having to glean which functions need which specific parameters

# Something like this
paramMap = [a => 5, b=> -5];
f_z = build_function(z, [x], [a, b]) # This doesn't work like I'd expect
# eval(f_z)(3, paramMap)
# raises errors

This seems like a very simple use-case, so I think I’m just missing something obvious. What am I doing wrong?

What do you expect it to do? Maybe you have an idea that would be good to add, but the documentation never says this should work nor does it describe what this syntax should mean.

In other contexts, I would use the @unpack macro on a Dict or NamedTuple to unpack the parameters into the environment.

What I’d like is for the Expression produced to do an analogous unpacking of the parameters requested. It would look something like this

function f_z(x::Any, a::Any, b::Any)
  return x+a
end

function f_z(x::Any, p::Any)

  a = p[a]
  b = p[b]

  f_z(x, a, b)
end

The above is the lowest-tech version of what I have in mind, but including some sort of @unpack functionality would make this much more useful. You can easily imagine that paramMap might contain 10+ different elements and this way rather than figure out which 2-3 parameters f_z requires and tailor the arguments appropriately, you can pass around the entire set of parameters and the function will handle the unpacking.

So you want build_function to, if it took in an object with keys (NamedTuple, Dict), to unload those values using the same key names so it would work on a passed in NamedTuple or Dict? If that’s right, that makes sense, could probably work, and would be worth an issue. But it’s not a feature that exists today.

Gotcha. Should I go ahead and submit an issue?

Given that the Vector{Pair} approach to parameters is present in a lot of the documentation, it seems like it should also convert something like [a => 5, b => 3] to a Dict and do the same unloading

Just to clarify, it’s not that build_function ought to do this, but the output of build_function, the expressions, ought to do this

Yes

It’s used in the system construction, which generates flat vector code for ODESystems and what not specifically to enforce type-stable fast code. Actually using dictionaries would make this really slow in practice, so it’s silently generating good code from the higher level “bad code”. We could let people build the other form in build_function (since using a NamedTuple or ComponentArray isn’t bad), though for many other reasons the system constructors would still generate flat vector code.

Point taken

issue submitted Functions created by build_function should supported passing parameters using NamedTuples and Dicts · Issue #1259 · SciML/ModelingToolkit.jl (github.com)