private void miStepLocalSearch_Click(object sender, EventArgs e) { int n = placed_circles.Count; #region Создание и заполнение вектора размещения P (2*n+1 x 1). Matrix P = new Matrix(2 * n + 1); for (int i = 0; i < placed_circles.Count; i++) { P[2 * i] = placed_circles[i].X; P[2 * i + 1] = placed_circles[i].Y; } P[2 * n] = length; #endregion #region Создание вектора градиента G (2*n+1 x 1). Matrix G = new Matrix(2 * n + 1); G[G.RowCount - 1] = 1; #endregion #region Создание и заполнение матрицы активных ограничений a (!2*n+1! x 2*n+1). Matrix A = new Matrix(0, 2 * n + 1); Matrix B = new Matrix(0, 2); #region Активные ограничения по полосе. for (int i = 0; i < placed_circles.Count; i++) { if (placed_circles[i].Y + placed_circles[i].R == height) { A.AddRow(); A[A.RowCount - 1, 2 * i + 1] = -1; B.AddRow(); B[B.RowCount - 1, 0] = -1; B[B.RowCount - 1, 1] = i; } if (placed_circles[i].X - placed_circles[i].R == 0) { A.AddRow(); A[A.RowCount - 1, 2 * i] = 1; B.AddRow(); B[B.RowCount - 1, 0] = -2; B[B.RowCount - 1, 1] = i; } if (placed_circles[i].Y - placed_circles[i].R == 0) { A.AddRow(); A[A.RowCount - 1, 2 * i + 1] = 1; B.AddRow(); B[B.RowCount - 1, 0] = -3; B[B.RowCount - 1, 1] = i; } if (placed_circles[i].X + placed_circles[i].R == length) { A.AddRow(); A[A.RowCount - 1, 2 * i] = -1; A[A.RowCount - 1, 2 * n] = 1; B.AddRow(); B[B.RowCount - 1, 0] = -4; B[B.RowCount - 1, 1] = i; } } #endregion #region Активные ограничения между кругами. for (int i = 0; i < placed_circles.Count - 1; i++) for (int j = i + 1; j < placed_circles.Count; j++) { if (Math.Abs(ExtendedDistance.Calc(placed_circles[i], placed_circles[j])) < 0.0001) { A.AddRow(); A[A.RowCount - 1, 2 * i] = 2 * (placed_circles[i].X - placed_circles[j].X); A[A.RowCount - 1, 2 * i + 1] = 2 * (placed_circles[i].Y - placed_circles[j].Y); A[A.RowCount - 1, 2 * j] = 2 * (placed_circles[j].X - placed_circles[i].X); A[A.RowCount - 1, 2 * j + 1] = 2 * (placed_circles[j].Y - placed_circles[i].Y); B.AddRow(); B[B.RowCount - 1, 0] = i; B[B.RowCount - 1, 1] = j; } } #endregion #endregion bool is_exit = false; do { Matrix ATr = A.Tr(); Matrix AOb = (A * ATr).Ob(); #region Рассчитать вектор множетелей Лагранжа U. Matrix U = AOb * A * G; #endregion #region Получить вектор направления d (2*n+1 x 1). Matrix D = ATr * U - G; #endregion if (D.IsNull(0.0001)) { int index = U.RowOfMinElement(); if (U[index] < -1e-8) { A.DelRow(index); B.DelRow(index); } else is_exit = true; } else { #region Находим длину шага L и соответствующее ему ограничение, которое добавляем в A. double L = double.PositiveInfinity; Matrix T; double td; double l; for (int i = 0; i < placed_circles.Count; i++) { T = new Matrix(1, 2 * n + 1); T[0, 2 * i + 1] = -1; td = (T * D)[0]; if (td < -1e-8) { l = -((T * P)[0] + height - placed_circles[i].R) / td; if (L > l) L = l; } T = new Matrix(1, 2 * n + 1); T[0, 2 * i] = 1; td = (T * D)[0]; if (td < -1e-8) { l = -((T * P)[0] - placed_circles[i].R) / td; if (L > l) L = l; } T = new Matrix(1, 2 * n + 1); T[0, 2 * i + 1] = 1; td = (T * D)[0]; if (td < -1e-8) { l = -((T * P)[0] - placed_circles[i].R) / td; if (L > l) L = l; } T = new Matrix(1, 2 * n + 1); T[0, 2 * i] = -1; T[0, 2 * n] = 1; td = (T * D)[0]; if (td < -1e-8) { l = -((T * P)[0] - placed_circles[i].R) / td; if (L > l) L = l; } } #endregion P += D * L; #region Проверить активные ограничения и удалить лишние. #endregion } } while (!is_exit); }