How to write a hash function for canonical kmers? This question is a follow up from How do kmer counters determine which kmer is 'canonical'?.

In that question we learned that kmer counting programs use a 2-bit hash function to internally represent canonical kmers as they are being counted.

Now I am wondering, how can we implement such a function in C/C++ or in python? More arbitrarily, how could I calculate the canonical kmer hash value using a mathematical function?

For example, how would we transform the 3-mer GAT or the 21-mer GAATACCATAGGATA to 1s and 0s such that:

hash(GAT) == hash(ATC)
hash(GAATACCATAGGATA) == hash(TATCCTATGGTATTC)
You can convert any string hash function to a "canonical" DNA string hash function.

Given a DNA string $s$, let $\overline{s}$ be its Watson-Crick reverse complement. Suppose $h:\Sigma^*\to\mathbb{Z}$ is an arbitrary string hash function. You can define
$$
\tilde{h}(s)\triangleq \min\{h(s),h(\overline{s})\}
$$
Then for any DNA string $s$
$$
\tilde{h}(s)=\tilde{h}(\overline{s})=\tilde{h}({\rm canonical}(s|h))
$$

PS: There are more than one ways to define "canonical" hash function. For example, let $h_0(\cdot)$ be the 2-bit encoding hash function. Given any integer hash function $g(\cdot)$, we can define:
$$
h'(s)\triangleq g\big[\min\{h_0(s),h_0(\overline{s})\}\big]
$$
Then we still have
$$
h'(s)=h'(\overline{s})
$$
You can also replace $\min\{\}$ with XOR or plus to get new definitions.