Skip to content

Instantly share code, notes, and snippets.

@lspector
Last active October 31, 2017 02:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lspector/a038002d2c32eee3a1d5680b69446cd6 to your computer and use it in GitHub Desktop.
Save lspector/a038002d2c32eee3a1d5680b69446cd6 to your computer and use it in GitHub Desktop.
Scrambling a self-eval map with a Markov chain for AI at Hampshire College: http://viewer.gorilla-repl.org/view.html?source=gist&id=a038002d2c32eee3a1d5680b69446cd6
;; gorilla-repl.fileformat = 1
;; **
;;; # Self-eval scramble
;;;
;;; Lee Spector, 2017
;;;
;;; This is code for Markov chain scrambling of self-evaluations for CS263: Artificial Intelligence at Hampshire College.
;;;
;;; In this text scrambler, we start with a random word and then follow it by some word that follows that word in the original text, with the probabilities for the following words derived from the numbers of times that they follow the first word in the original text. Then we repeat the process to choose a word to follow the second word, and so on. While it's possible to do this by computing the probabilities of all word pairs in the input, we can do it more simply, and achieve the same results, with random rotations.
;; **
;; @@
(ns self-eval-scramble)
;; @@
;; =>
;;; {"type":"html","content":"<span class='clj-nil'>nil</span>","value":"nil"}
;; <=
;; **
;;; First, let's write a function that rotates a sequence by a random amount:
;; **
;; @@
(defn rotate-randomly
"Returns sequence rotated a random amount."
[sequence]
(let [n (rand-int (count sequence))]
(concat (drop n sequence)
(take n sequence))))
;; @@
;; =>
;;; {"type":"html","content":"<span class='clj-var'>#&#x27;self-eval-scramble/rotate-randomly</span>","value":"#'self-eval-scramble/rotate-randomly"}
;; <=
;; **
;;; Let's try it out:
;; **
;; @@
(rotate-randomly [1 2 3 4 5 6 7 8 9])
;; @@
;; =>
;;; {"type":"list-like","open":"<span class='clj-lazy-seq'>(</span>","close":"<span class='clj-lazy-seq'>)</span>","separator":" ","items":[{"type":"html","content":"<span class='clj-long'>3</span>","value":"3"},{"type":"html","content":"<span class='clj-long'>4</span>","value":"4"},{"type":"html","content":"<span class='clj-long'>5</span>","value":"5"},{"type":"html","content":"<span class='clj-long'>6</span>","value":"6"},{"type":"html","content":"<span class='clj-long'>7</span>","value":"7"},{"type":"html","content":"<span class='clj-long'>8</span>","value":"8"},{"type":"html","content":"<span class='clj-long'>9</span>","value":"9"},{"type":"html","content":"<span class='clj-long'>1</span>","value":"1"},{"type":"html","content":"<span class='clj-long'>2</span>","value":"2"}],"value":"(3 4 5 6 7 8 9 1 2)"}
;; <=
;; **
;;; Now, let's write a function that takes an item and a sequence, and rotates the sequence until the provided item comes first. We'll assume that the item is indeed present in the sequence:
;; **
;; @@
(defn rotate-to
"Returns sequence rotated until item is first.
Never returns if item is not in the collection!"
[item sequence]
(loop [s sequence]
(if (= item (first s))
s
(recur (concat (rest s) [(first s)])))))
;; @@
;; =>
;;; {"type":"html","content":"<span class='clj-var'>#&#x27;self-eval-scramble/rotate-to</span>","value":"#'self-eval-scramble/rotate-to"}
;; <=
;; **
;;; Let's try this out too:
;; **
;; @@
(rotate-to 23 [9 43 1 4 23 99 100 20])
;; @@
;; =>
;;; {"type":"list-like","open":"<span class='clj-lazy-seq'>(</span>","close":"<span class='clj-lazy-seq'>)</span>","separator":" ","items":[{"type":"html","content":"<span class='clj-long'>23</span>","value":"23"},{"type":"html","content":"<span class='clj-long'>99</span>","value":"99"},{"type":"html","content":"<span class='clj-long'>100</span>","value":"100"},{"type":"html","content":"<span class='clj-long'>20</span>","value":"20"},{"type":"html","content":"<span class='clj-long'>9</span>","value":"9"},{"type":"html","content":"<span class='clj-long'>43</span>","value":"43"},{"type":"html","content":"<span class='clj-long'>1</span>","value":"1"},{"type":"html","content":"<span class='clj-long'>4</span>","value":"4"}],"value":"(23 99 100 20 9 43 1 4)"}
;; <=
;; **
;;; That's all we need to do the core computation here, which I'll call "rephrase":
;; **
;; @@
(defn rephrase
"Returns a sequence derived from the given sequence."
[sequence]
(take (count sequence)
(iterate (fn [item]
(second (rotate-to item (rotate-randomly sequence))))
(rand-nth sequence))))
;; @@
;; =>
;;; {"type":"html","content":"<span class='clj-var'>#&#x27;self-eval-scramble/rephrase</span>","value":"#'self-eval-scramble/rephrase"}
;; <=
;; **
;;; Let's try that out:
;; **
;; @@
(rephrase '(Looking for a certain ratio
Someone must have left it underneath the carpet
Looking up and down the radio
Oh, oh, nothing there this time
Looking for a certain ratio
Someone said they saw it parking in a car lot
Looking up and down the radio
Oh, oh, nothing there this time
Going back down to the rodeo
Oh, oh, oh, oh, oh, oh, oh, oh, here we go!))
;; @@
;; =>
;;; {"type":"list-like","open":"<span class='clj-lazy-seq'>(</span>","close":"<span class='clj-lazy-seq'>)</span>","separator":" ","items":[{"type":"html","content":"<span class='clj-symbol'>oh</span>","value":"oh"},{"type":"html","content":"<span class='clj-symbol'>nothing</span>","value":"nothing"},{"type":"html","content":"<span class='clj-symbol'>there</span>","value":"there"},{"type":"html","content":"<span class='clj-symbol'>this</span>","value":"this"},{"type":"html","content":"<span class='clj-symbol'>time</span>","value":"time"},{"type":"html","content":"<span class='clj-symbol'>Looking</span>","value":"Looking"},{"type":"html","content":"<span class='clj-symbol'>for</span>","value":"for"},{"type":"html","content":"<span class='clj-symbol'>a</span>","value":"a"},{"type":"html","content":"<span class='clj-symbol'>car</span>","value":"car"},{"type":"html","content":"<span class='clj-symbol'>lot</span>","value":"lot"},{"type":"html","content":"<span class='clj-symbol'>Looking</span>","value":"Looking"},{"type":"html","content":"<span class='clj-symbol'>for</span>","value":"for"},{"type":"html","content":"<span class='clj-symbol'>a</span>","value":"a"},{"type":"html","content":"<span class='clj-symbol'>certain</span>","value":"certain"},{"type":"html","content":"<span class='clj-symbol'>ratio</span>","value":"ratio"},{"type":"html","content":"<span class='clj-symbol'>Someone</span>","value":"Someone"},{"type":"html","content":"<span class='clj-symbol'>must</span>","value":"must"},{"type":"html","content":"<span class='clj-symbol'>have</span>","value":"have"},{"type":"html","content":"<span class='clj-symbol'>left</span>","value":"left"},{"type":"html","content":"<span class='clj-symbol'>it</span>","value":"it"},{"type":"html","content":"<span class='clj-symbol'>underneath</span>","value":"underneath"},{"type":"html","content":"<span class='clj-symbol'>the</span>","value":"the"},{"type":"html","content":"<span class='clj-symbol'>rodeo</span>","value":"rodeo"},{"type":"html","content":"<span class='clj-symbol'>Oh</span>","value":"Oh"},{"type":"html","content":"<span class='clj-symbol'>oh</span>","value":"oh"},{"type":"html","content":"<span class='clj-symbol'>nothing</span>","value":"nothing"},{"type":"html","content":"<span class='clj-symbol'>there</span>","value":"there"},{"type":"html","content":"<span class='clj-symbol'>this</span>","value":"this"},{"type":"html","content":"<span class='clj-symbol'>time</span>","value":"time"},{"type":"html","content":"<span class='clj-symbol'>Going</span>","value":"Going"},{"type":"html","content":"<span class='clj-symbol'>back</span>","value":"back"},{"type":"html","content":"<span class='clj-symbol'>down</span>","value":"down"},{"type":"html","content":"<span class='clj-symbol'>the</span>","value":"the"},{"type":"html","content":"<span class='clj-symbol'>radio</span>","value":"radio"},{"type":"html","content":"<span class='clj-symbol'>Oh</span>","value":"Oh"},{"type":"html","content":"<span class='clj-symbol'>oh</span>","value":"oh"},{"type":"html","content":"<span class='clj-symbol'>nothing</span>","value":"nothing"},{"type":"html","content":"<span class='clj-symbol'>there</span>","value":"there"},{"type":"html","content":"<span class='clj-symbol'>this</span>","value":"this"},{"type":"html","content":"<span class='clj-symbol'>time</span>","value":"time"},{"type":"html","content":"<span class='clj-symbol'>Going</span>","value":"Going"},{"type":"html","content":"<span class='clj-symbol'>back</span>","value":"back"},{"type":"html","content":"<span class='clj-symbol'>down</span>","value":"down"},{"type":"html","content":"<span class='clj-symbol'>the</span>","value":"the"},{"type":"html","content":"<span class='clj-symbol'>radio</span>","value":"radio"},{"type":"html","content":"<span class='clj-symbol'>Oh</span>","value":"Oh"},{"type":"html","content":"<span class='clj-symbol'>oh</span>","value":"oh"},{"type":"html","content":"<span class='clj-symbol'>oh</span>","value":"oh"},{"type":"html","content":"<span class='clj-symbol'>nothing</span>","value":"nothing"},{"type":"html","content":"<span class='clj-symbol'>there</span>","value":"there"},{"type":"html","content":"<span class='clj-symbol'>this</span>","value":"this"},{"type":"html","content":"<span class='clj-symbol'>time</span>","value":"time"},{"type":"html","content":"<span class='clj-symbol'>Looking</span>","value":"Looking"},{"type":"html","content":"<span class='clj-symbol'>up</span>","value":"up"},{"type":"html","content":"<span class='clj-symbol'>and</span>","value":"and"},{"type":"html","content":"<span class='clj-symbol'>down</span>","value":"down"},{"type":"html","content":"<span class='clj-symbol'>the</span>","value":"the"},{"type":"html","content":"<span class='clj-symbol'>radio</span>","value":"radio"},{"type":"html","content":"<span class='clj-symbol'>Oh</span>","value":"Oh"},{"type":"html","content":"<span class='clj-symbol'>oh</span>","value":"oh"},{"type":"html","content":"<span class='clj-symbol'>oh</span>","value":"oh"},{"type":"html","content":"<span class='clj-symbol'>nothing</span>","value":"nothing"},{"type":"html","content":"<span class='clj-symbol'>there</span>","value":"there"},{"type":"html","content":"<span class='clj-symbol'>this</span>","value":"this"},{"type":"html","content":"<span class='clj-symbol'>time</span>","value":"time"},{"type":"html","content":"<span class='clj-symbol'>Looking</span>","value":"Looking"},{"type":"html","content":"<span class='clj-symbol'>for</span>","value":"for"},{"type":"html","content":"<span class='clj-symbol'>a</span>","value":"a"},{"type":"html","content":"<span class='clj-symbol'>certain</span>","value":"certain"}],"value":"(oh nothing there this time Looking for a car lot Looking for a certain ratio Someone must have left it underneath the rodeo Oh oh nothing there this time Going back down the radio Oh oh nothing there this time Going back down the radio Oh oh oh nothing there this time Looking up and down the radio Oh oh oh nothing there this time Looking for a certain)"}
;; <=
;; **
;;; Now we need another bit of code that will take a self-eval map, pull the relevant strings, break them into substrings, rephrase the whole thing, and then join the substrings back together:
;; **
;; @@
(use 'clojure.string)
(defn self-eval-scramble
[m]
(join " "(rephrase (split (join " " (concat (vals (dissoc m :name :submission :attendance :rice))
(map :topics (:rice m))))
#"\s+"))))
;; @@
;; =>
;;; {"type":"html","content":"<span class='clj-var'>#&#x27;self-eval-scramble/self-eval-scramble</span>","value":"#'self-eval-scramble/self-eval-scramble"}
;; <=
;; **
;;; Now we can scramble a self-eval map as follows:
;; **
;; @@
(self-eval-scramble
{:name "Kathy Koder"
:submission 0
:attendance "I attended every class and participated with enthusiasm."
:demonic "I worked on basic Clojure data structures and heuristic search."
:rice [{:partner "Connie Conjer"
:location "APL"
:time "2:00 PM 9/23/17"
:topics "Reviewed search and played Rock Paper Stuff."}
{:partner "Victor Vector"
:location "ASH lobby"
:time "4:30 PM 10/30/17"
:topics "Logic programming."}]
:code "My code computes the answer to the ultimate question of life, the universe, and everything."
:text "I refuted John Searle and discussed ways to prevent bots from taking down websites."
:presentation "I presented my code, showing that it always gives the same answer."
:knowledge "I have learned how to produce all truths using only a few lazy functions."})
;; @@
;; =>
;;; {"type":"html","content":"<span class='clj-string'>&quot;truths using only a few lazy functions. I presented my code, showing that it always gives the same answer. I worked on basic Clojure data structures and everything. I refuted John Searle and heuristic search. My code computes the answer to prevent bots from taking down websites. Reviewed search and heuristic search. My code computes the ultimate question of life, the answer to prevent bots from taking down websites. Reviewed search and played Rock&quot;</span>","value":"\"truths using only a few lazy functions. I presented my code, showing that it always gives the same answer. I worked on basic Clojure data structures and everything. I refuted John Searle and heuristic search. My code computes the answer to prevent bots from taking down websites. Reviewed search and heuristic search. My code computes the ultimate question of life, the answer to prevent bots from taking down websites. Reviewed search and played Rock\""}
;; <=
;; @@
;; @@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment