Gauss-Jordan matrix inversion: Difference between revisions
Content added Content deleted
m (Minor edit to Java code) |
m (Moved C++ after C#) |
||
Line 217: | Line 217: | ||
0.02413 0.05669 0.12579 0.06824 -0.21726 |
0.02413 0.05669 0.12579 0.06824 -0.21726 |
||
</pre> |
</pre> |
||
=={{header|ALGOL 60}}== |
=={{header|ALGOL 60}}== |
||
Line 304: | Line 303: | ||
1 0 -2 4 |
1 0 -2 4 |
||
4 1 2 2 |
4 1 2 2 |
||
</pre> |
|||
=={{header|C++}}== |
|||
<lang cpp>#include <algorithm> |
|||
#include <cassert> |
|||
#include <iomanip> |
|||
#include <iostream> |
|||
#include <vector> |
|||
template <typename scalar_type> class matrix { |
|||
public: |
|||
matrix(size_t rows, size_t columns) |
|||
: rows_(rows), columns_(columns), elements_(rows * columns) {} |
|||
matrix(size_t rows, size_t columns, scalar_type value) |
|||
: rows_(rows), columns_(columns), elements_(rows * columns, value) {} |
|||
matrix(size_t rows, size_t columns, std::initializer_list<scalar_type> values) |
|||
: rows_(rows), columns_(columns), elements_(rows * columns) { |
|||
assert(values.size() <= rows_ * columns_); |
|||
std::copy(values.begin(), values.end(), elements_.begin()); |
|||
} |
|||
size_t rows() const { return rows_; } |
|||
size_t columns() const { return columns_; } |
|||
scalar_type& operator()(size_t row, size_t column) { |
|||
assert(row < rows_); |
|||
assert(column < columns_); |
|||
return elements_[row * columns_ + column]; |
|||
} |
|||
const scalar_type& operator()(size_t row, size_t column) const { |
|||
assert(row < rows_); |
|||
assert(column < columns_); |
|||
return elements_[row * columns_ + column]; |
|||
} |
|||
private: |
|||
size_t rows_; |
|||
size_t columns_; |
|||
std::vector<scalar_type> elements_; |
|||
}; |
|||
template <typename scalar_type> |
|||
matrix<scalar_type> product(const matrix<scalar_type>& a, |
|||
const matrix<scalar_type>& b) { |
|||
assert(a.columns() == b.rows()); |
|||
size_t arows = a.rows(); |
|||
size_t bcolumns = b.columns(); |
|||
size_t n = a.columns(); |
|||
matrix<scalar_type> c(arows, bcolumns); |
|||
for (size_t i = 0; i < arows; ++i) { |
|||
for (size_t j = 0; j < n; ++j) { |
|||
for (size_t k = 0; k < bcolumns; ++k) |
|||
c(i, k) += a(i, j) * b(j, k); |
|||
} |
|||
} |
|||
return c; |
|||
} |
|||
template <typename scalar_type> |
|||
void swap_rows(matrix<scalar_type>& m, size_t i, size_t j) { |
|||
size_t columns = m.columns(); |
|||
for (size_t column = 0; column < columns; ++column) |
|||
std::swap(m(i, column), m(j, column)); |
|||
} |
|||
// Convert matrix to reduced row echelon form |
|||
template <typename scalar_type> |
|||
void rref(matrix<scalar_type>& m) { |
|||
size_t rows = m.rows(); |
|||
size_t columns = m.columns(); |
|||
for (size_t row = 0, lead = 0; row < rows && lead < columns; ++row, ++lead) { |
|||
size_t i = row; |
|||
while (m(i, lead) == 0) { |
|||
if (++i == rows) { |
|||
i = row; |
|||
if (++lead == columns) |
|||
return; |
|||
} |
|||
} |
|||
swap_rows(m, i, row); |
|||
if (m(row, lead) != 0) { |
|||
scalar_type f = m(row, lead); |
|||
for (size_t column = 0; column < columns; ++column) |
|||
m(row, column) /= f; |
|||
} |
|||
for (size_t j = 0; j < rows; ++j) { |
|||
if (j == row) |
|||
continue; |
|||
scalar_type f = m(j, lead); |
|||
for (size_t column = 0; column < columns; ++column) |
|||
m(j, column) -= f * m(row, column); |
|||
} |
|||
} |
|||
} |
|||
template <typename scalar_type> |
|||
matrix<scalar_type> inverse(const matrix<scalar_type>& m) { |
|||
assert(m.rows() == m.columns()); |
|||
size_t rows = m.rows(); |
|||
matrix<scalar_type> tmp(rows, 2 * rows, 0); |
|||
for (size_t row = 0; row < rows; ++row) { |
|||
for (size_t column = 0; column < rows; ++column) |
|||
tmp(row, column) = m(row, column); |
|||
tmp(row, row + rows) = 1; |
|||
} |
|||
rref(tmp); |
|||
matrix<scalar_type> inv(rows, rows); |
|||
for (size_t row = 0; row < rows; ++row) { |
|||
for (size_t column = 0; column < rows; ++column) |
|||
inv(row, column) = tmp(row, column + rows); |
|||
} |
|||
return inv; |
|||
} |
|||
template <typename scalar_type> |
|||
void print(std::ostream& out, const matrix<scalar_type>& m) { |
|||
size_t rows = m.rows(), columns = m.columns(); |
|||
out << std::fixed << std::setprecision(4); |
|||
for (size_t row = 0; row < rows; ++row) { |
|||
for (size_t column = 0; column < columns; ++column) { |
|||
if (column > 0) |
|||
out << ' '; |
|||
out << std::setw(7) << m(row, column); |
|||
} |
|||
out << '\n'; |
|||
} |
|||
} |
|||
int main() { |
|||
matrix<double> m(3, 3, {2, -1, 0, -1, 2, -1, 0, -1, 2}); |
|||
std::cout << "Matrix:\n"; |
|||
print(std::cout, m); |
|||
auto inv(inverse(m)); |
|||
std::cout << "Inverse:\n"; |
|||
print(std::cout, inv); |
|||
std::cout << "Product of matrix and inverse:\n"; |
|||
print(std::cout, product(m, inv)); |
|||
std::cout << "Inverse of inverse:\n"; |
|||
print(std::cout, inverse(inv)); |
|||
return 0; |
|||
}</lang> |
|||
{{out}} |
|||
<pre> |
|||
Matrix: |
|||
2.0000 -1.0000 0.0000 |
|||
-1.0000 2.0000 -1.0000 |
|||
0.0000 -1.0000 2.0000 |
|||
Inverse: |
|||
0.7500 0.5000 0.2500 |
|||
0.5000 1.0000 0.5000 |
|||
0.2500 0.5000 0.7500 |
|||
Product of matrix and inverse: |
|||
1.0000 0.0000 0.0000 |
|||
-0.0000 1.0000 -0.0000 |
|||
0.0000 0.0000 1.0000 |
|||
Inverse of inverse: |
|||
2.0000 -1.0000 0.0000 |
|||
-1.0000 2.0000 -1.0000 |
|||
0.0000 -1.0000 2.0000 |
|||
</pre> |
</pre> |
||
Line 682: | Line 519: | ||
-0.695652173913043 0.36231884057971 0.0797101449275362 0.195652173913043 |
-0.695652173913043 0.36231884057971 0.0797101449275362 0.195652173913043 |
||
-0.565217391304348 0.231884057971014 -0.0289855072463768 0.565217391304348 |
-0.565217391304348 0.231884057971014 -0.0289855072463768 0.565217391304348 |
||
</pre> |
|||
=={{header|C++}}== |
|||
<lang cpp>#include <algorithm> |
|||
#include <cassert> |
|||
#include <iomanip> |
|||
#include <iostream> |
|||
#include <vector> |
|||
template <typename scalar_type> class matrix { |
|||
public: |
|||
matrix(size_t rows, size_t columns) |
|||
: rows_(rows), columns_(columns), elements_(rows * columns) {} |
|||
matrix(size_t rows, size_t columns, scalar_type value) |
|||
: rows_(rows), columns_(columns), elements_(rows * columns, value) {} |
|||
matrix(size_t rows, size_t columns, std::initializer_list<scalar_type> values) |
|||
: rows_(rows), columns_(columns), elements_(rows * columns) { |
|||
assert(values.size() <= rows_ * columns_); |
|||
std::copy(values.begin(), values.end(), elements_.begin()); |
|||
} |
|||
size_t rows() const { return rows_; } |
|||
size_t columns() const { return columns_; } |
|||
scalar_type& operator()(size_t row, size_t column) { |
|||
assert(row < rows_); |
|||
assert(column < columns_); |
|||
return elements_[row * columns_ + column]; |
|||
} |
|||
const scalar_type& operator()(size_t row, size_t column) const { |
|||
assert(row < rows_); |
|||
assert(column < columns_); |
|||
return elements_[row * columns_ + column]; |
|||
} |
|||
private: |
|||
size_t rows_; |
|||
size_t columns_; |
|||
std::vector<scalar_type> elements_; |
|||
}; |
|||
template <typename scalar_type> |
|||
matrix<scalar_type> product(const matrix<scalar_type>& a, |
|||
const matrix<scalar_type>& b) { |
|||
assert(a.columns() == b.rows()); |
|||
size_t arows = a.rows(); |
|||
size_t bcolumns = b.columns(); |
|||
size_t n = a.columns(); |
|||
matrix<scalar_type> c(arows, bcolumns); |
|||
for (size_t i = 0; i < arows; ++i) { |
|||
for (size_t j = 0; j < n; ++j) { |
|||
for (size_t k = 0; k < bcolumns; ++k) |
|||
c(i, k) += a(i, j) * b(j, k); |
|||
} |
|||
} |
|||
return c; |
|||
} |
|||
template <typename scalar_type> |
|||
void swap_rows(matrix<scalar_type>& m, size_t i, size_t j) { |
|||
size_t columns = m.columns(); |
|||
for (size_t column = 0; column < columns; ++column) |
|||
std::swap(m(i, column), m(j, column)); |
|||
} |
|||
// Convert matrix to reduced row echelon form |
|||
template <typename scalar_type> |
|||
void rref(matrix<scalar_type>& m) { |
|||
size_t rows = m.rows(); |
|||
size_t columns = m.columns(); |
|||
for (size_t row = 0, lead = 0; row < rows && lead < columns; ++row, ++lead) { |
|||
size_t i = row; |
|||
while (m(i, lead) == 0) { |
|||
if (++i == rows) { |
|||
i = row; |
|||
if (++lead == columns) |
|||
return; |
|||
} |
|||
} |
|||
swap_rows(m, i, row); |
|||
if (m(row, lead) != 0) { |
|||
scalar_type f = m(row, lead); |
|||
for (size_t column = 0; column < columns; ++column) |
|||
m(row, column) /= f; |
|||
} |
|||
for (size_t j = 0; j < rows; ++j) { |
|||
if (j == row) |
|||
continue; |
|||
scalar_type f = m(j, lead); |
|||
for (size_t column = 0; column < columns; ++column) |
|||
m(j, column) -= f * m(row, column); |
|||
} |
|||
} |
|||
} |
|||
template <typename scalar_type> |
|||
matrix<scalar_type> inverse(const matrix<scalar_type>& m) { |
|||
assert(m.rows() == m.columns()); |
|||
size_t rows = m.rows(); |
|||
matrix<scalar_type> tmp(rows, 2 * rows, 0); |
|||
for (size_t row = 0; row < rows; ++row) { |
|||
for (size_t column = 0; column < rows; ++column) |
|||
tmp(row, column) = m(row, column); |
|||
tmp(row, row + rows) = 1; |
|||
} |
|||
rref(tmp); |
|||
matrix<scalar_type> inv(rows, rows); |
|||
for (size_t row = 0; row < rows; ++row) { |
|||
for (size_t column = 0; column < rows; ++column) |
|||
inv(row, column) = tmp(row, column + rows); |
|||
} |
|||
return inv; |
|||
} |
|||
template <typename scalar_type> |
|||
void print(std::ostream& out, const matrix<scalar_type>& m) { |
|||
size_t rows = m.rows(), columns = m.columns(); |
|||
out << std::fixed << std::setprecision(4); |
|||
for (size_t row = 0; row < rows; ++row) { |
|||
for (size_t column = 0; column < columns; ++column) { |
|||
if (column > 0) |
|||
out << ' '; |
|||
out << std::setw(7) << m(row, column); |
|||
} |
|||
out << '\n'; |
|||
} |
|||
} |
|||
int main() { |
|||
matrix<double> m(3, 3, {2, -1, 0, -1, 2, -1, 0, -1, 2}); |
|||
std::cout << "Matrix:\n"; |
|||
print(std::cout, m); |
|||
auto inv(inverse(m)); |
|||
std::cout << "Inverse:\n"; |
|||
print(std::cout, inv); |
|||
std::cout << "Product of matrix and inverse:\n"; |
|||
print(std::cout, product(m, inv)); |
|||
std::cout << "Inverse of inverse:\n"; |
|||
print(std::cout, inverse(inv)); |
|||
return 0; |
|||
}</lang> |
|||
{{out}} |
|||
<pre> |
|||
Matrix: |
|||
2.0000 -1.0000 0.0000 |
|||
-1.0000 2.0000 -1.0000 |
|||
0.0000 -1.0000 2.0000 |
|||
Inverse: |
|||
0.7500 0.5000 0.2500 |
|||
0.5000 1.0000 0.5000 |
|||
0.2500 0.5000 0.7500 |
|||
Product of matrix and inverse: |
|||
1.0000 0.0000 0.0000 |
|||
-0.0000 1.0000 -0.0000 |
|||
0.0000 0.0000 1.0000 |
|||
Inverse of inverse: |
|||
2.0000 -1.0000 0.0000 |
|||
-1.0000 2.0000 -1.0000 |
|||
0.0000 -1.0000 2.0000 |
|||
</pre> |
</pre> |
||