Testing and debugging: Linear Algebra Project#
Today’s assignment.
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).
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 abuild/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
mainbranch, 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:
// ----------------------------------------------------------------------
// 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.cand make a separatetest_vector_dot.c. Update theCMakeLists.txtaccordingly.Add a new file
vector_add.c, and write a functionvector_add(x, y, z)that addsxandyand puts the result intoz. Write a test for this routine in a separate file. Update theCMakeLists.txtaccordingly.(more challenging) Add a new file
matrix_vector_mul.c, and write a functionmatrix_vector_mul(A, x, y)that calculatesy = Ax, whereAis a N x N matrix. Write a test for it. Update theCMakeLists.txtaccordingly.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
linalgthat 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 printx, then setxto10, then print it again. In themainfunction, make a variabledouble x = 99.;and pass it tofoo(). Print the value ofxin the main program before and after you callfoo(x). What happens? Why?Rename the variable you’re using in the implementation of
foo()toy. What happens? Why?Let’s do this again, but this time with an array of two doubles
double arr[2]. Adddouble arr[2] = { 3., 4. };to your main program, and implement a correspondingfoo_array()function. Repeat the same steps as above, and see what happens. Why?Finally, let’s use a
struct– let’s sayarrwas actually a point, witharr[0]being the x-coordinate andarr[1]the y-coordinate. We can make astruct point:
struct point {
double x;
double y;
};
To initialize it, you can do
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 callingmain()function, for all of the variants offoo...()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, 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.