simple_simulate.alc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. include "primitives.alh"
  2. include "modelling.alh"
  3. include "object_operations.alh"
  4. include "conformance_scd.alh"
  5. include "io.alh"
  6. include "metamodels.alh"
  7. include "mini_modify.alh"
  8. include "utils.alh"
  9. Boolean function main(model : Element):
  10. String cmd
  11. Boolean running
  12. Element schedule_init
  13. Element schedule_run
  14. Element schedule
  15. Float current_time
  16. String time
  17. current_time = 0.0
  18. schedule_init = create_schedule(model)
  19. schedule_run = read_root()
  20. Element nodes
  21. Element inputs
  22. String node
  23. model_define_attribute(model["metamodel"], "DTCBD/Block", "signal", True, "DTCBD/Float")
  24. nodes = allInstances(model, "DTCBD/Block")
  25. inputs = dict_create()
  26. while (set_len(nodes) > 0):
  27. node = set_pop(nodes)
  28. dict_add(inputs, node, allAssociationOrigins(model, node, "DTCBD/Link"))
  29. while (bool_not(has_input())):
  30. if (current_time == 0.0):
  31. schedule = schedule_init
  32. else:
  33. if (element_eq(schedule_run, read_root())):
  34. schedule_run = create_schedule(model)
  35. schedule = schedule_run
  36. current_time = step_simulation(model, schedule, current_time, inputs)
  37. output("CLOSE")
  38. return False!
  39. Element function create_schedule(model : Element):
  40. // Create nice graph first
  41. Element nodes
  42. Element successors
  43. String element_name
  44. Element incoming_links
  45. Element all_blocks
  46. nodes = allInstances(model, "DTCBD/Block")
  47. successors = set_create()
  48. while (set_len(nodes) > 0):
  49. element_name = set_pop(nodes)
  50. if (is_nominal_instance(model, element_name, "DTCBD/ICBlock")):
  51. if (bool_not(is_physical_float(read_attribute(model, element_name, "last_in")))):
  52. incoming_links = allIncomingAssociationInstances(model, element_name, "DTCBD/InitialCondition")
  53. else:
  54. incoming_links = create_node()
  55. else:
  56. incoming_links = allIncomingAssociationInstances(model, element_name, "DTCBD/Link")
  57. while (set_len(incoming_links) > 0):
  58. String source
  59. source = readAssociationSource(model, set_pop(incoming_links))
  60. list_append(successors, create_tuple(source, element_name))
  61. Element values
  62. values = create_node()
  63. dict_add(values, "edges", successors)
  64. dict_add(values, "nodes", allInstances(model, "DTCBD/Block"))
  65. dict_add(values, "dfsCounter", 0)
  66. dict_add(values, "orderNumber", dict_create())
  67. dict_add(values, "visited_topSort", set_create())
  68. dict_add(values, "unvisited_strongComp", set_create())
  69. dict_overwrite(values, "SCC", strongComp(values))
  70. return values["SCC"]!
  71. Void function topSort(values : Element):
  72. Element nodes_copy
  73. String node
  74. dict_overwrite(values, "visited_topSort", set_create())
  75. nodes_copy = set_copy(values["nodes"])
  76. while (set_len(nodes_copy) > 0):
  77. node = set_pop(nodes_copy)
  78. if (bool_not(set_in(values["visited_topSort"], node))):
  79. dfsLabelling(values, node)
  80. return!
  81. Element function get_successors(values : Element, node : String, key : String):
  82. Element edges
  83. Element result
  84. String edge
  85. result = set_create()
  86. edges = list_copy(values[key])
  87. while (list_len(edges) > 0):
  88. edge = list_pop_final(edges)
  89. if (cast_string(edge[0]) == node):
  90. set_add(result, edge[1])
  91. return result!
  92. Void function dfsLabelling(values : Element, node : String):
  93. Element successors
  94. String successor
  95. // if not node.visited
  96. if (bool_not(set_in(values["visited_topSort"], node))):
  97. // node.visited = True
  98. set_add(values["visited_topSort"], node)
  99. // for neighbour in node.out_neighbours:
  100. // dfsLabelling(neighbour, graph)
  101. successors = get_successors(values, node, "edges")
  102. while (set_len(successors) > 0):
  103. successor = set_pop(successors)
  104. dfsLabelling(values, successor)
  105. // node.orderNumber = dfsCounter
  106. dict_overwrite(values["orderNumber"], node, values["dfsCounter"])
  107. // dfsCounter += 1
  108. dict_overwrite(values, "dfsCounter", cast_integer(values["dfsCounter"]) + 1)
  109. return !
  110. Element function dfsCollect(values : Element, start_node : String):
  111. Element result
  112. String successor
  113. Element successors
  114. result = set_create()
  115. // if not node.visited
  116. if (set_in(values["unvisited_strongComp"], start_node)):
  117. list_append(result, start_node)
  118. // node.visited = True
  119. set_remove(values["unvisited_strongComp"], start_node)
  120. // for neighbour in node.out_neighbours:
  121. // dfsLabelling(neighbour, graph)
  122. successors = get_successors(values, start_node, "rev_edges")
  123. while (set_len(successors) > 0):
  124. successor = set_pop(successors)
  125. list_extend(result, dfsCollect(values, successor))
  126. return result!
  127. String function highest_orderNumber(values : Element):
  128. Integer max
  129. String max_element
  130. Element search
  131. String elem
  132. max = -1
  133. search = set_copy(values["unvisited_strongComp"])
  134. while (set_len(search) > 0):
  135. elem = set_pop(search)
  136. if (cast_integer(values["orderNumber"][elem]) > max):
  137. max = values["orderNumber"][elem]
  138. max_element = elem
  139. return max_element!
  140. Element function reverse_edges(edges : Element):
  141. Element result
  142. Element elem
  143. result = list_create()
  144. edges = list_copy(edges)
  145. while (list_len(edges) > 0):
  146. elem = list_pop_final(edges)
  147. list_append(result, create_tuple(elem[1], elem[0]))
  148. return result!
  149. Element function strongComp(values : Element):
  150. Element graph
  151. Element sccs
  152. String start_node
  153. Element strong_components
  154. Element component
  155. sccs = list_create()
  156. topSort(values)
  157. dict_overwrite(values, "unvisited_strongComp", set_copy(values["nodes"]))
  158. dict_overwrite(values, "rev_edges", reverse_edges(values["edges"]))
  159. strong_components = list_create()
  160. while (set_len(values["unvisited_strongComp"]) > 0):
  161. start_node = highest_orderNumber(values)
  162. component = dfsCollect(values, start_node)
  163. list_append(sccs, component)
  164. return sccs!
  165. Element function get_topolist(values : Element):
  166. Element result
  167. Element predecessors
  168. Element remaining
  169. String current_element
  170. Element cur_predecessors
  171. result = list_create()
  172. predecessors = dict_copy(values["predecessors"])
  173. while (dict_len(predecessors) > 0):
  174. remaining = dict_keys(predecessors)
  175. while (set_len(remaining) > 0):
  176. current_element = set_pop(remaining)
  177. cur_predecessors = predecessors[current_element]
  178. if (set_len(set_overlap(list_to_set(result), cur_predecessors)) == set_len(cur_predecessors)):
  179. // All predecessors of this node have already been visited
  180. dict_delete(predecessors, current_element)
  181. remaining = dict_keys(predecessors)
  182. list_append(result, current_element)
  183. return result!
  184. Integer function min(a : Integer, b : Integer):
  185. if (a < b):
  186. return a!
  187. else:
  188. return b!
  189. Void function strongconnect(v : String, values : Element):
  190. // if (v.index is undefined) then
  191. // strongconnect(V)
  192. if (dict_in(values["indices"], v)):
  193. return!
  194. // v.index := index
  195. dict_overwrite(values["indices"], v, values["index"])
  196. // v.lowlink := indwx
  197. dict_overwrite(values["lowlink"], v, values["index"])
  198. // index := index + 1
  199. dict_overwrite(values, "index", cast_integer(values["index"]) + 1)
  200. // S.push(v)
  201. list_append(values["S"], v)
  202. // v.onStack := true
  203. dict_overwrite(values["onStack"], v, True)
  204. Element successors
  205. String w
  206. successors = values["successors"][v]
  207. while (set_len(successors) > 0):
  208. // for each (v, w) in E do
  209. w = set_pop(successors)
  210. // if (w.index is undefined) then
  211. if (bool_not(dict_in(values["indices"], w))):
  212. // strongconnect(w)
  213. strongconnect(w, values)
  214. // v.lowlink := min(v.lowlink, w.lowlink)
  215. dict_overwrite(values["lowlink"], v, min(values["lowlink"][v], values["lowlink"][w]))
  216. elif (dict_in(values["onStack"], w)):
  217. // else if (w.onStack)
  218. if (values["onStack"][w]):
  219. // v.lowlink := min(v.lowlink, w.index)
  220. dict_overwrite(values["lowlink"], v, min(values["lowlink"][v], values["indices"][w]))
  221. // if (v.lowlink == v.index) then
  222. if (value_eq(values["lowlink"][v], values["indices"][v])):
  223. Element scc
  224. // Start a new strongly connected component
  225. scc = create_node()
  226. // It will always differ now
  227. // w := S.pop()
  228. w = list_pop_final(values["S"])
  229. // w.onStack = false
  230. dict_overwrite(values["onStack"], w, False)
  231. // add w to current strongly connected component
  232. list_append(scc, w)
  233. // while w != v
  234. while (w != v):
  235. // w := S.pop()
  236. w = list_pop_final(values["S"])
  237. // w.onStack = false
  238. dict_overwrite(values["onStack"], w, False)
  239. // add w to current strongly connected component
  240. list_append(scc, w)
  241. // output the current strongly connected component
  242. list_insert(values["SCC"], scc, 0)
  243. return!
  244. Boolean function solve_scc(model : Element, scc : Element):
  245. Element m
  246. Integer i
  247. Integer j
  248. String block
  249. String blocktype
  250. Element incoming
  251. String selected
  252. Float constant
  253. Element t
  254. // Construct the matrix first, with as many rows as there are variables
  255. // Number of columns is 1 higher
  256. i = 0
  257. m = create_node()
  258. while (i < read_nr_out(scc)):
  259. j = 0
  260. t = create_node()
  261. while (j < (read_nr_out(scc) + 1)):
  262. list_append(t, 0.0)
  263. j = j + 1
  264. list_append(m, t)
  265. i = i + 1
  266. // Matrix initialized to 0.0
  267. i = 0
  268. while (i < read_nr_out(scc)):
  269. // First element of scc
  270. block = scc[i]
  271. blocktype = read_type(model, block)
  272. // First write 1 in the current block
  273. dict_overwrite(m[i], i, 1.0)
  274. // Now check all blocks that are incoming
  275. if (blocktype == "DTCBD/AdditionBlock"):
  276. constant = 0.0
  277. elif (blocktype == "DTCBD/MultiplyBlock"):
  278. constant = 1.0
  279. incoming = allIncomingAssociationInstances(model, block, "DTCBD/Link")
  280. Integer index_to_write_constant
  281. index_to_write_constant = -1
  282. while (read_nr_out(incoming) > 0):
  283. selected = readAssociationSource(model, set_pop(incoming))
  284. if (list_in(scc, selected)):
  285. // Part of the loop, so in the index of selected in scc
  286. // Five options:
  287. if (blocktype == "DTCBD/AdditionBlock"):
  288. // 1) AdditionBlock
  289. // Add the negative of this signal, which is as of yet unknown
  290. // x = y + z --> x - y - z = 0
  291. dict_overwrite(m[i], list_index_of(scc, selected), -1.0)
  292. elif (blocktype == "DTCBD/MultiplyBlock"):
  293. // 2) MultiplyBlock
  294. if (index_to_write_constant != -1):
  295. return False!
  296. index_to_write_constant = list_index_of(scc, selected)
  297. elif (blocktype == "DTCBD/NegatorBlock"):
  298. // 3) NegatorBlock
  299. // Add the positive of the signal, which is as of yet unknown
  300. dict_overwrite(m[i], list_index_of(scc, selected), 1.0)
  301. elif (blocktype == "DTCBD/DelayBlock"):
  302. // 5) DelayBlock
  303. // Just copies a single value
  304. dict_overwrite(m[i], list_index_of(scc, selected), -1.0)
  305. else:
  306. // Block that cannot be handled
  307. return False!
  308. else:
  309. // A constant, which we can assume is already computed and thus usable
  310. if (blocktype == "DTCBD/AdditionBlock"):
  311. constant = constant + cast_float(read_attribute(model, selected, "signal"))
  312. dict_overwrite(m[i], read_nr_out(scc), constant)
  313. elif (blocktype == "DTCBD/MultiplyBlock"):
  314. constant = constant * cast_float(read_attribute(model, selected, "signal"))
  315. // Not written to constant part, as multiplies a variable
  316. // Any other block is impossible:
  317. // * Constant would never be part of a SCC
  318. // * Delay would never get an incoming constant
  319. // * Negation and Inverse only get 1 input, which is a variable in a loop
  320. // * Integrator and Derivator never get an incoming constant
  321. if (index_to_write_constant != -1):
  322. dict_overwrite(m[i], index_to_write_constant, -constant)
  323. i = i + 1
  324. // Solve matrix now
  325. eliminateGaussJordan(m)
  326. // Now go over m and set signals for each element
  327. // Assume that everything worked out...
  328. i = 0
  329. while (i < read_nr_out(m)):
  330. block = scc[i]
  331. instantiate_attribute(model, block, "signal", m[i][read_nr_out(scc)])
  332. i = i + 1
  333. return True!
  334. Integer function list_index_of(lst : Element, elem : Element):
  335. Integer i
  336. i = 0
  337. while (i < read_nr_out(lst)):
  338. if (value_eq(list_read(lst, i), elem)):
  339. return i!
  340. else:
  341. i = i + 1
  342. return -1!
  343. Float function step_simulation(model : Element, schedule : Element, time : Float, inputs : Element):
  344. Float signal
  345. Element incoming
  346. String selected
  347. String block
  348. String elem
  349. String blocktype
  350. Element memory_blocks
  351. Integer i
  352. Float delta_t
  353. Element scc
  354. delta_t = 0.1
  355. memory_blocks = set_create()
  356. i = 0
  357. while (i < list_len(schedule)):
  358. scc = list_read(schedule, i)
  359. i = i + 1
  360. if (list_len(scc) > 1):
  361. if (bool_not(solve_scc(model, scc))):
  362. output("ALGEBRAIC_LOOP")
  363. return time!
  364. else:
  365. block = list_read(scc, 0)
  366. // Execute "block"
  367. blocktype = read_type(model, block)
  368. incoming = set_copy(inputs[block])
  369. if (blocktype == "DTCBD/ConstantBlock"):
  370. signal = cast_float(read_attribute(model, block, "value"))
  371. elif (blocktype == "DTCBD/AdditionBlock"):
  372. signal = 0.0
  373. while (set_len(incoming) > 0):
  374. selected = set_pop(incoming)
  375. signal = signal + cast_float(read_attribute(model, selected, "signal"))
  376. elif (blocktype == "DTCBD/MultiplyBlock"):
  377. signal = 1.0
  378. while (set_len(incoming) > 0):
  379. selected = set_pop(incoming)
  380. signal = signal * cast_float(read_attribute(model, selected, "signal"))
  381. elif (blocktype == "DTCBD/NegatorBlock"):
  382. signal = 0.0
  383. while (set_len(incoming) > 0):
  384. selected = set_pop(incoming)
  385. signal = float_neg(cast_float(read_attribute(model, selected, "signal")))
  386. elif (blocktype == "DTCBD/InverseBlock"):
  387. signal = 0.0
  388. while (set_len(incoming) > 0):
  389. selected = set_pop(incoming)
  390. signal = float_division(1.0, cast_float(read_attribute(model, selected, "signal")))
  391. elif (blocktype == "DTCBD/DelayBlock"):
  392. signal = 0.0
  393. if (bool_not(is_physical_float(read_attribute(model, block, "last_in")))):
  394. // No memory yet, so use initial condition
  395. incoming = allAssociationOrigins(model, block, "DTCBD/InitialCondition")
  396. while (set_len(incoming) > 0):
  397. selected = set_pop(incoming)
  398. signal = cast_float(read_attribute(model, selected, "signal"))
  399. else:
  400. signal = read_attribute(model, block, "last_in")
  401. set_add(memory_blocks, block)
  402. elif (blocktype == "DTCBD/ProbeBlock"):
  403. signal = 0.0
  404. while (set_len(incoming) > 0):
  405. signal = cast_float(read_attribute(model, set_pop(incoming), "signal"))
  406. output(cast_string(time) + " " + cast_string(read_attribute(model, block, "name")) + " " + cast_string(signal))
  407. log(cast_string(time) + " " + cast_string(read_attribute(model, block, "name")) + " " + cast_string(signal))
  408. instantiate_attribute(model, block, "signal", signal)
  409. while (set_len(memory_blocks) > 0):
  410. block = set_pop(memory_blocks)
  411. // Update memory
  412. incoming = set_copy(inputs[block])
  413. while (set_len(incoming) > 0):
  414. selected = set_pop(incoming)
  415. instantiate_attribute(model, block, "last_in", cast_float(read_attribute(model, selected, "signal")))
  416. // Increase simulation time
  417. return time + delta_t!
  418. Void function eliminateGaussJordan(m : Element):
  419. Integer i
  420. Integer j
  421. Integer f
  422. Integer g
  423. Boolean searching
  424. Element t
  425. Float divisor
  426. i = 0
  427. j = 0
  428. while (i < read_nr_out(m)):
  429. // Make sure pivot m[i][j] != 0, swapping if necessary
  430. while (cast_float(m[i][j]) == 0.0):
  431. // Is zero, so find row which is not zero
  432. f = i + 1
  433. searching = True
  434. while (searching):
  435. if (f >= read_nr_out(m)):
  436. // No longer any rows left, so just increase column counter
  437. searching = False
  438. j = j + 1
  439. else:
  440. if (cast_float(m[f][j]) == 0.0):
  441. // Also zero, so continue
  442. f = f + 1
  443. else:
  444. // Found non-zero, so swap row
  445. t = cast_float(m[f])
  446. dict_overwrite(m, f, cast_float(m[i]))
  447. dict_overwrite(m, i, t)
  448. searching = False
  449. // If we have increased j, we will just start the loop again (possibly), as m[i][j] might be zero again
  450. // Pivot in m[i][j] guaranteed to not be 0
  451. // Now divide complete row by value of m[i][j] to make it equal 1
  452. f = j
  453. divisor = cast_float(m[i][j])
  454. while (f < read_nr_out(m[i])):
  455. dict_overwrite(m[i], f, float_division(cast_float(m[i][f]), divisor))
  456. f = f + 1
  457. // Eliminate all rows in the j-th column, except the i-th row
  458. f = 0
  459. while (f < read_nr_out(m)):
  460. if (bool_not(f == i)):
  461. g = j
  462. divisor = cast_float(m[f][j])
  463. while (g < read_nr_out(m[f])):
  464. dict_overwrite(m[f], g, cast_float(m[f][g]) - (divisor * cast_float(m[i][g])))
  465. g = g + 1
  466. f = f + 1
  467. // Increase row and column
  468. i = i + 1
  469. j = j + 1
  470. return !
  471. String function matrix2string(m : Element):
  472. Integer i
  473. Integer j
  474. String result
  475. result = ""
  476. i = 0
  477. while (i < read_nr_out(m)):
  478. j = 0
  479. while (j < read_nr_out(m[i])):
  480. result = result + cast_string(m[i][j]) + ", "
  481. j = j + 1
  482. i = i + 1
  483. result = result + "\n"
  484. return result!