Skip to content

Commit

Permalink
import
Browse files Browse the repository at this point in the history
  • Loading branch information
rupertnash committed Mar 10, 2024
0 parents commit 3a4d680
Show file tree
Hide file tree
Showing 129 changed files with 12,003 additions and 0 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Modern C++ for Computational Scientists

Repository view: <https://github.com/EPCCed/APT-CPP>

Pages view: <https://EPCCed.github.io/APT-CPP/>

Since the 2011 revision to the C++ language and standard library, the
ways it is now being used are quite different. Used well, these
features enable the programmer to write elegant, reusable and portable
code that runs efficiently on a variety of architectures.

However it is still a very large and complex tool. This set of
lectures and practical exercises, will cover a minimal set of features
to allow an experienced non-C++ programmer to get to grips with
language. These include:
* defining your own types
* overloading
* templates
* containers
* iterators
* lambdas
* standard algorithms
* threading

It concludes with a brief discussion of modern frameworks for portable
parallel performance which are commonly implemented in C++.

* [Lectures](lectures/)
* [Practical exercises](exercises/)
13 changes: 13 additions & 0 deletions exercises/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# C++ exercise

Practical exercises for C++ course

See each subdirectory for further instructions

* [Complex numbers](complex/)
* [Containers](containers/)
* [Morton-order matrix class template](morton-order/)
* [Using algorithms](algorithm/)
* [Eigen](eigen/)
* [Simple use of threads](threads/)
* [Portable performance with Kokkos](kokkos/)
4 changes: 4 additions & 0 deletions exercises/algorithm/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CXXFLAGS = --std=c++17
CC = $(CXX)

ex : ex.o
12 changes: 12 additions & 0 deletions exercises/algorithm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Algorithm use exercise

In the file `ex.cpp` there is an incomplete program which, by
following the instructions in the comments, you can finish.

You will likely want to refer to the documentation of the standard
library algorithms, which, for reasons, are split across two headers:

- <https://en.cppreference.com/w/cpp/algorithm>

- <https://en.cppreference.com/w/cpp/numeric#Numeric_algorithms>

91 changes: 91 additions & 0 deletions exercises/algorithm/ex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include <algorithm>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <numeric>
#include <vector>

void print_vec(std::vector<int> &vec) {
for (auto &el : vec) {
std::cout << el << " ";
}
std::cout << std::endl << std::endl;
}

int main(int argc, char* argv[]) {
// First, a warmup of basic algorithm usage
auto nums = std::vector<int>(50);

// let's initalize our vector with some random numbers
for (int i = 0; i < 50; ++i) {
nums[i] = std::rand() % 100;
}

// Bonus: can we do this using the algorithms library? Hint - std::generate
// and use the following lambda
auto gen = []() { return std::rand() % 100; };

// Your code here....

// Now, sort nums.

// Your code here....

std::cout << "Sorted nums: ";
print_vec(nums);
// Reverse sort nums, using (a) sort on its own and (b) using sort and another
// algorithm function

// Your code here....

std::cout << "Reverse sorted nums (a): ";
print_vec(nums);

// Your code here....

std::cout << "Reverse sorted nums (b): ";
print_vec(nums);

// Now, lets look at a more involved example. We'll be working through Project
// Euler No.2 (https://projecteuler.net/problem=2) "By considering the terms in
// the Fibonacci sequence whose values do not exceed four million, find the sum
// of the even-valued terms"

// First lets get the fist 47 fibonacci numbers
// BONUS: use std::transform

auto fibs = std::vector<int>(47);

// Your code here....


print_vec(fibs);

// Next, get all that are less than or equal to 4 million, and store them in
// fibs_less HINT: use std::copy_if and std::back_inserter

auto fibs_less = std::vector<int>();

// Your code here....

std::cout << "fibs <= 4000000: ";
print_vec(fibs_less);

// Now, get the evens. Use the same approach as above
auto evens = std::vector<int>();

// Your code here....


std::cout << "Evens: ";
print_vec(evens);

// Finally, let's sum them (hint: std::accumulate)

int sum = 0;

std::cout << "Sum of even fibonacci numbers not greater than 4 million: "
<< sum << std::endl;

return 0;
}
15 changes: 15 additions & 0 deletions exercises/complex/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CXXFLAGS = --std=c++17 -I../include

test : complex.o test.o
$(CXX) $^ -o $@

test.o : catch.hpp

catch.hpp :
wget https://github.com/catchorg/Catch2/releases/download/v2.13.6/catch.hpp

run : test
./test

clean :
rm -rf *.o test
3 changes: 3 additions & 0 deletions exercises/complex/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This document is available in multiple formats:
* [PDF](instructions.pdf)
* [Markdown](instructions.md)
44 changes: 44 additions & 0 deletions exercises/complex/complex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "complex.hpp"
#include <cmath>



double const& Complex::real() {
return re;
}

double Complex::imag() const {
return im;
}

Complex Complex::conj() const {
return Complex{re, -im};
}

double Complex::norm() const {
return std::sqrt(norm2());
}

double Complex::norm2() const {
return re*re + im*im;
}

bool operator==(Complex const& a, Complex const& b) {
return (a.re == b.re) && (a.im == b.re);
}
bool operator!=(Complex const& a, Complex const& b) {
return !(a == b);
}

Complex operator+(Complex const& a, Complex const& b) {
return Complex{a.re + b.re, a.im + b.im};
}


