Module hosh.misc.math
Pure Python linear algebra module
Expand source code
# Copyright (c) 2021. Davi Pereira dos Santos
# This file is part of the hosh project.
# Please respect the license - more about this in the section (*) below.
#
# hosh is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# hosh is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with hosh. If not, see <http://www.gnu.org/licenses/>.
#
# (*) Removing authorship by any means, e.g. by distribution of derived
# works or verbatim, obfuscated, compiled or rewritten versions of any
# part of this work is illegal and is unethical regarding the effort and
# time spent here.
"""
Pure Python linear algebra module
"""
from hosh.misc.root import root
cellsroot = root
def int2cells(num, mod):
"""
Convert an integer to cells representing a 4x4 unitriangular matrix
>>> e = [42821,772431,428543,443530,42121,7213]
>>> e == int2cells(cells2int(e,4294967291), 4294967291)
True
>>> try:
... int2cells(-1, 10)
... except Exception as e:
... print(e)
Number -1 too large for given mod 10
Parameters
----------
num
mod
Returns
-------
"""
m = [0, 0, 0, 0, 0, 0]
num, m[5] = divmod(num, mod)
num, m[4] = divmod(num, mod)
num, m[3] = divmod(num, mod)
num, m[2] = divmod(num, mod)
num, m[1] = divmod(num, mod)
rest, m[0] = divmod(num, mod)
if rest != 0: # pragma: no cover
raise Exception(f"Number {num} too large for given mod {mod}")
return m
def cells2int(m, mod):
"""
Convert cells representing a 4x4 unitriangular matrix to an integer.
Usage:
>>> n = 986723489762345987253897254295863
>>> cells2int(int2cells(n, 4294967291), 4294967291) == n
True
Parameters
----------
m
List with six values
mod
Large prime number
Returns
-------
Lexicographic rank of the element (at least according to the disposition of cells adopted here)
"""
return m[5] + m[4] * mod + m[3] * (mod ** 2) + m[2] * (mod ** 3) + m[1] * (mod ** 4) + m[0] * (mod ** 5)
def cellsmul(a, b, mod):
"""
Multiply two unitriangular matrices 4x4 modulo 'mod'.
'a' and 'b' given as lists in the format: [a5, a4, a3, a2, a1, a0]
1 a4 a1 a0
0 1 a2 a3
0 0 1 a5
0 0 0 1
>>> a, b = [51,18340,56,756,456,344], [781,2340,9870,1234,9134,3134]
>>> cellsmul(b, cellsinv(b, 4294967291), 4294967291) == [0,0,0,0,0,0]
True
>>> c = cellsmul(a, b, 4294967291)
>>> cellsmul(c, cellsinv(b, 4294967291), 4294967291) == a
True
Parameters
----------
a
List with six values
b
Another (or the same) list with six values
mod
Large prime number
Returns
-------
The list that corresponds to the resulting element from multiplication
"""
return [
(a[0] + b[0]) % mod,
(a[1] + b[1]) % mod,
(a[2] + b[2] + a[3] * b[0]) % mod,
(a[3] + b[3]) % mod,
(a[4] + b[4] + a[1] * b[3]) % mod,
(a[5] + b[5] + a[1] * b[2] + a[4] * b[0]) % mod,
]
def cellsinv(m, mod, additive=False):
"""
Inverse of unitriangular matrix modulo 'mod'
'm' given as a list in the format: [a5, a4, a3, a2, a1, a0]
1 a4 a1 a0
0 1 a2 a3
0 0 1 a5
0 0 0 1
Based on https://groupprops.subwiki.org/wiki/Unitriangular_matrix_group:UT(4,p)
>>> from hosh.misc.math import cellsinv
>>> e = [42821,772431,428543,443530,42121,7213]
>>> cellsinv(cellsinv(e, 4294967291), 4294967291) == e
True
>>> cellsinv(cellsinv(e, 4294967291, additive=True), 4294967291, additive=True) == e
True
>>> e = [1,2,3,4,5,6]
>>> cellsinv(e, 7, additive=True)
[6, 5, 4, 3, 2, 1]
Parameters
----------
m
List with six values
mod
Large prime number
additive
Whether to calculate additive inverse or not (multiplicative)
Returns
-------
The list that corresponds to the inverse element
"""
if additive:
return [(mod - m[0]) % mod, (mod - m[1]) % mod, (mod - m[2]) % mod, (mod - m[3]) % mod, (mod - m[4]) % mod, (mod - m[5]) % mod]
return [
-m[0] % mod,
-m[1] % mod,
(m[3] * m[0] - m[2]) % mod,
-m[3] % mod,
(m[1] * m[3] - m[4]) % mod,
(m[1] * m[2] + m[4] * m[0] - m[1] * m[3] * m[0] - m[5]) % mod,
]
def cellspow(m, k, mod):
result_cells = [0, 0, 0, 0, 0, 0]
for i in range(0, k):
result_cells = cellsmul(result_cells, m, mod)
return result_cells
Functions
def cells2int(m, mod)
-
Convert cells representing a 4x4 unitriangular matrix to an integer.
Usage:
>>> n = 986723489762345987253897254295863 >>> cells2int(int2cells(n, 4294967291), 4294967291) == n True
Parameters
m
- List with six values
mod
- Large prime number
Returns
Lexicographic rank of the element (at least according to the disposition of cells adopted here)
Expand source code
def cells2int(m, mod): """ Convert cells representing a 4x4 unitriangular matrix to an integer. Usage: >>> n = 986723489762345987253897254295863 >>> cells2int(int2cells(n, 4294967291), 4294967291) == n True Parameters ---------- m List with six values mod Large prime number Returns ------- Lexicographic rank of the element (at least according to the disposition of cells adopted here) """ return m[5] + m[4] * mod + m[3] * (mod ** 2) + m[2] * (mod ** 3) + m[1] * (mod ** 4) + m[0] * (mod ** 5)
def cellsinv(m, mod, additive=False)
-
Inverse of unitriangular matrix modulo 'mod'
'm' given as a list in the format: [a5, a4, a3, a2, a1, a0]
1 a4 a1 a0 0 1 a2 a3 0 0 1 a5 0 0 0 1
Based on https://groupprops.subwiki.org/wiki/Unitriangular_matrix_group:UT(4,p)
>>> from hosh.misc.math import cellsinv >>> e = [42821,772431,428543,443530,42121,7213] >>> cellsinv(cellsinv(e, 4294967291), 4294967291) == e True
>>> cellsinv(cellsinv(e, 4294967291, additive=True), 4294967291, additive=True) == e True
>>> e = [1,2,3,4,5,6] >>> cellsinv(e, 7, additive=True) [6, 5, 4, 3, 2, 1]
Parameters
m
- List with six values
mod
- Large prime number
additive
- Whether to calculate additive inverse or not (multiplicative)
Returns
The list that corresponds to the inverse element
Expand source code
def cellsinv(m, mod, additive=False): """ Inverse of unitriangular matrix modulo 'mod' 'm' given as a list in the format: [a5, a4, a3, a2, a1, a0] 1 a4 a1 a0 0 1 a2 a3 0 0 1 a5 0 0 0 1 Based on https://groupprops.subwiki.org/wiki/Unitriangular_matrix_group:UT(4,p) >>> from hosh.misc.math import cellsinv >>> e = [42821,772431,428543,443530,42121,7213] >>> cellsinv(cellsinv(e, 4294967291), 4294967291) == e True >>> cellsinv(cellsinv(e, 4294967291, additive=True), 4294967291, additive=True) == e True >>> e = [1,2,3,4,5,6] >>> cellsinv(e, 7, additive=True) [6, 5, 4, 3, 2, 1] Parameters ---------- m List with six values mod Large prime number additive Whether to calculate additive inverse or not (multiplicative) Returns ------- The list that corresponds to the inverse element """ if additive: return [(mod - m[0]) % mod, (mod - m[1]) % mod, (mod - m[2]) % mod, (mod - m[3]) % mod, (mod - m[4]) % mod, (mod - m[5]) % mod] return [ -m[0] % mod, -m[1] % mod, (m[3] * m[0] - m[2]) % mod, -m[3] % mod, (m[1] * m[3] - m[4]) % mod, (m[1] * m[2] + m[4] * m[0] - m[1] * m[3] * m[0] - m[5]) % mod, ]
def cellsmul(a, b, mod)
-
Multiply two unitriangular matrices 4x4 modulo 'mod'.
'a' and 'b' given as lists in the format: [a5, a4, a3, a2, a1, a0]
1 a4 a1 a0 0 1 a2 a3 0 0 1 a5 0 0 0 1
>>> a, b = [51,18340,56,756,456,344], [781,2340,9870,1234,9134,3134] >>> cellsmul(b, cellsinv(b, 4294967291), 4294967291) == [0,0,0,0,0,0] True >>> c = cellsmul(a, b, 4294967291) >>> cellsmul(c, cellsinv(b, 4294967291), 4294967291) == a True
Parameters
a
- List with six values
b
- Another (or the same) list with six values
mod
- Large prime number
Returns
The list that corresponds to the resulting element from multiplication
Expand source code
def cellsmul(a, b, mod): """ Multiply two unitriangular matrices 4x4 modulo 'mod'. 'a' and 'b' given as lists in the format: [a5, a4, a3, a2, a1, a0] 1 a4 a1 a0 0 1 a2 a3 0 0 1 a5 0 0 0 1 >>> a, b = [51,18340,56,756,456,344], [781,2340,9870,1234,9134,3134] >>> cellsmul(b, cellsinv(b, 4294967291), 4294967291) == [0,0,0,0,0,0] True >>> c = cellsmul(a, b, 4294967291) >>> cellsmul(c, cellsinv(b, 4294967291), 4294967291) == a True Parameters ---------- a List with six values b Another (or the same) list with six values mod Large prime number Returns ------- The list that corresponds to the resulting element from multiplication """ return [ (a[0] + b[0]) % mod, (a[1] + b[1]) % mod, (a[2] + b[2] + a[3] * b[0]) % mod, (a[3] + b[3]) % mod, (a[4] + b[4] + a[1] * b[3]) % mod, (a[5] + b[5] + a[1] * b[2] + a[4] * b[0]) % mod, ]
def cellspow(m, k, mod)
-
Expand source code
def cellspow(m, k, mod): result_cells = [0, 0, 0, 0, 0, 0] for i in range(0, k): result_cells = cellsmul(result_cells, m, mod) return result_cells
def int2cells(num, mod)
-
Convert an integer to cells representing a 4x4 unitriangular matrix
>>> e = [42821,772431,428543,443530,42121,7213] >>> e == int2cells(cells2int(e,4294967291), 4294967291) True >>> try: ... int2cells(-1, 10) ... except Exception as e: ... print(e) Number -1 too large for given mod 10
Parameters
num
mod
Returns
Expand source code
def int2cells(num, mod): """ Convert an integer to cells representing a 4x4 unitriangular matrix >>> e = [42821,772431,428543,443530,42121,7213] >>> e == int2cells(cells2int(e,4294967291), 4294967291) True >>> try: ... int2cells(-1, 10) ... except Exception as e: ... print(e) Number -1 too large for given mod 10 Parameters ---------- num mod Returns ------- """ m = [0, 0, 0, 0, 0, 0] num, m[5] = divmod(num, mod) num, m[4] = divmod(num, mod) num, m[3] = divmod(num, mod) num, m[2] = divmod(num, mod) num, m[1] = divmod(num, mod) rest, m[0] = divmod(num, mod) if rest != 0: # pragma: no cover raise Exception(f"Number {num} too large for given mod {mod}") return m