forum.alglib.net
http://forum.alglib.net/

Least Squares for Non-Linear Curve fitting in C#
http://forum.alglib.net/viewtopic.php?f=2&t=3792
Page 1 of 1

Author:  sagh0901 [ Sun Feb 26, 2017 10:27 am ]
Post subject:  Least Squares for Non-Linear Curve fitting in C#

I was using Math.Numerics in C# for my coding purposes but now I am learning Alglib since it has cross platform universal implementations. I am moving my Non-Linear curve fitting for the assumed equation and with sample generated data and upon successful i can fit my own data.
Curve Equation is : y = a * cos(b * x + c) + d * sin(e * x + f)

and C# code is :
Code:
class Program
    {

        public static int Main(string[] args)
        {

            /*string fileName = @"C:\Dropbox\Dropbox\Trade\AVLTreeC#\TestFiles\exchange.csv";
            GetRawDataXY(fileName);*/
            double[] coeffs=InitalizeSampleData(1000);
            System.Console.WriteLine("Curve original Coeffs are : {0}", alglib.ap.format(coeffs, 10));
            Random randNum = new Random();
           // Random randInt = new Random();
            double[] c = Enumerable.Repeat(0, 5 + 1)
                    .Select(i => randNum.NextDouble() + 1).ToArray();
            double epsf = 0;
            double epsx = 0.000001;
            int maxits = 0;
            int info;
            alglib.lsfitstate state;
            alglib.lsfitreport rep;

            //
            // Fitting without weights
            //
            alglib.lsfitcreatefgh(Curve.Xdata, Curve.Ydata, c, out state);
            alglib.lsfitsetcond(state, epsf, epsx, maxits);
            alglib.lsfitfit(state, ModelValue, ModelGradient, ModelHessian, null, null);
            alglib.lsfitresults(state, out info, out c, out rep);
            System.Console.WriteLine("{0}", info); // EXPECTED: 2
            System.Console.WriteLine("Curve Generated coeffs without weights are : {0}", alglib.ap.format(c, 10)); // EXPECTED: [1.5]

           
            System.Console.ReadLine();
            return 0;
        }

        private static double[] InitalizeSampleData(int sampleSize)
        {
            int count = 0;
            Random randNum = new Random();
            // Random randInt = new Random();
            double[] coeffs = Enumerable.Repeat(0, 5 + 1)
                    .Select(j => randNum.NextDouble() + 1).ToArray();

            Curve.Xdata = new double[sampleSize, 1];
            Curve.Ydata = new double[sampleSize];
            for (int i=0;i<sampleSize;i++)
            {
               
                Curve.Xdata[count, 0] = Convert.ToDouble(i+1);
               
                double[] xData =new double[1] { Curve.Xdata[count,0] };
                ModelValue(coeffs, xData, ref Curve.Ydata[count], null);
               
                count++;

            }
            return coeffs;
        }

        protected static void ModelValue(double[] parameters, double[] x, ref double func, object obj)
        {
            func = parameters[0] * Math.Cos(parameters[1] * x[0] + parameters[2]) + parameters[3] * Math.Sin(parameters[4] * x[0] + parameters[5]);
        }

        protected static void ModelGradient(double[] parameters, double[] x, ref double func, double[] gradient, object obj)
        {
            ModelValue(parameters, x, ref func, obj);
            gradient[0] = Math.Cos(parameters[1] * x[0] + parameters[2]);
            gradient[1] = -parameters[0] * Math.Sin(parameters[1] * x[0] + parameters[2]) * x[0];
            gradient[2] = -parameters[0] * Math.Sin(parameters[1] * x[0] + parameters[2]);
            gradient[3] = Math.Sin(parameters[4] * x[0] + parameters[5]);
            gradient[4] = parameters[3] * Math.Cos(parameters[4] * x[0] + parameters[5]) * x[0];
            gradient[5] = parameters[3] * Math.Cos(parameters[4] * x[0] + parameters[5]);
        }

        protected static void ModelHessian(double[] c, double[] x, ref double func, double[] grad, double[,] hess, object obj)
        {
            ModelValue(c, x, ref func, obj);
            ModelGradient(c, x, ref func, grad, obj);
            Hessian(x[0], c, ref hess);
        }

        private static void Hessian(double x, double[] parameters, ref double[,] hess)
        {

            hess[0, 0] = 0; //d2/du2
            hess[1, 0] = -Math.Sin(parameters[1] * x + parameters[2]) * x; //d2/dvdu
            hess[2, 0] = -Math.Sin(parameters[1] * x + parameters[2]); //d2/dwdu
            hess[3, 0] = 0;//d2/dxdu
            hess[4, 0] = 0;//d2/dydu
            hess[5, 0] = 0;//d2/dydz

            hess[0, 1] = -Math.Sin(parameters[1] * x + parameters[2]);//d2/dudv
            hess[1, 1] = -parameters[0] * Math.Cos(parameters[1] * x + parameters[2]) * x * x; //d2/dv2
            hess[2, 1] = -parameters[0] * Math.Cos(parameters[1] * x + parameters[2]) * x; //d2/dwdv
            hess[3, 1] = 0;//d2/dxdv
            hess[4, 1] = 0;//d2/dydv
            hess[5, 1] = 0;////d2/dzdv

            hess[0, 2] = -Math.Sin(parameters[1] * x + parameters[2]) * x;//d2/dudw
            hess[1, 2] = -parameters[0] * Math.Cos(parameters[1] * x + parameters[2]) * x;  //d2/dvdw
            hess[2, 2] = -parameters[0] * Math.Cos(parameters[1] * x + parameters[2]); //d2/dw2
            hess[3, 2] = 0;//d2/dxdw
            hess[4, 2] = 0;//d2/dydw
            hess[5, 2] = 0;////d2/dzdw

            hess[0, 3] = 0;//d2/dudx
            hess[1, 3] = 0;  //d2/dvdx
            hess[2, 3] = 0; //d2/dwdx
            hess[3, 3] = 0; //d2/dx2
            hess[4, 3] = Math.Cos(parameters[4] * x + parameters[5]) * x;//d2/dydx
            hess[5, 3] = Math.Cos(parameters[4] * x + parameters[5]); ////d2/dzdx

            hess[0, 4] = 0;//d2/dudy
            hess[1, 4] = 0;  //d2/dvdy
            hess[2, 4] = 0; //d2/dwdy
            hess[3, 4] = Math.Cos(parameters[4] * x + parameters[5]) * x; //d2/dxdy
            hess[4, 4] = -parameters[3] * Math.Sin(parameters[4] * x + parameters[5]) * x * x;//d2/dy2
            hess[5, 4] = -parameters[3] * Math.Sin(parameters[4] * x + parameters[5]) * x; ////d2/dzdy


            hess[0, 5] = 0;//d2/dudz
            hess[1, 5] = 0;  //d2/dvdz
            hess[2, 5] = 0; //d2/dwdz
            hess[3, 5] = Math.Cos(parameters[4] * x + parameters[5]);  //d2/dxdz
            hess[4, 5] = -parameters[3] * Math.Sin(parameters[4] * x + parameters[5]) * x;//d2/dydz
            hess[5, 5] = -parameters[3] * Math.Sin(parameters[4] * x + parameters[5]); ////d2/dz2



        }

        public static void GetRawDataXY(string filename)
        {
         
            int count = 0;

            var lines = File.ReadAllLines(filename);
            Curve.Xdata = new double[lines.Count(),1];
            Curve.Ydata = new double[lines.Count()];
            foreach (var line in lines)
            {

                var elements = line.Split(';');
                Curve.Xdata[count,0] = Convert.ToDouble(elements[0]);
                Curve.Ydata[count] = Convert.ToDouble(elements[1]);
                count++;

            }
        }
       
        public class Curve
        {
            /*Global Variables*/
            public static double[,] Xdata;
            public static double[] Ydata;
           


        }

       
    }


