Showing posts with label implicit-conversion. Show all posts
Showing posts with label implicit-conversion. Show all posts

Monday, April 24, 2017

Scala: generic weighted average function

Leave a Comment

I want to implement a generic weighted average function which relaxes the requirement on the values and the weights being of the same type. ie, I want to support sequences of say: (value:Float,weight:Int) and (value:Int,weight:Float) arguments and not just: (value:Int,weight:Int). [See my earlier question in the run up to this.]

This is what I currently have:

def weightedSum[A: Numeric](weightedValues: GenSeq[(A, A)]): (A, A)  def weightedAverage[A: Numeric](weightedValues: GenSeq[(A, A)]): A = {     val (weightSum, weightedValueSum) = weightedSum(weightedValues)     implicitly[Numeric[A]] match {         case num: Fractional[A] => ...         case num: Integral[A] => ...         case _ => sys.error("Undivisable numeric!")     } } 

This works perfectly if I feed it for example:

val values:Seq[(Float,Float)] = List((1,2f),(1,3f)) val avg= weightedAverage(values) 

However if I don't "upcast" the weights from Int to Float:

val values= List((1,2f),(1,3f)) //scalac sees it as Seq[(Int,Float)]  val avg= weightedAverage(values) 

Scala compiler will tell me:

error: could not find implicit value for evidence parameter of type Numeric[AnyVal]
val avg= weightedAverage(values)

Is there a way of getting round this?

I had an attempt at writing a NumericCombine class that I parameterized with A and B which "combines" the types into a "common" type AB (for example, combining Float and Int gives you Float) :

abstract class NumericCombine[A: Numeric, B: Numeric] {     type AB <: AnyVal      def fromA(x: A): AB     def fromB(y: B): AB     val num: Numeric[AB]      def plus(x: A, y: B): AB = num.plus(fromA(x), fromB(y))     def minus(x: A, y: B): AB = num.minus(fromA(x), fromB(y))     def times(x: A, y: B): AB = num.times(fromA(x), fromB(y)) } 

and I managed to write simple times and plus functions based on this with the typeclass pattern, but since NumericCombine introduces a path-dependent type AB, "composing" the types is proving to be more difficult than I expected. look at this question for more information and see here for the full implementation of NumericCombine.

Update

A somewhat satisfactory solution has been obtained as an answer to another question (full working demo here) however there is still room for some design improvement taking into account the points raised in the discussion with @ziggystar.

2 Answers

Answers 1

Linear combinations

I think the more general task that involves weighting/scaling some elements of type T by a scalar of type S is that of a linear combination. Here are the constraints on the weights for some tasks:

So the most general case according to this classification is the linear combination. According to Wikipedia, it requires the weights, S, to be a field, and T to form a vector space over S.

Spire

You could set up these requirements with typeclasses. There's also spire, which already has typeclasses for Field and VectorSpace. I have never used it myself, so you have to check it out yourself.

Float/Int won't work

What is also apparent from this discussion, and what you have already observed, is the fact that having Float as a weight, and Int as the element type will not work out, as the whole numbers do not form a vector space over the reals. You'd have to promote Int to Float first.

Solution via typeclass

There are only two major candidates for the scalar type, i.e., Float and Double. And mainly only Int is a candidate for promoting, so you could do the following as a simple and not so general solution:

case class Promotable[R,T](promote: R => T)  object Promotable {   implicit val intToFloat = Promotable[Int,Float](_.toFloat)   implicit val floatToDouble = Promotable[Float,Double](_.toDouble)   implicit val intToDouble = Promotable[Int,Double](_.toDouble)    implicit def identityInst[A] = Promotable[A,A](identity) }As a "small" solution you could write a typeclass   def weightedAverage[S,VS](values: Seq[(S,VS)])(implicit p: Promotable[VS,S]) = ??? 

Answers 2

First of all your template is wrong. (And sorry if the "template" expression is wrong - I am a novice in scala). Your functions expect tuples where both elements are of the same type ( [A: Numeric] ) , instead of tuples where elements are of different types ( [A: Numeric, B: Numeric] ) ( (Int, Float) vs (Float, Float) )

