This was my first and only solution and I couldn't be bothered to optimize it because making even minor changes is incredibly bugsome.

I tried to minimize the number of comparisons between elements. The obvious approach would be to compare the match pattern with each of the four 3-length substrings of the sample, with each substring comparison being processed one element at a time from left to right, for a total of 12 comparisons per sample. We can improve the average case slightly by moving on to the next 3-length substring as soon as a non-match is found, but the worst case remains at 12 comparisons.

This algorithm has some redundancies. If the first two atoms of the match pattern are the same (e.g. AAF) and the third comparison of the current substring is a non-match, then we can skip the first comparison of the next substring, since it is equivalent to the second comparison of the current substring, which is a match (because otherwise we wouldn't have reached the third comparison).

On the other hand, if the first two atoms of the match pattern are different (e.g. AFF) and the third comparison of the current substring is a non-match, then we can skip the next substring altogether, since the first comparison of the next substring is guaranteed to be a non-match.

In both cases, the worst case makes 9 comparisons per sample. Conveniently, the only difference between these two cases is an extra shift on the lower register when a non-match is made while the right-most atom of the register is on the duplicator. On the left prong of the multibonder, there is a quintessence atom if the first two atoms of the match pattern are different, which carries out the extra shift.

There's a lot of overhead in area, cost, and latency caused by false matches being made once the registers move off of the duplicators.