Ofcourse I am getting some values for Coeffs. But I wonder whether this approach is correct. I suspect on function alglib.lsfitfit algorithm. I have hard in understanding what it does. I just followed documentation. Does it minimize on R2 basis? I want my curve fitting to stop fitting when it reached below criteria:
NewCalcR2-oldCalcR2 is <= Given delta value or
Magnitude of(OldCoffVector-NewCoeffVector) <=GivenDeltaValue or IterationCount reached maximum
Ofcourse I know this by looking at Info value. I need to make sure if this is correct.

Output from Console:
Image

As you see from ouput, original and generated coeff no way near to the value. I want the generated coeffs to be as approximate equal to that. How could i achieve that?

Author:  Sergey.Bochkanov [ Mon Feb 27, 2017 9:21 am ]
Post subject:  Re: Least Squares for Non-Linear Curve fitting in C#

Hi! I have a few thoughts:

1. You may find it easier to work with optimizer created with lsfitcreatefg (just gradient is used) or even with lsfitcreatef (you specify just function value, numerical differentiation is used, it is often convenient for fast prototyping).

2. I noticed that you use random initial point. However, your target function is notoriously hard one - sine and cosine functions result in difficult landscape with many bad local extrema. So, it is very unlikely that you will converge to the same coeffs as ones which were used to generate dataset.

If you want to solve a toy problem with aim of reproducing original coefficients used to generate dataset, it is better to distort these original coefficients a little, and pass them to lsfit optimizer as initial point. You will see whether it is able to refine them and restore original values - or not. You may start from small distortions, like 1.0E-3 in magnitude, and increase them step by step. Different coefficients will show different tolerances to distortions - ones "hidden within" sine and cosine will be most intolerable.

3. lsfit optimizer returns a lot of information in the rep parameter. Say, rep.rmserror and rep.avgerror contain different kinds of error metric on your dataset - root-mean-square and average.

Author:  sagh0901 [ Mon Feb 27, 2017 12:02 pm ]
Post subject:  Re: Least Squares for Non-Linear Curve fitting in C#

Thanks for the reply.

What do you mean by distort the orginal coefficients? Should i substract the magnitude or add the magnitude to the coeffs?

Can i Use distorted coeffs of sample generated data to my actual dataset?

Author:  Sergey.Bochkanov [ Tue Feb 28, 2017 5:06 pm ]
Post subject:  Re: Least Squares for Non-Linear Curve fitting in C#

Say, generate data using coefficient vector C0. Then, generate random noise E with zero mean and unit standard deviation. Then let C1=C0 + 0.01*E, and try to solve least squares problem using C1 as initial estimate. If everything is right, it should converge to C0.

Author:  sagh0901 [ Sun Mar 05, 2017 6:01 pm ]
Post subject:  Re: Least Squares for Non-Linear Curve fitting in C#

Thanks, Its working..

Page 1 of 1 All times are UTC
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/