Compare commits

...

4 Commits

Author SHA1 Message Date
RD 56744bd389 master > master: notebook - widgets 2022-10-21 22:10:11 +02:00
RD 6f24f4f635 master > master: src - widgets 2022-10-21 22:08:09 +02:00
RD f9186f0464 master > master: justfile
issue mit jupyter widgets
2022-10-21 22:07:35 +02:00
RD 9a2c87def3 master > master: requirements
issue mit jupyter widgets
2022-10-21 22:07:26 +02:00
8 changed files with 212 additions and 27 deletions

View File

@ -104,6 +104,7 @@ build-misc:
@just _copy-file-if-not-exists "templates/template.env" ".env"
build-requirements:
@{{PYTHON}} -m pip install --disable-pip-version-check -r requirements.txt
@{{PYTHON}} -m jupyter nbextension enable --py widgetsnbextension
build-models:
@echo "Generate data models from schemata."
@just _delete-if-folder-exists "models/generated"

View File

@ -38,6 +38,7 @@
"\n",
"from src.maths.diagrams import *;\n",
"from src.maths.sets import *;\n",
"from src.widgets import *;\n",
"\n",
"np.random.seed(8007253); # zur Wiederholbarkeit"
]
@ -48,6 +49,20 @@
"metadata": {},
"outputs": [],
"source": [
"FunctionDiagramWidget(\n",
" N = 2,\n",
" fnames = ['f', 'g', 'h'],\n",
" setnames = ['X', 'Y', 'Z', 'W'],\n",
").run();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ohne Zufallserzeugung:\n",
"X = ['a', 'b', 'c', 'd', 'e'];\n",
"Y = [2, 3, 5, 7, 11, 13, 17];\n",
"Z = ['α', 'β', 'γ', 'δ'];\n",
@ -59,24 +74,6 @@
");\n",
"comp.draw(show_labels=True);"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"X = randomset_alphabet(N=3);\n",
"Y = randomset_integers(N=5);\n",
"Z = randomset_greek(N=7);\n",
"f = random_function(X, Y, injective=True);\n",
"g = random_function(Y, Z, injective=True);\n",
"comp = Functions(\n",
" Function(name=('f', 'X', 'Y'), domain=X, codomain=Y, fct=f),\n",
" Function(name=('g', 'Y', 'Z'), domain=Y, codomain=Z, fct=g),\n",
");\n",
"comp.draw(show_labels=False);"
]
}
],
"metadata": {

View File

@ -4,6 +4,12 @@ wheel>=0.37.1
# jupyter
ipython>=8.3.0
jupyter>=1.0.0
widgetsnbextension>=3.6.1
# FIXME
# according to https://github.com/microsoft/vscode-jupyter/issues/8552
# need to use v 7.7.2 for now
# ipywidgets>=8.0.2
ipywidgets==7.7.2
# running
codetiming>=1.3.0

View File

@ -63,7 +63,7 @@ class Function(Generic[T1,T2]):
];
return getattr(self, '_indexes');
def draw(self) -> Figure:
def draw(self) -> tuple[Figure, Axes]:
return Functions(self).draw();
class Functions:
@ -74,7 +74,7 @@ class Functions:
self.fcts = list(f);
self.name = r' \circ '.join([ fct.name[0] for fct in self.fcts ][::-1]);
def draw(self, show_labels: bool = True) -> Figure:
def draw(self, show_labels: bool = True) -> tuple[Figure, Axes]:
N = len(self.fcts);
obj = mplot.subplots(1, 1, constrained_layout=True);
fig: Figure = obj[0];
@ -165,8 +165,7 @@ class Functions:
# update range of composition:
comp_range = comp_range_next;
return fig;
return fig, axs;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AUXILIARY

View File

@ -54,6 +54,7 @@ def random_function(
Y: list[T2],
injective: Optional[bool] = None,
surjective: Optional[bool] = None,
force: bool = False,
) -> list[tuple[T1, T2]]:
m = len(X);
n = len(Y);
@ -61,6 +62,15 @@ def random_function(
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.';

View File

@ -10,6 +10,7 @@ from IPython.display import display_latex;
from IPython.display import display_png;
from IPython.display import display_markdown;
from IPython.display import display;
import ipywidgets as widgets;
# from array_to_latex import to_ltx as array_to_latex; # <- has issues
from qiskit.visualization import array_to_latex;
@ -18,10 +19,11 @@ from qiskit.visualization import array_to_latex;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'Latex',
'display',
'display_latex',
'display_png',
'display_markdown',
'array_to_latex',
'display_latex',
'display_markdown',
'display_png',
'display',
'Latex',
'widgets',
];

