1

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.

WestCoastProjects
  • 58,982
  • 91
  • 316
  • 560

1 Answers1

2

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!

dlwh
  • 2,257
  • 11
  • 23
  • 1
    Please feel free to ask more questions here or on the mailing list. I do my best to be responsive. In general Breeze tries to general (almost pathologically so), so that operations can be defined in terms of other operations. For example, we can define a sparse svd for any type that has a transpose and matrix multiply. Most of the complexity is in service of that. – dlwh Jan 19 '15 at 21:56
  • Wow, that's an amazing answer, thanks! I am just learning Breeze, was just trying to learn this before catching some sleep last night. Would love to find/pay for a book that had this kind of language (even if it was self-published PDF on Amazon...) – Brian Topping Feb 13 '15 at 04:43
  • Thanks! I have thought about writing a book, and I plan to, but I'm pretty bandwidth constrained right now. Do you have a favorite book about numpy (or Julia, or Matlab, or something) similar that I could look at as inspiration? – dlwh Feb 14 '15 at 16:51