<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

# Testing and debugging: Linear Algebra Project


Today's [assignment](https://classroom.github.com/a/bPzYrXVA).

## Linear algebra project in C

Today we'll start working on yet another toy project, but it's getting a bit
more realistic. This work (as it expands over the next couple of classes) has
multiple objectives:

- Get some practice with cmake and C / C++.

- Understand some basic ideas behind object-oriented programming, and learn
  about structuring your code.

- Learn some of the ideas behind C++ and how it makes things "prettier" than C.

- Understand how multi-dimensional arrays work.

There is rather little in terms of (detailed) instructions today. So you'll have
to use whatever resources are available to you (prior knowledge, notes from
previous clases, your team members, your friendly instructor, discord, google, AI,
whatever...)

### First steps

(Nothing is really new here, but I'll repeat it here as a checklist which might
be useful for future reference until the process becomes natural.)

- Sign up for the class repository (see link above).

<!-- - Since most of you guys are using VS Code, I set up the assignment in a way
  that there should be a button "Open in VS Code" that'll make life a bit
  easier. Still, it's obviously good to know how to clone a repository from
  github and set it up, so feel free to keep doing that.
 -->
- VS Code will recognize that this is a cmake project (maybe you'll have to
  install the "CMake Tools" extension first), and it'll automatically configure,
  and even build your project in a `build/` directory at the top-level of the
  cloned repository. If you prefer to run cmake by hand (again, certainly good
  practice), I strongly recommend duplicating that structure, ie., creating a
  `build/` directory at the top level of your repo.

- This assignment is another opportunity to work as a team. You can practice
  creating your own branch to work in, then pushing that branch to github and
  opening a pull request, to merge the changes into the `main` branch, which
  will make it show up in the "Feedback" pull request. (The "Feedback" pull
  request is really just a regular pull request, except that it's not meant to
  be merged, it's for me to look at your work and provide feedback.)

  As before, there are many options on how to collaborate, and you can use whatever works best for you. You can work together on the same branch (that probably means one person is doing the actual coding, while the other is providing input and suggestions), switchingroles as you make progress. Or you can each work on your own branch, and then merge your branches together. One way to do this, which will help avoid conflicts is for each team member to make their own branch, implement a certain task, then make a pull request. You may end up with multiple pull requests doing roughly the same thing, so at that point you could discuss which one you like the best, and just merge that one. That would be a good thing to document in the notes in the feedback PR, including a link to the PR(s) that you decided to not merge (and could then close).
  
### Linear Algebra: It all starts with a dot product

As opposed to Fortran, neither C nor C++ really have much concept of
mathematical objects that are useful for numerical computations. So the idea
here is to see what it takes to add some basic linear algebra capabilities.

In today's repo, I started by writing a (very basic) `vector_dot()` function in
`c/vector_dot.c`:

```c
// ----------------------------------------------------------------------
// vector_dot
//
// returns the dot product of the two vectors
// x: first vector
// y: second vector

double vector_dot(double* x, double* y)
{
  double sum = 0.f;
  for (int i = 0; i < N; i++) {
    sum += x[i] * y[i];
  }
  return sum;
}
```

I also added a very basic (and not very automatic test). This is where it all
begins...

#### Your turn

- Take the test part of the code out of `vector_dot.c` and make a separate
  `test_vector_dot.c`. Update the `CMakeLists.txt` accordingly.

- Add a new file `vector_add.c`, and write a function `vector_add(x, y, z)` that
  adds `x` and `y` and puts the result into `z`. Write a test for this routine in a
  separate file. Update the `CMakeLists.txt` accordingly.

- (more challenging) Add a new file `matrix_vector_mul.c`, and write a function
  `matrix_vector_mul(A, x, y)` that calculates `y = Ax`, where `A` is a N x N
  matrix. Write a test for it. Update the `CMakeLists.txt` accordingly.

- Add at least one automated test for each of the three functions, which will be
  run by `ctest .`. (You can base these tests on testing code you already have.)

- Build a library `linalg` that contains the three linear algebra functions
  above. Change your tests to link with that library.

- Start thinking about how to make this library more generic, in particular, how
  to avoid having it work only with the hardcoded vector size N = 3.


### Structs, argument passing and pointers

Let's switch gears for a minute, as the following will come in handy later. It seems like a good idea at this point to clarify some C/C++ features that
often is non-intuitive to programmers not experienced in those languages.

#### Your turn

[This may end up being a bit of a struggle. Don't hesitate to ask for help if you get stuck, and it's okay if not everything makes sense right now.]

For the following, write some small pieces of code. Create a new directory for it, set up cmake for it, too. Commit the various steps of your test
code and copy&paste the output into your feedback pull request, together with
some interpretation of what that output means.

- Write a function `void foo(double x)`. That function should print `x`, then
  set `x` to `10`, then print it again. In the `main` function, make a variable
  `double x = 99.;` and pass it to `foo()`. Print the value of `x` in the main
  program before and after you call `foo(x)`. What happens? Why?

- Rename the variable you're using in the implementation of `foo()` to `y`. What happens? Why?

- Let's do this again, but this time with an array of two doubles `double arr[2]`. Add `double arr[2] = { 3., 4. };` to your main program, and implement a corresponding `foo_array()` function. Repeat the same steps as above, and see what happens. Why?

- Finally, let's use a `struct` -- let's say `arr` was actually a point, with `arr[0]`
  being the x-coordinate and `arr[1]` the y-coordinate. We can make a `struct point`:

```c
struct point {
  double x;
  double y;
};
```

To initialize it, you can do

```c
  struct point p;
  p.x = 2.;
  p.y = 3.;
  // or all in one line:
  // struct point p = { .x = 2., .y = 2. };
```


Pass `p` to a new `foo_point()` function, and implement that function to print its argument there, and reassign new values.
Again, what happens, and why?

- [This is not trivial]. Change your code such that the new values assigned in
  `foo...()` actually make it back to the calling `main()` function, for all of the variants of `foo...()` you have.

## Homework

- As usual, finish the class work above, and don't forget to commit as you go.

- As I mentioned in the previous class, I'm giving you an opportunity to have a second go at the class 3/4 homework and add a reflection, as an opportunity to get back some missing credit for it.

  In particular, in order to do so, go through the [sample solution for the class 3/4 homework](https://github.com/UNH-HPC-2026/class-3-kai/pull/1), and using that, review your own work by adding comments to your feedback PR. You don't have to redo everything, but you should at least identify what you missed, what you got right, what you learned, and what still doesn't make sense. You can go and do some things you have mixed previously in your own code, by making more commits and pushing (syncing) them. 

