Created
December 25, 2016 21:46
-
-
Save elvircrn/351be203a13736dae3f9043d233fe03b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cstdio> | |
#include <cstdlib> | |
#include <queue> | |
#include <cmath> | |
#include <stack> | |
#include <map> | |
#include <set> | |
#include <algorithm> | |
#include <sstream> | |
#include <unordered_map> | |
#include <functional> | |
#include <utility> | |
#define EQBEGIN std::cout << "\\begin{equation*}\n\\begin{aligned}\n"; | |
#define EQEND std::cout << "\\end{aligned}\n\\end{equation*}\n"; | |
/* | |
Svaka test metoda testira jednu funkcionalnost jedne metode a svaka | |
test_exc testira jedan exception jedne metode. | |
*/ | |
#include <iostream> | |
#include <cstdio> | |
#include <cstdlib> | |
#include <string> | |
#include <cstring> | |
#include <functional> | |
#include <vector> | |
#include <cmath> | |
#include <vector> | |
#include <limits> | |
#include <functional> | |
#include <numeric> | |
#include <type_traits> | |
#define EPS std::numeric_limits<double>::epsilon() | |
class Vector | |
{ | |
std::vector<double> elements; | |
void DimCheck(int n) const; | |
void PushBack(const double &elem); | |
void DimCheck(const Vector &v1, const Vector &v2) const; | |
void DimCheck(const Vector &v) const; | |
void RangeCheck(int index) const; | |
Vector& ForEach(const std::function<double(double)> &f); | |
void CheckZero(double x) const; | |
public: | |
explicit Vector(int n); | |
Vector(std::initializer_list<double> l); | |
Vector(const std::vector<double> &v); | |
int NElems() const; | |
double &operator[](int i); | |
double operator[](int i) const; | |
double &operator()(int i); | |
double operator()(int i) const; | |
void Print(char separator = '\n') const; | |
friend Vector operator +(const Vector &v1, const Vector &v2); | |
Vector &operator +=(const Vector &v); | |
friend Vector operator -(const Vector &v1, const Vector &v2); | |
Vector &operator -=(const Vector &v); | |
friend Vector operator *(double s, const Vector &v); | |
friend Vector operator *(const Vector &v, double s); | |
Vector &operator *=(double s); | |
friend double operator *(const Vector &v1, const Vector &v2); | |
friend Vector operator /(const Vector &v, double s); | |
Vector &operator /=(double s); | |
bool operator== (const Vector &v) const; | |
bool operator!= (const Vector &v) const; | |
~Vector(); | |
bool JesuLiJednaki(double x, double y, double Eps = EPS) const | |
{ | |
if (std::abs(x) < EPS) | |
x = 0; | |
if (std::abs(y) < EPS) | |
y = 0; | |
return std::fabs(x - y) <= Eps * (std::fabs(x) + std::fabs(y)); | |
} | |
friend class Matrix; | |
friend class LUDecomposer; | |
friend class QRDecomposer; | |
}; | |
#include <cmath> | |
class Matrix | |
{ | |
protected: | |
std::vector<Vector> mat; | |
void ListCheck(const std::initializer_list<std::vector<double>>&) const; | |
void RangeCheck(int x) const; | |
void RangeCheck(int x, int y) const; | |
void DimCheck(int, int) const; | |
void DimCheck(int) const; | |
void DimCheck(const Matrix &m) const; | |
void DimCheck(const Matrix &m1, const Matrix &m2) const; | |
void DimCheck(const Vector &v1) const; | |
void DimSameCheck(const Matrix &m1, const Matrix &m2) const; | |
void DimSameCheck(const Matrix &m1) const; | |
void CheckZero(double x, double Eps) const; | |
void SquareCheck() const; | |
void ColSameCheck(const Matrix &m) const; | |
void RowSameCheck(const Matrix &m) const; | |
// Does not do out of bound check! | |
Vector& operator()(int i); | |
Vector operator()(int i) const; | |
double SumAbs() const; | |
public: | |
Matrix(int m, int n); | |
Matrix(const Vector &v); | |
Matrix(std::initializer_list<std::vector<double>> l); | |
int NRows() const; | |
int NCols() const; | |
double* operator[](int i); | |
const double* operator[](int i) const; | |
double &operator()(int i, int j); | |
double operator()(int i, int j) const; | |
void Print(int width = 10) const; | |
friend Matrix operator +(const Matrix &m1, const Matrix &m2); | |
Matrix &operator +=(const Matrix &m); | |
friend Matrix operator -(const Matrix &m1, const Matrix &m2); | |
Matrix &operator -=(const Matrix &m); | |
friend Matrix operator *(double s, const Matrix &m); | |
friend Matrix operator *(const Matrix &m, double s); | |
Matrix &operator *=(double s); | |
friend Matrix operator *(const Matrix &m1, const Matrix &m2); | |
Matrix &operator *=(const Matrix &m); | |
friend Vector operator *(const Matrix &m, const Vector &v); | |
friend Matrix Transpose(const Matrix &m); | |
void Transpose(); | |
friend Matrix LeftDiv(Matrix m1, Matrix m2); | |
friend Vector LeftDiv(Matrix m, Vector v); | |
friend Matrix operator /(const Matrix &m, double s); | |
Matrix operator /=(double s); | |
friend Matrix operator /(Matrix m1, Matrix m2); | |
Matrix operator /=(Matrix m); | |
double Det() const; | |
friend double Det(Matrix m); | |
void Invert(); | |
friend Matrix Inverse(Matrix m); | |
void ReduceToRREF(); | |
Matrix RREF(Matrix m); | |
int Rank() const; | |
friend int Rank(Matrix a); | |
bool operator==(const Matrix &m) const; | |
bool JesuLiJednaki(double x, double y, double Eps) const; | |
~Matrix(); | |
friend class LUDecomposer; | |
friend class QRDecomposer; | |
}; | |
class LUDecomposer | |
{ | |
protected: | |
Matrix lu; | |
Vector w; | |
bool operator== (const LUDecomposer &lud) const; | |
public: | |
LUDecomposer(Matrix m); | |
void Solve(const Vector &b, Vector &x) const; | |
Vector Solve(Vector b) const; | |
void Solve(Matrix &b, Matrix &x) const; | |
Matrix Solve(Matrix b) const; | |
Matrix GetCompactLU() const; | |
Matrix GetL() const; | |
Matrix GetU() const; | |
Vector GetPermutation() const; | |
~LUDecomposer(); | |
}; | |
class QRDecomposer | |
{ | |
protected: | |
Matrix a; | |
Vector d; | |
void RSolve(Vector &b, Vector &x) const; | |
void QRDimCheck(const Matrix &m) const; | |
void QTDimCheck(const Matrix &m) const; | |
void QTDimCheck(const Vector &v) const; | |
void SingularZeroCheck(double x, double Eps = EPS) const; | |
public: | |
QRDecomposer(Matrix m); | |
void Solve(const Vector &b, Vector &x) const; | |
Vector Solve(Vector b) const; | |
void Solve(Matrix &b, Matrix &x) const; | |
Matrix Solve(Matrix b) const; | |
Vector MulQWith(Vector v) const; | |
Matrix MulQWith(Matrix m) const; | |
Vector MulQTWith(Vector v) const; | |
Matrix MulQTWith(Matrix m) const; | |
Matrix GetQ() const; | |
Matrix GetR() const; | |
~QRDecomposer(); | |
}; | |
bool test_1() | |
{ | |
Matrix AA({ {2, 1, 3}, {2, 6, 8}, {6, 8, 18} }); | |
Matrix BB({ {1}, {3}, {5} }); | |
return LeftDiv(AA, BB) == Matrix({ {0.3}, {0.4}, {0.0} }); | |
} | |
bool test_2() | |
{ | |
Matrix AA({ { 2, 1, 3 },{ 2, 6, 8 },{ 6, 8, 18 } }); | |
Vector BB({ 1, 3, 5 }); | |
return LeftDiv(AA, BB) == Vector({ 0.3, 0.4, 0.0 }); | |
} | |
bool test_3() | |
{ | |
Matrix A = Matrix({ { -2, -1, 3 }, { 2, 6, 8 }, { 6, 8, 18 } }); | |
Matrix B = Matrix({ { 10, 3, 5 } }); | |
return (B / A) == Matrix({ { -2.35, -1.925, 1.525 } }); | |
} | |
bool test_4() | |
{ | |
Matrix mat = { {9, 2, 3}, {4, 5, 6}, {7, 8, 9} }; | |
return mat.JesuLiJednaki(-24.0, mat.Det(), 1e-12); | |
} | |
bool test_5() | |
{ | |
Matrix mat = { {9, 2, 3}, {4, 5, 6}, {7, 8, 9} }; | |
return mat.JesuLiJednaki(-24.0, Det(mat), 1e-12); | |
} | |
bool test_6() | |
{ | |
Matrix A = Matrix({ { -2, -1, 3 },{ 2, 6, 8 },{ 6, 8, 18 } }); | |
Matrix B = Matrix({ { 10, 3, 5 } }); | |
B /= A; | |
return B == Matrix({ { -2.35, -1.925, 1.525 } }); | |
} | |
bool test_7() | |
{ | |
Matrix A = Matrix({ { -2, -1, 3 },{ 2, 6, 8 },{ 6, 8, 18 } }); | |
A.Invert(); | |
return A == Matrix({ {-0.275, -0.2625, 0.1625}, | |
{ -0.075, 0.3375, -0.1375 }, | |
{ 0.125, -0.0625, 0.0625} }); | |
} | |
bool test_8() | |
{ | |
Matrix A = Matrix({ { -2, -1, 3 },{ 2, 6, 8 },{ 6, 8, 18 } }); | |
return Inverse(A) == Matrix({ { -0.275, -0.2625, 0.1625 }, | |
{ -0.075, 0.3375, -0.1375 }, | |
{ 0.125, -0.0625, 0.0625 } }); | |
} | |
bool test_9() | |
{ | |
Matrix m = { {3, 4, 18, 34, 0, 2, 31}, {1, -3, -7, -6, 2, 4, 26}, {2, 1, 7, 16, 3, -1, 27}, {5, 11, 43, 74, 2, 0, 56}, {3, -3, -3, 6, -1, 14, 55}, {-2, 0, -4, -12, 1, 5, 6}, {1, -6, -16, -18, 4, 4, 33} }; | |
m.ReduceToRREF(); | |
return m == Matrix( | |
{ | |
{ 1, 0, 2, 6, 0, 0, 7 }, | |
{ 0, 1, 3, 4, 0, 0, 1 }, | |
{ 0, 0, 0, 0, 1, 0, 5 }, | |
{ 0, 0, 0, 0, 0, 1, 3 }, | |
{ 0, 0, 0, 0, 0, 0, 0 }, | |
{ 0, 0, 0, 0, 0, 0, 0 }, | |
{ 0, 0, 0, 0, 0, 0, 0 } | |
}); | |
} | |
bool test_10() | |
{ | |
Matrix m = { { 3, 4, 18, 34, 0, 2, 31 },{ 1, -3, -7, -6, 2, 4, 26 },{ 2, 1, 7, 16, 3, -1, 27 },{ 5, 11, 43, 74, 2, 0, 56 },{ 3, -3, -3, 6, -1, 14, 55 },{ -2, 0, -4, -12, 1, 5, 6 },{ 1, -6, -16, -18, 4, 4, 33 } }; | |
return m.RREF(m) == Matrix( | |
{ | |
{ 1, 0, 2, 6, 0, 0, 7 }, | |
{ 0, 1, 3, 4, 0, 0, 1 }, | |
{ 0, 0, 0, 0, 1, 0, 5 }, | |
{ 0, 0, 0, 0, 0, 1, 3 }, | |
{ 0, 0, 0, 0, 0, 0, 0 }, | |
{ 0, 0, 0, 0, 0, 0, 0 }, | |
{ 0, 0, 0, 0, 0, 0, 0 } | |
}); | |
} | |
bool test_11() | |
{ | |
Matrix m = { { 3, 4, 18, 34, 0, 2, 31 },{ 1, -3, -7, -6, 2, 4, 26 },{ 2, 1, 7, 16, 3, -1, 27 },{ 5, 11, 43, 74, 2, 0, 56 },{ 3, -3, -3, 6, -1, 14, 55 },{ -2, 0, -4, -12, 1, 5, 6 },{ 1, -6, -16, -18, 4, 4, 33 } }; | |
return m.Rank() == 4; | |
} | |
bool test_12() | |
{ | |
Matrix m = { { 3, 4, 18, 34, 0, 2, 31 },{ 1, -3, -7, -6, 2, 4, 26 },{ 2, 1, 7, 16, 3, -1, 27 },{ 5, 11, 43, 74, 2, 0, 56 },{ 3, -3, -3, 6, -1, 14, 55 },{ -2, 0, -4, -12, 1, 5, 6 },{ 1, -6, -16, -18, 4, 4, 33 } }; | |
return Rank(m) == 4; | |
} | |
bool test_13() | |
{ | |
Matrix Z = { { 11,9,24,2 },{ 1,5,2,6 },{ 3,17,18,1 },{ 2,5,7,1 } }; | |
LUDecomposer d(Z); | |
Matrix L = d.GetL(); | |
Matrix U = d.GetU(); | |
Vector W = d.GetPermutation(); | |
Matrix res = L * U; | |
for (int i = 0; i < W.NElems(); i++) | |
for (int j = 0; j < res.NCols(); j++) | |
std::swap(res[i][j], res[(int)W[i]][j]); | |
return (Z == res) && (W == Vector({ 0, 2, 2, 3 })); | |
} | |
bool test_14() | |
{ | |
Matrix Z = { { 1,9,2,2 },{ 1,5,-2,6 },{ 3,7,8,1 },{ 2,5,7,1 } }; | |
Vector V = { 5,9,2,2 }; | |
LUDecomposer d(Z); | |
Vector X(4); | |
d.Solve(V, X); | |
return (Inverse(Z) * V) == X; | |
} | |
bool test_15() | |
{ | |
Matrix Z = { { 1,9,2,2 },{ 1,5,-2,6 },{ 3,7,8,1 },{ 2,5,7,1 } }; | |
Matrix A = { { 5,9,2,2 },{ -1,5,-2,6 },{ -3,10,8,-1 },{ 2,-5,7,1 } }; | |
LUDecomposer d(Z); | |
Matrix X(Z.NRows(), Z.NCols()); | |
d.Solve(A, X); | |
return (Inverse(Z) * A == X); | |
} | |
bool test_16() | |
{ | |
Matrix A = Matrix( | |
{ {6, 8, 2}, | |
{5, 7, 4}, | |
{3, 1,9} } | |
); | |
QRDecomposer qr = QRDecomposer(A); | |
Matrix Q = qr.GetQ(); | |
Matrix R = qr.GetR(); | |
Matrix E = Matrix(Q.NRows(), Q.NCols()); | |
for (int i = 0; i < E.NRows(); i++) | |
E[i][i] = 1.0; | |
return (Q * R == A) && (Q * Transpose(Q) == E); | |
} | |
bool test_17() | |
{ | |
Matrix Z = { { 1,9,2,2 },{ 1,5,-2,6 },{ 3,7,8,1 },{ 2,5,7,1 } }; | |
Vector V = { 5,9,2,2 }; | |
Vector X(V.NElems()); | |
QRDecomposer qr = QRDecomposer(Z); | |
qr.Solve(V, X); | |
return (Inverse(Z) * V == X); | |
} | |
bool test_18() | |
{ | |
Matrix Z = { { 1,9,2,2 },{ 1,5,-2,6 },{ 3,7,8,1 },{ 2,5,7,1 } }; | |
Matrix A = { { 5,9,2,2 },{ -1,5,-2,6 },{ -3,10,8,-1 },{ 2,-5,7,1 } }; | |
Matrix X = A; | |
QRDecomposer qr = QRDecomposer(Z); | |
qr.Solve(A, X); | |
return (Inverse(Z) * A) == X; | |
} | |
bool exc_test1() | |
{ | |
Matrix singular = { { 1, 2, 3, 4 },{ 5, 6, 7, 8 },{ 9, 10, 11, 12 },{ 13, 14, 15, 16 } }; | |
Matrix A = { { -1, 2, 0, 1 }, { 4, 5, 1, 2 }, {3, 2, 6, 8 }, {1, 5, 0, 3} }; | |
putchar('\n'); | |
putchar('\n'); | |
try | |
{ | |
(LeftDiv(singular, A)).Print(); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test2() | |
{ | |
Matrix singular = { { 1, 2, 3, 4 },{ 5, 6, 7, 8 },{ 9, 10, 11, 12 },{ 13, 14, 15, 16 } }; | |
Matrix A = { { -1, 2, 0, 1 },{ 4, 5, 1, 2 },{ 3, 2, 6, 8 },{ 1, 5, 0, 3 } }; | |
Vector v = { 1, 4, 2, 1 }; | |
try | |
{ | |
LeftDiv(singular, v); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test3() | |
{ | |
Matrix badFormat = { {4, 5, 12 },{ 3, 2, 8 },{ 1, 0, 3 } }; | |
Vector v = { 1, 4, 2, 1 }; | |
try | |
{ | |
LeftDiv(badFormat, v); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test4() | |
{ | |
Matrix A = { { 1, 2, 3, 4 }, { 2, 2, 1, 1, } }; | |
try | |
{ | |
A /= 0.0; | |
} | |
catch (std::domain_error r) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test5() | |
{ | |
Matrix singular = { { 1, 2, 3, 4 },{ 5, 6, 7, 8 },{ 9, 10, 11, 12 },{ 13, 14, 15, 16 } }; | |
Matrix b = { { 1, 2, 3, 4 }, { 3, 3, 3, 3 }, {2, 2, 2, 2}, {8, 1, 2, 4 } }; | |
try | |
{ | |
b / singular; | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test6() | |
{ | |
Matrix singular = { { 1, 2, 3, 4 },{ 5, 6, 7, 8 },{ 9, 10, 11, 12 },{ 13, 14, 15, 16 } }; | |
try | |
{ | |
singular.Invert(); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test7() | |
{ | |
Matrix singular = { { 1, 2, 3, 4 },{ 5, 6, 7, 8 },{ 9, 10, 11, 12 },{ 13, 14, 15, 16 } }; | |
try | |
{ | |
Inverse(singular); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test8() | |
{ | |
Matrix singular = { { 1, 2, 3, 4 },{ 5, 6, 7, 8 },{ 9, 10, 11, 12 },{ 13, 14, 15, 16 } }; | |
try | |
{ | |
LUDecomposer lu = LUDecomposer(singular); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test9() | |
{ | |
Matrix m = { { 5, 6, 7, 8 },{ 9, 10, 11, 12 },{ 13, 14, 15, 16 } }; | |
try | |
{ | |
LUDecomposer lu = LUDecomposer(m); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test10() | |
{ | |
Vector v3 = { 1, 2, 3 }; | |
Vector v4 = { 1, 2, 3, 4 }; | |
Matrix z = { { 1,19,2,2 },{ 1,50,-2,6 },{ 30,7,8,1 },{ 2,5,7,1 } }; | |
LUDecomposer lu = LUDecomposer(z); | |
try | |
{ | |
lu.Solve(v3, v4); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test11() | |
{ | |
Vector v3 = { 1, 2, 3 }; | |
Vector v4 = { 1, 2, 3 }; | |
Matrix z = { { 1,19,2,2 },{ 1,50,-2,6 },{ 30,7,8,1 },{ 2,5,7,1 } }; | |
LUDecomposer lu = LUDecomposer(z); | |
try | |
{ | |
lu.Solve(v3, v4); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test12() | |
{ | |
Vector v3 = { 1, 2, 3 }; | |
Matrix z = { { 1,19,2,2 },{ 1,50,-2,6 },{ 30,7,8,1 },{ 2,5,7,1 } }; | |
LUDecomposer lu = LUDecomposer(z); | |
try | |
{ | |
lu.Solve(v3); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test13() | |
{ | |
Matrix z = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 } }; | |
Matrix a = { { 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 } }; | |
LUDecomposer lu = LUDecomposer(z); | |
try | |
{ | |
lu.Solve(a); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test14() | |
{ | |
Matrix z = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 } }; | |
Matrix a = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 } }; | |
Matrix x(4, 3); | |
LUDecomposer lu = LUDecomposer(z); | |
try | |
{ | |
lu.Solve(a, x); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
// NRows() > NCols() | |
bool exc_test15() | |
{ | |
Matrix m = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 } }; | |
try | |
{ | |
QRDecomposer qr = QRDecomposer(m); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test16() | |
{ | |
Matrix m(4, 4); | |
try | |
{ | |
QRDecomposer qr = QRDecomposer(m); | |
} | |
catch (std::domain_error d) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
// QR square check. | |
bool exc_test17() | |
{ | |
Matrix z = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 }, {1, 2, 1, 1} }; | |
QRDecomposer qr(z); | |
Vector v{ 1, 2, 3, 4 }; | |
Vector a(4); | |
try | |
{ | |
qr.Solve(v, a); | |
} | |
catch (std::domain_error e) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
// QR square check. | |
bool exc_test18() | |
{ | |
Matrix z = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 },{ 1, 2, 1, 1 } }; | |
QRDecomposer qr(z); | |
Vector v{ 1, 2, 3, 4 }; | |
Vector a(4); | |
try | |
{ | |
qr.Solve(v); | |
} | |
catch (std::domain_error e) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
// QR Format check | |
bool exc_test19() | |
{ | |
Matrix z = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 },{ 1, 2, 1, 1 } }; | |
QRDecomposer qr(z); | |
Vector v{ 1, 2, 3, 4 }; | |
Vector a(4); | |
try | |
{ | |
qr.Solve(v); | |
} | |
catch (std::domain_error e) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test20() | |
{ | |
Matrix z = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 },{ 1, 2, 1, 1 } }; | |
QRDecomposer qr(z); | |
Matrix x = { { 1 } }; | |
try | |
{ | |
qr.MulQTWith(x); | |
} | |
catch (std::domain_error e) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test21() | |
{ | |
Matrix z = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 },{ 1, 2, 1, 1 } }; | |
QRDecomposer qr(z); | |
Vector x { 1, 2 }; | |
try | |
{ | |
qr.MulQTWith(x); | |
} | |
catch (std::domain_error e) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
bool exc_test22() | |
{ | |
Matrix z = { { 1,-19,122,2 },{ 1,50,-2,6 },{ 130,7,8,1 },{ -12,500,7,221 },{ 1, 2, 1, 1 } }; | |
QRDecomposer qr(z); | |
Matrix x{ { 1, 2 } }; | |
try | |
{ | |
qr.MulQTWith(x); | |
} | |
catch (std::domain_error e) { return true; } | |
catch (...) { return false; } | |
return false; | |
} | |
std::vector<std::function<bool()>> tests; | |
std::vector<std::function<bool()>> exc_tests; | |
void initTests() | |
{ | |
tests.push_back(test_1); | |
tests.push_back(test_2); | |
tests.push_back(test_3); | |
tests.push_back(test_4); | |
tests.push_back(test_5); | |
tests.push_back(test_6); | |
tests.push_back(test_7); | |
tests.push_back(test_8); | |
tests.push_back(test_9); | |
tests.push_back(test_10); | |
tests.push_back(test_11); | |
tests.push_back(test_12); | |
tests.push_back(test_13); | |
tests.push_back(test_14); | |
tests.push_back(test_15); | |
tests.push_back(test_16); | |
tests.push_back(test_17); | |
tests.push_back(test_18); | |
} | |
void initExcTests() | |
{ | |
exc_tests.push_back(exc_test1); | |
exc_tests.push_back(exc_test2); | |
exc_tests.push_back(exc_test3); | |
exc_tests.push_back(exc_test4); | |
exc_tests.push_back(exc_test5); | |
exc_tests.push_back(exc_test6); | |
exc_tests.push_back(exc_test7); | |
exc_tests.push_back(exc_test8); | |
exc_tests.push_back(exc_test9); | |
exc_tests.push_back(exc_test10); | |
exc_tests.push_back(exc_test11); | |
exc_tests.push_back(exc_test12); | |
exc_tests.push_back(exc_test13); | |
exc_tests.push_back(exc_test14); | |
exc_tests.push_back(exc_test15); | |
exc_tests.push_back(exc_test16); | |
exc_tests.push_back(exc_test17); | |
exc_tests.push_back(exc_test18); | |
exc_tests.push_back(exc_test19); | |
exc_tests.push_back(exc_test20); | |
exc_tests.push_back(exc_test21); | |
exc_tests.push_back(exc_test22); | |
} | |
void runTests() | |
{ | |
for (int i = 0; i < (int)tests.size(); i++) | |
std::cout << "Test number " << i + 1 << ": " << ((tests[i]()) ? "OK\n" : "BAD\n"); | |
} | |
void runExcTests() | |
{ | |
for (int i = 0; i < (int)exc_tests.size(); i++) | |
std::cout << "Exception test number " << i + 1 << ": " << ((exc_tests[i]()) ? "OK\n" : "BAD\n"); | |
} | |
void test() | |
{ | |
initTests(); | |
initExcTests(); | |
runTests(); | |
putchar('\n'); | |
runExcTests(); | |
} | |
#include <iostream> | |
void Vector::DimCheck(int n) const | |
{ | |
if (n <= 0) | |
throw std::range_error("Bad dimension"); | |
} | |
void Vector::CheckZero(double x) const | |
{ | |
if (JesuLiJednaki(x, 0)) | |
throw std::domain_error("Division by zero"); | |
} | |
void Vector::PushBack(const double & elem) | |
{ | |
elements.push_back(elem); | |
} | |
void Vector::DimCheck(const Vector & v1, const Vector & v2) const | |
{ | |
if (v1.NElems() != v2.NElems()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
void Vector::DimCheck(const Vector &v) const | |
{ | |
if (NElems() != v.NElems()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
void Vector::RangeCheck(int index) const | |
{ | |
if (index < 0 || NElems() <= index) | |
throw std::range_error("Invalid index"); | |
} | |
Vector& Vector::ForEach(const std::function<double(double)>& f) | |
{ | |
for (auto &x : elements) | |
x = f(x); | |
return (*this); | |
} | |
Vector::Vector(int n) | |
{ | |
DimCheck(n); | |
elements.resize(n, 0); | |
} | |
Vector::Vector(std::initializer_list<double> l) | |
{ | |
DimCheck(l.size()); | |
elements = l; | |
} | |
Vector::Vector(const std::vector<double>& v) | |
{ | |
DimCheck(v.size()); | |
elements = v; | |
} | |
int Vector::NElems() const | |
{ | |
return elements.size(); | |
} | |
double & Vector::operator[](int i) | |
{ | |
RangeCheck(i); | |
return elements[i]; | |
} | |
double Vector::operator[](int i) const | |
{ | |
RangeCheck(i); | |
return elements[i]; | |
} | |
double & Vector::operator()(int i) | |
{ | |
i--; | |
RangeCheck(i); | |
return elements[i]; | |
} | |
double Vector::operator()(int i) const | |
{ | |
i--; | |
RangeCheck(i); | |
return elements[i]; | |
} | |
void Vector::Print(char separator) const | |
{ | |
bool first(true); | |
for (auto x : elements) | |
{ | |
if (!first) | |
printf("%c", separator); | |
std::cout << x; | |
if (first) | |
first = false; | |
} | |
} | |
Vector & Vector::operator+=(const Vector & v) | |
{ | |
DimCheck(v); | |
for (int i = 0; i < v.NElems(); i++) | |
elements[i] += v[i]; | |
return (*this); | |
} | |
Vector & Vector::operator-=(const Vector & v) | |
{ | |
DimCheck(v); | |
for (int i = 0; i < v.NElems(); i++) | |
elements[i] -= v[i]; | |
return (*this); | |
} | |
Vector & Vector::operator*=(double s) | |
{ | |
return ForEach([&s](double x) { return x * s; }); | |
} | |
Vector & Vector::operator/=(double s) | |
{ | |
CheckZero(s); | |
ForEach([&s](double x) -> double { return x / s; }); | |
return (*this); | |
} | |
bool Vector::operator==(const Vector & v) const | |
{ | |
for (int i = 0; i < v.NElems(); i++) | |
if (!JesuLiJednaki(elements[i], v[i], 1e-12)) | |
return false; | |
return true; | |
} | |
bool Vector::operator!=(const Vector & v) const | |
{ | |
for (int i = 0; i < v.NElems(); i++) | |
if (JesuLiJednaki(elements[i], v[i], 1e-12)) | |
return false; | |
return true; | |
} | |
Vector::~Vector() | |
{ | |
} | |
Vector operator+(const Vector & v1, const Vector & v2) | |
{ | |
v1.DimCheck(v2); | |
Vector ret(v1.NElems()); | |
for (int i = 0; i < v1.NElems(); i++) | |
ret[i] = (v1[i] + v2[i]); | |
return ret; | |
} | |
Vector operator-(const Vector & v1, const Vector & v2) | |
{ | |
v1.DimCheck(v2); | |
Vector ret(v1.NElems()); | |
for (int i = 0; i < v1.NElems(); i++) | |
ret[i] = (v1[i] - v2[i]); | |
return ret; | |
} | |
Vector operator*(double s, const Vector &v) | |
{ | |
Vector ret = v; | |
return ret.ForEach([&s](double x) { return x * s; }); | |
} | |
Vector operator*(const Vector & v, double s) | |
{ | |
Vector ret = v; | |
return ret.ForEach([&s](double x) { return x * s; }); | |
} | |
double operator*(const Vector & v1, const Vector & v2) | |
{ | |
v1.DimCheck(v2); | |
double ret = 0.0; | |
for (int i = 0; i < v1.NElems(); i++) | |
ret += v1[i] * v2[i]; | |
return ret; | |
} | |
Vector operator/(const Vector & v, double s) | |
{ | |
v.CheckZero(s); | |
Vector ret = v; | |
ret.ForEach([&s](double x) -> double { return x / s; }); | |
return ret; | |
} | |
#include <iostream> | |
#include <iomanip> | |
#include <cstdio> | |
#include <vector> | |
void Matrix::ListCheck(const std::initializer_list<std::vector<double>> &l) const | |
{ | |
if (!l.size()) | |
throw std::range_error("Bad dimension"); | |
int first = l.begin()->size(); | |
for (auto item : l) | |
if (item.size() == 0) | |
throw std::range_error("Bad dimension"); | |
else if (item.size() != first) | |
throw std::logic_error("Bad matrix"); | |
} | |
void Matrix::RangeCheck(int x) const | |
{ | |
if (mat.empty() || x < 0 || (int)mat.size() <= x) | |
throw std::range_error("Invalid index"); | |
} | |
void Matrix::RangeCheck(int x, int y) const | |
{ | |
if (mat.empty() || (int)mat.size() < x || mat[0].NElems() < y) | |
throw std::range_error("Invalid index"); | |
} | |
void Matrix::DimCheck(int n, int m) const | |
{ | |
if (n <= 0 || m <= 0) | |
throw std::range_error("Bad dimension"); | |
} | |
void Matrix::DimCheck(int n) const | |
{ | |
if (n < 0 || n >= NRows()) | |
throw std::range_error("Bad dimensions"); | |
} | |
void Matrix::DimCheck(const Matrix & m) const | |
{ | |
if (NCols() != m.NRows()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
void Matrix::CheckZero(double x, double Eps) const | |
{ | |
if (std::abs(x) < Eps) | |
throw std::domain_error("Division by zero"); | |
} | |
// assumes matrix is not empty | |
void Matrix::SquareCheck() const | |
{ | |
if (NCols() != NRows()) | |
throw std::domain_error("Divisor matrix is singular"); | |
} | |
void Matrix::ColSameCheck(const Matrix & m) const | |
{ | |
if (NCols() != m.NCols()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
void Matrix::RowSameCheck(const Matrix & m) const | |
{ | |
if (NRows() != m.NRows()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
Vector & Matrix::operator()(int i) | |
{ | |
return mat[i - 1]; | |
} | |
Vector Matrix::operator()(int i) const | |
{ | |
return mat[i - 1]; | |
} | |
double Matrix::SumAbs() const | |
{ | |
double sum = 0; | |
for (int i = 0; i < NRows(); i++) | |
for (int j = 0; j < NCols(); j++) | |
sum += std::abs(mat[i][j]); | |
return sum; | |
} | |
void Matrix::DimCheck(const Matrix & m1, const Matrix & m2) const | |
{ | |
m1.DimCheck(m2); | |
} | |
void Matrix::DimCheck(const Vector & v1) const | |
{ | |
if (NCols() != v1.NElems()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
void Matrix::DimSameCheck(const Matrix & m1, const Matrix & m2) const | |
{ | |
if (m1.NRows() != m2.NRows() || m2.NCols() != m2.NCols()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
void Matrix::DimSameCheck(const Matrix & m1) const | |
{ | |
if (NRows() != m1.NRows() || NCols() != m1.NCols()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
Matrix::Matrix(int n, int m) | |
{ | |
DimCheck(n, m); | |
mat.resize(n, Vector(m)); | |
} | |
Matrix::Matrix(const Vector & v) | |
{ | |
mat.resize(v.NElems(), Vector(1)); | |
mat[0] = v; | |
} | |
Matrix::Matrix(std::initializer_list<std::vector<double>> l) | |
{ | |
ListCheck(l); | |
for (auto item : l) | |
mat.push_back(Vector(item)); | |
} | |
int Matrix::NRows() const | |
{ | |
return mat.size(); | |
} | |
int Matrix::NCols() const | |
{ | |
return mat[0].NElems(); | |
} | |
double* Matrix::operator[](int i) | |
{ | |
RangeCheck(i); | |
return mat[i].elements.data(); | |
} | |
const double* Matrix::operator[](int i) const | |
{ | |
RangeCheck(i); | |
return mat[i].elements.data(); | |
} | |
double & Matrix::operator()(int i, int j) | |
{ | |
i--; | |
j--; | |
RangeCheck(i, j); | |
return mat[i][j]; | |
} | |
double Matrix::operator()(int i, int j) const | |
{ | |
i--; | |
j--; | |
RangeCheck(i, j); | |
return mat[i][j]; | |
} | |
void Matrix::Print(int width) const | |
{ | |
for (int i = 0; i < (int)mat.size(); i++) | |
{ | |
for (int j = 0; j < mat[i].NElems(); j++) | |
std::cout << std::setw(width) << mat[i][j]; | |
if (i < (int)mat.size() - 1) | |
std::putchar('\n'); | |
} | |
} | |
Matrix & Matrix::operator+=(const Matrix & m) | |
{ | |
DimSameCheck(m); | |
for (int i = 0; i < m.NRows(); i++) | |
for (int j = 0; j < m.NCols(); j++) | |
mat[i][j] += m[i][j]; | |
return (*this); | |
} | |
Matrix & Matrix::operator-=(const Matrix & m) | |
{ | |
DimSameCheck(m); | |
for (int i = 0; i < m.NRows(); i++) | |
for (int j = 0; j < m.NCols(); j++) | |
mat[i][j] -= m[i][j]; | |
return (*this); | |
} | |
Matrix & Matrix::operator*=(double s) | |
{ | |
for (int i = 0; i < NRows(); i++) | |
for (int j = 0; j < NCols(); j++) | |
mat[i][j] *= s; | |
return (*this); | |
} | |
void Matrix::Transpose() | |
{ | |
if (NCols() == NRows()) | |
{ | |
for (int i = 0; i < NRows() - 1; i++) | |
for (int j = i + 1; j < NCols(); j++) | |
std::swap(mat[i][j], mat[j][i]); | |
} | |
else | |
{ | |
Matrix help = Matrix(NCols(), NRows()); | |
for (int i = 0; i < help.NRows(); i++) | |
for (int j = 0; j < help.NCols(); j++) | |
help[i][j] = mat[j][i]; | |
(*this) = help; | |
} | |
} | |
bool Matrix::operator==(const Matrix & m) const | |
{ | |
if (NRows() != m.NRows() || NCols() != m.NCols()) | |
return false; | |
for (int i = 0; i < m.NRows(); i++) | |
for (int j = 0; j < m.NCols(); j++) | |
if (!JesuLiJednaki(mat[i][j], m[i][j], 1e-12)) | |
return false; | |
return true; | |
} | |
bool Matrix::JesuLiJednaki(double x, double y, double Eps) const | |
{ | |
if (std::abs(x) < Eps) | |
x = 0; | |
if (std::abs(y) < Eps) | |
y = 0; | |
return std::abs(x - y) <= Eps * (std::abs(x) + std::abs(y)); | |
} | |
Matrix::~Matrix() | |
{ | |
} | |
Matrix Matrix::operator/=(double s) | |
{ | |
CheckZero(s, EPS); | |
for (int i = 0; i < NRows(); i++) | |
for (int j = 0; j < NCols(); j++) | |
mat[i][j] /= s; | |
return (*this); | |
} | |
Matrix Matrix::operator/=(Matrix B) | |
{ | |
Matrix &A = (*this); | |
B.SquareCheck(); | |
A.DimCheck(B); | |
int n = B.NRows(); | |
int m = A.NCols(); | |
double sum = B.SumAbs(); | |
for (int k = 1; k <= B.NCols(); k++) | |
{ | |
int p = k; | |
for (int i = k + 1; i <= n; i++) | |
if (std::abs(B[k - 1][i - 1]) > std::abs(B[k - 1][p - 1])) | |
p = i; | |
if (std::abs(B[k - 1][p - 1]) <= EPS * sum) | |
throw std::domain_error("Divisor matrix is singular"); | |
if (p != k) | |
{ | |
for (int j = 1; j <= n; j++) | |
std::swap(B[j - 1][k - 1], B[j - 1][p - 1]); | |
for (int j = 1; j <= A.NRows(); j++) | |
std::swap(A[j - 1][k - 1], A[j - 1][p - 1]); | |
} | |
for (int i = k + 1; i <= B.NCols(); i++) | |
{ | |
double mi = B(k, i) / B(k, k); | |
for (int j = 1; j <= B.NRows(); j++) | |
B[j - 1][i - 1] -= mi * B[j - 1][k - 1]; | |
for (int j = 1; j <= A.NRows(); j++) | |
A[j - 1][i - 1] -= mi * A[j - 1][k - 1]; | |
} | |
} | |
Matrix X = Matrix(A.NRows(), B.NCols()); | |
for (int k = 1; k <= A.NRows(); k++) | |
{ | |
for (int i = A.NCols(); i >= 1; i--) | |
{ | |
double s = A[k - 1][i - 1]; | |
for (int j = i + 1; j <= A.NCols(); j++) | |
s -= B[j - 1][i - 1] * X[k - 1][j - 1]; | |
X[k - 1][i - 1] = s / B[i - 1][i - 1]; | |
} | |
} | |
A = X; | |
return X; | |
} | |
double Matrix::Det() const | |
{ | |
SquareCheck(); | |
double d = 1; | |
int n = NRows(); | |
Matrix a(*this); | |
double sum = SumAbs(); | |
for (int k = 0; k < n; k++) | |
{ | |
int p = k; | |
for (int i = k + 1; i < n; i++) | |
if (std::abs(a[i][k]) > std::abs(a[p][k])) | |
p = i; | |
if (std::abs(a[p][k]) < EPS * sum) | |
return 0.0; | |
if (p != k) | |
{ | |
d *= -1.0; | |
std::swap(a(k + 1), a(p + 1)); | |
} | |
for (int i = k + 1; i < n; i++) | |
{ | |
double mi = a[i][k] / a[k][k]; | |
for (int j = k + 1; j < n; j++) | |
a[i][j] -= mi * a[k][j]; | |
} | |
} | |
for (int i = 0; i < n; i++) | |
d *= a[i][i]; | |
return d; | |
} | |
// Square check | |
void Matrix::Invert() | |
{ | |
SquareCheck(); | |
Matrix& a = (*this); // NOTE: Does not create another matrix! | |
int n = NRows(); | |
std::vector<int>w(n); | |
double sum = a.SumAbs(); | |
for (int k = 1; k <= n; k++) | |
{ | |
int p = k; | |
for (int i = k + 1; i <= n; i++) | |
if (std::abs(a[i - 1][k - 1]) > std::abs(a[p - 1][k - 1])) | |
p = i; | |
if (std::abs(a[p - 1][k - 1]) < EPS * sum) | |
throw std::domain_error("Matrix is singular"); | |
if (p != k) | |
std::swap(a(k), a(p)); | |
w[k - 1] = p; | |
double mi = a[k - 1][k - 1]; | |
a[k - 1][k - 1] = 1.0; | |
a(k) /= mi; | |
for (int i = 1; i <= n; i++) | |
{ | |
if (i != k) | |
{ | |
mi = a[i - 1][k - 1]; | |
a[i - 1][k - 1] = 0.0; | |
for (int j = 1; j <= n; j++) | |
a[i - 1][j - 1] -= mi * a[k - 1][j - 1]; | |
} | |
} | |
} | |
for (int j = n; j >= 1; j--) | |
{ | |
int p = w[j - 1]; | |
if (p != j) | |
for (int i = 1; i <= n; i++) | |
std::swap(a[i - 1][p - 1], a[i - 1][j - 1]); | |
} | |
} | |
void Matrix::ReduceToRREF() | |
{ | |
int k = 0; | |
int l = 0; | |
int n = NRows(); | |
int m = NCols(); | |
std::vector<int>w(n, 0); | |
Matrix &a = (*this); | |
double sum = SumAbs(); | |
while (k <= m && l <= n) | |
{ | |
l++; | |
k++; | |
double v = 0; | |
int p = 0; | |
while (v < EPS * sum && l <= n) | |
{ | |
p = k; | |
for (int i = k; i <= m; i++) | |
{ | |
if (std::abs(a[i - 1][l - 1]) > v) | |
{ | |
v = std::abs(a[i - 1][l - 1]); | |
p = i; | |
} | |
} | |
if (v < EPS * sum) | |
l++; | |
} | |
if (l <= n) | |
{ | |
w[l - 1] = true; | |
if (p != k) | |
std::swap(a(k), a(p)); | |
double mi = a[k - 1][l - 1]; | |
for (int j = l; j <= n; j++) | |
a[k - 1][j - 1] /= mi; | |
for (int i = 1; i <= m; i++) | |
{ | |
if (i != k) | |
{ | |
mi = a[i - 1][l - 1]; | |
for (int j = l; j <= n; j++) | |
a[i - 1][j - 1] -= mi * a[k - 1][j - 1]; | |
} | |
} | |
} | |
} | |
} | |
Matrix Matrix::RREF(Matrix m) | |
{ | |
m.ReduceToRREF(); | |
return m; | |
} | |
int Matrix::Rank() const | |
{ | |
int k = 0; | |
int l = 0; | |
int n = NRows(); | |
int m = NCols(); | |
std::vector<int>w(n, 0); | |
Matrix a = (*this); | |
double sum = SumAbs(); | |
while (k <= m && l <= n) | |
{ | |
l++; | |
k++; | |
double v = 0; | |
int p = 0; | |
while (v < EPS * sum && l <= n) | |
{ | |
p = k; | |
for (int i = k; i <= m; i++) | |
{ | |
if (std::abs(a[i - 1][l - 1]) > v) | |
{ | |
v = std::abs(a[i - 1][l - 1]); | |
p = i; | |
} | |
} | |
if (v < EPS * sum) | |
l++; | |
} | |
if (l <= n) | |
{ | |
w[l - 1] = true; | |
if (p != k) | |
std::swap(a(k), a(p)); | |
double mi = a[k - 1][l - 1]; | |
for (int j = l; j <= n; j++) | |
a[k - 1][j - 1] /= mi; | |
for (int i = 1; i <= m; i++) | |
{ | |
if (i != k) | |
{ | |
mi = a[i - 1][l - 1]; | |
for (int j = l; j <= n; j++) | |
a[i - 1][j - 1] -= mi * a[k - 1][j - 1]; | |
} | |
} | |
} | |
} | |
return k - 1; | |
} | |
Matrix operator+(const Matrix & m1, const Matrix & m2) | |
{ | |
m1.DimSameCheck(m2); | |
Matrix m = m1; | |
for (int i = 0; i < m1.NRows(); i++) | |
for (int j = 0; j < m2.NCols(); j++) | |
m[i][j] += m2[i][j]; | |
return m; | |
} | |
Matrix operator-(const Matrix & m1, const Matrix & m2) | |
{ | |
m1.DimSameCheck(m2); | |
Matrix m = m1; | |
for (int i = 0; i < m1.NRows(); i++) | |
for (int j = 0; j < m2.NCols(); j++) | |
m[i][j] -= m2[i][j]; | |
return m; | |
} | |
Matrix operator*(double s, const Matrix & m) | |
{ | |
Matrix ret = m; | |
for (int i = 0; i < m.NRows(); i++) | |
for (int j = 0; j < m.NCols(); j++) | |
ret[i][j] *= s; | |
return ret; | |
} | |
Matrix operator*(const Matrix & m, double s) | |
{ | |
Matrix ret = m; | |
for (int i = 0; i < m.NRows(); i++) | |
for (int j = 0; j < m.NCols(); j++) | |
ret[i][j] *= s; | |
return ret; | |
} | |
Matrix operator*(const Matrix & m1, const Matrix & m2) | |
{ | |
m1.DimCheck(m2); | |
Matrix ret(m1.NRows(), m2.NCols()); | |
for (int i = 0; i < m1.NRows(); i++) | |
for (int j = 0; j < m2.NCols(); j++) | |
for (int k = 0; k < m1.NCols(); k++) | |
ret.mat[i][j] += (m1[i][k] * m2[k][j]); | |
return ret; | |
} | |
Vector operator*(const Matrix & m, const Vector & v) | |
{ | |
m.DimCheck(v); | |
Vector ret = Vector(m.NRows()); | |
for (int i = 0; i < m.NRows(); i++) | |
for (int j = 0; j < m.NCols(); j++) | |
ret[i] += m[i][j] * v[j]; | |
return ret; | |
} | |
Matrix Transpose(const Matrix & m) | |
{ | |
Matrix ret = Matrix(m.NCols(), m.NRows()); | |
for (int i = 0; i < ret.NRows(); i++) | |
for (int j = 0; j < ret.NCols(); j++) | |
ret[i][j] = m[j][i]; | |
return ret; | |
} | |
// Square check | |
// Format check | |
// Singular check | |
Matrix LeftDiv(Matrix A, Matrix B) | |
{ | |
A.SquareCheck(); | |
A.DimCheck(B); | |
int n = A.NRows(); | |
int m = B.NCols(); | |
double sum = 0.0; | |
for (int k = 1; k <= n; k++) | |
{ | |
int p = k; | |
for (int i = k + 1; i <= n; i++) | |
{ | |
sum += std::abs(A[i - 1][k - 1]); | |
if (std::abs(A[i - 1][k - 1]) > std::abs(A[p - 1][k - 1])) | |
p = i; | |
} | |
if (std::abs(A[p - 1][k - 1]) <= EPS * sum) | |
throw std::domain_error("Divisor matrix is singular"); | |
if (p != k) | |
{ | |
std::swap(A(k), A(p)); | |
std::swap(B(k), B(p)); | |
} | |
for (int i = k + 1; i <= n; i++) | |
{ | |
double mi = A[i - 1][k - 1] / A[k - 1][k - 1]; | |
A(i) -= mi * A(k); | |
B(i) -= mi * B(k); | |
} | |
} | |
Matrix X = Matrix(n, m); | |
for (int k = 1; k <= m; k++) | |
{ | |
for (int i = n; i >= 1; i--) | |
{ | |
double s = B[i - 1][k - 1]; | |
for (int j = i + 1; j <= n; j++) | |
s -= A[i - 1][j - 1] * X[j - 1][k - 1]; | |
X[i - 1][k - 1] = s / A[i - 1][i - 1]; | |
} | |
} | |
return X; | |
} | |
// Square check | |
// Format check | |
// Singular check | |
Vector LeftDiv(Matrix A, Vector B) | |
{ | |
A.SquareCheck(); | |
A.DimCheck(B); | |
int n = A.NRows(); | |
int m = B.NElems(); | |
double sum = 0.0; | |
for (int k = 1; k <= n; k++) | |
{ | |
int p = k; | |
for (int i = k + 1; i <= n; i++) | |
{ | |
sum += std::abs(A[i - 1][k - 1]); | |
if (std::abs(A[i - 1][k - 1]) > std::abs(A[p - 1][k - 1])) | |
p = i; | |
} | |
if (std::abs(A[p - 1][k - 1]) <= EPS * sum) | |
throw std::domain_error("Divisor matrix is singular"); | |
if (p != k) | |
{ | |
std::swap(A(k), A(p)); | |
std::swap(B(k), B(p)); | |
} | |
for (int i = k + 1; i <= n; i++) | |
{ | |
double mi = A[i - 1][k - 1] / A[k - 1][k - 1]; | |
A(i) -= mi * A(k); | |
B(i) -= mi * B(k); | |
} | |
} | |
Vector X = Vector(n); | |
for (int k = 1; k <= m; k++) | |
{ | |
for (int i = n; i >= 1; i--) | |
{ | |
double s = B[i - 1]; | |
for (int j = i + 1; j <= n; j++) | |
s -= A(i, j) * X(j); | |
X(i) = s / A[i - 1][i - 1]; | |
} | |
} | |
return X; | |
} | |
// Zero check | |
Matrix operator/(const Matrix & m, double s) | |
{ | |
m.CheckZero(s, EPS); | |
Matrix ret = m; | |
for (int i = 0; i < ret.NRows(); i++) | |
for (int j = 0; j < ret.NCols(); j++) | |
ret[i][j] /= s; | |
return ret; | |
} | |
// Format check | |
// Singular check | |
// Square check | |
Matrix operator/(Matrix A, Matrix B) | |
{ | |
B.SquareCheck(); | |
A.DimCheck(B); | |
int n = B.NRows(); | |
int m = A.NCols(); | |
double sum = 0.0; | |
for (int k = 1; k <= B.NCols(); k++) | |
{ | |
int p = k; | |
for (int i = k + 1; i <= n; i++) | |
{ | |
sum += std::abs(B[k - 1][i - 1]); | |
if (std::abs(B(k, i)) > std::abs(B(k, p))) | |
p = i; | |
} | |
if (std::abs(B(k, p)) <= EPS * sum) | |
throw std::domain_error("Divisor matrix is singular"); | |
if (p != k) | |
{ | |
for (int j = 1; j <= n; j++) | |
std::swap(B[j - 1][k - 1], B[j - 1][p - 1]); | |
for (int j = 1; j <= A.NRows(); j++) | |
std::swap(A[j - 1][k - 1], A[j - 1][p - 1]); | |
} | |
for (int i = k + 1; i <= B.NCols(); i++) | |
{ | |
double mi = B(k, i) / B(k, k); | |
for (int j = 1; j <= B.NRows(); j++) | |
B[j - 1][i - 1] -= mi * B[j - 1][k - 1]; | |
for (int j = 1; j <= A.NRows(); j++) | |
A[j - 1][i - 1] -= mi * A[j - 1][k - 1]; | |
} | |
} | |
Matrix X = Matrix(A.NRows(), B.NCols()); | |
for (int k = 1; k <= A.NRows(); k++) | |
{ | |
for (int i = A.NCols(); i >= 1; i--) | |
{ | |
double s = A(k, i); | |
for (int j = i + 1; j <= A.NCols(); j++) | |
s -= B(j, i) * X(k, j); | |
X(k, i) = s / B(i, i); | |
} | |
} | |
return X; | |
} | |
// Square check | |
double Det(Matrix m) | |
{ | |
m.SquareCheck(); | |
double d = 1; | |
int n = m.NRows(); | |
// Ne oduzimati bodove zbog ovog jer ne pravim novi objekat. | |
Matrix& a = m; | |
double sum = 0.0; | |
for (int k = 0; k < n; k++) | |
{ | |
int p = k; | |
for (int i = k + 1; i < n; i++) | |
{ | |
if (std::abs(a[i][k]) > std::abs(a[p][k])) | |
p = i; | |
sum += a[i][k]; | |
} | |
if (std::abs(a[p][k]) < EPS * sum) | |
return 0.0; | |
if (p != k) | |
{ | |
d *= -1.0; | |
std::swap(a(k + 1), a(p + 1)); | |
} | |
for (int i = k + 1; i < n; i++) | |
{ | |
double mi = a[i][k] / a[k][k]; | |
for (int j = k + 1; j < n; j++) | |
a[i][j] -= mi * a[k][j]; | |
} | |
} | |
for (int i = 0; i < n; i++) | |
d *= a[i][i]; | |
return d; | |
} | |
// Square check | |
// Singular check | |
Matrix Inverse(Matrix m) | |
{ | |
m.SquareCheck(); | |
m.Invert(); | |
return m; | |
} | |
int Rank(Matrix a) | |
{ | |
int k = 0; | |
int l = 0; | |
int n = a.NRows(); | |
int m = a.NCols(); | |
std::vector<int>w(n, 0); | |
double sum = a.SumAbs(); | |
while (k <= m && l <= n) | |
{ | |
l++; | |
k++; | |
double v = 0; | |
int p = 0; | |
while (v < EPS * sum && l <= n) | |
{ | |
p = k; | |
for (int i = k; i <= m; i++) | |
{ | |
if (std::abs(a[i - 1][l - 1]) > v) | |
{ | |
v = std::abs(a[i - 1][l - 1]); | |
p = i; | |
} | |
} | |
if (v < EPS * sum) | |
l++; | |
} | |
if (l <= n) | |
{ | |
w[l - 1] = true; | |
if (p != k) | |
std::swap(a(k), a(p)); | |
double mi = a[k - 1][l - 1]; | |
for (int j = l; j <= n; j++) | |
a[k - 1][j - 1] /= mi; | |
for (int i = 1; i <= m; i++) | |
{ | |
if (i != k) | |
{ | |
mi = a[i - 1][l - 1]; | |
for (int j = l; j <= n; j++) | |
a[i - 1][j - 1] -= mi * a[k - 1][j - 1]; | |
} | |
} | |
} | |
} | |
return k - 1; | |
} | |
Matrix & Matrix::operator*=(const Matrix & m) | |
{ | |
DimCheck(m); | |
Matrix ret(NRows(), m.NCols()); | |
for (int i = 0; i < NRows(); i++) | |
for (int j = 0; j < m.NCols(); j++) | |
for (int k = 0; k < NCols(); k++) | |
ret.mat[i][j] += (mat[i][k] * m[k][j]); | |
(*this) = ret; | |
return (*this); | |
} | |
template<class T> | |
T fast_pow(const T &base, const T &e, int power) | |
{ | |
if (power == 0) | |
return e; | |
else if (power == 1) | |
return base; | |
else if (power % 2 == 0) | |
{ | |
T t = fast_pow(base, e, power / 2); | |
return t * t; | |
} | |
else | |
{ | |
return fast_pow(base, e, power - 1) * base; | |
} | |
} | |
// NOTE: Only used for testing purposes | |
bool LUDecomposer::operator==(const LUDecomposer & lud) const | |
{ | |
return lu == lud.lu; | |
} | |
LUDecomposer::~LUDecomposer() | |
{ | |
} | |
// Square check. | |
// Singular check. | |
LUDecomposer::LUDecomposer(Matrix a) : lu(a), w(a.NRows()) | |
{ | |
lu.SquareCheck(); | |
int n = lu.NRows(); | |
int m = lu.NRows(); | |
int p = 0; | |
double s; | |
double sum = lu.SumAbs(); | |
for (int j = 0; j < n; j++) | |
{ | |
for (int i = 0; i <= j; i++) | |
{ | |
s = lu[i][j]; | |
for (int k = 0; k < i; k++) | |
s -= lu[i][k] * lu[k][j]; | |
lu[i][j] = s; | |
} | |
p = j; | |
for (int i = j + 1; i < n; i++) | |
{ | |
sum += std::abs(lu[i][j]); | |
s = lu[i][j]; | |
for (int k = 0; k <= j - 1; k++) | |
s -= lu[i][k] * lu[k][j]; | |
lu[i][j] = s; | |
if (std::abs(s) > std::abs(lu[p][j])) | |
p = i; | |
} | |
if (std::abs(lu[p][j]) < EPS * sum) | |
throw std::domain_error("Matrix is singular"); | |
if (p != j) | |
std::swap(lu(j + 1), lu(p + 1)); | |
w[j] = p; | |
double mi = 1 / lu[j][j]; | |
for (int i = j + 1; i < n; i++) | |
lu[i][j] *= mi; | |
} | |
} | |
/* | |
Jos ovu noc za njene oci | |
jos ovu noc za njeno lice | |
hej sviracu stimaj zice | |
*/ | |
// Incompatible formats. | |
void LUDecomposer::Solve(const Vector & b, Vector & x) const | |
{ | |
lu.DimCheck(b); | |
b.DimCheck(x); // It works, trust me. | |
x = b; | |
int n = b.NElems(); | |
Matrix l = GetL(); | |
Matrix u = GetU(); | |
for (int i = 0; i < n; i++) | |
{ | |
double s = x[(int)w[i]]; | |
x[(int)w[i]] = x[i]; | |
for (int j = 0; j < i; j++) | |
s -= l[i][j] * x[j]; | |
x[i] = s; | |
} | |
for (int i = n - 1; i > -1; i--) | |
{ | |
double s = x[i]; | |
for (int j = i + 1; j < n; j++) | |
s -= u[i][j] * x[j]; | |
x[i] = s / u[i][i]; | |
} | |
} | |
// Incompatible formats. | |
Vector LUDecomposer::Solve(Vector b) const | |
{ | |
lu.DimCheck(b); | |
int n = b.NElems(); | |
Vector y(n); | |
Matrix l = GetL(); | |
Matrix u = GetU(); | |
Vector x(n); | |
double s; | |
for (int i = 0; i < n; i++) | |
{ | |
std::swap(b[i], b[(int)w[i]]); | |
s = b[i]; | |
for (int j = 0; j < i; j++) | |
s -= l[i][j] * y[j]; | |
y[i] = s; | |
} | |
for (int i = n - 1; i > -1; i--) | |
{ | |
s = y[i]; | |
for (int j = i + 1; j < n; j++) | |
s -= u[i][j] * y[j]; | |
x[i] = s / u[i][i]; | |
} | |
return x; | |
} | |
// Incompatible formats. | |
void LUDecomposer::Solve(Matrix & b, Matrix & x) const | |
{ | |
b.ColSameCheck(x); | |
lu.DimCheck(b); | |
lu.DimCheck(x); | |
int n = b.NRows(); | |
int m = b.NCols(); | |
Vector xx(n); | |
for (int j = 0; j < m; j++) | |
{ | |
for (int i = 0; i < n; i++) | |
xx[i] = b[i][j]; | |
Solve(xx, xx); | |
for (int i = 0; i < n; i++) | |
x[i][j] = xx[i]; | |
} | |
} | |
// Incompatible formats. | |
Matrix LUDecomposer::Solve(Matrix b) const | |
{ | |
lu.DimCheck(b); | |
Matrix ret(b.NRows(), b.NCols()); | |
Solve(b, ret); | |
return ret; | |
} | |
Matrix LUDecomposer::GetCompactLU() const | |
{ | |
return lu; | |
} | |
Matrix LUDecomposer::GetL() const | |
{ | |
Matrix l(lu); | |
for (int i = 0; i < lu.NRows() - 1; i++) | |
{ | |
l[i][i] = 1.0; | |
for (int j = i + 1; j < lu.NCols(); j++) | |
l[i][j] = 0.0; | |
} | |
l[lu.NRows() - 1][lu.NRows() - 1] = 1.0; | |
return l; | |
} | |
Matrix LUDecomposer::GetU() const | |
{ | |
Matrix u(lu); | |
for (int i = 0; i < lu.NRows() - 1; i++) | |
for (int j = i + 1; j < lu.NCols(); j++) | |
u[j][i] = 0.0; | |
return u; | |
} | |
Vector LUDecomposer::GetPermutation() const | |
{ | |
return w; | |
} | |
#include <cmath> | |
#include <cstdlib> | |
#include <algorithm> | |
Matrix QRDecomposer::GetQ() const | |
{ | |
int m = a.NRows(); | |
int n = a.NCols(); | |
Matrix q(m, m); | |
for (int j = 0; j < m; j++) | |
{ | |
q[j][j] = 1; | |
for (int k = n - 1; k > -1; k--) | |
{ | |
double s = 0; | |
for (int i = k; i < m; i++) | |
s += a[i][k] * q[i][j]; | |
for (int i = k; i < m; i++) | |
q[i][j] -= s * a[i][k]; | |
} | |
} | |
return q; | |
} | |
Matrix QRDecomposer::GetR() const | |
{ | |
Matrix r(a); | |
for (int i = 0; i < a.NRows(); i++) | |
{ | |
r[i][i] = d[i]; | |
for (int j = i + 1; j < a.NCols(); j++) | |
r[j][i] = 0.0; | |
} | |
return r; | |
} | |
QRDecomposer::~QRDecomposer() | |
{ | |
} | |
// QR dimension check. | |
// Singular check. | |
QRDecomposer::QRDecomposer(Matrix ma) : a(ma), d(a.NRows()) | |
{ | |
QRDimCheck(a); | |
int m = a.NRows(); | |
int n = a.NCols(); | |
double mi; | |
for (int k = 0; k < n; k++) | |
{ | |
double s = 0; | |
for (int i = k; i < m; i++) | |
s += (a[i][k] * a[i][k]); | |
s = sqrt(s); | |
mi = sqrt(s * (s + std::abs(a[k][k]))); | |
if (a[k][k] < 0.0) | |
s = -s; | |
SingularZeroCheck(mi); | |
a[k][k] = (a[k][k] + s) / mi; | |
for (int i = k + 1; i < m; i++) | |
a[i][k] /= mi; | |
d[k] = -s; | |
for (int j = k + 1; j < n; j++) | |
{ | |
s = 0.0; | |
for (int i = k; i < m; i++) | |
s += a[i][k] * a[i][j]; | |
for (int i = k; i < m; i++) | |
a[i][j] -= s * a[i][k]; | |
} | |
} | |
} | |
// Format check | |
// QR square check | |
void QRDecomposer::Solve(const Vector & b, Vector & x) const | |
{ | |
a.SquareCheck(); | |
b.DimCheck(x); | |
a.DimCheck(b); // Transitive!!! | |
x = MulQTWith(b); | |
RSolve(x, x); | |
} | |
// Format check | |
// QR square check | |
Vector QRDecomposer::Solve(Vector b) const | |
{ | |
a.SquareCheck(); | |
a.DimCheck(b); | |
Vector x(b.NElems()); | |
Solve(b, x); | |
return x; | |
} | |
// QR Square check | |
// Format check | |
void QRDecomposer::Solve(Matrix & b, Matrix & x) const | |
{ | |
a.SquareCheck(); | |
a.DimCheck(b); | |
b.DimSameCheck(x); | |
int n = b.NRows(); | |
int m = b.NCols(); | |
Vector xx(n); | |
for (int j = 0; j < m; j++) | |
{ | |
for (int i = 0; i < n; i++) | |
xx[i] = b[i][j]; | |
Solve(xx, xx); | |
for (int i = 0; i < n; i++) | |
x[i][j] = xx[i]; | |
} | |
} | |
// QR Square check | |
// Format check | |
Matrix QRDecomposer::Solve(Matrix b) const | |
{ | |
a.SquareCheck(); | |
a.DimCheck(b); | |
Matrix ret = b; | |
Solve(b, ret); | |
return ret; | |
} | |
// Protected method, does not throw any exceptions | |
void QRDecomposer::RSolve(Vector &b, Vector &x) const | |
{ | |
double s = 0; | |
int n = a.NRows(); | |
for (int i = n - 1; i >= 0; i--) | |
{ | |
s = b[i]; | |
for (int j = i + 1; j < n; j++) | |
s -= a[i][j] * x[j]; | |
x[i] = s / d[i]; | |
} | |
} | |
void QRDecomposer::QRDimCheck(const Matrix &m) const | |
{ | |
if (m.NRows() < m.NCols()) | |
throw std::domain_error("Invalid matrix format"); | |
} | |
void QRDecomposer::QTDimCheck(const Matrix & m) const | |
{ | |
if (a.NRows() != m.NRows()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
void QRDecomposer::QTDimCheck(const Vector & v) const | |
{ | |
if (a.NRows() != v.NElems()) | |
throw std::domain_error("Incompatible formats"); | |
} | |
void QRDecomposer::SingularZeroCheck(double x, double Eps) const | |
{ | |
if (std::abs(x) < Eps) | |
throw std::domain_error("Matrix is singular"); | |
} | |
// Format check | |
Vector QRDecomposer::MulQWith(Vector y) const | |
{ | |
a.DimCheck(y); | |
int n = a.NRows(); | |
int m = a.NCols(); | |
for (int k = n - 1; k > -1; k--) | |
{ | |
double s = 0; | |
for (int i = k; i < m; i++) | |
s += a[i][k] * y[i]; | |
for (int i = k; i < m; i++) | |
y[i] -= s * a[i][k]; | |
} | |
return y; | |
} | |
// Format check | |
Matrix QRDecomposer::MulQWith(Matrix y) const | |
{ | |
a.DimCheck(y); | |
int n = a.NRows(); | |
int m = a.NCols(); | |
for (int j = 0; j < y.NCols(); j++) | |
{ | |
for (int k = n - 1; k > -1; k--) | |
{ | |
double s = 0; | |
for (int i = k; i < y.NRows(); i++) | |
s += a[i][k] * y[i] [j]; | |
for (int i = k; i < y.NRows(); i++) | |
y[i][j] -= s * a[i][k]; | |
} | |
} | |
return y; | |
} | |
// Format check | |
Vector QRDecomposer::MulQTWith(Vector y) const | |
{ | |
a.DimCheck(y); | |
int n = a.NRows(); | |
int m = a.NCols(); | |
for (int k = 0; k < n; k++) | |
{ | |
double s = 0; | |
for (int i = k; i < m; i++) | |
s += a[i][k] * y[i]; | |
for (int i = k; i < m; i++) | |
y[i] -= s * a[i][k]; | |
} | |
return y; | |
} | |
// Format check | |
Matrix QRDecomposer::MulQTWith(Matrix y) const | |
{ | |
a.DimCheck(y); | |
int n = a.NRows(); | |
for (int j = 0; j < y.NCols(); j++) | |
{ | |
for (int k = 0; k < n; k++) | |
{ | |
double s = 0; | |
for (int i = k; i < y.NRows(); i++) | |
s += a[i][k] * y[i][j]; | |
for (int i = k; i < y.NRows(); i++) | |
y[i][j] -= s * a[i][k]; | |
} | |
} | |
return y; | |
} | |
namespace patch | |
{ | |
template<class T> std::string to_string(const T &n) | |
{ | |
std::ostringstream stm; | |
stm << n; | |
return stm.str(); | |
} | |
} | |
template<class T> | |
class HuffmanTree | |
{ | |
private: | |
typedef std::pair<T, int> Node; | |
typedef std::pair<double, T> Data; | |
struct Edge | |
{ | |
T v; | |
char c; | |
Edge() { } | |
Edge(const Node &_v, char _c) : v(_v), c(_c) { } | |
}; | |
std::unordered_map<T, T> parent; | |
std::unordered_map<T, double> prob; | |
std::map<Node, std::vector<Node>> graph; | |
std::vector<char> codes; | |
std::unordered_map<T, int> groupSize; | |
std::vector<std::pair<T, double>> dataSet; | |
Node root; | |
int codeSize; | |
std::unordered_map<T, std::string> huffman; | |
int TakeCount(int n) const | |
{ | |
return 2 + ((n - 4) % (codes.size() - 1)); | |
} | |
void InitValues(const std::vector<std::pair<T, double>> &dataSet) | |
{ | |
for (auto& x : dataSet) | |
{ | |
prob[x.first] = x.second; | |
parent[x.first] = x.first; | |
groupSize[x.first] = 1; | |
} | |
} | |
T Find(const T &x) | |
{ | |
if (parent[x] == x) | |
return x; | |
else | |
return parent[x] = Find(parent[x]); | |
} | |
Node FindNode(const T &x) | |
{ | |
return Node(x, groupSize[x]); | |
} | |
Node Union(const T &x, const T &y) | |
{ | |
T fX = Find(x); | |
T fY = Find(y); | |
if (groupSize[fX] < groupSize[fY]) | |
{ | |
groupSize[fY] += groupSize[fX]; | |
parent [fX] = fY; | |
return Node(fY, groupSize[fY]); | |
} | |
else | |
{ | |
groupSize[fX] += groupSize[fY]; | |
parent [fY] = fX; | |
return Node(fX, groupSize[fX]); | |
} | |
} | |
void Huffman() | |
{ | |
std::priority_queue<Data, | |
std::vector<Data>, | |
std::function<bool(const Data &a, const Data &b)>> pq ( | |
[](const Data &a, const Data &b) -> bool | |
{ | |
return a.first > b.first; | |
}); | |
for (auto& x : prob) | |
pq.push(Data(x.second, x.first)); | |
Node node; | |
while (pq.size() > 1) | |
{ | |
int m = TakeCount((int)pq.size()); | |
auto mainElem = pq.top(); | |
pq.pop(); | |
Node lastNode = FindNode(mainElem.second); | |
double count = mainElem.first; | |
std::vector<Node> nodes(m - 1); // TODO: Optimize | |
for (int i = 0; i < m - 1; i++) | |
{ | |
auto help = pq.top(); | |
pq.pop(); | |
count += help.first; | |
nodes [i] = FindNode(help.second); | |
node = Union(help.second, mainElem.second); | |
} | |
nodes.push_back(lastNode); | |
for (Node& n : nodes) | |
graph[node].push_back(n); | |
pq.push(Data(count, node.first)); | |
} | |
root = node; | |
} | |
void Traverse(const Node ¤t, std::string buffer, int depth = 0, bool write = false) | |
{ | |
depth++; | |
if (write) | |
for (int i = 0; i < depth; i++) | |
std::putchar('-'); | |
if (graph[current].size() && write) | |
{ | |
for (int i = 0; i < graph[current].size() - 1; i++) | |
std::cout << prob[graph[current][i].first] << " + "; | |
std::cout << prob[graph[current].back().first] << '\n'; | |
} | |
int index = 0; | |
for (auto& next : graph[current]) | |
Traverse(next, buffer + codes[index++], depth, write); | |
if (!graph[current].size()) | |
{ | |
huffman[current.first] = buffer; | |
if (write) | |
std::cout << current.first << ' ' << buffer << '\n'; | |
} | |
} | |
std::vector<std::pair<T, double>> MixMe(const std::vector<std::pair<T, double>> &dS, int token) | |
{ | |
if (token == 1) | |
{ | |
dataSet = dS; | |
return dataSet; | |
} | |
auto mix = MixMe(dS, token - 1); | |
dataSet.clear(); | |
for (int i = 0; i < dS.size(); i++) | |
for (int j = 0; j < mix.size(); j++) | |
dataSet.emplace_back(dS[i].first + mix[j].first, dS[i].second * mix[j].second); | |
return dataSet; | |
} | |
double hinf; | |
int depth; | |
int ogSize; | |
public: | |
static std::vector<std::pair<T, double>> GetProb(const std::vector<std::pair<T, int>> &in) | |
{ | |
std::vector<std::pair<T, double>> v; | |
int total = 0; | |
for (auto &x : in) | |
total += x.second; | |
for (auto &x : in) | |
v.emplace_back(x.first, (double)x.second / total); | |
return v; | |
} | |
HuffmanTree(const std::vector<std::pair<T, double>> &_dataSet, | |
const std::vector<char> &_codes, | |
int mix = 1) : codes(_codes) | |
{ | |
depth = mix; | |
hinf = 0.0; | |
ogSize = _dataSet.size(); | |
for (auto& e : _dataSet) | |
hinf -= std::log2(e.second) * e.second; | |
dataSet = MixMe(_dataSet, mix); | |
for (auto s : dataSet) | |
std::cout << s.first << ' ' << s.second << '\n'; | |
std::cout << '\n'; | |
InitValues(dataSet); | |
Huffman(); | |
} | |
void Join(bool write = false) | |
{ | |
if (write) | |
std::cout << ".-\n"; | |
Traverse(root, "", 0, write); | |
} | |
std::string Encode(std::string text) | |
{ | |
int len = dataSet[0].first.length(); | |
std::string ret; | |
for (int i = 0; i < text.length(); i += len) | |
ret += huffman[text.substr(i, len)]; | |
return ret; | |
} | |
void Analyze() | |
{ | |
for (auto& elem : dataSet) | |
std::cout << elem.first << " &\\rightarrow " << elem.second << "\\\\\n"; | |
std::cout << "\n\n"; | |
for (auto& elem : huffman) | |
std::cout << elem.first << " &\\rightarrow " << elem.second << "\\\\\n"; | |
double nsr = 0.0; | |
for (auto &e : huffman) | |
nsr += prob[e.first] * e.second.length(); | |
std::cout << "n_{sr} &= " << nsr << '\n'; | |
std::cout << "H (X \\mid X^\\infty) &= -\\sum_{i=1}^{" << ogSize << "}\\mid p_i \\mid log_2(p_i) \\approx = " << hinf << '\n'; | |
double speed = depth * hinf / nsr; | |
std::cout << "\\overbar{I(X)} &= " << depth << "\\frac{H (X \\mid X^\\infty)}{n_{sr}\\tau} \\approx \\frac{" << speed << "}{\\tau}\n"; | |
std::cout << "brzina prenosa = " << speed << '\n'; | |
double perc = speed / std::log2((int)codes.size()); | |
std::cout << "procenat iskoristenosti = " << perc * 100.0 << "\\%\n"; | |
} | |
}; | |
template<class T> | |
class ShannonFanoTree | |
{ | |
std::vector<char> codes; | |
std::map<T, std::string> shannonFano; | |
std::vector<double> prefix; | |
std::map<T, double> prob; | |
std::vector<std::pair<T, double>> dataSet; | |
double GetSum(int left, int right) | |
{ | |
return prefix[right] - (!left ? 0 : prefix[left - 1]); | |
} | |
int FindIndex(int left, int right) | |
{ | |
if (right - left < 3) | |
return left; | |
double total = GetSum(left, right); | |
int l = left, r = right, pivot; | |
while (l < r) | |
{ | |
pivot = (l + r) / 2; | |
if (GetSum(left, pivot) * 2 < total) | |
l = pivot + 1; | |
else | |
r = pivot - 1; | |
} | |
return l; | |
} | |
void InitValues() | |
{ | |
prefix.resize(dataSet.size()); | |
prefix[0] = dataSet[0].second; | |
prob[dataSet[0].first] = dataSet[0].second; | |
for (int i = 1; i < prefix.size(); i++) | |
{ | |
prefix[i] = prefix[i - 1] + dataSet[i].second; | |
prob[dataSet[i].first] = dataSet[i].second; | |
} | |
} | |
int depth; | |
void Solve(int left, int right, char color = '0', bool print = false) | |
{ | |
if (print) | |
for (int i = 0; i < depth; i++) | |
std::putchar('-'); | |
depth++; | |
if (left == right) | |
{ | |
shannonFano[dataSet[left].first] += color; | |
if (print) | |
std::cout << dataSet[left].first << '=' << shannonFano[dataSet[left].first] << '\n'; | |
depth--; | |
return; | |
} | |
int index = FindIndex(left, right); | |
if (left != index) | |
for (int i = left; i <= index; i++) | |
shannonFano[dataSet[i].first] += codes[0]; | |
if (right != index + 1) | |
for (int i = index + 1; i <= right; i++) | |
shannonFano[dataSet[i].first] += codes[1]; | |
if (print) | |
std::cout << GetSum(left, index) << " + " << GetSum(index + 1, right) << '\n'; | |
Solve(left, index, codes[0], print); | |
Solve(index + 1, right, codes[1], print); | |
depth--; | |
} | |
std::vector<std::pair<T, double>> MixMe(const std::vector<std::pair<T, double>> &dS, int token) | |
{ | |
if (token == 1) | |
return dataSet = dS; | |
auto mix = MixMe(dS, token - 1); | |
dataSet.clear(); | |
for (int i = 0; i < dS.size(); i++) | |
for (int j = 0; j < mix.size(); j++) | |
dataSet.emplace_back(dS[i].first + mix[j].first, dS[i].second * mix[j].second); | |
return dataSet; | |
} | |
double hinf; | |
int ogSize; | |
double nsr; | |
public: | |
double GetNsr() | |
{ | |
return nsr; | |
} | |
static std::vector<std::pair<T, double>> GetProb(const std::vector<std::pair<T, int>> &in) | |
{ | |
std::vector<std::pair<T, double>> v; | |
int total = 0; | |
for (auto &x : in) | |
total += x.second; | |
for (auto &x : in) | |
v.emplace_back(x.first, (double)x.second / total); | |
return v; | |
} | |
ShannonFanoTree() { } | |
ShannonFanoTree(const std::vector<std::pair<T, double>> &dS, | |
const std::vector<char> &_codes, | |
int mix = 1) : depth(mix) | |
{ | |
codes = _codes; | |
hinf = 0.0; | |
ogSize = dS.size(); | |
for (auto& d : dS) | |
hinf -= d.second * std::log2(d.second); | |
MixMe(dS, mix); | |
std::sort(dataSet.begin(), dataSet.end(), [](auto x, auto y) { return x.second > y.second; }); // C++14 | |
InitValues(); | |
} | |
void Solve(bool write) | |
{ | |
Solve(0, dataSet.size() - 1, codes[0], write); | |
} | |
void Analyze(double _hinf = -1.0) | |
{ | |
if (_hinf > -0.5) | |
hinf = _hinf; | |
for (auto elem : dataSet) | |
std::cout << elem.first << " &\\rightarrow " << elem.second << "\\\\\n"; | |
EQBEGIN | |
for (auto& elem : shannonFano) | |
std::cout << elem.first << " &\\rightarrow " << elem.second << "\\\\\n"; | |
EQEND | |
nsr = 0.0; | |
for (auto &e : shannonFano) | |
nsr += prob[e.first] * e.second.length(); | |
EQBEGIN | |
std::cout << "n_{sr} &= " << nsr << '\n'; | |
std::cout << "H (X \\mid X^\\infty) &= \\sum_{i=1}^{" << ogSize << "}\\mid p_i \\mid log_2(p_i) \\approx = " << hinf << '\n'; | |
double speed = depth * hinf / nsr; | |
std::cout << "\\overbar{I(X)} &= " << depth << "\\frac{H (X \\mid X^\\infty)}{n_{sr}\\tau} \\approx \\frac{" << speed << "}{\\tau}\n"; | |
EQEND | |
double perc = speed; | |
std::cout << "procenat iskoristenosti = " << perc * 100.0 << "\\%\n"; | |
} | |
std::string Encode(std::string text) | |
{ | |
int len = dataSet[0].first.length(); | |
std::string ret; | |
for (int i = 0; i < text.length(); i += len) | |
ret += shannonFano[text.substr(i, len)]; | |
return ret; | |
} | |
}; | |
template<class T> | |
class StateSolver | |
{ | |
private: | |
std::map<T, ShannonFanoTree<T>> sf; | |
std::vector<T> names; | |
std::vector<char> codes; | |
std::vector<T> states; | |
std::map<T, double> p; | |
Matrix og; | |
int n; | |
double hinf; | |
public: | |
StateSolver(const Matrix& _og, const std::vector<T> &_states, const std::vector<char> &_codes) : states(_states), codes(_codes), og(Matrix(1, 1)) | |
{ | |
og = _og; | |
n = og.NRows(); | |
Matrix transf = og; | |
transf.Transpose(); | |
for (int i = 0; i < transf.NRows() - 1; i++) | |
{ | |
transf[i][i] -= 1.0; | |
transf[transf.NRows() - 1][i] = 1.0; | |
} | |
transf[transf.NRows() - 1][transf.NRows() - 1] = 1.0; | |
Vector v(transf.NRows()); | |
v[transf.NRows() - 1] = 1.0; | |
std::vector<double> H(og.NRows(), 0.0); | |
Vector pV = QRDecomposer(transf).Solve(v); | |
for (int i = 0; i < pV.NElems(); i++) | |
p[_states[i]] = pV[i]; | |
for (int i = 0; i < og.NRows(); i++) | |
for (int j = 0; j < og.NCols(); j++) | |
if (og[i][j] > std::numeric_limits<double>::epsilon()) | |
H[i] -= og[i][j] * std::log2(og[i][j]); | |
for (int i = 0; i < 3; i++) | |
hinf += pV[i] * H[i]; | |
} | |
void Solve(int depth, std::string text) | |
{ | |
double nsr = 0.0; | |
for (int i = 0; i < n; i++) | |
{ | |
std::cout << "current state: " << states[i] << '\n'; | |
std::vector<std::pair<T, double>> data; | |
for (int j = 0; j < states.size(); j++) | |
data.emplace_back(states[j], og[i][j]); | |
sf[states[i]] = ShannonFanoTree<std::string>(data, codes, depth); | |
sf[states[i]].Solve(true); | |
sf[states[i]].Analyze(hinf); | |
nsr += p[states[i]] * sf[states[i]].GetNsr(); | |
std::cout << text << " &\\approx " << sf[states[i]].Encode(text) << '\n'; | |
std::cout << '\\\\\n'; | |
std::cout << "\n\n"; | |
system("pause"); | |
} | |
std::cout << "<----------- TOTAL -------------------->\n"; | |
std::cout << "n_{sr} &= " << nsr << '\n'; | |
double speed = hinf / nsr; | |
std::cout << "\\overbar{I(X)} &= " << depth << "\\frac{H (X \\mid X^\\infty)}{n_{sr}\\tau} \\approx \\frac{" << speed << "}{\\tau}\n"; | |
} | |
}; | |
int main() | |
{ | |
// a | |
/* | |
std::vector<std::pair<std::string, double>> p = { { "a", 0.35 }, { "b", 0.15 }, { "c", 0.5 } }; | |
ShannonFanoTree<std::string> shannonFano(p, { '0', '1' }, 2); | |
shannonFano.Solve(true); | |
shannonFano.Analyze(); | |
std::cout << shannonFano.Encode("cbbbbcacbccabb") << '\n'; | |
*/ | |
// c | |
/* | |
Matrix m = Matrix({ | |
{ 0.4, 0.2, 0.4}, | |
{0.4, 0.2, 0.4}, | |
{ 0.3, 0.1, 0.6 }}); | |
Matrix m = Matrix({ | |
{ 0.8, 0.1, 0.1 }, | |
{ 0.2, 0.7, 0.1 }, | |
{ 0.05, 0.05, 0.9 }}); | |
StateSolver<std::string>(m, { "a", "b", "c" }, { '0', '1' }).Solve(2); | |
*/ | |
// d | |
// | |
// | |
// 5 a | |
/* | |
std::vector<int> v = { 36, 85, 28, 51, 71, 76, 91, 82, 29, 30 }; | |
std::vector<std::pair<std::string, int>> p; | |
std::string word = "A"; | |
for (int i = 0; i < v.size(); i++) | |
{ | |
p.emplace_back(word, v[i]); | |
word[0]++; | |
} | |
auto sf = ShannonFanoTree<std::string>(ShannonFanoTree<std::string>::GetProb(p), { '0', '1' }); | |
sf.Solve(true); | |
sf.Analyze(); | |
*/ | |
// 5 b i c | |
/* | |
std::vector<int> v = { 36, 85, 28, 51, 71, 76, 91, 82, 29, 30 }; | |
std::vector<std::pair<std::string, int>> p; | |
std::string word = "A"; | |
for (int i = 0; i < v.size(); i++) | |
{ | |
p.emplace_back(word, v[i]); | |
word[0]++; | |
} | |
auto sf = HuffmanTree<std::string>(ShannonFanoTree<std::string>::GetProb(p), { '0', '1', '2' }); | |
sf.Join(true); | |
sf.Analyze(); | |
*/ | |
// 6 | |
/* | |
std::vector<double> v = { 0.25, 0.15, 0.4, 0.2 }; | |
std::vector<std::pair<std::string, double>> p; | |
for (int i = 0; i < v.size(); i++) | |
p.emplace_back(std::string(1, 'A' + i), v[i]); | |
*/ | |
// 6a) | |
/* | |
ShannonFanoTree<std::string> sfTreea(p, { '0', '1' }, 1); | |
sfTreea.Solve(true); | |
sfTreea.Analyze(); | |
std::cout << "ADDDDDBB \\rightarrow " << sfTreea.Encode("ADDDDDBB") << '\n'; | |
*/ | |
// b) | |
/* | |
HuffmanTree<std::string> htb(p, { '0', '1' }, 1); | |
htb.Join(true); | |
htb.Analyze(); | |
std::cout << "encoding: " << htb.Encode("ADDDDDBB") << '\n'; | |
*/ | |
// c) | |
/* | |
ShannonFanoTree<std::string> htc(p, { '0', '1' }, 2); | |
htc.Solve(true); | |
htc.Analyze(); | |
std::cout << "encoding: " << htc.Encode("ADDDDDBB") << '\n'; | |
*/ | |
// d) | |
/* | |
HuffmanTree<std::string> htd(p, { '0', '1' }, 2); | |
htd.Join(true); | |
htd.Analyze(); | |
std::cout << "encoding: " << htd.Encode("ADDDDDBB") << '\n'; | |
*/ | |
// a | |
/* | |
std::vector<std::pair<std::string, double>> p = { { "a", 0.35 }, { "b", 0.15 }, { "c", 0.5 } }; | |
ShannonFanoTree<std::string> shannonFano(p, { '0', '1' }, 1); | |
shannonFano.Solve(true); | |
shannonFano.Analyze(); | |
std::cout << shannonFano.Encode("cbbbbcacbccabb") << '\n'; | |
*/ | |
/* | |
std::vector<std::pair<std::string, double>> p = { { "a", 0.35 }, { "b", 0.15 }, { "c", 0.5 } }; | |
ShannonFanoTree<std::string> shannonFano(p, { '0', '1' }, 2); | |
shannonFano.Solve(true); | |
shannonFano.Analyze(); | |
std::cout << shannonFano.Encode("cbbbbcacbccabb") << '\n'; | |
*/ | |
/* | |
Matrix m = Matrix({ | |
{ 0.4, 0.2, 0.4 }, | |
{ 0.4, 0.2, 0.4 }, | |
{ 0.3, 0.1, 0.6 }}); | |
*/ | |
// c | |
//StateSolver<std::string>(m, { "a", "b", "c" }, { '0', '1' }).Solve(1, "cbbbbcacbccabb"); | |
// d | |
StateSolver<std::string>(m, { "a", "b", "c" }, { '0', '1' }).Solve(2, "cbbbbcacbccabb"); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment