On Tue, 01 Aug 2006 17:48:41 +0900, Peter Hickman wrote:

> The source code is available from 
> http://peterhi.dyndns.org/write_it_in_c/index.html

Here is another version in Ruby.  It uses a more clever algorithm.
It makes use of the fact that permuting the rows or the columns of
a latin square still gives a latin square.  It also passes a constraint
on the columns that the given number can be in, to reduce the backtracking
even more.

It runs in 15 seconds on my machine, which I find quite acceptable.

I am sure that this algorithm coded in a compiled functional or logic
language would be about as fast, or faster than your C code, but with the
advantages of a higher level language.

I still think you benchmark is flawed, because 
  1) the C program works only for squares of size 5
  2) It shows totally no relevance to the kind of problems that you 
     would use Ruby for.  If you want raw speed for numerical applications,
     then I would suggest to use a functional language (i.e. ocaml).
  3) If your application runs slowly, it is probably better to think first
     about why it is slow, if you can improve the code with faster
     algorithms or removing bottlenecks.

Kristof Bastiaensen

---------------- latin2.rb --------------------
require 'permutation'

$size = (ARGV.shift || 5).to_i
MaxVal = $size-1

RowPermutations = Permutation.new($size).map{|p| p.value}
BaseStr = (2..$size).to_a.join
StrPermutations = Permutation.new($size-1).map{|p| p.project(BaseStr)}

StartColumns = (1..MaxVal).to_a
def init_columns(el)
   a = StartColumns.dup
   a.delete_at(el-1)
   return a
end

def insert(sqr, num, row, columns)
   insert(sqr, num, row+1, columns) if (row == num)
   columns.each do |col|
      next if sqr[row][col] != ?.
      sqr[row][col] = num + ?1
      if (row == MaxVal)
         insert(sqr, num+1, 1, init_columns(num+1))
      elsif (num == MaxVal && row == MaxVal - 1)
         print_solution(sqr)
      else
         insert(sqr, num, row+1, columns - [col])
      end
      sqr[row][col] = ?.
   end
end

def print_solution(sqr)
   RowPermutations.each do |rp|
      StrPermutations.each do |sp|
         0.upto(MaxVal) do |r| 
            print sqr[rp[r]].tr(BaseStr, sp)
            print ":"
         end
         puts
      end
   end
end

$square = [("1" + BaseStr)] +
   Array.new($size-1) { |i| (i+2).to_s + "." * ($size - 1) }

insert($square, 0, 1, StartColumns)