January 2021

When I learned how to use SIMD instructions in C a few months ago I was put off by how clunky it felt. There is a lot of boilerplate involved to account for different architectures that do or don't support MMX, SSE, AVX-2 or AVX-512, and the massive blocks of unrolled loops are not great for code readability and binary sizes. This article explains how RISC-V reduces the complexity of SIMD by implementing a generalized notion of vectors in hardware. Special status and control registers (CSR) are used to keep track of the vector length, and the hardware takes care of the chunking and looping. This improves code readability and reduces the overhead involved in repeatedly decoding the same load/operate/store instructions each loop.

I've been meaning to pick up Rust as a language. Whenever I step out from the magical land of Python into the sterile lab that is C I enjoy the simplicity and absolute control of the language tremendously, but I also miss a lot of expressiveness and versatility that I'm used to from Python. Because I'm not yet burdened by a history in C++ or C#, I want to see what the Rust hype is about. This article gives a quick but pretty comprehensive introduction to the language in a quick, no-frills writing style that I like.

I too watched the Queen's Gambit and subsequently thought about chess more than before (which was close to never). This article is about the inner workfings of the Stockfish chess engine They explain what choices were made , and how these choices compare with some other designs. It's a fun read to learn more about a practical application of a simple feedforward neural network.

Bitwarden released Emergency Access this month. Its aim is to solve the problem of what happens to your password vault after you're gone. I hadn't given it much thought, but this actually seems like an pretty important thing to care of nowadays.

You may have heard of Python's defaultdicts, which takes a callable and returns its result whenever you index a missing value.

from collections import defaultdict
names = defaultdict(int)
print(counter['foos'])
# 0
counter['bars'] += 1
print(counter['bars'])
# 1

Autovivication is the idea of doing this recursively every time an undefined value is dereferenced:

from collections import defaultdict
autovivificator = lambda: defaultdict(autovivificator)
av = autovivificator ()
av['foos']['subfoo']['subsubfoo'] = 'foobaz'
av['bars']['subbar']['subsubbar'] = 'barbaz'
print(av)
# defaultdict(<function __main__.<lambda>()>,
#        {'foos': defaultdict(<function __main__.<lambda>()>,
#                     {'subfoo': defaultdict(<function __main__.<lambda>()>,
#                                  {'subsubfoo': 'foobaz'})}),
#         'bars': defaultdict(<function __main__.<lambda>()>,
#                     {'subbar': defaultdict(<function __main__.<lambda>()>,
#                                  {'subsubbar': 'barbaz'})})})

I recently made a mistake in naming some neural network architecture "LeNet" while it actually wasn't that architecture. I already produced about 900 log files with the wrong name in them, but no worries; just use the following snippet to replace lenet with fcsmall in-place for all files that end in log:

sed -i s/lenet/fcsmall/g *.log