6

I'm looking for a simple function that will accept an array of double values and return the mathematical derivative.

Math.NET appears to have such a function, but it's asking for the following syntax:

double FirstDerivative(Func<double, double> f, double x)

I'm not sure why I would need to specify a function. I just want a preexisting function that I can pass data to.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Nick Gallant
  • 285
  • 1
  • 3
  • 12
  • 2
    Did you see this post, [Mathematical Derivation with C#](http://stackoverflow.com/q/373186/231316)? – Chris Haas Dec 10 '15 at 16:16
  • @ChrisHaas - you saved me from typing [this answer](http://stackoverflow.com/a/373265/1364007) but less well-written. – Wai Ha Lee Dec 10 '15 at 16:17
  • An derivate is just the area bellow that array of points you need to pass, so just calculate each area and sum them all. That's it – bto.rdz Dec 10 '15 at 16:17
  • 4
    hmm... the area below a curve is actually the integral, not derivative.... – jsanalytics Dec 10 '15 at 16:28
  • @bto.rdz Derivative is the direction of a tangent at a specific point on the function graph. – IS4 Dec 10 '15 at 16:31
  • 2
    The derivative of an array doesn't make a whole lot of sense. Where does your array of data come from? The only context I'm aware of where you compute a derivative using a discrete set of points is when you want to numerically approximate the derivative of a function (which is likely what that `FirstDerivative` function does, but it discretizes the function itself). – Kyle Dec 10 '15 at 16:37
  • @jstreet my bad, then what he can do is evaluate the equation of a Line with 2 points, this is the best he can do with an array, it is a numeric approach and will be more precise if delta(distance between points) is close to zero – bto.rdz Dec 10 '15 at 16:48
  • 1
    Do you want an array of the differences between pairs of consecutive points from the original array? – Graham Dec 10 '15 at 16:49
  • Yes, that's correct. I'm looking for the derivative (e.g. velocity) between each pair of consecutive points from an array of distances. – Nick Gallant Dec 10 '15 at 18:04
  • What you need is to fit a cubic spline through the data end then evaluate the slope (or curvature) at each point. Please update the question so it makes more sense. – John Alexiou Dec 10 '15 at 20:19
  • Also if you want a non-linear regression to evaluate the slope at different points from measured data look at: http://stackoverflow.com/a/8005339/380384 – John Alexiou Dec 10 '15 at 20:23
  • Math.NET has [Cubic Spline](http://numerics.mathdotnet.com/api/MathNet.Numerics.Interpolation/CubicSpline.htm) evaluation capabilities. – John Alexiou Dec 10 '15 at 20:25

4 Answers4

13

Take your data points and create a Math.NET Numerics Cubic Spline object. Then use the .Differentiate() method to get the slope at each point you want.

Example

Try the code below:

static class Program
{
    const int column_width = 12;
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        var xvec = new DenseVector(new double[] { 0.0, 1.0, 2.0, 3.0, 4.0 });
        var yvec = new DenseVector(new double[] { 3.0, 2.7, 2.3, 1.6, 0.2 });
        Debug.WriteLine("Input Data Table");
        Debug.WriteLine($"{"x",column_width} {"y",column_width}");
        for(int i = 0; i < xvec.Count; i++)
        {
            Debug.WriteLine($"{xvec[i],column_width:G5} {yvec[i],column_width:G5}");
        }
        Debug.WriteLine(" ");
        var cs = CubicSpline.InterpolateNatural(xvec, yvec);

        var x = new DenseVector(15);
        var y = new DenseVector(x.Count);
        var dydx = new DenseVector(x.Count);
        Debug.WriteLine("Interpoaltion Results Table");
        Debug.WriteLine($"{"x",column_width} {"y",column_width} {"dy/dx",column_width}");
        for(int i = 0; i < x.Count; i++)
        {
            x[i] = (4.0*i)/(x.Count-1);
            y[i] = cs.Interpolate(x[i]);
            dydx[i] = cs.Differentiate(x[i]);
            Debug.WriteLine($"{x[i],column_width:G5} {y[i],column_width:G5} {dydx[i],column_width:G5}");
        }


    }
}

And look at the debug output:

Input Data Table
           x            y
           0            3
           1          2.7
           2          2.3
           3          1.6
           4          0.2

Interpoaltion Results Table
           x            y        dy/dx
           0            3     -0.28214
     0.28571        2.919     -0.28652
     0.57143       2.8354     -0.29964
     0.85714       2.7469      -0.3215
      1.1429       2.6509     -0.35168
      1.4286       2.5454     -0.38754
      1.7143        2.429     -0.42864
           2          2.3       -0.475
      2.2857        2.154     -0.55809
      2.5714       1.9746      -0.7094
      2.8571       1.7422     -0.92894
      3.1429       1.4382      -1.1979
      3.4286       1.0646      -1.4034
      3.7143      0.64404      -1.5267
           4          0.2      -1.5679

plot1

John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • Can you please show how it can be achieved by some code example? – IndustProg Feb 05 '18 at 12:25
  • Notice that a natural spline has the 2nd derivative set to zero at the end (that's why the green line is constant at the ends). There are other options where end slopes are specified and the 2nd derivative is not zero. – John Alexiou Feb 06 '18 at 14:51
1

If you aren't opposed to libraries other than Math.Net, you could try AlgLib and their spline1ddiff function

Building the spline is easy, and the Akima spline looks to be nice and smooth through the points. If you wanted a method that takes in a set of data and returns the derivatives, here's an example using the AlgLib math library:

public static void CalculateDerivatives(this Dictionary<double, double> inputPoints, out Dictionary<double, double> firstDerivatives, out Dictionary<double, double> secondDerivatives)
{
        var inputPointsXArray = inputPoints.Keys.ToArray();
        var inputPointsYArray = inputPoints.Values.ToArray();

        spline1dinterpolant akimaSplineToDifferentiate;
        alglib.spline1dbuildakima(inputPointsXArray, inputPointsYArray, out akimaSplineToDifferentiate);

        firstDerivatives = new Dictionary<double, double>();
        secondDerivatives = new Dictionary<double, double>();
        foreach (var pair in inputPoints)
        {
            var xPoint = pair.Key;
            double functionVal, firstDeriv, secondDeriv;
            alglib.spline1ddiff(akimaSplineToDifferentiate, xPoint, out functionVal, out firstDeriv, out secondDeriv);

            firstDerivatives.Add(point, firstDeriv);
            secondDerivatives.Add(point, secondDeriv);
        }
}

Be Warned: Akima Spline has unpredictable behavior outside of the range of your dataset.

morleyc
  • 2,169
  • 10
  • 48
  • 108
Jacob Shanley
  • 893
  • 1
  • 8
  • 19
0

Thanks for the responses.

I believe I'll need to iterate through the array, calling the Differentiate function from Math.NET, or perhaps simply write my own (rise over run) calculation.

Nick Gallant
  • 285
  • 1
  • 3
  • 12
  • 1
    Don't just take the simple difference of consecutive points, as the results will be very choppy. You have to interpolate the points and differentiate the interpolation. Please share some of the data points in the post so we can try different things. – John Alexiou Dec 11 '15 at 14:39
0

Here you have derivative extension for function

public static Func<double[], double> Derivative(this Func<double[], double> func, int derivativeIndex)
{
    double step = 0.001;
    return income => 
    {
        double[] increasedIncome = (double[])income.Clone();
        increasedIncome[derivativeIndex] += step;

        double[] decreasedIncome = (double[])income.Clone();
        decreasedIncome[derivativeIndex] -= step;

        return (func(increasedIncome) - func(decreasedIncome)) / (2 * step);
    };
}
Jacob Shanley
  • 893
  • 1
  • 8
  • 19