Skip to content

DuckDB 1.4.4 reports internal error, but v1.5-dev4092 works when run following sql #7

@l1t1

Description

@l1t1
CREATE TABLE sudoku9_9 (
  id int NOT NULL,
  puzzle varchar(255) DEFAULT NULL,
  PRIMARY KEY (id)
);
insert into sudoku9_9(id,puzzle) values('801','76?5?89?4
9?467??52
85124?6??
1??367245
??592?1??
?23??5?69
5?????397
????5?4?1
2??19?586');
WITH RECURSIVE
bs_t AS MATERIALIZED (
SELECT id, replace(puzzle, E'\n', '') AS bs
FROM sudoku9_9
)
--from bs_t limit 1;
,
init_t AS (
SELECT id, row_can, col_can, box_can, todo, bs AS done
FROM bs_t
CROSS JOIN LATERAL (
WITH board_t AS (
SELECT
array_agg(mask ORDER BY i) AS bd,
COALESCE(array_agg(((i // 9 + 1) << 8) | ((i % 9 + 1) << 4) | (i // 27 * 3 + i % 9 // 3 + 1))
FILTER (WHERE mask = 0), ARRAY[]::int[]) AS todo
FROM (
SELECT i, (1 << (ascii(substr(bs, i+1, 1)) - 49)) & 511 mask
FROM generate_series(0, 80) g(i)
			) AS bd_t
		)
SELECT
ARRAY[
xor(511, (bd[1]  | bd[2]  | bd[3]  | bd[4]  | bd[5]  | bd[6]  | bd[7]  | bd[8]  | bd[9])),
xor(511, (bd[10] | bd[11] | bd[12] | bd[13] | bd[14] | bd[15] | bd[16] | bd[17] | bd[18])),
xor(511, (bd[19] | bd[20] | bd[21] | bd[22] | bd[23] | bd[24] | bd[25] | bd[26] | bd[27])),
xor(511, (bd[28] | bd[29] | bd[30] | bd[31] | bd[32] | bd[33] | bd[34] | bd[35] | bd[36])),
xor(511, (bd[37] | bd[38] | bd[39] | bd[40] | bd[41] | bd[42] | bd[43] | bd[44] | bd[45])),
xor(511, (bd[46] | bd[47] | bd[48] | bd[49] | bd[50] | bd[51] | bd[52] | bd[53] | bd[54])),
xor(511, (bd[55] | bd[56] | bd[57] | bd[58] | bd[59] | bd[60] | bd[61] | bd[62] | bd[63])),
xor(511, (bd[64] | bd[65] | bd[66] | bd[67] | bd[68] | bd[69] | bd[70] | bd[71] | bd[72])),
xor(511, (bd[73] | bd[74] | bd[75] | bd[76] | bd[77] | bd[78] | bd[79] | bd[80] | bd[81]))
			]::int[] AS row_can,

ARRAY[
xor(511, (bd[1]  | bd[10] | bd[19] | bd[28] | bd[37] | bd[46] | bd[55] | bd[64] | bd[73])),
xor(511, (bd[2]  | bd[11] | bd[20] | bd[29] | bd[38] | bd[47] | bd[56] | bd[65] | bd[74])),
xor(511, (bd[3]  | bd[12] | bd[21] | bd[30] | bd[39] | bd[48] | bd[57] | bd[66] | bd[75])),
xor(511, (bd[4]  | bd[13] | bd[22] | bd[31] | bd[40] | bd[49] | bd[58] | bd[67] | bd[76])),
xor(511, (bd[5]  | bd[14] | bd[23] | bd[32] | bd[41] | bd[50] | bd[59] | bd[68] | bd[77])),
xor(511, (bd[6]  | bd[15] | bd[24] | bd[33] | bd[42] | bd[51] | bd[60] | bd[69] | bd[78])),
xor(511, (bd[7]  | bd[16] | bd[25] | bd[34] | bd[43] | bd[52] | bd[61] | bd[70] | bd[79])),
xor(511, (bd[8]  | bd[17] | bd[26] | bd[35] | bd[44] | bd[53] | bd[62] | bd[71] | bd[80])),
xor(511, (bd[9]  | bd[18] | bd[27] | bd[36] | bd[45] | bd[54] | bd[63] | bd[72] | bd[81]))
			]::int[] AS col_can,

ARRAY[
xor(511, (bd[1]  | bd[2]  | bd[3]  | bd[10] | bd[11] | bd[12] | bd[19] | bd[20] | bd[21])),
xor(511, (bd[4]  | bd[5]  | bd[6]  | bd[13] | bd[14] | bd[15] | bd[22] | bd[23] | bd[24])),
xor(511, (bd[7]  | bd[8]  | bd[9]  | bd[16] | bd[17] | bd[18] | bd[25] | bd[26] | bd[27])),
xor(511, (bd[28] | bd[29] | bd[30] | bd[37] | bd[38] | bd[39] | bd[46] | bd[47] | bd[48])),
xor(511, (bd[31] | bd[32] | bd[33] | bd[40] | bd[41] | bd[42] | bd[49] | bd[50] | bd[51])),
xor(511, (bd[34] | bd[35] | bd[36] | bd[43] | bd[44] | bd[45] | bd[52] | bd[53] | bd[54])),
xor(511, (bd[55] | bd[56] | bd[57] | bd[64] | bd[65] | bd[66] | bd[73] | bd[74] | bd[75])),
xor(511, (bd[58] | bd[59] | bd[60] | bd[67] | bd[68] | bd[69] | bd[76] | bd[77] | bd[78])),
xor(511, (bd[61] | bd[62] | bd[63] | bd[70] | bd[71] | bd[72] | bd[79] | bd[80] | bd[81]))
			]::int[] AS box_can,

			todo
FROM board_t
	) AS rcb_t
)
--from init_t;
,

infer_t AS (
SELECT id, row_can, col_can, box_can, todo, done, TRUE AS expand
FROM init_t

UNION ALL

SELECT
		id,
CASE
WHEN expand_ IS NOT NULL
THEN row_can[:r - 1] ||[ xor(row_can[r] , candidates)] || row_can[r + 1:]
ELSE row_can
END,
CASE
WHEN expand_ IS NOT NULL
THEN col_can[:c - 1] ||[ xor(col_can[c] , candidates)] || col_can[c + 1:]
ELSE col_can
END,
CASE
WHEN expand_ IS NOT NULL
THEN box_can[:b - 1] ||[ xor(box_can[b] , candidates)] || box_can[b + 1:]
ELSE box_can
END,
CASE
WHEN expand_ IS NOT NULL
THEN todo[:i - 1] || todo[i + 1:]
ELSE todo
END,
CASE
WHEN expand_ IS NOT NULL
--THEN set_byte(done, (r << 3) + r + c - 10, bit_count((candidates - 1))::int + 49)
THEN substr(done,1, (r << 3) + r + c - 10)|| chr( bit_count((candidates - 1))::int + 49)||substr(done, (r << 3) + r + c - 8)
ELSE done
END,
		expand_
FROM infer_t
LEFT JOIN LATERAL (
SELECT i, r, c, b, candidates, TRUE AS expand_
FROM (select generate_subscripts(todo, 1) i)t(i)
CROSS JOIN LATERAL (
SELECT todo[i] >> 8 AS r, (todo[i] >> 4) & 15 AS c, todo[i] & 15 AS b
		) AS infer_rcb_t
CROSS JOIN LATERAL (
SELECT row_can[r] & col_can[c] & box_can[b] AS candidates
		) AS infer_can_t
WHERE bit_count(candidates) = 1
		LIMIT 1
	) AS infer_next_t ON TRUE
WHERE expand IS NOT NULL
),
infer_rst_t AS (
SELECT id, row_can, col_can, box_can, todo, done
FROM infer_t
WHERE expand IS NULL
)
--SELECT count(*) FROM infer_rst_t WHERE length(todo) = 0 ;

,

search_t AS (
SELECT
		id,
0 AS deep,
FALSE AS back,
0 AS back_can,
		row_can,
		col_can,
		box_can,
		todo,
		done,
ARRAY[]::int[][] stack,
CASE WHEN length(todo) = 0 THEN TRUE ELSE NULL::boolean END AS status
FROM infer_rst_t

UNION ALL

SELECT
		id,
		deep + 1,
CASE WHEN candidate != 0 THEN FALSE ELSE TRUE END,
		s_cand,

CASE
WHEN candidate != 0
THEN row_can[:r - 1] || [xor(row_can[r] , candidate)] || row_can[r + 1:]
ELSE
				row_can[:s_r - 1] ||[xor(row_can[s_r] , (s_cand & -s_cand))] ||row_can[s_r + 1:]
END,

CASE
WHEN candidate != 0
THEN col_can[:c - 1] || [xor(col_can[c] , candidate)] || col_can[c + 1:]
ELSE
				col_can[:s_c - 1] ||[xor(col_can[s_c] , (s_cand & -s_cand))] ||col_can[s_c + 1:]
END,

CASE
WHEN candidate != 0
THEN box_can[:b - 1] || [xor(box_can[b] , candidate)] || box_can[b + 1:]
ELSE
				box_can[:s_b - 1] ||[xor(box_can[s_b] , (s_cand & -s_cand))] ||box_can[s_b + 1:]
END,

CASE
WHEN candidate != 0
THEN todo[:i - 1] || todo[i + 1:]
ELSE [stack[sp][1]] || todo
END,

CASE
WHEN candidate != 0
--THEN set_byte(done, (r << 3) + r + c - 10, bit_count((candidate - 1))::int + 49)
THEN substr(done,1, (r << 3) + r + c - 10)|| chr( bit_count((candidate - 1))::int + 49)||substr(done, (r << 3) + r + c - 8)
ELSE done
END,

CASE
WHEN candidate != 0
THEN stack || ARRAY[ARRAY[(r << 8) | (c << 4) | b, candidates]]
ELSE stack[:sp - 1]
END,

CASE
WHEN candidate != 0
THEN CASE WHEN length(todo) <= 1 THEN TRUE ELSE NULL END
WHEN length(stack) = 0 THEN FALSE
-- 示例题库中最大检索深度只用459就够了,这里设定超65000才放弃
-- 应该完全足够解出所有题目了,正确率比速度更重要,慢就慢点
WHEN deep >= 6000 THEN FALSE
ELSE NULL
END

FROM search_t
LEFT  JOIN LATERAL (
		(
-- 先找1比sort limit 1更快
SELECT i AS i_, r_, c_, b_, candidates_
FROM (select generate_subscripts(todo, 1) i)t(i)
CROSS JOIN LATERAL (
SELECT todo[i] >> 8 AS r_, (todo[i] >> 4) & 15 AS c_, todo[i] & 15 AS b_
			) AS search1_rcb_t
CROSS JOIN LATERAL (
SELECT row_can[r_] & col_can[c_] & box_can[b_] AS candidates_
			) AS search1_can_t
WHERE bit_count(candidates_) = 1
			LIMIT 1
		)
UNION ALL
		(
WITH mrv_t AS (
SELECT i AS i_, r_, c_, b_, candidates_, bit_count(candidates_) AS cnt
FROM (select generate_subscripts(todo, 1) i)t(i)
CROSS JOIN LATERAL (
SELECT todo[i] >> 8 AS r_, (todo[i] >> 4) & 15 AS c_, todo[i] & 15 AS b_
				) AS search2_rcb_t
CROSS JOIN LATERAL (
SELECT row_can[r_] & col_can[c_] & box_can[b_] AS candidates_
				) AS search2_can_t
			),
-- 找min值比sort limit 1更快
			mrv_min_t AS (
SELECT min(cnt) AS cnt FROM mrv_t
			)
SELECT i_, r_, c_, b_, candidates_
FROM mrv_t
JOIN mrv_min_t
ON mrv_t.cnt = mrv_min_t.cnt
where back = FALSE			LIMIT 1
		)
		LIMIT 1
	) AS forward_t on true --ON back = FALSE
LEFT JOIN LATERAL (
SELECT
1 AS i_,
todo[1] >> 8 AS r_,
(todo[1] >> 4) & 15 AS c_,
todo[1] & 15 AS b_,
back_can & (back_can - 1) AS candidates_
where back = TRUE 
	) AS backward_t on true
CROSS JOIN LATERAL (
SELECT
COALESCE(backward_t.i_, forward_t.i_) AS i,
COALESCE(backward_t.r_, forward_t.r_) AS r,
COALESCE(backward_t.c_, forward_t.c_) AS c,
COALESCE(backward_t.b_, forward_t.b_) AS b,
COALESCE(backward_t.candidates_, forward_t.candidates_) AS candidates,
			(COALESCE(backward_t.candidates_, forward_t.candidates_) &
-COALESCE(backward_t.candidates_, forward_t.candidates_)) AS candidate,
-- 这俩可能为NULL,为NULL时会判定为不可解,所以即使生成了一些NULL中间数据,会丢弃掉。我已确认不影响程序正确性
			array_length(stack, 1) AS sp,
			stack[array_length(stack, 1)][2] AS s_cand
	) AS final_t
LEFT  JOIN LATERAL (
SELECT
stack[sp][1] >> 8 AS s_r,
(stack[sp][1] >> 4) & 15 AS s_c,
stack[sp][1] & 15 s_b
where candidate = 0 
	) AS extra_t on true --ON candidate = 0 
WHERE status IS NULL
)
--select * from search_t ;
,
search_rst_t AS (
SELECT id, done FROM search_t WHERE status = TRUE
)

SELECT
	t.id AS id,
	puzzle,
	
		substr(done, 1,  9) || E'\n' ||
		substr(done, 10, 9) || E'\n' ||
		substr(done, 19, 9) || E'\n' ||
		substr(done, 28, 9) || E'\n' ||
		substr(done, 37, 9) || E'\n' ||
		substr(done, 46, 9) || E'\n' ||
		substr(done, 55, 9) || E'\n' ||
		substr(done, 64, 9) || E'\n' ||
		substr(done, 73, 9)
	 AS result
FROM sudoku9_9 t
LEFT JOIN search_rst_t USING(id)
;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions