I’m not sure whether it’s possible to do what you want with @nloops. Those macros are somewhat limited in their capability. I’ve seldom found them actually useful.
I typically find CartesianIndices to be more powerful for nested loop ranges. For example,
julia> ci = CartesianIndices(ntuple(Returns(1:3),3))
CartesianIndices((1:3, 1:3, 1:3))
julia> for c in Iterators.filter(c -> issorted(Tuple(c);rev=true), ci); display(Tuple(c)); end
(1, 1, 1)
(2, 1, 1)
(3, 1, 1)
(2, 2, 1)
(3, 2, 1)
(3, 3, 1)
(2, 2, 2)
(3, 2, 2)
(3, 3, 2)
(3, 3, 3)
Equivalently, you could drop the filter and instead check the issorted condition (and continue if it’s violated).
However, (unless the compiler is quite clever, which I’m doubting here) this will still loop over every possible index in order to throw many out (not a big deal in 2-3 dimensions but becomes worse with more).
Another option is to construct a custom iterator that more efficiently visits the lower triangle using the iteration interface.