Министерство Образования Российской Федерации
Санкт-петербургский государственный ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ «ЛЭТИ» ИМЕНИ В. И.УЛЬЯНОВА (ЛЕНИНА)
197376, Санкт-Петербург, ул. Проф. Попова, 5
Факультет компьютерных технологий и информатики
Кафедра САПР
«ЗАЧТЕНО»
________ П.А. Алешкевич
ОТЧЕТ О ЛАБОРАТОРНОЙ РАБОТЕ №5
Проектирование программы оптимизации
Студенты группы 2375 А. Филатов
В. Каверзин
Санкт Петербург 2004
Содержание:
Задание 3
Спецификация программы 3
Текст программы 3
Описание интерфейса 10
Сравнение с работой надстройки «Поиск решения» 12
Результаты тестирования программы 12
Ответы на контрольные вопросы 13
Наследование относится только к классам объектов. Это означает, что каждый объект может иметь наследников, каждый из которых будет обладать всеми полями и методами своего предка. Кроме того, как правило, классы-наследники совместимы по типу со своими предками. Наследование бывает двух видов: 13
Вывод 14
Задание
Целью работы является изучение современной технологии разработки программ оптимизации, ориентированных на язык C++.
Реализовать на языке С++ программу оптимизации. Протестировать программу и сравнить результаты работы заданных методов оптимизации при использовании различных критериев окончания поиска и при задании различных значений погрешности локализации минимума. Сделать выводы.
Спецификация программы
Программа построена таким образом, чтобы пользователь имел возможность оказывать определяющее воздействие на ход выполнения программы и алгоритмы поиска решений. Для этого в основной функции GZ_3, решающей задачу нахождения минимума выбранной функции методом Гаусса-Зейделя, реализована возможность определения максимального количества итераций, определения интересующей точности вычислений. В программе предусмотрена возможность повторного запуска процесса вычисления с корректирующими значениями начальной точки, максимального количества итераций и интересующей точности.
Основным объектом, которым пользуются все функции программы, является объект «Вектор», который представлен в программе классом Vector. В классе реализованы все процедуры обработки объектов классаVector, необходимые для работы программы. Основная расчетная функцияGZ_3 возвращает именно объект классаVector.
В программе пользователю предоставляется возможность выбрать метод нахождения шага, доставляющего минимум целевой функции при движении вдоль заданной прямой. Таких методов в программе реализовано два: метод Золотого Сечения(1) и метод Пауэлла. Они оба имеют одинаковые параметры, и их задача сводится только к нахождению шага, доставляющего минимум целевой функции при движении вдоль заданной прямой.
Текст программы
#include <iostream.h>
#include <conio.h>
#include <math.h>
class Vector
{
public:
Vector(int Size);
Vector(const Vector& v);
~Vector();
int size() const;
double& Vector::operator[](int N);
double Vector::operator[](int N) const;
void Summa(const Vector& a, const Vector& b);
void Razn(const Vector& a, const Vector& b);
Vector Scal(Vector x, double d);
double Umn(const Vector& a, const Vector& b);
Vector& operator=(const Vector& a);
void Write() const;
Vector Grad(const Vector& x);
/***************Lab3***************/
void Swenn(const Vector& x, Vector& p, double& ala, double& alb);
//double ZS1(Vector& x, Vector p, double al1, double al2);
double ZS1(Vector& x, Vector p, double al1, double al2, double E);
double Pauell(Vector& x, Vector p, double al1, double al2, double E);
/***************Lab4***************/
Vector Evec(int n, int Num);
double Norma(Vector x);
Vector GZ_3(Vector& x, double E, int maxiter, int& iter, int& bool, int method);
Vector operator+(const Vector& a)
{
Vector s(nSize);
s.Summa(*this, a);
return s;
}
Vector operator-(const Vector& a)
{
Vector s(nSize);
s.Razn(*this, a);
return s;
}
double operator*(const Vector& a)
{
double w;
Vector s(nSize);
w = s.Umn(*this, a);
return w;
}
void operator*=(double d)
{
for (int i = 0; i < nSize; i++)
Coord[i] *= d;
}
private:
double* Coord;
int nSize;
};
Vector::Vector(int Size)
{
nSize = Size;
Coord = new double[Size];
}
Vector::Vector(const Vector& v)
{
nSize = v.size();
Coord = new double[nSize];
for (int i = 0; i < nSize; i++)
Coord[i] = v[i];
}
Vector::~Vector()
{
delete[] Coord;
}
int Vector::size() const
{
return nSize;
}
double& Vector::operator[](int N)
{
return *&Coord[N];
}
double Vector::operator[](int N) const
{
return Coord[N];
}
Vector Vector::Scal(Vector x, double d)
{
int i = x.size();
Vector W(i);
for(int j=0; j<i; j++)
W[j] = x[j]*d;
return W;
}
void Vector::Summa(const Vector& a, const Vector& b)
{
int s = a.size();
int i;
if ((s = b.size()) != 0 )
{
for (i = 0; i < s; i++)
{
Coord[i] = a[i] + b[i];
}
}
else
{
cout<<"ERROR!"<<endl;
}
}
void Vector::Razn(const Vector& a, const Vector& b)
{
int s = a.size();
int i;
if ((s = b.size()) != 0 )
{
for (i = 0; i < s; i++)
{
Coord[i] = a[i] - b[i];
}
}
else
{
cout<<"ERROR!"<<endl;
}
}
double Vector::Umn(const Vector& a, const Vector& b)
{
int s = a.size();
//int i;
double Um=0;
if ((s = b.size()) != 0 )
{
for (int i = 0; i < s; i++)
{
Coord[i] = a[i] * b[i];
Um = Um + Coord[i];
}
}
return Um;
}
Vector& Vector::operator =(const Vector& a)
{
for (int i = 0; i < nSize; i++)
{
Coord[i] = a.Coord[i];
}
return *this;
}
void Vector::Write() const
{
cout<<"This is vector:"<<endl;
for (int i = 0; i < nSize; i++)
{
cout<<Coord[i]<<endl;
};
}
double F (Vector t)
{
double result = 0;
if (t.size() == 2)
result = pow(t[1]-t[0]*t[0], 2) + pow(1-t[0], 2);
if (t.size() == 3)
result = (t[0]-1)*(t[0]-1) + (t[1]-3)*(t[1]-3) + 4*(t[2]+5)*(t[2]+5);
if (t.size() == 4)
result = 100*pow(t[1]-t[0]*t[0], 2) + (1-t[0])*(1-t[0]) + 90*pow(t[3]-t[2]*t[2], 2) + pow(1-t[2], 3) + 10.1*(t[1]-1)*(t[1]-1) + (t[3]-1)*(t[3]-1) + (t[1]-1)*(t[3]-1);
return result;
}
double ChP(Vector x, int i) //formula dlia chislennogo differentsirovania
{
int t = x.size();
double w = -1000;
double h = 0.000001;
Vector q(t);
if (t >= i)
w = ( F(x + q.Scal(q.Evec(t, i), h)) - F(x - q.Scal(q.Evec(t, i), h)) )/(2*h);
return w;
}
Vector Vector::Grad(const Vector& x)
{
int i = x.size();
Vector w(i);
for (int j = 1; j<=i; j++)
{
w[j-1] = ChP(x, j);
}
return w;
}
void Vector::Swenn(const Vector& x, Vector& p, double& ala, double& alb)
{
int r = x.size();
Vector G(r);
G = G.Grad(x); // Proverka napravlenia ubivania functsii...
if ((G * p) > 0)
{
p*=-1;
}
double f1, f2, al = 0.000001;
Vector x1(r);
Vector x2(r);
x1 = x;
f1 = G * p;
do
{
al = al*2;
G = G.Scal(p, al);
x2 = x1 + G;
G = G.Grad(x2);
f2 = G * p;
}
while (f1*f2 > 0);
alb = al;
ala = al/2;
}
double Vector::ZS1(Vector& x, Vector p, double al1, double al2, double E)
{ // metod Zolotogo Sechenia-1
double l, m, f1, f2, help1, help2;
int j=0;
l = al1 + 0.38196601125*fabs(al1-al2);
m = al1 + 0.61803398875*fabs(al1-al2);
int r = x.size();
Vector G(r);
Vector x1(r);
Vector x2(r);
while ( (fabs(al1-al2) >= E) || (fabs(f1-f2) >= E) )
{
j = j + 1;
x1 = x + G.Scal(p, l);
f1 = F(x1);
x2 = x + G.Scal(p, m);
f2 = F(x2);
if (f1 < f2)
{
al2 = m;
m = l;
l = al1 + 0.38196601125*fabs(al1-al2);
}
if (f1 >= f2)
{
al1 = l;
l = m;
m = al1 + 0.61803398875*fabs(al1-al2);
}
}
return (al1+al2)/2;
}
Vector Vector::Evec(int n, int Num) // - koordinatniy ort
{ // dlinoy 'n'
Vector W(n); // i 1-tsey na 'Num'
int i=0;
while (i<n)
{
W[i] = 0;
i++;
}
W[Num-1] = 1;
return W;
}
double Vector::Norma(Vector x)
{
int i = x.size();
double d=0;
for (int j = 0; j < i; j++)
d = d + x[j]*x[j];
return sqrt(d);
}
double Vector::Pauell(Vector& x, Vector p, double al1, double al2, double E)
{ //metod Pauella
double a, b, bb, c, d, dd, help1, help2, Q, S;
int r = x.size();
Vector xa(r);
Vector xb(r);
Vector xc(r);
Vector xd(r);
a = al1;
b = (al1+al2)/2;
c = al2;
xa = x + xa.Scal(p, a);
xb = x + xb.Scal(p, b);
xc = x + xc.Scal(p, c);
help1 = ( F(xa)*(b*b-c*c) + F(xb)*(c*c-a*a) + F(xc)*(a*a-b*b) );
help2 = (F(xa)*(b-c) + F(xb)*(c-a) + F(xc)*(a-b));
if (help2 == 0)
help2 = 0.0000001;
d = 0.5*help1/help2;
xd = x + xd.Scal(p, d);
while ((fabs((d-b)/b) >= E) || (fabs(F(xd)-F(xb))/F(xb) >= E ))
{
if (b<d)
{
if (F(xb)<F(xd))
{
c = d;
b = (a+c)/2;
}
else
{
a = b;
b = (a + c)/2;
}
}
if (b>d)
{
if (F(xb)>F(xd))
{
c = b;
b = (a + c)/2;
}
else
{
a = d;
b = (a + c)/2;
}
}
xa = x + xa.Scal(p, a);
xb = x + xb.Scal(p, b);
xc = x + xc.Scal(p, c);
help1 = (F(xa)-F(xb))*(b-c)*(c-a);
help2 = (F(xa)*(b-c) + F(xb)*(c-a) + F(xc)*(a-b));
if (help2 == 0)
break; // Delenie na nol'
d = (a+b)/2 + 0.5*(help1/help2);
xd = x + xd.Scal(p, d);
bb = b;
dd = d;
}
b = bb;
d = dd;
return (b + d)/2;
}
Vector Vector::GZ_3(Vector& x, double E, int maxiter, int& iter, int& bool, int method)
{
int r = x.size();
Vector p(r); //napravlenie
Vector G(r); //vspomogatel'naya
Vector t(r); //dubliruet 'x'
double w, al, a, b, k;
int y=0;
t = x;
bool = 0;
while ( ( Norma(G.Grad(t)) >= E ) && ( y < maxiter ) )
{
k = Norma(G.Grad(t));
for (int i = 1; i<=r; i++)
{
w = ChP(t, i);
p = p.Scal(Evec(r,i), w);
G.Swenn(t, p, a, b);
if (method == 1)
al = G.ZS1(t, p, a, b, E); //alpha i-oe
if (method == 2)
al = G.Pauell(t, p, a, b, E); //alpha i-oe
t = t + G.Scal(p, al);
}
y++;
}
if (Norma(G.Grad(t)) < E)
bool = 1;
iter = y;
return t;
}
/***********************************************/
void main()
{
clrscr();
double E;
int it=0, maxit, tochnost;
int choice, razmer, method, itogoiter=0;
char otvet, dalshe;
cout<<"Dannaia programma ispol'zuet metod GAUSSA-ZEIDELIA"<<endl;
cout<<"dlia nahojdenia minimuma funktsii."<<endl;
cout<<"Predusmotren vibor metoda promejutochnih raschetov (ZS-1, Pauell)"<<endl;
cout<<endl;
cout<<"Viberite functsiu:"<<endl;
cout<<"1. f(x1,x2) = (x2-x1x1)(x2-x1x1) + (1-x1)(1-x1);"<<endl;
cout<<"2. f(x1,x2,x3) = (x1-1)(x1-1) + (x2-3)(x2-3) + 4(x3+5)(x3+5)"<<endl;
//cout<<"3. f(x1,x2,x3,x4) = x1 - 10x2 + 5(x3-x4) + (x2-2x3)^4 + 10(x1-x4)^4"<<endl;
cout<<"3. f(x1,x2,x3,x4) = 100(x2-x1x1)^2 + (1-x1)^2 + 90(x4-x3x3)^2 + (1-x3)^3 + "<<endl;
cout<<" + 10.1(x2-1)^2 + (x4-1)^2 + 19.8(x2-1)(x4-1)"<<endl;
cin>>choice;
razmer = choice + 1;
Vector x(razmer);
for (int i = 0; i < razmer; i++)
x[i] = 0;
cout<<"Po umolchaniu nachalnaia tochka imeet koordinati x[i]=0.5. Izmenit'? (y/n)"<<endl;
otvet = getch();
if (otvet == 'y')
for (int i = 0; i < razmer; i++)
{
cout<<"Zadaite "<<i+1<<" koordinatu: ";
cin>>x[i];
}
Vector Q3(razmer);
int pomoshnik = 0;
do
{
cout<<endl;
cout<<"Viberite metod rascheta:"<<endl;
cout<<"1. Metod Zolotogo Sechenia (1);"<<endl;
cout<<"2. Metod Pauella"<<endl;
cin>>method;
cout<<"Vvedite max kol-vo iteratsii: ";
cin>> maxit;
cout<<"Vvedite pogreshnost' (E = 0.00001 - 0.0000000001) : ";
cin>>E;
cout<<endl;
if (pomoshnik > 0)
{
x = Q3;
cout<<"Izmenit' nachal'nuiu tochku? (y/n)"<<endl;
otvet = getch();
if (otvet == 'y')
for (int i = 0; i < razmer; i++)
{
cout<<"Zadaite "<<i+1<<" koordinatu: ";
cin>>x[i];
}
};
Q3 = Q3.GZ_3(x, E, maxit, it, tochnost, method);
cout<<"kolichestvo iteratsii v dannom shage: "<<it;
itogoiter = itogoiter + it;
cout<<", vsego: "<<itogoiter<<endl;
if (tochnost == 1)
{
cout<<"tochnost' DOSTIGNUTA... "<<endl;
}
else
{
cout<<"tochnost' NE dostignuta... "<<endl;
}
Q3.Write();
cout<<"Prodoljit' rascheti? (y/n)"<<endl;
dalshe = getch();
pomoshnik++;
}
while (dalshe != 'n');
}