aoc_1215.slt 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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_1215.md
  10. mode cockroach
  11. statement ok
  12. CREATE TABLE input (input TEXT);
  13. statement ok
  14. INSERT INTO input
  15. VALUES ('rn=1,xw-,nn=8,zg=2,lw=4,oo=2,tt-,wv=9,hy=7,rs=8,sm=4,lf-,td=9,zz=1,ca=2,nd-');
  16. query II
  17. WITH MUTUALLY RECURSIVE (RETURN AT RECURSION LIMIT 10)
  18. strings(r INT, string TEXT) AS (
  19. SELECT r, regexp_split_to_array(input, ',')[r]
  20. FROM input, generate_series(1, array_length(regexp_split_to_array(input, ','), 1)) r
  21. ),
  22. -- Advance the hash by one character, until all strings are empty.
  23. hashes(string TEXT, hash BIGINT) AS (
  24. SELECT string, 0 as hash
  25. FROM strings
  26. UNION ALL
  27. SELECT substring(string, 2), ((hash + ascii(substring(string, 1, 1))) * 17) % 256
  28. FROM hashes
  29. WHERE length(string) > 0
  30. ),
  31. part1(part1 BIGINT) AS (
  32. SELECT SUM(hash)
  33. FROM hashes
  34. WHERE string = ''
  35. ),
  36. -- Parse strings as symbol plus commands; either `-` or `=X`.
  37. commands(r INT, symb TEXT, op INT) AS (
  38. SELECT
  39. r,
  40. CASE WHEN substring(string, length(string)) = '-'
  41. THEN substring(string, 1, length(string)-1)
  42. ELSE substring(string, 1, length(string)-2)
  43. END,
  44. CASE WHEN substring(string, length(string)) = '-'
  45. THEN 0
  46. ELSE substring(string, length(string))::INT
  47. END
  48. FROM strings
  49. ),
  50. -- Operations that happen after a symbol's last delete operation.
  51. -- All other operations do not matter, and do not affect the state.
  52. final_ops(r INT, symb TEXT, op INT) AS (
  53. SELECT *
  54. FROM commands
  55. WHERE r > COALESCE(
  56. (SELECT MAX(r)
  57. FROM commands c2
  58. WHERE commands.symb = c2.symb
  59. AND c2.op = 0), 0)
  60. ),
  61. -- Each symbol is summarized by their first final insert time, and the last final operation
  62. final_state(r INT, symb TEXT, op INT) AS (
  63. SELECT DISTINCT ON(symb)
  64. (SELECT MIN(r) FROM final_ops fo2 WHERE fo2.symb = final_ops.symb),
  65. symb,
  66. op
  67. FROM final_ops
  68. ORDER BY symb, r DESC, op
  69. ),
  70. -- Redo the hash computation on symbols rather than commands.
  71. hashes2(start TEXT, string TEXT, hash BIGINT) AS (
  72. SELECT symb as start, symb as string, 0 as hash
  73. FROM final_state
  74. UNION ALL
  75. SELECT start, substring(string, 2), ((hash + ascii(substring(string, 1, 1))) * 17) % 256
  76. FROM hashes2
  77. WHERE length(string) > 0
  78. ),
  79. -- Bin up the state, so's we can tabulate it
  80. binned(hash BIGINT, r INT, symb TEXT, op INT) AS (
  81. SELECT hash, final_state.*
  82. FROM hashes2, final_state
  83. WHERE hashes2.start = symb
  84. AND hashes2.string = ''
  85. ),
  86. -- Sum the product of 1 + hash, the position in bin by r, and the op.
  87. part2(part2 BIGINT) AS (
  88. SELECT SUM(
  89. (1 + hash) *
  90. (SELECT COUNT(*) FROM binned b2 WHERE binned.hash = b2.hash AND binned.r >= b2.r) *
  91. op
  92. )
  93. FROM binned
  94. ),
  95. potato(x int) as (select 1)
  96. SELECT * FROM part1, part2;
  97. ----
  98. 2021 6155
  99. query T multiline
  100. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, arity, join implementations) AS VERBOSE TEXT FOR
  101. WITH MUTUALLY RECURSIVE (RETURN AT RECURSION LIMIT 10)
  102. strings(r INT, string TEXT) AS (
  103. SELECT r, regexp_split_to_array(input, ',')[r]
  104. FROM input, generate_series(1, array_length(regexp_split_to_array(input, ','), 1)) r
  105. ),
  106. -- Advance the hash by one character, until all strings are empty.
  107. hashes(string TEXT, hash BIGINT) AS (
  108. SELECT string, 0 as hash
  109. FROM strings
  110. UNION ALL
  111. SELECT substring(string, 2), ((hash + ascii(substring(string, 1, 1))) * 17) % 256
  112. FROM hashes
  113. WHERE length(string) > 0
  114. ),
  115. part1(part1 BIGINT) AS (
  116. SELECT SUM(hash)
  117. FROM hashes
  118. WHERE string = ''
  119. ),
  120. -- Parse strings as symbol plus commands; either `-` or `=X`.
  121. commands(r INT, symb TEXT, op INT) AS (
  122. SELECT
  123. r,
  124. CASE WHEN substring(string, length(string)) = '-'
  125. THEN substring(string, 1, length(string)-1)
  126. ELSE substring(string, 1, length(string)-2)
  127. END,
  128. CASE WHEN substring(string, length(string)) = '-'
  129. THEN 0
  130. ELSE substring(string, length(string))::INT
  131. END
  132. FROM strings
  133. ),
  134. -- Operations that happen after a symbol's last delete operation.
  135. -- All other operations do not matter, and do not affect the state.
  136. final_ops(r INT, symb TEXT, op INT) AS (
  137. SELECT *
  138. FROM commands
  139. WHERE r > COALESCE(
  140. (SELECT MAX(r)
  141. FROM commands c2
  142. WHERE commands.symb = c2.symb
  143. AND c2.op = 0), 0)
  144. ),
  145. -- Each symbol is summarized by their first final insert time, and the last final operation
  146. final_state(r INT, symb TEXT, op INT) AS (
  147. SELECT DISTINCT ON(symb)
  148. (SELECT MIN(r) FROM final_ops fo2 WHERE fo2.symb = final_ops.symb),
  149. symb,
  150. op
  151. FROM final_ops
  152. ORDER BY symb, r DESC, op
  153. ),
  154. -- Redo the hash computation on symbols rather than commands.
  155. hashes2(start TEXT, string TEXT, hash BIGINT) AS (
  156. SELECT symb as start, symb as string, 0 as hash
  157. FROM final_state
  158. UNION ALL
  159. SELECT start, substring(string, 2), ((hash + ascii(substring(string, 1, 1))) * 17) % 256
  160. FROM hashes2
  161. WHERE length(string) > 0
  162. ),
  163. -- Bin up the state, so's we can tabulate it
  164. binned(hash BIGINT, r INT, symb TEXT, op INT) AS (
  165. SELECT hash, final_state.*
  166. FROM hashes2, final_state
  167. WHERE hashes2.start = symb
  168. AND hashes2.string = ''
  169. ),
  170. -- Sum the product of 1 + hash, the position in bin by r, and the op.
  171. part2(part2 BIGINT) AS (
  172. SELECT SUM(
  173. (1 + hash) *
  174. (SELECT COUNT(*) FROM binned b2 WHERE binned.hash = b2.hash AND binned.r >= b2.r) *
  175. op
  176. )
  177. FROM binned
  178. ),
  179. potato(x int) as (select 1)
  180. SELECT * FROM part1, part2;
  181. ----
  182. Explained Query:
  183. With
  184. cte l0 =
  185. Project (#1, #2) // { arity: 2 }
  186. Map (array_index(regexp_split_to_array[",", case_insensitive=false](#0{input}), integer_to_bigint(#1{r}))) // { arity: 3 }
  187. FlatMap generate_series(1, (regexp_split_to_array[",", case_insensitive=false](#0{input}) array_length 1), 1) // { arity: 2 }
  188. ReadStorage materialize.public.input // { arity: 1 }
  189. cte l1 =
  190. Distinct project=[#0] // { arity: 1 }
  191. Project (#2) // { arity: 1 }
  192. Map (case when ("-" = substr(#1{string}, char_length(#1{string}))) then substr(#1{string}, 1, (char_length(#1{string}) - 1)) else substr(#1{string}, 1, (char_length(#1{string}) - 2)) end) // { arity: 3 }
  193. Get l0 // { arity: 2 }
  194. cte l2 =
  195. Reduce group_by=[#0] aggregates=[max(#1{r})] // { arity: 2 }
  196. Project (#0, #1) // { arity: 2 }
  197. Join on=(#0{symb} = #2{symb}) type=differential // { arity: 3 }
  198. implementation
  199. %0:l1[#0{symb}]UKA » %1:l0[#1{symb}]Kef
  200. ArrangeBy keys=[[#0{symb}]] // { arity: 1 }
  201. Get l1 // { arity: 1 }
  202. ArrangeBy keys=[[#1{symb}]] // { arity: 2 }
  203. Project (#0, #3) // { arity: 2 }
  204. Filter (#3) IS NOT NULL AND (0 = case when #2 then 0 else text_to_integer(substr(#1{string}, char_length(#1{string}))) end) // { arity: 4 }
  205. Map (("-" = substr(#1{string}, char_length(#1{string}))), case when #2 then substr(#1{string}, 1, (char_length(#1{string}) - 1)) else substr(#1{string}, 1, (char_length(#1{string}) - 2)) end) // { arity: 4 }
  206. Get l0 // { arity: 2 }
  207. cte l3 =
  208. Union // { arity: 2 }
  209. Get l2 // { arity: 2 }
  210. Map (null) // { arity: 2 }
  211. Union // { arity: 1 }
  212. Negate // { arity: 1 }
  213. Project (#0) // { arity: 1 }
  214. Get l2 // { arity: 2 }
  215. Get l1 // { arity: 1 }
  216. cte l4 =
  217. Project (#0..=#2) // { arity: 3 }
  218. Filter (#0{r} > coalesce(#4{max}, 0)) // { arity: 5 }
  219. Join on=(#1 = #3) type=differential // { arity: 5 }
  220. implementation
  221. %1[#0]UK » %0:l0[#1]K
  222. ArrangeBy keys=[[#1]] // { arity: 3 }
  223. Project (#0, #3, #4) // { arity: 3 }
  224. Map (("-" = substr(#1{string}, char_length(#1{string}))), case when #2 then substr(#1{string}, 1, (char_length(#1{string}) - 1)) else substr(#1{string}, 1, (char_length(#1{string}) - 2)) end, case when #2 then 0 else text_to_integer(substr(#1{string}, char_length(#1{string}))) end) // { arity: 5 }
  225. Get l0 // { arity: 2 }
  226. ArrangeBy keys=[[#0]] // { arity: 2 }
  227. Union // { arity: 2 }
  228. Get l3 // { arity: 2 }
  229. Map (null) // { arity: 2 }
  230. Union // { arity: 1 }
  231. Negate // { arity: 1 }
  232. Project (#0) // { arity: 1 }
  233. Get l3 // { arity: 2 }
  234. Get l1 // { arity: 1 }
  235. cte l5 =
  236. Distinct project=[#0] // { arity: 1 }
  237. Project (#1) // { arity: 1 }
  238. Get l4 // { arity: 3 }
  239. cte l6 =
  240. Reduce group_by=[#0] aggregates=[min(#1{r})] // { arity: 2 }
  241. Project (#0, #1) // { arity: 2 }
  242. Join on=(#0{symb} = #2{symb}) type=differential // { arity: 3 }
  243. implementation
  244. %0:l5[#0{symb}]UKA » %1:l4[#1{symb}]K
  245. ArrangeBy keys=[[#0{symb}]] // { arity: 1 }
  246. Get l5 // { arity: 1 }
  247. ArrangeBy keys=[[#1{symb}]] // { arity: 2 }
  248. Project (#0, #1) // { arity: 2 }
  249. Filter (#1{symb}) IS NOT NULL // { arity: 3 }
  250. Get l4 // { arity: 3 }
  251. cte l7 =
  252. Union // { arity: 2 }
  253. Get l6 // { arity: 2 }
  254. Map (null) // { arity: 2 }
  255. Union // { arity: 1 }
  256. Negate // { arity: 1 }
  257. Project (#0) // { arity: 1 }
  258. Get l6 // { arity: 2 }
  259. Get l5 // { arity: 1 }
  260. cte l8 =
  261. Project (#1..=#4) // { arity: 4 }
  262. TopK group_by=[#1] order_by=[#0 desc nulls_first, #2 asc nulls_last] limit=1 // { arity: 5 }
  263. Project (#0..=#2, #4{min}, #5) // { arity: 5 }
  264. Map ((#1) IS NULL) // { arity: 6 }
  265. Join on=(#1 = #3) type=differential // { arity: 5 }
  266. implementation
  267. %1[#0]UK » %0:l4[#1]K
  268. ArrangeBy keys=[[#1]] // { arity: 3 }
  269. Get l4 // { arity: 3 }
  270. ArrangeBy keys=[[#0]] // { arity: 2 }
  271. Union // { arity: 2 }
  272. Get l7 // { arity: 2 }
  273. Map (null) // { arity: 2 }
  274. Union // { arity: 1 }
  275. Negate // { arity: 1 }
  276. Project (#0) // { arity: 1 }
  277. Get l7 // { arity: 2 }
  278. Get l5 // { arity: 1 }
  279. Return // { arity: 2 }
  280. With Mutually Recursive
  281. cte [recursion_limit=10, return_at_limit] l9 =
  282. Union // { arity: 2 }
  283. Project (#1, #2) // { arity: 2 }
  284. Map (0) // { arity: 3 }
  285. Get l0 // { arity: 2 }
  286. Project (#2, #3) // { arity: 2 }
  287. Filter (char_length(#0{string}) > 0) // { arity: 4 }
  288. Map (substr(#0{string}, 2), (((#1{hash} + integer_to_bigint(ascii(substr(#0{string}, 1, 1)))) * 17) % 256)) // { arity: 4 }
  289. Get l9 // { arity: 2 }
  290. cte l10 =
  291. Reduce aggregates=[sum(#0{hash})] // { arity: 1 }
  292. Project (#1) // { arity: 1 }
  293. Filter (#0{string} = "") // { arity: 2 }
  294. Get l9 // { arity: 2 }
  295. cte [recursion_limit=10, return_at_limit] l11 =
  296. Union // { arity: 3 }
  297. Project (#0, #0, #4) // { arity: 3 }
  298. Map (0) // { arity: 5 }
  299. Get l8 // { arity: 4 }
  300. Project (#0, #3, #4) // { arity: 3 }
  301. Filter (char_length(#1{string}) > 0) // { arity: 5 }
  302. Map (substr(#1{string}, 2), (((#2{hash} + integer_to_bigint(ascii(substr(#1{string}, 1, 1)))) * 17) % 256)) // { arity: 5 }
  303. Get l11 // { arity: 3 }
  304. Return // { arity: 2 }
  305. With
  306. cte l12 =
  307. Project (#1, #3, #4{min}) // { arity: 3 }
  308. Join on=(#0{start} = #2{symb}) type=differential // { arity: 5 }
  309. implementation
  310. %1:l8[#0{symb}]UKf » %0:l11[#0{start}]Kef
  311. ArrangeBy keys=[[#0{start}]] // { arity: 2 }
  312. Project (#0, #2) // { arity: 2 }
  313. Filter (#1{string} = "") AND (#0{start}) IS NOT NULL // { arity: 3 }
  314. Get l11 // { arity: 3 }
  315. ArrangeBy keys=[[#0{symb}]] // { arity: 3 }
  316. Project (#0..=#2{min}) // { arity: 3 }
  317. Filter NOT(#3) // { arity: 4 }
  318. Get l8 // { arity: 4 }
  319. cte l13 =
  320. Project (#0, #2{min}) // { arity: 2 }
  321. Get l12 // { arity: 3 }
  322. cte l14 =
  323. Distinct project=[#0, #1{min}] // { arity: 2 }
  324. Get l13 // { arity: 2 }
  325. cte l15 =
  326. Reduce group_by=[#0, #1{min}] aggregates=[count(*)] // { arity: 3 }
  327. Project (#0, #1{min}) // { arity: 2 }
  328. Filter (#1{min} >= #3{min}) // { arity: 4 }
  329. Join on=(#0{hash} = #2{hash}) type=differential // { arity: 4 }
  330. implementation
  331. %0:l14[#0{hash}]K » %1:l13[#0{hash}]K
  332. ArrangeBy keys=[[#0{hash}]] // { arity: 2 }
  333. Get l14 // { arity: 2 }
  334. ArrangeBy keys=[[#0{hash}]] // { arity: 2 }
  335. Get l13 // { arity: 2 }
  336. cte l16 =
  337. Union // { arity: 3 }
  338. Get l15 // { arity: 3 }
  339. Map (0) // { arity: 3 }
  340. Union // { arity: 2 }
  341. Negate // { arity: 2 }
  342. Project (#0, #1{min}) // { arity: 2 }
  343. Get l15 // { arity: 3 }
  344. Get l14 // { arity: 2 }
  345. cte l17 =
  346. Reduce aggregates=[sum((((1 + #0{hash}) * #2{count}) * integer_to_bigint(#1{op})))] // { arity: 1 }
  347. Project (#0, #1, #5{count}) // { arity: 3 }
  348. Join on=(#0 = #3 AND #2{min} = #4{min}) type=differential // { arity: 6 }
  349. implementation
  350. %1[#0, #1]UKK » %0:l12[#0, #2]KK
  351. ArrangeBy keys=[[#0, #2{min}]] // { arity: 3 }
  352. Get l12 // { arity: 3 }
  353. ArrangeBy keys=[[#0, #1{min}]] // { arity: 3 }
  354. Union // { arity: 3 }
  355. Get l16 // { arity: 3 }
  356. Map (null) // { arity: 3 }
  357. Union // { arity: 2 }
  358. Negate // { arity: 2 }
  359. Project (#0, #1{min}) // { arity: 2 }
  360. Get l16 // { arity: 3 }
  361. Get l14 // { arity: 2 }
  362. Return // { arity: 2 }
  363. CrossJoin type=differential // { arity: 2 }
  364. implementation
  365. %0[×]U » %1[×]U
  366. ArrangeBy keys=[[]] // { arity: 1 }
  367. Project (#1) // { arity: 1 }
  368. Map (numeric_to_bigint(#0{sum})) // { arity: 2 }
  369. Union // { arity: 1 }
  370. Get l10 // { arity: 1 }
  371. Map (null) // { arity: 1 }
  372. Union // { arity: 0 }
  373. Negate // { arity: 0 }
  374. Project () // { arity: 0 }
  375. Get l10 // { arity: 1 }
  376. Constant // { arity: 0 }
  377. - ()
  378. ArrangeBy keys=[[]] // { arity: 1 }
  379. Project (#1) // { arity: 1 }
  380. Map (numeric_to_bigint(#0{sum})) // { arity: 2 }
  381. Union // { arity: 1 }
  382. Get l17 // { arity: 1 }
  383. Map (null) // { arity: 1 }
  384. Union // { arity: 0 }
  385. Negate // { arity: 0 }
  386. Project () // { arity: 0 }
  387. Get l17 // { arity: 1 }
  388. Constant // { arity: 0 }
  389. - ()
  390. Source materialize.public.input
  391. Target cluster: quickstart
  392. EOF