thanks, the compiler seems to be pleased with the first part:
```scala
  sealed trait Matrix2[R,C,V] {
    val sizeHint: SizeHint = NoClue
    def +(that: Matrix2[R,C,V])(implicit mon: Monoid[V], ord: Ordering[(R,C)]): Matrix2[R,C,V] = Sum(this, that, mon, ord)
    def *[C2](that: Matrix2[C,C2,V])(implicit ring: Ring[V], ord: Ordering[C], ord2: Ordering[(R,C2)]): Matrix2[R,C2,V] = Product(this, that, false, ring, ord, ord2)
    val tpipe: TypedPipe[(R, C, V)]
    def transpose: Matrix2[C,R,V] = Literal(tpipe.map(x => (x._2, x._1, x._3)), sizeHint)
    lazy val optimizedSelf = optimize(this)._2
  }

  case class Product[R,C,C2,V](left: Matrix2[R,C,V], right: Matrix2[C,C2,V], optimal: Boolean = false, ring: Ring[V], ord: Ordering[C], ord2: Ordering[(R,C2)]) extends Matrix2[R,C2,V] {
    def toPipe(): TypedPipe[(R, C2, V)] = {
      if (optimal) {
        // TODO: pick the best joining algorithm based the sizeHint
        val one = left.tpipe.groupBy(x => x._2)(ord)
        val two = right.tpipe.groupBy(x => x._1)(ord)

        one.join(two).mapValues { case (l, r) => (l._1, r._2, ring.times(l._3, r._3)) }.values.
          groupBy(w => (w._1, w._2))(ord2).mapValues { _._3 }
          .sum(ring)
          .filter { kv => ring.isNonZero(kv._2) }
          .map { case ((r, c), v) => (r, c, v) }

      } else {
        optimizedSelf.tpipe
      }
    }

    override lazy val tpipe = toPipe()
    override val sizeHint = left.sizeHint * right.sizeHint
  }

  case class Sum[R, C, V](left: Matrix2[R, C, V], right: Matrix2[R, C, V], mon: Monoid[V], ord: Ordering[(R,C)]) extends Matrix2[R, C, V] {
    def toPipe(): TypedPipe[(R, C, V)] = {
      if (left.equals(right)) {
        left.optimizedSelf.tpipe.map(v => (v._1, v._2, mon.plus(v._3, v._3)))
      } else {
        (left.optimizedSelf.tpipe ++ right.optimizedSelf.tpipe).groupBy(x => (x._1, x._2))(ord).mapValues { _._3 }
          .sum(mon)
          .filter { kv => mon.isNonZero(kv._2) }
          .map { case ((r, c), v) => (r, c, v) }
      }
    }

    override lazy val tpipe = toPipe()
    override val sizeHint = left.sizeHint + right.sizeHint
  }

  case class Literal[R,C,V](override val tpipe: TypedPipe[(R, C, V)], override val sizeHint: SizeHint) extends Matrix2[R, C, V]

```