Anyway the below compiles and hopefully will work well after you fill it with your desired calculus.

import scala.collection._  def weightedSum[A: Numeric, B: Numeric](weightedValues: GenSeq[(A,B)]): (A,B) = {   weightedValues.foldLeft((implicitly[Numeric[A]].zero, implicitly[Numeric[B]].zero)) { (z, t) =>     (   implicitly[Numeric[A]].plus(z._1, t._1),          implicitly[Numeric[B]].plus(z._2, t._2)     )    }  }  def weightedAverage[A: Numeric, B: Numeric](weightedValues: GenSeq[(A,B)]): A = {   val (weightSum, weightedValueSum) = weightedSum(weightedValues)   implicitly[Numeric[A]] match {     case num: Fractional[A] => implicitly[Numeric[A]].zero     case num: Integral[A] => implicitly[Numeric[A]].zero     case _ => sys.error("Undivisable numeric!")   } }  val values1: Seq[(Float, Float)] = List((1, 2f), (1, 3f)) val values2: Seq[(Int, Float)] = List((1, 2f), (1, 3f))  val wa1 = weightedAverage(values1) val wa2 = weightedAverage(values2) 
Read More

Thursday, April 7, 2016

Implementing multiparameter C++ template like behaviour on C# using Policy Pattern

Leave a Comment

I'm trying to implement a c++ like template with C# generics and policy pattern based on this answer

This is a sample of the pattern:

interface ISomePolicy<T,U> {     void _doSomething(U u); }   class MyClass<T,U>:      ISomePolicy<int, double>,      ISomePolicy<int, int>     {      internal T myElement {get;set;}      public MyClass(T Element) {         myElement = Element;     }      void ISomePolicy<int, double>._doSomething(double u)     {         Console.WriteLine("this is int, double");     }      void ISomePolicy<int, int>._doSomething(int u)     {         Console.WriteLine("this is int, int");     }      }  static class MyClassExtension {      //What I want to do     public static void doSomething<P, T, U>(this P oTh, U u) where P : MyClass<T, U>, ISomePolicy<T, U>     {         oTh._doSomething(u);     }  } 

My intended behaviour is like this:

  MyClass<int, double> oClass = new MyClass<int, double>(3);    oClass.doSomething(0.5); //This works   oClass.doSomething(1);   //This works    oClass.doSomething("This should fail"); //Breaks at compile time               MyClass<string, double> oClass1 = new MyClass<string, double>("sadfsd"); //Not implemented, wasn't able to prevent the construction.    oClass1.doSomething(0.4); //Breaks at compile time 

But so far I wasn't able to make .net accept Generic Extension with less arguments than parameters

I can call the interface explicitly, which is horrible verbose defeating the purpose of all this.

oClass.doSomething < MyClass<int, double>,int,double>(0.5); 

I thought of working that around with a wrapper:

static class MyClassExtension{     private static void wrappedDoSomething<P, T, U>(this P oTh, U u)      where P : MyClass<T, U>, ISomePolicy<T, U>     {         oTh._doSomething(u);     }      public static void doSomething<T, U>(this MyClass<T, U> oTh, U u)      {         oTh.wrappedDoSomething<MyClass<T, U>, T, U>(u);     } } 

But the wrapper can't resolve both types for the wrapped function, failing with:

Error 1 The type 'MyClass' cannot be used as type parameter 'P' in the generic type or method 'MyClassExtension.wrappedDoSomething(P, U)'. There is no implicit reference conversion from 'MyClass' to 'ISomePolicy'

Any insights to fix the parameters issue or redesign all this are appreciated.


For context this would be used to wrap I/O translators. T in my case would be the target I/O format, and U the object representation of that data used by my framework.

I'm aware that this can be easily achieved with delegates or interfaces, but the objective is that the framework user easily instantiates the desired translation, and if an implementation doesn't exists, it can be trivially added to a common interface.


EDIT: Resolving a generic method from inside another generic method/class neither seems to work on mono.

2 Answers

Answers 1

Usually, policies should not contain data. For example,

interface ISomePolicy<T, U> {     void _doSomething(T t, U u); }  struct SomePolicyImplementation :     ISomePolicy<int, double>,     ISomePolicy<int, int>,     ISomePolicy<double, double> {     void ISomePolicy<int, int>._doSomething(int t, int u)         => Console.WriteLine("this is int, int");      void ISomePolicy<int, double>._doSomething(int t, double u)         => Console.WriteLine("this is int, double");      void ISomePolicy<double, double>._doSomething(double t, double u)         => Console.WriteLine("this is double, double"); }  static class SomePolicyExtension {     public static void doSomething<P, T, U>(this P policy, T t, U u)         where P : struct, ISomePolicy<T, U>         => policy._doSomething(t, u); } 

If you would like to combine policies and data then you may consider different interface

interface IEmbeddedPolicy<U> {     void _doSomething(U u); }  class MyClass<T> :     IEmbeddedPolicy<double>,     IEmbeddedPolicy<int> {     public T Value { get; }      public MyClass(T value) { this.Value = value; }      void IEmbeddedPolicy<int>._doSomething(int u)         => Console.WriteLine("this is T, int");      void IEmbeddedPolicy<double>._doSomething(double u)         => Console.WriteLine("this is T, double"); }  static class EmbeddedPolicyExtension {     public static void doSomething<E, U>(this E embedded, U u)         where E : IEmbeddedPolicy<U>         => embedded._doSomething(u); } 

Or combination of these two concepts

class MySuperClass<P, T>:     IEmbeddedPolicy<double>,     IEmbeddedPolicy<int>     where P: struct, ISomePolicy<T, double>, ISomePolicy<T, int> {     public T Value { get; }      public MySuperClass(T value) { this.Value = value; }      void IEmbeddedPolicy<int>._doSomething(int u)         => new P()._doSomething(this.Value, u);      void IEmbeddedPolicy<double>._doSomething(double u)         => new P()._doSomething(this.Value, u); } 

Usage:

// independent policy var policy = new SomePolicyImplementation();  policy.doSomething(5, 6); policy.doSomething(5, 6.7); policy.doSomething(5.3, 6.7);  // embedded policy var my = new MyClass<int>(54); my.doSomething(5); my.doSomething(89.7);  // combination var x = new MySuperClass<SomePolicyImplementation, int>(53); x.doSomething(9); x.doSomething(18.3); 

Answers 2

Tried your code, but even simple calls did not work out of box. Main problem is that MyClass contains unknown element type 'myEement' - that type cannot be deduced from function call parameters. However - if you make a generalization and omit object type - your sample will work in out of box manner:

using System; using System.Collections.Generic;  interface ISomePolicy<U>  {     void _doSomething(U u); }  public class MyClass<U> :      ISomePolicy<double>,      ISomePolicy<int> {     internal object myEement { get; set; }      public MyClass(object Element)     {         myEement = Element;     }      void ISomePolicy<double>._doSomething(double u)     {         Console.WriteLine("this is double");     }      void ISomePolicy<int>._doSomething(int u)     {         Console.WriteLine("this is int");     } }  static class MyClassExtension {     public static void doSomething<P, U>(this P oTh, U u) where P : ISomePolicy<U>     {         oTh._doSomething(u);     } }  class Program {     static void Main()     {         MyClass<double> oClass = new MyClass<double>(3);         oClass.doSomething(0.5); //This works         oClass.doSomething(1);   //This works                     //oClass.doSomething("Will not work");     } } 

What is up to myEement (or you probably meant myElement) - you can get's it's type at run-time if necessary.

myElement.GetType(), or cast to it - e.g. if( myElement is int ) DoSomethingWithInt( (int) myElement ); 

However - reflection always might slow down your execution. If you don't intend to create super heavy class hierarchy with huge amount of instances - then this should be sufficient for your needs.

Read More