master > master: src - clean up

- enums für Alphabete
- button layout
- refresh Knopf
- aspect ratio
This commit is contained in:
RD 2022-10-22 09:15:34 +02:00
parent 56744bd389
commit 1d627623c7
5 changed files with 142 additions and 39 deletions

View File

@ -28,7 +28,7 @@ __all__ = [
T1 = TypeVar('T1');
T2 = TypeVar('T2');
SCALE = (1., 4.);
SCALE = (1., 1.5);
OFFSET = (3., 0.);
HMARGIN = 0.1;
VMARGIN = 0.2;
@ -119,15 +119,15 @@ class Functions:
for k, f in enumerate(self.fcts):
if k == 0:
comp_range = f.domain;
p_domain = random_points(nr_points=len(f.domain), scale=SCALE, centre=origin + k*offset);
p_domain = random_points(nr_points=len(f.domain), scale=SCALE, centre=origin + k*offset, tol=0.5);
else:
p_domain = p_codomain;
p_codomain = random_points(nr_points=len(f.codomain), scale=SCALE, centre=origin + (k+1)*offset);
p_codomain = random_points(nr_points=len(f.codomain), scale=SCALE, centre=origin + (k+1)*offset, tol=0.5);
# range of composition so far:
comp_range_next = [y for x, y in f.fct if x in comp_range];
if k == 0:
axs.scatter(p_domain[:, 0], p_domain[:, 1], label='', color='black', marker='o');
axs.scatter(p_domain[:, 0], p_domain[:, 1], label='', color='blue', marker='o');
if show_labels:
for i, p in enumerate(p_domain):
x_name = f.domain[i];
@ -136,7 +136,7 @@ class Functions:
for j, p in enumerate(p_codomain):
y = f.codomain[j];
marker = 'o' if (y in comp_range_next) else '.';
axs.scatter([p[0]], [p[1]], label='', color='black', marker=marker);
axs.scatter([p[0]], [p[1]], label='', color='blue', marker=marker);
y_name = f.codomain[j];
if show_labels:
axs.annotate(text=f'{y_name}', xy=p, textcoords='offset points', xytext=ANNOTATE_OFFSET, ha='center', size=FONTSIZE_PTS);
@ -146,7 +146,7 @@ class Functions:
q = p_codomain[j];
x = f.domain[i];
if k == 0 or (x in comp_range):
axs.plot([p[0], q[0]], [p[1], q[1]], label='', color='black', linewidth=1);
axs.plot([p[0], q[0]], [p[1], q[1]], label='', color='blue', linewidth=1);
else:
axs.plot([p[0], q[0]], [p[1], q[1]], label='', color='red', linestyle='--', linewidth=1);
@ -165,6 +165,7 @@ class Functions:
# update range of composition:
comp_range = comp_range_next;
axs.set_aspect('equal')
return fig, axs;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -188,7 +189,7 @@ def random_points(
scale: tuple[float, float] = (1., 1.),
centre: tuple[float, float] = (0., 0.),
force: bool = False,
tol: float = 0.2,
tol: float = 0.1,
) -> NDArray[Shape['*, 2'], Float]:
theta = np.linspace(start=0, stop=2*np.pi, num=nr_points, endpoint=False);
r_min = 0.25;

View File

@ -12,8 +12,8 @@ from src.maths.sets.random import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'Letters',
'random_function',
'randomset_alphabet',
'randomset_greek',
'randomset_integers',
];

View File

