aoc_1212.slt 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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_1212.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(r INT, characters TEXT, springs TEXT) AS (
  18. SELECT
  19. row_id,
  20. regexp_split_to_array(regexp_split_to_array(input, '\n')[row_id], ' ')[1] || '.',
  21. regexp_split_to_array(regexp_split_to_array(input, '\n')[row_id], ' ')[2]
  22. FROM
  23. input,
  24. generate_series(1, array_length(regexp_split_to_array(input, '\n'), 1)) row_id
  25. ),
  26. characters(r INT, pos INT, symb TEXT) AS (
  27. SELECT
  28. r,
  29. pos,
  30. substring(characters, pos, 1)
  31. FROM
  32. lines,
  33. generate_series(1, length(characters)) pos
  34. ),
  35. springs(r INT, pos INT, len INT) AS (
  36. SELECT
  37. r,
  38. pos,
  39. regexp_split_to_array(springs, ',')[pos]::INT
  40. FROM
  41. lines,
  42. generate_series(1, array_length(regexp_split_to_array(springs, ','), 1)) pos
  43. ),
  44. -- How many ways can we pack row `r`'s first `spring` springs (plus a space) into the first `chars` characters?
  45. -- Importantly, the "plus a space" applies to the last spring also! Each of these should admit the immediate appending of a new spring.
  46. fits(r INT, chars INT, spring INT) AS (
  47. -- We can pack no springs into no characters.
  48. SELECT r, 0, 0
  49. FROM lines
  50. -- We can extend any fits with a blank, as long as there are no '#' observations.
  51. UNION ALL
  52. SELECT fits.r, fits.chars + 1, fits.spring
  53. FROM fits, characters
  54. WHERE fits.r = characters.r
  55. AND fits.chars + 1 = characters.pos
  56. AND characters.symb != '#'
  57. -- We can extend any fits with the next spring and a blank, as long as no '.' in the spring and no '#' in the blank.
  58. UNION ALL
  59. SELECT fits.r, fits.chars + springs.len + 1, fits.spring + 1
  60. FROM
  61. fits,
  62. springs,
  63. characters
  64. WHERE fits.r = springs.r
  65. AND fits.spring + 1 = springs.pos
  66. AND fits.r = characters.r
  67. AND fits.chars + springs.len + 1 = characters.pos
  68. AND characters.symb != '#'
  69. AND NOT EXISTS (SELECT FROM characters c WHERE c.r = fits.r AND c.symb = '.' AND c.pos BETWEEN fits.chars + 1 AND fits.chars + springs.len)
  70. ),
  71. fit_counts(r INT, chars INT, spring INT, count BIGINT) AS (
  72. SELECT r, chars, spring, COUNT(*) AS count
  73. FROM fits
  74. GROUP BY r, chars, spring
  75. ),
  76. counts(r INT, chars INT, spring INT, count BIGINT) AS (
  77. SELECT DISTINCT ON (r) r, chars, spring, count
  78. FROM fit_counts
  79. ORDER BY r, chars DESC, spring DESC
  80. ),
  81. potato (x INT) AS ( SELECT 1 )
  82. SELECT SUM(count) FROM counts;
  83. ----
  84. Explained Query:
  85. With
  86. cte l0 =
  87. Project (#1, #3, #4) // { arity: 3 }
  88. Map (regexp_split_to_array[" ", case_insensitive=false](array_index(regexp_split_to_array["\n", case_insensitive=false](#0{input}), integer_to_bigint(#1{row_id}))), (array_index(#2, 1) || "."), array_index(#2, 2)) // { arity: 5 }
  89. FlatMap generate_series(1, (regexp_split_to_array["\n", case_insensitive=false](#0{input}) array_length 1), 1) // { arity: 2 }
  90. ReadStorage materialize.public.input // { arity: 1 }
  91. cte l1 =
  92. Project (#0, #2, #3) // { arity: 3 }
  93. Map (substr(#1{characters}, #2{pos}, 1)) // { arity: 4 }
  94. FlatMap generate_series(1, char_length(#1{characters}), 1) // { arity: 3 }
  95. Project (#0, #1) // { arity: 2 }
  96. Get l0 // { arity: 3 }
  97. cte l2 =
  98. ArrangeBy keys=[[#0{r}, #1{pos}]] // { arity: 2 }
  99. Project (#0, #1) // { arity: 2 }
  100. Filter (#2{symb} != "#") // { arity: 3 }
  101. Get l1 // { arity: 3 }
  102. Return // { arity: 1 }
  103. With Mutually Recursive
  104. cte l3 =
  105. Project (#0..=#2, #5) // { arity: 4 }
  106. Join on=(#0{r} = #3{r} = #6{r} AND #4{pos} = (#2{spring} + 1) AND #7{pos} = ((#1{chars} + #5{len}) + 1)) type=delta // { arity: 8 }
  107. implementation
  108. %0:l5 » %1[#0{r}, #1{pos}]KK » %2:l2[#0{r}, #1{pos}]KKf
  109. %1 » %0:l5[#0{r}, (#2{spring} + 1)]KK » %2:l2[#0{r}, #1{pos}]KKf
  110. %2:l2 » %0:l5[#0{r}]K » %1[#0{r}, #1{pos}]KK
  111. ArrangeBy keys=[[#0{r}], [#0{r}, (#2{spring} + 1)]] // { arity: 3 }
  112. Get l5 // { arity: 3 }
  113. ArrangeBy keys=[[#0{r}, #1{pos}]] // { arity: 3 }
  114. Project (#0, #2, #3) // { arity: 3 }
  115. Map (text_to_integer(array_index(regexp_split_to_array[",", case_insensitive=false](#1{springs}), integer_to_bigint(#2{pos})))) // { arity: 4 }
  116. FlatMap generate_series(1, (regexp_split_to_array[",", case_insensitive=false](#1{springs}) array_length 1), 1) // { arity: 3 }
  117. Project (#0, #2) // { arity: 2 }
  118. Get l0 // { arity: 3 }
  119. Get l2 // { arity: 2 }
  120. cte l4 =
  121. Distinct project=[#0..=#2] // { arity: 3 }
  122. Project (#0, #1, #3) // { arity: 3 }
  123. Get l3 // { arity: 4 }
  124. cte l5 =
  125. Union // { arity: 3 }
  126. Project (#0, #3, #4) // { arity: 3 }
  127. Map (0, 0) // { arity: 5 }
  128. Get l0 // { arity: 3 }
  129. Project (#0, #5, #2) // { arity: 3 }
  130. Map ((#1{chars} + 1)) // { arity: 6 }
  131. Join on=(#0{r} = #3{r} AND #4{pos} = (#1{chars} + 1)) type=differential // { arity: 5 }
  132. implementation
  133. %1:l2[#0{r}, #1{pos}]KKf » %0:l5[#0{r}, (#1{chars} + 1)]KKf
  134. ArrangeBy keys=[[#0{r}, (#1{chars} + 1)]] // { arity: 3 }
  135. Get l5 // { arity: 3 }
  136. Get l2 // { arity: 2 }
  137. Project (#0, #7, #8) // { arity: 3 }
  138. Map (((#1{chars} + #3{len}) + 1), (#2{spring} + 1)) // { arity: 9 }
  139. Join on=(#0 = #4 AND #1 = #5 AND #3 = #6) type=differential // { arity: 7 }
  140. implementation
  141. %0:l3[#0, #1, #3]KKK » %1[#0..=#2]KKK
  142. ArrangeBy keys=[[#0, #1, #3]] // { arity: 4 }
  143. Get l3 // { arity: 4 }
  144. ArrangeBy keys=[[#0..=#2]] // { arity: 3 }
  145. Union // { arity: 3 }
  146. Negate // { arity: 3 }
  147. Distinct project=[#0..=#2] // { arity: 3 }
  148. Project (#0..=#2) // { arity: 3 }
  149. Filter (#4{pos} >= (#1{chars} + 1)) AND (#4{pos} <= (#1{chars} + #2{len})) // { arity: 5 }
  150. Join on=(#0{r} = #3{r}) type=differential // { arity: 5 }
  151. implementation
  152. %1:l1[#0{r}]Kef » %0:l4[#0{r}]Kef
  153. ArrangeBy keys=[[#0{r}]] // { arity: 3 }
  154. Get l4 // { arity: 3 }
  155. ArrangeBy keys=[[#0{r}]] // { arity: 2 }
  156. Project (#0, #1) // { arity: 2 }
  157. Filter (#2{symb} = ".") // { arity: 3 }
  158. Get l1 // { arity: 3 }
  159. Get l4 // { arity: 3 }
  160. Return // { arity: 1 }
  161. With
  162. cte l6 =
  163. Reduce aggregates=[sum(#0{count})] // { arity: 1 }
  164. Project (#3{count}) // { arity: 1 }
  165. TopK group_by=[#0] order_by=[#1 desc nulls_first, #2 desc nulls_first] limit=1 // { arity: 4 }
  166. Reduce group_by=[#0..=#2] aggregates=[count(*)] // { arity: 4 }
  167. Get l5 // { arity: 3 }
  168. Return // { arity: 1 }
  169. Union // { arity: 1 }
  170. Get l6 // { arity: 1 }
  171. Map (null) // { arity: 1 }
  172. Union // { arity: 0 }
  173. Negate // { arity: 0 }
  174. Project () // { arity: 0 }
  175. Get l6 // { arity: 1 }
  176. Constant // { arity: 0 }
  177. - ()
  178. Source materialize.public.input
  179. Target cluster: quickstart
  180. EOF