Commit 1b9abf80 authored by ralfh's avatar ralfh

New homework codes for MatrixBlocks and MatrixReduce

parent 36afabbc
#ifndef MATRIXBLOCK_HPP
#define MATRIXBLOCK_HPP
// The purpose of this exercise is introduce block operations on Eigen matrices.
// TO DO: Include the appropriate header files.
// START
#include <Eigen/Dense>
// END
// We can use the Eigen namespace to improve the readability of our code.
// This allows us to skip the "Eigen::" in "Eigen::MatrixXd" for example.
// TO DO: Add the following line below: using namespace Eigen;
// START
using namespace Eigen;
// END
MatrixXd zero_row_col( MatrixXd A, int p, int q ){
/*
* This function takes a matrix A, and returns a matrix that is exactly the same,
* except that row p and column q are set to zero.
*/
// We can use .rows() and .cols() to get the number of rows and columns in A.
int rows = A.rows();
int cols = A.cols();
VectorXd v;
VectorXd u;
// TO DO: Initialize u and v with zeros, and make sure they are of the appropriate sizes.
// START
u = VectorXd::Zero(cols);
v = VectorXd::Zero(rows);
// END
// We can access rows and columns of A by A.row() and A.col().
A.row(p) = u;
A.col(q) = v;
// Question: Have we now changed the matrix that was passed as an argument to this function,
// or is A a copy of that matrix?
return A;
}
MatrixXd swap_left_right_blocks( MatrixXd A, int p ){
/*
* Writing as a block matrix A = [B C], where B denotes the first p columns of A,
* and C denotes the q=(A.cols() - p) last columns, this functions returns D = [C B].
*/
MatrixXd B, C;
int q = A.cols() - p;
// A.block( i, j, m, n ) returns the m by n block that has its top-left corner at the index (i,j) in A.
// Hence, the first p columns of A can be accessed in the following way:
B = A.block( 0, 0, A.rows(), p );
// TO DO: Use A.block() to define C as the matrix containing the last q columns of A.
// START
C = A.block( 0, p, A.rows(), q );
// END
// The block() method can access arbitrary blocks within a matrix.
// For our purposes, it is actually simpler to use leftCols() and rightCols().
A.leftCols( q ) = C;
// TO DO: Use A.rightCols() to fill in the remaining columns of the new matrix A.
// START
A.rightCols( p ) = B;
// END
// Tip: Many more methods exist that are special cases of block(),
// e.g. topRows(), bottomRows(), topLeftCorner(), bottomLeftCorner(), ...
// For vectors we have head(), tail(), and segment().
return A;
}
MatrixXd tridiagonal( int n, double a, double b, double c){
/*
* This function creates an n by n tridiagonal matrix with the values
* a on the subdiagonal,
* b on the diagonal, and
* c on the superdiagonal.
* Example for n=5:
* [ b c 0 0 0 ]
* [ a b c 0 0 ]
* A = [ 0 a b c 0 ]
* [ 0 0 a b c ]
* [ 0 0 0 a b ]
*/
MatrixXd A;
// TO DO: Fill the matrix A with zeros. Then fill the subdiagonal with the value a, the diagonal with b and the superdiagonal with c.
// Hint: You can get the diagonal of A by A.diagonal(). Moreover, you can get the super- and subdiagonals by passing +1 or -1 as arguments to A.diagonal().
// START
A = MatrixXd::Zero(n,n);
A.diagonal(-1) = VectorXd::Constant(n-1,a);
A.diagonal() = VectorXd::Constant(n,b);
A.diagonal(1) = VectorXd::Constant(n-1,c);
// END
return A;
}
#endif
# Code Expert Generic Project Configuration.
#
# In case this file is omitted, the execution is done with the default values.
# You can either define a cmd or a script file to be executed.
# Default to script file setting a cmd overrides it.
cmd:
# compile: echo "COMPILE"
# run: echo "RUN"
# test: echo "TEST"
# submit: echo "SUBMIT"
# All scripts are set by default to "/scripts/${ACTION}.sh"
script:
compile: /scripts/compile.sh
run: /scripts/run.sh
test: /scripts/test.sh
submit: /scripts/submit.sh
\ No newline at end of file
descriptions:
default:
name: Default
default: true
# Optionally add mulitple versions here.
# Use the file name without the .md extension as key and add a `name:` to it.
\ No newline at end of file
# Tutorial: part 2/3
## Matrix blocks
> Eigen matrices have a range of methods to access their submatrices (blocks), instead of individual entries at a time.Suppose A is an Eigen::MatrixXd object, then a few useful methods are:
* `A.row(i)`: the i-th row of A,
* `A.col(j)`: the j-th column of A,
* `A.topRows(p)`: the first p rows of A,
* `A.leftCols(q)`: the first q columns of A,
* `A.bottomRightCorner(p,q)`: the p by q matrix formed by the intersection of the last p rows and last q columns of A, and more generally
* `A.block(i,j,p,q)`: the p by q submatrix of A, whose top-left corner is at the index (i,j).
> The purpose of this exercise is to learn to declare and initialize Eigen matrices, and to get familiar with some handy typedefs and methods.
> Open "MatrixBlocks.hpp" and fill in the missing code in between the delimiters `// START` and `// END` according to the instructions preceded by `// TO DO:`.
> Read each function of the program carefully. The code will not compile until after the first two tasks are finished, which is to include headers and set the namespace.
\ No newline at end of file
# Tests of MatrixBlocks.hpp
> There are three functions in MatrixBlocks.hpp and main.cpp has one test for each function.
***
> `zero_row_col( MatrixXd A, int p, int q )`: This function returns a copy of A with row p and column q set to zero.
The test prints `zero_row_col(Matrix3d::Constant(-1),0,1)`, and the correct result is:
```
0 0 0
-1 0 -1
-1 0 -1
```
***
> `swap_left_right_blocks( MatrixXd A, int p )`: This function swaps splits the matrix A into two blocks, the first p columns and the rest, and returns a matrix in which these blocks have been swapped.
The test prints `swap_left_right_blocks(MatrixXd::Identity(4,3),2)`, and the correct result is:
```
0 1 0
0 0 1
1 0 0
0 0 0
```
***
> `tridiagonal( int n, double a, double b, double c)`: This function creates an n by n tridiagonal matrix with constant diagonals with the values a, b, and c.
The test prints `tridiagonal(4,-1,2,-1)`, and the correct result is:
```
2 -1 0 0
-1 2 -1 0
0 -1 2 -1
0 0 -1 2
```
#include "MatrixBlocks.hpp"
#include <iostream>
int main(){
std::cout<< "\nTest of zero_row_col():\n";
Matrix3d A = Matrix3d::Constant(-1);
std::cout<< zero_row_col( A, 0, 1 ) << "\n\n";
std::cout<< "Test of swap_left_right_blocks():\n";
MatrixXd B = MatrixXd::Identity( 4, 3 );
std::cout<< swap_left_right_blocks( B, 2 ) << "\n\n";
std::cout<< "Test of tridiagonal():\n";
std::cout<<tridiagonal(4,-1,2,-1)<< "\n\n";
return 0;
}
#!/bin/bash
echo "Compiling ..."
# compile c code
# find . -iname '*.cpp' | sort | xargs g++ -fdiagnostics-color=always --pedantic -Wextra -Wall -std=c++14 -I/usr/include/python3.7m -llibpython -o bin/a.out || exit 1
# Compiling for 'matplotlibcpp.h'
mkdir -p bin
find . -iname '*.cpp' | sort | xargs \
g++ -fdiagnostics-color=always -std=c++11 \
-I/usr/local/include/python3.7m \
-I/usr/local/lib/python3.7/site-packages/numpy/core/include \
-I/usr/include/eigen3/ \
-lpython3.7m \
-lpthread -lutil -ldl \
-Xlinker -export-dynamic \
-o bin/a.out
echo "Compilation successful"
\ No newline at end of file
#!/bin/bash
export PYTHONIOENCODING="UTF-8"
# compile (call compile script)
bash "${WORKDIR}/scripts/compile.sh"
# run
bin/a.out
\ No newline at end of file
#!/bin/bash
echo "Not implemented"
\ No newline at end of file
#!/bin/bash
# run (call run script)
bash "${WORKDIR}/scripts/run.sh"
\ No newline at end of file
// "testname", "input", "expected output", "points", "execution time limit (ms)"
"zero_row_col", "(any input)", " 0 0 0\n-1 0 -1\n-1 0 -1", "1", "5000",
"swap_left_right_blocks", "(any input)", "0 1 0\n0 0 1\n1 0 0\n0 0 0", "1", "5000",
"tridiagonal", "(any input)", " 2 -1 0 0\n-1 2 -1 0\n 0 -1 2 -1\n 0 0 -1 2", "1", "5000",
#ifndef MATRIXREDUCE_HPP
#define MATRIXREDUCE_HPP
// The purpose of this exercise is introduce reduction operations.
// TO DO: Include the appropriate header files and namespaces
// START
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
// END
// Eigen matrices have a range of methods that reduce them to a single number.
// Suppose A is a MatrixXd object, then a few useful methods are:
// A.size(): the number of entries in A,
// A.sum(): the sum of all entries in A,
// A.prod(): the product of all entries in A,
// A.minCoeff(): the minimum value amongst the entries of A,
// A.maxCoeff(): the maximum value amongst the entries of A, and
// A.norm(): The (Frobenius) norm of the matrix A.
// TO DO: Write a function "average" that takes as argument a "MatrixXd" object and returns a "double".
// m = average(A) should calculate the average of the entries of A.
// START
double average( MatrixXd A ){
/*
* Calculates the average of the entries of A
*/
double m;
m = A.sum()/A.size();
return m;
}
// END
// Question: is there a reduction method that returns the average of A directly?
double percent_zero( MatrixXd A ){
/*
* Calculates how many entries of A are exactly equal to zero,
* as a percentage of the total number of entries.
*/
// Eigen provides an Array class, that is similar to Matrix,
// but has operations that are entry-wise rather than linear algebra operations.
// For example, multiplying two Arrays is entry-wise multiplication, and not matrix multiplication.
ArrayXXd Arr(A);
// The benefit of using an Array here is that we can do entry-wise boolean comparison,
// which is not available for matrices.
int zeros = (Arr == 0).count();
double ratio;
// TO DO: Calculate the ratio of zero entries.
// START
ratio = ((double) zeros)/A.size();
// END
return ratio*100;
}
int has_zero_column( MatrixXd A ){
/*
* Returns 1 if A has a column that is exactly equal to zero.
* Returns 0 otherwise.
*/
int result;
// A vector is the zero vector if and only if it has norm 0.
// The following vector contains the squared norms of the columns of A.
VectorXd norms = A.colwise().squaredNorm();
// The norm is 0 if and only if the norm squared is zero.
// We use squaredNorm() instead of norm(), because norm() = sqrt(squaredNorm())
// calculates a square root that is not necessary for our purposes.
// TO DO: Check if any one of the norms is equal to zero.
// Hint: Use an ArrayXd and entry-wise comparison.
// START
ArrayXd Arr(norms);
result = (Arr == 0).any();
// END
return result;
}
MatrixXd columns_sum_to_zero( MatrixXd A ){
/*
* Returns a matrix that is like A, but the entries on the diagonal
* have been changed so that the sum of the columns is equal to 0.
*/
MatrixXd B(A);
// TO DO: Replace the diagonal of B with values such that the columns of B sum up to zero.
// Hint: Use diagonal(), rowwise(), and sum().
// START
int p = std::min(B.rows(),B.cols());
B.diagonal() = VectorXd::Zero(p);
B.diagonal() = -B.rowwise().sum();
// END
return B;
}
#endif
# Code Expert Generic Project Configuration.
#
# In case this file is omitted, the execution is done with the default values.
# You can either define a cmd or a script file to be executed.
# Default to script file setting a cmd overrides it.
cmd:
# compile: echo "COMPILE"
# run: echo "RUN"
# test: echo "TEST"
# submit: echo "SUBMIT"
# All scripts are set by default to "/scripts/${ACTION}.sh"
script:
compile: /scripts/compile.sh
run: /scripts/run.sh
test: /scripts/test.sh
submit: /scripts/submit.sh
\ No newline at end of file
descriptions:
default:
name: Default
default: true
# Optionally add mulitple versions here.
# Use the file name without the .md extension as key and add a `name:` to it.
\ No newline at end of file
# Tutorial: part 3/3
## Matrix reductions
> Eigen matrices have a range of methods that reduce them to a single number. Suppose A is an Eigen::MatrixXd object, then a few useful methods are:
* `A.size()`: the number of entries in A,
* `A.sum()`: the sum of all entries in A,
* `A.prod()`: the product of all entries in A,
* `A.minCoeff()`: the minimum value amongst the entries of A,
* `A.maxCoeff()`: the maximum value amongst the entries of A, and
* `A.norm()`: The (Frobenius) norm of the matrix A.
> The [Eigen::Array class](https://eigen.tuxfamily.org/dox/group__TutorialArrayClass.html) is also featured in this exercise to perform coefficient-wise comparison.
> Open "MatrixReduce.hpp" and fill in the missing code in between the delimiters `// START` and `// END` according to the instructions preceded by `// TO DO:`.
> Read each function of the program carefully. The code will not compile until after the first two tasks are finished, which is to include headers, set the namespace, and write the average() function.
\ No newline at end of file
# Tests of MatrixReduction.hpp
> There are four functions in MatrixReduction.hpp and main.cpp has one test for each function.
***
> `average( MatrixXd A )`: This function should calculate the average of the entries in A.
The test prints `average(Matrix3d::Identity())`, and the correct result is:
```
0.333333
```
***
> `percent_zero( MatrixXd A )`: This function calculates the percentage of entries in A that are exactly equal to zero.
The test prints `percent_zero(Matrix3d::Identity())`, and the correct result is:
```
66.6667
```
***
> `has_zero_column( MatrixXd A )`: This function checks if any one of the columns in A is equal to zero.
The test prints
`has_zero_column(B)` followed by `has_zero_column(B.transpose())` where `B=MatrixXd::Identity(4,5)`, and the correct result is:
```
1 0
```
***
> `columns_sum_to_zero( MatrixXd A )`: This functions returns a copy of A, except that the diagonal entries have been changed in a way such that the columns of the new matrix sum to zero.
The test prints `columns_sum_to_zero(C)` where `C=Matrix3d::Random()+Matrix3d::Constant(1)` (the random seed is fixed), and the correct result is:
```
-0.721194 0.160061 0.561133
0.0929355 -0.989846 0.896911
1.98551 0.159289 -2.1448
```
#include "MatrixReduce.hpp"
#include <iostream>
int main(){
std::cout<< "\nTest of average():\n";
Matrix3d A = Matrix3d::Identity();
std::cout<< average( A ) << "\n\n";
std::cout<< "Test of percent_zero():\n";
std::cout<< percent_zero( A ) << "\n\n";
std::cout<< "Test of has_zero_column():\n";
MatrixXd B = MatrixXd::Identity(4,5);
std::cout<< has_zero_column( B ) << " " << has_zero_column( B.transpose() ) << "\n\n";
std::cout<< "Test of columns_sum_to_zero():\n";
std::srand(5); // So that random behaviour is predictable.
Matrix3d C = Matrix3d::Random() + Matrix3d::Constant(1);
std::cout<< columns_sum_to_zero( C ) << "\n\n";
return 0;
}
#!/bin/bash
echo "Compiling ..."
# compile c code
# find . -iname '*.cpp' | sort | xargs g++ -fdiagnostics-color=always --pedantic -Wextra -Wall -std=c++14 -I/usr/include/python3.7m -llibpython -o bin/a.out || exit 1
# Compiling for 'matplotlibcpp.h'
mkdir -p bin
find . -iname '*.cpp' | sort | xargs \
g++ -fdiagnostics-color=always -std=c++11 \
-I/usr/local/include/python3.7m \
-I/usr/local/lib/python3.7/site-packages/numpy/core/include \
-I/usr/include/eigen3/ \
-lpython3.7m \
-lpthread -lutil -ldl \
-Xlinker -export-dynamic \
-o bin/a.out
echo "Compilation successful"
\ No newline at end of file
#!/bin/bash
export PYTHONIOENCODING="UTF-8"
# compile (call compile script)
bash "${WORKDIR}/scripts/compile.sh"
# run
bin/a.out
\ No newline at end of file
#!/bin/bash
echo "Not implemented"
\ No newline at end of file
#!/bin/bash
# run (call run script)
bash "${WORKDIR}/scripts/run.sh"
\ No newline at end of file
// "testname", "input", "expected output", "points", "execution time limit (ms)"
"average", "(any input)", "0.333333", "1", "5000",
"percent_zero", "(any input)", "66.6667", "1", "5000",
"has_zero_column", "(any input)", "1 0", "1", "5000",
"columns_sum_to_zero", "(any input)", "-0.721194 0.160061 0.561133\n0.0929355 -0.989846 0.896911\n 1.98551 0.159289 -2.1448", "1", "5000",
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment