Files
HM2/P3/CMyVektor.cpp
2026-01-04 15:35:46 +01:00

213 lines
6.6 KiB
C++
Executable File

#include "CMyVektor.h"
#include <math.h>
#include <iostream>
int CMyVektor::getDimension() {
return dimension;
}
// Vektor Element bei index i
double& CMyVektor::operator[](int i) {
return werte.at(i);
}
double CMyVektor::getElement(int i) {
return werte.at(i - 1);
}
void CMyVektor::setElement(int i, double j) {
werte.at(i - 1) = j;
}
void CMyVektor::setElements(std::vector<double> x) {
for (int i = 0; i < x.size(); i++)
werte[i] = x[i];
}
// Betrag des Vektors
double CMyVektor::length() {
double l = 0.0;
for (int i = 0; i < werte.size(); i++)
l += pow(werte.at(i), 2);
return(sqrt(l));
}
// Ausgabe im Vektorformat
std::ostream& operator<< (std::ostream& os, CMyVektor& vektor) {
os << "(";
for (int i = 0; i < vektor.getDimension(); i++) {
os << vektor[i];
if (i < vektor.getDimension() - 1) os << "|";
}
os << ")";
return os;
}
/* Vektor Addition
a1 + b1 = a1+b1
a2 + b2 = a2+b2
: : :
ai + bi = ai+bi
*/
CMyVektor operator+(CMyVektor a, CMyVektor b) {
// Vektoren addierbar?
if (a.getDimension() != b.getDimension())
return a;
CMyVektor sum(a.getDimension());
for (int i = 0; i < a.getDimension(); i++)
sum[i] = a[i] + b[i];
return sum;
}
/* Skalare Multiplikation
a1 * s = v1
a2 * s = v2
: : :
ai * s = vi
*/
CMyVektor operator*(double s, CMyVektor a) {
CMyVektor vektor(a.getDimension());
for (int i = 0; i < a.getDimension(); i++)
vektor[i] = s * a[i];
return vektor;
}
CMyVektor gradient(double f(CMyVektor x), CMyVektor x) {
CMyVektor grad(x.getDimension());
CMyVektor xh(x.getDimension()); // x mit "Wackelei" an x_i
xh = x;
double fx = f(x);
double h = 1e-8;
// Berechnung der partiellen Ableitung nach x_i und Zusammenfassung in grad
for (int i = 0; i < x.getDimension(); i++) {
// xh[0] xh[1] ... xh[n]
// x_1+h,x_2,...,x_n x_1,x_2+h,...,x_n x_1,x_2,...,x_n+1
xh[i] += h;
// grad[i] = df/dx_i => numerische Ableitung nach dem jeweilige x_i
grad[i] = (f(xh) - fx) / h;
// Zurücksetzen der "Wackelei"
xh[i] -= h;
}
return grad;
}
CMyVektor gradientenverfahren(double f(CMyVektor x), CMyVektor x, double lambda) {
int schritt_zaehler = 0;
CMyVektor gradfx(x.getDimension());
CMyVektor x_neu(x.getDimension());
gradfx = gradient(f, x);
while (gradient(f, x).length() >= 1e-5 && schritt_zaehler < 25) {
x_neu = x + lambda * gradfx;
std::cout
<< "Schritt " << schritt_zaehler << ": " << std::endl
<< " x = " << x << std::endl
<< " λ = " << lambda << std::endl
<< " f(x) = " << f(x) << std::endl
<< " grad f(x) = " << gradfx << std::endl
<< " ||grad f(x)|| = " << gradfx.length() << std::endl << std::endl
<< " x_neu = " << x_neu << std::endl
<< " f(x_neu) = " << f(x_neu) << std::endl << std::endl;
// Halbierung
if (f(x_neu) <= f(x)) {
double lamda_test = lambda * 0.5;
CMyVektor x_test = x + lamda_test * gradfx;
std::cout
<< " ↯ f(x) = " << f(x) << " ≥ f(x_neu) = " << f(x_neu) << std::endl << std::endl
<< " ? Test mit halbierter Schrittweite (λ = " << lamda_test << "): " << std::endl
<< " x_test = " << x_test << std::endl
<< " f(x_test) = " << f(x_test) << std::endl << std::endl;
if (f(x) < f(x_test))
std::cout
<< " ✓ f(x) = " << f(x) << " < f(x_test) = " << f(x_test) << std::endl
<< " ! Übernehme Schrittweite." << std::endl << std::endl;
// weiter Halbieren wenn f(x_test) <= f(x)
while (f(x_test) <= f(x)) {
std::cout
<< " ↯ f(x) = " << f(x) << " ≥ f(x_test) = " << f(x_test) << std::endl << std::endl;
lamda_test *= 0.5;
x_test = x + lamda_test * gradfx;
std::cout
<< " ? Test mit halbierter Schrittweite (λ = " << lamda_test << "): " << std::endl
<< " x_test = " << x_test << std::endl
<< " f(x_test) = " << f(x_test) << std::endl << std::endl;
// Ausgabe beim letzten Durchlauf der Schleife
if (!(f(x_test) <= f(x)))
std::cout
<< " ✓ f(x) = " << f(x) << " < f(x_test) = " << f(x_test) << std::endl << std::endl
<< " ! Übernehme Schrittweite λ = " << lamda_test << std::endl << std::endl;
}
lambda = lamda_test;
x_neu = x_test;
}
// Verdopplung
else {
double lamda_test = lambda * 2;
CMyVektor x_test = x + lamda_test * gradfx;
std::cout
<< " ? Test mit doppelter Schrittweite (λ = " << lamda_test << "): " << std::endl
<< " x_test = " << x_test << std::endl
<< " f(x_test) = " << f(x_test) << std::endl << std::endl;
if (f(x_test) > f(x_neu)) {
x_neu = x_test;
lambda = lamda_test;
std::cout
<< " ! Übernehme verdoppelte Schrittweite λ = " << lamda_test << std::endl
<< " ✓ f(x_neu) = " << f(x_neu) << " < f(x_test) = " << f(x_test) << std::endl << std::endl;
}
else {
std::cout
<< " ↯ f(x_neu) = " << f(x_neu) << " ≥ f(x_test) = " << f(x_test) << std::endl
<< " ! behalte aktuelle Schrittweite λ = " << lambda << std::endl << std::endl;
}
}
std::cout << std::endl;
x = x_neu;
gradfx = gradient(f, x);
schritt_zaehler++;
}
// Zusammenfassung des Endes
if (gradfx.length() < 1e-5)
std::cout
<< "Ende wegen ||grad f(x)|| < 10^-5 bei" << std::endl;
else
std::cout
<< "Ende wegen 25. Schritt" << std::endl;
std::cout
<< " x = " << x << std::endl
<< " λ = " << lambda << std::endl
<< " f(x) = " << f(x) << std::endl
<< " grad f(x) = " << gradfx << std::endl
<< " ||grad f(x)|| = " << gradfx.length() << std::endl
<< "-----------------------------------------------------" << std::endl << std::endl;
return x_neu;
}