123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- # Copyright Materialize, Inc. and contributors. All rights reserved.
- #
- # Use of this software is governed by the Business Source License
- # included in the LICENSE file at the root of this repository.
- #
- # As of the Change Date specified in that file, in accordance with
- # the Business Source License, use of this software will be governed
- # by the Apache License, Version 2.0.
- # https://github.com/MaterializeInc/advent-of-code-2023/blob/main/week1/aoc_1218.md
- mode cockroach
- statement ok
- CREATE TABLE input (input TEXT);
- statement ok
- INSERT INTO input VALUES (
- 'R 1 (#53d732)
- L 5 (#292431)
- U 6 (#4c7272)
- L 9 (#49ace3)
- U 3 (#7b94e6)
- R 1 (#5579d4)
- L 9 (#1d7886)
- U 3 (#171219)
- R 9 (#45fa39)
- R 11 (#222422)
- U 6 (#91c869)
- L 8 (#7581c5)
- U 9 (#46aab5)
- R 9 (#6f72a5)
- L 7 (#42abb1)');
- query II
- WITH MUTUALLY RECURSIVE
- lines(r INT, line TEXT) AS (
- SELECT r, regexp_split_to_array(input, '\n')[r] as line
- FROM input, generate_series(1, array_length(regexp_split_to_array(input, '\n'), 1)) r
- ),
- split1(r INT, dr INT, dc INT, steps INT) AS (
- SELECT
- r,
- CASE WHEN regexp_split_to_array(line, ' ')[1] = 'U' THEN -1
- WHEN regexp_split_to_array(line, ' ')[1] = 'D' THEN 1
- ELSE 0
- END,
- CASE WHEN regexp_split_to_array(line, ' ')[1] = 'L' THEN -1
- WHEN regexp_split_to_array(line, ' ')[1] = 'R' THEN 1
- ELSE 0
- END,
- regexp_split_to_array(line, ' ')[2]::INT
- FROM lines
- ),
- -- Part 1 is prefix sum followed by area calculations.
- -- We'll brute force the prefix sum part, and use the
- -- "trapezoid formula", summing + and - contributions
- -- as the path moves around.
- path1(r1 INT, c1 INT, r2 INT, c2 INT, rounds INT) AS (
- SELECT 0, 0, 0, 0, 1
- UNION
- SELECT
- path1.r2,
- path1.c2,
- path1.r2 + split1.dr * split1.steps,
- path1.c2 + split1.dc * split1.steps,
- path1.rounds + 1
- FROM path1, split1
- WHERE path1.rounds = split1.r
- ),
- -- The area carved by the path, plus half a unit of area
- -- for each path step, plus 4 * (1/4) units for the net
- -- four 90 degree turns.
- part1(part1 BIGINT) AS (
- SELECT
- ABS((SELECT SUM((r1 + r2) * (c1 - c2)) FROM path1)) / 2
- + (SELECT SUM(steps) FROM split1) / 2
- + 1
- ),
- -- Part 2 changes how we parse each line to give long paths.
- split2(r INT, dr INT, dc INT, steps INT) AS (
- SELECT
- r,
- CASE WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '3' THEN -1
- WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '1' THEN 1
- ELSE 0
- END,
- CASE WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '2' THEN -1
- WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '0' THEN 1
- ELSE 0
- END,
- 256 * 256 * get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 0)
- + 256 * get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 1)
- + get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 2)
- FROM lines
- ),
- path2(r1 BIGINT, c1 BIGINT, r2 BIGINT, c2 BIGINT, rounds INT) AS (
- SELECT 0, 0, 0, 0, 1
- UNION
- SELECT
- path2.r2,
- path2.c2,
- path2.r2 + split2.dr * split2.steps,
- path2.c2 + split2.dc * split2.steps,
- path2.rounds + 1
- FROM path2, split2
- WHERE path2.rounds = split2.r
- ),
- -- The area carved by the path, plus half a unit of area
- -- for each path step, plus 4 * (1/4) units for the net
- -- four 90 degree turns.
- part2(part2 BIGINT) AS (
- SELECT
- ABS((SELECT SUM((r1 + r2) * (c1 - c2)) FROM path2)) / 2
- + (SELECT SUM(steps) FROM split2) / 2
- + 1
- )
- SELECT * FROM part1, part2;
- ----
- 73 34133752459
- query T multiline
- EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, arity, join implementations) AS VERBOSE TEXT FOR
- WITH MUTUALLY RECURSIVE
- lines(r INT, line TEXT) AS (
- SELECT r, regexp_split_to_array(input, '\n')[r] as line
- FROM input, generate_series(1, array_length(regexp_split_to_array(input, '\n'), 1)) r
- ),
- split1(r INT, dr INT, dc INT, steps INT) AS (
- SELECT
- r,
- CASE WHEN regexp_split_to_array(line, ' ')[1] = 'U' THEN -1
- WHEN regexp_split_to_array(line, ' ')[1] = 'D' THEN 1
- ELSE 0
- END,
- CASE WHEN regexp_split_to_array(line, ' ')[1] = 'L' THEN -1
- WHEN regexp_split_to_array(line, ' ')[1] = 'R' THEN 1
- ELSE 0
- END,
- regexp_split_to_array(line, ' ')[2]::INT
- FROM lines
- ),
- -- Part 1 is prefix sum followed by area calculations.
- -- We'll brute force the prefix sum part, and use the
- -- "trapezoid formula", summing + and - contributions
- -- as the path moves around.
- path1(r1 INT, c1 INT, r2 INT, c2 INT, rounds INT) AS (
- SELECT 0, 0, 0, 0, 1
- UNION
- SELECT
- path1.r2,
- path1.c2,
- path1.r2 + split1.dr * split1.steps,
- path1.c2 + split1.dc * split1.steps,
- path1.rounds + 1
- FROM path1, split1
- WHERE path1.rounds = split1.r
- ),
- -- The area carved by the path, plus half a unit of area
- -- for each path step, plus 4 * (1/4) units for the net
- -- four 90 degree turns.
- part1(part1 BIGINT) AS (
- SELECT
- ABS((SELECT SUM((r1 + r2) * (c1 - c2)) FROM path1)) / 2
- + (SELECT SUM(steps) FROM split1) / 2
- + 1
- ),
- -- Part 2 changes how we parse each line to give long paths.
- split2(r INT, dr INT, dc INT, steps INT) AS (
- SELECT
- r,
- CASE WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '3' THEN -1
- WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '1' THEN 1
- ELSE 0
- END,
- CASE WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '2' THEN -1
- WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '0' THEN 1
- ELSE 0
- END,
- 256 * 256 * get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 0)
- + 256 * get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 1)
- + get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 2)
- FROM lines
- ),
- path2(r1 BIGINT, c1 BIGINT, r2 BIGINT, c2 BIGINT, rounds INT) AS (
- SELECT 0, 0, 0, 0, 1
- UNION
- SELECT
- path2.r2,
- path2.c2,
- path2.r2 + split2.dr * split2.steps,
- path2.c2 + split2.dc * split2.steps,
- path2.rounds + 1
- FROM path2, split2
- WHERE path2.rounds = split2.r
- ),
- -- The area carved by the path, plus half a unit of area
- -- for each path step, plus 4 * (1/4) units for the net
- -- four 90 degree turns.
- part2(part2 BIGINT) AS (
- SELECT
- ABS((SELECT SUM((r1 + r2) * (c1 - c2)) FROM path2)) / 2
- + (SELECT SUM(steps) FROM split2) / 2
- + 1
- )
- SELECT * FROM part1, part2;
- ----
- Explained Query:
- With
- cte l0 =
- Project (#1, #2) // { arity: 2 }
- Map (array_index(regexp_split_to_array["\n", case_insensitive=false](#0{input}), integer_to_bigint(#1{r}))) // { arity: 3 }
- FlatMap generate_series(1, (regexp_split_to_array["\n", case_insensitive=false](#0{input}) array_length 1), 1) // { arity: 2 }
- ReadStorage materialize.public.input // { arity: 1 }
- cte l1 =
- Reduce aggregates=[sum(#0{steps})] // { arity: 1 }
- Project (#2) // { arity: 1 }
- Map (text_to_integer(array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 2))) // { arity: 3 }
- Get l0 // { arity: 2 }
- cte l2 =
- Union // { arity: 1 }
- Get l1 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l1 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- Return // { arity: 2 }
- With Mutually Recursive
- cte l3 =
- Distinct project=[#0..=#4] // { arity: 5 }
- Union // { arity: 5 }
- Project (#0, #1, #7..=#9) // { arity: 5 }
- Map ((#0{r2} + (#4{dr} * #6{steps})), (#1{c2} + (#5{dc} * #6{steps})), (#2{rounds} + 1)) // { arity: 10 }
- Join on=(#2{rounds} = #3{r}) type=differential // { arity: 7 }
- implementation
- %0:l3[#2{rounds}]K » %1:l0[#0{r}]K
- ArrangeBy keys=[[#2{rounds}]] // { arity: 3 }
- Project (#2..=#4) // { arity: 3 }
- Get l3 // { arity: 5 }
- ArrangeBy keys=[[#0{r}]] // { arity: 4 }
- Project (#0, #4..=#6) // { arity: 4 }
- Map (regexp_split_to_array[" ", case_insensitive=false](#1{line}), array_index(#2, 1), case when (#3 = "U") then -1 else case when ("D" = array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 1)) then 1 else 0 end end, case when (#3 = "L") then -1 else case when ("R" = array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 1)) then 1 else 0 end end, text_to_integer(array_index(#2, 2))) // { arity: 7 }
- Get l0 // { arity: 2 }
- Constant // { arity: 5 }
- - (0, 0, 0, 0, 1)
- cte l4 =
- Reduce aggregates=[sum(((#0{r1} + #2{r2}) * (#1{c1} - #3{c2})))] // { arity: 1 }
- Project (#0..=#3) // { arity: 4 }
- Get l3 // { arity: 5 }
- cte l5 =
- Union // { arity: 1 }
- Get l4 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l4 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- cte l6 =
- Distinct project=[#0..=#4] // { arity: 5 }
- Union // { arity: 5 }
- Project (#0, #1, #7..=#9) // { arity: 5 }
- Map ((#0{r2} + integer_to_bigint((#4{dr} * #6{steps}))), (#1{c2} + integer_to_bigint((#5{dc} * #6{steps}))), (#2{rounds} + 1)) // { arity: 10 }
- Join on=(#2{rounds} = #3{r}) type=differential // { arity: 7 }
- implementation
- %0:l6[#2{rounds}]K » %1:l0[#0{r}]K
- ArrangeBy keys=[[#2{rounds}]] // { arity: 3 }
- Project (#2..=#4) // { arity: 3 }
- Get l6 // { arity: 5 }
- ArrangeBy keys=[[#0{r}]] // { arity: 4 }
- Project (#0, #4, #5, #7) // { arity: 4 }
- Map (array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 3), substr(#2, 8, 1), case when (#3 = "3") then -1 else case when ("1" = substr(array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 3), 8, 1)) then 1 else 0 end end, case when (#3 = "2") then -1 else case when ("0" = substr(array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 3), 8, 1)) then 1 else 0 end end, decode(("0" || substr(#2, 3, 5)), "hex"), (((65536 * get_byte(#6, 0)) + (256 * get_byte(#6, 1))) + get_byte(#6, 2))) // { arity: 8 }
- Get l0 // { arity: 2 }
- Constant // { arity: 5 }
- - (0, 0, 0, 0, 1)
- Return // { arity: 2 }
- With
- cte l7 =
- Reduce aggregates=[sum(((#0{r1} + #2{r2}) * (#1{c1} - #3{c2})))] // { arity: 1 }
- Project (#0..=#3) // { arity: 4 }
- Get l6 // { arity: 5 }
- cte l8 =
- Union // { arity: 1 }
- Get l7 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l7 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- cte l9 =
- Reduce aggregates=[sum(#0{steps})] // { arity: 1 }
- Project (#3) // { arity: 1 }
- Map (decode(("0" || substr(array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 3), 3, 5)), "hex"), (((65536 * get_byte(#2, 0)) + (256 * get_byte(#2, 1))) + get_byte(#2, 2))) // { arity: 4 }
- Get l0 // { arity: 2 }
- cte l10 =
- Union // { arity: 1 }
- Get l9 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l9 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- Return // { arity: 2 }
- Project (#4, #5) // { arity: 2 }
- Map ((((abs(#0{sum}) / 2) + (#1{sum} / 2)) + 1), numeric_to_bigint((((abs(#2{sum}) / 2) + bigint_to_numeric((#3{sum} / 2))) + 1))) // { arity: 6 }
- CrossJoin type=delta // { arity: 4 }
- implementation
- %0 » %1[×]U » %2[×]U » %3[×]U
- %1 » %0[×]U » %2[×]U » %3[×]U
- %2 » %0[×]U » %1[×]U » %3[×]U
- %3 » %0[×]U » %1[×]U » %2[×]U
- ArrangeBy keys=[[]] // { arity: 1 }
- Union // { arity: 1 }
- Get l5 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l5 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- ArrangeBy keys=[[]] // { arity: 1 }
- Union // { arity: 1 }
- Get l2 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l2 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- ArrangeBy keys=[[]] // { arity: 1 }
- Union // { arity: 1 }
- Get l8 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l8 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- ArrangeBy keys=[[]] // { arity: 1 }
- Union // { arity: 1 }
- Get l10 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l10 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- Source materialize.public.input
- Target cluster: quickstart
- EOF
|