diff --git a/src/widgets/function_diagrams.py b/src/widgets/function_diagrams.py index 596d7cf..bdbd958 100644 --- a/src/widgets/function_diagrams.py +++ b/src/widgets/function_diagrams.py @@ -23,6 +23,21 @@ __all__ = [ 'FunctionDiagramWidget', ]; +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# EXPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class FunctionProperty(Enum): + NOTHING = '—'; + INJECTIVE = 'injektiv'; + SURJECTIVE = 'surjektiv'; + NOT_INJECTIVE = '¬ injektiv'; + NOT_SURJECTIVE = '¬ surjektiv'; + INJECTIVE_NOT_SURJECTIVE = 'injektiv + ¬ surjektiv'; + NOT_INJECTIVE_SURJECTIVE = '¬ injektiv + surjektiv'; + BOTH = 'injektiv + surjektiv'; + NEITHER = '¬ injektiv + ¬ surjektiv'; + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Class # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -73,8 +88,9 @@ class FunctionDiagramWidget(): 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)]; + 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, cardinalities) ]; comp = Functions(*[ Function( @@ -86,18 +102,18 @@ class FunctionDiagramWidget(): 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'); + # # 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): @@ -121,45 +137,19 @@ class FunctionDiagramWidget(): ) for setname, XX in zip(self.setnames[:(N+1)], self.setsfrom[:(N+1)]) ]; - controls_injective = [ - widgets.Checkbox( - value = False, - description = f'{fname} injektiv?', - style = { + controls_property = [ + widgets.RadioButtons( + options = [e.value for e in FunctionProperty], + value = FunctionProperty.NOTHING.value, + layout = { 'description_width': 'initial', + 'width': 'initial', }, - visible = True, + # description = f'Eigenschaften von {self.fnames[k]}', + disabled = False, ) - for fname in self.fnames[:N] + for k in range(N) ]; - controls_surjective = [ - widgets.Checkbox( - value = False, - description = f'{fname} surjectiv?', - style = { - 'description_width': 'initial', - }, - visible = True, - ) - for fname in self.fnames[: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( [ button_refresh ] \ + [ button_show_labels ] \ @@ -168,15 +158,19 @@ class FunctionDiagramWidget(): widgets.HBox( [ widgets.VBox( - [control_injective, control_surjective], + [ + widgets.Text(f'Eigenschaften von {fname}'), + control_property + ], layout = { + 'description_width': 'initial', + 'width': 'initial', 'display': 'flex', 'align_items': 'stretch', - 'width': '100%', 'overflow': 'hidden', - }, + } ) - for control_injective, control_surjective in zip(controls_injective, controls_surjective) + for fname, control_property in zip(self.fnames[:N], controls_property) ], ) ], @@ -186,8 +180,33 @@ class FunctionDiagramWidget(): f = self.handler_plot, 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'property_{k}': controls_property[k] for k in range(N) } \ | { 'refresh': button_refresh } )); return; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# AUXILIARY METHODS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def option_to_property(option: str) -> Optional[FunctionProperty]: + try: + return FunctionProperty(option); + except: + return None; + +def is_injective(property: Optional[FunctionProperty]) -> Optional[bool]: + match property: + case FunctionProperty.INJECTIVE | FunctionProperty.INJECTIVE_NOT_SURJECTIVE | FunctionProperty.BOTH: + return True; + case FunctionProperty.NOT_INJECTIVE | FunctionProperty.NOT_INJECTIVE_SURJECTIVE | FunctionProperty.NEITHER: + return False; + return None; + +def is_surjective(property: Optional[FunctionProperty]) -> Optional[bool]: + match property: + case FunctionProperty.SURJECTIVE | FunctionProperty.NOT_INJECTIVE_SURJECTIVE | FunctionProperty.BOTH: + return True; + case FunctionProperty.NOT_SURJECTIVE | FunctionProperty.INJECTIVE_NOT_SURJECTIVE | FunctionProperty.NEITHER: + return False; + return None;