Skip to content

Commit

Permalink
Merge pull request #89 from SciML/getter
Browse files Browse the repository at this point in the history
Add expression retrieval command
  • Loading branch information
ChrisRackauckas authored Apr 16, 2024
2 parents e13311f + b7328b6 commit 3b96455
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "RuntimeGeneratedFunctions"
uuid = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47"
authors = ["Chris Rackauckas <[email protected]> and contributors"]
version = "0.5.12"
version = "0.5.13"

[deps]
ExprTools = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
Expand Down
98 changes: 98 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,101 @@ end
f = g()
@show f(1)
```

## Retrieving Expressions

From a constructed RuntimeGeneratedFunction, you can retrieve the expressions using the
`RuntimeGeneratedFunctions.get_expression` command. For example:

```julia
ex = :((x) -> x^2)
rgf = @RuntimeGeneratedFunction(ex)
julia> RuntimeGeneratedFunctions.get_expression(rgf)
#=
quote
#= c:\Users\accou\OneDrive\Computer\Desktop\test.jl:39 =#
x ^ 2
end
=#
```

This can be used to get the expression even if `drop_expr` has been performed.

### Example: Retrieving Expressions from ModelingToolkit.jl

[ModelingToolkit.jl](https://github.com/SciML/ModelingToolkit.jl) uses
RuntimeGeneratedFunctions.jl for the construction of its functions to avoid issues of
world-age. Take for example its tutorial:

```julia
using ModelingToolkit, RuntimeGeneratedFunctions
using ModelingToolkit: t_nounits as t, D_nounits as D

@mtkmodel FOL begin
@parameters begin
τ # parameters
end
@variables begin
x(t) # dependent variables
end
@equations begin
D(x) ~ (1 - x) / τ
end
end

using DifferentialEquations: solve
@mtkbuild fol = FOL()
prob = ODEProblem(fol, [fol.x => 0.0], (0.0, 10.0), [fol.τ => 3.0])
```

If we check the function:

```julia
julia> prob.f
(::ODEFunction{true, SciMLBase.AutoSpecialize, ModelingToolkit.var"#f#697"{RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x2cce5cf2, 0xd20b0d73, 0xd14ed8a6, 0xa4d56c4f, 0x72958ea1), Nothing}, RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x7f3c227e, 0x8f116bb1, 0xb3528ad5, 0x9c57c605, 0x60f580c3), Nothing}}, UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ModelingToolkit.var"#852#generated_observed#706"{Bool, ODESystem, Dict{Any, Any}, Vector{Any}}, Nothing, ODESystem, Nothing, Nothing}) (generic function with 1 method)
```

It's a RuntimeGeneratedFunction. We can find the code for this system using the retrieval
command on the function we want. For example, for the in-place function:

```julia
julia> RuntimeGeneratedFunctions.get_expression(prob.f.f.f_iip)

:((ˍ₋out, ˍ₋arg1, ˍ₋arg2, t)->begin
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:373 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:374 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:375 =#
begin
begin
begin
#= C:\Users\accou\.julia\packages\Symbolics\HIg7O\src\build_function.jl:546 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:422 =# @inbounds begin
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:418 =#
ˍ₋out[1] = (/)((+)(1, (*)(-1, ˍ₋arg1[1])), ˍ₋arg2[1])
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:420 =#
nothing
end
end
end
end
end)
```

or the out-of-place function:

```julia
julia> RuntimeGeneratedFunctions.get_expression(prob.f.f.f_oop)
:((ˍ₋arg1, ˍ₋arg2, t)->begin
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:373 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:374 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:375 =#
begin
begin
begin
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:468 =#
(SymbolicUtils.Code.create_array)(typeof(ˍ₋arg1), nothing, Val{1}(), Val{(1,)}(), (/)((+)(1, (*)(-1, ˍ₋arg1[1])), ˍ₋arg2[1]))
end
end
end
end)
```
97 changes: 97 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,103 @@ f = g()
@show f(1)
```

## Retrieving Expressions

