master > master: src - cleanup

This commit is contained in:
RD 2022-10-23 14:13:02 +02:00
parent 8d585f96c7
commit dc5918682c
2 changed files with 175 additions and 105 deletions

View File

@ -22,9 +22,7 @@ __all__ = [
'GetState', 'GetState',
'CallValue', 'CallValue',
'CallError', 'CallError',
'keep_calm_and_carry_on',
'run_safely', 'run_safely',
'to_async',
]; ];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -52,6 +52,12 @@ class FunctionDiagramWidget():
setsfrom: list[list[Any]]; setsfrom: list[list[Any]];
card: list[int]; card: list[int];
ctrl_nr: widgets.IntSlider;
btn_refresh: widgets.ToggleButton;
ctrls_card: list[widgets.IntSlider];
ctrls_property: list[widgets.IntSlider];
fcts: Functions;
def __init__( def __init__(
self, self,
fnames: list[str], fnames: list[str],
@ -60,7 +66,7 @@ class FunctionDiagramWidget():
N: Optional[int] = None, N: Optional[int] = None,
): ):
self.state = None; self.state = None;
self.N = N; self.N = N or 1;
self.N_max = len(fnames); self.N_max = len(fnames);
assert len(setnames) == len(fnames) + 1, f'The number of sets must be {self.N_max+1}.'; assert len(setnames) == len(fnames) + 1, f'The number of sets must be {self.N_max+1}.';
self.fnames = fnames; self.fnames = fnames;
@ -81,35 +87,23 @@ class FunctionDiagramWidget():
self.card = [ min(3, len(XX)) for XX in self.setsfrom ]; self.card = [ min(3, len(XX)) for XX in self.setsfrom ];
def run(self): def run(self):
if self.N is None: '''
control_nr = widgets.IntSlider(description=f'# Funktionen', min=1, max=self.N_max); Runs the widget.
display(control_nr); '''
else: self.create_widgets();
control_nr = widgets.IntSlider(value=self.N); display(widgets.interactive_output(
self.state = widgets.interactive_output(self.handler_wrapper, controls={'N': control_nr}); f = self.handler_main,
display(self.state); controls = {'N': self.ctrl_nr},
));
def handler_plot(self, N: int, show_labels: bool, **kwargs):
self.card[:(N+1)] = [ kwargs[f'card_{k}'] for k in range(N+1) ];
properties = [ option_to_property(kwargs[f'property_{k}']) for k in range(N)];
injective = list(map(is_injective, properties));
surjective = list(map(is_surjective, properties));
X = [ XX[:card] for XX, card in zip(self.setsfrom[:(N+1)], self.card[:(N+1)]) ];
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);
return; return;
def handler_wrapper(self, N: int): def create_widgets(self):
button_refresh = widgets.ToggleButton(description='Neu laden'); '''
button_show_labels = widgets.Checkbox( Initialises the widgets.
'''
N = self.N_max;
self.btn_refresh = widgets.ToggleButton(description='Neu laden');
self.btn_show_labels = widgets.Checkbox(
description = 'Labels anzeigen?', description = 'Labels anzeigen?',
value = True, value = True,
style = { style = {
@ -117,21 +111,31 @@ class FunctionDiagramWidget():
}, },
visible = True visible = True
); );
control_nr = widgets.IntSlider(value=N); self.ctrl_nr = widgets.IntSlider(value=self.N, description=f'# Funktionen', min=1, max=self.N_max);
controls_card = [ cards_max = [ len(XX) for XX in self.setsfrom ];
card_max_max = max(cards_max);
self.ctrls_card = [
widgets.IntSlider( widgets.IntSlider(
value = card, value = card,
description = f'|{setname}|', description = f'|{setname}|',
min = 1, min = 1,
max = len(XX), max = card_max,
layout = {
'width': 'initial',
# FIXME: scales wrong:
# 'width': f'{100*cards_max/card_max_max}%',
},
)
for setname, XX, card, card_max in zip(
self.setnames[:(N+1)],
self.setsfrom[:(N+1)],
self.card[:(N+1)],
cards_max[:(N+1)],
) )
for setname, XX, card in zip(self.setnames[:(N+1)], self.setsfrom[:(N+1)], self.card[:(N+1)])
]; ];
self.ctrls_property = [
# controls for properties of functions
controls_property = [
widgets.RadioButtons( widgets.RadioButtons(
options = [ e.value for e in possible_properties(all=True) ], options = [ e.value for e in possible_properties(self.card[k], self.card[k+1]) ],
value = FunctionProperty.NOTHING.value, value = FunctionProperty.NOTHING.value,
layout = { layout = {
'description_width': 'initial', 'description_width': 'initial',
@ -141,59 +145,121 @@ class FunctionDiagramWidget():
) )
for k in range(N) for k in range(N)
]; ];
# NOTE: dynamically change the possible properties based on the cardinalities. for k, ctrl_card in enumerate(self.ctrls_card):
def update_controls_property(change, k: int): ctrl_card.observe(partial(self.handler_upd_card, k=k), names='value');
self.card[k] = change['new']; # FIXME: this does not behave correctly:
if k > 0: self.btn_show_labels.observe(partial(self.handler_plot, create=False));
m = self.card[k-1]; return;
n = self.card[k];
controls_property[k-1].options = [ e.value for e in possible_properties(m, n) ];
if k < N:
m = self.card[k];
n = self.card[k+1];
controls_property[k].options = [ e.value for e in possible_properties(m, n) ];
for k, control_card in enumerate(controls_card): def handler_main(self, *_, **__):
control_card.observe( '''
partial(update_controls_property, k=k), Main handler for updating widgets.
names='value', '''
); N = self.N = self.ctrl_nr.value;
ui = widgets.VBox([] \
ui = widgets.VBox( + [ self.btn_refresh ] \
[ button_refresh ] \ + [ self.btn_show_labels ] \
+ [ button_show_labels ] \ + [ widgets.Text(f'Größen den Mengen:') ] \
+ controls_card \ + self.ctrls_card[:(N+1)] \
+ [ + [widgets.HBox(
widgets.HBox( [
[ widgets.VBox(
widgets.VBox( [
[ widgets.Text(f'Eigenschaften von {fname}'),
widgets.Text(f'Eigenschaften von {fname}'), ctrl_property
control_property ],
], layout = {
layout = { 'description_width': 'initial',
'description_width': 'initial', 'width': 'initial',
'width': 'initial', 'display': 'flex',
'display': 'flex', 'align_items': 'stretch',
'align_items': 'stretch', 'overflow': 'hidden',
'overflow': 'hidden', }
} )
) for fname, ctrl_property in zip(self.fnames[:N], self.ctrls_property[:N])
for fname, control_property in zip(self.fnames[:N], controls_property) ],
], )],
)
],
); );
display(ui); display(ui);
display(widgets.interactive_output( display(widgets.interactive_output(
f = self.handler_plot, f = self.handler_plot,
controls = { 'N': control_nr, 'show_labels': button_show_labels } \ controls = dict(
| { f'card_{k}': controls_card[k] for k in range(N+1) } \ N = self.ctrl_nr,
| { f'property_{k}': controls_property[k] for k in range(N) } \ refresh = self.btn_refresh,
| { 'refresh': button_refresh } # FIXME: shoud not have to rely on this:
show_labels = self.btn_show_labels,
**{
f'card[{k}]': ctrl_card
for k, ctrl_card in enumerate(self.ctrls_card)
},
**{
f'property[{k}]': ctrl_property
for k, ctrl_property in enumerate(self.ctrls_property)
},
),
)); ));
return; return;
def handler_plot(self, *_, create: bool = True, **__):
'''
Method to create sets, functions, and plot.
'''
self.card = [ ctrl_card.value for ctrl_card in self.ctrls_card ];
if create:
N = self.N;
options = list(map(lambda ctrl: ctrl.value, self.ctrls_property[:N]));
properties = list(map(option_to_property, options));
injective = list(map(is_injective, properties));
surjective = list(map(is_surjective, properties));
sets = [ XX[:card] for XX, card in zip(self.setsfrom[:(N+1)], self.card[:(N+1)]) ];
self.fcts = Functions(*[
Function(
name = (fname, nameX, nameY),
domain = X,
codomain = Y,
fct = random_function(X, Y, injective=inj, surjective=surj, force=False),
)
for fname, nameX, nameY, X, Y, inj, surj in zip(
self.fnames,
self.setnames,
self.setnames[1:],
sets,
sets[1:],
injective,
surjective,
)
]);
# FIXME:
# upon toggling show labels button, this even triggers multiple times,
# and only the old value registers.
show_labels = self.btn_show_labels.value;
fig, axs = self.fcts.draw(show_labels=show_labels);
return;
def handler_upd_card(self, change, k: int):
'''
Handler for altering function property options
upon change of set cardinality.
'''
self.card[k] = change['new'];
def upd(j: int):
m = self.card[j];
n = self.card[j+1];
value = self.ctrls_property[j].value;
options = [ e.value for e in possible_properties(m, n) ];
if value not in options:
value = FunctionProperty.NOTHING.value;
self.ctrls_property[j].options = options;
self.ctrls_property[j].value = value;
return;
if k > 0:
upd(k-1);
if k < self.N:
upd(k);
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AUXILIARY METHODS # AUXILIARY METHODS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -204,36 +270,42 @@ def option_to_property(option: str) -> Optional[FunctionProperty]:
except: except:
return None; return None;
def possible_properties(m: int = 1, n: int = 1, all: bool = False) -> list[FunctionProperty]: def possible_properties(m: int = 1, n: int = 1) -> list[FunctionProperty]:
if not all: if m == n:
if m == 1 and n == 1: if m == 1:
return [ return [
e for e in FunctionProperty e for e in FunctionProperty
if (is_injective(e) not in [False]) if (is_injective(e) not in [False])
and (is_surjective(e) not in [False]) and (is_surjective(e) not in [False])
]; ];
elif m == 1 and n > 1: else:
return [ return [
e for e in FunctionProperty e for e in FunctionProperty
if (is_injective(e) not in [False]) if not (is_surjective(e) in [True] and is_injective(e) in [False])
and (is_surjective(e) not in [True]) and not (is_surjective(e) in [False] and is_injective(e) in [True])
];
elif n == 1 and m > 1:
return [
e for e in FunctionProperty
if (is_surjective(e) not in [False])
and (is_injective(e) not in [True])
];
elif m > n:
return [
e for e in FunctionProperty
if (is_injective(e) not in [True])
];
elif n > m:
return [
e for e in FunctionProperty
if (is_surjective(e) not in [True])
]; ];
elif m == 1 and n > 1:
return [
e for e in FunctionProperty
if (is_injective(e) not in [False])
and (is_surjective(e) not in [True])
];
elif n == 1 and m > 1:
return [
e for e in FunctionProperty
if (is_surjective(e) not in [False])
and (is_injective(e) not in [True])
];
elif m > n:
return [
e for e in FunctionProperty
if (is_injective(e) not in [True])
];
elif n > m:
return [
e for e in FunctionProperty
if (is_surjective(e) not in [True])
];
return [ e for e in FunctionProperty ]; return [ e for e in FunctionProperty ];
def is_injective(property: Optional[FunctionProperty]) -> Optional[bool]: def is_injective(property: Optional[FunctionProperty]) -> Optional[bool]: