Advertisement
Guest User

DLX Algo

a guest
Jan 9th, 2016
295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.87 KB | None | 0 0
  1. import numpy as np
  2. import time as tm
  3. import os
  4.  
  5. class Node(object):
  6.  
  7.     def __init__(self, left, right, top, bot, column_header, rowID):
  8.         self.left = left
  9.         self.right = right
  10.         self.top = top
  11.         self.bot = bot
  12.         self.header = column_header
  13.         self.rowID = rowID
  14.    
  15.     def __repr__(self):
  16.         return 'node in column'+str(self.header)+'and row'+str(self.rowID)
  17.    
  18. class ColumnHeader(object):
  19.  
  20.     def __init__(self, size, name, left, right, top, bot):
  21.         self.name = name
  22.         self.size = size
  23.         self.left = left
  24.         self.right = right
  25.         self.top = top
  26.         self.bot = bot
  27.        
  28.     def __repr__(self):
  29.         return 'CH ' + str(self.name) + '|size :' + self.size
  30.  
  31.        
  32. class SparseMatrix(object):
  33.    
  34.     def __init__(self,matrix):
  35.         self.m=np.copy(matrix)
  36.         h,l=self.m.shape
  37.         self.sm = np.vstack((np.empty((1,l), ColumnHeader),np.empty(self.m.shape, Node)))
  38.         self.header=ColumnHeader(l,'header',None,None,None,None)
  39.        
  40.         self.createColumns()
  41.         self.fillColumns()
  42.         self.linkNodes()
  43.        
  44.     def createColumns(self):
  45.         l=self.m.shape[1]
  46.        
  47.         self.sm[0,0]=ColumnHeader(0,'0',self.header,None,None,None)
  48.         self.header.right=self.sm[0,0]
  49.        
  50.         for i in range(1,l):
  51.             self.sm[0,i]=ColumnHeader(0,str(i),self.sm[0,i-1],None,None,None)
  52.             self.sm[0,i-1].right=self.sm[0,i]
  53.            
  54.         self.header.left=self.sm[0,l-1]
  55.         self.sm[0,l-1].right=self.header
  56.        
  57.        
  58.     def fillColumns(self):
  59.         h,l=self.sm.shape
  60.  
  61.         for j in range(0,l):
  62.             column_size=0
  63.             for i in range(1,h):
  64.                 if self.m[i-1,j]==1:
  65.                     column_size+=1
  66.                     self.sm[i,j]=Node(None,None,None,None,self.sm[0,j],i-1)
  67.             self.sm[0,j].size=column_size
  68.            
  69.        
  70.     def linkNodes(self):
  71.         h,l=self.sm.shape
  72.        
  73.         for j in range(0,l):
  74.             current_node=self.sm[0,j]
  75.             for i in range(1,h):
  76.                 if self.sm[i,j]!=None:
  77.                     current_node.bot=self.sm[i,j]
  78.                     self.sm[i,j].top=current_node
  79.                     current_node=self.sm[i,j]
  80.             current_node.bot=self.sm[0,j]
  81.             self.sm[0,j].top=current_node
  82.            
  83.         for i in range(1,h):
  84.             k=0
  85.             while self.sm[i,k] == None: k+=1
  86.             current_node=self.sm[i,k]
  87.             for j in range(k+1,l):
  88.                 if self.sm[i,j] != None:
  89.                     current_node.right=self.sm[i,j]
  90.                     self.sm[i,j].left=current_node
  91.                     current_node=self.sm[i,j]
  92.                    
  93.             current_node.right=self.sm[i,k]
  94.             self.sm[i,k].left=current_node
  95.  
  96.     def coverColumn(self,column_header):
  97.         column_header.left.right=column_header.right
  98.         column_header.right.left=column_header.left
  99.        
  100.         row=column_header.bot
  101.         while row!=column_header:
  102.             node=row.right
  103.             while node!=row:
  104.                 node.top.bot=node.bot
  105.                 node.bot.top=node.top
  106.                 node.header.size-=1
  107.                 node=node.right
  108.             row=row.bot
  109.  
  110.  
  111.     def uncoverColumn(self,column_header):
  112.         row=column_header.top
  113.         while row!=column_header:
  114.             node=row.left
  115.             while node!=row:
  116.                 node.top.bot=node
  117.                 node.bot.top=node
  118.                 node.header.size+=1
  119.                 node=node.left
  120.             row=row.top
  121.            
  122.         column_header.left.right=column_header
  123.         column_header.right.left=column_header
  124.  
  125.     def getSmallerColumn(self):
  126.         c=self.header.right
  127.         choice = c
  128.         lowestsize = c.size
  129.         while c.right != self.header:
  130.             c=c.right
  131.             if c.size< lowestsize:
  132.                 lowestsize = c.size
  133.                 choice = c
  134.         return choice
  135.    
  136.     def __repr__(self):
  137.         repr=""
  138.         cur=self.header.right.bot
  139.         while cur != self.header.right:
  140.             repr += "row " + str(cur.rowID) + " \n"
  141.             node = cur
  142.             repr += "   -columns " + str(node.header.name) + "\n"
  143.             node=node.right
  144.             while node != cur:
  145.                 repr += "   -columns " + str(node.header.name) + "\n"
  146.                 node = node.right
  147.             cur=cur.bot
  148.        
  149.         return repr
  150.  
  151.  
  152. def XAlgorithm(sparse_matrix):
  153.     solution = [None] * (sparse_matrix.header.size)
  154.     sp=sparse_matrix
  155.    
  156.     def XAlgorithmRec(k):
  157.  
  158.         if sp.header.right==sp.header : return solution
  159.        
  160.         C=sp.getSmallerColumn()
  161.         sp.coverColumn(C)
  162.        
  163.         row=C.bot
  164.         while row!=C:
  165.             solution[k]=row.rowID
  166.            
  167.             node=row.right
  168.             while node!=row:
  169.                 sp.coverColumn(node.header)
  170.                 node=node.right
  171.                
  172.             keepSearching = XAlgorithmRec(k+1)
  173.             if keepSearching :
  174.                 return True
  175.            
  176.             #Backing part
  177.             node = row.left
  178.             while node != row:
  179.                 sp.uncoverColumn(node.header)
  180.                 node=node.left
  181.                
  182.             row=row.bot
  183.            
  184.         sp.uncoverColumn(C)
  185.         return False
  186.    
  187.     return XAlgorithmRec(0),solution
  188.    
  189.  
  190. class Sudoku(object):
  191.    
  192.     def __init__(self,str,size=9): #str est une chaine de caractères, avec des 0 dans les cases vides/ size est la largeur du sudoku (9 std)
  193.         self.matrix = []
  194.         self.size=size
  195.         assert (len(str)==size**2),"The string is not well sized"
  196.        
  197.         grid=self.list2dFromstr(size,str)
  198.         for i in range(size):
  199.             for j in range(size):
  200.                 v=grid[i][j]
  201.                 if v in range(1,size+1):
  202.                     self.matrix.append(self.dlxRow(i,j,v)) #row of the matrix
  203.                 elif v==0:
  204.                     for k in range(1,size+1):
  205.                         self.matrix.append(self.dlxRow(i,j,k))
  206.        
  207.  
  208.         self.sp=SparseMatrix(self.matrix)
  209.  
  210.  
  211.     def solve(self):
  212.         self.solution = XAlgorithm(self.sp)
  213.         if not self.solution[0] :
  214.             return False
  215.         else:
  216.             gridsolved=[ [None for _ in range(self.size)] for __ in range(self.size)]
  217.             for x in self.solution[1]: #x is a row index part of the solution
  218.                 if x!=None:
  219.                     row,col,val=self.dlx_row_to_rcv(self.matrix[x])
  220.                     gridsolved[row][col]=val
  221.             self.solved=np.array(gridsolved)
  222.             return True
  223.      
  224.     def dlxRow(self,row,col,val):
  225.         val-=1
  226.         return self.encode(row,col)+self.encode(row,val)+self.encode(col,val)+self.encode(self.row_col_to_box(row,col),val)
  227.        
  228.     def list2dFromstr(self,size,str):
  229.         grid=[ [None for _ in range(size)] for __ in range(size)]
  230.         for i in range(size**2):
  231.             grid[i//size][i%size]=int(str[i])
  232.         return grid
  233.        
  234.    
  235.     def row_col_to_box(self,row, col):
  236.         #Return the index for the box that the given (r, c) sudoku coordinates fits into. Boxes go like this:
  237.         #0 1 2    0 1
  238.         #3 4 5    2 3
  239.         #6 7 8
  240.         d=int(np.sqrt(self.size))
  241.         return (row - (row % d)) + (col // d)
  242.  
  243.     def encode(self,major, minor):
  244.     #Build a list of 81 values, with a 1 in the spot corresponding to the value of the major attribute and minor attribute.
  245.         out = [0] * self.size**2
  246.         out [major*self.size + minor] = 1
  247.         return out
  248.  
  249.     def dlx_row_to_rcv(self,dlxrow):
  250.     #Pull (row,col,val) out from an encoded DLX list.
  251.         d=self.size**2
  252.         rowcol = dlxrow[0:d]
  253.         rownum = dlxrow[d: 2*d]
  254.         row,col = self.decode(rowcol)
  255.         ignore,num = self.decode(rownum)
  256.         return (row,col,num + 1)
  257.  
  258.     def decode(self,lst):
  259.     #Take a list of 81 values with a single 1, decode two values out of its position. Return them in a tuple (major,minor).
  260.         position = lst.index(1)
  261.         minor = position % self.size
  262.         major = position // self.size
  263.         return (major,minor)
  264.  
  265.  
  266. def Stats():
  267.     strF=""
  268.    
  269.    
  270.     strF+="###########################################\n"
  271.     strF+="#Sudoku solver by A.Depasse, DLX algorithm#\n"
  272.     strF+="###########################################\n"
  273.    
  274.     strF+="-------------------------------------------\n"
  275.     strF+="Loading file \'toSolve.txt\' ...\n"
  276.     t1=tm.clock()
  277.     fichier=open('toSolve.txt','r')
  278.     sudokus=fichier.read().split('\n')
  279.     t2=tm.clock()
  280.     strF+="File loaded in "+ str(t2-t1) +"s. \n"
  281.     fichier.close
  282.     strF+="-------------------------------------------\n"
  283.     size,title=sudokus[0].split(',')
  284.     strF+="File name : "+title+"\n"
  285.     strF+="sudoku size : "+size+"\n"
  286.     strF+="number of sudokus : "+ str(len(sudokus)-1) + "\n"
  287.     strF+="-------------------------------------------\n"
  288.     strF+="Starting solving process\n"
  289.     deltatimes=[]
  290.     for x in sudokus[1:]:
  291.         t3=tm.clock()
  292.         g=Sudoku(x,int(size))
  293.         if not g.solve():
  294.             strF+="Error : one sudoku cannot be solved. Interruption!\n"
  295.             out=open("results.txt",'w')
  296.             out.write(strF)
  297.             out.close()
  298.             return False
  299.         t4=tm.clock()
  300.         deltatimes.append(t4-t3)
  301.     strF+="Sudokus solved ! \n"
  302.     strF+="-------------------------------------------\n"
  303.     strF+="Statistics : \n"
  304.     totaltime=sum(deltatimes)
  305.     avgtime=np.mean(deltatimes)
  306.     strF+="Total time : "+str(totaltime)+"\n"
  307.     strF+="Mean time for one puzzle : "+str(avgtime)+"\n"
  308.     strF+="-------------------------------------------\n"
  309.     out=open("results.txt",'w')
  310.     out.write(strF)
  311.     out.close()
  312.    
  313.    
  314. Stats()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement