104 lines
3.6 KiB
Python
104 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# IMPORTS
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
from __future__ import annotations;
|
|
|
|
from src.thirdparty.types import *;
|
|
from src.thirdparty.maths import *;
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# EXPORTS
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
__all__ = [
|
|
'randomset_integers',
|
|
'randomset_alphabet',
|
|
'randomset_greek',
|
|
'random_function',
|
|
];
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# CONSTANTS / VARIABLES
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
ALPHA = 'abcdefghijklmnopqrstuvwxyz';
|
|
GREEK = 'αβγδεζηθικλμνξοπρςτυφχψω';
|
|
T1 = TypeVar('T1');
|
|
T2 = TypeVar('T2');
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# METHODS
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
def randomset_integers(N: int = -1, low: int = 1, high: int = 1) -> list[int]:
|
|
if N == -1:
|
|
N = random.randint(low, high);
|
|
return list(range(1, N+1));
|
|
|
|
def randomset_alphabet(N: int = -1, low: int = 1, high: int = 1) -> list[int]:
|
|
if N == -1:
|
|
N = random.randint(low, high);
|
|
return list([a for k, a in enumerate(ALPHA) if k < N]);
|
|
|
|
def randomset_greek(N: int = -1, low: int = 1, high: int = 1) -> list[int]:
|
|
if N == -1:
|
|
N = random.randint(low, high);
|
|
return list([a for k, a in enumerate(GREEK) if k < N]);
|
|
|
|
def random_function(
|
|
X: list[T1],
|
|
Y: list[T2],
|
|
injective: Optional[bool] = None,
|
|
surjective: Optional[bool] = None,
|
|
force: bool = False,
|
|
) -> list[tuple[T1, T2]]:
|
|
m = len(X);
|
|
n = len(Y);
|
|
if m == 0:
|
|
return [];
|
|
if n == 0:
|
|
raise Exception(f'Impossible to create a function with {m} elements in the domain and {n} in the codomain.');
|
|
if not force:
|
|
if injective and m > n:
|
|
injective = None;
|
|
if surjective and m < n:
|
|
surjective = None;
|
|
if not injective and m == 1:
|
|
injective = None;
|
|
if not surjective and n == 1:
|
|
surjective = None;
|
|
match (injective, surjective):
|
|
case (True, _):
|
|
assert m <= n, f'Impossible to create an injective function with {m} elements in the domain and {n} in the codomain.';
|
|
Y = random.sample(Y, m);
|
|
return [(x, y) for x, y in zip(X, Y)];
|
|
case (_, True):
|
|
assert m >= n, f'Impossible to create an surjective function with {m} elements in the domain and {n} in the codomain.';
|
|
indexes = random.sample(list(range(m)), n);
|
|
g = [ (indexes[j], Y[j]) for j in range(n) ] \
|
|
+ [
|
|
(i, random.choice(Y))
|
|
for i in range(m)
|
|
if not i in indexes
|
|
];
|
|
g = sorted(g, key=lambda o: o[0]);
|
|
return [ (X[i], y) for (i, y) in g ];
|
|
case (False, _):
|
|
assert m > 1, f'Impossible to create a non-injective function with {m} elements in the domain.';
|
|
indexes = random.sample(list(range(m)), m);
|
|
g = random_function(indexes, Y);
|
|
[(i0, y0), (i1, y1)] = g[:2];
|
|
g[0] = (i0, y1);
|
|
g = sorted(g, key=lambda o: o[0]);
|
|
return [ (X[i], y) for (i, y) in g ];
|
|
case (_, False):
|
|
assert n > 1, f'Impossible to create a non-surjective function with {n} elements in the codomain.';
|
|
Y = random.sample(Y, n-1);
|
|
return random_function(X, Y);
|
|
case _:
|
|
return [ (x, random.choice(Y)) for x in X ];
|