galois.FieldArray.log(base: ElementLike | ArrayLike | None = None) int | ndarray

Computes the discrete logarithm of the array \(x\) base \(\beta\).

Parameters:
base: ElementLike | ArrayLike | None = None

A primitive element or elements \(\beta\) of the finite field that is the base of the logarithm. The default is None which uses primitive_element.

Slower performance

If the FieldArray is configured to use lookup tables (ufunc_mode == "jit-lookup") and this method is invoked with a base different from primitive_element, then explicit calculation will be used (which is slower than using lookup tables).

Returns:

An integer array \(i\) of powers of \(\beta\) such that \(\beta^i = x\). The return array shape obeys NumPy broadcasting rules.

Examples

Compute the logarithm of \(x\) with default base \(\alpha\), which is the specified primitive element of the field.

In [1]: GF = galois.GF(3**5)

In [2]: alpha = GF.primitive_element; alpha
Out[2]: GF(3, order=3^5)

In [3]: x = GF.Random(10, low=1); x
Out[3]: GF([ 73, 183,  50,  54,  33, 172,  86, 196,  71,   5], order=3^5)

In [4]: i = x.log(); i
Out[4]: array([109, 171,  51, 124,  75, 206,  73,  91, 182,   5])

In [5]: np.array_equal(alpha ** i, x)
Out[5]: True
In [6]: GF = galois.GF(3**5, repr="poly")

In [7]: alpha = GF.primitive_element; alpha
Out[7]: GF(α, order=3^5)

In [8]: x = GF.Random(10, low=1); x
Out[8]: 
GF([                α + 1,              α^3 + 2α,   2α^4 + 2α^3 + α + 1,
               2α^3 + α^2,       2α^4 + α^2 + 2α, α^4 + 2α^3 + 2α^2 + 2,
           2α^4 + α^3 + 2,        2α^3 + α^2 + 2,                   α^2,
           2α^4 + α^2 + 1], order=3^5)

In [9]: i = x.log(); i
Out[9]: array([ 69,  75, 205, 128,  78,  43, 220, 233,   2, 206])

In [10]: np.array_equal(alpha ** i, x)
Out[10]: True
In [11]: GF = galois.GF(3**5, repr="power")

In [12]: alpha = GF.primitive_element; alpha
Out[12]: GF(α, order=3^5)

In [13]: x = GF.Random(10, low=1); x
Out[13]: 
GF([ α^14,  α^66,  α^21, α^174,  α^58, α^174,  α^45, α^208,  α^97, α^104],
   order=3^5)

In [14]: i = x.log(); i
Out[14]: array([ 14,  66,  21, 174,  58, 174,  45, 208,  97, 104])

In [15]: np.array_equal(alpha ** i, x)
Out[15]: True

With the default argument, numpy.log() and log() are equivalent.

In [16]: np.array_equal(np.log(x), x.log())
Out[16]: True

Compute the logarithm of \(x\) with a different base \(\beta\), which is another primitive element of the field.

In [17]: beta = GF.primitive_elements[-1]; beta
Out[17]: GF(242, order=3^5)

In [18]: i = x.log(beta); i
Out[18]: array([  4,  88, 127, 188, 224, 188, 203,  94,  45, 168])

In [19]: np.array_equal(beta ** i, x)
Out[19]: True
In [20]: beta = GF.primitive_elements[-1]; beta
Out[20]: GF(2α^4 + 2α^3 + 2α^2 + 2α + 2, order=3^5)

In [21]: i = x.log(beta); i
Out[21]: array([  4,  88, 127, 188, 224, 188, 203,  94,  45, 168])

In [22]: np.array_equal(beta ** i, x)
Out[22]: True
In [23]: beta = GF.primitive_elements[-1]; beta
Out[23]: GF(α^185, order=3^5)

In [24]: i = x.log(beta); i
Out[24]: array([  4,  88, 127, 188, 224, 188, 203,  94,  45, 168])

In [25]: np.array_equal(beta ** i, x)
Out[25]: True

Compute the logarithm of a single finite field element base all of the primitive elements of the field.

In [26]: x = GF.Random(low=1); x
Out[26]: GF(37, order=3^5)

In [27]: bases = GF.primitive_elements

In [28]: i = x.log(bases); i
Out[28]: 
array([227, 105, 239,  53,  93,  97, 179,  31, 113,  43,  59, 237,  35,
       241, 149, 217, 145,  47,  85,   1,  63,  67, 221,  91, 199,  39,
         9, 195, 171, 163, 223, 213,  95, 181,  89, 119, 139,  23, 135,
        57,  41, 207,  71,  51, 151, 175,  69, 189, 185, 201, 155,  49,
       159,  37, 141, 193, 101,   7,  17, 131,  65, 127, 169, 229, 191,
        75,  45,  19,  87,  15, 173, 161,  79, 125,  81, 109, 133, 183,
       219, 215, 107, 157, 103, 225, 153, 211,  61,  21, 115,  83, 203,
       137, 123, 111, 147, 235,  25, 177, 129,  27, 117,  73, 233, 197,
       167, 205,  29,   5,   3,  13])

In [29]: np.all(bases ** i == x)
Out[29]: True
In [30]: x = GF.Random(low=1); x
Out[30]: GF(α^3 + α^2 + 2α, order=3^5)

In [31]: bases = GF.primitive_elements

In [32]: i = x.log(bases); i
Out[32]: 
array([210, 224,  42, 226, 150,  94, 156,  50, 112, 124, 142,  70, 236,
        14,  92, 108, 148,  68,  20, 228,  86,  30,  52, 178, 118, 180,
       116, 174,  26, 138,  24, 164, 122, 128, 206,  28, 232, 162,  46,
       170, 152,   6, 216,  12,  64, 212,   2,  16,  72,  90,   8,  40,
       194, 208, 204, 202,  38, 144,   4, 102,  58, 158,  54, 182, 230,
       160,  96, 218, 234,  32, 240, 166, 104, 186,  76, 168,  74, 100,
        80, 136, 196, 222,  10, 238,  36, 192, 114, 190,  84,  48,  62,
        18, 214, 140, 120,  98, 134, 184, 130, 106,  56, 188, 126, 146,
        82,  34,  78, 172, 200,  60])

In [33]: np.all(bases ** i == x)
Out[33]: True
In [34]: x = GF.Random(low=1); x
Out[34]: GF(α^87, order=3^5)

In [35]: bases = GF.primitive_elements

In [36]: i = x.log(bases); i
Out[36]: 
array([ 87, 117, 211, 225, 235, 115,  75, 159, 119,  41,  45,  29,  39,
       151,   7, 145, 127, 163, 233,  91, 167,  47,  25,  53, 201, 161,
        93,  79,  73,  71, 207,  23, 175,  15, 113, 181,  65, 157, 185,
       105, 101, 203, 169,  43, 189, 195, 229,  17, 137, 141,  69, 103,
       191, 221,   5, 139, 237, 153,  95,  63, 107, 183, 133,  27, 199,
        49, 223,  35, 173, 155,  13, 131, 171,   1, 111, 239,   3, 197,
        85, 205,  57,   9, 177, 147, 129,  83, 227, 217,  59,  51,  81,
       125,  61, 179,  67,  89,  97, 135, 123,  37, 241, 109, 149,  19,
       193,  21, 219, 213,  31, 215])

In [37]: np.all(bases ** i == x)
Out[37]: True