Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

collect on a Adjoint{T,Array{T,1}} should return a Adjoint{T,Array{T,1}} #762

Closed
roelstappers opened this issue Aug 25, 2020 · 16 comments
Closed
Labels
breaking This change will break code

Comments

@roelstappers
Copy link

roelstappers commented Aug 25, 2020

The documentation of collect states that it will return an object with the same shape and number of dimensions. However currently calling collect on objects of type Adjoint{T,Array{T,1}} returns a 1xn matrix and these have different behaviour. An Adjoint of a vector in julia is a linear operator that maps vectors to scalars (as it should be) but this is not equivalent to a 1xn matrix which maps vectors to 1-element vectors. e.g.

julia> a = [1,2,3]; b = [1,2,3];

julia> a'*b
14

julia> collect(a')*b
1-element Array{Int64,1}:
 14

One solution would be to let collect on a Adjoint{T,Array{T,1}} return a Adjoint{T,Array{T,1}}.

Also calling size on objects of type Adjoint{T,Array{T,1}} returns (1,n) indicating that it is an 1xn matrix instead this should return e.g. (0,n) or (nothing,n)

@yuyichao yuyichao added the breaking This change will break code label Aug 25, 2020
@yuyichao
Copy link

The size return value is correct. A zero or nothing as the first dimension does not make any sense.

And for exactly this reason, the returned type from collect is also correct. There’s no guarantee that operates on the returned value is exactly he same as the input, that is simply impossible.

@roelstappers
Copy link
Author

Can you elaborate a bit more? How can the return value of size be correct when the adjoint of a vector is not a map from vectors to vectors but from vectors to scalars. Having size return (1,n) would mean that it is a linear map from vectors with n-elements to vectors with 1-element. Am I missing something?

For your second point. The proposal would exactly provide that guarantee as the return value of collect would be identical to it's input value.

@mbauman
Copy link
Member

mbauman commented Aug 25, 2020

This was the compromise that was achieved through #42: adjoint vectors participate in the linear algebra of matrices largely behaving as though they were 1×N matrices, but with special behaviors upon multiplication and such.

collect is rather under-defined as it currently stands (and behaves).

@yuyichao
Copy link

How can the return value of size be correct when the adjoint of a vector is not a map from vectors to vectors but from vectors to scalars.

Because scalar does not have dimension 0 or nothing.

julia> size(1, 1)
1

Having size return (1,n) would mean that it is a linear map from vectors with n-elements to vectors with 1-element.

No, it just mean the returned value should have a dimension of 1, which it does.

For your second point. The proposal would exactly provide that guarantee as the return value of collect would be identical to it's input value.

No it doesn't. What I'm talking about is that this is a property that's impossible to achieve for all input type and it is not at all the goal of this function. If you want a function that maintains all properties of a type, the correct function to use is identity.

collect is rather under-defined as it currently stands (and behaves).

While I think there are probably things that are less than well defined but I think the matching of the shape is pretty well define here.

@roelstappers
Copy link
Author

The size of a scalar is current an empty tuple

julia> size(1)
()

@yuyichao
Copy link

The size of a scalar is current an empty tuple

Correct, but it does have a size 1. What I was saying is that returning 0 or a non-number doesn't make any sense.

@mbauman
Copy link
Member

mbauman commented Aug 25, 2020

That's correct — it behaves like a 0-dimensional array. Just like zero-dimensional arrays, though, you can ask for the length of the "missing" dimensions and it'll return 1.

@roelstappers
Copy link
Author

Sorry for asking so many questions but I don't understand why it would it be a problem to return 0? Does it have to do with numbers being iterable in Julia? e.g. in this issue JuliaLang/julia#11769 Jeff mentions numbers to be zero-dimensional so why couldn't size just return 0?

And I guess for the missing dimensions returning 0 instead of 1 could make sense but that is a bit out of scope of the current issue.

@mbauman
Copy link
Member

mbauman commented Aug 25, 2020

These are better questions for the discourse mailing list. 0×N already has a very well-defined meaning (it's an empty matrix with 0 rows).

@roelstappers
Copy link
Author

I removed the last sentence from the original issue to keep the discussion focused on the behavior of collect

@Moelf
Copy link
Contributor

Moelf commented Oct 20, 2021

This should be closed, collect is not identity. When the object is "lazy" wrapper, I lean towards the collect materialize something, in this case, making a matrix.

An analogy can be drawn from a lazy vector that is <:AbstractVector{T}, although it behaves like a vector in all possible ways, collect() should still materialize it instead of being an alias of identity.

@roelstappers
Copy link
Author

Fine to close this but I think what @mbauman mentions above

adjoint vectors participate in the linear algebra of matrices largely behaving as though they were 1×N matrices

Is the real problem.
Given vectors a and b it is clear from the inner product a' * b that a' considered as a linear operator is mapping vectors to scalars. This is not what a 1xn matrix does.

@Moelf
Copy link
Contributor

Moelf commented Oct 21, 2021

how come? It's pretty common for textbooks to write something like:

<a, b> = a^T b

or wikipedia:

if vectors are identified with row matrices, a b^T

Maybe you're saying 1xn * nx1 should return 1x1, well I guess 1x1 matrix is not useful in math so it's conceptually reduced to a scalar.

@oscardssmith
Copy link
Member

Isn't this conversation just #42 redux?

@roelstappers
Copy link
Author

how come? It's pretty common for textbooks to write something like:

<a, b> = a^T b

or wikipedia:

if vectors are identified with row matrices, a b^T

Maybe you're saying 1xn * nx1 should return 1x1, well I guess 1x1 matrix is not useful in math so it's conceptually reduced to a scalar.

No my point is that collect turns a Linear form .

A linear form is a linear map from a vector space to its field of scalars (often, the real numbers or the complex numbers).

into a 1xn matrix which maps to 1-element vectors. My expectations was that collect would only effect the memory representation of an object, e.g. going from lazy to non-lazy but not change the "behavior" of linear operators.

@roelstappers
Copy link
Author

Isn't this conversation just #42 redux?

Yeah let's stop now before it's too late.

@KristofferC KristofferC transferred this issue from JuliaLang/julia Nov 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking This change will break code
Projects
None yet
Development

No branches or pull requests

6 participants