aoc_1220.slt 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Use of this software is governed by the Business Source License
  4. # included in the LICENSE file at the root of this repository.
  5. #
  6. # As of the Change Date specified in that file, in accordance with
  7. # the Business Source License, use of this software will be governed
  8. # by the Apache License, Version 2.0.
  9. # https://github.com/MaterializeInc/advent-of-code-2023/blob/main/week1/aoc_1220.md
  10. mode cockroach
  11. statement ok
  12. CREATE TABLE input (input TEXT);
  13. # no input data
  14. query T multiline
  15. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, arity, join implementations) AS VERBOSE TEXT FOR
  16. WITH MUTUALLY RECURSIVE
  17. lines(line TEXT) AS ( SELECT regexp_split_to_table(input, '\n') FROM input ),
  18. links(name TEXT, link TEXT) AS (
  19. SELECT
  20. substring(regexp_split_to_array(line, ' ')[1], 2),
  21. trim(',' FROM regexp_split_to_array(line, ' ')[x])
  22. FROM
  23. lines, generate_series(3, array_length(regexp_split_to_array(line, ' '), 1)) x
  24. ),
  25. -- One special line has op 'b' and name 'roadcaster'.
  26. types(op TEXT, name TEXT) AS (
  27. SELECT
  28. substring(regexp_split_to_array(line, ' ')[1], 1, 1),
  29. substring(regexp_split_to_array(line, ' ')[1], 2)
  30. FROM
  31. lines
  32. ),
  33. -- Part one: simulate 1000 steps of 'broadcaster' being activated with a low pulse.
  34. -- tally up total low and high pulses, and then multiply.
  35. -- The state carried across steps are the last-transmitted pulses of each operator.
  36. -- This should also tell us the final state of the `%` operators.
  37. -- We'll also need the totals of low and high pulses, so that we can add them up.
  38. seed(press INT, counter INT) AS (
  39. SELECT 1, 1
  40. UNION
  41. SELECT press, counter - 1
  42. FROM seed
  43. WHERE counter > 0
  44. UNION
  45. SELECT press + 1, 20
  46. FROM seed
  47. WHERE counter = 0
  48. AND press < 4100
  49. ),
  50. -- Emitted pulses after various button presses, in various rounds of resolution.
  51. pulses(name TEXT, press INT, round INT, pulse TEXT) AS (
  52. -- One thousand button presses, each followed by rounds of resolution.
  53. SELECT 'roadcaster', press, 1, 'lo' FROM seed WHERE counter = 0
  54. UNION ALL SELECT * FROM flip
  55. UNION ALL SELECT * FROM conj
  56. ),
  57. -- Counters; every 'lo' input pulse flips and emits the state.
  58. flip(name TEXT, press INT, round INT, pulse TEXT) AS (
  59. -- Each `signal` needs to behave as if all "prior" signals have been processed, ordered by (press, round, source).
  60. SELECT
  61. name,
  62. press,
  63. round + 1,
  64. -- Look for the most recently emitted signal, and we'll produce the opposite of that one.
  65. CASE WHEN (
  66. SELECT COUNT(*)
  67. FROM signal s1
  68. WHERE s1.target = types.name
  69. AND s1.pulse = 'lo'
  70. AND ((s1.press < signal.press) OR
  71. (s1.press = signal.press AND s1.round < signal.round) OR
  72. (s1.press = signal.press AND s1.round = signal.round AND s1.source < signal.source))
  73. ) % 2 = 0
  74. THEN 'hi'
  75. ELSE 'lo'
  76. END
  77. FROM signal, types
  78. WHERE signal.target = types.name
  79. AND types.op = '%'
  80. AND signal.pulse = 'lo'
  81. ),
  82. -- NAND gates; every input pulse evokes the NAND of most recent inputs.
  83. conj(name TEXT, press INT, round INT, pulse TEXT) AS (
  84. SELECT
  85. name,
  86. press,
  87. round + 1,
  88. -- Look for the most recently received signals from each input,
  89. -- including this one, and iff all 'hi' then 'lo'.
  90. CASE WHEN (
  91. (SELECT COUNT(*) FROM links WHERE link = types.name)
  92. =
  93. (SELECT COUNT(*) FROM (
  94. SELECT DISTINCT ON (source) source, pulse
  95. FROM signal s1
  96. WHERE s1.target = types.name
  97. AND ((s1.press < signal.press) OR
  98. (s1.press = signal.press AND s1.round < signal.round) OR
  99. (s1.press = signal.press AND s1.round = signal.round AND s1.source <= signal.source))
  100. OPTIONS (DISTINCT ON INPUT GROUP SIZE = 1000)
  101. ORDER BY source, press DESC, round DESC
  102. )
  103. WHERE pulse = 'hi'))
  104. THEN 'lo'
  105. ELSE 'hi'
  106. END
  107. FROM signal, types
  108. WHERE signal.target = types.name
  109. AND types.op = '&'
  110. ),
  111. -- A record of a pulse into an operator, from another operator.
  112. -- We track the source so that '&' operators can make any sense.
  113. signal(source TEXT, target TEXT, press INT, round INT, pulse TEXT) AS (
  114. SELECT pulses.name, links.link, pulses.press, pulses.round, pulses.pulse
  115. FROM pulses, links
  116. WHERE pulses.name = links.name
  117. AND pulses.round > 0
  118. ),
  119. part1(pulse TEXT, count BIGINT) AS (
  120. SELECT pulse, count(*) FROM signal GROUP BY pulse
  121. ),
  122. potato(x INT) AS (SELECT 1)
  123. SELECT * FROM signal WHERE target = 'cn' AND pulse = 'hi';
  124. ----
  125. Explained Query:
  126. With
  127. cte l0 =
  128. Project (#1) // { arity: 1 }
  129. FlatMap unnest_array(regexp_split_to_array["\n", case_insensitive=false](#0{input})) // { arity: 2 }
  130. ReadStorage materialize.public.input // { arity: 1 }
  131. cte l1 =
  132. Project (#3, #4) // { arity: 2 }
  133. Map (regexp_split_to_array[" ", case_insensitive=false](#0{line}), substr(array_index(#2, 1), 2), btrim(array_index(#2, integer_to_bigint(#1{x})), ",")) // { arity: 5 }
  134. FlatMap generate_series(3, (regexp_split_to_array[" ", case_insensitive=false](#0{line}) array_length 1), 1) // { arity: 2 }
  135. Get l0 // { arity: 1 }
  136. cte l2 =
  137. Project (#1, #2) // { arity: 2 }
  138. Map (array_index(regexp_split_to_array[" ", case_insensitive=false](#0{line}), 1), substr(#1, 2)) // { arity: 3 }
  139. Get l0 // { arity: 1 }
  140. Return // { arity: 5 }
  141. With Mutually Recursive
  142. cte l3 =
  143. Distinct project=[#0, #1] monotonic // { arity: 2 }
  144. Union // { arity: 2 }
  145. Project (#0, #2) // { arity: 2 }
  146. Filter (#1{counter} > 0) // { arity: 3 }
  147. Map ((#1{counter} - 1)) // { arity: 3 }
  148. Get l3 // { arity: 2 }
  149. Project (#2, #3) // { arity: 2 }
  150. Filter (#1{counter} = 0) AND (#0{press} < 4100) // { arity: 4 }
  151. Map ((#0{press} + 1), 20) // { arity: 4 }
  152. Get l3 // { arity: 2 }
  153. Constant // { arity: 2 }
  154. - (1, 1)
  155. cte l4 =
  156. Union // { arity: 4 }
  157. Project (#2, #0, #3, #4) // { arity: 4 }
  158. Filter (#1{counter} = 0) // { arity: 5 }
  159. Map ("roadcaster", 1, "lo") // { arity: 5 }
  160. Get l3 // { arity: 2 }
  161. Filter (#2{round} > 0) // { arity: 4 }
  162. Get l12 // { arity: 4 }
  163. Filter (#2{round} > 0) // { arity: 4 }
  164. Get l26 // { arity: 4 }
  165. cte l5 =
  166. ArrangeBy keys=[[#1{target}]] // { arity: 4 }
  167. Project (#0..=#3) // { arity: 4 }
  168. Filter (#4{pulse} = "lo") AND (#1{target}) IS NOT NULL // { arity: 5 }
  169. Get l27 // { arity: 5 }
  170. cte l6 =
  171. Project (#0..=#3, #5) // { arity: 5 }
  172. Map ((#3{round} + 1)) // { arity: 6 }
  173. Join on=(#1{target} = #4{name}) type=differential // { arity: 5 }
  174. implementation
  175. %0:l5[#1{target}]Kef » %1:l2[#0{name}]Kef
  176. Get l5 // { arity: 4 }
  177. ArrangeBy keys=[[#0{name}]] // { arity: 1 }
  178. Project (#1) // { arity: 1 }
  179. Filter ("%" = substr(#0, 1, 1)) // { arity: 2 }
  180. Get l2 // { arity: 2 }
  181. cte l7 =
  182. Distinct project=[#0, #2, #3, #1] // { arity: 4 }
  183. Project (#0..=#3) // { arity: 4 }
  184. Get l6 // { arity: 5 }
  185. cte l8 =
  186. Reduce group_by=[#0..=#3] aggregates=[count(*)] // { arity: 5 }
  187. Project (#0..=#3) // { arity: 4 }
  188. Filter ((#6{press} < #1{press}) OR ((#1{press} = #6{press}) AND ((#7{round} < #2{round}) OR ((#2{round} = #7{round}) AND (#4{source} < #0{source}))))) // { arity: 8 }
  189. Join on=(#3{name} = #5{target}) type=differential // { arity: 8 }
  190. implementation
  191. %1:l5[#1{target}]Kef » %0:l7[#3{name}]Kef
  192. ArrangeBy keys=[[#3{name}]] // { arity: 4 }
  193. Get l7 // { arity: 4 }
  194. Get l5 // { arity: 4 }
  195. cte l9 =
  196. ArrangeBy keys=[[#0..=#3]] // { arity: 4 }
  197. Get l7 // { arity: 4 }
  198. cte l10 =
  199. Union // { arity: 5 }
  200. Get l8 // { arity: 5 }
  201. Project (#0..=#3, #8) // { arity: 5 }
  202. Map (0) // { arity: 9 }
  203. Join on=(#0 = #4 AND #1 = #5 AND #2 = #6 AND #3 = #7) type=differential // { arity: 8 }
  204. implementation
  205. %1:l9[#0..=#3]UKKKK » %0[#0..=#3]KKKK
  206. ArrangeBy keys=[[#0..=#3]] // { arity: 4 }
  207. Union // { arity: 4 }
  208. Negate // { arity: 4 }
  209. Project (#0..=#3) // { arity: 4 }
  210. Get l8 // { arity: 5 }
  211. Get l7 // { arity: 4 }
  212. Get l9 // { arity: 4 }
  213. cte l11 =
  214. Union // { arity: 5 }
  215. Get l10 // { arity: 5 }
  216. Project (#0..=#3, #5) // { arity: 5 }
  217. FlatMap guard_subquery_size(#4{count}) // { arity: 6 }
  218. Reduce group_by=[#0..=#3] aggregates=[count(*)] // { arity: 5 }
  219. Project (#0..=#3) // { arity: 4 }
  220. Get l10 // { arity: 5 }
  221. cte l12 =
  222. Project (#1, #2, #4, #10) // { arity: 4 }
  223. Map (case when (0 = (#9{count} % 2)) then "hi" else "lo" end) // { arity: 11 }
  224. Join on=(#0 = #5 AND #1 = #8 AND #2 = #6 AND #3 = #7) type=differential // { arity: 10 }
  225. implementation
  226. %0:l6[#0, #2, #3, #1]KKKK » %1[#0..=#3]KKKK
  227. ArrangeBy keys=[[#0, #2, #3, #1]] // { arity: 5 }
  228. Get l6 // { arity: 5 }
  229. ArrangeBy keys=[[#0..=#3]] // { arity: 5 }
  230. Union // { arity: 5 }
  231. Get l11 // { arity: 5 }
  232. Project (#0..=#3, #8) // { arity: 5 }
  233. Map (null) // { arity: 9 }
  234. Join on=(#0 = #4 AND #1 = #5 AND #2 = #6 AND #3 = #7) type=differential // { arity: 8 }
  235. implementation
  236. %1:l9[#0..=#3]UKKKK » %0[#0..=#3]KKKK
  237. ArrangeBy keys=[[#0..=#3]] // { arity: 4 }
  238. Union // { arity: 4 }
  239. Negate // { arity: 4 }
  240. Distinct project=[#0..=#3] // { arity: 4 }
  241. Project (#0..=#3) // { arity: 4 }
  242. Get l11 // { arity: 5 }
  243. Get l7 // { arity: 4 }
  244. Get l9 // { arity: 4 }
  245. cte l13 =
  246. Filter (#1{target}) IS NOT NULL // { arity: 5 }
  247. Get l27 // { arity: 5 }
  248. cte l14 =
  249. Project (#0..=#3, #5) // { arity: 5 }
  250. Map ((#3{round} + 1)) // { arity: 6 }
  251. Join on=(#1{target} = #4{name}) type=differential // { arity: 5 }
  252. implementation
  253. %1:l2[#0{name}]Kef » %0:l13[#1{target}]Kef
  254. ArrangeBy keys=[[#1{target}]] // { arity: 4 }
  255. Project (#0..=#3) // { arity: 4 }
  256. Get l13 // { arity: 5 }
  257. ArrangeBy keys=[[#0{name}]] // { arity: 1 }
  258. Project (#1) // { arity: 1 }
  259. Filter ("&" = substr(#0, 1, 1)) // { arity: 2 }
  260. Get l2 // { arity: 2 }
  261. cte l15 =
  262. Distinct project=[#0] // { arity: 1 }
  263. Project (#1) // { arity: 1 }
  264. Get l14 // { arity: 5 }
  265. cte l16 =
  266. ArrangeBy keys=[[#0{name}]] // { arity: 1 }
  267. Get l15 // { arity: 1 }
  268. cte l17 =
  269. Reduce group_by=[#0] aggregates=[count(*)] // { arity: 2 }
  270. Project (#0) // { arity: 1 }
  271. Join on=(#0{name} = #1{link}) type=differential // { arity: 2 }
  272. implementation
  273. %0:l16[#0{name}]UK » %1:l1[#0{link}]K
  274. Get l16 // { arity: 1 }
  275. ArrangeBy keys=[[#0{link}]] // { arity: 1 }
  276. Project (#1) // { arity: 1 }
  277. Filter (#1{link}) IS NOT NULL // { arity: 2 }
  278. Get l1 // { arity: 2 }
  279. cte l18 =
  280. Union // { arity: 2 }
  281. Get l17 // { arity: 2 }
  282. Project (#0, #2) // { arity: 2 }
  283. Map (0) // { arity: 3 }
  284. Join on=(#0 = #1) type=differential // { arity: 2 }
  285. implementation
  286. %1:l16[#0]UK » %0[#0]K
  287. ArrangeBy keys=[[#0]] // { arity: 1 }
  288. Union // { arity: 1 }
  289. Negate // { arity: 1 }
  290. Project (#0) // { arity: 1 }
  291. Get l17 // { arity: 2 }
  292. Get l15 // { arity: 1 }
  293. Get l16 // { arity: 1 }
  294. cte l19 =
  295. Union // { arity: 2 }
  296. Get l18 // { arity: 2 }
  297. Project (#0, #2) // { arity: 2 }
  298. FlatMap guard_subquery_size(#1{count}) // { arity: 3 }
  299. Reduce group_by=[#0] aggregates=[count(*)] // { arity: 2 }
  300. Project (#0) // { arity: 1 }
  301. Get l18 // { arity: 2 }
  302. cte l20 =
  303. Project (#0..=#4, #6{count}) // { arity: 6 }
  304. Join on=(#1 = #5) type=differential // { arity: 7 }
  305. implementation
  306. %0:l14[#1]K » %1[#0]K
  307. ArrangeBy keys=[[#1]] // { arity: 5 }
  308. Get l14 // { arity: 5 }
  309. ArrangeBy keys=[[#0]] // { arity: 2 }
  310. Union // { arity: 2 }
  311. Get l19 // { arity: 2 }
  312. Project (#0, #2) // { arity: 2 }
  313. Map (null) // { arity: 3 }
  314. Join on=(#0 = #1) type=differential // { arity: 2 }
  315. implementation
  316. %1:l16[#0]UK » %0[#0]K
  317. ArrangeBy keys=[[#0]] // { arity: 1 }
  318. Union // { arity: 1 }
  319. Negate // { arity: 1 }
  320. Distinct project=[#0] // { arity: 1 }
  321. Project (#0) // { arity: 1 }
  322. Get l19 // { arity: 2 }
  323. Get l15 // { arity: 1 }
  324. Get l16 // { arity: 1 }
  325. cte l21 =
  326. Distinct project=[#0, #2, #3, #1] // { arity: 4 }
  327. Project (#0..=#3) // { arity: 4 }
  328. Get l20 // { arity: 6 }
  329. cte l22 =
  330. Reduce group_by=[#0..=#3] aggregates=[count(*)] // { arity: 5 }
  331. Project (#0..=#3) // { arity: 4 }
  332. Filter (#7{pulse} = "hi") // { arity: 8 }
  333. TopK group_by=[#0, #1, #2, #3, #4] order_by=[#5 desc nulls_first, #6 desc nulls_first] limit=1 exp_group_size=1000 // { arity: 8 }
  334. Project (#0..=#4, #6..=#8) // { arity: 8 }
  335. Filter ((#6{press} < #1{press}) OR ((#1{press} = #6{press}) AND ((#7{round} < #2{round}) OR ((#2{round} = #7{round}) AND (#4{source} <= #0{source}))))) // { arity: 9 }
  336. Join on=(#3{name} = #5{target}) type=differential // { arity: 9 }
  337. implementation
  338. %0:l21[#3{name}]K » %1:l13[#1{target}]K
  339. ArrangeBy keys=[[#3{name}]] // { arity: 4 }
  340. Get l21 // { arity: 4 }
  341. ArrangeBy keys=[[#1{target}]] // { arity: 5 }
  342. Get l13 // { arity: 5 }
  343. cte l23 =
  344. ArrangeBy keys=[[#0..=#3]] // { arity: 4 }
  345. Get l21 // { arity: 4 }
  346. cte l24 =
  347. Union // { arity: 5 }
  348. Get l22 // { arity: 5 }
  349. Project (#0..=#3, #8) // { arity: 5 }
  350. Map (0) // { arity: 9 }
  351. Join on=(#0 = #4 AND #1 = #5 AND #2 = #6 AND #3 = #7) type=differential // { arity: 8 }
  352. implementation
  353. %1:l23[#0..=#3]UKKKK » %0[#0..=#3]KKKK
  354. ArrangeBy keys=[[#0..=#3]] // { arity: 4 }
  355. Union // { arity: 4 }
  356. Negate // { arity: 4 }
  357. Project (#0..=#3) // { arity: 4 }
  358. Get l22 // { arity: 5 }
  359. Get l21 // { arity: 4 }
  360. Get l23 // { arity: 4 }
  361. cte l25 =
  362. Union // { arity: 5 }
  363. Get l24 // { arity: 5 }
  364. Project (#0..=#3, #5) // { arity: 5 }
  365. FlatMap guard_subquery_size(#4{count}) // { arity: 6 }
  366. Reduce group_by=[#0..=#3] aggregates=[count(*)] // { arity: 5 }
  367. Project (#0..=#3) // { arity: 4 }
  368. Get l24 // { arity: 5 }
  369. cte l26 =
  370. Project (#1, #2, #4, #11) // { arity: 4 }
  371. Map (case when (#5{count} = #10{count}) then "lo" else "hi" end) // { arity: 12 }
  372. Join on=(#0 = #6 AND #1 = #9 AND #2 = #7 AND #3 = #8) type=differential // { arity: 11 }
  373. implementation
  374. %0:l20[#0, #2, #3, #1]KKKK » %1[#0..=#3]KKKK
  375. ArrangeBy keys=[[#0, #2, #3, #1]] // { arity: 6 }
  376. Get l20 // { arity: 6 }
  377. ArrangeBy keys=[[#0..=#3]] // { arity: 5 }
  378. Union // { arity: 5 }
  379. Get l25 // { arity: 5 }
  380. Project (#0..=#3, #8) // { arity: 5 }
  381. Map (null) // { arity: 9 }
  382. Join on=(#0 = #4 AND #1 = #5 AND #2 = #6 AND #3 = #7) type=differential // { arity: 8 }
  383. implementation
  384. %1:l23[#0..=#3]UKKKK » %0[#0..=#3]KKKK
  385. ArrangeBy keys=[[#0..=#3]] // { arity: 4 }
  386. Union // { arity: 4 }
  387. Negate // { arity: 4 }
  388. Distinct project=[#0..=#3] // { arity: 4 }
  389. Project (#0..=#3) // { arity: 4 }
  390. Get l25 // { arity: 5 }
  391. Get l21 // { arity: 4 }
  392. Get l23 // { arity: 4 }
  393. cte l27 =
  394. Project (#0, #5, #1..=#3) // { arity: 5 }
  395. Join on=(#0{name} = #4{name}) type=differential // { arity: 6 }
  396. implementation
  397. %0:l4[#0{name}]K » %1:l1[#0{name}]K
  398. ArrangeBy keys=[[#0{name}]] // { arity: 4 }
  399. Get l4 // { arity: 4 }
  400. ArrangeBy keys=[[#0{name}]] // { arity: 2 }
  401. Filter (#0{name}) IS NOT NULL // { arity: 2 }
  402. Get l1 // { arity: 2 }
  403. Return // { arity: 5 }
  404. Filter (#1{target} = "cn") AND (#4{pulse} = "hi") // { arity: 5 }
  405. Get l27 // { arity: 5 }
  406. Source materialize.public.input
  407. Target cluster: quickstart
  408. EOF