In a previous post I said I would come back to explain a few somewhat opaque lines in my matrix-based solution to Advent of Code 2022, day 2. This is what I’m going to do here.

There’s three smallish things I thought it was worth pointing out. None is going to surprise veteran python coders, but they might be of interest to some.

# Building matrices

So the first line I want to look at is:

```
B = np.array(list("012" * 3)).astype(int).reshape(3, 3)
```

This builds the matrix $B$ from the previous post as a numpy array. Reminder that matrix $B$ looks like this:

So this line of code is throwing together a bunch of small things that we should unpack.
First, in the middle there, we have a string `"123"`

,
which we then multiply by 3.
Multiplying a string by $n$ means repeating it $n$ times.
So `"012" * 3`

is the same as `"012012012"`

.
Next we turn that string into a list.
That is, we treat the string as a list of single character strings:
`list("012" * 3)`

is:
`["0", "1", "2", "0", "1", "2", "0", "1", "2"]`

.

We take that list, and turn it into a numpy array.
`np.array(list("012"*3))`

is a one-dimensional array of strings.

```
>>> np.array(list("012"*3))
array(['0', '1', '2', '0', '1', '2', '0', '1', '2'], dtype='<U1')
```

That `dtype='<U1'`

is telling us that numpy is treating the data type of the array
as unicode strings, which is not what we want.
`.astype(int)`

turns it into a one-dimensional array of ints
(which works because each string can be cast to an int).

```
>>> np.array(list("012"*3)).astype(int)
array([0, 1, 2, 0, 1, 2, 0, 1, 2])
>>> np.array(list("012"*3)).astype(int).dtype
dtype('int64')
```

And finally, `.reshape(3,3)`

reshapes the array into a 3 by 3 array.

```
>>> np.array(list("012" * 3)).astype(int).reshape(3, 3)
array([[0, 1, 2],
[0, 1, 2],
[0, 1, 2]])
```

# Matching vectors

The second thing I wanted to explain is `_get_vec`

:

```
def _get_vec(in_val, values):
return (np.array(list(values)) == in_val).astype(int)
```

Recall that for the AoC problem, the input was a string,
with moves represented by letters – “A”, “B” or “C” for their move, “X”, “Y”, or “Z” for my move –
and what we wanted to get out, for the matrix solution
was a unit vector with a “1” in the position corresponding to the move.
That is, if their move was a “B”, we wanted to get out $(0,1,0)$.
This is precisely what the above function does:
put in “B” and “ABC” as the two arguments and it returns `np.array([0,1,0])`

.

So what is it doing?
Starting from the inside again, we have `list(values)`

which is doing the same trick we had before:
take a string, and return a list of characters.
Then we turn that list into a numpy array.
We then compare that numpy array of characters to the `in_val`

argument, using the `==`

comparison operator.
This gives us a boolean array:
with `False`

where the character in that position doesn’t match `in_val`

and `True`

where we do have a match.
So `np.array(list("ABC")) == "B"`

is `np.array([False, True, False])`

.
The final step is to turn that boolean array into an array of integers:
`False`

maps to `0`

and `True`

maps to `1`

.
This gives us `np.array([0,1,0])`

as desired.

# Matrix multiplication

The last thing I wanted to mention is the quickest, and possibly the most surprising.
Python has a matrix multiplication infix operator!
Or rather, there’s a PEP spec for one, and numpy implements it.
Use `A @ B`

to multiply matrices `A`

and `B`

together.
That’s neat, and not something I was aware of until I went looking for it.
Will I get much use out of it?
Probably not.
But it’s nice to know it’s there.