Getting the implicit scala Numeric number from Azavea Numeric

I use the Azavea Numeric Scala library for general math operations. However, I cannot use them with the Scala Collections API, since they require Scala Numeric, and it seems that the two Numerics are mutually exclusive. Is there any way to avoid re-implementing all the mathematical operations in Scala Collections for Azavea Numeric, except that all types need index restrictions for Numerics?

import Predef.{any2stringadd => _, _} class Numeric { def addOne[T: com.azavea.math.Numeric](x: T) { import com.azavea.math.EasyImplicits._ val y = x + 1 // Compiles val seq = Seq(x) val z = seq.sum // Could not find implicit value for parameter num: Numeric[T] } } 

Where Azavea Numeric is defined as

 trait Numeric[@scala.specialized A] extends java.lang.Object with com.azavea.math.ConvertableFrom[A] with com.azavea.math.ConvertableTo[A] with scala.ScalaObject { def abs(a:A):A ...remaining methods redacted... } object Numeric { implicit object IntIsNumeric extends IntIsNumeric implicit object LongIsNumeric extends LongIsNumeric implicit object FloatIsNumeric extends FloatIsNumeric implicit object DoubleIsNumeric extends DoubleIsNumeric implicit object BigIntIsNumeric extends BigIntIsNumeric implicit object BigDecimalIsNumeric extends BigDecimalIsNumeric def numeric[@specialized(Int, Long, Float, Double) A:Numeric]:Numeric[A] = implicitly[Numeric[A]] } 
+8
generics scala numeric
source share
2 answers

The most common solution would be to write a class that wraps com.azavea.math.Numeric and implements scala.math.Numeric in terms of:

 class AzaveaNumericWrapper[T]( implicit val n: com.azavea.math.Numeric[T] ) extends scala.math.Numeric { def compare (x: T, y: T): Int = n.compare(x, y) def minus (x: T, y: T): T = n.minus(x, y) // and so on } 

Then we implement the implicit conversion:

 // NOTE: in scala 2.10, we could directly declare AzaveaNumericWrapper as an implicit class implicit def toAzaveaNumericWrapper[T]( implicit n: com.azavea.math.Numeric[T] ) = new AzaveaNumericWrapper( n ) 

The fact that n itself is implicit is key here: it allows you to automatically use implicit values ​​of type com.azavea.math.Numeric , where na is an implicit value of type scala.math.Numeric . Note that to complete this, you probably want to do the opposite as well (write the ScalaNumericWrapper class, which implements com.azavea.math.Numeric in terms of scala.math.Numeric).

Now there is a flaw for the above solution: you get a conversion (and therefore instanciation) for each call (to a method that has a context binding like scala.math.Numeric , and where you are only an instance of com.azavea.math.Numeric ). So you really want to define an implicit singleton instance of AzaveaNumericWrapper for each of your number types. Assuming you have types MyType and MyOtherType for which you have defined instances of com.azavea.math.Numeric :

 implicit object MyTypeIsNumeric extends AzaveaNumericWrapper[MyType] implicit object MyOtherTypeIsNumeric extends AzaveaNumericWrapper[MyOtherType] //... 

Also, keep in mind that the obvious primary purpose of the azavea Numeric class is to significantly increase execution speed (mainly because of its specialization in type of parameters). Using the wrapper as described above, you lose the specialization and therefore the speed that goes out of it. Specialization must be used to the end, and as soon as you invoke a general method that is not specialized, you introduce into the world of unspecialized generics (even if this method then calls a specialized method). Therefore, in cases where speed matters, try using azavea Numeric directly instead of scala Numeric (just because AzaveaNumericWrapper uses it internally does not mean that you will get any increase in speed, since there will be no specialization here).

You may have noticed that in my examples I avoided defining instances of AzaveaNumericWrapper for types Int , Long and so on. This is because the implicit scala.math.Numeric values ​​for these types are already (in the standard library). You may be tempted to simply hide them (via something like import scala.math.Numeric.{ShortIsIntegral => _} ) to be sure that your own (Azavea-supported) version is being used, but it makes no sense. The only reason I can think of is to make it work faster, but as explained above, it will not.

+2
source share

You can use the RΓ©gis Jean-Gilles solution, which is nice, and wrap Azavea Numeric. You can also try to recreate the methods yourself, but using Azavea Numeric. Besides NumericRange, most of them should be fairly easy to implement.

You might be interested in Spire , who excels at the Azavea Digital Library. It has all the same functions, but also some new ones (more operations, new types of numbers, sorting and selection, etc.). If you use 2.10 (most of our work is focused on 2.10), then using Spire Numeric eliminates almost all the overhead of the general approach and often works as fast as a direct (not general) implementation.

However, I think your question is a good suggestion; we really need to add the toScalaNumeric method in numeric. What Scala collection methods did you plan to use? Spire adds several new methods to arrays such as qsum, qproduct, qnorm (p), qsort, qselect (k), etc.

+4
source share

All Articles