16
src/widgets/__init__.py Normal file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.widgets.function_diagrams import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'FunctionDiagramWidget',
];

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from __future__ import annotations;
from src.thirdparty.types import *;
from src.thirdparty.plots import *;
from src.thirdparty.render import *;
from src.maths.diagrams import *;
from src.maths.sets import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'FunctionDiagramWidget',
];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class FunctionDiagramWidget():
state: Optional[widgets.Output];
N: Optional[int];
N_max: int;
fnames: list[str];
setnames: list[str];
def __init__(
self,
fnames: list[str],
setnames: list[str],
N: Optional[int] = None,
):
self.state = None;
self.N = N;
self.N_max = len(fnames);
assert len(setnames) == len(fnames) + 1, f'The number of sets must be {self.N_max+1}.';
self.fnames = fnames;
self.setnames = setnames;
def run(self):
if self.N is None:
control_nr = widgets.IntSlider(description=f'# Funktionen', min=1, max=self.N_max);
display(control_nr);
else:
control_nr = widgets.IntSlider(value=self.N);
self.state = widgets.interactive_output(self.handler_wrapper, controls={'N': control_nr});
display(self.state);
def handler_plot(self, N: int, show_labels: bool, **kwargs):
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 ];
comp = Functions(*[
Function(
name = (f'{self.fnames[k]}', f'{self.setnames[k]}', f'{self.setnames[k+1]}'),
domain = X[k],
codomain = X[k+1],
fct = random_function(X[k], X[k+1], injective=injective[k], surjective=surjective[k], force=False)
)
for k in range(N)
]);
fig, axs = comp.draw(show_labels=show_labels);
# for k in range(N):
# [m, n] = cardinalities[k:][:2];
# inj = injective[k];
# surj = surjective[k];
# if m < n and surj:
# print(f'\x1b[1m{self.fnames[k]}\x1b[0m kann nicht surjektiv sein');
# if m > n and inj:
# print(f'\x1b[1m{self.fnames[k]}\x1b[0m kann nicht injektiv sein');
# if n == 1 and not surj:
# print(f'\x1b[1m{self.fnames[k]}\x1b[0m kann nicht nicht-surjektiv sein');
# if m == 1 and not inj:
# print(f'\x1b[1m{self.fnames[k]}\x1b[0m kann nicht nicht-injektiv sein');
return;
def handler_wrapper(self, N: int):
show_labels = widgets.Checkbox(description='Labels anzeigen?', style={'description_width': 'initial'}, visible=True);
control_nr = widgets.IntSlider(value=N);
controls_card = [
widgets.IntSlider(
value = None,
description = f'|{self.setnames[k]}|',
min = 1,
max = 24,
)
for k in range(N+1)
];
controls_injective = [
widgets.Checkbox(
value = None,
description = f'{self.fnames[k]} injektiv?',
style = {
'description_width': 'initial',
},
visible = True,
)
for k in range(N)
];
controls_surjective = [
widgets.Checkbox(
value = None,
description = f'{self.fnames[k]} surjectiv?',
style = {
'description_width': 'initial',
},
visible = True,
)
for k in range(N)
];
# controls_func = [None for _ in range(2*N)];
# controls_func[::2] = controls_injective;
# controls_func[1::2] = controls_surjective;
# controls_func = [
# widgets.RadioButtons(
# options = [ None, 'inj', 'surj', 'bij' ],
# # default:
# value = 'inj',
# layout = {
# 'description_width': 'initial',
# 'width': 'max-content',
# },
# description = f'{self.fnames[k]}',
# disabled = False,
# )
# for k in range(N)
# ];
ui = widgets.VBox(
[show_labels] \
+ controls_card \
+ [
widgets.HBox([control_injective, control_surjective])
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 } \
| { 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) }
));
return;