Java IntStream, Range and mapToDouble and reduce function equivalent in C#

Viewed 615

Can someone help me with what will the below lines of Java do ? Or can you give an C# equivalent of the below lines of code

  public static double[] logSumExp(List<Double> a, List<Double> b) {
    double amax = Collections.max(a);
    double sum = IntStream.range(0, a.size())
                     .mapToDouble(i -> Math.exp(a.get(i) - amax) * (i < b.size() ? b.get(i) : 1.0))
                     .reduce(0.0, Double::sum);
    double sign = Math.signum(sum);
    sum *= sign;
    double abs = Math.log(sum) + amax;
    double[] ret = {abs, sign};
    return ret;
  }
3 Answers

Code using streams in Java usually translates well into LINQ in .NET.

map or mapToXXX works like Select, reduce is Aggregate, but here Sum is more convenient. IntStream.range is Enumerable.Range. Everything else should have a "obvious" equivalent.

public static double[] LogSumExp(IList<double> a, IList<double> b) {
    double amax = a.Max();
    double sum = Enumerable.Range(0, a.Count)
                    .Select(i => Math.Exp(a[i] - amax) * (i < b.Count ? b[i] : 1.0))
                    .Sum();
    double sign = Math.Sign(sum);
    sum *= sign;
    double abs = Math.Log(sum) + amax;
    double[] ret = {abs, sign};
    return ret;
}

If you are using C# 7+, you should really be returning a tuple instead:

public static (double abs, double sign) LogSumExp(IList<double> a, IList<double> b) {
    ...
    return (abs, sign);
}

The long answer to what that function does is well explained in this LogSumExp Wikipedia Page. It's usually referred to by its short name, LSE, or softmax.

The link also explains why the need to subtract the max from each value before applying the exponent and adding the max at the end.

Regarding Java/C# conversion, Java Streams operations are very similar to LINQ operations. For this specific case, the literal conversion should be straightforward as almost all methods are named the same (mind the naming conventions).

The less obvious ones:

  • Collections.max is a simple LINQ extension method named Max that can be applied directly to lists.
  • IntStream is simply Enumerable and has a method Range as well.
  • mapToDouble be achieved in LINQ with Select.
  • reduce, in this case, can be replaced by Sum.

Hope you find this information useful.

The C# equivalent code.

    public static double[] logSumExp(List<Double> a, List<Double> b)
    {
        double amax = a.Max();
        double sum = Enumerable.Range(0, a.Count()).Sum(i => Math.Exp(a[i] - amax) * (i < b.Count() ? b[i] : 1.0));
        double sign = Math.Sign(sum);
        sum *= sign;
        double abs = Math.Log(sum) + amax;
        double[] ret = {abs, sign};
        return ret;
    }
Related