I would like to compress a multi dimensional unit vector to an integer [0, N), but with a guarantee that the restored vector and the original one, have angle at most a degrees. The goal is to make the number of required integers, N as small as possible.
For example, for 2D unit vector, and desired max angle of 60 degrees we can simply compress the vector to the nearest point on a circle-inscribed hexagon and use integers [0, 6) to encode the vertex.
Is there an easy way to achieve that in D dimensions? Perhaps https://en.wikipedia.org/wiki/Regular_polytope could be used? Approximate solutions are fine.
Thanks a lot!
Not sure to what extent (if any) this answers/addresses your question. If you've already "compressed" the $2D$ case to $[1,n)$ like you illustrated, then the $3D$ case boils down to finding an $\mathbb N\times\mathbb N\to\mathbb N$ mapping (and its inverse), giving you one enumeration for two circles in, say, the $x,y-$plane and then in the orthogonal plane containing that $x,y-$unit vector. That mapping is canonically given by the pairing function, https://en.wikipedia.org/wiki/Pairing_function And then you can iterate that for $\mathbb N^n\to\mathbb N$ for higher-dimensional cases.
Or maybe even more straightforward, just use discrete $x_i,i=1\ldots D$ integer coordinates for the $D-$dimensional case (with some $\Delta x_i$'s of your choice for the discrete intervals). Then $n\in\mathbb N^D$ ($\sim\mathbb N$ by the iterated pairing function) specifies a point in that space. And just normalize it for a unit vector.
>>E d i t<<
-----------------------
If still interested, below's some code in C (I'll leave you to translate to javascript/python as needed) that accomplishes your "compression" pretty well. It's discussed a little further below the listing...
It basically uses the "JeanMarie" method rather than my original pairing function suggestion. This turns out to be much more compact if your range of coordinate values is small, because it first calculates range=hivalue-lovalue and uses that range as a base. And it also subtracts the smallest of your values from each value, so that your coordinates are translated from low-to-high to 0-to-range (with a slight little alteration). So all that can be somewhat more efficient than just choosing a constant number of bits for each coordinate value.
For example, save it as coordpack.c and compile as
cc -DTESTDRIVE coordpack.c -o coordpack
and then if you run it as, for example,
./coordpack 5 3 1 -2 4 4 2 6 -1 1 -1 2 3
the output is
So it packed 13 numbers with a range of $6-(-2)=8$ into one 64-bit (unsigned long long) integer whose decimal value is $13682439925725679620$, as printed. That's about the max it can do for that range. It does a few checks to make sure your input isn't out-of-bounds, but it'll still get fooled and screw up -- needs a few more checks.