SymbolicML / DynamicQuantities.jl

Efficient and type-stable physical quantities in Julia
https://symbolicml.org/DynamicQuantities.jl/dev/
Apache License 2.0
132 stars 17 forks source link

Registering custom unit propagation rules #64

Open gaurav-arya opened 11 months ago

gaurav-arya commented 11 months ago

It could be useful for users (especially package authors) to write custom unit propagation rules for their functions, that instruct DynamicQuantities on how units propagate from the input to the output without having to analyze the whole function. Writing a generic rule for abstract quantities seems nearly already possible with a simple dispatch, for example:

julia> using DynamicQuantities

julia> function mycube(x)
           # this function does not like DynamicQuantities
           x isa AbstractQuantity && sleep(1)
           return x^3
       end
mycube (generic function with 1 method)

julia> function mycube(x::AbstractQuantity)
           return DynamicQuantities.new_quantity(typeof(x), mycube(ustrip(x)), dimension(x)^3)
       end
mycube (generic function with 2 methods)

julia> @time mycube(1u"m")
  0.000001 seconds
1.0 m³

The "nearly" is because DynamicQuantities.new_quantity is not currently public API: should it be?

One could imagine using this pattern for performance on a complicated function (e.g. with many inner loops, scalar calculations, etc.), in cases where exists a performance overhead of DynamicQuantities and a package author wants to ensure zero-overhead performance while avoiding the everything-is-a-new-type approach of unitful, e.g. #55.

We could make the process even easier than the above, too. For example, we could automate the process of ustrip'ing and feeding into the original functions, handling general inputs via Functors.fmap(ustrip, args), so that the user only has to specify how the dimension is propagated.