2

In the language of Clojure I am trying to pass a variable that I am defining within a let as a parameter to a function within the same let. The variable itself represents a list of vectors representing edges in a graph. The function I want to pass it to uses the list to make sure that it does not generate the same value within the list.

The function in whole

(defn random-WS 
  ([n k] (random-WS (- n 1) k (reg-ring-lattice n k)))
  ([n k graph] 
   (cond (= n -1) graph
         :else
         (let [rem-list (for [j (range (count (graph n))) :when (< (rand) 0.5)]
                          [n (nth (seq (graph n)) j)])
               add-list (for [j (range (count rem-list))]
                          (random-WSE graph n add-list))
               new-graph (reduce add-edge (reduce rem-edge graph rem-list) add-list)]
           (random-WS (- n 1) k new-graph)))))

The actual problem statement is seen here

add-list (for [j (range (count rem-list))]
    (random-WSE graph n add-list))

Again for clarity, the function random-WSE generates a random edge for my graph based on some rules. Given the current graph, current node n, and current list of edges to add add-list it will generate one more edge to add to the list based on some rules.

The only real idea I have is to first let add-list () to first define it before then redefining it. Though this still has somewhat the same issue, though add-list is now defined, it will be () through out the for statement. Thus the function random-WSE will not take into account the edges already in the list.

Is there a way to "evaluate" add-list at some defined point within its own definition so that it can be used, within its definition? So I would first "evaluate" it to () before the for and then "evaluate" after each iteration of the for.

If you're interested the function is used to create a random Watts-Stogatz graph.

2 Answers 2

3

From what I get of your description of this algorithm, add-list grows (accumulates) during the problematic for loop. Accumulation (for a very broad acceptation of accumulation) is a strong sign you should use reduce:

(reduce (fn [add-list j] (conj add-list (random-WSE graph n add-list))) [] (range (count rem-list))

Sign up to request clarification or add additional context in comments.

Comments

0

Basically you're chaining results in your let, in the sense that the result of the first computation (resulting in rem-list) is the sole input for your second computation (your trouble point) which again is the sole input for your third computation, which is finally the sole input to your final computation step (your recursion step). If this chaining sounds familiar, that's because it is: think about reformulating your let construction in terms of the threading macro ->.

I.e. something along the lines of

(defn- rem-list [graph n]
   ...)
(defn- add-list [remlist n]
   ...)
(defn- new-graph [addlist]
   ...)

(defn random-ws 
   ([n k] ...)
   ([graph n k] ;; <- note the moved parameter
     (cond (= n -1) graph
           :else    
           (-> graph
               (rem-list n)
               (add-list n)
               (new-graph)
               (random-ws (dec n) k))))

You can then formulate add-list as a simple recursive function (maybe introduce an accumulator variable) or use the reduce variant that cgrand explained.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.