Search code examples
scalascala-breeze

Where are low level implementations for transpose (DenseMatrix or DenseVector) in Scala breeze?


Behind the

<foo>.t(..)  // .t() is transpose 

method of [DenseVector|DenseMatrix] is a relative labyrinthe of implicits, traits, and class hierarchies. Some of the pieces:

  • trait CanTranspose
  • class/object Transpose and associated implicits
  • trait/object numericOps with corresponding implicits:
  • trait TransposeLowPrio

Here is a possible example of what I am looking for: inside the Transpose object there is the following low-level code (the "dot"):

  implicit def transTimesNormalFromDot[T, U, R](implicit dot: OpMulInner.Impl2[T, U, R]): OpMulMatrix.Impl2[Transpose[T], U, R] = {
    new OpMulMatrix.Impl2[Transpose[T], U, R] {
      def apply(v: Transpose[T], v2: U): R = {
        dot(v.inner, v2)
      }
    }
  }

Note however that Intellij IDE was unable to find any usages. I am trying to find how the DenseMatrix and DenseVector implement the transpose.


Solution

  • I freely admit the implicits can be a bit hard to follow. The .t method for NumericOps (which is where DenseVector and DM get it from) is defined as follows:

      final def t[TT >: This, That](implicit op: CanTranspose[TT, That]) =
        op.apply(repr)
    

    DenseMatrix has a CanTranspose implicit defined like so:

      implicit def canTranspose[V]: CanTranspose[DenseMatrix[V], DenseMatrix[V]] = {
        new CanTranspose[DenseMatrix[V], DenseMatrix[V]] {
          def apply(from: DenseMatrix[V]) = {
            new DenseMatrix(data = from.data, offset = from.offset,
             cols = from.rows, rows = from.cols, 
             majorStride = from.majorStride,
             isTranspose = !from.isTranspose)
          }
        }
      }
    

    The relevant bit is the flip of the isTranspose boolean (and the swap of rows and columns). So ".t" on a DenseMatrix just creates a new DenseMatrix that is either column-major (!isTranspose) and row-major (isTranpose).

    DenseVector has no CanTranspose implicit in general. Instead, there's an implicit defined for all Tensors in the Tensor companion object:

      implicit def transposeTensor[K, V, T](implicit ev: T<:<Tensor[K, V]): CanTranspose[T, Transpose[T]] = {
        new CanTranspose[T, Transpose[T]] {
          def apply(from: T): Transpose[T] = new Transpose(from)
        }
    
      }
    

    So dv.t gives a Transpose[DenseVector].

    Hope that helps!