Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ipython-with-reprs Sphinx directive #430

Merged
merged 6 commits into from
Nov 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
107 changes: 65 additions & 42 deletions docs/basic-usage/array-arithmetic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ In the sections below, the finite field :math:`\mathrm{GF}(3^5)` and arrays :mat
x = GF([184, 25, 157, 31]); x
y = GF([179, 9, 139, 27]); y

Ufuncs
------
Standard arithmetic
-------------------

`NumPy ufuncs <https://numpy.org/devdocs/reference/ufuncs.html>`_ are universal functions that operate on scalars. Unary ufuncs operate on
a single scalar and binary ufuncs operate on two scalars. NumPy extends the scalar operation of ufuncs to operate on arrays in various ways.
Expand All @@ -23,123 +23,140 @@ Expand any section for more details.

.. details:: Addition: `x + y == np.add(x, y)`
:class: example
:open:

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
y
x + y
np.add(x, y)

.. details:: Additive inverse: `-x == np.negative(x)`
:class: example

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
-x
np.negative(x)

Any array added to its additive inverse results in zero.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
x + np.negative(x)

.. details:: Subtraction: `x - y == np.subtract(x, y)`
:class: example

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
y
x - y
np.subtract(x, y)

.. details:: Multiplication: `x * y == np.multiply(x, y)`
:class: example

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
y
x * y
np.multiply(x, y)

.. details:: Scalar multiplication: `x * z == np.multiply(x, z)`
.. details:: Scalar multiplication: `x * 4 == np.multiply(x, 4)`
:class: example

Scalar multiplication is essentially *repeated addition*. It is the "multiplication" of finite field elements
and integers. The integer value indicates how many additions of the field element to sum.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
x * 4
np.multiply(x, 4)
x + x + x + x

In finite fields :math:`\mathrm{GF}(p^m)`, the characteristic :math:`p` is the smallest value when multiplied by
any non-zero field element that results in 0.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

p = GF.characteristic; p
x * p

.. details:: Multiplicative inverse: `y ** -1 == np.reciprocal(y)`
:class: example

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

y
y ** -1
GF(1) / y
np.reciprocal(y)

Any array multiplied by its multiplicative inverse results in one.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

y * np.reciprocal(y)

.. details:: Division: `x / y == x // y == np.divide(x, y)`
:class: example

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
y
x / y
x // y
np.divide(x, y)

.. details:: Remainder: `x % y == np.remainder(x, y)`
:class: example

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
y
x % y
np.remainder(x, y)

.. details:: Divmod: `divmod(x, y) == np.divmod(x, y)`
:class: example

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
y
x // y, x % y
divmod(x, y)
np.divmod(x, y)

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

q, r = divmod(x, y)
q*y + r == x

.. details:: Exponentiation: `x ** z == np.power(x, z)`
.. details:: Exponentiation: `x ** 3 == np.power(x, 3)`
:class: example

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
x ** 3
np.power(x, 3)
x * x * x

.. details:: Square root: `np.sqrt(x)`
:class: example

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
x.is_square()
z = np.sqrt(x); z
z ** 2 == x
Expand All @@ -151,17 +168,19 @@ Expand any section for more details.

Compute the logarithm base :math:`\alpha`, the primitive element of the field.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

y
z = np.log(y); z
alpha = GF.primitive_element; alpha
alpha ** z == y

Compute the logarithm base :math:`\beta`, a different primitive element of the field. See :func:`FieldArray.log` for more
details.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

y
beta = GF.primitive_elements[-1]; beta
z = y.log(beta); z
beta ** z == y
Expand All @@ -176,16 +195,16 @@ Expand any section for more details.

.. details:: `reduce()`
:class: example
:open:

The :obj:`~numpy.ufunc.reduce` methods reduce the input array's dimension by one, applying the ufunc across one axis.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
np.add.reduce(x)
x[0] + x[1] + x[2] + x[3]

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

np.multiply.reduce(x)
x[0] * x[1] * x[2] * x[3]
Expand All @@ -195,12 +214,13 @@ Expand any section for more details.

The :obj:`~numpy.ufunc.accumulate` methods accumulate the result of the ufunc across a specified axis.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
np.add.accumulate(x)
GF([x[0], x[0] + x[1], x[0] + x[1] + x[2], x[0] + x[1] + x[2] + x[3]])

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

