# enjmiah/GaloisPy

Coding theory and finite field computations
Python Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information. .gitignore .travis.yml CONTRIBUTING.md Galois.py LICENSE README.md bounds.py gcd.py tests.py

# GaloisPy A Python library for computations involving finite Galois fields.

Written in Python 3. Experimental support for Python 2.

Try it online.

## Usage

### Creating a field

Use the constructor for the `GF` class to create a finite Galois field, with the size of the field as its first argument.

```>>> from Galois import *
>>> GF4 = GF(4)```

The `GF` constructor also accepts an optional second argument, `verbose`, which determines whether or not you wish to see step-by-step solutions. For more information, see the Step-by-step solutions section.

### Basic operations

In GaloisPy, vectors are represented by Python lists: `[0, 1, 0, 1]`

Matrices are represented by lists of row vectors:

``````[[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]
``````

Note that GaloisPy uses Python primitives as field elements. The elements a and b in GF(4) are represented with the strings `'a'` and `'b'` respectively. Integers are represented by Python numbers.

To add or multiply two scalars in a field:

```>>> GF11 = GF(11)
2
0
>>> GF11.mult_scalar(2, 10)
9
>>> GF4 = GF(4)
'a'
>>> GF4.mult_scalar("a", "b")
1```

Many of the functions in GaloisPy work with vectors as well:

```>>> GF4.add([0, 1, "a", "b"], ["a", 1, "b", 0])
['a', 0, 1, 'b']
>>> GF11.add_inverse([2, 10, 8, 7, 0])
[9, 1, 3, 4, 11]```

Notable functions:

• `add_inverse(x)` returns the additive inverse of vector or scalar `x`
• `negative(x)` is another name for `add_inverse(x)`
• `mult_inverse(a)` returns the multiplicative inverse of scalar `a`
• `exp_scalar(a, n)` returns an over the field
• `scale_vec(a, v)` returns scalar `a` times vector `v`
• `is_lin_indep(S)` returns `True` if and only if `S` is a linearly independent set of vectors
• `dot_vec(u, v)` returns the dot product of `u` and `v`
• `rref(M)` returns the RREF of the matrix `M`
• `rank(M)` returns the rank of matrix `M`

All methods are pure functions (they do not have side effects).

### Encoding and decoding

• `encode(G, w)` returns the codeword from encoding word `w` with generator matrix `G`
• `is_generator_matrix(M)` returns `True` if and only if `M` is a valid generator matrix
• `is_standard_form(M, 'g')` returns `True` if and only if `M` is a valid generator matrix in standard form
• `is_standard_form(M, 'p')` returns `True` if and only if `M` is a valid parity-check matrix in standard form
• `create_pc_matrix(G)` creates a parity-check matrix from generator matrix `G`
• `is_pc_matrix(A, B)` returns `True` if and only if `A` and `B` are parity-check matrices of each other

All methods are pure functions (they do not have side effects).

### Step-by-step solutions

An important feature in GaloisPy is the ability to see step-by-step solutions. Whether or not you see step-by-step solutions is determined by the `verbose` member of the created `GF` instance.

You can specify this when you create the field. Alternately, you can change the `verbose` member at any time.

```>>> GF4 = GF(4, verbose=True)
>>> GF7 = GF(7)
>>> GF7.verbose = True```

You can also pass an additional `verbose` argument to methods that support it. This takes precedence over the value of the `verbose` member.

```>>> GF3 = GF(3)
>>> M = [[1, 1, 2, 1, 2],
[1, 0, 1, 1, 0],
[1, 2, 0, 1, 1],
[1, 1, 2, 0, 2],
[2, 2, 1, 2, 1]]
>>> M = GF3.rref(M, verbose=True)
# You will see the solution here...```

The following functions feature step-by-step solutions:

• `rref()`
• `mult_inverse()`

The following functions will print some extra information if `verbose` is `True`:

• `is_pc_matrix()`

Step-by-step solutions use the 1-based indexing convention of mathematics.

Here's some examples:

```>>> GF4 = GF(4)
>>> a = "a"; b = "b"
>>> M_2 = [[0, 0, b, 0],
[0, 0, 0, 0],
[a, 0, b, 1],
[1, 0, a, b]]
>>> M_2rref = GF4.rref(M_2, verbose=True)

| 0 0 b 0 |   Original matrix.
| 0 0 0 0 |
| a 0 b 1 |
| 1 0 a b |

| a 0 b 1 |   Exchange rows 1 and 3.
| 0 0 0 0 |
| 0 0 b 0 |
| 1 0 a b |

| a 0 b 1 |   PLAN: Pivot down from position (1, 1)
| 0 0 0 0 |
| 0 0 b 0 |
| 1 0 a b |

| a 0 b 1 |   Added b times row 1 to row 4.
| 0 0 0 0 |
| 0 0 b 0 |
| 0 0 0 0 |

| 1 0 a b |   Scale row 1 by b.
| 0 0 0 0 |
| 0 0 b 0 |
| 0 0 0 0 |

| 1 0 a b |   Exchange rows 2 and 3.
| 0 0 b 0 |
| 0 0 0 0 |
| 0 0 0 0 |

| 1 0 a b |   PLAN: Pivot down from position (2, 3)
| 0 0 b 0 |
| 0 0 0 0 |
| 0 0 0 0 |

| 1 0 a b |   Scale row 2 by a.
| 0 0 1 0 |
| 0 0 0 0 |
| 0 0 0 0 |

| 1 0 a b |   PLAN: Pivot up from position (2, 3)
| 0 0 1 0 |
| 0 0 0 0 |
| 0 0 0 0 |

| 1 0 0 b |   Added a times row 2 to row 1.
| 0 0 1 0 |
| 0 0 0 0 |
| 0 0 0 0 |
>>> GF983 = GF(983)
>>> GF983.mult_inverse(444, verbose=True)

983 = 2 * 444 + 95   ==>   95 = 983 - 2 * 444   ==>   t = 0 - 2 * 1 = -2
444 = 4 * 95 + 64   ==>   64 = 444 - 4 * 95   ==>   t = 1 - 4 * -2 = 9
95 = 1 * 64 + 31   ==>   31 = 95 - 1 * 64   ==>   t = -2 - 1 * 9 = -11
64 = 2 * 31 + 2   ==>   2 = 64 - 2 * 31   ==>   t = 9 - 2 * -11 = 31
31 = 15 * 2 + 1   ==>   1 = 31 - 15 * 2   ==>   t = -11 - 15 * 31 = -476
2 = 2 * 1 + 0   ==>   0 = 2 - 2 * 1
-476 mod 983 = 507
Multiplicative inverse is 507
507```

## Contributing

You can’t perform that action at this time.