コード例 #1
0
ファイル: FormMain.cs プロジェクト: Ring-r/opt
            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);
            }