Compare commits

..

No commits in common. "c2ac8e4c13dd5a3b821b8f98f499a5d319e5b181" and "240c6737620086a9f2ece3dfeb308e47ccef4f22" have entirely different histories.

4 changed files with 111 additions and 195 deletions

View File

@ -224,9 +224,6 @@ _display-logs:
@- cat logs/debug.log @- cat logs/debug.log
@echo "" @echo ""
@echo "----------------" @echo "----------------"
logs:
@just _create-logs
@tail -f logs/debug.log &
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: processes # TARGETS: processes

View File

@ -22,9 +22,8 @@
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"# imports\n",
"import os;\n", "import os;\n",
"import sys; \n", "import sys;\n",
"\n", "\n",
"# NOTE: need this to force jupyter to reload imports:\n", "# NOTE: need this to force jupyter to reload imports:\n",
"for key in list(sys.modules.keys()):\n", "for key in list(sys.modules.keys()):\n",
@ -50,21 +49,11 @@
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"# Userinput - Anzahl der Funktionen\n", "FunctionDiagramWidget(\n",
"fnames = ['f', 'g', 'h', 'i', 'j'];\n", " N = 2,\n",
"setnames = ['X', 'Y', 'Z', 'U', 'V', 'W'];\n", " fnames = ['f', 'g', 'h', 'i', 'j'],\n",
"ctrl = widgets.IntSlider(value=1, description=f'# Funktionen', min=1, max=len(fnames));\n", " setnames = ['X', 'Y', 'Z', 'U', 'V', 'W'],\n",
"display(ctrl);" ").run();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Widget - Mengen und Funktionen\n",
"FunctionDiagramWidget(N=ctrl.value, fnames=fnames, setnames=setnames).run();"
] ]
}, },
{ {

View File

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

View File

@ -52,12 +52,6 @@ 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],
@ -66,7 +60,7 @@ class FunctionDiagramWidget():
N: Optional[int] = None, N: Optional[int] = None,
): ):
self.state = None; self.state = None;
self.N = N or 1; self.N = N;
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;
@ -87,23 +81,35 @@ 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:
Runs the widget. control_nr = widgets.IntSlider(description=f'# Funktionen', min=1, max=self.N_max);
''' display(control_nr);
self.create_widgets(); else:
display(widgets.interactive_output( control_nr = widgets.IntSlider(value=self.N);
f = self.handler_main, self.state = widgets.interactive_output(self.handler_wrapper, controls={'N': control_nr});
controls = {'N': self.ctrl_nr}, display(self.state);
));
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 create_widgets(self): def handler_wrapper(self, N: int):
''' button_refresh = widgets.ToggleButton(description='Neu laden');
Initialises the widgets. button_show_labels = widgets.Checkbox(
'''
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 = {
@ -111,31 +117,21 @@ class FunctionDiagramWidget():
}, },
visible = True visible = True
); );
self.ctrl_nr = widgets.IntSlider(value=self.N, description=f'# Funktionen', min=1, max=self.N_max); control_nr = widgets.IntSlider(value=N);
cards_max = [ len(XX) for XX in self.setsfrom ]; controls_card = [
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 = card_max, max = len(XX),
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(self.card[k], self.card[k+1]) ], options = [ e.value for e in possible_properties(all=True) ],
value = FunctionProperty.NOTHING.value, value = FunctionProperty.NOTHING.value,
layout = { layout = {
'description_width': 'initial', 'description_width': 'initial',
@ -145,121 +141,59 @@ class FunctionDiagramWidget():
) )
for k in range(N) for k in range(N)
]; ];
for k, ctrl_card in enumerate(self.ctrls_card): # NOTE: dynamically change the possible properties based on the cardinalities.
ctrl_card.observe(partial(self.handler_upd_card, k=k), names='value'); def update_controls_property(change, k: int):
# FIXME: this does not behave correctly: self.card[k] = change['new'];
self.btn_show_labels.observe(partial(self.handler_plot, create=False)); if k > 0:
return; m = self.card[k-1];
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) ];
def handler_main(self, *_, **__): for k, control_card in enumerate(controls_card):
''' control_card.observe(
Main handler for updating widgets. partial(update_controls_property, k=k),
''' names='value',
N = self.N = self.ctrl_nr.value; );
ui = widgets.VBox([] \
+ [ self.btn_refresh ] \ ui = widgets.VBox(
+ [ self.btn_show_labels ] \ [ button_refresh ] \
+ [ widgets.Text(f'Größen den Mengen:') ] \ + [ button_show_labels ] \
+ self.ctrls_card[:(N+1)] \ + controls_card \
+ [widgets.HBox( + [
[ widgets.HBox(
widgets.VBox( [
[ widgets.VBox(
widgets.Text(f'Eigenschaften von {fname}'), [
ctrl_property widgets.Text(f'Eigenschaften von {fname}'),
], control_property
layout = { ],
'description_width': 'initial', layout = {
'width': 'initial', 'description_width': 'initial',
'display': 'flex', 'width': 'initial',
'align_items': 'stretch', 'display': 'flex',
'overflow': 'hidden', 'align_items': 'stretch',
} '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 = dict( controls = { 'N': control_nr, 'show_labels': button_show_labels } \
N = self.ctrl_nr, | { f'card_{k}': controls_card[k] for k in range(N+1) } \
refresh = self.btn_refresh, | { f'property_{k}': controls_property[k] for k in range(N) } \
# FIXME: shoud not have to rely on this: | { 'refresh': button_refresh }
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
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -270,42 +204,36 @@ def option_to_property(option: str) -> Optional[FunctionProperty]:
except: except:
return None; return None;
def possible_properties(m: int = 1, n: int = 1) -> list[FunctionProperty]: def possible_properties(m: int = 1, n: int = 1, all: bool = False) -> list[FunctionProperty]:
if m == n: if not all:
if m == 1: if m == 1 and n == 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])
]; ];
else: elif m == 1 and n > 1:
return [ return [
e for e in FunctionProperty e for e in FunctionProperty
if not (is_surjective(e) in [True] and is_injective(e) in [False]) if (is_injective(e) not in [False])
and not (is_surjective(e) in [False] and is_injective(e) in [True]) 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])
]; ];
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]: