Добавил:
Studfiles2
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Оптимизация в САПР / Malgin_kurs / METODI
.cpp#include "stdafx.h"
#include "Malgin_kurs.h"
#include "METODI.h"
#include "Matrix.h"
#include <math.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// Обычный констуктор по умолчанию
CMETODI::CMETODI(
CString str) // строка с формулой
{
sFormula=str; // присваивыем члену класса значение фармулы
sFormula.MakeUpper(); // делаем все буквы заглавными
a=.0; // обнуляем а
b=.0; // обнуляем b
alpha=.0; // обнуляем alpha - коэффициент удлинения вектора
}
// Деструктор
CMETODI::~CMETODI()
{
}
// Возвращение значения функции в заданной точке
double CMETODI::f(
CMatrix &x) // точка
{
CString m_strFormulainput; // формула в виде строки
m_strFormulainput=sFormula; // присваиваем значение формулы
for (int i=1; i<=x.getSizeRow(); i++) // заменяем все аргументы на соответствующие
m_strFormulainput.Replace("X"+Int_To_String(i),Double_To_String(x(i,1))); // числовые значения
return EnterFunction.Vichislenie(m_strFormulainput);
}
// Норма вектора или матрицы
double CMETODI::norma(
CMatrix &x) // матрица-аргумент
{
double res=0; // текущая сумма квадратов элементов
int m=x.getSizeRow(), // количество строк
n=x.getSizeCol(); // количество столбцов
for(int i=1; i<=m; i++) // последовательно находим
{ // сумму квадратов
for(int j=1; j<=n; j++) // всех элементов
{ // матрицы
res+=x(i,j)*x(i,j);
}
}
return sqrt(res); // возвращае корень из суммы квадратов
}
// Производная (градиент) функции
CMatrix CMETODI::df(
CMatrix &x) // матрица-аргумент
{
CMatrix res(x); // временная матрица-результат
// CMatrix ort(x); // временная матрица-орт
CMatrix xl(x),xr(x);
double h=0.000001; // приращение
// ort=ort.setNull(); // обнуляем орт
for(int i=1;i<=x.getSizeRow();i++) // численно вычисляем
{ // производную в
/*
ort[i]=1; // соответствии с
res[i]=(f(x+h*ort)-f(x-h*ort))/(2*h); // формулой центральной
ort[i]=0; // конечной разности
*/
xl[i]+=h;
xr[i]-=h;
res[i]=(f(xl)-f(xr))/(2*h);
xl[i]-=h;
xr[i]+=h;
}
return res; // возвращаем результат
}
//--------------------------------------------------------------------
// Производная функции по направлению
//--------------------------------------------------------------------
double CMETODI::dfp(
CMatrix x, // точка
CMatrix p) // направление
{
if(x.getSizeRow()==p.getSizeRow() && // проверяем соответствие
x.getSizeCol()==p.getSizeCol()) // размерностей матрицы направления
{ // и матрицы точки
CMatrix res(1,1); // результирующая матрица-число
x=df(x); // вычисляем производную (градиент) в точке
res=x.getTranspose()*p; // находим производную по направлению
// в соответствии с алгоритмом
return res(1,1); // возвращаем результат
}
else
return 0; // при ошибке возвращаем 0
}
// Вторая производная функции
double CMETODI::d2f(
CMatrix &x, // точка
int i, // номер производной по первой переменной
int j) // номер производной по второй переменной
{
/* Вторая производная вычисляется по следующей формуле:
f(x+hi*ei+hj*ej)-f(x+hi*ei)-f(x+hj*ej)+f(x)
-------------------------------------------
hi*hj
*/
double h=0.00001; // приращение
CMatrix e_i(x), // первый орт
e_j(x); // второй орт
e_i.setNull(); // обнуляем первый орт
e_j.setNull(); // обнуляем второй орт
e_i[i]=h; // присваиваем i-ой координате первого орта значение 1
e_j[j]=h; // присваиваем j-ой координате второго орта значение 1
// возвращаем полученное значение второй производной
//return (f(x+h*e_i+h*e_j)-f(x+h*e_i)-f(x+h*e_j)+f(x))/(h*h);
return (f(x+e_i+e_j)-f(x+e_i)-f(x+e_j)+f(x))/(h*h);
}
//--------------------------------------------------------------------
// Поиск числа Фибоначчи
//--------------------------------------------------------------------
double CMETODI::Fib(
double x) // номер числа
{
double s, // итоговое число
tmp; // временная переменная
if(x>=1) // проверяем условие существования числа
{
s=1; // сумма = 1
tmp=0; // обнуляем временныю переменную
for(double k=0; k<x; k++)
{ // в соответствии с методов
s=s+tmp; // нахождения числа Фибоначчи
tmp = s-tmp; // осуществляем поиск
}
return s; // возвращаем результат
}
else
return 1; // если индекс меньше 1, возвращаем 1
}
//--------------------------------------------------------------------
// Матрица Гессе - матрица вторых производных
//--------------------------------------------------------------------
CMatrix CMETODI::hesse(
CMatrix &x) // точка
{
CMatrix res(x.getSizeRow(),x.getSizeRow()); // результирующая
// квадратная матрица
// т.к. матрица Гессе - это матрица вторых
// производных, то просто последовательно
// пробегаем по этой матрице, присваивая
// её элементам значения вторух производных
for (int i=1; i<=x.getSizeRow(); i++)
for (int j=1; j<=x.getSizeRow(); j++)
res(i,j)=d2f(x,i,j);
return res; // возвращаем результат
}
//--------------------------------------------------------------------
// Вычисление обратной матрицы методом Гаусса-Жордана
//--------------------------------------------------------------------
CMatrix CMETODI::inverseGJ(
CMatrix &cs) // матрица-аргумент
{
int n=cs.getSizeRow(); // число строк
CMatrix c(cs); // временная матрица-результат
// индексы обменяных строк
int *list_i1=new int[n]; assert(list_i1!=0);
int *list_i2=new int[n]; assert(list_i2!=0);
int lp=0;
// выбор ведущего элемента по столбцу
for(int k=1; k<=n; k++)
{
// поиск максимального по модулю элемента по столбцу
double max=-1e300;
int max_i=-1;
for(int i=k; i<=n; i++)
{
if(fabs(c(i,k))>max)
{
max=fabs(c(i,k));
max_i=i;
}
}
if(max_i==-1)
{
// "Ошибка: определитель равен нулю"
}
else
{
// если максимальный элемент не
// является диагональным - обмен строк
if(max_i!=k)
{
c.swapRow(k,max_i);
list_i1[lp]=k;
list_i2[lp]=max_i;
++lp;
}
}
// построение новой матрицы
double lead=c(k,k);
CMatrix lead_col(c.getCol(k)), lead_row(c.getRow(k));
c(k,k)=1./lead;
for(i=1; i<=n; i++)
{
if(i!=k)
{
c(i,k)=lead_col[i]/lead;
}
}
for(int j=1; j<=n; j++)
{
if(j!=k)
{
c(k,j)=-lead_row[j]/lead;
}
}
for(i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(i!=k && j!=k)
{
c(i,j)-=lead_col[i]/lead*lead_row[j];
}
}
}
}
// обмен столбцов
while(lp>0)
{
--lp;
int j1=list_i1[lp];
int j2=list_i2[lp];
c.swapCol(j1,j2);
}
delete [] list_i1;
delete [] list_i2;
return c; // возвращаем результат
}
//////////////////////////////////////////////////////////////////////
// Методы одномерной оптимизации
//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
// Выбор метода одномерной оптимизации
//--------------------------------------------------------------------
int CMETODI::FindAlpha(
CMatrix &x, // начальная точка
CMatrix &p, // направление поиска
double &e1, // погрешность
int &n) // номер метода
{
a=.0; // обнуляем а
b=.0; // обнуляем b
alpha=.0; // обнуляем alpha - коэффициент удлинения вектора
double e=e1*.001;
int k=0, // счётчик числа итераций
max_step=35; // максимальное количество шагов
k+=Swann(x,p); // локализация минимума методом Свенна
switch(n) // в соответствии с выбранным методом запускаем его
{
case 1: k+=Bolcano(x,p,e,max_step); // метод Больцано
break;
case 2: k+=ZS_1(x,p,e,max_step); // метод ЗС-1
break;
case 3: k+=ZS_2(x,p,e,max_step); // метод ЗС-2
break;
case 4: k+=Pauell_Odn(x,p,e,max_step); // метод Пауэлла
break;
case 5: k+=Davidon(x,p,e,max_step); // метод Давидона
break;
case 6: k+=Fibonachchi_1(x,p,e,max_step); // метод Фибоначчи-1
break;
case 7: k+=Fibonachchi_2(x,p,e,max_step); // метод Фибоначчи-2
break;
case 8: k+=ExIn(x,p,e,max_step); // метод кубической экстраполяции-интерполяции
break;
}
return k; // возвращаем число итераций
}
//--------------------------------------------------------------------
// Метод Свенна
//--------------------------------------------------------------------
int CMETODI::Swann(CMatrix &x,CMatrix &p)
{
double h = 0.1; // шаг
double la = 0; // значение функции
int k = 0; // счётчик числа итераций
if(dfp(x,p)>0) // если необходимо,
h=-h; // меням направление поиска
while(dfp(x+la*p,p)*dfp(x+(la+h)*p,p)>0) // сокращаем ТИЛ до начала
{ // возрастания функции
la += h; // изменяем значения функции
h = 2*h; // удваиваем шаг
k++; // увеличиваем счётчик числа итераций
}
if(h<0) // проверяем направление поиска
{ // и в соответствии с ним
b = la; // присваиваем новые значения
a = la+h; // локализированного минимума
}
else
{
a = la;
b = la+h;
}
return k; // возвращаем число итераций
}
//--------------------------------------------------------------------
// Метод Больцано
//--------------------------------------------------------------------
int CMETODI::Bolcano(
CMatrix &x, // начальная точка
CMatrix &p, // направление поиска
double &e, // погрешность поиска
int &max_step) // максимальное количество итераций
{
int k=0; // устанавливаем счётчик числа итераций
// сокращаем ТИЛ до соответствующего условия
while((fabs(dfp(x+((a+b)/2)*p,p)))>e && fabs(b-a)>e && k<max_step)
{
k++; // увеличиваем счётчик итераций
if(dfp(x+((a+b)/2)*p,p)>0) // локализуем минимум
b=(a+b)/2; // в соответствии с
else // методом
a=(a+b)/2;
}
alpha = (a+b)/2; // изменяем значение коэффициента удлинения вектора
return k; // возвращаем количесво итераций
}
//--------------------------------------------------------------------
// Метод золотого сечения - 1
//--------------------------------------------------------------------
int CMETODI::ZS_1(
CMatrix &x, // начальная точка
CMatrix &p, // направление поиска
double &e, // погрешность поиска
int &max_step) // максимальное количество итераций
{
int k=0; // задаём счётчик числа итераций
double l = a+0.382*fabs(b-a); // выбираем первую точку
double m = a+0.618*fabs(b-a); // выбираем вторую точку
// сокращаем ТИЛ до соответствующего условия
while((fabs(dfp(x+((a+b)/2)*p,p)))>e && fabs(a-b)>e && k<max_step)
{
if(f(x+l*p)<f(x+m*p))
{
b = m;
m = l;
l = a+0.382*fabs(b-a);
}
else
{
a = l;
l = m;
m = a+0.618*fabs(b-a);
}
k++; // увеличиваем счётчик итераций
}
alpha = (a+b)/2; // изменяем значение коэффициента удлинения вектора
return k; // возвращаем количество итераций
}
//--------------------------------------------------------------------
// Метод золотого сечения - 2
//--------------------------------------------------------------------
int CMETODI::ZS_2(
CMatrix &x, // начальная точка
CMatrix &p, // направление поиска
double &e, // погрешность поиска
int &max_step) // максимальное количество итераций
{
int k=0; // задаём счётчик числа итераций
double x1 = a + 0.618*fabs(b-a); //выбираем первую точку
double x2 = a + b - x1; //выбираем вторую точку
// сокращаем ТИЛ до соответствующего условия
while((fabs(dfp(x+((a+b)/2)*p,p)))>e && fabs(a-b)>e && k<max_step)
{
if(f(x+x1*p) > f(x+x2*p))
{
if(x1 > x2)
b = x1;
else
a = x1;
x1 = a + 0.618*fabs(b-a);
}
else
{
if(x1 > x2)
a = x2;
else
b = x2;
x2 = a + b - x1;
}
k++; // увеличиваем счётчик итераций
}
alpha=(a+b)/2; // изменяем значение коэффициента удлинения вектора
return k; // возвращаем количество итераций
}
//--------------------------------------------------------------------
// Метод Пауэлла
//--------------------------------------------------------------------
int CMETODI::Pauell_Odn(
CMatrix &x, // начальная точка
CMatrix &p, // направление поиска
double &e, // погрешность поиска
int &max_step) // максимальное количество итераций
{
int k=0; // задаём счётчик числа итераций
double c=b,d; // задаём необходимые переменные
b=(a+c)/2; // определяем начальное значение b
// определяем начальное значение d
d=0.5*(f(x+a*p)*(b*b-c*c)+f(x+b*p)*(c*c-a*a)+f(x+c*p)*(a*a-b*b))/
(f(x+a*p)*(b-c)+f(x+b*p)*(c-a)+f(x+c*p)*(a-b));
// сокращаем ТИЛ до соответствующего условия
while((fabs((d-b)/fabs(b))>e) && (fabs((f(x+d*p)-f(x+b*p))/f(x+b*p))>e) && k<max_step)
{
if(f(x+b*p)>f(x+d*p))
{
if(b>d) // выбираем "лучшую" точку -
c=b; // которой соответствует наименьшее
else // значение функции, и, обозначив её как b
a=b; // рассматриваем 4 ситуации
b=d;
}
else
{
if(b>d)
c=d;
else
a=d;
}
// определяем значение d
d = 0.5*((f(x+a*p)-f(x+b*p))*(b-c)*(c-a))/
(f(x+a*p)*(b-c)+f(x+b*p)*(c-a)+f(x+c*p)*(a-b))+0.5*(a+b);
k++; // увеличиваем счётчик итераций
}
alpha=(b+d)/2; // изменяем значение коэффициента удлинения вектора
return k; // возвращаем количество итераций
}
//--------------------------------------------------------------------
// Метод Давидона
//--------------------------------------------------------------------
int CMETODI::Davidon(
CMatrix &x, // начальная точка
CMatrix &p, // направление поиска
double &e, // погрешность поиска
int &max_step) // максимальное количество итераций
{
int k=0; // задаём счётчик числа итераций
double z,w,r; // задаём необходимые переменные
if (a>b)
{
r=b;
b=a;
a=r;
}
// находим переменные в соответстви с методом
z=dfp(x+a*p,p)+dfp(x+b*p,p)+3*(f(x+a*p)-f(x+b*p))/(b-a);
w=sqrt(z*z-dfp(x+a*p,p)*dfp(x+b*p,p));
r=a+(b-a)*(z-dfp(x+a*p,p)+w)/(dfp(x+b*p,p)-dfp(x+a*p,p)+2*w);
// сокращаем ТИЛ до соответствующего условия
while((fabs(dfp(x+((a+b)/2)*p,p)))>e && fabs(a-b)>e && k<max_step && dfp(x+r*p,p)>e)
{
k++; // увеличиваем счётчик итераций
if(dfp(x+r*p,p)<0) // рассматриваем 2 ситуации
a=r;
else
b=r;
// находим переменные в соответстви с методом
z=dfp(x+a*p,p)+dfp(x+b*p,p)+3*(f(x+a*p)-f(x+b*p))/(b-a);
w=sqrt(z*z-dfp(x+a*p,p)*dfp(x+b*p,p));
r=a+(b-a)*(z-dfp(x+a*p,p)+w)/(dfp(x+b*p,p)-dfp(x+a*p,p)+2*w);
}
alpha=r/*(a+b)/2*/; // изменяем значение коэффициента удлинения вектора
return k; // возвращаем количество итераций
}
//--------------------------------------------------------------------
// Метод Фибоначчи-1
//--------------------------------------------------------------------
int CMETODI::Fibonachchi_1(
CMatrix &x, // начальная точка
CMatrix &p, // направление поиска
double &e, // погрешность поиска
int &max_step) // максимальное количество итераций
{
int k=0; // задаём счётчик числа итераций
double Ln=0.01*e; // задаём длину конечного интервала
double n=0; // порядковый номер числа Фибоначчи
while(Fib(n)<(b-a)/Ln) // определяем этот номер в
n++; // соответствии с алгоритмом
double l, m; // задаём необходимые переменные
l=a+(Fib(n-2)*(b-a))/(Fib(n)); // первая начальная точка
m=a+(Fib(n-1)*(b-a))/(Fib(n)); // вторая начальная точка
while(k<n-1) // сокращаем ТИЛ в соответствии с методом
{
if(f(x+l*p)<f(x+m*p))
{
b=m;
m=l;
l=a+(Fib(n-k-2)*(b-a))/Fib(n-k);
}
else
{
a=l;
l=m;
m=a+(Fib(n-k-1)*(b-a))/Fib(n-k);
}
k++; // увеличиваем счётчик итераций
}
if(f(x+l*p)<=f(x+m*p)) // рассматриваем 2 возможные ситуации,
alpha=(a+m)/2; // вычисляем результирующее значение и
else // изменяем значение коэффициента
alpha=(l+b)/2; // удлинения вектора
return k; // возвращаем количество итераций
}
//--------------------------------------------------------------------
// Метод Фибоначчи-2
//--------------------------------------------------------------------
int CMETODI::Fibonachchi_2(
CMatrix &x, // начальная точка
CMatrix &p, // направление поиска
double &e, // погрешность поиска
int &max_step) // максимальное количество итераций
{
int k=0; // задаём счётчик числа итераций
double Ln = 0.01*e; // задаём длину конечного интервала
double x1 ,x2; // задаём необходимые переменные
double n=0; // порядковый номер числа Фибоначчи
while(Fib(n)<(b-a)/Ln) // определяем этот номер в
n++; // соответствии с алгоритмом
x1=a+Fib(n-1)*(b-a)/Fib(n)+pow((-1),n)*e/Fib(n); // первая начальная точка
while(k<n) // сокращаем ТИЛ в соответствии с методом
{
x2 = a+b-x1; // вторая точка
if(f(x+x1*p)<f(x+x2*p)) // Сокращаем текущий интервал
{ // локализации рассмотрением
if(x1<x2) // 4-х ситуаций, аналогично
b=x2; // методу золотого сечения-2
else
a=x2;
}
else
{
if(x1<x2)
a=x1;
else
b=x1;
x1=x2;
}
k++; // увеличиваем счётчик итераций
}
alpha=x2; // изменяем значение коэффициента удлинения вектора
return k; // возвращаем количество итераций
}
//--------------------------------------------------------------------
// Метод экстраполяции-интерполяции
//--------------------------------------------------------------------
int CMETODI::ExIn(
CMatrix &x, // начальная точка
CMatrix &p, // направление поиска
double &e, // погрешность поиска
int &max_step) // максимальное количество итераций
{
int k=0; // задаём счётчик числа итераций
double c=0,d=norma(x); // задаём необходимые переменные
double h=0.001; // шаг
// сокращаем ТИЛ в соответствии с методом
while((fabs((d-b)/b)>e) && (fabs((f(x+d*p)-f(x+b*p))/f(x+b*p))>e) && k<max_step)
{
b=d;
a=b-h;
c=b+h;
d=0.5*(f(x+a*p)*(b*b-c*c)+f(x+b*p)*(c*c-a*a)+
f(x+c*p)*(a*a-b*b))/(f(x+a*p)*(b-c)+f(x+b*p)*(c-a)+f(x+c*p)*(a-b));
k++; // увеличиваем счётчик итераций
}
alpha=(b+d)/2; // изменяем значение коэффициента удлинения вектора
return k; // возвращаем количество итераций
}
//////////////////////////////////////////////////////////////////////
// Методы многомерной оптимизации
//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
// Метод параллельных касательных
//--------------------------------------------------------------------
CMatrix CMETODI::ParallelKasat(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step, // максимальное количество итераций
int i1Min) // метод одномерного поиска
{
int k=0; // задаём счётчик числа итераций
CMatrix x2, // промежуточная точка
x0=x, // начальная точка
d, // ускоряющее направление
p; // направление поиска
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
do
{
p = -df(x); // устанавливаем антградиентное направление
x = x+alpha*p; // спускаемся в точку х2
x2 = x; // сохраняем точку х2
p = -df(x); // устанавливаем антградиентное направление
FindAlpha(x,p,e,i1Min); // находим коэффициент удлинения вектора
x = x+alpha*p; // спускаемся в точку х3
d = x-x0; // определяем ускоряющее направление
FindAlpha(x,p,e,i1Min); // находим коэффициент удлинения вектора
x = x+alpha*d; // спускаемся в точку х4
x0 = x2; // если КОП не выполняется, то х2 - новая начальная точка
k++; // увеличиваем счётчик итераций
MASSIV.insertCol(x); // добавляем новое значение х в массив
}
while(norma(d)>e && norma(df(x))>e && k<*max_step);
*max_step=k; // возвращаем количество итераций
return x; // возвращаем найденный минимум
}
//--------------------------------------------------------------------
// Метод Коши
//--------------------------------------------------------------------
CMatrix CMETODI::Koshi(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step, // максимальное количество итераций
int i1Min) // метод одномерного поиска
{
int k=0; // задаём счётчик числа итераций
CMatrix p(x); // направление поиска
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
do
{
p = -df(x); // устанавливаем антградиентное направление
FindAlpha(x,p,e,i1Min); // находим коэффициент удлинения вектора
x = x+p*alpha; // спускаемся в следующую точку х
k++; // увеличиваем счётчик итераций
MASSIV.insertCol(x); // добавляем новое значение х в массив
}
while(norma(p)>e && fabs(f(x+alpha*p)-f(x))>e && k<*max_step); // комбинированный КОП
*max_step=k; // возвращаем количество итераций
return x; // возвращаем найденный минимум
}
//--------------------------------------------------------------------
// Метод циклического покоординатного спуска
//--------------------------------------------------------------------
CMatrix CMETODI::CPS(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step, // максимальное количество итераций
int i1Min) // метод одномерного поиска
{
int k=0; // задаём счётчик числа итераций
CMatrix x_prev(x), // предыдущее значение
d(x), // ускоряющее направление
p(x); // направление поиска
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
do
{
x_prev = x; // сохраняем точку
for(int i=1; i<=x.getSizeRow(); i++)
{ // выполняем серию одномерных
p[i] = 1; // поисков вдоль координатных осей
FindAlpha(x,p,e,i1Min); // находим коэффициент удлинения вектора
x = x + p*alpha; // спускаемся в следующую точку х
p[i] = 0;
}
d = x - x_prev; // определяем ускоряющее направление
k++; // увеличиваем счётчик итераций
MASSIV.insertCol(x); // добавляем новое значение х в массив
}
while(norma(d)>e && norma(df(x))>e && k<*max_step); // комбинированный КОП
*max_step=k; // возвращаем количество итераций
return x; // возвращаем найденный минимум
}
//--------------------------------------------------------------------
// Метод Гаусса-Зейделя
//--------------------------------------------------------------------
CMatrix CMETODI::GaussZeydel(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step, // максимальное количество итераций
int i1Min) // метод одномерного поиска
{
int k=0; // задаём счётчик числа итераций
CMatrix x_prev(x), // предыдущее значение
d(x), // ускоряющее направление
p(x); // направление поиска
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
do
{
x_prev = x; // сохраняем точку
for(int i=1; i<=x.getSizeRow(); i++)
{ // выполняем серию одномерных
p[i] = df(x)[i]; // поисков вдоль производной
FindAlpha(x,p,e,i1Min); // находим коэффициент удлинения вектора
x = x + p*alpha; // спускаемся в следующую точку х
p[i] = 0;
}
d = x - x_prev; // определяем ускоряющее направление
k++; // увеличиваем счётчик итераций
MASSIV.insertCol(x); // добавляем новое значение х в массив
}
while(norma(d)>e && norma(df(x))>e && k<*max_step); // комбинированный КОП
*max_step=k; // возвращаем количество итераций
return x; // возвращаем найденный минимум
}
//--------------------------------------------------------------------
// Метод Хука-Дживса
//--------------------------------------------------------------------
CMatrix CMETODI::HookJeeves(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step) // максимальное количество итераций
{
CMatrix h(x), // шаг поиска в виде матрицы
b(x), // базовая точка
c, q; // вспомогательные матрицы
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
for(int i=1; i<=h.getSizeRow(); i++)
h[i]=1; // задаём начальный шаг
int n=x.getSizeRow(), // количество строк
is_sample=0, // флаг для следующенго поиска
k=0; // задаём счётчик числа итераций
while(norma(h)>e && k<*max_step) // проверяем стандартный КОП
{
// выполняем исследующий поиск
int not_found=1; // флаг на окончание поиска
for(int i=1; i<=n; i++)
{
double f_x=f(x); // находим значение производной
c=x; // сохраняем точку
c[i]+=h[i]; // шаг в положительном направлении i-ой коорд.
if(f(c)<=f_x) // если нашли подходящую точку
{
x=c; // сохраняем точку
not_found=0; // устанавливаем флаг в 0
}
else // если не нашли подходящую точку
{
c[i]-=2*h[i]; // шаг в отрицательном направлении i-ой корд.
if(f(c)<f_x)
{
x=c; // сохраняем точку
not_found=0; // устанавливаем флаг в 0
}
}
//k++;
}
if(is_sample) // проверяем необходимость
{ // следующего исследующего поиска
if(not_found || !(f(x)<f(q)))
{
// возвращаемся к базовой точке
x=q;
b=q;
is_sample=0;
continue;
}
else
{
// запоминаем новую базовую точку
b=q;
}
}
else
{
if(not_found)
{
// если исследующий поиск закончился неудачей - уменьшаем шаг
h/=10; // (здесь beta = 10)
continue;
}
}
// выполняем ускоряющий поиск
q=x;
x=x*2-b;
is_sample=1;
k++; // увеличиваем счётчик итераций
MASSIV.insertCol(x); // добавляем новое значение х в массив
}
MASSIV.insertCol(x); // добавляем новое значение х в массив
k++; // увеличиваем счётчик итераций
*max_step=k; // возвращаем количество итераций
return x; // возвращаем найденный минимум
}
//--------------------------------------------------------------------
// Обобщённый метод Ньютона
//--------------------------------------------------------------------
CMatrix CMETODI::Newton_Ob(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step, // максимальное количество итераций
int i1Min) // метод одномерного поиска
{
int k=0; // задаём счётчик числа итераций
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
if(norma(df(x))<e) // дополнительный КОП:
{ // если х0 - точка
*max_step=0; // минимума, то завершить
return x; // поиск
}
CMatrix x0(x), // предыдущая точка
x1, // текущая точка
p; // направление поиска
for(k=0; k<*max_step; k++) // выполняем поиск в
{ // соответствии с методом
if(norma(df(x0))<e) // проверка на окончание поиска
break;
p=(-inverseGJ(hesse(x0))*df(x0)); // выбираем ньютоновское направление поиска
FindAlpha(x,p,e,i1Min); // находим коэффициент удлинения вектора
x1=x0+p*alpha; // спускаемся в новую точку
// проверка на окончание поиска
if(norma(x1-x0)/norma(x0)<e && norma(x0)<e && norma(x1)<e)
break;
// дополнительный КОП
if (norma(df(x1))>norma(df(x0)))
{
*max_step=k;
return x0;
}
x0=x1; // сохрарняем предыдущую точку
MASSIV.insertCol(x0); // добавляем новое значение х в массив
}
*max_step=k; // возвращаем количество итераций
return x1; // возвращаем найденный минимум
}
//--------------------------------------------------------------------
// Метод Зангвила
//--------------------------------------------------------------------
CMatrix CMETODI::Sangvil(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step) // максимальное количество итераций
{
int k=0; // задаём счётчик числа итераций
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
if(norma(df(x))<e) // дополнительный КОП:
{ // если х0 - точка
*max_step=0; // минимума, то завершить
return x; // поиск
}
CMatrix x0(x), // предыдущая точка
x1, // текущая точка
i; // единичная матрица
i.setSingle(x0.getSizeRow()); // переопределение размера
double lambda=1000; // необходимый коэффициент
for(k=0; k<*max_step; k++) // выполняем поиск в
{ // соответствии с методом
if(norma(df(x0))<e) // проверка на окончание поиска
break;
for(;;) // бесконечный цикл
{
x1=x0-inverseGJ(hesse(x0)+lambda*i)*df(x0); // новая точка
if(f(x1)<f(x0)) // рассматриваем
{ // 2 ситуации
lambda*=0.5;
break;
}
else
lambda*=2;
}
x0=x1; // сохрарняем предыдущую точку
MASSIV.insertCol(x0); // добавляем новое значение х в массив
}
*max_step=k; // возвращаем количество итераций
return x1; // возвращаем найденный минимум
}
//--------------------------------------------------------------------
// Метод Флетчера-Ривса
//--------------------------------------------------------------------
CMatrix CMETODI::FletcherReeves(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step, // максимальное количество итераций
int i1Min) // метод одномерного поиска
{
int k=0; // задаём счётчик числа итераций
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
CMatrix p(x), // направление поиска
g(x); // градиент функции
double beta; // число, меняющее длину р
// сокращаем ТИЛ в соответствии с методом
while(norma(df(x))>e && k<*max_step)
{
k++; // увеличиваем счётчик итераций
if(k%(x.getSizeRow())==1) // проверяем номер итерации
p = -df(x); // устанавливаем антиградиентное напрвление
else
{ // вычисляем в соответствии с формулой
beta = (pow(norma(df(x)),2))/(pow(norma(g),2));
p = -df(x) + p*beta; // новое направление поиска
}
g=df(x); // сохраняем текущий градиент
FindAlpha(x,p,e,i1Min); // находим коэффициент удлинения вектора
x = x + p*alpha; // спускаемся в новую точку
MASSIV.insertCol(x); // добавляем новое значение х в массив
}
*max_step=k; // возвращаем количество итераций
return x; // возвращаем найденный минимум
}
//--------------------------------------------------------------------
// Метод Пауэлла - 1
//--------------------------------------------------------------------
CMatrix CMETODI::Pauell_1(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step, // максимальное количество итераций
int i1Min) // метод одномерного поиска
{
int k=0; // задаём счётчик числа итераций
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
CMatrix x1(x), // начальная точка
p(x), // направление поиска
d(x), // ускоряющее направление
PI; // система сопряжённых направлений
// устанавливаем начальное значение системы
PI.setSize(x.getSizeRow(),x.getSizeRow()+1);
p.setNull(); // делаем направление поиска нулевым
// строим начальную поисковую систему,
// которая состоит из координатных ортов
for(int i=1; i<=x.getSizeRow(); i++)
{
p[i] = 1;
PI.setCol(i,p);
p[i] = 0;
}
// сокращаем ТИЛ в соответствии с методом
while(norma(df(x))>e && k<*max_step)
{
x1=x; // сохраняем начальную точку
// выполняем поиск вдоль системы направлений
for(i=1; i<=x.getSizeRow(); i++)
{
p=PI.getCol(i); // получаем направление
FindAlpha(x,p,e,i1Min); // находим коэффициент удлинения вектора
x = x + alpha*p; // спускаемся в новую точку
}
d=x-x1; // получаем новое направление
FindAlpha(x,d,e,i1Min); // находим коэффициент удлинения вектора
x = x + alpha*d; // спускаемся в новую точку
PI.setCol(x.getSizeRow()+1,d); // устанавливаем последним
// новое направление
if(x.getSizeRow()!=1)
for(i=1; i<=x.getSizeCol()+1; i++) // создаём новую систему
PI.setCol(i,PI.getCol(i+1)); // в соответствии с методом
k++; // увеличиваем счётчик итераций
MASSIV.insertCol(x); // добавляем новое значение х в массив
}
*max_step=k; // возвращаем количество итераций
return x; // возвращаем найденный минимум
}
//--------------------------------------------------------------------
// Метод Пауэлла - 2
//--------------------------------------------------------------------
CMatrix CMETODI::Pauell_2(
CMatrix x, // начальная точка
double e, // погрешность поиска
int* max_step, // максимальное количество итераций
int i1Min) // метод одномерного поиска
{
int k=0; // задаём счётчик числа итераций
// переопределяем массив значений х
// при пошаговом поиске и задаём
// значение начальной точки
MASSIV.setSize(x.getSizeRow(),x.getSizeCol());
MASSIV.setCol(1,x);
CMatrix x1(x), // начальная точка
p(x), // направление поиска
d(x), // ускоряющее направление
PI; // система сопряжённых направлений
// устанавливаем начальное значение системы
PI.setSize(x.getSizeRow(),x.getSizeRow()+1);
p.setNull(); // делаем направление поиска нулевым
// строим начальную поисковую систему,
// которая состоит из координатных ортов
for(int i=1; i<=x.getSizeRow(); i++)
{
p[i] = 1;
PI.setCol(i,p);
p[i] = 0;
}
// сокращаем ТИЛ в соответствии с методом
while(norma(df(x))>e && f(x1)>=f(x) && k<*max_step)
{
x1=x; // сохраняем начальную точку
// выполняем поиск вдоль системы направлений
for(i=1; i<=x.getSizeRow(); i++)
{
p=PI.getCol(i); // получаем направление
FindAlpha(x,p,e,i1Min); // находим коэффициент удлинения вектора
x = x + alpha*p; // спускаемся в новую точку
}
d=x-x1; // получаем новое направление
FindAlpha(x,d,e,i1Min); // находим коэффициент удлинения вектора
x = x + alpha*d; // спускаемся в новую точку
PI.setCol(1,d);
PI.setCol(x.getSizeRow()+1,d); // устанавливаем последним
// новое направление
if(x.getSizeRow()!=1)
for(i=2; i<x.getSizeCol()+1; i++) // создаём новую систему
PI.setCol(i,PI.getCol(i+1)); // в соответствии с методом
k++; // увеличиваем счётчик итераций
MASSIV.insertCol(x); // добавляем новое значение х в массив
}
*max_step=k; // возвращаем количество итераций
return x; // возвращаем найденный минимум
}
//Для метода Бокса ограничения
int isComplies_a_b(CMatrix &X, CMatrix &A, CMatrix &B, int num)
{
double ai[5], bi[5];
switch(num)
{
case 17: // N43 в лабдоке
ai[0]=-4.82843;
ai[1]=-2.414214;
bi[0]=0.82843;
bi[1]=0.414214;
A.setSingle(4);
B.setSingle(1);
if((X[0]>=-4.82843)&&(X[1]>=-2.414214)&&(X[0]<=0.82843)&&(X[1]<=0.414214))
return 1;
else
return 0;
case 18: // N40 в лабдоке
ai[0]=0;
ai[1]=0;
ai[2]=0;
bi[0]=20;
bi[1]=11;
bi[2]=42;
A.setSingle(4);
B.setSingle(1);
if((X[0]>=0)&&(X[1]>=0)&&(X[2]>=0)&&(X[0]<=20)&&(X[1]<=11)&&(X[2]<=42))
return 1;
else
return 0;
default: return 0;
}
}
int isComplies_g(CMatrix X, int num)
{
switch(num)
{
case 17: // N43 в лабдоке
//if((X.getCol()+X.getCol()*X.getCol()-1)<=0)&&(-1*X.getCol(1)+2*X.getCol(1)<=0))
return 1;
// else
return 0;
case 18: // N40 в лабдоке
if(X[0]+2*X[1]+2*X[2]<=72)
return 1;
else
return 0;
default: return 0;
}
}
//проверка условий до сюда
CMatrix centerOfGravity(CMatrix *M, int Msize, CMatrix Vsize, int excludedNum)
{
CMatrix res(Vsize); //размер задачи
for(int i=0; i<Msize; i++) //размер комплекса
if(i!=excludedNum) res=res + M[i];
res=(1/(double)(Msize-1)) * res;
return res;
}
void sortComplexByFuncVal(CMatrix *M, int Msize, int num)
{
CMatrix temp;
for(int i=0; i<Msize; i++)
for(int j=0; j<Msize-1; j++)
{
// if(f(M)>f(M))
{
temp=M[j];
M[j]=M[j+1];
M[j+1]=temp;
}
}
}
double findMaxDistance(CMatrix *M, int Msize) //максимал расстояния между точками из комплекса
{
double res=0, temp=0;
for(int i=0; i<Msize; i++)
for(int j=0; j<Msize; j++)
{
// temp=norma(M[i]-M[j]);
if(temp>res)
res=temp;
}
return res; // для копа
}
CMatrix CMETODI::ComplexBox(CMatrix x,int num)
{
CMatrix complex[2*5+1];
int complexSize=2*x.getSizeRow(); // размер комплекса >(n+1), принимаем его = 2n
int ii=0;
for(ii=1; ii<complexSize; ii++)
complex[ii]=x.setSingle(5);
complex[0]=x;
CMatrix Xi=x, Xc=x, Xh=x, Xr=x, X0=x;
double alpha=1.3, sigma=0, sum=0, sum2=0, Eps=0.0001;
CMatrix Ai;
CMatrix Bi;
int nmax_dot=0;
srand((unsigned)time(NULL));
int k=0, kk=0, kkk=0;
int i=0;
Xc=x;
for(i=1; i<complexSize; i++) // 4, 10
{
for(int j=0; j<=x.getSizeRow(); j++) // 5
Xi[j]=Ai[j] + ((double)rand()/(double)(RAND_MAX)) * (Bi[j]-Ai[j]);
kkk=0;
while(!(isComplies_g(Xi, num)&&(isComplies_a_b(Xi, Ai, Bi, num)))) // 6
{
Xi=0.5*(Xi+Xc); // 7
if(kkk++>1000)
{
break;
}
}
complex[i]=Xi; // 5
Xc=(1/(double)i)*((i-1)*Xc+Xi); // 8
}
for(ii=0; ii<complexSize; ii++)
sortComplexByFuncVal(complex, complexSize, num);
do // вторая блок-схема
{
for(ii=0; ii<complexSize; ii++)
nmax_dot=complexSize-1;
X0=centerOfGravity(&complex[0], complexSize, x, nmax_dot); // 13
Xh=complex[nmax_dot]; // Xh=Xk // 14
Xr=(alpha+1)*X0 - alpha*Xh; // 15
kk=0;
do
{
if(isComplies_g(Xr, num)&&(isComplies_a_b(Xr, Ai, Bi, num))) // 16
{
if(f(Xr) > f(Xh)) // 20
{
Xr=0.5*(Xr+X0); // 19
continue;
}
else
{
break; // ->21
}
}
if(!isComplies_a_b(Xr, Ai, Bi, num))
{
for(ii=0; ii<Xr.getSizeCol(); ii++) // 17
{
if(Xr[ii]<Ai[ii])
Xr[ii] = Ai[ii] + 1e-6;
}
for(ii=0; ii<=Xr.getSizeRow(); ii++)
{
if(Xr[ii]>Bi[ii])
Xr[ii] = Bi[ii] - 1e-6;
}
}
if(!isComplies_g(Xr, num)) // 18
{
Xr=0.5*(Xr+X0);
}
if(kk++>1000) break;
}
while(!((isComplies_g(Xr, num))&&(isComplies_a_b(x, Ai, Bi, num))));
complex[nmax_dot]=Xr; // 22
sortComplexByFuncVal(complex, complexSize, num);
// 23
sum=0; sum2=0; sigma=0;
for(ii=0; ii<complexSize; ii++)
{
sum+=f(complex[ii]);
}
sum/=double(complexSize);
for(ii=0; ii<complexSize; ii++)
sigma += pow(f(complex[ii]) - sum, 2)/complexSize;
if(k++>1000) break;
if((sigma < Eps) && (findMaxDistance(&complex[0], complexSize-1)<Eps)) break;
}
while(1);
x+=complex[0];
return x;
}
Соседние файлы в папке Malgin_kurs