Задание
Целью работы является изучение современной технологии разработки программ оптимизации, ориентированных на язык C++.
Реализовать на языке С++ программу оптимизации. Протестировать программу и сравнить результаты работы заданных методов оптимизации при использовании различных критериев окончания поиска и при задании различных значений погрешности локализации минимума. Сделать выводы.
Спецификация программы
Программа построена таким образом, чтобы пользователь имел возможность оказывать определяющее воздействие на ход выполнения программы и алгоритмы поиска решений. Для этого в основной функции, решающей задачу нахождения минимума выбранной функции, реализована возможность определения максимального количества итераций, определения интересующей точности вычислений. В программе предусмотрена возможность повторного запуска процесса вычисления с корректирующими значениями начальной точки, максимального количества итераций и интересующей точности.
Основным объектом, которым пользуются все функции программы, является объект «Вектор», который представлен в программе классом Vector. В классе реализованы все процедуры обработки объектов класса Vector, необходимые для работы программы. Основная расчетная функция возвращает именно объект класса Vector.
В программе пользователю предоставляется возможность выбрать тестовую функцию по своему усмотрению.
Текст программы
#include <iostream.h>
#include <math.h>
class vector
{
private:
int num, fun, d;
double x[5], p[5], step, l;
public:
vector();
void InputDot(int n, int fun1, int def);
void PassInfo();
double Function(double k);
double Differential(int n, double k);
void Gradient(int n);
double CreateStep();
void OutResult();
};
vector::vector() // "Пустой" вектор
{
for (int i=0; i<5; i++)
{
x[i]=0;
p[i]=0;
}
step=0; // Шаг
l=0; // Длина
fun=0; // Функция для работы еще не выбрана
}
void vector::InputDot(int n, int fun1, int def) // Задаем начальную точку
{
cout<<"Enter coordinates of an index point\n";
for (int i=0; i<n; i++)
{
cout<<"x["<<i<<"] :";
cin>>x[i];
}
num=n;// Запоминаем с каким количеством переменных работаем
fun=fun1; // Фиксируем номер выбранной функции
d=def; // Выбранный тип дифференцирования
}
void vector::PassInfo() //Новая координата вектора, образованная путем смещения
{
for (int i=0; i<num; i++) // Уже знаем кол-во переменных
{
x[i]=x[i]+step*p[i]; // Уже знаем значение step
}
}
double vector::Function(double k) // Меню выбора тестовой функции
{
switch(fun)
{
case 1:
return (x[0]+k*p[0])*(x[0]+k*p[0])+2*(x[1]+k*p[1])*(x[1]+k*p[1])-2*(x[0]+k*p[0])*(x[1]+k*p[1])+(x[1]+k*p[1]);
break;
case 2:
return (x[0]+k*p[0]-1)*(x[0]+k*p[0]-1)+(x[1]+k*p[1]-3)*(x[1]+k*p[1]-3)+4*(x[2]+k*p[2]+5)*(x[2]+k*p[2]+5);
break;
case 3:
return 100*((x[1]+k*p[1])-(x[0]+k*p[0])*(x[0]+k*p[0]))*((x[1]+k*p[1])-(x[0]+k*p[0])*(x[0]+k*p[0]))+(1-(x[0]+k*p[0]))*(1-(x[0]+k*p[0]));
break;
default:
return 0;
}
}
double vector::Differential(int n, double k) //Частные производные функции
{
double x1, h=0.0000001, d1, d2; // Потребуется для численного дифференцирования
if(d==1) // Аналитический тип дифференцирования
{
switch(fun) // в зависимости от номера функции
{
case 1:
switch(n) // в зависимости от переменной, по которой дифференцируют
{
case 0:
return 2*((x[0]+k*p[0])-(x[1]+k*p[1]));
case 1:
return 4*(x[1]+k*p[1])-2*(x[0]+k*p[0])+1;
default:
return 0;
}
case 2:
switch(n) // в зависимости от переменной, по которой дифференцируют
{
case 0:
return 2*(x[0]+k*p[0]-1);
case 1:
return 2*(x[1]+k*p[1]-3);
case 2:
return 8*(x[2]+k*p[2]+5);
default:
return 0;
}
case 3:
switch(n) // в зависимости от переменной, по которой дифференцируют
{
case 0:
return -400*((x[1]+k*p[1])-(x[0]+k*p[0])*(x[0]+k*p[0]))-2*(1-(x[0]+k*p[0]));
case 1:
return 200*((x[1]+k*p[1])-(x[0]+k*p[0])*(x[0]+k*p[0]));
default:
return 0;
}
default:
return 0;
}
}
else // Численное дифференцирование
{
x1=x[n]; // Переменную, по которой дифференцируем, обзываем x1
x[n]=x[n]-h;
d1=Function(0);
x[n]=x[n]+2*h;
d2=Function(0);
x[n]=x1;
return (d1+d2)/2*h;
}
}
void vector::Gradient(int n) //Градиент - вектор из частных производных
{
for(int i=0; i<num; i++)
{
if(i==n)
p[i]=Differential(i,0);
else
p[i]=0;
}
}
double vector::CreateStep() // Получим step - результат одномерной минимизации
{
double h1,x_1,x_2,a,b,n,e;
int k=0;
h1=0.01;
x_1=h1;
if(Function(0)<Function(x_1)) // Метод Свенна
{
h1=-h1;
x_1=h1;
}
do
{
h1=2*h1;
x_1=x_1+h1;
}
while(Function(x_1-h1)>Function(x_1));
a=x_1-1.5*h1; // Получили отрезок
b=x_1;
if(a>b) // Для удобства переименовали границы
{
n=a;
a=b;
b=n;
}
e=0.001;
x_1=a+0.618*fabs(b-a); // Локализуем минимум методом Золотого Сечения 2
do
{
x_2=a+b-x_1;
if((x_1<x_2)&&(Function(x_1)<Function(x_2)))
b=x_2;
if((x_1<x_2)&&(Function(x_1)>=Function(x_2)))
{
a=x_1;
x_1=x_2;
}
if((x_1>x_2)&&(Function(x_1)<Function(x_2)))
a=x_2;
if((x_1>x_2)&&(Function(x_1)>=Function(x_2)))
{
b=x_1;
x_1=x_2;
}
k++;
}
while((fabs(b-a)>e)&&(k<200));
step=(a+b)/2; // Найденый минимум
return step;
}
void vector::OutResult() // Вывод результата на экран
{
cout<<"The following coordinates of a point of a minimum are received:\n";
for(int i=0;i<num;i++)
{
cout<<x[i]<<" ";
}
cout<<'\n';
}
void main()
{
vector X;
double e, s;
int k=0, M, i, number, flag=1, fun1, def;
cout<<"1 - x1^2 + 2*x2^2 - 2*x1*x2 + x2 \n";
cout<<"2 - (x1-1)^2+(x2-3)^2+4*(x3+5)^2 \n";
cout<<"3 - 100*(x2-x1^2)^2+(1-x1)^2\n";
cout<<"Enter number of function: ";
cin>>fun1;
switch(fun1)
{
case 1:
number=2;
break;
case 2:
number=3;
break;
case 3:
number=2;
break;
default:
number=0;
break;
}
cout<<"Enter accuracy for criterion of the ending of search: e=";
cin>>e;
cout<<"Set restrictions on amount of iterations: M=";
cin>>M;
cout<<"Enter type of differentiation:\n";
cout<<"1 - Analytical\n";
cout<<"2 - Numerical\n";
cin>>def;
X.InputDot(number, fun1, def);
do
{
for(i=0; i<number; i++)
{
X.Gradient(i);
s=X.CreateStep();
X.PassInfo();
}
k++;
}
while((fabs(X.Function(0)-X.Function(-s))>=e)&&(k<M)); //Главным образом, здесь е влияет на результат
cout<<"Quantity of the executed steps: "<<k<<'\n';
X.OutResult();
}