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

transpose should not be recursive #51813

Closed
adienes opened this issue Oct 21, 2023 · 11 comments
Closed

transpose should not be recursive #51813

adienes opened this issue Oct 21, 2023 · 11 comments
Labels
domain:linear algebra Linear algebra kind:speculative Whether the change will be implemented is speculative

Comments

@adienes
Copy link
Contributor

adienes commented Oct 21, 2023

I understand the argument for adjoint, but transpose is really something different. I think it's somewhat silly that e.g. Matrix{String} cannot be transpose'd. if a type wants to opt-in to recursive transpose it can do so via dispatch

@jishnub jishnub added kind:speculative Whether the change will be implemented is speculative domain:linear algebra Linear algebra labels Oct 22, 2023
@nsajko
Copy link
Contributor

nsajko commented Oct 22, 2023

The transpose docs already point to permutedims as a non-recursive generalization: https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#Base.transpose

Related previous discussion: #4774, #20978

@adienes
Copy link
Contributor Author

adienes commented Oct 22, 2023

I'm quite confused why #20978 was closed

it looks like near the end, people were mostly in agreement that

[recursive] transpose however is lacking even a single motivation or actual use case.

or to put it under a trait

probably makes sense even if we do something else as well), some kind of type-check or trait for whether an element should do recursive transpose

So I'm confused. There seemed to be pretty solid consensus that transpose should be made non-recursive - e.g. #20978 (comment), #20978 (comment), #20978 (comment), #20978 (comment), and #23424.

I'll cast a small vote in favor of non-recursive transpose and ctranspose for AbstractArrays, with both being recursive on AbstractArray{T} where T<:AbstractArray.

and yet the issue was closed leaving transpose recursive? 😕

I understand that this is in some cases mathematically consistent with other functions. however a Matrix{String} is not really a mathematical object, just something I'm using for data preprocessing. if a Matrix must be only objects that should be interpreted as linear maps / tensors / yada yada, then I shouldn't be able to construct a Matrix{String} in the first place. actually with that said, I don't think this issue should have the linear algebra label

.

this is one of those situations where it feels that we have let some esoteric principle win out over a really annoying usability problem. like really, take a step back from the linalg textbook for a second, does it really make sense that transpose(::Matrix{T}) only works if T itself is transposable? to me that's such a strange design choice

@nsajko
Copy link
Contributor

nsajko commented Oct 22, 2023

[recursive] transpose however is lacking even a single motivation or actual use case

No, the recursiveness seems to be necessary for a transpose, consider the following:

transpose_necessary_property1(t, a) = (tt)(a) == a

transpose_necessary_property2(t, u, v) = t(v*u) == t(u)*t(v)

for candidate  (permutedims, transpose)
  v = [rand(2, 2) for _  0:1, _  0:2]
  u = [rand(2, 2) for _  0:2, _  0:2]

  transpose_necessary_property1(candidate, u) ||
    println(candidate, " fails the first necessary property, can't be transpose")

  transpose_necessary_property2(candidate, u, v) ||
    println(candidate, " fails the second necessary property, can't be transpose")
end

It outputs:

permutedims fails the second necessary property, can't be transpose

@nsajko
Copy link
Contributor

nsajko commented Oct 22, 2023

This PR and the associated discussion are also relevant: #7244.

@adienes
Copy link
Contributor Author

adienes commented Oct 22, 2023

transpose_necessary_property2(t, u, v) = t(v*u) == t(u)*t(v)

this is only necessary if you treat the elements as scalars and every Matrix as a linear map and not just an arbitrary AbstractArray. for transpose as a data preprocessing tool it is absolutely not necesary

which is exactly what I am protesting: I find it very silly that permutedims is considered a generic Array method but transpose is only for linear algebra use, when it seems clear to me that transpose should be a special case of permutedims

I understand that this has been discussed at length before, but reading through some threads I really don't see any good justification or consensus that transpose should be recursive. it seems it is only this way as a historical accident + momentum, with justifications bolted on after the fact.

the only compelling use case at all I see in those discussions is to transpose block matrices, which should have been done with a new type + dispatch

@oxinabox
Copy link
Contributor

All of our basic linear algebra operations are recursive.
Like *, dot and a few others.

It's required that transpose also be recursive to maintain a' * b == dot(a, b).

There is a strong case to be made that we should indeed get rid of this behaviour in Julia 2.0 (if that ever happens). And leave the representations of interesting vector spaces represented nested arrays to a special type -- not to Array
But we would need to get rid of whole recursive thing. Not just transpose.

Anyways this is breaking so this appropriate labels.
We won't be able to do this any time soon (if ever), if we do every decide we want to do that.

@nsajko
Copy link
Contributor

nsajko commented Oct 22, 2023

leave the representations of interesting vector spaces represented nested arrays to a special type -- not to Array

This reminds of the mathematical programming language Fricas. Its type system and standard library distinguish between:

  1. "two-dimensional array" types, which are basically 2D tables and their element type is completely arbitary

  2. "matrix" types, which may share some of their implementation with some "two-dimensional array" types, but their allowed element type is somewhat restricted (it must be a multiplicative monoid) so that the usual mathematical operations could be defined on them safely

However, it seems to me that the trend in Julia is to use traits instead of abstract types? So I guess adienes' suggestion may materialize partially, but only in Julia 2?

@jariji
Copy link
Contributor

jariji commented Oct 23, 2023

It's required that transpose also be recursive to maintain a' * b == dot(a, b).

I don't see transpose in this expression, only ' which is adjoint.

@nsajko
Copy link
Contributor

nsajko commented Oct 23, 2023

Rethinking this issue, I'm finding it a bit absurd. It's not even a feature request, seeing as the single-argument permutedims method already behaves exactly as requested. So this issue could basically be rephrased as "please make transpose not behave like a transpose for Matrix", which is clearly nonsensical.

Perhaps the underlying issue is the already discussed way Julia's Base and LinearAlgebra conflate the non-mathematical "multidimensional table" and mathematical "multidimensional array/cartesian tensor" type categories, however:

  1. If that's an issue, it should be a separate issue on Github.

  2. It seems to me that this conflation may be just a red herring here. This is because, even if we got a cleaner design in the future, one that doesn't conflate non-algebraic and algebraic usage, I'm imagining that transpose wouldn't even be defined for the non-algebraic/"just table" types, as it's really a linear/tensor algebra concept.

@adienes
Copy link
Contributor Author

adienes commented Oct 24, 2023

I follow, but do not agree with the argument.

anyway, looks like this is unlikely to change. thank you for the thoughts

@adienes adienes closed this as completed Oct 24, 2023
@nsajko
Copy link
Contributor

nsajko commented Oct 24, 2023

You could just leave it open, many other open issues exist with the https://github.com/JuliaLang/julia/labels/speculative or https://github.com/JuliaLang/julia/labels/breaking labels.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:linear algebra Linear algebra kind:speculative Whether the change will be implemented is speculative
Projects
None yet
Development

No branches or pull requests

5 participants