DorianGrey
DorianGrey

Reputation: 45

Specialization of a generic-generic parameter with another, simple-generic parameter

I'm currently working on a project that includes Gaussian Processes for Machine Learning. Considering the examples and explanations in the book, I'm trying to create a generic function for the various parameters that are part of a trained GP-object - thus, the following declaration is the most general one for a (simple) training function.

def train[T, M <: MatrixInverter[T], S <: Kernel[T]](): GP_Spawn[T] = null

(I've removed the parameter list and the implementation, just if you're wondering.) Tdescribes the numeric type, e.g. it may be Double or Int. MatrixInverter[T] is a trait that enforces a calculateInverse function. Kernel[T] is the corresponding trait for a kernel-function. As some of you may already know, training in a gaussian process can be changed (somehow simplified) when using a Cholesky-Decomposition as the matrix-inverter - thus, I've considered to specialize the function mentioned above. Due to the documentation of the @specialized tag, it should be something like this:

def train[T, @specialized(CholeskyDecomposition[T]) M <: MatrixInverter[T], S <: Kernel[T]](): GP_Spawn[T] 

It's obvious that all parameters are more or less depending on T, since they need to use some variables (types T,Vector[T],Matrix[T]) that depend on it. If I try to compile the code mentioned above, the scala-compiler (2.9.2) complains about

error: not found: value CholeskyDecomposition

I'm not sure what this means, since the import import algorithms.{CholeskyDecomposition, MatrixInverter} is correct. Besides, it's curious to see that the import of CholeskyDecomposition is marked as Unused import statement. CholeskyDecomposition has a companion that includes some constants that are related to the algorithm itself, but I don't assume this aspect to be the reason for this error.

Any ideas what may cause this error ? And, furthermore, how to solve it without cutting of the generic approach ?

Edit:

After reading the answers are considering some re-ordering of my code, I ended up with a solution at runtime that uses type-matching.

val testMat = new Matrix[T](3, 3)
val testInv = fac(testMat)    
testInv match {
    case chol : CholeskyDecomposition[T] => println("Found Cholesky!")
    case _ => println("Found something different.")
}

And it works now :) Thanks to all!

Upvotes: 2

Views: 196

Answers (3)

Rex Kerr
Rex Kerr

Reputation: 167891

If you have a class C that is specialized on type T, then

class D[@specialized T, C[T]](c: C[T]) { ... }

will use the T-specialized verson of C.

This is all you need anyway. There is no point to specialization on object; generic code works just as well since everything non-primitive is an object anyway.

Upvotes: 3

paradigmatic
paradigmatic

Reputation: 40461

You can only specialize a generic parameter with a primitive type: Int, Double, etc. So you can specialize T but not Foo[T] even if T is a primitive.

Upvotes: 5

Jatin
Jatin

Reputation: 31724

As per the API, it says:

Type T can be specialized on a subset of the primitive types by
specifying a list of primitive types to specialize at:

So it is basically only for primitive types.

Upvotes: 1

Related Questions