//method to calculate the root for a system of functions given an initial guess/vector
        //Gradient Descent with Fixed Alpha
        public double[] GradientAlpha(FunctionMatrix f, double[] x, double toler)
        {
            int counter = 0;
            int dim = x.GetLength(0);
            int r = f.Rows;

            double[,] Jmat = new double[r, dim];
            Matrix MJmat = new Matrix(Jmat);
            Vector VFg1 = new Vector(r);
            Vector Vz = new Vector(dim);
            Vector VFg3 = new Vector(r);
            Vector VFg2 = new Vector(r);
            Vector VFgc = new Vector(r);
            Vector VFgnew = new Vector(r);
            Vector Vxnew = new Vector(dim);

            double alpha2 = 0;
            double alpha3 = 0;
            double[] xold = x;
            double[] xnew = new double[dim];
            double g1 = 0;
            double g2 = 0;
            double g3 = 0;
            double gc = 0;
            double gnew = 0;
            double normz = 0;
            double h1 = 0;
            double h2 = 0;
            double h3 = 0;
            double ac = 0;

            do
            {
                VFg1 = f.EvaluateVector(xold);
                g1 = VFg1.Magnitude();

                //calculate the Jacobian
                Jmat = jacobi(f, xold, 0.001);
                //now update the Matrix object which represents the Jacobian
                for (int i = 0; i < r; i++)
                    for (int j = 0; j < dim; j++)
                        MJmat[i, j] = Jmat[i, j];

                Vz = 2 * (MJmat * VFg1);

                normz = Math.Sqrt(Vz.Magnitude());

                if (normz > toler)
                {
                    Vz = (1 / normz) * Vz;
                    alpha3 = 1;

                    VFg3 = f.EvaluateVector((double[])((Vector)xold - (alpha3 * Vz)));
                    g3 = VFg3.Magnitude();

                    while (Math.Abs(g3 - g1) > toler)
                    {
                        alpha3 = 0.5 * alpha3;

                        VFg3 = f.EvaluateVector((double[])((Vector)xold - (alpha3 * Vz)));
                        g3 = VFg3.Magnitude();
                        if (Math.Abs(alpha3) < 0.5 * toler)
                            break;
                    }

                    alpha2 = 0.5 * alpha3;
                    VFg2 = f.EvaluateVector((double[])((Vector)xold - (alpha2 * Vz)));
                    g2 = VFg2.Magnitude();

                    //perform interpolation
                    h1 = (g2 - g1) / alpha2;
                    h2 = (g3 - g2) / (alpha3 - alpha2);
                    h3 = (h2 - h1) / alpha3;
                    ac = 0.5 * (alpha2 - (h1 / h3));

                    VFgc = f.EvaluateVector((double[])((Vector)xold - (ac * Vz)));
                    gc = VFgc.Magnitude();

                    if (gc < g3)
                    {
                        Vxnew = ((Vector)xold) - (ac * Vz);
                        VFgnew = f.EvaluateVector((double[])Vxnew);
                        gnew = VFgnew.Magnitude();
                    }
                    else
                    {
                        Vxnew = ((Vector)xold) - (alpha3 * Vz);
                        VFgnew = f.EvaluateVector((double[])Vxnew);
                        gnew = VFgnew.Magnitude();
                    }

                    //test for convergence
                    if (Math.Abs(gnew - g1) < toler)
                        break;
                    else
                    {
                        xold = (double[])Vxnew;
                        counter++;
                    }

                    //end if
                }

            } while (counter < 100);

            return (double[])Vxnew;
            //end of method
        }
        //method to calculate the root for a system of functions given an initial guess/vector
        public double[] newtonraphson(FunctionMatrix f, double[] x, double toler)
        {
            int maxiter = 1000;
            double err = 10000000;
            int counter = 0;
            int dim = x.GetLength(0);
            int r = f.Rows;
            double[] xn = new double[dim];
            //populating vector xn
            for (int i = 0; i < dim; i++)
                xn[i] = x[i];
            double[] xnp1 = new double[dim];

            while ((counter < maxiter) && (err > toler))
            {
                Vector Fn = f.EvaluateVector(xn);
                //converting to Vector Objects
                Vector Vxn = new Vector(xn);

                //Need to calculate the Jacobi and convert it to a matrix
                double[,] j = jacobi(f, xn, 0.001);
                double[,] jinv = s.find_inverse(j, j.GetLength(0));
                Matrix Jinv = new Matrix(jinv);

                //this is just F(xn)/F'(xn)
                Vector tmp = Jinv * Fn;

                //xnp1 = xn - F(xn)/F'(xn)
                Vector Vxnp1 = Vxn - tmp;

                //what is the size of the err i.e. xnp1-xn
                Vector Diff = Vxnp1 - Vxn;
                err = Diff.maxNorm();
                double[] t = new double[dim];

                xnp1 = (double[])Vxnp1;
                xn = xnp1;
                counter++;
            }

            return xn;
            //end of method
        }
 //method to calculate the inverse of a matrix using the Sherman Morrison formula
 //this method will be utilised in the Broyden method
 public double[,] BroydenAinv(double[,] Ainvold, double[] deltax, double[] deltaF)
 {
     Matrix MAinvold = new Matrix(Ainvold);
     Vector Vdeltax = new Vector(deltax);
     Vector VdeltaF = new Vector(deltaF);
     //placeholder vector, won't be used for anything apart from calling the outer product and dot product Vector methods
     Vector interim = new Vector(1);
     Vector temp = new Vector(interim.dot(MAinvold, VdeltaF));
     Vector u = new Vector(Vdeltax - temp);
     Vector v = new Vector(interim.dot(Vdeltax, MAinvold));
     Matrix numer = new Matrix(interim.outer(u, v));
     double denom = interim.dot(Vdeltax, temp);
     Matrix update = new Matrix(1 / denom * numer);
     Matrix MAinvnew = new Matrix(MAinvold + update);
     double[,] Ainvnew = (double[,])MAinvnew;
     return Ainvnew;
 }
        //method to calculate the root for a system of functions given an initial guess/vector
        public double[] BroydenShermanMorrison(FunctionMatrix f, double[] x, double toler)
        {
            double err = 10000000;
            int counter = 0;
            int dim = x.GetLength(0);
            int r = f.Rows;
            double[] xn = new double[dim];
            //populating vector xn
            for (int i = 0; i < dim; i++)
                xn[i] = x[i];
            double[] xnp1 = new double[dim];

            //first iteration i.e. use Newton Raphson for one iteration, the Inverse of the Jacobi will be used as the Ainv for Broyden
            Vector Fn = f.EvaluateVector(xn);
            Vector Vxn = new Vector(xn);
            //Need to calculate the Jacobi and convert it to a matrix
            double[,] j = jacobi(f, xn, 0.001);
            double[,] jinv = s.find_inverse(j, j.GetLength(0));
            Matrix Jinv = new Matrix(jinv);
            //this is just F(xn)/F'(xn)
            Vector tmp = Jinv * Fn;
            //xnp1 = xn - F(xn)/F'(xn)
            Vector Vxnp1 = Vxn - tmp;
            //what is the size of the err i.e. xnp1-xn
            Vector Vdeltax = Vxnp1 - Vxn;
            err = Vdeltax.maxNorm();
            xnp1 = (double[])Vxnp1;

            Vector placeholder = new Vector(1);

            //we'll use these later
            Vector VFnold = f.EvaluateVector(xn);
            Vector VFnew = f.EvaluateVector(xnp1);
            Vector VdeltaF = VFnew - VFnold;
            double[,] Aold = new double[dim, dim];
            double[,] Anew = new double[dim, dim];

            //now we'll start on the Broyden iteration element
            if (err < toler)
                return xn;
            else
            {
                while ((err > toler) && (counter < 1000))
                {
                    if (counter == 0)
                    {
                        Aold = jinv;
                        Anew = BroydenAinv(Aold, (double[])Vdeltax, (double[])VdeltaF);
                    }
                    else
                    {
                        Anew = BroydenAinv(Aold, (double[])Vdeltax, (double[])VdeltaF);
                    }
                    //now update all the variables
                    Vxnp1 = Vxn - placeholder.dot(new Matrix(Anew), VFnew);
                    Vdeltax = Vxnp1 - Vxn;
                    err = Vdeltax.maxNorm();
                    Aold = Anew;
                    VFnold = f.EvaluateVector((double[])Vxn);
                    VFnew = f.EvaluateVector((double[])Vxnp1);
                    VdeltaF = VFnew - VFnold;
                    Vxn = Vxnp1;
                    xn = (double[])Vxn;
                    counter++;
                }
                return xn;
            }
            //end of method
        }
 //dot product of a vector and a Matrix
 public Vector dot(Vector v, Matrix m)
 {
     int mrows = m.Rows;
     int mcols = m.Cols;
     int vrows = v.Rows;
     if (mcols == vrows)
     {
         double[] temp = new double[mrows];
         for (int i = 0; i < mrows; i++)
         {
             double sum = 0;
             for (int j = 0; j < vrows; j++)
             {
                 double c = m[i, j] * v[j];
                 sum = sum + m[i, j] * v[j];
             }
             temp[i] = sum;
         }
         Vector ans = new Vector(temp);
         return ans;
     }
     else
         return v;
 }
 //outer productover of two vectors
 //dot product of two vectors
 public Matrix outer(Vector v1, Vector v2)
 {
     int r1 = v1.Rows;
     int r2 = v2.Rows;
     double[,] temp = new double[v1.rows, v2.rows];
     for (int i = 0; i < r1; i++)
     {
         for (int j = 0; j < r2; j++)
         {
             temp[i, j] = v1.data[i] * v2.data[j];
         }
     }
     Matrix m = new Matrix(temp);
     return m;
 }
 public static Vector operator -(Vector a)
 {
     Vector tmp = new Vector(a.rows);
     for (int i = 0; i < a.rows; i++)
         tmp.data[i] = -a.data[i];
     return tmp;
 }
 //dot product of two vectors
 public double dot(Vector v1, Vector v2)
 {
     int r1 = v1.Rows;
     int r2 = v2.Rows;
     if (r1 == r2)
     {
         double sum = 0;
         for (int i = 0; i < r1; i++)
         {
             sum = sum + v1.data[i] * v2.data[i];
         }
         return sum;
     }
     else return 0;
 }
 public static Vector operator +(Vector a)
 {
     Vector tmp = new Vector(a);
     return tmp;
 }
 public static Vector operator -(Vector a, Vector b)
 {
     if (a.rows != b.rows)
         return null;
     Vector tmp = new Vector(a.rows);
     for (int i = 0; i < a.rows; i++)
         tmp.data[i] = a.data[i] - b.data[i];
     return tmp;
 }
 //Product of Matrix and vector
 public static Vector operator *(Matrix a, Vector b)
 {
     if (a.Cols != b.rows)
         return null;
     int i, j;
     double sum = 0;
     Vector tmp = new Vector(a.Rows);
     for (i = 0; i < a.Rows; i++)
     {
         sum = 0;
         for (j = 0; j < a.Cols; j++)
             sum += a[i, j] * b[j];
         tmp[i] = sum;
     }
     return tmp;
 }
 //scalar product
 public static Vector operator *(double a, Vector b)
 {
     Vector tmp = new Vector(b.rows);
     for (int i = 0; i < b.rows; i++)
         tmp[i] = a * b[i];
     return tmp;
 }
 //scalar product
 public static double operator *(Vector a, Vector b)
 {
     if (a.rows != b.rows)
         return 0;
     Vector tmp = new Vector(a.rows);
     double sum = 0;
     for (int i = 0; i < a.rows; i++)
         sum += a[i] * b[i];
     return sum;
 }
 public Vector(Vector val)
 {
     rows = val.rows;
     data = new double[rows];
     for (int i = 0; i < rows; i++)
         data[i] = val.data[i];
 }
 public Vector EvaluateVector(double[] val)
 {
     Vector tmp = new Vector(rows);
     int i;
     for (i = 0; i < rows; i++)
         tmp[i] = f[i, 0](val);
     return tmp;
 }