Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
8
Добавлен:
01.05.2014
Размер:
40.64 Кб
Скачать
#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