Skip to content

Commit

Permalink
feat: Add Gram Schmidt Orthogonalisation (TheAlgorithms#1339)
Browse files Browse the repository at this point in the history
* Add Gram Schmidt Orthogonalisation

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

After removing '&' while passing the parameters. The changes in array B are not reflected.

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

All the changes have been done and changes in B are also reflected.

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Fix spelling of brief

* updating DIRECTORY.md

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update gram_schmidt.cpp

* Update linear_algebra/gram_schmidt.cpp

* Update linear_algebra/gram_schmidt.cpp

* Update linear_algebra/gram_schmidt.cpp

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Co-authored-by: Ayaan Khan <[email protected]>
  • Loading branch information
3 people authored Oct 31, 2020
1 parent 7b92e8d commit fb5e00f
Show file tree
Hide file tree
Showing 2 changed files with 254 additions and 0 deletions.
3 changes: 3 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@
* [Linear Probing Hash Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/hashing/linear_probing_hash_table.cpp)
* [Quadratic Probing Hash Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/hashing/quadratic_probing_hash_table.cpp)

## Linear Algebra
* [Gram Schmidt](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/linear_algebra/gram_schmidt.cpp)

## Machine Learning
* [Adaline Learning](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/adaline_learning.cpp)
* [Kohonen Som Topology](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/kohonen_som_topology.cpp)
Expand Down
251 changes: 251 additions & 0 deletions linear_algebra/gram_schmidt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
/**
* @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;
}

0 comments on commit fb5e00f

Please sign in to comment.