From 1158e626cb8fe76d6b3de9fdd7bd39672e62460a Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 14:29:48 +0100 Subject: [PATCH 01/92] feat: Added a class implemetation of complex numbers along with implementation of all (most) binary operations involved with complex numbers. --- math/complex_numbers.cpp | 183 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 math/complex_numbers.cpp diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp new file mode 100644 index 000000000..8d778d735 --- /dev/null +++ b/math/complex_numbers.cpp @@ -0,0 +1,183 @@ +/** + * Copyright 2020 @author tjgurwara99 + * @file + * + * A basic implementation of Complex Number field as a class with operators overloaded to accommodate (mathematical) field operations. + */ + +#include +#include +#include + +/** + * Class Complex to represent complex numbers as a field. + */ +class Complex { + // The real value of the complex number + double re; + // The imaginary value of the complex number + double im; + + public: + /** + * Complex Constructor which initialises the complex number which takes two arguments. + * @param x The real value of the complex number. + * @param y The imaginary value of the complex number. + */ + Complex(double x, double y) { + this->re = x; + this->im = y; + } + + /** + * Complex Constructor which initialises the complex number with no arguments. + */ + Complex() { + Complex(0.0,0.0); + } + + /** + * Member function (getter) to access the class' re value. + */ + double real() const { + return this->re; + } + + /** + * Member function (getter) to access the class' im value. + */ + double imag() const { + return this->im; + } + + /** + * Member function to which gives the absolute value (modulus) of our complex number + * @return \f$ \sqrt{z \dot \bar{z} \f$ where \f$ z \f$ is our complex number. + */ + double abs() const { + return std::sqrt(this->re*this->re + this->im*this->im); + } + + /** + * Operator overload to be able to add two complex numbers. + * @param other The other number that is added to the current number. + * @return result current number plus other number + */ + Complex operator+(const Complex& other) { + Complex result(this->re + other.re, this->im + other.im); + return result; + } + + /** + * Operator overload to be able to subtract two complex numbers. + * @param other The other number being subtracted from the current number. + * @return result current number subtract other number + */ + Complex operator-(const Complex& other) { + Complex result(this->re - other.re, this->im - other.im); + return result; + } + + /** + * Operator overload to be able to multiple two complex numbers. + * @param other The other number to multiply the current number to. + * @return result current number times other number. + */ + Complex operator*(const Complex& other) { + Complex result(this->re * other.re - this->im * other.im, + this->re * other.im + this->im * other.re); + return result; + } + + /** + * Operator overload of the BITWISE NOT which gives us the conjugate of our complex number. + * NOTE: This is overloading the BITWISE operator but its not a BITWISE operation in this definition. + * @return result The conjugate of our complex number. + */ + Complex operator~() const { + Complex result(this->re, -(this->im)); + return result; + } + + /** + * Operator overload to be able to divide two complex numbers. This function would throw an exception if the other number is zero. + * @param other The other number we divide our number by. + * @return result Current number divided by other number. + */ + Complex operator/(const Complex& other) { + Complex result = *this * ~other; + double denominator = other.abs() * other.abs(); + if (denominator != 0) { + result = Complex(result.real() / denominator, result.imag() / denominator); + return result; + } + else { + throw std::invalid_argument("Undefined Value"); + } + } +}; + +/** + * Logical Equal overload for our Complex class. + * @param a Left hand side of our expression + * @param b Right hand side of our expression + * @return 'True' If real and imaginary parts of a and b are same + * @return 'False' Otherwise. + */ +bool operator==(const Complex& a, const Complex& b) { + double del_real = a.real() - b.real(); + double del_imag = a.imag() - b.imag(); + return ((del_real <= 1e-15 && del_real >= - 1e-15 ) && (del_imag <= 1e-15 && del_imag >= - 1e-15)); +} + +/** + * Overloaded insersion operator to accommodate the printing of our complex number in their standard form. + * @param os The console stream + * @param num The complex number. + */ +std::ostream& operator<<(std::ostream& os, const Complex& num) { + os << num.real(); + if (num.imag() < 0) { + os << " - " << -num.imag(); + } + else { + os << " + " << num.imag(); + } + os << "i"; + return os; +} + +/** + * Tests Function + */ +void tests() { + Complex num1(1,1), num2(1,1); + // Test for addition + assert(((void)"1 + 1i + 1 + 1i is equal to 2 + 2i but the addition doesn't add up \n", + (num1 + num2) == Complex(2,2))); + std::cout << "First test passes." << std::endl; + // Test for subtraction + assert(((void)"1 + 1i - 1 - 1i is equal to 0 but the program says otherwise. \n", + (num1 - num2) == Complex(0,0))); + std::cout << "Second test passes." << std::endl; + // Test for multiplication + assert(((void)"(1 + 1i) * (1 + 1i) is equal to 2i but the program says otherwise. \n", + (num1 * num2) == Complex(0,2))); + std::cout << "Third test passes." << std::endl; + // Test for division + assert(((void)"(1 + 1i) / (1 + 1i) is equal to 1 but the program says otherwise.\n", + (num1 / num2) == Complex(1,0))); + std::cout << "Fourth test passes." << std::endl; + // Test for conjugates + assert(((void)"(1 + 1i) has a conjugate which is equal to (1 - 1i) but the program says otherwise.\n", + ~num1 == Complex(1,-1))); + std::cout << "Fifth test passes." << std::endl; + +} +/** + * Main function + */ +int main() { + tests(); + return 0; +} From f4fa366da501e41cac6bd274df4a02fc345d0c3b Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 14:32:08 +0100 Subject: [PATCH 02/92] docs: Fixed some clangformat issues with the documentation --- math/complex_numbers.cpp | 98 +++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 8d778d735..9a381b125 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -2,11 +2,12 @@ * Copyright 2020 @author tjgurwara99 * @file * - * A basic implementation of Complex Number field as a class with operators overloaded to accommodate (mathematical) field operations. + * A basic implementation of Complex Number field as a class with operators + * overloaded to accommodate (mathematical) field operations. */ -#include #include +#include #include /** @@ -18,9 +19,10 @@ class Complex { // The imaginary value of the complex number double im; - public: + public: /** - * Complex Constructor which initialises the complex number which takes two arguments. + * Complex Constructor which initialises the complex number which takes two + * arguments. * @param x The real value of the complex number. * @param y The imaginary value of the complex number. */ @@ -28,34 +30,31 @@ class Complex { this->re = x; this->im = y; } - + /** - * Complex Constructor which initialises the complex number with no arguments. + * Complex Constructor which initialises the complex number with no + * arguments. */ - Complex() { - Complex(0.0,0.0); - } + Complex() { Complex(0.0, 0.0); } /** * Member function (getter) to access the class' re value. */ - double real() const { - return this->re; - } + double real() const { return this->re; } /** * Member function (getter) to access the class' im value. */ - double imag() const { - return this->im; - } + double imag() const { return this->im; } /** - * Member function to which gives the absolute value (modulus) of our complex number - * @return \f$ \sqrt{z \dot \bar{z} \f$ where \f$ z \f$ is our complex number. + * Member function to which gives the absolute value (modulus) of our + * complex number + * @return \f$ \sqrt{z \dot \bar{z}} \f$ where \f$ z \f$ is our complex + * number. */ double abs() const { - return std::sqrt(this->re*this->re + this->im*this->im); + return std::sqrt(this->re * this->re + this->im * this->im); } /** @@ -63,7 +62,7 @@ class Complex { * @param other The other number that is added to the current number. * @return result current number plus other number */ - Complex operator+(const Complex& other) { + Complex operator+(const Complex &other) { Complex result(this->re + other.re, this->im + other.im); return result; } @@ -73,7 +72,7 @@ class Complex { * @param other The other number being subtracted from the current number. * @return result current number subtract other number */ - Complex operator-(const Complex& other) { + Complex operator-(const Complex &other) { Complex result(this->re - other.re, this->im - other.im); return result; } @@ -83,15 +82,16 @@ class Complex { * @param other The other number to multiply the current number to. * @return result current number times other number. */ - Complex operator*(const Complex& other) { + Complex operator*(const Complex &other) { Complex result(this->re * other.re - this->im * other.im, this->re * other.im + this->im * other.re); return result; } /** - * Operator overload of the BITWISE NOT which gives us the conjugate of our complex number. - * NOTE: This is overloading the BITWISE operator but its not a BITWISE operation in this definition. + * Operator overload of the BITWISE NOT which gives us the conjugate of our + * complex number. NOTE: This is overloading the BITWISE operator but its + * not a BITWISE operation in this definition. * @return result The conjugate of our complex number. */ Complex operator~() const { @@ -100,18 +100,19 @@ class Complex { } /** - * Operator overload to be able to divide two complex numbers. This function would throw an exception if the other number is zero. + * Operator overload to be able to divide two complex numbers. This function + * would throw an exception if the other number is zero. * @param other The other number we divide our number by. * @return result Current number divided by other number. */ - Complex operator/(const Complex& other) { + Complex operator/(const Complex &other) { Complex result = *this * ~other; double denominator = other.abs() * other.abs(); if (denominator != 0) { - result = Complex(result.real() / denominator, result.imag() / denominator); + result = Complex(result.real() / denominator, + result.imag() / denominator); return result; - } - else { + } else { throw std::invalid_argument("Undefined Value"); } } @@ -124,23 +125,24 @@ class Complex { * @return 'True' If real and imaginary parts of a and b are same * @return 'False' Otherwise. */ -bool operator==(const Complex& a, const Complex& b) { +bool operator==(const Complex &a, const Complex &b) { double del_real = a.real() - b.real(); double del_imag = a.imag() - b.imag(); - return ((del_real <= 1e-15 && del_real >= - 1e-15 ) && (del_imag <= 1e-15 && del_imag >= - 1e-15)); + return ((del_real <= 1e-15 && del_real >= -1e-15) && + (del_imag <= 1e-15 && del_imag >= -1e-15)); } /** - * Overloaded insersion operator to accommodate the printing of our complex number in their standard form. + * Overloaded insersion operator to accommodate the printing of our complex + * number in their standard form. * @param os The console stream * @param num The complex number. */ -std::ostream& operator<<(std::ostream& os, const Complex& num) { +std::ostream &operator<<(std::ostream &os, const Complex &num) { os << num.real(); if (num.imag() < 0) { os << " - " << -num.imag(); - } - else { + } else { os << " + " << num.imag(); } os << "i"; @@ -151,28 +153,32 @@ std::ostream& operator<<(std::ostream& os, const Complex& num) { * Tests Function */ void tests() { - Complex num1(1,1), num2(1,1); + Complex num1(1, 1), num2(1, 1); // Test for addition - assert(((void)"1 + 1i + 1 + 1i is equal to 2 + 2i but the addition doesn't add up \n", - (num1 + num2) == Complex(2,2))); + assert(((void)"1 + 1i + 1 + 1i is equal to 2 + 2i but the addition doesn't " + "add up \n", + (num1 + num2) == Complex(2, 2))); std::cout << "First test passes." << std::endl; // Test for subtraction - assert(((void)"1 + 1i - 1 - 1i is equal to 0 but the program says otherwise. \n", - (num1 - num2) == Complex(0,0))); + assert(((void)"1 + 1i - 1 - 1i is equal to 0 but the program says " + "otherwise. \n", + (num1 - num2) == Complex(0, 0))); std::cout << "Second test passes." << std::endl; // Test for multiplication - assert(((void)"(1 + 1i) * (1 + 1i) is equal to 2i but the program says otherwise. \n", - (num1 * num2) == Complex(0,2))); + assert(((void)"(1 + 1i) * (1 + 1i) is equal to 2i but the program says " + "otherwise. \n", + (num1 * num2) == Complex(0, 2))); std::cout << "Third test passes." << std::endl; // Test for division - assert(((void)"(1 + 1i) / (1 + 1i) is equal to 1 but the program says otherwise.\n", - (num1 / num2) == Complex(1,0))); + assert(((void)"(1 + 1i) / (1 + 1i) is equal to 1 but the program says " + "otherwise.\n", + (num1 / num2) == Complex(1, 0))); std::cout << "Fourth test passes." << std::endl; // Test for conjugates - assert(((void)"(1 + 1i) has a conjugate which is equal to (1 - 1i) but the program says otherwise.\n", - ~num1 == Complex(1,-1))); + assert(((void)"(1 + 1i) has a conjugate which is equal to (1 - 1i) but the " + "program says otherwise.\n", + ~num1 == Complex(1, -1))); std::cout << "Fifth test passes." << std::endl; - } /** * Main function From 8969047d3ff8fe6f08966f0a465b239a4fdc16a0 Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 14:41:46 +0100 Subject: [PATCH 03/92] fix: Added missing header --- math/complex_numbers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 9a381b125..4505b5677 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -9,6 +9,7 @@ #include #include #include +#include /** * Class Complex to represent complex numbers as a field. From 626ab310955b5417675b0487a8d4f79f1786d355 Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 14:53:09 +0100 Subject: [PATCH 04/92] fix: incorrect constructor delegation --- math/complex_numbers.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 4505b5677..10e50b22a 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -36,7 +36,10 @@ class Complex { * Complex Constructor which initialises the complex number with no * arguments. */ - Complex() { Complex(0.0, 0.0); } + Complex() { + this->re = 0.0; + this.im = 0.0; + } /** * Member function (getter) to access the class' re value. From c419e1f7882298fb98567898f82482fd2cd4c29a Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 14:54:10 +0100 Subject: [PATCH 05/92] fix: arrow operator instead of dot --- math/complex_numbers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 10e50b22a..189d0b831 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -38,7 +38,7 @@ class Complex { */ Complex() { this->re = 0.0; - this.im = 0.0; + this->im = 0.0; } /** From 1708de2296204efd863e485068a96078ce76f5af Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 16:23:49 +0100 Subject: [PATCH 06/92] fix: fixed all pull request suggestions --- math/complex_numbers.cpp | 88 +++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 189d0b831..4ae5c493b 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -6,10 +6,11 @@ * overloaded to accommodate (mathematical) field operations. */ +#include #include +#include #include #include -#include /** * Class Complex to represent complex numbers as a field. @@ -27,19 +28,13 @@ class Complex { * @param x The real value of the complex number. * @param y The imaginary value of the complex number. */ - Complex(double x, double y) { - this->re = x; - this->im = y; - } + explicit Complex(double x = 0.f, double y = 0.f) : re(x), im(y) { ; } /** - * Complex Constructor which initialises the complex number with no - * arguments. + * Copy Constructor + * @param other The other number to equate our number to. */ - Complex() { - this->re = 0.0; - this->im = 0.0; - } + Complex(const Complex &other) : re(other.real()), im(other.imag()) { ; } /** * Member function (getter) to access the class' re value. @@ -61,6 +56,26 @@ class Complex { return std::sqrt(this->re * this->re + this->im * this->im); } + /** + * Member function which gives the argument of our complex number. + * @return Argument of our Complex number. + */ + double arg() const { + if (this->re > 0) { + return std::atan(this->im / this->re); + } else if (this->re < 0 && this->im >= 0) { + return std::atan(this->im / this->re) + M_PI; + } else if (this->re < 0 && this->im < 0) { + return std::atan(this->im / this->re) - M_PI; + } else if (this->re == 0 && this->im > 0) { + return M_PI / 2; + } else if (this->re == 0 && this->im < 0) { + return -M_PI / 2; + } else { + throw std::invalid_argument("Undefined Value"); + } + } + /** * Operator overload to be able to add two complex numbers. * @param other The other number that is added to the current number. @@ -111,7 +126,8 @@ class Complex { */ Complex operator/(const Complex &other) { Complex result = *this * ~other; - double denominator = other.abs() * other.abs(); + double denominator = + other.real() * other.real() + other.imag() * other.imag(); if (denominator != 0) { result = Complex(result.real() / denominator, result.imag() / denominator); @@ -120,6 +136,16 @@ class Complex { throw std::invalid_argument("Undefined Value"); } } + + /** + * Operator overload to be able to copy RHS instance of Complex to LHS + * instance of Complex + */ + const Complex &operator=(const Complex &other) { + this->re = other.real(); + this->im = other.imag(); + return *this; + } }; /** @@ -130,10 +156,7 @@ class Complex { * @return 'False' Otherwise. */ bool operator==(const Complex &a, const Complex &b) { - double del_real = a.real() - b.real(); - double del_imag = a.imag() - b.imag(); - return ((del_real <= 1e-15 && del_real >= -1e-15) && - (del_imag <= 1e-15 && del_imag >= -1e-15)); + return a.real() == b.real() && a.imag() == b.imag(); } /** @@ -143,13 +166,13 @@ bool operator==(const Complex &a, const Complex &b) { * @param num The complex number. */ std::ostream &operator<<(std::ostream &os, const Complex &num) { - os << num.real(); + os << "(" << num.real(); if (num.imag() < 0) { os << " - " << -num.imag(); } else { os << " + " << num.imag(); } - os << "i"; + os << "i)"; return os; } @@ -158,32 +181,49 @@ std::ostream &operator<<(std::ostream &os, const Complex &num) { */ void tests() { Complex num1(1, 1), num2(1, 1); + std::complex cnum1(1, 1), cnum2(1, 1); // Test for addition assert(((void)"1 + 1i + 1 + 1i is equal to 2 + 2i but the addition doesn't " "add up \n", - (num1 + num2) == Complex(2, 2))); + ((num1 + num2).real() == (cnum1 + cnum2).real() && + (num1 + num2).imag() == (cnum1 + cnum2).imag()))); std::cout << "First test passes." << std::endl; // Test for subtraction assert(((void)"1 + 1i - 1 - 1i is equal to 0 but the program says " "otherwise. \n", - (num1 - num2) == Complex(0, 0))); + ((num1 - num2).real() == (cnum1 - cnum2).real() && + (num1 - num2).imag() == (cnum1 - cnum2).imag()))); std::cout << "Second test passes." << std::endl; // Test for multiplication assert(((void)"(1 + 1i) * (1 + 1i) is equal to 2i but the program says " "otherwise. \n", - (num1 * num2) == Complex(0, 2))); + ((num1 * num2).real() == (cnum1 * cnum2).real() && + (num1 * num2).imag() == (cnum1 * cnum2).imag()))); std::cout << "Third test passes." << std::endl; // Test for division assert(((void)"(1 + 1i) / (1 + 1i) is equal to 1 but the program says " "otherwise.\n", - (num1 / num2) == Complex(1, 0))); + ((num1 / num2).real() == (cnum1 / cnum2).real() && + (num1 / num2).imag() == (cnum1 / cnum2).imag()))); std::cout << "Fourth test passes." << std::endl; // Test for conjugates assert(((void)"(1 + 1i) has a conjugate which is equal to (1 - 1i) but the " "program says otherwise.\n", - ~num1 == Complex(1, -1))); - std::cout << "Fifth test passes." << std::endl; + ((~num1).real() == std::conj(cnum1).real() && + (~num1).imag() == std::conj(cnum1).imag()))); + std::cout << "Fifth test passes.\n"; + // Test for Argument of our complex number + assert(((void)"(1 + 1i) has argument PI / 4 but the program differs from " + "the std::complex result.\n", + (num1.arg() == std::arg(cnum1)))); + std::cout << "Sixth test passes.\n"; + // Test for absolute value of our complex number + assert(((void)"(1 + 1i) has absolute value sqrt(2) but the program differs " + "from the std::complex result. \n", + (num1.abs() == std::abs(cnum1)))); + std::cout << "Seventh test passes.\n"; } + /** * Main function */ From 52f918a4ffb11aec4fbc4b22d026e2e0a39b867d Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 16:33:54 +0100 Subject: [PATCH 07/92] fix: Fixed issue with Windows CI test - M_PI doesn't work on Windows CI --- math/complex_numbers.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 4ae5c493b..9d6ede15d 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -12,6 +12,11 @@ #include #include +/** + * Global constant for pi to work with Windows environment + */ +const double pi = 3.14159265358979323846; + /** * Class Complex to represent complex numbers as a field. */ @@ -64,13 +69,13 @@ class Complex { if (this->re > 0) { return std::atan(this->im / this->re); } else if (this->re < 0 && this->im >= 0) { - return std::atan(this->im / this->re) + M_PI; + return std::atan(this->im / this->re) + pi; } else if (this->re < 0 && this->im < 0) { - return std::atan(this->im / this->re) - M_PI; + return std::atan(this->im / this->re) - pi; } else if (this->re == 0 && this->im > 0) { - return M_PI / 2; + return pi / 2; } else if (this->re == 0 && this->im < 0) { - return -M_PI / 2; + return -pi / 2; } else { throw std::invalid_argument("Undefined Value"); } From b9658104cb024a1044f2b621566dadf9a184f8a2 Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 17:56:53 +0100 Subject: [PATCH 08/92] fix: Taken onboard some suggested changes --- math/complex_numbers.cpp | 70 ++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 9d6ede15d..03dfe1069 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -12,11 +12,6 @@ #include #include -/** - * Global constant for pi to work with Windows environment - */ -const double pi = 3.14159265358979323846; - /** * Class Complex to represent complex numbers as a field. */ @@ -30,8 +25,8 @@ class Complex { /** * Complex Constructor which initialises the complex number which takes two * arguments. - * @param x The real value of the complex number. - * @param y The imaginary value of the complex number. + * @param x The real value of the complex number (optional). + * @param y The imaginary value of the complex number (optional). */ explicit Complex(double x = 0.f, double y = 0.f) : re(x), im(y) { ; } @@ -63,23 +58,9 @@ class Complex { /** * Member function which gives the argument of our complex number. - * @return Argument of our Complex number. + * @return Argument of our Complex number in radians. */ - double arg() const { - if (this->re > 0) { - return std::atan(this->im / this->re); - } else if (this->re < 0 && this->im >= 0) { - return std::atan(this->im / this->re) + pi; - } else if (this->re < 0 && this->im < 0) { - return std::atan(this->im / this->re) - pi; - } else if (this->re == 0 && this->im > 0) { - return pi / 2; - } else if (this->re == 0 && this->im < 0) { - return -pi / 2; - } else { - throw std::invalid_argument("Undefined Value"); - } - } + double arg() const { return atan2(this->im, this->re); } /** * Operator overload to be able to add two complex numbers. @@ -181,41 +162,60 @@ std::ostream &operator<<(std::ostream &os, const Complex &num) { return os; } +/** + * Function to get random numbers to generate our complex numbers for test + */ +double get_rand() { return (std::rand() % 100 - 50) / 100.f; } + /** * Tests Function */ void tests() { - Complex num1(1, 1), num2(1, 1); - std::complex cnum1(1, 1), cnum2(1, 1); + std::srand(std::time(nullptr)); + double x1 = get_rand(), y1 = get_rand(), x2 = get_rand(), y2 = get_rand(); + Complex num1(x1, y1), num2(x2, y2); + std::complex cnum1(x1, y1), cnum2(x2, y2); + Complex result; + std::complex expected; // Test for addition + result = num1 + num2; + expected = cnum1 + cnum2; assert(((void)"1 + 1i + 1 + 1i is equal to 2 + 2i but the addition doesn't " "add up \n", - ((num1 + num2).real() == (cnum1 + cnum2).real() && - (num1 + num2).imag() == (cnum1 + cnum2).imag()))); + (result.real() == expected.real() && + result.imag() == expected.imag()))); std::cout << "First test passes." << std::endl; // Test for subtraction + result = num1 - num2; + expected = cnum1 - cnum2; assert(((void)"1 + 1i - 1 - 1i is equal to 0 but the program says " "otherwise. \n", - ((num1 - num2).real() == (cnum1 - cnum2).real() && - (num1 - num2).imag() == (cnum1 - cnum2).imag()))); + (result.real() == expected.real() && + result.imag() == expected.imag()))); std::cout << "Second test passes." << std::endl; // Test for multiplication + result = num1 * num2; + expected = cnum1 * cnum2; assert(((void)"(1 + 1i) * (1 + 1i) is equal to 2i but the program says " "otherwise. \n", - ((num1 * num2).real() == (cnum1 * cnum2).real() && - (num1 * num2).imag() == (cnum1 * cnum2).imag()))); + (result.real() == expected.real() && + result.imag() == expected.imag()))); std::cout << "Third test passes." << std::endl; // Test for division + result = num1 / num2; + expected = cnum1 / cnum2; assert(((void)"(1 + 1i) / (1 + 1i) is equal to 1 but the program says " "otherwise.\n", - ((num1 / num2).real() == (cnum1 / cnum2).real() && - (num1 / num2).imag() == (cnum1 / cnum2).imag()))); + (result.real() == expected.real() && + result.imag() == expected.imag()))); std::cout << "Fourth test passes." << std::endl; // Test for conjugates + result = ~num1; + expected = std::conj(cnum1); assert(((void)"(1 + 1i) has a conjugate which is equal to (1 - 1i) but the " "program says otherwise.\n", - ((~num1).real() == std::conj(cnum1).real() && - (~num1).imag() == std::conj(cnum1).imag()))); + (result.real() == expected.real() && + result.imag() == expected.imag()))); std::cout << "Fifth test passes.\n"; // Test for Argument of our complex number assert(((void)"(1 + 1i) has argument PI / 4 but the program differs from " From 907b8298309d898b6d3b967a9ba5b3fc62a6afe8 Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 18:00:53 +0100 Subject: [PATCH 09/92] docs: copyright message --- math/complex_numbers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 03dfe1069..b2353d785 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -1,5 +1,5 @@ /** - * Copyright 2020 @author tjgurwara99 + * @author tjgurwara99 * @file * * A basic implementation of Complex Number field as a class with operators From ce81700380e656ce6ec8898c7e87e3669ec9e5c3 Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 18:04:42 +0100 Subject: [PATCH 10/92] fix: added missing header for std::time --- math/complex_numbers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index b2353d785..43b1d5fda 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -11,6 +11,7 @@ #include #include #include +#include /** * Class Complex to represent complex numbers as a field. From 61084adbd3b73aa5312836aa1836188dc24881f8 Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 18:16:26 +0100 Subject: [PATCH 11/92] fix: fixed forgotten namespace --- math/complex_numbers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 43b1d5fda..9168c08aa 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -61,7 +61,7 @@ class Complex { * Member function which gives the argument of our complex number. * @return Argument of our Complex number in radians. */ - double arg() const { return atan2(this->im, this->re); } + double arg() const { return std::atan2(this->im, this->re); } /** * Operator overload to be able to add two complex numbers. From bcd5df725d83e06ae2fb69b0ccacbef5c56e454b Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 19:23:15 +0100 Subject: [PATCH 12/92] feat: added polar form initialisation to our Complex class --- math/complex_numbers.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 9168c08aa..35e11ba1d 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -9,9 +9,9 @@ #include #include #include +#include #include #include -#include /** * Class Complex to represent complex numbers as a field. @@ -26,10 +26,22 @@ class Complex { /** * Complex Constructor which initialises the complex number which takes two * arguments. - * @param x The real value of the complex number (optional). - * @param y The imaginary value of the complex number (optional). + * @param x If the third parameter is 'true' then this x is the absolute + * value of the complex number, if the third parameter is 'false' then this + * x is the real value of the complex number (optional). + * @param y If the third parameter is 'true' then this y is the argument of + * the complex number, if the third parameter is 'false' then this y is the + * imaginary value of the complex number (optional). + * @param is_polar 'false' by default. If we want to initialise our complex + * number using polar form then set this to true, otherwise set it to false + * to use initialiser which initialises real and imaginary values using the + * first two parameters (optional). */ - explicit Complex(double x = 0.f, double y = 0.f) : re(x), im(y) { ; } + explicit Complex(double x = 0.f, double y = 0.f, bool is_polar = false) + : re(is_polar ? x * std::cos(y) : x), + im(is_polar ? x * std::sin(y) : y) { + ; + } /** * Copy Constructor From 95320b38a4a2aefaf0eb6b757438560b36d272f4 Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 19:29:11 +0100 Subject: [PATCH 13/92] fix: cpplint issues --- math/complex_numbers.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 35e11ba1d..a4ee69829 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -22,7 +22,7 @@ class Complex { // The imaginary value of the complex number double im; - public: + public: /** * Complex Constructor which initialises the complex number which takes two * arguments. @@ -39,9 +39,7 @@ class Complex { */ explicit Complex(double x = 0.f, double y = 0.f, bool is_polar = false) : re(is_polar ? x * std::cos(y) : x), - im(is_polar ? x * std::sin(y) : y) { - ; - } + im(is_polar ? x * std::sin(y) : y) { ; } /** * Copy Constructor From 9048e19184c3df765465c150ec7fa89151c41cd5 Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 19:32:05 +0100 Subject: [PATCH 14/92] fix: cpplint issues --- math/complex_numbers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index a4ee69829..30edf4964 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -39,13 +39,13 @@ class Complex { */ explicit Complex(double x = 0.f, double y = 0.f, bool is_polar = false) : re(is_polar ? x * std::cos(y) : x), - im(is_polar ? x * std::sin(y) : y) { ; } + im(is_polar ? x * std::sin(y) : y) {} /** * Copy Constructor * @param other The other number to equate our number to. */ - Complex(const Complex &other) : re(other.real()), im(other.imag()) { ; } + Complex(const Complex &other) : re(other.real()), im(other.imag()) {} /** * Member function (getter) to access the class' re value. From 75d8ee7cf07ee546e5f9fdbfad904060840fa607 Mon Sep 17 00:00:00 2001 From: Tajmeet Singh Date: Tue, 23 Jun 2020 19:43:56 +0100 Subject: [PATCH 15/92] fix: Readability issues --- math/complex_numbers.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/math/complex_numbers.cpp b/math/complex_numbers.cpp index 30edf4964..8b24c6d3c 100644 --- a/math/complex_numbers.cpp +++ b/math/complex_numbers.cpp @@ -37,9 +37,16 @@ class Complex { * to use initialiser which initialises real and imaginary values using the * first two parameters (optional). */ - explicit Complex(double x = 0.f, double y = 0.f, bool is_polar = false) - : re(is_polar ? x * std::cos(y) : x), - im(is_polar ? x * std::sin(y) : y) {} + explicit Complex(double x = 0.f, double y = 0.f, bool is_polar = false) { + if (!is_polar) { + re = x; + im = y; + return; + } + + re = x * std::cos(y); + im = x * std::sin(y); + } /** * Copy Constructor From 7393d88811c7ddb58d73db3fd554eb1fd414f298 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 23 Jun 2020 19:02:47 +0000 Subject: [PATCH 16/92] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 080e5f5d8..eb75ce3e5 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -102,6 +102,7 @@ ## Math * [Binary Exponent](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/binary_exponent.cpp) * [Check Prime](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/check_prime.cpp) + * [Complex Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/complex_numbers.cpp) * [Double Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/double_factorial.cpp) * [Eulers Totient Function](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/eulers_totient_function.cpp) * [Extended Euclid Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/extended_euclid_algorithm.cpp) From 1d7a73ea583c27eaa39ed90793db698e6997b6a7 Mon Sep 17 00:00:00 2001 From: Neeraj C <35414531+iamnambiar@users.noreply.github.com> Date: Wed, 24 Jun 2020 01:03:42 +0530 Subject: [PATCH 17/92] feat: add check_amicable_pair.cpp (#879) * feat: add check_amicable_pair.cpp * fix: space between else and brace. * fix: spaces between tokens * fix: removed sqrt and test func combined to single * docs: removed wiki link Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> * docs: add markdown syntax for wikipedia link Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> * docs: change brief to details in comment Line 7 Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> * docs: typo fixed Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> * docs: removed extra line Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> * docs: removed copyright Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> * docs: add author name Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> * fix: shortened the code in is_amicable() Co-authored-by: David Leal * fix: changed is_amicable to are_amicable * docs: cleared unwanted line Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Co-authored-by: David Leal --- math/check_amicable_pair.cpp | 70 ++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 math/check_amicable_pair.cpp diff --git a/math/check_amicable_pair.cpp b/math/check_amicable_pair.cpp new file mode 100644 index 000000000..83a5d7364 --- /dev/null +++ b/math/check_amicable_pair.cpp @@ -0,0 +1,70 @@ +/** + * + * @file + * \brief A C++ Program to check whether a pair of number is [amicable pair](https://en.wikipedia.org/wiki/Amicable_numbers) or not. + * + * \details + * Amicable Pair are two positive integers such that sum of the proper divisor + * of each number is equal to the other number. + * @author iamnambiar + */ +#include +#include + +/** + * Function to calculate the sum of all the proper divisor + * of an integer. + * @param num First number. + * @return Sum of the proper divisor of the number. + */ +int sum_of_divisor(int num) { + // Variable to store the sum of all proper divisors. + int sum = 0; + // Below loop condition helps to reduce Time complexity by a factor of square root of the number. + for (int div = 2; div * div <= num; ++div) { + // Check 'div' is divisor of 'num'. + if (num % div == 0) { + // If both divisor are same, add once to 'sum' + if (div == (num / div)) { + sum += div; + } else { + // If both divisor are not the same, add both to 'sum'. + sum += (div + (num / div)); + } + } + } + return sum + 1; +} + +/** + * Function to check whether the pair is amicable or not. + * @param x First number. + * @param y Second number. + * @return `true` if the pair is amicable + * @return `false` if the pair is not amicable + */ +bool are_amicable(int x, int y) { + return (sum_of_divisor(x) == y) && (sum_of_divisor(y) == x); +} + +/** + * Function for testing the is_amicable() with + * all the test cases. + */ +void test() { + // are_amicable(220, 284) returns true. + assert(are_amicable(220, 284) == true); + // are_amicable(6232, 6368) returns true. + assert(are_amicable(6368, 6232) == true); + // are_amicable(458, 232) returns false. + assert(are_amicable(458, 232) == false); +} + +/** + * Main Function +*/ +int main() { + test(); + std::cout << "Assertion Success." << std::endl; + return 0; +} From 2d4a1dd19fd6835c63bb533aedcf3ab807fa889a Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 23 Jun 2020 19:34:19 +0000 Subject: [PATCH 18/92] formatting source-code for 1d7a73ea583c27eaa39ed90793db698e6997b6a7 --- math/check_amicable_pair.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/math/check_amicable_pair.cpp b/math/check_amicable_pair.cpp index 83a5d7364..4f1255d19 100644 --- a/math/check_amicable_pair.cpp +++ b/math/check_amicable_pair.cpp @@ -1,18 +1,19 @@ /** - * + * * @file - * \brief A C++ Program to check whether a pair of number is [amicable pair](https://en.wikipedia.org/wiki/Amicable_numbers) or not. - * + * \brief A C++ Program to check whether a pair of number is [amicable + * pair](https://en.wikipedia.org/wiki/Amicable_numbers) or not. + * * \details - * Amicable Pair are two positive integers such that sum of the proper divisor + * Amicable Pair are two positive integers such that sum of the proper divisor * of each number is equal to the other number. * @author iamnambiar */ -#include #include +#include /** - * Function to calculate the sum of all the proper divisor + * Function to calculate the sum of all the proper divisor * of an integer. * @param num First number. * @return Sum of the proper divisor of the number. @@ -20,7 +21,8 @@ int sum_of_divisor(int num) { // Variable to store the sum of all proper divisors. int sum = 0; - // Below loop condition helps to reduce Time complexity by a factor of square root of the number. + // Below loop condition helps to reduce Time complexity by a factor of + // square root of the number. for (int div = 2; div * div <= num; ++div) { // Check 'div' is divisor of 'num'. if (num % div == 0) { @@ -48,7 +50,7 @@ bool are_amicable(int x, int y) { } /** - * Function for testing the is_amicable() with + * Function for testing the is_amicable() with * all the test cases. */ void test() { @@ -62,7 +64,7 @@ void test() { /** * Main Function -*/ + */ int main() { test(); std::cout << "Assertion Success." << std::endl; From 26ffe8c6d7c30220b05af8071a3bbd0c4c6afb35 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 23 Jun 2020 19:34:19 +0000 Subject: [PATCH 19/92] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index eb75ce3e5..6e43ba3f2 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -101,6 +101,7 @@ ## Math * [Binary Exponent](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/binary_exponent.cpp) + * [Check Amicable Pair](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/check_amicable_pair.cpp) * [Check Prime](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/check_prime.cpp) * [Complex Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/complex_numbers.cpp) * [Double Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/double_factorial.cpp) From 0356a9cdf30b0f3ecdf5632e73e9f8a00a924253 Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 14:35:13 -0500 Subject: [PATCH 20/92] fix: Various LGTM fixes --- data_structures/binary_search_tree.cpp | 12 ++++++------ math/realtime_stats.cpp | 2 +- sorting/bead_sort.cpp | 2 +- sorting/comb_sort.cpp | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/data_structures/binary_search_tree.cpp b/data_structures/binary_search_tree.cpp index 3cc7d09fb..86057c6c5 100644 --- a/data_structures/binary_search_tree.cpp +++ b/data_structures/binary_search_tree.cpp @@ -14,17 +14,17 @@ struct node { node *right; }; -struct queue { +struct Queue { node *t[100]; int front; int rear; }; -queue q; +Queue queue; -void enqueue(node *n) { q.t[q.rear++] = n; } +void enqueue(node *n) { queue.t[queue.rear++] = n; } -node *dequeue() { return (q.t[q.front++]); } +node *dequeue() { return (queue.t[queue.front++]); } void Insert(node *n, int x) { if (x < n->val) { @@ -123,8 +123,8 @@ void Post(node *n) { } int main() { - q.front = 0; - q.rear = 0; + queue.front = 0; + queue.rear = 0; int value; int ch; node *root = new node; diff --git a/math/realtime_stats.cpp b/math/realtime_stats.cpp index 5f353ac4d..672acfa03 100644 --- a/math/realtime_stats.cpp +++ b/math/realtime_stats.cpp @@ -35,7 +35,7 @@ class stats_computer1 { n++; T tmp = x - K; Ex += tmp; - Ex2 += tmp * tmp; + Ex2 += static_cast(tmp) * tmp; } /** return sample mean computed till last sample */ diff --git a/sorting/bead_sort.cpp b/sorting/bead_sort.cpp index f3276bfcd..4745987d9 100644 --- a/sorting/bead_sort.cpp +++ b/sorting/bead_sort.cpp @@ -14,7 +14,7 @@ void beadSort(int *a, int len) { // allocating memory unsigned char *beads = new unsigned char[max * len]; - memset(beads, 0, max * len); + memset(beads, 0, static_cast(max) * len); // mark the beads for (int i = 0; i < len; i++) diff --git a/sorting/comb_sort.cpp b/sorting/comb_sort.cpp index 1b0a4d706..ab0b456dd 100644 --- a/sorting/comb_sort.cpp +++ b/sorting/comb_sort.cpp @@ -14,7 +14,7 @@ int FindNextGap(int x) { return std::max(1, x); } -void CombSort(int a[], int l, int r) { +void CombSort(int b[], int l, int r) { // Init gap int gap = n; @@ -30,8 +30,8 @@ void CombSort(int a[], int l, int r) { // Compare all elements with current gap for (int i = l; i <= r - gap; ++i) { - if (a[i] > a[i + gap]) { - std::swap(a[i], a[i + gap]); + if (b[i] > b[i + gap]) { + std::swap(b[i], b[i + gap]); swapped = true; } } From 0767af4a0d20f22c9bb22e569aa9d24ea5a09f5a Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 15:26:55 -0500 Subject: [PATCH 21/92] fix: Revert `comb_sort` changes --- sorting/comb_sort.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sorting/comb_sort.cpp b/sorting/comb_sort.cpp index ab0b456dd..1b0a4d706 100644 --- a/sorting/comb_sort.cpp +++ b/sorting/comb_sort.cpp @@ -14,7 +14,7 @@ int FindNextGap(int x) { return std::max(1, x); } -void CombSort(int b[], int l, int r) { +void CombSort(int a[], int l, int r) { // Init gap int gap = n; @@ -30,8 +30,8 @@ void CombSort(int b[], int l, int r) { // Compare all elements with current gap for (int i = l; i <= r - gap; ++i) { - if (b[i] > b[i + gap]) { - std::swap(b[i], b[i + gap]); + if (a[i] > a[i + gap]) { + std::swap(a[i], a[i + gap]); swapped = true; } } From 48b7773b37fe13792eed229e12aa54bec7d1ce5a Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 16:34:53 -0500 Subject: [PATCH 22/92] fix: Various LGTM fixes --- data_structures/stack_using_array.cpp | 14 +++++++------- data_structures/stack_using_linked_list.cpp | 14 +++++++------- math/fibonacci_fast.cpp | 12 ++++++------ others/paranthesis_matching.cpp | 10 +++++----- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/data_structures/stack_using_array.cpp b/data_structures/stack_using_array.cpp index 36be9eb39..ab2d7d7dd 100644 --- a/data_structures/stack_using_array.cpp +++ b/data_structures/stack_using_array.cpp @@ -1,31 +1,31 @@ #include int *stack; -int top = 0, stack_size; +int top_var = 0, stack_size; void push(int x) { - if (top == stack_size) { + if (top_var == stack_size) { std::cout << "\nOverflow"; } else { - stack[top++] = x; + stack[top_var++] = x; } } void pop() { - if (top == 0) { + if (top_var == 0) { std::cout << "\nUnderflow"; } else { - std::cout << "\n" << stack[--top] << " deleted"; + std::cout << "\n" << stack[--top_var] << " deleted"; } } void show() { - for (int i = 0; i < top; i++) { + for (int i = 0; i < top_var; i++) { std::cout << stack[i] << "\n"; } } -void topmost() { std::cout << "\nTopmost element: " << stack[top - 1]; } +void topmost() { std::cout << "\nTopmost element: " << stack[top_var - 1]; } int main() { std::cout << "\nEnter stack_size of stack : "; std::cin >> stack_size; diff --git a/data_structures/stack_using_linked_list.cpp b/data_structures/stack_using_linked_list.cpp index ae53fe95a..05f0d3d6a 100644 --- a/data_structures/stack_using_linked_list.cpp +++ b/data_structures/stack_using_linked_list.cpp @@ -6,28 +6,28 @@ struct node { node *next; }; -node *top; +node *top_var; void push(int x) { node *n = new node; n->val = x; - n->next = top; - top = n; + n->next = top_var; + top_var = n; } void pop() { - if (top == NULL) { + if (top_var == NULL) { cout << "\nUnderflow"; } else { - node *t = top; + node *t = top_var; cout << "\n" << t->val << " deleted"; - top = top->next; + top_var = top_var->next; delete t; } } void show() { - node *t = top; + node *t = top_var; while (t != NULL) { cout << t->val << "\n"; t = t->next; diff --git a/math/fibonacci_fast.cpp b/math/fibonacci_fast.cpp index 8fdb20058..80e9108ea 100644 --- a/math/fibonacci_fast.cpp +++ b/math/fibonacci_fast.cpp @@ -24,23 +24,23 @@ const uint64_t MAX = 93; /** Array of computed fibonacci numbers */ -uint64_t f[MAX] = {0}; +uint64_t numbers[MAX] = {0}; /** Algorithm */ uint64_t fib(uint64_t n) { if (n == 0) return 0; if (n == 1 || n == 2) - return (f[n] = 1); + return (numbers[n] = 1); - if (f[n]) - return f[n]; + if (numbers[n]) + return numbers[n]; uint64_t k = (n % 2 != 0) ? (n + 1) / 2 : n / 2; - f[n] = (n % 2 != 0) ? (fib(k) * fib(k) + fib(k - 1) * fib(k - 1)) + numbers[n] = (n % 2 != 0) ? (fib(k) * fib(k) + fib(k - 1) * fib(k - 1)) : (2 * fib(k - 1) + fib(k)) * fib(k); - return f[n]; + return numbers[n]; } /** Main function */ diff --git a/others/paranthesis_matching.cpp b/others/paranthesis_matching.cpp index 2a6358d94..0a1a9e474 100644 --- a/others/paranthesis_matching.cpp +++ b/others/paranthesis_matching.cpp @@ -20,13 +20,13 @@ char stack[MAX]; //! pointer to track stack index -int top = -1; +int top_var = -1; //! push byte to stack variable -void push(char ch) { stack[++top] = ch; } +void push(char ch) { stack[++top_var] = ch; } //! pop a byte out of stack variable -char pop() { return stack[top--]; } +char pop() { return stack[top_var--]; } //! @}-------------- end stack ----------- @@ -56,7 +56,7 @@ int main() { while (valid == 1 && i < exp.length()) { if (exp[i] == '(' || exp[i] == '{' || exp[i] == '[' || exp[i] == '<') { push(exp[i]); - } else if (top >= 0 && stack[top] == opening(exp[i])) { + } else if (top_var >= 0 && stack[top_var] == opening(exp[i])) { pop(); } else { valid = 0; @@ -65,7 +65,7 @@ int main() { } // makes sure the stack is empty after processsing (above) - if (valid == 1 && top == -1) { + if (valid == 1 && top_var == -1) { std::cout << "\nCorrect Expression"; } else { std::cout << "\nWrong Expression"; From cdacbf1998fd060c08897c687f8f695ff27559fa Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 16:37:46 -0500 Subject: [PATCH 23/92] fix: Remove namespace --- data_structures/stack_using_linked_list.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/data_structures/stack_using_linked_list.cpp b/data_structures/stack_using_linked_list.cpp index 05f0d3d6a..3dcf03f8a 100644 --- a/data_structures/stack_using_linked_list.cpp +++ b/data_structures/stack_using_linked_list.cpp @@ -1,5 +1,4 @@ #include -using namespace std; struct node { int val; @@ -17,10 +16,10 @@ void push(int x) { void pop() { if (top_var == NULL) { - cout << "\nUnderflow"; + std::cout << "\nUnderflow"; } else { node *t = top_var; - cout << "\n" << t->val << " deleted"; + std::cout << "\n" << t->val << " deleted"; top_var = top_var->next; delete t; } @@ -29,7 +28,7 @@ void pop() { void show() { node *t = top_var; while (t != NULL) { - cout << t->val << "\n"; + std::cout << t->val << "\n"; t = t->next; } } @@ -37,14 +36,14 @@ void show() { int main() { int ch, x; do { - cout << "\n1. Push"; - cout << "\n2. Pop"; - cout << "\n3. Print"; - cout << "\nEnter Your Choice : "; - cin >> ch; + std::cout << "\n1. Push"; + std::cout << "\n2. Pop"; + std::cout << "\n3. Print"; + std::cout << "\nEnter Your Choice : "; + std::cin >> ch; if (ch == 1) { - cout << "\nInsert : "; - cin >> x; + std::cout << "\nInsert : "; + std::cin >> x; push(x); } else if (ch == 2) { pop(); From a6c3667f308cc27c3b97beafe0123885d38114a2 Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 17:38:17 -0500 Subject: [PATCH 24/92] fix: Release allocated memory --- data_structures/stack_using_array.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data_structures/stack_using_array.cpp b/data_structures/stack_using_array.cpp index ab2d7d7dd..6702f2d59 100644 --- a/data_structures/stack_using_array.cpp +++ b/data_structures/stack_using_array.cpp @@ -51,5 +51,7 @@ int main() { } } while (ch != 0); + delete stack; + return 0; } From 957a05bd0cd7e21017e13f57be3998ae1cdd7b73 Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 17:39:29 -0500 Subject: [PATCH 25/92] fix: Convert global variables to local --- math/fibonacci_fast.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/math/fibonacci_fast.cpp b/math/fibonacci_fast.cpp index 80e9108ea..dba8b9dc0 100644 --- a/math/fibonacci_fast.cpp +++ b/math/fibonacci_fast.cpp @@ -19,15 +19,15 @@ #include #include -/** maximum number that can be computed - The result after 93 cannot be stored - * in a `uint64_t` data type. */ -const uint64_t MAX = 93; - -/** Array of computed fibonacci numbers */ -uint64_t numbers[MAX] = {0}; - /** Algorithm */ uint64_t fib(uint64_t n) { + // maximum number that can be computed - The result after 93 cannot be stored + // in a `uint64_t` data type. + static const uint64_t MAX = 93; + + // Array of computed fibonacci numbers */ + static uint64_t numbers[MAX] = {0}; + if (n == 0) return 0; if (n == 1 || n == 2) From cea644bdc31710e1544623934e8ca8646fc9a97d Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 17:52:04 -0500 Subject: [PATCH 26/92] fix: Use delete[] operator --- data_structures/stack_using_array.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/stack_using_array.cpp b/data_structures/stack_using_array.cpp index 6702f2d59..b78e08e37 100644 --- a/data_structures/stack_using_array.cpp +++ b/data_structures/stack_using_array.cpp @@ -51,7 +51,7 @@ int main() { } } while (ch != 0); - delete stack; + delete[] stack; return 0; } From da18b9049898dc061e3cb2e5b73f173a90bf19d4 Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 17:53:20 -0500 Subject: [PATCH 27/92] fix: Use #define --- math/fibonacci_fast.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/math/fibonacci_fast.cpp b/math/fibonacci_fast.cpp index dba8b9dc0..fa81f9561 100644 --- a/math/fibonacci_fast.cpp +++ b/math/fibonacci_fast.cpp @@ -19,12 +19,15 @@ #include #include +/** + * maximum number that can be computed - The result after 93 cannot be stored + * in a `uint64_t` data type. + */ + +#define MAX 93 + /** Algorithm */ uint64_t fib(uint64_t n) { - // maximum number that can be computed - The result after 93 cannot be stored - // in a `uint64_t` data type. - static const uint64_t MAX = 93; - // Array of computed fibonacci numbers */ static uint64_t numbers[MAX] = {0}; From 01c52789111c8853db3812a36b139e4670431eed Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 18:22:21 -0500 Subject: [PATCH 28/92] fix: fibonacci_fast.cpp fixes --- math/fibonacci_fast.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/math/fibonacci_fast.cpp b/math/fibonacci_fast.cpp index fa81f9561..be68bab70 100644 --- a/math/fibonacci_fast.cpp +++ b/math/fibonacci_fast.cpp @@ -28,22 +28,20 @@ /** Algorithm */ uint64_t fib(uint64_t n) { - // Array of computed fibonacci numbers */ - static uint64_t numbers[MAX] = {0}; + static uint64_t f1 = 1, f2 = 1; // using static keyword will retain the values of f1 and f2 for the next function call. - if (n == 0) + if (n <= 2) + return f2; + if (n >= 93) { + std::err << "Cannot compute for n>93 due to limit of 64-bit integers\n"; return 0; - if (n == 1 || n == 2) - return (numbers[n] = 1); + } - if (numbers[n]) - return numbers[n]; + uint64_t temp = f2; // we do not need temp to be static + f2 += f1; + f1 = temp; - uint64_t k = (n % 2 != 0) ? (n + 1) / 2 : n / 2; - - numbers[n] = (n % 2 != 0) ? (fib(k) * fib(k) + fib(k - 1) * fib(k - 1)) - : (2 * fib(k - 1) + fib(k)) * fib(k); - return numbers[n]; + return f2; } /** Main function */ From 52b9b0bb98ad730822fc07834e2f06afeaebe8f4 Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 18:23:37 -0500 Subject: [PATCH 29/92] docs: Change variable name --- data_structures/stack_using_array.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/data_structures/stack_using_array.cpp b/data_structures/stack_using_array.cpp index b78e08e37..22b397ba8 100644 --- a/data_structures/stack_using_array.cpp +++ b/data_structures/stack_using_array.cpp @@ -1,31 +1,31 @@ #include int *stack; -int top_var = 0, stack_size; +int stack_idx = 0, stack_size; void push(int x) { - if (top_var == stack_size) { + if (stack_idx == stack_size) { std::cout << "\nOverflow"; } else { - stack[top_var++] = x; + stack[stack_idx++] = x; } } void pop() { - if (top_var == 0) { + if (stack_idx == 0) { std::cout << "\nUnderflow"; } else { - std::cout << "\n" << stack[--top_var] << " deleted"; + std::cout << "\n" << stack[--stack_idx] << " deleted"; } } void show() { - for (int i = 0; i < top_var; i++) { + for (int i = 0; i < stack_idx; i++) { std::cout << stack[i] << "\n"; } } -void topmost() { std::cout << "\nTopmost element: " << stack[top_var - 1]; } +void topmost() { std::cout << "\nTopmost element: " << stack[stack_idx - 1]; } int main() { std::cout << "\nEnter stack_size of stack : "; std::cin >> stack_size; From f05aadf3b8fddae08331fa127f7e75a6ab44e37a Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 18:26:47 -0500 Subject: [PATCH 30/92] fix: Wrong function name --- math/fibonacci_fast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/fibonacci_fast.cpp b/math/fibonacci_fast.cpp index be68bab70..e7582df73 100644 --- a/math/fibonacci_fast.cpp +++ b/math/fibonacci_fast.cpp @@ -33,7 +33,7 @@ uint64_t fib(uint64_t n) { if (n <= 2) return f2; if (n >= 93) { - std::err << "Cannot compute for n>93 due to limit of 64-bit integers\n"; + std::cerr << "Cannot compute for n>93 due to limit of 64-bit integers\n"; return 0; } From b6fdaa63eb5f14c1a8d18aef476707baccd72ee6 Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 18:45:56 -0500 Subject: [PATCH 31/92] docs: Change variable names --- data_structures/stack_using_linked_list.cpp | 14 +++++++------- others/paranthesis_matching.cpp | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/data_structures/stack_using_linked_list.cpp b/data_structures/stack_using_linked_list.cpp index 3dcf03f8a..315b4e3b9 100644 --- a/data_structures/stack_using_linked_list.cpp +++ b/data_structures/stack_using_linked_list.cpp @@ -5,28 +5,28 @@ struct node { node *next; }; -node *top_var; +node *stack_idx; void push(int x) { node *n = new node; n->val = x; - n->next = top_var; - top_var = n; + n->next = stack_idx; + stack_idx = n; } void pop() { - if (top_var == NULL) { + if (stack_idx == NULL) { std::cout << "\nUnderflow"; } else { - node *t = top_var; + node *t = stack_idx; std::cout << "\n" << t->val << " deleted"; - top_var = top_var->next; + stack_idx = stack_idx->next; delete t; } } void show() { - node *t = top_var; + node *t = stack_idx; while (t != NULL) { std::cout << t->val << "\n"; t = t->next; diff --git a/others/paranthesis_matching.cpp b/others/paranthesis_matching.cpp index 0a1a9e474..d9c52c813 100644 --- a/others/paranthesis_matching.cpp +++ b/others/paranthesis_matching.cpp @@ -20,13 +20,13 @@ char stack[MAX]; //! pointer to track stack index -int top_var = -1; +int stack_idx = -1; //! push byte to stack variable -void push(char ch) { stack[++top_var] = ch; } +void push(char ch) { stack[++stack_idx] = ch; } //! pop a byte out of stack variable -char pop() { return stack[top_var--]; } +char pop() { return stack[stack_idx--]; } //! @}-------------- end stack ----------- @@ -56,7 +56,7 @@ int main() { while (valid == 1 && i < exp.length()) { if (exp[i] == '(' || exp[i] == '{' || exp[i] == '[' || exp[i] == '<') { push(exp[i]); - } else if (top_var >= 0 && stack[top_var] == opening(exp[i])) { + } else if (stack_idx >= 0 && stack[stack_idx] == opening(exp[i])) { pop(); } else { valid = 0; @@ -65,7 +65,7 @@ int main() { } // makes sure the stack is empty after processsing (above) - if (valid == 1 && top_var == -1) { + if (valid == 1 && stack_idx == -1) { std::cout << "\nCorrect Expression"; } else { std::cout << "\nWrong Expression"; From e0fa86816aee2c41d21a2716c0ef913c5ad1ec3e Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Tue, 23 Jun 2020 18:50:14 -0500 Subject: [PATCH 32/92] fix: Variable name --- data_structures/stack_using_linked_list.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/data_structures/stack_using_linked_list.cpp b/data_structures/stack_using_linked_list.cpp index 315b4e3b9..3dcf03f8a 100644 --- a/data_structures/stack_using_linked_list.cpp +++ b/data_structures/stack_using_linked_list.cpp @@ -5,28 +5,28 @@ struct node { node *next; }; -node *stack_idx; +node *top_var; void push(int x) { node *n = new node; n->val = x; - n->next = stack_idx; - stack_idx = n; + n->next = top_var; + top_var = n; } void pop() { - if (stack_idx == NULL) { + if (top_var == NULL) { std::cout << "\nUnderflow"; } else { - node *t = stack_idx; + node *t = top_var; std::cout << "\n" << t->val << " deleted"; - stack_idx = stack_idx->next; + top_var = top_var->next; delete t; } } void show() { - node *t = stack_idx; + node *t = top_var; while (t != NULL) { std::cout << t->val << "\n"; t = t->next; From 95890fdb6642ba584c28368126344a44aa69e2f2 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Wed, 24 Jun 2020 10:26:55 -0400 Subject: [PATCH 33/92] create copy constructor --- data_structures/stack.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/data_structures/stack.h b/data_structures/stack.h index f4b8992e7..3957b4d8d 100644 --- a/data_structures/stack.h +++ b/data_structures/stack.h @@ -34,6 +34,36 @@ class stack { size = 0; } + /** Copy constructor*/ + explicit stack(const stack &other) { + node *newNode, *current, *last; + + /* If stack is no empty, make it empty */ + if (stackTop != NULL) { + stackTop = NULL; + } + if (otherStack.stackTop == NULL) { + stackTop = NULL; + } else { + current = otherStack.stackTop; + stackTop = new node; + stackTop->data = current->data; + stackTop->next = NULL; + last = stackTop; + current = current->next; + /* Copy the remaining stack */ + while (current != NULL) { + newNode = new node; + newNode->data = current->data; + newNode->next = NULL; + last->next = newNode; + last = newNode; + current = current->next; + } + } + size = otherStack.size; + } + /** Destructor */ ~stack() {} From 94a494edf59a99ec0457e7fa264e7d17b4c5c6ce Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Wed, 24 Jun 2020 10:27:23 -0400 Subject: [PATCH 34/92] replace NULL with nullptr --- data_structures/stack.h | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/data_structures/stack.h b/data_structures/stack.h index 3957b4d8d..31a5abe34 100644 --- a/data_structures/stack.h +++ b/data_structures/stack.h @@ -20,7 +20,7 @@ class stack { void display() { node *current = stackTop; std::cout << "Top --> "; - while (current != NULL) { + while (current != nullptr) { std::cout << current->data << " "; current = current->next; } @@ -30,7 +30,7 @@ class stack { /** Default constructor*/ stack() { - stackTop = NULL; + stackTop = nullptr; size = 0; } @@ -39,23 +39,23 @@ class stack { node *newNode, *current, *last; /* If stack is no empty, make it empty */ - if (stackTop != NULL) { - stackTop = NULL; + if (stackTop != nullptr) { + stackTop = nullptr; } - if (otherStack.stackTop == NULL) { - stackTop = NULL; + if (otherStack.stackTop == nullptr) { + stackTop = nullptr; } else { current = otherStack.stackTop; stackTop = new node; stackTop->data = current->data; - stackTop->next = NULL; + stackTop->next = nullptr; last = stackTop; current = current->next; /* Copy the remaining stack */ - while (current != NULL) { + while (current != nullptr) { newNode = new node; newNode->data = current->data; - newNode->next = NULL; + newNode->next = nullptr; last->next = newNode; last = newNode; current = current->next; @@ -68,7 +68,7 @@ class stack { ~stack() {} /** Determine whether the stack is empty */ - bool isEmptyStack() { return (stackTop == NULL); } + bool isEmptyStack() { return (stackTop == nullptr); } /** Add new item to the stack */ void push(Type item) { @@ -82,7 +82,7 @@ class stack { /** Return the top element of the stack */ Type top() { - assert(stackTop != NULL); + assert(stackTop != nullptr); return stackTop->data; } @@ -100,30 +100,30 @@ class stack { } /** Clear stack */ - void clear() { stackTop = NULL; } + void clear() { stackTop = nullptr; } /** Overload "=" the assignment operator */ stack &operator=(const stack &otherStack) { node *newNode, *current, *last; /* If stack is no empty, make it empty */ - if (stackTop != NULL) { - stackTop = NULL; + if (stackTop != nullptr) { + stackTop = nullptr; } - if (otherStack.stackTop == NULL) { - stackTop = NULL; + if (otherStack.stackTop == nullptr) { + stackTop = nullptr; } else { current = otherStack.stackTop; stackTop = new node; stackTop->data = current->data; - stackTop->next = NULL; + stackTop->next = nullptr; last = stackTop; current = current->next; /* Copy the remaining stack */ - while (current != NULL) { + while (current != nullptr) { newNode = new node; newNode->data = current->data; - newNode->next = NULL; + newNode->next = nullptr; last->next = newNode; last = newNode; current = current->next; From 631b50cede4ad0cc5ad350f88c2cc01280d54101 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Wed, 24 Jun 2020 10:37:15 -0400 Subject: [PATCH 35/92] update documetnation --- data_structures/stack.h | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/data_structures/stack.h b/data_structures/stack.h index 31a5abe34..429e0265f 100644 --- a/data_structures/stack.h +++ b/data_structures/stack.h @@ -1,18 +1,27 @@ -/* This class specifies the basic operation on a stack as a linked list */ +/** + * @file stack.h + * @author danghai + * @brief This class specifies the basic operation on a stack as a linked list + **/ #ifndef DATA_STRUCTURES_STACK_H_ #define DATA_STRUCTURES_STACK_H_ #include #include -/* Definition of the node */ +/** Definition of the node as a linked-list + * \tparam Type type of data nodes of the linked list should contain + */ template struct node { - Type data; - node *next; + Type data; ///< data at current node + node *next; ///< pointer to the next ::node instance }; -/* Definition of the stack class */ +/** Definition of the stack class + * \tparam Type type of data nodes of the linked list in the stack should + * contain + */ template class stack { public: @@ -135,7 +144,7 @@ class stack { private: node *stackTop; /**< Pointer to the stack */ - int size; + int size; ///< size of stack }; #endif // DATA_STRUCTURES_STACK_H_ From 9b01676b338ee75d6a2eb06574ed660d0ac9c5ea Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Wed, 24 Jun 2020 10:48:18 -0400 Subject: [PATCH 36/92] fixed function argument --- data_structures/stack.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/stack.h b/data_structures/stack.h index 429e0265f..483648046 100644 --- a/data_structures/stack.h +++ b/data_structures/stack.h @@ -44,7 +44,7 @@ class stack { } /** Copy constructor*/ - explicit stack(const stack &other) { + explicit stack(const stack &otherStack) { node *newNode, *current, *last; /* If stack is no empty, make it empty */ From 5e3307620c8a092a982610fa8f7ced49c7ce06f5 Mon Sep 17 00:00:00 2001 From: Neeraj C Date: Wed, 24 Jun 2020 20:46:23 +0530 Subject: [PATCH 37/92] feat: create math/armstrong_number.cpp --- math/armstrong_number.cpp | 77 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 math/armstrong_number.cpp diff --git a/math/armstrong_number.cpp b/math/armstrong_number.cpp new file mode 100644 index 000000000..0b5f01cd1 --- /dev/null +++ b/math/armstrong_number.cpp @@ -0,0 +1,77 @@ +/** + * @file + * \brief A C++ program to check whether a number is armstrong number or not. + * + * \details + * Armstrong number or [Narcissistic number](https://en.wikipedia.org/wiki/Narcissistic_number) + * is a number that is the sum of its own digits raised to the power of the number of digits. + * @author iamnambiar +*/ +#include +#include +#include + +/** + * Function to calculate the total number of digits in the number. + * @param num Number + * @return Total number of digits. + */ +int number_of_digits(int num) { + int total_digits = 0; + while (num > 0) { + num = num / 10; + ++total_digits; + } + return total_digits; +} + +/** + * Function to check whether the number is armstrong number or not. + * @param num Number + * @return `true` if the number is armstrong. + * @return `false` if the number is not armstrong. + */ +bool is_armstrong(int number) { + // If the number is less than 0, then it is not a armstrong number. + if (number < 0) { + return false; + } + int sum = 0; + int temp = number; + // Finding the total number of digits in the number + int total_digits = number_of_digits(number); + while (temp > 0) { + int rem = temp % 10; + // Finding each digit raised to the power total digit and add it to the total sum + sum = sum + pow(rem, total_digits); + temp = temp / 10; + } + return number == sum; +} + +/** + * Function for testing the is_amicable() with + * all the test cases. + */ +void test() { + // is_armstrong(370) returns true. + assert(is_armstrong(370) == true); + // is_armstrong(225) returns false. + assert(is_armstrong(225) == false); + // is_armstrong(-23) returns false. + assert(is_armstrong(-23) == false); + // is_armstrong(153) returns true. + assert(is_armstrong(153) == true); + // is_armstrong(0) returns true. + assert(is_armstrong(0) == true); + // is_armstrong(12) returns false. + assert(is_armstrong(12) == false); +} + +/** + * Main Function +*/ +int main() { + test(); + return 0; +} From 5b3e30a937e488b3de38673134db136cb1e19759 Mon Sep 17 00:00:00 2001 From: Neeraj C <35414531+iamnambiar@users.noreply.github.com> Date: Wed, 24 Jun 2020 20:52:32 +0530 Subject: [PATCH 38/92] docs: typo fixed --- math/armstrong_number.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/math/armstrong_number.cpp b/math/armstrong_number.cpp index 0b5f01cd1..166c98c07 100644 --- a/math/armstrong_number.cpp +++ b/math/armstrong_number.cpp @@ -50,8 +50,8 @@ bool is_armstrong(int number) { } /** - * Function for testing the is_amicable() with - * all the test cases. + * Function for testing the is_armstrong() function + * with all the test cases. */ void test() { // is_armstrong(370) returns true. From c7ff9d66f1e7c18b43e51d183f1299b25293ac55 Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Wed, 24 Jun 2020 12:12:30 -0500 Subject: [PATCH 39/92] feat: Add exit option --- data_structures/stack_using_array.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/data_structures/stack_using_array.cpp b/data_structures/stack_using_array.cpp index 22b397ba8..0c0813d5e 100644 --- a/data_structures/stack_using_array.cpp +++ b/data_structures/stack_using_array.cpp @@ -32,6 +32,7 @@ int main() { stack = new int[stack_size]; int ch, x; do { + std::cout << "\n0. Exit"; std::cout << "\n1. Push"; std::cout << "\n2. Pop"; std::cout << "\n3. Print"; From 4c6b3b86c1f191339770039b8c7f377a5a18fc4e Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Wed, 24 Jun 2020 17:14:57 +0000 Subject: [PATCH 40/92] formatting source-code for c7ff9d66f1e7c18b43e51d183f1299b25293ac55 --- math/fibonacci_fast.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/math/fibonacci_fast.cpp b/math/fibonacci_fast.cpp index e7582df73..0948276a0 100644 --- a/math/fibonacci_fast.cpp +++ b/math/fibonacci_fast.cpp @@ -19,7 +19,7 @@ #include #include -/** +/** * maximum number that can be computed - The result after 93 cannot be stored * in a `uint64_t` data type. */ @@ -28,16 +28,19 @@ /** Algorithm */ uint64_t fib(uint64_t n) { - static uint64_t f1 = 1, f2 = 1; // using static keyword will retain the values of f1 and f2 for the next function call. - + static uint64_t f1 = 1, + f2 = 1; // using static keyword will retain the values of + // f1 and f2 for the next function call. + if (n <= 2) return f2; if (n >= 93) { - std::cerr << "Cannot compute for n>93 due to limit of 64-bit integers\n"; + std::cerr + << "Cannot compute for n>93 due to limit of 64-bit integers\n"; return 0; } - uint64_t temp = f2; // we do not need temp to be static + uint64_t temp = f2; // we do not need temp to be static f2 += f1; f1 = temp; From a190674131ea47919edb5987e3d713b2a9b0c0d1 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Wed, 24 Jun 2020 18:27:01 -0400 Subject: [PATCH 41/92] fix errors in matrix_exponentiation --- others/matrix_exponentiation.cpp | 55 +++++++++++++++----------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/others/matrix_exponentiation.cpp b/others/matrix_exponentiation.cpp index d44d22593..d646b3977 100644 --- a/others/matrix_exponentiation.cpp +++ b/others/matrix_exponentiation.cpp @@ -36,21 +36,18 @@ using std::vector; #define endl std::endl /*! shorthand definition for `int64_t` */ -#define pb push_back +#define pb push_back #define MOD 1000000007 -/** returns absolute value */ -inline ll ab(ll x) { return x > 0LL ? x : -x; } - -/** global variable k +/** global variable mat_size * @todo @stepfencurryxiao add documetnation */ -ll k; +ll mat_size; -/** global vector variables +/** global vector variables used in the ::ans function. * @todo @stepfencurryxiao add documetnation */ -vector a, b, c; +vector fib_b, fib_c; /** To multiply 2 matrices * \param [in] A matrix 1 of size (m\f$\times\f$n) @@ -59,10 +56,10 @@ vector a, b, c; */ vector> multiply(const vector> &A, const vector> &B) { - vector> C(k + 1, vector(k + 1)); - for (ll i = 1; i <= k; i++) { - for (ll j = 1; j <= k; j++) { - for (ll z = 1; z <= k; z++) { + vector> C(mat_size + 1, vector(mat_size + 1)); + for (ll i = 1; i <= mat_size; i++) { + for (ll j = 1; j <= mat_size; j++) { + for (ll z = 1; z <= mat_size; z++) { C[i][j] = (C[i][j] + (A[i][z] * B[z][j]) % MOD) % MOD; } } @@ -94,24 +91,24 @@ vector> power(const vector> &A, ll p) { ll ans(ll n) { if (n == 0) return 0; - if (n <= k) - return b[n - 1]; + if (n <= mat_size) + return fib_b[n - 1]; // F1 - vector F1(k + 1); - for (ll i = 1; i <= k; i++) F1[i] = b[i - 1]; + vector F1(mat_size + 1); + for (ll i = 1; i <= mat_size; i++) F1[i] = fib_b[i - 1]; // Transpose matrix - vector> T(k + 1, vector(k + 1)); - for (ll i = 1; i <= k; i++) { - for (ll j = 1; j <= k; j++) { - if (i < k) { + vector> T(mat_size + 1, vector(mat_size + 1)); + for (ll i = 1; i <= mat_size; i++) { + for (ll j = 1; j <= mat_size; j++) { + if (i < mat_size) { if (j == i + 1) T[i][j] = 1; else T[i][j] = 0; continue; } - T[i][j] = c[k - j]; + T[i][j] = fib_c[mat_size - j]; } } // T^n-1 @@ -119,7 +116,7 @@ ll ans(ll n) { // T*F1 ll res = 0; - for (ll i = 1; i <= k; i++) { + for (ll i = 1; i <= mat_size; i++) { res = (res + (T[1][i] * F1[i]) % MOD) % MOD; } return res; @@ -133,19 +130,19 @@ int main() { cin >> t; ll i, j, x; while (t--) { - cin >> k; - for (i = 0; i < k; i++) { + cin >> mat_size; + for (i = 0; i < mat_size; i++) { cin >> x; - b.pb(x); + fib_b.pb(x); } - for (i = 0; i < k; i++) { + for (i = 0; i < mat_size; i++) { cin >> x; - c.pb(x); + fib_c.pb(x); } cin >> x; cout << ans(x) << endl; - b.clear(); - c.clear(); + fib_b.clear(); + fib_c.clear(); } return 0; } From ef5f33083405e4d7f54650173f8aa9fcf9ff9fe7 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Wed, 24 Jun 2020 22:28:10 +0000 Subject: [PATCH 42/92] formatting source-code for a190674131ea47919edb5987e3d713b2a9b0c0d1 --- others/matrix_exponentiation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/others/matrix_exponentiation.cpp b/others/matrix_exponentiation.cpp index d646b3977..bde7f521b 100644 --- a/others/matrix_exponentiation.cpp +++ b/others/matrix_exponentiation.cpp @@ -36,7 +36,7 @@ using std::vector; #define endl std::endl /*! shorthand definition for `int64_t` */ -#define pb push_back +#define pb push_back #define MOD 1000000007 /** global variable mat_size From 9c75856235a9cae35ae9833633ef37d65714bdef Mon Sep 17 00:00:00 2001 From: Neeraj C <35414531+iamnambiar@users.noreply.github.com> Date: Thu, 25 Jun 2020 07:59:39 +0530 Subject: [PATCH 43/92] docs: clean the comment Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> --- math/armstrong_number.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/armstrong_number.cpp b/math/armstrong_number.cpp index 166c98c07..3b7e67cc5 100644 --- a/math/armstrong_number.cpp +++ b/math/armstrong_number.cpp @@ -1,6 +1,6 @@ /** * @file - * \brief A C++ program to check whether a number is armstrong number or not. + * \brief Program to check if a number is an [Armstrong/Narcissistic number](https://en.wikipedia.org/wiki/Narcissistic_number) in decimal system. * * \details * Armstrong number or [Narcissistic number](https://en.wikipedia.org/wiki/Narcissistic_number) From 06ca2a69532bb1bc17173d14804a2329450fe2e8 Mon Sep 17 00:00:00 2001 From: Neeraj C <35414531+iamnambiar@users.noreply.github.com> Date: Thu, 25 Jun 2020 08:00:37 +0530 Subject: [PATCH 44/92] fix: spaces between include and header file Co-authored-by: David Leal --- math/armstrong_number.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/math/armstrong_number.cpp b/math/armstrong_number.cpp index 3b7e67cc5..f8c7510e8 100644 --- a/math/armstrong_number.cpp +++ b/math/armstrong_number.cpp @@ -7,9 +7,9 @@ * is a number that is the sum of its own digits raised to the power of the number of digits. * @author iamnambiar */ -#include -#include -#include +#include +#include +#include /** * Function to calculate the total number of digits in the number. From 06f425493b1567a7394d533dda525b4d64583be9 Mon Sep 17 00:00:00 2001 From: Neeraj C <35414531+iamnambiar@users.noreply.github.com> Date: Thu, 25 Jun 2020 10:59:44 +0530 Subject: [PATCH 45/92] fix: changed to std::pow Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> --- math/armstrong_number.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/armstrong_number.cpp b/math/armstrong_number.cpp index f8c7510e8..db8eb0fb7 100644 --- a/math/armstrong_number.cpp +++ b/math/armstrong_number.cpp @@ -43,7 +43,7 @@ bool is_armstrong(int number) { while (temp > 0) { int rem = temp % 10; // Finding each digit raised to the power total digit and add it to the total sum - sum = sum + pow(rem, total_digits); + sum = sum + std::pow(rem, total_digits); temp = temp / 10; } return number == sum; From 351a1b712a982f72396559be40e7dd37d9b6db2c Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 25 Jun 2020 09:51:24 +0000 Subject: [PATCH 46/92] formatting source-code for ca70c3097e51f7a3845cabf3a140d3a1fb2f3cb3 --- math/armstrong_number.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/math/armstrong_number.cpp b/math/armstrong_number.cpp index db8eb0fb7..426de327b 100644 --- a/math/armstrong_number.cpp +++ b/math/armstrong_number.cpp @@ -1,15 +1,17 @@ /** * @file - * \brief Program to check if a number is an [Armstrong/Narcissistic number](https://en.wikipedia.org/wiki/Narcissistic_number) in decimal system. - * + * \brief Program to check if a number is an [Armstrong/Narcissistic + * number](https://en.wikipedia.org/wiki/Narcissistic_number) in decimal system. + * * \details - * Armstrong number or [Narcissistic number](https://en.wikipedia.org/wiki/Narcissistic_number) - * is a number that is the sum of its own digits raised to the power of the number of digits. + * Armstrong number or [Narcissistic + * number](https://en.wikipedia.org/wiki/Narcissistic_number) is a number that + * is the sum of its own digits raised to the power of the number of digits. * @author iamnambiar -*/ + */ #include -#include #include +#include /** * Function to calculate the total number of digits in the number. @@ -42,7 +44,8 @@ bool is_armstrong(int number) { int total_digits = number_of_digits(number); while (temp > 0) { int rem = temp % 10; - // Finding each digit raised to the power total digit and add it to the total sum + // Finding each digit raised to the power total digit and add it to the + // total sum sum = sum + std::pow(rem, total_digits); temp = temp / 10; } @@ -50,7 +53,7 @@ bool is_armstrong(int number) { } /** - * Function for testing the is_armstrong() function + * Function for testing the is_armstrong() function * with all the test cases. */ void test() { @@ -70,7 +73,7 @@ void test() { /** * Main Function -*/ + */ int main() { test(); return 0; From 21093365cd2b3ac8ba4e081329a4eb24827e42d0 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 25 Jun 2020 09:51:24 +0000 Subject: [PATCH 47/92] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 6e43ba3f2..257b4160d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -100,6 +100,7 @@ * [Kohonen Som Trace](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/kohonen_som_trace.cpp) ## Math + * [Armstrong Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/armstrong_number.cpp) * [Binary Exponent](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/binary_exponent.cpp) * [Check Amicable Pair](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/check_amicable_pair.cpp) * [Check Prime](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/check_prime.cpp) From 5939792a9dbef599055b3cc88e9835e6065ce2f2 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 09:14:21 -0400 Subject: [PATCH 48/92] fix self-tests and unsigned comparision to zero refer #897 and https://lgtm.com/projects/g/TheAlgorithms/C-Plus-Plus/rev/pr-f6e7cda8faf908e87511f30e782190233bdee68c --- math/double_factorial.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/math/double_factorial.cpp b/math/double_factorial.cpp index 8e5ffcefa..1d1f7dae4 100644 --- a/math/double_factorial.cpp +++ b/math/double_factorial.cpp @@ -32,10 +32,33 @@ uint64_t double_factorial_recursive(uint64_t n) { return n * double_factorial_recursive(n - 2); } -/// main function -int main() { - uint64_t n; - std::cin >> n; - assert(n >= 0); - std::cout << double_factorial_iterative(n); +/** Wrapper to run tests using both recursive and iterative implementations. + * The checks are only valid in debug builds due to the use of `assert()` + * statements. + * \param [in] n number to check double factorial for + * \param [in] expected expected result + */ +void test(uint64_t n, uint64_t expected) { + assert(double_factorial_iterative(n) == expected); + assert(double_factorial_recursive(n) == expected); } + +/** + * Test implementations + */ +void tests() { + std::cout << "Test 1:\t n=5\t..."; + test(5, 15); + std::cout << "passed\n"; + + std::cout << "Test 2:\t n=15\t..."; + test(15, 2027025); + std::cout << "passed\n"; + + std::cout << "Test 3:\t n=0\t..."; + test(0, 1); + std::cout << "passed\n"; +} + +/// main function +int main() { tests(); } From d8b121b1191fed37442a52873692af36091f3c16 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 09:26:20 -0400 Subject: [PATCH 49/92] disable timestamps in footer of html docs --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 957be35f5..adb1c740a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ if(DOXYGEN_FOUND) set(DOXYGEN_GENERATE_MAN NO) set(DOXYGEN_USE_MATHJAX YES) set(DOXYGEN_GENERATE_HTML YES) - set(DOXYGEN_HTML_TIMESTAMP YES) + # set(DOXYGEN_HTML_TIMESTAMP YES) set(DOXYGEN_EXTRACT_STATIC YES) set(DOXYGEN_INLINE_SOURCES YES) set(DOXYGEN_CREATE_SUBDIRS YES) From 66eb05e0daf68fdc43e0da3bf4a7b56038191b45 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 09:59:36 -0400 Subject: [PATCH 50/92] added wiki link in file brieff --- math/double_factorial.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/math/double_factorial.cpp b/math/double_factorial.cpp index 1d1f7dae4..a400ae147 100644 --- a/math/double_factorial.cpp +++ b/math/double_factorial.cpp @@ -1,8 +1,9 @@ /** * @file - * @brief Compute double factorial: \f$n!!\f$ + * @brief Compute [double + * factorial](https://en.wikipedia.org/wiki/Double_factorial): \f$n!!\f$ * - * Double factorial of a non-negative integer n, is defined as the product of + * Double factorial of a non-negative integer `n`, is defined as the product of * all the integers from 1 to n that have the same parity (odd or even) as n. *
It is also called as semifactorial of a number and is denoted by * \f$n!!\f$ From 2c61414a838611dc19ce6296164133d642b185fa Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 13:38:11 -0400 Subject: [PATCH 51/92] split lu_decomposition to a header file and templated the function --- numerical_methods/lu_decompose.cpp | 74 +++------------------------- numerical_methods/lu_decomposition.h | 65 ++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 66 deletions(-) create mode 100644 numerical_methods/lu_decomposition.h diff --git a/numerical_methods/lu_decompose.cpp b/numerical_methods/lu_decompose.cpp index a0a2d00ab..2ce5fb653 100644 --- a/numerical_methods/lu_decompose.cpp +++ b/numerical_methods/lu_decompose.cpp @@ -7,73 +7,15 @@ #include #include #include -#include -#ifdef _OPENMP -#include -#endif -/** Perform LU decomposition on matrix - * \param[in] A matrix to decompose - * \param[out] L output L matrix - * \param[out] U output U matrix - * \returns 0 if no errors - * \returns negative if error occurred - */ -int lu_decomposition(const std::vector> &A, - std::vector> *L, - std::vector> *U) { - int row, col, j; - int mat_size = A.size(); - - if (mat_size != A[0].size()) { - // check matrix is a square matrix - std::cerr << "Not a square matrix!\n"; - return -1; - } - - // regularize each row - for (row = 0; row < mat_size; row++) { - // Upper triangular matrix -#ifdef _OPENMP -#pragma omp for -#endif - for (col = row; col < mat_size; col++) { - // Summation of L[i,j] * U[j,k] - double lu_sum = 0.; - for (j = 0; j < row; j++) lu_sum += L[0][row][j] * U[0][j][col]; - - // Evaluate U[i,k] - U[0][row][col] = A[row][col] - lu_sum; - } - - // Lower triangular matrix -#ifdef _OPENMP -#pragma omp for -#endif - for (col = row; col < mat_size; col++) { - if (row == col) { - L[0][row][col] = 1.; - continue; - } - - // Summation of L[i,j] * U[j,k] - double lu_sum = 0.; - for (j = 0; j < row; j++) lu_sum += L[0][col][j] * U[0][j][row]; - - // Evaluate U[i,k] - L[0][col][row] = (A[col][row] - lu_sum) / U[0][row][row]; - } - } - - return 0; -} +#include "./lu_decomposition.h" /** * operator to print a matrix */ template std::ostream &operator<<(std::ostream &out, - std::vector> const &v) { + std::vector> const &v) { const int width = 10; const char separator = ' '; @@ -99,14 +41,14 @@ int main(int argc, char **argv) { std::srand(std::time(NULL)); // random number initializer /* Create a square matrix with random values */ - std::vector> A(mat_size); - std::vector> L(mat_size); // output - std::vector> U(mat_size); // output + std::vector> A(mat_size, + std::valarray(mat_size)); + std::vector> L( + mat_size, std::valarray(mat_size)); // output + std::vector> U( + mat_size, std::valarray(mat_size)); // output for (int i = 0; i < mat_size; i++) { // calloc so that all valeus are '0' by default - A[i] = std::vector(mat_size); - L[i] = std::vector(mat_size); - U[i] = std::vector(mat_size); for (int j = 0; j < mat_size; j++) /* create random values in the limits [-range2, range-1] */ A[i][j] = static_cast(std::rand() % range - range2); diff --git a/numerical_methods/lu_decomposition.h b/numerical_methods/lu_decomposition.h new file mode 100644 index 000000000..9cb881ba9 --- /dev/null +++ b/numerical_methods/lu_decomposition.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +/** Perform LU decomposition on matrix + * \param[in] A matrix to decompose + * \param[out] L output L matrix + * \param[out] U output U matrix + * \returns 0 if no errors + * \returns negative if error occurred + */ +template +int lu_decomposition(const std::vector> &A, + std::vector> *L, + std::vector> *U) { + int row, col, j; + int mat_size = A.size(); + + if (mat_size != A[0].size()) { + // check matrix is a square matrix + std::cerr << "Not a square matrix!\n"; + return -1; + } + + // regularize each row + for (row = 0; row < mat_size; row++) { + // Upper triangular matrix +#ifdef _OPENMP +#pragma omp for +#endif + for (col = row; col < mat_size; col++) { + // Summation of L[i,j] * U[j,k] + double lu_sum = 0.; + for (j = 0; j < row; j++) lu_sum += L[0][row][j] * U[0][j][col]; + + // Evaluate U[i,k] + U[0][row][col] = A[row][col] - lu_sum; + } + + // Lower triangular matrix +#ifdef _OPENMP +#pragma omp for +#endif + for (col = row; col < mat_size; col++) { + if (row == col) { + L[0][row][col] = 1.; + continue; + } + + // Summation of L[i,j] * U[j,k] + double lu_sum = 0.; + for (j = 0; j < row; j++) lu_sum += L[0][col][j] * U[0][j][row]; + + // Evaluate U[i,k] + L[0][col][row] = (A[col][row] - lu_sum) / U[0][row][row]; + } + } + + return 0; +} From e1b1c71e7cca268c9fbad41d2d6b315ff63b9756 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 14:40:47 -0400 Subject: [PATCH 52/92] Apply suggestions from code review Co-authored-by: David Leal --- math/double_factorial.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/math/double_factorial.cpp b/math/double_factorial.cpp index a400ae147..db22cc672 100644 --- a/math/double_factorial.cpp +++ b/math/double_factorial.cpp @@ -61,5 +61,10 @@ void tests() { std::cout << "passed\n"; } -/// main function -int main() { tests(); } +/** + * Main function + */ +int main() { + tests(); + return 0; +} From b1620ff2f57036bbd81faf57d09268d7b368c1a3 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 25 Jun 2020 18:41:27 +0000 Subject: [PATCH 53/92] formatting source-code for e1b1c71e7cca268c9fbad41d2d6b315ff63b9756 --- math/double_factorial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/double_factorial.cpp b/math/double_factorial.cpp index db22cc672..72feda60c 100644 --- a/math/double_factorial.cpp +++ b/math/double_factorial.cpp @@ -61,7 +61,7 @@ void tests() { std::cout << "passed\n"; } -/** +/** * Main function */ int main() { From e22f56c90628fa02017a43f581384a0c06551821 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 25 Jun 2020 18:43:00 +0000 Subject: [PATCH 54/92] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 257b4160d..679e6f7d8 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -140,6 +140,7 @@ * [Gaussian Elimination](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/gaussian_elimination.cpp) * [Golden Search Extrema](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/golden_search_extrema.cpp) * [Lu Decompose](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/lu_decompose.cpp) + * [Lu Decomposition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/lu_decomposition.h) * [Newton Raphson Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/newton_raphson_method.cpp) * [Ode Forward Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ode_forward_euler.cpp) * [Ode Midpoint Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ode_midpoint_euler.cpp) From f29c14032a73160444f5be4df03a2c03ca4acbb5 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 14:51:54 -0400 Subject: [PATCH 55/92] added determinant computation using LU decomposition --- numerical_methods/lu_decomposition.h | 34 ++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/numerical_methods/lu_decomposition.h b/numerical_methods/lu_decomposition.h index 9cb881ba9..42c29e4f2 100644 --- a/numerical_methods/lu_decomposition.h +++ b/numerical_methods/lu_decomposition.h @@ -36,7 +36,9 @@ int lu_decomposition(const std::vector> &A, for (col = row; col < mat_size; col++) { // Summation of L[i,j] * U[j,k] double lu_sum = 0.; - for (j = 0; j < row; j++) lu_sum += L[0][row][j] * U[0][j][col]; + for (j = 0; j < row; j++) { + lu_sum += L[0][row][j] * U[0][j][col]; + } // Evaluate U[i,k] U[0][row][col] = A[row][col] - lu_sum; @@ -54,7 +56,9 @@ int lu_decomposition(const std::vector> &A, // Summation of L[i,j] * U[j,k] double lu_sum = 0.; - for (j = 0; j < row; j++) lu_sum += L[0][col][j] * U[0][j][row]; + for (j = 0; j < row; j++) { + lu_sum += L[0][col][j] * U[0][j][row]; + } // Evaluate U[i,k] L[0][col][row] = (A[col][row] - lu_sum) / U[0][row][row]; @@ -63,3 +67,29 @@ int lu_decomposition(const std::vector> &A, return 0; } + +/** + * @brief Compute determinant of an NxN square matrix using LU decomposition. + * Using LU decomposition, the determinant is given by the product of diagonal + * elements of matrices L and U. + * + * @tparam T datatype of input matrix - int, unsigned int, double, etc + * @param A input square matrix + * @return determinant of matrix A + */ +template +double determinant_lu(const std::vector> &A) { + std::vector> L(A.size(), + std::valarray(A.size())); + std::vector> U(A.size(), + std::valarray(A.size())); + + if (lu_decomposition(A, &L, &U) < 0) + return 0; + + double result = 1.f; + for (size_t i = 0; i < A.size(); i++) { + result *= L[i][i] * U[i][i]; + } + return result; +} From c1b0635f993c72fa32de11bc4df73b7dc77509b8 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 15:03:12 -0400 Subject: [PATCH 56/92] create and added matrix type --- numerical_methods/lu_decomposition.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/numerical_methods/lu_decomposition.h b/numerical_methods/lu_decomposition.h index 42c29e4f2..22af249a5 100644 --- a/numerical_methods/lu_decomposition.h +++ b/numerical_methods/lu_decomposition.h @@ -7,6 +7,10 @@ #include #endif +/** Define matrix type as a `std::vector` of `std::valarray` */ +template +using matrix = std::vector>; + /** Perform LU decomposition on matrix * \param[in] A matrix to decompose * \param[out] L output L matrix @@ -15,9 +19,7 @@ * \returns negative if error occurred */ template -int lu_decomposition(const std::vector> &A, - std::vector> *L, - std::vector> *U) { +int lu_decomposition(const matrix &A, matrix *L, matrix *U) { int row, col, j; int mat_size = A.size(); @@ -78,11 +80,9 @@ int lu_decomposition(const std::vector> &A, * @return determinant of matrix A */ template -double determinant_lu(const std::vector> &A) { - std::vector> L(A.size(), - std::valarray(A.size())); - std::vector> U(A.size(), - std::valarray(A.size())); +double determinant_lu(const matrix &A) { + matrix L(A.size(), std::valarray(A.size())); + matrix U(A.size(), std::valarray(A.size())); if (lu_decomposition(A, &L, &U) < 0) return 0; From 84cf0da2bbf3dc7c1dd0dd8ff916317208068cef Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 15:03:57 -0400 Subject: [PATCH 57/92] automated self-test of LU decomposition using sample case and determinant checks --- numerical_methods/lu_decompose.cpp | 52 +++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/numerical_methods/lu_decompose.cpp b/numerical_methods/lu_decompose.cpp index 2ce5fb653..b27fed2ee 100644 --- a/numerical_methods/lu_decompose.cpp +++ b/numerical_methods/lu_decompose.cpp @@ -4,6 +4,7 @@ * square matrix * \author [Krishna Vedala](https://github.com/kvedala) */ +#include #include #include #include @@ -14,8 +15,7 @@ * operator to print a matrix */ template -std::ostream &operator<<(std::ostream &out, - std::vector> const &v) { +std::ostream &operator<<(std::ostream &out, matrix const &v) { const int width = 10; const char separator = ' '; @@ -29,24 +29,19 @@ std::ostream &operator<<(std::ostream &out, return out; } -/** Main function */ -int main(int argc, char **argv) { +/** + * Test LU decomposition + * \todo better ways to self-check a matrix output? + */ +void test1() { int mat_size = 3; // default matrix size const int range = 50; const int range2 = range >> 1; - if (argc == 2) - mat_size = atoi(argv[1]); - - std::srand(std::time(NULL)); // random number initializer - /* Create a square matrix with random values */ - std::vector> A(mat_size, - std::valarray(mat_size)); - std::vector> L( - mat_size, std::valarray(mat_size)); // output - std::vector> U( - mat_size, std::valarray(mat_size)); // output + matrix A(mat_size, std::valarray(mat_size)); + matrix L(mat_size, std::valarray(mat_size)); // output + matrix U(mat_size, std::valarray(mat_size)); // output for (int i = 0; i < mat_size; i++) { // calloc so that all valeus are '0' by default for (int j = 0; j < mat_size; j++) @@ -63,6 +58,33 @@ int main(int argc, char **argv) { std::cout << "A = \n" << A << "\n"; std::cout << "L = \n" << L << "\n"; std::cout << "U = \n" << U << "\n"; +} +/** + * @brief Test determinant computation using LU decomposition + */ +void test2() { + std::cout << "Determinant test 1..."; + matrix A1({{1, 2, 3}, {4, 9, 6}, {7, 8, 9}}); + assert(determinant_lu(A1) == -48); + std::cout << "passed\n"; + + std::cout << "Determinant test 2..."; + matrix A2({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); + assert(determinant_lu(A2) == 0); + std::cout << "passed\n"; + + std::cout << "Determinant test 3..."; + matrix A3({{1.2, 2.3, 3.4}, {4.5, 5.6, 6.7}, {7.8, 8.9, 9.0}}); + assert(determinant_lu(A3) == 3.63); + std::cout << "passed\n"; +} + +/** Main function */ +int main(int argc, char **argv) { + std::srand(std::time(NULL)); // random number initializer + + test1(); + test2(); return 0; } From 68dd9b1235f1d2a33d0a873a33ff55846bc8a4f6 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 15:22:02 -0400 Subject: [PATCH 58/92] added file documentation --- numerical_methods/lu_decomposition.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/numerical_methods/lu_decomposition.h b/numerical_methods/lu_decomposition.h index 22af249a5..4999fc40f 100644 --- a/numerical_methods/lu_decomposition.h +++ b/numerical_methods/lu_decomposition.h @@ -1,3 +1,10 @@ +/** + * @file lu_decomposition.h + * @author [Krishna Vedala](https://github.com/kvedala) + * @brief Functions associated with [LU + * Decomposition](https://en.wikipedia.org/wiki/LU_decomposition) + * of a square matrix. + */ #pragma once #include From 0429b5dd888030ce9b0c069875491aac1261660e Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 25 Jun 2020 18:01:41 -0400 Subject: [PATCH 59/92] fix documentation --- numerical_methods/lu_decompose.cpp | 2 +- numerical_methods/lu_decomposition.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/numerical_methods/lu_decompose.cpp b/numerical_methods/lu_decompose.cpp index b27fed2ee..66f1a8551 100644 --- a/numerical_methods/lu_decompose.cpp +++ b/numerical_methods/lu_decompose.cpp @@ -61,7 +61,7 @@ void test1() { } /** - * @brief Test determinant computation using LU decomposition + * Test determinant computation using LU decomposition */ void test2() { std::cout << "Determinant test 1..."; diff --git a/numerical_methods/lu_decomposition.h b/numerical_methods/lu_decomposition.h index 4999fc40f..402fe6e3b 100644 --- a/numerical_methods/lu_decomposition.h +++ b/numerical_methods/lu_decomposition.h @@ -78,7 +78,7 @@ int lu_decomposition(const matrix &A, matrix *L, matrix *U) { } /** - * @brief Compute determinant of an NxN square matrix using LU decomposition. + * Compute determinant of an NxN square matrix using LU decomposition. * Using LU decomposition, the determinant is given by the product of diagonal * elements of matrices L and U. * From 11a6542bf2704de3cbba22843fa8322e87569cc0 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 08:04:01 -0400 Subject: [PATCH 60/92] added test cases --- .../ordinary_least_squares_regressor.cpp | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/numerical_methods/ordinary_least_squares_regressor.cpp b/numerical_methods/ordinary_least_squares_regressor.cpp index bbd75a742..d36a84042 100644 --- a/numerical_methods/ordinary_least_squares_regressor.cpp +++ b/numerical_methods/ordinary_least_squares_regressor.cpp @@ -9,6 +9,7 @@ * * \author [Krishna Vedala](https://github.com/kvedala) */ +#include #include // for print formatting #include #include @@ -352,10 +353,48 @@ std::vector predict_OLS_regressor(std::vector> const &X, return result; } +/** Self test checks */ +void test() { + int F = 3, N = 5; + + // test function = x^2 -5 + std::cout << "Test 1 (quadratic function)...."; + std::vector> data1( + {{-5, 25, -125}, {-1, 1, -1}, {0, 0, 0}, {1, 1, 1}, {6, 36, 216}}); + std::vector Y1({20, -4, -5, -4, 31}); + std::vector beta1 = fit_OLS_regressor(data1, Y1); + std::vector> test1( + {{-2, 4, -8}, {2, 4, 8}, {-10, 100, -1000}, {10, 100, 1000}}); + std::vector expected1({-1, -1, 95, 95}); + std::vector out1 = predict_OLS_regressor(test1, beta1); + for (size_t rows = 0; rows < out1.size(); rows++) + assert(std::abs(out1[rows] - expected1[rows]) < 0.01); // accuracy + std::cout << "passed\n"; + + // test function = x^3 + x^2 - 100 + std::cout << "Test 2 (cubic function)...."; + std::vector> data2( + {{-5, 25, -125}, {-1, 1, -1}, {0, 0, 0}, {1, 1, 1}, {6, 36, 216}}); + std::vector Y2({-200, -100, -100, 98, 152}); + std::vector beta2 = fit_OLS_regressor(data2, Y2); + std::vector> test2( + {{-2, 4, -8}, {2, 4, 8}, {-10, 100, -1000}, {10, 100, 1000}}); + std::vector expected2({-104, -88, -1000, 1000}); + std::vector out2 = predict_OLS_regressor(test2, beta2); + for (size_t rows = 0; rows < out2.size(); rows++) + assert(std::abs(out2[rows] - expected2[rows]) < 0.01); // accuracy + std::cout << "passed\n"; + + std::cout << std::endl; // ensure test results are displayed on screen + // (flush stdout) +} + /** * main function */ int main() { + test(); + size_t N, F; std::cout << "Enter number of features: "; From 6d127e3adfbbb0f64abb94d1800fa5f5c66ec3cc Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 08:09:34 -0400 Subject: [PATCH 61/92] added inline documentation --- .../ordinary_least_squares_regressor.cpp | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/numerical_methods/ordinary_least_squares_regressor.cpp b/numerical_methods/ordinary_least_squares_regressor.cpp index d36a84042..614fdab9a 100644 --- a/numerical_methods/ordinary_least_squares_regressor.cpp +++ b/numerical_methods/ordinary_least_squares_regressor.cpp @@ -357,32 +357,46 @@ std::vector predict_OLS_regressor(std::vector> const &X, void test() { int F = 3, N = 5; - // test function = x^2 -5 + /* test function = x^2 -5 */ std::cout << "Test 1 (quadratic function)...."; + // create training data set with features = x, x^2, x^3 std::vector> data1( {{-5, 25, -125}, {-1, 1, -1}, {0, 0, 0}, {1, 1, 1}, {6, 36, 216}}); + // create corresponding outputs std::vector Y1({20, -4, -5, -4, 31}); + // perform regression modelling std::vector beta1 = fit_OLS_regressor(data1, Y1); + // create test data set with same features = x, x^2, x^3 std::vector> test1( {{-2, 4, -8}, {2, 4, 8}, {-10, 100, -1000}, {10, 100, 1000}}); + // expected regression outputs std::vector expected1({-1, -1, 95, 95}); + // predicted regression outputs std::vector out1 = predict_OLS_regressor(test1, beta1); + // compare predicted results are within +-0.01 limit of expected for (size_t rows = 0; rows < out1.size(); rows++) - assert(std::abs(out1[rows] - expected1[rows]) < 0.01); // accuracy + assert(std::abs(out1[rows] - expected1[rows]) < 0.01); std::cout << "passed\n"; - // test function = x^3 + x^2 - 100 + /* test function = x^3 + x^2 - 100 */ std::cout << "Test 2 (cubic function)...."; + // create training data set with features = x, x^2, x^3 std::vector> data2( {{-5, 25, -125}, {-1, 1, -1}, {0, 0, 0}, {1, 1, 1}, {6, 36, 216}}); + // create corresponding outputs std::vector Y2({-200, -100, -100, 98, 152}); + // perform regression modelling std::vector beta2 = fit_OLS_regressor(data2, Y2); + // create test data set with same features = x, x^2, x^3 std::vector> test2( {{-2, 4, -8}, {2, 4, 8}, {-10, 100, -1000}, {10, 100, 1000}}); + // expected regression outputs std::vector expected2({-104, -88, -1000, 1000}); + // predicted regression outputs std::vector out2 = predict_OLS_regressor(test2, beta2); + // compare predicted results are within +-0.01 limit of expected for (size_t rows = 0; rows < out2.size(); rows++) - assert(std::abs(out2[rows] - expected2[rows]) < 0.01); // accuracy + assert(std::abs(out2[rows] - expected2[rows]) < 0.01); std::cout << "passed\n"; std::cout << std::endl; // ensure test results are displayed on screen From 0d2a58409e3c9c4a1c77878555b93c8de36c1a01 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 08:14:50 -0400 Subject: [PATCH 62/92] include cstdlib for std::abs() --- numerical_methods/ordinary_least_squares_regressor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/numerical_methods/ordinary_least_squares_regressor.cpp b/numerical_methods/ordinary_least_squares_regressor.cpp index 614fdab9a..4761a6d96 100644 --- a/numerical_methods/ordinary_least_squares_regressor.cpp +++ b/numerical_methods/ordinary_least_squares_regressor.cpp @@ -10,6 +10,7 @@ * \author [Krishna Vedala](https://github.com/kvedala) */ #include +#include // for std::abs #include // for print formatting #include #include From 7ff384e59b5741b2b1d0ff981efa10ed891b5350 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 08:20:53 -0400 Subject: [PATCH 63/92] replace cstdlib with cmath for float overload of std::abs() --- numerical_methods/ordinary_least_squares_regressor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numerical_methods/ordinary_least_squares_regressor.cpp b/numerical_methods/ordinary_least_squares_regressor.cpp index 4761a6d96..7482d84da 100644 --- a/numerical_methods/ordinary_least_squares_regressor.cpp +++ b/numerical_methods/ordinary_least_squares_regressor.cpp @@ -10,7 +10,7 @@ * \author [Krishna Vedala](https://github.com/kvedala) */ #include -#include // for std::abs +#include // for std::abs #include // for print formatting #include #include From 9a8b6ddd2ee2854032245a348298a33fdaf8202d Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 08:22:12 -0400 Subject: [PATCH 64/92] typo correction from #910 --- numerical_methods/ordinary_least_squares_regressor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numerical_methods/ordinary_least_squares_regressor.cpp b/numerical_methods/ordinary_least_squares_regressor.cpp index 7482d84da..dcbbcf8c7 100644 --- a/numerical_methods/ordinary_least_squares_regressor.cpp +++ b/numerical_methods/ordinary_least_squares_regressor.cpp @@ -423,7 +423,7 @@ int main() { std::vector Y(N); std::cout - << "Enter training data. Per sample, provide features ad one output." + << "Enter training data. Per sample, provide features and one output." << std::endl; for (size_t rows = 0; rows < N; rows++) { From 0690a140ecfbe55583186169577aab3b2cd16103 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 09:03:20 -0400 Subject: [PATCH 65/92] move OLS regressor to machine learning folder --- .../ordinary_least_squares_regressor.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {numerical_methods => machine_learning}/ordinary_least_squares_regressor.cpp (100%) diff --git a/numerical_methods/ordinary_least_squares_regressor.cpp b/machine_learning/ordinary_least_squares_regressor.cpp similarity index 100% rename from numerical_methods/ordinary_least_squares_regressor.cpp rename to machine_learning/ordinary_least_squares_regressor.cpp From dcd0d6b47864468cd9645e22e206e5b59bea4c6f Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Fri, 26 Jun 2020 13:04:18 +0000 Subject: [PATCH 66/92] updating DIRECTORY.md --- DIRECTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 679e6f7d8..d678276bc 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -98,6 +98,7 @@ * [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) * [Kohonen Som Trace](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/kohonen_som_trace.cpp) + * [Ordinary Least Squares Regressor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/ordinary_least_squares_regressor.cpp) ## Math * [Armstrong Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/armstrong_number.cpp) @@ -145,7 +146,6 @@ * [Ode Forward Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ode_forward_euler.cpp) * [Ode Midpoint Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ode_midpoint_euler.cpp) * [Ode Semi Implicit Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ode_semi_implicit_euler.cpp) - * [Ordinary Least Squares Regressor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ordinary_least_squares_regressor.cpp) * [Qr Decompose](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/qr_decompose.h) * [Qr Decomposition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/qr_decomposition.cpp) * [Qr Eigen Values](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/qr_eigen_values.cpp) From 052c3fbca87802cc8ab95f5deb08bd94badab4fa Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 10:37:56 -0400 Subject: [PATCH 67/92] use better test function names to avoid conflict --- machine_learning/ordinary_least_squares_regressor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machine_learning/ordinary_least_squares_regressor.cpp b/machine_learning/ordinary_least_squares_regressor.cpp index dcbbcf8c7..54d100300 100644 --- a/machine_learning/ordinary_least_squares_regressor.cpp +++ b/machine_learning/ordinary_least_squares_regressor.cpp @@ -355,7 +355,7 @@ std::vector predict_OLS_regressor(std::vector> const &X, } /** Self test checks */ -void test() { +void ols_test() { int F = 3, N = 5; /* test function = x^2 -5 */ @@ -408,7 +408,7 @@ void test() { * main function */ int main() { - test(); + ols_test(); size_t N, F; From b9c1f6bf363aa6e34fcaa664adafef3158ce7841 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 10:53:42 -0400 Subject: [PATCH 68/92] use better test data variable names to avoid conflict --- machine_learning/ordinary_least_squares_regressor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/machine_learning/ordinary_least_squares_regressor.cpp b/machine_learning/ordinary_least_squares_regressor.cpp index 54d100300..896504e20 100644 --- a/machine_learning/ordinary_least_squares_regressor.cpp +++ b/machine_learning/ordinary_least_squares_regressor.cpp @@ -368,12 +368,12 @@ void ols_test() { // perform regression modelling std::vector beta1 = fit_OLS_regressor(data1, Y1); // create test data set with same features = x, x^2, x^3 - std::vector> test1( + std::vector> test_data1( {{-2, 4, -8}, {2, 4, 8}, {-10, 100, -1000}, {10, 100, 1000}}); // expected regression outputs std::vector expected1({-1, -1, 95, 95}); // predicted regression outputs - std::vector out1 = predict_OLS_regressor(test1, beta1); + std::vector out1 = predict_OLS_regressor(test_data1, beta1); // compare predicted results are within +-0.01 limit of expected for (size_t rows = 0; rows < out1.size(); rows++) assert(std::abs(out1[rows] - expected1[rows]) < 0.01); @@ -389,12 +389,12 @@ void ols_test() { // perform regression modelling std::vector beta2 = fit_OLS_regressor(data2, Y2); // create test data set with same features = x, x^2, x^3 - std::vector> test2( + std::vector> test_data2( {{-2, 4, -8}, {2, 4, 8}, {-10, 100, -1000}, {10, 100, 1000}}); // expected regression outputs std::vector expected2({-104, -88, -1000, 1000}); // predicted regression outputs - std::vector out2 = predict_OLS_regressor(test2, beta2); + std::vector out2 = predict_OLS_regressor(test_data2, beta2); // compare predicted results are within +-0.01 limit of expected for (size_t rows = 0; rows < out2.size(); rows++) assert(std::abs(out2[rows] - expected2[rows]) < 0.01); From 9379ae1a6c0731780c0b5260a553051ab5a46d82 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 13:46:46 -0400 Subject: [PATCH 69/92] added LGTM status --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8734158b7..a6cde5f50 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # The Algorithms - C++ # {#mainpage} -[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/C-Plus-Plus) +[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/C-Plus-Plus) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/TheAlgorithms/C-Plus-Plus.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/TheAlgorithms/C-Plus-Plus/context:cpp) [![Gitter chat](https://img.shields.io/badge/Chat-Gitter-ff69b4.svg?label=Chat&logo=gitter&style=flat-square)](https://gitter.im/TheAlgorithms) ![contributions welcome](https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square) ![GitHub repo size](https://img.shields.io/github/repo-size/TheAlgorithms/C-Plus-Plus?color=red&style=flat-square) From b3d85cd8e158bb6482735101762f6f73d6348e74 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 14:23:25 -0400 Subject: [PATCH 70/92] add LGTM status + remove HTML tags and use Markdown syntax Signed-off-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a6cde5f50..53320a5b1 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # The Algorithms - C++ # {#mainpage} + [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/C-Plus-Plus) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/TheAlgorithms/C-Plus-Plus.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/TheAlgorithms/C-Plus-Plus/context:cpp) [![Gitter chat](https://img.shields.io/badge/Chat-Gitter-ff69b4.svg?label=Chat&logo=gitter&style=flat-square)](https://gitter.im/TheAlgorithms) -![contributions welcome](https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square) +[![contributions welcome](https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square)]("https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md") ![GitHub repo size](https://img.shields.io/github/repo-size/TheAlgorithms/C-Plus-Plus?color=red&style=flat-square) ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/TheAlgorithms/C-Plus-Plus?color=green&style=flat-square) -![Doxygen CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Doxygen%20CI/badge.svg) -![Awesome CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Awesome%20CI%20Workflow/badge.svg) +[![Doxygen CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Doxygen%20CI/badge.svg)]("https://TheAlgorithms.github.io/C-Plus-Plus") +[![Awesome CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Awesome%20CI%20Workflow/badge.svg)]("https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22") [Online Documentation](https://TheAlgorithms.github.io/C-Plus-Plus). From c5933c8525452c300ef961881bf883646db359dc Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 14:29:10 -0400 Subject: [PATCH 71/92] updated project summary description Signed-off-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 53320a5b1..aa0f96e80 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,15 @@ [![Doxygen CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Doxygen%20CI/badge.svg)]("https://TheAlgorithms.github.io/C-Plus-Plus") [![Awesome CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Awesome%20CI%20Workflow/badge.svg)]("https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22") -[Online Documentation](https://TheAlgorithms.github.io/C-Plus-Plus). +## Algorithms implemented in C++ (for education) +The repository is a collection of implementation of a variety of algorithms implemented in C++. These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations are meant to be a learning resource for educators and students. Hence, one may find more than one implementation for the same algorithm with different optimizations and different strategies used that would be documented therein. + +## Documentation + +[Online Documentation](https://TheAlgorithms.github.io/C-Plus-Plus) is generated from the repository source codes directly. The documentation contains all resources including source code snippets, details on execution of the programs, diagrammatic representation of program flow, and links to external resources where necessary. The documentation also introduces interactive source code with links to documentation for C++ STL library functions used. Click on [Files menu](https://TheAlgorithms.github.io/C-Plus-Plus/files.html) to see the list of all the files documented with the code. -### Algorithms implemented in C++ (for education) -The implementations are for learning purpose. They may be less efficient than the implementation in the standard library. +## Contributions -### Contribute Guidelines -Read our [Contribution Guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md) before you contribute. +As a community developed and community maintained repository, we welcome new un-plagiarized contributions. Read our [Contribution Guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md) before you contribute. From aa16f4d113c028be73c9871d554b95e233ede32d Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 14:29:45 -0400 Subject: [PATCH 72/92] added features description Signed-off-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index aa0f96e80..bb8d32dcb 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,16 @@ The repository is a collection of implementation of a variety of algorithms implemented in C++. These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations are meant to be a learning resource for educators and students. Hence, one may find more than one implementation for the same algorithm with different optimizations and different strategies used that would be documented therein. +## Features + +* The repository provides implementations of various algorithms in one of the most fundamental general purpose languages - [C++](https://en.wikipedia.org/wiki/C%2B%2B). +* Well documented source code with detailed explanations provide a valuable resource for educators and students alike. +* Each source code is atomic using [STL classes](https://en.wikipedia.org/wiki/Standard_Template_Library) and _no external libraries_ are required for their compilation and execution. Thus the fundamentals of the algorithms can be studied in much depth. +* Source codes are [compiled and tested](https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22) for every commit on the latest versions of three major operating systems Windows, MacOS and Ubuntu (Linux) using MSVC 16 2019, AppleClang 11.0 and GNU 7.5.0 respectively. +* Strict adherence [C++11](https://en.wikipedia.org/wiki/C%2B%2B11) standard ensures portability of code to embedded systems as well like ESP32, ARM Cortex, etc with little to no changes. +* Self-checks within programs ensure correct implementations with confidence. +* Modular implementations and OpenSource licensing enable the functions to be utilized conveniently in other applications. + ## Documentation [Online Documentation](https://TheAlgorithms.github.io/C-Plus-Plus) is generated from the repository source codes directly. The documentation contains all resources including source code snippets, details on execution of the programs, diagrammatic representation of program flow, and links to external resources where necessary. The documentation also introduces interactive source code with links to documentation for C++ STL library functions used. From 54dcadf07d5e7810655172fb9ed9f3b94e714c2a Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 14:38:03 -0400 Subject: [PATCH 73/92] fix contributions description Signed-off-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb8d32dcb..f711c58b8 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,4 @@ Click on [Files menu](https://TheAlgorithms.github.io/C-Plus-Plus/files.html) to ## Contributions -As a community developed and community maintained repository, we welcome new un-plagiarized contributions. Read our [Contribution Guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md) before you contribute. +As a community developed and community maintained repository, we welcome new un-plagiarized quality contributions. Please read our [Contribution Guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md). From a9c005da70569a168ffaf17ddd3ee286a6bd31dd Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 14:49:05 -0400 Subject: [PATCH 74/92] overview + comment why mainpage Signed-off-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f711c58b8..0dfb173bf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # The Algorithms - C++ # {#mainpage} + [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/C-Plus-Plus) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/TheAlgorithms/C-Plus-Plus.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/TheAlgorithms/C-Plus-Plus/context:cpp) [![Gitter chat](https://img.shields.io/badge/Chat-Gitter-ff69b4.svg?label=Chat&logo=gitter&style=flat-square)](https://gitter.im/TheAlgorithms) @@ -8,7 +9,7 @@ [![Doxygen CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Doxygen%20CI/badge.svg)]("https://TheAlgorithms.github.io/C-Plus-Plus") [![Awesome CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Awesome%20CI%20Workflow/badge.svg)]("https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22") -## Algorithms implemented in C++ (for education) +## Overview The repository is a collection of implementation of a variety of algorithms implemented in C++. These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations are meant to be a learning resource for educators and students. Hence, one may find more than one implementation for the same algorithm with different optimizations and different strategies used that would be documented therein. @@ -18,7 +19,7 @@ The repository is a collection of implementation of a variety of algorithms impl * Well documented source code with detailed explanations provide a valuable resource for educators and students alike. * Each source code is atomic using [STL classes](https://en.wikipedia.org/wiki/Standard_Template_Library) and _no external libraries_ are required for their compilation and execution. Thus the fundamentals of the algorithms can be studied in much depth. * Source codes are [compiled and tested](https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22) for every commit on the latest versions of three major operating systems Windows, MacOS and Ubuntu (Linux) using MSVC 16 2019, AppleClang 11.0 and GNU 7.5.0 respectively. -* Strict adherence [C++11](https://en.wikipedia.org/wiki/C%2B%2B11) standard ensures portability of code to embedded systems as well like ESP32, ARM Cortex, etc with little to no changes. +* Strict adherence to [C++11](https://en.wikipedia.org/wiki/C%2B%2B11) standard ensures portability of code to embedded systems as well like ESP32, ARM Cortex, etc with little to no changes. * Self-checks within programs ensure correct implementations with confidence. * Modular implementations and OpenSource licensing enable the functions to be utilized conveniently in other applications. From 8f72445a6dcce05be377bcaf31495385c0f1baf4 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 20:14:36 -0400 Subject: [PATCH 75/92] minor punctuations --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0dfb173bf..e5755c3a5 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ The repository is a collection of implementation of a variety of algorithms impl * The repository provides implementations of various algorithms in one of the most fundamental general purpose languages - [C++](https://en.wikipedia.org/wiki/C%2B%2B). * Well documented source code with detailed explanations provide a valuable resource for educators and students alike. * Each source code is atomic using [STL classes](https://en.wikipedia.org/wiki/Standard_Template_Library) and _no external libraries_ are required for their compilation and execution. Thus the fundamentals of the algorithms can be studied in much depth. -* Source codes are [compiled and tested](https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22) for every commit on the latest versions of three major operating systems Windows, MacOS and Ubuntu (Linux) using MSVC 16 2019, AppleClang 11.0 and GNU 7.5.0 respectively. -* Strict adherence to [C++11](https://en.wikipedia.org/wiki/C%2B%2B11) standard ensures portability of code to embedded systems as well like ESP32, ARM Cortex, etc with little to no changes. +* Source codes are [compiled and tested](https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22) for every commit on the latest versions of three major operating systems viz., Windows, MacOS and Ubuntu (Linux) using MSVC 16 2019, AppleClang 11.0 and GNU 7.5.0 respectively. +* Strict adherence to [C++11](https://en.wikipedia.org/wiki/C%2B%2B11) standard ensures portability of code to embedded systems as well like ESP32, ARM Cortex, etc. with little to no changes. * Self-checks within programs ensure correct implementations with confidence. * Modular implementations and OpenSource licensing enable the functions to be utilized conveniently in other applications. From 0f42f8f96ca404a90ef9b9a24293782c00f8505e Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 20:20:43 -0400 Subject: [PATCH 76/92] apply suggestions by reviewers --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e5755c3a5..e99ec1311 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## Overview -The repository is a collection of implementation of a variety of algorithms implemented in C++. These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations are meant to be a learning resource for educators and students. Hence, one may find more than one implementation for the same algorithm with different optimizations and different strategies used that would be documented therein. +The repository is a collection of implementation of a variety of algorithms implemented in C++. These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations and the associated documentation are meant to provide a learning resource for educators and students. Hence, one may find more than one implementation for the same objective but using a different algorithm strategies and optimizations. ## Features @@ -30,4 +30,4 @@ Click on [Files menu](https://TheAlgorithms.github.io/C-Plus-Plus/files.html) to ## Contributions -As a community developed and community maintained repository, we welcome new un-plagiarized quality contributions. Please read our [Contribution Guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md). +As a community developed and maintained repository, we welcome new un-plagiarized quality contributions. Please read our [Contribution Guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md). From 7218eeb5b8440499d4ce477255486fd788ecc91d Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 20:36:03 -0400 Subject: [PATCH 77/92] initial cipher folder commit --- ciphers/CMakeLists.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 ciphers/CMakeLists.txt diff --git a/ciphers/CMakeLists.txt b/ciphers/CMakeLists.txt new file mode 100644 index 000000000..1efde3087 --- /dev/null +++ b/ciphers/CMakeLists.txt @@ -0,0 +1,18 @@ +# If necessary, use the RELATIVE flag, otherwise each source file may be listed +# with full pathname. RELATIVE may makes it easier to extract an executable name +# automatically. +file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp ) +# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c ) +# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES) +foreach( testsourcefile ${APP_SOURCES} ) + # I used a simple string replace, to cut off .cpp. + string( REPLACE ".cpp" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX) + if(OpenMP_CXX_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_CXX) + endif() + install(TARGETS ${testname} DESTINATION "bin/ciphers") + +endforeach( testsourcefile ${APP_SOURCES} ) From db28999ca3f01f0bf779875ccf7295d354ff8ade Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 20:36:46 -0400 Subject: [PATCH 78/92] initial hill-cipher commit - does not execute corectly --- ciphers/hill_cipher.cpp | 411 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 411 insertions(+) create mode 100644 ciphers/hill_cipher.cpp diff --git a/ciphers/hill_cipher.cpp b/ciphers/hill_cipher.cpp new file mode 100644 index 000000000..10fed923d --- /dev/null +++ b/ciphers/hill_cipher.cpp @@ -0,0 +1,411 @@ +/** + * @file hill_cipher.cpp + * @author [Krishna Vedala](https://github.com/kvedala) + * @brief Implementation of [Hill + * cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm. + * + * Program to generate the encryption-decryption key and perform encryption and + * decryption of ASCII text. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +#include "../numerical_methods/lu_decomposition.h" + +/** + * operator to print a matrix + */ +template +static std::ostream &operator<<(std::ostream &out, matrix const &v) { + const int width = 15; + const char separator = ' '; + + for (size_t row = 0; row < v.size(); row++) { + for (size_t col = 0; col < v[row].size(); col++) + out << std::left << std::setw(width) << std::setfill(separator) + << v[row][col]; + out << std::endl; + } + + return out; +} + +/** \namespace ciphers + * \brief Algorithms for encryption and decryption + */ +namespace ciphers { +/** dictionary of characters that can be encrypted and decrypted */ +static const std::string STRKEY = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&" + "*()_+`-=[]{}|;':\",./<>?\\\r\n "; + +/** + * @brief Implementation of [Hill + * Cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm + */ +class HillCipher { + private: + /** + * @brief Function to generate a random integer in a given interval + * + * @param a lower limit of interval + * @param b upper limit of interval + * @tparam T type of output + * @return random integer in the interval \f$[a,b)\f$ + */ + template + static const T2 rand_range(T1 a, T1 b) { + // generate random number between 0 and 1 + long double r = static_cast(std::rand()) / RAND_MAX; + + // scale and return random number as integer + return static_cast(r * (b - a) + a); + } + + /** + * @brief Function overload to fill a matrix with random integers in a given + * interval + * + * @param M pointer to matrix to be filled with random numbers + * @param a lower limit of interval + * @param b upper limit of interval + * @tparam T1 type of input range + * @tparam T2 type of matrix + * @return determinant of generated random matrix + */ + template + static const double rand_range(matrix *M, T1 a, T1 b) { + for (size_t i = 0; i < M->size(); i++) { + for (size_t j = 0; j < M[0][0].size(); j++) { + M[0][i][j] = rand_range(a, b); + } + } + + return determinant_lu(*M); + } + + /** + * @brief Compute + * [GCD](https://en.wikipedia.org/wiki/Greatest_common_divisor) of two + * integers using Euler's algorithm + * + * @param a first number + * @param b second number + * @return GCD of \f$a\f$ and \f$b\f$ + */ + template + static const T gcd(T a, T b) { + if (b > a) // ensure always a < b + std::swap(a, b); + + while (b != 0) { + T tmp = b; + b = a % b; + a = tmp; + } + + return a; + } + + /** + * @brief helper function to perform vector multiplication with encryption + * or decryption matrix + * + * @param vector vector to multiply + * @param key encryption or decryption key matrix + * @return corresponding encrypted or decrypted text + */ + static const std::valarray mat_mul( + const std::valarray &vector, const matrix &key) { + std::valarray out(vector); // make a copy + + for (size_t i = 0; i < key.size(); i++) { + int tmp = 0; + for (size_t j = 0; j < vector.size(); j++) { + tmp += key[i][j] * vector[j]; + } + out[i] = static_cast(tmp % STRKEY.length()); + } + + return out; + } + + /** + * @brief Convenience function to perform block cipher operations. The + * operations are identical for both encryption and decryption. + * + * @param text input text to encrypt or decrypt + * @param key key for encryption or decryption + * @return encrypted/decrypted output + */ + static const std::string codec(const std::string &text, + const matrix &key) { + size_t text_len = text.length(); + size_t key_len = key.size(); + + // length of output string must be a multiple of key_len + // create output string and initialize with '\0' character + size_t L2 = text_len % key_len == 0 + ? text_len + : text_len + key_len - (text_len % key_len); + std::string coded_text(L2, '\0'); + + // temporary array for batch processing + std::valarray batch_int(key_len); + for (size_t i = 0; i < L2 - key_len + 1; i += key_len) { + for (size_t j = 0; j < key_len; j++) { + batch_int[j] = static_cast( + STRKEY.find(text[i + j])); // get index of character in key + } + + batch_int = mat_mul(batch_int, key); + + for (size_t j = 0; j < key_len; j++) { + coded_text[i + j] = + STRKEY[batch_int[j]]; // get character at key + } + } + + return coded_text; + } + + /** + * Get matrix inverse using Row-transformations. Given matrix must + * be a square and non-singular. + * \returns inverse matrix + **/ + template + static matrix get_inverse(matrix const &A) { + // Assuming A is square matrix + size_t N = A.size(); + + matrix inverse(N, std::valarray(N)); + for (size_t row = 0; row < N; row++) { + for (size_t col = 0; col < N; col++) { + // create identity matrix + inverse[row][col] = (row == col) ? 1.f : 0.f; + } + } + + if (A.size() != A[0].size()) { + std::cerr << "A must be a square matrix!" << std::endl; + return inverse; + } + + // preallocate a temporary matrix identical to A + matrix temp(N, std::valarray(N)); + for (size_t row = 0; row < N; row++) { + for (size_t col = 0; col < N; col++) + temp[row][col] = static_cast(A[row][col]); + } + + // start transformations + for (size_t row = 0; row < N; row++) { + for (size_t row2 = row; row2 < N && temp[row][row] == 0; row2++) { + // this to ensure diagonal elements are not 0 + temp[row] = temp[row] + temp[row2]; + inverse[row] = inverse[row] + inverse[row2]; + } + + for (size_t col2 = row; col2 < N && temp[row][row] == 0; col2++) { + // this to further ensure diagonal elements are not 0 + for (size_t row2 = 0; row2 < N; row2++) { + temp[row2][row] = temp[row2][row] + temp[row2][col2]; + inverse[row2][row] = + inverse[row2][row] + inverse[row2][col2]; + } + } + + if (temp[row][row] == 0) { + // Probably a low-rank matrix and hence singular + std::cerr << "Low-rank matrix, no inverse!" << std::endl; + return inverse; + } + + // set diagonal to 1 + double divisor = temp[row][row]; + temp[row] = temp[row] / divisor; + inverse[row] = inverse[row] / divisor; + // Row transformations + for (size_t row2 = 0; row2 < N; row2++) { + if (row2 == row) + continue; + double factor = temp[row2][row]; + temp[row2] = temp[row2] - factor * temp[row]; + inverse[row2] = inverse[row2] - factor * inverse[row]; + } + } + + return inverse; + } + + static int modulo(int a, int b) { + int ret = a % b; + if (ret < 0) + ret += b; + return ret; + } + + public: + /** + * @brief Generate encryption matrix of a given size. Larger size matrices + * are difficult to generate but provide more security. + * + * @param size size of matrix (typically \f$\text{size}\le10\f$) + * @return Encryption martix + */ + static matrix generate_encryption_key(size_t size) { + matrix encrypt_key(size, std::valarray(size)); + int mat_determinant = -1; // because matrix has only ints, the + // determinant will also be an int + + int L = static_cast(STRKEY.length()); + + double dd; + do { + dd = rand_range(&encrypt_key, 0, L); + mat_determinant = static_cast(dd); + + if (mat_determinant < 0) + mat_determinant = (mat_determinant % L) + L; + } while (dd <= 0.1 || // while singular or ill-defined + !std::isfinite(dd) || // while determinant is not finite + gcd(mat_determinant, L) != 1); // while no common factors + // std::cout << + + return encrypt_key; + } + + /** + * @brief Generate decryption matrix from an encryption matrix key. + * + * @param encrypt_key encryption key for which to create a decrypt key + * @return Decryption martix + */ + static matrix generate_decryption_key(matrix const &encrypt_key) { + size_t size = encrypt_key.size(); + int L = static_cast(STRKEY.length()); + + matrix decrypt_key(size, std::valarray(size)); + int det_encrypt = static_cast(determinant_lu(encrypt_key)); + + int mat_determinant = det_encrypt < 0 ? det_encrypt % L : det_encrypt; + + matrix tmp_inverse = get_inverse(encrypt_key); + double d2 = determinant_lu(decrypt_key); + + // find co-prime factor for inversion + int det_inv = -1; + for (int i = 0; i < L; i++) { + if (modulo(mat_determinant * i, L) == 1) { + det_inv = i; + break; + } + } + + if (det_inv == -1) { + std::cerr << "Could not find a co-prime for inversion\n"; + std::exit(EXIT_FAILURE); + } + + mat_determinant = det_inv * det_encrypt; + + // perform modular inverse of encryption matrix + int i; +#ifdef _OPENMP +#pragma parallel omp for private(i) +#endif + for (i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + int temp = std::round(tmp_inverse[i][j] * mat_determinant); + decrypt_key[i][j] = modulo(temp, L); + } + } + return decrypt_key; + } + + /** + * @brief Generate encryption and decryption key pair + * + * @param size size of matrix key (typically \f$\text{size}\le10\f$) + * @return std::pair, matrix> encryption and decryption + * keys as a pair + */ + static std::pair, matrix> generate_keys(size_t size) { + matrix encrypt_key = generate_encryption_key(size); + matrix decrypt_key = generate_decryption_key(encrypt_key); + double det2 = determinant_lu(decrypt_key); + while (det2 < 0.1) { + encrypt_key = generate_encryption_key(size); + decrypt_key = generate_decryption_key(encrypt_key); + det2 = determinant_lu(decrypt_key); + } + return std::make_pair(encrypt_key, decrypt_key); + } + + /** + * @brief Encrypt a given text using a given key + * + * @param text string to encrypt + * @param encrypt_key key for encryption + * @return encrypted text + */ + static const std::string encrypt_text(const std::string &text, + const matrix &encrypt_key) { + return codec(text, encrypt_key); + } + + /** + * @brief Decrypt a given text using a given key + * + * @param text string to decrypt + * @param decrypt_key key for decryption + * @return decrypted text + */ + static const std::string decrypt_text(const std::string &text, + const matrix &decrypt_key) { + return codec(text, decrypt_key); + } +}; + +} // namespace ciphers + +/** Main function */ +int main() { + std::srand(std::time(nullptr)); + + std::cout << "Key dictionary: (" << ciphers::STRKEY.length() << ")\n\t" + << ciphers::STRKEY << "\n"; + + std::string text = "This is a simple text with numb3r5 and exclamat!0n."; + // std::string text = "Hello world!"; + std::cout << "Original text:\n\t" << text << std::endl; + + std::pair, matrix> p = + ciphers::HillCipher::generate_keys(5); + matrix ekey = p.first; + matrix dkey = p.second; + // matrix ekey = {{22, 28, 25}, {5, 26, 15}, {14, 18, 9}}; + // std::cout << "Encryption key: \n" << ekey; + std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey); + std::cout << "Encrypted text:\n\t" << gibberish << std::endl; + + // matrix dkey = ciphers::HillCipher::generate_decryption_key(ekey); + // std::cout << "Decryption key: \n" << dkey; + std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey); + std::cout << "Reconstruct text:\n\t" << txt_back << std::endl; + + assert(txt_back == text); + + return 0; +} From 0b57b895439bb6c7539851f5ef42c2b2195bedf8 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 27 Jun 2020 00:37:39 +0000 Subject: [PATCH 79/92] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 679e6f7d8..a3c66cd96 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -10,6 +10,9 @@ * [Rat Maze](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/rat_maze.cpp) * [Sudoku Solve](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/sudoku_solve.cpp) +## Ciphers + * [Hill Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/hill_cipher.cpp) + ## Data Structures * [Avltree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/avltree.cpp) * [Binary Search Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/binary_search_tree.cpp) From bade62d0633965f4816b2022717eaf597a6981b6 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 21:44:02 -0400 Subject: [PATCH 80/92] working hill cipher --- ciphers/hill_cipher.cpp | 80 ++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/ciphers/hill_cipher.cpp b/ciphers/hill_cipher.cpp index 10fed923d..59ce73705 100644 --- a/ciphers/hill_cipher.cpp +++ b/ciphers/hill_cipher.cpp @@ -5,15 +5,31 @@ * cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm. * * Program to generate the encryption-decryption key and perform encryption and - * decryption of ASCII text. + * decryption of ASCII text using the famous block cipher algorithm. This is a + * powerful encryption algorithm that is relatively easy to implement with a + * given key. The strength of the algorithm depends on the size of the block + * encryption matrix key; the bigger the matrix, the stronger the encryption and + * more difficult to break it. However, the important requirement for the matrix + * is that: + * 1. matrix should be invertible - all inversion conditions should be satisfied + * and + * 2. its determinant must not have any common factors with the length of + * character set + * Due to this restriction, most implementations only implement with small 3x3 + * encryption keys and a small subset of ASCII alphabets. + * + * In the current implementation, I present to you an implementation for + * generating larger encryption keys (I have attempted upto 10x10) and an ASCII + * character set of 97 printable characters. Hence, a typical ASCII text file + * could be easily encrypted with the module. */ #include #include +#include #include #include #include -#include #include #include #ifdef _OPENMP @@ -45,7 +61,7 @@ static std::ostream &operator<<(std::ostream &out, matrix const &v) { */ namespace ciphers { /** dictionary of characters that can be encrypted and decrypted */ -static const std::string STRKEY = +static const char *STRKEY = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&" "*()_+`-=[]{}|;':\",./<>?\\\r\n "; @@ -129,17 +145,41 @@ class HillCipher { const std::valarray &vector, const matrix &key) { std::valarray out(vector); // make a copy + size_t L = std::strlen(STRKEY); + for (size_t i = 0; i < key.size(); i++) { int tmp = 0; for (size_t j = 0; j < vector.size(); j++) { tmp += key[i][j] * vector[j]; } - out[i] = static_cast(tmp % STRKEY.length()); + out[i] = static_cast(tmp % L); } return out; } + /** + * @brief Get the character at a given index in the ::STRKEY + * + * @param idx index value + * @return character at the index + */ + static inline char get_idx_char(const uint8_t idx) { return STRKEY[idx]; } + + /** + * @brief Get the index of a character in the ::STRKEY + * + * @param ch character to search + * @return index of character + */ + static inline uint8_t get_char_idx(const char ch) { + size_t L = std::strlen(STRKEY); + + for (uint8_t idx = 0; idx < L; idx++) + if (STRKEY[idx] == ch) + return idx; + } + /** * @brief Convenience function to perform block cipher operations. The * operations are identical for both encryption and decryption. @@ -164,8 +204,7 @@ class HillCipher { std::valarray batch_int(key_len); for (size_t i = 0; i < L2 - key_len + 1; i += key_len) { for (size_t j = 0; j < key_len; j++) { - batch_int[j] = static_cast( - STRKEY.find(text[i + j])); // get index of character in key + batch_int[j] = get_char_idx(text[i + j]); } batch_int = mat_mul(batch_int, key); @@ -259,26 +298,33 @@ class HillCipher { public: /** * @brief Generate encryption matrix of a given size. Larger size matrices - * are difficult to generate but provide more security. + * are difficult to generate but provide more security. Important conditions + * are: + * 1. matrix should be invertible + * 2. determinant must not have any common factors with the length of + * character key * * @param size size of matrix (typically \f$\text{size}\le10\f$) * @return Encryption martix */ static matrix generate_encryption_key(size_t size) { matrix encrypt_key(size, std::valarray(size)); + matrix min_mat = encrypt_key; int mat_determinant = -1; // because matrix has only ints, the // determinant will also be an int - - int L = static_cast(STRKEY.length()); + int L = std::strlen(STRKEY); double dd; do { - dd = rand_range(&encrypt_key, 0, L); + // keeping the random number range smaller generates better + // defined matrices with more ease of cracking + dd = rand_range(&encrypt_key, 0, 10); mat_determinant = static_cast(dd); if (mat_determinant < 0) - mat_determinant = (mat_determinant % L) + L; - } while (dd <= 0.1 || // while singular or ill-defined + mat_determinant = (mat_determinant % L); + } while (std::abs(dd) > 1e3 || // while ill-defined + dd < 0.1 || // while singular !std::isfinite(dd) || // while determinant is not finite gcd(mat_determinant, L) != 1); // while no common factors // std::cout << @@ -294,7 +340,7 @@ class HillCipher { */ static matrix generate_decryption_key(matrix const &encrypt_key) { size_t size = encrypt_key.size(); - int L = static_cast(STRKEY.length()); + int L = std::strlen(STRKEY); matrix decrypt_key(size, std::valarray(size)); int det_encrypt = static_cast(determinant_lu(encrypt_key)); @@ -384,7 +430,7 @@ class HillCipher { int main() { std::srand(std::time(nullptr)); - std::cout << "Key dictionary: (" << ciphers::STRKEY.length() << ")\n\t" + std::cout << "Key dictionary: (" << std::strlen(ciphers::STRKEY) << ")\n\t" << ciphers::STRKEY << "\n"; std::string text = "This is a simple text with numb3r5 and exclamat!0n."; @@ -392,16 +438,16 @@ int main() { std::cout << "Original text:\n\t" << text << std::endl; std::pair, matrix> p = - ciphers::HillCipher::generate_keys(5); + ciphers::HillCipher::generate_keys(8); matrix ekey = p.first; matrix dkey = p.second; // matrix ekey = {{22, 28, 25}, {5, 26, 15}, {14, 18, 9}}; - // std::cout << "Encryption key: \n" << ekey; + std::cout << "Encryption key: \n" << ekey; std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey); std::cout << "Encrypted text:\n\t" << gibberish << std::endl; // matrix dkey = ciphers::HillCipher::generate_decryption_key(ekey); - // std::cout << "Decryption key: \n" << dkey; + std::cout << "Decryption key: \n" << dkey; std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey); std::cout << "Reconstruct text:\n\t" << txt_back << std::endl; From f932aed5d2aebc4fe1febcdb8a3583a505ac72b4 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 22:02:21 -0400 Subject: [PATCH 81/92] more docs + more control on matrix creation --- ciphers/hill_cipher.cpp | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/ciphers/hill_cipher.cpp b/ciphers/hill_cipher.cpp index 59ce73705..f1382f57e 100644 --- a/ciphers/hill_cipher.cpp +++ b/ciphers/hill_cipher.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #ifdef _OPENMP @@ -98,6 +99,12 @@ class HillCipher { * @tparam T1 type of input range * @tparam T2 type of matrix * @return determinant of generated random matrix + * + * @warning There will need to be a balance between the matrix size and the + * range of random numbers. If the matrix is large, the range of random + * numbers must be small to have a well defined keys. Or if the matrix is + * smaller, the random numbers range can be larger. For an 8x8 matrix, range + * should be no more than \f$[0,10]\f$ */ template static const double rand_range(matrix *M, T1 a, T1 b) { @@ -303,11 +310,18 @@ class HillCipher { * 1. matrix should be invertible * 2. determinant must not have any common factors with the length of * character key + * There is no head-fast way to generate hte matrix under the given + * numerical restrictions of the machine but the conditions added achieve + * the goals. Bigger the matrix, greater is the probability of the matrix + * being ill-defined. * * @param size size of matrix (typically \f$\text{size}\le10\f$) + * @param limit1 lower limit of range of random elements (default=0) + * @param limit2 upper limit of range of random elements (default=10) * @return Encryption martix */ - static matrix generate_encryption_key(size_t size) { + static matrix generate_encryption_key(size_t size, int limit1 = 0, + int limit2 = 10) { matrix encrypt_key(size, std::valarray(size)); matrix min_mat = encrypt_key; int mat_determinant = -1; // because matrix has only ints, the @@ -318,7 +332,7 @@ class HillCipher { do { // keeping the random number range smaller generates better // defined matrices with more ease of cracking - dd = rand_range(&encrypt_key, 0, 10); + dd = rand_range(&encrypt_key, limit1, limit2); mat_determinant = static_cast(dd); if (mat_determinant < 0) @@ -384,15 +398,21 @@ class HillCipher { * @brief Generate encryption and decryption key pair * * @param size size of matrix key (typically \f$\text{size}\le10\f$) + * @param limit1 lower limit of range of random elements (default=0) + * @param limit2 upper limit of range of random elements (default=10) * @return std::pair, matrix> encryption and decryption * keys as a pair + * + * @see ::generate_encryption_key */ - static std::pair, matrix> generate_keys(size_t size) { + static std::pair, matrix> generate_keys(size_t size, + int limit1 = 0, + int limit2 = 10) { matrix encrypt_key = generate_encryption_key(size); matrix decrypt_key = generate_decryption_key(encrypt_key); double det2 = determinant_lu(decrypt_key); - while (det2 < 0.1) { - encrypt_key = generate_encryption_key(size); + while (std::abs(det2) < 0.1 || std::abs(det2) > 1e3) { + encrypt_key = generate_encryption_key(size, limit1, limit2); decrypt_key = generate_decryption_key(encrypt_key); det2 = determinant_lu(decrypt_key); } @@ -438,20 +458,20 @@ int main() { std::cout << "Original text:\n\t" << text << std::endl; std::pair, matrix> p = - ciphers::HillCipher::generate_keys(8); + ciphers::HillCipher::generate_keys(10, 0, 5); matrix ekey = p.first; matrix dkey = p.second; // matrix ekey = {{22, 28, 25}, {5, 26, 15}, {14, 18, 9}}; - std::cout << "Encryption key: \n" << ekey; + // std::cout << "Encryption key: \n" << ekey; std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey); std::cout << "Encrypted text:\n\t" << gibberish << std::endl; // matrix dkey = ciphers::HillCipher::generate_decryption_key(ekey); - std::cout << "Decryption key: \n" << dkey; + // std::cout << "Decryption key: \n" << dkey; std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey); std::cout << "Reconstruct text:\n\t" << txt_back << std::endl; - assert(txt_back == text); + assert((txt_back == text) == true); return 0; } From fc489f7f4514eee705c76e84d908f7b83669840c Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Fri, 26 Jun 2020 23:42:16 -0400 Subject: [PATCH 82/92] test2 + refinements --- ciphers/hill_cipher.cpp | 88 +++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 20 deletions(-) diff --git a/ciphers/hill_cipher.cpp b/ciphers/hill_cipher.cpp index f1382f57e..cdcd795d4 100644 --- a/ciphers/hill_cipher.cpp +++ b/ciphers/hill_cipher.cpp @@ -1,6 +1,5 @@ /** * @file hill_cipher.cpp - * @author [Krishna Vedala](https://github.com/kvedala) * @brief Implementation of [Hill * cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm. * @@ -21,7 +20,14 @@ * In the current implementation, I present to you an implementation for * generating larger encryption keys (I have attempted upto 10x10) and an ASCII * character set of 97 printable characters. Hence, a typical ASCII text file - * could be easily encrypted with the module. + * could be easily encrypted with the module. The larger character set increases + * the modulo of cipher and hence the matrix determinants can get very large + * very quickly rendering them ill-defined. + * + * \note This program uses determinant computation using LU decomposition from + * the file lu_decomposition.h + * + * @author [Krishna Vedala](https://github.com/kvedala) */ #include @@ -31,8 +37,6 @@ #include #include #include -#include -#include #ifdef _OPENMP #include #endif @@ -64,7 +68,7 @@ namespace ciphers { /** dictionary of characters that can be encrypted and decrypted */ static const char *STRKEY = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&" - "*()_+`-=[]{}|;':\",./<>?\\\r\n "; + "*()_+`-=[]{}|;':\",./<>?\\\r\n \0"; /** * @brief Implementation of [Hill @@ -182,9 +186,13 @@ class HillCipher { static inline uint8_t get_char_idx(const char ch) { size_t L = std::strlen(STRKEY); - for (uint8_t idx = 0; idx < L; idx++) + for (uint8_t idx = 0; idx <= L; idx++) if (STRKEY[idx] == ch) return idx; + + std::cerr << __func__ << ":" << __LINE__ << ": (" << ch + << ") Should not reach here!\n"; + return 0; } /** @@ -208,8 +216,12 @@ class HillCipher { std::string coded_text(L2, '\0'); // temporary array for batch processing - std::valarray batch_int(key_len); - for (size_t i = 0; i < L2 - key_len + 1; i += key_len) { + int i; +#ifdef _OPENMP +#pragma parallel omp for private(i) +#endif + for (i = 0; i < L2 - key_len + 1; i += key_len) { + std::valarray batch_int(key_len); for (size_t j = 0; j < key_len; j++) { batch_int[j] = get_char_idx(text[i + j]); } @@ -338,7 +350,7 @@ class HillCipher { if (mat_determinant < 0) mat_determinant = (mat_determinant % L); } while (std::abs(dd) > 1e3 || // while ill-defined - dd < 0.1 || // while singular + std::abs(dd) < 0.1 || // while singular !std::isfinite(dd) || // while determinant is not finite gcd(mat_determinant, L) != 1); // while no common factors // std::cout << @@ -446,21 +458,21 @@ class HillCipher { } // namespace ciphers -/** Main function */ -int main() { - std::srand(std::time(nullptr)); - - std::cout << "Key dictionary: (" << std::strlen(ciphers::STRKEY) << ")\n\t" - << ciphers::STRKEY << "\n"; - - std::string text = "This is a simple text with numb3r5 and exclamat!0n."; +/** + * @brief Self test 1 - using 3x3 randomly generated key + * + * @param text string to encrypt and decrypt + */ +void test1(const std::string &text) { // std::string text = "Hello world!"; - std::cout << "Original text:\n\t" << text << std::endl; + std::cout << "======Test 1 (3x3 key) ======\nOriginal text:\n\t" << text + << std::endl; std::pair, matrix> p = - ciphers::HillCipher::generate_keys(10, 0, 5); + ciphers::HillCipher::generate_keys(3, 0, 100); matrix ekey = p.first; matrix dkey = p.second; + // matrix ekey = {{22, 28, 25}, {5, 26, 15}, {14, 18, 9}}; // std::cout << "Encryption key: \n" << ekey; std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey); @@ -471,7 +483,43 @@ int main() { std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey); std::cout << "Reconstruct text:\n\t" << txt_back << std::endl; - assert((txt_back == text) == true); + assert(txt_back == text); +} + +/** + * @brief Self test 2 - using 8x8 randomly generated key + * + * @param text string to encrypt and decrypt + */ +void test2(const std::string &text) { + // std::string text = "Hello world!"; + std::cout << "======Test 2 (8x8 key) ======\nOriginal text:\n\t" << text + << std::endl; + + std::pair, matrix> p = + ciphers::HillCipher::generate_keys(8, 0, 10); + matrix ekey = p.first; + matrix dkey = p.second; + + std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey); + std::cout << "Encrypted text:\n\t" << gibberish << std::endl; + + std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey); + std::cout << "Reconstruct text:\n\t" << txt_back << std::endl; + + assert(text.compare(0, text.length() - 1, txt_back) == 0); +} + +/** Main function */ +int main() { + std::srand(std::time(nullptr)); + std::cout << "Key dictionary: (" << std::strlen(ciphers::STRKEY) << ")\n\t" + << ciphers::STRKEY << "\n"; + + std::string text = "This is a simple text with numb3r5 and exclamat!0n."; + + test1(text); + test2(text); return 0; } From 541f762deb37990d8c38bd50e76b95f12464adb8 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 27 Jun 2020 14:43:11 -0400 Subject: [PATCH 83/92] working algorithm --- ciphers/hill_cipher.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ciphers/hill_cipher.cpp b/ciphers/hill_cipher.cpp index cdcd795d4..4c8c87d26 100644 --- a/ciphers/hill_cipher.cpp +++ b/ciphers/hill_cipher.cpp @@ -484,6 +484,7 @@ void test1(const std::string &text) { std::cout << "Reconstruct text:\n\t" << txt_back << std::endl; assert(txt_back == text); + std::cout << "Passed :)\n"; } /** @@ -497,7 +498,7 @@ void test2(const std::string &text) { << std::endl; std::pair, matrix> p = - ciphers::HillCipher::generate_keys(8, 0, 10); + ciphers::HillCipher::generate_keys(8, 0, 5); matrix ekey = p.first; matrix dkey = p.second; @@ -507,7 +508,8 @@ void test2(const std::string &text) { std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey); std::cout << "Reconstruct text:\n\t" << txt_back << std::endl; - assert(text.compare(0, text.length() - 1, txt_back) == 0); + assert(txt_back.compare(0, text.size(), text) == 0); + std::cout << "Passed :)\n"; } /** Main function */ From e8849dc36f149906220d7108c4fded29c2ce5f58 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 27 Jun 2020 15:45:48 -0400 Subject: [PATCH 84/92] save keys to file + more docs --- ciphers/hill_cipher.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/ciphers/hill_cipher.cpp b/ciphers/hill_cipher.cpp index 4c8c87d26..45315e088 100644 --- a/ciphers/hill_cipher.cpp +++ b/ciphers/hill_cipher.cpp @@ -26,6 +26,9 @@ * * \note This program uses determinant computation using LU decomposition from * the file lu_decomposition.h + * \note The matrix generation algorithm is very rudimentary and does not + * guarantee an invertible modulus matrix. \todo Better matrix generation + * algorithm. * * @author [Krishna Vedala](https://github.com/kvedala) */ @@ -34,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -350,7 +354,7 @@ class HillCipher { if (mat_determinant < 0) mat_determinant = (mat_determinant % L); } while (std::abs(dd) > 1e3 || // while ill-defined - std::abs(dd) < 0.1 || // while singular + dd < 0.1 || // while singular or negative determinant !std::isfinite(dd) || // while determinant is not finite gcd(mat_determinant, L) != 1); // while no common factors // std::cout << @@ -483,6 +487,12 @@ void test1(const std::string &text) { std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey); std::cout << "Reconstruct text:\n\t" << txt_back << std::endl; + std::ofstream out_file("hill_cipher_test1.txt"); + out_file << "Block size: " << ekey.size() << "\n"; + out_file << "Encryption Key:\n" << ekey; + out_file << "\nDecryption Key:\n" << dkey; + out_file.close(); + assert(txt_back == text); std::cout << "Passed :)\n"; } @@ -498,7 +508,7 @@ void test2(const std::string &text) { << std::endl; std::pair, matrix> p = - ciphers::HillCipher::generate_keys(8, 0, 5); + ciphers::HillCipher::generate_keys(8, 0, 3); matrix ekey = p.first; matrix dkey = p.second; @@ -508,6 +518,12 @@ void test2(const std::string &text) { std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey); std::cout << "Reconstruct text:\n\t" << txt_back << std::endl; + std::ofstream out_file("hill_cipher_test2.txt"); + out_file << "Block size: " << ekey.size() << "\n"; + out_file << "Encryption Key:\n" << ekey; + out_file << "\nDecryption Key:\n" << dkey; + out_file.close(); + assert(txt_back.compare(0, text.size(), text) == 0); std::cout << "Passed :)\n"; } From 25c2b82e51b3311998973168e2a9b9c0a3f643c7 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 27 Jun 2020 15:49:46 -0400 Subject: [PATCH 85/92] include ciphers folder in cmake compilation Signed-off-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index adb1c740a..712c3db42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ endif() add_subdirectory(math) add_subdirectory(others) add_subdirectory(search) +add_subdirectory(ciphers) add_subdirectory(strings) add_subdirectory(sorting) add_subdirectory(geometry) From 12799c561691ca8d15cd3454bae1d427f5dc6feb Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 27 Jun 2020 16:00:12 -0400 Subject: [PATCH 86/92] fix lgtm errors --- ciphers/hill_cipher.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ciphers/hill_cipher.cpp b/ciphers/hill_cipher.cpp index 45315e088..1fef0f32e 100644 --- a/ciphers/hill_cipher.cpp +++ b/ciphers/hill_cipher.cpp @@ -115,7 +115,7 @@ class HillCipher { * should be no more than \f$[0,10]\f$ */ template - static const double rand_range(matrix *M, T1 a, T1 b) { + static double rand_range(matrix *M, T1 a, T1 b) { for (size_t i = 0; i < M->size(); i++) { for (size_t j = 0; j < M[0][0].size(); j++) { M[0][i][j] = rand_range(a, b); @@ -190,7 +190,7 @@ class HillCipher { static inline uint8_t get_char_idx(const char ch) { size_t L = std::strlen(STRKEY); - for (uint8_t idx = 0; idx <= L; idx++) + for (size_t idx = 0; idx <= L; idx++) if (STRKEY[idx] == ch) return idx; From 988df1ba59a9895dfab2293d63bca5b400f16847 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 27 Jun 2020 16:59:31 -0400 Subject: [PATCH 87/92] added licenses - #911 --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e99ec1311..9b79c11ef 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## Overview -The repository is a collection of implementation of a variety of algorithms implemented in C++. These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations and the associated documentation are meant to provide a learning resource for educators and students. Hence, one may find more than one implementation for the same objective but using a different algorithm strategies and optimizations. +The repository is a collection of open-source implementation of a variety of algorithms implemented in C++ and licensed under [MIT License](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/LICENSE). These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations and the associated documentation are meant to provide a learning resource for educators and students. Hence, one may find more than one implementation for the same objective but using a different algorithm strategies and optimizations. ## Features @@ -28,6 +28,9 @@ The repository is a collection of implementation of a variety of algorithms impl [Online Documentation](https://TheAlgorithms.github.io/C-Plus-Plus) is generated from the repository source codes directly. The documentation contains all resources including source code snippets, details on execution of the programs, diagrammatic representation of program flow, and links to external resources where necessary. The documentation also introduces interactive source code with links to documentation for C++ STL library functions used. Click on [Files menu](https://TheAlgorithms.github.io/C-Plus-Plus/files.html) to see the list of all the files documented with the code. +[Documentation of Algorithms in C++](https://thealgorithms.github.io/C-Plus-Plus) by [The Algorithms Contributors](https://github.com/TheAlgorithms) is licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1)
+Creative Commons LicenseCredit must be given to you, the creatorAdaptations must be shared under the same terms + ## Contributions As a community developed and maintained repository, we welcome new un-plagiarized quality contributions. Please read our [Contribution Guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md). From 2d67ce3f52c3924b258667d4148905922054eb80 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 27 Jun 2020 17:06:10 -0400 Subject: [PATCH 88/92] fix article `the` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b79c11ef..1d4186d5d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## Overview -The repository is a collection of open-source implementation of a variety of algorithms implemented in C++ and licensed under [MIT License](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/LICENSE). These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations and the associated documentation are meant to provide a learning resource for educators and students. Hence, one may find more than one implementation for the same objective but using a different algorithm strategies and optimizations. +The repository is a collection of open-source implementation of a variety of algorithms implemented in C++ and licensed under [MIT License](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/LICENSE). The algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations and the associated documentation are meant to provide a learning resource for educators and students. Hence, one may find more than one implementation for the same objective but using a different algorithm strategies and optimizations. ## Features From 998c1ce9be4deb4ae7d6098524ead0748c48c2c7 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 27 Jun 2020 17:06:59 -0400 Subject: [PATCH 89/92] remove closed pull-requests info graphic --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 1d4186d5d..9db8e85ba 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ [![Gitter chat](https://img.shields.io/badge/Chat-Gitter-ff69b4.svg?label=Chat&logo=gitter&style=flat-square)](https://gitter.im/TheAlgorithms) [![contributions welcome](https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square)]("https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md") ![GitHub repo size](https://img.shields.io/github/repo-size/TheAlgorithms/C-Plus-Plus?color=red&style=flat-square) -![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/TheAlgorithms/C-Plus-Plus?color=green&style=flat-square) [![Doxygen CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Doxygen%20CI/badge.svg)]("https://TheAlgorithms.github.io/C-Plus-Plus") [![Awesome CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Awesome%20CI%20Workflow/badge.svg)]("https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22") From 695851b2888e143d15eaab00172f38a1eca7f841 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 27 Jun 2020 17:11:19 -0400 Subject: [PATCH 90/92] fix alternatie text for 'by' icon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9db8e85ba..417d5769f 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The repository is a collection of open-source implementation of a variety of alg Click on [Files menu](https://TheAlgorithms.github.io/C-Plus-Plus/files.html) to see the list of all the files documented with the code. [Documentation of Algorithms in C++](https://thealgorithms.github.io/C-Plus-Plus) by [The Algorithms Contributors](https://github.com/TheAlgorithms) is licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1)
-Creative Commons LicenseCredit must be given to you, the creatorAdaptations must be shared under the same terms +Creative Commons LicenseCredit must be given to the creatorAdaptations must be shared under the same terms ## Contributions From de828baa8deed53c9547ea8b2c4d78637039fd75 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 27 Jun 2020 21:13:48 -0400 Subject: [PATCH 91/92] removed incorrect quotes from links --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 417d5769f..f499f06e7 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # The Algorithms - C++ # {#mainpage} -[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/C-Plus-Plus) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/TheAlgorithms/C-Plus-Plus.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/TheAlgorithms/C-Plus-Plus/context:cpp) +[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/C-Plus-Plus) +[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/TheAlgorithms/C-Plus-Plus.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/TheAlgorithms/C-Plus-Plus/context:cpp) [![Gitter chat](https://img.shields.io/badge/Chat-Gitter-ff69b4.svg?label=Chat&logo=gitter&style=flat-square)](https://gitter.im/TheAlgorithms) -[![contributions welcome](https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square)]("https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md") +[![contributions welcome](https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square)](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md) ![GitHub repo size](https://img.shields.io/github/repo-size/TheAlgorithms/C-Plus-Plus?color=red&style=flat-square) -[![Doxygen CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Doxygen%20CI/badge.svg)]("https://TheAlgorithms.github.io/C-Plus-Plus") -[![Awesome CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Awesome%20CI%20Workflow/badge.svg)]("https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22") +[![Doxygen CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Doxygen%20CI/badge.svg)](https://TheAlgorithms.github.io/C-Plus-Plus) +[![Awesome CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Awesome%20CI%20Workflow/badge.svg)](https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22) ## Overview From f87bc251b918cd4674f50ac55185588ceaab078f Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 28 Jun 2020 09:14:41 -0400 Subject: [PATCH 92/92] fix link to contributors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f499f06e7..d19ac813d 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The repository is a collection of open-source implementation of a variety of alg [Online Documentation](https://TheAlgorithms.github.io/C-Plus-Plus) is generated from the repository source codes directly. The documentation contains all resources including source code snippets, details on execution of the programs, diagrammatic representation of program flow, and links to external resources where necessary. The documentation also introduces interactive source code with links to documentation for C++ STL library functions used. Click on [Files menu](https://TheAlgorithms.github.io/C-Plus-Plus/files.html) to see the list of all the files documented with the code. -[Documentation of Algorithms in C++](https://thealgorithms.github.io/C-Plus-Plus) by [The Algorithms Contributors](https://github.com/TheAlgorithms) is licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1)
+[Documentation of Algorithms in C++](https://thealgorithms.github.io/C-Plus-Plus) by [The Algorithms Contributors](https://github.com/TheAlgorithms/C-Plus-Plus/graphs/contributors) is licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1)
Creative Commons LicenseCredit must be given to the creatorAdaptations must be shared under the same terms ## Contributions