If I'm reading correctly, it looks like decompose is intended to give all
partitions of val into num summands.
Julia actually has this function as part of Base:
julia> collect(Vector{Int}, partitions(10, 3))
8-element Array{Array{Int64,1},1}:
[8,1,1]
[7,2,1]
[6,3,1]
[5,4,1]
[6,2,2]
[5,3,2]
[4,4,2]
[4,3,3]
partitions actually returns an iterator, so if you can process the
partitions 1-by-1, you don't actually have to store them all at once.
You can see how it's implemented here:
https://github.com/JuliaLang/julia/blob/8396c9f5c9a3483e35f5e1f9ef63d4c6b3f45b04/base/combinatorics.jl#L307-L369
On Sunday, October 18, 2015 at 9:49:45 PM UTC-4, Patrick Useldinger wrote:
>
> Hi everybody,
>
> I am currently benchmarking languages to write a kakuro solver in. I am
> not really familiar with Julia but ported the small algorithm I had written
> in Lisp and PyPy to Julia nevertheless. Unfortunately Julia's performance
> is really bad and I'm reaching out to the community to find out whether
> it's due to my coding or not.
>
> Here's the code in Julia:
>
> function decompose(val, num)
> function sub(num, tot, res, pos, allres)
> if val==tot && num==0
> union(allres, res)
> elseif tot<val && num>0 && !isempty(pos)
> sub(num-1, tot+pos[1], union(copy(res),pos[1]), pos[2:end], sub(num,
> tot, res, pos[2:end], allres))
> else
> allres
> end
> end
> sub(num, 0, Int16[], 1:(max(num, 10))-1, Array[])
> end
>
> for i in 1:45
> for j in 2:20
> res = decompose(i, j)
> end
> end
>
> It takes roughly 13.4 seconds on my computer.
>
> The equivalent Python code
>
> def decompose(val, num):
> def sub(num, tot, res, pos, allres):
> if tot == val and num == 0:
> return allres+res
> elif tot < val and num != 0 and pos:
> return sub(num-1, tot+pos[0], res+[pos[0]], pos[1:], sub(num,
> tot, res, pos[1:], allres))
> else:
> return allres
> return sub(num, 0, [], range(1, max(num, 10)), [])
>
>
> if __name__ == "__main__":
> for i in range(1, 46):
> for j in range(2,21):
> res = decompose(i,j)
>
> is 1.4 seconds and the Lisp
>
> defun decompose (val num)
> (labels ((sub (num tot res pos allres)
> (cond
> ((and (= tot val) (zerop num)) (cons (reverse res) allres))
> ((and (< tot val) (not (zerop num)) (not (null pos)))
> (sub (1- num) (+ tot (car pos)) (cons (car pos) res) (cdr
> pos)
> (sub num tot res (cdr pos) allres)))
> (t allres))))
> (reverse (sub num 0 nil (loop for i from 1 below (max num 10) collect
> i) nil))))
>
> (time
> (loop for val from 1 below 46 do
> (loop for num from 2 below 21 do
> (let ((res (decompose val num)))))))
>
> is 0.5 seconds.
>
> Any hints to make the Julia code perform better?
>
> Regards,
> -Patrick
>