From de370416ac4f939db5c11ac3f351b2a069e67b18 Mon Sep 17 00:00:00 2001 From: JuliusHerrmann Date: Fri, 16 Jul 2021 16:42:48 +0200 Subject: [PATCH] json works now --- visualizer/public/js/main.js | 72 +- .../__pycache__/graphUtils.cpython-39.pyc | Bin 0 -> 785 bytes visualizer/public/python/graphUtils.py | 21 + visualizer/public/python/json | 159787 +++++++++++++++ .../public/python/simulationAdvanced.py | 241 + .../src/Controller/SimulationController.php | 46 +- 6 files changed, 160138 insertions(+), 29 deletions(-) create mode 100644 visualizer/public/python/__pycache__/graphUtils.cpython-39.pyc create mode 100644 visualizer/public/python/graphUtils.py create mode 100644 visualizer/public/python/json create mode 100644 visualizer/public/python/simulationAdvanced.py diff --git a/visualizer/public/js/main.js b/visualizer/public/js/main.js index 110a213..dc686d2 100644 --- a/visualizer/public/js/main.js +++ b/visualizer/public/js/main.js @@ -1,3 +1,6 @@ +// Put the real domain here +var baseUrl = "http://localhost" + var network; var simulationData; animationPlaying = false; @@ -8,6 +11,34 @@ const stepSlider = document.querySelector('#stepRange'); const stepField = document.querySelector('#stepField'); const animationDurationSlider = document.querySelector('#animationDurationRange'); const animationDurationField = document.querySelector('#animationDurationField'); + +var selectedGraph; +var horizon; +var states; +var initial_distribution; +var rules; +var colors; + +// Debuging +//selectedGraph = "strict graph GraphHello {\n0 -- 1;\n1 -- 2;\n1 -- 3;\n}"; +//selectedGraph = "strict graph Default {\n0 -- 1;\n1 -- 2;\n2 -- 3;\n3 -- 4;\n4 -- 5;\n0 -- 5;\n0 -- 3;\n0 -- 4;\n0 -- 2;\n1 -- 4;\n1 -- 5;\n1 -- 6;\n3 -- 5;\n3 -- 6;\n3 -- 4;\n}" + +selectedGraph = "strict graph Default {\n0 -- 10;\n0 -- 1;\n1 -- 11;\n1 -- 2;\n2 -- 12;\n2 -- 3;\n3 -- 13;\n3 -- 4;\n4 -- 14;\n4 -- 5;\n5 -- 15;\n5 -- 6;\n6 -- 16;\n6 -- 7;\n7 -- 17;\n7 -- 8;\n8 -- 18;\n8 -- 9;\n9 -- 19;\n10 -- 20;\n10 -- 11;\n11 -- 21;\n11 -- 12;\n12 -- 22;\n12 -- 13;\n13 -- 23;\n13 -- 14;\n14 -- 24;\n14 -- 15;\n15 -- 25;\n15 -- 16;\n16 -- 26;\n16 -- 17;\n17 -- 27;\n17 -- 18;\n18 -- 28;\n18 -- 19;\n19 -- 29;\n20 -- 30;\n20 -- 21;\n21 -- 31;\n21 -- 22;\n22 -- 32;\n22 -- 23;\n23 -- 33;\n23 -- 24;\n24 -- 34;\n24 -- 25;\n25 -- 35;\n25 -- 26;\n26 -- 36;\n26 -- 27;\n27 -- 37;\n27 -- 28;\n28 -- 38;\n28 -- 29;\n29 -- 39;\n30 -- 40;\n30 -- 31;\n31 -- 41;\n31 -- 32;\n32 -- 42;\n32 -- 33;\n33 -- 43;\n33 -- 34;\n34 -- 44;\n34 -- 35;\n35 -- 45;\n35 -- 36;\n36 -- 46;\n36 -- 37;\n37 -- 47;\n37 -- 38;\n38 -- 48;\n38 -- 39;\n39 -- 49;\n40 -- 50;\n40 -- 41;\n41 -- 51;\n41 -- 42;\n42 -- 52;\n42 -- 43;\n43 -- 53;\n43 -- 44;\n44 -- 54;\n44 -- 45;\n45 -- 55;\n45 -- 46;\n46 -- 56;\n46 -- 47;\n47 -- 57;\n47 -- 48;\n48 -- 58;\n48 -- 49;\n49 -- 59;\n50 -- 60;\n50 -- 51;\n51 -- 61;\n51 -- 52;\n52 -- 62;\n52 -- 53;\n53 -- 63;\n53 -- 54;\n54 -- 64;\n54 -- 55;\n55 -- 65;\n55 -- 56;\n56 -- 66;\n56 -- 57;\n57 -- 67;\n57 -- 58;\n58 -- 68;\n58 -- 59;\n59 -- 69;\n60 -- 70;\n60 -- 61;\n61 -- 71;\n61 -- 62;\n62 -- 72;\n62 -- 63;\n63 -- 73;\n63 -- 64;\n64 -- 74;\n64 -- 65;\n65 -- 75;\n65 -- 66;\n66 -- 76;\n66 -- 67;\n67 -- 77;\n67 -- 68;\n68 -- 78;\n68 -- 69;\n69 -- 79;\n70 -- 80;\n70 -- 71;\n71 -- 81;\n71 -- 72;\n72 -- 82;\n72 -- 73;\n73 -- 83;\n73 -- 74;\n74 -- 84;\n74 -- 75;\n75 -- 85;\n75 -- 76;\n76 -- 86;\n76 -- 77;\n77 -- 87;\n77 -- 78;\n78 -- 88;\n78 -- 79;\n79 -- 89;\n80 -- 90;\n80 -- 81;\n81 -- 91;\n81 -- 82;\n82 -- 92;\n82 -- 83;\n83 -- 93;\n83 -- 84;\n84 -- 94;\n84 -- 85;\n85 -- 95;\n85 -- 86;\n86 -- 96;\n86 -- 87;\n87 -- 97;\n87 -- 88;\n88 -- 98;\n88 -- 89;\n89 -- 99;\n90 -- 91;\n91 -- 92;\n92 -- 93;\n93 -- 94;\n94 -- 95;\n95 -- 96;\n96 -- 97;\n97 -- 98;\n98 -- 99;}" + +horizon = 20.0; +//states = ["S", "I", "R"]; +states = ["N", "I", "V"]; +//initial_distribution = [0.5, 0.5, 0]; +initial_distribution = [0.9, 0.1, 0]; +//rules = "I R 1.0 R S 0.7 I S I I I I 0.8"; +rules = "N V 0.1 I N I I 0.5 I I N I I I 0.9 I N 0.2"; +// S I R +colors = { + "N" : "#000000", + "I" : "#ffffff", + "V" : "#75c44c" +} + function createGraphFromDot(dotString){ var parsedData = vis.parseDOTNetwork(dotString); // create a network @@ -62,32 +93,37 @@ function createGraphFromDot(dotString){ function visualizeOneStep(step){ for(i = 0; i < step.length; i++){ n = network.body.nodes[i]; - //console.log(step[i]) - if(step[i][0] == 0){ - n.setOptions({ - color:{ - background: "#0000ff", - } - }); - }else{ - n.setOptions({ - color:{ - background: "#ff0000", - } - }); - } + n.setOptions({ + color:{ + background: colors[step[i]] + } + }); } network.redraw(); } function getSimulation(){ - fetch("http://localhost/simulate") + //prepare the json data + json = { + graph: selectedGraph, + horizon: horizon, + states: states, + initial_distribution : initial_distribution, + rules : rules + } + + //combine url + url = baseUrl + "/simulate?data=" + JSON.stringify(json); + + fetch(url) .then(response => response.json()) .then(response =>{ + console.log(response) simulationData = response; - stepSlider.max = simulationData.steps - 1; - createGraphFromDot(simulationData.dotGraph); + stepSlider.max = simulationData.states.length - 1; + //createGraphFromDot(simulationData.dotGraph); + createGraphFromDot(json.graph); visualizeOneStep(simulationData.states[0]); //kelvin to celsius //let temp = Math.ceil(response.main.temp - 273.15); @@ -102,7 +138,7 @@ function playAnimation(){ //Play the animation animationInterval = setInterval(function(){ //This is the animation routine - if(currentAnimationStep == simulationData.steps){ + if(currentAnimationStep == simulationData.states.length - 1){ //At the end of animation clearInterval(animationInterval); animationPlaying = false; diff --git a/visualizer/public/python/__pycache__/graphUtils.cpython-39.pyc b/visualizer/public/python/__pycache__/graphUtils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec5a2c8f895947438577a6d8744f11f722ba4c11 GIT binary patch literal 785 zcmYk4zi$&U6vzF1b`l~|RaK=X3p#bn5Kgc#P*q5TwL%masv>d3*TitSyZU@U4&M~` zD-cp6vGC9E2Y6-5#@vZ#hyL)%&+mu*js1Cvd%Z5far*o3+e1po9~aynm?KYcmb+*K z5%86q5J5$ND+qQ>hJ51oTn&y+8|PD;qJe$Dp7FWpNBYZi`1VND-*Ei}LI8kS}8 zJh6ey3fsynT~yk_XA27z;5EFtd>+m6c@n*^QdyPJIGYtQI=Jl$~x9E z&#t3HMMd>4m6NDg=ouFLMP6x{miLQ=?ImKGq_Wg6^Kq`hz1jnXyZH5K2b2pZu5dLR zo@+!uF_@ADAzdJ<6*R;ktbvPy6#^c36oP9obP0m@$v3PvR8!25O=jt^zHShwpdYAu zaXvQ01YVn#Hp%y82>qbmS{O4zisO)D&P*X|9< zJ!b8izII+sM R with rate 1.0 + ("R", "S", 0.7), # spontaneous rule R -> S with rate 0.7 + (("I","S","I"),("I","I","I"), 0.8)] # contact rule I+S -> I+I with rate 0.4 + +simulation = [] + +class Rule: + def __init__(self, ruleParts, probability): + self.ruleParts = ruleParts + self.probability = probability + + def getString(self): + output = "(" + for part in self.ruleParts: + output += f"({part.getFromState().getValue()}, {part.getToState().getValue()}), " + output = output[0:len(output)-2] + output += f"), {self.probability})" + return output + + def getOutput(self): + # index of to state is ruleParts / 2 + toStateIndex = int(len(self.ruleParts) / 2) + fromTuple = [] + toTuple = [] + for i in range(toStateIndex): + fromTuple.append(self.ruleParts[i]) + toTuple.append(self.ruleParts[i + toStateIndex]) + + if(len(fromTuple) > 1): + fromTuple = tuple(fromTuple) + toTuple = tuple(toTuple) + return (fromTuple, toTuple, self.probability,) + else: + return (fromTuple[0], toTuple[0], self.probability,) + + + +def parseState(string): + output = "" + i = 0 + while(not(string[i].isdigit() or string[i] == " ")): + output += string[i] + i += 1 + return (output, string[i+1:],) + +def parseRate(string): + output = "" + i = 0 + while(not string[i] == " "): + output += string[i] + i += 1 + if(i == len(string)): + break + return(float(output), string[i+1:]) + + +# Extract rules from string +# example: "Inf Inf Inf R 0.8" +def stringToRule(Input): + allRules = [] + rulePartsBuffer = [] + while(len(Input) > 0): + newString = parseState(Input) + rulePartsBuffer.append(newString[0]) + + # check if we are at the end + if(newString[1][0].isdigit()): + newString = parseRate(newString[1]) + allRules.append(Rule(rulePartsBuffer.copy(), newString[0])) + rulePartsBuffer.clear() + + Input = newString[1] + + output = [] + for r in allRules: + output.append(r.getOutput()) + return output + +def stringToStates(inp): + inp = inp.split(" ") + out = [] + for s in inp: + out.append(s) + return out + +def stringToDistr(inp): + inp = inp.split(" ") + out = [] + for i in inp: + out.append(float(i)) + return out + +# parse the input wohooooo +# rules = stringToRule(sys.argv[1]) +# states = stringToStates(sys.argv[2]) +# initial_distribution = stringToDistr(sys.argv[3]) + +jsonInput = json.loads(sys.argv[1]) +# print(jsonInput["graph"]) +graph_as_edgelist = graphUtils.dotToEdgelist(jsonInput["graph"])[1] +horizon = jsonInput["horizon"] +states = jsonInput["states"] +initial_distribution = jsonInput["initial_distribution"] +rules = stringToRule(jsonInput["rules"]) +# print(graph_as_edgelist) + + +#graph_as_edgelist = [(0, 4), (0, 1), (1, 5), (1, 2), (2, 6), (2, 3), (3, 7), (4, 8), (4, 5), (5, 9), (5, 6), (6, 10), (6, 7), (7, 11), (8, 12), (8, 9), (9, 13), (9, 10), (10, 14), (10, 11), (11, 15), (12, 13), (13, 14), (14, 15)] + +# print(graphUtils.edgelistToDot("testGraph", graph_as_edgelist)) +# print(graphUtils.dotToEdgelist("strict graph 'testGraph' {\n0 -- 4;\n0 -- 1;\n1 -- 5;\n}")[0]) + +# horizon = 20.0 # wie lange wird simuliert +# initial_distribution = [0.5, 0.5, 0.0] # gleiche Reihenfolge wie states, musss zu rules passen und normalisiert werden +timepoint_num = 101 +def get_next_state(current_labels): + fastes_firing_time = 10000000.0 #dummy + firing_rule = None + firing_node = None + firing_edge = None + + # iterate over nodes + for node in nodes: + current_state = current_labels[node] + for rule in rules: + if 'tuple' in str(type(rule[0])): + # is contact rule + continue + if current_state == rule[0]: + current_fireing_time = np.random.exponential(1.0/rule[2]) + if current_fireing_time < fastes_firing_time: + fastes_firing_time = current_fireing_time + firing_rule = rule + firing_node = node + firing_edge = None + + + # iterate over edges: + for edge in graph_as_edgelist: + node1, node2 = edge + current_state1 = current_labels[node1] + current_state2 = current_labels[node2] + for rule in rules: + if 'str' in str(type(rule[0])): + # is spont. rule + continue + if (current_state1 == rule[0][0] and current_state2 == rule[0][1]) or (current_state2 == rule[0][0] and current_state1 == rule[0][1]): + current_fireing_time = np.random.exponential(1.0/rule[2]) + if current_fireing_time < fastes_firing_time: + fastes_firing_time = current_fireing_time + firing_rule = rule + firing_node = None + firing_edge = edge + + + if firing_rule is None: + # no rule could fire + return None, fastes_firing_time # would happen anyway but still + + # apply rule + new_labels = list(current_labels) # copy + + if firing_node is not None: + new_labels[firing_node] = firing_rule[1] + return new_labels, fastes_firing_time + + assert(firing_edge is not None) + change_node1 = firing_edge[0] + change_node2 = firing_edge[1] + # we have to check which node changes in which direction + if new_labels[change_node1] == firing_rule[0][0] and new_labels[change_node2] == firing_rule[0][1]: + new_labels[change_node1] = firing_rule[1][0] + new_labels[change_node2] = firing_rule[1][1] + else: + new_labels[change_node1] = firing_rule[1][1] + new_labels[change_node2] = firing_rule[1][0] + + + return new_labels, fastes_firing_time + +def count_states(current_labels): + counter = [0 for _ in states] + simulation.append(current_labels) + for label in current_labels: + index = states.index(label) + counter[index] += 1 + return counter + +nodes = sorted(list(set([e[0] for e in graph_as_edgelist] + [e[1] for e in graph_as_edgelist]))) +assert(nodes == list(range(len(nodes)))) # nodes haben labels 0... + +# setup +timepoints_samples = np.linspace(0.0, horizon, timepoint_num) +timepoints_samples_static = np.linspace(0.0, horizon, timepoint_num) +initial_labels = list(np.random.choice(states, len(nodes), p=initial_distribution)) +current_labels = initial_labels +global_clock = 0.0 +labels = list() +timepoints = list() +state_counts = list() + + +# simulate +while len(timepoints_samples) > 0: + new_labels, time_passed = get_next_state(current_labels) + global_clock += time_passed + while len(timepoints_samples) > 0 and global_clock > timepoints_samples[0]: + labels.append(list(current_labels)) + state_counts.append(count_states(current_labels)) + timepoints_samples = timepoints_samples[1:] + current_labels = new_labels + + +for l in simulation: + # print(l) + pass + +# if(rulesComp == rules): + # print("Rules were parsed correctly") +# else: + # print("Rules were not parsed correctly") + +# prepare the output json file +outputJson = { + "states": simulation + } +print(json.dumps(outputJson)) diff --git a/visualizer/src/Controller/SimulationController.php b/visualizer/src/Controller/SimulationController.php index b14008d..ed9e71e 100644 --- a/visualizer/src/Controller/SimulationController.php +++ b/visualizer/src/Controller/SimulationController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -17,21 +18,44 @@ class SimulationController extends AbstractController 'controller_name' => 'SimulationController', ]); } - #[Route('/simulate', name: 'run_simulation')] - public function simulate(): Response - { - $process1 = new Process(['python3', 'python/simulation.py']); - //$process = new Process(['cat', 'python/graph.dot']); - $process1->run(); - //$process->run(); + #[Route('/simulate', name: 'run_simulation')] + public function simulate(Request $request): Response + { + $input = $request->query->get('data'); + $process = new Process(['python3', 'python/simulationAdvanced.py', $input]); + //$process = new Process(['python3', 'python/simulationAdvanced.py', '{ + //"graph": "strict graph GraphHello {\n0 -- 1;\n1 -- 2;\n1 -- 3;\n}", + //"horizon": 20.0, + //"states": ["S", "I", "R"], + //"initial_distribution": [0.5, 0.5, 0], + //"rules": "I R 1.0 R S 0.7 I S I I 0.8" +//}']); + $process->run(); // executes after the command finishes - if (!$process1->isSuccessful()) { - throw new ProcessFailedException($process1); + if (!$process->isSuccessful()) { + throw new ProcessFailedException($process); } - $output = $process1->getOutput(); + $output = $process->getOutput(); $response = new Response($output); return $response; - } + } + //#[Route('/simulate', name: 'run_simulation')] + //public function simulate(): Response + //{ + //$process1 = new Process(['python3', 'python/simulation.py']); + ////$process = new Process(['cat', 'python/graph.dot']); + //$process1->run(); + ////$process->run(); +// + //// executes after the command finishes + //if (!$process1->isSuccessful()) { + //throw new ProcessFailedException($process1); + //} +// + //$output = $process1->getOutput(); + //$response = new Response($output); + //return $response; + //} }