final presentation, restructure of the repository, updated code to have weighted probabilities and more

This commit is contained in:
Tom
2026-07-24 17:33:59 +02:00
parent c129ba7206
commit 1a4e53b30a
20 changed files with 3290 additions and 2969 deletions

View File

@@ -30,18 +30,6 @@ def Continue(title="") -> None:
print()
# def MainMenu() -> None:
# global currentFunction
# options = ["Simulator", "Calculator", "Quit"]
# actions: list[Callable[[], None]] = [SimulatorMenu, StopApplication]
# selectedIndex = ShowMenu(
# options, title="Boolean Network Simulator\nby Tom Zuidberg"
# )
# currentFunction = actions[selectedIndex]
def StopApplication() -> None:
quit()
@@ -151,11 +139,14 @@ def BooleanNetworkMenu(
functionStrings: list = [None for _ in range(3)]
functionsDirtyFlag = False
current_highlight = 0
functions_highlight = 0
probFunctionStrings: list[list[str]] = [[] for _ in range(3)]
if bn is not None and funcStrings is not None and funcs is not None:
boolNetwork = bn
functions = funcs
functionStrings = funcStrings
probFunctionStrings = [[] for _ in range(boolNetwork.size)]
def Menu() -> None:
nonlocal current_highlight
@@ -164,10 +155,7 @@ def BooleanNetworkMenu(
f"Set size (current: {boolNetwork.size}) WARNING: this will reset all other options!",
f"Set state (current: {str(boolNetwork)[-boolNetwork.size :]})",
f"Set update scheme (current: {boolNetwork.updateScheme})",
*[
f"Set update function of node x{i} (current: {functionStrings[i - 1]})"
for i in range(1, boolNetwork.size + 1)
],
"Edit update functions",
None,
"Update once (hold ENTER for continuous updates)",
"Update multiple times",
@@ -182,7 +170,7 @@ def BooleanNetworkMenu(
SetSizeHelper,
SetStateHelper,
SetUpdateSchemeHelper,
*[partial(SetFunctionHelper, i) for i in range(boolNetwork.size)],
FunctionsMenu,
None,
UpdateHelper,
MultiUpdateHelper,
@@ -204,7 +192,7 @@ def BooleanNetworkMenu(
actions[selectedIndex]()
def SetSizeHelper() -> None:
nonlocal boolNetwork, functions, functionStrings
nonlocal boolNetwork, functions, functionStrings, probFunctionStrings
while True:
size = input("Set new size (Leave empty to cancel):\n").strip()
if size == "":
@@ -219,6 +207,7 @@ def BooleanNetworkMenu(
boolNetwork = BooleanNetwork(size)
functions = [None for _ in range(size)]
functionStrings = [None for _ in range(size)]
probFunctionStrings = [[] for _ in range(size)]
return
def SetStateHelper() -> None:
@@ -237,9 +226,32 @@ def BooleanNetworkMenu(
print("Invalid input:", e)
def SetUpdateSchemeHelper() -> None:
nonlocal boolNetwork
nonlocal boolNetwork, functions, functionStrings, functionsDirtyFlag
def AdoptFromProbabilistic() -> None:
nonlocal functionsDirtyFlag
for i in range(boolNetwork.size):
if probFunctionStrings[i]:
funcString = probFunctionStrings[i][0]
func = eval(
"lambda "
+ ",".join(f"x{j}" for j in range(1, boolNetwork.size + 1))
+ ":"
+ funcString
)
functions[i] = func
functionStrings[i] = funcString
functionsDirtyFlag = True
def SwitchToSynchronous() -> None:
wasProbabilistic = boolNetwork.updateScheme == "probabilistic"
boolNetwork.UseSynchronousScheme()
if wasProbabilistic:
AdoptFromProbabilistic()
def SetSequentialHelper() -> None:
wasProbabilistic = boolNetwork.updateScheme == "probabilistic"
while True:
seq = input(
"Set sequence. (Leave empty to cancel)\nFormat example: '1,4,3,2'\n"
@@ -252,26 +264,24 @@ def BooleanNetworkMenu(
try:
seq = [int(i) for i in seq]
boolNetwork.UseSequentialScheme(seq)
if wasProbabilistic:
AdoptFromProbabilistic()
return
except Exception as e:
print("Invalid input:", e)
def SetProbabilisticHelper() -> None:
while True:
chance = input(
"Set flip chance as float between 0.0 and 1.0. (Leave empty to cancel)\n"
).strip()
if chance == "":
print("Cancelled")
return
def SwitchToAsyncRandom() -> None:
wasProbabilistic = boolNetwork.updateScheme == "probabilistic"
boolNetwork.UseAsynchronousRandomScheme()
if wasProbabilistic:
AdoptFromProbabilistic()
try:
chance = float(chance)
boolNetwork.UseProbabilisticScheme(chance)
return
except Exception as e:
print("Invalid input:", e)
def SwitchToProbabilistic() -> None:
for i in range(boolNetwork.size):
if not probFunctionStrings[i] and functions[i] is not None:
boolNetwork.AddProbabilisticFunction(i, functions[i], 1.0)
probFunctionStrings[i].append(functionStrings[i])
boolNetwork.UseProbabilisticScheme()
title = "Select update scheme:"
options = [
@@ -282,15 +292,120 @@ def BooleanNetworkMenu(
"Cancel",
]
actions = [
lambda: boolNetwork.UseSynchronousScheme(),
SwitchToSynchronous,
SetSequentialHelper,
SetProbabilisticHelper,
lambda: boolNetwork.UseAsynchronousRandomScheme(),
SwitchToProbabilistic,
SwitchToAsyncRandom,
lambda: None,
]
actions[ShowMenu(options=options, title=title)]()
def FunctionsMenu() -> None:
nonlocal functions_highlight
done: bool = False
def Menu() -> None:
nonlocal functions_highlight
title = "Edit update functions:"
deleteTargets: list = []
if boolNetwork.updateScheme in ("synchronous", "sequential", None):
options = [
*[
f"Set update function of node x{i} (current: {functionStrings[i - 1]})"
for i in range(1, boolNetwork.size + 1)
],
None,
"Return",
]
actions = [
*[partial(SetFunctionHelper, i) for i in range(boolNetwork.size)],
None,
ReturnHelper,
]
elif boolNetwork.updateScheme == "asynchronous_random":
options = [
*[
f"Set update function of node x{i} (current: {functionStrings[i - 1]})"
for i in range(1, boolNetwork.size + 1)
],
None,
*[
f"Set selection weight of node x{i} (current: {boolNetwork.node_selection_weights[i - 1]})"
for i in range(1, boolNetwork.size + 1)
],
None,
"Return",
]
actions = [
*[partial(SetFunctionHelper, i) for i in range(boolNetwork.size)],
None,
*[partial(SetNodeWeightHelper, i) for i in range(boolNetwork.size)],
None,
ReturnHelper,
]
else: # probabilistic
title = "Edit update functions:\n(highlight a function entry and press 'd' to delete it)"
options = []
actions = []
for i in range(boolNetwork.size):
for j in range(len(probFunctionStrings[i])):
options.append(
f"Set update function #{j + 1} of node x{i + 1} (current: {probFunctionStrings[i][j]})"
)
actions.append(partial(EditProbFunctionHelper, i, j))
deleteTargets.append((i, j))
options.append(
f"Set weight of function #{j + 1} of node x{i + 1} (current: {boolNetwork.probabilistic_weights[i][j]})"
)
actions.append(partial(EditProbWeightHelper, i, j))
deleteTargets.append(None)
options.append(f"Add new function for node x{i + 1}")
actions.append(partial(AddProbFunctionHelper, i))
deleteTargets.append(None)
options.append(None)
actions.append(None)
deleteTargets.append(None)
options.append("Return")
actions.append(ReturnHelper)
deleteTargets.append(None)
if boolNetwork.updateScheme == "probabilistic":
menu = TerminalMenu(
menu_entries=options,
title=title,
multi_select=False,
cursor_index=functions_highlight,
accept_keys=("enter", "d"),
)
selectedIndex = menu.show()
if selectedIndex is None:
selectedIndex = len(options) - 1
acceptKey = "enter"
else:
acceptKey = menu.chosen_accept_key
functions_highlight = selectedIndex
if acceptKey == "d" and deleteTargets[selectedIndex] is not None:
DeleteProbFunctionHelper(*deleteTargets[selectedIndex])
else:
actions[selectedIndex]()
return
selectedIndex = ShowMenu(
options=options, title=title, highlight_entry=functions_highlight
)
functions_highlight = selectedIndex
actions[selectedIndex]()
def ReturnHelper() -> None:
nonlocal done
done = True
while not done:
Menu()
def UpdateHelper() -> None:
nonlocal functions, boolNetwork, functionsDirtyFlag
if functionsDirtyFlag:
@@ -377,6 +492,115 @@ def BooleanNetworkMenu(
except Exception as e:
print("Error while parsing function:", e)
def SetNodeWeightHelper(index: int) -> None:
nonlocal boolNetwork
while True:
weight = input(
f"Set new selection weight for node x{index + 1}. Must be a positive number. (Leave empty to cancel)\n"
).strip()
if weight == "":
print("Cancelled")
return
try:
weight = float(weight)
boolNetwork.SetNodeSelectionWeight(index, weight)
return
except Exception as e:
print("Invalid input:", e)
def AddProbFunctionHelper(index: int) -> None:
nonlocal boolNetwork, probFunctionStrings
while True:
funcString = input(
f"Set new function for node x{index + 1}. The function will receive all nodes in form of x1, x2, ..., x[size]. (Leave empty to cancel)\n"
)
if funcString == "":
print("Cancelled")
return
try:
func = (
"lambda "
+ ",".join(f"x{i}" for i in range(1, boolNetwork.size + 1))
+ ":"
+ funcString
)
func = eval(func)
if not isinstance(func, FunctionType):
print("Please enter a valid function. Got: " + func)
continue
except Exception as e:
print("Error while parsing function:", e)
continue
weight = 1.0
weightInput = input(
"Set weight for this function. Must be a positive number. (Leave empty for default 1.0)\n"
).strip()
if weightInput != "":
try:
weight = float(weightInput)
except ValueError:
print("Invalid weight, using default 1.0")
weight = 1.0
try:
boolNetwork.AddProbabilisticFunction(index, func, weight)
probFunctionStrings[index].append(funcString)
return
except Exception as e:
print("Error while adding function:", e)
def EditProbFunctionHelper(index: int, function_index: int) -> None:
nonlocal boolNetwork, probFunctionStrings
while True:
funcString = input(
f"Set new function for node x{index + 1}, function #{function_index + 1}. (Leave empty to cancel)\n"
)
if funcString == "":
print("Cancelled")
return
try:
func = (
"lambda "
+ ",".join(f"x{i}" for i in range(1, boolNetwork.size + 1))
+ ":"
+ funcString
)
func = eval(func)
if not isinstance(func, FunctionType):
print("Please enter a valid function. Got: " + func)
continue
boolNetwork.SetProbabilisticFunction(index, function_index, func)
probFunctionStrings[index][function_index] = funcString
return
except Exception as e:
print("Error while parsing function:", e)
def EditProbWeightHelper(index: int, function_index: int) -> None:
nonlocal boolNetwork
while True:
weight = input(
f"Set new weight for node x{index + 1}, function #{function_index + 1}. Must be a positive number. (Leave empty to cancel)\n"
).strip()
if weight == "":
print("Cancelled")
return
try:
weight = float(weight)
boolNetwork.SetProbabilisticFunctionWeight(index, function_index, weight)
return
except Exception as e:
print("Invalid input:", e)
def DeleteProbFunctionHelper(index: int, function_index: int) -> None:
nonlocal boolNetwork, probFunctionStrings
try:
boolNetwork.RemoveProbabilisticFunction(index, function_index)
del probFunctionStrings[index][function_index]
except Exception as e:
print("Error while deleting function:", e)
Continue()
def ToggleWriteToFileHelper():
nonlocal writeToFile
writeToFile = not writeToFile