GF2::Vector — Encode a Bit-Vector as a String.
Methods to encode a bit-vector as a string in a binary or hex format.
std::string
to_string(bool bit_order=false, char off='0', char on='1') const; (1)
std::string to_bit_order(char off='0', char on='1') const; (2)
std::string to_hex() const; (3)
| 1 | Get a binary-string representation for the bit-vector using the given characters for set and unset elements. |
| 2 | Get a binary-string representation for the bit-vector in bit-order using the given characters for set and unset elements. |
| 3 | Get a hex-string representation for the bit-vector. |
| Parameters | |
|---|---|
|
Defaults to |
|
The characters to use for set and unset elements in binary encodings. Defaults to the usual 1 and 0. Characters for hex-strings are fixed to the standard set of 0123456789ABCDE. |
The most straightforward character encoding for any bit-vector is a binary string containing just 0’s and 1’s, e.g. "10101". We allow for an optional prefix "0b" or "0B" to act as a visual clue to the string’s contents, e.g. "0b10101". Apart from the optional prefix, each character in the binary string will translate to one element in the vector.
The other supported encoding is a compact hex type string containing just the 16 hex characters 0123456789ABCDEF. For example, the string "3ED02". Again, we allow for an optional prefix "0x" or "0X" e.g. "0x3ED02".
Each hex character naturally translates to 4 elements in a GF2::Vector.
The hex string "0x0" is equivalent to the binary string "0b0000", and so on, up to string "0xF" which is the same as the binary "0b1111".
The hex pair "0x0F" will be interpreted in the vector as 0b00001111.
This is of course the advantage of hex—it is a more compact format that occupies a quarter of the space needed to write out a full binary string.
However, what happens if you want to encode a vector whose size is not a multiple of 4?
We handle that by allowing the final character in the string to have a base that is not 16.
This is achieved by allowing for an optional suffix which must be one of "_2", "_4", or "_8".
If present, the prefix gives the base for just the _final_ character in the otherwise hex based string.
If there is no suffix the final character is assumed to be hex just like all the others.
So the string "0x1" (no suffix so the last character is the default hex base 16) is equivalent to "0b0001".
On the other hand, the string "0x1_8" (the last character is base 8) is equivalent to "0b001".
Similarly the string "0x1_4" (the last character is base 4) is equivalent to "0b01" and finally, the string "0x1_2" (the last character is base 2) is equivalent to "0b1"
In the string "0x3ED01_8", the first four characters '3', 'E', 'D', and '0' are interpreted as hex values and each will consume four slots in the vector. However, that final "1_8" is parsed as an octal 1 so only takes up three slots 0b001. In all then this particular vector has size 4 x 4 + 3 = 19.
If the suffix is present, the final character must fit inside the base given by that suffix. The string "0x3_8" is fine but trying to parse "0x3_2" will result in a std::invalid_argument exception as the final character is not either 0 or 1 which are the only valid options for something that is supposed to be base 2.
|
#include <GF2/GF2.h>
int main()
{
GF2::Vector v(32, [&](size_t k) { return (k + 1) % 2; }); (1)
std::cout << "v: " << v.to_string() << '\n'; (2)
std::cout << "v: " << v.to_bit_order() << '\n'; (3)
std::cout << "v: " << v.to_bit_order('.', '-') << '\n'; (4)
}
| 1 | v has all the even elements set to 1. |
| 2 | Printing v in vector_order using the default 0’s and 1’s for the element values. v0 is on the left. |
| 3 | Printing v in bit_order using the default 0’s and 1’s for the element values. v0 is on the right. |
| 4 | Printing v in bit_order using dots and dashes for the element values. v0 is on the right. |
v: 10101010101010101010101010101010
v: 01010101010101010101010101010101
v: .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
#include <GF2/GF2.h>
int main()
{
auto v5 = GF2::Vector<>::ones(5);
auto v6 = GF2::Vector<>::ones(6);
auto v7 = GF2::Vector<>::ones(7);
auto v8 = GF2::Vector<>::ones(8);
auto v9 = GF2::Vector<>::ones(9);
std::cout << "v5: " << v5.to_string() << "\t hex: " << v5.to_hex() << '\n';
std::cout << "v6: " << v6.to_string() << "\t hex: " << v6.to_hex() << '\n';
std::cout << "v7: " << v7.to_string() << "\t hex: " << v7.to_hex() << '\n';
std::cout << "v8: " << v8.to_string() << "\t hex: " << v8.to_hex() << '\n';
std::cout << "v9: " << v9.to_string() << "\t hex: " << v9.to_hex() << '\n';
}
v5: 11111 hex: F1_2
v6: 111111 hex: F3_4
v7: 1111111 hex: F7_8
v8: 11111111 hex: FF
v9: 111111111 hex: FF1_2
#include <GF2/GF2.h>
int main()
{
auto v5 = GF2::Vector<>::random(5); (1)
auto v6 = GF2::Vector<>::random(6);
auto v7 = GF2::Vector<>::random(7);
auto v8 = GF2::Vector<>::random(8);
auto v9 = GF2::Vector<>::random(9);
GF2::Vector<> u5(v5.to_hex()); (2)
GF2::Vector<> u6(v6.to_hex());
GF2::Vector<> u7(v7.to_hex());
GF2::Vector<> u8(v8.to_hex());
GF2::Vector<> u9(v9.to_hex());
std::cout << "v5 " << v5 << "\t u5 " << u5 << (v5 == u5 ? "\t match " : "\t FAIL") << '\n';
std::cout << "v6 " << v6 << "\t u6 " << u6 << (v6 == u6 ? "\t match " : "\t FAIL") << '\n';
std::cout << "v7 " << v7 << "\t u7 " << u7 << (v7 == u7 ? "\t match " : "\t FAIL") << '\n';
std::cout << "v8 " << v8 << "\t u8 " << u8 << (v8 == u8 ? "\t match " : "\t FAIL") << '\n';
std::cout << "v9 " << v9 << "\t u9 " << u9 << (v9 == u9 ? "\t match " : "\t FAIL") << '\n';
}
| 1 | Set up some bit-vectors of various lengths with random 50-50 fills. |
| 2 | Convert the bit-vectors to hex-strings and use those to construct bit-vectors. Check that the two sets of vectors match. |
v5 01011 u5 01011 match
v6 000111 u6 000111 match
v7 1101011 u7 1101011 match
v8 11010110 u8 11010110 match
v9 110111001 u9 110111001 match