np.multiply.accumulate(x)
GF([x[0], x[0] * x[1], x[0] * x[1] * x[2], x[0] * x[1] * x[2] * x[3]])
Expand All @@ -211,12 +231,13 @@ Expand any section for more details.
The :obj:`~numpy.ufunc.reduceat` methods reduces the input array's dimension by one, applying the ufunc across one axis
in-between certain indices.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
np.add.reduceat(x, [0, 3])
GF([x[0] + x[1] + x[2], x[3]])

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

np.multiply.reduceat(x, [0, 3])
GF([x[0] * x[1] * x[2], x[3]])
Expand All @@ -226,11 +247,13 @@ Expand any section for more details.

The :obj:`~numpy.ufunc.outer` methods applies the ufunc to each pair of inputs.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
y
np.add.outer(x, y)

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

np.multiply.outer(x, y)

Expand All @@ -239,8 +262,9 @@ Expand any section for more details.

The :obj:`~numpy.ufunc.at` methods performs the ufunc in-place at the specified indices.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
z = x.copy()
# Negate indices 0 and 1 in-place
np.negative.at(x, [0, 1]); x
Expand All @@ -253,10 +277,11 @@ Advanced arithmetic

.. details:: Convolution: `np.convolve(x, y)`
:class: example
:open:

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x
y
np.convolve(x, y)

.. details:: FFT: `np.fft.fft(x)`
Expand All @@ -265,13 +290,13 @@ Advanced arithmetic
The Discrete Fourier Transform (DFT) of size :math:`n` over the finite field :math:`\mathrm{GF}(p^m)` exists when there
exists a primitive :math:`n`-th root of unity. This occurs when :math:`n\ |\ p^m - 1`.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

GF = galois.GF(7**5)
n = 6
# n divides p^m - 1
(GF.order - 1) % n
x = GF.Random(n); x
x = GF.Random(n, seed=1); x
X = np.fft.fft(x); X
np.fft.ifft(X)

Expand All @@ -283,13 +308,13 @@ Advanced arithmetic
The inverse Discrete Fourier Transform (DFT) of size :math:`n` over the finite field :math:`\mathrm{GF}(p^m)` exists when there
exists a primitive :math:`n`-th root of unity. This occurs when :math:`n\ |\ p^m - 1`.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

GF = galois.GF(7**5)
n = 6
# n divides p^m - 1
(GF.order - 1) % n
x = GF.Random(n); x
x = GF.Random(n, seed=1); x
X = np.fft.fft(x); X
np.fft.ifft(X)

Expand All @@ -305,7 +330,6 @@ Expand any section for more details.

.. details:: Dot product: `np.dot(a, b)`
:class: example
:open:

.. ipython:: python

Expand Down Expand Up @@ -355,7 +379,7 @@ Expand any section for more details.
A @ B
np.matmul(A, B)

.. details:: Matrix exponentiation: `np.linalg.matrix_power(A, z)`
.. details:: Matrix exponentiation: `np.linalg.matrix_power(A, 3)`
:class: example

.. ipython:: python
Expand All @@ -374,7 +398,7 @@ Expand any section for more details.
A = GF([[23, 11, 3, 3], [13, 6, 16, 4], [12, 10, 5, 3], [17, 23, 15, 28]]); A
np.linalg.det(A)

.. details:: Matrix rank: `np.linalg.matrix_rank(A, z)`
.. details:: Matrix rank: `np.linalg.matrix_rank(A)`
:class: example

.. ipython:: python
Expand Down Expand Up @@ -423,7 +447,6 @@ not included in NumPy.

.. details:: Row space: `A.row_space()`
:class: example
:open:

.. ipython:: python

Expand Down
10 changes: 5 additions & 5 deletions docs/basic-usage/array-classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ and :func:`~galois.GR` (future).

A :obj:`~galois.FieldArray` subclass is created using the class factory function :func:`~galois.GF`.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

GF = galois.GF(3**5)
print(GF.properties)
Expand Down Expand Up @@ -66,7 +66,7 @@ with :obj:`~galois.FieldArray.irreducible_poly`.

A :obj:`~galois.FieldArray` instance is created using `GF`'s constructor.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

x = GF([23, 78, 163, 124])
x
Expand Down Expand Up @@ -94,13 +94,13 @@ alternate constructors use `PascalCase` while other classmethods use `snake_case

For example, to generate a random array of given shape call :func:`~galois.FieldArray.Random`.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

GF.Random((2, 3))
GF.Random((3, 2), seed=1)

Or, create an identity matrix using :func:`~galois.FieldArray.Identity`.

.. ipython:: python
.. ipython-with-reprs:: int,poly,power

GF.Identity(4)

Expand Down