/// <summary>
 /// Симплексная таблица в каноническом виде
 /// </summary>
 /// <param name="x_i">вектор номеров базисных элементов</param>
 /// <param name="c_j">коефициенты при неизвестных в целевой функции</param>
 /// <param name="equationSystem">ситема уравнений</param>
 /// <param name="b">вектор свободных членов</param>
 public CanonicalSimplexTable(int[] x_i, SimplexNumber[] c_j, double[,] equationSystem, double[] b)
 {
     //сохраняем номера базисных переменых
     X_I = x_i;
     //создаем симплекс-таблицу
     SimplexTable = new SimplexNumber[equationSystem.GetLength(0)+1, equationSystem.GetLength(1)+1];
     //добавляем в таблицу a_ij
     for (int i = 0; i < equationSystem.GetLength(0); i++)
         for (int j = 0; j < equationSystem.GetLength(1); j++)
             SimplexTable[i, j] = new SimplexNumber(equationSystem[i, j]);
     //... b_i
     for (int i = 0; i < b.Length; i++)
         SimplexTable[i, equationSystem.GetLength(1)] = new SimplexNumber(b[i]);
     //... delta_j
     for (int j = 0; j < equationSystem.GetLength(1); j++)
     {
         SimplexTable[equationSystem.GetLength(0), j] = -c_j[j];
         for (int i = 0; i < equationSystem.GetLength(0); i++)
             SimplexTable[equationSystem.GetLength(0), j] += c_j[x_i[i]] * SimplexTable[i, j];
     }
     //... Z(b_i)
     for (int i = 0; i < b.Length; i++)
         SimplexTable[equationSystem.GetLength(0), equationSystem.GetLength(1)] += c_j[x_i[i]] * b[i];
 }
        /// <summary>
        /// находит значения независимых переменных при которых целевая функция максимизируется
        /// </summary>
        public void Maximize(bool showSteps = true)
        {
            while (true) {
                bool rowWasFound = false;
                bool colWasFound = false;
                //отображаем текущее состояние если нужно
                if (showSteps)
                {
                    ShowTable(DisplayMode.InConsole);
                    Console.WriteLine();
                }
                //находим номер столбца с отрицательной delta
                int col_min = 0;
                for (int j = 0; j < SimplexTable.GetLength(1) - 1; j++)
                    if (SimplexTable[SimplexTable.GetLength(0) - 1, j].Round(roundTo) < 0 && SimplexTable[SimplexTable.GetLength(0) - 1, j] <= SimplexTable[SimplexTable.GetLength(0) - 1, col_min])
                    {
                        var t = SimplexTable[SimplexTable.GetLength(0) - 1, j];
                        var vg = SimplexTable[SimplexTable.GetLength(0) - 1, j].Round(roundTo) < 0;
                        col_min = j;
                        colWasFound = true;
                    }
                //если полученая на предыдущем шаге таблица оптимальна выводим результат и выходим из функции
                if (!colWasFound)
                {
                    SimplexNumber[] rez = new SimplexNumber[SimplexTable.GetLength(1)-1];
                    for (int j = 0; j < SimplexTable.GetLength(1)-1; j++)
                    {
                        int k = -1;
                        for (int i = 0; i < X_I.Length; i++)
                        {
                            if (X_I[i] == j)
                                k = i;
                        }
                        rez[j] = k == -1 ? new SimplexNumber(0) : SimplexTable[k, SimplexTable.GetLength(1) - 1].Round(4);
                    }
                    MessageBox.Show("Целевая функция имеет максимум при X=(" + String.Join("; ",rez) + "), при этом Z(X)=" + SimplexTable[SimplexTable.GetLength(0) - 1, SimplexTable.GetLength(1) - 1] + ".", "Вот так вот!", MessageBoxButtons.OK);
                    return;
                }

                //находим номер строки с минимальной b_i/a_is
                int row_min = 0;
                for (int i = 0; i < SimplexTable.GetLength(0) - 1; i++)
                {
                    if (SimplexTable[i, col_min].Round(roundTo) > 0 && (SimplexTable[i, SimplexTable.GetLength(1) - 1] / SimplexTable[i, col_min] <= SimplexTable[row_min, SimplexTable.GetLength(1) - 1] / SimplexTable[row_min, col_min] || SimplexTable[row_min, col_min].Round(roundTo)<=0))
                    {
                        row_min = i;
                        rowWasFound = true;
                    }
                }
                //если все a_is не положительны выводим соответствующее сообщение
                if (!rowWasFound)
                {
                    MessageBox.Show("Функция неограничена в даной области решений.", "Вот так вот!", MessageBoxButtons.OK);
                    return;
                }
                //в противном случае делаем еще один шаг
                MakeStep(row_min,col_min);
            }
        }
 /// <summary>
 /// выполняет одну итерацию симплекс-метода
 /// </summary>
 /// <param name="row_min">номер строки разрешающего элемента</param>
 /// <param name="col_min">номер столбца разрешающего элемента</param>
 public void MakeStep(int row_min, int col_min)
 {
     SimplexNumber[,] newSimplexTable = new SimplexNumber[SimplexTable.GetLength(0), SimplexTable.GetLength(1)];
     //выполняем одну итерацию симплексного метода
     SimplexNumber rElement = SimplexTable[row_min, col_min];
     for (int i = 0; i < SimplexTable.GetLength(0); i++)
         for (int j = 0; j < SimplexTable.GetLength(1); j++)
         {
             if (i == row_min)
             {
                 newSimplexTable[i, j] = SimplexTable[i, j] / rElement;
                 continue;
             }
             newSimplexTable[i, j] = SimplexTable[i, j] - SimplexTable[row_min, j] * SimplexTable[i, col_min] / rElement;//from caet
         }
     //устанавливаем новый базис
     X_I[row_min] = col_min;
     //фиксируем полученый результат
     SimplexTable = newSimplexTable;
 }