From a constructed RuntimeGeneratedFunction, you can retrieve the expressions using the
`RuntimeGeneratedFunctions.get_expression` command. For example:

```julia
ex = :((x) -> x^2)
rgf = @RuntimeGeneratedFunction(ex)
julia> RuntimeGeneratedFunctions.get_expression(rgf)
:((x,)->begin
#= REPL[14]:1 =#
x ^ 2
end)
```

This can be used to get the expression even if `drop_expr` has been performed.

### Example: Retrieving Expressions from ModelingToolkit.jl

[ModelingToolkit.jl](https://github.com/SciML/ModelingToolkit.jl) uses
RuntimeGeneratedFunctions.jl for the construction of its functions to avoid issues of
world-age. Take for example its tutorial:

```julia
using ModelingToolkit, RuntimeGeneratedFunctions
using ModelingToolkit: t_nounits as t, D_nounits as D

@mtkmodel FOL begin
@parameters begin
τ # parameters
end
@variables begin
x(t) # dependent variables
end
@equations begin
D(x) ~ (1 - x) / τ
end
end

using DifferentialEquations: solve
@mtkbuild fol = FOL()
prob = ODEProblem(fol, [fol.x => 0.0], (0.0, 10.0), [fol.τ => 3.0])
```

If we check the function:

```julia
julia> prob.f
(::ODEFunction{true, SciMLBase.AutoSpecialize, ModelingToolkit.var"#f#697"{RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x2cce5cf2, 0xd20b0d73, 0xd14ed8a6, 0xa4d56c4f, 0x72958ea1), Nothing}, RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x7f3c227e, 0x8f116bb1, 0xb3528ad5, 0x9c57c605, 0x60f580c3), Nothing}}, UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ModelingToolkit.var"#852#generated_observed#706"{Bool, ODESystem, Dict{Any, Any}, Vector{Any}}, Nothing, ODESystem, Nothing, Nothing}) (generic function with 1 method)
```

It's a RuntimeGeneratedFunction. We can find the code for this system using the retrieval
command on the function we want. For example, for the in-place function:

```julia
julia> RuntimeGeneratedFunctions.get_expression(prob.f.f.f_iip)

:((ˍ₋out, ˍ₋arg1, ˍ₋arg2, t)->begin
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:373 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:374 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:375 =#
begin
begin
begin
#= C:\Users\accou\.julia\packages\Symbolics\HIg7O\src\build_function.jl:546 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:422 =# @inbounds begin
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:418 =#
ˍ₋out[1] = (/)((+)(1, (*)(-1, ˍ₋arg1[1])), ˍ₋arg2[1])
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:420 =#
nothing
end
end
end
end
end)
```

or the out-of-place function:

```julia
julia> RuntimeGeneratedFunctions.get_expression(prob.f.f.f_oop)
:((ˍ₋arg1, ˍ₋arg2, t)->begin
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:373 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:374 =#
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:375 =#
begin
begin
begin
#= C:\Users\accou\.julia\packages\SymbolicUtils\c0xQb\src\code.jl:468 =#
(SymbolicUtils.Code.create_array)(typeof(ˍ₋arg1), nothing, Val{1}(), Val{(1,)}(), (/)((+)(1, (*)(-1, ˍ₋arg1[1])), ˍ₋arg2[1]))
end
end
end
end)
```


## Reproducibility

```@raw html
Expand Down
11 changes: 11 additions & 0 deletions src/RuntimeGeneratedFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,17 @@ function closures_to_opaque(ex::Expr, return_type = nothing)
return Expr(head, Any[closures_to_opaque(x, return_type) for x in args]...)
end

function get_expression(rgf::RuntimeGeneratedFunction{argnames, cache_tag,
context_tag, id, B}) where {
argnames,
cache_tag,
context_tag,
id,
B
}
func_expr = Expr(:->, Expr(:tuple, argnames...), _lookup_body(cache_tag, id))
end

# We write an explicit serialize() and deserialize() here to manage caching of
# the body on a remote node when using Serialization.jl (in Distributed.jl
# and elsewhere)
Expand Down

0 comments on commit 3b96455

Please sign in to comment.