mirror of
https://hub.njuu.cf/TheAlgorithms/C-Plus-Plus.git
synced 2023-10-11 13:05:55 +08:00
252 lines
7.8 KiB
C++
252 lines
7.8 KiB
C++
|
/**
|
||
|
* @file
|
||
|
* @brief [Gram Schmidt Orthogonalisation Process](https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process)
|
||
|
*
|
||
|
* @details
|
||
|
* Takes the input of Linearly Independent Vectors,
|
||
|
* returns vectors orthogonal to each other.
|
||
|
*
|
||
|
* ### Algorithm
|
||
|
* Take the first vector of given LI vectors as first vector of Orthogonal vectors.
|
||
|
* Take projection of second input vector on the first vector of Orthogonal vector
|
||
|
* and subtract it from the 2nd LI vector.
|
||
|
* Take projection of third vector on the second vector of Othogonal vectors and subtract it from the 3rd LI vector.
|
||
|
* Keep repeating the above process until all the vectors in the given input array are exhausted.
|
||
|
*
|
||
|
* For Example:
|
||
|
* In R2,
|
||
|
* Input LI Vectors={(3,1),(2,2)}
|
||
|
* then Orthogonal Vectors= {(3, 1),(-0.4, 1.2)}
|
||
|
*
|
||
|
* Have defined maximum dimension of vectors to be 10 and number of vectors
|
||
|
* taken is 20.
|
||
|
* Please do not give linearly dependent vectors
|
||
|
*
|
||
|
*
|
||
|
* @author [Akanksha Gupta](https://github.com/Akanksha-Gupta920)
|
||
|
*/
|
||
|
|
||
|
#include <iostream> /// for io operations
|
||
|
#include <cassert> /// for assert
|
||
|
#include <cmath> /// for fabs
|
||
|
#include <array> /// for std::array
|
||
|
|
||
|
/**
|
||
|
* @namespace linear_algebra
|
||
|
* @brief Linear Algebra algorithms
|
||
|
*/
|
||
|
namespace linear_algebra {
|
||
|
/**
|
||
|
* @namespace gram_schmidt
|
||
|
* @brief Functions for [Gram Schmidt Orthogonalisation Process](https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process)
|
||
|
*/
|
||
|
namespace gram_schmidt {
|
||
|
/**
|
||
|
* Dot product function.
|
||
|
* Takes 2 vectors along with their dimension as input and returns the dot product.
|
||
|
* @param x vector 1
|
||
|
* @param y vector 2
|
||
|
* @param c dimension of the vectors
|
||
|
*
|
||
|
* @returns sum
|
||
|
*/
|
||
|
double dot_product(const std::array<double, 10>& x, const std::array<double, 10>& y, const int& c) {
|
||
|
double sum = 0;
|
||
|
for (int i = 0; i < c; ++i) {
|
||
|
sum += x[i] * y[i];
|
||
|
}
|
||
|
return sum;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Projection Function
|
||
|
* Takes input of 2 vectors along with their dimension and evaluates their projection in temp
|
||
|
*
|
||
|
* @param x Vector 1
|
||
|
* @param y Vector 2
|
||
|
* @param c dimension of each vector
|
||
|
*
|
||
|
* @returns factor
|
||
|
*/
|
||
|
double projection(const std::array<double, 10>& x,const std::array<double, 10>& y,
|
||
|
const int& c) {
|
||
|
double dot = dot_product(x, y, c); ///The dot product of two vectors is taken
|
||
|
double anorm = dot_product(y, y, c); ///The norm of the second vector is taken.
|
||
|
double factor = dot / anorm; ///multiply that factor with every element in a 3rd vector, whose initial values are same as the 2nd vector.
|
||
|
return factor;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function to print the orthogonalised vector
|
||
|
*
|
||
|
* @param r number of vectors
|
||
|
* @param c dimenaion of vectors
|
||
|
* @param B stores orthogonalised vectors
|
||
|
*
|
||
|
* @returns void
|
||
|
*/
|
||
|
void display(const int& r,const int& c,const std::array<std::array<double, 10>, 20>& B) {
|
||
|
for (int i = 0; i < r; ++i) {
|
||
|
std::cout << "Vector " << i + 1 << ": ";
|
||
|
for (int j = 0; j < c; ++j) {
|
||
|
std::cout << B[i][j] << " ";
|
||
|
}
|
||
|
std::cout << '\n';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function for the process of Gram Schimdt Process
|
||
|
* @param r number of vectors
|
||
|
* @param c dimension of vectors
|
||
|
* @param A stores input of given LI vectors
|
||
|
* @param B stores orthogonalised vectors
|
||
|
*
|
||
|
* @returns void
|
||
|
*/
|
||
|
void gram_schmidt(int r,const int& c,const std::array<std::array<double, 10>, 20>& A,
|
||
|
std::array<std::array<double, 10>, 20> B) {
|
||
|
if (c < r) { /// we check whether appropriate dimensions are given or not.
|
||
|
std::cout
|
||
|
<< "Dimension of vector is less than number of vector, hence \n first "
|
||
|
<< c << " vectors are orthogonalised\n";
|
||
|
r = c;
|
||
|
}
|
||
|
|
||
|
int k = 1;
|
||
|
|
||
|
while (k <= r) {
|
||
|
if (k == 1) {
|
||
|
for (int j = 0; j < c; j++) B[0][j] = A[0][j]; ///First vector is copied as it is.
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
std::array<double, 10> all_projection{}; ///array to store projections
|
||
|
for (int i = 0; i < c; ++i) {
|
||
|
all_projection[i] = 0; ///First initialised to zero
|
||
|
}
|
||
|
|
||
|
int l = 1;
|
||
|
while (l < k) {
|
||
|
std::array<double, 10> temp{}; ///to store previous projected array
|
||
|
double factor; ///to store the factor by which the previous array will change
|
||
|
factor = projection(A[k - 1], B[l - 1], c);
|
||
|
for(int i = 0; i < c; ++i)
|
||
|
temp[i] = B[l - 1][i] * factor; ///projected array created
|
||
|
for (int j = 0; j < c; ++j) {
|
||
|
all_projection[j] = all_projection[j] + temp[j]; ///we take the projection with all the previous vector and add them.
|
||
|
}
|
||
|
l++;
|
||
|
}
|
||
|
for (int i = 0; i < c; ++i) {
|
||
|
B[k - 1][i] = A[k - 1][i] - all_projection[i]; ///subtract total projection vector from the input vector
|
||
|
}
|
||
|
}
|
||
|
k++;
|
||
|
}
|
||
|
display(r, c, B); //for displaying orthogoanlised vectors
|
||
|
}
|
||
|
} // namespace gram_schmidt
|
||
|
} // namespace linear_algebra
|
||
|
/**
|
||
|
* Test Function. Process has been tested for 3 Sample Inputs
|
||
|
* @returns void
|
||
|
*/
|
||
|
static void test() {
|
||
|
std::array<std::array<double, 10>, 20> a1 = {
|
||
|
{{1, 0, 1, 0}, {1, 1, 1, 1}, {0, 1, 2, 1}}};
|
||
|
std::array<std::array<double, 10>, 20> b1 = {{0}};
|
||
|
double dot1 = 0;
|
||
|
linear_algebra::gram_schmidt::gram_schmidt(3, 4, a1, b1);
|
||
|
int flag = 1;
|
||
|
for (int i = 0; i < 2; ++i)
|
||
|
for (int j = i + 1; j < 3; ++j) {
|
||
|
dot1 = fabs(linear_algebra::gram_schmidt::dot_product(b1[i], b1[j], 4));
|
||
|
if (dot1 > 0.1) {
|
||
|
flag = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (flag == 0) std::cout << "Vectors are linearly dependent\n";
|
||
|
assert(flag == 1);
|
||
|
std::cout << "Passed Test Case 1\n ";
|
||
|
|
||
|
std::array<std::array<double, 10>, 20> a2 = {{{3, 1}, {2, 2}}};
|
||
|
std::array<std::array<double, 10>, 20> b2 = {{0}};
|
||
|
double dot2 = 0;
|
||
|
linear_algebra::gram_schmidt::gram_schmidt(2, 2, a2, b2);
|
||
|
flag = 1;
|
||
|
for (int i = 0; i < 1; ++i)
|
||
|
for (int j = i + 1; j < 2; ++j) {
|
||
|
dot2 = fabs(linear_algebra::gram_schmidt::dot_product(b2[i], b2[j], 2));
|
||
|
if (dot2 > 0.1) {
|
||
|
flag = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (flag == 0) std::cout << "Vectors are linearly dependent\n";
|
||
|
assert(flag == 1);
|
||
|
std::cout << "Passed Test Case 2\n";
|
||
|
|
||
|
std::array<std::array<double, 10>, 20> a3 = {{{1, 2, 2}, {-4, 3, 2}}};
|
||
|
std::array<std::array<double, 10>, 20> b3 = {{0}};
|
||
|
double dot3 = 0;
|
||
|
linear_algebra::gram_schmidt::gram_schmidt(2, 3, a3, b3);
|
||
|
flag = 1;
|
||
|
for (int i = 0; i < 1; ++i)
|
||
|
for (int j = i + 1; j < 2; ++j) {
|
||
|
dot3 = fabs(linear_algebra::gram_schmidt::dot_product(b3[i], b3[j], 3));
|
||
|
if (dot3 > 0.1) {
|
||
|
flag = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (flag == 0) std::cout << "Vectors are linearly dependent\n" ;
|
||
|
assert(flag == 1);
|
||
|
std::cout << "Passed Test Case 3\n";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Main Function
|
||
|
* @return 0 on exit
|
||
|
*/
|
||
|
int main() {
|
||
|
int r=0, c=0;
|
||
|
test(); // perform self tests
|
||
|
std::cout << "Enter the dimension of your vectors\n";
|
||
|
std::cin >> c;
|
||
|
std::cout << "Enter the number of vectors you will enter\n";
|
||
|
std::cin >> r;
|
||
|
|
||
|
std::array<std::array<double, 10>, 20>
|
||
|
A{}; ///a 2-D array for storing all vectors
|
||
|
std::array<std::array<double, 10>, 20> B = {
|
||
|
{0}}; /// a 2-D array for storing orthogonalised vectors
|
||
|
/// storing vectors in array A
|
||
|
for (int i = 0; i < r; ++i) {
|
||
|
std::cout << "Enter vector " << i + 1 <<'\n'; ///Input of vectors is taken
|
||
|
for (int j = 0; j < c; ++j) {
|
||
|
std::cout << "Value " << j + 1 << "th of vector: ";
|
||
|
std::cin >> A[i][j];
|
||
|
}
|
||
|
std::cout <<'\n';
|
||
|
}
|
||
|
|
||
|
linear_algebra::gram_schmidt::gram_schmidt(r, c, A, B);
|
||
|
|
||
|
double dot = 0;
|
||
|
int flag = 1; ///To check whether vectors are orthogonal or not
|
||
|
for (int i = 0; i < r - 1; ++i) {
|
||
|
for (int j = i + 1; j < r; ++j) {
|
||
|
dot = fabs(linear_algebra::gram_schmidt::dot_product(B[i], B[j], c));
|
||
|
if (dot > 0.1) /// take make the process numerically stable, upper bound for the dot product take 0.1
|
||
|
{
|
||
|
flag = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (flag == 0) std::cout << "Vectors are linearly dependent\n";
|
||
|
return 0;
|
||
|
}
|