During a simulation, it can be useful to monitor some representative values of an array (mean, max, min, median).
With a colleague, we’ve tried to write a function or macro that prints the minimum and maximum value of an array.
The idea was to pass only one argument, the array of interest. Then, the function or macro would internally retrieve the variable name, the values of interest (e.g. `minimum(x)') and print a string. The current MWE looks like this:
macro minmax(x)
quote
name = $(string(x))
var = $(esc(x))
info = @sprintf("min(%05s) = %2.4e --- max(%05s) = %2.4e\n", name, minimum(var), name, maximum(var))
print(info)
end
end
So one can call the macro like this @minmax(x) and get, e.g.: min( x) = 1.0000e+00 --- max( x) = 1.0000e+00
Question 0: Is there already a package that provides such type of functions/macros?
Question 1: That’s handy but as it’s a macro, I don’t think it’s possible to use multiple dispatch to change the formatting of number based on the type of x. Or is it possible?
For example, it would be great to print using %d if x is an integer array.
Question 2: Regarding formatting. Now lets assume I have arrays with different values, some have only positive values, some have both positive and negative values, some only negative:
# Arrays
x = ones(10)
y = -1*ones(10)
z = ones(10)
z[1] = -1
# Print info
@minmax(x)
@minmax(y)
@minmax(z)
This returns an output which is all shifted because of the occurrence of minus signs:
If you printed a summary for all the arrays at once, the best solution would probably be to use PrettyTables.jl. But as I understand it, you have a running simulation and wish to summarize an array in each iteration. In that case, it is difficult (impossible) to align the lines when you don’t know what to the future arrays will contain (current array might contain only single-digit numbers, but the following array might contain triple-digit numbers). Nevertheless, you might have some intuition about what the value ranges are. I would avoid macros and tried something like this:
using Printf
# fmt_val is supposed to provide a string representation of `x`
# in the desired format
fmt_val(x) = string(x)
fmt_val(x::Integer) = x < 0 ? string(x) : " " * string(x)
# This might be useful when, e.g., minimum returns single-digit integers,
# but maximum returns triple-digit integers. In that case, you want to
# differentiate between integers returned from minimum and maximum.
struct CustomResult{T}
x::T
end
fmt_val(x::CustomResult{<:Integer}) = @sprintf "%05d" x.x
fmt_val(x::CustomResult{<:Real}) = @sprintf "%05.4f" x.x
custom_maximum(vals) = CustomResult(maximum(vals))
function minmax(name, vals)
# list of values to compute together with their labels
summaries = ["min" => minimum,
"max" => maximum,
"mymax" => custom_maximum]
print(name, ": ")
for (i, (label, func)) in enumerate(summaries)
print(label, "=", fmt_val(func(vals)))
i < length(summaries) && print(", ")
end
println()
end
Since it is a function, you would have to pass the variable name:
Thanks a lot for the input. It’s a nice one that switches printing style based on the type, cool!
Yes, I would like to call these functions at each iteration.
I guess there will be no way to get these points at the same time:
pass the variable only, not also a string representing its name (because one needs a macro for this)
use multiple dispatch (because one needs a function for this)
make sure that the text is aligned (because it’s not possible)