Array creation

Explicit construction

Galois field arrays can be constructed either explicitly or through numpy view casting. The method of array creation is the same for all Galois fields, but \(\mathrm{GF}(7)\) is used as an example here.

# Represents an existing numpy array
In [1]: x_np = np.random.randint(0, 7, 10, dtype=int); x_np
Out[1]: array([2, 0, 2, 6, 3, 0, 2, 4, 6, 5])

# Create a Galois field array through explicit construction (x_np is copied)
In [2]: x = GF7(x_np); x
Out[2]: GF([2, 0, 2, 6, 3, 0, 2, 4, 6, 5], order=7)

View casting

# View cast an existing array to a Galois field array (no copy operation)
In [3]: y = x_np.view(GF7); y
Out[3]: GF([2, 0, 2, 6, 3, 0, 2, 4, 6, 5], order=7)

Warning

View casting creates a pointer to the original data and simply interprets it as a new numpy.ndarray subclass, namely the Galois field classes. So, if the original array is modified so will the Galois field array.

In [4]: x_np
Out[4]: array([2, 0, 2, 6, 3, 0, 2, 4, 6, 5])

# Add 1 (mod 7) to the first element of x_np
In [5]: x_np[0] = (x_np[0] + 1) % 7; x_np
Out[5]: array([3, 0, 2, 6, 3, 0, 2, 4, 6, 5])

# Notice x is unchanged due to the copy during the explicit construction
In [6]: x
Out[6]: GF([2, 0, 2, 6, 3, 0, 2, 4, 6, 5], order=7)

# Notice y is changed due to view casting
In [7]: y
Out[7]: GF([3, 0, 2, 6, 3, 0, 2, 4, 6, 5], order=7)

Alternate constructors

There are alternate constructors for convenience: galois.GFArray.Zeros, galois.GFArray.Ones, galois.GFArray.Range, galois.GFArray.Random, and galois.GFArray.Elements.

In [8]: GF256.Random((2,5))
Out[8]: 
GF([[ 79,  86, 178, 193, 108],
    [127, 221,  93,   2,  42]], order=2^8)

In [9]: GF256.Range(10,20)
Out[9]: GF([10, 11, 12, 13, 14, 15, 16, 17, 18, 19], order=2^8)

In [10]: GF256.Elements()
Out[10]: 
GF([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
     14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,
     28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,
     42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,
     56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
     70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,
     84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,
     98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
    112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
    126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
    140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
    154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
    182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195,
    196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
    210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
    224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237,
    238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
    252, 253, 254, 255], order=2^8)

Array dtypes

Galois field arrays support all signed and unsigned integer dtypes, presuming the data type can store values in \([0, p^m)\). The default dtype is the smallest valid unsigned dtype.

In [11]: GF = galois.GF(7)

In [12]: a = GF.Random(10); a
Out[12]: GF([4, 5, 3, 6, 0, 6, 5, 4, 6, 4], order=7)

In [13]: a.dtype
Out[13]: dtype('uint8')

# Type cast an existing Galois field array to a different dtype
In [14]: a = a.astype(np.int16); a
Out[14]: GF([4, 5, 3, 6, 0, 6, 5, 4, 6, 4], order=7)

In [15]: a.dtype
Out[15]: dtype('int16')

A specific dtype can be chosen by providing the dtype keyword argument during array creation.

# Explicitly create a Galois field array with a specific dtype
In [16]: b = GF.Random(10, dtype=np.int16); b
Out[16]: GF([4, 5, 1, 4, 6, 4, 4, 2, 6, 2], order=7)

In [17]: b.dtype
Out[17]: dtype('int16')

Field element display modes

The default representation of a finite field element is the integer representation. That is, for \(\mathrm{GF}(p^m)\) the \(p^m\) elements are represented as \(\{0,1,\dots,p^m-1\}\). For extension fields, the field elements can alternatively be represented as polynomials in \(\mathrm{GF}(p)[x]\) with degree less than \(m\). For prime fields, the integer and polynomial representations are equivalent because in the polynomial representation each element is a degree-:math`0` polynomial over \(\mathrm{GF}(p)\).

For example, in \(\mathrm{GF}(2^3)\) the integer representation of the \(8\) field elements is \(\{0, 1, 2, 3, 4, 5, 6, 7\}\) and the polynomial representation is \(\{0,\ 1,\ x,\ x+1,\ x^2,\ x^2+1,\ x^2+x,\ x^2+x+1\}\).

In [18]: GF = galois.GF(2**3)

In [19]: a = GF.Random(10)

# The default mode represents the field elements as integers
In [20]: a
Out[20]: GF([2, 4, 0, 7, 6, 2, 4, 5, 5, 4], order=2^3)

# The display mode can be set to "poly" mode
In [21]: GF.display("poly"); a
Out[21]: 
GF([α, α^2, 0, α^2 + α + 1, α^2 + α, α, α^2, α^2 + 1, α^2 + 1, α^2],
   order=2^3)

# The display mode can be set to "power" mode
In [22]: GF.display("power"); a
Out[22]: GF([α, α^2, -∞, α^5, α^4, α, α^2, α^6, α^6, α^2], order=2^3)

# Reset the display mode to the default
In [23]: GF.display(); a
Out[23]: GF([2, 4, 0, 7, 6, 2, 4, 5, 5, 4], order=2^3)

The galois.GFArray.display method can be called as a context manager.

# The original display mode
In [24]: print(a)
GF([2, 4, 0, 7, 6, 2, 4, 5, 5, 4], order=2^3)

# The new display context
In [25]: with GF.display("poly"):
   ....:    print(a)
   ....: 
GF([α, α^2, 0, α^2 + α + 1, α^2 + α, α, α^2, α^2 + 1, α^2 + 1, α^2],
   order=2^3)

In [26]: with GF.display("power"):
   ....:    print(a)
   ....: 
GF([α, α^2, -∞, α^5, α^4, α, α^2, α^6, α^6, α^2], order=2^3)

# Returns to the original display mode
In [27]: print(a)
GF([2, 4, 0, 7, 6, 2, 4, 5, 5, 4], order=2^3)