How to make this faster

Helmut Jarausch jarausch at igpm.rwth-aachen.de
Fri Jul 5 18:07:03 CEST 2013


On Fri, 05 Jul 2013 16:38:43 +0100, Oscar Benjamin wrote:

> On 5 July 2013 16:17, Helmut Jarausch <jarausch at igpm.rwth-aachen.de> wrote:
>>
>> I've tried the following version
>>
>> def find_good_cell() :
>>   Best= None
>>   minPoss= 10
>>   for r,c in Grid :
>>     if  Grid[(r,c)] > 0 : continue
> 
> Sorry, I think what I meant was that you should have a structure
> called e.g. Remaining which is the set of all (r, c) pairs that you
> want to loop over here. Then there's no need to check on each
> iteration whether or not Grid[(r, c)] > 0. When I said "sparse" I
> meant that you don't need to set keys in Grid unless you actually have
> a value there so the test "Grid[(r, c)] > 0" would look like "(r, c)
> in Grid". Remaining is the set of all (r, c) pairs not in Grid that
> you update incrementally with .add() and .remove().
> 
> Then this
> 
>    for r,c in Grid :
>      if  Grid[(r,c)] > 0 : continue
> 
> becomes
> 
>     for r, c in Remaining:
> 
>>     Sq_No= (r//3)*3+c//3
>>     Possibilities= 9-len(Row_Digits[r] | Col_Digits[c] | Sqr_Digits[Sq_No])
>>     if ( Possibilities < minPoss ) :
>>       minPoss= Possibilities
>>       Best= (r,c)
>>
>>   if minPoss == 0 : Best=(-1,-1)
>>   return Best
>>
>> All_digits= set((1,2,3,4,5,6,7,8,9))
> 
> All_digits= set(range(1, 10))
> 
> or
> 
> All_digits = {1,2,3,4,5,6,7,8,9}
> 
>>
>> def Solve(R_Cells) :
>>   if  R_Cells == 0 :
>>     print("\n\n++++++++++ S o l u t i o n ++++++++++\n")
>>     Print_Grid()
>>     return True
>>
>>   r,c= find_good_cell()
>>   if r < 0 : return False
>>   Sq_No= (r//3)*3+c//3
>>
>>   for d in All_digits - (Row_Digits[r] | Col_Digits[c] | Sqr_Digits[Sq_No]) :
>>     # put d into Grid
>>     Grid[(r,c)]= d
>>     Row_Digits[r].add(d)
>>     Col_Digits[c].add(d)
>>     Sqr_Digits[Sq_No].add(d)
>>
>>     Success= Solve(R_Cells-1)
>>
>>     # remove d again
>>     Grid[(r,c)]= 0
>>     Row_Digits[r].remove(d)
>>     Col_Digits[c].remove(d)
>>     Sqr_Digits[Sq_No].remove(d)
>>
>>     if Success :
>>       Zuege.append((d,r,c))
>>       return True
>>
>>   return False
>>
>> which turns out to be as fast as the previous "dictionary only version".
>> Probably,  set.remove is a bit slow
> 
> No it's not and you're not using it in your innermost loops anyway.
> Probably the loop I referred to isn't your bottleneck.
> 

I've tried your suggestion, but unless I've misunderstood your suggestion it's a bit slower
than the solution above.

The solution above take 0.79 seconds (mean of 100 calls) while the following version
take 1.05 seconds (mean of 100 calls):


Grid = {(i,j):0 for i in range(9) for j in range(9)}
Remaining= {(i,j) for i in range(9) for j in range(9)}
Row_Digits = [set() for r in range(9)]
Col_Digits = [set() for c in range(9)]
Sqr_Digits = [set() for s in range(9)]

.... remove some pairs from Remaining for the initial set of the given Sudoku

def find_good_cell() :
  Best= None
  minPoss= 10
  for r,c in Remaining :
    Sq_No= (r//3)*3+c//3
    Possibilities= 9-len(Row_Digits[r] | Col_Digits[c] | Sqr_Digits[Sq_No])
    if ( Possibilities < minPoss ) :
      minPoss= Possibilities
      Best= (r,c)

  if minPoss == 0 : Best=(-1,-1)
  return Best

All_digits= set(range(1,10))

def Solve(R_Cells) :
  if  R_Cells == 0 :
    print("\n\n++++++++++ S o l u t i o n ++++++++++\n")
    Print_Grid()
    return True

  r,c= find_good_cell()
  if r < 0 : return False
  Sq_No= (r//3)*3+c//3
  
  for d in All_digits - (Row_Digits[r] | Col_Digits[c] | Sqr_Digits[Sq_No]) :
    # put d into Grid
    Grid[(r,c)]= d
    Remaining.remove((r,c))
    Row_Digits[r].add(d)
    Col_Digits[c].add(d)
    Sqr_Digits[Sq_No].add(d)
    
    Success= Solve(R_Cells-1)

    # remove d again
    Grid[(r,c)]= 0
    Remaining.add((r,c))
    Row_Digits[r].remove(d)
    Col_Digits[c].remove(d)
    Sqr_Digits[Sq_No].remove(d)
  
    if Success :
      Zuege.append((d,r,c))
      return True

  return False





More information about the Python-list mailing list