Search code examples
c#constraintsselectiongeneric-programming

C# Generic Algorithm constraining parameter to number


I am writing a generic roulette selection algorithm. Normally, property is a primitive numeric type that can be used in summation of each element's "score".

However, since the implementation is intended to be generic and there is no way to constrain the type of the property to be a numeric primitive directly, I have no clear way to sum the values and select proportionally by the value of property.

In the below code, you will notice that I am trying to add the property's value to sum and rouletteSum. This code produces errors, since PropertyInfo.GetValue() returns an object that I cannot cast to a primitive numeric type without essentially breaking the genericness of the implementation.

What approach can I take to assure genericness of the algorithm while still being able to proportionally compare and select from the values of the provided property?

One consideration is to constrain P to IConvertible, but I would imagine that would result in some ugly typecasting when supplying primitives in the property parameter.

public class RouletteSelectionFunction : ISelectionFunction
{
  public string Name => "Roulette";

  public T Select<T, P>( IEnumerable<T> elements, Expression<Func<T, P>> property )
    where T : class
  {
    var prop = ( PropertyInfo ) ( ( MemberExpression ) property.Body ).Member;

    // Sum all fitnesses and normalize negatives
    // by shifting range to minimum of 0
    double sum = 0.0;
    double lowest = 0.0;
    for ( var i = 0; i < elements.Count(); i++ )
    {
      var value = prop.GetValue( elements.ElementAt( i ) );
      sum += value;
      if ( value < lowest )
        lowest = value;
    }
    lowest = Math.Abs( lowest );
    sum += lowest * elements.Count();

    // Roll roulette and select victor
    double rouletteSum = 0;
    double random = RandomGen.NextDouble() * sum; //RandomGen wraps Random() class and NextDouble() returns number between 0 and 1
    for( var i = 0; i < elements.Count(); i++ )
    {
      rouletteSum += prop.GetValue( elements.ElementAt( i ) );
      if ( random <= rouletteSum )
        return elements.ElementAt( i );
    }

    throw new SelectionFailedException( "Roulette Selection could not determine victor" );
  }
}

// Call via:
// RouletteSelectionFunction.Select( elements, x => x.Score )

Solution

  • What approach can I take to assure genericness of the algorithm while still being able to proportionally compare and select from the values of the provided property?

    You don't, at least not easily. C# has never provided a generic type system suitable for abstractions over arithmetic.

    There have been many proposals over the years. For example, you could imagine allowing static members in interfaces, and then you could say where T : IAddable<T>, where IAddable<T> is an interface that promises that there is an public static T operator +(T, T) on T.

    You could also explicitly pass in a Func<T, T, T> that implements your sum, and so on.

    But the problem you face is essentially that you wish to abuse generics in order to form specializations that are not actually generic. We think of generics as being something like List<T> where you really, truly can make a list of any type whatsoever. Is your code actually generic? It sounds like it could be made to work by simply saying that sums sum to double.