That is really nice thank you. I'd have to take a real hard look at
it, to see whether or not it's the exact algorithm I need, but
nonetheless, you pointed me in the right direction. The code I
produced was a mess of mutable state and loops. Thank you very much!

On Nov 16, 6:29 pm, Ken Wesson <kwess...@gmail.com> wrote:
> I took a stab at it:
>
> (defn make-verts [n]
>   (zipmap (range n) (repeat [])))
>
> (defn free-legs? [m i d]
>   (< (count (m i)) d))
>
> (defn free-leg-indices [m n d]
>   (filter #(free-legs? m % d) (range n)))
>
> (defn first-free-leg [m n d]
>   (first (free-leg-indices m n d)))
>
> (defn random-free-leg [m n d]
>   (let [fli (free-leg-indices m n d)
>         fl-counts (zipmap fli (map #(- d (count (m %))) fli))
>         fli2 (mapcat #(repeat (fl-counts %) %) fli)]
>     (nth fli2 (rand-int (count fli2)))))
>
> (defn add-random-edge [m n d]
>   (let [i1 (first-free-leg m n d)
>         i2 (random-free-leg (update-in m [i1] conj 'dummy) n d)]
>     (update-in (update-in m [i1] conj i2) [i2] conj i1)))
>
> (defn d-regular-graph-edges [n d]
>   (/ (* n d) 2))
>
> (defn random-d-regular-graph [n d]
>   (nth
>     (iterate #(add-random-edge % n d) (make-verts n))
>     (d-regular-graph-edges n d)))
>
> It seems to work and looks pretty functional to me.
>
> user=> (random-d-regular-graph 5 2)
> {4 [0 0],
>  3 [1 1],
>  2 [2 2],
>  1 [3 3],
>  0 [4 4]}
> user=> (random-d-regular-graph 5 2)
> {4 [1 3],
>  3 [1 4],
>  2 [2 2],
>  1 [3 4],
>  0 [0 0]}
> user=> (random-d-regular-graph 5 2)
> {4 [0 2],
>  3 [0 1],
>  2 [1 4],
>  1 [2 3],
>  0 [3 4]}
> user=> (random-d-regular-graph 4 3)
> {3 [0 1 2],
>  2 [0 1 3],
>  1 [0 2 3],
>  0 [1 3 2]}
> user=> (random-d-regular-graph 4 3)
> {3 [0 0 1],
>  2 [1 2 2],
>  1 [0 3 2],
>  0 [1 3 3]}
>
> Obviously it b0rks if the product of the number of vertices and the
> degree isn't even:
>
> user=> (random-d-regular-graph 3 3)
> {2 [1 1],
>  1 [0 2 2],
>  0 [1 0 0]}
>
> As you can see there's one free leg left over.
>
> The only slightly tricky bit in the code is the (update-in ...
> 'dummy). It's there to avoid this:
>
> user=> (random-d-regular-graph 5 2)
> {4 [0 0],
>  3 [1],
>  2 [1 2 2],
>  1 [3 2],
>  0 [4 4]}
>
> In this example, for the final random edge it took a free leg on 2 and
> saw that 2 and 3 still had free legs and randomly picked 2. So, when
> it goes to pick the other leg to join it has to view the leg already
> chosen as already taken.
>
> Now, this picks one leg for each new edge to be the first in a fixed
> traversal order of verts-then-legs and the other randomly and
> uniformly from all of the other free legs remaining. If that's not
> what you wanted, say if in particular having two edges from the same
> node to the same other node is verboten, I hope at least that the
> outline of the code shows you how this kind of thing can be done
> without mutables or even loop/recur and that you can adapt your own
> algorithm to the same basic structure -- that you can see where the
> random selection of the second leg of a new edge occurs and where you
> might make it pick in a different way or avoid parallel pairs of
> edges, etc.
>
> If you want global properties such as connectedness, that's more
> complicated; my first inclination would be to wrap the whole thing in
> a (first (remove is-bad-in-some-way? (repeatedly
> #(random-d-regular-graph n d)))) but I expect that would slow to a
> crawl if is-bad-in-some-way? is usually true for a fully general
> random graph and either n or d is at all large.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to