数独优化求解C库tdoku-lib的使用

tdoku-lib是基于优化求解器tdoku改造的动态库和静态库,它的存储库地址 https://github.com/hackerzhuli/tdoku-lib

1.拉取源代码

复制代码
root@DESKTOP-59T6U68:/mnt/c/d# git clone https://github.com/hackerzhuli/tdoku-lib.git

Cloning into 'tdoku-lib'...
remote: Enumerating objects: 1230, done.
remote: Counting objects: 100% (339/339), done.
remote: Compressing objects: 100% (77/77), done.
remote: Total 1230 (delta 288), reused 284 (delta 255), pack-reused 891 (from 1)
Receiving objects: 100% (1230/1230), 72.96 MiB | 3.20 MiB/s, done.
Resolving deltas: 100% (885/885), done.
Updating files: 100% (27/27), done.

2.编译

复制代码
root@DESKTOP-59T6U68:/mnt/c/d# cd tdoku-lib
root@DESKTOP-59T6U68:/mnt/c/d/tdoku-lib# docker start gcc
gcc
root@DESKTOP-59T6U68:/mnt/c/d/tdoku-lib# docker exec -it gcc bash
root@6ae32a5ffcde:/# cd /par/tdoku-lib/
root@6ae32a5ffcde:/par/tdoku-lib# ./BUILD.sh
-- The C compiler identification is GNU 14.2.0
-- The CXX compiler identification is GNU 14.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/local/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /par/tdoku-lib/build
[  6%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_simd.cc.o
[ 12%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_basic.cc.o
[ 18%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_scc.cc.o
/par/tdoku-lib/src/solver_dpll_triad_scc.cc:20:11: error: 'uint16_t' does not name a type
   20 | constexpr uint16_t kNumLiterals = kNumBoxes * kNumPosClausesPerBox * kNumValues * 2;
      |           ^~~~~~~~
/par/tdoku-lib/src/solver_dpll_triad_scc.cc:11:1: note: 'uint16_t' is defined in header '<cstdint>'; this is probably fixable by adding '#include <cstdint>'
   10 | #include <vector>
  +++ |+#include <cstdint>
   11 |

...
/par/tdoku-lib/src/solver_dpll_triad_scc.cc:526:38: error: 'Literal' was not declared in this scope
  526 |                 if (result_.asserted[Literal(box, elm, val)]) {
      |                                      ^~~~~~~
/par/tdoku-lib/src/solver_dpll_triad_scc.cc: At global scope:
/par/tdoku-lib/src/solver_dpll_triad_scc.cc:540:65: error: 'uint32_t' has not been declared
  540 | size_t TdokuSolverDpllTriadScc(const char *input, size_t limit, uint32_t configuration,
      |                                                                 ^~~~~~~~
make[2]: *** [CMakeFiles/tdoku_object.dir/build.make:104: CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_scc.cc.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:93: CMakeFiles/tdoku_object.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

编译出错。

按照编译的提示,在solver_dpll_triad_scc.cc的开头加上#include <cstdint>,重新编译通过

复制代码
root@6ae32a5ffcde:/par/tdoku-lib# ./BUILD.sh
...
[  6%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_simd.cc.o
[ 12%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_basic.cc.o
[ 18%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_scc.cc.o
[ 25%] Building CXX object CMakeFiles/tdoku_object.dir/src/util.cc.o
[ 31%] Building CXX object CMakeFiles/tdoku_object.dir/src/generate.cc.o
[ 37%] Building CXX object CMakeFiles/tdoku_object.dir/src/solve.cc.o
make[2]: warning:  Clock skew detected.  Your build may be incomplete.
[ 37%] Built target tdoku_object
[ 43%] Linking CXX static library libtdoku_static.a
[ 43%] Built target tdoku_static
[ 50%] Linking CXX shared library libtdoku_shared.so
[ 50%] Built target tdoku_shared
[ 56%] Building CXX object CMakeFiles/run_tests.dir/test/run_tests.cc.o
[ 62%] Building CXX object CMakeFiles/run_tests.dir/src/util.cc.o
[ 68%] Building CXX object CMakeFiles/run_tests.dir/src/solver_dpll_triad_simd.cc.o
[ 75%] Linking CXX executable run_tests
[ 75%] Built target run_tests
[ 81%] Building CXX object CMakeFiles/grid_lib.dir/src/grid_lib.cc.o
[ 87%] Linking CXX static library libgrid_lib.a
[ 87%] Built target grid_lib
[ 93%] Building CXX object CMakeFiles/grid_tools.dir/src/grid_tools.cc.o
[100%] Linking CXX executable grid_tools
[100%] Built target grid_tools
make[1]: warning:  Clock skew detected.  Your build may be incomplete.
make: warning:  Clock skew detected.  Your build may be incomplete.
root@6ae32a5ffcde:/par/tdoku-lib#

3.执行

执行编译出来的run_tests文件,显示PASS: tdoku

复制代码
root@6ae32a5ffcde:/par/tdoku-lib/build# ./run_tests
Error opening test/test_puzzles
root@6ae32a5ffcde:/par/tdoku-lib/build# cd ..
root@6ae32a5ffcde:/par/tdoku-lib# build/run_tests
PASS: tdoku

再编译示例文件,

c 复制代码
#include "../include/tdoku.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char **argv) {
    size_t limit = argc > 1 ? atoll(argv[1]) : 10000;

    char *puzzle = NULL;
    char solution[81];
    size_t size, guesses;

    while (getline(&puzzle, &size, stdin) != -1) {
        if (strlen(puzzle) < 81 || puzzle[0] == '#') continue;
        solution[0] = '\0';
        size_t count = SolveSudoku(puzzle, limit, 0, solution, &guesses);
        if (limit > 1 && count == 1) {
            SolveSudoku(puzzle, 1, 0, solution, &guesses);
        }
        printf("%.81s:%ld:%.81s\n", puzzle, count, solution);
    }
}

slove求解文件中的数独题目,空格用"."表示。结果输出到控制台,格式是题目:解序号:解

复制代码
root@6ae32a5ffcde:/par/tdoku-lib# gcc example/solve.c build/libtdoku_static.a -O3 -o solve -lstdc++ -lm
root@6ae32a5ffcde:/par/tdoku-lib# unzip data.zip
root@6ae32a5ffcde:/par/tdoku-lib# ./solve < data/puzzles0_kaggle
..2..76416712.....5..3..28.46......9.35.18.6...7.93..4.9.5.61...5..7...3..48...2.:1:382957641671284935549361287468725319935418762127693854293546178856172493714839526
...6.2..9.3..1.6..1.238.5.4.15...96....94.....27..38.58.42..3.7.....8.....6.7125.:1:748652139539714682162389574415827963683945721927163845854296317271538496396471258
^C

示例还有python程序

python 复制代码
import sys
from ctypes import *

class Tdoku:
    def __init__(self):
        self.__tdoku = CDLL("build/libtdoku_shared.so")

        self.__solve = self.__tdoku.TdokuSolverDpllTriadSimd
        self.__solve.restype = c_ulonglong

        self.__constrain = self.__tdoku.TdokuConstrain
        self.__constrain.restype = c_bool

        self.__minimize = self.__tdoku.TdokuMinimize
        self.__minimize.restype = c_bool

    def Solve(self, puzzle):
        if type(puzzle) is str:
            puzzle = str.encode(puzzle)
        limit = c_ulonglong(1)
        config = c_ulong(0)
        solution = create_string_buffer(81)
        guesses = c_ulonglong(0)
        count = self.__solve(c_char_p(puzzle), limit, config, solution, pointer(guesses))
        if count:
            return count, solution.value.decode(), guesses.value
        else:
            return 0, "", guesses

    def Count(self, puzzle, limit=2):
        if type(puzzle) is str:
            puzzle = str.encode(puzzle)
        limit = c_ulonglong(limit)
        config = c_ulong(0)
        solution = create_string_buffer(81)
        guesses = c_ulonglong(0)
        count = self.__solve(c_char_p(puzzle), limit, config, solution, pointer(guesses))
        return count

    def Constrain(self, partial_puzzle):
        if type(partial_puzzle) is str:
            buffer = create_string_buffer(str.encode(partial_puzzle))
        else:
            buffer = create_string_buffer(partial_puzzle)
        pencilmark = c_bool(False)
        self.__constrain(pencilmark, buffer)
        return buffer.value

    def Minimize(self, non_minimal_puzzle):
        if type(non_minimal_puzzle) is str:
            buffer = create_string_buffer(str.encode(non_minimal_puzzle))
        else:
            buffer = create_string_buffer(non_minimal_puzzle)
        pencilmark = c_bool(False)
        monotonic = c_bool(False)
        self.__minimize(pencilmark, monotonic, buffer)
        return buffer.value


if __name__ == '__main__':
    tdoku = Tdoku()

    if len(sys.argv) > 1:
        filename = sys.argv[1]
    else:
        filename = 'data/puzzles2_17_clue'

    with open(filename, 'r') as f:
        for puzzle in f.readlines():
            if len(puzzle) >= 81 and not puzzle.startswith('#'):
                count, solution, guesses = tdoku.Solve(puzzle)
                print("%.81s:%lu:%.81s:%lu" % (puzzle, count, solution, guesses))

这次还多出来一列猜测数

复制代码
root@6ae32a5ffcde:/par/tdoku-lib# python3 example/solve.py data/puzzles0_kaggle|more
.5..83.17...1..4..3.4..56.8....3...9.9.8245....6....7...9....5...729..861.36.72.4:1:652483917978162435314975628825736149791824563436519872269348751547291386183657294:0
2.6.3......1.65.7..471.8.5.5......29..8.194.6...42...1....428..6.93....5.7.....13:1:256734198891265374347198652514683729728519436963427581135942867689371245472856913:0

Traceback (most recent call last):
  File "/par/tdoku-lib/example/solve.py", line 73, in <module>
    print("%.81s:%lu:%.81s:%lu" % (puzzle, count, solution, guesses))
BrokenPipeError: [Errno 32] Broken pipe
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
BrokenPipeError: [Errno 32] Broken pip

用49150道17个未知数的题目测试性能,并与dlx程序比较

复制代码
root@6ae32a5ffcde:/par/tdoku-lib# time ./solve < data/puzzles2_17_clue >17result.txt

real    0m0.622s
user    0m0.229s
sys     0m0.017s

root@6ae32a5ffcde:/par/1230# time ./dlxline <sudoku17.txt >sudoku17outdlx.txt

real    0m1.568s
user    0m1.122s
sys     0m0.073s

tdoku用时只有dlx的40%。采用不同的文件是因为两个程序要求的空格符不同,一个是.,另一个是0。

相关推荐
2501_918126914 分钟前
学习所有用c语言定义stm32的语句
c语言·stm32·嵌入式硬件·学习·个人开发
@大迁世界5 分钟前
6 款轻量级 CLI 工具,取代了我臃肿的开发软件
开发语言·lua
handler018 分钟前
算法:Trie树(字典树)
c语言·数据结构·c++·笔记·算法·深度优先
ZPC82109 分钟前
PPO (Proximal Policy Optimization) 算法模块详细拆解
人工智能·pytorch·算法·机器人
阿Y加油吧12 分钟前
力扣打卡day06——滑动窗口最大值、最小覆盖子串
数据结构·算法·leetcode
沉鱼.4413 分钟前
日期题目集
数据结构·算法
MegaDataFlowers14 分钟前
依赖注入(DI)
java·开发语言
csbysj202016 分钟前
Foundation 输入框尺寸指南
开发语言
wertyuytrewm17 分钟前
用Python实现自动化的Web测试(Selenium)
jvm·数据库·python
码云数智-园园17 分钟前
Tailwind CSS vs. 传统CSS/Sass:2026年前端样式开发的深度博弈
开发语言