Лабораторная работа №7 / 7
.docЦель работы
Изучение методов переменной метрики и разработка программы, удовлетворяющей требованиям лабораторной работы 5.
В программе использовать метод Пирсона-3.
Тестовые функции:
1) (x1x2x3 – 1)2 + 5[x3(x1 + x2) – 2]2 + 2(x1 + x2 + x3 – 3)2 , начальная точка (x1)t = (-1; -1; -1), истинный минимум (x*)t = (1; 1; 1);
2) 0.1(12 + x12 + (1 + x22)/x12 + (x12x22 + 100)/(x14x24)) , начальная точка (x1)t = (0.5; 0.5),
истинный минимум (x*)t = (1.743; 2.036);
Краткое описание метода оптимизации
Суть методов переменной метрики заключается в введении некоторой матрицы Ак , корректирующей направление поиска. (Рк = Акyк) Создается серия квазиньютоновских направлений pk (k=1,…,n), где n число переменных, минимизируемой функции. Доказано, что если функция квадратичная n-порядка, то минимум из любой точки Х1 отыскивается не более чем за n итераций. Для произвольных функций из-за накопления погрешности при вычислении градиента у матрицы А перестает выполняться условие положительной определенности, что вызывает искажение аппроксимации и вынуждает периодически через n шагов прибегать к процедуре рестарта.
Начальный этап:
Установить значение счетчика к=1;
Задать точность вычислений е=10-4 – 10-7
Задать начальную точку Х;
Основной этап:
Шаг 1: Построить квазиньютоновское направление:
Для метода Пирсона-3:
Шаг 2: Найти αk, по направлению pk, как результат одномерной минимизации.
Шаг 3: Положить к=к+1 и перейти в новую точку xk+1= xk+ αk * pk
Шаг 4: Проверить критерий окончания поиска ||||<e;
Если выполняется, то минимум найден Хмин= Хк , иначе перейти на шаг 1.
Выводы
В результате проведения работы была создана программа, способная находить минимум функции с помощью метода Пирсона-3, а также были получены навыки объектно-ориентированного программирования на языке С++.
Ответы на контрольные вопросы
1. Выполнить 2 шага аналитического решения задачи Вашего варианта задания.
2. Сравнить методы переменной метрики.
Все методы переменной метрики отличаются только способом нахождения матрицы А.. Метод БФШ менее остальных нуждается в обновлении направлений.А для метода ДФП точность важна и по этому у необходимо вычислять как можно точнее, например сочетать методы Больцана и Давидона или методы золотого сечения и ДСК.
3. Какие алгоритмы линейного поиска рекомендуют для применения в программах, реализующих квазиньютоновские методы?
Рекомендуется сочетать успешно «стартующие» и хорошо «финиширующие» методы, например, методы Больцана и Давидона или методы золотого сечения и ДСК.
4. Как выбирается начальная матрица A1 в методе ДФП? Что такое процедура рестарта, зачем она нужна?
Матрица A1 – любая симметричная матрица >0, удобно выбирать матрицу Е. В дальнейшем матрицы А определяются с учетом предыдущих матриц до n-го шага. На n шагу необходимо проводить пересчет поискового направления и приравнивать матрицу А матрице Е. Это необходимо из-за накопления погрешности при вычислении у из-за чего перестает выполняться условие положительности матрицы А. В случае, если минимизируется квадратичная функция, процедура рестарта не нужна, так как минимум будет найден менее чем за n шагов.
Текст программы
#include "stdafx.h"
int c;
class Pirson
{
private: double eps;
double Xo[3];
double p[3];
double A[3][3];
double ag[3];
public: double Function (double);
void Init(double,double,double);
double DifFunction (double);
void AntiGradient ();
double Swenn4 (int);//TIL
double Bolcano (void);//min in direction
double Alpha (double, double);
void Pirson3 (void);
void Output();};
int main(int argc, char* argv[])
{
Pirson Obj;
c=1;
cout<<"\t\t\t Laboratory work #7"<<"\n"<<endl;
cout<<"\t\t\t Pearson's method #3"<<"\n"<<endl;
cout<<"Function1:0.1(12+x1^2+(1+x2^2)/x1^2+(x1^2*x2^2+100)/(x1^4*x2^4))"<<endl;
Obj.Init(0.5,0.5,0);Obj.Pirson3();Obj.Output();
cout<<"True minimum:(1.743;2.036)"<<endl;
c=2;
cout<<"\nFunction2:(x1x2x3 -1)^2+5[x3(x1+x2)-2]^2+2(x1+x2+x3-3)^2"<<endl;
Obj.Init(-1,-1,-1);Obj.Pirson3();Obj.Output();
cout<<"True minimum:(1;1;1)"<<endl;
cin.get();
return 0;
}
double Pirson::Function(double a)
{
double res;
double x[3]={Xo[0] + a*p[0], Xo[1] + a*p[1], Xo[2] + a*p[2]};
if(c==1)
res=0.1*(12+x[0]*x[0]+(1+x[1]*x[1])/(x[0]*x[0])+(x[0]*x[0]*x[1]*x[1]+100)/(x[0]*x[0]*x[0]*x[0]*x[1]*x[1]*x[1]*x[1]));
else
res=(x[0]*x[1]*x[2]-1)*(x[0]*x[1]*x[2]-1)+5*(x[2]*(x[0]+x[1])-2)*(x[2]*(x[0]+x[1])-2)+2*(x[0]+x[1]+x[2]-3)*(x[0]+x[1]+x[2]-3);
return(res);
}
void Pirson::Init(double x1, double x2, double x3)
{
eps = 0.00000001; Xo[0]=x1;Xo[1]=x2;Xo[2]=x3;
}
double Pirson::DifFunction(double x)
{
double res;
res = (Function(x+eps) - Function(x))/eps;
return(res);
}
double Pirson::Swenn4(int i)
{
double a = 0.0001,m,n,x=0;
if (DifFunction(x) > 0)
{
p[0]= -p[0];p[1]= -p[1];
}
do
{
a = 2*a;x += a;
}
while(DifFunction(x-a)*DifFunction(x)>0);
m = x-a; n = x;
if (i == 1)
return(m);
else
return(n);
}
double Pirson::Bolcano()
{
double x, K = 1, L, A, B;
A = Swenn4(1);
B = Swenn4(2);L = B - A;x = (A + B)/2;
while((fabs(DifFunction(x)) > eps) || (L > eps))
{
if (DifFunction(x) < 0)
A = x;
else
B = x;
L = B - A;x = (A + B)/2;K++;
}
return(x);
}
void Pirson::AntiGradient()
{
if(c==1)
{
p[0] = -(0.2/(Xo[0]*Xo[0]*Xo[0]*Xo[1]*Xo[1])-(0.4*(Xo[0]*Xo[0]*Xo[1]*Xo[1]+100))/(Xo[0]*Xo[0]*Xo[0]*Xo[0]*Xo[0]*Xo[1]*Xo[1]*Xo[1]*Xo[1])+0.2*Xo[0]-0.2*(1+Xo[1]*Xo[1])/(Xo[0]*Xo[0]*Xo[0]));
p[1] = -(0.2/(Xo[0]*Xo[0]*Xo[1]*Xo[1]*Xo[1])-(0.4*(Xo[0]*Xo[0]*Xo[1]*Xo[1]+100))/(Xo[0]*Xo[0]*Xo[0]*Xo[0]*Xo[1]*Xo[1]*Xo[1]*Xo[1]*Xo[1])+0.2*Xo[1]/(Xo[0]*Xo[0]));
}
else
{
p[0] = -(2*(Xo[0]*Xo[1]*Xo[2]-1)*Xo[1]*Xo[2]+10*(Xo[0]*Xo[2]+Xo[1]*Xo[2]-2)*Xo[2]+4*Xo[0]+4*Xo[1]+4*Xo[2]-12);
p[1] = -(2*(Xo[0]*Xo[1]*Xo[2]-1)*Xo[0]*Xo[2]+10*(Xo[0]*Xo[2]+Xo[1]*Xo[2]-2)*Xo[2]+4*Xo[0]+4*Xo[1]+4*Xo[2]-12);
p[2] = -(2*(Xo[0]*Xo[1]*Xo[2]-1)*Xo[0]*Xo[1]+10*(Xo[0]*Xo[2]+Xo[1]*Xo[2]-2)*(Xo[0]+Xo[1])+4*Xo[0]+4*Xo[1]+4*Xo[2]-12);
}
}
double Pirson::Alpha(double x,double y)
{
double res;
res = sqrt(x*x + y*y);
return(res);
}
void Pirson::Pirson3()
{
int i,j;
int k = 1;
double Min,gamma[3],s[3],x[3],xs[3];
for(i=0;i<3;i++)
for (j=0;j<3;j++)
{
if(i==j)
{
A[i][j]= -1;
}
else
{
A[i][j]=0;
}
}
for(i=0;i<3;i++)
x[i]=Xo[i];
do
{
AntiGradient();
for(i=0;i<3;i++)
ag[i] = p[i];
for(i=0;i<3;i++)
gamma[i]=gamma[i] - ag[i];
if(k==1||k==3||k==5)
{
for(i=0;i<2;i++)
for(j=0;j<2;j++)
if(i==j)
{
A[i][j] = 1;
}
else
{
A[i][j] = 0;
}
}
else
{
for(i=0;i<2;i++)
s[i]=A[i][0]*gamma[0]+A[i][1]*gamma[1];
for(i=0;i<3;i++)
xs[i]=x[i] - s[i];
for(i=0;i<2;i++)
for(j=0;j<2;j++)
A[i][j]=A[i][j]+xs[i]*s[j]/(s[0]*gamma[0]+s[1]*gamma[1]);
for(i=0;i<2;i++)
p[i] = A[i][0]*ag[0]+A[i][1]*ag[1];
}
for(i=0;i<3;i++)
gamma[i]=ag[i];
for(i=0;i<2;i++)
x[i]=Xo[i];
Min=Bolcano();
Xo[0] += Min*p[0]; Xo[1] += Min*p[1]; Xo[2] += Min*p[2];
for(i=0;i<2;i++)
x[i]=Xo[i] - x[i];
k++;
}
while (Alpha (x[0], x[1]) > eps && Alpha (ag[0],ag[1]) > eps);
}
void Pirson::Output()
{
if(c==1)
cout<<"Min=("<<Xo[0]<<","<<Xo[1]<<")"<<endl;
else
cout<<"Min=("<<Xo[0]<<","<<Xo[1]<<","<<Xo[2]<<")"<<endl;
}
Спецификация программы.
Входные данные: начальная точка, погрешность,исходная функция.
Выходные данные: значение минимума.
Спецификация функций программы.
double Function(double) –возвращает значение функции.
double DifFunction(double) – вычисление значения производной в точке.
double Swenn(int) – нахождение ТИЛ.
double Boltsano() – нахождение минимума в заданном напрвлении.
void AntiGradient() – вычисление антиградиента.
double Alpha(double, double) – вычисление нормы вектора.
void Pirson3() – реализация метода Пирсон-3.
void Init(double,double,double) – инициализация.
void Output() – вывод минимума.
Результат выполнения программы.
Схема алгоритма Пирсон-3