There's some inconsistency in the complex(...)
methods:
help?> complex
complex(r, [i])
Convert real numbers or arrays to complex. i defaults to zero.
julia> complex(rand(3))
3-element Array{Complex{Float64},1}:
0.7485012418373351 + 0.0im
0.9146512879195354 + 0.0im
0.6380568113960479 + 0.0im
julia> complex(rand(3), rand(3))
ERROR: MethodError: no method matching complex(::Array{Float64,1}, ::Array{Float64,1})
Closest candidates are:
complex(::AbstractArray{T,N} where N) where T at complex.jl:1012
Stacktrace:
[1] top-level scope at none:0
You can always broadcast, of course: complex.(rand(3), rand(3))
works fine. But it seems like it should either accept arrays for both arguments, or not at all.
Removing the mixed-shape methods would be technically breaking but if no one is using this in PkgEval then we might be able to change this as a "minor change" in a minor release.
Maybe I am missing something but what are "the mixed-shape methods"?
AFAIU, the reason for having complex
on an Array
work is the same as having real
work which was discussed at some point, pretty sure @stevengj argued for that. Don't think that extends to multiple array arguments though. The docs are wrong here, of course.
With a single array argument there is a standard algebraic meaning for "complexifying" a vector space — that is, complex(vector)
is a "vector" operation just like array + array
, not merely a random operation that we happen to be performing elementwise.
Now that I think about it, in the same sense that you can write array + im*array
as a vector operation, and there is a standard meaning for real(array)
and imag(array)
, I suppose you can assign a sensible algebraic meaning to complex(array, array)
, though this nomenclature isn't very common. So it wouldn't be crazy to add this method. I'm not enthusiastic, however.
R^2 is the only real space bijective with C, so if we're keeping things rigorous, let's throw an error if someone passes complex(::Array)
anything besides a Vector{<:Real} of length two. In that sense, the current behavior on arrays equates to broadcasting a map R -> R^2 -> C, with the imaginary coordinate always zero. I don't think that's sensible.
@stillyslalom, that's not what complex(x)
means: if x
is in a real vector space V
then it's an injection, not a bijection, into the complexified vector space. (This includes the "scalar" case of x::Real
.)
I agree that the current behavior serves as an injection, but the function is complex
, not complexify
: it's more a noun (a constructor) than a verb (an operator). if we're constructing complex numbers in the Cayley-Dickson sense, each coordinate in the complex plane requires an ordered pair (a, b) of reals, and the current behavior sets b to zero.
My comment was made under the misapprehension that complex([1,2,3], 1)
worked. Since it does not, I retract my comment.
@stillyslalom, in Julia, we name functions complex(x)
, float(x)
, string(x)
, big(x)
, and in general foo(x)
when it constructs a foo-like type from x
, and these are all injections. Just because we don't spell it "complexify" doesn't mean that isn't what the function does. complex(x)
can be whatever function we want it to be, and the function that we long ago decided we want is the complexification injection. Nor are mathematical questions decided on the basis of spelling.
(The bijection that you are referring to is spelled Complex(x...)
in Julia.)
The two-array constructor method existed before being deprecated in the "More Dots" push, and the one-array method seems more semantically similar to that than to a complexify
function. Regardless of what it's called, I would be surprised if more than a small fraction of extant complex(::Array)
calls have the semantic intent of 'complexify', versus simply serving as a vectorized constructor. Since one can get the same thing from Complex.(::Array) as complex(::Array), it seems like the latter can be deprecated: even if it has a sensible algebraic meaning, I'm not sure that meaning is in sufficiently common use to justify inclusion in Base.
Sure, we could deprecate that in 2.0.
I don't think it matters whether callers of complex(::Array)
intend vectorized conversion to complex or complexification. They give the same answer whichever way you think about it, so why does it matter?
We should define complex(array)
for the same reason we define real(array)
and imag(array)
and conj(array)
and array*scalar
and array+array
, even though all of these things can be done with dot operations: they have standard algebraic meanings that are part and parcel of being a vector space or a complex vector space.
(A minor advantage is also that complex(array)
can avoid making a copy if the elements are already Complex
.)
I don’t have an objection to restoring the two argument “vectorized” form as well (for two arrays of the same shape only) since that has a sensible algebraic meaning, though I don’t think it’s as essential.
Most helpful comment
We should define
complex(array)
for the same reason we definereal(array)
andimag(array)
andconj(array)
andarray*scalar
andarray+array
, even though all of these things can be done with dot operations: they have standard algebraic meanings that are part and parcel of being a vector space or a complex vector space.(A minor advantage is also that
complex(array)
can avoid making a copy if the elements are alreadyComplex
.)I don’t have an objection to restoring the two argument “vectorized” form as well (for two arrays of the same shape only) since that has a sensible algebraic meaning, though I don’t think it’s as essential.