mfp1-2022/src/maths/sets/random.py

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 ];