Skip to content

Commit 984e92d

Browse files
committed
Add error hints for unsuported operations
This also adds the note for `abs`/`abs2` into README.md.
1 parent 81c9ada commit 984e92d

File tree

2 files changed

+45
-4
lines changed

2 files changed

+45
-4
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,20 @@ RGBRGB{Float64}:
110110
0.0 0.0 0.0
111111
-0.03 0.0 0.02
112112
```
113+
114+
### `abs` and `abs2`
115+
116+
To begin with, there is no general and straightforward definition of the
117+
absolute value of a vector.
118+
There are roughly two possible definitions of `abs`/`abs2`: as a channel-wise
119+
operator or as a function which returns a real number based on the norm.
120+
For the latter, there are also variations in the definition of norm.
121+
122+
In ColorVectorSpace v0.9 and later, `abs` is defined as a channel-wise operator
123+
and `abs2` is undefined.
124+
The following are alternatives for the definitions in ColorVectorSpace v0.8 and
125+
earlier.
126+
```julia
127+
_abs(c) = mapreducec(v->abs(float(v)), +, 0, c)
128+
_abs2(c) = mapreducec(v->float(v)^2, +, 0, c)
129+
```

src/ColorVectorSpace.jl

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,15 @@ copy(c::MathTypes) = c
188188
abs(c::MathTypes) = mapc(abs, c)
189189
norm(c::MathTypes, p::Real=2) = (cc = channels(c); norm(cc, p)/(p == 0 ? length(cc) : length(cc)^(1/p)))
190190
()(a::C, b::C) where {C<:MathTypes} = mapc(*, a, b)
191+
()(a::C, b::C) where {C<:MathTypes} = throw(MethodError(dot, (a, b)))
192+
()(a::C, b::C) where {C<:MathTypes} = throw(MethodError(tensor, (a, b)))
191193

192194
## Mixed types
193195
(+)(a::MathTypes, b::MathTypes) = (+)(promote(a, b)...)
194196
(-)(a::MathTypes, b::MathTypes) = (-)(promote(a, b)...)
195197
()(a::MathTypes, b::MathTypes) = ()(promote(a, b)...)
196-
198+
()(a::MathTypes, b::MathTypes) = ()(promote(a, b)...) # not fully supported, but used for error hints
199+
()(a::MathTypes, b::MathTypes) = ()(promote(a, b)...) # not fully supported, but used for error hints
197200

198201
# Scalar RGB
199202
(*)(f::Real, c::AbstractRGB) = rettype(*, f, c)(f*red(c), f*green(c), f*blue(c))
@@ -220,8 +223,10 @@ end
220223
(-)(a::TransparentRGB, b::TransparentRGB) = rettype(-, a, b)(red(a)-red(b), green(a)-green(b), blue(a)-blue(b), alpha(a)-alpha(b))
221224

222225
# New multiplication operators
223-
()(x::AbstractRGB, y::AbstractRGB) = (T = acctype(eltype(x), eltype(y)); T(red(x))*T(red(y)) + T(green(x))*T(green(y)) + T(blue(x))*T(blue(y)))/3
224-
()(x::Union{AbstractRGB,AbstractGray}, y::Union{AbstractRGB,AbstractGray}) = (promote(x, y)...)
226+
function ()(x::AbstractRGB, y::AbstractRGB)
227+
T = acctype(eltype(x), eltype(y))
228+
(T(red(x))*T(red(y)) + T(green(x))*T(green(y)) + T(blue(x))*T(blue(y)))/3
229+
end
225230
# ⊗ defined below
226231

227232

@@ -384,7 +389,6 @@ function ⊗(a::AbstractRGB, b::AbstractRGB)
384389
agbr, abbg, arbb, abbr, arbg, agbb = ag*br, ab*bg, ar*bb, ab*br, ar*bg, ag*bb
385390
return RGBRGB(ar*br, agbr, abbr, arbg, ag*bg, abbg, arbb, agbb, ab*bb)
386391
end
387-
(a::Union{AbstractRGB,AbstractGray}, b::Union{AbstractRGB,AbstractGray}) = (promote(a, b)...)
388392

389393
"""
390394
varmult(op, itr; corrected::Bool=true, mean=Statistics.mean(itr), dims=:)
@@ -432,6 +436,26 @@ function __init__()
432436
# Color is not necessary, this is just to show it's possible.
433437
A, B = argtypes
434438
A !== B && print(io, "\nIn binary operation with $A and $B, the return type is ambiguous")
439+
elseif exc.f === dot && length(argtypes) == 2
440+
if any(C -> C <: Union{TransparentGray, TransparentRGB}, argtypes)
441+
print(io, "\n`dot` (or `⋅`) for transparent colors is not supported ")
442+
print(io, "because the normalization is designed for opaque grays and RGBs.")
443+
print(io, "\nYou can use `reducec(+, 0, mapc(float, a) ⊙ mapc(float, b))` ")
444+
print(io, "to get the dot product without normalization.")
445+
end
446+
elseif exc.f === tensor && length(argtypes) == 2
447+
if any(C -> C <: Union{TransparentGray, TransparentRGB}, argtypes)
448+
print(io, "\n`tensor` (or `⊗`) for transparent colors is not supported ")
449+
print(io, "due to the non-high demand.")
450+
end
451+
elseif exc.f === abs2 && length(argtypes) == 1
452+
C = argtypes[1]
453+
if C <: MathTypes
454+
print(io, "\nIt is ambiguous whether `abs2(::$C)` should return a real number ")
455+
print(io, "or a color object.")
456+
print(io, "\nYou can use `_abs2(c) = mapreducec(v->float(v)^2, +, 0, c)` ")
457+
print(io, "to get the value compatible with ColorVectorSpace v0.8 or earlier.")
458+
end
435459
end
436460
end
437461
end

0 commit comments

Comments
 (0)