S
S
skosterin882016-09-21 11:40:45
C++ / C#
skosterin88, 2016-09-21 11:40:45

The program throws an IndexOutOfRangeException error. What is the reason and how to fight?

I am currently working on a project that involves solving systems of N equations with N unknowns using Newton's method. There is a class "system of equations":

public class EquationsSystem
    {
        /// <summary>
        /// Функции, определяющие внешний вид уравнений системы. Каждое уравнение имеет вид F(x1,x2,...xN) = 0.
        /// </summary>
        public List<Func<double[], double[], double>> EquationFunctions { get; set; }
        /// <summary>
        /// Коэффициенты в уравнениях системы.
        /// </summary>
        public List<double[]> EquationsCoefficients { get; set; }
    }

about the course of the case, he encountered the need to solve systems of equations of the same type. This is how, for example, the function itself looks like, which determines the appearance of the equation:
static double EquationFunction(double[] x, double[] beta, int inxX)
{
            double equationValue = 0.0;

            int qVars= x.Length;

            equationValue = beta[0] + beta[1] * x[inxX] + (beta[2] / (qVars-1)) * (x.Sum() - x[inxX]);

            return equationValue;
}

And this is how a fragment of a function looks like, where a system of equations is created:
static EquationsSystem CreateEquationsSystem(List<double[]> lstCoeffsInEquations)
        {
            int qEquations = lstCoeffsInEquations.Count;
            int qCoeffs = lstCoeffsInEquations[0].Length;

            EquationsSystem system = new EquationsSystem()
            {
                EquationFunctions = new List<Func<double[], double[], double>>(),
                EquationsCoefficients = new List<double[]>(),
            };          

            for (int i = 0; i < qEquations; i++)
            {
                system.EquationFunctions.Add(new Func<double[], double[], double>((x, beta) =>
                EquationFunction(x, beta, i));
            }      

            for (int i = 0; i < qEquations; i++)
            {
                system.EquationsCoefficients.Add(new double[qCoeffs]);
                for (int j = 0; j < qCoeffs; j++)
                {
                    system.EquationsCoefficients[i][j] = lstCoeffsInEquations[i][j];
                }
            }
            
            return system;
        }

There are 4 equations in the system, each of which is described by a function like the one above.
There are no difficulties in the process of creating a system. But at the moment when it is necessary to perform numerical differentiation of these functions (for the matrix of first derivatives, which is built at each iteration of the solution), the program falls into heresy. Here is a function that performs the calculation of the derivative:
public static double GetDerivative(Func<double[], double[], double> function, double[] variables, int inxVariable, double[] coefficients, double eps)
        {
            ...
            //Остальная часть не важна
            double f = function(variables, coefficients);
            ...
 
        }

At this very place, the program tries to calculate the value of the function and throws an IndexOutOfRangeException error. Judging by the data in the Call Stack panel, it again jumps into the CreateEquationsSystem() function here:
...
for (int i = 0; i < qEquations; i++)
            {
                system.EquationFunctions.Add(new Func<double[], double[], double>((x, beta) =>
                EquationFunction(x, beta, i));
            }     
...
,
then into the EquationFunction() function:
static double EquationFunction(double[] x, double[] beta, int inxX)
{
            double equationValue = 0.0;

            int qVars= x.Length;

            equationValue = beta[0] + beta[1] * x[inxX] + (beta[2] / (qVars-1)) * (x.Sum() - x[inxX]);

            return equationValue;
}

and throws an error there. Given that I have 4 equations, inxX for all calculations should change from 0 to 3 and nothing else. But the program thinks that at this moment inxX is equal to 4 there and sends me to the forest about this.
Accordingly, 2 questions:
- how did it happen?
- how to solve the problem? After all, there can actually be as many equations as you like, without adding each manually separately.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
Maa-Kut, 2016-09-21
@skosterin88

Very similar to the problem of improper use of closures. Try like this:

for (int i = 0; i < qEquations; i++)
{
    int index = i;
    system.EquationFunctions.Add(new Func<double[], double[], double>((x, beta) =>
        EquationFunction(x, beta, index)); // <-- index вместо i
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question