Eigen transpose product
Reference issue
What does this implement/fix?
Follow up on !1598 (merged), which I reverted due to a few loose ends.
Essentially, products written like C.noalias() = (A * B).transpose() trigger an avoidable memory allocation, which is never desirable for time and memory complexity, especially for users who have strict memory constraints. This can easily be avoided by writing the product with an algebraically equivalent expression C.noalias() = B.transpose() * A.transpose(). This MR does that by specializing Product::transpose() and Product::adjoint() to do just that.
The tricky part is that transpose() may not be consistently defined for each expression. DenseBase<Derived>::tranpose() returns Tranpose<Derived>. PermutationBase<Derived>::transpose() returns Inverse<Derived>. It is still worth handling permutation matrices, as (A * P).transpose() still triggers an avoidable allocation that is avoided by writing P.inverse() * A.transpose().
To cover all the scenarios that I have not considered, I am defaulting the transposed product to the current implementation where we just transpose the result. If other expression combinations are identified that could benefit from this strategy, we can add an additional specialization.