Java 为什么翻译的数独解算器比原版慢?

Java 为什么翻译的数独解算器比原版慢?,java,python,numpy,sudoku,Java,Python,Numpy,Sudoku,我将Java数独解算器转录成python。一切正常,但是解决问题需要2分钟,而在Java中,同样的难题只需要几秒钟。此外,所需的迭代次数也完全相同。我错过什么了吗 import numpy as np def solve_recursive(puzzle, pos): if(pos == 81): print puzzle return True if(puzzle[pos] != 0): i

我将Java数独解算器转录成python。一切正常,但是解决问题需要2分钟,而在Java中,同样的难题只需要几秒钟。此外,所需的迭代次数也完全相同。我错过什么了吗

import numpy as np
def solve_recursive(puzzle, pos):
        if(pos == 81):
            print puzzle
            return True
        if(puzzle[pos] != 0):
            if (not solve_recursive(puzzle, pos+1)):
                return False
            else:
                return True

        row = np.copy(puzzle[pos//9*9:pos//9*9+9])
        col = np.copy(puzzle[pos%9::9])
        short = (pos%9)//3*3 + pos//27*27
        square = np.concatenate((puzzle[short:short+3],puzzle[short+9:short+12],puzzle[short+18:short+21]))

        for i in range(1,10):
            puzzle[pos] = i
            if(i not in row and i not in col and i not in square and solve_recursive(puzzle, pos+1)):
                return True

        puzzle[pos] = 0
        return False
puzzle = np.array([[0,0,0,0,0,0,0,8,3],
              [0,2,0,1,0,0,0,0,0],
              [0,0,0,0,0,0,0,4,0],
              [0,0,0,6,1,0,2,0,0],
              [8,0,0,0,0,0,9,0,0],
              [0,0,4,0,0,0,0,0,0],
              [0,6,0,3,0,0,5,0,0],
              [1,0,0,0,0,0,0,7,0],
              [0,0,0,0,0,8,0,0,0]])
solve_recursive(puzzle.ravel(), 0)
编辑:

根据@hpaulj的建议,我重新编写了代码,以使用numpy的2D阵列:

import numpy as np
def solve_recursive(puzzle, pos):
        if pos == (0,9):
            print puzzle
            raise Exception("Solution")
        if(puzzle[pos] != 0):
            if(pos[0] == 8):
                solve_recursive(puzzle, (0,pos[1]+1))
                return
            elif pos[0] < 8:
                solve_recursive(puzzle, (pos[0]+1, pos[1]))
                return

        for i in range(1,10):
            if(i not in puzzle[pos[0]] and i not in puzzle[:,pos[1]] and i not in puzzle[pos[0]//3*3:pos[0]//3*3+3,pos[1]//3*3:pos[1]//3*3+3]):
                puzzle[pos] = i
                if(pos[0] == 8):
                    solve_recursive(puzzle, (0,pos[1]+1))
                elif pos[0] < 8:
                    solve_recursive(puzzle, (pos[0]+1, pos[1]))
        puzzle[pos] = 0
puzzle = np.array([[0,0,0,0,0,0,0,8,3],
          [0,2,0,1,0,0,0,0,0],
          [0,0,0,0,0,0,0,4,0],
          [0,0,0,6,1,0,2,0,0],
          [8,0,0,0,0,0,9,0,0],
          [0,0,4,0,0,0,0,0,0],
          [0,6,0,3,0,0,5,0,0],
          [1,0,0,0,0,0,0,7,0],
          [0,0,0,0,0,8,0,0,0]])
solve_recursive(puzzle, (0,0))
将numpy导入为np
def solve_recursive(谜题、位置):
如果位置==(0,9):
印刷拼图
引发异常(“解决方案”)
如果(拼图[pos]!=0):
如果(位置[0]==8):
求解递归(谜题,(0,位置[1]+1))
回来
elif位置[0]<8:
求解递归(谜题,(位置[0]+1,位置[1]))
回来
对于范围(1,10)内的i:
如果(我不在拼图[pos[0]]中,我不在拼图[:,pos[1]]中,我不在拼图[pos[0]//3*3:pos[0]//3*3+3,pos[1]//3*3:pos[1]//3*3+3]):
拼图[pos]=i
如果(位置[0]==8):
求解递归(谜题,(0,位置[1]+1))
elif位置[0]<8:
求解递归(谜题,(位置[0]+1,位置[1]))
拼图[pos]=0
拼图=np.数组([[0,0,0,0,0,0,0,8,3],
[0,2,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,4,0],
[0,0,0,6,1,0,2,0,0],
[8,0,0,0,0,0,9,0,0],
[0,0,4,0,0,0,0,0,0],
[0,6,0,3,0,0,5,0,0],
[1,0,0,0,0,0,0,7,0],
[0,0,0,0,0,8,0,0,0]])
求解递归(谜题,(0,0))

忽略在递归调用的底部抛出异常是相当不雅观的,这比我原来的解决方案快得多。使用像链接的Norvig解算器这样的字典是合理的选择吗

我修改了您的函数以打印
pos
,并保持调用次数的连续计数。我很早就停止了

pos==46时停止会导致1190次调用,只有轻微的可见延迟。但对于47人来说,这个数字是416621,跑一分钟或更长时间

假设它在做某种递归搜索,这个问题的难度在46到47之间有一个量子跳跃

是的,Python作为解释语言将比Java运行得慢。可能的解决方案包括找出递归调用中出现这种跳跃的原因。或者提高每次通话的速度

您设置了9x9 numpy阵列,但随后立即将其展开。然后,函数本身将电路板视为81个值的列表。这意味着选择行、列和子矩阵要比阵列仍然是二维的情况复杂得多。实际上,数组只是一个列表

我可以想象两种加速通话的方法。一种是重新编码以使用列表板。对于小型数组和迭代操作,列表的开销比数组小,因此通常更快。另一种方法是对其进行编码,以真正利用阵列的2d特性
numpy
解决方案只有在允许
numpy
使用编译后的代码执行大多数操作时才是好的。在数组上的迭代很慢

==================

更改您的函数,使其与平面列表而不是raveled数组一起工作,运行速度会快得多。如果最大pos为47,则运行时间为15秒,而原始版本为1m 15秒(板数和迭代次数相同)

我正在清理2d numpy阵列版本,但并没有使其更快

纯列表版本也是在
pypy
上运行得更快的一个很好的候选版本

用于二维数组的代码的一部分

    r,c = np.unravel_index(pos, (9,9))            
    if(puzzle[r,c] != 0):
        return solve_numpy(puzzle, pos+1)
    row = puzzle[r,:].copy()
    col = puzzle[:,c].copy()
    r1, c1 = 3*(r//3), 3*(c//3)
    square = puzzle[r1:r1+3, c1:c1+3].flatten()
    for i in range(1,10):
        puzzle[r,c] = i
        if(i not in row and i not in col and i not in square):
            if solve_numpy(puzzle, pos+1):
                return True
    puzzle[r,c] = 0
索引更清晰,但速度没有提高。除了更简单的索引外,它没有充分利用整个数组操作

列表
版本与原始版本没有太大区别,但速度更快:

    row = puzzle[pos//9*9:pos//9*9+9]
    col = puzzle[pos%9::9]
    short = (pos%9)//3*3 + pos//27*27
    square = puzzle[short:short+3] + \
             puzzle[short+9:short+12] + \
             puzzle[short+18:short+21]
讨论数独解决方案的方法,由人工智能专家用pythoN编写


使用此
Norvig
解算器,网格解决方案需要0.01秒。信息主要存储在词典中。你的案例很简单,可以用他的两个基本任务策略来解决。不搜索解决方案的速度非常快。

问题是缺少语法有效的python代码和所有Java代码。顺便说一句:
如果没有条件:返回False;否则返回真值
与返回条件
相同。(苦苦挣扎于一行py语法;希望你能理解)。请提供一个简单的例子,并记录在案:根据你使用的python解释器,python可能比Java-FWIW慢,我可以在0.115s(2GHz奔腾4)内用python解决数独问题,但我的算法比你的算法效率高一点。