//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
        }
 //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;
 }