It is true that it must be commutative, but not true that it must be
non-associative.  Here is a sample implementation of a hash function for
sets that is commutative and associative but doesn't collide for these
sorts of common rearrangements.  The idea of this proof of concept is that
the hash value of a set is the sum of (expt 3 (abs (hash item))) for each
item in the set.

Implementation:

;; First a wrap-around implementation of expt
(defn- expt [base pow]
  (if (zero? pow) 1
    (loop [n (int pow), y (int 1), z (int base)]
      (let [t (even? n), n (quot n 2)]
        (cond
          t (recur n y (unchecked-multiply-int z z))
          (zero? n) (unchecked-multiply-int z y)
          :else (recur n (unchecked-multiply-int z y)
(unchecked-multiply-int z z)))))))

(declare my-hash)

(defn set-hash [coll]
  (reduce + (for [item (seq coll)] (expt 3 (my-hash item)))))

(defn my-hash [i]
  (if (set? i) (set-hash i) (hash i)))

=> (my-hash #{#{1 2} 3})
531468
=> (my-hash #{#{1 3} 2})
-1010140990

=> (my-hash #{#{1 3} #{2 4}})
-2065039966
=> (my-hash #{#{1 2} #{3 4}})
-868484254

=> (my-hash #{[1 2] [2 1]})
-3497906806
=> (my-hash #{[1 1] [2 2]})
-443882362


So this is certainly a solvable problem, the real question is how to go
about designing such a hash function around a smaller number of simple
arithmetic operations.  Also, the above implementation is kind of lame
because that expt function treats the hash value of the item as a positive
number, effectively cutting the possible hash values in half.  So this
implementation isn't practical, but should serve as an illustration of what
could be done.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to