Release 0.4.0

This is a major release with a lot of new features related to static types for tensors and ops. The graph construction API is now statically-typed, thus enabling much better type safety than before.

Tensors and outputs are now statically-typed and the types used are the Scala types that correspond to the tensors’ TensorFlow data types. For example:

val t1 = Tensor(0.5, 1) // The inferred type is Tensor[Double].
val t2 = Tensor(1, 2)   // The inferred type is Tensor[Int].
val t3 = t1 + t2        // The inferred type is Tensor[Double].
val t4 = t3.isNaN       // The inferred type is Tensor[Boolean].
val t5 = t3.any()       // Fails at compile-time because `any()` is only
                        // supported for Tensor[Boolean].

A similar situation now applies to Outputs. Ops are also typed and so is the auto-differentiation implementation.

This resulted in major simplifications in the data pipeline and the high level learn API. Datasets and dataset iterators do not “carry” T, V, D, and S types with them now, but rather just the type of the elements they contain/produce.

A new type trait called TF is also introduced that denotes supported Scala types in TensorFlow (e.g., TF[Int] and TF[Float]). Similarly, some more type traits are introduced to denote type constraints for various ops (e.g., IsIntOrUInt[Int], IsIntOrUInt[Long], IsFloatOrDouble[Float], etc.). These type traits are powered by a general implementation of union types for Scala.

Other new features include: - data module: - Added support for the mapAndBatch transformation.