@ -15,9 +15,9 @@ from src.thirdparty.maths import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'Letters',
'randomset_integers',
'randomset_alphabet',
'randomset_greek',
'random_function',
];
@ -25,29 +25,68 @@ __all__ = [
# CONSTANTS / VARIABLES
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALPHA = 'abcdefghijklmnopqrstuvwxyz';
GREEK = 'αβγδεζηθικλμνξοπρςτυφχψω';
# local usage only
T1 = TypeVar('T1');
T2 = TypeVar('T2');
class Letters(Enum):
# 'abcdefghijklmnopqrstuvwxyz'
ROMAN = [chr(97 + n) for n in range(26)];
# 'αβγδεζηθικλμνξοπρςτυφχψω'
GREEK = [chr(945 + n) for n in range(25)]
# 'אבגדהוזחטיךכלםמןנסעףפץצקרשת' (but <—)
HEBREW = [chr(1488 + n) for n in range(27)];
SYMBOLS = [
r'$|0\rangle$',
r'$|\uparrow\rangle$',
r'$|\downarrow\rangle$',
r'$\sqrt{2}$',
r'$\pi$',
r'$e$',
r'$\frac{1}{137}$',
r'$\infty$',
# r'$-\infty$',
r'$\clubsuit$',
# r'$\diamondsuit$',
r'$\heartsuit$',
# r'$\spadesuit$',
r'$\hbar$',
];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def randomset_integers(N: int = -1, low: int = 1, high: int = 1) -> list[int]:
def randomset_integers(
N: int = -1,
low: int = 1,
high: int = 1,
shuffle: bool = False,
) -> list[int]:
if N == -1:
N = random.randint(low, high);
return list(range(1, N+1));
values = list(range(1, N+1));
if shuffle:
return sample(values, size=N, replace=False);
return values;
def randomset_alphabet(N: int = -1, low: int = 1, high: int = 1) -> list[int]:
if N == -1:
def randomset_alphabet(
mode: Letters,
N: int = -1,
low: int = 1,
high: int = 1,
shuffle: bool = False,
full: bool = False,
) -> list[str]:
letters: list[str] = mode.value;
if full:
N = len(letters);
elif N == -1:
high = min(low+1, high)
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]);
if shuffle:
return sample(letters, size=N, replace=False);
return letters[:N];
def random_function(
X: list[T1],

View File

@ -9,6 +9,29 @@ from fractions import Fraction;
import math;
import numpy as np;
import random;
from typing import TypeVar;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# MODIFICATIONS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# local usage only
T = TypeVar('T');
def sample(
X: list[T],
size: int = 1,
replace: bool = True,
) -> list[T]:
'''
@inputs
- `X` - a list
- `size` <int> - desired sample size
- `replace` <bool> - optional replacement
@returns a sample from an uniformly distributed set.
'''
return np.random.choice(X, size=size, replace=replace).tolist();
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
@ -19,4 +42,5 @@ __all__ = [
'math',
'np',
'random',
'sample',
];

View File

@ -9,6 +9,7 @@ from __future__ import annotations;
from src.thirdparty.types import *;
from src.thirdparty.plots import *;
from src.thirdparty.maths import *;
from src.thirdparty.render import *;
from src.maths.diagrams import *;
@ -32,11 +33,13 @@ class FunctionDiagramWidget():
N_max: int;
fnames: list[str];
setnames: list[str];
setsfrom: list[list[Any]];
def __init__(
self,
fnames: list[str],
setnames: list[str],
setsfrom: dict[str, list[Any]] | list[list[Any]] = [],
N: Optional[int] = None,
):
self.state = None;
@ -45,6 +48,19 @@ class FunctionDiagramWidget():
assert len(setnames) == len(fnames) + 1, f'The number of sets must be {self.N_max+1}.';
self.fnames = fnames;
self.setnames = setnames;
# fix set contents:
if isinstance(setsfrom, dict):
default = randomset_alphabet(mode=Letters.ROMAN, shuffle=True, full=True);
setsfrom = [ setsfrom.get(name, default) for name in setnames ];
if len(setsfrom) == 0:
setsfrom = [
randomset_alphabet(mode=Letters.SYMBOLS, shuffle=True, full=True),
randomset_alphabet(mode=Letters.ROMAN, shuffle=True, full=True),
randomset_alphabet(mode=Letters.HEBREW, shuffle=True, full=True),
randomset_alphabet(mode=Letters.GREEK, shuffle=True, full=True),
];
n = len(setsfrom);
self.setsfrom = [ setsfrom[k % n] for k, name in enumerate(setnames) ];
def run(self):
if self.N is None:
@ -59,7 +75,7 @@ class FunctionDiagramWidget():
cardinalities = [ kwargs[f'card_{k}'] for k in range(N+1)];
injective = [ kwargs[f'injective_{k}'] for k in range(N)];
surjective = [ kwargs[f'surjective_{k}'] for k in range(N)];
X = [ randomset_alphabet(N=card) for card in cardinalities ];
X = [ XX[:card] for XX, card in zip(self.setsfrom, cardinalities) ];
comp = Functions(*[
Function(
name = (f'{self.fnames[k]}', f'{self.setnames[k]}', f'{self.setnames[k+1]}'),
@ -85,38 +101,47 @@ class FunctionDiagramWidget():
return;
def handler_wrapper(self, N: int):
show_labels = widgets.Checkbox(description='Labels anzeigen?', style={'description_width': 'initial'}, visible=True);
button_refresh = widgets.ToggleButton(description='Neu laden');
button_show_labels = widgets.Checkbox(
description = 'Labels anzeigen?',
value = True,
style = {
'description_width': 'initial',
},
visible = True
);
control_nr = widgets.IntSlider(value=N);
controls_card = [
widgets.IntSlider(
value = None,
description = f'|{self.setnames[k]}|',
# value = None,
value = min(3,len(XX)),
description = f'|{setname}|',
min = 1,
max = 24,
max = len(XX),
)
for k in range(N+1)
for setname, XX in zip(self.setnames[:(N+1)], self.setsfrom[:(N+1)])
];
controls_injective = [
widgets.Checkbox(
value = None,
description = f'{self.fnames[k]} injektiv?',
value = False,
description = f'{fname} injektiv?',
style = {
'description_width': 'initial',
},
visible = True,
)
for k in range(N)
for fname in self.fnames[:N]
];
controls_surjective = [
widgets.Checkbox(
value = None,
description = f'{self.fnames[k]} surjectiv?',
value = False,
description = f'{fname} surjectiv?',
style = {
'description_width': 'initial',
},
visible = True,
)
for k in range(N)
for fname in self.fnames[:N]
];
# controls_func = [None for _ in range(2*N)];
# controls_func[::2] = controls_injective;
@ -136,19 +161,33 @@ class FunctionDiagramWidget():
# for k in range(N)
# ];
ui = widgets.VBox(
[show_labels] \
[ button_refresh ] \
+ [ button_show_labels ] \
+ controls_card \
+ [
widgets.HBox([control_injective, control_surjective])
for control_injective, control_surjective in zip(controls_injective, controls_surjective)
]
widgets.HBox(
[
widgets.VBox(
[control_injective, control_surjective],
layout = {
'display': 'flex',
'align_items': 'stretch',
'width': '100%',
'overflow': 'hidden',
},
)
for control_injective, control_surjective in zip(controls_injective, controls_surjective)
],
)
],
);
display(ui);
display(widgets.interactive_output(
f = self.handler_plot,
controls = { 'N': control_nr, 'show_labels': show_labels } \
controls = { 'N': control_nr, 'show_labels': button_show_labels } \
| { f'card_{k}': controls_card[k] for k in range(N+1) } \
| { f'injective_{k}': controls_injective[k] for k in range(N) } \
| { f'surjective_{k}': controls_surjective[k] for k in range(N) }
| { f'surjective_{k}': controls_surjective[k] for k in range(N) } \
| { 'refresh': button_refresh }
));
return;