Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use unsorted arguments by default #44

Merged
merged 4 commits into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "TermInterface"
uuid = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c"
authors = ["Shashi Gowda <[email protected]>", "Alessandro Cheli <[email protected]>"]
version = "1.0.1"
version = "1.1.0"
0x0f0f0f marked this conversation as resolved.
Show resolved Hide resolved

[compat]
julia = "1"
Expand Down
24 changes: 17 additions & 7 deletions src/TermInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,30 @@ export operation

Returns the arguments to the function call in a function call expression.
`iscall(x)` must be true as a precondition.

Depending on the type and internal representation of `x`,
`arguments(x)` may return an unsorted collection nondeterministically,
This is to make sure to retrieve the arguments of an expression when the order of arguments does not matter
but the speed of the operation does.
To ensure to retrieve arguments in a sorted manner, you can use
and implement the function `sorted_arguments`.
"""
function arguments end
export arguments

"""
unsorted_arguments(x::T)
sorted_arguments(x::T)

If x is a expression satisfying `iscall(x)` and your expression type `T` provides
and optimized implementation for storing the arguments, this function can
be used to retrieve the arguments when the order of arguments does not matter
but the speed of the operation does.
Returns the arguments to the function call in a function call expression, in a **sorted fashion**.
`iscall(x)` must be true as a precondition. Analogous to `arguments`,
but ensures that the operation is deterministic and always returns
the arguments in the order they are stored.

By default, this redirects to `arguments`, therefore implementing
it is optional.
"""
unsorted_arguments(x) = arguments(x)
export unsorted_arguments
sorted_arguments(x) = arguments(x)
export sorted_arguments


"""
Expand Down
24 changes: 24 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,27 @@ using Test
@test !iscall(ex)
@test ex == maketerm(Expr, :ref, [:arr, :i, :j], nothing)
end

@testset "Unsorted arguments" begin
struct Sum
d::Dict{Int, Any}
Sum(xs...) = new(Dict{Int, Any}(xs...))
end

TermInterface.isexpr(s::Sum) = true
TermInterface.head(::Sum) = (+)
TermInterface.operation(s::Sum) = head(s)
TermInterface.arguments(s::Sum) = [:($coeff * $val) for (coeff, val) in s.d]
TermInterface.children(s::Sum) = sorted_arguments(s)
TermInterface.sorted_arguments(s::Sum) = [:($coeff * $val) for (coeff, val) in sort!(collect(pairs(s.d)))]

s = Sum(1 => :A, 2 => :B, 3 => :C)
@test operation(s) == head(s) == (+)
args = arguments(s)
@test :(1A) in args
@test :(2B) in args
@test :(3C) in args

@test sorted_arguments(s) == [:(1A), :(2B), :(3C)]
@test children(s) == sorted_arguments(s)
end
Loading