Files
Gene-Regulatory-Networks-Se…/code/main.py

404 lines
13 KiB
Python

from functools import partial
from types import FunctionType
from typing import Callable, Optional
import numpy as np
from simple_term_menu import TerminalMenu
from typing_extensions import Concatenate
from simulator import BooleanNetwork
def ShowMenu(options: list[str], title: str = "", highlight_entry: int = 0) -> int:
menu = TerminalMenu(
menu_entries=options,
title=title,
multi_select=False,
cursor_index=highlight_entry,
)
selectedIndex = menu.show()
if selectedIndex is None:
selectedIndex = len(options) - 1
return selectedIndex # pyright: ignore[reportReturnType]
def Continue(title="") -> None:
ShowMenu(title=title, options=[None, "Continue"], highlight_entry=1)
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()
def MainMenu() -> None:
global currentFunction
def SelectExampleMenu() -> None:
def bn4nodeSync() -> None:
functions = [
lambda x1, x2, x3, x4: not x2,
lambda x1, x2, x3, x4: x1,
lambda x1, x2, x3, x4: x1 ^ x4,
lambda x1, x2, x3, x4: x3,
]
bn = BooleanNetwork(4).UseSynchronousScheme().SetFunctions(functions)
global currentFunction
funcStrings = ["not x2", "x1", "x1 ^ x4", "x3"]
currentFunction = partial(BooleanNetworkMenu, bn, functions, funcStrings)
def bn4nodeSeq() -> None:
functions = [
lambda x1, x2, x3, x4: not x2,
lambda x1, x2, x3, x4: x1,
lambda x1, x2, x3, x4: x1 ^ x4,
lambda x1, x2, x3, x4: x3,
]
bn = (
BooleanNetwork(4)
.UseSequentialScheme([1, 2, 3, 4])
.SetFunctions(functions)
)
global currentFunction
funcStrings = ["not x2", "x1", "x1 ^ x4", "x3"]
currentFunction = partial(BooleanNetworkMenu, bn, functions, funcStrings)
def bn3nodeSync() -> None:
functions = [
lambda x1, x2, x3: not x3,
lambda x1, x2, x3: not x1,
lambda x1, x2, x3: not x2,
]
bn = BooleanNetwork(3).UseSynchronousScheme().SetFunctions(functions)
global currentFunction
funcStrings = ["not x3", "not x1", "not x2"]
currentFunction = partial(BooleanNetworkMenu, bn, functions, funcStrings)
def bn3nodeSeq() -> None:
functions = [
lambda x1, x2, x3: not x3,
lambda x1, x2, x3: not x1,
lambda x1, x2, x3: not x2,
]
bn = (
BooleanNetwork(3).UseSequentialScheme([1, 2, 3]).SetFunctions(functions)
)
global currentFunction
funcStrings = ["not x3", "not x1", "not x2"]
currentFunction = partial(BooleanNetworkMenu, bn, functions, funcStrings)
def ReturnHelper() -> None:
global currentFunction
currentFunction = MainMenu
title = "Select an example boolean network:"
options = [
"4-node network with synchronous update",
"4-node network with sequential update",
"3-node repressilator network with synchronous update",
"3-node repressilator network with sequential update",
"Return to main menu",
]
actions = [bn4nodeSync, bn4nodeSeq, bn3nodeSync, bn3nodeSeq, ReturnHelper]
actions[ShowMenu(options=options, title=title)]()
options = [
"Set up a new boolean network",
"Set up a boolean network from existing ones",
"Quit",
]
actions: list[Callable[[], None]] = [
BooleanNetworkMenu,
SelectExampleMenu,
StopApplication,
]
selectedIndex = ShowMenu(
options, title="Boolean Network Simulator\nby Tom Zuidberg"
)
currentFunction = actions[selectedIndex]
def BooleanNetworkMenu(
bn: Optional[BooleanNetwork] = None,
funcs: Optional[list[Callable[Concatenate[bool, ...], bool]]] = None,
funcStrings: Optional[list[str]] = None,
) -> None:
global currentFunction
boolNetwork: BooleanNetwork = BooleanNetwork(3)
writeToFile: bool = False
done: bool = False
functions: list = [None for _ in range(3)]
functionStrings: list = [None for _ in range(3)]
functionsDirtyFlag = False
current_highlight = 0
if bn is not None and funcStrings is not None and funcs is not None:
boolNetwork = bn
functions = funcs
functionStrings = funcStrings
def Menu() -> None:
nonlocal current_highlight
title: str = f"Boolean Network: {boolNetwork} (timeStep | state)"
options = [
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)
],
None,
"Update once (hold ENTER for continuous updates)",
"Update multiple times",
f"Write to file (works only with multi-update) (current: {writeToFile})",
"Get Markov-Chain matrix (resets timeStep and state)",
"Get stationairy distribution (resets timeStep and state)",
None,
"Return to main menu",
]
actions = [
SetSizeHelper,
SetStateHelper,
SetUpdateSchemeHelper,
*[partial(SetFunctionHelper, i) for i in range(boolNetwork.size)],
None,
UpdateHelper,
MultiUpdateHelper,
ToggleWriteToFileHelper,
GetMarkovChainHelper,
GetStableDistrHelper,
None,
ReturnHelper,
]
if boolNetwork.updateScheme in ("synchronous", "sequential", None):
options.pop(-3)
actions.pop(-3)
selectedIndex = ShowMenu(
options=options, title=title, highlight_entry=current_highlight
)
current_highlight = selectedIndex
actions[selectedIndex]()
def SetSizeHelper() -> None:
nonlocal boolNetwork, functions, functionStrings
while True:
size = input("Set new size (Leave empty to cancel):\n").strip()
if size == "":
print("Cancelled")
return
try:
size = int(size)
except ValueError:
print("Please enter only integers.")
continue
boolNetwork = BooleanNetwork(size)
functions = [None for _ in range(size)]
functionStrings = [None for _ in range(size)]
return
def SetStateHelper() -> None:
nonlocal boolNetwork
while True:
state = input(
"Set new state (Leave empty to cancel).\nAccepted format example: '01001'\n"
).strip()
if state == "":
print("Cancelled")
return
try:
boolNetwork.SetState(state)
return
except AssertionError as e:
print("Invalid input:", e)
def SetUpdateSchemeHelper() -> None:
nonlocal boolNetwork
def SetSequentialHelper() -> None:
while True:
seq = input(
"Set sequence. (Leave empty to cancel)\nFormat example: '1,4,3,2'\n"
).strip()
if seq == "":
print("Cancelled")
return
seq = seq.split(",")
try:
seq = [int(i) for i in seq]
boolNetwork.UseSequentialScheme(seq)
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
try:
chance = float(chance)
boolNetwork.UseProbabilisticScheme(chance)
return
except Exception as e:
print("Invalid input:", e)
title = "Select update scheme:"
options = [
"Synchronous update scheme",
"Sequential update scheme",
"Probabilistic update scheme",
"Asynchronous random update scheme",
"Cancel",
]
actions = [
lambda: boolNetwork.UseSynchronousScheme(),
SetSequentialHelper,
SetProbabilisticHelper,
lambda: boolNetwork.UseAsynchronousRandomScheme(),
lambda: None,
]
actions[ShowMenu(options=options, title=title)]()
def UpdateHelper() -> None:
nonlocal functions, boolNetwork, functionsDirtyFlag
if functionsDirtyFlag:
try:
boolNetwork.SetFunctions(functions)
functionsDirtyFlag = False
except Exception as e:
print("Error while updating the functions:", e)
return
try:
boolNetwork.Update()
except Exception as e:
print("Error while simulating once:", e)
def MultiUpdateHelper() -> None:
nonlocal boolNetwork, writeToFile, functions, functionsDirtyFlag
if functionsDirtyFlag:
try:
boolNetwork.SetFunctions(functions)
functionsDirtyFlag = False
except Exception as e:
print("Error while updating functions:", e)
n = 0
while True:
n = input(
"Enter amount of time steps to be simulated. (Leave empty to cancel)\n"
).strip()
if n == "":
print("Cancelled")
return
try:
n = int(n)
if n < 0:
raise ValueError
break
except ValueError:
print("Invalid input")
try:
boolNetwork.Update(
n, verbose=not writeToFile or n < 1000, writeToFile=writeToFile
)
Continue("Writing to file completed") if writeToFile else Continue()
except Exception as e:
print("Error while simulating:", e)
def GetMarkovChainHelper() -> None:
nonlocal boolNetwork
print(boolNetwork.GetTransitionMatrix())
Continue()
boolNetwork.SetState([False for _ in range(boolNetwork.size)])
def GetStableDistrHelper() -> None:
print(boolNetwork.GetStableProbabilityDistribution())
Continue()
boolNetwork.SetState([False for _ in range(boolNetwork.size)])
def SetFunctionHelper(index: int) -> None:
nonlocal boolNetwork, functions, functionStrings, functionsDirtyFlag
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
functions[index] = func
functionStrings[index] = funcString
functionsDirtyFlag = True
return
except Exception as e:
print("Error while parsing function:", e)
def ToggleWriteToFileHelper():
nonlocal writeToFile
writeToFile = not writeToFile
def ReturnHelper():
nonlocal done
done = True
while not done:
Menu()
currentFunction = MainMenu
def main() -> None:
global currentFunction
currentFunction = MainMenu
np.set_printoptions(precision=5, linewidth=300, sign=" ")
while True:
currentFunction()
if __name__ == "__main__":
main()