Complex operator*(Complex const& a, Complex const& b) {
// (a + ib)*(c + id) == (a*c - b*d) + i(b*c + a*d)
}

Complex operator-(Complex const& a) {
return Complex{-a.re, -a.im};
}
43 changes: 43 additions & 0 deletions exercises/complex/complex.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef CPPEX_COMPLEX_COMPLEX_HPP
#define CPPEX_COMPLEX_COMPLEX_HPP

// Simple complex number class
class Complex {
public:
// Default value is zero
Complex() = default;
// Construct purely real complex
// Construct from real and imaginary parts

// Access components
double real() const;
double imag() const;

// Compute the complex conjugate
Complex conj();

// Compute the magnitude and squared magnitude
double norm() const;
double norm2() const;

// Declare comparisons
friend bool operator==(Complex const& a, Complex const& b);
friend bool operator!=(Complex const& a, Complex const& b);

// Declare binary arithmetic operators
friend Complex operator+(Complex const& a, Complex const& b);
friend Complex operator-(Complex const& a, Complex const& b);
friend Complex operator*(Complex const& a, Complex const& b);
friend Complex operator/(Complex const& a, Complex const& b);
// Question: how would you declare multiplication and division by a real number?

// Unary negation
friend Complex operator-(Complex const& a);

private:
double re = 0.0;
double im = 0.0;
};


#endif
32 changes: 32 additions & 0 deletions exercises/complex/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Introductory C++ exercises
## Rupert Nash
## [email protected]

The files for this are on [Github](https://github.com/EPCCed/APT-CPP).

To check out the repository run:

```bash
git clone https://github.com/EPCCed/APT-CPP
cd APT-CPP/exercises/complex
```

## Task

You have been provided with a simple, *partial* implementation of a complex number class and an associated test program. Your task is to alter the complex.cpp/complex.hpp files until the tests compile and run correctly! (Please don't edit the test.cpp program!). To compile, you need a C++17 capable compiler - on Cirrus the default `gcc` module is fine - then just use `make`.

This initial program fails:

```bash
$ module load gcc
$ make
c++ --std=c++17 -I../include -c -o complex.o complex.cpp
complex.cpp:6:24: error: out-of-line definition of 'real' does not match any declaration in 'Complex'
double const& Complex::real() {
^~~~
./complex.hpp:13:10: note: member declaration does not match because it is const qualified
double real() const;

```
You need to start tracking down the bugs and fixing them.
Binary file added exercises/complex/instructions.pdf
Binary file not shown.
95 changes: 95 additions & 0 deletions exercises/complex/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Catch2 is a unit testing library
// Here we let it create a main() function for us
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

#include "complex.hpp"

TEST_CASE("Complex numbers are constructed real/imag parts readable") {
const Complex zero;
REQUIRE(zero.real() == 0.0);
REQUIRE(zero.imag() == 0.0);

const Complex one{1.0};
REQUIRE(one.real() == 1.0);
REQUIRE(one.imag() == 0.0);

const Complex i{0, 1};
REQUIRE(i.real() == 0.0);
REQUIRE(i.imag() == 1.0);

const Complex z1{1, -83};
const Complex z2 = z1;
REQUIRE(i.real() == 0.0);
REQUIRE(i.imag() == 1.0);
}

TEST_CASE("Complex numbers can be compared") {
const Complex zero;
const Complex one{1.0};
const Complex i{0, 1};
REQUIRE(zero == zero);
REQUIRE(one == one);
REQUIRE(i == i);
REQUIRE(zero != one);
REQUIRE(one != i);
}

TEST_CASE("Complex numbers can have magnitude computed") {
REQUIRE(Complex{}.norm2() == 0.0);
REQUIRE(Complex{3,4}.norm2() == 25.0);
}

// Pure real => z == z*
void CheckConjReal(double x) {
Complex z{x};
REQUIRE(z == z.conj());
}
// Pure imaginary => z* == -z
void CheckConjImag(double y) {
Complex z{0.0, y};

REQUIRE(z == -z.conj());
}

TEST_CASE("Complex numbers be conjugated") {
CheckConjReal(0);
CheckConjReal(1);
CheckConjReal(-3.14);
CheckConjReal(1.876e6);

CheckConjImag(0);
CheckConjImag(1);
CheckConjImag(-3.14);
CheckConjImag(1.876e6);
}

void CheckZplusZeq2Z(const Complex& z) {
REQUIRE(z + z == Complex{2*z.real(), 2*z.imag()});
}
void CheckZminusZeq0(const Complex& z) {
REQUIRE(z - z == Complex{});
}

TEST_CASE("Complex number can be added and subtracted") {
CheckZplusZeq2Z(1);
CheckZplusZeq2Z(0);
CheckZplusZeq2Z(-1);

CheckZminusZeq0(1);
CheckZminusZeq0(0);
CheckZminusZeq0(-1);
CheckZminusZeq0(Complex{1,2});
CheckZminusZeq0(Complex{-42, 1e-3});
}

TEST_CASE("Complex numbers can be multiplied") {
const Complex i{0, 1};
Complex z{1};
z = z*i;
REQUIRE(z == i);
z = z*i;
REQUIRE(z == Complex{-1});
z = z*i;
REQUIRE(z == -i);
}
Loading

0 comments on commit 3a4d680

Please sign in to comment.